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:
Alexey Samsonov 2014-10-10 22:06:59 +00:00
parent 968e1f2f5b
commit fcc00a10e3
3 changed files with 145 additions and 2 deletions

View File

@ -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)

View File

@ -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

View File

@ -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) {