mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
GP-1529: Interrupt emulator when decoding uninitialized memory
This commit is contained in:
parent
738e662e82
commit
4aa54dd1f9
25 changed files with 274 additions and 100 deletions
|
@ -18,6 +18,7 @@ package ghidra.app.plugin.core.debug.service.emulation;
|
|||
import java.util.Map;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
import generic.ULongSpan.ULongSpanSet;
|
||||
import ghidra.app.plugin.core.debug.service.emulation.data.PcodeDebuggerDataAccess;
|
||||
import ghidra.generic.util.datastruct.SemisparseByteArray;
|
||||
import ghidra.pcode.exec.AccessPcodeExecutionException;
|
||||
|
@ -52,28 +53,17 @@ public abstract class AbstractRWTargetPcodeExecutorStatePiece
|
|||
super(language, space, backing, bytes, written);
|
||||
}
|
||||
|
||||
protected abstract void fillUninitialized(AddressSet uninitialized);
|
||||
protected abstract ULongSpanSet readUninitializedFromTarget(ULongSpanSet uninitialized);
|
||||
|
||||
@Override
|
||||
public byte[] read(long offset, int size, Reason reason) {
|
||||
if (backing != null) {
|
||||
AddressSet uninitialized =
|
||||
addrSet(bytes.getUninitialized(offset, offset + size - 1));
|
||||
if (uninitialized.isEmpty()) {
|
||||
return super.read(offset, size, reason);
|
||||
}
|
||||
|
||||
fillUninitialized(uninitialized);
|
||||
|
||||
AddressSetView unknown = backing.intersectUnknown(
|
||||
addrSet(bytes.getUninitialized(offset, offset + size - 1)));
|
||||
if (!unknown.isEmpty() && reason == Reason.EXECUTE) {
|
||||
warnUnknown(unknown);
|
||||
}
|
||||
protected ULongSpanSet readUninitializedFromBacking(ULongSpanSet uninitialized) {
|
||||
uninitialized = readUninitializedFromTarget(uninitialized);
|
||||
if (uninitialized.isEmpty()) {
|
||||
return uninitialized;
|
||||
}
|
||||
|
||||
return super.readUninitializedFromBacking(uninitialized);
|
||||
// TODO: What to flush when bytes in the trace change?
|
||||
return super.read(offset, size, reason);
|
||||
}
|
||||
|
||||
protected <T> T waitTimeout(CompletableFuture<T> future) {
|
||||
|
|
|
@ -18,6 +18,8 @@ package ghidra.app.plugin.core.debug.service.emulation;
|
|||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import generic.ULongSpan;
|
||||
import generic.ULongSpan.ULongSpanSet;
|
||||
import ghidra.app.plugin.core.debug.service.emulation.data.PcodeDebuggerDataAccess;
|
||||
import ghidra.app.plugin.core.debug.service.emulation.data.PcodeDebuggerMemoryAccess;
|
||||
import ghidra.generic.util.datastruct.SemisparseByteArray;
|
||||
|
@ -81,27 +83,27 @@ public class RWTargetMemoryPcodeExecutorStatePiece
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void fillUninitialized(AddressSet uninitialized) {
|
||||
protected ULongSpanSet readUninitializedFromTarget(ULongSpanSet uninitialized) {
|
||||
if (space.isUniqueSpace()) {
|
||||
return;
|
||||
return uninitialized;
|
||||
}
|
||||
AddressSetView unknown;
|
||||
unknown = backing.intersectUnknown(uninitialized);
|
||||
AddressSet addrsUninit = addrSet(uninitialized);
|
||||
unknown = backing.intersectUnknown(addrsUninit);
|
||||
if (unknown.isEmpty()) {
|
||||
return;
|
||||
return uninitialized;
|
||||
}
|
||||
if (waitTimeout(backing.readFromTargetMemory(unknown))) {
|
||||
unknown = backing.intersectUnknown(uninitialized);
|
||||
if (backing.isLive() && waitTimeout(backing.readFromTargetMemory(unknown))) {
|
||||
unknown = backing.intersectUnknown(addrsUninit);
|
||||
if (unknown.isEmpty()) {
|
||||
return;
|
||||
return uninitialized;
|
||||
}
|
||||
}
|
||||
if (backing.readFromStaticImages(bytes, unknown)) {
|
||||
unknown = backing.intersectUnknown(uninitialized);
|
||||
if (unknown.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ULongSpan bound = uninitialized.bound();
|
||||
return bytes.getUninitialized(bound.min(), bound.max());
|
||||
}
|
||||
return uninitialized;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -18,6 +18,7 @@ package ghidra.app.plugin.core.debug.service.emulation;
|
|||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import generic.ULongSpan.ULongSpanSet;
|
||||
import ghidra.app.plugin.core.debug.service.emulation.data.PcodeDebuggerDataAccess;
|
||||
import ghidra.app.plugin.core.debug.service.emulation.data.PcodeDebuggerRegistersAccess;
|
||||
import ghidra.generic.util.datastruct.SemisparseByteArray;
|
||||
|
@ -78,15 +79,14 @@ public class RWTargetRegistersPcodeExecutorStatePiece
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void fillUninitialized(AddressSet uninitialized) {
|
||||
if (space.isUniqueSpace()) {
|
||||
return;
|
||||
protected ULongSpanSet readUninitializedFromTarget(ULongSpanSet uninitialized) {
|
||||
if (space.isUniqueSpace() || !backing.isLive()) {
|
||||
return uninitialized;
|
||||
}
|
||||
if (!backing.isLive()) {
|
||||
return;
|
||||
}
|
||||
AddressSetView unknown = backing.intersectUnknown(uninitialized);
|
||||
AddressSet addrsUninit = addrSet(uninitialized);
|
||||
AddressSetView unknown = backing.intersectUnknown(addrsUninit);
|
||||
waitTimeout(backing.readFromTargetRegisters(unknown));
|
||||
return uninitialized;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -353,7 +353,7 @@ public class UnwindAnalysis {
|
|||
public SymPcodeExecutorState executeToPc(Deque<BlockEdge> to) throws CancelledException {
|
||||
SymPcodeExecutorState state = new SymPcodeExecutorState(program);
|
||||
SymPcodeExecutor exec =
|
||||
SymPcodeExecutor.forProgram(program, state, Reason.EXECUTE, warnings, monitor);
|
||||
SymPcodeExecutor.forProgram(program, state, Reason.EXECUTE_READ, warnings, monitor);
|
||||
executePathTo(exec, to);
|
||||
executeBlockTo(exec, pcBlock.block, pc);
|
||||
return state;
|
||||
|
@ -375,7 +375,7 @@ public class UnwindAnalysis {
|
|||
public SymPcodeExecutorState executeFromPc(SymPcodeExecutorState state,
|
||||
Deque<BlockEdge> from) throws CancelledException {
|
||||
SymPcodeExecutor exec =
|
||||
SymPcodeExecutor.forProgram(program, state, Reason.EXECUTE, warnings, monitor);
|
||||
SymPcodeExecutor.forProgram(program, state, Reason.EXECUTE_READ, warnings, monitor);
|
||||
executeBlockFrom(exec, pcBlock.block, pc);
|
||||
executePathFrom(exec, from);
|
||||
return state;
|
||||
|
|
|
@ -39,6 +39,7 @@ import ghidra.app.plugin.core.debug.service.platform.DebuggerPlatformServicePlug
|
|||
import ghidra.app.services.DebuggerEmulationService.EmulationResult;
|
||||
import ghidra.app.services.DebuggerStaticMappingService;
|
||||
import ghidra.app.services.DebuggerTraceManagerService.ActivationCause;
|
||||
import ghidra.pcode.exec.DecodePcodeExecutionException;
|
||||
import ghidra.pcode.exec.InterruptPcodeExecutionException;
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.address.Address;
|
||||
|
@ -343,13 +344,53 @@ public class DebuggerEmulationServiceTest extends AbstractGhidraHeadedDebuggerGU
|
|||
.toString(16));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInterruptOnDecodeUninitialized() throws Exception {
|
||||
createProgram();
|
||||
intoProject(program);
|
||||
Assembler asm = Assemblers.getAssembler(program);
|
||||
Memory memory = program.getMemory();
|
||||
Address addrText = addr(program, 0x00400000);
|
||||
Register regPC = program.getRegister("pc");
|
||||
|
||||
try (Transaction tx = program.openTransaction("Initialize")) {
|
||||
MemoryBlock blockText = memory.createInitializedBlock(".text", addrText, 0x1000,
|
||||
(byte) 0, TaskMonitor.DUMMY, false);
|
||||
blockText.setExecute(true);
|
||||
asm.assemble(addrText,
|
||||
"br 0x003ffffe");
|
||||
}
|
||||
|
||||
programManager.openProgram(program);
|
||||
waitForSwing();
|
||||
codeBrowser.goTo(new ProgramLocation(program, addrText));
|
||||
waitForSwing();
|
||||
|
||||
performEnabledAction(codeBrowser.getProvider(), emulationPlugin.actionEmulateProgram, true);
|
||||
|
||||
Trace trace = traceManager.getCurrentTrace();
|
||||
assertNotNull(trace);
|
||||
|
||||
TraceThread thread = Unique.assertOne(trace.getThreadManager().getAllThreads());
|
||||
TraceMemorySpace regs = trace.getMemoryManager().getMemoryRegisterSpace(thread, false);
|
||||
|
||||
EmulationResult result = emulationPlugin.run(trace.getPlatformManager().getHostPlatform(),
|
||||
TraceSchedule.snap(0), TaskMonitor.DUMMY, Scheduler.oneThread(thread));
|
||||
|
||||
assertEquals(TraceSchedule.parse("0:t0-1"), result.schedule());
|
||||
assertTrue(result.error() instanceof DecodePcodeExecutionException);
|
||||
|
||||
long scratch = result.snapshot();
|
||||
assertEquals(new BigInteger("003ffffe", 16), regs.getViewValue(scratch, regPC).getUnsignedValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecutionBreakpoint() throws Exception {
|
||||
createProgram();
|
||||
intoProject(program);
|
||||
Assembler asm = Assemblers.getAssembler(program);
|
||||
Memory memory = program.getMemory();
|
||||
Address addrText = addr(program, 0x000400000);
|
||||
Address addrText = addr(program, 0x00400000);
|
||||
Register regPC = program.getRegister("pc");
|
||||
Register regR0 = program.getRegister("r0");
|
||||
Register regR1 = program.getRegister("r1");
|
||||
|
@ -411,7 +452,7 @@ public class DebuggerEmulationServiceTest extends AbstractGhidraHeadedDebuggerGU
|
|||
intoProject(program);
|
||||
Assembler asm = Assemblers.getAssembler(program);
|
||||
Memory memory = program.getMemory();
|
||||
Address addrText = addr(program, 0x000400000);
|
||||
Address addrText = addr(program, 0x00400000);
|
||||
Address addrI1;
|
||||
Address addrI2;
|
||||
try (Transaction tx = program.openTransaction("Initialize")) {
|
||||
|
@ -470,7 +511,7 @@ public class DebuggerEmulationServiceTest extends AbstractGhidraHeadedDebuggerGU
|
|||
intoProject(program);
|
||||
Assembler asm = Assemblers.getAssembler(program);
|
||||
Memory memory = program.getMemory();
|
||||
Address addrText = addr(program, 0x000400000);
|
||||
Address addrText = addr(program, 0x00400000);
|
||||
Register regPC = program.getRegister("pc");
|
||||
Register regR0 = program.getRegister("r0");
|
||||
Register regR1 = program.getRegister("r1");
|
||||
|
@ -537,7 +578,7 @@ public class DebuggerEmulationServiceTest extends AbstractGhidraHeadedDebuggerGU
|
|||
intoProject(program);
|
||||
Assembler asm = Assemblers.getAssembler(program);
|
||||
Memory memory = program.getMemory();
|
||||
Address addrText = addr(program, 0x000400000);
|
||||
Address addrText = addr(program, 0x00400000);
|
||||
Register regPC = program.getRegister("pc");
|
||||
Register regR0 = program.getRegister("r0");
|
||||
Register regR1 = program.getRegister("r1");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue