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]

Re: Some new Ptrace tests


On Fri, 2006-06-23 at 16:48 +0200, Mark Wielaard wrote:
> On Fri, 2006-06-23 at 10:06 -0400, Andrew Cagney wrote:
> > you may want to take a step back and look at 
> > frysk.sys.PtraceByteBuffer.  The core and the ui access a thread's 
> > memory via 64-bit[ish] byte buffers and not ptrace.
> 
> Thanks! That is precisely what I need.

And as a penance for not having seen that handy class earlier I wrote
some tests for it. Also to figure out how to actually use this for
variable and function content watching/manipulation. And those tests
actually exposed a bug in PtraceByteBuffer.peek(). Patch for the test
and the fix attached.

2006-06-26  Mark Wielaard  <mark@klomp.org>

    * frysk-sys/frysk/sys/TestPtraceByteBuffer.java: New test.
    * frysk-sys/frysk/sys/TestLib.java (intVal, byteVal, longVal):
    New static fields.
    (getIntValAddr, getByteValAddr, getLongValAddr): New native methods.
    (getFuncAddr): Likewise.
    (getFuncBytes): Likewise.
    * frysk-sys/frysk/sys/cni/TestLib.cxx
    (forkIt): Set intVal, byteVal and longVal for child process to
    different values.
    (dummyfunc): New static function.
    (getIntValAddr, getByteValAddr, getLongValAddr): New method.
    (getFuncAddr): Likewise.
    (getFuncBytes): Likewise.

    * frysk-sys/frysk/sys/cni/PtraceByteBuffer.cxx (peek): Use off when
    storing bytes.

In need to set the PtraceByteBuffer.Area.TEXT to ByteOrder.LITTLE_ENDIAN
for reading and writing the variables. But I assume the text area has
the native endianness of the target platform. Should the test figure out
what the target endianness is. Or should PtraceByteBuffer itself return
the areas in the target endianness? And is there a helper method already
to get the endianness of the platform?

Cheers,

Mark
? ptracebuffer.patch
Index: frysk/sys/TestLib.java
===================================================================
RCS file: /cvs/frysk/frysk-sys/frysk/sys/TestLib.java,v
retrieving revision 1.1
diff -u -r1.1 TestLib.java
--- frysk/sys/TestLib.java	15 Jun 2006 17:05:03 -0000	1.1
+++ frysk/sys/TestLib.java	26 Jun 2006 12:29:19 -0000
@@ -1,6 +1,6 @@
 // This file is part of the program FRYSK.
 //
-// Copyright 2005, Red Hat Inc.
+// Copyright 2005, 2006 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
@@ -41,8 +41,23 @@
 
 public class TestLib {
 
+  /* Values for inspection with ptrace peek. */
+  static int intVal = 42;
+  static byte byteVal = 43;
+  static long longVal = 44;
+
 	public static native int forkIt ();
 	
 	public static native int waitIt (int pid);
 	
+  /* Returns the address of a variable for inspection. */
+  public static native long getIntValAddr();
+  public static native long getLongValAddr();
+  public static native long getByteValAddr();
+
+  /* Returns the address of a function for inspection. */
+  public static native long getFuncAddr();
+
+  /* Returns the first 4 instruction bytes of the getFuncAddr(). */
+  public static native byte[] getFuncBytes();
 }
Index: frysk/sys/TestPtraceByteBuffer.java
===================================================================
RCS file: frysk/sys/TestPtraceByteBuffer.java
diff -N frysk/sys/TestPtraceByteBuffer.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ frysk/sys/TestPtraceByteBuffer.java	26 Jun 2006 12:29:19 -0000
@@ -0,0 +1,140 @@
+// This file is part of the program FRYSK.
+//
+// Copyright 2006, 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.sys;
+
+import junit.framework.TestCase;
+import inua.eio.*;
+import java.util.Arrays;
+
+public class TestPtraceByteBuffer extends TestCase
+{
+  private int pid;
+
+  protected void setUp()
+  {
+    pid = TestLib.forkIt();
+    Ptrace.attach(pid);
+    TestLib.waitIt(pid);
+  }
+
+  protected void tearDown()
+  {
+    Ptrace.detach(pid, 15);
+  }
+
+  /**
+   * Tests that a variable in the traced child can be manipulated.
+   */
+  public void testTextVariable()
+  {
+    ByteBuffer buffer;
+    buffer = new PtraceByteBuffer(pid, PtraceByteBuffer.Area.TEXT,
+				  0xffffffffl);
+    buffer = buffer.order(ByteOrder.LITTLE_ENDIAN);
+    long addr;
+
+    // Int
+    addr = TestLib.getIntValAddr();
+    int intVal = buffer.getInt(addr);
+    assertEquals("Forked child int value", 52, intVal);
+    assertEquals("Our own int value", 42, TestLib.intVal);
+
+    buffer.putInt(addr, 2);
+    assertEquals("Our own int value after poke", 42, TestLib.intVal);
+    intVal = buffer.getByte(addr);
+    assertEquals("Forked child int value after poke", 2, intVal);
+
+    // Byte
+    addr = TestLib.getByteValAddr();
+    long byteVal = buffer.getByte(addr);
+    assertEquals("Forked child byte value", 53, byteVal);
+    assertEquals("Our own long value", 43, TestLib.byteVal);
+
+    buffer.putByte(addr, (byte) 3);
+    assertEquals("Our own byte value after poke", 43, TestLib.byteVal);
+    byteVal = buffer.getByte(addr);
+    assertEquals("Forked child long value after poke", 3, byteVal);
+
+    // Long
+    addr = TestLib.getLongValAddr();
+    long longVal = buffer.getLong(addr);
+    assertEquals("Forked child long value", 54, longVal);
+    assertEquals("Our own long value", 44, TestLib.longVal);
+
+    buffer.putLong(addr, 4);
+    assertEquals("Our own long value after poke", 44, TestLib.longVal);
+    longVal = buffer.getByte(addr);
+    assertEquals("Forked child long value after poke", 4, longVal);
+  }
+
+  /**
+   * Tests that function code in the traced child can be manipulated.
+   */
+  public void testDataFunction()
+  {
+    PtraceByteBuffer buffer;
+    buffer = new PtraceByteBuffer(pid, PtraceByteBuffer.Area.DATA,
+				  0xffffffffl);
+
+    long addr = TestLib.getFuncAddr();
+    byte[] bytes = TestLib.getFuncBytes();
+    byte[] childBytes = new byte[4];
+    buffer.get(addr, childBytes, 0, 4);
+    assertTrue("Child function address word",
+	       Arrays.equals(bytes, childBytes));
+
+    // int 0x80, int3
+    byte[] newBytes = new byte[]
+      { (byte) 0xcd, (byte) 0x80, (byte) 0xcc, (byte) 0x00 };
+    buffer.position(addr);
+    buffer.putByte(newBytes[0]);
+    buffer.putByte(newBytes[1]);
+    buffer.putByte(newBytes[2]);
+    buffer.putByte(newBytes[3]);
+    bytes = TestLib.getFuncBytes();
+    assertTrue("Our own function bytes after poke",
+	       ! Arrays.equals(bytes, newBytes));
+    buffer.get(addr, childBytes, 0, 4);
+    assertTrue("Forked function word after poke",
+	       Arrays.equals(newBytes, childBytes));
+  }
+  
+}
+
Index: frysk/sys/cni/PtraceByteBuffer.cxx
===================================================================
RCS file: /cvs/frysk/frysk-sys/frysk/sys/cni/PtraceByteBuffer.cxx,v
retrieving revision 1.1
diff -u -r1.1 PtraceByteBuffer.cxx
--- frysk/sys/cni/PtraceByteBuffer.cxx	16 Jun 2006 22:34:55 -0000	1.1
+++ frysk/sys/cni/PtraceByteBuffer.cxx	26 Jun 2006 12:29:19 -0000
@@ -152,7 +152,7 @@
     pend = paddr + sizeof (int);
 
   for (unsigned long a = addr; a < pend; a++)
-    bytes[a - addr] = tmp.byte[a - paddr];
+    bytes[a - addr + off] = tmp.byte[a - paddr];
 
   return pend - addr;
 }
Index: frysk/sys/cni/TestLib.cxx
===================================================================
RCS file: /cvs/frysk/frysk-sys/frysk/sys/cni/TestLib.cxx,v
retrieving revision 1.1
diff -u -r1.1 TestLib.cxx
--- frysk/sys/cni/TestLib.cxx	15 Jun 2006 17:05:03 -0000	1.1
+++ frysk/sys/cni/TestLib.cxx	26 Jun 2006 12:29:19 -0000
@@ -1,6 +1,6 @@
 // This file is part of the program FRYSK.
 //
-// Copyright 2005, Red Hat Inc.
+// Copyright 2005, 2006 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
@@ -63,6 +63,9 @@
     perror("Error: could not fork child process");
     exit(1);
   } else if (pid == 0) { /* Child */
+    intVal = 52;
+    byteVal = 53;
+    longVal = 54;
     sleep(5);
     printf("DETACHED PROCESS: EXITING\n");
   }
@@ -73,3 +76,42 @@
 frysk::sys::TestLib::waitIt(jint pid) {
 	return waitpid(pid, NULL, __WALL);
 }
+
+/* Dummy static function for use by getFuncAddr. */
+static void
+dummyfunc ()
+{
+  printf("never used, will be overwritten in child");
+}
+
+/* Returns the address of the value we want to inspect in the child. */
+jlong
+frysk::sys::TestLib::getIntValAddr ()
+{
+  return (jlong) &intVal;
+}
+jlong
+frysk::sys::TestLib::getLongValAddr ()
+{
+  return (jlong) &longVal;
+}
+jlong
+frysk::sys::TestLib::getByteValAddr ()
+{
+  return (jlong) &byteVal;
+}
+
+jlong
+frysk::sys::TestLib::getFuncAddr ()
+{
+  return (jlong) dummyfunc;
+}
+
+jbyteArray
+frysk::sys::TestLib::getFuncBytes ()
+{
+  char *addr = (char *) dummyfunc;
+  jbyteArray bytes = JvNewByteArray (4);
+  memcpy (elements (bytes), addr, 4);
+  return bytes;
+}

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