From 8db62801bd2efe1b9e6493b1a4ecadf605791b99 Mon Sep 17 00:00:00 2001 From: Elena Zannoni Date: Mon, 10 Jul 2000 14:43:37 +0000 Subject: 2000-07-10 Elena Zannoni * config/sh/tm-sh.h (STORE_RETURN_VALUE): Redefine as sh_store_return_value(). * sh-tdep.c (sh_store_return_value): New function. Store the value returned by a function into the appropriate register. 2000-07-10 Elena Zannoni * sh-tdep.c (sh_skip_prologue): Before looking at the actual instructions, try to see if the symbol table can be of help, by calling after_prologue(). If this doesn't work, call skip_prologue_hard_way(). (skip_prologue_hard_way): Renamed from sh_skip_prologue. Add some more instruction pattern matching for pushing of arguments, and manipulation of r14. (after_prologue): New function. Use symbol table info to determine the end of the prologue, if possible. --- gdb/ChangeLog | 19 +++++++ gdb/config/sh/tm-sh.h | 7 +-- gdb/sh-tdep.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 167 insertions(+), 13 deletions(-) (limited to 'gdb') diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 435cd2d..72584e0 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,22 @@ +2000-07-10 Elena Zannoni + + * config/sh/tm-sh.h (STORE_RETURN_VALUE): Redefine as + sh_store_return_value(). + * sh-tdep.c (sh_store_return_value): New function. Store the + value returned by a function into the appropriate register. + +2000-07-10 Elena Zannoni + + * sh-tdep.c (sh_skip_prologue): Before looking at the actual + instructions, try to see if the symbol table can be of help, by + calling after_prologue(). If this doesn't work, call + skip_prologue_hard_way(). + (skip_prologue_hard_way): Renamed from sh_skip_prologue. Add some + more instruction pattern matching for pushing of arguments, and + manipulation of r14. + (after_prologue): New function. Use symbol table info to determine + the end of the prologue, if possible. + 2000-07-07 Michael Snyder * findvar.c (_initialize_findvar, build_findvar, write_fp, read_fp, diff --git a/gdb/config/sh/tm-sh.h b/gdb/config/sh/tm-sh.h index ca6d9e5..bb03f53 100644 --- a/gdb/config/sh/tm-sh.h +++ b/gdb/config/sh/tm-sh.h @@ -181,12 +181,11 @@ extern void sh_extract_return_value (struct type *, void *, void *); sh_extract_return_value (TYPE, REGBUF, VALBUF) /* Write into appropriate registers a function return value - of type TYPE, given in virtual format. - - Things always get returned in R0/R1 */ + of type TYPE, given in virtual format. */ +extern void sh_store_return_value (struct type *, void *); #define STORE_RETURN_VALUE(TYPE,VALBUF) \ - write_register_bytes (REGISTER_BYTE(0), VALBUF, TYPE_LENGTH (TYPE)) + sh_store_return_value (TYPE, VALBUF) /* Extract from an array REGBUF containing the (raw) register state the address in which a function should return its structure value, diff --git a/gdb/sh-tdep.c b/gdb/sh-tdep.c index 052fb56..19bfa8e 100644 --- a/gdb/sh-tdep.c +++ b/gdb/sh-tdep.c @@ -161,19 +161,74 @@ sh_processor_type_table[] = [sts.l pr,@-r15] [mov.l r14,@-r15] [mov r15,r14] + + Actually it can be more complicated than this. For instance, with + newer gcc's: + + mov.l r14,@-r15 + add #-12,r15 + mov r15,r14 + mov r4,r1 + mov r5,r2 + mov.l r6,@(4,r14) + mov.l r7,@(8,r14) + mov.b r1,@r14 + mov r14,r1 + mov r14,r1 + add #2,r1 + mov.w r2,@r1 + */ +/* STS.L PR,@-r15 0100111100100010 + r15-4-->r15, PR-->(r15) */ #define IS_STS(x) ((x) == 0x4f22) + +/* MOV.L Rm,@-r15 00101111mmmm0110 + r15-4-->r15, Rm-->(R15) */ #define IS_PUSH(x) (((x) & 0xff0f) == 0x2f06) + #define GET_PUSHED_REG(x) (((x) >> 4) & 0xf) + +/* MOV r15,r14 0110111011110011 + r15-->r14 */ #define IS_MOV_SP_FP(x) ((x) == 0x6ef3) + +/* ADD #imm,r15 01111111iiiiiiii + r15+imm-->r15 */ #define IS_ADD_SP(x) (((x) & 0xff00) == 0x7f00) + #define IS_MOV_R3(x) (((x) & 0xff00) == 0x1a00) #define IS_SHLL_R3(x) ((x) == 0x4300) + +/* ADD r3,r15 0011111100111100 + r15+r3-->r15 */ #define IS_ADD_R3SP(x) ((x) == 0x3f3c) + +/* FMOV.S FRm,@-Rn Rn-4-->Rn, FRm-->(Rn) 1111nnnnmmmm1011 + or + FMOV DRm,@-Rn Rn-8-->Rn, DRm-->(Rn) 1111nnnnmmm01011 + or + FMOV XDm,@-Rn Rn-8-->Rn, XDm-->(Rn) 1111nnnnmmm11011 */ #define IS_FMOV(x) (((x) & 0xf00f) == 0xf00b) -#define FPSCR_SZ (1 << 20) +/* MOV Rm,Rn Rm-->Rn 0110nnnnmmmm0011 + or + MOV.L Rm,@(disp,Rn) Rm-->(dispx4+Rn) 0001nnnnmmmmdddd + or + MOV.L Rm,@Rn Rm-->(Rn) 0010nnnnmmmm0010 + where Rm is one of r4,r5,r6,r7 which are the argument registers. */ +#define IS_ARG_MOV(x) \ +(((((x) & 0xf00f) == 0x6003) && (((x) & 0x00f0) >= 0x0040 && ((x) & 0x00f0) <= 0x0070)) \ +|| ((((x) & 0xf000) == 0x1000) && (((x) & 0x00f0) >= 0x0040 && ((x) & 0x00f0) <= 0x0070)) \ +|| ((((x) & 0xf00f) == 0x2002) && (((x) & 0x00f0) >= 0x0040 && ((x) & 0x00f0) <= 0x0070))) + +/* MOV.L Rm,@(disp,r14) 00011110mmmmdddd + Rm-->(dispx4+r14) where Rm is one of r4,r5,r6,r7 */ +#define IS_MOV_R14(x) \ +((((x) & 0xff00) == 0x1e) && (((x) & 0x00f0) >= 0x0040 && ((x) & 0x00f0) <= 0x0070)) + +#define FPSCR_SZ (1 << 20) /* Should call_function allocate stack space for a struct return? */ int @@ -184,14 +239,46 @@ sh_use_struct_convention (gcc_p, type) return (TYPE_LENGTH (type) > 1); } - /* Skip any prologue before the guts of a function */ -CORE_ADDR -sh_skip_prologue (start_pc) +/* Skip the prologue using the debug information. If this fails we'll + fall back on the 'guess' method below. */ +static CORE_ADDR +after_prologue (pc) + CORE_ADDR pc; +{ + struct symtab_and_line sal; + CORE_ADDR func_addr, func_end; + + /* If we can not find the symbol in the partial symbol table, then + there is no hope we can determine the function's start address + with this code. */ + if (!find_pc_partial_function (pc, NULL, &func_addr, &func_end)) + return 0; + + /* Get the line associated with FUNC_ADDR. */ + sal = find_pc_line (func_addr, 0); + + /* There are only two cases to consider. First, the end of the source line + is within the function bounds. In that case we return the end of the + source line. Second is the end of the source line extends beyond the + bounds of the current function. We need to use the slow code to + examine instructions in that case. */ + if (sal.end < func_end) + return sal.end; + else + return 0; +} + +/* Here we look at each instruction in the function, and try to guess + where the prologue ends. Unfortunately this is not always + accurate. */ +static CORE_ADDR +skip_prologue_hard_way (start_pc) CORE_ADDR start_pc; { CORE_ADDR here, end; + int updated_fp = 0; if (!start_pc) return 0; @@ -201,19 +288,45 @@ sh_skip_prologue (start_pc) int w = read_memory_integer (here, 2); here += 2; if (IS_FMOV (w) || IS_PUSH (w) || IS_STS (w) || IS_MOV_R3 (w) - || IS_ADD_R3SP (w) || IS_ADD_SP (w) || IS_SHLL_R3 (w)) - start_pc = here; - - if (IS_MOV_SP_FP (w)) + || IS_ADD_R3SP (w) || IS_ADD_SP (w) || IS_SHLL_R3 (w) + || IS_ARG_MOV (w) || IS_MOV_R14 (w)) { start_pc = here; - break; } + else if (IS_MOV_SP_FP (w)) + { + start_pc = here; + updated_fp = 1; + } + else + /* Don't bail out yet, if we are before the copy of sp. */ + if (updated_fp) + break; } return start_pc; } +CORE_ADDR +sh_skip_prologue (pc) + CORE_ADDR pc; +{ + CORE_ADDR post_prologue_pc; + + /* See if we can determine the end of the prologue via the symbol table. + If so, then return either PC, or the PC after the prologue, whichever + is greater. */ + + post_prologue_pc = after_prologue (pc); + + /* If after_prologue returned a useful address, then use it. Else + fall back on the instruction skipping code. */ + if (post_prologue_pc != 0) + return max (pc, post_prologue_pc); + else + return (skip_prologue_hard_way (pc)); +} + /* Disassemble an instruction. */ int @@ -786,6 +899,29 @@ sh_extract_return_value (type, regbuf, valbuf) error ("bad size for return value"); } +/* If the architecture is sh4 or sh3e, store a function's return value + in the R0 general register or in the FP0 floating point register, + depending on the type of the return value. In all the other cases + the result is stored in r0. */ +void +sh_store_return_value (struct type *type, void *valbuf) +{ + int cpu; + if (TARGET_ARCHITECTURE->arch == bfd_arch_sh) + cpu = TARGET_ARCHITECTURE->mach; + else + cpu = 0; + if (cpu == bfd_mach_sh3e || cpu == bfd_mach_sh4) + { + if (TYPE_CODE (type) == TYPE_CODE_FLT) + write_register_bytes (REGISTER_BYTE (FP0_REGNUM), valbuf, TYPE_LENGTH (type)); + else + write_register_bytes (REGISTER_BYTE (0), valbuf, TYPE_LENGTH (type)); + } + else + write_register_bytes (REGISTER_BYTE (0), valbuf, TYPE_LENGTH (type)); +} + void _initialize_sh_tdep () { -- cgit v1.1