aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/probe-event.c
diff options
context:
space:
mode:
authorMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>2010-10-21 06:13:41 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2010-10-21 14:11:44 -0400
commit469b9b88488e89114bb3e9ac5ee7906b7b96123f (patch)
tree9f002195a8b1167eddbe560ac834e6ba2dedb19f /tools/perf/util/probe-event.c
parentfb8c5a56c7ddbc2b0d2ee7a8da60fe1355f75141 (diff)
perf probe: Add basic module support
Add basic module probe support on perf probe. This introduces "--module <MODNAME>" option to perf probe for putting probes and showing lines and variables in the given module. Currently, this supports only probing on running modules. Supporting off-line module probing is the next step. e.g.) [show lines] # ./perf probe --module drm -L drm_vblank_info <drm_vblank_info:0> 0 int drm_vblank_info(struct seq_file *m, void *data) 1 { struct drm_info_node *node = (struct drm_info_node *) m->private 3 struct drm_device *dev = node->minor->dev; ... [show vars] # ./perf probe --module drm -V drm_vblank_info:3 Available variables at drm_vblank_info:3 @<drm_vblank_info+20> (unknown_type) data struct drm_info_node* node struct seq_file* m [put a probe] # ./perf probe --module drm drm_vblank_info:3 node m Add new event: probe:drm_vblank_info (on drm_vblank_info:3 with node m) You can now use it on all perf tools, such as: perf record -e probe:drm_vblank_info -aR sleep 1 [list probes] # ./perf probe -l probe:drm_vblank_info (on drm_vblank_info:3@drivers/gpu/drm/drm_info.c with ... Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Paul Mackerras <paulus@samba.org> Cc: Ingo Molnar <mingo@elte.hu> Cc: Frederic Weisbecker <fweisbec@gmail.com> LKML-Reference: <20101021101341.3542.71638.stgit@ltc236.sdl.hitachi.co.jp> Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/util/probe-event.c')
-rw-r--r--tools/perf/util/probe-event.c123
1 files changed, 79 insertions, 44 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 82b0976e2053..3b6a5297bf16 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -74,10 +74,9 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
74static char *synthesize_perf_probe_point(struct perf_probe_point *pp); 74static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
75static struct machine machine; 75static struct machine machine;
76 76
77/* Initialize symbol maps and path of vmlinux */ 77/* Initialize symbol maps and path of vmlinux/modules */
78static int init_vmlinux(void) 78static int init_vmlinux(void)
79{ 79{
80 struct dso *kernel;
81 int ret; 80 int ret;
82 81
83 symbol_conf.sort_by_name = true; 82 symbol_conf.sort_by_name = true;
@@ -91,33 +90,61 @@ static int init_vmlinux(void)
91 goto out; 90 goto out;
92 } 91 }
93 92
94 ret = machine__init(&machine, "/", 0); 93 ret = machine__init(&machine, "", HOST_KERNEL_ID);
95 if (ret < 0) 94 if (ret < 0)
96 goto out; 95 goto out;
97 96
98 kernel = dso__new_kernel(symbol_conf.vmlinux_name); 97 if (machine__create_kernel_maps(&machine) < 0) {
99 if (kernel == NULL) 98 pr_debug("machine__create_kernel_maps ");
100 die("Failed to create kernel dso."); 99 goto out;
101 100 }
102 ret = __machine__create_kernel_maps(&machine, kernel);
103 if (ret < 0)
104 pr_debug("Failed to create kernel maps.\n");
105
106out: 101out:
107 if (ret < 0) 102 if (ret < 0)
108 pr_warning("Failed to init vmlinux path.\n"); 103 pr_warning("Failed to init vmlinux path.\n");
109 return ret; 104 return ret;
110} 105}
111 106
107static struct symbol *__find_kernel_function_by_name(const char *name,
108 struct map **mapp)
109{
110 return machine__find_kernel_function_by_name(&machine, name, mapp,
111 NULL);
112}
113
114const char *kernel_get_module_path(const char *module)
115{
116 struct dso *dso;
117
118 if (module) {
119 list_for_each_entry(dso, &machine.kernel_dsos, node) {
120 if (strncmp(dso->short_name + 1, module,
121 dso->short_name_len - 2) == 0)
122 goto found;
123 }
124 pr_debug("Failed to find module %s.\n", module);
125 return NULL;
126 } else {
127 dso = machine.vmlinux_maps[MAP__FUNCTION]->dso;
128 if (dso__load_vmlinux_path(dso,
129 machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) {
130 pr_debug("Failed to load kernel map.\n");
131 return NULL;
132 }
133 }
134found:
135 return dso->long_name;
136}
137
112#ifdef DWARF_SUPPORT 138#ifdef DWARF_SUPPORT
113static int open_vmlinux(void) 139static int open_vmlinux(const char *module)
114{ 140{
115 if (map__load(machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) { 141 const char *path = kernel_get_module_path(module);
116 pr_debug("Failed to load kernel map.\n"); 142 if (!path) {
117 return -EINVAL; 143 pr_err("Failed to find path of %s module", module ?: "kernel");
144 return -ENOENT;
118 } 145 }
119 pr_debug("Try to open %s\n", machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name); 146 pr_debug("Try to open %s\n", path);
120 return open(machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name, O_RDONLY); 147 return open(path, O_RDONLY);
121} 148}
122 149
123/* 150/*
@@ -125,20 +152,19 @@ static int open_vmlinux(void)
125 * Currently only handles kprobes. 152 * Currently only handles kprobes.
126 */ 153 */
127static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, 154static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
128 struct perf_probe_point *pp) 155 struct perf_probe_point *pp)
129{ 156{
130 struct symbol *sym; 157 struct symbol *sym;
131 int fd, ret = -ENOENT; 158 struct map *map;
159 u64 addr;
160 int ret = -ENOENT;
132 161
133 sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION], 162 sym = __find_kernel_function_by_name(tp->symbol, &map);
134 tp->symbol, NULL);
135 if (sym) { 163 if (sym) {
136 fd = open_vmlinux(); 164 addr = map->unmap_ip(map, sym->start + tp->offset);
137 if (fd >= 0) { 165 pr_debug("try to find %s+%ld@%llx\n", tp->symbol,
138 ret = find_perf_probe_point(fd, 166 tp->offset, addr);
139 sym->start + tp->offset, pp); 167 ret = find_perf_probe_point((unsigned long)addr, pp);
140 close(fd);
141 }
142 } 168 }
143 if (ret <= 0) { 169 if (ret <= 0) {
144 pr_debug("Failed to find corresponding probes from " 170 pr_debug("Failed to find corresponding probes from "
@@ -156,12 +182,12 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
156/* Try to find perf_probe_event with debuginfo */ 182/* Try to find perf_probe_event with debuginfo */
157static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 183static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
158 struct probe_trace_event **tevs, 184 struct probe_trace_event **tevs,
159 int max_tevs) 185 int max_tevs, const char *module)
160{ 186{
161 bool need_dwarf = perf_probe_event_need_dwarf(pev); 187 bool need_dwarf = perf_probe_event_need_dwarf(pev);
162 int fd, ntevs; 188 int fd, ntevs;
163 189
164 fd = open_vmlinux(); 190 fd = open_vmlinux(module);
165 if (fd < 0) { 191 if (fd < 0) {
166 if (need_dwarf) { 192 if (need_dwarf) {
167 pr_warning("Failed to open debuginfo file.\n"); 193 pr_warning("Failed to open debuginfo file.\n");
@@ -300,7 +326,7 @@ error:
300 * Show line-range always requires debuginfo to find source file and 326 * Show line-range always requires debuginfo to find source file and
301 * line number. 327 * line number.
302 */ 328 */
303int show_line_range(struct line_range *lr) 329int show_line_range(struct line_range *lr, const char *module)
304{ 330{
305 int l = 1; 331 int l = 1;
306 struct line_node *ln; 332 struct line_node *ln;
@@ -313,7 +339,7 @@ int show_line_range(struct line_range *lr)
313 if (ret < 0) 339 if (ret < 0)
314 return ret; 340 return ret;
315 341
316 fd = open_vmlinux(); 342 fd = open_vmlinux(module);
317 if (fd < 0) { 343 if (fd < 0) {
318 pr_warning("Failed to open debuginfo file.\n"); 344 pr_warning("Failed to open debuginfo file.\n");
319 return fd; 345 return fd;
@@ -421,7 +447,7 @@ static int show_available_vars_at(int fd, struct perf_probe_event *pev,
421 447
422/* Show available variables on given probe point */ 448/* Show available variables on given probe point */
423int show_available_vars(struct perf_probe_event *pevs, int npevs, 449int show_available_vars(struct perf_probe_event *pevs, int npevs,
424 int max_vls, bool externs) 450 int max_vls, const char *module, bool externs)
425{ 451{
426 int i, fd, ret = 0; 452 int i, fd, ret = 0;
427 453
@@ -429,7 +455,7 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
429 if (ret < 0) 455 if (ret < 0)
430 return ret; 456 return ret;
431 457
432 fd = open_vmlinux(); 458 fd = open_vmlinux(module);
433 if (fd < 0) { 459 if (fd < 0) {
434 pr_warning("Failed to open debuginfo file.\n"); 460 pr_warning("Failed to open debuginfo file.\n");
435 return fd; 461 return fd;
@@ -447,8 +473,15 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
447#else /* !DWARF_SUPPORT */ 473#else /* !DWARF_SUPPORT */
448 474
449static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, 475static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
450 struct perf_probe_point *pp) 476 struct perf_probe_point *pp)
451{ 477{
478 struct symbol *sym;
479
480 sym = __find_kernel_function_by_name(tp->symbol, NULL);
481 if (!sym) {
482 pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);
483 return -ENOENT;
484 }
452 pp->function = strdup(tp->symbol); 485 pp->function = strdup(tp->symbol);
453 if (pp->function == NULL) 486 if (pp->function == NULL)
454 return -ENOMEM; 487 return -ENOMEM;
@@ -460,7 +493,7 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
460 493
461static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 494static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
462 struct probe_trace_event **tevs __unused, 495 struct probe_trace_event **tevs __unused,
463 int max_tevs __unused) 496 int max_tevs __unused, const char *mod __unused)
464{ 497{
465 if (perf_probe_event_need_dwarf(pev)) { 498 if (perf_probe_event_need_dwarf(pev)) {
466 pr_warning("Debuginfo-analysis is not supported.\n"); 499 pr_warning("Debuginfo-analysis is not supported.\n");
@@ -469,14 +502,15 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
469 return 0; 502 return 0;
470} 503}
471 504
472int show_line_range(struct line_range *lr __unused) 505int show_line_range(struct line_range *lr __unused, const char *module __unused)
473{ 506{
474 pr_warning("Debuginfo-analysis is not supported.\n"); 507 pr_warning("Debuginfo-analysis is not supported.\n");
475 return -ENOSYS; 508 return -ENOSYS;
476} 509}
477 510
478int show_available_vars(struct perf_probe_event *pevs __unused, 511int show_available_vars(struct perf_probe_event *pevs __unused,
479 int npevs __unused, int max_probe_points __unused) 512 int npevs __unused, int max_vls __unused,
513 const char *module __unused, bool externs __unused)
480{ 514{
481 pr_warning("Debuginfo-analysis is not supported.\n"); 515 pr_warning("Debuginfo-analysis is not supported.\n");
482 return -ENOSYS; 516 return -ENOSYS;
@@ -1159,7 +1193,7 @@ error:
1159} 1193}
1160 1194
1161static int convert_to_perf_probe_event(struct probe_trace_event *tev, 1195static int convert_to_perf_probe_event(struct probe_trace_event *tev,
1162 struct perf_probe_event *pev) 1196 struct perf_probe_event *pev)
1163{ 1197{
1164 char buf[64] = ""; 1198 char buf[64] = "";
1165 int i, ret; 1199 int i, ret;
@@ -1588,14 +1622,14 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
1588 1622
1589static int convert_to_probe_trace_events(struct perf_probe_event *pev, 1623static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1590 struct probe_trace_event **tevs, 1624 struct probe_trace_event **tevs,
1591 int max_tevs) 1625 int max_tevs, const char *module)
1592{ 1626{
1593 struct symbol *sym; 1627 struct symbol *sym;
1594 int ret = 0, i; 1628 int ret = 0, i;
1595 struct probe_trace_event *tev; 1629 struct probe_trace_event *tev;
1596 1630
1597 /* Convert perf_probe_event with debuginfo */ 1631 /* Convert perf_probe_event with debuginfo */
1598 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs); 1632 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, module);
1599 if (ret != 0) 1633 if (ret != 0)
1600 return ret; 1634 return ret;
1601 1635
@@ -1644,8 +1678,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1644 } 1678 }
1645 1679
1646 /* Currently just checking function name from symbol map */ 1680 /* Currently just checking function name from symbol map */
1647 sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION], 1681 sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
1648 tev->point.symbol, NULL);
1649 if (!sym) { 1682 if (!sym) {
1650 pr_warning("Kernel symbol \'%s\' not found.\n", 1683 pr_warning("Kernel symbol \'%s\' not found.\n",
1651 tev->point.symbol); 1684 tev->point.symbol);
@@ -1668,7 +1701,7 @@ struct __event_package {
1668}; 1701};
1669 1702
1670int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, 1703int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1671 int max_tevs, bool force_add) 1704 int max_tevs, const char *module, bool force_add)
1672{ 1705{
1673 int i, j, ret; 1706 int i, j, ret;
1674 struct __event_package *pkgs; 1707 struct __event_package *pkgs;
@@ -1689,7 +1722,9 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1689 pkgs[i].pev = &pevs[i]; 1722 pkgs[i].pev = &pevs[i];
1690 /* Convert with or without debuginfo */ 1723 /* Convert with or without debuginfo */
1691 ret = convert_to_probe_trace_events(pkgs[i].pev, 1724 ret = convert_to_probe_trace_events(pkgs[i].pev,
1692 &pkgs[i].tevs, max_tevs); 1725 &pkgs[i].tevs,
1726 max_tevs,
1727 module);
1693 if (ret < 0) 1728 if (ret < 0)
1694 goto end; 1729 goto end;
1695 pkgs[i].ntevs = ret; 1730 pkgs[i].ntevs = ret;