#include "defs.h"
#include "frame.h"
#include "frame-base.h"
#include "frame-unwind.h"
#include "dwarf2-frame.h"
#include "symtab.h"
#include "gdbtypes.h"
#include "gdbcmd.h"
#include "gdbcore.h"
#include "value.h"
#include "dis-asm.h"
#include "inferior.h"
#include "gdb_string.h"
#include "gdb_assert.h"
#include "arch-utils.h"
#include "regcache.h"
#include "osabi.h"
#include "elf-bfd.h"
#include "elf/sh.h"
#include "gdb/sim-sh.h"
enum sh_abi
{
SH_ABI_UNKNOWN,
SH_ABI_32,
SH_ABI_64
};
struct gdbarch_tdep
{
enum sh_abi sh_abi;
};
struct sh64_frame_cache
{
CORE_ADDR base;
LONGEST sp_offset;
CORE_ADDR pc;
int uses_fp;
int media_mode;
CORE_ADDR saved_regs[SIM_SH64_NR_REGS];
CORE_ADDR saved_sp;
};
enum
{
R0_REGNUM = 0,
DEFAULT_RETURN_REGNUM = 2,
STRUCT_RETURN_REGNUM = 2,
ARG0_REGNUM = 2,
ARGLAST_REGNUM = 9,
FLOAT_ARGLAST_REGNUM = 11,
MEDIA_FP_REGNUM = 14,
PR_REGNUM = 18,
SR_REGNUM = 65,
DR0_REGNUM = 141,
DR_LAST_REGNUM = 172,
FPP0_REGNUM = 173,
FPP_LAST_REGNUM = 204,
FV0_REGNUM = 205,
FV_LAST_REGNUM = 220,
R0_C_REGNUM = 221,
R_LAST_C_REGNUM = 236,
PC_C_REGNUM = 237,
GBR_C_REGNUM = 238,
MACH_C_REGNUM = 239,
MACL_C_REGNUM = 240,
PR_C_REGNUM = 241,
T_C_REGNUM = 242,
FPSCR_C_REGNUM = 243,
FPUL_C_REGNUM = 244,
FP0_C_REGNUM = 245,
FP_LAST_C_REGNUM = 260,
DR0_C_REGNUM = 261,
DR_LAST_C_REGNUM = 268,
FV0_C_REGNUM = 269,
FV_LAST_C_REGNUM = 272,
FPSCR_REGNUM = SIM_SH64_FPCSR_REGNUM,
SSR_REGNUM = SIM_SH64_SSR_REGNUM,
SPC_REGNUM = SIM_SH64_SPC_REGNUM,
TR7_REGNUM = SIM_SH64_TR0_REGNUM + 7,
FP_LAST_REGNUM = SIM_SH64_FR0_REGNUM + SIM_SH64_NR_FP_REGS - 1
};
static const char *
sh64_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",
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
"r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
"r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
"r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47",
"r48", "r49", "r50", "r51", "r52", "r53", "r54", "r55",
"r56", "r57", "r58", "r59", "r60", "r61", "r62", "r63",
"pc",
"sr", "ssr", "spc",
"tr0", "tr1", "tr2", "tr3", "tr4", "tr5", "tr6", "tr7",
"fpscr",
"fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7",
"fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15",
"fr16", "fr17", "fr18", "fr19", "fr20", "fr21", "fr22", "fr23",
"fr24", "fr25", "fr26", "fr27", "fr28", "fr29", "fr30", "fr31",
"fr32", "fr33", "fr34", "fr35", "fr36", "fr37", "fr38", "fr39",
"fr40", "fr41", "fr42", "fr43", "fr44", "fr45", "fr46", "fr47",
"fr48", "fr49", "fr50", "fr51", "fr52", "fr53", "fr54", "fr55",
"fr56", "fr57", "fr58", "fr59", "fr60", "fr61", "fr62", "fr63",
"dr0", "dr2", "dr4", "dr6", "dr8", "dr10", "dr12", "dr14",
"dr16", "dr18", "dr20", "dr22", "dr24", "dr26", "dr28", "dr30",
"dr32", "dr34", "dr36", "dr38", "dr40", "dr42", "dr44", "dr46",
"dr48", "dr50", "dr52", "dr54", "dr56", "dr58", "dr60", "dr62",
"fp0", "fp2", "fp4", "fp6", "fp8", "fp10", "fp12", "fp14",
"fp16", "fp18", "fp20", "fp22", "fp24", "fp26", "fp28", "fp30",
"fp32", "fp34", "fp36", "fp38", "fp40", "fp42", "fp44", "fp46",
"fp48", "fp50", "fp52", "fp54", "fp56", "fp58", "fp60", "fp62",
"fv0", "fv4", "fv8", "fv12", "fv16", "fv20", "fv24", "fv28",
"fv32", "fv36", "fv40", "fv44", "fv48", "fv52", "fv56", "fv60",
"r0_c", "r1_c", "r2_c", "r3_c", "r4_c", "r5_c", "r6_c", "r7_c",
"r8_c", "r9_c", "r10_c", "r11_c", "r12_c", "r13_c", "r14_c", "r15_c",
"pc_c",
"gbr_c", "mach_c", "macl_c", "pr_c", "t_c",
"fpscr_c", "fpul_c",
"fr0_c", "fr1_c", "fr2_c", "fr3_c", "fr4_c", "fr5_c", "fr6_c", "fr7_c",
"fr8_c", "fr9_c", "fr10_c", "fr11_c", "fr12_c", "fr13_c", "fr14_c", "fr15_c",
"dr0_c", "dr2_c", "dr4_c", "dr6_c", "dr8_c", "dr10_c", "dr12_c", "dr14_c",
"fv0_c", "fv4_c", "fv8_c", "fv12_c",
};
if (reg_nr < 0)
return NULL;
if (reg_nr >= (sizeof (register_names) / sizeof (*register_names)))
return NULL;
return register_names[reg_nr];
}
#define NUM_PSEUDO_REGS_SH_MEDIA 80
#define NUM_PSEUDO_REGS_SH_COMPACT 51
#define MSYMBOL_IS_SPECIAL(msym) \
(((long) MSYMBOL_INFO (msym) & 0x80000000) != 0)
static void
sh64_elf_make_msymbol_special (asymbol *sym, struct minimal_symbol *msym)
{
if (msym == NULL)
return;
if (((elf_symbol_type *)(sym))->internal_elf_sym.st_other == STO_SH5_ISA32)
{
MSYMBOL_INFO (msym) = (char *) (((long) MSYMBOL_INFO (msym)) | 0x80000000);
SYMBOL_VALUE_ADDRESS (msym) |= 1;
}
}
#define IS_ISA32_ADDR(addr) ((addr) & 1)
#define MAKE_ISA32_ADDR(addr) ((addr) | 1)
#define UNMAKE_ISA32_ADDR(addr) ((addr) & ~1)
static int
pc_is_isa32 (bfd_vma memaddr)
{
struct minimal_symbol *sym;
if (IS_ISA32_ADDR (memaddr))
return 1;
sym = lookup_minimal_symbol_by_pc (memaddr);
if (sym)
return MSYMBOL_IS_SPECIAL (sym);
else
return 0;
}
static const unsigned char *
sh64_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
{
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
{
if (pc_is_isa32 (*pcptr))
{
static unsigned char big_breakpoint_media[] = {0x6f, 0xf5, 0xff, 0xf0};
*pcptr = UNMAKE_ISA32_ADDR (*pcptr);
*lenptr = sizeof (big_breakpoint_media);
return big_breakpoint_media;
}
else
{
static unsigned char big_breakpoint_compact[] = {0x0, 0x3b};
*lenptr = sizeof (big_breakpoint_compact);
return big_breakpoint_compact;
}
}
else
{
if (pc_is_isa32 (*pcptr))
{
static unsigned char little_breakpoint_media[] = {0xf0, 0xff, 0xf5, 0x6f};
*pcptr = UNMAKE_ISA32_ADDR (*pcptr);
*lenptr = sizeof (little_breakpoint_media);
return little_breakpoint_media;
}
else
{
static unsigned char little_breakpoint_compact[] = {0x3b, 0x0};
*lenptr = sizeof (little_breakpoint_compact);
return little_breakpoint_compact;
}
}
}
#define IS_PTABSL_R18(x) (((x) & 0xffffff8f) == 0x6bf14a00)
#define IS_STS_R0(x) ((x) == 0x4022)
#define IS_STS_PR(x) (((x) & 0xf0ff) == 0x2a)
#define IS_MOV_TO_R15(x) (((x) & 0xff00) == 0x1f00)
#define IS_MOV_R14(x) (((x) & 0xfff0) == 0x1fe0)
#define IS_STQ_R18_R14(x) (((x) & 0xfff003ff) == 0xace00120)
#define IS_STQ_R18_R15(x) (((x) & 0xfff003ff) == 0xacf00120)
#define IS_STL_R18_R15(x) (((x) & 0xfff003ff) == 0xa8f00120)
#define IS_STQ_R14_R15(x) (((x) & 0xfff003ff) == 0xacf000e0)
#define IS_STL_R14_R15(x) (((x) & 0xfff003ff) == 0xa8f000e0)
#define IS_ADDIL_SP_MEDIA(x) (((x) & 0xfff003ff) == 0xd4f000f0)
#define IS_ADDI_SP_MEDIA(x) (((x) & 0xfff003ff) == 0xd0f000f0)
#define IS_ADDL_SP_FP_MEDIA(x) ((x) == 0x00f8fce0)
#define IS_ADD_SP_FP_MEDIA(x) ((x) == 0x00f9fce0)
#define IS_MOV_SP_FP_MEDIA(x) (IS_ADDL_SP_FP_MEDIA(x) || IS_ADD_SP_FP_MEDIA(x))
#define IS_MOV_R0(x) (((x) & 0xff00) == 0xe000)
#define IS_MOVL_R0(x) (((x) & 0xff00) == 0xd000)
#define IS_ADD_SP_R0(x) ((x) == 0x30fc)
#define IS_MOV_R14_R0(x) ((x) == 0x20e6)
#define IS_MEDIA_IND_ARG_MOV(x) \
((((x) & 0xfc0ffc0f) == 0x0009fc00) && (((x) & 0x03f00000) >= 0x00200000 && ((x) & 0x03f00000) <= 0x00900000))
#define IS_MEDIA_ARG_MOV(x) \
(((((x) & 0xfc0ffc0f) == 0xac000000) || (((x) & 0xfc0ffc0f) == 0xa8000000)) \
&& (((x) & 0x000003f0) >= 0x00000020 && ((x) & 0x000003f0) <= 0x00000090))
#define IS_MEDIA_MOV_TO_R14(x) \
((((x) & 0xfffffc0f) == 0xa0e00000) \
|| (((x) & 0xfffffc0f) == 0xa4e00000) \
|| (((x) & 0xfffffc0f) == 0xa8e00000) \
|| (((x) & 0xfffffc0f) == 0xb4e00000) \
|| (((x) & 0xfffffc0f) == 0xbce00000))
#define IS_COMPACT_IND_ARG_MOV(x) \
((((x) & 0xf00f) == 0x6003) && (((x) & 0x00f0) >= 0x0020) && (((x) & 0x00f0) <= 0x0090))
#define IS_COMPACT_ARG_MOV(x) \
(((((x) & 0xff0f) == 0x2e02) && (((x) & 0x00f0) >= 0x0020) && ((x) & 0x00f0) <= 0x0090))
#define IS_COMPACT_MOV_TO_R14(x) \
((((x) & 0xff0f) == 0x2e00) || (((x) & 0xff0f) == 0x2e01))
#define IS_JSR_R0(x) ((x) == 0x400b)
#define IS_NOP(x) ((x) == 0x0009)
#define IS_MOV_SP_FP(x) ((x) == 0x6ef3)
#define IS_ADD_SP(x) (((x) & 0xff00) == 0x7f00)
static CORE_ADDR
after_prologue (CORE_ADDR pc)
{
struct symtab_and_line sal;
CORE_ADDR func_addr, func_end;
if (!find_pc_partial_function (pc, NULL, &func_addr, &func_end))
return 0;
sal = find_pc_line (func_addr, 0);
if (sal.end < func_end)
return sal.end;
else
return 0;
}
static CORE_ADDR
look_for_args_moves (CORE_ADDR start_pc, int media_mode)
{
CORE_ADDR here, end;
int w;
int insn_size = (media_mode ? 4 : 2);
for (here = start_pc, end = start_pc + (insn_size * 28); here < end;)
{
if (media_mode)
{
w = read_memory_integer (UNMAKE_ISA32_ADDR (here), insn_size);
here += insn_size;
if (IS_MEDIA_IND_ARG_MOV (w))
{
int next_insn = read_memory_integer (UNMAKE_ISA32_ADDR (here),
insn_size);
here += insn_size;
if (IS_MEDIA_MOV_TO_R14 (next_insn))
start_pc = here;
}
else if (IS_MEDIA_ARG_MOV (w))
{
start_pc = here;
}
else
break;
}
else
{
w = read_memory_integer (here, insn_size);
w = w & 0xffff;
here += insn_size;
if (IS_COMPACT_IND_ARG_MOV (w))
{
int next_insn = 0xffff & read_memory_integer (here, insn_size);
here += insn_size;
if (IS_COMPACT_MOV_TO_R14 (next_insn))
start_pc = here;
}
else if (IS_COMPACT_ARG_MOV (w))
{
start_pc = here;
}
else if (IS_MOVL_R0 (w))
{
int next_insn = 0xffff & read_memory_integer (here, insn_size);
here += insn_size;
if (IS_JSR_R0 (next_insn))
{
next_insn = 0xffff & read_memory_integer (here, insn_size);
here += insn_size;
if (IS_NOP (next_insn))
start_pc = here;
}
}
else
break;
}
}
return start_pc;
}
static CORE_ADDR
sh64_skip_prologue_hard_way (CORE_ADDR start_pc)
{
CORE_ADDR here, end;
int updated_fp = 0;
int insn_size = 4;
int media_mode = 1;
if (!start_pc)
return 0;
if (pc_is_isa32 (start_pc) == 0)
{
insn_size = 2;
media_mode = 0;
}
for (here = start_pc, end = start_pc + (insn_size * 28); here < end;)
{
if (media_mode)
{
int w = read_memory_integer (UNMAKE_ISA32_ADDR (here), insn_size);
here += insn_size;
if (IS_STQ_R18_R14 (w) || IS_STQ_R18_R15 (w) || IS_STQ_R14_R15 (w)
|| IS_STL_R14_R15 (w) || IS_STL_R18_R15 (w)
|| IS_ADDIL_SP_MEDIA (w) || IS_ADDI_SP_MEDIA (w) || IS_PTABSL_R18 (w))
{
start_pc = here;
}
else if (IS_MOV_SP_FP (w) || IS_MOV_SP_FP_MEDIA(w))
{
start_pc = here;
updated_fp = 1;
}
else
if (updated_fp)
{
start_pc = look_for_args_moves (here - insn_size, media_mode);
break;
}
}
else
{
int w = 0xffff & read_memory_integer (here, insn_size);
here += insn_size;
if (IS_STS_R0 (w) || IS_STS_PR (w)
|| IS_MOV_TO_R15 (w) || IS_MOV_R14 (w)
|| IS_MOV_R0 (w) || IS_ADD_SP_R0 (w) || IS_MOV_R14_R0 (w))
{
start_pc = here;
}
else if (IS_MOV_SP_FP (w))
{
start_pc = here;
updated_fp = 1;
}
else
if (updated_fp)
{
start_pc = look_for_args_moves (here - insn_size, media_mode);
break;
}
}
}
return start_pc;
}
static CORE_ADDR
sh64_skip_prologue (CORE_ADDR pc)
{
CORE_ADDR post_prologue_pc;
post_prologue_pc = after_prologue (pc);
if (post_prologue_pc != 0)
return max (pc, post_prologue_pc);
else
return sh64_skip_prologue_hard_way (pc);
}
static int
sh64_use_struct_convention (struct type *type)
{
return (TYPE_LENGTH (type) > 8);
}
static int
gdb_print_insn_sh64 (bfd_vma memaddr, disassemble_info *info)
{
info->endian = TARGET_BYTE_ORDER;
return print_insn_sh (memaddr, info);
}
static int
sh64_fv_reg_base_num (int fv_regnum)
{
int fp_regnum;
fp_regnum = FP0_REGNUM +
(fv_regnum - FV0_REGNUM) * 4;
return fp_regnum;
}
static int
sh64_dr_reg_base_num (int dr_regnum)
{
int fp_regnum;
fp_regnum = FP0_REGNUM +
(dr_regnum - DR0_REGNUM) * 2;
return fp_regnum;
}
static int
sh64_fpp_reg_base_num (int fpp_regnum)
{
int fp_regnum;
fp_regnum = FP0_REGNUM +
(fpp_regnum - FPP0_REGNUM) * 2;
return fp_regnum;
}
static int
sh64_compact_reg_base_num (int reg_nr)
{
int base_regnum = reg_nr;
if (reg_nr >= R0_C_REGNUM
&& reg_nr <= R_LAST_C_REGNUM)
base_regnum = reg_nr - R0_C_REGNUM;
else if (reg_nr >= FP0_C_REGNUM
&& reg_nr <= FP_LAST_C_REGNUM)
base_regnum = reg_nr - FP0_C_REGNUM + FP0_REGNUM;
else if (reg_nr >= DR0_C_REGNUM
&& reg_nr <= DR_LAST_C_REGNUM)
base_regnum = sh64_dr_reg_base_num (DR0_REGNUM + reg_nr - DR0_C_REGNUM);
else if (reg_nr >= FV0_C_REGNUM
&& reg_nr <= FV_LAST_C_REGNUM)
base_regnum = sh64_fv_reg_base_num (FV0_REGNUM + reg_nr - FV0_C_REGNUM);
else if (reg_nr == PC_C_REGNUM)
base_regnum = PC_REGNUM;
else if (reg_nr == GBR_C_REGNUM)
base_regnum = 16;
else if (reg_nr == MACH_C_REGNUM
|| reg_nr == MACL_C_REGNUM)
base_regnum = 17;
else if (reg_nr == PR_C_REGNUM)
base_regnum = PR_REGNUM;
else if (reg_nr == T_C_REGNUM)
base_regnum = 19;
else if (reg_nr == FPSCR_C_REGNUM)
base_regnum = FPSCR_REGNUM;
else if (reg_nr == FPUL_C_REGNUM)
base_regnum = FP0_REGNUM + 32;
return base_regnum;
}
static int
sign_extend (int value, int bits)
{
value = value & ((1 << bits) - 1);
return (value & (1 << (bits - 1))
? value | (~((1 << bits) - 1))
: value);
}
static void
sh64_analyze_prologue (struct gdbarch *gdbarch,
struct sh64_frame_cache *cache,
CORE_ADDR func_pc,
CORE_ADDR current_pc)
{
int reg_nr;
int pc;
int opc;
int insn;
int r0_val = 0;
int insn_size;
int gdb_register_number;
int register_number;
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
cache->sp_offset = 0;
pc = func_pc;
if (cache->media_mode)
insn_size = 4;
else
insn_size = 2;
opc = pc + (insn_size * 28);
if (opc > current_pc)
opc = current_pc;
for ( ; pc <= opc; pc += insn_size)
{
insn = read_memory_integer (cache->media_mode ? UNMAKE_ISA32_ADDR (pc)
: pc,
insn_size);
if (!cache->media_mode)
{
if (IS_STS_PR (insn))
{
int next_insn = read_memory_integer (pc + insn_size, insn_size);
if (IS_MOV_TO_R15 (next_insn))
{
cache->saved_regs[PR_REGNUM] =
cache->sp_offset - ((((next_insn & 0xf) ^ 0x8) - 0x8) << 2);
pc += insn_size;
}
}
else if (IS_MOV_R14 (insn))
cache->saved_regs[MEDIA_FP_REGNUM] =
cache->sp_offset - ((((insn & 0xf) ^ 0x8) - 0x8) << 2);
else if (IS_MOV_R0 (insn))
{
r0_val = ((insn & 0xff) ^ 0x80) - 0x80;
}
else if (IS_ADD_SP_R0 (insn))
{
}
else if (IS_STS_R0 (insn))
{
cache->saved_regs[PR_REGNUM] = cache->sp_offset - (r0_val - 4);
r0_val -= 4;
}
else if (IS_MOV_R14_R0 (insn))
{
cache->saved_regs[MEDIA_FP_REGNUM] = cache->sp_offset
- (r0_val - 4);
r0_val -= 4;
}
else if (IS_ADD_SP (insn))
cache->sp_offset -= ((insn & 0xff) ^ 0x80) - 0x80;
else if (IS_MOV_SP_FP (insn))
break;
}
else
{
if (IS_ADDIL_SP_MEDIA (insn) || IS_ADDI_SP_MEDIA (insn))
cache->sp_offset -=
sign_extend ((((insn & 0xffc00) ^ 0x80000) - 0x80000) >> 10, 9);
else if (IS_STQ_R18_R15 (insn))
cache->saved_regs[PR_REGNUM] =
cache->sp_offset - (sign_extend ((insn & 0xffc00) >> 10, 9) << 3);
else if (IS_STL_R18_R15 (insn))
cache->saved_regs[PR_REGNUM] =
cache->sp_offset - (sign_extend ((insn & 0xffc00) >> 10, 9) << 2);
else if (IS_STQ_R14_R15 (insn))
cache->saved_regs[MEDIA_FP_REGNUM] =
cache->sp_offset - (sign_extend ((insn & 0xffc00) >> 10, 9) << 3);
else if (IS_STL_R14_R15 (insn))
cache->saved_regs[MEDIA_FP_REGNUM] =
cache->sp_offset - (sign_extend ((insn & 0xffc00) >> 10, 9) << 2);
else if (IS_MOV_SP_FP_MEDIA (insn))
break;
}
}
if (cache->saved_regs[MEDIA_FP_REGNUM] >= 0)
cache->uses_fp = 1;
}
static CORE_ADDR
sh64_extract_struct_value_address (struct regcache *regcache)
{
ULONGEST val;
regcache_raw_read_unsigned (regcache, STRUCT_RETURN_REGNUM, &val);
return val;
}
static CORE_ADDR
sh64_frame_align (struct gdbarch *ignore, CORE_ADDR sp)
{
return sp & ~7;
}
static CORE_ADDR
sh64_push_dummy_call (struct gdbarch *gdbarch,
struct value *function,
struct regcache *regcache,
CORE_ADDR bp_addr,
int nargs, struct value **args,
CORE_ADDR sp, int struct_return,
CORE_ADDR struct_addr)
{
int stack_offset, stack_alloc;
int int_argreg;
int float_argreg;
int double_argreg;
int float_arg_index = 0;
int double_arg_index = 0;
int argnum;
struct type *type;
CORE_ADDR regval;
char *val;
char valbuf[8];
char valbuf_tmp[8];
int len;
int argreg_size;
int fp_args[12];
memset (fp_args, 0, sizeof (fp_args));
sp = sh64_frame_align (gdbarch, sp);
if (struct_return)
regcache_cooked_write_unsigned (regcache,
STRUCT_RETURN_REGNUM, struct_addr);
for (argnum = 0, stack_alloc = 0; argnum < nargs; argnum++)
stack_alloc += ((TYPE_LENGTH (value_type (args[argnum])) + 7) & ~7);
sp -= stack_alloc;
int_argreg = ARG0_REGNUM;
float_argreg = FP0_REGNUM;
double_argreg = DR0_REGNUM;
for (argnum = 0, stack_offset = 0; argnum < nargs; argnum++)
{
type = value_type (args[argnum]);
len = TYPE_LENGTH (type);
memset (valbuf, 0, sizeof (valbuf));
if (TYPE_CODE (type) != TYPE_CODE_FLT)
{
argreg_size = register_size (current_gdbarch, int_argreg);
if (len < argreg_size)
{
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
memcpy (valbuf + argreg_size - len,
(char *) value_contents (args[argnum]), len);
else
memcpy (valbuf, (char *) value_contents (args[argnum]), len);
val = valbuf;
}
else
val = (char *) value_contents (args[argnum]);
while (len > 0)
{
if (int_argreg > ARGLAST_REGNUM)
{
write_memory (sp + stack_offset, (const bfd_byte *) val,
argreg_size);
stack_offset += 8;
}
if (int_argreg <= ARGLAST_REGNUM)
{
regval = extract_unsigned_integer (val, argreg_size);
regcache_cooked_write_unsigned (regcache, int_argreg, regval);
}
len -= argreg_size;
val += argreg_size;
int_argreg++;
}
}
else
{
val = (char *) value_contents (args[argnum]);
if (len == 4)
{
while (fp_args[float_arg_index])
float_arg_index ++;
if (float_arg_index <= FLOAT_ARGLAST_REGNUM)
{
regcache_cooked_write (regcache,
FP0_REGNUM + float_arg_index,
val);
fp_args[float_arg_index] = 1;
int_argreg ++;
}
else
;
}
else if (len == 8)
{
while (fp_args[double_arg_index])
double_arg_index += 2;
if (double_arg_index < FLOAT_ARGLAST_REGNUM)
{
int double_register_offset = double_arg_index / 2;
int regnum = DR0_REGNUM + double_register_offset;
regcache_cooked_write (regcache, regnum, val);
fp_args[double_arg_index] = 1;
fp_args[double_arg_index + 1] = 1;
int_argreg ++;
}
else
;
}
}
}
regcache_cooked_write_unsigned (regcache, PR_REGNUM, bp_addr);
regcache_cooked_write_unsigned (regcache, SP_REGNUM, sp);
return sp;
}
static void
sh64_extract_return_value (struct type *type, struct regcache *regcache,
void *valbuf)
{
int len = TYPE_LENGTH (type);
if (TYPE_CODE (type) == TYPE_CODE_FLT)
{
if (len == 4)
{
regcache_raw_read (regcache, FP0_REGNUM, valbuf);
}
else if (len == 8)
{
DOUBLEST val;
char buf[8];
regcache_cooked_read (regcache, DR0_REGNUM, &buf);
if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
floatformat_to_doublest (&floatformat_ieee_double_littlebyte_bigword,
buf, &val);
else
floatformat_to_doublest (&floatformat_ieee_double_big,
buf, &val);
store_typed_floating (valbuf, type, val);
}
}
else
{
if (len <= 8)
{
int offset;
char buf[8];
regcache_raw_read (regcache, DEFAULT_RETURN_REGNUM, buf);
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
offset = register_size (current_gdbarch, DEFAULT_RETURN_REGNUM)
- len;
else
offset = 0;
memcpy (valbuf, buf + offset, len);
}
else
error ("bad size for return value");
}
}
static void
sh64_store_return_value (struct type *type, struct regcache *regcache,
const void *valbuf)
{
char buf[64];
int len = TYPE_LENGTH (type);
if (TYPE_CODE (type) == TYPE_CODE_FLT)
{
int i, regnum = FP0_REGNUM;
for (i = 0; i < len; i += 4)
if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
regcache_raw_write (regcache, regnum++,
(char *) valbuf + len - 4 - i);
else
regcache_raw_write (regcache, regnum++, (char *) valbuf + i);
}
else
{
int return_register = DEFAULT_RETURN_REGNUM;
int offset = 0;
if (len <= register_size (current_gdbarch, return_register))
{
memset (buf, 0, register_size (current_gdbarch, return_register));
if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
offset = 0;
else
offset = register_size (current_gdbarch, return_register) - len;
memcpy (buf + offset, valbuf, len);
regcache_raw_write (regcache, return_register, buf);
}
else
regcache_raw_write (regcache, return_register, valbuf);
}
}
static enum return_value_convention
sh64_return_value (struct gdbarch *gdbarch, struct type *type,
struct regcache *regcache,
void *readbuf, const void *writebuf)
{
if (sh64_use_struct_convention (type))
return RETURN_VALUE_STRUCT_CONVENTION;
if (writebuf)
sh64_store_return_value (type, regcache, writebuf);
else if (readbuf)
sh64_extract_return_value (type, regcache, readbuf);
return RETURN_VALUE_REGISTER_CONVENTION;
}
static void
sh64_show_media_regs (void)
{
int i;
printf_filtered ("PC=%s SR=%016llx \n",
paddr (read_register (PC_REGNUM)),
(long long) read_register (SR_REGNUM));
printf_filtered ("SSR=%016llx SPC=%016llx \n",
(long long) read_register (SSR_REGNUM),
(long long) read_register (SPC_REGNUM));
printf_filtered ("FPSCR=%016lx\n ",
(long) read_register (FPSCR_REGNUM));
for (i = 0; i < 64; i = i + 4)
printf_filtered ("\nR%d-R%d %016llx %016llx %016llx %016llx\n",
i, i + 3,
(long long) read_register (i + 0),
(long long) read_register (i + 1),
(long long) read_register (i + 2),
(long long) read_register (i + 3));
printf_filtered ("\n");
for (i = 0; i < 64; i = i + 8)
printf_filtered ("FR%d-FR%d %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
i, i + 7,
(long) read_register (FP0_REGNUM + i + 0),
(long) read_register (FP0_REGNUM + i + 1),
(long) read_register (FP0_REGNUM + i + 2),
(long) read_register (FP0_REGNUM + i + 3),
(long) read_register (FP0_REGNUM + i + 4),
(long) read_register (FP0_REGNUM + i + 5),
(long) read_register (FP0_REGNUM + i + 6),
(long) read_register (FP0_REGNUM + i + 7));
}
static void
sh64_show_compact_regs (void)
{
int i;
printf_filtered ("PC=%s \n",
paddr (read_register (PC_C_REGNUM)));
printf_filtered ("GBR=%08lx MACH=%08lx MACL=%08lx PR=%08lx T=%08lx\n",
(long) read_register (GBR_C_REGNUM),
(long) read_register (MACH_C_REGNUM),
(long) read_register (MACL_C_REGNUM),
(long) read_register (PR_C_REGNUM),
(long) read_register (T_C_REGNUM));
printf_filtered ("FPSCR=%08lx FPUL=%08lx\n",
(long) read_register (FPSCR_C_REGNUM),
(long) read_register (FPUL_C_REGNUM));
for (i = 0; i < 16; i = i + 4)
printf_filtered ("\nR%d-R%d %08lx %08lx %08lx %08lx\n",
i, i + 3,
(long) read_register (i + 0),
(long) read_register (i + 1),
(long) read_register (i + 2),
(long) read_register (i + 3));
printf_filtered ("\n");
for (i = 0; i < 16; i = i + 8)
printf_filtered ("FR%d-FR%d %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
i, i + 7,
(long) read_register (FP0_REGNUM + i + 0),
(long) read_register (FP0_REGNUM + i + 1),
(long) read_register (FP0_REGNUM + i + 2),
(long) read_register (FP0_REGNUM + i + 3),
(long) read_register (FP0_REGNUM + i + 4),
(long) read_register (FP0_REGNUM + i + 5),
(long) read_register (FP0_REGNUM + i + 6),
(long) read_register (FP0_REGNUM + i + 7));
}
void
sh64_show_regs (void)
{
if (deprecated_selected_frame
&& pc_is_isa32 (get_frame_pc (deprecated_selected_frame)))
sh64_show_media_regs ();
else
sh64_show_compact_regs ();
}
static struct type *
sh64_build_float_register_type (int high)
{
struct type *temp;
temp = create_range_type (NULL, builtin_type_int, 0, high);
return create_array_type (NULL, builtin_type_float, temp);
}
static struct type *
sh64_register_type (struct gdbarch *gdbarch, int reg_nr)
{
if ((reg_nr >= FP0_REGNUM
&& reg_nr <= FP_LAST_REGNUM)
|| (reg_nr >= FP0_C_REGNUM
&& reg_nr <= FP_LAST_C_REGNUM))
return builtin_type_float;
else if ((reg_nr >= DR0_REGNUM
&& reg_nr <= DR_LAST_REGNUM)
|| (reg_nr >= DR0_C_REGNUM
&& reg_nr <= DR_LAST_C_REGNUM))
return builtin_type_double;
else if (reg_nr >= FPP0_REGNUM
&& reg_nr <= FPP_LAST_REGNUM)
return sh64_build_float_register_type (1);
else if ((reg_nr >= FV0_REGNUM
&& reg_nr <= FV_LAST_REGNUM)
||(reg_nr >= FV0_C_REGNUM
&& reg_nr <= FV_LAST_C_REGNUM))
return sh64_build_float_register_type (3);
else if (reg_nr == FPSCR_REGNUM)
return builtin_type_int;
else if (reg_nr >= R0_C_REGNUM
&& reg_nr < FP0_C_REGNUM)
return builtin_type_int;
else
return builtin_type_long_long;
}
static void
sh64_register_convert_to_virtual (int regnum, struct type *type,
char *from, char *to)
{
if (TARGET_BYTE_ORDER != BFD_ENDIAN_LITTLE)
{
memcpy (to, from, register_size (current_gdbarch, regnum));
return;
}
if ((regnum >= DR0_REGNUM
&& regnum <= DR_LAST_REGNUM)
|| (regnum >= DR0_C_REGNUM
&& regnum <= DR_LAST_C_REGNUM))
{
DOUBLEST val;
floatformat_to_doublest (&floatformat_ieee_double_littlebyte_bigword,
from, &val);
store_typed_floating (to, type, val);
}
else
error ("sh64_register_convert_to_virtual called with non DR register number");
}
static void
sh64_register_convert_to_raw (struct type *type, int regnum,
const void *from, void *to)
{
if (TARGET_BYTE_ORDER != BFD_ENDIAN_LITTLE)
{
memcpy (to, from, register_size (current_gdbarch, regnum));
return;
}
if ((regnum >= DR0_REGNUM
&& regnum <= DR_LAST_REGNUM)
|| (regnum >= DR0_C_REGNUM
&& regnum <= DR_LAST_C_REGNUM))
{
DOUBLEST val = deprecated_extract_floating (from, TYPE_LENGTH(type));
floatformat_from_doublest (&floatformat_ieee_double_littlebyte_bigword,
&val, to);
}
else
error ("sh64_register_convert_to_raw called with non DR register number");
}
static void
sh64_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
int reg_nr, void *buffer)
{
int base_regnum;
int portion;
int offset = 0;
char temp_buffer[MAX_REGISTER_SIZE];
if (reg_nr >= DR0_REGNUM
&& reg_nr <= DR_LAST_REGNUM)
{
base_regnum = sh64_dr_reg_base_num (reg_nr);
for (portion = 0; portion < 2; portion++)
regcache_raw_read (regcache, base_regnum + portion,
(temp_buffer
+ register_size (gdbarch, base_regnum) * portion));
sh64_register_convert_to_virtual (reg_nr,
gdbarch_register_type (gdbarch,
reg_nr),
temp_buffer, buffer);
}
else if (reg_nr >= FPP0_REGNUM
&& reg_nr <= FPP_LAST_REGNUM)
{
base_regnum = sh64_fpp_reg_base_num (reg_nr);
for (portion = 0; portion < 2; portion++)
regcache_raw_read (regcache, base_regnum + portion,
((char *) buffer
+ register_size (gdbarch, base_regnum) * portion));
}
else if (reg_nr >= FV0_REGNUM
&& reg_nr <= FV_LAST_REGNUM)
{
base_regnum = sh64_fv_reg_base_num (reg_nr);
for (portion = 0; portion < 4; portion++)
regcache_raw_read (regcache, base_regnum + portion,
((char *) buffer
+ register_size (gdbarch, base_regnum) * portion));
}
else if (reg_nr >= R0_C_REGNUM
&& reg_nr <= T_C_REGNUM)
{
base_regnum = sh64_compact_reg_base_num (reg_nr);
regcache_raw_read (regcache, base_regnum, temp_buffer);
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
offset = 4;
memcpy (buffer, temp_buffer + offset, 4);
}
else if (reg_nr >= FP0_C_REGNUM
&& reg_nr <= FP_LAST_C_REGNUM)
{
base_regnum = sh64_compact_reg_base_num (reg_nr);
regcache_raw_read (regcache, base_regnum, buffer);
}
else if (reg_nr >= DR0_C_REGNUM
&& reg_nr <= DR_LAST_C_REGNUM)
{
base_regnum = sh64_compact_reg_base_num (reg_nr);
for (portion = 0; portion < 2; portion++)
regcache_raw_read (regcache, base_regnum + portion,
(temp_buffer
+ register_size (gdbarch, base_regnum) * portion));
sh64_register_convert_to_virtual (reg_nr,
gdbarch_register_type (gdbarch,
reg_nr),
temp_buffer, buffer);
}
else if (reg_nr >= FV0_C_REGNUM
&& reg_nr <= FV_LAST_C_REGNUM)
{
base_regnum = sh64_compact_reg_base_num (reg_nr);
for (portion = 0; portion < 4; portion++)
regcache_raw_read (regcache, base_regnum + portion,
((char *) buffer
+ register_size (gdbarch, base_regnum) * portion));
}
else if (reg_nr == FPSCR_C_REGNUM)
{
int fpscr_base_regnum;
int sr_base_regnum;
unsigned int fpscr_value;
unsigned int sr_value;
unsigned int fpscr_c_value;
unsigned int fpscr_c_part1_value;
unsigned int fpscr_c_part2_value;
fpscr_base_regnum = FPSCR_REGNUM;
sr_base_regnum = SR_REGNUM;
regcache_raw_read (regcache, fpscr_base_regnum, temp_buffer);
fpscr_value = extract_unsigned_integer (temp_buffer, 4);
regcache_raw_read (regcache, sr_base_regnum, temp_buffer);
sr_value = extract_unsigned_integer (temp_buffer, 4);
fpscr_c_part1_value = fpscr_value & 0x3fffd;
fpscr_c_part2_value = (sr_value & 0x7000) << 6;
fpscr_c_value = fpscr_c_part1_value | fpscr_c_part2_value;
store_unsigned_integer (buffer, 4, fpscr_c_value);
}
else if (reg_nr == FPUL_C_REGNUM)
{
base_regnum = sh64_compact_reg_base_num (reg_nr);
regcache_raw_read (regcache, base_regnum, buffer);
}
}
static void
sh64_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
int reg_nr, const void *buffer)
{
int base_regnum, portion;
int offset;
char temp_buffer[MAX_REGISTER_SIZE];
if (reg_nr >= DR0_REGNUM
&& reg_nr <= DR_LAST_REGNUM)
{
base_regnum = sh64_dr_reg_base_num (reg_nr);
sh64_register_convert_to_raw (gdbarch_register_type (gdbarch, reg_nr),
reg_nr,
buffer, temp_buffer);
for (portion = 0; portion < 2; portion++)
regcache_raw_write (regcache, base_regnum + portion,
(temp_buffer
+ register_size (gdbarch,
base_regnum) * portion));
}
else if (reg_nr >= FPP0_REGNUM
&& reg_nr <= FPP_LAST_REGNUM)
{
base_regnum = sh64_fpp_reg_base_num (reg_nr);
for (portion = 0; portion < 2; portion++)
regcache_raw_write (regcache, base_regnum + portion,
((char *) buffer
+ register_size (gdbarch,
base_regnum) * portion));
}
else if (reg_nr >= FV0_REGNUM
&& reg_nr <= FV_LAST_REGNUM)
{
base_regnum = sh64_fv_reg_base_num (reg_nr);
for (portion = 0; portion < 4; portion++)
regcache_raw_write (regcache, base_regnum + portion,
((char *) buffer
+ register_size (gdbarch,
base_regnum) * portion));
}
else if (reg_nr >= R0_C_REGNUM
&& reg_nr <= T_C_REGNUM)
{
base_regnum = sh64_compact_reg_base_num (reg_nr);
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
offset = 4;
else
offset = 0;
regcache_raw_read (regcache, base_regnum, temp_buffer);
memcpy (temp_buffer + offset, buffer, 4);
regcache_raw_write (regcache, base_regnum, temp_buffer);
}
else if (reg_nr >= FP0_C_REGNUM
&& reg_nr <= FP_LAST_C_REGNUM)
{
base_regnum = sh64_compact_reg_base_num (reg_nr);
regcache_raw_write (regcache, base_regnum, buffer);
}
else if (reg_nr >= DR0_C_REGNUM
&& reg_nr <= DR_LAST_C_REGNUM)
{
base_regnum = sh64_compact_reg_base_num (reg_nr);
for (portion = 0; portion < 2; portion++)
{
sh64_register_convert_to_raw (gdbarch_register_type (gdbarch,
reg_nr),
reg_nr,
buffer, temp_buffer);
regcache_raw_write (regcache, base_regnum + portion,
(temp_buffer
+ register_size (gdbarch,
base_regnum) * portion));
}
}
else if (reg_nr >= FV0_C_REGNUM
&& reg_nr <= FV_LAST_C_REGNUM)
{
base_regnum = sh64_compact_reg_base_num (reg_nr);
for (portion = 0; portion < 4; portion++)
{
regcache_raw_write (regcache, base_regnum + portion,
((char *) buffer
+ register_size (gdbarch,
base_regnum) * portion));
}
}
else if (reg_nr == FPSCR_C_REGNUM)
{
int fpscr_base_regnum;
int sr_base_regnum;
unsigned int fpscr_value;
unsigned int sr_value;
unsigned int old_fpscr_value;
unsigned int old_sr_value;
unsigned int fpscr_c_value;
unsigned int fpscr_mask;
unsigned int sr_mask;
fpscr_base_regnum = FPSCR_REGNUM;
sr_base_regnum = SR_REGNUM;
fpscr_c_value = extract_unsigned_integer (buffer, 4);
fpscr_mask = 0x0003fffd;
sr_mask = 0x001c0000;
fpscr_value = fpscr_c_value & fpscr_mask;
sr_value = (fpscr_value & sr_mask) >> 6;
regcache_raw_read (regcache, fpscr_base_regnum, temp_buffer);
old_fpscr_value = extract_unsigned_integer (temp_buffer, 4);
old_fpscr_value &= 0xfffc0002;
fpscr_value |= old_fpscr_value;
store_unsigned_integer (temp_buffer, 4, fpscr_value);
regcache_raw_write (regcache, fpscr_base_regnum, temp_buffer);
regcache_raw_read (regcache, sr_base_regnum, temp_buffer);
old_sr_value = extract_unsigned_integer (temp_buffer, 4);
old_sr_value &= 0xffff8fff;
sr_value |= old_sr_value;
store_unsigned_integer (temp_buffer, 4, sr_value);
regcache_raw_write (regcache, sr_base_regnum, temp_buffer);
}
else if (reg_nr == FPUL_C_REGNUM)
{
base_regnum = sh64_compact_reg_base_num (reg_nr);
regcache_raw_write (regcache, base_regnum, buffer);
}
}
static void
sh64_do_cr_c_register_info (struct ui_file *file, struct frame_info *frame,
int cr_c_regnum)
{
switch (cr_c_regnum)
{
case PC_C_REGNUM:
fprintf_filtered (file, "pc_c\t0x%08x\n",
(int) get_frame_register_unsigned (frame, cr_c_regnum));
break;
case GBR_C_REGNUM:
fprintf_filtered (file, "gbr_c\t0x%08x\n",
(int) get_frame_register_unsigned (frame, cr_c_regnum));
break;
case MACH_C_REGNUM:
fprintf_filtered (file, "mach_c\t0x%08x\n",
(int) get_frame_register_unsigned (frame, cr_c_regnum));
break;
case MACL_C_REGNUM:
fprintf_filtered (file, "macl_c\t0x%08x\n",
(int) get_frame_register_unsigned (frame, cr_c_regnum));
break;
case PR_C_REGNUM:
fprintf_filtered (file, "pr_c\t0x%08x\n",
(int) get_frame_register_unsigned (frame, cr_c_regnum));
break;
case T_C_REGNUM:
fprintf_filtered (file, "t_c\t0x%08x\n",
(int) get_frame_register_unsigned (frame, cr_c_regnum));
break;
case FPSCR_C_REGNUM:
fprintf_filtered (file, "fpscr_c\t0x%08x\n",
(int) get_frame_register_unsigned (frame, cr_c_regnum));
break;
case FPUL_C_REGNUM:
fprintf_filtered (file, "fpul_c\t0x%08x\n",
(int) get_frame_register_unsigned (frame, cr_c_regnum));
break;
}
}
static void
sh64_do_fp_register (struct gdbarch *gdbarch, struct ui_file *file,
struct frame_info *frame, int regnum)
{
unsigned char *raw_buffer;
double flt;
int inv;
int j;
raw_buffer = (unsigned char *) alloca (register_size (gdbarch, FP0_REGNUM));
if (!frame_register_read (frame, regnum, raw_buffer))
error ("can't read register %d (%s)", regnum, REGISTER_NAME (regnum));
flt = unpack_double (builtin_type_float, raw_buffer, &inv);
fputs_filtered (REGISTER_NAME (regnum), file);
print_spaces_filtered (15 - strlen (REGISTER_NAME (regnum)), file);
if (inv)
fprintf_filtered (file, "<invalid float>");
else
fprintf_filtered (file, "%-10.9g", flt);
fprintf_filtered (file, "\t(raw 0x");
for (j = 0; j < register_size (gdbarch, regnum); j++)
{
int idx = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? j
: register_size (gdbarch, regnum) - 1 - j;
fprintf_filtered (file, "%02x", raw_buffer[idx]);
}
fprintf_filtered (file, ")");
fprintf_filtered (file, "\n");
}
static void
sh64_do_pseudo_register (struct gdbarch *gdbarch, struct ui_file *file,
struct frame_info *frame, int regnum)
{
if (regnum < NUM_REGS
|| regnum >= NUM_REGS + NUM_PSEUDO_REGS_SH_MEDIA
+ NUM_PSEUDO_REGS_SH_COMPACT)
internal_error (__FILE__, __LINE__,
_("Invalid pseudo register number %d\n"), regnum);
else if ((regnum >= DR0_REGNUM && regnum <= DR_LAST_REGNUM))
{
int fp_regnum = sh64_dr_reg_base_num (regnum);
fprintf_filtered (file, "dr%d\t0x%08x%08x\n", regnum - DR0_REGNUM,
(unsigned) get_frame_register_unsigned (frame, fp_regnum),
(unsigned) get_frame_register_unsigned (frame, fp_regnum + 1));
}
else if ((regnum >= DR0_C_REGNUM && regnum <= DR_LAST_C_REGNUM))
{
int fp_regnum = sh64_compact_reg_base_num (regnum);
fprintf_filtered (file, "dr%d_c\t0x%08x%08x\n", regnum - DR0_C_REGNUM,
(unsigned) get_frame_register_unsigned (frame, fp_regnum),
(unsigned) get_frame_register_unsigned (frame, fp_regnum + 1));
}
else if ((regnum >= FV0_REGNUM && regnum <= FV_LAST_REGNUM))
{
int fp_regnum = sh64_fv_reg_base_num (regnum);
fprintf_filtered (file, "fv%d\t0x%08x\t0x%08x\t0x%08x\t0x%08x\n",
regnum - FV0_REGNUM,
(unsigned) get_frame_register_unsigned (frame, fp_regnum),
(unsigned) get_frame_register_unsigned (frame, fp_regnum + 1),
(unsigned) get_frame_register_unsigned (frame, fp_regnum + 2),
(unsigned) get_frame_register_unsigned (frame, fp_regnum + 3));
}
else if ((regnum >= FV0_C_REGNUM && regnum <= FV_LAST_C_REGNUM))
{
int fp_regnum = sh64_compact_reg_base_num (regnum);
fprintf_filtered (file, "fv%d_c\t0x%08x\t0x%08x\t0x%08x\t0x%08x\n",
regnum - FV0_C_REGNUM,
(unsigned) get_frame_register_unsigned (frame, fp_regnum),
(unsigned) get_frame_register_unsigned (frame, fp_regnum + 1),
(unsigned) get_frame_register_unsigned (frame, fp_regnum + 2),
(unsigned) get_frame_register_unsigned (frame, fp_regnum + 3));
}
else if (regnum >= FPP0_REGNUM && regnum <= FPP_LAST_REGNUM)
{
int fp_regnum = sh64_fpp_reg_base_num (regnum);
fprintf_filtered (file, "fpp%d\t0x%08x\t0x%08x\n", regnum - FPP0_REGNUM,
(unsigned) get_frame_register_unsigned (frame, fp_regnum),
(unsigned) get_frame_register_unsigned (frame, fp_regnum + 1));
}
else if (regnum >= R0_C_REGNUM && regnum <= R_LAST_C_REGNUM)
{
int c_regnum = sh64_compact_reg_base_num (regnum);
fprintf_filtered (file, "r%d_c\t0x%08x\n", regnum - R0_C_REGNUM,
(unsigned) get_frame_register_unsigned (frame, c_regnum));
}
else if (regnum >= FP0_C_REGNUM && regnum <= FP_LAST_C_REGNUM)
sh64_do_fp_register (gdbarch, file, frame, regnum);
else if (regnum >= PC_C_REGNUM && regnum <= FPUL_C_REGNUM)
sh64_do_cr_c_register_info (file, frame, regnum);
}
static void
sh64_do_register (struct gdbarch *gdbarch, struct ui_file *file,
struct frame_info *frame, int regnum)
{
unsigned char raw_buffer[MAX_REGISTER_SIZE];
fputs_filtered (REGISTER_NAME (regnum), file);
print_spaces_filtered (15 - strlen (REGISTER_NAME (regnum)), file);
if (!frame_register_read (frame, regnum, raw_buffer))
fprintf_filtered (file, "*value not available*\n");
val_print (gdbarch_register_type (gdbarch, regnum), raw_buffer, 0, 0,
file, 'x', 1, 0, Val_pretty_default);
fprintf_filtered (file, "\t");
val_print (gdbarch_register_type (gdbarch, regnum), raw_buffer, 0, 0,
file, 0, 1, 0, Val_pretty_default);
fprintf_filtered (file, "\n");
}
static void
sh64_print_register (struct gdbarch *gdbarch, struct ui_file *file,
struct frame_info *frame, int regnum)
{
if (regnum < 0 || regnum >= NUM_REGS + NUM_PSEUDO_REGS)
internal_error (__FILE__, __LINE__,
_("Invalid register number %d\n"), regnum);
else if (regnum >= 0 && regnum < NUM_REGS)
{
if (TYPE_CODE (gdbarch_register_type (gdbarch, regnum)) == TYPE_CODE_FLT)
sh64_do_fp_register (gdbarch, file, frame, regnum);
else
sh64_do_register (gdbarch, file, frame, regnum);
}
else if (regnum < NUM_REGS + NUM_PSEUDO_REGS)
sh64_do_pseudo_register (gdbarch, file, frame, regnum);
}
static void
sh64_media_print_registers_info (struct gdbarch *gdbarch, struct ui_file *file,
struct frame_info *frame, int regnum,
int fpregs)
{
if (regnum != -1)
{
if (*(REGISTER_NAME (regnum)) == '\0')
error ("Not a valid register for the current processor type");
sh64_print_register (gdbarch, file, frame, regnum);
}
else
{
regnum = 0;
while (regnum < NUM_REGS)
{
if (REGISTER_NAME (regnum) == NULL
|| *(REGISTER_NAME (regnum)) == '\0')
{
regnum++;
continue;
}
if (TYPE_CODE (gdbarch_register_type (gdbarch, regnum))
== TYPE_CODE_FLT)
{
if (fpregs)
{
sh64_do_fp_register (gdbarch, file, frame, regnum);
regnum ++;
}
else
regnum += FP_LAST_REGNUM - FP0_REGNUM;
}
else
{
sh64_do_register (gdbarch, file, frame, regnum);
regnum++;
}
}
if (fpregs)
while (regnum < NUM_REGS + NUM_PSEUDO_REGS)
{
sh64_do_pseudo_register (gdbarch, file, frame, regnum);
regnum++;
}
}
}
static void
sh64_compact_print_registers_info (struct gdbarch *gdbarch,
struct ui_file *file,
struct frame_info *frame, int regnum,
int fpregs)
{
if (regnum != -1)
{
if (*(REGISTER_NAME (regnum)) == '\0')
error ("Not a valid register for the current processor type");
if (regnum >= 0 && regnum < R0_C_REGNUM)
error ("Not a valid register for the current processor mode.");
sh64_print_register (gdbarch, file, frame, regnum);
}
else
{
regnum = R0_C_REGNUM;
while (regnum < NUM_REGS + NUM_PSEUDO_REGS)
{
sh64_do_pseudo_register (gdbarch, file, frame, regnum);
regnum++;
}
}
}
static void
sh64_print_registers_info (struct gdbarch *gdbarch, struct ui_file *file,
struct frame_info *frame, int regnum, int fpregs)
{
if (pc_is_isa32 (get_frame_pc (frame)))
sh64_media_print_registers_info (gdbarch, file, frame, regnum, fpregs);
else
sh64_compact_print_registers_info (gdbarch, file, frame, regnum, fpregs);
}
static struct sh64_frame_cache *
sh64_alloc_frame_cache (void)
{
struct sh64_frame_cache *cache;
int i;
cache = FRAME_OBSTACK_ZALLOC (struct sh64_frame_cache);
cache->base = 0;
cache->saved_sp = 0;
cache->sp_offset = 0;
cache->pc = 0;
cache->uses_fp = 0;
for (i = 0; i < SIM_SH64_NR_REGS; i++)
{
cache->saved_regs[i] = -1;
}
return cache;
}
static struct sh64_frame_cache *
sh64_frame_cache (struct frame_info *next_frame, void **this_cache)
{
struct sh64_frame_cache *cache;
CORE_ADDR current_pc;
int i;
if (*this_cache)
return *this_cache;
cache = sh64_alloc_frame_cache ();
*this_cache = cache;
current_pc = frame_pc_unwind (next_frame);
cache->media_mode = pc_is_isa32 (current_pc);
cache->base = frame_unwind_register_unsigned (next_frame, MEDIA_FP_REGNUM);
if (cache->base == 0)
return cache;
cache->pc = frame_func_unwind (next_frame);
if (cache->pc != 0)
sh64_analyze_prologue (current_gdbarch, cache, cache->pc, current_pc);
if (!cache->uses_fp)
{
cache->base = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
}
cache->saved_sp = cache->base + cache->sp_offset;
for (i = 0; i < SIM_SH64_NR_REGS; i++)
if (cache->saved_regs[i] != -1)
cache->saved_regs[i] = cache->saved_sp - cache->saved_regs[i];
return cache;
}
static void
sh64_frame_prev_register (struct frame_info *next_frame, void **this_cache,
int regnum, enum opt_state *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
int *realnump, void *valuep)
{
struct sh64_frame_cache *cache = sh64_frame_cache (next_frame, this_cache);
gdb_assert (regnum >= 0);
if (regnum == SP_REGNUM && cache->saved_sp)
{
*optimizedp = opt_okay;
*lvalp = not_lval;
*addrp = 0;
*realnump = -1;
if (valuep)
{
store_unsigned_integer (valuep,
register_size (current_gdbarch, SP_REGNUM),
cache->saved_sp);
}
return;
}
if (regnum == PC_REGNUM)
regnum = PR_REGNUM;
if (regnum < SIM_SH64_NR_REGS && cache->saved_regs[regnum] != -1)
{
int reg_size = register_size (current_gdbarch, regnum);
int size;
*optimizedp = opt_okay;
*lvalp = lval_memory;
*addrp = cache->saved_regs[regnum];
*realnump = -1;
if (gdbarch_tdep (current_gdbarch)->sh_abi == SH_ABI_32
&& (regnum == MEDIA_FP_REGNUM || regnum == PR_REGNUM))
size = 4;
else
size = reg_size;
if (valuep)
{
memset (valuep, 0, reg_size);
if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
read_memory (*addrp, valuep, size);
else
read_memory (*addrp, (char *) valuep + reg_size - size, size);
}
return;
}
*optimizedp = opt_okay;
*lvalp = lval_register;
*addrp = 0;
*realnump = regnum;
if (valuep)
frame_unwind_register (next_frame, (*realnump), valuep);
}
static void
sh64_frame_this_id (struct frame_info *next_frame, void **this_cache,
struct frame_id *this_id)
{
struct sh64_frame_cache *cache = sh64_frame_cache (next_frame, this_cache);
if (cache->base == 0)
return;
*this_id = frame_id_build (cache->saved_sp, cache->pc);
}
static const struct frame_unwind sh64_frame_unwind = {
NORMAL_FRAME,
sh64_frame_this_id,
sh64_frame_prev_register
};
static const struct frame_unwind *
sh64_frame_sniffer (struct frame_info *next_frame)
{
return &sh64_frame_unwind;
}
static CORE_ADDR
sh64_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
return frame_unwind_register_unsigned (next_frame, SP_REGNUM);
}
static CORE_ADDR
sh64_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
return frame_unwind_register_unsigned (next_frame, PC_REGNUM);
}
static struct frame_id
sh64_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
return frame_id_build (sh64_unwind_sp (gdbarch, next_frame),
frame_pc_unwind (next_frame));
}
static CORE_ADDR
sh64_frame_base_address (struct frame_info *next_frame, void **this_cache)
{
struct sh64_frame_cache *cache = sh64_frame_cache (next_frame, this_cache);
return cache->base;
}
static const struct frame_base sh64_frame_base = {
&sh64_frame_unwind,
sh64_frame_base_address,
sh64_frame_base_address,
sh64_frame_base_address
};
struct gdbarch *
sh64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
struct gdbarch *gdbarch;
struct gdbarch_tdep *tdep;
arches = gdbarch_list_lookup_by_info (arches, &info);
if (arches != NULL)
return arches->gdbarch;
tdep = XMALLOC (struct gdbarch_tdep);
gdbarch = gdbarch_alloc (&info, tdep);
if (info.abfd && bfd_get_arch_size (info.abfd) == 64)
{
tdep->sh_abi = SH_ABI_64;
set_gdbarch_ptr_bit (gdbarch, 8 * TARGET_CHAR_BIT);
set_gdbarch_long_bit (gdbarch, 8 * TARGET_CHAR_BIT);
}
else
{
tdep->sh_abi = SH_ABI_32;
set_gdbarch_ptr_bit (gdbarch, 4 * TARGET_CHAR_BIT);
set_gdbarch_long_bit (gdbarch, 4 * TARGET_CHAR_BIT);
}
set_gdbarch_short_bit (gdbarch, 2 * TARGET_CHAR_BIT);
set_gdbarch_int_bit (gdbarch, 4 * TARGET_CHAR_BIT);
set_gdbarch_long_bit (gdbarch, 4 * TARGET_CHAR_BIT);
set_gdbarch_long_long_bit (gdbarch, 8 * TARGET_CHAR_BIT);
set_gdbarch_float_bit (gdbarch, 4 * TARGET_CHAR_BIT);
set_gdbarch_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
set_gdbarch_long_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
set_gdbarch_num_regs (gdbarch, SIM_SH64_NR_REGS);
set_gdbarch_sp_regnum (gdbarch, 15);
set_gdbarch_pc_regnum (gdbarch, 64);
set_gdbarch_fp0_regnum (gdbarch, SIM_SH64_FR0_REGNUM);
set_gdbarch_num_pseudo_regs (gdbarch, NUM_PSEUDO_REGS_SH_MEDIA
+ NUM_PSEUDO_REGS_SH_COMPACT);
set_gdbarch_register_name (gdbarch, sh64_register_name);
set_gdbarch_register_type (gdbarch, sh64_register_type);
set_gdbarch_pseudo_register_read (gdbarch, sh64_pseudo_register_read);
set_gdbarch_pseudo_register_write (gdbarch, sh64_pseudo_register_write);
set_gdbarch_breakpoint_from_pc (gdbarch, sh64_breakpoint_from_pc);
set_gdbarch_print_insn (gdbarch, gdb_print_insn_sh64);
set_gdbarch_register_sim_regno (gdbarch, legacy_register_sim_regno);
set_gdbarch_write_pc (gdbarch, generic_target_write_pc);
set_gdbarch_return_value (gdbarch, sh64_return_value);
set_gdbarch_deprecated_extract_struct_value_address (gdbarch,
sh64_extract_struct_value_address);
set_gdbarch_skip_prologue (gdbarch, sh64_skip_prologue);
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
set_gdbarch_push_dummy_call (gdbarch, sh64_push_dummy_call);
set_gdbarch_believe_pcc_promotion (gdbarch, 1);
set_gdbarch_frame_align (gdbarch, sh64_frame_align);
set_gdbarch_unwind_sp (gdbarch, sh64_unwind_sp);
set_gdbarch_unwind_pc (gdbarch, sh64_unwind_pc);
set_gdbarch_unwind_dummy_id (gdbarch, sh64_unwind_dummy_id);
frame_base_set_default (gdbarch, &sh64_frame_base);
set_gdbarch_print_registers_info (gdbarch, sh64_print_registers_info);
set_gdbarch_elf_make_msymbol_special (gdbarch,
sh64_elf_make_msymbol_special);
gdbarch_init_osabi (info, gdbarch);
frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
frame_unwind_append_sniffer (gdbarch, sh64_frame_sniffer);
return gdbarch;
}