123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678 |
- /* OS ABI variant handling for GDB.
- Copyright (C) 2001-2022 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
- (__FILE__, __LINE__,
- _("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
- (__FILE__, __LINE__,
- _("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
- (__FILE__, __LINE__,
- _("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
- (__FILE__, __LINE__,
- _("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);
- }
- void
- gdbarch_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch)
- {
- 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))
- {
- (*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;
- char *note;
- 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. */
- note = (char *) alloca (sectsize);
- /* .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 (__FILE__, __LINE__,
- _("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 (__FILE__, __LINE__, _("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
- (__FILE__, __LINE__,
- _("_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);
- }
|