summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Support/Unix
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2016-05-20 21:18:12 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2016-05-20 21:18:12 +0000
commit14d965166c7166a109bdd75333a4a8f8cf668299 (patch)
tree58d8a4c01b0ca305bd878184a47d1b79f1d7752a /llvm/lib/Support/Unix
parent50223310ba56d1db725f4c110ec54966e9bfba92 (diff)
downloadbcm5719-llvm-14d965166c7166a109bdd75333a4a8f8cf668299.tar.gz
bcm5719-llvm-14d965166c7166a109bdd75333a4a8f8cf668299.zip
Reinstate r269992 (reverting r270267), but restricted to cases where glibc is
the C standard library implementation in use. This works around a glibc bug in the backtrace() function where it fails to produce a backtrace on x86_64 if libgcc / libunwind is statically linked. llvm-svn: 270276
Diffstat (limited to 'llvm/lib/Support/Unix')
-rw-r--r--llvm/lib/Support/Unix/Signals.inc63
1 files changed, 59 insertions, 4 deletions
diff --git a/llvm/lib/Support/Unix/Signals.inc b/llvm/lib/Support/Unix/Signals.inc
index f9951a509c9..cf621c0cf76 100644
--- a/llvm/lib/Support/Unix/Signals.inc
+++ b/llvm/lib/Support/Unix/Signals.inc
@@ -47,6 +47,17 @@
#if HAVE_LINK_H
#include <link.h>
#endif
+#if HAVE_UNWIND_BACKTRACE
+// FIXME: We should be able to use <unwind.h> for any target that has an
+// _Unwind_Backtrace function, but on FreeBSD the configure test passes
+// despite the function not existing, and on Android, <unwind.h> conflicts
+// with <link.h>.
+#ifdef __GLIBC__
+#include <unwind.h>
+#else
+#undef HAVE_UNWIND_BACKTRACE
+#endif
+#endif
using namespace llvm;
@@ -340,17 +351,61 @@ static bool findModulesAndOffsets(void **StackTrace, int Depth,
}
#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
// 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
// doesn't demangle symbols.
void llvm::sys::PrintStackTrace(raw_ostream &OS) {
-#if defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES)
- static void* StackTrace[256];
+#if defined(ENABLE_BACKTRACES)
+ static void *StackTrace[256];
+ int depth = 0;
+#if defined(HAVE_BACKTRACE)
// 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)));
+#endif
+ if (!depth)
+ return;
+
if (printSymbolizedStackTrace(StackTrace, depth, OS))
return;
#if HAVE_DLFCN_H && __GNUG__
@@ -400,7 +455,7 @@ void llvm::sys::PrintStackTrace(raw_ostream &OS) {
}
OS << '\n';
}
-#else
+#elif defined(HAVE_BACKTRACE)
backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO);
#endif
#endif
OpenPOWER on IntegriCloud