This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFC ARM multi-arch and object format detection


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 ----

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