linux/tools/perf/util/srcline.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <inttypes.h>
   3#include <signal.h>
   4#include <stdio.h>
   5#include <stdlib.h>
   6#include <string.h>
   7#include <sys/types.h>
   8
   9#include <linux/kernel.h>
  10#include <linux/string.h>
  11#include <linux/zalloc.h>
  12
  13#include "util/dso.h"
  14#include "util/debug.h"
  15#include "util/callchain.h"
  16#include "util/symbol_conf.h"
  17#include "srcline.h"
  18#include "string2.h"
  19#include "symbol.h"
  20#include "subcmd/run-command.h"
  21
  22bool srcline_full_filename;
  23
  24static const char *dso__name(struct dso *dso)
  25{
  26        const char *dso_name;
  27
  28        if (dso->symsrc_filename)
  29                dso_name = dso->symsrc_filename;
  30        else
  31                dso_name = dso->long_name;
  32
  33        if (dso_name[0] == '[')
  34                return NULL;
  35
  36        if (!strncmp(dso_name, "/tmp/perf-", 10))
  37                return NULL;
  38
  39        return dso_name;
  40}
  41
  42static int inline_list__append(struct symbol *symbol, char *srcline,
  43                               struct inline_node *node)
  44{
  45        struct inline_list *ilist;
  46
  47        ilist = zalloc(sizeof(*ilist));
  48        if (ilist == NULL)
  49                return -1;
  50
  51        ilist->symbol = symbol;
  52        ilist->srcline = srcline;
  53
  54        if (callchain_param.order == ORDER_CALLEE)
  55                list_add_tail(&ilist->list, &node->val);
  56        else
  57                list_add(&ilist->list, &node->val);
  58
  59        return 0;
  60}
  61
  62/* basename version that takes a const input string */
  63static const char *gnu_basename(const char *path)
  64{
  65        const char *base = strrchr(path, '/');
  66
  67        return base ? base + 1 : path;
  68}
  69
  70static char *srcline_from_fileline(const char *file, unsigned int line)
  71{
  72        char *srcline;
  73
  74        if (!file)
  75                return NULL;
  76
  77        if (!srcline_full_filename)
  78                file = gnu_basename(file);
  79
  80        if (asprintf(&srcline, "%s:%u", file, line) < 0)
  81                return NULL;
  82
  83        return srcline;
  84}
  85
  86static struct symbol *new_inline_sym(struct dso *dso,
  87                                     struct symbol *base_sym,
  88                                     const char *funcname)
  89{
  90        struct symbol *inline_sym;
  91        char *demangled = NULL;
  92
  93        if (!funcname)
  94                funcname = "??";
  95
  96        if (dso) {
  97                demangled = dso__demangle_sym(dso, 0, funcname);
  98                if (demangled)
  99                        funcname = demangled;
 100        }
 101
 102        if (base_sym && strcmp(funcname, base_sym->name) == 0) {
 103                /* reuse the real, existing symbol */
 104                inline_sym = base_sym;
 105                /* ensure that we don't alias an inlined symbol, which could
 106                 * lead to double frees in inline_node__delete
 107                 */
 108                assert(!base_sym->inlined);
 109        } else {
 110                /* create a fake symbol for the inline frame */
 111                inline_sym = symbol__new(base_sym ? base_sym->start : 0,
 112                                         base_sym ? (base_sym->end - base_sym->start) : 0,
 113                                         base_sym ? base_sym->binding : 0,
 114                                         base_sym ? base_sym->type : 0,
 115                                         funcname);
 116                if (inline_sym)
 117                        inline_sym->inlined = 1;
 118        }
 119
 120        free(demangled);
 121
 122        return inline_sym;
 123}
 124
 125#define MAX_INLINE_NEST 1024
 126
 127#ifdef HAVE_LIBBFD_SUPPORT
 128
 129/*
 130 * Implement addr2line using libbfd.
 131 */
 132#define PACKAGE "perf"
 133#include <bfd.h>
 134
 135struct a2l_data {
 136        const char      *input;
 137        u64             addr;
 138
 139        bool            found;
 140        const char      *filename;
 141        const char      *funcname;
 142        unsigned        line;
 143
 144        bfd             *abfd;
 145        asymbol         **syms;
 146};
 147
 148static int bfd_error(const char *string)
 149{
 150        const char *errmsg;
 151
 152        errmsg = bfd_errmsg(bfd_get_error());
 153        fflush(stdout);
 154
 155        if (string)
 156                pr_debug("%s: %s\n", string, errmsg);
 157        else
 158                pr_debug("%s\n", errmsg);
 159
 160        return -1;
 161}
 162
 163static int slurp_symtab(bfd *abfd, struct a2l_data *a2l)
 164{
 165        long storage;
 166        long symcount;
 167        asymbol **syms;
 168        bfd_boolean dynamic = FALSE;
 169
 170        if ((bfd_get_file_flags(abfd) & HAS_SYMS) == 0)
 171                return bfd_error(bfd_get_filename(abfd));
 172
 173        storage = bfd_get_symtab_upper_bound(abfd);
 174        if (storage == 0L) {
 175                storage = bfd_get_dynamic_symtab_upper_bound(abfd);
 176                dynamic = TRUE;
 177        }
 178        if (storage < 0L)
 179                return bfd_error(bfd_get_filename(abfd));
 180
 181        syms = malloc(storage);
 182        if (dynamic)
 183                symcount = bfd_canonicalize_dynamic_symtab(abfd, syms);
 184        else
 185                symcount = bfd_canonicalize_symtab(abfd, syms);
 186
 187        if (symcount < 0) {
 188                free(syms);
 189                return bfd_error(bfd_get_filename(abfd));
 190        }
 191
 192        a2l->syms = syms;
 193        return 0;
 194}
 195
 196static void find_address_in_section(bfd *abfd, asection *section, void *data)
 197{
 198        bfd_vma pc, vma;
 199        bfd_size_type size;
 200        struct a2l_data *a2l = data;
 201        flagword flags;
 202
 203        if (a2l->found)
 204                return;
 205
 206#ifdef bfd_get_section_flags
 207        flags = bfd_get_section_flags(abfd, section);
 208#else
 209        flags = bfd_section_flags(section);
 210#endif
 211        if ((flags & SEC_ALLOC) == 0)
 212                return;
 213
 214        pc = a2l->addr;
 215#ifdef bfd_get_section_vma
 216        vma = bfd_get_section_vma(abfd, section);
 217#else
 218        vma = bfd_section_vma(section);
 219#endif
 220#ifdef bfd_get_section_size
 221        size = bfd_get_section_size(section);
 222#else
 223        size = bfd_section_size(section);
 224#endif
 225
 226        if (pc < vma || pc >= vma + size)
 227                return;
 228
 229        a2l->found = bfd_find_nearest_line(abfd, section, a2l->syms, pc - vma,
 230                                           &a2l->filename, &a2l->funcname,
 231                                           &a2l->line);
 232
 233        if (a2l->filename && !strlen(a2l->filename))
 234                a2l->filename = NULL;
 235}
 236
 237static struct a2l_data *addr2line_init(const char *path)
 238{
 239        bfd *abfd;
 240        struct a2l_data *a2l = NULL;
 241
 242        abfd = bfd_openr(path, NULL);
 243        if (abfd == NULL)
 244                return NULL;
 245
 246        if (!bfd_check_format(abfd, bfd_object))
 247                goto out;
 248
 249        a2l = zalloc(sizeof(*a2l));
 250        if (a2l == NULL)
 251                goto out;
 252
 253        a2l->abfd = abfd;
 254        a2l->input = strdup(path);
 255        if (a2l->input == NULL)
 256                goto out;
 257
 258        if (slurp_symtab(abfd, a2l))
 259                goto out;
 260
 261        return a2l;
 262
 263out:
 264        if (a2l) {
 265                zfree((char **)&a2l->input);
 266                free(a2l);
 267        }
 268        bfd_close(abfd);
 269        return NULL;
 270}
 271
 272static void addr2line_cleanup(struct a2l_data *a2l)
 273{
 274        if (a2l->abfd)
 275                bfd_close(a2l->abfd);
 276        zfree((char **)&a2l->input);
 277        zfree(&a2l->syms);
 278        free(a2l);
 279}
 280
 281static int inline_list__append_dso_a2l(struct dso *dso,
 282                                       struct inline_node *node,
 283                                       struct symbol *sym)
 284{
 285        struct a2l_data *a2l = dso->a2l;
 286        struct symbol *inline_sym = new_inline_sym(dso, sym, a2l->funcname);
 287        char *srcline = NULL;
 288
 289        if (a2l->filename)
 290                srcline = srcline_from_fileline(a2l->filename, a2l->line);
 291
 292        return inline_list__append(inline_sym, srcline, node);
 293}
 294
 295static int addr2line(const char *dso_name, u64 addr,
 296                     char **file, unsigned int *line, struct dso *dso,
 297                     bool unwind_inlines, struct inline_node *node,
 298                     struct symbol *sym)
 299{
 300        int ret = 0;
 301        struct a2l_data *a2l = dso->a2l;
 302
 303        if (!a2l) {
 304                dso->a2l = addr2line_init(dso_name);
 305                a2l = dso->a2l;
 306        }
 307
 308        if (a2l == NULL) {
 309                if (!symbol_conf.disable_add2line_warn)
 310                        pr_warning("addr2line_init failed for %s\n", dso_name);
 311                return 0;
 312        }
 313
 314        a2l->addr = addr;
 315        a2l->found = false;
 316
 317        bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l);
 318
 319        if (!a2l->found)
 320                return 0;
 321
 322        if (unwind_inlines) {
 323                int cnt = 0;
 324
 325                if (node && inline_list__append_dso_a2l(dso, node, sym))
 326                        return 0;
 327
 328                while (bfd_find_inliner_info(a2l->abfd, &a2l->filename,
 329                                             &a2l->funcname, &a2l->line) &&
 330                       cnt++ < MAX_INLINE_NEST) {
 331
 332                        if (a2l->filename && !strlen(a2l->filename))
 333                                a2l->filename = NULL;
 334
 335                        if (node != NULL) {
 336                                if (inline_list__append_dso_a2l(dso, node, sym))
 337                                        return 0;
 338                                // found at least one inline frame
 339                                ret = 1;
 340                        }
 341                }
 342        }
 343
 344        if (file) {
 345                *file = a2l->filename ? strdup(a2l->filename) : NULL;
 346                ret = *file ? 1 : 0;
 347        }
 348
 349        if (line)
 350                *line = a2l->line;
 351
 352        return ret;
 353}
 354
 355void dso__free_a2l(struct dso *dso)
 356{
 357        struct a2l_data *a2l = dso->a2l;
 358
 359        if (!a2l)
 360                return;
 361
 362        addr2line_cleanup(a2l);
 363
 364        dso->a2l = NULL;
 365}
 366
 367#else /* HAVE_LIBBFD_SUPPORT */
 368
 369struct a2l_subprocess {
 370        struct child_process addr2line;
 371        FILE *to_child;
 372        FILE *from_child;
 373};
 374
 375static int filename_split(char *filename, unsigned int *line_nr)
 376{
 377        char *sep;
 378
 379        sep = strchr(filename, '\n');
 380        if (sep)
 381                *sep = '\0';
 382
 383        if (!strcmp(filename, "??:0"))
 384                return 0;
 385
 386        sep = strchr(filename, ':');
 387        if (sep) {
 388                *sep++ = '\0';
 389                *line_nr = strtoul(sep, NULL, 0);
 390                return 1;
 391        }
 392
 393        return 0;
 394}
 395
 396static void addr2line_subprocess_cleanup(struct a2l_subprocess *a2l)
 397{
 398        if (a2l->addr2line.pid != -1) {
 399                kill(a2l->addr2line.pid, SIGKILL);
 400                finish_command(&a2l->addr2line); /* ignore result, we don't care */
 401                a2l->addr2line.pid = -1;
 402        }
 403
 404        if (a2l->to_child != NULL) {
 405                fclose(a2l->to_child);
 406                a2l->to_child = NULL;
 407        }
 408
 409        if (a2l->from_child != NULL) {
 410                fclose(a2l->from_child);
 411                a2l->from_child = NULL;
 412        }
 413
 414        free(a2l);
 415}
 416
 417static struct a2l_subprocess *addr2line_subprocess_init(const char *path)
 418{
 419        const char *argv[] = { "addr2line", "-e", path, "-i", "-f", NULL };
 420        struct a2l_subprocess *a2l = zalloc(sizeof(*a2l));
 421        int start_command_status = 0;
 422
 423        if (a2l == NULL)
 424                goto out;
 425
 426        a2l->to_child = NULL;
 427        a2l->from_child = NULL;
 428
 429        a2l->addr2line.pid = -1;
 430        a2l->addr2line.in = -1;
 431        a2l->addr2line.out = -1;
 432        a2l->addr2line.no_stderr = 1;
 433
 434        a2l->addr2line.argv = argv;
 435        start_command_status = start_command(&a2l->addr2line);
 436        a2l->addr2line.argv = NULL; /* it's not used after start_command; avoid dangling pointers */
 437
 438        if (start_command_status != 0) {
 439                pr_warning("could not start addr2line for %s: start_command return code %d\n",
 440                           path,
 441                           start_command_status);
 442                goto out;
 443        }
 444
 445        a2l->to_child = fdopen(a2l->addr2line.in, "w");
 446        if (a2l->to_child == NULL) {
 447                pr_warning("could not open write-stream to addr2line of %s\n", path);
 448                goto out;
 449        }
 450
 451        a2l->from_child = fdopen(a2l->addr2line.out, "r");
 452        if (a2l->from_child == NULL) {
 453                pr_warning("could not open read-stream from addr2line of %s\n", path);
 454                goto out;
 455        }
 456
 457        return a2l;
 458
 459out:
 460        if (a2l)
 461                addr2line_subprocess_cleanup(a2l);
 462
 463        return NULL;
 464}
 465
 466static int read_addr2line_record(struct a2l_subprocess *a2l,
 467                                 char **function,
 468                                 char **filename,
 469                                 unsigned int *line_nr)
 470{
 471        /*
 472         * Returns:
 473         * -1 ==> error
 474         * 0 ==> sentinel (or other ill-formed) record read
 475         * 1 ==> a genuine record read
 476         */
 477        char *line = NULL;
 478        size_t line_len = 0;
 479        unsigned int dummy_line_nr = 0;
 480        int ret = -1;
 481
 482        if (function != NULL)
 483                zfree(function);
 484
 485        if (filename != NULL)
 486                zfree(filename);
 487
 488        if (line_nr != NULL)
 489                *line_nr = 0;
 490
 491        if (getline(&line, &line_len, a2l->from_child) < 0 || !line_len)
 492                goto error;
 493
 494        if (function != NULL)
 495                *function = strdup(strim(line));
 496
 497        zfree(&line);
 498        line_len = 0;
 499
 500        if (getline(&line, &line_len, a2l->from_child) < 0 || !line_len)
 501                goto error;
 502
 503        if (filename_split(line, line_nr == NULL ? &dummy_line_nr : line_nr) == 0) {
 504                ret = 0;
 505                goto error;
 506        }
 507
 508        if (filename != NULL)
 509                *filename = strdup(line);
 510
 511        zfree(&line);
 512        line_len = 0;
 513
 514        return 1;
 515
 516error:
 517        free(line);
 518        if (function != NULL)
 519                zfree(function);
 520        if (filename != NULL)
 521                zfree(filename);
 522        return ret;
 523}
 524
 525static int inline_list__append_record(struct dso *dso,
 526                                      struct inline_node *node,
 527                                      struct symbol *sym,
 528                                      const char *function,
 529                                      const char *filename,
 530                                      unsigned int line_nr)
 531{
 532        struct symbol *inline_sym = new_inline_sym(dso, sym, function);
 533
 534        return inline_list__append(inline_sym, srcline_from_fileline(filename, line_nr), node);
 535}
 536
 537static int addr2line(const char *dso_name, u64 addr,
 538                     char **file, unsigned int *line_nr,
 539                     struct dso *dso,
 540                     bool unwind_inlines,
 541                     struct inline_node *node,
 542                     struct symbol *sym __maybe_unused)
 543{
 544        struct a2l_subprocess *a2l = dso->a2l;
 545        char *record_function = NULL;
 546        char *record_filename = NULL;
 547        unsigned int record_line_nr = 0;
 548        int record_status = -1;
 549        int ret = 0;
 550        size_t inline_count = 0;
 551
 552        if (!a2l) {
 553                dso->a2l = addr2line_subprocess_init(dso_name);
 554                a2l = dso->a2l;
 555        }
 556
 557        if (a2l == NULL) {
 558                if (!symbol_conf.disable_add2line_warn)
 559                        pr_warning("%s %s: addr2line_subprocess_init failed\n", __func__, dso_name);
 560                goto out;
 561        }
 562
 563        /*
 564         * Send our request and then *deliberately* send something that can't be interpreted as
 565         * a valid address to ask addr2line about (namely, ","). This causes addr2line to first
 566         * write out the answer to our request, in an unbounded/unknown number of records, and
 567         * then to write out the lines "??" and "??:0", so that we can detect when it has
 568         * finished giving us anything useful. We have to be careful about the first record,
 569         * though, because it may be genuinely unknown, in which case we'll get two sets of
 570         * "??"/"??:0" lines.
 571         */
 572        if (fprintf(a2l->to_child, "%016"PRIx64"\n,\n", addr) < 0 || fflush(a2l->to_child) != 0) {
 573                pr_warning("%s %s: could not send request\n", __func__, dso_name);
 574                goto out;
 575        }
 576
 577        switch (read_addr2line_record(a2l, &record_function, &record_filename, &record_line_nr)) {
 578        case -1:
 579                pr_warning("%s %s: could not read first record\n", __func__, dso_name);
 580                goto out;
 581        case 0:
 582                /*
 583                 * The first record was invalid, so return failure, but first read another
 584                 * record, since we asked a junk question and have to clear the answer out.
 585                 */
 586                switch (read_addr2line_record(a2l, NULL, NULL, NULL)) {
 587                case -1:
 588                        pr_warning("%s %s: could not read delimiter record\n", __func__, dso_name);
 589                        break;
 590                case 0:
 591                        /* As expected. */
 592                        break;
 593                default:
 594                        pr_warning("%s %s: unexpected record instead of sentinel",
 595                                   __func__, dso_name);
 596                        break;
 597                }
 598                goto out;
 599        default:
 600                break;
 601        }
 602
 603        if (file) {
 604                *file = strdup(record_filename);
 605                ret = 1;
 606        }
 607        if (line_nr)
 608                *line_nr = record_line_nr;
 609
 610        if (unwind_inlines) {
 611                if (node && inline_list__append_record(dso, node, sym,
 612                                                       record_function,
 613                                                       record_filename,
 614                                                       record_line_nr)) {
 615                        ret = 0;
 616                        goto out;
 617                }
 618        }
 619
 620        /* We have to read the records even if we don't care about the inline info. */
 621        while ((record_status = read_addr2line_record(a2l,
 622                                                      &record_function,
 623                                                      &record_filename,
 624                                                      &record_line_nr)) == 1) {
 625                if (unwind_inlines && node && inline_count++ < MAX_INLINE_NEST) {
 626                        if (inline_list__append_record(dso, node, sym,
 627                                                       record_function,
 628                                                       record_filename,
 629                                                       record_line_nr)) {
 630                                ret = 0;
 631                                goto out;
 632                        }
 633                        ret = 1; /* found at least one inline frame */
 634                }
 635        }
 636
 637out:
 638        free(record_function);
 639        free(record_filename);
 640        return ret;
 641}
 642
 643void dso__free_a2l(struct dso *dso)
 644{
 645        struct a2l_subprocess *a2l = dso->a2l;
 646
 647        if (!a2l)
 648                return;
 649
 650        addr2line_subprocess_cleanup(a2l);
 651
 652        dso->a2l = NULL;
 653}
 654
 655#endif /* HAVE_LIBBFD_SUPPORT */
 656
 657static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
 658                                        struct dso *dso, struct symbol *sym)
 659{
 660        struct inline_node *node;
 661
 662        node = zalloc(sizeof(*node));
 663        if (node == NULL) {
 664                perror("not enough memory for the inline node");
 665                return NULL;
 666        }
 667
 668        INIT_LIST_HEAD(&node->val);
 669        node->addr = addr;
 670
 671        addr2line(dso_name, addr, NULL, NULL, dso, true, node, sym);
 672        return node;
 673}
 674
 675/*
 676 * Number of addr2line failures (without success) before disabling it for that
 677 * dso.
 678 */
 679#define A2L_FAIL_LIMIT 123
 680
 681char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
 682                  bool show_sym, bool show_addr, bool unwind_inlines,
 683                  u64 ip)
 684{
 685        char *file = NULL;
 686        unsigned line = 0;
 687        char *srcline;
 688        const char *dso_name;
 689
 690        if (!dso->has_srcline)
 691                goto out;
 692
 693        dso_name = dso__name(dso);
 694        if (dso_name == NULL)
 695                goto out;
 696
 697        if (!addr2line(dso_name, addr, &file, &line, dso,
 698                       unwind_inlines, NULL, sym))
 699                goto out;
 700
 701        srcline = srcline_from_fileline(file, line);
 702        free(file);
 703
 704        if (!srcline)
 705                goto out;
 706
 707        dso->a2l_fails = 0;
 708
 709        return srcline;
 710
 711out:
 712        if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) {
 713                dso->has_srcline = 0;
 714                dso__free_a2l(dso);
 715        }
 716
 717        if (!show_addr)
 718                return (show_sym && sym) ?
 719                            strndup(sym->name, sym->namelen) : NULL;
 720
 721        if (sym) {
 722                if (asprintf(&srcline, "%s+%" PRIu64, show_sym ? sym->name : "",
 723                                        ip - sym->start) < 0)
 724                        return SRCLINE_UNKNOWN;
 725        } else if (asprintf(&srcline, "%s[%" PRIx64 "]", dso->short_name, addr) < 0)
 726                return SRCLINE_UNKNOWN;
 727        return srcline;
 728}
 729
 730/* Returns filename and fills in line number in line */
 731char *get_srcline_split(struct dso *dso, u64 addr, unsigned *line)
 732{
 733        char *file = NULL;
 734        const char *dso_name;
 735
 736        if (!dso->has_srcline)
 737                goto out;
 738
 739        dso_name = dso__name(dso);
 740        if (dso_name == NULL)
 741                goto out;
 742
 743        if (!addr2line(dso_name, addr, &file, line, dso, true, NULL, NULL))
 744                goto out;
 745
 746        dso->a2l_fails = 0;
 747        return file;
 748
 749out:
 750        if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) {
 751                dso->has_srcline = 0;
 752                dso__free_a2l(dso);
 753        }
 754
 755        return NULL;
 756}
 757
 758void free_srcline(char *srcline)
 759{
 760        if (srcline && strcmp(srcline, SRCLINE_UNKNOWN) != 0)
 761                free(srcline);
 762}
 763
 764char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
 765                  bool show_sym, bool show_addr, u64 ip)
 766{
 767        return __get_srcline(dso, addr, sym, show_sym, show_addr, false, ip);
 768}
 769
 770struct srcline_node {
 771        u64                     addr;
 772        char                    *srcline;
 773        struct rb_node          rb_node;
 774};
 775
 776void srcline__tree_insert(struct rb_root_cached *tree, u64 addr, char *srcline)
 777{
 778        struct rb_node **p = &tree->rb_root.rb_node;
 779        struct rb_node *parent = NULL;
 780        struct srcline_node *i, *node;
 781        bool leftmost = true;
 782
 783        node = zalloc(sizeof(struct srcline_node));
 784        if (!node) {
 785                perror("not enough memory for the srcline node");
 786                return;
 787        }
 788
 789        node->addr = addr;
 790        node->srcline = srcline;
 791
 792        while (*p != NULL) {
 793                parent = *p;
 794                i = rb_entry(parent, struct srcline_node, rb_node);
 795                if (addr < i->addr)
 796                        p = &(*p)->rb_left;
 797                else {
 798                        p = &(*p)->rb_right;
 799                        leftmost = false;
 800                }
 801        }
 802        rb_link_node(&node->rb_node, parent, p);
 803        rb_insert_color_cached(&node->rb_node, tree, leftmost);
 804}
 805
 806char *srcline__tree_find(struct rb_root_cached *tree, u64 addr)
 807{
 808        struct rb_node *n = tree->rb_root.rb_node;
 809
 810        while (n) {
 811                struct srcline_node *i = rb_entry(n, struct srcline_node,
 812                                                  rb_node);
 813
 814                if (addr < i->addr)
 815                        n = n->rb_left;
 816                else if (addr > i->addr)
 817                        n = n->rb_right;
 818                else
 819                        return i->srcline;
 820        }
 821
 822        return NULL;
 823}
 824
 825void srcline__tree_delete(struct rb_root_cached *tree)
 826{
 827        struct srcline_node *pos;
 828        struct rb_node *next = rb_first_cached(tree);
 829
 830        while (next) {
 831                pos = rb_entry(next, struct srcline_node, rb_node);
 832                next = rb_next(&pos->rb_node);
 833                rb_erase_cached(&pos->rb_node, tree);
 834                free_srcline(pos->srcline);
 835                zfree(&pos);
 836        }
 837}
 838
 839struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr,
 840                                            struct symbol *sym)
 841{
 842        const char *dso_name;
 843
 844        dso_name = dso__name(dso);
 845        if (dso_name == NULL)
 846                return NULL;
 847
 848        return addr2inlines(dso_name, addr, dso, sym);
 849}
 850
 851void inline_node__delete(struct inline_node *node)
 852{
 853        struct inline_list *ilist, *tmp;
 854
 855        list_for_each_entry_safe(ilist, tmp, &node->val, list) {
 856                list_del_init(&ilist->list);
 857                free_srcline(ilist->srcline);
 858                /* only the inlined symbols are owned by the list */
 859                if (ilist->symbol && ilist->symbol->inlined)
 860                        symbol__delete(ilist->symbol);
 861                free(ilist);
 862        }
 863
 864        free(node);
 865}
 866
 867void inlines__tree_insert(struct rb_root_cached *tree,
 868                          struct inline_node *inlines)
 869{
 870        struct rb_node **p = &tree->rb_root.rb_node;
 871        struct rb_node *parent = NULL;
 872        const u64 addr = inlines->addr;
 873        struct inline_node *i;
 874        bool leftmost = true;
 875
 876        while (*p != NULL) {
 877                parent = *p;
 878                i = rb_entry(parent, struct inline_node, rb_node);
 879                if (addr < i->addr)
 880                        p = &(*p)->rb_left;
 881                else {
 882                        p = &(*p)->rb_right;
 883                        leftmost = false;
 884                }
 885        }
 886        rb_link_node(&inlines->rb_node, parent, p);
 887        rb_insert_color_cached(&inlines->rb_node, tree, leftmost);
 888}
 889
 890struct inline_node *inlines__tree_find(struct rb_root_cached *tree, u64 addr)
 891{
 892        struct rb_node *n = tree->rb_root.rb_node;
 893
 894        while (n) {
 895                struct inline_node *i = rb_entry(n, struct inline_node,
 896                                                 rb_node);
 897
 898                if (addr < i->addr)
 899                        n = n->rb_left;
 900                else if (addr > i->addr)
 901                        n = n->rb_right;
 902                else
 903                        return i;
 904        }
 905
 906        return NULL;
 907}
 908
 909void inlines__tree_delete(struct rb_root_cached *tree)
 910{
 911        struct inline_node *pos;
 912        struct rb_node *next = rb_first_cached(tree);
 913
 914        while (next) {
 915                pos = rb_entry(next, struct inline_node, rb_node);
 916                next = rb_next(&pos->rb_node);
 917                rb_erase_cached(&pos->rb_node, tree);
 918                inline_node__delete(pos);
 919        }
 920}
 921