aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2017-01-26 10:20:59 -0500
committerIngo Molnar <mingo@kernel.org>2017-01-26 10:20:59 -0500
commite2cf00c257f5bbc071b489b1dfbeaa30b6f12da6 (patch)
treeaa1af0d0f4bbbdd9d706574478fec568895f817b /tools/perf
parent47cd95a6326888a46e7ce8389cd394a3e1c647e7 (diff)
parentec347870a9d423a4b88657d6a85b5163b3f949ee (diff)
Merge tag 'perf-core-for-mingo-4.11-20170126' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull the latest perf/core updates from Arnaldo Carvalho de Melo: New features: - Introduce 'perf ftrace' a perf front end to the kernel's ftrace function and function_graph tracer, defaulting to the "function_graph" tracer, more work will be done in reviving this effort, forward porting it from its initial patch submission (Namhyung Kim) - Add 'e' and 'c' hotkeys to expand/collapse call chains for a single hist entry in the 'perf report' and 'perf top' TUI (Jiri Olsa) Fixes: - Fix wrong register name for arm64, used in 'perf probe' (He Kuang) - Fix map offsets in relocation in libbpf (Joe Stringer) - Fix looking up dwarf unwind stack info (Matija Glavinic Pecotic) Infrastructure changes: - libbpf prog functions sync with what is exported via uapi (Joe Stringer) Trivial changes: - Remove unnecessary checks and assignments in 'perf probe's try_to_find_absolute_address() (Markus Elfring) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Build1
-rw-r--r--tools/perf/Documentation/perf-c2c.txt2
-rw-r--r--tools/perf/Documentation/perf-ftrace.txt36
-rw-r--r--tools/perf/arch/arm64/include/dwarf-regs-table.h12
-rw-r--r--tools/perf/builtin-c2c.c3
-rw-r--r--tools/perf/builtin-ftrace.c243
-rw-r--r--tools/perf/builtin.h1
-rw-r--r--tools/perf/command-list.txt1
-rw-r--r--tools/perf/perf.c1
-rw-r--r--tools/perf/tests/llvm.c2
-rw-r--r--tools/perf/ui/browsers/hists.c60
-rw-r--r--tools/perf/util/dso.c48
-rw-r--r--tools/perf/util/header.c4
-rw-r--r--tools/perf/util/probe-event.c11
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c6
-rw-r--r--tools/perf/util/trace-event-info.c33
-rw-r--r--tools/perf/util/trace-event-parse.c17
-rw-r--r--tools/perf/util/trace-event-read.c77
-rw-r--r--tools/perf/util/trace-event.h1
-rw-r--r--tools/perf/util/unwind-libunwind-local.c54
20 files changed, 546 insertions, 67 deletions
diff --git a/tools/perf/Build b/tools/perf/Build
index 7039ecb89170..9b79f8d7db50 100644
--- a/tools/perf/Build
+++ b/tools/perf/Build
@@ -3,6 +3,7 @@ perf-y += builtin-annotate.o
3perf-y += builtin-config.o 3perf-y += builtin-config.o
4perf-y += builtin-diff.o 4perf-y += builtin-diff.o
5perf-y += builtin-evlist.o 5perf-y += builtin-evlist.o
6perf-y += builtin-ftrace.o
6perf-y += builtin-help.o 7perf-y += builtin-help.o
7perf-y += builtin-sched.o 8perf-y += builtin-sched.o
8perf-y += builtin-buildid-list.o 9perf-y += builtin-buildid-list.o
diff --git a/tools/perf/Documentation/perf-c2c.txt b/tools/perf/Documentation/perf-c2c.txt
index 3f06730c7f47..2da07e51e119 100644
--- a/tools/perf/Documentation/perf-c2c.txt
+++ b/tools/perf/Documentation/perf-c2c.txt
@@ -248,7 +248,7 @@ output fields set for caheline offsets output:
248 Code address, Code symbol, Shared Object, Source line 248 Code address, Code symbol, Shared Object, Source line
249 dso - coalesced by shared object 249 dso - coalesced by shared object
250 250
251By default the coalescing is setup with 'pid,tid,iaddr'. 251By default the coalescing is setup with 'pid,iaddr'.
252 252
253STDIO OUTPUT 253STDIO OUTPUT
254------------ 254------------
diff --git a/tools/perf/Documentation/perf-ftrace.txt b/tools/perf/Documentation/perf-ftrace.txt
new file mode 100644
index 000000000000..2d96de6132a9
--- /dev/null
+++ b/tools/perf/Documentation/perf-ftrace.txt
@@ -0,0 +1,36 @@
1perf-ftrace(1)
2=============
3
4NAME
5----
6perf-ftrace - simple wrapper for kernel's ftrace functionality
7
8
9SYNOPSIS
10--------
11[verse]
12'perf ftrace' <command>
13
14DESCRIPTION
15-----------
16The 'perf ftrace' command is a simple wrapper of kernel's ftrace
17functionality. It only supports single thread tracing currently and
18just reads trace_pipe in text and then write it to stdout.
19
20The following options apply to perf ftrace.
21
22OPTIONS
23-------
24
25-t::
26--tracer=::
27 Tracer to use: function_graph or function.
28
29-v::
30--verbose=::
31 Verbosity level.
32
33
34SEE ALSO
35--------
36linkperf:perf-record[1], linkperf:perf-trace[1]
diff --git a/tools/perf/arch/arm64/include/dwarf-regs-table.h b/tools/perf/arch/arm64/include/dwarf-regs-table.h
index 26759363f921..36e375f5a211 100644
--- a/tools/perf/arch/arm64/include/dwarf-regs-table.h
+++ b/tools/perf/arch/arm64/include/dwarf-regs-table.h
@@ -2,12 +2,12 @@
2/* This is included in perf/util/dwarf-regs.c */ 2/* This is included in perf/util/dwarf-regs.c */
3 3
4static const char * const aarch64_regstr_tbl[] = { 4static const char * const aarch64_regstr_tbl[] = {
5 "%r0", "%r1", "%r2", "%r3", "%r4", 5 "%x0", "%x1", "%x2", "%x3", "%x4",
6 "%r5", "%r6", "%r7", "%r8", "%r9", 6 "%x5", "%x6", "%x7", "%x8", "%x9",
7 "%r10", "%r11", "%r12", "%r13", "%r14", 7 "%x10", "%x11", "%x12", "%x13", "%x14",
8 "%r15", "%r16", "%r17", "%r18", "%r19", 8 "%x15", "%x16", "%x17", "%x18", "%x19",
9 "%r20", "%r21", "%r22", "%r23", "%r24", 9 "%x20", "%x21", "%x22", "%x23", "%x24",
10 "%r25", "%r26", "%r27", "%r28", "%r29", 10 "%x25", "%x26", "%x27", "%x28", "%x29",
11 "%lr", "%sp", 11 "%lr", "%sp",
12}; 12};
13#endif 13#endif
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c
index f8ca7a4ebabc..e2b21723bbf8 100644
--- a/tools/perf/builtin-c2c.c
+++ b/tools/perf/builtin-c2c.c
@@ -58,7 +58,7 @@ struct c2c_hist_entry {
58 struct hist_entry he; 58 struct hist_entry he;
59}; 59};
60 60
61static char const *coalesce_default = "pid,tid,iaddr"; 61static char const *coalesce_default = "pid,iaddr";
62 62
63struct perf_c2c { 63struct perf_c2c {
64 struct perf_tool tool; 64 struct perf_tool tool;
@@ -2476,6 +2476,7 @@ static int build_cl_output(char *cl_sort, bool no_source)
2476 "mean_rmt," 2476 "mean_rmt,"
2477 "mean_lcl," 2477 "mean_lcl,"
2478 "mean_load," 2478 "mean_load,"
2479 "tot_recs,"
2479 "cpucnt,", 2480 "cpucnt,",
2480 add_sym ? "symbol," : "", 2481 add_sym ? "symbol," : "",
2481 add_dso ? "dso," : "", 2482 add_dso ? "dso," : "",
diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c
new file mode 100644
index 000000000000..d05658d2b8f1
--- /dev/null
+++ b/tools/perf/builtin-ftrace.c
@@ -0,0 +1,243 @@
1/*
2 * builtin-ftrace.c
3 *
4 * Copyright (c) 2013 LG Electronics, Namhyung Kim <namhyung@kernel.org>
5 *
6 * Released under the GPL v2.
7 */
8
9#include "builtin.h"
10#include "perf.h"
11
12#include <unistd.h>
13#include <signal.h>
14
15#include "debug.h"
16#include <subcmd/parse-options.h>
17#include "evlist.h"
18#include "target.h"
19#include "thread_map.h"
20
21
22#define DEFAULT_TRACER "function_graph"
23
24struct perf_ftrace {
25 struct perf_evlist *evlist;
26 struct target target;
27 const char *tracer;
28};
29
30static bool done;
31
32static void sig_handler(int sig __maybe_unused)
33{
34 done = true;
35}
36
37/*
38 * perf_evlist__prepare_workload will send a SIGUSR1 if the fork fails, since
39 * we asked by setting its exec_error to the function below,
40 * ftrace__workload_exec_failed_signal.
41 *
42 * XXX We need to handle this more appropriately, emitting an error, etc.
43 */
44static void ftrace__workload_exec_failed_signal(int signo __maybe_unused,
45 siginfo_t *info __maybe_unused,
46 void *ucontext __maybe_unused)
47{
48 /* workload_exec_errno = info->si_value.sival_int; */
49 done = true;
50}
51
52static int write_tracing_file(const char *name, const char *val)
53{
54 char *file;
55 int fd, ret = -1;
56 ssize_t size = strlen(val);
57
58 file = get_tracing_file(name);
59 if (!file) {
60 pr_debug("cannot get tracing file: %s\n", name);
61 return -1;
62 }
63
64 fd = open(file, O_WRONLY);
65 if (fd < 0) {
66 pr_debug("cannot open tracing file: %s\n", name);
67 goto out;
68 }
69
70 if (write(fd, val, size) == size)
71 ret = 0;
72 else
73 pr_debug("write '%s' to tracing/%s failed\n", val, name);
74
75 close(fd);
76out:
77 put_tracing_file(file);
78 return ret;
79}
80
81static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused)
82{
83 if (write_tracing_file("tracing_on", "0") < 0)
84 return -1;
85
86 if (write_tracing_file("current_tracer", "nop") < 0)
87 return -1;
88
89 if (write_tracing_file("set_ftrace_pid", " ") < 0)
90 return -1;
91
92 return 0;
93}
94
95static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
96{
97 char *trace_file;
98 int trace_fd;
99 char *trace_pid;
100 char buf[4096];
101 struct pollfd pollfd = {
102 .events = POLLIN,
103 };
104
105 if (geteuid() != 0) {
106 pr_err("ftrace only works for root!\n");
107 return -1;
108 }
109
110 if (argc < 1)
111 return -1;
112
113 signal(SIGINT, sig_handler);
114 signal(SIGUSR1, sig_handler);
115 signal(SIGCHLD, sig_handler);
116
117 reset_tracing_files(ftrace);
118
119 /* reset ftrace buffer */
120 if (write_tracing_file("trace", "0") < 0)
121 goto out;
122
123 if (perf_evlist__prepare_workload(ftrace->evlist, &ftrace->target,
124 argv, false, ftrace__workload_exec_failed_signal) < 0)
125 goto out;
126
127 if (write_tracing_file("current_tracer", ftrace->tracer) < 0) {
128 pr_err("failed to set current_tracer to %s\n", ftrace->tracer);
129 goto out;
130 }
131
132 if (asprintf(&trace_pid, "%d", thread_map__pid(ftrace->evlist->threads, 0)) < 0) {
133 pr_err("failed to allocate pid string\n");
134 goto out;
135 }
136
137 if (write_tracing_file("set_ftrace_pid", trace_pid) < 0) {
138 pr_err("failed to set pid: %s\n", trace_pid);
139 goto out_free_pid;
140 }
141
142 trace_file = get_tracing_file("trace_pipe");
143 if (!trace_file) {
144 pr_err("failed to open trace_pipe\n");
145 goto out_free_pid;
146 }
147
148 trace_fd = open(trace_file, O_RDONLY);
149
150 put_tracing_file(trace_file);
151
152 if (trace_fd < 0) {
153 pr_err("failed to open trace_pipe\n");
154 goto out_free_pid;
155 }
156
157 fcntl(trace_fd, F_SETFL, O_NONBLOCK);
158 pollfd.fd = trace_fd;
159
160 if (write_tracing_file("tracing_on", "1") < 0) {
161 pr_err("can't enable tracing\n");
162 goto out_close_fd;
163 }
164
165 perf_evlist__start_workload(ftrace->evlist);
166
167 while (!done) {
168 if (poll(&pollfd, 1, -1) < 0)
169 break;
170
171 if (pollfd.revents & POLLIN) {
172 int n = read(trace_fd, buf, sizeof(buf));
173 if (n < 0)
174 break;
175 if (fwrite(buf, n, 1, stdout) != 1)
176 break;
177 }
178 }
179
180 write_tracing_file("tracing_on", "0");
181
182 /* read remaining buffer contents */
183 while (true) {
184 int n = read(trace_fd, buf, sizeof(buf));
185 if (n <= 0)
186 break;
187 if (fwrite(buf, n, 1, stdout) != 1)
188 break;
189 }
190
191out_close_fd:
192 close(trace_fd);
193out_free_pid:
194 free(trace_pid);
195out:
196 reset_tracing_files(ftrace);
197
198 return done ? 0 : -1;
199}
200
201int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
202{
203 int ret;
204 struct perf_ftrace ftrace = {
205 .tracer = "function_graph",
206 .target = { .uid = UINT_MAX, },
207 };
208 const char * const ftrace_usage[] = {
209 "perf ftrace [<options>] <command>",
210 "perf ftrace [<options>] -- <command> [<options>]",
211 NULL
212 };
213 const struct option ftrace_options[] = {
214 OPT_STRING('t', "tracer", &ftrace.tracer, "tracer",
215 "tracer to use: function_graph(default) or function"),
216 OPT_INCR('v', "verbose", &verbose,
217 "be more verbose"),
218 OPT_END()
219 };
220
221 argc = parse_options(argc, argv, ftrace_options, ftrace_usage,
222 PARSE_OPT_STOP_AT_NON_OPTION);
223 if (!argc)
224 usage_with_options(ftrace_usage, ftrace_options);
225
226 ftrace.evlist = perf_evlist__new();
227 if (ftrace.evlist == NULL)
228 return -ENOMEM;
229
230 ret = perf_evlist__create_maps(ftrace.evlist, &ftrace.target);
231 if (ret < 0)
232 goto out_delete_evlist;
233
234 if (ftrace.tracer == NULL)
235 ftrace.tracer = DEFAULT_TRACER;
236
237 ret = __cmd_ftrace(&ftrace, argc, argv);
238
239out_delete_evlist:
240 perf_evlist__delete(ftrace.evlist);
241
242 return ret;
243}
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index b55f5be486a1..036e1e35b1a8 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -41,6 +41,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix);
41int cmd_inject(int argc, const char **argv, const char *prefix); 41int cmd_inject(int argc, const char **argv, const char *prefix);
42int cmd_mem(int argc, const char **argv, const char *prefix); 42int cmd_mem(int argc, const char **argv, const char *prefix);
43int cmd_data(int argc, const char **argv, const char *prefix); 43int cmd_data(int argc, const char **argv, const char *prefix);
44int cmd_ftrace(int argc, const char **argv, const char *prefix);
44 45
45int find_scripts(char **scripts_array, char **scripts_path_array); 46int find_scripts(char **scripts_array, char **scripts_path_array);
46#endif 47#endif
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index fb45613dba9e..ac3efd396a72 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -11,6 +11,7 @@ perf-data mainporcelain common
11perf-diff mainporcelain common 11perf-diff mainporcelain common
12perf-config mainporcelain common 12perf-config mainporcelain common
13perf-evlist mainporcelain common 13perf-evlist mainporcelain common
14perf-ftrace mainporcelain common
14perf-inject mainporcelain common 15perf-inject mainporcelain common
15perf-kallsyms mainporcelain common 16perf-kallsyms mainporcelain common
16perf-kmem mainporcelain common 17perf-kmem mainporcelain common
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 0324cd15e42a..34bcf90f8871 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -71,6 +71,7 @@ static struct cmd_struct commands[] = {
71 { "inject", cmd_inject, 0 }, 71 { "inject", cmd_inject, 0 },
72 { "mem", cmd_mem, 0 }, 72 { "mem", cmd_mem, 0 },
73 { "data", cmd_data, 0 }, 73 { "data", cmd_data, 0 },
74 { "ftrace", cmd_ftrace, 0 },
74}; 75};
75 76
76struct pager_config { 77struct pager_config {
diff --git a/tools/perf/tests/llvm.c b/tools/perf/tests/llvm.c
index 02a33ebcd992..d357dab72e68 100644
--- a/tools/perf/tests/llvm.c
+++ b/tools/perf/tests/llvm.c
@@ -13,7 +13,7 @@ static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz)
13 struct bpf_object *obj; 13 struct bpf_object *obj;
14 14
15 obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, NULL); 15 obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, NULL);
16 if (IS_ERR(obj)) 16 if (libbpf_get_error(obj))
17 return TEST_FAIL; 17 return TEST_FAIL;
18 bpf_object__close(obj); 18 bpf_object__close(obj);
19 return TEST_OK; 19 return TEST_OK;
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 641b40234a9d..fc4fb669ceee 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -501,8 +501,8 @@ static int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he,
501 return n; 501 return n;
502} 502}
503 503
504static void hist_entry__set_folding(struct hist_entry *he, 504static void __hist_entry__set_folding(struct hist_entry *he,
505 struct hist_browser *hb, bool unfold) 505 struct hist_browser *hb, bool unfold)
506{ 506{
507 hist_entry__init_have_children(he); 507 hist_entry__init_have_children(he);
508 he->unfolded = unfold ? he->has_children : false; 508 he->unfolded = unfold ? he->has_children : false;
@@ -520,12 +520,34 @@ static void hist_entry__set_folding(struct hist_entry *he,
520 he->nr_rows = 0; 520 he->nr_rows = 0;
521} 521}
522 522
523static void hist_entry__set_folding(struct hist_entry *he,
524 struct hist_browser *browser, bool unfold)
525{
526 double percent;
527
528 percent = hist_entry__get_percent_limit(he);
529 if (he->filtered || percent < browser->min_pcnt)
530 return;
531
532 __hist_entry__set_folding(he, browser, unfold);
533
534 if (!he->depth || unfold)
535 browser->nr_hierarchy_entries++;
536 if (he->leaf)
537 browser->nr_callchain_rows += he->nr_rows;
538 else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) {
539 browser->nr_hierarchy_entries++;
540 he->has_no_entry = true;
541 he->nr_rows = 1;
542 } else
543 he->has_no_entry = false;
544}
545
523static void 546static void
524__hist_browser__set_folding(struct hist_browser *browser, bool unfold) 547__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
525{ 548{
526 struct rb_node *nd; 549 struct rb_node *nd;
527 struct hist_entry *he; 550 struct hist_entry *he;
528 double percent;
529 551
530 nd = rb_first(&browser->hists->entries); 552 nd = rb_first(&browser->hists->entries);
531 while (nd) { 553 while (nd) {
@@ -535,21 +557,6 @@ __hist_browser__set_folding(struct hist_browser *browser, bool unfold)
535 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD); 557 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
536 558
537 hist_entry__set_folding(he, browser, unfold); 559 hist_entry__set_folding(he, browser, unfold);
538
539 percent = hist_entry__get_percent_limit(he);
540 if (he->filtered || percent < browser->min_pcnt)
541 continue;
542
543 if (!he->depth || unfold)
544 browser->nr_hierarchy_entries++;
545 if (he->leaf)
546 browser->nr_callchain_rows += he->nr_rows;
547 else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) {
548 browser->nr_hierarchy_entries++;
549 he->has_no_entry = true;
550 he->nr_rows = 1;
551 } else
552 he->has_no_entry = false;
553 } 560 }
554} 561}
555 562
@@ -564,6 +571,15 @@ static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
564 ui_browser__reset_index(&browser->b); 571 ui_browser__reset_index(&browser->b);
565} 572}
566 573
574static void hist_browser__set_folding_selected(struct hist_browser *browser, bool unfold)
575{
576 if (!browser->he_selection)
577 return;
578
579 hist_entry__set_folding(browser->he_selection, browser, unfold);
580 browser->b.nr_entries = hist_browser__nr_entries(browser);
581}
582
567static void ui_browser__warn_lost_events(struct ui_browser *browser) 583static void ui_browser__warn_lost_events(struct ui_browser *browser)
568{ 584{
569 ui_browser__warning(browser, 4, 585 ui_browser__warning(browser, 4,
@@ -637,10 +653,18 @@ int hist_browser__run(struct hist_browser *browser, const char *help)
637 /* Collapse the whole world. */ 653 /* Collapse the whole world. */
638 hist_browser__set_folding(browser, false); 654 hist_browser__set_folding(browser, false);
639 break; 655 break;
656 case 'c':
657 /* Collapse the selected entry. */
658 hist_browser__set_folding_selected(browser, false);
659 break;
640 case 'E': 660 case 'E':
641 /* Expand the whole world. */ 661 /* Expand the whole world. */
642 hist_browser__set_folding(browser, true); 662 hist_browser__set_folding(browser, true);
643 break; 663 break;
664 case 'e':
665 /* Expand the selected entry. */
666 hist_browser__set_folding_selected(browser, true);
667 break;
644 case 'H': 668 case 'H':
645 browser->show_headers = !browser->show_headers; 669 browser->show_headers = !browser->show_headers;
646 hist_browser__update_rows(browser); 670 hist_browser__update_rows(browser);
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index d2c6cdd9d42b..28d41e709128 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -9,6 +9,13 @@
9#include "debug.h" 9#include "debug.h"
10#include "vdso.h" 10#include "vdso.h"
11 11
12static const char * const debuglink_paths[] = {
13 "%.0s%s",
14 "%s/%s",
15 "%s/.debug/%s",
16 "/usr/lib/debug%s/%s"
17};
18
12char dso__symtab_origin(const struct dso *dso) 19char dso__symtab_origin(const struct dso *dso)
13{ 20{
14 static const char origin[] = { 21 static const char origin[] = {
@@ -44,24 +51,43 @@ int dso__read_binary_type_filename(const struct dso *dso,
44 size_t len; 51 size_t len;
45 52
46 switch (type) { 53 switch (type) {
47 case DSO_BINARY_TYPE__DEBUGLINK: { 54 case DSO_BINARY_TYPE__DEBUGLINK:
48 char *debuglink; 55 {
56 const char *last_slash;
57 char dso_dir[PATH_MAX];
58 char symfile[PATH_MAX];
59 unsigned int i;
49 60
50 len = __symbol__join_symfs(filename, size, dso->long_name); 61 len = __symbol__join_symfs(filename, size, dso->long_name);
51 debuglink = filename + len; 62 last_slash = filename + len;
52 while (debuglink != filename && *debuglink != '/') 63 while (last_slash != filename && *last_slash != '/')
53 debuglink--; 64 last_slash--;
54 if (*debuglink == '/')
55 debuglink++;
56 65
57 ret = -1; 66 strncpy(dso_dir, filename, last_slash - filename);
58 if (!is_regular_file(filename)) 67 dso_dir[last_slash-filename] = '\0';
68
69 if (!is_regular_file(filename)) {
70 ret = -1;
71 break;
72 }
73
74 ret = filename__read_debuglink(filename, symfile, PATH_MAX);
75 if (ret)
59 break; 76 break;
60 77
61 ret = filename__read_debuglink(filename, debuglink, 78 /* Check predefined locations where debug file might reside */
62 size - (debuglink - filename)); 79 ret = -1;
80 for (i = 0; i < ARRAY_SIZE(debuglink_paths); i++) {
81 snprintf(filename, size,
82 debuglink_paths[i], dso_dir, symfile);
83 if (is_regular_file(filename)) {
84 ret = 0;
85 break;
86 }
63 } 87 }
88
64 break; 89 break;
90 }
65 case DSO_BINARY_TYPE__BUILD_ID_CACHE: 91 case DSO_BINARY_TYPE__BUILD_ID_CACHE:
66 if (dso__build_id_filename(dso, filename, size) == NULL) 92 if (dso__build_id_filename(dso, filename, size) == NULL)
67 ret = -1; 93 ret = -1;
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 00fd8a8850d3..c567d9f0aa92 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -2803,8 +2803,10 @@ static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel,
2803 } 2803 }
2804 2804
2805 event = pevent_find_event(pevent, evsel->attr.config); 2805 event = pevent_find_event(pevent, evsel->attr.config);
2806 if (event == NULL) 2806 if (event == NULL) {
2807 pr_debug("cannot find event format for %d\n", (int)evsel->attr.config);
2807 return -1; 2808 return -1;
2809 }
2808 2810
2809 if (!evsel->name) { 2811 if (!evsel->name) {
2810 snprintf(bf, sizeof(bf), "%s:%s", event->system, event->name); 2812 snprintf(bf, sizeof(bf), "%s:%s", event->system, event->name);
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 6a6f44dd594b..2c1bca240597 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -3023,20 +3023,17 @@ static int try_to_find_absolute_address(struct perf_probe_event *pev,
3023 3023
3024 tev->nargs = pev->nargs; 3024 tev->nargs = pev->nargs;
3025 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); 3025 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
3026 if (!tev->args) { 3026 if (!tev->args)
3027 err = -ENOMEM;
3028 goto errout; 3027 goto errout;
3029 } 3028
3030 for (i = 0; i < tev->nargs; i++) 3029 for (i = 0; i < tev->nargs; i++)
3031 copy_to_probe_trace_arg(&tev->args[i], &pev->args[i]); 3030 copy_to_probe_trace_arg(&tev->args[i], &pev->args[i]);
3032 3031
3033 return 1; 3032 return 1;
3034 3033
3035errout: 3034errout:
3036 if (*tevs) { 3035 clear_probe_trace_events(*tevs, 1);
3037 clear_probe_trace_events(*tevs, 1); 3036 *tevs = NULL;
3038 *tevs = NULL;
3039 }
3040 return err; 3037 return err;
3041} 3038}
3042 3039
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index e55a132f69b7..014ecd6f67c4 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -350,8 +350,10 @@ static void perl_process_tracepoint(struct perf_sample *sample,
350 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) 350 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
351 return; 351 return;
352 352
353 if (!event) 353 if (!event) {
354 die("ug! no event found for type %" PRIu64, (u64)evsel->attr.config); 354 pr_debug("ug! no event found for type %" PRIu64, (u64)evsel->attr.config);
355 return;
356 }
355 357
356 pid = raw_field_value(event, "common_pid", data); 358 pid = raw_field_value(event, "common_pid", data);
357 359
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index d995743cb673..ceb0e2720223 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -42,7 +42,7 @@
42#include "evsel.h" 42#include "evsel.h"
43#include "debug.h" 43#include "debug.h"
44 44
45#define VERSION "0.5" 45#define VERSION "0.6"
46 46
47static int output_fd; 47static int output_fd;
48 48
@@ -379,6 +379,34 @@ out:
379 return err; 379 return err;
380} 380}
381 381
382static int record_saved_cmdline(void)
383{
384 unsigned int size;
385 char *path;
386 struct stat st;
387 int ret, err = 0;
388
389 path = get_tracing_file("saved_cmdlines");
390 if (!path) {
391 pr_debug("can't get tracing/saved_cmdline");
392 return -ENOMEM;
393 }
394
395 ret = stat(path, &st);
396 if (ret < 0) {
397 /* not found */
398 size = 0;
399 if (write(output_fd, &size, 8) != 8)
400 err = -EIO;
401 goto out;
402 }
403 err = record_file(path, 8);
404
405out:
406 put_tracing_file(path);
407 return err;
408}
409
382static void 410static void
383put_tracepoints_path(struct tracepoint_path *tps) 411put_tracepoints_path(struct tracepoint_path *tps)
384{ 412{
@@ -539,6 +567,9 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
539 if (err) 567 if (err)
540 goto out; 568 goto out;
541 err = record_ftrace_printk(); 569 err = record_ftrace_printk();
570 if (err)
571 goto out;
572 err = record_saved_cmdline();
542 573
543out: 574out:
544 /* 575 /*
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 33b52eaa39db..de0078e21408 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -160,6 +160,23 @@ void parse_ftrace_printk(struct pevent *pevent,
160 } 160 }
161} 161}
162 162
163void parse_saved_cmdline(struct pevent *pevent,
164 char *file, unsigned int size __maybe_unused)
165{
166 char *comm;
167 char *line;
168 char *next = NULL;
169 int pid;
170
171 line = strtok_r(file, "\n", &next);
172 while (line) {
173 sscanf(line, "%d %ms", &pid, &comm);
174 pevent_register_comm(pevent, comm, pid);
175 free(comm);
176 line = strtok_r(NULL, "\n", &next);
177 }
178}
179
163int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size) 180int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size)
164{ 181{
165 return pevent_parse_event(pevent, buf, size, "ftrace"); 182 return pevent_parse_event(pevent, buf, size, "ftrace");
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index b67a0ccf5ab9..27420159bf69 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -260,39 +260,53 @@ static int read_header_files(struct pevent *pevent)
260 260
261static int read_ftrace_file(struct pevent *pevent, unsigned long long size) 261static int read_ftrace_file(struct pevent *pevent, unsigned long long size)
262{ 262{
263 int ret;
263 char *buf; 264 char *buf;
264 265
265 buf = malloc(size); 266 buf = malloc(size);
266 if (buf == NULL) 267 if (buf == NULL) {
268 pr_debug("memory allocation failure\n");
267 return -1; 269 return -1;
270 }
268 271
269 if (do_read(buf, size) < 0) { 272 ret = do_read(buf, size);
270 free(buf); 273 if (ret < 0) {
271 return -1; 274 pr_debug("error reading ftrace file.\n");
275 goto out;
272 } 276 }
273 277
274 parse_ftrace_file(pevent, buf, size); 278 ret = parse_ftrace_file(pevent, buf, size);
279 if (ret < 0)
280 pr_debug("error parsing ftrace file.\n");
281out:
275 free(buf); 282 free(buf);
276 return 0; 283 return ret;
277} 284}
278 285
279static int read_event_file(struct pevent *pevent, char *sys, 286static int read_event_file(struct pevent *pevent, char *sys,
280 unsigned long long size) 287 unsigned long long size)
281{ 288{
289 int ret;
282 char *buf; 290 char *buf;
283 291
284 buf = malloc(size); 292 buf = malloc(size);
285 if (buf == NULL) 293 if (buf == NULL) {
294 pr_debug("memory allocation failure\n");
286 return -1; 295 return -1;
296 }
287 297
288 if (do_read(buf, size) < 0) { 298 ret = do_read(buf, size);
299 if (ret < 0) {
289 free(buf); 300 free(buf);
290 return -1; 301 goto out;
291 } 302 }
292 303
293 parse_event_file(pevent, buf, size, sys); 304 ret = parse_event_file(pevent, buf, size, sys);
305 if (ret < 0)
306 pr_debug("error parsing event file.\n");
307out:
294 free(buf); 308 free(buf);
295 return 0; 309 return ret;
296} 310}
297 311
298static int read_ftrace_files(struct pevent *pevent) 312static int read_ftrace_files(struct pevent *pevent)
@@ -341,6 +355,36 @@ static int read_event_files(struct pevent *pevent)
341 return 0; 355 return 0;
342} 356}
343 357
358static int read_saved_cmdline(struct pevent *pevent)
359{
360 unsigned long long size;
361 char *buf;
362 int ret;
363
364 /* it can have 0 size */
365 size = read8(pevent);
366 if (!size)
367 return 0;
368
369 buf = malloc(size + 1);
370 if (buf == NULL) {
371 pr_debug("memory allocation failure\n");
372 return -1;
373 }
374
375 ret = do_read(buf, size);
376 if (ret < 0) {
377 pr_debug("error reading saved cmdlines\n");
378 goto out;
379 }
380
381 parse_saved_cmdline(pevent, buf, size);
382 ret = 0;
383out:
384 free(buf);
385 return ret;
386}
387
344ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe) 388ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe)
345{ 389{
346 char buf[BUFSIZ]; 390 char buf[BUFSIZ];
@@ -379,10 +423,11 @@ ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe)
379 return -1; 423 return -1;
380 if (show_version) 424 if (show_version)
381 printf("version = %s\n", version); 425 printf("version = %s\n", version);
382 free(version);
383 426
384 if (do_read(buf, 1) < 0) 427 if (do_read(buf, 1) < 0) {
428 free(version);
385 return -1; 429 return -1;
430 }
386 file_bigendian = buf[0]; 431 file_bigendian = buf[0];
387 host_bigendian = bigendian(); 432 host_bigendian = bigendian();
388 433
@@ -423,6 +468,11 @@ ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe)
423 err = read_ftrace_printk(pevent); 468 err = read_ftrace_printk(pevent);
424 if (err) 469 if (err)
425 goto out; 470 goto out;
471 if (atof(version) >= 0.6) {
472 err = read_saved_cmdline(pevent);
473 if (err)
474 goto out;
475 }
426 476
427 size = trace_data_size; 477 size = trace_data_size;
428 repipe = false; 478 repipe = false;
@@ -438,5 +488,6 @@ ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe)
438out: 488out:
439 if (pevent) 489 if (pevent)
440 trace_event__cleanup(tevent); 490 trace_event__cleanup(tevent);
491 free(version);
441 return size; 492 return size;
442} 493}
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index b0af9c81bb0d..1fbc044f9eb0 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -42,6 +42,7 @@ raw_field_value(struct event_format *event, const char *name, void *data);
42 42
43void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size); 43void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size);
44void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size); 44void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size);
45void parse_saved_cmdline(struct pevent *pevent, char *file, unsigned int size);
45 46
46ssize_t trace_report(int fd, struct trace_event *tevent, bool repipe); 47ssize_t trace_report(int fd, struct trace_event *tevent, bool repipe);
47 48
diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c
index 6fec84dff3f7..bfb9b7987692 100644
--- a/tools/perf/util/unwind-libunwind-local.c
+++ b/tools/perf/util/unwind-libunwind-local.c
@@ -35,6 +35,7 @@
35#include "util.h" 35#include "util.h"
36#include "debug.h" 36#include "debug.h"
37#include "asm/bug.h" 37#include "asm/bug.h"
38#include "dso.h"
38 39
39extern int 40extern int
40UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, 41UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
@@ -297,15 +298,58 @@ static int read_unwind_spec_debug_frame(struct dso *dso,
297 int fd; 298 int fd;
298 u64 ofs = dso->data.debug_frame_offset; 299 u64 ofs = dso->data.debug_frame_offset;
299 300
301 /* debug_frame can reside in:
302 * - dso
303 * - debug pointed by symsrc_filename
304 * - gnu_debuglink, which doesn't necessary
305 * has to be pointed by symsrc_filename
306 */
300 if (ofs == 0) { 307 if (ofs == 0) {
301 fd = dso__data_get_fd(dso, machine); 308 fd = dso__data_get_fd(dso, machine);
302 if (fd < 0) 309 if (fd >= 0) {
303 return -EINVAL; 310 ofs = elf_section_offset(fd, ".debug_frame");
311 dso__data_put_fd(dso);
312 }
313
314 if (ofs <= 0) {
315 fd = open(dso->symsrc_filename, O_RDONLY);
316 if (fd >= 0) {
317 ofs = elf_section_offset(fd, ".debug_frame");
318 close(fd);
319 }
320 }
321
322 if (ofs <= 0) {
323 char *debuglink = malloc(PATH_MAX);
324 int ret = 0;
325
326 ret = dso__read_binary_type_filename(
327 dso, DSO_BINARY_TYPE__DEBUGLINK,
328 machine->root_dir, debuglink, PATH_MAX);
329 if (!ret) {
330 fd = open(debuglink, O_RDONLY);
331 if (fd >= 0) {
332 ofs = elf_section_offset(fd,
333 ".debug_frame");
334 close(fd);
335 }
336 }
337 if (ofs > 0) {
338 if (dso->symsrc_filename != NULL) {
339 pr_warning(
340 "%s: overwrite symsrc(%s,%s)\n",
341 __func__,
342 dso->symsrc_filename,
343 debuglink);
344 free(dso->symsrc_filename);
345 }
346 dso->symsrc_filename = debuglink;
347 } else {
348 free(debuglink);
349 }
350 }
304 351
305 /* Check the .debug_frame section for unwinding info */
306 ofs = elf_section_offset(fd, ".debug_frame");
307 dso->data.debug_frame_offset = ofs; 352 dso->data.debug_frame_offset = ofs;
308 dso__data_put_fd(dso);
309 } 353 }
310 354
311 *offset = ofs; 355 *offset = ofs;