From a76ea826a50f9ce025b2935476c72b7e134fef25 Mon Sep 17 00:00:00 2001 From: Nurdin Premji Date: Sat, 12 Apr 2008 16:54:14 -0400 Subject: [PATCH] Initial work on stepping over signal --- frysk-core/frysk/hpd/StepCommand.java | 12 ++- frysk-core/frysk/pkglibdir/funit-signal.c | 130 +++++++++++++++++++++ frysk-core/frysk/rt/Breakpoint.java | 5 +- frysk-core/frysk/stepping/SteppingEngine.java | 83 ++++++++++++-- frysk-core/frysk/stepping/TaskStepEngine.java | 7 +- frysk-core/frysk/stepping/TestStepping.java | 89 ++++++++++++++ frysk-core/frysk/stepping/TestSteppingEngine.java | 3 +- 7 files changed, 310 insertions(+), 19 deletions(-) create mode 100644 frysk-core/frysk/pkglibdir/funit-signal.c diff --git a/frysk-core/frysk/hpd/StepCommand.java b/frysk-core/frysk/hpd/StepCommand.java index a8cc3c0..7cd854e 100644 --- a/frysk-core/frysk/hpd/StepCommand.java +++ b/frysk-core/frysk/hpd/StepCommand.java @@ -60,10 +60,17 @@ public class StepCommand extends ParameterizedCommand { ((Options)options).instruction = true; } }); + + add(new CommandOption("stepoversignal", 's', "step over signals", null) { + void parse(String argument, Object options) { + ((Options) options).stepOverSignal = true; + } + }); } private class Options { boolean instruction = false; + boolean stepOverSignal = false; } Object options() { @@ -79,7 +86,10 @@ public class StepCommand extends ParameterizedCommand { taskList.add(taskIter.next()); } if (cli.steppingObserver != null) { - + if (((Options) options).stepOverSignal == true) { + cli.getSteppingEngine().setStepOverSignal(true); + } + if (((Options) options).instruction == false) { fine.log(this, "Stepping line"); cli.getSteppingEngine().stepLine(taskList); diff --git a/frysk-core/frysk/pkglibdir/funit-signal.c b/frysk-core/frysk/pkglibdir/funit-signal.c new file mode 100644 index 0000000..e2f11fd --- /dev/null +++ b/frysk-core/frysk/pkglibdir/funit-signal.c @@ -0,0 +1,130 @@ +// This file is part of the program FRYSK. +// +// Copyright 2008, 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 volatile interfaces identified in the file named EXCEPTION found in +// the source code files (the "Approved volatile interfaces"). The files of +// Non-GPL Code may instantiate templates or use macros or inline +// functions from the Approved volatile 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 volatile 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. + +#include +#include +#include +#include +#include +#include + +pthread_t tester_thread; + + +volatile int j = 0; +volatile int lock = 1; +volatile int sig; +volatile pid_t pid; + +void +*signal_parent () +{ + while (lock); + + kill (pid, sig); + + while(1); +} + +void +handler (int sig) +{ + + if (sig == SIGUSR1) // _signalHandlerEntry_ + { + --j; + ++j; + } + else + exit(EXIT_FAILURE); + + return; + +} + +int +main (int argc, char ** argv) +{ + + if (argc < 3) + { + printf("Usage: funit-signal \n"); + exit(0); + } + + errno = 0; + pid_t target_pid = (pid_t) strtoul(argv[1], (char **) NULL, 10); + if (errno) + { + perror ("Invalid pid"); + exit (EXIT_FAILURE); + } + + errno = 0; + int signal = (int) strtoul (argv[2], (char **) NULL, 10); + if (errno) + { + perror ("Invalid signal"); + exit (EXIT_FAILURE); + } + + pid = target_pid; + sig = signal; + + struct sigaction sa; + sa.sa_handler = handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sigaction(SIGUSR1, &sa, NULL); + + pthread_create (&tester_thread, NULL, signal_parent, NULL); + + lock = 0; + + while(1) + { + --j; + ++j; + --j; + ++j; + raise(SIGUSR1); // _signalRaiseCall_ + } + return 0; + +} diff --git a/frysk-core/frysk/rt/Breakpoint.java b/frysk-core/frysk/rt/Breakpoint.java index 4066f6e..850bbb6 100644 --- a/frysk-core/frysk/rt/Breakpoint.java +++ b/frysk-core/frysk/rt/Breakpoint.java @@ -83,7 +83,7 @@ public class Breakpoint implements TaskObserver.Code { else { fine.log(this, "updateHit adding instruction observer", task, "address", address); - task.requestAddInstructionObserver(this.steppingEngine.getSteppingObserver()); + this.steppingEngine.requestAddSteppingObserver(task); this.steppingEngine.addBlocker(task, this); } @@ -106,7 +106,8 @@ public class Breakpoint implements TaskObserver.Code { monitor.notifyAll(); } // System.err.println("BreakPoint.addedTo"); - ((Task) observable).requestDeleteInstructionObserver(this.steppingEngine.getSteppingObserver()); + Task task = (Task) observable; + this.steppingEngine.requestRemoveSteppingObserver(task); } public boolean isAdded () { diff --git a/frysk-core/frysk/stepping/SteppingEngine.java b/frysk-core/frysk/stepping/SteppingEngine.java index 7ff86f1..c505407 100644 --- a/frysk-core/frysk/stepping/SteppingEngine.java +++ b/frysk-core/frysk/stepping/SteppingEngine.java @@ -53,6 +53,7 @@ import frysk.sys.ProcessIdentifier; import frysk.sys.ProcessIdentifierFactory; import lib.dwfl.DwflLine; import frysk.debuginfo.DebugInfoFrame; +import frysk.debuginfo.DebugInfoStackFactory; import frysk.event.RequestStopEvent; import frysk.proc.Action; import frysk.proc.Manager; @@ -96,6 +97,18 @@ public class SteppingEngine { /* Observer used to block Tasks, as well as providing the mechanism to * step them, by an instruction each time. */ private SteppingObserver steppingObserver; + + public void requestAddSteppingObserver(Task task) + { + task.requestAddInstructionObserver(steppingObserver); + task.requestAddSignaledObserver(steppingObserver); + } + + public void requestRemoveSteppingObserver(Task task) + { + task.requestDeleteInstructionObserver(steppingObserver); + task.requestDeleteSignaledObserver(steppingObserver); + } /* Ensures that newly spawned Tasks are maintained by the SteppingEngine * class, and also makes sure that exiting Tasks are taken care of and cleaned @@ -448,6 +461,26 @@ public class SteppingEngine { this.steppingObserver.notifyNotBlocked(tse); } } + + public void stepOverSignal(Task task) { + DebugInfoFrame frame = DebugInfoStackFactory + .createDebugInfoStackTrace(task); + + long address = frame.getAddress(); + + fine.log(this, "Looking for address: 0x", Long.toHexString(address), "Line #: ", frame.getLine().getLine()); + + TaskStepEngine tse = (TaskStepEngine) this.taskStateMap.get(task); + tse.setState(new StepOutState(task)); + this.steppingObserver.notifyNotBlocked(tse); + + int i = ((Integer) this.contextMap.get(task.getProc())).intValue(); + this.contextMap.put(task.getProc(), new Integer(++i)); + + this.breakpoint = new SteppingBreakpoint(this, address); + this.breakpointMap.put(task, this.breakpoint); + task.requestAddCodeObserver(this.breakpoint, address); + } /** * Performs a step-over operation on a list of tasks; none of the given @@ -479,6 +512,13 @@ public class SteppingEngine { } } } + + + private boolean stepOverSignal = false; + public void setStepOverSignal(boolean bol) { + fine.log(this, "Setting stepOverSignal"); + stepOverSignal = bol; + } /** * Sets the stage for stepping out of a frame. Runs until a breakpoint on the @@ -596,7 +636,7 @@ public class SteppingEngine { this.steppingObserver.notifyNotBlocked(tse); } continueForStepping(t, false); - t.requestDeleteInstructionObserver(this.steppingObserver); + requestRemoveSteppingObserver(t); } } } @@ -715,7 +755,8 @@ public class SteppingEngine { tse = (TaskStepEngine) this.taskStateMap.get(t); tse.setState(new RunningState(t)); this.steppingObserver.notifyNotBlocked(tse); - t.requestDeleteInstructionObserver(this.steppingObserver); + + requestRemoveSteppingObserver(t); } return; } else @@ -735,7 +776,7 @@ public class SteppingEngine { tse = (TaskStepEngine) this.taskStateMap.get(t); tse.setState(new RunningState(t)); this.steppingObserver.notifyNotBlocked(tse); - t.requestDeleteInstructionObserver(this.steppingObserver); + requestRemoveSteppingObserver(t); } else { /* Put all threads back into a master list */ temp.add(t); @@ -829,7 +870,7 @@ public class SteppingEngine { t.requestDeleteTerminatingObserver(this.threadLifeObservable); t.requestDeleteTerminatedObserver(this.threadLifeObservable); t.requestDeleteClonedObserver(this.threadLifeObservable); - t.requestDeleteInstructionObserver(this.steppingObserver); + requestRemoveSteppingObserver(t); cleanTask(t); } } @@ -1026,7 +1067,7 @@ public class SteppingEngine { } protected class SteppingObserver extends Observable implements - TaskObserver.Instruction { + TaskObserver.Instruction, TaskObserver.Signaled{ /** * Callback for TaskObserver.Instruction. Each time a Task is blocked, either @@ -1042,6 +1083,14 @@ public class SteppingEngine { * @return Action.BLOCK Continue blocking this incoming Task */ public synchronized Action updateExecuted(Task task) { + + DebugInfoFrame frame = DebugInfoStackFactory + .createDebugInfoStackTrace(task); + + long address = frame.getAddress(); + + fine.log(this, "At address: 0x", Long.toHexString(address), "Line #: ", frame.getLine().getLine()); + // System.err.println("SE.SO.updateEx: " + task); /* Check to see if acting upon this event produces a stopped state * change. If so, decrement the number of Tasks active in the Task's @@ -1104,6 +1153,20 @@ public class SteppingEngine { this.setChanged(); this.notifyObservers(tse); } + + + public Action updateSignaled(Task task, Signal signal) { + fine.log(this, "updateSignaled called"); + if (stepOverSignal) { + fine.log(this, "updateSignaled, stepping over"); + + requestRemoveSteppingObserver(task); + stepOverSignal(task); + fine.log(this, "finished step over signal"); + return Action.BLOCK; + } + return Action.CONTINUE; + } } public void requestAdd() { @@ -1130,7 +1193,7 @@ public class SteppingEngine { Iterator i = list.iterator(); while (i.hasNext()) { t = (Task) i.next(); - t.requestAddInstructionObserver(this.steppingObserver); + requestAddSteppingObserver(t); } } @@ -1162,8 +1225,8 @@ public class SteppingEngine { offspring, SteppingEngine.this)); SteppingEngine.this.threadsList.addLast(offspring); - offspring.requestAddInstructionObserver(SteppingEngine.this.steppingObserver); - + requestAddSteppingObserver(offspring); + offspring.requestAddClonedObserver(this); offspring.requestAddTerminatingObserver(this); offspring.requestAddTerminatedObserver(this); @@ -1302,7 +1365,7 @@ public class SteppingEngine { addy = address; fine.log(this, "updateHit task", task, "address", address, "adding instruction observer"); - task.requestAddInstructionObserver(SteppingEngine.this.steppingObserver); + requestAddSteppingObserver(task); } ++triggered; @@ -1326,7 +1389,7 @@ public class SteppingEngine { } Task t = (Task) observable; - t.requestDeleteInstructionObserver(steppingObserver); + requestRemoveSteppingObserver(t); continueForStepping(t, false); } diff --git a/frysk-core/frysk/stepping/TaskStepEngine.java b/frysk-core/frysk/stepping/TaskStepEngine.java index be1cf4b..9120fd5 100644 --- a/frysk-core/frysk/stepping/TaskStepEngine.java +++ b/frysk-core/frysk/stepping/TaskStepEngine.java @@ -183,17 +183,16 @@ public class TaskStepEngine { } /** - * Returns the current State of this TaskStepEngine's Task. + * Sets the current State of this TaskStepEngine's Task. * - * @param newState - * The current State of this TaskStepEngine's Task + * @param newState The new State of this TaskStepEngine's Task */ public void setState(State newState) { this.state = newState; } /** - * Sets the current State of this TaskStepEngine's Task. + * Returns the current State of this TaskStepEngine's Task. * * @return state The current State of this TaskStepEngine's Task. */ diff --git a/frysk-core/frysk/stepping/TestStepping.java b/frysk-core/frysk/stepping/TestStepping.java index b14c4f3..059a7c6 100644 --- a/frysk-core/frysk/stepping/TestStepping.java +++ b/frysk-core/frysk/stepping/TestStepping.java @@ -135,6 +135,9 @@ public class TestStepping extends TestLib { assertTrue("Line information present", frame.getLine() != SourceLocation.UNKNOWN); /** The stepping operation */ + + //Send a signal to myTask + this.se.stepLine(theTask); this.testStarted = true; @@ -443,6 +446,91 @@ public class TestStepping extends TestLib { assertRunUntilStop("Running test"); cleanup(); } + + public void testStepThroughSignal() { + /** Variable setup */ + + String source = Config.getRootSrcDir() + + "frysk-core/frysk/pkglibdir/funit-signal.c"; + + this.scanner = new TestfileTokenScanner(new File(source)); + + /* The line number where the test begins */ + int start = this.scanner.findTokenLine("_signalRaiseCall_"); + + /* The line number the test should end up at */ + int end = this.scanner.findTokenLine("_signalHandlerEntry_"); + + /* The test process */ + SynchronizedOffspring process + = new SynchronizedOffspring(Signal.USR1, + new String[] { + getExecPath("funit-signal"), + Integer.toString(Pid.get().intValue()), + Integer.toString(Signal.USR1.intValue()) + }); + this.testStarted = false; + + /** Test initialization */ + Task myTask = initTask(process, source, start, end); + + this.currentTest = new AssertLine(end, myTask); + + DebugInfoFrame frame = DebugInfoStackFactory + .createDebugInfoStackTrace(myTask); + assertTrue("Line information present", frame.getLine() != SourceLocation.UNKNOWN); + + /** The stepping operation */ + this.se.stepLine(myTask); + + this.testStarted = true; + + /** Run to completion */ + assertRunUntilStop("Running test"); + cleanup(); + } + + public void testStepOverSignal() { + /** Variable setup */ + + String source = Config.getRootSrcDir() + + "frysk-core/frysk/pkglibdir/funit-signal.c"; + + this.scanner = new TestfileTokenScanner(new File(source)); + + /* The line number where the test begins */ + int start = this.scanner.findTokenLine("_signalRaiseCall_"); + + /* The test process */ + SynchronizedOffspring process + = new SynchronizedOffspring(Signal.USR1, + new String[] { + getExecPath("funit-signal"), + Integer.toString(Pid.get().intValue()), + Integer.toString(Signal.USR1.intValue()) + }); + this.testStarted = false; + + /** Test initialization */ + Task myTask = initTask(process, source, start, start); + + this.se.setStepOverSignal(true); + + this.currentTest = new AssertLine(start, myTask); + + DebugInfoFrame frame = DebugInfoStackFactory + .createDebugInfoStackTrace(myTask); + assertTrue("Line information present", frame.getLine() != SourceLocation.UNKNOWN); + + /** The stepping operation */ + this.se.stepLine(myTask); + + this.testStarted = true; + + /** Run to completion */ + assertRunUntilStop("Running test"); + cleanup(); + } public void testASMSingleStep() { @@ -1151,6 +1239,7 @@ public class TestStepping extends TestLib { DebugInfoFrame frame = DebugInfoStackFactory .createDebugInfoStackTrace(task); int lineNr = frame.getLine().getLine(); + assertEquals("line number", success, lineNr); Manager.eventLoop.requestStop(); } diff --git a/frysk-core/frysk/stepping/TestSteppingEngine.java b/frysk-core/frysk/stepping/TestSteppingEngine.java index af0da7f..e4e49d3 100644 --- a/frysk-core/frysk/stepping/TestSteppingEngine.java +++ b/frysk-core/frysk/stepping/TestSteppingEngine.java @@ -335,8 +335,7 @@ public class TestSteppingEngine extends TestLib { assertTrue("Line information present", frame.getLine() != SourceLocation.UNKNOWN); /** The stepping operation */ - this.se.stepOver(theTask, DebugInfoStackFactory - .createDebugInfoStackTrace(theTask)); + this.se.stepOver(theTask, frame); this.testStarted = true; // System.err.println("waiting for finish"); -- 1.5.4.1