+static bool CriticalSectionInitialized = false;
+
+enum {
+#if defined(_M_X64)
+ NativeMachineType = IMAGE_FILE_MACHINE_AMD64
+#else
+ 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];
+ size_t 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(NativeMachineType, hProcess, hThread, &StackFrame,
+ Context, 0, fSymFunctionTableAccess64,
+ fSymGetModuleBase64, 0)) {
+ break;
+ }
+
+ if (StackFrame.AddrFrame.Offset == 0)
+ break;
+
+ using namespace llvm;
+ // Print the PC in hexadecimal.
+ DWORD64 PC = StackFrame.AddrPC.Offset;
+#if defined(_M_X64)
+ OS << format("0x%016llX", PC);
+#elif defined(_M_IX86)
+ OS << format("0x%08lX", static_cast<DWORD>(PC));
+#endif
+
+// Print the parameters. Assume there are four.
+#if defined(_M_X64)
+ OS << format(" (0x%016llX 0x%016llX 0x%016llX 0x%016llX)",
+ StackFrame.Params[0], StackFrame.Params[1], StackFrame.Params[2],
+ StackFrame.Params[3]);
+#elif defined(_M_IX86)
+ OS << format(" (0x%08lX 0x%08lX 0x%08lX 0x%08lX)",
+ static_cast<DWORD>(StackFrame.Params[0]),
+ static_cast<DWORD>(StackFrame.Params[1]),
+ static_cast<DWORD>(StackFrame.Params[2]),
+ static_cast<DWORD>(StackFrame.Params[3]));
+#endif
+ // Verify the PC belongs to a module in this process.
+ if (!fSymGetModuleBase64(hProcess, PC)) {
+ OS << " <unknown module>\n";
+ continue;
+ }
+
+ // Print the symbol name.
+ char buffer[512];
+ IMAGEHLP_SYMBOL64 *symbol = reinterpret_cast<IMAGEHLP_SYMBOL64 *>(buffer);
+ memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL64));
+ symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
+ symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL64);
+
+ DWORD64 dwDisp;
+ if (!fSymGetSymFromAddr64(hProcess, PC, &dwDisp, symbol)) {
+ OS << '\n';
+ continue;
+ }
+
+ buffer[511] = 0;
+ if (dwDisp > 0)
+ OS << format(", %s() + 0x%llX bytes(s)", (const char*)symbol->Name,
+ dwDisp);
+ else
+ OS << format(", %s", (const char*)symbol->Name);
+
+ // Print the source file and line number information.
+ IMAGEHLP_LINE64 line = {};
+ DWORD dwLineDisp;
+ line.SizeOfStruct = sizeof(line);
+ if (fSymGetLineFromAddr64(hProcess, PC, &dwLineDisp, &line)) {
+ OS << format(", %s, line %lu", line.FileName, line.LineNumber);
+ if (dwLineDisp > 0)
+ OS << format(" + 0x%lX byte(s)", dwLineDisp);
+ }
+
+ OS << '\n';
+ }
+}