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-exception 6// 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 21static llvm::symbolize::LLVMSymbolizer *Symbolizer = nullptr; 22static bool Demangle = true; 23static bool InlineFrames = true; 24 25static llvm::symbolize::LLVMSymbolizer *getDefaultSymbolizer() { 26 if (Symbolizer) 27 return Symbolizer; 28 llvm::symbolize::LLVMSymbolizer::Options Opts; 29 Opts.Demangle = Demangle; 30 Symbolizer = new llvm::symbolize::LLVMSymbolizer(Opts); 31 return Symbolizer; 32} 33 34static llvm::symbolize::PrinterConfig getDefaultPrinterConfig() { 35 llvm::symbolize::PrinterConfig Config; 36 Config.Pretty = false; 37 Config.Verbose = false; 38 Config.PrintFunctions = true; 39 Config.PrintAddress = false; 40 Config.SourceContextLines = 0; 41 return Config; 42} 43 44namespace __sanitizer { 45int internal_snprintf(char *buffer, uintptr_t length, const char *format, 46 ...); 47} // namespace __sanitizer 48 49extern "C" { 50 51typedef uint64_t u64; 52 53bool __sanitizer_symbolize_code(const char *ModuleName, uint64_t ModuleOffset, 54 char *Buffer, int MaxLength) { 55 std::string Result; 56 { 57 llvm::raw_string_ostream OS(Result); 58 llvm::symbolize::PrinterConfig Config = getDefaultPrinterConfig(); 59 llvm::symbolize::Request Request{ModuleName, ModuleOffset}; 60 auto Printer = 61 std::make_unique<llvm::symbolize::LLVMPrinter>(OS, OS, Config); 62 63 // TODO: it is neccessary to set proper SectionIndex here. 64 // object::SectionedAddress::UndefSection works for only absolute addresses. 65 if (InlineFrames) { 66 auto ResOrErr = getDefaultSymbolizer()->symbolizeInlinedCode( 67 ModuleName, 68 {ModuleOffset, llvm::object::SectionedAddress::UndefSection}); 69 Printer->print(Request, 70 ResOrErr ? ResOrErr.get() : llvm::DIInliningInfo()); 71 } else { 72 auto ResOrErr = getDefaultSymbolizer()->symbolizeCode( 73 ModuleName, 74 {ModuleOffset, llvm::object::SectionedAddress::UndefSection}); 75 Printer->print(Request, ResOrErr ? ResOrErr.get() : llvm::DILineInfo()); 76 } 77 } 78 return __sanitizer::internal_snprintf(Buffer, MaxLength, "%s", 79 Result.c_str()) < MaxLength; 80} 81 82bool __sanitizer_symbolize_data(const char *ModuleName, uint64_t ModuleOffset, 83 char *Buffer, int MaxLength) { 84 std::string Result; 85 { 86 llvm::symbolize::PrinterConfig Config = getDefaultPrinterConfig(); 87 llvm::raw_string_ostream OS(Result); 88 llvm::symbolize::Request Request{ModuleName, ModuleOffset}; 89 auto Printer = 90 std::make_unique<llvm::symbolize::LLVMPrinter>(OS, OS, Config); 91 92 // TODO: it is neccessary to set proper SectionIndex here. 93 // object::SectionedAddress::UndefSection works for only absolute addresses. 94 auto ResOrErr = getDefaultSymbolizer()->symbolizeData( 95 ModuleName, 96 {ModuleOffset, llvm::object::SectionedAddress::UndefSection}); 97 Printer->print(Request, ResOrErr ? ResOrErr.get() : llvm::DIGlobal()); 98 } 99 return __sanitizer::internal_snprintf(Buffer, MaxLength, "%s", 100 Result.c_str()) < MaxLength; 101} 102 103void __sanitizer_symbolize_flush() { 104 if (Symbolizer) 105 Symbolizer->flush(); 106} 107 108int __sanitizer_symbolize_demangle(const char *Name, char *Buffer, 109 int MaxLength) { 110 std::string Result = 111 llvm::symbolize::LLVMSymbolizer::DemangleName(Name, nullptr); 112 return __sanitizer::internal_snprintf(Buffer, MaxLength, "%s", 113 Result.c_str()) < MaxLength 114 ? static_cast<int>(Result.size() + 1) 115 : 0; 116} 117 118bool __sanitizer_symbolize_set_demangle(bool Value) { 119 // Must be called before LLVMSymbolizer created. 120 if (Symbolizer) 121 return false; 122 Demangle = Value; 123 return true; 124} 125 126bool __sanitizer_symbolize_set_inline_frames(bool Value) { 127 InlineFrames = Value; 128 return true; 129} 130 131// Override __cxa_atexit and ignore callbacks. 132// This prevents crashes in a configuration when the symbolizer 133// is built into sanitizer runtime and consequently into the test process. 134// LLVM libraries have some global objects destroyed during exit, 135// so if the test process triggers any bugs after that, the symbolizer crashes. 136// An example stack trace of such crash: 137// 138// #1 __cxa_throw 139// #2 std::__u::__throw_system_error 140// #3 std::__u::recursive_mutex::lock 141// #4 __sanitizer_llvm::ManagedStaticBase::RegisterManagedStatic 142// #5 __sanitizer_llvm::errorToErrorCode 143// #6 __sanitizer_llvm::getFileAux 144// #7 __sanitizer_llvm::MemoryBuffer::getFileOrSTDIN 145// #10 __sanitizer_llvm::symbolize::LLVMSymbolizer::getOrCreateModuleInfo 146// #13 __sanitizer::Symbolizer::SymbolizeData 147// #14 __tsan::SymbolizeData 148// #16 __tsan::ReportRace 149// #18 __tsan_write4 150// #19 race() () at test/tsan/atexit4.cpp 151// #20 cxa_at_exit_wrapper 152// #21 __cxa_finalize 153// #22 __do_fini 154// 155// For the standalone llvm-symbolizer this does not hurt, 156// we just don't destroy few global objects on exit. 157int __cxa_atexit(void (*f)(void *a), void *arg, void *dso) { return 0; } 158 159} // extern "C" 160