]>
Commit | Line | Data |
---|---|---|
f35db108 WM |
1 | //===-- sanitizer_symbolizer.h ----------------------------------*- C++ -*-===// |
2 | // | |
b667dd70 ML |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. | |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
f35db108 WM |
6 | // |
7 | //===----------------------------------------------------------------------===// | |
8 | // | |
df77f0e4 KS |
9 | // Symbolizer is used by sanitizers to map instruction address to a location in |
10 | // source code at run-time. Symbolizer either uses __sanitizer_symbolize_* | |
11 | // defined in the program, or (if they are missing) tries to find and | |
12 | // launch "llvm-symbolizer" commandline tool in a separate process and | |
13 | // communicate with it. | |
f35db108 | 14 | // |
df77f0e4 KS |
15 | // Generally we should try to avoid calling system library functions during |
16 | // symbolization (and use their replacements from sanitizer_libc.h instead). | |
f35db108 WM |
17 | //===----------------------------------------------------------------------===// |
18 | #ifndef SANITIZER_SYMBOLIZER_H | |
19 | #define SANITIZER_SYMBOLIZER_H | |
20 | ||
696d846a MO |
21 | #include "sanitizer_common.h" |
22 | #include "sanitizer_mutex.h" | |
b667dd70 | 23 | #include "sanitizer_vector.h" |
f35db108 WM |
24 | |
25 | namespace __sanitizer { | |
26 | ||
27 | struct AddressInfo { | |
696d846a MO |
28 | // Owns all the string members. Storage for them is |
29 | // (de)allocated using sanitizer internal allocator. | |
f35db108 | 30 | uptr address; |
dee5ea7a | 31 | |
f35db108 WM |
32 | char *module; |
33 | uptr module_offset; | |
5d3805fc | 34 | ModuleArch module_arch; |
dee5ea7a KS |
35 | |
36 | static const uptr kUnknown = ~(uptr)0; | |
f35db108 | 37 | char *function; |
dee5ea7a KS |
38 | uptr function_offset; |
39 | ||
f35db108 WM |
40 | char *file; |
41 | int line; | |
42 | int column; | |
43 | ||
696d846a | 44 | AddressInfo(); |
dee5ea7a | 45 | // Deletes all strings and resets all fields. |
696d846a | 46 | void Clear(); |
5d3805fc | 47 | void FillModuleInfo(const char *mod_name, uptr mod_offset, ModuleArch arch); |
696d846a | 48 | }; |
f35db108 | 49 | |
696d846a MO |
50 | // Linked list of symbolized frames (each frame is described by AddressInfo). |
51 | struct SymbolizedStack { | |
52 | SymbolizedStack *next; | |
53 | AddressInfo info; | |
54 | static SymbolizedStack *New(uptr addr); | |
55 | // Deletes current, and all subsequent frames in the linked list. | |
56 | // The object cannot be accessed after the call to this function. | |
57 | void ClearAll(); | |
58 | ||
59 | private: | |
60 | SymbolizedStack(); | |
f35db108 WM |
61 | }; |
62 | ||
c5be964a | 63 | // For now, DataInfo is used to describe global variable. |
2660d12d | 64 | struct DataInfo { |
696d846a MO |
65 | // Owns all the string members. Storage for them is |
66 | // (de)allocated using sanitizer internal allocator. | |
2660d12d KS |
67 | char *module; |
68 | uptr module_offset; | |
5d3805fc JJ |
69 | ModuleArch module_arch; |
70 | ||
10189819 MO |
71 | char *file; |
72 | uptr line; | |
2660d12d KS |
73 | char *name; |
74 | uptr start; | |
75 | uptr size; | |
c5be964a | 76 | |
696d846a MO |
77 | DataInfo(); |
78 | void Clear(); | |
2660d12d KS |
79 | }; |
80 | ||
b667dd70 ML |
81 | struct LocalInfo { |
82 | char *function_name = nullptr; | |
83 | char *name = nullptr; | |
84 | char *decl_file = nullptr; | |
85 | unsigned decl_line = 0; | |
86 | ||
87 | bool has_frame_offset = false; | |
88 | bool has_size = false; | |
89 | bool has_tag_offset = false; | |
90 | ||
91 | sptr frame_offset; | |
92 | uptr size; | |
93 | uptr tag_offset; | |
94 | ||
95 | void Clear(); | |
96 | }; | |
97 | ||
98 | struct FrameInfo { | |
99 | char *module; | |
100 | uptr module_offset; | |
101 | ModuleArch module_arch; | |
102 | ||
103 | InternalMmapVector<LocalInfo> locals; | |
104 | void Clear(); | |
105 | }; | |
106 | ||
696d846a MO |
107 | class SymbolizerTool; |
108 | ||
109 | class Symbolizer final { | |
f35db108 | 110 | public: |
866e32ad KS |
111 | /// Initialize and return platform-specific implementation of symbolizer |
112 | /// (if it wasn't already initialized). | |
df77f0e4 | 113 | static Symbolizer *GetOrInit(); |
10189819 | 114 | static void LateInitialize(); |
696d846a MO |
115 | // Returns a list of symbolized frames for a given address (containing |
116 | // all inlined functions, if necessary). | |
117 | SymbolizedStack *SymbolizePC(uptr address); | |
118 | bool SymbolizeData(uptr address, DataInfo *info); | |
b667dd70 | 119 | bool SymbolizeFrame(uptr address, FrameInfo *info); |
696d846a MO |
120 | |
121 | // The module names Symbolizer returns are stable and unique for every given | |
122 | // module. It is safe to store and compare them as pointers. | |
123 | bool GetModuleNameAndOffsetForPC(uptr pc, const char **module_name, | |
124 | uptr *module_address); | |
125 | const char *GetModuleNameForPc(uptr pc) { | |
126 | const char *module_name = nullptr; | |
127 | uptr unused; | |
128 | if (GetModuleNameAndOffsetForPC(pc, &module_name, &unused)) | |
129 | return module_name; | |
130 | return nullptr; | |
df77f0e4 | 131 | } |
696d846a | 132 | |
ef1b3fda | 133 | // Release internal caches (if any). |
696d846a | 134 | void Flush(); |
ef1b3fda | 135 | // Attempts to demangle the provided C++ mangled name. |
696d846a | 136 | const char *Demangle(const char *name); |
f35db108 | 137 | |
df77f0e4 KS |
138 | // Allow user to install hooks that would be called before/after Symbolizer |
139 | // does the actual file/line info fetching. Specific sanitizers may need this | |
140 | // to distinguish system library calls made in user code from calls made | |
141 | // during in-process symbolization. | |
142 | typedef void (*StartSymbolizationHook)(); | |
143 | typedef void (*EndSymbolizationHook)(); | |
144 | // May be called at most once. | |
145 | void AddHooks(StartSymbolizationHook start_hook, | |
146 | EndSymbolizationHook end_hook); | |
147 | ||
5d3805fc | 148 | void RefreshModules(); |
10189819 MO |
149 | const LoadedModule *FindModuleForAddress(uptr address); |
150 | ||
5d3805fc JJ |
151 | void InvalidateModuleList(); |
152 | ||
df77f0e4 | 153 | private: |
696d846a MO |
154 | // GetModuleNameAndOffsetForPC has to return a string to the caller. |
155 | // Since the corresponding module might get unloaded later, we should create | |
156 | // our owned copies of the strings that we can safely return. | |
157 | // ModuleNameOwner does not provide any synchronization, thus calls to | |
158 | // its method should be protected by |mu_|. | |
159 | class ModuleNameOwner { | |
160 | public: | |
161 | explicit ModuleNameOwner(BlockingMutex *synchronized_by) | |
eac97531 ML |
162 | : last_match_(nullptr), mu_(synchronized_by) { |
163 | storage_.reserve(kInitialCapacity); | |
164 | } | |
696d846a MO |
165 | const char *GetOwnedCopy(const char *str); |
166 | ||
167 | private: | |
168 | static const uptr kInitialCapacity = 1000; | |
169 | InternalMmapVector<const char*> storage_; | |
170 | const char *last_match_; | |
171 | ||
172 | BlockingMutex *mu_; | |
173 | } module_names_; | |
174 | ||
df77f0e4 | 175 | /// Platform-specific function for creating a Symbolizer object. |
866e32ad | 176 | static Symbolizer *PlatformInit(); |
696d846a MO |
177 | |
178 | bool FindModuleNameAndOffsetForAddress(uptr address, const char **module_name, | |
5d3805fc JJ |
179 | uptr *module_offset, |
180 | ModuleArch *module_arch); | |
10189819 | 181 | ListOfModules modules_; |
5d3805fc | 182 | ListOfModules fallback_modules_; |
696d846a MO |
183 | // If stale, need to reload the modules before looking up addresses. |
184 | bool modules_fresh_; | |
185 | ||
186 | // Platform-specific default demangler, must not return nullptr. | |
187 | const char *PlatformDemangle(const char *name); | |
df77f0e4 KS |
188 | |
189 | static Symbolizer *symbolizer_; | |
190 | static StaticSpinMutex init_mu_; | |
191 | ||
696d846a MO |
192 | // Mutex locked from public methods of |Symbolizer|, so that the internals |
193 | // (including individual symbolizer tools and platform-specific methods) are | |
194 | // always synchronized. | |
195 | BlockingMutex mu_; | |
196 | ||
696d846a MO |
197 | IntrusiveList<SymbolizerTool> tools_; |
198 | ||
199 | explicit Symbolizer(IntrusiveList<SymbolizerTool> tools); | |
df77f0e4 KS |
200 | |
201 | static LowLevelAllocator symbolizer_allocator_; | |
202 | ||
203 | StartSymbolizationHook start_hook_; | |
204 | EndSymbolizationHook end_hook_; | |
205 | class SymbolizerScope { | |
206 | public: | |
207 | explicit SymbolizerScope(const Symbolizer *sym); | |
208 | ~SymbolizerScope(); | |
209 | private: | |
210 | const Symbolizer *sym_; | |
211 | }; | |
3c6331c2 ML |
212 | |
213 | // Calls `LateInitialize()` on all items in `tools_`. | |
214 | void LateInitializeTools(); | |
df77f0e4 | 215 | }; |
f35db108 | 216 | |
10189819 MO |
217 | #ifdef SANITIZER_WINDOWS |
218 | void InitializeDbgHelpIfNeeded(); | |
219 | #endif | |
220 | ||
f35db108 WM |
221 | } // namespace __sanitizer |
222 | ||
223 | #endif // SANITIZER_SYMBOLIZER_H |