mirror of
https://github.com/NationalSecurityAgency/ghidra
synced 2024-08-28 05:20:21 +00:00
Merge remote-tracking branch 'origin/GP-2467_Dan_SleighProgramCompiler-textBlock--SQUASHED'
This commit is contained in:
commit
b951224fce
|
@ -24,7 +24,6 @@
|
|||
//@toolbar
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.plugin.assembler.Assembler;
|
||||
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
|
||||
* invoke it.
|
||||
*/
|
||||
emulator.inject(injectHere, List.of(
|
||||
"print_utf8(RCX);",
|
||||
"emu_exec_decoded();"));
|
||||
emulator.inject(injectHere, """
|
||||
print_utf8(RCX);
|
||||
emu_exec_decoded();
|
||||
""");
|
||||
|
||||
/*
|
||||
* Run the experiment: This should interrupt on the second SYSCALL, because any value other
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
//@toolbar
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.plugin.assembler.*;
|
||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||
|
@ -102,10 +101,10 @@ public class StandAloneEmuExampleScript extends GhidraScript {
|
|||
*/
|
||||
byte[] hw = "Hello, World!\n".getBytes(UTF8);
|
||||
emulator.getSharedState().setVar(dyn, 0xdeadbeefL, hw.length, true, hw);
|
||||
PcodeProgram init = SleighProgramCompiler.compileProgram(language, "init", List.of(
|
||||
"RIP = 0x" + entry + ";",
|
||||
"RSP = 0x00001000;"),
|
||||
library);
|
||||
PcodeProgram init = SleighProgramCompiler.compileProgram(language, "init", String.format("""
|
||||
RIP = 0x%s;
|
||||
RSP = 0x00001000;
|
||||
""", entry), library);
|
||||
thread.getExecutor().execute(init, library);
|
||||
thread.overrideContextWithDefault();
|
||||
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
|
||||
* invoke it.
|
||||
*/
|
||||
emulator.inject(injectHere, List.of(
|
||||
"print_utf8(RCX);",
|
||||
"emu_exec_decoded();"));
|
||||
emulator.inject(injectHere, """
|
||||
print_utf8(RCX);
|
||||
emu_exec_decoded();
|
||||
""");
|
||||
|
||||
/*
|
||||
* 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.getInputs().stream().collect(Collectors.joining(",")));
|
||||
print(") {\n");
|
||||
for (String line : userop.getLines()) {
|
||||
print(line);
|
||||
}
|
||||
print(userop.getBody());
|
||||
print("}\n\n");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
//@toolbar
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.plugin.assembler.Assembler;
|
||||
import ghidra.app.plugin.assembler.Assemblers;
|
||||
|
@ -184,10 +183,11 @@ public class StandAloneSyscallEmuExampleScript extends GhidraScript {
|
|||
/*
|
||||
* Initialize the thread
|
||||
*/
|
||||
PcodeProgram init = SleighProgramCompiler.compileProgram(language, "init", List.of(
|
||||
"RIP = 0x" + entry + ";",
|
||||
"RSP = 0x00001000;"),
|
||||
library);
|
||||
PcodeProgram init =
|
||||
SleighProgramCompiler.compileProgram(language, "init", String.format("""
|
||||
RIP = 0x%s;
|
||||
RSP = 0x00001000;
|
||||
""", entry), library);
|
||||
thread.getExecutor().execute(init, library);
|
||||
thread.overrideContextWithDefault();
|
||||
thread.reInitialize();
|
||||
|
|
|
@ -69,8 +69,10 @@ public class DebuggerPcodeStepperPluginScreenShots extends GhidraScreenShotGener
|
|||
|
||||
PcodeExecutor<byte[]> exe =
|
||||
TraceSleighUtils.buildByteExecutor(tb.trace, snap0, thread, 0);
|
||||
exe.executeSleighLine("RIP = 0x00400000");
|
||||
exe.executeSleighLine("RSP = 0x0010fff8");
|
||||
exe.executeSleigh("""
|
||||
RIP = 0x00400000;
|
||||
RSP = 0x0010fff8;
|
||||
""");
|
||||
|
||||
Assembler asm = Assemblers.getAssembler(tb.trace.getFixedProgramView(snap0));
|
||||
asm.assemble(tb.addr(0x00400000), "SUB RSP,0x40");
|
||||
|
|
|
@ -69,14 +69,18 @@ public class DebuggerWatchesPluginScreenShots extends GhidraScreenShotGenerator
|
|||
|
||||
PcodeExecutor<byte[]> executor0 =
|
||||
TraceSleighUtils.buildByteExecutor(tb.trace, snap0, thread, 0);
|
||||
executor0.executeSleighLine("RSP = 0x7ffefff8");
|
||||
executor0.executeSleighLine("*:4 (RSP+8) = 0x4030201");
|
||||
executor0.executeSleigh("""
|
||||
RSP = 0x7ffefff8;
|
||||
*:4 (RSP+8) = 0x4030201;
|
||||
""");
|
||||
|
||||
PcodeExecutor<byte[]> executor1 =
|
||||
TraceSleighUtils.buildByteExecutor(tb.trace, snap1, thread, 0);
|
||||
executor1.executeSleighLine("RSP = 0x7ffefff8");
|
||||
executor1.executeSleighLine("*:4 (RSP+8) = 0x1020304");
|
||||
executor1.executeSleighLine("*:4 0x7fff0004:8 = 0x4A9A70C8");
|
||||
executor1.executeSleigh("""
|
||||
RSP = 0x7ffefff8;
|
||||
*:4 (RSP+8) = 0x1020304;
|
||||
*:4 0x7fff0004:8 = 0x4A9A70C8;
|
||||
""");
|
||||
}
|
||||
|
||||
watchesProvider.addWatch("RSP");
|
||||
|
|
|
@ -134,11 +134,12 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
|||
});
|
||||
}
|
||||
|
||||
protected TraceRecorder addMappedBreakpointOpenAndWait() throws Exception {
|
||||
protected TraceRecorder addMappedBreakpointOpenAndWait() throws Throwable {
|
||||
createTestModel();
|
||||
mb.createTestProcessesAndThreads();
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
createTargetTraceMapper(mb.testProcess1), ActionSource.AUTOMATIC);
|
||||
waitRecorder(recorder);
|
||||
Trace trace = recorder.getTrace();
|
||||
createProgramFromTrace(trace);
|
||||
intoProject(trace);
|
||||
|
@ -260,7 +261,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
|||
Set.of("SW_EXECUTE", "HW_EXECUTE", "READ,WRITE", "READ", "WRITE");
|
||||
|
||||
@Test
|
||||
public void testProgramNoBreakPopupMenus() throws Exception {
|
||||
public void testProgramNoBreakPopupMenus() throws Throwable {
|
||||
// NOTE: Need a target to have any breakpoint actions, even on programs
|
||||
addMappedBreakpointOpenAndWait();
|
||||
|
||||
|
@ -276,7 +277,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testTraceNoBreakPopupMenus() throws Exception {
|
||||
public void testTraceNoBreakPopupMenus() throws Throwable {
|
||||
TraceRecorder recorder = addMappedBreakpointOpenAndWait();
|
||||
Trace trace = recorder.getTrace();
|
||||
traceManager.activateTrace(trace);
|
||||
|
@ -414,7 +415,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
|||
|
||||
@Test
|
||||
public void testActionToggleBreakpointProgramWithNoCurrentBreakpointOnInstruction()
|
||||
throws Exception {
|
||||
throws Throwable {
|
||||
addMappedBreakpointOpenAndWait(); // wasteful, but whatever
|
||||
for (LogicalBreakpoint lb : List.copyOf(breakpointService.getAllBreakpoints())) {
|
||||
lb.delete();
|
||||
|
@ -442,7 +443,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testActionToggleBreakpointProgramWithNoCurrentBreakpointOnData() throws Exception {
|
||||
public void testActionToggleBreakpointProgramWithNoCurrentBreakpointOnData() throws Throwable {
|
||||
addMappedBreakpointOpenAndWait(); // wasteful, but whatever
|
||||
for (LogicalBreakpoint lb : List.copyOf(breakpointService.getAllBreakpoints())) {
|
||||
lb.delete();
|
||||
|
@ -470,7 +471,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testActionToggleBreakpointProgram() throws Exception {
|
||||
public void testActionToggleBreakpointProgram() throws Throwable {
|
||||
addMappedBreakpointOpenAndWait();
|
||||
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
|
||||
|
||||
|
@ -486,7 +487,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testActionToggleBreakpointTrace() throws Exception {
|
||||
public void testActionToggleBreakpointTrace() throws Throwable {
|
||||
TraceRecorder recorder = addMappedBreakpointOpenAndWait();
|
||||
Trace trace = recorder.getTrace();
|
||||
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
|
||||
|
@ -527,14 +528,16 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
|||
}
|
||||
|
||||
protected void testActionSetBreakpointProgram(DockingAction action,
|
||||
Set<TraceBreakpointKind> expectedKinds) throws Exception {
|
||||
Set<TraceBreakpointKind> expectedKinds) throws Throwable {
|
||||
addMappedBreakpointOpenAndWait(); // Adds an unneeded breakpoint. Aw well.
|
||||
|
||||
performAction(action, staticCtx(addr(program, 0x0400321)), false);
|
||||
DebuggerPlaceBreakpointDialog dialog =
|
||||
waitForDialogComponent(DebuggerPlaceBreakpointDialog.class);
|
||||
dialog.setName("Test name");
|
||||
runSwing(() -> dialog.okCallback());
|
||||
runSwing(() -> {
|
||||
dialog.setName("Test name");
|
||||
dialog.okCallback();
|
||||
});
|
||||
|
||||
waitForPass(() -> {
|
||||
LogicalBreakpoint lb = Unique.assertOne(
|
||||
|
@ -546,7 +549,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
|||
}
|
||||
|
||||
protected void testActionSetBreakpointTrace(DockingAction action,
|
||||
Set<TraceBreakpointKind> expectedKinds) throws Exception {
|
||||
Set<TraceBreakpointKind> expectedKinds) throws Throwable {
|
||||
TraceRecorder recorder = addMappedBreakpointOpenAndWait(); // Adds an unneeded breakpoint. Aw well.
|
||||
Trace trace = recorder.getTrace();
|
||||
|
||||
|
@ -568,67 +571,67 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testActionSetSoftwareBreakpointProgram() throws Exception {
|
||||
public void testActionSetSoftwareBreakpointProgram() throws Throwable {
|
||||
testActionSetBreakpointProgram(breakpointMarkerPlugin.actionSetSoftwareBreakpoint,
|
||||
Set.of(TraceBreakpointKind.SW_EXECUTE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionSetSoftwareBreakpointTrace() throws Exception {
|
||||
public void testActionSetSoftwareBreakpointTrace() throws Throwable {
|
||||
testActionSetBreakpointTrace(breakpointMarkerPlugin.actionSetSoftwareBreakpoint,
|
||||
Set.of(TraceBreakpointKind.SW_EXECUTE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionSetExecuteBreakpointProgram() throws Exception {
|
||||
public void testActionSetExecuteBreakpointProgram() throws Throwable {
|
||||
testActionSetBreakpointProgram(breakpointMarkerPlugin.actionSetExecuteBreakpoint,
|
||||
Set.of(TraceBreakpointKind.HW_EXECUTE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionSetExecuteBreakpointTrace() throws Exception {
|
||||
public void testActionSetExecuteBreakpointTrace() throws Throwable {
|
||||
testActionSetBreakpointTrace(breakpointMarkerPlugin.actionSetExecuteBreakpoint,
|
||||
Set.of(TraceBreakpointKind.HW_EXECUTE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionSetReadWriteBreakpointProgram() throws Exception {
|
||||
public void testActionSetReadWriteBreakpointProgram() throws Throwable {
|
||||
testActionSetBreakpointProgram(breakpointMarkerPlugin.actionSetReadWriteBreakpoint,
|
||||
Set.of(TraceBreakpointKind.READ, TraceBreakpointKind.WRITE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionSetReadWriteBreakpointTrace() throws Exception {
|
||||
public void testActionSetReadWriteBreakpointTrace() throws Throwable {
|
||||
testActionSetBreakpointTrace(breakpointMarkerPlugin.actionSetReadWriteBreakpoint,
|
||||
Set.of(TraceBreakpointKind.READ, TraceBreakpointKind.WRITE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionSetReadBreakpointProgram() throws Exception {
|
||||
public void testActionSetReadBreakpointProgram() throws Throwable {
|
||||
testActionSetBreakpointProgram(breakpointMarkerPlugin.actionSetReadBreakpoint,
|
||||
Set.of(TraceBreakpointKind.READ));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionSetReadBreakpointTrace() throws Exception {
|
||||
public void testActionSetReadBreakpointTrace() throws Throwable {
|
||||
testActionSetBreakpointTrace(breakpointMarkerPlugin.actionSetReadBreakpoint,
|
||||
Set.of(TraceBreakpointKind.READ));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionSetWriteBreakpointProgram() throws Exception {
|
||||
public void testActionSetWriteBreakpointProgram() throws Throwable {
|
||||
testActionSetBreakpointProgram(breakpointMarkerPlugin.actionSetWriteBreakpoint,
|
||||
Set.of(TraceBreakpointKind.WRITE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionSetWriteBreakpointTrace() throws Exception {
|
||||
public void testActionSetWriteBreakpointTrace() throws Throwable {
|
||||
testActionSetBreakpointTrace(breakpointMarkerPlugin.actionSetWriteBreakpoint,
|
||||
Set.of(TraceBreakpointKind.WRITE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionEnableBreakpointProgram() throws Exception {
|
||||
public void testActionEnableBreakpointProgram() throws Throwable {
|
||||
addMappedBreakpointOpenAndWait();
|
||||
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
|
||||
lb.disable();
|
||||
|
@ -641,7 +644,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testActionEnableBreakpointTrace() throws Exception {
|
||||
public void testActionEnableBreakpointTrace() throws Throwable {
|
||||
TraceRecorder recorder = addMappedBreakpointOpenAndWait();
|
||||
Trace trace = recorder.getTrace();
|
||||
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
|
||||
|
@ -656,7 +659,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testActionDisableBreakpointProgram() throws Exception {
|
||||
public void testActionDisableBreakpointProgram() throws Throwable {
|
||||
addMappedBreakpointOpenAndWait();
|
||||
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
|
||||
|
||||
|
@ -667,7 +670,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testActionDisableBreakpointTrace() throws Exception {
|
||||
public void testActionDisableBreakpointTrace() throws Throwable {
|
||||
TraceRecorder recorder = addMappedBreakpointOpenAndWait();
|
||||
Trace trace = recorder.getTrace();
|
||||
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
|
||||
|
@ -680,7 +683,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testActionClearBreakpointProgram() throws Exception {
|
||||
public void testActionClearBreakpointProgram() throws Throwable {
|
||||
addMappedBreakpointOpenAndWait();
|
||||
|
||||
performAction(breakpointMarkerPlugin.actionClearBreakpoint,
|
||||
|
@ -690,7 +693,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testActionClearBreakpointTrace() throws Exception {
|
||||
public void testActionClearBreakpointTrace() throws Throwable {
|
||||
TraceRecorder recorder = addMappedBreakpointOpenAndWait();
|
||||
Trace trace = recorder.getTrace();
|
||||
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
|
||||
|
|
|
@ -1269,7 +1269,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
.createRegion(".text", 0, tb.range(0x00400000, 0x0040ffff),
|
||||
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
|
||||
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;
|
||||
|
@ -1279,7 +1279,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
.createRegion(".text", 0, tb2.range(0x200, 0x3ff), TraceMemoryFlag.READ,
|
||||
TraceMemoryFlag.EXECUTE);
|
||||
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);
|
||||
|
|
|
@ -82,7 +82,7 @@ public class DebuggerPcodeStepperProviderTest extends AbstractGhidraHeadedDebugg
|
|||
thread = tb.getOrAddThread("1", 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));
|
||||
iit = asm.assemble(start,
|
||||
|
@ -166,7 +166,7 @@ public class DebuggerPcodeStepperProviderTest extends AbstractGhidraHeadedDebugg
|
|||
.anyMatch(r -> r.getCode().contains("emu_swi"))));
|
||||
}
|
||||
|
||||
protected List<PcodeRow> format(List<String> sleigh) {
|
||||
protected List<PcodeRow> format(String sleigh) {
|
||||
SleighLanguage language = (SleighLanguage) getToyBE64Language();
|
||||
PcodeProgram prog = SleighProgramCompiler.compileProgram(language, "test", sleigh,
|
||||
PcodeUseropLibrary.nil());
|
||||
|
@ -179,7 +179,7 @@ public class DebuggerPcodeStepperProviderTest extends AbstractGhidraHeadedDebugg
|
|||
|
||||
@Test
|
||||
public void testPcodeFormatterSimple() {
|
||||
List<PcodeRow> rows = format(List.of("r0 = 1;"));
|
||||
List<PcodeRow> rows = format("r0 = 1;");
|
||||
assertEquals(2, rows.size());
|
||||
assertEquals("<html></html>", rows.get(0).getLabel());
|
||||
assertEquals(FallthroughPcodeRow.class, rows.get(1).getClass());
|
||||
|
@ -187,9 +187,10 @@ public class DebuggerPcodeStepperProviderTest extends AbstractGhidraHeadedDebugg
|
|||
|
||||
@Test
|
||||
public void testPcodeFormatterStartsLabel() {
|
||||
List<PcodeRow> rows = format(List.of(
|
||||
"<L0> r0 = 1;",
|
||||
"goto <L0>;"));
|
||||
List<PcodeRow> rows = format("""
|
||||
<L0> r0 = 1;
|
||||
goto <L0>;
|
||||
""");
|
||||
assertEquals(3, rows.size());
|
||||
assertEquals("<html><span class=\"lab\"><0></span></html>", rows.get(0).getLabel());
|
||||
assertEquals("<html></html>", rows.get(1).getLabel());
|
||||
|
@ -198,10 +199,11 @@ public class DebuggerPcodeStepperProviderTest extends AbstractGhidraHeadedDebugg
|
|||
|
||||
@Test
|
||||
public void testPcodeFormatterMiddleLabel() {
|
||||
List<PcodeRow> rows = format(List.of(
|
||||
"if 1:1 goto <SKIP>;",
|
||||
"r0 = 1;",
|
||||
"<SKIP> r1 = 2;"));
|
||||
List<PcodeRow> rows = format("""
|
||||
if 1:1 goto <SKIP>;
|
||||
r0 = 1;
|
||||
<SKIP> r1 = 2;
|
||||
""");
|
||||
assertEquals(4, rows.size());
|
||||
assertEquals("<html></html>", rows.get(0).getLabel());
|
||||
assertEquals("<html></html>", rows.get(1).getLabel());
|
||||
|
@ -211,10 +213,11 @@ public class DebuggerPcodeStepperProviderTest extends AbstractGhidraHeadedDebugg
|
|||
|
||||
@Test
|
||||
public void testPcodeFormatterFallthroughLabel() {
|
||||
List<PcodeRow> rows = format(List.of(
|
||||
"if 1:1 goto <SKIP>;",
|
||||
"r0 = 1;",
|
||||
"<SKIP>"));
|
||||
List<PcodeRow> rows = format("""
|
||||
if 1:1 goto <SKIP>;
|
||||
r0 = 1;
|
||||
<SKIP>
|
||||
""");
|
||||
assertEquals(3, rows.size());
|
||||
assertEquals("<html></html>", rows.get(0).getLabel());
|
||||
assertEquals("<html></html>", rows.get(1).getLabel());
|
||||
|
@ -224,12 +227,13 @@ public class DebuggerPcodeStepperProviderTest extends AbstractGhidraHeadedDebugg
|
|||
|
||||
@Test
|
||||
public void testPcodeFormatterManyLabel() {
|
||||
List<PcodeRow> rows = format(List.of(
|
||||
"<L0> goto <L1>;",
|
||||
"<L1> goto <L2>;",
|
||||
"<L2> goto <L3>;",
|
||||
"goto <L0>;",
|
||||
"<L3>"));
|
||||
List<PcodeRow> rows = format("""
|
||||
<L0> goto <L1>;
|
||||
<L1> goto <L2>;
|
||||
<L2> goto <L3>;
|
||||
goto <L0>;
|
||||
<L3>
|
||||
""");
|
||||
assertEquals(5, rows.size());
|
||||
// NB. templates number labels in order of appearance in BRANCHes
|
||||
assertEquals("<html><span class=\"lab\"><3></span></html>", rows.get(0).getLabel());
|
||||
|
|
|
@ -469,7 +469,7 @@ public class DebuggerRegistersProviderTest extends AbstractGhidraHeadedDebuggerG
|
|||
|
||||
TraceThread thread = addThread();
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
tb.exec(0, 0, thread, List.of("pc = 100;"));
|
||||
tb.exec(0, 0, thread, "pc = 100;");
|
||||
}
|
||||
traceManager.activateThread(thread);
|
||||
waitForSwing();
|
||||
|
@ -800,10 +800,11 @@ public class DebuggerRegistersProviderTest extends AbstractGhidraHeadedDebuggerG
|
|||
modelData.stream().filter(r -> r.getRegister() == pc).findFirst().orElse(null);
|
||||
assertNotNull(pcAvail);
|
||||
|
||||
pcAvail.setSelected(false);
|
||||
dialog.availableTableModel.fireTableDataChanged();
|
||||
dialog.okCallback();
|
||||
waitForSwing();
|
||||
runSwing(() -> {
|
||||
pcAvail.setSelected(false);
|
||||
dialog.availableTableModel.fireTableDataChanged();
|
||||
dialog.okCallback();
|
||||
});
|
||||
|
||||
assertNull(getRegisterRow(pc));
|
||||
assertTrue(registersProvider.actionSelectRegisters.isEnabled());
|
||||
|
|
|
@ -148,7 +148,7 @@ public class DebuggerStateEditingServiceTest extends AbstractGhidraHeadedDebugge
|
|||
|
||||
Assembler asm = Assemblers.getAssembler(tb.trace.getFixedProgramView(0));
|
||||
asm.assemble(tb.addr(0x00400000), "imm r0,#123");
|
||||
executor.executeSleighLine("pc = 0x00400000");
|
||||
executor.executeSleigh("pc = 0x00400000;");
|
||||
}
|
||||
traceManager.activateTrace(tb.trace);
|
||||
editingService.setCurrentMode(tb.trace, StateEditingMode.WRITE_EMULATOR);
|
||||
|
@ -186,7 +186,7 @@ public class DebuggerStateEditingServiceTest extends AbstractGhidraHeadedDebugge
|
|||
|
||||
Assembler asm = Assemblers.getAssembler(tb.trace.getFixedProgramView(0));
|
||||
asm.assemble(tb.addr(0x00400000), "imm r0,#123");
|
||||
executor.executeSleighLine("pc = 0x00400000");
|
||||
executor.executeSleigh("pc = 0x00400000;");
|
||||
}
|
||||
traceManager.activateTrace(tb.trace);
|
||||
editingService.setCurrentMode(tb.trace, StateEditingMode.WRITE_EMULATOR);
|
||||
|
|
|
@ -337,7 +337,7 @@ public class DebuggerTraceManagerServiceTest extends AbstractGhidraHeadedDebugge
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testAutoActivatePresent() throws Exception {
|
||||
public void testAutoActivatePresent() throws Throwable {
|
||||
assertTrue(traceManager.isAutoActivatePresent());
|
||||
|
||||
createTestModel();
|
||||
|
@ -345,6 +345,7 @@ public class DebuggerTraceManagerServiceTest extends AbstractGhidraHeadedDebugge
|
|||
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
createTargetTraceMapper(mb.testProcess1), ActionSource.AUTOMATIC);
|
||||
waitRecorder(recorder);
|
||||
Trace trace = recorder.getTrace();
|
||||
|
||||
traceManager.openTrace(trace);
|
||||
|
|
|
@ -18,7 +18,6 @@ package ghidra.pcode.exec;
|
|||
import static org.junit.Assert.*;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
@ -29,7 +28,6 @@ import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
|||
import ghidra.app.services.ActionSource;
|
||||
import ghidra.app.services.TraceRecorder;
|
||||
import ghidra.dbg.model.TestTargetRegisterBankInThread;
|
||||
import ghidra.pcode.exec.*;
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.trace.model.Trace;
|
||||
|
@ -100,7 +98,7 @@ public class TraceRecorderAsyncPcodeExecTest extends AbstractGhidraHeadedDebugge
|
|||
SleighLanguage language = (SleighLanguage) trace.getBaseLanguage();
|
||||
|
||||
PcodeProgram prog = SleighProgramCompiler.compileProgram(language, "test",
|
||||
List.of("r2 = r0 + r1;"), PcodeUseropLibrary.NIL);
|
||||
"r2 = r0 + r1;", PcodeUseropLibrary.NIL);
|
||||
|
||||
Register r0 = language.getRegister("r0");
|
||||
Register r1 = language.getRegister("r1");
|
||||
|
|
|
@ -314,7 +314,7 @@ public class PatchStep implements Step {
|
|||
@Override
|
||||
public <T> void execute(PcodeThread<T> emuThread, Stepper<T> stepper, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
PcodeProgram prog = emuThread.getMachine().compileSleigh("schedule", List.of(sleigh + ";"));
|
||||
PcodeProgram prog = emuThread.getMachine().compileSleigh("schedule", sleigh + ";");
|
||||
emuThread.getExecutor().execute(prog, emuThread.getUseropLibrary());
|
||||
}
|
||||
|
||||
|
@ -368,7 +368,7 @@ public class PatchStep implements Step {
|
|||
|
||||
protected Map<AddressSpace, SemisparseByteArray> getPatches(Language language) {
|
||||
PcodeProgram prog = SleighProgramCompiler.compileProgram((SleighLanguage) language,
|
||||
"schedule", List.of(sleigh + ";"), PcodeUseropLibrary.nil());
|
||||
"schedule", sleigh + ";", PcodeUseropLibrary.nil());
|
||||
// SemisparseArray is a bit overkill, no?
|
||||
Map<AddressSpace, SemisparseByteArray> result = new TreeMap<>();
|
||||
for (PcodeOp op : prog.getCode()) {
|
||||
|
|
|
@ -35,7 +35,7 @@ import ghidra.util.database.UndoableTransaction;
|
|||
|
||||
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 {
|
||||
return initTrace(tb, tb.range(0x00400000, 0x0040ffff), tb.range(0x00100000, 0x0010ffff),
|
||||
stateInit, assembly);
|
||||
|
@ -53,14 +53,13 @@ public class AbstractTracePcodeEmulatorTest extends AbstractGhidraHeadlessIntegr
|
|||
* memory where it was assembled.
|
||||
*
|
||||
* @param tb the trace builder
|
||||
* @param stateInit SLEIGH source lines to execute to initialize the trace state before
|
||||
* emulation. Each line must end with ";"
|
||||
* @param stateInit Sleigh source to execute to initialize the trace state before emulation
|
||||
* @param assembly lines of assembly to place starting at {@code 0x00400000}
|
||||
* @return a new trace thread, whose register state is initialized as specified
|
||||
* @throws Throwable if anything goes wrong
|
||||
*/
|
||||
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();
|
||||
TraceThread thread;
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
|
|
|
@ -54,10 +54,10 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
@Test
|
||||
public void testSinglePUSH() throws Throwable {
|
||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||
TraceThread thread = initTrace(tb,
|
||||
List.of(
|
||||
"RIP = 0x00400000;",
|
||||
"RSP = 0x00110000;"),
|
||||
TraceThread thread = initTrace(tb, """
|
||||
RIP = 0x00400000;
|
||||
RSP = 0x00110000;
|
||||
""",
|
||||
List.of(
|
||||
"PUSH 0xdeadbeef"));
|
||||
|
||||
|
@ -94,10 +94,10 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
@Test
|
||||
public void testDoublePUSH() throws Throwable {
|
||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||
TraceThread thread = initTrace(tb,
|
||||
List.of(
|
||||
"RIP = 0x00400000;",
|
||||
"RSP = 0x00110000;"),
|
||||
TraceThread thread = initTrace(tb, """
|
||||
RIP = 0x00400000;
|
||||
RSP = 0x00110000;
|
||||
""",
|
||||
List.of(
|
||||
"PUSH 0xdeadbeef",
|
||||
"PUSH 0xbaadf00d"));
|
||||
|
@ -133,11 +133,11 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||
Register pc = tb.language.getProgramCounter();
|
||||
|
||||
TraceThread thread = initTrace(tb,
|
||||
List.of(
|
||||
"RIP = 0x00400000;",
|
||||
"RSP = 0x00110000;",
|
||||
"RAX = 0x12345678;"),
|
||||
TraceThread thread = initTrace(tb, """
|
||||
RIP = 0x00400000;
|
||||
RSP = 0x00110000;
|
||||
RAX = 0x12345678;
|
||||
""",
|
||||
List.of(
|
||||
"JMP 0x00400007", // 2 bytes
|
||||
"MOV EAX,0xdeadbeef", // 5 bytes
|
||||
|
@ -189,11 +189,12 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
AssemblyPatternBlock thumbPat = AssemblyPatternBlock.fromRegisterValue(thumbCtx);
|
||||
|
||||
// NOTE: Assemble the thumb section separately
|
||||
TraceThread thread = initTrace(tb,
|
||||
List.of(
|
||||
"pc = 0x00400000;",
|
||||
"sp = 0x00110000;",
|
||||
"*:4 0x00400008:4 = 0x00401001;"), // immediately after bx
|
||||
// write 0x00401001 immediately after bx (0x00400008)
|
||||
TraceThread thread = initTrace(tb, """
|
||||
pc = 0x00400000;
|
||||
sp = 0x00110000;
|
||||
*:4 0x00400008:4 = 0x00401001;
|
||||
""",
|
||||
List.of(
|
||||
"ldr r6, [pc,#0]!", // 4 bytes, pc+4 should be 00400008
|
||||
"bx r6")); // 4 bytes
|
||||
|
@ -241,10 +242,10 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "Toy:BE:64:default")) {
|
||||
assertEquals(Register.NO_CONTEXT, tb.language.getContextBaseRegister());
|
||||
|
||||
TraceThread thread = initTrace(tb,
|
||||
List.of(
|
||||
"pc = 0x00400000;",
|
||||
"sp = 0x00110000;"),
|
||||
TraceThread thread = initTrace(tb, """
|
||||
pc = 0x00400000;
|
||||
sp = 0x00110000;
|
||||
""",
|
||||
List.of(
|
||||
"imm r0, #911")); // decimal
|
||||
|
||||
|
@ -272,10 +273,10 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
@Test
|
||||
public void testBRDS() throws Throwable {
|
||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "Toy:BE:64:default")) {
|
||||
TraceThread thread = initTrace(tb,
|
||||
List.of(
|
||||
"pc = 0x00400000;",
|
||||
"sp = 0x00110000;"),
|
||||
TraceThread thread = initTrace(tb, """
|
||||
pc = 0x00400000;
|
||||
sp = 0x00110000;
|
||||
""",
|
||||
List.of(
|
||||
"brds 0x00400006",
|
||||
"imm r0, #911", // decimal
|
||||
|
@ -314,13 +315,13 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
@Test
|
||||
public void testSelfModifyingX86() throws Throwable {
|
||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||
TraceThread thread = initTrace(tb,
|
||||
List.of(
|
||||
"RIP = 0x00400000;",
|
||||
"RSP = 0x00110000;",
|
||||
"RAX = 0x12345678;",
|
||||
// NB. Assembly actually happens first, so this is modifying
|
||||
"*:1 0x00400007:8 = *0x00400007:8 ^ 0xcc;"),
|
||||
// NB. Assembly actually happens first, so Sleigh will modify it
|
||||
TraceThread thread = initTrace(tb, """
|
||||
RIP = 0x00400000;
|
||||
RSP = 0x00110000;
|
||||
RAX = 0x12345678;
|
||||
*:1 0x00400007:8 = *0x00400007:8 ^ 0xcc;
|
||||
""",
|
||||
List.of(
|
||||
// First instruction undoes the modification above
|
||||
"XOR byte ptr [0x00400007], 0xcc", // 7 bytes
|
||||
|
@ -356,10 +357,10 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
@Test
|
||||
public void testDoublePUSH_pCode() throws Throwable {
|
||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||
TraceThread thread = initTrace(tb,
|
||||
List.of(
|
||||
"RIP = 0x00400000;",
|
||||
"RSP = 0x00110000;"),
|
||||
TraceThread thread = initTrace(tb, """
|
||||
RIP = 0x00400000;
|
||||
RSP = 0x00110000;
|
||||
""",
|
||||
List.of(
|
||||
"PUSH 0xdeadbeef",
|
||||
"PUSH 0xbaadf00d"));
|
||||
|
@ -424,10 +425,10 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
dumped.append(NumericUtilities.convertBytesToString(in));
|
||||
}
|
||||
};
|
||||
TraceThread thread = initTrace(tb,
|
||||
List.of(
|
||||
"RIP = 0x00400000;",
|
||||
"RSP = 0x00110000;"),
|
||||
TraceThread thread = initTrace(tb, """
|
||||
RIP = 0x00400000;
|
||||
RSP = 0x00110000;
|
||||
""",
|
||||
List.of(
|
||||
"PUSH 0xdeadbeef",
|
||||
"PUSH 0xbaadf00d"));
|
||||
|
@ -438,7 +439,7 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
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());
|
||||
emuThread.overrideContextWithDefault();
|
||||
|
||||
|
@ -472,10 +473,10 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
dumped.append(NumericUtilities.convertBytesToString(in));
|
||||
}
|
||||
};
|
||||
TraceThread thread = initTrace(tb,
|
||||
List.of(
|
||||
"RIP = 0x00400000;",
|
||||
"RSP = 0x00110000;"),
|
||||
TraceThread thread = initTrace(tb, """
|
||||
RIP = 0x00400000;
|
||||
RSP = 0x00110000;
|
||||
""",
|
||||
List.of(
|
||||
"PUSH 0xdeadbeef",
|
||||
"PUSH 0xbaadf00d"));
|
||||
|
@ -486,12 +487,13 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
return hexLib;
|
||||
}
|
||||
};
|
||||
emu.inject(tb.addr(0x00400006), List.of(
|
||||
"hexdump(RSP);",
|
||||
"emu_swi();",
|
||||
"hexdump(RIP);",
|
||||
"emu_exec_decoded();",
|
||||
"hexdump(RIP);"));
|
||||
emu.inject(tb.addr(0x00400006), """
|
||||
hexdump(RSP);
|
||||
emu_swi();
|
||||
hexdump(RIP);
|
||||
emu_exec_decoded();
|
||||
hexdump(RIP);
|
||||
""");
|
||||
PcodeThread<byte[]> emuThread = emu.newThread(thread.getPath());
|
||||
emuThread.overrideContextWithDefault();
|
||||
|
||||
|
@ -527,11 +529,11 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
@Test
|
||||
public void testBreakpoints() throws Throwable {
|
||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||
TraceThread thread = initTrace(tb,
|
||||
List.of(
|
||||
"RIP = 0x00400000;",
|
||||
"RSP = 0x00110000;",
|
||||
"RAX = 0;"),
|
||||
TraceThread thread = initTrace(tb, """
|
||||
RIP = 0x00400000;
|
||||
RSP = 0x00110000;
|
||||
RAX = 0;
|
||||
""",
|
||||
List.of(
|
||||
"PUSH 0xdeadbeef",
|
||||
"PUSH 0xbaadf00d"));
|
||||
|
@ -561,11 +563,11 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
@Test
|
||||
public void testCLZ() throws Throwable {
|
||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "ARM:LE:32:v8")) {
|
||||
TraceThread thread = initTrace(tb,
|
||||
List.of(
|
||||
"pc = 0x00400000;",
|
||||
"sp = 0x00110000;",
|
||||
"r0 = 0x00008000;"),
|
||||
TraceThread thread = initTrace(tb, """
|
||||
pc = 0x00400000;
|
||||
sp = 0x00110000;
|
||||
r0 = 0x00008000;
|
||||
""",
|
||||
List.of(
|
||||
"clz r1, r0"));
|
||||
|
||||
|
@ -594,12 +596,12 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||
Register pc = tb.language.getProgramCounter();
|
||||
|
||||
TraceThread thread = initTrace(tb,
|
||||
List.of(
|
||||
"RIP = 0x00400000;",
|
||||
"RSP = 0x00110000;",
|
||||
"*:8 0x00600008:8 = 0x0123456789abcdef;", // LE
|
||||
"*:8 0x00600000:8 = 0xfedcba9876543210;"),
|
||||
TraceThread thread = initTrace(tb, """
|
||||
RIP = 0x00400000;
|
||||
RSP = 0x00110000;
|
||||
*:8 0x00600008:8 = 0x0123456789abcdef;
|
||||
*:8 0x00600000:8 = 0xfedcba9876543210;
|
||||
""",
|
||||
List.of(
|
||||
"MOVAPS XMM0, xmmword ptr [0x00600000]"));
|
||||
|
||||
|
@ -632,12 +634,12 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||
Register pc = tb.language.getProgramCounter();
|
||||
|
||||
TraceThread thread = initTrace(tb,
|
||||
List.of(
|
||||
"RIP = 0x00400000;",
|
||||
"RSP = 0x00110000;",
|
||||
"RAX = 0x7fffffff;",
|
||||
"RCX = 4;"),
|
||||
TraceThread thread = initTrace(tb, """
|
||||
RIP = 0x00400000;
|
||||
RSP = 0x00110000;
|
||||
RAX = 0x7fffffff;
|
||||
RCX = 4;
|
||||
""",
|
||||
List.of(
|
||||
"SAR EAX, CL"));
|
||||
|
||||
|
@ -662,11 +664,11 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
@Test
|
||||
public void testCachedReadAfterSmallWrite() throws Throwable {
|
||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||
TraceThread thread = initTrace(tb,
|
||||
List.of(
|
||||
"RIP = 0x00400000;",
|
||||
"RSP = 0x00110000;",
|
||||
"RAX = 0x12345678;"),
|
||||
TraceThread thread = initTrace(tb, """
|
||||
RIP = 0x00400000;
|
||||
RSP = 0x00110000;
|
||||
RAX = 0x12345678;
|
||||
""",
|
||||
List.of(
|
||||
"XOR AH, AH",
|
||||
"MOV RCX, RAX"));
|
||||
|
@ -689,9 +691,9 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
@Test(expected = AccessPcodeExecutionException.class)
|
||||
public void testCheckedMOV_err() throws Throwable {
|
||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||
TraceThread thread = initTrace(tb,
|
||||
List.of(
|
||||
"RIP = 0x00400000;"),
|
||||
TraceThread thread = initTrace(tb, """
|
||||
RIP = 0x00400000;
|
||||
""",
|
||||
List.of(
|
||||
"MOV RCX,RAX"));
|
||||
|
||||
|
@ -711,10 +713,11 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
@Test
|
||||
public void testCheckedMOV_known() throws Throwable {
|
||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||
TraceThread thread = initTrace(tb,
|
||||
List.of(
|
||||
"RIP = 0x00400000;",
|
||||
"RAX = 0x1234;"), // Make it known in the trace
|
||||
// Make RAX known in the trace
|
||||
TraceThread thread = initTrace(tb, """
|
||||
RIP = 0x00400000;
|
||||
RAX = 0x1234;
|
||||
""",
|
||||
List.of(
|
||||
"MOV RCX,RAX"));
|
||||
|
||||
|
@ -735,10 +738,11 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
@Test(expected = AccessPcodeExecutionException.class)
|
||||
public void testCheckedMOV_knownPast_err() throws Throwable {
|
||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||
TraceThread thread = initTrace(tb,
|
||||
List.of(
|
||||
"RIP = 0x00400000;",
|
||||
"RAX = 0x1234;"), // Make it known in the trace
|
||||
// Make RAX known in the trace
|
||||
TraceThread thread = initTrace(tb, """
|
||||
RIP = 0x00400000;
|
||||
RAX = 0x1234;
|
||||
""",
|
||||
List.of(
|
||||
"MOV RCX,RAX"));
|
||||
|
||||
|
@ -760,10 +764,11 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
@Test
|
||||
public void testCheckedMOV_knownPast_has() throws Throwable {
|
||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||
TraceThread thread = initTrace(tb,
|
||||
List.of(
|
||||
"RIP = 0x00400000;",
|
||||
"RAX = 0x1234;"), // Make it known in the trace
|
||||
// Make RAX known in the trace
|
||||
TraceThread thread = initTrace(tb, """
|
||||
RIP = 0x00400000;
|
||||
RAX = 0x1234;
|
||||
""",
|
||||
List.of(
|
||||
"MOV RCX,RAX"));
|
||||
|
||||
|
@ -785,9 +790,9 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
@Test
|
||||
public void testCheckedMOV_initialized() throws Throwable {
|
||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||
TraceThread thread = initTrace(tb,
|
||||
List.of(
|
||||
"RIP = 0x00400000;"),
|
||||
TraceThread thread = initTrace(tb, """
|
||||
RIP = 0x00400000;
|
||||
""",
|
||||
List.of(
|
||||
"MOV RAX,0", // Have the program initialize it
|
||||
"MOV RCX,RAX"));
|
||||
|
@ -820,11 +825,11 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
ctxManager.setValue(lang, ctxVal, Range.atLeast(0L),
|
||||
tb.range(0x00400000, 0x00400002));
|
||||
}
|
||||
TraceThread thread = initTrace(tb,
|
||||
List.of(
|
||||
"RIP = 0x00400000;",
|
||||
"RSP = 0x00110000;",
|
||||
"RAX = 0xff12345678;"),
|
||||
TraceThread thread = initTrace(tb, """
|
||||
RIP = 0x00400000;
|
||||
RSP = 0x00110000;
|
||||
RAX = 0xff12345678;
|
||||
""",
|
||||
List.of(
|
||||
"DEC EAX",
|
||||
"MOV ECX,EAX"));
|
||||
|
@ -863,11 +868,11 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
@Test
|
||||
public void testMOV_EAX_dword_RBPm4() throws Throwable {
|
||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||
TraceThread thread = initTrace(tb,
|
||||
List.of(
|
||||
"RIP = 0x00400000;",
|
||||
"RSP = 0x00110000;",
|
||||
"*:4 (0:8-4) = 0x12345678;"),
|
||||
TraceThread thread = initTrace(tb, """
|
||||
RIP = 0x00400000;
|
||||
RSP = 0x00110000;
|
||||
*:4 (0:8-4) = 0x12345678;
|
||||
""",
|
||||
List.of(
|
||||
"MOV EAX, dword ptr [RBP + -0x4]"));
|
||||
|
||||
|
@ -898,10 +903,10 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
@Test(expected = PcodeExecutionException.class)
|
||||
public void testMOV_EAX_dword_RBPm2_x64() throws Throwable {
|
||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||
TraceThread thread = initTrace(tb,
|
||||
List.of(
|
||||
"RIP = 0x00400000;",
|
||||
"RSP = 0x00110000;"),
|
||||
TraceThread thread = initTrace(tb, """
|
||||
RIP = 0x00400000;
|
||||
RSP = 0x00110000;
|
||||
""",
|
||||
List.of(
|
||||
"MOV EAX, dword ptr [RBP + -0x2]"));
|
||||
|
||||
|
@ -921,10 +926,10 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
@Test(expected = PcodeExecutionException.class)
|
||||
public void testMOV_EAX_dword_EBPm2_x86() throws Throwable {
|
||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:32:default")) {
|
||||
TraceThread thread = initTrace(tb,
|
||||
List.of(
|
||||
"EIP = 0x00400000;",
|
||||
"ESP = 0x00110000;"),
|
||||
TraceThread thread = initTrace(tb, """
|
||||
EIP = 0x00400000;
|
||||
ESP = 0x00110000;
|
||||
""",
|
||||
List.of(
|
||||
"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")) {
|
||||
assertEquals(Register.NO_CONTEXT, tb.language.getContextBaseRegister());
|
||||
|
||||
TraceThread thread = initTrace(tb,
|
||||
List.of(
|
||||
"pc = 0x00400000;",
|
||||
"sp = 0x00110000;"),
|
||||
TraceThread thread = initTrace(tb, """
|
||||
pc = 0x00400000;
|
||||
sp = 0x00110000;
|
||||
""",
|
||||
List.of(
|
||||
"unimpl"));
|
||||
|
||||
|
@ -966,11 +971,11 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
Address stackStart = tb.language.getDefaultDataSpace().getAddress(0, true);
|
||||
TraceThread thread = initTrace(tb,
|
||||
new AddressRangeImpl(textStart, 0x200),
|
||||
new AddressRangeImpl(stackStart, 1),
|
||||
List.of(
|
||||
"PC = 0x000100;",
|
||||
"W1 = 0x0800;",
|
||||
"*[ram]:2 0x000800:3 = 0x1234;"),
|
||||
new AddressRangeImpl(stackStart, 1), """
|
||||
PC = 0x000100;
|
||||
W1 = 0x0800;
|
||||
*[ram]:2 0x000800:3 = 0x1234;
|
||||
""",
|
||||
List.of(
|
||||
"mov.w [W1], W0"));
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ import static org.junit.Assert.assertArrayEquals;
|
|||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
|
@ -207,14 +206,14 @@ public class TraceSleighUtilsTest extends AbstractGhidraHeadlessIntegrationTest
|
|||
public void testCompileSleighProgram() throws Exception {
|
||||
try (ToyDBTraceBuilder b = new ToyDBTraceBuilder("test", TOY_BE_64_HARVARD)) {
|
||||
PcodeProgram sp = SleighProgramCompiler.compileProgram((SleighLanguage) b.language,
|
||||
"test", List.of(
|
||||
"if (r0) goto <else>;",
|
||||
" r1 = 6;",
|
||||
" goto <done>;",
|
||||
"<else>",
|
||||
" r1 = 7;",
|
||||
"<done>"),
|
||||
PcodeUseropLibrary.NIL);
|
||||
"test", """
|
||||
if (r0) goto <else>;
|
||||
r1 = 6;
|
||||
goto <done>;
|
||||
<else>
|
||||
r1 = 7;
|
||||
<done>
|
||||
""", PcodeUseropLibrary.NIL);
|
||||
TraceThread thread;
|
||||
try (UndoableTransaction tid = b.startTransaction()) {
|
||||
thread = b.getOrAddThread("Thread1", 0);
|
||||
|
|
|
@ -27,7 +27,6 @@ import java.nio.charset.CharsetEncoder;
|
|||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Range;
|
||||
|
||||
|
@ -131,9 +130,9 @@ public class ToyDBTraceBuilder implements AutoCloseable {
|
|||
* @param snap the snap to modify
|
||||
* @param frame the frame to modify
|
||||
* @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,
|
||||
"builder", sleigh, PcodeUseropLibrary.nil());
|
||||
TraceSleighUtils.buildByteExecutor(trace, snap, thread, frame)
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
*/
|
||||
package ghidra.trace.model.time.schedule;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||
import ghidra.pcode.emu.PcodeThread;
|
||||
import ghidra.pcode.emu.ThreadPcodeExecutorState;
|
||||
|
@ -167,7 +165,7 @@ class TestThread implements PcodeThread<Void> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void inject(Address address, List<String> sleigh) {
|
||||
public void inject(Address address, String source) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -257,19 +257,19 @@ public abstract class AbstractPcodeMachine<T> implements PcodeMachine<T> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PcodeProgram compileSleigh(String sourceName, List<String> lines) {
|
||||
return SleighProgramCompiler.compileProgram(language, sourceName, lines, stubLibrary);
|
||||
public PcodeProgram compileSleigh(String sourceName, String source) {
|
||||
return SleighProgramCompiler.compileProgram(language, sourceName, source, stubLibrary);
|
||||
}
|
||||
|
||||
@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
|
||||
* 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
|
||||
* built p-code.
|
||||
*/
|
||||
PcodeProgram pcode = compileSleigh("machine_inject:" + address, sleigh);
|
||||
PcodeProgram pcode = compileSleigh("machine_inject:" + address, source);
|
||||
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
|
||||
* frames)
|
||||
*/
|
||||
PcodeProgram pcode = compileSleigh("breakpoint:" + address, List.of(
|
||||
"if (!(" + sleighCondition + ")) goto <nobreak>;",
|
||||
" emu_swi();",
|
||||
"<nobreak>",
|
||||
" emu_exec_decoded();"));
|
||||
PcodeProgram pcode = compileSleigh("breakpoint:" + address, String.format("""
|
||||
if (!(%s)) goto <nobreak>;
|
||||
emu_swi();
|
||||
<nobreak>
|
||||
emu_exec_decoded();
|
||||
""", sleighCondition));
|
||||
injects.put(address, pcode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,10 +33,10 @@ import ghidra.util.Msg;
|
|||
* The default implementation of {@link PcodeThread} suitable for most applications
|
||||
*
|
||||
* <p>
|
||||
* When emulating on concrete state, consider using {@link ModifiedPcodeThread}, so that
|
||||
* state modifiers from the older {@link Emulator} are incorporated. In either case, it may be
|
||||
* worthwhile to examine existing state modifiers to ensure they are appropriately represented in
|
||||
* any abstract state. It may be necessary to port them.
|
||||
* When emulating on concrete state, consider using {@link ModifiedPcodeThread}, so that state
|
||||
* modifiers from the older {@link Emulator} are incorporated. In either case, it may be worthwhile
|
||||
* to examine existing state modifiers to ensure they are appropriately represented in any abstract
|
||||
* state. It may be necessary to port them.
|
||||
*
|
||||
* <p>
|
||||
* 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
|
||||
public void executeSleighLine(String line) {
|
||||
PcodeProgram program = SleighProgramCompiler.compileProgram(language, "line",
|
||||
List.of(line + ";"), thread.library);
|
||||
public void executeSleigh(String source) {
|
||||
PcodeProgram program =
|
||||
SleighProgramCompiler.compileProgram(language, "exec", source, thread.library);
|
||||
execute(program, thread.library);
|
||||
}
|
||||
|
||||
|
@ -588,9 +588,9 @@ public class DefaultPcodeThread<T> implements PcodeThread<T> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void inject(Address address, List<String> sleigh) {
|
||||
public void inject(Address address, String source) {
|
||||
PcodeProgram pcode = SleighProgramCompiler.compileProgram(
|
||||
language, "thread_inject:" + address, sleigh, library);
|
||||
language, "thread_inject:" + address, source, library);
|
||||
injects.put(address, pcode);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
package ghidra.pcode.emu;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||
import ghidra.pcode.emu.DefaultPcodeThread.PcodeEmulationLibrary;
|
||||
|
@ -31,7 +30,7 @@ import ghidra.program.model.address.Address;
|
|||
public interface PcodeMachine<T> {
|
||||
|
||||
/**
|
||||
* Get the machine's SLEIGH language (processor model)
|
||||
* Get the machine's Sleigh language (processor model)
|
||||
*
|
||||
* @return the language
|
||||
*/
|
||||
|
@ -61,7 +60,7 @@ public interface PcodeMachine<T> {
|
|||
*
|
||||
* <p>
|
||||
* 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
|
||||
* 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
|
||||
|
@ -114,26 +113,26 @@ public interface PcodeMachine<T> {
|
|||
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>
|
||||
* This links in the userop library given at construction time and those defining the emulation
|
||||
* userops, e.g., {@code emu_swi}.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
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>
|
||||
* 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
|
||||
* 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
|
||||
* execute the overridden instruction.
|
||||
*
|
||||
|
@ -143,9 +142,9 @@ public interface PcodeMachine<T> {
|
|||
* double-wrapping, etc.
|
||||
*
|
||||
* @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
|
||||
|
@ -165,10 +164,10 @@ public interface PcodeMachine<T> {
|
|||
* <p>
|
||||
* 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
|
||||
* 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 sleighCondition a SLEIGH expression which controls the breakpoint
|
||||
* @param sleighCondition a Sleigh expression which controls the breakpoint
|
||||
*/
|
||||
void addBreakpoint(Address address, String sleighCondition);
|
||||
}
|
||||
|
|
|
@ -336,9 +336,9 @@ public interface PcodeThread<T> {
|
|||
* inject.
|
||||
*
|
||||
* @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
|
||||
|
|
|
@ -28,9 +28,10 @@ public class X86PcodeStateInitializer implements PcodeStateInitializer {
|
|||
private static final List<LanguageID> LANG_IDS = List.of(
|
||||
new LanguageID("x86:LE:32:default"),
|
||||
new LanguageID("x86:LE:64:default"));
|
||||
private static final List<String> SOURCE = List.of(
|
||||
"FS_OFFSET = 0;",
|
||||
"GS_OFFSET = 0;");
|
||||
private static final String SOURCE = """
|
||||
FS_OFFSET = 0;
|
||||
GS_OFFSET = 0;
|
||||
""";
|
||||
|
||||
@Override
|
||||
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) {
|
||||
PcodeProgram program = SleighProgramCompiler.compileProgram(language,
|
||||
"line", List.of(line + ";"), PcodeUseropLibrary.NIL);
|
||||
public void executeSleigh(String source) {
|
||||
PcodeProgram program =
|
||||
SleighProgramCompiler.compileProgram(language, "exec", source, PcodeUseropLibrary.NIL);
|
||||
execute(program, PcodeUseropLibrary.nil());
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
*/
|
||||
package ghidra.pcode.exec;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||
|
@ -65,7 +64,7 @@ public class SleighPcodeUseropDefinition<T> implements PcodeUseropDefinition<T>
|
|||
private final Factory factory;
|
||||
private final String name;
|
||||
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) {
|
||||
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>
|
||||
* 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
|
||||
* @param additionalBody the additional source
|
||||
*/
|
||||
public Builder sleigh(Collection<String> additionalLines) {
|
||||
this.lines.addAll(additionalLines);
|
||||
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));
|
||||
}
|
||||
public Builder body(CharSequence additionalBody) {
|
||||
body.append(additionalBody);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -144,23 +114,23 @@ public class SleighPcodeUseropDefinition<T> implements PcodeUseropDefinition<T>
|
|||
*/
|
||||
public <T> SleighPcodeUseropDefinition<T> build() {
|
||||
return new SleighPcodeUseropDefinition<>(factory.language, name, List.copyOf(params),
|
||||
List.copyOf(lines));
|
||||
body.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private final SleighLanguage language;
|
||||
private final String name;
|
||||
private final List<String> params;
|
||||
private final List<String> lines;
|
||||
private final String body;
|
||||
|
||||
private final Map<List<Varnode>, PcodeProgram> cacheByArgs = new HashMap<>();
|
||||
|
||||
protected SleighPcodeUseropDefinition(SleighLanguage language, String name, List<String> params,
|
||||
List<String> lines) {
|
||||
String body) {
|
||||
this.language = language;
|
||||
this.name = name;
|
||||
this.params = params;
|
||||
this.lines = lines;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -181,7 +151,7 @@ public class SleighPcodeUseropDefinition<T> implements PcodeUseropDefinition<T>
|
|||
args.add(outArg);
|
||||
args.addAll(inArgs);
|
||||
return cacheByArgs.computeIfAbsent(args,
|
||||
a -> SleighProgramCompiler.compileUserop(language, name, params, lines, library, a));
|
||||
a -> SleighProgramCompiler.compileUserop(language, name, params, body, library, a));
|
||||
}
|
||||
|
||||
@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
|
||||
*/
|
||||
public List<String> getLines() {
|
||||
return lines;
|
||||
public String getBody() {
|
||||
return body;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,8 +19,6 @@ import java.io.IOException;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ghidra.app.plugin.processors.sleigh.*;
|
||||
import ghidra.app.plugin.processors.sleigh.template.ConstructTpl;
|
||||
import ghidra.pcodeCPort.pcoderaw.VarnodeData;
|
||||
|
@ -66,12 +64,12 @@ public class SleighProgramCompiler {
|
|||
* @param language the language
|
||||
* @param parser the parser
|
||||
* @param sourceName the name of the program, for error diagnostics
|
||||
* @param text the SLEIGH source
|
||||
* @param source the Sleigh source
|
||||
* @return the constructor template
|
||||
*/
|
||||
public static ConstructTpl compileTemplate(Language language, PcodeParser parser,
|
||||
String sourceName, String text) {
|
||||
return parser.compilePcode(text, EXPRESSION_SOURCE_NAME, 1);
|
||||
String sourceName, String source) {
|
||||
return parser.compilePcode(source, EXPRESSION_SOURCE_NAME, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -82,7 +80,7 @@ public class SleighProgramCompiler {
|
|||
* @return the list of p-code ops
|
||||
* @throws UnknownInstructionException in case of crossbuilds, the target instruction is unknown
|
||||
* @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)
|
||||
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>
|
||||
* 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
|
||||
* 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
|
||||
* 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 sourceName a diagnostic name for the SLEIGH source
|
||||
* @param lines the lines of SLEIGH source. These are joined with line separators but no
|
||||
* semicolon!
|
||||
* @param sourceName a diagnostic name for the Sleigh source
|
||||
* @param source the Sleigh source
|
||||
* @param library the userop library or stub library for binding userop symbols
|
||||
* @return the compiled p-code program
|
||||
*/
|
||||
public static PcodeProgram compileProgram(SleighLanguage language, String sourceName,
|
||||
List<String> lines, PcodeUseropLibrary<?> library) {
|
||||
String source, PcodeUseropLibrary<?> library) {
|
||||
PcodeParser parser = createParser(language);
|
||||
Map<Integer, UserOpSymbol> symbols = library.getSymbols(language);
|
||||
addParserSymbols(parser, symbols);
|
||||
|
||||
ConstructTpl template =
|
||||
compileTemplate(language, parser, sourceName, StringUtils.join(lines, "\n"));
|
||||
ConstructTpl template = compileTemplate(language, parser, sourceName, source);
|
||||
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>
|
||||
* 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.
|
||||
*
|
||||
* @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
|
||||
* 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 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 paramName the symbol name for the parameter
|
||||
* @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,
|
||||
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>
|
||||
* 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
|
||||
* 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
|
||||
* 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
|
||||
* 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 params the names of parameters in order. Index 0 names the output symbol, probably
|
||||
* {@link SleighPcodeUseropDefinition#OUT_SYMBOL_NAME}
|
||||
* @param lines the lines of SLEIGH source. These are joined with line separators but no
|
||||
* semicolon!
|
||||
* @param source the Sleigh source
|
||||
* @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.
|
||||
* @return a p-code program that implements the userop for the given arguments
|
||||
*/
|
||||
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) {
|
||||
PcodeParser parser = createParser(language);
|
||||
Map<Integer, UserOpSymbol> symbols = library.getSymbols(language);
|
||||
|
@ -288,7 +283,6 @@ public class SleighProgramCompiler {
|
|||
}
|
||||
}
|
||||
|
||||
String source = StringUtils.join(lines, "\n");
|
||||
try {
|
||||
ConstructTpl template = compileTemplate(language, parser, opName, source);
|
||||
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
|
||||
* @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
|
||||
|
|
|
@ -49,8 +49,14 @@ class AssignStmt extends AbstractStmt implements RValInternal, StmtWithVal {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected String generate(Label next, Label fall) {
|
||||
return lhs.generate() + " = " + rhs.generate() + ";\n" + next.genGoto(fall);
|
||||
protected StringTree generate(Label next, Label 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
|
||||
|
|
|
@ -49,16 +49,16 @@ class BlockStmt extends AbstractStmt {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected String generate(Label next, Label fall) {
|
||||
protected StringTree generate(Label next, Label fall) {
|
||||
if (children.isEmpty()) {
|
||||
return next.genGoto(fall);
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
StringTree st = new StringTree();
|
||||
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));
|
||||
return sb.toString();
|
||||
st.append(children.get(children.size() - 1).generate(next, fall));
|
||||
return st;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -29,8 +29,14 @@ class DeclStmt extends AbstractStmt {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected String generate(Label next, Label fall) {
|
||||
return "local " + name + ":" + type.getLength() + ";\n" +
|
||||
next.genGoto(fall);
|
||||
protected StringTree generate(Label next, Label fall) {
|
||||
StringTree st = new StringTree();
|
||||
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
|
||||
protected String generate(Label next, Label fall) {
|
||||
protected StringTree generate(Label next, Label fall) {
|
||||
Label lTest = ctx.new FreshLabel();
|
||||
Label lBegin = ctx.new FreshLabel();
|
||||
Label lExit = lBreak = next.freshOrBorrow();
|
||||
Label lStep = lContinue = ctx.new FreshLabel();
|
||||
|
||||
String initGen = init.generate(lTest, lTest);
|
||||
String testGen = lExit.genGoto(cond.notb(), lBegin);
|
||||
String stmtGen = stmt.generate(lStep, lStep);
|
||||
String stepGen = step.generate(lTest, fall);
|
||||
return initGen +
|
||||
lTest.genAnchor() +
|
||||
testGen +
|
||||
lBegin.genAnchor() +
|
||||
stmtGen +
|
||||
lStep.genAnchor() +
|
||||
stepGen +
|
||||
lExit.genAnchor();
|
||||
StringTree initGen = init.generate(lTest, lTest);
|
||||
StringTree testGen = lExit.genGoto(cond.notb(), lBegin);
|
||||
StringTree stmtGen = stmt.generate(lStep, lStep);
|
||||
StringTree stepGen = step.generate(lTest, fall);
|
||||
|
||||
StringTree st = new StringTree();
|
||||
st.append(initGen);
|
||||
st.append(lTest.genAnchor());
|
||||
st.append(testGen);
|
||||
st.append(lBegin.genAnchor());
|
||||
st.append(stmtGen);
|
||||
st.append(lStep.genAnchor());
|
||||
st.append(stepGen);
|
||||
st.append(lExit.genAnchor());
|
||||
return st;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,8 @@ class IfStmt extends ConditionalStmt {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected String generate(Label next, Label fall) {
|
||||
protected StringTree generate(Label next, Label fall) {
|
||||
StringTree st = new StringTree();
|
||||
if (elseStmt == null) {
|
||||
if (stmt.isSingleGoto()) {
|
||||
return stmt.getNext().genGoto(cond, fall);
|
||||
|
@ -34,28 +35,31 @@ class IfStmt extends ConditionalStmt {
|
|||
Label lTrue = ctx.new FreshLabel();
|
||||
Label lFalse = next.freshOrBorrow();
|
||||
|
||||
String condGen = lFalse.genGoto(cond.notb(), lTrue);
|
||||
String stmtGen = stmt.generate(next, fall);
|
||||
return condGen +
|
||||
lTrue.genAnchor() +
|
||||
stmtGen +
|
||||
lFalse.genAnchor();
|
||||
StringTree condGen = lFalse.genGoto(cond.notb(), lTrue);
|
||||
StringTree stmtGen = stmt.generate(next, fall);
|
||||
|
||||
st.append(condGen);
|
||||
st.append(lTrue.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();
|
||||
Label lTrue = ctx.new FreshLabel();
|
||||
Label lExit = next.freshOrBorrow();
|
||||
StringTree condGen = lTrue.genGoto(cond, lFalse);
|
||||
StringTree elseGen = elseStmt.generate(lExit, lTrue);
|
||||
StringTree stmtGen = stmt.generate(next, fall);
|
||||
|
||||
String condGen = lTrue.genGoto(cond, lFalse);
|
||||
String elseGen = elseStmt.generate(lExit, lTrue);
|
||||
String stmtGen = stmt.generate(next, fall);
|
||||
|
||||
return condGen +
|
||||
lFalse.genAnchor() +
|
||||
elseGen +
|
||||
lTrue.genAnchor() +
|
||||
stmtGen +
|
||||
lExit.genAnchor();
|
||||
st.append(condGen);
|
||||
st.append(lFalse.genAnchor());
|
||||
st.append(elseGen);
|
||||
st.append(lTrue.genAnchor());
|
||||
st.append(stmtGen);
|
||||
st.append(lExit.genAnchor());
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
||||
protected void addElse(Stmt elseStmt) {
|
||||
|
|
|
@ -32,7 +32,7 @@ abstract class LoopTruncateStmt extends AbstractStmt {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected String generate(Label next, Label fall) {
|
||||
protected StringTree generate(Label next, Label fall) {
|
||||
return getNext().genGoto(fall);
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,11 @@ class RawStmt extends AbstractStmt {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected String generate(Label next, Label fall) {
|
||||
return stmt + ";\n" + next.genGoto(fall);
|
||||
protected StringTree generate(Label next, Label 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
|
||||
protected String generate(Label next, Label fall) {
|
||||
protected StringTree generate(Label next, Label fall) {
|
||||
RoutineStmt routine = Objects.requireNonNull(nearest(RoutineStmt.class));
|
||||
|
||||
if (!ctx.isAssignable(routine.retType, result.getType())) {
|
||||
ctx.emitResultTypeMismatch(routine, result);
|
||||
}
|
||||
|
||||
return SleighPcodeUseropDefinition.OUT_SYMBOL_NAME + " = " + result.generate() + ";\n" +
|
||||
routine.lReturn.genGoto(fall);
|
||||
StringTree st = new StringTree();
|
||||
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
|
||||
protected String generate(Label next, Label fall) {
|
||||
return "return " + target.generate() + ";\n";
|
||||
protected StringTree generate(Label next, Label fall) {
|
||||
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
|
||||
protected String generate(Label next, Label fall) {
|
||||
protected StringTree generate(Label next, Label fall) {
|
||||
if (children.isEmpty()) {
|
||||
return "";
|
||||
return StringTree.single("");
|
||||
}
|
||||
Label lExit = lReturn = next.freshOrBorrow();
|
||||
// This is an odd case, because it's the root: use lExit instead of fall
|
||||
String blockGen = super.generate(lReturn, lExit);
|
||||
return blockGen +
|
||||
lExit.genAnchor();
|
||||
StringTree blockGen = super.generate(lReturn, lExit);
|
||||
|
||||
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
|
||||
*
|
||||
* <p>
|
||||
* 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
|
||||
* labels.)
|
||||
*
|
||||
* @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}"
|
||||
|
@ -1001,7 +1002,7 @@ public class StructuredSleigh {
|
|||
*
|
||||
* @return the label's expression
|
||||
*/
|
||||
abstract String ref();
|
||||
abstract StringTree ref();
|
||||
|
||||
/**
|
||||
* Generate a goto statement that targets this label
|
||||
|
@ -1009,7 +1010,7 @@ public class StructuredSleigh {
|
|||
* @param fall the label following the goto
|
||||
* @return the Sleigh code
|
||||
*/
|
||||
abstract String genGoto(Label fall);
|
||||
abstract StringTree genGoto(Label fall);
|
||||
|
||||
/**
|
||||
* Generate a conditional goto statement that targets this label
|
||||
|
@ -1018,7 +1019,7 @@ public class StructuredSleigh {
|
|||
* @param fall the label following the goto
|
||||
* @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
|
||||
public String genAnchor() {
|
||||
public StringTree genAnchor() {
|
||||
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
|
||||
public String ref() {
|
||||
return "<" + getName() + ">";
|
||||
public StringTree ref() {
|
||||
StringTree st = new StringTree();
|
||||
st.append("<");
|
||||
st.append(getName());
|
||||
st.append(">");
|
||||
return st;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String genGoto(Label fall) {
|
||||
public StringTree genGoto(Label 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
|
||||
public String genGoto(RVal cond, Label fall) {
|
||||
public StringTree genGoto(RVal cond, Label 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
|
||||
public String genAnchor() {
|
||||
return "";
|
||||
public StringTree genAnchor() {
|
||||
return StringTree.single("");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String ref() {
|
||||
public StringTree ref() {
|
||||
return borrowed.ref();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String genGoto(Label fall) {
|
||||
public StringTree genGoto(Label fall) {
|
||||
if (this == fall) { // placed will also check
|
||||
return "";
|
||||
return StringTree.single("");
|
||||
}
|
||||
return borrowed.genGoto(fall);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String genGoto(RVal cond, Label fall) {
|
||||
public StringTree genGoto(RVal cond, Label fall) {
|
||||
if (this == fall) { // placed with also check
|
||||
return "";
|
||||
return StringTree.single("");
|
||||
}
|
||||
return borrowed.genGoto(cond, fall);
|
||||
}
|
||||
|
@ -1132,22 +1150,22 @@ public class StructuredSleigh {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String genAnchor() {
|
||||
return "";
|
||||
public StringTree genAnchor() {
|
||||
return StringTree.single("");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String ref() {
|
||||
public StringTree ref() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String genGoto(Label fall) {
|
||||
return "";
|
||||
public StringTree genGoto(Label fall) {
|
||||
return StringTree.single("");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String genGoto(RVal cond, Label fall) {
|
||||
public StringTree genGoto(RVal cond, Label fall) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
@ -1703,8 +1721,8 @@ public class StructuredSleigh {
|
|||
e);
|
||||
}
|
||||
});
|
||||
String source = root.generate(FALL, FALL);
|
||||
builder.sleigh(source);
|
||||
StringTree source = root.generate(FALL, FALL);
|
||||
builder.body(source.toString());
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -43,8 +43,12 @@ class VoidExprStmt extends AbstractStmt implements RValInternal, StmtWithVal {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected String generate(Label next, Label fall) {
|
||||
return expr.generate() + ";\n" + next.genGoto(fall);
|
||||
protected StringTree generate(Label next, Label fall) {
|
||||
StringTree st = new StringTree();
|
||||
st.append(expr.generate());
|
||||
st.append(";\n");
|
||||
st.append(next.genGoto(fall));
|
||||
return st;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -23,17 +23,21 @@ class WhileStmt extends LoopStmt {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected String generate(Label next, Label fall) {
|
||||
protected StringTree generate(Label next, Label fall) {
|
||||
Label lTest = lContinue = ctx.new FreshLabel();
|
||||
Label lBegin = ctx.new FreshLabel();
|
||||
Label lExit = lBreak = next.freshOrBorrow();
|
||||
|
||||
String testGen = lExit.genGoto(cond.notb(), lBegin);
|
||||
String stmtGen = stmt.generate(lTest, fall);
|
||||
return lTest.genAnchor() +
|
||||
testGen +
|
||||
lBegin.genAnchor() +
|
||||
stmtGen +
|
||||
lExit.genAnchor();
|
||||
StringTree testGen = lExit.genGoto(cond.notb(), lBegin);
|
||||
StringTree stmtGen = stmt.generate(lTest, fall);
|
||||
|
||||
StringTree st = new StringTree();
|
||||
|
||||
st.append(lTest.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.Lookup;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -53,15 +52,15 @@ public class AnnotatedPcodeUseropLibraryTest extends AbstractGhidraHeadlessInteg
|
|||
}
|
||||
|
||||
protected <T> void executeSleigh(PcodeExecutor<T> executor, PcodeUseropLibrary<T> library,
|
||||
String... lines) {
|
||||
String source) {
|
||||
PcodeProgram program = SleighProgramCompiler.compileProgram(executor.getLanguage(), "test",
|
||||
List.of(lines), library);
|
||||
source, library);
|
||||
executor.execute(program, library);
|
||||
}
|
||||
|
||||
protected void executeSleigh(PcodeUseropLibrary<byte[]> library, String... lines)
|
||||
protected void executeSleigh(PcodeUseropLibrary<byte[]> library, String source)
|
||||
throws Exception {
|
||||
executeSleigh(createBytesExecutor(), library, lines);
|
||||
executeSleigh(createBytesExecutor(), library, source);
|
||||
}
|
||||
|
||||
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 java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -27,26 +25,34 @@ import ghidra.program.model.lang.LanguageID;
|
|||
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
|
||||
|
||||
public class PcodeFrameTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||
static final List<String> SAMPLE_ADD = List.of(
|
||||
"r0 = r0 + r1;");
|
||||
static final List<String> SAMPLE_ADD2 = List.of(
|
||||
"r0 = r0 + r1 + r2;");
|
||||
static final List<String> SAMPLE_IF = List.of(
|
||||
"if (r0 == r1) goto <skip>;",
|
||||
"r2 = r2 + 1;",
|
||||
"<skip>");
|
||||
static final List<String> SAMPLE_LOOP = List.of(
|
||||
"<loop>",
|
||||
"r0 = r0 + 1;",
|
||||
"if (r0 == r1) goto <loop>;");
|
||||
static final List<String> SAMPLE_BRANCH = List.of(
|
||||
"goto 0x1234;");
|
||||
static final List<String> SAMPLE_LOAD = List.of(
|
||||
"r0 = *:8 r1;");
|
||||
static final List<String> SAMPLE_LANG_USEROP = List.of(
|
||||
"pcodeop_one(r0);");
|
||||
static final List<String> SAMPLE_LIB_USEROP = List.of(
|
||||
"__lib_userop(r0);");
|
||||
static final String SAMPLE_ADD = """
|
||||
r0 = r0 + r1;
|
||||
""";
|
||||
static final String SAMPLE_ADD2 = """
|
||||
r0 = r0 + r1 + r2;
|
||||
""";
|
||||
static final String SAMPLE_IF = """
|
||||
if (r0 == r1) goto <skip>;
|
||||
r2 = r2 + 1;
|
||||
<skip>
|
||||
""";
|
||||
static final String SAMPLE_LOOP = """
|
||||
<loop>
|
||||
r0 = r0 + 1;
|
||||
if (r0 == r1) goto <loop>;
|
||||
""";
|
||||
static final String SAMPLE_BRANCH = """
|
||||
goto 0x1234;
|
||||
""";
|
||||
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> {
|
||||
@PcodeUserop
|
||||
|
@ -63,11 +69,11 @@ public class PcodeFrameTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||
(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);
|
||||
}
|
||||
|
||||
private PcodeFrame frame(List<String> sample) {
|
||||
private PcodeFrame frame(String sample) {
|
||||
PcodeProgram program = compile(sample);
|
||||
return new PcodeFrame(language, program.code, program.useropNames);
|
||||
}
|
||||
|
@ -75,172 +81,172 @@ public class PcodeFrameTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||
@Test
|
||||
public void testProgramToStringAdd() throws Exception {
|
||||
PcodeProgram program = compile(SAMPLE_ADD);
|
||||
assertEquals("" +
|
||||
"<PcodeProgram:\n" +
|
||||
" r0 = INT_ADD r0, r1\n" +
|
||||
">",
|
||||
assertEquals("""
|
||||
<PcodeProgram:
|
||||
r0 = INT_ADD r0, r1
|
||||
>""",
|
||||
program.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProgramToStringAdd2() throws Exception {
|
||||
PcodeProgram program = compile(SAMPLE_ADD2);
|
||||
assertEquals("" +
|
||||
"<PcodeProgram:\n" +
|
||||
" $U2000:8 = INT_ADD r0, r1\n" +
|
||||
" r0 = INT_ADD $U2000:8, r2\n" +
|
||||
">",
|
||||
assertEquals("""
|
||||
<PcodeProgram:
|
||||
$U2000:8 = INT_ADD r0, r1
|
||||
r0 = INT_ADD $U2000:8, r2
|
||||
>""",
|
||||
program.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProgramToStringIf() throws Exception {
|
||||
PcodeProgram program = compile(SAMPLE_IF);
|
||||
assertEquals("" +
|
||||
"<PcodeProgram:\n" +
|
||||
" $U2000:1 = INT_EQUAL r0, r1\n" +
|
||||
" CBRANCH <0>, $U2000:1\n" +
|
||||
" r2 = INT_ADD r2, 1:8\n" +
|
||||
"<0>\n" +
|
||||
">",
|
||||
assertEquals("""
|
||||
<PcodeProgram:
|
||||
$U2000:1 = INT_EQUAL r0, r1
|
||||
CBRANCH <0>, $U2000:1
|
||||
r2 = INT_ADD r2, 1:8
|
||||
<0>
|
||||
>""",
|
||||
program.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProgramToStringLoop() throws Exception {
|
||||
PcodeProgram program = compile(SAMPLE_LOOP);
|
||||
assertEquals("" +
|
||||
"<PcodeProgram:\n" +
|
||||
"<0>\n" +
|
||||
" r0 = INT_ADD r0, 1:8\n" +
|
||||
" $U2080:1 = INT_EQUAL r0, r1\n" +
|
||||
" CBRANCH <0>, $U2080:1\n" +
|
||||
">",
|
||||
assertEquals("""
|
||||
<PcodeProgram:
|
||||
<0>
|
||||
r0 = INT_ADD r0, 1:8
|
||||
$U2080:1 = INT_EQUAL r0, r1
|
||||
CBRANCH <0>, $U2080:1
|
||||
>""",
|
||||
program.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProgramToStringLoad() throws Exception {
|
||||
PcodeProgram program = compile(SAMPLE_LOAD);
|
||||
assertEquals("" +
|
||||
"<PcodeProgram:\n" +
|
||||
" r0 = LOAD ram(r1)\n" +
|
||||
">",
|
||||
assertEquals("""
|
||||
<PcodeProgram:
|
||||
r0 = LOAD ram(r1)
|
||||
>""",
|
||||
program.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProgramToStringLangUserop() throws Exception {
|
||||
PcodeProgram program = compile(SAMPLE_LANG_USEROP);
|
||||
assertEquals("" +
|
||||
"<PcodeProgram:\n" +
|
||||
" CALLOTHER \"pcodeop_one\", r0\n" +
|
||||
">",
|
||||
assertEquals("""
|
||||
<PcodeProgram:
|
||||
CALLOTHER "pcodeop_one", r0
|
||||
>""",
|
||||
program.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProgramToStringLibUserop() throws Exception {
|
||||
PcodeProgram program = compile(SAMPLE_LIB_USEROP);
|
||||
assertEquals("" +
|
||||
"<PcodeProgram:\n" +
|
||||
" CALLOTHER \"__lib_userop\", r0\n" +
|
||||
">",
|
||||
assertEquals("""
|
||||
<PcodeProgram:
|
||||
CALLOTHER "__lib_userop", r0
|
||||
>""",
|
||||
program.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFrameToStringAdd() throws Exception {
|
||||
PcodeFrame frame = frame(SAMPLE_ADD);
|
||||
assertEquals("" +
|
||||
"<p-code frame: index=0 {\n" +
|
||||
" -> r0 = INT_ADD r0, r1\n" +
|
||||
"}>",
|
||||
assertEquals("""
|
||||
<p-code frame: index=0 {
|
||||
-> r0 = INT_ADD r0, r1
|
||||
}>""",
|
||||
frame.toString());
|
||||
|
||||
frame.advance();
|
||||
assertEquals("" +
|
||||
"<p-code frame: index=1 {\n" +
|
||||
" r0 = INT_ADD r0, r1\n" +
|
||||
" *> fall-through\n" +
|
||||
"}>",
|
||||
assertEquals("""
|
||||
<p-code frame: index=1 {
|
||||
r0 = INT_ADD r0, r1
|
||||
*> fall-through
|
||||
}>""",
|
||||
frame.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFrameToStringIf() throws Exception {
|
||||
PcodeFrame frame = frame(SAMPLE_IF);
|
||||
assertEquals("" +
|
||||
"<p-code frame: index=0 {\n" +
|
||||
" -> $U2000:1 = INT_EQUAL r0, r1\n" +
|
||||
" CBRANCH <0>, $U2000:1\n" +
|
||||
" r2 = INT_ADD r2, 1:8\n" +
|
||||
" <0>\n" +
|
||||
"}>",
|
||||
assertEquals("""
|
||||
<p-code frame: index=0 {
|
||||
-> $U2000:1 = INT_EQUAL r0, r1
|
||||
CBRANCH <0>, $U2000:1
|
||||
r2 = INT_ADD r2, 1:8
|
||||
<0>
|
||||
}>""",
|
||||
frame.toString());
|
||||
|
||||
frame.advance();
|
||||
frame.advance();
|
||||
frame.advance();
|
||||
assertEquals("" +
|
||||
"<p-code frame: index=3 {\n" +
|
||||
" $U2000:1 = INT_EQUAL r0, r1\n" +
|
||||
" CBRANCH <0>, $U2000:1\n" +
|
||||
" r2 = INT_ADD r2, 1:8\n" +
|
||||
" <0>\n" +
|
||||
" *> fall-through\n" +
|
||||
"}>",
|
||||
assertEquals("""
|
||||
<p-code frame: index=3 {
|
||||
$U2000:1 = INT_EQUAL r0, r1
|
||||
CBRANCH <0>, $U2000:1
|
||||
r2 = INT_ADD r2, 1:8
|
||||
<0>
|
||||
*> fall-through
|
||||
}>""",
|
||||
frame.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFrameToStringLoop() throws Exception {
|
||||
PcodeFrame frame = frame(SAMPLE_LOOP);
|
||||
assertEquals("" +
|
||||
"<p-code frame: index=0 {\n" +
|
||||
" <0>\n" +
|
||||
" -> r0 = INT_ADD r0, 1:8\n" +
|
||||
" $U2080:1 = INT_EQUAL r0, r1\n" +
|
||||
" CBRANCH <0>, $U2080:1\n" +
|
||||
"}>",
|
||||
assertEquals("""
|
||||
<p-code frame: index=0 {
|
||||
<0>
|
||||
-> r0 = INT_ADD r0, 1:8
|
||||
$U2080:1 = INT_EQUAL r0, r1
|
||||
CBRANCH <0>, $U2080:1
|
||||
}>""",
|
||||
frame.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFrameToStringBranch() throws Exception {
|
||||
PcodeFrame frame = frame(SAMPLE_BRANCH);
|
||||
assertEquals("" +
|
||||
"<p-code frame: index=0 {\n" +
|
||||
" -> BRANCH *[ram]0x1234:8\n" +
|
||||
"}>",
|
||||
assertEquals("""
|
||||
<p-code frame: index=0 {
|
||||
-> BRANCH *[ram]0x1234:8
|
||||
}>""",
|
||||
frame.toString());
|
||||
|
||||
frame.advance();
|
||||
frame.finishAsBranch();
|
||||
assertEquals("" +
|
||||
"<p-code frame: index=-1 branched=0 {\n" +
|
||||
" *> BRANCH *[ram]0x1234:8\n" +
|
||||
"}>",
|
||||
assertEquals("""
|
||||
<p-code frame: index=-1 branched=0 {
|
||||
*> BRANCH *[ram]0x1234:8
|
||||
}>""",
|
||||
frame.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFrameToStringLangUserop() throws Exception {
|
||||
PcodeFrame frame = frame(SAMPLE_LANG_USEROP);
|
||||
assertEquals("" +
|
||||
"<p-code frame: index=0 {\n" +
|
||||
" -> CALLOTHER \"pcodeop_one\", r0\n" +
|
||||
"}>",
|
||||
assertEquals("""
|
||||
<p-code frame: index=0 {
|
||||
-> CALLOTHER \"pcodeop_one\", r0
|
||||
}>""",
|
||||
frame.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFrameToStringLibUserop() throws Exception {
|
||||
PcodeFrame frame = frame(SAMPLE_LIB_USEROP);
|
||||
assertEquals("" +
|
||||
"<p-code frame: index=0 {\n" +
|
||||
" -> CALLOTHER \"__lib_userop\", r0\n" +
|
||||
"}>",
|
||||
assertEquals("""
|
||||
<p-code frame: index=0 {
|
||||
-> CALLOTHER \"__lib_userop\", r0
|
||||
}>""",
|
||||
frame.toString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ public class StructuredSleighTest extends AbstractGhidraHeadlessIntegrationTest
|
|||
}
|
||||
};
|
||||
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)
|
||||
|
@ -90,7 +90,7 @@ public class StructuredSleighTest extends AbstractGhidraHeadlessIntegrationTest
|
|||
}
|
||||
};
|
||||
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
|
||||
|
@ -103,10 +103,10 @@ public class StructuredSleighTest extends AbstractGhidraHeadlessIntegrationTest
|
|||
}
|
||||
};
|
||||
SleighPcodeUseropDefinition<Object> myUserop = ss.generate().get("my_userop");
|
||||
assertEquals(List.of("" +
|
||||
"local my_var:4;\n" +
|
||||
"__op_output = (my_var * 0x2:4);\n"),
|
||||
myUserop.getLines());
|
||||
assertEquals("""
|
||||
local my_var:4;
|
||||
__op_output = (my_var * 0x2:4);
|
||||
""", myUserop.getBody());
|
||||
// Verify the source compiles
|
||||
myUserop.programFor(new Varnode(r0.getAddress(), r0.getNumBytes()), List.of(),
|
||||
PcodeUseropLibrary.NIL);
|
||||
|
@ -121,7 +121,7 @@ public class StructuredSleighTest extends AbstractGhidraHeadlessIntegrationTest
|
|||
}
|
||||
};
|
||||
SleighPcodeUseropDefinition<Object> myUserop = ss.generate().get("my_userop");
|
||||
assertEquals(List.of(""), myUserop.getLines());
|
||||
assertEquals("", myUserop.getBody());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -137,14 +137,14 @@ public class StructuredSleighTest extends AbstractGhidraHeadlessIntegrationTest
|
|||
}
|
||||
};
|
||||
SleighPcodeUseropDefinition<Object> myUserop = ss.generate().get("my_userop");
|
||||
assertEquals(List.of("" +
|
||||
"if 0x1:1 goto <L1>;\n" +
|
||||
"tmp = 0x2:4;\n" +
|
||||
"goto <L2>;\n" +
|
||||
"<L1>\n" +
|
||||
"tmp = 0x1:4;\n" +
|
||||
"<L2>\n"),
|
||||
myUserop.getLines());
|
||||
assertEquals("""
|
||||
if 0x1:1 goto <L1>;
|
||||
tmp = 0x2:4;
|
||||
goto <L2>;
|
||||
<L1>
|
||||
tmp = 0x1:4;
|
||||
<L2>
|
||||
""", myUserop.getBody());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -158,11 +158,11 @@ public class StructuredSleighTest extends AbstractGhidraHeadlessIntegrationTest
|
|||
}
|
||||
};
|
||||
SleighPcodeUseropDefinition<Object> myUserop = ss.generate().get("my_userop");
|
||||
assertEquals(List.of("" +
|
||||
"if (!0x1:1) goto <L1>;\n" +
|
||||
"tmp = 0x1:4;\n" +
|
||||
"<L1>\n"),
|
||||
myUserop.getLines());
|
||||
assertEquals("""
|
||||
if (!0x1:1) goto <L1>;
|
||||
tmp = 0x1:4;
|
||||
<L1>
|
||||
""", myUserop.getBody());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -179,17 +179,18 @@ public class StructuredSleighTest extends AbstractGhidraHeadlessIntegrationTest
|
|||
}
|
||||
};
|
||||
SleighPcodeUseropDefinition<Object> myUserop = ss.generate().get("my_userop");
|
||||
assertEquals(List.of("" + "local i:4;\n" +
|
||||
"local sum:4;\n" +
|
||||
"i = 0x0:4;\n" +
|
||||
"<L2>\n" +
|
||||
"if (i >= n) goto <L1>;\n" +
|
||||
"sum = (sum + i);\n" +
|
||||
"i = (i + 0x1:4);\n" +
|
||||
"goto <L2>;\n" +
|
||||
"<L1>\n" +
|
||||
"__op_output = sum;\n"),
|
||||
myUserop.getLines());
|
||||
assertEquals("""
|
||||
local i:4;
|
||||
local sum:4;
|
||||
i = 0x0:4;
|
||||
<L2>
|
||||
if (i >= n) goto <L1>;
|
||||
sum = (sum + i);
|
||||
i = (i + 0x1:4);
|
||||
goto <L2>;
|
||||
<L1>
|
||||
__op_output = sum;
|
||||
""", myUserop.getBody());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -209,19 +210,19 @@ public class StructuredSleighTest extends AbstractGhidraHeadlessIntegrationTest
|
|||
}
|
||||
};
|
||||
SleighPcodeUseropDefinition<Object> myUserop = ss.generate().get("my_userop");
|
||||
assertEquals(List.of("" +
|
||||
"local i:4;\n" +
|
||||
"local sum:4;\n" +
|
||||
"i = 0x0:4;\n" +
|
||||
"<L2>\n" +
|
||||
"if (i >= n) goto <L1>;\n" +
|
||||
"sum = (sum + i);\n" +
|
||||
"if (sum >= 0x3e8:4) goto <L1>;\n" +
|
||||
"i = (i + 0x1:4);\n" +
|
||||
"goto <L2>;\n" +
|
||||
"<L1>\n" +
|
||||
"__op_output = sum;\n"),
|
||||
myUserop.getLines());
|
||||
assertEquals("""
|
||||
local i:4;
|
||||
local sum:4;
|
||||
i = 0x0:4;
|
||||
<L2>
|
||||
if (i >= n) goto <L1>;
|
||||
sum = (sum + i);
|
||||
if (sum >= 0x3e8:4) goto <L1>;
|
||||
i = (i + 0x1:4);
|
||||
goto <L2>;
|
||||
<L1>
|
||||
__op_output = sum;
|
||||
""", myUserop.getBody());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -233,7 +234,7 @@ public class StructuredSleighTest extends AbstractGhidraHeadlessIntegrationTest
|
|||
}
|
||||
};
|
||||
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.
|
||||
// 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.assertTrue;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
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 ProgramLocation(program, tb.addr(0x00400000)), 0x1000, false);
|
||||
thread = tb.getOrAddThread("Threads[0]", 0);
|
||||
tb.exec(0, 0, thread, List.of(
|
||||
"RIP = 0x55550000;"));
|
||||
tb.exec(0, 0, thread, "RIP = 0x55550000;");
|
||||
}
|
||||
waitForDomainObject(tb.trace);
|
||||
waitForPass(() -> assertEquals(new ProgramLocation(program, tb.addr(0x00400000)),
|
||||
|
|
|
@ -194,7 +194,7 @@ public class TaintPcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTes
|
|||
public void testTaintViaSleigh() throws Exception {
|
||||
prepareEmulator();
|
||||
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 =
|
||||
emulator.getSharedState().getVar(space, 0x00400000, 8, true);
|
||||
|
|
|
@ -63,7 +63,7 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
@Test
|
||||
public void testReadStateMemory() throws Throwable {
|
||||
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()) {
|
||||
TracePropertyMap<String> taintMap = tb.trace.getAddressPropertyManager()
|
||||
|
@ -73,7 +73,7 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
|
||||
TaintTracePcodeEmulator emu = new TaintTracePcodeEmulator(tb.trace, 0);
|
||||
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 =
|
||||
emuThread.getState().getVar(tb.language.getRegister("RAX"));
|
||||
|
@ -89,7 +89,7 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
@Test
|
||||
public void testReadStateRegister() throws Throwable {
|
||||
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 regEBX = tb.language.getRegister("EBX");
|
||||
|
||||
|
@ -103,7 +103,7 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
|
||||
TaintTracePcodeEmulator emu = new TaintTracePcodeEmulator(tb.trace, 0);
|
||||
PcodeThread<Pair<byte[], TaintVec>> emuThread = emu.newThread(thread.getPath());
|
||||
emuThread.getExecutor().executeSleighLine("RAX = RBX");
|
||||
emuThread.getExecutor().executeSleigh("RAX = RBX;");
|
||||
|
||||
Pair<byte[], TaintVec> valRAX =
|
||||
emuThread.getState().getVar(regRAX);
|
||||
|
@ -119,7 +119,7 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
@Test
|
||||
public void testWriteStateMemory() throws Throwable {
|
||||
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);
|
||||
TaintVec taintVal = TaintVec.empties(8);
|
||||
|
@ -146,7 +146,7 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
public void testWriteStateRegister() throws Throwable {
|
||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||
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);
|
||||
PcodeThread<Pair<byte[], TaintVec>> emuThread = emu.newThread(thread.getPath());
|
||||
|
@ -176,9 +176,9 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
public void testEmptyTaintClears() throws Throwable {
|
||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||
AddressSpace ram = tb.language.getAddressFactory().getDefaultAddressSpace();
|
||||
TraceThread thread = initTrace(tb,
|
||||
List.of(
|
||||
"RIP = 0x00400000;"),
|
||||
TraceThread thread = initTrace(tb, """
|
||||
RIP = 0x00400000;
|
||||
""",
|
||||
List.of(
|
||||
"MOV qword ptr [0x00600000], RAX",
|
||||
"MOV qword ptr [0x00600000], RBX"));
|
||||
|
@ -214,9 +214,9 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
@Test
|
||||
public void testZeroByXor() throws Throwable {
|
||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||
TraceThread thread = initTrace(tb,
|
||||
List.of(
|
||||
"RIP = 0x00400000;"),
|
||||
TraceThread thread = initTrace(tb, """
|
||||
RIP = 0x00400000;
|
||||
""",
|
||||
List.of(
|
||||
"XOR RAX, RAX"));
|
||||
|
||||
|
@ -245,9 +245,9 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
@Test
|
||||
public void testZeroByXorVia32() throws Throwable {
|
||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||
TraceThread thread = initTrace(tb,
|
||||
List.of(
|
||||
"RIP = 0x00400000;"),
|
||||
TraceThread thread = initTrace(tb, """
|
||||
RIP = 0x00400000;
|
||||
""",
|
||||
List.of(
|
||||
"XOR EAX, EAX"));
|
||||
|
||||
|
|
Loading…
Reference in a new issue