mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 01:39:21 +02:00
GP-5134: Don't require user to set 'Load Emulator'.
This commit is contained in:
parent
954ff4e124
commit
cfc4adbef6
14 changed files with 45 additions and 74 deletions
|
@ -273,10 +273,6 @@
|
|||
<LI><IMG alt="" src="icon.debugger.autoread" width="16"> Read Visible Memory, RO Once -
|
||||
(default) behaves like Read Visible Memory, except it will neglect read-only ranges that have
|
||||
been read previously.</LI>
|
||||
|
||||
<LI><IMG alt="" src="icon.debugger.emulate"> Load Emulator from Programs - populates the
|
||||
trace database using mapped program databases. This is often preferred during "pure
|
||||
emulation," so that the dynamic listing's contents match those of the static listing.</LI>
|
||||
</UL>
|
||||
</BODY>
|
||||
</HTML>
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -838,13 +838,11 @@ public interface DebuggerResources {
|
|||
|
||||
String NAME_VIS_RO_ONCE = "Read Visible Memory, RO Once";
|
||||
String NAME_VISIBLE = "Read Visible Memory";
|
||||
String NAME_LOAD_EMU = "Load Emulator from Programs";
|
||||
String NAME_NONE = "Do Not Read Memory";
|
||||
|
||||
// TODO: Separate icon for each
|
||||
Icon ICON_VIS_RO_ONCE = ICON_AUTOREAD;
|
||||
Icon ICON_VISIBLE = ICON_AUTOREAD;
|
||||
Icon ICON_LOAD_EMU = ICON_EMULATE;
|
||||
Icon ICON_NONE = ICON_DELETE;
|
||||
|
||||
static <T> MultiStateActionBuilder<T> builder(Plugin owner) {
|
||||
|
|
|
@ -25,12 +25,14 @@ import javax.swing.event.ChangeEvent;
|
|||
import javax.swing.event.ChangeListener;
|
||||
|
||||
import ghidra.app.plugin.core.debug.gui.control.TargetActionTask;
|
||||
import ghidra.app.plugin.core.debug.service.emulation.ProgramEmulationUtils;
|
||||
import ghidra.debug.api.action.InstanceUtils;
|
||||
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
||||
import ghidra.framework.options.SaveState;
|
||||
import ghidra.framework.plugintool.AutoConfigState.ConfigFieldCodec;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.util.classfinder.ClassSearcher;
|
||||
import ghidra.util.classfinder.ExtensionPoint;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
@ -89,6 +91,14 @@ public interface AutoReadMemorySpec extends ExtensionPoint {
|
|||
|
||||
Icon getMenuIcon();
|
||||
|
||||
default AutoReadMemorySpec getEffective(DebuggerCoordinates coordinates) {
|
||||
Trace trace = coordinates.getTrace();
|
||||
if (trace != null && ProgramEmulationUtils.isEmulatedProgram(trace)) {
|
||||
return LoadEmulatorAutoReadMemorySpec.INSTANCE;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the automatic read, if applicable
|
||||
*
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -228,7 +228,7 @@ public abstract class DebuggerReadsMemoryTrait {
|
|||
return;
|
||||
}
|
||||
AddressSet visible = new AddressSet(this.visible);
|
||||
autoSpec.readMemory(tool, current, visible).thenAccept(b -> {
|
||||
autoSpec.getEffective(current).readMemory(tool, current, visible).thenAccept(b -> {
|
||||
if (b) {
|
||||
memoryWasRead(visible);
|
||||
}
|
||||
|
@ -284,6 +284,10 @@ public abstract class DebuggerReadsMemoryTrait {
|
|||
|
||||
public void setAutoSpec(AutoReadMemorySpec autoSpec) {
|
||||
// TODO: What if action == null?
|
||||
if (autoSpec == null || autoSpec.getConfigName() == null) {
|
||||
throw new IllegalArgumentException("autoSpec " + autoSpec.getClass() +
|
||||
"not allowed in menu. Cannot be set explicitly.");
|
||||
}
|
||||
actionAutoRead.setCurrentActionStateByUserData(autoSpec);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -21,7 +21,6 @@ import java.util.concurrent.CompletableFuture;
|
|||
import javax.swing.Icon;
|
||||
|
||||
import db.Transaction;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AutoReadMemoryAction;
|
||||
import ghidra.app.plugin.core.debug.service.emulation.ProgramEmulationUtils;
|
||||
import ghidra.app.plugin.core.debug.service.model.record.RecorderUtils;
|
||||
import ghidra.app.plugin.core.debug.utils.AbstractMappedMemoryBytesVisitor;
|
||||
|
@ -35,27 +34,22 @@ import ghidra.trace.model.Trace;
|
|||
import ghidra.trace.model.memory.TraceMemoryManager;
|
||||
import ghidra.trace.model.memory.TraceMemoryState;
|
||||
|
||||
public class LoadEmulatorAutoReadMemorySpec implements AutoReadMemorySpec {
|
||||
public static final String CONFIG_NAME = "2_LOAD_EMULATOR";
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return this.getClass() == obj.getClass();
|
||||
}
|
||||
enum LoadEmulatorAutoReadMemorySpec implements AutoReadMemorySpec {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public String getConfigName() {
|
||||
return CONFIG_NAME;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMenuName() {
|
||||
return AutoReadMemoryAction.NAME_LOAD_EMU;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getMenuIcon() {
|
||||
return AutoReadMemoryAction.ICON_LOAD_EMU;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -47,6 +47,11 @@ public class NoneAutoReadMemorySpec implements AutoReadMemorySpec {
|
|||
return AutoReadMemoryAction.ICON_NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AutoReadMemorySpec getEffective(DebuggerCoordinates coordinates) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> readMemory(PluginTool tool, DebuggerCoordinates coordinates,
|
||||
AddressSetView visible) {
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -34,7 +34,6 @@ import generic.Unique;
|
|||
import ghidra.app.context.ListingActionContext;
|
||||
import ghidra.app.plugin.core.assembler.AssemblerPluginTestHelper;
|
||||
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerTest;
|
||||
import ghidra.app.plugin.core.debug.gui.action.LoadEmulatorAutoReadMemorySpec;
|
||||
import ghidra.app.plugin.core.debug.gui.listing.*;
|
||||
import ghidra.app.plugin.core.debug.service.control.DebuggerControlServicePlugin;
|
||||
import ghidra.app.plugin.core.debug.service.emulation.DebuggerEmulationServicePlugin;
|
||||
|
@ -155,10 +154,6 @@ public class DebuggerDisassemblyTest extends AbstractGhidraHeadedDebuggerTest {
|
|||
listingProvider.setAutoDisassemble(true);
|
||||
}
|
||||
|
||||
protected void enableLoadEmulator() throws Throwable {
|
||||
runSwing(() -> listingProvider.setAutoReadMemorySpec(new LoadEmulatorAutoReadMemorySpec()));
|
||||
}
|
||||
|
||||
protected DebuggerListingActionContext createActionContext(Address start, int len) {
|
||||
TraceProgramView view = tb.trace.getProgramView();
|
||||
ProgramSelection sel = new ProgramSelection(start, start.addWrap(len - 1));
|
||||
|
@ -369,7 +364,6 @@ public class DebuggerDisassemblyTest extends AbstractGhidraHeadedDebuggerTest {
|
|||
traceManager.openTrace(tb.trace);
|
||||
traceManager.activateThread(thread);
|
||||
|
||||
enableLoadEmulator();
|
||||
enableAutoDisassembly();
|
||||
|
||||
waitForPass(() -> {
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -40,7 +40,7 @@ import ghidra.app.decompiler.component.DecompilerPanel;
|
|||
import ghidra.app.nav.Navigatable;
|
||||
import ghidra.app.plugin.core.analysis.AutoAnalysisPlugin;
|
||||
import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
|
||||
import ghidra.app.plugin.core.debug.gui.action.*;
|
||||
import ghidra.app.plugin.core.debug.gui.action.SPLocationTrackingSpec;
|
||||
import ghidra.app.plugin.core.debug.gui.breakpoint.DebuggerBreakpointsProvider;
|
||||
import ghidra.app.plugin.core.debug.gui.console.DebuggerConsoleProvider;
|
||||
import ghidra.app.plugin.core.debug.gui.copying.DebuggerCopyActionsPlugin;
|
||||
|
@ -818,7 +818,7 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testEmulation_LazyStaleListing() throws Throwable {
|
||||
public void testEmulation_InitialListing() throws Throwable {
|
||||
emulateCommandLineParser();
|
||||
|
||||
runSwing(() -> tool.setSize(1920, 1080));
|
||||
|
@ -829,9 +829,6 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
|
|||
public void testEmulation_ListingAfterResume() throws Throwable {
|
||||
emulateCommandLineParser();
|
||||
|
||||
DebuggerListingProvider listing = getProvider(DebuggerListingProvider.class);
|
||||
listing.setAutoReadMemorySpec(
|
||||
AutoReadMemorySpec.fromConfigName(LoadEmulatorAutoReadMemorySpec.CONFIG_NAME));
|
||||
EmulationResult result = flatDbg.getEmulationService()
|
||||
.run(flatDbg.getCurrentPlatform(), flatDbg.getCurrentEmulationSchedule(), monitor,
|
||||
Scheduler.oneThread(flatDbg.getCurrentThread()));
|
||||
|
|
|
@ -369,29 +369,13 @@ actually loaded into an emulator, yet, because Ghidra allocates and
|
|||
caches emulators as needed. Instead, what you have is a single-snapshot
|
||||
trace without a live target. The initial state is snapshot 0, and
|
||||
emulation is started by navigating to a schedule, just like in
|
||||
extrapolation. You might be unnerved by the apparently empty and stale
|
||||
Dynamic listing:</p>
|
||||
extrapolation.</p>
|
||||
<figure>
|
||||
<img src="images/Emulation_LazyStaleListing.png"
|
||||
alt="Stale listing upon starting pure emulation" />
|
||||
<figcaption aria-hidden="true">Stale listing upon starting pure
|
||||
<img src="images/Emulation_InitialListing.png"
|
||||
alt="Listing upon starting pure emulation" />
|
||||
<figcaption aria-hidden="true">Listing upon starting pure
|
||||
emulation</figcaption>
|
||||
</figure>
|
||||
<p>This is perhaps more a matter of preference, but by default, Ghidra
|
||||
will only populate the Dynamic listing with state initialized by the
|
||||
emulator itself. When the emulator reads, it will “read through”
|
||||
uninitialized state by reading the mapped program image instead. This
|
||||
spares the loader from having to copy a potentially large program image
|
||||
into the emulator. In general, you should refer to the Static listing
|
||||
when following the program counter. If you see contents in the Dynamic
|
||||
listing following the program counter, then you are probably dealing
|
||||
with self-modifying code.</p>
|
||||
<p><strong>NOTE</strong>: If you prefer to see the Dynamic listing
|
||||
initialized with the program image, you may select <strong>Load Emulator
|
||||
from Program</strong> from the <strong>Auto-Read</strong> drop-down
|
||||
button in the Dynamic Listing. The loading is still done lazily as each
|
||||
page is viewed in the listing pane. You will want to change this back
|
||||
when debugging a live target!</p>
|
||||
<p>Because we can easily step back and forth as well as navigate to
|
||||
arbitrary points in time, emulation should feel relatively free of risk;
|
||||
however, the point about stubbing dependencies will become apparent. If
|
||||
|
|
|
@ -163,19 +163,8 @@ This will map the program into a new trace.
|
|||
Technically, it is not actually loaded into an emulator, yet, because Ghidra allocates and caches emulators as needed.
|
||||
Instead, what you have is a single-snapshot trace without a live target.
|
||||
The initial state is snapshot 0, and emulation is started by navigating to a schedule, just like in extrapolation.
|
||||
You might be unnerved by the apparently empty and stale Dynamic listing:
|
||||
|
||||

|
||||
|
||||
This is perhaps more a matter of preference, but by default, Ghidra will only populate the Dynamic listing with state initialized by the emulator itself.
|
||||
When the emulator reads, it will "read through" uninitialized state by reading the mapped program image instead.
|
||||
This spares the loader from having to copy a potentially large program image into the emulator.
|
||||
In general, you should refer to the Static listing when following the program counter.
|
||||
If you see contents in the Dynamic listing following the program counter, then you are probably dealing with self-modifying code.
|
||||
|
||||
**NOTE**: If you prefer to see the Dynamic listing initialized with the program image, you may select **Load Emulator from Program** from the **Auto-Read** drop-down button in the Dynamic Listing.
|
||||
The loading is still done lazily as each page is viewed in the listing pane.
|
||||
You will want to change this back when debugging a live target!
|
||||

|
||||
|
||||
Because we can easily step back and forth as well as navigate to arbitrary points in time, emulation should feel relatively free of risk; however, the point about stubbing dependencies will become apparent.
|
||||
If you feel the need to start over, there are two methods:
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
Binary file not shown.
Before Width: | Height: | Size: 26 KiB |
Binary file not shown.
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
|
@ -83,7 +83,7 @@ GhidraClass/Debugger/images/Breakpoints_MissingModuleNote.png||GHIDRA||||END|
|
|||
GhidraClass/Debugger/images/Breakpoints_PopAfterSRandRand.png||GHIDRA||||END|
|
||||
GhidraClass/Debugger/images/Breakpoints_SeedValueAfterBreakSRand.png||GHIDRA||||END|
|
||||
GhidraClass/Debugger/images/Breakpoints_SyncedAfterImportLibC.png||GHIDRA||||END|
|
||||
GhidraClass/Debugger/images/Emulation_LazyStaleListing.png||GHIDRA||||END|
|
||||
GhidraClass/Debugger/images/Emulation_InitialListing.png||GHIDRA||||END|
|
||||
GhidraClass/Debugger/images/Emulation_ListingAfterResume.png||GHIDRA||||END|
|
||||
GhidraClass/Debugger/images/Emulation_ListingForCmdlineSet.png||GHIDRA||||END|
|
||||
GhidraClass/Debugger/images/Emulation_PcodeStepper.png||GHIDRA||||END|
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue