aboutsummaryrefslogtreecommitdiff
path: root/compiler-rt/lib/sanitizer_common/symbolizer/sanitizer_symbolize.cpp
blob: 3809880d50b4ae5f8bf4dd40560fed73f3055013 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//===-- sanitizer_symbolize.cpp ---------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Implementation of weak hooks from sanitizer_symbolizer_posix_libcdep.cpp.
//
//===----------------------------------------------------------------------===//

#include <stdio.h>

#include <string>

#include "llvm/DebugInfo/Symbolize/DIPrinter.h"
#include "llvm/DebugInfo/Symbolize/Symbolize.h"

static llvm::symbolize::LLVMSymbolizer *getDefaultSymbolizer() {
  static llvm::symbolize::LLVMSymbolizer *DefaultSymbolizer =
      new llvm::symbolize::LLVMSymbolizer();
  return DefaultSymbolizer;
}

static llvm::symbolize::PrinterConfig getDefaultPrinterConfig() {
  llvm::symbolize::PrinterConfig Config;
  Config.Pretty = false;
  Config.Verbose = false;
  Config.PrintFunctions = true;
  Config.PrintAddress = false;
  Config.SourceContextLines = 0;
  return Config;
}

namespace __sanitizer {
int internal_snprintf(char *buffer, unsigned long length, const char *format,
                      ...);
}  // namespace __sanitizer

extern "C" {

typedef uint64_t u64;

bool __sanitizer_symbolize_code(const char *ModuleName, uint64_t ModuleOffset,
                                char *Buffer, int MaxLength,
                                bool SymbolizeInlineFrames) {
  std::string Result;
  {
    llvm::raw_string_ostream OS(Result);
    llvm::symbolize::PrinterConfig Config = getDefaultPrinterConfig();
    llvm::symbolize::Request Request{ModuleName, ModuleOffset};
    auto Printer =
        std::make_unique<llvm::symbolize::LLVMPrinter>(OS, OS, Config);

    // TODO: it is neccessary to set proper SectionIndex here.
    // object::SectionedAddress::UndefSection works for only absolute addresses.
    if (SymbolizeInlineFrames) {
      auto ResOrErr = getDefaultSymbolizer()->symbolizeInlinedCode(
          ModuleName,
          {ModuleOffset, llvm::object::SectionedAddress::UndefSection});
      Printer->print(Request,
                     ResOrErr ? ResOrErr.get() : llvm::DIInliningInfo());
    } else {
      auto ResOrErr = getDefaultSymbolizer()->symbolizeCode(
          ModuleName,
          {ModuleOffset, llvm::object::SectionedAddress::UndefSection});
      Printer->print(Request, ResOrErr ? ResOrErr.get() : llvm::DILineInfo());
    }
  }
  return __sanitizer::internal_snprintf(Buffer, MaxLength, "%s",
                                        Result.c_str()) < MaxLength;
}

bool __sanitizer_symbolize_data(const char *ModuleName, uint64_t ModuleOffset,
                                char *Buffer, int MaxLength) {
  std::string Result;
  {
    llvm::symbolize::PrinterConfig Config = getDefaultPrinterConfig();
    llvm::raw_string_ostream OS(Result);
    llvm::symbolize::Request Request{ModuleName, ModuleOffset};
    auto Printer =
        std::make_unique<llvm::symbolize::LLVMPrinter>(OS, OS, Config);

    // TODO: it is neccessary to set proper SectionIndex here.
    // object::SectionedAddress::UndefSection works for only absolute addresses.
    auto ResOrErr = getDefaultSymbolizer()->symbolizeData(
        ModuleName,
        {ModuleOffset, llvm::object::SectionedAddress::UndefSection});
    Printer->print(Request, ResOrErr ? ResOrErr.get() : llvm::DIGlobal());
  }
  return __sanitizer::internal_snprintf(Buffer, MaxLength, "%s",
                                        Result.c_str()) < MaxLength;
}

void __sanitizer_symbolize_flush() { getDefaultSymbolizer()->flush(); }

int __sanitizer_symbolize_demangle(const char *Name, char *Buffer,
                                   int MaxLength) {
  std::string Result =
      llvm::symbolize::LLVMSymbolizer::DemangleName(Name, nullptr);
  return __sanitizer::internal_snprintf(Buffer, MaxLength, "%s",
                                        Result.c_str()) < MaxLength
             ? static_cast<int>(Result.size() + 1)
             : 0;
}

// Override __cxa_atexit and ignore callbacks.
// This prevents crashes in a configuration when the symbolizer
// is built into sanitizer runtime and consequently into the test process.
// LLVM libraries have some global objects destroyed during exit,
// so if the test process triggers any bugs after that, the symbolizer crashes.
// An example stack trace of such crash:
//
// #1  __cxa_throw
// #2  std::__u::__throw_system_error
// #3  std::__u::recursive_mutex::lock
// #4  __sanitizer_llvm::ManagedStaticBase::RegisterManagedStatic
// #5  __sanitizer_llvm::errorToErrorCode
// #6  __sanitizer_llvm::getFileAux
// #7  __sanitizer_llvm::MemoryBuffer::getFileOrSTDIN
// #10 __sanitizer_llvm::symbolize::LLVMSymbolizer::getOrCreateModuleInfo
// #13 __sanitizer::Symbolizer::SymbolizeData
// #14 __tsan::SymbolizeData
// #16 __tsan::ReportRace
// #18 __tsan_write4
// #19 race() () at test/tsan/atexit4.cpp
// #20 cxa_at_exit_wrapper
// #21 __cxa_finalize
// #22 __do_fini
//
// For the standalone llvm-symbolizer this does not hurt,
// we just don't destroy few global objects on exit.
int __cxa_atexit(void (*f)(void *a), void *arg, void *dso) { return 0; }

}  // extern "C"