X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Farc-tdep.c;h=4817c623df4d66b834e1dffeab03f9a49f57b5ad;hb=99a5596592eda72c5c60b45cdfabb47e426132d5;hp=7bb93adb3600eeb01df2518df4ee4b779b1aa68d;hpb=fa42dd2e8328560e65c888277ab146810c1763a8;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/arc-tdep.c b/gdb/arc-tdep.c index 7bb93adb36..4817c623df 100644 --- a/gdb/arc-tdep.c +++ b/gdb/arc-tdep.c @@ -1,6 +1,6 @@ -/* Target dependent code for ARC arhitecture, for GDB. +/* Target dependent code for ARC architecture, for GDB. - Copyright 2005-2016 Free Software Foundation, Inc. + Copyright 2005-2019 Free Software Foundation, Inc. Contributed by Synopsys Inc. This file is part of GDB. @@ -28,10 +28,12 @@ #include "gdbcore.h" #include "gdbcmd.h" #include "objfiles.h" +#include "prologue-value.h" #include "trad-frame.h" /* ARC header files. */ #include "opcode/arc.h" +#include "opcodes/arc-dis.h" #include "arc-tdep.h" /* Standard headers. */ @@ -41,8 +43,7 @@ #include "features/arc-v2.c" #include "features/arc-arcompact.c" -/* The frame unwind cache for the ARC. Current structure is a stub, because - it should be filled in during the prologue analysis. */ +/* The frame unwind cache for ARC. */ struct arc_frame_cache { @@ -51,7 +52,35 @@ struct arc_frame_cache frame. */ CORE_ADDR prev_sp; - /* Store addresses for registers saved in prologue. */ + /* Register that is a base for this frame - FP for normal frame, SP for + non-FP frames. */ + int frame_base_reg; + + /* Offset from the previous SP to the current frame base. If GCC uses + `SUB SP,SP,offset` to allocate space for local variables, then it will be + done after setting up a frame pointer, but it still will be considered + part of prologue, therefore SP will be lesser than FP at the end of the + prologue analysis. In this case that would be an offset from old SP to a + new FP. But in case of non-FP frames, frame base is an SP and thus that + would be an offset from old SP to new SP. What is important is that this + is an offset from old SP to a known register, so it can be used to find + old SP. + + Using FP is preferable, when possible, because SP can change in function + body after prologue due to alloca, variadic arguments or other shenanigans. + If that is the case in the caller frame, then PREV_SP will point to SP at + the moment of function call, but it will be different from SP value at the + end of the caller prologue. As a result it will not be possible to + reconstruct caller's frame and go past it in the backtrace. Those things + are unlikely to happen to FP - FP value at the moment of function call (as + stored on stack in callee prologue) is also an FP value at the end of the + caller's prologue. */ + + LONGEST frame_base_offset; + + /* Store addresses for registers saved in prologue. During prologue analysis + GDB stores offsets relatively to "old SP", then after old SP is evaluated, + offsets are replaced with absolute addresses. */ struct trad_frame_saved_reg *saved_regs; }; @@ -59,6 +88,10 @@ struct arc_frame_cache int arc_debug; +/* List of "maintenance print arc" commands. */ + +static struct cmd_list_element *maintenance_print_arc_list = NULL; + /* XML target description features. */ static const char core_v2_feature_name[] = "org.gnu.gdb.arc.core.v2"; @@ -86,7 +119,7 @@ static const char *const core_v2_register_names[] = { "r48", "r49", "r50", "r51", "r52", "r53", "r54", "r55", "r56", "r57", "accl", "acch", - "lp_count", "pcl", + "lp_count", "reserved", "limm", "pcl", }; static const char *const aux_minimal_register_names[] = { @@ -109,9 +142,274 @@ static const char *const core_arcompact_register_names[] = { "r48", "r49", "r50", "r51", "r52", "r53", "r54", "r55", "r56", "r57", "r58", "r59", - "lp_count", "pcl", + "lp_count", "reserved", "limm", "pcl", }; +static char *arc_disassembler_options = NULL; + +/* Functions are sorted in the order as they are used in the + _initialize_arc_tdep (), which uses the same order as gdbarch.h. Static + functions are defined before the first invocation. */ + +/* Returns an unsigned value of OPERAND_NUM in instruction INSN. + For relative branch instructions returned value is an offset, not an actual + branch target. */ + +static ULONGEST +arc_insn_get_operand_value (const struct arc_instruction &insn, + unsigned int operand_num) +{ + switch (insn.operands[operand_num].kind) + { + case ARC_OPERAND_KIND_LIMM: + gdb_assert (insn.limm_p); + return insn.limm_value; + case ARC_OPERAND_KIND_SHIMM: + return insn.operands[operand_num].value; + default: + /* Value in instruction is a register number. */ + struct regcache *regcache = get_current_regcache (); + ULONGEST value; + regcache_cooked_read_unsigned (regcache, + insn.operands[operand_num].value, + &value); + return value; + } +} + +/* Like arc_insn_get_operand_value, but returns a signed value. */ + +static LONGEST +arc_insn_get_operand_value_signed (const struct arc_instruction &insn, + unsigned int operand_num) +{ + switch (insn.operands[operand_num].kind) + { + case ARC_OPERAND_KIND_LIMM: + gdb_assert (insn.limm_p); + /* Convert unsigned raw value to signed one. This assumes 2's + complement arithmetic, but so is the LONG_MIN value from generic + defs.h and that assumption is true for ARC. */ + gdb_static_assert (sizeof (insn.limm_value) == sizeof (int)); + return (((LONGEST) insn.limm_value) ^ INT_MIN) - INT_MIN; + case ARC_OPERAND_KIND_SHIMM: + /* Sign conversion has been done by binutils. */ + return insn.operands[operand_num].value; + default: + /* Value in instruction is a register number. */ + struct regcache *regcache = get_current_regcache (); + LONGEST value; + regcache_cooked_read_signed (regcache, + insn.operands[operand_num].value, + &value); + return value; + } +} + +/* Get register with base address of memory operation. */ + +static int +arc_insn_get_memory_base_reg (const struct arc_instruction &insn) +{ + /* POP_S and PUSH_S have SP as an implicit argument in a disassembler. */ + if (insn.insn_class == PUSH || insn.insn_class == POP) + return ARC_SP_REGNUM; + + gdb_assert (insn.insn_class == LOAD || insn.insn_class == STORE); + + /* Other instructions all have at least two operands: operand 0 is data, + operand 1 is address. Operand 2 is offset from address. However, see + comment to arc_instruction.operands - in some cases, third operand may be + missing, namely if it is 0. */ + gdb_assert (insn.operands_count >= 2); + return insn.operands[1].value; +} + +/* Get offset of a memory operation INSN. */ + +static CORE_ADDR +arc_insn_get_memory_offset (const struct arc_instruction &insn) +{ + /* POP_S and PUSH_S have offset as an implicit argument in a + disassembler. */ + if (insn.insn_class == POP) + return 4; + else if (insn.insn_class == PUSH) + return -4; + + gdb_assert (insn.insn_class == LOAD || insn.insn_class == STORE); + + /* Other instructions all have at least two operands: operand 0 is data, + operand 1 is address. Operand 2 is offset from address. However, see + comment to arc_instruction.operands - in some cases, third operand may be + missing, namely if it is 0. */ + if (insn.operands_count < 3) + return 0; + + CORE_ADDR value = arc_insn_get_operand_value (insn, 2); + /* Handle scaling. */ + if (insn.writeback_mode == ARC_WRITEBACK_AS) + { + /* Byte data size is not valid for AS. Halfword means shift by 1 bit. + Word and double word means shift by 2 bits. */ + gdb_assert (insn.data_size_mode != ARC_SCALING_B); + if (insn.data_size_mode == ARC_SCALING_H) + value <<= 1; + else + value <<= 2; + } + return value; +} + +CORE_ADDR +arc_insn_get_branch_target (const struct arc_instruction &insn) +{ + gdb_assert (insn.is_control_flow); + + /* BI [c]: PC = nextPC + (c << 2). */ + if (insn.insn_class == BI) + { + ULONGEST reg_value = arc_insn_get_operand_value (insn, 0); + return arc_insn_get_linear_next_pc (insn) + (reg_value << 2); + } + /* BIH [c]: PC = nextPC + (c << 1). */ + else if (insn.insn_class == BIH) + { + ULONGEST reg_value = arc_insn_get_operand_value (insn, 0); + return arc_insn_get_linear_next_pc (insn) + (reg_value << 1); + } + /* JLI and EI. */ + /* JLI and EI depend on optional AUX registers. Not supported right now. */ + else if (insn.insn_class == JLI) + { + fprintf_unfiltered (gdb_stderr, + "JLI_S instruction is not supported by the GDB."); + return 0; + } + else if (insn.insn_class == EI) + { + fprintf_unfiltered (gdb_stderr, + "EI_S instruction is not supported by the GDB."); + return 0; + } + /* LEAVE_S: PC = BLINK. */ + else if (insn.insn_class == LEAVE) + { + struct regcache *regcache = get_current_regcache (); + ULONGEST value; + regcache_cooked_read_unsigned (regcache, ARC_BLINK_REGNUM, &value); + return value; + } + /* BBIT0/1, BRcc: PC = currentPC + operand. */ + else if (insn.insn_class == BBIT0 || insn.insn_class == BBIT1 + || insn.insn_class == BRCC) + { + /* Most instructions has branch target as their sole argument. However + conditional brcc/bbit has it as a third operand. */ + CORE_ADDR pcrel_addr = arc_insn_get_operand_value (insn, 2); + + /* Offset is relative to the 4-byte aligned address of the current + instruction, hence last two bits should be truncated. */ + return pcrel_addr + align_down (insn.address, 4); + } + /* B, Bcc, BL, BLcc, LP, LPcc: PC = currentPC + operand. */ + else if (insn.insn_class == BRANCH || insn.insn_class == LOOP) + { + CORE_ADDR pcrel_addr = arc_insn_get_operand_value (insn, 0); + + /* Offset is relative to the 4-byte aligned address of the current + instruction, hence last two bits should be truncated. */ + return pcrel_addr + align_down (insn.address, 4); + } + /* J, Jcc, JL, JLcc: PC = operand. */ + else if (insn.insn_class == JUMP) + { + /* All jumps are single-operand. */ + return arc_insn_get_operand_value (insn, 0); + } + + /* This is some new and unknown instruction. */ + gdb_assert_not_reached ("Unknown branch instruction."); +} + +/* Dump INSN into gdb_stdlog. */ + +static void +arc_insn_dump (const struct arc_instruction &insn) +{ + struct gdbarch *gdbarch = target_gdbarch (); + + arc_print ("Dumping arc_instruction at %s\n", + paddress (gdbarch, insn.address)); + arc_print ("\tlength = %u\n", insn.length); + + if (!insn.valid) + { + arc_print ("\tThis is not a valid ARC instruction.\n"); + return; + } + + arc_print ("\tlength_with_limm = %u\n", insn.length + (insn.limm_p ? 4 : 0)); + arc_print ("\tcc = 0x%x\n", insn.condition_code); + arc_print ("\tinsn_class = %u\n", insn.insn_class); + arc_print ("\tis_control_flow = %i\n", insn.is_control_flow); + arc_print ("\thas_delay_slot = %i\n", insn.has_delay_slot); + + CORE_ADDR next_pc = arc_insn_get_linear_next_pc (insn); + arc_print ("\tlinear_next_pc = %s\n", paddress (gdbarch, next_pc)); + + if (insn.is_control_flow) + { + CORE_ADDR t = arc_insn_get_branch_target (insn); + arc_print ("\tbranch_target = %s\n", paddress (gdbarch, t)); + } + + arc_print ("\tlimm_p = %i\n", insn.limm_p); + if (insn.limm_p) + arc_print ("\tlimm_value = 0x%08x\n", insn.limm_value); + + if (insn.insn_class == STORE || insn.insn_class == LOAD + || insn.insn_class == PUSH || insn.insn_class == POP) + { + arc_print ("\twriteback_mode = %u\n", insn.writeback_mode); + arc_print ("\tdata_size_mode = %u\n", insn.data_size_mode); + arc_print ("\tmemory_base_register = %s\n", + gdbarch_register_name (gdbarch, + arc_insn_get_memory_base_reg (insn))); + /* get_memory_offset returns an unsigned CORE_ADDR, but treat it as a + LONGEST for a nicer representation. */ + arc_print ("\taddr_offset = %s\n", + plongest (arc_insn_get_memory_offset (insn))); + } + + arc_print ("\toperands_count = %u\n", insn.operands_count); + for (unsigned int i = 0; i < insn.operands_count; ++i) + { + int is_reg = (insn.operands[i].kind == ARC_OPERAND_KIND_REG); + + arc_print ("\toperand[%u] = {\n", i); + arc_print ("\t\tis_reg = %i\n", is_reg); + if (is_reg) + arc_print ("\t\tregister = %s\n", + gdbarch_register_name (gdbarch, insn.operands[i].value)); + /* Don't know if this value is signed or not, so print both + representations. This tends to look quite ugly, especially for big + numbers. */ + arc_print ("\t\tunsigned value = %s\n", + pulongest (arc_insn_get_operand_value (insn, i))); + arc_print ("\t\tsigned value = %s\n", + plongest (arc_insn_get_operand_value_signed (insn, i))); + arc_print ("\t}\n"); + } +} + +CORE_ADDR +arc_insn_get_linear_next_pc (const struct arc_instruction &insn) +{ + /* In ARC long immediate is always 4 bytes. */ + return (insn.address + insn.length + (insn.limm_p ? 4 : 0)); +} + /* Implement the "write_pc" gdbarch method. In ARC PC register is a normal register so in most cases setting PC value @@ -149,7 +447,7 @@ static const char *const core_arcompact_register_names[] = { static void arc_write_pc (struct regcache *regcache, CORE_ADDR new_pc) { - struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct gdbarch *gdbarch = regcache->arch (); if (arc_debug) debug_printf ("arc: Writing PC, new value=%s\n", @@ -211,19 +509,6 @@ arc_virtual_frame_pointer (struct gdbarch *gdbarch, CORE_ADDR pc, *offset_ptr = 0; } -/* Implement the "dummy_id" gdbarch method. - - Tear down a dummy frame created by arc_push_dummy_call (). This data has - to be constructed manually from the data in our hand. The stack pointer - and program counter can be obtained from the frame info. */ - -static struct frame_id -arc_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame) -{ - return frame_id_build (get_frame_sp (this_frame), - get_frame_pc (this_frame)); -} - /* Implement the "push_dummy_call" gdbarch method. Stack Frame Layout @@ -294,7 +579,8 @@ arc_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame) static CORE_ADDR arc_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, + struct value **args, CORE_ADDR sp, + function_call_return_method return_method, CORE_ADDR struct_addr) { if (arc_debug) @@ -309,7 +595,7 @@ arc_push_dummy_call (struct gdbarch *gdbarch, struct value *function, value return? If so, struct_addr is the address of the reserved space for the return structure to be written on the stack, and that address is passed to that function as a hidden first argument. */ - if (struct_return) + if (return_method == return_method_struct) { /* Pass the return address in the first argument register. */ regcache_cooked_write_unsigned (regcache, arg_reg, struct_addr); @@ -366,7 +652,7 @@ arc_push_dummy_call (struct gdbarch *gdbarch, struct value *function, /* Note we don't use write_unsigned here, since that would convert the byte order, but we are already in the correct byte order. */ - regcache_cooked_write (regcache, arg_reg, data); + regcache->cooked_write (arg_reg, data); data += ARC_REGISTER_SIZE; total_space -= ARC_REGISTER_SIZE; @@ -430,8 +716,19 @@ arc_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp, CORE_ADDR funaddr, static int arc_cannot_fetch_register (struct gdbarch *gdbarch, int regnum) { - /* Assume that register is readable if it is unknown. */ - return FALSE; + /* Assume that register is readable if it is unknown. LIMM and RESERVED are + not real registers, but specific register numbers. They are available as + regnums to align architectural register numbers with GDB internal regnums, + but they shouldn't appear in target descriptions generated by + GDB-servers. */ + switch (regnum) + { + case ARC_RESERVED_REGNUM: + case ARC_LIMM_REGNUM: + return true; + default: + return false; + } } /* Implement the "cannot_store_register" gdbarch method. */ @@ -439,13 +736,16 @@ arc_cannot_fetch_register (struct gdbarch *gdbarch, int regnum) static int arc_cannot_store_register (struct gdbarch *gdbarch, int regnum) { - /* Assume that register is writable if it is unknown. */ + /* Assume that register is writable if it is unknown. See comment in + arc_cannot_fetch_register about LIMM and RESERVED. */ switch (regnum) { + case ARC_RESERVED_REGNUM: + case ARC_LIMM_REGNUM: case ARC_PCL_REGNUM: - return TRUE; + return true; default: - return FALSE; + return false; } } @@ -557,6 +857,28 @@ arc_store_return_value (struct gdbarch *gdbarch, struct type *type, error (_("arc_store_return_value: type length too large.")); } +/* Implement the "get_longjmp_target" gdbarch method. */ + +static int +arc_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc) +{ + if (arc_debug) + debug_printf ("arc: get_longjmp_target\n"); + + struct gdbarch *gdbarch = get_frame_arch (frame); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int pc_offset = tdep->jb_pc * ARC_REGISTER_SIZE; + gdb_byte buf[ARC_REGISTER_SIZE]; + CORE_ADDR jb_addr = get_frame_register_unsigned (frame, ARC_FIRST_ARG_REGNUM); + + if (target_read_memory (jb_addr + pc_offset, buf, ARC_REGISTER_SIZE)) + return 0; /* Failed to read from memory. */ + + *pc = extract_unsigned_integer (buf, ARC_REGISTER_SIZE, + gdbarch_byte_order (gdbarch)); + return 1; +} + /* Implement the "return_value" gdbarch method. */ static enum return_value_convention @@ -609,6 +931,407 @@ arc_frame_base_address (struct frame_info *this_frame, void **prologue_cache) return (CORE_ADDR) get_frame_register_unsigned (this_frame, ARC_FP_REGNUM); } +/* Helper function that returns valid pv_t for an instruction operand: + either a register or a constant. */ + +static pv_t +arc_pv_get_operand (pv_t *regs, const struct arc_instruction &insn, int operand) +{ + if (insn.operands[operand].kind == ARC_OPERAND_KIND_REG) + return regs[insn.operands[operand].value]; + else + return pv_constant (arc_insn_get_operand_value (insn, operand)); +} + +/* Determine whether the given disassembled instruction may be part of a + function prologue. If it is, the information in the frame unwind cache will + be updated. */ + +static bool +arc_is_in_prologue (struct gdbarch *gdbarch, const struct arc_instruction &insn, + pv_t *regs, struct pv_area *stack) +{ + /* It might be that currently analyzed address doesn't contain an + instruction, hence INSN is not valid. It likely means that address points + to a data, non-initialized memory, or middle of a 32-bit instruction. In + practice this may happen if GDB connects to a remote target that has + non-zeroed memory. GDB would read PC value and would try to analyze + prologue, but there is no guarantee that memory contents at the address + specified in PC is address is a valid instruction. There is not much that + that can be done about that. */ + if (!insn.valid) + return false; + + /* Branch/jump or a predicated instruction. */ + if (insn.is_control_flow || insn.condition_code != ARC_CC_AL) + return false; + + /* Store of some register. May or may not update base address register. */ + if (insn.insn_class == STORE || insn.insn_class == PUSH) + { + /* There is definitely at least one operand - register/value being + stored. */ + gdb_assert (insn.operands_count > 0); + + /* Store at some constant address. */ + if (insn.operands_count > 1 + && insn.operands[1].kind != ARC_OPERAND_KIND_REG) + return false; + + /* Writeback modes: + Mode Address used Writeback value + -------------------------------------------------- + No reg + offset no + A/AW reg + offset reg + offset + AB reg reg + offset + AS reg + (offset << scaling) no + + "PUSH reg" is an alias to "ST.AW reg, [SP, -4]" encoding. However + 16-bit PUSH_S is a distinct instruction encoding, where offset and + base register are implied through opcode. */ + + /* Register with base memory address. */ + int base_reg = arc_insn_get_memory_base_reg (insn); + + /* Address where to write. arc_insn_get_memory_offset returns scaled + value for ARC_WRITEBACK_AS. */ + pv_t addr; + if (insn.writeback_mode == ARC_WRITEBACK_AB) + addr = regs[base_reg]; + else + addr = pv_add_constant (regs[base_reg], + arc_insn_get_memory_offset (insn)); + + if (stack->store_would_trash (addr)) + return false; + + if (insn.data_size_mode != ARC_SCALING_D) + { + /* Find the value being stored. */ + pv_t store_value = arc_pv_get_operand (regs, insn, 0); + + /* What is the size of a the stored value? */ + CORE_ADDR size; + if (insn.data_size_mode == ARC_SCALING_B) + size = 1; + else if (insn.data_size_mode == ARC_SCALING_H) + size = 2; + else + size = ARC_REGISTER_SIZE; + + stack->store (addr, size, store_value); + } + else + { + if (insn.operands[0].kind == ARC_OPERAND_KIND_REG) + { + /* If this is a double store, than write N+1 register as well. */ + pv_t store_value1 = regs[insn.operands[0].value]; + pv_t store_value2 = regs[insn.operands[0].value + 1]; + stack->store (addr, ARC_REGISTER_SIZE, store_value1); + stack->store (pv_add_constant (addr, ARC_REGISTER_SIZE), + ARC_REGISTER_SIZE, store_value2); + } + else + { + pv_t store_value + = pv_constant (arc_insn_get_operand_value (insn, 0)); + stack->store (addr, ARC_REGISTER_SIZE * 2, store_value); + } + } + + /* Is base register updated? */ + if (insn.writeback_mode == ARC_WRITEBACK_A + || insn.writeback_mode == ARC_WRITEBACK_AB) + regs[base_reg] = pv_add_constant (regs[base_reg], + arc_insn_get_memory_offset (insn)); + + return true; + } + else if (insn.insn_class == MOVE) + { + gdb_assert (insn.operands_count == 2); + + /* Destination argument can be "0", so nothing will happen. */ + if (insn.operands[0].kind == ARC_OPERAND_KIND_REG) + { + int dst_regnum = insn.operands[0].value; + regs[dst_regnum] = arc_pv_get_operand (regs, insn, 1); + } + return true; + } + else if (insn.insn_class == SUB) + { + gdb_assert (insn.operands_count == 3); + + /* SUB 0,b,c. */ + if (insn.operands[0].kind != ARC_OPERAND_KIND_REG) + return true; + + int dst_regnum = insn.operands[0].value; + regs[dst_regnum] = pv_subtract (arc_pv_get_operand (regs, insn, 1), + arc_pv_get_operand (regs, insn, 2)); + return true; + } + else if (insn.insn_class == ENTER) + { + /* ENTER_S is a prologue-in-instruction - it saves all callee-saved + registers according to given arguments thus greatly reducing code + size. Which registers will be actually saved depends on arguments. + + ENTER_S {R13-...,FP,BLINK} stores registers in following order: + + new SP -> + BLINK + R13 + R14 + R15 + ... + FP + old SP -> + + There are up to three arguments for this opcode, as presented by ARC + disassembler: + 1) amount of general-purpose registers to be saved - this argument is + always present even when it is 0; + 2) FP register number (27) if FP has to be stored, otherwise argument + is not present; + 3) BLINK register number (31) if BLINK has to be stored, otherwise + argument is not present. If both FP and BLINK are stored, then FP + is present before BLINK in argument list. */ + gdb_assert (insn.operands_count > 0); + + int regs_saved = arc_insn_get_operand_value (insn, 0); + + bool is_fp_saved; + if (insn.operands_count > 1) + is_fp_saved = (insn.operands[1].value == ARC_FP_REGNUM); + else + is_fp_saved = false; + + bool is_blink_saved; + if (insn.operands_count > 1) + is_blink_saved = (insn.operands[insn.operands_count - 1].value + == ARC_BLINK_REGNUM); + else + is_blink_saved = false; + + /* Amount of bytes to be allocated to store specified registers. */ + CORE_ADDR st_size = ((regs_saved + is_fp_saved + is_blink_saved) + * ARC_REGISTER_SIZE); + pv_t new_sp = pv_add_constant (regs[ARC_SP_REGNUM], -st_size); + + /* Assume that if the last register (closest to new SP) can be written, + then it is possible to write all of them. */ + if (stack->store_would_trash (new_sp)) + return false; + + /* Current store address. */ + pv_t addr = regs[ARC_SP_REGNUM]; + + if (is_fp_saved) + { + addr = pv_add_constant (addr, -ARC_REGISTER_SIZE); + stack->store (addr, ARC_REGISTER_SIZE, regs[ARC_FP_REGNUM]); + } + + /* Registers are stored in backward order: from GP (R26) to R13. */ + for (int i = ARC_R13_REGNUM + regs_saved - 1; i >= ARC_R13_REGNUM; i--) + { + addr = pv_add_constant (addr, -ARC_REGISTER_SIZE); + stack->store (addr, ARC_REGISTER_SIZE, regs[i]); + } + + if (is_blink_saved) + { + addr = pv_add_constant (addr, -ARC_REGISTER_SIZE); + stack->store (addr, ARC_REGISTER_SIZE, + regs[ARC_BLINK_REGNUM]); + } + + gdb_assert (pv_is_identical (addr, new_sp)); + + regs[ARC_SP_REGNUM] = new_sp; + + if (is_fp_saved) + regs[ARC_FP_REGNUM] = regs[ARC_SP_REGNUM]; + + return true; + } + + /* Some other architectures, like nds32 or arm, try to continue as far as + possible when building a prologue cache (as opposed to when skipping + prologue), so that cache will be as full as possible. However current + code for ARC doesn't recognize some instructions that may modify SP, like + ADD, AND, OR, etc, hence there is no way to guarantee that SP wasn't + clobbered by the skipped instruction. Potential existence of extension + instruction, which may do anything they want makes this even more complex, + so it is just better to halt on a first unrecognized instruction. */ + + return false; +} + +/* Copy of gdb_buffered_insn_length_fprintf from disasm.c. */ + +static int ATTRIBUTE_PRINTF (2, 3) +arc_fprintf_disasm (void *stream, const char *format, ...) +{ + return 0; +} + +struct disassemble_info +arc_disassemble_info (struct gdbarch *gdbarch) +{ + struct disassemble_info di; + init_disassemble_info (&di, &null_stream, arc_fprintf_disasm); + di.arch = gdbarch_bfd_arch_info (gdbarch)->arch; + di.mach = gdbarch_bfd_arch_info (gdbarch)->mach; + di.endian = gdbarch_byte_order (gdbarch); + di.read_memory_func = [](bfd_vma memaddr, gdb_byte *myaddr, + unsigned int len, struct disassemble_info *info) + { + return target_read_code (memaddr, myaddr, len); + }; + return di; +} + +/* Analyze the prologue and update the corresponding frame cache for the frame + unwinder for unwinding frames that doesn't have debug info. In such + situation GDB attempts to parse instructions in the prologue to understand + where each register is saved. + + If CACHE is not NULL, then it will be filled with information about saved + registers. + + There are several variations of prologue which GDB may encounter. "Full" + prologue looks like this: + + sub sp,sp, ; Space for variadic arguments. + push blink ; Store return address. + push r13 ; Store callee saved registers (up to R26/GP). + push r14 + push fp ; Store frame pointer. + mov fp,sp ; Update frame pointer. + sub sp,sp, ; Create space for local vars on the stack. + + Depending on compiler options lots of things may change: + + 1) BLINK is not saved in leaf functions. + 2) Frame pointer is not saved and updated if -fomit-frame-pointer is used. + 3) 16-bit versions of those instructions may be used. + 4) Instead of a sequence of several push'es, compiler may instead prefer to + do one subtract on stack pointer and then store registers using normal + store, that doesn't update SP. Like this: + + + sub sp,sp,8 ; Create space for callee-saved registers. + st r13,[sp,4] ; Store callee saved registers (up to R26/GP). + st r14,[sp,0] + + 5) ENTER_S instruction can encode most of prologue sequence in one + instruction (except for those subtracts for variadic arguments and local + variables). + 6) GCC may use "millicode" functions from libgcc to store callee-saved + registers with minimal code-size requirements. This function currently + doesn't support this. + + ENTRYPOINT is a function entry point where prologue starts. + + LIMIT_PC is a maximum possible end address of prologue (meaning address + of first instruction after the prologue). It might also point to the middle + of prologue if execution has been stopped by the breakpoint at this address + - in this case debugger should analyze prologue only up to this address, + because further instructions haven't been executed yet. + + Returns address of the first instruction after the prologue. */ + +static CORE_ADDR +arc_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR entrypoint, + const CORE_ADDR limit_pc, struct arc_frame_cache *cache) +{ + if (arc_debug) + debug_printf ("arc: analyze_prologue (entrypoint=%s, limit_pc=%s)\n", + paddress (gdbarch, entrypoint), + paddress (gdbarch, limit_pc)); + + /* Prologue values. Only core registers can be stored. */ + pv_t regs[ARC_LAST_CORE_REGNUM + 1]; + for (int i = 0; i <= ARC_LAST_CORE_REGNUM; i++) + regs[i] = pv_register (i, 0); + pv_area stack (ARC_SP_REGNUM, gdbarch_addr_bit (gdbarch)); + + CORE_ADDR current_prologue_end = entrypoint; + + /* Look at each instruction in the prologue. */ + while (current_prologue_end < limit_pc) + { + struct arc_instruction insn; + struct disassemble_info di = arc_disassemble_info (gdbarch); + arc_insn_decode (current_prologue_end, &di, arc_delayed_print_insn, + &insn); + + if (arc_debug >= 2) + arc_insn_dump (insn); + + /* If this instruction is in the prologue, fields in the cache will be + updated, and the saved registers mask may be updated. */ + if (!arc_is_in_prologue (gdbarch, insn, regs, &stack)) + { + /* Found an instruction that is not in the prologue. */ + if (arc_debug) + debug_printf ("arc: End of prologue reached at address %s\n", + paddress (gdbarch, insn.address)); + break; + } + + current_prologue_end = arc_insn_get_linear_next_pc (insn); + } + + if (cache != NULL) + { + /* Figure out if it is a frame pointer or just a stack pointer. */ + if (pv_is_register (regs[ARC_FP_REGNUM], ARC_SP_REGNUM)) + { + cache->frame_base_reg = ARC_FP_REGNUM; + cache->frame_base_offset = -regs[ARC_FP_REGNUM].k; + } + else + { + cache->frame_base_reg = ARC_SP_REGNUM; + cache->frame_base_offset = -regs[ARC_SP_REGNUM].k; + } + + /* Assign offset from old SP to all saved registers. */ + for (int i = 0; i <= ARC_LAST_CORE_REGNUM; i++) + { + CORE_ADDR offset; + if (stack.find_reg (gdbarch, i, &offset)) + cache->saved_regs[i].addr = offset; + } + } + + return current_prologue_end; +} + +/* Estimated maximum prologue length in bytes. This should include: + 1) Store instruction for each callee-saved register (R25 - R13 + 1) + 2) Two instructions for FP + 3) One for BLINK + 4) Three substract instructions for SP (for variadic args, for + callee saved regs and for local vars) and assuming that those SUB use + long-immediate (hence double length). + 5) Stores of arguments registers are considered part of prologue too + (R7 - R1 + 1). + This is quite an extreme case, because even with -O0 GCC will collapse first + two SUBs into one and long immediate values are quite unlikely to appear in + this case, but still better to overshoot a bit - prologue analysis will + anyway stop at the first instruction that doesn't fit prologue, so this + limit will be rarely reached. */ + +const static int MAX_PROLOGUE_LENGTH + = 4 * (ARC_R25_REGNUM - ARC_R13_REGNUM + 1 + 2 + 1 + 6 + + ARC_LAST_ARG_REGNUM - ARC_FIRST_ARG_REGNUM + 1); + /* Implement the "skip_prologue" gdbarch method. Skip the prologue for the function at PC. This is done by checking from @@ -638,15 +1361,19 @@ arc_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc) /* No prologue info in symbol table, have to analyze prologue. */ /* Find an upper limit on the function prologue using the debug - information. If the debug information could not be used to provide that - bound, then pass 0 and arc_scan_prologue will estimate value itself. */ + information. If there is no debug information about prologue end, then + skip_prologue_using_sal will return 0. */ CORE_ADDR limit_pc = skip_prologue_using_sal (gdbarch, pc); - /* We don't have a proper analyze_prologue function yet, but its result - should be returned here. Currently GDB will just stop at the first - instruction of function if debug information doesn't have prologue info; - and if there is a debug info about prologue - this code path will not be - taken at all. */ - return (limit_pc == 0 ? pc : limit_pc); + + /* If there is no debug information at all, it is required to give some + semi-arbitrary hard limit on amount of bytes to scan during prologue + analysis. */ + if (limit_pc == 0) + limit_pc = pc + MAX_PROLOGUE_LENGTH; + + /* Find the address of the first instruction after the prologue by scanning + through it - no other information is needed, so pass NULL as a cache. */ + return arc_analyze_prologue (gdbarch, pc, limit_pc, NULL); } /* Implement the "print_insn" gdbarch method. @@ -661,15 +1388,37 @@ arc_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc) that will not print, or `stream` should be different from standard gdb_stdlog. */ -static int +int arc_delayed_print_insn (bfd_vma addr, struct disassemble_info *info) { - int (*print_insn) (bfd_vma, struct disassemble_info *); - /* exec_bfd may be null, if GDB is run without a target BFD file. Opcodes - will handle NULL value gracefully. */ - print_insn = arc_get_disassembler (exec_bfd); - gdb_assert (print_insn != NULL); - return print_insn (addr, info); + /* Standard BFD "machine number" field allows libopcodes disassembler to + distinguish ARC 600, 700 and v2 cores, however v2 encompasses both ARC EM + and HS, which have some difference between. There are two ways to specify + what is the target core: + 1) via the disassemble_info->disassembler_options; + 2) otherwise libopcodes will use private (architecture-specific) ELF + header. + + Using disassembler_options is preferable, because it comes directly from + GDBserver which scanned an actual ARC core identification info. However, + not all GDBservers report core architecture, so as a fallback GDB still + should support analysis of ELF header. The libopcodes disassembly code + uses the section to find the BFD and the BFD to find the ELF header, + therefore this function should set disassemble_info->section properly. + + disassembler_options was already set by non-target specific code with + proper options obtained via gdbarch_disassembler_options (). + + This function might be called multiple times in a sequence, reusing same + disassemble_info. */ + if ((info->disassembler_options == NULL) && (info->section == NULL)) + { + struct obj_section *s = find_pc_section (addr); + if (s != NULL) + info->section = s->the_bfd_section; + } + + return default_print_insn (addr, info); } /* Baremetal breakpoint instructions. @@ -693,9 +1442,7 @@ static const gdb_byte arc_brk_s_le[] = { 0xff, 0x7f }; static const gdb_byte arc_brk_be[] = { 0x25, 0x6f, 0x00, 0x3f }; static const gdb_byte arc_brk_le[] = { 0x6f, 0x25, 0x3f, 0x00 }; -/* Implement the "breakpoint_from_pc" gdbarch method. - - For ARC ELF, breakpoint uses the 16-bit BRK_S instruction, which is 0x7fff +/* For ARC ELF, breakpoint uses the 16-bit BRK_S instruction, which is 0x7fff (little endian) or 0xff7f (big endian). We used to insert BRK_S even instead of 32-bit instructions, which works mostly ok, unless breakpoint is inserted into delay slot instruction. In this case if branch is taken @@ -712,15 +1459,12 @@ static const gdb_byte arc_brk_le[] = { 0x6f, 0x25, 0x3f, 0x00 }; NB: Baremetal GDB uses BRK[_S], while user-space GDB uses TRAP_S. BRK[_S] is much better because it doesn't commit unlike TRAP_S, so it can be set in delay slots; however it cannot be used in user-mode, hence usage of TRAP_S - in GDB for user-space. + in GDB for user-space. */ - PCPTR is a pointer to the PC where we want to place a breakpoint. LENPTR - is a number of bytes used by the breakpoint. Returns the byte sequence of - a breakpoint instruction. */ +/* Implement the "breakpoint_kind_from_pc" gdbarch method. */ -static const gdb_byte * -arc_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, - int *lenptr) +static int +arc_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr) { size_t length_with_limm = gdb_insn_length (gdbarch, *pcptr); @@ -729,55 +1473,60 @@ arc_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, bytes for 32-bit instructions. */ if ((length_with_limm == 4 || length_with_limm == 8) && !arc_mach_is_arc600 (gdbarch)) + return sizeof (arc_brk_le); + else + return sizeof (arc_brk_s_le); +} + +/* Implement the "sw_breakpoint_from_kind" gdbarch method. */ + +static const gdb_byte * +arc_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size) +{ + *size = kind; + + if (kind == sizeof (arc_brk_le)) { - *lenptr = sizeof (arc_brk_le); return ((gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) ? arc_brk_be : arc_brk_le); } else { - *lenptr = sizeof (arc_brk_s_le); return ((gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) ? arc_brk_s_be : arc_brk_s_le); } } -/* Implement the "unwind_pc" gdbarch method. */ +/* Implement the "frame_align" gdbarch method. */ static CORE_ADDR -arc_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) +arc_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp) { - int pc_regnum = gdbarch_pc_regnum (gdbarch); - CORE_ADDR pc = frame_unwind_register_unsigned (next_frame, pc_regnum); - - if (arc_debug) - debug_printf ("arc: unwind PC: %s\n", paddress (gdbarch, pc)); - - return pc; + return align_down (sp, 4); } -/* Implement the "unwind_sp" gdbarch method. */ +/* Dump the frame info. Used for internal debugging only. */ -static CORE_ADDR -arc_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame) +static void +arc_print_frame_cache (struct gdbarch *gdbarch, const char *message, + struct arc_frame_cache *cache, int addresses_known) { - int sp_regnum = gdbarch_sp_regnum (gdbarch); - CORE_ADDR sp = frame_unwind_register_unsigned (next_frame, sp_regnum); - - if (arc_debug) - debug_printf ("arc: unwind SP: %s\n", paddress (gdbarch, sp)); + debug_printf ("arc: frame_info %s\n", message); + debug_printf ("arc: prev_sp = %s\n", paddress (gdbarch, cache->prev_sp)); + debug_printf ("arc: frame_base_reg = %i\n", cache->frame_base_reg); + debug_printf ("arc: frame_base_offset = %s\n", + plongest (cache->frame_base_offset)); - return sp; -} - -/* Implement the "frame_align" gdbarch method. */ - -static CORE_ADDR -arc_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp) -{ - return align_down (sp, 4); + for (int i = 0; i <= ARC_BLINK_REGNUM; i++) + { + if (trad_frame_addr_p (cache->saved_regs, i)) + debug_printf ("arc: saved register %s at %s %s\n", + gdbarch_register_name (gdbarch, i), + (addresses_known) ? "address" : "offset", + paddress (gdbarch, cache->saved_regs[i].addr)); + } } /* Frame unwinder for normal frames. */ @@ -791,12 +1540,11 @@ arc_make_frame_cache (struct frame_info *this_frame) struct gdbarch *gdbarch = get_frame_arch (this_frame); CORE_ADDR block_addr = get_frame_address_in_block (this_frame); - CORE_ADDR prev_pc = get_frame_pc (this_frame); - CORE_ADDR entrypoint, prologue_end; if (find_pc_partial_function (block_addr, NULL, &entrypoint, &prologue_end)) { struct symtab_and_line sal = find_pc_line (entrypoint, 0); + CORE_ADDR prev_pc = get_frame_pc (this_frame); if (sal.line == 0) /* No line info so use current PC. */ prologue_end = prev_pc; @@ -808,18 +1556,42 @@ arc_make_frame_cache (struct frame_info *this_frame) } else { + /* If find_pc_partial_function returned nothing then there is no symbol + information at all for this PC. Currently it is assumed in this case + that current PC is entrypoint to function and try to construct the + frame from that. This is, probably, suboptimal, for example ARM + assumes in this case that program is inside the normal frame (with + frame pointer). ARC, perhaps, should try to do the same. */ entrypoint = get_frame_register_unsigned (this_frame, gdbarch_pc_regnum (gdbarch)); - prologue_end = 0; + prologue_end = entrypoint + MAX_PROLOGUE_LENGTH; } /* Allocate new frame cache instance and space for saved register info. - * FRAME_OBSTACK_ZALLOC will initialize fields to zeroes. */ + FRAME_OBSTACK_ZALLOC will initialize fields to zeroes. */ struct arc_frame_cache *cache = FRAME_OBSTACK_ZALLOC (struct arc_frame_cache); cache->saved_regs = trad_frame_alloc_saved_regs (this_frame); - /* Should call analyze_prologue here, when it will be implemented. */ + arc_analyze_prologue (gdbarch, entrypoint, prologue_end, cache); + + if (arc_debug) + arc_print_frame_cache (gdbarch, "after prologue", cache, false); + + CORE_ADDR unwound_fb = get_frame_register_unsigned (this_frame, + cache->frame_base_reg); + if (unwound_fb == 0) + return cache; + cache->prev_sp = unwound_fb + cache->frame_base_offset; + + for (int i = 0; i <= ARC_LAST_CORE_REGNUM; i++) + { + if (trad_frame_addr_p (cache->saved_regs, i)) + cache->saved_regs[i].addr += cache->prev_sp; + } + + if (arc_debug) + arc_print_frame_cache (gdbarch, "after previous SP found", cache, true); return cache; } @@ -876,9 +1648,6 @@ static struct value * arc_frame_prev_register (struct frame_info *this_frame, void **this_cache, int regnum) { - if (arc_debug) - debug_printf ("arc: frame_prev_register (regnum = %d)\n", regnum); - if (*this_cache == NULL) *this_cache = arc_make_frame_cache (this_frame); struct arc_frame_cache *cache = (struct arc_frame_cache *) (*this_cache); @@ -951,7 +1720,7 @@ static const struct frame_base arc_normal_base = { Returns TRUE if input tdesc was valid and in this case it will assign TDESC and TDESC_DATA output parameters. */ -static int +static bool arc_tdesc_init (struct gdbarch_info info, const struct target_desc **tdesc, struct tdesc_arch_data **tdesc_data) { @@ -977,7 +1746,7 @@ arc_tdesc_init (struct gdbarch_info info, const struct target_desc **tdesc, tag. */ /* Cannot use arc_mach_is_arcv2 (), because gdbarch is not created yet. */ const int is_arcv2 = (info.bfd_arch_info->mach == bfd_mach_arc_arcv2); - int is_reduced_rf; + bool is_reduced_rf; const char *const *core_regs; const char *core_feature_name; @@ -1034,10 +1803,10 @@ arc_tdesc_init (struct gdbarch_info info, const struct target_desc **tdesc, { arc_print (_("Error: ARC v2 target description supplied for " "non-ARCv2 target.\n")); - return FALSE; + return false; } - is_reduced_rf = FALSE; + is_reduced_rf = false; core_feature_name = core_v2_feature_name; core_regs = core_v2_register_names; } @@ -1050,10 +1819,10 @@ arc_tdesc_init (struct gdbarch_info info, const struct target_desc **tdesc, { arc_print (_("Error: ARC v2 target description supplied for " "non-ARCv2 target.\n")); - return FALSE; + return false; } - is_reduced_rf = TRUE; + is_reduced_rf = true; core_feature_name = core_reduced_v2_feature_name; core_regs = core_v2_register_names; } @@ -1067,10 +1836,10 @@ arc_tdesc_init (struct gdbarch_info info, const struct target_desc **tdesc, { arc_print (_("Error: ARCompact target description supplied " "for non-ARCompact target.\n")); - return FALSE; + return false; } - is_reduced_rf = FALSE; + is_reduced_rf = false; core_feature_name = core_arcompact_feature_name; core_regs = core_arcompact_register_names; } @@ -1078,7 +1847,7 @@ arc_tdesc_init (struct gdbarch_info info, const struct target_desc **tdesc, { arc_print (_("Error: Couldn't find core register feature in " "supplied target description.")); - return FALSE; + return false; } } } @@ -1113,11 +1882,11 @@ arc_tdesc_init (struct gdbarch_info info, const struct target_desc **tdesc, arc_print (_("Error: Cannot find required register `%s' in " "feature `%s'.\n"), core_regs[i], core_feature_name); tdesc_data_cleanup (tdesc_data_loc); - return FALSE; + return false; } } - /* Mandatory AUX registeres are intentionally few and are common between + /* Mandatory AUX registers are intentionally few and are common between ARCompact and ARC v2, so same code can be used for both. */ feature = tdesc_find_feature (tdesc_loc, aux_minimal_feature_name); if (feature == NULL) @@ -1125,7 +1894,7 @@ arc_tdesc_init (struct gdbarch_info info, const struct target_desc **tdesc, arc_print (_("Error: Cannot find required feature `%s' in supplied " "target description.\n"), aux_minimal_feature_name); tdesc_data_cleanup (tdesc_data_loc); - return FALSE; + return false; } for (int i = ARC_FIRST_AUX_REGNUM; i <= ARC_LAST_AUX_REGNUM; i++) @@ -1138,14 +1907,42 @@ arc_tdesc_init (struct gdbarch_info info, const struct target_desc **tdesc, "in feature `%s'.\n"), name, tdesc_feature_name (feature)); tdesc_data_cleanup (tdesc_data_loc); - return FALSE; + return false; } } *tdesc = tdesc_loc; *tdesc_data = tdesc_data_loc; - return TRUE; + return true; +} + +/* Implement the type_align gdbarch function. */ + +static ULONGEST +arc_type_align (struct gdbarch *gdbarch, struct type *type) +{ + switch (TYPE_CODE (type)) + { + case TYPE_CODE_PTR: + case TYPE_CODE_FUNC: + case TYPE_CODE_FLAGS: + case TYPE_CODE_INT: + case TYPE_CODE_RANGE: + case TYPE_CODE_FLT: + case TYPE_CODE_ENUM: + case TYPE_CODE_REF: + case TYPE_CODE_RVALUE_REF: + case TYPE_CODE_CHAR: + case TYPE_CODE_BOOL: + case TYPE_CODE_DECFLOAT: + case TYPE_CODE_METHODPTR: + case TYPE_CODE_MEMBERPTR: + type = check_typedef (type); + return std::min (4, TYPE_LENGTH (type)); + default: + return 0; + } } /* Implement the "init" gdbarch method. */ @@ -1162,14 +1959,18 @@ arc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) if (!arc_tdesc_init (info, &tdesc, &tdesc_data)) return NULL; - struct gdbarch *gdbarch = gdbarch_alloc (&info, NULL); + /* Allocate the ARC-private target-dependent information structure, and the + GDB target-independent information structure. */ + struct gdbarch_tdep *tdep = XCNEW (struct gdbarch_tdep); + tdep->jb_pc = -1; /* No longjmp support by default. */ + struct gdbarch *gdbarch = gdbarch_alloc (&info, tdep); /* Data types. */ 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_long_long_align_bit (gdbarch, 32); + set_gdbarch_type_align (gdbarch, arc_type_align); set_gdbarch_float_bit (gdbarch, 32); set_gdbarch_float_format (gdbarch, floatformats_ieee_single); set_gdbarch_double_bit (gdbarch, 64); @@ -1192,7 +1993,6 @@ arc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_ps_regnum (gdbarch, ARC_STATUS32_REGNUM); set_gdbarch_fp0_regnum (gdbarch, -1); /* No FPU registers. */ - set_gdbarch_dummy_id (gdbarch, arc_dummy_id); set_gdbarch_push_dummy_call (gdbarch, arc_push_dummy_call); set_gdbarch_push_dummy_code (gdbarch, arc_push_dummy_code); @@ -1206,7 +2006,8 @@ arc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_skip_prologue (gdbarch, arc_skip_prologue); set_gdbarch_inner_than (gdbarch, core_addr_lessthan); - set_gdbarch_breakpoint_from_pc (gdbarch, arc_breakpoint_from_pc); + set_gdbarch_breakpoint_kind_from_pc (gdbarch, arc_breakpoint_kind_from_pc); + set_gdbarch_sw_breakpoint_from_kind (gdbarch, arc_sw_breakpoint_from_kind); /* On ARC 600 BRK_S instruction advances PC, unlike other ARC cores. */ if (!arc_mach_is_arc600 (gdbarch)) @@ -1214,9 +2015,6 @@ arc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) else set_gdbarch_decr_pc_after_break (gdbarch, 2); - set_gdbarch_unwind_pc (gdbarch, arc_unwind_pc); - set_gdbarch_unwind_sp (gdbarch, arc_unwind_sp); - set_gdbarch_frame_align (gdbarch, arc_frame_align); set_gdbarch_print_insn (gdbarch, arc_delayed_print_insn); @@ -1246,6 +2044,64 @@ arc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) It can override functions set earlier. */ gdbarch_init_osabi (info, gdbarch); + if (tdep->jb_pc >= 0) + set_gdbarch_get_longjmp_target (gdbarch, arc_get_longjmp_target); + + /* Disassembler options. Enforce CPU if it was specified in XML target + description, otherwise use default method of determining CPU (ELF private + header). */ + if (info.target_desc != NULL) + { + const struct bfd_arch_info *tdesc_arch + = tdesc_architecture (info.target_desc); + if (tdesc_arch != NULL) + { + xfree (arc_disassembler_options); + /* FIXME: It is not really good to change disassembler options + behind the scene, because that might override options + specified by the user. However as of now ARC doesn't support + `set disassembler-options' hence this code is the only place + where options are changed. It also changes options for all + existing gdbarches, which also can be problematic, if + arc_gdbarch_init will start reusing existing gdbarch + instances. */ + /* Target description specifies a BFD architecture, which is + different from ARC cpu, as accepted by disassembler (and most + other ARC tools), because cpu values are much more fine grained - + there can be multiple cpu values per single BFD architecture. As + a result this code should translate architecture to some cpu + value. Since there is no info on exact cpu configuration, it is + best to use the most feature-rich CPU, so that disassembler will + recognize all instructions available to the specified + architecture. */ + switch (tdesc_arch->mach) + { + case bfd_mach_arc_arc601: + arc_disassembler_options = xstrdup ("cpu=arc601"); + break; + case bfd_mach_arc_arc600: + arc_disassembler_options = xstrdup ("cpu=arc600"); + break; + case bfd_mach_arc_arc700: + arc_disassembler_options = xstrdup ("cpu=arc700"); + break; + case bfd_mach_arc_arcv2: + /* Machine arcv2 has three arches: ARCv2, EM and HS; where ARCv2 + is treated as EM. */ + if (arc_arch_is_hs (tdesc_arch)) + arc_disassembler_options = xstrdup ("cpu=hs38_linux"); + else + arc_disassembler_options = xstrdup ("cpu=em4_fpuda"); + break; + default: + arc_disassembler_options = NULL; + break; + } + set_gdbarch_disassembler_options (gdbarch, + &arc_disassembler_options); + } + } + tdesc_use_registers (gdbarch, tdesc, tdesc_data); return gdbarch; @@ -1256,11 +2112,38 @@ arc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) static void arc_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file) { - /* Empty for now. */ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + fprintf_unfiltered (file, "arc_dump_tdep: jb_pc = %i\n", tdep->jb_pc); } -/* Suppress warning from -Wmissing-prototypes. */ -extern initialize_file_ftype _initialize_arc_tdep; +/* Wrapper for "maintenance print arc" list of commands. */ + +static void +maintenance_print_arc_command (const char *args, int from_tty) +{ + cmd_show_list (maintenance_print_arc_list, from_tty, ""); +} + +/* This command accepts single argument - address of instruction to + disassemble. */ + +static void +dump_arc_instruction_command (const char *args, int from_tty) +{ + struct value *val; + if (args != NULL && strlen (args) > 0) + val = evaluate_expression (parse_expression (args).get ()); + else + val = access_value_history (0); + record_latest_value (val); + + CORE_ADDR address = value_as_address (val); + struct arc_instruction insn; + struct disassemble_info di = arc_disassemble_info (target_gdbarch ()); + arc_insn_decode (address, &di, arc_delayed_print_insn, &insn); + arc_insn_dump (insn); +} void _initialize_arc_tdep (void) @@ -1272,6 +2155,18 @@ _initialize_arc_tdep (void) /* Register ARC-specific commands with gdb. */ + /* Add root prefix command for "maintenance print arc" commands. */ + add_prefix_cmd ("arc", class_maintenance, maintenance_print_arc_command, + _("ARC-specific maintenance commands for printing GDB " + "internal state."), + &maintenance_print_arc_list, "maintenance print arc ", 0, + &maintenanceprintlist); + + add_cmd ("arc-instruction", class_maintenance, + dump_arc_instruction_command, + _("Dump arc_instruction structure for specified address."), + &maintenance_print_arc_list); + /* Debug internals for ARC GDB. */ add_setshow_zinteger_cmd ("arc", class_maintenance, &arc_debug,