List Info

Thread: Re: How to avoid stepping inside libpthread




Re: How to avoid stepping inside libpthread
user name
2007-07-13 02:03:41
On Thu, 12 Jul 2007 07:10:21 -0400, Daniel Jacobowitz
<drowfalse.org> wrote:
> > +      /* Assume that there is at most one branch
in the atomic
> > +	 sequence.  If a branch is found, put a
breakpoint in its
> > +	 destination address.  */
> > +      branch_bp = mips_next_pc (loc);
> > +      if (branch_bp != loc + MIPS_INSN32_SIZE)
> 
> That's not what you want to do.  mips_next_pc decides
based on the
> current registers whether each branch is taken or not
taken, so this
> will not detect untaken branches (and it's got the
wrong set of
> registers, since loc != current pc).  I think we'll
have to make
> mips_next_pc return whether a control flow changing
instruction was
> found.  Possibly whether an acceptable branch was
found, to avoid
> subroutine calls, if that's going to be a problem.

Oh yes, thank you for suggestion.  Here is an updated patch
against
current snapshot.

--- gdb-6.6.50.20070711.org/gdb/mips-tdep.c	2007-06-19
02:45:26.000000000 +0900
+++ gdb-6.6.50.20070711/gdb/mips-tdep.c	2007-07-13
16:02:01.000000000 +0900
 -2293,6
+2293,111  mips_addr_bits_remove (CORE_ADDR addr)
     return addr;
 }
 
+/* Instructions used during single-stepping of atomic
sequences.  */
+#define LL_OPCODE 0x30
+#define LLD_OPCODE 0x34
+#define SC_OPCODE 0x38
+#define SCD_OPCODE 0x3c
+
+/* Checks for an atomic sequence of instructions beginning
with a LL/LLD
+   instruction and ending with a SC/SCD instruction.  If
such a sequence
+   is found, attempt to step through it.  A breakpoint is
placed at the end of 
+   the sequence.  */
+
+static int
+deal_with_atomic_sequence (CORE_ADDR pc)
+{
+  CORE_ADDR breaks[2] = {-1, -1};
+  CORE_ADDR loc = pc;
+  CORE_ADDR branch_bp; /* Breakpoint at branch
instruction's destination.  */
+  unsigned long insn;
+  int insn_count;
+  int index;
+  int last_breakpoint = 0; /* Defaults to 0 (no breakpoints
placed).  */  
+  const int atomic_sequence_length = 16; /* Instruction
sequence length.  */
+
+  if (pc & 0x01)
+    return 0;
+
+  insn = mips_fetch_instruction (loc);
+  /* Assume all atomic sequences start with a ll/lld
instruction.  */
+  if (itype_op (insn) != LL_OPCODE && itype_op
(insn) != LLD_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)
+    {
+      int is_branch = 0;
+      loc += MIPS_INSN32_SIZE;
+      insn = mips_fetch_instruction (loc);
+
+      /* Assume that there is at most one branch in the
atomic
+	 sequence.  If a branch is found, put a breakpoint in its
+	 destination address.  */
+      switch (itype_op (insn))
+	{
+	case 0: /* SPECIAL */
+	  if (rtype_funct (insn) >> 1 == 4) /* JR, JALR */
+	    return 0; /* fallback to the standard single-step
code. */
+	  break;
+	case 1: /* REGIMM */
+	  is_branch = ((itype_rt (insn) & 0xc0) == 0); /*
B{LT,GE}Z* */
+	  break;
+	case 2: /* J */
+	case 3: /* JAL */
+	  return 0; /* fallback to the standard single-step code.
*/
+	case 4: /* BEQ */
+	case 5: /* BNE */
+	case 6: /* BLEZ */
+	case 7: /* BGTZ */
+	case 20: /* BEQL */
+	case 21: /* BNEL */
+	case 22: /* BLEZL */
+	case 23: /* BGTTL */
+	  is_branch = 1;
+	  break;
+	case 17: /* COP1 */
+	case 18: /* COP2 */
+	case 19: /* COP3 */
+	  is_branch = (itype_rs (insn) == 8); /* BCzF, BCzFL,
BCzT, BCzTL */
+	  break;
+	}
+      if (is_branch)
+	{
+	  branch_bp = loc + mips32_relative_offset (insn) + 4;
+	  if (last_breakpoint >= 1)
+	    return 0; /* More than one branch found, fallback to
the
+			 standard single-step code.  */
+	  breaks[1] = branch_bp;
+	  last_breakpoint++;
+	}
+
+      if (itype_op (insn) == SC_OPCODE || itype_op (insn)
== SCD_OPCODE)
+	break;
+    }
+
+  /* Assume that the atomic sequence ends with a sc/scd
instruction.  */
+  if (itype_op (insn) != SC_OPCODE && itype_op
(insn) != SCD_OPCODE)
+    return 0;
+
+  loc += MIPS_INSN32_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) in the
atomic sequence */
+  if (last_breakpoint && pc <= breaks[1]
&& breaks[1] <= breaks[0])
+    last_breakpoint = 0;
+
+  /* Effectively inserts the breakpoints.  */
+  for (index = 0; index <= last_breakpoint; index++)
+      insert_single_step_breakpoint (breaks[index]);
+
+  return 1;
+}
+
 /* mips_software_single_step() is called just before we
want to resume
    the inferior, if we want to single-step it but there is
no hardware
    or kernel single-step support (MIPS on GNU/Linux for
example).  We find
 -2304,6
+2409,9  mips_software_single_step (struct frame_
   CORE_ADDR pc, next_pc;
 
   pc = get_frame_pc (frame);
+  if (deal_with_atomic_sequence (pc))
+    return 1;
+
   next_pc = mips_next_pc (frame, pc);
 
   insert_single_step_breakpoint (next_pc);

Re: How to avoid stepping inside libpthread
country flaguser name
United States
2007-09-26 11:06:50
On Fri, Jul 13, 2007 at 04:03:41PM +0900, Atsushi Nemoto
wrote:
> Oh yes, thank you for suggestion.  Here is an updated
patch against
> current snapshot.

Hi Atsushi,

I'm sorry I never got back to you about this.  I tried your
patch
today and it seems to work.  But do you have an FSF
copyright
assignment, or are you planning on getting one?  This is
too
substantial for us to merge it without one.

-- 
Daniel Jacobowitz
CodeSourcery

[1-2]

about | contact  Other archives ( Real Estate discussion Medical topics )