This is the mail archive of the gdb@sourceware.org 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 / remote protocol] ELF segment based qOffsets


[Remote protocol change, so I've CC'd gdb@.]

This patch adds two new features to the qOffsets packet.

First, if the remote target replies "Text=4000;Data=9000" GDB used to
relocate the .text and .data sections in the object file.  But
sections are not a good unit of relocation on many modern systems.
What about the .rodata section?  Or more esoteric things for
dynamic executables, like .dynamic and .got?  They get left
behind.

So this patch lets the symfile reader (e.g. elfread) describe the
segments of the object file which can be relocated individually.  In
ELF, that means PT_LOAD entries in the program headers.  Conventional
executables have two, one for the code and another for the writable
data.  In special circumstances there may be one, or a multitude.
The default is to assume that any fully linked executable (i.e. not a
.o or .obj file) must be relocated in a single chunk, except for
ELF where we can parse the program headers.

Now, when we get Text=4000 we relocate the entire text segment by
0x4000 bytes.

Second, I was working with a SymbianOS target where the original
segment addresses are not available on the target.  In the ELF file we
may have a program header at 0x1000 and another at 0x9000; but on the
target we only have two loadable regions and those addresses are
completely gone.  So I added TextSeg= and DataSeg=.  They're just like
Text= except for one thing: instead of adjusting the address by the
supplied offset, the segment's base address is completely replaced.
GDB reports an error if it can't break the file down into segments.

Things not done, but easy extensions if someone needs them later:

  - remote protocol support for relocating arbitrary numbers of
  segments.  This would be easy now; add Seg3=XXXX et cetera to
  the parser in get_offsets and document it.

  - segment based relocation for other commands.  I think it would
  be sensible to use it for add-symbol-file too but you'd have to
  adjust the user interface.

Here is the documentation of the new support, and the patch is at the
end of the message.  What do you all think?  Eli, is the
documentation OK?

@@ -23428,14 +23428,31 @@ digits).  See @code{remote.c:parse_threa
 @item qOffsets
 @cindex section offsets, remote request
 @cindex @samp{qOffsets} packet
-Get section offsets that the target used when re-locating the downloaded
-image.  @emph{Note: while a @code{Bss} offset is included in the
-response, @value{GDBN} ignores this and instead applies the @code{Data}
-offset to the @code{Bss} section.}
+Get section offsets that the target used when relocating the downloaded
+image.
 
 Reply:
 @table @samp
-@item Text=@var{xxx};Data=@var{yyy};Bss=@var{zzz}
+@item Text=@var{xxx};Data=@var{yyy}@r{[};Bss=@var{zzz}@r{]}
+Relocate the @code{Text} section by @var{xxx} from its original address.
+Relocate the @code{Data} section by @var{yyy} from its original address.
+If the object file format provides segment information (e.g.@: @sc{elf}
+@samp{PT_LOAD} program headers), @value{GDBN} will relocate entire
+segments by the supplied offsets.
+
+@emph{Note: while a @code{Bss} offset may be included in the response,
+@value{GDBN} ignores this and instead applies the @code{Data} offset
+to the @code{Bss} section.}
+
+@item TextSeg=@var{xxx}@r{[};DataSeg=@var{yyy}@r{]}
+Relocate the first segment of the object file, which conventionally
+contains program code, to a starting address of @var{xxx}.  If
+@samp{DataSeg} is specified, relocate the second segment, which
+conventionally contains modifiable data, to a starting address of
+@var{yyy}.  @value{GDBN} will report an error if the object file
+does not contain segment information, or does not contain at least
+as many segments as mentioned in the reply.  Extra segments are
+kept at fixed offsets relative to the last relocated segment.
 @end table
 
-- 
Daniel Jacobowitz
CodeSourcery

2007-05-09  Daniel Jacobowitz  <dan@codesourcery.com>

	* coffread.c (coff_sym_fns): Add default_symfile_segments.
	* dbxread.c (aout_sym_fns): Likewise.
	* elfread.c (elf_symfile_segments): New.
	(elf_sym_fns): Add elf_symfile_segments.
	* mipsread.c (ecoff_sym_fns): Add default_symfile_segments.
	* remote.c (get_offsets): Use symfile_map_offsets_to_segments.
	Skip if there is no symfile_objfile.  Handle TextSeg and DataSeg.
	* somread.c (som_sym_fns): Use default_symfile_segments.
	* symfile.c (find_sym_fns): Take a BFD and return the sym_fns.
	(init_objfile_sect_indices): Call symfile_find_segment_sections.
	(default_symfile_segments): New function.
	(syms_from_objfile): Update call to find_sym_fns.
	(symfile_get_segment_data, free_symfile_segment_data): New.
	(symfile_map_offsets_to_segments): New.
	(symfile_find_segment_sections): New.
	* symfile.h (struct symfile_segment_data): New.
	(struct sym_fns): Add sym_segments.
	(default_symfile_segments, symfile_get_segment_data)
	(free_symfile_segment_data): New prototypes.
	(symfile_map_offsets_to_segments): Likewise.
	* xcoffread.c (xcoff_sym_fns): Add default_symfile_segments.
	* Makefile.in (elf_internal_h): New.
	(elfread.o): Update.
	* NEWS: Mention qOffsets changes.

	* gdb.texinfo (General Query Packets): Document qOffsets changes.

---
 gdb/Makefile.in     |    4 
 gdb/NEWS            |    4 
 gdb/coffread.c      |    2 
 gdb/dbxread.c       |    2 
 gdb/doc/gdb.texinfo |   27 +++++-
 gdb/elfread.c       |   74 +++++++++++++++++
 gdb/mipsread.c      |    2 
 gdb/remote.c        |  116 ++++++++++++++++++++++------
 gdb/somread.c       |    2 
 gdb/symfile.c       |  214 ++++++++++++++++++++++++++++++++++++++++++++++------
 gdb/symfile.h       |   39 +++++++++
 gdb/xcoffread.c     |    2 
 12 files changed, 436 insertions(+), 52 deletions(-)

Index: gdb/coffread.c
===================================================================
--- gdb/coffread.c.orig	2007-05-09 11:30:07.000000000 -0400
+++ gdb/coffread.c	2007-05-09 11:30:13.000000000 -0400
@@ -2133,6 +2133,8 @@ static struct sym_fns coff_sym_fns =
   coff_symfile_read,		/* sym_read: read a symbol file into symtab */
   coff_symfile_finish,		/* sym_finish: finished with file, cleanup */
   default_symfile_offsets,	/* sym_offsets:  xlate external to internal form */
+  default_symfile_segments,	/* sym_segments: Get segment information from
+				   a file.  */
   NULL				/* next: pointer to next struct sym_fns */
 };
 
Index: gdb/dbxread.c
===================================================================
--- gdb/dbxread.c.orig	2007-05-09 11:30:07.000000000 -0400
+++ gdb/dbxread.c	2007-05-09 11:30:13.000000000 -0400
@@ -3505,6 +3505,8 @@ static struct sym_fns aout_sym_fns =
   dbx_symfile_read,		/* sym_read: read a symbol file into symtab */
   dbx_symfile_finish,		/* sym_finish: finished with file, cleanup */
   default_symfile_offsets,	/* sym_offsets: parse user's offsets to internal form */
+  default_symfile_segments,	/* sym_segments: Get segment information from
+				   a file.  */
   NULL				/* next: pointer to next struct sym_fns */
 };
 
Index: gdb/elfread.c
===================================================================
--- gdb/elfread.c.orig	2007-05-09 11:30:07.000000000 -0400
+++ gdb/elfread.c	2007-05-09 11:30:13.000000000 -0400
@@ -26,6 +26,8 @@
 #include "bfd.h"
 #include "gdb_string.h"
 #include "elf-bfd.h"
+#include "elf/common.h"
+#include "elf/internal.h"
 #include "elf/mips.h"
 #include "symtab.h"
 #include "symfile.h"
@@ -51,6 +53,76 @@ struct elfinfo
 
 static void free_elfinfo (void *);
 
+/* Locate the segments in ABFD.  */
+
+static struct symfile_segment_data *
+elf_symfile_segments (bfd *abfd)
+{
+  Elf_Internal_Phdr *phdrs, **segments;
+  long phdrs_size;
+  int num_phdrs, num_segments, num_sections, i;
+  asection *sect;
+  struct symfile_segment_data *data;
+
+  phdrs_size = bfd_get_elf_phdr_upper_bound (abfd);
+  if (phdrs_size == -1)
+    return NULL;
+
+  phdrs = alloca (phdrs_size);
+  num_phdrs = bfd_get_elf_phdrs (abfd, phdrs);
+  if (num_phdrs == -1)
+    return NULL;
+
+  num_segments = 0;
+  segments = alloca (sizeof (Elf_Internal_Phdr *) * num_phdrs);
+  for (i = 0; i < num_phdrs; i++)
+    if (phdrs[i].p_type == PT_LOAD)
+      segments[num_segments++] = &phdrs[i];
+
+  if (num_segments == 0)
+    return NULL;
+
+  data = XZALLOC (struct symfile_segment_data);
+  data->num_segments = num_segments;
+  data->segment_bases = XCALLOC (num_segments, CORE_ADDR);
+  data->segment_sizes = XCALLOC (num_segments, CORE_ADDR);
+
+  for (i = 0; i < num_segments; i++)
+    {
+      data->segment_bases[i] = segments[i]->p_vaddr;
+      data->segment_sizes[i] = segments[i]->p_memsz;
+    }
+
+  num_sections = bfd_count_sections (abfd);
+  data->segment_info = XCALLOC (num_sections, int);
+
+  for (i = 0, sect = abfd->sections; sect != NULL; i++, sect = sect->next)
+    {
+      int j;
+      CORE_ADDR vma;
+
+      if ((bfd_get_section_flags (abfd, sect) & SEC_ALLOC) == 0)
+	continue;
+
+      vma = bfd_get_section_vma (abfd, sect);
+
+      for (j = 0; j < num_segments; j++)
+	if (segments[j]->p_memsz > 0
+	    && vma >= segments[j]->p_vaddr
+	    && vma < segments[j]->p_vaddr + segments[j]->p_memsz)
+	  {
+	    data->segment_info[i] = j + 1;
+	    break;
+	  }
+
+      if (bfd_get_section_size (sect) > 0 && j == num_segments)
+	warning (_("Loadable segment \"%s\" outside of ELF segments"),
+		 bfd_section_name (abfd, sect));
+    }
+
+  return data;
+}
+
 /* We are called once per section from elf_symfile_read.  We
    need to examine each section we are passed, check to see
    if it is something we are interested in processing, and
@@ -741,6 +813,8 @@ static struct sym_fns elf_sym_fns =
   elf_symfile_read,		/* sym_read: read a symbol file into symtab */
   elf_symfile_finish,		/* sym_finish: finished with file, cleanup */
   default_symfile_offsets,	/* sym_offsets:  Translate ext. to int. relocation */
+  elf_symfile_segments,		/* sym_segments: Get segment information from
+				   a file.  */
   NULL				/* next: pointer to next struct sym_fns */
 };
 
Index: gdb/mipsread.c
===================================================================
--- gdb/mipsread.c.orig	2007-05-09 11:30:07.000000000 -0400
+++ gdb/mipsread.c	2007-05-09 11:30:13.000000000 -0400
@@ -394,6 +394,8 @@ static struct sym_fns ecoff_sym_fns =
   mipscoff_symfile_read,	/* sym_read: read a symbol file into symtab */
   mipscoff_symfile_finish,	/* sym_finish: finished with file, cleanup */
   default_symfile_offsets,	/* sym_offsets: dummy FIXME til implem sym reloc */
+  default_symfile_segments,	/* sym_segments: Get segment information from
+				   a file.  */
   NULL				/* next: pointer to next struct sym_fns */
 };
 
Index: gdb/remote.c
===================================================================
--- gdb/remote.c.orig	2007-05-09 11:30:07.000000000 -0400
+++ gdb/remote.c	2007-05-09 13:27:04.000000000 -0400
@@ -2008,9 +2008,13 @@ get_offsets (void)
   struct remote_state *rs = get_remote_state ();
   char *buf;
   char *ptr;
-  int lose;
-  CORE_ADDR text_addr, data_addr, bss_addr;
+  int lose, num_segments = 0, do_sections, do_segments;
+  CORE_ADDR text_addr, data_addr, bss_addr, segments[2];
   struct section_offsets *offs;
+  struct symfile_segment_data *data;
+
+  if (symfile_objfile == NULL)
+    return;
 
   putpkt ("qOffsets");
   getpkt (&rs->buf, &rs->buf_size, 0);
@@ -2039,47 +2043,109 @@ get_offsets (void)
       /* Don't use strtol, could lose on big values.  */
       while (*ptr && *ptr != ';')
 	text_addr = (text_addr << 4) + fromhex (*ptr++);
-    }
-  else
-    lose = 1;
 
-  if (!lose && strncmp (ptr, ";Data=", 6) == 0)
-    {
-      ptr += 6;
-      while (*ptr && *ptr != ';')
-	data_addr = (data_addr << 4) + fromhex (*ptr++);
-    }
-  else
-    lose = 1;
+      if (strncmp (ptr, ";Data=", 6) == 0)
+	{
+	  ptr += 6;
+	  while (*ptr && *ptr != ';')
+	    data_addr = (data_addr << 4) + fromhex (*ptr++);
+	}
+      else
+	lose = 1;
 
-  if (!lose && strncmp (ptr, ";Bss=", 5) == 0)
+      if (!lose && strncmp (ptr, ";Bss=", 5) == 0)
+	{
+	  ptr += 5;
+	  while (*ptr && *ptr != ';')
+	    bss_addr = (bss_addr << 4) + fromhex (*ptr++);
+
+	  if (bss_addr != data_addr)
+	    warning (_("Target reported unsupported offsets: %s"), buf);
+	}
+      else
+	lose = 1;
+    }
+  else if (strncmp (ptr, "TextSeg=", 8) == 0)
     {
-      ptr += 5;
+      ptr += 8;
+      /* Don't use strtol, could lose on big values.  */
       while (*ptr && *ptr != ';')
-	bss_addr = (bss_addr << 4) + fromhex (*ptr++);
+	text_addr = (text_addr << 4) + fromhex (*ptr++);
+      num_segments = 1;
+
+      if (strncmp (ptr, ";DataSeg=", 9) == 0)
+	{
+	  ptr += 9;
+	  while (*ptr && *ptr != ';')
+	    data_addr = (data_addr << 4) + fromhex (*ptr++);
+	  num_segments++;
+	}
     }
   else
     lose = 1;
 
   if (lose)
     error (_("Malformed response to offset query, %s"), buf);
-
-  if (symfile_objfile == NULL)
-    return;
+  else if (*ptr != '\0')
+    warning (_("Target reported unsupported offsets: %s"), buf);
 
   offs = ((struct section_offsets *)
 	  alloca (SIZEOF_N_SECTION_OFFSETS (symfile_objfile->num_sections)));
   memcpy (offs, symfile_objfile->section_offsets,
 	  SIZEOF_N_SECTION_OFFSETS (symfile_objfile->num_sections));
 
-  offs->offsets[SECT_OFF_TEXT (symfile_objfile)] = text_addr;
+  data = get_symfile_segment_data (symfile_objfile->obfd);
+  do_segments = (data != NULL);
+  do_sections = num_segments == 0;
+
+  /* Text= and Data= specify offsets for the text and data sections,
+     but symfile_map_offsets_to_segments expects base addresses
+     instead of offsets.  If we have two segments, we can still
+     try to relocate the whole segments instead of just ".text"
+     and ".data".  */
+  if (num_segments == 0)
+    {
+      do_sections = 1;
+      if (data == NULL || data->num_segments != 2)
+	do_segments = 0;
+      else
+	{
+	  segments[0] = data->segment_bases[0] + text_addr;
+	  segments[1] = data->segment_bases[1] + data_addr;
+	}
+    }
+  else
+    {
+      do_sections = 0;
+      segments[0] = text_addr;
+      segments[1] = data_addr;
+    }
+
+  if (do_segments)
+    {
+      int ret = symfile_map_offsets_to_segments (symfile_objfile->obfd, data,
+						 offs, num_segments, segments);
+
+      if (ret == 0 && !do_sections)
+	error (_("Can not handle qOffsets TextSeg response with this symbol file"));
 
-  /* This is a temporary kludge to force data and bss to use the same offsets
-     because that's what nlmconv does now.  The real solution requires changes
-     to the stub and remote.c that I don't have time to do right now.  */
+      if (ret > 0)
+	do_sections = 0;
+    }
 
-  offs->offsets[SECT_OFF_DATA (symfile_objfile)] = data_addr;
-  offs->offsets[SECT_OFF_BSS (symfile_objfile)] = data_addr;
+  free_symfile_segment_data (data);
+
+  if (do_sections)
+    {
+      offs->offsets[SECT_OFF_TEXT (symfile_objfile)] = text_addr;
+
+      /* This is a temporary kludge to force data and bss to use the same offsets
+	 because that's what nlmconv does now.  The real solution requires changes
+	 to the stub and remote.c that I don't have time to do right now.  */
+
+      offs->offsets[SECT_OFF_DATA (symfile_objfile)] = data_addr;
+      offs->offsets[SECT_OFF_BSS (symfile_objfile)] = data_addr;
+    }
 
   objfile_relocate (symfile_objfile, offs);
 }
Index: gdb/somread.c
===================================================================
--- gdb/somread.c.orig	2007-05-09 11:30:07.000000000 -0400
+++ gdb/somread.c	2007-05-09 11:30:13.000000000 -0400
@@ -697,6 +697,8 @@ static struct sym_fns som_sym_fns =
   som_symfile_read,		/* sym_read: read a symbol file into symtab */
   som_symfile_finish,		/* sym_finish: finished with file, cleanup */
   som_symfile_offsets,		/* sym_offsets:  Translate ext. to int. relocation */
+  default_symfile_segments,	/* sym_segments: Get segment information from
+				   a file.  */
   NULL				/* next: pointer to next struct sym_fns */
 };
 
Index: gdb/symfile.c
===================================================================
--- gdb/symfile.c.orig	2007-05-09 11:30:07.000000000 -0400
+++ gdb/symfile.c	2007-05-09 11:30:13.000000000 -0400
@@ -107,7 +107,7 @@ bfd *symfile_bfd_open (char *);
 
 int get_section_index (struct objfile *, char *);
 
-static void find_sym_fns (struct objfile *);
+static struct sym_fns *find_sym_fns (bfd *);
 
 static void decrement_reading_symtab (void *);
 
@@ -147,6 +147,8 @@ static char *find_separate_debug_file (s
 
 static void init_filename_language_table (void);
 
+static void symfile_find_segment_sections (struct objfile *objfile);
+
 void _initialize_symfile (void);
 
 /* List of all available sym_fns.  On gdb startup, each object file reader
@@ -431,12 +433,19 @@ init_objfile_sect_indices (struct objfil
   /* This is where things get really weird...  We MUST have valid
      indices for the various sect_index_* members or gdb will abort.
      So if for example, there is no ".text" section, we have to
-     accomodate that.  Except when explicitly adding symbol files at
-     some address, section_offsets contains nothing but zeros, so it
-     doesn't matter which slot in section_offsets the individual
-     sect_index_* members index into.  So if they are all zero, it is
-     safe to just point all the currently uninitialized indices to the
-     first slot. */
+     accomodate that.  First, check for a file with the standard
+     one or two segments.  */
+
+  symfile_find_segment_sections (objfile);
+
+  /* Except when explicitly adding symbol files at some address,
+     section_offsets contains nothing but zeros, so it doesn't matter
+     which slot in section_offsets the individual sect_index_* members
+     index into.  So if they are all zero, it is safe to just point
+     all the currently uninitialized indices to the first slot.  But
+     beware: if this is the main executable, it may be relocated
+     later, e.g. by the remote qOffsets packet, and then this will
+     be wrong!  That's why we try segments first.  */
 
   for (i = 0; i < objfile->num_sections; i++)
     {
@@ -640,6 +649,70 @@ default_symfile_offsets (struct objfile 
 }
 
 
+/* Divide the file into segments, which are individual relocatable units.
+   This is the default version of the sym_fns.sym_segments function for
+   symbol readers that do not have an explicit representation of segments.
+   It assumes that object files do not have segments, and fully linked
+   files have a single segment.  */
+
+struct symfile_segment_data *
+default_symfile_segments (bfd *abfd)
+{
+  int num_sections, i;
+  asection *sect;
+  struct symfile_segment_data *data;
+  CORE_ADDR low, high;
+
+  /* Relocatable files contain enough information to position each
+     loadable section independently; they should not be relocated
+     in segments.  */
+  if ((bfd_get_file_flags (abfd) & (EXEC_P | DYNAMIC)) == 0)
+    return NULL;
+
+  /* Make sure there is at least one loadable section in the file.  */
+  for (sect = abfd->sections; sect != NULL; sect = sect->next)
+    {
+      if ((bfd_get_section_flags (abfd, sect) & SEC_ALLOC) == 0)
+	continue;
+
+      break;
+    }
+  if (sect == NULL)
+    return NULL;
+
+  low = bfd_get_section_vma (abfd, sect);
+  high = low + bfd_get_section_size (sect);
+
+  data = XZALLOC (struct symfile_segment_data);
+  data->num_segments = 1;
+  data->segment_bases = XCALLOC (1, CORE_ADDR);
+  data->segment_sizes = XCALLOC (1, CORE_ADDR);
+
+  num_sections = bfd_count_sections (abfd);
+  data->segment_info = XCALLOC (num_sections, int);
+
+  for (i = 0, sect = abfd->sections; sect != NULL; i++, sect = sect->next)
+    {
+      CORE_ADDR vma;
+
+      if ((bfd_get_section_flags (abfd, sect) & SEC_ALLOC) == 0)
+	continue;
+
+      vma = bfd_get_section_vma (abfd, sect);
+      if (vma < low)
+	low = vma;
+      if (vma + bfd_get_section_size (sect) > high)
+	high = vma + bfd_get_section_size (sect);
+
+      data->segment_info[i] = 1;
+    }
+
+  data->segment_bases[0] = low;
+  data->segment_sizes[0] = high - low;
+
+  return data;
+}
+
 /* Process a symbol file, as either the main file or as a dynamically
    loaded file.
 
@@ -686,7 +759,7 @@ syms_from_objfile (struct objfile *objfi
   gdb_assert (! (addrs && offsets));
 
   init_entry_point_info (objfile);
-  find_sym_fns (objfile);
+  objfile->sf = find_sym_fns (objfile->obfd);
 
   if (objfile->sf == NULL)
     return;	/* No symbols. */
@@ -1507,29 +1580,23 @@ add_symtab_fns (struct sym_fns *sf)
    struct sym_fns in the objfile structure, that contains cached
    information about the symbol file.  */
 
-static void
-find_sym_fns (struct objfile *objfile)
+static struct sym_fns *
+find_sym_fns (bfd *abfd)
 {
   struct sym_fns *sf;
-  enum bfd_flavour our_flavour = bfd_get_flavour (objfile->obfd);
-  char *our_target = bfd_get_target (objfile->obfd);
+  enum bfd_flavour our_flavour = bfd_get_flavour (abfd);
 
   if (our_flavour == bfd_target_srec_flavour
       || our_flavour == bfd_target_ihex_flavour
       || our_flavour == bfd_target_tekhex_flavour)
-    return;	/* No symbols.  */
+    return NULL;	/* No symbols.  */
 
   for (sf = symtab_fns; sf != NULL; sf = sf->next)
-    {
-      if (our_flavour == sf->sym_flavour)
-	{
-	  objfile->sf = sf;
-	  return;
-	}
-    }
+    if (our_flavour == sf->sym_flavour)
+      return sf;
 
   error (_("I'm sorry, Dave, I can't do that.  Symbol format `%s' unknown."),
-	 bfd_get_target (objfile->obfd));
+	 bfd_get_target (abfd));
 }
 
 
@@ -3777,6 +3844,111 @@ symfile_relocate_debug_section (bfd *abf
   return bfd_simple_get_relocated_section_contents (abfd, sectp, buf, NULL);
 }
 
+struct symfile_segment_data *
+get_symfile_segment_data (bfd *abfd)
+{
+  struct sym_fns *sf = find_sym_fns (abfd);
+
+  if (sf == NULL)
+    return NULL;
+
+  return sf->sym_segments (abfd);
+}
+
+void
+free_symfile_segment_data (struct symfile_segment_data *data)
+{
+  xfree (data->segment_bases);
+  xfree (data->segment_sizes);
+  xfree (data->segment_info);
+  xfree (data);
+}
+
+int
+symfile_map_offsets_to_segments (bfd *abfd, struct symfile_segment_data *data,
+				 struct section_offsets *offsets,
+				 int num_segment_bases,
+				 const CORE_ADDR *segment_bases)
+{
+  int i;
+  asection *sect;
+
+  /* If we do not have segment mappings for the object file, we
+     can not relocate it by segments.  */
+  gdb_assert (data != NULL);
+  gdb_assert (data->num_segments > 0);
+
+  /* If more offsets are provided than we have segments, make sure the
+     excess offsets are all the same as the last segment's offset.
+     This allows "Text=X;Data=X" for files which have only a single
+     segment.  */
+  if (num_segment_bases > data->num_segments)
+    for (i = data->num_segments; i < num_segment_bases; i++)
+      if (segment_bases[i] != segment_bases[data->num_segments - 1])
+	return 0;
+
+  for (i = 0, sect = abfd->sections; sect != NULL; i++, sect = sect->next)
+    {
+      CORE_ADDR vma;
+      int which = data->segment_info[i];
+
+      if (which > num_segment_bases)
+	offsets->offsets[i] = segment_bases[num_segment_bases - 1];
+      else if (which > 0)
+	offsets->offsets[i] = segment_bases[which - 1];
+      else
+	continue;
+
+      offsets->offsets[i] -= data->segment_bases[which - 1];
+    }
+
+  return 1;
+}
+
+static void
+symfile_find_segment_sections (struct objfile *objfile)
+{
+  bfd *abfd = objfile->obfd;
+  int i;
+  asection *sect;
+  struct symfile_segment_data *data;
+
+  data = get_symfile_segment_data (objfile->obfd);
+  if (data == NULL)
+    return;
+
+  if (data->num_segments != 1 && data->num_segments != 2)
+    {
+      free_symfile_segment_data (data);
+      return;
+    }
+
+  for (i = 0, sect = abfd->sections; sect != NULL; i++, sect = sect->next)
+    {
+      CORE_ADDR vma;
+      int which = data->segment_info[i];
+
+      if (which == 1)
+	{
+	  if (objfile->sect_index_text == -1)
+	    objfile->sect_index_text = sect->index;
+
+	  if (objfile->sect_index_rodata == -1)
+	    objfile->sect_index_rodata = sect->index;
+	}
+      else if (which == 2)
+	{
+	  if (objfile->sect_index_data == -1)
+	    objfile->sect_index_data = sect->index;
+
+	  if (objfile->sect_index_bss == -1)
+	    objfile->sect_index_bss = sect->index;
+	}
+    }
+
+  free_symfile_segment_data (data);
+}
+
 void
 _initialize_symfile (void)
 {
Index: gdb/symfile.h
===================================================================
--- gdb/symfile.h.orig	2007-05-09 11:30:07.000000000 -0400
+++ gdb/symfile.h	2007-05-09 11:30:13.000000000 -0400
@@ -84,6 +84,28 @@ struct section_addr_info
   } other[1];
 };
 
+struct symfile_segment_data
+{
+  /* How many segments are present in this file.  If there are
+     two, the text segment is the first one and the data segment
+     is the second one.  */
+  int num_segments;
+
+  /* If NUM_SEGMENTS is greater than zero, the original base address
+     of each segment.  */
+  CORE_ADDR *segment_bases;
+
+  /* If NUM_SEGMENTS is greater than zero, the memory size of each
+     segment.  */
+  CORE_ADDR *segment_sizes;
+
+  /* If NUM_SEGMENTS is greater than zero, this is an array of entries
+     recording which segment contains each BFD section.  It is
+     ordered by section index.  A zero means that the section is not
+     in any segment.  */
+  int *segment_info;
+};
+
 /* Structure to keep track of symbol reading functions for various
    object file types.  */
 
@@ -130,6 +152,12 @@ struct sym_fns
 
   void (*sym_offsets) (struct objfile *, struct section_addr_info *);
 
+  /* This function produces a format-independent description of
+     the segments of ABFD.  Each segment is a unit of the file
+     which may be relocated independently.  */
+
+  struct symfile_segment_data *(*sym_segments) (bfd *abfd);
+
   /* Finds the next struct sym_fns.  They are allocated and
      initialized in whatever module implements the functions pointed
      to; an initializer calls add_symtab_fns to add them to the global
@@ -145,6 +173,10 @@ struct sym_fns
 extern void default_symfile_offsets (struct objfile *objfile,
 				     struct section_addr_info *);
 
+/* The default version of sym_fns.sym_segments for readers that don't
+   do anything special.  */
+
+extern struct symfile_segment_data *default_symfile_segments (bfd *abfd);
 
 extern void extend_psymbol_list (struct psymbol_allocation_list *,
 				 struct objfile *);
@@ -309,6 +341,13 @@ extern void symbol_file_clear (int from_
 extern bfd_byte *symfile_relocate_debug_section (bfd *abfd, asection *sectp,
 						 bfd_byte * buf);
 
+extern int symfile_map_offsets_to_segments (bfd *,
+					    struct symfile_segment_data *,
+					    struct section_offsets *,
+					    int, const CORE_ADDR *);
+struct symfile_segment_data *get_symfile_segment_data (bfd *abfd);
+void free_symfile_segment_data (struct symfile_segment_data *data);
+
 /* From dwarf2read.c */
 
 extern int dwarf2_has_info (struct objfile *);
Index: gdb/xcoffread.c
===================================================================
--- gdb/xcoffread.c.orig	2007-05-09 11:30:07.000000000 -0400
+++ gdb/xcoffread.c	2007-05-09 11:30:13.000000000 -0400
@@ -3015,6 +3015,8 @@ static struct sym_fns xcoff_sym_fns =
   xcoff_initial_scan,		/* sym_read: read a symbol file into symtab */
   xcoff_symfile_finish,		/* sym_finish: finished with file, cleanup */
   xcoff_symfile_offsets,	/* sym_offsets: xlate offsets ext->int form */
+  default_symfile_segments,	/* sym_segments: Get segment information from
+				   a file.  */
   NULL				/* next: pointer to next struct sym_fns */
 };
 
Index: gdb/Makefile.in
===================================================================
--- gdb/Makefile.in.orig	2007-05-09 11:30:07.000000000 -0400
+++ gdb/Makefile.in	2007-05-09 13:27:00.000000000 -0400
@@ -586,6 +586,7 @@ coff_ecoff_h =	$(INCLUDE_DIR)/coff/ecoff
 coff_internal_h =	$(INCLUDE_DIR)/coff/internal.h
 dis_asm_h =	$(INCLUDE_DIR)/dis-asm.h $(bfd_h)
 elf_common_h =	$(INCLUDE_DIR)/elf/common.h
+elf_internal_h =	$(INCLUDE_DIR)/elf/internal.h
 elf_reloc_macros_h =	$(INCLUDE_DIR)/elf/reloc-macros.h
 elf_sh_h =	$(INCLUDE_DIR)/elf/sh.h
 elf_arm_h =	$(INCLUDE_DIR)/elf/arm.h $(elf_reloc_macros_h)
@@ -1958,7 +1959,8 @@ dwarf2read.o: dwarf2read.c $(defs_h) $(b
 	$(gdb_string_h) $(gdb_assert_h)
 elfread.o: elfread.c $(defs_h) $(bfd_h) $(gdb_string_h) $(elf_bfd_h) \
 	$(elf_mips_h) $(symtab_h) $(symfile_h) $(objfiles_h) $(buildsym_h) \
-	$(stabsread_h) $(gdb_stabs_h) $(complaints_h) $(demangle_h)
+	$(stabsread_h) $(gdb_stabs_h) $(complaints_h) $(demangle_h) \
+	$(elf_common_h) $(elf_internal_h)
 environ.o: environ.c $(defs_h) $(environ_h) $(gdb_string_h)
 eval.o: eval.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \
 	$(value_h) $(expression_h) $(target_h) $(frame_h) $(language_h) \
Index: gdb/NEWS
===================================================================
--- gdb/NEWS.orig	2007-05-09 11:30:07.000000000 -0400
+++ gdb/NEWS	2007-05-09 11:30:13.000000000 -0400
@@ -31,6 +31,10 @@ has been rewritten to use the standard G
 
 * GDB can now step into C++ functions which are called through thunks.
 
+* The GDB remote protocol "qOffsets" packet can now honor ELF segment
+layout.  It also supports a TextSeg= and DataSeg= response when only
+segment base addresses (rather than offsets) are available.
+
 * New commands
 
 set mem inaccessible-by-default
Index: gdb/doc/gdb.texinfo
===================================================================
--- gdb/doc/gdb.texinfo.orig	2007-05-09 11:30:07.000000000 -0400
+++ gdb/doc/gdb.texinfo	2007-05-09 11:30:13.000000000 -0400
@@ -23428,14 +23428,31 @@ digits).  See @code{remote.c:parse_threa
 @item qOffsets
 @cindex section offsets, remote request
 @cindex @samp{qOffsets} packet
-Get section offsets that the target used when re-locating the downloaded
-image.  @emph{Note: while a @code{Bss} offset is included in the
-response, @value{GDBN} ignores this and instead applies the @code{Data}
-offset to the @code{Bss} section.}
+Get section offsets that the target used when relocating the downloaded
+image.
 
 Reply:
 @table @samp
-@item Text=@var{xxx};Data=@var{yyy};Bss=@var{zzz}
+@item Text=@var{xxx};Data=@var{yyy}@r{[};Bss=@var{zzz}@r{]}
+Relocate the @code{Text} section by @var{xxx} from its original address.
+Relocate the @code{Data} section by @var{yyy} from its original address.
+If the object file format provides segment information (e.g.@: @sc{elf}
+@samp{PT_LOAD} program headers), @value{GDBN} will relocate entire
+segments by the supplied offsets.
+
+@emph{Note: while a @code{Bss} offset may be included in the response,
+@value{GDBN} ignores this and instead applies the @code{Data} offset
+to the @code{Bss} section.}
+
+@item TextSeg=@var{xxx}@r{[};DataSeg=@var{yyy}@r{]}
+Relocate the first segment of the object file, which conventionally
+contains program code, to a starting address of @var{xxx}.  If
+@samp{DataSeg} is specified, relocate the second segment, which
+conventionally contains modifiable data, to a starting address of
+@var{yyy}.  @value{GDBN} will report an error if the object file
+does not contain segment information, or does not contain at least
+as many segments as mentioned in the reply.  Extra segments are
+kept at fixed offsets relative to the last relocated segment.
 @end table
 
 @item qP @var{mode} @var{threadid}


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