llvm.org GIT mirror llvm / cf44b36
Work around a glibc bug: backtrace() spuriously fails if - glibc is dynamically linked, and - libgcc_s is unavailable (for instance, another library is being used to provide the compiler runtime or libgcc is statically linked), and - the target is x86_64. If we run backtrace() and it fails to find any stack frames, try using _Unwind_Backtrace instead if available. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@269992 91177308-0d34-0410-b5e6-96231b3b80d8 Richard Smith 4 years ago
2 changed file(s) with 52 addition(s) and 4 deletion(s). Raw diff Collapse all Expand all
143143 # function checks
144144 check_symbol_exists(arc4random "stdlib.h" HAVE_DECL_ARC4RANDOM)
145145 check_symbol_exists(backtrace "execinfo.h" HAVE_BACKTRACE)
146 check_symbol_exists(_Unwind_Backtrace "unwind.h" HAVE_UNWIND_BACKTRACE)
146147 check_symbol_exists(getpagesize unistd.h HAVE_GETPAGESIZE)
147148 check_symbol_exists(getrusage sys/resource.h HAVE_GETRUSAGE)
148149 check_symbol_exists(setrlimit sys/resource.h HAVE_SETRLIMIT)
4343 #endif
4444 #if HAVE_LINK_H
4545 #include
46 #endif
47 #if HAVE_UNWIND_BACKTRACE
48 #include
4649 #endif
4750
4851 using namespace llvm;
308311 }
309312 #endif // defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES) && ...
310313
314 #if defined(ENABLE_BACKTRACES) && defined(HAVE_UNWIND_BACKTRACE)
315 static int unwindBacktrace(void **StackTrace, int MaxEntries) {
316 if (MaxEntries < 0)
317 return 0;
318
319 // Skip the first frame ('unwindBacktrace' itself).
320 int Entries = -1;
321
322 auto HandleFrame = [&](_Unwind_Context *Context) -> _Unwind_Reason_Code {
323 // Apparently we need to detect reaching the end of the stack ourselves.
324 void *IP = (void *)_Unwind_GetIP(Context);
325 if (!IP)
326 return _URC_END_OF_STACK;
327
328 assert(Entries < MaxEntries && "recursively called after END_OF_STACK?");
329 if (Entries >= 0)
330 StackTrace[Entries] = IP;
331
332 if (++Entries == MaxEntries)
333 return _URC_END_OF_STACK;
334 return _URC_NO_REASON;
335 };
336
337 _Unwind_Backtrace(
338 [](_Unwind_Context *Context, void *Handler) {
339 return (*static_cast(Handler))(Context);
340 },
341 static_cast(&HandleFrame));
342 return std::max(Entries, 0);
343 }
344 #endif
345
311346 // PrintStackTrace - In the case of a program crash or fault, print out a stack
312347 // trace so that the user has an indication of why and where we died.
313348 //
314349 // On glibc systems we have the 'backtrace' function, which works nicely, but
315350 // doesn't demangle symbols.
316351 void llvm::sys::PrintStackTrace(raw_ostream &OS) {
317 #if defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES)
318 static void* StackTrace[256];
352 #if defined(ENABLE_BACKTRACES)
353 static void *StackTrace[256];
354 int depth = 0;
355 #if defined(HAVE_BACKTRACE)
319356 // Use backtrace() to output a backtrace on Linux systems with glibc.
320 int depth = backtrace(StackTrace,
357 if (!depth)
358 depth = backtrace(StackTrace, static_cast(array_lengthof(StackTrace)));
359 #endif
360 #if defined(HAVE_UNWIND_BACKTRACE)
361 // Try _Unwind_Backtrace() if backtrace() failed.
362 if (!depth)
363 depth = unwindBacktrace(StackTrace,
321364 static_cast(array_lengthof(StackTrace)));
365 #endif
366 if (!depth)
367 return;
368
322369 if (printSymbolizedStackTrace(StackTrace, depth, OS))
323370 return;
324371 #if HAVE_DLFCN_H && __GNUG__
368415 }
369416 OS << '\n';
370417 }
371 #else
418 #elif defined(HAVE_BACKTRACE)
372419 backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO);
373420 #endif
374421 #endif