sanitizer_symbolizer_win.cc revision 2d1fdb26e458c4ddc04155c1d421bced3ba90cd0
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.h"
22
23namespace __sanitizer {
24
25class WinSymbolizer : public Symbolizer {
26 public:
27  WinSymbolizer() : initialized_(false) {}
28
29  uptr SymbolizePC(uptr addr, AddressInfo *frames, uptr max_frames) {
30    if (max_frames == 0)
31      return 0;
32
33    BlockingMutexLock l(&dbghelp_mu_);
34    if (!initialized_) {
35      SymSetOptions(SYMOPT_DEFERRED_LOADS |
36                    SYMOPT_UNDNAME |
37                    SYMOPT_LOAD_LINES);
38      CHECK(SymInitialize(GetCurrentProcess(), 0, TRUE));
39      // FIXME: We don't call SymCleanup() on exit yet - should we?
40      initialized_ = true;
41    }
42
43    // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
44    char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)];
45    PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
46    symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
47    symbol->MaxNameLen = MAX_SYM_NAME;
48    DWORD64 offset = 0;
49    BOOL got_objname = SymFromAddr(GetCurrentProcess(),
50                                   (DWORD64)addr, &offset, symbol);
51    if (!got_objname)
52      return 0;
53
54    DWORD unused;
55    IMAGEHLP_LINE64 line_info;
56    line_info.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
57    BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(), (DWORD64)addr,
58                                             &unused, &line_info);
59    AddressInfo *info = &frames[0];
60    info->Clear();
61    info->function = internal_strdup(symbol->Name);
62    info->function_offset = (uptr)offset;
63    if (got_fileline) {
64      info->file = internal_strdup(line_info.FileName);
65      info->line = line_info.LineNumber;
66    }
67
68    IMAGEHLP_MODULE64 mod_info;
69    internal_memset(&mod_info, 0, sizeof(mod_info));
70    mod_info.SizeOfStruct = sizeof(mod_info);
71    if (SymGetModuleInfo64(GetCurrentProcess(), addr, &mod_info))
72      info->FillAddressAndModuleInfo(addr, mod_info.ImageName,
73                                     addr - (uptr)mod_info.BaseOfImage);
74    return 1;
75  }
76
77  bool CanReturnFileLineInfo() {
78    return true;
79  }
80
81  const char *Demangle(const char *name) {
82    CHECK(initialized_);
83    static char demangle_buffer[1000];
84    if (name[0] == '\01' &&
85        UnDecorateSymbolName(name + 1, demangle_buffer, sizeof(demangle_buffer),
86                             UNDNAME_NAME_ONLY))
87      return demangle_buffer;
88    else
89      return name;
90  }
91
92  // FIXME: Implement GetModuleNameAndOffsetForPC().
93
94 private:
95  // All DbgHelp functions are single threaded, so we should use a mutex to
96  // serialize accesses.
97  BlockingMutex dbghelp_mu_;
98  bool initialized_;
99};
100
101Symbolizer *Symbolizer::PlatformInit(const char *path_to_external) {
102  static bool called_once = false;
103  CHECK(!called_once && "Shouldn't create more than one symbolizer");
104  called_once = true;
105  return new(symbolizer_allocator_) WinSymbolizer();
106}
107
108}  // namespace __sanitizer
109
110#endif  // _WIN32
111