Merge remote-tracking branch 'origin/Ghidra_11.3'
|
@ -66,7 +66,7 @@ public class DebuggerCoordinates {
|
||||||
private static final String KEY_FRAME = "Frame";
|
private static final String KEY_FRAME = "Frame";
|
||||||
private static final String KEY_OBJ_PATH = "ObjectPath";
|
private static final String KEY_OBJ_PATH = "ObjectPath";
|
||||||
|
|
||||||
public static boolean equalsIgnoreRecorderAndView(DebuggerCoordinates a,
|
public static boolean equalsIgnoreTargetAndView(DebuggerCoordinates a,
|
||||||
DebuggerCoordinates b) {
|
DebuggerCoordinates b) {
|
||||||
if (!Objects.equals(a.trace, b.trace)) {
|
if (!Objects.equals(a.trace, b.trace)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -417,6 +417,36 @@ public class DebuggerCoordinates {
|
||||||
newFrame, newPath);
|
newFrame, newPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given coordinates are the same as this but with an extra or differing patch.
|
||||||
|
*
|
||||||
|
* @param that the other coordinates
|
||||||
|
* @return true if the difference is only in the final patch step
|
||||||
|
*/
|
||||||
|
public boolean differsOnlyByPatch(DebuggerCoordinates that) {
|
||||||
|
if (!Objects.equals(this.trace, that.trace)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Objects.equals(this.platform, that.platform)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!Objects.equals(this.thread, that.thread)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Consider defaults
|
||||||
|
if (!Objects.equals(this.getFrame(), that.getFrame())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!Objects.equals(this.getObject(), that.getObject())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!this.getTime().differsOnlyByPatch(that.getTime())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public DebuggerCoordinates frame(int newFrame) {
|
public DebuggerCoordinates frame(int newFrame) {
|
||||||
if (trace == null) {
|
if (trace == null) {
|
||||||
return NOWHERE;
|
return NOWHERE;
|
||||||
|
@ -621,7 +651,11 @@ public class DebuggerCoordinates {
|
||||||
if (registerContainer != null) {
|
if (registerContainer != null) {
|
||||||
return registerContainer;
|
return registerContainer;
|
||||||
}
|
}
|
||||||
return registerContainer = getObject().findRegisterContainer(getFrame());
|
TraceObject object = getObject();
|
||||||
|
if (object == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return registerContainer = object.findRegisterContainer(getFrame());
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized long getViewSnap() {
|
public synchronized long getViewSnap() {
|
||||||
|
|
|
@ -52,6 +52,10 @@ public class DebuggerTrackLocationTrait {
|
||||||
protected static final AutoConfigState.ClassHandler<DebuggerTrackLocationTrait> CONFIG_STATE_HANDLER =
|
protected static final AutoConfigState.ClassHandler<DebuggerTrackLocationTrait> CONFIG_STATE_HANDLER =
|
||||||
AutoConfigState.wireHandler(DebuggerTrackLocationTrait.class, MethodHandles.lookup());
|
AutoConfigState.wireHandler(DebuggerTrackLocationTrait.class, MethodHandles.lookup());
|
||||||
|
|
||||||
|
public enum TrackCause {
|
||||||
|
USER, DB_CHANGE, NAVIGATION, EMU_PATCH, SPEC_CHANGE_API;
|
||||||
|
}
|
||||||
|
|
||||||
protected class ForTrackingListener extends TraceDomainObjectListener {
|
protected class ForTrackingListener extends TraceDomainObjectListener {
|
||||||
|
|
||||||
public ForTrackingListener() {
|
public ForTrackingListener() {
|
||||||
|
@ -68,7 +72,7 @@ public class DebuggerTrackLocationTrait {
|
||||||
if (!tracker.affectedByBytesChange(space, range, current)) {
|
if (!tracker.affectedByBytesChange(space, range, current)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
doTrack();
|
doTrack(TrackCause.DB_CHANGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stackChanged(TraceStack stack) {
|
private void stackChanged(TraceStack stack) {
|
||||||
|
@ -79,7 +83,7 @@ public class DebuggerTrackLocationTrait {
|
||||||
if (!tracker.affectedByStackChange(stack, current)) {
|
if (!tracker.affectedByStackChange(stack, current)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
doTrack();
|
doTrack(TrackCause.DB_CHANGE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,11 +192,11 @@ public class DebuggerTrackLocationTrait {
|
||||||
public void setSpec(LocationTrackingSpec spec) {
|
public void setSpec(LocationTrackingSpec spec) {
|
||||||
if (action == null) {
|
if (action == null) {
|
||||||
// It might if the client doesn't need a new button, e.g., TraceDiff
|
// It might if the client doesn't need a new button, e.g., TraceDiff
|
||||||
doSetSpec(spec);
|
doSetSpec(spec, TrackCause.SPEC_CHANGE_API);
|
||||||
}
|
}
|
||||||
else if (!hasSpec(spec)) {
|
else if (!hasSpec(spec)) {
|
||||||
Msg.warn(this, "No action state for given tracking spec: " + spec);
|
Msg.warn(this, "No action state for given tracking spec: " + spec);
|
||||||
doSetSpec(spec);
|
doSetSpec(spec, TrackCause.SPEC_CHANGE_API);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
action.setCurrentActionStateByUserData(spec);
|
action.setCurrentActionStateByUserData(spec);
|
||||||
|
@ -234,21 +238,21 @@ public class DebuggerTrackLocationTrait {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void clickedSpecButton(ActionContext ctx) {
|
protected void clickedSpecButton(ActionContext ctx) {
|
||||||
doTrack();
|
doTrack(TrackCause.USER);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void clickedSpecMenu(ActionState<LocationTrackingSpec> newState,
|
protected void clickedSpecMenu(ActionState<LocationTrackingSpec> newState,
|
||||||
EventTrigger trigger) {
|
EventTrigger trigger) {
|
||||||
doSetSpec(newState.getUserData());
|
doSetSpec(newState.getUserData(), TrackCause.USER);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void doSetSpec(LocationTrackingSpec spec) {
|
protected void doSetSpec(LocationTrackingSpec spec, TrackCause cause) {
|
||||||
if (this.spec != spec) {
|
if (this.spec != spec) {
|
||||||
this.spec = spec;
|
this.spec = spec;
|
||||||
this.tracker = spec.getTracker();
|
this.tracker = spec.getTracker();
|
||||||
specChanged(spec);
|
specChanged(spec);
|
||||||
}
|
}
|
||||||
doTrack();
|
doTrack(cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ProgramLocation computeTrackedLocation() {
|
protected ProgramLocation computeTrackedLocation() {
|
||||||
|
@ -282,9 +286,15 @@ public class DebuggerTrackLocationTrait {
|
||||||
return spec.getLocationLabel() + " = " + trackedLocation.getByteAddress();
|
return spec.getLocationLabel() + " = " + trackedLocation.getByteAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void doTrack() {
|
protected void doTrack(TrackCause cause) {
|
||||||
try {
|
try {
|
||||||
trackedLocation = computeTrackedLocation();
|
ProgramLocation newLocation = computeTrackedLocation();
|
||||||
|
if (Objects.equals(newLocation, trackedLocation)) {
|
||||||
|
if (cause == TrackCause.DB_CHANGE || cause == TrackCause.EMU_PATCH) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trackedLocation = newLocation;
|
||||||
locationTracked();
|
locationTracked();
|
||||||
}
|
}
|
||||||
catch (Throwable ex) {
|
catch (Throwable ex) {
|
||||||
|
@ -315,11 +325,12 @@ public class DebuggerTrackLocationTrait {
|
||||||
if (doListeners) {
|
if (doListeners) {
|
||||||
removeOldListeners();
|
removeOldListeners();
|
||||||
}
|
}
|
||||||
|
boolean isPatch = current.differsOnlyByPatch(coordinates);
|
||||||
current = coordinates;
|
current = coordinates;
|
||||||
if (doListeners) {
|
if (doListeners) {
|
||||||
addNewListeners();
|
addNewListeners();
|
||||||
}
|
}
|
||||||
doTrack();
|
doTrack(isPatch ? TrackCause.EMU_PATCH : TrackCause.NAVIGATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeConfigState(SaveState saveState) {
|
public void writeConfigState(SaveState saveState) {
|
||||||
|
|
|
@ -235,7 +235,7 @@ public class DebuggerListingProvider extends CodeViewerProvider {
|
||||||
super(DebuggerListingProvider.this.tool, DebuggerListingProvider.this.plugin,
|
super(DebuggerListingProvider.this.tool, DebuggerListingProvider.this.plugin,
|
||||||
DebuggerListingProvider.this);
|
DebuggerListingProvider.this);
|
||||||
|
|
||||||
getListingPanel().addIndexMapChangeListener(e -> this.doTrack());
|
getListingPanel().addIndexMapChangeListener(e -> this.doTrack(TrackCause.DB_CHANGE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -90,7 +90,7 @@ public abstract class AbstractQueryTablePanel<T, M extends AbstractQueryTableMod
|
||||||
}
|
}
|
||||||
|
|
||||||
public void goToCoordinates(DebuggerCoordinates coords) {
|
public void goToCoordinates(DebuggerCoordinates coords) {
|
||||||
if (DebuggerCoordinates.equalsIgnoreRecorderAndView(current, coords)) {
|
if (DebuggerCoordinates.equalsIgnoreTargetAndView(current, coords)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DebuggerCoordinates previous = current;
|
DebuggerCoordinates previous = current;
|
||||||
|
|
|
@ -234,7 +234,7 @@ public class ObjectsTreePanel extends JPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void goToCoordinates(DebuggerCoordinates coords) {
|
public void goToCoordinates(DebuggerCoordinates coords) {
|
||||||
if (DebuggerCoordinates.equalsIgnoreRecorderAndView(current, coords)) {
|
if (DebuggerCoordinates.equalsIgnoreTargetAndView(current, coords)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
previous = current;
|
previous = current;
|
||||||
|
|
|
@ -470,4 +470,25 @@ public class Sequence implements Comparable<Sequence> {
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean differsOnlyByPatch(Sequence that) {
|
||||||
|
int size = this.steps.size();
|
||||||
|
if (size == that.steps.size()) {
|
||||||
|
if (size == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!this.steps.subList(0, size - 1).equals(that.steps.subList(0, size - 1))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Step thisLast = this.steps.getLast();
|
||||||
|
Step thatLast = that.steps.getLast();
|
||||||
|
return thisLast.equals(thatLast) ||
|
||||||
|
thisLast instanceof PatchStep && thatLast instanceof PatchStep;
|
||||||
|
}
|
||||||
|
if (size == that.steps.size() - 1) {
|
||||||
|
Step thatLast = that.steps.getLast();
|
||||||
|
return thatLast instanceof PatchStep;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -673,4 +673,20 @@ public class TraceSchedule implements Comparable<TraceSchedule> {
|
||||||
public TraceSchedule assumeRecorded() {
|
public TraceSchedule assumeRecorded() {
|
||||||
return new TraceSchedule(snap, steps, pSteps, Source.RECORD);
|
return new TraceSchedule(snap, steps, pSteps, Source.RECORD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean differsOnlyByPatch(TraceSchedule that) {
|
||||||
|
if (this.snap != that.snap) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.pSteps.isNop() != that.pSteps.isNop()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.pSteps.isNop()) {
|
||||||
|
return this.steps.differsOnlyByPatch(that.steps);
|
||||||
|
}
|
||||||
|
if (!this.steps.equals(that.steps)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return this.pSteps.differsOnlyByPatch(that.pSteps);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -470,4 +470,37 @@ public class TraceScheduleTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||||
"t0-{r0=0x200000001};t0-{r1l=0x3}", time.toString());
|
"t0-{r0=0x200000001};t0-{r1l=0x3}", time.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDiffersOnlyByPatch() throws Exception {
|
||||||
|
assertTrue(TraceSchedule.parse("1").differsOnlyByPatch(TraceSchedule.parse("1")));
|
||||||
|
assertTrue(TraceSchedule.parse("1:1").differsOnlyByPatch(TraceSchedule.parse("1:1")));
|
||||||
|
assertTrue(TraceSchedule.parse("1:1.1").differsOnlyByPatch(TraceSchedule.parse("1:1.1")));
|
||||||
|
assertTrue(TraceSchedule.parse("1:1;{r0=1}")
|
||||||
|
.differsOnlyByPatch(TraceSchedule.parse("1:1;{r0=1}")));
|
||||||
|
assertTrue(TraceSchedule.parse("1:1.1;{r0=1}")
|
||||||
|
.differsOnlyByPatch(TraceSchedule.parse("1:1.1;{r0=1}")));
|
||||||
|
|
||||||
|
assertFalse(TraceSchedule.parse("1").differsOnlyByPatch(TraceSchedule.parse("1:1")));
|
||||||
|
assertFalse(TraceSchedule.parse("1:1").differsOnlyByPatch(TraceSchedule.parse("1")));
|
||||||
|
|
||||||
|
assertFalse(TraceSchedule.parse("1:1").differsOnlyByPatch(TraceSchedule.parse("1:2")));
|
||||||
|
assertFalse(TraceSchedule.parse("1:2").differsOnlyByPatch(TraceSchedule.parse("1:1")));
|
||||||
|
|
||||||
|
assertFalse(TraceSchedule.parse("1:1").differsOnlyByPatch(TraceSchedule.parse("1:1.1")));
|
||||||
|
assertFalse(TraceSchedule.parse("1:1.1").differsOnlyByPatch(TraceSchedule.parse("1:1")));
|
||||||
|
|
||||||
|
assertTrue(TraceSchedule.parse("1").differsOnlyByPatch(TraceSchedule.parse("1:{r0=1}")));
|
||||||
|
assertFalse(TraceSchedule.parse("1:{r0=1}").differsOnlyByPatch(TraceSchedule.parse("1")));
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
TraceSchedule.parse("1:1").differsOnlyByPatch(TraceSchedule.parse("1:1;{r0=1}")));
|
||||||
|
assertFalse(
|
||||||
|
TraceSchedule.parse("1:1;{r0=1}").differsOnlyByPatch(TraceSchedule.parse("1:1")));
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
TraceSchedule.parse("1:1.1").differsOnlyByPatch(TraceSchedule.parse("1:1.1;{r0=1}")));
|
||||||
|
assertFalse(
|
||||||
|
TraceSchedule.parse("1:1.1;{r0=1}").differsOnlyByPatch(TraceSchedule.parse("1:1.1")));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ import docking.action.DockingActionIf;
|
||||||
import docking.widgets.fieldpanel.FieldPanel;
|
import docking.widgets.fieldpanel.FieldPanel;
|
||||||
import generic.Unique;
|
import generic.Unique;
|
||||||
import generic.jar.ResourceFile;
|
import generic.jar.ResourceFile;
|
||||||
|
import ghidra.GhidraTestApplicationLayout;
|
||||||
import ghidra.app.cmd.disassemble.DisassembleCommand;
|
import ghidra.app.cmd.disassemble.DisassembleCommand;
|
||||||
import ghidra.app.context.ProgramLocationActionContext;
|
import ghidra.app.context.ProgramLocationActionContext;
|
||||||
import ghidra.app.decompiler.component.DecompilerPanel;
|
import ghidra.app.decompiler.component.DecompilerPanel;
|
||||||
|
@ -109,6 +110,7 @@ import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.ConsoleTaskMonitor;
|
import ghidra.util.task.ConsoleTaskMonitor;
|
||||||
import help.screenshot.GhidraScreenShotGenerator;
|
import help.screenshot.GhidraScreenShotGenerator;
|
||||||
|
import utility.application.ApplicationLayout;
|
||||||
|
|
||||||
public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
|
public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
|
||||||
implements AsyncTestUtils {
|
implements AsyncTestUtils {
|
||||||
|
@ -145,6 +147,18 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ApplicationLayout createApplicationLayout() throws IOException {
|
||||||
|
return new GhidraTestApplicationLayout(new File(getTestDirectoryPath())) {
|
||||||
|
@Override
|
||||||
|
protected Set<String> getDependentModulePatterns() {
|
||||||
|
Set<String> patterns = super.getDependentModulePatterns();
|
||||||
|
patterns.add("Debugger-agent");
|
||||||
|
return patterns;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected TestEnv newTestEnv() throws Exception {
|
protected TestEnv newTestEnv() throws Exception {
|
||||||
return env = new MyTestEnv("DebuggerCourse");
|
return env = new MyTestEnv("DebuggerCourse");
|
||||||
|
@ -734,7 +748,7 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
|
||||||
mappings.addModuleMappings(proposal.computeMap().values(), monitor, true);
|
mappings.addModuleMappings(proposal.computeMap().values(), monitor, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
waitForCondition(() -> flatDbg.translateDynamicToStatic(dynAddr) != null);
|
//waitForCondition(() -> flatDbg.translateDynamicToStatic(dynAddr) != null);
|
||||||
|
|
||||||
runSwing(() -> tool.setSize(1920, 1080));
|
runSwing(() -> tool.setSize(1920, 1080));
|
||||||
captureProvider(DebuggerStaticMappingProvider.class);
|
captureProvider(DebuggerStaticMappingProvider.class);
|
||||||
|
|
|
@ -152,12 +152,16 @@ id="toc-customized-launching">Customized Launching</a></li>
|
||||||
<li><a href="#exercise-launch-with-command-line-help"
|
<li><a href="#exercise-launch-with-command-line-help"
|
||||||
id="toc-exercise-launch-with-command-line-help">Exercise: Launch with
|
id="toc-exercise-launch-with-command-line-help">Exercise: Launch with
|
||||||
Command-line Help</a></li>
|
Command-line Help</a></li>
|
||||||
<li><a href="#attaching" id="toc-attaching">Attaching</a></li>
|
<li><a href="#attaching" id="toc-attaching">Attaching</a>
|
||||||
<li><a href="#exercise-attach" id="toc-exercise-attach">Exercise:
|
<ul>
|
||||||
Attach</a></li>
|
|
||||||
<li><a href="#troubleshooting-1"
|
<li><a href="#troubleshooting-1"
|
||||||
id="toc-troubleshooting-1">Troubleshooting</a></li>
|
id="toc-troubleshooting-1">Troubleshooting</a></li>
|
||||||
</ul></li>
|
</ul></li>
|
||||||
|
<li><a href="#exercise-attach" id="toc-exercise-attach">Exercise:
|
||||||
|
Attach</a></li>
|
||||||
|
<li><a href="#troubleshooting-2"
|
||||||
|
id="toc-troubleshooting-2">Troubleshooting</a></li>
|
||||||
|
</ul></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
<section id="getting-started" class="level1">
|
<section id="getting-started" class="level1">
|
||||||
|
@ -453,13 +457,14 @@ target waits for input.</p>
|
||||||
<li>Run <code>termmines</code> in a terminal outside of Ghidra with the
|
<li>Run <code>termmines</code> in a terminal outside of Ghidra with the
|
||||||
desired command-line parameters.</li>
|
desired command-line parameters.</li>
|
||||||
<li>In the Ghidra Debugger, use the <strong>Launch</strong> button
|
<li>In the Ghidra Debugger, use the <strong>Launch</strong> button
|
||||||
drop-down and select <strong>Configured and Launch termmines using… →
|
drop-down and select <strong>Configure and Launch termmines using… →
|
||||||
raw gdb</strong>. The “raw” connector will give us a GDB session without
|
gdb</strong>.</li>
|
||||||
a target.</li>
|
<li>Clear the <strong>Image</strong> field to configure a GDB session
|
||||||
|
without a target.</li>
|
||||||
<li>Ghidra needs to know the location of gdb and the architecture of the
|
<li>Ghidra needs to know the location of gdb and the architecture of the
|
||||||
intended target. The defaults are correct for 64-bit x86 targets using
|
intended target. The defaults are correct for 64-bit x86 targets using
|
||||||
the system’s copy of GDB. Probably, you can just click
|
the system’s copy of GDB.</li>
|
||||||
<strong>Launch</strong>.</li>
|
<li>Click <strong>Launch</strong>.</li>
|
||||||
<li>In the <strong>Model</strong> window (to the left), expand the
|
<li>In the <strong>Model</strong> window (to the left), expand the
|
||||||
<em>Available</em> node.</li>
|
<em>Available</em> node.</li>
|
||||||
<li>In the filter box, type <code>termmines</code>.</li>
|
<li>In the filter box, type <code>termmines</code>.</li>
|
||||||
|
@ -467,6 +472,17 @@ the system’s copy of GDB. Probably, you can just click
|
||||||
you prefer, note the PID, e.g. 1234, then in the
|
you prefer, note the PID, e.g. 1234, then in the
|
||||||
<strong>Terminal</strong> type, e.g., <code>attach 1234</code>.</li>
|
<strong>Terminal</strong> type, e.g., <code>attach 1234</code>.</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
<p><strong>TIP</strong>: In later exercises, you may use the
|
||||||
|
<strong>Reset</strong> button to re-populate the default value for the
|
||||||
|
<strong>Image</strong> field. Be sure to change <strong>Run
|
||||||
|
Command</strong> back to “start”, though.</p>
|
||||||
|
<section id="troubleshooting-1" class="level3">
|
||||||
|
<h3>Troubleshooting</h3>
|
||||||
|
<p>If the <strong>Model</strong> window is blank, check for a “noname”
|
||||||
|
tab in the Dynamic Listing, and click it.</p>
|
||||||
|
<p>If the <strong>Model</strong> window seems incomplete after
|
||||||
|
attaching, check that its Filter box is cleared.</p>
|
||||||
|
</section>
|
||||||
</section>
|
</section>
|
||||||
<section id="exercise-attach" class="level2">
|
<section id="exercise-attach" class="level2">
|
||||||
<h2>Exercise: Attach</h2>
|
<h2>Exercise: Attach</h2>
|
||||||
|
@ -476,7 +492,7 @@ in <code>read</code> you have completed this exercise. Quit GDB from the
|
||||||
<strong>Terminal</strong> before proceeding to the next module: <a
|
<strong>Terminal</strong> before proceeding to the next module: <a
|
||||||
href="A2-UITour.html">A Tour of the UI</a></p>
|
href="A2-UITour.html">A Tour of the UI</a></p>
|
||||||
</section>
|
</section>
|
||||||
<section id="troubleshooting-1" class="level2">
|
<section id="troubleshooting-2" class="level2">
|
||||||
<h2>Troubleshooting</h2>
|
<h2>Troubleshooting</h2>
|
||||||
<p>If you get <code>Operation not permitted</code> or similar when
|
<p>If you get <code>Operation not permitted</code> or similar when
|
||||||
trying to attach, it is likely your Linux system is configured with
|
trying to attach, it is likely your Linux system is configured with
|
||||||
|
|
|
@ -219,15 +219,24 @@ when using Trace RMI.
|
||||||
Note this technique is only possible because the target waits for input.
|
Note this technique is only possible because the target waits for input.
|
||||||
|
|
||||||
1. Run `termmines` in a terminal outside of Ghidra with the desired command-line parameters.
|
1. Run `termmines` in a terminal outside of Ghidra with the desired command-line parameters.
|
||||||
1. In the Ghidra Debugger, use the **Launch** button drop-down and select **Configured and Launch termmines using... → raw gdb**.
|
1. In the Ghidra Debugger, use the **Launch** button drop-down and select **Configure and Launch termmines using... → gdb**.
|
||||||
The "raw" connector will give us a GDB session without a target.
|
1. Clear the **Image** field to configure a GDB session without a target.
|
||||||
1. Ghidra needs to know the location of gdb and the architecture of the intended target.
|
1. Ghidra needs to know the location of gdb and the architecture of the intended target.
|
||||||
The defaults are correct for 64-bit x86 targets using the system's copy of GDB.
|
The defaults are correct for 64-bit x86 targets using the system's copy of GDB.
|
||||||
Probably, you can just click **Launch**.
|
1. Click **Launch**.
|
||||||
1. In the **Model** window (to the left), expand the *Available* node.
|
1. In the **Model** window (to the left), expand the *Available* node.
|
||||||
1. In the filter box, type `termmines`.
|
1. In the filter box, type `termmines`.
|
||||||
1. Right click on the node and select **Attach**, or, if you prefer, note the PID, e.g. 1234, then in the **Terminal** type, e.g., `attach 1234`.
|
1. Right click on the node and select **Attach**, or, if you prefer, note the PID, e.g. 1234, then in the **Terminal** type, e.g., `attach 1234`.
|
||||||
|
|
||||||
|
**TIP**: In later exercises, you may use the **Reset** button to re-populate the default value for the **Image** field.
|
||||||
|
Be sure to change **Run Command** back to "start", though.
|
||||||
|
|
||||||
|
### Troubleshooting
|
||||||
|
|
||||||
|
If the **Model** window is blank, check for a "noname" tab in the Dynamic Listing, and click it.
|
||||||
|
|
||||||
|
If the **Model** window seems incomplete after attaching, check that its Filter box is cleared.
|
||||||
|
|
||||||
## Exercise: Attach
|
## Exercise: Attach
|
||||||
|
|
||||||
Try attaching on your own, if you have not already.
|
Try attaching on your own, if you have not already.
|
||||||
|
|
|
@ -312,7 +312,10 @@ forward a single instruction each time you press it. Also notice that
|
||||||
the Static Listing moves with the Dynamic Listing. You may navigate in
|
the Static Listing moves with the Dynamic Listing. You may navigate in
|
||||||
either listing, and so long as there is a corresponding location in the
|
either listing, and so long as there is a corresponding location in the
|
||||||
other, the two will stay synchronized. You may also open the Decompiler
|
other, the two will stay synchronized. You may also open the Decompiler
|
||||||
just as you would in the CodeBrowser, and it will stay in sync too.</p>
|
just as you would in the CodeBrowser, and it will stay in sync too.
|
||||||
|
<strong>TIP</strong>: If you get lost in memory, you can seek back to
|
||||||
|
the program counter by double-clicking “pc = …” in the top right of the
|
||||||
|
listing.</p>
|
||||||
<p>When you have clicked <img src="images/stepinto.png"
|
<p>When you have clicked <img src="images/stepinto.png"
|
||||||
alt="step into" /> <strong>Step Into</strong> a sufficient number of
|
alt="step into" /> <strong>Step Into</strong> a sufficient number of
|
||||||
times, you should end up in a subroutine. You can click <img
|
times, you should end up in a subroutine. You can click <img
|
||||||
|
|
|
@ -142,6 +142,7 @@ Notice that the Dynamic Listing moves forward a single instruction each time you
|
||||||
Also notice that the Static Listing moves with the Dynamic Listing.
|
Also notice that the Static Listing moves with the Dynamic Listing.
|
||||||
You may navigate in either listing, and so long as there is a corresponding location in the other, the two will stay synchronized.
|
You may navigate in either listing, and so long as there is a corresponding location in the other, the two will stay synchronized.
|
||||||
You may also open the Decompiler just as you would in the CodeBrowser, and it will stay in sync too.
|
You may also open the Decompiler just as you would in the CodeBrowser, and it will stay in sync too.
|
||||||
|
**TIP**: If you get lost in memory, you can seek back to the program counter by double-clicking "pc = ..." in the top right of the listing.
|
||||||
|
|
||||||
When you have clicked  **Step Into** a sufficient number of times, you should end up in a subroutine.
|
When you have clicked  **Step Into** a sufficient number of times, you should end up in a subroutine.
|
||||||
You can click  **Step Out** to leave the subroutine.
|
You can click  **Step Out** to leave the subroutine.
|
||||||
|
|
|
@ -273,7 +273,9 @@ toggle action, press <strong><code>K</code></strong> on the keyboard, or
|
||||||
double-click its icon in the margin.</li>
|
double-click its icon in the margin.</li>
|
||||||
<li>From the Model window, expand the <em>Breakpoints</em> node and
|
<li>From the Model window, expand the <em>Breakpoints</em> node and
|
||||||
double-click a breakpoint, or select one with the keyboard and press
|
double-click a breakpoint, or select one with the keyboard and press
|
||||||
<strong><code>ENTER</code></strong>.</li>
|
<strong><code>ENTER</code></strong>. For GDB, this must be done from the
|
||||||
|
top-level <em>Breakpoints</em> node, not the one subordinate to the
|
||||||
|
<em>inferior</em>.</li>
|
||||||
<li>From the Breakpoints window, single-click the breakpoint’s status
|
<li>From the Breakpoints window, single-click the breakpoint’s status
|
||||||
icon, right-click an entry and select a toggle action, or create a
|
icon, right-click an entry and select a toggle action, or create a
|
||||||
selection and use a toggling action from the local toolbar. Either panel
|
selection and use a toggling action from the local toolbar. Either panel
|
||||||
|
@ -340,7 +342,8 @@ synchronized after importing libc</figcaption>
|
||||||
<section id="troubleshooting" class="level4">
|
<section id="troubleshooting" class="level4">
|
||||||
<h4>Troubleshooting</h4>
|
<h4>Troubleshooting</h4>
|
||||||
<p>If it seems nothing has changed, except now you have a second program
|
<p>If it seems nothing has changed, except now you have a second program
|
||||||
database open, then the new module may not be successfully mapped.</p>
|
database open, then the new module may not be successfully mapped. Try
|
||||||
|
one or more of the following:</p>
|
||||||
<ol type="1">
|
<ol type="1">
|
||||||
<li>Re-check the Debug Console window and verify the note has been
|
<li>Re-check the Debug Console window and verify the note has been
|
||||||
removed.</li>
|
removed.</li>
|
||||||
|
@ -349,6 +352,9 @@ system, so the name of the module and the name of the program database
|
||||||
do not match.</li>
|
do not match.</li>
|
||||||
<li>Ensure that <code>libc</code> is the current program (tab) in the
|
<li>Ensure that <code>libc</code> is the current program (tab) in the
|
||||||
Static Listing.</li>
|
Static Listing.</li>
|
||||||
|
<li>Wait for auto-analysis of <code>libc</code> to complete. Yeah, it
|
||||||
|
may take a moment, but auto-mapping is queued as a background task, and
|
||||||
|
so it cannot map things until auto-analysis is done.</li>
|
||||||
<li>In the Modules window, right-click on <code>libc</code>, and select
|
<li>In the Modules window, right-click on <code>libc</code>, and select
|
||||||
<strong>Map Module to libc</strong>. (Names and titles will likely
|
<strong>Map Module to libc</strong>. (Names and titles will likely
|
||||||
differ.)</li>
|
differ.)</li>
|
||||||
|
@ -446,7 +452,7 @@ boards for any <code>termmines</code> session.</p>
|
||||||
<p>Write a program that takes a seed from the user and prints a diagram
|
<p>Write a program that takes a seed from the user and prints a diagram
|
||||||
of the first game board with the mines indicated. Optionally, have it
|
of the first game board with the mines indicated. Optionally, have it
|
||||||
print each subsequent game board when the user presses
|
print each subsequent game board when the user presses
|
||||||
<strong>ENTER</strong>. Check your work by re-launching
|
<strong><code>ENTER</code></strong>. Check your work by re-launching
|
||||||
<code>termmines</code>, capturing its seed, inputting it into your
|
<code>termmines</code>, capturing its seed, inputting it into your
|
||||||
program, and then winning the game. Optionally, win 2 more games in the
|
program, and then winning the game. Optionally, win 2 more games in the
|
||||||
same session.</p>
|
same session.</p>
|
||||||
|
|
|
@ -96,6 +96,7 @@ There are several ways to toggle a breakpoint:
|
||||||
|
|
||||||
1. In any listing, as in setting a breakpoint, right-click and select a toggle action, press **`K`** on the keyboard, or double-click its icon in the margin.
|
1. In any listing, as in setting a breakpoint, right-click and select a toggle action, press **`K`** on the keyboard, or double-click its icon in the margin.
|
||||||
1. From the Model window, expand the *Breakpoints* node and double-click a breakpoint, or select one with the keyboard and press **`ENTER`**.
|
1. From the Model window, expand the *Breakpoints* node and double-click a breakpoint, or select one with the keyboard and press **`ENTER`**.
|
||||||
|
For GDB, this must be done from the top-level *Breakpoints* node, not the one subordinate to the *inferior*.
|
||||||
1. From the Breakpoints window, single-click the breakpoint's status icon, right-click an entry and select a toggle action, or create a selection and use a toggling action from the local toolbar.
|
1. From the Breakpoints window, single-click the breakpoint's status icon, right-click an entry and select a toggle action, or create a selection and use a toggling action from the local toolbar.
|
||||||
Either panel works, but the top panel is preferred to keep the breakpoints consistent.
|
Either panel works, but the top panel is preferred to keep the breakpoints consistent.
|
||||||
The local toolbar also has actions for toggling all breakpoints in the session.
|
The local toolbar also has actions for toggling all breakpoints in the session.
|
||||||
|
@ -138,10 +139,13 @@ Once imported, the Breakpoints window should update to reflect the static addres
|
||||||
#### Troubleshooting
|
#### Troubleshooting
|
||||||
|
|
||||||
If it seems nothing has changed, except now you have a second program database open, then the new module may not be successfully mapped.
|
If it seems nothing has changed, except now you have a second program database open, then the new module may not be successfully mapped.
|
||||||
|
Try one or more of the following:
|
||||||
|
|
||||||
1. Re-check the Debug Console window and verify the note has been removed.
|
1. Re-check the Debug Console window and verify the note has been removed.
|
||||||
1. If not, it might be because the module is symlinked in the file system, so the name of the module and the name of the program database do not match.
|
1. If not, it might be because the module is symlinked in the file system, so the name of the module and the name of the program database do not match.
|
||||||
1. Ensure that `libc` is the current program (tab) in the Static Listing.
|
1. Ensure that `libc` is the current program (tab) in the Static Listing.
|
||||||
|
1. Wait for auto-analysis of `libc` to complete.
|
||||||
|
Yeah, it may take a moment, but auto-mapping is queued as a background task, and so it cannot map things until auto-analysis is done.
|
||||||
1. In the Modules window, right-click on `libc`, and select **Map Module to libc**. (Names and titles will likely differ.)
|
1. In the Modules window, right-click on `libc`, and select **Map Module to libc**. (Names and titles will likely differ.)
|
||||||
|
|
||||||
### Capturing the Random Seed
|
### Capturing the Random Seed
|
||||||
|
@ -214,6 +218,6 @@ Because, as we have now confirmed, `termmines` is importing its random number ge
|
||||||
Further, because we can capture the seed, and we know the placement algorithm, we can perfectly replicate the sequence of game boards for any `termmines` session.
|
Further, because we can capture the seed, and we know the placement algorithm, we can perfectly replicate the sequence of game boards for any `termmines` session.
|
||||||
|
|
||||||
Write a program that takes a seed from the user and prints a diagram of the first game board with the mines indicated.
|
Write a program that takes a seed from the user and prints a diagram of the first game board with the mines indicated.
|
||||||
Optionally, have it print each subsequent game board when the user presses **ENTER**.
|
Optionally, have it print each subsequent game board when the user presses **`ENTER`**.
|
||||||
Check your work by re-launching `termmines`, capturing its seed, inputting it into your program, and then winning the game.
|
Check your work by re-launching `termmines`, capturing its seed, inputting it into your program, and then winning the game.
|
||||||
Optionally, win 2 more games in the same session.
|
Optionally, win 2 more games in the same session.
|
||||||
|
|
|
@ -195,8 +195,8 @@ pointer there, just like you would in the Static Listing. You can now
|
||||||
navigate to that address by double-clicking it. To return to the stack
|
navigate to that address by double-clicking it. To return to the stack
|
||||||
pointer, you can use the back arrow in the global toolbar, you can click
|
pointer, you can use the back arrow in the global toolbar, you can click
|
||||||
the <img src="images/register-marker.png" alt="track location" /> Track
|
the <img src="images/register-marker.png" alt="track location" /> Track
|
||||||
Location button, or you can double-click the <code>sp = [Address]</code>
|
Location button, or you can double-click the “sp = …” label in the top
|
||||||
label in the top right of the Dynamic Listing.</p>
|
right of the Dynamic Listing.</p>
|
||||||
<p>To examine a more complicated stack segment, we will break at
|
<p>To examine a more complicated stack segment, we will break at
|
||||||
<code>rand</code>. Ensure your breakpoint at <code>rand</code> is
|
<code>rand</code>. Ensure your breakpoint at <code>rand</code> is
|
||||||
enabled and press <img src="images/resume.png" alt="resume" /> Resume.
|
enabled and press <img src="images/resume.png" alt="resume" /> Resume.
|
||||||
|
@ -450,7 +450,7 @@ address is into <code>main</code>, you could use
|
||||||
href="../../../Ghidra/Features/Decompiler/src/main/doc/sleigh.xml">Sleigh
|
href="../../../Ghidra/Features/Decompiler/src/main/doc/sleigh.xml">Sleigh
|
||||||
documentation</a>.</p>
|
documentation</a>.</p>
|
||||||
<p>Sleigh is a bit unconventional in that its operators are typed rather
|
<p>Sleigh is a bit unconventional in that its operators are typed rather
|
||||||
than its variables. All variables are fix-length bit vectors. Their
|
than its variables. All variables are fixed-length bit vectors. Their
|
||||||
sizes are specified in bytes, but they have no other type
|
sizes are specified in bytes, but they have no other type
|
||||||
information.</p>
|
information.</p>
|
||||||
<section id="variables-and-constants" class="level3">
|
<section id="variables-and-constants" class="level3">
|
||||||
|
|
|
@ -68,7 +68,7 @@ Since the target has just entered `main`, we should expect a return address at t
|
||||||
With your cursor at the stack pointer, press **`P`** to place a pointer there, just like
|
With your cursor at the stack pointer, press **`P`** to place a pointer there, just like
|
||||||
you would in the Static Listing.
|
you would in the Static Listing.
|
||||||
You can now navigate to that address by double-clicking it.
|
You can now navigate to that address by double-clicking it.
|
||||||
To return to the stack pointer, you can use the back arrow in the global toolbar, you can click the  Track Location button, or you can double-click the `sp = [Address]` label in the top right of the Dynamic Listing.
|
To return to the stack pointer, you can use the back arrow in the global toolbar, you can click the  Track Location button, or you can double-click the "sp = ..." label in the top right of the Dynamic Listing.
|
||||||
|
|
||||||
To examine a more complicated stack segment, we will break at `rand`.
|
To examine a more complicated stack segment, we will break at `rand`.
|
||||||
Ensure your breakpoint at `rand` is enabled and press  Resume.
|
Ensure your breakpoint at `rand` is enabled and press  Resume.
|
||||||
|
@ -244,7 +244,7 @@ For example, to see how far a return address is into `main`, you could use `*:8
|
||||||
For the complete specification, see the Semantic Section in the [Sleigh documentation](../../../Ghidra/Features/Decompiler/src/main/doc/sleigh.xml).
|
For the complete specification, see the Semantic Section in the [Sleigh documentation](../../../Ghidra/Features/Decompiler/src/main/doc/sleigh.xml).
|
||||||
|
|
||||||
Sleigh is a bit unconventional in that its operators are typed rather than its variables.
|
Sleigh is a bit unconventional in that its operators are typed rather than its variables.
|
||||||
All variables are fix-length bit vectors.
|
All variables are fixed-length bit vectors.
|
||||||
Their sizes are specified in bytes, but they have no other type information.
|
Their sizes are specified in bytes, but they have no other type information.
|
||||||
|
|
||||||
### Variables and Constants
|
### Variables and Constants
|
||||||
|
|
|
@ -676,8 +676,7 @@ Invalidate Emulator Cache</strong>.</li>
|
||||||
<strong>Resume</strong>.</li>
|
<strong>Resume</strong>.</li>
|
||||||
</ol>
|
</ol>
|
||||||
<p>Stubbing any remaining external calls is left as an exercise. You are
|
<p>Stubbing any remaining external calls is left as an exercise. You are
|
||||||
successful when the emulator crashes with
|
successful when the emulator crashes with “pc = 00000000”.</p>
|
||||||
<code>pc = 00000000</code>.</p>
|
|
||||||
<p>Clear or disable your breakpoint and invalidate the emulator cache
|
<p>Clear or disable your breakpoint and invalidate the emulator cache
|
||||||
again before proceeding to the next technique.</p>
|
again before proceeding to the next technique.</p>
|
||||||
</section>
|
</section>
|
||||||
|
@ -718,7 +717,7 @@ write the Sleigh code to mimic a <code>RET</code>. As with the
|
||||||
<code>CALL</code> override technique, you must now invalidate the
|
<code>CALL</code> override technique, you must now invalidate the
|
||||||
emulator cache and resume. Stubbing any remaining external functions is
|
emulator cache and resume. Stubbing any remaining external functions is
|
||||||
left as an exercise. You are successful when the emulator crashes with
|
left as an exercise. You are successful when the emulator crashes with
|
||||||
<code>pc = 00000000</code>.</p>
|
“pc = 00000000”.</p>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
<section id="wrapping-up" class="level3">
|
<section id="wrapping-up" class="level3">
|
||||||
|
|
|
@ -377,7 +377,7 @@ After you have written your Sleigh code:
|
||||||
1. Click  **Resume**.
|
1. Click  **Resume**.
|
||||||
|
|
||||||
Stubbing any remaining external calls is left as an exercise.
|
Stubbing any remaining external calls is left as an exercise.
|
||||||
You are successful when the emulator crashes with `pc = 00000000`.
|
You are successful when the emulator crashes with "pc = 00000000".
|
||||||
|
|
||||||
Clear or disable your breakpoint and invalidate the emulator cache again before proceeding to the next technique.
|
Clear or disable your breakpoint and invalidate the emulator cache again before proceeding to the next technique.
|
||||||
|
|
||||||
|
@ -412,7 +412,7 @@ return [RIP];
|
||||||
Notice that we cannot just write `RET`, but instead must write the Sleigh code to mimic a `RET`.
|
Notice that we cannot just write `RET`, but instead must write the Sleigh code to mimic a `RET`.
|
||||||
As with the `CALL` override technique, you must now invalidate the emulator cache and resume.
|
As with the `CALL` override technique, you must now invalidate the emulator cache and resume.
|
||||||
Stubbing any remaining external functions is left as an exercise.
|
Stubbing any remaining external functions is left as an exercise.
|
||||||
You are successful when the emulator crashes with `pc = 00000000`.
|
You are successful when the emulator crashes with "pc = 00000000".
|
||||||
|
|
||||||
### Wrapping Up
|
### Wrapping Up
|
||||||
|
|
||||||
|
|
|
@ -168,17 +168,14 @@ class="sourceCode numberSource java numberLines"><code class="sourceCode java"><
|
||||||
<span id="cb1-6"><a href="#cb1-6"></a> <span class="kw">protected</span> <span class="dt">void</span> <span class="fu">run</span><span class="op">()</span> <span class="kw">throws</span> <span class="bu">Exception</span> <span class="op">{</span></span>
|
<span id="cb1-6"><a href="#cb1-6"></a> <span class="kw">protected</span> <span class="dt">void</span> <span class="fu">run</span><span class="op">()</span> <span class="kw">throws</span> <span class="bu">Exception</span> <span class="op">{</span></span>
|
||||||
<span id="cb1-7"><a href="#cb1-7"></a> <span class="op">}</span></span>
|
<span id="cb1-7"><a href="#cb1-7"></a> <span class="op">}</span></span>
|
||||||
<span id="cb1-8"><a href="#cb1-8"></a><span class="op">}</span></span></code></pre></div>
|
<span id="cb1-8"><a href="#cb1-8"></a><span class="op">}</span></span></code></pre></div>
|
||||||
<p><strong>NOTE</strong>: The scripting API has been refactored a little
|
<p><strong>NOTE</strong>: The scripting API has been refactored since
|
||||||
since the transition from Recorder-based to TraceRmi-based targets.
|
the transition from Recorder-based to TraceRmi-based targets. Parts of
|
||||||
Parts of the API that are back-end agnostic are accessible from the
|
the API that are back-end agnostic are accessible from the
|
||||||
<code>FlatDebuggerAPI</code> interface. Parts of the API that require a
|
<code>FlatDebuggerAPI</code> interface. Parts of the API that require a
|
||||||
specific back end are in <code>FlatDebuggerRmiAPI</code> and
|
specific back end are in <code>FlatDebuggerRmiAPI</code>. The old
|
||||||
<code>FlatDebuggerRecorderAPI</code>, the latter of which is deprecated.
|
<code>FlatDebuggerRecorderAPI</code> was removed in Ghidra 11.3, and
|
||||||
If a script written for version 11.0.2 or prior is not compiling, it can
|
scripts needing it should be ported to
|
||||||
most likely be patched up by changing
|
<code>FlatDebuggerRmiAPI</code>.</p>
|
||||||
<code>implements FlatDebuggerAPI</code> to
|
|
||||||
<code>implements FlatDebuggerRecorderAPI</code>, but we recommend
|
|
||||||
porting it to use <code>implements FlatDebuggerRmiAPI</code>.</p>
|
|
||||||
<p>Technically, the Debugger’s “deep” API is accessible to scripts;
|
<p>Technically, the Debugger’s “deep” API is accessible to scripts;
|
||||||
however, the flat API is preferred for scripting. Also, the flat API is
|
however, the flat API is preferred for scripting. Also, the flat API is
|
||||||
usually more stable than the deep API. However, because the dynamic
|
usually more stable than the deep API. However, because the dynamic
|
||||||
|
|
|
@ -24,10 +24,10 @@ public class DemoDebuggerScript extends GhidraScript implements FlatDebuggerAPI
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**NOTE**: The scripting API has been refactored a little since the transition from Recorder-based to TraceRmi-based targets.
|
**NOTE**: The scripting API has been refactored since the transition from Recorder-based to TraceRmi-based targets.
|
||||||
Parts of the API that are back-end agnostic are accessible from the `FlatDebuggerAPI` interface.
|
Parts of the API that are back-end agnostic are accessible from the `FlatDebuggerAPI` interface.
|
||||||
Parts of the API that require a specific back end are in `FlatDebuggerRmiAPI` and `FlatDebuggerRecorderAPI`, the latter of which is deprecated.
|
Parts of the API that require a specific back end are in `FlatDebuggerRmiAPI`.
|
||||||
If a script written for version 11.0.2 or prior is not compiling, it can most likely be patched up by changing `implements FlatDebuggerAPI` to `implements FlatDebuggerRecorderAPI`, but we recommend porting it to use `implements FlatDebuggerRmiAPI`.
|
The old `FlatDebuggerRecorderAPI` was removed in Ghidra 11.3, and scripts needing it should be ported to `FlatDebuggerRmiAPI`.
|
||||||
|
|
||||||
Technically, the Debugger's "deep" API is accessible to scripts; however, the flat API is preferred for scripting.
|
Technically, the Debugger's "deep" API is accessible to scripts; however, the flat API is preferred for scripting.
|
||||||
Also, the flat API is usually more stable than the deep API.
|
Also, the flat API is usually more stable than the deep API.
|
||||||
|
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 23 KiB |