Skip to content

Commit

Permalink
Bootloader build: Add traceback to debug pyiboot01
Browse files Browse the repository at this point in the history
Adds the Python traceback information to debug errors during
pyiboot01_bootstrap when running in Windows in windowed mode. This will
allow debugging errors like in Issue pyinstaller#4213.

Signed-off-by: Dan Yeaw <dyeaw@ford.com>
  • Loading branch information
danyeaw committed Dec 28, 2019
1 parent 498e6ee commit a4ed5d0
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 4 deletions.
Binary file modified PyInstaller/bootloader/Windows-64bit/run.exe
Binary file not shown.
Binary file modified PyInstaller/bootloader/Windows-64bit/run_d.exe
Binary file not shown.
Binary file modified PyInstaller/bootloader/Windows-64bit/runw.exe
Binary file not shown.
Binary file modified PyInstaller/bootloader/Windows-64bit/runw_d.exe
Binary file not shown.
62 changes: 58 additions & 4 deletions bootloader/src/pyi_launch.c
Expand Up @@ -363,13 +363,17 @@ int
pyi_launch_run_scripts(ARCHIVE_STATUS *status)
{
unsigned char *data;
const char *cchar_pvalue, *cchar_tb;
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, *ptraceback;
PyObject *pyth_str_pvalue, *pyth_tb, *pyth_str_tb, *pyth_module, *pyth_func;

__main__ = PI_PyImport_AddModule("__main__");

Expand Down Expand Up @@ -422,14 +426,64 @@ 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);
pyth_str_pvalue = PI_PyObject_Str(pvalue);

if (is_py2) {
char_pvalue = PI_PyString_AsString(pyth_str_pvalue);
FATALERROR("Error: %s\n", char_pvalue);
} else {
cchar_pvalue = PI_PyUnicode_AsUTF8(pyth_str_pvalue);
FATALERROR("Error: %s\n", cchar_pvalue);
}
Py_DECREF(pyth_str_pvalue);

/* Next see if we can get a full traceback, only works with
* --noarchive */

module_name = "traceback";
pyth_module = PI_PyImport_ImportModule(module_name);

if (pyth_module != NULL) {
pyth_func = PI_PyObject_GetAttrString(pyth_module, "format_exception");
if (pyth_func) {
pyth_tb = PI_PyObject_CallFunctionObjArgs(pyth_func, ptype, pvalue, ptraceback, NULL);
pyth_str_tb = PI_PyObject_Str(pyth_tb);
if (is_py2) {
char_tb = PI_PyString_AsString(pyth_str_tb);
FATALERROR("Traceback: %s\n", char_tb);
} else {
cchar_tb = PI_PyUnicode_AsUTF8(pyth_str_tb);
FATALERROR("Traceback: %s\n", cchar_tb);
}
Py_DECREF(pyth_tb);
Py_DECREF(pyth_str_tb);
}
Py_DECREF(pyth_func);
}
Py_DECREF(ptype);
Py_DECREF(pvalue);
Py_DECREF(ptraceback);
Py_DECREF(pyth_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
20 changes: 20 additions & 0 deletions bootloader/src/pyi_python.c
Expand Up @@ -55,6 +55,11 @@ DECLPROC(PyErr_Clear);
DECLPROC(PyErr_Occurred);
DECLPROC(PyErr_Print);

DECLPROC(PyErr_Fetch);
DECLPROC(PyObject_Str);
DECLPROC(PyUnicode_AsUTF8);
DECLPROC(PyObject_GetAttrString);

DECLPROC(PyImport_AddModule);
DECLPROC(PyImport_ExecCodeModule);
DECLPROC(PyImport_ImportModule);
Expand All @@ -63,9 +68,11 @@ DECLPROC(PyList_New);
DECLPROC(PyLong_AsLong);
DECLPROC(PyModule_GetDict);
DECLPROC(PyObject_CallFunction);
DECLPROC(PyObject_CallFunctionObjArgs);
DECLPROC(PyObject_SetAttrString);
DECLPROC(PyRun_SimpleString);
DECLPROC(PyString_FromString);
DECLPROC(PyString_AsString);
DECLPROC(PySys_AddWarnOption);
DECLPROC(PySys_SetArgvEx);
DECLPROC(PySys_GetObject);
Expand Down Expand Up @@ -127,12 +134,20 @@ 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, PyRun_SimpleString);

GETPROC(dll, PyObject_Str);

GETPROC(dll, PyErr_Fetch);

if (pyvers < 30) {
GETPROC(dll, PyString_FromString);
GETPROC(dll, PyString_FromFormat);
GETPROC(dll, PyString_AsString);
}
;
GETPROC(dll, PySys_AddWarnOption);
Expand Down Expand Up @@ -168,6 +183,11 @@ pyi_python_map_names(HMODULE dll, int pyvers)
GETPROC(dll, PyUnicode_DecodeFSDefault);
}

if (pyvers >= 33) {
/* new in Python 3.3 */
GETPROC(dll, PyUnicode_AsUTF8);
}

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

return 0;
Expand Down
8 changes: 8 additions & 0 deletions bootloader/src/pyi_python.h
Expand Up @@ -122,6 +122,7 @@ EXTDECLPROC(PyObject *, PyString_FromString, (const 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

0 comments on commit a4ed5d0

Please sign in to comment.