[llvm] r252118 - [Windows] Symbolize with llvm-symbolizer instead of dbghelp in a self-host

Mehdi Amini via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 4 18:34:52 PST 2015


Hi Reid,

It seems that this commit broke the OS X build, I tried to fix it in r252137, can you take a look?

Thanks,

Mehdi

> On Nov 4, 2015, at 5:07 PM, Reid Kleckner via llvm-commits <llvm-commits at lists.llvm.org> wrote:
> 
> Author: rnk
> Date: Wed Nov  4 19:07:54 2015
> New Revision: 252118
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=252118&view=rev
> Log:
> [Windows] Symbolize with llvm-symbolizer instead of dbghelp in a self-host
> 
> Summary:
> llvm-symbolizer understands both PDBs and DWARF, so it is more likely to
> succeed at symbolization. If llvm-symbolizer is unavailable, we will
> fall back to dbghelp. This also makes our crash traces more similar
> between Windows and Linux.
> 
> Reviewers: Bigcheese, zturner, chapuni
> 
> Subscribers: llvm-commits
> 
> Differential Revision: http://reviews.llvm.org/D12884
> 
> Modified:
>    llvm/trunk/lib/Support/Signals.cpp
>    llvm/trunk/lib/Support/Unix/Signals.inc
>    llvm/trunk/lib/Support/Windows/Signals.inc
> 
> Modified: llvm/trunk/lib/Support/Signals.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Signals.cpp?rev=252118&r1=252117&r2=252118&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Support/Signals.cpp (original)
> +++ llvm/trunk/lib/Support/Signals.cpp Wed Nov  4 19:07:54 2015
> @@ -12,10 +12,20 @@
> //
> //===----------------------------------------------------------------------===//
> 
> +#include "llvm/ADT/STLExtras.h"
> +#include "llvm/ADT/StringRef.h"
> #include "llvm/Config/config.h"
> +#include "llvm/Support/ErrorOr.h"
> +#include "llvm/Support/FileSystem.h"
> +#include "llvm/Support/FileUtilities.h"
> +#include "llvm/Support/Format.h"
> #include "llvm/Support/ManagedStatic.h"
> +#include "llvm/Support/MemoryBuffer.h"
> +#include "llvm/Support/Mutex.h"
> +#include "llvm/Support/Program.h"
> #include "llvm/Support/Signals.h"
> -
> +#include "llvm/Support/StringSaver.h"
> +#include "llvm/Support/raw_ostream.h"
> #include <vector>
> 
> namespace llvm {
> @@ -37,6 +47,118 @@ void sys::RunSignalHandlers() {
> }
> }
> 
> +using namespace llvm;
> +
> +static bool findModulesAndOffsets(void **StackTrace, int Depth,
> +                                  const char **Modules, intptr_t *Offsets,
> +                                  const char *MainExecutableName,
> +                                  StringSaver &StrPool);
> +
> +/// Format a pointer value as hexadecimal. Zero pad it out so its always the
> +/// same width.
> +static FormattedNumber format_ptr(void *PC) {
> +  // Each byte is two hex digits plus 2 for the 0x prefix.
> +  unsigned PtrWidth = 2 + 2 * sizeof(void *);
> +  return format_hex((uint64_t)PC, PtrWidth);
> +}
> +
> +/// Helper that launches llvm-symbolizer and symbolizes a backtrace.
> +static bool printSymbolizedStackTrace(void **StackTrace, int Depth,
> +                                      llvm::raw_ostream &OS) {
> +  // FIXME: Subtract necessary number from StackTrace entries to turn return addresses
> +  // into actual instruction addresses.
> +  // Use llvm-symbolizer tool to symbolize the stack traces.
> +  ErrorOr<std::string> LLVMSymbolizerPathOrErr =
> +      sys::findProgramByName("llvm-symbolizer");
> +  if (!LLVMSymbolizerPathOrErr)
> +    return false;
> +  const std::string &LLVMSymbolizerPath = *LLVMSymbolizerPathOrErr;
> +  // 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;
> +
> +  BumpPtrAllocator Allocator;
> +  StringSaver StrPool(Allocator);
> +  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(), StrPool))
> +    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());
> +
> +  {
> +    raw_fd_ostream Input(InputFD, true);
> +    for (int i = 0; i < Depth; i++) {
> +      if (Modules[i])
> +        Input << Modules[i] << " " << (void*)Offsets[i] << "\n";
> +    }
> +  }
> +
> +  StringRef InputFileStr(InputFile);
> +  StringRef OutputFileStr(OutputFile);
> +  StringRef StderrFileStr;
> +  const StringRef *Redirects[] = {&InputFileStr, &OutputFileStr,
> +                                  &StderrFileStr};
> +  const char *Args[] = {"llvm-symbolizer", "--functions=linkage", "--inlining",
> +#ifdef LLVM_ON_WIN32
> +                        // Pass --relative-address on Windows so that we don't
> +                        // have to add ImageBase from PE file.
> +                        // FIXME: Make this the default for llvm-symbolizer.
> +                        "--relative-address",
> +#endif
> +                        "--demangle", nullptr};
> +  int RunResult =
> +      sys::ExecuteAndWait(LLVMSymbolizerPath, Args, nullptr, Redirects);
> +  if (RunResult != 0)
> +    return false;
> +
> +  // This report format is based on the sanitizer stack trace printer.  See
> +  // sanitizer_stacktrace_printer.cc in compiler-rt.
> +  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]) {
> +      OS << '#' << frame_no++ << ' ' << format_ptr(StackTrace[i]) << '\n';
> +      continue;
> +    }
> +    // Read pairs of lines (function name and file/line info) until we
> +    // encounter empty line.
> +    for (;;) {
> +      if (CurLine == Lines.end())
> +        return false;
> +      StringRef FunctionName = *CurLine++;
> +      if (FunctionName.empty())
> +        break;
> +      OS << '#' << frame_no++ << ' ' << format_ptr(StackTrace[i]) << ' ';
> +      if (!FunctionName.startswith("??"))
> +        OS << FunctionName << ' ';
> +      if (CurLine == Lines.end())
> +        return false;
> +      StringRef FileLineInfo = *CurLine++;
> +      if (!FileLineInfo.startswith("??"))
> +        OS << FileLineInfo;
> +      else
> +        OS << "(" << Modules[i] << '+' << format_hex(Offsets[i], 0) << ")";
> +      OS << "\n";
> +    }
> +  }
> +  return true;
> +}
> +
> // Include the platform-specific parts of this class.
> #ifdef LLVM_ON_UNIX
> #include "Unix/Signals.inc"
> 
> Modified: llvm/trunk/lib/Support/Unix/Signals.inc
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Unix/Signals.inc?rev=252118&r1=252117&r2=252118&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Support/Unix/Signals.inc (original)
> +++ llvm/trunk/lib/Support/Unix/Signals.inc Wed Nov  4 19:07:54 2015
> @@ -291,7 +291,8 @@ static int dl_iterate_phdr_cb(dl_phdr_in
> 
> static bool findModulesAndOffsets(void **StackTrace, int Depth,
>                                   const char **Modules, intptr_t *Offsets,
> -                                  const char *MainExecutableName) {
> +                                  const char *MainExecutableName,
> +                                  StringSaver &StrPool) {
>   DlIteratePhdrData data = {StackTrace, Depth,   true,
>                             Modules,    Offsets, MainExecutableName};
>   dl_iterate_phdr(dl_iterate_phdr_cb, &data);
> @@ -304,92 +305,6 @@ static bool findModulesAndOffsets(void *
>   return false;
> }
> #endif
> -
> -static bool printSymbolizedStackTrace(void **StackTrace, int Depth,
> -                                      llvm::raw_ostream &OS) {
> -  // FIXME: Subtract necessary number from StackTrace entries to turn return addresses
> -  // into actual instruction addresses.
> -  // Use llvm-symbolizer tool to symbolize the stack traces.
> -  ErrorOr<std::string> LLVMSymbolizerPathOrErr =
> -      sys::findProgramByName("llvm-symbolizer");
> -  if (!LLVMSymbolizerPathOrErr)
> -    return false;
> -  const std::string &LLVMSymbolizerPath = *LLVMSymbolizerPathOrErr;
> -  // 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());
> -
> -  {
> -    raw_fd_ostream Input(InputFD, true);
> -    for (int i = 0; i < Depth; i++) {
> -      if (Modules[i])
> -        Input << Modules[i] << " " << (void*)Offsets[i] << "\n";
> -    }
> -  }
> -
> -  StringRef InputFileStr(InputFile);
> -  StringRef OutputFileStr(OutputFile);
> -  StringRef StderrFileStr;
> -  const StringRef *Redirects[] = {&InputFileStr, &OutputFileStr,
> -                                  &StderrFileStr};
> -  const char *Args[] = {"llvm-symbolizer", "--functions=linkage", "--inlining",
> -                        "--demangle", nullptr};
> -  int RunResult =
> -      sys::ExecuteAndWait(LLVMSymbolizerPath, Args, nullptr, Redirects);
> -  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]) {
> -      OS << format("#%d %p\n", frame_no++, StackTrace[i]);
> -      continue;
> -    }
> -    // Read pairs of lines (function name and file/line info) until we
> -    // encounter empty line.
> -    for (;;) {
> -      if (CurLine == Lines.end())
> -        return false;
> -      StringRef FunctionName = *CurLine++;
> -      if (FunctionName.empty())
> -        break;
> -      OS << format("#%d %p ", frame_no++, StackTrace[i]);
> -      if (!FunctionName.startswith("??"))
> -        OS << format("%s ", FunctionName.str().c_str());
> -      if (CurLine == Lines.end())
> -        return false;
> -      StringRef FileLineInfo = *CurLine++;
> -      if (!FileLineInfo.startswith("??"))
> -        OS << format("%s", FileLineInfo.str().c_str());
> -      else
> -        OS << format("(%s+%p)", Modules[i], (void *)Offsets[i]);
> -      OS << "\n";
> -    }
> -  }
> -  return true;
> -}
> #endif // defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES)
> 
> // PrintStackTrace - In the case of a program crash or fault, print out a stack
> 
> Modified: llvm/trunk/lib/Support/Windows/Signals.inc
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Windows/Signals.inc?rev=252118&r1=252117&r2=252118&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Support/Windows/Signals.inc (original)
> +++ llvm/trunk/lib/Support/Windows/Signals.inc Wed Nov  4 19:07:54 2015
> @@ -135,6 +135,10 @@ typedef BOOL (WINAPI *fpSymGetLineFromAd
>                       PDWORD, PIMAGEHLP_LINE64);
> static fpSymGetLineFromAddr64 fSymGetLineFromAddr64;
> 
> +typedef BOOL(WINAPI *fpSymGetModuleInfo64)(HANDLE hProcess, DWORD64 dwAddr,
> +                                           PIMAGEHLP_MODULE64 ModuleInfo);
> +static fpSymGetModuleInfo64 fSymGetModuleInfo64;
> +
> typedef PVOID (WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64);
> static fpSymFunctionTableAccess64 fSymFunctionTableAccess64;
> 
> @@ -144,6 +148,9 @@ static fpSymSetOptions fSymSetOptions;
> typedef BOOL (WINAPI *fpSymInitialize)(HANDLE, PCSTR, BOOL);
> static fpSymInitialize fSymInitialize;
> 
> +typedef BOOL (WINAPI *fpEnumerateLoadedModules)(HANDLE,PENUMLOADED_MODULES_CALLBACK64,PVOID);
> +static fpEnumerateLoadedModules fEnumerateLoadedModules;
> +
> static bool load64BitDebugHelp(void) {
>   HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll");
>   if (hLib) {
> @@ -155,10 +162,14 @@ static bool load64BitDebugHelp(void) {
>                       ::GetProcAddress(hLib, "SymGetSymFromAddr64");
>     fSymGetLineFromAddr64 = (fpSymGetLineFromAddr64)
>                       ::GetProcAddress(hLib, "SymGetLineFromAddr64");
> +    fSymGetModuleInfo64 = (fpSymGetModuleInfo64)
> +                      ::GetProcAddress(hLib, "SymGetModuleInfo64");
>     fSymFunctionTableAccess64 = (fpSymFunctionTableAccess64)
>                      ::GetProcAddress(hLib, "SymFunctionTableAccess64");
>     fSymSetOptions = (fpSymSetOptions)::GetProcAddress(hLib, "SymSetOptions");
>     fSymInitialize = (fpSymInitialize)::GetProcAddress(hLib, "SymInitialize");
> +    fEnumerateLoadedModules = (fpEnumerateLoadedModules)
> +      ::GetProcAddress(hLib, "EnumerateLoadedModules64");
>   }
>   return fStackWalk64 && fSymInitialize && fSymSetOptions;
> }
> @@ -183,23 +194,106 @@ static PTOP_LEVEL_EXCEPTION_FILTER OldFi
> static CRITICAL_SECTION CriticalSection;
> static bool CriticalSectionInitialized = false;
> 
> -static void PrintStackTraceForThread(llvm::raw_ostream &OS, HANDLE hProcess,
> -                                     HANDLE hThread, STACKFRAME64 &StackFrame,
> -                                     CONTEXT *Context) {
> -  DWORD machineType;
> +enum {
> #if defined(_M_X64)
> -  machineType = IMAGE_FILE_MACHINE_AMD64;
> +  NativeMachineType = IMAGE_FILE_MACHINE_AMD64
> #else
> -  machineType = IMAGE_FILE_MACHINE_I386;
> +  NativeMachineType = IMAGE_FILE_MACHINE_I386
> #endif
> +};
> +
> +static bool printStackTraceWithLLVMSymbolizer(llvm::raw_ostream &OS,
> +                                              HANDLE hProcess, HANDLE hThread,
> +                                              STACKFRAME64 &StackFrameOrig,
> +                                              CONTEXT *ContextOrig) {
> +  // StackWalk64 modifies the incoming stack frame and context, so copy them.
> +  STACKFRAME64 StackFrame = StackFrameOrig;
> +
> +  // Copy the register context so that we don't modify it while we unwind. We
> +  // could use InitializeContext + CopyContext, but that's only required to get
> +  // at AVX registers, which typically aren't needed by StackWalk64. Reduce the
> +  // flag set to indicate that there's less data.
> +  CONTEXT Context = *ContextOrig;
> +  Context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
> +
> +  static void *StackTrace[256];
> +  int Depth = 0;
> +  while (fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame,
> +                      &Context, 0, fSymFunctionTableAccess64,
> +                      fSymGetModuleBase64, 0)) {
> +    if (StackFrame.AddrFrame.Offset == 0)
> +      break;
> +    StackTrace[Depth++] = (void *)(uintptr_t)StackFrame.AddrPC.Offset;
> +    if (Depth >= array_lengthof(StackTrace))
> +      break;
> +  }
> 
> +  return printSymbolizedStackTrace(&StackTrace[0], Depth, OS);
> +}
> +
> +namespace {
> +struct FindModuleData {
> +  void **StackTrace;
> +  int Depth;
> +  const char **Modules;
> +  intptr_t *Offsets;
> +  StringSaver *StrPool;
> +};
> +}
> +
> +static BOOL CALLBACK findModuleCallback(WIN32_ELMCB_PCSTR ModuleName,
> +                                        DWORD64 ModuleBase, ULONG ModuleSize,
> +                                        void *VoidData) {
> +  FindModuleData *Data = (FindModuleData*)VoidData;
> +  intptr_t Beg = ModuleBase;
> +  intptr_t End = Beg + ModuleSize;
> +  for (int I = 0; I < Data->Depth; I++) {
> +    if (Data->Modules[I])
> +      continue;
> +    intptr_t Addr = (intptr_t)Data->StackTrace[I];
> +    if (Beg <= Addr && Addr < End) {
> +      Data->Modules[I] = Data->StrPool->save(ModuleName);
> +      Data->Offsets[I] = Addr - Beg;
> +    }
> +  }
> +  return TRUE;
> +}
> +
> +static bool findModulesAndOffsets(void **StackTrace, int Depth,
> +                                  const char **Modules, intptr_t *Offsets,
> +                                  const char *MainExecutableName,
> +                                  StringSaver &StrPool) {
> +  if (!fEnumerateLoadedModules)
> +    return false;
> +  FindModuleData Data;
> +  Data.StackTrace = StackTrace;
> +  Data.Depth = Depth;
> +  Data.Modules = Modules;
> +  Data.Offsets = Offsets;
> +  Data.StrPool = &StrPool;
> +  fEnumerateLoadedModules(GetCurrentProcess(), findModuleCallback, &Data);
> +  return true;
> +}
> +
> +static void PrintStackTraceForThread(llvm::raw_ostream &OS, HANDLE hProcess,
> +                                     HANDLE hThread, STACKFRAME64 &StackFrame,
> +                                     CONTEXT *Context) {
>   // Initialize the symbol handler.
>   fSymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES);
>   fSymInitialize(hProcess, NULL, TRUE);
> 
> +  // Try llvm-symbolizer first. llvm-symbolizer knows how to deal with both PDBs
> +  // and DWARF, so it should do a good job regardless of what debug info or
> +  // linker is in use.
> +  if (printStackTraceWithLLVMSymbolizer(OS, hProcess, hThread, StackFrame,
> +                                        Context)) {
> +    return;
> +  }
> +
>   while (true) {
> -    if (!fStackWalk64(machineType, hProcess, hThread, &StackFrame, Context, 0,
> -                      fSymFunctionTableAccess64, fSymGetModuleBase64, 0)) {
> +    if (!fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame,
> +                      Context, 0, fSymFunctionTableAccess64,
> +                      fSymGetModuleBase64, 0)) {
>       break;
>     }
> 
> @@ -404,7 +498,6 @@ extern "C" VOID WINAPI RtlCaptureContext
> #endif
> 
> void llvm::sys::PrintStackTrace(raw_ostream &OS) {
> -
>   STACKFRAME64 StackFrame = {};
>   CONTEXT Context = {};
>   ::RtlCaptureContext(&Context);
> 
> 
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits



More information about the llvm-commits mailing list