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