This is the mail archive of the frysk@sources.redhat.com mailing list for the frysk project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

step-by-step


Hi,

This adds a first pass at the stepping Instruction observer. There
aren't any new testcases yet (but a little demo program will follow
right after this email). All existing tests of course PASS. More tests,
to see how the new observer interacts with the other observers will be
added tomorrow.

I am posting this now so people can start looking at it and maybe try it
out to see if it fits in their use cases. I also thought it might be
useful as a simple way to have a blocking observer for a Task (although
it might not be ideal, I'll reply to Nurdins post).

This uses the needsSuspendedAction support in TaskObservation. No actual
action is really needed for a stepping Instruction observer, but the
Task must be suspended when this observer is added so it can start
stepping from then on. Every place where we used to check for a 'normal'
or a 'syscall' ptrace continue we now have a new check whether we need a
'stepping' ptrace continue for the Task.

2006-10-12  Mark Wielaard  <mark@klomp.org>

    * Proc.java (InstructionAction): New static inner class.
    (requestAddInstructionObserver): New method.
    (requestDeleteInstructionObserver): New method.
    * Task.java (instructionObservers): New field.
    (requestAddInstructionObserver): New method.
    (requestDeleteInstructionObserver): New method.
    (notifyInstruction): New method.
    * TaskObserver.java (Instruction): Update documentation.
    * TaskState.java: Check whether instruction observers are installed
    and do a sendStepInstruction() instead of a sendContinue() or
    sendSyscallContinue().
    (Running.handleTrappedEvent): Also check for instruction observer
    steps.

Committed. Comments welcome.

Cheers,

Mark
Index: frysk-core/frysk/proc/Proc.java
===================================================================
RCS file: /cvs/frysk/frysk-core/frysk/proc/Proc.java,v
retrieving revision 1.83
diff -u -r1.83 Proc.java
--- frysk-core/frysk/proc/Proc.java	11 Oct 2006 16:04:37 -0000	1.83
+++ frysk-core/frysk/proc/Proc.java	12 Oct 2006 21:22:22 -0000
@@ -598,6 +598,80 @@
       Manager.eventLoop.add(to);
     }
 
+
+    /**
+     * Class describing the action to take on the suspended Task
+     * before adding or deleting an Instruction observer. No
+     * particular actions are needed, but we must make sure the Task
+     * is suspended.
+     */
+    final static class InstructionAction implements Runnable
+    {
+      public void run()
+      {
+	// There is nothing in particular we need to do.  We just want
+	// to make sure the Task is stopped so we can send it a step
+	// instruction or, when deleted, start resuming the process
+	// normally.
+      }
+    }
+
+    /**
+     * (Internal) Tell the process to add the specified Instruction
+     * Observation, attaching and/or suspending the process if
+     * necessary.  As soon as the observation is added and the task
+     * isn't blocked it will inform the Instruction observer of every
+     * step of the task.
+     */
+    void requestAddInstructionObserver (final Task task,
+					TaskObservable observable,
+					TaskObserver.Instruction observer)
+    {
+      logger.log (Level.FINE, "{0} requestAddInstructionObserver\n", this); 
+      TaskObservation to;
+      InstructionAction ia = new InstructionAction();
+      to = new TaskObservation(task, observable, observer, ia, true)
+	{
+	  public void execute ()
+	  {
+	    handleAddObservation (this);
+	  }
+	  
+	  public boolean needsSuspendedAction()
+	  {
+	    return task.instructionObservers.numberOfObservers() == 0;
+	  }
+	};
+      Manager.eventLoop.add(to);
+    }
+    
+    /**
+     * (Internal) Tell the process to delete the specified Instruction
+     * Observation, detaching and/or suspending from the process if
+     * necessary.
+     */
+    void requestDeleteInstructionObserver (final Task task,
+					   TaskObservable observable,
+					   TaskObserver.Instruction observer)
+    {
+      logger.log (Level.FINE, "{0} requestDeleteInstructionObserver\n", this); 
+      TaskObservation to;
+      InstructionAction ia = new InstructionAction();
+      to = new TaskObservation(task, observable, observer, ia, false)
+	{
+	  public void execute ()
+	  {
+	    handleAddObservation (this);
+	  }
+	  
+	  public boolean needsSuspendedAction()
+	  {
+	    return task.instructionObservers.numberOfObservers() == 1;
+	  }
+	};
+      Manager.eventLoop.add(to);
+    }
+
     /**
      * Table of this processes child processes.
      */
Index: frysk-core/frysk/proc/Task.java
===================================================================
RCS file: /cvs/frysk/frysk-core/frysk/proc/Task.java,v
retrieving revision 1.103
diff -u -r1.103 Task.java
--- frysk-core/frysk/proc/Task.java	11 Oct 2006 16:04:37 -0000	1.103
+++ frysk-core/frysk/proc/Task.java	12 Oct 2006 21:22:22 -0000
@@ -917,6 +917,52 @@
     return blockers.size();
   }
 
+  /**
+   * Set of Instruction observers.
+   */
+  TaskObservable instructionObservers = new TaskObservable(this);
+  
+  /**
+   * Request the addition of a Instruction observer that will be
+   * notified as soon as the task executes an instruction.
+   * <code>o.updateExecuted</code> is called as soon as the Task
+   * starts running again (is not blocked or stopped) and executes the
+   * next instruction.
+   */
+  public void requestAddInstructionObserver(TaskObserver.Instruction o)
+  {
+    logger.log(Level.FINE, "{0} requestAddInstructionObserver\n", this);
+    proc.requestAddInstructionObserver(this, instructionObservers, o);
+  }
+
+  /**
+   * Delete TaskObserver.Instruction from the TaskObserver pool.
+   */
+  public void requestDeleteInstructionObserver (TaskObserver.Instruction o)
+  {
+    logger.log(Level.FINE, "{0} requestDeleteInstructionObserver\n", this);
+    proc.requestDeleteInstructionObserver(this, instructionObservers, o);
+  }
+  
+  /**
+   * Notify all Instruction observers. Returns the total number of
+   * blocking observers.
+   */
+  int notifyInstruction()
+  {
+    logger.log(Level.FINE, "{0} notifyInstruction()\n", this);
+    
+    Iterator i = instructionObservers.iterator();
+    while (i.hasNext())
+      {
+	TaskObserver.Instruction observer;
+	observer = (TaskObserver.Instruction) i.next();
+	if (observer.updateExecuted(this) == Action.BLOCK)
+	  blockers.add(observer);
+      }
+    return blockers.size();
+  }
+
   // List containing the TaskObservations that are pending addition
   // or deletion (in order that they were requested). Will be dealt with
   // as soon as a stop event is received during one of the running states.
Index: frysk-core/frysk/proc/TaskObserver.java
===================================================================
RCS file: /cvs/frysk/frysk-core/frysk/proc/TaskObserver.java,v
retrieving revision 1.17
diff -u -r1.17 TaskObserver.java
--- frysk-core/frysk/proc/TaskObserver.java	21 Sep 2006 16:45:01 -0000	1.17
+++ frysk-core/frysk/proc/TaskObserver.java	12 Oct 2006 21:22:22 -0000
@@ -177,7 +177,9 @@
 
     /**
      * Interface used to notify that a Task has executed a single
-     * instruction.
+     * instruction. <code>updateExecuted</code> is called as soon after
+     * the Instruction observer is added to the Task and the Task starts
+     * running again (isn't blocked or suspended).
      */
     public interface Instruction
 	extends TaskObserver
Index: frysk-core/frysk/proc/TaskState.java
===================================================================
RCS file: /cvs/frysk/frysk-core/frysk/proc/TaskState.java,v
retrieving revision 1.121
diff -u -r1.121 TaskState.java
--- frysk-core/frysk/proc/TaskState.java	11 Oct 2006 16:04:37 -0000	1.121
+++ frysk-core/frysk/proc/TaskState.java	12 Oct 2006 21:22:22 -0000
@@ -296,7 +296,12 @@
 	    task.sendSetOptions();
 	    if (task.notifyAttached () > 0)
 	      return new BlockedSignal(signal, false);
-	    if (task.syscallObservers.numberOfObservers() > 0)
+	    if (task.instructionObservers.numberOfObservers() > 0)
+	      {
+		task.sendStepInstruction(signal);
+		return running;
+	      }
+	    else if (task.syscallObservers.numberOfObservers() > 0)
 	      {
 		task.sendSyscallContinue(signal);
 		return syscallRunning;
@@ -606,6 +611,7 @@
 	    // XXX: Really notify attached here?
 	    if (task.notifyAttached () > 0)
                 return blockedContinue;
+	    // XXX - What about syscall or instruction observers?
 	    task.sendContinue (0);
 	    return running;
 	}
@@ -663,7 +669,12 @@
 		      {
 			return blockedContinue;
 		      }
-		    if (task.syscallObservers.numberOfObservers() > 0)
+		    if (task.instructionObservers.numberOfObservers() > 0)
+		      {
+			task.sendStepInstruction(0);
+			return running;
+		      }
+		    else if (task.syscallObservers.numberOfObservers() > 0)
 		      {
 			task.sendSyscallContinue (0);
 			return syscallRunning;
@@ -702,7 +713,9 @@
 	 */
         private void sendContinue(Task task, int sig)
         {
-	  if (syscalltracing)
+	  if (task.instructionObservers.numberOfObservers() > 0)
+	    task.sendStepInstruction(sig);
+	  else if (syscalltracing)
 	    task.sendSyscallContinue(sig);
 	  else
 	    task.sendContinue(sig);
@@ -733,8 +746,10 @@
 	TaskState handleStoppedEvent (Task task)
 	{
 	  Collection pendingObservations = task.pendingObservations;
+	  // XXX Real stop event! - Do we want observers here?
+	  // What state should the task be after being stopped?
 	  if (pendingObservations.isEmpty())
-	    throw new RuntimeException("Whoa!");
+	    throw new RuntimeException("Unhandled real stop event");
 
 	  Iterator it = pendingObservations.iterator();
 	  while (it.hasNext())
@@ -747,7 +762,13 @@
 	      it.remove();
 	    }
 
-	  if (task.syscallObservers.numberOfObservers() > 0)
+	  // See how to continue depending on the kind of observers.
+	  if (task.instructionObservers.numberOfObservers() > 0)
+	    {
+	      task.sendStepInstruction(0);
+	      return insyscall ? inSyscallRunning : running;
+	    }
+	  else if (task.syscallObservers.numberOfObservers() > 0)
 	    {
 	      task.sendSyscallContinue(0);
 	      return insyscall ? inSyscallRunningTraced : syscallRunning;
@@ -814,6 +835,11 @@
 	      }
 	    else
 	      {
+		if (task.instructionObservers.numberOfObservers() > 0)
+		  {
+		    task.sendStepInstruction(0);
+		    return inSyscallRunning;
+		  }
 		if (syscalltracing)
 		  {
 		    task.sendSyscallContinue(0);
@@ -861,12 +887,15 @@
 	}
 
       /**
-       * Handles traps caused by breakpoints. If there are any Code
-       * observers at the address of the trap they get notified. If
-       * none of the Code observers blocks we continue over the
-       * breakpoint (breakpoint stepping state), otherwise we block
-       * till all blocking observers are happy (breakpoint stopped
-       * state).
+       * Handles traps caused by breakpoints or instruction
+       * stepping. If there are any Code observers at the address of
+       * the trap they get notified. If none of the Code observers
+       * blocks we continue over the breakpoint (breakpoint stepping
+       * state), otherwise we block till all blocking observers are
+       * happy (breakpoint stopped state). If there are no Code observers
+       * installed at the address, but we are stepping then all instruction
+       * observers are notified. Otherwise it is a real trap event and we
+       * pass it on to the task itself.
        */
       TaskState handleTrappedEvent (Task task)
       {
@@ -899,8 +928,22 @@
 	int blockers = task.notifyCodeBreakpoint(address);
 	if (blockers == -1)
 	  {
-	    // This is not a trap event generated by us.
-	    return handleSignaledEvent (task, Sig.TRAP_);
+	    // Maybe we were stepping this Task
+	    if (task.instructionObservers.numberOfObservers() > 0)
+	      {
+		if (task.notifyInstruction() > 0)
+		  return blockedContinue();
+		else
+		  {
+		    sendContinue(task, 0);
+		    return this;
+		  }
+	      }
+	    else
+	      {
+		// This is not a trap event generated by us.
+		return handleSignaledEvent (task, Sig.TRAP_);
+	      }
 	  }
 	else if (blockers == 0)
 	  {
@@ -971,12 +1014,12 @@
 	    if (insyscall && task.notifySyscallExit() > 0)
 	      return blockedContinue;
 
-	    task.sendSyscallContinue(0);
+	    sendContinue(task, 0);
 	    return insyscall ? syscallRunning : inSyscallRunningTraced;
 	  }
 	else
 	  {
-	    task.sendContinue(0);
+	    sendContinue(task, 0);
 	    return this;
 	  }
       }
@@ -1127,6 +1170,11 @@
 	    task.blockers.remove (observer);
 	    if (task.blockers.size () > 0)
 		return this; // Still blocked.
+	    if (task.instructionObservers.numberOfObservers() > 0)
+	      {
+		task.sendStepInstruction(sig);
+		return running;
+	      }
 	    if (task.syscallObservers.numberOfObservers() > 0)
 	      {
 		task.sendSyscallContinue(sig);

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]