mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-16 00:17:32 +00:00
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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@219354 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
46e29705c6
commit
ee3948fdbe
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -14,9 +14,14 @@
|
||||
|
||||
#include "Unix.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/Support/Mutex.h"
|
||||
#include "llvm/Support/UniqueLock.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/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) {
|
||||
|
Loading…
Reference in New Issue
Block a user