* 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.
This commit is contained in:
parent
e9ecd94986
commit
d2427a719b
9 changed files with 1450 additions and 1529 deletions
|
@ -1,3 +1,77 @@
|
|||
2003-05-29 Richard Henderson <rth@redhat.com>
|
||||
|
||||
* 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 <cagney@redhat.com>
|
||||
|
||||
* gdb_assert.h (gdb_assert_fail): Provide different definitions
|
||||
|
|
|
@ -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;
|
||||
|
||||
if (read_memory_nobpt (pc, (char *) &w, 4) != 0)
|
||||
return -1;
|
||||
|
||||
off = -1;
|
||||
switch (w)
|
||||
switch (alpha_read_insn (pc))
|
||||
{
|
||||
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 */
|
||||
case 0x47de0410: /* bis $30,$30,$16 */
|
||||
case 0x47fe0410: /* bis $31,$30,$16 */
|
||||
return 0;
|
||||
|
||||
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;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
pc -= off;
|
||||
if (pc & 0x7)
|
||||
{
|
||||
/* designated sequence is not quadword aligned */
|
||||
return -1;
|
||||
}
|
||||
if (read_memory_nobpt (pc, (char *) i, sizeof (i)) != 0)
|
||||
}
|
||||
|
||||
static LONGEST
|
||||
alpha_linux_sigtramp_offset (CORE_ADDR pc)
|
||||
{
|
||||
long i, off;
|
||||
|
||||
if (pc & 3)
|
||||
return -1;
|
||||
|
||||
if (i[0] == 0x47de0410 && i[1] == 0x43ecf400 && i[2] == 0x00000083)
|
||||
return off;
|
||||
/* Guess where we might be in the sequence. */
|
||||
off = alpha_linux_sigtramp_offset_1 (pc);
|
||||
if (off < 0)
|
||||
return -1;
|
||||
|
||||
return -1;
|
||||
/* Verify that the other two insns of the sequence are as we expect. */
|
||||
pc -= off;
|
||||
for (i = 0; i < 12; i += 4)
|
||||
{
|
||||
if (i == off)
|
||||
continue;
|
||||
if (alpha_linux_sigtramp_offset_1 (pc + i) != i)
|
||||
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;
|
||||
}
|
||||
|
|
442
gdb/alpha-mdebug-tdep.c
Normal file
442
gdb/alpha-mdebug-tdep.c
Normal file
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
2249
gdb/alpha-tdep.c
2249
gdb/alpha-tdep.c
File diff suppressed because it is too large
Load diff
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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. */
|
||||
|
|
Loading…
Reference in a new issue