Index: frysk-core/frysk/pkglibdir/funit-alarm.c =================================================================== RCS file: frysk-core/frysk/pkglibdir/funit-alarm.c diff -N frysk-core/frysk/pkglibdir/funit-alarm.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ frysk-core/frysk/pkglibdir/funit-alarm.c 12 Feb 2007 15:05:34 -0000 @@ -0,0 +1,98 @@ +// 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. + +#include +#include +#include +#include +#include + +// When counter is zero stop. +static volatile int counter; + +// Dummy counter to increment so we look busy. +static volatile int i; + +// struct to set itimer. +static struct itimerval ival; + +static void +signal_handler(int sig) +{ + if (sig == SIGPROF) + { + counter--; + if (counter == 0) + { + // Shutdown timer. + ival.it_value.tv_sec = 0; + ival.it_value.tv_usec = 0; + setitimer (ITIMER_PROF, &ival, NULL); + } + } + else + { + fprintf (stderr, "Wrong signal recieved %d\n", sig); + exit (-1); + } +} + +int +main (int argc, char *argv[]) +{ + counter = 3; + + signal (SIGPROF, &signal_handler); + + // Setup a timer to fire after 0.005 seconds again and again. + ival.it_value.tv_sec = 0; + ival.it_value.tv_usec = 5000; + ival.it_interval.tv_sec = 0; + ival.it_interval.tv_usec = 5000; + if (setitimer (ITIMER_PROF, &ival, NULL) != 0) + { + perror ("setitimer failed"); + exit (-1); + } + + while (counter > 0) + i += counter; // Do something useful... + + return 0; +} Index: frysk-core/frysk/proc/Isa.java =================================================================== RCS file: /cvs/frysk/frysk-core/frysk/proc/Isa.java,v retrieving revision 1.17 diff -u -u -r1.17 Isa.java --- frysk-core/frysk/proc/Isa.java 7 Feb 2007 18:08:25 -0000 1.17 +++ frysk-core/frysk/proc/Isa.java 12 Feb 2007 15:05:34 -0000 @@ -1,6 +1,6 @@ // This file is part of the program FRYSK. // -// Copyright 2005, 2006 Red Hat Inc. +// Copyright 2005, 2006, 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 @@ -127,6 +127,12 @@ boolean hasExecutedSpuriousTrap(Task task); /** + * Returns true if the given Task is at an instruction that will invoke + * the sig return system call. + */ + boolean isAtSyscallSigReturn(Task task); + + /** * Return an array of ByteBuffers for accessing the register * banks. It's possible for different elements of the array to be * shared. Index: frysk-core/frysk/proc/IsaIA32.java =================================================================== RCS file: /cvs/frysk/frysk-core/frysk/proc/IsaIA32.java,v retrieving revision 1.16 diff -u -u -r1.16 IsaIA32.java --- frysk-core/frysk/proc/IsaIA32.java 7 Feb 2007 18:08:25 -0000 1.16 +++ frysk-core/frysk/proc/IsaIA32.java 12 Feb 2007 15:05:34 -0000 @@ -325,6 +325,27 @@ && task.getMemory().getByte(address - 2) == (byte) 0xcd); } + /** + * Returns true if the given Task is at an instruction that will invoke + * the sig return system call. + * + * On x86 this is when the pc is at a int 0x80 instruction and the + * eax register contains 0x77. + */ + public boolean isAtSyscallSigReturn(Task task) + { + long address = pc(task); + boolean result = (task.getMemory().getByte(address) == (byte) 0xcd + && task.getMemory().getByte(address + 1) == (byte) 0x80); + if (result) + { + Register eax = getRegisterByName("eax"); + long syscall_num = eax.get(task); + result &= syscall_num == 0x77; + } + return result; + } + public Syscall[] getSyscallList () { return LinuxIa32Syscall.syscallList; Index: frysk-core/frysk/proc/IsaPowerPC.java =================================================================== RCS file: /cvs/frysk/frysk-core/frysk/proc/IsaPowerPC.java,v retrieving revision 1.3 diff -u -u -r1.3 IsaPowerPC.java --- frysk-core/frysk/proc/IsaPowerPC.java 7 Feb 2007 18:08:25 -0000 1.3 +++ frysk-core/frysk/proc/IsaPowerPC.java 12 Feb 2007 15:05:34 -0000 @@ -133,6 +133,18 @@ return false; } + /** + * Returns true if the given Task is at an instruction that will invoke + * the sig return system call. + * + * FIXME On powerpc this method is not yet implemented and always + * return false. + */ + public boolean isAtSyscallSigReturn(Task task) + { + return false; + } + public Syscall[] getSyscallList () { return LinuxPowerPCSyscall.syscallList; Index: frysk-core/frysk/proc/IsaX8664.java =================================================================== RCS file: /cvs/frysk/frysk-core/frysk/proc/IsaX8664.java,v retrieving revision 1.8 diff -u -u -r1.8 IsaX8664.java --- frysk-core/frysk/proc/IsaX8664.java 7 Feb 2007 18:08:25 -0000 1.8 +++ frysk-core/frysk/proc/IsaX8664.java 12 Feb 2007 15:05:34 -0000 @@ -314,6 +314,27 @@ return false; } + /** + * Returns true if the given Task is at an instruction that will invoke + * the sig return system call. + * + * On x86_64 this is when the pc is at a 'syscall' instruction and the + * rax register contains 0x0f. + */ + public boolean isAtSyscallSigReturn(Task task) + { + long address = pc(task); + boolean result = (task.getMemory().getByte(address) == (byte) 0x0f + && task.getMemory().getByte(address + 1) == (byte) 0x05); + if (result) + { + Register rax = getRegisterByName("rax"); + long syscall_num = rax.get(task); + result &= syscall_num == 0x0f; + } + return result; + } + public Syscall[] getSyscallList () { return LinuxX8664Syscall.syscallList; Index: frysk-core/frysk/proc/LinuxPtraceTask.java =================================================================== RCS file: /cvs/frysk/frysk-core/frysk/proc/LinuxPtraceTask.java,v retrieving revision 1.7 diff -u -u -r1.7 LinuxPtraceTask.java --- frysk-core/frysk/proc/LinuxPtraceTask.java 7 Feb 2007 18:08:25 -0000 1.7 +++ frysk-core/frysk/proc/LinuxPtraceTask.java 12 Feb 2007 15:05:34 -0000 @@ -1,6 +1,6 @@ // This file is part of the program FRYSK. // -// Copyright 2005, 2006, Red Hat Inc. +// Copyright 2005, 2006, 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 @@ -163,6 +163,7 @@ logger.log(Level.FINE, "{0} sendStepInstruction\n", this); step_send = true; sig_send = sig; + syscall_sigret = getIsa().isAtSyscallSigReturn(this); try { Ptrace.singleStep(getTid(), sig); Index: frysk-core/frysk/proc/LinuxPtraceTaskState.java =================================================================== RCS file: /cvs/frysk/frysk-core/frysk/proc/LinuxPtraceTaskState.java,v retrieving revision 1.8 diff -u -u -r1.8 LinuxPtraceTaskState.java --- frysk-core/frysk/proc/LinuxPtraceTaskState.java 8 Feb 2007 22:29:47 -0000 1.8 +++ frysk-core/frysk/proc/LinuxPtraceTaskState.java 12 Feb 2007 15:05:35 -0000 @@ -942,6 +942,7 @@ // architectures). if (task.step_send && (task.sig_send != 0 + || task.syscall_sigret || isa.hasExecutedSpuriousTrap(task))) { sendContinue(task, 0); @@ -1167,7 +1168,7 @@ newState = insyscall ? inSyscallRunningTraced : syscallRunning; else newState = running; - newState.sendContinue(task, 0); + newState.sendContinue(task, sig); return newState; } Index: frysk-core/frysk/proc/Task.java =================================================================== RCS file: /cvs/frysk/frysk-core/frysk/proc/Task.java,v retrieving revision 1.121 diff -u -u -r1.121 Task.java --- frysk-core/frysk/proc/Task.java 7 Feb 2007 18:08:25 -0000 1.121 +++ frysk-core/frysk/proc/Task.java 12 Feb 2007 15:05:35 -0000 @@ -907,6 +907,11 @@ // The signal, or zero, send last to the task. int sig_send; + // When the last request to the process was a step request, whether + // it was a request to step a sigreturn syscall. + // Set by sendStepInstruction(). + boolean syscall_sigret; + /** * Notify all Code observers of the breakpoint. Return the number of * blocking observers or -1 if no Code observer were installed on this Index: frysk-core/frysk/proc/TestTaskObserverInstructionSigReturn.java =================================================================== RCS file: frysk-core/frysk/proc/TestTaskObserverInstructionSigReturn.java diff -N frysk-core/frysk/proc/TestTaskObserverInstructionSigReturn.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ frysk-core/frysk/proc/TestTaskObserverInstructionSigReturn.java 12 Feb 2007 15:05:35 -0000 @@ -0,0 +1,150 @@ +// 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.proc; + +import java.io.File; + +import frysk.Config; +import frysk.sys.Sig; + +public class TestTaskObserverInstructionSigReturn + extends TestLib + implements TaskObserver.Attached, + TaskObserver.Instruction, + TaskObserver.Terminating, + TaskObserver.Signaled +{ + // Counter for instruction observer hits. + long hit; + + // How the process exited. + int exit; + + // What process task are we talking about? + Task task; + + // How many times have we been signaled? + int signaled; + + public void testStepSigReturn() + { + // Init. + hit = 0; + signaled = 0; + exit = -1; + + // Start and attach. + String command = new File(Config.getPkgLibDir(), "funit-alarm").getPath(); + Manager.host.requestCreateAttachedProc(new String[] {command}, this); + assertRunUntilStop("Creating process"); + + // Add a terminated and signaled observer. + task.requestAddTerminatingObserver(this); + task.requestAddSignaledObserver(this); + task.requestUnblock(this); + assertRunUntilStop("Waiting for first PROF signal"); + + // Add a stepping observer. + task.requestAddInstructionObserver(this); + task.requestUnblock(this); + assertRunUntilStop("Stepping through till completion"); + + assertTrue("steps were made", + hit > 5 * signaled /* random very low bound guess really */); + assertEquals("signaled", 3, signaled); + assertEquals("process exited nicely", 0, exit); + } + + // Common interface methods + public void addedTo (Object observable) + { + // ignored + } + + public void addFailed (Object observable, Throwable w) + { + w.printStackTrace(); + } + + public void deletedFrom (Object observable) + { + // ignored + } + + // TaskObserver.Attached interface + public Action updateAttached(Task task) + { + this.task = task; + Manager.eventLoop.requestStop(); + return Action.BLOCK; + } + + // TaskObserver.Instruction interface + public Action updateExecuted(Task task) + { + hit++; + return Action.CONTINUE; + } + + // TaskObserver.Terminated interface + public Action updateTerminating(Task task, boolean signal, int exit) + { + Manager.eventLoop.requestStop(); + + this.exit = exit; + return Action.CONTINUE; + } + + // TaskObserver.Signaled interface + public Action updateSignaled (Task task, int signal) + { + if (signal != Sig.PROF_) + fail("Wrong signal received: " + signal); + + signaled++; + if (signaled == 1) + { + Manager.eventLoop.requestStop(); + return Action.BLOCK; + } + + return Action.CONTINUE; + } +}