| /* OS ABI variant handling for GDB. | 
 |  | 
 |    Copyright (C) 2001-2023 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 3 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, see <http://www.gnu.org/licenses/>.  */ | 
 |  | 
 | #include "defs.h" | 
 |  | 
 | #include "osabi.h" | 
 | #include "arch-utils.h" | 
 | #include "gdbcmd.h" | 
 | #include "command.h" | 
 | #include "gdb_bfd.h" | 
 |  | 
 | #include "elf-bfd.h" | 
 |  | 
 | #ifndef GDB_OSABI_DEFAULT | 
 | #define GDB_OSABI_DEFAULT GDB_OSABI_UNKNOWN | 
 | #endif | 
 |  | 
 | /* State for the "set osabi" command.  */ | 
 | static enum { osabi_auto, osabi_default, osabi_user } user_osabi_state; | 
 | static enum gdb_osabi user_selected_osabi; | 
 | static const char *gdb_osabi_available_names[GDB_OSABI_INVALID + 3] = { | 
 |   "auto", | 
 |   "default", | 
 |   "none", | 
 |   NULL | 
 | }; | 
 | static const char *set_osabi_string; | 
 |  | 
 | /* Names associated with each osabi.  */ | 
 |  | 
 | struct osabi_names | 
 | { | 
 |   /* The "pretty" name.  */ | 
 |  | 
 |   const char *pretty; | 
 |  | 
 |   /* The triplet regexp, or NULL if not known.  */ | 
 |  | 
 |   const char *regexp; | 
 | }; | 
 |  | 
 | /* This table matches the indices assigned to enum gdb_osabi.  Keep | 
 |    them in sync.  */ | 
 | static const struct osabi_names gdb_osabi_names[] = | 
 | { | 
 |   { "unknown", NULL }, | 
 |   { "none", NULL }, | 
 |  | 
 |   { "SVR4", NULL }, | 
 |   { "GNU/Hurd", NULL }, | 
 |   { "Solaris", NULL }, | 
 |   { "GNU/Linux", "linux(-gnu[^-]*)?" }, | 
 |   { "FreeBSD", NULL }, | 
 |   { "NetBSD", NULL }, | 
 |   { "OpenBSD", NULL }, | 
 |   { "WindowsCE", NULL }, | 
 |   { "DJGPP", NULL }, | 
 |   { "QNX-Neutrino", NULL }, | 
 |   { "Cygwin", NULL }, | 
 |   { "Windows", NULL }, | 
 |   { "AIX", NULL }, | 
 |   { "DICOS", NULL }, | 
 |   { "Darwin", NULL }, | 
 |   { "OpenVMS", NULL }, | 
 |   { "LynxOS178", NULL }, | 
 |   { "Newlib", NULL }, | 
 |   { "SDE", NULL }, | 
 |   { "PikeOS", NULL }, | 
 |  | 
 |   { "<invalid>", NULL } | 
 | }; | 
 |  | 
 | const char * | 
 | gdbarch_osabi_name (enum gdb_osabi osabi) | 
 | { | 
 |   if (osabi >= GDB_OSABI_UNKNOWN && osabi < GDB_OSABI_INVALID) | 
 |     return gdb_osabi_names[osabi].pretty; | 
 |  | 
 |   return gdb_osabi_names[GDB_OSABI_INVALID].pretty; | 
 | } | 
 |  | 
 | /* See osabi.h.  */ | 
 |  | 
 | const char * | 
 | osabi_triplet_regexp (enum gdb_osabi osabi) | 
 | { | 
 |   if (osabi >= GDB_OSABI_UNKNOWN && osabi < GDB_OSABI_INVALID) | 
 |     return gdb_osabi_names[osabi].regexp; | 
 |  | 
 |   return gdb_osabi_names[GDB_OSABI_INVALID].regexp; | 
 | } | 
 |  | 
 | /* Lookup the OS ABI corresponding to the specified target description | 
 |    string.  */ | 
 |  | 
 | enum gdb_osabi | 
 | osabi_from_tdesc_string (const char *name) | 
 | { | 
 |   int i; | 
 |  | 
 |   for (i = 0; i < ARRAY_SIZE (gdb_osabi_names); i++) | 
 |     if (strcmp (name, gdb_osabi_names[i].pretty) == 0) | 
 |       { | 
 | 	/* See note above: the name table matches the indices assigned | 
 | 	   to enum gdb_osabi.  */ | 
 | 	enum gdb_osabi osabi = (enum gdb_osabi) i; | 
 |  | 
 | 	if (osabi == GDB_OSABI_INVALID) | 
 | 	  return GDB_OSABI_UNKNOWN; | 
 | 	else | 
 | 	  return osabi; | 
 |       } | 
 |  | 
 |   return GDB_OSABI_UNKNOWN; | 
 | } | 
 |  | 
 | /* 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; | 
 |   const struct bfd_arch_info *arch_info; | 
 |   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, unsigned long machine, | 
 | 			enum gdb_osabi osabi, | 
 | 			void (*init_osabi)(struct gdbarch_info, | 
 | 					   struct gdbarch *)) | 
 | { | 
 |   struct gdb_osabi_handler **handler_p; | 
 |   const struct bfd_arch_info *arch_info = bfd_lookup_arch (arch, machine); | 
 |   const char **name_ptr; | 
 |  | 
 |   /* Registering an OS ABI handler for "unknown" is not allowed.  */ | 
 |   if (osabi == GDB_OSABI_UNKNOWN) | 
 |     { | 
 |       internal_error | 
 | 	(_("gdbarch_register_osabi: An attempt to register a handler for " | 
 | 	 "OS ABI \"%s\" for architecture %s was made.  The handler will " | 
 | 	 "not be registered"), | 
 | 	 gdbarch_osabi_name (osabi), | 
 | 	 bfd_printable_arch_mach (arch, machine)); | 
 |       return; | 
 |     } | 
 |  | 
 |   gdb_assert (arch_info); | 
 |  | 
 |   for (handler_p = &gdb_osabi_handler_list; *handler_p != NULL; | 
 |        handler_p = &(*handler_p)->next) | 
 |     { | 
 |       if ((*handler_p)->arch_info == arch_info | 
 | 	  && (*handler_p)->osabi == osabi) | 
 | 	{ | 
 | 	  internal_error | 
 | 	    (_("gdbarch_register_osabi: A handler for OS ABI \"%s\" " | 
 | 	     "has already been registered for architecture %s"), | 
 | 	     gdbarch_osabi_name (osabi), | 
 | 	     arch_info->printable_name); | 
 | 	  /* If user wants to continue, override previous definition.  */ | 
 | 	  (*handler_p)->init_osabi = init_osabi; | 
 | 	  return; | 
 | 	} | 
 |     } | 
 |  | 
 |   (*handler_p) = XNEW (struct gdb_osabi_handler); | 
 |   (*handler_p)->next = NULL; | 
 |   (*handler_p)->arch_info = arch_info; | 
 |   (*handler_p)->osabi = osabi; | 
 |   (*handler_p)->init_osabi = init_osabi; | 
 |  | 
 |   /* Add this OS ABI to the list of enum values for "set osabi", if it isn't | 
 |      already there.  */ | 
 |   for (name_ptr = gdb_osabi_available_names; *name_ptr; name_ptr ++) | 
 |     { | 
 |       if (*name_ptr == gdbarch_osabi_name (osabi)) | 
 | 	return; | 
 |     } | 
 |   *name_ptr++ = gdbarch_osabi_name (osabi); | 
 |   *name_ptr = NULL; | 
 | } | 
 |  | 
 |  | 
 | /* 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 = XNEW (struct gdb_osabi_sniffer); | 
 |   sniffer->arch = arch; | 
 |   sniffer->flavour = flavour; | 
 |   sniffer->sniffer = sniffer_fn; | 
 |  | 
 |   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, match; | 
 |   int match_specific; | 
 |  | 
 |   /* If we aren't in "auto" mode, return the specified OS ABI.  */ | 
 |   if (user_osabi_state == osabi_user) | 
 |     return user_selected_osabi; | 
 |  | 
 |   /* If we don't have a binary, just return unknown.  The caller may | 
 |      have other sources the OSABI can be extracted from, e.g., the | 
 |      target description.  */ | 
 |   if (abfd == NULL) | 
 |     return GDB_OSABI_UNKNOWN; | 
 |  | 
 |   match = GDB_OSABI_UNKNOWN; | 
 |   match_specific = 0; | 
 |  | 
 |   for (sniffer = gdb_osabi_sniffer_list; sniffer != NULL; | 
 |        sniffer = sniffer->next) | 
 |     { | 
 |       if ((sniffer->arch == bfd_arch_unknown /* wildcard */ | 
 | 	   || sniffer->arch == bfd_get_arch (abfd)) | 
 | 	  && sniffer->flavour == bfd_get_flavour (abfd)) | 
 | 	{ | 
 | 	  osabi = (*sniffer->sniffer) (abfd); | 
 | 	  if (osabi < GDB_OSABI_UNKNOWN || osabi >= GDB_OSABI_INVALID) | 
 | 	    { | 
 | 	      internal_error | 
 | 		(_("gdbarch_lookup_osabi: invalid OS ABI (%d) from sniffer " | 
 | 		 "for architecture %s flavour %d"), | 
 | 		 (int) osabi, | 
 | 		 bfd_printable_arch_mach (bfd_get_arch (abfd), 0), | 
 | 		 (int) bfd_get_flavour (abfd)); | 
 | 	    } | 
 | 	  else if (osabi != GDB_OSABI_UNKNOWN) | 
 | 	    { | 
 | 	      /* A specific sniffer always overrides a generic sniffer. | 
 | 		 Croak on multiple match if the two matches are of the | 
 | 		 same class.  If the user wishes to continue, we'll use | 
 | 		 the first match.  */ | 
 | 	      if (match != GDB_OSABI_UNKNOWN) | 
 | 		{ | 
 | 		  if ((match_specific && sniffer->arch != bfd_arch_unknown) | 
 | 		   || (!match_specific && sniffer->arch == bfd_arch_unknown)) | 
 | 		    { | 
 | 		      internal_error | 
 | 			(_("gdbarch_lookup_osabi: multiple %sspecific OS ABI " | 
 | 			 "match for architecture %s flavour %d: first " | 
 | 			 "match \"%s\", second match \"%s\""), | 
 | 			 match_specific ? "" : "non-", | 
 | 			 bfd_printable_arch_mach (bfd_get_arch (abfd), 0), | 
 | 			 (int) bfd_get_flavour (abfd), | 
 | 			 gdbarch_osabi_name (match), | 
 | 			 gdbarch_osabi_name (osabi)); | 
 | 		    } | 
 | 		  else if (sniffer->arch != bfd_arch_unknown) | 
 | 		    { | 
 | 		      match = osabi; | 
 | 		      match_specific = 1; | 
 | 		    } | 
 | 		} | 
 | 	      else | 
 | 		{ | 
 | 		  match = osabi; | 
 | 		  if (sniffer->arch != bfd_arch_unknown) | 
 | 		    match_specific = 1; | 
 | 		} | 
 | 	    } | 
 | 	} | 
 |     } | 
 |  | 
 |   return match; | 
 | } | 
 |  | 
 |  | 
 | /* Return non-zero if architecture A can run code written for | 
 |    architecture B.  */ | 
 | static int | 
 | can_run_code_for (const struct bfd_arch_info *a, const struct bfd_arch_info *b) | 
 | { | 
 |   /* BFD's 'A->compatible (A, B)' functions return zero if A and B are | 
 |      incompatible.  But if they are compatible, it returns the 'more | 
 |      featureful' of the two arches.  That is, if A can run code | 
 |      written for B, but B can't run code written for A, then it'll | 
 |      return A. | 
 |  | 
 |      struct bfd_arch_info objects are singletons: that is, there's | 
 |      supposed to be exactly one instance for a given machine.  So you | 
 |      can tell whether two are equivalent by comparing pointers.  */ | 
 |   return (a == b || a->compatible (a, b) == a); | 
 | } | 
 |  | 
 | /* Return OS ABI handler for INFO.  */ | 
 |  | 
 | static struct gdb_osabi_handler * | 
 | gdbarch_osabi_handler (struct gdbarch_info info) | 
 | { | 
 |   struct gdb_osabi_handler *handler; | 
 |  | 
 |   gdb_assert (info.osabi != GDB_OSABI_UNKNOWN); | 
 |  | 
 |   for (handler = gdb_osabi_handler_list; handler != NULL; | 
 |        handler = handler->next) | 
 |     { | 
 |       if (handler->osabi != info.osabi) | 
 | 	continue; | 
 |  | 
 |       /* If the architecture described by ARCH_INFO can run code for | 
 | 	 the architecture we registered the handler for, then the | 
 | 	 handler is applicable.  Note, though, that if the handler is | 
 | 	 for an architecture that is a superset of ARCH_INFO, we can't | 
 | 	 use that --- it would be perfectly correct for it to install | 
 | 	 gdbarch methods that refer to registers / instructions / | 
 | 	 other facilities ARCH_INFO doesn't have. | 
 |  | 
 | 	 NOTE: kettenis/20021027: There may be more than one machine | 
 | 	 type that is compatible with the desired machine type.  Right | 
 | 	 now we simply return the first match, which is fine for now. | 
 | 	 However, we might want to do something smarter in the future.  */ | 
 |       /* NOTE: cagney/2003-10-23: The code for "a can_run_code_for b" | 
 | 	 is implemented using BFD's compatible method (a->compatible | 
 | 	 (b) == a -- the lowest common denominator between a and b is | 
 | 	 a).  That method's definition of compatible may not be as you | 
 | 	 expect.  For instance the test "amd64 can run code for i386" | 
 | 	 (or more generally "64-bit ISA can run code for the 32-bit | 
 | 	 ISA").  BFD doesn't normally consider 32-bit and 64-bit | 
 | 	 "compatible" so it doesn't succeed.  */ | 
 |       if (can_run_code_for (info.bfd_arch_info, handler->arch_info)) | 
 | 	return handler; | 
 |     } | 
 |  | 
 |   return nullptr; | 
 | } | 
 |  | 
 | /* See osabi.h.  */ | 
 |  | 
 | bool | 
 | has_gdb_osabi_handler (struct gdbarch_info info) | 
 | { | 
 |   return gdbarch_osabi_handler (info) != nullptr; | 
 | } | 
 |  | 
 | void | 
 | gdbarch_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch) | 
 | { | 
 |   struct gdb_osabi_handler *handler; | 
 |  | 
 |   gdb_assert (info.osabi != GDB_OSABI_UNKNOWN); | 
 |   handler = gdbarch_osabi_handler (info); | 
 |  | 
 |   if (handler != nullptr) | 
 |     { | 
 |       (*handler->init_osabi) (info, gdbarch); | 
 |       return; | 
 |     } | 
 |  | 
 |   if (info.osabi == GDB_OSABI_NONE) | 
 |     { | 
 |       /* Don't complain about no OSABI.  Assume the user knows | 
 | 	 what they are doing.  */ | 
 |       return; | 
 |     } | 
 |  | 
 |   warning | 
 |     ("A handler for the OS ABI \"%s\" is not built into this configuration\n" | 
 |      "of GDB.  Attempting to continue with the default %s settings.\n", | 
 |      gdbarch_osabi_name (info.osabi), | 
 |      info.bfd_arch_info->printable_name); | 
 | } | 
 |  | 
 | /* Limit on the amount of data to be read.  */ | 
 | #define MAX_NOTESZ	128 | 
 |  | 
 | /* Return non-zero if NOTE matches NAME, DESCSZ and TYPE.  If | 
 |    *SECTSIZE is non-zero, then this reads that many bytes from | 
 |    the start of the section and clears *SECTSIZE.  */ | 
 |  | 
 | static int | 
 | check_note (bfd *abfd, asection *sect, char *note, unsigned int *sectsize, | 
 | 	    const char *name, unsigned long descsz, unsigned long type) | 
 | { | 
 |   unsigned long notesz; | 
 |  | 
 |   if (*sectsize) | 
 |     { | 
 |       if (!bfd_get_section_contents (abfd, sect, note, 0, *sectsize)) | 
 | 	return 0; | 
 |       *sectsize = 0; | 
 |     } | 
 |  | 
 |   /* Calculate the size of this note.  */ | 
 |   notesz = strlen (name) + 1; | 
 |   notesz = ((notesz + 3) & ~3); | 
 |   notesz += descsz; | 
 |   notesz = ((notesz + 3) & ~3); | 
 |  | 
 |   /* If this assertion triggers, increase MAX_NOTESZ.  */ | 
 |   gdb_assert (notesz <= MAX_NOTESZ); | 
 |  | 
 |   /* Check whether SECT is big enough to contain the complete note.  */ | 
 |   if (notesz > bfd_section_size (sect)) | 
 |     return 0; | 
 |  | 
 |   /* Check the note name.  */ | 
 |   if (bfd_h_get_32 (abfd, note) != (strlen (name) + 1) | 
 |       || strcmp (note + 12, name) != 0) | 
 |     return 0; | 
 |  | 
 |   /* Check the descriptor size.  */ | 
 |   if (bfd_h_get_32 (abfd, note + 4) != descsz) | 
 |     return 0; | 
 |  | 
 |   /* Check the note type.  */ | 
 |   if (bfd_h_get_32 (abfd, note + 8) != type) | 
 |     return 0; | 
 |  | 
 |   return 1; | 
 | } | 
 |  | 
 | /* Generic sniffer for ELF flavoured files.  */ | 
 |  | 
 | void | 
 | generic_elf_osabi_sniff_abi_tag_sections (bfd *abfd, asection *sect, | 
 | 					  enum gdb_osabi *osabi) | 
 | { | 
 |   const char *name; | 
 |   unsigned int sectsize; | 
 |  | 
 |   name = bfd_section_name (sect); | 
 |   sectsize = bfd_section_size (sect); | 
 |  | 
 |   /* Limit the amount of data to read.  */ | 
 |   if (sectsize > MAX_NOTESZ) | 
 |     sectsize = MAX_NOTESZ; | 
 |  | 
 |   /* We lazily read the section data here.  Since we use | 
 |      BFD_DECOMPRESS, we can't use bfd_get_section_contents on a | 
 |      compressed section.  But, since note sections are not compressed, | 
 |      deferring the reading until we recognize the section avoids any | 
 |      error.  */ | 
 |   char note[MAX_NOTESZ]; | 
 |  | 
 |   /* .note.ABI-tag notes, used by GNU/Linux and FreeBSD.  */ | 
 |   if (strcmp (name, ".note.ABI-tag") == 0) | 
 |     { | 
 |       /* GNU.  */ | 
 |       if (check_note (abfd, sect, note, §size, "GNU", 16, NT_GNU_ABI_TAG)) | 
 | 	{ | 
 | 	  unsigned int abi_tag = bfd_h_get_32 (abfd, note + 16); | 
 |  | 
 | 	  switch (abi_tag) | 
 | 	    { | 
 | 	    case GNU_ABI_TAG_LINUX: | 
 | 	      *osabi = GDB_OSABI_LINUX; | 
 | 	      break; | 
 |  | 
 | 	    case GNU_ABI_TAG_HURD: | 
 | 	      *osabi = GDB_OSABI_HURD; | 
 | 	      break; | 
 |  | 
 | 	    case GNU_ABI_TAG_SOLARIS: | 
 | 	      *osabi = GDB_OSABI_SOLARIS; | 
 | 	      break; | 
 |  | 
 | 	    case GNU_ABI_TAG_FREEBSD: | 
 | 	      *osabi = GDB_OSABI_FREEBSD; | 
 | 	      break; | 
 |  | 
 | 	    case GNU_ABI_TAG_NETBSD: | 
 | 	      *osabi = GDB_OSABI_NETBSD; | 
 | 	      break; | 
 |  | 
 | 	    default: | 
 | 	      warning (_("GNU ABI tag value %u unrecognized."), abi_tag); | 
 | 	      break; | 
 | 	    } | 
 | 	  return; | 
 | 	} | 
 |  | 
 |       /* FreeBSD.  */ | 
 |       if (check_note (abfd, sect, note, §size, "FreeBSD", 4, | 
 | 		      NT_FREEBSD_ABI_TAG)) | 
 | 	{ | 
 | 	  /* There is no need to check the version yet.  */ | 
 | 	  *osabi = GDB_OSABI_FREEBSD; | 
 | 	  return; | 
 | 	} | 
 |  | 
 |       return; | 
 |     } | 
 |  | 
 |   /* .note.netbsd.ident notes, used by NetBSD.  */ | 
 |   if (strcmp (name, ".note.netbsd.ident") == 0 | 
 |       && check_note (abfd, sect, note, §size, "NetBSD", 4, NT_NETBSD_IDENT)) | 
 |     { | 
 |       /* There is no need to check the version yet.  */ | 
 |       *osabi = GDB_OSABI_NETBSD; | 
 |       return; | 
 |     } | 
 |  | 
 |   /* .note.openbsd.ident notes, used by OpenBSD.  */ | 
 |   if (strcmp (name, ".note.openbsd.ident") == 0 | 
 |       && check_note (abfd, sect, note, §size, "OpenBSD", 4, | 
 | 		     NT_OPENBSD_IDENT)) | 
 |     { | 
 |       /* There is no need to check the version yet.  */ | 
 |       *osabi = GDB_OSABI_OPENBSD; | 
 |       return; | 
 |     } | 
 |  | 
 |   /* .note.netbsdcore.procinfo notes, used by NetBSD.  */ | 
 |   if (strcmp (name, ".note.netbsdcore.procinfo") == 0) | 
 |     { | 
 |       *osabi = GDB_OSABI_NETBSD; | 
 |       return; | 
 |     } | 
 | } | 
 |  | 
 | static enum gdb_osabi | 
 | generic_elf_osabi_sniffer (bfd *abfd) | 
 | { | 
 |   unsigned int elfosabi; | 
 |   enum gdb_osabi osabi = GDB_OSABI_UNKNOWN; | 
 |  | 
 |   elfosabi = elf_elfheader (abfd)->e_ident[EI_OSABI]; | 
 |  | 
 |   switch (elfosabi) | 
 |     { | 
 |     case ELFOSABI_NONE: | 
 |     case ELFOSABI_GNU: | 
 |     case ELFOSABI_HPUX: | 
 |       /* When the EI_OSABI field in the ELF header is ELFOSABI_NONE | 
 | 	 (0), then the ELF structures in the file are conforming to | 
 | 	 the base specification for that machine (there are no | 
 | 	 OS-specific extensions).  In order to determine the real OS | 
 | 	 in use, we must look for OS-specific notes. | 
 |  | 
 | 	 The same applies for ELFOSABI_GNU: this can mean GNU/Hurd, | 
 | 	 GNU/Linux, and possibly more.  */ | 
 |  | 
 |       /* And likewise ELFOSABI_HPUX.  For some reason the default | 
 | 	 value for the EI_OSABI field is ELFOSABI_HPUX for all PA-RISC | 
 | 	 targets (with the exception of GNU/Linux).  */ | 
 |       for (asection *sect : gdb_bfd_sections (abfd)) | 
 | 	generic_elf_osabi_sniff_abi_tag_sections (abfd, sect, &osabi); | 
 |       break; | 
 |  | 
 |     case ELFOSABI_FREEBSD: | 
 |       osabi = GDB_OSABI_FREEBSD; | 
 |       break; | 
 |  | 
 |     case ELFOSABI_NETBSD: | 
 |       osabi = GDB_OSABI_NETBSD; | 
 |       break; | 
 |  | 
 |     case ELFOSABI_SOLARIS: | 
 |       osabi = GDB_OSABI_SOLARIS; | 
 |       break; | 
 |  | 
 |     case ELFOSABI_OPENVMS: | 
 |       osabi = GDB_OSABI_OPENVMS; | 
 |       break; | 
 |     } | 
 |  | 
 |   if (osabi == GDB_OSABI_UNKNOWN) | 
 |     { | 
 |       /* The FreeBSD folks have been naughty; they stored the string | 
 | 	 "FreeBSD" in the padding of the e_ident field of the ELF | 
 | 	 header to "brand" their ELF binaries in FreeBSD 3.x.  */ | 
 |       if (memcmp (&elf_elfheader (abfd)->e_ident[8], | 
 | 		  "FreeBSD", sizeof ("FreeBSD")) == 0) | 
 | 	osabi = GDB_OSABI_FREEBSD; | 
 |     } | 
 |  | 
 |   return osabi; | 
 | } | 
 |  | 
 | static void | 
 | set_osabi (const char *args, int from_tty, struct cmd_list_element *c) | 
 | { | 
 |   if (strcmp (set_osabi_string, "auto") == 0) | 
 |     user_osabi_state = osabi_auto; | 
 |   else if (strcmp (set_osabi_string, "default") == 0) | 
 |     { | 
 |       user_selected_osabi = GDB_OSABI_DEFAULT; | 
 |       user_osabi_state = osabi_user; | 
 |     } | 
 |   else | 
 |     { | 
 |       int i; | 
 |  | 
 |       for (i = 1; i < GDB_OSABI_INVALID; i++) | 
 | 	{ | 
 | 	  enum gdb_osabi osabi = (enum gdb_osabi) i; | 
 |  | 
 | 	  if (strcmp (set_osabi_string, gdbarch_osabi_name (osabi)) == 0) | 
 | 	    { | 
 | 	      user_selected_osabi = osabi; | 
 | 	      user_osabi_state = osabi_user; | 
 | 	      break; | 
 | 	    } | 
 | 	} | 
 |       if (i == GDB_OSABI_INVALID) | 
 | 	internal_error (_("Invalid OS ABI \"%s\" passed to command handler."), | 
 | 			set_osabi_string); | 
 |     } | 
 |  | 
 |   /* NOTE: At some point (true multiple architectures) we'll need to be more | 
 |      graceful here.  */ | 
 |   gdbarch_info info; | 
 |   if (! gdbarch_update_p (info)) | 
 |     internal_error (_("Updating OS ABI failed.")); | 
 | } | 
 |  | 
 | static void | 
 | show_osabi (struct ui_file *file, int from_tty, struct cmd_list_element *c, | 
 | 	    const char *value) | 
 | { | 
 |   if (user_osabi_state == osabi_auto) | 
 |     gdb_printf (file, | 
 | 		_("The current OS ABI is \"auto\" " | 
 | 		  "(currently \"%s\").\n"), | 
 | 		gdbarch_osabi_name (gdbarch_osabi (get_current_arch ()))); | 
 |   else | 
 |     gdb_printf (file, _("The current OS ABI is \"%s\".\n"), | 
 | 		gdbarch_osabi_name (user_selected_osabi)); | 
 |  | 
 |   if (GDB_OSABI_DEFAULT != GDB_OSABI_UNKNOWN) | 
 |     gdb_printf (file, _("The default OS ABI is \"%s\".\n"), | 
 | 		gdbarch_osabi_name (GDB_OSABI_DEFAULT)); | 
 | } | 
 |  | 
 | void _initialize_gdb_osabi (); | 
 | void | 
 | _initialize_gdb_osabi () | 
 | { | 
 |   if (strcmp (gdb_osabi_names[GDB_OSABI_INVALID].pretty, "<invalid>") != 0) | 
 |     internal_error | 
 |       (_("_initialize_gdb_osabi: gdb_osabi_names[] is inconsistent")); | 
 |  | 
 |   /* Register a generic sniffer for ELF flavoured files.  */ | 
 |   gdbarch_register_osabi_sniffer (bfd_arch_unknown, | 
 | 				  bfd_target_elf_flavour, | 
 | 				  generic_elf_osabi_sniffer); | 
 |  | 
 |   /* Register the "set osabi" command.  */ | 
 |   user_osabi_state = osabi_auto; | 
 |   set_osabi_string = gdb_osabi_available_names[0]; | 
 |   gdb_assert (strcmp (set_osabi_string, "auto") == 0); | 
 |   add_setshow_enum_cmd ("osabi", class_support, gdb_osabi_available_names, | 
 | 			&set_osabi_string, | 
 | 			_("Set OS ABI of target."), | 
 | 			_("Show OS ABI of target."), | 
 | 			NULL, set_osabi, show_osabi, | 
 | 			&setlist, &showlist); | 
 | } |