use of org.mapleir.ir.code.Expr in project maple-ir by LLVM-but-worse.
the class ExpressionEvaluator method evalPossibleValues0.
private TaintableSet<ConstantExpr> evalPossibleValues0(NullPermeableHashMap<ControlFlowGraph, Set<Local>> visited, LocalValueResolver resolver, Expr e) {
if (e.getOpcode() == CONST_LOAD) {
TaintableSet<ConstantExpr> set = new TaintableSet<>();
set.add((ConstantExpr) e);
return set;
} else /*else if(e.getOpcode() == PHI) {
PhiExpr phi = (PhiExpr) e;
TaintableSet<ConstantExpr> set = new HashSet<>();
for(Expr pA : phi.getArguments().values()) {
TaintableSet<ConstantExpr> s = evalPossibleValues(resolver, pA);
set.union(s);
}
return set;
}*/
if (e.getOpcode() == ARITHMETIC) {
ArithmeticExpr ae = (ArithmeticExpr) e;
Expr l = ae.getLeft();
Expr r = ae.getRight();
TaintableSet<ConstantExpr> le = evalPossibleValues0(visited, resolver, l);
TaintableSet<ConstantExpr> re = evalPossibleValues0(visited, resolver, r);
TaintableSet<ConstantExpr> results = new TaintableSet<>(le.isTainted() | re.isTainted());
for (Iterator<Pair<ConstantExpr, ConstantExpr>> it = le.product(re); it.hasNext(); ) {
Pair<ConstantExpr, ConstantExpr> lcrc = it.next();
ConstantExpr lc = lcrc.getKey();
ConstantExpr rc = lcrc.getValue();
EvaluationFunctor<Number> b = factory.arithmetic(lc.getType(), rc.getType(), ae.getType(), ae.getOperator());
results.add(new ConstantExpr(b.eval(lc.getConstant(), rc.getConstant())));
}
return results;
} else if (e.getOpcode() == NEGATE) {
NegationExpr neg = (NegationExpr) e;
TaintableSet<ConstantExpr> inputs = evalPossibleValues0(visited, resolver, neg.getExpression());
TaintableSet<ConstantExpr> outputs = new TaintableSet<>(inputs.isTainted());
for (ConstantExpr c : inputs) {
EvaluationFunctor<Number> b = factory.negate(c.getType());
outputs.add(new ConstantExpr(b.eval(c.getConstant())));
}
return outputs;
} else if (e.getOpcode() == LOCAL_LOAD) {
VarExpr v = (VarExpr) e;
Local l = v.getLocal();
ControlFlowGraph g = e.getBlock().getGraph();
visited.getNonNull(g).add(l);
TaintableSet<Expr> defExprs = resolver.getValues(g, l);
TaintableSet<ConstantExpr> vals = new TaintableSet<>(defExprs.isTainted());
for (Expr defE : defExprs) {
if (defE.getOpcode() == LOCAL_LOAD) {
VarExpr v2 = (VarExpr) defE;
Local l2 = v2.getLocal();
if (visited.getNonNull(g).contains(l2)) {
continue;
}
visited.getNonNull(g).add(l2);
}
TaintableSet<ConstantExpr> defConstVals = evalPossibleValues0(visited, resolver, defE);
vals.union(defConstVals);
}
return vals;
} else if (e.getOpcode() == CAST) {
CastExpr cast = (CastExpr) e;
TaintableSet<ConstantExpr> inputs = evalPossibleValues0(visited, resolver, cast.getExpression());
TaintableSet<ConstantExpr> outputs = new TaintableSet<>(inputs.isTainted());
for (ConstantExpr ce : inputs) {
// TODO: czech out::
// can get expressions like (double)({lvar7_1 * 4})
// where {lvar7_1 * 4} has type INT but the real
// eval consts are all bytes or shorts etc
/*if(!ce.getType().equals(cast.getExpression().getType())) {
System.err.printf("want to cast %s%n", cast);
System.err.printf(" in: %s, death: %s%n", set, ce);
throw new IllegalStateException(ce.getType() + " : " + cast.getExpression().getType());
}*/
Type from = ce.getType();
Type to = cast.getType();
boolean p1 = TypeUtils.isPrimitive(from);
boolean p2 = TypeUtils.isPrimitive(to);
if (p1 != p2) {
throw new IllegalStateException(from + " to " + to);
}
if (!p1 && !p2) {
throw new IllegalStateException(from + " to " + to);
// return new TaintableSet<>();
}
EvaluationFunctor<Number> b = factory.cast(from, to);
outputs.add(new ConstantExpr(b.eval(ce.getConstant())));
}
return outputs;
} else if (e.getOpcode() == COMPARE) {
// throw new UnsupportedOperationException("todo lmao");
// ComparisonExpr comp = (ComparisonExpr) e;
// Expr l = comp.getLeft();
// Expr r = comp.getRight();
//
// Expr le = eval(pool, l);
// Expr re = eval(pool, r);
//
// if(le != null && re != null) {
// ConstantExpr lc = (ConstantExpr) le;
// ConstantExpr rc = (ConstantExpr) re;
//
// Bridge b = getComparisonBridge(lc.getType(), rc.getType(), comp.getComparisonType());
//
// System.out.println(b.method);
// System.out.println(comp + " -> " + b.eval(lc.getConstant(), rc.getConstant()));
// ConstantExpr cr = new ConstantExpr((int)b.eval(lc.getConstant(), rc.getConstant()));
// return cr;
// }
}
/* uncomputable value, i.e. non const. */
return new TaintableSet<>(true);
}
use of org.mapleir.ir.code.Expr in project maple-ir by LLVM-but-worse.
the class MethodRenamerPass method rename.
public static void rename(AnalysisContext cxt, Map<MethodNode, String> remapped, boolean warn) {
ApplicationClassSource source = cxt.getApplication();
InvocationResolver resolver = cxt.getInvocationResolver();
for (ClassNode cn : source.iterate()) {
{
if (cn.outerMethod != null) {
// ClassNode owner = tree.getClass(cn.outerClass);
System.out.println("Outer: " + cn.outerClass + "." + cn.outerMethod + " " + cn.outerMethodDesc);
cn.outerClass = null;
cn.outerMethod = null;
cn.outerMethodDesc = null;
// System.out.println(owner.name);
// do {
// for(MethodNode m : owner.methods) {
// System.out.println(m);
// if(m.name.equals(cn.outerMethod) && m.desc.equals(cn.outerMethodDesc)) {
// System.out.println("m: " + m);
// }
// }
// owner = tree.getClass(owner.superName);
// System.out.println(cn.superName);
// System.out.println(owner);
// } while(owner != null);
}
}
Set<Expr> visited = new HashSet<>();
for (MethodNode m : cn.methods) {
ControlFlowGraph cfg = cxt.getIRCache().getFor(m);
for (BasicBlock b : cfg.vertices()) {
for (Stmt stmt : b) {
for (Expr e : stmt.enumerateOnlyChildren()) {
if (e.getOpcode() == Opcode.INVOKE) {
InvocationExpr invoke = (InvocationExpr) e;
if (visited.contains(invoke)) {
throw new RuntimeException(invoke.toString());
}
visited.add(invoke);
if (invoke.getOwner().startsWith("[")) {
System.err.println(" ignore array object invoke: " + invoke + ", owner: " + invoke.getOwner());
continue;
}
if (invoke.isStatic()) {
MethodNode site = resolver.resolveStaticCall(invoke.getOwner(), invoke.getName(), invoke.getDesc());
if (site != null) {
if (remapped.containsKey(site)) {
invoke.setName(remapped.get(site));
} else {
if (warn && mustMark(source, invoke.getOwner())) {
System.err.println(" invalid site(s): " + invoke);
}
}
} else {
if (mustMark(source, invoke.getOwner())) {
System.err.printf(" can't resolve(s) %s ; %s.%s %s%n", invoke, invoke.getOwner(), invoke.getName(), invoke.getDesc());
if (invoke.getOwner().equals("hey")) {
for (MethodNode mm : cxt.getApplication().findClassNode(invoke.getOwner()).methods) {
System.out.println(mm);
}
throw new UnsupportedOperationException();
}
}
}
} else {
// Set<MethodNode> sites = resolver.resolveVirtualCalls(invoke.getOwner(), invoke.getName(), invoke.getDesc());
// Set<ClassNode> classes = source.getStructures().dfsTree(cn, true, true, true);
// Set<MethodNode> sites = getVirtualMethods(cxt, classes, invoke.getName(), invoke.getDesc());
Set<MethodNode> sites = resolver.getHierarchyMethodChain(source.findClassNode(invoke.getOwner()), invoke.getName(), invoke.getDesc(), true);
if (sites.size() > 0) {
/* all of the sites must be linked by the same name,
* so we can use any to find the new name. */
boolean anyContains = false;
boolean allContains = true;
for (MethodNode s : sites) {
anyContains |= remapped.containsKey(s);
allContains &= remapped.containsKey(s);
}
if (anyContains && !allContains) {
System.err.println("mismatch: ");
// System.err.println(classes);
System.err.println(sites);
throw new RuntimeException();
}
MethodNode site = sites.iterator().next();
if (remapped.containsKey(site)) {
invoke.setName(remapped.get(site));
} else {
if (warn && !site.name.equals("<init>") && canRename(cxt, sites)) {
System.err.println(" invalid site(v): " + invoke + ", " + sites);
}
}
} else {
if (mustMark(source, invoke.getOwner())) {
System.err.println(" can't resolve(v) " + invoke + ", owner: " + invoke.getOwner() + " desc " + invoke.getDesc());
// System.err.println(" classes: " + classes);
}
}
}
} else if (e.getOpcode() == Opcode.DYNAMIC_INVOKE) {
throw new UnsupportedOperationException();
}
}
}
}
}
}
/* Rename the methods after as we need to resolve
* them using the old names during the invocation
* analysis above. */
for (Entry<MethodNode, String> e : remapped.entrySet()) {
// System.out.printf("%s -> %s%n", e.getKey(), e.getValue());
e.getKey().name = e.getValue();
}
}
use of org.mapleir.ir.code.Expr in project maple-ir by LLVM-but-worse.
the class SSAGenPass method updatePhiArgTypes.
private void updatePhiArgTypes(Set<BasicBlock> vis) {
// update types for phi args
for (BasicBlock b : order) {
for (Stmt s : b) {
if (s.getOpcode() != Opcode.PHI_STORE) {
break;
}
CopyPhiStmt cps = (CopyPhiStmt) s;
for (Entry<BasicBlock, Expr> e : cps.getExpression().getArguments().entrySet()) {
BasicBlock src = e.getKey();
if (vis.contains(src))
continue;
VarExpr v = (VarExpr) e.getValue();
Local l = v.getLocal();
// what if the def is never reached?
AbstractCopyStmt def = pool.defs.get(l);
v.setType(def.getType());
}
}
}
}
use of org.mapleir.ir.code.Expr in project maple-ir by LLVM-but-worse.
the class SSAGenPass method insertPhis.
private void insertPhis(BasicBlock b, Local l, int i, LinkedList<BasicBlock> queue) {
if (b == null || b == builder.head) {
// exit
return;
}
Local newl = builder.graph.getLocals().get(l.getIndex(), 0, l.isStack());
for (BasicBlock x : doms.iteratedFrontier(b)) {
if (insertion.get(x) < i) {
// pruned SSA
if (liveness.in(x).contains(l)) {
if ((l == svar0) && handlers.contains(x)) /* == faster than contains. */
{
/* Note: this is quite subtle. Since there is a
* copy, (svar0 = catch()) at the start of each
* handler block, technically any natural flowing
* svar0 definition is killed upon entry to the
* block, so it is not considered live. One way to
* check if the variable is live-in, therefore, is
* by checking whether svar0 is live-out of the
* catch() definition. We handle it here, since
* the previous liveness check which is used for
* pruned SSA will fail in this case. */
/* Ok fuck that that, it's considered live-in
* even if there is a catch()::
* #see SSaBlockLivenessAnalyser.precomputeBlock*/
boolean naturalFlow = false;
for (FlowEdge<BasicBlock> e : builder.graph.getReverseEdges(x)) {
if (e.getType() != FlowEdges.TRYCATCH) {
naturalFlow = true;
break;
}
}
if (naturalFlow) {
CopyVarStmt catcher = null;
for (Stmt stmt : x) {
if (stmt.getOpcode() == Opcode.LOCAL_STORE) {
CopyVarStmt copy = (CopyVarStmt) stmt;
Expr e = copy.getExpression();
if (e.getOpcode() == Opcode.CATCH) {
catcher = copy;
break;
}
}
}
if (catcher == null) {
/* Handler but no catch copy?
* This can't happen since svar0 is
* the only reserved register for
* catch copies, and this block cannot
* be visited twice to insert a phi or
* psi(ephi) node. */
throw new IllegalStateException(x.getDisplayName());
}
/* Map<BasicBlock, Expression> vls = new HashMap<>();
for(FlowEdge<BasicBlock> fe : builder.graph.getReverseEdges(x)) {
vls.put(fe.src, new VarExpr(newl, null));
}
vls.put(x, catcher.getExpression().copy());
catcher.delete();
PhiExpr phi = new PhiExceptionExpr(vls);
CopyPhiStmt assign = new CopyPhiStmt(new VarExpr(l, null), phi);
x.add(0, assign); */
throw new UnsupportedOperationException(builder.method.toString());
}
}
if (builder.graph.getReverseEdges(x).size() > 1) {
Map<BasicBlock, Expr> vls = new HashMap<>();
for (FlowEdge<BasicBlock> fe : builder.graph.getReverseEdges(x)) {
vls.put(fe.src(), new VarExpr(newl, null));
}
PhiExpr phi = new PhiExpr(vls);
CopyPhiStmt assign = new CopyPhiStmt(new VarExpr(l, null), phi);
x.add(0, assign);
}
}
insertion.put(x, i);
if (process.get(x) < i) {
process.put(x, i);
queue.add(x);
}
}
}
}
use of org.mapleir.ir.code.Expr in project maple-ir by LLVM-but-worse.
the class SSAGenPass method makeValue.
private void makeValue(AbstractCopyStmt copy, VersionedLocal ssaL) {
/* Attempts to find the 'value' of a local.
* The value can be the following types:
* param - assigned by caller method
* phi - set by a phi node
* const - compiletime constant
* var - runtime computed
*
* when a copy x = y, is visited,
* if y is a var, x inherits
* the value and value type.
* */
Expr e = copy.getExpression();
int opcode = e.getOpcode();
if (opcode == Opcode.LOCAL_LOAD) {
if (copy.isSynthetic()) {
/* equals itself (pure value).*/
LatestValue value = new LatestValue(builder.graph, LatestValue.PARAM, ssaL, null);
latest.put(ssaL, value);
} else {
/* i.e. x = y, where x and y are both variables.
*
* It is expected that the local uses of the copy
* (rhs) are visited before the target is.
*/
VarExpr rhs = (VarExpr) e;
VersionedLocal rhsL = (VersionedLocal) rhs.getLocal();
/* the rhsL must have been visited already
* and the lhsL must not have been.*/
if (!latest.containsKey(ssaL)) {
if (latest.containsKey(rhsL)) {
LatestValue anc = latest.get(rhsL);
// TODO: maybe advance the src local if we
// can validate an expr propagation to the
// new copy dst.
LatestValue value = new LatestValue(builder.graph, anc.getType(), rhsL, anc.getSuggestedValue(), anc.getSource());
value.importConstraints(anc);
latest.put(ssaL, value);
} else {
throw new IllegalStateException("Non anc parent: " + ssaL + " = " + rhsL + " (def: " + pool.defs.get(rhsL) + ")");
}
} else {
throw new IllegalStateException("Revisit def " + ssaL + " ( = " + rhsL + ")");
}
}
} else {
LatestValue value;
if (opcode == Opcode.CONST_LOAD) {
ConstantExpr ce = (ConstantExpr) e;
value = new LatestValue(builder.graph, LatestValue.CONST, ce, null);
} else if ((opcode & Opcode.CLASS_PHI) == Opcode.CLASS_PHI) {
value = new LatestValue(builder.graph, LatestValue.PHI, ssaL, null);
} else {
if (e.getOpcode() == Opcode.LOCAL_LOAD) {
throw new RuntimeException(copy + " " + e);
}
value = new LatestValue(builder.graph, LatestValue.VAR, e, ssaL);
value.makeConstraints(e);
}
latest.put(ssaL, value);
}
// System.out.println("made val " + ssaL + " -> " + latest.get(ssaL));
}
Aggregations