mirror of
https://github.com/python/cpython.git
synced 2025-07-08 03:45:36 +00:00
gh-127604: Add C stack dumps to faulthandler
(#128159)
This commit is contained in:
parent
ea8ec95cfa
commit
8dfa840773
13 changed files with 378 additions and 69 deletions
|
@ -18,7 +18,25 @@
|
|||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h> // lseek()
|
||||
#endif
|
||||
#if defined(HAVE_EXECINFO_H) && defined(HAVE_DLFCN_H) && defined(HAVE_LINK_H)
|
||||
# include <execinfo.h> // backtrace(), backtrace_symbols()
|
||||
# include <dlfcn.h> // dladdr1()
|
||||
# include <link.h> // struct DL_info
|
||||
# if defined(HAVE_BACKTRACE) && defined(HAVE_BACKTRACE_SYMBOLS) && defined(HAVE_DLADDR1)
|
||||
# define CAN_C_BACKTRACE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__STDC_NO_VLA__) && (__STDC_NO_VLA__ == 1)
|
||||
/* Use alloca() for VLAs. */
|
||||
# define VLA(type, name, size) type *name = alloca(size)
|
||||
#elif !defined(__STDC_NO_VLA__) || (__STDC_NO_VLA__ == 0)
|
||||
/* Use actual C VLAs.*/
|
||||
# define VLA(type, name, size) type name[size]
|
||||
#elif defined(CAN_C_BACKTRACE)
|
||||
/* VLAs are not possible. Disable C stack trace functions. */
|
||||
# undef CAN_C_BACKTRACE
|
||||
#endif
|
||||
|
||||
#define OFF(x) offsetof(PyTracebackObject, x)
|
||||
#define PUTS(fd, str) (void)_Py_write_noraise(fd, str, strlen(str))
|
||||
|
@ -1166,3 +1184,93 @@ _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef CAN_C_BACKTRACE
|
||||
/* Based on glibc's implementation of backtrace_symbols(), but only uses stack memory. */
|
||||
void
|
||||
_Py_backtrace_symbols_fd(int fd, void *const *array, Py_ssize_t size)
|
||||
{
|
||||
VLA(Dl_info, info, size);
|
||||
VLA(int, status, size);
|
||||
/* Fill in the information we can get from dladdr() */
|
||||
for (Py_ssize_t i = 0; i < size; ++i) {
|
||||
struct link_map *map;
|
||||
status[i] = dladdr1(array[i], &info[i], (void **)&map, RTLD_DL_LINKMAP);
|
||||
if (status[i] != 0
|
||||
&& info[i].dli_fname != NULL
|
||||
&& info[i].dli_fname[0] != '\0') {
|
||||
/* The load bias is more useful to the user than the load
|
||||
address. The use of these addresses is to calculate an
|
||||
address in the ELF file, so its prelinked bias is not
|
||||
something we want to subtract out */
|
||||
info[i].dli_fbase = (void *) map->l_addr;
|
||||
}
|
||||
}
|
||||
for (Py_ssize_t i = 0; i < size; ++i) {
|
||||
if (status[i] == 0
|
||||
|| info[i].dli_fname == NULL
|
||||
|| info[i].dli_fname[0] == '\0'
|
||||
) {
|
||||
dprintf(fd, " Binary file '<unknown>' [%p]\n", array[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (info[i].dli_sname == NULL) {
|
||||
/* We found no symbol name to use, so describe it as
|
||||
relative to the file. */
|
||||
info[i].dli_saddr = info[i].dli_fbase;
|
||||
}
|
||||
|
||||
if (info[i].dli_sname == NULL
|
||||
&& info[i].dli_saddr == 0) {
|
||||
dprintf(fd, " Binary file \"%s\" [%p]\n",
|
||||
info[i].dli_fname,
|
||||
array[i]);
|
||||
}
|
||||
else {
|
||||
char sign;
|
||||
ptrdiff_t offset;
|
||||
if (array[i] >= (void *) info[i].dli_saddr) {
|
||||
sign = '+';
|
||||
offset = array[i] - info[i].dli_saddr;
|
||||
}
|
||||
else {
|
||||
sign = '-';
|
||||
offset = info[i].dli_saddr - array[i];
|
||||
}
|
||||
const char *symbol_name = info[i].dli_sname != NULL ? info[i].dli_sname : "";
|
||||
dprintf(fd, " Binary file \"%s\", at %s%c%#tx [%p]\n",
|
||||
info[i].dli_fname,
|
||||
symbol_name,
|
||||
sign, offset, array[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_Py_DumpStack(int fd)
|
||||
{
|
||||
#define BACKTRACE_SIZE 32
|
||||
PUTS(fd, "Current thread's C stack trace (most recent call first):\n");
|
||||
VLA(void *, callstack, BACKTRACE_SIZE);
|
||||
int frames = backtrace(callstack, BACKTRACE_SIZE);
|
||||
if (frames == 0) {
|
||||
// Some systems won't return anything for the stack trace
|
||||
PUTS(fd, " <system returned no stack trace>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
_Py_backtrace_symbols_fd(fd, callstack, frames);
|
||||
if (frames == BACKTRACE_SIZE) {
|
||||
PUTS(fd, " <truncated rest of calls>\n");
|
||||
}
|
||||
|
||||
#undef BACKTRACE_SIZE
|
||||
}
|
||||
#else
|
||||
void
|
||||
_Py_DumpStack(int fd)
|
||||
{
|
||||
PUTS(fd, "Current thread's C stack trace (most recent call first):\n");
|
||||
PUTS(fd, " <cannot get C stack on this system>\n");
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue