Index: lib/Support/Unix/Signals.inc =================================================================== --- lib/Support/Unix/Signals.inc +++ 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 #include #include @@ -38,6 +43,7 @@ #if HAVE_MACH_MACH_H #include #endif +#include using namespace llvm; @@ -264,6 +270,118 @@ RegisterHandlers(); } +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 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::vectormodules(Depth, nullptr); + std::vector offsets(Depth, 0); + DlIteratePhdrData data = {StackTrace, Depth, + true, modules.data(), + offsets.data(), MainExecutableName.c_str()}; + dl_iterate_phdr(dl_iterate_phdr_cb, &data); + 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 Redirects(3, nullptr); + auto InputFileStr = llvm::make_unique(InputFile); + auto OutputFileStr = llvm::make_unique(OutputFile); + auto StderrFileStr = llvm::make_unique(); + Redirects[0] = InputFileStr.get(); + Redirects[1] = OutputFileStr.get(); + Redirects[2] = StderrFileStr.get(); + + { + 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 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 +394,8 @@ // Use backtrace() to output a backtrace on Linux systems with glibc. int depth = backtrace(StackTrace, static_cast(array_lengthof(StackTrace))); + if (printSymbolizedStackTrace(StackTrace, depth, FD)) + return; #if HAVE_DLFCN_H && __GNUG__ int width = 0; for (int i = 0; i < depth; ++i) {