GP-3904: Adjusted pure emulation to work with overlays.

This commit is contained in:
Dan 2023-11-14 11:12:10 -05:00
parent 0fb2014df1
commit 4f9c672e49
2 changed files with 41 additions and 13 deletions

View File

@ -53,8 +53,10 @@ import ghidra.util.exception.DuplicateNameException;
* Most of these are already integrated via the {@link DebuggerEmulationService}. Please see if that * Most of these are already integrated via the {@link DebuggerEmulationService}. Please see if that
* service satisfies your use case before employing these directly. * 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"; 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 * Create regions for each block in a program, without relocation, and map the program in
* *
* <p> * <p>
* This creates a region for each loaded, non-overlay block in the program. Permissions/flags * This creates a region for each loaded, block in the program. Typically, only non-overlay
* are assigned accordingly. A single static mapping is generated to cover the entire range of * blocks are included. To activate an overlay space, include it in the set of
* created regions. Note that no bytes are copied in, as that could be prohibitive for large * {@code activeOverlays}. This will alter the mapping from the trace to the static program such
* programs. Instead, the emulator should load them, based on the static mapping, as needed. * 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.
* *
* <p> * <p>
* A transaction must already be started on the destination trace. * A transaction must already be started on the destination trace.
* *
* @param snapshot the destination snapshot, usually 0 * @param snapshot the destination snapshot, usually 0
* @param program the program to load * @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<AddressSpace> activeOverlays) {
Trace trace = snapshot.getTrace(); Trace trace = snapshot.getTrace();
PathPattern patRegion = computePatternRegion(trace); PathPattern patRegion = computePatternRegion(trace);
Map<AddressSpace, Extrema> extremaBySpace = new HashMap<>(); Map<AddressSpace, Extrema> extremaBySpace = new HashMap<>();
Lifespan nowOn = Lifespan.nowOn(snapshot.getKey());
try { try {
for (MemoryBlock block : program.getMemory().getBlocks()) { for (MemoryBlock block : program.getMemory().getBlocks()) {
if (!DebuggerStaticMappingUtils.isReal(block)) { if (!DebuggerStaticMappingUtils.isReal(block)) {
@ -147,18 +155,35 @@ public enum ProgramEmulationUtils {
.consider(range); .consider(range);
String modName = getModuleName(program); 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 String path = PathUtils.toString(patRegion
.applyKeys(block.getStart() + "-" + modName + ":" + block.getName()) .applyKeys(block.getStart() + "-" + modName + ":" + block.getName())
.getSingletonPath()); .getSingletonPath());
trace.getMemoryManager() trace.getMemoryManager()
.createRegion(path, snapshot.getKey(), range, getRegionFlags(block)); .createRegion(path, snapshot.getKey(), range, getRegionFlags(block));
} }
AddressSet identical = new AddressSet();
for (Extrema extrema : extremaBySpace.values()) { 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( DebuggerStaticMappingUtils.addMapping(
new DefaultTraceLocation(trace, null, Lifespan.nowOn(snapshot.getKey()), new DefaultTraceLocation(trace, null, nowOn, phys),
extrema.getMin()), new ProgramLocation(program, block.getStart()),
new ProgramLocation(program, extrema.getMin()), extrema.getLength(), false); 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 catch (TraceOverlappedRegionException | DuplicateNameException
@ -407,7 +432,10 @@ public enum ProgramEmulationUtils {
TraceSnapshot initial = TraceSnapshot initial =
trace.getTimeManager().createSnapshot(EMULATION_STARTED_AT + pc); trace.getTimeManager().createSnapshot(EMULATION_STARTED_AT + pc);
long snap = initial.getKey(); long snap = initial.getKey();
loadExecutable(initial, program); List<AddressSpace> overlays =
pc.getAddressSpace().isOverlaySpace() ? List.of(pc.getAddressSpace())
: List.of();
loadExecutable(initial, program, overlays);
doLaunchEmulationThread(trace, snap, program, pc, pc); doLaunchEmulationThread(trace, snap, program, pc, pc);
} }
trace.clearUndo(); trace.clearUndo();

View File

@ -703,7 +703,7 @@ public class DebuggerBreakpointsProviderTest extends AbstractGhidraHeadedDebugge
createTrace(program.getLanguageID().getIdAsString()); createTrace(program.getLanguageID().getIdAsString());
try (Transaction startTransaction = tb.startTransaction()) { try (Transaction startTransaction = tb.startTransaction()) {
TraceSnapshot initial = tb.trace.getTimeManager().getSnapshot(0, true); TraceSnapshot initial = tb.trace.getTimeManager().getSnapshot(0, true);
ProgramEmulationUtils.loadExecutable(initial, program); ProgramEmulationUtils.loadExecutable(initial, program, List.of());
Address pc = program.getMinAddress(); Address pc = program.getMinAddress();
ProgramEmulationUtils.doLaunchEmulationThread(tb.trace, 0, program, pc, pc); ProgramEmulationUtils.doLaunchEmulationThread(tb.trace, 0, program, pc, pc);
} }