• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- sanitizer_symbolizer_posix_libcdep.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 // POSIX-specific implementation of symbolizer parts.
13 //===----------------------------------------------------------------------===//
14 
15 #include "sanitizer_platform.h"
16 #if SANITIZER_POSIX
17 #include "sanitizer_allocator_internal.h"
18 #include "sanitizer_common.h"
19 #include "sanitizer_flags.h"
20 #include "sanitizer_internal_defs.h"
21 #include "sanitizer_linux.h"
22 #include "sanitizer_placement_new.h"
23 #include "sanitizer_procmaps.h"
24 #include "sanitizer_symbolizer.h"
25 #include "sanitizer_symbolizer_libbacktrace.h"
26 
27 #include <errno.h>
28 #include <stdlib.h>
29 #include <sys/wait.h>
30 #include <unistd.h>
31 
32 // C++ demangling function, as required by Itanium C++ ABI. This is weak,
33 // because we do not require a C++ ABI library to be linked to a program
34 // using sanitizers; if it's not present, we'll just use the mangled name.
35 namespace __cxxabiv1 {
36   extern "C" SANITIZER_WEAK_ATTRIBUTE
37   char *__cxa_demangle(const char *mangled, char *buffer,
38                                   size_t *length, int *status);
39 }
40 
41 namespace __sanitizer {
42 
43 // Attempts to demangle the name via __cxa_demangle from __cxxabiv1.
DemangleCXXABI(const char * name)44 static const char *DemangleCXXABI(const char *name) {
45   // FIXME: __cxa_demangle aggressively insists on allocating memory.
46   // There's not much we can do about that, short of providing our
47   // own demangler (libc++abi's implementation could be adapted so that
48   // it does not allocate). For now, we just call it anyway, and we leak
49   // the returned value.
50   if (__cxxabiv1::__cxa_demangle)
51     if (const char *demangled_name =
52           __cxxabiv1::__cxa_demangle(name, 0, 0, 0))
53       return demangled_name;
54 
55   return name;
56 }
57 
58 // Extracts the prefix of "str" that consists of any characters not
59 // present in "delims" string, and copies this prefix to "result", allocating
60 // space for it.
61 // Returns a pointer to "str" after skipping extracted prefix and first
62 // delimiter char.
ExtractToken(const char * str,const char * delims,char ** result)63 static const char *ExtractToken(const char *str, const char *delims,
64                                 char **result) {
65   uptr prefix_len = internal_strcspn(str, delims);
66   *result = (char*)InternalAlloc(prefix_len + 1);
67   internal_memcpy(*result, str, prefix_len);
68   (*result)[prefix_len] = '\0';
69   const char *prefix_end = str + prefix_len;
70   if (*prefix_end != '\0') prefix_end++;
71   return prefix_end;
72 }
73 
74 // Same as ExtractToken, but converts extracted token to integer.
ExtractInt(const char * str,const char * delims,int * result)75 static const char *ExtractInt(const char *str, const char *delims,
76                               int *result) {
77   char *buff;
78   const char *ret = ExtractToken(str, delims, &buff);
79   if (buff != 0) {
80     *result = (int)internal_atoll(buff);
81   }
82   InternalFree(buff);
83   return ret;
84 }
85 
ExtractUptr(const char * str,const char * delims,uptr * result)86 static const char *ExtractUptr(const char *str, const char *delims,
87                                uptr *result) {
88   char *buff;
89   const char *ret = ExtractToken(str, delims, &buff);
90   if (buff != 0) {
91     *result = (uptr)internal_atoll(buff);
92   }
93   InternalFree(buff);
94   return ret;
95 }
96 
97 class ExternalSymbolizerInterface {
98  public:
99   // Can't declare pure virtual functions in sanitizer runtimes:
100   // __cxa_pure_virtual might be unavailable.
SendCommand(bool is_data,const char * module_name,uptr module_offset)101   virtual char *SendCommand(bool is_data, const char *module_name,
102                             uptr module_offset) {
103     UNIMPLEMENTED();
104   }
105 };
106 
107 // SymbolizerProcess encapsulates communication between the tool and
108 // external symbolizer program, running in a different subprocess.
109 // SymbolizerProcess may not be used from two threads simultaneously.
110 class SymbolizerProcess : public ExternalSymbolizerInterface {
111  public:
SymbolizerProcess(const char * path)112   explicit SymbolizerProcess(const char *path)
113       : path_(path),
114         input_fd_(kInvalidFd),
115         output_fd_(kInvalidFd),
116         times_restarted_(0),
117         failed_to_start_(false),
118         reported_invalid_path_(false) {
119     CHECK(path_);
120     CHECK_NE(path_[0], '\0');
121   }
122 
SendCommand(bool is_data,const char * module_name,uptr module_offset)123   char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
124     for (; times_restarted_ < kMaxTimesRestarted; times_restarted_++) {
125       // Start or restart symbolizer if we failed to send command to it.
126       if (char *res = SendCommandImpl(is_data, module_name, module_offset))
127         return res;
128       Restart();
129     }
130     if (!failed_to_start_) {
131       Report("WARNING: Failed to use and restart external symbolizer!\n");
132       failed_to_start_ = true;
133     }
134     return 0;
135   }
136 
137  private:
Restart()138   bool Restart() {
139     if (input_fd_ != kInvalidFd)
140       internal_close(input_fd_);
141     if (output_fd_ != kInvalidFd)
142       internal_close(output_fd_);
143     return StartSymbolizerSubprocess();
144   }
145 
SendCommandImpl(bool is_data,const char * module_name,uptr module_offset)146   char *SendCommandImpl(bool is_data, const char *module_name,
147                         uptr module_offset) {
148     if (input_fd_ == kInvalidFd || output_fd_ == kInvalidFd)
149       return 0;
150     CHECK(module_name);
151     if (!RenderInputCommand(buffer_, kBufferSize, is_data, module_name,
152                             module_offset))
153       return 0;
154     if (!writeToSymbolizer(buffer_, internal_strlen(buffer_)))
155       return 0;
156     if (!readFromSymbolizer(buffer_, kBufferSize))
157       return 0;
158     return buffer_;
159   }
160 
readFromSymbolizer(char * buffer,uptr max_length)161   bool readFromSymbolizer(char *buffer, uptr max_length) {
162     if (max_length == 0)
163       return true;
164     uptr read_len = 0;
165     while (true) {
166       uptr just_read = internal_read(input_fd_, buffer + read_len,
167                                      max_length - read_len - 1);
168       // We can't read 0 bytes, as we don't expect external symbolizer to close
169       // its stdout.
170       if (just_read == 0 || just_read == (uptr)-1) {
171         Report("WARNING: Can't read from symbolizer at fd %d\n", input_fd_);
172         return false;
173       }
174       read_len += just_read;
175       if (ReachedEndOfOutput(buffer, read_len))
176         break;
177     }
178     buffer[read_len] = '\0';
179     return true;
180   }
181 
writeToSymbolizer(const char * buffer,uptr length)182   bool writeToSymbolizer(const char *buffer, uptr length) {
183     if (length == 0)
184       return true;
185     uptr write_len = internal_write(output_fd_, buffer, length);
186     if (write_len == 0 || write_len == (uptr)-1) {
187       Report("WARNING: Can't write to symbolizer at fd %d\n", output_fd_);
188       return false;
189     }
190     return true;
191   }
192 
StartSymbolizerSubprocess()193   bool StartSymbolizerSubprocess() {
194     if (!FileExists(path_)) {
195       if (!reported_invalid_path_) {
196         Report("WARNING: invalid path to external symbolizer!\n");
197         reported_invalid_path_ = true;
198       }
199       return false;
200     }
201 
202     int *infd = NULL;
203     int *outfd = NULL;
204     // The client program may close its stdin and/or stdout and/or stderr
205     // thus allowing socketpair to reuse file descriptors 0, 1 or 2.
206     // In this case the communication between the forked processes may be
207     // broken if either the parent or the child tries to close or duplicate
208     // these descriptors. The loop below produces two pairs of file
209     // descriptors, each greater than 2 (stderr).
210     int sock_pair[5][2];
211     for (int i = 0; i < 5; i++) {
212       if (pipe(sock_pair[i]) == -1) {
213         for (int j = 0; j < i; j++) {
214           internal_close(sock_pair[j][0]);
215           internal_close(sock_pair[j][1]);
216         }
217         Report("WARNING: Can't create a socket pair to start "
218                "external symbolizer (errno: %d)\n", errno);
219         return false;
220       } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) {
221         if (infd == NULL) {
222           infd = sock_pair[i];
223         } else {
224           outfd = sock_pair[i];
225           for (int j = 0; j < i; j++) {
226             if (sock_pair[j] == infd) continue;
227             internal_close(sock_pair[j][0]);
228             internal_close(sock_pair[j][1]);
229           }
230           break;
231         }
232       }
233     }
234     CHECK(infd);
235     CHECK(outfd);
236 
237     // Real fork() may call user callbacks registered with pthread_atfork().
238     int pid = internal_fork();
239     if (pid == -1) {
240       // Fork() failed.
241       internal_close(infd[0]);
242       internal_close(infd[1]);
243       internal_close(outfd[0]);
244       internal_close(outfd[1]);
245       Report("WARNING: failed to fork external symbolizer "
246              " (errno: %d)\n", errno);
247       return false;
248     } else if (pid == 0) {
249       // Child subprocess.
250       internal_close(STDOUT_FILENO);
251       internal_close(STDIN_FILENO);
252       internal_dup2(outfd[0], STDIN_FILENO);
253       internal_dup2(infd[1], STDOUT_FILENO);
254       internal_close(outfd[0]);
255       internal_close(outfd[1]);
256       internal_close(infd[0]);
257       internal_close(infd[1]);
258       for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--)
259         internal_close(fd);
260       ExecuteWithDefaultArgs(path_);
261       internal__exit(1);
262     }
263 
264     // Continue execution in parent process.
265     internal_close(outfd[0]);
266     internal_close(infd[1]);
267     input_fd_ = infd[0];
268     output_fd_ = outfd[1];
269 
270     // Check that symbolizer subprocess started successfully.
271     int pid_status;
272     SleepForMillis(kSymbolizerStartupTimeMillis);
273     int exited_pid = waitpid(pid, &pid_status, WNOHANG);
274     if (exited_pid != 0) {
275       // Either waitpid failed, or child has already exited.
276       Report("WARNING: external symbolizer didn't start up correctly!\n");
277       return false;
278     }
279 
280     return true;
281   }
282 
RenderInputCommand(char * buffer,uptr max_length,bool is_data,const char * module_name,uptr module_offset) const283   virtual bool RenderInputCommand(char *buffer, uptr max_length, bool is_data,
284                                   const char *module_name,
285                                   uptr module_offset) const {
286     UNIMPLEMENTED();
287   }
288 
ReachedEndOfOutput(const char * buffer,uptr length) const289   virtual bool ReachedEndOfOutput(const char *buffer, uptr length) const {
290     UNIMPLEMENTED();
291   }
292 
ExecuteWithDefaultArgs(const char * path_to_binary) const293   virtual void ExecuteWithDefaultArgs(const char *path_to_binary) const {
294     UNIMPLEMENTED();
295   }
296 
297   const char *path_;
298   int input_fd_;
299   int output_fd_;
300 
301   static const uptr kBufferSize = 16 * 1024;
302   char buffer_[kBufferSize];
303 
304   static const uptr kMaxTimesRestarted = 5;
305   static const int kSymbolizerStartupTimeMillis = 10;
306   uptr times_restarted_;
307   bool failed_to_start_;
308   bool reported_invalid_path_;
309 };
310 
311 // For now we assume the following protocol:
312 // For each request of the form
313 //   <module_name> <module_offset>
314 // passed to STDIN, external symbolizer prints to STDOUT response:
315 //   <function_name>
316 //   <file_name>:<line_number>:<column_number>
317 //   <function_name>
318 //   <file_name>:<line_number>:<column_number>
319 //   ...
320 //   <empty line>
321 class LLVMSymbolizerProcess : public SymbolizerProcess {
322  public:
LLVMSymbolizerProcess(const char * path)323   explicit LLVMSymbolizerProcess(const char *path) : SymbolizerProcess(path) {}
324 
325  private:
RenderInputCommand(char * buffer,uptr max_length,bool is_data,const char * module_name,uptr module_offset) const326   bool RenderInputCommand(char *buffer, uptr max_length, bool is_data,
327                           const char *module_name, uptr module_offset) const {
328     internal_snprintf(buffer, max_length, "%s\"%s\" 0x%zx\n",
329                       is_data ? "DATA " : "", module_name, module_offset);
330     return true;
331   }
332 
ReachedEndOfOutput(const char * buffer,uptr length) const333   bool ReachedEndOfOutput(const char *buffer, uptr length) const {
334     // Empty line marks the end of llvm-symbolizer output.
335     return length >= 2 && buffer[length - 1] == '\n' &&
336            buffer[length - 2] == '\n';
337   }
338 
ExecuteWithDefaultArgs(const char * path_to_binary) const339   void ExecuteWithDefaultArgs(const char *path_to_binary) const {
340 #if defined(__x86_64__)
341     const char* const kSymbolizerArch = "--default-arch=x86_64";
342 #elif defined(__i386__)
343     const char* const kSymbolizerArch = "--default-arch=i386";
344 #elif defined(__powerpc64__)
345     const char* const kSymbolizerArch = "--default-arch=powerpc64";
346 #else
347     const char* const kSymbolizerArch = "--default-arch=unknown";
348 #endif
349     execl(path_to_binary, path_to_binary, kSymbolizerArch, (char *)0);
350   }
351 };
352 
353 class Addr2LineProcess : public SymbolizerProcess {
354  public:
Addr2LineProcess(const char * path,const char * module_name)355   Addr2LineProcess(const char *path, const char *module_name)
356       : SymbolizerProcess(path), module_name_(internal_strdup(module_name)) {}
357 
module_name() const358   const char *module_name() const { return module_name_; }
359 
360  private:
RenderInputCommand(char * buffer,uptr max_length,bool is_data,const char * module_name,uptr module_offset) const361   bool RenderInputCommand(char *buffer, uptr max_length, bool is_data,
362                           const char *module_name, uptr module_offset) const {
363     if (is_data)
364       return false;
365     CHECK_EQ(0, internal_strcmp(module_name, module_name_));
366     internal_snprintf(buffer, max_length, "0x%zx\n", module_offset);
367     return true;
368   }
369 
ReachedEndOfOutput(const char * buffer,uptr length) const370   bool ReachedEndOfOutput(const char *buffer, uptr length) const {
371     // Output should consist of two lines.
372     int num_lines = 0;
373     for (uptr i = 0; i < length; ++i) {
374       if (buffer[i] == '\n')
375         num_lines++;
376       if (num_lines >= 2)
377         return true;
378     }
379     return false;
380   }
381 
ExecuteWithDefaultArgs(const char * path_to_binary) const382   void ExecuteWithDefaultArgs(const char *path_to_binary) const {
383     execl(path_to_binary, path_to_binary, "-Cfe", module_name_, (char *)0);
384   }
385 
386   const char *module_name_;  // Owned, leaked.
387 };
388 
389 class Addr2LinePool : public ExternalSymbolizerInterface {
390  public:
Addr2LinePool(const char * addr2line_path,LowLevelAllocator * allocator)391   explicit Addr2LinePool(const char *addr2line_path,
392                          LowLevelAllocator *allocator)
393       : addr2line_path_(addr2line_path), allocator_(allocator),
394         addr2line_pool_(16) {}
395 
SendCommand(bool is_data,const char * module_name,uptr module_offset)396   char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
397     if (is_data)
398       return 0;
399     Addr2LineProcess *addr2line = 0;
400     for (uptr i = 0; i < addr2line_pool_.size(); ++i) {
401       if (0 ==
402           internal_strcmp(module_name, addr2line_pool_[i]->module_name())) {
403         addr2line = addr2line_pool_[i];
404         break;
405       }
406     }
407     if (!addr2line) {
408       addr2line =
409           new(*allocator_) Addr2LineProcess(addr2line_path_, module_name);
410       addr2line_pool_.push_back(addr2line);
411     }
412     return addr2line->SendCommand(is_data, module_name, module_offset);
413   }
414 
415  private:
416   const char *addr2line_path_;
417   LowLevelAllocator *allocator_;
418   InternalMmapVector<Addr2LineProcess*> addr2line_pool_;
419 };
420 
421 #if SANITIZER_SUPPORTS_WEAK_HOOKS
422 extern "C" {
423 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
424 bool __sanitizer_symbolize_code(const char *ModuleName, u64 ModuleOffset,
425                                 char *Buffer, int MaxLength);
426 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
427 bool __sanitizer_symbolize_data(const char *ModuleName, u64 ModuleOffset,
428                                 char *Buffer, int MaxLength);
429 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
430 void __sanitizer_symbolize_flush();
431 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
432 int __sanitizer_symbolize_demangle(const char *Name, char *Buffer,
433                                    int MaxLength);
434 }  // extern "C"
435 
436 class InternalSymbolizer {
437  public:
438   typedef bool (*SanitizerSymbolizeFn)(const char*, u64, char*, int);
439 
get(LowLevelAllocator * alloc)440   static InternalSymbolizer *get(LowLevelAllocator *alloc) {
441     if (__sanitizer_symbolize_code != 0 &&
442         __sanitizer_symbolize_data != 0) {
443       return new(*alloc) InternalSymbolizer();
444     }
445     return 0;
446   }
447 
SendCommand(bool is_data,const char * module_name,uptr module_offset)448   char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
449     SanitizerSymbolizeFn symbolize_fn = is_data ? __sanitizer_symbolize_data
450                                                 : __sanitizer_symbolize_code;
451     if (symbolize_fn(module_name, module_offset, buffer_, kBufferSize))
452       return buffer_;
453     return 0;
454   }
455 
Flush()456   void Flush() {
457     if (__sanitizer_symbolize_flush)
458       __sanitizer_symbolize_flush();
459   }
460 
Demangle(const char * name)461   const char *Demangle(const char *name) {
462     if (__sanitizer_symbolize_demangle) {
463       for (uptr res_length = 1024;
464            res_length <= InternalSizeClassMap::kMaxSize;) {
465         char *res_buff = static_cast<char*>(InternalAlloc(res_length));
466         uptr req_length =
467             __sanitizer_symbolize_demangle(name, res_buff, res_length);
468         if (req_length > res_length) {
469           res_length = req_length + 1;
470           InternalFree(res_buff);
471           continue;
472         }
473         return res_buff;
474       }
475     }
476     return name;
477   }
478 
479  private:
InternalSymbolizer()480   InternalSymbolizer() { }
481 
482   static const int kBufferSize = 16 * 1024;
483   static const int kMaxDemangledNameSize = 1024;
484   char buffer_[kBufferSize];
485 };
486 #else  // SANITIZER_SUPPORTS_WEAK_HOOKS
487 
488 class InternalSymbolizer {
489  public:
get(LowLevelAllocator * alloc)490   static InternalSymbolizer *get(LowLevelAllocator *alloc) { return 0; }
SendCommand(bool is_data,const char * module_name,uptr module_offset)491   char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
492     return 0;
493   }
Flush()494   void Flush() { }
Demangle(const char * name)495   const char *Demangle(const char *name) { return name; }
496 };
497 
498 #endif  // SANITIZER_SUPPORTS_WEAK_HOOKS
499 
500 class POSIXSymbolizer : public Symbolizer {
501  public:
POSIXSymbolizer(ExternalSymbolizerInterface * external_symbolizer,InternalSymbolizer * internal_symbolizer,LibbacktraceSymbolizer * libbacktrace_symbolizer)502   POSIXSymbolizer(ExternalSymbolizerInterface *external_symbolizer,
503                   InternalSymbolizer *internal_symbolizer,
504                   LibbacktraceSymbolizer *libbacktrace_symbolizer)
505       : Symbolizer(),
506         external_symbolizer_(external_symbolizer),
507         internal_symbolizer_(internal_symbolizer),
508         libbacktrace_symbolizer_(libbacktrace_symbolizer) {}
509 
SymbolizePC(uptr addr,AddressInfo * frames,uptr max_frames)510   uptr SymbolizePC(uptr addr, AddressInfo *frames, uptr max_frames) {
511     BlockingMutexLock l(&mu_);
512     if (max_frames == 0)
513       return 0;
514     const char *module_name;
515     uptr module_offset;
516     if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset))
517       return 0;
518     // First, try to use libbacktrace symbolizer (if it's available).
519     if (libbacktrace_symbolizer_ != 0) {
520       mu_.CheckLocked();
521       uptr res = libbacktrace_symbolizer_->SymbolizeCode(
522           addr, frames, max_frames, module_name, module_offset);
523       if (res > 0)
524         return res;
525     }
526     const char *str = SendCommand(false, module_name, module_offset);
527     if (str == 0) {
528       // Symbolizer was not initialized or failed. Fill only data
529       // about module name and offset.
530       AddressInfo *info = &frames[0];
531       info->Clear();
532       info->FillAddressAndModuleInfo(addr, module_name, module_offset);
533       return 1;
534     }
535     uptr frame_id = 0;
536     for (frame_id = 0; frame_id < max_frames; frame_id++) {
537       AddressInfo *info = &frames[frame_id];
538       char *function_name = 0;
539       str = ExtractToken(str, "\n", &function_name);
540       CHECK(function_name);
541       if (function_name[0] == '\0') {
542         // There are no more frames.
543         break;
544       }
545       info->Clear();
546       info->FillAddressAndModuleInfo(addr, module_name, module_offset);
547       info->function = function_name;
548       // Parse <file>:<line>:<column> buffer.
549       char *file_line_info = 0;
550       str = ExtractToken(str, "\n", &file_line_info);
551       CHECK(file_line_info);
552       const char *line_info = ExtractToken(file_line_info, ":", &info->file);
553       line_info = ExtractInt(line_info, ":", &info->line);
554       line_info = ExtractInt(line_info, "", &info->column);
555       InternalFree(file_line_info);
556 
557       // Functions and filenames can be "??", in which case we write 0
558       // to address info to mark that names are unknown.
559       if (0 == internal_strcmp(info->function, "??")) {
560         InternalFree(info->function);
561         info->function = 0;
562       }
563       if (0 == internal_strcmp(info->file, "??")) {
564         InternalFree(info->file);
565         info->file = 0;
566       }
567     }
568     if (frame_id == 0) {
569       // Make sure we return at least one frame.
570       AddressInfo *info = &frames[0];
571       info->Clear();
572       info->FillAddressAndModuleInfo(addr, module_name, module_offset);
573       frame_id = 1;
574     }
575     return frame_id;
576   }
577 
SymbolizeData(uptr addr,DataInfo * info)578   bool SymbolizeData(uptr addr, DataInfo *info) {
579     BlockingMutexLock l(&mu_);
580     LoadedModule *module = FindModuleForAddress(addr);
581     if (module == 0)
582       return false;
583     const char *module_name = module->full_name();
584     uptr module_offset = addr - module->base_address();
585     internal_memset(info, 0, sizeof(*info));
586     info->address = addr;
587     info->module = internal_strdup(module_name);
588     info->module_offset = module_offset;
589     // First, try to use libbacktrace symbolizer (if it's available).
590     if (libbacktrace_symbolizer_ != 0) {
591       mu_.CheckLocked();
592       if (libbacktrace_symbolizer_->SymbolizeData(info))
593         return true;
594     }
595     const char *str = SendCommand(true, module_name, module_offset);
596     if (str == 0)
597       return true;
598     str = ExtractToken(str, "\n", &info->name);
599     str = ExtractUptr(str, " ", &info->start);
600     str = ExtractUptr(str, "\n", &info->size);
601     info->start += module->base_address();
602     return true;
603   }
604 
GetModuleNameAndOffsetForPC(uptr pc,const char ** module_name,uptr * module_address)605   bool GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
606                                    uptr *module_address) {
607     BlockingMutexLock l(&mu_);
608     return FindModuleNameAndOffsetForAddress(pc, module_name, module_address);
609   }
610 
CanReturnFileLineInfo()611   bool CanReturnFileLineInfo() {
612     return internal_symbolizer_ != 0 || external_symbolizer_ != 0 ||
613            libbacktrace_symbolizer_ != 0;
614   }
615 
Flush()616   void Flush() {
617     BlockingMutexLock l(&mu_);
618     if (internal_symbolizer_ != 0) {
619       SymbolizerScope sym_scope(this);
620       internal_symbolizer_->Flush();
621     }
622   }
623 
Demangle(const char * name)624   const char *Demangle(const char *name) {
625     BlockingMutexLock l(&mu_);
626     // Run hooks even if we don't use internal symbolizer, as cxxabi
627     // demangle may call system functions.
628     SymbolizerScope sym_scope(this);
629     // Try to use libbacktrace demangler (if available).
630     if (libbacktrace_symbolizer_ != 0) {
631       if (const char *demangled = libbacktrace_symbolizer_->Demangle(name))
632         return demangled;
633     }
634     if (internal_symbolizer_ != 0)
635       return internal_symbolizer_->Demangle(name);
636     return DemangleCXXABI(name);
637   }
638 
PrepareForSandboxing()639   void PrepareForSandboxing() {
640 #if SANITIZER_LINUX && !SANITIZER_ANDROID
641     BlockingMutexLock l(&mu_);
642     // Cache /proc/self/exe on Linux.
643     CacheBinaryName();
644 #endif
645   }
646 
647  private:
SendCommand(bool is_data,const char * module_name,uptr module_offset)648   char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
649     mu_.CheckLocked();
650     // First, try to use internal symbolizer.
651     if (internal_symbolizer_) {
652       SymbolizerScope sym_scope(this);
653       return internal_symbolizer_->SendCommand(is_data, module_name,
654                                                module_offset);
655     }
656     // Otherwise, fall back to external symbolizer.
657     if (external_symbolizer_) {
658       SymbolizerScope sym_scope(this);
659       return external_symbolizer_->SendCommand(is_data, module_name,
660                                                module_offset);
661     }
662     return 0;
663   }
664 
FindModuleForAddress(uptr address)665   LoadedModule *FindModuleForAddress(uptr address) {
666     mu_.CheckLocked();
667     bool modules_were_reloaded = false;
668     if (modules_ == 0 || !modules_fresh_) {
669       modules_ = (LoadedModule*)(symbolizer_allocator_.Allocate(
670           kMaxNumberOfModuleContexts * sizeof(LoadedModule)));
671       CHECK(modules_);
672       n_modules_ = GetListOfModules(modules_, kMaxNumberOfModuleContexts,
673                                     /* filter */ 0);
674       CHECK_GT(n_modules_, 0);
675       CHECK_LT(n_modules_, kMaxNumberOfModuleContexts);
676       modules_fresh_ = true;
677       modules_were_reloaded = true;
678     }
679     for (uptr i = 0; i < n_modules_; i++) {
680       if (modules_[i].containsAddress(address)) {
681         return &modules_[i];
682       }
683     }
684     // Reload the modules and look up again, if we haven't tried it yet.
685     if (!modules_were_reloaded) {
686       // FIXME: set modules_fresh_ from dlopen()/dlclose() interceptors.
687       // It's too aggressive to reload the list of modules each time we fail
688       // to find a module for a given address.
689       modules_fresh_ = false;
690       return FindModuleForAddress(address);
691     }
692     return 0;
693   }
694 
FindModuleNameAndOffsetForAddress(uptr address,const char ** module_name,uptr * module_offset)695   bool FindModuleNameAndOffsetForAddress(uptr address, const char **module_name,
696                                          uptr *module_offset) {
697     mu_.CheckLocked();
698     LoadedModule *module = FindModuleForAddress(address);
699     if (module == 0)
700       return false;
701     *module_name = module->full_name();
702     *module_offset = address - module->base_address();
703     return true;
704   }
705 
706   // 16K loaded modules should be enough for everyone.
707   static const uptr kMaxNumberOfModuleContexts = 1 << 14;
708   LoadedModule *modules_;  // Array of module descriptions is leaked.
709   uptr n_modules_;
710   // If stale, need to reload the modules before looking up addresses.
711   bool modules_fresh_;
712   BlockingMutex mu_;
713 
714   ExternalSymbolizerInterface *external_symbolizer_;  // Leaked.
715   InternalSymbolizer *const internal_symbolizer_;     // Leaked.
716   LibbacktraceSymbolizer *libbacktrace_symbolizer_;   // Leaked.
717 };
718 
PlatformInit(const char * path_to_external)719 Symbolizer *Symbolizer::PlatformInit(const char *path_to_external) {
720   if (!common_flags()->symbolize) {
721     return new(symbolizer_allocator_) POSIXSymbolizer(0, 0, 0);
722   }
723   InternalSymbolizer* internal_symbolizer =
724       InternalSymbolizer::get(&symbolizer_allocator_);
725   ExternalSymbolizerInterface *external_symbolizer = 0;
726   LibbacktraceSymbolizer *libbacktrace_symbolizer = 0;
727 
728   if (!internal_symbolizer) {
729     libbacktrace_symbolizer =
730         LibbacktraceSymbolizer::get(&symbolizer_allocator_);
731     if (!libbacktrace_symbolizer) {
732       if (path_to_external && path_to_external[0] == '\0') {
733         // External symbolizer is explicitly disabled. Do nothing.
734       } else {
735         // Find path to llvm-symbolizer if it's not provided.
736         if (!path_to_external)
737           path_to_external = FindPathToBinary("llvm-symbolizer");
738         if (path_to_external) {
739           external_symbolizer = new(symbolizer_allocator_)
740               LLVMSymbolizerProcess(path_to_external);
741         } else if (common_flags()->allow_addr2line) {
742           // If llvm-symbolizer is not found, try to use addr2line.
743           if (const char *addr2line_path = FindPathToBinary("addr2line")) {
744             external_symbolizer = new(symbolizer_allocator_)
745                 Addr2LinePool(addr2line_path, &symbolizer_allocator_);
746           }
747         }
748       }
749     }
750   }
751 
752   return new(symbolizer_allocator_) POSIXSymbolizer(
753       external_symbolizer, internal_symbolizer, libbacktrace_symbolizer);
754 }
755 
756 }  // namespace __sanitizer
757 
758 #endif  // SANITIZER_POSIX
759