X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fnios2-tdep.c;h=6e00a322d24ec8a13ab43a7d5c4a1af19189ef2f;hb=cd9629e1df1a280c19e1daaf6c1195afbab0aca9;hp=27580128dc300e99370842f6d6534d887133f93a;hpb=7f1659b5875387986901ee9bccd5247bf6899afc;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/nios2-tdep.c b/gdb/nios2-tdep.c index 27580128dc..6e00a322d2 100644 --- a/gdb/nios2-tdep.c +++ b/gdb/nios2-tdep.c @@ -1,5 +1,5 @@ /* Target-machine dependent code for Nios II, for GDB. - Copyright (C) 2012-2014 Free Software Foundation, Inc. + Copyright (C) 2012-2020 Free Software Foundation, Inc. Contributed by Peter Brookes (pbrookes@altera.com) and Andrew Draper (adraper@altera.com). Contributed by Mentor Graphics, Inc. @@ -37,16 +37,13 @@ #include "value.h" #include "symfile.h" #include "arch-utils.h" -#include "floatformat.h" #include "infcall.h" #include "regset.h" #include "target-descriptions.h" /* To get entry_point_address. */ #include "objfiles.h" - -/* Nios II ISA specific encodings and macros. */ -#include "opcode/nios2.h" +#include /* Nios II specific header. */ #include "nios2-tdep.h" @@ -55,19 +52,21 @@ /* Control debugging information emitted in this file. */ -static int nios2_debug = 0; +static bool nios2_debug = false; /* The following structures are used in the cache for prologue analysis; see the reg_value and reg_saved tables in struct nios2_unwind_cache, respectively. */ -/* struct reg_value is used to record that a register has the same value - as reg at the given offset from the start of a function. */ +/* struct reg_value is used to record that a register has reg's initial + value at the start of a function plus the given constant offset. + If reg == 0, then the value is just the offset. + If reg < 0, then the value is unknown. */ struct reg_value { int reg; - unsigned int offset; + int offset; }; /* struct reg_saved is used to record that a register value has been saved at @@ -141,17 +140,15 @@ static int nios2_dwarf2gdb_regno_map[] = NIOS2_MPUACC_REGNUM /* 48 */ }; +gdb_static_assert (ARRAY_SIZE (nios2_dwarf2gdb_regno_map) == NIOS2_NUM_REGS); /* Implement the dwarf2_reg_to_regnum gdbarch method. */ static int nios2_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int dw_reg) { - if (dw_reg < 0 || dw_reg > NIOS2_NUM_REGS) - { - warning (_("Dwarf-2 uses unmapped register #%d"), dw_reg); - return dw_reg; - } + if (dw_reg < 0 || dw_reg >= NIOS2_NUM_REGS) + return -1; return nios2_dwarf2gdb_regno_map[dw_reg]; } @@ -212,13 +209,13 @@ nios2_extract_return_value (struct gdbarch *gdbarch, struct type *valtype, /* Return values of up to 8 bytes are returned in $r2 $r3. */ if (len <= register_size (gdbarch, NIOS2_R2_REGNUM)) - regcache_cooked_read (regcache, NIOS2_R2_REGNUM, valbuf); + regcache->cooked_read (NIOS2_R2_REGNUM, valbuf); else { gdb_assert (len <= (register_size (gdbarch, NIOS2_R2_REGNUM) + register_size (gdbarch, NIOS2_R3_REGNUM))); - regcache_cooked_read (regcache, NIOS2_R2_REGNUM, valbuf); - regcache_cooked_read (regcache, NIOS2_R3_REGNUM, valbuf + 4); + regcache->cooked_read (NIOS2_R2_REGNUM, valbuf); + regcache->cooked_read (NIOS2_R3_REGNUM, valbuf + 4); } } @@ -233,13 +230,13 @@ nios2_store_return_value (struct gdbarch *gdbarch, struct type *valtype, /* Return values of up to 8 bytes are returned in $r2 $r3. */ if (len <= register_size (gdbarch, NIOS2_R2_REGNUM)) - regcache_cooked_write (regcache, NIOS2_R2_REGNUM, valbuf); + regcache->cooked_write (NIOS2_R2_REGNUM, valbuf); else { gdb_assert (len <= (register_size (gdbarch, NIOS2_R2_REGNUM) + register_size (gdbarch, NIOS2_R3_REGNUM))); - regcache_cooked_write (regcache, NIOS2_R2_REGNUM, valbuf); - regcache_cooked_write (regcache, NIOS2_R3_REGNUM, valbuf + 4); + regcache->cooked_write (NIOS2_R2_REGNUM, valbuf); + regcache->cooked_write (NIOS2_R3_REGNUM, valbuf + 4); } } @@ -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) - { - 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; + int is_r2 = (mach == bfd_mach_nios2r2); + + if (!is_r2) + { + 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; @@ -658,10 +1110,10 @@ nios2_in_epilogue_p (struct gdbarch *gdbarch, return 0; } -/* Implement the in_function_epilogue_p gdbarch method. */ +/* Implement the stack_frame_destroyed_p gdbarch method. */ static int -nios2_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc) +nios2_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc) { CORE_ADDR func_addr; @@ -684,10 +1136,12 @@ nios2_in_function_epilogue_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 @@ -697,22 +1151,29 @@ nios2_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc) stw sp, constant(rx) mov sp, rx - 5) A frame pointer save, which can be either a MOV or ADDI. + 4) A frame pointer save, which can be either a MOV or ADDI. - 6) A further stack pointer adjustment. This is normally included - adjustment in step 4 unless the total adjustment is too large + 5) A further stack pointer adjustment. This is normally included + adjustment in step 3 unless the total adjustment is too large to be done in one step. 7) A stack overflow check, which can take either of these forms: bgeu sp, rx, +8 - break 3 + trap 3 or bltu sp, rx, .Lstack_overflow ... .Lstack_overflow: - break 3 - If present, this is inserted after the stack pointer adjustments - for steps 3, 4, and 6. + trap 3 + + Older versions of GCC emitted "break 3" instead of "trap 3" here, + so we check for both cases. + + Older GCC versions emitted stack overflow checks after the SP + adjustments in both steps 3 and 4. Starting with GCC 6, there is + at most one overflow check, which is placed before the first + stack adjustment for R2 CDX and after the first stack adjustment + otherwise. The prologue instructions may be combined or interleaved with other instructions. @@ -734,7 +1195,6 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc, Note that this number should not be too large, else we can potentially end up iterating through unmapped memory. */ int ninsns, max_insns = 50; - int regno; enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); unsigned long mach = gdbarch_bfd_arch_info (gdbarch)->mach; @@ -744,8 +1204,6 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc, struct reg_value *value = cache->reg_value; struct reg_value temp_value[NIOS2_NUM_REGS]; - int i; - /* Save the starting PC so we can correct the pc after running through the prolog, using symbol info. */ CORE_ADDR pc = start_pc; @@ -782,7 +1240,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) @@ -805,7 +1263,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. */ @@ -822,7 +1285,7 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc, /* If any registers were saved on the stack before then we can't backtrace into them now. */ - for (i = 0 ; i < NIOS2_NUM_REGS ; i++) + for (int i = 0 ; i < NIOS2_NUM_REGS ; i++) { if (cache->reg_saved[i].basereg == NIOS2_SP_REGNUM) cache->reg_saved[i].basereg = -1; @@ -842,6 +1305,11 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc, cache->reg_saved[NIOS2_SP_REGNUM].addr = -4; } + else if (rc == NIOS2_SP_REGNUM && ra == NIOS2_FP_REGNUM) + /* This is setting SP from FP. This only happens in the + function epilogue. */ + break; + else if (rc != 0) { if (value[rb].reg == 0) @@ -853,13 +1321,21 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc, value[rc].offset = value[ra].offset + value[rb].offset; } - prologue_end = pc; + /* The add/move is only considered a prologue instruction + if the destination is SP or FP. */ + if (rc == NIOS2_SP_REGNUM || rc == NIOS2_FP_REGNUM) + prologue_end = pc; } else if (nios2_match_sub (insn, op, mach, &ra, &rb, &rc)) { /* SUB rc, ra, rb */ - if (rc != 0) + if (rc == NIOS2_SP_REGNUM && rb == NIOS2_SP_REGNUM + && value[rc].reg != 0) + /* If we are decrementing the SP by a non-constant amount, + this is alloca, not part of the prologue. */ + break; + else if (rc != 0) { if (value[rb].reg == 0) value[rc].reg = value[ra].reg; @@ -873,12 +1349,13 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc, { /* ADDI rb, ra, imm */ - /* The first stack adjustment is part of the prologue. - Any subsequent stack adjustments are either down to - alloca or the epilogue so stop analysing when we hit - them. */ + /* A positive stack adjustment has to be part of the epilogue. */ if (rb == NIOS2_SP_REGNUM - && (value[rb].offset != 0 || value[ra].reg != NIOS2_SP_REGNUM)) + && (imm > 0 || value[ra].reg != NIOS2_SP_REGNUM)) + break; + + /* Likewise restoring SP from FP. */ + else if (rb == NIOS2_SP_REGNUM && ra == NIOS2_FP_REGNUM) break; if (rb != 0) @@ -887,7 +1364,10 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc, value[rb].offset = value[ra].offset + imm; } - prologue_end = pc; + /* The add is only considered a prologue instruction + if the destination is SP or FP. */ + if (rb == NIOS2_SP_REGNUM || rb == NIOS2_FP_REGNUM) + prologue_end = pc; } else if (nios2_match_orhi (insn, op, mach, &ra, &rb, &uimm)) @@ -911,9 +1391,7 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc, if (orig > 0 && (value[rb].offset == 0 || (orig == NIOS2_EA_REGNUM && value[rb].offset == -4)) - && ((value[ra].reg == NIOS2_SP_REGNUM - && cache->reg_saved[orig].basereg != NIOS2_SP_REGNUM) - || cache->reg_saved[orig].basereg == -1)) + && value[ra].reg == NIOS2_SP_REGNUM) { if (pc < current_pc) { @@ -932,6 +1410,41 @@ 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 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 (int 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 @@ -955,9 +1468,9 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc, if ra has been stored into r8 beforehand and if it's before the stack adjust. Note mcount corrupts r2-r3, r9-r15 & ra. */ - for (i = 2 ; i <= 3 ; i++) + for (int i = 2 ; i <= 3 ; i++) value[i].reg = -1; - for (i = 9 ; i <= 15 ; i++) + for (int i = 9 ; i <= 15 ; i++) value[i].reg = -1; value[NIOS2_RA_REGNUM].reg = -1; @@ -978,14 +1491,15 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc, else if (cond == branch_geu) { /* BGEU sp, rx, +8 - BREAK 3 + TRAP 3 (or BREAK 3) This instruction sequence is used in stack checking; we can ignore it. */ unsigned int next_insn; const struct nios2_opcode *next_op = nios2_fetch_insn (gdbarch, pc, &next_insn); if (next_op != NULL - && nios2_match_break (next_insn, op, mach, &uimm)) + && (nios2_match_trap (next_insn, op, mach, &uimm) + || nios2_match_break (next_insn, op, mach, &uimm))) pc += next_op->size; else break; @@ -993,13 +1507,14 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc, else if (cond == branch_ltu) { /* BLTU sp, rx, .Lstackoverflow - If the location branched to holds a BREAK 3 instruction - then this is also stack overflow detection. */ + If the location branched to holds a TRAP or BREAK + instruction then this is also stack overflow detection. */ unsigned int next_insn; const struct nios2_opcode *next_op = nios2_fetch_insn (gdbarch, pc + imm, &next_insn); if (next_op != NULL - && nios2_match_break (next_insn, op, mach, &uimm)) + && (nios2_match_trap (next_insn, op, mach, &uimm) + || nios2_match_break (next_insn, op, mach, &uimm))) ; else break; @@ -1008,11 +1523,16 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc, break; } - /* All other calls or jumps (including returns) terminate + /* All other calls, jumps, returns, TRAPs, or BREAKs terminate the prologue. */ 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_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; } @@ -1100,14 +1620,14 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc, /* Adjust all the saved registers such that they contain addresses instead of offsets. */ - for (i = 0; i < NIOS2_NUM_REGS; i++) + for (int i = 0; i < NIOS2_NUM_REGS; i++) if (cache->reg_saved[i].basereg == NIOS2_SP_REGNUM) { cache->reg_saved[i].basereg = NIOS2_Z_REGNUM; cache->reg_saved[i].addr += frame_high; } - for (i = 0; i < NIOS2_NUM_REGS; i++) + for (int i = 0; i < NIOS2_NUM_REGS; i++) if (cache->reg_saved[i].basereg == NIOS2_GP_REGNUM) { CORE_ADDR gp = get_frame_register_unsigned (this_frame, @@ -1164,7 +1684,7 @@ nios2_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc) = skip_prologue_using_sal (gdbarch, func_addr); if (post_prologue_pc != 0) - return max (start_pc, post_prologue_pc); + return std::max (start_pc, post_prologue_pc); } /* Prologue analysis does the rest.... */ @@ -1172,38 +1692,83 @@ nios2_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc) return nios2_analyze_prologue (gdbarch, start_pc, start_pc, &cache, NULL); } -/* Implement the breakpoint_from_pc gdbarch hook. */ +/* Implement the breakpoint_kind_from_pc gdbarch method. */ -static const gdb_byte* -nios2_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *bp_addr, - int *bp_size) +static int +nios2_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr) { - enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch); unsigned long mach = gdbarch_bfd_arch_info (gdbarch)->mach; - /* R1 break encoding: - ((0x1e << 17) | (0x34 << 11) | (0x1f << 6) | (0x3a << 0)) - 0x003da7fa */ - static const gdb_byte r1_breakpoint_le[] = {0xfa, 0xa7, 0x3d, 0x0}; - static const gdb_byte r1_breakpoint_be[] = {0x0, 0x3d, 0xa7, 0xfa}; - *bp_size = NIOS2_OPCODE_SIZE; - if (byte_order_for_code == BFD_ENDIAN_BIG) - return r1_breakpoint_be; + if (mach == bfd_mach_nios2r2) + { + unsigned int insn; + const struct nios2_opcode *op + = nios2_fetch_insn (gdbarch, *pcptr, &insn); + + if (op && op->size == NIOS2_CDX_OPCODE_SIZE) + return NIOS2_CDX_OPCODE_SIZE; + else + return NIOS2_OPCODE_SIZE; + } else - return r1_breakpoint_le; + return NIOS2_OPCODE_SIZE; } -/* Implement the print_insn gdbarch method. */ +/* Implement the sw_breakpoint_from_kind gdbarch method. */ -static int -nios2_print_insn (bfd_vma memaddr, disassemble_info *info) +static const gdb_byte * +nios2_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size) { - if (info->endian == BFD_ENDIAN_BIG) - return print_insn_big_nios2 (memaddr, info); +/* The Nios II ABI for Linux says: "Userspace programs should not use + the break instruction and userspace debuggers should not insert + one." and "Userspace breakpoints are accomplished using the trap + instruction with immediate operand 31 (all ones)." + + So, we use "trap 31" consistently as the breakpoint on bare-metal + as well as Linux targets. */ + + /* 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. */ + *size = kind; + + if (kind == NIOS2_CDX_OPCODE_SIZE) + { + static const gdb_byte cdx_breakpoint_le[] = {0xc9, 0xd7}; + + return cdx_breakpoint_le; + } else - return print_insn_little_nios2 (memaddr, info); -} + { + unsigned long mach = gdbarch_bfd_arch_info (gdbarch)->mach; + + if (mach == bfd_mach_nios2r2) + { + static const gdb_byte r2_breakpoint_le[] = {0x20, 0x00, 0xfd, 0xb7}; + return r2_breakpoint_le; + } + else + { + enum bfd_endian byte_order_for_code + = gdbarch_byte_order_for_code (gdbarch); + /* 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}; + + if (byte_order_for_code == BFD_ENDIAN_BIG) + return r1_breakpoint_be; + else + return r1_breakpoint_le; + } + } +} /* Implement the frame_align gdbarch method. */ @@ -1232,30 +1797,19 @@ nios2_return_value (struct gdbarch *gdbarch, struct value *function, return RETURN_VALUE_REGISTER_CONVENTION; } -/* Implement the dummy_id gdbarch method. */ - -static struct frame_id -nios2_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame) -{ - return frame_id_build - (get_frame_register_unsigned (this_frame, NIOS2_SP_REGNUM), - get_frame_pc (this_frame)); -} - /* Implement the push_dummy_call gdbarch method. */ static CORE_ADDR nios2_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) + function_call_return_method return_method, + CORE_ADDR struct_addr) { int argreg; - int float_argreg; int argnum; - int len = 0; + int arg_space = 0; int stack_offset = 0; - CORE_ADDR func_addr = find_function_addr (function, NULL); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); /* Set the return address register to point to the entry point of @@ -1264,15 +1818,15 @@ nios2_push_dummy_call (struct gdbarch *gdbarch, struct value *function, /* Now make space on the stack for the args. */ for (argnum = 0; argnum < nargs; argnum++) - len += align_up (TYPE_LENGTH (value_type (args[argnum])), 4); - sp -= len; + arg_space += align_up (TYPE_LENGTH (value_type (args[argnum])), 4); + sp -= arg_space; /* Initialize the register pointer. */ argreg = NIOS2_FIRST_ARGREG; /* The struct_return pointer occupies the first parameter-passing register. */ - if (struct_return) + if (return_method == return_method_struct) regcache_cooked_write_unsigned (regcache, argreg++, struct_addr); /* Now load as many as possible of the first arguments into @@ -1281,11 +1835,9 @@ nios2_push_dummy_call (struct gdbarch *gdbarch, struct value *function, for (argnum = 0; argnum < nargs; argnum++) { const gdb_byte *val; - gdb_byte valbuf[MAX_REGISTER_SIZE]; struct value *arg = args[argnum]; struct type *arg_type = check_typedef (value_type (arg)); int len = TYPE_LENGTH (arg_type); - enum type_code typecode = TYPE_CODE (arg_type); val = value_contents (arg); @@ -1336,14 +1888,6 @@ nios2_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) return extract_typed_address (buf, builtin_type (gdbarch)->builtin_func_ptr); } -/* Implement the unwind_sp gdbarch method. */ - -static CORE_ADDR -nios2_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame) -{ - return frame_unwind_register_unsigned (this_frame, NIOS2_SP_REGNUM); -} - /* Use prologue analysis to fill in the register cache *THIS_PROLOGUE_CACHE for THIS_FRAME. This function initializes *THIS_PROLOGUE_CACHE first. */ @@ -1355,10 +1899,9 @@ nios2_frame_unwind_cache (struct frame_info *this_frame, struct gdbarch *gdbarch = get_frame_arch (this_frame); CORE_ADDR current_pc; struct nios2_unwind_cache *cache; - int i; if (*this_prologue_cache) - return *this_prologue_cache; + return (struct nios2_unwind_cache *) *this_prologue_cache; cache = FRAME_OBSTACK_ZALLOC (struct nios2_unwind_cache); *this_prologue_cache = cache; @@ -1463,10 +2006,9 @@ nios2_stub_frame_cache (struct frame_info *this_frame, void **this_cache) CORE_ADDR stack_addr; struct trad_frame_cache *this_trad_cache; struct gdbarch *gdbarch = get_frame_arch (this_frame); - int num_regs = gdbarch_num_regs (gdbarch); if (*this_cache != NULL) - return *this_cache; + return (struct trad_frame_cache *) *this_cache; this_trad_cache = trad_frame_cache_zalloc (this_frame); *this_cache = this_trad_cache; @@ -1521,7 +2063,6 @@ nios2_stub_frame_sniffer (const struct frame_unwind *self, struct frame_info *this_frame, void **cache) { gdb_byte dummy[4]; - struct obj_section *s; CORE_ADDR pc = get_frame_address_in_block (this_frame); /* Use the stub unwinder for unreadable code. */ @@ -1552,9 +2093,9 @@ static const struct frame_unwind nios2_stub_frame_unwind = branch prediction. */ static CORE_ADDR -nios2_get_next_pc (struct frame_info *frame, CORE_ADDR pc) +nios2_get_next_pc (struct regcache *regcache, CORE_ADDR pc) { - struct gdbarch *gdbarch = get_frame_arch (frame); + struct gdbarch *gdbarch = regcache->arch (); struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); unsigned long mach = gdbarch_bfd_arch_info (gdbarch)->mach; unsigned int insn; @@ -1563,7 +2104,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. */ @@ -1572,10 +2113,10 @@ nios2_get_next_pc (struct frame_info *frame, CORE_ADDR pc) if (nios2_match_branch (insn, op, mach, &ra, &rb, &imm, &cond)) { - int ras = get_frame_register_signed (frame, ra); - int rbs = get_frame_register_signed (frame, rb); - unsigned int rau = get_frame_register_unsigned (frame, ra); - unsigned int rbu = get_frame_register_unsigned (frame, rb); + int ras = regcache_raw_get_signed (regcache, ra); + int rbs = regcache_raw_get_signed (regcache, rb); + unsigned int rau = regcache_raw_get_unsigned (regcache, ra); + unsigned int rbu = regcache_raw_get_unsigned (regcache, rb); pc += op->size; switch (cond) @@ -1612,18 +2153,48 @@ nios2_get_next_pc (struct frame_info *frame, CORE_ADDR pc) } } - else if (nios2_match_jmpi (insn, op, mach, &uimm) - || nios2_match_calli (insn, op, mach, &uimm)) + else if (nios2_match_jmpi (insn, op, mach, &uimm)) pc = (pc & 0xf0000000) | uimm; + else if (nios2_match_calli (insn, op, mach, &uimm)) + { + CORE_ADDR callto = (pc & 0xf0000000) | uimm; + if (tdep->is_kernel_helper != NULL + && tdep->is_kernel_helper (callto)) + /* Step over call to kernel helper, which we cannot debug + from user space. */ + pc += op->size; + else + pc = callto; + } - else if (nios2_match_jmpr (insn, op, mach, &ra) - || nios2_match_callr (insn, op, mach, &ra)) - pc = get_frame_register_unsigned (frame, ra); + else if (nios2_match_jmpr (insn, op, mach, &ra)) + pc = regcache_raw_get_unsigned (regcache, ra); + else if (nios2_match_callr (insn, op, mach, &ra)) + { + CORE_ADDR callto = regcache_raw_get_unsigned (regcache, ra); + if (tdep->is_kernel_helper != NULL + && tdep->is_kernel_helper (callto)) + /* Step over call to kernel helper. */ + pc += op->size; + else + pc = callto; + } - 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, get_current_frame ()); + else + pc = regcache_raw_get_unsigned (regcache, 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 (get_current_frame (), op); } else @@ -1634,16 +2205,12 @@ nios2_get_next_pc (struct frame_info *frame, CORE_ADDR pc) /* Implement the software_single_step gdbarch method. */ -static int -nios2_software_single_step (struct frame_info *frame) +static std::vector +nios2_software_single_step (struct regcache *regcache) { - struct gdbarch *gdbarch = get_frame_arch (frame); - struct address_space *aspace = get_frame_address_space (frame); - CORE_ADDR next_pc = nios2_get_next_pc (frame, get_frame_pc (frame)); - - insert_single_step_breakpoint (gdbarch, aspace, next_pc); + CORE_ADDR next_pc = nios2_get_next_pc (regcache, regcache_read_pc (regcache)); - return 1; + return {next_pc}; } /* Implement the get_longjump_target gdbarch method. */ @@ -1664,6 +2231,42 @@ nios2_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc) return 1; } +/* Implement the type_align gdbarch function. */ + +static ULONGEST +nios2_type_align (struct gdbarch *gdbarch, struct type *type) +{ + switch (TYPE_CODE (type)) + { + case TYPE_CODE_PTR: + case TYPE_CODE_FUNC: + case TYPE_CODE_FLAGS: + case TYPE_CODE_INT: + case TYPE_CODE_RANGE: + case TYPE_CODE_FLT: + case TYPE_CODE_ENUM: + case TYPE_CODE_REF: + case TYPE_CODE_RVALUE_REF: + case TYPE_CODE_CHAR: + case TYPE_CODE_BOOL: + case TYPE_CODE_DECFLOAT: + case TYPE_CODE_METHODPTR: + case TYPE_CODE_MEMBERPTR: + type = check_typedef (type); + return std::min (4, TYPE_LENGTH (type)); + default: + return 0; + } +} + +/* Implement the gcc_target_options gdbarch method. */ +static std::string +nios2_gcc_target_options (struct gdbarch *gdbarch) +{ + /* GCC doesn't know "-m32". */ + return {}; +} + /* Initialize the Nios II gdbarch. */ static struct gdbarch * @@ -1671,7 +2274,7 @@ nios2_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) { struct gdbarch *gdbarch; struct gdbarch_tdep *tdep; - int register_bytes, i; + int i; struct tdesc_arch_data *tdesc_data = NULL; const struct target_desc *tdesc = info.target_desc; @@ -1711,7 +2314,7 @@ nios2_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) /* None found, create a new architecture from the information provided. */ - tdep = xcalloc (1, sizeof (struct gdbarch_tdep)); + tdep = XCNEW (struct gdbarch_tdep); gdbarch = gdbarch_alloc (&info, tdep); /* longjmp support not enabled by default. */ @@ -1727,6 +2330,8 @@ nios2_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_float_bit (gdbarch, 32); set_gdbarch_double_bit (gdbarch, 64); + set_gdbarch_type_align (gdbarch, nios2_type_align); + set_gdbarch_float_format (gdbarch, floatformats_ieee_single); set_gdbarch_double_format (gdbarch, floatformats_ieee_double); @@ -1750,12 +2355,11 @@ nios2_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_return_value (gdbarch, nios2_return_value); set_gdbarch_skip_prologue (gdbarch, nios2_skip_prologue); - set_gdbarch_in_function_epilogue_p (gdbarch, nios2_in_function_epilogue_p); - set_gdbarch_breakpoint_from_pc (gdbarch, nios2_breakpoint_from_pc); + set_gdbarch_stack_frame_destroyed_p (gdbarch, nios2_stack_frame_destroyed_p); + set_gdbarch_breakpoint_kind_from_pc (gdbarch, nios2_breakpoint_kind_from_pc); + set_gdbarch_sw_breakpoint_from_kind (gdbarch, nios2_sw_breakpoint_from_kind); - set_gdbarch_dummy_id (gdbarch, nios2_dummy_id); set_gdbarch_unwind_pc (gdbarch, nios2_unwind_pc); - set_gdbarch_unwind_sp (gdbarch, nios2_unwind_sp); /* The dwarf2 unwinder will normally produce the best results if the debug information is available, so register it first. */ @@ -1766,6 +2370,9 @@ nios2_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) /* Single stepping. */ set_gdbarch_software_single_step (gdbarch, nios2_software_single_step); + /* Target options for compile. */ + set_gdbarch_gcc_target_options (gdbarch, nios2_gcc_target_options); + /* Hook in ABI-specific overrides, if they have been registered. */ gdbarch_init_osabi (info, gdbarch); @@ -1774,8 +2381,6 @@ nios2_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) frame_base_set_default (gdbarch, &nios2_frame_base); - set_gdbarch_print_insn (gdbarch, nios2_print_insn); - /* Enable inferior call support. */ set_gdbarch_push_dummy_call (gdbarch, nios2_push_dummy_call); @@ -1785,8 +2390,6 @@ nios2_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) return gdbarch; } -extern initialize_file_ftype _initialize_nios2_tdep; /* -Wmissing-prototypes */ - void _initialize_nios2_tdep (void) {