168d75effSDimitry Andric //===-- sanitizer_symbolizer_posix_libcdep.cpp ----------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file is shared between AddressSanitizer and ThreadSanitizer
1068d75effSDimitry Andric // run-time libraries.
1168d75effSDimitry Andric // POSIX-specific implementation of symbolizer parts.
1268d75effSDimitry Andric //===----------------------------------------------------------------------===//
1368d75effSDimitry Andric 
1468d75effSDimitry Andric #include "sanitizer_platform.h"
155f757f3fSDimitry Andric #include "sanitizer_symbolizer_markup.h"
1668d75effSDimitry Andric #if SANITIZER_POSIX
1706c3fb27SDimitry Andric #  include <dlfcn.h>  // for dlsym()
1806c3fb27SDimitry Andric #  include <errno.h>
1906c3fb27SDimitry Andric #  include <stdint.h>
2006c3fb27SDimitry Andric #  include <stdlib.h>
2106c3fb27SDimitry Andric #  include <sys/wait.h>
2206c3fb27SDimitry Andric #  include <unistd.h>
2306c3fb27SDimitry Andric 
2468d75effSDimitry Andric #  include "sanitizer_allocator_internal.h"
2568d75effSDimitry Andric #  include "sanitizer_common.h"
2668d75effSDimitry Andric #  include "sanitizer_file.h"
2768d75effSDimitry Andric #  include "sanitizer_flags.h"
2868d75effSDimitry Andric #  include "sanitizer_internal_defs.h"
2968d75effSDimitry Andric #  include "sanitizer_linux.h"
3068d75effSDimitry Andric #  include "sanitizer_placement_new.h"
3168d75effSDimitry Andric #  include "sanitizer_posix.h"
3268d75effSDimitry Andric #  include "sanitizer_procmaps.h"
3368d75effSDimitry Andric #  include "sanitizer_symbolizer_internal.h"
3468d75effSDimitry Andric #  include "sanitizer_symbolizer_libbacktrace.h"
3568d75effSDimitry Andric #  include "sanitizer_symbolizer_mac.h"
3668d75effSDimitry Andric 
3768d75effSDimitry Andric // C++ demangling function, as required by Itanium C++ ABI. This is weak,
3868d75effSDimitry Andric // because we do not require a C++ ABI library to be linked to a program
3968d75effSDimitry Andric // using sanitizers; if it's not present, we'll just use the mangled name.
4068d75effSDimitry Andric namespace __cxxabiv1 {
4168d75effSDimitry Andric   extern "C" SANITIZER_WEAK_ATTRIBUTE
4268d75effSDimitry Andric   char *__cxa_demangle(const char *mangled, char *buffer,
4368d75effSDimitry Andric                                   size_t *length, int *status);
4468d75effSDimitry Andric }
4568d75effSDimitry Andric 
4668d75effSDimitry Andric namespace __sanitizer {
4768d75effSDimitry Andric 
4868d75effSDimitry Andric // Attempts to demangle the name via __cxa_demangle from __cxxabiv1.
DemangleCXXABI(const char * name)4968d75effSDimitry Andric const char *DemangleCXXABI(const char *name) {
5068d75effSDimitry Andric   // FIXME: __cxa_demangle aggressively insists on allocating memory.
5168d75effSDimitry Andric   // There's not much we can do about that, short of providing our
5268d75effSDimitry Andric   // own demangler (libc++abi's implementation could be adapted so that
5368d75effSDimitry Andric   // it does not allocate). For now, we just call it anyway, and we leak
5468d75effSDimitry Andric   // the returned value.
5568d75effSDimitry Andric   if (&__cxxabiv1::__cxa_demangle)
5668d75effSDimitry Andric     if (const char *demangled_name =
5768d75effSDimitry Andric           __cxxabiv1::__cxa_demangle(name, 0, 0, 0))
5868d75effSDimitry Andric       return demangled_name;
5968d75effSDimitry Andric 
605f757f3fSDimitry Andric   return nullptr;
6168d75effSDimitry Andric }
6268d75effSDimitry Andric 
6368d75effSDimitry Andric // As of now, there are no headers for the Swift runtime. Once they are
6468d75effSDimitry Andric // present, we will weakly link since we do not require Swift runtime to be
6568d75effSDimitry Andric // linked.
6668d75effSDimitry Andric typedef char *(*swift_demangle_ft)(const char *mangledName,
6768d75effSDimitry Andric                                    size_t mangledNameLength, char *outputBuffer,
6868d75effSDimitry Andric                                    size_t *outputBufferSize, uint32_t flags);
6968d75effSDimitry Andric static swift_demangle_ft swift_demangle_f;
7068d75effSDimitry Andric 
7168d75effSDimitry Andric // This must not happen lazily at symbolication time, because dlsym uses
7268d75effSDimitry Andric // malloc and thread-local storage, which is not a good thing to do during
7368d75effSDimitry Andric // symbolication.
InitializeSwiftDemangler()7468d75effSDimitry Andric static void InitializeSwiftDemangler() {
7568d75effSDimitry Andric   swift_demangle_f = (swift_demangle_ft)dlsym(RTLD_DEFAULT, "swift_demangle");
7668d75effSDimitry Andric }
7768d75effSDimitry Andric 
7868d75effSDimitry Andric // Attempts to demangle a Swift name. The demangler will return nullptr if a
7968d75effSDimitry Andric // non-Swift name is passed in.
DemangleSwift(const char * name)8068d75effSDimitry Andric const char *DemangleSwift(const char *name) {
8168d75effSDimitry Andric   if (swift_demangle_f)
8268d75effSDimitry Andric     return swift_demangle_f(name, internal_strlen(name), 0, 0, 0);
8368d75effSDimitry Andric 
8468d75effSDimitry Andric   return nullptr;
8568d75effSDimitry Andric }
8668d75effSDimitry Andric 
DemangleSwiftAndCXX(const char * name)8768d75effSDimitry Andric const char *DemangleSwiftAndCXX(const char *name) {
8868d75effSDimitry Andric   if (!name) return nullptr;
8968d75effSDimitry Andric   if (const char *swift_demangled_name = DemangleSwift(name))
9068d75effSDimitry Andric     return swift_demangled_name;
9168d75effSDimitry Andric   return DemangleCXXABI(name);
9268d75effSDimitry Andric }
9368d75effSDimitry Andric 
CreateTwoHighNumberedPipes(int * infd_,int * outfd_)9468d75effSDimitry Andric static bool CreateTwoHighNumberedPipes(int *infd_, int *outfd_) {
9568d75effSDimitry Andric   int *infd = NULL;
9668d75effSDimitry Andric   int *outfd = NULL;
9768d75effSDimitry Andric   // The client program may close its stdin and/or stdout and/or stderr
9868d75effSDimitry Andric   // thus allowing socketpair to reuse file descriptors 0, 1 or 2.
9968d75effSDimitry Andric   // In this case the communication between the forked processes may be
10068d75effSDimitry Andric   // broken if either the parent or the child tries to close or duplicate
10168d75effSDimitry Andric   // these descriptors. The loop below produces two pairs of file
10268d75effSDimitry Andric   // descriptors, each greater than 2 (stderr).
10368d75effSDimitry Andric   int sock_pair[5][2];
10468d75effSDimitry Andric   for (int i = 0; i < 5; i++) {
10568d75effSDimitry Andric     if (pipe(sock_pair[i]) == -1) {
10668d75effSDimitry Andric       for (int j = 0; j < i; j++) {
10768d75effSDimitry Andric         internal_close(sock_pair[j][0]);
10868d75effSDimitry Andric         internal_close(sock_pair[j][1]);
10968d75effSDimitry Andric       }
11068d75effSDimitry Andric       return false;
11168d75effSDimitry Andric     } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) {
11268d75effSDimitry Andric       if (infd == NULL) {
11368d75effSDimitry Andric         infd = sock_pair[i];
11468d75effSDimitry Andric       } else {
11568d75effSDimitry Andric         outfd = sock_pair[i];
11668d75effSDimitry Andric         for (int j = 0; j < i; j++) {
11768d75effSDimitry Andric           if (sock_pair[j] == infd) continue;
11868d75effSDimitry Andric           internal_close(sock_pair[j][0]);
11968d75effSDimitry Andric           internal_close(sock_pair[j][1]);
12068d75effSDimitry Andric         }
12168d75effSDimitry Andric         break;
12268d75effSDimitry Andric       }
12368d75effSDimitry Andric     }
12468d75effSDimitry Andric   }
12568d75effSDimitry Andric   CHECK(infd);
12668d75effSDimitry Andric   CHECK(outfd);
12768d75effSDimitry Andric   infd_[0] = infd[0];
12868d75effSDimitry Andric   infd_[1] = infd[1];
12968d75effSDimitry Andric   outfd_[0] = outfd[0];
13068d75effSDimitry Andric   outfd_[1] = outfd[1];
13168d75effSDimitry Andric   return true;
13268d75effSDimitry Andric }
13368d75effSDimitry Andric 
StartSymbolizerSubprocess()13468d75effSDimitry Andric bool SymbolizerProcess::StartSymbolizerSubprocess() {
13568d75effSDimitry Andric   if (!FileExists(path_)) {
13668d75effSDimitry Andric     if (!reported_invalid_path_) {
13768d75effSDimitry Andric       Report("WARNING: invalid path to external symbolizer!\n");
13868d75effSDimitry Andric       reported_invalid_path_ = true;
13968d75effSDimitry Andric     }
14068d75effSDimitry Andric     return false;
14168d75effSDimitry Andric   }
14268d75effSDimitry Andric 
14368d75effSDimitry Andric   const char *argv[kArgVMax];
14468d75effSDimitry Andric   GetArgV(path_, argv);
14568d75effSDimitry Andric   pid_t pid;
14668d75effSDimitry Andric 
1475ffd83dbSDimitry Andric   // Report how symbolizer is being launched for debugging purposes.
1485ffd83dbSDimitry Andric   if (Verbosity() >= 3) {
1495ffd83dbSDimitry Andric     // Only use `Report` for first line so subsequent prints don't get prefixed
1505ffd83dbSDimitry Andric     // with current PID.
1515ffd83dbSDimitry Andric     Report("Launching Symbolizer process: ");
1525ffd83dbSDimitry Andric     for (unsigned index = 0; index < kArgVMax && argv[index]; ++index)
1535ffd83dbSDimitry Andric       Printf("%s ", argv[index]);
1545ffd83dbSDimitry Andric     Printf("\n");
1555ffd83dbSDimitry Andric   }
1565ffd83dbSDimitry Andric 
15768d75effSDimitry Andric   if (use_posix_spawn_) {
15881ad6265SDimitry Andric #if SANITIZER_APPLE
1595ffd83dbSDimitry Andric     fd_t fd = internal_spawn(argv, const_cast<const char **>(GetEnvP()), &pid);
16068d75effSDimitry Andric     if (fd == kInvalidFd) {
16168d75effSDimitry Andric       Report("WARNING: failed to spawn external symbolizer (errno: %d)\n",
16268d75effSDimitry Andric              errno);
16368d75effSDimitry Andric       return false;
16468d75effSDimitry Andric     }
16568d75effSDimitry Andric 
16668d75effSDimitry Andric     input_fd_ = fd;
16768d75effSDimitry Andric     output_fd_ = fd;
16881ad6265SDimitry Andric #else  // SANITIZER_APPLE
16968d75effSDimitry Andric     UNIMPLEMENTED();
17081ad6265SDimitry Andric #endif  // SANITIZER_APPLE
17168d75effSDimitry Andric   } else {
17268d75effSDimitry Andric     fd_t infd[2] = {}, outfd[2] = {};
17368d75effSDimitry Andric     if (!CreateTwoHighNumberedPipes(infd, outfd)) {
17468d75effSDimitry Andric       Report("WARNING: Can't create a socket pair to start "
17568d75effSDimitry Andric              "external symbolizer (errno: %d)\n", errno);
17668d75effSDimitry Andric       return false;
17768d75effSDimitry Andric     }
17868d75effSDimitry Andric 
1795ffd83dbSDimitry Andric     pid = StartSubprocess(path_, argv, GetEnvP(), /* stdin */ outfd[0],
18068d75effSDimitry Andric                           /* stdout */ infd[1]);
18168d75effSDimitry Andric     if (pid < 0) {
18268d75effSDimitry Andric       internal_close(infd[0]);
18368d75effSDimitry Andric       internal_close(outfd[1]);
18468d75effSDimitry Andric       return false;
18568d75effSDimitry Andric     }
18668d75effSDimitry Andric 
18768d75effSDimitry Andric     input_fd_ = infd[0];
18868d75effSDimitry Andric     output_fd_ = outfd[1];
18968d75effSDimitry Andric   }
19068d75effSDimitry Andric 
19168d75effSDimitry Andric   CHECK_GT(pid, 0);
19268d75effSDimitry Andric 
19368d75effSDimitry Andric   // Check that symbolizer subprocess started successfully.
19468d75effSDimitry Andric   SleepForMillis(kSymbolizerStartupTimeMillis);
19568d75effSDimitry Andric   if (!IsProcessRunning(pid)) {
19668d75effSDimitry Andric     // Either waitpid failed, or child has already exited.
19768d75effSDimitry Andric     Report("WARNING: external symbolizer didn't start up correctly!\n");
19868d75effSDimitry Andric     return false;
19968d75effSDimitry Andric   }
20068d75effSDimitry Andric 
20168d75effSDimitry Andric   return true;
20268d75effSDimitry Andric }
20368d75effSDimitry Andric 
204e8d8bef9SDimitry Andric class Addr2LineProcess final : public SymbolizerProcess {
20568d75effSDimitry Andric  public:
Addr2LineProcess(const char * path,const char * module_name)20668d75effSDimitry Andric   Addr2LineProcess(const char *path, const char *module_name)
20768d75effSDimitry Andric       : SymbolizerProcess(path), module_name_(internal_strdup(module_name)) {}
20868d75effSDimitry Andric 
module_name() const20968d75effSDimitry Andric   const char *module_name() const { return module_name_; }
21068d75effSDimitry Andric 
21168d75effSDimitry Andric  private:
GetArgV(const char * path_to_binary,const char * (& argv)[kArgVMax]) const21268d75effSDimitry Andric   void GetArgV(const char *path_to_binary,
21368d75effSDimitry Andric                const char *(&argv)[kArgVMax]) const override {
21468d75effSDimitry Andric     int i = 0;
21568d75effSDimitry Andric     argv[i++] = path_to_binary;
2160eae32dcSDimitry Andric     if (common_flags()->demangle)
2170eae32dcSDimitry Andric       argv[i++] = "-C";
2180eae32dcSDimitry Andric     if (common_flags()->symbolize_inline_frames)
2190eae32dcSDimitry Andric       argv[i++] = "-i";
2200eae32dcSDimitry Andric     argv[i++] = "-fe";
22168d75effSDimitry Andric     argv[i++] = module_name_;
22268d75effSDimitry Andric     argv[i++] = nullptr;
2230eae32dcSDimitry Andric     CHECK_LE(i, kArgVMax);
22468d75effSDimitry Andric   }
22568d75effSDimitry Andric 
22668d75effSDimitry Andric   bool ReachedEndOfOutput(const char *buffer, uptr length) const override;
22768d75effSDimitry Andric 
ReadFromSymbolizer()22881ad6265SDimitry Andric   bool ReadFromSymbolizer() override {
22981ad6265SDimitry Andric     if (!SymbolizerProcess::ReadFromSymbolizer())
23068d75effSDimitry Andric       return false;
23181ad6265SDimitry Andric     auto &buff = GetBuff();
23268d75effSDimitry Andric     // We should cut out output_terminator_ at the end of given buffer,
23368d75effSDimitry Andric     // appended by addr2line to mark the end of its meaningful output.
23468d75effSDimitry Andric     // We cannot scan buffer from it's beginning, because it is legal for it
23568d75effSDimitry Andric     // to start with output_terminator_ in case given offset is invalid. So,
23668d75effSDimitry Andric     // scanning from second character.
23781ad6265SDimitry Andric     char *garbage = internal_strstr(buff.data() + 1, output_terminator_);
23868d75effSDimitry Andric     // This should never be NULL since buffer must end up with
23968d75effSDimitry Andric     // output_terminator_.
24068d75effSDimitry Andric     CHECK(garbage);
24181ad6265SDimitry Andric 
24268d75effSDimitry Andric     // Trim the buffer.
24381ad6265SDimitry Andric     uintptr_t new_size = garbage - buff.data();
24481ad6265SDimitry Andric     GetBuff().resize(new_size);
24581ad6265SDimitry Andric     GetBuff().push_back('\0');
24668d75effSDimitry Andric     return true;
24768d75effSDimitry Andric   }
24868d75effSDimitry Andric 
24968d75effSDimitry Andric   const char *module_name_;  // Owned, leaked.
25068d75effSDimitry Andric   static const char output_terminator_[];
25168d75effSDimitry Andric };
25268d75effSDimitry Andric 
25368d75effSDimitry Andric const char Addr2LineProcess::output_terminator_[] = "??\n??:0\n";
25468d75effSDimitry Andric 
ReachedEndOfOutput(const char * buffer,uptr length) const25568d75effSDimitry Andric bool Addr2LineProcess::ReachedEndOfOutput(const char *buffer,
25668d75effSDimitry Andric                                           uptr length) const {
25768d75effSDimitry Andric   const size_t kTerminatorLen = sizeof(output_terminator_) - 1;
25868d75effSDimitry Andric   // Skip, if we read just kTerminatorLen bytes, because Addr2Line output
25968d75effSDimitry Andric   // should consist at least of two pairs of lines:
26068d75effSDimitry Andric   // 1. First one, corresponding to given offset to be symbolized
26168d75effSDimitry Andric   // (may be equal to output_terminator_, if offset is not valid).
26268d75effSDimitry Andric   // 2. Second one for output_terminator_, itself to mark the end of output.
26368d75effSDimitry Andric   if (length <= kTerminatorLen) return false;
26468d75effSDimitry Andric   // Addr2Line output should end up with output_terminator_.
26568d75effSDimitry Andric   return !internal_memcmp(buffer + length - kTerminatorLen,
26668d75effSDimitry Andric                           output_terminator_, kTerminatorLen);
26768d75effSDimitry Andric }
26868d75effSDimitry Andric 
269e8d8bef9SDimitry Andric class Addr2LinePool final : public SymbolizerTool {
27068d75effSDimitry Andric  public:
Addr2LinePool(const char * addr2line_path,LowLevelAllocator * allocator)27168d75effSDimitry Andric   explicit Addr2LinePool(const char *addr2line_path,
27268d75effSDimitry Andric                          LowLevelAllocator *allocator)
27368d75effSDimitry Andric       : addr2line_path_(addr2line_path), allocator_(allocator) {
27468d75effSDimitry Andric     addr2line_pool_.reserve(16);
27568d75effSDimitry Andric   }
27668d75effSDimitry Andric 
SymbolizePC(uptr addr,SymbolizedStack * stack)27768d75effSDimitry Andric   bool SymbolizePC(uptr addr, SymbolizedStack *stack) override {
27868d75effSDimitry Andric     if (const char *buf =
27968d75effSDimitry Andric             SendCommand(stack->info.module, stack->info.module_offset)) {
28068d75effSDimitry Andric       ParseSymbolizePCOutput(buf, stack);
28168d75effSDimitry Andric       return true;
28268d75effSDimitry Andric     }
28368d75effSDimitry Andric     return false;
28468d75effSDimitry Andric   }
28568d75effSDimitry Andric 
SymbolizeData(uptr addr,DataInfo * info)28668d75effSDimitry Andric   bool SymbolizeData(uptr addr, DataInfo *info) override {
28768d75effSDimitry Andric     return false;
28868d75effSDimitry Andric   }
28968d75effSDimitry Andric 
29068d75effSDimitry Andric  private:
SendCommand(const char * module_name,uptr module_offset)29168d75effSDimitry Andric   const char *SendCommand(const char *module_name, uptr module_offset) {
29268d75effSDimitry Andric     Addr2LineProcess *addr2line = 0;
29368d75effSDimitry Andric     for (uptr i = 0; i < addr2line_pool_.size(); ++i) {
29468d75effSDimitry Andric       if (0 ==
29568d75effSDimitry Andric           internal_strcmp(module_name, addr2line_pool_[i]->module_name())) {
29668d75effSDimitry Andric         addr2line = addr2line_pool_[i];
29768d75effSDimitry Andric         break;
29868d75effSDimitry Andric       }
29968d75effSDimitry Andric     }
30068d75effSDimitry Andric     if (!addr2line) {
30168d75effSDimitry Andric       addr2line =
30268d75effSDimitry Andric           new(*allocator_) Addr2LineProcess(addr2line_path_, module_name);
30368d75effSDimitry Andric       addr2line_pool_.push_back(addr2line);
30468d75effSDimitry Andric     }
30568d75effSDimitry Andric     CHECK_EQ(0, internal_strcmp(module_name, addr2line->module_name()));
30668d75effSDimitry Andric     char buffer[kBufferSize];
30768d75effSDimitry Andric     internal_snprintf(buffer, kBufferSize, "0x%zx\n0x%zx\n",
30868d75effSDimitry Andric                       module_offset, dummy_address_);
30968d75effSDimitry Andric     return addr2line->SendCommand(buffer);
31068d75effSDimitry Andric   }
31168d75effSDimitry Andric 
31268d75effSDimitry Andric   static const uptr kBufferSize = 64;
31368d75effSDimitry Andric   const char *addr2line_path_;
31468d75effSDimitry Andric   LowLevelAllocator *allocator_;
31568d75effSDimitry Andric   InternalMmapVector<Addr2LineProcess*> addr2line_pool_;
31668d75effSDimitry Andric   static const uptr dummy_address_ =
31768d75effSDimitry Andric       FIRST_32_SECOND_64(UINT32_MAX, UINT64_MAX);
31868d75effSDimitry Andric };
31968d75effSDimitry Andric 
32068d75effSDimitry Andric #  if SANITIZER_SUPPORTS_WEAK_HOOKS
32168d75effSDimitry Andric extern "C" {
3225ffd83dbSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE bool
3235ffd83dbSDimitry Andric __sanitizer_symbolize_code(const char *ModuleName, u64 ModuleOffset,
32468d75effSDimitry Andric                            char *Buffer, int MaxLength);
3250eae32dcSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE bool
3260eae32dcSDimitry Andric __sanitizer_symbolize_data(const char *ModuleName, u64 ModuleOffset,
3270eae32dcSDimitry Andric                            char *Buffer, int MaxLength);
3285f757f3fSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE bool
3295f757f3fSDimitry Andric __sanitizer_symbolize_frame(const char *ModuleName, u64 ModuleOffset,
3305f757f3fSDimitry Andric                             char *Buffer, int MaxLength);
3310eae32dcSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void
3320eae32dcSDimitry Andric __sanitizer_symbolize_flush();
3335f757f3fSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE bool
3340eae32dcSDimitry Andric __sanitizer_symbolize_demangle(const char *Name, char *Buffer, int MaxLength);
3350eae32dcSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE bool
3360eae32dcSDimitry Andric __sanitizer_symbolize_set_demangle(bool Demangle);
3370eae32dcSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE bool
3380eae32dcSDimitry Andric __sanitizer_symbolize_set_inline_frames(bool InlineFrames);
33968d75effSDimitry Andric }  // extern "C"
34068d75effSDimitry Andric 
341e8d8bef9SDimitry Andric class InternalSymbolizer final : public SymbolizerTool {
34268d75effSDimitry Andric  public:
get(LowLevelAllocator * alloc)34368d75effSDimitry Andric   static InternalSymbolizer *get(LowLevelAllocator *alloc) {
344*cb14a3feSDimitry Andric     // These one is the most used one, so we will use it to detect a presence of
345*cb14a3feSDimitry Andric     // internal symbolizer.
346*cb14a3feSDimitry Andric     if (&__sanitizer_symbolize_code == nullptr)
347*cb14a3feSDimitry Andric       return nullptr;
3480eae32dcSDimitry Andric     CHECK(__sanitizer_symbolize_set_demangle(common_flags()->demangle));
3490eae32dcSDimitry Andric     CHECK(__sanitizer_symbolize_set_inline_frames(
3500eae32dcSDimitry Andric         common_flags()->symbolize_inline_frames));
35168d75effSDimitry Andric     return new (*alloc) InternalSymbolizer();
35268d75effSDimitry Andric   }
35368d75effSDimitry Andric 
SymbolizePC(uptr addr,SymbolizedStack * stack)35468d75effSDimitry Andric   bool SymbolizePC(uptr addr, SymbolizedStack *stack) override {
35568d75effSDimitry Andric     bool result = __sanitizer_symbolize_code(
3565f757f3fSDimitry Andric         stack->info.module, stack->info.module_offset, buffer_, sizeof(buffer_));
3570eae32dcSDimitry Andric     if (result)
3580eae32dcSDimitry Andric       ParseSymbolizePCOutput(buffer_, stack);
35968d75effSDimitry Andric     return result;
36068d75effSDimitry Andric   }
36168d75effSDimitry Andric 
SymbolizeData(uptr addr,DataInfo * info)36268d75effSDimitry Andric   bool SymbolizeData(uptr addr, DataInfo *info) override {
36368d75effSDimitry Andric     bool result = __sanitizer_symbolize_data(info->module, info->module_offset,
3645f757f3fSDimitry Andric                                              buffer_, sizeof(buffer_));
36568d75effSDimitry Andric     if (result) {
36668d75effSDimitry Andric       ParseSymbolizeDataOutput(buffer_, info);
36768d75effSDimitry Andric       info->start += (addr - info->module_offset);  // Add the base address.
36868d75effSDimitry Andric     }
36968d75effSDimitry Andric     return result;
37068d75effSDimitry Andric   }
37168d75effSDimitry Andric 
SymbolizeFrame(uptr addr,FrameInfo * info)3725f757f3fSDimitry Andric   bool SymbolizeFrame(uptr addr, FrameInfo *info) override {
3735f757f3fSDimitry Andric     bool result = __sanitizer_symbolize_frame(info->module, info->module_offset,
3745f757f3fSDimitry Andric                                               buffer_, sizeof(buffer_));
3755f757f3fSDimitry Andric     if (result)
3765f757f3fSDimitry Andric       ParseSymbolizeFrameOutput(buffer_, &info->locals);
3775f757f3fSDimitry Andric     return result;
3785f757f3fSDimitry Andric   }
3795f757f3fSDimitry Andric 
Flush()380*cb14a3feSDimitry Andric   void Flush() override { __sanitizer_symbolize_flush(); }
38168d75effSDimitry Andric 
Demangle(const char * name)38268d75effSDimitry Andric   const char *Demangle(const char *name) override {
383*cb14a3feSDimitry Andric     if (__sanitizer_symbolize_demangle(name, buffer_, sizeof(buffer_))) {
3845f757f3fSDimitry Andric       char *res_buff = nullptr;
3855f757f3fSDimitry Andric       ExtractToken(buffer_, "", &res_buff);
38668d75effSDimitry Andric       return res_buff;
38768d75effSDimitry Andric     }
3885f757f3fSDimitry Andric     return nullptr;
38968d75effSDimitry Andric   }
39068d75effSDimitry Andric 
39168d75effSDimitry Andric  private:
InternalSymbolizer()39268d75effSDimitry Andric   InternalSymbolizer() {}
39368d75effSDimitry Andric 
3945f757f3fSDimitry Andric   char buffer_[16 * 1024];
39568d75effSDimitry Andric };
39668d75effSDimitry Andric #  else  // SANITIZER_SUPPORTS_WEAK_HOOKS
39768d75effSDimitry Andric 
398e8d8bef9SDimitry Andric class InternalSymbolizer final : public SymbolizerTool {
39968d75effSDimitry Andric  public:
get(LowLevelAllocator * alloc)40068d75effSDimitry Andric   static InternalSymbolizer *get(LowLevelAllocator *alloc) { return 0; }
40168d75effSDimitry Andric };
40268d75effSDimitry Andric 
40368d75effSDimitry Andric #  endif  // SANITIZER_SUPPORTS_WEAK_HOOKS
40468d75effSDimitry Andric 
PlatformDemangle(const char * name)40568d75effSDimitry Andric const char *Symbolizer::PlatformDemangle(const char *name) {
40668d75effSDimitry Andric   return DemangleSwiftAndCXX(name);
40768d75effSDimitry Andric }
40868d75effSDimitry Andric 
ChooseExternalSymbolizer(LowLevelAllocator * allocator)40968d75effSDimitry Andric static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) {
41068d75effSDimitry Andric   const char *path = common_flags()->external_symbolizer_path;
411fe6060f1SDimitry Andric 
412fe6060f1SDimitry Andric   if (path && internal_strchr(path, '%')) {
413fe6060f1SDimitry Andric     char *new_path = (char *)InternalAlloc(kMaxPathLength);
414fe6060f1SDimitry Andric     SubstituteForFlagValue(path, new_path, kMaxPathLength);
415fe6060f1SDimitry Andric     path = new_path;
416fe6060f1SDimitry Andric   }
417fe6060f1SDimitry Andric 
41868d75effSDimitry Andric   const char *binary_name = path ? StripModuleName(path) : "";
419fe6060f1SDimitry Andric   static const char kLLVMSymbolizerPrefix[] = "llvm-symbolizer";
42068d75effSDimitry Andric   if (path && path[0] == '\0') {
42168d75effSDimitry Andric     VReport(2, "External symbolizer is explicitly disabled.\n");
42268d75effSDimitry Andric     return nullptr;
423fe6060f1SDimitry Andric   } else if (!internal_strncmp(binary_name, kLLVMSymbolizerPrefix,
424fe6060f1SDimitry Andric                                internal_strlen(kLLVMSymbolizerPrefix))) {
42568d75effSDimitry Andric     VReport(2, "Using llvm-symbolizer at user-specified path: %s\n", path);
42668d75effSDimitry Andric     return new(*allocator) LLVMSymbolizer(path, allocator);
42768d75effSDimitry Andric   } else if (!internal_strcmp(binary_name, "atos")) {
42881ad6265SDimitry Andric #if SANITIZER_APPLE
42968d75effSDimitry Andric     VReport(2, "Using atos at user-specified path: %s\n", path);
43068d75effSDimitry Andric     return new(*allocator) AtosSymbolizer(path, allocator);
43181ad6265SDimitry Andric #else  // SANITIZER_APPLE
43268d75effSDimitry Andric     Report("ERROR: Using `atos` is only supported on Darwin.\n");
43368d75effSDimitry Andric     Die();
43481ad6265SDimitry Andric #endif  // SANITIZER_APPLE
43568d75effSDimitry Andric   } else if (!internal_strcmp(binary_name, "addr2line")) {
43668d75effSDimitry Andric     VReport(2, "Using addr2line at user-specified path: %s\n", path);
43768d75effSDimitry Andric     return new(*allocator) Addr2LinePool(path, allocator);
43868d75effSDimitry Andric   } else if (path) {
43968d75effSDimitry Andric     Report("ERROR: External symbolizer path is set to '%s' which isn't "
44068d75effSDimitry Andric            "a known symbolizer. Please set the path to the llvm-symbolizer "
44168d75effSDimitry Andric            "binary or other known tool.\n", path);
44268d75effSDimitry Andric     Die();
44368d75effSDimitry Andric   }
44468d75effSDimitry Andric 
44568d75effSDimitry Andric   // Otherwise symbolizer program is unknown, let's search $PATH
44668d75effSDimitry Andric   CHECK(path == nullptr);
44781ad6265SDimitry Andric #if SANITIZER_APPLE
44868d75effSDimitry Andric   if (const char *found_path = FindPathToBinary("atos")) {
44968d75effSDimitry Andric     VReport(2, "Using atos found at: %s\n", found_path);
45068d75effSDimitry Andric     return new(*allocator) AtosSymbolizer(found_path, allocator);
45168d75effSDimitry Andric   }
45281ad6265SDimitry Andric #endif  // SANITIZER_APPLE
45368d75effSDimitry Andric   if (const char *found_path = FindPathToBinary("llvm-symbolizer")) {
45468d75effSDimitry Andric     VReport(2, "Using llvm-symbolizer found at: %s\n", found_path);
45568d75effSDimitry Andric     return new(*allocator) LLVMSymbolizer(found_path, allocator);
45668d75effSDimitry Andric   }
45768d75effSDimitry Andric   if (common_flags()->allow_addr2line) {
45868d75effSDimitry Andric     if (const char *found_path = FindPathToBinary("addr2line")) {
45968d75effSDimitry Andric       VReport(2, "Using addr2line found at: %s\n", found_path);
46068d75effSDimitry Andric       return new(*allocator) Addr2LinePool(found_path, allocator);
46168d75effSDimitry Andric     }
46268d75effSDimitry Andric   }
46368d75effSDimitry Andric   return nullptr;
46468d75effSDimitry Andric }
46568d75effSDimitry Andric 
ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> * list,LowLevelAllocator * allocator)46668d75effSDimitry Andric static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list,
46768d75effSDimitry Andric                                   LowLevelAllocator *allocator) {
46868d75effSDimitry Andric   if (!common_flags()->symbolize) {
46968d75effSDimitry Andric     VReport(2, "Symbolizer is disabled.\n");
47068d75effSDimitry Andric     return;
47168d75effSDimitry Andric   }
4725f757f3fSDimitry Andric   if (common_flags()->enable_symbolizer_markup) {
4735f757f3fSDimitry Andric     VReport(2, "Using symbolizer markup");
4745f757f3fSDimitry Andric     SymbolizerTool *tool = new (*allocator) MarkupSymbolizerTool();
4755f757f3fSDimitry Andric     CHECK(tool);
4765f757f3fSDimitry Andric     list->push_back(tool);
4775f757f3fSDimitry Andric   }
47868d75effSDimitry Andric   if (IsAllocatorOutOfMemory()) {
47968d75effSDimitry Andric     VReport(2, "Cannot use internal symbolizer: out of memory\n");
48068d75effSDimitry Andric   } else if (SymbolizerTool *tool = InternalSymbolizer::get(allocator)) {
48168d75effSDimitry Andric     VReport(2, "Using internal symbolizer.\n");
48268d75effSDimitry Andric     list->push_back(tool);
48368d75effSDimitry Andric     return;
48468d75effSDimitry Andric   }
48568d75effSDimitry Andric   if (SymbolizerTool *tool = LibbacktraceSymbolizer::get(allocator)) {
48668d75effSDimitry Andric     VReport(2, "Using libbacktrace symbolizer.\n");
48768d75effSDimitry Andric     list->push_back(tool);
48868d75effSDimitry Andric     return;
48968d75effSDimitry Andric   }
49068d75effSDimitry Andric 
49168d75effSDimitry Andric   if (SymbolizerTool *tool = ChooseExternalSymbolizer(allocator)) {
49268d75effSDimitry Andric     list->push_back(tool);
49368d75effSDimitry Andric   }
49468d75effSDimitry Andric 
49581ad6265SDimitry Andric #if SANITIZER_APPLE
49668d75effSDimitry Andric   VReport(2, "Using dladdr symbolizer.\n");
49768d75effSDimitry Andric   list->push_back(new(*allocator) DlAddrSymbolizer());
49881ad6265SDimitry Andric #endif  // SANITIZER_APPLE
49968d75effSDimitry Andric }
50068d75effSDimitry Andric 
PlatformInit()50168d75effSDimitry Andric Symbolizer *Symbolizer::PlatformInit() {
50268d75effSDimitry Andric   IntrusiveList<SymbolizerTool> list;
50368d75effSDimitry Andric   list.clear();
50468d75effSDimitry Andric   ChooseSymbolizerTools(&list, &symbolizer_allocator_);
50568d75effSDimitry Andric   return new(symbolizer_allocator_) Symbolizer(list);
50668d75effSDimitry Andric }
50768d75effSDimitry Andric 
LateInitialize()50868d75effSDimitry Andric void Symbolizer::LateInitialize() {
5090eae32dcSDimitry Andric   Symbolizer::GetOrInit();
51068d75effSDimitry Andric   InitializeSwiftDemangler();
51168d75effSDimitry Andric }
51268d75effSDimitry Andric 
51368d75effSDimitry Andric }  // namespace __sanitizer
51468d75effSDimitry Andric 
51568d75effSDimitry Andric #endif  // SANITIZER_POSIX
516