| From b547f2cf06c3fb468cd56b5a7cb9ab7ec093796b Mon Sep 17 00:00:00 2001 |
| From: Masami Hiramatsu <mhiramat@kernel.org> |
| Date: Fri, 25 Oct 2019 17:46:25 +0900 |
| Subject: [PATCH] perf probe: Fix wrong address verification |
| |
| commit 07d369857808b7e8e471bbbbb0074a6718f89b31 upstream. |
| |
| Since there are some DIE which has only ranges instead of the |
| combination of entrypc/highpc, address verification must use |
| dwarf_haspc() instead of dwarf_entrypc/dwarf_highpc. |
| |
| Also, the ranges only DIE will have a partial code in different section |
| (e.g. unlikely code will be in text.unlikely as "FUNC.cold" symbol). In |
| that case, we can not use dwarf_entrypc() or die_entrypc(), because the |
| offset from original DIE can be a minus value. |
| |
| Instead, this simply gets the symbol and offset from symtab. |
| |
| Without this patch; |
| |
| # perf probe -D clear_tasks_mm_cpumask:1 |
| Failed to get entry address of clear_tasks_mm_cpumask |
| Error: Failed to add events. |
| |
| And with this patch: |
| |
| # perf probe -D clear_tasks_mm_cpumask:1 |
| p:probe/clear_tasks_mm_cpumask clear_tasks_mm_cpumask+0 |
| p:probe/clear_tasks_mm_cpumask_1 clear_tasks_mm_cpumask+5 |
| p:probe/clear_tasks_mm_cpumask_2 clear_tasks_mm_cpumask+8 |
| p:probe/clear_tasks_mm_cpumask_3 clear_tasks_mm_cpumask+16 |
| p:probe/clear_tasks_mm_cpumask_4 clear_tasks_mm_cpumask+82 |
| |
| Committer testing: |
| |
| I managed to reproduce the above: |
| |
| [root@quaco ~]# perf probe -D clear_tasks_mm_cpumask:1 |
| p:probe/clear_tasks_mm_cpumask _text+919968 |
| p:probe/clear_tasks_mm_cpumask_1 _text+919973 |
| p:probe/clear_tasks_mm_cpumask_2 _text+919976 |
| [root@quaco ~]# |
| |
| But then when trying to actually put the probe in place, it fails if I |
| use :0 as the offset: |
| |
| [root@quaco ~]# perf probe -L clear_tasks_mm_cpumask | head -5 |
| <clear_tasks_mm_cpumask@/usr/src/debug/kernel-5.2.fc30/linux-5.2.18-200.fc30.x86_64/kernel/cpu.c:0> |
| 0 void clear_tasks_mm_cpumask(int cpu) |
| 1 { |
| 2 struct task_struct *p; |
| |
| [root@quaco ~]# perf probe clear_tasks_mm_cpumask:0 |
| Probe point 'clear_tasks_mm_cpumask' not found. |
| Error: Failed to add events. |
| [root@quaco |
| |
| The next patch is needed to fix this case. |
| |
| Fixes: 576b523721b7 ("perf probe: Fix probing symbols with optimization suffix") |
| Reported-by: Arnaldo Carvalho de Melo <acme@kernel.org> |
| Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> |
| Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org> |
| Cc: Jiri Olsa <jolsa@redhat.com> |
| Cc: Namhyung Kim <namhyung@kernel.org> |
| Link: http://lore.kernel.org/lkml/157199318513.8075.10463906803299647907.stgit@devnote2 |
| Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c |
| index 6ef738baed4e..4bcea5b97f8a 100644 |
| --- a/tools/perf/util/probe-finder.c |
| +++ b/tools/perf/util/probe-finder.c |
| @@ -598,38 +598,26 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod, |
| const char *function, |
| struct probe_trace_point *tp) |
| { |
| - Dwarf_Addr eaddr, highaddr; |
| + Dwarf_Addr eaddr; |
| GElf_Sym sym; |
| const char *symbol; |
| |
| /* Verify the address is correct */ |
| - if (dwarf_entrypc(sp_die, &eaddr) != 0) { |
| - pr_warning("Failed to get entry address of %s\n", |
| - dwarf_diename(sp_die)); |
| - return -ENOENT; |
| - } |
| - if (dwarf_highpc(sp_die, &highaddr) != 0) { |
| - pr_warning("Failed to get end address of %s\n", |
| - dwarf_diename(sp_die)); |
| - return -ENOENT; |
| - } |
| - if (paddr > highaddr) { |
| - pr_warning("Offset specified is greater than size of %s\n", |
| + if (!dwarf_haspc(sp_die, paddr)) { |
| + pr_warning("Specified offset is out of %s\n", |
| dwarf_diename(sp_die)); |
| return -EINVAL; |
| } |
| |
| - symbol = dwarf_diename(sp_die); |
| + /* Try to get actual symbol name from symtab */ |
| + symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL); |
| if (!symbol) { |
| - /* Try to get the symbol name from symtab */ |
| - symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL); |
| - if (!symbol) { |
| - pr_warning("Failed to find symbol at 0x%lx\n", |
| - (unsigned long)paddr); |
| - return -ENOENT; |
| - } |
| - eaddr = sym.st_value; |
| + pr_warning("Failed to find symbol at 0x%lx\n", |
| + (unsigned long)paddr); |
| + return -ENOENT; |
| } |
| + eaddr = sym.st_value; |
| + |
| tp->offset = (unsigned long)(paddr - eaddr); |
| tp->address = (unsigned long)paddr; |
| tp->symbol = strdup(symbol); |
| -- |
| 2.7.4 |
| |