Imported Upstream version 4.8.1
[platform/upstream/gcc48.git] / libsanitizer / sanitizer_common / sanitizer_symbolizer.cc
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 //===----------------------------------------------------------------------===//
11
12 #include "sanitizer_common.h"
13 #include "sanitizer_placement_new.h"
14 #include "sanitizer_procmaps.h"
15 #include "sanitizer_symbolizer.h"
16
17 namespace __sanitizer {
18
19 void AddressInfo::Clear() {
20   InternalFree(module);
21   InternalFree(function);
22   InternalFree(file);
23   internal_memset(this, 0, sizeof(AddressInfo));
24 }
25
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;
30 }
31
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_++;
37 }
38
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;
43   }
44   return false;
45 }
46
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;
61 }
62
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);
70   }
71   InternalFree(buff);
72   return ret;
73 }
74
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);
81   }
82   InternalFree(buff);
83   return ret;
84 }
85
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);
108   }
109
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_;
119   }
120
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_);
127   }
128
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;
142       }
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;
148       }
149     }
150     return true;
151   }
152
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;
160     }
161     return true;
162   }
163
164   const char *path_;
165   int input_fd_;
166   int output_fd_;
167
168   static const uptr kBufferSize = 16 * 1024;
169   char buffer_[kBufferSize];
170
171   static const uptr kMaxTimesRestarted = 5;
172   uptr times_restarted_;
173 };
174
175 static LowLevelAllocator symbolizer_allocator;  // Linker initialized.
176
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"
186
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();
195     }
196     return 0;
197   }
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;
204   }
205
206  private:
207   InternalSymbolizer() { }
208
209   static const int kBufferSize = 16 * 1024;
210   char buffer_[kBufferSize];
211 };
212 #else  // SANITIZER_SUPPORTS_WEAK_HOOKS
213
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;
219   }
220 };
221
222 #endif  // SANITIZER_SUPPORTS_WEAK_HOOKS
223
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;
242     }
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;
252       }
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);
264
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;
270       }
271       if (0 == internal_strcmp(info->file, "??")) {
272         InternalFree(info->file);
273         info->file = 0;
274       }
275     }
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;
282     }
283     return frame_id;
284   }
285
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;
304   }
305
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;
314   }
315
316   bool IsSymbolizerAvailable() {
317     if (internal_symbolizer_ == 0)
318       internal_symbolizer_ = InternalSymbolizer::get();
319     return internal_symbolizer_ || external_symbolizer_;
320   }
321
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();
327     }
328     if (internal_symbolizer_) {
329       return internal_symbolizer_->SendCommand(is_data, module_name,
330                                                module_offset);
331     }
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;
338     }
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;
351       }
352     }
353   }
354
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);
363     }
364     for (uptr i = 0; i < n_modules_; i++) {
365       if (modules_[i].containsAddress(address)) {
366         return &modules_[i];
367       }
368     }
369     return 0;
370   }
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;
378     }
379   }
380
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_;
385
386   ExternalSymbolizer *external_symbolizer_;  // Leaked.
387   InternalSymbolizer *internal_symbolizer_;  // Leaked.
388 };
389
390 static Symbolizer symbolizer;  // Linker initialized.
391
392 uptr SymbolizeCode(uptr address, AddressInfo *frames, uptr max_frames) {
393   return symbolizer.SymbolizeCode(address, frames, max_frames);
394 }
395
396 bool SymbolizeData(uptr address, DataInfo *info) {
397   return symbolizer.SymbolizeData(address, info);
398 }
399
400 bool InitializeExternalSymbolizer(const char *path_to_symbolizer) {
401   return symbolizer.InitializeExternalSymbolizer(path_to_symbolizer);
402 }
403
404 bool IsSymbolizerAvailable() {
405   return symbolizer.IsSymbolizerAvailable();
406 }
407
408 }  // namespace __sanitizer