Blame SOURCES/rhbz1376515.patch

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