/* Intel 386 target-dependent stuff.
- Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
- 1998, 1999, 2000, 2001
- Free Software Foundation, Inc.
+
+ Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
+ 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
This file is part of GDB.
#include "regcache.h"
#include "doublest.h"
#include "value.h"
-
#include "gdb_assert.h"
+#include "elf-bfd.h"
+
+#include "i386-tdep.h"
+
/* Names of the registers. The first 10 registers match the register
numbering scheme used by GCC for stabs and DWARF. */
static char *i386_register_names[] =
return read_memory_unsigned_integer (frame->frame + 4, 4);
}
+CORE_ADDR
+i386go32_frame_saved_pc (struct frame_info *frame)
+{
+ return read_memory_integer (frame->frame + 4, 4);
+}
+
/* Immediately after a function call, return the saved pc. */
CORE_ADDR
i386_push_dummy_frame (void)
{
CORE_ADDR sp = read_register (SP_REGNUM);
+ CORE_ADDR fp;
int regnum;
char regbuf[MAX_REGISTER_RAW_SIZE];
sp = push_word (sp, read_register (PC_REGNUM));
sp = push_word (sp, read_register (FP_REGNUM));
- write_register (FP_REGNUM, sp);
+ fp = sp;
for (regnum = 0; regnum < NUM_REGS; regnum++)
{
read_register_gen (regnum, regbuf);
sp = push_bytes (sp, regbuf, REGISTER_RAW_SIZE (regnum));
}
write_register (SP_REGNUM, sp);
+ write_register (FP_REGNUM, fp);
}
/* Insert the (relative) function address into the call sequence
#ifdef GET_LONGJMP_TARGET
+/* FIXME: Multi-arching does not set JB_PC and JB_ELEMENT_SIZE yet.
+ Fill in with dummy value to enable compilation. */
+#ifndef JB_PC
+#define JB_PC 0
+#endif /* JB_PC */
+
+#ifndef JB_ELEMENT_SIZE
+#define JB_ELEMENT_SIZE 4
+#endif /* JB_ELEMENT_SIZE */
+
/* Figure out where the longjmp will land. Slurp the args out of the
stack. We expect the first arg to be a pointer to the jmp_buf
structure from which we extract the pc (JB_PC) that we will land
}
\f
+/* This table matches the indices assigned to enum i386_abi. Keep
+ them in sync. */
+static const char * const i386_abi_names[] =
+{
+ "<unknown>",
+ "SVR4",
+ "NetBSD",
+ "GNU/Linux",
+ "GNU/Hurd",
+ "Solaris",
+ "FreeBSD",
+ NULL
+};
+
+
+#define ABI_TAG_OS_GNU_LINUX I386_ABI_LINUX
+#define ABI_TAG_OS_GNU_HURD I386_ABI_HURD
+#define ABI_TAG_OS_GNU_SOLARIS I386_ABI_INVALID
+#define ABI_TAG_OS_FREEBSD I386_ABI_FREEBSD
+#define ABI_TAG_OS_NETBSD I386_ABI_NETBSD
+
+static void
+process_note_sections (bfd *abfd, asection *sect, void *obj)
+{
+ int *abi = 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 abi_tag_os = bfd_h_get_32 (abfd, note + 16);
+
+ /* The case numbers are from abi-tags in glibc. */
+ switch (abi_tag_os)
+ {
+ case GNU_ABI_TAG_LINUX:
+ *abi = ABI_TAG_OS_GNU_LINUX;
+ break;
+
+ case GNU_ABI_TAG_HURD:
+ *abi = ABI_TAG_OS_GNU_HURD;
+ break;
+
+ case GNU_ABI_TAG_SOLARIS:
+ *abi = ABI_TAG_OS_GNU_SOLARIS;
+ break;
+
+ default:
+ internal_error
+ (__FILE__, __LINE__,
+ "process_note_abi_sections: unknown ABI OS tag %d",
+ abi_tag_os);
+ break;
+ }
+ }
+ else if (name_length == 8 && data_length == 4
+ && note_type == NT_FREEBSD_ABI_TAG
+ && strcmp (note + 12, "FreeBSD") == 0)
+ *abi = ABI_TAG_OS_FREEBSD;
+ }
+ /* 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)
+ *abi = ABI_TAG_OS_NETBSD;
+ }
+}
+
+static int
+i386_elf_abi_from_note (bfd *abfd)
+{
+ enum i386_abi abi = I386_ABI_UNKNOWN;
+
+ bfd_map_over_sections (abfd, process_note_sections, &abi);
+
+ return abi;
+}
+
+static enum i386_abi
+i386_elf_abi (bfd *abfd)
+{
+ int elfosabi = elf_elfheader (abfd)->e_ident[EI_OSABI];
+
+ /* The fact that the EI_OSABI byte is set to ELFOSABI_NONE doesn't
+ necessarily mean that this is a System V ELF binary. To further
+ distinguish between binaries for differens operating systems,
+ check for vendor-specific note elements. */
+ if (elfosabi == ELFOSABI_NONE)
+ {
+ enum i386_abi abi = i386_elf_abi_from_note (abfd);
+
+ if (abi != I386_ABI_UNKNOWN)
+ return abi;
+
+ /* FreeBSD folks are naughty; they stored the string "FreeBSD"
+ in the padding of the e_ident field of the ELF header. */
+ if (strcmp (&elf_elfheader (abfd)->e_ident[8], "FreeBSD") == 0)
+ return I386_ABI_FREEBSD;
+ }
+
+ switch (elfosabi)
+ {
+ case ELFOSABI_NONE:
+ return I386_ABI_SVR4;
+ case ELFOSABI_FREEBSD:
+ return I386_ABI_FREEBSD;
+ }
+
+ return I386_ABI_UNKNOWN;
+}
+
+struct i386_abi_handler
+{
+ struct i386_abi_handler *next;
+ enum i386_abi abi;
+ void (*init_abi)(struct gdbarch_info, struct gdbarch *);
+};
+
+struct i386_abi_handler *i386_abi_handler_list = NULL;
+
+void
+i386_gdbarch_register_os_abi (enum i386_abi abi,
+ void (*init_abi)(struct gdbarch_info,
+ struct gdbarch *))
+{
+ struct i386_abi_handler **handler_p;
+
+ for (handler_p = &i386_abi_handler_list; *handler_p != NULL;
+ handler_p = &(*handler_p)->next)
+ {
+ if ((*handler_p)->abi == abi)
+ {
+ internal_error
+ (__FILE__, __LINE__,
+ "i386_gdbarch_register_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_abi = init_abi;
+ return;
+ }
+ }
+ (*handler_p)
+ = (struct i386_abi_handler *) xmalloc (sizeof (struct i386_abi_handler));
+ (*handler_p)->next = NULL;
+ (*handler_p)->abi = abi;
+ (*handler_p)->init_abi = init_abi;
+}
+
+struct gdbarch *
+i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+ struct gdbarch_tdep *tdep;
+ struct gdbarch *gdbarch;
+ enum i386_abi abi = I386_ABI_UNKNOWN;
+ struct i386_abi_handler *abi_handler;
+
+ if (info.abfd != NULL)
+ {
+ switch (bfd_get_flavour (info.abfd))
+ {
+ case bfd_target_elf_flavour:
+ abi= i386_elf_abi (info.abfd);
+ break;
+
+ default:
+ /* Not sure what to do here, leave the ABI as unknown. */
+ break;
+ }
+ }
+
+ /* Find a candidate among extant architectures. */
+ 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->abi == abi)
+ return arches->gdbarch;
+ }
+
+ /* Allocate space for the new architecture. */
+ tdep = XMALLOC (struct gdbarch_tdep);
+ gdbarch = gdbarch_alloc (&info, tdep);
+
+ tdep->abi = abi;
+
+ /* FIXME: kettenis/2001-11-24: Although not all IA-32 processors
+ have the SSE registers, it's easier to set the default to 8. */
+ tdep->num_xmm_regs = 8;
+
+ set_gdbarch_use_generic_dummy_frames (gdbarch, 0);
+
+ /* Call dummy code. */
+ set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
+ set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 5);
+ set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1);
+ set_gdbarch_call_dummy_p (gdbarch, 1);
+ set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0);
+
+ set_gdbarch_get_saved_register (gdbarch, generic_get_saved_register);
+ set_gdbarch_push_arguments (gdbarch, i386_push_arguments);
+
+ set_gdbarch_pc_in_call_dummy (gdbarch, pc_in_call_dummy_on_stack);
+
+ /* NOTE: tm-i386nw.h and tm-i386v4.h override this. */
+ set_gdbarch_frame_chain_valid (gdbarch, file_frame_chain_valid);
+
+ /* NOTE: tm-i386aix.h, tm-i386bsd.h, tm-i386os9k.h, tm-linux.h,
+ tm-ptx.h, tm-symmetry.h currently override this. Sigh. */
+ set_gdbarch_num_regs (gdbarch, NUM_GREGS + NUM_FREGS + NUM_SSE_REGS);
+
+ /* Hook in ABI-specific overrides, if they have been registered. */
+ if (abi == I386_ABI_UNKNOWN)
+ {
+ /* Don't complain about not knowing the ABI variant if we don't
+ have an inferior. */
+ if (info.abfd)
+ fprintf_filtered
+ (gdb_stderr, "GDB doesn't recognize the ABI of the inferior. "
+ "Attempting to continue with the default i386 settings");
+ }
+ else
+ {
+ for (abi_handler = i386_abi_handler_list; abi_handler != NULL;
+ abi_handler = abi_handler->next)
+ if (abi_handler->abi == abi)
+ break;
+
+ if (abi_handler)
+ abi_handler->init_abi (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 i386 settings",
+ i386_abi_names[abi]);
+ }
+ }
+
+ return gdbarch;
+}
/* Provide a prototype to silence -Wmissing-prototypes. */
void _initialize_i386_tdep (void);
void
_initialize_i386_tdep (void)
{
+ register_gdbarch_init (bfd_arch_i386, i386_gdbarch_init);
+
/* Initialize the table saying where each register starts in the
register file. */
{