Skip to content

Commit

Permalink
adapted qilin to the Callgraph API
Browse files Browse the repository at this point in the history
  • Loading branch information
JonasKlauke committed Jul 15, 2024
1 parent 47f0e16 commit c7fcbe9
Show file tree
Hide file tree
Showing 33 changed files with 201 additions and 155 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class Call {
@Nonnull private final MethodSignature targetMethodSignature;
@Nonnull private final InvokableStmt invokableStmt;

Call(
public Call(
@Nonnull MethodSignature sourceMethodSignature,
@Nonnull MethodSignature targetMethodSignature,
@Nonnull InvokableStmt invokableStmt) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import sootup.core.jimple.common.expr.AbstractInvokeExpr;
import sootup.core.jimple.common.expr.JSpecialInvokeExpr;
import sootup.core.jimple.common.expr.JStaticInvokeExpr;
import sootup.core.jimple.common.stmt.InvokableStmt;
import sootup.core.jimple.common.stmt.JAssignStmt;
import sootup.core.jimple.common.stmt.JInvokeStmt;
import sootup.core.jimple.common.stmt.Stmt;
Expand All @@ -54,7 +55,7 @@
public class CallGraphBuilder {
private static final ClassType clRunnable = PTAUtils.getClassType("java.lang.Runnable");
protected final Map<VarNode, Collection<VirtualCallSite>> receiverToSites;
protected final Map<SootMethod, Map<Object, Stmt>> methodToInvokeStmt;
protected final Map<SootMethod, Map<Object, InvokableStmt>> methodToInvokeStmt;
protected final Set<ContextMethod> reachMethods;
private ChunkedQueue<ContextMethod> rmQueue;

Expand Down Expand Up @@ -177,7 +178,11 @@ protected void dispatch(AllocNode receiverNode, VirtualCallSite site) {
}

private void addVirtualEdge(
ContextMethod caller, Stmt callStmt, SootMethod callee, Kind kind, AllocNode receiverNode) {
ContextMethod caller,
InvokableStmt callStmt,
SootMethod callee,
Kind kind,
AllocNode receiverNode) {
Context tgtContext = pta.createCalleeCtx(caller, receiverNode, new CallSite(callStmt), callee);
ContextMethod cstarget = pta.parameterize(callee, tgtContext);
handleCallEdge(new Edge(caller, callStmt, cstarget, kind));
Expand All @@ -187,7 +192,7 @@ private void addVirtualEdge(
}

public void injectCallEdge(Object heapOrType, ContextMethod callee, Kind kind) {
Map<Object, Stmt> stmtMap =
Map<Object, InvokableStmt> stmtMap =
methodToInvokeStmt.computeIfAbsent(callee.method(), k -> DataFactory.createMap());
if (!stmtMap.containsKey(heapOrType)) {
AbstractInvokeExpr ie =
Expand All @@ -203,7 +208,8 @@ public void injectCallEdge(Object heapOrType, ContextMethod callee, Kind kind) {
}
}

public void addStaticEdge(ContextMethod caller, Stmt callStmt, SootMethod calleem, Kind kind) {
public void addStaticEdge(
ContextMethod caller, InvokableStmt callStmt, SootMethod calleem, Kind kind) {
Context typeContext = pta.createCalleeCtx(caller, null, new CallSite(callStmt), calleem);
ContextMethod callee = pta.parameterize(calleem, typeContext);
handleCallEdge(new Edge(caller, callStmt, callee, kind));
Expand Down Expand Up @@ -247,7 +253,7 @@ private void processCallAssign(Edge e) {
MethodNodeFactory srcnf = srcmpag.nodeFactory();
MethodNodeFactory tgtnf = tgtmpag.nodeFactory();
SootMethod tgtmtd = tgtmpag.getMethod();
AbstractInvokeExpr ie = s.getInvokeExpr();
AbstractInvokeExpr ie = s.asInvokableStmt().getInvokeExpr().get();
// add arg --> param edges.
int numArgs = ie.getArgCount();
for (int i = 0; i < numArgs; i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import sootup.core.jimple.common.ref.JParameterRef;
import sootup.core.jimple.common.ref.JStaticFieldRef;
import sootup.core.jimple.common.ref.JThisRef;
import sootup.core.jimple.common.stmt.InvokableStmt;
import sootup.core.jimple.common.stmt.JAssignStmt;
import sootup.core.jimple.common.stmt.JIdentityStmt;
import sootup.core.jimple.common.stmt.JReturnStmt;
Expand Down Expand Up @@ -131,9 +132,9 @@ public Node getNode(Value v) {

/** Adds the edges required for this statement to the graph. */
public final void handleStmt(Stmt s) {
if (s.containsInvokeExpr()) {
mpag.addCallStmt(s);
handleInvokeStmt(s);
if (s.isInvokableStmt() && s.asInvokableStmt().containsInvokeExpr()) {
mpag.addCallStmt(s.asInvokableStmt());
handleInvokeStmt(s.asInvokableStmt());
} else {
handleIntraStmt(s);
}
Expand All @@ -143,8 +144,8 @@ public final void handleStmt(Stmt s) {
* Adds the edges required for this statement to the graph. Add throw stmt if the invoke method
* throws an Exception.
*/
protected void handleInvokeStmt(Stmt s) {
AbstractInvokeExpr ie = s.getInvokeExpr();
protected void handleInvokeStmt(InvokableStmt s) {
AbstractInvokeExpr ie = s.getInvokeExpr().get();
int numArgs = ie.getArgCount();
for (int i = 0; i < numArgs; i++) {
Value arg = ie.getArg(i);
Expand Down
41 changes: 19 additions & 22 deletions sootup.qilin/src/main/java/qilin/core/builder/callgraph/Edge.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,21 @@
import qilin.core.context.Context;
import qilin.core.pag.ContextMethod;
import qilin.util.Invalidable;
import sootup.callgraph.CallGraph;
import sootup.core.jimple.common.expr.AbstractInvokeExpr;
import sootup.core.jimple.common.expr.JInterfaceInvokeExpr;
import sootup.core.jimple.common.expr.JSpecialInvokeExpr;
import sootup.core.jimple.common.expr.JStaticInvokeExpr;
import sootup.core.jimple.common.expr.JVirtualInvokeExpr;
import sootup.core.jimple.common.stmt.Stmt;
import sootup.core.jimple.common.stmt.InvokableStmt;
import sootup.core.model.SootMethod;

/**
* Represents a single edge in a call graph.
*
* @author Ondrej Lhotak
*/
public final class Edge implements Invalidable {
public final class Edge extends CallGraph.Call implements Invalidable {

/**
* The method in which the call occurs; may be null for calls not occurring in a specific method
Expand All @@ -27,12 +28,6 @@ public final class Edge implements Invalidable {
/** The target method of the call edge. */
private ContextMethod tgt;

/**
* The unit at which the call occurs; may be null for calls not occurring at a specific statement
* (eg. calls in native code)
*/
private Stmt srcUnit;

/**
* The kind of edge. Note: kind should not be tested by other classes; instead, accessors such as
* isExplicit() should be added.
Expand All @@ -41,17 +36,17 @@ public final class Edge implements Invalidable {

private boolean invalid = false;

public Edge(ContextMethod src, Stmt srcUnit, ContextMethod tgt, Kind kind) {
public Edge(ContextMethod src, InvokableStmt srcUnit, ContextMethod tgt, Kind kind) {
super(src.method().getSignature(), tgt.method().getSignature(), srcUnit);
this.src = src;
this.srcUnit = srcUnit;
this.tgt = tgt;
this.kind = kind;
}

public Edge(ContextMethod src, Stmt srcUnit, ContextMethod tgt) {
this.kind = ieToKind(srcUnit.getInvokeExpr());
public Edge(ContextMethod src, InvokableStmt srcUnit, ContextMethod tgt) {
super(src.method().getSignature(), tgt.method().getSignature(), srcUnit);
this.kind = ieToKind(srcUnit.getInvokeExpr().get());
this.src = src;
this.srcUnit = srcUnit;
this.tgt = tgt;
}

Expand All @@ -67,12 +62,12 @@ public ContextMethod getSrc() {
return src;
}

public Stmt srcUnit() {
return srcUnit;
public InvokableStmt srcUnit() {
return getInvokableStmt();
}

public Stmt srcStmt() {
return srcUnit;
public InvokableStmt srcStmt() {
return getInvokableStmt();
}

public SootMethod tgt() {
Expand Down Expand Up @@ -150,7 +145,6 @@ public boolean isInvalid() {
public void invalidate() {
// Since the edge remains in the QueueReaders for a while, the GC could not claim old units.
src = null;
srcUnit = null;
tgt = null;
invalid = true;
}
Expand All @@ -164,8 +158,8 @@ public int hashCode() {
if (src != null) {
ret = ret * 32 + src.hashCode();
}
if (srcUnit != null) {
ret = ret * 32 + srcUnit.hashCode();
if (getInvokableStmt() != null) {
ret = ret * 32 + getInvokableStmt().hashCode();
}
return ret;
}
Expand All @@ -176,12 +170,15 @@ public boolean equals(Object other) {
return false;
}
Edge o = (Edge) other;
return (o.src == this.src) && (o.srcUnit == srcUnit) && (o.tgt == tgt) && (o.kind == kind);
return (o.src == this.src)
&& (o.srcStmt() == this.srcStmt())
&& (o.tgt == tgt)
&& (o.kind == kind);
}

@Override
public String toString() {
return this.kind + " edge: " + srcUnit + " in " + src + " ==> " + tgt;
return this.kind + " edge: " + srcStmt() + " in " + src + " ==> " + tgt;
}

private Edge nextByUnit = this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,17 @@
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import qilin.core.pag.ContextMethod;
import qilin.util.DataFactory;
import qilin.util.queue.ChunkedQueue;
import qilin.util.queue.QueueReader;
import sootup.callgraph.MutableCallGraph;
import sootup.core.jimple.common.stmt.InvokableStmt;
import sootup.core.jimple.common.stmt.Stmt;
import sootup.core.model.SootMethod;
import sootup.core.signatures.MethodSignature;
Expand All @@ -49,7 +52,7 @@
*/
public class OnFlyCallGraph implements MutableCallGraph, Iterable<Edge> {
protected Set<MethodSignature> methods = DataFactory.createSet();
protected Map<MethodSignature, Set<MethodSignature>> calls = DataFactory.createMap();
protected Map<MethodSignature, Set<Call>> calls = DataFactory.createMap();
protected int callCnt = 0;

protected Set<Edge> edges = new LinkedHashSet<>();
Expand All @@ -69,7 +72,7 @@ public boolean addEdge(Edge e) {
MethodSignature tgtSig = e.getTgt().method().getSignature();
addMethod(srcSig);
addMethod(tgtSig);
addCall(srcSig, tgtSig);
addCall(srcSig, tgtSig, e.srcStmt());
stream.add(e);

Edge position = srcUnitToEdge.get(e.srcUnit());
Expand Down Expand Up @@ -129,7 +132,7 @@ public boolean removeAllEdgesOutOf(Stmt u) {
* @param in The new statement
* @return True if at least one edge was affected by this operation
*/
public boolean swapEdgesOutOf(Stmt out, Stmt in) {
public boolean swapEdgesOutOf(InvokableStmt out, InvokableStmt in) {
boolean hasSwapped = false;
for (Iterator<Edge> edgeRdr = edgesOutOf(out); edgeRdr.hasNext(); ) {
Edge e = edgeRdr.next();
Expand Down Expand Up @@ -166,7 +169,7 @@ public boolean removeEdge(Edge e, boolean removeInEdgeList) {
}
MethodSignature srcSig = e.getSrc().method().getSignature();
MethodSignature tgtSig = e.getTgt().method().getSignature();
Set<MethodSignature> tgtSigs = calls.getOrDefault(srcSig, Collections.emptySet());
Set<Call> tgtSigs = calls.getOrDefault(srcSig, Collections.emptySet());
assert (!tgtSigs.isEmpty());
tgtSigs.remove(tgtSig);
// !FIXME only edge is removed. I do not remove the added nodes.
Expand Down Expand Up @@ -430,10 +433,11 @@ public void addMethod(@Nonnull MethodSignature calledMethod) {

@Override
public void addCall(
@Nonnull MethodSignature sourceMethod, @Nonnull MethodSignature targetMethod) {
Set<MethodSignature> targets =
this.calls.computeIfAbsent(sourceMethod, k -> DataFactory.createSet());
if (targets.add(targetMethod)) {
@Nonnull MethodSignature sourceMethod,
@Nonnull MethodSignature targetMethod,
@Nonnull InvokableStmt stmt) {
Set<Call> targets = this.calls.computeIfAbsent(sourceMethod, k -> DataFactory.createSet());
if (targets.add(new Call(sourceMethod, targetMethod, stmt))) {
++callCnt;
}
}
Expand All @@ -457,9 +461,16 @@ public boolean containsMethod(@Nonnull MethodSignature method) {

@Override
public boolean containsCall(
@Nonnull MethodSignature sourceMethod, @Nonnull MethodSignature targetMethod) {
if (this.calls.containsKey(sourceMethod)) {
if (this.calls.get(sourceMethod).contains(targetMethod)) {
@Nonnull MethodSignature sourceMethod,
@Nonnull MethodSignature targetMethod,
InvokableStmt stmt) {
return containsCall(new Call(sourceMethod, targetMethod, stmt));
}

@Override
public boolean containsCall(@Nonnull Call call) {
if (this.calls.containsKey(call.getSourceMethodSignature())) {
if (this.calls.get(call.getSourceMethodSignature()).contains(call)) {
return true;
}
}
Expand All @@ -478,13 +489,35 @@ public String exportAsDot() {

@Nonnull
@Override
public Set<MethodSignature> callsFrom(@Nonnull MethodSignature sourceMethod) {
public Set<Call> callsFrom(@Nonnull MethodSignature sourceMethod) {
return this.calls.getOrDefault(sourceMethod, Collections.emptySet());
}

@Nonnull
@Override
public Set<MethodSignature> callsTo(@Nonnull MethodSignature targetMethod) {
public Set<Call> callsTo(@Nonnull MethodSignature targetMethod) {
throw new UnsupportedOperationException();
}

@Nonnull
@Override
public Set<MethodSignature> callTargetsFrom(@Nonnull MethodSignature sourceMethod) {
return callsFrom(sourceMethod).stream()
.map(call -> call.getTargetMethodSignature())
.collect(Collectors.toSet());
}

@Nonnull
@Override
public Set<MethodSignature> callSourcesTo(@Nonnull MethodSignature targetMethod) {
return callsTo(targetMethod).stream()
.map(call -> call.getSourceMethodSignature())
.collect(Collectors.toSet());
}

// TODO: implement me
@Override
public List<MethodSignature> getEntryMethods() {
return Collections.emptyList();
}
}
8 changes: 4 additions & 4 deletions sootup.qilin/src/main/java/qilin/core/pag/CallSite.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,18 @@
package qilin.core.pag;

import qilin.core.context.ContextElement;
import sootup.core.jimple.common.stmt.Stmt;
import sootup.core.jimple.common.stmt.InvokableStmt;

/** callsite based context element in the points to analysis. */
public class CallSite implements ContextElement {

private final Stmt unit;
private final InvokableStmt unit;

public CallSite(Stmt unit) {
public CallSite(InvokableStmt unit) {
this.unit = unit;
}

public Stmt getUnit() {
public InvokableStmt getUnit() {
return unit;
}

Expand Down
7 changes: 4 additions & 3 deletions sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import sootup.core.jimple.Jimple;
import sootup.core.jimple.basic.Trap;
import sootup.core.jimple.common.ref.JStaticFieldRef;
import sootup.core.jimple.common.stmt.InvokableStmt;
import sootup.core.jimple.common.stmt.Stmt;
import sootup.core.model.Body;
import sootup.core.model.SootClass;
Expand All @@ -44,7 +45,7 @@ public class MethodPAG {
private final ChunkedQueue<Node> internalEdges = new ChunkedQueue<>();
private final QueueReader<Node> internalReader = internalEdges.reader();
private final Set<SootMethod> clinits = DataFactory.createSet();
private final Collection<Stmt> invokeStmts = DataFactory.createSet();
private final Collection<InvokableStmt> invokeStmts = DataFactory.createSet();
public Body body;

/**
Expand Down Expand Up @@ -81,11 +82,11 @@ public MethodNodeFactory nodeFactory() {
return nodeFactory;
}

public Collection<Stmt> getInvokeStmts() {
public Collection<InvokableStmt> getInvokeStmts() {
return invokeStmts;
}

public boolean addCallStmt(Stmt unit) {
public boolean addCallStmt(InvokableStmt unit) {
return this.invokeStmts.add(unit);
}

Expand Down
Loading

0 comments on commit c7fcbe9

Please sign in to comment.