static Type mergeStructMemberTypes(DataLayout dataLayout, Type t1, Type t2) { int align1 = dataLayout.getAlignment(t1); int align2 = dataLayout.getAlignment(t2); int size1 = dataLayout.getStoreSize(t1); int size2 = dataLayout.getStoreSize(t2); Type result = align1 < align2 ? t2 : t1; int size = align1 < align2 ? size2 : size1; int pad = Math.max(size1, size2) - size; if (pad > 0) { return new StructureType(result, new ArrayType(pad, I8)); } else { return result; } }
private StructureType getStructType(SootClass clazz, boolean checkEmpty) { int n = 0; for (SootMethod method : clazz.getMethods()) { n = Math.max(getStructMemberOffset(method) + 1, n); } Type[] result = new Type[n + 1]; StructureType superType = null; if (clazz.hasSuperclass()) { SootClass superclass = clazz.getSuperclass(); if (!superclass.getName().equals("org.robovm.rt.bro.Struct")) { superType = getStructType(superclass, false); } } result[0] = superType != null ? superType : new StructureType(); for (SootMethod method : clazz.getMethods()) { int offset = getStructMemberOffset(method); if (offset != -1) { if (!method.isNative() && !method.isStatic()) { throw new IllegalArgumentException( "@StructMember annotated method " + method + " must be native and not static"); } Type type = null; if (method.getParameterCount() == 0) { soot.Type sootType = method.getReturnType(); // Possibly a getter if (hasPointerAnnotation(method) && !sootType.equals(LongType.v())) { throw new IllegalArgumentException( "@StructMember(" + offset + ") annotated getter " + method + " must be of type long when annotated with @Pointer"); } if (hasMachineSizedFloatAnnotation(method) && !sootType.equals(DoubleType.v()) && !sootType.equals(FloatType.v())) { throw new IllegalArgumentException( "@StructMember(" + offset + ") annotated getter " + method + " must be of type float or double when annotated with @MachineSizedFloat"); } if ((hasMachineSizedSIntAnnotation(method) || hasMachineSizedUIntAnnotation(method)) && !sootType.equals(LongType.v())) { throw new IllegalArgumentException( "@StructMember(" + offset + ") annotated getter " + method + " must be of type long when annotated with @MachineSizedSInt or @MachineSizedUInt"); } if (sootType instanceof soot.ArrayType && !hasArrayAnnotation(method)) { throw new IllegalArgumentException( "@Array annotation expected on struct member getter " + method); } } else if (method.getParameterCount() == 1) { soot.Type sootType = method.getParameterType(0); if (hasPointerAnnotation(method, 0) && !sootType.equals(LongType.v())) { throw new IllegalArgumentException( "@StructMember(" + offset + ") annotated setter " + method + " must be of type long when annotated with @Pointer"); } if (hasMachineSizedFloatAnnotation(method, 0) && !sootType.equals(DoubleType.v()) && !sootType.equals(FloatType.v())) { throw new IllegalArgumentException( "@StructMember(" + offset + ") annotated setter " + method + " must be of type float or double when annotated with @MachineSizedFloat"); } if ((hasMachineSizedSIntAnnotation(method, 0) || hasMachineSizedUIntAnnotation(method)) && !sootType.equals(LongType.v())) { throw new IllegalArgumentException( "@StructMember(" + offset + ") annotated setter " + method + " must be of type long when annotated with @MachineSizedSInt or @MachineSizedUInt"); } if (sootType instanceof soot.ArrayType && !hasArrayAnnotation(method, 0)) { throw new IllegalArgumentException( "@Array annotation expected on first parameter of struct member setter " + method); } soot.Type retType = method.getReturnType(); // The return type of the setter must be void or this if (!retType.equals(VoidType.v()) && !(retType instanceof RefType && ((RefType) retType).getSootClass().equals(clazz))) { throw new IllegalArgumentException( "Setter " + method + " for " + "@StructMember(" + offset + ") " + " must either return nothing or return a " + clazz); } } else { throw new IllegalArgumentException( "@StructMember annotated method " + method + " has too many parameters"); } type = getStructMemberType(method); int index = offset + 1; if (result[index] == null) { result[index] = type; } else if (type != result[index]) { // Two members mapped to the same offset (union). Pick // the type with the largest alignment and pad with bytes // up to the largest size. result[index] = mergeStructMemberTypes(config.getDataLayout(), type, result[index]); } } } for (int i = 1; i < result.length; i++) { if (result[i] == null) { throw new IllegalArgumentException("No @StructMember(" + i + ") defined in class " + clazz); } } if (!clazz.isAbstract() && checkEmpty && n == 0 && superType == null) { throw new IllegalArgumentException( "Struct class " + clazz + " has no @StructMember annotated methods"); } return new StructureType(result); }