mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-04-25 17:25:17 +02:00
Merge tag 'Ghidra_12.0.4_build' into stable
This commit is contained in:
@@ -1,3 +1,33 @@
|
||||
# Ghidra 12.0.4 Change History (March 2026)
|
||||
|
||||
### Improvements
|
||||
* _Analysis_. Updated the RTTI Analyzer to better handle the case where class names cannot be demangled correctly. Previously, class members would end up in global namespace. Now, a class namespace with the mangled name will be created so that items in that class can be correctly grouped together. (GP-6431, Issue #8944)
|
||||
* _GUI_. Fixed a potential zip path traversal vulnerability when importing Ghidra theme zip files. (GP-6455)
|
||||
* _Scripting_. Improved RTTI Windows script vbtable discovery to recognize some invalid tables. (GP-6446, Issue #8944)
|
||||
|
||||
### Bugs
|
||||
* _Analysis_. Fixed an issue with constants from one function finding their way into another function that is jumped to, and mid-constant propagation the jump is turned into a call. (GP-6442)
|
||||
* _Analysis_. Corrected analysis problem which failed to properly link thunk functions in the EXTERNAL memory block to existing External library symbols instead of creating new external functions in the unknown external library. (GP-6465)
|
||||
* _Bookmarks_. Corrected potential Bookmark exception which can occur if bookmarks were ever deleted: <I>Missing bookmark table<I>. (GP-6517)
|
||||
* _Debugger_. Fixed a deadlock when saving Traces from the __Close Project__ dialog. (GP-6392)
|
||||
* _Debugger:Memory_. Fixed a bug in the Memory viewer when looking at multiple address spaces. (GP-6449, Issue #8982)
|
||||
* _Disassembly_. Refactored `PsuedoDisassembler` to use the normal high level Disassembler instead of calling `Language.parse()`. (GP-6496)
|
||||
* _Exporter_. Enable cancellation for SARIF exports (GP-6469)
|
||||
* _Listing_. Fixed Listing display to show single string operands. (GP-6095)
|
||||
* _Processors_. Fixed the semantics of the AARCH64 `ldpsw` instruction. (GP-5590, Issue #6469, #8008)
|
||||
* _Processors_. Fixed issue with PIC-18 instructions double-incrementing/decrementing. (GP-6004, Issue #3342, #8501)
|
||||
* _Processors_. Corrected Xtensa slapsec token field naming. (GP-6080)
|
||||
* _Processors_. Corrected semantics for the CR16 `tbit` instruction. (GP-6181, Issue #8716)
|
||||
* _Processors_. Corrected mnemonic and semantics for eBPF atomic compare-and-exchange instructions. (GP-6182, Issue #8721)
|
||||
* _Processors_. Added missing definition for PowerPC Altivec `vadduws` instruction that was mistakenly commented out. (GP-6268, Issue #8821)
|
||||
* _Processors_. Added support for AARCH64 Common Short Sequence Compression (CSSC) instructions. (GP-6448, Issue #8973, #8979)
|
||||
* _Processors_. Fixed semantics of AARCH64 `ldar` instruction. (GP-6473, Issue #6467, #8014)
|
||||
* _Processors_. Corrected disassembly for MIPS instruction `sdbbp16`. (GP-6489)
|
||||
* _Processors_. Added MIPS32 `save` and `restore` instructions, and refactored coprocessor register read/write. (GP-6501)
|
||||
|
||||
### Notable API Changes
|
||||
* _GUI_. (GP-6480) The resultsLimit and minLength parameters of the AddressRangeTableModel constructor have been removed.
|
||||
|
||||
# Ghidra 12.0.3 Change History (February 2026)
|
||||
|
||||
### New Features
|
||||
|
||||
@@ -36,6 +36,7 @@ import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.trace.model.*;
|
||||
import ghidra.trace.model.memory.*;
|
||||
import ghidra.util.MathUtilities;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public enum BasicAutoReadMemorySpec implements AutoReadMemorySpec {
|
||||
@@ -52,7 +53,8 @@ public enum BasicAutoReadMemorySpec implements AutoReadMemorySpec {
|
||||
/**
|
||||
* Automatically read all visible memory
|
||||
*/
|
||||
VISIBLE("1_READ_VISIBLE", AutoReadMemoryAction.NAME_VISIBLE, AutoReadMemoryAction.ICON_VISIBLE) {
|
||||
VISIBLE("1_READ_VISIBLE", AutoReadMemoryAction.NAME_VISIBLE,
|
||||
AutoReadMemoryAction.ICON_VISIBLE) {
|
||||
@Override
|
||||
public CompletableFuture<Boolean> readMemory(PluginTool tool,
|
||||
DebuggerCoordinates coordinates,
|
||||
@@ -77,7 +79,8 @@ public enum BasicAutoReadMemorySpec implements AutoReadMemorySpec {
|
||||
* Automatically read all visible memory, unless it is read-only, in which case, only read it if
|
||||
* it has not already been read.
|
||||
*/
|
||||
VIS_RO_ONCE("2_READ_VIS_RO_ONCE", AutoReadMemoryAction.NAME_VIS_RO_ONCE, AutoReadMemoryAction.ICON_VIS_RO_ONCE) {
|
||||
VIS_RO_ONCE("2_READ_VIS_RO_ONCE", AutoReadMemoryAction.NAME_VIS_RO_ONCE,
|
||||
AutoReadMemoryAction.ICON_VIS_RO_ONCE) {
|
||||
@Override
|
||||
public CompletableFuture<Boolean> readMemory(PluginTool tool,
|
||||
DebuggerCoordinates coordinates,
|
||||
@@ -136,8 +139,15 @@ public enum BasicAutoReadMemorySpec implements AutoReadMemorySpec {
|
||||
// Not terribly efficient, but this is one range most of the time
|
||||
for (AddressRange range : set) {
|
||||
AddressSpace space = range.getAddressSpace();
|
||||
Address min = space.getAddress(range.getMinAddress().getOffset() & blockMask);
|
||||
Address max = space.getAddress(range.getMaxAddress().getOffset() | ~blockMask);
|
||||
long minOffset = range.getMinAddress().getOffset() & blockMask;
|
||||
minOffset = MathUtilities.unsignedMax(minOffset, space.getMinAddress().getOffset());
|
||||
long maxOffset = range.getMaxAddress().getOffset() | ~blockMask;
|
||||
maxOffset = MathUtilities.unsignedMin(maxOffset, space.getMaxAddress().getOffset());
|
||||
if (minOffset > maxOffset) {
|
||||
continue;
|
||||
}
|
||||
Address min = space.getAddress(minOffset);
|
||||
Address max = space.getAddress(maxOffset);
|
||||
result.add(new AddressRangeImpl(min, max));
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -47,6 +47,9 @@ public class CachedBytePage {
|
||||
record CacheKey(DebuggerCoordinates coordinates, Address start) {
|
||||
int computeOffset(DebuggerCoordinates coordinates, Address address) {
|
||||
if (coordsEqualForMemory(this.coordinates, coordinates)) {
|
||||
if (start.getAddressSpace() != address.getAddressSpace()) {
|
||||
return -1;
|
||||
}
|
||||
long offset = address.subtract(start);
|
||||
if (0 <= offset && offset < PAGE_SIZE) {
|
||||
return (int) offset;
|
||||
|
||||
@@ -634,7 +634,7 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Collection<Trace> getOpenTraces() {
|
||||
public Collection<Trace> getOpenTraces() {
|
||||
synchronized (listenersByTrace) {
|
||||
return Set.copyOf(tracesView);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package ghidra.trace.database;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
@@ -876,16 +875,10 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(String comment, TaskMonitor monitor) throws IOException, CancelledException {
|
||||
objectManager.flushWbCaches();
|
||||
super.save(comment, monitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveToPackedFile(File outputFile, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
objectManager.flushWbCaches();
|
||||
super.saveToPackedFile(outputFile, monitor);
|
||||
protected void prepareToSave() {
|
||||
try (Transaction tx = openForcedTransaction("flush for save")) {
|
||||
objectManager.flushWbCaches();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isClosing() {
|
||||
@@ -895,9 +888,9 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
||||
@Override
|
||||
protected void close() {
|
||||
closing = true;
|
||||
objectManager.flushWbCaches();
|
||||
super.close();
|
||||
// NOTE: Any unsaved changes in the write-back cache are unrecoverable
|
||||
objectManager.waitWbWorkers();
|
||||
super.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -41,16 +41,16 @@ public class DBTraceContentHandler extends DBWithUserDataContentHandler<DBTrace>
|
||||
static final Class<DBTrace> TRACE_DOMAIN_OBJECT_CLASS = DBTrace.class;
|
||||
static final String TRACE_CONTENT_DEFAULT_TOOL = "Debugger";
|
||||
|
||||
private static final DBTraceLinkContentHandler linkHandler = new DBTraceLinkContentHandler();
|
||||
private static final DBTraceLinkContentHandler LINK_HANDLER = new DBTraceLinkContentHandler();
|
||||
|
||||
@Override
|
||||
public long createFile(FileSystem fs, FileSystem userfs, String path, String name,
|
||||
DomainObject obj, TaskMonitor monitor)
|
||||
throws IOException, InvalidNameException, CancelledException {
|
||||
if (!(obj instanceof DBTrace)) {
|
||||
if (!(obj instanceof DBTrace trace)) {
|
||||
throw new IOException("Unsupported domain object: " + obj.getClass().getName());
|
||||
}
|
||||
return createFile((DBTrace) obj, TRACE_CONTENT_TYPE, fs, path, name, monitor);
|
||||
return createFile(trace, TRACE_CONTENT_TYPE, fs, path, name, monitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -340,6 +340,6 @@ public class DBTraceContentHandler extends DBWithUserDataContentHandler<DBTrace>
|
||||
|
||||
@Override
|
||||
public DBTraceLinkContentHandler getLinkHandler() {
|
||||
return linkHandler;
|
||||
return LINK_HANDLER;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,8 +40,9 @@ class DBTraceObjectValueWriteBehindCache {
|
||||
private final AsyncReference<Boolean, Void> busy = new AsyncReference<>(false);
|
||||
private volatile boolean flushing = false;
|
||||
|
||||
private final Map<DBTraceObject, Map<String, NavigableMap<Long, DBTraceObjectValueBehind>>> cachedValues =
|
||||
new HashMap<>();
|
||||
private final Map<DBTraceObject,
|
||||
Map<String, NavigableMap<Long, DBTraceObjectValueBehind>>> cachedValues =
|
||||
new HashMap<>();
|
||||
|
||||
public DBTraceObjectValueWriteBehindCache(DBTraceObjectManager manager) {
|
||||
this.manager = manager;
|
||||
@@ -51,7 +52,7 @@ class DBTraceObjectValueWriteBehindCache {
|
||||
}
|
||||
|
||||
private void workLoop() {
|
||||
while (!manager.trace.isClosed()) {
|
||||
while (!manager.trace.isClosing()) {
|
||||
try {
|
||||
synchronized (cachedValues) {
|
||||
if (cachedValues.isEmpty()) {
|
||||
@@ -69,7 +70,7 @@ class DBTraceObjectValueWriteBehindCache {
|
||||
cachedValues.wait(left);
|
||||
}
|
||||
}
|
||||
if (manager.trace.isClosed()) {
|
||||
if (manager.trace.isClosing()) {
|
||||
break;
|
||||
}
|
||||
writeBatch();
|
||||
|
||||
@@ -669,10 +669,12 @@ public class CreateThunkFunctionCmd extends BackgroundCommand<Program> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle conversion of label within reserved EXTERNAL block to a real
|
||||
* external function which can be thunked. This may be necessary when a
|
||||
* loaded symbol failed to identify itself as a function. This will
|
||||
* only handle single symbols contained within the global namespace.
|
||||
* Facilitates conversion of a global label within the reserved EXTERNAL block to an
|
||||
* external function which can be thunked. This may be necessary when a loaded symbol
|
||||
* failed to identify itself as a function.
|
||||
* <p>
|
||||
* NOTE: If a suitable External symbol is found or created the original symbol for the
|
||||
* thunk function will be removed.
|
||||
*
|
||||
* @param program the program
|
||||
* @param entry function being created
|
||||
@@ -696,10 +698,29 @@ public class CreateThunkFunctionCmd extends BackgroundCommand<Program> {
|
||||
}
|
||||
try {
|
||||
ExternalManager extMgr = program.getExternalManager();
|
||||
ExternalLocation extLoc =
|
||||
extMgr.addExtFunction(Library.UNKNOWN, s.getName(), null, s.getSource());
|
||||
|
||||
Symbol externalSymbol = null;
|
||||
for (Symbol symbol : symbolTable.getSymbols(s.getName())) {
|
||||
// Only consider external symbols directly in a Library root Namespace
|
||||
if (!symbol.isExternal() || !symbol.getParentNamespace().isLibrary()) {
|
||||
continue;
|
||||
}
|
||||
if (externalSymbol != null) {
|
||||
// multiple ambiguous external symbols - can't decide
|
||||
return null;
|
||||
}
|
||||
externalSymbol = symbol;
|
||||
}
|
||||
|
||||
if (externalSymbol == null) {
|
||||
ExternalLocation extLoc =
|
||||
extMgr.addExtFunction(Library.UNKNOWN, s.getName(), null, s.getSource());
|
||||
externalSymbol = extLoc.getSymbol();
|
||||
}
|
||||
|
||||
s.delete(); // remove original symbol from EXTERNAL block
|
||||
return extLoc.getExternalSpaceAddress();
|
||||
|
||||
return externalSymbol.getAddress();
|
||||
}
|
||||
catch (DuplicateNameException | InvalidInputException e) {
|
||||
// ignore - unexpected
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.util.stream.StreamSupport;
|
||||
import docking.widgets.table.AbstractDynamicTableColumn;
|
||||
import docking.widgets.table.TableColumnDescriptor;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.framework.plugintool.ServiceProvider;
|
||||
import ghidra.program.model.address.*;
|
||||
@@ -43,20 +44,23 @@ public class AddressRangeTableModel extends GhidraProgramTableModel<AddressRange
|
||||
private static final int MAX_ADDRESS_COLUMN_INDEX = 1;
|
||||
|
||||
private ProgramSelection selection;
|
||||
private int resultsLimit;
|
||||
private long minLength;
|
||||
private PluginTool tool;
|
||||
|
||||
protected AddressRangeTableModel(PluginTool tool, Program program, ProgramSelection selection,
|
||||
int resultsLimit, long minLength) {
|
||||
protected AddressRangeTableModel(PluginTool tool, Program program, ProgramSelection selection) {
|
||||
super("Selected Ranges in " + program.getName(), tool, program, null);
|
||||
this.selection = selection;
|
||||
this.resultsLimit = resultsLimit;
|
||||
this.minLength = minLength;
|
||||
this.tool = tool;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLoad(Accumulator<AddressRangeInfo> accumulator, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
ToolOptions options = tool.getOptions(CodeBrowserSelectionPlugin.OPTION_CATEGORY_NAME);
|
||||
int resultsLimit = options.getInt(CodeBrowserSelectionPlugin.RANGES_LIMIT_OPTION_NAME,
|
||||
CodeBrowserSelectionPlugin.RANGES_LIMIT_DEFAULT);
|
||||
long minLength = options.getLong(CodeBrowserSelectionPlugin.MIN_RANGE_SIZE_OPTION_NAME,
|
||||
CodeBrowserSelectionPlugin.MIN_RANGE_SIZE_DEFAULT);
|
||||
|
||||
AddressRangeIterator rangeIter = selection.getAddressRanges();
|
||||
ReferenceManager refManager = program.getReferenceManager();
|
||||
while (rangeIter.hasNext()) {
|
||||
@@ -103,11 +107,6 @@ public class AddressRangeTableModel extends GhidraProgramTableModel<AddressRange
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
reload();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TableColumnDescriptor<AddressRangeInfo> createTableColumnDescriptor() {
|
||||
TableColumnDescriptor<AddressRangeInfo> descriptor = new TableColumnDescriptor<>();
|
||||
|
||||
@@ -151,11 +151,8 @@ public class CodeBrowserSelectionPlugin extends Plugin {
|
||||
tool.setStatusInfo("Unable to create selected ranges table: no addresses in selection");
|
||||
return;
|
||||
}
|
||||
ToolOptions options = tool.getOptions(OPTION_CATEGORY_NAME);
|
||||
int resultsLimit = options.getInt(RANGES_LIMIT_OPTION_NAME, RANGES_LIMIT_DEFAULT);
|
||||
long minLength = options.getLong(MIN_RANGE_SIZE_OPTION_NAME, MIN_RANGE_SIZE_DEFAULT);
|
||||
AddressRangeTableModel model =
|
||||
new AddressRangeTableModel(tool, program, selection, resultsLimit, minLength);
|
||||
|
||||
AddressRangeTableModel model = new AddressRangeTableModel(tool, program, selection);
|
||||
Icon markerIcon = new GIcon("icon.plugin.codebrowser.cursor.marker");
|
||||
String title = "Selected Ranges in " + program.getName();
|
||||
TableComponentProvider<AddressRangeInfo> tableProvider =
|
||||
|
||||
@@ -449,9 +449,6 @@ abstract class OperandFieldHelper extends FieldFactory {
|
||||
|
||||
private ListingField getFieldForInstruction(Instruction inst, ProxyObj<?> proxy, int varWidth) {
|
||||
int numOperands = inst.getNumOperands();
|
||||
if (numOperands == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
OpFieldResults results = new OpFieldResults(proxy);
|
||||
OperandFieldElement separator = createLeadingSeparatorElement(inst);
|
||||
|
||||
@@ -450,7 +450,7 @@ public class SymbolicPropogator {
|
||||
this.destination = destination;
|
||||
this.pcodeIndex = pcodeIndex;
|
||||
this.continueAfterHittingFlow = continueAfterHittingFlow;
|
||||
vContext.pushMemState();
|
||||
vContext.pushMemState(pcodeIndex != 0);
|
||||
}
|
||||
|
||||
public boolean isContinueAfterHittingFlow() {
|
||||
@@ -484,6 +484,9 @@ public class SymbolicPropogator {
|
||||
throws CancelledException {
|
||||
visitedBody = new AddressSet();
|
||||
AddressSet conflicts = new AddressSet();
|
||||
|
||||
// Locations that were jump and are now call targets and might be on saved future flows
|
||||
HashSet<Address> doNotFlowTo = new HashSet<>();
|
||||
|
||||
// prime the context stack with the entry point address
|
||||
Stack<SavedFlowState> contextStack = new Stack<>();
|
||||
@@ -536,6 +539,11 @@ public class SymbolicPropogator {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// don't follow flow if on list of jump targets that were turned into calls
|
||||
if (doNotFlowTo.contains(nextAddr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
HashSet<Address> visitSet = visitedMap.get(nextAddr);
|
||||
if (visitSet != null) {
|
||||
@@ -636,6 +644,9 @@ public class SymbolicPropogator {
|
||||
Address targets[] = getInstructionFlows(instr);
|
||||
for (Address target : targets) {
|
||||
handleFunctionSideEffects(instr, target, monitor);
|
||||
// a jump target has already been pushed as a future flow trace
|
||||
// need to make sure values aren't propagated into the call targets
|
||||
doNotFlowTo.add(target);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.program.model.symbol.Reference;
|
||||
import ghidra.program.model.symbol.ReferenceIterator;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.datastruct.FixedSizeHashMap;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
@@ -76,8 +77,16 @@ public class VarnodeContext implements ProcessorContext {
|
||||
// temp values for individual instruction computation before being merged into
|
||||
// the end flow state for an instruction
|
||||
private HashMap<Address, Varnode> tempVals = new HashMap<>();
|
||||
protected HashMap<Address, Varnode> tempUniqueVals = new HashMap<>();
|
||||
protected HashMap<Address, Varnode> tempUniqueVals;
|
||||
protected boolean keepTempUniqueValues = false;
|
||||
|
||||
// During tracing of paths, unique values need to be stored if the language has crossbuilds.
|
||||
// MaxCrossBuilds is the general number of uniques with values that should be stored in the cache.
|
||||
// The maxUniqueBytes is the number of actual entries (bytes) in the cache to keep. This is based
|
||||
// on the size of a pointer, which is in general the size of a register. This is not intended
|
||||
// to support general computation of values, and is more geared to 32/64 bit contstants and pointers.
|
||||
private static final int MaxCrossBuilds = 200; // maximum instructions worth of uniques
|
||||
private int maxUniqueBytes = 0; // number of bytes worth of uniques to keep
|
||||
|
||||
// Values that must be cleared from final instruction flow state
|
||||
protected HashSet<Varnode> clearVals = new HashSet<>();
|
||||
@@ -158,7 +167,10 @@ public class VarnodeContext implements ProcessorContext {
|
||||
|
||||
memoryVals.push(new HashMap<Address, Varnode>());
|
||||
regVals.push((new HashMap<Address, Varnode>()));
|
||||
uniqueVals.push(new HashMap<Address, Varnode>());
|
||||
|
||||
maxUniqueBytes = MaxCrossBuilds * program.getDefaultPointerSize();
|
||||
tempUniqueVals = new HashMap<Address,Varnode>();
|
||||
uniqueVals.push(new FixedSizeHashMap<Address, Varnode>(maxUniqueBytes));
|
||||
|
||||
setupValidSymbolicStackNames(program);
|
||||
|
||||
@@ -169,6 +181,9 @@ public class VarnodeContext implements ProcessorContext {
|
||||
if (language instanceof SleighLanguage) {
|
||||
// Must preserve temp values if named pcode sections exist (i.e., cross-builds are used)
|
||||
keepTempUniqueValues = ((SleighLanguage) language).numSections() != 0;
|
||||
if (keepTempUniqueValues) {
|
||||
tempUniqueVals = new FixedSizeHashMap<Address, Varnode>(maxUniqueBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -419,9 +434,13 @@ public class VarnodeContext implements ProcessorContext {
|
||||
Varnode rvnode = null;
|
||||
if (varnode.isUnique()) {
|
||||
rvnode = getMemoryValue(tempUniqueVals,varnode,signed);
|
||||
if (rvnode == null && keepTempUniqueValues) {
|
||||
rvnode = getMemoryValue(uniqueVals,0,varnode,signed);
|
||||
}
|
||||
// TODO: if doing full cross build tracking, need to
|
||||
// look back at uniqueVals stack. For now,
|
||||
// since any cross builds are flushed on branches
|
||||
// just use tempUniqueVals
|
||||
// if (rvnode == null && keepTempUniqueValues) {
|
||||
// rvnode = getMemoryValue(uniqueVals,0,varnode,signed);
|
||||
//}
|
||||
}
|
||||
else {
|
||||
rvnode = getMemoryValue(tempVals, varnode, signed);
|
||||
@@ -1029,9 +1048,13 @@ public class VarnodeContext implements ProcessorContext {
|
||||
// merge tempvals to top of regVals
|
||||
regVals.peek().putAll(tempVals);
|
||||
|
||||
if (keepTempUniqueValues) {
|
||||
uniqueVals.peek().putAll(tempUniqueVals);
|
||||
}
|
||||
// TODO: if doing full cross build tracking, need to
|
||||
// save tmpuniques into uniqueVals. For now,
|
||||
// since any cross builds are flushed on branches
|
||||
// just use tempUniqueVals
|
||||
//if (keepTempUniqueValues) {
|
||||
// uniqueVals.peek().putAll(tempUniqueVals);
|
||||
//}
|
||||
|
||||
if (clearContext) {
|
||||
if (!keepTempUniqueValues) {
|
||||
@@ -1971,18 +1994,33 @@ public class VarnodeContext implements ProcessorContext {
|
||||
|
||||
/**
|
||||
* Save the current memory state
|
||||
* @param saveTempUniques - if internal branching, must save the tempUniques as well
|
||||
* Note: currently unique values do not survive in the sleigh parser for crossbuild
|
||||
* lookback if any branch is taken. In the future crossbuilds may be path based.
|
||||
* This will need to be re-worked and the unique value state treated as other path
|
||||
* tracing and stored in uniqueVals.
|
||||
*/
|
||||
public void pushMemState() {
|
||||
public void pushMemState(boolean saveTempUniques) {
|
||||
Stack<HashMap<Address, Varnode>> newRegValsTrace =
|
||||
(Stack<HashMap<Address, Varnode>>) regVals.clone();
|
||||
regTraces.push(newRegValsTrace);
|
||||
regVals.push(new HashMap<Address, Varnode>());
|
||||
|
||||
// TODO: only save if need to
|
||||
Stack<HashMap<Address, Varnode>> newUniqueValsTrace =
|
||||
(Stack<HashMap<Address, Varnode>>) uniqueVals.clone();
|
||||
uniqueTraces.push(newUniqueValsTrace);
|
||||
uniqueVals.push(new HashMap<Address, Varnode>());
|
||||
FixedSizeHashMap<Address, Varnode> uniqueValsState = new FixedSizeHashMap<Address, Varnode>(maxUniqueBytes);
|
||||
// if pushing state for internal branching, must save unique state for restored path
|
||||
// For now, only put temp unique values if internally branching.
|
||||
// Note: saved tempUniqueVals are stored at the top of the trace stack, this is different than
|
||||
// than other trace stacks, as those trace stacks, the top of the stack is the current
|
||||
// state and the older stack entries are existing old states before a branch occurred.
|
||||
if (saveTempUniques) {
|
||||
newUniqueValsTrace.push((HashMap<Address, Varnode>) tempUniqueVals.clone());
|
||||
} else {
|
||||
newUniqueValsTrace.push(new FixedSizeHashMap<>(maxUniqueBytes));
|
||||
}
|
||||
uniqueVals.push(uniqueValsState);
|
||||
|
||||
Stack<HashMap<Address, Varnode>> newMemValsTrace =
|
||||
(Stack<HashMap<Address, Varnode>>) memoryVals.clone();
|
||||
@@ -1999,9 +2037,14 @@ public class VarnodeContext implements ProcessorContext {
|
||||
public void popMemState() {
|
||||
regVals = regTraces.pop();
|
||||
memoryVals = memTraces.pop();
|
||||
|
||||
// TODO: only save if need to
|
||||
|
||||
// restore old temp values if any was saved
|
||||
tempUniqueVals = uniqueTraces.peek().peek();
|
||||
uniqueVals = uniqueTraces.pop();
|
||||
if (tempUniqueVals == null) {
|
||||
// if no tempUnique values stored for this path
|
||||
tempUniqueVals = new FixedSizeHashMap<>(maxUniqueBytes);
|
||||
}
|
||||
|
||||
lastSet = lastSetSaves.pop();
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -25,8 +25,7 @@ import ghidra.app.cmd.label.DemanglerCmd;
|
||||
import ghidra.app.plugin.core.analysis.ReferenceAddressPair;
|
||||
import ghidra.app.util.NamespaceUtils;
|
||||
import ghidra.app.util.PseudoDisassembler;
|
||||
import ghidra.app.util.demangler.DemangledObject;
|
||||
import ghidra.app.util.demangler.DemanglerUtil;
|
||||
import ghidra.app.util.demangler.*;
|
||||
import ghidra.framework.plugintool.ServiceProvider;
|
||||
import ghidra.program.flatapi.FlatProgramAPI;
|
||||
import ghidra.program.model.address.*;
|
||||
@@ -2859,7 +2858,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||
}
|
||||
mangledLabel = "_ZTS" + mangledLabel;
|
||||
|
||||
if (!isTypeinfoNameString(mangledLabel)) {
|
||||
if (!isTypeinfoNameString(mangledLabel, typeinfoNameAddress)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -3029,15 +3028,27 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isTypeinfoNameString(String string) {
|
||||
private boolean isTypeinfoNameString(String string, Address address) {
|
||||
|
||||
DemangledObject demangledObject = DemanglerUtil.demangle(string);
|
||||
if (demangledObject == null) {
|
||||
List<DemangledObject> demangledObjects = DemanglerUtil.demangle(program, string, address);
|
||||
if (demangledObjects == null || demangledObjects.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (demangledObject.getName().equals("typeinfo-name")) {
|
||||
return true;
|
||||
for (DemangledObject demangledObject : demangledObjects) {
|
||||
|
||||
DemanglerOptions options = demangledObject.getMangledContext().getOptions();
|
||||
|
||||
// Currently no good way to do this since this is in Decompiler package and GnuDemangler
|
||||
// is in its own package. Once no longer a script but an analyzer in Base, update to
|
||||
// do !(options instanceof GnuDemanglerOptions)
|
||||
if (!options.toString().contains("gnu")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (demangledObject.getName().equals("typeinfo-name")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1516,6 +1516,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||
highFunction, recoveredClass, constructor, vbtableOffset);
|
||||
|
||||
if (vbtableAddress != null) {
|
||||
if (isInvalidVbtable(vbtableAddress)) {
|
||||
continue;
|
||||
}
|
||||
return vbtableAddress;
|
||||
}
|
||||
}
|
||||
@@ -1541,6 +1544,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||
highFunction, recoveredClass, constructor, vbtableOffset);
|
||||
|
||||
if (vbtableAddress != null) {
|
||||
if (isInvalidVbtable(vbtableAddress)) {
|
||||
continue;
|
||||
}
|
||||
return vbtableAddress;
|
||||
}
|
||||
}
|
||||
@@ -1549,6 +1555,33 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||
|
||||
}
|
||||
|
||||
private boolean isInvalidVbtable(Address address) {
|
||||
|
||||
// check to see if already has a non-default symbol that is not vbtable
|
||||
Symbol symbol = program.getSymbolTable().getPrimarySymbol(address);
|
||||
if (symbol.getSource() != SourceType.DEFAULT &&
|
||||
!symbol.getName().contains("vbtable")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// check to see if table contains an address reference
|
||||
// if it is an address then is very unlikely this is a vbtable since
|
||||
// it needs offset values and most are either large negatives (FFFFF....) or small offsets
|
||||
// both of which are not valid addresses in a normal PE binary
|
||||
Address referencedAddress = extendedFlatAPI.getPointer(address);
|
||||
|
||||
// if null then not an address so possibly valid
|
||||
if (referencedAddress == null) {
|
||||
return false;
|
||||
}
|
||||
// if is program memory location then invalid
|
||||
if (program.getMemory().contains(referencedAddress)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to find the address of the vbtable referenced at the given offset in the given function
|
||||
* @param fillStructHelper a reusable {@link FillOutStructureHelper} instance to be used
|
||||
|
||||
@@ -22,10 +22,10 @@ import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
import ghidra.util.exception.*;
|
||||
|
||||
/**
|
||||
* This command will create a TypeDescriptor data type. Since unsized arrays are not properly
|
||||
@@ -133,8 +133,10 @@ public class CreateTypeDescriptorBackgroundCmd
|
||||
|
||||
Program program = model.getProgram();
|
||||
String demangledName = model.getDemangledTypeDescriptor();
|
||||
|
||||
// if cannot demangle then use the mangled name
|
||||
if (demangledName == null) {
|
||||
return false;
|
||||
demangledName = model.getOriginalTypename();
|
||||
}
|
||||
String prefix = demangledName + " ";
|
||||
|
||||
@@ -147,9 +149,25 @@ public class CreateTypeDescriptorBackgroundCmd
|
||||
// Label
|
||||
Namespace classNamespace = model.getDescriptorAsNamespace();
|
||||
|
||||
if (classNamespace == null) {
|
||||
Msg.error(RttiUtil.class, "Cannot get namespace from model " + model.getAddress());
|
||||
return false;
|
||||
// if cannot demangle then use the mangled name as the namespace
|
||||
if (classNamespace == null || classNamespace.isGlobal()) {
|
||||
Msg.error(RttiUtil.class, "Cannot get demangled namespace from model " +
|
||||
model.getAddress() + " so will use the mangled name for the namespace");
|
||||
try {
|
||||
classNamespace = program.getSymbolTable()
|
||||
.getOrCreateNameSpace(program.getGlobalNamespace(), demangledName,
|
||||
SourceType.IMPORTED);
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
// ok if it is duplicate as it was likely created in another rtti handling method
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
Msg.error(TypeDescriptorModel.class,
|
||||
"Failed to create mangled namespace: " + e.getMessage());
|
||||
classNamespace = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// If PDB had been run, then the namespace here might already have been promoted to
|
||||
|
||||
@@ -28,11 +28,9 @@ import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.DumbMemBufferImpl;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
@@ -473,6 +471,10 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel {
|
||||
return hasComplexType() ? demangledDataType.getOriginalDemangled() : null;
|
||||
}
|
||||
|
||||
public String getOriginalTypename() {
|
||||
return originalTypeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets just the name of the type descriptor.
|
||||
* @return the name of the thing referred to by this descriptor, or null if it couldn't
|
||||
@@ -583,6 +585,23 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel {
|
||||
Program program = getProgram();
|
||||
namespace = DemangledObject.createNamespace(program, demangledDataType,
|
||||
program.getGlobalNamespace(), false);
|
||||
|
||||
// if for some reason the mangled name can't be demangled, use the mangled name
|
||||
if (namespace.isGlobal()) {
|
||||
try {
|
||||
namespace = program.getSymbolTable()
|
||||
.getOrCreateNameSpace(program.getGlobalNamespace(), originalTypeName,
|
||||
SourceType.IMPORTED);
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
// ok if it is duplicate as it was likely created in another rtti handling method
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
Msg.error(TypeDescriptorModel.class,
|
||||
"Failed to create namespace: " + e.getMessage());
|
||||
namespace = null;
|
||||
}
|
||||
}
|
||||
return namespace;
|
||||
}
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ public class CreateVfTableBackgroundCmd extends AbstractCreateDataBackgroundCmd<
|
||||
String demangledTypeDescriptor = rtti0Model.getDemangledTypeDescriptor();
|
||||
String prefixString = ((demangledTypeDescriptor != null)
|
||||
? (demangledTypeDescriptor + Namespace.DELIMITER)
|
||||
: "");
|
||||
: rtti0Model.getOriginalTypename() + Namespace.DELIMITER);
|
||||
data.setComment(CommentType.EOL, "terminator for " + prefixString + VF_TABLE_LABEL);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -23,8 +23,10 @@ import ghidra.app.cmd.data.TypeDescriptorModel;
|
||||
import ghidra.app.util.NamespaceUtils;
|
||||
import ghidra.app.util.PseudoDisassembler;
|
||||
import ghidra.app.util.datatype.microsoft.MSDataTypeUtils;
|
||||
import ghidra.app.util.demangler.DemangledException;
|
||||
import ghidra.app.util.demangler.DemangledObject;
|
||||
import ghidra.app.util.demangler.DemanglerUtil;
|
||||
import ghidra.app.util.demangler.microsoft.MicrosoftDemangler;
|
||||
import ghidra.app.util.demangler.microsoft.MicrosoftMangledContext;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.listing.*;
|
||||
@@ -82,16 +84,22 @@ public class RttiUtil {
|
||||
}
|
||||
|
||||
// check for similar symbol
|
||||
MicrosoftDemangler demangler = new MicrosoftDemangler();
|
||||
DemangledObject matchingDemangledObject = null;
|
||||
SymbolIterator symbols = symbolTable.getSymbolsAsIterator(rttiAddress);
|
||||
for (Symbol symbol : symbols) {
|
||||
String name = symbol.getName();
|
||||
|
||||
// if mangled get the matching demangled object if there is one and save for after loop
|
||||
// in case symbols are not demangled yet
|
||||
DemangledObject demangledObject = DemanglerUtil.demangle(name);
|
||||
if (demangledObject != null && demangledObject.getName().contains(rttiSuffix)) {
|
||||
matchingDemangledObject = demangledObject;
|
||||
try {
|
||||
MicrosoftMangledContext mangledContext =
|
||||
demangler.createMangledContext(name, null, program, symbol.getAddress());
|
||||
DemangledObject demangledObject = demangler.demangle(mangledContext);
|
||||
if (demangledObject != null && demangledObject.getName().contains(rttiSuffix)) {
|
||||
matchingDemangledObject = demangledObject;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
catch (DemangledException e) {
|
||||
// Couldn't demangle.
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -313,7 +321,11 @@ public class RttiUtil {
|
||||
public static String getDescriptorTypeNamespace(TypeDescriptorModel rtti0Model) {
|
||||
String descriptorTypeNamespace = rtti0Model.getDescriptorTypeNamespace(); // Can be null.
|
||||
if (descriptorTypeNamespace == null) {
|
||||
descriptorTypeNamespace = ""; // Couldn't get namespace so leave it off.
|
||||
|
||||
descriptorTypeNamespace = rtti0Model.getOriginalTypename();
|
||||
|
||||
Msg.warn(RttiUtil.class, rtti0Model.getAddress().toString() +
|
||||
": Could not demangle TypeDescriptor namespace so using the mangled string as the namespace.");
|
||||
}
|
||||
return descriptorTypeNamespace;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -45,6 +45,7 @@ public class SarifBookmarkWriter extends AbstractExtWriter {
|
||||
private void genBookmarks(TaskMonitor monitor) throws CancelledException, IOException{
|
||||
monitor.initialize(bookmarks.size());
|
||||
for (Bookmark b : bookmarks) {
|
||||
monitor.checkCancelled();
|
||||
ExtBookmark isf = new ExtBookmark(b);
|
||||
SarifObject sarif = new SarifObject(BookmarksSarifMgr.SUBKEY, BookmarksSarifMgr.KEY, getTree(isf), b.getAddress(), b.getAddress());
|
||||
objects.add(getTree(sarif));
|
||||
|
||||
@@ -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.
|
||||
@@ -50,6 +50,7 @@ public class SarifCodeWriter extends AbstractExtWriter {
|
||||
private void genCode(TaskMonitor monitor) throws CancelledException, IOException{
|
||||
monitor.initialize(blocks.size());
|
||||
for (AddressRange range : blocks) {
|
||||
monitor.checkCancelled();
|
||||
ExtCodeBlock isf = new ExtCodeBlock(range);
|
||||
SarifObject sarif = new SarifObject(CodeSarifMgr.SUBKEY, CodeSarifMgr.KEY, getTree(isf), range.getMinAddress(), range.getMaxAddress());
|
||||
objects.add(getTree(sarif));
|
||||
|
||||
@@ -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.
|
||||
@@ -56,6 +56,7 @@ public class SarifCommentWriter extends AbstractExtWriter {
|
||||
}
|
||||
monitor.initialize(comments0.size());
|
||||
for (Pair<CodeUnit, Pair<String, String>> pair : comments0) {
|
||||
monitor.checkCancelled();
|
||||
CodeUnit cu = pair.first;
|
||||
ExtComment isf = new ExtComment(pair.second, true);
|
||||
SarifObject sarif = new SarifObject(CommentsSarifMgr.SUBKEY, CommentsSarifMgr.KEY, getTree(isf), cu.getMinAddress(),
|
||||
|
||||
@@ -45,6 +45,7 @@ public class SarifDataWriter extends AbstractExtWriter {
|
||||
private void genData(TaskMonitor monitor) throws CancelledException {
|
||||
monitor.initialize(definedData.size());
|
||||
for (Data d : definedData) {
|
||||
monitor.checkCancelled();
|
||||
ExtData isf = new ExtData(d);
|
||||
SarifObject sarif = new SarifObject("DefinedData", DefinedDataSarifMgr.KEY,
|
||||
getTree(isf), d.getMinAddress(), d.getMaxAddress());
|
||||
|
||||
@@ -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.
|
||||
@@ -44,6 +44,7 @@ public class SarifEntryPointWriter extends AbstractExtWriter {
|
||||
private void genCode(TaskMonitor monitor) throws CancelledException, IOException{
|
||||
monitor.initialize(entryPoints.size());
|
||||
for (Address addr : entryPoints) {
|
||||
monitor.checkCancelled();
|
||||
ExtEntryPoint isf = new ExtEntryPoint(addr);
|
||||
SarifObject sarif = new SarifObject(ExtEntryPointSarifMgr.SUBKEY, ExtEntryPointSarifMgr.KEY, getTree(isf), addr, addr);
|
||||
objects.add(getTree(sarif));
|
||||
|
||||
@@ -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.
|
||||
@@ -44,6 +44,7 @@ public class SarifEquateWriter extends AbstractExtWriter {
|
||||
private void genCode(TaskMonitor monitor) throws CancelledException, IOException{
|
||||
monitor.initialize(equates.size());
|
||||
for (Equate equate : equates) {
|
||||
monitor.checkCancelled();
|
||||
ExtEquate isf = new ExtEquate(equate);
|
||||
SarifObject sarif = new SarifObject(EquatesSarifMgr.SUBKEY, EquatesSarifMgr.KEY, getTree(isf), null);
|
||||
objects.add(getTree(sarif));
|
||||
|
||||
@@ -53,6 +53,7 @@ public class SarifClassesNamespaceWriter extends AbstractExtWriter {
|
||||
monitor.initialize(classes.size());
|
||||
Iterator<GhidraClass> classNamespaces = symbolTable.getClassNamespaces();
|
||||
while (classNamespaces.hasNext()) {
|
||||
monitor.checkCancelled();
|
||||
GhidraClass next = classNamespaces.next();
|
||||
walkSymbols(next);
|
||||
monitor.increment();
|
||||
|
||||
@@ -22,10 +22,7 @@ import java.util.List;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
|
||||
import ghidra.program.model.symbol.ExternalLocation;
|
||||
import ghidra.program.model.symbol.ExternalLocationIterator;
|
||||
import ghidra.program.model.symbol.ExternalManager;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import sarif.export.AbstractExtWriter;
|
||||
@@ -53,6 +50,7 @@ public class SarifExternalLibraryWriter extends AbstractExtWriter {
|
||||
private void genLibraries(TaskMonitor monitor) throws CancelledException, IOException {
|
||||
monitor.initialize(externalNames.size());
|
||||
for (String n : externalNames) {
|
||||
monitor.checkCancelled();
|
||||
String path = externalManager.getExternalLibraryPath(n);
|
||||
if (path == null) {
|
||||
path = "";
|
||||
@@ -63,6 +61,7 @@ public class SarifExternalLibraryWriter extends AbstractExtWriter {
|
||||
|
||||
ExternalLocationIterator externalLocations = externalManager.getExternalLocations(n);
|
||||
while (externalLocations.hasNext()) {
|
||||
monitor.checkCancelled();
|
||||
ExternalLocation loc = externalLocations.next();
|
||||
ExtLibraryLocation obj = new ExtLibraryLocation(loc);
|
||||
SarifObject sarif2 = new SarifObject(ExternalLibSarifMgr.SUBKEY1, ExternalLibSarifMgr.KEY, getTree(obj), loc.getAddress(), loc.getAddress());
|
||||
|
||||
@@ -56,6 +56,7 @@ public class SarifFunctionWriter extends AbstractExtWriter {
|
||||
private void genFunctions(TaskMonitor monitor) throws CancelledException, IOException{
|
||||
monitor.initialize(requestedFunctions.size());
|
||||
for (Function f : requestedFunctions) {
|
||||
monitor.checkCancelled();
|
||||
addSymbol(f.getSymbol());
|
||||
ExtFunction isf = new ExtFunction(f, monitor);
|
||||
SarifObject sarif = new SarifObject("Function", FunctionsSarifMgr.KEY, getTree(isf), f.getBody());
|
||||
|
||||
@@ -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.
|
||||
@@ -52,6 +52,7 @@ public class SarifMemoryMapWriter extends AbstractExtWriter {
|
||||
private void genMaps(TaskMonitor monitor) throws CancelledException, IOException {
|
||||
monitor.initialize(memory.size());
|
||||
for (Pair<AddressRange, MemoryBlock> m : memory) {
|
||||
monitor.checkCancelled();
|
||||
AddressRange range = m.first;
|
||||
ExtMemoryMap isf = new ExtMemoryMap(m.first, m.second, bytesFile, write);
|
||||
SarifObject sarif = new SarifObject(MemoryMapSarifMgr.SUBKEY, MemoryMapSarifMgr.KEY, getTree(isf),
|
||||
|
||||
@@ -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.
|
||||
@@ -52,9 +52,7 @@ public class SarifPropertyListWriter extends AbstractExtWriter {
|
||||
List<String> propNames = propList.getOptionNames();
|
||||
Collections.sort(propNames);
|
||||
for (String name : propNames) {
|
||||
if (monitor.isCancelled()) {
|
||||
throw new CancelledException();
|
||||
}
|
||||
monitor.checkCancelled();
|
||||
if (propList.isAlias(name)) { // don't write out properties that are just mirrors of some other property
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -19,16 +19,9 @@ import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressIterator;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.util.IntPropertyMap;
|
||||
import ghidra.program.model.util.LongPropertyMap;
|
||||
import ghidra.program.model.util.ObjectPropertyMap;
|
||||
import ghidra.program.model.util.PropertyMap;
|
||||
import ghidra.program.model.util.StringPropertyMap;
|
||||
import ghidra.program.model.util.VoidPropertyMap;
|
||||
import ghidra.program.model.util.*;
|
||||
import ghidra.util.SaveableColor;
|
||||
import ghidra.util.SaveablePoint;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
@@ -78,6 +71,7 @@ public class SarifPropertyMapWriter extends AbstractExtWriter {
|
||||
private void genVoidMap(VoidPropertyMap map, TaskMonitor monitor) throws CancelledException {
|
||||
AddressIterator iter = set != null ? map.getPropertyIterator(set) : map.getPropertyIterator();
|
||||
while (iter.hasNext()) {
|
||||
monitor.checkCancelled();
|
||||
Address addr = iter.next();
|
||||
ExtProperty isf = new ExtProperty(map.getName(), "void", null);
|
||||
SarifObject sarif = new SarifObject(PropertiesSarifMgr.SUBKEY, PropertiesSarifMgr.KEY, getTree(isf), addr,
|
||||
@@ -90,9 +84,7 @@ public class SarifPropertyMapWriter extends AbstractExtWriter {
|
||||
private void genIntMap(IntPropertyMap map, TaskMonitor monitor) throws CancelledException {
|
||||
AddressIterator iter = set != null ? map.getPropertyIterator(set) : map.getPropertyIterator();
|
||||
while (iter.hasNext()) {
|
||||
if (monitor.isCancelled()) {
|
||||
throw new CancelledException();
|
||||
}
|
||||
monitor.checkCancelled();
|
||||
try {
|
||||
Address addr = iter.next();
|
||||
int value = map.getInt(addr);
|
||||
@@ -109,9 +101,7 @@ public class SarifPropertyMapWriter extends AbstractExtWriter {
|
||||
private void genLongMap(LongPropertyMap map, TaskMonitor monitor) throws CancelledException {
|
||||
AddressIterator iter = set != null ? map.getPropertyIterator(set) : map.getPropertyIterator();
|
||||
while (iter.hasNext()) {
|
||||
if (monitor.isCancelled()) {
|
||||
throw new CancelledException();
|
||||
}
|
||||
monitor.checkCancelled();
|
||||
try {
|
||||
Address addr = iter.next();
|
||||
long value = map.getLong(addr);
|
||||
@@ -129,9 +119,7 @@ public class SarifPropertyMapWriter extends AbstractExtWriter {
|
||||
private void genStringMap(StringPropertyMap map, TaskMonitor monitor) throws CancelledException {
|
||||
AddressIterator iter = set != null ? map.getPropertyIterator(set) : map.getPropertyIterator();
|
||||
while (iter.hasNext()) {
|
||||
if (monitor.isCancelled()) {
|
||||
throw new CancelledException();
|
||||
}
|
||||
monitor.checkCancelled();
|
||||
Address addr = iter.next();
|
||||
String value = map.getString(addr);
|
||||
ExtProperty isf = new ExtProperty(map.getName(), "string", value);
|
||||
@@ -145,9 +133,7 @@ public class SarifPropertyMapWriter extends AbstractExtWriter {
|
||||
private void genObjectMap(ObjectPropertyMap<?> map, TaskMonitor monitor) throws CancelledException {
|
||||
AddressIterator iter = set != null ? map.getPropertyIterator(set) : map.getPropertyIterator();
|
||||
while (iter.hasNext()) {
|
||||
if (monitor.isCancelled()) {
|
||||
throw new CancelledException();
|
||||
}
|
||||
monitor.checkCancelled();
|
||||
Address addr = iter.next();
|
||||
Object value = map.get(addr);
|
||||
ExtProperty isf;
|
||||
|
||||
@@ -23,9 +23,7 @@ import com.google.gson.JsonArray;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.symbol.Equate;
|
||||
import ghidra.program.model.symbol.EquateReference;
|
||||
import ghidra.program.model.symbol.EquateTable;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import sarif.export.AbstractExtWriter;
|
||||
@@ -52,17 +50,12 @@ public class SarifEquateRefWriter extends AbstractExtWriter {
|
||||
|
||||
Iterator<Equate> iter = equateTable.getEquates();
|
||||
while (iter.hasNext()) {
|
||||
if (monitor.isCancelled()) {
|
||||
throw new CancelledException();
|
||||
}
|
||||
Equate equate = iter.next();
|
||||
String name = equate.getName();
|
||||
long value = equate.getValue();
|
||||
EquateReference[] refs = equate.getReferences();
|
||||
for (int i = 0; i < refs.length; i++) {
|
||||
if (monitor.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
monitor.checkCancelled();
|
||||
Address addr = refs[i].getAddress();
|
||||
if (!set.contains(addr)) {
|
||||
continue;
|
||||
|
||||
@@ -23,9 +23,7 @@ import com.google.gson.JsonArray;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.symbol.Equate;
|
||||
import ghidra.program.model.symbol.EquateReference;
|
||||
import ghidra.program.model.symbol.EquateTable;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import sarif.export.AbstractExtWriter;
|
||||
@@ -60,9 +58,7 @@ public class SarifEquateWriter extends AbstractExtWriter {
|
||||
long value = equate.getValue();
|
||||
EquateReference[] refs = equate.getReferences();
|
||||
for (int i = 0; i < refs.length; i++) {
|
||||
if (monitor.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
monitor.checkCancelled();
|
||||
Address addr = refs[i].getAddress();
|
||||
if (!set.contains(addr)) {
|
||||
continue;
|
||||
|
||||
@@ -23,12 +23,7 @@ import java.util.List;
|
||||
import com.google.gson.JsonArray;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.symbol.ExternalLocation;
|
||||
import ghidra.program.model.symbol.ExternalReference;
|
||||
import ghidra.program.model.symbol.Reference;
|
||||
import ghidra.program.model.symbol.ReferenceManager;
|
||||
import ghidra.program.model.symbol.ShiftedReference;
|
||||
import ghidra.program.model.symbol.StackReference;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import sarif.export.AbstractExtWriter;
|
||||
@@ -63,9 +58,7 @@ public class SarifReferenceWriter extends AbstractExtWriter {
|
||||
for (Address addr : references) {
|
||||
Reference[] refs = referenceManager.getReferencesFrom(addr);
|
||||
for (int i = 0; i < refs.length; i++) {
|
||||
if (monitor.isCancelled()) {
|
||||
throw new CancelledException();
|
||||
}
|
||||
monitor.checkCancelled();
|
||||
Reference ref = refs[i];
|
||||
if (ref.isRegisterReference()) {
|
||||
ExtRegisterReference mref = new ExtRegisterReference(ref);
|
||||
|
||||
@@ -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.
|
||||
@@ -44,6 +44,7 @@ public class SarifRelocationWriter extends AbstractExtWriter {
|
||||
private void genRelocation(TaskMonitor monitor) throws CancelledException, IOException {
|
||||
monitor.initialize(relocs.size());
|
||||
for (Relocation r : relocs) {
|
||||
monitor.checkCancelled();
|
||||
ExtRelocation isf = new ExtRelocation(r);
|
||||
SarifObject sarif = new SarifObject(RelocationTableSarifMgr.SUBKEY, RelocationTableSarifMgr.KEY,
|
||||
getTree(isf), r.getAddress(), r.getAddress());
|
||||
|
||||
@@ -22,9 +22,7 @@ import java.util.List;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
import ghidra.program.model.symbol.SymbolType;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import sarif.export.AbstractExtWriter;
|
||||
@@ -49,6 +47,7 @@ public class SarifSymbolWriter extends AbstractExtWriter {
|
||||
private void genSymbols(TaskMonitor monitor) throws CancelledException, IOException{
|
||||
monitor.initialize(symbols.size());
|
||||
for (Symbol s : symbols) {
|
||||
monitor.checkCancelled();
|
||||
SymbolType symbolType = s.getSymbolType();
|
||||
if (s.getSource() == SourceType.DEFAULT) {
|
||||
continue;
|
||||
|
||||
@@ -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.
|
||||
@@ -47,6 +47,7 @@ public class SarifTreeWriter extends AbstractExtWriter {
|
||||
private void genTree(TaskMonitor monitor) throws CancelledException, IOException {
|
||||
monitor.initialize(modules.size());
|
||||
for (Pair<String, ProgramModule> pair : modules) {
|
||||
monitor.checkCancelled();
|
||||
ExtModule isf = new ExtModule(pair.first, pair.second, visited);
|
||||
SarifObject sarif = new SarifObject(ProgramTreeSarifMgr.SUBKEY, ProgramTreeSarifMgr.KEY, getTree(isf), null);
|
||||
objects.add(getTree(sarif));
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package docking.action;
|
||||
|
||||
import java.awt.event.InputEvent;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.*;
|
||||
@@ -102,6 +103,9 @@ public class KeyBindingsManager implements PropertyChangeListener {
|
||||
|
||||
// map standard keystroke to action
|
||||
doAddKeyBinding(provider, action, keyStroke);
|
||||
|
||||
// map workaround keystroke to action
|
||||
fixupAltGraphKeyStrokeMapping(provider, action, keyStroke);
|
||||
}
|
||||
|
||||
public String validateActionKeyBinding(DockingActionIf dockingAction, KeyStroke ks) {
|
||||
@@ -146,6 +150,24 @@ public class KeyBindingsManager implements PropertyChangeListener {
|
||||
doAddKeyBinding(provider, action, keyStroke, keyStroke);
|
||||
}
|
||||
|
||||
private void fixupAltGraphKeyStrokeMapping(ComponentProvider provider, DockingActionIf action,
|
||||
KeyStroke keyStroke) {
|
||||
|
||||
// special case
|
||||
int modifiers = keyStroke.getModifiers();
|
||||
if ((modifiers & InputEvent.ALT_DOWN_MASK) == InputEvent.ALT_DOWN_MASK) {
|
||||
//
|
||||
// Also register the 'Alt' binding with the 'Alt Graph' mask. This fixes the but
|
||||
// on Windows (https://bugs.openjdk.java.net/browse/JDK-8194873)
|
||||
// that have different key codes for the left and right Alt keys.
|
||||
//
|
||||
modifiers |= InputEvent.ALT_GRAPH_DOWN_MASK;
|
||||
KeyStroke updateKeyStroke =
|
||||
KeyStroke.getKeyStroke(keyStroke.getKeyCode(), modifiers, false);
|
||||
doAddKeyBinding(provider, action, updateKeyStroke, keyStroke);
|
||||
}
|
||||
}
|
||||
|
||||
private void doAddKeyBinding(ComponentProvider provider, DockingActionIf action,
|
||||
KeyStroke mappingKeyStroke, KeyStroke actionKeyStroke) {
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -24,6 +24,7 @@ import org.apache.commons.io.FileUtils;
|
||||
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.util.Msg;
|
||||
import utilities.util.FileUtilities;
|
||||
|
||||
/**
|
||||
* Reads Themes from a file or {@link Reader}
|
||||
@@ -138,6 +139,9 @@ class ThemeReader extends AbstractThemeReader {
|
||||
String relativePath = path.substring(indexOf, path.length());
|
||||
File dir = Application.getUserSettingsDirectory();
|
||||
File iconFile = new File(dir, relativePath);
|
||||
if (!FileUtilities.isPathContainedWithin(dir, iconFile)) {
|
||||
throw new IOException("Zip entry escapes target directory: " + relativePath);
|
||||
}
|
||||
FileUtils.copyInputStreamToFile(is, iconFile);
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -55,31 +55,36 @@ abstract class AbstractTransactionManager {
|
||||
|
||||
checkLockingTask();
|
||||
|
||||
boolean doPrepare = false;
|
||||
synchronized (this) {
|
||||
if (getCurrentTransactionInfo() != null && !transactionTerminated) {
|
||||
return false;
|
||||
}
|
||||
if (lockCount == 0) {
|
||||
for (DomainObjectAdapterDB domainObj : getDomainObjects()) {
|
||||
if (domainObj.isChanged()) {
|
||||
domainObj.prepareToSave();
|
||||
}
|
||||
}
|
||||
doPrepare = true;
|
||||
}
|
||||
lockReason = reason;
|
||||
++lockCount;
|
||||
return true;
|
||||
}
|
||||
if (doPrepare) {
|
||||
for (DomainObjectAdapterDB domainObj : getDomainObjects()) {
|
||||
if (domainObj.isChanged()) {
|
||||
domainObj.prepareToSave();
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to obtain a modification lock on the domain object when generating a
|
||||
* background snapshot.
|
||||
* Attempt to obtain a modification lock on the domain object when generating a background
|
||||
* snapshot.
|
||||
*
|
||||
* @param domainObj domain object corresponding to snapshot
|
||||
* @param hasProgress true if monitor has progress indicator
|
||||
* @param title title to be used for monitor
|
||||
* @return monitor object if lock obtained successfully, else null which indicates that a
|
||||
* modification is in process.
|
||||
* modification is in process.
|
||||
*/
|
||||
final synchronized LockingTaskMonitor lockForSnapshot(DomainObjectAdapterDB domainObj,
|
||||
boolean hasProgress, String title) {
|
||||
@@ -106,9 +111,10 @@ abstract class AbstractTransactionManager {
|
||||
|
||||
/**
|
||||
* Force transaction lock and terminate current transaction.
|
||||
*
|
||||
* @param rollback true if rollback of non-commited changes should occurs, false if commit
|
||||
* should be done. NOTE: it can be potentially detrimental to commit an incomplete transaction
|
||||
* and should be avoided.
|
||||
* should be done. NOTE: it can be potentially detrimental to commit an incomplete
|
||||
* transaction and should be avoided.
|
||||
* @param reason very short reason for requesting lock
|
||||
*/
|
||||
final void forceLock(boolean rollback, String reason) {
|
||||
@@ -131,9 +137,10 @@ abstract class AbstractTransactionManager {
|
||||
|
||||
/**
|
||||
* Terminate current transaction.
|
||||
*
|
||||
* @param rollback true if rollback of non-commited changes should occurs, false if commit
|
||||
* should be done. NOTE: it can be potentially detrimental to commit an incomplete transaction
|
||||
* and should be avoided.
|
||||
* should be done. NOTE: it can be potentially detrimental to commit an incomplete
|
||||
* transaction and should be avoided.
|
||||
* @param notify true for listeners to be notified else false
|
||||
*/
|
||||
abstract void terminateTransaction(boolean rollback, boolean notify);
|
||||
@@ -159,8 +166,7 @@ abstract class AbstractTransactionManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Block on active locking task.
|
||||
* Do not invoke this method from within a synchronized block.
|
||||
* Block on active locking task. Do not invoke this method from within a synchronized block.
|
||||
*/
|
||||
final void checkLockingTask() {
|
||||
synchronized (this) {
|
||||
@@ -173,6 +179,7 @@ abstract class AbstractTransactionManager {
|
||||
|
||||
/**
|
||||
* Throw lock exception if currently locked
|
||||
*
|
||||
* @throws DomainObjectLockedException if currently locked
|
||||
*/
|
||||
final void verifyNoLock() throws DomainObjectLockedException {
|
||||
@@ -194,7 +201,7 @@ abstract class AbstractTransactionManager {
|
||||
}
|
||||
}
|
||||
|
||||
final int startTransaction(DomainObjectAdapterDB object, String description,
|
||||
final int startTransactionChecked(DomainObjectAdapterDB object, String description,
|
||||
AbortedTransactionListener listener, boolean notify)
|
||||
throws TerminatedTransactionException {
|
||||
|
||||
@@ -222,47 +229,53 @@ abstract class AbstractTransactionManager {
|
||||
boolean commit, boolean notify) throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Returns the undo stack depth.
|
||||
* (The number of items on the undo stack)
|
||||
* This method is for JUnits.
|
||||
* Returns the undo stack depth. (The number of items on the undo stack) This method is for
|
||||
* JUnits.
|
||||
*
|
||||
* @return the undo stack depth
|
||||
*/
|
||||
abstract int getUndoStackDepth();
|
||||
|
||||
/**
|
||||
* Returns true if there is at least one redo transaction to be redone.
|
||||
*
|
||||
* @return true if there is at least one redo transaction to be redone
|
||||
*/
|
||||
abstract boolean canRedo();
|
||||
|
||||
/**
|
||||
* Returns true if there is at least one undo transaction to be undone.
|
||||
*
|
||||
* @return true if there is at least one undo transaction to be undone
|
||||
*/
|
||||
abstract boolean canUndo();
|
||||
|
||||
/**
|
||||
* Returns the name of the next undo transaction (The most recent change).
|
||||
*
|
||||
* @return the name of the next undo transaction (The most recent change)
|
||||
*/
|
||||
abstract String getRedoName();
|
||||
|
||||
/**
|
||||
* Returns the name of the next redo transaction (The most recent undo).
|
||||
*
|
||||
* @return the name of the next redo transaction (The most recent undo)
|
||||
*/
|
||||
abstract String getUndoName();
|
||||
|
||||
/**
|
||||
* Returns the names of all undoable transactions in reverse chronological order. In other
|
||||
* words the transaction at the top of the list must be undone first.
|
||||
* Returns the names of all undoable transactions in reverse chronological order. In other words
|
||||
* the transaction at the top of the list must be undone first.
|
||||
*
|
||||
* @return the names of all undoable transactions in reverse chronological order
|
||||
*/
|
||||
abstract List<String> getAllUndoNames();
|
||||
|
||||
/**
|
||||
* Returns the names of all redoable transactions in chronological order. In other words
|
||||
* the transaction at the top of the list must be redone first.
|
||||
* Returns the names of all redoable transactions in chronological order. In other words the
|
||||
* transaction at the top of the list must be redone first.
|
||||
*
|
||||
* @return the names of all redoable transactions in chronological order
|
||||
*/
|
||||
abstract List<String> getAllRedoNames();
|
||||
@@ -321,7 +334,7 @@ abstract class AbstractTransactionManager {
|
||||
abstract void doClose(DomainObjectAdapterDB object);
|
||||
|
||||
/**
|
||||
* Set instance as immutable by disabling use of transactions. Attempts to start a transaction
|
||||
* Set instance as immutable by disabling use of transactions. Attempts to start a transaction
|
||||
* will result in a {@link TerminatedTransactionException}.
|
||||
*/
|
||||
public void setImmutable() {
|
||||
|
||||
@@ -133,7 +133,7 @@ public abstract class DomainObjectAdapterDB extends DomainObjectAdapter implemen
|
||||
* using a shared transaction manager. If either or both is already shared,
|
||||
* a transition to a single shared transaction manager will be
|
||||
* performed.
|
||||
* @param domainObj
|
||||
* @param domainObj the domain object to synchronize with
|
||||
* @throws LockException if lock or open transaction is active on either
|
||||
* this or the specified domain object
|
||||
*/
|
||||
@@ -184,7 +184,7 @@ public abstract class DomainObjectAdapterDB extends DomainObjectAdapter implemen
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the open handle to the underlying database.
|
||||
* {@return the open handle to the underlying database}
|
||||
*/
|
||||
public DBHandle getDBHandle() {
|
||||
return dbh;
|
||||
@@ -259,17 +259,17 @@ public abstract class DomainObjectAdapterDB extends DomainObjectAdapter implemen
|
||||
return transactionMgr.lock(reason);
|
||||
}
|
||||
|
||||
void prepareToSave() {
|
||||
int txId = transactionMgr.startTransaction(this, "Update Metadata", null, true, true);
|
||||
try {
|
||||
/**
|
||||
* Prepare to save and store any last minute DB data. The default behavior is to invoke
|
||||
* {@link #updateMetadata()}.
|
||||
*/
|
||||
protected void prepareToSave() {
|
||||
try (Transaction tx = openForcedTransaction("Update Metadata")) {
|
||||
updateMetadata();
|
||||
}
|
||||
catch (IOException e) {
|
||||
dbError(e);
|
||||
}
|
||||
finally {
|
||||
transactionMgr.endTransaction(this, txId, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,24 +310,40 @@ public abstract class DomainObjectAdapterDB extends DomainObjectAdapter implemen
|
||||
transactionMgr.unlock(handler);
|
||||
}
|
||||
|
||||
private class DomainObjectTransaction extends Transaction {
|
||||
private final int txId;
|
||||
|
||||
DomainObjectTransaction(int txId) {
|
||||
this.txId = txId;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean endTransaction(boolean commit) {
|
||||
DomainObjectAdapterDB.this.endTransaction(txId, commit);
|
||||
return commit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSubTransaction() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open forced transaction which bypasses any lock checking, although method should only be
|
||||
* used in very controlled situations where a save lock is in place.
|
||||
* @param description transaction description
|
||||
* @return {@link AutoCloseable} transaction object
|
||||
*/
|
||||
protected Transaction openForcedTransaction(String description) {
|
||||
int txId = transactionMgr.startTransaction(this, description, null, true, true);
|
||||
return new DomainObjectTransaction(txId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transaction openTransaction(String description)
|
||||
throws TerminatedTransactionException, IllegalStateException {
|
||||
return new Transaction() {
|
||||
|
||||
int txId = startTransaction(description);
|
||||
|
||||
@Override
|
||||
protected boolean endTransaction(boolean commit) {
|
||||
DomainObjectAdapterDB.this.endTransaction(txId, commit);
|
||||
return commit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSubTransaction() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
return new DomainObjectTransaction(startTransaction(description));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -348,7 +364,8 @@ public abstract class DomainObjectAdapterDB extends DomainObjectAdapter implemen
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
return transactionMgr.startTransaction(this, description, listener, true);
|
||||
return transactionMgr.startTransactionChecked(this, description, listener,
|
||||
true);
|
||||
}
|
||||
catch (DomainObjectLockedException e) {
|
||||
if (!exceptionHandler.apply(e)) {
|
||||
|
||||
@@ -103,11 +103,12 @@ class DomainObjectTransactionManager extends AbstractTransactionManager {
|
||||
throw new IllegalArgumentException("invalid domain object");
|
||||
}
|
||||
|
||||
if (!force) {
|
||||
verifyNoLock();
|
||||
}
|
||||
|
||||
if (transaction == null) {
|
||||
|
||||
if (!force) {
|
||||
verifyNoLock();
|
||||
}
|
||||
|
||||
transactionTerminated = false;
|
||||
transaction =
|
||||
new DomainObjectDBTransaction(domainObj.dbh.startTransaction(), domainObj);
|
||||
|
||||
@@ -1037,7 +1037,7 @@ class GhidraFolderData {
|
||||
if (doa.isClosed()) {
|
||||
throw new ClosedException();
|
||||
}
|
||||
if (!doa.lock(null)) {
|
||||
if (!doa.lock("create file")) {
|
||||
throw new IOException("Object is busy and can not be saved");
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -152,11 +152,12 @@ class SynchronizedTransactionManager extends AbstractTransactionManager {
|
||||
synchronized int startTransaction(DomainObjectAdapterDB object, String description,
|
||||
AbortedTransactionListener listener, boolean force, boolean notify) {
|
||||
|
||||
if (!force) {
|
||||
verifyNoLock();
|
||||
}
|
||||
|
||||
if (transaction == null) {
|
||||
|
||||
if (!force) {
|
||||
verifyNoLock();
|
||||
}
|
||||
|
||||
transactionTerminated = false;
|
||||
transaction = new SynchronizedTransaction(domainObjectTransactionManagers);
|
||||
int txId = transaction.addEntry(object, description, listener);
|
||||
|
||||
@@ -311,7 +311,7 @@ class FileActionManager {
|
||||
locked = false;
|
||||
break;
|
||||
}
|
||||
if (!domainObjects[lastIndex].lock(null)) {
|
||||
if (!domainObjects[lastIndex].lock("save changes")) {
|
||||
String title = "Exit Ghidra";
|
||||
StringBuffer buf = new StringBuffer();
|
||||
DomainObject d = domainObjects[lastIndex];
|
||||
|
||||
@@ -400,7 +400,7 @@ public interface DomainObject {
|
||||
* </pre>
|
||||
*
|
||||
* @param description a short description of the changes to be made.
|
||||
* @return transaction object
|
||||
* @return {@link AutoCloseable} transaction object
|
||||
* @throws IllegalStateException if this {@link DomainObject} has already been closed.
|
||||
*/
|
||||
public Transaction openTransaction(String description) throws IllegalStateException;
|
||||
|
||||
@@ -19,6 +19,7 @@ import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
import ghidra.program.disassemble.Disassembler;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.PointerDataType;
|
||||
@@ -28,6 +29,7 @@ import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* PseudoDisassembler.java
|
||||
@@ -71,7 +73,7 @@ public class PseudoDisassembler {
|
||||
|
||||
private boolean respectExecuteFlag = false;
|
||||
|
||||
private int lastCheckValidDisassemblyCount; // number of last instructions disassembled
|
||||
private int lastCheckValidDisassemblyCount; // number of last instructions disassembled in checkValidSubroutine
|
||||
|
||||
/**
|
||||
* Create a pseudo disassembler for the given program.
|
||||
@@ -98,8 +100,11 @@ public class PseudoDisassembler {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last number of disassembled instructions
|
||||
* or the number of initial contiguous instruction if requireContiguous is true
|
||||
* Get the last number of disassembled instructions,
|
||||
* or the number of initial contiguous instruction if requireContiguous is true,
|
||||
* after calls to in checkValidSubroutine() or isValidSubroutine()
|
||||
*
|
||||
* @return number of disassembled instructions
|
||||
*/
|
||||
public int getLastCheckValidInstructionCount() {
|
||||
return lastCheckValidDisassemblyCount;
|
||||
@@ -128,17 +133,15 @@ public class PseudoDisassembler {
|
||||
UnknownInstructionException, UnknownContextException {
|
||||
|
||||
PseudoDisassemblerContext procContext = new PseudoDisassemblerContext(programContext);
|
||||
|
||||
procContext.flowStart(addr);
|
||||
return disassemble(addr, procContext, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disassemble a single instruction. The program is not affected.
|
||||
* @param addr
|
||||
* @param disassemblerContext
|
||||
* @param isInDelaySlot
|
||||
* @return
|
||||
* @param addr location to disassemble
|
||||
* @param disassemblerContext context for disassembly
|
||||
* @param isInDelaySlot true if instruction to be disassembled is in a delaySlot
|
||||
* @return disassembled instruction
|
||||
* @throws InsufficientBytesException
|
||||
* @throws UnknownInstructionException
|
||||
* @throws UnknownContextException
|
||||
@@ -148,41 +151,18 @@ public class PseudoDisassembler {
|
||||
throws InsufficientBytesException, UnknownInstructionException,
|
||||
UnknownContextException {
|
||||
|
||||
MemBuffer memBuffer = new DumbMemBufferImpl(memory, addr);
|
||||
|
||||
// check that address is defined in memory
|
||||
try {
|
||||
memBuffer.getByte(0);
|
||||
}
|
||||
catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
InstructionPrototype prototype = null;
|
||||
addr = setTargetContextForDisassembly(disassemblerContext, addr);
|
||||
RegisterValue entryContext = getTargetStartContext(addr, disassemblerContext);
|
||||
|
||||
try {
|
||||
prototype = language.parse(memBuffer, disassemblerContext, isInDelaySlot);
|
||||
// Only disassemble one instruction, and always re-disassemble
|
||||
// in case context has changed.
|
||||
Instruction instr = pseudoDisassemble(addr, entryContext, 1, true);
|
||||
return (PseudoInstruction) instr;
|
||||
}
|
||||
catch (UnknownInstructionException unknownExc) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (prototype == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PseudoInstruction instr;
|
||||
try {
|
||||
instr = new PseudoInstruction(program, addr, prototype, memBuffer, disassemblerContext);
|
||||
}
|
||||
catch (Exception e) {
|
||||
// this is here, if a prototype matches for some number of bytes, but
|
||||
// the actual instruction is longer than the number of bytes needed for matching
|
||||
// the prototype. And all the bytes for the instruction are not available.
|
||||
return null;
|
||||
}
|
||||
|
||||
return instr;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -224,34 +204,21 @@ public class PseudoDisassembler {
|
||||
PseudoDisassemblerContext disassemblerContext) throws InsufficientBytesException,
|
||||
UnknownInstructionException, UnknownContextException {
|
||||
|
||||
addr = setTargetContextForDisassembly(disassemblerContext, addr);
|
||||
RegisterValue targetContext = getTargetStartContext(addr, disassemblerContext);
|
||||
|
||||
pseudoDisassembler = Disassembler.getDisassembler(program, false, false, false,
|
||||
TaskMonitor.DUMMY, msg -> {
|
||||
// ignore log errors
|
||||
});
|
||||
|
||||
MemBuffer memBuffer = new ByteMemBufferImpl(addr, bytes, language.isBigEndian());
|
||||
|
||||
// check that address is defined in memory
|
||||
try {
|
||||
memBuffer.getByte(0);
|
||||
}
|
||||
catch (Exception e) {
|
||||
InstructionBlock instrBlock = pseudoDisassembler.pseudoDisassembleBlock(memBuffer, targetContext, 1);
|
||||
if (instrBlock == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
InstructionPrototype prototype = null;
|
||||
disassemblerContext.flowStart(addr);
|
||||
prototype = language.parse(memBuffer, disassemblerContext, false);
|
||||
|
||||
if (prototype == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PseudoInstruction instr;
|
||||
try {
|
||||
instr = new PseudoInstruction(program, addr, prototype, memBuffer, disassemblerContext);
|
||||
}
|
||||
catch (AddressOverflowException e) {
|
||||
throw new InsufficientBytesException(
|
||||
"failed to build pseudo instruction at " + addr + ": " + e.getMessage());
|
||||
}
|
||||
|
||||
return instr;
|
||||
return (PseudoInstruction) instrBlock.getInstructionAt(addr);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -265,9 +232,7 @@ public class PseudoDisassembler {
|
||||
* @return {@link PseudoData} that acts like Data
|
||||
*/
|
||||
public PseudoData applyDataType(Address addr, DataType dt) {
|
||||
|
||||
Memory memory = program.getMemory();
|
||||
|
||||
|
||||
MemBuffer memBuffer = new DumbMemBufferImpl(memory, addr);
|
||||
|
||||
// check that address is defined in memory
|
||||
@@ -424,9 +389,10 @@ public class PseudoDisassembler {
|
||||
AddressSet body = new AddressSet();
|
||||
AddressSet instrStarts = new AddressSet();
|
||||
|
||||
entryPoint = setTargetContextForDisassembly(procContext, entryPoint);
|
||||
|
||||
Address target = entryPoint;
|
||||
|
||||
entryPoint = setTargetContextForDisassembly(procContext, entryPoint);
|
||||
RegisterValue entryContext = getTargetStartContext(entryPoint, procContext);
|
||||
|
||||
ArrayList<Address> targetList = new ArrayList<>(); // list of valid targets
|
||||
ArrayList<Address> untriedTargetList = new ArrayList<>(); // list of valid targets
|
||||
@@ -458,17 +424,15 @@ public class PseudoDisassembler {
|
||||
return body;
|
||||
}
|
||||
|
||||
procContext.flowStart(entryPoint);
|
||||
|
||||
try {
|
||||
// look some number of fallthroughs to see if this
|
||||
// is a valid run of instructions.
|
||||
|
||||
for (int i = 0; target != null && i < maxInstr; i++) {
|
||||
PseudoInstruction instr;
|
||||
instr = disassemble(target, procContext, false);
|
||||
Instruction instr;
|
||||
instr = pseudoDisassemble(target, entryContext, maxInstructions, false);
|
||||
|
||||
boolean doContinue = processor.process(instr);
|
||||
boolean doContinue = processor.process((PseudoInstruction)instr);
|
||||
if (!doContinue) {
|
||||
return body;
|
||||
}
|
||||
@@ -482,7 +446,7 @@ public class PseudoDisassembler {
|
||||
instrStarts.addRange(instr.getMinAddress(), instr.getMinAddress());
|
||||
|
||||
// check whether processor wants to follow flow on this instruction
|
||||
if (!processor.followFlows(instr)) {
|
||||
if (!processor.followFlows((PseudoInstruction) instr)) {
|
||||
target = getNextTarget(body, untriedTargetList);
|
||||
continue;
|
||||
}
|
||||
@@ -530,13 +494,8 @@ public class PseudoDisassembler {
|
||||
target = newTarget;
|
||||
}
|
||||
}
|
||||
catch (InsufficientBytesException e) {
|
||||
processor.process(null);
|
||||
}
|
||||
catch (UnknownInstructionException e) {
|
||||
processor.process(null);
|
||||
}
|
||||
catch (UnknownContextException e) {
|
||||
// bad instruction
|
||||
processor.process(null);
|
||||
}
|
||||
|
||||
@@ -662,6 +621,7 @@ public class PseudoDisassembler {
|
||||
AddressSetView execSet = memory.getExecuteSet();
|
||||
|
||||
entryPoint = setTargetContextForDisassembly(procContext, entryPoint);
|
||||
RegisterValue entryContext = getTargetStartContext(entryPoint, procContext);
|
||||
|
||||
Address target = entryPoint;
|
||||
|
||||
@@ -683,24 +643,12 @@ public class PseudoDisassembler {
|
||||
return false;
|
||||
}
|
||||
|
||||
RepeatInstructionByteTracker repeatInstructionByteTracker =
|
||||
new RepeatInstructionByteTracker(MAX_REPEAT_BYTES_LIMIT, null);
|
||||
|
||||
procContext.flowStart(entryPoint);
|
||||
try {
|
||||
// look some number of fallthroughs to see if this
|
||||
// is a valid run of instructions.
|
||||
|
||||
for (int i = 0; target != null && i < maxInstructions; i++) {
|
||||
if (target.compareTo(procContext.getAddress()) < 0) {
|
||||
procContext.copyToFutureFlowState(target);
|
||||
procContext.flowEnd(procContext.getAddress());
|
||||
procContext.flowStart(target);
|
||||
}
|
||||
else {
|
||||
procContext.flowToAddress(target);
|
||||
}
|
||||
PseudoInstruction instr = disassemble(target, procContext, false);
|
||||
Instruction instr = pseudoDisassemble(target, entryContext, maxInstructions, false);
|
||||
|
||||
if (instr == null) {
|
||||
// if the target is in the external section, which is uninitialized, ignore it!
|
||||
@@ -712,7 +660,6 @@ public class PseudoDisassembler {
|
||||
}
|
||||
targetList.remove(target);
|
||||
target = getNextTarget(body, untriedTargetList);
|
||||
repeatInstructionByteTracker.reset();
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -723,7 +670,7 @@ public class PseudoDisassembler {
|
||||
}
|
||||
|
||||
// check if we are getting into bad instruction runs
|
||||
if (repeatInstructionByteTracker.exceedsRepeatBytePattern(instr)) {
|
||||
if (lastPseudoInstructionBlock.getInstructionConflict() != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -743,8 +690,7 @@ public class PseudoDisassembler {
|
||||
catch (AddressOverflowException e) {
|
||||
return false;
|
||||
}
|
||||
procContext.flowToAddress(addr);
|
||||
PseudoInstruction dsInstr = disassemble(addr, procContext, true);
|
||||
Instruction dsInstr = pseudoDisassemble(addr, entryContext, maxInstructions, false);
|
||||
if (dsInstr == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -762,9 +708,8 @@ public class PseudoDisassembler {
|
||||
// if instruction has fall thru
|
||||
Address fallThru = null;
|
||||
if (instr.hasFallthrough()) {
|
||||
if (checkNonReturning(program, flowType, instr)) {
|
||||
if (checkNonReturning(flowType, instr)) {
|
||||
target = getNextTarget(body, untriedTargetList);
|
||||
repeatInstructionByteTracker.reset();
|
||||
continue;
|
||||
}
|
||||
newTarget = instr.getFallThrough();
|
||||
@@ -793,7 +738,6 @@ public class PseudoDisassembler {
|
||||
|
||||
if (newTarget == null) {
|
||||
newTarget = getNextTarget(body, untriedTargetList);
|
||||
repeatInstructionByteTracker.reset();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -817,7 +761,6 @@ public class PseudoDisassembler {
|
||||
if (func != null) {
|
||||
didCallValidSubroutine = true;
|
||||
newTarget = getNextTarget(body, untriedTargetList);
|
||||
repeatInstructionByteTracker.reset();
|
||||
continue;
|
||||
}
|
||||
targetList.add(address);
|
||||
@@ -865,18 +808,10 @@ public class PseudoDisassembler {
|
||||
target = newTarget;
|
||||
}
|
||||
}
|
||||
catch (InsufficientBytesException e) {
|
||||
// can't parse not enough bytes
|
||||
return false;
|
||||
}
|
||||
catch (UnknownInstructionException e) {
|
||||
// bad instruction
|
||||
return false;
|
||||
}
|
||||
catch (UnknownContextException e) {
|
||||
// something wrong with context
|
||||
return false;
|
||||
}
|
||||
|
||||
// get rid of anything on target list that is in body of instruction
|
||||
Iterator<Address> iter = targetList.iterator();
|
||||
@@ -905,8 +840,71 @@ public class PseudoDisassembler {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private InstructionBlock lastPseudoInstructionBlock;
|
||||
private Disassembler pseudoDisassembler;
|
||||
|
||||
/**
|
||||
* Disassemble a block of instructions
|
||||
*
|
||||
* @param addr location to disassemble
|
||||
* @param entryContext context at the start of the block
|
||||
* @param maxInstr maximum number of instructions to disassemble
|
||||
* @param forceRedisassembly force re-disassembly (don't use cached block)
|
||||
*
|
||||
* @return the instruction (PseudoInstruction)
|
||||
* @throws UnknownInstructionException if instruction at location not disassemblable
|
||||
*/
|
||||
|
||||
private boolean checkNonReturning(Program program, FlowType flowType, PseudoInstruction instr) {
|
||||
private Instruction pseudoDisassemble(Address addr, RegisterValue entryContext, int maxInstr, boolean forceRedisassembly) throws UnknownInstructionException {
|
||||
Instruction instr;
|
||||
if (!forceRedisassembly && lastPseudoInstructionBlock != null) {
|
||||
instr = lastPseudoInstructionBlock.getInstructionAt(addr);
|
||||
if (instr != null) {
|
||||
return instr;
|
||||
}
|
||||
InstructionError error = lastPseudoInstructionBlock.getInstructionConflict();
|
||||
if (error != null && addr.equals(error.getInstructionAddress())) {
|
||||
throw new UnknownInstructionException(error.getConflictMessage());
|
||||
}
|
||||
lastPseudoInstructionBlock = null;
|
||||
}
|
||||
|
||||
if (pseudoDisassembler == null) {
|
||||
pseudoDisassembler = Disassembler.getDisassembler(program, false, false, false,
|
||||
TaskMonitor.DUMMY, msg -> {
|
||||
// ignore log errors
|
||||
});
|
||||
pseudoDisassembler.setRepeatPatternLimit(MAX_REPEAT_BYTES_LIMIT);
|
||||
} else if (forceRedisassembly) {
|
||||
pseudoDisassembler.resetDisassemblerContext();
|
||||
}
|
||||
|
||||
lastPseudoInstructionBlock =
|
||||
pseudoDisassembler.pseudoDisassembleBlock(addr, entryContext, maxInstr);
|
||||
if (lastPseudoInstructionBlock != null) {
|
||||
InstructionError error = lastPseudoInstructionBlock.getInstructionConflict(); // Look for zero-byte run first
|
||||
if (error != null &&
|
||||
error.getConflictMessage().startsWith("Maximum run of Zero-Byte")) {
|
||||
throw new UnknownInstructionException(error.getConflictMessage()); // Don't return any of the zero-byte instructions
|
||||
}
|
||||
instr = lastPseudoInstructionBlock.getInstructionAt(addr);
|
||||
if (instr != null) {
|
||||
return instr;
|
||||
}
|
||||
if (error != null && addr.equals(error.getInstructionAddress())) {
|
||||
throw new UnknownInstructionException(error.getConflictMessage());
|
||||
}
|
||||
if (program.getMemory().isExternalBlockAddress(addr)) {
|
||||
throw new UnknownInstructionException(
|
||||
"Unable to disassemble EXTERNAL block location: " + addr);
|
||||
}
|
||||
}
|
||||
throw new UnknownInstructionException("Invalid instruction address (improperly aligned)");
|
||||
}
|
||||
|
||||
private boolean checkNonReturning(FlowType flowType, Instruction instr) {
|
||||
if (!flowType.isCall()) {
|
||||
return false;
|
||||
}
|
||||
@@ -1059,6 +1057,25 @@ public class PseudoDisassembler {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the context register setup with the starting context for target
|
||||
*
|
||||
* @param target address to get context register value
|
||||
* @param procContext disassembly context
|
||||
* @return context register value set with current context for target
|
||||
*/
|
||||
private RegisterValue getTargetStartContext(Address target,
|
||||
PseudoDisassemblerContext procContext) {
|
||||
procContext.flowStart(target);
|
||||
|
||||
RegisterValue entryContext = null;
|
||||
Register baseContextRegister = procContext.getBaseContextRegister();
|
||||
if (baseContextRegister != null) {
|
||||
entryContext = procContext.getRegisterValue(baseContextRegister);
|
||||
}
|
||||
return entryContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if program has uses the low bit of an address to change Instruction Set mode
|
||||
|
||||
@@ -71,27 +71,21 @@ public class BookmarkDBAdapterV3 extends BookmarkDBAdapter {
|
||||
throw new VersionException(true);
|
||||
}
|
||||
else if (typeIDs.length != 0) {
|
||||
int version = -1;
|
||||
for (int i = 0; i < typeIDs.length; i++) {
|
||||
int id = typeIDs[i];
|
||||
tables[id] = handle.getTable(BOOKMARK_TABLE_NAME + id);
|
||||
}
|
||||
boolean noTables = (tables[typeIDs[0]] == null);
|
||||
int version = noTables ? -1 : tables[typeIDs[0]].getSchema().getVersion();
|
||||
for (int i = 1; i < typeIDs.length; i++) {
|
||||
int id = typeIDs[i];
|
||||
if (noTables) {
|
||||
if (tables[id] != null) {
|
||||
throw new IOException("Missing bookmark table");
|
||||
String tableName = BOOKMARK_TABLE_NAME + id;
|
||||
Table table = handle.getTable(tableName);
|
||||
if (table != null) {
|
||||
int schemaVersion = table.getSchema().getVersion();
|
||||
if (version >= 0 && schemaVersion != version) {
|
||||
throw new IOException("Inconsistent bookmark table versions");
|
||||
}
|
||||
version = schemaVersion;
|
||||
}
|
||||
else if (tables[id].getSchema().getVersion() != version) {
|
||||
throw new IOException("Inconsistent bookmark table versions");
|
||||
}
|
||||
tables[id] = table;
|
||||
}
|
||||
if (noTables) {
|
||||
throw new VersionException(true);
|
||||
}
|
||||
else if (version != VERSION) {
|
||||
if (version >= 0 && version != VERSION) {
|
||||
throw new VersionException(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ public class BookmarkDBManager implements BookmarkManager, ErrorHandler, Manager
|
||||
int typeId = (int) rec.getKey();
|
||||
BookmarkTypeDB type =
|
||||
new BookmarkTypeDB(typeId, rec.getString(BookmarkTypeDBAdapter.TYPE_NAME_COL));
|
||||
type.setHasBookmarks(true);
|
||||
type.setHasBookmarks(bookmarkAdapter.hasTable(typeId));
|
||||
typesByName.put(type.getTypeString(), type);
|
||||
typesArray.put(typeId, type);
|
||||
}
|
||||
@@ -208,9 +208,11 @@ public class BookmarkDBManager implements BookmarkManager, ErrorHandler, Manager
|
||||
typesArray.put(typeId, bmt);
|
||||
}
|
||||
if (create && !bmt.hasBookmarks()) {
|
||||
|
||||
// Ensure that both type record and bookmarks table exists
|
||||
bookmarkTypeAdapter.addType(bmt.getTypeId(), bmt.getTypeString());
|
||||
bmt.setHasBookmarks(true);
|
||||
bookmarkAdapter.addType(bmt.getTypeId());
|
||||
bmt.setHasBookmarks(true);
|
||||
|
||||
// fire event
|
||||
program.setObjChanged(ProgramEvent.BOOKMARK_TYPE_ADDED, bmt, null, null);
|
||||
|
||||
@@ -2841,7 +2841,7 @@ is size.ldstr=3 & b_2429=0x8 & b_23=1 & L=1 & b_21=0 & b_15=1 & addrReg & Rt_GPR
|
||||
:ldar Rt_GPR32, addrReg
|
||||
is size.ldstr=2 & b_2429=0x8 & b_23=1 & L=1 & b_21=0 & b_1620=0b11111 & b_15=1 & b_1014=0b11111 & addrReg & Rt_GPR32 & Rt_GPR64
|
||||
{
|
||||
Rt_GPR64 = *addrReg;
|
||||
Rt_GPR64 = zext(*:4 addrReg);
|
||||
}
|
||||
|
||||
# C6.2.146 LDARB page C6-1516 line 89986 MATCH x08c08000/mask=xffe08000
|
||||
@@ -3049,7 +3049,7 @@ is b_3031=0b10 & b_2529=0b10100 & (b_24=1 | b_23=1) & b_22=1 & Rt2_GPR64 & addrP
|
||||
is b_2531=0b0110100 & (b_24=1 | b_23=1) & b_22=1 & Rt2_GPR64 & addrPairIndexed & Rt_GPR64
|
||||
{
|
||||
local addrval1:8 = sext(*:4 addrPairIndexed);
|
||||
local addrval2:8 = sext(*:4 (addrPairIndexed + 8));
|
||||
local addrval2:8 = sext(*:4 (addrPairIndexed + 4));
|
||||
Rt_GPR64 = addrval1;
|
||||
Rt2_GPR64 = addrval2;
|
||||
}
|
||||
@@ -8366,4 +8366,211 @@ is b_1231=0b11010101000000000100 & b_0007=0b00111111
|
||||
OV = tmpOV;
|
||||
}
|
||||
|
||||
# FEAT_CSSC
|
||||
:abs Rd_GPR32, Rn_GPR32
|
||||
is sf=0 & b_30=1 & S=0 & b_2428=0x1a & b_2123=0x6 & b_1620=0x0 & b_1015=0x8 & Rd_GPR32 & Rn_GPR32
|
||||
{
|
||||
local tmp = Rn_GPR32;
|
||||
local test = tmp s< 0;
|
||||
Rd_GPR32 = (zext(!test)*tmp) + (zext(test)*(-tmp));
|
||||
}
|
||||
|
||||
:abs Rd_GPR64, Rn_GPR64
|
||||
is sf=1 & b_30=1 & S=0 & b_2428=0x1a & b_2123=0x6 & b_1620=0x0 & b_1015=0x8 & Rd_GPR64 & Rn_GPR64
|
||||
{
|
||||
local tmp = Rn_GPR64;
|
||||
local test = tmp s< 0;
|
||||
Rd_GPR64 = (zext(!test)*tmp) + (zext(test)*(-tmp));
|
||||
}
|
||||
|
||||
:cnt Rd_GPR32, Rn_GPR32
|
||||
is sf=0 & b_30=1 & S=0 & b_2428=0x1a & b_2123=0x6 & b_1620=0x0 & b_1015=0x7 & Rd_GPR32 & Rn_GPR32
|
||||
{
|
||||
local tmp = Rn_GPR32;
|
||||
Rd_GPR32 = popcount(tmp);
|
||||
}
|
||||
|
||||
:cnt Rd_GPR64, Rn_GPR64
|
||||
is sf=1 & b_30=1 & S=0 & b_2428=0x1a & b_2123=0x6 & b_1620=0x0 & b_1015=0x7 & Rd_GPR64 & Rn_GPR64
|
||||
{
|
||||
local tmp = Rn_GPR64;
|
||||
Rd_GPR64 = popcount(tmp);
|
||||
}
|
||||
|
||||
:ctz Rd_GPR32, Rn_GPR32
|
||||
is sf=0 & b_3030=1 & S=0 & b_2428=0x1a & b_2123=6 & dp1.opcode2=0x0 & b_1015=0x6 & Rn_GPR32 & Rd_GPR32 & Rd_GPR64
|
||||
{
|
||||
# equivalent to RBIT; CLZ
|
||||
local tmp = Rn_GPR32;
|
||||
tmp = (((tmp & 0xaaaaaaaa) >> 1) | ((tmp & 0x55555555) << 1));
|
||||
tmp = (((tmp & 0xcccccccc) >> 2) | ((tmp & 0x33333333) << 2));
|
||||
tmp = (((tmp & 0xf0f0f0f0) >> 4) | ((tmp & 0x0f0f0f0f) << 4));
|
||||
tmp = (((tmp & 0xff00ff00) >> 8) | ((tmp & 0x00ff00ff) << 8));
|
||||
tmp = ((tmp >> 16) | (tmp << 16));
|
||||
Rd_GPR64 = lzcount(tmp);
|
||||
}
|
||||
|
||||
:ctz Rd_GPR64, Rn_GPR64
|
||||
is sf=1 & b_3030=1 & S=0 & b_2428=0x1a & b_2123=6 & dp1.opcode2=0x0 & b_1015=0x6 & Rn_GPR64 & Rd_GPR64
|
||||
{
|
||||
# equivalent to RBIT; CLZ
|
||||
local tmp = Rn_GPR64;
|
||||
tmp = (((tmp & 0xaaaaaaaaaaaaaaaa) >> 1) | ((tmp & 0x5555555555555555) << 1));
|
||||
tmp = (((tmp & 0xcccccccccccccccc) >> 2) | ((tmp & 0x3333333333333333) << 2));
|
||||
tmp = (((tmp & 0xf0f0f0f0f0f0f0f0) >> 4) | ((tmp & 0x0f0f0f0f0f0f0f0f) << 4));
|
||||
tmp = (((tmp & 0xff00ff00ff00ff00) >> 8) | ((tmp & 0x00ff00ff00ff00ff) << 8));
|
||||
tmp = (((tmp & 0xffff0000ffff0000) >> 16) | ((tmp & 0x0000ffff0000ffff) << 16));
|
||||
tmp = ((tmp >> 32) | (tmp << 32));
|
||||
Rd_GPR64 = lzcount(tmp);
|
||||
}
|
||||
|
||||
cssc_simm32: "#"^val is simm8 [ val = simm8 * 1; ] { export *[const]:4 val; }
|
||||
cssc_simm64: "#"^val is simm8 [ val = simm8 * 1; ] { export *[const]:8 val; }
|
||||
|
||||
cssc_imm32: "#"^val is imm8 [ val = imm8 * 1; ] { export *[const]:4 val; }
|
||||
cssc_imm64: "#"^val is imm8 [ val = imm8 * 1; ] { export *[const]:8 val; }
|
||||
|
||||
|
||||
:smax Rd_GPR32, Rn_GPR32, cssc_simm32
|
||||
is sf=0 & b_30=0 & S=0 & b_2428=0x11 & b_2123=0x6 & b_1820=0x0 & Rd_GPR32 & Rn_GPR32 & cssc_simm32
|
||||
{
|
||||
local tmp = Rn_GPR32;
|
||||
local tmp2 = cssc_simm32;
|
||||
local test:1 = tmp s>= tmp2;
|
||||
Rd_GPR32 = (zext(test)*tmp) + (zext(!test)*(tmp2));
|
||||
}
|
||||
|
||||
:smax Rd_GPR64, Rn_GPR64, cssc_simm64
|
||||
is sf=1 & b_30=0 & S=0 & b_2428=0x11 & b_2123=0x6 & b_1820=0x0 & Rd_GPR64 & Rn_GPR64 & cssc_simm64
|
||||
{
|
||||
local tmp = Rn_GPR64;
|
||||
local tmp2 = cssc_simm64;
|
||||
local test = tmp s>= tmp2;
|
||||
Rd_GPR64 = (zext(test)*tmp) + (zext(!test)*(tmp2));
|
||||
}
|
||||
|
||||
:smax Rd_GPR32, Rn_GPR32, Rm_GPR32
|
||||
is sf=0 & b_30=0 & S=0 & b_2428=0x1a & b_2123=0x6 & b_1015=0x18 & Rd_GPR32 & Rn_GPR32 & Rm_GPR32
|
||||
{
|
||||
local tmp = Rn_GPR32;
|
||||
local tmp2 = Rm_GPR32;
|
||||
local test = tmp s>= tmp2;
|
||||
Rd_GPR32 = (zext(test)*tmp) + (zext(!test)*(tmp2));
|
||||
}
|
||||
|
||||
:smax Rd_GPR64, Rn_GPR64, Rm_GPR64
|
||||
is sf=1 & b_30=0 & S=0 & b_2428=0x1a & b_2123=0x6 & b_1015=0x18 & Rd_GPR64 & Rn_GPR64 & Rm_GPR64
|
||||
{
|
||||
local tmp = Rn_GPR64;
|
||||
local tmp2 = Rm_GPR64;
|
||||
local test = tmp s>= tmp2;
|
||||
Rd_GPR64 = (zext(test)*tmp) + (zext(!test)*(tmp2));
|
||||
}
|
||||
|
||||
:smin Rd_GPR32, Rn_GPR32, cssc_simm32
|
||||
is sf=0 & b_30=0 & S=0 & b_2428=0x11 & b_2123=0x6 & b_1820=0x2 & Rd_GPR32 & Rn_GPR32 & cssc_simm32
|
||||
{
|
||||
local tmp = Rn_GPR32;
|
||||
local tmp2 = cssc_simm32;
|
||||
local test:1 = tmp s<= tmp2;
|
||||
Rd_GPR32 = (zext(test)*tmp) + (zext(!test)*(tmp2));
|
||||
}
|
||||
|
||||
:smin Rd_GPR64, Rn_GPR64, cssc_simm64
|
||||
is sf=1 & b_30=0 & S=0 & b_2428=0x11 & b_2123=0x6 & b_1820=0x2 & Rd_GPR64 & Rn_GPR64 & cssc_simm64
|
||||
{
|
||||
local tmp = Rn_GPR64;
|
||||
local tmp2 = cssc_simm64;
|
||||
local test = tmp s<= tmp2;
|
||||
Rd_GPR64 = (zext(test)*tmp) + (zext(!test)*(tmp2));
|
||||
}
|
||||
|
||||
:smin Rd_GPR32, Rn_GPR32, Rm_GPR32
|
||||
is sf=0 & b_30=0 & S=0 & b_2428=0x1a & b_2123=0x6 & b_1015=0x1a & Rd_GPR32 & Rn_GPR32 & Rm_GPR32
|
||||
{
|
||||
local tmp = Rn_GPR32;
|
||||
local tmp2 = Rm_GPR32;
|
||||
local test = tmp s<= tmp2;
|
||||
Rd_GPR32 = (zext(test)*tmp) + (zext(!test)*(tmp2));
|
||||
}
|
||||
|
||||
:smin Rd_GPR64, Rn_GPR64, Rm_GPR64
|
||||
is sf=1 & b_30=0 & S=0 & b_2428=0x1a & b_2123=0x6 & b_1015=0x1a & Rd_GPR64 & Rn_GPR64 & Rm_GPR64
|
||||
{
|
||||
local tmp = Rn_GPR64;
|
||||
local tmp2 = Rm_GPR64;
|
||||
local test = tmp s<= tmp2;
|
||||
Rd_GPR64 = (zext(test)*tmp) + (zext(!test)*(tmp2));
|
||||
}
|
||||
|
||||
:umax Rd_GPR32, Rn_GPR32, cssc_imm32
|
||||
is sf=0 & b_30=0 & S=0 & b_2428=0x11 & b_2123=0x6 & b_1820=0x1 & Rd_GPR32 & Rn_GPR32 & cssc_imm32
|
||||
{
|
||||
local tmp = Rn_GPR32;
|
||||
local tmp2 = cssc_imm32;
|
||||
local test:1 = tmp >= tmp2;
|
||||
Rd_GPR32 = (zext(test)*tmp) + (zext(!test)*(tmp2));
|
||||
}
|
||||
|
||||
:umax Rd_GPR64, Rn_GPR64, cssc_imm64
|
||||
is sf=1 & b_30=0 & S=0 & b_2428=0x11 & b_2123=0x6 & b_1820=0x1 & Rd_GPR64 & Rn_GPR64 & cssc_imm64
|
||||
{
|
||||
local tmp = Rn_GPR64;
|
||||
local tmp2 = cssc_imm64;
|
||||
local test = tmp >= tmp2;
|
||||
Rd_GPR64 = (zext(test)*tmp) + (zext(!test)*(tmp2));
|
||||
}
|
||||
|
||||
:umax Rd_GPR32, Rn_GPR32, Rm_GPR32
|
||||
is sf=0 & b_30=0 & S=0 & b_2428=0x1a & b_2123=0x6 & b_1015=0x19 & Rd_GPR32 & Rn_GPR32 & Rm_GPR32
|
||||
{
|
||||
local tmp = Rn_GPR32;
|
||||
local tmp2 = Rm_GPR32;
|
||||
local test = tmp >= tmp2;
|
||||
Rd_GPR32 = (zext(test)*tmp) + (zext(!test)*(tmp2));
|
||||
}
|
||||
|
||||
:umax Rd_GPR64, Rn_GPR64, Rm_GPR64
|
||||
is sf=1 & b_30=0 & S=0 & b_2428=0x1a & b_2123=0x6 & b_1015=0x19 & Rd_GPR64 & Rn_GPR64 & Rm_GPR64
|
||||
{
|
||||
local tmp = Rn_GPR64;
|
||||
local tmp2 = Rm_GPR64;
|
||||
local test = tmp >= tmp2;
|
||||
Rd_GPR64 = (zext(test)*tmp) + (zext(!test)*(tmp2));
|
||||
}
|
||||
|
||||
:umin Rd_GPR32, Rn_GPR32, cssc_imm32
|
||||
is sf=0 & b_30=0 & S=0 & b_2428=0x11 & b_2123=0x6 & b_1820=0x3 & Rd_GPR32 & Rn_GPR32 & cssc_imm32
|
||||
{
|
||||
local tmp = Rn_GPR32;
|
||||
local tmp2 = cssc_imm32;
|
||||
local test:1 = tmp <= tmp2;
|
||||
Rd_GPR32 = (zext(test)*tmp) + (zext(!test)*(tmp2));
|
||||
}
|
||||
|
||||
:umin Rd_GPR64, Rn_GPR64, cssc_imm64
|
||||
is sf=1 & b_30=0 & S=0 & b_2428=0x11 & b_2123=0x6 & b_1820=0x3 & Rd_GPR64 & Rn_GPR64 & cssc_imm64
|
||||
{
|
||||
local tmp = Rn_GPR64;
|
||||
local tmp2 = cssc_imm64;
|
||||
local test = tmp <= tmp2;
|
||||
Rd_GPR64 = (zext(test)*tmp) + (zext(!test)*(tmp2));
|
||||
}
|
||||
|
||||
:umin Rd_GPR32, Rn_GPR32, Rm_GPR32
|
||||
is sf=0 & b_30=0 & S=0 & b_2428=0x1a & b_2123=0x6 & b_1015=0x1b & Rd_GPR32 & Rn_GPR32 & Rm_GPR32
|
||||
{
|
||||
local tmp = Rn_GPR32;
|
||||
local tmp2 = Rm_GPR32;
|
||||
local test = tmp <= tmp2;
|
||||
Rd_GPR32 = (zext(test)*tmp) + (zext(!test)*(tmp2));
|
||||
}
|
||||
|
||||
:umin Rd_GPR64, Rn_GPR64, Rm_GPR64
|
||||
is sf=1 & b_30=0 & S=0 & b_2428=0x1a & b_2123=0x6 & b_1015=0x1b & Rd_GPR64 & Rn_GPR64 & Rm_GPR64
|
||||
{
|
||||
local tmp = Rn_GPR64;
|
||||
local tmp2 = Rm_GPR64;
|
||||
local test = tmp <= tmp2;
|
||||
Rd_GPR64 = (zext(test)*tmp) + (zext(!test)*(tmp2));
|
||||
}
|
||||
|
||||
@@ -1131,10 +1131,12 @@ define token instrAARCH64 (32) endian = little
|
||||
|
||||
imm6 = (10,15)
|
||||
aa_imm7 = (15,21)
|
||||
imm8 = (10,17)
|
||||
imm12 = (10,21)
|
||||
imm16 = (5,20)
|
||||
|
||||
simm7 = (15,21) signed
|
||||
simm8 = (10,17) signed
|
||||
simm9 = (12,20) signed
|
||||
simm14 = (5,18) signed
|
||||
simm19 = (5,23) signed
|
||||
|
||||
@@ -1240,20 +1240,14 @@ macro do_lshb(count, dest) {
|
||||
*:2 tmp = val | mask; # clear bit, store
|
||||
}
|
||||
|
||||
# TBIT - test bit
|
||||
# TBIT - test bit in register
|
||||
:TBIT imm4a, src1 is hi=0x06 & imm4a & src1 {
|
||||
tmp:4 = zext(src1);
|
||||
val:2 = *:2 tmp; # load dst operand
|
||||
mask:2 = 1 << imm4a;
|
||||
bit:2 = (val & mask) >> imm4a;
|
||||
$(F) = bit:1; # save bit
|
||||
$(F) = (src1 & mask) != 0;
|
||||
}
|
||||
:TBIT src, src1 is hi=0x07 & src & src1 {
|
||||
tmp:4 = zext(src1);
|
||||
val:2 = *:2 tmp; # load dst operand
|
||||
mask:2 = 1 << src;
|
||||
bit:2 = (val & mask) >> src;
|
||||
$(F) = bit:1; # save bit
|
||||
$(F) = (src1 & mask) != 0;
|
||||
}
|
||||
|
||||
# TBITB - test bit in low-order byte
|
||||
|
||||
@@ -502,6 +502,10 @@ define token instr(32)
|
||||
prime = (26,31)
|
||||
bit25 = (25,25)
|
||||
zero2425 = (24,25)
|
||||
svrs_xreg = (23,25)
|
||||
svrs_xregb0 = (23,23)
|
||||
svrs_xregb1 = (24,24)
|
||||
svrs_xregb2 = (25,25)
|
||||
zero2325 = (23,25)
|
||||
zero1 = (22,25)
|
||||
rs32 = (21,25)
|
||||
@@ -530,6 +534,7 @@ define token instr(32)
|
||||
off21 = (0,20) signed # 21 bit signed offset in conditional branch/link
|
||||
off16 = (0,15) signed # 16 bit signed offset in conditional branch/link
|
||||
bit21 = (21,21)
|
||||
svrs_frame_hi = (19,22)
|
||||
bitz19 = (19,20)
|
||||
pcrel = (19,20)
|
||||
pcrel2 = (18,20)
|
||||
@@ -557,8 +562,16 @@ define token instr(32)
|
||||
lohiacx = (16,19)
|
||||
nd = (17,17)
|
||||
tf = (16,16)
|
||||
svrs_aregb3 = (18,18)
|
||||
svrs_aregb2 = (17,17)
|
||||
svrs_aregb1 = (16,16)
|
||||
svrs_aregb0 = (15,15)
|
||||
svrs_areg = (15,18)
|
||||
|
||||
zero1320 = (13,20)
|
||||
zero1315 = (13,15)
|
||||
save = (13,13)
|
||||
svrs_ra = (12,12)
|
||||
szero = (11,25)
|
||||
mask = (11,20)
|
||||
baser6 = (11,15)
|
||||
@@ -600,7 +613,9 @@ define token instr(32)
|
||||
ac = (11,12)
|
||||
bp = (11,12)
|
||||
bit10 = (10,10)
|
||||
svrs_s0 = (10,10)
|
||||
spec2 = (9,10)
|
||||
svrs_s1 = (9,9)
|
||||
spec3 = (8,10)
|
||||
simmed9 = (7,15)
|
||||
zero2 = (7,10)
|
||||
@@ -613,7 +628,7 @@ define token instr(32)
|
||||
fct2 = (6,10)
|
||||
zero5 = (6,10)
|
||||
wsbh = (6,10)
|
||||
|
||||
svrs_frame_low = (6,9)
|
||||
bp3 = (6,8)
|
||||
sel_0608 = (6,8)
|
||||
sa2 = (6,7)
|
||||
|
||||
@@ -12,6 +12,14 @@
|
||||
|
||||
define token m16instr (16)
|
||||
m16_op=(11,15)
|
||||
m16_rd0_0 = (11,15)
|
||||
m16_rd0_1 = (11,15)
|
||||
m16_rd0_2 = (11,15)
|
||||
m16_rd0_3 = (11,15)
|
||||
m16_rd0_4 = (11,15)
|
||||
m16_rd0_5 = (11,15)
|
||||
m16_rd0_6 = (11,15)
|
||||
m16_rd0_7 = (11,15)
|
||||
m16_i_imm=(0,4)
|
||||
m16_rx=(8,10)
|
||||
m16_rxa=(8,10)
|
||||
@@ -74,6 +82,95 @@ attach variables [ ext_m16r32 m16_i8_r32 ] [
|
||||
t8 t9 k0 k1 gp sp s8 ra
|
||||
];
|
||||
|
||||
|
||||
attach variables [ m16_rd0_0 ] [
|
||||
Index Random EntryLo0 EntryLo1
|
||||
Context PageMask Wired HWREna
|
||||
BadVAddr Count EntryHi Compare
|
||||
Status Cause EPC PRId
|
||||
Config LLAddr WatchLo WatchHi
|
||||
XContext cop0_reg21 cop0_reg22 Debug
|
||||
DEPC PerfCnt ErrCtl CacheErr
|
||||
TagLo TagHi ErrorEPC DESAVE
|
||||
];
|
||||
|
||||
attach variables [ m16_rd0_1 ] [
|
||||
MVPControl VPEControl TCStatus cop0_reg3.1
|
||||
ContextConfig PageGrain SRSConf0 cop0_reg7.1
|
||||
cop0_reg8.1 cop0_reg9.1 cop0_reg10.1 cop0_reg11.1
|
||||
IntCtl cop0_reg13.1 cop0_reg14.1 EBase
|
||||
Config1 cop0_reg17.1 WatchLo.1 WatchHi.1
|
||||
cop0_reg20.1 cop0_reg21.1 cop0_reg22.1 TraceControl
|
||||
cop0_reg24.1 PerfCnt.1 cop0_reg26.1 CacheErr.1
|
||||
DataLo.1 DataHi.1 cop0_reg30.1 cop0_reg31.1
|
||||
];
|
||||
|
||||
attach variables [ m16_rd0_2 ] [
|
||||
MVPConf0 VPEConf0 TCBind cop0_reg3.2
|
||||
cop0_reg4.2 cop0_reg5.2 SRSConf1 cop0_reg7.2
|
||||
cop0_reg8.2 cop0_reg9.2 cop0_reg10.2 cop0_reg11.2
|
||||
SRSCtl cop0_reg13.2 cop0_reg14.2 cop0_reg15.2
|
||||
Config2 cop0_reg17.2 WatchLo.2 WatchHi.2
|
||||
cop0_reg20.2 cop0_reg21.2 cop0_reg22.2 TraceControl2
|
||||
cop0_reg24.2 PerfCnt.2 cop0_reg26.2 CacheErr.2
|
||||
TagLo.2 TagHi.2 cop0_reg30.2 cop0_reg31.2
|
||||
];
|
||||
|
||||
attach variables [ m16_rd0_3 ] [
|
||||
MVPConf1 VPEConf1 TCRestart cop0_reg3.3
|
||||
cop0_reg4.3 cop0_reg5.3 SRSConf2 cop0_reg7.3
|
||||
cop0_reg8.3 cop0_reg9.3 cop0_reg10.3 cop0_reg11.3
|
||||
SRSMap cop0_reg13.3 cop0_reg14.3 cop0_reg15.3
|
||||
Config3 cop0_reg17.3 WatchLo.3 WatchHi.3
|
||||
cop0_reg20.3 cop0_reg21.3 cop0_reg22.3 UserTraceData
|
||||
cop0_reg24.3 PerfCnt.3 cop0_reg26.3 CacheErr.3
|
||||
DataLo.3 DataHi.3 cop0_reg30.3 cop0_reg31.3
|
||||
];
|
||||
|
||||
attach variables [ m16_rd0_4 ] [
|
||||
cop0_reg0.4 YQMask TCHalt cop0_reg3.4
|
||||
cop0_reg4.4 cop0_reg5.4 SRSConf3 cop0_reg7.4
|
||||
cop0_reg8.4 cop0_reg9.4 cop0_reg10.4 cop0_reg11.4
|
||||
cop0_reg12.4 cop0_reg13.4 cop0_reg14.4 cop0_reg15.4
|
||||
cop0_reg16.4 cop0_reg17.4 WatchLo.4 WatchHi.4
|
||||
cop0_reg20.4 cop0_reg21.4 cop0_reg22.4 TraceBPC
|
||||
cop0_reg24.4 PerfCnt.4 cop0_reg26.4 CacheErr.4
|
||||
TagLo.4 TagHi.4 cop0_reg30.4 cop0_reg31.4
|
||||
];
|
||||
|
||||
attach variables [ m16_rd0_5 ] [
|
||||
cop0_reg0.5 VPESchedule TCContext cop0_reg3.5
|
||||
cop0_reg4.5 cop0_reg5.5 SRSConf4 cop0_reg7.5
|
||||
cop0_reg8.5 cop0_reg9.5 cop0_reg10.5 cop0_reg11.5
|
||||
cop0_reg12.5 cop0_reg13.5 cop0_reg14.5 cop0_reg15.5
|
||||
cop0_reg16.5 cop0_reg17.5 WatchLo.5 WatchHi.5
|
||||
cop0_reg20.5 cop0_reg21.5 cop0_reg22.5 cop0_reg23.5
|
||||
cop0_reg24.5 PerfCnt.5 cop0_reg26.5 CacheErr.5
|
||||
DataLo.5 DataHi.5 cop0_reg30.5 cop0_reg31.5
|
||||
];
|
||||
|
||||
attach variables [ m16_rd0_6 ] [
|
||||
cop0_reg0.6 VPEScheFBack TCSchedule cop0_reg3.6
|
||||
cop0_reg4.6 cop0_reg5.6 cop0_reg6.6 cop0_reg7.6
|
||||
cop0_reg8.6 cop0_reg9.6 cop0_reg10.6 cop0_reg11.6
|
||||
cop0_reg12.6 cop0_reg13.6 cop0_reg14.6 cop0_reg15.6
|
||||
cop0_reg16.6 cop0_reg17.6 WatchLo.6 WatchHi.6
|
||||
cop0_reg20.6 cop0_reg21.6 cop0_reg22.6 cop0_reg23.6
|
||||
cop0_reg24.6 PerfCnt.6 cop0_reg26.6 CacheErr.6
|
||||
TagLo.6 TagHi.6 cop0_reg30.6 cop0_reg31.6
|
||||
];
|
||||
|
||||
attach variables [ m16_rd0_7 ] [
|
||||
cop0_reg0.7 VPEOpt TCScheFBack cop0_reg3.7
|
||||
cop0_reg4.7 cop0_reg5.7 cop0_reg6.7 cop0_reg7.7
|
||||
cop0_reg8.7 cop0_reg9.7 cop0_reg10.7 cop0_reg11.7
|
||||
cop0_reg12.7 cop0_reg13.7 cop0_reg14.7 cop0_reg15.7
|
||||
cop0_reg16.7 cop0_reg17.7 WatchLo.7 WatchHi.7
|
||||
cop0_reg20.7 cop0_reg21.7 cop0_reg22.7 cop0_reg23.7
|
||||
cop0_reg24.7 PerfCnt.7 cop0_reg26.7 CacheErr.7
|
||||
DataLo.7 DataHi.7 cop0_reg30.7 cop0_reg31.7
|
||||
];
|
||||
|
||||
@ifdef MIPS64
|
||||
attach variables [ m16_rxa m16_rya m16_rza m16_mv_rza]
|
||||
[ s0_lo s1_lo v0_lo v1_lo a0_lo a1_lo a2_lo a3_lo ];
|
||||
@@ -87,6 +184,7 @@ attach variables [ ext_m16r32a m16_i8_r32a ] [
|
||||
|
||||
RZ: m16_rz is m16_rz { export m16_rz; }
|
||||
|
||||
|
||||
@else # !MIPS64
|
||||
attach variables [ m16_rxa m16_rya m16_rza m16_mv_rza ]
|
||||
[ s0 s1 v0 v1 a0 a1 a2 a3 ];
|
||||
@@ -912,11 +1010,21 @@ E2_REGOFF: imm is ext_imm_2124 & m16_i_imm [ imm = m16_i_imm | (ext_imm_2124 <<
|
||||
m16_rx = sext( valOrig | valLoad );
|
||||
}
|
||||
|
||||
:mfc0 m16_ry, m16_i_imm, ext_imm_2123 is ISA_MODE=1 & RELP=1 & ext_isjal=0 & ext_is_ext=1 & ext_imm_2426=0 & ext_imm_2123 & ext_imm_1620=0 & m16_op=0b01100 & m16_rx=0b111 & m16_ry & m16_i_imm {
|
||||
m16_ry = getCopReg(0:1,m16_i_imm:1,ext_imm_2123:1);
|
||||
|
||||
m16_RD0: m16_rd0_0 is m16_rd0_0 & ext_imm_2123=0 { export m16_rd0_0; }
|
||||
m16_RD0: m16_rd0_1 is m16_rd0_1 & ext_imm_2123=1 { export m16_rd0_1; }
|
||||
m16_RD0: m16_rd0_2 is m16_rd0_2 & ext_imm_2123=2 { export m16_rd0_2; }
|
||||
m16_RD0: m16_rd0_3 is m16_rd0_3 & ext_imm_2123=3 { export m16_rd0_3; }
|
||||
m16_RD0: m16_rd0_4 is m16_rd0_4 & ext_imm_2123=4 { export m16_rd0_4; }
|
||||
m16_RD0: m16_rd0_5 is m16_rd0_5 & ext_imm_2123=5 { export m16_rd0_5; }
|
||||
m16_RD0: m16_rd0_6 is m16_rd0_6 & ext_imm_2123=6 { export m16_rd0_6; }
|
||||
m16_RD0: m16_rd0_7 is m16_rd0_7 & ext_imm_2123=7 { export m16_rd0_7; }
|
||||
|
||||
:mfc0 m16_ry, m16_RD0 is ISA_MODE=1 & RELP=1 & ext_isjal=0 & ext_is_ext=1 & ext_imm_2426=0 & ext_imm_2123 & ext_imm_1620=0 & m16_op=0b01100 & m16_rx=0b111 & m16_ry & m16_RD0 {
|
||||
m16_ry = zext( m16_RD0:$(SIZETO4) );
|
||||
}
|
||||
:mtc0 m16_ry, m16_i_imm, ext_imm_2123 is ISA_MODE=1 & RELP=1 & ext_isjal=0 & ext_is_ext=1 & ext_imm_2426=0 & ext_imm_2123 & ext_imm_1620=1 & m16_op=0b01100 & m16_rx=0b111 & m16_ry & m16_i_imm {
|
||||
setCopReg(0:1,m16_ry,m16_i_imm:1,ext_imm_2123:1);
|
||||
:mtc0 m16_ry, m16_RD0 is ISA_MODE=1 & RELP=1 & ext_isjal=0 & ext_is_ext=1 & ext_imm_2426=0 & ext_imm_2123 & ext_imm_1620=1 & m16_op=0b01100 & m16_rx=0b111 & m16_ry & m16_RD0 {
|
||||
setCopReg(0:1, m16_RD0, m16_ry);
|
||||
}
|
||||
|
||||
:movz m16_rx, m16_ry, ext_rb is ISA_MODE=1 & RELP=1 & ext_isjal=0 & ext_is_ext=1 & ext_imm_2226=0 & ext_imm_21=1 & ext_imm_1920=0 & ext_rb & m16_op=0b00110 & m16_rx & m16_ry & m16_shft_sa=1 & m16_shft_f=0b10 {
|
||||
|
||||
@@ -191,11 +191,13 @@ define pcodeop special2;
|
||||
|
||||
# 0100 0010 0000 0000 0000 0000 0001 1000
|
||||
:eret is $(AMODE) & prime=0x10 & fct=0x18 & bit25=1 & copfill=0 {
|
||||
return[EPC];
|
||||
JXWritePC(EPC);
|
||||
return[EPC];
|
||||
}
|
||||
|
||||
:eretnc is $(AMODE) & prime=0x10 & fct=0x18 & bit25=1 & copfill=1 {
|
||||
return[EPC];
|
||||
JXWritePC(EPC);
|
||||
return[EPC];
|
||||
}
|
||||
|
||||
# 0111 11ss ssst tttt mmmm mLLL LL00 0000
|
||||
@@ -423,13 +425,13 @@ define pcodeop special2;
|
||||
|
||||
# 0100 1000 000t tttt iiii iiii iiii iiii
|
||||
:mfc2 RT, immed is $(AMODE) & prime=0x12 & copop=0 & RT & immed {
|
||||
tmp:$(REGSIZE) = getCopReg(2:1, immed:4);
|
||||
tmp:4 = getCopReg(2:1, immed:4);
|
||||
RT = sext( tmp );
|
||||
}
|
||||
|
||||
# 0100 1000 011t tttt iiii iiii iiii iiii
|
||||
:mfhc2 RT, immed is $(AMODE) & prime=0x12 & copop=3 & RT & fs & immed {
|
||||
tmp:$(REGSIZE) = getCopReg(2:1, immed:4);
|
||||
tmp:4 = getCopReg(2:1, immed:4);
|
||||
RT = sext(tmp >> 32);
|
||||
}
|
||||
|
||||
@@ -450,16 +452,20 @@ define pcodeop special2;
|
||||
}
|
||||
|
||||
# 0100 0000 100t tttt dddd d000 0000 0sss
|
||||
:mtc0 RTsrc, RD0, sel is $(AMODE) & prime=0x10 & copop=4 & RTsrc & RD0 & zero6=0 & sel {
|
||||
setCopReg(0:1, RD0, RTsrc, sel:1);
|
||||
:mtc0 RTsrc, RD0 is $(AMODE) & prime=0x10 & copop=4 & RTsrc & RD0 & zero6=0 {
|
||||
setCopReg(0:1, RD0, RTsrc);
|
||||
}
|
||||
|
||||
# 0100 1000 100t tttt iiii iiii iiii iiii
|
||||
:mtc2 RTsrc, immed is $(AMODE) & prime=0x12 & copop=4 & RTsrc & immed {
|
||||
setCopReg(2:1, immed:4, RTsrc);
|
||||
}
|
||||
|
||||
:mthc0 RTsrc, RD0, sel is $(AMODE) & prime=0x10 & copop=6 & RTsrc & RD0 & zero6=0 & sel {
|
||||
setCopReg(0:1, RD0, RTsrc, sel:1);
|
||||
tmp:4 = RTsrc:$(SIZETO4);
|
||||
low:4 = RD0:4;
|
||||
val:8 = (zext(tmp) << 32) + zext(low);
|
||||
setCopReg(0:1, RD0, val);
|
||||
}
|
||||
|
||||
# 0100 1000 111t tttt iiii iiii iiii iiii
|
||||
@@ -1747,5 +1753,224 @@ define pcodeop SYNC;
|
||||
signalReservedInstruction(immed:2);
|
||||
}
|
||||
|
||||
rsRa: is svrs_ra=0 {}
|
||||
rsRa: ra is svrs_ra=1 & ra {
|
||||
tsp = tsp-$(REGSIZE);
|
||||
MemSrcCast(ra,tsp);
|
||||
}
|
||||
|
||||
svRa: is svrs_ra=0 {}
|
||||
svRa: ra is svrs_ra=1 & ra {
|
||||
tsp = tsp-$(REGSIZE);
|
||||
MemDestCast(tsp,ra);
|
||||
}
|
||||
|
||||
rs_statReg: is svrs_areg {}
|
||||
rs_statReg: ",a3" is (svrs_areg=1 | svrs_areg=5 | svrs_areg=9 |svrs_areg=0xd) {
|
||||
tsp = tsp-4;
|
||||
MemSrcCast(a3,tsp);
|
||||
}
|
||||
rs_statReg: ",a2-a3" is (svrs_areg=2 | svrs_areg=6 | svrs_areg=0xa) {
|
||||
tsp = tsp-4;
|
||||
MemSrcCast(a3,tsp);
|
||||
tsp = tsp-4;
|
||||
MemSrcCast(a2,tsp);
|
||||
}
|
||||
rs_statReg: ",a1-a3" is (svrs_areg=3 | svrs_areg=7) {
|
||||
tsp = tsp-4;
|
||||
MemSrcCast(a3,tsp);
|
||||
tsp = tsp-4;
|
||||
MemSrcCast(a2,tsp);
|
||||
tsp = tsp-4;
|
||||
MemSrcCast(a1,tsp);
|
||||
}
|
||||
rs_statReg: ",a0-a3" is svrs_areg=0xb {
|
||||
tsp = tsp-4;
|
||||
MemSrcCast(a3,tsp);
|
||||
tsp = tsp-4;
|
||||
MemSrcCast(a2,tsp);
|
||||
tsp = tsp-4;
|
||||
MemSrcCast(a1,tsp);
|
||||
tsp = tsp-4;
|
||||
MemSrcCast(a0,tsp);
|
||||
}
|
||||
|
||||
rsStat: is svrs_areg=0 | svrs_areg=4 | svrs_areg=8 | svrs_areg=0xc | svrs_areg=0xe {}
|
||||
rsStat: rs_statReg is rs_statReg {
|
||||
build rs_statReg;
|
||||
}
|
||||
|
||||
|
||||
sv_statReg: is svrs_areg {}
|
||||
sv_statReg: ",a3" is (svrs_areg=1 | svrs_areg=5 | svrs_areg=9 | svrs_areg=0xd) {
|
||||
tsp = tsp-4;
|
||||
MemDestCast(tsp,a3);
|
||||
}
|
||||
sv_statReg: ",a2-a3" is (svrs_areg=2 | svrs_areg=6 | svrs_areg=0xa) {
|
||||
tsp = tsp-4;
|
||||
MemDestCast(tsp,a3);
|
||||
tsp = tsp-4;
|
||||
MemDestCast(tsp,a2);
|
||||
}
|
||||
sv_statReg: ",a1-a3" is (svrs_areg=3 | svrs_areg=7) {
|
||||
tsp = tsp-4;
|
||||
MemDestCast(tsp,a3);
|
||||
tsp = tsp-4;
|
||||
MemDestCast(tsp,a2);
|
||||
tsp = tsp-4;
|
||||
MemDestCast(tsp,a1);
|
||||
}
|
||||
sv_statReg: ",a0-a3" is svrs_areg=0xb {
|
||||
tsp = tsp-4;
|
||||
MemDestCast(tsp,a3);
|
||||
tsp = tsp-4;
|
||||
MemDestCast(tsp,a2);
|
||||
tsp = tsp-4;
|
||||
MemDestCast(tsp,a1);
|
||||
tsp = tsp-4;
|
||||
MemDestCast(tsp,a0);
|
||||
}
|
||||
|
||||
svStat: is svrs_areg=0 | svrs_areg=4 | svrs_areg=8 | svrs_areg=0xc | svrs_areg=0xe {}
|
||||
svStat: sv_statReg is sv_statReg {
|
||||
build sv_statReg;
|
||||
}
|
||||
|
||||
sv_areg1: is svrs_aregb2=0 {}
|
||||
sv_areg1: "a0," is svrs_aregb2=1 {
|
||||
ptr:$(REGSIZE) = sp;
|
||||
MemDestCast(ptr,a0);
|
||||
}
|
||||
|
||||
sv_areg2: sv_areg1 is sv_areg1 { build sv_areg1; }
|
||||
sv_areg2: "a0-a1," is svrs_aregb3=1 & svrs_aregb2=0 & (svrs_aregb1=0 | svrs_aregb0=0) {
|
||||
ptr:$(REGSIZE) = sp;
|
||||
MemDestCast(ptr,a0);
|
||||
ptr = sp+4;
|
||||
MemDestCast(ptr,a1);
|
||||
}
|
||||
|
||||
sv_areg3: sv_areg2 is sv_areg2 { build sv_areg2; }
|
||||
sv_areg3: "a0-a2," is svrs_aregb3=1 & svrs_aregb2=1 & svrs_aregb1=0 {
|
||||
ptr:$(REGSIZE) = sp;
|
||||
MemDestCast(ptr,a0);
|
||||
ptr = sp+4;
|
||||
MemDestCast(ptr,a1);
|
||||
ptr = sp+8;
|
||||
MemDestCast(ptr,a2);
|
||||
}
|
||||
|
||||
sv_areg4: sv_areg3 is sv_areg3 { build sv_areg3; }
|
||||
sv_areg4: "a0-a3," is svrs_areg=0xe {
|
||||
ptr:$(REGSIZE) = sp;
|
||||
MemDestCast(ptr,a0);
|
||||
ptr = sp+4;
|
||||
MemDestCast(ptr,a1);
|
||||
ptr = sp+8;
|
||||
MemDestCast(ptr,a2);
|
||||
ptr = sp+12;
|
||||
MemDestCast(ptr,a3);
|
||||
}
|
||||
|
||||
svAregs: is svrs_aregb3=0 | svrs_areg=0xb | svrs_areg=0xf {}
|
||||
svAregs: sv_areg4 is sv_areg4 {
|
||||
build sv_areg4;
|
||||
}
|
||||
|
||||
rs_s0: is svrs_s0 {}
|
||||
rs_s0: is svrs_s0=1 { tsp = tsp-$(REGSIZE); MemSrcCast(s0,tsp); }
|
||||
|
||||
rs_s1: is svrs_s1 {}
|
||||
rs_s1: is svrs_s1=1 { tsp = tsp-$(REGSIZE); MemSrcCast(s1,tsp); }
|
||||
|
||||
rs_s8: is svrs_xreg=6 {}
|
||||
rs_s8: is svrs_xreg { tsp = tsp-$(REGSIZE); MemSrcCast(s8,tsp); }
|
||||
|
||||
rs_s7: is svrs_xreg=5 {}
|
||||
rs_s7: is rs_s8 { build rs_s8; tsp = tsp-$(REGSIZE); MemSrcCast(s7,tsp); }
|
||||
|
||||
rs_s6: is svrs_xreg=4 {}
|
||||
rs_s6: is rs_s7 { build rs_s7; tsp = tsp-$(REGSIZE); MemSrcCast(s6,tsp); }
|
||||
|
||||
rs_s5: is svrs_xreg=3 {}
|
||||
rs_s5: is rs_s6 { build rs_s6; tsp = tsp-$(REGSIZE); MemSrcCast(s5,tsp); }
|
||||
|
||||
rs_s4: is svrs_xreg=2 {}
|
||||
rs_s4: is rs_s5 { build rs_s5; tsp = tsp-$(REGSIZE); MemSrcCast(s4,tsp); }
|
||||
|
||||
rs_s3: is svrs_xreg=1 {}
|
||||
rs_s3: is rs_s4 { build rs_s4; tsp = tsp-$(REGSIZE); MemSrcCast(s3,tsp); }
|
||||
|
||||
rs_s2: is svrs_xreg=0 {}
|
||||
rs_s2: is rs_s3 { build rs_s3; tsp = tsp-$(REGSIZE); MemSrcCast(s2,tsp); }
|
||||
|
||||
rsXsregs: is svrs_s0=0 & svrs_s1=0 & svrs_xreg=0 {}
|
||||
rsXsregs: ","svrs_xreg is svrs_s0 & svrs_s1 & svrs_xreg & rs_s2 & rs_s1 & rs_s0 {
|
||||
build rs_s2;
|
||||
build rs_s1;
|
||||
build rs_s0;
|
||||
}
|
||||
|
||||
sv_s0: is svrs_s0 {}
|
||||
sv_s0: is svrs_s0=1 { tsp = tsp-$(REGSIZE); MemDestCast(tsp,s0);}
|
||||
|
||||
sv_s1: is svrs_s1 {}
|
||||
sv_s1: is svrs_s1=1 { tsp = tsp-$(REGSIZE); MemDestCast(tsp,s1); }
|
||||
|
||||
sv_s8: is svrs_xreg=6 {}
|
||||
sv_s8: is svrs_xreg { tsp = tsp-$(REGSIZE); MemDestCast(tsp,s8); }
|
||||
|
||||
sv_s7: is svrs_xreg=5 {}
|
||||
sv_s7: is sv_s8 { build sv_s8; tsp = tsp-$(REGSIZE); MemDestCast(tsp,s7); }
|
||||
|
||||
sv_s6: is svrs_xreg=4 {}
|
||||
sv_s6: is sv_s7 { build sv_s7; tsp = tsp-$(REGSIZE); MemDestCast(tsp,s6); }
|
||||
|
||||
sv_s5: is svrs_xreg=3 {}
|
||||
sv_s5: is sv_s6 { build sv_s6; tsp = tsp-$(REGSIZE); MemDestCast(tsp,s5); }
|
||||
|
||||
sv_s4: is svrs_xreg=2 {}
|
||||
sv_s4: is sv_s5 { build sv_s5; tsp = tsp-$(REGSIZE); MemDestCast(tsp,s4); }
|
||||
|
||||
sv_s3: is svrs_xreg=1 {}
|
||||
sv_s3: is sv_s4 { build sv_s4; tsp = tsp-$(REGSIZE); MemDestCast(tsp,s3); }
|
||||
|
||||
sv_s2: is svrs_xreg=0 {}
|
||||
sv_s2: is sv_s3 { build sv_s3; tsp = tsp-$(REGSIZE); MemDestCast(tsp,s2); }
|
||||
|
||||
svXsregs: is svrs_s0=0 & svrs_s0=0 & svrs_xreg=0 {}
|
||||
svXsregs: ","svrs_xreg is svrs_s0 & svrs_s1 & svrs_xreg & sv_s0 & sv_s1 & sv_s2 {
|
||||
build sv_s2;
|
||||
build sv_s1;
|
||||
build sv_s0;
|
||||
}
|
||||
|
||||
svFramesize: ,val is svrs_frame_hi=0 & svrs_frame_low=0 [val = 128; ] {export *[const]:2 val;}
|
||||
svFramesize: ,val is svrs_frame_hi & svrs_frame_low [val = ((svrs_frame_hi << 4) | svrs_frame_low) << 3;] {export *[const]:2 val;}
|
||||
|
||||
|
||||
:save svRa^svXsregs^svAregs^svFramesize is $(AMODE) & REL6=1 & prime=0x1c & fct=0x1f & save=0x01 & svRa & svXsregs & svAregs & svStat & svFramesize {
|
||||
tsp = sp;
|
||||
build svAregs;
|
||||
build svRa;
|
||||
build svXsregs;
|
||||
build svStat;
|
||||
build svFramesize;
|
||||
|
||||
tmp:2 = svFramesize;
|
||||
sp = sp - zext(tmp);
|
||||
}
|
||||
|
||||
:restore rsRa^rsXsregs^rsStat^svFramesize is $(AMODE) & REL6=1 & prime=0x1c & fct=0x1f & save=0x00 & rsRa & rsXsregs & rsStat & svFramesize {
|
||||
build svFramesize;
|
||||
|
||||
tmp:2 = svFramesize;
|
||||
tsp = sp+zext(tmp);
|
||||
|
||||
build rsRa;
|
||||
build rsXsregs;
|
||||
build rsStat;
|
||||
|
||||
sp = sp+zext(tmp);
|
||||
}
|
||||
@include "mipsfloat.sinc"
|
||||
|
||||
@@ -1313,7 +1313,7 @@ STORE_TOP16: STORE_SREG^ra,EXT_CODE4E(sp) is mic_listr6 & REL6=1 & STORE_SREG &
|
||||
break(mic_code:2);
|
||||
}
|
||||
|
||||
:sdbbp16 SDB16 is ISA_MODE=1 & RELP=0 & mic_op=0b100010 & SDB16 & ((mic_break=0b101100 & REL6=0) | (mic_breakr6=0b111011 & REL6=1)) {
|
||||
:sdbbp16 SDB16 is ISA_MODE=1 & RELP=0 & mic_op=0b010001 & SDB16 & ((mic_break=0b101100 & REL6=0) | (mic_breakr6=0b111011 & REL6=1)) {
|
||||
break(SDB16);
|
||||
}
|
||||
|
||||
|
||||
@@ -340,7 +340,7 @@ fREGLoc: freg is a=0 & f8=0xdb & freg {
|
||||
}
|
||||
|
||||
# Direct File register data
|
||||
srcREG: fREGLoc is fREGLoc { export fREGLoc; }
|
||||
srcREG: fREGLoc is fREGLoc { export fREGLoc; }
|
||||
|
||||
# PCL read - latch PC into PCL, PCLATH, and PCLATU
|
||||
srcREG: "PC" is a=0 & f8=0xf9 {
|
||||
@@ -348,18 +348,128 @@ srcREG: "PC" is a=0 & f8=0xf9 {
|
||||
export PCL;
|
||||
}
|
||||
|
||||
# Destination register (either srcREG or WREG)
|
||||
destREG: "0" is d=0 { export WREG; }
|
||||
destREG: "1" is d=1 & srcREG { export srcREG; }
|
||||
#destREG: "1" is d=1 & f8=0xf9 {
|
||||
# # Storing to PCL must write the PC using both the stored PCL (PC<7:0>), PCLATH (PC<15:8>) and PCLATU (PC<21:16>)
|
||||
# # The ADDWF and MOVWF definitions below have a specific case to handle this write to PCL
|
||||
# export PCL;
|
||||
#}
|
||||
dfLoc: f8 is a=0 & f8_57=0x0 & f8 { export *[DATA]:1 f8; } # 0x00-0x1f (Access mode)
|
||||
dfLoc: f8 is a=0 & f8_57=0x1 & f8 { export *[DATA]:1 f8; } # 0x20-0x3f (Access mode)
|
||||
dfLoc: f8 is a=0 & f8_57=0x2 & f8 { export *[DATA]:1 f8; } # 0x40-0x5f (Access mode)
|
||||
dfLoc: freg is a=0 & freg { export freg; } # 0xf60-0xfff (Access mode)
|
||||
|
||||
# TOSL - access mirrored into stack space using STKPTR
|
||||
dfLoc: freg is a=0 & f8=0xfd & freg {
|
||||
addr:1 = STKPTR + 1;
|
||||
export *[HWSTACK]:1 addr;
|
||||
}
|
||||
|
||||
# TOSH - access mirrored into stack space using STKPTR
|
||||
dfLoc: freg is a=0 & f8=0xfe & freg {
|
||||
addr:1 = STKPTR + 2;
|
||||
export *[HWSTACK]:1 addr;
|
||||
}
|
||||
|
||||
# TOSU - access mirrored into stack space using STKPTR
|
||||
dfLoc: freg is a=0 & f8=0xff & freg {
|
||||
addr:1 = STKPTR + 3;
|
||||
export *[HWSTACK]:1 addr;
|
||||
}
|
||||
|
||||
# Indirect File Register access - INDF0
|
||||
dfLoc: freg is a=0 & f8=0xef & freg {
|
||||
addr:2 = FSR0;
|
||||
export *[DATA]:1 addr;
|
||||
}
|
||||
|
||||
# Indirect File Register access - INDF1
|
||||
dfLoc: freg is a=0 & f8=0xe7 & freg {
|
||||
addr:2 = FSR1;
|
||||
export *[DATA]:1 addr;
|
||||
}
|
||||
|
||||
# Indirect File Register access - INDF2
|
||||
dfLoc: freg is a=0 & f8=0xdf & freg {
|
||||
addr:2 = FSR2;
|
||||
export *[DATA]:1 addr;
|
||||
}
|
||||
|
||||
## Post-increment File Register access - POSTINC0
|
||||
dfLoc: freg is a=0 & f8=0xee & freg {
|
||||
addr:2 = FSR0;
|
||||
export *[DATA]:1 addr;
|
||||
}
|
||||
|
||||
# Post-increment File Register access - POSTINC1
|
||||
dfLoc: freg is a=0 & f8=0xe6 & freg {
|
||||
addr:2 = FSR1;
|
||||
export *[DATA]:1 addr;
|
||||
}
|
||||
|
||||
# Post-increment File Register access - POSTINC2
|
||||
dfLoc: freg is a=0 & f8=0xde & freg {
|
||||
addr:2 = FSR2;
|
||||
export *[DATA]:1 addr;
|
||||
}
|
||||
|
||||
# Post-decrement File Register access - POSTDEC0
|
||||
dfLoc: freg is a=0 & f8=0xed & freg {
|
||||
addr:2 = FSR0;
|
||||
export *[DATA]:1 addr;
|
||||
}
|
||||
|
||||
# Post-decrement File Register access - POSTDEC1
|
||||
dfLoc: freg is a=0 & f8=0xe5 & freg {
|
||||
addr:2 = FSR1;
|
||||
export *[DATA]:1 addr;
|
||||
}
|
||||
|
||||
dfLoc: freg is a=0 & f8=0xdd & freg {
|
||||
addr:2 = FSR2;
|
||||
export *[DATA]:1 addr;
|
||||
}
|
||||
|
||||
# Pre-increment File Register access - PREINC0
|
||||
dfLoc: freg is a=0 & f8=0xec & freg {
|
||||
FSR0 = FSR0 + 1;
|
||||
addr:2 = FSR0;
|
||||
export *[DATA]:1 addr;
|
||||
}
|
||||
|
||||
# Pre-increment File Register access - PREINC1
|
||||
dfLoc: freg is a=0 & f8=0xe4 & freg {
|
||||
FSR1 = FSR1 + 1;
|
||||
addr:2 = FSR1;
|
||||
export *[DATA]:1 addr;
|
||||
}
|
||||
|
||||
# Pre-increment File Register access - PREINC2
|
||||
dfLoc: freg is a=0 & f8=0xdc & freg {
|
||||
FSR2 = FSR2 + 1;
|
||||
addr:2 = FSR2;
|
||||
export *[DATA]:1 addr;
|
||||
}
|
||||
|
||||
# Pre-increment w/WREG-Offset File Register access - PLUSW0
|
||||
dfLoc: freg is a=0 & f8=0xeb & freg {
|
||||
FSR0 = FSR0 + 1;
|
||||
addr:2 = FSR0 + sext(WREG);
|
||||
export *[DATA]:1 addr;
|
||||
}
|
||||
|
||||
# Pre-increment w/WREG-Offset File Register access - PLUSW1
|
||||
dfLoc: freg is a=0 & f8=0xe3 & freg {
|
||||
FSR1 = FSR1 + 1;
|
||||
addr:2 = FSR1 + sext(WREG);
|
||||
export *[DATA]:1 addr;
|
||||
}
|
||||
|
||||
# Pre-increment w/WREG-Offset File Register access - PLUSW2
|
||||
dfLoc: freg is a=0 & f8=0xdb & freg {
|
||||
FSR2 = FSR2 + 1;
|
||||
addr:2 = FSR2 + sext(WREG);
|
||||
export *[DATA]:1 addr;
|
||||
}
|
||||
|
||||
# Destination operand representation (w: W register is destination; f: specified fREG is destination)
|
||||
D: "w" is d=0 { }
|
||||
D: "f" is d=1 { }
|
||||
# Destination register (either srcREG or WREG)
|
||||
destREG: "0" is d=0 { export WREG; }
|
||||
destREG: "1" is d=1 & dfLoc { export dfLoc; }
|
||||
|
||||
# Source File Registers specified by a 12-bit absolute offsets within 32-bit instriction
|
||||
srcREG32: fs is fs { export *[DATA]:1 fs; } # 0x000-0xeff
|
||||
@@ -667,7 +777,7 @@ A: "BANKED" is a=1 { }
|
||||
# BYTE-ORIENTED FILE REGISTER OPERATIONS
|
||||
#
|
||||
|
||||
:ADDWF srcREG, D, A is op6=0x09 & srcREG & A & destREG & D {
|
||||
:ADDWF srcREG, destREG, A is op6=0x09 & srcREG & destREG & A {
|
||||
# 0010 01da ffff ffff
|
||||
# 0010 0100 0000 0000 -> ADDWF DAT_DATA_0000, w, ACCESS
|
||||
# 0010 0101 0000 0000 -> ADDWF REG0x0, w, BANKED
|
||||
@@ -677,7 +787,8 @@ A: "BANKED" is a=1 { }
|
||||
# 0010 0111 0000 0000 -> ADDWF REG0x0, f, BANKED
|
||||
# 0010 0110 1101 1000 -> ADDWF STATUS, f, ACCESS
|
||||
# 0010 0111 1101 1000 -> ADDWF REG0xD8, f, BANKED
|
||||
# 0010 0100 1111 1001 -> ADDWF PC, w, ACCESS
|
||||
build destREG;
|
||||
build srcREG;
|
||||
tmp:1 = srcREG; # read only once!
|
||||
setAddFlags(tmp, WREG);
|
||||
tmp = tmp + WREG;
|
||||
@@ -685,7 +796,7 @@ A: "BANKED" is a=1 { }
|
||||
setResultFlags(tmp);
|
||||
}
|
||||
|
||||
:ADDWF pcl, D, A is op6=0x09 & A & D & d=1 & pcl {
|
||||
:ADDWF pcl, destREG, A is op6=0x09 & A & destREG & pcl {
|
||||
# 0010 01da ffff ffff
|
||||
# 0010 0110 1111 1001 -> ADDWF PC, f, ACCESS
|
||||
addr:3 = inst_start;
|
||||
@@ -700,7 +811,7 @@ A: "BANKED" is a=1 { }
|
||||
goto [addr];
|
||||
}
|
||||
|
||||
:ADDWFC srcREG, D, A is op6=0x08 & srcREG & destREG & D & A {
|
||||
:ADDWFC srcREG, destREG, A is op6=0x08 & srcREG & destREG & A {
|
||||
# 0010 00da ffff ffff
|
||||
# 0010 0000 0000 0000 -> ADDWFC DAT_DATA_0000, w, ACCESS
|
||||
# 0010 0001 0000 0000 -> ADDWFC REG0x0, w, BANKED
|
||||
@@ -710,6 +821,8 @@ A: "BANKED" is a=1 { }
|
||||
# 0010 0011 0000 0000 -> ADDWFC REG0x0, f, BANKED
|
||||
# 0010 0010 1101 1000 -> ADDWFC STATUS, f, ACCESS
|
||||
# 0010 0011 1101 1000 -> ADDWFC REG0xD8, f, BANKED
|
||||
build destREG;
|
||||
build srcREG;
|
||||
local tmpC = C & 1;
|
||||
tmp:1 = srcREG;
|
||||
setAddCFlags(tmp, WREG);
|
||||
@@ -718,7 +831,7 @@ A: "BANKED" is a=1 { }
|
||||
setResultFlags(tmp);
|
||||
}
|
||||
|
||||
:ANDWF srcREG, D, A is op6=0x05 & srcREG & destREG & D & A {
|
||||
:ANDWF srcREG, destREG, A is op6=0x05 & srcREG & destREG & A {
|
||||
# 0001 01da ffff ffff
|
||||
# 0001 0100 0000 0000 -> ANDWF DAT_DATA_0000, w, ACCESS
|
||||
# 0001 0101 0000 0000 -> ANDWF REG0x0, w, BANKED
|
||||
@@ -728,6 +841,8 @@ A: "BANKED" is a=1 { }
|
||||
# 0001 0111 0000 0000 -> ANDWF REG0x0, f, BANKED
|
||||
# 0001 0110 1101 1000 -> ANDWF STATUS, f, ACCESS
|
||||
# 0001 0111 1101 1000 -> ANDWF REG0xD8, f, BANKED
|
||||
build destREG;
|
||||
build srcREG;
|
||||
tmp:1 = srcREG & WREG;
|
||||
destREG = tmp;
|
||||
setResultFlags(tmp);
|
||||
@@ -743,7 +858,7 @@ A: "BANKED" is a=1 { }
|
||||
Z = 1;
|
||||
}
|
||||
|
||||
:COMF srcREG, D, A is op6=0x07 & srcREG & destREG & D & A {
|
||||
:COMF srcREG, destREG, A is op6=0x07 & srcREG & destREG & A {
|
||||
# 0001 11da ffff ffff
|
||||
# 0001 1100 0000 0000 -> COMF DAT_DATA_0000, w, ACCESS
|
||||
# 0001 1101 0000 0000 -> COMF REG0x0, w, BANKED
|
||||
@@ -753,6 +868,8 @@ A: "BANKED" is a=1 { }
|
||||
# 0001 1111 0000 0000 -> COMF REG0x0, f, BANKED
|
||||
# 0001 1110 1101 1000 -> COMF STATUS, f, ACCESS
|
||||
# 0001 1111 1101 1000 -> COMF REG0xD8, f, BANKED
|
||||
build destREG;
|
||||
build srcREG;
|
||||
tmp:1 = ~srcREG;
|
||||
destREG = tmp;
|
||||
setResultFlags(tmp);
|
||||
@@ -785,7 +902,7 @@ A: "BANKED" is a=1 { }
|
||||
if (srcREG < WREG) goto skipInst;
|
||||
}
|
||||
|
||||
:DECF srcREG, D, A is op6=0x01 & srcREG & destREG & D & A {
|
||||
:DECF srcREG, destREG, A is op6=0x01 & srcREG & destREG & A {
|
||||
# 0000 01da ffff ffff
|
||||
# 0000 0100 0000 0000 -> DECF DAT_DATA_0000, w, ACCESS
|
||||
# 0000 0101 0000 0000 -> DECF REG0x0, w, BANKED
|
||||
@@ -795,6 +912,8 @@ A: "BANKED" is a=1 { }
|
||||
# 0000 0111 0000 0000 -> DECF REG0x0, f, BANKED
|
||||
# 0000 0110 1101 1000 -> DECF STATUS, f, ACCESS
|
||||
# 0000 0111 1101 1000 -> DECF REG0xD8, f, BANKED
|
||||
build destREG;
|
||||
build srcREG;
|
||||
tmp:1 = srcREG;
|
||||
setSubtractFlags(tmp, 1);
|
||||
tmp = tmp - 1;
|
||||
@@ -802,7 +921,7 @@ A: "BANKED" is a=1 { }
|
||||
setResultFlags(tmp);
|
||||
}
|
||||
|
||||
:DECFSZ srcREG, D, A is op6=0x0b & srcREG & destREG & D & A & skipInst {
|
||||
:DECFSZ srcREG, destREG, A is op6=0x0b & srcREG & destREG & A & skipInst {
|
||||
# 0010 11da ffff ffff
|
||||
# 0010 1100 0000 0000 -> DECFSZ DAT_DATA_0000, w, ACCESS
|
||||
# 0010 1101 0000 0000 -> DECFSZ REG0x0, w, BANKED
|
||||
@@ -812,12 +931,15 @@ A: "BANKED" is a=1 { }
|
||||
# 0010 1111 0000 0000 -> DECFSZ REG0x0, f, BANKED
|
||||
# 0010 1110 1101 1000 -> DECFSZ STATUS, f, ACCESS
|
||||
# 0010 1111 1101 1000 -> DECFSZ REG0xD8, f, BANKED
|
||||
build destREG;
|
||||
build srcREG;
|
||||
tmp:1 = srcREG - 1;
|
||||
destREG = tmp;
|
||||
if (tmp == 0) goto skipInst;
|
||||
}
|
||||
|
||||
:DCFSNZ srcREG, D, A is op6=0x13 & srcREG & destREG & D & A & skipInst {
|
||||
|
||||
:DCFSNZ srcREG, destREG, A is op6=0x13 & srcREG & destREG & A & skipInst {
|
||||
# 0100 11da ffff ffff
|
||||
# 0100 1100 0000 0000 -> DCFSNZ DAT_DATA_0000, w, ACCESS
|
||||
# 0100 1101 0000 0000 -> DCFSNZ REG0x0, w, BANKED
|
||||
@@ -827,12 +949,15 @@ A: "BANKED" is a=1 { }
|
||||
# 0100 1111 0000 0000 -> DCFSNZ REG0x0, f, BANKED
|
||||
# 0100 1110 1101 1000 -> DCFSNZ STATUS, f, ACCESS
|
||||
# 0100 1111 1101 1000 -> DCFSNZ REG0xD8, f, BANKED
|
||||
build destREG;
|
||||
build srcREG;
|
||||
tmp:1 = srcREG - 1;
|
||||
destREG = tmp;
|
||||
if (tmp != 0) goto skipInst;
|
||||
}
|
||||
|
||||
:INCF srcREG, D, A is op6=0x0a & srcREG & destREG & D & A {
|
||||
|
||||
:INCF srcREG, destREG, A is op6=0x0a & srcREG & destREG & A {
|
||||
# 0010 10da ffff ffff
|
||||
# 0010 1000 0000 0000 -> INCF DAT_DATA_0000, w, ACCESS
|
||||
# 0010 1001 0000 0000 -> INCF REG0x0, w, BANKED
|
||||
@@ -842,6 +967,8 @@ A: "BANKED" is a=1 { }
|
||||
# 0010 1011 0000 0000 -> INCF REG0x0, f, BANKED
|
||||
# 0010 1010 1101 1000 -> INCF STATUS, f, ACCESS
|
||||
# 0010 1011 1101 1000 -> INCF REG0xD8, f, BANKED
|
||||
build destREG;
|
||||
build srcREG;
|
||||
tmp:1 = srcREG; # read once only!
|
||||
setAddFlags(tmp, 1);
|
||||
tmp = tmp + 1;
|
||||
@@ -849,7 +976,7 @@ A: "BANKED" is a=1 { }
|
||||
setResultFlags(tmp);
|
||||
}
|
||||
|
||||
:INCFSZ srcREG, D, A is op6=0x0f & srcREG & destREG & D & A & skipInst {
|
||||
:INCFSZ srcREG, destREG, A is op6=0x0f & srcREG & destREG & A & skipInst {
|
||||
# 0011 11da ffff ffff
|
||||
# 0011 1100 0000 0000 -> INCFSZ DAT_DATA_0000, w, ACCESS
|
||||
# 0011 1101 0000 0000 -> INCFSZ REG0x0, w, BANKED
|
||||
@@ -859,12 +986,14 @@ A: "BANKED" is a=1 { }
|
||||
# 0011 1111 0000 0000 -> INCFSZ REG0x0, f, BANKED
|
||||
# 0011 1110 1101 1000 -> INCFSZ STATUS, f, ACCESS
|
||||
# 0011 1111 1101 1000 -> INCFSZ REG0xD8, f, BANKED
|
||||
build destREG;
|
||||
build srcREG;
|
||||
tmp:1 = srcREG + 1;
|
||||
destREG = tmp;
|
||||
if (tmp == 0) goto skipInst;
|
||||
}
|
||||
|
||||
:INFSNZ srcREG, D, A is op6=0x12 & srcREG & destREG & D & A & skipInst {
|
||||
:INFSNZ srcREG, destREG, A is op6=0x12 & srcREG & destREG & A & skipInst {
|
||||
# 0100 10da ffff ffff
|
||||
# 0100 1000 0000 0000 -> INFSNZ DAT_DATA_0000, w, ACCESS
|
||||
# 0100 1001 0000 0000 -> INFSNZ REG0x0, w, BANKED
|
||||
@@ -874,12 +1003,14 @@ A: "BANKED" is a=1 { }
|
||||
# 0100 1011 0000 0000 -> INFSNZ REG0x0, f, BANKED
|
||||
# 0100 1010 1101 1000 -> INFSNZ STATUS, f, ACCESS
|
||||
# 0100 1011 1101 1000 -> INFSNZ REG0xD8, f, BANKED
|
||||
build destREG;
|
||||
build srcREG;
|
||||
tmp:1 = srcREG + 1;
|
||||
destREG = tmp;
|
||||
if (tmp != 0) goto skipInst;
|
||||
}
|
||||
|
||||
:IORWF srcREG, D, A is op6=0x04 & srcREG & destREG & D & A {
|
||||
:IORWF srcREG, destREG, A is op6=0x04 & srcREG & destREG & A {
|
||||
# 0001 00da ffff ffff
|
||||
# 0001 0000 0000 0000 -> IORWF DAT_DATA_0000, w, ACCESS
|
||||
# 0001 0001 0000 0000 -> IORWF REG0x0, w, BANKED
|
||||
@@ -889,26 +1020,28 @@ A: "BANKED" is a=1 { }
|
||||
# 0001 0011 0000 0000 -> IORWF REG0x0, f, BANKED
|
||||
# 0001 0010 1101 1000 -> IORWF STATUS, f, ACCESS
|
||||
# 0001 0011 1101 1000 -> IORWF REG0xD8, f, BANKED
|
||||
build destREG;
|
||||
build srcREG;
|
||||
tmp:1 = srcREG | WREG;
|
||||
destREG = tmp;
|
||||
setResultFlags(tmp);
|
||||
}
|
||||
|
||||
:MOVF srcREG, D, A is op6=0x14 & srcREG & destREG & D & A {
|
||||
:MOVF srcREG, destREG, A is op6=0x14 & srcREG & destREG & A {
|
||||
# 0101 00da ffff ffff
|
||||
# 0101 0000 0000 0000 -> MOVF DAT_DATA_0000, w, ACCESS
|
||||
# 0101 0001 0000 0000 -> MOVF REG0x0, w, BANKED
|
||||
# 0101 0000 1101 1000 -> MOVF STATUS, w, ACCESS
|
||||
# 0101 0001 1101 1000 -> MOVF REG0xD8, w, BANKED
|
||||
# 0101 0000 1110 1111 -> MOVF INDF0, w, ACCESS
|
||||
# 0101 0000 1110 0111 -> MOVF INDF1, w, ACCESS
|
||||
# 0101 0000 1101 1111 -> MOVF INDF2, w, ACCESS
|
||||
# 0101 0010 0000 0000 -> MOVF DAT_DATA_0000, f, ACCESS
|
||||
# 0101 0011 0000 0000 -> MOVF REG0x0, f, BANKED
|
||||
# 0101 0010 1101 1000 -> MOVF STATUS, f, ACCESS
|
||||
# 0101 0011 1101 1000 -> MOVF REG0xD8, f, BANKED
|
||||
|
||||
# 0101 0000 1110 1111 -> MOVF INDF0, w, ACCESS
|
||||
# 0101 0000 1110 0111 -> MOVF INDF1, w, ACCESS
|
||||
# 0101 0000 1101 1111 -> MOVF INDF2, w, ACCESS
|
||||
|
||||
build destREG;
|
||||
build srcREG;
|
||||
tmp:1 = srcREG;
|
||||
destREG = tmp;
|
||||
setResultFlags(tmp);
|
||||
@@ -967,7 +1100,7 @@ A: "BANKED" is a=1 { }
|
||||
setResultFlags(tmp);
|
||||
}
|
||||
|
||||
:RLCF srcREG, D, A is op6=0x0d & srcREG & destREG & D & A {
|
||||
:RLCF srcREG, destREG, A is op6=0x0d & srcREG & destREG & A {
|
||||
# 0011 01da ffff ffff
|
||||
# 0011 0100 0000 0000 -> RLCF DAT_DATA_0000, w, ACCESS
|
||||
# 0011 0101 0000 0000 -> RLCF REG0x0, w, BANKED
|
||||
@@ -977,6 +1110,8 @@ A: "BANKED" is a=1 { }
|
||||
# 0011 0111 0000 0000 -> RLCF REG0x0, f, BANKED
|
||||
# 0011 0110 1101 1000 -> RLCF STATUS, f, ACCESS
|
||||
# 0011 0111 1101 1000 -> RLCF REG0xD8, f, BANKED
|
||||
build destREG;
|
||||
build srcREG;
|
||||
local tmpC = C & 1;
|
||||
tmp:1 = srcREG;
|
||||
C = (tmp s< 0);
|
||||
@@ -985,7 +1120,7 @@ A: "BANKED" is a=1 { }
|
||||
setResultFlags(tmp);
|
||||
}
|
||||
|
||||
:RLNCF srcREG, D, A is op6=0x11 & srcREG & destREG & D & A {
|
||||
:RLNCF srcREG, destREG, A is op6=0x11 & srcREG & destREG & A {
|
||||
# 0100 01da ffff ffff
|
||||
# 0100 0100 0000 0000 -> RLNCF DAT_DATA_0000, w, ACCESS
|
||||
# 0100 0101 0000 0000 -> RLNCF REG0x0, w, BANKED
|
||||
@@ -995,12 +1130,14 @@ A: "BANKED" is a=1 { }
|
||||
# 0100 0111 0000 0000 -> RLNCF REG0x0, f, BANKED
|
||||
# 0100 0110 1101 1000 -> RLNCF STATUS, f, ACCESS
|
||||
# 0100 0111 1101 1000 -> RLNCF REG0xD8, f, BANKED
|
||||
build destREG;
|
||||
build srcREG;
|
||||
tmp:1 = srcREG << 1;
|
||||
destREG = tmp;
|
||||
setResultFlags(tmp);
|
||||
}
|
||||
|
||||
:RRCF srcREG, D, A is op6=0x0c & srcREG & destREG & D & A {
|
||||
:RRCF srcREG, destREG, A is op6=0x0c & srcREG & destREG & A {
|
||||
# 0011 00da ffff ffff
|
||||
# 0011 0000 0000 0000 -> RRCF DAT_DATA_0000, w, ACCESS
|
||||
# 0011 0001 0000 0000 -> RRCF REG0x0, w, BANKED
|
||||
@@ -1010,6 +1147,8 @@ A: "BANKED" is a=1 { }
|
||||
# 0011 0011 0000 0000 -> RRCF REG0x0, f, BANKED
|
||||
# 0011 0010 1101 1000 -> RRCF STATUS, f, ACCESS
|
||||
# 0011 0011 1101 1000 -> RRCF REG0xD8, f, BANKED
|
||||
build destREG;
|
||||
build srcREG;
|
||||
local tmpC = C << 7;
|
||||
tmp:1 = srcREG;
|
||||
C = (tmp & 1);
|
||||
@@ -1018,16 +1157,14 @@ A: "BANKED" is a=1 { }
|
||||
setResultFlags(tmp);
|
||||
}
|
||||
|
||||
:RRNCF srcREG, D, A is op6=0x10 & srcREG & destREG & D & A {
|
||||
:RRNCF srcREG, destREG, A is op6=0x10 & srcREG & destREG & A {
|
||||
# 0100 00da ffff ffff
|
||||
# 0100 0000 0000 0000 -> RRNCF DAT_DATA_0000, w, ACCESS
|
||||
# 0100 0001 0000 0000 -> RRNCF REG0x0, w, BANKED
|
||||
# 0100 0000 1101 1000 -> RRNCF STATUS, w, ACCESS
|
||||
# 0100 0001 1101 1000 -> RRNCF REG0xD8, w, BANKED
|
||||
# 0100 0010 0000 0000 -> RRNCF DAT_DATA_0000, f, ACCESS
|
||||
# 0100 0011 0000 0000 -> RRNCF REG0x0, f, BANKED
|
||||
# 0100 0010 1101 1000 -> RRNCF STATUS, f, ACCESS
|
||||
# 0100 0011 1101 1000 -> RRNCF REG0xD8, f, BANKED
|
||||
build destREG;
|
||||
build srcREG;
|
||||
tmp:1 = srcREG >> 1;
|
||||
destREG = tmp;
|
||||
setResultFlags(tmp);
|
||||
@@ -1042,7 +1179,7 @@ A: "BANKED" is a=1 { }
|
||||
srcREG = 0xff;
|
||||
}
|
||||
|
||||
:SUBFWB srcREG, D, A is op6=0x15 & srcREG & destREG & D & A {
|
||||
:SUBFWB srcREG, destREG, A is op6=0x15 & srcREG & destREG & A {
|
||||
# 0101 01da ffff ffff
|
||||
# 0101 0100 0000 0000 -> SUBFWB DAT_DATA_0000, w, ACCESS
|
||||
# 0101 0101 0000 0000 -> SUBFWB REG0x0, w, BANKED
|
||||
@@ -1052,6 +1189,8 @@ A: "BANKED" is a=1 { }
|
||||
# 0101 0111 0000 0000 -> SUBFWB REG0x0, f, BANKED
|
||||
# 0101 0110 1101 1000 -> SUBFWB STATUS, f, ACCESS
|
||||
# 0101 0111 1101 1000 -> SUBFWB REG0xD8, f, BANKED
|
||||
build destREG;
|
||||
build srcREG;
|
||||
local notC = ~(C & 1);
|
||||
tmp:1 = srcREG;
|
||||
setSubtractCFlags(WREG, tmp);
|
||||
@@ -1060,7 +1199,7 @@ A: "BANKED" is a=1 { }
|
||||
setResultFlags(tmp);
|
||||
}
|
||||
|
||||
:SUBWF srcREG, D, A is op6=0x17 & srcREG & destREG & D & A {
|
||||
:SUBWF srcREG, destREG, A is op6=0x17 & srcREG & destREG & A {
|
||||
# 0101 11da ffff ffff
|
||||
# 0101 1100 0000 0000 -> SUBWF DAT_DATA_0000, w, ACCESS
|
||||
# 0101 1101 0000 0000 -> SUBWF REG0x0, w, BANKED
|
||||
@@ -1070,6 +1209,8 @@ A: "BANKED" is a=1 { }
|
||||
# 0101 1111 0000 0000 -> SUBWF REG0x0, f, BANKED
|
||||
# 0101 1110 1101 1000 -> SUBWF STATUS, f, ACCESS
|
||||
# 0101 1111 1101 1000 -> SUBWF REG0xD8, f, BANKED
|
||||
build destREG;
|
||||
build srcREG;
|
||||
tmp:1 = srcREG;
|
||||
setSubtractFlags(tmp, WREG);
|
||||
tmp = tmp - WREG;
|
||||
@@ -1077,7 +1218,7 @@ A: "BANKED" is a=1 { }
|
||||
setResultFlags(tmp);
|
||||
}
|
||||
|
||||
:SUBWFB srcREG, D, A is op6=0x16 & srcREG & destREG & D & A {
|
||||
:SUBWFB srcREG, destREG, A is op6=0x16 & srcREG & destREG & A {
|
||||
# 0101 10da ffff ffff
|
||||
# 0101 1000 0000 0000 -> SUBWFB DAT_DATA_0000, w, ACCESS
|
||||
# 0101 1001 0000 0000 -> SUBWFB REG0x0, w, BANKED
|
||||
@@ -1087,6 +1228,8 @@ A: "BANKED" is a=1 { }
|
||||
# 0101 1011 0000 0000 -> SUBWFB REG0x0, f, BANKED
|
||||
# 0101 1010 1101 1000 -> SUBWFB STATUS, f, ACCESS
|
||||
# 0101 1011 1101 1000 -> SUBWFB REG0xD8, f, BANKED
|
||||
build destREG;
|
||||
build srcREG;
|
||||
local notC = ~(C & 1);
|
||||
tmp:1 = srcREG;
|
||||
setSubtractCFlags(tmp, WREG);
|
||||
@@ -1095,7 +1238,7 @@ A: "BANKED" is a=1 { }
|
||||
setResultFlags(tmp);
|
||||
}
|
||||
|
||||
:SWAPF srcREG, D, A is op6=0x0e & srcREG & destREG & D & A {
|
||||
:SWAPF srcREG, destREG, A is op6=0x0e & srcREG & destREG & A {
|
||||
# 0011 10da ffff ffff
|
||||
# 0011 1000 0000 0000 -> SWAPF DAT_DATA_0000, w, ACCESS
|
||||
# 0011 1001 0000 0000 -> SWAPF REG0x0, w, BANKED
|
||||
@@ -1105,8 +1248,10 @@ A: "BANKED" is a=1 { }
|
||||
# 0011 1011 0000 0000 -> SWAPF REG0x0, f, BANKED
|
||||
# 0011 1010 1101 1000 -> SWAPF STATUS, f, ACCESS
|
||||
# 0011 1011 1101 1000 -> SWAPF REG0xD8, f, BANKED
|
||||
build destREG;
|
||||
build srcREG;
|
||||
tmp:1 = srcREG;
|
||||
destREG = (tmp << 4) | (tmp >> 4);
|
||||
destREG = (tmp << 4) | (tmp >> 4);
|
||||
}
|
||||
|
||||
:TSTFSZ srcREG, A is op6=0x19 & d=0x1 & srcREG & A & skipInst {
|
||||
@@ -1118,7 +1263,7 @@ A: "BANKED" is a=1 { }
|
||||
if (srcREG == 0) goto skipInst;
|
||||
}
|
||||
|
||||
:XORWF srcREG, D, A is op6=0x06 & srcREG & destREG & D & A {
|
||||
:XORWF srcREG, destREG, A is op6=0x06 & srcREG & destREG & A {
|
||||
# 0001 10da ffff ffff
|
||||
# 0001 1000 0000 0000 -> XORWF DAT_DATA_0000, w, ACCESS
|
||||
# 0001 1001 0000 0000 -> XORWF REG0x0, w, BANKED
|
||||
@@ -1128,6 +1273,8 @@ A: "BANKED" is a=1 { }
|
||||
# 0001 1011 0000 0000 -> XORWF REG0x0, f, BANKED
|
||||
# 0001 1010 1101 1000 -> XORWF STATUS, f, ACCESS
|
||||
# 0001 1011 1101 1000 -> XORWF REG0xD8, f, BANKED
|
||||
build destREG;
|
||||
build srcREG;
|
||||
tmp:1 = WREG ^ srcREG;
|
||||
destREG = tmp;
|
||||
setResultFlags(tmp);
|
||||
|
||||
@@ -381,11 +381,10 @@ vaddubm_part2: is vrA_8_8 & vrA_8_9 & vrA_8_10 & vrA_8_11 & vrA_8_12 & vrA_8_13
|
||||
vrD_32_3 = vrA_32_3 + vrB_32_3;
|
||||
}
|
||||
|
||||
# Collides with vadduws
|
||||
# :vadduws vrD,vrA,vrB is OP=4 & vrD & vrA & vrB & XOP_0_10=640
|
||||
# { # TODO definition
|
||||
# vrD = vectorAddUnsignedWordSaturate(vrA,vrB);
|
||||
# }
|
||||
:vadduws vrD,vrA,vrB is OP=4 & vrD & vrA & vrB & XOP_0_10=640
|
||||
{ # TODO definition
|
||||
vrD = vectorAddUnsignedWordSaturate(vrA,vrB);
|
||||
}
|
||||
|
||||
:vand vrD,vrA,vrB is OP=4 & vrD & vrA & vrB & XOP_0_10=1028
|
||||
{ # TODO definition
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
# 16 bytes. Customizable, if found they should be flagged.
|
||||
|
||||
define pcodeop flix;
|
||||
:FLIX u_4_23 is op0=0xe & u_4_23 {
|
||||
# Care probably needs to be taken here with BE support if any FLIX instructions are ever defined
|
||||
:FLIX flix_i20 is op0=0xe & flix_i20 {
|
||||
flix();
|
||||
}
|
||||
@@ -108,6 +108,8 @@ define token insn(24)
|
||||
ar = (8,11)
|
||||
fr = (8,11)
|
||||
br = (8,11)
|
||||
mw = (8,9)
|
||||
mx = (10,10)
|
||||
as = (12,15)
|
||||
fs = (12,15)
|
||||
bs = (12,15)
|
||||
@@ -115,45 +117,42 @@ define token insn(24)
|
||||
at = (16,19)
|
||||
ft = (16,19)
|
||||
bt = (16,19)
|
||||
my = (18,18)
|
||||
op0 = (20,23)
|
||||
|
||||
# Signed and unsigned immediates. Named [us]N_L.M, where u and s denote signedness, L and M the
|
||||
# least and most significant bit of the immediate in the instruction word, and N the length
|
||||
# (i.e. M-L+1).
|
||||
u3_21_23 = (1,3)
|
||||
u4_20_23 = (0,3)
|
||||
s8_16_23 = (0,7) signed
|
||||
u8_16_23 = (0,7)
|
||||
u12_12_23 = (0,11)
|
||||
s12_12_23 = (0,11) signed
|
||||
u16_8_23 = (0,15)
|
||||
s8_6_23 = (0,17) signed
|
||||
u1_20 = (0,0)
|
||||
u2_18_19 = (4,5)
|
||||
u3_17_19 = (5,7)
|
||||
u2_16_17 = (6,7)
|
||||
u1_16 = (4,4)
|
||||
u1_15_15 = (11,11)
|
||||
u2_14_15 = (10,11)
|
||||
u3_13_15 = (9,11)
|
||||
u4_12_15 = (8,11)
|
||||
m0m1_14_14 = (10,10)
|
||||
u2_12_13 = (8,9)
|
||||
mw_12_13 = (8,9)
|
||||
u1_12 = (8,8)
|
||||
u4_8_11 = (12,15)
|
||||
u8_4_11 = (12,19)
|
||||
s4_8_11 = (12,15) signed
|
||||
u1_7_7 = (19,19)
|
||||
u2_6_7 = (16,17)
|
||||
u3_5_7 = (17,19)
|
||||
u4_4_7 = (16,19)
|
||||
s4_4_7 = (16,19)
|
||||
m2m3_6_6 = (18,18)
|
||||
u_4_23 = (0,19)
|
||||
t2_4_5 = (16,17)
|
||||
u2_4_5 = (18,19)
|
||||
u1_4 = (16,16)
|
||||
op2_1_3 = (1,3)
|
||||
op2_0 = (0,0)
|
||||
ri8_i8 = (0,7)
|
||||
ri8_si8 = (0,7) signed
|
||||
bri12_i12 = (0,11)
|
||||
bri12_si12 = (0,11) signed
|
||||
ri16_i16 = (0,15)
|
||||
call_o18 = (0,17) signed
|
||||
op1_1_3 = (5,7)
|
||||
op1_0 = (4,4)
|
||||
op_r_3 = (11,11)
|
||||
op_r_2_2 = (10,11)
|
||||
op_r_1_3 = (9,11)
|
||||
op_r_0_2 = (8,9)
|
||||
op_r_0 = (8,8)
|
||||
op_r = (8,11)
|
||||
op_s = (12,15)
|
||||
op_st = (12,19)
|
||||
op_st_i8 = (12,15) signed
|
||||
op_t_3 = (19,19)
|
||||
op_t_1_3 = (17,19)
|
||||
op_t_0_2 = (16,17)
|
||||
op_t = (16,19)
|
||||
op_t_0 = (16,16)
|
||||
op_t_si4 = (16,19) signed
|
||||
|
||||
# If flix instructions are defined for a BE processor
|
||||
# this will possibly need to be split for the operands
|
||||
flix_i20 = (0,19)
|
||||
|
||||
# Care needs to be taken with these for BE
|
||||
bri8_n = (18,19)
|
||||
bri8_m = (16,17)
|
||||
;
|
||||
|
||||
# little-endian -> big-endian 16-bit conversion chart
|
||||
@@ -167,14 +166,14 @@ define token narrowinsn(16)
|
||||
n_at = (8,11)
|
||||
n_op0 = (12,15)
|
||||
|
||||
n_u4_12_15 = (0,3)
|
||||
n_s4_12_15 = (0,3) signed
|
||||
n_u4_8_11 = (4,7)
|
||||
n_u1_7 = (11,11)
|
||||
n_u2_6_7 = (10,11)
|
||||
n_u4_4_7 = (8,11)
|
||||
n_s3_4_6 = (8,10)
|
||||
n_u2_4_5 = (8,9)
|
||||
ri6_i6_0_4 = (0,3)
|
||||
ri6_si6_0_4 = (0,3) signed
|
||||
n_op_t = (4,7)
|
||||
n_op_s_3 = (11,11)
|
||||
n_op_s_2_2 = (10,11)
|
||||
n_op_s = (8,11)
|
||||
n_op_s_0_3 = (8,10)
|
||||
ri6_i6_4_2 = (8,9)
|
||||
;
|
||||
|
||||
@else
|
||||
@@ -182,9 +181,12 @@ define token narrowinsn(16)
|
||||
define token insn(24)
|
||||
# Named opcode/register fields.
|
||||
op2 = (20,23)
|
||||
op1 = (16,19)
|
||||
ar = (12,15)
|
||||
fr = (12,15)
|
||||
br = (12,15)
|
||||
mw = (12,13)
|
||||
mx = (14,14)
|
||||
as = (8,11)
|
||||
fs = (8,11)
|
||||
bs = (8,11)
|
||||
@@ -192,46 +194,40 @@ define token insn(24)
|
||||
at = (4,7)
|
||||
ft = (4,7)
|
||||
bt = (4,7)
|
||||
op1 = (16,19)
|
||||
my = (6,6)
|
||||
op0 = (0,3)
|
||||
|
||||
# Signed and unsigned immediates. Named [us]N_L_M, where u and s denote signedness, L and M the
|
||||
# least and most significant bit of the immediate in the instruction word, and N the length
|
||||
# (i.e. M-L+1).
|
||||
u3_21_23 = (21,23)
|
||||
u4_20_23 = (20,23)
|
||||
s8_16_23 = (16,23) signed
|
||||
u8_16_23 = (16,23)
|
||||
u12_12_23 = (12,23)
|
||||
s12_12_23 = (12,23) signed
|
||||
u16_8_23 = (8,23)
|
||||
s8_6_23 = (6,23) signed
|
||||
u1_20 = (20,20)
|
||||
u2_18_19 = (18,19)
|
||||
u3_17_19 = (17,19)
|
||||
u2_16_17 = (16,17)
|
||||
u1_16 = (16,16)
|
||||
u1_15_15 = (15,15)
|
||||
u2_14_15 = (14,15)
|
||||
u3_13_15 = (13,15)
|
||||
u4_12_15 = (12,15)
|
||||
m0m1_14_14 = (14,14)
|
||||
u2_12_13 = (12,13)
|
||||
mw_12_13 = (12,13)
|
||||
u1_12 = (12,12)
|
||||
u4_8_11 = (8,11)
|
||||
u8_4_11 = (4,11)
|
||||
s4_8_11 = (8,11) signed
|
||||
u1_7_7 = (7,7)
|
||||
u2_6_7 = (6,7)
|
||||
u3_5_7 = (5,7)
|
||||
u4_4_7 = (4,7)
|
||||
s4_4_7 = (4,7)
|
||||
m2m3_6_6 = (6,6)
|
||||
u_4_23 = (4,23)
|
||||
t2_4_5 = (4,5)
|
||||
u2_4_5 = (4,5)
|
||||
u1_4 = (4,4)
|
||||
op2_1_3 = (21,23)
|
||||
op2_0 = (20,20)
|
||||
ri8_i8 = (16,23)
|
||||
ri8_si8 = (16,23) signed
|
||||
bri12_i12 = (12,23)
|
||||
bri12_si12 = (12,23) signed
|
||||
ri16_i16 = (8,23)
|
||||
call_o18 = (6,23) signed
|
||||
op1_1_3 = (17,19)
|
||||
op1_0 = (16,16)
|
||||
op_r_3 = (15,15)
|
||||
op_r_2_2 = (14,15)
|
||||
op_r_1_3 = (13,15)
|
||||
op_r_0_2 = (12,13)
|
||||
op_r_0 = (12,12)
|
||||
op_r = (12,15)
|
||||
op_s = (8,11)
|
||||
op_st = (4,11)
|
||||
op_st_i8 = (8,11) signed
|
||||
op_t_3 = (7,7)
|
||||
op_t_1_3 = (5,7)
|
||||
op_t_0_2 = (4,5)
|
||||
op_t_0 = (4,4)
|
||||
op_t = (4,7)
|
||||
op_t_si4 = (4,7) signed
|
||||
flix_i20 = (4,23)
|
||||
bri8_n = (4,5)
|
||||
bri8_m = (6,7)
|
||||
;
|
||||
|
||||
# Narrow 16-bit instructions; fields are always prefixed with n_.
|
||||
@@ -241,14 +237,14 @@ define token narrowinsn(16)
|
||||
n_at = (4,7)
|
||||
n_op0 = (0, 3)
|
||||
|
||||
n_u4_12_15 = (12,15)
|
||||
n_s4_12_15 = (12,15) signed
|
||||
n_u4_8_11 = (8,11)
|
||||
n_u1_7 = (7,7)
|
||||
n_u2_6_7 = (6,7)
|
||||
n_u4_4_7 = (4,7)
|
||||
n_s3_4_6 = (4,6)
|
||||
n_u2_4_5 = (4,5)
|
||||
ri6_i6_0_4 = (12,15)
|
||||
ri6_si6_0_4 = (12,15) signed
|
||||
n_op_t = (8,11)
|
||||
n_op_s_3 = (7,7)
|
||||
n_op_s_2_2 = (6,7)
|
||||
n_op_s = (4,7)
|
||||
n_op_s_0_3 = (4,6)
|
||||
ri6_i6_4_2 = (4,5)
|
||||
;
|
||||
|
||||
@endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -87,15 +87,15 @@ attach variables [ br bs bt ] [
|
||||
# bits are named foo_LL.LM_ML.MM, where LL is the least significant bits of the least
|
||||
# singificant operand half, LM the most significant bits of the least significant operand half, etc.
|
||||
|
||||
attach variables [ mw_12_13 ] [
|
||||
attach variables [ mw ] [
|
||||
M0 M1 M2 M3
|
||||
];
|
||||
|
||||
attach variables [ m2m3_6_6 ] [
|
||||
attach variables [ my ] [
|
||||
M2 M3
|
||||
];
|
||||
|
||||
attach variables [ m0m1_14_14 ] [
|
||||
attach variables [ mx ] [
|
||||
M0 M1
|
||||
];
|
||||
|
||||
@@ -184,62 +184,62 @@ define pcodeop xsr;
|
||||
# bits are named foo_LL_LM_ML_MM, where LL is the least significant bits of the least
|
||||
# singificant operand half, LM the most significant bits of the least significant operand half, etc.
|
||||
|
||||
srel_16_23: rel is s8_16_23 [ rel = inst_start + s8_16_23 + 4; ] { export *:4 rel; }
|
||||
ri8_srel: rel is ri8_si8 [ rel = inst_start + ri8_si8 + 4; ] { export *:4 rel; }
|
||||
|
||||
srel_12_23: rel is s12_12_23 [ rel = inst_start + s12_12_23 + 4; ] { export *:4 rel; }
|
||||
bri12_srel: rel is bri12_si12 [ rel = inst_start + bri12_si12 + 4; ] { export *:4 rel; }
|
||||
|
||||
srel_6_23: rel is s8_6_23 [ rel = inst_start + s8_6_23 + 4; ] { export *:4 rel; }
|
||||
|
||||
urel_12_15_4_5: rel is n_u2_4_5 & n_u4_12_15 [
|
||||
rel = inst_start + ((n_u2_4_5 << 4) | n_u4_12_15) + 4;
|
||||
ri6_rel: rel is ri6_i6_4_2 & ri6_i6_0_4 [
|
||||
rel = inst_start + ((ri6_i6_4_2 << 4) | ri6_i6_0_4) + 4;
|
||||
] { export *:4 rel; }
|
||||
|
||||
srel_6_23_sb2: rel is s8_6_23 [
|
||||
rel = (inst_start & ~3) + ( s8_6_23 << 2 ) + 4;
|
||||
call_srel: rel is call_o18 [ rel = inst_start + call_o18 + 4; ] { export *:4 rel; }
|
||||
|
||||
call_srel_sh2: rel is call_o18 [
|
||||
rel = (inst_start & ~3) + ( call_o18 << 2 ) + 4;
|
||||
] { export *:4 rel; }
|
||||
|
||||
srel_8_23_oex_sb2: rel is u16_8_23 [
|
||||
rel = ((inst_start + 3) & ~3) + ((u16_8_23 | 0xffff0000) << 2);
|
||||
srel_oex_sh2: rel is ri16_i16 [
|
||||
rel = ((inst_start + 3) & ~3) + ((ri16_i16 | 0xffff0000) << 2);
|
||||
] { export *:4 rel; }
|
||||
|
||||
# Immediates split across the instruction.
|
||||
u5_8_11_20: tmp is u1_20 & u4_8_11 [ tmp = (u1_20 << 4) | u4_8_11; ] { export *[const]:4 tmp; }
|
||||
u5_4_7_20: tmp is u1_20 & u4_4_7 [ tmp = 32 - ((u1_20 << 4) | u4_4_7); ] { export *[const]:4 tmp; }
|
||||
u5_8_11_16: tmp is u1_16 & u4_8_11 [ tmp = (u1_16 << 4) | u4_8_11; ] { export *[const]:4 tmp; }
|
||||
u5_4_7_12: tmp is u1_12 & u4_4_7 [ tmp = (u1_12 << 4) | u4_4_7; ] { export *[const]:4 tmp; }
|
||||
u5_8_11_4: tmp is u1_4 & u4_8_11 [ tmp = (u1_4 << 4) | u4_8_11; ] { export *[const]:4 tmp; }
|
||||
u5_8_11_20: tmp is op2_0 & op_s [ tmp = (op2_0 << 4) | op_s; ] { export *[const]:4 tmp; }
|
||||
u5_4_7_20: tmp is op2_0 & op_t [ tmp = 32 - ((op2_0 << 4) | op_t); ] { export *[const]:4 tmp; }
|
||||
u5_8_11_16: tmp is op1_0 & op_s [ tmp = (op1_0 << 4) | op_s; ] { export *[const]:4 tmp; }
|
||||
u5_4_7_12: tmp is op_r_0 & op_t [ tmp = (op_r_0 << 4) | op_t; ] { export *[const]:4 tmp; }
|
||||
u5_8_11_4: tmp is op_t_0 & op_s [ tmp = (op_t_0 << 4) | op_s; ] { export *[const]:4 tmp; }
|
||||
|
||||
# Signed 12-bit (extended to 16) immediate, used by MOVI.
|
||||
s16_16_23_8_11: tmp is s4_8_11 & u8_16_23 [
|
||||
tmp = (s4_8_11 << 8) | u8_16_23;
|
||||
movi_si16: tmp is op_st_i8 & ri8_i8 [
|
||||
tmp = (op_st_i8 << 8) | ri8_i8;
|
||||
] { export *[const]:2 tmp; }
|
||||
|
||||
# An “asymmetric” immediate from -32..95, used by MOVI.N.
|
||||
n_s8_12_15_4_6_asymm: tmp is n_s3_4_6 & n_s4_12_15 [
|
||||
tmp = ((((n_s3_4_6 & 7) << 4) | (n_s4_12_15 & 15)) |
|
||||
((((n_s3_4_6 >> 2) & 1) & ((n_s3_4_6 >> 1) & 1)) << 7));
|
||||
movin_si8: tmp is n_op_s_0_3 & ri6_si6_0_4 [
|
||||
tmp = ((((n_op_s_0_3 & 7) << 4) | (ri6_si6_0_4 & 15)) |
|
||||
((((n_op_s_0_3 >> 2) & 1) & ((n_op_s_0_3 >> 1) & 1)) << 7));
|
||||
] { export *[const]:1 tmp; }
|
||||
|
||||
# Immediates shifted or with offset.
|
||||
s16_16_23_sb8: tmp is s8_16_23 [ tmp = s8_16_23 << 8; ] { export *[const]:4 tmp; }
|
||||
u15_12_23_sb3: tmp is u12_12_23 [ tmp = u12_12_23 << 3; ] { export *[const]:4 tmp; }
|
||||
u10_16_23_sb2: tmp is u8_16_23 [ tmp = u8_16_23 << 2; ] { export *[const]:4 tmp; }
|
||||
u9_16_23_sb1: tmp is u8_16_23 [ tmp = u8_16_23 << 1; ] { export *[const]:4 tmp; }
|
||||
u5_20_23_plus1: tmp is u4_20_23 [ tmp = u4_20_23 + 1; ] { export *[const]:4 tmp; }
|
||||
u8_20_23_sb4: tmp is u4_20_23 [ tmp = u4_20_23 << 4; ] { export *[const]:4 tmp; }
|
||||
u5_4_7_plus7: tmp is u4_4_7 [ tmp = u4_4_7 + 7; ] { export *[const]:4 tmp; }
|
||||
ri8_si8_sh8: tmp is ri8_si8 [ tmp = ri8_si8 << 8; ] { export *[const]:4 tmp; }
|
||||
bri12_i12_sh3: tmp is bri12_i12 [ tmp = bri12_i12 << 3; ] { export *[const]:4 tmp; }
|
||||
ri8_i8_sh2: tmp is ri8_i8 [ tmp = ri8_i8 << 2; ] { export *[const]:4 tmp; }
|
||||
u9_16_23_sb1: tmp is ri8_i8 [ tmp = ri8_i8 << 1; ] { export *[const]:4 tmp; }
|
||||
u5_20_23_plus1: tmp is op2 [ tmp = op2 + 1; ] { export *[const]:4 tmp; }
|
||||
u8_20_23_sb4: tmp is op2 [ tmp = op2 << 4; ] { export *[const]:4 tmp; }
|
||||
u5_4_7_plus7: tmp is op_t [ tmp = op_t + 7; ] { export *[const]:4 tmp; }
|
||||
|
||||
n_u6_12_15_sb2: tmp is n_u4_12_15 [ tmp = n_u4_12_15 << 2; ] { export *[const]:4 tmp; }
|
||||
n_u6_12_15_sb2: tmp is ri6_i6_0_4 [ tmp = ri6_i6_0_4 << 2; ] { export *[const]:4 tmp; }
|
||||
|
||||
# One-extended. FIXME: Verify this. Only used by [LS]32E (window extension), which aren’t yet
|
||||
# implemented.
|
||||
s5_12_15_oex: tmp is u4_12_15 [ tmp = (u4_12_15 << 2) - 64; ] { export *[const]:2 tmp; }
|
||||
s5_12_15_oex: tmp is op_r [ tmp = (op_r << 2) - 64; ] { export *[const]:2 tmp; }
|
||||
|
||||
# Some 4-bit immediates with mappings that can’t be (easily) expressed in a single disassembly action.
|
||||
|
||||
# n_u4_4_7 with 0 being -1, used by ADDI.N.
|
||||
n_s4_4_7_nozero: tmp is n_u4_4_7 = 0 [ tmp = -1; ] { export *[const]:4 tmp; }
|
||||
n_s4_4_7_nozero: tmp is n_u4_4_7 [ tmp = n_u4_4_7+0; ] { export *[const]:4 tmp; }
|
||||
n_s4_4_7_nozero: tmp is n_op_s = 0 [ tmp = -1; ] { export *[const]:4 tmp; }
|
||||
n_s4_4_7_nozero: tmp is n_op_s [ tmp = n_op_s+0; ] { export *[const]:4 tmp; }
|
||||
|
||||
# B4CONST(ar) (Branch Immediate) encodings, pg. 41 f.
|
||||
r_b4const: tmp is ar = 0 [ tmp = 0xffffffff; ] { export *[const]:4 tmp; }
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
# This is broken out because it collides with the floating point instructions. It is not included by default
|
||||
|
||||
# DEPBITS - Add (RRR), pg. 394.
|
||||
shiftimm: simm is u4_20_23 & u1_16 [ simm = u1_16 << 4 + u4_20_23; ] { export *[const]:4 simm; }
|
||||
:depbits as, at, shiftimm, u4_12_15 is u3_17_19=0x5 & u4_12_15 & as & at & op0 = 0 & shiftimm {
|
||||
mask:4 = (1 << u4_12_15) - 1;
|
||||
shiftimm: simm is op2 & op1_0 [ simm = op1_0 << 4 + op2; ] { export *[const]:4 simm; }
|
||||
:depbits as, at, shiftimm, u4_12_15 is op1_1_3=0x5 & op_r & as & at & op0 = 0 & shiftimm {
|
||||
mask:4 = (1 << op_r) - 1;
|
||||
bits:4 = (as & mask) << shiftimm;
|
||||
mask = mask << shiftimm;
|
||||
at = (~mask & at) | bits;
|
||||
|
||||
@@ -272,38 +272,38 @@ DST4: dst is dst { local tmp:4 = dst:4; export tmp; }
|
||||
# BPF_ADD:
|
||||
|
||||
# BPF_STX | BPF_ATOMIC | BPF_W
|
||||
:STXXADDW [dst + off], src is imm=0x0 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 { *:4 (dst + off) = *:4 (dst + off) + src:4; }
|
||||
:AADD32 [dst + off], src is imm=0x0 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 { *:4 (dst + off) = *:4 (dst + off) + src:4; }
|
||||
|
||||
# BPF_STX | BPF_ATOMIC | BPF_DW
|
||||
:STXXADDDW [dst + off], src is imm=0x0 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 { *:8 (dst + off) = *:8 (dst + off) + src; }
|
||||
:AADD [dst + off], src is imm=0x0 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 { *:8 (dst + off) = *:8 (dst + off) + src; }
|
||||
|
||||
# BPF_OR:
|
||||
|
||||
:STXXADDW [dst + off], src is imm=0x40 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 { *:4 (dst + off) = *:4 (dst + off) | src:4; }
|
||||
:AOR32 [dst + off], src is imm=0x40 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 { *:4 (dst + off) = *:4 (dst + off) | src:4; }
|
||||
|
||||
:STXXADDDW [dst + off], src is imm=0x40 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 { *:8 (dst + off) = *:8 (dst + off) | src; }
|
||||
:AOR [dst + off], src is imm=0x40 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 { *:8 (dst + off) = *:8 (dst + off) | src; }
|
||||
|
||||
# BPF_AND:
|
||||
|
||||
:STXXADDW [dst + off], src is imm=0x50 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 { *:4 (dst + off) = *:4 (dst + off) & src:4; }
|
||||
:AAND32 [dst + off], src is imm=0x50 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 { *:4 (dst + off) = *:4 (dst + off) & src:4; }
|
||||
|
||||
:STXXADDDW [dst + off], src is imm=0x50 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 { *:8 (dst + off) = *:8 (dst + off) & src; }
|
||||
:AAND [dst + off], src is imm=0x50 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 { *:8 (dst + off) = *:8 (dst + off) & src; }
|
||||
|
||||
# BPF_XOR:
|
||||
|
||||
:STXXADDW [dst + off], src is imm=0xa0 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 { *:4 (dst + off) = *:4 (dst + off) ^ src:4; }
|
||||
:AXOR32 [dst + off], src is imm=0xa0 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 { *:4 (dst + off) = *:4 (dst + off) ^ src:4; }
|
||||
|
||||
:STXXADDDW [dst + off], src is imm=0xa0 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 { *:8 (dst + off) = *:8 (dst + off) ^ src; }
|
||||
:AXOR [dst + off], src is imm=0xa0 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 { *:8 (dst + off) = *:8 (dst + off) ^ src; }
|
||||
|
||||
# BPF_ADD | BPF_FETCH -> src = atomic_fetch_add(dst + off, src):
|
||||
|
||||
:STXXADDW [dst + off], src is imm=0x1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 {
|
||||
:AFADD32 [dst + off], src is imm=0x1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 {
|
||||
local tmp:4 = *:4 (dst + off);
|
||||
*:4 (dst + off) = *:4 (dst + off) + src:4;
|
||||
src = zext(tmp);
|
||||
}
|
||||
|
||||
:STXXADDDW [dst + off], src is imm=0x1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 {
|
||||
:AFADD [dst + off], src is imm=0x1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 {
|
||||
local tmp:8 = *:8 (dst + off);
|
||||
*:8 (dst + off) = *:8 (dst + off) + src;
|
||||
src = tmp;
|
||||
@@ -311,13 +311,13 @@ DST4: dst is dst { local tmp:4 = dst:4; export tmp; }
|
||||
|
||||
# BPF_OR | BPF_FETCH -> src = atomic_fetch_or(dst + off, src):
|
||||
|
||||
:STXXADDW [dst + off], src is imm=0x41 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 {
|
||||
:AFOR32 [dst + off], src is imm=0x41 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 {
|
||||
local tmp:4 = *:4 (dst + off);
|
||||
*:4 (dst + off) = *:4 (dst + off) | src:4;
|
||||
src = zext(tmp);
|
||||
}
|
||||
|
||||
:STXXADDDW [dst + off], src is imm=0x41 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 {
|
||||
:AFOR [dst + off], src is imm=0x41 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 {
|
||||
local tmp:8 = *:8 (dst + off);
|
||||
*:8 (dst + off) = *:8 (dst + off) | src;
|
||||
src = tmp;
|
||||
@@ -325,13 +325,13 @@ DST4: dst is dst { local tmp:4 = dst:4; export tmp; }
|
||||
|
||||
# BPF_AND | BPF_FETCH -> src = atomic_fetch_and(dst + off, src):
|
||||
|
||||
:STXXADDW [dst + off], src is imm=0x51 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 {
|
||||
:AFAND32 [dst + off], src is imm=0x51 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 {
|
||||
local tmp:4 = *:4 (dst + off);
|
||||
*:4 (dst + off) = *:4 (dst + off) & src:4;
|
||||
src = zext(tmp);
|
||||
}
|
||||
|
||||
:STXXADDDW [dst + off], src is imm=0x51 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 {
|
||||
:AFAND [dst + off], src is imm=0x51 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 {
|
||||
local tmp:8 = *:8 (dst + off);
|
||||
*:8 (dst + off) = *:8 (dst + off) & src;
|
||||
src = tmp;
|
||||
@@ -339,13 +339,13 @@ DST4: dst is dst { local tmp:4 = dst:4; export tmp; }
|
||||
|
||||
# BPF_XOR | BPF_FETCH -> src = atomic_fetch_xor(dst + off, src):
|
||||
|
||||
:STXXADDW [dst + off], src is imm=0xa1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 {
|
||||
:AFXOR32 [dst + off], src is imm=0xa1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 {
|
||||
local tmp:4 = *:4 (dst + off);
|
||||
*:4 (dst + off) = *:4 (dst + off) ^ src:4;
|
||||
src = zext(tmp);
|
||||
}
|
||||
|
||||
:STXXADDDW [dst + off], src is imm=0xa1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 {
|
||||
:AFXOR [dst + off], src is imm=0xa1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 {
|
||||
local tmp:8 = *:8 (dst + off);
|
||||
*:8 (dst + off) = *:8 (dst + off) ^ src;
|
||||
src = tmp;
|
||||
@@ -353,13 +353,13 @@ DST4: dst is dst { local tmp:4 = dst:4; export tmp; }
|
||||
|
||||
# BPF_XCHG -> src_reg = atomic_xchg(dst + off, src):
|
||||
|
||||
:STXXADDW [dst + off], src is imm=0xe1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 {
|
||||
:AXCHG32 [dst + off], src is imm=0xe1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 {
|
||||
local tmp:4 = *:4 (dst + off);
|
||||
*:4 (dst + off) = src:4;
|
||||
src = zext(tmp);
|
||||
}
|
||||
|
||||
:STXXADDDW [dst + off], src is imm=0xe1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 {
|
||||
:AXCHG [dst + off], src is imm=0xe1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 {
|
||||
local tmp:8 = *:8 (dst + off);
|
||||
*:8 (dst + off) = src;
|
||||
src = tmp;
|
||||
@@ -367,20 +367,21 @@ DST4: dst is dst { local tmp:4 = dst:4; export tmp; }
|
||||
|
||||
# BPF_CMPXCHG -> R0 = atomic_cmpxchg(dst + off, R0, src):
|
||||
|
||||
:STXXADDW [dst + off], src is imm=0xf1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 {
|
||||
:ACMP32 [dst + off], src is imm=0xf1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 {
|
||||
local tmp:4 = *:4 (dst + off);
|
||||
if (R0:4 == tmp) goto <equal>;
|
||||
R0 = zext(tmp);
|
||||
<equal>
|
||||
if (R0:4 != tmp) goto <notEqual>;
|
||||
*:4 (dst + off) = src:4;
|
||||
<notEqual>
|
||||
R0 = zext(tmp);
|
||||
}
|
||||
|
||||
:STXXADDDW [dst + off], src is imm=0xf1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 {
|
||||
:ACMP [dst + off], src is imm=0xf1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 {
|
||||
local tmp:8 = *:8 (dst + off);
|
||||
if (R0 == tmp) goto <equal>;
|
||||
R0 = tmp;
|
||||
<equal>
|
||||
*:8 (dst + off) = src;
|
||||
if (R0 != tmp) goto <notEqual>;
|
||||
*:8 (dst + off) = src;
|
||||
goto inst_next;
|
||||
<notEqual>
|
||||
R0 = tmp;
|
||||
}
|
||||
|
||||
#Jump instructions (BPF_JMP, BPF_JMP32)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
application.name=Ghidra
|
||||
application.version=12.0.3
|
||||
application.version=12.0.4
|
||||
application.release.name=DEV
|
||||
application.layout.version=3
|
||||
application.gradle.min=8.5
|
||||
|
||||
Reference in New Issue
Block a user