Merge tag 'Ghidra_12.0.4_build' into stable

This commit is contained in:
Ryan Kurtz
2026-03-04 04:42:11 -05:00
66 changed files with 2061 additions and 1121 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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();

View File

@@ -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

View File

@@ -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<>();

View File

@@ -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 =

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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();

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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));

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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));

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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(),

View File

@@ -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());

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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));

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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));

View File

@@ -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();

View File

@@ -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());

View File

@@ -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());

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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),

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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;
}

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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());

View File

@@ -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;

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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));

View File

@@ -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) {

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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);
}

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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() {

View File

@@ -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)) {

View File

@@ -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);

View File

@@ -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");
}

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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);

View File

@@ -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];

View File

@@ -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;

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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));
}

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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"

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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 arent 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 cant 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; }

View File

@@ -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;

View File

@@ -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)

View File

@@ -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