This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [RFC] "single step" atomic instruction sequences as a whole on PPC
- From: Luis Machado <luisgpm at linux dot vnet dot ibm dot com>
- To: uweigand at de dot ibm dot com
- Cc: gdb-patches at sourceware dot org
- Date: Thu, 03 May 2007 11:51:15 -0300
- Subject: Re: [RFC] "single step" atomic instruction sequences as a whole on PPC
- References: <200705021408.l42E8Qc0019267@dyn-9-152-216-62.boeblingen.de.ibm.com>
- Reply-to: luisgpm at linux dot vnet dot ibm dot com
Ulrich,
Thanks for the comments.
I've modified the patch according to your suggestions. Any additional
comments on it?
Any suggestions for the duplicate breakpoint detection? Maybe it could
be handled in a better way.
Best Regards.
Luis
2007-04-13 Luis Machado <luisgpm@br.ibm.com>
* rs6000-tdep.c: Defines masks for POWER instructions that set
and use the reservation flag (LWARX,LDARX,STWCX,STDCX).
* rs6000-tdep.c (deal_with_atomic_sequence): Handles single
stepping through an atomic sequence of instructions.
* rs6000-tdep.c (rs6000_software_single_step): Added a function
call to check if we are stepping through an atomic sequence of
instructions.
* rs6000-tdep.c (rs6000_gdbarch_init): Initializes a function to
check for atomic instruction sequences while single stepping.
Index: gdb/rs6000-tdep.c
===================================================================
--- gdb.orig/rs6000-tdep.c 2007-05-03 06:06:21.000000000 -0700
+++ gdb/rs6000-tdep.c 2007-05-03 07:45:09.000000000 -0700
@@ -719,8 +719,93 @@
return little_breakpoint;
}
+#define LWARX_MASK 0xfc0007fe
+#define LWARX_INSTRUCTION 0x7c000028
+#define LDARX_INSTRUCTION 0x7c0000A8
+#define STWCX_MASK 0xfc0007ff
+#define STWCX_INSTRUCTION 0x7c00012d
+#define STDCX_INSTRUCTION 0x7c0001ad
+#define BC_MASK 0xfc000000
+#define BC_INSTRUCTION 0x40000000
+
+static int
+deal_with_atomic_sequence(struct regcache *regcache)
+{
+ CORE_ADDR pc = read_pc ();
+ CORE_ADDR breaks[16] = {-1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1};
+ CORE_ADDR branch_bp; /* Breakpoint at destination of a banch instruction */
+ CORE_ADDR loc = pc;
+ int insn = read_memory_integer (loc, PPC_INSN_SIZE);
+ int insn_count;
+ int index; /* Index used for the "breaks" arrays */
+ int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed) */
+ const int atomic_sequence_length = 16;
+ const int opcode = BC_INSTRUCTION; /* Branch instruction's OPcode */
+
+ /* Assume all atomic sequences start with an lwarx or ldarx instruction. */
+ if ((insn & LWARX_MASK) != LWARX_INSTRUCTION
+ && (insn & LWARX_MASK) != LDARX_INSTRUCTION)
+ return 0;
+
+ /* Assume that no atomic sequence is longer than "atomic_sequence_length
+ instructions. */
+ for (insn_count = 0; insn_count < atomic_sequence_length ; ++insn_count)
+ {
+ loc += PPC_INSN_SIZE;
+ insn = read_memory_integer (loc, PPC_INSN_SIZE);
+
+ /* Check for conditiconal branches in the middle of the sequence
+ and put breakpoints in their destinations */
+ if ((insn & BC_MASK) == BC_INSTRUCTION)
+ {
+ branch_bp = branch_dest(opcode, insn, pc, breaks[0]);
+
+ /* Make sure we don't have two breakpoints at the same address */
+ for (index = 0; index <= last_breakpoint; index++)
+ breaks[last_breakpoint] = (breaks[last_breakpoint] == branch_bp)?
+ -1:branch_bp;
+
+ if (breaks[last_breakpoint] != -1)
+ last_breakpoint++;
+ }
-/* AIX does not support PT_STEP. Simulate it. */
+ if ((insn & STWCX_MASK) == STWCX_INSTRUCTION
+ || (insn & STWCX_MASK) == STDCX_INSTRUCTION)
+ break;
+ }
+
+ /* Assume that the atomic sequence ends with a stwcx/stdcx instruction */
+ if ((insn & STWCX_MASK) != STWCX_INSTRUCTION
+ && (insn & STWCX_MASK) != STDCX_INSTRUCTION)
+ {
+ warning (_("\nTried to step over an atomic sequence of instructions at %s\n \
+ but could not find the end of the sequence."),
+ core_addr_to_string(pc));
+ return 0;
+ }
+
+ loc += PPC_INSN_SIZE;
+ insn = read_memory_integer (loc, PPC_INSN_SIZE);
+
+ for (index = 0; index < last_breakpoint; index++)
+ if (loc == breaks[index])
+ break;
+
+ /* Insert a breakpoint right after the end of the atomic sequence */
+ if (index == last_breakpoint)
+ breaks[last_breakpoint++] = loc;
+
+ /* Effectively inserts all the breakpoints */
+ for (index = 0; index < last_breakpoint; index++)
+ insert_single_step_breakpoint (breaks[index]);
+
+ gdb_flush (gdb_stdout);
+
+ return 1;
+}
+
+/* AIX does not support PT_STEP. Simulate it. */
int
rs6000_software_single_step (struct regcache *regcache)
@@ -737,6 +822,9 @@
insn = read_memory_integer (loc, 4);
+ if (deal_with_atomic_sequence(regcache))
+ return 1;
+
breaks[0] = loc + breakp_sz;
opcode = insn >> 26;
breaks[1] = branch_dest (opcode, insn, loc, breaks[0]);
@@ -3461,6 +3549,9 @@
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
set_gdbarch_breakpoint_from_pc (gdbarch, rs6000_breakpoint_from_pc);
+ /* Handles single stepping of atomic sequences */
+ set_gdbarch_software_single_step(gdbarch, deal_with_atomic_sequence);
+
/* Handle the 64-bit SVR4 minimal-symbol convention of using "FN"
for the descriptor and ".FN" for the entry-point -- a user
specifying "break FN" will unexpectedly end up with a breakpoint