alpha_extract_struct_value_address;
static gdbarch_use_struct_convention_ftype alpha_use_struct_convention;
+static gdbarch_breakpoint_from_pc_ftype alpha_breakpoint_from_pc;
+
static gdbarch_frame_args_address_ftype alpha_frame_args_address;
static gdbarch_frame_locals_address_ftype alpha_frame_locals_address;
static gdbarch_init_frame_pc_first_ftype alpha_init_frame_pc_first;
static gdbarch_init_extra_frame_info_ftype alpha_init_extra_frame_info;
+static gdbarch_get_longjmp_target_ftype alpha_get_longjmp_target;
+
struct frame_extra_info
{
alpha_extra_func_info_t proc_desc;
*/
/* *INDENT-ON* */
-
-
#define PROC_LOW_ADDR(proc) ((proc)->pdr.adr) /* least address */
/* These next two fields are kind of being hijacked. I wonder if
iline is too small for the values it needs to hold, if GDB is
}
*linked_proc_desc_table = NULL;
\f
-int
-alpha_osf_in_sigtramp (CORE_ADDR pc, char *func_name)
+static CORE_ADDR
+alpha_frame_past_sigtramp_frame (struct frame_info *frame, CORE_ADDR pc)
{
- return (func_name != NULL && STREQ ("__sigtramp", func_name));
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (tdep->skip_sigtramp_frame != NULL)
+ return (tdep->skip_sigtramp_frame (frame, pc));
+
+ return (0);
}
-/* Under OSF/1, the __sigtramp routine is frameless and has a frame
- size of zero, but we are able to backtrace through it. */
-CORE_ADDR
-alpha_osf_skip_sigtramp_frame (struct frame_info *frame, CORE_ADDR pc)
+static LONGEST
+alpha_dynamic_sigtramp_offset (CORE_ADDR pc)
{
- char *name;
- find_pc_partial_function (pc, &name, (CORE_ADDR *) NULL, (CORE_ADDR *) NULL);
- if (PC_IN_SIGTRAMP (pc, name))
- return frame->frame;
- else
- return 0;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ /* Must be provided by OS/ABI variant code if supported. */
+ if (tdep->dynamic_sigtramp_offset != NULL)
+ return (tdep->dynamic_sigtramp_offset (pc));
+
+ return (-1);
+}
+
+#define ALPHA_PROC_SIGTRAMP_MAGIC 0x0e0f0f0f
+
+/* Return TRUE if the procedure descriptor PROC is a procedure
+ descriptor that refers to a dynamically generated signal
+ trampoline routine. */
+static int
+alpha_proc_desc_is_dyn_sigtramp (struct alpha_extra_func_info *proc)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (tdep->dynamic_sigtramp_offset != NULL)
+ return (proc->pdr.isym == ALPHA_PROC_SIGTRAMP_MAGIC);
+
+ return (0);
+}
+
+static void
+alpha_set_proc_desc_is_dyn_sigtramp (struct alpha_extra_func_info *proc)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (tdep->dynamic_sigtramp_offset != NULL)
+ proc->pdr.isym = ALPHA_PROC_SIGTRAMP_MAGIC;
}
-\f
/* Dynamically create a signal-handler caller procedure descriptor for
the signal-handler return code starting at address LOW_ADDR. The
PROC_FREG_MASK (proc_desc) = 0xffff;
PROC_PC_REG (proc_desc) = 26;
PROC_LOCALOFF (proc_desc) = 0;
- SET_PROC_DESC_IS_DYN_SIGTRAMP (proc_desc);
+ alpha_set_proc_desc_is_dyn_sigtramp (proc_desc);
return (proc_desc);
}
\f
}
\f
+static CORE_ADDR
+alpha_sigcontext_addr (struct frame_info *fi)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (tdep->sigcontext_addr)
+ return (tdep->sigcontext_addr (fi));
+
+ return (0);
+}
+
/* Guaranteed to set frame->saved_regs to some values (it never leaves it
NULL). */
{
CORE_ADDR sigcontext_addr;
- sigcontext_addr = SIGCONTEXT_ADDR (frame);
+ sigcontext_addr = alpha_sigcontext_addr (frame);
+ if (sigcontext_addr == 0)
+ {
+ /* Don't know where the sigcontext is; just bail. */
+ return;
+ }
for (ireg = 0; ireg < 32; ireg++)
{
reg_position = sigcontext_addr + SIGFRAME_REGSAVE_OFF + ireg * 8;
if (proc_desc)
{
- if (PROC_DESC_IS_DYN_SIGTRAMP (proc_desc))
+ if (alpha_proc_desc_is_dyn_sigtramp (proc_desc))
return PROC_LOW_ADDR (proc_desc); /* "prologue" is in kernel */
/* If function is frameless, then we need to do it the hard way. I
/* If PC is inside a dynamically generated sigtramp handler,
create and push a procedure descriptor for that code: */
- offset = DYNAMIC_SIGTRAMP_OFFSET (pc);
+ offset = alpha_dynamic_sigtramp_offset (pc);
if (offset >= 0)
return push_sigtramp_desc (pc - offset);
/* The previous frame from a sigtramp frame might be frameless
and have frame size zero. */
&& !frame->signal_handler_caller)
- return FRAME_PAST_SIGTRAMP_FRAME (frame, saved_pc);
+ return alpha_frame_past_sigtramp_frame (frame, saved_pc);
else
return read_next_frame_reg (frame, PROC_FRAME_REG (proc_desc))
+ PROC_FRAME_OFFSET (proc_desc);
Get the value of the frame relative sp, procedure might have been
interrupted by a signal at it's very start. */
else if (frame->pc == PROC_LOW_ADDR (proc_desc)
- && !PROC_DESC_IS_DYN_SIGTRAMP (proc_desc))
+ && !alpha_proc_desc_is_dyn_sigtramp (proc_desc))
frame->frame = read_next_frame_reg (frame->next, SP_REGNUM);
else
frame->frame = read_next_frame_reg (frame->next, PROC_FRAME_REG (proc_desc))
flush_cached_frames ();
if (proc_desc && (PROC_DESC_IS_DUMMY (proc_desc)
- || PROC_DESC_IS_DYN_SIGTRAMP (proc_desc)))
+ || alpha_proc_desc_is_dyn_sigtramp (proc_desc)))
{
struct linked_proc_info *pi_ptr, *prev_ptr;
CORE_ADDR post_prologue_pc;
char buf[4];
-#ifdef GDB_TARGET_HAS_SHARED_LIBS
/* Silently return the unaltered pc upon memory errors.
This could happen on OSF/1 if decode_line_1 tries to skip the
prologue for quickstarted shared library functions when the
shared library is not yet mapped in.
Reading target memory is slow over serial lines, so we perform
- this check only if the target has shared libraries. */
+ this check only if the target has shared libraries (which all
+ Alpha targets do). */
if (target_read_memory (pc, buf, 4))
return pc;
-#endif
/* See if we can determine the end of the prologue via the symbol table.
If so, then return either PC, or the PC after the prologue, whichever
error ("Cannot store value in floating point register");
}
+static const unsigned char *
+alpha_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
+{
+ static const unsigned char alpha_breakpoint[] =
+ { 0x80, 0, 0, 0 }; /* call_pal bpt */
+
+ *lenptr = sizeof(alpha_breakpoint);
+ return (alpha_breakpoint);
+}
+
/* Given a return value in `regbuf' with a type `valtype',
extract and copy its value into `valbuf'. */
static void
alpha_extract_return_value (struct type *valtype,
- char regbuf[REGISTER_BYTES], char *valbuf)
+ char regbuf[ALPHA_REGISTER_BYTES], char *valbuf)
{
if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
alpha_register_convert_to_virtual (FP0_REGNUM, valtype,
REGISTER_RAW_SIZE (ALPHA_V0_REGNUM)));
}
+/* Figure out where the longjmp will land.
+ 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 at. The PC is copied
+ into the "pc". This routine returns true on success. */
+
+static int
+alpha_get_longjmp_target (CORE_ADDR *pc)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ CORE_ADDR jb_addr;
+ char raw_buffer[ALPHA_MAX_REGISTER_RAW_SIZE];
+
+ jb_addr = read_register (ALPHA_A0_REGNUM);
+
+ if (target_read_memory (jb_addr + (tdep->jb_pc * tdep->jb_elt_size),
+ raw_buffer, tdep->jb_elt_size))
+ return 0;
+
+ *pc = extract_address (raw_buffer, tdep->jb_elt_size);
+ return 1;
+}
+
/* alpha_software_single_step() is called just before we want to resume
the inferior, if we want to single-step it but there is no hardware
or kernel single-step support (NetBSD on Alpha, for example). We find
}
\f
-/* This table matches the indices assigned to enum alpha_abi. Keep
- them in sync. */
-static const char * const alpha_abi_names[] =
-{
- "<unknown>",
- "OSF/1",
- "GNU/Linux",
- "FreeBSD",
- "NetBSD",
- NULL
-};
-
-static void
-process_note_abi_tag_sections (bfd *abfd, asection *sect, void *obj)
-{
- enum alpha_abi *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 == 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 = ALPHA_ABI_LINUX;
- break;
-
- case 1 :
- internal_error
- (__FILE__, __LINE__,
- "process_note_abi_sections: Hurd objects not supported");
- break;
-
- case 2 :
- 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);
- break;
- }
- }
- }
- /* 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 == 1
- && strcmp (note + 12, "NetBSD") == 0)
- /* XXX Should we check the version here?
- Probably not necessary yet. */
- *os_ident_ptr = ALPHA_ABI_NETBSD;
- }
-}
-
-static int
-get_elfosabi (bfd *abfd)
-{
- int elfosabi;
- enum alpha_abi alpha_abi = ALPHA_ABI_UNKNOWN;
-
- elfosabi = elf_elfheader (abfd)->e_ident[EI_OSABI];
-
- /* When elfosabi is 0 (ELFOSABI_NONE), this is supposed to indicate
- what we're on a SYSV system. However, GNU/Linux uses a note section
- to record OS/ABI info, but leaves e_ident[EI_OSABI] zero. So we
- have to check the note sections too. */
- if (elfosabi == 0)
- {
- bfd_map_over_sections (abfd,
- process_note_abi_tag_sections,
- &alpha_abi);
- }
-
- if (alpha_abi != ALPHA_ABI_UNKNOWN)
- return alpha_abi;
-
- switch (elfosabi)
- {
- case ELFOSABI_NONE:
- /* Leave it as unknown. */
- break;
-
- case ELFOSABI_NETBSD:
- return ALPHA_ABI_NETBSD;
-
- case ELFOSABI_FREEBSD:
- return ALPHA_ABI_FREEBSD;
-
- case ELFOSABI_LINUX:
- return ALPHA_ABI_LINUX;
- }
-
- return ALPHA_ABI_UNKNOWN;
-}
-
-struct alpha_abi_handler
-{
- struct alpha_abi_handler *next;
- enum alpha_abi abi;
- void (*init_abi)(struct gdbarch_info, struct gdbarch *);
-};
-
-struct alpha_abi_handler *alpha_abi_handler_list = NULL;
-
-void
-alpha_gdbarch_register_os_abi (enum alpha_abi abi,
- void (*init_abi)(struct gdbarch_info,
- struct gdbarch *))
-{
- struct alpha_abi_handler **handler_p;
-
- for (handler_p = &alpha_abi_handler_list; *handler_p != NULL;
- handler_p = &(*handler_p)->next)
- {
- if ((*handler_p)->abi == abi)
- {
- internal_error
- (__FILE__, __LINE__,
- "alpha_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_abi = init_abi;
- return;
- }
- }
-
- (*handler_p)
- = (struct alpha_abi_handler *) xmalloc (sizeof (struct alpha_abi_handler));
- (*handler_p)->next = NULL;
- (*handler_p)->abi = abi;
- (*handler_p)->init_abi = init_abi;
-}
/* Initialize the current architecture based on INFO. If possible, re-use an
architecture from ARCHES, which is a list of architectures already created
{
struct gdbarch_tdep *tdep;
struct gdbarch *gdbarch;
- enum alpha_abi alpha_abi = ALPHA_ABI_UNKNOWN;
- struct alpha_abi_handler *abi_handler;
+ enum gdb_osabi osabi = GDB_OSABI_UNKNOWN;
/* Try to determine the ABI of the object we are loading. */
if (info.abfd != NULL)
{
- switch (bfd_get_flavour (info.abfd))
+ osabi = gdbarch_lookup_osabi (info.abfd);
+ if (osabi == GDB_OSABI_UNKNOWN)
{
- case bfd_target_elf_flavour:
- alpha_abi = get_elfosabi (info.abfd);
- break;
-
- case bfd_target_ecoff_flavour:
- /* Assume it's OSF/1. */
- alpha_abi = ALPHA_ABI_OSF1;
- break;
-
- default:
- /* Not sure what to do here, leave the ABI as unknown. */
- break;
+ /* If it's an ECOFF file, assume it's OSF/1. */
+ if (bfd_get_flavour (info.abfd) == bfd_target_ecoff_flavour)
+ osabi = GDB_OSABI_OSF1;
}
}
{
/* Make sure the ABI selection matches. */
tdep = gdbarch_tdep (arches->gdbarch);
- if (tdep && tdep->alpha_abi == alpha_abi)
+ if (tdep && tdep->osabi == osabi)
return arches->gdbarch;
}
tdep = xmalloc (sizeof (struct gdbarch_tdep));
gdbarch = gdbarch_alloc (&info, tdep);
- tdep->alpha_abi = alpha_abi;
- if (alpha_abi < ALPHA_ABI_INVALID)
- tdep->abi_name = alpha_abi_names[alpha_abi];
- else
- {
- internal_error (__FILE__, __LINE__, "Invalid setting of alpha_abi %d",
- (int) alpha_abi);
- tdep->abi_name = "<invalid>";
- }
+ tdep->osabi = osabi;
/* Lowest text address. This is used by heuristic_proc_start() to
decide when to stop looking. */
tdep->vm_min_address = (CORE_ADDR) 0x120000000;
+ tdep->dynamic_sigtramp_offset = NULL;
+ tdep->skip_sigtramp_frame = NULL;
+ tdep->sigcontext_addr = NULL;
+
+ tdep->jb_pc = -1; /* longjmp support not enabled by default */
+
/* Type sizes */
set_gdbarch_short_bit (gdbarch, 16);
set_gdbarch_int_bit (gdbarch, 32);
set_gdbarch_init_frame_pc_first (gdbarch, alpha_init_frame_pc_first);
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+ set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
/* Floats are always passed as doubles. */
set_gdbarch_coerce_float_to_double (gdbarch,
standard_coerce_float_to_double);
+ set_gdbarch_breakpoint_from_pc (gdbarch, alpha_breakpoint_from_pc);
set_gdbarch_decr_pc_after_break (gdbarch, 4);
+
+ set_gdbarch_function_start_offset (gdbarch, 0);
set_gdbarch_frame_args_skip (gdbarch, 0);
/* Hook in ABI-specific overrides, if they have been registered. */
- if (alpha_abi == ALPHA_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 Alpha settings");
- }
- else
- {
- for (abi_handler = alpha_abi_handler_list; abi_handler != NULL;
- abi_handler = abi_handler->next)
- if (abi_handler->abi == alpha_abi)
- break;
+ gdbarch_init_osabi (info, gdbarch, osabi);
- 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 Alpha settings",
- alpha_abi_names[alpha_abi]);
- }
- }
+ /* Now that we have tuned the configuration, set a few final things
+ based on what the OS ABI has told us. */
+
+ if (tdep->jb_pc >= 0)
+ set_gdbarch_get_longjmp_target (gdbarch, alpha_get_longjmp_target);
return gdbarch;
}
if (tdep == NULL)
return;
- if (tdep->abi_name != NULL)
- fprintf_unfiltered (file, "alpha_dump_tdep: ABI = %s\n", tdep->abi_name);
- else
- internal_error (__FILE__, __LINE__,
- "alpha_dump_tdep: illegal setting of tdep->alpha_abi (%d)",
- (int) tdep->alpha_abi);
+ fprintf_unfiltered (file, "alpha_dump_tdep: OS ABI = %s\n",
+ gdbarch_osabi_name (tdep->osabi));
fprintf_unfiltered (file,
"alpha_dump_tdep: vm_min_address = 0x%lx\n",
(long) tdep->vm_min_address);
+
+ fprintf_unfiltered (file,
+ "alpha_dump_tdep: jb_pc = %d\n",
+ tdep->jb_pc);
+ fprintf_unfiltered (file,
+ "alpha_dump_tdep: jb_elt_size = %ld\n",
+ (long) tdep->jb_elt_size);
}
void