X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Falpha-tdep.c;h=02062140ecb2562249ee760aeac61e4a06dbefcb;hb=21002a635bf3da33367592e3a3ab3cce24fe5299;hp=0f5f7d7910bd2b6e2489acbde31972cd8b4b1325;hpb=32f6f25d26077d885a4d49b26abf2f7ceadbf334;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/alpha-tdep.c b/gdb/alpha-tdep.c index 0f5f7d7910..02062140ec 100644 --- a/gdb/alpha-tdep.c +++ b/gdb/alpha-tdep.c @@ -1,12 +1,12 @@ /* 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. + + Copyright (C) 1993-2016 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 + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -15,12 +15,14 @@ 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. */ + along with this program. If not, see . */ #include "defs.h" +#include "doublest.h" #include "frame.h" +#include "frame-unwind.h" +#include "frame-base.h" +#include "dwarf2-frame.h" #include "inferior.h" #include "symtab.h" #include "value.h" @@ -29,257 +31,62 @@ #include "dis-asm.h" #include "symfile.h" #include "objfiles.h" -#include "gdb_string.h" #include "linespec.h" #include "regcache.h" -#include "doublest.h" +#include "reggroups.h" #include "arch-utils.h" +#include "osabi.h" +#include "block.h" +#include "infcall.h" +#include "trad-frame.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_store_return_value_ftype alpha_store_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 *); +/* Instruction decoding. The notations for registers, immediates and + opcodes are the same as the one used in Compaq's Alpha architecture + handbook. */ -static alpha_extra_func_info_t push_sigtramp_desc (CORE_ADDR low_addr); +#define INSN_OPCODE(insn) ((insn & 0xfc000000) >> 26) -static CORE_ADDR read_next_frame_reg (struct frame_info *, int); +/* Memory instruction format */ +#define MEM_RA(insn) ((insn & 0x03e00000) >> 21) +#define MEM_RB(insn) ((insn & 0x001f0000) >> 16) +#define MEM_DISP(insn) \ + (((insn & 0x8000) == 0) ? (insn & 0xffff) : -((-insn) & 0xffff)) -static CORE_ADDR heuristic_proc_start (CORE_ADDR); +static const int lda_opcode = 0x08; +static const int stq_opcode = 0x2d; -static alpha_extra_func_info_t heuristic_proc_desc (CORE_ADDR, - CORE_ADDR, - struct frame_info *); +/* Branch instruction format */ +#define BR_RA(insn) MEM_RA(insn) -static alpha_extra_func_info_t find_proc_desc (CORE_ADDR, - struct frame_info *); +static const int br_opcode = 0x30; +static const int bne_opcode = 0x3d; -#if 0 -static int alpha_in_lenient_prologue (CORE_ADDR, CORE_ADDR); -#endif +/* Operate instruction format */ +#define OPR_FUNCTION(insn) ((insn & 0xfe0) >> 5) +#define OPR_HAS_IMMEDIATE(insn) ((insn & 0x1000) == 0x1000) +#define OPR_RA(insn) MEM_RA(insn) +#define OPR_RC(insn) ((insn & 0x1f)) +#define OPR_LIT(insn) ((insn & 0x1fe000) >> 13) -static void reinit_frame_cache_sfunc (char *, int, struct cmd_list_element *); +static const int subq_opcode = 0x10; +static const int subq_function = 0x29; -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); -} +/* Return the name of the REGNO register. -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); -} - + An empty name corresponds to a register number that used to + be used for a virtual register. That virtual register has + been removed, but the index is still reserved to maintain + compatibility with existing remote alpha targets. */ static const char * -alpha_register_name (int regno) +alpha_register_name (struct gdbarch *gdbarch, int regno) { - static char *register_names[] = + static const char * const register_names[] = { "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp", @@ -289,1268 +96,1371 @@ alpha_register_name (int regno) "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", + "pc", "", "unique" }; 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); + return NULL; + if (regno >= ARRAY_SIZE(register_names)) + return NULL; + return register_names[regno]; } static int -alpha_cannot_store_register (int regno) +alpha_cannot_fetch_register (struct gdbarch *gdbarch, int regno) { - return (regno == FP_REGNUM || regno == ALPHA_ZERO_REGNUM); + return (strlen (alpha_register_name (gdbarch, regno)) == 0); } static int -alpha_register_convertible (int regno) +alpha_cannot_store_register (struct gdbarch *gdbarch, int regno) { - return (regno >= FP0_REGNUM && regno <= FP0_REGNUM + 31); + return (regno == ALPHA_ZERO_REGNUM + || strlen (alpha_register_name (gdbarch, regno)) == 0); } static struct type * -alpha_register_virtual_type (int regno) +alpha_register_type (struct gdbarch *gdbarch, int regno) { - return ((regno >= FP0_REGNUM && regno < (FP0_REGNUM+31)) - ? builtin_type_double : builtin_type_long); -} + if (regno == ALPHA_SP_REGNUM || regno == ALPHA_GP_REGNUM) + return builtin_type (gdbarch)->builtin_data_ptr; + if (regno == ALPHA_PC_REGNUM) + return builtin_type (gdbarch)->builtin_func_ptr; -static int -alpha_register_byte (int regno) -{ - return (regno * 8); -} + /* Don't need to worry about little vs big endian until + some jerk tries to port to alpha-unicosmk. */ + if (regno >= ALPHA_FP0_REGNUM && regno < ALPHA_FP0_REGNUM + 31) + return builtin_type (gdbarch)->builtin_double; -static int -alpha_register_raw_size (int regno) -{ - return 8; + return builtin_type (gdbarch)->builtin_int64; } +/* Is REGNUM a member of REGGROUP? */ + static int -alpha_register_virtual_size (int regno) +alpha_register_reggroup_p (struct gdbarch *gdbarch, int regnum, + struct reggroup *group) { - return 8; -} - + /* Filter out any registers eliminated, but whose regnum is + reserved for backward compatibility, e.g. the vfp. */ + if (gdbarch_register_name (gdbarch, regnum) == NULL + || *gdbarch_register_name (gdbarch, regnum) == '\0') + return 0; -static CORE_ADDR -alpha_sigcontext_addr (struct frame_info *fi) -{ - struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); + if (group == all_reggroup) + return 1; + + /* Zero should not be saved or restored. Technically it is a general + register (just as $f31 would be a float if we represented it), but + there's no point displaying it during "info regs", so leave it out + of all groups except for "all". */ + if (regnum == ALPHA_ZERO_REGNUM) + return 0; + + /* All other registers are saved and restored. */ + if (group == save_reggroup || group == restore_reggroup) + return 1; + + /* All other groups are non-overlapping. */ - if (tdep->sigcontext_addr) - return (tdep->sigcontext_addr (fi)); + /* Since this is really a PALcode memory slot... */ + if (regnum == ALPHA_UNIQUE_REGNUM) + return group == system_reggroup; - return (0); + /* Force the FPCR to be considered part of the floating point state. */ + if (regnum == ALPHA_FPCR_REGNUM) + return group == float_reggroup; + + if (regnum >= ALPHA_FP0_REGNUM && regnum < ALPHA_FP0_REGNUM + 31) + return group == float_reggroup; + else + return group == general_reggroup; } -/* Guaranteed to set frame->saved_regs to some values (it never leaves it - NULL). */ +/* The following represents exactly the conversion performed by + the LDS instruction. This applies to both single-precision + floating point and 32-bit integers. */ static void -alpha_find_saved_regs (struct frame_info *frame) +alpha_lds (struct gdbarch *gdbarch, void *out, const void *in) { - 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) + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + ULONGEST mem + = extract_unsigned_integer ((const gdb_byte *) in, 4, byte_order); + ULONGEST frac = (mem >> 0) & 0x7fffff; + ULONGEST sign = (mem >> 31) & 1; + ULONGEST exp_msb = (mem >> 30) & 1; + ULONGEST exp_low = (mem >> 23) & 0x7f; + ULONGEST exp, reg; + + exp = (exp_msb << 10) | exp_low; + if (exp_msb) { - 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; + if (exp_low == 0x7f) + exp = 0x7ff; + } + else + { + if (exp_low != 0x00) + exp |= 0x380; } - 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; + reg = (sign << 63) | (exp << 52) | (frac << 29); + store_unsigned_integer ((gdb_byte *) out, 8, byte_order, reg); +} - /* Fill in the offsets for the registers which gen_mask says - were saved. */ +/* Similarly, this represents exactly the conversion performed by + the STS instruction. */ - reg_position = frame->frame + PROC_REG_OFFSET (proc_desc); - mask = PROC_REG_MASK (proc_desc); +static void +alpha_sts (struct gdbarch *gdbarch, void *out, const void *in) +{ + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + ULONGEST reg, mem; - returnreg = PROC_PC_REG (proc_desc); + reg = extract_unsigned_integer ((const gdb_byte *) in, 8, byte_order); + mem = ((reg >> 32) & 0xc0000000) | ((reg >> 29) & 0x3fffffff); + store_unsigned_integer ((gdb_byte *) out, 4, byte_order, mem); +} - /* 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. */ - } +/* 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. */ - for (ireg = 0; ireg <= 31; ++ireg) - if (mask & (1 << ireg)) - { - frame->saved_regs[ireg] = reg_position; - reg_position += 8; - } +static int +alpha_convert_register_p (struct gdbarch *gdbarch, int regno, + struct type *type) +{ + return (regno >= ALPHA_FP0_REGNUM && regno < ALPHA_FP0_REGNUM + 31 + && TYPE_LENGTH (type) != 8); +} - /* Fill in the offsets for the registers which float_mask says - were saved. */ +static int +alpha_register_to_value (struct frame_info *frame, int regnum, + struct type *valtype, gdb_byte *out, + int *optimizedp, int *unavailablep) +{ + struct gdbarch *gdbarch = get_frame_arch (frame); + gdb_byte in[MAX_REGISTER_SIZE]; - reg_position = frame->frame + PROC_FREG_OFFSET (proc_desc); - mask = PROC_FREG_MASK (proc_desc); + /* Convert to TYPE. */ + if (!get_frame_register_bytes (frame, regnum, 0, + register_size (gdbarch, regnum), + in, optimizedp, unavailablep)) + return 0; - for (ireg = 0; ireg <= 31; ++ireg) - if (mask & (1 << ireg)) - { - frame->saved_regs[FP0_REGNUM + ireg] = reg_position; - reg_position += 8; - } + if (TYPE_LENGTH (valtype) == 4) + { + alpha_sts (gdbarch, out, in); + *optimizedp = *unavailablep = 0; + return 1; + } - frame->saved_regs[PC_REGNUM] = frame->saved_regs[returnreg]; + error (_("Cannot retrieve value from floating point register")); } static void -alpha_frame_init_saved_regs (struct frame_info *fi) +alpha_value_to_register (struct frame_info *frame, int regnum, + struct type *valtype, const gdb_byte *in) { - if (fi->saved_regs == NULL) - alpha_find_saved_regs (fi); - fi->saved_regs[SP_REGNUM] = fi->frame; -} + gdb_byte out[MAX_REGISTER_SIZE]; -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 ()); + switch (TYPE_LENGTH (valtype)) + { + case 4: + alpha_lds (get_frame_arch (frame), out, in); + break; + default: + error (_("Cannot store value in floating point register")); + } + put_frame_register (frame, regnum, out); } + +/* The alpha passes the first six arguments in the registers, the rest on + the stack. The register arguments are stored in ARG_REG_BUFFER, and + then moved into the register file; this simplifies the passing of a + large struct which extends from the registers to the stack, plus avoids + three ptrace invocations per word. + + We don't bother tracking which register values should go in integer + regs or fp regs; we load the same values into both. + + 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 -read_next_frame_reg (struct frame_info *fi, int regno) +alpha_push_dummy_call (struct gdbarch *gdbarch, struct value *function, + struct regcache *regcache, CORE_ADDR bp_addr, + int nargs, struct value **args, CORE_ADDR sp, + int struct_return, CORE_ADDR struct_addr) { - for (; fi; fi = fi->next) + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + int i; + int accumulate_size = struct_return ? 8 : 0; + struct alpha_arg { - /* 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 + const gdb_byte *contents; + int len; + int offset; + }; + struct alpha_arg *alpha_args = XALLOCAVEC (struct alpha_arg, nargs); + struct alpha_arg *m_arg; + gdb_byte arg_reg_buffer[ALPHA_REGISTER_SIZE * ALPHA_NUM_ARG_REGS]; + int required_arg_regs; + CORE_ADDR func_addr = find_function_addr (function, NULL); + + /* The ABI places the address of the called function in T12. */ + regcache_cooked_write_signed (regcache, ALPHA_T12_REGNUM, func_addr); + + /* Set the return address register to point to the entry point + of the program, where a breakpoint lies in wait. */ + regcache_cooked_write_signed (regcache, ALPHA_RA_REGNUM, bp_addr); + + /* Lay out the arguments in memory. */ + 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)) { - if (fi->saved_regs == NULL) - alpha_find_saved_regs (fi); - if (fi->saved_regs[regno]) - return read_memory_integer (fi->saved_regs[regno], 8); + 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) == 4) + { + /* 32-bit values must be sign-extended to 64 bits + even if the base data type is unsigned. */ + arg_type = builtin_type (gdbarch)->builtin_int32; + arg = value_cast (arg_type, arg); + } + if (TYPE_LENGTH (arg_type) < ALPHA_REGISTER_SIZE) + { + arg_type = builtin_type (gdbarch)->builtin_int64; + arg = value_cast (arg_type, arg); + } + break; + + case TYPE_CODE_FLT: + /* "float" arguments loaded in registers must be passed in + register format, aka "double". */ + if (accumulate_size < sizeof (arg_reg_buffer) + && TYPE_LENGTH (arg_type) == 4) + { + arg_type = builtin_type (gdbarch)->builtin_double; + arg = value_cast (arg_type, arg); + } + /* Tru64 5.1 has a 128-bit long double, and passes this by + invisible reference. No one else uses this data type. */ + else if (TYPE_LENGTH (arg_type) == 16) + { + /* Allocate aligned storage. */ + sp = (sp & -16) - 16; + + /* Write the real data into the stack. */ + write_memory (sp, value_contents (arg), 16); + + /* Construct the indirection. */ + arg_type = lookup_pointer_type (arg_type); + arg = value_from_pointer (arg_type, sp); + } + break; + + case TYPE_CODE_COMPLEX: + /* ??? The ABI says that complex values are passed as two + separate scalar values. This distinction only matters + for complex float. However, GCC does not implement this. */ + + /* Tru64 5.1 has a 128-bit long double, and passes this by + invisible reference. */ + if (TYPE_LENGTH (arg_type) == 32) + { + /* Allocate aligned storage. */ + sp = (sp & -16) - 16; + + /* Write the real data into the stack. */ + write_memory (sp, value_contents (arg), 32); + + /* Construct the indirection. */ + arg_type = lookup_pointer_type (arg_type); + arg = value_from_pointer (arg_type, sp); + } + 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); } - 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; + /* 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; - if (proc_desc && PROC_DESC_IS_DUMMY (proc_desc)) - return read_memory_integer (frame->frame - 8, 8); + /* Make room for the arguments on the stack. */ + if (accumulate_size < sizeof(arg_reg_buffer)) + accumulate_size = 0; + else + accumulate_size -= sizeof(arg_reg_buffer); + sp -= accumulate_size; - return read_next_frame_reg (frame, pcreg); -} + /* Keep sp aligned to a multiple of 16 as the ABI requires. */ + sp &= ~15; -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; + /* `Push' arguments on the stack. */ + for (i = nargs; m_arg--, --i >= 0;) + { + const gdb_byte *contents = m_arg->contents; + int offset = m_arg->offset; + int len = m_arg->len; - /* Skip over shared library trampoline if necessary. */ - tmp = SKIP_TRAMPOLINE_CODE (pc); - if (tmp != 0) - pc = tmp; + /* Copy the bytes destined for registers into arg_reg_buffer. */ + if (offset < sizeof(arg_reg_buffer)) + { + if (offset + len <= sizeof(arg_reg_buffer)) + { + memcpy (arg_reg_buffer + offset, contents, len); + continue; + } + else + { + int tlen = sizeof(arg_reg_buffer) - offset; + memcpy (arg_reg_buffer + offset, contents, tlen); + offset += tlen; + contents += tlen; + len -= tlen; + } + } - proc_desc = find_proc_desc (pc, frame->next); - pcreg = proc_desc ? PROC_PC_REG (proc_desc) : ALPHA_RA_REGNUM; + /* Everything else goes to the stack. */ + write_memory (sp + offset - sizeof(arg_reg_buffer), contents, len); + } + if (struct_return) + store_unsigned_integer (arg_reg_buffer, ALPHA_REGISTER_SIZE, + byte_order, struct_addr); - if (frame->signal_handler_caller) - return alpha_frame_saved_pc (frame); - else - return read_register (pcreg); -} + /* Load the argument registers. */ + for (i = 0; i < required_arg_regs; i++) + { + regcache_cooked_write (regcache, ALPHA_A0_REGNUM + i, + arg_reg_buffer + i*ALPHA_REGISTER_SIZE); + regcache_cooked_write (regcache, ALPHA_FPA0_REGNUM + i, + arg_reg_buffer + i*ALPHA_REGISTER_SIZE); + } + /* Finally, update the stack pointer. */ + regcache_cooked_write_signed (regcache, ALPHA_SP_REGNUM, sp); -static struct alpha_extra_func_info temp_proc_desc; -static CORE_ADDR temp_saved_regs[ALPHA_NUM_REGS]; + return sp; +} -/* Nonzero if instruction at PC is a return instruction. "ret - $zero,($ra),1" on alpha. */ +/* Extract from REGCACHE the value about to be returned from a function + and copy it into VALBUF. */ -static int -alpha_about_to_return (CORE_ADDR pc) +static void +alpha_extract_return_value (struct type *valtype, struct regcache *regcache, + gdb_byte *valbuf) { - return read_memory_integer (pc, 4) == 0x6bfa8001; -} + struct gdbarch *gdbarch = get_regcache_arch (regcache); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + gdb_byte raw_buffer[ALPHA_REGISTER_SIZE]; + ULONGEST l; + switch (TYPE_CODE (valtype)) + { + case TYPE_CODE_FLT: + switch (TYPE_LENGTH (valtype)) + { + case 4: + regcache_cooked_read (regcache, ALPHA_FP0_REGNUM, raw_buffer); + alpha_sts (gdbarch, valbuf, raw_buffer); + break; + case 8: + regcache_cooked_read (regcache, ALPHA_FP0_REGNUM, valbuf); + break; -/* This fencepost looks highly suspicious to me. Removing it also - seems suspicious as it could affect remote debugging across serial - lines. */ + case 16: + regcache_cooked_read_unsigned (regcache, ALPHA_V0_REGNUM, &l); + read_memory (l, valbuf, 16); + break; -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; + default: + internal_error (__FILE__, __LINE__, + _("unknown floating point width")); + } + break; - if (start_pc == 0) - return 0; + case TYPE_CODE_COMPLEX: + switch (TYPE_LENGTH (valtype)) + { + case 8: + /* ??? This isn't correct wrt the ABI, but it's what GCC does. */ + regcache_cooked_read (regcache, ALPHA_FP0_REGNUM, valbuf); + break; - if (heuristic_fence_post == UINT_MAX - || fence < tdep->vm_min_address) - fence = tdep->vm_min_address; + case 16: + regcache_cooked_read (regcache, ALPHA_FP0_REGNUM, valbuf); + regcache_cooked_read (regcache, ALPHA_FP0_REGNUM + 1, valbuf + 8); + break; - /* 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)) + case 32: + regcache_cooked_read_unsigned (regcache, ALPHA_V0_REGNUM, &l); + read_memory (l, valbuf, 32); + break; + + default: + internal_error (__FILE__, __LINE__, + _("unknown floating point width")); + } break; - start_pc += 4; /* skip return */ - return start_pc; + default: + /* Assume everything else degenerates to an integer. */ + regcache_cooked_read_unsigned (regcache, ALPHA_V0_REGNUM, &l); + store_unsigned_integer (valbuf, TYPE_LENGTH (valtype), byte_order, l); + break; + } } -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; +/* Insert the given value into REGCACHE as if it was being + returned by a function. */ - 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; +static void +alpha_store_return_value (struct type *valtype, struct regcache *regcache, + const gdb_byte *valbuf) +{ + struct gdbarch *gdbarch = get_regcache_arch (regcache); + gdb_byte raw_buffer[ALPHA_REGISTER_SIZE]; + ULONGEST l; - 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) + switch (TYPE_CODE (valtype)) { - char buf[4]; - unsigned long word; - int status; + case TYPE_CODE_FLT: + switch (TYPE_LENGTH (valtype)) + { + case 4: + alpha_lds (gdbarch, raw_buffer, valbuf); + regcache_cooked_write (regcache, ALPHA_FP0_REGNUM, raw_buffer); + break; + + case 8: + regcache_cooked_write (regcache, ALPHA_FP0_REGNUM, valbuf); + break; - status = read_memory_nobpt (cur_pc, buf, 4); - if (status) - memory_error (status, cur_pc); - word = extract_unsigned_integer (buf, 4); + case 16: + /* FIXME: 128-bit long doubles are returned like structures: + by writing into indirect storage provided by the caller + as the first argument. */ + error (_("Cannot set a 128-bit long double return value.")); - 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; + default: + internal_error (__FILE__, __LINE__, + _("unknown floating point width")); } - 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)) + break; + + case TYPE_CODE_COMPLEX: + switch (TYPE_LENGTH (valtype)) { - char buf[4]; - unsigned long word; + case 8: + /* ??? This isn't correct wrt the ABI, but it's what GCC does. */ + regcache_cooked_write (regcache, ALPHA_FP0_REGNUM, valbuf); + break; - if (read_memory_nobpt (cur_pc, buf, 4)) - break; - cur_pc += 4; - word = extract_unsigned_integer (buf, 4); + case 16: + regcache_cooked_write (regcache, ALPHA_FP0_REGNUM, valbuf); + regcache_cooked_write (regcache, ALPHA_FP0_REGNUM + 1, valbuf + 8); + break; - 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; - } + case 32: + /* FIXME: 128-bit long doubles are returned like structures: + by writing into indirect storage provided by the caller + as the first argument. */ + error (_("Cannot set a 128-bit long double return value.")); + + default: + internal_error (__FILE__, __LINE__, + _("unknown floating point width")); } + break; + + default: + /* Assume everything else degenerates to an integer. */ + /* 32-bit values must be sign-extended to 64 bits + even if the base data type is unsigned. */ + if (TYPE_LENGTH (valtype) == 4) + valtype = builtin_type (gdbarch)->builtin_int32; + l = unpack_long (valtype, valbuf); + regcache_cooked_write_unsigned (regcache, ALPHA_V0_REGNUM, l); + 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++) +static enum return_value_convention +alpha_return_value (struct gdbarch *gdbarch, struct value *function, + struct type *type, struct regcache *regcache, + gdb_byte *readbuf, const gdb_byte *writebuf) +{ + enum type_code code = TYPE_CODE (type); + + if ((code == TYPE_CODE_STRUCT + || code == TYPE_CODE_UNION + || code == TYPE_CODE_ARRAY) + && gdbarch_tdep (gdbarch)->return_in_memory (type)) { - if (reg_mask & 1 << regno) - temp_saved_regs[regno] += vfp; + if (readbuf) + { + ULONGEST addr; + regcache_raw_read_unsigned (regcache, ALPHA_V0_REGNUM, &addr); + read_memory (addr, readbuf, TYPE_LENGTH (type)); + } + + return RETURN_VALUE_ABI_RETURNS_ADDRESS; } - 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; + if (readbuf) + alpha_extract_return_value (type, regcache, readbuf); + if (writebuf) + alpha_store_return_value (type, regcache, writebuf); + + return RETURN_VALUE_REGISTER_CONVENTION; } -/* This returns the PC of the first inst after the prologue. If we can't - find the prologue, then return 0. */ +static int +alpha_return_in_memory_always (struct type *type) +{ + return 1; +} + +static const gdb_byte * +alpha_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pc, int *len) +{ + static const gdb_byte break_insn[] = { 0x80, 0, 0, 0 }; /* call_pal bpt */ -static CORE_ADDR -after_prologue (CORE_ADDR pc, alpha_extra_func_info_t proc_desc) + *len = sizeof(break_insn); + return break_insn; +} + + +/* This returns the PC of the first insn after the prologue. + If we can't find the prologue, then return 0. */ + +CORE_ADDR +alpha_after_prologue (CORE_ADDR pc) { 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 */ + return 0; 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. */ +/* Read an instruction from memory at PC, looking through breakpoints. */ -static int -alpha_in_prologue (CORE_ADDR pc, alpha_extra_func_info_t proc_desc) +unsigned int +alpha_read_insn (struct gdbarch *gdbarch, CORE_ADDR pc) { - 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; + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + gdb_byte buf[ALPHA_INSN_SIZE]; + int res; + + res = target_read_memory (pc, buf, sizeof (buf)); + if (res != 0) + memory_error (TARGET_XFER_E_IO, pc); + return extract_unsigned_integer (buf, sizeof (buf), byte_order); } -static alpha_extra_func_info_t -find_proc_desc (CORE_ADDR pc, struct frame_info *next_frame) +/* 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. */ + +static CORE_ADDR +alpha_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc) { - 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; + unsigned long inst; + int offset; + CORE_ADDR post_prologue_pc; + gdb_byte buf[ALPHA_INSN_SIZE]; - 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; - } + /* 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, sizeof (buf))) + return pc; - b = block_for_pc (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. */ - find_pc_partial_function (pc, NULL, &startaddr, NULL); - if (b == NULL) - sym = NULL; - else + post_prologue_pc = alpha_after_prologue (pc); + 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 += ALPHA_INSN_SIZE) { - 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); + inst = alpha_read_insn (gdbarch, pc + offset); + + 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 /* stq reg,n($sp) */ + || (inst & 0xfc1f0000) == 0x9c1e0000) /* stt reg,n($sp) */ + && (inst & 0x03e00000) != 0x03e00000) /* reg != $zero */ + continue; + + if (inst == 0x47de040f) /* bis sp,sp,fp */ + continue; + if (inst == 0x47fe040f) /* bis zero,sp,fp */ + continue; + + break; } + return pc + offset; +} - /* 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; + +static const int ldl_l_opcode = 0x2a; +static const int ldq_l_opcode = 0x2b; +static const int stl_c_opcode = 0x2e; +static const int stq_c_opcode = 0x2f; + +/* Checks for an atomic sequence of instructions beginning with a LDL_L/LDQ_L + instruction and ending with a STL_C/STQ_C instruction. If such a sequence + is found, attempt to step through it. A breakpoint is placed at the end of + the sequence. */ + +static int +alpha_deal_with_atomic_sequence (struct frame_info *frame) +{ + struct gdbarch *gdbarch = get_frame_arch (frame); + struct address_space *aspace = get_frame_address_space (frame); + CORE_ADDR pc = get_frame_pc (frame); + CORE_ADDR breaks[2] = {-1, -1}; + CORE_ADDR loc = pc; + CORE_ADDR closing_insn; /* Instruction that closes the atomic sequence. */ + unsigned int insn = alpha_read_insn (gdbarch, loc); + int insn_count; + int index; + int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed). */ + const int atomic_sequence_length = 16; /* Instruction sequence length. */ + int bc_insn_count = 0; /* Conditional branch instruction count. */ + + /* Assume all atomic sequences start with a LDL_L/LDQ_L instruction. */ + if (INSN_OPCODE (insn) != ldl_l_opcode + && INSN_OPCODE (insn) != ldq_l_opcode) + return 0; - if (sym) + /* Assume that no atomic sequence is longer than "atomic_sequence_length" + instructions. */ + for (insn_count = 0; insn_count < atomic_sequence_length; ++insn_count) { - /* 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) + loc += ALPHA_INSN_SIZE; + insn = alpha_read_insn (gdbarch, loc); + + /* Assume that there is at most one branch in the atomic + sequence. If a branch is found, put a breakpoint in + its destination address. */ + if (INSN_OPCODE (insn) >= br_opcode) { - 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; - } - } + int immediate = (insn & 0x001fffff) << 2; + + immediate = (immediate ^ 0x400000) - 0x400000; + + if (bc_insn_count >= 1) + return 0; /* More than one branch found, fallback + to the standard single-step code. */ + + breaks[1] = loc + ALPHA_INSN_SIZE + immediate; + + bc_insn_count++; + last_breakpoint++; } + + if (INSN_OPCODE (insn) == stl_c_opcode + || INSN_OPCODE (insn) == stq_c_opcode) + break; } - 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; + + /* Assume that the atomic sequence ends with a STL_C/STQ_C instruction. */ + if (INSN_OPCODE (insn) != stl_c_opcode + && INSN_OPCODE (insn) != stq_c_opcode) + return 0; + + closing_insn = loc; + loc += ALPHA_INSN_SIZE; + + /* Insert a breakpoint right after the end of the atomic sequence. */ + breaks[0] = loc; + + /* Check for duplicated breakpoints. Check also for a breakpoint + placed (branch instruction's destination) anywhere in sequence. */ + if (last_breakpoint + && (breaks[1] == breaks[0] + || (breaks[1] >= pc && breaks[1] <= closing_insn))) + last_breakpoint = 0; + + /* Effectively inserts the breakpoints. */ + for (index = 0; index <= last_breakpoint; index++) + insert_single_step_breakpoint (gdbarch, aspace, breaks[index]); + + return 1; } -alpha_extra_func_info_t cached_proc_desc; + +/* 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 CORE_ADDR -alpha_frame_chain (struct frame_info *frame) +static int +alpha_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc) { - alpha_extra_func_info_t proc_desc; - CORE_ADDR saved_pc = FRAME_SAVED_PC (frame); + struct gdbarch *gdbarch = get_frame_arch (frame); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + CORE_ADDR jb_addr; + gdb_byte raw_buffer[ALPHA_REGISTER_SIZE]; - if (saved_pc == 0 || inside_entry_file (saved_pc)) - return 0; + jb_addr = get_frame_register_unsigned (frame, ALPHA_A0_REGNUM); - proc_desc = find_proc_desc (saved_pc, frame); - if (!proc_desc) + if (target_read_memory (jb_addr + (tdep->jb_pc * tdep->jb_elt_size), + raw_buffer, tdep->jb_elt_size)) 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); + *pc = extract_unsigned_integer (raw_buffer, tdep->jb_elt_size, byte_order); + return 1; } -void -alpha_print_extra_frame_info (struct frame_info *fi) + +/* Frame unwinder for signal trampolines. We use alpha tdep bits that + describe the location and shape of the sigcontext structure. After + that, all registers are in memory, so it's easy. */ +/* ??? Shouldn't we be able to do this generically, rather than with + OSABI data specific to Alpha? */ + +struct alpha_sigtramp_unwind_cache { - 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)); + CORE_ADDR sigcontext_addr; +}; + +static struct alpha_sigtramp_unwind_cache * +alpha_sigtramp_frame_unwind_cache (struct frame_info *this_frame, + void **this_prologue_cache) +{ + struct alpha_sigtramp_unwind_cache *info; + struct gdbarch_tdep *tdep; + + if (*this_prologue_cache) + return (struct alpha_sigtramp_unwind_cache *) *this_prologue_cache; + + info = FRAME_OBSTACK_ZALLOC (struct alpha_sigtramp_unwind_cache); + *this_prologue_cache = info; + + tdep = gdbarch_tdep (get_frame_arch (this_frame)); + info->sigcontext_addr = tdep->sigcontext_addr (this_frame); + + return info; +} + +/* Return the address of REGNUM in a sigtramp frame. Since this is + all arithmetic, it doesn't seem worthwhile to cache it. */ + +static CORE_ADDR +alpha_sigtramp_register_address (struct gdbarch *gdbarch, + CORE_ADDR sigcontext_addr, int regnum) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + if (regnum >= 0 && regnum < 32) + return sigcontext_addr + tdep->sc_regs_offset + regnum * 8; + else if (regnum >= ALPHA_FP0_REGNUM && regnum < ALPHA_FP0_REGNUM + 32) + return sigcontext_addr + tdep->sc_fpregs_offset + regnum * 8; + else if (regnum == ALPHA_PC_REGNUM) + return sigcontext_addr + tdep->sc_pc_offset; + + return 0; } +/* Given a GDB frame, determine the address of the calling function's + frame. This will be used to create a new GDB frame struct. */ + static void -alpha_init_extra_frame_info (int fromleaf, struct frame_info *frame) +alpha_sigtramp_frame_this_id (struct frame_info *this_frame, + void **this_prologue_cache, + struct frame_id *this_id) { - /* 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) + struct gdbarch *gdbarch = get_frame_arch (this_frame); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + struct alpha_sigtramp_unwind_cache *info + = alpha_sigtramp_frame_unwind_cache (this_frame, this_prologue_cache); + CORE_ADDR stack_addr, code_addr; + + /* If the OSABI couldn't locate the sigcontext, give up. */ + if (info->sigcontext_addr == 0) + return; + + /* If we have dynamic signal trampolines, find their start. + If we do not, then we must assume there is a symbol record + that can provide the start address. */ + if (tdep->dynamic_sigtramp_offset) { - /* 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); + int offset; + code_addr = get_frame_pc (this_frame); + offset = tdep->dynamic_sigtramp_offset (gdbarch, code_addr); + if (offset >= 0) + code_addr -= offset; 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]; - } - } + code_addr = 0; } -} + else + code_addr = get_frame_func (this_frame); -static CORE_ADDR -alpha_frame_locals_address (struct frame_info *fi) -{ - return (fi->frame - fi->extra_info->localoff); + /* The stack address is trivially read from the sigcontext. */ + stack_addr = alpha_sigtramp_register_address (gdbarch, info->sigcontext_addr, + ALPHA_SP_REGNUM); + stack_addr = get_frame_memory_unsigned (this_frame, stack_addr, + ALPHA_REGISTER_SIZE); + + *this_id = frame_id_build (stack_addr, code_addr); } -static CORE_ADDR -alpha_frame_args_address (struct frame_info *fi) +/* Retrieve the value of REGNUM in FRAME. Don't give up! */ + +static struct value * +alpha_sigtramp_frame_prev_register (struct frame_info *this_frame, + void **this_prologue_cache, int regnum) { - return (fi->frame - (ALPHA_NUM_ARG_REGS * 8)); + struct alpha_sigtramp_unwind_cache *info + = alpha_sigtramp_frame_unwind_cache (this_frame, this_prologue_cache); + CORE_ADDR addr; + + if (info->sigcontext_addr != 0) + { + /* All integer and fp registers are stored in memory. */ + addr = alpha_sigtramp_register_address (get_frame_arch (this_frame), + info->sigcontext_addr, regnum); + if (addr != 0) + return frame_unwind_got_memory (this_frame, regnum, addr); + } + + /* This extra register may actually be in the sigcontext, but our + current description of it in alpha_sigtramp_frame_unwind_cache + doesn't include it. Too bad. Fall back on whatever's in the + outer frame. */ + return frame_unwind_got_register (this_frame, regnum, regnum); } -/* 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. +static int +alpha_sigtramp_frame_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, + void **this_prologue_cache) +{ + struct gdbarch *gdbarch = get_frame_arch (this_frame); + CORE_ADDR pc = get_frame_pc (this_frame); + const char *name; - 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. + /* NOTE: cagney/2004-04-30: Do not copy/clone this code. Instead + look at tramp-frame.h and other simplier per-architecture + sigtramp unwinders. */ - 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. */ + /* We shouldn't even bother to try if the OSABI didn't register a + sigcontext_addr handler or pc_in_sigtramp hander. */ + if (gdbarch_tdep (gdbarch)->sigcontext_addr == NULL) + return 0; + if (gdbarch_tdep (gdbarch)->pc_in_sigtramp == NULL) + return 0; -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"); + /* Otherwise we should be in a signal frame. */ + find_pc_partial_function (pc, &name, NULL, NULL); + if (gdbarch_tdep (gdbarch)->pc_in_sigtramp (gdbarch, pc, name)) + return 1; - return create_new_frame (argv[0], argv[1]); + return 0; } -/* 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 const struct frame_unwind alpha_sigtramp_frame_unwind = { + SIGTRAMP_FRAME, + default_frame_unwind_stop_reason, + alpha_sigtramp_frame_this_id, + alpha_sigtramp_frame_prev_register, + NULL, + alpha_sigtramp_frame_sniffer +}; + + + +/* 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 int heuristic_fence_post = 0; + +/* Attempt to locate the start of the function containing PC. We assume that + the previous function ends with an about_to_return insn. Not foolproof by + any means, since gcc is happy to put the epilogue in the middle of a + function. But we're guessing anyway... */ static CORE_ADDR -alpha_push_arguments (int nargs, struct value **args, CORE_ADDR sp, - int struct_return, CORE_ADDR struct_addr) +alpha_heuristic_proc_start (struct gdbarch *gdbarch, CORE_ADDR pc) { - 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; + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + CORE_ADDR last_non_nop = pc; + CORE_ADDR fence = pc - heuristic_fence_post; + CORE_ADDR orig_pc = pc; + CORE_ADDR func; + struct inferior *inf; + + if (pc == 0) + return 0; - 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); - } + /* First see if we can find the start of the function from minimal + symbol information. This can succeed with a binary that doesn't + have debug info, but hasn't been stripped. */ + func = get_pc_function_start (pc); + if (func) + return func; + + if (heuristic_fence_post == -1 + || fence < tdep->vm_min_address) + fence = tdep->vm_min_address; + + /* Search back for previous return; also stop at a 0, which might be + seen for instance before the start of a code section. Don't include + nops, since this usually indicates padding between functions. */ + for (pc -= ALPHA_INSN_SIZE; pc >= fence; pc -= ALPHA_INSN_SIZE) + { + unsigned int insn = alpha_read_insn (gdbarch, pc); + switch (insn) + { + case 0: /* invalid insn */ + case 0x6bfa8001: /* ret $31,($26),1 */ + return last_non_nop; + + case 0x2ffe0000: /* unop: ldq_u $31,0($30) */ + case 0x47ff041f: /* nop: bis $31,$31,$31 */ break; + default: + last_non_nop = pc; 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; + inf = current_inferior (); - /* `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) + /* It's not clear to me why we reach this point when stopping 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 (inf->control.stop_soon == NO_STOP_QUIETLY) { - store_address (raw_buffer, sizeof (CORE_ADDR), struct_addr); - write_memory (sp, raw_buffer, sizeof (CORE_ADDR)); - } + static int blurb_printed = 0; - /* Load the argument registers. */ - for (i = 0; i < required_arg_regs; i++) - { - LONGEST val; + if (fence == tdep->vm_min_address) + warning (_("Hit beginning of text section without finding \ +enclosing function for address %s"), paddress (gdbarch, orig_pc)); + else + warning (_("Hit heuristic-fence-post without finding \ +enclosing function for address %s"), paddress (gdbarch, orig_pc)); - val = read_memory_integer (sp + i * 8, 8); - write_register (ALPHA_A0_REGNUM + i, val); - write_register (ALPHA_FPA0_REGNUM + i, val); + 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 sp + arg_regs_size; + return 0; } -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<>= 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; -} +/* Fallback alpha frame unwinder. Uses instruction scanning and knows + something about the traditional layout of alpha stack frames. */ + +struct alpha_heuristic_unwind_cache +{ + CORE_ADDR vfp; + CORE_ADDR start_pc; + struct trad_frame_saved_reg *saved_regs; + int return_reg; +}; + +/* If a probing loop sequence starts at PC, simulate it and compute + FRAME_SIZE and PC after its execution. Otherwise, return with PC and + FRAME_SIZE unchanged. */ static void -alpha_pop_frame (void) +alpha_heuristic_analyze_probing_loop (struct gdbarch *gdbarch, CORE_ADDR *pc, + int *frame_size) { - register int regnum; - struct frame_info *frame = get_current_frame (); - CORE_ADDR new_sp = frame->frame; + CORE_ADDR cur_pc = *pc; + int cur_frame_size = *frame_size; + int nb_of_iterations, reg_index, reg_probe; + unsigned int insn; - alpha_extra_func_info_t proc_desc = frame->extra_info->proc_desc; + /* The following pattern is recognized as a probing loop: - /* 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); + lda REG_INDEX,NB_OF_ITERATIONS + lda REG_PROBE,(sp) - /* 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... */ + LOOP_START: + stq zero,(REG_PROBE) + subq REG_INDEX,0x1,REG_INDEX + lda REG_PROBE,(REG_PROBE) + bne REG_INDEX, LOOP_START + + lda sp,(REG_PROBE) - 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 anything different is found, the function returns without + changing PC and FRAME_SIZE. Otherwise, PC will point immediately + after this sequence, and FRAME_SIZE will be updated. */ - 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; + /* lda REG_INDEX,NB_OF_ITERATIONS */ - 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; - } + insn = alpha_read_insn (gdbarch, cur_pc); + if (INSN_OPCODE (insn) != lda_opcode) + return; + reg_index = MEM_RA (insn); + nb_of_iterations = MEM_DISP (insn); - if (pi_ptr == NULL) - error ("Can't locate dummy extra frame info\n"); + /* lda REG_PROBE,(sp) */ - if (prev_ptr != NULL) - prev_ptr->next = pi_ptr->next; - else - linked_proc_desc_table = pi_ptr->next; + cur_pc += ALPHA_INSN_SIZE; + insn = alpha_read_insn (gdbarch, cur_pc); + if (INSN_OPCODE (insn) != lda_opcode + || MEM_RB (insn) != ALPHA_SP_REGNUM) + return; + reg_probe = MEM_RA (insn); + cur_frame_size -= MEM_DISP (insn); + + /* stq zero,(REG_PROBE) */ + + cur_pc += ALPHA_INSN_SIZE; + insn = alpha_read_insn (gdbarch, cur_pc); + if (INSN_OPCODE (insn) != stq_opcode + || MEM_RA (insn) != 0x1f + || MEM_RB (insn) != reg_probe) + return; + + /* subq REG_INDEX,0x1,REG_INDEX */ + + cur_pc += ALPHA_INSN_SIZE; + insn = alpha_read_insn (gdbarch, cur_pc); + if (INSN_OPCODE (insn) != subq_opcode + || !OPR_HAS_IMMEDIATE (insn) + || OPR_FUNCTION (insn) != subq_function + || OPR_LIT(insn) != 1 + || OPR_RA (insn) != reg_index + || OPR_RC (insn) != reg_index) + return; + + /* lda REG_PROBE,(REG_PROBE) */ + + cur_pc += ALPHA_INSN_SIZE; + insn = alpha_read_insn (gdbarch, cur_pc); + if (INSN_OPCODE (insn) != lda_opcode + || MEM_RA (insn) != reg_probe + || MEM_RB (insn) != reg_probe) + return; + cur_frame_size -= MEM_DISP (insn) * nb_of_iterations; - xfree (pi_ptr); - } + /* bne REG_INDEX, LOOP_START */ + + cur_pc += ALPHA_INSN_SIZE; + insn = alpha_read_insn (gdbarch, cur_pc); + if (INSN_OPCODE (insn) != bne_opcode + || MEM_RA (insn) != reg_index) + return; + + /* lda sp,(REG_PROBE) */ + + cur_pc += ALPHA_INSN_SIZE; + insn = alpha_read_insn (gdbarch, cur_pc); + if (INSN_OPCODE (insn) != lda_opcode + || MEM_RA (insn) != ALPHA_SP_REGNUM + || MEM_RB (insn) != reg_probe) + return; + cur_frame_size -= MEM_DISP (insn); + + *pc = cur_pc; + *frame_size = cur_frame_size; } - -/* 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) +static struct alpha_heuristic_unwind_cache * +alpha_heuristic_frame_unwind_cache (struct frame_info *this_frame, + void **this_prologue_cache, + CORE_ADDR start_pc) { - 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; + struct gdbarch *gdbarch = get_frame_arch (this_frame); + struct alpha_heuristic_unwind_cache *info; + ULONGEST val; + CORE_ADDR limit_pc, cur_pc; + int frame_reg, frame_size, return_reg, reg; - /* 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. */ + if (*this_prologue_cache) + return (struct alpha_heuristic_unwind_cache *) *this_prologue_cache; - post_prologue_pc = after_prologue (pc, NULL); + info = FRAME_OBSTACK_ZALLOC (struct alpha_heuristic_unwind_cache); + *this_prologue_cache = info; + info->saved_regs = trad_frame_alloc_saved_regs (this_frame); - if (post_prologue_pc != 0) - return max (pc, post_prologue_pc); + limit_pc = get_frame_pc (this_frame); + if (start_pc == 0) + start_pc = alpha_heuristic_proc_start (gdbarch, limit_pc); + info->start_pc = start_pc; - /* Can't determine prologue from the symbol table, need to examine - instructions. */ + frame_reg = ALPHA_SP_REGNUM; + frame_size = 0; + return_reg = -1; - /* 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) + /* If we've identified a likely place to start, do code scanning. */ + if (start_pc != 0) { - int status; + /* Limit the forward search to 50 instructions. */ + if (start_pc + 200 < limit_pc) + limit_pc = start_pc + 200; - status = read_memory_nobpt (pc + offset, buf, 4); - if (status) - memory_error (status, pc + offset); - inst = extract_unsigned_integer (buf, 4); + for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += ALPHA_INSN_SIZE) + { + unsigned int word = alpha_read_insn (gdbarch, cur_pc); - /* 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 ((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) */ + { + reg = (word & 0x03e00000) >> 21; + + /* Ignore this instruction if we have already encountered + an instruction saving the same register earlier in the + function code. The current instruction does not tell + us where the original value upon function entry is saved. + All it says is that the function we are scanning reused + that register for some computation of its own, and is now + saving its result. */ + if (trad_frame_addr_p(info->saved_regs, reg)) + continue; + + if (reg == 31) + continue; + + /* 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. */ + /* Hack: temporarily add one, so that the offset is non-zero + and we can tell which registers have save offsets below. */ + info->saved_regs[reg].addr = (word & 0xffff) + 1; + + /* 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 + 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 (return_reg == -1 + && cur_pc < (start_pc + 80) + && (reg == ALPHA_T7_REGNUM + || reg == ALPHA_T9_REGNUM + || reg == ALPHA_RA_REGNUM)) + return_reg = reg; + } + else if ((word & 0xffe0ffff) == 0x6be08001) /* ret zero,reg,1 */ + return_reg = (word >> 16) & 0x1f; + else if (word == 0x47de040f) /* bis sp,sp,fp */ + frame_reg = ALPHA_GCC_FP_REGNUM; + else if (word == 0x47fe040f) /* bis zero,sp,fp */ + frame_reg = ALPHA_GCC_FP_REGNUM; - 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; + alpha_heuristic_analyze_probing_loop (gdbarch, &cur_pc, &frame_size); + } - 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; + /* If we haven't found a valid return address register yet, keep + searching in the procedure prologue. */ + if (return_reg == -1) + { + while (cur_pc < (limit_pc + 80) && cur_pc < (start_pc + 80)) + { + unsigned int word = alpha_read_insn (gdbarch, cur_pc); - break; - } - return pc + offset; -} + if ((word & 0xfc1f0000) == 0xb41e0000) /* stq reg,n($sp) */ + { + reg = (word & 0x03e00000) >> 21; + if (reg == ALPHA_T7_REGNUM + || reg == ALPHA_T9_REGNUM + || reg == ALPHA_RA_REGNUM) + { + return_reg = reg; + break; + } + } + else if ((word & 0xffe0ffff) == 0x6be08001) /* ret zero,reg,1 */ + { + return_reg = (word >> 16) & 0x1f; + break; + } -static CORE_ADDR -alpha_skip_prologue (CORE_ADDR addr) -{ - return (alpha_skip_prologue_internal (addr, 0)); -} + cur_pc += ALPHA_INSN_SIZE; + } + } + } -#if 0 -/* Is address PC in the prologue (loosely defined) for function at - STARTADDR? */ + /* Failing that, do default to the customary RA. */ + if (return_reg == -1) + return_reg = ALPHA_RA_REGNUM; + info->return_reg = return_reg; -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; - } + val = get_frame_register_unsigned (this_frame, frame_reg); + info->vfp = val + frame_size; - 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"); -} + /* Convert offsets to absolute addresses. See above about adding + one to the offsets to make all detected offsets non-zero. */ + for (reg = 0; reg < ALPHA_NUM_REGS; ++reg) + if (trad_frame_addr_p(info->saved_regs, reg)) + info->saved_regs[reg].addr += val - 1; -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; - } + /* The stack pointer of the previous frame is computed by popping + the current stack frame. */ + if (!trad_frame_addr_p (info->saved_regs, ALPHA_SP_REGNUM)) + trad_frame_set_value (info->saved_regs, ALPHA_SP_REGNUM, info->vfp); - 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"); + return info; } -static const unsigned char * -alpha_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr) +/* Given a GDB frame, determine the address of the calling function's + frame. This will be used to create a new GDB frame struct. */ + +static void +alpha_heuristic_frame_this_id (struct frame_info *this_frame, + void **this_prologue_cache, + struct frame_id *this_id) { - static const unsigned char alpha_breakpoint[] = - { 0x80, 0, 0, 0 }; /* call_pal bpt */ + struct alpha_heuristic_unwind_cache *info + = alpha_heuristic_frame_unwind_cache (this_frame, this_prologue_cache, 0); - *lenptr = sizeof(alpha_breakpoint); - return (alpha_breakpoint); + *this_id = frame_id_build (info->vfp, info->start_pc); } -/* Given a return value in `regbuf' with a type `valtype', - extract and copy its value into `valbuf'. */ +/* Retrieve the value of REGNUM in FRAME. Don't give up! */ -static void -alpha_extract_return_value (struct type *valtype, - char regbuf[ALPHA_REGISTER_BYTES], char *valbuf) +static struct value * +alpha_heuristic_frame_prev_register (struct frame_info *this_frame, + void **this_prologue_cache, int regnum) { - 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)); + struct alpha_heuristic_unwind_cache *info + = alpha_heuristic_frame_unwind_cache (this_frame, this_prologue_cache, 0); + + /* The PC of the previous frame is stored in the link register of + the current frame. Frob regnum so that we pull the value from + the correct place. */ + if (regnum == ALPHA_PC_REGNUM) + regnum = info->return_reg; + + return trad_frame_get_prev_register (this_frame, info->saved_regs, regnum); } -/* Given a return value in `regbuf' with a type `valtype', - write its value into the appropriate register. */ +static const struct frame_unwind alpha_heuristic_frame_unwind = { + NORMAL_FRAME, + default_frame_unwind_stop_reason, + alpha_heuristic_frame_this_id, + alpha_heuristic_frame_prev_register, + NULL, + default_frame_sniffer +}; -static void -alpha_store_return_value (struct type *valtype, char *valbuf) +static CORE_ADDR +alpha_heuristic_frame_base_address (struct frame_info *this_frame, + void **this_prologue_cache) { - 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); + struct alpha_heuristic_unwind_cache *info + = alpha_heuristic_frame_unwind_cache (this_frame, this_prologue_cache, 0); - write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, length); + return info->vfp; } +static const struct frame_base alpha_heuristic_frame_base = { + &alpha_heuristic_frame_unwind, + alpha_heuristic_frame_base_address, + alpha_heuristic_frame_base_address, + alpha_heuristic_frame_base_address +}; + /* Just like reinit_frame_cache, but with the right arguments to be - callable as an sfunc. */ + callable as an sfunc. Used by the "set heuristic-fence-post" command. */ static void reinit_frame_cache_sfunc (char *args, int from_tty, struct cmd_list_element *c) @@ -1558,135 +1468,190 @@ 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). - */ + +/* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that + dummy frame. The frame ID's base needs to match the TOS value + saved by save_dummy_frame_tos(), and the PC match the dummy frame's + breakpoint. */ -CORE_ADDR -alpha_call_dummy_address (void) +static struct frame_id +alpha_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame) +{ + ULONGEST base; + base = get_frame_register_unsigned (this_frame, ALPHA_SP_REGNUM); + return frame_id_build (base, get_frame_pc (this_frame)); +} + +static CORE_ADDR +alpha_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) { - CORE_ADDR entry; - struct minimal_symbol *sym; + ULONGEST pc; + pc = frame_unwind_register_unsigned (next_frame, ALPHA_PC_REGNUM); + return pc; +} - entry = entry_point_address (); + +/* Helper routines for alpha*-nat.c files to move register sets to and + from core files. The UNIQUE pointer is allowed to be NULL, as most + targets don't supply this value in their core files. */ - if (entry != 0) - return entry; +void +alpha_supply_int_regs (struct regcache *regcache, int regno, + const void *r0_r30, const void *pc, const void *unique) +{ + const gdb_byte *regs = (const gdb_byte *) r0_r30; + int i; - sym = lookup_minimal_symbol ("_Prelude", NULL, symfile_objfile); + for (i = 0; i < 31; ++i) + if (regno == i || regno == -1) + regcache_raw_supply (regcache, i, regs + i * 8); - if (!sym || MSYMBOL_TYPE (sym) != mst_text) - return 0; - else - return SYMBOL_VALUE_ADDRESS (sym) + 4; + if (regno == ALPHA_ZERO_REGNUM || regno == -1) + { + const gdb_byte zero[8] = { 0 }; + + regcache_raw_supply (regcache, ALPHA_ZERO_REGNUM, zero); + } + + if (regno == ALPHA_PC_REGNUM || regno == -1) + regcache_raw_supply (regcache, ALPHA_PC_REGNUM, pc); + + if (regno == ALPHA_UNIQUE_REGNUM || regno == -1) + regcache_raw_supply (regcache, ALPHA_UNIQUE_REGNUM, unique); } -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) +void +alpha_fill_int_regs (const struct regcache *regcache, + int regno, void *r0_r30, void *pc, void *unique) { - CORE_ADDR bp_address = CALL_DUMMY_ADDRESS (); + gdb_byte *regs = (gdb_byte *) r0_r30; + int i; - if (bp_address == 0) - error ("no place to put call"); - write_register (ALPHA_RA_REGNUM, bp_address); - write_register (ALPHA_T12_REGNUM, fun); -} + for (i = 0; i < 31; ++i) + if (regno == i || regno == -1) + regcache_raw_collect (regcache, i, regs + i * 8); -/* 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 }; + if (regno == ALPHA_PC_REGNUM || regno == -1) + regcache_raw_collect (regcache, ALPHA_PC_REGNUM, pc); -static int -alpha_use_struct_convention (int gcc_p, struct type *type) -{ - /* Structures are returned by ref in extra arg0. */ - return 1; + if (unique && (regno == ALPHA_UNIQUE_REGNUM || regno == -1)) + regcache_raw_collect (regcache, ALPHA_UNIQUE_REGNUM, unique); } -static void -alpha_store_struct_return (CORE_ADDR addr, CORE_ADDR sp) +void +alpha_supply_fp_regs (struct regcache *regcache, int regno, + const void *f0_f30, const void *fpcr) { - /* Store the address of the place in which to copy the structure the - subroutine will return. Handled by alpha_push_arguments. */ + const gdb_byte *regs = (const gdb_byte *) f0_f30; + int i; + + for (i = ALPHA_FP0_REGNUM; i < ALPHA_FP0_REGNUM + 31; ++i) + if (regno == i || regno == -1) + regcache_raw_supply (regcache, i, + regs + (i - ALPHA_FP0_REGNUM) * 8); + + if (regno == ALPHA_FPCR_REGNUM || regno == -1) + regcache_raw_supply (regcache, ALPHA_FPCR_REGNUM, fpcr); } -static CORE_ADDR -alpha_extract_struct_value_address (char *regbuf) +void +alpha_fill_fp_regs (const struct regcache *regcache, + int regno, void *f0_f30, void *fpcr) { - return (extract_address (regbuf + REGISTER_BYTE (ALPHA_V0_REGNUM), - REGISTER_RAW_SIZE (ALPHA_V0_REGNUM))); + gdb_byte *regs = (gdb_byte *) f0_f30; + int i; + + for (i = ALPHA_FP0_REGNUM; i < ALPHA_FP0_REGNUM + 31; ++i) + if (regno == i || regno == -1) + regcache_raw_collect (regcache, i, + regs + (i - ALPHA_FP0_REGNUM) * 8); + + if (regno == ALPHA_FPCR_REGNUM || regno == -1) + regcache_raw_collect (regcache, ALPHA_FPCR_REGNUM, fpcr); } -/* 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. */ + +/* Return nonzero if the G_floating register value in REG is equal to + zero for FP control instructions. */ + static int -alpha_get_longjmp_target (CORE_ADDR *pc) +fp_register_zero_p (LONGEST reg) { - struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); - CORE_ADDR jb_addr; - char raw_buffer[ALPHA_MAX_REGISTER_RAW_SIZE]; + /* Check that all bits except the sign bit are zero. */ + const LONGEST zero_mask = ((LONGEST) 1 << 63) ^ -1; - jb_addr = read_register (ALPHA_A0_REGNUM); + return ((reg & zero_mask) == 0); +} - if (target_read_memory (jb_addr + (tdep->jb_pc * tdep->jb_elt_size), - raw_buffer, tdep->jb_elt_size)) - return 0; +/* Return the value of the sign bit for the G_floating register + value held in REG. */ - *pc = extract_address (raw_buffer, tdep->jb_elt_size); - return 1; +static int +fp_register_sign_bit (LONGEST reg) +{ + const LONGEST sign_mask = (LONGEST) 1 << 63; + + return ((reg & sign_mask) != 0); } /* 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. */ + the target of the coming instruction and breakpoint it. */ static CORE_ADDR -alpha_next_pc (CORE_ADDR pc) +alpha_next_pc (struct frame_info *frame, CORE_ADDR pc) { + struct gdbarch *gdbarch = get_frame_arch (frame); unsigned int insn; unsigned int op; + int regno; int offset; LONGEST rav; - insn = read_memory_unsigned_integer (pc, sizeof (insn)); + insn = alpha_read_insn (gdbarch, pc); - /* Opcode is top 6 bits. */ + /* 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); + return (get_frame_register_unsigned (frame, (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 */ + if (op == 0x30 /* BR */ + || op == 0x34) /* BSR */ { branch_taken: offset = (insn & 0x001fffff); if (offset & 0x00100000) offset |= 0xffe00000; - offset *= 4; - return (pc + 4 + offset); + offset *= ALPHA_INSN_SIZE; + return (pc + ALPHA_INSN_SIZE + offset); } /* Need to determine if branch is taken; read RA. */ - rav = (LONGEST) read_register ((insn >> 21) & 0x1f); + regno = (insn >> 21) & 0x1f; + switch (op) + { + case 0x31: /* FBEQ */ + case 0x36: /* FBGE */ + case 0x37: /* FBGT */ + case 0x33: /* FBLE */ + case 0x32: /* FBLT */ + case 0x35: /* FBNE */ + regno += gdbarch_fp0_regnum (gdbarch); + } + + rav = get_frame_register_signed (frame, regno); + switch (op) { case 0x38: /* BLBC */ @@ -1721,38 +1686,56 @@ alpha_next_pc (CORE_ADDR pc) if (rav >= 0) goto branch_taken; break; + + /* Floating point branches. */ + + case 0x31: /* FBEQ */ + if (fp_register_zero_p (rav)) + goto branch_taken; + break; + case 0x36: /* FBGE */ + if (fp_register_sign_bit (rav) == 0 || fp_register_zero_p (rav)) + goto branch_taken; + break; + case 0x37: /* FBGT */ + if (fp_register_sign_bit (rav) == 0 && ! fp_register_zero_p (rav)) + goto branch_taken; + break; + case 0x33: /* FBLE */ + if (fp_register_sign_bit (rav) == 1 || fp_register_zero_p (rav)) + goto branch_taken; + break; + case 0x32: /* FBLT */ + if (fp_register_sign_bit (rav) == 1 && ! fp_register_zero_p (rav)) + goto branch_taken; + break; + case 0x35: /* FBNE */ + if (! fp_register_zero_p (rav)) + goto branch_taken; + break; } } /* Not a branch or branch not taken; target PC is: pc + 4 */ - return (pc + 4); + return (pc + ALPHA_INSN_SIZE); } -void -alpha_software_single_step (enum target_signal sig, int insert_breakpoints_p) +int +alpha_software_single_step (struct frame_info *frame) { - static CORE_ADDR next_pc; - typedef char binsn_quantum[BREAKPOINT_MAX]; - static binsn_quantum break_mem; - CORE_ADDR pc; + struct gdbarch *gdbarch = get_frame_arch (frame); + struct address_space *aspace = get_frame_address_space (frame); + CORE_ADDR pc, next_pc; - if (insert_breakpoints_p) - { - pc = read_pc (); - next_pc = alpha_next_pc (pc); + pc = get_frame_pc (frame); + next_pc = alpha_next_pc (frame, pc); - target_insert_breakpoint (next_pc, break_mem); - } - else - { - target_remove_breakpoint (next_pc, break_mem); - write_pc (next_pc); - } + insert_single_step_breakpoint (gdbarch, aspace, next_pc); + return 1; } - /* 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. @@ -1765,46 +1748,28 @@ 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; - } + arches = gdbarch_list_lookup_by_info (arches, &info); + if (arches != NULL) + return arches->gdbarch; - tdep = xmalloc (sizeof (struct gdbarch_tdep)); + tdep = XNEW (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; + /* Lowest text address. This is used by heuristic_proc_start() + to decide when to stop looking. */ + tdep->vm_min_address = (CORE_ADDR) 0x120000000LL; tdep->dynamic_sigtramp_offset = NULL; - tdep->skip_sigtramp_frame = NULL; tdep->sigcontext_addr = NULL; + tdep->sc_pc_offset = 2 * 8; + tdep->sc_regs_offset = 4 * 8; + tdep->sc_fpregs_offset = tdep->sc_regs_offset + 32 * 8 + 8; + + tdep->jb_pc = -1; /* longjmp support not enabled by default. */ - tdep->jb_pc = -1; /* longjmp support not enabled by default */ + tdep->return_in_memory = alpha_return_in_memory_always; /* Type sizes */ set_gdbarch_short_bit (gdbarch, 16); @@ -1819,98 +1784,52 @@ alpha_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) /* 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_register_type (gdbarch, alpha_register_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_convert_register_p (gdbarch, alpha_convert_register_p); + set_gdbarch_register_to_value (gdbarch, alpha_register_to_value); + set_gdbarch_value_to_register (gdbarch, alpha_value_to_register); - set_gdbarch_skip_prologue (gdbarch, alpha_skip_prologue); + set_gdbarch_register_reggroup_p (gdbarch, alpha_register_reggroup_p); - set_gdbarch_frame_num_args (gdbarch, frame_num_args_unknown); - set_gdbarch_frameless_function_invocation (gdbarch, - generic_frameless_function_invocation_not); + /* Prologue heuristics. */ + set_gdbarch_skip_prologue (gdbarch, alpha_skip_prologue); - set_gdbarch_saved_pc_after_call (gdbarch, alpha_saved_pc_after_call); + /* Disassembler. */ + set_gdbarch_print_insn (gdbarch, print_insn_alpha); - 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); + /* Call info. */ - set_gdbarch_frame_init_saved_regs (gdbarch, alpha_frame_init_saved_regs); + set_gdbarch_return_value (gdbarch, alpha_return_value); - set_gdbarch_use_struct_convention (gdbarch, alpha_use_struct_convention); - set_gdbarch_deprecated_extract_return_value (gdbarch, alpha_extract_return_value); + /* Settings for calling functions in the inferior. */ + set_gdbarch_push_dummy_call (gdbarch, alpha_push_dummy_call); - set_gdbarch_store_struct_return (gdbarch, alpha_store_struct_return); - set_gdbarch_store_return_value (gdbarch, alpha_store_return_value); - set_gdbarch_deprecated_extract_struct_value_address (gdbarch, - alpha_extract_struct_value_address); + /* Methods for saving / extracting a dummy frame's ID. */ + set_gdbarch_dummy_id (gdbarch, alpha_dummy_id); - /* 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); + /* Return the unwound PC value. */ + set_gdbarch_unwind_pc (gdbarch, alpha_unwind_pc); 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_decr_pc_after_break (gdbarch, ALPHA_INSN_SIZE); + set_gdbarch_cannot_step_breakpoint (gdbarch, 1); - set_gdbarch_function_start_offset (gdbarch, 0); - set_gdbarch_frame_args_skip (gdbarch, 0); + /* Handles single stepping of atomic sequences. */ + set_gdbarch_software_single_step (gdbarch, alpha_deal_with_atomic_sequence); /* Hook in ABI-specific overrides, if they have been registered. */ - gdbarch_init_osabi (info, gdbarch, osabi); + gdbarch_init_osabi (info, gdbarch); /* Now that we have tuned the configuration, set a few final things based on what the OS ABI has told us. */ @@ -1918,56 +1837,46 @@ alpha_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) if (tdep->jb_pc >= 0) set_gdbarch_get_longjmp_target (gdbarch, alpha_get_longjmp_target); + frame_unwind_append_unwinder (gdbarch, &alpha_sigtramp_frame_unwind); + frame_unwind_append_unwinder (gdbarch, &alpha_heuristic_frame_unwind); + + frame_base_set_default (gdbarch, &alpha_heuristic_frame_base); + return gdbarch; } -static void -alpha_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file) +void +alpha_dwarf2_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { - 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); + dwarf2_append_unwinders (gdbarch); + frame_base_append_sniffer (gdbarch, dwarf2_frame_base_sniffer); } +extern initialize_file_ftype _initialize_alpha_tdep; /* -Wmissing-prototypes */ + 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; + gdbarch_register (bfd_arch_alpha, alpha_gdbarch_init, NULL); /* 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); + add_setshow_zinteger_cmd ("heuristic-fence-post", class_support, + &heuristic_fence_post, _("\ +Set the distance searched for the start of a function."), _("\ +Show the distance searched for the start of a function."), _("\ +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."), + reinit_frame_cache_sfunc, + NULL, /* FIXME: i18n: The distance searched for + the start of a function is \"%d\". */ + &setlist, &showlist); }