This is the mail archive of the frysk@sourceware.org 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]

[patch] Make fstep really start at the first instruction


Hi,

fstep had a bug (http://sourceware.org/bugzilla/show_bug.cgi?id=4668)
where it would not wait till the instruction observer would be attached
which meant it would miss the first few instructions. Fixing that by
blocking, waiting for the observer to be properly installed and only
then continuing made fstep start in the dynamic loader. Since this is
probably not what the user is interested in we now put a breakpoint at
the real process entry point (which will be entered by the dynamic
loader) and then insert an Instruction observer. Doing this revealed a
bug in the wantToAttachContinue state that didn't handle observer
addition and unblocking (I thought there was a bug report for this
already, but couldn't find it).

The following is a patch for all this and a new test case.

frysk-core/frysk/bindir/ChangeLog
2007-07-09  Mark Wielaard  <mwielaard@redhat.com>

    Fixes bug #4668
    * fstep.java: Implement TaskObserver.Code.
    (updateAttached): Depending on whether or not the user supplied a
    command line to execute or a pid to trace either put a breakpoint
    on the first real instruction or start tracing immediately. Return
    Action.BLOCK.
    (updateHit): New method.
    (addedTo): Unblock task.
    * TestFStep.java: New test.

frysk-core/frysk/proc/live/ChangeLog
2007-07-09  Mark Wielaard  <mwielaard@redhat.com>

    * LinuxTaskState.java (wantToAttachContinue): Add
    handleAddObservation() and handleUnblock().

Tested on x86 Fedora 7 and x86_64 Fedora Core 6. No regressions and the
new test passes.

The trick of exec, attaching, blocking, inserting a code observer on the
process entry point and presenting the user with the process starting at
that address might also be appropriate for the fhpd and frysk-gui.

Cheers,

Mark
Index: frysk-core/frysk/bindir/TestFStep.java
===================================================================
RCS file: frysk-core/frysk/bindir/TestFStep.java
diff -N frysk-core/frysk/bindir/TestFStep.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ frysk-core/frysk/bindir/TestFStep.java	9 Jul 2007 16:12:38 -0000
@@ -0,0 +1,84 @@
+// This file is part of the program FRYSK.
+//
+// Copyright 2007, Red Hat Inc.
+//
+// FRYSK is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// FRYSK is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with FRYSK; if not, write to the Free Software Foundation,
+// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+// 
+// In addition, as a special exception, Red Hat, Inc. gives You the
+// additional right to link the code of FRYSK with code not covered
+// under the GNU General Public License ("Non-GPL Code") and to
+// distribute linked combinations including the two, subject to the
+// limitations in this paragraph. Non-GPL Code permitted under this
+// exception must only link to the code of FRYSK through those well
+// defined interfaces identified in the file named EXCEPTION found in
+// the source code files (the "Approved Interfaces"). The files of
+// Non-GPL Code may instantiate templates or use macros or inline
+// functions from the Approved Interfaces without causing the
+// resulting work to be covered by the GNU General Public
+// License. Only Red Hat, Inc. may make changes or additions to the
+// list of Approved Interfaces. You must obey the GNU General Public
+// License in all respects for all of the FRYSK code and other code
+// used in conjunction with FRYSK except the Non-GPL Code covered by
+// this exception. If you modify this file, you may extend this
+// exception to your version of the file, but you are not obligated to
+// do so. If you do not wish to provide this exception without
+// modification, you must delete this exception statement from your
+// version and license this file solely under the GPL without
+// exception.
+
+
+package frysk.bindir;
+
+import java.io.File;
+
+import frysk.Config;
+import frysk.expunit.*;
+
+import frysk.proc.TestLib;
+
+import lib.elf.*;
+
+public class TestFStep
+  extends TestLib
+{
+  // Makes sure that fstep at least comes across the entry point of the
+  // stepped program.
+  public void testFirstStep() throws Exception
+  {
+    Elf e = new Elf("/bin/true", ElfCommand.ELF_C_READ);
+    try
+      {
+	ElfEHeader h = e.getEHeader();
+	final String entryAddress = "0x" + Long.toHexString(h.entry);
+
+	String command;
+	command = new File(Config.getBinDir(), "fstep").getAbsolutePath();
+	String argument = "/bin/true";
+	Expect expect = new Expect(new String[] { command, argument });
+	try
+	  {
+	    Regex regex = new Regex("^\\[\\d+\\]\t" + entryAddress + "\t");
+	    expect.expect(regex);
+	  }
+	finally
+	  {
+	    expect.close();
+	  }
+      }
+    finally
+      {
+	e.close();
+      }
+  }
+}
Index: frysk-core/frysk/bindir/fstep.java
===================================================================
RCS file: /cvs/frysk/frysk-core/frysk/bindir/fstep.java,v
retrieving revision 1.9
diff -u -r1.9 fstep.java
--- frysk-core/frysk/bindir/fstep.java	4 Jul 2007 22:14:25 -0000	1.9
+++ frysk-core/frysk/bindir/fstep.java	9 Jul 2007 16:12:38 -0000
@@ -47,6 +47,7 @@
 
 public class fstep
   implements TaskObserver.Attached,
+  TaskObserver.Code,
   TaskObserver.Instruction,
   TaskObserver.Terminated
 {
@@ -194,11 +195,44 @@
 
     tasks.put(task, Long.valueOf(0));
 
-    task.requestAddTerminatedObserver(this);
+    // If this is an attach for a command given on the command line
+    // then we want to start stepping at the actual start of the
+    // process (and not inside the dynamic linker).
+    long startAddress = 0;
+    if (command != null && command.length != 0)
+      {
+	Auxv[] auxv = task.getProc().getAuxv ();
+	for (int i = 0; i < auxv.length; i++)
+	  {
+	    if (auxv[i].type == inua.elf.AT.ENTRY)
+	      {
+		startAddress = auxv[i].val;
+		break;
+	      }
+	  }
+      }
+
+    if (startAddress == 0)
+      {
+	// Immediately start tracing steps.
+	task.requestAddInstructionObserver(this);
+	task.requestAddTerminatedObserver(this);
+      }
+    else
+      task.requestAddCodeObserver(this, startAddress);
+    return Action.BLOCK;
+  }
+
+  // TaskObserver.Code interface
+  public Action updateHit(Task task, long address)
+  {
+    task.requestDeleteCodeObserver(this, address);
     task.requestAddInstructionObserver(this);
-    return Action.CONTINUE;
+    task.requestAddTerminatedObserver(this);
+    return Action.BLOCK;
   }
 
+
   // TaskObserver.Terminated interface
   public Action updateTerminated(Task task, boolean signal, int exit)
   {
@@ -240,7 +274,8 @@
 
   public void addedTo (Object observable)
   {
-    // Unused
+    Task task = (Task) observable;
+    task.requestUnblock(this);
   }
 
   public void addFailed (Object observable, Throwable w)
Index: frysk-core/frysk/proc/live/LinuxTaskState.java
===================================================================
RCS file: /cvs/frysk/frysk-core/frysk/proc/live/LinuxTaskState.java,v
retrieving revision 1.2
diff -u -r1.2 LinuxTaskState.java
--- frysk-core/frysk/proc/live/LinuxTaskState.java	27 Jun 2007 12:47:20 -0000	1.2
+++ frysk-core/frysk/proc/live/LinuxTaskState.java	9 Jul 2007 16:12:38 -0000
@@ -534,6 +534,22 @@
 		    logger.log (Level.FINE, "{0} handleSignaledEvent\n", task);
 		    return blockOrAttachContinue (task, signal);
 		}
+
+	      // Adding or removing observers doesn't impact this state.
+	      public TaskState handleAddObservation(Task task,
+						    TaskObservation to)
+	      {
+		logger.log (Level.FINE, "{0} handleAddObservation\n", task);
+		to.add();
+		return this;
+	      }
+	      public TaskState handleUnblock (Task task,
+					      TaskObserver observer)
+	      {
+		logger.log (Level.FINE, "{0} handleUnblock\n", task); 
+		task.blockers.remove(observer);
+		return this;
+	      }
 	    };
 	/**
 	 * The task has stopped; just waiting for all the blockers to

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