X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=gdb%2Fnios2-tdep.c;h=196f50bc8694271000a3a2b3b87b85521ced60d4;hb=1d506c26d9772bcd84e1a7b3a8c8c5bc602dbf61;hp=055dc76900bb7f198566783677169ff52403fb56;hpb=a1217d97c4b0449d052fad3d2df2ab58b48f918c;p=thirdparty%2Fbinutils-gdb.git diff --git a/gdb/nios2-tdep.c b/gdb/nios2-tdep.c index 055dc76900b..196f50bc869 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-2013 Free Software Foundation, Inc. + Copyright (C) 2012-2024 Free Software Foundation, Inc. Contributed by Peter Brookes (pbrookes@altera.com) and Andrew Draper (adraper@altera.com). Contributed by Mentor Graphics, Inc. @@ -24,7 +24,7 @@ #include "frame-unwind.h" #include "frame-base.h" #include "trad-frame.h" -#include "dwarf2-frame.h" +#include "dwarf2/frame.h" #include "symtab.h" #include "inferior.h" #include "gdbtypes.h" @@ -37,17 +37,13 @@ #include "value.h" #include "symfile.h" #include "arch-utils.h" -#include "floatformat.h" -#include "gdb_assert.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" @@ -56,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 @@ -142,17 +140,15 @@ static int nios2_dwarf2gdb_regno_map[] = NIOS2_MPUACC_REGNUM /* 48 */ }; +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\n"), dw_reg); - return dw_reg; - } + if (dw_reg < 0 || dw_reg >= NIOS2_NUM_REGS) + return -1; return nios2_dwarf2gdb_regno_map[dw_reg]; } @@ -164,7 +160,7 @@ static const char *const nios2_reg_names[NIOS2_NUM_REGS] = "zero", "at", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", - "et", "bt", "gp", "sp", "fp", "ea", "ba", "ra", + "et", "bt", "gp", "sp", "fp", "ea", "sstatus", "ra", "pc", "status", "estatus", "bstatus", "ienable", "ipending", "cpuid", "ctl6", "exception", @@ -178,7 +174,7 @@ static const char * nios2_register_name (struct gdbarch *gdbarch, int regno) { /* Use mnemonic aliases for GPRs. */ - if (regno >= 0 && regno < NIOS2_NUM_REGS) + if (regno < NIOS2_NUM_REGS) return nios2_reg_names[regno]; else return tdesc_register_name (gdbarch, regno); @@ -209,17 +205,17 @@ static void nios2_extract_return_value (struct gdbarch *gdbarch, struct type *valtype, struct regcache *regcache, gdb_byte *valbuf) { - int len = TYPE_LENGTH (valtype); + int len = valtype->length (); /* 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); } } @@ -230,17 +226,17 @@ static void nios2_store_return_value (struct gdbarch *gdbarch, struct type *valtype, struct regcache *regcache, const gdb_byte *valbuf) { - int len = TYPE_LENGTH (valtype); + int len = valtype->length (); /* 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); } } @@ -253,15 +249,15 @@ nios2_setup_default (struct nios2_unwind_cache *cache) int i; for (i = 0; i < NIOS2_NUM_REGS; i++) - { - /* All registers start off holding their previous values. */ - cache->reg_value[i].reg = i; - cache->reg_value[i].offset = 0; - - /* All registers start off not saved. */ - cache->reg_saved[i].basereg = -1; - cache->reg_saved[i].addr = 0; - } + { + /* All registers start off holding their previous values. */ + cache->reg_value[i].reg = i; + cache->reg_value[i].offset = 0; + + /* All registers start off not saved. */ + cache->reg_saved[i].basereg = -1; + cache->reg_saved[i].addr = 0; + } } /* Initialize the unwind cache. */ @@ -276,112 +272,855 @@ nios2_init_cache (struct nios2_unwind_cache *cache, CORE_ADDR pc) nios2_setup_default (cache); } -/* Helper function to identify when we're in a function epilogue; - that is, the part of the function from the point at which the - stack adjustment is made, to the return or sibcall. On Nios II, - we want to check that the CURRENT_PC is a return-type instruction - and that the previous instruction is a stack adjustment. - START_PC is the beginning of the function in question. */ +/* Read and identify an instruction at PC. If INSNP is non-null, + store the instruction word into that location. Return the opcode + pointer or NULL if the memory couldn't be read or disassembled. */ + +static const struct nios2_opcode * +nios2_fetch_insn (struct gdbarch *gdbarch, CORE_ADDR pc, + unsigned int *insnp) +{ + LONGEST memword; + unsigned long mach = gdbarch_bfd_arch_info (gdbarch)->mach; + unsigned int insn; + + 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; + if (insnp) + *insnp = insn; + return nios2_find_opcode_hash (insn, mach); +} + + +/* Match and disassemble an ADD-type instruction, with 3 register operands. + Returns true on success, and fills in the operand pointers. */ static int -nios2_in_epilogue_p (struct gdbarch *gdbarch, - CORE_ADDR current_pc, - CORE_ADDR start_pc) +nios2_match_add (uint32_t insn, const struct nios2_opcode *op, + unsigned long mach, int *ra, int *rb, int *rc) { - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + int is_r2 = (mach == bfd_mach_nios2r2); - /* There has to be a previous instruction in the function. */ - if (current_pc > start_pc) + 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; +} + +/* Match and disassemble a SUB-type instruction, with 3 register operands. + Returns true on success, and fills in the operand pointers. */ + +static int +nios2_match_sub (uint32_t insn, const struct nios2_opcode *op, + unsigned long mach, int *ra, int *rb, int *rc) +{ + 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; +} + +/* Match and disassemble an ADDI-type instruction, with 2 register operands + and one immediate operand. + Returns true on success, and fills in the operand pointers. */ + +static int +nios2_match_addi (uint32_t insn, const struct nios2_opcode *op, + unsigned long mach, int *ra, int *rb, int *imm) +{ + 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; +} + +/* Match and disassemble an ORHI-type instruction, with 2 register operands + and one unsigned immediate operand. + Returns true on success, and fills in the operand pointers. */ + +static int +nios2_match_orhi (uint32_t insn, const struct nios2_opcode *op, + unsigned long mach, int *ra, int *rb, unsigned int *uimm) +{ + 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; +} + +/* Match and disassemble a STW-type instruction, with 2 register operands + and one immediate operand. + Returns true on success, and fills in the operand pointers. */ - /* Check whether the previous instruction was a stack - adjustment. */ - unsigned int insn - = read_memory_unsigned_integer (current_pc - NIOS2_OPCODE_SIZE, - NIOS2_OPCODE_SIZE, byte_order); +static int +nios2_match_stw (uint32_t insn, const struct nios2_opcode *op, + unsigned long mach, int *ra, int *rb, int *imm) +{ + 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; +} + +/* Match and disassemble a LDW-type instruction, with 2 register operands + and one immediate operand. + Returns true on success, and fills in the operand pointers. */ + +static int +nios2_match_ldw (uint32_t insn, const struct nios2_opcode *op, + unsigned long mach, int *ra, int *rb, int *imm) +{ + 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; +} + +/* Match and disassemble a RDCTL instruction, with 2 register operands. + Returns true on success, and fills in the operand pointers. */ + +static int +nios2_match_rdctl (uint32_t insn, const struct nios2_opcode *op, + unsigned long mach, int *ra, int *rc) +{ + int is_r2 = (mach == bfd_mach_nios2r2); - if ((insn & 0xffc0003c) == 0xdec00004 /* ADDI sp, sp, */ - || (insn & 0xffc1ffff) == 0xdec1883a /* ADD sp, sp, */ - || (insn & 0xffc0003f) == 0xdec00017) /* LDW sp, constant(sp) */ + 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)) { - /* Then check if it's followed by a return or a tail - call. */ - insn = read_memory_unsigned_integer (current_pc, NIOS2_OPCODE_SIZE, - byte_order); - - if (insn == 0xf800283a /* RET */ - || insn == 0xe800083a /* ERET */ - || (insn & 0x07ffffff) == 0x0000683a /* JMP */ - || (insn & 0xffc0003f) == 6) /* BR */ - return 1; + *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; } -/* Implement the in_function_epilogue_p gdbarch method. */ +/* Match and disassemble a POP.N or LDWM instruction. + Returns true on success, and fills in the operand pointers. */ static int -nios2_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc) +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) { - CORE_ADDR func_addr; + int is_r2 = (mach == bfd_mach_nios2r2); - if (find_pc_partial_function (pc, NULL, &func_addr, NULL)) - return nios2_in_epilogue_p (gdbarch, pc, func_addr); + 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. + Returns true on success, and fills in the operand pointers. */ + +enum branch_condition { + branch_none, + branch_eq, + branch_ne, + branch_ge, + branch_geu, + branch_lt, + branch_ltu +}; + +static int +nios2_match_branch (uint32_t insn, const struct nios2_opcode *op, + unsigned long mach, int *ra, int *rb, int *imm, + enum branch_condition *cond) +{ + 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; + } + 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; } -/* Define some instruction patterns supporting wildcard bits via a - mask. */ +/* Match and disassemble a direct jump instruction, with an + unsigned operand. Returns true on success, and fills in the operand + pointer. */ -typedef struct +static int +nios2_match_jmpi (uint32_t insn, const struct nios2_opcode *op, + unsigned long mach, unsigned int *uimm) { - unsigned int insn; - unsigned int mask; -} wild_insn; + 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; +} + +/* Match and disassemble a direct call instruction, with an + unsigned operand. Returns true on success, and fills in the operand + pointer. */ -static const wild_insn profiler_insn[] = +static int +nios2_match_calli (uint32_t insn, const struct nios2_opcode *op, + unsigned long mach, unsigned int *uimm) { - { 0x0010e03a, 0x00000000 }, /* nextpc r8 */ - { 0xf813883a, 0x00000000 }, /* mov r9,ra */ - { 0x02800034, 0x003fffc0 }, /* movhi r10,257 */ - { 0x52800004, 0x003fffc0 }, /* addi r10,r10,-31992 */ - { 0x00000000, 0xffffffc0 }, /* call */ - { 0x483f883a, 0x00000000 } /* mov ra,r9 */ -}; + 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; +} + +/* Match and disassemble an indirect jump instruction, with a + (possibly implicit) register operand. Returns true on success, and fills + in the operand pointer. */ -static const wild_insn irqentry_insn[] = +static int +nios2_match_jmpr (uint32_t insn, const struct nios2_opcode *op, + unsigned long mach, int *ra) { - { 0x0031307a, 0x00000000 }, /* rdctl et,estatus */ - { 0xc600004c, 0x00000000 }, /* andi et,et,1 */ - { 0xc0000026, 0x003fffc0 }, /* beq et,zero, */ - { 0x0031313a, 0x00000000 }, /* rdctl et,ipending */ - { 0xc0000026, 0x003fffc0 } /* beq et,zero, */ -}; + 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 + operand. Returns true on success, and fills in the operand pointer. */ -/* Attempt to match SEQUENCE, which is COUNT insns long, at START_PC. */ +static int +nios2_match_callr (uint32_t insn, const struct nios2_opcode *op, + unsigned long mach, int *ra) +{ + 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; +} + +/* Match and disassemble a break instruction, with an unsigned operand. + Returns true on success, and fills in the operand pointer. */ static int -nios2_match_sequence (struct gdbarch *gdbarch, CORE_ADDR start_pc, - const wild_insn *sequence, int count) +nios2_match_break (uint32_t insn, const struct nios2_opcode *op, + unsigned long mach, unsigned int *uimm) { - CORE_ADDR pc = start_pc; - int i; + 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; +} + +/* Match and disassemble a trap instruction, with an unsigned operand. + Returns true on success, and fills in the operand pointer. */ + +static int +nios2_match_trap (uint32_t insn, const struct nios2_opcode *op, + unsigned long mach, unsigned int *uimm) +{ + 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; +} + +/* Helper function to identify when we're in a function epilogue; + that is, the part of the function from the point at which the + stack adjustments are made, to the return or sibcall. + Note that we may have several stack adjustment instructions, and + this function needs to test whether the stack teardown has already + started before current_pc, not whether it has completed. */ + +static int +nios2_in_epilogue_p (struct gdbarch *gdbarch, + CORE_ADDR current_pc, + 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. */ + int ninsns, max_insns = 5; unsigned int insn; - enum bfd_endian byte_order = gdbarch_byte_order (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; + + /* There has to be a previous instruction in the function. */ + if (current_pc <= start_pc) + return 0; - for (i = 0 ; i < count ; i++) + /* 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) + SPINCI.N n + LDWSP.N sp, n(sp) + LDWM {reglist}, (sp)++, wb */ + for (ninsns = 0; ninsns < max_insns; ninsns++) { - insn = read_memory_unsigned_integer (pc, NIOS2_OPCODE_SIZE, byte_order); - if ((insn & ~sequence[i].mask) != sequence[i].insn) - return 0; + int ok = 0; - pc += NIOS2_OPCODE_SIZE; + /* Fetch the insn at pc. */ + op = nios2_fetch_insn (gdbarch, pc, &insn); + if (op == NULL) + return 0; + pc += op->size; + + /* Was it a stack adjustment? */ + if (nios2_match_addi (insn, op, mach, &ra, &rb, &imm)) + ok = (rb == NIOS2_SP_REGNUM); + else if (nios2_match_add (insn, op, mach, &ra, &rb, &rc)) + 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; } - return 1; + /* No stack adjustments found. */ + if (ninsns == 0) + return 0; + + /* We found more stack adjustments than we expect GCC to be generating. + Since it looks like a stack unwind might be in progress tell GDB to + treat it as such. */ + if (ninsns == max_insns) + return 1; + + /* The next instruction following the stack adjustments must be a + 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; + + return 0; +} + +/* Implement the stack_frame_destroyed_p gdbarch method. */ + +static int +nios2_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + CORE_ADDR func_addr; + + if (find_pc_partial_function (pc, NULL, &func_addr, NULL)) + return nios2_in_epilogue_p (gdbarch, pc, func_addr); + + return 0; } /* Do prologue analysis, returning the PC of the first instruction @@ -390,92 +1129,74 @@ nios2_match_sequence (struct gdbarch *gdbarch, CORE_ADDR start_pc, interested in skipping the prologue. Otherwise CACHE is filled in from the frame information. - The prologue will consist of the following parts: - 1) Optional profiling instrumentation. The old version uses six - instructions. We step over this if there is an exact match. - nextpc r8 - mov r9, ra - movhi r10, %hiadj(.LP2) - addi r10, r10, %lo(.LP2) - call mcount - mov ra, r9 - The new version uses two or three instructions (the last of - these might get merged in with the STW which saves RA to the - stack). We interpret these. + The prologue may consist of the following parts: + 1) Profiling instrumentation. For non-PIC code it looks like: mov r8, ra call mcount mov ra, r8 - 2) Optional interrupt entry decision. Again, we step over - this if there is an exact match. - rdctl et,estatus - andi et,et,1 - beq et,zero, - rdctl et,ipending - beq et,zero, - - 3) A stack adjustment or stack which, which will be one of: - addi sp, sp, -constant - or: - movi r8, constant - sub sp, sp, r8 - or - movhi r8, constant - addi r8, r8, constant - sub sp, sp, r8 - or + 2) A stack adjustment and save of R4-R7 for varargs functions. + 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. + 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 + in place of a stack adjustment. It looks like: movhi rx, %hiadj(newstack) addhi rx, rx, %lo(newstack) stw sp, constant(rx) mov sp, rx - 4) An optional stack check, which can take either of these forms: + 4) A frame pointer save, which can be either a MOV or ADDI. + + 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 + trap 3 + + Older versions of GCC emitted "break 3" instead of "trap 3" here, + so we check for both cases. - 5) Saving any registers which need to be saved. These will - normally just be stored onto the stack: - stw rx, constant(sp) - but in the large frame case will use r8 as an offset back - to the cfa: - add r8, r8, sp - stw rx, -constant(r8) + 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. - Saving control registers looks slightly different: - rdctl rx, ctlN - stw rx, constant(sp) - - 6) An optional FP setup, either if the user has requested a - frame pointer or if the function calls alloca. - This is always: - mov fp, sp - - The prologue instructions may be interleaved, and the register - saves and FP setup can occur in either order. + The prologue instructions may be combined or interleaved with other + instructions. To cope with all this variability we decode all the instructions - from the start of the prologue until we hit a branch, call or - return. For each of the instructions mentioned in 3, 4 and 5 we - handle the limited cases of stores to the stack and operations - on constant values. */ + from the start of the prologue until we hit an instruction that + cannot possibly be a prologue instruction, such as a branch, call, + return, or epilogue instruction. The prologue is considered to end + at the last instruction that can definitely be considered a + prologue instruction. */ static CORE_ADDR nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc, const CORE_ADDR current_pc, struct nios2_unwind_cache *cache, - struct frame_info *this_frame) + frame_info_ptr this_frame) { - /* Maximum lines of prologue to check. + /* Maximum number of possibly-prologue instructions to check. Note that this number should not be too large, else we can potentially end up iterating through unmapped memory. */ - CORE_ADDR limit_pc = start_pc + 200; - int regno; + int ninsns, max_insns = 50; enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + unsigned long mach = gdbarch_bfd_arch_info (gdbarch)->mach; /* Does the frame set up the FP register? */ int base_reg = 0; @@ -483,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; @@ -496,77 +1215,66 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc, functions which switch stacks? */ CORE_ADDR frame_high; - /* Is this the end of the prologue? */ - int within_prologue = 1; - + /* The last definitely-prologue instruction seen. */ CORE_ADDR prologue_end; /* Is this the innermost function? */ int innermost = (this_frame ? (frame_relative_level (this_frame) == 0) : 1); if (nios2_debug) - fprintf_unfiltered (gdb_stdlog, - "{ nios2_analyze_prologue start=%s, current=%s ", - paddress (gdbarch, start_pc), - paddress (gdbarch, current_pc)); + gdb_printf (gdb_stdlog, + "{ nios2_analyze_prologue start=%s, current=%s ", + paddress (gdbarch, start_pc), + paddress (gdbarch, current_pc)); /* Set up the default values of the registers. */ nios2_setup_default (cache); - /* If the first few instructions are the profile entry, then skip - over them. Newer versions of the compiler use more efficient - profiling code. */ - if (nios2_match_sequence (gdbarch, pc, profiler_insn, - ARRAY_SIZE (profiler_insn))) - pc += ARRAY_SIZE (profiler_insn) * NIOS2_OPCODE_SIZE; - - /* If the first few instructions are an interrupt entry, then skip - over them too. */ - if (nios2_match_sequence (gdbarch, pc, irqentry_insn, - ARRAY_SIZE (irqentry_insn))) - { - pc += ARRAY_SIZE (irqentry_insn) * NIOS2_OPCODE_SIZE; - exception_handler = 1; - } - - prologue_end = start_pc; - /* Find the prologue instructions. */ - while (pc < limit_pc && within_prologue) + prologue_end = start_pc; + for (ninsns = 0; ninsns < max_insns; ninsns++) { /* Present instruction. */ uint32_t insn; - - int prologue_insn = 0; + const struct nios2_opcode *op; + int ra, rb, rc, imm; + unsigned int uimm; + unsigned int reglist; + int wb, id, ret; + enum branch_condition cond; if (pc == current_pc) - { - /* When we reach the current PC we must save the current - register state (for the backtrace) but keep analysing - because there might be more to find out (eg. is this an - exception handler). */ - memcpy (temp_value, value, sizeof (temp_value)); - value = temp_value; - if (nios2_debug) - fprintf_unfiltered (gdb_stdlog, "*"); - } + { + /* When we reach the current PC we must save the current + register state (for the backtrace) but keep analysing + because there might be more to find out (eg. is this an + exception handler). */ + memcpy (temp_value, value, sizeof (temp_value)); + value = temp_value; + if (nios2_debug) + gdb_printf (gdb_stdlog, "*"); + } + + op = nios2_fetch_insn (gdbarch, pc, &insn); - insn = read_memory_unsigned_integer (pc, NIOS2_OPCODE_SIZE, byte_order); - pc += NIOS2_OPCODE_SIZE; + /* Unknown opcode? Stop scanning. */ + if (op == NULL) + break; + pc += op->size; if (nios2_debug) - fprintf_unfiltered (gdb_stdlog, "[%08X]", insn); + { + if (op->size == 2) + gdb_printf (gdb_stdlog, "[%04X]", insn & 0xffff); + else + gdb_printf (gdb_stdlog, "[%08X]", insn); + } /* The following instructions can appear in the prologue. */ - if ((insn & 0x0001ffff) == 0x0001883a) + if (nios2_match_add (insn, op, mach, &ra, &rb, &rc)) { /* ADD rc, ra, rb (also used for MOV) */ - - int ra = GET_IW_A (insn); - int rb = GET_IW_B (insn); - int rc = GET_IW_C (insn); - if (rc == NIOS2_SP_REGNUM && rb == 0 && value[ra].reg == cache->reg_saved[NIOS2_SP_REGNUM].basereg) @@ -577,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; @@ -597,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) @@ -607,18 +1320,22 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc, value[rc].reg = -1; value[rc].offset = value[ra].offset + value[rb].offset; } - prologue_insn = 1; - } - else if ((insn & 0x0001ffff) == 0x0001983a) + /* 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 */ - - int ra = GET_IW_A (insn); - int rb = GET_IW_B (insn); - int rc = GET_IW_C (insn); - - 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; @@ -628,185 +1345,195 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc, } } - else if ((insn & 0x0000003f) == 0x00000004) + else if (nios2_match_addi (insn, op, mach, &ra, &rb, &imm)) { - /* ADDI rb, ra, immed (also used for MOVI) */ - short immed = GET_IW_IMM16 (insn); - int ra = GET_IW_A (insn); - int rb = GET_IW_B (insn); - - /* 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. */ + /* ADDI rb, ra, imm */ + + /* 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) { value[rb].reg = value[ra].reg; - value[rb].offset = value[ra].offset + immed; + value[rb].offset = value[ra].offset + imm; } - prologue_insn = 1; + /* 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 ((insn & 0x0000003f) == 0x00000034) + else if (nios2_match_orhi (insn, op, mach, &ra, &rb, &uimm)) { - /* ORHI rb, ra, immed (also used for MOVHI) */ - unsigned int immed = GET_IW_IMM16 (insn); - int ra = GET_IW_A (insn); - int rb = GET_IW_B (insn); - + /* ORHI rb, ra, uimm (also used for MOVHI) */ if (rb != 0) { - value[rb].reg = (value[ra].reg == 0) ? 0 : -1; - value[rb].offset = value[ra].offset | (immed << 16); + value[rb].reg = (value[ra].reg == 0) ? 0 : -1; + value[rb].offset = value[ra].offset | (uimm << 16); } } - else if ((insn & IW_OP_MASK) == OP_STW - || (insn & IW_OP_MASK) == OP_STWIO) - { - /* STW rb, immediate(ra) */ - - short immed16 = GET_IW_IMM16 (insn); - int ra = GET_IW_A (insn); - int rb = GET_IW_B (insn); + else if (nios2_match_stw (insn, op, mach, &ra, &rb, &imm)) + { + /* STW rb, imm(ra) */ - /* Are we storing the original value of a register? + /* Are we storing the original value of a register to the stack? For exception handlers the value of EA-4 (return address from interrupts etc) is sometimes stored. */ int orig = value[rb].reg; if (orig > 0 && (value[rb].offset == 0 - || (orig == NIOS2_EA_REGNUM && value[rb].offset == -4))) + || (orig == NIOS2_EA_REGNUM && value[rb].offset == -4)) + && value[ra].reg == NIOS2_SP_REGNUM) { - /* We are most interested in stores to the stack, but - also take note of stores to other places as they - might be useful later. */ - if ((value[ra].reg == NIOS2_SP_REGNUM - && cache->reg_saved[orig].basereg != NIOS2_SP_REGNUM) - || cache->reg_saved[orig].basereg == -1) + if (pc < current_pc) { - if (pc < current_pc) - { - /* Save off callee saved registers. */ - cache->reg_saved[orig].basereg = value[ra].reg; - cache->reg_saved[orig].addr - = value[ra].offset + GET_IW_IMM16 (insn); - } - - prologue_insn = 1; - - if (orig == NIOS2_EA_REGNUM || orig == NIOS2_ESTATUS_REGNUM) - exception_handler = 1; + /* Save off callee saved registers. */ + cache->reg_saved[orig].basereg = value[ra].reg; + cache->reg_saved[orig].addr = value[ra].offset + imm; } + + prologue_end = pc; + + if (orig == NIOS2_EA_REGNUM || orig == NIOS2_ESTATUS_REGNUM) + exception_handler = 1; } else - /* Non-stack memory writes are not part of the - prologue. */ - within_prologue = 0; - } + /* Non-stack memory writes cannot appear in the prologue. */ + break; + } - else if ((insn & 0xffc1f83f) == 0x0001303a) + else if (nios2_match_stwm (insn, op, mach, + ®list, &ra, &imm, &wb, &id)) { - /* RDCTL rC, ctlN */ - int rc = GET_IW_C (insn); - int n = GET_IW_CONTROL_REGNUM (insn); + /* 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 + This can appear in exception handlers in combination with + a subsequent save to the stack frame. */ if (rc != 0) { - value[rc].reg = NIOS2_STATUS_REGNUM + n; + value[rc].reg = NIOS2_STATUS_REGNUM + ra; value[rc].offset = 0; } - - prologue_insn = 1; - } - - else if ((insn & 0x0000003f) == 0 - && value[8].reg == NIOS2_RA_REGNUM - && value[8].offset == 0 - && value[NIOS2_SP_REGNUM].reg == NIOS2_SP_REGNUM - && value[NIOS2_SP_REGNUM].offset == 0) - { - /* A CALL instruction. This is treated as a call to mcount - 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++) - value[i].reg = -1; - for (i = 9 ; i <= 15 ; i++) - value[i].reg = -1; - value[NIOS2_RA_REGNUM].reg = -1; - - prologue_insn = 1; } - else if ((insn & 0xf83fffff) == 0xd800012e) + else if (nios2_match_calli (insn, op, mach, &uimm)) { - /* BGEU sp, rx, +8 - BREAK 3 - This instruction sequence is used in stack checking; - we can ignore it. */ - unsigned int next_insn - = read_memory_unsigned_integer (pc, NIOS2_OPCODE_SIZE, byte_order); - - if (next_insn != 0x003da0fa) - within_prologue = 0; - else - pc += NIOS2_OPCODE_SIZE; - } + if (value[8].reg == NIOS2_RA_REGNUM + && value[8].offset == 0 + && value[NIOS2_SP_REGNUM].reg == NIOS2_SP_REGNUM + && value[NIOS2_SP_REGNUM].offset == 0) + { + /* A CALL instruction. This is treated as a call to mcount + 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 (int i = 2 ; i <= 3 ; i++) + value[i].reg = -1; + for (int i = 9 ; i <= 15 ; i++) + value[i].reg = -1; + value[NIOS2_RA_REGNUM].reg = -1; + + prologue_end = pc; + } - else if ((insn & 0xf800003f) == 0xd8000036) - { - /* BLTU sp, rx, .Lstackoverflow - If the location branched to holds a BREAK 3 instruction - then this is also stack overflow detection. We can - ignore it. */ - CORE_ADDR target_pc = pc + ((insn & 0x3fffc0) >> 6); - unsigned int target_insn - = read_memory_unsigned_integer (target_pc, NIOS2_OPCODE_SIZE, - byte_order); - - if (target_insn != 0x003da0fa) - within_prologue = 0; + /* Other calls are not part of the prologue. */ + else + break; } - /* Any other instructions are allowed to be moved up into the - prologue. If we reach a branch, call or return then the - prologue is considered over. We also consider a second stack - adjustment as terminating the prologue (see above). */ - else + else if (nios2_match_branch (insn, op, mach, &ra, &rb, &imm, &cond)) { - switch (GET_IW_OP (insn)) + /* Branches not involving a stack overflow check aren't part of + the prologue. */ + if (ra != NIOS2_SP_REGNUM) + break; + else if (cond == branch_geu) { - case OP_BEQ: - case OP_BGE: - case OP_BGEU: - case OP_BLT: - case OP_BLTU: - case OP_BNE: - case OP_BR: - case OP_CALL: - within_prologue = 0; - break; - case OP_OPX: - if (GET_IW_OPX (insn) == OPX_RET - || GET_IW_OPX (insn) == OPX_ERET - || GET_IW_OPX (insn) == OPX_BRET - || GET_IW_OPX (insn) == OPX_CALLR - || GET_IW_OPX (insn) == OPX_JMP) - within_prologue = 0; - break; - default: - break; + /* BGEU sp, rx, +8 + 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_trap (next_insn, op, mach, &uimm) + || nios2_match_break (next_insn, op, mach, &uimm))) + pc += next_op->size; + else + break; } + else if (cond == branch_ltu) + { + /* BLTU sp, rx, .Lstackoverflow + 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_trap (next_insn, op, mach, &uimm) + || nios2_match_break (next_insn, op, mach, &uimm))) + ; + else + break; + } + else + break; } - if (prologue_insn) - prologue_end = pc; + /* 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_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; } /* If THIS_FRAME is NULL, we are being called from skip_prologue @@ -827,7 +1554,7 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc, cache->return_regnum = NIOS2_EA_REGNUM; if (nios2_debug) - fprintf_unfiltered (gdb_stdlog, "\n-> retreg=%d, ", cache->return_regnum); + gdb_printf (gdb_stdlog, "\n-> retreg=%d, ", cache->return_regnum); if (cache->reg_value[NIOS2_FP_REGNUM].reg == NIOS2_SP_REGNUM) /* If the FP now holds an offset from the CFA then this is a @@ -844,7 +1571,7 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc, /* Somehow the stack pointer has been corrupted. We can't return. */ if (nios2_debug) - fprintf_unfiltered (gdb_stdlog, " }\n"); + gdb_printf (gdb_stdlog, " }\n"); return 0; } @@ -871,7 +1598,7 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc, if (ra == current_pc) { if (nios2_debug) - fprintf_unfiltered + gdb_printf (gdb_stdlog, ", r%d@r%d+?> }\n", paddress (gdbarch, cache->reg_value[base_reg].offset), @@ -893,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, @@ -933,8 +1660,8 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc, } if (nios2_debug) - fprintf_unfiltered (gdb_stdlog, "cfa=%s }\n", - paddress (gdbarch, cache->cfa)); + gdb_printf (gdb_stdlog, "cfa=%s }\n", + paddress (gdbarch, cache->cfa)); return prologue_end; } @@ -944,7 +1671,6 @@ nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc, static CORE_ADDR nios2_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc) { - CORE_ADDR limit_pc; CORE_ADDR func_addr; struct nios2_unwind_cache cache; @@ -955,10 +1681,10 @@ nios2_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc) if (find_pc_partial_function (start_pc, NULL, &func_addr, NULL)) { CORE_ADDR post_prologue_pc - = skip_prologue_using_sal (gdbarch, func_addr); + = 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.... */ @@ -966,40 +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) { - /* break encoding: 31->27 26->22 21->17 16->11 10->6 5->0 */ - /* 00000 00000 0x1d 0x2d 11111 0x3a */ - /* 00000 00000 11101 101101 11111 111010 */ - /* In bytes: 00000000 00111011 01101111 11111010 */ - /* 0x0 0x3b 0x6f 0xfa */ - static const gdb_byte breakpoint_le[] = {0xfa, 0x6f, 0x3b, 0x0}; - static const gdb_byte breakpoint_be[] = {0x0, 0x3b, 0x6f, 0xfa}; - - enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch); - - *bp_size = 4; - if (gdbarch_byte_order_for_code (gdbarch) == BFD_ENDIAN_BIG) - return breakpoint_be; + unsigned long mach = gdbarch_bfd_arch_info (gdbarch)->mach; + + 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 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. */ @@ -1017,7 +1786,7 @@ nios2_return_value (struct gdbarch *gdbarch, struct value *function, struct type *type, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf) { - if (TYPE_LENGTH (type) > 8) + if (type->length () > 8) return RETURN_VALUE_STRUCT_CONVENTION; if (readbuf) @@ -1028,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) + struct regcache *regcache, CORE_ADDR bp_addr, + int nargs, struct value **args, CORE_ADDR sp, + 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 @@ -1060,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 (args[argnum]->type ()->length (), 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 @@ -1077,19 +1835,17 @@ 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); + struct type *arg_type = check_typedef (arg->type ()); + int len = arg_type->length (); - val = value_contents (arg); + val = arg->contents ().data (); /* Copy the argument to general registers or the stack in - register-sized pieces. Large arguments are split between - registers and stack. */ + register-sized pieces. Large arguments are split between + registers and stack. */ while (len > 0) - { + { int partial_len = (len < 4 ? len : 4); if (argreg <= NIOS2_LAST_ARGREG) @@ -1124,7 +1880,7 @@ nios2_push_dummy_call (struct gdbarch *gdbarch, struct value *function, /* Implement the unwind_pc gdbarch method. */ static CORE_ADDR -nios2_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) +nios2_unwind_pc (struct gdbarch *gdbarch, frame_info_ptr next_frame) { gdb_byte buf[4]; @@ -1132,29 +1888,20 @@ 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. */ static struct nios2_unwind_cache * -nios2_frame_unwind_cache (struct frame_info *this_frame, +nios2_frame_unwind_cache (frame_info_ptr this_frame, void **this_prologue_cache) { 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; @@ -1173,7 +1920,7 @@ nios2_frame_unwind_cache (struct frame_info *this_frame, /* Implement the this_id function for the normal unwinder. */ static void -nios2_frame_this_id (struct frame_info *this_frame, void **this_cache, +nios2_frame_this_id (frame_info_ptr this_frame, void **this_cache, struct frame_id *this_id) { struct nios2_unwind_cache *cache = @@ -1189,7 +1936,7 @@ nios2_frame_this_id (struct frame_info *this_frame, void **this_cache, /* Implement the prev_register function for the normal unwinder. */ static struct value * -nios2_frame_prev_register (struct frame_info *this_frame, void **this_cache, +nios2_frame_prev_register (frame_info_ptr this_frame, void **this_cache, int regnum) { struct nios2_unwind_cache *cache = @@ -1219,7 +1966,7 @@ nios2_frame_prev_register (struct frame_info *this_frame, void **this_cache, for the normal unwinder. */ static CORE_ADDR -nios2_frame_base_address (struct frame_info *this_frame, void **this_cache) +nios2_frame_base_address (frame_info_ptr this_frame, void **this_cache) { struct nios2_unwind_cache *info = nios2_frame_unwind_cache (this_frame, this_cache); @@ -1232,6 +1979,7 @@ nios2_frame_base_address (struct frame_info *this_frame, void **this_cache) static const struct frame_unwind nios2_frame_unwind = { + "nios2 prologue", NORMAL_FRAME, default_frame_unwind_stop_reason, nios2_frame_this_id, @@ -1252,24 +2000,23 @@ static const struct frame_base nios2_frame_base = in the stub unwinder. */ static struct trad_frame_cache * -nios2_stub_frame_cache (struct frame_info *this_frame, void **this_cache) +nios2_stub_frame_cache (frame_info_ptr this_frame, void **this_cache) { CORE_ADDR pc; CORE_ADDR start_addr; 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; /* The return address is in the link register. */ trad_frame_set_reg_realreg (this_trad_cache, - gdbarch_pc_regnum (gdbarch), - NIOS2_RA_REGNUM); + gdbarch_pc_regnum (gdbarch), + NIOS2_RA_REGNUM); /* Frame ID, since it's a frameless / stackless function, no stack space is allocated and SP on entry is the current SP. */ @@ -1286,8 +2033,8 @@ nios2_stub_frame_cache (struct frame_info *this_frame, void **this_cache) /* Implement the this_id function for the stub unwinder. */ static void -nios2_stub_frame_this_id (struct frame_info *this_frame, void **this_cache, - struct frame_id *this_id) +nios2_stub_frame_this_id (frame_info_ptr this_frame, void **this_cache, + struct frame_id *this_id) { struct trad_frame_cache *this_trad_cache = nios2_stub_frame_cache (this_frame, this_cache); @@ -1298,8 +2045,8 @@ nios2_stub_frame_this_id (struct frame_info *this_frame, void **this_cache, /* Implement the prev_register function for the stub unwinder. */ static struct value * -nios2_stub_frame_prev_register (struct frame_info *this_frame, - void **this_cache, int regnum) +nios2_stub_frame_prev_register (frame_info_ptr this_frame, + void **this_cache, int regnum) { struct trad_frame_cache *this_trad_cache = nios2_stub_frame_cache (this_frame, this_cache); @@ -1314,38 +2061,26 @@ nios2_stub_frame_prev_register (struct frame_info *this_frame, static int nios2_stub_frame_sniffer (const struct frame_unwind *self, - struct frame_info *this_frame, void **cache) + frame_info_ptr 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. */ if (target_read_memory (get_frame_pc (this_frame), dummy, 4) != 0) return 1; - if (in_plt_section (pc, NULL)) + if (in_plt_section (pc)) return 1; return 0; } -/* Implement the this_base, this_locals, and this_args hooks - for the stub unwinder. */ - -static CORE_ADDR -nios2_stub_frame_base_address (struct frame_info *this_frame, void **this_cache) -{ - struct trad_frame_cache *this_trad_cache - = nios2_stub_frame_cache (this_frame, this_cache); - - return trad_frame_get_this_base (this_trad_cache); -} - /* Define the data structures for the stub unwinder. */ static const struct frame_unwind nios2_stub_frame_unwind = { + "nios2 stub", NORMAL_FRAME, default_frame_unwind_stop_reason, nios2_stub_frame_this_id, @@ -1354,138 +2089,139 @@ static const struct frame_unwind nios2_stub_frame_unwind = nios2_stub_frame_sniffer }; -static const struct frame_base nios2_stub_frame_base = -{ - &nios2_stub_frame_unwind, - nios2_stub_frame_base_address, - nios2_stub_frame_base_address, - nios2_stub_frame_base_address -}; -/* Helper function to read an instruction at PC. */ - -static unsigned long -nios2_fetch_instruction (struct gdbarch *gdbarch, CORE_ADDR pc) -{ - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - - return read_memory_unsigned_integer (pc, NIOS2_OPCODE_SIZE, byte_order); -} /* Determine where to set a single step breakpoint while considering 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_tdep *tdep = gdbarch_tdep (gdbarch); - unsigned long inst; - int op; - int imm16; + struct gdbarch *gdbarch = regcache->arch (); + nios2_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + unsigned long mach = gdbarch_bfd_arch_info (gdbarch)->mach; + unsigned int insn; + const struct nios2_opcode *op = nios2_fetch_insn (gdbarch, pc, &insn); int ra; int rb; - int ras; - int rbs; - unsigned int rau; - unsigned int rbu; - - inst = nios2_fetch_instruction (gdbarch, pc); - pc += NIOS2_OPCODE_SIZE; - - imm16 = (short) GET_IW_IMM16 (inst); - ra = GET_IW_A (inst); - rb = GET_IW_B (inst); - ras = get_frame_register_signed (frame, ra); - rbs = get_frame_register_signed (frame, rb); - rau = get_frame_register_unsigned (frame, ra); - rbu = get_frame_register_unsigned (frame, rb); - - switch (GET_IW_OP (inst)) - { - case OP_BEQ: - if (ras == rbs) - pc += imm16; - break; - - case OP_BGE: - if (ras >= rbs) - pc += imm16; - break; - - case OP_BGEU: - if (rau >= rbu) - pc += imm16; - break; - - case OP_BLT: - if (ras < rbs) - pc += imm16; - break; - - case OP_BLTU: - if (rau < rbu) - pc += imm16; - break; - - case OP_BNE: - if (ras != rbs) - pc += imm16; - break; - - case OP_BR: - pc += imm16; - break; - - case OP_JMPI: - case OP_CALL: - pc = (pc & 0xf0000000) | (GET_IW_IMM26 (inst) << 2); - break; - - case OP_OPX: - switch (GET_IW_OPX (inst)) + int imm; + unsigned int uimm; + int wb, id, ret; + enum branch_condition cond; + + /* Do something stupid if we can't disassemble the insn at pc. */ + if (op == NULL) + return pc + NIOS2_OPCODE_SIZE; + + if (nios2_match_branch (insn, op, mach, &ra, &rb, &imm, &cond)) + { + 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) { - case OPX_JMP: - case OPX_CALLR: - case OPX_RET: - pc = ras; + case branch_none: + pc += imm; + break; + case branch_eq: + if (ras == rbs) + pc += imm; + break; + case branch_ne: + if (ras != rbs) + pc += imm; + break; + case branch_ge: + if (ras >= rbs) + pc += imm; + break; + case branch_geu: + if (rau >= rbu) + pc += imm; + break; + case branch_lt: + if (ras < rbs) + pc += imm; + break; + case branch_ltu: + if (rau < rbu) + pc += imm; break; - - case OPX_TRAP: - if (tdep->syscall_next_pc != NULL) - return tdep->syscall_next_pc (frame); - default: break; } - break; - default: - break; } + + 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)) + 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_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 (get_current_frame (), op); + } + + else + pc += op->size; + return 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)); + CORE_ADDR next_pc = nios2_get_next_pc (regcache, regcache_read_pc (regcache)); - insert_single_step_breakpoint (gdbarch, aspace, next_pc); - - return 1; + return {next_pc}; } /* Implement the get_longjump_target gdbarch method. */ static int -nios2_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc) +nios2_get_longjmp_target (frame_info_ptr frame, CORE_ADDR *pc) { struct gdbarch *gdbarch = get_frame_arch (frame); - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + nios2_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); CORE_ADDR jb_addr = get_frame_register_unsigned (frame, NIOS2_R4_REGNUM); gdb_byte buf[4]; @@ -1497,15 +2233,49 @@ 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 ()) + { + 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 ()); + 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 * nios2_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) { - struct gdbarch *gdbarch; - struct gdbarch_tdep *tdep; - int register_bytes, i; - struct tdesc_arch_data *tdesc_data = NULL; + int i; + tdesc_arch_data_up tdesc_data; const struct target_desc *tdesc = info.target_desc; if (!tdesc_has_registers (tdesc)) @@ -1527,14 +2297,11 @@ nios2_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) valid_p = 1; for (i = 0; i < NIOS2_NUM_REGS; i++) - valid_p &= tdesc_numbered_register (feature, tdesc_data, i, + valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), i, nios2_reg_names[i]); if (!valid_p) - { - tdesc_data_cleanup (tdesc_data); - return NULL; - } + return NULL; } /* Find a candidate among the list of pre-declared architectures. */ @@ -1544,8 +2311,9 @@ 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)); - gdbarch = gdbarch_alloc (&info, tdep); + gdbarch *gdbarch + = gdbarch_alloc (&info, gdbarch_tdep_up (new nios2_gdbarch_tdep)); + nios2_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); /* longjmp support not enabled by default. */ tdep->jb_pc = -1; @@ -1560,6 +2328,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); @@ -1583,12 +2353,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. */ @@ -1599,6 +2368,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); @@ -1607,21 +2379,18 @@ 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); - if (tdesc_data) - tdesc_use_registers (gdbarch, tdesc, tdesc_data); + if (tdesc_data != nullptr) + tdesc_use_registers (gdbarch, tdesc, std::move (tdesc_data)); return gdbarch; } -extern initialize_file_ftype _initialize_nios2_tdep; /* -Wmissing-prototypes */ - +void _initialize_nios2_tdep (); void -_initialize_nios2_tdep (void) +_initialize_nios2_tdep () { gdbarch_register (bfd_arch_nios2, nios2_gdbarch_init, NULL); initialize_tdesc_nios2 ();