libunwind-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Libunwind-devel] Multi-platform unwinding i386 binary on x86_64 bugs an


From: Nurdin Premji
Subject: [Libunwind-devel] Multi-platform unwinding i386 binary on x86_64 bugs and patch.
Date: Tue, 24 Apr 2007 16:24:39 -0400
User-agent: Thunderbird 1.5.0.10 (X11/20070302)

While attempting to unwind an i386 binary on an x86_64 machine I found the following two bugs.

The first is that _UPTi_find_unwind_table when reading the eh_frame_ptr and fde_count assume the existence of unw_local_addr_space, which doesn't exist when compiled for the non-native i386 architecture. This was fixed by creating a dummy address space with an access_mem callback which is the only callback called by this method.

The second is that the variable for the address passed to access_mem is too small (unw_word_t) to hold a full 64 bit address. This was fixed by specifying that the elf image should be mapped into the first 32 bit address space with the MAP_32BIT flag for mmap(2).
### Eclipse Workspace Patch 1.0
#P frysk
Index: frysk-imports/libunwind/src/ptrace/_UPT_find_proc_info.c
===================================================================
RCS file: /cvs/frysk/frysk-imports/libunwind/src/ptrace/_UPT_find_proc_info.c,v
retrieving revision 1.5
diff -u -r1.5 _UPT_find_proc_info.c
--- frysk-imports/libunwind/src/ptrace/_UPT_find_proc_info.c    21 Mar 2007 
17:37:48 -0000      1.5
+++ frysk-imports/libunwind/src/ptrace/_UPT_find_proc_info.c    24 Apr 2007 
19:09:23 -0000
@@ -170,7 +170,6 @@
   unw_word_t addr, eh_frame_start, fde_count, load_base;
   struct dwarf_eh_frame_hdr *hdr;
   unw_proc_info_t pi;
-  unw_accessors_t *a;
   Elf_W(Ehdr) *ehdr;
   int i, ret;
 
@@ -236,8 +235,7 @@
             path, hdr->version);
       return 0;
     }
-
-  a = unw_get_accessors (unw_local_addr_space);
+ 
   addr = (unw_word_t) (hdr + 1);
 
   /* Fill in a dummy proc_info structure.  We just need to fill in
@@ -247,14 +245,37 @@
   memset (&pi, 0, sizeof (pi));
   pi.gp = ui->di_cache.gp;
 
+//The following is a dummy local address space used by 
dwarf_read_encoded_pointer.
+  int 
+  local_access_mem (unw_addr_space_t as, unw_word_t addr,
+               unw_word_t *val, int write, void *arg) 
+  {    
+       if (write)
+       {
+         Debug (16, "mem[%x] <- %x\n", addr, *val);
+          *(unw_word_t *) addr = *val;
+       }
+       else
+       {
+          *val = *(unw_word_t *) addr;
+          Debug (16, "mem[%x] -> %x\n", addr, *val);
+       }
+       return 0;
+  }
+  
+  unw_accessors_t temp_local_accessors = {NULL, NULL, NULL, local_access_mem, 
+                                         NULL, NULL,   NULL, NULL, NULL};
+  unw_addr_space_t temp_local_addr_space 
+       = unw_create_addr_space(&temp_local_accessors, 0);
+
   /* (Optionally) read eh_frame_ptr: */
-  if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a,
+  if ((ret = dwarf_read_encoded_pointer (temp_local_addr_space, 
&temp_local_accessors,
                                         &addr, hdr->eh_frame_ptr_enc, &pi,
                                         &eh_frame_start, NULL)) < 0)
     return NULL;
 
   /* (Optionally) read fde_count: */
-  if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a,
+  if ((ret = dwarf_read_encoded_pointer (temp_local_addr_space, 
&temp_local_accessors,
                                         &addr, hdr->fde_count_enc, &pi,
                                         &fde_count, NULL)) < 0)
     return NULL;
Index: frysk-imports/libunwind/src/elfxx.h
===================================================================
RCS file: /cvs/frysk/frysk-imports/libunwind/src/elfxx.h,v
retrieving revision 1.3
diff -u -r1.3 elfxx.h
--- frysk-imports/libunwind/src/elfxx.h 12 Mar 2007 15:26:07 -0000      1.3
+++ frysk-imports/libunwind/src/elfxx.h 24 Apr 2007 19:09:23 -0000
@@ -42,6 +42,10 @@
 # define elf_w(x)      _Uelf64_##x
 #endif
 
+#ifndef MAP_32BIT
+# define MAP_32BIT 0
+#endif
+
 static inline int
 elf_map_image (struct elf_image *ei, const char *path)
 {
@@ -59,7 +63,7 @@
     }
 
   ei->size = stat.st_size;
-  ei->image = mmap (NULL, ei->size, PROT_READ, MAP_PRIVATE, fd, 0);
+  ei->image = mmap (NULL, ei->size, PROT_READ, MAP_PRIVATE | MAP_32BIT, fd, 0);
   close (fd);
   if (ei->image == MAP_FAILED)
     return -1;
Index: frysk-imports/libunwind/src/os-linux.c
===================================================================
RCS file: /cvs/frysk/frysk-imports/libunwind/src/os-linux.c,v
retrieving revision 1.5
diff -u -r1.5 os-linux.c
--- frysk-imports/libunwind/src/os-linux.c      12 Mar 2007 15:26:07 -0000      
1.5
+++ frysk-imports/libunwind/src/os-linux.c      24 Apr 2007 19:29:05 -0000
@@ -35,6 +35,10 @@
 # define MAX_VDSO_SIZE ((size_t) sysconf (_SC_PAGESIZE))
 #endif
 
+#ifndef MAP_32BIT
+# define MAP_32BIT 0
+#endif
+
 PROTECTED int
 tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei,
                    pid_t pid, unw_word_t ip,
@@ -91,7 +95,7 @@
     }
 
   ei->image = mmap (0, ei->size, PROT_READ | PROT_WRITE,
-                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+                   MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0);
   if (ei->image == MAP_FAILED)
     return found;

reply via email to

[Prev in Thread] Current Thread [Next in Thread]