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