* i386-tdep.h (struct gdbarch_tdep): Add `os_ident' member.
authorMark Kettenis <kettenis@gnu.org>
Tue, 1 Jan 2002 16:29:43 +0000 (16:29 +0000)
committerMark Kettenis <kettenis@gnu.org>
Tue, 1 Jan 2002 16:29:43 +0000 (16:29 +0000)
* i386-tdep.c: Include "elf-bfd.h".
(process_note_abi_tag_sections): New function.
(i386_gdbarch_init): Add code to recognize various OS/ABI
combinations.

gdb/ChangeLog
gdb/i386-tdep.c
gdb/i386-tdep.h

index 30cdf79..26fa10e 100644 (file)
@@ -1,5 +1,11 @@
 2002-01-01  Mark Kettenis  <kettenis@gnu.org>
 
+       * i386-tdep.h (struct gdbarch_tdep): Add `os_ident' member.
+       * i386-tdep.c: Include "elf-bfd.h".
+       (process_note_abi_tag_sections): New function.
+       (i386_gdbarch_init): Add code to recognize various OS/ABI
+       combinations.
+
        * maint.c (_initialize_maint_cmds): Add missing \ in
        string-literal.
 
index 524a6ff..31ecb76 100644 (file)
 #include "regcache.h"
 #include "doublest.h"
 #include "value.h"
-#include "i386-tdep.h"
 #include "gdb_assert.h"
 
+#include "elf-bfd.h"
+
+#include "i386-tdep.h"
+
 #undef XMALLOC
 #define XMALLOC(TYPE) ((TYPE*) xmalloc (sizeof (TYPE)))
 
@@ -1205,21 +1208,104 @@ gdb_print_insn_i386 (bfd_vma memaddr, disassemble_info *info)
 }
 
 \f
+static void
+process_note_abi_tag_sections (bfd *abfd, asection *sect, void *obj)
+{
+  int *os_ident_ptr = obj;
+  const char *name;
+  unsigned int sect_size;
+
+  name = bfd_get_section_name (abfd, sect);
+  sect_size = bfd_section_size (abfd, sect);
+  if (strcmp (name, ".note.ABI-tag") == 0 && sect_size > 0)
+    {
+      unsigned int name_length, data_length, note_type;
+      char *note = alloca (sect_size);
+
+      bfd_get_section_contents (abfd, sect, note,
+                                (file_ptr) 0, (bfd_size_type) sect_size);
+
+      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 = ELFOSABI_LINUX;
+              break;
+            case 1:
+              *os_ident_ptr = ELFOSABI_HURD;
+              break;
+            case 2:
+              *os_ident_ptr = ELFOSABI_SOLARIS;
+              break;
+            default:
+              internal_error (__FILE__, __LINE__,
+                              "process_note_abi_sections: "
+                              "unknown OS number %d", os_number);
+              break;
+            }
+        }
+    }
+}
 
 struct gdbarch *
 i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 {
   struct gdbarch_tdep *tdep;
   struct gdbarch *gdbarch;
+  int os_ident;
 
-  /* For the moment there is only one i386 architecture.  */
-  if (arches != NULL)
-    return arches->gdbarch;
+  if (info.abfd != NULL
+      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    {
+      os_ident = elf_elfheader (info.abfd)->e_ident[EI_OSABI];
+
+      /* If os_ident is 0, it is not necessarily the case that we're
+         on a SYSV system.  (ELFOSABI_NONE is defined to be 0.)
+         GNU/Linux uses a note section to record OS/ABI info, but
+         leaves e_ident[EI_OSABI] zero.  So we have to check for note
+         sections too.  */
+      if (os_ident == ELFOSABI_NONE)
+       bfd_map_over_sections (info.abfd,
+                              process_note_abi_tag_sections,
+                              &os_ident);
+         
+      /* If that didn't help us, revert to some non-standard checks.  */
+      if (os_ident == ELFOSABI_NONE)
+       {
+         /* FreeBSD folks are naughty; they stored the string
+            "FreeBSD" in the padding of the e_ident field of the ELF
+            header.  */
+         if (strcmp (&elf_elfheader (info.abfd)->e_ident[8], "FreeBSD") == 0)
+           os_ident = ELFOSABI_FREEBSD;
+        }
+    }
+  else
+    os_ident = -1;
+
+  for (arches = gdbarch_list_lookup_by_info (arches, &info);
+       arches != NULL;
+       arches = gdbarch_list_lookup_by_info (arches->next, &info))
+    {
+      if (gdbarch_tdep (current_gdbarch)->os_ident != os_ident)
+        continue;
+      return arches->gdbarch;
+    }
 
   /* Allocate space for the new architecture.  */
   tdep = XMALLOC (struct gdbarch_tdep);
   gdbarch = gdbarch_alloc (&info, tdep);
 
+  tdep->os_ident = os_ident;
+
   /* FIXME: kettenis/2001-11-24: Although not all IA-32 processors
      have the SSE registers, it's easier to set the default to 8.  */
   tdep->num_xmm_regs = 8;
index 5c8ed9a..a990adf 100644 (file)
@@ -43,6 +43,9 @@
 /* i386 architecture specific information.  */
 struct gdbarch_tdep
 {
+  /* OS/ABI.  */
+  int os_ident;
+
   /* Number of SSE registers.  */
   int num_xmm_regs;
 };