提交 5a6f6314 编写于 作者: M Masami Hiramatsu 提交者: Arnaldo Carvalho de Melo

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: NMasami 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.jpSigned-off-by: NArnaldo Carvalho de Melo <acme@redhat.com>
上级 8f33f7de
...@@ -249,34 +249,6 @@ static int convert_exec_to_group(const char *exec, char **result) ...@@ -249,34 +249,6 @@ static int convert_exec_to_group(const char *exec, char **result)
return ret; return ret;
} }
static int convert_to_perf_probe_point(struct probe_trace_point *tp,
struct perf_probe_point *pp)
{
struct symbol *sym;
struct map *map;
u64 addr = kernel_get_symbol_address_by_name(tp->symbol, true);
if (addr) {
addr += tp->offset;
sym = __find_kernel_function(addr, &map);
if (!sym)
goto failed;
pp->function = strdup(sym->name);
pp->offset = addr - map->unmap_ip(map, sym->start);
} else {
failed:
pp->function = strdup(tp->symbol);
pp->offset = tp->offset;
}
if (pp->function == NULL)
return -ENOMEM;
pp->retprobe = tp->retprobe;
return 0;
}
#ifdef HAVE_DWARF_SUPPORT #ifdef HAVE_DWARF_SUPPORT
/* Open new debuginfo of given module */ /* Open new debuginfo of given module */
static struct debuginfo *open_debuginfo(const char *module) static struct debuginfo *open_debuginfo(const char *module)
...@@ -298,44 +270,6 @@ static struct debuginfo *open_debuginfo(const char *module) ...@@ -298,44 +270,6 @@ static struct debuginfo *open_debuginfo(const char *module)
return debuginfo__new(path); return debuginfo__new(path);
} }
/*
* Convert trace point to probe point with debuginfo
* Currently only handles kprobes.
*/
static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
struct perf_probe_point *pp)
{
u64 addr = 0;
int ret = -ENOENT;
struct debuginfo *dinfo;
addr = kernel_get_symbol_address_by_name(tp->symbol, false);
if (addr) {
addr += tp->offset;
pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol,
tp->offset, addr);
dinfo = open_debuginfo(tp->module);
if (dinfo) {
ret = debuginfo__find_probe_point(dinfo,
(unsigned long)addr, pp);
debuginfo__delete(dinfo);
} else {
pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n",
addr);
ret = -ENOENT;
}
}
if (ret <= 0) {
pr_debug("Failed to find corresponding probes from "
"debuginfo. Use kprobe event information.\n");
return convert_to_perf_probe_point(tp, pp);
}
pp->retprobe = tp->retprobe;
return 0;
}
static int get_text_start_address(const char *exec, unsigned long *address) static int get_text_start_address(const char *exec, unsigned long *address)
{ {
Elf *elf; Elf *elf;
...@@ -364,6 +298,57 @@ static int get_text_start_address(const char *exec, unsigned long *address) ...@@ -364,6 +298,57 @@ static int get_text_start_address(const char *exec, unsigned long *address)
return ret; return ret;
} }
/*
* Convert trace point to probe point with debuginfo
*/
static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp,
struct perf_probe_point *pp,
bool is_kprobe)
{
struct debuginfo *dinfo = NULL;
unsigned long stext = 0;
u64 addr = tp->address;
int ret = -ENOENT;
/* convert the address to dwarf address */
if (!is_kprobe) {
if (!addr) {
ret = -EINVAL;
goto error;
}
ret = get_text_start_address(tp->module, &stext);
if (ret < 0)
goto error;
addr += stext;
} else {
addr = kernel_get_symbol_address_by_name(tp->symbol, false);
if (addr == 0)
goto error;
addr += tp->offset;
}
pr_debug("try to find information at %" PRIx64 " in %s\n", addr,
tp->module ? : "kernel");
dinfo = open_debuginfo(tp->module);
if (dinfo) {
ret = debuginfo__find_probe_point(dinfo,
(unsigned long)addr, pp);
debuginfo__delete(dinfo);
} else {
pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n", addr);
ret = -ENOENT;
}
if (ret > 0) {
pp->retprobe = tp->retprobe;
return 0;
}
error:
pr_debug("Failed to find corresponding probes from debuginfo.\n");
return ret ? : -ENOENT;
}
static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
int ntevs, const char *exec) int ntevs, const char *exec)
{ {
...@@ -815,10 +800,12 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs, ...@@ -815,10 +800,12 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
#else /* !HAVE_DWARF_SUPPORT */ #else /* !HAVE_DWARF_SUPPORT */
static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, static int
struct perf_probe_point *pp) find_perf_probe_point_from_dwarf(struct probe_trace_point *tp __maybe_unused,
struct perf_probe_point *pp __maybe_unused,
bool is_kprobe __maybe_unused)
{ {
return convert_to_perf_probe_point(tp, pp); return -ENOSYS;
} }
static int try_to_find_probe_trace_events(struct perf_probe_event *pev, static 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,16 +1330,21 @@ static int parse_probe_trace_command(const char *cmd,
} else } else
p = argv[1]; p = argv[1];
fmt1_str = strtok_r(p, "+", &fmt); fmt1_str = strtok_r(p, "+", &fmt);
tp->symbol = strdup(fmt1_str); if (fmt1_str[0] == '0') /* only the address started with 0x */
if (tp->symbol == NULL) { tp->address = strtoul(fmt1_str, NULL, 0);
ret = -ENOMEM; else {
goto out; /* Only the symbol-based probe has offset */
tp->symbol = strdup(fmt1_str);
if (tp->symbol == NULL) {
ret = -ENOMEM;
goto out;
}
fmt2_str = strtok_r(NULL, "", &fmt);
if (fmt2_str == NULL)
tp->offset = 0;
else
tp->offset = strtoul(fmt2_str, NULL, 10);
} }
fmt2_str = strtok_r(NULL, "", &fmt);
if (fmt2_str == NULL)
tp->offset = 0;
else
tp->offset = strtoul(fmt2_str, NULL, 10);
tev->nargs = argc - 2; tev->nargs = argc - 2;
tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
...@@ -1623,6 +1615,79 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev) ...@@ -1623,6 +1615,79 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)
return NULL; return NULL;
} }
static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
struct perf_probe_point *pp,
bool is_kprobe)
{
struct symbol *sym = NULL;
struct map *map;
u64 addr;
int ret = -ENOENT;
if (!is_kprobe) {
map = dso__new_map(tp->module);
if (!map)
goto out;
addr = tp->address;
sym = map__find_symbol(map, addr, NULL);
} else {
addr = kernel_get_symbol_address_by_name(tp->symbol, true);
if (addr) {
addr += tp->offset;
sym = __find_kernel_function(addr, &map);
}
}
if (!sym)
goto out;
pp->retprobe = tp->retprobe;
pp->offset = addr - map->unmap_ip(map, sym->start);
pp->function = strdup(sym->name);
ret = pp->function ? 0 : -ENOMEM;
out:
if (map && !is_kprobe) {
dso__delete(map->dso);
map__delete(map);
}
return ret;
}
static int convert_to_perf_probe_point(struct probe_trace_point *tp,
struct perf_probe_point *pp,
bool is_kprobe)
{
char buf[128];
int ret;
ret = find_perf_probe_point_from_dwarf(tp, pp, is_kprobe);
if (!ret)
return 0;
ret = find_perf_probe_point_from_map(tp, pp, is_kprobe);
if (!ret)
return 0;
pr_debug("Failed to find probe point from both of dwarf and map.\n");
if (tp->symbol) {
pp->function = strdup(tp->symbol);
pp->offset = tp->offset;
} else if (!tp->module && !is_kprobe) {
ret = e_snprintf(buf, 128, "0x%" PRIx64, (u64)tp->address);
if (ret < 0)
return ret;
pp->function = strdup(buf);
pp->offset = 0;
}
if (pp->function == NULL)
return -ENOMEM;
pp->retprobe = tp->retprobe;
return 0;
}
static int convert_to_perf_probe_event(struct probe_trace_event *tev, static int convert_to_perf_probe_event(struct probe_trace_event *tev,
struct perf_probe_event *pev, bool is_kprobe) struct perf_probe_event *pev, bool is_kprobe)
{ {
...@@ -1636,11 +1701,7 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev, ...@@ -1636,11 +1701,7 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev,
return -ENOMEM; return -ENOMEM;
/* Convert trace_point to probe_point */ /* Convert trace_point to probe_point */
if (is_kprobe) ret = convert_to_perf_probe_point(&tev->point, &pev->point, is_kprobe);
ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
else
ret = convert_to_perf_probe_point(&tev->point, &pev->point);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册