* tm-sparc.c (EXTRA_FRAME_INFO): New field sp_offset.
* sparc-tdep.c (sparc_init_extra_frame_info): Set it. (examine_prologue, sparc_init_extra_frame_info): Use ->frame plus ->sp_offset to compute the address something is saved at, not ->bottom. * sparc-tdep.c (get_saved_register): New function. * tm-sparc.h: Define GET_SAVED_REGISTER; don't define FRAME_FIND_SAVED_REGS, HAVE_REGISTER_WINDOWS or REGISTER_IN_WINDOW_P. * stack.c (frame_info): Add comment about what to do if FRAME_FIND_SAVED_REGS is not defined. * sparc-tdep.c (sparc_init_extra_frame_info): Set ->frame field here. Get it right for flat frames. * sparc-tdep.c (sparc_frame_chain): Instead of returning meaningful value for ->frame field, just return dummy value. This change is needed because the old code didn't deal with mixed flat and non-flat frames. * sparc-tdep.c (sparc_pop_frame): Write SP_REGNUM from frame->frame, don't go through saved regs for this. * sparc-tdep.c: Move guts of skip_prologue to new function examine_prologue. Check for flat prologue and set is_flat. Provide the caller with the information about what is saved where if desired. (skip_prologue, sparc_frame_find_saved_regs): Call examine_prologue. * sparc-tdep.c: Replace union sparc_insn_layout and anonymous union in isannulled, which won't work on a little-endian host, with X_* macros. * sparc-tdep.c (sparc_frame_saved_pc): If addr == 0, the saved PC is still in %o7. * config/sparc/tm-sparc.h: Define INIT_FRAME_PC and INIT_FRAME_PC_FIRST. * blockframe.c (get_prev_frame_info): Modify comments regarding INIT_FRAME_PC_FIRST and the sparc. * sparc-tdep.c (single_step): Use 4 not sizeof (long) for size of instruction.
This commit is contained in:
parent
4ec56c1fec
commit
ee7b9e92f6
3 changed files with 473 additions and 238 deletions
|
@ -1,10 +1,55 @@
|
|||
Sat Dec 17 13:23:21 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
|
||||
|
||||
* tm-sparc.c (EXTRA_FRAME_INFO): New field sp_offset.
|
||||
* sparc-tdep.c (sparc_init_extra_frame_info): Set it.
|
||||
(examine_prologue, sparc_init_extra_frame_info): Use ->frame plus
|
||||
->sp_offset to compute the address something is saved at, not
|
||||
->bottom.
|
||||
|
||||
* sparc-tdep.c (get_saved_register): New function.
|
||||
* tm-sparc.h: Define GET_SAVED_REGISTER; don't define
|
||||
FRAME_FIND_SAVED_REGS, HAVE_REGISTER_WINDOWS or REGISTER_IN_WINDOW_P.
|
||||
* stack.c (frame_info): Add comment about what to do if
|
||||
FRAME_FIND_SAVED_REGS is not defined.
|
||||
|
||||
* sparc-tdep.c (sparc_init_extra_frame_info): Set ->frame field
|
||||
here. Get it right for flat frames.
|
||||
* sparc-tdep.c (sparc_frame_chain): Instead of returning
|
||||
meaningful value for ->frame field, just return dummy value.
|
||||
This change is needed because the old code didn't deal with mixed
|
||||
flat and non-flat frames.
|
||||
|
||||
* sparc-tdep.c (sparc_pop_frame): Write SP_REGNUM from
|
||||
frame->frame, don't go through saved regs for this.
|
||||
|
||||
* sparc-tdep.c: Move guts of skip_prologue to new function
|
||||
examine_prologue. Check for flat prologue and set is_flat.
|
||||
Provide the caller with the information about what is saved where
|
||||
if desired.
|
||||
(skip_prologue, sparc_frame_find_saved_regs): Call examine_prologue.
|
||||
|
||||
* sparc-tdep.c: Replace union sparc_insn_layout and anonymous
|
||||
union in isannulled, which won't work on a little-endian host,
|
||||
with X_* macros.
|
||||
|
||||
* sparc-tdep.c (sparc_frame_saved_pc): If addr == 0, the saved PC
|
||||
is still in %o7.
|
||||
|
||||
* config/sparc/tm-sparc.h: Define INIT_FRAME_PC and
|
||||
INIT_FRAME_PC_FIRST.
|
||||
* blockframe.c (get_prev_frame_info): Modify comments regarding
|
||||
INIT_FRAME_PC_FIRST and the sparc.
|
||||
|
||||
* sparc-tdep.c (single_step): Use 4 not sizeof (long) for size of
|
||||
instruction.
|
||||
|
||||
Sat Dec 17 02:33:37 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de)
|
||||
|
||||
* c-typeprint.c (c_type_print_base): Use `show' of -1 to print
|
||||
the return type of methods to avoid infinite loops with anonymous
|
||||
types.
|
||||
* valops.c (search_struct_field): Handle anonymous unions.
|
||||
|
||||
|
||||
* sparc-tdep.c (sunos4_skip_trampoline_code): New function
|
||||
to correctly handle steps into -g compiled PIC objects in the
|
||||
main executable.
|
||||
|
|
|
@ -187,11 +187,12 @@ extern CORE_ADDR sparc_pc_adjust PARAMS ((CORE_ADDR));
|
|||
register state, the array `registers'. On the sparc, `registers'
|
||||
contains the ins and locals, even though they are saved on the
|
||||
stack rather than with the other registers, and this causes hair
|
||||
and confusion in places like pop_frame. It probably would be
|
||||
and confusion in places like pop_frame. It might be
|
||||
better to remove the ins and locals from `registers', make sure
|
||||
that get_saved_register can get them from the stack (even in the
|
||||
innermost frame), and make this the way to access them. For the
|
||||
frame pointer we would do that via TARGET_READ_FP. */
|
||||
frame pointer we would do that via TARGET_READ_FP. On the other hand,
|
||||
that is likely to be confusing or worse for flat frames. */
|
||||
|
||||
#define REGISTER_BYTES (32*4+32*4+8*4)
|
||||
|
||||
|
@ -200,18 +201,11 @@ extern CORE_ADDR sparc_pc_adjust PARAMS ((CORE_ADDR));
|
|||
/* ?? */
|
||||
#define REGISTER_BYTE(N) ((N)*4)
|
||||
|
||||
/* The SPARC processor has register windows. */
|
||||
/* We need to override GET_SAVED_REGISTER so that we can deal with the way
|
||||
outs change into ins in different frames. HAVE_REGISTER_WINDOWS can't
|
||||
deal with this case and also handle flat frames at the same time. */
|
||||
|
||||
#define HAVE_REGISTER_WINDOWS
|
||||
|
||||
/* Is this register part of the register window system? A yes answer
|
||||
implies that 1) The name of this register will not be the same in
|
||||
other frames, and 2) This register is automatically "saved" (out
|
||||
registers shifting into ins counts) upon subroutine calls and thus
|
||||
there is no need to search more than one stack frame for it. */
|
||||
|
||||
#define REGISTER_IN_WINDOW_P(regnum) \
|
||||
((regnum) >= 8 && (regnum) < 32)
|
||||
#define GET_SAVED_REGISTER 1
|
||||
|
||||
/* Number of bytes of storage in the actual machine representation
|
||||
for register N. */
|
||||
|
@ -342,8 +336,12 @@ sparc_extract_struct_value_address PARAMS ((char [REGISTER_BYTES]));
|
|||
#define EXTRA_FRAME_INFO \
|
||||
CORE_ADDR bottom; \
|
||||
int flat; \
|
||||
/* Following fields only relevant for flat frames. */ \
|
||||
CORE_ADDR pc_addr; \
|
||||
CORE_ADDR fp_addr; \
|
||||
/* Add this to ->frame to get the value of the stack pointer at the */ \
|
||||
/* time of the register saves. */ \
|
||||
int sp_offset;
|
||||
|
||||
#define INIT_EXTRA_FRAME_INFO(fromleaf, fci) \
|
||||
sparc_init_extra_frame_info (fromleaf, fci)
|
||||
|
@ -356,8 +354,19 @@ extern void sparc_init_extra_frame_info ();
|
|||
(fi)->pc_addr, (fi)->fp_addr); \
|
||||
}
|
||||
|
||||
#ifdef __STDC__
|
||||
struct frame_info;
|
||||
#endif
|
||||
|
||||
#define FRAME_CHAIN(thisframe) (sparc_frame_chain (thisframe))
|
||||
extern CORE_ADDR sparc_frame_chain ();
|
||||
extern CORE_ADDR sparc_frame_chain PARAMS ((struct frame_info *));
|
||||
|
||||
/* INIT_EXTRA_FRAME_INFO needs the PC to detect flat frames. */
|
||||
|
||||
#define INIT_FRAME_PC(fromleaf, prev) /* nothing */
|
||||
#define INIT_FRAME_PC_FIRST(fromleaf, prev) \
|
||||
(prev)->pc = ((fromleaf) ? SAVED_PC_AFTER_CALL ((prev)->next) : \
|
||||
(prev)->next ? FRAME_SAVED_PC ((prev)->next) : read_pc ());
|
||||
|
||||
/* Define other aspects of the stack frame. */
|
||||
|
||||
|
@ -397,19 +406,6 @@ extern CORE_ADDR sparc_frame_saved_pc ();
|
|||
/* Return number of bytes at start of arglist that are not really args. */
|
||||
|
||||
#define FRAME_ARGS_SKIP 68
|
||||
|
||||
/* Put here the code to store, into a struct frame_saved_regs,
|
||||
the addresses of the saved registers of frame described by FRAME_INFO.
|
||||
The actual code is in sparc-tdep.c so we can debug it sanely. */
|
||||
|
||||
#define FRAME_FIND_SAVED_REGS(fi, frame_saved_regs) \
|
||||
sparc_frame_find_saved_regs ((fi), &(frame_saved_regs))
|
||||
#ifdef __STDC__
|
||||
struct frame_info;
|
||||
struct frame_saved_regs;
|
||||
#endif
|
||||
extern void sparc_frame_find_saved_regs PARAMS ((struct frame_info *,
|
||||
struct frame_saved_regs *));
|
||||
|
||||
/* Things needed for making the inferior call functions. */
|
||||
/*
|
||||
|
|
614
gdb/sparc-tdep.c
614
gdb/sparc-tdep.c
|
@ -31,30 +31,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|||
|
||||
#include "gdbcore.h"
|
||||
|
||||
/* Definition of SPARC instruction layouts. */
|
||||
|
||||
union sparc_insn_layout
|
||||
{
|
||||
unsigned long int code;
|
||||
struct
|
||||
{
|
||||
unsigned int op:2;
|
||||
unsigned int rd:5;
|
||||
unsigned int op2:3;
|
||||
unsigned int imm22:22;
|
||||
} sethi;
|
||||
struct
|
||||
{
|
||||
unsigned int op:2;
|
||||
unsigned int rd:5;
|
||||
unsigned int op3:6;
|
||||
unsigned int rs1:5;
|
||||
unsigned int i:1;
|
||||
unsigned int simm13:13;
|
||||
} add;
|
||||
int i;
|
||||
};
|
||||
|
||||
/* From infrun.c */
|
||||
extern int stop_after_trap;
|
||||
|
||||
|
@ -66,6 +42,21 @@ extern int stop_after_trap;
|
|||
|
||||
int deferred_stores = 0; /* Cumulates stores we want to do eventually. */
|
||||
|
||||
/* Macros to extract fields from sparc instructions. */
|
||||
#define X_OP(i) (((i) >> 30) & 0x3)
|
||||
#define X_RD(i) (((i) >> 25) & 0x1f)
|
||||
#define X_A(i) (((i) >> 29) & 1)
|
||||
#define X_COND(i) (((i) >> 25) & 0xf)
|
||||
#define X_OP2(i) (((i) >> 22) & 0x7)
|
||||
#define X_IMM22(i) ((i) & 0x3fffff)
|
||||
#define X_OP3(i) (((i) >> 19) & 0x3f)
|
||||
#define X_RS1(i) (((i) >> 14) & 0x1f)
|
||||
#define X_I(i) (((i) >> 13) & 1)
|
||||
#define X_IMM13(i) ((i) & 0x1fff)
|
||||
/* Sign extension macros. */
|
||||
#define X_SIMM13(i) ((X_IMM13 (i) ^ 0x1000) - 0x1000)
|
||||
#define X_DISP22(i) ((X_IMM22 (i) ^ 0x200000) - 0x200000)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
Error, not_branch, bicc, bicca, ba, baa, ticc, ta
|
||||
|
@ -114,7 +105,7 @@ single_step (ignore)
|
|||
/* printf_unfiltered ("set break at %x\n",next_pc); */
|
||||
|
||||
pc = read_register (PC_REGNUM);
|
||||
pc_instruction = read_memory_integer (pc, sizeof(pc_instruction));
|
||||
pc_instruction = read_memory_integer (pc, 4);
|
||||
br = isannulled (pc_instruction, pc, &target);
|
||||
brknpc4 = brktrg = 0;
|
||||
|
||||
|
@ -166,69 +157,91 @@ sparc_init_extra_frame_info (fromleaf, fi)
|
|||
{
|
||||
char *name;
|
||||
CORE_ADDR addr;
|
||||
union sparc_insn_layout x;
|
||||
int insn;
|
||||
|
||||
fi->bottom =
|
||||
(fi->next ?
|
||||
(fi->frame == fi->next->frame ? fi->next->bottom : fi->next->frame) :
|
||||
read_register (SP_REGNUM));
|
||||
|
||||
/* If fi->next is NULL, then we already set ->frame by passing read_fp()
|
||||
to create_new_frame. */
|
||||
if (fi->next)
|
||||
{
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
int err;
|
||||
|
||||
/* Compute ->frame as if not flat. If it is flat, we'll change
|
||||
it later. */
|
||||
/* FIXME: If error reading memory, should just stop backtracing, rather
|
||||
than error(). */
|
||||
get_saved_register (buf, 0, 0, fi, FP_REGNUM, 0);
|
||||
fi->frame = extract_address (buf, REGISTER_RAW_SIZE (FP_REGNUM));
|
||||
}
|
||||
|
||||
/* Decide whether this is a function with a ``flat register window''
|
||||
frame. For such functions, the frame pointer is actually in %i7. */
|
||||
fi->flat = 0;
|
||||
if (find_pc_partial_function (fi->pc, &name, &addr, NULL))
|
||||
{
|
||||
/* See if the function starts with an add (which will be of a
|
||||
negative number if a flat frame) to the sp. */
|
||||
x.i = read_memory_integer (addr, 4);
|
||||
if (x.add.op == 2 && x.add.rd == 14 && x.add.op3 == 0)
|
||||
negative number if a flat frame) to the sp. FIXME: Does not
|
||||
handle large frames which will need more than one instruction
|
||||
to adjust the sp. */
|
||||
insn = read_memory_integer (addr, 4);
|
||||
if (X_OP (insn) == 2 && X_RD (insn) == 14 && X_OP3 (insn) == 0
|
||||
&& X_I (insn) && X_SIMM13 (insn) < 0)
|
||||
{
|
||||
int offset = X_SIMM13 (insn);
|
||||
|
||||
/* Then look for a save of %i7 into the frame. */
|
||||
x.i = read_memory_integer (addr + 4, 4);
|
||||
if (x.add.op == 3
|
||||
&& x.add.rd == 31
|
||||
&& x.add.op3 == 4
|
||||
&& x.add.rs1 == 14)
|
||||
insn = read_memory_integer (addr + 4, 4);
|
||||
if (X_OP (insn) == 3
|
||||
&& X_RD (insn) == 31
|
||||
&& X_OP3 (insn) == 4
|
||||
&& X_RS1 (insn) == 14)
|
||||
{
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
|
||||
/* We definitely have a flat frame now. */
|
||||
fi->flat = 1;
|
||||
|
||||
fi->sp_offset = offset;
|
||||
|
||||
/* Overwrite the frame's address with the value in %i7. */
|
||||
fi->frame =
|
||||
(fi->next ?
|
||||
(fi->frame == fi->next->frame ? fi->bottom : fi->frame) :
|
||||
read_register (I7_REGNUM));
|
||||
get_saved_register (buf, 0, 0, fi, I7_REGNUM, 0);
|
||||
fi->frame = extract_address (buf, REGISTER_RAW_SIZE (I7_REGNUM));
|
||||
|
||||
/* Record where the fp got saved. */
|
||||
fi->fp_addr = fi->bottom + x.add.simm13;
|
||||
fi->fp_addr = fi->frame + fi->sp_offset + X_SIMM13 (insn);
|
||||
|
||||
/* Also try to collect where the pc got saved to. */
|
||||
fi->pc_addr = 0;
|
||||
x.i = read_memory_integer (addr + 12, 4);
|
||||
if (x.add.op == 3
|
||||
&& x.add.rd == 15
|
||||
&& x.add.op3 == 4
|
||||
&& x.add.rs1 == 14)
|
||||
fi->pc_addr = fi->bottom + x.add.simm13;
|
||||
insn = read_memory_integer (addr + 12, 4);
|
||||
if (X_OP (insn) == 3
|
||||
&& X_RD (insn) == 15
|
||||
&& X_OP3 (insn) == 4
|
||||
&& X_RS1 (insn) == 14)
|
||||
fi->pc_addr = fi->frame + fi->sp_offset + X_SIMM13 (insn);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fi->next && fi->frame == 0)
|
||||
{
|
||||
/* Kludge to cause init_prev_frame_info to destroy the new frame. */
|
||||
fi->frame = fi->next->frame;
|
||||
fi->pc = fi->next->pc;
|
||||
}
|
||||
}
|
||||
|
||||
CORE_ADDR
|
||||
sparc_frame_chain (frame)
|
||||
struct frame_info *frame;
|
||||
{
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
int err;
|
||||
CORE_ADDR addr;
|
||||
|
||||
if (frame->flat)
|
||||
addr = frame->fp_addr;
|
||||
else
|
||||
addr = frame->frame + FRAME_SAVED_I0 +
|
||||
REGISTER_RAW_SIZE (FP_REGNUM) * (FP_REGNUM - I0_REGNUM);
|
||||
err = target_read_memory (addr, buf, REGISTER_RAW_SIZE (FP_REGNUM));
|
||||
if (err)
|
||||
return 0;
|
||||
return extract_address (buf, REGISTER_RAW_SIZE (FP_REGNUM));
|
||||
/* Value that will cause FRAME_CHAIN_VALID to not worry about the chain
|
||||
value. If it realy is zero, we detect it later in
|
||||
sparc_init_prev_frame. */
|
||||
return (CORE_ADDR)1;
|
||||
}
|
||||
|
||||
CORE_ADDR
|
||||
|
@ -285,6 +298,12 @@ sparc_frame_saved_pc (frame)
|
|||
else
|
||||
addr = frame->bottom + FRAME_SAVED_I0 +
|
||||
REGISTER_RAW_SIZE (I7_REGNUM) * (I7_REGNUM - I0_REGNUM);
|
||||
|
||||
if (addr == 0)
|
||||
/* A flat frame leaf function might not save the PC anywhere,
|
||||
just leave it in %o7. */
|
||||
return PC_ADJUST (read_register (O7_REGNUM));
|
||||
|
||||
read_memory (addr, buf, REGISTER_RAW_SIZE (I7_REGNUM));
|
||||
return PC_ADJUST (extract_address (buf, REGISTER_RAW_SIZE (I7_REGNUM)));
|
||||
}
|
||||
|
@ -326,24 +345,29 @@ setup_arbitrary_frame (argc, argv)
|
|||
This routine should be more specific in its actions; making sure
|
||||
that it uses the same register in the initial prologue section. */
|
||||
|
||||
CORE_ADDR
|
||||
skip_prologue (start_pc, frameless_p)
|
||||
static CORE_ADDR examine_prologue PARAMS ((CORE_ADDR, int, struct frame_info *,
|
||||
struct frame_saved_regs *));
|
||||
|
||||
static CORE_ADDR
|
||||
examine_prologue (start_pc, frameless_p, fi, saved_regs)
|
||||
CORE_ADDR start_pc;
|
||||
int frameless_p;
|
||||
struct frame_info *fi;
|
||||
struct frame_saved_regs *saved_regs;
|
||||
{
|
||||
union sparc_insn_layout x;
|
||||
int insn;
|
||||
int dest = -1;
|
||||
CORE_ADDR pc = start_pc;
|
||||
int is_flat = 0;
|
||||
|
||||
x.i = read_memory_integer (pc, 4);
|
||||
insn = read_memory_integer (pc, 4);
|
||||
|
||||
/* Recognize the `sethi' insn and record its destination. */
|
||||
if (x.sethi.op == 0 && x.sethi.op2 == 4)
|
||||
if (X_OP (insn) == 0 && X_OP2 (insn) == 4)
|
||||
{
|
||||
dest = x.sethi.rd;
|
||||
dest = X_RD (insn);
|
||||
pc += 4;
|
||||
x.i = read_memory_integer (pc, 4);
|
||||
insn = read_memory_integer (pc, 4);
|
||||
}
|
||||
|
||||
/* Recognize an add immediate value to register to either %g1 or
|
||||
|
@ -352,63 +376,99 @@ skip_prologue (start_pc, frameless_p)
|
|||
It doesn't check that rs1 == rd because in theory "sub %g0, 5, %g1"
|
||||
followed by "save %sp, %g1, %sp" is a valid prologue (Not that
|
||||
I imagine any compiler really does that, however). */
|
||||
if (x.add.op == 2 && x.add.i && (x.add.rd == 1 || x.add.rd == dest))
|
||||
if (X_OP (insn) == 2
|
||||
&& X_I (insn)
|
||||
&& (X_RD (insn) == 1 || X_RD (insn) == dest))
|
||||
{
|
||||
pc += 4;
|
||||
x.i = read_memory_integer (pc, 4);
|
||||
insn = read_memory_integer (pc, 4);
|
||||
}
|
||||
|
||||
/* This recognizes any SAVE insn. But why do the XOR and then
|
||||
the compare? That's identical to comparing against 60 (as long
|
||||
as there isn't any sign extension). */
|
||||
if (x.add.op == 2 && (x.add.op3 ^ 32) == 28)
|
||||
/* Recognize any SAVE insn. */
|
||||
if (X_OP (insn) == 2 && X_OP3 (insn) == 60)
|
||||
{
|
||||
pc += 4;
|
||||
if (frameless_p) /* If the save is all we care about, */
|
||||
return pc; /* return before doing more work */
|
||||
x.i = read_memory_integer (pc, 4);
|
||||
insn = read_memory_integer (pc, 4);
|
||||
}
|
||||
else if (x.add.op == 2 && x.add.rd == 14 && x.add.op3 == 0)
|
||||
/* Recognize add to %sp. */
|
||||
else if (X_OP (insn) == 2 && X_RD (insn) == 14 && X_OP3 (insn) == 0)
|
||||
{
|
||||
pc += 4;
|
||||
if (frameless_p) /* If the add is all we care about, */
|
||||
return pc; /* return before doing more work */
|
||||
/* FIXME test that the following instructions are the right ones
|
||||
for a flat frame */
|
||||
x.i = read_memory_integer (pc, 4);
|
||||
pc += 4;
|
||||
x.i = read_memory_integer (pc, 4);
|
||||
pc += 4;
|
||||
x.i = read_memory_integer (pc, 4);
|
||||
is_flat = 1;
|
||||
insn = read_memory_integer (pc, 4);
|
||||
/* Recognize store of frame pointer (i7). */
|
||||
if (X_OP (insn) == 3
|
||||
&& X_RD (insn) == 31
|
||||
&& X_OP3 (insn) == 4
|
||||
&& X_RS1 (insn) == 14)
|
||||
{
|
||||
pc += 4;
|
||||
insn = read_memory_integer (pc, 4);
|
||||
|
||||
/* Recognize sub %sp, <anything>, %i7. */
|
||||
if (X_OP (insn) == 2
|
||||
&& X_OP3 (insn) == 4
|
||||
&& X_RS1 (insn) == 14
|
||||
&& X_RD (insn) == 31)
|
||||
{
|
||||
pc += 4;
|
||||
insn = read_memory_integer (pc, 4);
|
||||
}
|
||||
else
|
||||
return pc;
|
||||
}
|
||||
else
|
||||
return pc;
|
||||
}
|
||||
else
|
||||
/* Without a save or add instruction, it's not a prologue. */
|
||||
return start_pc;
|
||||
|
||||
/* Now we need to recognize stores into the frame from the input
|
||||
registers. This recognizes all non alternate stores of input
|
||||
register, into a location offset from the frame pointer. */
|
||||
while ((x.add.op == 3
|
||||
&& (x.add.op3 & 0x3c) == 4 /* Store, non-alternate. */
|
||||
&& (x.add.rd & 0x18) == 0x18 /* Input register. */
|
||||
&& x.add.i /* Immediate mode. */
|
||||
&& x.add.rs1 == 30 /* Off of frame pointer. */
|
||||
/* Into reserved stack space. */
|
||||
&& x.add.simm13 >= 0x44
|
||||
&& x.add.simm13 < 0x5b)
|
||||
|| (is_flat
|
||||
&& x.add.op == 3
|
||||
&& x.add.op3 == 4
|
||||
&& x.add.rs1 == 14
|
||||
))
|
||||
while (1)
|
||||
{
|
||||
/* Recognize stores into the frame from the input registers.
|
||||
This recognizes all non alternate stores of input register,
|
||||
into a location offset from the frame pointer. */
|
||||
if ((X_OP (insn) == 3
|
||||
&& (X_OP3 (insn) & 0x3c) == 4 /* Store, non-alternate. */
|
||||
&& (X_RD (insn) & 0x18) == 0x18 /* Input register. */
|
||||
&& X_I (insn) /* Immediate mode. */
|
||||
&& X_RS1 (insn) == 30 /* Off of frame pointer. */
|
||||
/* Into reserved stack space. */
|
||||
&& X_SIMM13 (insn) >= 0x44
|
||||
&& X_SIMM13 (insn) < 0x5b))
|
||||
;
|
||||
else if (is_flat
|
||||
&& X_OP (insn) == 3
|
||||
&& X_OP3 (insn) == 4
|
||||
&& X_RS1 (insn) == 14
|
||||
)
|
||||
{
|
||||
if (saved_regs && X_I (insn))
|
||||
saved_regs->regs[X_RD (insn)] =
|
||||
fi->frame + fi->sp_offset + X_SIMM13 (insn);
|
||||
}
|
||||
else
|
||||
break;
|
||||
pc += 4;
|
||||
x.i = read_memory_integer (pc, 4);
|
||||
insn = read_memory_integer (pc, 4);
|
||||
}
|
||||
|
||||
return pc;
|
||||
}
|
||||
|
||||
CORE_ADDR
|
||||
skip_prologue (start_pc, frameless_p)
|
||||
CORE_ADDR start_pc;
|
||||
int frameless_p;
|
||||
{
|
||||
return examine_prologue (start_pc, frameless_p, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Check instruction at ADDR to see if it is an annulled branch.
|
||||
All other instructions will go to NPC or will trap.
|
||||
Set *TARGET if we find a candidate branch; set to zero if not. */
|
||||
|
@ -420,138 +480,135 @@ isannulled (instruction, addr, target)
|
|||
{
|
||||
branch_type val = not_branch;
|
||||
long int offset; /* Must be signed for sign-extend. */
|
||||
union
|
||||
{
|
||||
unsigned long int code;
|
||||
struct
|
||||
{
|
||||
unsigned int op:2;
|
||||
unsigned int a:1;
|
||||
unsigned int cond:4;
|
||||
unsigned int op2:3;
|
||||
unsigned int disp22:22;
|
||||
} b;
|
||||
} insn;
|
||||
|
||||
*target = 0;
|
||||
insn.code = instruction;
|
||||
|
||||
if (insn.b.op == 0
|
||||
&& (insn.b.op2 == 2 || insn.b.op2 == 6 || insn.b.op2 == 7))
|
||||
if (X_OP (instruction) == 0
|
||||
&& (X_OP2 (instruction) == 2
|
||||
|| X_OP2 (instruction) == 6
|
||||
|| X_OP2 (instruction) == 7))
|
||||
{
|
||||
if (insn.b.cond == 8)
|
||||
val = insn.b.a ? baa : ba;
|
||||
if (X_COND (instruction) == 8)
|
||||
val = X_A (instruction) ? baa : ba;
|
||||
else
|
||||
val = insn.b.a ? bicca : bicc;
|
||||
offset = 4 * ((int) (insn.b.disp22 << 10) >> 10);
|
||||
val = X_A (instruction) ? bicca : bicc;
|
||||
offset = 4 * X_DISP22 (instruction);
|
||||
*target = addr + offset;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Find register number REGNUM relative to FRAME and put its
|
||||
(raw) contents in *RAW_BUFFER. Set *OPTIMIZED if the variable
|
||||
was optimized out (and thus can't be fetched). If the variable
|
||||
was fetched from memory, set *ADDRP to where it was fetched from,
|
||||
otherwise it was fetched from a register.
|
||||
|
||||
/* sparc_frame_find_saved_regs ()
|
||||
|
||||
Stores, into a struct frame_saved_regs,
|
||||
the addresses of the saved registers of frame described by FRAME_INFO.
|
||||
This includes special registers such as pc and fp saved in special
|
||||
ways in the stack frame. sp is even more special:
|
||||
the address we return for it IS the sp for the next frame.
|
||||
|
||||
Note that on register window machines, we are currently making the
|
||||
assumption that window registers are being saved somewhere in the
|
||||
frame in which they are being used. If they are stored in an
|
||||
inferior frame, find_saved_register will break.
|
||||
|
||||
On the Sun 4, the only time all registers are saved is when
|
||||
a dummy frame is involved. Otherwise, the only saved registers
|
||||
are the LOCAL and IN registers which are saved as a result
|
||||
of the "save/restore" opcodes. This condition is determined
|
||||
by address rather than by value.
|
||||
|
||||
The "pc" is not stored in a frame on the SPARC. (What is stored
|
||||
is a return address minus 8.) sparc_pop_frame knows how to
|
||||
deal with that. Other routines might or might not.
|
||||
|
||||
See tm-sparc.h (PUSH_FRAME and friends) for CRITICAL information
|
||||
about how this works. */
|
||||
The argument RAW_BUFFER must point to aligned memory. */
|
||||
|
||||
void
|
||||
sparc_frame_find_saved_regs (fi, saved_regs_addr)
|
||||
struct frame_info *fi;
|
||||
struct frame_saved_regs *saved_regs_addr;
|
||||
get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval)
|
||||
char *raw_buffer;
|
||||
int *optimized;
|
||||
CORE_ADDR *addrp;
|
||||
struct frame_info *frame;
|
||||
int regnum;
|
||||
enum lval_type *lval;
|
||||
{
|
||||
register int regnum;
|
||||
CORE_ADDR frame_addr = FRAME_FP (fi);
|
||||
struct frame_info *frame1;
|
||||
CORE_ADDR addr;
|
||||
|
||||
if (!fi)
|
||||
fatal ("Bad frame info struct in FRAME_FIND_SAVED_REGS");
|
||||
if (optimized)
|
||||
*optimized = 0;
|
||||
|
||||
memset (saved_regs_addr, 0, sizeof (*saved_regs_addr));
|
||||
|
||||
if (fi->pc >= (fi->bottom ? fi->bottom :
|
||||
read_register (SP_REGNUM))
|
||||
&& fi->pc <= FRAME_FP(fi))
|
||||
addr = 0;
|
||||
frame1 = frame->next;
|
||||
while (frame1 != NULL)
|
||||
{
|
||||
/* Dummy frame. All but the window regs are in there somewhere. */
|
||||
for (regnum = G1_REGNUM; regnum < G1_REGNUM+7; regnum++)
|
||||
saved_regs_addr->regs[regnum] =
|
||||
frame_addr + (regnum - G0_REGNUM) * 4 - 0xa0;
|
||||
for (regnum = I0_REGNUM; regnum < I0_REGNUM+8; regnum++)
|
||||
saved_regs_addr->regs[regnum] =
|
||||
frame_addr + (regnum - I0_REGNUM) * 4 - 0xc0;
|
||||
for (regnum = FP0_REGNUM; regnum < FP0_REGNUM + 32; regnum++)
|
||||
saved_regs_addr->regs[regnum] =
|
||||
frame_addr + (regnum - FP0_REGNUM) * 4 - 0x80;
|
||||
for (regnum = Y_REGNUM; regnum < NUM_REGS; regnum++)
|
||||
saved_regs_addr->regs[regnum] =
|
||||
frame_addr + (regnum - Y_REGNUM) * 4 - 0xe0;
|
||||
frame_addr = fi->bottom ?
|
||||
fi->bottom : read_register (SP_REGNUM);
|
||||
}
|
||||
else if (fi->flat)
|
||||
{
|
||||
/* Flat register window frame. */
|
||||
saved_regs_addr->regs[RP_REGNUM] = fi->pc_addr;
|
||||
saved_regs_addr->regs[I7_REGNUM] = fi->fp_addr;
|
||||
frame_addr = fi->bottom ? fi->bottom : read_register (SP_REGNUM);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Normal frame. Just Local and In registers */
|
||||
frame_addr = fi->bottom ?
|
||||
fi->bottom : read_register (SP_REGNUM);
|
||||
for (regnum = L0_REGNUM; regnum < L0_REGNUM+8; regnum++)
|
||||
saved_regs_addr->regs[regnum] =
|
||||
(frame_addr + (regnum - L0_REGNUM) * REGISTER_RAW_SIZE (L0_REGNUM)
|
||||
+ FRAME_SAVED_L0);
|
||||
for (regnum = I0_REGNUM; regnum < I0_REGNUM+8; regnum++)
|
||||
saved_regs_addr->regs[regnum] =
|
||||
(frame_addr + (regnum - I0_REGNUM) * REGISTER_RAW_SIZE (I0_REGNUM)
|
||||
+ FRAME_SAVED_I0);
|
||||
}
|
||||
if (fi->next)
|
||||
{
|
||||
if (fi->flat)
|
||||
if (frame1->pc >= (frame1->bottom ? frame1->bottom :
|
||||
read_register (SP_REGNUM))
|
||||
&& frame1->pc <= FRAME_FP (frame1))
|
||||
{
|
||||
saved_regs_addr->regs[O7_REGNUM] = fi->pc_addr;
|
||||
/* Dummy frame. All but the window regs are in there somewhere. */
|
||||
if (regnum >= G1_REGNUM && regnum < G1_REGNUM + 7)
|
||||
addr = frame1->frame + (regnum - G0_REGNUM) * 4 - 0xa0;
|
||||
else if (regnum >= I0_REGNUM && regnum < I0_REGNUM + 8)
|
||||
addr = frame1->frame + (regnum - I0_REGNUM) * 4 - 0xc0;
|
||||
else if (regnum >= FP0_REGNUM && regnum < FP0_REGNUM + 32)
|
||||
addr = frame1->frame + (regnum - FP0_REGNUM) * 4 - 0x80;
|
||||
else if (regnum >= Y_REGNUM && regnum < NUM_REGS)
|
||||
addr = frame1->frame + (regnum - Y_REGNUM) * 4 - 0xe0;
|
||||
}
|
||||
else if (frame1->flat)
|
||||
{
|
||||
|
||||
if (regnum == RP_REGNUM)
|
||||
addr = frame1->pc_addr;
|
||||
else if (regnum == I7_REGNUM)
|
||||
addr = frame1->fp_addr;
|
||||
else
|
||||
{
|
||||
CORE_ADDR func_start;
|
||||
struct frame_saved_regs regs;
|
||||
memset (®s, 0, sizeof (regs));
|
||||
|
||||
find_pc_partial_function (frame1->pc, NULL, &func_start, NULL);
|
||||
examine_prologue (func_start, 0, frame1, ®s);
|
||||
addr = regs.regs[regnum];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Pull off either the next frame pointer or the stack pointer */
|
||||
CORE_ADDR next_next_frame_addr =
|
||||
(fi->next->bottom ?
|
||||
fi->next->bottom :
|
||||
read_register (SP_REGNUM));
|
||||
for (regnum = O0_REGNUM; regnum < O0_REGNUM+8; regnum++)
|
||||
saved_regs_addr->regs[regnum] =
|
||||
(next_next_frame_addr
|
||||
+ (regnum - O0_REGNUM) * REGISTER_RAW_SIZE (O0_REGNUM)
|
||||
+ FRAME_SAVED_I0);
|
||||
/* Normal frame. Local and In registers are saved on stack. */
|
||||
if (regnum >= I0_REGNUM && regnum < I0_REGNUM + 8)
|
||||
addr = (frame1->prev->bottom
|
||||
+ (regnum - I0_REGNUM) * REGISTER_RAW_SIZE (I0_REGNUM)
|
||||
+ FRAME_SAVED_I0);
|
||||
else if (regnum >= L0_REGNUM && regnum < L0_REGNUM + 8)
|
||||
addr = (frame1->prev->bottom
|
||||
+ (regnum - L0_REGNUM) * REGISTER_RAW_SIZE (L0_REGNUM)
|
||||
+ FRAME_SAVED_L0);
|
||||
else if (regnum >= O0_REGNUM && regnum < O0_REGNUM + 8)
|
||||
{
|
||||
/* Outs become ins. */
|
||||
get_saved_register (raw_buffer, optimized, addrp, frame1,
|
||||
(regnum - O0_REGNUM + I0_REGNUM), lval);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (addr != 0)
|
||||
break;
|
||||
frame1 = frame1->next;
|
||||
}
|
||||
/* Otherwise, whatever we would get from ptrace(GETREGS) is accurate */
|
||||
saved_regs_addr->regs[SP_REGNUM] = FRAME_FP (fi);
|
||||
if (addr != 0)
|
||||
{
|
||||
if (lval != NULL)
|
||||
*lval = lval_memory;
|
||||
if (regnum == SP_REGNUM)
|
||||
{
|
||||
if (raw_buffer != NULL)
|
||||
{
|
||||
/* Put it back in target format. */
|
||||
store_address (raw_buffer, REGISTER_RAW_SIZE (regnum), addr);
|
||||
}
|
||||
if (addrp != NULL)
|
||||
*addrp = 0;
|
||||
return;
|
||||
}
|
||||
if (raw_buffer != NULL)
|
||||
read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lval != NULL)
|
||||
*lval = lval_register;
|
||||
addr = REGISTER_BYTE (regnum);
|
||||
if (raw_buffer != NULL)
|
||||
read_register_gen (regnum, raw_buffer);
|
||||
}
|
||||
if (addrp != NULL)
|
||||
*addrp = addr;
|
||||
}
|
||||
|
||||
/* Push an empty stack frame, and record in it the current PC, regs, etc.
|
||||
|
@ -595,6 +652,124 @@ sparc_push_dummy_frame ()
|
|||
write_register (I7_REGNUM, read_pc() - 8);
|
||||
}
|
||||
|
||||
/* sparc_frame_find_saved_regs (). This function is here only because
|
||||
pop_frame uses it. Note there is an interesting corner case which
|
||||
I think few ports of GDB get right--if you are popping a frame
|
||||
which does not save some register that *is* saved by a more inner
|
||||
frame (such a frame will never be a dummy frame because dummy
|
||||
frames save all registers). Rewriting pop_frame to use
|
||||
get_saved_register would solve this problem and also get rid of the
|
||||
ugly duplication between sparc_frame_find_saved_regs and
|
||||
get_saved_register.
|
||||
|
||||
Stores, into a struct frame_saved_regs,
|
||||
the addresses of the saved registers of frame described by FRAME_INFO.
|
||||
This includes special registers such as pc and fp saved in special
|
||||
ways in the stack frame. sp is even more special:
|
||||
the address we return for it IS the sp for the next frame.
|
||||
|
||||
Note that on register window machines, we are currently making the
|
||||
assumption that window registers are being saved somewhere in the
|
||||
frame in which they are being used. If they are stored in an
|
||||
inferior frame, find_saved_register will break.
|
||||
|
||||
On the Sun 4, the only time all registers are saved is when
|
||||
a dummy frame is involved. Otherwise, the only saved registers
|
||||
are the LOCAL and IN registers which are saved as a result
|
||||
of the "save/restore" opcodes. This condition is determined
|
||||
by address rather than by value.
|
||||
|
||||
The "pc" is not stored in a frame on the SPARC. (What is stored
|
||||
is a return address minus 8.) sparc_pop_frame knows how to
|
||||
deal with that. Other routines might or might not.
|
||||
|
||||
See tm-sparc.h (PUSH_FRAME and friends) for CRITICAL information
|
||||
about how this works. */
|
||||
|
||||
static void sparc_frame_find_saved_regs PARAMS ((struct frame_info *,
|
||||
struct frame_saved_regs *));
|
||||
|
||||
static void
|
||||
sparc_frame_find_saved_regs (fi, saved_regs_addr)
|
||||
struct frame_info *fi;
|
||||
struct frame_saved_regs *saved_regs_addr;
|
||||
{
|
||||
register int regnum;
|
||||
CORE_ADDR frame_addr = FRAME_FP (fi);
|
||||
|
||||
if (!fi)
|
||||
fatal ("Bad frame info struct in FRAME_FIND_SAVED_REGS");
|
||||
|
||||
memset (saved_regs_addr, 0, sizeof (*saved_regs_addr));
|
||||
|
||||
if (fi->pc >= (fi->bottom ? fi->bottom :
|
||||
read_register (SP_REGNUM))
|
||||
&& fi->pc <= FRAME_FP(fi))
|
||||
{
|
||||
/* Dummy frame. All but the window regs are in there somewhere. */
|
||||
for (regnum = G1_REGNUM; regnum < G1_REGNUM+7; regnum++)
|
||||
saved_regs_addr->regs[regnum] =
|
||||
frame_addr + (regnum - G0_REGNUM) * 4 - 0xa0;
|
||||
for (regnum = I0_REGNUM; regnum < I0_REGNUM+8; regnum++)
|
||||
saved_regs_addr->regs[regnum] =
|
||||
frame_addr + (regnum - I0_REGNUM) * 4 - 0xc0;
|
||||
for (regnum = FP0_REGNUM; regnum < FP0_REGNUM + 32; regnum++)
|
||||
saved_regs_addr->regs[regnum] =
|
||||
frame_addr + (regnum - FP0_REGNUM) * 4 - 0x80;
|
||||
for (regnum = Y_REGNUM; regnum < NUM_REGS; regnum++)
|
||||
saved_regs_addr->regs[regnum] =
|
||||
frame_addr + (regnum - Y_REGNUM) * 4 - 0xe0;
|
||||
frame_addr = fi->bottom ?
|
||||
fi->bottom : read_register (SP_REGNUM);
|
||||
}
|
||||
else if (fi->flat)
|
||||
{
|
||||
CORE_ADDR func_start;
|
||||
find_pc_partial_function (fi->pc, NULL, &func_start, NULL);
|
||||
examine_prologue (func_start, 0, fi, saved_regs_addr);
|
||||
|
||||
/* Flat register window frame. */
|
||||
saved_regs_addr->regs[RP_REGNUM] = fi->pc_addr;
|
||||
saved_regs_addr->regs[I7_REGNUM] = fi->fp_addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Normal frame. Just Local and In registers */
|
||||
frame_addr = fi->bottom ?
|
||||
fi->bottom : read_register (SP_REGNUM);
|
||||
for (regnum = L0_REGNUM; regnum < L0_REGNUM+8; regnum++)
|
||||
saved_regs_addr->regs[regnum] =
|
||||
(frame_addr + (regnum - L0_REGNUM) * REGISTER_RAW_SIZE (L0_REGNUM)
|
||||
+ FRAME_SAVED_L0);
|
||||
for (regnum = I0_REGNUM; regnum < I0_REGNUM+8; regnum++)
|
||||
saved_regs_addr->regs[regnum] =
|
||||
(frame_addr + (regnum - I0_REGNUM) * REGISTER_RAW_SIZE (I0_REGNUM)
|
||||
+ FRAME_SAVED_I0);
|
||||
}
|
||||
if (fi->next)
|
||||
{
|
||||
if (fi->flat)
|
||||
{
|
||||
saved_regs_addr->regs[O7_REGNUM] = fi->pc_addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Pull off either the next frame pointer or the stack pointer */
|
||||
CORE_ADDR next_next_frame_addr =
|
||||
(fi->next->bottom ?
|
||||
fi->next->bottom :
|
||||
read_register (SP_REGNUM));
|
||||
for (regnum = O0_REGNUM; regnum < O0_REGNUM+8; regnum++)
|
||||
saved_regs_addr->regs[regnum] =
|
||||
(next_next_frame_addr
|
||||
+ (regnum - O0_REGNUM) * REGISTER_RAW_SIZE (O0_REGNUM)
|
||||
+ FRAME_SAVED_I0);
|
||||
}
|
||||
}
|
||||
/* Otherwise, whatever we would get from ptrace(GETREGS) is accurate */
|
||||
saved_regs_addr->regs[SP_REGNUM] = FRAME_FP (fi);
|
||||
}
|
||||
|
||||
/* Discard from the stack the innermost frame, restoring all saved registers.
|
||||
|
||||
Note that the values stored in fsr by get_frame_saved_regs are *in
|
||||
|
@ -618,7 +793,7 @@ sparc_pop_frame ()
|
|||
char raw_buffer[REGISTER_BYTES];
|
||||
int regnum;
|
||||
|
||||
get_frame_saved_regs (frame, &fsr);
|
||||
sparc_frame_find_saved_regs (frame, &fsr);
|
||||
if (fsr.regs[FP0_REGNUM])
|
||||
{
|
||||
read_memory (fsr.regs[FP0_REGNUM], raw_buffer, 32 * 4);
|
||||
|
@ -650,9 +825,16 @@ sparc_pop_frame ()
|
|||
for (regnum = I0_REGNUM; regnum < I0_REGNUM + 8; ++regnum)
|
||||
if (fsr.regs[regnum])
|
||||
write_register (regnum, read_memory_integer (fsr.regs[regnum], 4));
|
||||
for (regnum = O0_REGNUM; regnum < O0_REGNUM + 8; ++regnum)
|
||||
|
||||
/* Handle all outs except stack pointer (o0-o5; o7). */
|
||||
for (regnum = O0_REGNUM; regnum < O0_REGNUM + 6; ++regnum)
|
||||
if (fsr.regs[regnum])
|
||||
write_register (regnum, read_memory_integer (fsr.regs[regnum], 4));
|
||||
if (fsr.regs[O0_REGNUM + 7])
|
||||
write_register (O0_REGNUM + 7,
|
||||
read_memory_integer (fsr.regs[O0_REGNUM + 7], 4));
|
||||
|
||||
write_register (SP_REGNUM, frame->frame, 4);
|
||||
}
|
||||
else if (fsr.regs[I0_REGNUM])
|
||||
{
|
||||
|
@ -690,9 +872,21 @@ sparc_pop_frame ()
|
|||
write_register (NPC_REGNUM,
|
||||
read_memory_integer (fsr.regs[NPC_REGNUM], 4));
|
||||
}
|
||||
else if (frame->flat && frame->pc_addr)
|
||||
else if (frame->flat)
|
||||
{
|
||||
pc = PC_ADJUST ((CORE_ADDR) read_memory_integer (frame->pc_addr, 4));
|
||||
if (frame->pc_addr)
|
||||
pc = PC_ADJUST ((CORE_ADDR) read_memory_integer (frame->pc_addr, 4));
|
||||
else
|
||||
{
|
||||
/* I think this happens only in the innermost frame, if so then
|
||||
it is a complicated way of saying
|
||||
"pc = read_register (O7_REGNUM);". */
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
get_saved_register (buf, 0, 0, frame, O7_REGNUM, 0);
|
||||
pc = PC_ADJUST (extract_address
|
||||
(buf, REGISTER_RAW_SIZE (O7_REGNUM)));
|
||||
}
|
||||
|
||||
write_register (PC_REGNUM, pc);
|
||||
write_register (NPC_REGNUM, pc + 4);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue