[PATCH perf/core 4/4] perf-probe: Match linkage name with mangled name

From: Masami Hiramatsu
Date: Fri Sep 23 2016 - 11:35:43 EST


Match linkage name with mangled name if exists. The linkage_name
is used for storing mangled name of the object.
Thus, this allows perf-probe to find appropriate probe point
from mangled symbol as below.

E.g. without this fix:
----
$ ./perf probe -x /usr/lib64/libstdc++.so.6 \
-D _ZNKSt15basic_fstreamXXIwSt11char_traitsIwEE7is_openEv
Probe point '_ZNKSt15basic_fstreamXXIwSt11char_traitsIwEE7is_openEv'
not found.
Error: Failed to add events.
----

With this fix, perf probe can find the correct one.
----
$ ./perf probe -x /usr/lib64/libstdc++.so.6 \
-D _ZNKSt15basic_fstreamXXIwSt11char_traitsIwEE7is_openEv
p:probe_libstdc/_ZNKSt15basic_fstreamXXIwSt11char_traitsIwEE7is_openEv
/usr/lib64/libstdc++.so.6.0.22:0x8ca60
----

Signed-off-by: Masami Hiramatsu <mhiramat@xxxxxxxxxx>
---
tools/perf/util/dwarf-aux.c | 28 ++++++++++++++++++++++++++--
tools/perf/util/dwarf-aux.h | 3 +++
2 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
index faec899..41e068e 100644
--- a/tools/perf/util/dwarf-aux.c
+++ b/tools/perf/util/dwarf-aux.c
@@ -130,6 +130,22 @@ int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr,
}

/**
+ * die_get_linkage_name - Get the linkage name of the object
+ * @dw_die: A DIE of the object
+ *
+ * Get the linkage name attiribute of given @dw_die.
+ * For C++ binary, the linkage name will be the mangled symbol.
+ */
+const char *die_get_linkage_name(Dwarf_Die *dw_die)
+{
+ Dwarf_Attribute attr;
+
+ if (dwarf_attr_integrate(dw_die, DW_AT_linkage_name, &attr) == NULL)
+ return NULL;
+ return dwarf_formstring(&attr);
+}
+
+/**
* die_compare_name - Compare diename and tname
* @dw_die: a DIE
* @tname: a string of target name
@@ -145,18 +161,26 @@ bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
}

/**
- * die_match_name - Match diename and glob
+ * die_match_name - Match diename/linkage name and glob
* @dw_die: a DIE
* @glob: a string of target glob pattern
*
* Glob matching the name of @dw_die and @glob. Return false if matching fail.
+ * This also match linkage name.
*/
bool die_match_name(Dwarf_Die *dw_die, const char *glob)
{
const char *name;

name = dwarf_diename(dw_die);
- return name ? strglobmatch(name, glob) : false;
+ if (name && strglobmatch(name, glob))
+ return true;
+ /* fall back to check linkage name */
+ name = die_get_linkage_name(dw_die);
+ if (name && strglobmatch(name, glob))
+ return true;
+
+ return false;
}

/**
diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h
index 8b6d2f8..8ac53bf 100644
--- a/tools/perf/util/dwarf-aux.h
+++ b/tools/perf/util/dwarf-aux.h
@@ -38,6 +38,9 @@ int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr,
int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr,
int (*callback)(Dwarf_Die *, void *), void *data);

+/* Get DW_AT_linkage_name (should be NULL for C binary) */
+const char *die_get_linkage_name(Dwarf_Die *dw_die);
+
/* Ensure that this DIE is a subprogram and definition (not declaration) */
bool die_is_func_def(Dwarf_Die *dw_die);