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