On Sun, Nov 13, 2011 at 10:41 PM, Richard Henderson <r...@redhat.com> wrote: > On 11/12/2011 07:38 AM, Uros Bizjak wrote: >> On Fri, Nov 11, 2011 at 8:58 PM, Dominique Dhumieres <domi...@lps.ens.fr> >> wrote: >> >>> For the record, Jakub's comment on IRC: >>> >>>> with older gdb you simply had to find the stwcx >>>> or whatever SC insn is, put a breakpoint after >>>> it and continue instead of single stepping >> >> I'm not familiar enough with gdb scripting to implement this, but if >> someone fix _.gdb script, I can test the correct fix... > > It's not in the gdb script, it's in gdb proper. > > If you care to have a peek, look at > > /* Handles single stepping of atomic sequences. */ > set_gdbarch_software_single_step (gdbarch, ppc_deal_with_atomic_sequence); > > in gdb/rs6000-tdep.c. It ought to be fairly easy to write > something similar for alpha-tdep.c.
Indeed, the attached is WIP gdb patch that survives all simulate-thread.exp tests. It is almost a copy of rs6000-tdep.c (*) (*) Please note the error in how relative address of the branch is calculated in rs6000-tdep.c, ppc_deal_with_atomic_sequence function. Target address immediate should be relative to "loc", not "pc" variable. Richard, can you please help with the calculation of branch target address for alpha... I'm sure that the helper function should be available somewhere... Uros.
--- alpha-tdep.c 2011-11-16 21:57:26.998112380 +0100 +++ alpha-tdep.c.ub 2011-11-16 21:56:11.739733014 +0100 @@ -65,6 +65,7 @@ /* Branch instruction format */ #define BR_RA(insn) MEM_RA(insn) +static const int beq_opcode = 0x39; static const int bne_opcode = 0x3d; /* Operate instruction format */ @@ -762,6 +763,96 @@ } + +static const int ldl_l_opcode = 0x2a; +static const int ldq_l_opcode = 0x2b; +static const int stl_c_opcode = 0x2e; +static const int stq_c_opcode = 0x2f; + +/* Checks for an atomic sequence of instructions beginning with a LWARX/LDARX + instruction and ending with a STWCX/STDCX instruction. If such a sequence + is found, attempt to step through it. A breakpoint is placed at the end of + the sequence. */ + +int +alpha_deal_with_atomic_sequence (struct frame_info *frame) +{ + struct gdbarch *gdbarch = get_frame_arch (frame); + struct address_space *aspace = get_frame_address_space (frame); + CORE_ADDR pc = get_frame_pc (frame); + CORE_ADDR breaks[2] = {-1, -1}; + CORE_ADDR loc = pc; + CORE_ADDR closing_insn; /* Instruction that closes the atomic sequence. */ + unsigned int insn = alpha_read_insn (gdbarch, loc); + int insn_count; + int index; + 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_OPCODE (insn) != ldl_l_opcode + && INSN_OPCODE (insn) != ldq_l_opcode) + 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 += ALPHA_INSN_SIZE; + insn = alpha_read_insn (gdbarch, loc); + + /* 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_OPCODE (insn) >= beq_opcode) + { + /* ??? */ + int immediate = ((insn & 0x001fffff) << 2); + + if (bc_insn_count >= 1) + return 0; /* More than one conditional branch found, fallback + to the standard single-step code. */ + + breaks[1] = loc + ALPHA_INSN_SIZE + immediate; + + bc_insn_count++; + last_breakpoint++; + } + + if (INSN_OPCODE (insn) == stl_c_opcode + || INSN_OPCODE (insn) == stq_c_opcode) + break; + } + + /* Assume that the atomic sequence ends with a stwcx/stdcx instruction. */ + if (INSN_OPCODE (insn) != stl_c_opcode + && INSN_OPCODE (insn) != stq_c_opcode) + return 0; + + closing_insn = loc; + loc += ALPHA_INSN_SIZE; + + /* Insert a breakpoint right after the end of the atomic sequence. */ + breaks[0] = loc; + + /* Check for duplicated breakpoints. Check also for a breakpoint + placed (branch instruction's destination) at the stwcx/stdcx + instruction, this resets the reservation and take us back to the + lwarx/ldarx instruction at the beginning of the atomic sequence. */ + if (last_breakpoint && ((breaks[1] == breaks[0]) + || (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]); + + return 1; +} + + /* Figure out where the longjmp will land. We expect the first arg to be a pointer to the jmp_buf structure from which we extract the PC (JB_PC) that we will land at. The PC is copied @@ -1749,6 +1840,9 @@ set_gdbarch_decr_pc_after_break (gdbarch, ALPHA_INSN_SIZE); set_gdbarch_cannot_step_breakpoint (gdbarch, 1); + /* Handles single stepping of atomic sequences. */ + set_gdbarch_software_single_step (gdbarch, alpha_deal_with_atomic_sequence); + /* Hook in ABI-specific overrides, if they have been registered. */ gdbarch_init_osabi (info, gdbarch);