RFA: ia64 portion of libunwind patch

David Mosberger davidm@napali.hpl.hp.com
Wed Nov 26 00:11:00 GMT 2003


Hi Andrew,

>>>>> On Mon, 10 Nov 2003 17:43:40 -0500, Andrew Cagney <ac131313@redhat.com> said:

  >> In any case, perhaps it is possible to add incremental reading
  >> support by stealing a bit from one of the members in the
  >> "unw_dyn_table_info".  All we really need is a single bit to
  >> indicate whether the table-data should be fetched from
  >> remote-memory.  I'll think about it some more.

  Andrew> It would be appreciated.  My suggestion was to use memory
  Andrew> reads when the unwind table pointer was NULL.  However,
  Andrew> anything would help.

OK, I looked into this a bit more: we can't just redefine the meaning
of the unwind-table pointer, because it may have the wrong size when
unwinding across platforms.  For example, when cross-unwinding an ia64
application on an x86 host (happens regularly with the Ski simulator),
the pointer will be 32 bits in size but the remote address will be 64
bits.  The reverse problem can happen when registering unwind info, so
there is no quick way out.

Fortunately, it's still possible to have a clean solution: we can
simply add a new unwind-table format, which is identical to the
standard table format except that the table-data is a remote-address
(i.e., "unw_word_t" instead of "unw_word_t *").  I checked in a patch
to do just that in libunwind:

	http://unwind.bkbits.net:8080/libunwind/cset@1.123

If you don't want to deal with bitkeeper, libunwind v0.95 should be
due out shortly and will include this change.  I'm rather happy with
this solution because it's clearly the clean way of doing it and it
retains backwards compatibility.

The one incompatibility introduced by this patch is that the interface
of the _Uia64_find_dyn_list() helper-routine changed slightly.  The
only known user of that interface is gdb at the moment, so I think
that's OK (and, in retrospect, the old interface was a mistake).

Below, I attached a patch which updates gdb to use the remote-table
facility.  It doesn't try to retain backwards compatibility.  If that
were an issue, you could autoconf-check whether the enumeration symbol
UNW_INFO_FORMAT_REMOTE_TABLE is defined by <libunwind.h> and use the
old code if not.

While I didn't try to run the gdb test-suite, I did try a test program
which does some on-the-fly code-generation and the backtrace command
seemed to work fine.  For example:

(gdb) bt
#0  0x6000000000004022 in ?? ()
#1  0x60000000000040a0 in ?? ()
#2  0x6000000000004140 in ?? ()
#3  0x40000000000017e0 in main (argc=-19616, argv=0x6000000000004180)
    at ../../libunwind/tests/ia64-test-dyn1.c:196

Now if only gdb were able to call unw_get_proc_name() when it can't
find a symbol-name.  If it did that, the backtrace would even show the
proper function names for the dynamically generatd code.  Is this
something that could be added?

Another concern: at the moment, libunwind-frame.c dlopen()'s
libunwind.so.  This doesn't really work, because libunwind.so is just
a convenience symlink which allows native apps to link against the
proper libunwind with "-lunwind".  The real library is called

	libunwind-$TARGET.so

where $TARGET would be one of ia64, x86, or hppa, depending on the
target architecture.  For details, see the "Files" section of
this URL:

 http://www.hpl.hp.com/research/linux/libunwind/man/libunwind(3).php

Also, if multi-target support is to work, gdb would have to do a
separate dlopen for each target architecture being debugged.

Thanks,

	--david

ChangeLog

2003-11-25 David Mosberger  <davidm@hpl.hp.com>

	* libunwind-frame.c (unw_find_dyn_list_p): Replace most arguments
	with a single unw_dyn_info_t pointer.
	(libunwind_find_dyn_list): Likewise.
	* libunwind-frame.h: Likewise.

	* ia64-tdep.c (ia64_find_unwind_table): Switch to using
	UNW_INFO_FORMAT_REMOTE_TABLE so we can avoid having to read in the
	entire unwind-table at once.  Support for this table format has
	been added to libunwind v0.95.
	(ia64_find_proc_info_x): Adjust for remote-unwind-table changes.
	(ia64_get_dyn_info_list): Adjust for interface change for
	libunwind_find_dyn_list().

Index: ia64-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/ia64-tdep.c,v
retrieving revision 1.104
diff -u -r1.104 ia64-tdep.c
--- ia64-tdep.c	17 Nov 2003 21:38:36 -0000	1.104
+++ ia64-tdep.c	25 Nov 2003 23:48:24 -0000
@@ -2452,23 +2452,11 @@
   dip->start_ip = segbase;
   dip->end_ip = dip->start_ip + p_text->p_memsz;
   dip->gp = FIND_GLOBAL_POINTER (ip);
-  dip->format = UNW_INFO_FORMAT_TABLE;
-  dip->u.ti.name_ptr = (unw_word_t) bfd_get_filename (bfd);
-  dip->u.ti.segbase = segbase;
-  dip->u.ti.table_len = p_unwind->p_memsz / sizeof (unw_word_t);
-
-  /* The following can happen in corner cases where dynamically
-     generated code falls into the same page that contains the
-     data-segment and the page-offset of the code is within the first
-     page of the executable.  */
-  if (ip < dip->start_ip || ip >= dip->end_ip)
-    return -UNW_ENOINFO;
-
-  /* Read in the libunwind table.  */
-  *buf = xmalloc (p_unwind->p_memsz);
-  target_read_memory (p_unwind->p_vaddr + load_base, (char *)(*buf), p_unwind->p_memsz);
-
-  dip->u.ti.table_data = (unw_word_t *)(*buf);
+  dip->format = UNW_INFO_FORMAT_REMOTE_TABLE;
+  dip->u.rti.name_ptr = (unw_word_t) bfd_get_filename (bfd);
+  dip->u.rti.segbase = segbase;
+  dip->u.rti.table_len = p_unwind->p_memsz / sizeof (unw_word_t);
+  dip->u.rti.table_data = p_unwind->p_vaddr + load_base;
 
   return 0;
 }
@@ -2490,22 +2478,32 @@
 	 version.  */
       if (get_kernel_table (ip, &di) < 0)
 	return -UNW_ENOINFO;
+
+      if (gdbarch_debug >= 1)
+	fprintf_unfiltered (gdb_stdlog, "%s: %lx -> "
+			    "(name=`%s',segbase=%lx,start=%lx,end=%lx,gp=%lx,"
+			    "length=%lu,data=%p)\n", __FUNCTION__,
+			    ip, (char *)di.u.ti.name_ptr,
+			    di.u.ti.segbase, di.start_ip, di.end_ip,
+			    di.gp, di.u.ti.table_len, di.u.ti.table_data);
     }
   else
     {
       ret = ia64_find_unwind_table (sec->objfile, ip, &di, &buf);
       if (ret < 0)
 	return ret;
-    }
 
-  if (gdbarch_debug >= 1)
-    fprintf_unfiltered (gdb_stdlog, "acquire_unwind_info: %lx -> "
-			"(name=`%s',segbase=%lx,start=%lx,end=%lx,gp=%lx,"
-			"length=%lu,data=%p)\n", ip, (char *)di.u.ti.name_ptr,
-			di.u.ti.segbase, di.start_ip, di.end_ip,
-			di.gp, di.u.ti.table_len, di.u.ti.table_data);
+      if (gdbarch_debug >= 1)
+	fprintf_unfiltered (gdb_stdlog, "%s: %lx -> "
+			    "(name=`%s',segbase=%lx,start=%lx,end=%lx,gp=%lx,"
+			    "length=%lu,data=%lx)\n", __FUNCTION__,
+			    ip, (char *)di.u.rti.name_ptr,
+			    di.u.rti.segbase, di.start_ip, di.end_ip,
+			    di.gp, di.u.rti.table_len, di.u.rti.table_data);
+    }
 
-  ret = libunwind_search_unwind_table (&as, ip, &di, pi, need_unwind_info, arg);
+  ret = libunwind_search_unwind_table (&as, ip, &di, pi, need_unwind_info,
+				       arg);
 
   /* We no longer need the dyn info storage so free it.  */
   xfree (buf);
@@ -2545,10 +2543,7 @@
       ret = ia64_find_unwind_table (objfile, ip, &di, &buf);
       if (ret >= 0)
 	{
-	  addr = libunwind_find_dyn_list (as, di.u.ti.table_data,
-					  (di.u.ti.table_len
-					   * sizeof (di.u.ti.table_data[0])),
-					  di.u.ti.segbase, di.gp, arg);
+	  addr = libunwind_find_dyn_list (as, &di, arg);
 	  /* We no longer need the dyn info storage so free it.  */
 	  xfree (buf);
 
Index: libunwind-frame.c
===================================================================
RCS file: /cvs/src/src/gdb/libunwind-frame.c,v
retrieving revision 1.1
diff -u -r1.1 libunwind-frame.c
--- libunwind-frame.c	14 Nov 2003 21:17:51 -0000	1.1
+++ libunwind-frame.c	25 Nov 2003 23:48:24 -0000
@@ -58,8 +58,8 @@
 static unw_addr_space_t (*unw_create_addr_space_p) (unw_accessors_t *, int);
 static int (*unw_search_unwind_table_p) (unw_addr_space_t, unw_word_t, unw_dyn_info_t *,
 					 unw_proc_info_t *, int, void *);
-static unw_word_t (*unw_find_dyn_list_p) (unw_addr_space_t, void *, size_t,
-					  unw_word_t, unw_word_t, void *);
+static unw_word_t (*unw_find_dyn_list_p) (unw_addr_space_t, unw_dyn_info_t *,
+					  void *);
 
 
 struct libunwind_frame_cache
@@ -170,11 +170,10 @@
   return cache;
 }
 
-unw_word_t 
-libunwind_find_dyn_list (unw_addr_space_t as, void *table, size_t table_size,
-			 unw_word_t segbase, unw_word_t gp, void *arg)
+unw_word_t
+libunwind_find_dyn_list (unw_addr_space_t as, unw_dyn_info_t *di, void *arg)
 {
-  return unw_find_dyn_list_p (as, table, table_size, segbase, gp, arg);
+  return unw_find_dyn_list_p (as, di, arg);
 }
 
 static const struct frame_unwind libunwind_frame_unwind =
Index: libunwind-frame.h
===================================================================
RCS file: /cvs/src/src/gdb/libunwind-frame.h,v
retrieving revision 1.1
diff -u -r1.1 libunwind-frame.h
--- libunwind-frame.h	14 Nov 2003 21:17:51 -0000	1.1
+++ libunwind-frame.h	25 Nov 2003 23:48:24 -0000
@@ -55,9 +55,9 @@
 int libunwind_search_unwind_table (void *as, long ip, void *di,
 				   void *pi, int need_unwind_info, void *args);
 
-unw_word_t libunwind_find_dyn_list (unw_addr_space_t, void *, size_t,
-				    unw_word_t, unw_word_t, void *);
-     
+unw_word_t libunwind_find_dyn_list (unw_addr_space_t, unw_dyn_info_t *,
+				    void *);
+
 #endif /* libunwind-frame.h */
 
 #endif /* HAVE_LIBUNWIND_H  */



More information about the Gdb-patches mailing list