diff options
author | Tiezhu Yang <yangtiezhu@loongson.cn> | 2025-09-01 09:29:55 +0800 |
---|---|---|
committer | Tiezhu Yang <yangtiezhu@loongson.cn> | 2025-09-03 20:56:30 +0800 |
commit | 40f41b242f85df71ef4cad64db7d6142992a2bd0 (patch) | |
tree | 9c08cabdbfd0f453b9472a467d8286302357deb0 | |
parent | 37e91976250feff58468e893715f8698d87a4143 (diff) | |
download | binutils-40f41b242f85df71ef4cad64db7d6142992a2bd0.zip binutils-40f41b242f85df71ef4cad64db7d6142992a2bd0.tar.gz binutils-40f41b242f85df71ef4cad64db7d6142992a2bd0.tar.bz2 |
gdb: LoongArch: Add and use cond_branch_destination_address()
In the current loongarch_deal_with_atomic_sequence(), it is just a loop
through a ll/sc atomic instruction sequence, the instructions before the
condition branch are not actually executed, thus the condition register
value is not proper to determine the destination address.
Add a new function cond_branch_destination_address() to calculate the
destination address of a condition branch instruction under an assumed
true condition, then only put a breakpoint at this address when it is
outside of the ll/sc atomic instruction sequence.
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
-rw-r--r-- | gdb/loongarch-tdep.c | 35 |
1 files changed, 34 insertions, 1 deletions
diff --git a/gdb/loongarch-tdep.c b/gdb/loongarch-tdep.c index 9ee0eb3..0bd8b36 100644 --- a/gdb/loongarch-tdep.c +++ b/gdb/loongarch-tdep.c @@ -427,6 +427,39 @@ loongarch_next_pc (struct regcache *regcache, CORE_ADDR cur_pc) return next_pc; } +/* Calculate the destination address of a condition branch instruction under an + assumed true condition */ + +static CORE_ADDR +cond_branch_destination_address (CORE_ADDR cur_pc, insn_t insn) +{ + size_t insn_len = loongarch_insn_length (insn); + CORE_ADDR next_pc = cur_pc + insn_len; + + if ((insn & 0xfc000000) == 0x58000000) /* beq rj, rd, offs16 */ + next_pc = cur_pc + loongarch_decode_imm ("10:16<<2", insn, 1); + else if ((insn & 0xfc000000) == 0x5c000000) /* bne rj, rd, offs16 */ + next_pc = cur_pc + loongarch_decode_imm ("10:16<<2", insn, 1); + else if ((insn & 0xfc000000) == 0x60000000) /* blt rj, rd, offs16 */ + next_pc = cur_pc + loongarch_decode_imm ("10:16<<2", insn, 1); + else if ((insn & 0xfc000000) == 0x64000000) /* bge rj, rd, offs16 */ + next_pc = cur_pc + loongarch_decode_imm ("10:16<<2", insn, 1); + else if ((insn & 0xfc000000) == 0x68000000) /* bltu rj, rd, offs16 */ + next_pc = cur_pc + loongarch_decode_imm ("10:16<<2", insn, 1); + else if ((insn & 0xfc000000) == 0x6c000000) /* bgeu rj, rd, offs16 */ + next_pc = cur_pc + loongarch_decode_imm ("10:16<<2", insn, 1); + else if ((insn & 0xfc000000) == 0x40000000) /* beqz rj, offs21 */ + next_pc = cur_pc + loongarch_decode_imm ("0:5|10:16<<2", insn, 1); + else if ((insn & 0xfc000000) == 0x44000000) /* bnez rj, offs21 */ + next_pc = cur_pc + loongarch_decode_imm ("0:5|10:16<<2", insn, 1); + else if ((insn & 0xfc000300) == 0x48000000) /* bceqz cj, offs21 */ + next_pc = cur_pc + loongarch_decode_imm ("0:5|10:16<<2", insn, 1); + else if ((insn & 0xfc000300) == 0x48000100) /* bcnez cj, offs21 */ + next_pc = cur_pc + loongarch_decode_imm ("0:5|10:16<<2", insn, 1); + + return next_pc; +} + /* We can't put a breakpoint in the middle of a ll/sc atomic sequence, so look for the end of the sequence and put the breakpoint there. */ @@ -459,7 +492,7 @@ loongarch_deal_with_atomic_sequence (struct regcache *regcache, CORE_ADDR cur_pc which is outside of the ll/sc atomic instruction sequence. */ else if (loongarch_insn_is_cond_branch (insn)) { - next_pc = loongarch_next_pc (regcache, cur_pc); + next_pc = cond_branch_destination_address (cur_pc, insn); if (next_pc != cur_pc + insn_len) next_pcs.push_back (next_pc); } |