From d2427a719bedac1dff31c9566234062b887f7cce Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 29 May 2003 23:02:53 +0000 Subject: [PATCH] * alpha-linux-tdep.c (alpha_linux_sigtramp_offset_1): New. (alpha_linux_sigtramp_offset): Use it. Make static. (alpha_linux_sigcontext_addr): Handle __NR_rt_sigreturn; update for new frame model. * alpha-mdebug-tdep.c: New file. * alpha-osf1-tdep.c (alpha_call_dummy_address): Move from alpha-tdep.c. (alpha_osf1_init_abi): Install it. * alpha-tdep.c (PROC_*): Move to alpha-mdebug-tdep.c. (linked_proc_desc_table): Remove. (alpha_frame_past_sigtramp_frame): Remove. (alpha_dynamic_sigtramp_offset): Remove. (ALPHA_PROC_SIGTRAMP_MAGIC): Remove. (alpha_proc_desc_is_dyn_sigtramp): Remove. (alpha_set_proc_desc_is_dyn_sigtramp): Remove. (push_sigtramp_desc): Remove. (alpha_cannot_fetch_register): Use ALPHA_FP_REGNUM. (alpha_cannot_store_register): Likewise. (alpha_sigcontext_addr): Remove. (alpha_find_saved_regs): Remove. (alpha_frame_init_saved_regs): Remove. (alpha_init_frame_pc_first): Remove. (read_next_frame_reg): Remove. (alpha_frame_saved_pc): Remove. (alpha_saved_pc_after_call): Remove. (temp_proc_desc, temp_saved_regs): Remove. (alpha_about_to_return): Remove. (cached_proc_desc): Remove. (alpha_frame_chain): Remove. (alpha_print_extra_frame_info): Remove. (alpha_init_extra_frame_info): Remove. (alpha_frame_locals_address): Remove. (alpha_frame_args_address): Remove. (alpha_push_arguments): Use ALPHA_REGISTER_BYTES not sizeof CORE_ADDR. (alpha_push_dummy_frame): Remove. (alpha_pop_frame): Remove. (alpha_after_prologue): Rename from after_prologue; remove mdebug bits. (alpha_read_insn): New. (alpha_skip_prologue): Merge alpha_skip_prologue_internal; adjust for different insn encodings. (alpha_in_lenient_prologue): Remove. (struct alpha_sigtramp_unwind_cache): New. (alpha_sigtramp_frame_unwind_cache): New. (alpha_sigtramp_register_address): New. (alpha_sigtramp_frame_this_id): New. (alpha_sigtramp_frame_prev_register): New. (alpha_sigtramp_frame_unwind): New. (alpha_sigtramp_frame_p): New. (struct alpha_heuristic_unwind_cache): New. (alpha_heuristic_proc_start): Rename from heuristic_proc_start; don't count nop insns that occur between functions. (alpha_heuristic_frame_unwind_cache): New; incorporate much of heuristic_proc_desc, but without the mdebug wrapping. (alpha_heuristic_frame_this_id): New. (alpha_heuristic_frame_prev_register): New. (alpha_heuristic_frame_unwind): New. (alpha_heuristic_frame_p): New. (alpha_heuristic_frame_base_address): New. (alpha_heuristic_frame_base): New. (alpha_unwind_dummy_id): New. (alpha_unwind_pc): New. (alpha_gdbarch_init): Don't set skip_sigtramp_frame. Kill use of frame related deprecated initializations; install replacements. (alpha_dump_tdep): Remove. * alpha-tdep.h (struct gdbarch_tdep): Remove skip_sigtramp_frame. (alpha_read_insn, alpha_after_prologue, alpha_heuristic_frame_unwind_cache, alpha_heuristic_frame_this_id, alpha_heuristic_frame_prev_register, alpha_heuristic_frame_base_address, alpha_mdebug_init_abi): Declare. * config/alpha/alpha-linux.mt (TDEPFILES): Add alpha-mdebug-tdep.o. * config/alpha/tm-alpha.h (PRINT_EXTRA_FRAME_INFO): Remove. * config/alpha/tm-alphalinux.h (SIGTRAMP_START, SIGTRAMP_END): Remove. --- gdb/ChangeLog | 74 ++ gdb/alpha-linux-tdep.c | 134 +- gdb/alpha-mdebug-tdep.c | 442 ++++++ gdb/alpha-osf1-tdep.c | 29 + gdb/alpha-tdep.c | 2139 +++++++++++------------------- gdb/alpha-tdep.h | 28 +- gdb/config/alpha/alpha-linux.mt | 3 +- gdb/config/alpha/tm-alpha.h | 5 - gdb/config/alpha/tm-alphalinux.h | 11 +- 9 files changed, 1393 insertions(+), 1472 deletions(-) create mode 100644 gdb/alpha-mdebug-tdep.c diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 0a810e96e1d..61819233b4f 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,77 @@ +2003-05-29 Richard Henderson + + * alpha-linux-tdep.c (alpha_linux_sigtramp_offset_1): New. + (alpha_linux_sigtramp_offset): Use it. Make static. + (alpha_linux_sigcontext_addr): Handle __NR_rt_sigreturn; + update for new frame model. + * alpha-mdebug-tdep.c: New file. + * alpha-osf1-tdep.c (alpha_call_dummy_address): Move from alpha-tdep.c. + (alpha_osf1_init_abi): Install it. + * alpha-tdep.c (PROC_*): Move to alpha-mdebug-tdep.c. + (linked_proc_desc_table): Remove. + (alpha_frame_past_sigtramp_frame): Remove. + (alpha_dynamic_sigtramp_offset): Remove. + (ALPHA_PROC_SIGTRAMP_MAGIC): Remove. + (alpha_proc_desc_is_dyn_sigtramp): Remove. + (alpha_set_proc_desc_is_dyn_sigtramp): Remove. + (push_sigtramp_desc): Remove. + (alpha_cannot_fetch_register): Use ALPHA_FP_REGNUM. + (alpha_cannot_store_register): Likewise. + (alpha_sigcontext_addr): Remove. + (alpha_find_saved_regs): Remove. + (alpha_frame_init_saved_regs): Remove. + (alpha_init_frame_pc_first): Remove. + (read_next_frame_reg): Remove. + (alpha_frame_saved_pc): Remove. + (alpha_saved_pc_after_call): Remove. + (temp_proc_desc, temp_saved_regs): Remove. + (alpha_about_to_return): Remove. + (cached_proc_desc): Remove. + (alpha_frame_chain): Remove. + (alpha_print_extra_frame_info): Remove. + (alpha_init_extra_frame_info): Remove. + (alpha_frame_locals_address): Remove. + (alpha_frame_args_address): Remove. + (alpha_push_arguments): Use ALPHA_REGISTER_BYTES not sizeof CORE_ADDR. + (alpha_push_dummy_frame): Remove. + (alpha_pop_frame): Remove. + (alpha_after_prologue): Rename from after_prologue; remove mdebug bits. + (alpha_read_insn): New. + (alpha_skip_prologue): Merge alpha_skip_prologue_internal; adjust + for different insn encodings. + (alpha_in_lenient_prologue): Remove. + (struct alpha_sigtramp_unwind_cache): New. + (alpha_sigtramp_frame_unwind_cache): New. + (alpha_sigtramp_register_address): New. + (alpha_sigtramp_frame_this_id): New. + (alpha_sigtramp_frame_prev_register): New. + (alpha_sigtramp_frame_unwind): New. + (alpha_sigtramp_frame_p): New. + (struct alpha_heuristic_unwind_cache): New. + (alpha_heuristic_proc_start): Rename from heuristic_proc_start; + don't count nop insns that occur between functions. + (alpha_heuristic_frame_unwind_cache): New; incorporate much of + heuristic_proc_desc, but without the mdebug wrapping. + (alpha_heuristic_frame_this_id): New. + (alpha_heuristic_frame_prev_register): New. + (alpha_heuristic_frame_unwind): New. + (alpha_heuristic_frame_p): New. + (alpha_heuristic_frame_base_address): New. + (alpha_heuristic_frame_base): New. + (alpha_unwind_dummy_id): New. + (alpha_unwind_pc): New. + (alpha_gdbarch_init): Don't set skip_sigtramp_frame. Kill use of + frame related deprecated initializations; install replacements. + (alpha_dump_tdep): Remove. + * alpha-tdep.h (struct gdbarch_tdep): Remove skip_sigtramp_frame. + (alpha_read_insn, alpha_after_prologue, + alpha_heuristic_frame_unwind_cache, alpha_heuristic_frame_this_id, + alpha_heuristic_frame_prev_register, + alpha_heuristic_frame_base_address, alpha_mdebug_init_abi): Declare. + * config/alpha/alpha-linux.mt (TDEPFILES): Add alpha-mdebug-tdep.o. + * config/alpha/tm-alpha.h (PRINT_EXTRA_FRAME_INFO): Remove. + * config/alpha/tm-alphalinux.h (SIGTRAMP_START, SIGTRAMP_END): Remove. + 2003-05-29 Andrew Cagney * gdb_assert.h (gdb_assert_fail): Provide different definitions diff --git a/gdb/alpha-linux-tdep.c b/gdb/alpha-linux-tdep.c index c5d7481fbf9..e89a0fa5fe1 100644 --- a/gdb/alpha-linux-tdep.c +++ b/gdb/alpha-linux-tdep.c @@ -23,93 +23,121 @@ #include "gdbcore.h" #include "value.h" #include "osabi.h" +#include "gdb_assert.h" #include "alpha-tdep.h" -/* Under GNU/Linux, signal handler invocations can be identified by the - designated code sequence that is used to return from a signal +/* Under GNU/Linux, signal handler invocations can be identified by + the designated code sequence that is used to return from a signal handler. In particular, the return address of a signal handler - points to the following sequence (the first instruction is quadword - aligned): - - bis $30,$30,$16 - addq $31,0x67,$0 - call_pal callsys - - Each instruction has a unique encoding, so we simply attempt to - match the instruction the pc is pointing to with any of the above - instructions. If there is a hit, we know the offset to the start - of the designated sequence and can then check whether we really are - executing in a designated sequence. If not, -1 is returned, - otherwise the offset from the start of the desingated sequence is - returned. - - There is a slight chance of false hits: code could jump into the - middle of the designated sequence, in which case there is no - guarantee that we are in the middle of a sigreturn syscall. Don't - think this will be a problem in praxis, though. */ -LONGEST -alpha_linux_sigtramp_offset (CORE_ADDR pc) + points to a sequence that copies $sp to $16, loads $0 with the + appropriate syscall number, and finally enters the kernel. + + This is somewhat complicated in that: + (1) the expansion of the "mov" assembler macro has changed over + time, from "bis src,src,dst" to "bis zero,src,dst", + (2) the kernel has changed from using "addq" to "lda" to load the + syscall number, + (3) there is a "normal" sigreturn and an "rt" sigreturn which + has a different stack layout. +*/ + +static long +alpha_linux_sigtramp_offset_1 (CORE_ADDR pc) { - unsigned int i[3], w; - long off; + switch (alpha_read_insn (pc)) + { + case 0x47de0410: /* bis $30,$30,$16 */ + case 0x47fe0410: /* bis $31,$30,$16 */ + return 0; - if (read_memory_nobpt (pc, (char *) &w, 4) != 0) - return -1; + case 0x43ecf400: /* addq $31,103,$0 */ + case 0x201f0067: /* lda $0,103($31) */ + case 0x201f015f: /* lda $0,351($31) */ + return 4; + + case 0x00000083: /* call_pal callsys */ + return 8; - off = -1; - switch (w) - { - case 0x47de0410: - off = 0; - break; /* bis $30,$30,$16 */ - case 0x43ecf400: - off = 4; - break; /* addq $31,0x67,$0 */ - case 0x00000083: - off = 8; - break; /* call_pal callsys */ default: return -1; } +} + +static LONGEST +alpha_linux_sigtramp_offset (CORE_ADDR pc) +{ + long i, off; + + if (pc & 3) + return -1; + + /* Guess where we might be in the sequence. */ + off = alpha_linux_sigtramp_offset_1 (pc); + if (off < 0) + return -1; + + /* Verify that the other two insns of the sequence are as we expect. */ pc -= off; - if (pc & 0x7) + for (i = 0; i < 12; i += 4) { - /* designated sequence is not quadword aligned */ - return -1; + if (i == off) + continue; + if (alpha_linux_sigtramp_offset_1 (pc + i) != i) + return -1; } - if (read_memory_nobpt (pc, (char *) i, sizeof (i)) != 0) - return -1; - - if (i[0] == 0x47de0410 && i[1] == 0x43ecf400 && i[2] == 0x00000083) - return off; - return -1; + return off; } static int alpha_linux_pc_in_sigtramp (CORE_ADDR pc, char *func_name) { - return (alpha_linux_sigtramp_offset (pc) >= 0); + return alpha_linux_sigtramp_offset (pc) >= 0; } static CORE_ADDR -alpha_linux_sigcontext_addr (struct frame_info *frame) +alpha_linux_sigcontext_addr (struct frame_info *next_frame) { - return (get_frame_base (frame) - 0x298); /* sizeof(struct sigcontext) */ + CORE_ADDR pc; + ULONGEST sp; + long off; + + pc = frame_pc_unwind (next_frame); + frame_unwind_unsigned_register (next_frame, ALPHA_SP_REGNUM, &sp); + + off = alpha_linux_sigtramp_offset (pc); + gdb_assert (off >= 0); + + /* __NR_rt_sigreturn has a couple of structures on the stack. This is: + + struct rt_sigframe { + struct siginfo info; + struct ucontext uc; + }; + + offsetof (struct rt_sigframe, uc.uc_mcontext); + */ + if (alpha_read_insn (pc - off + 4) == 0x201f015f) + return sp + 176; + + /* __NR_sigreturn has the sigcontext structure at the top of the stack. */ + return sp; } static void alpha_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + struct gdbarch_tdep *tdep; + + alpha_mdebug_init_abi (info, gdbarch); set_gdbarch_pc_in_sigtramp (gdbarch, alpha_linux_pc_in_sigtramp); + tdep = gdbarch_tdep (gdbarch); tdep->dynamic_sigtramp_offset = alpha_linux_sigtramp_offset; tdep->sigcontext_addr = alpha_linux_sigcontext_addr; - tdep->jb_pc = 2; tdep->jb_elt_size = 8; } diff --git a/gdb/alpha-mdebug-tdep.c b/gdb/alpha-mdebug-tdep.c new file mode 100644 index 00000000000..2f84d6d4096 --- /dev/null +++ b/gdb/alpha-mdebug-tdep.c @@ -0,0 +1,442 @@ +/* Target-dependent mdebug code for the ALPHA architecture. + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 + Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "frame.h" +#include "frame-unwind.h" +#include "frame-base.h" +#include "inferior.h" +#include "symtab.h" +#include "value.h" +#include "gdbcmd.h" +#include "gdbcore.h" +#include "dis-asm.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdb_string.h" +#include "linespec.h" +#include "regcache.h" +#include "doublest.h" +#include "arch-utils.h" +#include "osabi.h" +#include "block.h" +#include "gdb_assert.h" + +#include "elf-bfd.h" + +#include "alpha-tdep.h" + +/* FIXME: Some of this code should perhaps be merged with mips. */ + +/* *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) +#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) + +/* Locate the mdebug PDR for the given PC. Return null if one can't + be found; you'll have to fall back to other methods in that case. */ + +static alpha_extra_func_info_t +find_proc_desc (CORE_ADDR pc) +{ + struct block *b = block_for_pc (pc); + alpha_extra_func_info_t proc_desc = NULL; + struct symbol *sym = NULL; + + if (b) + { + CORE_ADDR startaddr; + find_pc_partial_function (pc, NULL, &startaddr, NULL); + + 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_DOMAIN, 0, NULL); + } + + if (sym) + { + proc_desc = (alpha_extra_func_info_t) SYMBOL_VALUE (sym); + + /* If we never found a PDR for this function in symbol reading, + then examine prologues to find the information. */ + if (proc_desc->pdr.framereg == -1) + proc_desc = NULL; + } + + return proc_desc; +} + +/* This returns the PC of the first inst after the prologue. If we can't + find the prologue, then return 0. */ + +static CORE_ADDR +alpha_mdebug_after_prologue (CORE_ADDR pc, alpha_extra_func_info_t proc_desc) +{ + if (proc_desc) + { + /* 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; + } + + return alpha_after_prologue (pc); +} + +/* Return non-zero if we *might* be in a function prologue. Return zero + if we are definitively *not* in a function prologue. */ + +static int +alpha_mdebug_in_prologue (CORE_ADDR pc, alpha_extra_func_info_t proc_desc) +{ + CORE_ADDR after_prologue_pc = alpha_mdebug_after_prologue (pc, proc_desc); + return (after_prologue_pc == 0 || pc < after_prologue_pc); +} + + +/* Frame unwinder that reads mdebug PDRs. */ + +struct alpha_mdebug_unwind_cache +{ + alpha_extra_func_info_t proc_desc; + CORE_ADDR vfp; + CORE_ADDR *saved_regs; + void *in_prologue_cache; +}; + +/* Extract all of the information about the frame from PROC_DESC + and store the resulting register save locations in the structure. */ + +static struct alpha_mdebug_unwind_cache * +alpha_mdebug_frame_unwind_cache (struct frame_info *next_frame, + void **this_prologue_cache) +{ + struct alpha_mdebug_unwind_cache *info; + alpha_extra_func_info_t proc_desc; + ULONGEST vfp; + CORE_ADDR pc, reg_position; + unsigned long mask; + int ireg, returnreg; + + if (*this_prologue_cache) + return *this_prologue_cache; + + info = FRAME_OBSTACK_ZALLOC (struct alpha_mdebug_unwind_cache); + *this_prologue_cache = info; + pc = frame_pc_unwind (next_frame); + + /* ??? We don't seem to be able to cache the lookup of the PDR + from alpha_mdebug_frame_p. It'd be nice if we could change + the arguments to that function. Oh well. */ + proc_desc = find_proc_desc (pc); + info->proc_desc = proc_desc; + gdb_assert (proc_desc != NULL); + + /* If we're in the prologue, the PDR for this frame is not yet valid. */ + /* ??? We could have said "no" in alpha_mdebug_frame_p, and we'd + walk down the list of unwinders and try the heuristic unwinder + and things would have been fine. However, since we have the PDR, + we know how to skip the search for the start of the procedure, + and all the uncertainty involved there. So instead, arrange for + us to defer to the heuristic unwinder directly. */ + if (alpha_mdebug_in_prologue (pc, proc_desc)) + { + alpha_heuristic_frame_unwind_cache (next_frame, + &info->in_prologue_cache, + PROC_LOW_ADDR (proc_desc)); + return info; + } + + info->saved_regs = frame_obstack_zalloc (SIZEOF_FRAME_SAVED_REGS); + + /* The VFP of the frame is at FRAME_REG+FRAME_OFFSET. */ + frame_unwind_unsigned_register (next_frame, PROC_FRAME_REG (proc_desc), &vfp); + vfp += PROC_FRAME_OFFSET (info->proc_desc); + info->vfp = vfp; + + /* Fill in the offsets for the registers which gen_mask says were saved. */ + + reg_position = vfp + PROC_REG_OFFSET (proc_desc); + mask = PROC_REG_MASK (proc_desc); + returnreg = PROC_PC_REG (proc_desc); + + /* Note that RA is always saved first, regardless of its actual + register number. */ + if (mask & (1 << returnreg)) + { + /* Clear bit for RA so we don't save it again later. */ + mask &= ~(1 << returnreg); + + info->saved_regs[returnreg] = reg_position; + reg_position += 8; + } + + for (ireg = 0; ireg <= 31; ++ireg) + if (mask & (1 << ireg)) + { + info->saved_regs[ireg] = reg_position; + reg_position += 8; + } + + reg_position = vfp + PROC_FREG_OFFSET (proc_desc); + mask = PROC_FREG_MASK (proc_desc); + + for (ireg = 0; ireg <= 31; ++ireg) + if (mask & (1 << ireg)) + { + info->saved_regs[FP0_REGNUM + ireg] = reg_position; + reg_position += 8; + } + + return info; +} + +/* 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_mdebug_frame_this_id (struct frame_info *next_frame, + void **this_prologue_cache, + struct frame_id *this_id) +{ + struct alpha_mdebug_unwind_cache *info + = alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache); + + /* If we're in the prologue, defer to the heuristic unwinder. */ + if (info->in_prologue_cache) + alpha_heuristic_frame_this_id (next_frame, &info->in_prologue_cache, + this_id); + else + *this_id = frame_id_build (info->vfp, frame_func_unwind (next_frame)); +} + +/* Retrieve the value of REGNUM in FRAME. Don't give up! */ + +static void +alpha_mdebug_frame_prev_register (struct frame_info *next_frame, + void **this_prologue_cache, + int regnum, int *optimizedp, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnump, void *bufferp) +{ + struct alpha_mdebug_unwind_cache *info + = alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache); + + /* If we're in the prologue, defer to the heuristic unwinder. */ + if (info->in_prologue_cache) + { + alpha_heuristic_frame_prev_register (next_frame, + &info->in_prologue_cache, + regnum, optimizedp, lvalp, + addrp, realnump, bufferp); + return; + } + + /* 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 == PC_REGNUM) + regnum = PROC_PC_REG (info->proc_desc); + + /* For all registers known to be saved in the current frame, + do the obvious and pull the value out. */ + if (info->saved_regs[regnum]) + { + *optimizedp = 0; + *lvalp = lval_memory; + *addrp = info->saved_regs[regnum]; + *realnump = -1; + if (bufferp != NULL) + read_memory (*addrp, bufferp, ALPHA_REGISTER_SIZE); + return; + } + + /* The stack pointer of the previous frame is computed by popping + the current stack frame. */ + if (regnum == SP_REGNUM) + { + *optimizedp = 0; + *lvalp = not_lval; + *addrp = 0; + *realnump = -1; + if (bufferp != NULL) + store_unsigned_integer (bufferp, ALPHA_REGISTER_SIZE, info->vfp); + return; + } + + /* Otherwise assume the next frame has the same register value. */ + frame_register (next_frame, regnum, optimizedp, lvalp, addrp, + realnump, bufferp); +} + +static const struct frame_unwind alpha_mdebug_frame_unwind = { + NORMAL_FRAME, + alpha_mdebug_frame_this_id, + alpha_mdebug_frame_prev_register +}; + +const struct frame_unwind * +alpha_mdebug_frame_p (CORE_ADDR pc) +{ + alpha_extra_func_info_t proc_desc; + + /* If this PC does not map to a PDR, then clearly this isn't an + mdebug frame. */ + proc_desc = find_proc_desc (pc); + if (proc_desc == NULL) + return NULL; + + return &alpha_mdebug_frame_unwind; +} + +static CORE_ADDR +alpha_mdebug_frame_base_address (struct frame_info *next_frame, + void **this_prologue_cache) +{ + struct alpha_mdebug_unwind_cache *info + = alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache); + + if (info->in_prologue_cache) + return alpha_heuristic_frame_base_address (next_frame, + &info->in_prologue_cache); + else + return info->vfp; +} + +static CORE_ADDR +alpha_mdebug_frame_locals_address (struct frame_info *next_frame, + void **this_prologue_cache) +{ + struct alpha_mdebug_unwind_cache *info + = alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache); + CORE_ADDR vfp; + + if (info->in_prologue_cache) + vfp = alpha_heuristic_frame_base_address (next_frame, + &info->in_prologue_cache); + else + vfp = info->vfp; + + return vfp - PROC_LOCALOFF (info->proc_desc); +} + +static CORE_ADDR +alpha_mdebug_frame_args_address (struct frame_info *next_frame, + void **this_prologue_cache) +{ + struct alpha_mdebug_unwind_cache *info + = alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache); + CORE_ADDR vfp; + + if (info->in_prologue_cache) + vfp = alpha_heuristic_frame_base_address (next_frame, + &info->in_prologue_cache); + else + vfp = info->vfp; + + return vfp - ALPHA_NUM_ARG_REGS * 8; +} + +static const struct frame_base alpha_mdebug_frame_base = { + &alpha_mdebug_frame_unwind, + alpha_mdebug_frame_base_address, + alpha_mdebug_frame_locals_address, + alpha_mdebug_frame_args_address +}; + +static const struct frame_base * +alpha_mdebug_frame_base_p (CORE_ADDR pc) +{ + alpha_extra_func_info_t proc_desc; + + /* If this PC does not map to a PDR, then clearly this isn't an + mdebug frame. */ + proc_desc = find_proc_desc (pc); + if (proc_desc == NULL) + return NULL; + + return &alpha_mdebug_frame_base; +} + + +void +alpha_mdebug_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + frame_unwind_append_predicate (gdbarch, alpha_mdebug_frame_p); + frame_base_append_predicate (gdbarch, alpha_mdebug_frame_base_p); +} diff --git a/gdb/alpha-osf1-tdep.c b/gdb/alpha-osf1-tdep.c index 4eaa3c4013c..26e17907607 100644 --- a/gdb/alpha-osf1-tdep.c +++ b/gdb/alpha-osf1-tdep.c @@ -53,6 +53,30 @@ alpha_osf1_sigcontext_addr (struct frame_info *frame) : frame->frame, 8)); } +/* 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). + */ + +static CORE_ADDR +alpha_call_dummy_address (void) +{ + CORE_ADDR entry; + struct minimal_symbol *sym; + + entry = entry_point_address (); + + if (entry != 0) + return entry; + + sym = lookup_minimal_symbol ("_Prelude", NULL, symfile_objfile); + + if (!sym || MSYMBOL_TYPE (sym) != mst_text) + return 0; + else + return SYMBOL_VALUE_ADDRESS (sym) + 4; +} + static void alpha_osf1_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) @@ -65,6 +89,11 @@ alpha_osf1_init_abi (struct gdbarch_info info, instead. */ set_gdbarch_software_single_step (gdbarch, alpha_software_single_step); + /* 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_address (gdbarch, alpha_call_dummy_address); + tdep->skip_sigtramp_frame = alpha_osf1_skip_sigtramp_frame; tdep->sigcontext_addr = alpha_osf1_sigcontext_addr; diff --git a/gdb/alpha-tdep.c b/gdb/alpha-tdep.c index ad7ca747507..66075279eef 100644 --- a/gdb/alpha-tdep.c +++ b/gdb/alpha-tdep.c @@ -21,6 +21,8 @@ #include "defs.h" #include "frame.h" +#include "frame-unwind.h" +#include "frame-base.h" #include "inferior.h" #include "symtab.h" #include "value.h" @@ -41,230 +43,7 @@ #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_deprecated_extract_return_value_ftype alpha_extract_return_value; -static gdbarch_deprecated_extract_struct_value_address_ftype - alpha_extract_struct_value_address; -static gdbarch_use_struct_convention_ftype alpha_use_struct_convention; - -static gdbarch_breakpoint_from_pc_ftype alpha_breakpoint_from_pc; - -static gdbarch_frame_args_address_ftype alpha_frame_args_address; -static gdbarch_frame_locals_address_ftype alpha_frame_locals_address; - -static gdbarch_skip_prologue_ftype alpha_skip_prologue; - -static gdbarch_get_longjmp_target_ftype alpha_get_longjmp_target; - -struct frame_extra_info - { - alpha_extra_func_info_t proc_desc; - int localoff; - int pc_reg; - }; - -/* FIXME: Some of this code should perhaps be merged with mips-tdep.c. */ - -/* Prototypes for local functions. */ - -static void alpha_find_saved_regs (struct frame_info *); - -static alpha_extra_func_info_t push_sigtramp_desc (CORE_ADDR low_addr); - -static CORE_ADDR read_next_frame_reg (struct frame_info *, int); - -static CORE_ADDR heuristic_proc_start (CORE_ADDR); - -static alpha_extra_func_info_t heuristic_proc_desc (CORE_ADDR, - CORE_ADDR, - struct frame_info *); - -static alpha_extra_func_info_t find_proc_desc (CORE_ADDR, - struct frame_info *); - -#if 0 -static int alpha_in_lenient_prologue (CORE_ADDR, CORE_ADDR); -#endif - -static void reinit_frame_cache_sfunc (char *, int, struct cmd_list_element *); - -static CORE_ADDR after_prologue (CORE_ADDR pc, - alpha_extra_func_info_t proc_desc); - -static int alpha_in_prologue (CORE_ADDR pc, - alpha_extra_func_info_t proc_desc); - -static int alpha_about_to_return (CORE_ADDR pc); - -void _initialize_alpha_tdep (void); - -/* Heuristic_proc_start may hunt through the text section for a long - time across a 2400 baud serial line. Allows the user to limit this - search. */ -static unsigned int heuristic_fence_post = 0; -/* *INDENT-OFF* */ -/* Layout of a stack frame on the alpha: - - | | - pdr members: | 7th ... nth arg, | - | `pushed' by caller. | - | | -----------------|-------------------------------|<-- old_sp == vfp - ^ ^ ^ ^ | | - | | | | | | - | |localoff | Copies of 1st .. 6th | - | | | | | argument if necessary. | - | | | v | | - | | | --- |-------------------------------|<-- FRAME_LOCALS_ADDRESS - | | | | | - | | | | Locals and temporaries. | - | | | | | - | | | |-------------------------------| - | | | | | - |-fregoffset | Saved float registers. | - | | | | F9 | - | | | | . | - | | | | . | - | | | | F2 | - | | v | | - | | -------|-------------------------------| - | | | | - | | | Saved registers. | - | | | S6 | - |-regoffset | . | - | | | . | - | | | S0 | - | | | pdr.pcreg | - | v | | - | ----------|-------------------------------| - | | | - frameoffset | Argument build area, gets | - | | 7th ... nth arg for any | - | | called procedure. | - v | | - -------------|-------------------------------|<-- sp - | | -*/ -/* *INDENT-ON* */ - -#define PROC_LOW_ADDR(proc) ((proc)->pdr.adr) /* least address */ -/* These next two fields are kind of being hijacked. I wonder if - iline is too small for the values it needs to hold, if GDB is - running on a 32-bit host. */ -#define PROC_HIGH_ADDR(proc) ((proc)->pdr.iline) /* upper address bound */ -#define PROC_DUMMY_FRAME(proc) ((proc)->pdr.cbLineOffset) /*CALL_DUMMY frame */ -#define PROC_FRAME_OFFSET(proc) ((proc)->pdr.frameoffset) -#define PROC_FRAME_REG(proc) ((proc)->pdr.framereg) -#define PROC_REG_MASK(proc) ((proc)->pdr.regmask) -#define PROC_FREG_MASK(proc) ((proc)->pdr.fregmask) -#define PROC_REG_OFFSET(proc) ((proc)->pdr.regoffset) -#define PROC_FREG_OFFSET(proc) ((proc)->pdr.fregoffset) -#define PROC_PC_REG(proc) ((proc)->pdr.pcreg) -#define PROC_LOCALOFF(proc) ((proc)->pdr.localoff) -#define PROC_SYMBOL(proc) (*(struct symbol**)&(proc)->pdr.isym) -#define _PROC_MAGIC_ 0x0F0F0F0F -#define PROC_DESC_IS_DUMMY(proc) ((proc)->pdr.isym == _PROC_MAGIC_) -#define SET_PROC_DESC_IS_DUMMY(proc) ((proc)->pdr.isym = _PROC_MAGIC_) - -struct linked_proc_info - { - struct alpha_extra_func_info info; - struct linked_proc_info *next; - } - *linked_proc_desc_table = NULL; - -static CORE_ADDR -alpha_frame_past_sigtramp_frame (struct frame_info *frame, CORE_ADDR pc) -{ - struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); - - if (tdep->skip_sigtramp_frame != NULL) - return (tdep->skip_sigtramp_frame (frame, pc)); - - return (0); -} - -static LONGEST -alpha_dynamic_sigtramp_offset (CORE_ADDR pc) -{ - struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); - - /* Must be provided by OS/ABI variant code if supported. */ - if (tdep->dynamic_sigtramp_offset != NULL) - return (tdep->dynamic_sigtramp_offset (pc)); - - return (-1); -} - -#define ALPHA_PROC_SIGTRAMP_MAGIC 0x0e0f0f0f - -/* Return TRUE if the procedure descriptor PROC is a procedure - descriptor that refers to a dynamically generated signal - trampoline routine. */ -static int -alpha_proc_desc_is_dyn_sigtramp (struct alpha_extra_func_info *proc) -{ - struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); - - if (tdep->dynamic_sigtramp_offset != NULL) - return (proc->pdr.isym == ALPHA_PROC_SIGTRAMP_MAGIC); - - return (0); -} - -static void -alpha_set_proc_desc_is_dyn_sigtramp (struct alpha_extra_func_info *proc) -{ - struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); - - if (tdep->dynamic_sigtramp_offset != NULL) - proc->pdr.isym = ALPHA_PROC_SIGTRAMP_MAGIC; -} - -/* Dynamically create a signal-handler caller procedure descriptor for - the signal-handler return code starting at address LOW_ADDR. The - descriptor is added to the linked_proc_desc_table. */ - -static alpha_extra_func_info_t -push_sigtramp_desc (CORE_ADDR low_addr) -{ - struct linked_proc_info *link; - alpha_extra_func_info_t proc_desc; - - link = (struct linked_proc_info *) - xmalloc (sizeof (struct linked_proc_info)); - link->next = linked_proc_desc_table; - linked_proc_desc_table = link; - - proc_desc = &link->info; - - proc_desc->numargs = 0; - PROC_LOW_ADDR (proc_desc) = low_addr; - PROC_HIGH_ADDR (proc_desc) = low_addr + 3 * 4; - PROC_DUMMY_FRAME (proc_desc) = 0; - PROC_FRAME_OFFSET (proc_desc) = 0x298; /* sizeof(struct sigcontext_struct) */ - PROC_FRAME_REG (proc_desc) = SP_REGNUM; - PROC_REG_MASK (proc_desc) = 0xffff; - PROC_FREG_MASK (proc_desc) = 0xffff; - PROC_PC_REG (proc_desc) = 26; - PROC_LOCALOFF (proc_desc) = 0; - alpha_set_proc_desc_is_dyn_sigtramp (proc_desc); - return (proc_desc); -} - static const char * alpha_register_name (int regno) { @@ -291,13 +70,13 @@ alpha_register_name (int regno) static int alpha_cannot_fetch_register (int regno) { - return (regno == DEPRECATED_FP_REGNUM || regno == ALPHA_ZERO_REGNUM); + return (regno == ALPHA_FP_REGNUM || regno == ALPHA_ZERO_REGNUM); } static int alpha_cannot_store_register (int regno) { - return (regno == DEPRECATED_FP_REGNUM || regno == ALPHA_ZERO_REGNUM); + return (regno == ALPHA_FP_REGNUM || regno == ALPHA_ZERO_REGNUM); } static int @@ -330,1228 +109,868 @@ alpha_register_virtual_size (int regno) { return 8; } - -static CORE_ADDR -alpha_sigcontext_addr (struct frame_info *fi) +/* 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) { - struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); + if (TYPE_LENGTH (valtype) >= REGISTER_RAW_SIZE (regnum)) + { + memcpy (virtual_buffer, raw_buffer, REGISTER_VIRTUAL_SIZE (regnum)); + return; + } + + if (TYPE_CODE (valtype) == TYPE_CODE_FLT) + { + double d = deprecated_extract_floating (raw_buffer, REGISTER_RAW_SIZE (regnum)); + deprecated_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"); +} - if (tdep->sigcontext_addr) - return (tdep->sigcontext_addr (fi)); +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; + } - return (0); + if (TYPE_CODE (valtype) == TYPE_CODE_FLT) + { + double d = deprecated_extract_floating (virtual_buffer, TYPE_LENGTH (valtype)); + deprecated_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"); } -/* Guaranteed to set frame->saved_regs to some values (it never leaves it - NULL). */ + +/* 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 void -alpha_find_saved_regs (struct frame_info *frame) +static CORE_ADDR +alpha_push_arguments (int nargs, struct value **args, CORE_ADDR sp, + int struct_return, CORE_ADDR struct_addr) { - 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 ((get_frame_type (frame) == SIGTRAMP_FRAME)) + int i; + int accumulate_size = struct_return ? 8 : 0; + int arg_regs_size = ALPHA_NUM_ARG_REGS * 8; + struct alpha_arg { - CORE_ADDR sigcontext_addr; + 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[ALPHA_REGISTER_BYTES]; + int required_arg_regs; - 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; - get_frame_saved_regs (frame)[ireg] = reg_position; - } - for (ireg = 0; ireg < 32; ireg++) + 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)) { - reg_position = sigcontext_addr + SIGFRAME_FPREGSAVE_OFF + ireg * 8; - get_frame_saved_regs (frame)[FP0_REGNUM + ireg] = reg_position; + case TYPE_CODE_INT: + case TYPE_CODE_BOOL: + case TYPE_CODE_CHAR: + case TYPE_CODE_RANGE: + case TYPE_CODE_ENUM: + if (TYPE_LENGTH (arg_type) < TYPE_LENGTH (builtin_type_long)) + { + arg_type = builtin_type_long; + arg = value_cast (arg_type, arg); + } + break; + default: + break; } - get_frame_saved_regs (frame)[PC_REGNUM] = sigcontext_addr + SIGFRAME_PC_OFF; - return; + 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); } - proc_desc = get_frame_extra_info (frame)->proc_desc; - if (proc_desc == NULL) - /* I'm not sure how/whether this can happen. Normally when we can't - find a proc_desc, we "synthesize" one using heuristic_proc_desc - and set the saved_regs right away. */ - return; - - /* Fill in the offsets for the registers which gen_mask says - were saved. */ + /* 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; - reg_position = get_frame_base (frame) + PROC_REG_OFFSET (proc_desc); - mask = PROC_REG_MASK (proc_desc); + /* Make room for the arguments on the stack. */ + if (accumulate_size < arg_regs_size) + accumulate_size = arg_regs_size; + sp -= accumulate_size; - returnreg = PROC_PC_REG (proc_desc); + /* Keep sp aligned to a multiple of 16 as the compiler does it too. */ + sp &= ~15; - /* Note that RA is always saved first, regardless of its actual - register number. */ - if (mask & (1 << returnreg)) + /* `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) { - get_frame_saved_regs (frame)[returnreg] = reg_position; - reg_position += 8; - mask &= ~(1 << returnreg); /* Clear bit for RA so we - don't save again later. */ + store_unsigned_integer (raw_buffer, ALPHA_REGISTER_BYTES, struct_addr); + write_memory (sp, raw_buffer, ALPHA_REGISTER_BYTES); } - for (ireg = 0; ireg <= 31; ++ireg) - if (mask & (1 << ireg)) - { - get_frame_saved_regs (frame)[ireg] = reg_position; - reg_position += 8; - } - - /* Fill in the offsets for the registers which float_mask says - were saved. */ - - reg_position = get_frame_base (frame) + PROC_FREG_OFFSET (proc_desc); - mask = PROC_FREG_MASK (proc_desc); + /* Load the argument registers. */ + for (i = 0; i < required_arg_regs; i++) + { + LONGEST val; - for (ireg = 0; ireg <= 31; ++ireg) - if (mask & (1 << ireg)) - { - get_frame_saved_regs (frame)[FP0_REGNUM + ireg] = reg_position; - reg_position += 8; - } + val = read_memory_integer (sp + i * 8, ALPHA_REGISTER_BYTES); + write_register (ALPHA_A0_REGNUM + i, val); + write_register (ALPHA_FPA0_REGNUM + i, val); + } - get_frame_saved_regs (frame)[PC_REGNUM] = get_frame_saved_regs (frame)[returnreg]; + return sp + arg_regs_size; } +/* Given a return value in `regbuf' with a type `valtype', + extract and copy its value into `valbuf'. */ + static void -alpha_frame_init_saved_regs (struct frame_info *fi) +alpha_extract_return_value (struct type *valtype, + char regbuf[ALPHA_REGISTER_BYTES], char *valbuf) { - if (get_frame_saved_regs (fi) == NULL) - alpha_find_saved_regs (fi); - get_frame_saved_regs (fi)[SP_REGNUM] = get_frame_base (fi); + 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)); } -static CORE_ADDR -alpha_init_frame_pc_first (int fromleaf, struct frame_info *prev) -{ - return (fromleaf - ? DEPRECATED_SAVED_PC_AFTER_CALL (get_next_frame (prev)) - : get_next_frame (prev) - ? DEPRECATED_FRAME_SAVED_PC (get_next_frame (prev)) - : read_pc ()); -} +/* Given a return value in `regbuf' with a type `valtype', + write its value into the appropriate register. */ -static CORE_ADDR -read_next_frame_reg (struct frame_info *fi, int regno) +static void +alpha_store_return_value (struct type *valtype, char *valbuf) { - for (; fi; fi = get_next_frame (fi)) + 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) { - /* We have to get the saved sp from the sigcontext - if it is a signal handler frame. */ - if (regno == SP_REGNUM && !(get_frame_type (fi) == SIGTRAMP_FRAME)) - return get_frame_base (fi); - else - { - if (get_frame_saved_regs (fi) == NULL) - alpha_find_saved_regs (fi); - if (get_frame_saved_regs (fi)[regno]) - return read_memory_integer (get_frame_saved_regs (fi)[regno], 8); - } + regnum = FP0_REGNUM; + length = REGISTER_RAW_SIZE (regnum); + alpha_register_convert_to_raw (valtype, regnum, valbuf, raw_buffer); } - return read_register (regno); + else + memcpy (raw_buffer, valbuf, length); + + deprecated_write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, length); } -static CORE_ADDR -alpha_frame_saved_pc (struct frame_info *frame) +static int +alpha_use_struct_convention (int gcc_p, struct type *type) { - alpha_extra_func_info_t proc_desc = get_frame_extra_info (frame)->proc_desc; - /* We have to get the saved pc from the sigcontext - if it is a signal handler frame. */ - int pcreg = ((get_frame_type (frame) == SIGTRAMP_FRAME) - ? PC_REGNUM - : get_frame_extra_info (frame)->pc_reg); - - if (proc_desc && PROC_DESC_IS_DUMMY (proc_desc)) - return read_memory_integer (get_frame_base (frame) - 8, 8); + /* Structures are returned by ref in extra arg0. */ + return 1; +} - return read_next_frame_reg (frame, pcreg); +static void +alpha_store_struct_return (CORE_ADDR addr, CORE_ADDR sp) +{ + /* Store the address of the place in which to copy the structure the + subroutine will return. Handled by alpha_push_arguments. */ } static CORE_ADDR -alpha_saved_pc_after_call (struct frame_info *frame) +alpha_extract_struct_value_address (char *regbuf) { - CORE_ADDR pc = get_frame_pc (frame); - CORE_ADDR tmp; - alpha_extra_func_info_t proc_desc; - int pcreg; - - /* Skip over shared library trampoline if necessary. */ - tmp = SKIP_TRAMPOLINE_CODE (pc); - if (tmp != 0) - pc = tmp; - - proc_desc = find_proc_desc (pc, get_next_frame (frame)); - pcreg = proc_desc ? PROC_PC_REG (proc_desc) : ALPHA_RA_REGNUM; - - if ((get_frame_type (frame) == SIGTRAMP_FRAME)) - return alpha_frame_saved_pc (frame); - else - return read_register (pcreg); + return (extract_address (regbuf + REGISTER_BYTE (ALPHA_V0_REGNUM), + REGISTER_RAW_SIZE (ALPHA_V0_REGNUM))); } - -static struct alpha_extra_func_info temp_proc_desc; -static CORE_ADDR temp_saved_regs[ALPHA_NUM_REGS]; - -/* Nonzero if instruction at PC is a return instruction. "ret - $zero,($ra),1" on alpha. */ - -static int -alpha_about_to_return (CORE_ADDR pc) + +static const unsigned char * +alpha_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr) { - return read_memory_integer (pc, 4) == 0x6bfa8001; -} - + static const unsigned char alpha_breakpoint[] = + { 0x80, 0, 0, 0 }; /* call_pal bpt */ + *lenptr = sizeof(alpha_breakpoint); + return (alpha_breakpoint); +} -/* This fencepost looks highly suspicious to me. Removing it also - seems suspicious as it could affect remote debugging across serial - lines. */ + +/* This returns the PC of the first insn after the prologue. + If we can't find the prologue, then return 0. */ -static CORE_ADDR -heuristic_proc_start (CORE_ADDR pc) +CORE_ADDR +alpha_after_prologue (CORE_ADDR pc) { - struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); - CORE_ADDR start_pc = pc; - CORE_ADDR fence = start_pc - heuristic_fence_post; + struct symtab_and_line sal; + CORE_ADDR func_addr, func_end; - if (start_pc == 0) + if (!find_pc_partial_function (pc, NULL, &func_addr, &func_end)) return 0; - if (heuristic_fence_post == UINT_MAX - || fence < tdep->vm_min_address) - fence = tdep->vm_min_address; - - /* search back for previous return */ - for (start_pc -= 4;; start_pc -= 4) - if (start_pc < fence) - { - /* It's not clear to me why we reach this point when - stop_soon, 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 == NO_STOP_QUIETLY) - { - static int blurb_printed = 0; - - if (fence == tdep->vm_min_address) - warning ("Hit beginning of text section without finding"); - else - warning ("Hit heuristic-fence-post without finding"); - - warning ("enclosing function for address 0x%s", paddr_nz (pc)); - if (!blurb_printed) - { - printf_filtered ("\ -This warning occurs if you are debugging a function without any symbols\n\ -(for example, in a stripped executable). In that case, you may wish to\n\ -increase the size of the search with the `set heuristic-fence-post' command.\n\ -\n\ -Otherwise, you told GDB there was a function where there isn't one, or\n\ -(more likely) you have encountered a bug in GDB.\n"); - blurb_printed = 1; - } - } - - return 0; - } - else if (alpha_about_to_return (start_pc)) - break; + sal = find_pc_line (func_addr, 0); + if (sal.end < func_end) + return sal.end; - start_pc += 4; /* skip return */ - return start_pc; + /* 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; } -static alpha_extra_func_info_t -heuristic_proc_desc (CORE_ADDR start_pc, CORE_ADDR limit_pc, - struct frame_info *next_frame) +/* Read an instruction from memory at PC, looking through breakpoints. */ + +unsigned int +alpha_read_insn (CORE_ADDR pc) { - 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; + char buf[4]; + int status; - 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; + status = read_memory_nobpt (pc, buf, 4); + if (status) + memory_error (status, pc); + return extract_unsigned_integer (buf, 4); +} - if (start_pc + 200 < limit_pc) - limit_pc = start_pc + 200; - frame_size = 0; - for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += 4) - { - char buf[4]; - unsigned long word; - int status; +/* 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. */ - status = read_memory_nobpt (cur_pc, buf, 4); - if (status) - memory_error (status, cur_pc); - word = extract_unsigned_integer (buf, 4); +static CORE_ADDR +alpha_skip_prologue (CORE_ADDR pc) +{ + unsigned long inst; + int offset; + CORE_ADDR post_prologue_pc; + char buf[4]; - if ((word & 0xffff0000) == 0x23de0000) /* lda $sp,n($sp) */ - { - if (word & 0x8000) - { - /* Consider only the first stack allocation instruction - to contain the static size of the frame. */ - if (frame_size == 0) - frame_size += (-word) & 0xffff; - } - else - /* Exit loop if a positive stack adjustment is found, which - usually means that the stack cleanup code in the function - epilogue is reached. */ - break; - } - else if ((word & 0xfc1f0000) == 0xb41e0000 /* stq reg,n($sp) */ - && (word & 0xffff0000) != 0xb7fe0000) /* reg != $zero */ - { - int reg = (word & 0x03e00000) >> 21; - reg_mask |= 1 << reg; - - /* Do not compute the address where the register was saved yet, - because we don't know yet if the offset will need to be - relative to $sp or $fp (we can not compute the address relative - to $sp if $sp is updated during the execution of the current - subroutine, for instance when doing some alloca). So just store - the offset for the moment, and compute the address later - when we know whether this frame has a frame pointer or not. - */ - temp_saved_regs[reg] = (short) word; - - /* Starting with OSF/1-3.2C, the system libraries are shipped - without local symbols, but they still contain procedure - descriptors without a symbol reference. GDB is currently - unable to find these procedure descriptors and uses - heuristic_proc_desc instead. - As some low level compiler support routines (__div*, __add*) - use a non-standard return address register, we have to - add some heuristics to determine the return address register, - or stepping over these routines will fail. - Usually the return address register is the first register - saved on the stack, but assembler optimization might - rearrange the register saves. - So we recognize only a few registers (t7, t9, ra) within - the procedure prologue as valid return address registers. - If we encounter a return instruction, we extract the - the return address register from it. - - FIXME: Rewriting GDB to access the procedure descriptors, - e.g. via the minimal symbol table, might obviate this hack. */ - if (pcreg == -1 - && cur_pc < (start_pc + 80) - && (reg == ALPHA_T7_REGNUM || reg == ALPHA_T9_REGNUM - || reg == ALPHA_RA_REGNUM)) - pcreg = reg; - } - else if ((word & 0xffe0ffff) == 0x6be08001) /* ret zero,reg,1 */ - pcreg = (word >> 16) & 0x1f; - else if (word == 0x47de040f || word == 0x47fe040f) /* bis sp,sp fp */ - { - /* ??? I am not sure what instruction is 0x47fe040f, and I - am suspecting that there was a typo and should have been - 0x47fe040f. I'm keeping it in the test above until further - investigation */ - has_frame_reg = 1; - vfp = read_next_frame_reg (next_frame, ALPHA_GCC_FP_REGNUM); - } - } - if (pcreg == -1) - { - /* If we haven't found a valid return address register yet, - keep searching in the procedure prologue. */ - while (cur_pc < (limit_pc + 80) && cur_pc < (start_pc + 80)) - { - char buf[4]; - unsigned long word; + /* 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; - if (read_memory_nobpt (cur_pc, buf, 4)) - break; - cur_pc += 4; - word = extract_unsigned_integer (buf, 4); + /* 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 ((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; - } - } - } + post_prologue_pc = alpha_after_prologue (pc); + if (post_prologue_pc != 0) + return max (pc, post_prologue_pc); - if (has_frame_reg) - PROC_FRAME_REG (&temp_proc_desc) = ALPHA_GCC_FP_REGNUM; - else - PROC_FRAME_REG (&temp_proc_desc) = SP_REGNUM; - - /* At this point, we know which of the Stack Pointer or the Frame Pointer - to use as the reference address to compute the saved registers address. - But in both cases, the processing above has set vfp to this reference - address, so just need to increment the offset of each saved register - by this address. */ - for (regno = 0; regno < NUM_REGS; regno++) - { - if (reg_mask & 1 << regno) - temp_saved_regs[regno] += vfp; - } + /* Can't determine prologue from the symbol table, need to examine + instructions. */ - 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; -} + /* 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) + { + inst = alpha_read_insn (pc + offset); -/* This returns the PC of the first inst after the prologue. If we can't - find the prologue, then return 0. */ + 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; -static CORE_ADDR -after_prologue (CORE_ADDR pc, alpha_extra_func_info_t proc_desc) -{ - struct symtab_and_line sal; - CORE_ADDR func_addr, func_end; + if (((inst & 0xfc1f0000) == 0xb41e0000 /* stq reg,n($sp) */ + || (inst & 0xfc1f0000) == 0x9c1e0000) /* stt reg,n($sp) */ + && (inst & 0x03e00000) != 0x03e00000) /* reg != $zero */ + continue; - if (!proc_desc) - proc_desc = find_proc_desc (pc, NULL); + if (inst == 0x47de040f) /* bis sp,sp,fp */ + continue; + if (inst == 0x47fe040f) /* bis zero,sp,fp */ + continue; - 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; + break; } + return pc + offset; +} - if (!find_pc_partial_function (pc, NULL, &func_addr, &func_end)) - return 0; /* Unknown */ - - sal = find_pc_line (func_addr, 0); - - if (sal.end < func_end) - return sal.end; + +/* Construct an inferior call to FUN. For Alpha this is as simple as + initializing the RA and T12 registers; everything else is set up by + generic code. */ - /* 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. */ +static void +alpha_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs, + struct value **args, struct type *type, int gcc_p) +{ + CORE_ADDR bp_address = CALL_DUMMY_ADDRESS (); - return 0; + if (bp_address == 0) + error ("no place to put call"); + write_register (ALPHA_RA_REGNUM, bp_address); + write_register (ALPHA_T12_REGNUM, fun); } -/* Return non-zero if we *might* be in a function prologue. Return zero if we - are definitively *not* in a function prologue. */ +/* On the Alpha, the call dummy code is never copied to user space + (see alpha_fix_call_dummy() above). The contents of this do not + matter. */ +LONGEST alpha_call_dummy_words[] = { 0 }; + + +/* Figure out where the longjmp will land. + We expect the first arg to be a pointer to the jmp_buf structure from + which we extract the PC (JB_PC) that we will land at. The PC is copied + into the "pc". This routine returns true on success. */ static int -alpha_in_prologue (CORE_ADDR pc, alpha_extra_func_info_t proc_desc) +alpha_get_longjmp_target (CORE_ADDR *pc) { - CORE_ADDR after_prologue_pc; + struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); + CORE_ADDR jb_addr; + char raw_buffer[ALPHA_MAX_REGISTER_RAW_SIZE]; - after_prologue_pc = after_prologue (pc, proc_desc); + jb_addr = read_register (ALPHA_A0_REGNUM); - if (after_prologue_pc == 0 - || pc < after_prologue_pc) - return 1; - else + if (target_read_memory (jb_addr + (tdep->jb_pc * tdep->jb_elt_size), + raw_buffer, tdep->jb_elt_size)) return 0; + + *pc = extract_address (raw_buffer, tdep->jb_elt_size); + return 1; } -static alpha_extra_func_info_t -find_proc_desc (CORE_ADDR pc, struct frame_info *next_frame) + +/* 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 { - 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 (DEPRECATED_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; + CORE_ADDR sigcontext_addr; +}; - 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; - } +static struct alpha_sigtramp_unwind_cache * +alpha_sigtramp_frame_unwind_cache (struct frame_info *next_frame, + void **this_prologue_cache) +{ + struct alpha_sigtramp_unwind_cache *info; + struct gdbarch_tdep *tdep; - b = block_for_pc (pc); + if (*this_prologue_cache) + return *this_prologue_cache; - find_pc_partial_function (pc, NULL, &startaddr, NULL); - if (b == NULL) - sym = NULL; - else - { - if (startaddr > BLOCK_START (b)) - /* This is the "pathological" case referred to in a comment in - print_frame_info. It might be better to move this check into - symbol reading. */ - sym = NULL; - else - sym = lookup_symbol (MIPS_EFI_SYMBOL_NAME, b, LABEL_DOMAIN, - 0, NULL); - } + info = FRAME_OBSTACK_ZALLOC (struct alpha_sigtramp_unwind_cache); + *this_prologue_cache = info; - /* 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; + tdep = gdbarch_tdep (current_gdbarch); + info->sigcontext_addr = tdep->sigcontext_addr (next_frame); - if (sym) - { - /* IF this is the topmost frame AND - * (this proc does not have debugging information OR - * the PC is in the procedure prologue) - * THEN create a "heuristic" proc_desc (by analyzing - * the actual code) to replace the "official" proc_desc. - */ - proc_desc = (alpha_extra_func_info_t) SYMBOL_VALUE (sym); - if (next_frame == NULL) - { - if (PROC_DESC_IS_DUMMY (proc_desc) || alpha_in_prologue (pc, proc_desc)) - { - alpha_extra_func_info_t found_heuristic = - heuristic_proc_desc (PROC_LOW_ADDR (proc_desc), - pc, next_frame); - if (found_heuristic) - { - PROC_LOCALOFF (found_heuristic) = - PROC_LOCALOFF (proc_desc); - PROC_PC_REG (found_heuristic) = PROC_PC_REG (proc_desc); - proc_desc = found_heuristic; - } - } - } - } - else - { - long offset; - - /* Is linked_proc_desc_table really necessary? It only seems to be used - by procedure call dummys. However, the procedures being called ought - to have their own proc_descs, and even if they don't, - heuristic_proc_desc knows how to create them! */ - - register struct linked_proc_info *link; - for (link = linked_proc_desc_table; link; link = link->next) - if (PROC_LOW_ADDR (&link->info) <= pc - && PROC_HIGH_ADDR (&link->info) > pc) - return &link->info; - - /* If PC is inside a dynamically generated sigtramp handler, - create and push a procedure descriptor for that code: */ - offset = alpha_dynamic_sigtramp_offset (pc); - if (offset >= 0) - return push_sigtramp_desc (pc - offset); - - /* If heuristic_fence_post is non-zero, determine the procedure - start address by examining the instructions. - This allows us to find the start address of static functions which - have no symbolic information, as startaddr would have been set to - the preceding global function start address by the - find_pc_partial_function call above. */ - if (startaddr == 0 || heuristic_fence_post != 0) - startaddr = heuristic_proc_start (pc); - - proc_desc = - heuristic_proc_desc (startaddr, pc, next_frame); - } - return proc_desc; + return info; } -alpha_extra_func_info_t cached_proc_desc; - -static CORE_ADDR -alpha_frame_chain (struct frame_info *frame) -{ - alpha_extra_func_info_t proc_desc; - CORE_ADDR saved_pc = DEPRECATED_FRAME_SAVED_PC (frame); +/* Return the address of REGNO in a sigtramp frame. Since this is all + arithmetic, it doesn't seem worthwhile to cache it. */ - if (saved_pc == 0 || inside_entry_file (saved_pc)) - return 0; +#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 - proc_desc = find_proc_desc (saved_pc, frame); - if (!proc_desc) - return 0; +static CORE_ADDR +alpha_sigtramp_register_address (CORE_ADDR sigcontext_addr, unsigned int regno) +{ + if (regno < 32) + return sigcontext_addr + SIGFRAME_REGSAVE_OFF + regno * 8; + if (regno >= FP0_REGNUM && regno < FP0_REGNUM + 32) + return sigcontext_addr + SIGFRAME_FPREGSAVE_OFF + regno * 8; + if (regno == PC_REGNUM) + return sigcontext_addr + SIGFRAME_PC_OFF; - 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. */ - && !(get_frame_type (frame) == SIGTRAMP_FRAME)) - 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); + return 0; } -void -alpha_print_extra_frame_info (struct frame_info *fi) -{ - if (fi - && get_frame_extra_info (fi) - && get_frame_extra_info (fi)->proc_desc - && get_frame_extra_info (fi)->proc_desc->pdr.framereg < NUM_REGS) - printf_filtered (" frame pointer is at %s+%s\n", - REGISTER_NAME (get_frame_extra_info (fi)->proc_desc->pdr.framereg), - paddr_d (get_frame_extra_info (fi)->proc_desc->pdr.frameoffset)); -} +/* 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 *next_frame, + void **this_prologue_cache, + struct frame_id *this_id) { - /* Use proc_desc calculated in frame_chain */ - alpha_extra_func_info_t proc_desc = - get_next_frame (frame) - ? cached_proc_desc - : find_proc_desc (get_frame_pc (frame), get_next_frame (frame)); - - frame_extra_info_zalloc (frame, sizeof (struct frame_extra_info)); - - /* NOTE: cagney/2003-01-03: No need to set saved_regs to NULL, - always NULL by default. */ - /* frame->saved_regs = NULL; */ - get_frame_extra_info (frame)->localoff = 0; - get_frame_extra_info (frame)->pc_reg = ALPHA_RA_REGNUM; - get_frame_extra_info (frame)->proc_desc = proc_desc == &temp_proc_desc ? 0 : proc_desc; - if (proc_desc) + struct alpha_sigtramp_unwind_cache *info + = alpha_sigtramp_frame_unwind_cache (next_frame, this_prologue_cache); + struct gdbarch_tdep *tdep; + 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. */ + tdep = gdbarch_tdep (current_gdbarch); + 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. */ - get_frame_extra_info (frame)->localoff = PROC_LOCALOFF (proc_desc); - get_frame_extra_info (frame)->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)) - deprecated_update_frame_base_hack (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 (get_frame_pc (frame) == PROC_LOW_ADDR (proc_desc) - && !alpha_proc_desc_is_dyn_sigtramp (proc_desc)) - deprecated_update_frame_base_hack (frame, read_next_frame_reg (get_next_frame (frame), SP_REGNUM)); + int offset; + code_addr = frame_pc_unwind (next_frame); + offset = tdep->dynamic_sigtramp_offset (code_addr); + if (offset >= 0) + code_addr -= offset; else - deprecated_update_frame_base_hack (frame, read_next_frame_reg (get_next_frame (frame), 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 (get_frame_type (frame) == SIGTRAMP_FRAME), it is not - yet set. */ - /* FIXME: cagney/2002-11-18: This problem will go away once - frame.c:get_prev_frame() is modified to set the frame's - type before calling functions like this. */ - find_pc_partial_function (get_frame_pc (frame), &name, - (CORE_ADDR *) NULL, (CORE_ADDR *) NULL); - if (!PC_IN_SIGTRAMP (get_frame_pc (frame), name)) - { - frame_saved_regs_zalloc (frame); - memcpy (get_frame_saved_regs (frame), temp_saved_regs, - SIZEOF_FRAME_SAVED_REGS); - get_frame_saved_regs (frame)[PC_REGNUM] - = get_frame_saved_regs (frame)[ALPHA_RA_REGNUM]; - } - } + code_addr = 0; } -} - -static CORE_ADDR -alpha_frame_locals_address (struct frame_info *fi) -{ - return (get_frame_base (fi) - get_frame_extra_info (fi)->localoff); -} - -static CORE_ADDR -alpha_frame_args_address (struct frame_info *fi) -{ - return (get_frame_base (fi) - (ALPHA_NUM_ARG_REGS * 8)); -} - -/* ALPHA stack frames are almost impenetrable. When execution stops, - we basically have to look at symbol information for the function - that we stopped in, which tells us *which* register (if any) is - the base of the frame pointer, and what offset from that register - the frame itself is at. - - This presents a problem when trying to examine a stack in memory - (that isn't executing at the moment), using the "frame" command. We - don't have a PC, nor do we have any registers except SP. + else + code_addr = frame_func_unwind (next_frame); - 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. */ + /* The stack address is trivially read from the sigcontext. */ + stack_addr = alpha_sigtramp_register_address (info->sigcontext_addr, + ALPHA_SP_REGNUM); + stack_addr = read_memory_unsigned_integer (stack_addr, ALPHA_REGISTER_SIZE); -struct frame_info * -alpha_setup_arbitrary_frame (int argc, CORE_ADDR *argv) -{ - if (argc != 2) - error ("ALPHA frame specifications require two arguments: sp and pc"); - - return create_new_frame (argv[0], argv[1]); + *this_id = frame_id_build (stack_addr, code_addr); } -/* 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. */ +/* Retrieve the value of REGNUM in FRAME. Don't give up! */ -static CORE_ADDR -alpha_push_arguments (int nargs, struct value **args, CORE_ADDR sp, - int struct_return, CORE_ADDR struct_addr) +static void +alpha_sigtramp_frame_prev_register (struct frame_info *next_frame, + void **this_prologue_cache, + int regnum, int *optimizedp, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnump, void *bufferp) { - 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 alpha_sigtramp_unwind_cache *info + = alpha_sigtramp_frame_unwind_cache (next_frame, this_prologue_cache); + CORE_ADDR addr; - for (i = 0, m_arg = alpha_args; i < nargs; i++, m_arg++) + if (info->sigcontext_addr != 0) { - 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)) + /* All integer and fp registers are stored in memory. */ + addr = alpha_sigtramp_register_address (info->sigcontext_addr, regnum); + if (addr != 0) { - case TYPE_CODE_INT: - case TYPE_CODE_BOOL: - case TYPE_CODE_CHAR: - case TYPE_CODE_RANGE: - case TYPE_CODE_ENUM: - if (TYPE_LENGTH (arg_type) < TYPE_LENGTH (builtin_type_long)) - { - arg_type = builtin_type_long; - arg = value_cast (arg_type, arg); - } - break; - default: - break; + *optimizedp = 0; + *lvalp = lval_memory; + *addrp = addr; + *realnump = -1; + if (bufferp != NULL) + read_memory (addr, bufferp, ALPHA_REGISTER_SIZE); + return; } - 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; + /* 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. */ + frame_register (next_frame, regnum, optimizedp, lvalp, addrp, + realnump, bufferp); +} - /* Keep sp aligned to a multiple of 16 as the compiler does it too. */ - sp &= ~15; +static const struct frame_unwind alpha_sigtramp_frame_unwind = { + SIGTRAMP_FRAME, + alpha_sigtramp_frame_this_id, + alpha_sigtramp_frame_prev_register +}; - /* `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) - { - /* NOTE: cagney/2003-05-09: Using sizeof CORE_ADDR here is just - wrong. */ - store_unsigned_integer (raw_buffer, sizeof (CORE_ADDR), struct_addr); - write_memory (sp, raw_buffer, sizeof (CORE_ADDR)); - } +static const struct frame_unwind * +alpha_sigtramp_frame_p (CORE_ADDR pc) +{ + char *name; - /* Load the argument registers. */ - for (i = 0; i < required_arg_regs; i++) - { - LONGEST val; + /* We shouldn't even bother to try if the OSABI didn't register + a sigcontext_addr handler. */ + if (!gdbarch_tdep (current_gdbarch)->sigcontext_addr) + return NULL; - val = read_memory_integer (sp + i * 8, 8); - write_register (ALPHA_A0_REGNUM + i, val); - write_register (ALPHA_FPA0_REGNUM + i, val); - } + /* Otherwise we should be in a signal frame. */ + find_pc_partial_function (pc, &name, NULL, NULL); + if (PC_IN_SIGTRAMP (pc, name)) + return &alpha_sigtramp_frame_unwind; - return sp + arg_regs_size; + return NULL; } + +/* Fallback alpha frame unwinder. Uses instruction scanning and knows + something about the traditional layout of alpha stack frames. */ -static void -alpha_push_dummy_frame (void) +struct alpha_heuristic_unwind_cache { - 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_unsigned_integer (raw_buffer, 8, read_register (ireg)); - write_memory (save_address, raw_buffer, 8); - save_address += 8; - } - - store_unsigned_integer (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_unsigned_integer (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) = DEPRECATED_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; -} + CORE_ADDR *saved_regs; + CORE_ADDR vfp; + CORE_ADDR start_pc; + int return_reg; +}; -static void -alpha_pop_frame (void) -{ - register int regnum; - struct frame_info *frame = get_current_frame (); - CORE_ADDR new_sp = get_frame_base (frame); +/* 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; - alpha_extra_func_info_t proc_desc = get_frame_extra_info (frame)->proc_desc; +/* 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... */ - /* 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 (get_frame_pc (frame), get_next_frame (frame)); +static CORE_ADDR +alpha_heuristic_proc_start (CORE_ADDR pc) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); + CORE_ADDR last_non_nop = pc; + CORE_ADDR fence = pc - heuristic_fence_post; + CORE_ADDR orig_pc = pc; - /* 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... */ + if (pc == 0) + return 0; - write_register (PC_REGNUM, DEPRECATED_FRAME_SAVED_PC (frame)); - if (get_frame_saved_regs (frame) == 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 (get_frame_saved_regs (frame)[regnum], - 8)); - for (regnum = 32; --regnum >= 0;) - if (PROC_FREG_MASK (proc_desc) & (1 << regnum)) - write_register (regnum + FP0_REGNUM, - read_memory_integer (get_frame_saved_regs (frame)[regnum + FP0_REGNUM], 8)); - } - write_register (SP_REGNUM, new_sp); - flush_cached_frames (); + if (heuristic_fence_post == UINT_MAX + || fence < tdep->vm_min_address) + fence = tdep->vm_min_address; - if (proc_desc && (PROC_DESC_IS_DUMMY (proc_desc) - || alpha_proc_desc_is_dyn_sigtramp (proc_desc))) + /* 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 -= 4; pc >= fence; pc -= 4) { - struct linked_proc_info *pi_ptr, *prev_ptr; - - for (pi_ptr = linked_proc_desc_table, prev_ptr = NULL; - pi_ptr != NULL; - prev_ptr = pi_ptr, pi_ptr = pi_ptr->next) + unsigned int insn = alpha_read_insn (pc); + switch (insn) { - if (&pi_ptr->info == proc_desc) - break; + 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; } + } - if (pi_ptr == NULL) - error ("Can't locate dummy extra frame info\n"); + /* 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 (stop_soon == NO_STOP_QUIETLY) + { + static int blurb_printed = 0; - if (prev_ptr != NULL) - prev_ptr->next = pi_ptr->next; + if (fence == tdep->vm_min_address) + warning ("Hit beginning of text section without finding"); else - linked_proc_desc_table = pi_ptr->next; + warning ("Hit heuristic-fence-post without finding"); + warning ("enclosing function for address 0x%s", paddr_nz (orig_pc)); - xfree (pi_ptr); - } -} - -/* To skip prologues, I use this predicate. Returns either PC itself - if the code at PC does not look like a function prologue; otherwise - returns an address that (if we're lucky) follows the prologue. If - LENIENT, then we must skip everything which is involved in setting - up the frame (it's OK to skip more, just so long as we don't skip - anything which might clobber the registers which are being saved. - Currently we must not skip more on the alpha, but we might need the - lenient stuff some day. */ + 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; + } + } -static CORE_ADDR -alpha_skip_prologue_internal (CORE_ADDR pc, int lenient) -{ - unsigned long inst; - int offset; - CORE_ADDR post_prologue_pc; - char buf[4]; + return 0; +} - /* 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 alpha_heuristic_unwind_cache * +alpha_heuristic_frame_unwind_cache (struct frame_info *next_frame, + void **this_prologue_cache, + CORE_ADDR start_pc) +{ + 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 *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 = frame_obstack_zalloc (SIZEOF_FRAME_SAVED_REGS); - if (post_prologue_pc != 0) - return max (pc, post_prologue_pc); + limit_pc = frame_pc_unwind (next_frame); + if (start_pc == 0) + start_pc = alpha_heuristic_proc_start (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; - - status = read_memory_nobpt (pc + offset, buf, 4); - if (status) - memory_error (status, pc + offset); - inst = extract_unsigned_integer (buf, 4); + /* Limit the forward search to 50 instructions. */ + if (start_pc + 200 < limit_pc) + limit_pc = start_pc + 200; - /* 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; + for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += 4) + { + unsigned int word = alpha_read_insn (cur_pc); - 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 ((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; + + 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] = (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 + 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 & 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 (cur_pc); - break; + 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; + } + } + } } - return pc + offset; -} -static CORE_ADDR -alpha_skip_prologue (CORE_ADDR addr) -{ - return (alpha_skip_prologue_internal (addr, 0)); -} + /* Failing that, do default to the customary RA. */ + if (return_reg == -1) + return_reg = ALPHA_RA_REGNUM; + info->return_reg = return_reg; -#if 0 -/* Is address PC in the prologue (loosely defined) for function at - STARTADDR? */ + frame_unwind_unsigned_register (next_frame, frame_reg, &val); + info->vfp = val + frame_size; -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; + /* 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 (info->saved_regs[reg]) + info->saved_regs[reg] += val - 1; + + return info; } -#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) +/* Given a GDB frame, determine the address of the calling function's + frame. This will be used to create a new GDB frame struct. */ + +void +alpha_heuristic_frame_this_id (struct frame_info *next_frame, + void **this_prologue_cache, + struct frame_id *this_id) { - if (TYPE_LENGTH (valtype) >= REGISTER_RAW_SIZE (regnum)) - { - memcpy (virtual_buffer, raw_buffer, REGISTER_VIRTUAL_SIZE (regnum)); - return; - } + struct alpha_heuristic_unwind_cache *info + = alpha_heuristic_frame_unwind_cache (next_frame, this_prologue_cache, 0); - if (TYPE_CODE (valtype) == TYPE_CODE_FLT) - { - double d = deprecated_extract_floating (raw_buffer, REGISTER_RAW_SIZE (regnum)); - deprecated_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"); + *this_id = frame_id_build (info->vfp, info->start_pc); } -static void -alpha_register_convert_to_raw (struct type *valtype, int regnum, - char *virtual_buffer, char *raw_buffer) +/* Retrieve the value of REGNUM in FRAME. Don't give up! */ + +void +alpha_heuristic_frame_prev_register (struct frame_info *next_frame, + void **this_prologue_cache, + int regnum, int *optimizedp, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnump, void *bufferp) { - if (TYPE_LENGTH (valtype) >= REGISTER_RAW_SIZE (regnum)) + struct alpha_heuristic_unwind_cache *info + = alpha_heuristic_frame_unwind_cache (next_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; + + /* For all registers known to be saved in the current frame, + do the obvious and pull the value out. */ + if (info->saved_regs[regnum]) { - memcpy (raw_buffer, virtual_buffer, REGISTER_RAW_SIZE (regnum)); + *optimizedp = 0; + *lvalp = lval_memory; + *addrp = info->saved_regs[regnum]; + *realnump = -1; + if (bufferp != NULL) + read_memory (*addrp, bufferp, ALPHA_REGISTER_SIZE); return; } - if (TYPE_CODE (valtype) == TYPE_CODE_FLT) - { - double d = deprecated_extract_floating (virtual_buffer, TYPE_LENGTH (valtype)); - deprecated_store_floating (raw_buffer, REGISTER_RAW_SIZE (regnum), d); - } - else if (TYPE_CODE (valtype) == TYPE_CODE_INT && TYPE_LENGTH (valtype) <= 4) + /* The stack pointer of the previous frame is computed by popping + the current stack frame. */ + if (regnum == ALPHA_SP_REGNUM) { - 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); + *optimizedp = 0; + *lvalp = not_lval; + *addrp = 0; + *realnump = -1; + if (bufferp != NULL) + store_unsigned_integer (bufferp, ALPHA_REGISTER_SIZE, info->vfp); + return; } - else - error ("Cannot store value in floating point register"); -} - -static const unsigned char * -alpha_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr) -{ - static const unsigned char alpha_breakpoint[] = - { 0x80, 0, 0, 0 }; /* call_pal bpt */ - *lenptr = sizeof(alpha_breakpoint); - return (alpha_breakpoint); + /* Otherwise assume the next frame has the same register value. */ + frame_register (next_frame, regnum, optimizedp, lvalp, addrp, + realnump, bufferp); } -/* Given a return value in `regbuf' with a type `valtype', - extract and copy its value into `valbuf'. */ +static const struct frame_unwind alpha_heuristic_frame_unwind = { + NORMAL_FRAME, + alpha_heuristic_frame_this_id, + alpha_heuristic_frame_prev_register +}; -static void -alpha_extract_return_value (struct type *valtype, - char regbuf[ALPHA_REGISTER_BYTES], char *valbuf) +static const struct frame_unwind * +alpha_heuristic_frame_p (CORE_ADDR pc) { - 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)); + return &alpha_heuristic_frame_unwind; } -/* Given a return value in `regbuf' with a type `valtype', - write its value into the appropriate register. */ - -static void -alpha_store_return_value (struct type *valtype, char *valbuf) +CORE_ADDR +alpha_heuristic_frame_base_address (struct frame_info *next_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 (next_frame, this_prologue_cache, 0); - deprecated_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) @@ -1559,90 +978,53 @@ reinit_frame_cache_sfunc (char *args, int from_tty, struct cmd_list_element *c) reinit_frame_cache (); } -/* This is the definition of CALL_DUMMY_ADDRESS. It's a heuristic that is used - to find a convenient place in the text segment to stick a breakpoint to - detect the completion of a target function call (ala call_function_by_hand). - */ - -CORE_ADDR -alpha_call_dummy_address (void) -{ - CORE_ADDR entry; - struct minimal_symbol *sym; - - entry = entry_point_address (); - - if (entry != 0) - return entry; + +/* 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. - sym = lookup_minimal_symbol ("_Prelude", NULL, symfile_objfile); + 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. - if (!sym || MSYMBOL_TYPE (sym) != mst_text) - return 0; - else - return SYMBOL_VALUE_ADDRESS (sym) + 4; -} + 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. */ -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) +struct frame_info * +alpha_setup_arbitrary_frame (int argc, CORE_ADDR *argv) { - CORE_ADDR bp_address = CALL_DUMMY_ADDRESS (); + if (argc != 2) + error ("ALPHA frame specifications require two arguments: sp and pc"); - if (bp_address == 0) - error ("no place to put call"); - write_register (ALPHA_RA_REGNUM, bp_address); - write_register (ALPHA_T12_REGNUM, fun); + return create_new_frame (argv[0], argv[1]); } -/* On the Alpha, the call dummy code is nevery copied to user space - (see alpha_fix_call_dummy() above). The contents of this do not - matter. */ -LONGEST alpha_call_dummy_words[] = { 0 }; - -static int -alpha_use_struct_convention (int gcc_p, struct type *type) -{ - /* Structures are returned by ref in extra arg0. */ - return 1; -} +/* 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. */ -static void -alpha_store_struct_return (CORE_ADDR addr, CORE_ADDR sp) +static struct frame_id +alpha_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame) { - /* Store the address of the place in which to copy the structure the - subroutine will return. Handled by alpha_push_arguments. */ + ULONGEST base; + frame_unwind_unsigned_register (next_frame, ALPHA_SP_REGNUM, &base); + return frame_id_build (base, frame_pc_unwind (next_frame)); } static CORE_ADDR -alpha_extract_struct_value_address (char *regbuf) -{ - return (extract_address (regbuf + REGISTER_BYTE (ALPHA_V0_REGNUM), - REGISTER_RAW_SIZE (ALPHA_V0_REGNUM))); -} - -/* Figure out where the longjmp will land. - We expect the first arg to be a pointer to the jmp_buf structure from - which we extract the PC (JB_PC) that we will land at. The PC is copied - into the "pc". This routine returns true on success. */ - -static int -alpha_get_longjmp_target (CORE_ADDR *pc) +alpha_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) { - struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); - CORE_ADDR jb_addr; - char raw_buffer[ALPHA_MAX_REGISTER_RAW_SIZE]; - - jb_addr = read_register (ALPHA_A0_REGNUM); - - if (target_read_memory (jb_addr + (tdep->jb_pc * tdep->jb_elt_size), - raw_buffer, tdep->jb_elt_size)) - return 0; - - *pc = extract_address (raw_buffer, tdep->jb_elt_size); - return 1; + ULONGEST pc; + frame_unwind_unsigned_register (next_frame, ALPHA_PC_REGNUM, &pc); + return pc; } + /* 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 @@ -1722,6 +1104,8 @@ alpha_next_pc (CORE_ADDR pc) if (rav >= 0) goto branch_taken; break; + + /* ??? Missing floating-point branches. */ } } @@ -1753,7 +1137,6 @@ alpha_software_single_step (enum target_signal sig, int insert_breakpoints_p) } - /* 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. @@ -1783,12 +1166,11 @@ alpha_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) tdep = xmalloc (sizeof (struct gdbarch_tdep)); gdbarch = gdbarch_alloc (&info, tdep); - /* Lowest text address. This is used by heuristic_proc_start() to - decide when to stop looking. */ + /* Lowest text address. This is used by heuristic_proc_start() + to decide when to stop looking. */ tdep->vm_min_address = (CORE_ADDR) 0x120000000; tdep->dynamic_sigtramp_offset = NULL; - tdep->skip_sigtramp_frame = NULL; tdep->sigcontext_addr = NULL; tdep->jb_pc = -1; /* longjmp support not enabled by default */ @@ -1829,53 +1211,34 @@ alpha_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) alpha_register_convert_to_virtual); set_gdbarch_register_convert_to_raw (gdbarch, alpha_register_convert_to_raw); + /* Prologue heuristics. */ set_gdbarch_skip_prologue (gdbarch, alpha_skip_prologue); + /* Call info. */ set_gdbarch_frame_num_args (gdbarch, frame_num_args_unknown); set_gdbarch_frameless_function_invocation (gdbarch, generic_frameless_function_invocation_not); - set_gdbarch_deprecated_saved_pc_after_call (gdbarch, alpha_saved_pc_after_call); - - set_gdbarch_deprecated_frame_chain (gdbarch, alpha_frame_chain); - set_gdbarch_deprecated_frame_saved_pc (gdbarch, alpha_frame_saved_pc); - - set_gdbarch_deprecated_frame_init_saved_regs (gdbarch, alpha_frame_init_saved_regs); - set_gdbarch_use_struct_convention (gdbarch, alpha_use_struct_convention); set_gdbarch_deprecated_extract_return_value (gdbarch, alpha_extract_return_value); - set_gdbarch_deprecated_store_struct_return (gdbarch, alpha_store_struct_return); set_gdbarch_deprecated_store_return_value (gdbarch, alpha_store_return_value); set_gdbarch_deprecated_extract_struct_value_address (gdbarch, alpha_extract_struct_value_address); /* Settings for calling functions in the inferior. */ - set_gdbarch_deprecated_use_generic_dummy_frames (gdbarch, 0); set_gdbarch_deprecated_push_arguments (gdbarch, alpha_push_arguments); - set_gdbarch_deprecated_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_deprecated_call_dummy_words (gdbarch, alpha_call_dummy_words); set_gdbarch_deprecated_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_deprecated_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_address (gdbarch, alpha_call_dummy_address); set_gdbarch_deprecated_pc_in_call_dummy (gdbarch, deprecated_pc_in_call_dummy_at_entry_point); - set_gdbarch_deprecated_push_dummy_frame (gdbarch, alpha_push_dummy_frame); - /* Should be using push_dummy_call. */ - set_gdbarch_deprecated_dummy_write_sp (gdbarch, generic_target_write_sp); set_gdbarch_deprecated_fix_call_dummy (gdbarch, alpha_fix_call_dummy); - set_gdbarch_deprecated_init_frame_pc (gdbarch, init_frame_pc_noop); - set_gdbarch_deprecated_init_frame_pc_first (gdbarch, alpha_init_frame_pc_first); + + /* Methods for saving / extracting a dummy frame's ID. */ + set_gdbarch_unwind_dummy_id (gdbarch, alpha_unwind_dummy_id); + set_gdbarch_save_dummy_frame_tos (gdbarch, generic_save_dummy_frame_tos); + + /* 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); @@ -1895,27 +1258,12 @@ 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); - return gdbarch; -} - -static void -alpha_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file) -{ - struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); - - if (tdep == NULL) - return; + frame_unwind_append_predicate (gdbarch, alpha_sigtramp_frame_p); + frame_unwind_append_predicate (gdbarch, alpha_heuristic_frame_p); - fprintf_unfiltered (file, - "alpha_dump_tdep: vm_min_address = 0x%lx\n", - (long) tdep->vm_min_address); + frame_base_set_default (gdbarch, &alpha_heuristic_frame_base); - 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); + return gdbarch; } void @@ -1923,8 +1271,7 @@ _initialize_alpha_tdep (void) { struct cmd_list_element *c; - gdbarch_register (bfd_arch_alpha, alpha_gdbarch_init, alpha_dump_tdep); - + gdbarch_register (bfd_arch_alpha, alpha_gdbarch_init, NULL); deprecated_tm_print_insn = print_insn_alpha; /* Let the user set the fence post for heuristic_proc_start. */ diff --git a/gdb/alpha-tdep.h b/gdb/alpha-tdep.h index 0e8aefbfe16..412ec37c5a9 100644 --- a/gdb/alpha-tdep.h +++ b/gdb/alpha-tdep.h @@ -80,19 +80,15 @@ /* Target-dependent structure in gdbarch. */ struct gdbarch_tdep { - CORE_ADDR vm_min_address; /* used by heuristic_proc_start */ + CORE_ADDR vm_min_address; /* Used by alpha_heuristic_proc_start. */ /* If PC is inside a dynamically-generated signal trampoline function (i.e. one copied onto the user stack at run-time), return how many bytes PC is beyond the start of that function. Otherwise, return -1. */ LONGEST (*dynamic_sigtramp_offset) (CORE_ADDR); - /* If FRAME refers to a sigtramp frame, return the address of the next - frame. */ - CORE_ADDR (*skip_sigtramp_frame) (struct frame_info *, CORE_ADDR); - - /* Translate a signal handler frame into the address of the sigcontext - structure for that signal handler. */ + /* Translate a signal handler stack base address into the address of + the sigcontext structure for that signal handler. */ CORE_ADDR (*sigcontext_addr) (struct frame_info *); int jb_pc; /* Offset to PC value in jump buffer. @@ -101,6 +97,22 @@ struct gdbarch_tdep size_t jb_elt_size; /* And the size of each entry in the buf. */ }; -void alpha_software_single_step (enum target_signal, int); +extern unsigned int alpha_read_insn (CORE_ADDR pc); +extern void alpha_software_single_step (enum target_signal, int); + +/* Let other files poke at the heuristic unwinder. */ +extern CORE_ADDR alpha_after_prologue (CORE_ADDR pc); +extern struct alpha_heuristic_unwind_cache * + alpha_heuristic_frame_unwind_cache (struct frame_info *, void **, CORE_ADDR); +extern void alpha_heuristic_frame_this_id (struct frame_info *, void **, + struct frame_id *); +extern void alpha_heuristic_frame_prev_register (struct frame_info *, + void **, int, int *, + enum lval_type *, + CORE_ADDR *, int *, void *); +extern CORE_ADDR alpha_heuristic_frame_base_address (struct frame_info *, + void **); + +extern void alpha_mdebug_init_abi (struct gdbarch_info, struct gdbarch *); #endif /* ALPHA_TDEP_H */ diff --git a/gdb/config/alpha/alpha-linux.mt b/gdb/config/alpha/alpha-linux.mt index 25538b34589..8fe98f264b7 100644 --- a/gdb/config/alpha/alpha-linux.mt +++ b/gdb/config/alpha/alpha-linux.mt @@ -1,3 +1,4 @@ # Target: Little-endian Alpha -TDEPFILES= alpha-tdep.o alpha-linux-tdep.o solib.o solib-svr4.o solib-legacy.o +TDEPFILES= alpha-tdep.o alpha-mdebug-tdep.o alpha-linux-tdep.o \ + solib.o solib-svr4.o solib-legacy.o TM_FILE= tm-alphalinux.h diff --git a/gdb/config/alpha/tm-alpha.h b/gdb/config/alpha/tm-alpha.h index feb752a1495..9ced4f238ed 100644 --- a/gdb/config/alpha/tm-alpha.h +++ b/gdb/config/alpha/tm-alpha.h @@ -64,11 +64,6 @@ typedef struct alpha_extra_func_info #define mips_extra_func_info alpha_extra_func_info #define mips_extra_func_info_t alpha_extra_func_info_t - -#define PRINT_EXTRA_FRAME_INFO(fi) alpha_print_extra_frame_info ((fi)) -extern void alpha_print_extra_frame_info (struct frame_info *); - - /* It takes two values to specify a frame on the ALPHA. Sigh. In fact, at the moment, the *PC* is the primary value that sets up diff --git a/gdb/config/alpha/tm-alphalinux.h b/gdb/config/alpha/tm-alphalinux.h index 4858b90eba2..30ae4f756f3 100644 --- a/gdb/config/alpha/tm-alphalinux.h +++ b/gdb/config/alpha/tm-alphalinux.h @@ -2,8 +2,8 @@ definitions here are used when the _target_ system is running GNU/Linux. - Copyright 1996, 1998, 1999, 2000, 2002 Free Software Foundation, - Inc. + Copyright 1996, 1998, 1999, 2000, 2002, 2003 + Free Software Foundation, Inc. This file is part of GDB. @@ -27,13 +27,6 @@ #include "alpha/tm-alpha.h" -/* Get start and end address of sigtramp handler. */ - -extern LONGEST alpha_linux_sigtramp_offset (CORE_ADDR); -#define SIGTRAMP_START(pc) (pc - alpha_linux_sigtramp_offset (pc)) -#define SIGTRAMP_END(pc) (SIGTRAMP_START(pc) + 3*4) - - /* Number of traps that happen between exec'ing the shell to run an inferior, and when we finally get to the inferior code. This is 2 on GNU/Linux and most implementations. */ -- 2.30.2