diff options
Diffstat (limited to 'tools/perf/util/probe-event.c')
-rw-r--r-- | tools/perf/util/probe-event.c | 173 |
1 files changed, 131 insertions, 42 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index f0223166e76..eb25900e221 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -117,6 +117,10 @@ static struct map *kernel_get_module_map(const char *module) | |||
117 | struct rb_node *nd; | 117 | struct rb_node *nd; |
118 | struct map_groups *grp = &machine.kmaps; | 118 | struct map_groups *grp = &machine.kmaps; |
119 | 119 | ||
120 | /* A file path -- this is an offline module */ | ||
121 | if (module && strchr(module, '/')) | ||
122 | return machine__new_module(&machine, 0, module); | ||
123 | |||
120 | if (!module) | 124 | if (!module) |
121 | module = "kernel"; | 125 | module = "kernel"; |
122 | 126 | ||
@@ -170,16 +174,24 @@ const char *kernel_get_module_path(const char *module) | |||
170 | } | 174 | } |
171 | 175 | ||
172 | #ifdef DWARF_SUPPORT | 176 | #ifdef DWARF_SUPPORT |
173 | static int open_vmlinux(const char *module) | 177 | /* Open new debuginfo of given module */ |
178 | static struct debuginfo *open_debuginfo(const char *module) | ||
174 | { | 179 | { |
175 | const char *path = kernel_get_module_path(module); | 180 | const char *path; |
176 | if (!path) { | 181 | |
177 | pr_err("Failed to find path of %s module.\n", | 182 | /* A file path -- this is an offline module */ |
178 | module ?: "kernel"); | 183 | if (module && strchr(module, '/')) |
179 | return -ENOENT; | 184 | path = module; |
185 | else { | ||
186 | path = kernel_get_module_path(module); | ||
187 | |||
188 | if (!path) { | ||
189 | pr_err("Failed to find path of %s module.\n", | ||
190 | module ?: "kernel"); | ||
191 | return NULL; | ||
192 | } | ||
180 | } | 193 | } |
181 | pr_debug("Try to open %s\n", path); | 194 | return debuginfo__new(path); |
182 | return open(path, O_RDONLY); | ||
183 | } | 195 | } |
184 | 196 | ||
185 | /* | 197 | /* |
@@ -193,13 +205,24 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, | |||
193 | struct map *map; | 205 | struct map *map; |
194 | u64 addr; | 206 | u64 addr; |
195 | int ret = -ENOENT; | 207 | int ret = -ENOENT; |
208 | struct debuginfo *dinfo; | ||
196 | 209 | ||
197 | sym = __find_kernel_function_by_name(tp->symbol, &map); | 210 | sym = __find_kernel_function_by_name(tp->symbol, &map); |
198 | if (sym) { | 211 | if (sym) { |
199 | addr = map->unmap_ip(map, sym->start + tp->offset); | 212 | addr = map->unmap_ip(map, sym->start + tp->offset); |
200 | pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol, | 213 | pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol, |
201 | tp->offset, addr); | 214 | tp->offset, addr); |
202 | ret = find_perf_probe_point((unsigned long)addr, pp); | 215 | |
216 | dinfo = debuginfo__new_online_kernel(addr); | ||
217 | if (dinfo) { | ||
218 | ret = debuginfo__find_probe_point(dinfo, | ||
219 | (unsigned long)addr, pp); | ||
220 | debuginfo__delete(dinfo); | ||
221 | } else { | ||
222 | pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n", | ||
223 | addr); | ||
224 | ret = -ENOENT; | ||
225 | } | ||
203 | } | 226 | } |
204 | if (ret <= 0) { | 227 | if (ret <= 0) { |
205 | pr_debug("Failed to find corresponding probes from " | 228 | pr_debug("Failed to find corresponding probes from " |
@@ -214,30 +237,70 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, | |||
214 | return 0; | 237 | return 0; |
215 | } | 238 | } |
216 | 239 | ||
240 | static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, | ||
241 | int ntevs, const char *module) | ||
242 | { | ||
243 | int i, ret = 0; | ||
244 | char *tmp; | ||
245 | |||
246 | if (!module) | ||
247 | return 0; | ||
248 | |||
249 | tmp = strrchr(module, '/'); | ||
250 | if (tmp) { | ||
251 | /* This is a module path -- get the module name */ | ||
252 | module = strdup(tmp + 1); | ||
253 | if (!module) | ||
254 | return -ENOMEM; | ||
255 | tmp = strchr(module, '.'); | ||
256 | if (tmp) | ||
257 | *tmp = '\0'; | ||
258 | tmp = (char *)module; /* For free() */ | ||
259 | } | ||
260 | |||
261 | for (i = 0; i < ntevs; i++) { | ||
262 | tevs[i].point.module = strdup(module); | ||
263 | if (!tevs[i].point.module) { | ||
264 | ret = -ENOMEM; | ||
265 | break; | ||
266 | } | ||
267 | } | ||
268 | |||
269 | if (tmp) | ||
270 | free(tmp); | ||
271 | |||
272 | return ret; | ||
273 | } | ||
274 | |||
217 | /* Try to find perf_probe_event with debuginfo */ | 275 | /* Try to find perf_probe_event with debuginfo */ |
218 | static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | 276 | static int try_to_find_probe_trace_events(struct perf_probe_event *pev, |
219 | struct probe_trace_event **tevs, | 277 | struct probe_trace_event **tevs, |
220 | int max_tevs, const char *module) | 278 | int max_tevs, const char *module) |
221 | { | 279 | { |
222 | bool need_dwarf = perf_probe_event_need_dwarf(pev); | 280 | bool need_dwarf = perf_probe_event_need_dwarf(pev); |
223 | int fd, ntevs; | 281 | struct debuginfo *dinfo = open_debuginfo(module); |
282 | int ntevs, ret = 0; | ||
224 | 283 | ||
225 | fd = open_vmlinux(module); | 284 | if (!dinfo) { |
226 | if (fd < 0) { | ||
227 | if (need_dwarf) { | 285 | if (need_dwarf) { |
228 | pr_warning("Failed to open debuginfo file.\n"); | 286 | pr_warning("Failed to open debuginfo file.\n"); |
229 | return fd; | 287 | return -ENOENT; |
230 | } | 288 | } |
231 | pr_debug("Could not open vmlinux. Try to use symbols.\n"); | 289 | pr_debug("Could not open debuginfo. Try to use symbols.\n"); |
232 | return 0; | 290 | return 0; |
233 | } | 291 | } |
234 | 292 | ||
235 | /* Searching trace events corresponding to probe event */ | 293 | /* Searching trace events corresponding to a probe event */ |
236 | ntevs = find_probe_trace_events(fd, pev, tevs, max_tevs); | 294 | ntevs = debuginfo__find_trace_events(dinfo, pev, tevs, max_tevs); |
295 | |||
296 | debuginfo__delete(dinfo); | ||
237 | 297 | ||
238 | if (ntevs > 0) { /* Succeeded to find trace events */ | 298 | if (ntevs > 0) { /* Succeeded to find trace events */ |
239 | pr_debug("find %d probe_trace_events.\n", ntevs); | 299 | pr_debug("find %d probe_trace_events.\n", ntevs); |
240 | return ntevs; | 300 | if (module) |
301 | ret = add_module_to_probe_trace_events(*tevs, ntevs, | ||
302 | module); | ||
303 | return ret < 0 ? ret : ntevs; | ||
241 | } | 304 | } |
242 | 305 | ||
243 | if (ntevs == 0) { /* No error but failed to find probe point. */ | 306 | if (ntevs == 0) { /* No error but failed to find probe point. */ |
@@ -371,8 +434,9 @@ int show_line_range(struct line_range *lr, const char *module) | |||
371 | { | 434 | { |
372 | int l = 1; | 435 | int l = 1; |
373 | struct line_node *ln; | 436 | struct line_node *ln; |
437 | struct debuginfo *dinfo; | ||
374 | FILE *fp; | 438 | FILE *fp; |
375 | int fd, ret; | 439 | int ret; |
376 | char *tmp; | 440 | char *tmp; |
377 | 441 | ||
378 | /* Search a line range */ | 442 | /* Search a line range */ |
@@ -380,13 +444,14 @@ int show_line_range(struct line_range *lr, const char *module) | |||
380 | if (ret < 0) | 444 | if (ret < 0) |
381 | return ret; | 445 | return ret; |
382 | 446 | ||
383 | fd = open_vmlinux(module); | 447 | dinfo = open_debuginfo(module); |
384 | if (fd < 0) { | 448 | if (!dinfo) { |
385 | pr_warning("Failed to open debuginfo file.\n"); | 449 | pr_warning("Failed to open debuginfo file.\n"); |
386 | return fd; | 450 | return -ENOENT; |
387 | } | 451 | } |
388 | 452 | ||
389 | ret = find_line_range(fd, lr); | 453 | ret = debuginfo__find_line_range(dinfo, lr); |
454 | debuginfo__delete(dinfo); | ||
390 | if (ret == 0) { | 455 | if (ret == 0) { |
391 | pr_warning("Specified source line is not found.\n"); | 456 | pr_warning("Specified source line is not found.\n"); |
392 | return -ENOENT; | 457 | return -ENOENT; |
@@ -448,7 +513,8 @@ end: | |||
448 | return ret; | 513 | return ret; |
449 | } | 514 | } |
450 | 515 | ||
451 | static int show_available_vars_at(int fd, struct perf_probe_event *pev, | 516 | static int show_available_vars_at(struct debuginfo *dinfo, |
517 | struct perf_probe_event *pev, | ||
452 | int max_vls, struct strfilter *_filter, | 518 | int max_vls, struct strfilter *_filter, |
453 | bool externs) | 519 | bool externs) |
454 | { | 520 | { |
@@ -463,7 +529,8 @@ static int show_available_vars_at(int fd, struct perf_probe_event *pev, | |||
463 | return -EINVAL; | 529 | return -EINVAL; |
464 | pr_debug("Searching variables at %s\n", buf); | 530 | pr_debug("Searching variables at %s\n", buf); |
465 | 531 | ||
466 | ret = find_available_vars_at(fd, pev, &vls, max_vls, externs); | 532 | ret = debuginfo__find_available_vars_at(dinfo, pev, &vls, |
533 | max_vls, externs); | ||
467 | if (ret <= 0) { | 534 | if (ret <= 0) { |
468 | pr_err("Failed to find variables at %s (%d)\n", buf, ret); | 535 | pr_err("Failed to find variables at %s (%d)\n", buf, ret); |
469 | goto end; | 536 | goto end; |
@@ -504,24 +571,26 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs, | |||
504 | int max_vls, const char *module, | 571 | int max_vls, const char *module, |
505 | struct strfilter *_filter, bool externs) | 572 | struct strfilter *_filter, bool externs) |
506 | { | 573 | { |
507 | int i, fd, ret = 0; | 574 | int i, ret = 0; |
575 | struct debuginfo *dinfo; | ||
508 | 576 | ||
509 | ret = init_vmlinux(); | 577 | ret = init_vmlinux(); |
510 | if (ret < 0) | 578 | if (ret < 0) |
511 | return ret; | 579 | return ret; |
512 | 580 | ||
581 | dinfo = open_debuginfo(module); | ||
582 | if (!dinfo) { | ||
583 | pr_warning("Failed to open debuginfo file.\n"); | ||
584 | return -ENOENT; | ||
585 | } | ||
586 | |||
513 | setup_pager(); | 587 | setup_pager(); |
514 | 588 | ||
515 | for (i = 0; i < npevs && ret >= 0; i++) { | 589 | for (i = 0; i < npevs && ret >= 0; i++) |
516 | fd = open_vmlinux(module); | 590 | ret = show_available_vars_at(dinfo, &pevs[i], max_vls, _filter, |
517 | if (fd < 0) { | ||
518 | pr_warning("Failed to open debug information file.\n"); | ||
519 | ret = fd; | ||
520 | break; | ||
521 | } | ||
522 | ret = show_available_vars_at(fd, &pevs[i], max_vls, _filter, | ||
523 | externs); | 591 | externs); |
524 | } | 592 | |
593 | debuginfo__delete(dinfo); | ||
525 | return ret; | 594 | return ret; |
526 | } | 595 | } |
527 | 596 | ||
@@ -990,7 +1059,7 @@ bool perf_probe_event_need_dwarf(struct perf_probe_event *pev) | |||
990 | 1059 | ||
991 | /* Parse probe_events event into struct probe_point */ | 1060 | /* Parse probe_events event into struct probe_point */ |
992 | static int parse_probe_trace_command(const char *cmd, | 1061 | static int parse_probe_trace_command(const char *cmd, |
993 | struct probe_trace_event *tev) | 1062 | struct probe_trace_event *tev) |
994 | { | 1063 | { |
995 | struct probe_trace_point *tp = &tev->point; | 1064 | struct probe_trace_point *tp = &tev->point; |
996 | char pr; | 1065 | char pr; |
@@ -1023,8 +1092,14 @@ static int parse_probe_trace_command(const char *cmd, | |||
1023 | 1092 | ||
1024 | tp->retprobe = (pr == 'r'); | 1093 | tp->retprobe = (pr == 'r'); |
1025 | 1094 | ||
1026 | /* Scan function name and offset */ | 1095 | /* Scan module name(if there), function name and offset */ |
1027 | ret = sscanf(argv[1], "%a[^+]+%lu", (float *)(void *)&tp->symbol, | 1096 | p = strchr(argv[1], ':'); |
1097 | if (p) { | ||
1098 | tp->module = strndup(argv[1], p - argv[1]); | ||
1099 | p++; | ||
1100 | } else | ||
1101 | p = argv[1]; | ||
1102 | ret = sscanf(p, "%a[^+]+%lu", (float *)(void *)&tp->symbol, | ||
1028 | &tp->offset); | 1103 | &tp->offset); |
1029 | if (ret == 1) | 1104 | if (ret == 1) |
1030 | tp->offset = 0; | 1105 | tp->offset = 0; |
@@ -1269,9 +1344,10 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev) | |||
1269 | if (buf == NULL) | 1344 | if (buf == NULL) |
1270 | return NULL; | 1345 | return NULL; |
1271 | 1346 | ||
1272 | len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s+%lu", | 1347 | len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu", |
1273 | tp->retprobe ? 'r' : 'p', | 1348 | tp->retprobe ? 'r' : 'p', |
1274 | tev->group, tev->event, | 1349 | tev->group, tev->event, |
1350 | tp->module ?: "", tp->module ? ":" : "", | ||
1275 | tp->symbol, tp->offset); | 1351 | tp->symbol, tp->offset); |
1276 | if (len <= 0) | 1352 | if (len <= 0) |
1277 | goto error; | 1353 | goto error; |
@@ -1378,6 +1454,8 @@ static void clear_probe_trace_event(struct probe_trace_event *tev) | |||
1378 | free(tev->group); | 1454 | free(tev->group); |
1379 | if (tev->point.symbol) | 1455 | if (tev->point.symbol) |
1380 | free(tev->point.symbol); | 1456 | free(tev->point.symbol); |
1457 | if (tev->point.module) | ||
1458 | free(tev->point.module); | ||
1381 | for (i = 0; i < tev->nargs; i++) { | 1459 | for (i = 0; i < tev->nargs; i++) { |
1382 | if (tev->args[i].name) | 1460 | if (tev->args[i].name) |
1383 | free(tev->args[i].name); | 1461 | free(tev->args[i].name); |
@@ -1729,7 +1807,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, | |||
1729 | /* Convert perf_probe_event with debuginfo */ | 1807 | /* Convert perf_probe_event with debuginfo */ |
1730 | ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, module); | 1808 | ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, module); |
1731 | if (ret != 0) | 1809 | if (ret != 0) |
1732 | return ret; | 1810 | return ret; /* Found in debuginfo or got an error */ |
1733 | 1811 | ||
1734 | /* Allocate trace event buffer */ | 1812 | /* Allocate trace event buffer */ |
1735 | tev = *tevs = zalloc(sizeof(struct probe_trace_event)); | 1813 | tev = *tevs = zalloc(sizeof(struct probe_trace_event)); |
@@ -1742,6 +1820,15 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, | |||
1742 | ret = -ENOMEM; | 1820 | ret = -ENOMEM; |
1743 | goto error; | 1821 | goto error; |
1744 | } | 1822 | } |
1823 | |||
1824 | if (module) { | ||
1825 | tev->point.module = strdup(module); | ||
1826 | if (tev->point.module == NULL) { | ||
1827 | ret = -ENOMEM; | ||
1828 | goto error; | ||
1829 | } | ||
1830 | } | ||
1831 | |||
1745 | tev->point.offset = pev->point.offset; | 1832 | tev->point.offset = pev->point.offset; |
1746 | tev->point.retprobe = pev->point.retprobe; | 1833 | tev->point.retprobe = pev->point.retprobe; |
1747 | tev->nargs = pev->nargs; | 1834 | tev->nargs = pev->nargs; |
@@ -1869,8 +1956,10 @@ static int __del_trace_probe_event(int fd, struct str_node *ent) | |||
1869 | 1956 | ||
1870 | pr_debug("Writing event: %s\n", buf); | 1957 | pr_debug("Writing event: %s\n", buf); |
1871 | ret = write(fd, buf, strlen(buf)); | 1958 | ret = write(fd, buf, strlen(buf)); |
1872 | if (ret < 0) | 1959 | if (ret < 0) { |
1960 | ret = -errno; | ||
1873 | goto error; | 1961 | goto error; |
1962 | } | ||
1874 | 1963 | ||
1875 | printf("Remove event: %s\n", ent->s); | 1964 | printf("Remove event: %s\n", ent->s); |
1876 | return 0; | 1965 | return 0; |