diff options
Diffstat (limited to 'gdb/alpha-tdep.c')
-rw-r--r-- | gdb/alpha-tdep.c | 1972 |
1 files changed, 0 insertions, 1972 deletions
diff --git a/gdb/alpha-tdep.c b/gdb/alpha-tdep.c deleted file mode 100644 index 7018d39..0000000 --- a/gdb/alpha-tdep.c +++ /dev/null @@ -1,1972 +0,0 @@ -/* Target-dependent code for the ALPHA architecture, for GDB, the GNU Debugger. - Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 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. */ - -#include "defs.h" -#include "frame.h" -#include "inferior.h" -#include "symtab.h" -#include "value.h" -#include "gdbcmd.h" -#include "gdbcore.h" -#include "dis-asm.h" -#include "symfile.h" -#include "objfiles.h" -#include "gdb_string.h" -#include "linespec.h" -#include "regcache.h" -#include "doublest.h" -#include "arch-utils.h" - -#include "elf-bfd.h" - -#include "alpha-tdep.h" - -static gdbarch_init_ftype alpha_gdbarch_init; - -static gdbarch_register_name_ftype alpha_register_name; -static gdbarch_register_raw_size_ftype alpha_register_raw_size; -static gdbarch_register_virtual_size_ftype alpha_register_virtual_size; -static gdbarch_register_virtual_type_ftype alpha_register_virtual_type; -static gdbarch_register_byte_ftype alpha_register_byte; -static gdbarch_cannot_fetch_register_ftype alpha_cannot_fetch_register; -static gdbarch_cannot_store_register_ftype alpha_cannot_store_register; -static gdbarch_register_convertible_ftype alpha_register_convertible; -static gdbarch_register_convert_to_virtual_ftype - alpha_register_convert_to_virtual; -static gdbarch_register_convert_to_raw_ftype alpha_register_convert_to_raw; -static gdbarch_store_struct_return_ftype alpha_store_struct_return; -static gdbarch_deprecated_extract_return_value_ftype alpha_extract_return_value; -static gdbarch_deprecated_extract_struct_value_address_ftype - 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_skip_prologue_ftype alpha_skip_prologue; -static gdbarch_saved_pc_after_call_ftype alpha_saved_pc_after_call; -static gdbarch_frame_chain_ftype alpha_frame_chain; -static gdbarch_frame_saved_pc_ftype alpha_frame_saved_pc; -static gdbarch_frame_init_saved_regs_ftype alpha_frame_init_saved_regs; - -static gdbarch_push_arguments_ftype alpha_push_arguments; -static gdbarch_push_dummy_frame_ftype alpha_push_dummy_frame; -static gdbarch_pop_frame_ftype alpha_pop_frame; -static gdbarch_fix_call_dummy_ftype alpha_fix_call_dummy; -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; - int localoff; - int pc_reg; - }; - -/* FIXME: Some of this code should perhaps be merged with mips-tdep.c. */ - -/* Prototypes for local functions. */ - -static void alpha_find_saved_regs (struct frame_info *); - -static alpha_extra_func_info_t push_sigtramp_desc (CORE_ADDR low_addr); - -static CORE_ADDR read_next_frame_reg (struct frame_info *, int); - -static CORE_ADDR heuristic_proc_start (CORE_ADDR); - -static alpha_extra_func_info_t heuristic_proc_desc (CORE_ADDR, - CORE_ADDR, - struct frame_info *); - -static alpha_extra_func_info_t find_proc_desc (CORE_ADDR, - struct frame_info *); - -#if 0 -static int alpha_in_lenient_prologue (CORE_ADDR, CORE_ADDR); -#endif - -static void reinit_frame_cache_sfunc (char *, int, struct cmd_list_element *); - -static CORE_ADDR after_prologue (CORE_ADDR pc, - alpha_extra_func_info_t proc_desc); - -static int alpha_in_prologue (CORE_ADDR pc, - alpha_extra_func_info_t proc_desc); - -static int alpha_about_to_return (CORE_ADDR pc); - -void _initialize_alpha_tdep (void); - -/* Heuristic_proc_start may hunt through the text section for a long - time across a 2400 baud serial line. Allows the user to limit this - search. */ -static unsigned int heuristic_fence_post = 0; -/* *INDENT-OFF* */ -/* Layout of a stack frame on the alpha: - - | | - pdr members: | 7th ... nth arg, | - | `pushed' by caller. | - | | -----------------|-------------------------------|<-- old_sp == vfp - ^ ^ ^ ^ | | - | | | | | | - | |localoff | Copies of 1st .. 6th | - | | | | | argument if necessary. | - | | | v | | - | | | --- |-------------------------------|<-- FRAME_LOCALS_ADDRESS - | | | | | - | | | | Locals and temporaries. | - | | | | | - | | | |-------------------------------| - | | | | | - |-fregoffset | Saved float registers. | - | | | | F9 | - | | | | . | - | | | | . | - | | | | F2 | - | | v | | - | | -------|-------------------------------| - | | | | - | | | Saved registers. | - | | | S6 | - |-regoffset | . | - | | | . | - | | | S0 | - | | | pdr.pcreg | - | v | | - | ----------|-------------------------------| - | | | - frameoffset | Argument build area, gets | - | | 7th ... nth arg for any | - | | called procedure. | - v | | - -------------|-------------------------------|<-- sp - | | -*/ -/* *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 - running on a 32-bit host. */ -#define PROC_HIGH_ADDR(proc) ((proc)->pdr.iline) /* upper address bound */ -#define PROC_DUMMY_FRAME(proc) ((proc)->pdr.cbLineOffset) /*CALL_DUMMY frame */ -#define PROC_FRAME_OFFSET(proc) ((proc)->pdr.frameoffset) -#define PROC_FRAME_REG(proc) ((proc)->pdr.framereg) -#define PROC_REG_MASK(proc) ((proc)->pdr.regmask) -#define PROC_FREG_MASK(proc) ((proc)->pdr.fregmask) -#define PROC_REG_OFFSET(proc) ((proc)->pdr.regoffset) -#define PROC_FREG_OFFSET(proc) ((proc)->pdr.fregoffset) -#define PROC_PC_REG(proc) ((proc)->pdr.pcreg) -#define PROC_LOCALOFF(proc) ((proc)->pdr.localoff) -#define PROC_SYMBOL(proc) (*(struct symbol**)&(proc)->pdr.isym) -#define _PROC_MAGIC_ 0x0F0F0F0F -#define PROC_DESC_IS_DUMMY(proc) ((proc)->pdr.isym == _PROC_MAGIC_) -#define SET_PROC_DESC_IS_DUMMY(proc) ((proc)->pdr.isym = _PROC_MAGIC_) - -struct linked_proc_info - { - struct alpha_extra_func_info info; - struct linked_proc_info *next; - } - *linked_proc_desc_table = NULL; - -static CORE_ADDR -alpha_frame_past_sigtramp_frame (struct frame_info *frame, CORE_ADDR pc) -{ - struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); - - if (tdep->skip_sigtramp_frame != NULL) - return (tdep->skip_sigtramp_frame (frame, pc)); - - return (0); -} - -static LONGEST -alpha_dynamic_sigtramp_offset (CORE_ADDR pc) -{ - 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; -} - -/* Dynamically create a signal-handler caller procedure descriptor for - the signal-handler return code starting at address LOW_ADDR. The - descriptor is added to the linked_proc_desc_table. */ - -static alpha_extra_func_info_t -push_sigtramp_desc (CORE_ADDR low_addr) -{ - struct linked_proc_info *link; - alpha_extra_func_info_t proc_desc; - - link = (struct linked_proc_info *) - xmalloc (sizeof (struct linked_proc_info)); - link->next = linked_proc_desc_table; - linked_proc_desc_table = link; - - proc_desc = &link->info; - - proc_desc->numargs = 0; - PROC_LOW_ADDR (proc_desc) = low_addr; - PROC_HIGH_ADDR (proc_desc) = low_addr + 3 * 4; - PROC_DUMMY_FRAME (proc_desc) = 0; - PROC_FRAME_OFFSET (proc_desc) = 0x298; /* sizeof(struct sigcontext_struct) */ - PROC_FRAME_REG (proc_desc) = SP_REGNUM; - PROC_REG_MASK (proc_desc) = 0xffff; - PROC_FREG_MASK (proc_desc) = 0xffff; - PROC_PC_REG (proc_desc) = 26; - PROC_LOCALOFF (proc_desc) = 0; - alpha_set_proc_desc_is_dyn_sigtramp (proc_desc); - return (proc_desc); -} - - -static const char * -alpha_register_name (int regno) -{ - static char *register_names[] = - { - "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6", - "t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp", - "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9", - "t10", "t11", "ra", "t12", "at", "gp", "sp", "zero", - "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", - "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", - "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", - "f24", "f25", "f26", "f27", "f28", "f29", "f30", "fpcr", - "pc", "vfp", - }; - - if (regno < 0) - return (NULL); - if (regno >= (sizeof(register_names) / sizeof(*register_names))) - return (NULL); - return (register_names[regno]); -} - -static int -alpha_cannot_fetch_register (int regno) -{ - return (regno == FP_REGNUM || regno == ALPHA_ZERO_REGNUM); -} - -static int -alpha_cannot_store_register (int regno) -{ - return (regno == FP_REGNUM || regno == ALPHA_ZERO_REGNUM); -} - -static int -alpha_register_convertible (int regno) -{ - return (regno >= FP0_REGNUM && regno <= FP0_REGNUM + 31); -} - -static struct type * -alpha_register_virtual_type (int regno) -{ - return ((regno >= FP0_REGNUM && regno < (FP0_REGNUM+31)) - ? builtin_type_double : builtin_type_long); -} - -static int -alpha_register_byte (int regno) -{ - return (regno * 8); -} - -static int -alpha_register_raw_size (int regno) -{ - return 8; -} - -static int -alpha_register_virtual_size (int regno) -{ - return 8; -} - - -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). */ - -static void -alpha_find_saved_regs (struct frame_info *frame) -{ - int ireg; - CORE_ADDR reg_position; - unsigned long mask; - alpha_extra_func_info_t proc_desc; - int returnreg; - - frame_saved_regs_zalloc (frame); - - /* If it is the frame for __sigtramp, the saved registers are located - in a sigcontext structure somewhere on the stack. __sigtramp - passes a pointer to the sigcontext structure on the stack. - If the stack layout for __sigtramp changes, or if sigcontext offsets - change, we might have to update this code. */ -#ifndef SIGFRAME_PC_OFF -#define SIGFRAME_PC_OFF (2 * 8) -#define SIGFRAME_REGSAVE_OFF (4 * 8) -#define SIGFRAME_FPREGSAVE_OFF (SIGFRAME_REGSAVE_OFF + 32 * 8 + 8) -#endif - if (frame->signal_handler_caller) - { - CORE_ADDR sigcontext_addr; - - 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; - frame->saved_regs[ireg] = reg_position; - } - for (ireg = 0; ireg < 32; ireg++) - { - reg_position = sigcontext_addr + SIGFRAME_FPREGSAVE_OFF + ireg * 8; - frame->saved_regs[FP0_REGNUM + ireg] = reg_position; - } - frame->saved_regs[PC_REGNUM] = sigcontext_addr + SIGFRAME_PC_OFF; - return; - } - - proc_desc = frame->extra_info->proc_desc; - if (proc_desc == NULL) - /* I'm not sure how/whether this can happen. Normally when we can't - find a proc_desc, we "synthesize" one using heuristic_proc_desc - and set the saved_regs right away. */ - return; - - /* Fill in the offsets for the registers which gen_mask says - were saved. */ - - reg_position = frame->frame + PROC_REG_OFFSET (proc_desc); - mask = PROC_REG_MASK (proc_desc); - - returnreg = PROC_PC_REG (proc_desc); - - /* Note that RA is always saved first, regardless of its actual - register number. */ - if (mask & (1 << returnreg)) - { - frame->saved_regs[returnreg] = reg_position; - reg_position += 8; - mask &= ~(1 << returnreg); /* Clear bit for RA so we - don't save again later. */ - } - - for (ireg = 0; ireg <= 31; ++ireg) - if (mask & (1 << ireg)) - { - frame->saved_regs[ireg] = reg_position; - reg_position += 8; - } - - /* Fill in the offsets for the registers which float_mask says - were saved. */ - - reg_position = frame->frame + PROC_FREG_OFFSET (proc_desc); - mask = PROC_FREG_MASK (proc_desc); - - for (ireg = 0; ireg <= 31; ++ireg) - if (mask & (1 << ireg)) - { - frame->saved_regs[FP0_REGNUM + ireg] = reg_position; - reg_position += 8; - } - - frame->saved_regs[PC_REGNUM] = frame->saved_regs[returnreg]; -} - -static void -alpha_frame_init_saved_regs (struct frame_info *fi) -{ - if (fi->saved_regs == NULL) - alpha_find_saved_regs (fi); - fi->saved_regs[SP_REGNUM] = fi->frame; -} - -static void -alpha_init_frame_pc_first (int fromleaf, struct frame_info *prev) -{ - prev->pc = (fromleaf ? SAVED_PC_AFTER_CALL (prev->next) : - prev->next ? FRAME_SAVED_PC (prev->next) : read_pc ()); -} - -static CORE_ADDR -read_next_frame_reg (struct frame_info *fi, int regno) -{ - for (; fi; fi = fi->next) - { - /* We have to get the saved sp from the sigcontext - if it is a signal handler frame. */ - if (regno == SP_REGNUM && !fi->signal_handler_caller) - return fi->frame; - else - { - if (fi->saved_regs == NULL) - alpha_find_saved_regs (fi); - if (fi->saved_regs[regno]) - return read_memory_integer (fi->saved_regs[regno], 8); - } - } - return read_register (regno); -} - -static CORE_ADDR -alpha_frame_saved_pc (struct frame_info *frame) -{ - alpha_extra_func_info_t proc_desc = frame->extra_info->proc_desc; - /* We have to get the saved pc from the sigcontext - if it is a signal handler frame. */ - int pcreg = frame->signal_handler_caller ? PC_REGNUM - : frame->extra_info->pc_reg; - - if (proc_desc && PROC_DESC_IS_DUMMY (proc_desc)) - return read_memory_integer (frame->frame - 8, 8); - - return read_next_frame_reg (frame, pcreg); -} - -static CORE_ADDR -alpha_saved_pc_after_call (struct frame_info *frame) -{ - CORE_ADDR pc = frame->pc; - CORE_ADDR tmp; - alpha_extra_func_info_t proc_desc; - int pcreg; - - /* Skip over shared library trampoline if necessary. */ - tmp = SKIP_TRAMPOLINE_CODE (pc); - if (tmp != 0) - pc = tmp; - - proc_desc = find_proc_desc (pc, frame->next); - pcreg = proc_desc ? PROC_PC_REG (proc_desc) : ALPHA_RA_REGNUM; - - if (frame->signal_handler_caller) - return alpha_frame_saved_pc (frame); - else - return read_register (pcreg); -} - - -static struct alpha_extra_func_info temp_proc_desc; -static CORE_ADDR temp_saved_regs[ALPHA_NUM_REGS]; - -/* Nonzero if instruction at PC is a return instruction. "ret - $zero,($ra),1" on alpha. */ - -static int -alpha_about_to_return (CORE_ADDR pc) -{ - return read_memory_integer (pc, 4) == 0x6bfa8001; -} - - - -/* This fencepost looks highly suspicious to me. Removing it also - seems suspicious as it could affect remote debugging across serial - lines. */ - -static CORE_ADDR -heuristic_proc_start (CORE_ADDR pc) -{ - struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); - CORE_ADDR start_pc = pc; - CORE_ADDR fence = start_pc - heuristic_fence_post; - - if (start_pc == 0) - return 0; - - if (heuristic_fence_post == UINT_MAX - || fence < tdep->vm_min_address) - fence = tdep->vm_min_address; - - /* search back for previous return */ - for (start_pc -= 4;; start_pc -= 4) - if (start_pc < fence) - { - /* It's not clear to me why we reach this point when - stop_soon_quietly, but with this test, at least we - don't print out warnings for every child forked (eg, on - decstation). 22apr93 rich@cygnus.com. */ - if (!stop_soon_quietly) - { - static int blurb_printed = 0; - - if (fence == tdep->vm_min_address) - warning ("Hit beginning of text section without finding"); - else - warning ("Hit heuristic-fence-post without finding"); - - warning ("enclosing function for address 0x%s", paddr_nz (pc)); - if (!blurb_printed) - { - printf_filtered ("\ -This warning occurs if you are debugging a function without any symbols\n\ -(for example, in a stripped executable). In that case, you may wish to\n\ -increase the size of the search with the `set heuristic-fence-post' command.\n\ -\n\ -Otherwise, you told GDB there was a function where there isn't one, or\n\ -(more likely) you have encountered a bug in GDB.\n"); - blurb_printed = 1; - } - } - - return 0; - } - else if (alpha_about_to_return (start_pc)) - break; - - start_pc += 4; /* skip return */ - return start_pc; -} - -static alpha_extra_func_info_t -heuristic_proc_desc (CORE_ADDR start_pc, CORE_ADDR limit_pc, - struct frame_info *next_frame) -{ - CORE_ADDR sp = read_next_frame_reg (next_frame, SP_REGNUM); - CORE_ADDR vfp = sp; - CORE_ADDR cur_pc; - int frame_size; - int has_frame_reg = 0; - unsigned long reg_mask = 0; - int pcreg = -1; - int regno; - - if (start_pc == 0) - return NULL; - memset (&temp_proc_desc, '\0', sizeof (temp_proc_desc)); - memset (&temp_saved_regs, '\0', SIZEOF_FRAME_SAVED_REGS); - PROC_LOW_ADDR (&temp_proc_desc) = start_pc; - - if (start_pc + 200 < limit_pc) - limit_pc = start_pc + 200; - frame_size = 0; - for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += 4) - { - char buf[4]; - unsigned long word; - int status; - - status = read_memory_nobpt (cur_pc, buf, 4); - if (status) - memory_error (status, cur_pc); - word = extract_unsigned_integer (buf, 4); - - if ((word & 0xffff0000) == 0x23de0000) /* lda $sp,n($sp) */ - { - if (word & 0x8000) - { - /* Consider only the first stack allocation instruction - to contain the static size of the frame. */ - if (frame_size == 0) - frame_size += (-word) & 0xffff; - } - else - /* Exit loop if a positive stack adjustment is found, which - usually means that the stack cleanup code in the function - epilogue is reached. */ - break; - } - else if ((word & 0xfc1f0000) == 0xb41e0000 /* stq reg,n($sp) */ - && (word & 0xffff0000) != 0xb7fe0000) /* reg != $zero */ - { - int reg = (word & 0x03e00000) >> 21; - reg_mask |= 1 << reg; - - /* Do not compute the address where the register was saved yet, - because we don't know yet if the offset will need to be - relative to $sp or $fp (we can not compute the address relative - to $sp if $sp is updated during the execution of the current - subroutine, for instance when doing some alloca). So just store - the offset for the moment, and compute the address later - when we know whether this frame has a frame pointer or not. - */ - temp_saved_regs[reg] = (short) word; - - /* Starting with OSF/1-3.2C, the system libraries are shipped - without local symbols, but they still contain procedure - descriptors without a symbol reference. GDB is currently - unable to find these procedure descriptors and uses - heuristic_proc_desc instead. - As some low level compiler support routines (__div*, __add*) - use a non-standard return address register, we have to - add some heuristics to determine the return address register, - or stepping over these routines will fail. - Usually the return address register is the first register - saved on the stack, but assembler optimization might - rearrange the register saves. - So we recognize only a few registers (t7, t9, ra) within - the procedure prologue as valid return address registers. - If we encounter a return instruction, we extract the - the return address register from it. - - FIXME: Rewriting GDB to access the procedure descriptors, - e.g. via the minimal symbol table, might obviate this hack. */ - if (pcreg == -1 - && cur_pc < (start_pc + 80) - && (reg == ALPHA_T7_REGNUM || reg == ALPHA_T9_REGNUM - || reg == ALPHA_RA_REGNUM)) - pcreg = reg; - } - else if ((word & 0xffe0ffff) == 0x6be08001) /* ret zero,reg,1 */ - pcreg = (word >> 16) & 0x1f; - else if (word == 0x47de040f || word == 0x47fe040f) /* bis sp,sp fp */ - { - /* ??? I am not sure what instruction is 0x47fe040f, and I - am suspecting that there was a typo and should have been - 0x47fe040f. I'm keeping it in the test above until further - investigation */ - has_frame_reg = 1; - vfp = read_next_frame_reg (next_frame, ALPHA_GCC_FP_REGNUM); - } - } - if (pcreg == -1) - { - /* If we haven't found a valid return address register yet, - keep searching in the procedure prologue. */ - while (cur_pc < (limit_pc + 80) && cur_pc < (start_pc + 80)) - { - char buf[4]; - unsigned long word; - - if (read_memory_nobpt (cur_pc, buf, 4)) - break; - cur_pc += 4; - word = extract_unsigned_integer (buf, 4); - - if ((word & 0xfc1f0000) == 0xb41e0000 /* stq reg,n($sp) */ - && (word & 0xffff0000) != 0xb7fe0000) /* reg != $zero */ - { - int reg = (word & 0x03e00000) >> 21; - if (reg == ALPHA_T7_REGNUM || reg == ALPHA_T9_REGNUM - || reg == ALPHA_RA_REGNUM) - { - pcreg = reg; - break; - } - } - else if ((word & 0xffe0ffff) == 0x6be08001) /* ret zero,reg,1 */ - { - pcreg = (word >> 16) & 0x1f; - break; - } - } - } - - if (has_frame_reg) - PROC_FRAME_REG (&temp_proc_desc) = ALPHA_GCC_FP_REGNUM; - else - PROC_FRAME_REG (&temp_proc_desc) = SP_REGNUM; - - /* At this point, we know which of the Stack Pointer or the Frame Pointer - to use as the reference address to compute the saved registers address. - But in both cases, the processing above has set vfp to this reference - address, so just need to increment the offset of each saved register - by this address. */ - for (regno = 0; regno < NUM_REGS; regno++) - { - if (reg_mask & 1 << regno) - temp_saved_regs[regno] += vfp; - } - - PROC_FRAME_OFFSET (&temp_proc_desc) = frame_size; - PROC_REG_MASK (&temp_proc_desc) = reg_mask; - PROC_PC_REG (&temp_proc_desc) = (pcreg == -1) ? ALPHA_RA_REGNUM : pcreg; - PROC_LOCALOFF (&temp_proc_desc) = 0; /* XXX - bogus */ - return &temp_proc_desc; -} - -/* This returns the PC of the first inst after the prologue. If we can't - find the prologue, then return 0. */ - -static CORE_ADDR -after_prologue (CORE_ADDR pc, alpha_extra_func_info_t proc_desc) -{ - struct symtab_and_line sal; - CORE_ADDR func_addr, func_end; - - if (!proc_desc) - proc_desc = find_proc_desc (pc, NULL); - - if (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 - strongly suspect that frameless always means prologueless... */ - if (PROC_FRAME_REG (proc_desc) == SP_REGNUM - && PROC_FRAME_OFFSET (proc_desc) == 0) - return 0; - } - - if (!find_pc_partial_function (pc, NULL, &func_addr, &func_end)) - return 0; /* Unknown */ - - sal = find_pc_line (func_addr, 0); - - if (sal.end < func_end) - return sal.end; - - /* The line after the prologue is after the end of the function. In this - case, tell the caller to find the prologue the hard way. */ - - return 0; -} - -/* Return non-zero if we *might* be in a function prologue. Return zero if we - are definitively *not* in a function prologue. */ - -static int -alpha_in_prologue (CORE_ADDR pc, alpha_extra_func_info_t proc_desc) -{ - CORE_ADDR after_prologue_pc; - - after_prologue_pc = after_prologue (pc, proc_desc); - - if (after_prologue_pc == 0 - || pc < after_prologue_pc) - return 1; - else - return 0; -} - -static alpha_extra_func_info_t -find_proc_desc (CORE_ADDR pc, struct frame_info *next_frame) -{ - alpha_extra_func_info_t proc_desc; - struct block *b; - struct symbol *sym; - CORE_ADDR startaddr; - - /* Try to get the proc_desc from the linked call dummy proc_descs - if the pc is in the call dummy. - This is hairy. In the case of nested dummy calls we have to find the - right proc_desc, but we might not yet know the frame for the dummy - as it will be contained in the proc_desc we are searching for. - So we have to find the proc_desc whose frame is closest to the current - stack pointer. */ - - if (PC_IN_CALL_DUMMY (pc, 0, 0)) - { - struct linked_proc_info *link; - CORE_ADDR sp = read_next_frame_reg (next_frame, SP_REGNUM); - alpha_extra_func_info_t found_proc_desc = NULL; - long min_distance = LONG_MAX; - - for (link = linked_proc_desc_table; link; link = link->next) - { - long distance = (CORE_ADDR) PROC_DUMMY_FRAME (&link->info) - sp; - if (distance > 0 && distance < min_distance) - { - min_distance = distance; - found_proc_desc = &link->info; - } - } - if (found_proc_desc != NULL) - return found_proc_desc; - } - - b = block_for_pc (pc); - - find_pc_partial_function (pc, NULL, &startaddr, NULL); - if (b == NULL) - sym = NULL; - else - { - if (startaddr > BLOCK_START (b)) - /* This is the "pathological" case referred to in a comment in - print_frame_info. It might be better to move this check into - symbol reading. */ - sym = NULL; - else - sym = lookup_symbol (MIPS_EFI_SYMBOL_NAME, b, LABEL_NAMESPACE, - 0, NULL); - } - - /* If we never found a PDR for this function in symbol reading, then - examine prologues to find the information. */ - if (sym && ((mips_extra_func_info_t) SYMBOL_VALUE (sym))->pdr.framereg == -1) - sym = NULL; - - if (sym) - { - /* IF this is the topmost frame AND - * (this proc does not have debugging information OR - * the PC is in the procedure prologue) - * THEN create a "heuristic" proc_desc (by analyzing - * the actual code) to replace the "official" proc_desc. - */ - proc_desc = (alpha_extra_func_info_t) SYMBOL_VALUE (sym); - if (next_frame == NULL) - { - if (PROC_DESC_IS_DUMMY (proc_desc) || alpha_in_prologue (pc, proc_desc)) - { - alpha_extra_func_info_t found_heuristic = - heuristic_proc_desc (PROC_LOW_ADDR (proc_desc), - pc, next_frame); - if (found_heuristic) - { - PROC_LOCALOFF (found_heuristic) = - PROC_LOCALOFF (proc_desc); - PROC_PC_REG (found_heuristic) = PROC_PC_REG (proc_desc); - proc_desc = found_heuristic; - } - } - } - } - else - { - long offset; - - /* Is linked_proc_desc_table really necessary? It only seems to be used - by procedure call dummys. However, the procedures being called ought - to have their own proc_descs, and even if they don't, - heuristic_proc_desc knows how to create them! */ - - register struct linked_proc_info *link; - for (link = linked_proc_desc_table; link; link = link->next) - if (PROC_LOW_ADDR (&link->info) <= pc - && PROC_HIGH_ADDR (&link->info) > pc) - return &link->info; - - /* If PC is inside a dynamically generated sigtramp handler, - create and push a procedure descriptor for that code: */ - offset = alpha_dynamic_sigtramp_offset (pc); - if (offset >= 0) - return push_sigtramp_desc (pc - offset); - - /* If heuristic_fence_post is non-zero, determine the procedure - start address by examining the instructions. - This allows us to find the start address of static functions which - have no symbolic information, as startaddr would have been set to - the preceding global function start address by the - find_pc_partial_function call above. */ - if (startaddr == 0 || heuristic_fence_post != 0) - startaddr = heuristic_proc_start (pc); - - proc_desc = - heuristic_proc_desc (startaddr, pc, next_frame); - } - return proc_desc; -} - -alpha_extra_func_info_t cached_proc_desc; - -static CORE_ADDR -alpha_frame_chain (struct frame_info *frame) -{ - alpha_extra_func_info_t proc_desc; - CORE_ADDR saved_pc = FRAME_SAVED_PC (frame); - - if (saved_pc == 0 || inside_entry_file (saved_pc)) - return 0; - - proc_desc = find_proc_desc (saved_pc, frame); - if (!proc_desc) - return 0; - - cached_proc_desc = proc_desc; - - /* Fetch the frame pointer for a dummy frame from the procedure - descriptor. */ - if (PROC_DESC_IS_DUMMY (proc_desc)) - return (CORE_ADDR) PROC_DUMMY_FRAME (proc_desc); - - /* If no frame pointer and frame size is zero, we must be at end - of stack (or otherwise hosed). If we don't check frame size, - we loop forever if we see a zero size frame. */ - if (PROC_FRAME_REG (proc_desc) == SP_REGNUM - && PROC_FRAME_OFFSET (proc_desc) == 0 - /* The previous frame from a sigtramp frame might be frameless - and have frame size zero. */ - && !frame->signal_handler_caller) - 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); -} - -void -alpha_print_extra_frame_info (struct frame_info *fi) -{ - if (fi - && fi->extra_info - && fi->extra_info->proc_desc - && fi->extra_info->proc_desc->pdr.framereg < NUM_REGS) - printf_filtered (" frame pointer is at %s+%s\n", - REGISTER_NAME (fi->extra_info->proc_desc->pdr.framereg), - paddr_d (fi->extra_info->proc_desc->pdr.frameoffset)); -} - -static void -alpha_init_extra_frame_info (int fromleaf, struct frame_info *frame) -{ - /* Use proc_desc calculated in frame_chain */ - alpha_extra_func_info_t proc_desc = - frame->next ? cached_proc_desc : find_proc_desc (frame->pc, frame->next); - - frame->extra_info = (struct frame_extra_info *) - frame_obstack_alloc (sizeof (struct frame_extra_info)); - - frame->saved_regs = NULL; - frame->extra_info->localoff = 0; - frame->extra_info->pc_reg = ALPHA_RA_REGNUM; - frame->extra_info->proc_desc = proc_desc == &temp_proc_desc ? 0 : proc_desc; - if (proc_desc) - { - /* Get the locals offset and the saved pc register from the - procedure descriptor, they are valid even if we are in the - middle of the prologue. */ - frame->extra_info->localoff = PROC_LOCALOFF (proc_desc); - frame->extra_info->pc_reg = PROC_PC_REG (proc_desc); - - /* Fixup frame-pointer - only needed for top frame */ - - /* Fetch the frame pointer for a dummy frame from the procedure - descriptor. */ - if (PROC_DESC_IS_DUMMY (proc_desc)) - frame->frame = (CORE_ADDR) PROC_DUMMY_FRAME (proc_desc); - - /* This may not be quite right, if proc has a real frame register. - 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) - && !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)) - + PROC_FRAME_OFFSET (proc_desc); - - if (proc_desc == &temp_proc_desc) - { - char *name; - - /* Do not set the saved registers for a sigtramp frame, - alpha_find_saved_registers will do that for us. - We can't use frame->signal_handler_caller, it is not yet set. */ - find_pc_partial_function (frame->pc, &name, - (CORE_ADDR *) NULL, (CORE_ADDR *) NULL); - if (!PC_IN_SIGTRAMP (frame->pc, name)) - { - frame->saved_regs = (CORE_ADDR *) - frame_obstack_alloc (SIZEOF_FRAME_SAVED_REGS); - memcpy (frame->saved_regs, temp_saved_regs, - SIZEOF_FRAME_SAVED_REGS); - frame->saved_regs[PC_REGNUM] - = frame->saved_regs[ALPHA_RA_REGNUM]; - } - } - } -} - -static CORE_ADDR -alpha_frame_locals_address (struct frame_info *fi) -{ - return (fi->frame - fi->extra_info->localoff); -} - -static CORE_ADDR -alpha_frame_args_address (struct frame_info *fi) -{ - return (fi->frame - (ALPHA_NUM_ARG_REGS * 8)); -} - -/* ALPHA stack frames are almost impenetrable. When execution stops, - we basically have to look at symbol information for the function - that we stopped in, which tells us *which* register (if any) is - the base of the frame pointer, and what offset from that register - the frame itself is at. - - This presents a problem when trying to examine a stack in memory - (that isn't executing at the moment), using the "frame" command. We - don't have a PC, nor do we have any registers except SP. - - This routine takes two arguments, SP and PC, and tries to make the - cached frames look as if these two arguments defined a frame on the - cache. This allows the rest of info frame to extract the important - arguments without difficulty. */ - -struct frame_info * -alpha_setup_arbitrary_frame (int argc, CORE_ADDR *argv) -{ - if (argc != 2) - error ("ALPHA frame specifications require two arguments: sp and pc"); - - return create_new_frame (argv[0], argv[1]); -} - -/* The alpha passes the first six arguments in the registers, the rest on - the stack. The register arguments are eventually transferred to the - argument transfer area immediately below the stack by the called function - anyway. So we `push' at least six arguments on the stack, `reload' the - argument registers and then adjust the stack pointer to point past the - sixth argument. This algorithm simplifies the passing of a large struct - which extends from the registers to the stack. - If the called function is returning a structure, the address of the - structure to be returned is passed as a hidden first argument. */ - -static CORE_ADDR -alpha_push_arguments (int nargs, struct value **args, CORE_ADDR sp, - int struct_return, CORE_ADDR struct_addr) -{ - int i; - int accumulate_size = struct_return ? 8 : 0; - int arg_regs_size = ALPHA_NUM_ARG_REGS * 8; - struct alpha_arg - { - char *contents; - int len; - int offset; - }; - struct alpha_arg *alpha_args = - (struct alpha_arg *) alloca (nargs * sizeof (struct alpha_arg)); - register struct alpha_arg *m_arg; - char raw_buffer[sizeof (CORE_ADDR)]; - int required_arg_regs; - - for (i = 0, m_arg = alpha_args; i < nargs; i++, m_arg++) - { - struct value *arg = args[i]; - struct type *arg_type = check_typedef (VALUE_TYPE (arg)); - /* Cast argument to long if necessary as the compiler does it too. */ - switch (TYPE_CODE (arg_type)) - { - case TYPE_CODE_INT: - case TYPE_CODE_BOOL: - case TYPE_CODE_CHAR: - case TYPE_CODE_RANGE: - case TYPE_CODE_ENUM: - if (TYPE_LENGTH (arg_type) < TYPE_LENGTH (builtin_type_long)) - { - arg_type = builtin_type_long; - arg = value_cast (arg_type, arg); - } - break; - default: - break; - } - m_arg->len = TYPE_LENGTH (arg_type); - m_arg->offset = accumulate_size; - accumulate_size = (accumulate_size + m_arg->len + 7) & ~7; - m_arg->contents = VALUE_CONTENTS (arg); - } - - /* Determine required argument register loads, loading an argument register - is expensive as it uses three ptrace calls. */ - required_arg_regs = accumulate_size / 8; - if (required_arg_regs > ALPHA_NUM_ARG_REGS) - required_arg_regs = ALPHA_NUM_ARG_REGS; - - /* Make room for the arguments on the stack. */ - if (accumulate_size < arg_regs_size) - accumulate_size = arg_regs_size; - sp -= accumulate_size; - - /* Keep sp aligned to a multiple of 16 as the compiler does it too. */ - sp &= ~15; - - /* `Push' arguments on the stack. */ - for (i = nargs; m_arg--, --i >= 0;) - write_memory (sp + m_arg->offset, m_arg->contents, m_arg->len); - if (struct_return) - { - store_address (raw_buffer, sizeof (CORE_ADDR), struct_addr); - write_memory (sp, raw_buffer, sizeof (CORE_ADDR)); - } - - /* Load the argument registers. */ - for (i = 0; i < required_arg_regs; i++) - { - LONGEST val; - - val = read_memory_integer (sp + i * 8, 8); - write_register (ALPHA_A0_REGNUM + i, val); - write_register (ALPHA_FPA0_REGNUM + i, val); - } - - return sp + arg_regs_size; -} - -static void -alpha_push_dummy_frame (void) -{ - int ireg; - struct linked_proc_info *link; - alpha_extra_func_info_t proc_desc; - CORE_ADDR sp = read_register (SP_REGNUM); - CORE_ADDR save_address; - char raw_buffer[ALPHA_MAX_REGISTER_RAW_SIZE]; - unsigned long mask; - - link = (struct linked_proc_info *) xmalloc (sizeof (struct linked_proc_info)); - link->next = linked_proc_desc_table; - linked_proc_desc_table = link; - - proc_desc = &link->info; - - /* - * The registers we must save are all those not preserved across - * procedure calls. - * In addition, we must save the PC and RA. - * - * Dummy frame layout: - * (high memory) - * Saved PC - * Saved F30 - * ... - * Saved F0 - * Saved R29 - * ... - * Saved R0 - * Saved R26 (RA) - * Parameter build area - * (low memory) - */ - -/* MASK(i,j) == (1<<i) + (1<<(i+1)) + ... + (1<<j)). Assume i<=j<31. */ -#define MASK(i,j) ((((LONGEST)1 << ((j)+1)) - 1) ^ (((LONGEST)1 << (i)) - 1)) -#define GEN_REG_SAVE_MASK (MASK(0,8) | MASK(16,29)) -#define GEN_REG_SAVE_COUNT 24 -#define FLOAT_REG_SAVE_MASK (MASK(0,1) | MASK(10,30)) -#define FLOAT_REG_SAVE_COUNT 23 - /* The special register is the PC as we have no bit for it in the save masks. - alpha_frame_saved_pc knows where the pc is saved in a dummy frame. */ -#define SPECIAL_REG_SAVE_COUNT 1 - - PROC_REG_MASK (proc_desc) = GEN_REG_SAVE_MASK; - PROC_FREG_MASK (proc_desc) = FLOAT_REG_SAVE_MASK; - /* PROC_REG_OFFSET is the offset from the dummy frame to the saved RA, - but keep SP aligned to a multiple of 16. */ - PROC_REG_OFFSET (proc_desc) = - -((8 * (SPECIAL_REG_SAVE_COUNT - + GEN_REG_SAVE_COUNT - + FLOAT_REG_SAVE_COUNT) - + 15) & ~15); - PROC_FREG_OFFSET (proc_desc) = - PROC_REG_OFFSET (proc_desc) + 8 * GEN_REG_SAVE_COUNT; - - /* Save general registers. - The return address register is the first saved register, all other - registers follow in ascending order. - The PC is saved immediately below the SP. */ - save_address = sp + PROC_REG_OFFSET (proc_desc); - store_address (raw_buffer, 8, read_register (ALPHA_RA_REGNUM)); - write_memory (save_address, raw_buffer, 8); - save_address += 8; - mask = PROC_REG_MASK (proc_desc) & 0xffffffffL; - for (ireg = 0; mask; ireg++, mask >>= 1) - if (mask & 1) - { - if (ireg == ALPHA_RA_REGNUM) - continue; - store_address (raw_buffer, 8, read_register (ireg)); - write_memory (save_address, raw_buffer, 8); - save_address += 8; - } - - store_address (raw_buffer, 8, read_register (PC_REGNUM)); - write_memory (sp - 8, raw_buffer, 8); - - /* Save floating point registers. */ - save_address = sp + PROC_FREG_OFFSET (proc_desc); - mask = PROC_FREG_MASK (proc_desc) & 0xffffffffL; - for (ireg = 0; mask; ireg++, mask >>= 1) - if (mask & 1) - { - store_address (raw_buffer, 8, read_register (ireg + FP0_REGNUM)); - write_memory (save_address, raw_buffer, 8); - save_address += 8; - } - - /* Set and save the frame address for the dummy. - This is tricky. The only registers that are suitable for a frame save - are those that are preserved across procedure calls (s0-s6). But if - a read system call is interrupted and then a dummy call is made - (see testsuite/gdb.t17/interrupt.exp) the dummy call hangs till the read - is satisfied. Then it returns with the s0-s6 registers set to the values - on entry to the read system call and our dummy frame pointer would be - destroyed. So we save the dummy frame in the proc_desc and handle the - retrieval of the frame pointer of a dummy specifically. The frame register - is set to the virtual frame (pseudo) register, it's value will always - be read as zero and will help us to catch any errors in the dummy frame - retrieval code. */ - PROC_DUMMY_FRAME (proc_desc) = sp; - PROC_FRAME_REG (proc_desc) = FP_REGNUM; - PROC_FRAME_OFFSET (proc_desc) = 0; - sp += PROC_REG_OFFSET (proc_desc); - write_register (SP_REGNUM, sp); - - PROC_LOW_ADDR (proc_desc) = CALL_DUMMY_ADDRESS (); - PROC_HIGH_ADDR (proc_desc) = PROC_LOW_ADDR (proc_desc) + 4; - - SET_PROC_DESC_IS_DUMMY (proc_desc); - PROC_PC_REG (proc_desc) = ALPHA_RA_REGNUM; -} - -static void -alpha_pop_frame (void) -{ - register int regnum; - struct frame_info *frame = get_current_frame (); - CORE_ADDR new_sp = frame->frame; - - alpha_extra_func_info_t proc_desc = frame->extra_info->proc_desc; - - /* we need proc_desc to know how to restore the registers; - if it is NULL, construct (a temporary) one */ - if (proc_desc == NULL) - proc_desc = find_proc_desc (frame->pc, frame->next); - - /* Question: should we copy this proc_desc and save it in - frame->proc_desc? If we do, who will free it? - For now, we don't save a copy... */ - - write_register (PC_REGNUM, FRAME_SAVED_PC (frame)); - if (frame->saved_regs == NULL) - alpha_find_saved_regs (frame); - if (proc_desc) - { - for (regnum = 32; --regnum >= 0;) - if (PROC_REG_MASK (proc_desc) & (1 << regnum)) - write_register (regnum, - read_memory_integer (frame->saved_regs[regnum], - 8)); - for (regnum = 32; --regnum >= 0;) - if (PROC_FREG_MASK (proc_desc) & (1 << regnum)) - write_register (regnum + FP0_REGNUM, - read_memory_integer (frame->saved_regs[regnum + FP0_REGNUM], 8)); - } - write_register (SP_REGNUM, new_sp); - flush_cached_frames (); - - if (proc_desc && (PROC_DESC_IS_DUMMY (proc_desc) - || alpha_proc_desc_is_dyn_sigtramp (proc_desc))) - { - struct linked_proc_info *pi_ptr, *prev_ptr; - - for (pi_ptr = linked_proc_desc_table, prev_ptr = NULL; - pi_ptr != NULL; - prev_ptr = pi_ptr, pi_ptr = pi_ptr->next) - { - if (&pi_ptr->info == proc_desc) - break; - } - - if (pi_ptr == NULL) - error ("Can't locate dummy extra frame info\n"); - - if (prev_ptr != NULL) - prev_ptr->next = pi_ptr->next; - else - linked_proc_desc_table = pi_ptr->next; - - xfree (pi_ptr); - } -} - -/* To skip prologues, I use this predicate. Returns either PC itself - if the code at PC does not look like a function prologue; otherwise - returns an address that (if we're lucky) follows the prologue. If - LENIENT, then we must skip everything which is involved in setting - up the frame (it's OK to skip more, just so long as we don't skip - anything which might clobber the registers which are being saved. - Currently we must not skip more on the alpha, but we might need the - lenient stuff some day. */ - -static CORE_ADDR -alpha_skip_prologue_internal (CORE_ADDR pc, int lenient) -{ - unsigned long inst; - int offset; - CORE_ADDR post_prologue_pc; - char buf[4]; - - /* 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 (which all - Alpha targets do). */ - if (target_read_memory (pc, buf, 4)) - return pc; - - /* 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 - is greater. */ - - post_prologue_pc = after_prologue (pc, NULL); - - if (post_prologue_pc != 0) - return max (pc, post_prologue_pc); - - /* Can't determine prologue from the symbol table, need to examine - instructions. */ - - /* Skip the typical prologue instructions. These are the stack adjustment - instruction and the instructions that save registers on the stack - or in the gcc frame. */ - for (offset = 0; offset < 100; offset += 4) - { - int status; - - status = read_memory_nobpt (pc + offset, buf, 4); - if (status) - memory_error (status, pc + offset); - inst = extract_unsigned_integer (buf, 4); - - /* The alpha has no delay slots. But let's keep the lenient stuff, - we might need it for something else in the future. */ - if (lenient && 0) - continue; - - if ((inst & 0xffff0000) == 0x27bb0000) /* ldah $gp,n($t12) */ - continue; - if ((inst & 0xffff0000) == 0x23bd0000) /* lda $gp,n($gp) */ - continue; - if ((inst & 0xffff0000) == 0x23de0000) /* lda $sp,n($sp) */ - continue; - if ((inst & 0xffe01fff) == 0x43c0153e) /* subq $sp,n,$sp */ - continue; - - if ((inst & 0xfc1f0000) == 0xb41e0000 - && (inst & 0xffff0000) != 0xb7fe0000) - continue; /* stq reg,n($sp) */ - /* reg != $zero */ - if ((inst & 0xfc1f0000) == 0x9c1e0000 - && (inst & 0xffff0000) != 0x9ffe0000) - continue; /* stt reg,n($sp) */ - /* reg != $zero */ - if (inst == 0x47de040f) /* bis sp,sp,fp */ - continue; - - break; - } - return pc + offset; -} - -static CORE_ADDR -alpha_skip_prologue (CORE_ADDR addr) -{ - return (alpha_skip_prologue_internal (addr, 0)); -} - -#if 0 -/* Is address PC in the prologue (loosely defined) for function at - STARTADDR? */ - -static int -alpha_in_lenient_prologue (CORE_ADDR startaddr, CORE_ADDR pc) -{ - CORE_ADDR end_prologue = alpha_skip_prologue_internal (startaddr, 1); - return pc >= startaddr && pc < end_prologue; -} -#endif - -/* The alpha needs a conversion between register and memory format if - the register is a floating point register and - memory format is float, as the register format must be double - or - memory format is an integer with 4 bytes or less, as the representation - of integers in floating point registers is different. */ -static void -alpha_register_convert_to_virtual (int regnum, struct type *valtype, - char *raw_buffer, char *virtual_buffer) -{ - if (TYPE_LENGTH (valtype) >= REGISTER_RAW_SIZE (regnum)) - { - memcpy (virtual_buffer, raw_buffer, REGISTER_VIRTUAL_SIZE (regnum)); - return; - } - - if (TYPE_CODE (valtype) == TYPE_CODE_FLT) - { - double d = extract_floating (raw_buffer, REGISTER_RAW_SIZE (regnum)); - store_floating (virtual_buffer, TYPE_LENGTH (valtype), d); - } - else if (TYPE_CODE (valtype) == TYPE_CODE_INT && TYPE_LENGTH (valtype) <= 4) - { - ULONGEST l; - l = extract_unsigned_integer (raw_buffer, REGISTER_RAW_SIZE (regnum)); - l = ((l >> 32) & 0xc0000000) | ((l >> 29) & 0x3fffffff); - store_unsigned_integer (virtual_buffer, TYPE_LENGTH (valtype), l); - } - else - error ("Cannot retrieve value from floating point register"); -} - -static void -alpha_register_convert_to_raw (struct type *valtype, int regnum, - char *virtual_buffer, char *raw_buffer) -{ - if (TYPE_LENGTH (valtype) >= REGISTER_RAW_SIZE (regnum)) - { - memcpy (raw_buffer, virtual_buffer, REGISTER_RAW_SIZE (regnum)); - return; - } - - if (TYPE_CODE (valtype) == TYPE_CODE_FLT) - { - double d = extract_floating (virtual_buffer, TYPE_LENGTH (valtype)); - store_floating (raw_buffer, REGISTER_RAW_SIZE (regnum), d); - } - else if (TYPE_CODE (valtype) == TYPE_CODE_INT && TYPE_LENGTH (valtype) <= 4) - { - ULONGEST l; - if (TYPE_UNSIGNED (valtype)) - l = extract_unsigned_integer (virtual_buffer, TYPE_LENGTH (valtype)); - else - l = extract_signed_integer (virtual_buffer, TYPE_LENGTH (valtype)); - l = ((l & 0xc0000000) << 32) | ((l & 0x3fffffff) << 29); - store_unsigned_integer (raw_buffer, REGISTER_RAW_SIZE (regnum), l); - } - else - 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[ALPHA_REGISTER_BYTES], char *valbuf) -{ - if (TYPE_CODE (valtype) == TYPE_CODE_FLT) - alpha_register_convert_to_virtual (FP0_REGNUM, valtype, - regbuf + REGISTER_BYTE (FP0_REGNUM), - valbuf); - else - memcpy (valbuf, regbuf + REGISTER_BYTE (ALPHA_V0_REGNUM), - TYPE_LENGTH (valtype)); -} - -/* Given a return value in `regbuf' with a type `valtype', - write its value into the appropriate register. */ - -static void -alpha_store_return_value (struct type *valtype, char *valbuf) -{ - char raw_buffer[ALPHA_MAX_REGISTER_RAW_SIZE]; - int regnum = ALPHA_V0_REGNUM; - int length = TYPE_LENGTH (valtype); - - if (TYPE_CODE (valtype) == TYPE_CODE_FLT) - { - regnum = FP0_REGNUM; - length = REGISTER_RAW_SIZE (regnum); - alpha_register_convert_to_raw (valtype, regnum, valbuf, raw_buffer); - } - else - memcpy (raw_buffer, valbuf, length); - - write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, length); -} - -/* Just like reinit_frame_cache, but with the right arguments to be - callable as an sfunc. */ - -static void -reinit_frame_cache_sfunc (char *args, int from_tty, struct cmd_list_element *c) -{ - reinit_frame_cache (); -} - -/* This is the definition of CALL_DUMMY_ADDRESS. It's a heuristic that is used - to find a convenient place in the text segment to stick a breakpoint to - detect the completion of a target function call (ala call_function_by_hand). - */ - -CORE_ADDR -alpha_call_dummy_address (void) -{ - CORE_ADDR entry; - struct minimal_symbol *sym; - - entry = entry_point_address (); - - if (entry != 0) - return entry; - - sym = lookup_minimal_symbol ("_Prelude", NULL, symfile_objfile); - - if (!sym || MSYMBOL_TYPE (sym) != mst_text) - return 0; - else - return SYMBOL_VALUE_ADDRESS (sym) + 4; -} - -static void -alpha_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs, - struct value **args, struct type *type, int gcc_p) -{ - CORE_ADDR bp_address = CALL_DUMMY_ADDRESS (); - - if (bp_address == 0) - error ("no place to put call"); - write_register (ALPHA_RA_REGNUM, bp_address); - write_register (ALPHA_T12_REGNUM, fun); -} - -/* On the Alpha, the call dummy code is nevery copied to user space - (see alpha_fix_call_dummy() above). The contents of this do not - matter. */ -LONGEST alpha_call_dummy_words[] = { 0 }; - -static int -alpha_use_struct_convention (int gcc_p, struct type *type) -{ - /* Structures are returned by ref in extra arg0. */ - return 1; -} - -static void -alpha_store_struct_return (CORE_ADDR addr, CORE_ADDR sp) -{ - /* Store the address of the place in which to copy the structure the - subroutine will return. Handled by alpha_push_arguments. */ -} - -static CORE_ADDR -alpha_extract_struct_value_address (char *regbuf) -{ - return (extract_address (regbuf + REGISTER_BYTE (ALPHA_V0_REGNUM), - 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 - the target of the coming instruction and breakpoint it. - - single_step is also called just after the inferior stops. If we had - set up a simulated single-step, we undo our damage. */ - -static CORE_ADDR -alpha_next_pc (CORE_ADDR pc) -{ - unsigned int insn; - unsigned int op; - int offset; - LONGEST rav; - - insn = read_memory_unsigned_integer (pc, sizeof (insn)); - - /* Opcode is top 6 bits. */ - op = (insn >> 26) & 0x3f; - - if (op == 0x1a) - { - /* Jump format: target PC is: - RB & ~3 */ - return (read_register ((insn >> 16) & 0x1f) & ~3); - } - - if ((op & 0x30) == 0x30) - { - /* Branch format: target PC is: - (new PC) + (4 * sext(displacement)) */ - if (op == 0x30 || /* BR */ - op == 0x34) /* BSR */ - { - branch_taken: - offset = (insn & 0x001fffff); - if (offset & 0x00100000) - offset |= 0xffe00000; - offset *= 4; - return (pc + 4 + offset); - } - - /* Need to determine if branch is taken; read RA. */ - rav = (LONGEST) read_register ((insn >> 21) & 0x1f); - switch (op) - { - case 0x38: /* BLBC */ - if ((rav & 1) == 0) - goto branch_taken; - break; - case 0x3c: /* BLBS */ - if (rav & 1) - goto branch_taken; - break; - case 0x39: /* BEQ */ - if (rav == 0) - goto branch_taken; - break; - case 0x3d: /* BNE */ - if (rav != 0) - goto branch_taken; - break; - case 0x3a: /* BLT */ - if (rav < 0) - goto branch_taken; - break; - case 0x3b: /* BLE */ - if (rav <= 0) - goto branch_taken; - break; - case 0x3f: /* BGT */ - if (rav > 0) - goto branch_taken; - break; - case 0x3e: /* BGE */ - if (rav >= 0) - goto branch_taken; - break; - } - } - - /* Not a branch or branch not taken; target PC is: - pc + 4 */ - return (pc + 4); -} - -void -alpha_software_single_step (enum target_signal sig, int insert_breakpoints_p) -{ - static CORE_ADDR next_pc; - typedef char binsn_quantum[BREAKPOINT_MAX]; - static binsn_quantum break_mem; - CORE_ADDR pc; - - if (insert_breakpoints_p) - { - pc = read_pc (); - next_pc = alpha_next_pc (pc); - - target_insert_breakpoint (next_pc, break_mem); - } - else - { - target_remove_breakpoint (next_pc, break_mem); - write_pc (next_pc); - } -} - - - -/* Initialize the current architecture based on INFO. If possible, re-use an - architecture from ARCHES, which is a list of architectures already created - during this debugging session. - - Called e.g. at program startup, when reading a core file, and when reading - a binary file. */ - -static struct gdbarch * -alpha_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) -{ - struct gdbarch_tdep *tdep; - struct gdbarch *gdbarch; - enum gdb_osabi osabi = GDB_OSABI_UNKNOWN; - - /* Try to determine the ABI of the object we are loading. */ - - if (info.abfd != NULL) - { - osabi = gdbarch_lookup_osabi (info.abfd); - if (osabi == GDB_OSABI_UNKNOWN) - { - /* 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; - } - } - - /* 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->osabi == osabi) - return arches->gdbarch; - } - - tdep = xmalloc (sizeof (struct gdbarch_tdep)); - gdbarch = gdbarch_alloc (&info, tdep); - - 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_long_bit (gdbarch, 64); - set_gdbarch_long_long_bit (gdbarch, 64); - set_gdbarch_float_bit (gdbarch, 32); - set_gdbarch_double_bit (gdbarch, 64); - set_gdbarch_long_double_bit (gdbarch, 64); - set_gdbarch_ptr_bit (gdbarch, 64); - - /* Register info */ - set_gdbarch_num_regs (gdbarch, ALPHA_NUM_REGS); - set_gdbarch_sp_regnum (gdbarch, ALPHA_SP_REGNUM); - set_gdbarch_fp_regnum (gdbarch, ALPHA_FP_REGNUM); - set_gdbarch_pc_regnum (gdbarch, ALPHA_PC_REGNUM); - set_gdbarch_fp0_regnum (gdbarch, ALPHA_FP0_REGNUM); - - set_gdbarch_register_name (gdbarch, alpha_register_name); - set_gdbarch_register_size (gdbarch, ALPHA_REGISTER_SIZE); - set_gdbarch_register_bytes (gdbarch, ALPHA_REGISTER_BYTES); - set_gdbarch_register_byte (gdbarch, alpha_register_byte); - set_gdbarch_register_raw_size (gdbarch, alpha_register_raw_size); - set_gdbarch_max_register_raw_size (gdbarch, ALPHA_MAX_REGISTER_RAW_SIZE); - set_gdbarch_register_virtual_size (gdbarch, alpha_register_virtual_size); - set_gdbarch_max_register_virtual_size (gdbarch, - ALPHA_MAX_REGISTER_VIRTUAL_SIZE); - set_gdbarch_register_virtual_type (gdbarch, alpha_register_virtual_type); - - set_gdbarch_cannot_fetch_register (gdbarch, alpha_cannot_fetch_register); - set_gdbarch_cannot_store_register (gdbarch, alpha_cannot_store_register); - - set_gdbarch_register_convertible (gdbarch, alpha_register_convertible); - set_gdbarch_register_convert_to_virtual (gdbarch, - alpha_register_convert_to_virtual); - set_gdbarch_register_convert_to_raw (gdbarch, alpha_register_convert_to_raw); - - set_gdbarch_skip_prologue (gdbarch, alpha_skip_prologue); - - set_gdbarch_frame_num_args (gdbarch, frame_num_args_unknown); - set_gdbarch_frameless_function_invocation (gdbarch, - generic_frameless_function_invocation_not); - - set_gdbarch_saved_pc_after_call (gdbarch, alpha_saved_pc_after_call); - - set_gdbarch_frame_chain (gdbarch, alpha_frame_chain); - set_gdbarch_frame_chain_valid (gdbarch, func_frame_chain_valid); - set_gdbarch_frame_saved_pc (gdbarch, alpha_frame_saved_pc); - - set_gdbarch_frame_init_saved_regs (gdbarch, alpha_frame_init_saved_regs); - - set_gdbarch_use_struct_convention (gdbarch, alpha_use_struct_convention); - set_gdbarch_deprecated_extract_return_value (gdbarch, alpha_extract_return_value); - - set_gdbarch_store_struct_return (gdbarch, alpha_store_struct_return); - set_gdbarch_deprecated_store_return_value (gdbarch, alpha_store_return_value); - set_gdbarch_deprecated_extract_struct_value_address (gdbarch, - alpha_extract_struct_value_address); - - /* Settings for calling functions in the inferior. */ - set_gdbarch_use_generic_dummy_frames (gdbarch, 0); - set_gdbarch_call_dummy_length (gdbarch, 0); - set_gdbarch_push_arguments (gdbarch, alpha_push_arguments); - set_gdbarch_pop_frame (gdbarch, alpha_pop_frame); - - /* On the Alpha, the call dummy code is never copied to user space, - stopping the user call is achieved via a bp_call_dummy breakpoint. - But we need a fake CALL_DUMMY definition to enable the proper - call_function_by_hand and to avoid zero length array warnings. */ - set_gdbarch_call_dummy_p (gdbarch, 1); - set_gdbarch_call_dummy_words (gdbarch, alpha_call_dummy_words); - set_gdbarch_sizeof_call_dummy_words (gdbarch, 0); - set_gdbarch_frame_args_address (gdbarch, alpha_frame_args_address); - set_gdbarch_frame_locals_address (gdbarch, alpha_frame_locals_address); - set_gdbarch_init_extra_frame_info (gdbarch, alpha_init_extra_frame_info); - - /* Alpha OSF/1 inhibits execution of code on the stack. But there is - no need for a dummy on the Alpha. PUSH_ARGUMENTS takes care of all - argument handling and bp_call_dummy takes care of stopping the dummy. */ - set_gdbarch_call_dummy_location (gdbarch, AT_ENTRY_POINT); - set_gdbarch_call_dummy_address (gdbarch, alpha_call_dummy_address); - set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1); - set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 0); - set_gdbarch_call_dummy_start_offset (gdbarch, 0); - set_gdbarch_pc_in_call_dummy (gdbarch, pc_in_call_dummy_at_entry_point); - set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0); - set_gdbarch_push_dummy_frame (gdbarch, alpha_push_dummy_frame); - set_gdbarch_fix_call_dummy (gdbarch, alpha_fix_call_dummy); - set_gdbarch_init_frame_pc (gdbarch, init_frame_pc_noop); - 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. */ - gdbarch_init_osabi (info, gdbarch, osabi); - - /* 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; -} - -static void -alpha_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file) -{ - struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); - - if (tdep == NULL) - return; - - 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 -_initialize_alpha_tdep (void) -{ - struct cmd_list_element *c; - - gdbarch_register (bfd_arch_alpha, alpha_gdbarch_init, alpha_dump_tdep); - - tm_print_insn = print_insn_alpha; - - /* Let the user set the fence post for heuristic_proc_start. */ - - /* We really would like to have both "0" and "unlimited" work, but - command.c doesn't deal with that. So make it a var_zinteger - because the user can always use "999999" or some such for unlimited. */ - c = add_set_cmd ("heuristic-fence-post", class_support, var_zinteger, - (char *) &heuristic_fence_post, - "\ -Set the distance searched for the start of a function.\n\ -If you are debugging a stripped executable, GDB needs to search through the\n\ -program for the start of a function. This command sets the distance of the\n\ -search. The only need to set it is when debugging a stripped executable.", - &setlist); - /* We need to throw away the frame cache when we set this, since it - might change our ability to get backtraces. */ - set_cmd_sfunc (c, reinit_frame_cache_sfunc); - add_show_from_set (c, &showlist); -} |