Alexey Samsonov | 6e893b6 | 2012-08-14 13:00:32 +0000 | [diff] [blame] | 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 | //===----------------------------------------------------------------------===// |
Evgeniy Stepanov | 24e1372 | 2013-03-19 14:33:38 +0000 | [diff] [blame] | 14 | |
| 15 | #include "sanitizer_platform.h" |
Evgeniy Stepanov | 30e110e | 2013-03-19 14:54:17 +0000 | [diff] [blame] | 16 | #if SANITIZER_WINDOWS |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 17 | #include <windows.h> |
| 18 | #include <dbghelp.h> |
| 19 | #pragma comment(lib, "dbghelp.lib") |
| 20 | |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 21 | #include "sanitizer_symbolizer_win.h" |
| 22 | #include "sanitizer_symbolizer_internal.h" |
Alexey Samsonov | 6e893b6 | 2012-08-14 13:00:32 +0000 | [diff] [blame] | 23 | |
| 24 | namespace __sanitizer { |
| 25 | |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 26 | namespace { |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 27 | |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 28 | bool is_dbghelp_initialized = false; |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 29 | |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 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 | } |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 35 | |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 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). |
| 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(); |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 57 | } |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 58 | is_dbghelp_initialized = true; |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 59 | |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 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 | |
| 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 | |
| 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 | |
Pirama Arumuga Nainar | 259f706 | 2015-05-06 11:49:53 -0700 | [diff] [blame] | 132 | const char *Symbolizer::PlatformDemangle(const char *name) { |
| 133 | return name; |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 134 | } |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 135 | |
Pirama Arumuga Nainar | 259f706 | 2015-05-06 11:49:53 -0700 | [diff] [blame] | 136 | void Symbolizer::PlatformPrepareForSandboxing() { |
| 137 | // Do nothing. |
| 138 | } |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 139 | |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 140 | Symbolizer *Symbolizer::PlatformInit() { |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 141 | IntrusiveList<SymbolizerTool> list; |
| 142 | list.clear(); |
| 143 | list.push_back(new(symbolizer_allocator_) WinSymbolizerTool()); |
Pirama Arumuga Nainar | 259f706 | 2015-05-06 11:49:53 -0700 | [diff] [blame] | 144 | return new(symbolizer_allocator_) Symbolizer(list); |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 145 | } |
Richard Smith | ab63743 | 2012-12-20 05:00:13 +0000 | [diff] [blame] | 146 | |
Alexey Samsonov | 6e893b6 | 2012-08-14 13:00:32 +0000 | [diff] [blame] | 147 | } // namespace __sanitizer |
| 148 | |
| 149 | #endif // _WIN32 |