Nios II R2 support for GDB.
2015-08-03 Sandra Loosemore <sandra@codesourcery.com> gdb/ * nios2-tdep.h: Include opcode/nios2.h here. (NIOS2_CDX_OPCODE_SIZE): New. (struct gdbarch_tdep): Add OP parameter to syscall_next_pc. * nios2-tdep.c: Don't include opcode/nios2.h here. (nios2_fetch_insn): For R2, try reading 2-byte instruction if 4-byte read fails. (nios2_match_add, nios2_match_sub): Add cases for R2 encodings. (nios2_match_addi, nios2_match_orhi): Likewise. (nios2_match_stw, nios2_match_ldw): Likewise. (nios2_match_rdctl): Likewise. (nios2_match_stwm, nios2_match_ldwm): New. (nios2_match_branch): Add cases for R2 encodings. (nios2_match_jmpi, nios2_match_calli): Likewise. (nios2_match_jmpr, nios2_match_callr): Likewise. (nios2_match_break, nios2_match_trap): Likewise. (nios2_in_epilogue_p): Add R2 support. (nios2_analyze_prologue): Update comments. Recognize R2 CDX prologues. (nios2_breakpoint_from_pc): Handle R2 instructions. (nios2_get_next_pc): Likewise. Adjust call to tdep->syscall_next_pc. * nios2-linux-tdep.c (nios2_r1_linux_rt_sigreturn_tramp_frame): Renamed from nios2_linux_rt_sigreturn_tramp_frame. Use instruction field macros instead of literal hex values. (nios2_r2_linux_rt_sigreturn_tramp_frame): New. (nios2_linux_syscall_next_pc): Adjust signature to pass OP. Use size field from OP instead of assuming all instructions are the same size. (nios2_linux_init_abi): Register appropriate unwinder for mach. gdb/gdbserver/ * linux-nios2-low.c (NIOS2_BREAKPOINT): Conditionalize for arch variant. (CDX_BREAKPOINT): Define for R2. (nios2_breakpoint_at): Check for CDX_BREAKPOINT when R2. (the_low_target): Add comments.
This commit is contained in:
parent
cb1c8103f1
commit
af60a1ef46
@ -1,3 +1,35 @@
|
||||
2015-08-03 Sandra Loosemore <sandra@codesourcery.com>
|
||||
|
||||
* nios2-tdep.h: Include opcode/nios2.h here.
|
||||
(NIOS2_CDX_OPCODE_SIZE): New.
|
||||
(struct gdbarch_tdep): Add OP parameter to syscall_next_pc.
|
||||
* nios2-tdep.c: Don't include opcode/nios2.h here.
|
||||
(nios2_fetch_insn): For R2, try reading 2-byte instruction if
|
||||
4-byte read fails.
|
||||
(nios2_match_add, nios2_match_sub): Add cases for R2 encodings.
|
||||
(nios2_match_addi, nios2_match_orhi): Likewise.
|
||||
(nios2_match_stw, nios2_match_ldw): Likewise.
|
||||
(nios2_match_rdctl): Likewise.
|
||||
(nios2_match_stwm, nios2_match_ldwm): New.
|
||||
(nios2_match_branch): Add cases for R2 encodings.
|
||||
(nios2_match_jmpi, nios2_match_calli): Likewise.
|
||||
(nios2_match_jmpr, nios2_match_callr): Likewise.
|
||||
(nios2_match_break, nios2_match_trap): Likewise.
|
||||
(nios2_in_epilogue_p): Add R2 support.
|
||||
(nios2_analyze_prologue): Update comments. Recognize R2 CDX
|
||||
prologues.
|
||||
(nios2_breakpoint_from_pc): Handle R2 instructions.
|
||||
(nios2_get_next_pc): Likewise. Adjust call to
|
||||
tdep->syscall_next_pc.
|
||||
* nios2-linux-tdep.c (nios2_r1_linux_rt_sigreturn_tramp_frame):
|
||||
Renamed from nios2_linux_rt_sigreturn_tramp_frame. Use
|
||||
instruction field macros instead of literal hex values.
|
||||
(nios2_r2_linux_rt_sigreturn_tramp_frame): New.
|
||||
(nios2_linux_syscall_next_pc): Adjust signature to pass OP.
|
||||
Use size field from OP instead of assuming all instructions
|
||||
are the same size.
|
||||
(nios2_linux_init_abi): Register appropriate unwinder for mach.
|
||||
|
||||
2015-08-03 Ulrich Weigand <uweigand@de.ibm.com>
|
||||
|
||||
* cp-namespace.c (cp_lookup_symbol_via_imports): Fix uninitialized
|
||||
|
@ -1,3 +1,11 @@
|
||||
2015-08-03 Sandra Loosemore <sandra@codesourcery.com>
|
||||
|
||||
* linux-nios2-low.c (NIOS2_BREAKPOINT): Conditionalize for
|
||||
arch variant.
|
||||
(CDX_BREAKPOINT): Define for R2.
|
||||
(nios2_breakpoint_at): Check for CDX_BREAKPOINT when R2.
|
||||
(the_low_target): Add comments.
|
||||
|
||||
2015-07-30 Yao Qi <yao.qi@linaro.org>
|
||||
|
||||
* linux-arm-low.c (arm_hwcap): Remove it.
|
||||
|
@ -117,9 +117,17 @@ nios2_set_pc (struct regcache *regcache, CORE_ADDR pc)
|
||||
supply_register_by_name (regcache, "pc", newpc.buf);
|
||||
}
|
||||
|
||||
/* Breakpoint support. */
|
||||
/* Breakpoint support. Also see comments on nios2_breakpoint_from_pc
|
||||
in nios2-tdep.c. */
|
||||
|
||||
static const unsigned int nios2_breakpoint = 0x003b6ffa;
|
||||
#if defined(__nios2_arch__) && __nios2_arch__ == 2
|
||||
#define NIOS2_BREAKPOINT 0xb7fd0020
|
||||
#define CDX_BREAKPOINT 0xd7c9
|
||||
#else
|
||||
#define NIOS2_BREAKPOINT 0x003b6ffa
|
||||
#endif
|
||||
|
||||
static const unsigned int nios2_breakpoint = NIOS2_BREAKPOINT;
|
||||
#define nios2_breakpoint_len 4
|
||||
|
||||
/* Implement the breakpoint_reinsert_addr linux_target_ops method. */
|
||||
@ -141,6 +149,13 @@ nios2_breakpoint_at (CORE_ADDR where)
|
||||
{
|
||||
unsigned int insn;
|
||||
|
||||
/* For R2, first check for the 2-byte CDX trap.n breakpoint encoding. */
|
||||
#if defined(__nios2_arch__) && __nios2_arch__ == 2
|
||||
(*the_target->read_memory) (where, (unsigned char *) &insn, 2);
|
||||
if (insn == CDX_BREAKPOINT)
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
(*the_target->read_memory) (where, (unsigned char *) &insn, 4);
|
||||
if (insn == nios2_breakpoint)
|
||||
return 1;
|
||||
@ -248,6 +263,12 @@ struct linux_target_ops the_low_target =
|
||||
NULL,
|
||||
nios2_get_pc,
|
||||
nios2_set_pc,
|
||||
|
||||
/* We only register the 4-byte breakpoint, even on R2 targets which also
|
||||
support 2-byte breakpoints. Since there is no supports_z_point_type
|
||||
function provided, gdbserver never inserts software breakpoints itself
|
||||
and instead relies on GDB to insert the breakpoint of the correct length
|
||||
via a memory write. */
|
||||
(const unsigned char *) &nios2_breakpoint,
|
||||
nios2_breakpoint_len,
|
||||
nios2_reinsert_addr,
|
||||
|
@ -156,13 +156,30 @@ nios2_linux_rt_sigreturn_init (const struct tramp_frame *self,
|
||||
trad_frame_set_id (this_cache, frame_id_build (base, func));
|
||||
}
|
||||
|
||||
static struct tramp_frame nios2_linux_rt_sigreturn_tramp_frame =
|
||||
/* Trampoline for sigreturn. This has the form
|
||||
movi r2, __NR_rt_sigreturn
|
||||
trap 0
|
||||
appropriately encoded for R1 or R2. */
|
||||
|
||||
static struct tramp_frame nios2_r1_linux_rt_sigreturn_tramp_frame =
|
||||
{
|
||||
SIGTRAMP_FRAME,
|
||||
4,
|
||||
{
|
||||
{ 0x00800004 | (139 << 6), -1 }, /* movi r2,__NR_rt_sigreturn */
|
||||
{ 0x003b683a, -1 }, /* trap */
|
||||
{ MATCH_R1_MOVI | SET_IW_I_B (2) | SET_IW_I_IMM16 (139), -1 },
|
||||
{ MATCH_R1_TRAP | SET_IW_R_IMM5 (0), -1},
|
||||
{ TRAMP_SENTINEL_INSN }
|
||||
},
|
||||
nios2_linux_rt_sigreturn_init
|
||||
};
|
||||
|
||||
static struct tramp_frame nios2_r2_linux_rt_sigreturn_tramp_frame =
|
||||
{
|
||||
SIGTRAMP_FRAME,
|
||||
4,
|
||||
{
|
||||
{ MATCH_R2_MOVI | SET_IW_F2I16_B (2) | SET_IW_F2I16_IMM16 (139), -1 },
|
||||
{ MATCH_R2_TRAP | SET_IW_X2L5_IMM5 (0), -1},
|
||||
{ TRAMP_SENTINEL_INSN }
|
||||
},
|
||||
nios2_linux_rt_sigreturn_init
|
||||
@ -172,7 +189,8 @@ static struct tramp_frame nios2_linux_rt_sigreturn_tramp_frame =
|
||||
instruction to be executed. */
|
||||
|
||||
static CORE_ADDR
|
||||
nios2_linux_syscall_next_pc (struct frame_info *frame)
|
||||
nios2_linux_syscall_next_pc (struct frame_info *frame,
|
||||
const struct nios2_opcode *op)
|
||||
{
|
||||
CORE_ADDR pc = get_frame_pc (frame);
|
||||
ULONGEST syscall_nr = get_frame_register_unsigned (frame, NIOS2_R2_REGNUM);
|
||||
@ -182,7 +200,7 @@ nios2_linux_syscall_next_pc (struct frame_info *frame)
|
||||
if (syscall_nr == 139 /* rt_sigreturn */)
|
||||
return frame_unwind_caller_pc (frame);
|
||||
|
||||
return pc + NIOS2_OPCODE_SIZE;
|
||||
return pc + op->size;
|
||||
}
|
||||
|
||||
/* Hook function for gdbarch_register_osabi. */
|
||||
@ -207,8 +225,12 @@ nios2_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
|
||||
set_gdbarch_iterate_over_regset_sections
|
||||
(gdbarch, nios2_iterate_over_regset_sections);
|
||||
/* Linux signal frame unwinders. */
|
||||
tramp_frame_prepend_unwinder (gdbarch,
|
||||
&nios2_linux_rt_sigreturn_tramp_frame);
|
||||
if (gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_nios2r2)
|
||||
tramp_frame_prepend_unwinder (gdbarch,
|
||||
&nios2_r2_linux_rt_sigreturn_tramp_frame);
|
||||
else
|
||||
tramp_frame_prepend_unwinder (gdbarch,
|
||||
&nios2_r1_linux_rt_sigreturn_tramp_frame);
|
||||
|
||||
tdep->syscall_next_pc = nios2_linux_syscall_next_pc;
|
||||
|
||||
|
709
gdb/nios2-tdep.c
709
gdb/nios2-tdep.c
@ -45,9 +45,6 @@
|
||||
/* To get entry_point_address. */
|
||||
#include "objfiles.h"
|
||||
|
||||
/* Nios II ISA specific encodings and macros. */
|
||||
#include "opcode/nios2.h"
|
||||
|
||||
/* Nios II specific header. */
|
||||
#include "nios2-tdep.h"
|
||||
|
||||
@ -287,8 +284,16 @@ nios2_fetch_insn (struct gdbarch *gdbarch, CORE_ADDR pc,
|
||||
unsigned long mach = gdbarch_bfd_arch_info (gdbarch)->mach;
|
||||
unsigned int insn;
|
||||
|
||||
if (!safe_read_memory_integer (pc, NIOS2_OPCODE_SIZE,
|
||||
gdbarch_byte_order (gdbarch), &memword))
|
||||
if (mach == bfd_mach_nios2r2)
|
||||
{
|
||||
if (!safe_read_memory_integer (pc, NIOS2_OPCODE_SIZE,
|
||||
BFD_ENDIAN_LITTLE, &memword)
|
||||
&& !safe_read_memory_integer (pc, NIOS2_CDX_OPCODE_SIZE,
|
||||
BFD_ENDIAN_LITTLE, &memword))
|
||||
return NULL;
|
||||
}
|
||||
else if (!safe_read_memory_integer (pc, NIOS2_OPCODE_SIZE,
|
||||
gdbarch_byte_order (gdbarch), &memword))
|
||||
return NULL;
|
||||
|
||||
insn = (unsigned int) memword;
|
||||
@ -305,13 +310,38 @@ static int
|
||||
nios2_match_add (uint32_t insn, const struct nios2_opcode *op,
|
||||
unsigned long mach, int *ra, int *rb, int *rc)
|
||||
{
|
||||
if (op->match == MATCH_R1_ADD || op->match == MATCH_R1_MOV)
|
||||
int is_r2 = (mach == bfd_mach_nios2r2);
|
||||
|
||||
if (!is_r2 && (op->match == MATCH_R1_ADD || op->match == MATCH_R1_MOV))
|
||||
{
|
||||
*ra = GET_IW_R_A (insn);
|
||||
*rb = GET_IW_R_B (insn);
|
||||
*rc = GET_IW_R_C (insn);
|
||||
return 1;
|
||||
}
|
||||
else if (!is_r2)
|
||||
return 0;
|
||||
else if (op->match == MATCH_R2_ADD || op->match == MATCH_R2_MOV)
|
||||
{
|
||||
*ra = GET_IW_F3X6L5_A (insn);
|
||||
*rb = GET_IW_F3X6L5_B (insn);
|
||||
*rc = GET_IW_F3X6L5_C (insn);
|
||||
return 1;
|
||||
}
|
||||
else if (op->match == MATCH_R2_ADD_N)
|
||||
{
|
||||
*ra = nios2_r2_reg3_mappings[GET_IW_T3X1_A3 (insn)];
|
||||
*rb = nios2_r2_reg3_mappings[GET_IW_T3X1_B3 (insn)];
|
||||
*rc = nios2_r2_reg3_mappings[GET_IW_T3X1_C3 (insn)];
|
||||
return 1;
|
||||
}
|
||||
else if (op->match == MATCH_R2_MOV_N)
|
||||
{
|
||||
*ra = GET_IW_F2_A (insn);
|
||||
*rb = 0;
|
||||
*rc = GET_IW_F2_B (insn);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -322,13 +352,31 @@ static int
|
||||
nios2_match_sub (uint32_t insn, const struct nios2_opcode *op,
|
||||
unsigned long mach, int *ra, int *rb, int *rc)
|
||||
{
|
||||
if (op->match == MATCH_R1_SUB)
|
||||
int is_r2 = (mach == bfd_mach_nios2r2);
|
||||
|
||||
if (!is_r2 && op->match == MATCH_R1_SUB)
|
||||
{
|
||||
*ra = GET_IW_R_A (insn);
|
||||
*rb = GET_IW_R_B (insn);
|
||||
*rc = GET_IW_R_C (insn);
|
||||
return 1;
|
||||
}
|
||||
else if (!is_r2)
|
||||
return 0;
|
||||
else if (op->match == MATCH_R2_SUB)
|
||||
{
|
||||
*ra = GET_IW_F3X6L5_A (insn);
|
||||
*rb = GET_IW_F3X6L5_B (insn);
|
||||
*rc = GET_IW_F3X6L5_C (insn);
|
||||
return 1;
|
||||
}
|
||||
else if (op->match == MATCH_R2_SUB_N)
|
||||
{
|
||||
*ra = nios2_r2_reg3_mappings[GET_IW_T3X1_A3 (insn)];
|
||||
*rb = nios2_r2_reg3_mappings[GET_IW_T3X1_B3 (insn)];
|
||||
*rc = nios2_r2_reg3_mappings[GET_IW_T3X1_C3 (insn)];
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -340,13 +388,49 @@ static int
|
||||
nios2_match_addi (uint32_t insn, const struct nios2_opcode *op,
|
||||
unsigned long mach, int *ra, int *rb, int *imm)
|
||||
{
|
||||
if (op->match == MATCH_R1_ADDI)
|
||||
int is_r2 = (mach == bfd_mach_nios2r2);
|
||||
|
||||
if (!is_r2 && op->match == MATCH_R1_ADDI)
|
||||
{
|
||||
*ra = GET_IW_I_A (insn);
|
||||
*rb = GET_IW_I_B (insn);
|
||||
*imm = (signed) (GET_IW_I_IMM16 (insn) << 16) >> 16;
|
||||
return 1;
|
||||
}
|
||||
else if (!is_r2)
|
||||
return 0;
|
||||
else if (op->match == MATCH_R2_ADDI)
|
||||
{
|
||||
*ra = GET_IW_F2I16_A (insn);
|
||||
*rb = GET_IW_F2I16_B (insn);
|
||||
*imm = (signed) (GET_IW_F2I16_IMM16 (insn) << 16) >> 16;
|
||||
return 1;
|
||||
}
|
||||
else if (op->match == MATCH_R2_ADDI_N || op->match == MATCH_R2_SUBI_N)
|
||||
{
|
||||
*ra = nios2_r2_reg3_mappings[GET_IW_T2X1I3_A3 (insn)];
|
||||
*rb = nios2_r2_reg3_mappings[GET_IW_T2X1I3_B3 (insn)];
|
||||
*imm = nios2_r2_asi_n_mappings[GET_IW_T2X1I3_IMM3 (insn)];
|
||||
if (op->match == MATCH_R2_SUBI_N)
|
||||
*imm = - (*imm);
|
||||
return 1;
|
||||
}
|
||||
else if (op->match == MATCH_R2_SPADDI_N)
|
||||
{
|
||||
*ra = nios2_r2_reg3_mappings[GET_IW_T1I7_A3 (insn)];
|
||||
*rb = NIOS2_SP_REGNUM;
|
||||
*imm = GET_IW_T1I7_IMM7 (insn) << 2;
|
||||
return 1;
|
||||
}
|
||||
else if (op->match == MATCH_R2_SPINCI_N || op->match == MATCH_R2_SPDECI_N)
|
||||
{
|
||||
*ra = NIOS2_SP_REGNUM;
|
||||
*rb = NIOS2_SP_REGNUM;
|
||||
*imm = GET_IW_X1I7_IMM7 (insn) << 2;
|
||||
if (op->match == MATCH_R2_SPDECI_N)
|
||||
*imm = - (*imm);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -358,13 +442,24 @@ static int
|
||||
nios2_match_orhi (uint32_t insn, const struct nios2_opcode *op,
|
||||
unsigned long mach, int *ra, int *rb, unsigned int *uimm)
|
||||
{
|
||||
if (op->match == MATCH_R1_ORHI)
|
||||
int is_r2 = (mach == bfd_mach_nios2r2);
|
||||
|
||||
if (!is_r2 && op->match == MATCH_R1_ORHI)
|
||||
{
|
||||
*ra = GET_IW_I_A (insn);
|
||||
*rb = GET_IW_I_B (insn);
|
||||
*uimm = GET_IW_I_IMM16 (insn);
|
||||
return 1;
|
||||
}
|
||||
else if (!is_r2)
|
||||
return 0;
|
||||
else if (op->match == MATCH_R2_ORHI)
|
||||
{
|
||||
*ra = GET_IW_F2I16_A (insn);
|
||||
*rb = GET_IW_F2I16_B (insn);
|
||||
*uimm = GET_IW_F2I16_IMM16 (insn);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -376,13 +471,52 @@ static int
|
||||
nios2_match_stw (uint32_t insn, const struct nios2_opcode *op,
|
||||
unsigned long mach, int *ra, int *rb, int *imm)
|
||||
{
|
||||
if (op->match == MATCH_R1_STW || op->match == MATCH_R1_STWIO)
|
||||
int is_r2 = (mach == bfd_mach_nios2r2);
|
||||
|
||||
if (!is_r2 && (op->match == MATCH_R1_STW || op->match == MATCH_R1_STWIO))
|
||||
{
|
||||
*ra = GET_IW_I_A (insn);
|
||||
*rb = GET_IW_I_B (insn);
|
||||
*imm = (signed) (GET_IW_I_IMM16 (insn) << 16) >> 16;
|
||||
return 1;
|
||||
}
|
||||
else if (!is_r2)
|
||||
return 0;
|
||||
else if (op->match == MATCH_R2_STW)
|
||||
{
|
||||
*ra = GET_IW_F2I16_A (insn);
|
||||
*rb = GET_IW_F2I16_B (insn);
|
||||
*imm = (signed) (GET_IW_F2I16_IMM16 (insn) << 16) >> 16;
|
||||
return 1;
|
||||
}
|
||||
else if (op->match == MATCH_R2_STWIO)
|
||||
{
|
||||
*ra = GET_IW_F2X4I12_A (insn);
|
||||
*rb = GET_IW_F2X4I12_B (insn);
|
||||
*imm = (signed) (GET_IW_F2X4I12_IMM12 (insn) << 20) >> 20;
|
||||
return 1;
|
||||
}
|
||||
else if (op->match == MATCH_R2_STW_N)
|
||||
{
|
||||
*ra = nios2_r2_reg3_mappings[GET_IW_T2I4_A3 (insn)];
|
||||
*rb = nios2_r2_reg3_mappings[GET_IW_T2I4_B3 (insn)];
|
||||
*imm = GET_IW_T2I4_IMM4 (insn) << 2;
|
||||
return 1;
|
||||
}
|
||||
else if (op->match == MATCH_R2_STWSP_N)
|
||||
{
|
||||
*ra = NIOS2_SP_REGNUM;
|
||||
*rb = GET_IW_F1I5_B (insn);
|
||||
*imm = GET_IW_F1I5_IMM5 (insn) << 2;
|
||||
return 1;
|
||||
}
|
||||
else if (op->match == MATCH_R2_STWZ_N)
|
||||
{
|
||||
*ra = nios2_r2_reg3_mappings[GET_IW_T1X1I6_A3 (insn)];
|
||||
*rb = 0;
|
||||
*imm = GET_IW_T1X1I6_IMM6 (insn) << 2;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -394,13 +528,45 @@ static int
|
||||
nios2_match_ldw (uint32_t insn, const struct nios2_opcode *op,
|
||||
unsigned long mach, int *ra, int *rb, int *imm)
|
||||
{
|
||||
if (op->match == MATCH_R1_LDW || op->match == MATCH_R1_LDWIO)
|
||||
int is_r2 = (mach == bfd_mach_nios2r2);
|
||||
|
||||
if (!is_r2 && (op->match == MATCH_R1_LDW || op->match == MATCH_R1_LDWIO))
|
||||
{
|
||||
*ra = GET_IW_I_A (insn);
|
||||
*rb = GET_IW_I_B (insn);
|
||||
*imm = (signed) (GET_IW_I_IMM16 (insn) << 16) >> 16;
|
||||
return 1;
|
||||
}
|
||||
else if (!is_r2)
|
||||
return 0;
|
||||
else if (op->match == MATCH_R2_LDW)
|
||||
{
|
||||
*ra = GET_IW_F2I16_A (insn);
|
||||
*rb = GET_IW_F2I16_B (insn);
|
||||
*imm = (signed) (GET_IW_F2I16_IMM16 (insn) << 16) >> 16;
|
||||
return 1;
|
||||
}
|
||||
else if (op->match == MATCH_R2_LDWIO)
|
||||
{
|
||||
*ra = GET_IW_F2X4I12_A (insn);
|
||||
*rb = GET_IW_F2X4I12_B (insn);
|
||||
*imm = (signed) (GET_IW_F2X4I12_IMM12 (insn) << 20) >> 20;
|
||||
return 1;
|
||||
}
|
||||
else if (op->match == MATCH_R2_LDW_N)
|
||||
{
|
||||
*ra = nios2_r2_reg3_mappings[GET_IW_T2I4_A3 (insn)];
|
||||
*rb = nios2_r2_reg3_mappings[GET_IW_T2I4_B3 (insn)];
|
||||
*imm = GET_IW_T2I4_IMM4 (insn) << 2;
|
||||
return 1;
|
||||
}
|
||||
else if (op->match == MATCH_R2_LDWSP_N)
|
||||
{
|
||||
*ra = NIOS2_SP_REGNUM;
|
||||
*rb = GET_IW_F1I5_B (insn);
|
||||
*imm = GET_IW_F1I5_IMM5 (insn) << 2;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -411,15 +577,126 @@ static int
|
||||
nios2_match_rdctl (uint32_t insn, const struct nios2_opcode *op,
|
||||
unsigned long mach, int *ra, int *rc)
|
||||
{
|
||||
if (op->match == MATCH_R1_RDCTL)
|
||||
int is_r2 = (mach == bfd_mach_nios2r2);
|
||||
|
||||
if (!is_r2 && (op->match == MATCH_R1_RDCTL))
|
||||
{
|
||||
*ra = GET_IW_R_IMM5 (insn);
|
||||
*rc = GET_IW_R_C (insn);
|
||||
return 1;
|
||||
}
|
||||
else if (!is_r2)
|
||||
return 0;
|
||||
else if (op->match == MATCH_R2_RDCTL)
|
||||
{
|
||||
*ra = GET_IW_F3X6L5_IMM5 (insn);
|
||||
*rc = GET_IW_F3X6L5_C (insn);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Match and disassemble a PUSH.N or STWM instruction.
|
||||
Returns true on success, and fills in the operand pointers. */
|
||||
|
||||
static int
|
||||
nios2_match_stwm (uint32_t insn, const struct nios2_opcode *op,
|
||||
unsigned long mach, unsigned int *reglist,
|
||||
int *ra, int *imm, int *wb, int *id)
|
||||
{
|
||||
int is_r2 = (mach == bfd_mach_nios2r2);
|
||||
|
||||
if (!is_r2)
|
||||
return 0;
|
||||
else if (op->match == MATCH_R2_PUSH_N)
|
||||
{
|
||||
*reglist = 1 << 31;
|
||||
if (GET_IW_L5I4X1_FP (insn))
|
||||
*reglist |= (1 << 28);
|
||||
if (GET_IW_L5I4X1_CS (insn))
|
||||
{
|
||||
int val = GET_IW_L5I4X1_REGRANGE (insn);
|
||||
*reglist |= nios2_r2_reg_range_mappings[val];
|
||||
}
|
||||
*ra = NIOS2_SP_REGNUM;
|
||||
*imm = GET_IW_L5I4X1_IMM4 (insn) << 2;
|
||||
*wb = 1;
|
||||
*id = 0;
|
||||
return 1;
|
||||
}
|
||||
else if (op->match == MATCH_R2_STWM)
|
||||
{
|
||||
unsigned int rawmask = GET_IW_F1X4L17_REGMASK (insn);
|
||||
if (GET_IW_F1X4L17_RS (insn))
|
||||
{
|
||||
*reglist = ((rawmask << 14) & 0x00ffc000);
|
||||
if (rawmask & (1 << 10))
|
||||
*reglist |= (1 << 28);
|
||||
if (rawmask & (1 << 11))
|
||||
*reglist |= (1 << 31);
|
||||
}
|
||||
else
|
||||
*reglist = rawmask << 2;
|
||||
*ra = GET_IW_F1X4L17_A (insn);
|
||||
*imm = 0;
|
||||
*wb = GET_IW_F1X4L17_WB (insn);
|
||||
*id = GET_IW_F1X4L17_ID (insn);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Match and disassemble a POP.N or LDWM instruction.
|
||||
Returns true on success, and fills in the operand pointers. */
|
||||
|
||||
static int
|
||||
nios2_match_ldwm (uint32_t insn, const struct nios2_opcode *op,
|
||||
unsigned long mach, unsigned int *reglist,
|
||||
int *ra, int *imm, int *wb, int *id, int *ret)
|
||||
{
|
||||
int is_r2 = (mach == bfd_mach_nios2r2);
|
||||
|
||||
if (!is_r2)
|
||||
return 0;
|
||||
else if (op->match == MATCH_R2_POP_N)
|
||||
{
|
||||
*reglist = 1 << 31;
|
||||
if (GET_IW_L5I4X1_FP (insn))
|
||||
*reglist |= (1 << 28);
|
||||
if (GET_IW_L5I4X1_CS (insn))
|
||||
{
|
||||
int val = GET_IW_L5I4X1_REGRANGE (insn);
|
||||
*reglist |= nios2_r2_reg_range_mappings[val];
|
||||
}
|
||||
*ra = NIOS2_SP_REGNUM;
|
||||
*imm = GET_IW_L5I4X1_IMM4 (insn) << 2;
|
||||
*wb = 1;
|
||||
*id = 1;
|
||||
*ret = 1;
|
||||
return 1;
|
||||
}
|
||||
else if (op->match == MATCH_R2_LDWM)
|
||||
{
|
||||
unsigned int rawmask = GET_IW_F1X4L17_REGMASK (insn);
|
||||
if (GET_IW_F1X4L17_RS (insn))
|
||||
{
|
||||
*reglist = ((rawmask << 14) & 0x00ffc000);
|
||||
if (rawmask & (1 << 10))
|
||||
*reglist |= (1 << 28);
|
||||
if (rawmask & (1 << 11))
|
||||
*reglist |= (1 << 31);
|
||||
}
|
||||
else
|
||||
*reglist = rawmask << 2;
|
||||
*ra = GET_IW_F1X4L17_A (insn);
|
||||
*imm = 0;
|
||||
*wb = GET_IW_F1X4L17_WB (insn);
|
||||
*id = GET_IW_F1X4L17_ID (insn);
|
||||
*ret = GET_IW_F1X4L17_PC (insn);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Match and disassemble a branch instruction, with (potentially)
|
||||
2 register operands and one immediate operand.
|
||||
@ -440,36 +717,93 @@ nios2_match_branch (uint32_t insn, const struct nios2_opcode *op,
|
||||
unsigned long mach, int *ra, int *rb, int *imm,
|
||||
enum branch_condition *cond)
|
||||
{
|
||||
switch (op->match)
|
||||
int is_r2 = (mach == bfd_mach_nios2r2);
|
||||
|
||||
if (!is_r2)
|
||||
{
|
||||
case MATCH_R1_BR:
|
||||
*cond = branch_none;
|
||||
break;
|
||||
case MATCH_R1_BEQ:
|
||||
*cond = branch_eq;
|
||||
break;
|
||||
case MATCH_R1_BNE:
|
||||
*cond = branch_ne;
|
||||
break;
|
||||
case MATCH_R1_BGE:
|
||||
*cond = branch_ge;
|
||||
break;
|
||||
case MATCH_R1_BGEU:
|
||||
*cond = branch_geu;
|
||||
break;
|
||||
case MATCH_R1_BLT:
|
||||
*cond = branch_lt;
|
||||
break;
|
||||
case MATCH_R1_BLTU:
|
||||
*cond = branch_ltu;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
switch (op->match)
|
||||
{
|
||||
case MATCH_R1_BR:
|
||||
*cond = branch_none;
|
||||
break;
|
||||
case MATCH_R1_BEQ:
|
||||
*cond = branch_eq;
|
||||
break;
|
||||
case MATCH_R1_BNE:
|
||||
*cond = branch_ne;
|
||||
break;
|
||||
case MATCH_R1_BGE:
|
||||
*cond = branch_ge;
|
||||
break;
|
||||
case MATCH_R1_BGEU:
|
||||
*cond = branch_geu;
|
||||
break;
|
||||
case MATCH_R1_BLT:
|
||||
*cond = branch_lt;
|
||||
break;
|
||||
case MATCH_R1_BLTU:
|
||||
*cond = branch_ltu;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
*imm = (signed) (GET_IW_I_IMM16 (insn) << 16) >> 16;
|
||||
*ra = GET_IW_I_A (insn);
|
||||
*rb = GET_IW_I_B (insn);
|
||||
return 1;
|
||||
}
|
||||
*imm = (signed) (GET_IW_I_IMM16 (insn) << 16) >> 16;
|
||||
*ra = GET_IW_I_A (insn);
|
||||
*rb = GET_IW_I_B (insn);
|
||||
return 1;
|
||||
else
|
||||
{
|
||||
switch (op->match)
|
||||
{
|
||||
case MATCH_R2_BR_N:
|
||||
*cond = branch_none;
|
||||
*ra = NIOS2_Z_REGNUM;
|
||||
*rb = NIOS2_Z_REGNUM;
|
||||
*imm = (signed) ((GET_IW_I10_IMM10 (insn) << 1) << 21) >> 21;
|
||||
return 1;
|
||||
case MATCH_R2_BEQZ_N:
|
||||
*cond = branch_eq;
|
||||
*ra = nios2_r2_reg3_mappings[GET_IW_T1I7_A3 (insn)];
|
||||
*rb = NIOS2_Z_REGNUM;
|
||||
*imm = (signed) ((GET_IW_T1I7_IMM7 (insn) << 1) << 24) >> 24;
|
||||
return 1;
|
||||
case MATCH_R2_BNEZ_N:
|
||||
*cond = branch_ne;
|
||||
*ra = nios2_r2_reg3_mappings[GET_IW_T1I7_A3 (insn)];
|
||||
*rb = NIOS2_Z_REGNUM;
|
||||
*imm = (signed) ((GET_IW_T1I7_IMM7 (insn) << 1) << 24) >> 24;
|
||||
return 1;
|
||||
case MATCH_R2_BR:
|
||||
*cond = branch_none;
|
||||
break;
|
||||
case MATCH_R2_BEQ:
|
||||
*cond = branch_eq;
|
||||
break;
|
||||
case MATCH_R2_BNE:
|
||||
*cond = branch_ne;
|
||||
break;
|
||||
case MATCH_R2_BGE:
|
||||
*cond = branch_ge;
|
||||
break;
|
||||
case MATCH_R2_BGEU:
|
||||
*cond = branch_geu;
|
||||
break;
|
||||
case MATCH_R2_BLT:
|
||||
*cond = branch_lt;
|
||||
break;
|
||||
case MATCH_R2_BLTU:
|
||||
*cond = branch_ltu;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
*ra = GET_IW_F2I16_A (insn);
|
||||
*rb = GET_IW_F2I16_B (insn);
|
||||
*imm = (signed) (GET_IW_F2I16_IMM16 (insn) << 16) >> 16;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Match and disassemble a direct jump instruction, with an
|
||||
@ -480,11 +814,20 @@ static int
|
||||
nios2_match_jmpi (uint32_t insn, const struct nios2_opcode *op,
|
||||
unsigned long mach, unsigned int *uimm)
|
||||
{
|
||||
if (op->match == MATCH_R1_JMPI)
|
||||
int is_r2 = (mach == bfd_mach_nios2r2);
|
||||
|
||||
if (!is_r2 && op->match == MATCH_R1_JMPI)
|
||||
{
|
||||
*uimm = GET_IW_J_IMM26 (insn) << 2;
|
||||
return 1;
|
||||
}
|
||||
else if (!is_r2)
|
||||
return 0;
|
||||
else if (op->match == MATCH_R2_JMPI)
|
||||
{
|
||||
*uimm = GET_IW_L26_IMM26 (insn) << 2;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -496,11 +839,20 @@ static int
|
||||
nios2_match_calli (uint32_t insn, const struct nios2_opcode *op,
|
||||
unsigned long mach, unsigned int *uimm)
|
||||
{
|
||||
if (op->match == MATCH_R1_CALL)
|
||||
int is_r2 = (mach == bfd_mach_nios2r2);
|
||||
|
||||
if (!is_r2 && op->match == MATCH_R1_CALL)
|
||||
{
|
||||
*uimm = GET_IW_J_IMM26 (insn) << 2;
|
||||
return 1;
|
||||
}
|
||||
else if (!is_r2)
|
||||
return 0;
|
||||
else if (op->match == MATCH_R2_CALL)
|
||||
{
|
||||
*uimm = GET_IW_L26_IMM26 (insn) << 2;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -512,23 +864,49 @@ static int
|
||||
nios2_match_jmpr (uint32_t insn, const struct nios2_opcode *op,
|
||||
unsigned long mach, int *ra)
|
||||
{
|
||||
switch (op->match)
|
||||
{
|
||||
case MATCH_R1_JMP:
|
||||
*ra = GET_IW_I_A (insn);
|
||||
return 1;
|
||||
case MATCH_R1_RET:
|
||||
*ra = NIOS2_RA_REGNUM;
|
||||
return 1;
|
||||
case MATCH_R1_ERET:
|
||||
*ra = NIOS2_EA_REGNUM;
|
||||
return 1;
|
||||
case MATCH_R1_BRET:
|
||||
*ra = NIOS2_BA_REGNUM;
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
int is_r2 = (mach == bfd_mach_nios2r2);
|
||||
|
||||
if (!is_r2)
|
||||
switch (op->match)
|
||||
{
|
||||
case MATCH_R1_JMP:
|
||||
*ra = GET_IW_I_A (insn);
|
||||
return 1;
|
||||
case MATCH_R1_RET:
|
||||
*ra = NIOS2_RA_REGNUM;
|
||||
return 1;
|
||||
case MATCH_R1_ERET:
|
||||
*ra = NIOS2_EA_REGNUM;
|
||||
return 1;
|
||||
case MATCH_R1_BRET:
|
||||
*ra = NIOS2_BA_REGNUM;
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
switch (op->match)
|
||||
{
|
||||
case MATCH_R2_JMP:
|
||||
*ra = GET_IW_F2I16_A (insn);
|
||||
return 1;
|
||||
case MATCH_R2_JMPR_N:
|
||||
*ra = GET_IW_F1X1_A (insn);
|
||||
return 1;
|
||||
case MATCH_R2_RET:
|
||||
case MATCH_R2_RET_N:
|
||||
*ra = NIOS2_RA_REGNUM;
|
||||
return 1;
|
||||
case MATCH_R2_ERET:
|
||||
*ra = NIOS2_EA_REGNUM;
|
||||
return 1;
|
||||
case MATCH_R2_BRET:
|
||||
*ra = NIOS2_BA_REGNUM;
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Match and disassemble an indirect call instruction, with a register
|
||||
@ -538,11 +916,25 @@ static int
|
||||
nios2_match_callr (uint32_t insn, const struct nios2_opcode *op,
|
||||
unsigned long mach, int *ra)
|
||||
{
|
||||
if (op->match == MATCH_R1_CALLR)
|
||||
int is_r2 = (mach == bfd_mach_nios2r2);
|
||||
|
||||
if (!is_r2 && op->match == MATCH_R1_CALLR)
|
||||
{
|
||||
*ra = GET_IW_I_A (insn);
|
||||
return 1;
|
||||
}
|
||||
else if (!is_r2)
|
||||
return 0;
|
||||
else if (op->match == MATCH_R2_CALLR)
|
||||
{
|
||||
*ra = GET_IW_F2I16_A (insn);
|
||||
return 1;
|
||||
}
|
||||
else if (op->match == MATCH_R2_CALLR_N)
|
||||
{
|
||||
*ra = GET_IW_F1X1_A (insn);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -553,11 +945,25 @@ static int
|
||||
nios2_match_break (uint32_t insn, const struct nios2_opcode *op,
|
||||
unsigned long mach, unsigned int *uimm)
|
||||
{
|
||||
if (op->match == MATCH_R1_BREAK)
|
||||
int is_r2 = (mach == bfd_mach_nios2r2);
|
||||
|
||||
if (!is_r2 && op->match == MATCH_R1_BREAK)
|
||||
{
|
||||
*uimm = GET_IW_R_IMM5 (insn);
|
||||
return 1;
|
||||
}
|
||||
else if (!is_r2)
|
||||
return 0;
|
||||
else if (op->match == MATCH_R2_BREAK)
|
||||
{
|
||||
*uimm = GET_IW_F3X6L5_IMM5 (insn);
|
||||
return 1;
|
||||
}
|
||||
else if (op->match == MATCH_R2_BREAK_N)
|
||||
{
|
||||
*uimm = GET_IW_X2L5_IMM5 (insn);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -568,11 +974,25 @@ static int
|
||||
nios2_match_trap (uint32_t insn, const struct nios2_opcode *op,
|
||||
unsigned long mach, unsigned int *uimm)
|
||||
{
|
||||
if (op->match == MATCH_R1_TRAP)
|
||||
int is_r2 = (mach == bfd_mach_nios2r2);
|
||||
|
||||
if (!is_r2 && op->match == MATCH_R1_TRAP)
|
||||
{
|
||||
*uimm = GET_IW_R_IMM5 (insn);
|
||||
return 1;
|
||||
}
|
||||
else if (!is_r2)
|
||||
return 0;
|
||||
else if (op->match == MATCH_R2_TRAP)
|
||||
{
|
||||
*uimm = GET_IW_F3X6L5_IMM5 (insn);
|
||||
return 1;
|
||||
}
|
||||
else if (op->match == MATCH_R2_TRAP_N)
|
||||
{
|
||||
*uimm = GET_IW_X2L5_IMM5 (insn);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -589,6 +1009,7 @@ nios2_in_epilogue_p (struct gdbarch *gdbarch,
|
||||
CORE_ADDR start_pc)
|
||||
{
|
||||
unsigned long mach = gdbarch_bfd_arch_info (gdbarch)->mach;
|
||||
int is_r2 = (mach == bfd_mach_nios2r2);
|
||||
/* Maximum number of possibly-epilogue instructions to check.
|
||||
Note that this number should not be too large, else we can
|
||||
potentially end up iterating through unmapped memory. */
|
||||
@ -597,6 +1018,7 @@ nios2_in_epilogue_p (struct gdbarch *gdbarch,
|
||||
const struct nios2_opcode *op = NULL;
|
||||
unsigned int uimm;
|
||||
int imm;
|
||||
int wb, id, ret;
|
||||
int ra, rb, rc;
|
||||
enum branch_condition cond;
|
||||
CORE_ADDR pc;
|
||||
@ -605,17 +1027,41 @@ nios2_in_epilogue_p (struct gdbarch *gdbarch,
|
||||
if (current_pc <= start_pc)
|
||||
return 0;
|
||||
|
||||
/* Find the previous instruction before current_pc.
|
||||
For the moment we will assume that all instructions are the
|
||||
same size here. */
|
||||
pc = current_pc - NIOS2_OPCODE_SIZE;
|
||||
/* Find the previous instruction before current_pc. For R2, it might
|
||||
be either a 16-bit or 32-bit instruction; the only way to know for
|
||||
sure is to scan through from the beginning of the function,
|
||||
disassembling as we go. */
|
||||
if (is_r2)
|
||||
for (pc = start_pc; ; )
|
||||
{
|
||||
op = nios2_fetch_insn (gdbarch, pc, &insn);
|
||||
if (op == NULL)
|
||||
return 0;
|
||||
if (pc + op->size < current_pc)
|
||||
pc += op->size;
|
||||
else
|
||||
break;
|
||||
/* We can skip over insns to a forward branch target. Since
|
||||
the branch offset is relative to the next instruction,
|
||||
it's correct to do this after incrementing the pc above. */
|
||||
if (nios2_match_branch (insn, op, mach, &ra, &rb, &imm, &cond)
|
||||
&& imm > 0
|
||||
&& pc + imm < current_pc)
|
||||
pc += imm;
|
||||
}
|
||||
/* Otherwise just go back to the previous 32-bit insn. */
|
||||
else
|
||||
pc = current_pc - NIOS2_OPCODE_SIZE;
|
||||
|
||||
/* Beginning with the previous instruction we just located, check whether
|
||||
we are in a sequence of at least one stack adjustment instruction.
|
||||
Possible instructions here include:
|
||||
ADDI sp, sp, n
|
||||
ADD sp, sp, rn
|
||||
LDW sp, n(sp) */
|
||||
LDW sp, n(sp)
|
||||
SPINCI.N n
|
||||
LDWSP.N sp, n(sp)
|
||||
LDWM {reglist}, (sp)++, wb */
|
||||
for (ninsns = 0; ninsns < max_insns; ninsns++)
|
||||
{
|
||||
int ok = 0;
|
||||
@ -633,6 +1079,9 @@ nios2_in_epilogue_p (struct gdbarch *gdbarch,
|
||||
ok = (rc == NIOS2_SP_REGNUM);
|
||||
else if (nios2_match_ldw (insn, op, mach, &ra, &rb, &imm))
|
||||
ok = (rb == NIOS2_SP_REGNUM);
|
||||
else if (nios2_match_ldwm (insn, op, mach, &uimm, &ra,
|
||||
&imm, &wb, &ret, &id))
|
||||
ok = (ra == NIOS2_SP_REGNUM && wb && id);
|
||||
if (!ok)
|
||||
break;
|
||||
}
|
||||
@ -648,9 +1097,12 @@ nios2_in_epilogue_p (struct gdbarch *gdbarch,
|
||||
return 1;
|
||||
|
||||
/* The next instruction following the stack adjustments must be a
|
||||
return, jump, or unconditional branch. */
|
||||
return, jump, or unconditional branch, or a CDX pop.n or ldwm
|
||||
that does an implicit return. */
|
||||
if (nios2_match_jmpr (insn, op, mach, &ra)
|
||||
|| nios2_match_jmpi (insn, op, mach, &uimm)
|
||||
|| (nios2_match_ldwm (insn, op, mach, &uimm, &ra, &imm, &wb, &id, &ret)
|
||||
&& ret)
|
||||
|| (nios2_match_branch (insn, op, mach, &ra, &rb, &imm, &cond)
|
||||
&& cond == branch_none))
|
||||
return 1;
|
||||
@ -684,10 +1136,12 @@ nios2_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc)
|
||||
mov ra, r8
|
||||
|
||||
2) A stack adjustment and save of R4-R7 for varargs functions.
|
||||
This is typically merged with item 3.
|
||||
For R2 CDX this is typically handled with a STWM, otherwise
|
||||
this is typically merged with item 3.
|
||||
|
||||
3) A stack adjustment and save of the callee-saved registers;
|
||||
typically an explicit SP decrement and individual register
|
||||
3) A stack adjustment and save of the callee-saved registers.
|
||||
For R2 CDX these are typically handled with a PUSH.N or STWM,
|
||||
otherwise as an explicit SP decrement and individual register
|
||||
saves.
|
||||
|
||||
There may also be a stack switch here in an exception handler
|
||||
@ -744,6 +1198,7 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc,
|
||||
int regno;
|
||||
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
|
||||
unsigned long mach = gdbarch_bfd_arch_info (gdbarch)->mach;
|
||||
int is_r2 = (mach == bfd_mach_nios2r2);
|
||||
|
||||
/* Does the frame set up the FP register? */
|
||||
int base_reg = 0;
|
||||
@ -789,7 +1244,7 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc,
|
||||
int ra, rb, rc, imm;
|
||||
unsigned int uimm;
|
||||
unsigned int reglist;
|
||||
int wb, ret;
|
||||
int wb, id, ret;
|
||||
enum branch_condition cond;
|
||||
|
||||
if (pc == current_pc)
|
||||
@ -812,7 +1267,12 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc,
|
||||
pc += op->size;
|
||||
|
||||
if (nios2_debug)
|
||||
fprintf_unfiltered (gdb_stdlog, "[%08X]", insn);
|
||||
{
|
||||
if (op->size == 2)
|
||||
fprintf_unfiltered (gdb_stdlog, "[%04X]", insn & 0xffff);
|
||||
else
|
||||
fprintf_unfiltered (gdb_stdlog, "[%08X]", insn);
|
||||
}
|
||||
|
||||
/* The following instructions can appear in the prologue. */
|
||||
|
||||
@ -954,6 +1414,42 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc,
|
||||
break;
|
||||
}
|
||||
|
||||
else if (nios2_match_stwm (insn, op, mach,
|
||||
®list, &ra, &imm, &wb, &id))
|
||||
{
|
||||
/* PUSH.N {reglist}, adjust
|
||||
or
|
||||
STWM {reglist}, --(SP)[, writeback] */
|
||||
int i;
|
||||
int off = 0;
|
||||
|
||||
if (ra != NIOS2_SP_REGNUM || id != 0)
|
||||
/* This is a non-stack-push memory write and cannot be
|
||||
part of the prologue. */
|
||||
break;
|
||||
|
||||
for (i = 31; i >= 0; i--)
|
||||
if (reglist & (1 << i))
|
||||
{
|
||||
int orig = value[i].reg;
|
||||
|
||||
off += 4;
|
||||
if (orig > 0 && value[i].offset == 0 && pc < current_pc)
|
||||
{
|
||||
cache->reg_saved[orig].basereg
|
||||
= value[NIOS2_SP_REGNUM].reg;
|
||||
cache->reg_saved[orig].addr
|
||||
= value[NIOS2_SP_REGNUM].offset - off;
|
||||
}
|
||||
}
|
||||
|
||||
if (wb)
|
||||
value[NIOS2_SP_REGNUM].offset -= off;
|
||||
value[NIOS2_SP_REGNUM].offset -= imm;
|
||||
|
||||
prologue_end = pc;
|
||||
}
|
||||
|
||||
else if (nios2_match_rdctl (insn, op, mach, &ra, &rc))
|
||||
{
|
||||
/* RDCTL rC, ctlN
|
||||
@ -1037,6 +1533,9 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc,
|
||||
else if (nios2_match_callr (insn, op, mach, &ra)
|
||||
|| nios2_match_jmpr (insn, op, mach, &ra)
|
||||
|| nios2_match_jmpi (insn, op, mach, &uimm)
|
||||
|| (nios2_match_ldwm (insn, op, mach, ®list, &ra,
|
||||
&imm, &wb, &id, &ret)
|
||||
&& ret)
|
||||
|| nios2_match_trap (insn, op, mach, &uimm)
|
||||
|| nios2_match_break (insn, op, mach, &uimm))
|
||||
break;
|
||||
@ -1215,16 +1714,45 @@ nios2_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *bp_addr,
|
||||
enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
|
||||
unsigned long mach = gdbarch_bfd_arch_info (gdbarch)->mach;
|
||||
|
||||
/* R1 trap encoding:
|
||||
((0x1d << 17) | (0x2d << 11) | (0x1f << 6) | (0x3a << 0))
|
||||
0x003b6ffa */
|
||||
static const gdb_byte r1_breakpoint_le[] = {0xfa, 0x6f, 0x3b, 0x0};
|
||||
static const gdb_byte r1_breakpoint_be[] = {0x0, 0x3b, 0x6f, 0xfa};
|
||||
*bp_size = NIOS2_OPCODE_SIZE;
|
||||
if (byte_order_for_code == BFD_ENDIAN_BIG)
|
||||
return r1_breakpoint_be;
|
||||
if (mach == bfd_mach_nios2r2)
|
||||
{
|
||||
/* R2 trap encoding:
|
||||
((0x2d << 26) | (0x1f << 21) | (0x1d << 16) | (0x20 << 0))
|
||||
0xb7fd0020
|
||||
CDX trap.n encoding:
|
||||
((0xd << 12) | (0x1f << 6) | (0x9 << 0))
|
||||
0xd7c9
|
||||
Note that code is always little-endian on R2. */
|
||||
static const gdb_byte r2_breakpoint_le[] = {0x20, 0x00, 0xfd, 0xb7};
|
||||
static const gdb_byte cdx_breakpoint_le[] = {0xc9, 0xd7};
|
||||
unsigned int insn;
|
||||
const struct nios2_opcode *op
|
||||
= nios2_fetch_insn (gdbarch, *bp_addr, &insn);
|
||||
|
||||
if (op && op->size == NIOS2_CDX_OPCODE_SIZE)
|
||||
{
|
||||
*bp_size = NIOS2_CDX_OPCODE_SIZE;
|
||||
return cdx_breakpoint_le;
|
||||
}
|
||||
else
|
||||
{
|
||||
*bp_size = NIOS2_OPCODE_SIZE;
|
||||
return r2_breakpoint_le;
|
||||
}
|
||||
}
|
||||
else
|
||||
return r1_breakpoint_le;
|
||||
{
|
||||
/* R1 trap encoding:
|
||||
((0x1d << 17) | (0x2d << 11) | (0x1f << 6) | (0x3a << 0))
|
||||
0x003b6ffa */
|
||||
static const gdb_byte r1_breakpoint_le[] = {0xfa, 0x6f, 0x3b, 0x0};
|
||||
static const gdb_byte r1_breakpoint_be[] = {0x0, 0x3b, 0x6f, 0xfa};
|
||||
*bp_size = NIOS2_OPCODE_SIZE;
|
||||
if (byte_order_for_code == BFD_ENDIAN_BIG)
|
||||
return r1_breakpoint_be;
|
||||
else
|
||||
return r1_breakpoint_le;
|
||||
}
|
||||
}
|
||||
|
||||
/* Implement the print_insn gdbarch method. */
|
||||
@ -1597,7 +2125,7 @@ nios2_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
|
||||
int rb;
|
||||
int imm;
|
||||
unsigned int uimm;
|
||||
int wb, ret;
|
||||
int wb, id, ret;
|
||||
enum branch_condition cond;
|
||||
|
||||
/* Do something stupid if we can't disassemble the insn at pc. */
|
||||
@ -1654,10 +2182,21 @@ nios2_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
|
||||
|| nios2_match_callr (insn, op, mach, &ra))
|
||||
pc = get_frame_register_unsigned (frame, ra);
|
||||
|
||||
else if (nios2_match_trap (insn, op, mach, &uimm))
|
||||
else if (nios2_match_ldwm (insn, op, mach, &uimm, &ra, &imm, &wb, &id, &ret)
|
||||
&& ret)
|
||||
{
|
||||
/* If ra is in the reglist, we have to use the value saved in the
|
||||
stack frame rather than the current value. */
|
||||
if (uimm & (1 << NIOS2_RA_REGNUM))
|
||||
pc = nios2_unwind_pc (gdbarch, frame);
|
||||
else
|
||||
pc = get_frame_register_unsigned (frame, NIOS2_RA_REGNUM);
|
||||
}
|
||||
|
||||
else if (nios2_match_trap (insn, op, mach, &uimm) && uimm == 0)
|
||||
{
|
||||
if (tdep->syscall_next_pc != NULL)
|
||||
return tdep->syscall_next_pc (frame);
|
||||
return tdep->syscall_next_pc (frame, op);
|
||||
}
|
||||
|
||||
else
|
||||
|
@ -20,6 +20,9 @@
|
||||
#ifndef NIOS2_TDEP_H
|
||||
#define NIOS2_TDEP_H
|
||||
|
||||
/* Nios II ISA specific encodings and macros. */
|
||||
#include "opcode/nios2.h"
|
||||
|
||||
/* Registers. */
|
||||
#define NIOS2_Z_REGNUM 0 /* Zero */
|
||||
#define NIOS2_R2_REGNUM 2 /* used for return value */
|
||||
@ -61,13 +64,15 @@
|
||||
|
||||
/* Size of an instruction, in bytes. */
|
||||
#define NIOS2_OPCODE_SIZE 4
|
||||
#define NIOS2_CDX_OPCODE_SIZE 2
|
||||
|
||||
/* Target-dependent structure in gdbarch. */
|
||||
struct gdbarch_tdep
|
||||
{
|
||||
/* Assumes FRAME is stopped at a syscall (trap) instruction; returns
|
||||
the expected next PC. */
|
||||
CORE_ADDR (*syscall_next_pc) (struct frame_info *frame);
|
||||
CORE_ADDR (*syscall_next_pc) (struct frame_info *frame,
|
||||
const struct nios2_opcode *op);
|
||||
|
||||
/* Offset to PC value in jump buffer.
|
||||
If this is negative, longjmp support will be disabled. */
|
||||
|
Loading…
Reference in New Issue
Block a user