diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/arch/sh/Makefile | 4 | ||||
-rw-r--r-- | tools/perf/arch/sh/util/dwarf-regs.c | 55 | ||||
-rw-r--r-- | tools/perf/util/probe-event.c | 69 | ||||
-rw-r--r-- | tools/perf/util/probe-event.h | 1 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.c | 96 |
5 files changed, 162 insertions, 63 deletions
diff --git a/tools/perf/arch/sh/Makefile b/tools/perf/arch/sh/Makefile new file mode 100644 index 000000000000..15130b50dfe3 --- /dev/null +++ b/tools/perf/arch/sh/Makefile | |||
@@ -0,0 +1,4 @@ | |||
1 | ifndef NO_DWARF | ||
2 | PERF_HAVE_DWARF_REGS := 1 | ||
3 | LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o | ||
4 | endif | ||
diff --git a/tools/perf/arch/sh/util/dwarf-regs.c b/tools/perf/arch/sh/util/dwarf-regs.c new file mode 100644 index 000000000000..a11edb007a6c --- /dev/null +++ b/tools/perf/arch/sh/util/dwarf-regs.c | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | * Mapping of DWARF debug register numbers into register names. | ||
3 | * | ||
4 | * Copyright (C) 2010 Matt Fleming <matt@console-pimps.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <libio.h> | ||
23 | #include <dwarf-regs.h> | ||
24 | |||
25 | /* | ||
26 | * Generic dwarf analysis helpers | ||
27 | */ | ||
28 | |||
29 | #define SH_MAX_REGS 18 | ||
30 | const char *sh_regs_table[SH_MAX_REGS] = { | ||
31 | "r0", | ||
32 | "r1", | ||
33 | "r2", | ||
34 | "r3", | ||
35 | "r4", | ||
36 | "r5", | ||
37 | "r6", | ||
38 | "r7", | ||
39 | "r8", | ||
40 | "r9", | ||
41 | "r10", | ||
42 | "r11", | ||
43 | "r12", | ||
44 | "r13", | ||
45 | "r14", | ||
46 | "r15", | ||
47 | "pc", | ||
48 | "pr", | ||
49 | }; | ||
50 | |||
51 | /* Return architecture dependent register string (for kprobe-tracer) */ | ||
52 | const char *get_arch_regstr(unsigned int n) | ||
53 | { | ||
54 | return (n <= SH_MAX_REGS) ? sh_regs_table[n] : NULL; | ||
55 | } | ||
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 09cf5465e10a..4445a1e7052f 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -195,6 +195,65 @@ static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev, | |||
195 | return ntevs; | 195 | return ntevs; |
196 | } | 196 | } |
197 | 197 | ||
198 | /* | ||
199 | * Find a src file from a DWARF tag path. Prepend optional source path prefix | ||
200 | * and chop off leading directories that do not exist. Result is passed back as | ||
201 | * a newly allocated path on success. | ||
202 | * Return 0 if file was found and readable, -errno otherwise. | ||
203 | */ | ||
204 | static int get_real_path(const char *raw_path, const char *comp_dir, | ||
205 | char **new_path) | ||
206 | { | ||
207 | const char *prefix = symbol_conf.source_prefix; | ||
208 | |||
209 | if (!prefix) { | ||
210 | if (raw_path[0] != '/' && comp_dir) | ||
211 | /* If not an absolute path, try to use comp_dir */ | ||
212 | prefix = comp_dir; | ||
213 | else { | ||
214 | if (access(raw_path, R_OK) == 0) { | ||
215 | *new_path = strdup(raw_path); | ||
216 | return 0; | ||
217 | } else | ||
218 | return -errno; | ||
219 | } | ||
220 | } | ||
221 | |||
222 | *new_path = malloc((strlen(prefix) + strlen(raw_path) + 2)); | ||
223 | if (!*new_path) | ||
224 | return -ENOMEM; | ||
225 | |||
226 | for (;;) { | ||
227 | sprintf(*new_path, "%s/%s", prefix, raw_path); | ||
228 | |||
229 | if (access(*new_path, R_OK) == 0) | ||
230 | return 0; | ||
231 | |||
232 | if (!symbol_conf.source_prefix) | ||
233 | /* In case of searching comp_dir, don't retry */ | ||
234 | return -errno; | ||
235 | |||
236 | switch (errno) { | ||
237 | case ENAMETOOLONG: | ||
238 | case ENOENT: | ||
239 | case EROFS: | ||
240 | case EFAULT: | ||
241 | raw_path = strchr(++raw_path, '/'); | ||
242 | if (!raw_path) { | ||
243 | free(*new_path); | ||
244 | *new_path = NULL; | ||
245 | return -ENOENT; | ||
246 | } | ||
247 | continue; | ||
248 | |||
249 | default: | ||
250 | free(*new_path); | ||
251 | *new_path = NULL; | ||
252 | return -errno; | ||
253 | } | ||
254 | } | ||
255 | } | ||
256 | |||
198 | #define LINEBUF_SIZE 256 | 257 | #define LINEBUF_SIZE 256 |
199 | #define NR_ADDITIONAL_LINES 2 | 258 | #define NR_ADDITIONAL_LINES 2 |
200 | 259 | ||
@@ -244,6 +303,7 @@ int show_line_range(struct line_range *lr) | |||
244 | struct line_node *ln; | 303 | struct line_node *ln; |
245 | FILE *fp; | 304 | FILE *fp; |
246 | int fd, ret; | 305 | int fd, ret; |
306 | char *tmp; | ||
247 | 307 | ||
248 | /* Search a line range */ | 308 | /* Search a line range */ |
249 | ret = init_vmlinux(); | 309 | ret = init_vmlinux(); |
@@ -266,6 +326,15 @@ int show_line_range(struct line_range *lr) | |||
266 | return ret; | 326 | return ret; |
267 | } | 327 | } |
268 | 328 | ||
329 | /* Convert source file path */ | ||
330 | tmp = lr->path; | ||
331 | ret = get_real_path(tmp, lr->comp_dir, &lr->path); | ||
332 | free(tmp); /* Free old path */ | ||
333 | if (ret < 0) { | ||
334 | pr_warning("Failed to find source file. (%d)\n", ret); | ||
335 | return ret; | ||
336 | } | ||
337 | |||
269 | setup_pager(); | 338 | setup_pager(); |
270 | 339 | ||
271 | if (lr->function) | 340 | if (lr->function) |
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index bc06d3e8bafa..ed362acff4b6 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h | |||
@@ -86,6 +86,7 @@ struct line_range { | |||
86 | int end; /* End line number */ | 86 | int end; /* End line number */ |
87 | int offset; /* Start line offset */ | 87 | int offset; /* Start line offset */ |
88 | char *path; /* Real path name */ | 88 | char *path; /* Real path name */ |
89 | char *comp_dir; /* Compile directory */ | ||
89 | struct list_head line_list; /* Visible lines */ | 90 | struct list_head line_list; /* Visible lines */ |
90 | }; | 91 | }; |
91 | 92 | ||
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 3e64e1fa1051..f88070ea5b90 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -58,55 +58,6 @@ static int strtailcmp(const char *s1, const char *s2) | |||
58 | return 0; | 58 | return 0; |
59 | } | 59 | } |
60 | 60 | ||
61 | /* | ||
62 | * Find a src file from a DWARF tag path. Prepend optional source path prefix | ||
63 | * and chop off leading directories that do not exist. Result is passed back as | ||
64 | * a newly allocated path on success. | ||
65 | * Return 0 if file was found and readable, -errno otherwise. | ||
66 | */ | ||
67 | static int get_real_path(const char *raw_path, char **new_path) | ||
68 | { | ||
69 | if (!symbol_conf.source_prefix) { | ||
70 | if (access(raw_path, R_OK) == 0) { | ||
71 | *new_path = strdup(raw_path); | ||
72 | return 0; | ||
73 | } else | ||
74 | return -errno; | ||
75 | } | ||
76 | |||
77 | *new_path = malloc((strlen(symbol_conf.source_prefix) + | ||
78 | strlen(raw_path) + 2)); | ||
79 | if (!*new_path) | ||
80 | return -ENOMEM; | ||
81 | |||
82 | for (;;) { | ||
83 | sprintf(*new_path, "%s/%s", symbol_conf.source_prefix, | ||
84 | raw_path); | ||
85 | |||
86 | if (access(*new_path, R_OK) == 0) | ||
87 | return 0; | ||
88 | |||
89 | switch (errno) { | ||
90 | case ENAMETOOLONG: | ||
91 | case ENOENT: | ||
92 | case EROFS: | ||
93 | case EFAULT: | ||
94 | raw_path = strchr(++raw_path, '/'); | ||
95 | if (!raw_path) { | ||
96 | free(*new_path); | ||
97 | *new_path = NULL; | ||
98 | return -ENOENT; | ||
99 | } | ||
100 | continue; | ||
101 | |||
102 | default: | ||
103 | free(*new_path); | ||
104 | *new_path = NULL; | ||
105 | return -errno; | ||
106 | } | ||
107 | } | ||
108 | } | ||
109 | |||
110 | /* Line number list operations */ | 61 | /* Line number list operations */ |
111 | 62 | ||
112 | /* Add a line to line number list */ | 63 | /* Add a line to line number list */ |
@@ -193,12 +144,21 @@ static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname) | |||
193 | return src; | 144 | return src; |
194 | } | 145 | } |
195 | 146 | ||
147 | /* Get DW_AT_comp_dir (should be NULL with older gcc) */ | ||
148 | static const char *cu_get_comp_dir(Dwarf_Die *cu_die) | ||
149 | { | ||
150 | Dwarf_Attribute attr; | ||
151 | if (dwarf_attr(cu_die, DW_AT_comp_dir, &attr) == NULL) | ||
152 | return NULL; | ||
153 | return dwarf_formstring(&attr); | ||
154 | } | ||
155 | |||
196 | /* Compare diename and tname */ | 156 | /* Compare diename and tname */ |
197 | static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) | 157 | static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) |
198 | { | 158 | { |
199 | const char *name; | 159 | const char *name; |
200 | name = dwarf_diename(dw_die); | 160 | name = dwarf_diename(dw_die); |
201 | return name ? strcmp(tname, name) : -1; | 161 | return name ? (strcmp(tname, name) == 0) : false; |
202 | } | 162 | } |
203 | 163 | ||
204 | /* Get type die, but skip qualifiers and typedef */ | 164 | /* Get type die, but skip qualifiers and typedef */ |
@@ -369,7 +329,7 @@ static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data) | |||
369 | tag = dwarf_tag(die_mem); | 329 | tag = dwarf_tag(die_mem); |
370 | if ((tag == DW_TAG_formal_parameter || | 330 | if ((tag == DW_TAG_formal_parameter || |
371 | tag == DW_TAG_variable) && | 331 | tag == DW_TAG_variable) && |
372 | (die_compare_name(die_mem, name) == 0)) | 332 | die_compare_name(die_mem, name)) |
373 | return DIE_FIND_CB_FOUND; | 333 | return DIE_FIND_CB_FOUND; |
374 | 334 | ||
375 | return DIE_FIND_CB_CONTINUE; | 335 | return DIE_FIND_CB_CONTINUE; |
@@ -388,7 +348,7 @@ static int __die_find_member_cb(Dwarf_Die *die_mem, void *data) | |||
388 | const char *name = data; | 348 | const char *name = data; |
389 | 349 | ||
390 | if ((dwarf_tag(die_mem) == DW_TAG_member) && | 350 | if ((dwarf_tag(die_mem) == DW_TAG_member) && |
391 | (die_compare_name(die_mem, name) == 0)) | 351 | die_compare_name(die_mem, name)) |
392 | return DIE_FIND_CB_FOUND; | 352 | return DIE_FIND_CB_FOUND; |
393 | 353 | ||
394 | return DIE_FIND_CB_SIBLING; | 354 | return DIE_FIND_CB_SIBLING; |
@@ -546,8 +506,8 @@ static int convert_variable_type(Dwarf_Die *vr_die, | |||
546 | return -ENOMEM; | 506 | return -ENOMEM; |
547 | } | 507 | } |
548 | } | 508 | } |
549 | if (die_compare_name(&type, "char") != 0 && | 509 | if (!die_compare_name(&type, "char") && |
550 | die_compare_name(&type, "unsigned char") != 0) { | 510 | !die_compare_name(&type, "unsigned char")) { |
551 | pr_warning("Failed to cast into string: " | 511 | pr_warning("Failed to cast into string: " |
552 | "%s is not (unsigned) char *.", | 512 | "%s is not (unsigned) char *.", |
553 | dwarf_diename(vr_die)); | 513 | dwarf_diename(vr_die)); |
@@ -1057,7 +1017,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) | |||
1057 | 1017 | ||
1058 | /* Check tag and diename */ | 1018 | /* Check tag and diename */ |
1059 | if (dwarf_tag(sp_die) != DW_TAG_subprogram || | 1019 | if (dwarf_tag(sp_die) != DW_TAG_subprogram || |
1060 | die_compare_name(sp_die, pp->function) != 0) | 1020 | !die_compare_name(sp_die, pp->function)) |
1061 | return DWARF_CB_OK; | 1021 | return DWARF_CB_OK; |
1062 | 1022 | ||
1063 | pf->fname = dwarf_decl_file(sp_die); | 1023 | pf->fname = dwarf_decl_file(sp_die); |
@@ -1256,13 +1216,11 @@ end: | |||
1256 | static int line_range_add_line(const char *src, unsigned int lineno, | 1216 | static int line_range_add_line(const char *src, unsigned int lineno, |
1257 | struct line_range *lr) | 1217 | struct line_range *lr) |
1258 | { | 1218 | { |
1259 | int ret; | 1219 | /* Copy source path */ |
1260 | |||
1261 | /* Copy real path */ | ||
1262 | if (!lr->path) { | 1220 | if (!lr->path) { |
1263 | ret = get_real_path(src, &lr->path); | 1221 | lr->path = strdup(src); |
1264 | if (ret != 0) | 1222 | if (lr->path == NULL) |
1265 | return ret; | 1223 | return -ENOMEM; |
1266 | } | 1224 | } |
1267 | return line_list__add_line(&lr->line_list, lineno); | 1225 | return line_list__add_line(&lr->line_list, lineno); |
1268 | } | 1226 | } |
@@ -1382,7 +1340,7 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data) | |||
1382 | struct line_range *lr = lf->lr; | 1340 | struct line_range *lr = lf->lr; |
1383 | 1341 | ||
1384 | if (dwarf_tag(sp_die) == DW_TAG_subprogram && | 1342 | if (dwarf_tag(sp_die) == DW_TAG_subprogram && |
1385 | die_compare_name(sp_die, lr->function) == 0) { | 1343 | die_compare_name(sp_die, lr->function)) { |
1386 | lf->fname = dwarf_decl_file(sp_die); | 1344 | lf->fname = dwarf_decl_file(sp_die); |
1387 | dwarf_decl_line(sp_die, &lr->offset); | 1345 | dwarf_decl_line(sp_die, &lr->offset); |
1388 | pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); | 1346 | pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); |
@@ -1425,6 +1383,7 @@ int find_line_range(int fd, struct line_range *lr) | |||
1425 | size_t cuhl; | 1383 | size_t cuhl; |
1426 | Dwarf_Die *diep; | 1384 | Dwarf_Die *diep; |
1427 | Dwarf *dbg; | 1385 | Dwarf *dbg; |
1386 | const char *comp_dir; | ||
1428 | 1387 | ||
1429 | dbg = dwarf_begin(fd, DWARF_C_READ); | 1388 | dbg = dwarf_begin(fd, DWARF_C_READ); |
1430 | if (!dbg) { | 1389 | if (!dbg) { |
@@ -1460,7 +1419,18 @@ int find_line_range(int fd, struct line_range *lr) | |||
1460 | } | 1419 | } |
1461 | off = noff; | 1420 | off = noff; |
1462 | } | 1421 | } |
1463 | pr_debug("path: %lx\n", (unsigned long)lr->path); | 1422 | |
1423 | /* Store comp_dir */ | ||
1424 | if (lf.found) { | ||
1425 | comp_dir = cu_get_comp_dir(&lf.cu_die); | ||
1426 | if (comp_dir) { | ||
1427 | lr->comp_dir = strdup(comp_dir); | ||
1428 | if (!lr->comp_dir) | ||
1429 | ret = -ENOMEM; | ||
1430 | } | ||
1431 | } | ||
1432 | |||
1433 | pr_debug("path: %s\n", lr->path); | ||
1464 | dwarf_end(dbg); | 1434 | dwarf_end(dbg); |
1465 | 1435 | ||
1466 | return (ret < 0) ? ret : lf.found; | 1436 | return (ret < 0) ? ret : lf.found; |