/**
*
*/
package soottocfg.soot.util;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import com.google.common.base.Preconditions;
import com.google.common.base.Verify;
import soot.ArrayType;
import soot.Modifier;
import soot.PrimType;
import soot.RefType;
import soot.Scene;
import soot.SootClass;
import soot.SootField;
import soot.SootMethod;
import soot.Type;
import soot.Unit;
import soot.Value;
import soot.VoidType;
import soot.jimple.ClassConstant;
import soot.jimple.DoubleConstant;
import soot.jimple.FloatConstant;
import soot.jimple.IntConstant;
import soot.jimple.InvokeStmt;
import soot.jimple.Jimple;
import soot.jimple.LongConstant;
import soot.jimple.NullConstant;
import soot.jimple.Stmt;
import soot.tagkit.AbstractHost;
import soot.tagkit.Host;
import soot.tagkit.SourceFileTag;
import soot.tagkit.Tag;
import soottocfg.Options;
import soottocfg.cfg.Program;
import soottocfg.cfg.SourceLocation;
import soottocfg.cfg.expression.BinaryExpression;
import soottocfg.cfg.expression.BinaryExpression.BinaryOperator;
import soottocfg.cfg.expression.Expression;
import soottocfg.cfg.expression.IdentifierExpression;
import soottocfg.cfg.expression.TupleAccessExpression;
import soottocfg.cfg.method.Method;
import soottocfg.cfg.statement.Statement;
import soottocfg.cfg.type.ReferenceType;
import soottocfg.cfg.variable.ClassVariable;
import soottocfg.cfg.variable.Variable;
import soottocfg.soot.SootRunner;
import soottocfg.soot.SootToCfg.MemModel;
import soottocfg.soot.memory_model.MemoryModel;
import soottocfg.soot.memory_model.NewMemoryModel;
/**
* @author schaef
*
*/
public enum SootTranslationHelpers {
INSTANCE;
public static SootTranslationHelpers v() {
Preconditions.checkArgument(initialized, "Call SootTranslationHelpers.initialize first!");
return INSTANCE;
}
public static final String HavocClassName = "Havoc_Class";
public static final String HavocMethodName = "havoc_";
private static boolean initialized = false;
/**
* Get a method that returns an unknown value of type t.
*
* @param t
* @return
*/
public SootMethod getHavocMethod(soot.Type t) {
if (!Scene.v().containsClass(HavocClassName)) {
SootClass sClass = new SootClass(HavocClassName, Modifier.PUBLIC | Modifier.PUBLIC);
sClass.setSuperclass(Scene.v().getSootClass("java.lang.Object"));
sClass.setResolvingLevel(SootClass.SIGNATURES);
Scene.v().addClass(sClass);
}
SootClass cls = Scene.v().getSootClass(HavocClassName);
final String havocMethodName = HavocMethodName + t.toString();
if (!cls.declaresMethodByName(havocMethodName)) {
cls.addMethod(new SootMethod(havocMethodName, Arrays.asList(new Type[] {}), t,
Modifier.PUBLIC | Modifier.STATIC));
}
return cls.getMethodByName("havoc_" + t.toString());
}
public static void initialize(Program program) {
initialized = true;
INSTANCE.reset();
INSTANCE.setProgram(program);
INSTANCE.setMemoryModelKind(Options.v().memModel());
}
private static final String parameterPrefix = "$in_";
// public static final String typeFieldName = "$dynamicType";
public static final String arrayElementTypeFieldName = "$elType";
public static final String lengthFieldName = "$length";
// public static final String indexFieldNamePrefix = "$idx_";
private transient SootMethod currentMethod;
// private transient SootClass currentClass;
private transient String currentSourceFileName;
private transient MemoryModel memoryModel;
private MemModel memoryModelKind = MemModel.PullPush;
private transient Program program;
public void reset() {
currentMethod = null;
currentSourceFileName = null;
memoryModel = null;
program = null;
writtenOnceFields = null;
}
private Set<SootField> writtenOnceFields;
public boolean isWrittenOnce(SootField f) {
if (writtenOnceFields==null) {
writtenOnceFields = WriteOnceFieldCollector.getWriteOnceInstanceFields();
}
return writtenOnceFields.contains(f);
}
public static List<SootField> findFieldsRecursivelyForRef(Value v) {
return findFieldsRecursively(((RefType) v.getType()).getSootClass());
}
public static List<SootField> findFieldsRecursively(SootClass sc) {
List<SootField> res = new LinkedList<SootField>();
if (sc.hasSuperclass() && sc.getSuperclass().resolvingLevel() > SootClass.DANGLING) {
res.addAll(findFieldsRecursively(sc.getSuperclass()));
}
res.addAll(sc.getFields());
return res;
}
public static List<SootField> findNonStaticFieldsRecursivelyForRef(Value v) {
return findNonStaticFieldsRecursively(((RefType) v.getType()).getSootClass());
}
public static List<SootField> findNonStaticFieldsRecursively(SootClass sc) {
List<SootField> res = new LinkedList<SootField>();
for (SootField sf : findFieldsRecursively(sc)) {
if (!sf.isStatic()) {
res.add(sf);
}
}
return res;
}
public static BinaryExpression createInstanceOfExpression(SourceLocation loc, Variable v, ClassVariable typ) {
Expression lhs = new TupleAccessExpression(loc, v, ReferenceType.TypeFieldName);
return createInstanceOfExpression(lhs, typ);
}
public static BinaryExpression createInstanceOfExpression(Expression lhs, ClassVariable typ) {
SourceLocation loc = lhs.getSourceLocation();
return new BinaryExpression(loc, BinaryOperator.PoLeq, lhs, new IdentifierExpression(loc, typ));
}
public Value getDefaultValue(soot.Type t) {
Value rhs = null;
if (t instanceof PrimType) {
if (t instanceof soot.BooleanType) {
rhs = IntConstant.v(0);
} else if (t instanceof soot.ByteType) {
rhs = IntConstant.v(0);
} else if (t instanceof soot.CharType) {
rhs = IntConstant.v(0);
} else if (t instanceof soot.DoubleType) {
rhs = DoubleConstant.v(0);
} else if (t instanceof soot.FloatType) {
rhs = FloatConstant.v(0);
} else if (t instanceof soot.IntType) {
rhs = IntConstant.v(0);
} else if (t instanceof soot.LongType) {
rhs = LongConstant.v(0);
} else if (t instanceof soot.ShortType) {
rhs = IntConstant.v(0);
} else {
throw new RuntimeException("Unknown type " + t);
}
} else {
rhs = NullConstant.v();
}
return rhs;
}
public ClassVariable getClassVariable(SootClass sc) {
return memoryModel.lookupClassVariable(getClassConstant(sc.getType()));
}
public ClassVariable getClassVariable(Type t) {
return getClassVariable(((RefType)t).getSootClass());
}
public ClassConstant getClassConstant(Type t) {
if (t instanceof RefType) {
final String className = ((RefType) t).getClassName().replace(".", "/");
return ClassConstant.v(className);
} else if (t instanceof ArrayType) {
// final String className =
// getFakeArrayClass((ArrayType)t).getName().replace(".", "/");
// return ClassConstant.v(className);
throw new RuntimeException("Remove Arrays first! " + t);
} else if (t instanceof PrimType) {
final String className = ((PrimType) t).toString();
return ClassConstant.v(className);
}
throw new RuntimeException("Not implemented");
}
public Method lookupOrCreateMethod(SootMethod m) {
if (this.program.lookupMethod(m.getSignature()) != null) {
return this.program.lookupMethod(m.getSignature());
}
int parameterCount = 0;
final List<Variable> parameterList = new LinkedList<Variable>();
if (!m.isStatic()) {
parameterList.add(new Variable(parameterPrefix + (parameterCount++),
getMemoryModel().lookupType(m.getDeclaringClass().getType())));
}
// if (Options.v().passCallerIdIntoMethods()) {
// parameterList.add(new Variable(parameterPrefix + (parameterCount++),
// IntType.instance()));
// }
for (int i = 0; i < m.getParameterCount(); i++) {
parameterList.add(new Variable(parameterPrefix + (parameterCount++),
getMemoryModel().lookupType(m.getParameterType(i))));
}
List<soottocfg.cfg.type.Type> outVarTypes = new LinkedList<soottocfg.cfg.type.Type>();
if (!m.getReturnType().equals(VoidType.v())) {
Verify.verifyNotNull(memoryModel);
outVarTypes.add(memoryModel.lookupType(m.getReturnType()));
} else if (m.isConstructor()) {
/*
* For constructors, we assume that they return all fields
* that are assigned in this constructor
*/
for (SootField sf : SootTranslationHelpers.findNonStaticFieldsRecursively(m.getDeclaringClass())) {
outVarTypes.add(memoryModel.lookupType(sf.getType()));
}
// ClassVariable cv = ((ReferenceType) memoryModel.lookupType(m.getDeclaringClass().getType()))
// .getClassVariable();
// for (Variable fieldVar : cv.getAssociatedFields()) {
// outVarTypes.add(fieldVar.getType());
// }
}
return Method.createMethodInProgram(program, m.getSignature(), parameterList, outVarTypes,
SootTranslationHelpers.v().getSourceLocation(m));
}
public Stmt getDefaultReturnStatement(Type returnType, Host createdFrom) {
Stmt stmt;
if (returnType instanceof VoidType) {
stmt = Jimple.v().newReturnVoidStmt();
} else {
stmt = Jimple.v().newReturnStmt(getDefaultValue(returnType));
}
stmt.addAllTagsOf(createdFrom);
return stmt;
}
void setProgram(Program p) {
this.program = p;
}
public Program getProgram() {
return this.program;
}
public SootClass getAssertionClass() {
return Scene.v().getSootClass(SootRunner.assertionClassName);
}
public SootMethod getAssertMethod() {
SootClass assertionClass = Scene.v().getSootClass(SootRunner.assertionClassName);
return assertionClass.getMethodByName(SootRunner.assertionProcedureName);
}
public SootField getExceptionGlobal() {
SootClass assertionClass = Scene.v().getSootClass(SootRunner.assertionClassName);
return assertionClass.getFieldByName(SootRunner.exceptionGlobalName);
}
public Value getExceptionGlobalRef() {
return Jimple.v().newStaticFieldRef(getExceptionGlobal().makeRef());
}
public Unit makeAssertion(Value cond, Host createdFrom) {
List<Value> args = new LinkedList<Value>();
args.add(cond);
InvokeStmt stmt = Jimple.v().newInvokeStmt(Jimple.v().newStaticInvokeExpr(getAssertMethod().makeRef(), args));
stmt.addAllTagsOf(createdFrom);
return stmt;
}
public SourceLocation getSourceLocation(Unit u) {
int lineNumber = u.getJavaSourceStartLineNumber();
if (lineNumber < 0) {
lineNumber = SootTranslationHelpers.v().getJavaSourceLine(SootTranslationHelpers.v().getCurrentMethod());
}
return new SourceLocation(this.currentSourceFileName, lineNumber);
}
public SourceLocation getSourceLocation(SootMethod sm) {
int lineNumber = sm.getJavaSourceStartLineNumber();
if (lineNumber < 0) {
lineNumber = SootTranslationHelpers.v().getJavaSourceLine(SootTranslationHelpers.v().getCurrentMethod());
}
return new SourceLocation(this.currentSourceFileName, lineNumber);
}
void setMemoryModelKind(MemModel kind) {
memoryModelKind = kind;
getMemoryModel();
}
public MemoryModel getMemoryModel() {
if (this.memoryModel == null) {
// TODO:
if (memoryModelKind == MemModel.PullPush) {
this.memoryModel = new NewMemoryModel();
} else {
throw new RuntimeException("Unknown memory model");
}
}
return this.memoryModel;
}
public void setCurrentClass(SootClass currentClass) {
String fn = findFileName(currentClass.getTags());
if (fn != null) {
this.currentSourceFileName = fn;
}
// this.currentClass = currentClass;
}
private String findFileName(List<Tag> tags) {
String fileName = null;
for (Tag tag : tags) {
if (tag instanceof SourceFileTag) {
SourceFileTag t = (SourceFileTag) tag;
if (t.getAbsolutePath() != null) {
fileName = t.getAbsolutePath();
} else {
if (t.getSourceFile() != null) {
fileName = t.getSourceFile();
}
}
} else {
// System.err.println("Unprocessed tag " + tag.getClass() + " -
// " + tag);
}
}
return fileName;
}
public SootMethod getCurrentMethod() {
return currentMethod;
}
public void setCurrentMethod(SootMethod currentMethod) {
String fn = findFileName(currentMethod.getTags());
if (fn != null) {
this.currentSourceFileName = fn;
}
this.currentMethod = currentMethod;
}
public String getCurrentSourceFileName() {
return this.currentSourceFileName;
}
public int getJavaSourceLine(AbstractHost ah) {
return ah.getJavaSourceStartLineNumber();
}
// public int getUniqueNumberForUnit(Unit u) {
// return u.hashCode();
// }
//
// public int getUniqueNumberForUnit(Statement s) {
// return s.hashCode();
// }
}