linux/tools/perf/util/srcline.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <inttypes.h>
   3#include <stdio.h>
   4#include <stdlib.h>
   5#include <string.h>
   6
   7#include <linux/kernel.h>
   8#include <linux/string.h>
   9#include <linux/zalloc.h>
  10
  11#include "util/dso.h"
  12#include "util/debug.h"
  13#include "util/callchain.h"
  14#include "util/symbol_conf.h"
  15#include "srcline.h"
  16#include "string2.h"
  17#include "symbol.h"
  18
  19bool srcline_full_filename;
  20
  21static const char *dso__name(struct dso *dso)
  22{
  23        const char *dso_name;
  24
  25        if (dso->symsrc_filename)
  26                dso_name = dso->symsrc_filename;
  27        else
  28                dso_name = dso->long_name;
  29
  30        if (dso_name[0] == '[')
  31                return NULL;
  32
  33        if (!strncmp(dso_name, "/tmp/perf-", 10))
  34                return NULL;
  35
  36        return dso_name;
  37}
  38
  39static int inline_list__append(struct symbol *symbol, char *srcline,
  40                               struct inline_node *node)
  41{
  42        struct inline_list *ilist;
  43
  44        ilist = zalloc(sizeof(*ilist));
  45        if (ilist == NULL)
  46                return -1;
  47
  48        ilist->symbol = symbol;
  49        ilist->srcline = srcline;
  50
  51        if (callchain_param.order == ORDER_CALLEE)
  52                list_add_tail(&ilist->list, &node->val);
  53        else
  54                list_add(&ilist->list, &node->val);
  55
  56        return 0;
  57}
  58
  59/* basename version that takes a const input string */
  60static const char *gnu_basename(const char *path)
  61{
  62        const char *base = strrchr(path, '/');
  63
  64        return base ? base + 1 : path;
  65}
  66
  67static char *srcline_from_fileline(const char *file, unsigned int line)
  68{
  69        char *srcline;
  70
  71        if (!file)
  72                return NULL;
  73
  74        if (!srcline_full_filename)
  75                file = gnu_basename(file);
  76
  77        if (asprintf(&srcline, "%s:%u", file, line) < 0)
  78                return NULL;
  79
  80        return srcline;
  81}
  82
  83static struct symbol *new_inline_sym(struct dso *dso,
  84                                     struct symbol *base_sym,
  85                                     const char *funcname)
  86{
  87        struct symbol *inline_sym;
  88        char *demangled = NULL;
  89
  90        if (!funcname)
  91                funcname = "??";
  92
  93        if (dso) {
  94                demangled = dso__demangle_sym(dso, 0, funcname);
  95                if (demangled)
  96                        funcname = demangled;
  97        }
  98
  99        if (base_sym && strcmp(funcname, base_sym->name) == 0) {
 100                /* reuse the real, existing symbol */
 101                inline_sym = base_sym;
 102                /* ensure that we don't alias an inlined symbol, which could
 103                 * lead to double frees in inline_node__delete
 104                 */
 105                assert(!base_sym->inlined);
 106        } else {
 107                /* create a fake symbol for the inline frame */
 108                inline_sym = symbol__new(base_sym ? base_sym->start : 0,
 109                                         base_sym ? (base_sym->end - base_sym->start) : 0,
 110                                         base_sym ? base_sym->binding : 0,
 111                                         base_sym ? base_sym->type : 0,
 112                                         funcname);
 113                if (inline_sym)
 114                        inline_sym->inlined = 1;
 115        }
 116
 117        free(demangled);
 118
 119        return inline_sym;
 120}
 121
 122#ifdef HAVE_LIBBFD_SUPPORT
 123
 124/*
 125 * Implement addr2line using libbfd.
 126 */
 127#define PACKAGE "perf"
 128#include <bfd.h>
 129
 130struct a2l_data {
 131        const char      *input;
 132        u64             addr;
 133
 134        bool            found;
 135        const char      *filename;
 136        const char      *funcname;
 137        unsigned        line;
 138
 139        bfd             *abfd;
 140        asymbol         **syms;
 141};
 142
 143static int bfd_error(const char *string)
 144{
 145        const char *errmsg;
 146
 147        errmsg = bfd_errmsg(bfd_get_error());
 148        fflush(stdout);
 149
 150        if (string)
 151                pr_debug("%s: %s\n", string, errmsg);
 152        else
 153                pr_debug("%s\n", errmsg);
 154
 155        return -1;
 156}
 157
 158static int slurp_symtab(bfd *abfd, struct a2l_data *a2l)
 159{
 160        long storage;
 161        long symcount;
 162        asymbol **syms;
 163        bfd_boolean dynamic = FALSE;
 164
 165        if ((bfd_get_file_flags(abfd) & HAS_SYMS) == 0)
 166                return bfd_error(bfd_get_filename(abfd));
 167
 168        storage = bfd_get_symtab_upper_bound(abfd);
 169        if (storage == 0L) {
 170                storage = bfd_get_dynamic_symtab_upper_bound(abfd);
 171                dynamic = TRUE;
 172        }
 173        if (storage < 0L)
 174                return bfd_error(bfd_get_filename(abfd));
 175
 176        syms = malloc(storage);
 177        if (dynamic)
 178                symcount = bfd_canonicalize_dynamic_symtab(abfd, syms);
 179        else
 180                symcount = bfd_canonicalize_symtab(abfd, syms);
 181
 182        if (symcount < 0) {
 183                free(syms);
 184                return bfd_error(bfd_get_filename(abfd));
 185        }
 186
 187        a2l->syms = syms;
 188        return 0;
 189}
 190
 191static void find_address_in_section(bfd *abfd, asection *section, void *data)
 192{
 193        bfd_vma pc, vma;
 194        bfd_size_type size;
 195        struct a2l_data *a2l = data;
 196
 197        if (a2l->found)
 198                return;
 199
 200        if ((bfd_get_section_flags(abfd, section) & SEC_ALLOC) == 0)
 201                return;
 202
 203        pc = a2l->addr;
 204        vma = bfd_get_section_vma(abfd, section);
 205        size = bfd_get_section_size(section);
 206
 207        if (pc < vma || pc >= vma + size)
 208                return;
 209
 210        a2l->found = bfd_find_nearest_line(abfd, section, a2l->syms, pc - vma,
 211                                           &a2l->filename, &a2l->funcname,
 212                                           &a2l->line);
 213
 214        if (a2l->filename && !strlen(a2l->filename))
 215                a2l->filename = NULL;
 216}
 217
 218static struct a2l_data *addr2line_init(const char *path)
 219{
 220        bfd *abfd;
 221        struct a2l_data *a2l = NULL;
 222
 223        abfd = bfd_openr(path, NULL);
 224        if (abfd == NULL)
 225                return NULL;
 226
 227        if (!bfd_check_format(abfd, bfd_object))
 228                goto out;
 229
 230        a2l = zalloc(sizeof(*a2l));
 231        if (a2l == NULL)
 232                goto out;
 233
 234        a2l->abfd = abfd;
 235        a2l->input = strdup(path);
 236        if (a2l->input == NULL)
 237                goto out;
 238
 239        if (slurp_symtab(abfd, a2l))
 240                goto out;
 241
 242        return a2l;
 243
 244out:
 245        if (a2l) {
 246                zfree((char **)&a2l->input);
 247                free(a2l);
 248        }
 249        bfd_close(abfd);
 250        return NULL;
 251}
 252
 253static void addr2line_cleanup(struct a2l_data *a2l)
 254{
 255        if (a2l->abfd)
 256                bfd_close(a2l->abfd);
 257        zfree((char **)&a2l->input);
 258        zfree(&a2l->syms);
 259        free(a2l);
 260}
 261
 262#define MAX_INLINE_NEST 1024
 263
 264static int inline_list__append_dso_a2l(struct dso *dso,
 265                                       struct inline_node *node,
 266                                       struct symbol *sym)
 267{
 268        struct a2l_data *a2l = dso->a2l;
 269        struct symbol *inline_sym = new_inline_sym(dso, sym, a2l->funcname);
 270        char *srcline = NULL;
 271
 272        if (a2l->filename)
 273                srcline = srcline_from_fileline(a2l->filename, a2l->line);
 274
 275        return inline_list__append(inline_sym, srcline, node);
 276}
 277
 278static int addr2line(const char *dso_name, u64 addr,
 279                     char **file, unsigned int *line, struct dso *dso,
 280                     bool unwind_inlines, struct inline_node *node,
 281                     struct symbol *sym)
 282{
 283        int ret = 0;
 284        struct a2l_data *a2l = dso->a2l;
 285
 286        if (!a2l) {
 287                dso->a2l = addr2line_init(dso_name);
 288                a2l = dso->a2l;
 289        }
 290
 291        if (a2l == NULL) {
 292                if (!symbol_conf.disable_add2line_warn)
 293                        pr_warning("addr2line_init failed for %s\n", dso_name);
 294                return 0;
 295        }
 296
 297        a2l->addr = addr;
 298        a2l->found = false;
 299
 300        bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l);
 301
 302        if (!a2l->found)
 303                return 0;
 304
 305        if (unwind_inlines) {
 306                int cnt = 0;
 307
 308                if (node && inline_list__append_dso_a2l(dso, node, sym))
 309                        return 0;
 310
 311                while (bfd_find_inliner_info(a2l->abfd, &a2l->filename,
 312                                             &a2l->funcname, &a2l->line) &&
 313                       cnt++ < MAX_INLINE_NEST) {
 314
 315                        if (a2l->filename && !strlen(a2l->filename))
 316                                a2l->filename = NULL;
 317
 318                        if (node != NULL) {
 319                                if (inline_list__append_dso_a2l(dso, node, sym))
 320                                        return 0;
 321                                // found at least one inline frame
 322                                ret = 1;
 323                        }
 324                }
 325        }
 326
 327        if (file) {
 328                *file = a2l->filename ? strdup(a2l->filename) : NULL;
 329                ret = *file ? 1 : 0;
 330        }
 331
 332        if (line)
 333                *line = a2l->line;
 334
 335        return ret;
 336}
 337
 338void dso__free_a2l(struct dso *dso)
 339{
 340        struct a2l_data *a2l = dso->a2l;
 341
 342        if (!a2l)
 343                return;
 344
 345        addr2line_cleanup(a2l);
 346
 347        dso->a2l = NULL;
 348}
 349
 350static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
 351                                        struct dso *dso, struct symbol *sym)
 352{
 353        struct inline_node *node;
 354
 355        node = zalloc(sizeof(*node));
 356        if (node == NULL) {
 357                perror("not enough memory for the inline node");
 358                return NULL;
 359        }
 360
 361        INIT_LIST_HEAD(&node->val);
 362        node->addr = addr;
 363
 364        addr2line(dso_name, addr, NULL, NULL, dso, true, node, sym);
 365        return node;
 366}
 367
 368#else /* HAVE_LIBBFD_SUPPORT */
 369
 370static int filename_split(char *filename, unsigned int *line_nr)
 371{
 372        char *sep;
 373
 374        sep = strchr(filename, '\n');
 375        if (sep)
 376                *sep = '\0';
 377
 378        if (!strcmp(filename, "??:0"))
 379                return 0;
 380
 381        sep = strchr(filename, ':');
 382        if (sep) {
 383                *sep++ = '\0';
 384                *line_nr = strtoul(sep, NULL, 0);
 385                return 1;
 386        }
 387
 388        return 0;
 389}
 390
 391static int addr2line(const char *dso_name, u64 addr,
 392                     char **file, unsigned int *line_nr,
 393                     struct dso *dso __maybe_unused,
 394                     bool unwind_inlines __maybe_unused,
 395                     struct inline_node *node __maybe_unused,
 396                     struct symbol *sym __maybe_unused)
 397{
 398        FILE *fp;
 399        char cmd[PATH_MAX];
 400        char *filename = NULL;
 401        size_t len;
 402        int ret = 0;
 403
 404        scnprintf(cmd, sizeof(cmd), "addr2line -e %s %016"PRIx64,
 405                  dso_name, addr);
 406
 407        fp = popen(cmd, "r");
 408        if (fp == NULL) {
 409                pr_warning("popen failed for %s\n", dso_name);
 410                return 0;
 411        }
 412
 413        if (getline(&filename, &len, fp) < 0 || !len) {
 414                pr_warning("addr2line has no output for %s\n", dso_name);
 415                goto out;
 416        }
 417
 418        ret = filename_split(filename, line_nr);
 419        if (ret != 1) {
 420                free(filename);
 421                goto out;
 422        }
 423
 424        *file = filename;
 425
 426out:
 427        pclose(fp);
 428        return ret;
 429}
 430
 431void dso__free_a2l(struct dso *dso __maybe_unused)
 432{
 433}
 434
 435static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
 436                                        struct dso *dso __maybe_unused,
 437                                        struct symbol *sym)
 438{
 439        FILE *fp;
 440        char cmd[PATH_MAX];
 441        struct inline_node *node;
 442        char *filename = NULL;
 443        char *funcname = NULL;
 444        size_t filelen, funclen;
 445        unsigned int line_nr = 0;
 446
 447        scnprintf(cmd, sizeof(cmd), "addr2line -e %s -i -f %016"PRIx64,
 448                  dso_name, addr);
 449
 450        fp = popen(cmd, "r");
 451        if (fp == NULL) {
 452                pr_err("popen failed for %s\n", dso_name);
 453                return NULL;
 454        }
 455
 456        node = zalloc(sizeof(*node));
 457        if (node == NULL) {
 458                perror("not enough memory for the inline node");
 459                goto out;
 460        }
 461
 462        INIT_LIST_HEAD(&node->val);
 463        node->addr = addr;
 464
 465        /* addr2line -f generates two lines for each inlined functions */
 466        while (getline(&funcname, &funclen, fp) != -1) {
 467                char *srcline;
 468                struct symbol *inline_sym;
 469
 470                strim(funcname);
 471
 472                if (getline(&filename, &filelen, fp) == -1)
 473                        goto out;
 474
 475                if (filename_split(filename, &line_nr) != 1)
 476                        goto out;
 477
 478                srcline = srcline_from_fileline(filename, line_nr);
 479                inline_sym = new_inline_sym(dso, sym, funcname);
 480
 481                if (inline_list__append(inline_sym, srcline, node) != 0) {
 482                        free(srcline);
 483                        if (inline_sym && inline_sym->inlined)
 484                                symbol__delete(inline_sym);
 485                        goto out;
 486                }
 487        }
 488
 489out:
 490        pclose(fp);
 491        free(filename);
 492        free(funcname);
 493
 494        return node;
 495}
 496
 497#endif /* HAVE_LIBBFD_SUPPORT */
 498
 499/*
 500 * Number of addr2line failures (without success) before disabling it for that
 501 * dso.
 502 */
 503#define A2L_FAIL_LIMIT 123
 504
 505char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
 506                  bool show_sym, bool show_addr, bool unwind_inlines,
 507                  u64 ip)
 508{
 509        char *file = NULL;
 510        unsigned line = 0;
 511        char *srcline;
 512        const char *dso_name;
 513
 514        if (!dso->has_srcline)
 515                goto out;
 516
 517        dso_name = dso__name(dso);
 518        if (dso_name == NULL)
 519                goto out;
 520
 521        if (!addr2line(dso_name, addr, &file, &line, dso,
 522                       unwind_inlines, NULL, sym))
 523                goto out;
 524
 525        srcline = srcline_from_fileline(file, line);
 526        free(file);
 527
 528        if (!srcline)
 529                goto out;
 530
 531        dso->a2l_fails = 0;
 532
 533        return srcline;
 534
 535out:
 536        if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) {
 537                dso->has_srcline = 0;
 538                dso__free_a2l(dso);
 539        }
 540
 541        if (!show_addr)
 542                return (show_sym && sym) ?
 543                            strndup(sym->name, sym->namelen) : NULL;
 544
 545        if (sym) {
 546                if (asprintf(&srcline, "%s+%" PRIu64, show_sym ? sym->name : "",
 547                                        ip - sym->start) < 0)
 548                        return SRCLINE_UNKNOWN;
 549        } else if (asprintf(&srcline, "%s[%" PRIx64 "]", dso->short_name, addr) < 0)
 550                return SRCLINE_UNKNOWN;
 551        return srcline;
 552}
 553
 554/* Returns filename and fills in line number in line */
 555char *get_srcline_split(struct dso *dso, u64 addr, unsigned *line)
 556{
 557        char *file = NULL;
 558        const char *dso_name;
 559
 560        if (!dso->has_srcline)
 561                goto out;
 562
 563        dso_name = dso__name(dso);
 564        if (dso_name == NULL)
 565                goto out;
 566
 567        if (!addr2line(dso_name, addr, &file, line, dso, true, NULL, NULL))
 568                goto out;
 569
 570        dso->a2l_fails = 0;
 571        return file;
 572
 573out:
 574        if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) {
 575                dso->has_srcline = 0;
 576                dso__free_a2l(dso);
 577        }
 578
 579        return NULL;
 580}
 581
 582void free_srcline(char *srcline)
 583{
 584        if (srcline && strcmp(srcline, SRCLINE_UNKNOWN) != 0)
 585                free(srcline);
 586}
 587
 588char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
 589                  bool show_sym, bool show_addr, u64 ip)
 590{
 591        return __get_srcline(dso, addr, sym, show_sym, show_addr, false, ip);
 592}
 593
 594struct srcline_node {
 595        u64                     addr;
 596        char                    *srcline;
 597        struct rb_node          rb_node;
 598};
 599
 600void srcline__tree_insert(struct rb_root_cached *tree, u64 addr, char *srcline)
 601{
 602        struct rb_node **p = &tree->rb_root.rb_node;
 603        struct rb_node *parent = NULL;
 604        struct srcline_node *i, *node;
 605        bool leftmost = true;
 606
 607        node = zalloc(sizeof(struct srcline_node));
 608        if (!node) {
 609                perror("not enough memory for the srcline node");
 610                return;
 611        }
 612
 613        node->addr = addr;
 614        node->srcline = srcline;
 615
 616        while (*p != NULL) {
 617                parent = *p;
 618                i = rb_entry(parent, struct srcline_node, rb_node);
 619                if (addr < i->addr)
 620                        p = &(*p)->rb_left;
 621                else {
 622                        p = &(*p)->rb_right;
 623                        leftmost = false;
 624                }
 625        }
 626        rb_link_node(&node->rb_node, parent, p);
 627        rb_insert_color_cached(&node->rb_node, tree, leftmost);
 628}
 629
 630char *srcline__tree_find(struct rb_root_cached *tree, u64 addr)
 631{
 632        struct rb_node *n = tree->rb_root.rb_node;
 633
 634        while (n) {
 635                struct srcline_node *i = rb_entry(n, struct srcline_node,
 636                                                  rb_node);
 637
 638                if (addr < i->addr)
 639                        n = n->rb_left;
 640                else if (addr > i->addr)
 641                        n = n->rb_right;
 642                else
 643                        return i->srcline;
 644        }
 645
 646        return NULL;
 647}
 648
 649void srcline__tree_delete(struct rb_root_cached *tree)
 650{
 651        struct srcline_node *pos;
 652        struct rb_node *next = rb_first_cached(tree);
 653
 654        while (next) {
 655                pos = rb_entry(next, struct srcline_node, rb_node);
 656                next = rb_next(&pos->rb_node);
 657                rb_erase_cached(&pos->rb_node, tree);
 658                free_srcline(pos->srcline);
 659                zfree(&pos);
 660        }
 661}
 662
 663struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr,
 664                                            struct symbol *sym)
 665{
 666        const char *dso_name;
 667
 668        dso_name = dso__name(dso);
 669        if (dso_name == NULL)
 670                return NULL;
 671
 672        return addr2inlines(dso_name, addr, dso, sym);
 673}
 674
 675void inline_node__delete(struct inline_node *node)
 676{
 677        struct inline_list *ilist, *tmp;
 678
 679        list_for_each_entry_safe(ilist, tmp, &node->val, list) {
 680                list_del_init(&ilist->list);
 681                free_srcline(ilist->srcline);
 682                /* only the inlined symbols are owned by the list */
 683                if (ilist->symbol && ilist->symbol->inlined)
 684                        symbol__delete(ilist->symbol);
 685                free(ilist);
 686        }
 687
 688        free(node);
 689}
 690
 691void inlines__tree_insert(struct rb_root_cached *tree,
 692                          struct inline_node *inlines)
 693{
 694        struct rb_node **p = &tree->rb_root.rb_node;
 695        struct rb_node *parent = NULL;
 696        const u64 addr = inlines->addr;
 697        struct inline_node *i;
 698        bool leftmost = true;
 699
 700        while (*p != NULL) {
 701                parent = *p;
 702                i = rb_entry(parent, struct inline_node, rb_node);
 703                if (addr < i->addr)
 704                        p = &(*p)->rb_left;
 705                else {
 706                        p = &(*p)->rb_right;
 707                        leftmost = false;
 708                }
 709        }
 710        rb_link_node(&inlines->rb_node, parent, p);
 711        rb_insert_color_cached(&inlines->rb_node, tree, leftmost);
 712}
 713
 714struct inline_node *inlines__tree_find(struct rb_root_cached *tree, u64 addr)
 715{
 716        struct rb_node *n = tree->rb_root.rb_node;
 717
 718        while (n) {
 719                struct inline_node *i = rb_entry(n, struct inline_node,
 720                                                 rb_node);
 721
 722                if (addr < i->addr)
 723                        n = n->rb_left;
 724                else if (addr > i->addr)
 725                        n = n->rb_right;
 726                else
 727                        return i;
 728        }
 729
 730        return NULL;
 731}
 732
 733void inlines__tree_delete(struct rb_root_cached *tree)
 734{
 735        struct inline_node *pos;
 736        struct rb_node *next = rb_first_cached(tree);
 737
 738        while (next) {
 739                pos = rb_entry(next, struct inline_node, rb_node);
 740                next = rb_next(&pos->rb_node);
 741                rb_erase_cached(&pos->rb_node, tree);
 742                inline_node__delete(pos);
 743        }
 744}
 745