X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fsh-tdep.c;h=9cb5278c4d49a4c1917cc28023b8fa4ebb561ead;hb=aa691b87c2317cc90bbe4964d79e5a29c29f348e;hp=3d8c62943fe1f727c339b21dbb8f23f5e07a4d97;hpb=7fe958be01489f0309b1b822b7cb191ccafe23af;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/sh-tdep.c b/gdb/sh-tdep.c index 3d8c62943f..9cb5278c4d 100644 --- a/gdb/sh-tdep.c +++ b/gdb/sh-tdep.c @@ -1,6 +1,6 @@ /* Target-dependent code for Renesas Super-H, for GDB. - Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 - Free Software Foundation, Inc. + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, + 2003, 2004 Free Software Foundation, Inc. This file is part of GDB. @@ -30,7 +30,6 @@ #include "frame-unwind.h" #include "dwarf2-frame.h" #include "symtab.h" -#include "symfile.h" #include "gdbtypes.h" #include "gdbcmd.h" #include "gdbcore.h" @@ -74,27 +73,6 @@ struct sh_frame_cache CORE_ADDR saved_sp; }; -static const char * -sh_generic_register_name (int reg_nr) -{ - static char *register_names[] = { - "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", - "pc", "pr", "gbr", "vbr", "mach", "macl", "sr", - "fpul", "fpscr", - "fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7", - "fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15", - "ssr", "spc", - "r0b0", "r1b0", "r2b0", "r3b0", "r4b0", "r5b0", "r6b0", "r7b0", - "r0b1", "r1b1", "r2b1", "r3b1", "r4b1", "r5b1", "r6b1", "r7b1", - }; - if (reg_nr < 0) - return NULL; - if (reg_nr >= (sizeof (register_names) / sizeof (*register_names))) - return NULL; - return register_names[reg_nr]; -} - static const char * sh_sh_register_name (int reg_nr) { @@ -212,8 +190,8 @@ sh_sh3_dsp_register_name (int reg_nr) "y0", "y1", "", "", "", "", "", "mod", "ssr", "spc", "rs", "re", "", "", "", "", "", "", - "r0b", "r1b", "r2b", "r3b", "r4b", "r5b", "r6b", "r7b" - "", "", "", "", "", "", "", "", + "r0b", "r1b", "r2b", "r3b", "r4b", "r5b", "r6b", "r7b", + "", "", "", "", "", "", "", "", }; if (reg_nr < 0) return NULL; @@ -256,6 +234,60 @@ sh_sh4_register_name (int reg_nr) return register_names[reg_nr]; } +static const char * +sh_sh4_nofpu_register_name (int reg_nr) +{ + static char *register_names[] = { + /* general registers 0-15 */ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + /* 16 - 22 */ + "pc", "pr", "gbr", "vbr", "mach", "macl", "sr", + /* 23, 24 */ + "", "", + /* floating point registers 25 - 40 -- not for nofpu target */ + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + /* 41, 42 */ + "ssr", "spc", + /* bank 0 43 - 50 */ + "r0b0", "r1b0", "r2b0", "r3b0", "r4b0", "r5b0", "r6b0", "r7b0", + /* bank 1 51 - 58 */ + "r0b1", "r1b1", "r2b1", "r3b1", "r4b1", "r5b1", "r6b1", "r7b1", + /* double precision (pseudo) 59 - 66 -- not for nofpu target */ + "", "", "", "", "", "", "", "", + /* vectors (pseudo) 67 - 70 -- not for nofpu target */ + "", "", "", "", + }; + if (reg_nr < 0) + return NULL; + if (reg_nr >= (sizeof (register_names) / sizeof (*register_names))) + return NULL; + return register_names[reg_nr]; +} + +static const char * +sh_sh4al_dsp_register_name (int reg_nr) +{ + static char *register_names[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "pc", "pr", "gbr", "vbr", "mach", "macl", "sr", + "", "dsr", + "a0g", "a0", "a1g", "a1", "m0", "m1", "x0", "x1", + "y0", "y1", "", "", "", "", "", "mod", + "ssr", "spc", + "rs", "re", "", "", "", "", "", "", + "r0b", "r1b", "r2b", "r3b", "r4b", "r5b", "r6b", "r7b", + "", "", "", "", "", "", "", "", + }; + if (reg_nr < 0) + return NULL; + if (reg_nr >= (sizeof (register_names) / sizeof (*register_names))) + return NULL; + return register_names[reg_nr]; +} + static const unsigned char * sh_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr) { @@ -279,6 +311,9 @@ sh_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr) #define GET_SOURCE_REG(x) (((x) >> 4) & 0xf) #define GET_TARGET_REG(x) (((x) >> 8) & 0xf) +/* JSR @Rm 0100mmmm00001011 */ +#define IS_JSR(x) (((x) & 0xf0ff) == 0x400b) + /* STS.L PR,@-r15 0100111100100010 r15-4-->r15, PR-->(r15) */ #define IS_STS(x) ((x) == 0x4f22) @@ -447,8 +482,7 @@ sh_analyze_prologue (CORE_ADDR pc, CORE_ADDR current_pc, } else if (IS_MOV_SP_FP (inst)) { - if (!cache->uses_fp) - cache->uses_fp = 1; + cache->uses_fp = 1; /* At this point, only allow argument register moves to other registers or argument register moves to @(X,fp) which are moving the register arguments onto the stack area allocated @@ -478,6 +512,20 @@ sh_analyze_prologue (CORE_ADDR pc, CORE_ADDR current_pc, } break; } + else if (IS_JSR (inst)) + { + /* We have found a jsr that has been scheduled into the prologue. + If we continue the scan and return a pc someplace after this, + then setting a breakpoint on this function will cause it to + appear to be called after the function it is calling via the + jsr, which will be very confusing. Most likely the next + instruction is going to be IS_MOV_SP_FP in the delay slot. If + so, note that before returning the current pc. */ + inst = read_memory_integer (pc + 2, 2); + if (IS_MOV_SP_FP (inst)) + cache->uses_fp = 1; + break; + } #if 0 /* This used to just stop when it found an instruction that was not considered part of the prologue. Now, we just keep going looking for likely instructions. */ @@ -543,9 +591,7 @@ sh_skip_prologue (CORE_ADDR start_pc) return pc; } -/* Should call_function allocate stack space for a struct return? - - The ABI says: +/* The ABI says: Aggregate types not bigger than 8 bytes that have the same size and alignment as one of the integer scalar types are returned in the @@ -788,6 +834,55 @@ sh_next_flt_argreg (int len) return FLOAT_ARG0_REGNUM + argreg; } +/* Helper function which figures out, if a type is treated like a float type. + + The FPU ABIs have a special way how to treat types as float types. + Structures with exactly one member, which is of type float or double, are + treated exactly as the base types float or double: + + struct sf { + float f; + }; + + struct sd { + double d; + }; + + are handled the same way as just + + float f; + + double d; + + As a result, arguments of these struct types are pushed into floating point + registers exactly as floats or doubles, using the same decision algorithm. + + The same is valid if these types are used as function return types. The + above structs are returned in fr0 resp. fr0,fr1 instead of in r0, r0,r1 + or even using struct convention as it is for other structs. */ + +static int +sh_treat_as_flt_p (struct type *type) +{ + int len = TYPE_LENGTH (type); + + /* Ordinary float types are obviously treated as float. */ + if (TYPE_CODE (type) == TYPE_CODE_FLT) + return 1; + /* Otherwise non-struct types are not treated as float. */ + if (TYPE_CODE (type) != TYPE_CODE_STRUCT) + return 0; + /* Otherwise structs with more than one memeber are not treated as float. */ + if (TYPE_NFIELDS (type) != 1) + return 0; + /* Otherwise if the type of that member is float, the whole type is + treated as float. */ + if (TYPE_CODE (TYPE_FIELD_TYPE (type, 0)) == TYPE_CODE_FLT) + return 1; + /* Otherwise it's not treated as float. */ + return 0; +} + static CORE_ADDR sh_push_dummy_call_fpu (struct gdbarch *gdbarch, CORE_ADDR func_addr, @@ -805,7 +900,8 @@ sh_push_dummy_call_fpu (struct gdbarch *gdbarch, CORE_ADDR regval; char *val; int len, reg_size = 0; - int pass_on_stack; + int pass_on_stack = 0; + int treat_as_flt; /* first force sp to a 4-byte alignment */ sp = sh_frame_align (gdbarch, sp); @@ -832,43 +928,59 @@ sh_push_dummy_call_fpu (struct gdbarch *gdbarch, /* Some decisions have to be made how various types are handled. This also differs in different ABIs. */ pass_on_stack = 0; - if (len > 16) - pass_on_stack = 1; /* Types bigger than 16 bytes are passed on stack. */ /* Find out the next register to use for a floating point value. */ - if (TYPE_CODE (type) == TYPE_CODE_FLT) + treat_as_flt = sh_treat_as_flt_p (type); + if (treat_as_flt) flt_argreg = sh_next_flt_argreg (len); + /* In contrast to non-FPU CPUs, arguments are never split between + registers and stack. If an argument doesn't fit in the remaining + registers it's always pushed entirely on the stack. */ + else if (len > ((ARGLAST_REGNUM - argreg + 1) * 4)) + pass_on_stack = 1; while (len > 0) { - if ((TYPE_CODE (type) == TYPE_CODE_FLT - && flt_argreg > FLOAT_ARGLAST_REGNUM) - || argreg > ARGLAST_REGNUM || pass_on_stack) + if ((treat_as_flt && flt_argreg > FLOAT_ARGLAST_REGNUM) + || (!treat_as_flt && (argreg > ARGLAST_REGNUM + || pass_on_stack))) { - /* The remainder of the data goes entirely on the stack, - 4-byte aligned. */ + /* The data goes entirely on the stack, 4-byte aligned. */ reg_size = (len + 3) & ~3; write_memory (sp + stack_offset, val, reg_size); stack_offset += reg_size; } - else if (TYPE_CODE (type) == TYPE_CODE_FLT - && flt_argreg <= FLOAT_ARGLAST_REGNUM) + else if (treat_as_flt && flt_argreg <= FLOAT_ARGLAST_REGNUM) { /* Argument goes in a float argument register. */ reg_size = register_size (gdbarch, flt_argreg); regval = extract_unsigned_integer (val, reg_size); + /* In little endian mode, float types taking two registers + (doubles on sh4, long doubles on sh2e, sh3e and sh4) must + be stored swapped in the argument registers. The below + code first writes the first 32 bits in the next but one + register, increments the val and len values accordingly + and then proceeds as normal by writing the second 32 bits + into the next register. */ + if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE + && TYPE_LENGTH (type) == 2 * reg_size) + { + regcache_cooked_write_unsigned (regcache, flt_argreg + 1, + regval); + val += reg_size; + len -= reg_size; + regval = extract_unsigned_integer (val, reg_size); + } regcache_cooked_write_unsigned (regcache, flt_argreg++, regval); } - else if (argreg <= ARGLAST_REGNUM) + else if (!treat_as_flt && argreg <= ARGLAST_REGNUM) { /* there's room in a register */ reg_size = register_size (gdbarch, argreg); regval = extract_unsigned_integer (val, reg_size); regcache_cooked_write_unsigned (regcache, argreg++, regval); } - /* Store the value reg_size bytes at a time. This means that things - larger than reg_size bytes may go partly in registers and partly - on the stack. */ + /* Store the value one register at a time or in one step on stack. */ len -= reg_size; val += reg_size; } @@ -986,12 +1098,15 @@ static void sh3e_sh4_extract_return_value (struct type *type, struct regcache *regcache, void *valbuf) { - if (TYPE_CODE (type) == TYPE_CODE_FLT) + if (sh_treat_as_flt_p (type)) { int len = TYPE_LENGTH (type); int i, regnum = FP0_REGNUM; for (i = 0; i < len; i += 4) - regcache_raw_read (regcache, regnum++, (char *) valbuf + i); + if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE) + regcache_raw_read (regcache, regnum++, (char *) valbuf + len - 4 - i); + else + regcache_raw_read (regcache, regnum++, (char *) valbuf + i); } else sh_default_extract_return_value (type, regcache, valbuf); @@ -1027,7 +1142,7 @@ static void sh3e_sh4_store_return_value (struct type *type, struct regcache *regcache, const void *valbuf) { - if (TYPE_CODE (type) == TYPE_CODE_FLT) + if (sh_treat_as_flt_p (type)) { int len = TYPE_LENGTH (type); int i, regnum = FP0_REGNUM; @@ -1272,6 +1387,36 @@ sh4_show_regs (void) (long) read_register (FP0_REGNUM + 15)); } +static void +sh4_nofpu_show_regs (void) +{ + printf_filtered ("PC=%s SR=%08lx PR=%08lx MACH=%08lx MACHL=%08lx\n", + paddr (read_register (PC_REGNUM)), + (long) read_register (SR_REGNUM), + (long) read_register (PR_REGNUM), + (long) read_register (MACH_REGNUM), + (long) read_register (MACL_REGNUM)); + + printf_filtered ("GBR=%08lx VBR=%08lx", + (long) read_register (GBR_REGNUM), + (long) read_register (VBR_REGNUM)); + printf_filtered (" SSR=%08lx SPC=%08lx", + (long) read_register (SSR_REGNUM), + (long) read_register (SPC_REGNUM)); + + printf_filtered + ("\nR0-R7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", + (long) read_register (0), (long) read_register (1), + (long) read_register (2), (long) read_register (3), + (long) read_register (4), (long) read_register (5), + (long) read_register (6), (long) read_register (7)); + printf_filtered ("R8-R15 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", + (long) read_register (8), (long) read_register (9), + (long) read_register (10), (long) read_register (11), + (long) read_register (12), (long) read_register (13), + (long) read_register (14), (long) read_register (15)); +} + static void sh_dsp_show_regs (void) { @@ -1390,8 +1535,8 @@ sh_default_register_type (struct gdbarch *gdbarch, int reg_nr) because they are stored as 4 individual FP elements. */ static void -sh_sh4_register_convert_to_virtual (int regnum, struct type *type, - char *from, char *to) +sh_register_convert_to_virtual (int regnum, struct type *type, + char *from, char *to) { if (regnum >= DR0_REGNUM && regnum <= DR_LAST_REGNUM) { @@ -1406,8 +1551,8 @@ sh_sh4_register_convert_to_virtual (int regnum, struct type *type, } static void -sh_sh4_register_convert_to_raw (struct type *type, int regnum, - const void *from, void *to) +sh_register_convert_to_raw (struct type *type, int regnum, + const void *from, void *to) { if (regnum >= DR0_REGNUM && regnum <= DR_LAST_REGNUM) { @@ -1458,10 +1603,9 @@ sh_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache, + register_size (gdbarch, base_regnum) * portion)); /* We must pay attention to the endiannes. */ - sh_sh4_register_convert_to_virtual (reg_nr, - gdbarch_register_type (gdbarch, - reg_nr), - temp_buffer, buffer); + sh_register_convert_to_virtual (reg_nr, + gdbarch_register_type (gdbarch, reg_nr), + temp_buffer, buffer); } else if (reg_nr >= FV0_REGNUM && reg_nr <= FV_LAST_REGNUM) { @@ -1488,8 +1632,8 @@ sh_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, base_regnum = dr_reg_base_num (reg_nr); /* We must pay attention to the endiannes. */ - sh_sh4_register_convert_to_raw (gdbarch_register_type (gdbarch, reg_nr), - reg_nr, buffer, temp_buffer); + sh_register_convert_to_raw (gdbarch_register_type (gdbarch, reg_nr), + reg_nr, buffer, temp_buffer); /* Write the real regs for which this one is an alias. */ for (portion = 0; portion < 2; portion++) @@ -1745,8 +1889,8 @@ sh_dsp_register_sim_regno (int nr) return SIM_SH_RS_REGNUM; if (nr == RE_REGNUM) return SIM_SH_RE_REGNUM; - if (nr >= R0_BANK_REGNUM && nr <= R7_BANK_REGNUM) - return nr - R0_BANK_REGNUM + SIM_SH_R0_BANK_REGNUM; + if (nr >= DSP_R0_BANK_REGNUM && nr <= DSP_R7_BANK_REGNUM) + return nr - DSP_R0_BANK_REGNUM + SIM_SH_R0_BANK_REGNUM; return nr; } @@ -2030,13 +2174,20 @@ sh_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) break; case bfd_mach_sh3_dsp: + case bfd_mach_sh4al_dsp: sh_show_regs = sh3_dsp_show_regs; break; case bfd_mach_sh4: + case bfd_mach_sh4a: sh_show_regs = sh4_show_regs; break; + case bfd_mach_sh4_nofpu: + case bfd_mach_sh4a_nofpu: + sh_show_regs = sh4_nofpu_show_regs; + break; + case bfd_mach_sh5: sh_show_regs = sh64_show_regs; /* SH5 is handled entirely in sh64-tdep.c */ @@ -2081,19 +2232,14 @@ sh_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_store_return_value (gdbarch, sh_default_store_return_value); set_gdbarch_extract_return_value (gdbarch, sh_default_extract_return_value); - set_gdbarch_extract_struct_value_address (gdbarch, - sh_extract_struct_value_address); + set_gdbarch_deprecated_extract_struct_value_address (gdbarch, sh_extract_struct_value_address); set_gdbarch_skip_prologue (gdbarch, sh_skip_prologue); set_gdbarch_inner_than (gdbarch, core_addr_lessthan); - set_gdbarch_decr_pc_after_break (gdbarch, 0); - set_gdbarch_function_start_offset (gdbarch, 0); set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_nofpu); - set_gdbarch_frame_args_skip (gdbarch, 0); - set_gdbarch_frameless_function_invocation (gdbarch, - frameless_look_for_prologue); + set_gdbarch_deprecated_frameless_function_invocation (gdbarch, legacy_frameless_look_for_prologue); set_gdbarch_believe_pcc_promotion (gdbarch, 1); set_gdbarch_frame_align (gdbarch, sh_frame_align); @@ -2155,6 +2301,7 @@ sh_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) break; case bfd_mach_sh4: + case bfd_mach_sh4a: set_gdbarch_register_name (gdbarch, sh_sh4_register_name); set_gdbarch_register_type (gdbarch, sh_sh4_register_type); set_gdbarch_fp0_regnum (gdbarch, 25); @@ -2167,8 +2314,18 @@ sh_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_fpu); break; + case bfd_mach_sh4_nofpu: + case bfd_mach_sh4a_nofpu: + set_gdbarch_register_name (gdbarch, sh_sh4_nofpu_register_name); + break; + + case bfd_mach_sh4al_dsp: + set_gdbarch_register_name (gdbarch, sh_sh4al_dsp_register_name); + set_gdbarch_register_sim_regno (gdbarch, sh_dsp_register_sim_regno); + break; + default: - set_gdbarch_register_name (gdbarch, sh_generic_register_name); + set_gdbarch_register_name (gdbarch, sh_sh_register_name); break; }