use of org.mapleir.app.service.InvocationResolver in project maple-ir by LLVM-but-worse.
the class ConcreteStaticInvocationPass method accept.
@Override
public int accept(AnalysisContext cxt, IPass prev, List<IPass> completed) {
int fixed = 0;
InvocationResolver resolver = cxt.getInvocationResolver();
for (ClassNode cn : cxt.getApplication().iterate()) {
for (MethodNode mn : cn.methods) {
ControlFlowGraph cfg = cxt.getIRCache().getFor(mn);
for (BasicBlock b : cfg.vertices()) {
for (Stmt stmt : b) {
for (Expr e : stmt.enumerateOnlyChildren()) {
if (e.getOpcode() == Opcode.INVOKE) {
InvocationExpr invoke = (InvocationExpr) e;
if (invoke.isStatic()) {
MethodNode invoked = resolver.resolveStaticCall(invoke.getOwner(), invoke.getName(), invoke.getDesc());
if (invoked != null) {
if (!invoked.owner.name.equals(invoke.getOwner())) {
invoke.setOwner(invoked.owner.name);
fixed++;
}
}
}
}
}
}
}
}
}
System.out.printf(" corrected %d dodgy static calls.%n", fixed);
return fixed;
}
use of org.mapleir.app.service.InvocationResolver in project maple-ir by LLVM-but-worse.
the class MethodRenamerPass method accept.
@Override
public int accept(AnalysisContext cxt, IPass prev, List<IPass> completed) {
ApplicationClassSource source = cxt.getApplication();
InvocationResolver resolver = cxt.getInvocationResolver();
Map<MethodNode, String> remapped = new HashMap<>();
int totalMethods = 0;
for (ClassNode cn : source.iterate()) {
totalMethods += cn.methods.size();
}
int i = RenamingUtil.computeMinimum(totalMethods);
for (ClassNode cn : source.iterate()) {
for (MethodNode m : cn.methods) {
if (!heuristic.shouldRename(m.name, m.access)) {
// System.out.println("Heuristic bypass meth " + m.name);
continue;
}
if (remapped.containsKey(m)) {
continue;
}
if (Modifier.isStatic(m.access)) {
if (!m.name.equals("<clinit>") && !SimpleApplicationContext.isMainMethod(m)) {
String newName = RenamingUtil.createName(i++);
remapped.put(m, newName);
}
} else {
if (!m.name.equals("<init>")) {
// Set<ClassNode> classes = source.getStructures().dfsTree(m.owner, true, true, true);
// Set<MethodNode> methods = getVirtualMethods(cxt, classes, m.name, m.desc);
Set<MethodNode> methods = resolver.getHierarchyMethodChain(m.owner, m.name, m.desc, true);
if (canRename(cxt, methods)) {
String newName = RenamingUtil.createName(i++);
for (MethodNode o : methods) {
// Set<MethodNode> s2 = InvocationResolver.getHierarchyMethodChain(cxt, o.owner, o.name, m.desc, true);
/*if(!methods.equals(s2)) {
System.err.printf("m: %s%n", m);
System.err.printf("o: %s%n", o);
System.err.println("this ms::");
for(MethodNode s : methods) {
System.err.printf(" %s%n", s);
}
System.err.println("o ms::");
for(MethodNode s : s2) {
System.err.printf(" %s%n", s);
}
throw new IllegalStateException();
}*/
/*if(remapped.containsKey(o)) {
System.err.printf("m: %s%n", m);
System.err.printf("o: %s%n", o);
System.err.println("this ms::");
for(MethodNode s : methods) {
System.err.printf(" %s%n", s);
}
System.err.println("o ms::");
for(MethodNode s : InvocationResolver.getHierarchyMethodChain(cxt, o.owner, o.name, m.desc, true)) {
System.err.printf(" %s%n", s);
}
System.err.println(" o debugset::");
for(MethodNode s : debugMap.get(o)) {
System.err.printf(" %s%n", s);
}
System.err.printf("on: %s%n", remapped.get(o));
System.err.printf("nn: %s%n", newName);
throw new IllegalStateException();
}*/
remapped.put(o, newName);
}
/*for(MethodNode hm : methods) {
debugMap.put(hm, methods);
}*/
} else {
System.out.println(" can't rename: " + methods);
}
}
}
}
}
rename(cxt, remapped, true);
System.out.printf(" Remapped %d/%d methods.%n", remapped.size(), totalMethods);
return remapped.size();
}
use of org.mapleir.app.service.InvocationResolver 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.app.service.InvocationResolver in project maple-ir by LLVM-but-worse.
the class ConstantParameterPass method accept.
@Override
public int accept(AnalysisContext cxt, IPass prev, List<IPass> completed) {
Map<MethodNode, Set<MethodNode>> chainMap = new HashMap<>();
for (MethodNode mn : cxt.getIRCache().getActiveMethods()) {
makeUpChain(cxt, mn, chainMap);
}
InvocationResolver resolver = cxt.getInvocationResolver();
Map<MethodNode, List<Set<Object>>> rawConstantParameters = new HashMap<>();
Map<MethodNode, boolean[]> chainedNonConstant = new HashMap<>();
Map<MethodNode, boolean[]> specificNonConstant = new HashMap<>();
IPAnalysisVisitor vis = new IPAnalysisVisitor() {
@Override
public void postVisitMethod(IPAnalysis analysis, MethodNode m) {
int pCount = Type.getArgumentTypes(m.desc).length;
/* init map entries */
if (!chainedNonConstant.containsKey(m)) {
for (MethodNode assoc : chainMap.get(m)) {
boolean[] arr = new boolean[pCount];
chainedNonConstant.put(assoc, arr);
}
for (MethodNode assoc : chainMap.get(m)) {
boolean[] arr = new boolean[pCount];
specificNonConstant.put(assoc, arr);
}
}
if (Modifier.isStatic(m.access)) {
if (!rawConstantParameters.containsKey(m)) {
List<Set<Object>> l = new ArrayList<>(pCount);
rawConstantParameters.put(m, l);
for (int i = 0; i < pCount; i++) {
l.add(new HashSet<>());
}
}
} else {
// TODO: cache
for (MethodNode site : resolver.resolveVirtualCalls(m, true)) {
if (!rawConstantParameters.containsKey(site)) {
List<Set<Object>> l = new ArrayList<>(pCount);
rawConstantParameters.put(site, l);
for (int i = 0; i < pCount; i++) {
l.add(new HashSet<>());
}
}
}
}
}
@Override
public void postProcessedInvocation(IPAnalysis analysis, MethodNode caller, MethodNode callee, Invocation call) {
Expr[] params = call.getParameterExprs();
for (int i = 0; i < params.length; i++) {
Expr e = params[i];
if (e.getOpcode() == Opcode.CONST_LOAD) {
if (Modifier.isStatic(callee.access)) {
rawConstantParameters.get(callee).get(i).add(((ConstantExpr) e).getConstant());
} else {
/* only chain callsites *can* have this input */
for (MethodNode site : resolver.resolveVirtualCalls(callee, true)) {
rawConstantParameters.get(site).get(i).add(((ConstantExpr) e).getConstant());
}
}
} else {
/* whole branch tainted */
for (MethodNode associated : chainMap.get(callee)) {
chainedNonConstant.get(associated)[i] = true;
}
/* callsites tainted */
if (Modifier.isStatic(callee.access)) {
specificNonConstant.get(callee)[i] = true;
} else {
/* only chain callsites *can* have this input */
for (MethodNode site : resolver.resolveVirtualCalls(callee, true)) {
specificNonConstant.get(site)[i] = true;
}
}
}
}
}
};
IPAnalysis constAnalysis = IPAnalysis.create(cxt, vis);
// ApplicationClassSource app = cxt.getApplication();
// ClassTree structures = app.getStructures();
/* remove all calls to library methods since we can't
* handle them. */
/*Iterator<Entry<MethodNode, List<Set<Object>>>> it = rawConstantParameters.entrySet().iterator();
while(it.hasNext()) {
Entry<MethodNode, List<Set<Object>>> en = it.next();
MethodNode m = en.getKey();
if(app.isLibraryClass(m.owner.name)) {
it.remove();
continue;
}
// TODO: MUST BE CONVERTED TO ACCOUNT FOR DIRECT SUPERS, NOT ALL
superFor: for(ClassNode cn : structures.getAllParents(m.owner)) {
if(app.isLibraryClass(cn.name)) {
for(MethodNode m1 : cn.methods) {
if(resolver.areMethodsCongruent(m1, m, Modifier.isStatic(m.access))) {
it.remove();
break superFor;
}
}
}
}
}*/
/* aggregate constant parameters indices with their chained
* methods such that the map contains only constant parameter
* indices that we can actually remove while keeping a valid chain.
*
* We do this as we can have methods from different branches that
* are cousin-related but have different constant parameter values.
* In these cases we can still inline the constants (different constants)
* and change the descriptions, keeping the chain. */
Map<MethodNode, boolean[]> filteredConstantParameters = new HashMap<>();
for (Entry<MethodNode, List<Set<Object>>> en : rawConstantParameters.entrySet()) {
MethodNode m = en.getKey();
List<Set<Object>> objParams = en.getValue();
boolean[] tainted = chainedNonConstant.get(m);
if (filteredConstantParameters.containsKey(m)) {
/* note: if this method is contained in the
* map all of it's cousin-reachable methods
* must also be and furthermore the dead map
* for the entire chain is the same array.
*
* we need to now merge the current dead map
* with the one specifically for this method.*/
boolean[] thisDeadMap = makeDeadMap(objParams, tainted);
boolean[] prevDeadMap = filteredConstantParameters.get(m);
if (thisDeadMap.length != prevDeadMap.length) {
throw new IllegalStateException(String.format("m: %s, chain:%s, %d:%d", m, chainMap.get(m), thisDeadMap.length, prevDeadMap.length));
}
/* each dead map contains true values for an
* index if that index is a constant parameter. */
for (int i = 0; i < prevDeadMap.length; i++) {
prevDeadMap[i] &= thisDeadMap[i];
}
} else {
boolean[] deadParams = makeDeadMap(objParams, tainted);
for (MethodNode chm : chainMap.get(m)) {
filteredConstantParameters.put(chm, deadParams);
}
}
ControlFlowGraph cfg = cxt.getIRCache().getFor(m);
// boolean b = false;
boolean[] specificTaint = specificNonConstant.get(m);
for (int i = 0; i < objParams.size(); i++) {
Set<Object> set = objParams.get(i);
if (!specificTaint[i] && set.size() == 1) {
inlineConstant(cfg, constAnalysis.getLocalIndex(m, i), set.iterator().next());
}
}
}
Map<MethodNode, String> remap = new HashMap<>();
Set<MethodNode> toRemove = new HashSet<>();
Set<Set<MethodNode>> mustRename = new HashSet<>();
for (Entry<MethodNode, boolean[]> en : filteredConstantParameters.entrySet()) {
MethodNode m = en.getKey();
if (!remap.containsKey(m) && !toRemove.contains(m)) {
boolean[] deadMap = en.getValue();
boolean notSame = false;
for (boolean b : deadMap) {
notSame |= b;
}
if (!notSame) {
/* eliminate all branches (same congruence class) */
for (MethodNode n : chainMap.get(m)) {
toRemove.add(n);
}
continue;
}
Type[] params = Type.getArgumentTypes(m.desc);
Type ret = Type.getReturnType(m.desc);
String desc = buildDesc(params, ret, deadMap);
Set<MethodNode> conflicts = new HashSet<>();
for (MethodNode chm : chainMap.get(m)) {
remap.put(chm, desc);
if (Modifier.isStatic(m.access)) {
MethodNode mm = resolver.resolveStaticCall(chm.owner.name, chm.name, desc);
if (mm != null) {
conflicts.add(mm);
}
} else {
if (chm.name.equals("<init>")) {
conflicts.addAll(resolver.resolveVirtualCalls(chm.owner.name, "<init>", desc, false));
} else {
conflicts.addAll(resolver.getHierarchyMethodChain(m.owner, m.name, desc, true));
}
}
}
if (conflicts.size() > 0) {
Set<MethodNode> chain = chainMap.get(m);
/* rename the smallest conflict set */
// if(chain.size() < conflicts.size()) {
//
// } else {
// mustRename.add(conflicts);
// }
mustRename.add(chain);
}
}
}
remap.keySet().removeAll(toRemove);
int k = RenamingUtil.numeric("aaaaa");
Map<MethodNode, String> methodNameRemap = new HashMap<>();
for (Set<MethodNode> set : mustRename) {
// MethodNode first = set.iterator().next();
// String newName = "rename_" + first.name;
String newName = RenamingUtil.createName(k++);
System.out.printf(" renaming %s to %s%n", set, newName);
System.out.println(" recom " + computeChain(cxt, set.iterator().next()));
Set<MethodNode> s2 = new HashSet<>();
for (MethodNode m : set) {
s2.addAll(chainMap.get(m));
}
if (!s2.equals(set)) {
System.err.println(set);
System.err.println(s2);
throw new IllegalStateException();
}
for (MethodNode m : set) {
methodNameRemap.put(m, newName);
}
}
if (mustRename.size() > 0) {
MethodRenamerPass.rename(cxt, methodNameRemap, false);
}
Set<MethodNode> visitedMethods = new HashSet<>();
Set<Expr> visitedExprs = new HashSet<>();
int killedTotal = 0;
for (; ; ) {
int killedBeforePass = killedTotal;
for (Entry<MethodNode, String> en : remap.entrySet()) {
MethodNode key = en.getKey();
String newDesc = en.getValue();
if (!visitedMethods.contains(key)) {
Set<MethodNode> chain = chainMap.get(key);
/*for(MethodNode n : chain) {
if(visitedMethods.contains(n)) {
throw new IllegalStateException(String.format("Invalid transistivityr: %s in %s but not %s", n, chain, key));
}
}*/
boolean[] dead = filteredConstantParameters.get(key);
for (MethodNode n : chain) {
n.desc = newDesc;
/* boolean[] dead = filteredConstantParameters.get(n);
boolean[] deadM = filteredConstantParameters.get(key);
if(!Arrays.equals(dead, deadM)) {
throw new IllegalStateException(String.format("neq: %s vs %s for %s and %s", Arrays.toString(dead), Arrays.toString(deadM), n, key));
} */
demoteDeadParamters(constAnalysis, cxt.getIRCache().getFor(n), n, dead);
for (Invocation call : constAnalysis.getCallsTo(n)) {
/* since the callgrapher finds all
* the methods in a hierarchy and considers
* it as a single invocation, a certain
* invocation may be considered multiple times. */
if (visitedExprs.contains(call)) {
continue;
}
/* the invocationexpr method desc is changed implicitly
* when the new expression is created in patchCall() */
visitedExprs.add(call);
patchCall(newDesc, call, dead);
killedTotal += chain.size();
}
}
visitedMethods.addAll(chain);
}
}
if (killedBeforePass == killedTotal) {
break;
}
}
System.out.printf(" removed %d constant parameters.%n", killedTotal);
return killedTotal;
}
use of org.mapleir.app.service.InvocationResolver in project maple-ir by LLVM-but-worse.
the class FieldRenamerPass method accept.
@Override
public int accept(AnalysisContext cxt, IPass prev, List<IPass> completed) {
Map<FieldNode, String> remapped = new HashMap<>();
// int totalFields = 0;
// int i = RenamingUtil.computeMinimum(totalFields);
ApplicationClassSource source = cxt.getApplication();
int i = RenamingUtil.numeric("aaaaa");
for (ClassNode cn : source.iterate()) {
// totalFields += cn.fields.size();
for (FieldNode fn : cn.fields) {
remapped.put(fn, RenamingUtil.createName(i++));
}
}
InvocationResolver resolver = cxt.getInvocationResolver();
for (ClassNode cn : source.iterate()) {
for (MethodNode m : cn.methods) {
ControlFlowGraph cfg = cxt.getIRCache().getFor(m);
for (BasicBlock b : cfg.vertices()) {
for (Stmt stmt : b) {
if (stmt.getOpcode() == Opcode.FIELD_STORE) {
FieldStoreStmt fs = (FieldStoreStmt) stmt;
FieldNode f = resolver.findField(fs.getOwner(), fs.getName(), fs.getDesc(), fs.getInstanceExpression() == null);
if (f != null) {
if (remapped.containsKey(f)) {
fs.setName(remapped.get(f));
} else if (mustMark(source, f.owner.name)) {
System.err.println(" no remap for " + f + ", owner: " + f.owner.name);
}
} else {
if (mustMark(source, fs.getOwner())) {
System.err.println(" can't resolve field(set): " + fs.getOwner() + "." + fs.getName() + " " + fs.getDesc() + ", " + (fs.getInstanceExpression() == null));
}
}
}
for (Expr e : stmt.enumerateOnlyChildren()) {
if (e.getOpcode() == Opcode.FIELD_LOAD) {
FieldLoadExpr fl = (FieldLoadExpr) e;
FieldNode f = resolver.findField(fl.getOwner(), fl.getName(), fl.getDesc(), fl.getInstanceExpression() == null);
if (f != null) {
if (remapped.containsKey(f)) {
fl.setName(remapped.get(f));
} else if (mustMark(source, f.owner.name)) {
System.err.println(" no remap for " + f + ", owner: " + f.owner.name);
}
} else {
if (mustMark(source, fl.getOwner())) {
System.err.println(" can't resolve field(get): " + fl.getOwner() + "." + fl.getName() + " " + fl.getDesc() + ", " + (fl.getInstanceExpression() == null));
}
}
}
}
}
}
}
}
for (Entry<FieldNode, String> e : remapped.entrySet()) {
e.getKey().name = e.getValue();
}
System.out.printf(" Renamed %d fields.%n", remapped.size());
return remapped.size();
}
Aggregations