linux/tools/perf/util/srcline.c
<<
>>
Prefs
   1#include <inttypes.h>
   2#include <stdio.h>
   3#include <stdlib.h>
   4#include <string.h>
   5
   6#include <linux/kernel.h>
   7
   8#include "util/dso.h"
   9#include "util/util.h"
  10#include "util/debug.h"
  11#include "util/callchain.h"
  12#include "srcline.h"
  13
  14#include "symbol.h"
  15
  16bool srcline_full_filename;
  17
  18static const char *dso__name(struct dso *dso)
  19{
  20        const char *dso_name;
  21
  22        if (dso->symsrc_filename)
  23                dso_name = dso->symsrc_filename;
  24        else
  25                dso_name = dso->long_name;
  26
  27        if (dso_name[0] == '[')
  28                return NULL;
  29
  30        if (!strncmp(dso_name, "/tmp/perf-", 10))
  31                return NULL;
  32
  33        return dso_name;
  34}
  35
  36static int inline_list__append(char *filename, char *funcname, int line_nr,
  37                               struct inline_node *node, struct dso *dso)
  38{
  39        struct inline_list *ilist;
  40        char *demangled;
  41
  42        ilist = zalloc(sizeof(*ilist));
  43        if (ilist == NULL)
  44                return -1;
  45
  46        ilist->filename = filename;
  47        ilist->line_nr = line_nr;
  48
  49        if (dso != NULL) {
  50                demangled = dso__demangle_sym(dso, 0, funcname);
  51                if (demangled == NULL) {
  52                        ilist->funcname = funcname;
  53                } else {
  54                        ilist->funcname = demangled;
  55                        free(funcname);
  56                }
  57        }
  58
  59        if (callchain_param.order == ORDER_CALLEE)
  60                list_add_tail(&ilist->list, &node->val);
  61        else
  62                list_add(&ilist->list, &node->val);
  63
  64        return 0;
  65}
  66
  67#ifdef HAVE_LIBBFD_SUPPORT
  68
  69/*
  70 * Implement addr2line using libbfd.
  71 */
  72#define PACKAGE "perf"
  73#include <bfd.h>
  74
  75struct a2l_data {
  76        const char      *input;
  77        u64             addr;
  78
  79        bool            found;
  80        const char      *filename;
  81        const char      *funcname;
  82        unsigned        line;
  83
  84        bfd             *abfd;
  85        asymbol         **syms;
  86};
  87
  88static int bfd_error(const char *string)
  89{
  90        const char *errmsg;
  91
  92        errmsg = bfd_errmsg(bfd_get_error());
  93        fflush(stdout);
  94
  95        if (string)
  96                pr_debug("%s: %s\n", string, errmsg);
  97        else
  98                pr_debug("%s\n", errmsg);
  99
 100        return -1;
 101}
 102
 103static int slurp_symtab(bfd *abfd, struct a2l_data *a2l)
 104{
 105        long storage;
 106        long symcount;
 107        asymbol **syms;
 108        bfd_boolean dynamic = FALSE;
 109
 110        if ((bfd_get_file_flags(abfd) & HAS_SYMS) == 0)
 111                return bfd_error(bfd_get_filename(abfd));
 112
 113        storage = bfd_get_symtab_upper_bound(abfd);
 114        if (storage == 0L) {
 115                storage = bfd_get_dynamic_symtab_upper_bound(abfd);
 116                dynamic = TRUE;
 117        }
 118        if (storage < 0L)
 119                return bfd_error(bfd_get_filename(abfd));
 120
 121        syms = malloc(storage);
 122        if (dynamic)
 123                symcount = bfd_canonicalize_dynamic_symtab(abfd, syms);
 124        else
 125                symcount = bfd_canonicalize_symtab(abfd, syms);
 126
 127        if (symcount < 0) {
 128                free(syms);
 129                return bfd_error(bfd_get_filename(abfd));
 130        }
 131
 132        a2l->syms = syms;
 133        return 0;
 134}
 135
 136static void find_address_in_section(bfd *abfd, asection *section, void *data)
 137{
 138        bfd_vma pc, vma;
 139        bfd_size_type size;
 140        struct a2l_data *a2l = data;
 141
 142        if (a2l->found)
 143                return;
 144
 145        if ((bfd_get_section_flags(abfd, section) & SEC_ALLOC) == 0)
 146                return;
 147
 148        pc = a2l->addr;
 149        vma = bfd_get_section_vma(abfd, section);
 150        size = bfd_get_section_size(section);
 151
 152        if (pc < vma || pc >= vma + size)
 153                return;
 154
 155        a2l->found = bfd_find_nearest_line(abfd, section, a2l->syms, pc - vma,
 156                                           &a2l->filename, &a2l->funcname,
 157                                           &a2l->line);
 158}
 159
 160static struct a2l_data *addr2line_init(const char *path)
 161{
 162        bfd *abfd;
 163        struct a2l_data *a2l = NULL;
 164
 165        abfd = bfd_openr(path, NULL);
 166        if (abfd == NULL)
 167                return NULL;
 168
 169        if (!bfd_check_format(abfd, bfd_object))
 170                goto out;
 171
 172        a2l = zalloc(sizeof(*a2l));
 173        if (a2l == NULL)
 174                goto out;
 175
 176        a2l->abfd = abfd;
 177        a2l->input = strdup(path);
 178        if (a2l->input == NULL)
 179                goto out;
 180
 181        if (slurp_symtab(abfd, a2l))
 182                goto out;
 183
 184        return a2l;
 185
 186out:
 187        if (a2l) {
 188                zfree((char **)&a2l->input);
 189                free(a2l);
 190        }
 191        bfd_close(abfd);
 192        return NULL;
 193}
 194
 195static void addr2line_cleanup(struct a2l_data *a2l)
 196{
 197        if (a2l->abfd)
 198                bfd_close(a2l->abfd);
 199        zfree((char **)&a2l->input);
 200        zfree(&a2l->syms);
 201        free(a2l);
 202}
 203
 204#define MAX_INLINE_NEST 1024
 205
 206static int inline_list__append_dso_a2l(struct dso *dso,
 207                                       struct inline_node *node)
 208{
 209        struct a2l_data *a2l = dso->a2l;
 210        char *funcname = a2l->funcname ? strdup(a2l->funcname) : NULL;
 211        char *filename = a2l->filename ? strdup(a2l->filename) : NULL;
 212
 213        return inline_list__append(filename, funcname, a2l->line, node, dso);
 214}
 215
 216static int addr2line(const char *dso_name, u64 addr,
 217                     char **file, unsigned int *line, struct dso *dso,
 218                     bool unwind_inlines, struct inline_node *node)
 219{
 220        int ret = 0;
 221        struct a2l_data *a2l = dso->a2l;
 222
 223        if (!a2l) {
 224                dso->a2l = addr2line_init(dso_name);
 225                a2l = dso->a2l;
 226        }
 227
 228        if (a2l == NULL) {
 229                pr_warning("addr2line_init failed for %s\n", dso_name);
 230                return 0;
 231        }
 232
 233        a2l->addr = addr;
 234        a2l->found = false;
 235
 236        bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l);
 237
 238        if (!a2l->found)
 239                return 0;
 240
 241        if (unwind_inlines) {
 242                int cnt = 0;
 243
 244                if (node && inline_list__append_dso_a2l(dso, node))
 245                        return 0;
 246
 247                while (bfd_find_inliner_info(a2l->abfd, &a2l->filename,
 248                                             &a2l->funcname, &a2l->line) &&
 249                       cnt++ < MAX_INLINE_NEST) {
 250
 251                        if (node != NULL) {
 252                                if (inline_list__append_dso_a2l(dso, node))
 253                                        return 0;
 254                                // found at least one inline frame
 255                                ret = 1;
 256                        }
 257                }
 258        }
 259
 260        if (file) {
 261                *file = a2l->filename ? strdup(a2l->filename) : NULL;
 262                ret = *file ? 1 : 0;
 263        }
 264
 265        if (line)
 266                *line = a2l->line;
 267
 268        return ret;
 269}
 270
 271void dso__free_a2l(struct dso *dso)
 272{
 273        struct a2l_data *a2l = dso->a2l;
 274
 275        if (!a2l)
 276                return;
 277
 278        addr2line_cleanup(a2l);
 279
 280        dso->a2l = NULL;
 281}
 282
 283static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
 284        struct dso *dso)
 285{
 286        struct inline_node *node;
 287
 288        node = zalloc(sizeof(*node));
 289        if (node == NULL) {
 290                perror("not enough memory for the inline node");
 291                return NULL;
 292        }
 293
 294        INIT_LIST_HEAD(&node->val);
 295        node->addr = addr;
 296
 297        if (!addr2line(dso_name, addr, NULL, NULL, dso, TRUE, node))
 298                goto out_free_inline_node;
 299
 300        if (list_empty(&node->val))
 301                goto out_free_inline_node;
 302
 303        return node;
 304
 305out_free_inline_node:
 306        inline_node__delete(node);
 307        return NULL;
 308}
 309
 310#else /* HAVE_LIBBFD_SUPPORT */
 311
 312static int filename_split(char *filename, unsigned int *line_nr)
 313{
 314        char *sep;
 315
 316        sep = strchr(filename, '\n');
 317        if (sep)
 318                *sep = '\0';
 319
 320        if (!strcmp(filename, "??:0"))
 321                return 0;
 322
 323        sep = strchr(filename, ':');
 324        if (sep) {
 325                *sep++ = '\0';
 326                *line_nr = strtoul(sep, NULL, 0);
 327                return 1;
 328        }
 329
 330        return 0;
 331}
 332
 333static int addr2line(const char *dso_name, u64 addr,
 334                     char **file, unsigned int *line_nr,
 335                     struct dso *dso __maybe_unused,
 336                     bool unwind_inlines __maybe_unused,
 337                     struct inline_node *node __maybe_unused)
 338{
 339        FILE *fp;
 340        char cmd[PATH_MAX];
 341        char *filename = NULL;
 342        size_t len;
 343        int ret = 0;
 344
 345        scnprintf(cmd, sizeof(cmd), "addr2line -e %s %016"PRIx64,
 346                  dso_name, addr);
 347
 348        fp = popen(cmd, "r");
 349        if (fp == NULL) {
 350                pr_warning("popen failed for %s\n", dso_name);
 351                return 0;
 352        }
 353
 354        if (getline(&filename, &len, fp) < 0 || !len) {
 355                pr_warning("addr2line has no output for %s\n", dso_name);
 356                goto out;
 357        }
 358
 359        ret = filename_split(filename, line_nr);
 360        if (ret != 1) {
 361                free(filename);
 362                goto out;
 363        }
 364
 365        *file = filename;
 366
 367out:
 368        pclose(fp);
 369        return ret;
 370}
 371
 372void dso__free_a2l(struct dso *dso __maybe_unused)
 373{
 374}
 375
 376static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
 377        struct dso *dso __maybe_unused)
 378{
 379        FILE *fp;
 380        char cmd[PATH_MAX];
 381        struct inline_node *node;
 382        char *filename = NULL;
 383        size_t len;
 384        unsigned int line_nr = 0;
 385
 386        scnprintf(cmd, sizeof(cmd), "addr2line -e %s -i %016"PRIx64,
 387                  dso_name, addr);
 388
 389        fp = popen(cmd, "r");
 390        if (fp == NULL) {
 391                pr_err("popen failed for %s\n", dso_name);
 392                return NULL;
 393        }
 394
 395        node = zalloc(sizeof(*node));
 396        if (node == NULL) {
 397                perror("not enough memory for the inline node");
 398                goto out;
 399        }
 400
 401        INIT_LIST_HEAD(&node->val);
 402        node->addr = addr;
 403
 404        while (getline(&filename, &len, fp) != -1) {
 405                if (filename_split(filename, &line_nr) != 1) {
 406                        free(filename);
 407                        goto out;
 408                }
 409
 410                if (inline_list__append(filename, NULL, line_nr, node,
 411                                        NULL) != 0)
 412                        goto out;
 413
 414                filename = NULL;
 415        }
 416
 417out:
 418        pclose(fp);
 419
 420        if (list_empty(&node->val)) {
 421                inline_node__delete(node);
 422                return NULL;
 423        }
 424
 425        return node;
 426}
 427
 428#endif /* HAVE_LIBBFD_SUPPORT */
 429
 430/*
 431 * Number of addr2line failures (without success) before disabling it for that
 432 * dso.
 433 */
 434#define A2L_FAIL_LIMIT 123
 435
 436char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
 437                  bool show_sym, bool show_addr, bool unwind_inlines)
 438{
 439        char *file = NULL;
 440        unsigned line = 0;
 441        char *srcline;
 442        const char *dso_name;
 443
 444        if (!dso->has_srcline)
 445                goto out;
 446
 447        dso_name = dso__name(dso);
 448        if (dso_name == NULL)
 449                goto out;
 450
 451        if (!addr2line(dso_name, addr, &file, &line, dso, unwind_inlines, NULL))
 452                goto out;
 453
 454        if (asprintf(&srcline, "%s:%u",
 455                                srcline_full_filename ? file : basename(file),
 456                                line) < 0) {
 457                free(file);
 458                goto out;
 459        }
 460
 461        dso->a2l_fails = 0;
 462
 463        free(file);
 464        return srcline;
 465
 466out:
 467        if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) {
 468                dso->has_srcline = 0;
 469                dso__free_a2l(dso);
 470        }
 471
 472        if (!show_addr)
 473                return (show_sym && sym) ?
 474                            strndup(sym->name, sym->namelen) : NULL;
 475
 476        if (sym) {
 477                if (asprintf(&srcline, "%s+%" PRIu64, show_sym ? sym->name : "",
 478                                        addr - sym->start) < 0)
 479                        return SRCLINE_UNKNOWN;
 480        } else if (asprintf(&srcline, "%s[%" PRIx64 "]", dso->short_name, addr) < 0)
 481                return SRCLINE_UNKNOWN;
 482        return srcline;
 483}
 484
 485void free_srcline(char *srcline)
 486{
 487        if (srcline && strcmp(srcline, SRCLINE_UNKNOWN) != 0)
 488                free(srcline);
 489}
 490
 491char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
 492                  bool show_sym, bool show_addr)
 493{
 494        return __get_srcline(dso, addr, sym, show_sym, show_addr, false);
 495}
 496
 497struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr)
 498{
 499        const char *dso_name;
 500
 501        dso_name = dso__name(dso);
 502        if (dso_name == NULL)
 503                return NULL;
 504
 505        return addr2inlines(dso_name, addr, dso);
 506}
 507
 508void inline_node__delete(struct inline_node *node)
 509{
 510        struct inline_list *ilist, *tmp;
 511
 512        list_for_each_entry_safe(ilist, tmp, &node->val, list) {
 513                list_del_init(&ilist->list);
 514                zfree(&ilist->filename);
 515                zfree(&ilist->funcname);
 516                free(ilist);
 517        }
 518
 519        free(node);
 520}
 521