aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/arch/sh/Makefile4
-rw-r--r--tools/perf/arch/sh/util/dwarf-regs.c55
-rw-r--r--tools/perf/util/probe-event.c69
-rw-r--r--tools/perf/util/probe-event.h1
-rw-r--r--tools/perf/util/probe-finder.c96
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 @@
1ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1
3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
4endif
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
30const 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) */
52const 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 */
204static 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 */
67static 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) */
148static 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 */
197static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) 157static 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:
1256static int line_range_add_line(const char *src, unsigned int lineno, 1216static 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;