This is the mail archive of the frysk@sources.redhat.com mailing list for the frysk project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: remote dwarf info using libunwind


On Sep 15, 2006, Alexandre Oliva <aoliva@redhat.com> wrote:

> Fixing vdso will take new code in libunwind to fetch the vdso ELF
> image from the target process memory.  It doesn't look hard, I'll take
> a stab at it in my next hacking session.

Here it is.  Ok to install in frysk?  We get perfect stack traces for
Tom's fdtrace with this patch, even when running 32-bit processes on
the FC6T3 x86_64 kernel, that leaves the path portion empty in
/proc/PID/maps in the last line, corresponding to the VDSO.

for  frysk/frysk-imports/libunwind/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* src/os-linux.h (maps_next): Don't error out just because
	path is missing.
	* include/tdep-hppa/libunwind_i.h (tdep_get_elf_image): Add as
	and arg to the parameter list.
	* include/tdep-ia64/libunwind_i.h (tdep_get_elf_image): Ditto.
	* include/tdep-ppc64/libunwind_i.h (tdep_get_elf_image): Ditto.
	* include/tdep-x86/libunwind_i.h (tdep_get_elf_image): Ditto.
	* include/tdep-x86_64/libunwind_i.h (tdep_get_elf_image): Ditto.
	* src/elfxx.h (get_proc_name): Ditto.
	* src/elfxx.c (get_proc_name): Ditto.  Adjust.
	* src/hppa/Ginit.c (get_static_proc_name): Adjust.
	* src/ia64/Ginit.c (get_static_proc_name): Ditto.
	* src/ppc64/Ginit.c (get_static_proc_name): Ditto.
	* src/x86/Ginit.c (get_static_proc_name): Ditto.
	* src/x86_64/Ginit.c (get_static_proc_name): Ditto.
	* src/ptrace/_UPT_find_proc_info.c (get_unwind_info): Ditto.
	* src/ptrace/_UPT_get_proc_name.c (_UPT_get_proc_name): Ditto.
	* src/os-hpux.c (tdep_get_elf_image): Ditto.
	* src/os-linux.c (tdep_get_elf_image): Ditto.  Read in 1-page
	segments that start with the ELF magic.
	(MAX_VDSO_SIZE): New.

Index: frysk/frysk-imports/libunwind/src/os-linux.h
===================================================================
--- frysk.orig/frysk-imports/libunwind/src/os-linux.h	2006-09-15 05:51:11.000000000 -0300
+++ frysk/frysk-imports/libunwind/src/os-linux.h	2006-09-16 02:48:34.000000000 -0300
@@ -283,8 +283,12 @@ maps_next (struct map_iterator *mi,
       cp = scan_char (cp, &colon);
       cp = scan_hex (cp, &minor);
       cp = scan_dec (cp, &inum);
+      if (!cp)
+	continue;
       cp = scan_string (cp, path, path_size);
-      if (!cp || dash != '-' || colon != ':')
+      if (!cp)
+	*path = 0;
+      if (dash != '-' || colon != ':')
 	continue;	/* skip line with unknown or bad format */
       return 1;
     }
Index: frysk/frysk-imports/libunwind/include/tdep-hppa/libunwind_i.h
===================================================================
--- frysk.orig/frysk-imports/libunwind/include/tdep-hppa/libunwind_i.h	2006-05-31 15:22:16.000000000 -0300
+++ frysk/frysk-imports/libunwind/include/tdep-hppa/libunwind_i.h	2006-09-16 03:44:12.000000000 -0300
@@ -250,8 +250,10 @@ extern int tdep_search_unwind_table (unw
 				     unw_dyn_info_t *di, unw_proc_info_t *pi,
 				     int need_unwind_info, void *arg);
 extern void *tdep_uc_addr (ucontext_t *uc, int reg);
-extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
-			       unsigned long *segbase, unsigned long *mapoff);
+extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei,
+			       pid_t pid, unw_word_t ip,
+			       unsigned long *segbase, unsigned long *mapoff,
+			       void *arg);
 extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
 			    unw_word_t *valp, int write);
 extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg,
Index: frysk/frysk-imports/libunwind/include/tdep-ia64/libunwind_i.h
===================================================================
--- frysk.orig/frysk-imports/libunwind/include/tdep-ia64/libunwind_i.h	2006-05-31 15:22:16.000000000 -0300
+++ frysk/frysk-imports/libunwind/include/tdep-ia64/libunwind_i.h	2006-09-16 03:44:29.000000000 -0300
@@ -243,8 +243,10 @@ extern void tdep_put_unwind_info (unw_ad
 				  unw_proc_info_t *pi, void *arg);
 extern void *tdep_uc_addr (ucontext_t *uc, unw_regnum_t regnum,
 			   uint8_t *nat_bitnr);
-extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
-			       unsigned long *segbase, unsigned long *mapoff);
+extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei,
+			       pid_t pid, unw_word_t ip,
+			       unsigned long *segbase, unsigned long *mapoff,
+			       void *arg);
 extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
 			    unw_word_t *valp, int write);
 extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg,
Index: frysk/frysk-imports/libunwind/include/tdep-ppc64/libunwind_i.h
===================================================================
--- frysk.orig/frysk-imports/libunwind/include/tdep-ppc64/libunwind_i.h	2006-08-29 04:48:10.000000000 -0300
+++ frysk/frysk-imports/libunwind/include/tdep-ppc64/libunwind_i.h	2006-09-16 03:44:39.000000000 -0300
@@ -189,8 +189,10 @@ extern int tdep_search_unwind_table (unw
 				     unw_dyn_info_t *di, unw_proc_info_t *pi,
 				     int need_unwind_info, void *arg);
 extern void *tdep_uc_addr (ucontext_t *uc, int reg);
-extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
-			       unsigned long *segbase, unsigned long *mapoff);
+extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei,
+			       pid_t pid, unw_word_t ip,
+			       unsigned long *segbase, unsigned long *mapoff,
+			       void *arg);
 extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
 			    unw_word_t *valp, int write);
 extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg,
Index: frysk/frysk-imports/libunwind/include/tdep-x86/libunwind_i.h
===================================================================
--- frysk.orig/frysk-imports/libunwind/include/tdep-x86/libunwind_i.h	2006-05-31 15:22:16.000000000 -0300
+++ frysk/frysk-imports/libunwind/include/tdep-x86/libunwind_i.h	2006-09-16 03:43:37.000000000 -0300
@@ -252,8 +252,10 @@ extern int tdep_search_unwind_table (unw
 				     unw_dyn_info_t *di, unw_proc_info_t *pi,
 				     int need_unwind_info, void *arg);
 extern void *tdep_uc_addr (ucontext_t *uc, int reg);
-extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
-			       unsigned long *segbase, unsigned long *mapoff);
+extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei,
+			       pid_t pid, unw_word_t ip,
+			       unsigned long *segbase, unsigned long *mapoff,
+			       void *arg);
 extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
 			    unw_word_t *valp, int write);
 extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg,
Index: frysk/frysk-imports/libunwind/include/tdep-x86_64/libunwind_i.h
===================================================================
--- frysk.orig/frysk-imports/libunwind/include/tdep-x86_64/libunwind_i.h	2006-05-31 15:22:16.000000000 -0300
+++ frysk/frysk-imports/libunwind/include/tdep-x86_64/libunwind_i.h	2006-09-16 03:43:56.000000000 -0300
@@ -187,8 +187,10 @@ extern int tdep_search_unwind_table (unw
 				     unw_dyn_info_t *di, unw_proc_info_t *pi,
 				     int need_unwind_info, void *arg);
 extern void *tdep_uc_addr (ucontext_t *uc, int reg);
-extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
-			       unsigned long *segbase, unsigned long *mapoff);
+extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei,
+			       pid_t pid, unw_word_t ip,
+			       unsigned long *segbase, unsigned long *mapoff,
+			       void *arg);
 extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
 			    unw_word_t *valp, int write);
 extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg,
Index: frysk/frysk-imports/libunwind/src/elfxx.c
===================================================================
--- frysk.orig/frysk-imports/libunwind/src/elfxx.c	2006-05-31 15:22:16.000000000 -0300
+++ frysk/frysk-imports/libunwind/src/elfxx.c	2006-09-16 04:04:43.000000000 -0300
@@ -134,8 +134,8 @@ elf_w (lookup_symbol) (unw_word_t ip, st
    sensitive to the performance of this routine, why bother...  */
 
 HIDDEN int
-elf_w (get_proc_name) (pid_t pid, unw_word_t ip, char *buf, size_t buf_len,
-		       unw_word_t *offp)
+elf_w (get_proc_name) (unw_addr_space_t as, pid_t pid, unw_word_t ip,
+		       char *buf, size_t buf_len, unw_word_t *offp, void *arg)
 {
   unsigned long segbase, mapoff;
   Elf_W (Addr) load_offset = 0;
@@ -144,7 +144,7 @@ elf_w (get_proc_name) (pid_t pid, unw_wo
   Elf_W (Phdr) *phdr;
   int i, ret;
 
-  ret = tdep_get_elf_image (&ei, pid, ip, &segbase, &mapoff);
+  ret = tdep_get_elf_image (as, &ei, pid, ip, &segbase, &mapoff, arg);
   if (ret < 0)
     return ret;
 
Index: frysk/frysk-imports/libunwind/src/elfxx.h
===================================================================
--- frysk.orig/frysk-imports/libunwind/src/elfxx.h	2006-05-31 15:22:16.000000000 -0300
+++ frysk/frysk-imports/libunwind/src/elfxx.h	2006-09-16 03:28:31.000000000 -0300
@@ -68,6 +68,7 @@ elf_map_image (struct elf_image *ei, con
 }
 
 extern int elf_w (valid_object) (struct elf_image *ei);
-extern int elf_w (get_proc_name) (pid_t pid, unw_word_t ip,
+extern int elf_w (get_proc_name) (unw_addr_space_t as,
+				  pid_t pid, unw_word_t ip,
 				  char *buf, size_t len,
-				  unw_word_t *offp);
+				  unw_word_t *offp, void *arg);
Index: frysk/frysk-imports/libunwind/src/hppa/Ginit.c
===================================================================
--- frysk.orig/frysk-imports/libunwind/src/hppa/Ginit.c	2006-05-31 16:04:20.000000000 -0300
+++ frysk/frysk-imports/libunwind/src/hppa/Ginit.c	2006-09-16 03:51:12.000000000 -0300
@@ -171,7 +171,7 @@ get_static_proc_name (unw_addr_space_t a
 		      char *buf, size_t buf_len, unw_word_t *offp,
 		      void *arg)
 {
-  return _Uelf32_get_proc_name (getpid (), ip, buf, buf_len, offp);
+  return _Uelf32_get_proc_name (as, getpid (), ip, buf, buf_len, offp, arg);
 }
 
 HIDDEN void
Index: frysk/frysk-imports/libunwind/src/ia64/Ginit.c
===================================================================
--- frysk.orig/frysk-imports/libunwind/src/ia64/Ginit.c	2006-05-31 16:04:20.000000000 -0300
+++ frysk/frysk-imports/libunwind/src/ia64/Ginit.c	2006-09-16 03:51:25.000000000 -0300
@@ -352,7 +352,7 @@ get_static_proc_name (unw_addr_space_t a
   if (!_Uelf64_get_proc_name)
     return -UNW_EINVAL;
 #endif
-  return _Uelf64_get_proc_name (getpid (), ip, buf, buf_len, offp);
+  return _Uelf64_get_proc_name (as, getpid (), ip, buf, buf_len, offp, arg);
 }
 
 HIDDEN void
Index: frysk/frysk-imports/libunwind/src/os-hpux.c
===================================================================
--- frysk.orig/frysk-imports/libunwind/src/os-hpux.c	2006-05-31 15:22:16.000000000 -0300
+++ frysk/frysk-imports/libunwind/src/os-hpux.c	2006-09-16 03:28:53.000000000 -0300
@@ -33,8 +33,10 @@ WITH THE SOFTWARE OR THE USE OR OTHER DE
 #include "elf64.h"
 
 HIDDEN int
-tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
-		    unsigned long *segbase, unsigned long *mapoff)
+tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei,
+		    pid_t pid, unw_word_t ip,
+		    unsigned long *segbase, unsigned long *mapoff,
+		    void *arg)
 {
   struct load_module_desc lmd;
   const char *path;
Index: frysk/frysk-imports/libunwind/src/os-linux.c
===================================================================
--- frysk.orig/frysk-imports/libunwind/src/os-linux.c	2006-09-16 03:23:04.000000000 -0300
+++ frysk/frysk-imports/libunwind/src/os-linux.c	2006-09-16 04:30:23.000000000 -0300
@@ -31,14 +31,22 @@ WITH THE SOFTWARE OR THE USE OR OTHER DE
 #include "libunwind_i.h"
 #include "os-linux.h"
 
+#ifndef MAX_VDSO_SIZE
+# define MAX_VDSO_SIZE ((size_t) sysconf (_SC_PAGESIZE))
+#endif
+
 PROTECTED int
-tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
-		    unsigned long *segbase, unsigned long *mapoff)
+tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei,
+		    pid_t pid, unw_word_t ip,
+		    unsigned long *segbase, unsigned long *mapoff,
+		    void *arg)
 {
   struct map_iterator mi;
   char path[PATH_MAX];
   int found = 0;
   unsigned long hi;
+  unw_accessors_t *a;
+  unw_word_t magic;
 
   maps_init (&mi, pid);
   while (maps_next (&mi, segbase, &hi, mapoff, path, sizeof (path)))
@@ -52,7 +60,65 @@ tdep_get_elf_image (struct elf_image *ei
   if (!found)
     return -1;
 
-  return elf_map_image (ei, path);
+  found = elf_map_image (ei, path);
+  if (found != -1)
+    return found;
+
+  /* If the above failed, try to bring in page-sized segments directly
+     from process memory.  This enables us to locate VDSO unwind
+     tables.  */
+  ei->size = hi - *segbase;
+  if (ei->size > MAX_VDSO_SIZE)
+    return found;
+
+  a = unw_get_accessors (as);
+  if (! a->access_mem)
+    return found;
+
+  /* Try to decide whether it's an ELF image before bringing it all
+     in.  */
+  if (ei->size <= EI_CLASS || ei->size <= sizeof (magic))
+    return found;
+
+  if (sizeof (magic) >= SELFMAG)
+    {
+      int ret = (*a->access_mem) (as, *segbase, &magic, 0, arg);
+      if (ret < 0)
+	return ret;
+
+      if (memcmp (&magic, ELFMAG, SELFMAG) != 0)
+	return found;
+    }
+
+  ei->image = mmap (0, ei->size, PROT_READ | PROT_WRITE,
+		    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  if (ei->image == MAP_FAILED)
+    return found;
+
+  if (sizeof (magic) >= SELFMAG)
+    {
+      *(unw_word_t *)ei->image = magic;
+      hi = sizeof (magic);
+    }
+  else
+    hi = 0;
+
+  for (; hi < ei->size; hi += sizeof (unw_word_t))
+    {
+      found = (*a->access_mem) (as, *segbase + hi, ei->image + hi,
+				0, arg);
+      if (found < 0)
+	{
+	  munmap (ei->image, ei->size);
+	  return found;
+	}
+    }
+
+  if (*segbase == *mapoff
+      && (*path == 0 || strcmp (path, "[vdso]") == 0))
+    *mapoff = 0;
+
+  return 0;
 }
 
 #endif /* UNW_REMOTE_ONLY */
Index: frysk/frysk-imports/libunwind/src/ppc64/Ginit.c
===================================================================
--- frysk.orig/frysk-imports/libunwind/src/ppc64/Ginit.c	2006-08-29 04:48:10.000000000 -0300
+++ frysk/frysk-imports/libunwind/src/ppc64/Ginit.c	2006-09-16 03:51:32.000000000 -0300
@@ -126,7 +126,7 @@ get_static_proc_name (unw_addr_space_t a
 		      char *buf, size_t buf_len, unw_word_t *offp,
 		      void *arg)
 {
-  return _Uelf64_get_proc_name (getpid (), ip, buf, buf_len, offp);
+  return _Uelf64_get_proc_name (as, getpid (), ip, buf, buf_len, offp, arg);
 }
 
 HIDDEN void
Index: frysk/frysk-imports/libunwind/src/ptrace/_UPT_find_proc_info.c
===================================================================
--- frysk.orig/frysk-imports/libunwind/src/ptrace/_UPT_find_proc_info.c	2006-09-13 06:33:23.000000000 -0300
+++ frysk/frysk-imports/libunwind/src/ptrace/_UPT_find_proc_info.c	2006-09-16 03:53:46.000000000 -0300
@@ -337,7 +337,7 @@ get_unwind_info (struct UPT_info *ui, un
       ui->di_cache.start_ip = ui->di_cache.end_ip = 0;
     }
 
-  if (tdep_get_elf_image (&ui->ei, ui->pid, ip, &segbase, &mapoff) < 0)
+  if (tdep_get_elf_image (as, &ui->ei, ui->pid, ip, &segbase, &mapoff, ui) < 0)
     return NULL;
 
   /* Here, SEGBASE is the starting-address of the (mmap'ped) segment
Index: frysk/frysk-imports/libunwind/src/ptrace/_UPT_get_proc_name.c
===================================================================
--- frysk.orig/frysk-imports/libunwind/src/ptrace/_UPT_get_proc_name.c	2006-05-31 16:04:20.000000000 -0300
+++ frysk/frysk-imports/libunwind/src/ptrace/_UPT_get_proc_name.c	2006-09-16 03:46:45.000000000 -0300
@@ -32,9 +32,9 @@ _UPT_get_proc_name (unw_addr_space_t as,
   struct UPT_info *ui = arg;
 
 #if ELF_CLASS == ELFCLASS64
-  return _Uelf64_get_proc_name (ui->pid, ip, buf, buf_len, offp);
+  return _Uelf64_get_proc_name (as, ui->pid, ip, buf, buf_len, offp, arg);
 #elif ELF_CLASS == ELFCLASS32
-  return _Uelf32_get_proc_name (ui->pid, ip, buf, buf_len, offp);
+  return _Uelf32_get_proc_name (as, ui->pid, ip, buf, buf_len, offp, arg);
 #else
   return -UNW_ENOINFO;
 #endif
Index: frysk/frysk-imports/libunwind/src/x86/Ginit.c
===================================================================
--- frysk.orig/frysk-imports/libunwind/src/x86/Ginit.c	2006-05-31 16:04:20.000000000 -0300
+++ frysk/frysk-imports/libunwind/src/x86/Ginit.c	2006-09-16 03:50:54.000000000 -0300
@@ -186,7 +186,7 @@ get_static_proc_name (unw_addr_space_t a
 		      char *buf, size_t buf_len, unw_word_t *offp,
 		      void *arg)
 {
-  return _Uelf32_get_proc_name (getpid (), ip, buf, buf_len, offp);
+  return _Uelf32_get_proc_name (as, getpid (), ip, buf, buf_len, offp, arg);
 }
 
 HIDDEN void
Index: frysk/frysk-imports/libunwind/src/x86_64/Ginit.c
===================================================================
--- frysk.orig/frysk-imports/libunwind/src/x86_64/Ginit.c	2006-05-31 16:04:20.000000000 -0300
+++ frysk/frysk-imports/libunwind/src/x86_64/Ginit.c	2006-09-16 03:51:03.000000000 -0300
@@ -232,7 +232,7 @@ get_static_proc_name (unw_addr_space_t a
 		      char *buf, size_t buf_len, unw_word_t *offp,
 		      void *arg)
 {
-  return _Uelf64_get_proc_name (getpid (), ip, buf, buf_len, offp);
+  return _Uelf64_get_proc_name (as, getpid (), ip, buf, buf_len, offp, arg);
 }
 
 HIDDEN void
-- 
Alexandre Oliva         http://www.lsd.ic.unicamp.br/~oliva/
Secretary for FSF Latin America        http://www.fsfla.org/
Red Hat Compiler Engineer   aoliva@{redhat.com, gcc.gnu.org}
Free Software Evangelist  oliva@{lsd.ic.unicamp.br, gnu.org}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]