* sh-tdep.c (sh_osabi_names): Declare.
authorJason Thorpe <thorpej@netbsd.org>
Wed, 8 May 2002 14:54:03 +0000 (14:54 +0000)
committerJason Thorpe <thorpej@netbsd.org>
Wed, 8 May 2002 14:54:03 +0000 (14:54 +0000)
(process_note_abi_tag_sections): New function.
(get_elfosabi): Ditto.
(sh_gdbarch_register_os_abi): Ditto.
(sh_dump_tdep): Ditto.
_initialize_sh_tdep): Use gdbarch_register to register
sh_gdbarch_init and sh_dump_tdep.
* config/sh/tm-sh.h (sh_osabi): Declare.
(gdbarch_tdep): Add sh_osabi and osabi_name members.

gdb/ChangeLog
gdb/config/sh/tm-sh.h
gdb/sh-tdep.c

index 44440f7..d9a85cf 100644 (file)
@@ -1,3 +1,15 @@
+2002-05-08  Jason Thorpe  <thorpej@wasabisystems.com>
+
+       * sh-tdep.c (sh_osabi_names): Declare.
+       (process_note_abi_tag_sections): New function.
+       (get_elfosabi): Ditto.
+       (sh_gdbarch_register_os_abi): Ditto.
+       (sh_dump_tdep): Ditto.
+       _initialize_sh_tdep): Use gdbarch_register to register
+       sh_gdbarch_init and sh_dump_tdep.
+       * config/sh/tm-sh.h (sh_osabi): Declare.
+       (gdbarch_tdep): Add sh_osabi and osabi_name members.
+
 2002-05-07  Andrew Cagney  <ac131313@redhat.com>
 
        * arm-tdep.c (arm_skip_prologue): Handle generic dummy frames.
index 1690ecf..e65d8cd 100644 (file)
 
 #define GDB_MULTI_ARCH 1
 
+/* ABI variants that we know about.  If you add to this enum, please
+   update the table of names in sh-tdep.c.  */
+enum sh_osabi
+{
+  SH_OSABI_UNKNOWN = 0,
+  SH_OSABI_LINUX,
+  SH_OSABI_NETBSD_ELF,
+
+  SH_OSABI_INVALID     /* Keep this last.  */
+};
+
 /* Information that is dependent on the processor variant. */
 
 struct gdbarch_tdep
@@ -56,6 +67,9 @@ struct gdbarch_tdep
     int ARGLAST_REGNUM;
     int FLOAT_ARGLAST_REGNUM;
     int RETURN_REGNUM;
+
+    enum sh_osabi sh_osabi;    /* OS/ABI of the inferior */
+    const char *osabi_name;    /* Name of the above */
   };
 
 /* Registers common to all the SH variants. */
@@ -81,4 +95,3 @@ enum
 #define LITTLE_REMOTE_BREAKPOINT { 0x20, 0xc3 } /* Used in remote.c */
 
 /*#define NOP   {0x20, 0x0b}*/ /* Who uses this???*/
-
index c47a668..4d6b113 100644 (file)
@@ -41,6 +41,8 @@
 #include "regcache.h"
 #include "doublest.h"
 
+#include "elf-bfd.h"
+
 #include "solib-svr4.h"
 
 void (*sh_show_regs) (void);
@@ -1895,6 +1897,176 @@ sh_linux_svr4_fetch_link_map_offsets (void)
 }
 #endif /* SVR4_SHARED_LIBS */
 
+\f
+/* This table matches the indices assigned to enum sh_osabi.  Keep
+   them in sync.  */
+static const char * const sh_osabi_names[] =
+{
+  "<unknown>",
+  "GNU/Linux",
+  "NetBSD ELF",
+  NULL
+};
+
+static void
+process_note_abi_tag_sections (bfd *abfd, asection *sect, void *obj)
+{
+  enum sh_osabi *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 == NT_GNU_ABI_TAG
+         && 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 GNU_ABI_TAG_LINUX:
+             *os_ident_ptr = SH_OSABI_LINUX;
+             break;
+
+           case GNU_ABI_TAG_HURD:
+             internal_error
+               (__FILE__, __LINE__,
+                "process_note_abi_sections: Hurd objects not supported");
+             break;
+
+           case GNU_ABI_TAG_SOLARIS:
+             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);
+           }
+       }
+    }
+  /* 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 == NT_NETBSD_IDENT
+         && strcmp (note + 12, "NetBSD") == 0)
+       /* XXX Should we check the version here?
+          Probably not necessary yet.  */
+       *os_ident_ptr = SH_OSABI_NETBSD_ELF;
+    }
+}
+
+static int
+get_elfosabi (bfd *abfd)
+{
+  int elfosabi;
+  enum sh_osabi sh_osabi = SH_OSABI_UNKNOWN;
+
+  elfosabi = elf_elfheader (abfd)->e_ident[EI_OSABI];
+
+  switch (elfosabi)
+    {
+    case ELFOSABI_NONE:
+      /* When elfosabi is 0 (ELFOSABI_NONE), this is supposed to indicate
+        that we're on a SYSV system.  However, some systems use note sections
+        to record OS/ABI info, but leave e_ident[EI_OSABI] zero.  So we
+        have to check the note sections too.  */
+      bfd_map_over_sections (abfd,
+                            process_note_abi_tag_sections,
+                            &sh_osabi);
+      break;
+
+    case ELFOSABI_NETBSD:
+      sh_osabi = SH_OSABI_NETBSD_ELF;
+      break;
+
+    case ELFOSABI_LINUX:
+      sh_osabi = SH_OSABI_LINUX;
+      break;
+    }
+
+  return (sh_osabi);
+}
+
+struct sh_osabi_handler
+{
+  struct sh_osabi_handler *next;
+  enum sh_osabi abi;
+  void (*init_osabi)(struct gdbarch_info, struct gdbarch *);
+};
+
+struct sh_osabi_handler *sh_osabi_handler_list = NULL;
+
+void
+sh_gdbarch_register_os_abi (enum sh_osabi abi,
+                            void (*init_osabi)(struct gdbarch_info,
+                                              struct gdbarch *))
+{
+  struct sh_osabi_handler **handler_p;
+
+  for (handler_p = &sh_osabi_handler_list; *handler_p != NULL;
+       handler_p = &(*handler_p)->next)
+    {
+      if ((*handler_p)->abi == abi)
+       {
+         internal_error
+           (__FILE__, __LINE__,
+            "sh_gdbarch_register_os_abi: A handler for this ABI variant "
+            "(%d) has already been registered", (int) abi);
+         /* If user wants to continue, override previous definition.  */
+         (*handler_p)->init_osabi = init_osabi;
+         return;
+       }
+    }
+
+  (*handler_p)
+    = (struct sh_osabi_handler *) xmalloc (sizeof (struct sh_osabi_handler));
+  (*handler_p)->next = NULL;
+  (*handler_p)->abi = abi;
+  (*handler_p)->init_osabi = init_osabi;
+}
+
 static gdbarch_init_ftype sh_gdbarch_init;
 
 static struct gdbarch *
@@ -1906,17 +2078,51 @@ sh_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   gdbarch_register_name_ftype *sh_register_name;
   gdbarch_store_return_value_ftype *sh_store_return_value;
   gdbarch_register_virtual_type_ftype *sh_register_virtual_type;
+  enum sh_osabi sh_osabi = SH_OSABI_UNKNOWN;
+  struct sh_osabi_handler *osabi_handler;
+
+  /* Try to determine the ABI of the object we are loading.  */
+
+  if (info.abfd != NULL)
+    {
+      switch (bfd_get_flavour (info.abfd))
+       {
+       case bfd_target_elf_flavour:
+         sh_osabi = get_elfosabi (info.abfd);
+         break;
+
+       default:
+         /* Just leave it as "unkown".  */
+         break;
+       }
+    }
 
   /* Find a candidate among the list of pre-declared architectures. */
-  arches = gdbarch_list_lookup_by_info (arches, &info);
-  if (arches != NULL)
-    return arches->gdbarch;
+  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->sh_osabi == sh_osabi)
+       return arches->gdbarch;
+    }
 
   /* None found, create a new architecture from the information
      provided. */
   tdep = XMALLOC (struct gdbarch_tdep);
   gdbarch = gdbarch_alloc (&info, tdep);
 
+  tdep->sh_osabi = sh_osabi;
+  if (sh_osabi < SH_OSABI_INVALID)
+    tdep->osabi_name = sh_osabi_names[sh_osabi];
+  else
+    {
+      internal_error (__FILE__, __LINE__, "Invalid setting of sh_osabi %d",
+                     (int) sh_osabi);
+      tdep->osabi_name = "<invalid>";
+    }
+
   /* Initialize the register numbers that are not common to all the
      variants to -1, if necessary thse will be overwritten in the case
      statement below. */
@@ -2167,15 +2373,58 @@ sh_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_frame_num_args (gdbarch, frame_num_args_unknown);
   set_gdbarch_believe_pcc_promotion (gdbarch, 1);
 
+  /* Hook in ABI-specific overrides, if they have been registered.  If
+     the ABI is unknown, this is probably an embedded target, so we
+     should not warn about this situation.  */
+  if (sh_osabi != SH_OSABI_UNKNOWN)
+    {
+      for (osabi_handler = sh_osabi_handler_list; osabi_handler != NULL;
+          osabi_handler = osabi_handler->next)
+       if (osabi_handler->abi == sh_osabi)
+         break;
+
+      if (osabi_handler)
+        osabi_handler->init_osabi (info, gdbarch);
+      else
+        {
+         /* We assume that if GDB_MULTI_ARCH is less than
+            GDB_MULTI_ARCH_TM that an ABI variant can be supported by 
+            overriding definitions in this file.  */
+         if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) 
+           fprintf_filtered
+             (gdb_stderr,
+              "A handler for the ABI variant \"%s\" is not built into this "
+              "configuration of GDB.  "
+              "Attempting to continue with the default SuperH settings",
+              sh_osabi_names[sh_osabi]);
+        }
+    }
+
   return gdbarch;
 }
 
+static void
+sh_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+  if (tdep == NULL)
+    return;
+
+  if (tdep->osabi_name != NULL)
+    fprintf_unfiltered (file, "sh_dump_tdep: OS ABI = %s\n", tdep->osabi_name);
+  else
+    internal_error (__FILE__, __LINE__,
+                   "sh_dump_tdep: illegal setting of tdep->sh_osabi (%d)",
+                   (int) tdep->sh_osabi);
+}
+
 void
 _initialize_sh_tdep (void)
 {
   struct cmd_list_element *c;
   
-  register_gdbarch_init (bfd_arch_sh, sh_gdbarch_init);
+  gdbarch_register (bfd_arch_sh, sh_gdbarch_init, sh_dump_tdep);
 
   add_com ("regs", class_vars, sh_show_regs_command, "Print all registers");
 }