From 5729359001c99ec1c861fde88944926f5fb76ffb Mon Sep 17 00:00:00 2001 From: Stafford Horne Date: Fri, 23 Oct 2020 13:39:53 +0900 Subject: gdb: or1k: add single step for linux native debugging Needed for single stepping in Linux, this adds the or1k implementation of or1k_software_single_step. Most of the implementation is borrowed from the bare metal single step code from or1k_single_step_through_delay which has been extracted and shared in helper function or1k_delay_slot_p. --- gdb/or1k-tdep.c | 66 ++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 19 deletions(-) (limited to 'gdb/or1k-tdep.c') diff --git a/gdb/or1k-tdep.c b/gdb/or1k-tdep.c index 6b0b62d..4c42e02 100644 --- a/gdb/or1k-tdep.c +++ b/gdb/or1k-tdep.c @@ -346,6 +346,33 @@ constexpr gdb_byte or1k_break_insn[] = {0x21, 0x00, 0x00, 0x01}; typedef BP_MANIPULATION (or1k_break_insn) or1k_breakpoint; +static int +or1k_delay_slot_p (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + const CGEN_INSN *insn; + CGEN_FIELDS tmp_fields; + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + insn = cgen_lookup_insn (tdep->gdb_cgen_cpu_desc, + NULL, + or1k_fetch_instruction (gdbarch, pc), + NULL, 32, &tmp_fields, 0); + + /* NULL here would mean the last instruction was not understood by cgen. + This should not usually happen, but if does its not a delay slot. */ + if (insn == NULL) + return 0; + + /* TODO: we should add a delay slot flag to the CGEN_INSN and remove + this hard coded test. */ + return ((CGEN_INSN_NUM (insn) == OR1K_INSN_L_J) + || (CGEN_INSN_NUM (insn) == OR1K_INSN_L_JAL) + || (CGEN_INSN_NUM (insn) == OR1K_INSN_L_JR) + || (CGEN_INSN_NUM (insn) == OR1K_INSN_L_JALR) + || (CGEN_INSN_NUM (insn) == OR1K_INSN_L_BNF) + || (CGEN_INSN_NUM (insn) == OR1K_INSN_L_BF)); +} + /* Implement the single_step_through_delay gdbarch method. */ static int @@ -355,10 +382,7 @@ or1k_single_step_through_delay (struct gdbarch *gdbarch, ULONGEST val; CORE_ADDR ppc; CORE_ADDR npc; - CGEN_FIELDS tmp_fields; - const CGEN_INSN *insn; struct regcache *regcache = get_current_regcache (); - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); /* Get the previous and current instruction addresses. If they are not adjacent, we cannot be in a delay slot. */ @@ -370,24 +394,28 @@ or1k_single_step_through_delay (struct gdbarch *gdbarch, if (0x4 != (npc - ppc)) return 0; - insn = cgen_lookup_insn (tdep->gdb_cgen_cpu_desc, - NULL, - or1k_fetch_instruction (gdbarch, ppc), - NULL, 32, &tmp_fields, 0); + return or1k_delay_slot_p (gdbarch, ppc); +} - /* NULL here would mean the last instruction was not understood by cgen. - This should not usually happen, but if does its not a delay slot. */ - if (insn == NULL) - return 0; +/* or1k_software_single_step() is called just before we want to resume + the inferior, if we want to single-step it but there is no hardware + or kernel single-step support (OpenRISC on GNU/Linux for example). We + find the target of the coming instruction skipping over delay slots + and breakpoint it. */ - /* TODO: we should add a delay slot flag to the CGEN_INSN and remove - this hard coded test. */ - return ((CGEN_INSN_NUM (insn) == OR1K_INSN_L_J) - || (CGEN_INSN_NUM (insn) == OR1K_INSN_L_JAL) - || (CGEN_INSN_NUM (insn) == OR1K_INSN_L_JR) - || (CGEN_INSN_NUM (insn) == OR1K_INSN_L_JALR) - || (CGEN_INSN_NUM (insn) == OR1K_INSN_L_BNF) - || (CGEN_INSN_NUM (insn) == OR1K_INSN_L_BF)); +std::vector +or1k_software_single_step (struct regcache *regcache) +{ + struct gdbarch *gdbarch = regcache->arch (); + CORE_ADDR pc, next_pc; + + pc = regcache_read_pc (regcache); + next_pc = pc + 4; + + if (or1k_delay_slot_p (gdbarch, pc)) + next_pc += 4; + + return {next_pc}; } /* Name for or1k general registers. */ -- cgit v1.1