198 lines · cpp
1//===-- sanitizer_symbolize.cpp ---------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Implementation of weak hooks from sanitizer_symbolizer_posix_libcdep.cpp.10//11//===----------------------------------------------------------------------===//12 13#include <inttypes.h>14#include <stdio.h>15 16#include <string>17 18#include "llvm/DebugInfo/Symbolize/DIPrinter.h"19#include "llvm/DebugInfo/Symbolize/Symbolize.h"20#include "llvm/Demangle/Demangle.h"21 22static llvm::symbolize::LLVMSymbolizer *Symbolizer = nullptr;23static bool Demangle = true;24static bool InlineFrames = true;25 26static llvm::symbolize::LLVMSymbolizer *getDefaultSymbolizer() {27 if (Symbolizer)28 return Symbolizer;29 llvm::symbolize::LLVMSymbolizer::Options Opts;30 Opts.Demangle = Demangle;31 Opts.UntagAddresses = true;32 Symbolizer = new llvm::symbolize::LLVMSymbolizer(Opts);33 return Symbolizer;34}35 36static llvm::symbolize::PrinterConfig getDefaultPrinterConfig() {37 llvm::symbolize::PrinterConfig Config;38 Config.Pretty = false;39 Config.Verbose = false;40 Config.PrintFunctions = true;41 Config.PrintAddress = false;42 Config.SourceContextLines = 0;43 return Config;44}45 46static llvm::symbolize::ErrorHandler symbolize_error_handler(47 llvm::raw_string_ostream &OS) {48 return49 [&](const llvm::ErrorInfoBase &ErrorInfo, llvm::StringRef ErrorBanner) {50 OS << ErrorBanner;51 ErrorInfo.log(OS);52 OS << '\n';53 };54}55 56namespace __sanitizer {57int internal_snprintf(char *buffer, uintptr_t length, const char *format, ...);58} // namespace __sanitizer59 60extern "C" {61 62typedef uint64_t u64;63 64bool __sanitizer_symbolize_code(const char *ModuleName, uint64_t ModuleOffset,65 char *Buffer, int MaxLength) {66 std::string Result;67 {68 llvm::raw_string_ostream OS(Result);69 llvm::symbolize::PrinterConfig Config = getDefaultPrinterConfig();70 llvm::symbolize::Request Request{ModuleName, ModuleOffset};71 auto Printer = std::make_unique<llvm::symbolize::LLVMPrinter>(72 OS, symbolize_error_handler(OS), Config);73 74 // TODO: it is necessary to set proper SectionIndex here.75 // object::SectionedAddress::UndefSection works for only absolute addresses.76 if (InlineFrames) {77 auto ResOrErr = getDefaultSymbolizer()->symbolizeInlinedCode(78 ModuleName,79 {ModuleOffset, llvm::object::SectionedAddress::UndefSection});80 if (!ResOrErr)81 return false;82 Printer->print(Request, ResOrErr.get());83 } else {84 auto ResOrErr = getDefaultSymbolizer()->symbolizeCode(85 ModuleName,86 {ModuleOffset, llvm::object::SectionedAddress::UndefSection});87 if (!ResOrErr)88 return false;89 Printer->print(Request, ResOrErr.get());90 }91 }92 return __sanitizer::internal_snprintf(Buffer, MaxLength, "%s",93 Result.c_str()) < MaxLength;94}95 96bool __sanitizer_symbolize_data(const char *ModuleName, uint64_t ModuleOffset,97 char *Buffer, int MaxLength) {98 std::string Result;99 {100 llvm::symbolize::PrinterConfig Config = getDefaultPrinterConfig();101 llvm::raw_string_ostream OS(Result);102 llvm::symbolize::Request Request{ModuleName, ModuleOffset};103 auto Printer = std::make_unique<llvm::symbolize::LLVMPrinter>(104 OS, symbolize_error_handler(OS), Config);105 106 // TODO: it is necessary to set proper SectionIndex here.107 // object::SectionedAddress::UndefSection works for only absolute addresses.108 auto ResOrErr = getDefaultSymbolizer()->symbolizeData(109 ModuleName,110 {ModuleOffset, llvm::object::SectionedAddress::UndefSection});111 if (!ResOrErr)112 return false;113 Printer->print(Request, ResOrErr.get());114 }115 return __sanitizer::internal_snprintf(Buffer, MaxLength, "%s",116 Result.c_str()) < MaxLength;117}118 119bool __sanitizer_symbolize_frame(const char *ModuleName, uint64_t ModuleOffset,120 char *Buffer, int MaxLength) {121 std::string Result;122 {123 llvm::symbolize::PrinterConfig Config = getDefaultPrinterConfig();124 llvm::raw_string_ostream OS(Result);125 llvm::symbolize::Request Request{ModuleName, ModuleOffset};126 auto Printer = std::make_unique<llvm::symbolize::LLVMPrinter>(127 OS, symbolize_error_handler(OS), Config);128 129 // TODO: it is necessary to set proper SectionIndex here.130 // object::SectionedAddress::UndefSection works for only absolute addresses.131 auto ResOrErr = getDefaultSymbolizer()->symbolizeFrame(132 ModuleName,133 {ModuleOffset, llvm::object::SectionedAddress::UndefSection});134 if (!ResOrErr)135 return false;136 Printer->print(Request, ResOrErr.get());137 }138 return __sanitizer::internal_snprintf(Buffer, MaxLength, "%s",139 Result.c_str()) < MaxLength;140}141 142void __sanitizer_symbolize_flush() {143 if (Symbolizer)144 Symbolizer->flush();145}146 147bool __sanitizer_symbolize_demangle(const char *Name, char *Buffer,148 int MaxLength) {149 std::string Result;150 if (!llvm::nonMicrosoftDemangle(Name, Result))151 return false;152 return __sanitizer::internal_snprintf(Buffer, MaxLength, "%s",153 Result.c_str()) < MaxLength;154}155 156bool __sanitizer_symbolize_set_demangle(bool Value) {157 // Must be called before LLVMSymbolizer created.158 if (Symbolizer)159 return false;160 Demangle = Value;161 return true;162}163 164bool __sanitizer_symbolize_set_inline_frames(bool Value) {165 InlineFrames = Value;166 return true;167}168 169// Override __cxa_atexit and ignore callbacks.170// This prevents crashes in a configuration when the symbolizer171// is built into sanitizer runtime and consequently into the test process.172// LLVM libraries have some global objects destroyed during exit,173// so if the test process triggers any bugs after that, the symbolizer crashes.174// An example stack trace of such crash:175//176// #1 __cxa_throw177// #2 std::__u::__throw_system_error178// #3 std::__u::recursive_mutex::lock179// #4 __sanitizer_llvm::ManagedStaticBase::RegisterManagedStatic180// #5 __sanitizer_llvm::errorToErrorCode181// #6 __sanitizer_llvm::getFileAux182// #7 __sanitizer_llvm::MemoryBuffer::getFileOrSTDIN183// #10 __sanitizer_llvm::symbolize::LLVMSymbolizer::getOrCreateModuleInfo184// #13 __sanitizer::Symbolizer::SymbolizeData185// #14 __tsan::SymbolizeData186// #16 __tsan::ReportRace187// #18 __tsan_write4188// #19 race() () at test/tsan/atexit4.cpp189// #20 cxa_at_exit_wrapper190// #21 __cxa_finalize191// #22 __do_fini192//193// For the standalone llvm-symbolizer this does not hurt,194// we just don't destroy few global objects on exit.195int __cxa_atexit(void (*f)(void *a), void *arg, void *dso) { return 0; }196 197} // extern "C"198