aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Samsonov <vonosmas@gmail.com>2014-10-08 22:57:47 +0000
committerAlexey Samsonov <vonosmas@gmail.com>2014-10-08 22:57:47 +0000
commitd88aa97cbda29d16ae4a52775b8246ce219f57be (patch)
tree8aebd8411318d3a163f68e8c263c45c99933f097
parent7a18a385f05802333fcd0df4ad228bcf47a13b22 (diff)
downloadllvm-d88aa97cbda29d16ae4a52775b8246ce219f57be.zip
llvm-d88aa97cbda29d16ae4a52775b8246ce219f57be.tar.gz
llvm-d88aa97cbda29d16ae4a52775b8246ce219f57be.tar.bz2
Use llvm-symbolizer to symbolize LLVM/Clang crash dumps.
This change modifies fatal signal handler used in LLVM tools. Now it attempts to find llvm-symbolizer binary and communicates with it in order to turn instruction addresses into function/file/line info entries. This should significantly improve stack traces readability in Debug builds. This feature only works on selected platforms (including Darwin and Linux). If the symbolization fails for some reason, signal handler will fallback to the original behavior. Reviewed in http://reviews.llvm.org/D5610 llvm-svn: 219354
-rwxr-xr-xllvm/cmake/config-ix.cmake1
-rw-r--r--llvm/include/llvm/Config/config.h.cmake3
-rw-r--r--llvm/lib/Support/Unix/Signals.inc140
3 files changed, 143 insertions, 1 deletions
diff --git a/llvm/cmake/config-ix.cmake b/llvm/cmake/config-ix.cmake
index 2976238..849da2d 100755
--- a/llvm/cmake/config-ix.cmake
+++ b/llvm/cmake/config-ix.cmake
@@ -50,6 +50,7 @@ check_include_file(execinfo.h HAVE_EXECINFO_H)
check_include_file(fcntl.h HAVE_FCNTL_H)
check_include_file(inttypes.h HAVE_INTTYPES_H)
check_include_file(limits.h HAVE_LIMITS_H)
+check_include_file(link.h HAVE_LINK_H)
check_include_file(malloc.h HAVE_MALLOC_H)
check_include_file(malloc/malloc.h HAVE_MALLOC_MALLOC_H)
check_include_file(ndir.h HAVE_NDIR_H)
diff --git a/llvm/include/llvm/Config/config.h.cmake b/llvm/include/llvm/Config/config.h.cmake
index 996f9ba..0ab765b 100644
--- a/llvm/include/llvm/Config/config.h.cmake
+++ b/llvm/include/llvm/Config/config.h.cmake
@@ -188,6 +188,9 @@
/* Define to 1 if you have the <limits.h> header file. */
#cmakedefine HAVE_LIMITS_H ${HAVE_LIMITS_H}
+/* Define to 1 if you have the <link.h> header file. */
+#cmakedefine HAVE_LINK_H ${HAVE_LINK_H}
+
/* Define if you can use -rdynamic. */
#define HAVE_LINK_EXPORT_DYNAMIC 1
diff --git a/llvm/lib/Support/Unix/Signals.inc b/llvm/lib/Support/Unix/Signals.inc
index 592674e..9291b617 100644
--- a/llvm/lib/Support/Unix/Signals.inc
+++ b/llvm/lib/Support/Unix/Signals.inc
@@ -14,9 +14,14 @@
#include "Unix.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Mutex.h"
+#include "llvm/Support/Program.h"
#include "llvm/Support/UniqueLock.h"
-#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <string>
#include <vector>
@@ -38,6 +43,9 @@
#if HAVE_MACH_MACH_H
#include <mach/mach.h>
#endif
+#if HAVE_LINK_H
+#include <link.h>
+#endif
using namespace llvm;
@@ -264,6 +272,134 @@ void llvm::sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) {
RegisterHandlers();
}
+#if HAVE_LINK_H
+struct DlIteratePhdrData {
+ void **StackTrace;
+ int depth;
+ bool first;
+ const char **modules;
+ intptr_t *offsets;
+ const char *main_exec_name;
+};
+
+static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
+ DlIteratePhdrData *data = (DlIteratePhdrData*)arg;
+ const char *name = data->first ? data->main_exec_name : info->dlpi_name;
+ data->first = false;
+ for (int i = 0; i < info->dlpi_phnum; i++) {
+ const ElfW(Phdr) *phdr = &info->dlpi_phdr[i];
+ if (phdr->p_type != PT_LOAD)
+ continue;
+ intptr_t beg = info->dlpi_addr + phdr->p_vaddr;
+ intptr_t end = beg + phdr->p_memsz;
+ for (int j = 0; j < data->depth; j++) {
+ if (data->modules[j])
+ continue;
+ intptr_t addr = (intptr_t)data->StackTrace[j];
+ if (beg <= addr && addr < end) {
+ data->modules[j] = name;
+ data->offsets[j] = addr - info->dlpi_addr;
+ }
+ }
+ }
+ return 0;
+}
+
+static bool findModulesAndOffsets(void **StackTrace, int Depth,
+ const char **Modules, intptr_t *Offsets,
+ const char *MainExecutableName) {
+ DlIteratePhdrData data = {StackTrace, Depth, true,
+ Modules, Offsets, MainExecutableName};
+ dl_iterate_phdr(dl_iterate_phdr_cb, &data);
+ return true;
+}
+#else
+static bool findModulesAndOffsets(void **StackTrace, int Depth,
+ const char **Modules, intptr_t *Offsets,
+ const char *MainExecutableName) {
+ return false;
+}
+#endif
+
+static bool printSymbolizedStackTrace(void **StackTrace, int Depth, FILE *FD) {
+ // FIXME: Subtract necessary number from StackTrace entries to turn return addresses
+ // into actual instruction addresses.
+ // Use llvm-symbolizer tool to symbolize the stack traces.
+ std::string LLVMSymbolizerPath = sys::FindProgramByName("llvm-symbolizer");
+ if (LLVMSymbolizerPath.empty())
+ return false;
+ // We don't know argv0 or the address of main() at this point, but try
+ // to guess it anyway (it's possible on some platforms).
+ std::string MainExecutableName = sys::fs::getMainExecutable(nullptr, nullptr);
+ if (MainExecutableName.empty() ||
+ MainExecutableName.find("llvm-symbolizer") != std::string::npos)
+ return false;
+
+ std::vector<const char *> Modules(Depth, nullptr);
+ std::vector<intptr_t> Offsets(Depth, 0);
+ if (!findModulesAndOffsets(StackTrace, Depth, Modules.data(), Offsets.data(),
+ MainExecutableName.c_str()))
+ return false;
+ int InputFD;
+ SmallString<32> InputFile, OutputFile;
+ sys::fs::createTemporaryFile("symbolizer-input", "", InputFD, InputFile);
+ sys::fs::createTemporaryFile("symbolizer-output", "", OutputFile);
+ FileRemover InputRemover(InputFile.c_str());
+ FileRemover OutputRemover(OutputFile.c_str());
+ std::vector<const StringRef *> Redirects(3, nullptr);
+ StringRef InputFileStr(InputFile);
+ StringRef OutputFileStr(OutputFile);
+ StringRef StderrFileStr;
+ Redirects[0] = &InputFileStr;
+ Redirects[1] = &OutputFileStr;
+ Redirects[2] = &StderrFileStr;
+
+ {
+ raw_fd_ostream Input(InputFD, true);
+ for (int i = 0; i < Depth; i++) {
+ if (Modules[i])
+ Input << Modules[i] << " " << (void*)Offsets[i] << "\n";
+ }
+ }
+
+ const char *args[] = {"llvm-symbolizer", nullptr};
+ int RunResult =
+ sys::ExecuteAndWait(LLVMSymbolizerPath, args, nullptr, Redirects.data());
+ if (RunResult != 0)
+ return false;
+
+ auto OutputBuf = MemoryBuffer::getFile(OutputFile.c_str());
+ if (std::error_code Err = OutputBuf.getError())
+ return false;
+ StringRef Output = OutputBuf.get()->getBuffer();
+ SmallVector<StringRef, 32> Lines;
+ Output.split(Lines, "\n");
+ auto CurLine = Lines.begin();
+ int frame_no = 0;
+ for (int i = 0; i < Depth; i++) {
+ if (!Modules[i]) {
+ fprintf(FD, "#%d %p\n", frame_no++, StackTrace[i]);
+ continue;
+ }
+ // Read pairs of lines (function name and file/line info) until we
+ // encounter empty line.
+ for (;;) {
+ StringRef FunctionName = *CurLine++;
+ if (FunctionName.empty())
+ break;
+ fprintf(FD, "#%d %p ", frame_no++, StackTrace[i]);
+ if (!FunctionName.startswith("??"))
+ fprintf(FD, "%s ", FunctionName.str().c_str());
+ StringRef FileLineInfo = *CurLine++;
+ if (!FileLineInfo.startswith("??"))
+ fprintf(FD, "%s", FileLineInfo.str().c_str());
+ else
+ fprintf(FD, "(%s+%p)", Modules[i], (void *)Offsets[i]);
+ fprintf(FD, "\n");
+ }
+ }
+ return true;
+}
// 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.
@@ -276,6 +412,8 @@ void llvm::sys::PrintStackTrace(FILE *FD) {
// Use backtrace() to output a backtrace on Linux systems with glibc.
int depth = backtrace(StackTrace,
static_cast<int>(array_lengthof(StackTrace)));
+ if (printSymbolizedStackTrace(StackTrace, depth, FD))
+ return;
#if HAVE_DLFCN_H && __GNUG__
int width = 0;
for (int i = 0; i < depth; ++i) {