public inbox for frysk-cvs@sourceware.org
help / color / mirror / Atom feed
From: mark@sourceware.org
To: frysk-cvs@sourceware.org
Subject: [SCM]  master: Signal frame tests and fix for first step into signal handler.
Date: Mon, 07 Apr 2008 11:39:00 -0000	[thread overview]
Message-ID: <20080407113958.1451.qmail@sourceware.org> (raw)

The branch, master has been updated
       via  9d75214af4176d3eb85faa5695880ee1af0f9128 (commit)
      from  d813a1df045eb2251c7f98c668b3ede11d98d9f1 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email.

- Log -----------------------------------------------------------------
commit 9d75214af4176d3eb85faa5695880ee1af0f9128
Author: Mark Wielaard <mwielaard@redhat.com>
Date:   Mon Apr 7 13:38:38 2008 +0200

    Signal frame tests and fix for first step into signal handler.

-----------------------------------------------------------------------

Summary of changes:
 frysk-core/frysk/pkglibdir/ChangeLog               |    4 +
 frysk-core/frysk/pkglibdir/funit-loop-signal.c     |   94 ++++++
 frysk-core/frysk/proc/live/ChangeLog               |    6 +
 .../frysk/proc/live/LinuxPtraceTaskState.java      |    8 +-
 frysk-core/frysk/stack/ChangeLog                   |    4 +
 frysk-core/frysk/stack/TestSignalStepFrame.java    |  340 ++++++++++++++++++++
 6 files changed, 454 insertions(+), 2 deletions(-)
 create mode 100644 frysk-core/frysk/pkglibdir/funit-loop-signal.c
 create mode 100644 frysk-core/frysk/stack/TestSignalStepFrame.java

First 500 lines of diff:
diff --git a/frysk-core/frysk/pkglibdir/ChangeLog b/frysk-core/frysk/pkglibdir/ChangeLog
index fce5b05..76d0c30 100644
--- a/frysk-core/frysk/pkglibdir/ChangeLog
+++ b/frysk-core/frysk/pkglibdir/ChangeLog
@@ -1,3 +1,7 @@
+2008-04-07  Mark Wielaard  <mwielaard@redhat.com>
+
+	* funit-loop-signal.c: New test.
+
 2008-04-04  Andrew Cagney  <cagney@redhat.com>
 
 	* funit-asm.S: Update to match frysk-asm.h's STORE_WORD.
diff --git a/frysk-core/frysk/pkglibdir/funit-loop-signal.c b/frysk-core/frysk/pkglibdir/funit-loop-signal.c
new file mode 100644
index 0000000..c3eacfa
--- /dev/null
+++ b/frysk-core/frysk/pkglibdir/funit-loop-signal.c
@@ -0,0 +1,94 @@
+// 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 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 <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+
+// Simple test prog that sets an alarm, spins in foo () till ALRM
+// signal arrives and twiddles a bit and breaks the loop.
+// Used to check a backtrace correctly shows the signal interrupted
+// function (and its parent).
+
+// Gets set to 1 by signal handler (foo checks the value).
+volatile int i;
+
+// Random counter variable to give foo () something to do.
+int count;
+
+// The signal handler.
+void
+handler (int sig)
+{
+  i = 1; // _signal_handler_
+}
+
+int
+foo (int x)
+{
+  i = 0;           // _foo_entry_
+  count = 0;
+
+  // Spin till signal sets i to one.
+  while (i == 0)
+    count += x;
+
+  i = 0; // _foo_exit_
+
+  return x - i;
+}
+
+int
+main (int argc, char *argv[], char *envp[])
+{
+  // Setup signal handler.
+  struct sigaction sa;
+  sa.sa_handler = handler;
+  sigemptyset(&sa.sa_mask);
+  sa.sa_flags = 0;
+  sigaction(SIGALRM, &sa, NULL) ;
+
+  // Trigger signal after 1 second.
+  alarm(1);
+
+  // Spin till signal
+  return foo (1); // zero
+
+  // Something with sigaltstack
+}
diff --git a/frysk-core/frysk/proc/live/ChangeLog b/frysk-core/frysk/proc/live/ChangeLog
index 2c1cacf..58b6fae 100644
--- a/frysk-core/frysk/proc/live/ChangeLog
+++ b/frysk-core/frysk/proc/live/ChangeLog
@@ -1,3 +1,9 @@
+2008-04-07  Mark Wielaard  <mwielaard@redhat.com>
+
+	* LinuxPtraceTaskState.java (Stepping.handleTrappedEvent):
+	Explicitly notify Instruction observers in special
+	"no step bit set" cases.
+
 2008-04-04  Phil Muldoon  <pmuldoon@redhat.com>
 
 	* LinuxPtraceProc.java (LinuxPtraceProc): Instatiate watchpoint
diff --git a/frysk-core/frysk/proc/live/LinuxPtraceTaskState.java b/frysk-core/frysk/proc/live/LinuxPtraceTaskState.java
index c08ff72..7d737f9 100644
--- a/frysk-core/frysk/proc/live/LinuxPtraceTaskState.java
+++ b/frysk-core/frysk/proc/live/LinuxPtraceTaskState.java
@@ -1152,12 +1152,16 @@ abstract class LinuxPtraceTaskState extends State {
 		    // trapping instruction) that we should ignore (this
 		    // would be nice to use to support syscall tracking
 		    // during stepping, but it doesn't happen on all
-		    // architectures).
+		    // architectures). In all these cases a step is actually
+		    // made so we should notify any instruction observers.
 		    if ((task.sigSendXXX != Signal.NONE
 			 || task.syscallSigretXXX
 			 || isa.hasExecutedSpuriousTrap(task)))
+		      if (task.notifyInstruction() > 0)
+			return blockedContinue();
+		      else
 			return sendContinue(task, Signal.NONE);
-	      
+
 		    // Deliver the real Trap event to the Task.  This is
 		    // somewhat weird, we are either stepping a trapping
 		    // instruction (breakpoint) that we didn't install, or
diff --git a/frysk-core/frysk/stack/ChangeLog b/frysk-core/frysk/stack/ChangeLog
index d6ca809..d16af8c 100644
--- a/frysk-core/frysk/stack/ChangeLog
+++ b/frysk-core/frysk/stack/ChangeLog
@@ -1,3 +1,7 @@
+2008-04-07  Mark Wielaard  <mwielaard@redhat.com>
+
+	* TestSignalStepFrame.java: New tests.
+
 2008-04-06  Petr Machata  <pmachata@redhat.com>
 
 	* Frame.java (toPrint): Code for 0-padding PC moved to
diff --git a/frysk-core/frysk/stack/TestSignalStepFrame.java b/frysk-core/frysk/stack/TestSignalStepFrame.java
new file mode 100644
index 0000000..7256621
--- /dev/null
+++ b/frysk-core/frysk/stack/TestSignalStepFrame.java
@@ -0,0 +1,340 @@
+// 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 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.stack;
+
+import java.io.*;
+import java.util.*;
+
+import frysk.config.*;
+
+import frysk.testbed.*;
+
+import frysk.proc.*;
+import frysk.rt.*;
+import frysk.symtab.*;
+import frysk.isa.signals.Signal;
+
+/**
+ * Test making sure all frames are available when stepping through a
+ * signal call. It checks on each step that both the interruped
+ * function and the main function are outer frames (in that order) of
+ * the inner frame (which is the signal processing function of the
+ * task).
+ *
+ * Note this checks the low level (libunwind) frames walking.  It
+ * doesn't test anything at a higher level or with the SteppingEngine.
+ */
+public class TestSignalStepFrame
+  extends TestLib
+  implements TaskObserver.Code, TaskObserver.Instruction, TaskObserver.Signaled
+{
+  // Starts the funit-loop-signal test and return the Task at the point
+  // that the signal arrived.
+  private Task setupLoopSignalTest()
+  {
+    String source = Config.getRootSrcDir()
+      + "frysk-core/frysk/pkglibdir/funit-loop-signal.c";
+
+    TestfileTokenScanner scanner = new TestfileTokenScanner(new File(source));
+    int foo_entry = scanner.findTokenLine("_foo_entry_");
+
+    File exe = Config.getPkgLibFile("funit-loop-signal");
+    DaemonBlockedAtEntry dbae = new DaemonBlockedAtEntry(exe);
+    
+    Task task = dbae.getMainTask();
+
+    LineBreakpoint entryBreak = new LineBreakpoint(-1, source, foo_entry, 0);
+
+    List entryAddresses = entryBreak.getBreakpointRawAddresses(task);
+
+    // Test sanity check
+    assertTrue("expecting one entry address", entryAddresses.size() == 1);
+
+    long entryAddress = ((Long) entryAddresses.get(0)).longValue();
+
+    task.requestAddCodeObserver(this, entryAddress);
+    assertRunUntilStop("adding Code observer");
+
+    dbae.requestUnblock();
+    assertRunUntilStop("Continuing to initial breakpoint");
+
+    // OK, everything setup. Now wait for the signal to arrive.
+    task.requestAddSignaledObserver(this);
+    assertRunUntilStop("adding Signaled observer");
+
+    task.requestUnblock(this);
+    assertRunUntilStop("waiting for signal to arrive");
+
+    // Signal arrived, on to the real test...
+    return task;
+  }
+
+  public void testFirstFrameInSignalHandler()
+  {
+    Task task = setupLoopSignalTest();
+
+    // Get the start address of the signal handler.
+    String source = Config.getRootSrcDir()
+      + "frysk-core/frysk/pkglibdir/funit-loop-signal.c";
+    TestfileTokenScanner scanner = new TestfileTokenScanner(new File(source));
+    int sig_entry = scanner.findTokenLine("_signal_handler_");
+    LineBreakpoint signalBreak = new LineBreakpoint(-1, source, sig_entry, 0);
+    List signalAddresses = signalBreak.getBreakpointRawAddresses(task);
+    // Test sanity check
+    assertTrue("expecting one entry address", signalAddresses.size() == 1);
+    long signalAddress = ((Long) signalAddresses.get(0)).longValue();
+    Symbol sym = SymbolFactory.getSymbol(task, signalAddress);
+    long signalStartAddr = sym.getAddress();
+    
+    // One step and we should be at the first signal handler instruction.
+    task.requestAddInstructionObserver(this);
+    assertRunUntilStop("adding Instruction observer");
+    task.requestUnblock(this);
+    assertRunUntilStop("Do first step into signal handler");
+
+    // We are at the first signal handler instruction.
+    // Check out frames.
+    Frame frame = StackFactory.createFrame(task);
+    assertFooAndMainOuterFrames("First frame in handler", frame);
+    assertEquals(frame.getAddress(), signalStartAddr);
+  }
+
+  public void testReturnFrameAfterSignalHandler()
+  {
+    if (unresolvedOnIA32(6044))
+      return;
+
+    Task task = setupLoopSignalTest();
+
+    // Record current pc and outer frame to check after signal is processed.
+    long returnAddress = task.getPC();
+    Frame returnOuter = StackFactory.createFrame(task).getOuter();
+
+    // From here on we will step through signal handler to see if we return.
+    task.requestAddInstructionObserver(this);
+    assertRunUntilStop("adding Instruction observer");
+
+    // One step and we should be at the first signal handler instruction.
+    task.requestUnblock(this);
+    assertRunUntilStop("Do first step into signal handler");
+
+    // We are at the first signal handler instruction.
+    // Check out frames.
+    Frame frame = StackFactory.createFrame(task);
+    assertFooAndMainOuterFrames("First frame in handler", frame);
+
+    // Count your steps. And bail out when there are too many.
+    int steps = 1;
+    long currentPC = task.getPC();
+    while (steps < 1000)
+      {
+	task.requestUnblock(this);
+	assertRunUntilStop("Do step: " + steps);
+	currentPC = task.getPC();
+	if (currentPC == returnAddress)
+	  break; // back from the signal!
+	steps++;
+      }
+    
+    assertTrue("more than one step", steps > 1);
+    assertTrue("less than a thousand steps", steps < 1000);
+
+    // Check if outerframe correct after signal.
+    Frame outer = StackFactory.createFrame(task).getOuter();
+    assertEquals("outer frame correct",
+		 returnOuter.getAddress(), outer.getAddress());
+  }
+
+  public void testStepSignalCallAllFrames()
+  {
+    if (unresolvedOnIA32(5961))
+      return;
+
+    Task task = setupLoopSignalTest();
+
+    // Record return address
+    long returnAddress = task.getPC();
+
+    // From here on we will step through to check all frames.
+    task.requestAddInstructionObserver(this);
+    assertRunUntilStop("adding Instruction observer");
+
+    // One step and we should be at the first signal handler instruction.
+    task.requestUnblock(this);
+    assertRunUntilStop("Do first step into signal handler");
+
+    // We are at the first signal handler instruction (actually right
+    // after it, a step into the signal handler executes the first
+    // instruction).
+    Frame frame = StackFactory.createFrame(task);
+    assertFooAndMainOuterFrames("First frame in handler", frame);
+
+    // Count your steps. And bail out when there are too many.
+    int steps = 1;
+    long currentPC = task.getPC();
+    while (steps < 1000)
+      {
+	task.requestUnblock(this);
+	assertRunUntilStop("Do step: " + steps);
+	currentPC = task.getPC();
+	if (currentPC == returnAddress)
+	  break; // back from the signal!
+	frame = StackFactory.createFrame(task);
+	assertFooAndMainOuterFrames("In signal handler step: " + steps, frame);
+	steps++;
+      }
+    
+    assertTrue("more than one step", steps > 1);
+    assertTrue("less than a thousand steps", steps < 1000);
+  }
+
+
+  // Walks up the call stack and checks that both foo() and main() are
+  // in there, in that order, and that they are not the first inner
+  // frame.
+  private void assertFooAndMainOuterFrames(String message, Frame frame)
+  {
+    Symbol sym = frame.getSymbol();
+    String name = sym.getName();
+    boolean ok = name.indexOf("foo") == -1 && name.indexOf("main") == -1;
+    if (! ok)
+      printBacktrace(frame);
+    assertTrue(message + " first inner frame should not be foo or main", ok);
+
+    boolean foo_seen = false;
+    boolean main_seen = false;
+    Frame outer = frame.getOuter();
+    while (ok && outer != null)
+      {
+	sym = outer.getSymbol();
+	name = sym.getName();
+	boolean sym_is_foo = name.indexOf("foo") != -1;
+	if (! foo_seen && sym_is_foo)
+	  foo_seen = true;
+	else if (foo_seen && sym_is_foo)
+	  {
+	    ok = false;
+	    printBacktrace(frame);
+	    assertTrue(message
+		       + " foo should be in the backtrace only once",
+		       ok);
+	  }
+
+	boolean sym_is_main = name.indexOf("main") != -1;
+	if (foo_seen && sym_is_main)
+	  {
+	    // Hurray done!
+	    main_seen = true;
+	    break;
+	  }
+
+	if (! foo_seen && sym_is_main)
+	  {
+	    ok = false;
+	    printBacktrace(frame);
+	    assertTrue(message
+		       + " foo should appear before main in backtrace",
+		       ok);
+	  }
+	outer = outer.getOuter();
+      }
+
+    ok = ok && foo_seen && main_seen && outer != null;
+    if (! ok)
+      printBacktrace(frame);
+    assertTrue(message
+	       + " both foo and main should be in the backtrace",
+	       ok);
+  }
+
+  // Helper function to print backtrace from given frame.
+  // Useful while debugging this test.
+  private void printBacktrace(Frame frame)
+  {
+    System.out.println(frame);
+    Frame outer = frame.getOuter();
+    while (outer != null)
+      {
+	System.out.println("\t" + outer);
+	outer = outer.getOuter();
+      }
+  }
+
+  // Code observer method, just stop and block when breakpoint hit.
+  public Action updateHit(Task task, long address)
+  {
+    Manager.eventLoop.requestStop();
+    return Action.BLOCK;
+  }
+
+  // Instruction observer method, just stop and block after each step.
+  public Action updateExecuted(Task task)
+  {
+    Manager.eventLoop.requestStop();
+    return Action.BLOCK;
+  }
+
+  // SignaledObserver method, just stop and block when signal comes in.
+  public Action updateSignaled(Task task, Signal signal)
+  {
+    Manager.eventLoop.requestStop();
+    return Action.BLOCK;
+  }
+
+  // TaskObserver methods, only addedTo is interesting.
+
+  public void addFailed(Object observable, Throwable w)
+  {
+    // Whoa!
+    w.printStackTrace();
+  }
+  
+  public void addedTo(Object observable)
+  {
+    Manager.eventLoop.requestStop();
+  }
+


hooks/post-receive
--
frysk system monitor/debugger


                 reply	other threads:[~2008-04-07 11:39 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080407113958.1451.qmail@sourceware.org \
    --to=mark@sourceware.org \
    --cc=frysk-cvs@sourceware.org \
    --cc=frysk@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).