From ee7b9e92f6c3749b4657986ba2c3bfeb87d608c5 Mon Sep 17 00:00:00 2001 From: Jim Kingdon Date: Sun, 18 Dec 1994 06:59:12 +0000 Subject: * 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. --- gdb/ChangeLog | 47 +++- gdb/config/sparc/tm-sparc.h | 50 ++--- gdb/sparc-tdep.c | 522 ++++++++++++++++++++++++++++++-------------- 3 files changed, 427 insertions(+), 192 deletions(-) (limited to 'gdb') diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 0fc5280..84e2e9b 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -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. diff --git a/gdb/config/sparc/tm-sparc.h b/gdb/config/sparc/tm-sparc.h index 36fb4e6..de0956e 100644 --- a/gdb/config/sparc/tm-sparc.h +++ b/gdb/config/sparc/tm-sparc.h @@ -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. */ /* diff --git a/gdb/sparc-tdep.c b/gdb/sparc-tdep.c index 22a0bd2..8801136 100644 --- a/gdb/sparc-tdep.c +++ b/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, , %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,37 +480,187 @@ 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. + + The argument RAW_BUFFER must point to aligned memory. */ + +void +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; +{ + struct frame_info *frame1; + CORE_ADDR addr; -/* sparc_frame_find_saved_regs () + if (optimized) + *optimized = 0; + + addr = 0; + frame1 = frame->next; + while (frame1 != NULL) + { + if (frame1->pc >= (frame1->bottom ? frame1->bottom : + read_register (SP_REGNUM)) + && frame1->pc <= FRAME_FP (frame1)) + { + /* 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 + { + /* 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; + } + 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. + + We save the non-windowed registers and the ins. The locals and outs + are new; they don't need to be saved. The i's and l's of + the last frame were already saved on the stack. */ + +/* Definitely see tm-sparc.h for more doc of the frame format here. */ + +void +sparc_push_dummy_frame () +{ + CORE_ADDR sp, old_sp; + char register_temp[0x140]; + + old_sp = sp = read_register (SP_REGNUM); + + /* Y, PS, WIM, TBR, PC, NPC, FPS, CPS regs */ + read_register_bytes (REGISTER_BYTE (Y_REGNUM), ®ister_temp[0], + REGISTER_RAW_SIZE (Y_REGNUM) * 8); + + read_register_bytes (REGISTER_BYTE (O0_REGNUM), ®ister_temp[8 * 4], + REGISTER_RAW_SIZE (O0_REGNUM) * 8); + + read_register_bytes (REGISTER_BYTE (G0_REGNUM), ®ister_temp[16 * 4], + REGISTER_RAW_SIZE (G0_REGNUM) * 8); + + read_register_bytes (REGISTER_BYTE (FP0_REGNUM), ®ister_temp[24 * 4], + REGISTER_RAW_SIZE (FP0_REGNUM) * 32); + + sp -= 0x140; + + write_register (SP_REGNUM, sp); + + write_memory (sp + 0x60, ®ister_temp[0], (8 + 8 + 8 + 32) * 4); + + write_register (FP_REGNUM, old_sp); + + /* Set return address register for the call dummy to the current PC. */ + 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. @@ -476,7 +686,10 @@ isannulled (instruction, addr, target) See tm-sparc.h (PUSH_FRAME and friends) for CRITICAL information about how this works. */ -void +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; @@ -511,10 +724,13 @@ sparc_frame_find_saved_regs (fi, saved_regs_addr) } 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; - frame_addr = fi->bottom ? fi->bottom : read_register (SP_REGNUM); } else { @@ -554,47 +770,6 @@ sparc_frame_find_saved_regs (fi, saved_regs_addr) saved_regs_addr->regs[SP_REGNUM] = FRAME_FP (fi); } -/* Push an empty stack frame, and record in it the current PC, regs, etc. - - We save the non-windowed registers and the ins. The locals and outs - are new; they don't need to be saved. The i's and l's of - the last frame were already saved on the stack. */ - -/* Definitely see tm-sparc.h for more doc of the frame format here. */ - -void -sparc_push_dummy_frame () -{ - CORE_ADDR sp, old_sp; - char register_temp[0x140]; - - old_sp = sp = read_register (SP_REGNUM); - - /* Y, PS, WIM, TBR, PC, NPC, FPS, CPS regs */ - read_register_bytes (REGISTER_BYTE (Y_REGNUM), ®ister_temp[0], - REGISTER_RAW_SIZE (Y_REGNUM) * 8); - - read_register_bytes (REGISTER_BYTE (O0_REGNUM), ®ister_temp[8 * 4], - REGISTER_RAW_SIZE (O0_REGNUM) * 8); - - read_register_bytes (REGISTER_BYTE (G0_REGNUM), ®ister_temp[16 * 4], - REGISTER_RAW_SIZE (G0_REGNUM) * 8); - - read_register_bytes (REGISTER_BYTE (FP0_REGNUM), ®ister_temp[24 * 4], - REGISTER_RAW_SIZE (FP0_REGNUM) * 32); - - sp -= 0x140; - - write_register (SP_REGNUM, sp); - - write_memory (sp + 0x60, ®ister_temp[0], (8 + 8 + 8 + 32) * 4); - - write_register (FP_REGNUM, old_sp); - - /* Set return address register for the call dummy to the current PC. */ - write_register (I7_REGNUM, read_pc() - 8); -} - /* 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); } -- cgit v1.1