From 31d99776c73d6fca13163da59c852b0fa99f89b8 Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Mon, 18 Jun 2007 15:46:38 +0000 Subject: [PATCH] * 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. * gdb.texinfo (General Query Packets): Document qOffsets changes. * Makefile.def: Add dependency from configure-gdb to all-bfd. * Makefile.in: Regenerated. --- ChangeLog | 5 ++ Makefile.def | 2 +- Makefile.in | 2 +- gdb/ChangeLog | 32 +++++++ gdb/Makefile.in | 6 +- gdb/NEWS | 4 + gdb/coffread.c | 2 + gdb/config.in | 3 + gdb/configure | 76 ++++++++++++++++ gdb/configure.ac | 24 +++++ gdb/dbxread.c | 4 + gdb/doc/ChangeLog | 4 + 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 + 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 + + * Makefile.def: Add dependency from configure-gdb to all-bfd. + * Makefile.in: Regenerated. + 2007-06-14 Paolo Bonzini * 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 + + * 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 * 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 +#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 +#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 + + * gdb.texinfo (General Query Packets): Document qOffsets changes. + 2007-06-13 Daniel Jacobowitz * 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 */ }; -- 2.30.2