This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB 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]

RFC: Improve support for "debugging" unlinked objects


If you compile a file containing both code and initialized data, and load
the unlinked object (.o) file using GDB, "print Variable" won't work. 
You'll get garbage-looking data, which is in fact the start of the first
section in the file - usually .text.

All sections appear to have address 0.  i.e., they overlap, sort of like
overlays but not similar enough to reuse the overlay machinery.  For this
case, if we fill in section_offsets, we can place them at random locations
which are sufficiently unique that we can see the locations of variables as
distinct.  And if we pass this information back to exec.c, we can see the
values of variables correctly, too.

Here's a patch along with a testcase; the test fails before the patch, and
passes afterwards.  Any comments on the way I fixed this?

-- 
Daniel Jacobowitz
CodeSourcery, LLC

2005-06-08  Daniel Jacobowitz  <dan@codesourcery.com>

	* Makefile.in (symfile.o): Add $(exec_h).
	* exec.h (exec_set_section_address): Add prototype.
	* exec.c (exec_set_section_address): New function.
	* symfile.c: Include "exec.h".
	(struct place_section_arg, place_section): New.
	(default_symfile_offsets): Call place_section for each
	section of a relocatable file.

2005-06-08  Daniel Jacobowitz  <dan@codesourcery.com>

	* gdb.base/relocate.c: Add a copyright notice.
	(dummy): Remove.
	* gdb.base/relocate.exp: Test printing the values of variables
	from a relocatable file.

Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.735
diff -u -p -r1.735 Makefile.in
--- Makefile.in	2 Jun 2005 16:52:04 -0000	1.735
+++ Makefile.in	8 Jun 2005 21:46:15 -0000
@@ -2642,7 +2642,7 @@ symfile.o: symfile.c $(defs_h) $(bfdlink
 	$(complaints_h) $(demangle_h) $(inferior_h) $(filenames_h) \
 	$(gdb_stabs_h) $(gdb_obstack_h) $(completer_h) $(bcache_h) \
 	$(hashtab_h) $(readline_h) $(gdb_assert_h) $(block_h) \
-	$(gdb_string_h) $(gdb_stat_h) $(observer_h)
+	$(gdb_string_h) $(gdb_stat_h) $(observer_h) $(exec_h)
 symfile-mem.o: symfile-mem.c $(defs_h) $(symtab_h) $(gdbcore_h) \
 	$(objfiles_h) $(exceptions_h) $(gdbcmd_h) $(target_h) $(value_h) \
 	$(symfile_h) $(observer_h) $(auxv_h) $(elf_common_h)
Index: exec.c
===================================================================
RCS file: /cvs/src/src/gdb/exec.c,v
retrieving revision 1.55
diff -u -p -r1.55 exec.c
--- exec.c	16 May 2005 04:45:43 -0000	1.55
+++ exec.c	8 Jun 2005 21:46:15 -0000
@@ -670,6 +670,27 @@ set_section_command (char *args, int fro
   error (_("Section %s not found"), secprint);
 }
 
+/* If we can find a section in FILENAME with BFD index INDEX, and the
+   user has not assigned an address to it yet (via "set section"), adjust it
+   to ADDRESS.  */
+
+void
+exec_set_section_address (const char *filename, int index, CORE_ADDR address)
+{
+  struct section_table *p;
+
+  for (p = exec_ops.to_sections; p < exec_ops.to_sections_end; p++)
+    {
+      if (strcmp (filename, p->bfd->filename) == 0
+	  && index == p->the_bfd_section->index
+	  && p->addr == 0)
+	{
+	  p->addr = address;
+	  p->endaddr += address;
+	}
+    }
+}
+
 /* If mourn is being called in all the right places, this could be say
    `gdb internal error' (since generic_mourn calls
    breakpoint_init_inferior).  */
Index: exec.h
===================================================================
RCS file: /cvs/src/src/gdb/exec.h,v
retrieving revision 1.2
diff -u -p -r1.2 exec.h
--- exec.h	12 Jan 2004 20:33:21 -0000	1.2
+++ exec.h	8 Jun 2005 21:46:15 -0000
@@ -36,4 +36,7 @@ extern struct target_ops exec_ops;
 extern int build_section_table (struct bfd *, struct section_table **,
 				struct section_table **);
 
+/* Set the loaded address of a section.  */
+extern void exec_set_section_address (const char *, int, CORE_ADDR);
+
 #endif
Index: symfile.c
===================================================================
RCS file: /cvs/src/src/gdb/symfile.c,v
retrieving revision 1.158
diff -u -p -r1.158 symfile.c
--- symfile.c	8 May 2005 14:46:52 -0000	1.158
+++ symfile.c	8 Jun 2005 21:46:16 -0000
@@ -49,6 +49,7 @@
 #include "gdb_assert.h"
 #include "block.h"
 #include "observer.h"
+#include "exec.h"
 
 #include <sys/types.h>
 #include <fcntl.h>
@@ -456,6 +457,84 @@ init_objfile_sect_indices (struct objfil
     }
 }
 
+/* The arguments to place_section.  */
+
+struct place_section_arg
+{
+  struct section_offsets *offsets;
+  CORE_ADDR lowest;
+};
+
+/* Find a unique offset to use for loadable section SECT if
+   the user did not provide an offset.  */
+
+void
+place_section (bfd *abfd, asection *sect, void *obj)
+{
+  struct place_section_arg *arg = obj;
+  CORE_ADDR *offsets = arg->offsets->offsets, start_addr;
+  int done;
+
+  /* We are only interested in loadable sections.  */
+  if ((bfd_get_section_flags (abfd, sect) & SEC_LOAD) == 0)
+    return;
+
+  /* If the user specified an offset, honor it.  */
+  if (offsets[sect->index] != 0)
+    return;
+
+  /* Otherwise, let's try to find a place for the section.  */
+  do {
+    asection *cur_sec;
+    ULONGEST align = 1 << bfd_get_section_alignment (abfd, sect);
+
+    start_addr = (arg->lowest + align - 1) & -align;
+    done = 1;
+
+    for (cur_sec = abfd->sections; cur_sec != NULL; cur_sec = cur_sec->next)
+      {
+	int indx = cur_sec->index;
+	CORE_ADDR cur_offset;
+
+	/* We don't need to compare against ourself.  */
+	if (cur_sec == sect)
+	  continue;
+
+	/* We can only conflict with loadable sections.  */
+	if ((bfd_get_section_flags (abfd, cur_sec) & SEC_LOAD) == 0)
+	  continue;
+
+	/* We do not expect this to happen; just ignore sections in a
+	   relocatable file with an assigned VMA.  */
+	if (bfd_section_vma (abfd, cur_sec) != 0)
+	  continue;
+
+	/* If the section offset is 0, either the section has not been placed
+	   yet, or it was the lowest section placed (in which case LOWEST
+	   will be past its end).  */
+	if (offsets[indx] == 0)
+	  continue;
+
+	/* If this section would overlap us, then we must move up.  */
+	if (start_addr + bfd_get_section_size (sect) > offsets[indx]
+	    && start_addr < offsets[indx] + bfd_get_section_size (cur_sec))
+	  {
+	    start_addr = offsets[indx] + bfd_get_section_size (cur_sec);
+	    start_addr = (start_addr + align - 1) & -align;
+	    done = 0;
+	    continue;
+	  }
+
+	/* Otherwise, we appear to be OK.  So far.  */
+      }
+    }
+  while (!done);
+
+  offsets[sect->index] = start_addr;
+  arg->lowest = start_addr + bfd_get_section_size (sect);
+
+  exec_set_section_address (bfd_get_filename (abfd), sect->index, start_addr);
+}
 
 /* Parse the user's idea of an offset for dynamic linking, into our idea
    of how to represent it for fast symbol reading.  This is the default
@@ -492,6 +571,19 @@ default_symfile_offsets (struct objfile 
       (objfile->section_offsets)->offsets[osp->sectindex] = osp->addr;
     }
 
+  /* For relocatable files, all loadable sections will start at zero.
+     The zero is meaningless, so try to pick arbitrary addresses such
+     that no loadable sections overlap.  This algorithm is quadratic,
+     but the number of sections in a single object file is generally
+     small.  */
+  if ((bfd_get_file_flags (objfile->obfd) & (EXEC_P | DYNAMIC)) == 0)
+    {
+      struct place_section_arg arg;
+      arg.offsets = objfile->section_offsets;
+      arg.lowest = 0;
+      bfd_map_over_sections (objfile->obfd, place_section, &arg);
+    }
+
   /* Remember the bfd indexes for the .text, .data, .bss and
      .rodata sections. */
   init_objfile_sect_indices (objfile);
Index: testsuite/gdb.base/relocate.c
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.base/relocate.c,v
retrieving revision 1.3
diff -u -p -r1.3 relocate.c
--- testsuite/gdb.base/relocate.c	29 Feb 2004 02:58:28 -0000	1.3
+++ testsuite/gdb.base/relocate.c	8 Jun 2005 21:46:16 -0000
@@ -1,10 +1,26 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2002, 2003, 2004, 2005
+   Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+ 
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
 static int static_foo = 1;
 static int static_bar = 2;
 
-/* This padding is just for the benefit of the test harness.  It
-   causes the globals to have different addresses than the functions.  */
-int dummy[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
-
 int global_foo = 3;
 int global_bar = 4;
 
Index: testsuite/gdb.base/relocate.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.base/relocate.exp,v
retrieving revision 1.4
diff -u -p -r1.4 relocate.exp
--- testsuite/gdb.base/relocate.exp	11 Sep 2003 18:59:02 -0000	1.4
+++ testsuite/gdb.base/relocate.exp	8 Jun 2005 21:46:16 -0000
@@ -1,4 +1,4 @@
-# Copyright 2002, 2003 Free Software Foundation, Inc.
+# Copyright 2002, 2003, 2005 Free Software Foundation, Inc.
 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -131,4 +131,16 @@ if { "${function_foo_addr}" == "${new_fu
   pass "function foo has a different address"
 }
 
-return 0
+# Now try loading the object as an exec-file; we should be able to print
+# the values of variables after we do this.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+# Check the values of the variables.
+gdb_test "print static_foo" "\\\$$decimal = 1"
+gdb_test "print static_bar" "\\\$$decimal = 2"
+gdb_test "print global_foo" "\\\$$decimal = 3"
+gdb_test "print global_bar" "\\\$$decimal = 4"


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