private Type getReturnType(String anno, SootMethod method) {
    soot.Type sootType = method.getReturnType();
    if (hasPointerAnnotation(method)) {
      if (!sootType.equals(LongType.v())) {
        throw new IllegalArgumentException(
            anno
                + " annotated method "
                + method
                + " must return long when annotated with @Pointer");
      }
      return I8_PTR;
    }
    if (hasMachineSizedFloatAnnotation(method)) {
      if (!sootType.equals(DoubleType.v()) && !sootType.equals(FloatType.v())) {
        throw new IllegalArgumentException(
            anno
                + " annotated method "
                + method
                + " must return float or double when annotated with @MachineSizedFloat");
      }
      return config.getArch().is32Bit() ? FLOAT : DOUBLE;
    }
    if (hasMachineSizedSIntAnnotation(method) || hasMachineSizedUIntAnnotation(method)) {
      if (!sootType.equals(LongType.v())) {
        throw new IllegalArgumentException(
            anno
                + " annotated method "
                + method
                + " must return long when annotated with @MachineSizedSInt or @MachineSizedUInt");
      }
      return config.getArch().is32Bit() ? I32 : I64;
    }
    if (isStruct(sootType)) {
      if (!isPassByValue(method)) {
        // Structs are returned by reference by default
        return new PointerType(getStructType(sootType));
      }
      return getStructType(sootType);
    } else if (isNativeObject(sootType)) {
      // NativeObjects are always returned by reference.
      return I8_PTR;
    } else if (sootType instanceof PrimType || sootType == VoidType.v()) {
      return getType(sootType);
    }

    MarshalerMethod marshalerMethod =
        config.getMarshalerLookup().findMarshalerMethod(new MarshalSite(method));
    if (marshalerMethod instanceof ValueMarshalerMethod) {
      return ((ValueMarshalerMethod) marshalerMethod).getNativeType(config.getArch());
    } else {
      return I8_PTR;
    }
  }
 private Type signatureToType(String desc) {
   String rawDesc = desc.replaceAll("<.*>", "");
   String internalName = rawDesc.replaceAll("^\\[*", "");
   int dims = rawDesc.length() - internalName.length();
   internalName = Types.getInternalNameFromDescriptor(internalName);
   soot.Type sootType = SootResolver.v().makeClassRef(internalName.replace('/', '.')).getType();
   for (int i = 0; i < dims; i++) {
     sootType = sootType.makeArrayType();
   }
   SootMethod m = new SootMethod("foo", Arrays.asList(sootType), VoidType.v());
   m.addTag(new SignatureTag("(" + desc + ")V"));
   SootMethodType mType = new SootMethodType(m);
   return mType.getGenericParameterTypes()[0];
 }
 protected Value marshalPrimitiveToNative(Function fn, SootMethod method, Value value) {
   soot.Type type = method.getReturnType();
   if (hasPointerAnnotation(method)) {
     value = marshalLongToPointer(fn, value);
   } else if (hasMachineSizedFloatAnnotation(method) && type.equals(DoubleType.v())) {
     value = marshalDoubleToMachineSizedFloat(fn, value);
   } else if (hasMachineSizedFloatAnnotation(method) && type.equals(FloatType.v())) {
     value = marshalFloatToMachineSizedFloat(fn, value);
   } else if (hasMachineSizedSIntAnnotation(method) && type.equals(LongType.v())) {
     value = marshalLongToMachineSizedInt(fn, value);
   } else if (hasMachineSizedUIntAnnotation(method) && type.equals(LongType.v())) {
     value = marshalLongToMachineSizedInt(fn, value);
   }
   return value;
 }
 protected Value marshalNativeToPrimitive(
     Function fn, SootMethod method, int paramIndex, Value value) {
   soot.Type type = method.getParameterType(paramIndex);
   if (hasPointerAnnotation(method, paramIndex)) {
     value = marshalPointerToLong(fn, value);
   } else if (hasMachineSizedFloatAnnotation(method, paramIndex) && type.equals(DoubleType.v())) {
     value = marshalMachineSizedFloatToDouble(fn, value);
   } else if (hasMachineSizedFloatAnnotation(method, paramIndex) && type.equals(FloatType.v())) {
     value = marshalMachineSizedFloatToFloat(fn, value);
   } else if (hasMachineSizedSIntAnnotation(method, paramIndex) && type.equals(LongType.v())) {
     value = marshalMachineSizedSIntToLong(fn, value);
   } else if (hasMachineSizedUIntAnnotation(method, paramIndex) && type.equals(LongType.v())) {
     value = marshalMachineSizedUIntToLong(fn, value);
   }
   return value;
 }
  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);
  }
  private Type getParameterType(String anno, SootMethod method, int i) {
    soot.Type sootType = method.getParameterType(i);
    if (hasPointerAnnotation(method, i)) {
      if (!sootType.equals(LongType.v())) {
        throw new IllegalArgumentException(
            "Parameter "
                + (i + 1)
                + " of "
                + anno
                + " annotated method "
                + method
                + " must be of type long when annotated with @Pointer.");
      }
      return I8_PTR;
    }
    if (hasMachineSizedFloatAnnotation(method, i)) {
      if (!sootType.equals(DoubleType.v()) && !sootType.equals(FloatType.v())) {
        throw new IllegalArgumentException(
            "Parameter "
                + (i + 1)
                + " of "
                + anno
                + " annotated method "
                + method
                + " must be of type float or double when annotated with @MachineSizedFloat.");
      }
      return config.getArch().is32Bit() ? FLOAT : DOUBLE;
    }
    if (hasMachineSizedSIntAnnotation(method, i) || hasMachineSizedUIntAnnotation(method, i)) {
      if (!sootType.equals(LongType.v())) {
        throw new IllegalArgumentException(
            "Parameter "
                + (i + 1)
                + " of "
                + anno
                + " annotated method "
                + method
                + " must be of type long when annotated with "
                + "@MachineSizedSInt or @MachineSizedUInt");
      }
      return config.getArch().is32Bit() ? I32 : I64;
    }
    if (hasStructRetAnnotation(method, i)) {
      if (i > 0) {
        throw new IllegalArgumentException(
            "Parameter "
                + (i + 1)
                + " of "
                + anno
                + " annotated method "
                + method
                + " cannot be annotated with @StructRet. Only the first"
                + " parameter may have this annotation.");
      }
      if (!isStruct(sootType)) {
        throw new IllegalArgumentException(
            "Parameter "
                + (i + 1)
                + " of "
                + anno
                + " annotated method "
                + method
                + " must be a sub class of Struct when annotated with @StructRet.");
      }
      // @StructRet implies pass by reference
      return new PointerType(getStructType(sootType));
    }
    if (isStruct(sootType)) {
      StructureType structType = getStructType(sootType);
      if (hasByValAnnotation(method, i)) {
        return getStructType(sootType);
      }
      return new PointerType(structType);
    } else if (isNativeObject(sootType)) {
      // NativeObjects are always passed by reference.
      return I8_PTR;
    } else if (sootType instanceof PrimType) {
      return getType(sootType);
    }

    MarshalerMethod marshalerMethod =
        config.getMarshalerLookup().findMarshalerMethod(new MarshalSite(method, i));
    if (marshalerMethod instanceof ValueMarshalerMethod) {
      return ((ValueMarshalerMethod) marshalerMethod).getNativeType(config.getArch());
    } else {
      return I8_PTR;
    }
  }