This is the mail archive of the frysk-cvs@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]

[SCM] frysk system monitor/debugger branch, master, updated. b64b53ab72226ccc8c0bab0372a6de8328d22f81


The branch, master has been updated
       via  b64b53ab72226ccc8c0bab0372a6de8328d22f81 (commit)
      from  9db08d018eb772dc97a7244e1c8bde3fbd523f8d (commit)

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

- Log -----------------------------------------------------------------
commit b64b53ab72226ccc8c0bab0372a6de8328d22f81
Author: Petr Machata <pmachata@redhat.com>
Date:   Thu Nov 8 14:02:46 2007 +0100

    Support for _dl_debug_state mmap/unmap guard.
    
    * Map/unmap guard refactored to class of its own.  Method attachTo(Task) will pick either _dl_debug_state-based guard, or syscall-based guard if the former isn't available for some reason.
    * Few coding style changes across the code.  Trying to become java compliant if the resulting patch is small enough.

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

Summary of changes:
 frysk-core/frysk/bindir/ChangeLog                  |    4 +
 frysk-core/frysk/bindir/fltrace.java               |   16 +-
 frysk-core/frysk/ftrace/ChangeLog                  |   10 +
 frysk-core/frysk/ftrace/Ltrace.java                |   41 ++---
 ...traceController.java => MappingController.java} |   17 +-
 frysk-core/frysk/ftrace/MappingGuard.java          |  182 ++++++++++++++++++++
 frysk-core/frysk/ftrace/ObjectFile.java            |  121 ++++++++------
 7 files changed, 300 insertions(+), 91 deletions(-)
 copy frysk-core/frysk/ftrace/{LtraceController.java => MappingController.java} (85%)
 create mode 100644 frysk-core/frysk/ftrace/MappingGuard.java

First 500 lines of diff:
diff --git a/frysk-core/frysk/bindir/ChangeLog b/frysk-core/frysk/bindir/ChangeLog
index 1b9e5b0..efc7825 100644
--- a/frysk-core/frysk/bindir/ChangeLog
+++ b/frysk-core/frysk/bindir/ChangeLog
@@ -1,3 +1,7 @@
+2007-11-08  Petr Machata  <pmachata@redhat.com>
+
+	* fltrace.java (MyLtraceObserver.pidInfo): new method
+
 2007-11-08  Phil Muldoon  <pmuldoon@redhat.com>
 
 	* TestFhd.java (testHpdCore): Add unresolved(5295).
diff --git a/frysk-core/frysk/bindir/fltrace.java b/frysk-core/frysk/bindir/fltrace.java
index 0b6c2e0..36ac581 100644
--- a/frysk-core/frysk/bindir/fltrace.java
+++ b/frysk-core/frysk/bindir/fltrace.java
@@ -325,6 +325,11 @@ public class fltrace
 	return new String(fill);
       }
 
+      private String pidInfo(Task task)
+      {
+	  return "[" + task.getProc().getPid() + "." + task.getTid() + "]";
+      }
+
       private void eventEntry(Task task, Object item, String eventType,
 			      String eventName, Object[] args)
       {
@@ -335,7 +340,7 @@ public class fltrace
         if (lineOpened())
 	  System.err.println('\\');
 
-    	System.err.print("[" + task.getTaskId().intValue() + "] "
+    	System.err.print(pidInfo(task) + " "
 			 + spaces + eventType + " ");
 	System.err.print(eventName + "(");
 	for (int i = 0; i < args.length; ++i) {
@@ -365,8 +370,7 @@ public class fltrace
             if (lineOpened())
 	      System.err.println();
 	    String spaces = repeat(' ', level);
-	    System.err.print("[" + task.getTaskId().intValue() + "] "
-			     + spaces + eventType + " " + eventName);
+	    System.err.print(pidInfo(task) + " " + spaces + eventType + " " + eventName);
 	  }
 
 	System.err.println(" = " + retVal);
@@ -376,12 +380,11 @@ public class fltrace
 
       private void eventSingle(Task task, String eventName)
       {
-	int pid = task.getTid();
 	int level = this.getLevel(task);
 
         if (lineOpened())
 	  System.err.println("\\");
-	System.err.println("[" + pid + "] " + repeat(' ', level) + eventName);
+	System.err.println(pidInfo(task) + " " + repeat(' ', level) + eventName);
 
         updateOpenLine(null, null);
       }
@@ -455,8 +458,7 @@ public class fltrace
       {
 	if (lineOpened())
 	  System.err.println('\\');
-	int pid = task.getTid();
-	System.err.print("[" + pid + "] ");
+	System.err.print(pidInfo(task) + " ");
 	if (signal)
 	  System.err.println("killed by " + Sig.toPrintString(value));
 	else
diff --git a/frysk-core/frysk/ftrace/ChangeLog b/frysk-core/frysk/ftrace/ChangeLog
index 99bbec7..2be067c 100644
--- a/frysk-core/frysk/ftrace/ChangeLog
+++ b/frysk-core/frysk/ftrace/ChangeLog
@@ -1,3 +1,13 @@
+2007-11-08  Petr Machata  <pmachata@redhat.com>
+
+	* MappingController.java: New file.
+	* MappingGuard.java: New file.
+	* Ltrace.java: No longer trace syscalls by default.
+	(LtraceTaskObserver.updateSyscallLeave): Move to MappingGuard.
+	* ObjectFile.java: Now loads program interpreter.
+	(setInterp, getInterp): New methods.
+	(lookupTracePoint): New method.
+
 2007-11-02  Petr Machata  <pmachata@redhat.com>
 
 	* TestLtrace.java (testArgumentsCorrect1): New test.
diff --git a/frysk-core/frysk/ftrace/Ltrace.java b/frysk-core/frysk/ftrace/Ltrace.java
index b359c4c..97979c9 100644
--- a/frysk-core/frysk/ftrace/Ltrace.java
+++ b/frysk-core/frysk/ftrace/Ltrace.java
@@ -73,10 +73,11 @@ public class Ltrace
   // True if we're tracing signals as well.
   boolean traceSignals = false;
 
-  // True if we're tracing syscalls.  Currently true by default,
-  // because we need to trace syscalls for correct mmap/munmap
-  // handling.
-  boolean traceSyscalls = true;
+  // True if we're tracing syscalls.
+  // TODO: this shouldn't be part of Ltrace class at all.  Make it so
+  // that Ltrace observes Tasks, and plug Ltrace into Ftrace's
+  // framework.
+  boolean traceSyscalls = false;
 
   // Task counter.
   int numTasks = 0;
@@ -313,7 +314,8 @@ public class Ltrace
 	       TaskObserver.Syscall,
 	       TaskObserver.Signaled,
 	       TaskObserver.Terminated,
-	       TaskObserver.Terminating
+	       TaskObserver.Terminating,
+	       MappingController
   {
     /** Remembers which files are currently mapped in which task. */
     private HashMap mapsForTask = new HashMap();
@@ -327,6 +329,9 @@ public class Ltrace
         Map&lt;task, Map&lt;address, List&lt;TracePoint&gt;&gt;&gt; */
     private HashMap retBreakpointsForTask = new HashMap();
 
+    /** Keeps track of map/unmap events. */
+    private MappingGuard mappingGuard = new MappingGuard(this);
+
     // ---------------------
     // --- ltrace driver ---
     // ---------------------
@@ -479,21 +484,6 @@ public class Ltrace
 	    }
 	}
 
-      // Unfortunately, I know of no reasonable, (as in platform
-      // independent) way to find whether a syscall is mmap,
-      // munmap, or anything else.  Hence this hack, which is
-      // probably still much better than rescanning the map on
-      // each syscall.
-      String name = syscall.getName();
-
-      if (name.indexOf("mmap") != -1
-	  || name.indexOf("munmap") != -1)
-	{
-	  this.checkMapUnmapUpdates(task, false);
-	  task.requestUnblock(this);
-	  return Action.BLOCK;
-	}
-
       return Action.CONTINUE;
     }
 
@@ -637,15 +627,14 @@ public class Ltrace
       long pc = task.getIsa().pc(task);
       logger.log(Level.FINE,
 		 "new task attached at 0x" + Long.toHexString(pc)
-		 + ", pid=" + task.getTaskId().intValue(), this);
+		 + ", pid=" + task.getTaskId().intValue());
 
       this.mapsForTask.put(task, java.util.Collections.EMPTY_SET);
-
-      // Can't use the EMPTY_MAPs here, cause these get modified directly.
       this.breakpointsForTask.put(task, new HashMap());
       this.retBreakpointsForTask.put(task, new HashMap());
 
       this.checkMapUnmapUpdates(task, false);
+      mappingGuard.attachTo(task);
 
       task.requestUnblock(this);
       return Action.BLOCK;
@@ -711,6 +700,12 @@ public class Ltrace
     // --- mmap/munmap handling ---
     // ----------------------------
 
+    /** Implementation of MappingController interface... */
+    public void checkMapUnmapUpdates(Task task)
+    {
+	checkMapUnmapUpdates(task, false);
+    }
+
     private void checkMapUnmapUpdates(Task task, boolean terminating)
     {
       Set mappedFiles = (Set)this.mapsForTask.get(task);
diff --git a/frysk-core/frysk/ftrace/LtraceController.java b/frysk-core/frysk/ftrace/MappingController.java
similarity index 85%
copy from frysk-core/frysk/ftrace/LtraceController.java
copy to frysk-core/frysk/ftrace/MappingController.java
index aae77e2..6f1b02f 100644
--- a/frysk-core/frysk/ftrace/LtraceController.java
+++ b/frysk-core/frysk/ftrace/MappingController.java
@@ -40,14 +40,15 @@
 package frysk.ftrace;
 
 /**
- * The LtraceController interface is used for decisions on what should
- * be done with each loaded library.
+ * Mapping guards signal request to rescan mappings through this
+ * interface.  The interface is package-private, because noone from
+ * outside should have to use it.
  */
-public interface LtraceController
+interface MappingController
 {
-  /**
-   * New library FILE was mapped in task TASK.  Use DRIVER to tell
-   * ltrace what to do.
-   */
-  void fileMapped(frysk.proc.Task task, ObjectFile file, Ltrace.Driver driver);
+    /**
+     * New library FILE was mapped in task TASK.  Use DRIVER to tell
+     * ltrace what to do.
+     */
+    void checkMapUnmapUpdates(frysk.proc.Task task);
 }
diff --git a/frysk-core/frysk/ftrace/MappingGuard.java b/frysk-core/frysk/ftrace/MappingGuard.java
new file mode 100644
index 0000000..e88e226
--- /dev/null
+++ b/frysk-core/frysk/ftrace/MappingGuard.java
@@ -0,0 +1,182 @@
+// 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.ftrace;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.logging.*;
+
+import frysk.proc.Action;
+import frysk.proc.Task;
+import frysk.proc.TaskObserver;
+
+class MappingGuard
+    implements TaskObserver.Code,
+	       TaskObserver.Syscall
+{
+    protected static final Logger logger = Logger.getLogger(FtraceLogger.LOGGER_ID);
+    private HashMap syscallCache = new HashMap();
+    private MappingController ltraceProper;
+
+    public MappingGuard(MappingController ltraceProper) {
+	this.ltraceProper = ltraceProper;
+    }
+
+    public Action updateHit (Task task, long address)
+    {
+	ltraceProper.checkMapUnmapUpdates(task);
+	task.requestUnblock(this);
+	return Action.BLOCK;
+    }
+
+    public Action updateSyscallEnter (Task task)
+    {
+	frysk.proc.Syscall syscall = task.getSyscallEventInfo().getSyscall(task);
+	syscallCache.put(task, syscall);
+	return Action.CONTINUE;
+    }
+
+    public Action updateSyscallExit (Task task)
+    {
+	frysk.proc.Syscall syscall = (frysk.proc.Syscall)syscallCache.remove(task);
+
+	// Unfortunately, I know of no reasonable (as in
+	// platform independent) way to find whether a syscall
+	// is mmap, munmap, or anything else.  Hence this hack,
+	// which is probably still much better than rescanning
+	// the map on each syscall.
+	String name = syscall.getName();
+	if (name.indexOf("mmap") != -1 || name.indexOf("munmap") != -1) {
+	    ltraceProper.checkMapUnmapUpdates(task);
+	    task.requestUnblock(this);
+	    return Action.BLOCK;
+	}
+
+	return Action.CONTINUE;
+    }
+
+    public void addFailed(Object o, Throwable t) {}
+    public void deletedFrom(Object o) {}
+    public void addedTo(Object o) {}
+
+    /**
+     * Try to setup guard based on _dl_debug_state.
+     *
+     * Set up _dl_debug_state observer to spot each mapping.  The
+     * proper way to do this is to look up the DT_DEBUG entry in
+     * task's DYNAMIC segment, and look into the structure it points
+     * to.  But we would have to wait for dynamic linker to fill
+     * this info, and meanwhile we would miss all the
+     * mapping/unmapping.
+     *
+     * @return true on success, false on failure.
+     */
+    private boolean setupDebugStateObserver(Task task)
+    {
+	logger.log(Level.FINE, "Entering....");
+
+	java.io.File f = new java.io.File(task.getProc().getExe());
+	ObjectFile objf = ObjectFile.buildFromFile(f);
+	String interp = objf.getInterp();
+	if (interp == null) {
+	    // We're boned.
+	    logger.log(Level.WARNING, "`{1}' has no interpreter.", f);
+	    return false;
+	}
+
+	java.io.File interppath = new java.io.File(interp);
+	try {
+	    interppath = interppath.getCanonicalFile();
+	}
+	catch (java.io.IOException e) {
+	    logger.log(Level.WARNING,
+		       "Couldn't get canonical path of ELF interpreter `{1}'.",
+		       interppath);
+	    return false;
+	}
+
+	ObjectFile interpf = ObjectFile.buildFromFile(interppath);
+	TracePoint tp = null;
+	try {
+	    tp = interpf.lookupTracePoint("_dl_debug_state",
+					  TracePointOrigin.DYNAMIC);
+	    if (tp == null) {
+		logger.log(Level.FINE,
+			   "Symbol _dl_debug_state not found in `{1}'.",
+			   interppath);
+		return false;
+	    }
+	}
+	catch (lib.dwfl.ElfException e) {
+	    e.printStackTrace();
+	    logger.log(Level.WARNING,
+		       "Problem reading DYNAMIC entry points from `{1}'",
+		       interppath);
+	    return false;
+	}
+
+	// Load initial set of mapped files.
+	Set currentMappings = MemoryMapping.buildForPid(task.getTid());
+	long relocation = -1;
+	for (Iterator it = currentMappings.iterator(); it.hasNext(); ) {
+	    MemoryMapping mm = (MemoryMapping)it.next();
+	    if (mm.path.equals(interppath)) {
+		relocation = mm.addressLow - interpf.getBaseAddress();
+		break;
+	    }
+	}
+	if (relocation == -1) {
+	    logger.log(Level.FINE, "Couldn't obtain relocation of interpreter.");
+	    return false;
+	}
+
+	// There we go!
+	long fin = tp.address + relocation;
+	task.requestAddCodeObserver(this, fin);
+	return true;
+    }
+
+    public void attachTo(Task task)
+    {
+	if (!setupDebugStateObserver(task))
+	    task.requestAddSyscallObserver(this);
+    }
+}
diff --git a/frysk-core/frysk/ftrace/ObjectFile.java b/frysk-core/frysk/ftrace/ObjectFile.java
index 8400e1e..ba9dbd7 100644
--- a/frysk-core/frysk/ftrace/ObjectFile.java
+++ b/frysk-core/frysk/ftrace/ObjectFile.java
@@ -71,6 +71,7 @@ public class ObjectFile
 {
   private File filename;
   private String soname = null;
+  private String interp = null;
   private long baseAddress = 0;
   private long entryPoint = 0;
   private static HashMap cachedFiles = new HashMap();
@@ -181,20 +182,18 @@ public class ObjectFile
       throws lib.dwfl.ElfException
     {
       ArrayList tracePoints = (ArrayList)this.tracePointMap.get(origin);
-      if (tracePoints != null)
-	{
+      if (tracePoints != null) {
 	  logger.log(Level.FINE, "" + tracePoints.size() + " tracepoints for origin " + origin + " retrieved from cache.");
 	  return tracePoints;
-	}
+      }
 
       logger.log(Level.FINE, "Loading tracepoints for origin " + origin + ".");
       if ((origin == TracePointOrigin.PLT
 	   || origin == TracePointOrigin.DYNAMIC)
 	  && this.haveDynamic)
-	{
+      {
 	  // Initialize dynamic symbol list for PLT if necessary...
-	  if (this.dynamicSymbolList == null)
-	    {
+	  if (this.dynamicSymbolList == null) {
 	      long count = ElfSymbol.symbolsCount(ObjectFile.this.dynamicSymtab);
 	      assertFitsToInt(count, "Symbol count");
 	      this.dynamicSymbolList = new Symbol[(int)count];
@@ -202,10 +201,9 @@ public class ObjectFile
 		= new ElfSymbol.Loader(ObjectFile.this.dynamicSymtab, ObjectFile.this.dynamicVersym,
 				       ObjectFile.this.dynamicVerdef, ObjectFile.this.dynamicVerdefCount,
 				       ObjectFile.this.dynamicVerneed, ObjectFile.this.dynamicVerneedCount);
-	    }
+	  }
 
-	  if (origin == TracePointOrigin.DYNAMIC)
-	    {
+	  if (origin == TracePointOrigin.DYNAMIC) {
 	      // Load dynamic symtab and PLT entries.
 	      logger.log(Level.FINER, "Loading dynamic symtab.");
 	      this.origin = TracePointOrigin.DYNAMIC;
@@ -213,10 +211,9 @@ public class ObjectFile
 	      this.tracePointMap.put(this.origin, this.tracePoints);
 
 	      this.dynamicLoader.loadAll(this);
-	    }
+	  }
 
-	  if (origin == TracePointOrigin.PLT)
-	    {
+	  if (origin == TracePointOrigin.PLT) {
 	      int pltCount = ObjectFile.this.pltRelocs.length;
 	      logger.log(Level.FINER, "Loading " + pltCount + " PLT entries.");
 
@@ -234,22 +231,20 @@ public class ObjectFile
 		/* XXX HACK: 386/x64 specific.  In general we want
 		 * platform-independent way of asking whether it's
 		 * JMP_SLOT relocation. */
-		if (ObjectFile.this.pltRelocs[i].type == 7)
-		  {
+		if (ObjectFile.this.pltRelocs[i].type == 7) {
 		    long pltEntryAddr = ObjectFile.this.pltAddr + pltEntrySize * (i + 1);
 		    long symbolIndex = ObjectFile.this.pltRelocs[i].symbolIndex;
 
 		    assertFitsToInt(symbolIndex, "Symbol associated with PLT entry");
 		    Symbol symbol = this.dynamicSymbolList[(int)symbolIndex];
-		    if (symbol == null)
-		      {
+		    if (symbol == null) {
 			logger.log(Level.FINEST,
 				   "Lazy loading symbol #" + symbolIndex);
 			this.origin = TracePointOrigin.DYNAMIC;
 			this.tracePoints = tracePointsDynamic;
 			this.dynamicLoader.load(symbolIndex, this);
 			symbol = this.dynamicSymbolList[(int)symbolIndex];
-		      }
+		    }
 		    if (symbol == null)
 		      throw new AssertionError("Dynamic symbol still not initialized.");
 
@@ -259,12 +254,11 @@ public class ObjectFile
 		    this.origin = TracePointOrigin.PLT;
 		    this.tracePoints = tracePointsPlt;
 		    this.addNewTracepoint(pltEntryAddr, symbol);
-		  }
-	    }
-	}
+		}
+	  }
+      }


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


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