16e893b61094a3bfb1a9f92fb019dd6fb153076b5Alexey Samsonov//===-- sanitizer_symbolizer_win.cc ---------------------------------------===//
26e893b61094a3bfb1a9f92fb019dd6fb153076b5Alexey Samsonov//
36e893b61094a3bfb1a9f92fb019dd6fb153076b5Alexey Samsonov//                     The LLVM Compiler Infrastructure
46e893b61094a3bfb1a9f92fb019dd6fb153076b5Alexey Samsonov//
56e893b61094a3bfb1a9f92fb019dd6fb153076b5Alexey Samsonov// This file is distributed under the University of Illinois Open Source
66e893b61094a3bfb1a9f92fb019dd6fb153076b5Alexey Samsonov// License. See LICENSE.TXT for details.
76e893b61094a3bfb1a9f92fb019dd6fb153076b5Alexey Samsonov//
86e893b61094a3bfb1a9f92fb019dd6fb153076b5Alexey Samsonov//===----------------------------------------------------------------------===//
96e893b61094a3bfb1a9f92fb019dd6fb153076b5Alexey Samsonov//
106e893b61094a3bfb1a9f92fb019dd6fb153076b5Alexey Samsonov// This file is shared between AddressSanitizer and ThreadSanitizer
116e893b61094a3bfb1a9f92fb019dd6fb153076b5Alexey Samsonov// run-time libraries.
126e893b61094a3bfb1a9f92fb019dd6fb153076b5Alexey Samsonov// Windows-specific implementation of symbolizer parts.
136e893b61094a3bfb1a9f92fb019dd6fb153076b5Alexey Samsonov//===----------------------------------------------------------------------===//
1424e13723f8477d8c42ab8b2a7f4f69fc089842f1Evgeniy Stepanov
1524e13723f8477d8c42ab8b2a7f4f69fc089842f1Evgeniy Stepanov#include "sanitizer_platform.h"
1630e110edf92303237d471f1cb8e3ad07954fb145Evgeniy Stepanov#if SANITIZER_WINDOWS
172d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#include <windows.h>
182d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#include <dbghelp.h>
192d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#pragma comment(lib, "dbghelp.lib")
202d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
217c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar#include "sanitizer_symbolizer_win.h"
227c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar#include "sanitizer_symbolizer_internal.h"
236e893b61094a3bfb1a9f92fb019dd6fb153076b5Alexey Samsonov
246e893b61094a3bfb1a9f92fb019dd6fb153076b5Alexey Samsonovnamespace __sanitizer {
256e893b61094a3bfb1a9f92fb019dd6fb153076b5Alexey Samsonov
267c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainarnamespace {
272d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
287c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainarbool is_dbghelp_initialized = false;
297c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar
307c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainarbool TrySymInitialize() {
317c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES);
327c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  return SymInitialize(GetCurrentProcess(), 0, TRUE);
337c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  // FIXME: We don't call SymCleanup() on exit yet - should we?
347c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar}
357c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar
367c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar// Initializes DbgHelp library, if it's not yet initialized. Calls to this
377c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar// function should be synchronized with respect to other calls to DbgHelp API
387c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar// (e.g. from WinSymbolizerTool).
397c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainarvoid InitializeDbgHelpIfNeeded() {
407c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  if (is_dbghelp_initialized)
417c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    return;
427c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  if (!TrySymInitialize()) {
437c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    // OK, maybe the client app has called SymInitialize already.
447c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    // That's a bit unfortunate for us as all the DbgHelp functions are
457c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    // single-threaded and we can't coordinate with the app.
467c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    // FIXME: Can we stop the other threads at this point?
477c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    // Anyways, we have to reconfigure stuff to make sure that SymInitialize
487c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    // has all the appropriate options set.
497c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    // Cross our fingers and reinitialize DbgHelp.
507c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    Report("*** WARNING: Failed to initialize DbgHelp!              ***\n");
517c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    Report("*** Most likely this means that the app is already      ***\n");
527c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    Report("*** using DbgHelp, possibly with incompatible flags.    ***\n");
537c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    Report("*** Due to technical reasons, symbolization might crash ***\n");
547c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    Report("*** or produce wrong results.                           ***\n");
557c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    SymCleanup(GetCurrentProcess());
567c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    TrySymInitialize();
577c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  }
587c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  is_dbghelp_initialized = true;
597c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar
607c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  // When an executable is run from a location different from the one where it
617c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  // was originally built, we may not see the nearby PDB files.
627c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  // To work around this, let's append the directory of the main module
637c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  // to the symbol search path.  All the failures below are not fatal.
647c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  const size_t kSymPathSize = 2048;
657c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  static wchar_t path_buffer[kSymPathSize + 1 + MAX_PATH];
667c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  if (!SymGetSearchPathW(GetCurrentProcess(), path_buffer, kSymPathSize)) {
677c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    Report("*** WARNING: Failed to SymGetSearchPathW ***\n");
687c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    return;
697c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  }
707c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  size_t sz = wcslen(path_buffer);
717c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  if (sz) {
727c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    CHECK_EQ(0, wcscat_s(path_buffer, L";"));
737c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    sz++;
742d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  }
757c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  DWORD res = GetModuleFileNameW(NULL, path_buffer + sz, MAX_PATH);
767c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  if (res == 0 || res == MAX_PATH) {
777c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    Report("*** WARNING: Failed to getting the EXE directory ***\n");
787c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    return;
797c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  }
807c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  // Write the zero character in place of the last backslash to get the
817c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  // directory of the main module at the end of path_buffer.
827c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  wchar_t *last_bslash = wcsrchr(path_buffer + sz, L'\\');
837c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  CHECK_NE(last_bslash, 0);
847c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  *last_bslash = L'\0';
857c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  if (!SymSetSearchPathW(GetCurrentProcess(), path_buffer)) {
867c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    Report("*** WARNING: Failed to SymSetSearchPathW\n");
877c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    return;
887c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  }
897c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar}
902d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
917c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar}  // namespace
927c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar
937c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainarbool WinSymbolizerTool::SymbolizePC(uptr addr, SymbolizedStack *frame) {
947c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  InitializeDbgHelpIfNeeded();
957c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar
967c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
977c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)];
987c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
997c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
1007c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  symbol->MaxNameLen = MAX_SYM_NAME;
1017c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  DWORD64 offset = 0;
1027c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  BOOL got_objname = SymFromAddr(GetCurrentProcess(),
1037c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar                                 (DWORD64)addr, &offset, symbol);
1047c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  if (!got_objname)
1057c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    return false;
1067c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar
1077c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  DWORD unused;
1087c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  IMAGEHLP_LINE64 line_info;
1097c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  line_info.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
1107c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(), (DWORD64)addr,
1117c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar                                           &unused, &line_info);
1127c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  frame->info.function = internal_strdup(symbol->Name);
1137c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  frame->info.function_offset = (uptr)offset;
1147c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  if (got_fileline) {
1157c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    frame->info.file = internal_strdup(line_info.FileName);
1167c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    frame->info.line = line_info.LineNumber;
1172d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  }
1187c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  return true;
1197c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar}
1202d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
1217c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainarconst char *WinSymbolizerTool::Demangle(const char *name) {
1227c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  CHECK(is_dbghelp_initialized);
1237c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  static char demangle_buffer[1000];
1247c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  if (name[0] == '\01' &&
1257c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar      UnDecorateSymbolName(name + 1, demangle_buffer, sizeof(demangle_buffer),
1267c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar                           UNDNAME_NAME_ONLY))
1277c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    return demangle_buffer;
1287c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  else
1297c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    return name;
1307c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar}
1312d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
132909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainarconst char *Symbolizer::PlatformDemangle(const char *name) {
133909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar  return name;
1347c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar}
1356d1862363c88c183b0ed7740fca876342cf0474bStephen Hines
136909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainarvoid Symbolizer::PlatformPrepareForSandboxing() {
137909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar  // Do nothing.
138909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar}
1392d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
1406d1862363c88c183b0ed7740fca876342cf0474bStephen HinesSymbolizer *Symbolizer::PlatformInit() {
1417c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  IntrusiveList<SymbolizerTool> list;
1427c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  list.clear();
1437c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  list.push_back(new(symbolizer_allocator_) WinSymbolizerTool());
144909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar  return new(symbolizer_allocator_) Symbolizer(list);
1452d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
146ab6374326389ff649ad857842b45488721c949dbRichard Smith
1476e893b61094a3bfb1a9f92fb019dd6fb153076b5Alexey Samsonov}  // namespace __sanitizer
1486e893b61094a3bfb1a9f92fb019dd6fb153076b5Alexey Samsonov
1496e893b61094a3bfb1a9f92fb019dd6fb153076b5Alexey Samsonov#endif  // _WIN32
150