perf probe: Filter out instances except for inlined subroutine and subprogram
authorMasami Hiramatsu <mhiramat@kernel.org>
Wed, 30 Oct 2019 07:09:30 +0000 (16:09 +0900)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Thu, 7 Nov 2019 11:30:19 +0000 (08:30 -0300)
Filter out instances except for inlined_subroutine and subprogram DIE in
die_walk_instances() and die_is_func_instance().

This fixes an issue that perf probe sets some probes on calling address
instead of a target function itself.

When perf probe walks on instances of an abstruct origin (a kind of
function prototype of inlined function), die_walk_instances() can also
pass a GNU_call_site (a GNU extension for call site) to callback. Since
it is not an inlined instance of target function, we have to filter out
when searching a probe point.

Without this patch, perf probe sets probes on call site address too.This
can happen on some function which is marked "inlined", but has actual
symbol. (I'm not sure why GCC mark it "inlined"):

  # perf probe -D vfs_read
  p:probe/vfs_read _text+2500017
  p:probe/vfs_read_1 _text+2499468
  p:probe/vfs_read_2 _text+2499563
  p:probe/vfs_read_3 _text+2498876
  p:probe/vfs_read_4 _text+2498512
  p:probe/vfs_read_5 _text+2498627

With this patch:

Slightly different results, similar tho:

  # perf probe -D vfs_read
  p:probe/vfs_read _text+2498512

Committer testing:

  # uname -a
  Linux quaco 5.3.8-200.fc30.x86_64 #1 SMP Tue Oct 29 14:46:22 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

Before:

  # perf probe -D vfs_read
  p:probe/vfs_read _text+3131557
  p:probe/vfs_read_1 _text+3130975
  p:probe/vfs_read_2 _text+3131047
  p:probe/vfs_read_3 _text+3130380
  p:probe/vfs_read_4 _text+3130000
  # uname -a
  Linux quaco 5.3.8-200.fc30.x86_64 #1 SMP Tue Oct 29 14:46:22 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
  #

After:

  # perf probe -D vfs_read
  p:probe/vfs_read _text+3130000
  #

Fixes: db0d2c6420ee ("perf probe: Search concrete out-of-line instances")
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: http://lore.kernel.org/lkml/157241937063.32002.11024544873990816590.stgit@devnote2
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/dwarf-aux.c

index f31001d13bfb40121eda2ca8e0269cfaa4a5a771..ac12890432044c099fc5cfaf4cb39117c8d008a3 100644 (file)
@@ -334,18 +334,22 @@ int die_entrypc(Dwarf_Die *dw_die, Dwarf_Addr *addr)
  * @dw_die: a DIE
  *
  * Ensure that this DIE is an instance (which has an entry address).
- * This returns true if @dw_die is a function instance. If not, you need to
- * call die_walk_instances() to find actual instances.
+ * This returns true if @dw_die is a function instance. If not, the @dw_die
+ * must be a prototype. You can use die_walk_instances() to find actual
+ * instances.
  **/
 bool die_is_func_instance(Dwarf_Die *dw_die)
 {
        Dwarf_Addr tmp;
        Dwarf_Attribute attr_mem;
+       int tag = dwarf_tag(dw_die);
 
-       /* Actually gcc optimizes non-inline as like as inlined */
-       return !dwarf_func_inline(dw_die) &&
-              (dwarf_entrypc(dw_die, &tmp) == 0 ||
-               dwarf_attr(dw_die, DW_AT_ranges, &attr_mem) != NULL);
+       if (tag != DW_TAG_subprogram &&
+           tag != DW_TAG_inlined_subroutine)
+               return false;
+
+       return dwarf_entrypc(dw_die, &tmp) == 0 ||
+               dwarf_attr(dw_die, DW_AT_ranges, &attr_mem) != NULL;
 }
 
 /**
@@ -624,6 +628,9 @@ static int __die_walk_instances_cb(Dwarf_Die *inst, void *data)
        Dwarf_Die *origin;
        int tmp;
 
+       if (!die_is_func_instance(inst))
+               return DIE_FIND_CB_CONTINUE;
+
        attr = dwarf_attr(inst, DW_AT_abstract_origin, &attr_mem);
        if (attr == NULL)
                return DIE_FIND_CB_CONTINUE;