diff options
Diffstat (limited to 'tools/perf/util')
-rw-r--r-- | tools/perf/util/annotate.c | 2 | ||||
-rw-r--r-- | tools/perf/util/dwarf-aux.c | 44 | ||||
-rw-r--r-- | tools/perf/util/dwarf-aux.h | 9 | ||||
-rw-r--r-- | tools/perf/util/header.c | 53 | ||||
-rw-r--r-- | tools/perf/util/hist.c | 2 | ||||
-rw-r--r-- | tools/perf/util/machine.c | 2 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.c | 138 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.h | 3 | ||||
-rw-r--r-- | tools/perf/util/session.c | 13 | ||||
-rw-r--r-- | tools/perf/util/session.h | 4 | ||||
-rw-r--r-- | tools/perf/util/symbol-elf.c | 16 | ||||
-rw-r--r-- | tools/perf/util/trace-event-parse.c | 2 |
12 files changed, 205 insertions, 83 deletions
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index bfc5a27597d6..7eae5488ecea 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -809,7 +809,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, | |||
809 | end = map__rip_2objdump(map, sym->end); | 809 | end = map__rip_2objdump(map, sym->end); |
810 | 810 | ||
811 | offset = line_ip - start; | 811 | offset = line_ip - start; |
812 | if (offset < 0 || (u64)line_ip > end) | 812 | if ((u64)line_ip < start || (u64)line_ip > end) |
813 | offset = -1; | 813 | offset = -1; |
814 | else | 814 | else |
815 | parsed_line = tmp2 + 1; | 815 | parsed_line = tmp2 + 1; |
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index 3e5f5430a28a..7defd77105d0 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c | |||
@@ -263,6 +263,21 @@ bool die_is_signed_type(Dwarf_Die *tp_die) | |||
263 | } | 263 | } |
264 | 264 | ||
265 | /** | 265 | /** |
266 | * die_is_func_def - Ensure that this DIE is a subprogram and definition | ||
267 | * @dw_die: a DIE | ||
268 | * | ||
269 | * Ensure that this DIE is a subprogram and NOT a declaration. This | ||
270 | * returns true if @dw_die is a function definition. | ||
271 | **/ | ||
272 | bool die_is_func_def(Dwarf_Die *dw_die) | ||
273 | { | ||
274 | Dwarf_Attribute attr; | ||
275 | |||
276 | return (dwarf_tag(dw_die) == DW_TAG_subprogram && | ||
277 | dwarf_attr(dw_die, DW_AT_declaration, &attr) == NULL); | ||
278 | } | ||
279 | |||
280 | /** | ||
266 | * die_get_data_member_location - Get the data-member offset | 281 | * die_get_data_member_location - Get the data-member offset |
267 | * @mb_die: a DIE of a member of a data structure | 282 | * @mb_die: a DIE of a member of a data structure |
268 | * @offs: The offset of the member in the data structure | 283 | * @offs: The offset of the member in the data structure |
@@ -392,6 +407,10 @@ static int __die_search_func_cb(Dwarf_Die *fn_die, void *data) | |||
392 | { | 407 | { |
393 | struct __addr_die_search_param *ad = data; | 408 | struct __addr_die_search_param *ad = data; |
394 | 409 | ||
410 | /* | ||
411 | * Since a declaration entry doesn't has given pc, this always returns | ||
412 | * function definition entry. | ||
413 | */ | ||
395 | if (dwarf_tag(fn_die) == DW_TAG_subprogram && | 414 | if (dwarf_tag(fn_die) == DW_TAG_subprogram && |
396 | dwarf_haspc(fn_die, ad->addr)) { | 415 | dwarf_haspc(fn_die, ad->addr)) { |
397 | memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die)); | 416 | memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die)); |
@@ -407,7 +426,7 @@ static int __die_search_func_cb(Dwarf_Die *fn_die, void *data) | |||
407 | * @die_mem: a buffer for result DIE | 426 | * @die_mem: a buffer for result DIE |
408 | * | 427 | * |
409 | * Search a non-inlined function DIE which includes @addr. Stores the | 428 | * Search a non-inlined function DIE which includes @addr. Stores the |
410 | * DIE to @die_mem and returns it if found. Returns NULl if failed. | 429 | * DIE to @die_mem and returns it if found. Returns NULL if failed. |
411 | */ | 430 | */ |
412 | Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr, | 431 | Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr, |
413 | Dwarf_Die *die_mem) | 432 | Dwarf_Die *die_mem) |
@@ -435,15 +454,32 @@ static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data) | |||
435 | } | 454 | } |
436 | 455 | ||
437 | /** | 456 | /** |
457 | * die_find_top_inlinefunc - Search the top inlined function at given address | ||
458 | * @sp_die: a subprogram DIE which including @addr | ||
459 | * @addr: target address | ||
460 | * @die_mem: a buffer for result DIE | ||
461 | * | ||
462 | * Search an inlined function DIE which includes @addr. Stores the | ||
463 | * DIE to @die_mem and returns it if found. Returns NULL if failed. | ||
464 | * Even if several inlined functions are expanded recursively, this | ||
465 | * doesn't trace it down, and returns the topmost one. | ||
466 | */ | ||
467 | Dwarf_Die *die_find_top_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | ||
468 | Dwarf_Die *die_mem) | ||
469 | { | ||
470 | return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem); | ||
471 | } | ||
472 | |||
473 | /** | ||
438 | * die_find_inlinefunc - Search an inlined function at given address | 474 | * die_find_inlinefunc - Search an inlined function at given address |
439 | * @cu_die: a CU DIE which including @addr | 475 | * @sp_die: a subprogram DIE which including @addr |
440 | * @addr: target address | 476 | * @addr: target address |
441 | * @die_mem: a buffer for result DIE | 477 | * @die_mem: a buffer for result DIE |
442 | * | 478 | * |
443 | * Search an inlined function DIE which includes @addr. Stores the | 479 | * Search an inlined function DIE which includes @addr. Stores the |
444 | * DIE to @die_mem and returns it if found. Returns NULl if failed. | 480 | * DIE to @die_mem and returns it if found. Returns NULL if failed. |
445 | * If several inlined functions are expanded recursively, this trace | 481 | * If several inlined functions are expanded recursively, this trace |
446 | * it and returns deepest one. | 482 | * it down and returns deepest one. |
447 | */ | 483 | */ |
448 | Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | 484 | Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, |
449 | Dwarf_Die *die_mem) | 485 | Dwarf_Die *die_mem) |
diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index 6ce1717784b7..b4fe90c6cb2d 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h | |||
@@ -38,6 +38,9 @@ extern int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr, | |||
38 | extern int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr, | 38 | extern int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr, |
39 | int (*callback)(Dwarf_Die *, void *), void *data); | 39 | int (*callback)(Dwarf_Die *, void *), void *data); |
40 | 40 | ||
41 | /* Ensure that this DIE is a subprogram and definition (not declaration) */ | ||
42 | extern bool die_is_func_def(Dwarf_Die *dw_die); | ||
43 | |||
41 | /* Compare diename and tname */ | 44 | /* Compare diename and tname */ |
42 | extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname); | 45 | extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname); |
43 | 46 | ||
@@ -76,7 +79,11 @@ extern Dwarf_Die *die_find_child(Dwarf_Die *rt_die, | |||
76 | extern Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr, | 79 | extern Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr, |
77 | Dwarf_Die *die_mem); | 80 | Dwarf_Die *die_mem); |
78 | 81 | ||
79 | /* Search an inlined function including given address */ | 82 | /* Search the top inlined function including given address */ |
83 | extern Dwarf_Die *die_find_top_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | ||
84 | Dwarf_Die *die_mem); | ||
85 | |||
86 | /* Search the deepest inlined function including given address */ | ||
80 | extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | 87 | extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, |
81 | Dwarf_Die *die_mem); | 88 | Dwarf_Die *die_mem); |
82 | 89 | ||
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 26441d0e571b..c3e5a3b817ab 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -199,9 +199,11 @@ static int write_buildid(char *name, size_t name_len, u8 *build_id, | |||
199 | return write_padded(fd, name, name_len + 1, len); | 199 | return write_padded(fd, name, name_len + 1, len); |
200 | } | 200 | } |
201 | 201 | ||
202 | static int __dsos__write_buildid_table(struct list_head *head, pid_t pid, | 202 | static int __dsos__write_buildid_table(struct list_head *head, |
203 | u16 misc, int fd) | 203 | struct machine *machine, |
204 | pid_t pid, u16 misc, int fd) | ||
204 | { | 205 | { |
206 | char nm[PATH_MAX]; | ||
205 | struct dso *pos; | 207 | struct dso *pos; |
206 | 208 | ||
207 | dsos__for_each_with_build_id(pos, head) { | 209 | dsos__for_each_with_build_id(pos, head) { |
@@ -215,6 +217,10 @@ static int __dsos__write_buildid_table(struct list_head *head, pid_t pid, | |||
215 | if (is_vdso_map(pos->short_name)) { | 217 | if (is_vdso_map(pos->short_name)) { |
216 | name = (char *) VDSO__MAP_NAME; | 218 | name = (char *) VDSO__MAP_NAME; |
217 | name_len = sizeof(VDSO__MAP_NAME) + 1; | 219 | name_len = sizeof(VDSO__MAP_NAME) + 1; |
220 | } else if (dso__is_kcore(pos)) { | ||
221 | machine__mmap_name(machine, nm, sizeof(nm)); | ||
222 | name = nm; | ||
223 | name_len = strlen(nm) + 1; | ||
218 | } else { | 224 | } else { |
219 | name = pos->long_name; | 225 | name = pos->long_name; |
220 | name_len = pos->long_name_len + 1; | 226 | name_len = pos->long_name_len + 1; |
@@ -240,10 +246,10 @@ static int machine__write_buildid_table(struct machine *machine, int fd) | |||
240 | umisc = PERF_RECORD_MISC_GUEST_USER; | 246 | umisc = PERF_RECORD_MISC_GUEST_USER; |
241 | } | 247 | } |
242 | 248 | ||
243 | err = __dsos__write_buildid_table(&machine->kernel_dsos, machine->pid, | 249 | err = __dsos__write_buildid_table(&machine->kernel_dsos, machine, |
244 | kmisc, fd); | 250 | machine->pid, kmisc, fd); |
245 | if (err == 0) | 251 | if (err == 0) |
246 | err = __dsos__write_buildid_table(&machine->user_dsos, | 252 | err = __dsos__write_buildid_table(&machine->user_dsos, machine, |
247 | machine->pid, umisc, fd); | 253 | machine->pid, umisc, fd); |
248 | return err; | 254 | return err; |
249 | } | 255 | } |
@@ -375,23 +381,31 @@ out_free: | |||
375 | return err; | 381 | return err; |
376 | } | 382 | } |
377 | 383 | ||
378 | static int dso__cache_build_id(struct dso *dso, const char *debugdir) | 384 | static int dso__cache_build_id(struct dso *dso, struct machine *machine, |
385 | const char *debugdir) | ||
379 | { | 386 | { |
380 | bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; | 387 | bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; |
381 | bool is_vdso = is_vdso_map(dso->short_name); | 388 | bool is_vdso = is_vdso_map(dso->short_name); |
389 | char *name = dso->long_name; | ||
390 | char nm[PATH_MAX]; | ||
382 | 391 | ||
383 | return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), | 392 | if (dso__is_kcore(dso)) { |
384 | dso->long_name, debugdir, | 393 | is_kallsyms = true; |
385 | is_kallsyms, is_vdso); | 394 | machine__mmap_name(machine, nm, sizeof(nm)); |
395 | name = nm; | ||
396 | } | ||
397 | return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), name, | ||
398 | debugdir, is_kallsyms, is_vdso); | ||
386 | } | 399 | } |
387 | 400 | ||
388 | static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) | 401 | static int __dsos__cache_build_ids(struct list_head *head, |
402 | struct machine *machine, const char *debugdir) | ||
389 | { | 403 | { |
390 | struct dso *pos; | 404 | struct dso *pos; |
391 | int err = 0; | 405 | int err = 0; |
392 | 406 | ||
393 | dsos__for_each_with_build_id(pos, head) | 407 | dsos__for_each_with_build_id(pos, head) |
394 | if (dso__cache_build_id(pos, debugdir)) | 408 | if (dso__cache_build_id(pos, machine, debugdir)) |
395 | err = -1; | 409 | err = -1; |
396 | 410 | ||
397 | return err; | 411 | return err; |
@@ -399,8 +413,9 @@ static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) | |||
399 | 413 | ||
400 | static int machine__cache_build_ids(struct machine *machine, const char *debugdir) | 414 | static int machine__cache_build_ids(struct machine *machine, const char *debugdir) |
401 | { | 415 | { |
402 | int ret = __dsos__cache_build_ids(&machine->kernel_dsos, debugdir); | 416 | int ret = __dsos__cache_build_ids(&machine->kernel_dsos, machine, |
403 | ret |= __dsos__cache_build_ids(&machine->user_dsos, debugdir); | 417 | debugdir); |
418 | ret |= __dsos__cache_build_ids(&machine->user_dsos, machine, debugdir); | ||
404 | return ret; | 419 | return ret; |
405 | } | 420 | } |
406 | 421 | ||
@@ -2753,6 +2768,18 @@ int perf_session__read_header(struct perf_session *session) | |||
2753 | if (perf_file_header__read(&f_header, header, fd) < 0) | 2768 | if (perf_file_header__read(&f_header, header, fd) < 0) |
2754 | return -EINVAL; | 2769 | return -EINVAL; |
2755 | 2770 | ||
2771 | /* | ||
2772 | * Sanity check that perf.data was written cleanly; data size is | ||
2773 | * initialized to 0 and updated only if the on_exit function is run. | ||
2774 | * If data size is still 0 then the file contains only partial | ||
2775 | * information. Just warn user and process it as much as it can. | ||
2776 | */ | ||
2777 | if (f_header.data.size == 0) { | ||
2778 | pr_warning("WARNING: The %s file's data size field is 0 which is unexpected.\n" | ||
2779 | "Was the 'perf record' command properly terminated?\n", | ||
2780 | session->filename); | ||
2781 | } | ||
2782 | |||
2756 | nr_attrs = f_header.attrs.size / f_header.attr_size; | 2783 | nr_attrs = f_header.attrs.size / f_header.attr_size; |
2757 | lseek(fd, f_header.attrs.offset, SEEK_SET); | 2784 | lseek(fd, f_header.attrs.offset, SEEK_SET); |
2758 | 2785 | ||
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 46a0d35a05e1..9ff6cf3e9a99 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -611,6 +611,8 @@ void hists__collapse_resort(struct hists *hists) | |||
611 | next = rb_first(root); | 611 | next = rb_first(root); |
612 | 612 | ||
613 | while (next) { | 613 | while (next) { |
614 | if (session_done()) | ||
615 | break; | ||
614 | n = rb_entry(next, struct hist_entry, rb_node_in); | 616 | n = rb_entry(next, struct hist_entry, rb_node_in); |
615 | next = rb_next(&n->rb_node_in); | 617 | next = rb_next(&n->rb_node_in); |
616 | 618 | ||
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 933d14f287ca..6188d2876a71 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -792,7 +792,7 @@ static int machine__create_modules(struct machine *machine) | |||
792 | modules = path; | 792 | modules = path; |
793 | } | 793 | } |
794 | 794 | ||
795 | if (symbol__restricted_filename(path, "/proc/modules")) | 795 | if (symbol__restricted_filename(modules, "/proc/modules")) |
796 | return -1; | 796 | return -1; |
797 | 797 | ||
798 | file = fopen(modules, "r"); | 798 | file = fopen(modules, "r"); |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index be0329394d56..c09e0a9fdf4c 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -118,7 +118,6 @@ static const Dwfl_Callbacks offline_callbacks = { | |||
118 | static int debuginfo__init_offline_dwarf(struct debuginfo *self, | 118 | static int debuginfo__init_offline_dwarf(struct debuginfo *self, |
119 | const char *path) | 119 | const char *path) |
120 | { | 120 | { |
121 | Dwfl_Module *mod; | ||
122 | int fd; | 121 | int fd; |
123 | 122 | ||
124 | fd = open(path, O_RDONLY); | 123 | fd = open(path, O_RDONLY); |
@@ -129,11 +128,11 @@ static int debuginfo__init_offline_dwarf(struct debuginfo *self, | |||
129 | if (!self->dwfl) | 128 | if (!self->dwfl) |
130 | goto error; | 129 | goto error; |
131 | 130 | ||
132 | mod = dwfl_report_offline(self->dwfl, "", "", fd); | 131 | self->mod = dwfl_report_offline(self->dwfl, "", "", fd); |
133 | if (!mod) | 132 | if (!self->mod) |
134 | goto error; | 133 | goto error; |
135 | 134 | ||
136 | self->dbg = dwfl_module_getdwarf(mod, &self->bias); | 135 | self->dbg = dwfl_module_getdwarf(self->mod, &self->bias); |
137 | if (!self->dbg) | 136 | if (!self->dbg) |
138 | goto error; | 137 | goto error; |
139 | 138 | ||
@@ -676,37 +675,42 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) | |||
676 | } | 675 | } |
677 | 676 | ||
678 | /* Convert subprogram DIE to trace point */ | 677 | /* Convert subprogram DIE to trace point */ |
679 | static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr, | 678 | static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod, |
680 | bool retprobe, struct probe_trace_point *tp) | 679 | Dwarf_Addr paddr, bool retprobe, |
680 | struct probe_trace_point *tp) | ||
681 | { | 681 | { |
682 | Dwarf_Addr eaddr, highaddr; | 682 | Dwarf_Addr eaddr, highaddr; |
683 | const char *name; | 683 | GElf_Sym sym; |
684 | 684 | const char *symbol; | |
685 | /* Copy the name of probe point */ | 685 | |
686 | name = dwarf_diename(sp_die); | 686 | /* Verify the address is correct */ |
687 | if (name) { | 687 | if (dwarf_entrypc(sp_die, &eaddr) != 0) { |
688 | if (dwarf_entrypc(sp_die, &eaddr) != 0) { | 688 | pr_warning("Failed to get entry address of %s\n", |
689 | pr_warning("Failed to get entry address of %s\n", | 689 | dwarf_diename(sp_die)); |
690 | dwarf_diename(sp_die)); | 690 | return -ENOENT; |
691 | return -ENOENT; | 691 | } |
692 | } | 692 | if (dwarf_highpc(sp_die, &highaddr) != 0) { |
693 | if (dwarf_highpc(sp_die, &highaddr) != 0) { | 693 | pr_warning("Failed to get end address of %s\n", |
694 | pr_warning("Failed to get end address of %s\n", | 694 | dwarf_diename(sp_die)); |
695 | dwarf_diename(sp_die)); | 695 | return -ENOENT; |
696 | return -ENOENT; | 696 | } |
697 | } | 697 | if (paddr > highaddr) { |
698 | if (paddr > highaddr) { | 698 | pr_warning("Offset specified is greater than size of %s\n", |
699 | pr_warning("Offset specified is greater than size of %s\n", | 699 | dwarf_diename(sp_die)); |
700 | dwarf_diename(sp_die)); | 700 | return -EINVAL; |
701 | return -EINVAL; | 701 | } |
702 | } | 702 | |
703 | tp->symbol = strdup(name); | 703 | /* Get an appropriate symbol from symtab */ |
704 | if (tp->symbol == NULL) | 704 | symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL); |
705 | return -ENOMEM; | 705 | if (!symbol) { |
706 | tp->offset = (unsigned long)(paddr - eaddr); | 706 | pr_warning("Failed to find symbol at 0x%lx\n", |
707 | } else | 707 | (unsigned long)paddr); |
708 | /* This function has no name. */ | 708 | return -ENOENT; |
709 | tp->offset = (unsigned long)paddr; | 709 | } |
710 | tp->offset = (unsigned long)(paddr - sym.st_value); | ||
711 | tp->symbol = strdup(symbol); | ||
712 | if (!tp->symbol) | ||
713 | return -ENOMEM; | ||
710 | 714 | ||
711 | /* Return probe must be on the head of a subprogram */ | 715 | /* Return probe must be on the head of a subprogram */ |
712 | if (retprobe) { | 716 | if (retprobe) { |
@@ -734,7 +738,7 @@ static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf) | |||
734 | } | 738 | } |
735 | 739 | ||
736 | /* If not a real subprogram, find a real one */ | 740 | /* If not a real subprogram, find a real one */ |
737 | if (dwarf_tag(sc_die) != DW_TAG_subprogram) { | 741 | if (!die_is_func_def(sc_die)) { |
738 | if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { | 742 | if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { |
739 | pr_warning("Failed to find probe point in any " | 743 | pr_warning("Failed to find probe point in any " |
740 | "functions.\n"); | 744 | "functions.\n"); |
@@ -980,12 +984,10 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) | |||
980 | struct dwarf_callback_param *param = data; | 984 | struct dwarf_callback_param *param = data; |
981 | struct probe_finder *pf = param->data; | 985 | struct probe_finder *pf = param->data; |
982 | struct perf_probe_point *pp = &pf->pev->point; | 986 | struct perf_probe_point *pp = &pf->pev->point; |
983 | Dwarf_Attribute attr; | ||
984 | 987 | ||
985 | /* Check tag and diename */ | 988 | /* Check tag and diename */ |
986 | if (dwarf_tag(sp_die) != DW_TAG_subprogram || | 989 | if (!die_is_func_def(sp_die) || |
987 | !die_compare_name(sp_die, pp->function) || | 990 | !die_compare_name(sp_die, pp->function)) |
988 | dwarf_attr(sp_die, DW_AT_declaration, &attr)) | ||
989 | return DWARF_CB_OK; | 991 | return DWARF_CB_OK; |
990 | 992 | ||
991 | /* Check declared file */ | 993 | /* Check declared file */ |
@@ -1151,7 +1153,7 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) | |||
1151 | tev = &tf->tevs[tf->ntevs++]; | 1153 | tev = &tf->tevs[tf->ntevs++]; |
1152 | 1154 | ||
1153 | /* Trace point should be converted from subprogram DIE */ | 1155 | /* Trace point should be converted from subprogram DIE */ |
1154 | ret = convert_to_trace_point(&pf->sp_die, pf->addr, | 1156 | ret = convert_to_trace_point(&pf->sp_die, tf->mod, pf->addr, |
1155 | pf->pev->point.retprobe, &tev->point); | 1157 | pf->pev->point.retprobe, &tev->point); |
1156 | if (ret < 0) | 1158 | if (ret < 0) |
1157 | return ret; | 1159 | return ret; |
@@ -1183,7 +1185,7 @@ int debuginfo__find_trace_events(struct debuginfo *self, | |||
1183 | { | 1185 | { |
1184 | struct trace_event_finder tf = { | 1186 | struct trace_event_finder tf = { |
1185 | .pf = {.pev = pev, .callback = add_probe_trace_event}, | 1187 | .pf = {.pev = pev, .callback = add_probe_trace_event}, |
1186 | .max_tevs = max_tevs}; | 1188 | .mod = self->mod, .max_tevs = max_tevs}; |
1187 | int ret; | 1189 | int ret; |
1188 | 1190 | ||
1189 | /* Allocate result tevs array */ | 1191 | /* Allocate result tevs array */ |
@@ -1252,7 +1254,7 @@ static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf) | |||
1252 | vl = &af->vls[af->nvls++]; | 1254 | vl = &af->vls[af->nvls++]; |
1253 | 1255 | ||
1254 | /* Trace point should be converted from subprogram DIE */ | 1256 | /* Trace point should be converted from subprogram DIE */ |
1255 | ret = convert_to_trace_point(&pf->sp_die, pf->addr, | 1257 | ret = convert_to_trace_point(&pf->sp_die, af->mod, pf->addr, |
1256 | pf->pev->point.retprobe, &vl->point); | 1258 | pf->pev->point.retprobe, &vl->point); |
1257 | if (ret < 0) | 1259 | if (ret < 0) |
1258 | return ret; | 1260 | return ret; |
@@ -1291,6 +1293,7 @@ int debuginfo__find_available_vars_at(struct debuginfo *self, | |||
1291 | { | 1293 | { |
1292 | struct available_var_finder af = { | 1294 | struct available_var_finder af = { |
1293 | .pf = {.pev = pev, .callback = add_available_vars}, | 1295 | .pf = {.pev = pev, .callback = add_available_vars}, |
1296 | .mod = self->mod, | ||
1294 | .max_vls = max_vls, .externs = externs}; | 1297 | .max_vls = max_vls, .externs = externs}; |
1295 | int ret; | 1298 | int ret; |
1296 | 1299 | ||
@@ -1324,8 +1327,8 @@ int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr, | |||
1324 | struct perf_probe_point *ppt) | 1327 | struct perf_probe_point *ppt) |
1325 | { | 1328 | { |
1326 | Dwarf_Die cudie, spdie, indie; | 1329 | Dwarf_Die cudie, spdie, indie; |
1327 | Dwarf_Addr _addr, baseaddr; | 1330 | Dwarf_Addr _addr = 0, baseaddr = 0; |
1328 | const char *fname = NULL, *func = NULL, *tmp; | 1331 | const char *fname = NULL, *func = NULL, *basefunc = NULL, *tmp; |
1329 | int baseline = 0, lineno = 0, ret = 0; | 1332 | int baseline = 0, lineno = 0, ret = 0; |
1330 | 1333 | ||
1331 | /* Adjust address with bias */ | 1334 | /* Adjust address with bias */ |
@@ -1346,27 +1349,36 @@ int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr, | |||
1346 | /* Find a corresponding function (name, baseline and baseaddr) */ | 1349 | /* Find a corresponding function (name, baseline and baseaddr) */ |
1347 | if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) { | 1350 | if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) { |
1348 | /* Get function entry information */ | 1351 | /* Get function entry information */ |
1349 | tmp = dwarf_diename(&spdie); | 1352 | func = basefunc = dwarf_diename(&spdie); |
1350 | if (!tmp || | 1353 | if (!func || |
1351 | dwarf_entrypc(&spdie, &baseaddr) != 0 || | 1354 | dwarf_entrypc(&spdie, &baseaddr) != 0 || |
1352 | dwarf_decl_line(&spdie, &baseline) != 0) | 1355 | dwarf_decl_line(&spdie, &baseline) != 0) { |
1356 | lineno = 0; | ||
1353 | goto post; | 1357 | goto post; |
1354 | func = tmp; | 1358 | } |
1355 | 1359 | ||
1356 | if (addr == (unsigned long)baseaddr) | 1360 | if (addr == (unsigned long)baseaddr) { |
1357 | /* Function entry - Relative line number is 0 */ | 1361 | /* Function entry - Relative line number is 0 */ |
1358 | lineno = baseline; | 1362 | lineno = baseline; |
1359 | else if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, | 1363 | fname = dwarf_decl_file(&spdie); |
1360 | &indie)) { | 1364 | goto post; |
1365 | } | ||
1366 | |||
1367 | /* Track down the inline functions step by step */ | ||
1368 | while (die_find_top_inlinefunc(&spdie, (Dwarf_Addr)addr, | ||
1369 | &indie)) { | ||
1370 | /* There is an inline function */ | ||
1361 | if (dwarf_entrypc(&indie, &_addr) == 0 && | 1371 | if (dwarf_entrypc(&indie, &_addr) == 0 && |
1362 | _addr == addr) | 1372 | _addr == addr) { |
1363 | /* | 1373 | /* |
1364 | * addr is at an inline function entry. | 1374 | * addr is at an inline function entry. |
1365 | * In this case, lineno should be the call-site | 1375 | * In this case, lineno should be the call-site |
1366 | * line number. | 1376 | * line number. (overwrite lineinfo) |
1367 | */ | 1377 | */ |
1368 | lineno = die_get_call_lineno(&indie); | 1378 | lineno = die_get_call_lineno(&indie); |
1369 | else { | 1379 | fname = die_get_call_file(&indie); |
1380 | break; | ||
1381 | } else { | ||
1370 | /* | 1382 | /* |
1371 | * addr is in an inline function body. | 1383 | * addr is in an inline function body. |
1372 | * Since lineno points one of the lines | 1384 | * Since lineno points one of the lines |
@@ -1374,19 +1386,27 @@ int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr, | |||
1374 | * be the entry line of the inline function. | 1386 | * be the entry line of the inline function. |
1375 | */ | 1387 | */ |
1376 | tmp = dwarf_diename(&indie); | 1388 | tmp = dwarf_diename(&indie); |
1377 | if (tmp && | 1389 | if (!tmp || |
1378 | dwarf_decl_line(&spdie, &baseline) == 0) | 1390 | dwarf_decl_line(&indie, &baseline) != 0) |
1379 | func = tmp; | 1391 | break; |
1392 | func = tmp; | ||
1393 | spdie = indie; | ||
1380 | } | 1394 | } |
1381 | } | 1395 | } |
1396 | /* Verify the lineno and baseline are in a same file */ | ||
1397 | tmp = dwarf_decl_file(&spdie); | ||
1398 | if (!tmp || strcmp(tmp, fname) != 0) | ||
1399 | lineno = 0; | ||
1382 | } | 1400 | } |
1383 | 1401 | ||
1384 | post: | 1402 | post: |
1385 | /* Make a relative line number or an offset */ | 1403 | /* Make a relative line number or an offset */ |
1386 | if (lineno) | 1404 | if (lineno) |
1387 | ppt->line = lineno - baseline; | 1405 | ppt->line = lineno - baseline; |
1388 | else if (func) | 1406 | else if (basefunc) { |
1389 | ppt->offset = addr - (unsigned long)baseaddr; | 1407 | ppt->offset = addr - (unsigned long)baseaddr; |
1408 | func = basefunc; | ||
1409 | } | ||
1390 | 1410 | ||
1391 | /* Duplicate strings */ | 1411 | /* Duplicate strings */ |
1392 | if (func) { | 1412 | if (func) { |
@@ -1474,7 +1494,7 @@ static int line_range_inline_cb(Dwarf_Die *in_die, void *data) | |||
1474 | return 0; | 1494 | return 0; |
1475 | } | 1495 | } |
1476 | 1496 | ||
1477 | /* Search function from function name */ | 1497 | /* Search function definition from function name */ |
1478 | static int line_range_search_cb(Dwarf_Die *sp_die, void *data) | 1498 | static int line_range_search_cb(Dwarf_Die *sp_die, void *data) |
1479 | { | 1499 | { |
1480 | struct dwarf_callback_param *param = data; | 1500 | struct dwarf_callback_param *param = data; |
@@ -1485,7 +1505,7 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data) | |||
1485 | if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die))) | 1505 | if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die))) |
1486 | return DWARF_CB_OK; | 1506 | return DWARF_CB_OK; |
1487 | 1507 | ||
1488 | if (dwarf_tag(sp_die) == DW_TAG_subprogram && | 1508 | if (die_is_func_def(sp_die) && |
1489 | die_compare_name(sp_die, lr->function)) { | 1509 | die_compare_name(sp_die, lr->function)) { |
1490 | lf->fname = dwarf_decl_file(sp_die); | 1510 | lf->fname = dwarf_decl_file(sp_die); |
1491 | dwarf_decl_line(sp_die, &lr->offset); | 1511 | dwarf_decl_line(sp_die, &lr->offset); |
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index 17e94d0c36f9..3b7d63018960 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h | |||
@@ -23,6 +23,7 @@ static inline int is_c_varname(const char *name) | |||
23 | /* debug information structure */ | 23 | /* debug information structure */ |
24 | struct debuginfo { | 24 | struct debuginfo { |
25 | Dwarf *dbg; | 25 | Dwarf *dbg; |
26 | Dwfl_Module *mod; | ||
26 | Dwfl *dwfl; | 27 | Dwfl *dwfl; |
27 | Dwarf_Addr bias; | 28 | Dwarf_Addr bias; |
28 | }; | 29 | }; |
@@ -77,6 +78,7 @@ struct probe_finder { | |||
77 | 78 | ||
78 | struct trace_event_finder { | 79 | struct trace_event_finder { |
79 | struct probe_finder pf; | 80 | struct probe_finder pf; |
81 | Dwfl_Module *mod; /* For solving symbols */ | ||
80 | struct probe_trace_event *tevs; /* Found trace events */ | 82 | struct probe_trace_event *tevs; /* Found trace events */ |
81 | int ntevs; /* Number of trace events */ | 83 | int ntevs; /* Number of trace events */ |
82 | int max_tevs; /* Max number of trace events */ | 84 | int max_tevs; /* Max number of trace events */ |
@@ -84,6 +86,7 @@ struct trace_event_finder { | |||
84 | 86 | ||
85 | struct available_var_finder { | 87 | struct available_var_finder { |
86 | struct probe_finder pf; | 88 | struct probe_finder pf; |
89 | Dwfl_Module *mod; /* For solving symbols */ | ||
87 | struct variable_list *vls; /* Found variable lists */ | 90 | struct variable_list *vls; /* Found variable lists */ |
88 | int nvls; /* Number of variable lists */ | 91 | int nvls; /* Number of variable lists */ |
89 | int max_vls; /* Max no. of variable lists */ | 92 | int max_vls; /* Max no. of variable lists */ |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 51f5edf2a6d0..568b750c01f6 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -256,6 +256,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool) | |||
256 | tool->sample = process_event_sample_stub; | 256 | tool->sample = process_event_sample_stub; |
257 | if (tool->mmap == NULL) | 257 | if (tool->mmap == NULL) |
258 | tool->mmap = process_event_stub; | 258 | tool->mmap = process_event_stub; |
259 | if (tool->mmap2 == NULL) | ||
260 | tool->mmap2 = process_event_stub; | ||
259 | if (tool->comm == NULL) | 261 | if (tool->comm == NULL) |
260 | tool->comm = process_event_stub; | 262 | tool->comm = process_event_stub; |
261 | if (tool->fork == NULL) | 263 | if (tool->fork == NULL) |
@@ -531,6 +533,9 @@ static int flush_sample_queue(struct perf_session *s, | |||
531 | return 0; | 533 | return 0; |
532 | 534 | ||
533 | list_for_each_entry_safe(iter, tmp, head, list) { | 535 | list_for_each_entry_safe(iter, tmp, head, list) { |
536 | if (session_done()) | ||
537 | return 0; | ||
538 | |||
534 | if (iter->timestamp > limit) | 539 | if (iter->timestamp > limit) |
535 | break; | 540 | break; |
536 | 541 | ||
@@ -1160,7 +1165,6 @@ static void perf_session__warn_about_errors(const struct perf_session *session, | |||
1160 | } | 1165 | } |
1161 | } | 1166 | } |
1162 | 1167 | ||
1163 | #define session_done() (*(volatile int *)(&session_done)) | ||
1164 | volatile int session_done; | 1168 | volatile int session_done; |
1165 | 1169 | ||
1166 | static int __perf_session__process_pipe_events(struct perf_session *self, | 1170 | static int __perf_session__process_pipe_events(struct perf_session *self, |
@@ -1308,7 +1312,7 @@ int __perf_session__process_events(struct perf_session *session, | |||
1308 | file_offset = page_offset; | 1312 | file_offset = page_offset; |
1309 | head = data_offset - page_offset; | 1313 | head = data_offset - page_offset; |
1310 | 1314 | ||
1311 | if (data_offset + data_size < file_size) | 1315 | if (data_size && (data_offset + data_size < file_size)) |
1312 | file_size = data_offset + data_size; | 1316 | file_size = data_offset + data_size; |
1313 | 1317 | ||
1314 | progress_next = file_size / 16; | 1318 | progress_next = file_size / 16; |
@@ -1372,10 +1376,13 @@ more: | |||
1372 | "Processing events..."); | 1376 | "Processing events..."); |
1373 | } | 1377 | } |
1374 | 1378 | ||
1379 | err = 0; | ||
1380 | if (session_done()) | ||
1381 | goto out_err; | ||
1382 | |||
1375 | if (file_pos < file_size) | 1383 | if (file_pos < file_size) |
1376 | goto more; | 1384 | goto more; |
1377 | 1385 | ||
1378 | err = 0; | ||
1379 | /* do the final flush for ordered samples */ | 1386 | /* do the final flush for ordered samples */ |
1380 | session->ordered_samples.next_flush = ULLONG_MAX; | 1387 | session->ordered_samples.next_flush = ULLONG_MAX; |
1381 | err = flush_sample_queue(session, tool); | 1388 | err = flush_sample_queue(session, tool); |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 3aa75fb2225f..04bf7373a7e5 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -124,4 +124,8 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session, | |||
124 | 124 | ||
125 | #define perf_session__set_tracepoints_handlers(session, array) \ | 125 | #define perf_session__set_tracepoints_handlers(session, array) \ |
126 | __perf_session__set_tracepoints_handlers(session, array, ARRAY_SIZE(array)) | 126 | __perf_session__set_tracepoints_handlers(session, array, ARRAY_SIZE(array)) |
127 | |||
128 | extern volatile int session_done; | ||
129 | |||
130 | #define session_done() (*(volatile int *)(&session_done)) | ||
127 | #endif /* __PERF_SESSION_H */ | 131 | #endif /* __PERF_SESSION_H */ |
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index a7b9ab557380..a9c829be5216 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c | |||
@@ -8,6 +8,22 @@ | |||
8 | #include "symbol.h" | 8 | #include "symbol.h" |
9 | #include "debug.h" | 9 | #include "debug.h" |
10 | 10 | ||
11 | #ifndef HAVE_ELF_GETPHDRNUM | ||
12 | static int elf_getphdrnum(Elf *elf, size_t *dst) | ||
13 | { | ||
14 | GElf_Ehdr gehdr; | ||
15 | GElf_Ehdr *ehdr; | ||
16 | |||
17 | ehdr = gelf_getehdr(elf, &gehdr); | ||
18 | if (!ehdr) | ||
19 | return -1; | ||
20 | |||
21 | *dst = ehdr->e_phnum; | ||
22 | |||
23 | return 0; | ||
24 | } | ||
25 | #endif | ||
26 | |||
11 | #ifndef NT_GNU_BUILD_ID | 27 | #ifndef NT_GNU_BUILD_ID |
12 | #define NT_GNU_BUILD_ID 3 | 28 | #define NT_GNU_BUILD_ID 3 |
13 | #endif | 29 | #endif |
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index fe7a27d67d2b..e9e1c03f927d 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c | |||
@@ -186,7 +186,7 @@ void parse_proc_kallsyms(struct pevent *pevent, | |||
186 | char *next = NULL; | 186 | char *next = NULL; |
187 | char *addr_str; | 187 | char *addr_str; |
188 | char *mod; | 188 | char *mod; |
189 | char *fmt; | 189 | char *fmt = NULL; |
190 | 190 | ||
191 | line = strtok_r(file, "\n", &next); | 191 | line = strtok_r(file, "\n", &next); |
192 | while (line) { | 192 | while (line) { |