GP-4241: Port EmulateInstructionStateModifiers to PcodeUseropLibraryFactories.

This commit is contained in:
Dan
2026-03-18 12:09:45 +00:00
parent 7afd08a2e2
commit fa23479747
69 changed files with 1438 additions and 88 deletions

View File

@@ -0,0 +1,47 @@
/* ###
* 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.emu.stdoplib;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.pcode.exec.*;
import ghidra.pcode.exec.PcodeUseropLibraryFactory.UseropLibrary;
// This treads on GP-4240 a bit. Still, enough to demonstrate the framework can support it.
@UseropLibrary("trig")
public class TrigPcodeUseropLibraryFactory implements PcodeUseropLibraryFactory {
@Override
@SuppressWarnings("unchecked")
public <T> PcodeUseropLibrary<T> create(SleighLanguage language,
PcodeArithmetic<T> arithmetic) {
return (PcodeUseropLibrary<T>) TrigPcodeUseropLibrary.INSTANCE;
}
public static class TrigPcodeUseropLibrary<T> extends AnnotatedPcodeUseropLibrary<T> {
public static final TrigPcodeUseropLibrary<?> INSTANCE = new TrigPcodeUseropLibrary<>();
@PcodeUserop(functional = true)
public float sin(float a) {
return (float) Math.sin(a);
}
// GP-5339: This won't work until we support overloaded userops
@PcodeUserop(functional = true)
public double sin(double a) {
return Math.sin(a);
}
}
}

View File

@@ -20,6 +20,7 @@ import java.util.*;
import java.util.stream.Collectors;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.program.model.lang.GhidraLanguagePropertyKeys;
import ghidra.util.Msg;
import ghidra.util.classfinder.ClassSearcher;
import ghidra.util.classfinder.ExtensionPoint;
@@ -33,7 +34,7 @@ import ghidra.util.classfinder.ExtensionPoint;
*/
public interface PcodeUseropLibraryFactory extends ExtensionPoint {
/** The property key for useropLib ids in pspec files */
public static final String KEY_USEROP_LIBS = "useropLibs";
public static final String KEY_USEROP_LIBS = GhidraLanguagePropertyKeys.USEROP_LIBS;
/**
* A required annotation for identifying the library in pspec files

View File

@@ -0,0 +1,243 @@
/* ###
* 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.exec;
import static org.junit.Assert.assertEquals;
import java.math.BigInteger;
import java.util.*;
import org.junit.AssumptionViolatedException;
import org.junit.Before;
import generic.test.AbstractGenericTest;
import ghidra.app.plugin.assembler.*;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.pcode.emu.*;
import ghidra.pcode.emulate.BreakTableCallBack;
import ghidra.pcode.emulate.Emulate;
import ghidra.pcode.exec.PcodeArithmetic.Purpose;
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
import ghidra.pcode.memstate.*;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.Register;
import ghidra.program.model.pcode.PcodeOp;
import ghidra.util.Msg;
import ghidra.util.NumericUtilities;
import ghidra.util.classfinder.ClassSearcher;
import ghidra.util.exception.MultipleCauses;
import ghidra.util.task.ConsoleTaskMonitor;
import ghidra.util.task.TaskMonitor;
public class AbstractEmulationEquivalenceTest extends AbstractGenericTest {
protected static final TaskMonitor MONITOR = new ConsoleTaskMonitor();
protected static class TestMemoryFaultHandler implements MemoryFaultHandler {
@Override
public boolean uninitializedRead(Address address, int size, byte[] buf, int bufOffset) {
return false;
}
@Override
public boolean unknownAddress(Address address, boolean write) {
return false;
}
}
protected interface DoAsm {
void accept(AssemblyBuffer buf) throws Exception;
}
@Before
public void setupSearch() throws Exception {
ClassSearcher.search(MONITOR);
}
protected long getEntryOffset() {
return 0x00400000;
}
protected void doTestEquivOld(SleighLanguage language, Map<String, String> init,
AssemblyBuffer buf, int count, Map<String, String> expected) throws Exception {
Address entry = buf.getEntry();
MemoryState state = new DefaultMemoryState(language);
Emulate emu = new Emulate(language, state, new BreakTableCallBack(language));
AddressSet regsUnchecked = new AddressSet();
state.setMemoryBank(new MemoryPageBank(language.getAddressFactory().getRegisterSpace(),
language.isBigEndian(), 0x1000, new TestMemoryFaultHandler()) {
@Override
public void setChunk(long offset, int size, byte[] val) {
super.setChunk(offset, size, val);
try {
regsUnchecked.add(new AddressRangeImpl(getSpace().getAddress(offset), size));
}
catch (AddressOverflowException | AddressOutOfBoundsException e) {
throw new AssertionError(e);
}
}
});
state.setMemoryBank(new MemoryPageBank(language.getDefaultSpace(),
language.isBigEndian(), 0x1000, new TestMemoryFaultHandler()) {
@Override
public void setChunk(long offset, int size, byte[] val) {
/*Msg.info(this, "Old set ram[0x%x]:%d = %s".formatted(offset, size,
NumericUtilities.convertBytesToString(val)));*/
super.setChunk(offset, size, val);
}
});
byte[] bytes = buf.getBytes();
state.setChunk(bytes, language.getDefaultSpace(), entry.getOffset(), bytes.length);
for (Map.Entry<String, String> ent : init.entrySet()) {
state.setValue(ent.getKey(), new BigInteger(ent.getValue(), 16));
}
emu.setExecuteAddress(entry);
for (int i = 0; i < count; i++) {
emu.executeInstruction(false, MONITOR);
}
for (Map.Entry<String, String> ent : expected.entrySet()) {
assertEquals("Old register value mismatch on " + ent.getKey(), ent.getValue(),
state.getBigInteger(ent.getKey()).toString(16));
Register reg = language.getRegister(ent.getKey());
if (!reg.getAddressSpace().isRegisterSpace()) {
continue;
}
regsUnchecked.delete(new AddressRangeImpl(reg.getAddress(), reg.getNumBytes()));
}
if (!regsUnchecked.isEmpty()) {
Set<String> regs = new TreeSet<>();
nextAddr: while (!regsUnchecked.isEmpty()) {
Address min = regsUnchecked.getMinAddress();
List<Register> found = Arrays.asList(language.getRegisters(min));
found.sort((r1, r2) -> r1.getBitLength() - r2.getBitLength());
for (Register r : found) {
AddressRange rng = new AddressRangeImpl(r.getAddress(), r.getNumBytes());
if (!regsUnchecked.contains(rng.getMinAddress(), rng.getMaxAddress())) {
continue;
}
regs.add(r.getName());
regsUnchecked.delete(rng);
continue nextAddr;
}
regsUnchecked.delete(min, min);
}
if (!regs.isEmpty()) {
throw new AssertionError("Some written registers were not asserted: " + regs);
}
}
}
protected void doTestEquivNew(SleighLanguage language, Map<String, String> init,
AssemblyBuffer buf, int count, Map<String, String> expected) throws Exception {
Address entry = buf.getEntry();
@SuppressWarnings("unused") // uncomment arg to PcodeEmulator to enable
PcodeEmulationCallbacks<byte[]> cb = new PcodeEmulationCallbacks<>() {
public <A, U> void dataWritten(PcodeThread<byte[]> thread,
PcodeExecutorStatePiece<A, U> piece, Address address, int length, U value) {
if (!address.isMemoryAddress()) {
return;
}
if (!(value instanceof byte[] v)) {
return;
}
Msg.info(this, "New set ram[0x%x]:%d = %s".formatted(address.getOffset(), length,
NumericUtilities.convertBytesToString(v)));
};
};
PcodeEmulator emu = new PcodeEmulator(language/*, cb*/) {
@Override
protected BytesPcodeThread createThread(String name) {
/**
* TODO: There's a branch somewhere that will make this not work.
*/
return new BytesPcodeThread(name, this) {
@Override
protected boolean onMissingUseropDef(PcodeOp op, String opName) {
return false;
}
};
}
};
byte[] bytes = buf.getBytes();
emu.getSharedState().setVar(entry, bytes.length, false, bytes);
PcodeThread<byte[]> thread = emu.newThread();
PcodeExecutorState<byte[]> state = thread.getState();
PcodeArithmetic<byte[]> arithmetic = thread.getArithmetic();
for (Map.Entry<String, String> ent : init.entrySet()) {
Register reg = language.getRegister(ent.getKey());
state.setVar(reg,
arithmetic.fromConst(new BigInteger(ent.getValue(), 16), reg.getNumBytes()));
}
thread.setCounter(entry);
thread.overrideContextWithDefault();
thread.stepInstruction(count);
for (Map.Entry<String, String> ent : expected.entrySet()) {
Register reg = language.getRegister(ent.getKey());
assertEquals("New register value mismatch on " + ent.getKey(), ent.getValue(),
arithmetic.toBigInteger(state.getVar(reg, Reason.INSPECT), Purpose.INSPECT)
.toString(16));
}
}
protected void doTestEquiv(SleighLanguage language, Map<String, String> init, DoAsm doAsm,
int count, Map<String, String> expected) throws Exception {
//Msg.info(this, "Language: " + language.getLanguageID());
Assembler asm = Assemblers.getAssembler(language);
Address entry = language.getDefaultSpace().getAddress(getEntryOffset());
AssemblyBuffer buf = new AssemblyBuffer(asm, entry);
doAsm.accept(buf);
AssertionError oldFailure = null;
AssertionError newFailure = null;
try {
doTestEquivOld(language, init, buf, count, expected);
}
catch (AssertionError e) {
oldFailure = e;
Msg.error("Old failed: " + e, e);
}
try {
doTestEquivNew(language, init, buf, count, expected);
}
catch (AssertionError e) {
newFailure = e;
Msg.error("New failed: " + e, e);
}
if (newFailure != null && oldFailure != null) {
throw new AssertionError("Both old and new failed",
new MultipleCauses(List.of(oldFailure, newFailure)));
}
if (newFailure != null) {
throw newFailure;
}
if (oldFailure != null) {
throw new AssumptionViolatedException(
"Old failed, but new passed: " + oldFailure.getMessage(), oldFailure);
}
}
}

View File

@@ -4,9 +4,9 @@
* 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.
@@ -89,6 +89,16 @@ public final class GhidraLanguagePropertyKeys {
public static final String EMULATE_INSTRUCTION_STATE_MODIFIER_CLASS =
"emulateInstructionStateModifierClass";
/**
* USEROP_LIBS is a string property that indicates keys for matching one or more
* {@code PcodeUseropLibaryFactory}s, which will be composed to form the library of custom
* userop implementations available to an emulator. The default is empty. NOTE: This is
* <em>not</em> the name of a class, but a comma-separated list of IDs. Each factory is also
* tagged with a list of IDs. If any ID matches, then that factory is given a chance to
* contribute userops.
*/
public static final String USEROP_LIBS = "useropLibs";
/**
* PCODE_INJECT_LIBRARY_CLASS indicates the classname of a PcodeInjectLibrary implementation
* that is used to generate p-code injection payloads which can replace either CALLs or CALLOTHERs

View File

@@ -3,6 +3,7 @@
<processor_spec>
<properties>
<property key="emulateInstructionStateModifierClass" value="ghidra.program.emulation.m68kEmulateInstructionStateModifier"/>
<property key="useropLibs" value="m68k,trig"/>
<property key="assemblyRating:68000:BE:32:default" value="PLATINUM"/>
</properties>
<programcounter register="PC"/>

View File

@@ -0,0 +1,29 @@
/* ###
* 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.program.emulation;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.pcode.exec.*;
import ghidra.pcode.exec.PcodeUseropLibraryFactory.UseropLibrary;
@UseropLibrary("m68k")
public class M68kPcodeUseropLibraryFactory implements PcodeUseropLibraryFactory {
@Override
public <T> PcodeUseropLibrary<T> create(SleighLanguage language,
PcodeArithmetic<T> arithmetic) {
return PcodeUseropLibrary.nil();
}
}

View File

@@ -22,6 +22,7 @@ import ghidra.pcode.memstate.MemoryState;
import ghidra.pcodeCPort.error.LowlevelError;
import ghidra.program.model.pcode.Varnode;
@Deprecated(forRemoval = true, since = "12.1")
public class m68kEmulateInstructionStateModifier extends EmulateInstructionStateModifier {
/*

View File

@@ -25,6 +25,7 @@ import ghidra.pcode.memstate.MemoryState;
import ghidra.program.model.pcode.Varnode;
//import ghidra.pcode.emulate.callother.SignalingNaNOpBehavior;
@Deprecated(forRemoval = true, since = "12.1")
public class AARCH64EmulateInstructionStateModifier extends EmulateInstructionStateModifier {
public AARCH64EmulateInstructionStateModifier(Emulate emu) {

View File

@@ -27,25 +27,25 @@ import ghidra.program.model.pcode.Varnode;
* https://developer.arm.com/documentation/ddi0602/2024-12/SIMD-FP-Instructions/TBL--Table-vector-lookup-
*/
@UseropLibrary("aarch64")
public class AARCH64PcodeUseropLibraryFactory implements PcodeUseropLibraryFactory {
public class Aarch64PcodeUseropLibraryFactory implements PcodeUseropLibraryFactory {
@Override
public <T> PcodeUseropLibrary<T> create(SleighLanguage language,
PcodeArithmetic<T> arithmetic) {
return new AARCH64PcodeUseropLibrary<>(language);
return new Aarch64PcodeUseropLibrary<>(language);
}
public static class AARCH64PcodeUseropLibrary<T> extends DefaultPcodeUseropLibrary<T> {
public AARCH64PcodeUseropLibrary(SleighLanguage language) {
public static class Aarch64PcodeUseropLibrary<T> extends AnnotatedPcodeUseropLibrary<T> {
public Aarch64PcodeUseropLibrary(SleighLanguage language) {
SleighPcodeUseropDefinition.Factory factory =
new SleighPcodeUseropDefinition.Factory(language);
putOp(factory.define("MP_INT_ABS").params("n").body(args -> """
if (n >= 0) goto <pos>;
__op_output = -n;
goto <done>;
<pos>:
goto <done>;
<pos>
__op_output = n;
<done>:
<done>
""").build());
putOp(factory.define("SIMD_PIECE").params("simdBytes", "offset").body(args -> """
@@ -74,7 +74,7 @@ public class AARCH64PcodeUseropLibraryFactory implements PcodeUseropLibraryFacto
return "local table:16 = %s;\n".formatted(regs[0]);
}
int size = 16; // Table is always made up of 16-byte (128-bit) regs
StringBuffer buf = new StringBuffer();
StringBuilder buf = new StringBuilder();
buf.append("local table:%d;\n".formatted(size * regs.length));
for (int i = 0; i < regs.length; i++) {
buf.append("table[%d,%d] = %s;\n".formatted(8 * size * i, 8 * size, regs[i]));
@@ -84,7 +84,7 @@ public class AARCH64PcodeUseropLibraryFactory implements PcodeUseropLibraryFacto
protected String genIndex(int size, int regCount) {
int tableSize = 16 * regCount;
StringBuffer buf = new StringBuffer();
StringBuilder buf = new StringBuilder();
buf.append("local indicies:%d = m;\n".formatted(size));
buf.append("local result:%d = init;\n".formatted(size));
for (int i = 0; i < size; i++) {
@@ -103,5 +103,19 @@ public class AARCH64PcodeUseropLibraryFactory implements PcodeUseropLibraryFacto
buf.append("__op_output = result;");
return buf.toString();
}
@PcodeUserop(functional = true)
public void CallSecureMonitor(int imm16) {
}
@PcodeUserop(functional = true)
public int ExclusiveMonitorPass(long addr, int rsize) {
return 0;
}
@PcodeUserop(functional = true)
public byte ExclusiveMonitorsStatus() {
return 0;
}
}
}

View File

@@ -45,7 +45,7 @@ import ghidra.util.exception.MultipleCauses;
import ghidra.util.task.ConsoleTaskMonitor;
import ghidra.util.task.TaskMonitor;
public class AARCH64PcodeLibraryTest extends AbstractGhidraHeadlessIntegrationTest {
public class Aarch64PcodeLibraryTest extends AbstractGhidraHeadlessIntegrationTest {
static final LanguageID LANG_ID_AARCH64 = new LanguageID("AARCH64:LE:64:v8A");
private SleighLanguage aarch64;

View File

@@ -293,19 +293,20 @@
<pentry minsize="1" maxsize="500" align="4">
<addr offset="0" space="stack"/>
</pentry>
</input>
<output killedbycall="true">
<pentry minsize="1" maxsize="4">
<register name="r0"/>
</pentry>
</output>
<unaffected>
<register name="sp"/>
</unaffected>
</prototype>
</input>
<output killedbycall="true">
<pentry minsize="1" maxsize="4">
<register name="r0"/>
</pentry>
</output>
<unaffected>
<register name="sp"/>
</unaffected>
</prototype>
<callotherfixup targetop="setISAMode">
<pcode incidentalcopy="true">
<input name="newTB"/>
<!-- NOP -->
<body><![CDATA[
r0 = r0;
@@ -338,8 +339,7 @@
r12 = lr + r3;
ISAModeSwitch = (r12 & 1) != 1;
TB = ISAModeSwitch;
TB = (r12 & 1) != 1;
pc = r12 & 0xfffffffe;
goto [pc];
]]></body>
@@ -356,8 +356,7 @@
offset = *:1 (tmpptr + r0);
lr = lr + 2 * zext(offset);
ISAModeSwitch = (lr & 1) != 0;
TB = ISAModeSwitch;
TB = (lr & 1) != 0;
pc = lr & 0xfffffffe;
goto [pc];
]]></body>
@@ -374,8 +373,7 @@
offset = *:1 (tmpptr + r0);
lr = lr + 2 * sext(offset);
ISAModeSwitch = (lr & 1) != 0;
TB = ISAModeSwitch;
TB = (lr & 1) != 0;
pc = lr & 0xfffffffe;
goto [pc];
]]></body>
@@ -393,8 +391,7 @@
offset = *:2 (tmpptr + index);
lr = lr + 2 * sext(offset);
ISAModeSwitch = (lr & 1) != 0;
TB = ISAModeSwitch;
TB = (lr & 1) != 0;
pc = lr & 0xfffffffe;
goto [pc];
]]></body>
@@ -412,8 +409,7 @@
offset = *:2 (tmpptr + index);
lr = lr + 2 * zext(offset);
ISAModeSwitch = (lr & 1) != 0;
TB = ISAModeSwitch;
TB = (lr & 1) != 0;
pc = lr & 0xfffffffe;
goto [pc];
]]></body>
@@ -432,8 +428,7 @@
offset = offset * 4;
lr = lr + offset;
ISAModeSwitch = (lr & 1) != 0;
TB = ISAModeSwitch;
TB = (lr & 1) != 0;
pc = lr & 0xfffffffe;
goto [pc];
]]></body>

View File

@@ -15,7 +15,6 @@ define register offset=0x0084 size=4 [ r14_svc r13_svc spsr_svc ];
define register offset=0x0090 size=8 [ mult_dat8 ]; # Special internal register for dealing with multiple stores/loads
define register offset=0x0090 size=16 [ mult_dat16 ]; # Special internal register for dealing with multiple stores/loads
define register offset=0x00A0 size=4 [ fpsr ]; # floating point state register (for FPA10 floating-point accelerator)
define register offset=0x0078 size=1 [ ISAModeSwitch ]; # generic name for TB ThumbBit - set same as TB
@define FPSCR_N "fpscr[31,1]"
@define FPSCR_Z "fpscr[30,1]"
@@ -193,7 +192,7 @@ define pcodeop ReverseBitOrder;
define pcodeop SendEvent;
define pcodeop setEndianState;
# Copies ISAModeSwitch to TMode
# Copies TB to TMode
define pcodeop setISAMode;
macro affectflags() {
@@ -204,14 +203,9 @@ macro affect_resflags() {
ZR = tmpZR; NG = tmpNG;
}
macro SetISAModeSwitch(value) {
ISAModeSwitch = value;
TB = ISAModeSwitch;
}
macro SetThumbMode(value) {
SetISAModeSwitch(value);
setISAMode();
TB = value;
setISAMode(TB);
}
#

View File

@@ -7,6 +7,7 @@
<property key="useNewFunctionStackAnalysis" value="true"/>
<property key="enableContiguousFunctionsOnly" value="false"/>
<property key="emulateInstructionStateModifierClass" value="ghidra.program.emulation.ARMEmulateInstructionStateModifier"/>
<property key="useropLibs" value="arm"/>
</properties>
<programcounter register="pc"/>
<context_data>
@@ -18,7 +19,11 @@
<set name="spsr" val="0"/>
</tracked_set>
</context_data>
<register_data>
<register name="TB" alias="ISAModeSwitch"/>
</register_data>
<default_symbols>
<symbol name="MasterStackPointer" address="ram:0x0" entry="false" type="code_ptr"/>
<symbol name="Reset" address="ram:0x4" entry="true" type="code_ptr"/>

View File

@@ -162,6 +162,7 @@
<callotherfixup targetop="setISAMode">
<pcode incidentalcopy="true">
<input name="newTB"/>
<!-- NOP -->
<body><![CDATA[
r0 = r0;
@@ -194,8 +195,7 @@
r12 = lr + r3;
ISAModeSwitch = (r12 & 1) != 1;
TB = ISAModeSwitch;
TB = (r12 & 1) != 1;
pc = r12 & 0xfffffffe;
goto [pc];
]]></body>
@@ -212,8 +212,7 @@
offset = *:1 (tmpptr + r0);
lr = lr + 2 * zext(offset);
ISAModeSwitch = (lr & 1) != 0;
TB = ISAModeSwitch;
TB = (lr & 1) != 0;
pc = lr & 0xfffffffe;
goto [pc];
]]></body>
@@ -230,8 +229,7 @@
offset = *:1 (tmpptr + r0);
lr = lr + 2 * sext(offset);
ISAModeSwitch = (lr & 1) != 0;
TB = ISAModeSwitch;
TB = (lr & 1) != 0;
pc = lr & 0xfffffffe;
goto [pc];
]]></body>
@@ -249,8 +247,7 @@
offset = *:2 (tmpptr + index);
lr = lr + 2 * sext(offset);
ISAModeSwitch = (lr & 1) != 0;
TB = ISAModeSwitch;
TB = (lr & 1) != 0;
pc = lr & 0xfffffffe;
goto [pc];
]]></body>
@@ -268,8 +265,7 @@
offset = *:2 (tmpptr + index);
lr = lr + 2 * zext(offset);
ISAModeSwitch = (lr & 1) != 0;
TB = ISAModeSwitch;
TB = (lr & 1) != 0;
pc = lr & 0xfffffffe;
goto [pc];
]]></body>
@@ -288,8 +284,7 @@
offset = offset * 4;
lr = lr + offset;
ISAModeSwitch = (lr & 1) != 0;
TB = ISAModeSwitch;
TB = (lr & 1) != 0;
pc = lr & 0xfffffffe;
goto [pc];
]]></body>

View File

@@ -82,6 +82,7 @@
<callotherfixup targetop="setISAMode">
<pcode incidentalcopy="true">
<input name="newTB"/>
<!-- NOP -->
<body><![CDATA[
r0 = r0;
@@ -113,8 +114,7 @@
r12 = lr + r3;
ISAModeSwitch = (r12 & 1) != 1;
TB = ISAModeSwitch;
TB = (r12 & 1) != 1;
pc = r12 & 0xfffffffe;
goto [pc];
]]></body>
@@ -131,8 +131,7 @@
offset = *:1 (tmpptr + r0);
lr = lr + 2 * zext(offset);
ISAModeSwitch = (lr & 1) != 0;
TB = ISAModeSwitch;
TB = (lr & 1) != 0;
pc = lr & 0xfffffffe;
goto [pc];
]]></body>
@@ -149,8 +148,7 @@
offset = *:1 (tmpptr + r0);
lr = lr + 2 * sext(offset);
ISAModeSwitch = (lr & 1) != 0;
TB = ISAModeSwitch;
TB = (lr & 1) != 0;
pc = lr & 0xfffffffe;
goto [pc];
]]></body>
@@ -168,8 +166,7 @@
offset = *:2 (tmpptr + index);
lr = lr + 2 * sext(offset);
ISAModeSwitch = (lr & 1) != 0;
TB = ISAModeSwitch;
TB = (lr & 1) != 0;
pc = lr & 0xfffffffe;
goto [pc];
]]></body>
@@ -187,8 +184,7 @@
offset = *:2 (tmpptr + index);
lr = lr + 2 * zext(offset);
ISAModeSwitch = (lr & 1) != 0;
TB = ISAModeSwitch;
TB = (lr & 1) != 0;
pc = lr & 0xfffffffe;
goto [pc];
]]></body>
@@ -207,8 +203,7 @@
offset = offset * 4;
lr = lr + offset;
ISAModeSwitch = (lr & 1) != 0;
TB = ISAModeSwitch;
TB = (lr & 1) != 0;
pc = lr & 0xfffffffe;
goto [pc];
]]></body>

View File

@@ -8,6 +8,7 @@
<property key="enableSharedReturnAnalysis" value="false"/>
<property key="enableContiguousFunctionsOnly" value="false"/>
<property key="emulateInstructionStateModifierClass" value="ghidra.program.emulation.ARMEmulateInstructionStateModifier"/>
<property key="useropLibs" value="arm"/>
</properties>
<programcounter register="pc"/>
<context_data>
@@ -18,7 +19,11 @@
<set name="spsr" val="0"/>
</tracked_set>
</context_data>
<register_data>
<register name="TB" alias="ISAModeSwitch"/>
</register_data>
<default_symbols>
<symbol name="Reset" address="ram:0x0" entry="true"/>
<symbol name="UndefinedInstruction" address="ram:0x4" entry="true"/>

View File

@@ -228,6 +228,7 @@
<callotherfixup targetop="setISAMode">
<pcode incidentalcopy="true">
<input name="newTB"/>
<!-- NOP -->
<body><![CDATA[
r0 = r0;

View File

@@ -2317,7 +2317,7 @@ ArmPCRelImmed12: reloff is U23=0 & immed & rotate
:blx HAddr24 is $(AMODE) & CALLoverride=0 & ARMcond=0 & cond=15 & c2527=5 & H24=0 & HAddr24
{
lr = inst_next;
SetISAModeSwitch(1); # TMode done by HAddr24's globalset
SetThumbMode(1); # TMode done by HAddr24's globalset
call HAddr24;
# don't do causes decompiler trouble TB = 0;
} # Always changes to THUMB mode
@@ -2325,7 +2325,7 @@ ArmPCRelImmed12: reloff is U23=0 & immed & rotate
:blx HAddr24 is $(AMODE) & CALLoverride=1 & ARMcond=0 & cond=15 & c2527=5 & H24=0 & HAddr24
{
lr = inst_next;
SetISAModeSwitch(1); # TMode done by HAddr24's globalset
SetThumbMode(1); # TMode done by HAddr24's globalset
goto HAddr24;
} # Always changes to THUMB mode
@@ -2333,7 +2333,7 @@ ArmPCRelImmed12: reloff is U23=0 & immed & rotate
:blx HAddr24 is $(AMODE) & ARMcond=0 & CALLoverride=0 & cond=15 & c2527=5 & H24=1 & HAddr24
{
lr = inst_next;
SetISAModeSwitch(1); # TMode done by HAddr24's globalset
SetThumbMode(1); # TMode done by HAddr24's globalset
call HAddr24;
# don't do causes decompiler trouble TB = 0;
} # Always changes to THUMB mode
@@ -2341,7 +2341,7 @@ ArmPCRelImmed12: reloff is U23=0 & immed & rotate
:blx HAddr24 is $(AMODE) & ARMcond=0 & CALLoverride=1 & cond=15 & c2527=5 & H24=1 & HAddr24
{
lr = inst_next;
SetISAModeSwitch(1); # TMode done by HAddr24's globalset
SetThumbMode(1); # TMode done by HAddr24's globalset
goto HAddr24;
} # Always changes to THUMB mode

View File

@@ -7,6 +7,7 @@
<property key="useNewFunctionStackAnalysis" value="true"/>
<property key="enableContiguousFunctionsOnly" value="false"/>
<property key="emulateInstructionStateModifierClass" value="ghidra.program.emulation.ARMEmulateInstructionStateModifier"/>
<property key="useropLibs" value="arm"/>
<property key="assemblyRating:ARM:BE:32:v7" value="PLATINUM"/>
<property key="assemblyRating:ARM:LE:32:v7" value="PLATINUM"/>
</properties>
@@ -42,6 +43,8 @@
</default_symbols>
<register_data>
<register name="TB" alias="ISAModeSwitch"/>
<register name="q0" group="NEON" vector_lane_sizes="1,2,4"/>
<register name="q1" group="NEON" vector_lane_sizes="1,2,4"/>
<register name="q2" group="NEON" vector_lane_sizes="1,2,4"/>

View File

@@ -8,6 +8,7 @@
<property key="useNewFunctionStackAnalysis" value="true"/>
<property key="enableContiguousFunctionsOnly" value="false"/>
<property key="emulateInstructionStateModifierClass" value="ghidra.program.emulation.ARMEmulateInstructionStateModifier"/>
<property key="useropLibs" value="arm"/>
<property key="assemblyRating:ARM:BE:32:v7" value="PLATINUM"/>
<property key="assemblyRating:ARM:LE:32:v7" value="PLATINUM"/>
</properties>
@@ -43,6 +44,8 @@
</default_symbols>
<register_data>
<register name="TB" alias="ISAModeSwitch"/>
<register name="q0" group="NEON" vector_lane_sizes="1,2,4"/>
<register name="q1" group="NEON" vector_lane_sizes="1,2,4"/>
<register name="q2" group="NEON" vector_lane_sizes="1,2,4"/>

View File

@@ -8,6 +8,7 @@
<property key="enableSharedReturnAnalysis" value="false"/>
<property key="enableContiguousFunctionsOnly" value="false"/>
<property key="emulateInstructionStateModifierClass" value="ghidra.program.emulation.ARMEmulateInstructionStateModifier"/>
<property key="useropLibs" value="arm"/>
</properties>
<programcounter register="pc"/>
<context_data>
@@ -19,7 +20,11 @@
<set name="spsr" val="0"/>
</tracked_set>
</context_data>
<register_data>
<register name="TB" alias="ISAModeSwitch"/>
</register_data>
<default_symbols>
<symbol name="Reset" address="ram:0x0" entry="true"/>
<symbol name="UndefinedInstruction" address="ram:0x4" entry="true"/>

View File

@@ -7,6 +7,7 @@
<property key="useNewFunctionStackAnalysis" value="true"/>
<property key="enableContiguousFunctionsOnly" value="false"/>
<property key="emulateInstructionStateModifierClass" value="ghidra.program.emulation.ARMEmulateInstructionStateModifier"/>
<property key="useropLibs" value="arm"/>
<property key="assemblyRating:ARM:BE:32:v7" value="PLATINUM"/>
<property key="assemblyRating:ARM:LE:32:v7" value="PLATINUM"/>
</properties>
@@ -20,7 +21,11 @@
<set name="spsr" val="0"/>
</tracked_set>
</context_data>
<register_data>
<register name="TB" alias="ISAModeSwitch"/>
</register_data>
<default_symbols>
<symbol name="Reset" address="ram:0x0" entry="true"/>
<symbol name="UndefinedInstruction" address="ram:0x4" entry="true"/>

View File

@@ -26,6 +26,7 @@ import ghidra.program.model.lang.Register;
import ghidra.program.model.lang.RegisterValue;
import ghidra.program.model.pcode.Varnode;
@Deprecated(forRemoval = true, since = "12.1")
public class ARMEmulateInstructionStateModifier extends EmulateInstructionStateModifier {
private Register TModeReg;

View File

@@ -0,0 +1,83 @@
/* ###
* 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.program.emulation;
public class ArmCpuState {
private volatile boolean irqEnabled = true;
private volatile boolean privileged = true;
private volatile long mainStackPointer;
private volatile long processStackPointer;
private volatile boolean threadModePrivileged;
private volatile boolean threadMode;
private volatile long basePriority;
public boolean isIrqEnabled() {
return irqEnabled;
}
public void setIrqEnabled(boolean irqEnabled) {
this.irqEnabled = irqEnabled;
}
public boolean isPrivileged() {
return privileged;
}
public void setPrivileged(boolean privileged) {
this.privileged = privileged;
}
public long getMainStackPointer() {
return mainStackPointer;
}
public void setMainStackPointer(long mainStackPointer) {
this.mainStackPointer = mainStackPointer;
}
public long getProcessStackPointer() {
return processStackPointer;
}
public void setProcessStackPointer(long processStackPointer) {
this.processStackPointer = processStackPointer;
}
public boolean isThreadModePrivileged() {
return threadModePrivileged;
}
public void setThreadModePrivileged(boolean threadModePrivileged) {
this.threadModePrivileged = threadModePrivileged;
}
public boolean isThreadMode() {
return threadMode;
}
public void setThreadMode(boolean threadMode) {
this.threadMode = threadMode;
}
public long getBasePriority() {
return basePriority;
}
public void setBasePriority(long basePriority) {
this.basePriority = basePriority;
}
}

View File

@@ -0,0 +1,117 @@
/* ###
* 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.program.emulation;
import java.math.BigInteger;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.pcode.emu.DefaultPcodeThread.PcodeThreadExecutor;
import ghidra.pcode.exec.*;
import ghidra.pcode.exec.PcodeUseropLibraryFactory.UseropLibrary;
import ghidra.program.model.lang.*;
import ghidra.util.Msg;
@UseropLibrary("arm")
public class ArmPcodeUseropLibraryFactory implements PcodeUseropLibraryFactory {
@Override
public <T> PcodeUseropLibrary<T> create(SleighLanguage language,
PcodeArithmetic<T> arithmetic) {
return new ArmPcodeUseropLibrary<>(language);
}
public static class ArmPcodeUseropLibrary<T> extends AnnotatedPcodeUseropLibrary<T> {
private final RegisterValue tMode;
private final RegisterValue aMode;
// LATER: This should probably be injected
private final ArmCpuState cpuState = new ArmCpuState();
public ArmPcodeUseropLibrary(Language language) {
Register tModeReg = language.getRegister("TMode");
if (tModeReg != null) {
tMode = new RegisterValue(tModeReg, BigInteger.ONE);
aMode = new RegisterValue(tModeReg, BigInteger.ZERO);
}
else {
tMode = null;
aMode = null;
}
}
@PcodeUserop(modifiesContext = true)
public void setISAMode(@OpExecutor PcodeExecutor<T> exec, boolean tb) {
if (!(exec instanceof PcodeThreadExecutor<T> tExec)) {
return;
}
tExec.getThread().overrideContext(tb ? tMode : aMode);
}
@PcodeUserop(functional = true)
public void disableIRQinterrupts() {
cpuState.setIrqEnabled(false);
}
@PcodeUserop(functional = true)
public void enableIRQinterrupts() {
cpuState.setIrqEnabled(true);
}
@PcodeUserop(functional = true, hasSideEffects = false)
public boolean isCurrentModePrivileged() {
return cpuState.isPrivileged();
}
@PcodeUserop(functional = true)
public void setMainStackPointer(long mainStackPointer) {
cpuState.setMainStackPointer(mainStackPointer);
}
@PcodeUserop(functional = true)
public void setProcessStackPointer(long processStackPointer) {
cpuState.setProcessStackPointer(processStackPointer);
}
@PcodeUserop(functional = true, hasSideEffects = false)
public long getProcessStackPointer() {
return cpuState.getProcessStackPointer();
}
@PcodeUserop(functional = true/*Maybe not*/)
public void DataSynchronizationBarrier(int todo) {
Msg.warn(this, "TODO:DataSyncBarrier");
}
@PcodeUserop(functional = true/*Maybe not*/)
public void InstructionSynchronizationBarrier(int todo) {
Msg.warn(this, "TODO:InsSyncBarrier");
}
@PcodeUserop(functional = true)
public void setThreadModePrivileged(boolean privileged) {
cpuState.setThreadModePrivileged(privileged);
}
@PcodeUserop(functional = true, hasSideEffects = false)
public boolean isThreadMode() {
return cpuState.isThreadMode();
}
@PcodeUserop(functional = true)
public void setBasePriority(long basePriority) {
cpuState.setBasePriority(basePriority);
}
}
}

View File

@@ -919,9 +919,12 @@ DXuPos: pos is lsb [ pos = lsb + 32; ] { tmp:1
DinsXSize: mysize is msbd & lsb [ mysize = msbd - lsb + 1 + 32; ] { tmp:1 = mysize; export tmp; }
@endif
define pcodeop setISAMode;
macro JXWritePC(addr) {
@ifdef ISA_VARIANT
ISAModeSwitch = (addr & 0x1) != 0;
setISAMode(ISAModeSwitch);
tmp:$(REGSIZE) = -2;
tmp = tmp & addr;
pc = tmp;

View File

@@ -639,9 +639,10 @@ SAVE_TOP: SAVE_ARG^EXT_FRAME^SAVE_RA^SAVE_SREG^SAVE_STAT is EXT_FRAME & SAVE_RA
:jalx Abs26_m16 is ISA_MODE=1 & RELP=1 & ext_isjal=1 & ext_tgt_x=1 & Abs26_m16
[ ext_delay=0b10; ISA_MODE = 0; globalset(Abs26_m16, ISA_MODE); globalset(inst_next, ext_delay); ] {
ra = inst_next | 0x1;
ra = inst_next | 0x1;
delayslot( 1 );
ISAModeSwitch = 0;
ISAModeSwitch = 0;
setISAMode(ISAModeSwitch);
call Abs26_m16;
}

View File

@@ -4,6 +4,7 @@
<properties>
<property key="addressesDoNotAppearDirectlyInCode" value="true"/>
<property key="emulateInstructionStateModifierClass" value="ghidra.program.emulation.MIPSEmulateInstructionStateModifier"/>
<property key="useropLibs" value="mips"/>
<property key="assemblyRating:MIPS:BE:32:default" value="PLATINUM"/>
</properties>
<programcounter register="pc"/>

View File

@@ -1018,6 +1018,7 @@ define pcodeop SYNC;
ra = inst_next;
delayslot( 1 );
ISAModeSwitch = 1;
setISAMode(ISAModeSwitch);
call Abs26;
}
@endif

View File

@@ -4,6 +4,7 @@
<properties>
<property key="addressesDoNotAppearDirectlyInCode" value="true"/>
<property key="emulateInstructionStateModifierClass" value="ghidra.program.emulation.MIPSEmulateInstructionStateModifier"/>
<property key="useropLibs" value="mips"/>
<property key="assemblyRating:MIPS:BE:32:R6" value="PLATINUM"/>
</properties>
<programcounter register="pc"/>

View File

@@ -154,5 +154,15 @@
</localrange>
</prototype>
</default_proto>
<callotherfixup targetop="setISAMode">
<pcode incidentalcopy="true">
<input name="newMode"/>
<!-- NOP -->
<body><![CDATA[
v0 = v0;
]]></body>
</pcode>
</callotherfixup>
</compiler_spec>

View File

@@ -84,5 +84,15 @@
</localrange>
</prototype>
</default_proto>
<callotherfixup targetop="setISAMode">
<pcode incidentalcopy="true">
<input name="newMode"/>
<!-- NOP -->
<body><![CDATA[
v0 = v0;
]]></body>
</pcode>
</callotherfixup>
</compiler_spec>

View File

@@ -183,6 +183,15 @@
<register name="gp"/> <!-- Compilers may save gp to the stack before a call and restore it afterward -->
</internal_storage>
</prototype>
<callotherfixup targetop="setISAMode">
<pcode incidentalcopy="true">
<input name="newMode"/>
<!-- NOP -->
<body><![CDATA[
v0 = v0;
]]></body>
</pcode>
</callotherfixup>
</compiler_spec>

View File

@@ -174,5 +174,15 @@
<register name="gp"/> <!-- Compilers may save gp to the stack before a call and restore it afterward -->
</internal_storage>
</prototype>
<callotherfixup targetop="setISAMode">
<pcode incidentalcopy="true">
<input name="newMode"/>
<!-- NOP -->
<body><![CDATA[
v0 = v0;
]]></body>
</pcode>
</callotherfixup>
</compiler_spec>

View File

@@ -4,6 +4,7 @@
<properties>
<property key="addressesDoNotAppearDirectlyInCode" value="true"/>
<property key="emulateInstructionStateModifierClass" value="ghidra.program.emulation.MIPSEmulateInstructionStateModifier"/>
<property key="useropLibs" value="mips"/>
<property key="assemblyRating:MIPS:BE:32:micro" value="PLATINUM"/>
</properties>
<programcounter register="pc"/>

View File

@@ -4,6 +4,7 @@
<properties>
<property key="addressesDoNotAppearDirectlyInCode" value="true"/>
<property key="emulateInstructionStateModifierClass" value="ghidra.program.emulation.MIPSEmulateInstructionStateModifier"/>
<property key="useropLibs" value="mips"/>
<property key="assemblyRating:MIPS:BE:64:64-32addr" value="PLATINUM"/>
<property key="assemblyRating:MIPS:BE:64:default" value="PLATINUM"/>
</properties>

View File

@@ -4,6 +4,7 @@
<properties>
<property key="addressesDoNotAppearDirectlyInCode" value="true"/>
<property key="emulateInstructionStateModifierClass" value="ghidra.program.emulation.MIPSEmulateInstructionStateModifier"/>
<property key="useropLibs" value="mips"/>
<property key="assemblyRating:MIPS:BE:64:R6" value="PLATINUM"/>
</properties>
<programcounter register="pc"/>

View File

@@ -133,4 +133,15 @@
</unaffected>
</prototype>
</default_proto>
<callotherfixup targetop="setISAMode">
<pcode incidentalcopy="true">
<input name="newMode"/>
<!-- NOP -->
<body><![CDATA[
v0 = v0;
]]></body>
</pcode>
</callotherfixup>
</compiler_spec>

View File

@@ -125,4 +125,15 @@
</localrange>
</prototype>
</default_proto>
<callotherfixup targetop="setISAMode">
<pcode incidentalcopy="true">
<input name="newMode"/>
<!-- NOP -->
<body><![CDATA[
v0 = v0;
]]></body>
</pcode>
</callotherfixup>
</compiler_spec>

View File

@@ -95,4 +95,15 @@
</unaffected>
</prototype>
</default_proto>
<callotherfixup targetop="setISAMode">
<pcode incidentalcopy="true">
<input name="newMode"/>
<!-- NOP -->
<body><![CDATA[
v0 = v0;
]]></body>
</pcode>
</callotherfixup>
</compiler_spec>

View File

@@ -186,4 +186,15 @@
</killedbycall>
</prototype>
</default_proto>
<callotherfixup targetop="setISAMode">
<pcode incidentalcopy="true">
<input name="newMode"/>
<!-- NOP -->
<body><![CDATA[
v0 = v0;
]]></body>
</pcode>
</callotherfixup>
</compiler_spec>

View File

@@ -170,4 +170,15 @@
</killedbycall>
</prototype>
</default_proto>
<callotherfixup targetop="setISAMode">
<pcode incidentalcopy="true">
<input name="newMode"/>
<!-- NOP -->
<body><![CDATA[
v0 = v0;
]]></body>
</pcode>
</callotherfixup>
</compiler_spec>

View File

@@ -4,6 +4,7 @@
<properties>
<property key="addressesDoNotAppearDirectlyInCode" value="true"/>
<property key="emulateInstructionStateModifierClass" value="ghidra.program.emulation.MIPSEmulateInstructionStateModifier"/>
<property key="useropLibs" value="mips"/>
</properties>
<programcounter register="pc"/>
<context_data>

View File

@@ -2369,7 +2369,8 @@ STORE_TOP16: STORE_SREG^ra,EXT_CODE4E(sp) is mic_listr6 & REL6=1 & STORE_SREG &
:jalx Abs26_mic2 is ISA_MODE=1 & RELP=0 & mic_op=0b111100 & REL6=0 & mic_code ; Abs26_mic2 [ ext_32_code = mic_code; ISA_MODE = 0; globalset(Abs26_mic2, ISA_MODE);] {
ra = inst_next | 0x1;
delayslot( 1 );
ISAModeSwitch = 0;
ISAModeSwitch = 0;
setISAMode(ISAModeSwitch);
call Abs26_mic2;
}

View File

@@ -4,9 +4,9 @@
* 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.
@@ -26,6 +26,7 @@ import ghidra.program.model.lang.RegisterValue;
import ghidra.program.model.pcode.PcodeOp;
//import ghidra.pcode.emulate.callother.SignalingNaNOpBehavior;
@Deprecated(forRemoval = true, since = "12.1")
public class MIPSEmulateInstructionStateModifier extends EmulateInstructionStateModifier {
private Register ismReg;

View File

@@ -0,0 +1,58 @@
/* ###
* 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.program.emulation;
import java.math.BigInteger;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.pcode.emu.DefaultPcodeThread.PcodeThreadExecutor;
import ghidra.pcode.exec.*;
import ghidra.pcode.exec.PcodeUseropLibraryFactory.UseropLibrary;
import ghidra.program.model.lang.*;
@UseropLibrary("mips")
public class MipsPcodeUseropLibraryFactory implements PcodeUseropLibraryFactory {
@Override
public <T> PcodeUseropLibrary<T> create(SleighLanguage language,
PcodeArithmetic<T> arithmetic) {
return new MipsPcodeUseropLibrary<>(language);
}
public static class MipsPcodeUseropLibrary<T> extends AnnotatedPcodeUseropLibrary<T> {
private final RegisterValue mode0;
private final RegisterValue mode1;
public MipsPcodeUseropLibrary(Language language) {
Register isaModeReg = language.getRegister("ISA_MODE");
if (isaModeReg != null) {
mode0 = new RegisterValue(isaModeReg, BigInteger.ZERO);
mode1 = new RegisterValue(isaModeReg, BigInteger.ONE);
}
else {
mode0 = null;
mode1 = null;
}
}
@PcodeUserop(modifiesContext = true)
public void setISAMode(@OpExecutor PcodeExecutor<T> exec, boolean mode) {
if (!(exec instanceof PcodeThreadExecutor<T> tExec)) {
return;
}
tExec.getThread().overrideContext(mode ? mode1 : mode0);
}
}
}

View File

@@ -4,6 +4,7 @@
<properties>
<property key="addressesDoNotAppearDirectlyInCode" value="true"/>
<property key="emulateInstructionStateModifierClass" value="ghidra.program.emulation.PPCEmulateInstructionStateModifier"/>
<property key="useropLibs" value="ppc"/>
<property key="assemblyRating:PowerPC:BE:32:default" value="PLATINUM"/>
</properties>
<programcounter register="pc"/>

View File

@@ -5,6 +5,7 @@
<properties>
<property key="addressesDoNotAppearDirectlyInCode" value="true"/>
<property key="emulateInstructionStateModifierClass" value="ghidra.program.emulation.PPCEmulateInstructionStateModifier"/>
<property key="useropLibs" value="ppc"/>
</properties>
<programcounter register="pc"/>

View File

@@ -4,6 +4,7 @@
<properties>
<property key="addressesDoNotAppearDirectlyInCode" value="true"/>
<property key="emulateInstructionStateModifierClass" value="ghidra.program.emulation.PPCEmulateInstructionStateModifier"/>
<property key="useropLibs" value="ppc"/>
<property key="assemblyRating:PowerPC:BE:64:A2-32addr" value="PLATINUM"/>
<property key="assemblyRating:PowerPC:BE:64:A2ALT-32addr" value="PLATINUM"/>
<property key="assemblyRating:PowerPC:BE:64:default" value="PLATINUM"/>

View File

@@ -24,6 +24,7 @@ import ghidra.pcode.memstate.MemoryState;
import ghidra.pcodeCPort.error.LowlevelError;
import ghidra.program.model.pcode.Varnode;
@Deprecated(forRemoval = true, since = "12.1")
public class PPCEmulateInstructionStateModifier extends EmulateInstructionStateModifier {
public PPCEmulateInstructionStateModifier(Emulate emu) {

View File

@@ -0,0 +1,55 @@
/* ###
* 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.program.emulation;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.pcode.exec.*;
import ghidra.pcode.exec.PcodeUseropLibraryFactory.UseropLibrary;
@UseropLibrary("ppc")
public class PpcPcodeUseropLibraryFactory implements PcodeUseropLibraryFactory {
@Override
public <T> PcodeUseropLibrary<T> create(SleighLanguage language,
PcodeArithmetic<T> arithmetic) {
return new PpcPcodeUseropLibrary<>(language);
}
public static class PpcPcodeUseropLibrary<T> extends AnnotatedPcodeUseropLibrary<T> {
public PpcPcodeUseropLibrary(SleighLanguage language) {
SleighPcodeUseropDefinition.Factory factory =
new SleighPcodeUseropDefinition.Factory(language);
putOp(factory.define("vectorPermute").params("s1", "s2", "p").body(args -> """
local table:32;
local result:16;
table[128,128] = s1;
table[0,128] = s2;
""" + genIndex() + """
__op_output = result;
""").build());
}
protected String genIndex() {
StringBuilder buf = new StringBuilder();
for (int i = 0; i < 16; i++) {
buf.append("idx%d:1 = 0x1f - (p(%d) & 0x1f);\n".formatted(i, i));
buf.append("tmp%d:1 = table(idx%d);\n".formatted(i, i));
buf.append("result[%d,8] = tmp%d;\n".formatted(8 * i, i));
}
return buf.toString();
}
}
}

View File

@@ -0,0 +1,107 @@
/* ###
* 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.program.emulation;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertNotNull;
import java.util.Map;
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.pcode.exec.*;
import ghidra.program.emulation.PpcPcodeUseropLibraryFactory.PpcPcodeUseropLibrary;
import ghidra.program.model.lang.LanguageID;
import ghidra.program.util.DefaultLanguageService;
public class PpcPcodeUseropLibraryTest extends AbstractEmulationEquivalenceTest {
static final LanguageID LANGI_ID_PCC64 = new LanguageID("PowerPC:BE:64:A2ALT-32addr");
static SleighLanguage PPC64;
@Before
public void setupPpc() throws Exception {
if (PPC64 == null) {
PPC64 = (SleighLanguage) DefaultLanguageService.getLanguageService()
.getLanguage(LANGI_ID_PCC64);
}
}
@Test
public void testFoundById() {
PcodeUseropLibrary<byte[]> lib = PcodeUseropLibraryFactory
.createUseropLibraryFromId("ppc", PPC64, BytesPcodeArithmetic.forLanguage(PPC64));
assertThat(lib, Matchers.instanceOf(PpcPcodeUseropLibrary.class));
}
@Test
public void testFoundByLang() {
PcodeUseropLibrary<byte[]> lib = PcodeUseropLibraryFactory
.createUseropLibraryForLanguage(PPC64, BytesPcodeArithmetic.forLanguage(PPC64));
assertNotNull(lib.getUserops().get("vectorPermute"));
}
@Test
public void testVperm1() throws Exception {
doTestEquiv(PPC64,
Map.ofEntries(
Map.entry("vs44", "ffffffffffffffff"),
Map.entry("vs45", "0123456789abcdef"),
Map.entry("vs33", "fedcba9876543210"),
Map.entry("vs43", "0004080c1014181c")),
buf -> buf.assemble("vperm v12,v13,v1,v11"), 1,
Map.ofEntries(
Map.entry("vs44", "1890000fe76"),
Map.entry("vs45", "123456789abcdef"),
Map.entry("vs33", "fedcba9876543210"),
Map.entry("vs43", "4080c1014181c")));
}
@Test
public void testVperm2() throws Exception {
doTestEquiv(PPC64,
Map.ofEntries(
Map.entry("vs44", "ffffffffffffffffffffffffffffffff"),
Map.entry("vs45", "ffffffe0000000000000000100000002"),
Map.entry("vs33", "00000003000000040000000500000006"),
Map.entry("vs43", "08090a0b0c0d0e0f1011121314151617")),
buf -> buf.assemble("vperm v12,v13,v1,v11"), 1,
Map.ofEntries(
Map.entry("vs44", "1000000020000000300000004"),
Map.entry("vs45", "ffffffe0000000000000000100000002"),
Map.entry("vs33", "3000000040000000500000006"),
Map.entry("vs43", "8090a0b0c0d0e0f1011121314151617")));
}
@Test
public void testVperm3() throws Exception {
doTestEquiv(PPC64,
Map.ofEntries(
Map.entry("vs44", "ffffffffffffffffffffffffffffffff"),
Map.entry("vs45", "00000001000000020000000300000004"),
Map.entry("vs33", "00000001000000020000000300000004"),
Map.entry("vs43", "101112131415161718191a1b1c1d1e1f")),
buf -> buf.assemble("vperm v12,v13,v1,v11"), 1,
Map.ofEntries(
Map.entry("vs44", "1000000020000000300000004"),
Map.entry("vs45", "1000000020000000300000004"),
Map.entry("vs33", "1000000020000000300000004"),
Map.entry("vs43", "101112131415161718191a1b1c1d1e1f")));
}
}

View File

@@ -4,9 +4,9 @@
* 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.
@@ -22,6 +22,7 @@ import ghidra.program.model.lang.RegisterValue;
import ghidra.program.model.pcode.PcodeOp;
import ghidra.pcode.emulate.Emulate;
@Deprecated(forRemoval = true, since = "12.1")
public class RISCVEmulateInstructionStateModifier extends EmulateInstructionStateModifier {
public RISCVEmulateInstructionStateModifier(Emulate emu) {

View File

@@ -5,6 +5,7 @@
<properties>
<property key="emulateInstructionStateModifierClass" value="ghidra.program.emulation.XtensaEmulateInstructionStateModifier" />
<property key="useropLibs" value="xtensa"/>
</properties>
<context_data>

View File

@@ -27,6 +27,7 @@ import ghidra.program.model.address.Address;
import ghidra.program.model.lang.Register;
import ghidra.program.model.pcode.Varnode;
@Deprecated(forRemoval = true, since = "12.1")
public class XtensaEmulateInstructionStateModifier extends EmulateInstructionStateModifier {
private Stack<RegisterStash> stashStack = new Stack<RegisterStash>();

View File

@@ -0,0 +1,196 @@
/* ###
* 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.program.emulation;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.pcode.error.LowlevelError;
import ghidra.pcode.exec.*;
import ghidra.pcode.exec.PcodeUseropLibraryFactory.UseropLibrary;
@UseropLibrary("xtensa")
public class XtensaPcodeUseropLibraryFactory implements PcodeUseropLibraryFactory {
@Override
public <T> PcodeUseropLibrary<T> create(SleighLanguage language,
PcodeArithmetic<T> arithmetic) {
return new XtensaPcodeUseropLibrary<>(language);
}
public static class IntStack {
public static final int INIT_SIZE = 16;
private int[] vals = new int[INIT_SIZE];
private int size = 0;
public void push(int value) {
if (size == vals.length) {
grow();
}
vals[size] = value;
size++;
}
public int pop() {
if (size == 0) {
throw new LowlevelError("stack is empty");
}
size--;
return vals[size];
}
private void grow() {
int[] vals = new int[this.vals.length * 2];
System.arraycopy(this.vals, 0, vals, 0, this.vals.length);
this.vals = vals;
}
}
public static class XtensaPcodeUseropLibrary<T> extends AnnotatedPcodeUseropLibrary<T> {
private final static int TYPE_COUNT = 0;
private final static int TYPE_VALUE = 1;
private final IntStack stack = new IntStack();
public XtensaPcodeUseropLibrary(SleighLanguage language) {
SleighPcodeUseropDefinition.Factory factory =
new SleighPcodeUseropDefinition.Factory(language);
putOp(factory.define("rotateRegWindow").params("callinc").body(args -> """
__pushCount(callinc);
if (callinc == 0) goto <done>;
if (callinc == 1) goto <push4>;
if (callinc == 2) goto <push8>;
if (callinc == 3) goto <push12>;
__lle_invalidCallinc(callinc);
<push4>
""" + genPushN(4) + """
goto <done>;
<push8>
""" + genPushN(8) + """
goto <done>;
<push12>
""" + genPushN(12) + """
<done>
""").build());
putOp(factory.define("restoreRegWindow").body(args -> """
callinc:4 = (a0 >> 30) & 0x3;
__popCount(callinc);
if (callinc == 0) goto <done>;
if (callinc == 1) goto <pop4>;
if (callinc == 2) goto <pop8>;
if (callinc == 3) goto <pop12>;
<pop4>
""" + genPopN(4) + """
goto <done>;
<pop8>
""" + genPopN(8) + """
goto <done>;
<pop12>
""" + genPopN(12) + """
<done>
""").build());
}
protected String genPushN(int n) {
StringBuilder buf = new StringBuilder();
int i = 0;
for (; i < n; i++) {
buf.append(" __pushValue(a%d);\n".formatted(i));
}
for (; i < 16; i++) {
buf.append(" a%d = a%d;\n".formatted(i - n, i));
}
return buf.toString();
}
protected String genPopN(int n) {
StringBuilder buf = new StringBuilder();
int i = 15;
for (; i >= n; i--) {
buf.append(" a%d = a%d;\n".formatted(i, i - n));
}
for (; i >= 0; i--) {
buf.append(" a%d = __popValue();\n".formatted(i));
}
return buf.toString();
}
@PcodeUserop(functional = true, hasSideEffects = false)
public void __lle_invalidCallinc(int callinc) {
throw new LowlevelError(
"rotateRegWindow: invalid value for CALLINC (0x%x)".formatted(callinc));
}
@PcodeUserop(functional = true)
public void __pushCount(int count) {
stack.push(TYPE_COUNT);
stack.push(count);
}
@PcodeUserop(functional = true)
public void __popCount(int count) {
int type = stack.pop();
int value = stack.pop();
if (type != TYPE_COUNT) {
throw new LowlevelError("Popped count, but got a value");
}
if (value != count) {
throw new LowlevelError("""
restoreRegWindow: return address CALLINC (%d) does not match last entry \
CALLINC value (%d)""".formatted(count, value));
}
}
@PcodeUserop(functional = true)
public void __pushValue(int value) {
stack.push(TYPE_VALUE);
stack.push(value);
}
@PcodeUserop(functional = true)
public int __popValue() {
int type = stack.pop();
int value = stack.pop();
if (type != TYPE_VALUE) {
throw new LowlevelError("Popped value, but got a count");
}
return value;
}
@PcodeUserop(canInline = true)
public void swap4() {
}
@PcodeUserop(canInline = true)
public void swap8() {
}
@PcodeUserop(canInline = true)
public void swap12() {
}
@PcodeUserop(canInline = true)
public void restore4() {
}
@PcodeUserop(canInline = true)
public void restore8() {
}
@PcodeUserop(canInline = true)
public void restore12() {
}
}
}

View File

@@ -4,6 +4,7 @@
<properties>
<property key="emulateInstructionStateModifierClass"
value="ghidra.program.emulation.TRICOREEmulateInstructionStateModifier"/>
<property key="useropLibs" value="tricore"/>
</properties>
<programcounter register="PC"/>

View File

@@ -4,6 +4,7 @@
<properties>
<property key="emulateInstructionStateModifierClass"
value="ghidra.program.emulation.TRICOREEmulateInstructionStateModifier"/>
<property key="useropLibs" value="tricore"/>
</properties>
<programcounter register="PC"/>

View File

@@ -4,6 +4,7 @@
<properties>
<property key="emulateInstructionStateModifierClass"
value="ghidra.program.emulation.TRICOREEmulateInstructionStateModifier"/>
<property key="useropLibs" value="tricore"/>
</properties>
<programcounter register="PC"/>

View File

@@ -4,6 +4,7 @@
<properties>
<property key="emulateInstructionStateModifierClass"
value="ghidra.program.emulation.TRICOREEmulateInstructionStateModifier"/>
<property key="useropLibs" value="tricore"/>
</properties>
<programcounter register="PC"/>

View File

@@ -27,6 +27,7 @@ import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.lang.Register;
import ghidra.program.model.pcode.Varnode;
@Deprecated(forRemoval = true, since = "12.1")
public class TRICOREEmulateInstructionStateModifier extends EmulateInstructionStateModifier {
Register FCX,PCXI,LCX,PSW,a10,a11,d8,a12,d12;

View File

@@ -0,0 +1,90 @@
/* ###
* 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.program.emulation;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.pcode.exec.*;
import ghidra.pcode.exec.PcodeUseropLibraryFactory.UseropLibrary;
@UseropLibrary("tricore")
public class TricorePcodeUseropLibraryFactory implements PcodeUseropLibraryFactory {
@Override
public <T> PcodeUseropLibrary<T> create(SleighLanguage language,
PcodeArithmetic<T> arithmetic) {
return new TricorePcodeUseropLibrary<>(language);
}
public static class TricorePcodeUseropLibrary<T> extends AnnotatedPcodeUseropLibrary<T> {
public TricorePcodeUseropLibrary(SleighLanguage language) {
SleighPcodeUseropDefinition.Factory factory =
new SleighPcodeUseropDefinition.Factory(language);
putOp(factory.define("saveCallerState")
.params("_fcx", "_lcx", "_pcxi")
.body(args -> """
local ea:4 = ((FCX & 0xffff0000) << 12) | ((FCX & 0xffff) << 6);
local new_fcx:4 = * ea;
if (new_fcx != 0) goto <skip_init>;
new_fcx = FCX + 1;
<skip_init>
* ea = PCXI;
* (ea + 4) = PSW;
* (ea + 8) = a10;
* (ea + 12) = a11;
* (ea + 16) = d8;
* (ea + 20) = d9;
* (ea + 24) = d10;
* (ea + 28) = d11;
* (ea + 32) = a12;
* (ea + 36) = a13;
* (ea + 40) = a14;
* (ea + 44) = a15;
* (ea + 48) = d12;
* (ea + 52) = d13;
* (ea + 56) = d14;
* (ea + 60) = d15;
PCXI = (PCXI & 0xfff00000) | ( FCX & 0x000fffff);
FCX = (FCX & 0xfff00000) | (new_fcx & 0x000fffff);
""")
.build());
putOp(factory.define("restoreCallerState")
.params("_fcx", "_lcx", "_pcxi")
.body(args -> """
local ea:4 = ((PCXI & 0xffff0000) << 12) | ((PCXI & 0x0000ffff) << 6);
local savePCXI = PCXI;
PCXI = * ea;
PSW = * (ea + 4);
a10 = * (ea + 8);
a11 = * (ea + 12);
d8 = * (ea + 16);
d9 = * (ea + 20);
d10 = * (ea + 24);
d11 = * (ea + 28);
a12 = * (ea + 32);
a13 = * (ea + 36);
a14 = * (ea + 40);
a15 = * (ea + 44);
d12 = * (ea + 48);
d13 = * (ea + 52);
d14 = * (ea + 56);
d15 = * (ea + 60);
* ea = FCX;
FCX = (FCX & 0xfff00000) | (savePCXI & 0x000fffff);
""")
.build());
}
}
}

View File

@@ -0,0 +1,121 @@
/* ###
* 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.program.emulation;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertNotNull;
import java.util.Map;
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.pcode.exec.*;
import ghidra.program.emulation.TricorePcodeUseropLibraryFactory.TricorePcodeUseropLibrary;
import ghidra.program.model.lang.LanguageID;
import ghidra.program.util.DefaultLanguageService;
public class TricorePcodeUseropLibraryTest extends AbstractEmulationEquivalenceTest {
static final LanguageID LANGI_ID_TRICORE = new LanguageID("tricore:LE:32:default");
static SleighLanguage TRICORE;
@Before
public void setupTricore() throws Exception {
if (TRICORE == null) {
TRICORE = (SleighLanguage) DefaultLanguageService.getLanguageService()
.getLanguage(LANGI_ID_TRICORE);
}
}
@Test
public void testFoundById() {
PcodeUseropLibrary<byte[]> lib = PcodeUseropLibraryFactory
.createUseropLibraryFromId("tricore", TRICORE,
BytesPcodeArithmetic.forLanguage(TRICORE));
assertThat(lib, Matchers.instanceOf(TricorePcodeUseropLibrary.class));
}
@Test
public void testFoundByLang() {
PcodeUseropLibrary<byte[]> lib = PcodeUseropLibraryFactory
.createUseropLibraryForLanguage(TRICORE, BytesPcodeArithmetic.forLanguage(TRICORE));
assertNotNull(lib.getUserops().get("saveCallerState"));
assertNotNull(lib.getUserops().get("restoreCallerState"));
}
@Test
public void testCall() throws Exception {
doTestEquiv(TRICORE,
Map.ofEntries(
Map.entry("FCX", "00020000"),
Map.entry("PCXI", "00000000"),
Map.entry("PSW", "00000000")),
buf -> buf.assemble("call 0x00401234"), 1,
Map.ofEntries(
Map.entry("PCXI", "20000"),
Map.entry("FCX", "20001"),
Map.entry("a11", "400004"),
Map.entry("PC", "401234")));
}
@Test
public void testCallRet() throws Exception {
doTestEquiv(TRICORE,
Map.ofEntries(
Map.entry("FCX", "00020001"),
Map.entry("PCXI", "00020000"),
Map.entry("a10", "1110"),
Map.entry("a11", "1111"),
Map.entry("a12", "1112"),
Map.entry("a13", "1113"),
Map.entry("a14", "1114"),
Map.entry("a15", "1115"),
Map.entry("d8", "1208"),
Map.entry("d9", "1209"),
Map.entry("d10", "1210"),
Map.entry("d11", "1211"),
Map.entry("d12", "1212"),
Map.entry("d13", "1213"),
Map.entry("d14", "1214"),
Map.entry("d15", "1215")),
buf -> {
buf.assemble("call 0x00400002"); // length is 2
buf.assemble("ret");
}, 2,
Map.ofEntries(
Map.entry("PCXI", "20000"),
Map.entry("PSW", "0"),
Map.entry("FCX", "20001"),
Map.entry("PC", "400002"),
Map.entry("a10", "1110"),
Map.entry("a11", "1111"),
Map.entry("a12", "1112"),
Map.entry("a13", "1113"),
Map.entry("a14", "1114"),
Map.entry("a15", "1115"),
Map.entry("d8", "1208"),
Map.entry("d9", "1209"),
Map.entry("d10", "1210"),
Map.entry("d11", "1211"),
Map.entry("d12", "1212"),
Map.entry("d13", "1213"),
Map.entry("d14", "1214"),
Map.entry("d15", "1215")));
}
}

View File

@@ -4,6 +4,7 @@
<processor_spec>
<properties>
<property key="useOperandReferenceAnalyzerSwitchTables" value="true"/>
<property key="useropLibs" value="x86"/>
</properties>
<programcounter register="EIP"/>
<segmented_address space="ram" type="real" />

View File

@@ -5,6 +5,7 @@
<processor_spec>
<properties>
<property key="useOperandReferenceAnalyzerSwitchTables" value="true"/>
<property key="useropLibs" value="x86"/>
</properties>
<programcounter register="EIP"/>
<segmented_address space="ram" type="protected"/>

View File

@@ -4,6 +4,7 @@
<properties>
<property key="useOperandReferenceAnalyzerSwitchTables" value="true"/>
<property key="assemblyRating:x86:LE:64:compat32" value="GOLD"/>
<property key="useropLibs" value="x86"/>
</properties>
<programcounter register="RIP"/>
<context_data>

View File

@@ -4,6 +4,7 @@
<properties>
<property key="useOperandReferenceAnalyzerSwitchTables" value="true"/>
<property key="assemblyRating:x86:LE:64:default" value="GOLD"/>
<property key="useropLibs" value="x86"/>
</properties>
<programcounter register="RIP"/>
<context_data>

View File

@@ -4,6 +4,7 @@
<properties>
<property key="useOperandReferenceAnalyzerSwitchTables" value="true"/>
<property key="assemblyRating:x86:LE:32:default" value="GOLD"/>
<property key="useropLibs" value="x86"/>
</properties>
<programcounter register="EIP"/>
<incidentalcopy>

View File

@@ -0,0 +1,45 @@
/* ###
* 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.program.emulation;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.pcode.exec.*;
import ghidra.pcode.exec.PcodeUseropLibraryFactory.UseropLibrary;
@UseropLibrary("x86")
public class X86PcodeUseropLibraryFactory implements PcodeUseropLibraryFactory {
@Override
public <T> PcodeUseropLibrary<T> create(SleighLanguage language,
PcodeArithmetic<T> arithmetic) {
return new X86PcodeUseropLibrary<>();
}
public static class X86PcodeUseropLibrary<T> extends AnnotatedPcodeUseropLibrary<T> {
/**
* LATER: For petri-dish emulation, this is perfect. However, for multi-threaded and
* systems-level stuff, we'll probably need an actual mutex of some sort. We'll also want to
* make sure the behavior is accurate in the face of errors and interrupts.
*/
@PcodeUserop(functional = true)
public void LOCK() {
}
@PcodeUserop(functional = true)
public void UNLOCK() {
}
}
}