diff options
Diffstat (limited to 'tools/perf/util/probe-event.c')
-rw-r--r-- | tools/perf/util/probe-event.c | 189 |
1 files changed, 148 insertions, 41 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index fcc16e4349df..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, ...) | |||
74 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp); | 74 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp); |
75 | static struct machine machine; | 75 | static struct machine machine; |
76 | 76 | ||
77 | /* Initialize symbol maps and path of vmlinux */ | 77 | /* Initialize symbol maps and path of vmlinux/modules */ |
78 | static int init_vmlinux(void) | 78 | static 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 | |||
106 | out: | 101 | out: |
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 | ||
107 | static 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 | |||
114 | const 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 | } | ||
134 | found: | ||
135 | return dso->long_name; | ||
136 | } | ||
137 | |||
112 | #ifdef DWARF_SUPPORT | 138 | #ifdef DWARF_SUPPORT |
113 | static int open_vmlinux(void) | 139 | static 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 | */ |
127 | static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, | 154 | static 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 */ |
157 | static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | 183 | static 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 | */ |
303 | int show_line_range(struct line_range *lr) | 329 | int 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; |
@@ -378,11 +404,84 @@ end: | |||
378 | return ret; | 404 | return ret; |
379 | } | 405 | } |
380 | 406 | ||
407 | static int show_available_vars_at(int fd, struct perf_probe_event *pev, | ||
408 | int max_vls, bool externs) | ||
409 | { | ||
410 | char *buf; | ||
411 | int ret, i; | ||
412 | struct str_node *node; | ||
413 | struct variable_list *vls = NULL, *vl; | ||
414 | |||
415 | buf = synthesize_perf_probe_point(&pev->point); | ||
416 | if (!buf) | ||
417 | return -EINVAL; | ||
418 | pr_debug("Searching variables at %s\n", buf); | ||
419 | |||
420 | ret = find_available_vars_at(fd, pev, &vls, max_vls, externs); | ||
421 | if (ret > 0) { | ||
422 | /* Some variables were found */ | ||
423 | fprintf(stdout, "Available variables at %s\n", buf); | ||
424 | for (i = 0; i < ret; i++) { | ||
425 | vl = &vls[i]; | ||
426 | /* | ||
427 | * A probe point might be converted to | ||
428 | * several trace points. | ||
429 | */ | ||
430 | fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol, | ||
431 | vl->point.offset); | ||
432 | free(vl->point.symbol); | ||
433 | if (vl->vars) { | ||
434 | strlist__for_each(node, vl->vars) | ||
435 | fprintf(stdout, "\t\t%s\n", node->s); | ||
436 | strlist__delete(vl->vars); | ||
437 | } else | ||
438 | fprintf(stdout, "(No variables)\n"); | ||
439 | } | ||
440 | free(vls); | ||
441 | } else | ||
442 | pr_err("Failed to find variables at %s (%d)\n", buf, ret); | ||
443 | |||
444 | free(buf); | ||
445 | return ret; | ||
446 | } | ||
447 | |||
448 | /* Show available variables on given probe point */ | ||
449 | int show_available_vars(struct perf_probe_event *pevs, int npevs, | ||
450 | int max_vls, const char *module, bool externs) | ||
451 | { | ||
452 | int i, fd, ret = 0; | ||
453 | |||
454 | ret = init_vmlinux(); | ||
455 | if (ret < 0) | ||
456 | return ret; | ||
457 | |||
458 | fd = open_vmlinux(module); | ||
459 | if (fd < 0) { | ||
460 | pr_warning("Failed to open debuginfo file.\n"); | ||
461 | return fd; | ||
462 | } | ||
463 | |||
464 | setup_pager(); | ||
465 | |||
466 | for (i = 0; i < npevs && ret >= 0; i++) | ||
467 | ret = show_available_vars_at(fd, &pevs[i], max_vls, externs); | ||
468 | |||
469 | close(fd); | ||
470 | return ret; | ||
471 | } | ||
472 | |||
381 | #else /* !DWARF_SUPPORT */ | 473 | #else /* !DWARF_SUPPORT */ |
382 | 474 | ||
383 | static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, | 475 | static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, |
384 | struct perf_probe_point *pp) | 476 | struct perf_probe_point *pp) |
385 | { | 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 | } | ||
386 | pp->function = strdup(tp->symbol); | 485 | pp->function = strdup(tp->symbol); |
387 | if (pp->function == NULL) | 486 | if (pp->function == NULL) |
388 | return -ENOMEM; | 487 | return -ENOMEM; |
@@ -394,7 +493,7 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, | |||
394 | 493 | ||
395 | static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | 494 | static int try_to_find_probe_trace_events(struct perf_probe_event *pev, |
396 | struct probe_trace_event **tevs __unused, | 495 | struct probe_trace_event **tevs __unused, |
397 | int max_tevs __unused) | 496 | int max_tevs __unused, const char *mod __unused) |
398 | { | 497 | { |
399 | if (perf_probe_event_need_dwarf(pev)) { | 498 | if (perf_probe_event_need_dwarf(pev)) { |
400 | pr_warning("Debuginfo-analysis is not supported.\n"); | 499 | pr_warning("Debuginfo-analysis is not supported.\n"); |
@@ -403,12 +502,19 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | |||
403 | return 0; | 502 | return 0; |
404 | } | 503 | } |
405 | 504 | ||
406 | int show_line_range(struct line_range *lr __unused) | 505 | int show_line_range(struct line_range *lr __unused, const char *module __unused) |
407 | { | 506 | { |
408 | pr_warning("Debuginfo-analysis is not supported.\n"); | 507 | pr_warning("Debuginfo-analysis is not supported.\n"); |
409 | return -ENOSYS; | 508 | return -ENOSYS; |
410 | } | 509 | } |
411 | 510 | ||
511 | int show_available_vars(struct perf_probe_event *pevs __unused, | ||
512 | int npevs __unused, int max_vls __unused, | ||
513 | const char *module __unused, bool externs __unused) | ||
514 | { | ||
515 | pr_warning("Debuginfo-analysis is not supported.\n"); | ||
516 | return -ENOSYS; | ||
517 | } | ||
412 | #endif | 518 | #endif |
413 | 519 | ||
414 | int parse_line_range_desc(const char *arg, struct line_range *lr) | 520 | int parse_line_range_desc(const char *arg, struct line_range *lr) |
@@ -1087,7 +1193,7 @@ error: | |||
1087 | } | 1193 | } |
1088 | 1194 | ||
1089 | static int convert_to_perf_probe_event(struct probe_trace_event *tev, | 1195 | static int convert_to_perf_probe_event(struct probe_trace_event *tev, |
1090 | struct perf_probe_event *pev) | 1196 | struct perf_probe_event *pev) |
1091 | { | 1197 | { |
1092 | char buf[64] = ""; | 1198 | char buf[64] = ""; |
1093 | int i, ret; | 1199 | int i, ret; |
@@ -1516,14 +1622,14 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, | |||
1516 | 1622 | ||
1517 | static int convert_to_probe_trace_events(struct perf_probe_event *pev, | 1623 | static int convert_to_probe_trace_events(struct perf_probe_event *pev, |
1518 | struct probe_trace_event **tevs, | 1624 | struct probe_trace_event **tevs, |
1519 | int max_tevs) | 1625 | int max_tevs, const char *module) |
1520 | { | 1626 | { |
1521 | struct symbol *sym; | 1627 | struct symbol *sym; |
1522 | int ret = 0, i; | 1628 | int ret = 0, i; |
1523 | struct probe_trace_event *tev; | 1629 | struct probe_trace_event *tev; |
1524 | 1630 | ||
1525 | /* Convert perf_probe_event with debuginfo */ | 1631 | /* Convert perf_probe_event with debuginfo */ |
1526 | ret = try_to_find_probe_trace_events(pev, tevs, max_tevs); | 1632 | ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, module); |
1527 | if (ret != 0) | 1633 | if (ret != 0) |
1528 | return ret; | 1634 | return ret; |
1529 | 1635 | ||
@@ -1572,8 +1678,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, | |||
1572 | } | 1678 | } |
1573 | 1679 | ||
1574 | /* Currently just checking function name from symbol map */ | 1680 | /* Currently just checking function name from symbol map */ |
1575 | sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION], | 1681 | sym = __find_kernel_function_by_name(tev->point.symbol, NULL); |
1576 | tev->point.symbol, NULL); | ||
1577 | if (!sym) { | 1682 | if (!sym) { |
1578 | pr_warning("Kernel symbol \'%s\' not found.\n", | 1683 | pr_warning("Kernel symbol \'%s\' not found.\n", |
1579 | tev->point.symbol); | 1684 | tev->point.symbol); |
@@ -1596,7 +1701,7 @@ struct __event_package { | |||
1596 | }; | 1701 | }; |
1597 | 1702 | ||
1598 | int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, | 1703 | int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, |
1599 | bool force_add, int max_tevs) | 1704 | int max_tevs, const char *module, bool force_add) |
1600 | { | 1705 | { |
1601 | int i, j, ret; | 1706 | int i, j, ret; |
1602 | struct __event_package *pkgs; | 1707 | struct __event_package *pkgs; |
@@ -1617,7 +1722,9 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, | |||
1617 | pkgs[i].pev = &pevs[i]; | 1722 | pkgs[i].pev = &pevs[i]; |
1618 | /* Convert with or without debuginfo */ | 1723 | /* Convert with or without debuginfo */ |
1619 | ret = convert_to_probe_trace_events(pkgs[i].pev, | 1724 | ret = convert_to_probe_trace_events(pkgs[i].pev, |
1620 | &pkgs[i].tevs, max_tevs); | 1725 | &pkgs[i].tevs, |
1726 | max_tevs, | ||
1727 | module); | ||
1621 | if (ret < 0) | 1728 | if (ret < 0) |
1622 | goto end; | 1729 | goto end; |
1623 | pkgs[i].ntevs = ret; | 1730 | pkgs[i].ntevs = ret; |