|
|
9201c6 |
From fced4ba337a4eddb4163994834a122e62c6efdfb Mon Sep 17 00:00:00 2001
|
|
|
9201c6 |
From: Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com>
|
|
|
9201c6 |
Date: Wed, 14 Sep 2016 13:32:51 +0530
|
|
|
9201c6 |
Subject: [PATCH 1/2] ppc64le: Store correct function entry address in
|
|
|
9201c6 |
symbol_table
|
|
|
9201c6 |
|
|
|
9201c6 |
PPC64 ELF ABI v2 has a Global Entry Point and a Local Entry Point for
|
|
|
9201c6 |
the functions. Debuginfo of ELF contains GEP which is same as entrypc
|
|
|
9201c6 |
while symbol table contains GEP and offset, from which we can calculate
|
|
|
9201c6 |
LEP. LEP is used to call function within single CU, when TOC pointer
|
|
|
9201c6 |
update is not required. Placing a probe on LEP catches call from both
|
|
|
9201c6 |
the GEP and the LEP but, by default, systemtap probes on GEP.
|
|
|
9201c6 |
|
|
|
9201c6 |
For ppc64le, Systemtap stores LEP in symbol table and prioritize symbol
|
|
|
9201c6 |
table over debuginfo. But, storing LEP in symbol table has couple of
|
|
|
9201c6 |
regression effect. As LEP is only required at a time of adding a probe,
|
|
|
9201c6 |
don't store it in symbol table.
|
|
|
9201c6 |
|
|
|
9201c6 |
No need to prioritize symbol table as well because debuginfo and symbol
|
|
|
9201c6 |
table both will contain Global Entry Point.
|
|
|
9201c6 |
|
|
|
9201c6 |
Revert commit b4c6a4b1cd00 ("Prioritize symbol table lookup for ppc64le")
|
|
|
9201c6 |
partially.
|
|
|
9201c6 |
|
|
|
9201c6 |
Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com>
|
|
|
9201c6 |
---
|
|
|
9201c6 |
tapsets.cxx | 62 +------------------------------------------------------------
|
|
|
9201c6 |
1 file changed, 1 insertion(+), 61 deletions(-)
|
|
|
9201c6 |
|
|
|
9201c6 |
diff --git a/tapsets.cxx b/tapsets.cxx
|
|
|
9201c6 |
index 4167678..a887e1f 100644
|
|
|
9201c6 |
--- a/tapsets.cxx
|
|
|
9201c6 |
+++ b/tapsets.cxx
|
|
|
9201c6 |
@@ -2134,18 +2134,6 @@ query_dwarf_inline_instance (Dwarf_Die * die, dwarf_query * q)
|
|
|
9201c6 |
}
|
|
|
9201c6 |
}
|
|
|
9201c6 |
|
|
|
9201c6 |
-static bool
|
|
|
9201c6 |
-is_filtered_func_exists (func_info_map_t const& filtered, func_info *fi)
|
|
|
9201c6 |
-{
|
|
|
9201c6 |
- for (unsigned i = 0; i < filtered.size(); i++)
|
|
|
9201c6 |
- {
|
|
|
9201c6 |
- if ((filtered[i].entrypc == fi->entrypc) && (filtered[i].name == fi->name))
|
|
|
9201c6 |
- return true;
|
|
|
9201c6 |
- }
|
|
|
9201c6 |
-
|
|
|
9201c6 |
- return false;
|
|
|
9201c6 |
-}
|
|
|
9201c6 |
-
|
|
|
9201c6 |
static int
|
|
|
9201c6 |
query_dwarf_func (Dwarf_Die * func, dwarf_query * q)
|
|
|
9201c6 |
{
|
|
|
9201c6 |
@@ -2198,37 +2186,7 @@ query_dwarf_func (Dwarf_Die * func, dwarf_query * q)
|
|
|
9201c6 |
q->dw.function_line (&func.decl_line);
|
|
|
9201c6 |
|
|
|
9201c6 |
Dwarf_Addr entrypc;
|
|
|
9201c6 |
-
|
|
|
9201c6 |
- func.entrypc = 0;
|
|
|
9201c6 |
- Dwarf_Addr bias;
|
|
|
9201c6 |
- Dwfl_Module *mod = q->dw.module;
|
|
|
9201c6 |
- Elf* elf = (dwarf_getelf (dwfl_module_getdwarf (mod, &bias))
|
|
|
9201c6 |
- ?: dwfl_module_getelf (mod, &bias));
|
|
|
9201c6 |
-
|
|
|
9201c6 |
- GElf_Ehdr ehdr_mem;
|
|
|
9201c6 |
- GElf_Ehdr* em = gelf_getehdr (elf, &ehdr_mem);
|
|
|
9201c6 |
- if (em == NULL) throw SEMANTIC_ERROR (_("Couldn't get elf header"));
|
|
|
9201c6 |
-
|
|
|
9201c6 |
- /* Giving priority to sym_table for ppc64*/
|
|
|
9201c6 |
- if ((em->e_machine == EM_PPC64) && ((em->e_flags & EF_PPC64_ABI) == 2)
|
|
|
9201c6 |
- && (q->dw.mod_info->sym_table))
|
|
|
9201c6 |
- {
|
|
|
9201c6 |
- /* The linkage name is the best match for the symbol table. */
|
|
|
9201c6 |
- const string& linkage_name = dwarf_linkage_name(&func.die)
|
|
|
9201c6 |
- ?: dwarf_diename(&func.die) ?: (string)func.name;
|
|
|
9201c6 |
-
|
|
|
9201c6 |
- set<func_info *> fis = q->dw.mod_info->sym_table->lookup_symbol(linkage_name);
|
|
|
9201c6 |
- for (set<func_info*>::iterator it=fis.begin(); it!=fis.end() ; ++it)
|
|
|
9201c6 |
- {
|
|
|
9201c6 |
- func.entrypc = (*it)->entrypc;
|
|
|
9201c6 |
- if (is_filtered_func_exists(q->filtered_functions, &func))
|
|
|
9201c6 |
- continue;
|
|
|
9201c6 |
- q->filtered_functions.push_back(func);
|
|
|
9201c6 |
- }
|
|
|
9201c6 |
- }
|
|
|
9201c6 |
-
|
|
|
9201c6 |
- /* If not ppc64 or not found in sym_table, try it directly. */
|
|
|
9201c6 |
- if (!func.entrypc && q->dw.function_entrypc (&entrypc))
|
|
|
9201c6 |
+ if (q->dw.function_entrypc (&entrypc))
|
|
|
9201c6 |
{
|
|
|
9201c6 |
func.entrypc = entrypc;
|
|
|
9201c6 |
q->filtered_functions.push_back (func);
|
|
|
9201c6 |
@@ -8448,13 +8406,6 @@ symbol_table::get_from_elf()
|
|
|
9201c6 |
int syments = dwfl_module_getsymtab(mod);
|
|
|
9201c6 |
assert(syments);
|
|
|
9201c6 |
prepare_section_rejection(mod);
|
|
|
9201c6 |
- Dwarf_Addr bias;
|
|
|
9201c6 |
- Elf* elf = (dwarf_getelf (dwfl_module_getdwarf (mod, &bias))
|
|
|
9201c6 |
- ?: dwfl_module_getelf (mod, &bias));
|
|
|
9201c6 |
-
|
|
|
9201c6 |
- GElf_Ehdr ehdr_mem;
|
|
|
9201c6 |
- GElf_Ehdr* em = gelf_getehdr (elf, &ehdr_mem);
|
|
|
9201c6 |
- if (em == NULL) throw SEMANTIC_ERROR (_("Couldn't get elf header"));
|
|
|
9201c6 |
|
|
|
9201c6 |
for (int i = 1; i < syments; ++i)
|
|
|
9201c6 |
{
|
|
|
9201c6 |
@@ -8487,18 +8438,7 @@ symbol_table::get_from_elf()
|
|
|
9201c6 |
continue;
|
|
|
9201c6 |
interned_string name = n;
|
|
|
9201c6 |
|
|
|
9201c6 |
- /*
|
|
|
9201c6 |
- * For ELF ABI v2 on PPC64 LE, we need to adjust sym.st_value corresponding
|
|
|
9201c6 |
- * to the bits of sym.st_other. These bits will tell us what's the offset
|
|
|
9201c6 |
- * of the local entry point from the global entry point.
|
|
|
9201c6 |
- *
|
|
|
9201c6 |
- * st_other field is currently only used with ABIv2 on ppc64
|
|
|
9201c6 |
- */
|
|
|
9201c6 |
Dwarf_Addr entrypc = addr;
|
|
|
9201c6 |
- if ((em->e_machine == EM_PPC64) && ((em->e_flags & EF_PPC64_ABI) == 2)
|
|
|
9201c6 |
- && (GELF_ST_TYPE(sym.st_info) == STT_FUNC) && sym.st_other)
|
|
|
9201c6 |
- entrypc += PPC64_LOCAL_ENTRY_OFFSET(sym.st_other);
|
|
|
9201c6 |
-
|
|
|
9201c6 |
if (GELF_ST_TYPE(sym.st_info) == STT_FUNC)
|
|
|
9201c6 |
add_symbol(name, (GELF_ST_BIND(sym.st_info) == STB_WEAK),
|
|
|
9201c6 |
reject, addr, entrypc);
|
|
|
9201c6 |
--
|
|
|
9201c6 |
1.8.3.1
|
|
|
9201c6 |
|
|
|
9201c6 |
From 1b83a55a0272f2eb0bdcd5809fb630e1f369d400 Mon Sep 17 00:00:00 2001
|
|
|
9201c6 |
From: Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com>
|
|
|
9201c6 |
Date: Wed, 14 Sep 2016 13:36:00 +0530
|
|
|
9201c6 |
Subject: [PATCH 2/2] ppc64le: Fix LEP usage for probing
|
|
|
9201c6 |
|
|
|
9201c6 |
PPC64 ELF ABI v2 has a Global Entry Point and a Local Entry Point for
|
|
|
9201c6 |
the functions. Debuginfo of ELF contains GEP which is same as entrypc
|
|
|
9201c6 |
while symbol table contains GEP and offset, from which we can calculate
|
|
|
9201c6 |
LEP. LEP is used to call function within single CU, when TOC pointer
|
|
|
9201c6 |
update is not required. Placing a probe on LEP catches call from both
|
|
|
9201c6 |
the GEP and the LEP but, by default, systemtap probes on GEP.
|
|
|
9201c6 |
|
|
|
9201c6 |
Commit b4c6a4b1cd00 ("Prioritize symbol table lookup for ppc64le") solve
|
|
|
9201c6 |
this issue by storing LEP in symbol table and prioritizing symbol table
|
|
|
9201c6 |
over debuginfo for ppc64le.
|
|
|
9201c6 |
|
|
|
9201c6 |
But there are few regression effect of this patch. Couple of examples
|
|
|
9201c6 |
are given below.
|
|
|
9201c6 |
|
|
|
9201c6 |
1. If target program is compiled without optimization and user is
|
|
|
9201c6 |
interested in function parameter, systemtap should probe after function
|
|
|
9201c6 |
prologue. But above patch forces probe on LEP and which result in garbage
|
|
|
9201c6 |
value of function parameter will get recorded.
|
|
|
9201c6 |
|
|
|
9201c6 |
$ make verbose=1 installcheck RUNTESTFLAGS='at_var.exp -v --debug'
|
|
|
9201c6 |
...
|
|
|
9201c6 |
# of expected passes 1
|
|
|
9201c6 |
# of unexpected failures 1
|
|
|
9201c6 |
|
|
|
9201c6 |
2. Probe on shared library function with parameter is failing at Pass 2.
|
|
|
9201c6 |
|
|
|
9201c6 |
$ make verbose=1 installcheck RUNTESTFLAGS='exelib.exp -v --debug'
|
|
|
9201c6 |
...
|
|
|
9201c6 |
# of expected passes 10
|
|
|
9201c6 |
# of unexpected failures 64
|
|
|
9201c6 |
|
|
|
9201c6 |
3. When symbol_name with offset is used to register kprobe, kernel itself
|
|
|
9201c6 |
will find LEP and adds offset to it. Systemtap using LEP to find offset
|
|
|
9201c6 |
is resulting in offset being added two times.
|
|
|
9201c6 |
GEP + lep_offset (by systemtap) + lep_offset (by kernel)
|
|
|
9201c6 |
|
|
|
9201c6 |
This can be solved by calculating LEP only at a time of adding a probe.
|
|
|
9201c6 |
That will make effect of LEP local to that area and won't have any
|
|
|
9201c6 |
regression effect.
|
|
|
9201c6 |
|
|
|
9201c6 |
After applying patch:
|
|
|
9201c6 |
|
|
|
9201c6 |
$ make verbose=1 installcheck RUNTESTFLAGS='at_var.exp -v --debug'
|
|
|
9201c6 |
...
|
|
|
9201c6 |
# of expected passes 2
|
|
|
9201c6 |
|
|
|
9201c6 |
$ make verbose=1 installcheck RUNTESTFLAGS='exelib.exp -v --debug'
|
|
|
9201c6 |
...
|
|
|
9201c6 |
# of expected passes 74
|
|
|
9201c6 |
|
|
|
9201c6 |
Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com>
|
|
|
9201c6 |
---
|
|
|
9201c6 |
tapsets.cxx | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
|
|
|
9201c6 |
1 file changed, 59 insertions(+), 1 deletion(-)
|
|
|
9201c6 |
|
|
|
9201c6 |
diff --git a/tapsets.cxx b/tapsets.cxx
|
|
|
9201c6 |
index a887e1f..30aebb9 100644
|
|
|
9201c6 |
--- a/tapsets.cxx
|
|
|
9201c6 |
+++ b/tapsets.cxx
|
|
|
9201c6 |
@@ -1376,6 +1376,59 @@ string path_remove_sysroot(const systemtap_session& sess, const string& path)
|
|
|
9201c6 |
return retval;
|
|
|
9201c6 |
}
|
|
|
9201c6 |
|
|
|
9201c6 |
+/*
|
|
|
9201c6 |
+ * Convert 'Global Entry Point' to 'Local Entry Point'.
|
|
|
9201c6 |
+ *
|
|
|
9201c6 |
+ * if @gep contains next address after prologue, don't change it.
|
|
|
9201c6 |
+ *
|
|
|
9201c6 |
+ * For ELF ABI v2 on PPC64 LE, we need to adjust sym.st_value corresponding
|
|
|
9201c6 |
+ * to the bits of sym.st_other. These bits will tell us what's the offset
|
|
|
9201c6 |
+ * of the local entry point from the global entry point.
|
|
|
9201c6 |
+ *
|
|
|
9201c6 |
+ * st_other field is currently only used with ABIv2 on ppc64
|
|
|
9201c6 |
+ */
|
|
|
9201c6 |
+static Dwarf_Addr
|
|
|
9201c6 |
+get_lep(dwarf_query *q, Dwarf_Addr gep)
|
|
|
9201c6 |
+{
|
|
|
9201c6 |
+ Dwarf_Addr bias;
|
|
|
9201c6 |
+ Dwfl_Module *mod = q->dw.module;
|
|
|
9201c6 |
+ Elf* elf = (dwarf_getelf (dwfl_module_getdwarf (mod, &bias))
|
|
|
9201c6 |
+ ?: dwfl_module_getelf (mod, &bias));
|
|
|
9201c6 |
+
|
|
|
9201c6 |
+ GElf_Ehdr ehdr_mem;
|
|
|
9201c6 |
+ GElf_Ehdr* em = gelf_getehdr (elf, &ehdr_mem);
|
|
|
9201c6 |
+ if (em == NULL)
|
|
|
9201c6 |
+ throw SEMANTIC_ERROR (_("Couldn't get elf header"));
|
|
|
9201c6 |
+
|
|
|
9201c6 |
+ if (!(em->e_machine == EM_PPC64) || !((em->e_flags & EF_PPC64_ABI) == 2))
|
|
|
9201c6 |
+ return gep;
|
|
|
9201c6 |
+
|
|
|
9201c6 |
+ int syments = dwfl_module_getsymtab(mod);
|
|
|
9201c6 |
+ for (int i = 1; i < syments; ++i)
|
|
|
9201c6 |
+ {
|
|
|
9201c6 |
+ GElf_Sym sym;
|
|
|
9201c6 |
+ GElf_Word section;
|
|
|
9201c6 |
+ GElf_Addr addr;
|
|
|
9201c6 |
+
|
|
|
9201c6 |
+#if _ELFUTILS_PREREQ (0, 158)
|
|
|
9201c6 |
+ dwfl_module_getsym_info (mod, i, &sym, &addr, §ion, NULL, NULL);
|
|
|
9201c6 |
+#else
|
|
|
9201c6 |
+ dwfl_module_getsym (mod, i, &sym, §ion);
|
|
|
9201c6 |
+ addr = sym.st_value;
|
|
|
9201c6 |
+#endif
|
|
|
9201c6 |
+
|
|
|
9201c6 |
+ /*
|
|
|
9201c6 |
+ * Symbol table contains module_bias + offset. Substract module_bias
|
|
|
9201c6 |
+ * to compare offset with gep.
|
|
|
9201c6 |
+ */
|
|
|
9201c6 |
+ if ((addr - bias) == gep && (GELF_ST_TYPE(sym.st_info) == STT_FUNC)
|
|
|
9201c6 |
+ && sym.st_other)
|
|
|
9201c6 |
+ return gep + PPC64_LOCAL_ENTRY_OFFSET(sym.st_other);
|
|
|
9201c6 |
+ }
|
|
|
9201c6 |
+
|
|
|
9201c6 |
+ return gep;
|
|
|
9201c6 |
+}
|
|
|
9201c6 |
+
|
|
|
9201c6 |
void
|
|
|
9201c6 |
dwarf_query::add_probe_point(interned_string dw_funcname,
|
|
|
9201c6 |
interned_string filename,
|
|
|
9201c6 |
@@ -1384,12 +1437,14 @@ dwarf_query::add_probe_point(interned_string dw_funcname,
|
|
|
9201c6 |
Dwarf_Addr addr)
|
|
|
9201c6 |
{
|
|
|
9201c6 |
interned_string reloc_section; // base section for relocation purposes
|
|
|
9201c6 |
+ Dwarf_Addr orig_addr = addr;
|
|
|
9201c6 |
Dwarf_Addr reloc_addr; // relocated
|
|
|
9201c6 |
interned_string module = dw.module_name; // "kernel" or other
|
|
|
9201c6 |
interned_string funcname = dw_funcname;
|
|
|
9201c6 |
|
|
|
9201c6 |
assert (! has_absolute); // already handled in dwarf_builder::build()
|
|
|
9201c6 |
|
|
|
9201c6 |
+ addr = get_lep(this, addr);
|
|
|
9201c6 |
reloc_addr = dw.relocate_address(addr, reloc_section);
|
|
|
9201c6 |
|
|
|
9201c6 |
// If we originally used the linkage name, then let's call it that way
|
|
|
9201c6 |
@@ -1455,7 +1510,10 @@ dwarf_query::add_probe_point(interned_string dw_funcname,
|
|
|
9201c6 |
|
|
|
9201c6 |
symbol_table *sym_table = mi->sym_table;
|
|
|
9201c6 |
func_info *symbol = sym_table->get_func_containing_address(addr);
|
|
|
9201c6 |
- Dwarf_Addr offset = addr - symbol->addr;
|
|
|
9201c6 |
+
|
|
|
9201c6 |
+ // Do not use LEP to find offset here. When 'symbol_name'
|
|
|
9201c6 |
+ // is used to register probe, kernel itself will find LEP.
|
|
|
9201c6 |
+ Dwarf_Addr offset = orig_addr - symbol->addr;
|
|
|
9201c6 |
results.push_back (new dwarf_derived_probe(funcname, filename,
|
|
|
9201c6 |
line, module,
|
|
|
9201c6 |
reloc_section, addr,
|
|
|
9201c6 |
--
|
|
|
9201c6 |
1.8.3.1
|
|
|
9201c6 |
|