1 // SPDX-License-Identifier: GPL-2.0 2 #include "srcline.h" 3 #include "addr2line.h" 4 #include "dso.h" 5 #include "callchain.h" 6 #include "libbfd.h" 7 #include "llvm.h" 8 #include "symbol.h" 9 10 #include <inttypes.h> 11 #include <string.h> 12 13 bool srcline_full_filename; 14 15 char *srcline__unknown = (char *)"??:0"; 16 17 static const char *srcline_dso_name(struct dso *dso) 18 { 19 const char *dso_name; 20 21 if (dso__symsrc_filename(dso)) 22 dso_name = dso__symsrc_filename(dso); 23 else 24 dso_name = dso__long_name(dso); 25 26 if (dso_name[0] == '[') 27 return NULL; 28 29 if (is_perf_pid_map_name(dso_name)) 30 return NULL; 31 32 return dso_name; 33 } 34 35 int inline_list__append(struct symbol *symbol, char *srcline, struct inline_node *node) 36 { 37 struct inline_list *ilist; 38 39 ilist = zalloc(sizeof(*ilist)); 40 if (ilist == NULL) 41 return -1; 42 43 ilist->symbol = symbol; 44 ilist->srcline = srcline; 45 46 if (callchain_param.order == ORDER_CALLEE) 47 list_add_tail(&ilist->list, &node->val); 48 else 49 list_add(&ilist->list, &node->val); 50 51 return 0; 52 } 53 54 /* basename version that takes a const input string */ 55 static const char *gnu_basename(const char *path) 56 { 57 const char *base = strrchr(path, '/'); 58 59 return base ? base + 1 : path; 60 } 61 62 char *srcline_from_fileline(const char *file, unsigned int line) 63 { 64 char *srcline; 65 66 if (!file) 67 return NULL; 68 69 if (!srcline_full_filename) 70 file = gnu_basename(file); 71 72 if (asprintf(&srcline, "%s:%u", file, line) < 0) 73 return NULL; 74 75 return srcline; 76 } 77 78 struct symbol *new_inline_sym(struct dso *dso, 79 struct symbol *base_sym, 80 const char *funcname) 81 { 82 struct symbol *inline_sym; 83 char *demangled = NULL; 84 85 if (!funcname) 86 funcname = "??"; 87 88 if (dso) { 89 demangled = dso__demangle_sym(dso, 0, funcname); 90 if (demangled) 91 funcname = demangled; 92 } 93 94 if (base_sym && strcmp(funcname, base_sym->name) == 0) { 95 /* reuse the real, existing symbol */ 96 inline_sym = base_sym; 97 /* ensure that we don't alias an inlined symbol, which could 98 * lead to double frees in inline_node__delete 99 */ 100 assert(!base_sym->inlined); 101 } else { 102 /* create a fake symbol for the inline frame */ 103 inline_sym = symbol__new(base_sym ? base_sym->start : 0, 104 base_sym ? (base_sym->end - base_sym->start) : 0, 105 base_sym ? base_sym->binding : 0, 106 base_sym ? base_sym->type : 0, 107 funcname); 108 if (inline_sym) 109 inline_sym->inlined = 1; 110 } 111 112 free(demangled); 113 114 return inline_sym; 115 } 116 117 static int addr2line(const char *dso_name, u64 addr, char **file, unsigned int *line_nr, 118 struct dso *dso, bool unwind_inlines, struct inline_node *node, 119 struct symbol *sym) 120 { 121 int ret; 122 123 ret = llvm__addr2line(dso_name, addr, file, line_nr, dso, unwind_inlines, node, sym); 124 if (ret > 0) 125 return ret; 126 127 ret = libbfd__addr2line(dso_name, addr, file, line_nr, dso, unwind_inlines, node, sym); 128 if (ret > 0) 129 return ret; 130 131 return cmd__addr2line(dso_name, addr, file, line_nr, dso, unwind_inlines, node, sym); 132 } 133 134 static struct inline_node *addr2inlines(const char *dso_name, u64 addr, 135 struct dso *dso, struct symbol *sym) 136 { 137 struct inline_node *node; 138 139 node = zalloc(sizeof(*node)); 140 if (node == NULL) { 141 perror("not enough memory for the inline node"); 142 return NULL; 143 } 144 145 INIT_LIST_HEAD(&node->val); 146 node->addr = addr; 147 148 addr2line(dso_name, addr, /*file=*/NULL, /*line_nr=*/NULL, dso, 149 /*unwind_inlines=*/true, node, sym); 150 151 return node; 152 } 153 154 /* 155 * Number of addr2line failures (without success) before disabling it for that 156 * dso. 157 */ 158 #define A2L_FAIL_LIMIT 123 159 160 char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym, 161 bool show_sym, bool show_addr, bool unwind_inlines, 162 u64 ip) 163 { 164 char *file = NULL; 165 unsigned line = 0; 166 char *srcline; 167 const char *dso_name; 168 169 if (!dso__has_srcline(dso)) 170 goto out; 171 172 dso_name = srcline_dso_name(dso); 173 if (dso_name == NULL) 174 goto out_err; 175 176 if (!addr2line(dso_name, addr, &file, &line, dso, 177 unwind_inlines, /*node=*/NULL, sym)) 178 goto out_err; 179 180 srcline = srcline_from_fileline(file, line); 181 free(file); 182 183 if (!srcline) 184 goto out_err; 185 186 dso__set_a2l_fails(dso, 0); 187 188 return srcline; 189 190 out_err: 191 dso__set_a2l_fails(dso, dso__a2l_fails(dso) + 1); 192 if (dso__a2l_fails(dso) > A2L_FAIL_LIMIT) { 193 dso__set_has_srcline(dso, false); 194 dso__free_a2l(dso); 195 } 196 out: 197 if (!show_addr) 198 return (show_sym && sym) ? 199 strndup(sym->name, sym->namelen) : SRCLINE_UNKNOWN; 200 201 if (sym) { 202 if (asprintf(&srcline, "%s+%" PRIu64, show_sym ? sym->name : "", 203 ip - sym->start) < 0) 204 return SRCLINE_UNKNOWN; 205 } else if (asprintf(&srcline, "%s[%" PRIx64 "]", dso__short_name(dso), addr) < 0) 206 return SRCLINE_UNKNOWN; 207 return srcline; 208 } 209 210 /* Returns filename and fills in line number in line */ 211 char *get_srcline_split(struct dso *dso, u64 addr, unsigned *line) 212 { 213 char *file = NULL; 214 const char *dso_name; 215 216 if (!dso__has_srcline(dso)) 217 return NULL; 218 219 dso_name = srcline_dso_name(dso); 220 if (dso_name == NULL) 221 goto out_err; 222 223 if (!addr2line(dso_name, addr, &file, line, dso, /*unwind_inlines=*/true, 224 /*node=*/NULL, /*sym=*/NULL)) 225 goto out_err; 226 227 dso__set_a2l_fails(dso, 0); 228 return file; 229 230 out_err: 231 dso__set_a2l_fails(dso, dso__a2l_fails(dso) + 1); 232 if (dso__a2l_fails(dso) > A2L_FAIL_LIMIT) { 233 dso__set_has_srcline(dso, false); 234 dso__free_a2l(dso); 235 } 236 237 return NULL; 238 } 239 240 void zfree_srcline(char **srcline) 241 { 242 if (*srcline == NULL) 243 return; 244 245 if (*srcline != SRCLINE_UNKNOWN) 246 free(*srcline); 247 248 *srcline = NULL; 249 } 250 251 char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym, 252 bool show_sym, bool show_addr, u64 ip) 253 { 254 return __get_srcline(dso, addr, sym, show_sym, show_addr, false, ip); 255 } 256 257 struct srcline_node { 258 u64 addr; 259 char *srcline; 260 struct rb_node rb_node; 261 }; 262 263 void srcline__tree_insert(struct rb_root_cached *tree, u64 addr, char *srcline) 264 { 265 struct rb_node **p = &tree->rb_root.rb_node; 266 struct rb_node *parent = NULL; 267 struct srcline_node *i, *node; 268 bool leftmost = true; 269 270 node = zalloc(sizeof(struct srcline_node)); 271 if (!node) { 272 perror("not enough memory for the srcline node"); 273 return; 274 } 275 276 node->addr = addr; 277 node->srcline = srcline; 278 279 while (*p != NULL) { 280 parent = *p; 281 i = rb_entry(parent, struct srcline_node, rb_node); 282 if (addr < i->addr) 283 p = &(*p)->rb_left; 284 else { 285 p = &(*p)->rb_right; 286 leftmost = false; 287 } 288 } 289 rb_link_node(&node->rb_node, parent, p); 290 rb_insert_color_cached(&node->rb_node, tree, leftmost); 291 } 292 293 char *srcline__tree_find(struct rb_root_cached *tree, u64 addr) 294 { 295 struct rb_node *n = tree->rb_root.rb_node; 296 297 while (n) { 298 struct srcline_node *i = rb_entry(n, struct srcline_node, 299 rb_node); 300 301 if (addr < i->addr) 302 n = n->rb_left; 303 else if (addr > i->addr) 304 n = n->rb_right; 305 else 306 return i->srcline; 307 } 308 309 return NULL; 310 } 311 312 void srcline__tree_delete(struct rb_root_cached *tree) 313 { 314 struct srcline_node *pos; 315 struct rb_node *next = rb_first_cached(tree); 316 317 while (next) { 318 pos = rb_entry(next, struct srcline_node, rb_node); 319 next = rb_next(&pos->rb_node); 320 rb_erase_cached(&pos->rb_node, tree); 321 zfree_srcline(&pos->srcline); 322 zfree(&pos); 323 } 324 } 325 326 struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr, 327 struct symbol *sym) 328 { 329 const char *dso_name; 330 331 dso_name = srcline_dso_name(dso); 332 if (dso_name == NULL) 333 return NULL; 334 335 return addr2inlines(dso_name, addr, dso, sym); 336 } 337 338 void inline_node__delete(struct inline_node *node) 339 { 340 struct inline_list *ilist, *tmp; 341 342 list_for_each_entry_safe(ilist, tmp, &node->val, list) { 343 list_del_init(&ilist->list); 344 zfree_srcline(&ilist->srcline); 345 /* only the inlined symbols are owned by the list */ 346 if (ilist->symbol && ilist->symbol->inlined) 347 symbol__delete(ilist->symbol); 348 free(ilist); 349 } 350 351 free(node); 352 } 353 354 void inlines__tree_insert(struct rb_root_cached *tree, 355 struct inline_node *inlines) 356 { 357 struct rb_node **p = &tree->rb_root.rb_node; 358 struct rb_node *parent = NULL; 359 const u64 addr = inlines->addr; 360 struct inline_node *i; 361 bool leftmost = true; 362 363 while (*p != NULL) { 364 parent = *p; 365 i = rb_entry(parent, struct inline_node, rb_node); 366 if (addr < i->addr) 367 p = &(*p)->rb_left; 368 else { 369 p = &(*p)->rb_right; 370 leftmost = false; 371 } 372 } 373 rb_link_node(&inlines->rb_node, parent, p); 374 rb_insert_color_cached(&inlines->rb_node, tree, leftmost); 375 } 376 377 struct inline_node *inlines__tree_find(struct rb_root_cached *tree, u64 addr) 378 { 379 struct rb_node *n = tree->rb_root.rb_node; 380 381 while (n) { 382 struct inline_node *i = rb_entry(n, struct inline_node, 383 rb_node); 384 385 if (addr < i->addr) 386 n = n->rb_left; 387 else if (addr > i->addr) 388 n = n->rb_right; 389 else 390 return i; 391 } 392 393 return NULL; 394 } 395 396 void inlines__tree_delete(struct rb_root_cached *tree) 397 { 398 struct inline_node *pos; 399 struct rb_node *next = rb_first_cached(tree); 400 401 while (next) { 402 pos = rb_entry(next, struct inline_node, rb_node); 403 next = rb_next(&pos->rb_node); 404 rb_erase_cached(&pos->rb_node, tree); 405 inline_node__delete(pos); 406 } 407 } 408