Skip to content

Commit

Permalink
Bootloader: (win) 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 pyinstaller#4213.
For showing the sorce lines, the aplication needs frozen with ``--noarchive``.

Signed-off-by: Dan Yeaw <dyeaw@ford.com>
  • Loading branch information
danyeaw authored and htgoebel committed Apr 19, 2020
1 parent cd3d805 commit 61d98d4
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 4 deletions.
50 changes: 46 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,51 @@ 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(_WIN32) && defined(WINDOWED) && defined(LAUNCH_DEBUG)
/* If running in Windows in windowed mode 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);

/* Next see if we can get a full traceback, only works
* with --noarchive */
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(_WIN32) and defined(WINDOWED) and defined(LAUNCH_DEBUG) */

PI_PyErr_Print();

#endif /* if defined(_WIN32) and 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
8 changes: 8 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,13 @@ 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 *));
EXTDECLPROC(char *, PyString_AsString, (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/4592.bootloader.rst
@@ -0,0 +1 @@
(Windows) Add ability to get traceback to debug pyiboot01_bootstrap errors.

0 comments on commit 61d98d4

Please sign in to comment.