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 namespace __sanitizer { 45 int internal_snprintf(char *buffer, uintptr_t length, const char *format, 46 ...); 47 } // namespace __sanitizer 48 49 extern "C" { 50 51 typedef uint64_t u64; 52 53 bool __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 82 bool __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 103 void __sanitizer_symbolize_flush() { 104 if (Symbolizer) 105 Symbolizer->flush(); 106 } 107 108 int __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 118 bool __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 126 bool __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. 157 int __cxa_atexit(void (*f)(void *a), void *arg, void *dso) { return 0; } 158 159 } // extern "C" 160