1 // SPDX-License-Identifier: GPL-2.0 1 2 3 /* 4 * Must come before the linux/compiler.h inclu 5 * macros (e.g. noinline) that conflict with c 6 * by LLVM. 7 */ 8 #pragma GCC diagnostic push 9 #pragma GCC diagnostic ignored "-Wunused-param 10 #include <llvm/DebugInfo/Symbolize/Symbolize.h 11 #include <llvm/Support/TargetSelect.h> 12 #pragma GCC diagnostic pop 13 14 #include <inttypes.h> 15 #include <stdio.h> 16 #include <sys/types.h> 17 #include <linux/compiler.h> 18 extern "C" { 19 #include <linux/zalloc.h> 20 } 21 #include "symbol_conf.h" 22 #include "llvm-c-helpers.h" 23 24 extern "C" 25 char *dso__demangle_sym(struct dso *dso, int k 26 27 using namespace llvm; 28 using llvm::symbolize::LLVMSymbolizer; 29 30 /* 31 * Allocate a static LLVMSymbolizer, which wil 32 * Unlike the bfd paths, LLVMSymbolizer has it 33 * to store anything in the dso struct. 34 */ 35 static LLVMSymbolizer *get_symbolizer() 36 { 37 static LLVMSymbolizer *instance = null 38 if (instance == nullptr) { 39 LLVMSymbolizer::Options opts; 40 /* 41 * LLVM sometimes demangles sl 42 * of the code, and this misma 43 * to get confused and mark no 44 * (since the name does not pr 45 * Thus, disable the demanglin 46 * handle it. 47 */ 48 opts.Demangle = false; 49 instance = new LLVMSymbolizer( 50 } 51 return instance; 52 } 53 54 /* Returns 0 on error, 1 on success. */ 55 static int extract_file_and_line(const DILineI 56 unsigned int 57 { 58 if (file) { 59 if (line_info.FileName == "<in 60 /* Match the conventio 61 *file = nullptr; 62 } else { 63 /* The caller expects 64 *file = strdup(line_in 65 if (*file == nullptr) 66 return 0; 67 } 68 } 69 if (line) 70 *line = line_info.Line; 71 return 1; 72 } 73 74 extern "C" 75 int llvm_addr2line(const char *dso_name, u64 a 76 char **file, unsigned int * 77 bool unwind_inlines, 78 llvm_a2l_frame **inline_fra 79 { 80 LLVMSymbolizer *symbolizer = get_symbo 81 object::SectionedAddress sectioned_add 82 addr, 83 object::SectionedAddress::Unde 84 }; 85 86 if (unwind_inlines) { 87 Expected<DIInliningInfo> res_o 88 symbolizer->symbolizeI 89 90 if (!res_or_err) 91 return 0; 92 unsigned num_frames = res_or_e 93 if (num_frames == 0) 94 return 0; 95 96 if (extract_file_and_line(res_ 97 file 98 return 0; 99 100 *inline_frames = (llvm_a2l_fra 101 num_frames, sizeof(**i 102 if (*inline_frames == nullptr) 103 return 0; 104 105 for (unsigned i = 0; i < num_f 106 const DILineInfo &src 107 108 llvm_a2l_frame &dst = 109 if (src.FileName == "< 110 /* Match the c 111 dst.filename = 112 else 113 dst.filename = 114 dst.funcname = strdup( 115 dst.line = src.Line; 116 117 if (dst.filename == nu 118 dst.funcname == nu 119 for (unsigned 120 zfree( 121 zfree( 122 } 123 zfree(inline_f 124 return 0; 125 } 126 } 127 128 return num_frames; 129 } else { 130 if (inline_frames) 131 *inline_frames = nullp 132 133 Expected<DILineInfo> res_or_er 134 symbolizer->symbolizeC 135 if (!res_or_err) 136 return 0; 137 return extract_file_and_line(* 138 } 139 } 140 141 static char * 142 make_symbol_relative_string(struct dso *dso, c 143 u64 addr, u64 base 144 { 145 if (!strcmp(sym_name, "<invalid>")) 146 return NULL; 147 148 char *demangled = dso__demangle_sym(ds 149 if (base_addr && base_addr != addr) { 150 char buf[256]; 151 snprintf(buf, sizeof(buf), "%s 152 demangled ? demangled 153 free(demangled); 154 return strdup(buf); 155 } else { 156 if (demangled) 157 return demangled; 158 else 159 return strdup(sym_name 160 } 161 } 162 163 extern "C" 164 char *llvm_name_for_code(struct dso *dso, cons 165 { 166 LLVMSymbolizer *symbolizer = get_symbo 167 object::SectionedAddress sectioned_add 168 addr, 169 object::SectionedAddress::Unde 170 }; 171 Expected<DILineInfo> res_or_err = 172 symbolizer->symbolizeCode(dso_ 173 if (!res_or_err) { 174 return NULL; 175 } 176 return make_symbol_relative_string( 177 dso, res_or_err->FunctionName. 178 addr, res_or_err->StartAddress 179 } 180 181 extern "C" 182 char *llvm_name_for_data(struct dso *dso, cons 183 { 184 LLVMSymbolizer *symbolizer = get_symbo 185 object::SectionedAddress sectioned_add 186 addr, 187 object::SectionedAddress::Unde 188 }; 189 Expected<DIGlobal> res_or_err = 190 symbolizer->symbolizeData(dso_ 191 if (!res_or_err) { 192 return NULL; 193 } 194 return make_symbol_relative_string( 195 dso, res_or_err->Name.c_str(), 196 addr, res_or_err->Start); 197 } 198
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.