]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
+memory_read callback.
authorJan Kratochvil <jan.kratochvil@redhat.com>
Wed, 24 Oct 2012 20:04:01 +0000 (22:04 +0200)
committerJan Kratochvil <jan.kratochvil@redhat.com>
Wed, 24 Oct 2012 20:04:01 +0000 (22:04 +0200)
backends/s390_frame_unwind.c
libdwfl/dwfl_frame_state.c
libdwfl/dwfl_frame_unwind.c
libdwfl/libdwfl.h
libdwfl/libdwflP.h
libebl/ebl-hooks.h
libebl/eblframeunwind.c
libebl/libebl.h

index f285d68462586727702750fba179f572d2b7d808..fa4c0aca1f11a1391806955783895a19aa809309 100644 (file)
@@ -38,9 +38,7 @@
 #include "libebl_CPU.h"
 
 bool
-s390_frame_unwind (Ebl *ebl, Dwfl_Frame_State **statep, Dwarf_Addr pc,
-                  bool (*memory_read) (Dwfl_Frame_State_Process *process,
-                                       Dwarf_Addr addr, Dwarf_Addr *result))
+s390_frame_unwind (Ebl *ebl, Dwfl_Frame_State **statep, Dwarf_Addr pc)
 {
   Dwfl_Frame_State *state = *statep;
   Dwfl_Frame_State_Process *process = state->thread->process;
@@ -52,7 +50,7 @@ s390_frame_unwind (Ebl *ebl, Dwfl_Frame_State **statep, Dwarf_Addr pc,
   pc++;
   /* We can assume big-endian read here.  */
   Dwarf_Addr instr;
-  if (! memory_read (process, pc, &instr))
+  if (! process->memory_read (pc, &instr, process->memory_read_user_data))
     return false;
   /* Fetch only the very first two bytes.  */
   instr = (instr >> (ebl->class == ELFCLASS64 ? 48 : 16)) & 0xffff;
@@ -73,13 +71,14 @@ s390_frame_unwind (Ebl *ebl, Dwfl_Frame_State **statep, Dwarf_Addr pc,
   /* "New-style RT frame" is not supported,
      assuming "Old-style RT frame and all non-RT frames".  */
   Dwarf_Addr sigreg_ptr;
-  if (! memory_read (process, next_cfa + 8, &sigreg_ptr))
+  if (! process->memory_read (next_cfa + 8, &sigreg_ptr,
+                             process->memory_read_user_data))
     return false;
   /* Skip PSW mask.  */
   sigreg_ptr += word_size;
   /* Read PSW address.  */
   Dwarf_Addr val;
-  if (! memory_read (process, sigreg_ptr, &val))
+  if (! process->memory_read (sigreg_ptr, &val, process->memory_read_user_data))
     return false;
   sigreg_ptr += word_size;
   size_t nregs = ebl->frame_state_nregs;
@@ -95,7 +94,8 @@ s390_frame_unwind (Ebl *ebl, Dwfl_Frame_State **statep, Dwarf_Addr pc,
   /* Then the GPRs.  */
   for (int i = 0; i < 16; i++)
     {
-      if (! memory_read (process, sigreg_ptr, &val))
+      if (! process->memory_read (sigreg_ptr, &val,
+                                 process->memory_read_user_data))
        return false;
       if (! dwfl_frame_state_reg_set (unwound, 0 + i, val))
        return false;
@@ -109,12 +109,14 @@ s390_frame_unwind (Ebl *ebl, Dwfl_Frame_State **statep, Dwarf_Addr pc,
   /* And finally the FPRs.  */
   for (int i = 0; i < 16; i++)
     {
-      if (! memory_read (process, sigreg_ptr, &val))
+      if (! process->memory_read (sigreg_ptr, &val,
+                                 process->memory_read_user_data))
        return false;
       if (ebl->class == ELFCLASS32)
        {
          Dwarf_Addr val_low;
-         if (! memory_read (process, sigreg_ptr + 4, &val_low))
+         if (! process->memory_read (sigreg_ptr + 4, &val_low,
+                                     process->memory_read_user_data))
            return false;
          val = (val << 32) | val_low;
        }
@@ -129,7 +131,8 @@ s390_frame_unwind (Ebl *ebl, Dwfl_Frame_State **statep, Dwarf_Addr pc,
       sigreg_ptr += sigreg_high_off;
       for (int i = 0; i < 16; i++)
        {
-         if (! memory_read (process, sigreg_ptr, &val))
+         if (! process->memory_read (sigreg_ptr, &val,
+                                     process->memory_read_user_data))
            return false;
          Dwarf_Addr val_low;
          if (! dwfl_frame_state_reg_get (unwound, 0 + i, &val_low))
index d5eae72f8066733ae8cd174e5b990f7c7f18afe1..f41b98473f8ec1a69c96bade6d355f1d3d4c5e9b 100644 (file)
 # define MIN(a, b) ((a) < (b) ? (a) : (b))
 #endif
 
+/* Exact copy from libdwfl/segment.c.  */
+
+static GElf_Addr
+segment_start (Dwfl *dwfl, GElf_Addr start)
+{
+  if (dwfl->segment_align > 1)
+    start &= -dwfl->segment_align;
+  return start;
+}
+
+/* Exact copy from libdwfl/segment.c.  */
+
+static GElf_Addr
+segment_end (Dwfl *dwfl, GElf_Addr end)
+{
+  if (dwfl->segment_align > 1)
+    end = (end + dwfl->segment_align - 1) & -dwfl->segment_align;
+  return end;
+}
+
 static bool
 tid_is_attached (Dwfl *dwfl, pid_t tid)
 {
@@ -169,7 +189,8 @@ process_free (Dwfl_Frame_State_Process *process)
 }
 
 static Dwfl_Frame_State_Process *
-process_alloc (Dwfl *dwfl)
+process_alloc (Dwfl *dwfl, dwfl_frame_memory_read_t *memory_read,
+              void *memory_read_user_data)
 {
   Dwfl_Frame_State_Process *process = malloc (sizeof (*process));
   if (process == NULL)
@@ -177,6 +198,8 @@ process_alloc (Dwfl *dwfl)
   process->dwfl = dwfl;
   process->ebl = NULL;
   process->ebl_close = NULL;
+  process->memory_read = memory_read;
+  process->memory_read_user_data = memory_read_user_data;
   process->core = NULL;
   process->core_fd = -1;
   process->thread = NULL;
@@ -211,15 +234,63 @@ ptrace_attach (pid_t tid)
   return true;
 }
 
+static bool
+dwfl_frame_state_pid_memory_read (Dwarf_Addr addr, Dwarf_Addr *result,
+                                 void *user_data)
+{
+  Dwfl_Frame_State_Process *process = user_data;
+  assert (process->core == NULL && process->thread->tid);
+  if (process->ebl->class == ELFCLASS64)
+    {
+      errno = 0;
+      *result = ptrace (PTRACE_PEEKDATA, process->thread->tid,
+                       (void *) (uintptr_t) addr, NULL);
+      if (errno != 0)
+       {
+         __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
+         return false;
+       }
+      return true;
+    }
+#if SIZEOF_LONG == 8
+  /* We do not care about reads unaliged to 4 bytes boundary.
+     But 0x...ffc read of 8 bytes could overrun a page.  */
+  bool lowered = (addr & 4) != 0;
+  if (lowered)
+    addr -= 4;
+#endif /* SIZEOF_LONG == 8 */
+  errno = 0;
+  *result = ptrace (PTRACE_PEEKDATA, process->thread->tid,
+                   (void *) (uintptr_t) addr, NULL);
+  if (errno != 0)
+    {
+      __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
+      return false;
+    }
+#if SIZEOF_LONG == 8
+# if BYTE_ORDER == BIG_ENDIAN
+  if (! lowered)
+    *result >>= 32;
+# else
+  if (lowered)
+    *result >>= 32;
+# endif
+#endif /* SIZEOF_LONG == 8 */
+  *result &= 0xffffffff;
+  return true;
+}
+
 Dwfl_Frame_State *
 dwfl_frame_state_pid (Dwfl *dwfl, pid_t pid)
 {
   char dirname[64];
   int i = snprintf (dirname, sizeof (dirname), "/proc/%ld/task", (long) pid);
   assert (i > 0 && i < (ssize_t) sizeof (dirname) - 1);
-  Dwfl_Frame_State_Process *process = process_alloc (dwfl);
+  Dwfl_Frame_State_Process *process;
+  process = process_alloc (dwfl, dwfl_frame_state_pid_memory_read, NULL);
   if (process == NULL)
     return NULL;
+  process->memory_read_user_data = process;
   for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next)
     {
       Dwfl_Error error = __libdwfl_module_getebl (mod);
@@ -312,12 +383,60 @@ dwfl_frame_state_pid (Dwfl *dwfl, pid_t pid)
 }
 INTDEF (dwfl_frame_state_pid)
 
+static bool
+dwfl_frame_state_core_memory_read (Dwarf_Addr addr, Dwarf_Addr *result,
+                                  void *user_data)
+{
+  Dwfl_Frame_State_Process *process = user_data;
+  Elf *core = process->core;
+  assert (core != NULL);
+  Dwfl *dwfl = process->dwfl;
+  static size_t phnum;
+  if (elf_getphdrnum (core, &phnum) < 0)
+    {
+      __libdwfl_seterrno (DWFL_E_LIBELF);
+      return false;
+    }
+  for (size_t cnt = 0; cnt < phnum; ++cnt)
+    {
+      GElf_Phdr phdr_mem, *phdr = gelf_getphdr (core, cnt, &phdr_mem);
+      if (phdr == NULL || phdr->p_type != PT_LOAD)
+       continue;
+      /* Bias is zero here, a core file itself has no bias.  */
+      GElf_Addr start = segment_start (dwfl, phdr->p_vaddr);
+      GElf_Addr end = segment_end (dwfl, phdr->p_vaddr + phdr->p_memsz);
+      unsigned bytes = process->ebl->class == ELFCLASS64 ? 8 : 4;
+      if (addr < start || addr + bytes > end)
+       continue;
+      Elf_Data *data;
+      data = elf_getdata_rawchunk (core, phdr->p_offset + addr - start,
+                                  bytes, ELF_T_ADDR);
+      if (data == NULL)
+       {
+         __libdwfl_seterrno (DWFL_E_LIBELF);
+         return false;
+       }
+      assert (data->d_size == bytes);
+      /* FIXME: Currently any arch supported for unwinding supports
+        unaligned access.  */
+      if (bytes == 8)
+       *result = *(const uint64_t *) data->d_buf;
+      else
+       *result = *(const uint32_t *) data->d_buf;
+      return true;
+    }
+  __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
+  return false;
+}
+
 Dwfl_Frame_State *
 dwfl_frame_state_core (Dwfl *dwfl, const char *corefile)
 {
-  Dwfl_Frame_State_Process *process = process_alloc (dwfl);
+  Dwfl_Frame_State_Process *process;
+  process = process_alloc (dwfl, dwfl_frame_state_core_memory_read, NULL);
   if (process == NULL)
     return NULL;
+  process->memory_read_user_data = process;
   int core_fd = open64 (corefile, O_RDONLY);
   if (core_fd < 0)
     {
@@ -521,7 +640,9 @@ INTDEF (dwfl_frame_state_core)
 
 Dwfl_Frame_State *
 dwfl_frame_state_data (Dwfl *dwfl, int pc_set, Dwarf_Addr pc, unsigned nregs,
-                      const uint64_t *regs_set, const Dwarf_Addr *regs)
+                      const uint64_t *regs_set, const Dwarf_Addr *regs,
+                      dwfl_frame_memory_read_t *memory_read,
+                      void *memory_read_user_data)
 {
   Ebl *ebl = NULL;
   for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next)
@@ -536,7 +657,8 @@ dwfl_frame_state_data (Dwfl *dwfl, int pc_set, Dwarf_Addr pc, unsigned nregs,
       __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
       return NULL;
     }
-  Dwfl_Frame_State_Process *process = process_alloc (dwfl);
+  Dwfl_Frame_State_Process *process;
+  process = process_alloc (dwfl, memory_read, memory_read_user_data);
   if (process == NULL)
     return NULL;
   process->ebl = ebl;
index fc70a95a1cfa731fdc616b3f542e345a02fbaac5..53a4cd65ae3a383f4a74c3b3f33d90006d6582aa 100644 (file)
 # define MAX(a, b) ((a) > (b) ? (a) : (b))
 #endif
 
-/* Exact copy from libdwfl/segment.c.  */
-
-static GElf_Addr
-segment_start (Dwfl *dwfl, GElf_Addr start)
-{
-  if (dwfl->segment_align > 1)
-    start &= -dwfl->segment_align;
-  return start;
-}
-
-/* Exact copy from libdwfl/segment.c.  */
-
-static GElf_Addr
-segment_end (Dwfl *dwfl, GElf_Addr end)
-{
-  if (dwfl->segment_align > 1)
-    end = (end + dwfl->segment_align - 1) & -dwfl->segment_align;
-  return end;
-}
-
 static bool
 state_get_reg (Dwfl_Frame_State *state, unsigned regno, Dwarf_Addr *val)
 {
@@ -71,95 +51,6 @@ state_get_reg (Dwfl_Frame_State *state, unsigned regno, Dwarf_Addr *val)
   return true;
 }
 
-static bool
-memory_read (Dwfl_Frame_State_Process *process, Dwarf_Addr addr,
-            Dwarf_Addr *result)
-{
-  if (process->core == NULL)
-    {
-      if (process->ebl->class == ELFCLASS64)
-       {
-         errno = 0;
-         *result = ptrace (PTRACE_PEEKDATA, process->thread->tid,
-                           (void *) (uintptr_t) addr, NULL);
-         if (errno != 0)
-           {
-             __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
-             return false;
-           }
-         return true;
-       }
-#if SIZEOF_LONG == 8
-      /* We do not care about reads unaliged to 4 bytes boundary.
-         But 0x...ffc read of 8 bytes could overrun a page.  */
-      bool lowered = (addr & 4) != 0;
-      if (lowered)
-       addr -= 4;
-#endif /* SIZEOF_LONG == 8 */
-      errno = 0;
-      *result = ptrace (PTRACE_PEEKDATA, process->thread->tid,
-                       (void *) (uintptr_t) addr, NULL);
-      if (errno != 0)
-       {
-         __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
-         return false;
-       }
-#if SIZEOF_LONG == 8
-# if BYTE_ORDER == BIG_ENDIAN
-      if (! lowered)
-       *result >>= 32;
-# else
-      if (lowered)
-       *result >>= 32;
-# endif
-#endif /* SIZEOF_LONG == 8 */
-      *result &= 0xffffffff;
-      return true;
-    }
-  if (process->core)
-    {
-      Elf *core = process->core;
-      Dwfl *dwfl = process->dwfl;
-      static size_t phnum;
-      if (elf_getphdrnum (core, &phnum) < 0)
-       {
-         __libdwfl_seterrno (DWFL_E_LIBELF);
-         return false;
-       }
-      for (size_t cnt = 0; cnt < phnum; ++cnt)
-       {
-         GElf_Phdr phdr_mem, *phdr = gelf_getphdr (core, cnt, &phdr_mem);
-         if (phdr == NULL || phdr->p_type != PT_LOAD)
-           continue;
-         /* Bias is zero here, a core file itself has no bias.  */
-         GElf_Addr start = segment_start (dwfl, phdr->p_vaddr);
-         GElf_Addr end = segment_end (dwfl, phdr->p_vaddr + phdr->p_memsz);
-         unsigned bytes = process->ebl->class == ELFCLASS64 ? 8 : 4;
-         if (addr < start || addr + bytes > end)
-           continue;
-         Elf_Data *data;
-         data = elf_getdata_rawchunk (core, phdr->p_offset + addr - start,
-                                      bytes, ELF_T_ADDR);
-         if (data == NULL)
-           {
-             __libdwfl_seterrno (DWFL_E_LIBELF);
-             return false;
-           }
-         assert (data->d_size == bytes);
-         /* FIXME: Currently any arch supported for unwinding supports
-            unaligned access.  */
-         if (bytes == 8)
-           *result = *(const uint64_t *) data->d_buf;
-         else
-           *result = *(const uint32_t *) data->d_buf;
-         return true;
-       }
-      __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
-      return false;
-    }
-  abort ();
-}
-
 static int
 bra_compar (const void *key_voidp, const void *elem_voidp)
 {
@@ -174,6 +65,7 @@ static bool
 expr_eval (Dwfl_Frame_State *state, Dwarf_Frame *frame, const Dwarf_Op *ops,
           size_t nops, Dwarf_Addr *result)
 {
+  Dwfl_Frame_State_Process *process = state->thread->process;
   if (nops == 0)
     {
       __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
@@ -287,7 +179,9 @@ expr_eval (Dwfl_Frame_State *state, Dwarf_Frame *frame, const Dwarf_Op *ops,
        is_location = false;
        break;
       case DW_OP_deref:
-       if (! pop (&val1) || ! memory_read (state->thread->process, val1, &val1)
+       if (! pop (&val1)
+           || ! process->memory_read (val1, &val1,
+                                      process->memory_read_user_data)
            || ! push (val1))
          {
            free (stack);
@@ -388,7 +282,8 @@ expr_eval (Dwfl_Frame_State *state, Dwarf_Frame *frame, const Dwarf_Op *ops,
       return false;
     }
   free (stack);
-  if (is_location && ! memory_read (state->thread->process, *result, result))
+  if (is_location && ! process->memory_read (*result, result,
+                                            process->memory_read_user_data))
     return false;
   return true;
 }
@@ -600,7 +495,7 @@ dwfl_frame_unwind (Dwfl_Frame_State **statep)
        }
     }
   *statep = state;
-  if (ebl_frame_unwind (state->thread->process->ebl, statep, pc, memory_read))
+  if (ebl_frame_unwind (state->thread->process->ebl, statep, pc))
     return true;
   if (state->unwound)
     {
index 943dfb70b40e9ef2ab89909877b9dd33f5981382..5cba1cb17deb0f06759c8e1a6a45b37fea259277 100644 (file)
@@ -572,10 +572,15 @@ extern Dwfl_Frame_State *dwfl_frame_state_core (Dwfl *dwfl,
                                                const char *corefile);
 
 /* Fetch inferior registers from a caller supplied storage.  */
+typedef bool dwfl_frame_memory_read_t (Dwarf_Addr addr, Dwarf_Addr *result,
+                                      void *user_data);
 extern Dwfl_Frame_State *dwfl_frame_state_data (Dwfl *dwfl, int pc_set,
                                                Dwarf_Addr pc, unsigned nregs,
                                                const uint64_t *regs_set,
-                                               const Dwarf_Addr *regs);
+                                               const Dwarf_Addr *regs,
+                                               dwfl_frame_memory_read_t
+                                                                  *memory_read,
+                                               void *memory_read_user_data);
 
 /* Return TRUE and update *STATEP for the unwound frame for successful unwind.
    Return TRUE and set *STATEP to NULL for the outermost frame.  Return FALSE
index 194beb64999a62c7301bdbf735a8c3bace684fe5..52f2f7f5760060913bf9c760eecfe03edb4409ac 100644 (file)
@@ -198,6 +198,8 @@ struct Dwfl_Frame_State_Process
   struct ebl *ebl;
   /* If it is false we share EBL with one of DWFL's Dwfl_Module->ebl.  */
   bool ebl_close : 1;
+  dwfl_frame_memory_read_t *memory_read;
+  void *memory_read_user_data;
   /* If there is no core file both CORE is NULL and CORE_FD is -1.  */
   Elf *core;
   int core_fd;
index 9372c8facf4fa4e26ae038921fa74feff8d07713..222680744fe33f2ba735af1fafe2b6e885981c23 100644 (file)
@@ -183,13 +183,8 @@ bool EBLHOOK(frame_dwarf_to_regno) (Ebl *ebl, unsigned *regno);
 void EBLHOOK(normalize_pc) (Ebl *ebl, Dwarf_Addr *pc);
 
 /* See dwfl_frame_unwind.  */
-bool
-  EBLHOOK(frame_unwind) (Ebl *ebl, struct Dwfl_Frame_State **statep,
-                        Dwarf_Addr pc,
-                        bool (*memory_read) (
-                                      struct Dwfl_Frame_State_Process *process,
-                                             Dwarf_Addr addr,
-                                             Dwarf_Addr *result));
+bool EBLHOOK(frame_unwind) (Ebl *ebl, struct Dwfl_Frame_State **statep,
+                           Dwarf_Addr pc);
 
 /* Destructor for ELF backend handle.  */
 void EBLHOOK(destr) (struct ebl *);
index c991c41909e201ca85269f6ca43b402c0bba7a2e..adc658b839fa0b01ebe0da2200d73fee513be906 100644 (file)
 #include <libeblP.h>
 
 bool
-ebl_frame_unwind (Ebl *ebl, struct Dwfl_Frame_State **statep, Dwarf_Addr pc,
-                 bool (*memory_read) (struct Dwfl_Frame_State_Process *process,
-                                      Dwarf_Addr addr, Dwarf_Addr *result))
+ebl_frame_unwind (Ebl *ebl, struct Dwfl_Frame_State **statep, Dwarf_Addr pc)
 {
   if (ebl == NULL || ebl->frame_unwind == NULL)
     return false;
-  return ebl->frame_unwind (ebl, statep, pc, memory_read);
+  return ebl->frame_unwind (ebl, statep, pc);
 }
index be2f5cb59afbe2a19a4956a51e396a88a8b90576..967980e57564c05d89edeca940fd3219b66c7c0f 100644 (file)
@@ -400,11 +400,8 @@ extern void ebl_normalize_pc (Ebl *ebl, Dwarf_Addr *pc)
 /* Get previous frame state for an existing frame state.  */
 struct Dwfl_Frame_State_Process;
 extern bool
-  ebl_frame_unwind (Ebl *ebl, struct Dwfl_Frame_State **statep, Dwarf_Addr pc,
-                   bool
-                     (*memory_read) (struct Dwfl_Frame_State_Process *process,
-                                     Dwarf_Addr addr, Dwarf_Addr *result))
-  __nonnull_attribute__ (1, 2, 4);
+  ebl_frame_unwind (Ebl *ebl, struct Dwfl_Frame_State **statep, Dwarf_Addr pc)
+  __nonnull_attribute__ (1, 2);
 
 /* Convert *REGNO as is in DWARF to a lower range.  */
 extern bool ebl_frame_dwarf_to_regno (Ebl *ebl, unsigned *regno)