Skip to content

Commit

Permalink
Bootloader: Add showing traceback in debug windowed mode.
Browse files Browse the repository at this point in the history
When running in Windows in windowed mode, the debug bootloader will now show
the Python traceback information. This help debuging errors during
pyiboot01_bootstrap. This will allow debugging errors like in Issue #4213.
For showing the source lines, the application needs to be frozen with ``--noarchive``.

Signed-off-by: Dan Yeaw <dyeaw@ford.com>
  • Loading branch information
danyeaw authored and htgoebel committed May 2, 2020
1 parent afe197d commit 70709cd
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 4 deletions.
52 changes: 48 additions & 4 deletions bootloader/src/pyi_launch.c
Expand Up @@ -364,13 +364,18 @@ int
pyi_launch_run_scripts(ARCHIVE_STATUS *status)
{
unsigned char *data;
const char *pvalue_cchar, *tb_cchar;
char buf[PATH_MAX];
char *char_pvalue, *char_tb, *module_name;
size_t namelen;
TOC * ptoc = status->tocbuff;
PyObject *__main__;
PyObject *__file__;
PyObject *main_dict;
PyObject *code, *retval;
PyObject *ptype, *pvalue, *pvalue_str;
PyObject *ptraceback, *tb, *tb_str;
PyObject *module, *func;

__main__ = PI_PyImport_AddModule("__main__");

Expand Down Expand Up @@ -417,14 +422,53 @@ pyi_launch_run_scripts(ARCHIVE_STATUS *status)
/* Run it */
retval = PI_PyEval_EvalCode(code, main_dict, main_dict);

/* If retval is NULL, an error occured. Otherwise, it is a Python object.
/* If retval is NULL, an error occurred. Otherwise, it is a Python object.
* (Since we evaluate module-level code, which is not allowed to return an
* object, the Python object returned is always None.) */
if (!retval) {
PI_PyErr_Print();
/* If the error was SystemExit, PyErr_Print calls exit() without
* returning. So don't print "Failed to execute" on SystemExit. */
FATALERROR("Failed to execute script %s\n", ptoc->name);

#if defined(WINDOWED) && defined(LAUNCH_DEBUG)
/* If running in windowed mode, sys.stderr will be None
* resp. NullWriter (see pyiboot01_bootstrap.py), thus
* PyErr_Print() below will not show any traceback. With
* debug, print the traceback to a message box. */

/* First get the value of the error */
PI_PyErr_Fetch(&ptype, &pvalue, &ptraceback);
pvalue_str = PI_PyObject_Str(pvalue);
pvalue_cchar = PI_PyUnicode_AsUTF8(pvalue_str);
FATALERROR("Error: %s\n", pvalue_cchar);
Py_DECREF(pvalue_str);

/* Attempt to get a full traceback, source lines will only
* be available with --noarchive option */
module_name = "traceback";
module = PI_PyImport_ImportModule(module_name);

if (module != NULL) {
func = PI_PyObject_GetAttrString(module, "format_exception");
if (func) {
tb = PI_PyObject_CallFunctionObjArgs(func, ptype, pvalue, ptraceback, NULL);
tb_str = PI_PyObject_Str(tb);
tb_cchar = PI_PyUnicode_AsUTF8(tb_str);
FATALERROR("Traceback: %s\n", tb_cchar);
Py_DECREF(tb);
Py_DECREF(tb_str);
}
Py_DECREF(func);
}
Py_DECREF(ptype);
Py_DECREF(pvalue);
Py_DECREF(ptraceback);
Py_DECREF(module);

#else /* if defined(WINDOWED) and defined(LAUNCH_DEBUG) */

PI_PyErr_Print();

#endif /* if defined(WINDOWED) and defined(LAUNCH_DEBUG) */

return -1;
}
free(data);
Expand Down
11 changes: 11 additions & 0 deletions bootloader/src/pyi_python.c
Expand Up @@ -57,6 +57,7 @@ DECLPROC(PyDict_GetItemString);
DECLPROC(PyErr_Clear);
DECLPROC(PyErr_Occurred);
DECLPROC(PyErr_Print);
DECLPROC(PyErr_Fetch);

DECLPROC(PyImport_AddModule);
DECLPROC(PyImport_ExecCodeModule);
Expand All @@ -66,7 +67,10 @@ DECLPROC(PyList_New);
DECLPROC(PyLong_AsLong);
DECLPROC(PyModule_GetDict);
DECLPROC(PyObject_CallFunction);
DECLPROC(PyObject_CallFunctionObjArgs);
DECLPROC(PyObject_SetAttrString);
DECLPROC(PyObject_GetAttrString);
DECLPROC(PyObject_Str);
DECLPROC(PyRun_SimpleString);
DECLPROC(PySys_AddWarnOption);
DECLPROC(PySys_SetArgvEx);
Expand All @@ -79,6 +83,7 @@ DECLPROC(Py_DecodeLocale);
DECLPROC(PyUnicode_FromFormat);
DECLPROC(PyUnicode_DecodeFSDefault);
DECLPROC(PyUnicode_Decode);
DECLPROC(PyUnicode_AsUTF8);

DECLPROC(PyEval_EvalCode);
DECLPROC(PyMarshal_ReadObjectFromString);
Expand Down Expand Up @@ -116,6 +121,7 @@ pyi_python_map_names(HMODULE dll, int pyvers)
GETPROC(dll, PyErr_Clear);
GETPROC(dll, PyErr_Occurred);
GETPROC(dll, PyErr_Print);
GETPROC(dll, PyErr_Fetch);
GETPROC(dll, PyImport_AddModule);
GETPROC(dll, PyImport_ExecCodeModule);
GETPROC(dll, PyImport_ImportModule);
Expand All @@ -124,7 +130,11 @@ pyi_python_map_names(HMODULE dll, int pyvers)
GETPROC(dll, PyLong_AsLong);
GETPROC(dll, PyModule_GetDict);
GETPROC(dll, PyObject_CallFunction);
GETPROC(dll, PyObject_CallFunctionObjArgs);
GETPROC(dll, PyObject_SetAttrString);
GETPROC(dll, PyObject_GetAttrString);
GETPROC(dll, PyObject_Str);

GETPROC(dll, PyRun_SimpleString);

GETPROC(dll, PySys_AddWarnOption);
Expand All @@ -142,6 +152,7 @@ pyi_python_map_names(HMODULE dll, int pyvers)
GETPROC(dll, PyUnicode_FromFormat);
GETPROC(dll, PyUnicode_Decode);
GETPROC(dll, PyUnicode_DecodeFSDefault);
GETPROC(dll, PyUnicode_AsUTF8);

VS("LOADER: Loaded functions from Python library.\n");

Expand Down
7 changes: 7 additions & 0 deletions bootloader/src/pyi_python.h
Expand Up @@ -123,6 +123,7 @@ EXTDECLPROC(PyObject *, Py_BuildValue, (char *, ...));
/* Create a Unicode object from the char buffer. The bytes will be interpreted as being UTF-8 encoded. */
EXTDECLPROC(PyObject *, PyUnicode_FromString, (const char *));
EXTDECLPROC(PyObject *, PyObject_CallFunction, (PyObject *, char *, ...));
EXTDECLPROC(PyObject *, PyObject_CallFunctionObjArgs, (PyObject *, ...));
EXTDECLPROC(PyObject *, PyModule_GetDict, (PyObject *));
EXTDECLPROC(PyObject *, PyDict_GetItemString, (PyObject *, char *));
EXTDECLPROC(void, PyErr_Clear, (void) );
Expand Down Expand Up @@ -151,6 +152,12 @@ EXTDECLPROC(PyObject *, PyUnicode_Decode,
EXTDECLPROC(PyObject *, PyEval_EvalCode, (PyObject *, PyObject *, PyObject *));
EXTDECLPROC(PyObject *, PyMarshal_ReadObjectFromString, (const char *, size_t)); /* Py_ssize_t */

/* Used to get traceback information while launching run scripts */
EXTDECLPROC(void, PyErr_Fetch, (PyObject **, PyObject **, PyObject **));
EXTDECLPROC(PyObject *, PyObject_Str, (PyObject *));
EXTDECLPROC(PyObject *, PyObject_GetAttrString, (PyObject *, const char *));
EXTDECLPROC(const char *, PyUnicode_AsUTF8, (PyObject *));

/*
* Macros for reference counting through exported functions
* (that is: without binding to the binary structure of a PyObject.
Expand Down
1 change: 1 addition & 0 deletions news/4213.bootloader.rst
@@ -0,0 +1 @@
In debug and windowed mode, print traceback to help debug pyiboot01_bootstrap errors.
1 change: 1 addition & 0 deletions news/4592.bootloader.rst
@@ -0,0 +1 @@
In debug and windowed mode, print traceback to help debug pyiboot01_bootstrap errors.

0 comments on commit 70709cd

Please sign in to comment.