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