diff options
author | Thiago Jung Bauermann <thiago.bauermann@linaro.org> | 2024-04-27 18:38:22 -0300 |
---|---|---|
committer | Thiago Jung Bauermann <thiago.bauermann@linaro.org> | 2024-05-03 00:26:23 -0300 |
commit | 35f398e1765eb07e4c790317f50fdd72933e2b38 (patch) | |
tree | 5cab49b303dabb3e326b10ee58620229eafe2bc4 | |
parent | 84a069db6714ddcf444095ed09dbcd7404834694 (diff) |
Implement software single stepping for MOPS instructions
-rw-r--r-- | gdb/aarch64-tdep.c | 107 |
1 files changed, 105 insertions, 2 deletions
diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c index 8d0553f3d7c..99a7fe4f970 100644 --- a/gdb/aarch64-tdep.c +++ b/gdb/aarch64-tdep.c @@ -3444,6 +3444,104 @@ value_of_aarch64_user_reg (const frame_info_ptr &frame, const void *baton) return value_of_register (*reg_p, get_next_frame_sentinel_okay (frame)); } +static std::vector<CORE_ADDR> +aarch64_software_single_step_mops (struct regcache *regcache, CORE_ADDR loc, + uint32_t insn) +{ + const int insn_size = 4; + struct gdbarch *gdbarch = regcache->arch (); + enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch); + uint8_t o0, op1, op2; + + o0 = bit (insn, 21); + op1 = bits (insn, 22, 23); + op2 = bits (insn, 12, 15); + + /* Look for the prologue instruction that begins the sequence. */ + + /* CPYFP* */ + if (!((o0 == 0 && op1 == 0) + /* SETP* */ + || (o0 == 0 && op1 == 3 && op2 < 4) + /* CPYP* */ + || (o0 == 1 && op1 == 0) + /* SETGP* */ + || (o0 == 1 && op1 == 3 && op2 < 4))) + /* Prologue instruction not found. */ + return {}; + + /* Now look for the main instruction in the middle of the sequence. */ + + loc += insn_size; + ULONGEST insn_from_memory; + if (!safe_read_memory_unsigned_integer (loc, insn_size, + byte_order_for_code, + &insn_from_memory)) + { + /* Assume we don't have a MOPS sequence, as we couldn't read the + instruction in this location. */ + return {}; + } + + insn = insn_from_memory; + aarch64_inst inst; + if (aarch64_decode_insn (insn, &inst, 1, nullptr) != 0) + return {}; + if (!AARCH64_CPU_HAS_FEATURE (*inst.opcode->avariant, MOPS)) + return {}; + + o0 = bit (insn, 21); + op1 = bits (insn, 22, 23); + op2 = bits (insn, 12, 15); + + /* CPYFM* */ + if (!((o0 == 0 && op1 == 1) + /* SETM* */ + || (o0 == 0 && op1 == 3 && op2 >= 4 && op2 < 8) + /* CPYM* */ + || (o0 == 1 && op1 == 1) + /* SETGM* */ + || (o0 == 1 && op1 == 3 && op2 >= 4 && op2 < 8))) + /* Main instruction not found. */ + return {}; + + /* Now look for the epilogue instruction that ends the sequence. */ + + loc += insn_size; + if (!safe_read_memory_unsigned_integer (loc, insn_size, + byte_order_for_code, + &insn_from_memory)) + { + /* Assume we don't have a MOPS sequence, as we couldn't read the + instruction in this location. */ + return {}; + } + + insn = insn_from_memory; + if (aarch64_decode_insn (insn, &inst, 1, nullptr) != 0) + return {}; + if (!AARCH64_CPU_HAS_FEATURE (*inst.opcode->avariant, MOPS)) + return {}; + + o0 = bit (insn, 21); + op1 = bits (insn, 22, 23); + op2 = bits (insn, 12, 15); + + /* CPYFE* */ + if (!((o0 == 0 && op1 == 2) + /* SETE* (op2 >= 12 is unallocated space) */ + || (o0 == 0 && op1 == 3 && op2 >= 8 && op2 < 12) + /* CPYE* */ + || (o0 == 1 && op1 == 2) + /* SETGE* (op2 >= 12 is unallocated space) */ + || (o0 == 1 && op1 == 3 && op2 >= 8 && op2 < 12))) + /* Epilogue instruction not found. */ + return {}; + + /* Insert breakpoint after the end of the atomic sequence. */ + return { loc + insn_size }; +} + /* Implement the "software_single_step" gdbarch method, needed to single step through atomic sequences on AArch64. */ @@ -3479,6 +3577,9 @@ aarch64_software_single_step (struct regcache *regcache) if (aarch64_decode_insn (insn, &inst, 1, NULL) != 0) return {}; + if (AARCH64_CPU_HAS_FEATURE (*inst.opcode->avariant, MOPS)) + return aarch64_software_single_step_mops (regcache, loc, insn); + /* Look for a Load Exclusive instruction which begins the sequence. */ if (inst.opcode->iclass != ldstexcl || bit (insn, 22) == 0) return {}; @@ -3808,8 +3909,10 @@ aarch64_displaced_step_copy_insn (struct gdbarch *gdbarch, if (aarch64_decode_insn (insn, &inst, 1, NULL) != 0) return NULL; - /* Look for a Load Exclusive instruction which begins the sequence. */ - if (inst.opcode->iclass == ldstexcl && bit (insn, 22)) + /* Look for a Load Exclusive instruction which begins the sequence, + or for a MOPS instruction. */ + if ((inst.opcode->iclass == ldstexcl && bit (insn, 22)) + || AARCH64_CPU_HAS_FEATURE (*inst.opcode->avariant, MOPS)) { /* We can't displaced step atomic sequences. */ return NULL; |