diff mbox

[3/6] Prevent the use of struct dl_phdr_info outside of dl_iterate_phdr

Message ID 1319704692-4464-4-git-send-email-ken.werner@linaro.org
State Accepted
Commit 059676cb00cfdd3be17dfdeb25547037737f1b68
Headers show

Commit Message

Ken Werner Oct. 27, 2011, 8:38 a.m. UTC
Since the dl_iterate_phdr is required for local unwinding only the use of
struct dl_phdr_info can be eliminated in case libunwind gets compiled for
remote unwinding. This enhances libunwinds portability to targets that
don't provide any dl_iterate_phdr functionality.

Signed-off-by: Ken Werner <ken.werner@linaro.org>
---
 include/dwarf.h                  |    4 ++-
 src/dwarf/Gfind_proc_info-lsb.c  |   73 ++++++++++++++++++--------------------
 src/ptrace/_UPT_find_proc_info.c |   50 ++++++++++---------------
 3 files changed, 58 insertions(+), 69 deletions(-)
diff mbox

Patch

diff --git a/include/dwarf.h b/include/dwarf.h
index cdf9f24..f2f8bf9 100644
--- a/include/dwarf.h
+++ b/include/dwarf.h
@@ -387,7 +387,9 @@  extern int dwarf_find_proc_info (unw_addr_space_t as, unw_word_t ip,
 				 int need_unwind_info, void *arg);
 #endif /* !UNW_REMOTE_ONLY */
 extern int dwarf_find_debug_frame (int found, unw_dyn_info_t *di_debug,
-				 struct dl_phdr_info *info, unw_word_t ip);
+				   unw_word_t ip, unw_word_t segbase,
+				   const char* obj_name, unw_word_t start,
+				   unw_word_t end);
 extern int dwarf_search_unwind_table (unw_addr_space_t as,
 				      unw_word_t ip,
 				      unw_dyn_info_t *di,
diff --git a/src/dwarf/Gfind_proc_info-lsb.c b/src/dwarf/Gfind_proc_info-lsb.c
index 77d1c00..ee3872e 100644
--- a/src/dwarf/Gfind_proc_info-lsb.c
+++ b/src/dwarf/Gfind_proc_info-lsb.c
@@ -26,7 +26,9 @@  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
 /* Locate an FDE via the ELF data-structures defined by LSB v1.3
    (http://www.linuxbase.org/spec/).  */
 
+#ifndef UNW_REMOTE_ONLY
 #include <link.h>
+#endif /* !UNW_REMOTE_ONLY */
 #include <stddef.h>
 #include <stdio.h>
 #include <limits.h>
@@ -269,17 +271,15 @@  find_binary_for_address (unw_word_t ip, char *name, size_t name_size)
    pointer to debug frame descriptor, or zero if not found.  */
 
 static struct unw_debug_frame_list *
-locate_debug_info (unw_addr_space_t as, struct dl_phdr_info *info,
-		   unw_word_t addr, const char *dlname)
+locate_debug_info (unw_addr_space_t as, unw_word_t addr, const char *dlname,
+		   unw_word_t start, unw_word_t end)
 {
   struct unw_debug_frame_list *w, *fdesc = 0;
   char path[PATH_MAX];
   char *name = path;
   int err;
-  uint64_t start = 0, end = 0;
   char *buf;
   size_t bufsize;
-  unsigned int i;
 
   /* First, see if we loaded this frame already.  */
 
@@ -306,29 +306,6 @@  locate_debug_info (unw_addr_space_t as, struct dl_phdr_info *info,
   else
     name = (char*) dlname;
 
-  /* Find the start/end of the described region by parsing the
-     dl_phdr_info structure.  */
-
-  start = info->dlpi_addr + info->dlpi_phdr[0].p_vaddr;
-  end = start;
-
-  for (i = 0; i < info->dlpi_phnum; i++)
-    {
-      Elf_W (Addr) hdrbase = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
-      Elf_W (Addr) hdrlimit = hdrbase + info->dlpi_phdr[i].p_memsz;
-
-      if (info->dlpi_phdr[i].p_type != PT_LOAD)
-	continue;
-
-      if (hdrbase < start)
-	start = hdrbase;
-      if (hdrlimit > end)
-	end = hdrlimit;
-    }
-
-  Debug (4, "calculated bounds of %lx-%lx for '%s'\n", (long)start, (long)end,
-	 name);
-  
   err = load_debug_frame (name, &buf, &bufsize, as == unw_local_addr_space);
   
   if (!err)
@@ -409,19 +386,19 @@  debug_frame_tab_compare (const void *a, const void *b)
 }
 
 PROTECTED int
-dwarf_find_debug_frame (int found, unw_dyn_info_t *di_debug,
-                       struct dl_phdr_info *info, unw_word_t ip)
+dwarf_find_debug_frame (int found, unw_dyn_info_t *di_debug, unw_word_t ip,
+			unw_word_t segbase, const char* obj_name,
+			unw_word_t start, unw_word_t end)
 {
   unw_dyn_info_t *di;
   struct unw_debug_frame_list *fdesc = 0;
   unw_accessors_t *a;
   unw_word_t addr;
 
-  Debug (15, "Trying to find .debug_frame info->dlpi_name=%s\n",
-        info->dlpi_name);
+  Debug (15, "Trying to find .debug_frame for %s\n", obj_name);
   di = di_debug;
 
-  fdesc = locate_debug_info (unw_local_addr_space, info, ip, info->dlpi_name);
+  fdesc = locate_debug_info (unw_local_addr_space, ip, obj_name, start, end);
 
   if (!fdesc)
     {
@@ -539,10 +516,10 @@  dwarf_find_debug_frame (int found, unw_dyn_info_t *di_debug,
       di->format = UNW_INFO_FORMAT_TABLE;
       di->start_ip = fdesc->start;
       di->end_ip = fdesc->end;
-      di->u.ti.name_ptr = (unw_word_t) (uintptr_t) info->dlpi_name;
+      di->u.ti.name_ptr = (unw_word_t) (uintptr_t) obj_name;
       di->u.ti.table_data = (unw_word_t *) fdesc;
       di->u.ti.table_len = sizeof (*fdesc) / sizeof (unw_word_t);
-      di->u.ti.segbase = (unw_word_t) (uintptr_t) info->dlpi_addr;
+      di->u.ti.segbase = segbase;
 
       found = 1;
       Debug (15, "found debug_frame table `%s': segbase=0x%lx, len=%lu, "
@@ -567,7 +544,7 @@  dwarf_callback (struct dl_phdr_info *info, size_t size, void *ptr)
   struct dwarf_callback_data *cb_data = ptr;
   unw_dyn_info_t *di = &cb_data->di;
   const Elf_W(Phdr) *phdr, *p_eh_hdr, *p_dynamic, *p_text;
-  unw_word_t addr, eh_frame_start, eh_frame_end, fde_count, ip;
+  unw_word_t addr, eh_frame_start, eh_frame_end, fde_count, ip, start, end;
   Elf_W(Addr) load_base, segbase = 0, max_load_addr = 0;
   int ret, need_unwind_info = cb_data->need_unwind_info;
   unw_proc_info_t *pi = cb_data->pi;
@@ -733,9 +710,29 @@  dwarf_callback (struct dl_phdr_info *info, size_t size, void *ptr)
     }
 
 #ifdef CONFIG_DEBUG_FRAME
-  {
-      found = dwarf_find_debug_frame (found, &cb_data->di_debug, info, ip);
-  }
+  /* Find the start/end of the described region by parsing the phdr_info
+     structure.  */
+  start = (unw_word_t) -1;
+  end = 0;
+
+  for (n = 0; n < info->dlpi_phnum; n++)
+    {
+      if (info->dlpi_phdr[n].p_type == PT_LOAD)
+        {
+	  unw_word_t seg_start = info->dlpi_addr + info->dlpi_phdr[n].p_vaddr;
+          unw_word_t seg_end = seg_start + info->dlpi_phdr[n].p_memsz;
+
+	  if (seg_start < start)
+	    start = seg_start;
+
+	  if (seg_end > end)
+	    end = seg_end;
+	}
+    }
+
+  found = dwarf_find_debug_frame (found, &cb_data->di_debug, ip,
+				  info->dlpi_addr, info->dlpi_name, start,
+				  end);
 #endif  /* CONFIG_DEBUG_FRAME */
 
   return found;
diff --git a/src/ptrace/_UPT_find_proc_info.c b/src/ptrace/_UPT_find_proc_info.c
index 7aaa0c2..ee0b698 100644
--- a/src/ptrace/_UPT_find_proc_info.c
+++ b/src/ptrace/_UPT_find_proc_info.c
@@ -172,6 +172,8 @@  _UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as,
   Elf_W(Phdr) *phdr, *ptxt = NULL, *peh_hdr = NULL, *pdyn = NULL;
   unw_word_t addr, eh_frame_start, fde_count, load_base;
   unw_word_t max_load_addr = 0;
+  unw_word_t start_ip = (unw_word_t) -1;
+  unw_word_t end_ip = 0;
   struct dwarf_eh_frame_hdr *hdr;
   unw_proc_info_t pi;
   unw_accessors_t *a;
@@ -194,6 +196,12 @@  _UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as,
       switch (phdr[i].p_type)
 	{
 	case PT_LOAD:
+	  if (phdr[i].p_vaddr < start_ip)
+	    start_ip = phdr[i].p_vaddr;
+
+	  if (phdr[i].p_vaddr + phdr[i].p_memsz > end_ip)
+	    end_ip = phdr[i].p_vaddr + phdr[i].p_memsz;
+
 	  if (phdr[i].p_offset == mapoff)
 	    ptxt = phdr + i;
 	  if ((uintptr_t) ui->ei.image + phdr->p_filesz > max_load_addr)
@@ -222,6 +230,10 @@  _UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as,
   if (!ptxt)
     return 0;
 
+  load_base = segbase - ptxt->p_vaddr;
+  start_ip += load_base;
+  end_ip += load_base;
+
   if (peh_hdr)
     {
       if (pdyn)
@@ -305,10 +317,8 @@  _UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as,
     #endif
 	}
 
-      load_base = segbase - ptxt->p_vaddr;
-
-      ui->di_cache.start_ip = segbase;
-      ui->di_cache.end_ip = ui->di_cache.start_ip + ptxt->p_memsz;
+      ui->di_cache.start_ip = start_ip;
+      ui->di_cache.end_ip = end_ip;
       ui->di_cache.format = UNW_INFO_FORMAT_REMOTE_TABLE;
       ui->di_cache.u.rti.name_ptr = 0;
       /* two 32-bit values (ip_offset/fde_offset) per table-entry: */
@@ -329,39 +339,19 @@  _UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as,
   if (parm_exidx)
     {
       ui->di_arm.format = UNW_INFO_FORMAT_ARM_EXIDX;
-      ui->di_arm.start_ip = segbase;
-      ui->di_arm.end_ip = ui->di_arm.start_ip + ptxt->p_memsz;
+      ui->di_arm.start_ip = start_ip;
+      ui->di_arm.end_ip = end_ip;
       ui->di_arm.u.rti.name_ptr = (unw_word_t) path;
-      ui->di_arm.u.rti.table_data = parm_exidx->p_vaddr + segbase -
-				    ptxt->p_vaddr;
+      ui->di_arm.u.rti.table_data = load_base + parm_exidx->p_vaddr;
       ui->di_arm.u.rti.table_len = parm_exidx->p_memsz;
       found = 1;
     }
 #endif
 
 #ifdef CONFIG_DEBUG_FRAME
-  {
-      /* Try .debug_frame. */
-      struct dl_phdr_info info;
-
-      info.dlpi_name = path;
-      info.dlpi_phdr = phdr;
-      info.dlpi_phnum = ehdr->e_phnum;
-
-      /* Fixup segbase to match correct base address. */
-      for (i = 0; i < info.dlpi_phnum; i++)
-       {
-         if (info.dlpi_phdr[i].p_type == PT_LOAD &&
-           info.dlpi_phdr[i].p_offset == 0)
-             {
-               segbase -= info.dlpi_phdr[i].p_vaddr;
-               break;
-             }
-       }
-      info.dlpi_addr = segbase;
-
-      found = dwarf_find_debug_frame (found, &ui->di_debug, &info, ip);
-  }
+  /* Try .debug_frame. */
+  found = dwarf_find_debug_frame (found, &ui->di_debug, ip, segbase, path,
+				  start_ip, end_ip);
 #endif
 
   return found;