1 //===-- sanitizer_symbolizer_win.cc ---------------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file is shared between AddressSanitizer and ThreadSanitizer
11 // run-time libraries.
12 // Windows-specific implementation of symbolizer parts.
13 //===----------------------------------------------------------------------===//
14 
15 #include "sanitizer_platform.h"
16 #if SANITIZER_WINDOWS
17 #include <windows.h>
18 #include <dbghelp.h>
19 #pragma comment(lib, "dbghelp.lib")
20 
21 #include "sanitizer_symbolizer_win.h"
22 #include "sanitizer_symbolizer_internal.h"
23 
24 namespace __sanitizer {
25 
26 namespace {
27 
28 bool is_dbghelp_initialized = false;
29 
TrySymInitialize()30 bool TrySymInitialize() {
31   SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES);
32   return SymInitialize(GetCurrentProcess(), 0, TRUE);
33   // FIXME: We don't call SymCleanup() on exit yet - should we?
34 }
35 
36 // Initializes DbgHelp library, if it's not yet initialized. Calls to this
37 // function should be synchronized with respect to other calls to DbgHelp API
38 // (e.g. from WinSymbolizerTool).
InitializeDbgHelpIfNeeded()39 void InitializeDbgHelpIfNeeded() {
40   if (is_dbghelp_initialized)
41     return;
42   if (!TrySymInitialize()) {
43     // OK, maybe the client app has called SymInitialize already.
44     // That's a bit unfortunate for us as all the DbgHelp functions are
45     // single-threaded and we can't coordinate with the app.
46     // FIXME: Can we stop the other threads at this point?
47     // Anyways, we have to reconfigure stuff to make sure that SymInitialize
48     // has all the appropriate options set.
49     // Cross our fingers and reinitialize DbgHelp.
50     Report("*** WARNING: Failed to initialize DbgHelp!              ***\n");
51     Report("*** Most likely this means that the app is already      ***\n");
52     Report("*** using DbgHelp, possibly with incompatible flags.    ***\n");
53     Report("*** Due to technical reasons, symbolization might crash ***\n");
54     Report("*** or produce wrong results.                           ***\n");
55     SymCleanup(GetCurrentProcess());
56     TrySymInitialize();
57   }
58   is_dbghelp_initialized = true;
59 
60   // When an executable is run from a location different from the one where it
61   // was originally built, we may not see the nearby PDB files.
62   // To work around this, let's append the directory of the main module
63   // to the symbol search path.  All the failures below are not fatal.
64   const size_t kSymPathSize = 2048;
65   static wchar_t path_buffer[kSymPathSize + 1 + MAX_PATH];
66   if (!SymGetSearchPathW(GetCurrentProcess(), path_buffer, kSymPathSize)) {
67     Report("*** WARNING: Failed to SymGetSearchPathW ***\n");
68     return;
69   }
70   size_t sz = wcslen(path_buffer);
71   if (sz) {
72     CHECK_EQ(0, wcscat_s(path_buffer, L";"));
73     sz++;
74   }
75   DWORD res = GetModuleFileNameW(NULL, path_buffer + sz, MAX_PATH);
76   if (res == 0 || res == MAX_PATH) {
77     Report("*** WARNING: Failed to getting the EXE directory ***\n");
78     return;
79   }
80   // Write the zero character in place of the last backslash to get the
81   // directory of the main module at the end of path_buffer.
82   wchar_t *last_bslash = wcsrchr(path_buffer + sz, L'\\');
83   CHECK_NE(last_bslash, 0);
84   *last_bslash = L'\0';
85   if (!SymSetSearchPathW(GetCurrentProcess(), path_buffer)) {
86     Report("*** WARNING: Failed to SymSetSearchPathW\n");
87     return;
88   }
89 }
90 
91 }  // namespace
92 
SymbolizePC(uptr addr,SymbolizedStack * frame)93 bool WinSymbolizerTool::SymbolizePC(uptr addr, SymbolizedStack *frame) {
94   InitializeDbgHelpIfNeeded();
95 
96   // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
97   char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)];
98   PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
99   symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
100   symbol->MaxNameLen = MAX_SYM_NAME;
101   DWORD64 offset = 0;
102   BOOL got_objname = SymFromAddr(GetCurrentProcess(),
103                                  (DWORD64)addr, &offset, symbol);
104   if (!got_objname)
105     return false;
106 
107   DWORD unused;
108   IMAGEHLP_LINE64 line_info;
109   line_info.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
110   BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(), (DWORD64)addr,
111                                            &unused, &line_info);
112   frame->info.function = internal_strdup(symbol->Name);
113   frame->info.function_offset = (uptr)offset;
114   if (got_fileline) {
115     frame->info.file = internal_strdup(line_info.FileName);
116     frame->info.line = line_info.LineNumber;
117   }
118   return true;
119 }
120 
Demangle(const char * name)121 const char *WinSymbolizerTool::Demangle(const char *name) {
122   CHECK(is_dbghelp_initialized);
123   static char demangle_buffer[1000];
124   if (name[0] == '\01' &&
125       UnDecorateSymbolName(name + 1, demangle_buffer, sizeof(demangle_buffer),
126                            UNDNAME_NAME_ONLY))
127     return demangle_buffer;
128   else
129     return name;
130 }
131 
PlatformDemangle(const char * name)132 const char *Symbolizer::PlatformDemangle(const char *name) {
133   return name;
134 }
135 
PlatformPrepareForSandboxing()136 void Symbolizer::PlatformPrepareForSandboxing() {
137   // Do nothing.
138 }
139 
PlatformInit()140 Symbolizer *Symbolizer::PlatformInit() {
141   IntrusiveList<SymbolizerTool> list;
142   list.clear();
143   list.push_back(new(symbolizer_allocator_) WinSymbolizerTool());
144   return new(symbolizer_allocator_) Symbolizer(list);
145 }
146 
147 }  // namespace __sanitizer
148 
149 #endif  // _WIN32
150