Merge remote-tracking branch 'origin/Ghidra_11.3'

This commit is contained in:
Ryan Kurtz 2025-01-16 06:00:06 -05:00
commit 466ba95857
25 changed files with 225 additions and 61 deletions

View file

@ -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() {

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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) {

View file

@ -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

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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;

View file

@ -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;

View file

@ -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;
}
} }

View file

@ -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);
}
} }

View file

@ -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")));
}
} }

View file

@ -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);

View file

@ -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 systems copy of GDB. Probably, you can just click the systems 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 systems 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

View file

@ -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... &rarr; raw gdb**. 1. In the Ghidra Debugger, use the **Launch** button drop-down and select **Configure and Launch termmines using... &rarr; 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.

View file

@ -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

View file

@ -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](images/stepinto.png) **Step Into** a sufficient number of times, you should end up in a subroutine. When you have clicked ![step into](images/stepinto.png) **Step Into** a sufficient number of times, you should end up in a subroutine.
You can click ![step out](images/stepout.png) **Step Out** to leave the subroutine. You can click ![step out](images/stepout.png) **Step Out** to leave the subroutine.

View file

@ -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 breakpoints status <li>From the Breakpoints window, single-click the breakpoints 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>

View file

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

View file

@ -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">

View file

@ -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](images/register-marker.png) 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](images/register-marker.png) 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](images/resume.png) Resume. Ensure your breakpoint at `rand` is enabled and press ![resume](images/resume.png) 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

View file

@ -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">

View file

@ -377,7 +377,7 @@ After you have written your Sleigh code:
1. Click ![resume button](images/resume.png) **Resume**. 1. Click ![resume button](images/resume.png) **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

View file

@ -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 Debuggers “deep” API is accessible to scripts; <p>Technically, the Debuggers “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

View file

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Before After
Before After