Merge remote-tracking branch

'origin/GP-1295_emteere_CParser_MacroExpansionTruthFix--SQUASHED' into
patch (Closes #3410, Closes #1652, Closes #2665, Closes #2666))
This commit is contained in:
ghidra1 2021-09-28 11:33:29 -04:00
commit 3ac5d727dd
4 changed files with 408 additions and 163 deletions

View file

@ -29,7 +29,7 @@ import ghidra.util.NumericUtilities;
*/
public class AddressEvaluator {
private static final String TOKEN_CHARS = "+-*/()<>|^&~ ";
private static final String TOKEN_CHARS = "+-*/()<>|^&~ =";
/**
* Gets a legitimate address for the specified program as indicated by the string.
@ -40,26 +40,15 @@ public class AddressEvaluator {
* to a unique legitimate address.
*/
public static Address evaluate(Program p, Address baseAddr, String s) {
StringTokenizer parser = new StringTokenizer(s, TOKEN_CHARS, true);
AddressFactory af = p.getAddressFactory();
SymbolTable st = p.getSymbolTable();
List<Object> list = new ArrayList<Object>();
if (baseAddr != null) {
list.add(baseAddr);
}
while (parser.hasMoreTokens()) {
String tok = parser.nextToken();
if (tok.equals(" ")) {
continue;
}
Object obj = Operator.getOperator(tok);
if (obj == null) {
obj = getValueObject(st, af, tok);
}
if (obj == null) {
return null;
}
list.add(obj);
if (!parseToList(s, af, st, list)) {
return null;
}
Object obj = eval(list);
if (obj instanceof Address) {
@ -70,45 +59,103 @@ public class AddressEvaluator {
return af.getDefaultAddressSpace().getAddress(((Long) obj).longValue());
}
catch (Exception e) {
// ignore
}
}
return null;
}
public static Long evaluateToLong(String s) {
StringTokenizer parser = new StringTokenizer(s, TOKEN_CHARS, true);
List<Object> list = new ArrayList<Object>();
while (parser.hasMoreTokens()) {
String tok = parser.nextToken();
if (tok.equals(" ")) {
continue;
}
Object obj = Operator.getOperator(tok);
if (obj == null) {
obj = getValueObject(tok);
}
if (obj == null) {
return null;
}
list.add(obj);
if (!parseToList(s, null, null, list)) {
return null;
}
Object obj = eval(list);
if (obj instanceof Address) {
return new Long(((Address) obj).getOffset());
return ((Address) obj).getOffset();
}
else if (obj instanceof Long) {
try {
return (Long) obj;
}
catch (Exception e) {
}
return (Long) obj;
}
return null;
}
protected static boolean parseToList(String s, AddressFactory af, SymbolTable st,
List<Object> list) {
StringTokenizer parser = new StringTokenizer(s, TOKEN_CHARS, true);
String lookahead = null;
while (lookahead != null || parser.hasMoreTokens()) {
String tok = null;
if (lookahead != null) {
tok = lookahead;
lookahead = null;
}
else {
tok = parser.nextToken();
}
if (tok.equals(" ")) {
continue;
}
// = must be followed by =, others can be followed
if (tok.equals("=") || tok.equals("!") || tok.equals("<") || tok.equals(">")) {
lookahead = parser.nextToken();
tok = checkDoubleToken(tok, lookahead);
// if tok is now longer, consumed lookahead
if (tok.length() > 1) {
lookahead = null;
}
}
Object obj = Operator.getOperator(tok);
if (obj == null) {
obj = getValueObject(st, af, tok);
}
if (obj == null) {
return false;
}
list.add(obj);
}
return true;
}
private static String checkDoubleToken(String tok, String lookahead) {
switch (tok) {
case "=":
if (lookahead.equals("=")) {
return "==";
}
break;
case "<":
if (lookahead.equals("=")) {
return "<=";
}
if (lookahead.equals("<")) {
return "<<";
}
break;
case ">":
if (lookahead.equals("=")) {
return ">=";
}
if (lookahead.equals(">")) {
return ">>";
}
break;
case "!":
if (lookahead.equals("=")) {
return "!=";
}
break;
}
return tok;
}
/**
* Gets a legitimate address for the specified program as indicated by the string.
* @param p the program to use for determining the address.
@ -179,8 +226,12 @@ public class AddressEvaluator {
private static Object getValueObject(SymbolTable st, AddressFactory af, String tok) {
if (st == null || af == null) {
return getValueObject(tok);
}
try {
return new Long(NumericUtilities.parseHexLong(tok));
return NumericUtilities.parseHexLong(tok);
}
catch (NumberFormatException e) {
// ignore
@ -215,10 +266,11 @@ public class AddressEvaluator {
strValue = strValue.substring(start);
}
return (radix == 10) ? new Long(NumericUtilities.parseLong(strValue))
: new Long(NumericUtilities.parseHexLong(strValue));
return (radix == 10) ? NumericUtilities.parseLong(strValue)
: NumericUtilities.parseHexLong(strValue);
}
catch (RuntimeException e) {
// ignore
}
return null;
}
@ -250,7 +302,7 @@ public class AddressEvaluator {
if (list.size() > 1 && list.get(0) == Operator.MINUS) {
Object obj = list.get(1);
if (obj instanceof Long) {
obj = new Long(-((Long) obj).longValue());
obj = -((Long) obj).longValue();
list.remove(0);
list.set(0, obj);
}
@ -260,7 +312,7 @@ public class AddressEvaluator {
if (list.size() > 1 && list.get(0) == Operator.NOT) {
Object obj = list.get(1);
if (obj instanceof Long) {
obj = new Long(~((Long) obj).longValue());
obj = ~((Long) obj).longValue();
list.remove(0);
list.set(0, obj);
}
@ -270,33 +322,15 @@ public class AddressEvaluator {
if (list.size() > 3 && list.get(2) == Operator.NOT) {
Object obj = list.get(3);
if (obj instanceof Long) {
obj = new Long(~((Long) obj).longValue());
obj = ~((Long) obj).longValue();
list.remove(2);
list.set(2, obj);
}
}
// evaluate all SHIFT because they have precedence
done = false;
while (!done) {
done = true;
for (int i = 0; i < list.size() - 1; i++) {
if ((list.get(i) == Operator.LEFTSHIFT && list.get(i + 1) == Operator.LEFTSHIFT) ||
(list.get(i) == Operator.RIGHTSHIFT &&
list.get(i + 1) == Operator.RIGHTSHIFT)) {
done = false;
if (i == 0 || i == list.size() - 2) {
return null;
}
Object value =
computeValue(list.get(i - 1), (Operator) list.get(i), list.get(i + 2));
if (value == null) {
return null;
}
list.subList(i, i + 3).clear();
list.set(i - 1, value);
}
}
if (!evaluateOperator(list, Operator.RIGHTSHIFT, Operator.LEFTSHIFT)) {
return null;
}
// evaluate all TIMES because they have precedence
@ -319,6 +353,19 @@ public class AddressEvaluator {
if (!evaluateOperator(list, Operator.OR, null)) {
return null;
}
if (!evaluateOperator(list, Operator.EQUALS, Operator.NOTEQUALS)) {
return null;
}
if (!evaluateOperator(list, Operator.LESS, Operator.GREATER)) {
return null;
}
if (!evaluateOperator(list, Operator.LESSEQUALS, Operator.GREATEREQUALS)) {
return null;
}
if (list.size() != 1) {
return null;
}
@ -352,42 +399,42 @@ public class AddressEvaluator {
private static Object computeValue(Object v1, Operator op, Object v2) {
if (op == Operator.TIMES) {
if ((v1 instanceof Long) && (v2 instanceof Long)) {
return new Long(((Long) v1).longValue() * ((Long) v2).longValue());
return ((Long) v1).longValue() * ((Long) v2).longValue();
}
}
if (op == Operator.DIVIDE) {
if ((v1 instanceof Long) && (v2 instanceof Long)) {
return new Long(((Long) v1).longValue() / ((Long) v2).longValue());
return ((Long) v1).longValue() / ((Long) v2).longValue();
}
}
else if (op == Operator.AND) {
if ((v1 instanceof Long) && (v2 instanceof Long)) {
return new Long(((Long) v1).longValue() & ((Long) v2).longValue());
return ((Long) v1).longValue() & ((Long) v2).longValue();
}
}
else if (op == Operator.XOR) {
if ((v1 instanceof Long) && (v2 instanceof Long)) {
return new Long(((Long) v1).longValue() ^ ((Long) v2).longValue());
return ((Long) v1).longValue() ^ ((Long) v2).longValue();
}
}
else if (op == Operator.OR) {
if ((v1 instanceof Long) && (v2 instanceof Long)) {
return new Long(((Long) v1).longValue() | ((Long) v2).longValue());
return ((Long) v1).longValue() | ((Long) v2).longValue();
}
}
else if (op == Operator.LEFTSHIFT) {
if ((v1 instanceof Long) && (v2 instanceof Long)) {
return new Long(((Long) v1).longValue() << ((Long) v2).longValue());
return ((Long) v1).longValue() << ((Long) v2).longValue();
}
}
else if (op == Operator.RIGHTSHIFT) {
if ((v1 instanceof Long) && (v2 instanceof Long)) {
return new Long(((Long) v1).longValue() >> ((Long) v2).longValue());
return ((Long) v1).longValue() >> ((Long) v2).longValue();
}
}
else if (op == Operator.PLUS) {
if ((v1 instanceof Long) && (v2 instanceof Long)) {
return new Long(((Long) v1).longValue() + ((Long) v2).longValue());
return ((Long) v1).longValue() + ((Long) v2).longValue();
}
else if ((v1 instanceof Address) && (v2 instanceof Long)) {
return ((Address) v1).addWrap(((Long) v2).longValue());
@ -398,7 +445,7 @@ public class AddressEvaluator {
}
else if (op == Operator.NOT) {
if (v2 instanceof Long) {
return new Long(~(((Long) v2).longValue()));
return ~(((Long) v2).longValue());
}
else if (v2 instanceof Address) {
return ((Address) v2).getNewAddress(~(((Long) v2).longValue()));
@ -406,15 +453,64 @@ public class AddressEvaluator {
}
else if (op == Operator.MINUS) {
if ((v1 instanceof Long) && (v2 instanceof Long)) {
return new Long(((Long) v1).longValue() - ((Long) v2).longValue());
return ((Long) v1).longValue() - ((Long) v2).longValue();
}
else if ((v1 instanceof Address) && (v2 instanceof Long)) {
return ((Address) v1).subtractWrap(((Long) v2).longValue());
}
else if ((v1 instanceof Address) && (v2 instanceof Address)) {
return new Long(((Address) v1).subtract((Address) v2));
return ((Address) v1).subtract((Address) v2);
}
}
else if (op == Operator.EQUALS) {
Long diff = getDifference(v1, v2);
if (diff != null) {
return diff == 0L ? 1L : 0L;
}
}
else if (op == Operator.NOTEQUALS) {
Long diff = getDifference(v1, v2);
if (diff != null) {
return diff != 0L ? 1L : 0L;
}
}
else if (op == Operator.LESSEQUALS) {
Long diff = getDifference(v1, v2);
if (diff != null) {
return diff <= 0L ? 1L : 0L;
}
}
else if (op == Operator.GREATEREQUALS) {
Long diff = getDifference(v1, v2);
if (diff != null) {
return diff >= 0L ? 1L : 0L;
}
}
else if (op == Operator.LESS) {
Long diff = getDifference(v1, v2);
if (diff != null) {
return diff < 0L ? 1L : 0L;
}
}
else if (op == Operator.GREATER) {
Long diff = getDifference(v1, v2);
if (diff != null) {
return diff > 0L ? 1L : 0L;
}
}
return null;
}
private static Long getDifference(Object v1, Object v2) {
if ((v1 instanceof Address) && (v2 instanceof Long)) {
return ((Address) v1).subtractWrap(((Long) v2).longValue()).getOffset();
}
else if ((v1 instanceof Address) && (v2 instanceof Address)) {
return ((Address) v1).subtract((Address) v2);
}
else if ((v1 instanceof Long) && (v2 instanceof Long)) {
return ((Long) v1).longValue() - ((Long) v2).longValue();
}
return null;
}
@ -436,20 +532,34 @@ public class AddressEvaluator {
}
class Operator {
static Operator PLUS = new Operator();
static Operator MINUS = new Operator();
static Operator TIMES = new Operator();
static Operator DIVIDE = new Operator();
static Operator AND = new Operator();
static Operator OR = new Operator();
static Operator NOT = new Operator();
static Operator XOR = new Operator();
static Operator LEFTSHIFT = new Operator();
static Operator RIGHTSHIFT = new Operator();
static Operator LEFT_PAREN = new Operator();
static Operator RIGHT_PAREN = new Operator();
static Operator PLUS = new Operator("+");
static Operator MINUS = new Operator("-");
static Operator TIMES = new Operator("*");
static Operator DIVIDE = new Operator("/");
static Operator AND = new Operator("&");
static Operator OR = new Operator("|");
static Operator NOT = new Operator("~");
static Operator XOR = new Operator("^");
static Operator LEFTSHIFT = new Operator("<<");
static Operator RIGHTSHIFT = new Operator(">>");
static Operator LEFT_PAREN = new Operator("(");
static Operator RIGHT_PAREN = new Operator(")");
static Operator EQUALS = new Operator("==");
static Operator NOTEQUALS = new Operator("!=");
static Operator LESS = new Operator("<");
static Operator GREATER = new Operator(">");
static Operator LESSEQUALS = new Operator("<=");
static Operator GREATEREQUALS = new Operator(">=");
private Operator() {
final String name;
private Operator(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
/**
@ -488,12 +598,30 @@ class Operator {
else if (tok.equals("(")) {
return LEFT_PAREN;
}
else if (tok.equals("<")) {
else if (tok.equals("<<")) {
return LEFTSHIFT;
}
else if (tok.equals(">")) {
else if (tok.equals(">>")) {
return RIGHTSHIFT;
}
else if (tok.equals("==")) {
return EQUALS;
}
else if (tok.equals("!=")) {
return NOTEQUALS;
}
else if (tok.equals("<")) {
return LESS;
}
else if (tok.equals(">")) {
return GREATER;
}
else if (tok.equals("<=")) {
return LESSEQUALS;
}
else if (tok.equals(">=")) {
return GREATEREQUALS;
}
return null;
}
}