spu-gdb vs. stabs

Alan Modra amodra@bigpond.net.au
Thu Dec 14 07:18:00 GMT 2006


The iovec support that Andrew added to BFD a couple of years ago
doesn't allow the user to provide a stat function.  This doesn't
matter in most cases, but someone ran into "ridiculous string table
size" errors a while ago when trying to debug an embedded spu binary
that used stabs.  The problem is that gdb/dbxread.c uses bfd_get_size
to validate string table accesses, and bfd_get_size uses the
underlying iovec->stat function which returns a zero struct stat.

There are a number of ways to fix this.  One is to modify dbxread.c
to accept a zero return from bfd_get_size.  Another is to make the
default iovec stat function return INT_MAX in st_size to effectively
circumvent the dbxread.c checks.  I chose to extend bfd_openr_iovec
to accept a user "stat" function so that the actual size can be
provided, but then cowardly decided to just return a size of INT_MAX
in the spu implementation for stat.  See the comment.  If the kernel
/proc file used to find the address of a spu embedded binary also
returned the size then we could easily provide a better stat
function.

Are the gdb bits OK to apply?

bfd/
	* opncls.c (bfd_openr_iovec): Add "stat" parameter.
	(struct opncls): Add "stat" field.
	(opncls_bstat): Call vec->stat.
	* bfd-in2.h: Regenerate.
	* elf32-spu.c (spu_elf_open_builtin_lib): Adjust.
gdb/
	* spu-linux-nat.c (spu_bfd_iovec_stat): New function.
	(spu_bfd_open): Adjust bfd_openr_iovec call.

Index: bfd/opncls.c
===================================================================
RCS file: /cvs/src/src/bfd/opncls.c,v
retrieving revision 1.44
diff -u -p -r1.44 opncls.c
--- bfd/opncls.c	1 Jun 2006 03:45:58 -0000	1.44
+++ bfd/opncls.c	14 Dec 2006 01:44:42 -0000
@@ -384,7 +384,10 @@ SYNOPSIS
                                                  file_ptr nbytes,
                                                  file_ptr offset),
                               int (*close) (struct bfd *nbfd,
-                                            void *stream));
+                                            void *stream),
+			      int (*stat) (struct bfd *abfd,
+					   void *stream,
+					   struct stat *sb));
 
 DESCRIPTION
 
@@ -411,6 +414,10 @@ DESCRIPTION
 	<<bfd_close>>.  @var{close} either succeeds returning 0, or
 	fails returning -1 (setting <<bfd_error>>).
 
+	Calls @var{stat} to fill in a stat structure for bfd_stat,
+	bfd_get_size, and bfd_get_mtime calls.  @var{stat} returns 0
+	on success, or returns -1 on failure (setting <<bfd_error>>).
+
 	If <<bfd_openr_iovec>> returns <<NULL>> then an error has
 	occurred.  Possible errors are <<bfd_error_no_memory>>,
 	<<bfd_error_invalid_target>> and <<bfd_error_system_call>>.
@@ -423,6 +430,7 @@ struct opncls
   file_ptr (*pread) (struct bfd *abfd, void *stream, void *buf,
 		     file_ptr nbytes, file_ptr offset);
   int (*close) (struct bfd *abfd, void *stream);
+  int (*stat) (struct bfd *abfd, void *stream, struct stat *sb);
   file_ptr where;
 };
 
@@ -485,10 +493,15 @@ opncls_bflush (struct bfd *abfd ATTRIBUT
 }
 
 static int
-opncls_bstat (struct bfd *abfd ATTRIBUTE_UNUSED, struct stat *sb)
+opncls_bstat (struct bfd *abfd, struct stat *sb)
 {
+  struct opncls *vec = abfd->iostream;
+
   memset (sb, 0, sizeof (*sb));
-  return 0;
+  if (vec->stat == NULL)
+    return 0;
+
+  return (vec->stat) (abfd, vec->stream, sb);
 }
 
 static const struct bfd_iovec opncls_iovec = {
@@ -507,7 +520,10 @@ bfd_openr_iovec (const char *filename, c
 				    file_ptr nbytes,
 				    file_ptr offset),
 		 int (*close) (struct bfd *nbfd,
-			       void *stream))
+			       void *stream),
+		 int (*stat) (struct bfd *abfd,
+			      void *stream,
+			      struct stat *sb))
 {
   bfd *nbfd;
   const bfd_target *target_vec;
@@ -539,6 +555,7 @@ bfd_openr_iovec (const char *filename, c
   vec->stream = stream;
   vec->pread = pread;
   vec->close = close;
+  vec->stat = stat;
 
   nbfd->iovec = &opncls_iovec;
   nbfd->iostream = vec;
Index: bfd/elf32-spu.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-spu.c,v
retrieving revision 1.1
diff -u -p -r1.1 elf32-spu.c
--- bfd/elf32-spu.c	25 Oct 2006 06:49:20 -0000	1.1
+++ bfd/elf32-spu.c	14 Dec 2006 01:44:35 -0000
@@ -1090,6 +1090,7 @@ spu_elf_open_builtin_lib (bfd **ovl_bfd,
 			      ovl_mgr_open,
 			      (void *) stream,
 			      ovl_mgr_pread,
+			      NULL,
 			      NULL);
   return *ovl_bfd != NULL;
 }
Index: gdb/spu-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/spu-linux-nat.c,v
retrieving revision 1.1
diff -u -p -r1.1 spu-linux-nat.c
--- gdb/spu-linux-nat.c	22 Nov 2006 13:49:53 -0000	1.1
+++ gdb/spu-linux-nat.c	14 Dec 2006 01:45:05 -0000
@@ -281,6 +281,22 @@ spu_bfd_iovec_pread (struct bfd *abfd, v
   return nbytes;
 }
 
+static int
+spu_bfd_iovec_stat (struct bfd *abfd, void *stream, struct stat *sb)
+{
+  /* We don't have an easy way of finding the size of embedded spu
+     images.  We could parse the in-memory ELF header and section
+     table to find the extent of the last section but that seems
+     pointless when the size is needed only for checks of other
+     parsed values in dbxread.c.  */
+#ifdef INT_MAX
+  sb->st_size = INT_MAX;
+#else
+  sb->st_size = ((unsigned) -1) >> 1;
+#endif
+  return 0;
+}
+
 static bfd *
 spu_bfd_open (CORE_ADDR addr)
 {
@@ -291,7 +307,8 @@ spu_bfd_open (CORE_ADDR addr)
 
   nbfd = bfd_openr_iovec (xstrdup ("<in-memory>"), "elf32-spu",
 			  spu_bfd_iovec_open, open_closure,
-			  spu_bfd_iovec_pread, spu_bfd_iovec_close);
+			  spu_bfd_iovec_pread, spu_bfd_iovec_close,
+			  spu_bfd_iovec_stat);
   if (!nbfd)
     return NULL;
 

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre



More information about the Binutils mailing list