mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +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
	
	 Peter Bierma
						Peter Bierma