aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorTiezhu Yang <yangtiezhu@loongson.cn>2025-09-01 09:29:55 +0800
committerTiezhu Yang <yangtiezhu@loongson.cn>2025-09-03 20:56:30 +0800
commit40f41b242f85df71ef4cad64db7d6142992a2bd0 (patch)
tree9c08cabdbfd0f453b9472a467d8286302357deb0 /gdb
parent37e91976250feff58468e893715f8698d87a4143 (diff)
downloadbinutils-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>
Diffstat (limited to 'gdb')
-rw-r--r--gdb/loongarch-tdep.c35
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);
}