public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 1/4] Fix ppc64 single step over atomic sequence testcase
@ 2014-03-28  3:41 Anton Blanchard
  2014-03-28  3:42 ` [PATCH 4/4] Add lbarx/stbcx., lharx/sthcx. and lqarx/stqcx. single stepping Anton Blanchard
                   ` (4 more replies)
  0 siblings, 5 replies; 15+ messages in thread
From: Anton Blanchard @ 2014-03-28  3:41 UTC (permalink / raw)
  To: gdb-patches, brobecker, emachado, luis_gustavo, ulrich.weigand

The current ppc64 single step over atomic sequence testcase is written
in C and breaks with some versions of gcc. Convert the test to
assembly and use stepi to step through it.

gdb/
2014-03-28  Anton Blanchard  <anton@samba.org>

	* gdb.arch/ppc64-atomic-inst.c: Remove.
	* gdb.arch/ppc64-atomic-inst.s: New file.
	* gdb.arch/ppc64-atomic-inst.exp: Adapt for asm based testcase.
---
 gdb/testsuite/gdb.arch/ppc64-atomic-inst.c   | 44 --------------------
 gdb/testsuite/gdb.arch/ppc64-atomic-inst.exp | 15 +++++--
 gdb/testsuite/gdb.arch/ppc64-atomic-inst.s   | 61 ++++++++++++++++++++++++++++
 3 files changed, 72 insertions(+), 48 deletions(-)
 delete mode 100644 gdb/testsuite/gdb.arch/ppc64-atomic-inst.c
 create mode 100644 gdb/testsuite/gdb.arch/ppc64-atomic-inst.s

diff --git a/gdb/testsuite/gdb.arch/ppc64-atomic-inst.c b/gdb/testsuite/gdb.arch/ppc64-atomic-inst.c
deleted file mode 100644
index 303e383..0000000
--- a/gdb/testsuite/gdb.arch/ppc64-atomic-inst.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/* This file is part of GDB, the GNU debugger.
-
-   Copyright 2008-2014 Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
-
-#include <stdio.h>
-
-int main()
-{
-  unsigned int word = 0;
-  unsigned int *word_addr = &word;
-  unsigned long dword = 0;
-  unsigned long *dword_addr = &dword;
-
-  __asm __volatile ("1:     lwarx   %0,0,%2\n"              \
-                    "       addi    %0,%0,1\n"              \
-                    "       stwcx.  %0,0,%2\n"              \
-                    "       bne-    1b"			    \
-                    : "=&b" (word), "=m" (*word_addr)       \
-                    : "b" (word_addr), "m" (*word_addr)     \
-                    : "cr0", "memory");			    \
-
-  __asm __volatile ("1:     ldarx   %0,0,%2\n"              \
-                    "       addi    %0,%0,1\n"              \
-                    "       stdcx.  %0,0,%2\n"              \
-                    "       bne-    1b"                     \
-                    : "=&b" (dword), "=m" (*dword_addr)     \
-                    : "b" (dword_addr), "m" (*dword_addr)   \
-                    : "cr0", "memory");                     \
-
-  return 0;
-}
diff --git a/gdb/testsuite/gdb.arch/ppc64-atomic-inst.exp b/gdb/testsuite/gdb.arch/ppc64-atomic-inst.exp
index f5f3b40..efcd82a 100644
--- a/gdb/testsuite/gdb.arch/ppc64-atomic-inst.exp
+++ b/gdb/testsuite/gdb.arch/ppc64-atomic-inst.exp
@@ -27,7 +27,7 @@ if {![istarget "powerpc*"] || ![is_lp64_target]} {
 }
 
 set testfile "ppc64-atomic-inst"
-set srcfile ${testfile}.c
+set srcfile ${testfile}.s
 set binfile ${objdir}/${subdir}/${testfile}
 set compile_flags {debug quiet}
 
@@ -50,11 +50,18 @@ set bp1 [gdb_get_line_number "lwarx"]
 gdb_breakpoint "$bp1" "Breakpoint $decimal at $hex" \
   "Set the breakpoint at the start of the sequence"
 
+set bp2 [gdb_get_line_number "ldarx"]
+gdb_breakpoint "$bp2" "Breakpoint $decimal at $hex" \
+  "Set the breakpoint at the start of the sequence"
+
 gdb_test continue "Continuing.*Breakpoint $decimal.*" \
   "Continue until breakpoint"
 
-gdb_test next ".*__asm __volatile.*" \
+gdb_test nexti "bne.*1b" \
   "Step through the lwarx/stwcx sequence"
 
-gdb_test next ".*return 0.*" \
-  "Step through the ldarx/stdcx sequence"
+gdb_test continue "Continuing.*Breakpoint $decimal.*" \
+  "Continue until breakpoint"
+
+gdb_test nexti "bne.*1b" \
+  "Step through the lwarx/stwcx sequence"
diff --git a/gdb/testsuite/gdb.arch/ppc64-atomic-inst.s b/gdb/testsuite/gdb.arch/ppc64-atomic-inst.s
new file mode 100644
index 0000000..15ccfd9
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/ppc64-atomic-inst.s
@@ -0,0 +1,61 @@
+/* This file is part of GDB, the GNU debugger.
+
+   Copyright 2008-2014 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+	.align 2
+	.globl main
+#if _CALL_ELF == 2
+	.type main,@function
+main:
+#else
+	.section ".opd","aw"
+	.align 3
+main:
+	.quad .main,.TOC.@tocbase,0
+	.size main,.-main
+	.previous
+	.globl .main
+	.type .main,@function
+.main:
+#endif
+
+	li	0,0
+	addi	4,1,-8
+
+	stw	0,0(4)
+1:	lwarx	5,0,4
+	cmpwi	5,0
+	bne	2f
+	addi	5,5,1
+	stwcx.	5,0,4
+	bne	1b
+
+	std	0,0(4)
+2:	ldarx	5,0,4
+	cmpdi	5,0
+	bne	3f
+	addi	5,5,1
+	stdcx.	5,0,4
+	bne	1b
+
+3:	li	3,0
+	blr
+
+#if _CALL_ELF == 2
+	.size main,.-main
+#else
+	.size .main,.-.main
+#endif
-- 
1.8.3.2

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 2/4] Support up to 3 conditional branches in an atomic sequence
  2014-03-28  3:41 [PATCH 1/4] Fix ppc64 single step over atomic sequence testcase Anton Blanchard
  2014-03-28  3:42 ` [PATCH 4/4] Add lbarx/stbcx., lharx/sthcx. and lqarx/stqcx. single stepping Anton Blanchard
  2014-03-28  3:42 ` [PATCH 3/4] Add multiple branches to ppc64 single step through atomic sequence testcase Anton Blanchard
@ 2014-03-28  3:42 ` Anton Blanchard
  2014-03-28 13:12   ` Joel Brobecker
  2014-03-28 13:05 ` [PATCH 1/4] Fix ppc64 single step over atomic sequence testcase Joel Brobecker
  2014-03-28 13:13 ` Ulrich Weigand
  4 siblings, 1 reply; 15+ messages in thread
From: Anton Blanchard @ 2014-03-28  3:42 UTC (permalink / raw)
  To: gdb-patches, brobecker, emachado, luis_gustavo, ulrich.weigand

gdb currently supports 1 conditional branch inside a ppc larx/stcx
critical region. Unfortunately there is existing code that contains more
than 1, for example in the ppc64 Linux kernel:

c00000000003ac18 <.__hash_page_4K>:
...
c00000000003ac4c:       ldarx   r31,0,r6
c00000000003ac50:       andc.   r0,r4,r31
c00000000003ac54:       bne-    c00000000003aee8 <htab_wrong_access>
c00000000003ac58:       andi.   r0,r31,2048
c00000000003ac5c:       bne-    c00000000003ae0c <htab_bail_ok>
c00000000003ac60:       rlwinm  r30,r4,30,24,24
c00000000003ac64:       or      r30,r30,r31
c00000000003ac68:       ori     r30,r30,2304
c00000000003ac6c:       oris    r30,r30,4096
c00000000003ac70:       stdcx.  r30,0,r6

If we try to single step through this we get stuck forever because
the reservation is never set when we step over the stdcx.

The following patch bumps the number to 3 conditional branches + 1
terminating branch. With this patch applied I can single step through
the offending function in the ppc64 Linux kernel.

gdb/
2014-03-28  Anton Blanchard  <anton@samba.org>

	* breakpoint.h (MAX_SINGLE_STEP_BREAKPOINTS): New define.
	* rs6000-tdep.c (ppc_deal_with_atomic_sequence): Allow for more
	than two breakpoints.
	* breakpoint.c (insert_single_step_breakpoint): Likewise.
	(insert_single_step_breakpoint): Likewise.
	(single_step_breakpoints_inserted): Likewise.
	(cancel_single_step_breakpoints): Likewise.
	(detach_single_step_breakpoints): Likewise.
	(single_step_breakpoint_inserted_here_p): Likewise.
---
 gdb/breakpoint.c  | 63 ++++++++++++++++++++++++++++---------------------------
 gdb/breakpoint.h  |  6 ++++--
 gdb/rs6000-tdep.c | 46 ++++++++++++++++++++++------------------
 3 files changed, 62 insertions(+), 53 deletions(-)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 19af9df..b12ea94 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -15036,11 +15036,10 @@ deprecated_remove_raw_breakpoint (struct gdbarch *gdbarch, void *bp)
   return ret;
 }
 
-/* One (or perhaps two) breakpoints used for software single
-   stepping.  */
+/* Breakpoints used for software single stepping.  */
 
-static void *single_step_breakpoints[2];
-static struct gdbarch *single_step_gdbarch[2];
+static void *single_step_breakpoints[MAX_SINGLE_STEP_BREAKPOINTS];
+static struct gdbarch *single_step_gdbarch[MAX_SINGLE_STEP_BREAKPOINTS];
 
 /* Create and insert a breakpoint for software single step.  */
 
@@ -15049,19 +15048,17 @@ insert_single_step_breakpoint (struct gdbarch *gdbarch,
 			       struct address_space *aspace, 
 			       CORE_ADDR next_pc)
 {
+  int i;
   void **bpt_p;
 
-  if (single_step_breakpoints[0] == NULL)
-    {
-      bpt_p = &single_step_breakpoints[0];
-      single_step_gdbarch[0] = gdbarch;
-    }
-  else
-    {
-      gdb_assert (single_step_breakpoints[1] == NULL);
-      bpt_p = &single_step_breakpoints[1];
-      single_step_gdbarch[1] = gdbarch;
-    }
+  for (i = 0; i < MAX_SINGLE_STEP_BREAKPOINTS; i++)
+    if (single_step_breakpoints[i] == NULL)
+        break;
+
+  gdb_assert (i < MAX_SINGLE_STEP_BREAKPOINTS);
+
+  bpt_p = &single_step_breakpoints[i];
+  single_step_gdbarch[i] = gdbarch;
 
   /* NOTE drow/2006-04-11: A future improvement to this function would
      be to only create the breakpoints once, and actually put them on
@@ -15082,8 +15079,13 @@ insert_single_step_breakpoint (struct gdbarch *gdbarch,
 int
 single_step_breakpoints_inserted (void)
 {
-  return (single_step_breakpoints[0] != NULL
-          || single_step_breakpoints[1] != NULL);
+  int i;
+
+  for (i = 0; i < MAX_SINGLE_STEP_BREAKPOINTS; i++)
+    if (single_step_breakpoints[i] != NULL)
+      return 1;
+
+  return 0;
 }
 
 /* Remove and delete any breakpoints used for software single step.  */
@@ -15091,22 +15093,21 @@ single_step_breakpoints_inserted (void)
 void
 remove_single_step_breakpoints (void)
 {
+  int i;
+
   gdb_assert (single_step_breakpoints[0] != NULL);
 
   /* See insert_single_step_breakpoint for more about this deprecated
      call.  */
-  deprecated_remove_raw_breakpoint (single_step_gdbarch[0],
-				    single_step_breakpoints[0]);
-  single_step_gdbarch[0] = NULL;
-  single_step_breakpoints[0] = NULL;
 
-  if (single_step_breakpoints[1] != NULL)
-    {
-      deprecated_remove_raw_breakpoint (single_step_gdbarch[1],
-					single_step_breakpoints[1]);
-      single_step_gdbarch[1] = NULL;
-      single_step_breakpoints[1] = NULL;
-    }
+  for (i = 0; i < MAX_SINGLE_STEP_BREAKPOINTS; i++)
+    if (single_step_breakpoints[i] != NULL)
+      {
+	deprecated_remove_raw_breakpoint (single_step_gdbarch[i],
+					  single_step_breakpoints[i]);
+	single_step_gdbarch[i] = NULL;
+	single_step_breakpoints[i] = NULL;
+      }
 }
 
 /* Delete software single step breakpoints without removing them from
@@ -15119,7 +15120,7 @@ cancel_single_step_breakpoints (void)
 {
   int i;
 
-  for (i = 0; i < 2; i++)
+  for (i = 0; i < MAX_SINGLE_STEP_BREAKPOINTS; i++)
     if (single_step_breakpoints[i])
       {
 	xfree (single_step_breakpoints[i]);
@@ -15136,7 +15137,7 @@ detach_single_step_breakpoints (void)
 {
   int i;
 
-  for (i = 0; i < 2; i++)
+  for (i = 0; i < MAX_SINGLE_STEP_BREAKPOINTS; i++)
     if (single_step_breakpoints[i])
       target_remove_breakpoint (single_step_gdbarch[i],
 				single_step_breakpoints[i]);
@@ -15151,7 +15152,7 @@ single_step_breakpoint_inserted_here_p (struct address_space *aspace,
 {
   int i;
 
-  for (i = 0; i < 2; i++)
+  for (i = 0; i < MAX_SINGLE_STEP_BREAKPOINTS; i++)
     {
       struct bp_target_info *bp_tgt = single_step_breakpoints[i];
       if (bp_tgt
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index d8e88fc..65d3ecb 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1443,8 +1443,10 @@ extern void add_solib_catchpoint (char *arg, int is_load, int is_temp,
    deletes all breakpoints.  */
 extern void delete_command (char *arg, int from_tty);
 
-/* Manage a software single step breakpoint (or two).  Insert may be
-   called twice before remove is called.  */
+/* Manage software single step breakpoints.  Insert may be
+   called multiple times before remove is called.  */
+#define MAX_SINGLE_STEP_BREAKPOINTS 4
+
 extern void insert_single_step_breakpoint (struct gdbarch *,
 					   struct address_space *, 
 					   CORE_ADDR);
diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
index dbe3aa2..be14e39 100644
--- a/gdb/rs6000-tdep.c
+++ b/gdb/rs6000-tdep.c
@@ -1088,7 +1088,7 @@ ppc_deal_with_atomic_sequence (struct frame_info *frame)
   struct address_space *aspace = get_frame_address_space (frame);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   CORE_ADDR pc = get_frame_pc (frame);
-  CORE_ADDR breaks[2] = {-1, -1};
+  CORE_ADDR breaks[MAX_SINGLE_STEP_BREAKPOINTS];
   CORE_ADDR loc = pc;
   CORE_ADDR closing_insn; /* Instruction that closes the atomic sequence.  */
   int insn = read_memory_integer (loc, PPC_INSN_SIZE, byte_order);
@@ -1097,7 +1097,6 @@ ppc_deal_with_atomic_sequence (struct frame_info *frame)
   int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed).  */  
   const int atomic_sequence_length = 16; /* Instruction sequence length.  */
   int opcode; /* Branch instruction's OPcode.  */
-  int bc_insn_count = 0; /* Conditional branch instruction count.  */
 
   /* Assume all atomic sequences start with a lwarx/ldarx instruction.  */
   if ((insn & LWARX_MASK) != LWARX_INSTRUCTION
@@ -1111,24 +1110,20 @@ ppc_deal_with_atomic_sequence (struct frame_info *frame)
       loc += PPC_INSN_SIZE;
       insn = read_memory_integer (loc, PPC_INSN_SIZE, byte_order);
 
-      /* Assume that there is at most one conditional branch in the atomic
-         sequence.  If a conditional branch is found, put a breakpoint in 
-         its destination address.  */
       if ((insn & BRANCH_MASK) == BC_INSN)
         {
           int immediate = ((insn & 0xfffc) ^ 0x8000) - 0x8000;
           int absolute = insn & 2;
 
-          if (bc_insn_count >= 1)
-            return 0; /* More than one conditional branch found, fallback 
+          if (last_breakpoint >= MAX_SINGLE_STEP_BREAKPOINTS - 1)
+            return 0; /* too many conditional branches found, fallback
                          to the standard single-step code.  */
  
 	  if (absolute)
-	    breaks[1] = immediate;
+	    breaks[last_breakpoint] = immediate;
 	  else
-	    breaks[1] = loc + immediate;
+	    breaks[last_breakpoint] = loc + immediate;
 
-	  bc_insn_count++;
 	  last_breakpoint++;
         }
 
@@ -1147,18 +1142,29 @@ ppc_deal_with_atomic_sequence (struct frame_info *frame)
   insn = read_memory_integer (loc, PPC_INSN_SIZE, byte_order);
 
   /* Insert a breakpoint right after the end of the atomic sequence.  */
-  breaks[0] = loc;
+  breaks[last_breakpoint] = loc;
 
-  /* Check for duplicated breakpoints.  Check also for a breakpoint
-     placed (branch instruction's destination) anywhere in sequence.  */
-  if (last_breakpoint
-      && (breaks[1] == breaks[0]
-	  || (breaks[1] >= pc && breaks[1] <= closing_insn)))
-    last_breakpoint = 0;
-
-  /* Effectively inserts the breakpoints.  */
   for (index = 0; index <= last_breakpoint; index++)
-    insert_single_step_breakpoint (gdbarch, aspace, breaks[index]);
+    {
+      int index2;
+      int insert_bp = 1;
+
+      /* Check for a breakpoint placed (branch instruction's destination)
+	 anywhere in sequence.  */
+      if (breaks[index] >= pc && breaks[index] <= closing_insn)
+	continue;
+
+      /* Check for duplicated breakpoints.  */
+      for (index2 = 0; index2 < index; index2++)
+        {
+	  if (breaks[index] == breaks[index2])
+	    insert_bp = 0;
+	}
+
+      /* insert the breakpoint.  */
+      if (insert_bp)
+        insert_single_step_breakpoint (gdbarch, aspace, breaks[index]);
+    }
 
   return 1;
 }
-- 
1.8.3.2

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 3/4] Add multiple branches to ppc64 single step through atomic sequence testcase
  2014-03-28  3:41 [PATCH 1/4] Fix ppc64 single step over atomic sequence testcase Anton Blanchard
  2014-03-28  3:42 ` [PATCH 4/4] Add lbarx/stbcx., lharx/sthcx. and lqarx/stqcx. single stepping Anton Blanchard
@ 2014-03-28  3:42 ` Anton Blanchard
  2014-03-28 13:14   ` Joel Brobecker
  2014-03-28  3:42 ` [PATCH 2/4] Support up to 3 conditional branches in an atomic sequence Anton Blanchard
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 15+ messages in thread
From: Anton Blanchard @ 2014-03-28  3:42 UTC (permalink / raw)
  To: gdb-patches, brobecker, emachado, luis_gustavo, ulrich.weigand

Test 3 conditional branches in an atomic sequence, 2 to the same
destination.

gdb/testsuite/
2014-03-28  Anton Blanchard  <anton@samba.org>

	* gdb.arch/ppc64-atomic-inst.s: Add second and third branch
	inside atomic sequence.
---
 gdb/testsuite/gdb.arch/ppc64-atomic-inst.s | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/gdb/testsuite/gdb.arch/ppc64-atomic-inst.s b/gdb/testsuite/gdb.arch/ppc64-atomic-inst.s
index 15ccfd9..0521170 100644
--- a/gdb/testsuite/gdb.arch/ppc64-atomic-inst.s
+++ b/gdb/testsuite/gdb.arch/ppc64-atomic-inst.s
@@ -39,18 +39,30 @@ main:
 1:	lwarx	5,0,4
 	cmpwi	5,0
 	bne	2f
+	cmpwi	5,1
+	beq	3f
+	cmpwi	5,2
+	beq	3f	/* branch to same destination */
 	addi	5,5,1
 	stwcx.	5,0,4
 	bne	1b
 
-	std	0,0(4)
-2:	ldarx	5,0,4
+2:	nop
+
+3:	std	0,0(4)
+1:	ldarx	5,0,4
 	cmpdi	5,0
-	bne	3f
+	bne	2f
+	cmpdi	5,1
+	beq	3f
+	cmpwi	5,2
+	beq	3f	/* branch to same destination */
 	addi	5,5,1
 	stdcx.	5,0,4
 	bne	1b
 
+2:	nop
+
 3:	li	3,0
 	blr
 
-- 
1.8.3.2

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 4/4] Add lbarx/stbcx., lharx/sthcx. and lqarx/stqcx. single stepping
  2014-03-28  3:41 [PATCH 1/4] Fix ppc64 single step over atomic sequence testcase Anton Blanchard
@ 2014-03-28  3:42 ` Anton Blanchard
  2014-03-28 13:17   ` Joel Brobecker
  2014-03-28  3:42 ` [PATCH 3/4] Add multiple branches to ppc64 single step through atomic sequence testcase Anton Blanchard
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 15+ messages in thread
From: Anton Blanchard @ 2014-03-28  3:42 UTC (permalink / raw)
  To: gdb-patches, brobecker, emachado, luis_gustavo, ulrich.weigand

Newer CPUs support byte, half word and quad word atomic update
sequences.

gdb/testsuite/
2014-03-28  Anton Blanchard  <anton@samba.org>

	* rs6000-tdep.c (ppc_deal_with_atomic_sequence): Add single step
	support for lbarx/stbcx., lharx/sthcx. and lqarx/stqcx.
---
 gdb/rs6000-tdep.c | 36 ++++++++++++++++++++++++++----------
 1 file changed, 26 insertions(+), 10 deletions(-)

diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
index be14e39..7257cc3 100644
--- a/gdb/rs6000-tdep.c
+++ b/gdb/rs6000-tdep.c
@@ -1070,14 +1070,21 @@ ppc_displaced_step_hw_singlestep (struct gdbarch *gdbarch,
 
 /* Instruction masks used during single-stepping of atomic sequences.  */
 #define LWARX_MASK 0xfc0007fe
+#define LBARX_INSTRUCTION 0x7c000068
+#define LHARX_INSTRUCTION 0x7c0000e8
 #define LWARX_INSTRUCTION 0x7c000028
 #define LDARX_INSTRUCTION 0x7c0000A8
+#define LQARX_INSTRUCTION 0x7c000228
+
 #define STWCX_MASK 0xfc0007ff
+#define STBCX_INSTRUCTION 0x7c00056d
+#define STHCX_INSTRUCTION 0x7c0005ad
 #define STWCX_INSTRUCTION 0x7c00012d
 #define STDCX_INSTRUCTION 0x7c0001ad
+#define STQCX_INSTRUCTION 0x7c00016d
 
-/* Checks for an atomic sequence of instructions beginning with a LWARX/LDARX
-   instruction and ending with a STWCX/STDCX instruction.  If such a sequence
+/* Checks for an atomic sequence of instructions beginning with a l[bhwdq]arx
+   instruction and ending with a st[bhwdq]cx instruction.  If such a sequence
    is found, attempt to step through it.  A breakpoint is placed at the end of 
    the sequence.  */
 
@@ -1098,9 +1105,12 @@ ppc_deal_with_atomic_sequence (struct frame_info *frame)
   const int atomic_sequence_length = 16; /* Instruction sequence length.  */
   int opcode; /* Branch instruction's OPcode.  */
 
-  /* Assume all atomic sequences start with a lwarx/ldarx instruction.  */
-  if ((insn & LWARX_MASK) != LWARX_INSTRUCTION
-      && (insn & LWARX_MASK) != LDARX_INSTRUCTION)
+  /* Assume all atomic sequences start with a l[bhwdq]arx instruction.  */
+  if ((insn & LWARX_MASK) != LBARX_INSTRUCTION
+      && (insn & LWARX_MASK) != LHARX_INSTRUCTION
+      && (insn & LWARX_MASK) != LWARX_INSTRUCTION
+      && (insn & LWARX_MASK) != LDARX_INSTRUCTION
+      && (insn & LWARX_MASK) != LQARX_INSTRUCTION)
     return 0;
 
   /* Assume that no atomic sequence is longer than "atomic_sequence_length" 
@@ -1127,14 +1137,20 @@ ppc_deal_with_atomic_sequence (struct frame_info *frame)
 	  last_breakpoint++;
         }
 
-      if ((insn & STWCX_MASK) == STWCX_INSTRUCTION
-          || (insn & STWCX_MASK) == STDCX_INSTRUCTION)
+      if ((insn & STWCX_MASK) == STBCX_INSTRUCTION
+          || (insn & STWCX_MASK) == STHCX_INSTRUCTION
+          || (insn & STWCX_MASK) == STWCX_INSTRUCTION
+          || (insn & STWCX_MASK) == STDCX_INSTRUCTION
+          || (insn & STWCX_MASK) == STQCX_INSTRUCTION)
         break;
     }
 
-  /* Assume that the atomic sequence ends with a stwcx/stdcx instruction.  */
-  if ((insn & STWCX_MASK) != STWCX_INSTRUCTION
-      && (insn & STWCX_MASK) != STDCX_INSTRUCTION)
+  /* Assume that the atomic sequence ends with a st[bhwdq]cx instruction.  */
+  if ((insn & STWCX_MASK) != STBCX_INSTRUCTION
+      && (insn & STWCX_MASK) != STHCX_INSTRUCTION
+      && (insn & STWCX_MASK) != STWCX_INSTRUCTION
+      && (insn & STWCX_MASK) != STDCX_INSTRUCTION
+      && (insn & STWCX_MASK) != STQCX_INSTRUCTION)
     return 0;
 
   closing_insn = loc;
-- 
1.8.3.2

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/4] Fix ppc64 single step over atomic sequence testcase
  2014-03-28  3:41 [PATCH 1/4] Fix ppc64 single step over atomic sequence testcase Anton Blanchard
                   ` (2 preceding siblings ...)
  2014-03-28  3:42 ` [PATCH 2/4] Support up to 3 conditional branches in an atomic sequence Anton Blanchard
@ 2014-03-28 13:05 ` Joel Brobecker
  2014-03-31  2:55   ` Anton Blanchard
  2014-03-28 13:13 ` Ulrich Weigand
  4 siblings, 1 reply; 15+ messages in thread
From: Joel Brobecker @ 2014-03-28 13:05 UTC (permalink / raw)
  To: Anton Blanchard; +Cc: gdb-patches, emachado, luis_gustavo, ulrich.weigand

> gdb/
> 2014-03-28  Anton Blanchard  <anton@samba.org>
> 
> 	* gdb.arch/ppc64-atomic-inst.c: Remove.
> 	* gdb.arch/ppc64-atomic-inst.s: New file.
> 	* gdb.arch/ppc64-atomic-inst.exp: Adapt for asm based testcase.

OK to commit.

>  set testfile "ppc64-atomic-inst"
> -set srcfile ${testfile}.c
> +set srcfile ${testfile}.s
>  set binfile ${objdir}/${subdir}/${testfile}
>  set compile_flags {debug quiet}

As a followup patch, you might want to adapt it to use standard_testfile
+ prepare_for_testing.

See: https://sourceware.org/gdb/wiki/GDBTestcaseCookbook

-- 
Joel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 2/4] Support up to 3 conditional branches in an atomic sequence
  2014-03-28  3:42 ` [PATCH 2/4] Support up to 3 conditional branches in an atomic sequence Anton Blanchard
@ 2014-03-28 13:12   ` Joel Brobecker
  2014-03-28 17:13     ` Pedro Alves
  0 siblings, 1 reply; 15+ messages in thread
From: Joel Brobecker @ 2014-03-28 13:12 UTC (permalink / raw)
  To: Anton Blanchard
  Cc: gdb-patches, emachado, luis_gustavo, ulrich.weigand, Pedro Alves

On Fri, Mar 28, 2014 at 02:41:49PM +1100, Anton Blanchard wrote:
> gdb currently supports 1 conditional branch inside a ppc larx/stcx
> critical region. Unfortunately there is existing code that contains more
> than 1, for example in the ppc64 Linux kernel:
> 
> c00000000003ac18 <.__hash_page_4K>:
> ...
> c00000000003ac4c:       ldarx   r31,0,r6
> c00000000003ac50:       andc.   r0,r4,r31
> c00000000003ac54:       bne-    c00000000003aee8 <htab_wrong_access>
> c00000000003ac58:       andi.   r0,r31,2048
> c00000000003ac5c:       bne-    c00000000003ae0c <htab_bail_ok>
> c00000000003ac60:       rlwinm  r30,r4,30,24,24
> c00000000003ac64:       or      r30,r30,r31
> c00000000003ac68:       ori     r30,r30,2304
> c00000000003ac6c:       oris    r30,r30,4096
> c00000000003ac70:       stdcx.  r30,0,r6
> 
> If we try to single step through this we get stuck forever because
> the reservation is never set when we step over the stdcx.
> 
> The following patch bumps the number to 3 conditional branches + 1
> terminating branch. With this patch applied I can single step through
> the offending function in the ppc64 Linux kernel.
> 
> gdb/
> 2014-03-28  Anton Blanchard  <anton@samba.org>
> 
> 	* breakpoint.h (MAX_SINGLE_STEP_BREAKPOINTS): New define.
> 	* rs6000-tdep.c (ppc_deal_with_atomic_sequence): Allow for more
> 	than two breakpoints.
> 	* breakpoint.c (insert_single_step_breakpoint): Likewise.
> 	(insert_single_step_breakpoint): Likewise.
> 	(single_step_breakpoints_inserted): Likewise.
> 	(cancel_single_step_breakpoints): Likewise.
> 	(detach_single_step_breakpoints): Likewise.
> 	(single_step_breakpoint_inserted_here_p): Likewise.

Overall, this looks like a nice generalization, but Pedro has been
more active in the breakpoint area than I have, so it would be nice
to have his feedback on this patch as well.

IIUC, it looks like MAX_SINGLE_STEP_BREAKPOINTS is actually not
the max, but MAX - 1. I was a little confused by that. Why not
change MAX to 3, and then adjust the array definition and code
accordingly? I think things will be slightly simpler to understand.


> ---
>  gdb/breakpoint.c  | 63 ++++++++++++++++++++++++++++---------------------------
>  gdb/breakpoint.h  |  6 ++++--
>  gdb/rs6000-tdep.c | 46 ++++++++++++++++++++++------------------
>  3 files changed, 62 insertions(+), 53 deletions(-)
> 
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index 19af9df..b12ea94 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -15036,11 +15036,10 @@ deprecated_remove_raw_breakpoint (struct gdbarch *gdbarch, void *bp)
>    return ret;
>  }
>  
> -/* One (or perhaps two) breakpoints used for software single
> -   stepping.  */
> +/* Breakpoints used for software single stepping.  */
>  
> -static void *single_step_breakpoints[2];
> -static struct gdbarch *single_step_gdbarch[2];
> +static void *single_step_breakpoints[MAX_SINGLE_STEP_BREAKPOINTS];
> +static struct gdbarch *single_step_gdbarch[MAX_SINGLE_STEP_BREAKPOINTS];
>  
>  /* Create and insert a breakpoint for software single step.  */
>  
> @@ -15049,19 +15048,17 @@ insert_single_step_breakpoint (struct gdbarch *gdbarch,
>  			       struct address_space *aspace, 
>  			       CORE_ADDR next_pc)
>  {
> +  int i;
>    void **bpt_p;
>  
> -  if (single_step_breakpoints[0] == NULL)
> -    {
> -      bpt_p = &single_step_breakpoints[0];
> -      single_step_gdbarch[0] = gdbarch;
> -    }
> -  else
> -    {
> -      gdb_assert (single_step_breakpoints[1] == NULL);
> -      bpt_p = &single_step_breakpoints[1];
> -      single_step_gdbarch[1] = gdbarch;
> -    }
> +  for (i = 0; i < MAX_SINGLE_STEP_BREAKPOINTS; i++)
> +    if (single_step_breakpoints[i] == NULL)
> +        break;
> +
> +  gdb_assert (i < MAX_SINGLE_STEP_BREAKPOINTS);
> +
> +  bpt_p = &single_step_breakpoints[i];
> +  single_step_gdbarch[i] = gdbarch;
>  
>    /* NOTE drow/2006-04-11: A future improvement to this function would
>       be to only create the breakpoints once, and actually put them on
> @@ -15082,8 +15079,13 @@ insert_single_step_breakpoint (struct gdbarch *gdbarch,
>  int
>  single_step_breakpoints_inserted (void)
>  {
> -  return (single_step_breakpoints[0] != NULL
> -          || single_step_breakpoints[1] != NULL);
> +  int i;
> +
> +  for (i = 0; i < MAX_SINGLE_STEP_BREAKPOINTS; i++)
> +    if (single_step_breakpoints[i] != NULL)
> +      return 1;
> +
> +  return 0;
>  }
>  
>  /* Remove and delete any breakpoints used for software single step.  */
> @@ -15091,22 +15093,21 @@ single_step_breakpoints_inserted (void)
>  void
>  remove_single_step_breakpoints (void)
>  {
> +  int i;
> +
>    gdb_assert (single_step_breakpoints[0] != NULL);
>  
>    /* See insert_single_step_breakpoint for more about this deprecated
>       call.  */
> -  deprecated_remove_raw_breakpoint (single_step_gdbarch[0],
> -				    single_step_breakpoints[0]);
> -  single_step_gdbarch[0] = NULL;
> -  single_step_breakpoints[0] = NULL;
>  
> -  if (single_step_breakpoints[1] != NULL)
> -    {
> -      deprecated_remove_raw_breakpoint (single_step_gdbarch[1],
> -					single_step_breakpoints[1]);
> -      single_step_gdbarch[1] = NULL;
> -      single_step_breakpoints[1] = NULL;
> -    }
> +  for (i = 0; i < MAX_SINGLE_STEP_BREAKPOINTS; i++)
> +    if (single_step_breakpoints[i] != NULL)
> +      {
> +	deprecated_remove_raw_breakpoint (single_step_gdbarch[i],
> +					  single_step_breakpoints[i]);
> +	single_step_gdbarch[i] = NULL;
> +	single_step_breakpoints[i] = NULL;
> +      }
>  }
>  
>  /* Delete software single step breakpoints without removing them from
> @@ -15119,7 +15120,7 @@ cancel_single_step_breakpoints (void)
>  {
>    int i;
>  
> -  for (i = 0; i < 2; i++)
> +  for (i = 0; i < MAX_SINGLE_STEP_BREAKPOINTS; i++)
>      if (single_step_breakpoints[i])
>        {
>  	xfree (single_step_breakpoints[i]);
> @@ -15136,7 +15137,7 @@ detach_single_step_breakpoints (void)
>  {
>    int i;
>  
> -  for (i = 0; i < 2; i++)
> +  for (i = 0; i < MAX_SINGLE_STEP_BREAKPOINTS; i++)
>      if (single_step_breakpoints[i])
>        target_remove_breakpoint (single_step_gdbarch[i],
>  				single_step_breakpoints[i]);
> @@ -15151,7 +15152,7 @@ single_step_breakpoint_inserted_here_p (struct address_space *aspace,
>  {
>    int i;
>  
> -  for (i = 0; i < 2; i++)
> +  for (i = 0; i < MAX_SINGLE_STEP_BREAKPOINTS; i++)
>      {
>        struct bp_target_info *bp_tgt = single_step_breakpoints[i];
>        if (bp_tgt
> diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
> index d8e88fc..65d3ecb 100644
> --- a/gdb/breakpoint.h
> +++ b/gdb/breakpoint.h
> @@ -1443,8 +1443,10 @@ extern void add_solib_catchpoint (char *arg, int is_load, int is_temp,
>     deletes all breakpoints.  */
>  extern void delete_command (char *arg, int from_tty);
>  
> -/* Manage a software single step breakpoint (or two).  Insert may be
> -   called twice before remove is called.  */
> +/* Manage software single step breakpoints.  Insert may be
> +   called multiple times before remove is called.  */
> +#define MAX_SINGLE_STEP_BREAKPOINTS 4
> +
>  extern void insert_single_step_breakpoint (struct gdbarch *,
>  					   struct address_space *, 
>  					   CORE_ADDR);
> diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
> index dbe3aa2..be14e39 100644
> --- a/gdb/rs6000-tdep.c
> +++ b/gdb/rs6000-tdep.c
> @@ -1088,7 +1088,7 @@ ppc_deal_with_atomic_sequence (struct frame_info *frame)
>    struct address_space *aspace = get_frame_address_space (frame);
>    enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
>    CORE_ADDR pc = get_frame_pc (frame);
> -  CORE_ADDR breaks[2] = {-1, -1};
> +  CORE_ADDR breaks[MAX_SINGLE_STEP_BREAKPOINTS];
>    CORE_ADDR loc = pc;
>    CORE_ADDR closing_insn; /* Instruction that closes the atomic sequence.  */
>    int insn = read_memory_integer (loc, PPC_INSN_SIZE, byte_order);
> @@ -1097,7 +1097,6 @@ ppc_deal_with_atomic_sequence (struct frame_info *frame)
>    int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed).  */  
>    const int atomic_sequence_length = 16; /* Instruction sequence length.  */
>    int opcode; /* Branch instruction's OPcode.  */
> -  int bc_insn_count = 0; /* Conditional branch instruction count.  */
>  
>    /* Assume all atomic sequences start with a lwarx/ldarx instruction.  */
>    if ((insn & LWARX_MASK) != LWARX_INSTRUCTION
> @@ -1111,24 +1110,20 @@ ppc_deal_with_atomic_sequence (struct frame_info *frame)
>        loc += PPC_INSN_SIZE;
>        insn = read_memory_integer (loc, PPC_INSN_SIZE, byte_order);
>  
> -      /* Assume that there is at most one conditional branch in the atomic
> -         sequence.  If a conditional branch is found, put a breakpoint in 
> -         its destination address.  */
>        if ((insn & BRANCH_MASK) == BC_INSN)
>          {
>            int immediate = ((insn & 0xfffc) ^ 0x8000) - 0x8000;
>            int absolute = insn & 2;
>  
> -          if (bc_insn_count >= 1)
> -            return 0; /* More than one conditional branch found, fallback 
> +          if (last_breakpoint >= MAX_SINGLE_STEP_BREAKPOINTS - 1)
> +            return 0; /* too many conditional branches found, fallback
>                           to the standard single-step code.  */
>   
>  	  if (absolute)
> -	    breaks[1] = immediate;
> +	    breaks[last_breakpoint] = immediate;
>  	  else
> -	    breaks[1] = loc + immediate;
> +	    breaks[last_breakpoint] = loc + immediate;
>  
> -	  bc_insn_count++;
>  	  last_breakpoint++;
>          }
>  
> @@ -1147,18 +1142,29 @@ ppc_deal_with_atomic_sequence (struct frame_info *frame)
>    insn = read_memory_integer (loc, PPC_INSN_SIZE, byte_order);
>  
>    /* Insert a breakpoint right after the end of the atomic sequence.  */
> -  breaks[0] = loc;
> +  breaks[last_breakpoint] = loc;
>  
> -  /* Check for duplicated breakpoints.  Check also for a breakpoint
> -     placed (branch instruction's destination) anywhere in sequence.  */
> -  if (last_breakpoint
> -      && (breaks[1] == breaks[0]
> -	  || (breaks[1] >= pc && breaks[1] <= closing_insn)))
> -    last_breakpoint = 0;
> -
> -  /* Effectively inserts the breakpoints.  */
>    for (index = 0; index <= last_breakpoint; index++)
> -    insert_single_step_breakpoint (gdbarch, aspace, breaks[index]);
> +    {
> +      int index2;
> +      int insert_bp = 1;
> +
> +      /* Check for a breakpoint placed (branch instruction's destination)
> +	 anywhere in sequence.  */
> +      if (breaks[index] >= pc && breaks[index] <= closing_insn)
> +	continue;
> +
> +      /* Check for duplicated breakpoints.  */
> +      for (index2 = 0; index2 < index; index2++)
> +        {
> +	  if (breaks[index] == breaks[index2])
> +	    insert_bp = 0;
> +	}
> +
> +      /* insert the breakpoint.  */
> +      if (insert_bp)
> +        insert_single_step_breakpoint (gdbarch, aspace, breaks[index]);
> +    }
>  
>    return 1;
>  }
> -- 
> 1.8.3.2

-- 
Joel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/4] Fix ppc64 single step over atomic sequence testcase
  2014-03-28  3:41 [PATCH 1/4] Fix ppc64 single step over atomic sequence testcase Anton Blanchard
                   ` (3 preceding siblings ...)
  2014-03-28 13:05 ` [PATCH 1/4] Fix ppc64 single step over atomic sequence testcase Joel Brobecker
@ 2014-03-28 13:13 ` Ulrich Weigand
  4 siblings, 0 replies; 15+ messages in thread
From: Ulrich Weigand @ 2014-03-28 13:13 UTC (permalink / raw)
  To: Anton Blanchard
  Cc: gdb-patches, brobecker, emachado, luis_gustavo, ulrich.weigand

Anton Blanchard wrote:

> +++ b/gdb/testsuite/gdb.arch/ppc64-atomic-inst.s

> +#if _CALL_ELF == 2

I just noticed that a '.s' file is not run through
the preprocessor, and thus this fails (the # is
regarded as a comment ...).

You need to rename the file to .S (and update the
filename in the .exp file) for the test to work
successfully.

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 3/4] Add multiple branches to ppc64 single step through atomic sequence testcase
  2014-03-28  3:42 ` [PATCH 3/4] Add multiple branches to ppc64 single step through atomic sequence testcase Anton Blanchard
@ 2014-03-28 13:14   ` Joel Brobecker
  0 siblings, 0 replies; 15+ messages in thread
From: Joel Brobecker @ 2014-03-28 13:14 UTC (permalink / raw)
  To: Anton Blanchard; +Cc: gdb-patches, emachado, luis_gustavo, ulrich.weigand

> Test 3 conditional branches in an atomic sequence, 2 to the same
> destination.
> 
> gdb/testsuite/
> 2014-03-28  Anton Blanchard  <anton@samba.org>
> 
> 	* gdb.arch/ppc64-atomic-inst.s: Add second and third branch
> 	inside atomic sequence.

Just a thought - is there no value in keeping the old assembly code
and creating an additional testcase? It would be very similar to
the one you already have, but then you'd be covering most cases...
Otherwise, the patch seems fine.

> ---
>  gdb/testsuite/gdb.arch/ppc64-atomic-inst.s | 18 +++++++++++++++---
>  1 file changed, 15 insertions(+), 3 deletions(-)
> 
> diff --git a/gdb/testsuite/gdb.arch/ppc64-atomic-inst.s b/gdb/testsuite/gdb.arch/ppc64-atomic-inst.s
> index 15ccfd9..0521170 100644
> --- a/gdb/testsuite/gdb.arch/ppc64-atomic-inst.s
> +++ b/gdb/testsuite/gdb.arch/ppc64-atomic-inst.s
> @@ -39,18 +39,30 @@ main:
>  1:	lwarx	5,0,4
>  	cmpwi	5,0
>  	bne	2f
> +	cmpwi	5,1
> +	beq	3f
> +	cmpwi	5,2
> +	beq	3f	/* branch to same destination */
>  	addi	5,5,1
>  	stwcx.	5,0,4
>  	bne	1b
>  
> -	std	0,0(4)
> -2:	ldarx	5,0,4
> +2:	nop
> +
> +3:	std	0,0(4)
> +1:	ldarx	5,0,4
>  	cmpdi	5,0
> -	bne	3f
> +	bne	2f
> +	cmpdi	5,1
> +	beq	3f
> +	cmpwi	5,2
> +	beq	3f	/* branch to same destination */
>  	addi	5,5,1
>  	stdcx.	5,0,4
>  	bne	1b
>  
> +2:	nop
> +
>  3:	li	3,0
>  	blr
>  
> -- 
> 1.8.3.2

-- 
Joel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 4/4] Add lbarx/stbcx., lharx/sthcx. and lqarx/stqcx. single stepping
  2014-03-28  3:42 ` [PATCH 4/4] Add lbarx/stbcx., lharx/sthcx. and lqarx/stqcx. single stepping Anton Blanchard
@ 2014-03-28 13:17   ` Joel Brobecker
  0 siblings, 0 replies; 15+ messages in thread
From: Joel Brobecker @ 2014-03-28 13:17 UTC (permalink / raw)
  To: Anton Blanchard; +Cc: gdb-patches, emachado, luis_gustavo, ulrich.weigand

> gdb/testsuite/
     ^^^^^^^^^^
Small typo. I'm sure you'll be adding the ChangeLog entry to the right
file, but we can also avoid this typo creeping into the revision log
of the commit that will eventually get pushed.

> 2014-03-28  Anton Blanchard  <anton@samba.org>
> 
> 	* rs6000-tdep.c (ppc_deal_with_atomic_sequence): Add single step
> 	support for lbarx/stbcx., lharx/sthcx. and lqarx/stqcx.

OK.

Thank you.

> ---
>  gdb/rs6000-tdep.c | 36 ++++++++++++++++++++++++++----------
>  1 file changed, 26 insertions(+), 10 deletions(-)
> 
> diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
> index be14e39..7257cc3 100644
> --- a/gdb/rs6000-tdep.c
> +++ b/gdb/rs6000-tdep.c
> @@ -1070,14 +1070,21 @@ ppc_displaced_step_hw_singlestep (struct gdbarch *gdbarch,
>  
>  /* Instruction masks used during single-stepping of atomic sequences.  */
>  #define LWARX_MASK 0xfc0007fe
> +#define LBARX_INSTRUCTION 0x7c000068
> +#define LHARX_INSTRUCTION 0x7c0000e8
>  #define LWARX_INSTRUCTION 0x7c000028
>  #define LDARX_INSTRUCTION 0x7c0000A8
> +#define LQARX_INSTRUCTION 0x7c000228
> +
>  #define STWCX_MASK 0xfc0007ff
> +#define STBCX_INSTRUCTION 0x7c00056d
> +#define STHCX_INSTRUCTION 0x7c0005ad
>  #define STWCX_INSTRUCTION 0x7c00012d
>  #define STDCX_INSTRUCTION 0x7c0001ad
> +#define STQCX_INSTRUCTION 0x7c00016d
>  
> -/* Checks for an atomic sequence of instructions beginning with a LWARX/LDARX
> -   instruction and ending with a STWCX/STDCX instruction.  If such a sequence
> +/* Checks for an atomic sequence of instructions beginning with a l[bhwdq]arx
> +   instruction and ending with a st[bhwdq]cx instruction.  If such a sequence
>     is found, attempt to step through it.  A breakpoint is placed at the end of 
>     the sequence.  */
>  
> @@ -1098,9 +1105,12 @@ ppc_deal_with_atomic_sequence (struct frame_info *frame)
>    const int atomic_sequence_length = 16; /* Instruction sequence length.  */
>    int opcode; /* Branch instruction's OPcode.  */
>  
> -  /* Assume all atomic sequences start with a lwarx/ldarx instruction.  */
> -  if ((insn & LWARX_MASK) != LWARX_INSTRUCTION
> -      && (insn & LWARX_MASK) != LDARX_INSTRUCTION)
> +  /* Assume all atomic sequences start with a l[bhwdq]arx instruction.  */
> +  if ((insn & LWARX_MASK) != LBARX_INSTRUCTION
> +      && (insn & LWARX_MASK) != LHARX_INSTRUCTION
> +      && (insn & LWARX_MASK) != LWARX_INSTRUCTION
> +      && (insn & LWARX_MASK) != LDARX_INSTRUCTION
> +      && (insn & LWARX_MASK) != LQARX_INSTRUCTION)
>      return 0;
>  
>    /* Assume that no atomic sequence is longer than "atomic_sequence_length" 
> @@ -1127,14 +1137,20 @@ ppc_deal_with_atomic_sequence (struct frame_info *frame)
>  	  last_breakpoint++;
>          }
>  
> -      if ((insn & STWCX_MASK) == STWCX_INSTRUCTION
> -          || (insn & STWCX_MASK) == STDCX_INSTRUCTION)
> +      if ((insn & STWCX_MASK) == STBCX_INSTRUCTION
> +          || (insn & STWCX_MASK) == STHCX_INSTRUCTION
> +          || (insn & STWCX_MASK) == STWCX_INSTRUCTION
> +          || (insn & STWCX_MASK) == STDCX_INSTRUCTION
> +          || (insn & STWCX_MASK) == STQCX_INSTRUCTION)
>          break;
>      }
>  
> -  /* Assume that the atomic sequence ends with a stwcx/stdcx instruction.  */
> -  if ((insn & STWCX_MASK) != STWCX_INSTRUCTION
> -      && (insn & STWCX_MASK) != STDCX_INSTRUCTION)
> +  /* Assume that the atomic sequence ends with a st[bhwdq]cx instruction.  */
> +  if ((insn & STWCX_MASK) != STBCX_INSTRUCTION
> +      && (insn & STWCX_MASK) != STHCX_INSTRUCTION
> +      && (insn & STWCX_MASK) != STWCX_INSTRUCTION
> +      && (insn & STWCX_MASK) != STDCX_INSTRUCTION
> +      && (insn & STWCX_MASK) != STQCX_INSTRUCTION)
>      return 0;
>  
>    closing_insn = loc;
> -- 
> 1.8.3.2

-- 
Joel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 2/4] Support up to 3 conditional branches in an atomic sequence
  2014-03-28 13:12   ` Joel Brobecker
@ 2014-03-28 17:13     ` Pedro Alves
  2014-03-28 17:22       ` Pedro Alves
  2014-03-28 17:32       ` Joel Brobecker
  0 siblings, 2 replies; 15+ messages in thread
From: Pedro Alves @ 2014-03-28 17:13 UTC (permalink / raw)
  To: Joel Brobecker
  Cc: Anton Blanchard, gdb-patches, emachado, luis_gustavo,
	ulrich.weigand, Pedro Alves

On 03/28/2014 01:12 PM, Joel Brobecker wrote:
> On Fri, Mar 28, 2014 at 02:41:49PM +1100, Anton Blanchard wrote:
>> gdb currently supports 1 conditional branch inside a ppc larx/stcx
>> critical region. Unfortunately there is existing code that contains more
>> than 1, for example in the ppc64 Linux kernel:
>>
>> c00000000003ac18 <.__hash_page_4K>:
>> ...
>> c00000000003ac4c:       ldarx   r31,0,r6
>> c00000000003ac50:       andc.   r0,r4,r31
>> c00000000003ac54:       bne-    c00000000003aee8 <htab_wrong_access>
>> c00000000003ac58:       andi.   r0,r31,2048
>> c00000000003ac5c:       bne-    c00000000003ae0c <htab_bail_ok>
>> c00000000003ac60:       rlwinm  r30,r4,30,24,24
>> c00000000003ac64:       or      r30,r30,r31
>> c00000000003ac68:       ori     r30,r30,2304
>> c00000000003ac6c:       oris    r30,r30,4096
>> c00000000003ac70:       stdcx.  r30,0,r6
>>
>> If we try to single step through this we get stuck forever because
>> the reservation is never set when we step over the stdcx.
>>
>> The following patch bumps the number to 3 conditional branches + 1
>> terminating branch. With this patch applied I can single step through
>> the offending function in the ppc64 Linux kernel.

Is there a hard limit?  Like, is there a limit on the number of instructions
that can appear inside a ppc larx/stcx region?

>>
>> gdb/
>> 2014-03-28  Anton Blanchard  <anton@samba.org>
>>
>> 	* breakpoint.h (MAX_SINGLE_STEP_BREAKPOINTS): New define.
>> 	* rs6000-tdep.c (ppc_deal_with_atomic_sequence): Allow for more
>> 	than two breakpoints.
>> 	* breakpoint.c (insert_single_step_breakpoint): Likewise.
>> 	(insert_single_step_breakpoint): Likewise.
>> 	(single_step_breakpoints_inserted): Likewise.
>> 	(cancel_single_step_breakpoints): Likewise.
>> 	(detach_single_step_breakpoints): Likewise.
>> 	(single_step_breakpoint_inserted_here_p): Likewise.
> 
> Overall, this looks like a nice generalization, but Pedro has been
> more active in the breakpoint area than I have, so it would be nice
> to have his feedback on this patch as well.
> 
> IIUC, it looks like MAX_SINGLE_STEP_BREAKPOINTS is actually not
> the max, but MAX - 1. I was a little confused by that. Why not
> change MAX to 3, and then adjust the array definition and code
> accordingly? I think things will be slightly simpler to understand.

IMO that would be more confusing.  I read MAX_SINGLE_STEP_BREAKPOINTS
as meaning the "maximum number of of single-step breakpoints we
can create simultaneously".  I think you're reading it as
"the highest index possible into the single-step breakpoints
array" ?

Maybe it'd be clearer to just rename the macro, to, say
NUM_SINGLE_STEP_BREAKPOINTS?

>> +  for (i = 0; i < MAX_SINGLE_STEP_BREAKPOINTS; i++)
>> +    if (single_step_breakpoints[i] == NULL)
>> +        break;

I notice something odd with the formatting.  E.g., above,
vs:

>> +  for (i = 0; i < MAX_SINGLE_STEP_BREAKPOINTS; i++)
>> +    if (single_step_breakpoints[i] != NULL)
>> +      return 1;

Probably tab vs spaces -- please make use to use tabs
for 8 spaces.

>> --- a/gdb/rs6000-tdep.c
>> +++ b/gdb/rs6000-tdep.c
>> @@ -1088,7 +1088,7 @@ ppc_deal_with_atomic_sequence (struct frame_info *frame)
>>    struct address_space *aspace = get_frame_address_space (frame);
>>    enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
>>    CORE_ADDR pc = get_frame_pc (frame);
>> -  CORE_ADDR breaks[2] = {-1, -1};
>> +  CORE_ADDR breaks[MAX_SINGLE_STEP_BREAKPOINTS];

If we ever bump MAX_SINGLE_STEP_BREAKPOINTS further,
you'd still only want 4 here.

I think it'd be better if this was:

  /* 3 conditional branches + 1 terminating branch.  */
  CORE_ADDR breaks[4];

Followed by:

gdb_static_assert (MAX_SINGLE_STEP_BREAKPOINTS >= ARRAY_SIZE (breaks));

This way clearly documents that we need to support 4 sss breakpoints.
As it is, nothing in your patch leaves any indication in the source to
that effect, so the poor soul trying to revamp software single-step
breakpoints could miss this.

>>    CORE_ADDR loc = pc;
>>    CORE_ADDR closing_insn; /* Instruction that closes the atomic sequence.  */
>>    int insn = read_memory_integer (loc, PPC_INSN_SIZE, byte_order);
>> @@ -1097,7 +1097,6 @@ ppc_deal_with_atomic_sequence (struct frame_info *frame)
>>    int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed).  */  
>>    const int atomic_sequence_length = 16; /* Instruction sequence length.  */
>>    int opcode; /* Branch instruction's OPcode.  */
>> -  int bc_insn_count = 0; /* Conditional branch instruction count.  */
>>  
>>    /* Assume all atomic sequences start with a lwarx/ldarx instruction.  */
>>    if ((insn & LWARX_MASK) != LWARX_INSTRUCTION
>> @@ -1111,24 +1110,20 @@ ppc_deal_with_atomic_sequence (struct frame_info *frame)
>>        loc += PPC_INSN_SIZE;
>>        insn = read_memory_integer (loc, PPC_INSN_SIZE, byte_order);
>>  
>> -      /* Assume that there is at most one conditional branch in the atomic
>> -         sequence.  If a conditional branch is found, put a breakpoint in 
>> -         its destination address.  */
>>        if ((insn & BRANCH_MASK) == BC_INSN)
>>          {
>>            int immediate = ((insn & 0xfffc) ^ 0x8000) - 0x8000;
>>            int absolute = insn & 2;
>>  
>> -          if (bc_insn_count >= 1)
>> -            return 0; /* More than one conditional branch found, fallback 
>> +          if (last_breakpoint >= MAX_SINGLE_STEP_BREAKPOINTS - 1)
>> +            return 0; /* too many conditional branches found, fallback

No need for '>=' IFAICS.  Here I'd suggest:

          if (last_breakpoint == ARRAY_SIZE (breaks) - 1)
            {
              /* Too many conditional branches found, fallback
                 to the standard single-step code.  */
              return 0;
            }

Note "Too" should be capitalized.  also, our style nowadays says
to wrap the comment and statement in a {}s if it's multiline,
even though the old code wasn't doing that.

With those changes this looks good to me.
-- 
Pedro Alves

>>   
>>  	  if (absolute)
>> -	    breaks[1] = immediate;
>> +	    breaks[last_breakpoint] = immediate;
>>  	  else
>> -	    breaks[1] = loc + immediate;
>> +	    breaks[last_breakpoint] = loc + immediate;
>>  
>> -	  bc_insn_count++;
>>  	  last_breakpoint++;
>>          }
>>  
>> @@ -1147,18 +1142,29 @@ ppc_deal_with_atomic_sequence (struct frame_info *frame)
>>    insn = read_memory_integer (loc, PPC_INSN_SIZE, byte_order);
>>  
>>    /* Insert a breakpoint right after the end of the atomic sequence.  */
>> -  breaks[0] = loc;
>> +  breaks[last_breakpoint] = loc;
>>  
>> -  /* Check for duplicated breakpoints.  Check also for a breakpoint
>> -     placed (branch instruction's destination) anywhere in sequence.  */
>> -  if (last_breakpoint
>> -      && (breaks[1] == breaks[0]
>> -	  || (breaks[1] >= pc && breaks[1] <= closing_insn)))
>> -    last_breakpoint = 0;
>> -
>> -  /* Effectively inserts the breakpoints.  */
>>    for (index = 0; index <= last_breakpoint; index++)
>> -    insert_single_step_breakpoint (gdbarch, aspace, breaks[index]);
>> +    {
>> +      int index2;
>> +      int insert_bp = 1;
>> +
>> +      /* Check for a breakpoint placed (branch instruction's destination)
>> +	 anywhere in sequence.  */
>> +      if (breaks[index] >= pc && breaks[index] <= closing_insn)
>> +	continue;
>> +
>> +      /* Check for duplicated breakpoints.  */
>> +      for (index2 = 0; index2 < index; index2++)
>> +        {
>> +	  if (breaks[index] == breaks[index2])
>> +	    insert_bp = 0;
>> +	}
>> +
>> +      /* insert the breakpoint.  */
>> +      if (insert_bp)
>> +        insert_single_step_breakpoint (gdbarch, aspace, breaks[index]);
>> +    }
>>  
>>    return 1;
>>  }
>> -- 
>> 1.8.3.2
> 

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 2/4] Support up to 3 conditional branches in an atomic sequence
  2014-03-28 17:13     ` Pedro Alves
@ 2014-03-28 17:22       ` Pedro Alves
  2014-03-28 17:32       ` Joel Brobecker
  1 sibling, 0 replies; 15+ messages in thread
From: Pedro Alves @ 2014-03-28 17:22 UTC (permalink / raw)
  To: Anton Blanchard
  Cc: Joel Brobecker, gdb-patches, emachado, luis_gustavo, ulrich.weigand

On 03/28/2014 05:12 PM, Pedro Alves wrote:

>>> --- a/gdb/rs6000-tdep.c
>>> +++ b/gdb/rs6000-tdep.c
>>> @@ -1088,7 +1088,7 @@ ppc_deal_with_atomic_sequence (struct frame_info *frame)
>>>    struct address_space *aspace = get_frame_address_space (frame);
>>>    enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
>>>    CORE_ADDR pc = get_frame_pc (frame);
>>> -  CORE_ADDR breaks[2] = {-1, -1};
>>> +  CORE_ADDR breaks[MAX_SINGLE_STEP_BREAKPOINTS];
> 
> If we ever bump MAX_SINGLE_STEP_BREAKPOINTS further,
> you'd still only want 4 here.
> 
> I think it'd be better if this was:
> 
>   /* 3 conditional branches + 1 terminating branch.  */
>   CORE_ADDR breaks[4];
> 
> Followed by:
> 
> gdb_static_assert (MAX_SINGLE_STEP_BREAKPOINTS >= ARRAY_SIZE (breaks));
> 
> This way clearly documents that we need to support 4 sss breakpoints.
> As it is, nothing in your patch leaves any indication in the source to
> that effect, so the poor soul trying to revamp software single-step
> breakpoints could miss this.

Sorry, I wrote this before realizing that there could even be more
condition branches in the region and writing the "is there a hard limit",
and then pushed send too soon.  So assuming there's no limit and we're
just trying to be practical in what we support, there's really no harm
in leaving this as:

 CORE_ADDR breaks[MAX_SINGLE_STEP_BREAKPOINTS];

but I still think a comment (+ the assert would be nice) is
missing.  Something like:

/* The ppc64 Linux kernel has regions with 3 conditional branches.
   (plus 1 for the terminating branch).  */
gdb_static_assert (MAX_SINGLE_STEP_BREAKPOINTS >= 4);

?

BTW, shouldn't GDB warn or even error out if too many
conditional branches are found?  I think that'd be better
than silently getting stuck forever.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 2/4] Support up to 3 conditional branches in an atomic sequence
  2014-03-28 17:13     ` Pedro Alves
  2014-03-28 17:22       ` Pedro Alves
@ 2014-03-28 17:32       ` Joel Brobecker
  2014-03-28 17:58         ` Pedro Alves
  1 sibling, 1 reply; 15+ messages in thread
From: Joel Brobecker @ 2014-03-28 17:32 UTC (permalink / raw)
  To: Pedro Alves
  Cc: Anton Blanchard, gdb-patches, emachado, luis_gustavo, ulrich.weigand

> > IIUC, it looks like MAX_SINGLE_STEP_BREAKPOINTS is actually not
> > the max, but MAX - 1. I was a little confused by that. Why not
> > change MAX to 3, and then adjust the array definition and code
> > accordingly? I think things will be slightly simpler to understand.
> 
> IMO that would be more confusing.  I read MAX_SINGLE_STEP_BREAKPOINTS
> as meaning the "maximum number of of single-step breakpoints we
> can create simultaneously".  I think you're reading it as
> "the highest index possible into the single-step breakpoints
> array" ?

Here is how I read the patch: MAX_SINGLE_STEP_BREAKPOINTS is the size
of the array, and we rely on the last element always being NULL
to determine the number of "live" elements we actually have.
Hence, to me, the maximum number of SS breakpoints we can handle
in practice is not MAX_SINGLE_STEP_BREAKPOINTS but 1 less. For
instance, I think the patch is trying to increase the number of
SS breakpoints to 3, and yet defines MAX_SINGLE_STEP_BREAKPOINTS
to 4.

Perhaps it's time to just use a vec? That way, we don't have
a limit at all anymore...

-- 
Joel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 2/4] Support up to 3 conditional branches in an atomic sequence
  2014-03-28 17:32       ` Joel Brobecker
@ 2014-03-28 17:58         ` Pedro Alves
  2014-03-28 18:10           ` Joel Brobecker
  0 siblings, 1 reply; 15+ messages in thread
From: Pedro Alves @ 2014-03-28 17:58 UTC (permalink / raw)
  To: Joel Brobecker
  Cc: Anton Blanchard, gdb-patches, emachado, luis_gustavo, ulrich.weigand

On 03/28/2014 05:32 PM, Joel Brobecker wrote:
>>> IIUC, it looks like MAX_SINGLE_STEP_BREAKPOINTS is actually not
>>> the max, but MAX - 1. I was a little confused by that. Why not
>>> change MAX to 3, and then adjust the array definition and code
>>> accordingly? I think things will be slightly simpler to understand.
>>
>> IMO that would be more confusing.  I read MAX_SINGLE_STEP_BREAKPOINTS
>> as meaning the "maximum number of of single-step breakpoints we
>> can create simultaneously".  I think you're reading it as
>> "the highest index possible into the single-step breakpoints
>> array" ?
> 
> Here is how I read the patch: MAX_SINGLE_STEP_BREAKPOINTS is the size
> of the array, and we rely on the last element always being NULL
> to determine the number of "live" elements we actually have.

But we can fill the whole array, there's no sentinel.  E.g.:

+  for (i = 0; i < MAX_SINGLE_STEP_BREAKPOINTS; i++)
+    if (single_step_breakpoints[i] == NULL)
+        break;
+
+  gdb_assert (i < MAX_SINGLE_STEP_BREAKPOINTS);
+

This just looks for the first empty slot.

> Hence, to me, the maximum number of SS breakpoints we can handle
> in practice is not MAX_SINGLE_STEP_BREAKPOINTS but 1 less.

Nope.  We can handle MAX_SINGLE_STEP_BREAKPOINTS.

> For
> instance, I think the patch is trying to increase the number of
> SS breakpoints to 3, and yet defines MAX_SINGLE_STEP_BREAKPOINTS
> to 4.

Anton is making the port handle 3 conditional branches + 1
terminating branch, so that's 4.  I guess it's either the
subject that's confusing you, or this, perhaps:

> -          if (bc_insn_count >= 1)
> -            return 0; /* More than one conditional branch found, fallback
> +          if (last_breakpoint >= MAX_SINGLE_STEP_BREAKPOINTS - 1)
> +            return 0; /* too many conditional branches found, fallback
>                           to the standard single-step code.  */

This is "- 1" here because that's leaving space for the terminating
branch.  At least, that's what I understood.

I blame lack of comments in the patch.  :-)

> Perhaps it's time to just use a vec? That way, we don't have
> a limit at all anymore...

Yeah...

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 2/4] Support up to 3 conditional branches in an atomic sequence
  2014-03-28 17:58         ` Pedro Alves
@ 2014-03-28 18:10           ` Joel Brobecker
  0 siblings, 0 replies; 15+ messages in thread
From: Joel Brobecker @ 2014-03-28 18:10 UTC (permalink / raw)
  To: Pedro Alves
  Cc: Anton Blanchard, gdb-patches, emachado, luis_gustavo, ulrich.weigand

> But we can fill the whole array, there's no sentinel.  E.g.:

Ah, ok, I was indeed confused. Lack of comments I will blame also :)

Thanks for clarifying it for me.
-- 
Joel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/4] Fix ppc64 single step over atomic sequence testcase
  2014-03-28 13:05 ` [PATCH 1/4] Fix ppc64 single step over atomic sequence testcase Joel Brobecker
@ 2014-03-31  2:55   ` Anton Blanchard
  0 siblings, 0 replies; 15+ messages in thread
From: Anton Blanchard @ 2014-03-31  2:55 UTC (permalink / raw)
  To: Joel Brobecker, ulrich.weigand; +Cc: gdb-patches, emachado, luis_gustavo


Hi,

Joel Brobecker <brobecker@adacore.com> wrote:

> As a followup patch, you might want to adapt it to use
> standard_testfile + prepare_for_testing.
> 
> See: https://sourceware.org/gdb/wiki/GDBTestcaseCookbook

Nice link. I took the opportunity to add these and make some other
modifications suggested.


"Ulrich Weigand" <uweigand@de.ibm.com> wrote:

> You need to rename the file to .S (and update the
> filename in the .exp file) for the test to work
> successfully.

Thanks Uli, fixed in the next spin.

Anton

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2014-03-31  2:55 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-03-28  3:41 [PATCH 1/4] Fix ppc64 single step over atomic sequence testcase Anton Blanchard
2014-03-28  3:42 ` [PATCH 4/4] Add lbarx/stbcx., lharx/sthcx. and lqarx/stqcx. single stepping Anton Blanchard
2014-03-28 13:17   ` Joel Brobecker
2014-03-28  3:42 ` [PATCH 3/4] Add multiple branches to ppc64 single step through atomic sequence testcase Anton Blanchard
2014-03-28 13:14   ` Joel Brobecker
2014-03-28  3:42 ` [PATCH 2/4] Support up to 3 conditional branches in an atomic sequence Anton Blanchard
2014-03-28 13:12   ` Joel Brobecker
2014-03-28 17:13     ` Pedro Alves
2014-03-28 17:22       ` Pedro Alves
2014-03-28 17:32       ` Joel Brobecker
2014-03-28 17:58         ` Pedro Alves
2014-03-28 18:10           ` Joel Brobecker
2014-03-28 13:05 ` [PATCH 1/4] Fix ppc64 single step over atomic sequence testcase Joel Brobecker
2014-03-31  2:55   ` Anton Blanchard
2014-03-28 13:13 ` Ulrich Weigand

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).