public inbox for frysk@sourceware.org
 help / color / mirror / Atom feed
* Fix for #5260
@ 2008-01-10  5:10 Mike Cvet
  0 siblings, 0 replies; only message in thread
From: Mike Cvet @ 2008-01-10  5:10 UTC (permalink / raw)
  To: frysk

[-- Attachment #1: Type: text/plain, Size: 418 bytes --]

I've attached some code which fixes the "stepping through a plt" problem 
listed in #5260. It identifies if the user has stepped into a .plt 
section in the program, and steps through the dynamic library linking 
code, landing the user back in their program.

I've included a test for it and ensured that it does not break any 
current tests; if nobody has any problems I'll commit it in a day or two.

Thanks!
- Mike

[-- Attachment #2: 5260.patch --]
[-- Type: text/x-patch, Size: 21404 bytes --]

diff --git a/frysk-core/frysk/hpd/StepInstructionCommand.java b/frysk-core/frysk/hpd/StepInstructionCommand.java
index 42d55e8..f683f1d 100644
--- a/frysk-core/frysk/hpd/StepInstructionCommand.java
+++ b/frysk-core/frysk/hpd/StepInstructionCommand.java
@@ -70,7 +70,7 @@ public class StepInstructionCommand extends ParameterizedCommand {
                } catch (InterruptedException ie) {
                }
            }
-           Iterator stepped = taskList.iterator();
+           Iterator stepped = ptset.getTasks();
            while (stepped.hasNext()) {
                Task task = (Task) stepped.next();
                DebugInfoFrame rf = cli.getTaskFrame(task);

diff --git a/frysk-core/frysk/stepping/InstructionStepState.java b/frysk-core/frysk/stepping/InstructionStepState.java
index 9557a77..8903147 100644
--- a/frysk-core/frysk/stepping/InstructionStepState.java
+++ b/frysk-core/frysk/stepping/InstructionStepState.java
@@ -39,23 +39,48 @@
 
 package frysk.stepping;
 
+import frysk.dwfl.ElfSectionCache;
 import frysk.proc.Task;
+import lib.dwfl.DwflLine;
+import lib.dwfl.ElfSectionHeader;
 
 public class InstructionStepState extends State {
+
+    private ElfSectionCache elfCache;
+    private final String PLT_DL_FIXUP = "_dl_fixup";
+
     public InstructionStepState(Task task) {
        this.task = task;
     }
 
     /**
-         * When the instruction observer from SteppingEngine returns, a single
-         * step has been performed. All that is left to do is to reset the State
-         * for this Task back to a StoppedState.
-         * 
-         * @param tse
-         *                The TaskStepEngine for this State.
-         * @return new StoppedState
-         */
+     * When the instruction observer from SteppingEngine returns, a single
+     * step has been performed. All that is left to do is to reset the State
+     * for this Task back to a StoppedState.
+     * 
+     * @param tse
+     *                The TaskStepEngine for this State.
+     * @return new StoppedState
+     */
     public State handleUpdate(TaskStepEngine tse) {
+
+       long addr = this.task.getIsa().pc(task);
+       this.elfCache = new ElfSectionCache(this.task);
+       ElfSectionHeader header = this.elfCache.getSectionHeader(".plt", addr);
+
+       /* If the user steps into a function call, the following catches the .plt section of the program, and
+        * ensures that Frysk steps past it, so that the user is landed back into their own code after the call. */
+       if ((header != null && header.addr <= addr && (header.addr + header.offset) >= addr)
+               && (header.type == ElfSectionHeader.ELF_SHT_PROGBITS || header.type == ElfSectionHeader.ELF_SHT_NOBITS)) {
+
+           DwflLine line = tse.getDwflLine();
+
+           if (line == null) {
+               tse.getSteppingEngine().continueForStepping(this.task, true);
+               return new InstructionStepThroughState(task, PLT_DL_FIXUP);
+           }
+       }
+
        return new StoppedState(this.task);
     }
 
diff --git a/frysk-core/frysk/stepping/LineStepState.java b/frysk-core/frysk/stepping/LineStepState.java
index 59d9539..19ba783 100644
--- a/frysk-core/frysk/stepping/LineStepState.java
+++ b/frysk-core/frysk/stepping/LineStepState.java
@@ -41,8 +41,11 @@ package frysk.stepping;
 
 import lib.dwfl.DwflLine;
 import frysk.proc.Task;
+//import frysk.stack.Frame;
+//import frysk.stack.StackFactory;
 
 public class LineStepState extends State {
+    
     public LineStepState(Task task) {
        this.task = task;
     }
@@ -56,15 +59,25 @@ public class LineStepState extends State {
      * @return this    If the line has not changed yet
      */
     public State handleUpdate(TaskStepEngine tse) {
-       int lineNum;
+       int lineNum = 0;
        DwflLine line = tse.getDwflLine();
 
        if (line == null) /* We're in no-debuginfo land */
        {
            tse.setLine(0);
-           /* Returned a StoppedState because line-stepping has no meaning
-            * when there is no debug information to relate the 'lines' to. */
-           return new StoppedState(this.task);
+           
+           /* Assume the user has stepped into some sort of library call for which
+            * there is no debugging information. Continue stepping through this 
+            * area until either new code with debuginfo is encountered, or the original
+            * calling code is returned to. */
+           
+           //Frame frame = StackFactory.createFrame(task);
+           //System.err.println("LineStepState:handleUpdate - no line " + frame.getSymbol().getDemangledName() + " 0x" + Long.toHexString(frame.getSymbol().
+           
+           //tse.getSteppingEngine().continueForStepping(this.task, true);
+           
+           //return this;
+               return new StoppedState(this.task);
        } else
            lineNum = line.getLineNum();
 
diff --git a/frysk-core/frysk/stepping/SteppingEngine.java b/frysk-core/frysk/stepping/SteppingEngine.java
index 68584ca..2b71fa7 100644
--- a/frysk-core/frysk/stepping/SteppingEngine.java
+++ b/frysk-core/frysk/stepping/SteppingEngine.java
@@ -487,9 +487,9 @@ public class SteppingEngine {
      * @param task   The Task to be stepped
      * @param frame The frame to step out of.
      */
-    public void stepOut(Task task, DebugInfoFrame frame) {
+    public void stepOut(Task task, Frame frame) {
 
-       long address = frame.getOuterDebugInfoFrame().getAddress();
+       long address = frame.getOuter().getAddress();
 
        TaskStepEngine tse = (TaskStepEngine) this.taskStateMap.get(task);
        tse.setState(new StepOutState(task));
@@ -502,6 +502,22 @@ public class SteppingEngine {
        this.breakpointMap.put(task, this.breakpoint);
        task.requestAddCodeObserver(this.breakpoint, address);
     }
+    
+    public void stepOut(Task task, Frame frame, State state) {
+
+       long address = frame.getOuter().getAddress();
+
+       TaskStepEngine tse = (TaskStepEngine) this.taskStateMap.get(task);
+       tse.setState(state);
+       this.steppingObserver.notifyNotBlocked(tse);
+
+       int i = ((Integer) this.contextMap.get(task.getProc())).intValue();
+       this.contextMap.put(task.getProc(), new Integer(++i));
+
+       this.breakpoint = new SteppingBreakpoint(this, address);
+       this.breakpointMap.put(task, this.breakpoint);
+       task.requestAddCodeObserver(this.breakpoint, address);
+    }
 
     /**
      * Performs a step-out operation on a list of Tasks - runs each Task until 
diff --git a/frysk-core/frysk/stepping/TaskStepEngine.java b/frysk-core/frysk/stepping/TaskStepEngine.java
index 6f35c67..6a84c14 100644
--- a/frysk-core/frysk/stepping/TaskStepEngine.java
+++ b/frysk-core/frysk/stepping/TaskStepEngine.java
@@ -54,6 +54,7 @@ import lib.dwfl.DwflLine;
  * State.handleUpdate().
  */
 public class TaskStepEngine {
+    
     private SteppingEngine steppingEngine;
 
     /* The Task for this TaskStepEngine */
diff --git a/frysk-core/frysk/stepping/TestStepping.java b/frysk-core/frysk/stepping/TestStepping.java
index 40df4e9..0ca8037 100644
--- a/frysk-core/frysk/stepping/TestStepping.java
+++ b/frysk-core/frysk/stepping/TestStepping.java
@@ -43,6 +43,7 @@ import java.io.File;
 import java.util.HashMap;
 import java.util.Observable;
 import java.util.Observer;
+
 import frysk.testbed.Offspring;
 import frysk.testbed.SynchronizedOffspring;
 import frysk.Config;
@@ -1009,6 +1010,81 @@ public class TestStepping extends TestLib {
        assertRunUntilStop("Running test");
        cleanup();
     }
+    
+    public void testInstructionStepThroughSection() {
+
+       class InstructionStepThroughSectionTest implements SteppingTest {
+
+           Task testTask = null;
+           String callingFrame = "foo";
+           boolean first = true;
+           int endLine = 0;
+           
+           public InstructionStepThroughSectionTest(Task task, int lineNum) {
+               testTask = task;
+               endLine = lineNum;
+           }
+
+           public void runAssertions() {
+               
+               DebugInfoFrame frame = DebugInfoStackFactory
+               .createDebugInfoStackTrace(testTask);
+       
+               String s = frame.getSymbol().getDemangledName();
+               
+               if (first) {
+                   se.stepLine(this.testTask);
+                   this.first = false;
+                   return;
+               }
+               
+               assertEquals("calling frame", callingFrame, s);
+               assertEquals("line number", endLine, frame.getLine().getLine());
+               Manager.eventLoop.requestStop();
+           }
+       }
+
+       /** Variable setup */
+       String source = Config.getRootSrcDir()
+               + "frysk-core/frysk/pkglibdir/funit-libcall.c";
+
+       this.scanner = new TestfileTokenScanner(new File(source));
+
+       int startLine = this.scanner.findTokenLine("_testIStepThrough_");
+
+       int endLine = startLine + 1;
+
+       /* The test process */
+       dbae = new DaemonBlockedAtEntry(Config.getPkgLibFile("funit-libcall"));
+
+       Task theTask = dbae.getMainTask();
+
+       this.testStarted = false;
+
+       initTaskWithTask(theTask, source, startLine, endLine);
+
+       this.currentTest = new InstructionStepThroughSectionTest(theTask, endLine);
+
+       DebugInfoFrame frame = DebugInfoStackFactory
+               .createDebugInfoStackTrace(theTask);
+       assertTrue("Line information present",
+               frame.getLine() != SourceLocation.UNKNOWN);
+
+       /** The stepping operation */
+       this.se.stepLine(theTask);
+
+       this.testStarted = true;
+       /** Run to completion */
+       assertRunUntilStop("Running test");
+       cleanup();
+    }

+// 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.dwfl;
+
+import java.util.WeakHashMap;
+
+import frysk.proc.Task;
+import lib.dwfl.Dwfl;
+import lib.dwfl.DwflModule;
+import lib.dwfl.Elf;
+import lib.dwfl.ElfSection;
+import lib.dwfl.ElfSectionHeader;
+import lib.dwfl.ModuleElfBias;
+
+/**
+ * Class to provide and cache requested ElfSectionHeaders based on name.
+ */
+public class ElfSectionCache {
+    
+    private Task task;
+    private WeakHashMap sectionMap;
+    
+    public ElfSectionCache (Task task) {
+	this.task = task;
+	this.sectionMap = new WeakHashMap();
+    }
+    
+    /**
+     * Returns an ElfSectionHeader representing the ELF header for this class' Task object as
+     * given by the section name and module address in the parameters to this method. Also
+     * caches the headers in a WeakHashMap for later use.
+     * 
+     * @param name	The name of the section
+     * @param addr	The module address
+     * @return		The corresponding ElfSectionHeader
+     */
+    public ElfSectionHeader getSectionHeader(String name, long addr) {
+	
+	if (this.sectionMap.containsKey(name))
+	    return (ElfSectionHeader) this.sectionMap.get(name);
+	
+	Dwfl dwfl = DwflCache.getDwfl(this.task);
+	DwflModule dwflModule = dwfl.getModule(addr);
+	ModuleElfBias elfBias = dwflModule.getElf();
+	Elf elf = elfBias.elf;
+	
+	for (ElfSection section = elf.getSection(0);
+	 section != null;
+	 section = elf.getNextSection(section)) {
+	    
+	    ElfSectionHeader sheader = section.getSectionHeader();
+	    if (sheader.name != null && sheader.name.equals(name)) {
+		
+		this.sectionMap.put(name, sheader);
+		return sheader;
+	    }
+	}
+	
+	return null;
+    }
+    
+    public Task getTask() {
+	return this.task;
+    }
+
+}

+// 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.dwfl;
+
+import lib.dwfl.ElfSectionHeader;
+import frysk.Config;
+import frysk.proc.Task;
+import frysk.testbed.DaemonBlockedAtEntry;
+import frysk.testbed.TestLib;
+
+public class TestElfSectionCache extends TestLib {
+    
+    public void testGetSectionHeader() {
+	
+	DaemonBlockedAtEntry dbae = new DaemonBlockedAtEntry(Config.getPkgLibFile("funit-libcall"));
+	Task task = dbae.getMainTask();
+	
+	long addr = task.getIsa().pc(task);
+	ElfSectionCache e = new ElfSectionCache(task);
+	
+	ElfSectionHeader plt = e.getSectionHeader(".plt", addr);
+	
+	assertTrue("Section not null", (plt != null));
+	assertTrue("Section name not null", (plt.name != null));
+	assertTrue("Section addr not zero", (plt.addr != 0));
+	assertTrue("Section offset not zero", (plt.offset != 0));
+    }
+
+}

+// 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.stepping;
+
+import lib.dwfl.DwflLine;
+import frysk.proc.Task;
+import frysk.stack.Frame;
+import frysk.stack.StackFactory;
+
+public class InstructionStepThroughState extends State {
+
+    private String name;
+    private int steppingOut = 0;
+
+    public InstructionStepThroughState(Task task) {
+	this.task = task;
+	this.name = null;
+    }
+
+    public InstructionStepThroughState(Task task, String name) {
+	this.task = task;
+	this.name = name;
+    }
+
+    /**
+     * State used to represent when a task has entered some section of the program (such
+     * as a .plt section) which must be carefully stepped through.
+     * 
+     * @param tse
+     *                The TaskStepEngine for this State.
+     * @return this	If more stepping needs to be done.
+     * @return StoppedState	If we have returned to user code. 
+     */
+    public State handleUpdate(TaskStepEngine tse) {
+
+	Frame frame = StackFactory.createFrame(task);
+	
+	/* This object has already performed a step-out operation on the task.
+	 * Here, clean up and perform another to return to user code. */
+	if (this.steppingOut == 1) {
+
+	    this.steppingOut = 2;
+	    tse.getSteppingEngine().removeBreakpoint(this.task);
+	    
+	    /* Here, we're back in  _dl_runtime_resolve - step out of this as well. */
+	    tse.getSteppingEngine().stepOut(this.task, frame, this); 
+	    return this;
+	    
+	} else if (this.steppingOut == 2) {
+	    
+	    this.steppingOut = 0;
+	    tse.getSteppingEngine().removeBreakpoint(this.task);
+	}
+
+	/* The frame being searched for has been reached. Perform a step-out. */
+	if (frame.getSymbol().getDemangledName().equals(this.name)) {
+	    
+	    this.steppingOut = 1;
+	    tse.getSteppingEngine().stepOut(this.task, frame, this);
+	    return this;
+
+	} else if (frame.getSymbol().getDemangledName().contains("_start")) {
+	    /* Avoid handling any code having to do with the initialization of a process */
+	    
+	    return new StoppedState(this.task);
+	    
+	} else {
+	    
+	    /* Inside some code without debuginfo, and isn't the function we're interested in.
+	     * Continue stepping through it. */
+	    if (tse.getLine() == 0) {
+		
+		DwflLine line = tse.getDwflLine();
+
+		if (line == null) {
+		    tse.getSteppingEngine()
+			    .continueForStepping(this.task, true);
+		    return this;
+		} else {
+		    /* Back in debuginfo. Finish the stepping operation. */
+		    return new StoppedState(this.task);
+		}
+	    } else {
+		/* Back in debuginfo. Finish the stepping operation. */
+		return new StoppedState(this.task);
+	    }
+	}
+    }
+
+    public boolean isStopped() {
+	return false;
+    }
+
+    public boolean isAlive() {
+	return true;
+    }
+}



^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2008-01-10  5:10 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-01-10  5:10 Fix for #5260 Mike Cvet

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).