{
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
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;
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);
}
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;
}
#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;
}
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)
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
{
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";