* 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:
Jim Kingdon 1994-12-18 06:59:12 +00:00
parent 4ec56c1fec
commit ee7b9e92f6
3 changed files with 473 additions and 238 deletions

View file

@ -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.

View file

@ -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. */
/*

View file

@ -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 (&regs, 0, sizeof (regs));
find_pc_partial_function (frame1->pc, NULL, &func_start, NULL);
examine_prologue (func_start, 0, frame1, &regs);
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);
}