mirror of
https://github.com/RPCSX/llvm.git
synced 2024-11-28 14:10:41 +00:00
Re-land r219354: Use llvm-symbolizer to symbolize LLVM/Clang crash dumps.
In fact, symbolization is now expected to work only on Linux and FreeBSD/NetBSD, where we have dl_iterate_phdr and can learn the main executable name without argv0 (it will be possible on BSD systems after http://reviews.llvm.org/D5693 lands). #ifdef-out the code for all the rest Unix systems. Reviewed in http://reviews.llvm.org/D5610 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@219534 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
968e1f2f5b
commit
fcc00a10e3
@ -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,135 @@ void llvm::sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) {
|
||||
RegisterHandlers();
|
||||
}
|
||||
|
||||
#if HAVE_LINK_H && (defined(__linux__) || defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__) || defined(__NetBSD__))
|
||||
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 auto *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 (!OutputBuf)
|
||||
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 +413,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