mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-25 13:42:06 +00:00
java version of local collision testing in sleigh
This commit is contained in:
parent
576afa4088
commit
2e5111cb22
@ -16,6 +16,11 @@
|
||||
*/
|
||||
package ghidra.pcodeCPort.semantics;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.*;
|
||||
|
||||
import org.jdom.Element;
|
||||
|
||||
import generic.stl.*;
|
||||
import ghidra.pcodeCPort.opcodes.OpCode;
|
||||
import ghidra.pcodeCPort.space.AddrSpace;
|
||||
@ -24,11 +29,6 @@ import ghidra.pcodeCPort.utils.XmlUtils;
|
||||
import ghidra.sleigh.grammar.Location;
|
||||
import ghidra.sleigh.grammar.LocationUtil;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.*;
|
||||
|
||||
import org.jdom.Element;
|
||||
|
||||
public class ConstructTpl {
|
||||
public final Location loc;
|
||||
protected int delayslot;
|
||||
@ -138,6 +138,15 @@ public class ConstructTpl {
|
||||
return new Pair<Integer, Location>(0, null);
|
||||
}
|
||||
|
||||
public boolean buildOnly() {
|
||||
for (OpTpl op : vec) {
|
||||
if (op.getOpcode() != OpCode.CPUI_MULTIEQUAL) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void changeHandleIndex(VectorSTL<Integer> handmap) {
|
||||
IteratorSTL<OpTpl> iter;
|
||||
for (iter = vec.begin(); !iter.isEnd(); iter.increment()) {
|
||||
|
@ -255,6 +255,7 @@ public class SleighCompile extends SleighBase {
|
||||
boolean warnunusedfields; // True if fields are defined but not used
|
||||
boolean enforcelocalkeyword; // Force slaspec to use 'local' keyword when defining temporary varnodes
|
||||
boolean lenientconflicterrors; // True if we ignore most pattern conflict errors
|
||||
public boolean warnalllocalcollisions;
|
||||
public boolean warnallnops;
|
||||
public VectorSTL<String> noplist = new VectorSTL<>();
|
||||
|
||||
@ -517,6 +518,79 @@ public class SleighCompile extends SleighBase {
|
||||
}
|
||||
}
|
||||
|
||||
static int findCollision(Map<Long, Integer> local2Operand, ArrayList<Long> locals,
|
||||
int operand) {
|
||||
Integer boxOperand = Integer.valueOf(operand);
|
||||
for (int i = 0; i < locals.size(); ++i) {
|
||||
Integer previous = local2Operand.putIfAbsent(locals.get(i), boxOperand);
|
||||
if (previous != null) {
|
||||
if (previous.intValue() != operand) {
|
||||
return previous.intValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
boolean checkLocalExports(Constructor ct) {
|
||||
if (ct.getTempl() == null) {
|
||||
return true; // No template, collisions impossible
|
||||
}
|
||||
if (ct.getTempl().buildOnly()) {
|
||||
return true; // Operand exports aren't manipulated, so no collision is possible
|
||||
}
|
||||
if (ct.getNumOperands() < 2) {
|
||||
return true; // Collisions can only happen with multiple operands
|
||||
}
|
||||
boolean noCollisions = true;
|
||||
Map<Long, Integer> collect = new TreeMap<Long, Integer>();
|
||||
for (int i = 0; i < ct.getNumOperands(); ++i) {
|
||||
ArrayList<Long> newCollect = new ArrayList<Long>();
|
||||
ct.getOperand(i).collectLocalValues(newCollect);
|
||||
if (newCollect.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
int collideOperand = findCollision(collect, newCollect, i);
|
||||
if (collideOperand >= 0) {
|
||||
noCollisions = false;
|
||||
if (warnalllocalcollisions) {
|
||||
Msg.warn(this, "Possible collision with symbol " +
|
||||
ct.getOperand(collideOperand).getName() + " and " +
|
||||
ct.getOperand(i).getName() + " in constructor from " + ct.getFilename() +
|
||||
" starting at line " + Integer.toString(ct.getLineno()));
|
||||
}
|
||||
break; // Don't continue
|
||||
}
|
||||
}
|
||||
return noCollisions;
|
||||
}
|
||||
|
||||
void checkLocalCollisions() {
|
||||
int collisionCount = 0;
|
||||
SubtableSymbol sym = root; // Start with the instruction table
|
||||
int i = -1;
|
||||
for (;;) {
|
||||
int numconst = sym.getNumConstructors();
|
||||
for (int j = 0; j < numconst; ++j) {
|
||||
if (!checkLocalExports(sym.getConstructor(j))) {
|
||||
collisionCount += 1;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
if (i >= tables.size()) {
|
||||
break;
|
||||
}
|
||||
sym = tables.get(i);
|
||||
}
|
||||
if (collisionCount > 0) {
|
||||
Msg.warn(this, "WARNING: " + Integer.toString(collisionCount) +
|
||||
" constructors with local collisions between operands");
|
||||
if (!warnalllocalcollisions) {
|
||||
Msg.warn(this, "Use -c switch to list each individually");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure label symbols are used properly
|
||||
String checkSymbols(SymbolScope scope) {
|
||||
entry("checkSymbols", scope);
|
||||
@ -638,6 +712,11 @@ public class SleighCompile extends SleighBase {
|
||||
lenientconflicterrors = val;
|
||||
}
|
||||
|
||||
void setLocalCollisionWarning(boolean val) {
|
||||
entry("setLocalCollisionWarning", val);
|
||||
warnalllocalcollisions = val;
|
||||
}
|
||||
|
||||
void setAllNopWarning(boolean val) {
|
||||
entry("setAllNopWarning", val);
|
||||
warnallnops = val;
|
||||
@ -656,6 +735,10 @@ public class SleighCompile extends SleighBase {
|
||||
if (errors > 0) {
|
||||
return;
|
||||
}
|
||||
checkLocalCollisions();
|
||||
if (errors > 0) {
|
||||
return;
|
||||
}
|
||||
buildPatterns();
|
||||
if (errors > 0) {
|
||||
return;
|
||||
|
@ -47,14 +47,16 @@ public class SleighCompileLauncher implements GhidraLaunchable {
|
||||
pathname -> pathname.getName().endsWith(".slaspec");
|
||||
|
||||
private static void initCompiler(SleighCompile compiler, Map<String, String> preprocs,
|
||||
boolean unnecessaryPcodeWarning, boolean lenientConflict, boolean allNopWarning,
|
||||
boolean deadTempWarning, boolean unusedFieldWarning, boolean enforceLocalKeyWord) {
|
||||
boolean unnecessaryPcodeWarning, boolean lenientConflict, boolean allCollisionWarning,
|
||||
boolean allNopWarning, boolean deadTempWarning, boolean unusedFieldWarning,
|
||||
boolean enforceLocalKeyWord) {
|
||||
Set<Entry<String, String>> entrySet = preprocs.entrySet();
|
||||
for (Entry<String, String> entry : entrySet) {
|
||||
compiler.setPreprocValue(entry.getKey(), entry.getValue());
|
||||
}
|
||||
compiler.setUnnecessaryPcodeWarning(unnecessaryPcodeWarning);
|
||||
compiler.setLenientConflict(lenientConflict);
|
||||
compiler.setLocalCollisionWarning(allCollisionWarning);
|
||||
compiler.setAllNopWarning(allNopWarning);
|
||||
compiler.setDeadTempWarning(deadTempWarning);
|
||||
compiler.setUnusedFieldWarning(unusedFieldWarning);
|
||||
@ -107,6 +109,7 @@ public class SleighCompileLauncher implements GhidraLaunchable {
|
||||
Msg.info(SleighCompile.class, " -n print warnings for all NOP constructors");
|
||||
Msg.info(SleighCompile.class, " -t print warnings for dead temporaries");
|
||||
Msg.info(SleighCompile.class, " -e enforce use of 'local' keyword for temporaries");
|
||||
Msg.info(SleighCompile.class, " -c print warnings for all constructors with colliding operands");
|
||||
Msg.info(SleighCompile.class, " -f print warnings for unused token fields");
|
||||
Msg.info(SleighCompile.class, " -DNAME=VALUE defines a preprocessor macro NAME with value VALUE (option may be repeated)");
|
||||
Msg.info(SleighCompile.class, " -dMODULE defines a preprocessor macro MODULE with a value of its module path (option may be repeated)");
|
||||
@ -117,6 +120,7 @@ public class SleighCompileLauncher implements GhidraLaunchable {
|
||||
|
||||
boolean unnecessaryPcodeWarning = false;
|
||||
boolean lenientConflict = true;
|
||||
boolean allCollisionWarning = false;
|
||||
boolean allNopWarning = false;
|
||||
boolean deadTempWarning = false;
|
||||
boolean enforceLocalKeyWord = false;
|
||||
@ -172,6 +176,9 @@ public class SleighCompileLauncher implements GhidraLaunchable {
|
||||
else if (args[i].charAt(1) == 'l') {
|
||||
lenientConflict = false;
|
||||
}
|
||||
else if (args[i].charAt(1) == 'c') {
|
||||
allCollisionWarning = true;
|
||||
}
|
||||
else if (args[i].charAt(1) == 'n') {
|
||||
allNopWarning = true;
|
||||
}
|
||||
@ -211,6 +218,7 @@ public class SleighCompileLauncher implements GhidraLaunchable {
|
||||
System.out.println("Compiling " + input + ":");
|
||||
SleighCompile compiler = new SleighCompile();
|
||||
initCompiler(compiler, preprocs, unnecessaryPcodeWarning, lenientConflict,
|
||||
allCollisionWarning,
|
||||
allNopWarning, deadTempWarning, unusedFieldWarning, enforceLocalKeyWord);
|
||||
|
||||
String outname = input.getName().replace(".slaspec", ".sla");
|
||||
@ -238,7 +246,8 @@ public class SleighCompileLauncher implements GhidraLaunchable {
|
||||
|
||||
// single file compile
|
||||
SleighCompile compiler = new SleighCompile();
|
||||
initCompiler(compiler, preprocs, unnecessaryPcodeWarning, lenientConflict, allNopWarning,
|
||||
initCompiler(compiler, preprocs, unnecessaryPcodeWarning, lenientConflict,
|
||||
allCollisionWarning, allNopWarning,
|
||||
deadTempWarning, unusedFieldWarning, enforceLocalKeyWord);
|
||||
if (i == args.length) {
|
||||
Msg.error(SleighCompile.class, "Missing input file name");
|
||||
|
@ -16,15 +16,16 @@
|
||||
package ghidra.pcodeCPort.slghsymbol;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import org.jdom.Element;
|
||||
|
||||
import generic.stl.IteratorSTL;
|
||||
import generic.stl.VectorSTL;
|
||||
import ghidra.pcodeCPort.context.*;
|
||||
import ghidra.pcodeCPort.semantics.ConstTpl.const_type;
|
||||
import ghidra.pcodeCPort.semantics.ConstructTpl;
|
||||
import ghidra.pcodeCPort.semantics.HandleTpl;
|
||||
import ghidra.pcodeCPort.sleighbase.SleighBase;
|
||||
import ghidra.pcodeCPort.slghpatexpress.*;
|
||||
import ghidra.pcodeCPort.utils.XmlUtils;
|
||||
@ -132,6 +133,34 @@ public class Constructor {
|
||||
}
|
||||
}
|
||||
|
||||
public void collectLocalExports(ArrayList<Long> results) {
|
||||
if (templ == null) {
|
||||
return;
|
||||
}
|
||||
HandleTpl handle = templ.getResult();
|
||||
if (handle == null) {
|
||||
return;
|
||||
}
|
||||
if (handle.getSpace().isConstSpace()) {
|
||||
return; // Even if the value is dynamic, the pointed to value won't get used
|
||||
}
|
||||
if (handle.getPtrSpace().getType() != const_type.real) {
|
||||
if (handle.getTempSpace().isUniqueSpace()) {
|
||||
results.add(handle.getTempOffset().getReal());
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (handle.getSpace().isUniqueSpace()) {
|
||||
results.add(handle.getPtrOffset().getReal());
|
||||
return;
|
||||
}
|
||||
if (handle.getSpace().getType() == const_type.handle) {
|
||||
int handleIndex = handle.getSpace().getHandleIndex();
|
||||
OperandSymbol opSym = getOperand(handleIndex);
|
||||
opSym.collectLocalValues(results);
|
||||
}
|
||||
}
|
||||
|
||||
public void setError(boolean val) {
|
||||
inerror = val;
|
||||
}
|
||||
@ -570,8 +599,9 @@ public class Constructor {
|
||||
// in bytes
|
||||
|
||||
OperandResolve resolve = new OperandResolve(operands);
|
||||
if (!pateq.resolveOperandLeft(resolve))
|
||||
if (!pateq.resolveOperandLeft(resolve)) {
|
||||
throw new SleighError("Unable to resolve operand offsets", location);
|
||||
}
|
||||
|
||||
// Unravel relative offsets to absolute (if possible)
|
||||
for (int i = 0; i < operands.size(); ++i) {
|
||||
|
@ -16,6 +16,12 @@
|
||||
*/
|
||||
package ghidra.pcodeCPort.slghsymbol;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.jdom.Element;
|
||||
|
||||
import ghidra.pcodeCPort.context.*;
|
||||
import ghidra.pcodeCPort.semantics.VarnodeTpl;
|
||||
import ghidra.pcodeCPort.sleighbase.SleighBase;
|
||||
@ -24,11 +30,6 @@ import ghidra.pcodeCPort.slghpatexpress.PatternExpression;
|
||||
import ghidra.pcodeCPort.utils.XmlUtils;
|
||||
import ghidra.sleigh.grammar.Location;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.List;
|
||||
|
||||
import org.jdom.Element;
|
||||
|
||||
public class OperandSymbol extends SpecificSymbol {
|
||||
|
||||
public static final int code_address = 1;
|
||||
@ -206,6 +207,13 @@ public class OperandSymbol extends SpecificSymbol {
|
||||
pos.popOperand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collectLocalValues(ArrayList<Long> results) {
|
||||
if (triple != null) {
|
||||
triple.collectLocalValues(results);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveXml(PrintStream s) {
|
||||
s.append("<operand_sym");
|
||||
|
@ -16,6 +16,11 @@
|
||||
*/
|
||||
package ghidra.pcodeCPort.slghsymbol;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.*;
|
||||
|
||||
import org.jdom.Element;
|
||||
|
||||
import generic.stl.IteratorSTL;
|
||||
import generic.stl.VectorSTL;
|
||||
import ghidra.pcodeCPort.context.*;
|
||||
@ -27,12 +32,6 @@ import ghidra.pcodeCPort.slghpattern.Pattern;
|
||||
import ghidra.pcodeCPort.utils.XmlUtils;
|
||||
import ghidra.sleigh.grammar.Location;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.jdom.Element;
|
||||
|
||||
public class SubtableSymbol extends TripleSymbol {
|
||||
|
||||
private TokenPattern pattern;
|
||||
@ -99,6 +98,13 @@ public class SubtableSymbol extends TripleSymbol {
|
||||
throw new SleighError("Cannot use subtable in expression", null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collectLocalValues(ArrayList<Long> results) {
|
||||
for (Constructor curConstruct : construct) {
|
||||
curConstruct.collectLocalExports(results);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public symbol_type getType() {
|
||||
return symbol_type.subtable_symbol;
|
||||
|
@ -16,13 +16,14 @@
|
||||
*/
|
||||
package ghidra.pcodeCPort.slghsymbol;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ghidra.pcodeCPort.context.FixedHandle;
|
||||
import ghidra.pcodeCPort.context.ParserWalker;
|
||||
import ghidra.pcodeCPort.slghpatexpress.PatternExpression;
|
||||
import ghidra.sleigh.grammar.Location;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
// This is the central sleigh object
|
||||
public abstract class TripleSymbol extends SleighSymbol {
|
||||
|
||||
@ -44,6 +45,10 @@ public abstract class TripleSymbol extends SleighSymbol {
|
||||
|
||||
public abstract void print(PrintStream s, ParserWalker pos);
|
||||
|
||||
public void collectLocalValues(ArrayList<Long> results) {
|
||||
// By default, assume symbol has no local exports
|
||||
}
|
||||
|
||||
public Constructor resolve(ParserWalker pos) {
|
||||
return null;
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
package ghidra.pcodeCPort.slghsymbol;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.jdom.Element;
|
||||
|
||||
@ -27,6 +28,7 @@ import ghidra.pcodeCPort.semantics.ConstTpl;
|
||||
import ghidra.pcodeCPort.semantics.VarnodeTpl;
|
||||
import ghidra.pcodeCPort.sleighbase.SleighBase;
|
||||
import ghidra.pcodeCPort.space.AddrSpace;
|
||||
import ghidra.pcodeCPort.space.spacetype;
|
||||
import ghidra.pcodeCPort.utils.XmlUtils;
|
||||
import ghidra.sleigh.grammar.Location;
|
||||
|
||||
@ -57,6 +59,13 @@ public class VarnodeSymbol extends PatternlessSymbol {
|
||||
s.append(getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collectLocalValues(ArrayList<Long> results) {
|
||||
if (fix.space.getType() == spacetype.IPTR_INTERNAL) {
|
||||
results.add(fix.offset);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public symbol_type getType() {
|
||||
return symbol_type.varnode_symbol;
|
||||
|
Loading…
Reference in New Issue
Block a user