crash-stack: adding fallback heuristic method for unwinding 71/76371/4
authorAdrian Szyndela <adrian.s@samsung.com>
Thu, 23 Jun 2016 13:01:27 +0000 (15:01 +0200)
committerAdrian Szyndela <adrian.s@samsung.com>
Wed, 24 Aug 2016 12:12:12 +0000 (05:12 -0700)
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* architectures.

Change-Id: I0ce28260ed9a6c51b925e1041a3496c1959cab1f

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

index b152beab3c31107b407b6362e4e24a2447f85df2..f346b955089ccabe1312ab9bbe6e518bfb38f973 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
 }