[PATCH/RFC] Generic OS ABI handling for gdbarch

Jason R Thorpe thorpej@wasabisystems.com
Sat May 11 21:20:00 GMT 2002


I started working on generic OS ABI handling for GDB today, lifting from
the various duplicated bits of code in several targets.

There are two pieces to the generic code:

	* OS ABI handlers.  These are basically the same as the OS ABI
	  handlers that exist on a per-target basis, but when they're
	  registered, you now specify a bfd_architecture.  Only one
	  OS ABI can exist per bfd_architecture.

	* OS ABI "sniffers".  These peek at a BFD with a given
	  bfd_architecture/bfd_flavour and determine which OS ABI
	  is correct for that BFD.  Multiple sniffers can exist for
	  a given bfd_architecture/bfd_flavour, e.g. one to sniff out
	  NetBSD a.out, one for FreeBSD a.out, etc.  If a sniffer
	  registers w/ bfd_architecture of "unknown", it can sniff
	  files of any architecture for its flavour.

	  There is a generic ELF sniffer that uses EI_OSABI and note
	  sections.  (This is an example of an arch == "unknown"
	  sniffer.)

	  The first sniffer to return other than GDB_OSABI_UNKNOWN
	  wins, so sniffers should be careful to only claim BFDs
	  they're sure about.

Tomorrow I'll make the Alpha and SH targets use the generic OS ABI
framework as examples.

Comments appreciated.

-- 
        -- Jason R. Thorpe <thorpej@wasabisystems.com>
-------------- next part --------------
Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.184
diff -u -r1.184 Makefile.in
--- Makefile.in	11 May 2002 22:14:19 -0000	1.184
+++ Makefile.in	12 May 2002 04:03:40 -0000
@@ -530,7 +530,7 @@
 	demangle.c dwarfread.c dwarf2read.c elfread.c environ.c eval.c \
 	event-loop.c event-top.c \
 	expprint.c f-exp.y f-lang.c f-typeprint.c f-valprint.c \
-	findvar.c regcache.c gdbarch.c arch-utils.c gdbtypes.c \
+	findvar.c regcache.c gdbarch.c arch-utils.c gdbtypes.c osabi.c \
 	inf-loop.c infcmd.c inflow.c infrun.c language.c \
 	kod.c kod-cisco.c \
 	ui-out.c cli-out.c \
@@ -634,6 +634,7 @@
 memattr_h =     memattr.h
 monitor_h =	monitor.h
 objfiles_h =	objfiles.h
+osabi_h =	osabi.h
 parser_defs_h =	parser-defs.h $(doublest_h)
 regcache_h =	regcache.h
 remote_h =	remote.h
@@ -712,7 +713,7 @@
 	symtab.o symfile.o symmisc.o linespec.o infcmd.o infrun.o \
 	expprint.o environ.o stack.o thread.o \
 	event-loop.o event-top.o inf-loop.o completer.o \
-	gdbarch.o arch-utils.o gdbtypes.o copying.o $(DEPFILES) \
+	gdbarch.o arch-utils.o gdbtypes.o osabi.o copying.o $(DEPFILES) \
 	memattr.o mem-break.o target.o parse.o language.o $(YYOBJ) buildsym.o \
 	builtin-regs.o std-regs.o \
 	signals.o \
@@ -1556,6 +1557,8 @@
 gdbtypes.o: gdbtypes.c $(bfd_h) $(complaints_h) $(defs_h) $(expression_h) \
 	$(gdbtypes_h) $(language_h) $(objfiles_h) $(symfile_h) $(symtab_h) \
 	$(target_h) $(value_h) $(gdb_string_h) $(wrapper_h) $(cp_abi_h)
+
+osabi.o: osabi.c $(defs_h) $(osabi_h) $(BFD_SRC)/elf-bfd.h
 
 go32-nat.o: go32-nat.c $(defs_h) $(inferior_h) gdb_wait.h $(gdbcore_h) \
 	$(command_h) $(floatformat_h) $(target_h) i387-tdep.h $(regcache_h)
Index: osabi.c
===================================================================
RCS file: osabi.c
diff -N osabi.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ osabi.c	12 May 2002 04:03:41 -0000
@@ -0,0 +1,334 @@
+/* OS ABI variant handling for GDB.
+   Copyright 2001, 2002 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,  
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+  
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "osabi.h"
+#include "elf-bfd.h"
+
+
+/* This table matches the indices assigned to enum gdb_osabi.  Keep
+   them in sync.  */
+static const char * const gdb_osabi_names[] =
+{
+  "<unknown>",
+
+  "SVR4",
+  "GNU Hurd",
+  "Solaris",
+  "OSF/1",
+  "GNU/Linux",
+  "FreeBSD a.out",
+  "FreeBSD ELF",
+  "NetBSD a.out",
+  "NetBSD ELF",
+  "Windows CE",
+
+  "ARM EABI v1"
+  "ARM EABI v2"
+  "ARM APCS",
+
+  NULL
+};
+
+const char *
+gdbarch_osabi_name (enum gdb_osabi osabi)
+{
+  if (osabi >= GDB_OSABI_UNKNOWN && osabi < GDB_OSABI_INVALID)
+    return gdb_osabi_names[osabi];
+
+  return "<invalid>";
+}
+
+/* Handler for a given architecture/OS ABI pair.  There should be only
+   one handler for a given OS ABI each architecture family.  */
+struct gdb_osabi_handler  
+{
+  struct gdb_osabi_handler *next;
+  enum bfd_architecture arch;
+  enum gdb_osabi osabi;
+  void (*init_osabi)(struct gdbarch_info, struct gdbarch *);
+};
+
+static struct gdb_osabi_handler *gdb_osabi_handler_list;
+
+void
+gdbarch_register_osabi (enum bfd_architecture arch, enum gdb_osabi osabi,
+                        void (*init_osabi)(struct gdbarch_info,
+					   struct gdbarch *))
+{
+  struct gdb_osabi_handler **handler_p;
+
+  for (handler_p = &gdb_osabi_handler_list; *handler_p != NULL;
+       handler_p = &(*handler_p)->next)
+    {
+      if ((*handler_p)->arch == arch
+	  && (*handler_p)->osabi == osabi)
+	{
+	  internal_error
+	    (__FILE__, __LINE__,
+	     "gdbarch_register_osabi: A handler for this OS ABI variant "
+	     "(%d) has already been registered for this architecture (%d)",
+	     (int) osabi, (int) arch);
+	  /* If user wants to continue, override previous definition.  */
+	  (*handler_p)->init_osabi = init_osabi;
+	  return;
+	}
+    }
+
+  (*handler_p)
+    = (struct gdb_osabi_handler *) xmalloc (sizeof (struct gdb_osabi_handler));
+  (*handler_p)->next = NULL;
+  (*handler_p)->arch = arch;
+  (*handler_p)->osabi = osabi;
+  (*handler_p)->init_osabi = init_osabi;
+}
+
+
+/* Sniffer to find the OS ABI for a given file's architecture and flavour. 
+   It is legal to have multiple sniffers for each arch/flavour pair, to
+   disambiguate one OS's a.out from another, for example.  The first sniffer
+   to return something other than GDB_OSABI_UNKNOWN wins, so a sniffer should
+   be careful to claim a file only if it knows for sure what it is.  */
+struct gdb_osabi_sniffer
+{
+  struct gdb_osabi_sniffer *next;
+  enum bfd_architecture arch;   /* bfd_arch_unknown == wildcard */
+  enum bfd_flavour flavour;
+  enum gdb_osabi (*sniffer)(bfd *);
+};
+
+static struct gdb_osabi_sniffer *gdb_osabi_sniffer_list;
+
+void
+gdbarch_register_osabi_sniffer (enum bfd_architecture arch,
+                                enum bfd_flavour flavour,
+				enum gdb_osabi (*sniffer_fn)(bfd *))
+{
+  struct gdb_osabi_sniffer *sniffer;
+
+  sniffer =
+    (struct gdb_osabi_sniffer *) xmalloc (sizeof (struct gdb_osabi_sniffer));
+  sniffer->arch = arch;
+  sniffer->flavour = flavour;
+
+  sniffer->next = gdb_osabi_sniffer_list;
+  gdb_osabi_sniffer_list = sniffer;
+}
+
+
+enum gdb_osabi
+gdbarch_lookup_osabi (bfd *abfd)
+{
+  struct gdb_osabi_sniffer *sniffer;
+  enum gdb_osabi osabi;
+
+  for (sniffer = gdb_osabi_sniffer_list; sniffer != NULL;
+       sniffer = sniffer->next)
+    {
+      if ((sniffer->arch == bfd_arch_unknown /* wildcard */
+	   || sniffer->arch == abfd->arch_info->arch)
+	  && sniffer->flavour == abfd->xvec->flavour)
+	{
+	  osabi = (*sniffer->sniffer) (abfd);
+	  if (osabi != GDB_OSABI_UNKNOWN)
+	    return osabi;
+	}
+    }
+
+  return GDB_OSABI_UNKNOWN;
+}
+
+int
+gdbarch_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch,
+                    enum gdb_osabi osabi)
+{
+  struct gdb_osabi_handler *handler;
+  bfd *abfd = info.abfd;
+
+  for (handler = gdb_osabi_handler_list; handler != NULL;
+       handler = handler->next)
+    {
+      if (handler->arch == abfd->arch_info->arch
+	  && handler->osabi == osabi)
+	{
+	  (*handler->init_osabi) (info, gdbarch);
+	  return 0;
+	}
+    }
+
+  /* Let the caller decide how much to complain.  */
+  return 1;
+}
+
+
+/* Generic sniffer for ELF flavoured files.  */
+
+static void
+process_note_abi_tag_sections (bfd *abfd, asection *sect, void *obj)
+{
+  enum gdb_osabi *os_ident_ptr = obj;
+  const char *name;
+  unsigned int sectsize;
+
+  name = bfd_get_section_name (abfd, sect);
+  sectsize = bfd_section_size (abfd, sect);
+
+  /* .note.ABI-tag notes, used by GNU/Linux and FreeBSD.  */
+  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);
+
+	  switch (os_number)
+	    {
+	    case GNU_ABI_TAG_LINUX:
+	      *os_ident_ptr = GDB_OSABI_LINUX;
+	      break;
+
+	    case GNU_ABI_TAG_HURD:
+	      *os_ident_ptr = GDB_OSABI_HURD;
+	      break;
+
+	    case GNU_ABI_TAG_SOLARIS:
+	      *os_ident_ptr = GDB_OSABI_SOLARIS;
+	      break;
+
+	    default:
+	      internal_error
+		(__FILE__, __LINE__,
+		 "process_note_abi_sections: unknown OS number %d",
+		 os_number);
+	    }
+	  return;
+	}
+      else if (name_length == 8 && data_length == 4
+	       && note_type == NT_FREEBSD_ABI_TAG
+	       && strcmp (note + 12, "FreeBSD") == 0)
+	{
+	  /* XXX Should we check the version here?  Probably not
+	     necessary yet.  */
+	  *os_ident_ptr = GDB_OSABI_FREEBSD_ELF;
+	}
+      return;
+    }
+
+  /* .note.netbsd.ident notes, used by NetBSD.  */
+  if (strcmp (name, ".note.netbsd.ident") == 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 == 7 && data_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 = GDB_OSABI_NETBSD_ELF;
+	}
+      return;
+    }
+}
+
+static enum gdb_osabi
+generic_elf_osabi_sniffer (bfd *abfd)
+{
+  int elfosabi;
+  enum gdb_osabi osabi = GDB_OSABI_UNKNOWN;
+
+  elfosabi = elf_elfheader (abfd)->e_ident[EI_OSABI];
+
+  switch (elfosabi)
+    {
+    case ELFOSABI_NONE:
+      /* When elfosabi is ELFOSABI_NONE (0), this is supposed to indicate
+	 that we're on a SVR4 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,
+			     &osabi);
+      break;
+
+    case ELFOSABI_FREEBSD:
+      osabi = GDB_OSABI_FREEBSD_ELF;
+      break;
+
+    case ELFOSABI_NETBSD:
+      osabi = GDB_OSABI_NETBSD_ELF;
+      break;
+
+    case ELFOSABI_LINUX:
+      osabi = GDB_OSABI_LINUX;
+      break;
+
+    case ELFOSABI_HURD:
+      osabi = GDB_OSABI_HURD;
+      break;
+
+    case ELFOSABI_SOLARIS:
+      osabi = GDB_OSABI_SOLARIS;
+      break;
+    }
+
+  return osabi;
+}
+
+
+void
+_initialize_gdb_osabi (void)
+{
+  /* Register a generic sniffer for ELF flavoured files.  */
+  gdbarch_register_osabi_sniffer (bfd_arch_unknown,
+				  bfd_target_elf_flavour,
+				  generic_elf_osabi_sniffer);
+}
Index: osabi.h
===================================================================
RCS file: osabi.h
diff -N osabi.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ osabi.h	12 May 2002 04:03:41 -0000
@@ -0,0 +1,72 @@
+/* OS ABI variant handling for GDB.
+   Copyright 2001, 2002 Free Software Foundation, Inc.
+   
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef OSABI_H
+#define OSABI_H
+
+/* List of known OS ABIs.  If you change this, make sure to update the
+   table in osabi.c.  */
+enum gdb_osabi
+{
+  GDB_OSABI_UNKNOWN = 0,	/* keep this first */
+
+  GDB_OSABI_SVR4,
+  GDB_OSABI_HURD,
+  GDB_OSABI_SOLARIS,
+  GDB_OSABI_OSF1,
+  GDB_OSABI_LINUX,
+  GDB_OSABI_FREEBSD_AOUT,
+  GDB_OSABI_FREEBSD_ELF,
+  GDB_OSABI_NETBSD_AOUT,
+  GDB_OSABI_NETBSD_ELF,
+  GDB_OSABI_WINCE,
+
+  GDB_OSABI_ARM_EABI_V1,
+  GDB_OSABI_ARM_EABI_V2,
+  GDB_OSABI_ARM_APCS,
+
+  GDB_OSABI_INVALID		/* keep this last */
+};
+
+/* Register an OS ABI sniffer.  Each arch/flavour may have more than
+   one sniffer.  This is used to e.g. differentiate one OS's a.out from
+   another.  The first sniffer to return something other than
+   GDB_OSABI_UNKNOWN wins, so a sniffer should be careful to claim a file
+   only if it knows for sure what it is.  */
+void gdbarch_register_osabi_sniffer (enum bfd_architecture,
+				     enum bfd_flavour,
+				     enum gdb_osabi (*)(bfd *));
+
+/* Register a handler for an OS ABI variant for a given architecture.  There
+   should be only one handler for a given OS ABI each architecture family.  */
+void gdbarch_register_osabi (enum bfd_architecture, enum gdb_osabi,
+                             void (*)(struct gdbarch_info,
+				      struct gdbarch *));
+
+/* Lookup the OS ABI corresponding to the specified BFD.  */
+enum gdb_osabi gdbarch_lookup_osabi (bfd *);
+
+/* Initialize the gdbarch for the specified OS ABI variant.  */
+int gdbarch_init_osabi (struct gdbarch_info, struct gdbarch *, enum gdb_osabi);
+
+/* Return the name of the specified OS ABI.  */
+const char *gdbarch_osabi_name (enum gdb_osabi);
+
+#endif /* OSABI_H */


More information about the Gdb-patches mailing list