]> sourceware.org Git - systemtap.git/commitdiff
PR12276: fix addr adjustment for symfileline()
authorAbegail Jakop <ajakop@redhat.com>
Mon, 22 Dec 2014 20:04:34 +0000 (15:04 -0500)
committerAbegail Jakop <ajakop@redhat.com>
Mon, 22 Dec 2014 20:04:34 +0000 (15:04 -0500)
runtime/sym*: adjust the given address to account for the load offset
runtime/transport/symbols.c: include the body of _stp_module_update_self()
if STP_NEED_LINE_DATA so that the sec_load_offset can be updated
tapset/linux/context-symbols.stp: remove the pragma myproc-unpriveleged
since it's spelled wrong, and it's not needed anyways
translate.cxx: add funtion find_debug_frame_offset() to set the
sec_load_offset for the ".text" section

runtime/sym.c
runtime/sym.h
runtime/transport/symbols.c
tapset/linux/context-symbols.stp
translate.cxx

index c79715962a6aa959967d2eef380653f9160f5cd7..8c2ea2c59bdb313eefe662e50a31dd719ece13c8 100644 (file)
@@ -267,6 +267,11 @@ unsigned long _stp_linenumber_lookup(unsigned long addr, struct task_struct *tas
     {
            unsigned long vm_start = 0;
            unsigned long vm_end = 0;
+#ifdef CONFIG_COMPAT
+      /* Handle 32bit signed values in 64bit longs, chop off top bits. */
+      if (test_tsk_thread_flag(task, TIF_32BIT))
+        addr &= ((compat_ulong_t) ~0);
+#endif
            m = _stp_umod_lookup(addr, task, &modname, &vm_start, &vm_end);
     }
   else
@@ -275,6 +280,25 @@ unsigned long _stp_linenumber_lookup(unsigned long addr, struct task_struct *tas
   if (m == NULL || m->debug_line == NULL)
     return 0;
 
+  // if addr is a kernel address, it will need to be adjusted
+  if (!task)
+    {
+      int i;
+      unsigned long offset = 0;
+      // have to factor in the load_offset of (specifically) the .text section
+      for (i=0; i<m->num_sections; i++)
+        if (!strcmp(m->sections[i].name, ".text"))
+          {
+            offset = (m->sections[i].static_addr - m->sections[i].sec_load_offset);
+            break;
+          }
+
+      if (addr < offset)
+        return 0;
+      addr = addr - offset;
+    }
+
+
   linep = m->debug_line;
   enddatap = m->debug_line + m->debug_line_len;
 
@@ -418,8 +442,6 @@ unsigned long _stp_linenumber_lookup(unsigned long addr, struct task_struct *tas
           else
             {
               int i;
-              if (opcode >= opcode_base)
-                return 0; // encountered a bad opcode
               for (i=stdopcode_lens_secp[opcode]; i>0; --i)
                 read_pointer ((const uint8_t **) &linep, endunitp, DW_EH_PE_leb128, user, compat_task);
             }
index 3ab49f988aa310a67790d0bd1e1fe6584c80f9b5..0cb770867501b0757b5a388e0bc778d4ecce2fac 100644 (file)
@@ -146,10 +146,12 @@ static void _stp_kmodule_update_address(const char* module,
                                         const char* section,
                                         unsigned long offset);
 
-#if defined(STP_USE_DWARF_UNWINDER) && defined(STP_NEED_UNWIND_DATA)
+#if (defined(STP_USE_DWARF_UNWINDER) && defined(STP_NEED_UNWIND_DATA)) \
+    || defined(STP_NEED_LINE_DATA)
 static struct _stp_module _stp_module_self;
 static struct _stp_section _stp_module_self_sections[];
 static struct _stp_symbol _stp_module_self_symbols_0[];
 static struct _stp_symbol _stp_module_self_symbols_1[];
-#endif /* defined(STP_USE_DWARF_UNWINDER) && defined(STP_NEED_UNWIND_DATA) */
+#endif /* defined(STP_USE_DWARF_UNWINDER) && defined(STP_NEED_UNWIND_DATA)
+          || defined(STP_NEED_LINE_DATA) */
 #endif /* _STP_SYM_H_ */
index 867d68624f4fa5f6494a7907553c5d651138e4fe..7274715f3576e0843dddbaf290fb35f3f6d5db5e 100644 (file)
@@ -182,8 +182,10 @@ static int _stp_module_notifier (struct notifier_block * nb,
 static int _stp_module_update_self (void)
 {
        /* Only bother if we need unwinding and have module_sect_attrs.  */
-#if defined(STP_USE_DWARF_UNWINDER) && defined(STP_NEED_UNWIND_DATA)
-#if defined(CONFIG_KALLSYMS) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
+  /* Or if we need to figure out the addr->file:line mapping */
+#if (defined(STP_USE_DWARF_UNWINDER) && defined(STP_NEED_UNWIND_DATA)) \
+    || defined(STP_NEED_LINE_DATA)
+#if defined(CONFIG_KALLSYMS)  && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
 
        bool found_eh_frame = false;
        struct module *mod = THIS_MODULE;
@@ -246,7 +248,8 @@ static int _stp_module_update_self (void)
        }
 
 #endif /* defined(CONFIG_KALLSYMS) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11) */
-#endif /* defined(STP_USE_DWARF_UNWINDER) && defined(STP_NEED_UNWIND_DATA) */
+#endif /* (defined(STP_USE_DWARF_UNWINDER) && defined(STP_NEED_UNWIND_DATA))
+          || defined(STP_NEED_LINE_DATA) */
 
        return 0;
 }
index e1d349a63def1be148313d0c16a539ebcd4d1b34..5622b4ba6eecdde0e1e9abbbb857a6cb29be17c8 100644 (file)
@@ -310,7 +310,7 @@ function sprint_syms (callers:string) {
  * found, the hex string representation of the address will be returned.
  */
 function symfileline:string (addr:long) %{
-/* pure */ /* myproc-unpriveleged */ /* pragma:symbols */ /* pragma:lines */
+/* pure */ /* pragma:symbols */ /* pragma:lines */
   _stp_snprint_addr(STAP_RETVALUE, MAXSTRINGLEN, STAP_ARG_addr,
                     _STP_SYM_LINENUMBER + _STP_SYM_FILENAME, NULL);
 %}
index 748b84d181b67ce39ea56f73ecb37f4925f8e485..f4b8b78f5bc35f8b42830b7753394c3ff610ebba 100644 (file)
@@ -6549,6 +6549,71 @@ dump_section_list (Dwfl_Module *m,
   return DWARF_CB_ABORT;
 }
 
+static void find_debug_frame_offset (Dwfl_Module *m,
+                                     unwindsym_dump_context *c)
+{
+  Dwarf_Addr start, bias = 0;
+  GElf_Ehdr *ehdr, ehdr_mem;
+  GElf_Shdr *shdr, shdr_mem;
+  Elf_Scn *scn = NULL;
+  Elf_Data *data = NULL;
+  Elf *elf;
+
+  dwfl_module_info (m, NULL, &start, NULL, NULL, NULL, NULL, NULL);
+
+  // fetch .debug_frame info preferably from dwarf debuginfo file.
+  elf = (dwarf_getelf (dwfl_module_getdwarf (m, &bias))
+        ?: dwfl_module_getelf (m, &bias));
+  ehdr = gelf_getehdr(elf, &ehdr_mem);
+
+  while ((scn = elf_nextscn(elf, scn)))
+    {
+      shdr = gelf_getshdr(scn, &shdr_mem);
+      if (strcmp(elf_strptr(elf, ehdr->e_shstrndx, shdr->sh_name),
+                ".debug_frame") == 0)
+       {
+         data = elf_rawdata(scn, NULL);
+         break;
+       }
+    }
+
+  if (!data) // need this check since dwarf_next_cfi() doesn't do it
+    return;
+
+  // In the .debug_frame the FDE encoding is always DW_EH_PE_absptr.
+  // So there is no need to read the CIEs.  And the size is either 4
+  // or 8, depending on the elf class from e_ident.
+  int size = (ehdr->e_ident[EI_CLASS] == ELFCLASS32) ? 4 : 8;
+  int res = 0;
+  Dwarf_Off off = 0;
+  Dwarf_CFI_Entry entry;
+
+  while (res != 1)
+    {
+      Dwarf_Off next_off;
+      res = dwarf_next_cfi (ehdr->e_ident, data, false, off, &next_off, &entry);
+      if (res == 0)
+       {
+         if (entry.CIE_id != DW_CIE_ID_64) // ignore CIEs
+           {
+             Dwarf_Addr addr;
+             if (size == 4)
+               addr = (*((uint32_t *) entry.fde.start));
+             else
+               addr = (*((uint64_t *) entry.fde.start));
+              Dwarf_Addr first_addr = addr;
+              int res = dwfl_module_relocate_address (m, &first_addr);
+              DWFL_ASSERT ("find_debug_frame_offset, dwfl_module_relocate_address",
+                           res >= 0);
+              c->debug_frame_off = addr - first_addr;
+           }
+       }
+      else if (res < 1)
+        return;
+      off = next_off;
+    }
+}
+
 static void
 dump_line_tables (Dwfl_Module *m, unwindsym_dump_context *c,
                   const char *modname, Dwarf_Addr base)
@@ -6582,6 +6647,11 @@ dump_line_tables (Dwfl_Module *m, unwindsym_dump_context *c,
           break;
         }
     }
+
+  // still need to get some kind of information about the sec_load_offset for
+  // kernel addresses if there is no unwind data
+  if (c->debug_line_len > 0 && !c->session.need_unwind)
+    find_debug_frame_offset (m, c);
 }
 
 /* Some architectures create special local symbols that are not
@@ -7021,7 +7091,18 @@ dump_unwindsym_cxt (Dwfl_Module *m,
        {
          c->output << ".debug_hdr = NULL,\n";
          c->output << ".debug_hdr_len = 0,\n";
+          if (c->session.need_lines && secname == ".text")
+            {
+              c->output << "#if defined(STP_NEED_LINE_DATA)\n";
+              Dwarf_Addr dwbias = 0;
+              dwfl_module_getdwarf (m, &dwbias);
+              c->output << ".sec_load_offset = 0x"
+                        << hex << debug_frame_off - dwbias << dec << "\n";
+              c->output << "#else\n";
+            }
          c->output << ".sec_load_offset = 0\n";
+          if (c->session.need_lines && secname == ".text")
+            c->output << "#endif /* STP_NEED_LINE_DATA */\n";
        }
 
        c->output << "},\n";
This page took 0.034858 seconds and 5 git commands to generate.