aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>2014-02-06 00:32:23 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2014-02-18 07:34:51 -0500
commit5a6f63145491f905de1c5c6c46c5cd62c004d0d1 (patch)
tree4f65f5278921ac1be6e95cd03d15f29a921c4f86
parent8f33f7deac485a61f38aa690b85489322a4d958e (diff)
perf probe: Show source-level or symbol-level info for uprobes
Show source-level or symbol-level information for uprobe events. Without this change; # ./perf probe -l probe_perf:dso__load_vmlinux (on 0x000000000006d110 in /kbuild/ksrc/linux-3/tools/perf/perf) With this change; # ./perf probe -l probe_perf:dso__load_vmlinux (on dso__load_vmlinux@util/symbol.c in /kbuild/ksrc/linux-3/tools/perf/perf) Changes from v2: - Update according to previous patches. Changes from v1: - Rewrite the code based on new series. Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Cc: David Ahern <dsahern@gmail.com> Cc: "David A. Long" <dave.long@linaro.org> Cc: Ingo Molnar <mingo@redhat.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: yrl.pp-manager.tt@hitachi.com Link: http://lkml.kernel.org/r/20140206053223.29635.51280.stgit@kbuild-fedora.yrl.intra.hitachi.co.jp Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--tools/perf/util/probe-event.c227
1 files changed, 144 insertions, 83 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index f86820c39ea4..3c35b7af2adb 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -249,34 +249,6 @@ out:
249 return ret; 249 return ret;
250} 250}
251 251
252static int convert_to_perf_probe_point(struct probe_trace_point *tp,
253 struct perf_probe_point *pp)
254{
255 struct symbol *sym;
256 struct map *map;
257 u64 addr = kernel_get_symbol_address_by_name(tp->symbol, true);
258
259 if (addr) {
260 addr += tp->offset;
261 sym = __find_kernel_function(addr, &map);
262 if (!sym)
263 goto failed;
264 pp->function = strdup(sym->name);
265 pp->offset = addr - map->unmap_ip(map, sym->start);
266 } else {
267failed:
268 pp->function = strdup(tp->symbol);
269 pp->offset = tp->offset;
270 }
271
272 if (pp->function == NULL)
273 return -ENOMEM;
274
275 pp->retprobe = tp->retprobe;
276
277 return 0;
278}
279
280#ifdef HAVE_DWARF_SUPPORT 252#ifdef HAVE_DWARF_SUPPORT
281/* Open new debuginfo of given module */ 253/* Open new debuginfo of given module */
282static struct debuginfo *open_debuginfo(const char *module) 254static struct debuginfo *open_debuginfo(const char *module)
@@ -298,44 +270,6 @@ static struct debuginfo *open_debuginfo(const char *module)
298 return debuginfo__new(path); 270 return debuginfo__new(path);
299} 271}
300 272
301/*
302 * Convert trace point to probe point with debuginfo
303 * Currently only handles kprobes.
304 */
305static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
306 struct perf_probe_point *pp)
307{
308 u64 addr = 0;
309 int ret = -ENOENT;
310 struct debuginfo *dinfo;
311
312 addr = kernel_get_symbol_address_by_name(tp->symbol, false);
313 if (addr) {
314 addr += tp->offset;
315 pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol,
316 tp->offset, addr);
317
318 dinfo = open_debuginfo(tp->module);
319 if (dinfo) {
320 ret = debuginfo__find_probe_point(dinfo,
321 (unsigned long)addr, pp);
322 debuginfo__delete(dinfo);
323 } else {
324 pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n",
325 addr);
326 ret = -ENOENT;
327 }
328 }
329 if (ret <= 0) {
330 pr_debug("Failed to find corresponding probes from "
331 "debuginfo. Use kprobe event information.\n");
332 return convert_to_perf_probe_point(tp, pp);
333 }
334 pp->retprobe = tp->retprobe;
335
336 return 0;
337}
338
339static int get_text_start_address(const char *exec, unsigned long *address) 273static int get_text_start_address(const char *exec, unsigned long *address)
340{ 274{
341 Elf *elf; 275 Elf *elf;
@@ -364,6 +298,57 @@ out:
364 return ret; 298 return ret;
365} 299}
366 300
301/*
302 * Convert trace point to probe point with debuginfo
303 */
304static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp,
305 struct perf_probe_point *pp,
306 bool is_kprobe)
307{
308 struct debuginfo *dinfo = NULL;
309 unsigned long stext = 0;
310 u64 addr = tp->address;
311 int ret = -ENOENT;
312
313 /* convert the address to dwarf address */
314 if (!is_kprobe) {
315 if (!addr) {
316 ret = -EINVAL;
317 goto error;
318 }
319 ret = get_text_start_address(tp->module, &stext);
320 if (ret < 0)
321 goto error;
322 addr += stext;
323 } else {
324 addr = kernel_get_symbol_address_by_name(tp->symbol, false);
325 if (addr == 0)
326 goto error;
327 addr += tp->offset;
328 }
329
330 pr_debug("try to find information at %" PRIx64 " in %s\n", addr,
331 tp->module ? : "kernel");
332
333 dinfo = open_debuginfo(tp->module);
334 if (dinfo) {
335 ret = debuginfo__find_probe_point(dinfo,
336 (unsigned long)addr, pp);
337 debuginfo__delete(dinfo);
338 } else {
339 pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n", addr);
340 ret = -ENOENT;
341 }
342
343 if (ret > 0) {
344 pp->retprobe = tp->retprobe;
345 return 0;
346 }
347error:
348 pr_debug("Failed to find corresponding probes from debuginfo.\n");
349 return ret ? : -ENOENT;
350}
351
367static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, 352static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
368 int ntevs, const char *exec) 353 int ntevs, const char *exec)
369{ 354{
@@ -815,10 +800,12 @@ out:
815 800
816#else /* !HAVE_DWARF_SUPPORT */ 801#else /* !HAVE_DWARF_SUPPORT */
817 802
818static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, 803static int
819 struct perf_probe_point *pp) 804find_perf_probe_point_from_dwarf(struct probe_trace_point *tp __maybe_unused,
805 struct perf_probe_point *pp __maybe_unused,
806 bool is_kprobe __maybe_unused)
820{ 807{
821 return convert_to_perf_probe_point(tp, pp); 808 return -ENOSYS;
822} 809}
823 810
824static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 811static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
@@ -1343,16 +1330,21 @@ static int parse_probe_trace_command(const char *cmd,
1343 } else 1330 } else
1344 p = argv[1]; 1331 p = argv[1];
1345 fmt1_str = strtok_r(p, "+", &fmt); 1332 fmt1_str = strtok_r(p, "+", &fmt);
1346 tp->symbol = strdup(fmt1_str); 1333 if (fmt1_str[0] == '0') /* only the address started with 0x */
1347 if (tp->symbol == NULL) { 1334 tp->address = strtoul(fmt1_str, NULL, 0);
1348 ret = -ENOMEM; 1335 else {
1349 goto out; 1336 /* Only the symbol-based probe has offset */
1337 tp->symbol = strdup(fmt1_str);
1338 if (tp->symbol == NULL) {
1339 ret = -ENOMEM;
1340 goto out;
1341 }
1342 fmt2_str = strtok_r(NULL, "", &fmt);
1343 if (fmt2_str == NULL)
1344 tp->offset = 0;
1345 else
1346 tp->offset = strtoul(fmt2_str, NULL, 10);
1350 } 1347 }
1351 fmt2_str = strtok_r(NULL, "", &fmt);
1352 if (fmt2_str == NULL)
1353 tp->offset = 0;
1354 else
1355 tp->offset = strtoul(fmt2_str, NULL, 10);
1356 1348
1357 tev->nargs = argc - 2; 1349 tev->nargs = argc - 2;
1358 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); 1350 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
@@ -1623,6 +1615,79 @@ error:
1623 return NULL; 1615 return NULL;
1624} 1616}
1625 1617
1618static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
1619 struct perf_probe_point *pp,
1620 bool is_kprobe)
1621{
1622 struct symbol *sym = NULL;
1623 struct map *map;
1624 u64 addr;
1625 int ret = -ENOENT;
1626
1627 if (!is_kprobe) {
1628 map = dso__new_map(tp->module);
1629 if (!map)
1630 goto out;
1631 addr = tp->address;
1632 sym = map__find_symbol(map, addr, NULL);
1633 } else {
1634 addr = kernel_get_symbol_address_by_name(tp->symbol, true);
1635 if (addr) {
1636 addr += tp->offset;
1637 sym = __find_kernel_function(addr, &map);
1638 }
1639 }
1640 if (!sym)
1641 goto out;
1642
1643 pp->retprobe = tp->retprobe;
1644 pp->offset = addr - map->unmap_ip(map, sym->start);
1645 pp->function = strdup(sym->name);
1646 ret = pp->function ? 0 : -ENOMEM;
1647
1648out:
1649 if (map && !is_kprobe) {
1650 dso__delete(map->dso);
1651 map__delete(map);
1652 }
1653
1654 return ret;
1655}
1656
1657static int convert_to_perf_probe_point(struct probe_trace_point *tp,
1658 struct perf_probe_point *pp,
1659 bool is_kprobe)
1660{
1661 char buf[128];
1662 int ret;
1663
1664 ret = find_perf_probe_point_from_dwarf(tp, pp, is_kprobe);
1665 if (!ret)
1666 return 0;
1667 ret = find_perf_probe_point_from_map(tp, pp, is_kprobe);
1668 if (!ret)
1669 return 0;
1670
1671 pr_debug("Failed to find probe point from both of dwarf and map.\n");
1672
1673 if (tp->symbol) {
1674 pp->function = strdup(tp->symbol);
1675 pp->offset = tp->offset;
1676 } else if (!tp->module && !is_kprobe) {
1677 ret = e_snprintf(buf, 128, "0x%" PRIx64, (u64)tp->address);
1678 if (ret < 0)
1679 return ret;
1680 pp->function = strdup(buf);
1681 pp->offset = 0;
1682 }
1683 if (pp->function == NULL)
1684 return -ENOMEM;
1685
1686 pp->retprobe = tp->retprobe;
1687
1688 return 0;
1689}
1690
1626static int convert_to_perf_probe_event(struct probe_trace_event *tev, 1691static int convert_to_perf_probe_event(struct probe_trace_event *tev,
1627 struct perf_probe_event *pev, bool is_kprobe) 1692 struct perf_probe_event *pev, bool is_kprobe)
1628{ 1693{
@@ -1636,11 +1701,7 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev,
1636 return -ENOMEM; 1701 return -ENOMEM;
1637 1702
1638 /* Convert trace_point to probe_point */ 1703 /* Convert trace_point to probe_point */
1639 if (is_kprobe) 1704 ret = convert_to_perf_probe_point(&tev->point, &pev->point, is_kprobe);
1640 ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
1641 else
1642 ret = convert_to_perf_probe_point(&tev->point, &pev->point);
1643
1644 if (ret < 0) 1705 if (ret < 0)
1645 return ret; 1706 return ret;
1646 1707