diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html index ceaad51b76..a5509bfc6f 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html @@ -273,10 +273,6 @@
  • Read Visible Memory, RO Once - (default) behaves like Read Visible Memory, except it will neglect read-only ranges that have been read previously.
  • - -
  • 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.
  • diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerResources.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerResources.java index 20fecad781..22c1cb4648 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerResources.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerResources.java @@ -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 MultiStateActionBuilder builder(Plugin owner) { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/AutoReadMemorySpec.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/AutoReadMemorySpec.java index e56606fb5f..5eeba15463 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/AutoReadMemorySpec.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/AutoReadMemorySpec.java @@ -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 * diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerReadsMemoryTrait.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerReadsMemoryTrait.java index 004c4cc108..b7a683ca33 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerReadsMemoryTrait.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerReadsMemoryTrait.java @@ -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); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/LoadEmulatorAutoReadMemorySpec.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/LoadEmulatorAutoReadMemorySpec.java index e230e09747..23bf5ed247 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/LoadEmulatorAutoReadMemorySpec.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/LoadEmulatorAutoReadMemorySpec.java @@ -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 diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/NoneAutoReadMemorySpec.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/NoneAutoReadMemorySpec.java index 3a20cee074..b03e11ebfb 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/NoneAutoReadMemorySpec.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/NoneAutoReadMemorySpec.java @@ -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 readMemory(PluginTool tool, DebuggerCoordinates coordinates, AddressSetView visible) { diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/disassemble/DebuggerDisassemblyTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/disassemble/DebuggerDisassemblyTest.java index 86c149b2f5..2e427ee300 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/disassemble/DebuggerDisassemblyTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/disassemble/DebuggerDisassemblyTest.java @@ -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(() -> { diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/screen/java/ghidraclass/debugger/screenshot/TutorialDebuggerScreenShots.java b/Ghidra/Test/DebuggerIntegrationTest/src/screen/java/ghidraclass/debugger/screenshot/TutorialDebuggerScreenShots.java index fe8982df4d..e58e8c9e3a 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/screen/java/ghidraclass/debugger/screenshot/TutorialDebuggerScreenShots.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/screen/java/ghidraclass/debugger/screenshot/TutorialDebuggerScreenShots.java @@ -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())); diff --git a/GhidraDocs/GhidraClass/Debugger/B2-Emulation.html b/GhidraDocs/GhidraClass/Debugger/B2-Emulation.html index 746c4537c3..10d18388af 100644 --- a/GhidraDocs/GhidraClass/Debugger/B2-Emulation.html +++ b/GhidraDocs/GhidraClass/Debugger/B2-Emulation.html @@ -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:

    +extrapolation.

    - -
    -

    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 diff --git a/GhidraDocs/GhidraClass/Debugger/B2-Emulation.md b/GhidraDocs/GhidraClass/Debugger/B2-Emulation.md index 64176a78ec..d6f7bc924c 100644 --- a/GhidraDocs/GhidraClass/Debugger/B2-Emulation.md +++ b/GhidraDocs/GhidraClass/Debugger/B2-Emulation.md @@ -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: -![Stale listing upon starting pure emulation](images/Emulation_LazyStaleListing.png) - -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! +![Listing upon starting pure emulation](images/Emulation_InitialListing.png) 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: diff --git a/GhidraDocs/GhidraClass/Debugger/images/Emulation_InitialListing.png b/GhidraDocs/GhidraClass/Debugger/images/Emulation_InitialListing.png new file mode 100644 index 0000000000..6a639d7179 Binary files /dev/null and b/GhidraDocs/GhidraClass/Debugger/images/Emulation_InitialListing.png differ diff --git a/GhidraDocs/GhidraClass/Debugger/images/Emulation_LazyStaleListing.png b/GhidraDocs/GhidraClass/Debugger/images/Emulation_LazyStaleListing.png deleted file mode 100644 index d5e243aa40..0000000000 Binary files a/GhidraDocs/GhidraClass/Debugger/images/Emulation_LazyStaleListing.png and /dev/null differ diff --git a/GhidraDocs/GhidraClass/Debugger/images/Emulation_ListingAfterResume.png b/GhidraDocs/GhidraClass/Debugger/images/Emulation_ListingAfterResume.png index 210336a2fe..94d901867b 100644 Binary files a/GhidraDocs/GhidraClass/Debugger/images/Emulation_ListingAfterResume.png and b/GhidraDocs/GhidraClass/Debugger/images/Emulation_ListingAfterResume.png differ diff --git a/GhidraDocs/certification.manifest b/GhidraDocs/certification.manifest index 07cb838275..85826860c5 100644 --- a/GhidraDocs/certification.manifest +++ b/GhidraDocs/certification.manifest @@ -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|