mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 12:41:49 +01:00
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. llvm-svn: 269992
This commit is contained in:
parent
428d853c02
commit
b9f1b721c1
@ -144,6 +144,7 @@ endif()
|
|||||||
# function checks
|
# function checks
|
||||||
check_symbol_exists(arc4random "stdlib.h" HAVE_DECL_ARC4RANDOM)
|
check_symbol_exists(arc4random "stdlib.h" HAVE_DECL_ARC4RANDOM)
|
||||||
check_symbol_exists(backtrace "execinfo.h" HAVE_BACKTRACE)
|
check_symbol_exists(backtrace "execinfo.h" HAVE_BACKTRACE)
|
||||||
|
check_symbol_exists(_Unwind_Backtrace "unwind.h" HAVE_UNWIND_BACKTRACE)
|
||||||
check_symbol_exists(getpagesize unistd.h HAVE_GETPAGESIZE)
|
check_symbol_exists(getpagesize unistd.h HAVE_GETPAGESIZE)
|
||||||
check_symbol_exists(getrusage sys/resource.h HAVE_GETRUSAGE)
|
check_symbol_exists(getrusage sys/resource.h HAVE_GETRUSAGE)
|
||||||
check_symbol_exists(setrlimit sys/resource.h HAVE_SETRLIMIT)
|
check_symbol_exists(setrlimit sys/resource.h HAVE_SETRLIMIT)
|
||||||
|
@ -45,6 +45,9 @@
|
|||||||
#if HAVE_LINK_H
|
#if HAVE_LINK_H
|
||||||
#include <link.h>
|
#include <link.h>
|
||||||
#endif
|
#endif
|
||||||
|
#if HAVE_UNWIND_BACKTRACE
|
||||||
|
#include <unwind.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
@ -309,17 +312,61 @@ static bool findModulesAndOffsets(void **StackTrace, int Depth,
|
|||||||
}
|
}
|
||||||
#endif // defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES) && ...
|
#endif // defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES) && ...
|
||||||
|
|
||||||
|
#if defined(ENABLE_BACKTRACES) && defined(HAVE_UNWIND_BACKTRACE)
|
||||||
|
static int unwindBacktrace(void **StackTrace, int MaxEntries) {
|
||||||
|
if (MaxEntries < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Skip the first frame ('unwindBacktrace' itself).
|
||||||
|
int Entries = -1;
|
||||||
|
|
||||||
|
auto HandleFrame = [&](_Unwind_Context *Context) -> _Unwind_Reason_Code {
|
||||||
|
// Apparently we need to detect reaching the end of the stack ourselves.
|
||||||
|
void *IP = (void *)_Unwind_GetIP(Context);
|
||||||
|
if (!IP)
|
||||||
|
return _URC_END_OF_STACK;
|
||||||
|
|
||||||
|
assert(Entries < MaxEntries && "recursively called after END_OF_STACK?");
|
||||||
|
if (Entries >= 0)
|
||||||
|
StackTrace[Entries] = IP;
|
||||||
|
|
||||||
|
if (++Entries == MaxEntries)
|
||||||
|
return _URC_END_OF_STACK;
|
||||||
|
return _URC_NO_REASON;
|
||||||
|
};
|
||||||
|
|
||||||
|
_Unwind_Backtrace(
|
||||||
|
[](_Unwind_Context *Context, void *Handler) {
|
||||||
|
return (*static_cast<decltype(HandleFrame) *>(Handler))(Context);
|
||||||
|
},
|
||||||
|
static_cast<void *>(&HandleFrame));
|
||||||
|
return std::max(Entries, 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// PrintStackTrace - In the case of a program crash or fault, print out a stack
|
// PrintStackTrace - In the case of a program crash or fault, print out a stack
|
||||||
// trace so that the user has an indication of why and where we died.
|
// trace so that the user has an indication of why and where we died.
|
||||||
//
|
//
|
||||||
// On glibc systems we have the 'backtrace' function, which works nicely, but
|
// On glibc systems we have the 'backtrace' function, which works nicely, but
|
||||||
// doesn't demangle symbols.
|
// doesn't demangle symbols.
|
||||||
void llvm::sys::PrintStackTrace(raw_ostream &OS) {
|
void llvm::sys::PrintStackTrace(raw_ostream &OS) {
|
||||||
#if defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES)
|
#if defined(ENABLE_BACKTRACES)
|
||||||
static void* StackTrace[256];
|
static void *StackTrace[256];
|
||||||
|
int depth = 0;
|
||||||
|
#if defined(HAVE_BACKTRACE)
|
||||||
// Use backtrace() to output a backtrace on Linux systems with glibc.
|
// Use backtrace() to output a backtrace on Linux systems with glibc.
|
||||||
int depth = backtrace(StackTrace,
|
if (!depth)
|
||||||
|
depth = backtrace(StackTrace, static_cast<int>(array_lengthof(StackTrace)));
|
||||||
|
#endif
|
||||||
|
#if defined(HAVE_UNWIND_BACKTRACE)
|
||||||
|
// Try _Unwind_Backtrace() if backtrace() failed.
|
||||||
|
if (!depth)
|
||||||
|
depth = unwindBacktrace(StackTrace,
|
||||||
static_cast<int>(array_lengthof(StackTrace)));
|
static_cast<int>(array_lengthof(StackTrace)));
|
||||||
|
#endif
|
||||||
|
if (!depth)
|
||||||
|
return;
|
||||||
|
|
||||||
if (printSymbolizedStackTrace(StackTrace, depth, OS))
|
if (printSymbolizedStackTrace(StackTrace, depth, OS))
|
||||||
return;
|
return;
|
||||||
#if HAVE_DLFCN_H && __GNUG__
|
#if HAVE_DLFCN_H && __GNUG__
|
||||||
@ -369,7 +416,7 @@ void llvm::sys::PrintStackTrace(raw_ostream &OS) {
|
|||||||
}
|
}
|
||||||
OS << '\n';
|
OS << '\n';
|
||||||
}
|
}
|
||||||
#else
|
#elif defined(HAVE_BACKTRACE)
|
||||||
backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO);
|
backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user