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