mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
GP-2467: Change SleighProgramCompiler to use String (text block) instead of List<String>
This commit is contained in:
parent
6a2cd80550
commit
9d6f278f39
48 changed files with 730 additions and 613 deletions
|
@ -24,7 +24,6 @@
|
||||||
//@toolbar
|
//@toolbar
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import ghidra.app.plugin.assembler.Assembler;
|
import ghidra.app.plugin.assembler.Assembler;
|
||||||
import ghidra.app.plugin.assembler.Assemblers;
|
import ghidra.app.plugin.assembler.Assemblers;
|
||||||
|
@ -149,9 +148,10 @@ public class DebuggerEmuExampleScript extends GhidraScript {
|
||||||
* Inject a call to our custom print userop. Otherwise, the language itself will never
|
* Inject a call to our custom print userop. Otherwise, the language itself will never
|
||||||
* invoke it.
|
* invoke it.
|
||||||
*/
|
*/
|
||||||
emulator.inject(injectHere, List.of(
|
emulator.inject(injectHere, """
|
||||||
"print_utf8(RCX);",
|
print_utf8(RCX);
|
||||||
"emu_exec_decoded();"));
|
emu_exec_decoded();
|
||||||
|
""");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Run the experiment: This should interrupt on the second SYSCALL, because any value other
|
* Run the experiment: This should interrupt on the second SYSCALL, because any value other
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
//@toolbar
|
//@toolbar
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import ghidra.app.plugin.assembler.*;
|
import ghidra.app.plugin.assembler.*;
|
||||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||||
|
@ -102,10 +101,10 @@ public class StandAloneEmuExampleScript extends GhidraScript {
|
||||||
*/
|
*/
|
||||||
byte[] hw = "Hello, World!\n".getBytes(UTF8);
|
byte[] hw = "Hello, World!\n".getBytes(UTF8);
|
||||||
emulator.getSharedState().setVar(dyn, 0xdeadbeefL, hw.length, true, hw);
|
emulator.getSharedState().setVar(dyn, 0xdeadbeefL, hw.length, true, hw);
|
||||||
PcodeProgram init = SleighProgramCompiler.compileProgram(language, "init", List.of(
|
PcodeProgram init = SleighProgramCompiler.compileProgram(language, "init", String.format("""
|
||||||
"RIP = 0x" + entry + ";",
|
RIP = 0x%s;
|
||||||
"RSP = 0x00001000;"),
|
RSP = 0x00001000;
|
||||||
library);
|
""", entry), library);
|
||||||
thread.getExecutor().execute(init, library);
|
thread.getExecutor().execute(init, library);
|
||||||
thread.overrideContextWithDefault();
|
thread.overrideContextWithDefault();
|
||||||
thread.reInitialize();
|
thread.reInitialize();
|
||||||
|
@ -114,9 +113,10 @@ public class StandAloneEmuExampleScript extends GhidraScript {
|
||||||
* Inject a call to our custom print userop. Otherwise, the language itself will never
|
* Inject a call to our custom print userop. Otherwise, the language itself will never
|
||||||
* invoke it.
|
* invoke it.
|
||||||
*/
|
*/
|
||||||
emulator.inject(injectHere, List.of(
|
emulator.inject(injectHere, """
|
||||||
"print_utf8(RCX);",
|
print_utf8(RCX);
|
||||||
"emu_exec_decoded();"));
|
emu_exec_decoded();
|
||||||
|
""");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Run the experiment: This should interrupt on the second SYSCALL, because any value other
|
* Run the experiment: This should interrupt on the second SYSCALL, because any value other
|
||||||
|
|
|
@ -103,9 +103,7 @@ public class StandAloneStructuredSleighScript extends GhidraScript {
|
||||||
print(userop.getName() + "(");
|
print(userop.getName() + "(");
|
||||||
print(userop.getInputs().stream().collect(Collectors.joining(",")));
|
print(userop.getInputs().stream().collect(Collectors.joining(",")));
|
||||||
print(") {\n");
|
print(") {\n");
|
||||||
for (String line : userop.getLines()) {
|
print(userop.getBody());
|
||||||
print(line);
|
|
||||||
}
|
|
||||||
print("}\n\n");
|
print("}\n\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
//@toolbar
|
//@toolbar
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import ghidra.app.plugin.assembler.Assembler;
|
import ghidra.app.plugin.assembler.Assembler;
|
||||||
import ghidra.app.plugin.assembler.Assemblers;
|
import ghidra.app.plugin.assembler.Assemblers;
|
||||||
|
@ -184,10 +183,11 @@ public class StandAloneSyscallEmuExampleScript extends GhidraScript {
|
||||||
/*
|
/*
|
||||||
* Initialize the thread
|
* Initialize the thread
|
||||||
*/
|
*/
|
||||||
PcodeProgram init = SleighProgramCompiler.compileProgram(language, "init", List.of(
|
PcodeProgram init =
|
||||||
"RIP = 0x" + entry + ";",
|
SleighProgramCompiler.compileProgram(language, "init", String.format("""
|
||||||
"RSP = 0x00001000;"),
|
RIP = 0x%s;
|
||||||
library);
|
RSP = 0x00001000;
|
||||||
|
""", entry), library);
|
||||||
thread.getExecutor().execute(init, library);
|
thread.getExecutor().execute(init, library);
|
||||||
thread.overrideContextWithDefault();
|
thread.overrideContextWithDefault();
|
||||||
thread.reInitialize();
|
thread.reInitialize();
|
||||||
|
|
|
@ -69,8 +69,10 @@ public class DebuggerPcodeStepperPluginScreenShots extends GhidraScreenShotGener
|
||||||
|
|
||||||
PcodeExecutor<byte[]> exe =
|
PcodeExecutor<byte[]> exe =
|
||||||
TraceSleighUtils.buildByteExecutor(tb.trace, snap0, thread, 0);
|
TraceSleighUtils.buildByteExecutor(tb.trace, snap0, thread, 0);
|
||||||
exe.executeSleighLine("RIP = 0x00400000");
|
exe.executeSleigh("""
|
||||||
exe.executeSleighLine("RSP = 0x0010fff8");
|
RIP = 0x00400000;
|
||||||
|
RSP = 0x0010fff8;
|
||||||
|
""");
|
||||||
|
|
||||||
Assembler asm = Assemblers.getAssembler(tb.trace.getFixedProgramView(snap0));
|
Assembler asm = Assemblers.getAssembler(tb.trace.getFixedProgramView(snap0));
|
||||||
asm.assemble(tb.addr(0x00400000), "SUB RSP,0x40");
|
asm.assemble(tb.addr(0x00400000), "SUB RSP,0x40");
|
||||||
|
|
|
@ -69,14 +69,18 @@ public class DebuggerWatchesPluginScreenShots extends GhidraScreenShotGenerator
|
||||||
|
|
||||||
PcodeExecutor<byte[]> executor0 =
|
PcodeExecutor<byte[]> executor0 =
|
||||||
TraceSleighUtils.buildByteExecutor(tb.trace, snap0, thread, 0);
|
TraceSleighUtils.buildByteExecutor(tb.trace, snap0, thread, 0);
|
||||||
executor0.executeSleighLine("RSP = 0x7ffefff8");
|
executor0.executeSleigh("""
|
||||||
executor0.executeSleighLine("*:4 (RSP+8) = 0x4030201");
|
RSP = 0x7ffefff8;
|
||||||
|
*:4 (RSP+8) = 0x4030201;
|
||||||
|
""");
|
||||||
|
|
||||||
PcodeExecutor<byte[]> executor1 =
|
PcodeExecutor<byte[]> executor1 =
|
||||||
TraceSleighUtils.buildByteExecutor(tb.trace, snap1, thread, 0);
|
TraceSleighUtils.buildByteExecutor(tb.trace, snap1, thread, 0);
|
||||||
executor1.executeSleighLine("RSP = 0x7ffefff8");
|
executor1.executeSleigh("""
|
||||||
executor1.executeSleighLine("*:4 (RSP+8) = 0x1020304");
|
RSP = 0x7ffefff8;
|
||||||
executor1.executeSleighLine("*:4 0x7fff0004:8 = 0x4A9A70C8");
|
*:4 (RSP+8) = 0x1020304;
|
||||||
|
*:4 0x7fff0004:8 = 0x4A9A70C8;
|
||||||
|
""");
|
||||||
}
|
}
|
||||||
|
|
||||||
watchesProvider.addWatch("RSP");
|
watchesProvider.addWatch("RSP");
|
||||||
|
|
|
@ -134,11 +134,12 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected TraceRecorder addMappedBreakpointOpenAndWait() throws Exception {
|
protected TraceRecorder addMappedBreakpointOpenAndWait() throws Throwable {
|
||||||
createTestModel();
|
createTestModel();
|
||||||
mb.createTestProcessesAndThreads();
|
mb.createTestProcessesAndThreads();
|
||||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||||
createTargetTraceMapper(mb.testProcess1), ActionSource.AUTOMATIC);
|
createTargetTraceMapper(mb.testProcess1), ActionSource.AUTOMATIC);
|
||||||
|
waitRecorder(recorder);
|
||||||
Trace trace = recorder.getTrace();
|
Trace trace = recorder.getTrace();
|
||||||
createProgramFromTrace(trace);
|
createProgramFromTrace(trace);
|
||||||
intoProject(trace);
|
intoProject(trace);
|
||||||
|
@ -260,7 +261,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
||||||
Set.of("SW_EXECUTE", "HW_EXECUTE", "READ,WRITE", "READ", "WRITE");
|
Set.of("SW_EXECUTE", "HW_EXECUTE", "READ,WRITE", "READ", "WRITE");
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProgramNoBreakPopupMenus() throws Exception {
|
public void testProgramNoBreakPopupMenus() throws Throwable {
|
||||||
// NOTE: Need a target to have any breakpoint actions, even on programs
|
// NOTE: Need a target to have any breakpoint actions, even on programs
|
||||||
addMappedBreakpointOpenAndWait();
|
addMappedBreakpointOpenAndWait();
|
||||||
|
|
||||||
|
@ -276,7 +277,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTraceNoBreakPopupMenus() throws Exception {
|
public void testTraceNoBreakPopupMenus() throws Throwable {
|
||||||
TraceRecorder recorder = addMappedBreakpointOpenAndWait();
|
TraceRecorder recorder = addMappedBreakpointOpenAndWait();
|
||||||
Trace trace = recorder.getTrace();
|
Trace trace = recorder.getTrace();
|
||||||
traceManager.activateTrace(trace);
|
traceManager.activateTrace(trace);
|
||||||
|
@ -414,7 +415,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testActionToggleBreakpointProgramWithNoCurrentBreakpointOnInstruction()
|
public void testActionToggleBreakpointProgramWithNoCurrentBreakpointOnInstruction()
|
||||||
throws Exception {
|
throws Throwable {
|
||||||
addMappedBreakpointOpenAndWait(); // wasteful, but whatever
|
addMappedBreakpointOpenAndWait(); // wasteful, but whatever
|
||||||
for (LogicalBreakpoint lb : List.copyOf(breakpointService.getAllBreakpoints())) {
|
for (LogicalBreakpoint lb : List.copyOf(breakpointService.getAllBreakpoints())) {
|
||||||
lb.delete();
|
lb.delete();
|
||||||
|
@ -442,7 +443,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testActionToggleBreakpointProgramWithNoCurrentBreakpointOnData() throws Exception {
|
public void testActionToggleBreakpointProgramWithNoCurrentBreakpointOnData() throws Throwable {
|
||||||
addMappedBreakpointOpenAndWait(); // wasteful, but whatever
|
addMappedBreakpointOpenAndWait(); // wasteful, but whatever
|
||||||
for (LogicalBreakpoint lb : List.copyOf(breakpointService.getAllBreakpoints())) {
|
for (LogicalBreakpoint lb : List.copyOf(breakpointService.getAllBreakpoints())) {
|
||||||
lb.delete();
|
lb.delete();
|
||||||
|
@ -470,7 +471,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testActionToggleBreakpointProgram() throws Exception {
|
public void testActionToggleBreakpointProgram() throws Throwable {
|
||||||
addMappedBreakpointOpenAndWait();
|
addMappedBreakpointOpenAndWait();
|
||||||
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
|
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
|
||||||
|
|
||||||
|
@ -486,7 +487,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testActionToggleBreakpointTrace() throws Exception {
|
public void testActionToggleBreakpointTrace() throws Throwable {
|
||||||
TraceRecorder recorder = addMappedBreakpointOpenAndWait();
|
TraceRecorder recorder = addMappedBreakpointOpenAndWait();
|
||||||
Trace trace = recorder.getTrace();
|
Trace trace = recorder.getTrace();
|
||||||
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
|
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
|
||||||
|
@ -527,14 +528,16 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void testActionSetBreakpointProgram(DockingAction action,
|
protected void testActionSetBreakpointProgram(DockingAction action,
|
||||||
Set<TraceBreakpointKind> expectedKinds) throws Exception {
|
Set<TraceBreakpointKind> expectedKinds) throws Throwable {
|
||||||
addMappedBreakpointOpenAndWait(); // Adds an unneeded breakpoint. Aw well.
|
addMappedBreakpointOpenAndWait(); // Adds an unneeded breakpoint. Aw well.
|
||||||
|
|
||||||
performAction(action, staticCtx(addr(program, 0x0400321)), false);
|
performAction(action, staticCtx(addr(program, 0x0400321)), false);
|
||||||
DebuggerPlaceBreakpointDialog dialog =
|
DebuggerPlaceBreakpointDialog dialog =
|
||||||
waitForDialogComponent(DebuggerPlaceBreakpointDialog.class);
|
waitForDialogComponent(DebuggerPlaceBreakpointDialog.class);
|
||||||
dialog.setName("Test name");
|
runSwing(() -> {
|
||||||
runSwing(() -> dialog.okCallback());
|
dialog.setName("Test name");
|
||||||
|
dialog.okCallback();
|
||||||
|
});
|
||||||
|
|
||||||
waitForPass(() -> {
|
waitForPass(() -> {
|
||||||
LogicalBreakpoint lb = Unique.assertOne(
|
LogicalBreakpoint lb = Unique.assertOne(
|
||||||
|
@ -546,7 +549,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void testActionSetBreakpointTrace(DockingAction action,
|
protected void testActionSetBreakpointTrace(DockingAction action,
|
||||||
Set<TraceBreakpointKind> expectedKinds) throws Exception {
|
Set<TraceBreakpointKind> expectedKinds) throws Throwable {
|
||||||
TraceRecorder recorder = addMappedBreakpointOpenAndWait(); // Adds an unneeded breakpoint. Aw well.
|
TraceRecorder recorder = addMappedBreakpointOpenAndWait(); // Adds an unneeded breakpoint. Aw well.
|
||||||
Trace trace = recorder.getTrace();
|
Trace trace = recorder.getTrace();
|
||||||
|
|
||||||
|
@ -568,67 +571,67 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testActionSetSoftwareBreakpointProgram() throws Exception {
|
public void testActionSetSoftwareBreakpointProgram() throws Throwable {
|
||||||
testActionSetBreakpointProgram(breakpointMarkerPlugin.actionSetSoftwareBreakpoint,
|
testActionSetBreakpointProgram(breakpointMarkerPlugin.actionSetSoftwareBreakpoint,
|
||||||
Set.of(TraceBreakpointKind.SW_EXECUTE));
|
Set.of(TraceBreakpointKind.SW_EXECUTE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testActionSetSoftwareBreakpointTrace() throws Exception {
|
public void testActionSetSoftwareBreakpointTrace() throws Throwable {
|
||||||
testActionSetBreakpointTrace(breakpointMarkerPlugin.actionSetSoftwareBreakpoint,
|
testActionSetBreakpointTrace(breakpointMarkerPlugin.actionSetSoftwareBreakpoint,
|
||||||
Set.of(TraceBreakpointKind.SW_EXECUTE));
|
Set.of(TraceBreakpointKind.SW_EXECUTE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testActionSetExecuteBreakpointProgram() throws Exception {
|
public void testActionSetExecuteBreakpointProgram() throws Throwable {
|
||||||
testActionSetBreakpointProgram(breakpointMarkerPlugin.actionSetExecuteBreakpoint,
|
testActionSetBreakpointProgram(breakpointMarkerPlugin.actionSetExecuteBreakpoint,
|
||||||
Set.of(TraceBreakpointKind.HW_EXECUTE));
|
Set.of(TraceBreakpointKind.HW_EXECUTE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testActionSetExecuteBreakpointTrace() throws Exception {
|
public void testActionSetExecuteBreakpointTrace() throws Throwable {
|
||||||
testActionSetBreakpointTrace(breakpointMarkerPlugin.actionSetExecuteBreakpoint,
|
testActionSetBreakpointTrace(breakpointMarkerPlugin.actionSetExecuteBreakpoint,
|
||||||
Set.of(TraceBreakpointKind.HW_EXECUTE));
|
Set.of(TraceBreakpointKind.HW_EXECUTE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testActionSetReadWriteBreakpointProgram() throws Exception {
|
public void testActionSetReadWriteBreakpointProgram() throws Throwable {
|
||||||
testActionSetBreakpointProgram(breakpointMarkerPlugin.actionSetReadWriteBreakpoint,
|
testActionSetBreakpointProgram(breakpointMarkerPlugin.actionSetReadWriteBreakpoint,
|
||||||
Set.of(TraceBreakpointKind.READ, TraceBreakpointKind.WRITE));
|
Set.of(TraceBreakpointKind.READ, TraceBreakpointKind.WRITE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testActionSetReadWriteBreakpointTrace() throws Exception {
|
public void testActionSetReadWriteBreakpointTrace() throws Throwable {
|
||||||
testActionSetBreakpointTrace(breakpointMarkerPlugin.actionSetReadWriteBreakpoint,
|
testActionSetBreakpointTrace(breakpointMarkerPlugin.actionSetReadWriteBreakpoint,
|
||||||
Set.of(TraceBreakpointKind.READ, TraceBreakpointKind.WRITE));
|
Set.of(TraceBreakpointKind.READ, TraceBreakpointKind.WRITE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testActionSetReadBreakpointProgram() throws Exception {
|
public void testActionSetReadBreakpointProgram() throws Throwable {
|
||||||
testActionSetBreakpointProgram(breakpointMarkerPlugin.actionSetReadBreakpoint,
|
testActionSetBreakpointProgram(breakpointMarkerPlugin.actionSetReadBreakpoint,
|
||||||
Set.of(TraceBreakpointKind.READ));
|
Set.of(TraceBreakpointKind.READ));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testActionSetReadBreakpointTrace() throws Exception {
|
public void testActionSetReadBreakpointTrace() throws Throwable {
|
||||||
testActionSetBreakpointTrace(breakpointMarkerPlugin.actionSetReadBreakpoint,
|
testActionSetBreakpointTrace(breakpointMarkerPlugin.actionSetReadBreakpoint,
|
||||||
Set.of(TraceBreakpointKind.READ));
|
Set.of(TraceBreakpointKind.READ));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testActionSetWriteBreakpointProgram() throws Exception {
|
public void testActionSetWriteBreakpointProgram() throws Throwable {
|
||||||
testActionSetBreakpointProgram(breakpointMarkerPlugin.actionSetWriteBreakpoint,
|
testActionSetBreakpointProgram(breakpointMarkerPlugin.actionSetWriteBreakpoint,
|
||||||
Set.of(TraceBreakpointKind.WRITE));
|
Set.of(TraceBreakpointKind.WRITE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testActionSetWriteBreakpointTrace() throws Exception {
|
public void testActionSetWriteBreakpointTrace() throws Throwable {
|
||||||
testActionSetBreakpointTrace(breakpointMarkerPlugin.actionSetWriteBreakpoint,
|
testActionSetBreakpointTrace(breakpointMarkerPlugin.actionSetWriteBreakpoint,
|
||||||
Set.of(TraceBreakpointKind.WRITE));
|
Set.of(TraceBreakpointKind.WRITE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testActionEnableBreakpointProgram() throws Exception {
|
public void testActionEnableBreakpointProgram() throws Throwable {
|
||||||
addMappedBreakpointOpenAndWait();
|
addMappedBreakpointOpenAndWait();
|
||||||
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
|
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
|
||||||
lb.disable();
|
lb.disable();
|
||||||
|
@ -641,7 +644,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testActionEnableBreakpointTrace() throws Exception {
|
public void testActionEnableBreakpointTrace() throws Throwable {
|
||||||
TraceRecorder recorder = addMappedBreakpointOpenAndWait();
|
TraceRecorder recorder = addMappedBreakpointOpenAndWait();
|
||||||
Trace trace = recorder.getTrace();
|
Trace trace = recorder.getTrace();
|
||||||
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
|
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
|
||||||
|
@ -656,7 +659,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testActionDisableBreakpointProgram() throws Exception {
|
public void testActionDisableBreakpointProgram() throws Throwable {
|
||||||
addMappedBreakpointOpenAndWait();
|
addMappedBreakpointOpenAndWait();
|
||||||
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
|
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
|
||||||
|
|
||||||
|
@ -667,7 +670,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testActionDisableBreakpointTrace() throws Exception {
|
public void testActionDisableBreakpointTrace() throws Throwable {
|
||||||
TraceRecorder recorder = addMappedBreakpointOpenAndWait();
|
TraceRecorder recorder = addMappedBreakpointOpenAndWait();
|
||||||
Trace trace = recorder.getTrace();
|
Trace trace = recorder.getTrace();
|
||||||
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
|
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
|
||||||
|
@ -680,7 +683,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testActionClearBreakpointProgram() throws Exception {
|
public void testActionClearBreakpointProgram() throws Throwable {
|
||||||
addMappedBreakpointOpenAndWait();
|
addMappedBreakpointOpenAndWait();
|
||||||
|
|
||||||
performAction(breakpointMarkerPlugin.actionClearBreakpoint,
|
performAction(breakpointMarkerPlugin.actionClearBreakpoint,
|
||||||
|
@ -690,7 +693,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testActionClearBreakpointTrace() throws Exception {
|
public void testActionClearBreakpointTrace() throws Throwable {
|
||||||
TraceRecorder recorder = addMappedBreakpointOpenAndWait();
|
TraceRecorder recorder = addMappedBreakpointOpenAndWait();
|
||||||
Trace trace = recorder.getTrace();
|
Trace trace = recorder.getTrace();
|
||||||
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
|
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
|
||||||
|
|
|
@ -1269,7 +1269,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||||
.createRegion(".text", 0, tb.range(0x00400000, 0x0040ffff),
|
.createRegion(".text", 0, tb.range(0x00400000, 0x0040ffff),
|
||||||
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
|
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
|
||||||
thread1 = tb.getOrAddThread("Thread1", 0);
|
thread1 = tb.getOrAddThread("Thread1", 0);
|
||||||
tb.exec(0, 0, thread1, java.util.List.of("RIP = 0x00400000;"));
|
tb.exec(0, 0, thread1, "RIP = 0x00400000;");
|
||||||
}
|
}
|
||||||
|
|
||||||
TraceThread thread2;
|
TraceThread thread2;
|
||||||
|
@ -1279,7 +1279,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||||
.createRegion(".text", 0, tb2.range(0x200, 0x3ff), TraceMemoryFlag.READ,
|
.createRegion(".text", 0, tb2.range(0x200, 0x3ff), TraceMemoryFlag.READ,
|
||||||
TraceMemoryFlag.EXECUTE);
|
TraceMemoryFlag.EXECUTE);
|
||||||
thread2 = tb2.getOrAddThread("Thread2", 0);
|
thread2 = tb2.getOrAddThread("Thread2", 0);
|
||||||
tb2.exec(0, 0, thread2, java.util.List.of("PC = 0x100;"));
|
tb2.exec(0, 0, thread2, "PC = 0x100;");
|
||||||
}
|
}
|
||||||
|
|
||||||
traceManager.openTrace(tb.trace);
|
traceManager.openTrace(tb.trace);
|
||||||
|
|
|
@ -82,7 +82,7 @@ public class DebuggerPcodeStepperProviderTest extends AbstractGhidraHeadedDebugg
|
||||||
thread = tb.getOrAddThread("1", 0);
|
thread = tb.getOrAddThread("1", 0);
|
||||||
|
|
||||||
PcodeExecutor<byte[]> init = TraceSleighUtils.buildByteExecutor(tb.trace, 0, thread, 0);
|
PcodeExecutor<byte[]> init = TraceSleighUtils.buildByteExecutor(tb.trace, 0, thread, 0);
|
||||||
init.executeSleighLine("pc = 0x00400000");
|
init.executeSleigh("pc = 0x00400000;");
|
||||||
|
|
||||||
Assembler asm = Assemblers.getAssembler(tb.trace.getFixedProgramView(0));
|
Assembler asm = Assemblers.getAssembler(tb.trace.getFixedProgramView(0));
|
||||||
iit = asm.assemble(start,
|
iit = asm.assemble(start,
|
||||||
|
@ -166,7 +166,7 @@ public class DebuggerPcodeStepperProviderTest extends AbstractGhidraHeadedDebugg
|
||||||
.anyMatch(r -> r.getCode().contains("emu_swi"))));
|
.anyMatch(r -> r.getCode().contains("emu_swi"))));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<PcodeRow> format(List<String> sleigh) {
|
protected List<PcodeRow> format(String sleigh) {
|
||||||
SleighLanguage language = (SleighLanguage) getToyBE64Language();
|
SleighLanguage language = (SleighLanguage) getToyBE64Language();
|
||||||
PcodeProgram prog = SleighProgramCompiler.compileProgram(language, "test", sleigh,
|
PcodeProgram prog = SleighProgramCompiler.compileProgram(language, "test", sleigh,
|
||||||
PcodeUseropLibrary.nil());
|
PcodeUseropLibrary.nil());
|
||||||
|
@ -179,7 +179,7 @@ public class DebuggerPcodeStepperProviderTest extends AbstractGhidraHeadedDebugg
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPcodeFormatterSimple() {
|
public void testPcodeFormatterSimple() {
|
||||||
List<PcodeRow> rows = format(List.of("r0 = 1;"));
|
List<PcodeRow> rows = format("r0 = 1;");
|
||||||
assertEquals(2, rows.size());
|
assertEquals(2, rows.size());
|
||||||
assertEquals("<html></html>", rows.get(0).getLabel());
|
assertEquals("<html></html>", rows.get(0).getLabel());
|
||||||
assertEquals(FallthroughPcodeRow.class, rows.get(1).getClass());
|
assertEquals(FallthroughPcodeRow.class, rows.get(1).getClass());
|
||||||
|
@ -187,9 +187,10 @@ public class DebuggerPcodeStepperProviderTest extends AbstractGhidraHeadedDebugg
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPcodeFormatterStartsLabel() {
|
public void testPcodeFormatterStartsLabel() {
|
||||||
List<PcodeRow> rows = format(List.of(
|
List<PcodeRow> rows = format("""
|
||||||
"<L0> r0 = 1;",
|
<L0> r0 = 1;
|
||||||
"goto <L0>;"));
|
goto <L0>;
|
||||||
|
""");
|
||||||
assertEquals(3, rows.size());
|
assertEquals(3, rows.size());
|
||||||
assertEquals("<html><span class=\"lab\"><0></span></html>", rows.get(0).getLabel());
|
assertEquals("<html><span class=\"lab\"><0></span></html>", rows.get(0).getLabel());
|
||||||
assertEquals("<html></html>", rows.get(1).getLabel());
|
assertEquals("<html></html>", rows.get(1).getLabel());
|
||||||
|
@ -198,10 +199,11 @@ public class DebuggerPcodeStepperProviderTest extends AbstractGhidraHeadedDebugg
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPcodeFormatterMiddleLabel() {
|
public void testPcodeFormatterMiddleLabel() {
|
||||||
List<PcodeRow> rows = format(List.of(
|
List<PcodeRow> rows = format("""
|
||||||
"if 1:1 goto <SKIP>;",
|
if 1:1 goto <SKIP>;
|
||||||
"r0 = 1;",
|
r0 = 1;
|
||||||
"<SKIP> r1 = 2;"));
|
<SKIP> r1 = 2;
|
||||||
|
""");
|
||||||
assertEquals(4, rows.size());
|
assertEquals(4, rows.size());
|
||||||
assertEquals("<html></html>", rows.get(0).getLabel());
|
assertEquals("<html></html>", rows.get(0).getLabel());
|
||||||
assertEquals("<html></html>", rows.get(1).getLabel());
|
assertEquals("<html></html>", rows.get(1).getLabel());
|
||||||
|
@ -211,10 +213,11 @@ public class DebuggerPcodeStepperProviderTest extends AbstractGhidraHeadedDebugg
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPcodeFormatterFallthroughLabel() {
|
public void testPcodeFormatterFallthroughLabel() {
|
||||||
List<PcodeRow> rows = format(List.of(
|
List<PcodeRow> rows = format("""
|
||||||
"if 1:1 goto <SKIP>;",
|
if 1:1 goto <SKIP>;
|
||||||
"r0 = 1;",
|
r0 = 1;
|
||||||
"<SKIP>"));
|
<SKIP>
|
||||||
|
""");
|
||||||
assertEquals(3, rows.size());
|
assertEquals(3, rows.size());
|
||||||
assertEquals("<html></html>", rows.get(0).getLabel());
|
assertEquals("<html></html>", rows.get(0).getLabel());
|
||||||
assertEquals("<html></html>", rows.get(1).getLabel());
|
assertEquals("<html></html>", rows.get(1).getLabel());
|
||||||
|
@ -224,12 +227,13 @@ public class DebuggerPcodeStepperProviderTest extends AbstractGhidraHeadedDebugg
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPcodeFormatterManyLabel() {
|
public void testPcodeFormatterManyLabel() {
|
||||||
List<PcodeRow> rows = format(List.of(
|
List<PcodeRow> rows = format("""
|
||||||
"<L0> goto <L1>;",
|
<L0> goto <L1>;
|
||||||
"<L1> goto <L2>;",
|
<L1> goto <L2>;
|
||||||
"<L2> goto <L3>;",
|
<L2> goto <L3>;
|
||||||
"goto <L0>;",
|
goto <L0>;
|
||||||
"<L3>"));
|
<L3>
|
||||||
|
""");
|
||||||
assertEquals(5, rows.size());
|
assertEquals(5, rows.size());
|
||||||
// NB. templates number labels in order of appearance in BRANCHes
|
// NB. templates number labels in order of appearance in BRANCHes
|
||||||
assertEquals("<html><span class=\"lab\"><3></span></html>", rows.get(0).getLabel());
|
assertEquals("<html><span class=\"lab\"><3></span></html>", rows.get(0).getLabel());
|
||||||
|
|
|
@ -469,7 +469,7 @@ public class DebuggerRegistersProviderTest extends AbstractGhidraHeadedDebuggerG
|
||||||
|
|
||||||
TraceThread thread = addThread();
|
TraceThread thread = addThread();
|
||||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||||
tb.exec(0, 0, thread, List.of("pc = 100;"));
|
tb.exec(0, 0, thread, "pc = 100;");
|
||||||
}
|
}
|
||||||
traceManager.activateThread(thread);
|
traceManager.activateThread(thread);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
@ -800,10 +800,11 @@ public class DebuggerRegistersProviderTest extends AbstractGhidraHeadedDebuggerG
|
||||||
modelData.stream().filter(r -> r.getRegister() == pc).findFirst().orElse(null);
|
modelData.stream().filter(r -> r.getRegister() == pc).findFirst().orElse(null);
|
||||||
assertNotNull(pcAvail);
|
assertNotNull(pcAvail);
|
||||||
|
|
||||||
pcAvail.setSelected(false);
|
runSwing(() -> {
|
||||||
dialog.availableTableModel.fireTableDataChanged();
|
pcAvail.setSelected(false);
|
||||||
dialog.okCallback();
|
dialog.availableTableModel.fireTableDataChanged();
|
||||||
waitForSwing();
|
dialog.okCallback();
|
||||||
|
});
|
||||||
|
|
||||||
assertNull(getRegisterRow(pc));
|
assertNull(getRegisterRow(pc));
|
||||||
assertTrue(registersProvider.actionSelectRegisters.isEnabled());
|
assertTrue(registersProvider.actionSelectRegisters.isEnabled());
|
||||||
|
|
|
@ -148,7 +148,7 @@ public class DebuggerStateEditingServiceTest extends AbstractGhidraHeadedDebugge
|
||||||
|
|
||||||
Assembler asm = Assemblers.getAssembler(tb.trace.getFixedProgramView(0));
|
Assembler asm = Assemblers.getAssembler(tb.trace.getFixedProgramView(0));
|
||||||
asm.assemble(tb.addr(0x00400000), "imm r0,#123");
|
asm.assemble(tb.addr(0x00400000), "imm r0,#123");
|
||||||
executor.executeSleighLine("pc = 0x00400000");
|
executor.executeSleigh("pc = 0x00400000;");
|
||||||
}
|
}
|
||||||
traceManager.activateTrace(tb.trace);
|
traceManager.activateTrace(tb.trace);
|
||||||
editingService.setCurrentMode(tb.trace, StateEditingMode.WRITE_EMULATOR);
|
editingService.setCurrentMode(tb.trace, StateEditingMode.WRITE_EMULATOR);
|
||||||
|
@ -186,7 +186,7 @@ public class DebuggerStateEditingServiceTest extends AbstractGhidraHeadedDebugge
|
||||||
|
|
||||||
Assembler asm = Assemblers.getAssembler(tb.trace.getFixedProgramView(0));
|
Assembler asm = Assemblers.getAssembler(tb.trace.getFixedProgramView(0));
|
||||||
asm.assemble(tb.addr(0x00400000), "imm r0,#123");
|
asm.assemble(tb.addr(0x00400000), "imm r0,#123");
|
||||||
executor.executeSleighLine("pc = 0x00400000");
|
executor.executeSleigh("pc = 0x00400000;");
|
||||||
}
|
}
|
||||||
traceManager.activateTrace(tb.trace);
|
traceManager.activateTrace(tb.trace);
|
||||||
editingService.setCurrentMode(tb.trace, StateEditingMode.WRITE_EMULATOR);
|
editingService.setCurrentMode(tb.trace, StateEditingMode.WRITE_EMULATOR);
|
||||||
|
|
|
@ -337,7 +337,7 @@ public class DebuggerTraceManagerServiceTest extends AbstractGhidraHeadedDebugge
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAutoActivatePresent() throws Exception {
|
public void testAutoActivatePresent() throws Throwable {
|
||||||
assertTrue(traceManager.isAutoActivatePresent());
|
assertTrue(traceManager.isAutoActivatePresent());
|
||||||
|
|
||||||
createTestModel();
|
createTestModel();
|
||||||
|
@ -345,6 +345,7 @@ public class DebuggerTraceManagerServiceTest extends AbstractGhidraHeadedDebugge
|
||||||
|
|
||||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||||
createTargetTraceMapper(mb.testProcess1), ActionSource.AUTOMATIC);
|
createTargetTraceMapper(mb.testProcess1), ActionSource.AUTOMATIC);
|
||||||
|
waitRecorder(recorder);
|
||||||
Trace trace = recorder.getTrace();
|
Trace trace = recorder.getTrace();
|
||||||
|
|
||||||
traceManager.openTrace(trace);
|
traceManager.openTrace(trace);
|
||||||
|
|
|
@ -18,7 +18,6 @@ package ghidra.pcode.exec;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -29,7 +28,6 @@ import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||||
import ghidra.app.services.ActionSource;
|
import ghidra.app.services.ActionSource;
|
||||||
import ghidra.app.services.TraceRecorder;
|
import ghidra.app.services.TraceRecorder;
|
||||||
import ghidra.dbg.model.TestTargetRegisterBankInThread;
|
import ghidra.dbg.model.TestTargetRegisterBankInThread;
|
||||||
import ghidra.pcode.exec.*;
|
|
||||||
import ghidra.pcode.utils.Utils;
|
import ghidra.pcode.utils.Utils;
|
||||||
import ghidra.program.model.lang.Register;
|
import ghidra.program.model.lang.Register;
|
||||||
import ghidra.trace.model.Trace;
|
import ghidra.trace.model.Trace;
|
||||||
|
@ -100,7 +98,7 @@ public class TraceRecorderAsyncPcodeExecTest extends AbstractGhidraHeadedDebugge
|
||||||
SleighLanguage language = (SleighLanguage) trace.getBaseLanguage();
|
SleighLanguage language = (SleighLanguage) trace.getBaseLanguage();
|
||||||
|
|
||||||
PcodeProgram prog = SleighProgramCompiler.compileProgram(language, "test",
|
PcodeProgram prog = SleighProgramCompiler.compileProgram(language, "test",
|
||||||
List.of("r2 = r0 + r1;"), PcodeUseropLibrary.NIL);
|
"r2 = r0 + r1;", PcodeUseropLibrary.NIL);
|
||||||
|
|
||||||
Register r0 = language.getRegister("r0");
|
Register r0 = language.getRegister("r0");
|
||||||
Register r1 = language.getRegister("r1");
|
Register r1 = language.getRegister("r1");
|
||||||
|
|
|
@ -314,7 +314,7 @@ public class PatchStep implements Step {
|
||||||
@Override
|
@Override
|
||||||
public <T> void execute(PcodeThread<T> emuThread, Stepper<T> stepper, TaskMonitor monitor)
|
public <T> void execute(PcodeThread<T> emuThread, Stepper<T> stepper, TaskMonitor monitor)
|
||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
PcodeProgram prog = emuThread.getMachine().compileSleigh("schedule", List.of(sleigh + ";"));
|
PcodeProgram prog = emuThread.getMachine().compileSleigh("schedule", sleigh + ";");
|
||||||
emuThread.getExecutor().execute(prog, emuThread.getUseropLibrary());
|
emuThread.getExecutor().execute(prog, emuThread.getUseropLibrary());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,7 +368,7 @@ public class PatchStep implements Step {
|
||||||
|
|
||||||
protected Map<AddressSpace, SemisparseByteArray> getPatches(Language language) {
|
protected Map<AddressSpace, SemisparseByteArray> getPatches(Language language) {
|
||||||
PcodeProgram prog = SleighProgramCompiler.compileProgram((SleighLanguage) language,
|
PcodeProgram prog = SleighProgramCompiler.compileProgram((SleighLanguage) language,
|
||||||
"schedule", List.of(sleigh + ";"), PcodeUseropLibrary.nil());
|
"schedule", sleigh + ";", PcodeUseropLibrary.nil());
|
||||||
// SemisparseArray is a bit overkill, no?
|
// SemisparseArray is a bit overkill, no?
|
||||||
Map<AddressSpace, SemisparseByteArray> result = new TreeMap<>();
|
Map<AddressSpace, SemisparseByteArray> result = new TreeMap<>();
|
||||||
for (PcodeOp op : prog.getCode()) {
|
for (PcodeOp op : prog.getCode()) {
|
||||||
|
|
|
@ -35,7 +35,7 @@ import ghidra.util.database.UndoableTransaction;
|
||||||
|
|
||||||
public class AbstractTracePcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTest {
|
public class AbstractTracePcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||||
|
|
||||||
public TraceThread initTrace(ToyDBTraceBuilder tb, List<String> stateInit,
|
public TraceThread initTrace(ToyDBTraceBuilder tb, String stateInit,
|
||||||
List<String> assembly) throws Throwable {
|
List<String> assembly) throws Throwable {
|
||||||
return initTrace(tb, tb.range(0x00400000, 0x0040ffff), tb.range(0x00100000, 0x0010ffff),
|
return initTrace(tb, tb.range(0x00400000, 0x0040ffff), tb.range(0x00100000, 0x0010ffff),
|
||||||
stateInit, assembly);
|
stateInit, assembly);
|
||||||
|
@ -53,14 +53,13 @@ public class AbstractTracePcodeEmulatorTest extends AbstractGhidraHeadlessIntegr
|
||||||
* memory where it was assembled.
|
* memory where it was assembled.
|
||||||
*
|
*
|
||||||
* @param tb the trace builder
|
* @param tb the trace builder
|
||||||
* @param stateInit SLEIGH source lines to execute to initialize the trace state before
|
* @param stateInit Sleigh source to execute to initialize the trace state before emulation
|
||||||
* emulation. Each line must end with ";"
|
|
||||||
* @param assembly lines of assembly to place starting at {@code 0x00400000}
|
* @param assembly lines of assembly to place starting at {@code 0x00400000}
|
||||||
* @return a new trace thread, whose register state is initialized as specified
|
* @return a new trace thread, whose register state is initialized as specified
|
||||||
* @throws Throwable if anything goes wrong
|
* @throws Throwable if anything goes wrong
|
||||||
*/
|
*/
|
||||||
public TraceThread initTrace(ToyDBTraceBuilder tb, AddressRange text, AddressRange stack,
|
public TraceThread initTrace(ToyDBTraceBuilder tb, AddressRange text, AddressRange stack,
|
||||||
List<String> stateInit, List<String> assembly) throws Throwable {
|
String stateInit, List<String> assembly) throws Throwable {
|
||||||
TraceMemoryManager mm = tb.trace.getMemoryManager();
|
TraceMemoryManager mm = tb.trace.getMemoryManager();
|
||||||
TraceThread thread;
|
TraceThread thread;
|
||||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||||
|
|
|
@ -54,10 +54,10 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
@Test
|
@Test
|
||||||
public void testSinglePUSH() throws Throwable {
|
public void testSinglePUSH() throws Throwable {
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||||
TraceThread thread = initTrace(tb,
|
TraceThread thread = initTrace(tb, """
|
||||||
List.of(
|
RIP = 0x00400000;
|
||||||
"RIP = 0x00400000;",
|
RSP = 0x00110000;
|
||||||
"RSP = 0x00110000;"),
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
"PUSH 0xdeadbeef"));
|
"PUSH 0xdeadbeef"));
|
||||||
|
|
||||||
|
@ -94,10 +94,10 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
@Test
|
@Test
|
||||||
public void testDoublePUSH() throws Throwable {
|
public void testDoublePUSH() throws Throwable {
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||||
TraceThread thread = initTrace(tb,
|
TraceThread thread = initTrace(tb, """
|
||||||
List.of(
|
RIP = 0x00400000;
|
||||||
"RIP = 0x00400000;",
|
RSP = 0x00110000;
|
||||||
"RSP = 0x00110000;"),
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
"PUSH 0xdeadbeef",
|
"PUSH 0xdeadbeef",
|
||||||
"PUSH 0xbaadf00d"));
|
"PUSH 0xbaadf00d"));
|
||||||
|
@ -133,11 +133,11 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||||
Register pc = tb.language.getProgramCounter();
|
Register pc = tb.language.getProgramCounter();
|
||||||
|
|
||||||
TraceThread thread = initTrace(tb,
|
TraceThread thread = initTrace(tb, """
|
||||||
List.of(
|
RIP = 0x00400000;
|
||||||
"RIP = 0x00400000;",
|
RSP = 0x00110000;
|
||||||
"RSP = 0x00110000;",
|
RAX = 0x12345678;
|
||||||
"RAX = 0x12345678;"),
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
"JMP 0x00400007", // 2 bytes
|
"JMP 0x00400007", // 2 bytes
|
||||||
"MOV EAX,0xdeadbeef", // 5 bytes
|
"MOV EAX,0xdeadbeef", // 5 bytes
|
||||||
|
@ -189,11 +189,12 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
AssemblyPatternBlock thumbPat = AssemblyPatternBlock.fromRegisterValue(thumbCtx);
|
AssemblyPatternBlock thumbPat = AssemblyPatternBlock.fromRegisterValue(thumbCtx);
|
||||||
|
|
||||||
// NOTE: Assemble the thumb section separately
|
// NOTE: Assemble the thumb section separately
|
||||||
TraceThread thread = initTrace(tb,
|
// write 0x00401001 immediately after bx (0x00400008)
|
||||||
List.of(
|
TraceThread thread = initTrace(tb, """
|
||||||
"pc = 0x00400000;",
|
pc = 0x00400000;
|
||||||
"sp = 0x00110000;",
|
sp = 0x00110000;
|
||||||
"*:4 0x00400008:4 = 0x00401001;"), // immediately after bx
|
*:4 0x00400008:4 = 0x00401001;
|
||||||
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
"ldr r6, [pc,#0]!", // 4 bytes, pc+4 should be 00400008
|
"ldr r6, [pc,#0]!", // 4 bytes, pc+4 should be 00400008
|
||||||
"bx r6")); // 4 bytes
|
"bx r6")); // 4 bytes
|
||||||
|
@ -241,10 +242,10 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "Toy:BE:64:default")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "Toy:BE:64:default")) {
|
||||||
assertEquals(Register.NO_CONTEXT, tb.language.getContextBaseRegister());
|
assertEquals(Register.NO_CONTEXT, tb.language.getContextBaseRegister());
|
||||||
|
|
||||||
TraceThread thread = initTrace(tb,
|
TraceThread thread = initTrace(tb, """
|
||||||
List.of(
|
pc = 0x00400000;
|
||||||
"pc = 0x00400000;",
|
sp = 0x00110000;
|
||||||
"sp = 0x00110000;"),
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
"imm r0, #911")); // decimal
|
"imm r0, #911")); // decimal
|
||||||
|
|
||||||
|
@ -272,10 +273,10 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
@Test
|
@Test
|
||||||
public void testBRDS() throws Throwable {
|
public void testBRDS() throws Throwable {
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "Toy:BE:64:default")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "Toy:BE:64:default")) {
|
||||||
TraceThread thread = initTrace(tb,
|
TraceThread thread = initTrace(tb, """
|
||||||
List.of(
|
pc = 0x00400000;
|
||||||
"pc = 0x00400000;",
|
sp = 0x00110000;
|
||||||
"sp = 0x00110000;"),
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
"brds 0x00400006",
|
"brds 0x00400006",
|
||||||
"imm r0, #911", // decimal
|
"imm r0, #911", // decimal
|
||||||
|
@ -314,13 +315,13 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
@Test
|
@Test
|
||||||
public void testSelfModifyingX86() throws Throwable {
|
public void testSelfModifyingX86() throws Throwable {
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||||
TraceThread thread = initTrace(tb,
|
// NB. Assembly actually happens first, so Sleigh will modify it
|
||||||
List.of(
|
TraceThread thread = initTrace(tb, """
|
||||||
"RIP = 0x00400000;",
|
RIP = 0x00400000;
|
||||||
"RSP = 0x00110000;",
|
RSP = 0x00110000;
|
||||||
"RAX = 0x12345678;",
|
RAX = 0x12345678;
|
||||||
// NB. Assembly actually happens first, so this is modifying
|
*:1 0x00400007:8 = *0x00400007:8 ^ 0xcc;
|
||||||
"*:1 0x00400007:8 = *0x00400007:8 ^ 0xcc;"),
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
// First instruction undoes the modification above
|
// First instruction undoes the modification above
|
||||||
"XOR byte ptr [0x00400007], 0xcc", // 7 bytes
|
"XOR byte ptr [0x00400007], 0xcc", // 7 bytes
|
||||||
|
@ -356,10 +357,10 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
@Test
|
@Test
|
||||||
public void testDoublePUSH_pCode() throws Throwable {
|
public void testDoublePUSH_pCode() throws Throwable {
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||||
TraceThread thread = initTrace(tb,
|
TraceThread thread = initTrace(tb, """
|
||||||
List.of(
|
RIP = 0x00400000;
|
||||||
"RIP = 0x00400000;",
|
RSP = 0x00110000;
|
||||||
"RSP = 0x00110000;"),
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
"PUSH 0xdeadbeef",
|
"PUSH 0xdeadbeef",
|
||||||
"PUSH 0xbaadf00d"));
|
"PUSH 0xbaadf00d"));
|
||||||
|
@ -424,10 +425,10 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
dumped.append(NumericUtilities.convertBytesToString(in));
|
dumped.append(NumericUtilities.convertBytesToString(in));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
TraceThread thread = initTrace(tb,
|
TraceThread thread = initTrace(tb, """
|
||||||
List.of(
|
RIP = 0x00400000;
|
||||||
"RIP = 0x00400000;",
|
RSP = 0x00110000;
|
||||||
"RSP = 0x00110000;"),
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
"PUSH 0xdeadbeef",
|
"PUSH 0xdeadbeef",
|
||||||
"PUSH 0xbaadf00d"));
|
"PUSH 0xbaadf00d"));
|
||||||
|
@ -438,7 +439,7 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
return hexLib;
|
return hexLib;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
emu.inject(tb.addr(0x00400006), List.of("hexdump(RSP);"));
|
emu.inject(tb.addr(0x00400006), "hexdump(RSP);");
|
||||||
PcodeThread<byte[]> emuThread = emu.newThread(thread.getPath());
|
PcodeThread<byte[]> emuThread = emu.newThread(thread.getPath());
|
||||||
emuThread.overrideContextWithDefault();
|
emuThread.overrideContextWithDefault();
|
||||||
|
|
||||||
|
@ -472,10 +473,10 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
dumped.append(NumericUtilities.convertBytesToString(in));
|
dumped.append(NumericUtilities.convertBytesToString(in));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
TraceThread thread = initTrace(tb,
|
TraceThread thread = initTrace(tb, """
|
||||||
List.of(
|
RIP = 0x00400000;
|
||||||
"RIP = 0x00400000;",
|
RSP = 0x00110000;
|
||||||
"RSP = 0x00110000;"),
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
"PUSH 0xdeadbeef",
|
"PUSH 0xdeadbeef",
|
||||||
"PUSH 0xbaadf00d"));
|
"PUSH 0xbaadf00d"));
|
||||||
|
@ -486,12 +487,13 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
return hexLib;
|
return hexLib;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
emu.inject(tb.addr(0x00400006), List.of(
|
emu.inject(tb.addr(0x00400006), """
|
||||||
"hexdump(RSP);",
|
hexdump(RSP);
|
||||||
"emu_swi();",
|
emu_swi();
|
||||||
"hexdump(RIP);",
|
hexdump(RIP);
|
||||||
"emu_exec_decoded();",
|
emu_exec_decoded();
|
||||||
"hexdump(RIP);"));
|
hexdump(RIP);
|
||||||
|
""");
|
||||||
PcodeThread<byte[]> emuThread = emu.newThread(thread.getPath());
|
PcodeThread<byte[]> emuThread = emu.newThread(thread.getPath());
|
||||||
emuThread.overrideContextWithDefault();
|
emuThread.overrideContextWithDefault();
|
||||||
|
|
||||||
|
@ -527,11 +529,11 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
@Test
|
@Test
|
||||||
public void testBreakpoints() throws Throwable {
|
public void testBreakpoints() throws Throwable {
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||||
TraceThread thread = initTrace(tb,
|
TraceThread thread = initTrace(tb, """
|
||||||
List.of(
|
RIP = 0x00400000;
|
||||||
"RIP = 0x00400000;",
|
RSP = 0x00110000;
|
||||||
"RSP = 0x00110000;",
|
RAX = 0;
|
||||||
"RAX = 0;"),
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
"PUSH 0xdeadbeef",
|
"PUSH 0xdeadbeef",
|
||||||
"PUSH 0xbaadf00d"));
|
"PUSH 0xbaadf00d"));
|
||||||
|
@ -561,11 +563,11 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
@Test
|
@Test
|
||||||
public void testCLZ() throws Throwable {
|
public void testCLZ() throws Throwable {
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "ARM:LE:32:v8")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "ARM:LE:32:v8")) {
|
||||||
TraceThread thread = initTrace(tb,
|
TraceThread thread = initTrace(tb, """
|
||||||
List.of(
|
pc = 0x00400000;
|
||||||
"pc = 0x00400000;",
|
sp = 0x00110000;
|
||||||
"sp = 0x00110000;",
|
r0 = 0x00008000;
|
||||||
"r0 = 0x00008000;"),
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
"clz r1, r0"));
|
"clz r1, r0"));
|
||||||
|
|
||||||
|
@ -594,12 +596,12 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||||
Register pc = tb.language.getProgramCounter();
|
Register pc = tb.language.getProgramCounter();
|
||||||
|
|
||||||
TraceThread thread = initTrace(tb,
|
TraceThread thread = initTrace(tb, """
|
||||||
List.of(
|
RIP = 0x00400000;
|
||||||
"RIP = 0x00400000;",
|
RSP = 0x00110000;
|
||||||
"RSP = 0x00110000;",
|
*:8 0x00600008:8 = 0x0123456789abcdef;
|
||||||
"*:8 0x00600008:8 = 0x0123456789abcdef;", // LE
|
*:8 0x00600000:8 = 0xfedcba9876543210;
|
||||||
"*:8 0x00600000:8 = 0xfedcba9876543210;"),
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
"MOVAPS XMM0, xmmword ptr [0x00600000]"));
|
"MOVAPS XMM0, xmmword ptr [0x00600000]"));
|
||||||
|
|
||||||
|
@ -632,12 +634,12 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||||
Register pc = tb.language.getProgramCounter();
|
Register pc = tb.language.getProgramCounter();
|
||||||
|
|
||||||
TraceThread thread = initTrace(tb,
|
TraceThread thread = initTrace(tb, """
|
||||||
List.of(
|
RIP = 0x00400000;
|
||||||
"RIP = 0x00400000;",
|
RSP = 0x00110000;
|
||||||
"RSP = 0x00110000;",
|
RAX = 0x7fffffff;
|
||||||
"RAX = 0x7fffffff;",
|
RCX = 4;
|
||||||
"RCX = 4;"),
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
"SAR EAX, CL"));
|
"SAR EAX, CL"));
|
||||||
|
|
||||||
|
@ -662,11 +664,11 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
@Test
|
@Test
|
||||||
public void testCachedReadAfterSmallWrite() throws Throwable {
|
public void testCachedReadAfterSmallWrite() throws Throwable {
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||||
TraceThread thread = initTrace(tb,
|
TraceThread thread = initTrace(tb, """
|
||||||
List.of(
|
RIP = 0x00400000;
|
||||||
"RIP = 0x00400000;",
|
RSP = 0x00110000;
|
||||||
"RSP = 0x00110000;",
|
RAX = 0x12345678;
|
||||||
"RAX = 0x12345678;"),
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
"XOR AH, AH",
|
"XOR AH, AH",
|
||||||
"MOV RCX, RAX"));
|
"MOV RCX, RAX"));
|
||||||
|
@ -689,9 +691,9 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
@Test(expected = AccessPcodeExecutionException.class)
|
@Test(expected = AccessPcodeExecutionException.class)
|
||||||
public void testCheckedMOV_err() throws Throwable {
|
public void testCheckedMOV_err() throws Throwable {
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||||
TraceThread thread = initTrace(tb,
|
TraceThread thread = initTrace(tb, """
|
||||||
List.of(
|
RIP = 0x00400000;
|
||||||
"RIP = 0x00400000;"),
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
"MOV RCX,RAX"));
|
"MOV RCX,RAX"));
|
||||||
|
|
||||||
|
@ -711,10 +713,11 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
@Test
|
@Test
|
||||||
public void testCheckedMOV_known() throws Throwable {
|
public void testCheckedMOV_known() throws Throwable {
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||||
TraceThread thread = initTrace(tb,
|
// Make RAX known in the trace
|
||||||
List.of(
|
TraceThread thread = initTrace(tb, """
|
||||||
"RIP = 0x00400000;",
|
RIP = 0x00400000;
|
||||||
"RAX = 0x1234;"), // Make it known in the trace
|
RAX = 0x1234;
|
||||||
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
"MOV RCX,RAX"));
|
"MOV RCX,RAX"));
|
||||||
|
|
||||||
|
@ -735,10 +738,11 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
@Test(expected = AccessPcodeExecutionException.class)
|
@Test(expected = AccessPcodeExecutionException.class)
|
||||||
public void testCheckedMOV_knownPast_err() throws Throwable {
|
public void testCheckedMOV_knownPast_err() throws Throwable {
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||||
TraceThread thread = initTrace(tb,
|
// Make RAX known in the trace
|
||||||
List.of(
|
TraceThread thread = initTrace(tb, """
|
||||||
"RIP = 0x00400000;",
|
RIP = 0x00400000;
|
||||||
"RAX = 0x1234;"), // Make it known in the trace
|
RAX = 0x1234;
|
||||||
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
"MOV RCX,RAX"));
|
"MOV RCX,RAX"));
|
||||||
|
|
||||||
|
@ -760,10 +764,11 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
@Test
|
@Test
|
||||||
public void testCheckedMOV_knownPast_has() throws Throwable {
|
public void testCheckedMOV_knownPast_has() throws Throwable {
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||||
TraceThread thread = initTrace(tb,
|
// Make RAX known in the trace
|
||||||
List.of(
|
TraceThread thread = initTrace(tb, """
|
||||||
"RIP = 0x00400000;",
|
RIP = 0x00400000;
|
||||||
"RAX = 0x1234;"), // Make it known in the trace
|
RAX = 0x1234;
|
||||||
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
"MOV RCX,RAX"));
|
"MOV RCX,RAX"));
|
||||||
|
|
||||||
|
@ -785,9 +790,9 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
@Test
|
@Test
|
||||||
public void testCheckedMOV_initialized() throws Throwable {
|
public void testCheckedMOV_initialized() throws Throwable {
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||||
TraceThread thread = initTrace(tb,
|
TraceThread thread = initTrace(tb, """
|
||||||
List.of(
|
RIP = 0x00400000;
|
||||||
"RIP = 0x00400000;"),
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
"MOV RAX,0", // Have the program initialize it
|
"MOV RAX,0", // Have the program initialize it
|
||||||
"MOV RCX,RAX"));
|
"MOV RCX,RAX"));
|
||||||
|
@ -820,11 +825,11 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
ctxManager.setValue(lang, ctxVal, Range.atLeast(0L),
|
ctxManager.setValue(lang, ctxVal, Range.atLeast(0L),
|
||||||
tb.range(0x00400000, 0x00400002));
|
tb.range(0x00400000, 0x00400002));
|
||||||
}
|
}
|
||||||
TraceThread thread = initTrace(tb,
|
TraceThread thread = initTrace(tb, """
|
||||||
List.of(
|
RIP = 0x00400000;
|
||||||
"RIP = 0x00400000;",
|
RSP = 0x00110000;
|
||||||
"RSP = 0x00110000;",
|
RAX = 0xff12345678;
|
||||||
"RAX = 0xff12345678;"),
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
"DEC EAX",
|
"DEC EAX",
|
||||||
"MOV ECX,EAX"));
|
"MOV ECX,EAX"));
|
||||||
|
@ -863,11 +868,11 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
@Test
|
@Test
|
||||||
public void testMOV_EAX_dword_RBPm4() throws Throwable {
|
public void testMOV_EAX_dword_RBPm4() throws Throwable {
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||||
TraceThread thread = initTrace(tb,
|
TraceThread thread = initTrace(tb, """
|
||||||
List.of(
|
RIP = 0x00400000;
|
||||||
"RIP = 0x00400000;",
|
RSP = 0x00110000;
|
||||||
"RSP = 0x00110000;",
|
*:4 (0:8-4) = 0x12345678;
|
||||||
"*:4 (0:8-4) = 0x12345678;"),
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
"MOV EAX, dword ptr [RBP + -0x4]"));
|
"MOV EAX, dword ptr [RBP + -0x4]"));
|
||||||
|
|
||||||
|
@ -898,10 +903,10 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
@Test(expected = PcodeExecutionException.class)
|
@Test(expected = PcodeExecutionException.class)
|
||||||
public void testMOV_EAX_dword_RBPm2_x64() throws Throwable {
|
public void testMOV_EAX_dword_RBPm2_x64() throws Throwable {
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||||
TraceThread thread = initTrace(tb,
|
TraceThread thread = initTrace(tb, """
|
||||||
List.of(
|
RIP = 0x00400000;
|
||||||
"RIP = 0x00400000;",
|
RSP = 0x00110000;
|
||||||
"RSP = 0x00110000;"),
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
"MOV EAX, dword ptr [RBP + -0x2]"));
|
"MOV EAX, dword ptr [RBP + -0x2]"));
|
||||||
|
|
||||||
|
@ -921,10 +926,10 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
@Test(expected = PcodeExecutionException.class)
|
@Test(expected = PcodeExecutionException.class)
|
||||||
public void testMOV_EAX_dword_EBPm2_x86() throws Throwable {
|
public void testMOV_EAX_dword_EBPm2_x86() throws Throwable {
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:32:default")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:32:default")) {
|
||||||
TraceThread thread = initTrace(tb,
|
TraceThread thread = initTrace(tb, """
|
||||||
List.of(
|
EIP = 0x00400000;
|
||||||
"EIP = 0x00400000;",
|
ESP = 0x00110000;
|
||||||
"ESP = 0x00110000;"),
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
"MOV EAX, dword ptr [EBP + -0x2]"));
|
"MOV EAX, dword ptr [EBP + -0x2]"));
|
||||||
|
|
||||||
|
@ -944,10 +949,10 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "Toy:BE:64:default")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "Toy:BE:64:default")) {
|
||||||
assertEquals(Register.NO_CONTEXT, tb.language.getContextBaseRegister());
|
assertEquals(Register.NO_CONTEXT, tb.language.getContextBaseRegister());
|
||||||
|
|
||||||
TraceThread thread = initTrace(tb,
|
TraceThread thread = initTrace(tb, """
|
||||||
List.of(
|
pc = 0x00400000;
|
||||||
"pc = 0x00400000;",
|
sp = 0x00110000;
|
||||||
"sp = 0x00110000;"),
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
"unimpl"));
|
"unimpl"));
|
||||||
|
|
||||||
|
@ -966,11 +971,11 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
Address stackStart = tb.language.getDefaultDataSpace().getAddress(0, true);
|
Address stackStart = tb.language.getDefaultDataSpace().getAddress(0, true);
|
||||||
TraceThread thread = initTrace(tb,
|
TraceThread thread = initTrace(tb,
|
||||||
new AddressRangeImpl(textStart, 0x200),
|
new AddressRangeImpl(textStart, 0x200),
|
||||||
new AddressRangeImpl(stackStart, 1),
|
new AddressRangeImpl(stackStart, 1), """
|
||||||
List.of(
|
PC = 0x000100;
|
||||||
"PC = 0x000100;",
|
W1 = 0x0800;
|
||||||
"W1 = 0x0800;",
|
*[ram]:2 0x000800:3 = 0x1234;
|
||||||
"*[ram]:2 0x000800:3 = 0x1234;"),
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
"mov.w [W1], W0"));
|
"mov.w [W1], W0"));
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
@ -207,14 +206,14 @@ public class TraceSleighUtilsTest extends AbstractGhidraHeadlessIntegrationTest
|
||||||
public void testCompileSleighProgram() throws Exception {
|
public void testCompileSleighProgram() throws Exception {
|
||||||
try (ToyDBTraceBuilder b = new ToyDBTraceBuilder("test", TOY_BE_64_HARVARD)) {
|
try (ToyDBTraceBuilder b = new ToyDBTraceBuilder("test", TOY_BE_64_HARVARD)) {
|
||||||
PcodeProgram sp = SleighProgramCompiler.compileProgram((SleighLanguage) b.language,
|
PcodeProgram sp = SleighProgramCompiler.compileProgram((SleighLanguage) b.language,
|
||||||
"test", List.of(
|
"test", """
|
||||||
"if (r0) goto <else>;",
|
if (r0) goto <else>;
|
||||||
" r1 = 6;",
|
r1 = 6;
|
||||||
" goto <done>;",
|
goto <done>;
|
||||||
"<else>",
|
<else>
|
||||||
" r1 = 7;",
|
r1 = 7;
|
||||||
"<done>"),
|
<done>
|
||||||
PcodeUseropLibrary.NIL);
|
""", PcodeUseropLibrary.NIL);
|
||||||
TraceThread thread;
|
TraceThread thread;
|
||||||
try (UndoableTransaction tid = b.startTransaction()) {
|
try (UndoableTransaction tid = b.startTransaction()) {
|
||||||
thread = b.getOrAddThread("Thread1", 0);
|
thread = b.getOrAddThread("Thread1", 0);
|
||||||
|
|
|
@ -27,7 +27,6 @@ import java.nio.charset.CharsetEncoder;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.google.common.collect.Range;
|
import com.google.common.collect.Range;
|
||||||
|
|
||||||
|
@ -131,9 +130,9 @@ public class ToyDBTraceBuilder implements AutoCloseable {
|
||||||
* @param snap the snap to modify
|
* @param snap the snap to modify
|
||||||
* @param frame the frame to modify
|
* @param frame the frame to modify
|
||||||
* @param thread the thread to modify, can be {@code null} if only memory is used
|
* @param thread the thread to modify, can be {@code null} if only memory is used
|
||||||
* @param sleigh the lines of Sleigh, including semicolons.
|
* @param sleigh the Sleigh source
|
||||||
*/
|
*/
|
||||||
public void exec(long snap, int frame, TraceThread thread, List<String> sleigh) {
|
public void exec(long snap, int frame, TraceThread thread, String sleigh) {
|
||||||
PcodeProgram program = SleighProgramCompiler.compileProgram((SleighLanguage) language,
|
PcodeProgram program = SleighProgramCompiler.compileProgram((SleighLanguage) language,
|
||||||
"builder", sleigh, PcodeUseropLibrary.nil());
|
"builder", sleigh, PcodeUseropLibrary.nil());
|
||||||
TraceSleighUtils.buildByteExecutor(trace, snap, thread, frame)
|
TraceSleighUtils.buildByteExecutor(trace, snap, thread, frame)
|
||||||
|
|
|
@ -15,8 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.trace.model.time.schedule;
|
package ghidra.trace.model.time.schedule;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||||
import ghidra.pcode.emu.PcodeThread;
|
import ghidra.pcode.emu.PcodeThread;
|
||||||
import ghidra.pcode.emu.ThreadPcodeExecutorState;
|
import ghidra.pcode.emu.ThreadPcodeExecutorState;
|
||||||
|
@ -167,7 +165,7 @@ class TestThread implements PcodeThread<Void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void inject(Address address, List<String> sleigh) {
|
public void inject(Address address, String source) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -257,19 +257,19 @@ public abstract class AbstractPcodeMachine<T> implements PcodeMachine<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PcodeProgram compileSleigh(String sourceName, List<String> lines) {
|
public PcodeProgram compileSleigh(String sourceName, String source) {
|
||||||
return SleighProgramCompiler.compileProgram(language, sourceName, lines, stubLibrary);
|
return SleighProgramCompiler.compileProgram(language, sourceName, source, stubLibrary);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void inject(Address address, List<String> sleigh) {
|
public void inject(Address address, String source) {
|
||||||
/**
|
/**
|
||||||
* TODO: Can I compile the template and build as if the inject were a
|
* TODO: Can I compile the template and build as if the inject were a
|
||||||
* instruction:^instruction constructor? This would require me to delay that build until
|
* instruction:^instruction constructor? This would require me to delay that build until
|
||||||
* execution, or at least check for instruction modification, if I do want to cache the
|
* execution, or at least check for instruction modification, if I do want to cache the
|
||||||
* built p-code.
|
* built p-code.
|
||||||
*/
|
*/
|
||||||
PcodeProgram pcode = compileSleigh("machine_inject:" + address, sleigh);
|
PcodeProgram pcode = compileSleigh("machine_inject:" + address, source);
|
||||||
injects.put(address, pcode);
|
injects.put(address, pcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,11 +292,12 @@ public abstract class AbstractPcodeMachine<T> implements PcodeMachine<T> {
|
||||||
* addressed by formalizing and better exposing the notion of p-code stacks (of p-code
|
* addressed by formalizing and better exposing the notion of p-code stacks (of p-code
|
||||||
* frames)
|
* frames)
|
||||||
*/
|
*/
|
||||||
PcodeProgram pcode = compileSleigh("breakpoint:" + address, List.of(
|
PcodeProgram pcode = compileSleigh("breakpoint:" + address, String.format("""
|
||||||
"if (!(" + sleighCondition + ")) goto <nobreak>;",
|
if (!(%s)) goto <nobreak>;
|
||||||
" emu_swi();",
|
emu_swi();
|
||||||
"<nobreak>",
|
<nobreak>
|
||||||
" emu_exec_decoded();"));
|
emu_exec_decoded();
|
||||||
|
""", sleighCondition));
|
||||||
injects.put(address, pcode);
|
injects.put(address, pcode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,10 +33,10 @@ import ghidra.util.Msg;
|
||||||
* The default implementation of {@link PcodeThread} suitable for most applications
|
* The default implementation of {@link PcodeThread} suitable for most applications
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* When emulating on concrete state, consider using {@link ModifiedPcodeThread}, so that
|
* When emulating on concrete state, consider using {@link ModifiedPcodeThread}, so that state
|
||||||
* state modifiers from the older {@link Emulator} are incorporated. In either case, it may be
|
* modifiers from the older {@link Emulator} are incorporated. In either case, it may be worthwhile
|
||||||
* worthwhile to examine existing state modifiers to ensure they are appropriately represented in
|
* to examine existing state modifiers to ensure they are appropriately represented in any abstract
|
||||||
* any abstract state. It may be necessary to port them.
|
* state. It may be necessary to port them.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* This class implements the control-flow logic of the target machine, cooperating with the p-code
|
* This class implements the control-flow logic of the target machine, cooperating with the p-code
|
||||||
|
@ -148,9 +148,9 @@ public class DefaultPcodeThread<T> implements PcodeThread<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void executeSleighLine(String line) {
|
public void executeSleigh(String source) {
|
||||||
PcodeProgram program = SleighProgramCompiler.compileProgram(language, "line",
|
PcodeProgram program =
|
||||||
List.of(line + ";"), thread.library);
|
SleighProgramCompiler.compileProgram(language, "exec", source, thread.library);
|
||||||
execute(program, thread.library);
|
execute(program, thread.library);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -588,9 +588,9 @@ public class DefaultPcodeThread<T> implements PcodeThread<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void inject(Address address, List<String> sleigh) {
|
public void inject(Address address, String source) {
|
||||||
PcodeProgram pcode = SleighProgramCompiler.compileProgram(
|
PcodeProgram pcode = SleighProgramCompiler.compileProgram(
|
||||||
language, "thread_inject:" + address, sleigh, library);
|
language, "thread_inject:" + address, source, library);
|
||||||
injects.put(address, pcode);
|
injects.put(address, pcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
package ghidra.pcode.emu;
|
package ghidra.pcode.emu;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||||
import ghidra.pcode.emu.DefaultPcodeThread.PcodeEmulationLibrary;
|
import ghidra.pcode.emu.DefaultPcodeThread.PcodeEmulationLibrary;
|
||||||
|
@ -31,7 +30,7 @@ import ghidra.program.model.address.Address;
|
||||||
public interface PcodeMachine<T> {
|
public interface PcodeMachine<T> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the machine's SLEIGH language (processor model)
|
* Get the machine's Sleigh language (processor model)
|
||||||
*
|
*
|
||||||
* @return the language
|
* @return the language
|
||||||
*/
|
*/
|
||||||
|
@ -61,7 +60,7 @@ public interface PcodeMachine<T> {
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* Thread userop libraries may have more userops than are defined in the machine's userop
|
* Thread userop libraries may have more userops than are defined in the machine's userop
|
||||||
* library. However, to compile SLEIGH programs linked to thread libraries, the thread's userops
|
* library. However, to compile Sleigh programs linked to thread libraries, the thread's userops
|
||||||
* must be known to the compiler. The stub library will name all userops common among the
|
* must be known to the compiler. The stub library will name all userops common among the
|
||||||
* threads, even if their definitions vary. <b>WARNING:</b> The stub library is not required to
|
* threads, even if their definitions vary. <b>WARNING:</b> The stub library is not required to
|
||||||
* provide implementations of the userops. Often they will throw exceptions, so do not attempt
|
* provide implementations of the userops. Often they will throw exceptions, so do not attempt
|
||||||
|
@ -114,26 +113,26 @@ public interface PcodeMachine<T> {
|
||||||
PcodeExecutorState<T> getSharedState();
|
PcodeExecutorState<T> getSharedState();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compile the given SLEIGH code for execution by a thread of this machine
|
* Compile the given Sleigh code for execution by a thread of this machine
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* This links in the userop library given at construction time and those defining the emulation
|
* This links in the userop library given at construction time and those defining the emulation
|
||||||
* userops, e.g., {@code emu_swi}.
|
* userops, e.g., {@code emu_swi}.
|
||||||
*
|
*
|
||||||
* @param sourceName a user-defined source name for the resulting "program"
|
* @param sourceName a user-defined source name for the resulting "program"
|
||||||
* @param lines the lines of SLEIGH source code
|
* @param lines the Sleigh source
|
||||||
* @return the compiled program
|
* @return the compiled program
|
||||||
*/
|
*/
|
||||||
PcodeProgram compileSleigh(String sourceName, List<String> lines);
|
PcodeProgram compileSleigh(String sourceName, String source);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override the p-code at the given address with the given SLEIGH source
|
* Override the p-code at the given address with the given Sleigh source
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* This will attempt to compile the given source against this machine's userop library and then
|
* This will attempt to compile the given source against this machine's userop library and then
|
||||||
* will inject it at the given address. The resulting p-code <em>replaces</em> that which would
|
* will inject it at the given address. The resulting p-code <em>replaces</em> that which would
|
||||||
* be executed by decoding the instruction at the given address. The means the machine will not
|
* be executed by decoding the instruction at the given address. The means the machine will not
|
||||||
* decode, nor advance its counter, unless the SLEIGH causes it. In most cases, the SLEIGH will
|
* decode, nor advance its counter, unless the Sleigh causes it. In most cases, the Sleigh will
|
||||||
* call {@link PcodeEmulationLibrary#emu_exec_decoded()} to cause the machine to decode and
|
* call {@link PcodeEmulationLibrary#emu_exec_decoded()} to cause the machine to decode and
|
||||||
* execute the overridden instruction.
|
* execute the overridden instruction.
|
||||||
*
|
*
|
||||||
|
@ -143,9 +142,9 @@ public interface PcodeMachine<T> {
|
||||||
* double-wrapping, etc.
|
* double-wrapping, etc.
|
||||||
*
|
*
|
||||||
* @param address the address to inject at
|
* @param address the address to inject at
|
||||||
* @param sleigh the SLEIGH source to compile and inject
|
* @param source the Sleigh source to compile and inject
|
||||||
*/
|
*/
|
||||||
void inject(Address address, List<String> sleigh);
|
void inject(Address address, String source);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the inject, if present, at the given address
|
* Remove the inject, if present, at the given address
|
||||||
|
@ -165,10 +164,10 @@ public interface PcodeMachine<T> {
|
||||||
* <p>
|
* <p>
|
||||||
* Breakpoints are implemented at the p-code level using an inject, without modification to the
|
* Breakpoints are implemented at the p-code level using an inject, without modification to the
|
||||||
* emulated image. As such, it cannot coexist with another inject. A client needing to break
|
* emulated image. As such, it cannot coexist with another inject. A client needing to break
|
||||||
* during an inject must use {@link PcodeEmulationLibrary#emu_swi()} in the injected SLEIGH.
|
* during an inject must use {@link PcodeEmulationLibrary#emu_swi()} in the injected Sleigh.
|
||||||
*
|
*
|
||||||
* @param address the address at which to break
|
* @param address the address at which to break
|
||||||
* @param sleighCondition a SLEIGH expression which controls the breakpoint
|
* @param sleighCondition a Sleigh expression which controls the breakpoint
|
||||||
*/
|
*/
|
||||||
void addBreakpoint(Address address, String sleighCondition);
|
void addBreakpoint(Address address, String sleighCondition);
|
||||||
}
|
}
|
||||||
|
|
|
@ -336,9 +336,9 @@ public interface PcodeThread<T> {
|
||||||
* inject.
|
* inject.
|
||||||
*
|
*
|
||||||
* @param address the address to inject at
|
* @param address the address to inject at
|
||||||
* @param sleigh the SLEIGH source to compile and inject
|
* @param source the Sleigh source to compile and inject
|
||||||
*/
|
*/
|
||||||
void inject(Address address, List<String> sleigh);
|
void inject(Address address, String source);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the per-thread inject, if present, at the given address
|
* Remove the per-thread inject, if present, at the given address
|
||||||
|
|
|
@ -28,9 +28,10 @@ public class X86PcodeStateInitializer implements PcodeStateInitializer {
|
||||||
private static final List<LanguageID> LANG_IDS = List.of(
|
private static final List<LanguageID> LANG_IDS = List.of(
|
||||||
new LanguageID("x86:LE:32:default"),
|
new LanguageID("x86:LE:32:default"),
|
||||||
new LanguageID("x86:LE:64:default"));
|
new LanguageID("x86:LE:64:default"));
|
||||||
private static final List<String> SOURCE = List.of(
|
private static final String SOURCE = """
|
||||||
"FS_OFFSET = 0;",
|
FS_OFFSET = 0;
|
||||||
"GS_OFFSET = 0;");
|
GS_OFFSET = 0;
|
||||||
|
""";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isApplicable(Language language) {
|
public boolean isApplicable(Language language) {
|
||||||
|
|
|
@ -91,13 +91,13 @@ public class PcodeExecutor<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compile and execute a line of Sleigh
|
* Compile and execute a block of Sleigh
|
||||||
*
|
*
|
||||||
* @param line the line, excluding the semicolon
|
* @param source the Sleigh source
|
||||||
*/
|
*/
|
||||||
public void executeSleighLine(String line) {
|
public void executeSleigh(String source) {
|
||||||
PcodeProgram program = SleighProgramCompiler.compileProgram(language,
|
PcodeProgram program =
|
||||||
"line", List.of(line + ";"), PcodeUseropLibrary.NIL);
|
SleighProgramCompiler.compileProgram(language, "exec", source, PcodeUseropLibrary.NIL);
|
||||||
execute(program, PcodeUseropLibrary.nil());
|
execute(program, PcodeUseropLibrary.nil());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.pcode.exec;
|
package ghidra.pcode.exec;
|
||||||
|
|
||||||
import java.text.MessageFormat;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||||
|
@ -65,7 +64,7 @@ public class SleighPcodeUseropDefinition<T> implements PcodeUseropDefinition<T>
|
||||||
private final Factory factory;
|
private final Factory factory;
|
||||||
private final String name;
|
private final String name;
|
||||||
private final List<String> params = new ArrayList<>();
|
private final List<String> params = new ArrayList<>();
|
||||||
private final List<String> lines = new ArrayList<>();
|
private final StringBuffer body = new StringBuffer();
|
||||||
|
|
||||||
protected Builder(Factory factory, String name) {
|
protected Builder(Factory factory, String name) {
|
||||||
this.factory = factory;
|
this.factory = factory;
|
||||||
|
@ -93,41 +92,12 @@ public class SleighPcodeUseropDefinition<T> implements PcodeUseropDefinition<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add lines of SLEIGH source
|
* Add Sleigh source to the body
|
||||||
*
|
*
|
||||||
* <p>
|
* @param additionalBody the additional source
|
||||||
* NOTE: The lines are joined only with line separators. No semicolons (;) are added at the
|
|
||||||
* end of each line.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* TODO: See if this can be made any prettier with text blocks in newer Java versions.
|
|
||||||
*
|
|
||||||
* @param additionalLines the additional lines
|
|
||||||
* @return this builder
|
|
||||||
*/
|
*/
|
||||||
public Builder sleigh(Collection<String> additionalLines) {
|
public Builder body(CharSequence additionalBody) {
|
||||||
this.lines.addAll(additionalLines);
|
body.append(additionalBody);
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see #sleigh(Collection)
|
|
||||||
*/
|
|
||||||
public Builder sleigh(String... additionalLines) {
|
|
||||||
return this.sleigh(Arrays.asList(additionalLines));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Treat each line as a pattern as in {@link MessageFormat#format(String, Object...)},
|
|
||||||
* replacing each with the result.
|
|
||||||
*
|
|
||||||
* @param arguments the arguments to pass to the formatter
|
|
||||||
* @return this builder
|
|
||||||
*/
|
|
||||||
public Builder applyAsPattern(Object[] arguments) {
|
|
||||||
for (int i = 0; i < lines.size(); i++) {
|
|
||||||
lines.set(i, MessageFormat.format(lines.get(i), arguments));
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,23 +114,23 @@ public class SleighPcodeUseropDefinition<T> implements PcodeUseropDefinition<T>
|
||||||
*/
|
*/
|
||||||
public <T> SleighPcodeUseropDefinition<T> build() {
|
public <T> SleighPcodeUseropDefinition<T> build() {
|
||||||
return new SleighPcodeUseropDefinition<>(factory.language, name, List.copyOf(params),
|
return new SleighPcodeUseropDefinition<>(factory.language, name, List.copyOf(params),
|
||||||
List.copyOf(lines));
|
body.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final SleighLanguage language;
|
private final SleighLanguage language;
|
||||||
private final String name;
|
private final String name;
|
||||||
private final List<String> params;
|
private final List<String> params;
|
||||||
private final List<String> lines;
|
private final String body;
|
||||||
|
|
||||||
private final Map<List<Varnode>, PcodeProgram> cacheByArgs = new HashMap<>();
|
private final Map<List<Varnode>, PcodeProgram> cacheByArgs = new HashMap<>();
|
||||||
|
|
||||||
protected SleighPcodeUseropDefinition(SleighLanguage language, String name, List<String> params,
|
protected SleighPcodeUseropDefinition(SleighLanguage language, String name, List<String> params,
|
||||||
List<String> lines) {
|
String body) {
|
||||||
this.language = language;
|
this.language = language;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.params = params;
|
this.params = params;
|
||||||
this.lines = lines;
|
this.body = body;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -181,7 +151,7 @@ public class SleighPcodeUseropDefinition<T> implements PcodeUseropDefinition<T>
|
||||||
args.add(outArg);
|
args.add(outArg);
|
||||||
args.addAll(inArgs);
|
args.addAll(inArgs);
|
||||||
return cacheByArgs.computeIfAbsent(args,
|
return cacheByArgs.computeIfAbsent(args,
|
||||||
a -> SleighProgramCompiler.compileUserop(language, name, params, lines, library, a));
|
a -> SleighProgramCompiler.compileUserop(language, name, params, body, library, a));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -211,11 +181,11 @@ public class SleighPcodeUseropDefinition<T> implements PcodeUseropDefinition<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the lines of source that define this userop
|
* Get the Sleigh source that defines this userop
|
||||||
*
|
*
|
||||||
* @return the lines
|
* @return the lines
|
||||||
*/
|
*/
|
||||||
public List<String> getLines() {
|
public String getBody() {
|
||||||
return lines;
|
return body;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,6 @@ import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
import ghidra.app.plugin.processors.sleigh.*;
|
import ghidra.app.plugin.processors.sleigh.*;
|
||||||
import ghidra.app.plugin.processors.sleigh.template.ConstructTpl;
|
import ghidra.app.plugin.processors.sleigh.template.ConstructTpl;
|
||||||
import ghidra.pcodeCPort.pcoderaw.VarnodeData;
|
import ghidra.pcodeCPort.pcoderaw.VarnodeData;
|
||||||
|
@ -66,12 +64,12 @@ public class SleighProgramCompiler {
|
||||||
* @param language the language
|
* @param language the language
|
||||||
* @param parser the parser
|
* @param parser the parser
|
||||||
* @param sourceName the name of the program, for error diagnostics
|
* @param sourceName the name of the program, for error diagnostics
|
||||||
* @param text the SLEIGH source
|
* @param source the Sleigh source
|
||||||
* @return the constructor template
|
* @return the constructor template
|
||||||
*/
|
*/
|
||||||
public static ConstructTpl compileTemplate(Language language, PcodeParser parser,
|
public static ConstructTpl compileTemplate(Language language, PcodeParser parser,
|
||||||
String sourceName, String text) {
|
String sourceName, String source) {
|
||||||
return parser.compilePcode(text, EXPRESSION_SOURCE_NAME, 1);
|
return parser.compilePcode(source, EXPRESSION_SOURCE_NAME, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -82,7 +80,7 @@ public class SleighProgramCompiler {
|
||||||
* @return the list of p-code ops
|
* @return the list of p-code ops
|
||||||
* @throws UnknownInstructionException in case of crossbuilds, the target instruction is unknown
|
* @throws UnknownInstructionException in case of crossbuilds, the target instruction is unknown
|
||||||
* @throws MemoryAccessException in case of crossbuilds, the target address cannot be accessed
|
* @throws MemoryAccessException in case of crossbuilds, the target address cannot be accessed
|
||||||
* @throws IOException for errors in during emitting
|
* @throws IOException for errors in during emitting
|
||||||
*/
|
*/
|
||||||
public static List<PcodeOp> buildOps(Language language, ConstructTpl template)
|
public static List<PcodeOp> buildOps(Language language, ConstructTpl template)
|
||||||
throws UnknownInstructionException, MemoryAccessException, IOException {
|
throws UnknownInstructionException, MemoryAccessException, IOException {
|
||||||
|
@ -164,33 +162,31 @@ public class SleighProgramCompiler {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compile the given SLEIGH source into a simple p-code program
|
* Compile the given Sleigh source into a simple p-code program
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* This is suitable for modifying program state using SLEIGH statements. Most likely, in
|
* This is suitable for modifying program state using Sleigh statements. Most likely, in
|
||||||
* scripting, or perhaps in a SLEIGH repl. The library given during compilation must match the
|
* scripting, or perhaps in a Sleigh repl. The library given during compilation must match the
|
||||||
* library given for execution, at least in its binding of userop IDs to symbols.
|
* library given for execution, at least in its binding of userop IDs to symbols.
|
||||||
*
|
*
|
||||||
* @param language the language of the target p-code machine
|
* @param language the language of the target p-code machine
|
||||||
* @param sourceName a diagnostic name for the SLEIGH source
|
* @param sourceName a diagnostic name for the Sleigh source
|
||||||
* @param lines the lines of SLEIGH source. These are joined with line separators but no
|
* @param source the Sleigh source
|
||||||
* semicolon!
|
|
||||||
* @param library the userop library or stub library for binding userop symbols
|
* @param library the userop library or stub library for binding userop symbols
|
||||||
* @return the compiled p-code program
|
* @return the compiled p-code program
|
||||||
*/
|
*/
|
||||||
public static PcodeProgram compileProgram(SleighLanguage language, String sourceName,
|
public static PcodeProgram compileProgram(SleighLanguage language, String sourceName,
|
||||||
List<String> lines, PcodeUseropLibrary<?> library) {
|
String source, PcodeUseropLibrary<?> library) {
|
||||||
PcodeParser parser = createParser(language);
|
PcodeParser parser = createParser(language);
|
||||||
Map<Integer, UserOpSymbol> symbols = library.getSymbols(language);
|
Map<Integer, UserOpSymbol> symbols = library.getSymbols(language);
|
||||||
addParserSymbols(parser, symbols);
|
addParserSymbols(parser, symbols);
|
||||||
|
|
||||||
ConstructTpl template =
|
ConstructTpl template = compileTemplate(language, parser, sourceName, source);
|
||||||
compileTemplate(language, parser, sourceName, StringUtils.join(lines, "\n"));
|
|
||||||
return constructProgram(PcodeProgram::new, language, template, symbols);
|
return constructProgram(PcodeProgram::new, language, template, symbols);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compile the given SLEIGH expression into a p-code program that can evaluate it
|
* Compile the given Sleigh expression into a p-code program that can evaluate it
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* TODO: Currently, expressions cannot be compiled for a user-supplied userop library. The
|
* TODO: Currently, expressions cannot be compiled for a user-supplied userop library. The
|
||||||
|
@ -198,7 +194,7 @@ public class SleighProgramCompiler {
|
||||||
* userop libraries are easily composed. It should be easy to add that feature if needed.
|
* userop libraries are easily composed. It should be easy to add that feature if needed.
|
||||||
*
|
*
|
||||||
* @param language the languge of the target p-code machine
|
* @param language the languge of the target p-code machine
|
||||||
* @param expression the SLEIGH expression to be evaluated
|
* @param expression the Sleigh expression to be evaluated
|
||||||
* @return a p-code program whose {@link PcodeExpression#evaluate(PcodeExecutor)} method will
|
* @return a p-code program whose {@link PcodeExpression#evaluate(PcodeExecutor)} method will
|
||||||
* evaluate the expression on the given executor and its state.
|
* evaluate the expression on the given executor and its state.
|
||||||
*/
|
*/
|
||||||
|
@ -213,7 +209,7 @@ public class SleighProgramCompiler {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a SLEIGH symbol for context when compiling a userop definition
|
* Generate a Sleigh symbol for context when compiling a userop definition
|
||||||
*
|
*
|
||||||
* @param language the language of the target p-code machine
|
* @param language the language of the target p-code machine
|
||||||
* @param sleigh a means of translating address spaces between execution and compilation
|
* @param sleigh a means of translating address spaces between execution and compilation
|
||||||
|
@ -221,7 +217,7 @@ public class SleighProgramCompiler {
|
||||||
* @param opName a diagnostic name for the userop in which this parameter applies
|
* @param opName a diagnostic name for the userop in which this parameter applies
|
||||||
* @param paramName the symbol name for the parameter
|
* @param paramName the symbol name for the parameter
|
||||||
* @param arg the varnode to bind to the parameter symbol
|
* @param arg the varnode to bind to the parameter symbol
|
||||||
* @return the named SLEIGH symbol bound to the given varnode
|
* @return the named Sleigh symbol bound to the given varnode
|
||||||
*/
|
*/
|
||||||
public static VarnodeSymbol paramSym(Language language, SleighBase sleigh, String opName,
|
public static VarnodeSymbol paramSym(Language language, SleighBase sleigh, String opName,
|
||||||
String paramName, Varnode arg) {
|
String paramName, Varnode arg) {
|
||||||
|
@ -232,11 +228,11 @@ public class SleighProgramCompiler {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compile the definition of a p-code userop from SLEIGH source into a p-code program
|
* Compile the definition of a p-code userop from Sleigh source into a p-code program
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* TODO: Defining a userop from SLEIGH source is currently a bit of a hack. It would be nice if
|
* TODO: Defining a userop from Sleigh source is currently a bit of a hack. It would be nice if
|
||||||
* there were a formalization of SLEIGH/p-code subroutines. At the moment, the control flow for
|
* there were a formalization of Sleigh/p-code subroutines. At the moment, the control flow for
|
||||||
* subroutines is handled out of band, which actually works fairly well. However, parameter
|
* subroutines is handled out of band, which actually works fairly well. However, parameter
|
||||||
* passing and returning results is not well defined. The current solution is to alias the
|
* passing and returning results is not well defined. The current solution is to alias the
|
||||||
* parameters to their arguments, implementing a pass-by-reference scheme. Similarly, the output
|
* parameters to their arguments, implementing a pass-by-reference scheme. Similarly, the output
|
||||||
|
@ -256,14 +252,13 @@ public class SleighProgramCompiler {
|
||||||
* @param opName the name of the userop (used only for diagnostics here)
|
* @param opName the name of the userop (used only for diagnostics here)
|
||||||
* @param params the names of parameters in order. Index 0 names the output symbol, probably
|
* @param params the names of parameters in order. Index 0 names the output symbol, probably
|
||||||
* {@link SleighPcodeUseropDefinition#OUT_SYMBOL_NAME}
|
* {@link SleighPcodeUseropDefinition#OUT_SYMBOL_NAME}
|
||||||
* @param lines the lines of SLEIGH source. These are joined with line separators but no
|
* @param source the Sleigh source
|
||||||
* semicolon!
|
|
||||||
* @param library the userop library or stub library for binding userop symbols
|
* @param library the userop library or stub library for binding userop symbols
|
||||||
* @param args the varnode arguments in order. Index 0 is the output varnode.
|
* @param args the varnode arguments in order. Index 0 is the output varnode.
|
||||||
* @return a p-code program that implements the userop for the given arguments
|
* @return a p-code program that implements the userop for the given arguments
|
||||||
*/
|
*/
|
||||||
public static PcodeProgram compileUserop(SleighLanguage language, String opName,
|
public static PcodeProgram compileUserop(SleighLanguage language, String opName,
|
||||||
List<String> params, List<String> lines, PcodeUseropLibrary<?> library,
|
List<String> params, String source, PcodeUseropLibrary<?> library,
|
||||||
List<Varnode> args) {
|
List<Varnode> args) {
|
||||||
PcodeParser parser = createParser(language);
|
PcodeParser parser = createParser(language);
|
||||||
Map<Integer, UserOpSymbol> symbols = library.getSymbols(language);
|
Map<Integer, UserOpSymbol> symbols = library.getSymbols(language);
|
||||||
|
@ -288,7 +283,6 @@ public class SleighProgramCompiler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String source = StringUtils.join(lines, "\n");
|
|
||||||
try {
|
try {
|
||||||
ConstructTpl template = compileTemplate(language, parser, opName, source);
|
ConstructTpl template = compileTemplate(language, parser, opName, source);
|
||||||
return constructProgram(PcodeProgram::new, language, template, symbols);
|
return constructProgram(PcodeProgram::new, language, template, symbols);
|
||||||
|
|
|
@ -79,7 +79,7 @@ abstract class AbstractStmt implements Stmt {
|
||||||
* @param fall the label positioned immediately after this statement in the generated code
|
* @param fall the label positioned immediately after this statement in the generated code
|
||||||
* @return the generated Sleigh code
|
* @return the generated Sleigh code
|
||||||
*/
|
*/
|
||||||
protected abstract String generate(Label next, Label fall);
|
protected abstract StringTree generate(Label next, Label fall);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the statement is or contains a single branch statement
|
* Check if the statement is or contains a single branch statement
|
||||||
|
|
|
@ -49,8 +49,14 @@ class AssignStmt extends AbstractStmt implements RValInternal, StmtWithVal {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String generate(Label next, Label fall) {
|
protected StringTree generate(Label next, Label fall) {
|
||||||
return lhs.generate() + " = " + rhs.generate() + ";\n" + next.genGoto(fall);
|
StringTree st = new StringTree();
|
||||||
|
st.append(lhs.generate());
|
||||||
|
st.append(" = ");
|
||||||
|
st.append(rhs.generate());
|
||||||
|
st.append(";\n");
|
||||||
|
st.append(next.genGoto(fall));
|
||||||
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -49,16 +49,16 @@ class BlockStmt extends AbstractStmt {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String generate(Label next, Label fall) {
|
protected StringTree generate(Label next, Label fall) {
|
||||||
if (children.isEmpty()) {
|
if (children.isEmpty()) {
|
||||||
return next.genGoto(fall);
|
return next.genGoto(fall);
|
||||||
}
|
}
|
||||||
StringBuilder sb = new StringBuilder();
|
StringTree st = new StringTree();
|
||||||
for (AbstractStmt c : children.subList(0, children.size() - 1)) {
|
for (AbstractStmt c : children.subList(0, children.size() - 1)) {
|
||||||
sb.append(c.generate(ctx.FALL, ctx.FALL));
|
st.append(c.generate(ctx.FALL, ctx.FALL));
|
||||||
}
|
}
|
||||||
sb.append(children.get(children.size() - 1).generate(next, fall));
|
st.append(children.get(children.size() - 1).generate(next, fall));
|
||||||
return sb.toString();
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -29,8 +29,14 @@ class DeclStmt extends AbstractStmt {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String generate(Label next, Label fall) {
|
protected StringTree generate(Label next, Label fall) {
|
||||||
return "local " + name + ":" + type.getLength() + ";\n" +
|
StringTree st = new StringTree();
|
||||||
next.genGoto(fall);
|
st.append("local ");
|
||||||
|
st.append(name);
|
||||||
|
st.append(":");
|
||||||
|
st.append(Integer.toString(type.getLength()));
|
||||||
|
st.append(";\n");
|
||||||
|
st.append(next.genGoto(fall));
|
||||||
|
return st;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,23 +29,26 @@ class ForStmt extends LoopStmt {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String generate(Label next, Label fall) {
|
protected StringTree generate(Label next, Label fall) {
|
||||||
Label lTest = ctx.new FreshLabel();
|
Label lTest = ctx.new FreshLabel();
|
||||||
Label lBegin = ctx.new FreshLabel();
|
Label lBegin = ctx.new FreshLabel();
|
||||||
Label lExit = lBreak = next.freshOrBorrow();
|
Label lExit = lBreak = next.freshOrBorrow();
|
||||||
Label lStep = lContinue = ctx.new FreshLabel();
|
Label lStep = lContinue = ctx.new FreshLabel();
|
||||||
|
|
||||||
String initGen = init.generate(lTest, lTest);
|
StringTree initGen = init.generate(lTest, lTest);
|
||||||
String testGen = lExit.genGoto(cond.notb(), lBegin);
|
StringTree testGen = lExit.genGoto(cond.notb(), lBegin);
|
||||||
String stmtGen = stmt.generate(lStep, lStep);
|
StringTree stmtGen = stmt.generate(lStep, lStep);
|
||||||
String stepGen = step.generate(lTest, fall);
|
StringTree stepGen = step.generate(lTest, fall);
|
||||||
return initGen +
|
|
||||||
lTest.genAnchor() +
|
StringTree st = new StringTree();
|
||||||
testGen +
|
st.append(initGen);
|
||||||
lBegin.genAnchor() +
|
st.append(lTest.genAnchor());
|
||||||
stmtGen +
|
st.append(testGen);
|
||||||
lStep.genAnchor() +
|
st.append(lBegin.genAnchor());
|
||||||
stepGen +
|
st.append(stmtGen);
|
||||||
lExit.genAnchor();
|
st.append(lStep.genAnchor());
|
||||||
|
st.append(stepGen);
|
||||||
|
st.append(lExit.genAnchor());
|
||||||
|
return st;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,8 @@ class IfStmt extends ConditionalStmt {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String generate(Label next, Label fall) {
|
protected StringTree generate(Label next, Label fall) {
|
||||||
|
StringTree st = new StringTree();
|
||||||
if (elseStmt == null) {
|
if (elseStmt == null) {
|
||||||
if (stmt.isSingleGoto()) {
|
if (stmt.isSingleGoto()) {
|
||||||
return stmt.getNext().genGoto(cond, fall);
|
return stmt.getNext().genGoto(cond, fall);
|
||||||
|
@ -34,28 +35,31 @@ class IfStmt extends ConditionalStmt {
|
||||||
Label lTrue = ctx.new FreshLabel();
|
Label lTrue = ctx.new FreshLabel();
|
||||||
Label lFalse = next.freshOrBorrow();
|
Label lFalse = next.freshOrBorrow();
|
||||||
|
|
||||||
String condGen = lFalse.genGoto(cond.notb(), lTrue);
|
StringTree condGen = lFalse.genGoto(cond.notb(), lTrue);
|
||||||
String stmtGen = stmt.generate(next, fall);
|
StringTree stmtGen = stmt.generate(next, fall);
|
||||||
return condGen +
|
|
||||||
lTrue.genAnchor() +
|
st.append(condGen);
|
||||||
stmtGen +
|
st.append(lTrue.genAnchor());
|
||||||
lFalse.genAnchor();
|
st.append(stmtGen);
|
||||||
|
st.append(lFalse.genAnchor());
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
Label lFalse = ctx.new FreshLabel();
|
||||||
|
Label lTrue = ctx.new FreshLabel();
|
||||||
|
Label lExit = next.freshOrBorrow();
|
||||||
|
|
||||||
Label lFalse = ctx.new FreshLabel();
|
StringTree condGen = lTrue.genGoto(cond, lFalse);
|
||||||
Label lTrue = ctx.new FreshLabel();
|
StringTree elseGen = elseStmt.generate(lExit, lTrue);
|
||||||
Label lExit = next.freshOrBorrow();
|
StringTree stmtGen = stmt.generate(next, fall);
|
||||||
|
|
||||||
String condGen = lTrue.genGoto(cond, lFalse);
|
st.append(condGen);
|
||||||
String elseGen = elseStmt.generate(lExit, lTrue);
|
st.append(lFalse.genAnchor());
|
||||||
String stmtGen = stmt.generate(next, fall);
|
st.append(elseGen);
|
||||||
|
st.append(lTrue.genAnchor());
|
||||||
return condGen +
|
st.append(stmtGen);
|
||||||
lFalse.genAnchor() +
|
st.append(lExit.genAnchor());
|
||||||
elseGen +
|
}
|
||||||
lTrue.genAnchor() +
|
return st;
|
||||||
stmtGen +
|
|
||||||
lExit.genAnchor();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void addElse(Stmt elseStmt) {
|
protected void addElse(Stmt elseStmt) {
|
||||||
|
|
|
@ -32,7 +32,7 @@ abstract class LoopTruncateStmt extends AbstractStmt {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String generate(Label next, Label fall) {
|
protected StringTree generate(Label next, Label fall) {
|
||||||
return getNext().genGoto(fall);
|
return getNext().genGoto(fall);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,11 @@ class RawStmt extends AbstractStmt {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String generate(Label next, Label fall) {
|
protected StringTree generate(Label next, Label fall) {
|
||||||
return stmt + ";\n" + next.genGoto(fall);
|
StringTree st = new StringTree();
|
||||||
|
st.append(stmt);
|
||||||
|
st.append(";\n");
|
||||||
|
st.append(next.genGoto(fall));
|
||||||
|
return st;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,14 +30,19 @@ class ResultStmt extends AbstractStmt {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String generate(Label next, Label fall) {
|
protected StringTree generate(Label next, Label fall) {
|
||||||
RoutineStmt routine = Objects.requireNonNull(nearest(RoutineStmt.class));
|
RoutineStmt routine = Objects.requireNonNull(nearest(RoutineStmt.class));
|
||||||
|
|
||||||
if (!ctx.isAssignable(routine.retType, result.getType())) {
|
if (!ctx.isAssignable(routine.retType, result.getType())) {
|
||||||
ctx.emitResultTypeMismatch(routine, result);
|
ctx.emitResultTypeMismatch(routine, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SleighPcodeUseropDefinition.OUT_SYMBOL_NAME + " = " + result.generate() + ";\n" +
|
StringTree st = new StringTree();
|
||||||
routine.lReturn.genGoto(fall);
|
st.append(SleighPcodeUseropDefinition.OUT_SYMBOL_NAME);
|
||||||
|
st.append(" = ");
|
||||||
|
st.append(result.generate());
|
||||||
|
st.append(";\n");
|
||||||
|
st.append(routine.lReturn.genGoto(fall));
|
||||||
|
return st;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,11 @@ class ReturnStmt extends AbstractStmt {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String generate(Label next, Label fall) {
|
protected StringTree generate(Label next, Label fall) {
|
||||||
return "return " + target.generate() + ";\n";
|
StringTree st = new StringTree();
|
||||||
|
st.append("return ");
|
||||||
|
st.append(target.generate());
|
||||||
|
st.append(";\n");
|
||||||
|
return st;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,14 +32,17 @@ class RoutineStmt extends BlockStmt {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String generate(Label next, Label fall) {
|
protected StringTree generate(Label next, Label fall) {
|
||||||
if (children.isEmpty()) {
|
if (children.isEmpty()) {
|
||||||
return "";
|
return StringTree.single("");
|
||||||
}
|
}
|
||||||
Label lExit = lReturn = next.freshOrBorrow();
|
Label lExit = lReturn = next.freshOrBorrow();
|
||||||
// This is an odd case, because it's the root: use lExit instead of fall
|
// This is an odd case, because it's the root: use lExit instead of fall
|
||||||
String blockGen = super.generate(lReturn, lExit);
|
StringTree blockGen = super.generate(lReturn, lExit);
|
||||||
return blockGen +
|
|
||||||
lExit.genAnchor();
|
StringTree st = new StringTree();
|
||||||
|
st.append(blockGen);
|
||||||
|
st.append(lExit.genAnchor());
|
||||||
|
return st;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.pcode.struct;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class StringTree {
|
||||||
|
public static StringTree single(CharSequence seq) {
|
||||||
|
StringTree st = new StringTree();
|
||||||
|
st.append(seq);
|
||||||
|
return st;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Node {
|
||||||
|
void walk(StringBuffer buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Branch implements Node {
|
||||||
|
List<Node> children = new LinkedList<>();
|
||||||
|
|
||||||
|
void addChild(Node child) {
|
||||||
|
children.add(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void walk(StringBuffer buf) {
|
||||||
|
for (Node child : children) {
|
||||||
|
child.walk(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Leaf implements Node {
|
||||||
|
final CharSequence seq;
|
||||||
|
|
||||||
|
public Leaf(CharSequence seq) {
|
||||||
|
this.seq = seq;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void walk(StringBuffer buf) {
|
||||||
|
buf.append(seq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Branch root = new Branch();
|
||||||
|
|
||||||
|
public void append(CharSequence seq) {
|
||||||
|
root.addChild(new Leaf(seq));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void append(StringTree tree) {
|
||||||
|
root.addChild(tree.root);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuffer buf = new StringBuffer();
|
||||||
|
root.walk(buf);
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -987,13 +987,14 @@ public class StructuredSleigh {
|
||||||
/**
|
/**
|
||||||
* Generate code for this label
|
* Generate code for this label
|
||||||
*
|
*
|
||||||
|
* <p>
|
||||||
* This must be the last method called on the label, because it relies on knowing whether or
|
* This must be the last method called on the label, because it relies on knowing whether or
|
||||||
* not the label is actually used. (The Sleigh compiler rejects code if it contains unused
|
* not the label is actually used. (The Sleigh compiler rejects code if it contains unused
|
||||||
* labels.)
|
* labels.)
|
||||||
*
|
*
|
||||||
* @return the Sleigh code
|
* @return the Sleigh code
|
||||||
*/
|
*/
|
||||||
abstract String genAnchor();
|
abstract StringTree genAnchor();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a reference to this label as it should appear in a Sleigh "{@code goto}"
|
* Generate a reference to this label as it should appear in a Sleigh "{@code goto}"
|
||||||
|
@ -1001,7 +1002,7 @@ public class StructuredSleigh {
|
||||||
*
|
*
|
||||||
* @return the label's expression
|
* @return the label's expression
|
||||||
*/
|
*/
|
||||||
abstract String ref();
|
abstract StringTree ref();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a goto statement that targets this label
|
* Generate a goto statement that targets this label
|
||||||
|
@ -1009,7 +1010,7 @@ public class StructuredSleigh {
|
||||||
* @param fall the label following the goto
|
* @param fall the label following the goto
|
||||||
* @return the Sleigh code
|
* @return the Sleigh code
|
||||||
*/
|
*/
|
||||||
abstract String genGoto(Label fall);
|
abstract StringTree genGoto(Label fall);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a conditional goto statement that targets this label
|
* Generate a conditional goto statement that targets this label
|
||||||
|
@ -1018,7 +1019,7 @@ public class StructuredSleigh {
|
||||||
* @param fall the label following the goto
|
* @param fall the label following the goto
|
||||||
* @return the Sleigh code
|
* @return the Sleigh code
|
||||||
*/
|
*/
|
||||||
abstract String genGoto(RVal cond, Label fall);
|
abstract StringTree genGoto(RVal cond, Label fall);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1041,32 +1042,49 @@ public class StructuredSleigh {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String genAnchor() {
|
public StringTree genAnchor() {
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
return "";
|
return StringTree.single("");
|
||||||
}
|
}
|
||||||
return "<" + name + ">\n";
|
StringTree st = new StringTree();
|
||||||
|
st.append("<");
|
||||||
|
st.append(name);
|
||||||
|
st.append(">\n");
|
||||||
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String ref() {
|
public StringTree ref() {
|
||||||
return "<" + getName() + ">";
|
StringTree st = new StringTree();
|
||||||
|
st.append("<");
|
||||||
|
st.append(getName());
|
||||||
|
st.append(">");
|
||||||
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String genGoto(Label fall) {
|
public StringTree genGoto(Label fall) {
|
||||||
if (this == fall) {
|
if (this == fall) {
|
||||||
return "";
|
return StringTree.single("");
|
||||||
}
|
}
|
||||||
return "goto " + ref() + ";\n";
|
StringTree st = new StringTree();
|
||||||
|
st.append("goto ");
|
||||||
|
st.append(ref());
|
||||||
|
st.append(";\n");
|
||||||
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String genGoto(RVal cond, Label fall) {
|
public StringTree genGoto(RVal cond, Label fall) {
|
||||||
if (this == fall) {
|
if (this == fall) {
|
||||||
return "";
|
return StringTree.single("");
|
||||||
}
|
}
|
||||||
return "if " + ((RValInternal) cond).generate() + " " + genGoto(fall);
|
StringTree st = new StringTree();
|
||||||
|
st.append("if ");
|
||||||
|
st.append(((RValInternal) cond).generate());
|
||||||
|
st.append(" ");
|
||||||
|
st.append(genGoto(fall));
|
||||||
|
return st;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1091,27 +1109,27 @@ public class StructuredSleigh {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String genAnchor() {
|
public StringTree genAnchor() {
|
||||||
return "";
|
return StringTree.single("");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String ref() {
|
public StringTree ref() {
|
||||||
return borrowed.ref();
|
return borrowed.ref();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String genGoto(Label fall) {
|
public StringTree genGoto(Label fall) {
|
||||||
if (this == fall) { // placed will also check
|
if (this == fall) { // placed will also check
|
||||||
return "";
|
return StringTree.single("");
|
||||||
}
|
}
|
||||||
return borrowed.genGoto(fall);
|
return borrowed.genGoto(fall);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String genGoto(RVal cond, Label fall) {
|
public StringTree genGoto(RVal cond, Label fall) {
|
||||||
if (this == fall) { // placed with also check
|
if (this == fall) { // placed with also check
|
||||||
return "";
|
return StringTree.single("");
|
||||||
}
|
}
|
||||||
return borrowed.genGoto(cond, fall);
|
return borrowed.genGoto(cond, fall);
|
||||||
}
|
}
|
||||||
|
@ -1132,22 +1150,22 @@ public class StructuredSleigh {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String genAnchor() {
|
public StringTree genAnchor() {
|
||||||
return "";
|
return StringTree.single("");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String ref() {
|
public StringTree ref() {
|
||||||
throw new AssertionError();
|
throw new AssertionError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String genGoto(Label fall) {
|
public StringTree genGoto(Label fall) {
|
||||||
return "";
|
return StringTree.single("");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String genGoto(RVal cond, Label fall) {
|
public StringTree genGoto(RVal cond, Label fall) {
|
||||||
throw new AssertionError();
|
throw new AssertionError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1703,8 +1721,8 @@ public class StructuredSleigh {
|
||||||
e);
|
e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
String source = root.generate(FALL, FALL);
|
StringTree source = root.generate(FALL, FALL);
|
||||||
builder.sleigh(source);
|
builder.body(source.toString());
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,8 +43,12 @@ class VoidExprStmt extends AbstractStmt implements RValInternal, StmtWithVal {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String generate(Label next, Label fall) {
|
protected StringTree generate(Label next, Label fall) {
|
||||||
return expr.generate() + ";\n" + next.genGoto(fall);
|
StringTree st = new StringTree();
|
||||||
|
st.append(expr.generate());
|
||||||
|
st.append(";\n");
|
||||||
|
st.append(next.genGoto(fall));
|
||||||
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -23,17 +23,21 @@ class WhileStmt extends LoopStmt {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String generate(Label next, Label fall) {
|
protected StringTree generate(Label next, Label fall) {
|
||||||
Label lTest = lContinue = ctx.new FreshLabel();
|
Label lTest = lContinue = ctx.new FreshLabel();
|
||||||
Label lBegin = ctx.new FreshLabel();
|
Label lBegin = ctx.new FreshLabel();
|
||||||
Label lExit = lBreak = next.freshOrBorrow();
|
Label lExit = lBreak = next.freshOrBorrow();
|
||||||
|
|
||||||
String testGen = lExit.genGoto(cond.notb(), lBegin);
|
StringTree testGen = lExit.genGoto(cond.notb(), lBegin);
|
||||||
String stmtGen = stmt.generate(lTest, fall);
|
StringTree stmtGen = stmt.generate(lTest, fall);
|
||||||
return lTest.genAnchor() +
|
|
||||||
testGen +
|
StringTree st = new StringTree();
|
||||||
lBegin.genAnchor() +
|
|
||||||
stmtGen +
|
st.append(lTest.genAnchor());
|
||||||
lExit.genAnchor();
|
st.append(testGen);
|
||||||
|
st.append(lBegin.genAnchor());
|
||||||
|
st.append(stmtGen);
|
||||||
|
st.append(lExit.genAnchor());
|
||||||
|
return st;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,6 @@ import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.lang.invoke.MethodHandles.Lookup;
|
import java.lang.invoke.MethodHandles.Lookup;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -53,15 +52,15 @@ public class AnnotatedPcodeUseropLibraryTest extends AbstractGhidraHeadlessInteg
|
||||||
}
|
}
|
||||||
|
|
||||||
protected <T> void executeSleigh(PcodeExecutor<T> executor, PcodeUseropLibrary<T> library,
|
protected <T> void executeSleigh(PcodeExecutor<T> executor, PcodeUseropLibrary<T> library,
|
||||||
String... lines) {
|
String source) {
|
||||||
PcodeProgram program = SleighProgramCompiler.compileProgram(executor.getLanguage(), "test",
|
PcodeProgram program = SleighProgramCompiler.compileProgram(executor.getLanguage(), "test",
|
||||||
List.of(lines), library);
|
source, library);
|
||||||
executor.execute(program, library);
|
executor.execute(program, library);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void executeSleigh(PcodeUseropLibrary<byte[]> library, String... lines)
|
protected void executeSleigh(PcodeUseropLibrary<byte[]> library, String source)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
executeSleigh(createBytesExecutor(), library, lines);
|
executeSleigh(createBytesExecutor(), library, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static void assertBytes(long expectedVal, int expectedSize, byte[] actual) {
|
protected static void assertBytes(long expectedVal, int expectedSize, byte[] actual) {
|
||||||
|
|
|
@ -17,8 +17,6 @@ package ghidra.pcode.exec;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -27,26 +25,34 @@ import ghidra.program.model.lang.LanguageID;
|
||||||
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
|
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
|
||||||
|
|
||||||
public class PcodeFrameTest extends AbstractGhidraHeadlessIntegrationTest {
|
public class PcodeFrameTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||||
static final List<String> SAMPLE_ADD = List.of(
|
static final String SAMPLE_ADD = """
|
||||||
"r0 = r0 + r1;");
|
r0 = r0 + r1;
|
||||||
static final List<String> SAMPLE_ADD2 = List.of(
|
""";
|
||||||
"r0 = r0 + r1 + r2;");
|
static final String SAMPLE_ADD2 = """
|
||||||
static final List<String> SAMPLE_IF = List.of(
|
r0 = r0 + r1 + r2;
|
||||||
"if (r0 == r1) goto <skip>;",
|
""";
|
||||||
"r2 = r2 + 1;",
|
static final String SAMPLE_IF = """
|
||||||
"<skip>");
|
if (r0 == r1) goto <skip>;
|
||||||
static final List<String> SAMPLE_LOOP = List.of(
|
r2 = r2 + 1;
|
||||||
"<loop>",
|
<skip>
|
||||||
"r0 = r0 + 1;",
|
""";
|
||||||
"if (r0 == r1) goto <loop>;");
|
static final String SAMPLE_LOOP = """
|
||||||
static final List<String> SAMPLE_BRANCH = List.of(
|
<loop>
|
||||||
"goto 0x1234;");
|
r0 = r0 + 1;
|
||||||
static final List<String> SAMPLE_LOAD = List.of(
|
if (r0 == r1) goto <loop>;
|
||||||
"r0 = *:8 r1;");
|
""";
|
||||||
static final List<String> SAMPLE_LANG_USEROP = List.of(
|
static final String SAMPLE_BRANCH = """
|
||||||
"pcodeop_one(r0);");
|
goto 0x1234;
|
||||||
static final List<String> SAMPLE_LIB_USEROP = List.of(
|
""";
|
||||||
"__lib_userop(r0);");
|
static final String SAMPLE_LOAD = """
|
||||||
|
r0 = *:8 r1;
|
||||||
|
""";
|
||||||
|
static final String SAMPLE_LANG_USEROP = """
|
||||||
|
pcodeop_one(r0);
|
||||||
|
""";
|
||||||
|
static final String SAMPLE_LIB_USEROP = """
|
||||||
|
__lib_userop(r0);
|
||||||
|
""";
|
||||||
|
|
||||||
static class MyLib extends AnnotatedPcodeUseropLibrary<Void> {
|
static class MyLib extends AnnotatedPcodeUseropLibrary<Void> {
|
||||||
@PcodeUserop
|
@PcodeUserop
|
||||||
|
@ -63,11 +69,11 @@ public class PcodeFrameTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||||
(SleighLanguage) getLanguageService().getLanguage(new LanguageID("Toy:BE:64:default"));
|
(SleighLanguage) getLanguageService().getLanguage(new LanguageID("Toy:BE:64:default"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private PcodeProgram compile(List<String> sample) {
|
private PcodeProgram compile(String sample) {
|
||||||
return SleighProgramCompiler.compileProgram(language, getName(), sample, library);
|
return SleighProgramCompiler.compileProgram(language, getName(), sample, library);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PcodeFrame frame(List<String> sample) {
|
private PcodeFrame frame(String sample) {
|
||||||
PcodeProgram program = compile(sample);
|
PcodeProgram program = compile(sample);
|
||||||
return new PcodeFrame(language, program.code, program.useropNames);
|
return new PcodeFrame(language, program.code, program.useropNames);
|
||||||
}
|
}
|
||||||
|
@ -75,172 +81,172 @@ public class PcodeFrameTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||||
@Test
|
@Test
|
||||||
public void testProgramToStringAdd() throws Exception {
|
public void testProgramToStringAdd() throws Exception {
|
||||||
PcodeProgram program = compile(SAMPLE_ADD);
|
PcodeProgram program = compile(SAMPLE_ADD);
|
||||||
assertEquals("" +
|
assertEquals("""
|
||||||
"<PcodeProgram:\n" +
|
<PcodeProgram:
|
||||||
" r0 = INT_ADD r0, r1\n" +
|
r0 = INT_ADD r0, r1
|
||||||
">",
|
>""",
|
||||||
program.toString());
|
program.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProgramToStringAdd2() throws Exception {
|
public void testProgramToStringAdd2() throws Exception {
|
||||||
PcodeProgram program = compile(SAMPLE_ADD2);
|
PcodeProgram program = compile(SAMPLE_ADD2);
|
||||||
assertEquals("" +
|
assertEquals("""
|
||||||
"<PcodeProgram:\n" +
|
<PcodeProgram:
|
||||||
" $U2000:8 = INT_ADD r0, r1\n" +
|
$U2000:8 = INT_ADD r0, r1
|
||||||
" r0 = INT_ADD $U2000:8, r2\n" +
|
r0 = INT_ADD $U2000:8, r2
|
||||||
">",
|
>""",
|
||||||
program.toString());
|
program.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProgramToStringIf() throws Exception {
|
public void testProgramToStringIf() throws Exception {
|
||||||
PcodeProgram program = compile(SAMPLE_IF);
|
PcodeProgram program = compile(SAMPLE_IF);
|
||||||
assertEquals("" +
|
assertEquals("""
|
||||||
"<PcodeProgram:\n" +
|
<PcodeProgram:
|
||||||
" $U2000:1 = INT_EQUAL r0, r1\n" +
|
$U2000:1 = INT_EQUAL r0, r1
|
||||||
" CBRANCH <0>, $U2000:1\n" +
|
CBRANCH <0>, $U2000:1
|
||||||
" r2 = INT_ADD r2, 1:8\n" +
|
r2 = INT_ADD r2, 1:8
|
||||||
"<0>\n" +
|
<0>
|
||||||
">",
|
>""",
|
||||||
program.toString());
|
program.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProgramToStringLoop() throws Exception {
|
public void testProgramToStringLoop() throws Exception {
|
||||||
PcodeProgram program = compile(SAMPLE_LOOP);
|
PcodeProgram program = compile(SAMPLE_LOOP);
|
||||||
assertEquals("" +
|
assertEquals("""
|
||||||
"<PcodeProgram:\n" +
|
<PcodeProgram:
|
||||||
"<0>\n" +
|
<0>
|
||||||
" r0 = INT_ADD r0, 1:8\n" +
|
r0 = INT_ADD r0, 1:8
|
||||||
" $U2080:1 = INT_EQUAL r0, r1\n" +
|
$U2080:1 = INT_EQUAL r0, r1
|
||||||
" CBRANCH <0>, $U2080:1\n" +
|
CBRANCH <0>, $U2080:1
|
||||||
">",
|
>""",
|
||||||
program.toString());
|
program.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProgramToStringLoad() throws Exception {
|
public void testProgramToStringLoad() throws Exception {
|
||||||
PcodeProgram program = compile(SAMPLE_LOAD);
|
PcodeProgram program = compile(SAMPLE_LOAD);
|
||||||
assertEquals("" +
|
assertEquals("""
|
||||||
"<PcodeProgram:\n" +
|
<PcodeProgram:
|
||||||
" r0 = LOAD ram(r1)\n" +
|
r0 = LOAD ram(r1)
|
||||||
">",
|
>""",
|
||||||
program.toString());
|
program.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProgramToStringLangUserop() throws Exception {
|
public void testProgramToStringLangUserop() throws Exception {
|
||||||
PcodeProgram program = compile(SAMPLE_LANG_USEROP);
|
PcodeProgram program = compile(SAMPLE_LANG_USEROP);
|
||||||
assertEquals("" +
|
assertEquals("""
|
||||||
"<PcodeProgram:\n" +
|
<PcodeProgram:
|
||||||
" CALLOTHER \"pcodeop_one\", r0\n" +
|
CALLOTHER "pcodeop_one", r0
|
||||||
">",
|
>""",
|
||||||
program.toString());
|
program.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProgramToStringLibUserop() throws Exception {
|
public void testProgramToStringLibUserop() throws Exception {
|
||||||
PcodeProgram program = compile(SAMPLE_LIB_USEROP);
|
PcodeProgram program = compile(SAMPLE_LIB_USEROP);
|
||||||
assertEquals("" +
|
assertEquals("""
|
||||||
"<PcodeProgram:\n" +
|
<PcodeProgram:
|
||||||
" CALLOTHER \"__lib_userop\", r0\n" +
|
CALLOTHER "__lib_userop", r0
|
||||||
">",
|
>""",
|
||||||
program.toString());
|
program.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFrameToStringAdd() throws Exception {
|
public void testFrameToStringAdd() throws Exception {
|
||||||
PcodeFrame frame = frame(SAMPLE_ADD);
|
PcodeFrame frame = frame(SAMPLE_ADD);
|
||||||
assertEquals("" +
|
assertEquals("""
|
||||||
"<p-code frame: index=0 {\n" +
|
<p-code frame: index=0 {
|
||||||
" -> r0 = INT_ADD r0, r1\n" +
|
-> r0 = INT_ADD r0, r1
|
||||||
"}>",
|
}>""",
|
||||||
frame.toString());
|
frame.toString());
|
||||||
|
|
||||||
frame.advance();
|
frame.advance();
|
||||||
assertEquals("" +
|
assertEquals("""
|
||||||
"<p-code frame: index=1 {\n" +
|
<p-code frame: index=1 {
|
||||||
" r0 = INT_ADD r0, r1\n" +
|
r0 = INT_ADD r0, r1
|
||||||
" *> fall-through\n" +
|
*> fall-through
|
||||||
"}>",
|
}>""",
|
||||||
frame.toString());
|
frame.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFrameToStringIf() throws Exception {
|
public void testFrameToStringIf() throws Exception {
|
||||||
PcodeFrame frame = frame(SAMPLE_IF);
|
PcodeFrame frame = frame(SAMPLE_IF);
|
||||||
assertEquals("" +
|
assertEquals("""
|
||||||
"<p-code frame: index=0 {\n" +
|
<p-code frame: index=0 {
|
||||||
" -> $U2000:1 = INT_EQUAL r0, r1\n" +
|
-> $U2000:1 = INT_EQUAL r0, r1
|
||||||
" CBRANCH <0>, $U2000:1\n" +
|
CBRANCH <0>, $U2000:1
|
||||||
" r2 = INT_ADD r2, 1:8\n" +
|
r2 = INT_ADD r2, 1:8
|
||||||
" <0>\n" +
|
<0>
|
||||||
"}>",
|
}>""",
|
||||||
frame.toString());
|
frame.toString());
|
||||||
|
|
||||||
frame.advance();
|
frame.advance();
|
||||||
frame.advance();
|
frame.advance();
|
||||||
frame.advance();
|
frame.advance();
|
||||||
assertEquals("" +
|
assertEquals("""
|
||||||
"<p-code frame: index=3 {\n" +
|
<p-code frame: index=3 {
|
||||||
" $U2000:1 = INT_EQUAL r0, r1\n" +
|
$U2000:1 = INT_EQUAL r0, r1
|
||||||
" CBRANCH <0>, $U2000:1\n" +
|
CBRANCH <0>, $U2000:1
|
||||||
" r2 = INT_ADD r2, 1:8\n" +
|
r2 = INT_ADD r2, 1:8
|
||||||
" <0>\n" +
|
<0>
|
||||||
" *> fall-through\n" +
|
*> fall-through
|
||||||
"}>",
|
}>""",
|
||||||
frame.toString());
|
frame.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFrameToStringLoop() throws Exception {
|
public void testFrameToStringLoop() throws Exception {
|
||||||
PcodeFrame frame = frame(SAMPLE_LOOP);
|
PcodeFrame frame = frame(SAMPLE_LOOP);
|
||||||
assertEquals("" +
|
assertEquals("""
|
||||||
"<p-code frame: index=0 {\n" +
|
<p-code frame: index=0 {
|
||||||
" <0>\n" +
|
<0>
|
||||||
" -> r0 = INT_ADD r0, 1:8\n" +
|
-> r0 = INT_ADD r0, 1:8
|
||||||
" $U2080:1 = INT_EQUAL r0, r1\n" +
|
$U2080:1 = INT_EQUAL r0, r1
|
||||||
" CBRANCH <0>, $U2080:1\n" +
|
CBRANCH <0>, $U2080:1
|
||||||
"}>",
|
}>""",
|
||||||
frame.toString());
|
frame.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFrameToStringBranch() throws Exception {
|
public void testFrameToStringBranch() throws Exception {
|
||||||
PcodeFrame frame = frame(SAMPLE_BRANCH);
|
PcodeFrame frame = frame(SAMPLE_BRANCH);
|
||||||
assertEquals("" +
|
assertEquals("""
|
||||||
"<p-code frame: index=0 {\n" +
|
<p-code frame: index=0 {
|
||||||
" -> BRANCH *[ram]0x1234:8\n" +
|
-> BRANCH *[ram]0x1234:8
|
||||||
"}>",
|
}>""",
|
||||||
frame.toString());
|
frame.toString());
|
||||||
|
|
||||||
frame.advance();
|
frame.advance();
|
||||||
frame.finishAsBranch();
|
frame.finishAsBranch();
|
||||||
assertEquals("" +
|
assertEquals("""
|
||||||
"<p-code frame: index=-1 branched=0 {\n" +
|
<p-code frame: index=-1 branched=0 {
|
||||||
" *> BRANCH *[ram]0x1234:8\n" +
|
*> BRANCH *[ram]0x1234:8
|
||||||
"}>",
|
}>""",
|
||||||
frame.toString());
|
frame.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFrameToStringLangUserop() throws Exception {
|
public void testFrameToStringLangUserop() throws Exception {
|
||||||
PcodeFrame frame = frame(SAMPLE_LANG_USEROP);
|
PcodeFrame frame = frame(SAMPLE_LANG_USEROP);
|
||||||
assertEquals("" +
|
assertEquals("""
|
||||||
"<p-code frame: index=0 {\n" +
|
<p-code frame: index=0 {
|
||||||
" -> CALLOTHER \"pcodeop_one\", r0\n" +
|
-> CALLOTHER \"pcodeop_one\", r0
|
||||||
"}>",
|
}>""",
|
||||||
frame.toString());
|
frame.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFrameToStringLibUserop() throws Exception {
|
public void testFrameToStringLibUserop() throws Exception {
|
||||||
PcodeFrame frame = frame(SAMPLE_LIB_USEROP);
|
PcodeFrame frame = frame(SAMPLE_LIB_USEROP);
|
||||||
assertEquals("" +
|
assertEquals("""
|
||||||
"<p-code frame: index=0 {\n" +
|
<p-code frame: index=0 {
|
||||||
" -> CALLOTHER \"__lib_userop\", r0\n" +
|
-> CALLOTHER \"__lib_userop\", r0
|
||||||
"}>",
|
}>""",
|
||||||
frame.toString());
|
frame.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@ public class StructuredSleighTest extends AbstractGhidraHeadlessIntegrationTest
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
SleighPcodeUseropDefinition<Object> myUserop = ss.generate().get("my_userop");
|
SleighPcodeUseropDefinition<Object> myUserop = ss.generate().get("my_userop");
|
||||||
assertEquals(List.of("__op_output = (param_1 * 0x2:4);\n"), myUserop.getLines());
|
assertEquals("__op_output = (param_1 * 0x2:4);\n", myUserop.getBody());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = SleighException.class)
|
@Test(expected = SleighException.class)
|
||||||
|
@ -90,7 +90,7 @@ public class StructuredSleighTest extends AbstractGhidraHeadlessIntegrationTest
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
SleighPcodeUseropDefinition<Object> myUserop = ss.generate().get("my_userop");
|
SleighPcodeUseropDefinition<Object> myUserop = ss.generate().get("my_userop");
|
||||||
assertEquals(List.of("__op_output = (r0 * 0x2:4);\n"), myUserop.getLines());
|
assertEquals("__op_output = (r0 * 0x2:4);\n", myUserop.getBody());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -103,10 +103,10 @@ public class StructuredSleighTest extends AbstractGhidraHeadlessIntegrationTest
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
SleighPcodeUseropDefinition<Object> myUserop = ss.generate().get("my_userop");
|
SleighPcodeUseropDefinition<Object> myUserop = ss.generate().get("my_userop");
|
||||||
assertEquals(List.of("" +
|
assertEquals("""
|
||||||
"local my_var:4;\n" +
|
local my_var:4;
|
||||||
"__op_output = (my_var * 0x2:4);\n"),
|
__op_output = (my_var * 0x2:4);
|
||||||
myUserop.getLines());
|
""", myUserop.getBody());
|
||||||
// Verify the source compiles
|
// Verify the source compiles
|
||||||
myUserop.programFor(new Varnode(r0.getAddress(), r0.getNumBytes()), List.of(),
|
myUserop.programFor(new Varnode(r0.getAddress(), r0.getNumBytes()), List.of(),
|
||||||
PcodeUseropLibrary.NIL);
|
PcodeUseropLibrary.NIL);
|
||||||
|
@ -121,7 +121,7 @@ public class StructuredSleighTest extends AbstractGhidraHeadlessIntegrationTest
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
SleighPcodeUseropDefinition<Object> myUserop = ss.generate().get("my_userop");
|
SleighPcodeUseropDefinition<Object> myUserop = ss.generate().get("my_userop");
|
||||||
assertEquals(List.of(""), myUserop.getLines());
|
assertEquals("", myUserop.getBody());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -137,14 +137,14 @@ public class StructuredSleighTest extends AbstractGhidraHeadlessIntegrationTest
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
SleighPcodeUseropDefinition<Object> myUserop = ss.generate().get("my_userop");
|
SleighPcodeUseropDefinition<Object> myUserop = ss.generate().get("my_userop");
|
||||||
assertEquals(List.of("" +
|
assertEquals("""
|
||||||
"if 0x1:1 goto <L1>;\n" +
|
if 0x1:1 goto <L1>;
|
||||||
"tmp = 0x2:4;\n" +
|
tmp = 0x2:4;
|
||||||
"goto <L2>;\n" +
|
goto <L2>;
|
||||||
"<L1>\n" +
|
<L1>
|
||||||
"tmp = 0x1:4;\n" +
|
tmp = 0x1:4;
|
||||||
"<L2>\n"),
|
<L2>
|
||||||
myUserop.getLines());
|
""", myUserop.getBody());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -158,11 +158,11 @@ public class StructuredSleighTest extends AbstractGhidraHeadlessIntegrationTest
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
SleighPcodeUseropDefinition<Object> myUserop = ss.generate().get("my_userop");
|
SleighPcodeUseropDefinition<Object> myUserop = ss.generate().get("my_userop");
|
||||||
assertEquals(List.of("" +
|
assertEquals("""
|
||||||
"if (!0x1:1) goto <L1>;\n" +
|
if (!0x1:1) goto <L1>;
|
||||||
"tmp = 0x1:4;\n" +
|
tmp = 0x1:4;
|
||||||
"<L1>\n"),
|
<L1>
|
||||||
myUserop.getLines());
|
""", myUserop.getBody());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -179,17 +179,18 @@ public class StructuredSleighTest extends AbstractGhidraHeadlessIntegrationTest
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
SleighPcodeUseropDefinition<Object> myUserop = ss.generate().get("my_userop");
|
SleighPcodeUseropDefinition<Object> myUserop = ss.generate().get("my_userop");
|
||||||
assertEquals(List.of("" + "local i:4;\n" +
|
assertEquals("""
|
||||||
"local sum:4;\n" +
|
local i:4;
|
||||||
"i = 0x0:4;\n" +
|
local sum:4;
|
||||||
"<L2>\n" +
|
i = 0x0:4;
|
||||||
"if (i >= n) goto <L1>;\n" +
|
<L2>
|
||||||
"sum = (sum + i);\n" +
|
if (i >= n) goto <L1>;
|
||||||
"i = (i + 0x1:4);\n" +
|
sum = (sum + i);
|
||||||
"goto <L2>;\n" +
|
i = (i + 0x1:4);
|
||||||
"<L1>\n" +
|
goto <L2>;
|
||||||
"__op_output = sum;\n"),
|
<L1>
|
||||||
myUserop.getLines());
|
__op_output = sum;
|
||||||
|
""", myUserop.getBody());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -209,19 +210,19 @@ public class StructuredSleighTest extends AbstractGhidraHeadlessIntegrationTest
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
SleighPcodeUseropDefinition<Object> myUserop = ss.generate().get("my_userop");
|
SleighPcodeUseropDefinition<Object> myUserop = ss.generate().get("my_userop");
|
||||||
assertEquals(List.of("" +
|
assertEquals("""
|
||||||
"local i:4;\n" +
|
local i:4;
|
||||||
"local sum:4;\n" +
|
local sum:4;
|
||||||
"i = 0x0:4;\n" +
|
i = 0x0:4;
|
||||||
"<L2>\n" +
|
<L2>
|
||||||
"if (i >= n) goto <L1>;\n" +
|
if (i >= n) goto <L1>;
|
||||||
"sum = (sum + i);\n" +
|
sum = (sum + i);
|
||||||
"if (sum >= 0x3e8:4) goto <L1>;\n" +
|
if (sum >= 0x3e8:4) goto <L1>;
|
||||||
"i = (i + 0x1:4);\n" +
|
i = (i + 0x1:4);
|
||||||
"goto <L2>;\n" +
|
goto <L2>;
|
||||||
"<L1>\n" +
|
<L1>
|
||||||
"__op_output = sum;\n"),
|
__op_output = sum;
|
||||||
myUserop.getLines());
|
""", myUserop.getBody());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -233,7 +234,7 @@ public class StructuredSleighTest extends AbstractGhidraHeadlessIntegrationTest
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
SleighPcodeUseropDefinition<Object> myUserop = ss.generate().get("my_userop");
|
SleighPcodeUseropDefinition<Object> myUserop = ss.generate().get("my_userop");
|
||||||
assertEquals(List.of("return (* 0xdeadbeef:8);\n"), myUserop.getLines());
|
assertEquals("return (* 0xdeadbeef:8);\n", myUserop.getBody());
|
||||||
// TODO: Test that the generated code compiles in a slaspec file.
|
// TODO: Test that the generated code compiles in a slaspec file.
|
||||||
// It's rejected for injects because "return" is not valid there.
|
// It's rejected for injects because "return" is not valid there.
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ package ghidra.pcode.emu.taint.full;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
@ -105,8 +104,7 @@ public class TaintDebuggerPcodeEmulatorTest extends AbstractGhidraHeadedDebugger
|
||||||
new DefaultTraceLocation(tb.trace, null, Range.atLeast(0L), tb.addr(0x55550000)),
|
new DefaultTraceLocation(tb.trace, null, Range.atLeast(0L), tb.addr(0x55550000)),
|
||||||
new ProgramLocation(program, tb.addr(0x00400000)), 0x1000, false);
|
new ProgramLocation(program, tb.addr(0x00400000)), 0x1000, false);
|
||||||
thread = tb.getOrAddThread("Threads[0]", 0);
|
thread = tb.getOrAddThread("Threads[0]", 0);
|
||||||
tb.exec(0, 0, thread, List.of(
|
tb.exec(0, 0, thread, "RIP = 0x55550000;");
|
||||||
"RIP = 0x55550000;"));
|
|
||||||
}
|
}
|
||||||
waitForDomainObject(tb.trace);
|
waitForDomainObject(tb.trace);
|
||||||
waitForPass(() -> assertEquals(new ProgramLocation(program, tb.addr(0x00400000)),
|
waitForPass(() -> assertEquals(new ProgramLocation(program, tb.addr(0x00400000)),
|
||||||
|
|
|
@ -194,7 +194,7 @@ public class TaintPcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTes
|
||||||
public void testTaintViaSleigh() throws Exception {
|
public void testTaintViaSleigh() throws Exception {
|
||||||
prepareEmulator();
|
prepareEmulator();
|
||||||
PcodeThread<?> thread = launchThread(start);
|
PcodeThread<?> thread = launchThread(start);
|
||||||
thread.getExecutor().executeSleighLine("*:8 0x00400000:8 = taint_arr(*:8 0x004000000:8)");
|
thread.getExecutor().executeSleigh("*:8 0x00400000:8 = taint_arr(*:8 0x004000000:8);");
|
||||||
|
|
||||||
Pair<byte[], TaintVec> taintVal =
|
Pair<byte[], TaintVec> taintVal =
|
||||||
emulator.getSharedState().getVar(space, 0x00400000, 8, true);
|
emulator.getSharedState().getVar(space, 0x00400000, 8, true);
|
||||||
|
|
|
@ -63,7 +63,7 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
@Test
|
@Test
|
||||||
public void testReadStateMemory() throws Throwable {
|
public void testReadStateMemory() throws Throwable {
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||||
TraceThread thread = initTrace(tb, List.of(), List.of());
|
TraceThread thread = initTrace(tb, "", List.of());
|
||||||
|
|
||||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||||
TracePropertyMap<String> taintMap = tb.trace.getAddressPropertyManager()
|
TracePropertyMap<String> taintMap = tb.trace.getAddressPropertyManager()
|
||||||
|
@ -73,7 +73,7 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
|
|
||||||
TaintTracePcodeEmulator emu = new TaintTracePcodeEmulator(tb.trace, 0);
|
TaintTracePcodeEmulator emu = new TaintTracePcodeEmulator(tb.trace, 0);
|
||||||
PcodeThread<Pair<byte[], TaintVec>> emuThread = emu.newThread(thread.getPath());
|
PcodeThread<Pair<byte[], TaintVec>> emuThread = emu.newThread(thread.getPath());
|
||||||
emuThread.getExecutor().executeSleighLine("RAX = *0x00400000:8");
|
emuThread.getExecutor().executeSleigh("RAX = *0x00400000:8;");
|
||||||
|
|
||||||
Pair<byte[], TaintVec> valRAX =
|
Pair<byte[], TaintVec> valRAX =
|
||||||
emuThread.getState().getVar(tb.language.getRegister("RAX"));
|
emuThread.getState().getVar(tb.language.getRegister("RAX"));
|
||||||
|
@ -89,7 +89,7 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
@Test
|
@Test
|
||||||
public void testReadStateRegister() throws Throwable {
|
public void testReadStateRegister() throws Throwable {
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||||
TraceThread thread = initTrace(tb, List.of(), List.of());
|
TraceThread thread = initTrace(tb, "", List.of());
|
||||||
Register regRAX = tb.language.getRegister("RAX");
|
Register regRAX = tb.language.getRegister("RAX");
|
||||||
Register regEBX = tb.language.getRegister("EBX");
|
Register regEBX = tb.language.getRegister("EBX");
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
|
|
||||||
TaintTracePcodeEmulator emu = new TaintTracePcodeEmulator(tb.trace, 0);
|
TaintTracePcodeEmulator emu = new TaintTracePcodeEmulator(tb.trace, 0);
|
||||||
PcodeThread<Pair<byte[], TaintVec>> emuThread = emu.newThread(thread.getPath());
|
PcodeThread<Pair<byte[], TaintVec>> emuThread = emu.newThread(thread.getPath());
|
||||||
emuThread.getExecutor().executeSleighLine("RAX = RBX");
|
emuThread.getExecutor().executeSleigh("RAX = RBX;");
|
||||||
|
|
||||||
Pair<byte[], TaintVec> valRAX =
|
Pair<byte[], TaintVec> valRAX =
|
||||||
emuThread.getState().getVar(regRAX);
|
emuThread.getState().getVar(regRAX);
|
||||||
|
@ -119,7 +119,7 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
@Test
|
@Test
|
||||||
public void testWriteStateMemory() throws Throwable {
|
public void testWriteStateMemory() throws Throwable {
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||||
initTrace(tb, List.of(), List.of());
|
initTrace(tb, "", List.of());
|
||||||
|
|
||||||
TaintTracePcodeEmulator emu = new TaintTracePcodeEmulator(tb.trace, 0);
|
TaintTracePcodeEmulator emu = new TaintTracePcodeEmulator(tb.trace, 0);
|
||||||
TaintVec taintVal = TaintVec.empties(8);
|
TaintVec taintVal = TaintVec.empties(8);
|
||||||
|
@ -146,7 +146,7 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
public void testWriteStateRegister() throws Throwable {
|
public void testWriteStateRegister() throws Throwable {
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||||
AddressSpace rs = tb.language.getAddressFactory().getRegisterSpace();
|
AddressSpace rs = tb.language.getAddressFactory().getRegisterSpace();
|
||||||
TraceThread thread = initTrace(tb, List.of(), List.of());
|
TraceThread thread = initTrace(tb, "", List.of());
|
||||||
|
|
||||||
TaintTracePcodeEmulator emu = new TaintTracePcodeEmulator(tb.trace, 0);
|
TaintTracePcodeEmulator emu = new TaintTracePcodeEmulator(tb.trace, 0);
|
||||||
PcodeThread<Pair<byte[], TaintVec>> emuThread = emu.newThread(thread.getPath());
|
PcodeThread<Pair<byte[], TaintVec>> emuThread = emu.newThread(thread.getPath());
|
||||||
|
@ -176,9 +176,9 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
public void testEmptyTaintClears() throws Throwable {
|
public void testEmptyTaintClears() throws Throwable {
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||||
AddressSpace ram = tb.language.getAddressFactory().getDefaultAddressSpace();
|
AddressSpace ram = tb.language.getAddressFactory().getDefaultAddressSpace();
|
||||||
TraceThread thread = initTrace(tb,
|
TraceThread thread = initTrace(tb, """
|
||||||
List.of(
|
RIP = 0x00400000;
|
||||||
"RIP = 0x00400000;"),
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
"MOV qword ptr [0x00600000], RAX",
|
"MOV qword ptr [0x00600000], RAX",
|
||||||
"MOV qword ptr [0x00600000], RBX"));
|
"MOV qword ptr [0x00600000], RBX"));
|
||||||
|
@ -214,9 +214,9 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
@Test
|
@Test
|
||||||
public void testZeroByXor() throws Throwable {
|
public void testZeroByXor() throws Throwable {
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||||
TraceThread thread = initTrace(tb,
|
TraceThread thread = initTrace(tb, """
|
||||||
List.of(
|
RIP = 0x00400000;
|
||||||
"RIP = 0x00400000;"),
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
"XOR RAX, RAX"));
|
"XOR RAX, RAX"));
|
||||||
|
|
||||||
|
@ -245,9 +245,9 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||||
@Test
|
@Test
|
||||||
public void testZeroByXorVia32() throws Throwable {
|
public void testZeroByXorVia32() throws Throwable {
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||||
TraceThread thread = initTrace(tb,
|
TraceThread thread = initTrace(tb, """
|
||||||
List.of(
|
RIP = 0x00400000;
|
||||||
"RIP = 0x00400000;"),
|
""",
|
||||||
List.of(
|
List.of(
|
||||||
"XOR EAX, EAX"));
|
"XOR EAX, EAX"));
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue