Support slim switch for cfg graph dump
[official-gcc.git] / libsanitizer / sanitizer_common / sanitizer_symbolizer.cc
blob2c9cb2b0a55d4a2e18362a1405f265f60afc703e
1 //===-- sanitizer_symbolizer.cc -------------------------------------------===//
2 //
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // This file is shared between AddressSanitizer and ThreadSanitizer
9 // run-time libraries. See sanitizer_symbolizer.h for details.
10 //===----------------------------------------------------------------------===//
12 #include "sanitizer_common.h"
13 #include "sanitizer_placement_new.h"
14 #include "sanitizer_procmaps.h"
15 #include "sanitizer_symbolizer.h"
17 namespace __sanitizer {
19 void AddressInfo::Clear() {
20 InternalFree(module);
21 InternalFree(function);
22 InternalFree(file);
23 internal_memset(this, 0, sizeof(AddressInfo));
26 LoadedModule::LoadedModule(const char *module_name, uptr base_address) {
27 full_name_ = internal_strdup(module_name);
28 base_address_ = base_address;
29 n_ranges_ = 0;
32 void LoadedModule::addAddressRange(uptr beg, uptr end) {
33 CHECK_LT(n_ranges_, kMaxNumberOfAddressRanges);
34 ranges_[n_ranges_].beg = beg;
35 ranges_[n_ranges_].end = end;
36 n_ranges_++;
39 bool LoadedModule::containsAddress(uptr address) const {
40 for (uptr i = 0; i < n_ranges_; i++) {
41 if (ranges_[i].beg <= address && address < ranges_[i].end)
42 return true;
44 return false;
47 // Extracts the prefix of "str" that consists of any characters not
48 // present in "delims" string, and copies this prefix to "result", allocating
49 // space for it.
50 // Returns a pointer to "str" after skipping extracted prefix and first
51 // delimiter char.
52 static const char *ExtractToken(const char *str, const char *delims,
53 char **result) {
54 uptr prefix_len = internal_strcspn(str, delims);
55 *result = (char*)InternalAlloc(prefix_len + 1);
56 internal_memcpy(*result, str, prefix_len);
57 (*result)[prefix_len] = '\0';
58 const char *prefix_end = str + prefix_len;
59 if (*prefix_end != '\0') prefix_end++;
60 return prefix_end;
63 // Same as ExtractToken, but converts extracted token to integer.
64 static const char *ExtractInt(const char *str, const char *delims,
65 int *result) {
66 char *buff;
67 const char *ret = ExtractToken(str, delims, &buff);
68 if (buff != 0) {
69 *result = (int)internal_atoll(buff);
71 InternalFree(buff);
72 return ret;
75 static const char *ExtractUptr(const char *str, const char *delims,
76 uptr *result) {
77 char *buff;
78 const char *ret = ExtractToken(str, delims, &buff);
79 if (buff != 0) {
80 *result = (uptr)internal_atoll(buff);
82 InternalFree(buff);
83 return ret;
86 // ExternalSymbolizer encapsulates communication between the tool and
87 // external symbolizer program, running in a different subprocess,
88 // For now we assume the following protocol:
89 // For each request of the form
90 // <module_name> <module_offset>
91 // passed to STDIN, external symbolizer prints to STDOUT response:
92 // <function_name>
93 // <file_name>:<line_number>:<column_number>
94 // <function_name>
95 // <file_name>:<line_number>:<column_number>
96 // ...
97 // <empty line>
98 class ExternalSymbolizer {
99 public:
100 ExternalSymbolizer(const char *path, int input_fd, int output_fd)
101 : path_(path),
102 input_fd_(input_fd),
103 output_fd_(output_fd),
104 times_restarted_(0) {
105 CHECK(path_);
106 CHECK_NE(input_fd_, kInvalidFd);
107 CHECK_NE(output_fd_, kInvalidFd);
110 char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
111 CHECK(module_name);
112 internal_snprintf(buffer_, kBufferSize, "%s%s 0x%zx\n",
113 is_data ? "DATA " : "", module_name, module_offset);
114 if (!writeToSymbolizer(buffer_, internal_strlen(buffer_)))
115 return 0;
116 if (!readFromSymbolizer(buffer_, kBufferSize))
117 return 0;
118 return buffer_;
121 bool Restart() {
122 if (times_restarted_ >= kMaxTimesRestarted) return false;
123 times_restarted_++;
124 internal_close(input_fd_);
125 internal_close(output_fd_);
126 return StartSymbolizerSubprocess(path_, &input_fd_, &output_fd_);
129 private:
130 bool readFromSymbolizer(char *buffer, uptr max_length) {
131 if (max_length == 0)
132 return true;
133 uptr read_len = 0;
134 while (true) {
135 uptr just_read = internal_read(input_fd_, buffer + read_len,
136 max_length - read_len);
137 // We can't read 0 bytes, as we don't expect external symbolizer to close
138 // its stdout.
139 if (just_read == 0 || just_read == (uptr)-1) {
140 Report("WARNING: Can't read from symbolizer at fd %d\n", input_fd_);
141 return false;
143 read_len += just_read;
144 // Empty line marks the end of symbolizer output.
145 if (read_len >= 2 && buffer[read_len - 1] == '\n' &&
146 buffer[read_len - 2] == '\n') {
147 break;
150 return true;
153 bool writeToSymbolizer(const char *buffer, uptr length) {
154 if (length == 0)
155 return true;
156 uptr write_len = internal_write(output_fd_, buffer, length);
157 if (write_len == 0 || write_len == (uptr)-1) {
158 Report("WARNING: Can't write to symbolizer at fd %d\n", output_fd_);
159 return false;
161 return true;
164 const char *path_;
165 int input_fd_;
166 int output_fd_;
168 static const uptr kBufferSize = 16 * 1024;
169 char buffer_[kBufferSize];
171 static const uptr kMaxTimesRestarted = 5;
172 uptr times_restarted_;
175 static LowLevelAllocator symbolizer_allocator; // Linker initialized.
177 #if SANITIZER_SUPPORTS_WEAK_HOOKS
178 extern "C" {
179 SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
180 bool __sanitizer_symbolize_code(const char *ModuleName, u64 ModuleOffset,
181 char *Buffer, int MaxLength);
182 SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
183 bool __sanitizer_symbolize_data(const char *ModuleName, u64 ModuleOffset,
184 char *Buffer, int MaxLength);
185 } // extern "C"
187 class InternalSymbolizer {
188 public:
189 typedef bool (*SanitizerSymbolizeFn)(const char*, u64, char*, int);
190 static InternalSymbolizer *get() {
191 if (__sanitizer_symbolize_code != 0 &&
192 __sanitizer_symbolize_data != 0) {
193 void *mem = symbolizer_allocator.Allocate(sizeof(InternalSymbolizer));
194 return new(mem) InternalSymbolizer();
196 return 0;
198 char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
199 SanitizerSymbolizeFn symbolize_fn = is_data ? __sanitizer_symbolize_data
200 : __sanitizer_symbolize_code;
201 if (symbolize_fn(module_name, module_offset, buffer_, kBufferSize))
202 return buffer_;
203 return 0;
206 private:
207 InternalSymbolizer() { }
209 static const int kBufferSize = 16 * 1024;
210 char buffer_[kBufferSize];
212 #else // SANITIZER_SUPPORTS_WEAK_HOOKS
214 class InternalSymbolizer {
215 public:
216 static InternalSymbolizer *get() { return 0; }
217 char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
218 return 0;
222 #endif // SANITIZER_SUPPORTS_WEAK_HOOKS
224 class Symbolizer {
225 public:
226 uptr SymbolizeCode(uptr addr, AddressInfo *frames, uptr max_frames) {
227 if (max_frames == 0)
228 return 0;
229 LoadedModule *module = FindModuleForAddress(addr);
230 if (module == 0)
231 return 0;
232 const char *module_name = module->full_name();
233 uptr module_offset = addr - module->base_address();
234 const char *str = SendCommand(false, module_name, module_offset);
235 if (str == 0) {
236 // External symbolizer was not initialized or failed. Fill only data
237 // about module name and offset.
238 AddressInfo *info = &frames[0];
239 info->Clear();
240 info->FillAddressAndModuleInfo(addr, module_name, module_offset);
241 return 1;
243 uptr frame_id = 0;
244 for (frame_id = 0; frame_id < max_frames; frame_id++) {
245 AddressInfo *info = &frames[frame_id];
246 char *function_name = 0;
247 str = ExtractToken(str, "\n", &function_name);
248 CHECK(function_name);
249 if (function_name[0] == '\0') {
250 // There are no more frames.
251 break;
253 info->Clear();
254 info->FillAddressAndModuleInfo(addr, module_name, module_offset);
255 info->function = function_name;
256 // Parse <file>:<line>:<column> buffer.
257 char *file_line_info = 0;
258 str = ExtractToken(str, "\n", &file_line_info);
259 CHECK(file_line_info);
260 const char *line_info = ExtractToken(file_line_info, ":", &info->file);
261 line_info = ExtractInt(line_info, ":", &info->line);
262 line_info = ExtractInt(line_info, "", &info->column);
263 InternalFree(file_line_info);
265 // Functions and filenames can be "??", in which case we write 0
266 // to address info to mark that names are unknown.
267 if (0 == internal_strcmp(info->function, "??")) {
268 InternalFree(info->function);
269 info->function = 0;
271 if (0 == internal_strcmp(info->file, "??")) {
272 InternalFree(info->file);
273 info->file = 0;
276 if (frame_id == 0) {
277 // Make sure we return at least one frame.
278 AddressInfo *info = &frames[0];
279 info->Clear();
280 info->FillAddressAndModuleInfo(addr, module_name, module_offset);
281 frame_id = 1;
283 return frame_id;
286 bool SymbolizeData(uptr addr, DataInfo *info) {
287 LoadedModule *module = FindModuleForAddress(addr);
288 if (module == 0)
289 return false;
290 const char *module_name = module->full_name();
291 uptr module_offset = addr - module->base_address();
292 internal_memset(info, 0, sizeof(*info));
293 info->address = addr;
294 info->module = internal_strdup(module_name);
295 info->module_offset = module_offset;
296 const char *str = SendCommand(true, module_name, module_offset);
297 if (str == 0)
298 return true;
299 str = ExtractToken(str, "\n", &info->name);
300 str = ExtractUptr(str, " ", &info->start);
301 str = ExtractUptr(str, "\n", &info->size);
302 info->start += module->base_address();
303 return true;
306 bool InitializeExternalSymbolizer(const char *path_to_symbolizer) {
307 int input_fd, output_fd;
308 if (!StartSymbolizerSubprocess(path_to_symbolizer, &input_fd, &output_fd))
309 return false;
310 void *mem = symbolizer_allocator.Allocate(sizeof(ExternalSymbolizer));
311 external_symbolizer_ = new(mem) ExternalSymbolizer(path_to_symbolizer,
312 input_fd, output_fd);
313 return true;
316 bool IsSymbolizerAvailable() {
317 if (internal_symbolizer_ == 0)
318 internal_symbolizer_ = InternalSymbolizer::get();
319 return internal_symbolizer_ || external_symbolizer_;
322 private:
323 char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
324 // First, try to use internal symbolizer.
325 if (internal_symbolizer_ == 0) {
326 internal_symbolizer_ = InternalSymbolizer::get();
328 if (internal_symbolizer_) {
329 return internal_symbolizer_->SendCommand(is_data, module_name,
330 module_offset);
332 // Otherwise, fall back to external symbolizer.
333 if (external_symbolizer_ == 0) {
334 ReportExternalSymbolizerError(
335 "WARNING: Trying to symbolize code, but external "
336 "symbolizer is not initialized!\n");
337 return 0;
339 for (;;) {
340 char *reply = external_symbolizer_->SendCommand(is_data, module_name,
341 module_offset);
342 if (reply)
343 return reply;
344 // Try to restart symbolizer subprocess. If we don't succeed, forget
345 // about it and don't try to use it later.
346 if (!external_symbolizer_->Restart()) {
347 ReportExternalSymbolizerError(
348 "WARNING: Failed to use and restart external symbolizer!\n");
349 external_symbolizer_ = 0;
350 return 0;
355 LoadedModule *FindModuleForAddress(uptr address) {
356 if (modules_ == 0) {
357 modules_ = (LoadedModule*)(symbolizer_allocator.Allocate(
358 kMaxNumberOfModuleContexts * sizeof(LoadedModule)));
359 CHECK(modules_);
360 n_modules_ = GetListOfModules(modules_, kMaxNumberOfModuleContexts);
361 CHECK_GT(n_modules_, 0);
362 CHECK_LT(n_modules_, kMaxNumberOfModuleContexts);
364 for (uptr i = 0; i < n_modules_; i++) {
365 if (modules_[i].containsAddress(address)) {
366 return &modules_[i];
369 return 0;
371 void ReportExternalSymbolizerError(const char *msg) {
372 // Don't use atomics here for now, as SymbolizeCode can't be called
373 // from multiple threads anyway.
374 static bool reported;
375 if (!reported) {
376 Report(msg);
377 reported = true;
381 // 16K loaded modules should be enough for everyone.
382 static const uptr kMaxNumberOfModuleContexts = 1 << 14;
383 LoadedModule *modules_; // Array of module descriptions is leaked.
384 uptr n_modules_;
386 ExternalSymbolizer *external_symbolizer_; // Leaked.
387 InternalSymbolizer *internal_symbolizer_; // Leaked.
390 static Symbolizer symbolizer; // Linker initialized.
392 uptr SymbolizeCode(uptr address, AddressInfo *frames, uptr max_frames) {
393 return symbolizer.SymbolizeCode(address, frames, max_frames);
396 bool SymbolizeData(uptr address, DataInfo *info) {
397 return symbolizer.SymbolizeData(address, info);
400 bool InitializeExternalSymbolizer(const char *path_to_symbolizer) {
401 return symbolizer.InitializeExternalSymbolizer(path_to_symbolizer);
404 bool IsSymbolizerAvailable() {
405 return symbolizer.IsSymbolizerAvailable();
408 } // namespace __sanitizer