2006-06-22 Paul Gilliam * rs6000-tdep (deal_with_atomic_sequence): new (rs6000_software_single_step): Call the new routine to check for atomic sequences of instructions that need to be single stepped 'as a whole'. --- old_rs6000-tdep.c 2006-06-22 13:16:03.000000000 -0700 +++ rs6000-tdep.c 2006-06-22 13:41:10.000000000 -0700 @@ -701,8 +701,81 @@ return little_breakpoint; } +#define LWARX_MASK 0xfc0007fe +#define LWARX_INSTRUCTION 0x7C000028 +#define STWCX_MASK 0xfc0007ff +#define STWCX_INSTRUCTION 0x7c00012d +#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) +{ + CORE_ADDR pc = read_pc (); + CORE_ADDR breaks[2] = {-1, -1}; + CORE_ADDR loc = pc; + int insn = read_memory_integer (loc, 4); + int last_break = 0; + int i; + + + /* Assume all atomic sequences start with an lwarx instruction. */ + if ((insn & LWARX_MASK) != LWARX_INSTRUCTION) + return 0; -/* AIX does not support PT_STEP. Simulate it. */ + /* 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, 4); + + /* 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) + break; + } + + /* Assume that the atomic sequence ends with a stwcx instruction + followed by a conditional branch instruction. */ + if ((insn & STWCX_MASK) != STWCX_INSTRUCTION) + error (_("Tried to step over an atomic sequence of instructions but could not find the end of the sequence.")); + + loc += PPC_INSN_SIZE; + insn = read_memory_integer (loc, 4); + + if ((insn & BC_MASK) != BC_INSTRUCTION) + error (_("Tried to step over an atomic sequence of instructions but it did not end as expected.")); + + breaks[0] = loc; + + /* This should never happen, but make sure we don't but + 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); + + return 1; +} + +/* AIX does not support PT_STEP. Simulate it, dealing with any sequence of + instructions that must be atomic. */ int rs6000_software_single_step (enum target_signal signal, @@ -722,6 +795,9 @@ insn = read_memory_integer (loc, 4); + if (deal_with_atomic_sequence (signal)) + return 1; + breaks[0] = loc + breakp_sz; opcode = insn >> 26; breaks[1] = branch_dest (opcode, insn, loc, breaks[0]);