]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
gdb: LoongArch: Add and use cond_branch_destination_address()
authorTiezhu Yang <yangtiezhu@loongson.cn>
Mon, 1 Sep 2025 01:29:55 +0000 (09:29 +0800)
committerTiezhu Yang <yangtiezhu@loongson.cn>
Wed, 3 Sep 2025 12:56:30 +0000 (20:56 +0800)
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>
gdb/loongarch-tdep.c

index 9ee0eb36ae826022ac0ce43e4d80398875f3d3ee..0bd8b36db0b0df0ffda4e9f072fc24d4ad95712b 100644 (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);
        }