From f64079c1b08b61276aabfa9c1563f508f4f5373f Mon Sep 17 00:00:00 2001 From: Gopi Kumar Bulusu Date: Tue, 12 Aug 2025 09:42:48 +0530 Subject: [PATCH] MicroBlaze: Add microblaze_software_single_step This patch supports native linux port of gdbserver for MicroBlaze * gdb/microblaze-tdep.c: Add microblaze_software_single_step, retained a few useful debug statements added for testing the patch. Signed-off-by: David Holsgrove Signed-off-by: Nathan Rossi Signed-off-by: Mahesh Bodapati Signed-off-by: Gopi Kumar Bulusu --- gdb/microblaze-tdep.c | 128 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 126 insertions(+), 2 deletions(-) diff --git a/gdb/microblaze-tdep.c b/gdb/microblaze-tdep.c index 7b58220871c..b0a84b2fe0f 100644 --- a/gdb/microblaze-tdep.c +++ b/gdb/microblaze-tdep.c @@ -373,6 +373,9 @@ microblaze_unwind_pc (struct gdbarch *gdbarch, const frame_info_ptr &next_frame) gdb_byte buf[4]; CORE_ADDR pc; + microblaze_debug ("microblaze_unwind_pc called\n"); + + frame_unwind_register (next_frame, MICROBLAZE_PC_REGNUM, buf); pc = extract_typed_address (buf, builtin_type (gdbarch)->builtin_func_ptr); /* For sentinel frame, return address is actual PC. For other frames, @@ -380,6 +383,9 @@ microblaze_unwind_pc (struct gdbarch *gdbarch, const frame_info_ptr &next_frame) generate correct return address in CIE. */ if (frame_relative_level (next_frame) >= 0) pc += 8; + + microblaze_debug ("microblaze_unwind_pc returning pc: %x \n", pc); + return pc; } @@ -423,8 +429,13 @@ microblaze_frame_cache (const frame_info_ptr &next_frame, void **this_cache) struct gdbarch *gdbarch = get_frame_arch (next_frame); int rn; - if (*this_cache) + microblaze_debug ("microblaze_frame_cache called.\n"); + + if (*this_cache) { + microblaze_debug ("microblaze_frame_cache: returning cache hit\n"); return (struct microblaze_frame_cache *) *this_cache; + } + cache = microblaze_alloc_frame_cache (); *this_cache = cache; @@ -439,6 +450,8 @@ microblaze_frame_cache (const frame_info_ptr &next_frame, void **this_cache) cache->pc = get_frame_address_in_block (next_frame); + microblaze_debug ("microblaze_frame_cache - returning (pc = %x).\n", cache->pc); + return cache; } @@ -590,7 +603,116 @@ microblaze_stabs_argument_has_addr (struct gdbarch *gdbarch, struct type *type) return (type->length () == 16); } - +long +microblaze_getreg(struct regcache *regcache, int regno) +{ + long regval = 0; + + if (regno >= 0 && regno < MICROBLAZE_NUM_REGS) + { + regval = regcache_raw_get_unsigned(regcache, regno); + } + + return regval; +} + +/* Return next pc values : next in sequence and/or branch/return target */ +static std::vector +microblaze_software_single_step (regcache *regcache) +{ + + gdbarch *arch = regcache->arch (); + + CORE_ADDR pc; + std::vector next_pcs; + long insn; + enum microblaze_instr minstr; + enum microblaze_instr_type insn_type; + short delay_slots; + int imm; + bool isunsignednum; + bool immfound = false; + struct address_candidates + { + CORE_ADDR address; + bool valid; + } candidates [2]; + + /* Get instruction */ + pc = regcache_read_pc (regcache); + insn = microblaze_fetch_instruction (pc); + minstr = get_insn_microblaze (insn, &isunsignednum, &insn_type, &delay_slots); + /* If the current instruction is an imm, look at the inst after */ + if (insn_type == immediate_inst) + { + int rd, ra, rb; + immfound = true; + minstr = microblaze_decode_insn (insn, &rd, &ra, &rb, &imm); + pc = pc + INST_WORD_SIZE; + insn = microblaze_fetch_instruction (pc); + minstr = get_insn_microblaze (insn, &isunsignednum, &insn_type, &delay_slots); + } + + candidates[0].valid = (insn_type != return_inst); + + /* Compute next instruction address - skip delay slots if any */ + candidates[0].address = pc + INST_WORD_SIZE + + (delay_slots * INST_WORD_SIZE); + + microblaze_debug ("single-step insn_type=%x pc=%lx insn=%lx\n", + insn_type, pc, insn); + + /* Compute target instruction address for branch or return instruction */ + candidates[1].valid = false; + if (insn_type == branch_inst || insn_type == return_inst) + { + int limm; + int lrd, lra, lrb; + long ra, rb; + bfd_boolean targetvalid; + bfd_boolean unconditionalbranch; + + microblaze_decode_insn(insn, &lrd, &lra, &lrb, &limm); + + ra = microblaze_getreg (regcache, lra); + rb = microblaze_getreg (regcache, lrb); + + candidates[1].address = microblaze_get_target_address ( + insn, immfound, imm, pc, ra, rb, + &targetvalid, &unconditionalbranch); + + microblaze_debug ( + "single-step uncondbr=%d targetvalid=%d target=%lx\n", + unconditionalbranch, targetvalid, candidates[1].address); + + /* Can reach next address ? */ + candidates[0].valid = + candidates[0].valid && (unconditionalbranch == FALSE); + + /* Can reach a distinct (not here) target address ? */ + candidates[1].valid = FALSE; + if (targetvalid && + candidates[1].address != pc && + (candidates[0].valid == FALSE || + (candidates[0].address != candidates[1].address))) + { + candidates[1].valid = TRUE; + } + } /* if (branch or return instruction) */ + + /* Create next_pcs vector */ + for (int ci = 0; ci < 2; ci++) + { + if (candidates[ci].valid) + { + next_pcs.push_back (candidates[ci].address); + microblaze_debug ("push_back (%lx)\n", candidates[ci].address); + } + } + + return next_pcs; +} + static int dwarf2_to_reg_map[78] = { 0 /* r0 */, 1 /* r1 */, 2 /* r2 */, 3 /* r3 */, /* 0- 3 */ 4 /* r4 */, 5 /* r5 */, 6 /* r6 */, 7 /* r7 */, /* 4- 7 */ @@ -715,6 +837,8 @@ microblaze_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_sw_breakpoint_from_kind (gdbarch, microblaze_breakpoint::bp_from_kind); + set_gdbarch_software_single_step (gdbarch, microblaze_software_single_step); + set_gdbarch_frame_args_skip (gdbarch, 8); set_gdbarch_unwind_pc (gdbarch, microblaze_unwind_pc); -- 2.47.1