public inbox for gdb-cvs@sourceware.org
help / color / mirror / Atom feed
* [binutils-gdb] gdb: LoongArch: Deal with atomic sequence
@ 2022-06-13 14:28 Tiezhu Yang
  0 siblings, 0 replies; only message in thread
From: Tiezhu Yang @ 2022-06-13 14:28 UTC (permalink / raw)
  To: gdb-cvs

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=208b57e53ed98106d20c7314e88d0a7225a8aa1d

commit 208b57e53ed98106d20c7314e88d0a7225a8aa1d
Author: Tiezhu Yang <yangtiezhu@loongson.cn>
Date:   Mon Jun 13 09:55:11 2022 +0800

    gdb: LoongArch: Deal with atomic sequence
    
    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.
    
    Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>

Diff:
---
 gdb/loongarch-tdep.c | 127 +++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 113 insertions(+), 14 deletions(-)

diff --git a/gdb/loongarch-tdep.c b/gdb/loongarch-tdep.c
index 963e832454a..e6b93a5cfce 100644
--- a/gdb/loongarch-tdep.c
+++ b/gdb/loongarch-tdep.c
@@ -45,22 +45,64 @@ loongarch_fetch_instruction (CORE_ADDR pc)
   return extract_unsigned_integer (buf, insn_len, BFD_ENDIAN_LITTLE);
 }
 
+/* Return TRUE if INSN is a unconditional branch instruction, otherwise return FALSE.  */
+
+static bool
+loongarch_insn_is_uncond_branch (insn_t insn)
+{
+  if ((insn & 0xfc000000) == 0x4c000000		/* jirl  */
+      || (insn & 0xfc000000) == 0x50000000	/* b     */
+      || (insn & 0xfc000000) == 0x54000000)	/* bl    */
+    return true;
+  return false;
+}
+
+/* Return TRUE if INSN is a conditional branch instruction, otherwise return FALSE.  */
+
+static bool
+loongarch_insn_is_cond_branch (insn_t insn)
+{
+  if ((insn & 0xfc000000) == 0x58000000		/* beq   */
+      || (insn & 0xfc000000) == 0x5c000000	/* bne   */
+      || (insn & 0xfc000000) == 0x60000000	/* blt   */
+      || (insn & 0xfc000000) == 0x64000000	/* bge	 */
+      || (insn & 0xfc000000) == 0x68000000	/* bltu  */
+      || (insn & 0xfc000000) == 0x6c000000	/* bgeu  */
+      || (insn & 0xfc000000) == 0x40000000	/* beqz  */
+      || (insn & 0xfc000000) == 0x44000000)	/* bnez  */
+    return true;
+  return false;
+}
+
 /* Return TRUE if INSN is a branch instruction, otherwise return FALSE.  */
 
 static bool
 loongarch_insn_is_branch (insn_t insn)
 {
-  if ((insn & 0xfc000000) == 0x4c000000       /* jirl	rd, rj, offs16  */
-      || (insn & 0xfc000000) == 0x50000000    /* b	offs26  */
-      || (insn & 0xfc000000) == 0x54000000    /* bl	offs26  */
-      || (insn & 0xfc000000) == 0x58000000    /* beq	rj, rd, offs16  */
-      || (insn & 0xfc000000) == 0x5c000000    /* bne	rj, rd, offs16  */
-      || (insn & 0xfc000000) == 0x60000000    /* blt	rj, rd, offs16  */
-      || (insn & 0xfc000000) == 0x64000000    /* bge	rj, rd, offs16  */
-      || (insn & 0xfc000000) == 0x68000000    /* bltu	rj, rd, offs16  */
-      || (insn & 0xfc000000) == 0x6c000000    /* bgeu	rj, rd, offs16  */
-      || (insn & 0xfc000000) == 0x40000000    /* beqz	rj, offs21  */
-      || (insn & 0xfc000000) == 0x44000000)   /* bnez	rj, offs21  */
+  bool is_uncond = loongarch_insn_is_uncond_branch (insn);
+  bool is_cond = loongarch_insn_is_cond_branch (insn);
+
+  return (is_uncond || is_cond);
+}
+
+/* Return TRUE if INSN is a Load Linked instruction, otherwise return FALSE.  */
+
+static bool
+loongarch_insn_is_ll (insn_t insn)
+{
+  if ((insn & 0xff000000) == 0x20000000		/* ll.w  */
+      || (insn & 0xff000000) == 0x22000000)	/* ll.d  */
+    return true;
+  return false;
+}
+
+/* Return TRUE if INSN is a Store Conditional instruction, otherwise return FALSE.  */
+
+static bool
+loongarch_insn_is_sc (insn_t insn)
+{
+  if ((insn & 0xff000000) == 0x21000000		/* sc.w  */
+      || (insn & 0xff000000) == 0x23000000)	/* sc.d  */
     return true;
   return false;
 }
@@ -182,8 +224,9 @@ loongarch_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
    next instruction.  */
 
 static CORE_ADDR
-loongarch_next_pc (struct regcache *regcache, CORE_ADDR cur_pc, insn_t insn)
+loongarch_next_pc (struct regcache *regcache, CORE_ADDR cur_pc)
 {
+  insn_t insn = loongarch_fetch_instruction (cur_pc);
   size_t insn_len = loongarch_insn_length (insn);
   CORE_ADDR next_pc = cur_pc + insn_len;
 
@@ -270,14 +313,70 @@ loongarch_next_pc (struct regcache *regcache, CORE_ADDR cur_pc, insn_t insn)
   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.  */
+
+static std::vector<CORE_ADDR>
+loongarch_deal_with_atomic_sequence (struct regcache *regcache, CORE_ADDR cur_pc)
+{
+  CORE_ADDR next_pc;
+  std::vector<CORE_ADDR> next_pcs;
+  insn_t insn = loongarch_fetch_instruction (cur_pc);
+  size_t insn_len = loongarch_insn_length (insn);
+  const int atomic_sequence_length = 16;
+  bool found_atomic_sequence_endpoint = false;
+
+  /* Look for a Load Linked instruction which begins the atomic sequence.  */
+  if (!loongarch_insn_is_ll (insn))
+    return {};
+
+  /* Assume that no atomic sequence is longer than "atomic_sequence_length" instructions.  */
+  for (int insn_count = 0; insn_count < atomic_sequence_length; ++insn_count)
+    {
+      cur_pc += insn_len;
+      insn = loongarch_fetch_instruction (cur_pc);
+
+      /* Look for a unconditional branch instruction, fallback to the standard code.  */
+      if (loongarch_insn_is_uncond_branch (insn))
+	{
+	  return {};
+	}
+      /* Look for a conditional branch instruction, put a breakpoint in its destination address.  */
+      else if (loongarch_insn_is_cond_branch (insn))
+	{
+	  next_pc = loongarch_next_pc (regcache, cur_pc);
+	  next_pcs.push_back (next_pc);
+	}
+      /* Look for a Store Conditional instruction which closes the atomic sequence.  */
+      else if (loongarch_insn_is_sc (insn))
+	{
+	  found_atomic_sequence_endpoint = true;
+	  next_pc = cur_pc + insn_len;
+	  next_pcs.push_back (next_pc);
+	  break;
+	}
+    }
+
+  /* We didn't find a closing Store Conditional instruction, fallback to the standard code.  */
+  if (!found_atomic_sequence_endpoint)
+    return {};
+
+  return next_pcs;
+}
+
 /* Implement the "software_single_step" gdbarch method  */
 
 static std::vector<CORE_ADDR>
 loongarch_software_single_step (struct regcache *regcache)
 {
   CORE_ADDR cur_pc = regcache_read_pc (regcache);
-  insn_t insn = loongarch_fetch_instruction (cur_pc);
-  CORE_ADDR next_pc = loongarch_next_pc (regcache, cur_pc, insn);
+  std::vector<CORE_ADDR> next_pcs
+    = loongarch_deal_with_atomic_sequence (regcache, cur_pc);
+
+  if (!next_pcs.empty ())
+    return next_pcs;
+
+  CORE_ADDR next_pc = loongarch_next_pc (regcache, cur_pc);
 
   return {next_pc};
 }


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-06-13 14:28 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-13 14:28 [binutils-gdb] gdb: LoongArch: Deal with atomic sequence Tiezhu Yang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).