crash-stack: adding fallback heuristic method for unwinding 08/96908/2
authorAdrian Szyndela <adrian.s@samsung.com>
Wed, 7 Sep 2016 10:15:20 +0000 (12:15 +0200)
committerŁukasz Stelmach <l.stelmach@samsung.com>
Thu, 8 Dec 2016 11:25:07 +0000 (12:25 +0100)
This reverts commit b7ef1fff4dd5f8f754df1431fe4b80fc1901b459,
which reverted commit f29763ccb1cf24bea7807b55ecd9722e3cb03743.

In case no better method is ready or available, this method
may yield some useful results. It simply walks over data stack
and checks word after word if it looks like an address from
any function. All such addresses are considered as call stack
functions. It should generally show all the called functions
that left any trace on the stack. However, among those there
may be a number of false positives.

This is currently used for x86_64 architecture.

Change-Id: If8fd88b8ab3e345a256006127c36bcb4022cc736

src/crash-stack/crash-stack-libelf.c

index b152bea..f346b95 100644 (file)
@@ -12,7 +12,7 @@ typedef union {
 static Register g_pc;
 static Register g_sp;
 
-#if _ELFUTILS_PREREQ(0, 158)
+#if _ELFUTILS_PREREQ(0,158)
 static int frame_callback(Dwfl_Frame *state, void *arg)
 {
        Callstack *callstack = (Callstack*)arg;
@@ -51,17 +51,65 @@ static bool is_in(const char *name, const char **names, int elems)
 
 void *get_place_for_register_value(const char *regname, int regnum)
 {
-  if (IS_IN(regname, pc_names)) return &g_pc;
-  else if (IS_IN(regname, sp_names)) return &g_sp;
+       if (IS_IN(regname, pc_names)) return &g_pc;
+       else if (IS_IN(regname, sp_names)) return &g_sp;
 
-  return 0;
+       return 0;
+}
+
+void explore_stack_in_search_of_functions(Dwfl *dwfl, Elf *core, pid_t pid, Mappings *mappings, Callstack *callstack)
+{
+       Dwarf_Addr stack_pointer = sizeof(uintptr_t) == 4 ? g_sp.reg32 : g_sp.reg64;
+       Dwarf_Addr stack_max_lookup = stack_pointer + 8*1024*1024;
+       bool data_remaining = true;
+       do {
+               uintptr_t value;
+               data_remaining = crash_stack_libelf_read_value(dwfl, core, pid, stack_pointer, &value, sizeof(value), mappings);
+               if (data_remaining)
+               {
+                       Dwarf_Addr bias;
+                       /* check presence of address in text sections */
+                       Dwfl_Module *module = dwfl_addrmodule(dwfl, value);
+                       if (module != NULL)
+                       {
+                               Dwarf_Addr elfval = value;
+                               GElf_Sym sym;
+                               GElf_Word shndxp = -1;
+                               dwfl_module_addrsym(module, value, &sym, &shndxp);
+                               Elf_Scn *scn = dwfl_module_address_section(module, &elfval, &bias);
+                               if (scn != 0 || shndxp != -1)
+                               {
+                                       callstack->tab[callstack->elems++] = value;
+                                       if (callstack->elems >= MAX_CALLSTACK_LEN)
+                                               return;
+                               }
+                               else
+                               {
+                                       /* check also inside [pie] and [exe] */
+                                       int i;
+                                       for (i = 0; i < mappings->elems; i++)
+                                       {
+                                               if (mappings->tab[i].m_start <= elfval && elfval < mappings->tab[i].m_end)
+                                               {
+                                                       callstack->tab[callstack->elems++] = value;
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+               }
+               stack_pointer += sizeof(uintptr_t);
+       } while (data_remaining && stack_pointer < stack_max_lookup );
 }
 
 void create_crash_stack(Dwfl *dwfl, Elf *core, pid_t pid, Mappings *mappings, Callstack *callstack)
 {
        callstack->elems = 0;
-#if _ELFUTILS_PREREQ(0, 158)
+#if _ELFUTILS_PREREQ(0,158)
        dwfl_getthreads(dwfl, thread_callback, callstack);
+#else
+       callstack->tab[callstack->elems++] = sizeof(uintptr_t) == 4 ? g_pc.reg32 : g_pc.reg64;
+       explore_stack_in_search_of_functions(dwfl, core, pid, mappings, callstack);
 #endif
 }