protected Value marshalObjectToNative( Function fn, MarshalerMethod marshalerMethod, MarshaledArg marshaledArg, Type nativeType, Value env, Value object, long flags) { Invokestatic invokestatic = marshalerMethod.getInvokeStatic(sootMethod.getDeclaringClass()); trampolines.add(invokestatic); Value handle = call(fn, invokestatic.getFunctionRef(), env, object, new IntegerConstant(flags)); Variable nativeValue = fn.newVariable(nativeType); if (nativeType instanceof StructureType || nativeType instanceof ArrayType) { Variable tmp = fn.newVariable(new PointerType(nativeType)); fn.add(new Inttoptr(tmp, handle, tmp.getType())); fn.add(new Load(nativeValue, tmp.ref())); } else { fn.add(new Inttoptr(nativeValue, handle, nativeType)); } if (marshaledArg != null) { marshaledArg.handle = handle; marshaledArg.object = object; } return nativeValue.ref(); }
private Function createAllocator() { Function fn = FunctionBuilder.allocator(sootClass); Value info = getInfoStruct(fn); Value result = call(fn, BC_ALLOCATE, fn.getParameterRef(0), info); fn.add(new Ret(result)); return fn; }
private Function createInstanceof() { Function fn = FunctionBuilder.instanceOf(sootClass); Value info = getInfoStruct(fn); Value result = call(fn, BC_INSTANCEOF, fn.getParameterRef(0), info, fn.getParameterRef(1)); fn.add(new Ret(result)); return fn; }
private Function createCheckcast() { Function fn = FunctionBuilder.checkcast(sootClass); Value info = getInfoStruct(fn); Value result = call(fn, BC_CHECKCAST, fn.getParameterRef(0), info, fn.getParameterRef(1)); fn.add(new Ret(result)); return fn; }
protected Value marshalNativeToArray( Function fn, MarshalerMethod marshalerMethod, Value env, String arrayClassName, Value nativeValue, long flags, int[] dimensions) { Invokestatic invokeToObject = marshalerMethod.getInvokeStatic(sootMethod.getDeclaringClass()); trampolines.add(invokeToObject); Variable handle = fn.newVariable(I64); fn.add(new Ptrtoint(handle, nativeValue, I64)); Value valueClass = ldcClass(fn, arrayClassName, env); List<Value> args = new ArrayList<>(); args.add(env); args.add(valueClass); args.add(handle.ref()); args.add(new IntegerConstant(flags)); args.addAll(arrayDimensionsValues(dimensions)); return call(fn, invokeToObject.getFunctionRef(), args); }
private Function createLdcClassWrapper() { Function fn = FunctionBuilder.ldcExternal(sootClass); Value info = getInfoStruct(fn); Value result = call(fn, LDC_CLASS_WRAPPER, fn.getParameterRef(0), info); fn.add(new Ret(result)); return fn; }
protected Value marshalDoubleToMachineSizedFloat(Function fn, Value value) { if (config.getArch().is32Bit()) { Variable result = fn.newVariable(FLOAT); fn.add(new Fptrunc(result, value, FLOAT)); return result.ref(); } else { return value; } }
protected Value marshalMachineSizedUIntToLong(Function fn, Value value) { if (config.getArch().is32Bit()) { Variable result = fn.newVariable(I64); fn.add(new Zext(result, value, I64)); return result.ref(); } else { return value; } }
protected Value marshalFloatToMachineSizedFloat(Function fn, Value value) { if (!config.getArch().is32Bit()) { Variable result = fn.newVariable(DOUBLE); fn.add(new Fpext(result, value, DOUBLE)); return result.ref(); } else { return value; } }
protected Value marshalLongToMachineSizedInt(Function fn, Value value) { if (config.getArch().is32Bit()) { Variable result = fn.newVariable(I32); fn.add(new Trunc(result, value, I32)); return result.ref(); } else { return value; } }
private Value getClassFieldPtr(Function f, SootField field) { Value info = getInfoStruct(f); Variable base = f.newVariable(I8_PTR); f.add(new Load(base, info)); return getFieldPtr( f, new VariableRef(base), offsetof(classType, 1, classFields.indexOf(field), 1), getType(field.getType())); }
private Function createFieldSetter(SootField field) { Function fn = FunctionBuilder.setter(field); Value fieldPtr = null; Value value = null; if (field.isStatic()) { fieldPtr = getClassFieldPtr(fn, field); value = fn.getParameterRef(1); } else { fieldPtr = getInstanceFieldPtr(fn, fn.getParameterRef(1), field); value = fn.getParameterRef(2); } if (Modifier.isVolatile(field.getModifiers()) || !field.isStatic() && Modifier.isFinal(field.getModifiers())) { if (LongType.v().equals(field.getType())) { fn.add(new Store(value, fieldPtr, false, Ordering.unordered, 8)); } else { fn.add(new Store(value, fieldPtr)); } fn.add(new Fence(Ordering.seq_cst)); } else { fn.add(new Store(value, fieldPtr)); } fn.add(new Ret()); return fn; }
protected Value ldcClass(Function fn, String name, Value env) { if (isArray(name) && isPrimitiveBaseType(name)) { String primitiveDesc = name.substring(name.length() - 1); Variable result = fn.newVariable(OBJECT_PTR); fn.add( new Load( result, new ConstantBitcast( new GlobalRef("array_" + primitiveDesc, CLASS_PTR), new PointerType(OBJECT_PTR)))); return result.ref(); } else { FunctionRef ldcClassFn = null; if (name.equals(this.className)) { ldcClassFn = FunctionBuilder.ldcInternal(this.className).ref(); } else { Trampoline trampoline = new LdcClass(this.className, name); trampolines.add(trampoline); ldcClassFn = trampoline.getFunctionRef(); } return call(fn, ldcClassFn, env); } }
protected Value marshalNativeToObject( Function fn, MarshalerMethod marshalerMethod, MarshaledArg marshaledArg, Value env, String valueClassName, Value nativeValue, long flags) { if (nativeValue.getType() instanceof StructureType) { nativeValue = createStackCopy(fn, nativeValue); } Invokestatic invokestatic = marshalerMethod.getInvokeStatic(sootMethod.getDeclaringClass()); trampolines.add(invokestatic); Value valueClass = ldcClass(fn, valueClassName, env); Variable handle = fn.newVariable(I64); fn.add(new Ptrtoint(handle, nativeValue, I64)); Value object = call( fn, invokestatic.getFunctionRef(), env, valueClass, handle.ref(), new IntegerConstant(flags)); if (marshaledArg != null) { marshaledArg.handle = handle.ref(); marshaledArg.object = object; } return object; }
public static Value getFieldPtr(Function f, Value base, Constant offset, Type fieldType) { Variable baseI8Ptr = f.newVariable(I8_PTR); f.add(new Bitcast(baseI8Ptr, base, I8_PTR)); Variable fieldI8Ptr = f.newVariable(I8_PTR); f.add(new Getelementptr(fieldI8Ptr, baseI8Ptr.ref(), offset)); Variable fieldPtr = f.newVariable(new PointerType(fieldType)); f.add(new Bitcast(fieldPtr, fieldI8Ptr.ref(), fieldPtr.getType())); return fieldPtr.ref(); }
protected void marshalArrayToNative( Function fn, MarshalerMethod marshalerMethod, Value env, Value object, Value destPtr, long flags, int[] dimensions) { Invokestatic invokestatic = marshalerMethod.getInvokeStatic(sootMethod.getDeclaringClass()); trampolines.add(invokestatic); Variable handle = fn.newVariable(I64); fn.add(new Ptrtoint(handle, destPtr, I64)); List<Value> args = new ArrayList<>(); args.add(env); args.add(object); args.add(handle.ref()); args.add(new IntegerConstant(flags)); args.addAll(arrayDimensionsValues(dimensions)); call(fn, invokestatic.getFunctionRef(), args); }
protected void storeValueForSetter( SootMethod method, Function function, Type memberType, Value memberPtr, Value env, Value value, long flags) { soot.Type type = method.getParameterType(0); if (needsMarshaler(type)) { MarshalerMethod marshalerMethod = config.getMarshalerLookup().findMarshalerMethod(new MarshalSite(method, 0)); if (memberType instanceof PrimitiveType) { value = marshalValueObjectToNative(function, marshalerMethod, memberType, env, value, flags); } else { if (memberType instanceof StructureType || memberType instanceof ArrayType) { // The parameter must not be null. We assume that Structs // never have a NULL handle so we just check that the Java // Object isn't null. call(function, CHECK_NULL, env, value); } if (memberType instanceof ArrayType) { // Array marshalArrayToNative( function, marshalerMethod, env, value, memberPtr, flags, getArrayDimensions(method, 0)); value = null; } else { value = marshalObjectToNative(function, marshalerMethod, null, memberType, env, value, flags); } } } else { value = marshalPrimitiveToNative(function, method, 0, value); } if (value != null) { function.add(new Store(value, memberPtr)); } }
private Function createFieldGetter(SootField field) { Function fn = FunctionBuilder.getter(field); Value fieldPtr = null; if (field.isStatic()) { fieldPtr = getClassFieldPtr(fn, field); } else { fieldPtr = getInstanceFieldPtr(fn, fn.getParameterRef(1), field); } Variable result = fn.newVariable(getType(field.getType())); if (Modifier.isVolatile(field.getModifiers())) { fn.add(new Fence(Ordering.seq_cst)); if (LongType.v().equals(field.getType())) { fn.add(new Load(result, fieldPtr, false, Ordering.unordered, 8)); } else { fn.add(new Load(result, fieldPtr)); } } else { fn.add(new Load(result, fieldPtr)); } fn.add(new Ret(new VariableRef(result))); return fn; }
protected Value createStackCopy(Function fn, Value value) { Variable stackCopy = fn.newVariable(new PointerType(value.getType())); fn.add(new Alloca(stackCopy, value.getType())); fn.add(new Store(value, stackCopy.ref())); return stackCopy.ref(); }
protected Value marshalPointerToLong(Function fn, Value pointer) { Variable result = fn.newVariable(I64); fn.add(new Ptrtoint(result, pointer, I64)); return result.ref(); }
private void createLookupFunction(SootMethod m) { // TODO: This should use a virtual method table or interface method table. Function function = FunctionBuilder.lookup(m); mb.addFunction(function); Variable reserved0 = function.newVariable(I8_PTR_PTR); function.add(new Getelementptr(reserved0, function.getParameterRef(0), 0, 4)); Variable reserved1 = function.newVariable(I8_PTR_PTR); function.add(new Getelementptr(reserved1, function.getParameterRef(0), 0, 5)); function.add(new Store(getString(m.getName()), reserved0.ref())); function.add(new Store(getString(getDescriptor(m)), reserved1.ref())); Value lookupFn = sootClass.isInterface() ? BC_LOOKUP_INTERFACE_METHOD : BC_LOOKUP_VIRTUAL_METHOD; List<Value> args = new ArrayList<Value>(); args.add(function.getParameterRef(0)); if (sootClass.isInterface()) { Value info = getInfoStruct(function); args.add(info); } args.add(function.getParameterRef(1)); args.add(getString(m.getName())); args.add(getString(getDescriptor(m))); Value fptr = call(function, lookupFn, args); Variable f = function.newVariable(function.getType()); function.add(new Bitcast(f, fptr, f.getType())); Value result = call(function, f.ref(), function.getParameterRefs()); function.add(new Ret(result)); }
private void compile(Clazz clazz, OutputStream out) throws IOException { sootClass = clazz.getSootClass(); mb = new ModuleBuilder(); trampolines = new HashSet<Trampoline>(); catches = new HashSet<String>(); classFields = getClassFields(sootClass); instanceFields = getInstanceFields(sootClass); classType = getClassType(sootClass); instanceType = getInstanceType(sootClass); attributesEncoder.encode(mb, sootClass); // Add a <clinit> method if the class has ConstantValueTags but no <clinit>. // This has to be done before createInfoStruct() is called otherwise the // ClassInfoHeader->initializer value will become NULL and constant static fields // will never be initialized. if (!sootClass.declaresMethodByName("<clinit>") && hasConstantValueTags(classFields)) { SootMethod clinit = new SootMethod("<clinit>", Collections.EMPTY_LIST, VoidType.v(), Modifier.STATIC); JimpleBody body = Jimple.v().newBody(clinit); clinit.setActiveBody(body); body.getUnits().add(new JReturnVoidStmt()); this.sootClass.addMethod(clinit); } if (isStruct(sootClass)) { if (!Modifier.isFinal(sootClass.getModifiers())) { throw new IllegalArgumentException("Struct class must be final"); } SootMethod _sizeOf = new SootMethod("_sizeOf", Collections.EMPTY_LIST, IntType.v(), Modifier.PROTECTED); sootClass.addMethod(_sizeOf); SootMethod sizeOf = new SootMethod( "sizeOf", Collections.EMPTY_LIST, IntType.v(), Modifier.PUBLIC | Modifier.STATIC); sootClass.addMethod(sizeOf); } mb.addInclude( getClass() .getClassLoader() .getResource( String.format("header-%s-%s.ll", config.getOs().getFamily(), config.getArch()))); mb.addInclude(getClass().getClassLoader().getResource("header.ll")); mb.addFunction(createInstanceof()); mb.addFunction(createCheckcast()); mb.addFunction(createLdcClass()); mb.addFunction(createLdcClassWrapper()); Function allocator = createAllocator(); mb.addFunction(allocator); mb.addFunction(createClassInitWrapperFunction(allocator.ref())); for (SootField f : sootClass.getFields()) { Function getter = createFieldGetter(f); Function setter = createFieldSetter(f); mb.addFunction(getter); mb.addFunction(setter); if (f.isStatic() && !f.isPrivate()) { mb.addFunction(createClassInitWrapperFunction(getter.ref())); if (!f.isFinal()) { mb.addFunction(createClassInitWrapperFunction(setter.ref())); } } } for (SootMethod method : sootClass.getMethods()) { String name = method.getName(); if (isBridge(method)) { bridgeMethod(method); } else if (isStruct(sootClass) && ("_sizeOf".equals(name) || "sizeOf".equals(name) || isStructMember(method))) { structMember(method); } else if (method.isNative()) { nativeMethod(method); } else if (!method.isAbstract()) { method(method); } if (!name.equals("<clinit>") && !name.equals("<init>") && !method.isPrivate() && !method.isStatic() && !Modifier.isFinal(method.getModifiers()) && !Modifier.isFinal(sootClass.getModifiers())) { createLookupFunction(method); } if (method.isStatic()) { String fnName = mangleMethod(method); if (method.isSynchronized()) { fnName += "_synchronized"; } FunctionRef fn = new FunctionRef(fnName, getFunctionType(method)); mb.addFunction(createClassInitWrapperFunction(fn)); } } Set<String> trampolineDependencies = new HashSet<String>(); for (Trampoline trampoline : trampolines) { trampolineResolver.compile(mb, trampoline); trampolineDependencies.addAll(trampolineResolver.getDependencies()); } Global classInfoStruct = null; StructureConstant classInfoErrorStruct = createClassInfoErrorStruct(); if (classInfoErrorStruct != null) { // The class cannot be loaded at runtime. Replace the ClassInfo struct // with a ClassInfoError struct with details of why. classInfoStruct = new Global(mangleClass(sootClass) + "_info_struct", classInfoErrorStruct); } else { classInfoStruct = new Global(mangleClass(sootClass) + "_info_struct", createClassInfoStruct()); } mb.addGlobal(classInfoStruct); Function infoFn = FunctionBuilder.infoStruct(sootClass); infoFn.add(new Ret(new ConstantBitcast(classInfoStruct.ref(), I8_PTR_PTR))); mb.addFunction(infoFn); out.write(mb.build().toString().getBytes("UTF-8")); clazz.clearDependencies(); clazz.addDependency( "java/lang/Object"); // Make sure no class or interface has zero dependencies if (sootClass.hasSuperclass() && !sootClass.isInterface()) { clazz.addDependency(getInternalName(sootClass.getSuperclass())); } for (SootClass iface : sootClass.getInterfaces()) { clazz.addDependency(getInternalName(iface)); } for (SootField f : sootClass.getFields()) { addDependencyIfNeeded(clazz, f.getType()); } for (SootMethod m : sootClass.getMethods()) { addDependencyIfNeeded(clazz, m.getReturnType()); @SuppressWarnings("unchecked") List<soot.Type> paramTypes = (List<soot.Type>) m.getParameterTypes(); for (soot.Type type : paramTypes) { addDependencyIfNeeded(clazz, type); } } clazz.addDependencies(attributesEncoder.getDependencies()); clazz.addDependencies(trampolineDependencies); clazz.addDependencies(catches); for (Trampoline t : trampolines) { if (!(t instanceof LdcString)) { String desc = t.getTarget(); if (desc.charAt(0) == 'L' || desc.charAt(0) == '[') { // Target is a descriptor addDependencyIfNeeded(clazz, desc); } else { clazz.addDependency(t.getTarget()); } } if (t instanceof FieldAccessor) { addDependencyIfNeeded(clazz, ((FieldAccessor) t).getFieldDesc()); } else if (t instanceof Invoke) { String methodDesc = ((Invoke) t).getMethodDesc(); addDependencyIfNeeded(clazz, getReturnTypeDescriptor(methodDesc)); for (String desc : getParameterDescriptors(methodDesc)) { addDependencyIfNeeded(clazz, desc); } } } clazz.saveDependencies(); }
protected Value marshalLongToPointer(Function fn, Value handle) { Variable result = fn.newVariable(I8_PTR); fn.add(new Inttoptr(result, handle, I8_PTR)); return result.ref(); }
private Function createClassInitWrapperFunction(FunctionRef targetFn) { Function fn = FunctionBuilder.clinitWrapper(targetFn); Value info = getInfoStruct(fn); Variable infoHeader = fn.newVariable(new PointerType(new StructureType(I8_PTR, I32))); fn.add(new Bitcast(infoHeader, info, infoHeader.getType())); Variable infoHeaderFlags = fn.newVariable(new PointerType(I32)); fn.add(new Getelementptr(infoHeaderFlags, infoHeader.ref(), 0, 1)); Variable flags = fn.newVariable(I32); fn.add(new Load(flags, infoHeaderFlags.ref())); Variable initializedFlag = fn.newVariable(I32); fn.add(new And(initializedFlag, flags.ref(), new IntegerConstant(CI_INITIALIZED))); Variable initialized = fn.newVariable(I1); fn.add( new Icmp( initialized, Icmp.Condition.eq, initializedFlag.ref(), new IntegerConstant(CI_INITIALIZED))); Label trueLabel = new Label(); Label falseLabel = new Label(); fn.add( new Br(initialized.ref(), fn.newBasicBlockRef(trueLabel), fn.newBasicBlockRef(falseLabel))); fn.newBasicBlock(trueLabel); Value result = call(fn, targetFn, fn.getParameterRefs()); fn.add(new Ret(result)); fn.newBasicBlock(falseLabel); call(fn, BC_INITIALIZE_CLASS, fn.getParameterRef(0), info); fn.add(new Br(fn.newBasicBlockRef(trueLabel))); return fn; }
protected Value loadValueForGetter( SootMethod method, Function fn, Type memberType, Value memberPtr, Value env, boolean dereference, long flags) { soot.Type type = method.getReturnType(); Value result = null; if (memberType instanceof StructureType) { // The member is a child struct contained in the current struct result = memberPtr; } else if (memberType instanceof ArrayType) { // The member is an array contained in the current struct result = memberPtr; } else if (dereference) { Variable tmp = fn.newVariable(memberType); fn.add(new Load(tmp, memberPtr)); result = tmp.ref(); } else { // Do not dereference the pointer but use it as is. This is needed for // global values such as _dispatch_main_q which is a struct and not a // pointer which we should load. We want the address of the struct. Variable tmp = fn.newVariable(memberType); fn.add(new Bitcast(tmp, memberPtr, tmp.getType())); result = tmp.ref(); } if (needsMarshaler(type)) { MarshalerMethod marshalerMethod = config.getMarshalerLookup().findMarshalerMethod(new MarshalSite(method)); String targetClassName = getInternalName(type); if (memberType instanceof PrimitiveType) { // Value type wrapping a primitive value (e.g. Enum, Integer and Bits) result = marshalNativeToValueObject(fn, marshalerMethod, env, targetClassName, result, flags); } else { if (memberType instanceof ArrayType) { // Array result = marshalNativeToArray( fn, marshalerMethod, env, targetClassName, result, flags, getArrayDimensions(method)); } else { result = marshalNativeToObject(fn, marshalerMethod, null, env, targetClassName, result, flags); } } } else { result = marshalNativeToPrimitive(fn, method, result); } return result; }