From 5729359001c99ec1c861fde88944926f5fb76ffb Mon Sep 17 00:00:00 2001 From: Stafford Horne Date: Fri, 23 Oct 2020 13:39:53 +0900 Subject: [PATCH] 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-linux-tdep.c | 2 ++ gdb/or1k-tdep.c | 68 ++++++++++++++++++++++++++++++------------- gdb/or1k-tdep.h | 5 ++++ 3 files changed, 55 insertions(+), 20 deletions(-) diff --git a/gdb/or1k-linux-tdep.c b/gdb/or1k-linux-tdep.c index a71a8202b1e..63c4171e295 100644 --- a/gdb/or1k-linux-tdep.c +++ b/gdb/or1k-linux-tdep.c @@ -154,6 +154,8 @@ or1k_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) /* GNU/Linux uses the dynamic linker included in the GNU C Library. */ set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver); + set_gdbarch_software_single_step (gdbarch, or1k_software_single_step); + /* Enable TLS support. */ set_gdbarch_fetch_tls_load_module_address (gdbarch, svr4_fetch_objfile_link_map); diff --git a/gdb/or1k-tdep.c b/gdb/or1k-tdep.c index 6b0b62d2c47..4c42e0242f3 100644 --- a/gdb/or1k-tdep.c +++ b/gdb/or1k-tdep.c @@ -346,33 +346,16 @@ constexpr gdb_byte or1k_break_insn[] = {0x21, 0x00, 0x00, 0x01}; typedef BP_MANIPULATION (or1k_break_insn) or1k_breakpoint; -/* Implement the single_step_through_delay gdbarch method. */ - static int -or1k_single_step_through_delay (struct gdbarch *gdbarch, - struct frame_info *this_frame) +or1k_delay_slot_p (struct gdbarch *gdbarch, CORE_ADDR pc) { - ULONGEST val; - CORE_ADDR ppc; - CORE_ADDR npc; - CGEN_FIELDS tmp_fields; const CGEN_INSN *insn; - struct regcache *regcache = get_current_regcache (); + CGEN_FIELDS tmp_fields; 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. */ - regcache_cooked_read_unsigned (regcache, OR1K_PPC_REGNUM, &val); - ppc = (CORE_ADDR) val; - regcache_cooked_read_unsigned (regcache, OR1K_NPC_REGNUM, &val); - npc = (CORE_ADDR) val; - - if (0x4 != (npc - ppc)) - return 0; - insn = cgen_lookup_insn (tdep->gdb_cgen_cpu_desc, NULL, - or1k_fetch_instruction (gdbarch, ppc), + or1k_fetch_instruction (gdbarch, pc), NULL, 32, &tmp_fields, 0); /* NULL here would mean the last instruction was not understood by cgen. @@ -390,6 +373,51 @@ or1k_single_step_through_delay (struct gdbarch *gdbarch, || (CGEN_INSN_NUM (insn) == OR1K_INSN_L_BF)); } +/* Implement the single_step_through_delay gdbarch method. */ + +static int +or1k_single_step_through_delay (struct gdbarch *gdbarch, + struct frame_info *this_frame) +{ + ULONGEST val; + CORE_ADDR ppc; + CORE_ADDR npc; + struct regcache *regcache = get_current_regcache (); + + /* Get the previous and current instruction addresses. If they are not + adjacent, we cannot be in a delay slot. */ + regcache_cooked_read_unsigned (regcache, OR1K_PPC_REGNUM, &val); + ppc = (CORE_ADDR) val; + regcache_cooked_read_unsigned (regcache, OR1K_NPC_REGNUM, &val); + npc = (CORE_ADDR) val; + + if (0x4 != (npc - ppc)) + return 0; + + return or1k_delay_slot_p (gdbarch, ppc); +} + +/* 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. */ + +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. */ static const char *const or1k_reg_names[OR1K_NUM_REGS] = { diff --git a/gdb/or1k-tdep.h b/gdb/or1k-tdep.h index d9dc1aca3c3..81d902ae49e 100644 --- a/gdb/or1k-tdep.h +++ b/gdb/or1k-tdep.h @@ -52,4 +52,9 @@ #define OR1K_NUM_TAP_RECORDS 8 #define OR1K_FRAME_RED_ZONE_SIZE 2536 +/* Single step based on where the current instruction will take us. */ +extern std::vector or1k_software_single_step + (struct regcache *regcache); + + #endif /* OR1K_TDEP_H */