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