diff options
author | Jason Thorpe <thorpej@netbsd.org> | 2002-05-08 14:54:03 +0000 |
---|---|---|
committer | Jason Thorpe <thorpej@netbsd.org> | 2002-05-08 14:54:03 +0000 |
commit | 8aef6ba894fe3c59144ba6c279c2f962a754b078 (patch) | |
tree | c6e5ec1a6d0d09b85e3aa4c48eaa3f185d0dba02 /gdb/sh-tdep.c | |
parent | dd8ca8a87ddf2752f4e0320effba7687ea6e7139 (diff) | |
download | gdb-8aef6ba894fe3c59144ba6c279c2f962a754b078.tar.gz |
* 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.
Diffstat (limited to 'gdb/sh-tdep.c')
-rw-r--r-- | gdb/sh-tdep.c | 257 |
1 files changed, 253 insertions, 4 deletions
diff --git a/gdb/sh-tdep.c b/gdb/sh-tdep.c index c47a6682eb9..4d6b1133dce 100644 --- a/gdb/sh-tdep.c +++ b/gdb/sh-tdep.c @@ -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 */ + +/* 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"); } |