From 4f9c672e49d24fe7df4bccc49c88acf7f8e7ff89 Mon Sep 17 00:00:00 2001 From: Dan <46821332+nsadeveloper789@users.noreply.github.com> Date: Tue, 14 Nov 2023 11:12:10 -0500 Subject: [PATCH] GP-3904: Adjusted pure emulation to work with overlays. --- .../emulation/ProgramEmulationUtils.java | 52 ++++++++++++++----- .../DebuggerBreakpointsProviderTest.java | 2 +- 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/ProgramEmulationUtils.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/ProgramEmulationUtils.java index 146097f5f0..9f9c9f4e01 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/ProgramEmulationUtils.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/ProgramEmulationUtils.java @@ -53,8 +53,10 @@ import ghidra.util.exception.DuplicateNameException; * Most of these are already integrated via the {@link DebuggerEmulationService}. Please see if that * service satisfies your use case before employing these directly. */ -public enum ProgramEmulationUtils { - ; +public class ProgramEmulationUtils { + private ProgramEmulationUtils() { + } + public static final String BLOCK_NAME_STACK = "STACK"; /** @@ -122,21 +124,27 @@ public enum ProgramEmulationUtils { * Create regions for each block in a program, without relocation, and map the program in * *

- * This creates a region for each loaded, non-overlay block in the program. Permissions/flags - * are assigned accordingly. A single static mapping is generated to cover the entire range of - * created regions. Note that no bytes are copied in, as that could be prohibitive for large - * programs. Instead, the emulator should load them, based on the static mapping, as needed. + * This creates a region for each loaded, block in the program. Typically, only non-overlay + * blocks are included. To activate an overlay space, include it in the set of + * {@code activeOverlays}. This will alter the mapping from the trace to the static program such + * that the specified overlays are effective. The gaps between overlays are mapped to their + * physical (non-overlay) portions. Permissions/flags are assigned accordingly. Note that no + * bytes are copied in, as that could be prohibitive for large programs. Instead, the emulator + * should load them, based on the static mapping, as needed. * *

* A transaction must already be started on the destination trace. * * @param snapshot the destination snapshot, usually 0 * @param program the program to load + * @param activeOverlays which overlay spaces to use */ - public static void loadExecutable(TraceSnapshot snapshot, Program program) { + public static void loadExecutable(TraceSnapshot snapshot, Program program, + List activeOverlays) { Trace trace = snapshot.getTrace(); PathPattern patRegion = computePatternRegion(trace); Map extremaBySpace = new HashMap<>(); + Lifespan nowOn = Lifespan.nowOn(snapshot.getKey()); try { for (MemoryBlock block : program.getMemory().getBlocks()) { if (!DebuggerStaticMappingUtils.isReal(block)) { @@ -147,18 +155,35 @@ public enum ProgramEmulationUtils { .consider(range); String modName = getModuleName(program); - // TODO: Do I populate modules, since the mapping will already be done? + // NB. No need to populate as module. + // UI will sync from mapping, so it's obvious where the cursor is. String path = PathUtils.toString(patRegion .applyKeys(block.getStart() + "-" + modName + ":" + block.getName()) .getSingletonPath()); trace.getMemoryManager() .createRegion(path, snapshot.getKey(), range, getRegionFlags(block)); } + AddressSet identical = new AddressSet(); for (Extrema extrema : extremaBySpace.values()) { + identical.add(extrema.getMin(), extrema.getMax()); + } + for (MemoryBlock block : program.getMemory().getBlocks()) { + if (!block.isOverlay() || + !activeOverlays.contains(block.getStart().getAddressSpace())) { + continue; + } + Address phys = block.getStart().getPhysicalAddress(); DebuggerStaticMappingUtils.addMapping( - new DefaultTraceLocation(trace, null, Lifespan.nowOn(snapshot.getKey()), - extrema.getMin()), - new ProgramLocation(program, extrema.getMin()), extrema.getLength(), false); + new DefaultTraceLocation(trace, null, nowOn, phys), + new ProgramLocation(program, block.getStart()), + block.getSize(), false); + identical.delete(phys, block.getEnd().getPhysicalAddress()); + } + for (AddressRange range : identical) { + DebuggerStaticMappingUtils.addMapping( + new DefaultTraceLocation(trace, null, nowOn, range.getMinAddress()), + new ProgramLocation(program, range.getMinAddress()), + range.getLength(), false); } } catch (TraceOverlappedRegionException | DuplicateNameException @@ -407,7 +432,10 @@ public enum ProgramEmulationUtils { TraceSnapshot initial = trace.getTimeManager().createSnapshot(EMULATION_STARTED_AT + pc); long snap = initial.getKey(); - loadExecutable(initial, program); + List overlays = + pc.getAddressSpace().isOverlaySpace() ? List.of(pc.getAddressSpace()) + : List.of(); + loadExecutable(initial, program, overlays); doLaunchEmulationThread(trace, snap, program, pc, pc); } trace.clearUndo(); diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsProviderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsProviderTest.java index 89508ef53f..c3cab8cc7d 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsProviderTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsProviderTest.java @@ -703,7 +703,7 @@ public class DebuggerBreakpointsProviderTest extends AbstractGhidraHeadedDebugge createTrace(program.getLanguageID().getIdAsString()); try (Transaction startTransaction = tb.startTransaction()) { TraceSnapshot initial = tb.trace.getTimeManager().getSnapshot(0, true); - ProgramEmulationUtils.loadExecutable(initial, program); + ProgramEmulationUtils.loadExecutable(initial, program, List.of()); Address pc = program.getMinAddress(); ProgramEmulationUtils.doLaunchEmulationThread(tb.trace, 0, program, pc, pc); }