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>
This commit is contained in:
Tiezhu Yang
2025-09-01 09:29:55 +08:00
parent 37e9197625
commit 40f41b242f

View File

@@ -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);
}