diff options
-rw-r--r-- | gdb/ChangeLog | 15 | ||||
-rw-r--r-- | gdb/Makefile.in | 2 | ||||
-rw-r--r-- | gdb/sparc-tdep.c | 300 | ||||
-rw-r--r-- | gdb/sparc-tdep.h | 99 |
4 files changed, 338 insertions, 78 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 48cb638..4b65576 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -12,6 +12,21 @@ * sparc-tdep.c (sparc_prologue_frameless_p): Implement. (sparc_gdbarch_init): Pass it to set_gdbarch_prologue_frameless_p. + + * sparc-tdep.h: New file. + * sparc-tdep.c (elf-bfd.h): Include. + (SPARC_HAS_FPU, FP_REGISTER_BYTES, FP_MAX_REGNUM, + SPARC_INTREG_SIZE, DUMMY_REG_SAVE_OFFSET, gdbarch_tdep, + CALL_DUMMY_CALL_OFFSET): Move out to sparc-tdep.h + (sparc_dump_tdep): New function. + (_initialize_sparc_tdep): Use gdbarch_register instead of + register_gdbarch_init which is deprecated. + (process_note_abi_tag_sections, sparc_abi_handler, + sparc_abi_handler_list, sparc_gdbarch_register_os_abi): New. + (sparc_gdbarch_init): Determine elf os ident key based upon + either the elf header or by using process_note_abi_tag_sections. + Fix 'gdbarch already exists' test by comparing os_ident as well. + As the last action, invoke OS abi_handler if installed. 2002-04-21 Jason Thorpe <thorpej@wasabisystems.com> diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 4eb39d6..43e8191 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -2062,7 +2062,7 @@ sparc-nat.o: sparc-nat.c $(bfd_h) $(defs_h) $(inferior_h) $(gdbcore_h) \ sparc-tdep.o: sparc-tdep.c $(floatformat_h) $(defs_h) $(gdbcore_h) \ $(inferior_h) $(objfiles_h) $(symfile_h) $(target_h) $(gdb_string_h) \ - $(arch_utils_h) $(regcache_h) + $(arch_utils_h) $(regcache_h) $(BFD_SRC)/elf-bfd.h sparc-tdep.h sparcl-tdep.o: sparcl-tdep.c $(defs_h) $(gdbcore_h) $(target_h) $(regcache_h) diff --git a/gdb/sparc-tdep.c b/gdb/sparc-tdep.c index 274daa6..8e0b998 100644 --- a/gdb/sparc-tdep.c +++ b/gdb/sparc-tdep.c @@ -34,6 +34,8 @@ #include "gdb_string.h" #include "regcache.h" +#include "elf-bfd.h" + #ifdef USE_PROC_FS #include <sys/procfs.h> /* Prototypes for supply_gregset etc. */ @@ -44,74 +46,7 @@ #include "symfile.h" /* for 'entry_point_address' */ -/* - * Some local macros that have multi-arch and non-multi-arch versions: - */ - -#if (GDB_MULTI_ARCH > 0) - -/* Does the target have Floating Point registers? */ -#define SPARC_HAS_FPU (gdbarch_tdep (current_gdbarch)->has_fpu) -/* Number of bytes devoted to Floating Point registers: */ -#define FP_REGISTER_BYTES (gdbarch_tdep (current_gdbarch)->fp_register_bytes) -/* Highest numbered Floating Point register. */ -#define FP_MAX_REGNUM (gdbarch_tdep (current_gdbarch)->fp_max_regnum) -/* Size of a general (integer) register: */ -#define SPARC_INTREG_SIZE (gdbarch_tdep (current_gdbarch)->intreg_size) -/* Offset within the call dummy stack of the saved registers. */ -#define DUMMY_REG_SAVE_OFFSET (gdbarch_tdep (current_gdbarch)->reg_save_offset) - -#else /* non-multi-arch */ - - -/* Does the target have Floating Point registers? */ -#if defined(TARGET_SPARCLET) || defined(TARGET_SPARCLITE) -#define SPARC_HAS_FPU 0 -#else -#define SPARC_HAS_FPU 1 -#endif - -/* Number of bytes devoted to Floating Point registers: */ -#if (GDB_TARGET_IS_SPARC64) -#define FP_REGISTER_BYTES (64 * 4) -#else -#if (SPARC_HAS_FPU) -#define FP_REGISTER_BYTES (32 * 4) -#else -#define FP_REGISTER_BYTES 0 -#endif -#endif - -/* Highest numbered Floating Point register. */ -#if (GDB_TARGET_IS_SPARC64) -#define FP_MAX_REGNUM (FP0_REGNUM + 48) -#else -#define FP_MAX_REGNUM (FP0_REGNUM + 32) -#endif - -/* Size of a general (integer) register: */ -#define SPARC_INTREG_SIZE (REGISTER_RAW_SIZE (G0_REGNUM)) - -/* Offset within the call dummy stack of the saved registers. */ -#if (GDB_TARGET_IS_SPARC64) -#define DUMMY_REG_SAVE_OFFSET (128 + 16) -#else -#define DUMMY_REG_SAVE_OFFSET 0x60 -#endif - -#endif /* GDB_MULTI_ARCH */ - -struct gdbarch_tdep - { - int has_fpu; - int fp_register_bytes; - int y_regnum; - int fp_max_regnum; - int intreg_size; - int reg_save_offset; - int call_dummy_call_offset; - int print_insn_mach; - }; +#include "sparc-tdep.h" /* Now make GDB_TARGET_IS_SPARC64 a runtime test. */ /* FIXME MVS: or try testing bfd_arch_info.arch and bfd_arch_info.mach ... @@ -2140,11 +2075,6 @@ sparclet_store_return_value (struct type *type, char *valbuf) } -#ifndef CALL_DUMMY_CALL_OFFSET -#define CALL_DUMMY_CALL_OFFSET \ - (gdbarch_tdep (current_gdbarch)->call_dummy_call_offset) -#endif /* CALL_DUMMY_CALL_OFFSET */ - /* Insert the function address into a call dummy instruction sequence stored at DUMMY. @@ -2245,11 +2175,13 @@ sparc_target_architecture_hook (const bfd_arch_info_type *ap) static struct gdbarch * sparc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches); +static void sparc_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file); + void _initialize_sparc_tdep (void) { /* Hook us into the gdbarch mechanism. */ - register_gdbarch_init (bfd_arch_sparc, sparc_gdbarch_init); + gdbarch_register (bfd_arch_sparc, sparc_gdbarch_init, sparc_dump_tdep); tm_print_insn = gdb_print_insn_sparc; tm_print_insn_info.mach = TM_PRINT_INSN_MACH; /* Selects sparc/sparclite */ @@ -2890,6 +2822,92 @@ sparc_return_value_on_stack (struct type *type) return 0; } + +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 sparc_abi_handler +{ + struct sparc_abi_handler *next; + int os_ident; + void (*init_abi)(struct gdbarch_info, struct gdbarch *); +}; + +struct sparc_abi_handler *sparc_abi_handler_list = NULL; + +void +sparc_gdbarch_register_os_abi (int os_ident, + void (*init_abi)(struct gdbarch_info, + struct gdbarch *)) +{ + struct sparc_abi_handler *p; + + for (p = sparc_abi_handler_list; p != NULL; p = p->next) + { + if (p->os_ident == os_ident) + { + internal_error + (__FILE__, __LINE__, + "sparc_gdbarch_register_os_abi: A handler for this ABI variant (%d)" + " has already been registered", (int)os_ident); + /* If user wants to continue, override previous definition. */ + p->init_abi = init_abi; + return; + } + } + + p = (struct sparc_abi_handler *) xmalloc (sizeof (*p)); + p->os_ident = os_ident; + p->init_abi = init_abi; + p->next = sparc_abi_handler_list; + sparc_abi_handler_list = p; +} + /* * Gdbarch "constructor" function. */ @@ -2911,6 +2929,8 @@ sparc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) { struct gdbarch *gdbarch; struct gdbarch_tdep *tdep; + struct sparc_abi_handler *abi_handler; + int os_ident; static LONGEST call_dummy_32[] = { 0xbc100001, 0x9de38000, 0xbc100002, 0xbe100003, @@ -2934,10 +2954,33 @@ sparc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) }; static LONGEST call_dummy_nil[] = {0}; + 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); + } + else + os_ident = -1; + /* First see if there is already a gdbarch that can satisfy the request. */ - 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)) + { + tdep = gdbarch_tdep (arches->gdbarch); + if (tdep && tdep->os_ident == os_ident) + return arches->gdbarch; + } /* None found: is the request for a sparc architecture? */ if (info.bfd_arch_info->arch != bfd_arch_sparc) @@ -2947,6 +2990,8 @@ sparc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) tdep = (struct gdbarch_tdep *) xmalloc (sizeof (struct gdbarch_tdep)); gdbarch = gdbarch_alloc (&info, tdep); + tdep->os_ident = os_ident; + /* First set settings that are common for all sparc architectures. */ set_gdbarch_believe_pcc_promotion (gdbarch, 1); set_gdbarch_breakpoint_from_pc (gdbarch, memory_breakpoint_from_pc); @@ -3218,6 +3263,107 @@ sparc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) break; } + for (abi_handler = sparc_abi_handler_list; + abi_handler; + abi_handler = abi_handler->next) + if (abi_handler->os_ident == os_ident) + break; + + if (abi_handler) + abi_handler->init_abi (info, gdbarch); + return gdbarch; } +static void +sparc_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); + + if (tdep == NULL) + return; + + fprintf_unfiltered (file, "sparc_dump_tdep: os_ident "); + switch (tdep->os_ident) + { + case ELFOSABI_NONE: + fprintf_unfiltered (file, "ELFOSABI_NONE"); + break; + case ELFOSABI_NETBSD: + fprintf_unfiltered (file, "ELFOSABI_NETBSD"); + break; + case ELFOSABI_LINUX: + fprintf_unfiltered (file, "ELFOSABI_LINUX"); + break; + case ELFOSABI_HURD: + fprintf_unfiltered (file, "ELFOSABI_HURD"); + break; + case ELFOSABI_SOLARIS: + fprintf_unfiltered (file, "ELFOSABI_SOLARIS"); + break; + case ELFOSABI_FREEBSD: + fprintf_unfiltered (file, "ELFOSABI_FREEBSD"); + break; + case ELFOSABI_OPENBSD: + fprintf_unfiltered (file, "ELFOSABI_OPENBSD"); + break; + case ELFOSABI_STANDALONE: + fprintf_unfiltered (file, "ELFOSABI_STANDALONE"); + break; + default: + fprintf_unfiltered (file, "UNKNOWN"); + break; + } + + fprintf_unfiltered (file, "sparc_dump_tdep: has_fpu %d\n", + tdep->has_fpu); + fprintf_unfiltered (file, "sparc_dump_tdep: fp_register_bytes %d\n", + tdep->fp_register_bytes); + fprintf_unfiltered (file, "sparc_dump_tdep: y_regnum %d\n", + tdep->y_regnum); + fprintf_unfiltered (file, "sparc_dump_tdep: fp_max_regnum %d\n", + tdep->fp_max_regnum); + fprintf_unfiltered (file, "sparc_dump_tdep: intreg_size %d\n", + tdep->intreg_size); + fprintf_unfiltered (file, "sparc_dump_tdep: reg_save_offset %d\n", + tdep->reg_save_offset); + fprintf_unfiltered (file, "sparc_dump_tdep: call_dummy_call_offset %d\n", + tdep->call_dummy_call_offset); + fprintf_unfiltered (file, "sparc_dump_tdep: print_insn_mach "); + switch (tdep->print_insn_mach) + { + case bfd_mach_sparc: + fprintf_unfiltered (file, "bfd_mach_sparc\n"); + break; + case bfd_mach_sparc_sparclet: + fprintf_unfiltered (file, "bfd_mach_sparc_sparclet\n"); + break; + case bfd_mach_sparc_sparclite: + fprintf_unfiltered (file, "bfd_mach_sparc_sparclite\n"); + break; + case bfd_mach_sparc_sparclite_le: + fprintf_unfiltered (file, "bfd_mach_sparc_sparclite_le\n"); + break; + case bfd_mach_sparc_v8plus: + fprintf_unfiltered (file, "bfd_mach_sparc_v8plus\n"); + break; + case bfd_mach_sparc_v8plusa: + fprintf_unfiltered (file, "bfd_mach_sparc_v8plusa\n"); + break; + case bfd_mach_sparc_v8plusb: + fprintf_unfiltered (file, "bfd_mach_sparc_v8plusb\n"); + break; + case bfd_mach_sparc_v9: + fprintf_unfiltered (file, "bfd_mach_sparc_v9\n"); + break; + case bfd_mach_sparc_v9a: + fprintf_unfiltered (file, "bfd_mach_sparc_v9a\n"); + break; + case bfd_mach_sparc_v9b: + fprintf_unfiltered (file, "bfd_mach_sparc_v9b\n"); + break; + default: + fprintf_unfiltered (file, "UNKNOWN\n"); + break; + }; +} diff --git a/gdb/sparc-tdep.h b/gdb/sparc-tdep.h new file mode 100644 index 0000000..88f6ee6 --- /dev/null +++ b/gdb/sparc-tdep.h @@ -0,0 +1,99 @@ +/* Common target dependent code for GDB on SPARC systems. + Copyright 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. */ + +/* + * Some local macros that have multi-arch and non-multi-arch versions: + */ + +#if (GDB_MULTI_ARCH > 0) + +/* Does the target have Floating Point registers? */ +#define SPARC_HAS_FPU (gdbarch_tdep (current_gdbarch)->has_fpu) +/* Number of bytes devoted to Floating Point registers: */ +#define FP_REGISTER_BYTES (gdbarch_tdep (current_gdbarch)->fp_register_bytes) +/* Highest numbered Floating Point register. */ +#define FP_MAX_REGNUM (gdbarch_tdep (current_gdbarch)->fp_max_regnum) +/* Size of a general (integer) register: */ +#define SPARC_INTREG_SIZE (gdbarch_tdep (current_gdbarch)->intreg_size) +/* Offset within the call dummy stack of the saved registers. */ +#define DUMMY_REG_SAVE_OFFSET (gdbarch_tdep (current_gdbarch)->reg_save_offset) + +#else /* non-multi-arch */ + +/* Does the target have Floating Point registers? */ +#if defined(TARGET_SPARCLET) || defined(TARGET_SPARCLITE) +#define SPARC_HAS_FPU 0 +#else +#define SPARC_HAS_FPU 1 +#endif + +/* Number of bytes devoted to Floating Point registers: */ +#if (GDB_TARGET_IS_SPARC64) +#define FP_REGISTER_BYTES (64 * 4) +#else +#if (SPARC_HAS_FPU) +#define FP_REGISTER_BYTES (32 * 4) +#else +#define FP_REGISTER_BYTES 0 +#endif +#endif + +/* Highest numbered Floating Point register. */ +#if (GDB_TARGET_IS_SPARC64) +#define FP_MAX_REGNUM (FP0_REGNUM + 48) +#else +#define FP_MAX_REGNUM (FP0_REGNUM + 32) +#endif + +/* Size of a general (integer) register: */ +#define SPARC_INTREG_SIZE (REGISTER_RAW_SIZE (G0_REGNUM)) + +/* Offset within the call dummy stack of the saved registers. */ +#if (GDB_TARGET_IS_SPARC64) +#define DUMMY_REG_SAVE_OFFSET (128 + 16) +#else +#define DUMMY_REG_SAVE_OFFSET 0x60 +#endif + +#endif /* GDB_MULTI_ARCH */ + +#ifndef CALL_DUMMY_CALL_OFFSET +#define CALL_DUMMY_CALL_OFFSET \ + (gdbarch_tdep (current_gdbarch)->call_dummy_call_offset) +#endif /* CALL_DUMMY_CALL_OFFSET */ + +struct gdbarch_tdep + { + int os_ident; + int has_fpu; + int fp_register_bytes; + int y_regnum; + int fp_max_regnum; + int intreg_size; + int reg_save_offset; + int call_dummy_call_offset; + int print_insn_mach; + }; + +/* How a OS variant tells the SPARC generic code that it can handle an ABI + type. */ +extern void sparc_gdbarch_register_os_abi (int os_ident, + void (*init_abi)(struct gdbarch_info, + struct gdbarch *)); |