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] LogicalMemoryBuffer


Hi,

This implements the logical memory view for Task.getMemory(). It is now
possible to view the process memory as if frysk-core hadn't touched it
at all. Users can now choose whether to get the raw view (with all the
bits in it that frysk-core might have changed for private house keeping)
through getRawMemory() or the logical view (which is the default old
getMemory() that almost everything outside frysk-core now uses). The gui
and fhpd could give the user the option to also get a raw memory view,
but in general the user is probably interested in the logical view as
the (running) process should see it. fcore could also choose to either
dump the logical memory view (which it already does since it just reads
the section maps from disk) or include the raw view (but that doesn't
seem wise since the user wouldn't know why the "garbage" breakpoint
instructions that frysk-core inserted are there).

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

    * Breakpoint.java: Implements Comparable.
    (getInstruction): New method.
    (getProc): New method.
    (compareTo): New method.
    * BreakpointAddresses.java (breakpoints): New field.
    (BreakpointAddresses): Initialize breakpoints.
    (getBreakpoint): New method.
    (getBreakpoints): New method.
    * MemoryMap.java: Make immutable.
    * Task.java (getRawMemory): New method.
    * TestTaskObserverCode (testViewBreakpointMemory): New test.
    (testViewBreakpointMap): New test.
    (getFunctionDie): New method.
    (getFunctionEntryAddress): Use getFunctionDie.

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

    * AddressSpaceByteBuffer.java (addressSpace): Now protected.
    (pid): Likewise.
    (AddressSpaceByteBuffer): Likewise.
    * LinuxTask.java (getRawMemory): New method name for sendrecMemory.
    (sendrecMemory): Implement through LogicalMemoryBuffer.
    * LogicalMemoryBuffer.java: New class.

There are a couple of new tests added for this that now all pass. No
regressions on x86_64 Fedora Core 6 and x86 Fedora 7. Although that was
somewhat hard to see since there are a couple of always failing and a
couple of intermediately failing tests in the tree. It would be nice to
get back to zero fail again.

A couple of things to note, questions and upcoming work:

- Some of the work with our ByteBuffers is somewhat awkward since we
pretend everything is longs. But arrays in java cannot address anything
bigger than a (positive) int. So having offsets and lengths as longs is
somewhat cheating since it will never work in practise. So there is some
casting back and forth. Maybe just change the ByteBuffer methods that
work on arrays to just take ints for offset and length.

- I added some comments about Breakpoints not really being immutable
objects which affects the thread-safety of the code. There are some
extra checks here and there. But it would be good to go over this. Maybe
this isn't really an issue since memory reads should only be done in
observers after an event notification. Can observers for different Tasks
of the same Proc be signaled simultaneously?

- LogicalMemoryBuffer is a filter on top of AddressSpaceByteBuffer but
really should be on top of MemorySpaceByteBuffer which is more
effecient. The used to be interface compatible, but a recent change to
MemorySpaceByteBuffer changed that and made that it less easy to wrap.
MemorySpaceByteBuffer is really just an optimization of
AddressSpaceByteBuffer (in the case of AddressSpace.TEXT/DATA) and all
code should go through the optimized path (StateLessFile) for accessing
memory if the AddressSpace allows it. So I am going to merge the two
(and fix up the places that currently use the slow path). Then I'll also
add the ByteBuffer.get() optimization that Chris pointed out.

- It would be nice to have an fhpd examine (gdb's x) command to show the
above work to the user (the gui already has a memory view). I like to
add that. The hpd spec doesn't seem to have something like this, nor
does it seem to have a way for expressions to take the address of
functions or raw addresses. Do we already have extensions for that?
I haven't yet looked at Nurdin's recent fhpd work, but this might
already do most of what I want, and more. So maybe all I need to do is
strip stuff from that because I just don't need the more :)

Cheers,

Mark
Index: frysk-core/frysk/proc/Breakpoint.java
===================================================================
RCS file: /cvs/frysk/frysk-core/frysk/proc/Breakpoint.java,v
retrieving revision 1.13
diff -u -r1.13 Breakpoint.java
--- frysk-core/frysk/proc/Breakpoint.java	9 Jul 2007 08:18:59 -0000	1.13
+++ frysk-core/frysk/proc/Breakpoint.java	20 Jul 2007 10:53:37 -0000
@@ -46,9 +46,11 @@
 
 /**
  * Internal proc class that represents a Breakpoint at a certain
- * address in a Proc.
+ * address in a Proc. Some attempts are made to have synchronize
+ * different Breakpoint instances at the same address in the same
+ * Proc, but currently this isn't a full singleton.
  */
-public class Breakpoint
+public class Breakpoint implements Comparable
 {
   // These two fields define a Breakpoint
   private final long address;
@@ -274,6 +276,34 @@
   }
 
   /**
+   * If this breakpoint is installed then the original instruction at
+   * the breakpoint address is returned. Otherwise null could be
+   * returned.
+   */
+  public Instruction getInstruction()
+  {
+    if (origInstruction == null)
+      {
+	// Try to get at the installed instance and sync with it.
+	synchronized(installed)
+	  {
+	    Breakpoint existing = (Breakpoint) installed.get(this);
+	    if (existing != null)
+	      this.origInstruction = existing.origInstruction;
+	  }
+      }
+    return origInstruction;
+  }
+
+  /**
+   * Returns the Proc to which this breakpoint belongs.
+   */
+  public Proc getProc()
+  {
+    return proc;
+  }
+
+  /**
    * Returns true if break point is installed and not yet removed.
    */
   public boolean isInstalled()
@@ -300,6 +330,15 @@
     return other.proc.equals(proc) && other.address == address;
   }
 
+  /**
+   * Uses natural ordering on address.
+   */
+  public int compareTo(Object o) 
+  {
+    Breakpoint other = (Breakpoint) o;
+    return (int) (this.address - other.address);
+  }
+
   public String toString()
   {
     return this.getClass().getName() + "[proc=" + proc
Index: frysk-core/frysk/proc/BreakpointAddresses.java
===================================================================
RCS file: /cvs/frysk/frysk-core/frysk/proc/BreakpointAddresses.java,v
retrieving revision 1.6
diff -u -r1.6 BreakpointAddresses.java
--- frysk-core/frysk/proc/BreakpointAddresses.java	19 May 2007 13:01:45 -0000	1.6
+++ frysk-core/frysk/proc/BreakpointAddresses.java	20 Jul 2007 10:53:37 -0000
@@ -1,6 +1,6 @@
 // This file is part of the program FRYSK.
 //
-// Copyright 2006, Red Hat Inc.
+// Copyright 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
@@ -70,7 +70,12 @@
    * will do.
    */
   private final HashMap map;
-  
+
+  /**
+   * A sorted set (on address) of Breakpoints, used for getBreakpoints().
+   */
+  private final TreeSet breakpoints;
+
   /**
    * Package private constructor used by the Proc when created.
    */
@@ -78,6 +83,7 @@
   {
     this.proc = proc;
     map = new HashMap();
+    breakpoints = new TreeSet();
   }
 
   /**
@@ -94,6 +100,7 @@
     ArrayList list = (ArrayList) map.get(breakpoint);
     if (list == null)
       {
+	breakpoints.add(breakpoint);
 	list = new ArrayList();
 	map.put(breakpoint, list);
 	list.add(observer);
@@ -126,6 +133,7 @@
     
     if (list.isEmpty())
       {
+	breakpoints.remove(breakpoint);
 	map.remove(breakpoint);
 	return true;
       }
@@ -153,6 +161,28 @@
     return observers;
   }
 
+  public Breakpoint getBreakpoint(long address)
+  {
+    Breakpoint breakpoint = Breakpoint.create(address, proc);
+    Object observer = map.get(breakpoint);
+    if (observer == null)
+      return null;
+    else
+      return breakpoint;
+  }
+
+  /**
+   * Returns an iterator that returns in address order all breakpoints
+   * (possibly) installed starting at the from address up to (but not
+   * including) the till address.
+   */
+  public Iterator getBreakpoints(long from, long till)
+  {
+    Breakpoint fromBreakpoint = Breakpoint.create(from, proc);
+    Breakpoint tillBreakpoint = Breakpoint.create(till, proc);
+    return breakpoints.subSet(fromBreakpoint, tillBreakpoint).iterator();
+  }
+
   /**
    * Called from TaskState when the Task gets an execed event which
    * clears the whole address space.
@@ -162,5 +192,6 @@
   public void removeAllCodeObservers()
   {
     map.clear();
+    breakpoints.clear();
   }
 }
Index: frysk-core/frysk/proc/MemoryMap.java
===================================================================
RCS file: /cvs/frysk/frysk-core/frysk/proc/MemoryMap.java,v
retrieving revision 1.3
diff -u -r1.3 MemoryMap.java
--- frysk-core/frysk/proc/MemoryMap.java	13 Jun 2007 21:10:30 -0000	1.3
+++ frysk-core/frysk/proc/MemoryMap.java	20 Jul 2007 10:53:37 -0000
@@ -48,19 +48,19 @@
  */
 public class MemoryMap
 {
-  public long addressLow;
-  public long addressHigh;
-  public boolean permRead;
-  public boolean permWrite;
-  public boolean permExecute;
-  public boolean shared;
-  public long offset;
-  public int devMajor;
-  public int devMinor;
-  public int inode;       
-  public int pathnameOffset;
-  public int pathnameLength; 
-  public String name;
+  public final long addressLow;
+  public final long addressHigh;
+  public final boolean permRead;
+  public final boolean permWrite;
+  public final boolean permExecute;
+  public final boolean shared;
+  public final long offset;
+  public final int devMajor;
+  public final int devMinor;
+  public final int inode;       
+  public final int pathnameOffset;
+  public final int pathnameLength; 
+  public final String name;
 
   public MemoryMap(long addressLow, long addressHigh,
 	     boolean permRead, boolean permWrite,
Index: frysk-core/frysk/proc/Task.java
===================================================================
RCS file: /cvs/frysk/frysk-core/frysk/proc/Task.java,v
retrieving revision 1.143
diff -u -r1.143 Task.java
--- frysk-core/frysk/proc/Task.java	5 Jul 2007 19:00:15 -0000	1.143
+++ frysk-core/frysk/proc/Task.java	20 Jul 2007 10:53:37 -0000
@@ -846,6 +846,21 @@
   }
 
   /**
+   * Returns the memory as seen by frysk-core. That includes things like
+   * inserted breakpoint instructions bytes which are filtered out by
+   * <code>getMemory()</code> (which is what you normally want unless
+   * you are interested in frysk-core specifics).
+   * <p>
+   * Default implementation calls <code>getMemory()</code>, need to be
+   * overriden by subclasses for which the raw memory view and the
+   * logical memory view are different.
+   */
+  public ByteBuffer getRawMemory()
+  {
+    return getMemory();
+  }
+
+  /**
    * Set of Code observers.
    *
    * XXX: Should not be public.
Index: frysk-core/frysk/proc/TestTaskObserverCode.java
===================================================================
RCS file: /cvs/frysk/frysk-core/frysk/proc/TestTaskObserverCode.java,v
retrieving revision 1.4
diff -u -r1.4 TestTaskObserverCode.java
--- frysk-core/frysk/proc/TestTaskObserverCode.java	16 Jul 2007 22:11:35 -0000	1.4
+++ frysk-core/frysk/proc/TestTaskObserverCode.java	20 Jul 2007 10:53:38 -0000
@@ -39,6 +39,8 @@
 
 package frysk.proc;
 
+import inua.eio.*;
+
 import frysk.sys.*;
 
 import lib.dwfl.*;
@@ -139,6 +141,230 @@
     assertRunUntilStop("cleanup");
   }
 
+  // Tests that breakpoint instructions are not visible to
+  // normal users of task memory (only through raw memory view).
+  public void testViewBreakpointMemory() throws Exception
+  {
+    // Create a child.
+    child = new AckDaemonProcess();
+    task = child.findTaskUsingRefresh (true);
+    proc = task.getProc();
+
+    // Make sure we are attached.
+    AttachedObserver attachedObserver = new AttachedObserver();
+    task.requestAddAttachedObserver(attachedObserver);
+    assertRunUntilStop("adding AttachedObserver");
+
+    ByteBuffer memory = task.getMemory();
+    ByteBuffer raw_memory = task.getRawMemory();
+    long address = getFunctionEntryAddress("bp1_func");
+    DwarfDie func1_die = getFunctionDie("bp1_func");
+    long func1_start = func1_die.getLowPC();
+    long func1_end = func1_die.getHighPC();
+
+    // Get the original byte and byte[] for the breakpoint address and
+    // whole function. Raw and logical should be similar.
+    byte bp1_orig;
+    memory.position(address);
+    bp1_orig = memory.getByte();
+
+    byte bp1_orig_raw;
+    raw_memory.position(address);
+    bp1_orig_raw = raw_memory.getByte();
+    assertEquals("orig and raw", bp1_orig, bp1_orig_raw);
+
+    byte[] func1_orig = new byte[(int) (func1_end - func1_start)];
+    memory.position(func1_start);
+    memory.get(func1_orig);
+
+    byte[] func1_orig_raw = new byte[(int) (func1_end - func1_start)];
+    raw_memory.position(func1_start);
+    raw_memory.get(func1_orig_raw);
+    assertTrue("func_orig and func_raw",
+	       Arrays.equals(func1_orig, func1_orig_raw));
+
+    // Insert breakpoint and check that (non-raw) view is the same.
+    CodeObserver code = new CodeObserver(task, address);
+    task.requestAddCodeObserver(code, address);
+    assertRunUntilStop("add breakpoint observer");
+
+    // Get the byte and byte[] for the breakpoint address and
+    // whole function. Raw should show the breakpoint.
+    byte bp1_insert;
+    memory.position(address);
+    bp1_insert = memory.getByte();
+    assertEquals("orig and insert", bp1_orig, bp1_insert);
+
+    byte bp1_insert_raw;
+    raw_memory.position(address);
+    bp1_insert_raw = raw_memory.getByte();
+    assertTrue("insert and raw", bp1_insert != bp1_insert_raw);
+
+    byte[] func1_insert = new byte[(int) (func1_end - func1_start)];
+    memory.position(func1_start);
+    memory.get(func1_insert);
+    assertTrue("func_orig and func_insert",
+	       Arrays.equals(func1_orig, func1_insert));
+    
+    byte[] func1_insert_raw = new byte[(int) (func1_end - func1_start)];
+    raw_memory.position(func1_start);
+    raw_memory.get(func1_insert_raw);
+    assertFalse("func_insert and func_insert_raw",
+		Arrays.equals(func1_insert, func1_insert_raw));
+
+    // And remove it again.
+    task.requestDeleteCodeObserver(code, address);
+    assertRunUntilStop("remove code observer again");
+
+    // Get the byte and byte[] for the breakpoint address and
+    // whole function. Neither memory view should show the breakpoint.
+    byte bp1_new;
+    memory.position(address);
+    bp1_new = memory.getByte();
+    assertEquals("orig and new", bp1_orig, bp1_new);
+
+    byte[] func1_new = new byte[(int) (func1_end - func1_start)];
+    memory.position(func1_start);
+    memory.get(func1_new);
+    assertTrue("func_orig and func_new",
+	       Arrays.equals(func1_orig, func1_new));
+
+    byte bp1_new_raw;
+    raw_memory.position(address);
+    bp1_new_raw = raw_memory.getByte();
+    assertEquals("new and raw",
+		 bp1_new, bp1_new_raw);
+
+    byte[] func1_new_raw = new byte[(int) (func1_end - func1_start)];
+    raw_memory.position(func1_start);
+    raw_memory.get(func1_new_raw);
+    assertTrue("func_new and func_new_raw",
+	       Arrays.equals(func1_new, func1_new_raw));
+  }
+
+  // Tests that breakpoint instructions are not visible in the entire
+  // code text map of the program.
+  public void testViewBreakpointMap() throws Exception
+  {
+    // Create a child.
+    child = new AckDaemonProcess();
+    task = child.findTaskUsingRefresh (true);
+    proc = task.getProc();
+
+    // Make sure we are attached.
+    AttachedObserver attachedObserver = new AttachedObserver();
+    task.requestAddAttachedObserver(attachedObserver);
+    assertRunUntilStop("adding AttachedObserver");
+
+    ByteBuffer memory = task.getMemory();
+    ByteBuffer raw_memory = task.getRawMemory();
+
+    DwarfDie func1_die = getFunctionDie("bp1_func");
+    long func1_start = func1_die.getLowPC();
+    long func1_end = func1_die.getHighPC();
+
+    DwarfDie func2_die = getFunctionDie("bp2_func");
+    long func2_start = func2_die.getLowPC();
+    long func2_end = func2_die.getHighPC();
+
+    long address = func1_start;
+    MemoryMap map = proc.getMap(func1_start);
+
+    int map_len = (int) (map.addressHigh - map.addressLow);
+
+    byte[] mem_orig = new byte[map_len];
+    byte[] raw_orig = new byte[map_len];
+    
+    memory.position(map.addressLow);
+    memory.get(mem_orig);
+    raw_memory.position(map.addressLow);
+    raw_memory.get(raw_orig);
+
+    assertTrue("mem_orig and raw_orig",
+	       Arrays.equals(mem_orig, raw_orig));
+
+    // Put breakpoints inside the map and at the beginning and the end
+    // to test the corner cases.
+    address = func1_start;
+    CodeObserver code1 = new CodeObserver(task, address);
+    task.requestAddCodeObserver(code1, address);
+    assertRunUntilStop("add breakpoint observer func1 start");
+
+    address = func1_end;
+    CodeObserver code2 = new CodeObserver(task, address);
+    task.requestAddCodeObserver(code2, address);
+    assertRunUntilStop("add breakpoint observer func1 end");
+
+    address = func2_start;
+    CodeObserver code3 = new CodeObserver(task, address);
+    task.requestAddCodeObserver(code3, address);
+    assertRunUntilStop("add breakpoint observer func2 start");
+
+    address = func2_end;
+    CodeObserver code4 = new CodeObserver(task, address);
+    task.requestAddCodeObserver(code4, address);
+    assertRunUntilStop("add breakpoint observer func2 end");
+
+    address = map.addressLow;
+    CodeObserver code5 = new CodeObserver(task, address);
+    task.requestAddCodeObserver(code5, address);
+    assertRunUntilStop("add breakpoint observer addressLow");
+
+    address = map.addressHigh - 1;
+    CodeObserver code6 = new CodeObserver(task, address);
+    task.requestAddCodeObserver(code6, address);
+    assertRunUntilStop("add breakpoint observer addressHigh");
+
+    byte[] bp_mem = new byte[map_len];
+    byte[] bp_raw = new byte[map_len];
+    
+    memory.position(map.addressLow);
+    memory.get(bp_mem);
+    raw_memory.position(map.addressLow);
+    raw_memory.get(bp_raw);
+
+    assertTrue("mem_orig and bp_mem",
+	       Arrays.equals(mem_orig, bp_mem));
+    assertFalse("raw_orig and bp_raw",
+		Arrays.equals(raw_orig, bp_raw));
+
+    // See if only the breakpoint addresses were affected.
+    bp_raw[(int) (func1_start - map.addressLow)] = memory.getByte(func1_start);
+    bp_raw[(int) (func1_end - map.addressLow)] = memory.getByte(func1_end);
+    bp_raw[(int) (func2_start - map.addressLow)] = memory.getByte(func2_start);
+    bp_raw[(int) (func2_end - map.addressLow)] = memory.getByte(func2_end);
+    bp_raw[0] = memory.getByte(map.addressLow);
+    bp_raw[map_len - 1] = memory.getByte(map.addressHigh - 1);
+
+    assertTrue("bp_mem and bp_raw",
+	       Arrays.equals(bp_mem, bp_raw));
+
+    // Remove all breakpoints and all memory should revert to be the same.
+    task.requestDeleteCodeObserver(code1, code1.address);
+    assertRunUntilStop("delete 1");
+    task.requestDeleteCodeObserver(code2, code2.address);
+    assertRunUntilStop("delete 2");
+    task.requestDeleteCodeObserver(code3, code3.address);
+    assertRunUntilStop("delete 3");
+    task.requestDeleteCodeObserver(code4, code4.address);
+    assertRunUntilStop("delete 4");
+    task.requestDeleteCodeObserver(code5, code5.address);
+    assertRunUntilStop("delete 5");
+    task.requestDeleteCodeObserver(code6, code6.address);
+    assertRunUntilStop("delete 6");
+
+    memory.position(map.addressLow);
+    memory.get(bp_mem);
+    raw_memory.position(map.addressLow);
+    raw_memory.get(bp_raw);
+
+    assertTrue("deleted mem_orig and bp_mem",
+               Arrays.equals(mem_orig, bp_mem));
+    assertTrue("deleted bp_mem and bp_raw",
+	       Arrays.equals(bp_mem, bp_raw));
+
+  }
+
   // Tells the child to run the dummy () function
   // which calls bp1_func () and bp2_func ().
   static final Sig dummySig = Sig.PROF;
@@ -172,23 +398,26 @@
    */
   long getFunctionEntryAddress(String func) throws ElfException
   {
-    Elf elf = new Elf(proc.getExe(), ElfCommand.ELF_C_READ);
-    Dwarf dwarf = new Dwarf(elf, DwarfCommand.READ, null);
-    DwarfDie die = DwarfDie.getDecl(dwarf, func);
+    DwarfDie die = getFunctionDie(func);
     ArrayList entryAddrs = die.getEntryBreakpoints();
 
     // We really expect just one entry point.
     assertEquals(entryAddrs.size(), 1);
-
-    // Add a Code observer on the address.
     return ((Long) entryAddrs.get(0)).longValue();
   }
 
+  DwarfDie getFunctionDie(String func) throws ElfException
+  {
+    Elf elf = new Elf(proc.getExe(), ElfCommand.ELF_C_READ);
+    Dwarf dwarf = new Dwarf(elf, DwarfCommand.READ, null);
+    return DwarfDie.getDecl(dwarf, func);
+  }
+
   static class CodeObserver
     implements TaskObserver.Code
   {
     private final Task task;
-    private final long address;
+    final long address;
 
     boolean hit;
 
Index: frysk-core/frysk/proc/live/AddressSpaceByteBuffer.java
===================================================================
RCS file: /cvs/frysk/frysk-core/frysk/proc/live/AddressSpaceByteBuffer.java,v
retrieving revision 1.1
diff -u -r1.1 AddressSpaceByteBuffer.java
--- frysk-core/frysk/proc/live/AddressSpaceByteBuffer.java	26 Jun 2007 22:12:52 -0000	1.1
+++ frysk-core/frysk/proc/live/AddressSpaceByteBuffer.java	20 Jul 2007 10:53:38 -0000
@@ -47,10 +47,10 @@
 public class AddressSpaceByteBuffer
     extends ByteBuffer
 {
-    private final AddressSpace addressSpace;
-    private final int pid;
+    protected final AddressSpace addressSpace;
+    protected final int pid;
 
-    private AddressSpaceByteBuffer (int pid, AddressSpace addressSpace,
+    protected AddressSpaceByteBuffer (int pid, AddressSpace addressSpace,
 				    long lowerExtreem, long upperExtreem)
     {
 	super (lowerExtreem, upperExtreem);
Index: frysk-core/frysk/proc/live/LinuxTask.java
===================================================================
RCS file: /cvs/frysk/frysk-core/frysk/proc/live/LinuxTask.java,v
retrieving revision 1.3
diff -u -r1.3 LinuxTask.java
--- frysk-core/frysk/proc/live/LinuxTask.java	18 Jul 2007 20:00:31 -0000	1.3
+++ frysk-core/frysk/proc/live/LinuxTask.java	20 Jul 2007 10:53:38 -0000
@@ -39,6 +39,7 @@
 
 package frysk.proc.live;
 
+import frysk.proc.BreakpointAddresses;
 import frysk.proc.TaskObserver;
 import frysk.proc.Proc;
 import frysk.proc.TaskId;
@@ -52,9 +53,11 @@
 import frysk.proc.Isa;
 import frysk.sys.Errno;
 import frysk.sys.Ptrace;
+import frysk.sys.Ptrace.AddressSpace;
 import frysk.sys.Sig;
 import frysk.sys.Signal;
 
+
 /**
  * A Linux Task tracked using PTRACE.
  */
@@ -88,9 +91,9 @@
 
 
     /**
-     * Return the memory byte-buffer.
+     * Return the raw memory byte-buffer.
      */
-    protected ByteBuffer sendrecMemory ()
+    public ByteBuffer getRawMemory ()
     {
 	logger.log(Level.FINE, "Begin fillMemory\n", this);
 	ByteOrder byteOrder = getIsa().getByteOrder();
@@ -99,7 +102,16 @@
 	logger.log(Level.FINE, "End fillMemory\n", this); 
 	return memory;
     }
-    
+
+    protected ByteBuffer sendrecMemory ()
+    {
+      int tid = getTid();
+      ByteOrder byteOrder = getIsa().getByteOrder();
+      BreakpointAddresses breakpoints = getProc().breakpoints;
+      return new LogicalMemoryBuffer(tid, AddressSpace.DATA,
+				     byteOrder, breakpoints);
+    }
+
     /**
      * Return the ISA's register-bank byte-buffers.
      */
Index: frysk-core/frysk/proc/live/LogicalMemoryBuffer.java
===================================================================
RCS file: frysk-core/frysk/proc/live/LogicalMemoryBuffer.java
diff -N frysk-core/frysk/proc/live/LogicalMemoryBuffer.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ frysk-core/frysk/proc/live/LogicalMemoryBuffer.java	20 Jul 2007 10:53:38 -0000
@@ -0,0 +1,152 @@
+// 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.live;
+
+import frysk.proc.Breakpoint;
+import frysk.proc.BreakpointAddresses;
+import frysk.proc.Instruction;
+
+import java.util.Iterator;
+
+import inua.eio.ByteBuffer;
+import inua.eio.ByteOrder;
+
+import frysk.sys.Ptrace.AddressSpace;
+
+/**
+ * MemorySpaceByteBuffer that filters out anything the frysk core
+ * might have done to the underlying memory. It takes the breakpoints
+ * embedded in the process and on a peek will filter those out and
+ * replace the bytes with the logical bytes as the user would normally
+ * see them from the process.
+ */
+class LogicalMemoryBuffer extends AddressSpaceByteBuffer
+{
+  // Byte order set on the buffer (needed for creating a subBuffer).
+  private final ByteOrder order;
+
+  // The breakpoints associated with the process address space.
+  private final BreakpointAddresses breakpoints;
+
+  // Private constructor used by subBuffer()
+  private LogicalMemoryBuffer(int tid, AddressSpace addressSpace,
+			      ByteOrder order,
+			      BreakpointAddresses breakpoints,
+			      long lower, long upper)
+  {
+    super(tid, addressSpace, lower, upper);
+    order(order);
+    this.order = order;
+    this.breakpoints = breakpoints;
+  }
+  
+  // Package local contructor used by LinuxTask to create a logical
+  // memory space for a task when requested.
+  LogicalMemoryBuffer(int tid,
+		      AddressSpace addressSpace,
+		      ByteOrder order,
+		      BreakpointAddresses breakpoints)
+  {
+    super(tid, addressSpace);
+    order(order);
+    this.order = order;
+    this.breakpoints = breakpoints;
+  }
+  
+  protected int peek(long caret)
+  {
+    Breakpoint breakpoint = breakpoints.getBreakpoint(caret);
+    if (breakpoint != null)
+      {
+	// This really shouldn't happen, it means the breakpoint
+	// is already uninstalled.
+	Instruction instruction = breakpoint.getInstruction();
+	if (instruction != null)
+	  {
+	    byte[] ibs = instruction.getBytes();
+	    return ibs[0] & 0xff;
+	  }
+      }
+    return super.peek(caret);
+  }
+  
+  protected long peek(long index, byte[] bytes, long offset, long length)
+  {
+    synchronized (breakpoints)
+      {
+	Iterator it;
+	it = breakpoints.getBreakpoints(index, index + length);
+	long r = 0;
+	while (it.hasNext())
+	  {
+	    Breakpoint breakpoint = (Breakpoint) it.next();
+	    long l = breakpoint.getAddress() - (index + r);
+	    // Do we need to be worried about "short peeks"?
+	    r += super.peek(index + r, bytes, offset + r, l);
+
+	    byte b;
+	    Instruction instruction = breakpoint.getInstruction();
+	    // This really shouldn't happen, it means the breakpoint
+	    // is already uninstalled.
+	    if (instruction != null)
+	      b = instruction.getBytes()[0];
+	    else
+	      b = (byte) super.peek(index + r);
+	    // Since we are addressing a array both offset and r
+	    // cannot really be bigger than an int, they could still
+	    // overflow, but then we get a negative offset exception
+	    // which seems fine because in that case offset + r was
+	    // already larger than the array length.
+	    bytes[(int) (offset + r)] = b;
+	    r++;
+	  }
+	return super.peek(index + r, bytes, offset + r, length - r) + r;
+      }
+  }
+  
+  protected ByteBuffer subBuffer(ByteBuffer parent,
+				 long lower, long upper)
+  {
+    LogicalMemoryBuffer sub = (LogicalMemoryBuffer) parent;
+    return new LogicalMemoryBuffer (sub.pid, sub.addressSpace,
+				    sub.order, sub.breakpoints,
+				    lower, upper);
+  }
+}

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