diff options
author | Ingo Molnar <mingo@kernel.org> | 2017-01-26 10:20:59 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2017-01-26 10:20:59 -0500 |
commit | e2cf00c257f5bbc071b489b1dfbeaa30b6f12da6 (patch) | |
tree | aa1af0d0f4bbbdd9d706574478fec568895f817b /tools/perf | |
parent | 47cd95a6326888a46e7ce8389cd394a3e1c647e7 (diff) | |
parent | ec347870a9d423a4b88657d6a85b5163b3f949ee (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/Build | 1 | ||||
-rw-r--r-- | tools/perf/Documentation/perf-c2c.txt | 2 | ||||
-rw-r--r-- | tools/perf/Documentation/perf-ftrace.txt | 36 | ||||
-rw-r--r-- | tools/perf/arch/arm64/include/dwarf-regs-table.h | 12 | ||||
-rw-r--r-- | tools/perf/builtin-c2c.c | 3 | ||||
-rw-r--r-- | tools/perf/builtin-ftrace.c | 243 | ||||
-rw-r--r-- | tools/perf/builtin.h | 1 | ||||
-rw-r--r-- | tools/perf/command-list.txt | 1 | ||||
-rw-r--r-- | tools/perf/perf.c | 1 | ||||
-rw-r--r-- | tools/perf/tests/llvm.c | 2 | ||||
-rw-r--r-- | tools/perf/ui/browsers/hists.c | 60 | ||||
-rw-r--r-- | tools/perf/util/dso.c | 48 | ||||
-rw-r--r-- | tools/perf/util/header.c | 4 | ||||
-rw-r--r-- | tools/perf/util/probe-event.c | 11 | ||||
-rw-r--r-- | tools/perf/util/scripting-engines/trace-event-perl.c | 6 | ||||
-rw-r--r-- | tools/perf/util/trace-event-info.c | 33 | ||||
-rw-r--r-- | tools/perf/util/trace-event-parse.c | 17 | ||||
-rw-r--r-- | tools/perf/util/trace-event-read.c | 77 | ||||
-rw-r--r-- | tools/perf/util/trace-event.h | 1 | ||||
-rw-r--r-- | tools/perf/util/unwind-libunwind-local.c | 54 |
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 | |||
3 | perf-y += builtin-config.o | 3 | perf-y += builtin-config.o |
4 | perf-y += builtin-diff.o | 4 | perf-y += builtin-diff.o |
5 | perf-y += builtin-evlist.o | 5 | perf-y += builtin-evlist.o |
6 | perf-y += builtin-ftrace.o | ||
6 | perf-y += builtin-help.o | 7 | perf-y += builtin-help.o |
7 | perf-y += builtin-sched.o | 8 | perf-y += builtin-sched.o |
8 | perf-y += builtin-buildid-list.o | 9 | perf-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 | ||
251 | By default the coalescing is setup with 'pid,tid,iaddr'. | 251 | By default the coalescing is setup with 'pid,iaddr'. |
252 | 252 | ||
253 | STDIO OUTPUT | 253 | STDIO 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 @@ | |||
1 | perf-ftrace(1) | ||
2 | ============= | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | perf-ftrace - simple wrapper for kernel's ftrace functionality | ||
7 | |||
8 | |||
9 | SYNOPSIS | ||
10 | -------- | ||
11 | [verse] | ||
12 | 'perf ftrace' <command> | ||
13 | |||
14 | DESCRIPTION | ||
15 | ----------- | ||
16 | The 'perf ftrace' command is a simple wrapper of kernel's ftrace | ||
17 | functionality. It only supports single thread tracing currently and | ||
18 | just reads trace_pipe in text and then write it to stdout. | ||
19 | |||
20 | The following options apply to perf ftrace. | ||
21 | |||
22 | OPTIONS | ||
23 | ------- | ||
24 | |||
25 | -t:: | ||
26 | --tracer=:: | ||
27 | Tracer to use: function_graph or function. | ||
28 | |||
29 | -v:: | ||
30 | --verbose=:: | ||
31 | Verbosity level. | ||
32 | |||
33 | |||
34 | SEE ALSO | ||
35 | -------- | ||
36 | linkperf: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 | ||
4 | static const char * const aarch64_regstr_tbl[] = { | 4 | static 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 | ||
61 | static char const *coalesce_default = "pid,tid,iaddr"; | 61 | static char const *coalesce_default = "pid,iaddr"; |
62 | 62 | ||
63 | struct perf_c2c { | 63 | struct 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 | |||
24 | struct perf_ftrace { | ||
25 | struct perf_evlist *evlist; | ||
26 | struct target target; | ||
27 | const char *tracer; | ||
28 | }; | ||
29 | |||
30 | static bool done; | ||
31 | |||
32 | static 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 | */ | ||
44 | static 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 | |||
52 | static 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); | ||
76 | out: | ||
77 | put_tracing_file(file); | ||
78 | return ret; | ||
79 | } | ||
80 | |||
81 | static 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 | |||
95 | static 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 | |||
191 | out_close_fd: | ||
192 | close(trace_fd); | ||
193 | out_free_pid: | ||
194 | free(trace_pid); | ||
195 | out: | ||
196 | reset_tracing_files(ftrace); | ||
197 | |||
198 | return done ? 0 : -1; | ||
199 | } | ||
200 | |||
201 | int 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 | |||
239 | out_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); | |||
41 | int cmd_inject(int argc, const char **argv, const char *prefix); | 41 | int cmd_inject(int argc, const char **argv, const char *prefix); |
42 | int cmd_mem(int argc, const char **argv, const char *prefix); | 42 | int cmd_mem(int argc, const char **argv, const char *prefix); |
43 | int cmd_data(int argc, const char **argv, const char *prefix); | 43 | int cmd_data(int argc, const char **argv, const char *prefix); |
44 | int cmd_ftrace(int argc, const char **argv, const char *prefix); | ||
44 | 45 | ||
45 | int find_scripts(char **scripts_array, char **scripts_path_array); | 46 | int 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 | |||
11 | perf-diff mainporcelain common | 11 | perf-diff mainporcelain common |
12 | perf-config mainporcelain common | 12 | perf-config mainporcelain common |
13 | perf-evlist mainporcelain common | 13 | perf-evlist mainporcelain common |
14 | perf-ftrace mainporcelain common | ||
14 | perf-inject mainporcelain common | 15 | perf-inject mainporcelain common |
15 | perf-kallsyms mainporcelain common | 16 | perf-kallsyms mainporcelain common |
16 | perf-kmem mainporcelain common | 17 | perf-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 | ||
76 | struct pager_config { | 77 | struct 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 | ||
504 | static void hist_entry__set_folding(struct hist_entry *he, | 504 | static 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 | ||
523 | static 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 | |||
523 | static void | 546 | static 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 | ||
574 | static 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 | |||
567 | static void ui_browser__warn_lost_events(struct ui_browser *browser) | 583 | static 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 | ||
12 | static const char * const debuglink_paths[] = { | ||
13 | "%.0s%s", | ||
14 | "%s/%s", | ||
15 | "%s/.debug/%s", | ||
16 | "/usr/lib/debug%s/%s" | ||
17 | }; | ||
18 | |||
12 | char dso__symtab_origin(const struct dso *dso) | 19 | char 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 | ||
3035 | errout: | 3034 | errout: |
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 | ||
47 | static int output_fd; | 47 | static int output_fd; |
48 | 48 | ||
@@ -379,6 +379,34 @@ out: | |||
379 | return err; | 379 | return err; |
380 | } | 380 | } |
381 | 381 | ||
382 | static 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 | |||
405 | out: | ||
406 | put_tracing_file(path); | ||
407 | return err; | ||
408 | } | ||
409 | |||
382 | static void | 410 | static void |
383 | put_tracepoints_path(struct tracepoint_path *tps) | 411 | put_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 | ||
543 | out: | 574 | out: |
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 | ||
163 | void 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 | |||
163 | int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size) | 180 | int 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 | ||
261 | static int read_ftrace_file(struct pevent *pevent, unsigned long long size) | 261 | static 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"); | ||
281 | out: | ||
275 | free(buf); | 282 | free(buf); |
276 | return 0; | 283 | return ret; |
277 | } | 284 | } |
278 | 285 | ||
279 | static int read_event_file(struct pevent *pevent, char *sys, | 286 | static 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"); | ||
307 | out: | ||
294 | free(buf); | 308 | free(buf); |
295 | return 0; | 309 | return ret; |
296 | } | 310 | } |
297 | 311 | ||
298 | static int read_ftrace_files(struct pevent *pevent) | 312 | static 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 | ||
358 | static 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; | ||
383 | out: | ||
384 | free(buf); | ||
385 | return ret; | ||
386 | } | ||
387 | |||
344 | ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe) | 388 | ssize_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) | |||
438 | out: | 488 | out: |
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 | ||
43 | void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size); | 43 | void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size); |
44 | void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size); | 44 | void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size); |
45 | void parse_saved_cmdline(struct pevent *pevent, char *file, unsigned int size); | ||
45 | 46 | ||
46 | ssize_t trace_report(int fd, struct trace_event *tevent, bool repipe); | 47 | ssize_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 | ||
39 | extern int | 40 | extern int |
40 | UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, | 41 | UNW_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; |