at v6.19 407 lines 8.8 kB view raw
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 13bool srcline_full_filename; 14 15char *srcline__unknown = (char *)"??:0"; 16 17static 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 35int 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 */ 55static const char *gnu_basename(const char *path) 56{ 57 const char *base = strrchr(path, '/'); 58 59 return base ? base + 1 : path; 60} 61 62char *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 78struct 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 117static 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 134static 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 160char *__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 190out_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 } 196out: 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 */ 211char *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 230out_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 240void 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 251char *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 257struct srcline_node { 258 u64 addr; 259 char *srcline; 260 struct rb_node rb_node; 261}; 262 263void 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 293char *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 312void 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 326struct 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 338void 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 354void 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 377struct 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 396void 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}