[RFC] "single step" atomic instruction sequences as a whole on PPC

Luis Machado
2007-04-28T23:31:35Z

[-- Attachment #1: Type: text/plain, Size: 291 bytes --]

Daniel,

Follows attached the ppc portion of the patch for single stepping of
atomic instruction sequences.

You did mention that it had some cosmetic issues, so i'd like to have
thoughts and comments on that.

I'm re-submitting this one as it didn't make its way to the list.

Thanks,
Luis

[-- Attachment #2: ppc-atomic-single-stepping.diff --]
[-- Type: text/x-patch, Size: 4509 bytes --]

2007-04-13 Paul Gilliam <pgilliam@us.ibm.com>
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-04-28 16:22:11.000000000 -0700
+++ gdb/rs6000-tdep.c 2007-04-28 16:25:17.000000000 -0700
@@ -719,6 +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
+#define IMMEDIATE_PART(insn) (((insn & ~3) << 16) >> 16)
+#define ABSOLUTE_P(insn) ((int) ((insn >> 1) & 1))
+
+static int
+deal_with_atomic_sequence (enum target_signal sig, int insert_breakpoints_p)
+{
+ CORE_ADDR pc = read_pc ();
+ CORE_ADDR breaks[2] = {-1, -1};
+ CORE_ADDR loc = pc;
+ int insn = read_memory_integer (loc, PPC_INSN_SIZE);
+ int last_break = 0;
+ int i;
+
+ if (insert_breakpoints_p)
+ {
+
+ /* 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 6 instructions. */
+ for (i = 1; i < 5; ++i)
+ {
+ loc += PPC_INSN_SIZE;
+ insn = read_memory_integer (loc, PPC_INSN_SIZE);
+
+ /* Assume at most one conditional branch instruction between
+ the lwarx and stwcx instructions.*/
+ if ((insn & BC_MASK) == BC_INSTRUCTION)
+ {
+ last_break = 1;
+ breaks[1] = IMMEDIATE_PART (insn);
+ if ( ! ABSOLUTE_P(insn))
+ breaks[1] += loc;
+ continue;
+ }
+
+ if ((insn & STWCX_MASK) == STWCX_INSTRUCTION
+ || (insn & STWCX_MASK) == STDCX_INSTRUCTION)
+ break;
+ }
+
+ /* Assume that the atomic sequence ends with a stwcx instruction
+ followed by a conditional branch instruction. */
+ if ((insn & STWCX_MASK) != STWCX_INSTRUCTION
+ && (insn & STWCX_MASK) != STDCX_INSTRUCTION)
+ warning (_("Tried 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));
+
+ loc += PPC_INSN_SIZE;
+ insn = read_memory_integer (loc, PPC_INSN_SIZE);
+
+ if ((insn & BC_MASK) != BC_INSTRUCTION)
+ warning (_("Tried to step over an atomic sequence of instructions at %s\n \
+ but the instruction sequence ended in an unexpected way."),
+ core_addr_to_string(pc));
+
+ breaks[0] = loc;
+
+ /* This should never happen, but make sure we don't put
+ two breakpoints on the same address. */
+ if (last_break && breaks[1] == breaks[0])
+ last_break = 0;
+
+ for (i = 0; i <= last_break; ++i)
+ insert_single_step_breakpoint (breaks[i]);
+
+ printf_unfiltered (_("Stepping over an atomic sequence of instructions beginning at %s\n"),
+ core_addr_to_string (pc));
+
+ gdb_flush (gdb_stdout);
+ }
+ else
+ remove_single_step_breakpoints();
+
+ return 1;
+}

/* AIX does not support PT_STEP. Simulate it. */

@@ -737,7 +824,10 @@

insn = read_memory_integer (loc, 4);

- breaks[0] = loc + breakp_sz;
+ if (deal_with_atomic_sequence (signal, insert_breakpoints_p))
+ return 1;
+
+ breaks[0] = loc + breakp_sz;
opcode = insn >> 26;
breaks[1] = branch_dest (opcode, insn, loc, breaks[0]);

@@ -3461,6 +3551,9 @@
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
set_gdbarch_breakpoint_from_pc (gdbarch, rs6000_breakpoint_from_pc);

+ /* Watch for locking instruction sequences during single stepping */
+ 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