diff options
Diffstat (limited to 'gdb/nios2-tdep.c')
-rw-r--r-- | gdb/nios2-tdep.c | 2406 |
1 files changed, 0 insertions, 2406 deletions
diff --git a/gdb/nios2-tdep.c b/gdb/nios2-tdep.c deleted file mode 100644 index 130c015..0000000 --- a/gdb/nios2-tdep.c +++ /dev/null @@ -1,2406 +0,0 @@ -/* Target-machine dependent code for Nios II, for GDB. - 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. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#include "extract-store-integer.h" -#include "frame.h" -#include "frame-unwind.h" -#include "frame-base.h" -#include "trad-frame.h" -#include "dwarf2/frame.h" -#include "symtab.h" -#include "inferior.h" -#include "gdbtypes.h" -#include "gdbcore.h" -#include "cli/cli-cmds.h" -#include "osabi.h" -#include "target.h" -#include "dis-asm.h" -#include "regcache.h" -#include "value.h" -#include "symfile.h" -#include "arch-utils.h" -#include "infcall.h" -#include "regset.h" -#include "target-descriptions.h" - -/* To get entry_point_address. */ -#include "objfiles.h" -#include <algorithm> - -/* Nios II specific header. */ -#include "nios2-tdep.h" - -#include "features/nios2.c" - -/* Control debugging information emitted in this file. */ - -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 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; - int offset; -}; - -/* struct reg_saved is used to record that a register value has been saved at - basereg + addr, for basereg >= 0. If basereg < 0, that indicates - that the register is not known to have been saved. Note that when - basereg == NIOS2_Z_REGNUM (that is, r0, which holds value 0), - addr is an absolute address. */ - -struct reg_saved -{ - int basereg; - CORE_ADDR addr; -}; - -struct nios2_unwind_cache -{ - /* The frame's base, optionally used by the high-level debug info. */ - CORE_ADDR base; - - /* The previous frame's inner most stack address. Used as this - frame ID's stack_addr. */ - CORE_ADDR cfa; - - /* The address of the first instruction in this function. */ - CORE_ADDR pc; - - /* Which register holds the return address for the frame. */ - int return_regnum; - - /* Table indicating what changes have been made to each register. */ - struct reg_value reg_value[NIOS2_NUM_REGS]; - - /* Table indicating where each register has been saved. */ - struct reg_saved reg_saved[NIOS2_NUM_REGS]; -}; - - -/* This array is a mapping from Dwarf-2 register numbering to GDB's. */ - -static int nios2_dwarf2gdb_regno_map[] = -{ - 0, 1, 2, 3, - 4, 5, 6, 7, - 8, 9, 10, 11, - 12, 13, 14, 15, - 16, 17, 18, 19, - 20, 21, 22, 23, - 24, 25, - NIOS2_GP_REGNUM, /* 26 */ - NIOS2_SP_REGNUM, /* 27 */ - NIOS2_FP_REGNUM, /* 28 */ - NIOS2_EA_REGNUM, /* 29 */ - NIOS2_BA_REGNUM, /* 30 */ - NIOS2_RA_REGNUM, /* 31 */ - NIOS2_PC_REGNUM, /* 32 */ - NIOS2_STATUS_REGNUM, /* 33 */ - NIOS2_ESTATUS_REGNUM, /* 34 */ - NIOS2_BSTATUS_REGNUM, /* 35 */ - NIOS2_IENABLE_REGNUM, /* 36 */ - NIOS2_IPENDING_REGNUM, /* 37 */ - NIOS2_CPUID_REGNUM, /* 38 */ - 39, /* CTL6 */ /* 39 */ - NIOS2_EXCEPTION_REGNUM, /* 40 */ - NIOS2_PTEADDR_REGNUM, /* 41 */ - NIOS2_TLBACC_REGNUM, /* 42 */ - NIOS2_TLBMISC_REGNUM, /* 43 */ - NIOS2_ECCINJ_REGNUM, /* 44 */ - NIOS2_BADADDR_REGNUM, /* 45 */ - NIOS2_CONFIG_REGNUM, /* 46 */ - NIOS2_MPUBASE_REGNUM, /* 47 */ - 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) - return -1; - - return nios2_dwarf2gdb_regno_map[dw_reg]; -} - -/* Canonical names for the 49 registers. */ - -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", "sstatus", "ra", - "pc", - "status", "estatus", "bstatus", "ienable", - "ipending", "cpuid", "ctl6", "exception", - "pteaddr", "tlbacc", "tlbmisc", "eccinj", - "badaddr", "config", "mpubase", "mpuacc" -}; - -/* Implement the register_name gdbarch method. */ - -static const char * -nios2_register_name (struct gdbarch *gdbarch, int regno) -{ - /* Use mnemonic aliases for GPRs. */ - if (regno < NIOS2_NUM_REGS) - return nios2_reg_names[regno]; - else - return tdesc_register_name (gdbarch, regno); -} - -/* Implement the register_type gdbarch method. */ - -static struct type * -nios2_register_type (struct gdbarch *gdbarch, int regno) -{ - /* If the XML description has register information, use that to - determine the register type. */ - if (tdesc_has_registers (gdbarch_target_desc (gdbarch))) - return tdesc_register_type (gdbarch, regno); - - if (regno == NIOS2_PC_REGNUM) - return builtin_type (gdbarch)->builtin_func_ptr; - else if (regno == NIOS2_SP_REGNUM) - return builtin_type (gdbarch)->builtin_data_ptr; - else - return builtin_type (gdbarch)->builtin_uint32; -} - -/* Given a return value in REGCACHE with a type VALTYPE, - extract and copy its value into VALBUF. */ - -static void -nios2_extract_return_value (struct gdbarch *gdbarch, struct type *valtype, - struct regcache *regcache, gdb_byte *valbuf) -{ - 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 (NIOS2_R2_REGNUM, valbuf); - else - { - gdb_assert (len <= (register_size (gdbarch, NIOS2_R2_REGNUM) - + register_size (gdbarch, NIOS2_R3_REGNUM))); - regcache->cooked_read (NIOS2_R2_REGNUM, valbuf); - regcache->cooked_read (NIOS2_R3_REGNUM, valbuf + 4); - } -} - -/* Write into appropriate registers a function return value - of type TYPE, given in virtual format. */ - -static void -nios2_store_return_value (struct gdbarch *gdbarch, struct type *valtype, - struct regcache *regcache, const gdb_byte *valbuf) -{ - 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 (NIOS2_R2_REGNUM, valbuf); - else - { - gdb_assert (len <= (register_size (gdbarch, NIOS2_R2_REGNUM) - + register_size (gdbarch, NIOS2_R3_REGNUM))); - regcache->cooked_write (NIOS2_R2_REGNUM, valbuf); - regcache->cooked_write (NIOS2_R3_REGNUM, valbuf + 4); - } -} - - -/* Set up the default values of the registers. */ - -static void -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; - } -} - -/* Initialize the unwind cache. */ - -static void -nios2_init_cache (struct nios2_unwind_cache *cache, CORE_ADDR pc) -{ - cache->base = 0; - cache->cfa = 0; - cache->pc = pc; - cache->return_regnum = NIOS2_RA_REGNUM; - nios2_setup_default (cache); -} - -/* 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_match_add (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_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. */ - -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 (!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. - 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; -} - -/* Match and disassemble a direct jump instruction, with an - unsigned operand. Returns true on success, and fills in the operand - pointer. */ - -static int -nios2_match_jmpi (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_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 int -nios2_match_calli (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_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 int -nios2_match_jmpr (uint32_t insn, const struct nios2_opcode *op, - unsigned long mach, int *ra) -{ - 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. */ - -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_break (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_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; - 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; - - /* 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++) - { - int ok = 0; - - /* 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; - } - - /* 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 - after the function prologue. Assumes CACHE has already been - initialized. THIS_FRAME can be null, in which case we are only - interested in skipping the prologue. Otherwise CACHE is filled in - from the frame information. - - 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) 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) 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 - trap 3 - or - bltu sp, rx, .Lstack_overflow - ... - .Lstack_overflow: - 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. - - To cope with all this variability we decode all the instructions - 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, - const frame_info_ptr &this_frame) -{ - /* 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. */ - 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; - - struct reg_value *value = cache->reg_value; - struct reg_value temp_value[NIOS2_NUM_REGS]; - - /* Save the starting PC so we can correct the pc after running - through the prolog, using symbol info. */ - CORE_ADDR pc = start_pc; - - /* Is this an exception handler? */ - int exception_handler = 0; - - /* What was the original value of SP (or fake original value for - functions which switch stacks? */ - CORE_ADDR frame_high; - - /* 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) - 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); - - /* Find the prologue instructions. */ - prologue_end = start_pc; - for (ninsns = 0; ninsns < max_insns; ninsns++) - { - /* Present instruction. */ - uint32_t insn; - 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) - gdb_printf (gdb_stdlog, "*"); - } - - op = nios2_fetch_insn (gdbarch, pc, &insn); - - /* Unknown opcode? Stop scanning. */ - if (op == NULL) - break; - pc += op->size; - - if (nios2_debug) - { - 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 (nios2_match_add (insn, op, mach, &ra, &rb, &rc)) - { - /* ADD rc, ra, rb (also used for MOV) */ - if (rc == NIOS2_SP_REGNUM - && rb == 0 - && value[ra].reg == cache->reg_saved[NIOS2_SP_REGNUM].basereg) - { - /* If the previous value of SP is available somewhere - near the new stack pointer value then this is a - stack switch. */ - - /* If any registers were saved on the stack before then - we can't backtrace into them now. */ - for (int i = 0 ; i < NIOS2_NUM_REGS ; i++) - { - if (cache->reg_saved[i].basereg == NIOS2_SP_REGNUM) - cache->reg_saved[i].basereg = -1; - if (value[i].reg == NIOS2_SP_REGNUM) - value[i].reg = -1; - } - - /* Create a fake "high water mark" 4 bytes above where SP - was stored and fake up the registers to be consistent - with that. */ - value[NIOS2_SP_REGNUM].reg = NIOS2_SP_REGNUM; - value[NIOS2_SP_REGNUM].offset - = (value[ra].offset - - cache->reg_saved[NIOS2_SP_REGNUM].addr - - 4); - cache->reg_saved[NIOS2_SP_REGNUM].basereg = NIOS2_SP_REGNUM; - 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) - value[rc].reg = value[ra].reg; - else if (value[ra].reg == 0) - value[rc].reg = value[rb].reg; - else - value[rc].reg = -1; - value[rc].offset = value[ra].offset + value[rb].offset; - } - - /* 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 == 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; - else - value[rc].reg = -1; - value[rc].offset = value[ra].offset - value[rb].offset; - } - } - - else if (nios2_match_addi (insn, op, mach, &ra, &rb, &imm)) - { - /* ADDI rb, ra, imm */ - - /* A positive stack adjustment has to be part of the epilogue. */ - if (rb == 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 + imm; - } - - /* 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)) - { - /* 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 | (uimm << 16); - } - } - - else if (nios2_match_stw (insn, op, mach, &ra, &rb, &imm)) - { - /* STW rb, imm(ra) */ - - /* 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)) - && value[ra].reg == NIOS2_SP_REGNUM) - { - 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 + imm; - } - - prologue_end = pc; - - if (orig == NIOS2_EA_REGNUM || orig == NIOS2_ESTATUS_REGNUM) - exception_handler = 1; - } - else - /* Non-stack memory writes cannot appear in the prologue. */ - 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 - 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 + ra; - value[rc].offset = 0; - } - } - - else if (nios2_match_calli (insn, op, mach, &uimm)) - { - 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; - } - - /* Other calls are not part of the prologue. */ - else - break; - } - - else if (nios2_match_branch (insn, op, mach, &ra, &rb, &imm, &cond)) - { - /* Branches not involving a stack overflow check aren't part of - the prologue. */ - if (ra != NIOS2_SP_REGNUM) - break; - else if (cond == branch_geu) - { - /* 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; - } - - /* 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 - and are only interested in the PROLOGUE_END value, so just - return that now and skip over the cache updates, which depend - on having frame information. */ - if (this_frame == NULL) - return prologue_end; - - /* If we are in the function epilogue and have already popped - registers off the stack in preparation for returning, then we - want to go back to the original register values. */ - if (innermost && nios2_in_epilogue_p (gdbarch, current_pc, start_pc)) - nios2_setup_default (cache); - - /* Exception handlers use a different return address register. */ - if (exception_handler) - cache->return_regnum = NIOS2_EA_REGNUM; - - if (nios2_debug) - 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 - normal frame which uses the frame pointer. */ - base_reg = NIOS2_FP_REGNUM; - else if (cache->reg_value[NIOS2_SP_REGNUM].reg == NIOS2_SP_REGNUM) - /* FP doesn't hold an offset from the CFA. If SP still holds an - offset from the CFA then we might be in a function which omits - the frame pointer, or we might be partway through the prologue. - In both cases we can find the CFA using SP. */ - base_reg = NIOS2_SP_REGNUM; - else - { - /* Somehow the stack pointer has been corrupted. - We can't return. */ - if (nios2_debug) - gdb_printf (gdb_stdlog, "<can't reach cfa> }\n"); - return 0; - } - - if (cache->reg_value[base_reg].offset == 0 - || cache->reg_saved[NIOS2_RA_REGNUM].basereg != NIOS2_SP_REGNUM - || cache->reg_saved[cache->return_regnum].basereg != NIOS2_SP_REGNUM) - { - /* If the frame didn't adjust the stack, didn't save RA or - didn't save EA in an exception handler then it must either - be a leaf function (doesn't call any other functions) or it - can't return. If it has called another function then it - can't be a leaf, so set base == 0 to indicate that we can't - backtrace past it. */ - - if (!innermost) - { - /* If it isn't the innermost function then it can't be a - leaf, unless it was interrupted. Check whether RA for - this frame is the same as PC. If so then it probably - wasn't interrupted. */ - CORE_ADDR ra - = get_frame_register_unsigned (this_frame, NIOS2_RA_REGNUM); - - if (ra == current_pc) - { - if (nios2_debug) - gdb_printf - (gdb_stdlog, - "<noreturn ADJUST %s, r31@r%d+?>, r%d@r%d+?> }\n", - paddress (gdbarch, cache->reg_value[base_reg].offset), - cache->reg_saved[NIOS2_RA_REGNUM].basereg, - cache->return_regnum, - cache->reg_saved[cache->return_regnum].basereg); - return 0; - } - } - } - - /* Get the value of whichever register we are using for the - base. */ - cache->base = get_frame_register_unsigned (this_frame, base_reg); - - /* What was the value of SP at the start of this function (or just - after the stack switch). */ - frame_high = cache->base - cache->reg_value[base_reg].offset; - - /* Adjust all the saved registers such that they contain addresses - instead of offsets. */ - 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 (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, - NIOS2_GP_REGNUM); - - for ( ; i < NIOS2_NUM_REGS; i++) - if (cache->reg_saved[i].basereg == NIOS2_GP_REGNUM) - { - cache->reg_saved[i].basereg = NIOS2_Z_REGNUM; - cache->reg_saved[i].addr += gp; - } - } - - /* Work out what the value of SP was on the first instruction of - this function. If we didn't switch stacks then this can be - trivially computed from the base address. */ - if (cache->reg_saved[NIOS2_SP_REGNUM].basereg == NIOS2_Z_REGNUM) - cache->cfa - = read_memory_unsigned_integer (cache->reg_saved[NIOS2_SP_REGNUM].addr, - 4, byte_order); - else - cache->cfa = frame_high; - - /* Exception handlers restore ESTATUS into STATUS. */ - if (exception_handler) - { - cache->reg_saved[NIOS2_STATUS_REGNUM] - = cache->reg_saved[NIOS2_ESTATUS_REGNUM]; - cache->reg_saved[NIOS2_ESTATUS_REGNUM].basereg = -1; - } - - if (nios2_debug) - gdb_printf (gdb_stdlog, "cfa=%s }\n", - paddress (gdbarch, cache->cfa)); - - return prologue_end; -} - -/* Implement the skip_prologue gdbarch hook. */ - -static CORE_ADDR -nios2_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc) -{ - CORE_ADDR func_addr; - - struct nios2_unwind_cache cache; - - /* See if we can determine the end of the prologue via the symbol - table. If so, then return either PC, or the PC after the - prologue, whichever is greater. */ - if (find_pc_partial_function (start_pc, NULL, &func_addr, NULL)) - { - CORE_ADDR post_prologue_pc - = skip_prologue_using_sal (gdbarch, func_addr); - - if (post_prologue_pc != 0) - return std::max (start_pc, post_prologue_pc); - } - - /* Prologue analysis does the rest.... */ - nios2_init_cache (&cache, start_pc); - return nios2_analyze_prologue (gdbarch, start_pc, start_pc, &cache, NULL); -} - -/* Implement the breakpoint_kind_from_pc gdbarch method. */ - -static int -nios2_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr) -{ - 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 NIOS2_OPCODE_SIZE; -} - -/* Implement the sw_breakpoint_from_kind gdbarch method. */ - -static const gdb_byte * -nios2_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size) -{ -/* 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 - { - 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. */ - -static CORE_ADDR -nios2_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr) -{ - return align_down (addr, 4); -} - - -/* Implement the return_value gdbarch method. */ - -static enum return_value_convention -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 () > 8) - return RETURN_VALUE_STRUCT_CONVENTION; - - if (readbuf) - nios2_extract_return_value (gdbarch, type, regcache, readbuf); - if (writebuf) - nios2_store_return_value (gdbarch, type, regcache, writebuf); - - return RETURN_VALUE_REGISTER_CONVENTION; -} - -/* 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, - function_call_return_method return_method, - CORE_ADDR struct_addr) -{ - int argreg; - int argnum; - int arg_space = 0; - int stack_offset = 0; - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - - /* Set the return address register to point to the entry point of - the program, where a breakpoint lies in wait. */ - regcache_cooked_write_signed (regcache, NIOS2_RA_REGNUM, bp_addr); - - /* Now make space on the stack for the args. */ - for (argnum = 0; argnum < nargs; argnum++) - 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 (return_method == return_method_struct) - regcache_cooked_write_unsigned (regcache, argreg++, struct_addr); - - /* Now load as many as possible of the first arguments into - registers, and push the rest onto the stack. Loop through args - from first to last. */ - for (argnum = 0; argnum < nargs; argnum++) - { - const gdb_byte *val; - struct value *arg = args[argnum]; - struct type *arg_type = check_typedef (arg->type ()); - int len = arg_type->length (); - - 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. */ - while (len > 0) - { - int partial_len = (len < 4 ? len : 4); - - if (argreg <= NIOS2_LAST_ARGREG) - { - /* The argument is being passed in a register. */ - CORE_ADDR regval = extract_unsigned_integer (val, partial_len, - byte_order); - - regcache_cooked_write_unsigned (regcache, argreg, regval); - argreg++; - } - else - { - /* The argument is being passed on the stack. */ - CORE_ADDR addr = sp + stack_offset; - - write_memory (addr, val, partial_len); - stack_offset += align_up (partial_len, 4); - } - - len -= partial_len; - val += partial_len; - } - } - - regcache_cooked_write_signed (regcache, NIOS2_SP_REGNUM, sp); - - /* Return adjusted stack pointer. */ - return sp; -} - -/* Implement the unwind_pc gdbarch method. */ - -static CORE_ADDR -nios2_unwind_pc (struct gdbarch *gdbarch, const frame_info_ptr &next_frame) -{ - gdb_byte buf[4]; - - frame_unwind_register (next_frame, NIOS2_PC_REGNUM, buf); - return extract_typed_address (buf, builtin_type (gdbarch)->builtin_func_ptr); -} - -/* 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 (const 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; - - if (*this_prologue_cache) - return (struct nios2_unwind_cache *) *this_prologue_cache; - - cache = FRAME_OBSTACK_ZALLOC (struct nios2_unwind_cache); - *this_prologue_cache = cache; - - /* Zero all fields. */ - nios2_init_cache (cache, get_frame_func (this_frame)); - - /* Prologue analysis does the rest... */ - current_pc = get_frame_pc (this_frame); - if (cache->pc != 0) - nios2_analyze_prologue (gdbarch, cache->pc, current_pc, cache, this_frame); - - return cache; -} - -/* Implement the this_id function for the normal unwinder. */ - -static void -nios2_frame_this_id (const frame_info_ptr &this_frame, void **this_cache, - struct frame_id *this_id) -{ - struct nios2_unwind_cache *cache = - nios2_frame_unwind_cache (this_frame, this_cache); - - /* This marks the outermost frame. */ - if (cache->base == 0) - return; - - *this_id = frame_id_build (cache->cfa, cache->pc); -} - -/* Implement the prev_register function for the normal unwinder. */ - -static struct value * -nios2_frame_prev_register (const frame_info_ptr &this_frame, void **this_cache, - int regnum) -{ - struct nios2_unwind_cache *cache = - nios2_frame_unwind_cache (this_frame, this_cache); - - gdb_assert (regnum >= 0 && regnum < NIOS2_NUM_REGS); - - /* The PC of the previous frame is stored in the RA register of - the current frame. Frob regnum so that we pull the value from - the correct place. */ - if (regnum == NIOS2_PC_REGNUM) - regnum = cache->return_regnum; - - if (regnum == NIOS2_SP_REGNUM && cache->cfa) - return frame_unwind_got_constant (this_frame, regnum, cache->cfa); - - /* If we've worked out where a register is stored then load it from - there. */ - if (cache->reg_saved[regnum].basereg == NIOS2_Z_REGNUM) - return frame_unwind_got_memory (this_frame, regnum, - cache->reg_saved[regnum].addr); - - return frame_unwind_got_register (this_frame, regnum, regnum); -} - -/* Implement the this_base, this_locals, and this_args hooks - for the normal unwinder. */ - -static CORE_ADDR -nios2_frame_base_address (const frame_info_ptr &this_frame, void **this_cache) -{ - struct nios2_unwind_cache *info - = nios2_frame_unwind_cache (this_frame, this_cache); - - return info->base; -} - -/* Data structures for the normal prologue-analysis-based - unwinder. */ - -static const struct frame_unwind nios2_frame_unwind = -{ - "nios2 prologue", - NORMAL_FRAME, - default_frame_unwind_stop_reason, - nios2_frame_this_id, - nios2_frame_prev_register, - NULL, - default_frame_sniffer -}; - -static const struct frame_base nios2_frame_base = -{ - &nios2_frame_unwind, - nios2_frame_base_address, - nios2_frame_base_address, - nios2_frame_base_address -}; - -/* Fill in the register cache *THIS_CACHE for THIS_FRAME for use - in the stub unwinder. */ - -static struct trad_frame_cache * -nios2_stub_frame_cache (const 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); - - if (*this_cache != NULL) - 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); - - /* Frame ID, since it's a frameless / stackless function, no stack - space is allocated and SP on entry is the current SP. */ - pc = get_frame_pc (this_frame); - find_pc_partial_function (pc, NULL, &start_addr, NULL); - stack_addr = get_frame_register_unsigned (this_frame, NIOS2_SP_REGNUM); - trad_frame_set_id (this_trad_cache, frame_id_build (start_addr, stack_addr)); - /* Assume that the frame's base is the same as the stack pointer. */ - trad_frame_set_this_base (this_trad_cache, stack_addr); - - return this_trad_cache; -} - -/* Implement the this_id function for the stub unwinder. */ - -static void -nios2_stub_frame_this_id (const 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); - - trad_frame_get_id (this_trad_cache, this_id); -} - -/* Implement the prev_register function for the stub unwinder. */ - -static struct value * -nios2_stub_frame_prev_register (const 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); - - return trad_frame_get_register (this_trad_cache, this_frame, regnum); -} - -/* Implement the sniffer function for the stub unwinder. - This unwinder is used for cases where the normal - prologue-analysis-based unwinder can't work, - such as PLT stubs. */ - -static int -nios2_stub_frame_sniffer (const struct frame_unwind *self, - const frame_info_ptr &this_frame, void **cache) -{ - gdb_byte dummy[4]; - 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)) - return 1; - - return 0; -} - -/* 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, - nios2_stub_frame_prev_register, - NULL, - nios2_stub_frame_sniffer -}; - - - -/* Determine where to set a single step breakpoint while considering - branch prediction. */ - -static CORE_ADDR -nios2_get_next_pc (struct regcache *regcache, CORE_ADDR pc) -{ - struct gdbarch *gdbarch = regcache->arch (); - nios2_gdbarch_tdep *tdep = gdbarch_tdep<nios2_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 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 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; - 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 std::vector<CORE_ADDR> -nios2_software_single_step (struct regcache *regcache) -{ - CORE_ADDR next_pc = nios2_get_next_pc (regcache, regcache_read_pc (regcache)); - - return {next_pc}; -} - -/* Implement the get_longjump_target gdbarch method. */ - -static int -nios2_get_longjmp_target (const frame_info_ptr &frame, CORE_ADDR *pc) -{ - struct gdbarch *gdbarch = get_frame_arch (frame); - nios2_gdbarch_tdep *tdep = gdbarch_tdep<nios2_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]; - - if (target_read_memory (jb_addr + (tdep->jb_pc * 4), buf, 4)) - return 0; - - *pc = extract_unsigned_integer (buf, 4, byte_order); - 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<ULONGEST> (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) -{ - int i; - tdesc_arch_data_up tdesc_data; - const struct target_desc *tdesc = info.target_desc; - - if (!tdesc_has_registers (tdesc)) - /* Pick a default target description. */ - tdesc = tdesc_nios2; - - /* Check any target description for validity. */ - if (tdesc_has_registers (tdesc)) - { - const struct tdesc_feature *feature; - int valid_p; - - feature = tdesc_find_feature (tdesc, "org.gnu.gdb.nios2.cpu"); - if (feature == NULL) - return NULL; - - tdesc_data = tdesc_data_alloc (); - - valid_p = 1; - - for (i = 0; i < NIOS2_NUM_REGS; i++) - valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), i, - nios2_reg_names[i]); - - if (!valid_p) - return NULL; - } - - /* Find a candidate among the list of pre-declared architectures. */ - arches = gdbarch_list_lookup_by_info (arches, &info); - if (arches != NULL) - return arches->gdbarch; - - /* None found, create a new architecture from the information - provided. */ - gdbarch *gdbarch - = gdbarch_alloc (&info, gdbarch_tdep_up (new nios2_gdbarch_tdep)); - nios2_gdbarch_tdep *tdep = gdbarch_tdep<nios2_gdbarch_tdep> (gdbarch); - - /* longjmp support not enabled by default. */ - tdep->jb_pc = -1; - - /* Data type sizes. */ - set_gdbarch_ptr_bit (gdbarch, 32); - set_gdbarch_addr_bit (gdbarch, 32); - set_gdbarch_short_bit (gdbarch, 16); - set_gdbarch_int_bit (gdbarch, 32); - set_gdbarch_long_bit (gdbarch, 32); - set_gdbarch_long_long_bit (gdbarch, 64); - 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); - - /* The register set. */ - set_gdbarch_num_regs (gdbarch, NIOS2_NUM_REGS); - set_gdbarch_sp_regnum (gdbarch, NIOS2_SP_REGNUM); - set_gdbarch_pc_regnum (gdbarch, NIOS2_PC_REGNUM); /* Pseudo register PC */ - - set_gdbarch_register_name (gdbarch, nios2_register_name); - set_gdbarch_register_type (gdbarch, nios2_register_type); - - /* Provide register mappings for stabs and dwarf2. */ - set_gdbarch_stab_reg_to_regnum (gdbarch, nios2_dwarf_reg_to_regnum); - set_gdbarch_dwarf2_reg_to_regnum (gdbarch, nios2_dwarf_reg_to_regnum); - - set_gdbarch_inner_than (gdbarch, core_addr_lessthan); - - /* Call dummy code. */ - set_gdbarch_frame_align (gdbarch, nios2_frame_align); - - set_gdbarch_return_value (gdbarch, nios2_return_value); - - set_gdbarch_skip_prologue (gdbarch, nios2_skip_prologue); - 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_unwind_pc (gdbarch, nios2_unwind_pc); - - /* The dwarf2 unwinder will normally produce the best results if - the debug information is available, so register it first. */ - dwarf2_append_unwinders (gdbarch); - frame_unwind_append_unwinder (gdbarch, &nios2_stub_frame_unwind); - frame_unwind_append_unwinder (gdbarch, &nios2_frame_unwind); - - /* 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); - - if (tdep->jb_pc >= 0) - set_gdbarch_get_longjmp_target (gdbarch, nios2_get_longjmp_target); - - frame_base_set_default (gdbarch, &nios2_frame_base); - - /* Enable inferior call support. */ - set_gdbarch_push_dummy_call (gdbarch, nios2_push_dummy_call); - - if (tdesc_data != nullptr) - tdesc_use_registers (gdbarch, tdesc, std::move (tdesc_data)); - - return gdbarch; -} - -void _initialize_nios2_tdep (); -void -_initialize_nios2_tdep () -{ - gdbarch_register (bfd_arch_nios2, nios2_gdbarch_init, NULL); - initialize_tdesc_nios2 (); - - /* Allow debugging this file's internals. */ - add_setshow_boolean_cmd ("nios2", class_maintenance, &nios2_debug, - _("Set Nios II debugging."), - _("Show Nios II debugging."), - _("When on, Nios II specific debugging is enabled."), - NULL, - NULL, - &setdebuglist, &showdebuglist); -} |