aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2014-01-19 07:09:01 -0500
committerIngo Molnar <mingo@kernel.org>2014-01-19 07:09:01 -0500
commit45e6af06367e7b2eb8dc49671092462d8f8a5f47 (patch)
tree68187bf0c9d8a1eb653d230dbd0d38ffd0046a27 /tools
parent3e7e09dbd1080de5dcf10092830e39bc2e2932ec (diff)
parent2a29190c040c0b11e39197c67abf6f87e0a61f9a (diff)
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf improvements and fixes from Arnaldo Carvalho de Melo: Infrastructure changes: * Improve callchain processing by removing unnecessary work. (Frederic Weisbecker) * Fix comm override error handling (Frederic Weisbecker) * Improve 'perf probe' exit path, release resources (Masami Hiramatsu) * Improve libtraceevent plugins exit path, allowing the registering of an unregister handler to be called at exit time (Namhyung Kim) * Add an alias to the build test makefile (make -C tools/perf build-test) (Namhyung Kim) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
-rw-r--r--tools/lib/traceevent/event-parse.c136
-rw-r--r--tools/lib/traceevent/event-parse.h5
-rw-r--r--tools/lib/traceevent/plugin_cfg80211.c6
-rw-r--r--tools/lib/traceevent/plugin_function.c3
-rw-r--r--tools/lib/traceevent/plugin_hrtimer.c10
-rw-r--r--tools/lib/traceevent/plugin_jbd2.c9
-rw-r--r--tools/lib/traceevent/plugin_kmem.c22
-rw-r--r--tools/lib/traceevent/plugin_kvm.c29
-rw-r--r--tools/lib/traceevent/plugin_mac80211.c7
-rw-r--r--tools/lib/traceevent/plugin_sched_switch.c12
-rw-r--r--tools/lib/traceevent/plugin_scsi.c6
-rw-r--r--tools/lib/traceevent/plugin_xen.c6
-rw-r--r--tools/perf/Makefile6
-rw-r--r--tools/perf/builtin-probe.c48
-rw-r--r--tools/perf/util/callchain.c23
-rw-r--r--tools/perf/util/comm.c19
-rw-r--r--tools/perf/util/comm.h2
-rw-r--r--tools/perf/util/probe-event.c111
-rw-r--r--tools/perf/util/probe-event.h6
-rw-r--r--tools/perf/util/symbol-elf.c5
-rw-r--r--tools/perf/util/symbol.h5
-rw-r--r--tools/perf/util/thread.c5
-rw-r--r--tools/perf/util/unwind.c20
23 files changed, 389 insertions, 112 deletions
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c
index 2ce565a73dd5..1587ea392ad6 100644
--- a/tools/lib/traceevent/event-parse.c
+++ b/tools/lib/traceevent/event-parse.c
@@ -5561,6 +5561,52 @@ int pevent_register_print_function(struct pevent *pevent,
5561} 5561}
5562 5562
5563/** 5563/**
5564 * pevent_unregister_print_function - unregister a helper function
5565 * @pevent: the handle to the pevent
5566 * @func: the function to process the helper function
5567 * @name: the name of the helper function
5568 *
5569 * This function removes existing print handler for function @name.
5570 *
5571 * Returns 0 if the handler was removed successully, -1 otherwise.
5572 */
5573int pevent_unregister_print_function(struct pevent *pevent,
5574 pevent_func_handler func, char *name)
5575{
5576 struct pevent_function_handler *func_handle;
5577
5578 func_handle = find_func_handler(pevent, name);
5579 if (func_handle && func_handle->func == func) {
5580 remove_func_handler(pevent, name);
5581 return 0;
5582 }
5583 return -1;
5584}
5585
5586static struct event_format *pevent_search_event(struct pevent *pevent, int id,
5587 const char *sys_name,
5588 const char *event_name)
5589{
5590 struct event_format *event;
5591
5592 if (id >= 0) {
5593 /* search by id */
5594 event = pevent_find_event(pevent, id);
5595 if (!event)
5596 return NULL;
5597 if (event_name && (strcmp(event_name, event->name) != 0))
5598 return NULL;
5599 if (sys_name && (strcmp(sys_name, event->system) != 0))
5600 return NULL;
5601 } else {
5602 event = pevent_find_event_by_name(pevent, sys_name, event_name);
5603 if (!event)
5604 return NULL;
5605 }
5606 return event;
5607}
5608
5609/**
5564 * pevent_register_event_handler - register a way to parse an event 5610 * pevent_register_event_handler - register a way to parse an event
5565 * @pevent: the handle to the pevent 5611 * @pevent: the handle to the pevent
5566 * @id: the id of the event to register 5612 * @id: the id of the event to register
@@ -5584,20 +5630,9 @@ int pevent_register_event_handler(struct pevent *pevent, int id,
5584 struct event_format *event; 5630 struct event_format *event;
5585 struct event_handler *handle; 5631 struct event_handler *handle;
5586 5632
5587 if (id >= 0) { 5633 event = pevent_search_event(pevent, id, sys_name, event_name);
5588 /* search by id */ 5634 if (event == NULL)
5589 event = pevent_find_event(pevent, id); 5635 goto not_found;
5590 if (!event)
5591 goto not_found;
5592 if (event_name && (strcmp(event_name, event->name) != 0))
5593 goto not_found;
5594 if (sys_name && (strcmp(sys_name, event->system) != 0))
5595 goto not_found;
5596 } else {
5597 event = pevent_find_event_by_name(pevent, sys_name, event_name);
5598 if (!event)
5599 goto not_found;
5600 }
5601 5636
5602 pr_stat("overriding event (%d) %s:%s with new print handler", 5637 pr_stat("overriding event (%d) %s:%s with new print handler",
5603 event->id, event->system, event->name); 5638 event->id, event->system, event->name);
@@ -5637,6 +5672,79 @@ int pevent_register_event_handler(struct pevent *pevent, int id,
5637 return -1; 5672 return -1;
5638} 5673}
5639 5674
5675static int handle_matches(struct event_handler *handler, int id,
5676 const char *sys_name, const char *event_name,
5677 pevent_event_handler_func func, void *context)
5678{
5679 if (id >= 0 && id != handler->id)
5680 return 0;
5681
5682 if (event_name && (strcmp(event_name, handler->event_name) != 0))
5683 return 0;
5684
5685 if (sys_name && (strcmp(sys_name, handler->sys_name) != 0))
5686 return 0;
5687
5688 if (func != handler->func || context != handler->context)
5689 return 0;
5690
5691 return 1;
5692}
5693
5694/**
5695 * pevent_unregister_event_handler - unregister an existing event handler
5696 * @pevent: the handle to the pevent
5697 * @id: the id of the event to unregister
5698 * @sys_name: the system name the handler belongs to
5699 * @event_name: the name of the event handler
5700 * @func: the function to call to parse the event information
5701 * @context: the data to be passed to @func
5702 *
5703 * This function removes existing event handler (parser).
5704 *
5705 * If @id is >= 0, then it is used to find the event.
5706 * else @sys_name and @event_name are used.
5707 *
5708 * Returns 0 if handler was removed successfully, -1 if event was not found.
5709 */
5710int pevent_unregister_event_handler(struct pevent *pevent, int id,
5711 const char *sys_name, const char *event_name,
5712 pevent_event_handler_func func, void *context)
5713{
5714 struct event_format *event;
5715 struct event_handler *handle;
5716 struct event_handler **next;
5717
5718 event = pevent_search_event(pevent, id, sys_name, event_name);
5719 if (event == NULL)
5720 goto not_found;
5721
5722 if (event->handler == func && event->context == context) {
5723 pr_stat("removing override handler for event (%d) %s:%s. Going back to default handler.",
5724 event->id, event->system, event->name);
5725
5726 event->handler = NULL;
5727 event->context = NULL;
5728 return 0;
5729 }
5730
5731not_found:
5732 for (next = &pevent->handlers; *next; next = &(*next)->next) {
5733 handle = *next;
5734 if (handle_matches(handle, id, sys_name, event_name,
5735 func, context))
5736 break;
5737 }
5738
5739 if (!(*next))
5740 return -1;
5741
5742 *next = handle->next;
5743 free_handler(handle);
5744
5745 return 0;
5746}
5747
5640/** 5748/**
5641 * pevent_alloc - create a pevent handle 5749 * pevent_alloc - create a pevent handle
5642 */ 5750 */
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h
index a3beca56cb35..791c539374c7 100644
--- a/tools/lib/traceevent/event-parse.h
+++ b/tools/lib/traceevent/event-parse.h
@@ -624,10 +624,15 @@ int pevent_print_func_field(struct trace_seq *s, const char *fmt,
624int pevent_register_event_handler(struct pevent *pevent, int id, 624int pevent_register_event_handler(struct pevent *pevent, int id,
625 const char *sys_name, const char *event_name, 625 const char *sys_name, const char *event_name,
626 pevent_event_handler_func func, void *context); 626 pevent_event_handler_func func, void *context);
627int pevent_unregister_event_handler(struct pevent *pevent, int id,
628 const char *sys_name, const char *event_name,
629 pevent_event_handler_func func, void *context);
627int pevent_register_print_function(struct pevent *pevent, 630int pevent_register_print_function(struct pevent *pevent,
628 pevent_func_handler func, 631 pevent_func_handler func,
629 enum pevent_func_arg_type ret_type, 632 enum pevent_func_arg_type ret_type,
630 char *name, ...); 633 char *name, ...);
634int pevent_unregister_print_function(struct pevent *pevent,
635 pevent_func_handler func, char *name);
631 636
632struct format_field *pevent_find_common_field(struct event_format *event, const char *name); 637struct format_field *pevent_find_common_field(struct event_format *event, const char *name);
633struct format_field *pevent_find_field(struct event_format *event, const char *name); 638struct format_field *pevent_find_field(struct event_format *event, const char *name);
diff --git a/tools/lib/traceevent/plugin_cfg80211.c b/tools/lib/traceevent/plugin_cfg80211.c
index 57e98221db20..c066b25905f8 100644
--- a/tools/lib/traceevent/plugin_cfg80211.c
+++ b/tools/lib/traceevent/plugin_cfg80211.c
@@ -22,3 +22,9 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
22 PEVENT_FUNC_ARG_VOID); 22 PEVENT_FUNC_ARG_VOID);
23 return 0; 23 return 0;
24} 24}
25
26void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
27{
28 pevent_unregister_print_function(pevent, process___le16_to_cpup,
29 "__le16_to_cpup");
30}
diff --git a/tools/lib/traceevent/plugin_function.c b/tools/lib/traceevent/plugin_function.c
index 39461485f9a7..80ba4ff1fe84 100644
--- a/tools/lib/traceevent/plugin_function.c
+++ b/tools/lib/traceevent/plugin_function.c
@@ -148,6 +148,9 @@ void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
148{ 148{
149 int i, x; 149 int i, x;
150 150
151 pevent_unregister_event_handler(pevent, -1, "ftrace", "function",
152 function_handler, NULL);
153
151 for (i = 0; i <= cpus; i++) { 154 for (i = 0; i <= cpus; i++) {
152 for (x = 0; x < fstack[i].size && fstack[i].stack[x]; x++) 155 for (x = 0; x < fstack[i].size && fstack[i].stack[x]; x++)
153 free(fstack[i].stack[x]); 156 free(fstack[i].stack[x]);
diff --git a/tools/lib/traceevent/plugin_hrtimer.c b/tools/lib/traceevent/plugin_hrtimer.c
index 0b0ebf30aa44..12bf14cc1152 100644
--- a/tools/lib/traceevent/plugin_hrtimer.c
+++ b/tools/lib/traceevent/plugin_hrtimer.c
@@ -76,3 +76,13 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
76 timer_start_handler, NULL); 76 timer_start_handler, NULL);
77 return 0; 77 return 0;
78} 78}
79
80void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
81{
82 pevent_unregister_event_handler(pevent, -1,
83 "timer", "hrtimer_expire_entry",
84 timer_expire_handler, NULL);
85
86 pevent_unregister_event_handler(pevent, -1, "timer", "hrtimer_start",
87 timer_start_handler, NULL);
88}
diff --git a/tools/lib/traceevent/plugin_jbd2.c b/tools/lib/traceevent/plugin_jbd2.c
index 2f93f81f0bac..0db714c721be 100644
--- a/tools/lib/traceevent/plugin_jbd2.c
+++ b/tools/lib/traceevent/plugin_jbd2.c
@@ -66,3 +66,12 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
66 PEVENT_FUNC_ARG_VOID); 66 PEVENT_FUNC_ARG_VOID);
67 return 0; 67 return 0;
68} 68}
69
70void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
71{
72 pevent_unregister_print_function(pevent, process_jbd2_dev_to_name,
73 "jbd2_dev_to_name");
74
75 pevent_unregister_print_function(pevent, process_jiffies_to_msecs,
76 "jiffies_to_msecs");
77}
diff --git a/tools/lib/traceevent/plugin_kmem.c b/tools/lib/traceevent/plugin_kmem.c
index 7115c8037ea8..70650ff48d78 100644
--- a/tools/lib/traceevent/plugin_kmem.c
+++ b/tools/lib/traceevent/plugin_kmem.c
@@ -70,3 +70,25 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
70 call_site_handler, NULL); 70 call_site_handler, NULL);
71 return 0; 71 return 0;
72} 72}
73
74void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
75{
76 pevent_unregister_event_handler(pevent, -1, "kmem", "kfree",
77 call_site_handler, NULL);
78
79 pevent_unregister_event_handler(pevent, -1, "kmem", "kmalloc",
80 call_site_handler, NULL);
81
82 pevent_unregister_event_handler(pevent, -1, "kmem", "kmalloc_node",
83 call_site_handler, NULL);
84
85 pevent_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_alloc",
86 call_site_handler, NULL);
87
88 pevent_unregister_event_handler(pevent, -1, "kmem",
89 "kmem_cache_alloc_node",
90 call_site_handler, NULL);
91
92 pevent_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_free",
93 call_site_handler, NULL);
94}
diff --git a/tools/lib/traceevent/plugin_kvm.c b/tools/lib/traceevent/plugin_kvm.c
index a0e282c6b967..9e0e8c61b43b 100644
--- a/tools/lib/traceevent/plugin_kvm.c
+++ b/tools/lib/traceevent/plugin_kvm.c
@@ -434,3 +434,32 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
434 PEVENT_FUNC_ARG_VOID); 434 PEVENT_FUNC_ARG_VOID);
435 return 0; 435 return 0;
436} 436}
437
438void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
439{
440 pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_exit",
441 kvm_exit_handler, NULL);
442
443 pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_emulate_insn",
444 kvm_emulate_insn_handler, NULL);
445
446 pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page",
447 kvm_mmu_get_page_handler, NULL);
448
449 pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page",
450 kvm_mmu_print_role, NULL);
451
452 pevent_unregister_event_handler(pevent, -1,
453 "kvmmmu", "kvm_mmu_unsync_page",
454 kvm_mmu_print_role, NULL);
455
456 pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page",
457 kvm_mmu_print_role, NULL);
458
459 pevent_unregister_event_handler(pevent, -1, "kvmmmu",
460 "kvm_mmu_prepare_zap_page", kvm_mmu_print_role,
461 NULL);
462
463 pevent_unregister_print_function(pevent, process_is_writable_pte,
464 "is_writable_pte");
465}
diff --git a/tools/lib/traceevent/plugin_mac80211.c b/tools/lib/traceevent/plugin_mac80211.c
index 558a3b91c046..7e15a0f1c2fd 100644
--- a/tools/lib/traceevent/plugin_mac80211.c
+++ b/tools/lib/traceevent/plugin_mac80211.c
@@ -93,3 +93,10 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
93 drv_bss_info_changed, NULL); 93 drv_bss_info_changed, NULL);
94 return 0; 94 return 0;
95} 95}
96
97void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
98{
99 pevent_unregister_event_handler(pevent, -1, "mac80211",
100 "drv_bss_info_changed",
101 drv_bss_info_changed, NULL);
102}
diff --git a/tools/lib/traceevent/plugin_sched_switch.c b/tools/lib/traceevent/plugin_sched_switch.c
index fea3724aa24f..f1ce60065258 100644
--- a/tools/lib/traceevent/plugin_sched_switch.c
+++ b/tools/lib/traceevent/plugin_sched_switch.c
@@ -146,3 +146,15 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
146 sched_wakeup_handler, NULL); 146 sched_wakeup_handler, NULL);
147 return 0; 147 return 0;
148} 148}
149
150void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
151{
152 pevent_unregister_event_handler(pevent, -1, "sched", "sched_switch",
153 sched_switch_handler, NULL);
154
155 pevent_unregister_event_handler(pevent, -1, "sched", "sched_wakeup",
156 sched_wakeup_handler, NULL);
157
158 pevent_unregister_event_handler(pevent, -1, "sched", "sched_wakeup_new",
159 sched_wakeup_handler, NULL);
160}
diff --git a/tools/lib/traceevent/plugin_scsi.c b/tools/lib/traceevent/plugin_scsi.c
index 7ef16cc96562..eda326fc8620 100644
--- a/tools/lib/traceevent/plugin_scsi.c
+++ b/tools/lib/traceevent/plugin_scsi.c
@@ -421,3 +421,9 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
421 PEVENT_FUNC_ARG_VOID); 421 PEVENT_FUNC_ARG_VOID);
422 return 0; 422 return 0;
423} 423}
424
425void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
426{
427 pevent_unregister_print_function(pevent, process_scsi_trace_parse_cdb,
428 "scsi_trace_parse_cdb");
429}
diff --git a/tools/lib/traceevent/plugin_xen.c b/tools/lib/traceevent/plugin_xen.c
index e7794298f3a9..3a413eaada68 100644
--- a/tools/lib/traceevent/plugin_xen.c
+++ b/tools/lib/traceevent/plugin_xen.c
@@ -128,3 +128,9 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
128 PEVENT_FUNC_ARG_VOID); 128 PEVENT_FUNC_ARG_VOID);
129 return 0; 129 return 0;
130} 130}
131
132void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
133{
134 pevent_unregister_print_function(pevent, process_xen_hypercall_name,
135 "xen_hypercall_name");
136}
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index eefb9fb0c02f..cb2e5868c8e8 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -75,6 +75,12 @@ clean:
75 $(make) 75 $(make)
76 76
77# 77#
78# The build-test target is not really parallel, don't print the jobs info:
79#
80build-test:
81 @$(MAKE) -f tests/make --no-print-directory
82
83#
78# All other targets get passed through: 84# All other targets get passed through:
79# 85#
80%: 86%:
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 43ff33d0007b..78948882e3de 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -59,7 +59,7 @@ static struct {
59 struct perf_probe_event events[MAX_PROBES]; 59 struct perf_probe_event events[MAX_PROBES];
60 struct strlist *dellist; 60 struct strlist *dellist;
61 struct line_range line_range; 61 struct line_range line_range;
62 const char *target; 62 char *target;
63 int max_probe_points; 63 int max_probe_points;
64 struct strfilter *filter; 64 struct strfilter *filter;
65} params; 65} params;
@@ -98,7 +98,10 @@ static int set_target(const char *ptr)
98 * short module name. 98 * short module name.
99 */ 99 */
100 if (!params.target && ptr && *ptr == '/') { 100 if (!params.target && ptr && *ptr == '/') {
101 params.target = ptr; 101 params.target = strdup(ptr);
102 if (!params.target)
103 return -ENOMEM;
104
102 found = 1; 105 found = 1;
103 buf = ptr + (strlen(ptr) - 3); 106 buf = ptr + (strlen(ptr) - 3);
104 107
@@ -116,6 +119,9 @@ static int parse_probe_event_argv(int argc, const char **argv)
116 char *buf; 119 char *buf;
117 120
118 found_target = set_target(argv[0]); 121 found_target = set_target(argv[0]);
122 if (found_target < 0)
123 return found_target;
124
119 if (found_target && argc == 1) 125 if (found_target && argc == 1)
120 return 0; 126 return 0;
121 127
@@ -217,7 +223,6 @@ static int opt_show_lines(const struct option *opt __maybe_unused,
217 223
218 params.show_lines = true; 224 params.show_lines = true;
219 ret = parse_line_range_desc(str, &params.line_range); 225 ret = parse_line_range_desc(str, &params.line_range);
220 INIT_LIST_HEAD(&params.line_range.line_list);
221 226
222 return ret; 227 return ret;
223} 228}
@@ -263,7 +268,28 @@ static int opt_set_filter(const struct option *opt __maybe_unused,
263 return 0; 268 return 0;
264} 269}
265 270
266int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) 271static void init_params(void)
272{
273 line_range__init(&params.line_range);
274}
275
276static void cleanup_params(void)
277{
278 int i;
279
280 for (i = 0; i < params.nevents; i++)
281 clear_perf_probe_event(params.events + i);
282 if (params.dellist)
283 strlist__delete(params.dellist);
284 line_range__clear(&params.line_range);
285 free(params.target);
286 if (params.filter)
287 strfilter__delete(params.filter);
288 memset(&params, 0, sizeof(params));
289}
290
291static int
292__cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
267{ 293{
268 const char * const probe_usage[] = { 294 const char * const probe_usage[] = {
269 "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", 295 "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
@@ -417,6 +443,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
417 ret = show_available_funcs(params.target, params.filter, 443 ret = show_available_funcs(params.target, params.filter,
418 params.uprobes); 444 params.uprobes);
419 strfilter__delete(params.filter); 445 strfilter__delete(params.filter);
446 params.filter = NULL;
420 if (ret < 0) 447 if (ret < 0)
421 pr_err(" Error: Failed to show functions." 448 pr_err(" Error: Failed to show functions."
422 " (%d)\n", ret); 449 " (%d)\n", ret);
@@ -456,6 +483,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
456 params.filter, 483 params.filter,
457 params.show_ext_vars); 484 params.show_ext_vars);
458 strfilter__delete(params.filter); 485 strfilter__delete(params.filter);
486 params.filter = NULL;
459 if (ret < 0) 487 if (ret < 0)
460 pr_err(" Error: Failed to show vars. (%d)\n", ret); 488 pr_err(" Error: Failed to show vars. (%d)\n", ret);
461 return ret; 489 return ret;
@@ -464,7 +492,6 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
464 492
465 if (params.dellist) { 493 if (params.dellist) {
466 ret = del_perf_probe_events(params.dellist); 494 ret = del_perf_probe_events(params.dellist);
467 strlist__delete(params.dellist);
468 if (ret < 0) { 495 if (ret < 0) {
469 pr_err(" Error: Failed to delete events. (%d)\n", ret); 496 pr_err(" Error: Failed to delete events. (%d)\n", ret);
470 return ret; 497 return ret;
@@ -483,3 +510,14 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
483 } 510 }
484 return 0; 511 return 0;
485} 512}
513
514int cmd_probe(int argc, const char **argv, const char *prefix)
515{
516 int ret;
517
518 init_params();
519 ret = __cmd_probe(argc, argv, prefix);
520 cleanup_params();
521
522 return ret;
523}
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 9eb4f57f8663..8d9db454f1a9 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -15,6 +15,8 @@
15#include <errno.h> 15#include <errno.h>
16#include <math.h> 16#include <math.h>
17 17
18#include "asm/bug.h"
19
18#include "hist.h" 20#include "hist.h"
19#include "util.h" 21#include "util.h"
20#include "sort.h" 22#include "sort.h"
@@ -358,19 +360,14 @@ append_chain_children(struct callchain_node *root,
358 /* lookup in childrens */ 360 /* lookup in childrens */
359 while (*p) { 361 while (*p) {
360 s64 ret; 362 s64 ret;
361 struct callchain_list *cnode;
362 363
363 parent = *p; 364 parent = *p;
364 rnode = rb_entry(parent, struct callchain_node, rb_node_in); 365 rnode = rb_entry(parent, struct callchain_node, rb_node_in);
365 cnode = list_first_entry(&rnode->val, struct callchain_list,
366 list);
367 366
368 /* just check first entry */ 367 /* If at least first entry matches, rely to children */
369 ret = match_chain(node, cnode); 368 ret = append_chain(rnode, cursor, period);
370 if (ret == 0) { 369 if (ret == 0)
371 append_chain(rnode, cursor, period);
372 goto inc_children_hit; 370 goto inc_children_hit;
373 }
374 371
375 if (ret < 0) 372 if (ret < 0)
376 p = &parent->rb_left; 373 p = &parent->rb_left;
@@ -391,11 +388,11 @@ append_chain(struct callchain_node *root,
391 struct callchain_cursor *cursor, 388 struct callchain_cursor *cursor,
392 u64 period) 389 u64 period)
393{ 390{
394 struct callchain_cursor_node *curr_snap = cursor->curr;
395 struct callchain_list *cnode; 391 struct callchain_list *cnode;
396 u64 start = cursor->pos; 392 u64 start = cursor->pos;
397 bool found = false; 393 bool found = false;
398 u64 matches; 394 u64 matches;
395 int cmp = 0;
399 396
400 /* 397 /*
401 * Lookup in the current node 398 * Lookup in the current node
@@ -410,7 +407,8 @@ append_chain(struct callchain_node *root,
410 if (!node) 407 if (!node)
411 break; 408 break;
412 409
413 if (match_chain(node, cnode) != 0) 410 cmp = match_chain(node, cnode);
411 if (cmp)
414 break; 412 break;
415 413
416 found = true; 414 found = true;
@@ -420,9 +418,8 @@ append_chain(struct callchain_node *root,
420 418
421 /* matches not, relay no the parent */ 419 /* matches not, relay no the parent */
422 if (!found) { 420 if (!found) {
423 cursor->curr = curr_snap; 421 WARN_ONCE(!cmp, "Chain comparison error\n");
424 cursor->pos = start; 422 return cmp;
425 return -1;
426 } 423 }
427 424
428 matches = cursor->pos - start; 425 matches = cursor->pos - start;
diff --git a/tools/perf/util/comm.c b/tools/perf/util/comm.c
index 67d1e404c0cb..f9e777629e21 100644
--- a/tools/perf/util/comm.c
+++ b/tools/perf/util/comm.c
@@ -94,19 +94,20 @@ struct comm *comm__new(const char *str, u64 timestamp)
94 return comm; 94 return comm;
95} 95}
96 96
97void comm__override(struct comm *comm, const char *str, u64 timestamp) 97int comm__override(struct comm *comm, const char *str, u64 timestamp)
98{ 98{
99 struct comm_str *old = comm->comm_str; 99 struct comm_str *new, *old = comm->comm_str;
100 100
101 comm->comm_str = comm_str__findnew(str, &comm_str_root); 101 new = comm_str__findnew(str, &comm_str_root);
102 if (!comm->comm_str) { 102 if (!new)
103 comm->comm_str = old; 103 return -ENOMEM;
104 return;
105 }
106 104
107 comm->start = timestamp; 105 comm_str__get(new);
108 comm_str__get(comm->comm_str);
109 comm_str__put(old); 106 comm_str__put(old);
107 comm->comm_str = new;
108 comm->start = timestamp;
109
110 return 0;
110} 111}
111 112
112void comm__free(struct comm *comm) 113void comm__free(struct comm *comm)
diff --git a/tools/perf/util/comm.h b/tools/perf/util/comm.h
index 7a86e5656710..fac5bd51befc 100644
--- a/tools/perf/util/comm.h
+++ b/tools/perf/util/comm.h
@@ -16,6 +16,6 @@ struct comm {
16void comm__free(struct comm *comm); 16void comm__free(struct comm *comm);
17struct comm *comm__new(const char *str, u64 timestamp); 17struct comm *comm__new(const char *str, u64 timestamp);
18const char *comm__str(const struct comm *comm); 18const char *comm__str(const struct comm *comm);
19void comm__override(struct comm *comm, const char *str, u64 timestamp); 19int comm__override(struct comm *comm, const char *str, u64 timestamp);
20 20
21#endif /* __PERF_COMM_H */ 21#endif /* __PERF_COMM_H */
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index a4ee6b4a840f..a8a9b6cd93a8 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -72,6 +72,7 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
72static char *synthesize_perf_probe_point(struct perf_probe_point *pp); 72static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
73static int convert_name_to_addr(struct perf_probe_event *pev, 73static int convert_name_to_addr(struct perf_probe_event *pev,
74 const char *exec); 74 const char *exec);
75static void clear_probe_trace_event(struct probe_trace_event *tev);
75static struct machine machine; 76static struct machine machine;
76 77
77/* Initialize symbol maps and path of vmlinux/modules */ 78/* Initialize symbol maps and path of vmlinux/modules */
@@ -172,54 +173,6 @@ const char *kernel_get_module_path(const char *module)
172 return (dso) ? dso->long_name : NULL; 173 return (dso) ? dso->long_name : NULL;
173} 174}
174 175
175#ifdef HAVE_DWARF_SUPPORT
176/* Copied from unwind.c */
177static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
178 GElf_Shdr *shp, const char *name)
179{
180 Elf_Scn *sec = NULL;
181
182 while ((sec = elf_nextscn(elf, sec)) != NULL) {
183 char *str;
184
185 gelf_getshdr(sec, shp);
186 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
187 if (!strcmp(name, str))
188 break;
189 }
190
191 return sec;
192}
193
194static int get_text_start_address(const char *exec, unsigned long *address)
195{
196 Elf *elf;
197 GElf_Ehdr ehdr;
198 GElf_Shdr shdr;
199 int fd, ret = -ENOENT;
200
201 fd = open(exec, O_RDONLY);
202 if (fd < 0)
203 return -errno;
204
205 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
206 if (elf == NULL)
207 return -EINVAL;
208
209 if (gelf_getehdr(elf, &ehdr) == NULL)
210 goto out;
211
212 if (!elf_section_by_name(elf, &ehdr, &shdr, ".text"))
213 goto out;
214
215 *address = shdr.sh_addr - shdr.sh_offset;
216 ret = 0;
217out:
218 elf_end(elf);
219 return ret;
220}
221#endif
222
223static int init_user_exec(void) 176static int init_user_exec(void)
224{ 177{
225 int ret = 0; 178 int ret = 0;
@@ -340,6 +293,34 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
340 return 0; 293 return 0;
341} 294}
342 295
296static int get_text_start_address(const char *exec, unsigned long *address)
297{
298 Elf *elf;
299 GElf_Ehdr ehdr;
300 GElf_Shdr shdr;
301 int fd, ret = -ENOENT;
302
303 fd = open(exec, O_RDONLY);
304 if (fd < 0)
305 return -errno;
306
307 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
308 if (elf == NULL)
309 return -EINVAL;
310
311 if (gelf_getehdr(elf, &ehdr) == NULL)
312 goto out;
313
314 if (!elf_section_by_name(elf, &ehdr, &shdr, ".text", NULL))
315 goto out;
316
317 *address = shdr.sh_addr - shdr.sh_offset;
318 ret = 0;
319out:
320 elf_end(elf);
321 return ret;
322}
323
343static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, 324static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
344 int ntevs, const char *exec) 325 int ntevs, const char *exec)
345{ 326{
@@ -407,6 +388,14 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
407 return ret; 388 return ret;
408} 389}
409 390
391static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
392{
393 int i;
394
395 for (i = 0; i < ntevs; i++)
396 clear_probe_trace_event(tevs + i);
397}
398
410/* Try to find perf_probe_event with debuginfo */ 399/* Try to find perf_probe_event with debuginfo */
411static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 400static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
412 struct probe_trace_event **tevs, 401 struct probe_trace_event **tevs,
@@ -442,6 +431,10 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
442 ret = add_module_to_probe_trace_events(*tevs, 431 ret = add_module_to_probe_trace_events(*tevs,
443 ntevs, target); 432 ntevs, target);
444 } 433 }
434 if (ret < 0) {
435 clear_probe_trace_events(*tevs, ntevs);
436 zfree(tevs);
437 }
445 return ret < 0 ? ret : ntevs; 438 return ret < 0 ? ret : ntevs;
446 } 439 }
447 440
@@ -781,6 +774,28 @@ int show_available_vars(struct perf_probe_event *pevs __maybe_unused,
781} 774}
782#endif 775#endif
783 776
777void line_range__clear(struct line_range *lr)
778{
779 struct line_node *ln;
780
781 free(lr->function);
782 free(lr->file);
783 free(lr->path);
784 free(lr->comp_dir);
785 while (!list_empty(&lr->line_list)) {
786 ln = list_first_entry(&lr->line_list, struct line_node, list);
787 list_del(&ln->list);
788 free(ln);
789 }
790 memset(lr, 0, sizeof(*lr));
791}
792
793void line_range__init(struct line_range *lr)
794{
795 memset(lr, 0, sizeof(*lr));
796 INIT_LIST_HEAD(&lr->line_list);
797}
798
784static int parse_line_num(char **ptr, int *val, const char *what) 799static int parse_line_num(char **ptr, int *val, const char *what)
785{ 800{
786 const char *start = *ptr; 801 const char *start = *ptr;
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index d481c46e0796..fcaf7273e85a 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -120,6 +120,12 @@ extern void clear_perf_probe_event(struct perf_probe_event *pev);
120/* Command string to line-range */ 120/* Command string to line-range */
121extern int parse_line_range_desc(const char *cmd, struct line_range *lr); 121extern int parse_line_range_desc(const char *cmd, struct line_range *lr);
122 122
123/* Release line range members */
124extern void line_range__clear(struct line_range *lr);
125
126/* Initialize line range */
127extern void line_range__init(struct line_range *lr);
128
123/* Internal use: Return kernel/module path */ 129/* Internal use: Return kernel/module path */
124extern const char *kernel_get_module_path(const char *module); 130extern const char *kernel_get_module_path(const char *module);
125 131
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 4b0a127a4d3b..759456728703 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -136,9 +136,8 @@ static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
136 return -1; 136 return -1;
137} 137}
138 138
139static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 139Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
140 GElf_Shdr *shp, const char *name, 140 GElf_Shdr *shp, const char *name, size_t *idx)
141 size_t *idx)
142{ 141{
143 Elf_Scn *sec = NULL; 142 Elf_Scn *sec = NULL;
144 size_t cnt = 1; 143 size_t cnt = 1;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index cbd680361806..fffe2888a1c7 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -52,6 +52,11 @@ static inline char *bfd_demangle(void __maybe_unused *v,
52# define PERF_ELF_C_READ_MMAP ELF_C_READ 52# define PERF_ELF_C_READ_MMAP ELF_C_READ
53#endif 53#endif
54 54
55#ifdef HAVE_LIBELF_SUPPORT
56extern Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
57 GElf_Shdr *shp, const char *name, size_t *idx);
58#endif
59
55#ifndef DMGL_PARAMS 60#ifndef DMGL_PARAMS
56#define DMGL_PARAMS (1 << 0) /* Include function args */ 61#define DMGL_PARAMS (1 << 0) /* Include function args */
57#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ 62#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index e3948612543e..0358882c8910 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -66,10 +66,13 @@ struct comm *thread__comm(const struct thread *thread)
66int thread__set_comm(struct thread *thread, const char *str, u64 timestamp) 66int thread__set_comm(struct thread *thread, const char *str, u64 timestamp)
67{ 67{
68 struct comm *new, *curr = thread__comm(thread); 68 struct comm *new, *curr = thread__comm(thread);
69 int err;
69 70
70 /* Override latest entry if it had no specific time coverage */ 71 /* Override latest entry if it had no specific time coverage */
71 if (!curr->start) { 72 if (!curr->start) {
72 comm__override(curr, str, timestamp); 73 err = comm__override(curr, str, timestamp);
74 if (err)
75 return err;
73 } else { 76 } else {
74 new = comm__new(str, timestamp); 77 new = comm__new(str, timestamp);
75 if (!new) 78 if (!new)
diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c
index 416f22bf3693..742f23bf35ff 100644
--- a/tools/perf/util/unwind.c
+++ b/tools/perf/util/unwind.c
@@ -28,6 +28,7 @@
28#include "session.h" 28#include "session.h"
29#include "perf_regs.h" 29#include "perf_regs.h"
30#include "unwind.h" 30#include "unwind.h"
31#include "symbol.h"
31#include "util.h" 32#include "util.h"
32 33
33extern int 34extern int
@@ -158,23 +159,6 @@ static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val,
158 __v; \ 159 __v; \
159 }) 160 })
160 161
161static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
162 GElf_Shdr *shp, const char *name)
163{
164 Elf_Scn *sec = NULL;
165
166 while ((sec = elf_nextscn(elf, sec)) != NULL) {
167 char *str;
168
169 gelf_getshdr(sec, shp);
170 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
171 if (!strcmp(name, str))
172 break;
173 }
174
175 return sec;
176}
177
178static u64 elf_section_offset(int fd, const char *name) 162static u64 elf_section_offset(int fd, const char *name)
179{ 163{
180 Elf *elf; 164 Elf *elf;
@@ -190,7 +174,7 @@ static u64 elf_section_offset(int fd, const char *name)
190 if (gelf_getehdr(elf, &ehdr) == NULL) 174 if (gelf_getehdr(elf, &ehdr) == NULL)
191 break; 175 break;
192 176
193 if (!elf_section_by_name(elf, &ehdr, &shdr, name)) 177 if (!elf_section_by_name(elf, &ehdr, &shdr, name, NULL))
194 break; 178 break;
195 179
196 offset = shdr.sh_offset; 180 offset = shdr.sh_offset;