summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--Makefile.def2
-rw-r--r--Makefile.in2
-rw-r--r--gdb/ChangeLog32
-rw-r--r--gdb/Makefile.in6
-rw-r--r--gdb/NEWS4
-rw-r--r--gdb/coffread.c2
-rw-r--r--gdb/config.in3
-rwxr-xr-xgdb/configure76
-rw-r--r--gdb/configure.ac24
-rw-r--r--gdb/dbxread.c4
-rw-r--r--gdb/doc/ChangeLog4
-rw-r--r--gdb/doc/gdb.texinfo27
-rw-r--r--gdb/elfread.c74
-rw-r--r--gdb/mipsread.c2
-rw-r--r--gdb/remote.c116
-rw-r--r--gdb/somread.c2
-rw-r--r--gdb/symfile.c214
-rw-r--r--gdb/symfile.h39
-rw-r--r--gdb/xcoffread.c2
20 files changed, 585 insertions, 55 deletions
diff --git a/ChangeLog b/ChangeLog
index 4fc9fc74c9c..f5cd00cee27 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2007-06-18 Daniel Jacobowitz <dan@codesourcery.com>
+
+ * Makefile.def: Add dependency from configure-gdb to all-bfd.
+ * Makefile.in: Regenerated.
+
2007-06-14 Paolo Bonzini <bonzini@gnu.org>
* Makefile.tpl (cleanstrap): Don't delete the toplevel Makefile.
diff --git a/Makefile.def b/Makefile.def
index 6436272ae9c..3d2c6eeeb44 100644
--- a/Makefile.def
+++ b/Makefile.def
@@ -314,10 +314,10 @@ dependencies = { module=configure-mpfr; on=all-gmp; };
// Host modules specific to gdb.
dependencies = { module=configure-gdb; on=configure-intl; };
dependencies = { module=configure-gdb; on=configure-sim; };
+dependencies = { module=configure-gdb; on=all-bfd; };
dependencies = { module=all-gdb; on=all-intl; };
dependencies = { module=all-gdb; on=all-libiberty; };
dependencies = { module=all-gdb; on=all-opcodes; };
-dependencies = { module=all-gdb; on=all-bfd; };
dependencies = { module=all-gdb; on=all-readline; };
dependencies = { module=all-gdb; on=all-build-bison; };
dependencies = { module=all-gdb; on=all-build-byacc; };
diff --git a/Makefile.in b/Makefile.in
index 785f53ba45a..e34410cf18b 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -49030,10 +49030,10 @@ configure-stageprofile-mpfr: maybe-all-stageprofile-gmp
configure-stagefeedback-mpfr: maybe-all-stagefeedback-gmp
configure-gdb: maybe-configure-intl
configure-gdb: maybe-configure-sim
+configure-gdb: maybe-all-bfd
all-gdb: maybe-all-intl
all-gdb: maybe-all-libiberty
all-gdb: maybe-all-opcodes
-all-gdb: maybe-all-bfd
all-gdb: maybe-all-readline
all-gdb: maybe-all-build-bison
all-gdb: maybe-all-build-byacc
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 00c31410064..0ed2af062ca 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,35 @@
+2007-06-18 Daniel Jacobowitz <dan@codesourcery.com>
+
+ * coffread.c (coff_sym_fns): Add default_symfile_segments.
+ * dbxread.c (start_psymtab): Check HAVE_ELF.
+ (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 (COMMON_OBS): Remove elfread.o.
+ (elf_internal_h): New.
+ (elfread.o): Update.
+ * configure.ac: Add elfread.o to COMMON_OBS if bfd/elf.o was
+ compiled.
+ * config.in, configure: Regenerated.
+ * NEWS: Mention qOffsets changes.
+
2007-06-16 Ulrich Weigand <uweigand@de.ibm.com>
* gdbtypes.h (builtin_type_m2_char, builtin_type_m2_int,
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 13570eba4ce..3d0fa409a30 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -586,6 +586,7 @@ coff_ecoff_h = $(INCLUDE_DIR)/coff/ecoff.h
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)
@@ -946,7 +947,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
signals.o \
gdb-events.o \
exec.o bcache.o objfiles.o observer.o minsyms.o maint.o demangle.o \
- dbxread.o coffread.o coff-pe-read.o elfread.o \
+ dbxread.o coffread.o coff-pe-read.o \
dwarf2read.o mipsread.o stabsread.o corefile.o \
dwarf2expr.o dwarf2loc.o dwarf2-frame.o \
ada-lang.o c-lang.o f-lang.o objc-lang.o \
@@ -1958,7 +1959,8 @@ dwarf2read.o: dwarf2read.c $(defs_h) $(bfd_h) $(symtab_h) $(gdbtypes_h) \
$(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) \
diff --git a/gdb/NEWS b/gdb/NEWS
index 596456daee0..59c241a7c11 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -37,6 +37,10 @@ has been rewritten to use the standard GDB remote protocol.
* GDB for the Cell/B.E. SPU now supports overlay debugging.
+* 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 remoteflow
diff --git a/gdb/coffread.c b/gdb/coffread.c
index 7ff53b7134b..dcd17d35faa 100644
--- a/gdb/coffread.c
+++ b/gdb/coffread.c
@@ -2139,6 +2139,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 */
};
diff --git a/gdb/config.in b/gdb/config.in
index 1ca8e46f99b..1534afe8275 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -110,6 +110,9 @@
*/
#undef HAVE_DIRENT_H
+/* Define if ELF support should be included. */
+#undef HAVE_ELF
+
/* Define to 1 if you have the `fork' function. */
#undef HAVE_FORK
diff --git a/gdb/configure b/gdb/configure
index 9d9309ea161..788351176a8 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -21797,6 +21797,82 @@ _ACEOF
esac
+# Add ELF support to GDB, but only if BFD includes ELF support.
+OLD_CFLAGS=$CFLAGS
+OLD_LDFLAGS=$LDFLAGS
+OLD_LIBS=$LIBS
+CFLAGS="$CFLAGS -I${srcdir}/../include -I${objdir}/../bfd -I${srcdir}/../bfd"
+LDFLAGS="$LDFLAGS -L../bfd -L../libiberty"
+LIBS="$LIBS -lbfd -liberty"
+echo "$as_me:$LINENO: checking for ELF support in BFD" >&5
+echo $ECHO_N "checking for ELF support in BFD... $ECHO_C" >&6
+if test "${gdb_cv_var_elf+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+#include "bfd.h"
+#include "elf-bfd.h"
+
+int
+main ()
+{
+bfd *abfd = NULL; bfd_get_elf_phdr_upper_bound (abfd);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gdb_cv_var_elf=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gdb_cv_var_elf=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $gdb_cv_var_elf" >&5
+echo "${ECHO_T}$gdb_cv_var_elf" >&6
+if test $gdb_cv_var_elf = yes; then
+ CONFIG_OBS="$CONFIG_OBS elfread.o"
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ELF 1
+_ACEOF
+
+fi
+CFLAGS=$OLD_CFLAGS
+LDFLAGS=$OLD_LDFLAGS
+LIBS=$OLD_LIBS
+
# Add any host-specific objects to GDB.
CONFIG_OBS="${CONFIG_OBS} ${gdb_host_obs}"
diff --git a/gdb/configure.ac b/gdb/configure.ac
index ea160990662..680a43e2a73 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -1255,6 +1255,30 @@ case ${host} in
esac
AC_SUBST(WIN32LIBS)
+# Add ELF support to GDB, but only if BFD includes ELF support.
+OLD_CFLAGS=$CFLAGS
+OLD_LDFLAGS=$LDFLAGS
+OLD_LIBS=$LIBS
+CFLAGS="$CFLAGS -I${srcdir}/../include -I${objdir}/../bfd -I${srcdir}/../bfd"
+LDFLAGS="$LDFLAGS -L../bfd -L../libiberty"
+LIBS="$LIBS -lbfd -liberty"
+AC_CACHE_CHECK([for ELF support in BFD], gdb_cv_var_elf,
+[AC_TRY_LINK(
+[#include <stdlib.h>
+#include "bfd.h"
+#include "elf-bfd.h"
+],
+[bfd *abfd = NULL; bfd_get_elf_phdr_upper_bound (abfd); ],
+gdb_cv_var_elf=yes, gdb_cv_var_elf=no)])
+if test $gdb_cv_var_elf = yes; then
+ CONFIG_OBS="$CONFIG_OBS elfread.o"
+ AC_DEFINE(HAVE_ELF, 1,
+ [Define if ELF support should be included.])
+fi
+CFLAGS=$OLD_CFLAGS
+LDFLAGS=$OLD_LDFLAGS
+LIBS=$OLD_LIBS
+
# Add any host-specific objects to GDB.
CONFIG_OBS="${CONFIG_OBS} ${gdb_host_obs}"
diff --git a/gdb/dbxread.c b/gdb/dbxread.c
index 702e315fd7c..bba9995a5e2 100644
--- a/gdb/dbxread.c
+++ b/gdb/dbxread.c
@@ -2148,11 +2148,13 @@ start_psymtab (struct objfile *objfile, char *filename, CORE_ADDR textlow,
STRING_OFFSET (result) = string_table_offset;
FILE_STRING_OFFSET (result) = file_string_table_offset;
+#ifdef HAVE_ELF
/* If we're handling an ELF file, drag some section-relocation info
for this source file out of the ELF symbol table, to compensate for
Sun brain death. This replaces the section_offsets in this psymtab,
if successful. */
elfstab_offset_sections (objfile, result);
+#endif
/* Deduce the source language from the filename for this psymtab. */
psymtab_language = deduce_language_from_filename (filename);
@@ -3505,6 +3507,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 */
};
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 8f7e7325d15..a3192a3d00a 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,7 @@
+2007-06-18 Daniel Jacobowitz <dan@codesourcery.com>
+
+ * gdb.texinfo (General Query Packets): Document qOffsets changes.
+
2007-06-13 Daniel Jacobowitz <dan@codesourcery.com>
* gdb.texinfo (Target Description Format): Add version attribute
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 230a6cad85e..377278611c5 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -23433,14 +23433,31 @@ digits). See @code{remote.c:parse_threadlist_response()}.
@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}
diff --git a/gdb/elfread.c b/gdb/elfread.c
index ea28d7c258a..7b84ede6c71 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -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 */
};
diff --git a/gdb/mipsread.c b/gdb/mipsread.c
index eb06f30a9dc..daa4ba72a43 100644
--- a/gdb/mipsread.c
+++ b/gdb/mipsread.c
@@ -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 */
};
diff --git a/gdb/remote.c b/gdb/remote.c
index f4f267b420d..3990a34285a 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -2016,9 +2016,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);
@@ -2047,47 +2051,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)
+ {
+ ptr += 5;
+ while (*ptr && *ptr != ';')
+ bss_addr = (bss_addr << 4) + fromhex (*ptr++);
- if (!lose && strncmp (ptr, ";Bss=", 5) == 0)
+ 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;
- /* 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. */
+ /* 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"));
+
+ 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);
}
diff --git a/gdb/somread.c b/gdb/somread.c
index c4f0744716f..199825c911e 100644
--- a/gdb/somread.c
+++ b/gdb/somread.c
@@ -438,6 +438,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 */
};
diff --git a/gdb/symfile.c b/gdb/symfile.c
index fac4c87ea06..f513dfa6f1b 100644
--- a/gdb/symfile.c
+++ b/gdb/symfile.c
@@ -106,7 +106,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 *);
@@ -146,6 +146,8 @@ static char *find_separate_debug_file (struct objfile *objfile);
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
@@ -430,12 +432,19 @@ init_objfile_sect_indices (struct objfile *objfile)
/* 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++)
{
@@ -639,6 +648,70 @@ default_symfile_offsets (struct objfile *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.
@@ -685,7 +758,7 @@ syms_from_objfile (struct objfile *objfile,
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. */
@@ -1505,29 +1578,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));
}
@@ -3771,6 +3838,111 @@ symfile_relocate_debug_section (bfd *abfd, asection *sectp, bfd_byte *buf)
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)
{
diff --git a/gdb/symfile.h b/gdb/symfile.h
index b24acc1c931..4d08c71ecc7 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -85,6 +85,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. */
@@ -131,6 +153,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
@@ -146,6 +174,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 *);
@@ -313,6 +345,13 @@ extern void simple_overlay_update (struct obj_section *);
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 *);
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index 8c8208ef51b..e5c2e08bbdf 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -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 */
};