This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
RFC ARM multi-arch and object format detection
- From: Richard Earnshaw <rearnsha at arm dot com>
- To: gdb-patches at sources dot redhat dot com
- Cc: Richard dot Earnshaw at arm dot com
- Date: Thu, 14 Feb 2002 18:37:07 +0000
- Subject: RFC ARM multi-arch and object format detection
- Organization: ARM Ltd.
- Reply-to: Richard dot Earnshaw at arm dot com
Most of the remaining multi-arch conversion work for the ARM is
target-specific. Below is an initial stab at detecting the various object
formats that I know about. It seems that, even for ELF, this isn't an
exact science -- There is a fairly-well defined flag in the elf header
(EI_OSABI), but no-one seems to set it reliably, certainly gas/gld don't!
I'd appreciate comments from anyone who has been through this gloop before.
If nobody yells loudly, I'll probably commit this sometime tomorrow.
R.
* arm-tdep.h (enum arm_abi): New.
(struct gdbarch_tdep): New.
(LOWEST_PC): Define if not previously defined; use multi-arch
tdep variable.
* config/arm/tm-arm.h (LOWEST_PC): Delete.
* config/arm/tm-nbsd.h (LOWEST_PC): Delete.
* armnbsd-nat.c: Include regcache.h.
* arm-tdep.c: Include elf/arm.h.
(process_note_abi_tag_sections): New function.
(get_elfosabi): New function.
(arm_gdbarch_init): Try to determine the type of object we've been
handed and set the ABI up appropriately.
(arm_dump_tdep): Dump target-dependent data.
(_initialize_arm_tdep): Register arm_dump_tdep.
* Makefile.in (armnbsd-nat.c, arm-tdep.c): Update dependencies.
? gdbarch.log
Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.158
diff -p -r1.158 Makefile.in
*** Makefile.in 2002/02/13 20:47:16 1.158
--- Makefile.in 2002/02/14 18:17:15
*************** arm-linux-tdep.o: arm-linux-tdep.c $(def
*** 1247,1255 ****
arm-tdep.o: arm-tdep.c $(defs_h) $(frame_h) $(inferior_h) $(gdbcmd_h) \
$(gdbcore_h) $(gdb_string_h) $(dis_asm_h) $(regcache_h) $(doublest_h) \
$(value_h) $(arch_utils_h) $(solib_svr4_h) arm-tdep.h \
! $(BFD_SRC)/elf-bfd.h $(INCLUDE_DIR)/coff/internal.h
! armnbsd-nat.o: armnbsd-nat.c $(defs_h) arm-tdep.h
bcache.o: bcache.c $(bcache_h) $(defs_h)
--- 1247,1256 ----
arm-tdep.o: arm-tdep.c $(defs_h) $(frame_h) $(inferior_h) $(gdbcmd_h) \
$(gdbcore_h) $(gdb_string_h) $(dis_asm_h) $(regcache_h) $(doublest_h) \
$(value_h) $(arch_utils_h) $(solib_svr4_h) arm-tdep.h \
! $(BFD_SRC)/elf-bfd.h $(INCLUDE_DIR)/coff/internal.h \
! $(INCLUDE_DIR)/elf/arm.h
! armnbsd-nat.o: armnbsd-nat.c $(defs_h) arm-tdep.h $(inferior_h) $(regcache_h)
bcache.o: bcache.c $(bcache_h) $(defs_h)
Index: arm-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/arm-tdep.c,v
retrieving revision 1.40
diff -p -r1.40 arm-tdep.c
*** arm-tdep.c 2002/02/13 16:32:33 1.40
--- arm-tdep.c 2002/02/14 18:17:22
***************
*** 39,44 ****
--- 39,45 ----
#include "elf-bfd.h"
#include "coff/internal.h"
+ #include "elf/arm.h"
/* Each OS has a different mechanism for accessing the various
registers stored in the sigcontext structure.
*************** arm_coff_make_msymbol_special(int val, s
*** 2440,2455 ****
MSYMBOL_SET_SPECIAL (msym);
}
static struct gdbarch *
arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
struct gdbarch *gdbarch;
! if (arches != NULL)
! return arches->gdbarch;
! /* XXX We'll probably need to set the tdep field soon. */
! gdbarch = gdbarch_alloc (&info, NULL);
/* Floating point sizes and format. */
switch (info.byte_order)
--- 2441,2670 ----
MSYMBOL_SET_SPECIAL (msym);
}
+
+ static void
+ process_note_abi_tag_sections (bfd *abfd, asection *sect, void *obj)
+ {
+ enum arm_abi *os_ident_ptr = obj;
+ const char *name;
+ unsigned int sectsize;
+
+ name = bfd_get_section_name (abfd, sect);
+ sectsize = bfd_section_size (abfd, sect);
+
+ if (strcmp (name, ".note.ABI-tag") == 0 && sectsize > 0)
+ {
+ unsigned int name_length, data_length, note_type;
+ char *note;
+
+ /* If the section is larger than this, it's probably not what we are
+ looking for. */
+ if (sectsize > 128)
+ sectsize = 128;
+
+ note = alloca (sectsize);
+
+ bfd_get_section_contents (abfd, sect, note,
+ (file_ptr) 0, (bfd_size_type) sectsize);
+
+ name_length = bfd_h_get_32 (abfd, note);
+ data_length = bfd_h_get_32 (abfd, note + 4);
+ note_type = bfd_h_get_32 (abfd, note + 8);
+
+ if (name_length == 4 && data_length == 16 && note_type == 1
+ && strcmp (note + 12, "GNU") == 0)
+ {
+ int os_number = bfd_h_get_32 (abfd, note + 16);
+
+ /* The case numbers are from abi-tags in glibc */
+ switch (os_number)
+ {
+ case 0 :
+ *os_ident_ptr = ARM_ABI_LINUX;
+ break;
+
+ case 1 :
+ internal_error
+ (__FILE__, __LINE__,
+ "process_note_abi_sections: Hurd objects not supported");
+ break;
+
+ case 2 :
+ internal_error
+ (__FILE__, __LINE__,
+ "process_note_abi_sections: Solaris objects not supported");
+ break;
+
+ default :
+ internal_error
+ (__FILE__, __LINE__,
+ "process_note_abi_sections: unknown OS number %d",
+ os_number);
+ break;
+ }
+ }
+ }
+ /* NetBSD uses a similar trick. */
+ else if (strcmp (name, ".note.netbsd.ident") == 0 && sectsize > 0)
+ {
+ unsigned int name_length, desc_length, note_type;
+ char *note;
+
+ /* If the section is larger than this, it's probably not what we are
+ looking for. */
+ if (sectsize > 128)
+ sectsize = 128;
+
+ note = alloca (sectsize);
+
+ bfd_get_section_contents (abfd, sect, note,
+ (file_ptr) 0, (bfd_size_type) sectsize);
+
+ name_length = bfd_h_get_32 (abfd, note);
+ desc_length = bfd_h_get_32 (abfd, note + 4);
+ note_type = bfd_h_get_32 (abfd, note + 8);
+
+ if (name_length == 7 && desc_length == 4 && note_type == 1
+ && strcmp (note + 12, "NetBSD") == 0)
+ /* XXX Should we check the version here?
+ Probably not necessary yet. */
+ *os_ident_ptr = ARM_ABI_NETBSD_ELF;
+ }
+ }
+
+ /* Return one of the ELFOSABI_ constants for BFDs representing ELF
+ executables. If it's not an ELF executable or if the OS/ABI couldn't
+ be determined, simply return -1. */
+
+ static int
+ get_elfosabi (bfd *abfd)
+ {
+ int elfosabi;
+ enum arm_abi arm_abi = ARM_ABI_UNKNOWN;
+
+ elfosabi = elf_elfheader (abfd)->e_ident[EI_OSABI];
+
+ /* When elfosabi is 0 (ELFOSABI_NONE), this is supposed to indicate
+ that we're on a SYSV system. However, GNU/Linux uses a note section
+ to record OS/ABI info, but leaves e_ident[EI_OSABI] zero. So we
+ have to check the note sections too.
+
+ GNU/ARM tools set the EI_OSABI field to ELFOSABI_ARM, so handle that
+ as well.*/
+ if (elfosabi == 0 || elfosabi == ELFOSABI_ARM)
+ {
+ bfd_map_over_sections (abfd,
+ process_note_abi_tag_sections,
+ &arm_abi);
+ }
+
+ if (arm_abi != ARM_ABI_UNKNOWN)
+ return arm_abi;
+
+ switch (elfosabi)
+ {
+ case ELFOSABI_NONE:
+ /* Existing ARM Tools don't set this field, so look at the EI_FLAGS
+ field for more information. */
+
+ switch (EF_ARM_EABI_VERSION(elf_elfheader(abfd)->e_flags))
+ {
+ case EF_ARM_EABI_VER1:
+ return ARM_ABI_EABI_V1;
+
+ case EF_ARM_EABI_VER2:
+ return ARM_ABI_EABI_V2;
+
+ case EF_ARM_EABI_UNKNOWN:
+ /* Assume GNU tools. */
+ return ARM_ABI_APCS;
+
+ default:
+ internal_error (__FILE__, __LINE__,
+ "get_elfosabi: Unknown ARM EABI version 0x%lx",
+ EF_ARM_EABI_VERSION(elf_elfheader(abfd)->e_flags));
+
+ }
+ break;
+
+ case ELFOSABI_NETBSD:
+ return ARM_ABI_NETBSD_ELF;
+
+ case ELFOSABI_FREEBSD:
+ return ARM_ABI_FREEBSD;
+
+ case ELFOSABI_LINUX:
+ return ARM_ABI_LINUX;
+
+ case ELFOSABI_ARM:
+ /* Assume GNU tools with the old APCS abi. */
+ return ARM_ABI_APCS;
+
+ default:
+ }
+
+ return ARM_ABI_UNKNOWN;
+ }
+
+ /* Initialize the current architecture based on INFO. If possible, re-use an
+ architecture from ARCHES, which is a list of architectures already created
+ during this debugging session.
+
+ Called e.g. at program startup, when reading a core file, and when reading
+ a binary file. */
+
static struct gdbarch *
arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
+ struct gdbarch_tdep *tdep;
struct gdbarch *gdbarch;
+ enum arm_abi arm_abi = ARM_ABI_UNKNOWN;
+
+ /* Try to deterimine the ABI of the object we are loading. */
+
+ if (info.abfd != NULL)
+ {
+ switch (bfd_get_flavour (info.abfd))
+ {
+ case bfd_target_elf_flavour:
+ arm_abi = get_elfosabi (info.abfd);
+ break;
+
+ case bfd_target_aout_flavour:
+ if (strcmp (bfd_get_target(info.abfd), "a.out-arm-netbsd") == 0)
+ arm_abi = ARM_ABI_NETBSD_AOUT;
+ else
+ /* Assume it's an old APCS-style ABI. */
+ arm_abi = ARM_ABI_APCS;
+ break;
+
+ case bfd_target_coff_flavour:
+ /* Assume it's an old APCS-style ABI. */
+ /* XXX WinCE? */
+ arm_abi = ARM_ABI_APCS;
+ break;
! default:
! /* Not sure what to do here, leave the ABI as unknown. */
! break;
! }
! }
!
! /* Find a candidate among extant architectures. */
! for (arches = gdbarch_list_lookup_by_info (arches, &info);
! arches != NULL;
! arches = gdbarch_list_lookup_by_info (arches->next, &info))
! {
! /* Make sure the ABI selection matches. */
! tdep = gdbarch_tdep (arches->gdbarch);
! if (tdep && tdep->arm_abi == arm_abi)
! return arches->gdbarch;
! }
!
! tdep = xmalloc (sizeof (struct gdbarch_tdep));
! gdbarch = gdbarch_alloc (&info, tdep);
! tdep->arm_abi = arm_abi;
/* Floating point sizes and format. */
switch (info.byte_order)
*************** arm_gdbarch_init (struct gdbarch_info in
*** 2473,2478 ****
--- 2688,2711 ----
"arm_gdbarch_init: bad byte order for float format");
}
+ switch (arm_abi)
+ {
+ case ARM_ABI_UNKNOWN:
+ case ARM_ABI_EABI_V1:
+ case ARM_ABI_EABI_V2:
+ case ARM_ABI_APCS:
+ case ARM_ABI_WINCE:
+ tdep->lowest_pc = 0x20; /* Just beyond the vectors. */
+ break;
+
+ case ARM_ABI_LINUX:
+ case ARM_ABI_NETBSD_AOUT:
+ case ARM_ABI_NETBSD_ELF:
+ case ARM_ABI_FREEBSD:
+ tdep->lowest_pc = 0x8000;
+ break;
+ }
+
set_gdbarch_use_generic_dummy_frames (gdbarch, 0);
/* Call dummy code. */
*************** arm_gdbarch_init (struct gdbarch_info in
*** 2580,2585 ****
--- 2813,2875 ----
return gdbarch;
}
+ static void
+ arm_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
+ {
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (tdep == NULL)
+ return;
+
+ switch (tdep->arm_abi)
+ {
+ case ARM_ABI_UNKNOWN:
+ fprintf_unfiltered (file, "arm_dump_tdep: ABI = <unknown>\n");
+ break;
+
+ case ARM_ABI_EABI_V1:
+ fprintf_unfiltered (file, "arm_dump_tdep: ABI = ARM EABI (version 1)\n");
+ break;
+
+ case ARM_ABI_EABI_V2:
+ fprintf_unfiltered (file, "arm_dump_tdep: ABI = ARM EABI (version 2)\n");
+ break;
+
+ case ARM_ABI_LINUX:
+ fprintf_unfiltered (file, "arm_dump_tdep: ABI = GNU/Linux\n");
+ break;
+
+ case ARM_ABI_NETBSD_AOUT:
+ fprintf_unfiltered (file, "arm_dump_tdep: ABI = NetBSD (a.out)\n");
+ break;
+
+ case ARM_ABI_NETBSD_ELF:
+ fprintf_unfiltered (file, "arm_dump_tdep: ABI = NetBSD (ELF)\n");
+ break;
+
+ case ARM_ABI_APCS:
+ fprintf_unfiltered (file, "arm_dump_tdep: ABI = APCS\n");
+ break;
+
+ case ARM_ABI_FREEBSD:
+ fprintf_unfiltered (file, "arm_dump_tdep: ABI = FreeBSD\n");
+ break;
+
+ case ARM_ABI_WINCE:
+ fprintf_unfiltered (file, "arm_dump_tdep: ABI = Windows CE\n");
+ break;
+
+ default:
+ internal_error (__FILE__, __LINE__,
+ "arm_dump_tdep: illegal setting of tdep->arm_abi (%d)",
+ (int) tdep->arm_abi);
+ break;
+ }
+
+ fprintf_unfiltered (file, "arm_dump_tdep: Lowest pc = 0x%lx",
+ (unsigned long) tdep->lowest_pc);
+ }
+
void
_initialize_arm_tdep (void)
{
*************** _initialize_arm_tdep (void)
*** 2593,2599 ****
static char *helptext;
if (GDB_MULTI_ARCH)
! register_gdbarch_init (bfd_arch_arm, arm_gdbarch_init);
tm_print_insn = gdb_print_insn_arm;
--- 2883,2889 ----
static char *helptext;
if (GDB_MULTI_ARCH)
! gdbarch_register (bfd_arch_arm, arm_gdbarch_init, arm_dump_tdep);
tm_print_insn = gdb_print_insn_arm;
Index: arm-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/arm-tdep.h,v
retrieving revision 1.2
diff -p -r1.2 arm-tdep.h
*** arm-tdep.h 2002/02/13 17:09:07 1.2
--- arm-tdep.h 2002/02/14 18:17:22
***************
*** 99,104 ****
--- 99,130 ----
#define FLAG_C 0x20000000
#define FLAG_V 0x10000000
+ /* ABI variants that we know about. */
+ enum arm_abi
+ {
+ ARM_ABI_UNKNOWN,
+ ARM_ABI_EABI_V1,
+ ARM_ABI_EABI_V2,
+ ARM_ABI_LINUX,
+ ARM_ABI_NETBSD_AOUT,
+ ARM_ABI_NETBSD_ELF,
+ ARM_ABI_APCS,
+ ARM_ABI_FREEBSD,
+ ARM_ABI_WINCE
+ };
+
+ /* Target-dependent structure in gdbarch. */
+ struct gdbarch_tdep
+ {
+ enum arm_abi arm_abi; /* OS/ABI of inferior. */
+ CORE_ADDR lowest_pc; /* Lowest address at which instructions
+ will appear. */
+ };
+
+ #ifndef LOWEST_PC
+ #define LOWEST_PC (gdbarch_tdep (current_gdbarch)->lowest_pc)
+ #endif
+
/* Prototypes for internal interfaces needed by more than one MD file. */
int arm_pc_is_thumb_dummy (CORE_ADDR);
Index: armnbsd-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/armnbsd-nat.c,v
retrieving revision 1.3
diff -p -r1.3 armnbsd-nat.c
*** armnbsd-nat.c 2002/02/11 18:34:08 1.3
--- armnbsd-nat.c 2002/02/14 18:17:22
***************
*** 29,34 ****
--- 29,35 ----
#include <machine/reg.h>
#include <machine/frame.h>
#include "inferior.h"
+ #include "regcache.h"
void
fetch_inferior_registers (regno)
Index: config/arm/tm-arm.h
===================================================================
RCS file: /cvs/src/src/gdb/config/arm/tm-arm.h,v
retrieving revision 1.27
diff -p -r1.27 tm-arm.h
*** tm-arm.h 2002/02/13 16:32:34 1.27
--- tm-arm.h 2002/02/14 18:17:22
***************
*** 70,76 ****
#define CALL_DUMMY_BREAKPOINT_OFFSET arm_call_dummy_breakpoint_offset()
extern int arm_call_dummy_breakpoint_offset (void);
- /* The first 0x20 bytes are the trap vectors. */
- #define LOWEST_PC 0x20
-
#endif /* TM_ARM_H */
--- 70,73 ----
Index: config/arm/tm-nbsd.h
===================================================================
RCS file: /cvs/src/src/gdb/config/arm/tm-nbsd.h,v
retrieving revision 1.3
diff -p -r1.3 tm-nbsd.h
*** tm-nbsd.h 2002/02/11 18:34:12 1.3
--- tm-nbsd.h 2002/02/14 18:17:22
***************
*** 27,36 ****
#define JB_ELEMENT_SIZE sizeof(long) /* jmp_buf[_JBLEN] is array of ints */
#define JB_PC 24 /* Setjmp()'s return PC saved here */
- /* The first page is not writeable in NetBSD. */
- #undef LOWEST_PC
- #define LOWEST_PC 0x8000
-
/* Return non-zero if inside a shared-library entry stub. */
#undef IN_SOLIB_CALL_TRAMPOLINE
#define IN_SOLIB_CALL_TRAMPOLINE(pc, name) \
--- 27,32 ----