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