/* * private Object getField(Object o, Class declaringClass, Class type, * int slot, boolean noAccessCheck) * * Primitive types need to be boxed. */ static void Dalvik_java_lang_reflect_Field_getField(const u4* args, JValue* pResult) { // ignore thisPtr in args[0] Object* obj = (Object*) args[1]; ClassObject* declaringClass = (ClassObject*) args[2]; ClassObject* fieldType = (ClassObject*) args[3]; int slot = args[4]; bool noAccessCheck = (args[5] != 0); JValue value; const JValue* fieldPtr; DataObject* result; //dvmDumpClass(obj->clazz, kDumpClassFullDetail); /* get a pointer to the field's data; performs access checks */ fieldPtr = getFieldDataAddr(obj, declaringClass, slot, false,noAccessCheck); if (fieldPtr == NULL) RETURN_VOID(); /* copy 4 or 8 bytes out */ if (fieldType->primitiveType == PRIM_LONG || fieldType->primitiveType == PRIM_DOUBLE) { value.j = fieldPtr->j; } else { value.i = fieldPtr->i; } result = dvmWrapPrimitive(value, fieldType); dvmReleaseTrackedAlloc((Object*) result, NULL); RETURN_PTR(result); }
/* * Return a new Object[] array with the contents of "args". We determine * the number and types of values in "args" based on the method signature. * Primitive types are boxed. * * Returns NULL if the method takes no arguments. * * The caller must call dvmReleaseTrackedAlloc() on the return value. * * On failure, returns with an appropriate exception raised. */ static ArrayObject* boxMethodArgs(const Method* method, const u4* args) { const char* desc = &method->shorty[1]; // [0] is the return type. ArrayObject* argArray = NULL; int argCount; Object** argObjects; bool failed = true; /* count args */ argCount = dexProtoGetParameterCount(&method->prototype); /* allocate storage */ argArray = dvmAllocArray(gDvm.classJavaLangObjectArray, argCount, kObjectArrayRefWidth, ALLOC_DEFAULT); if (argArray == NULL) goto bail; argObjects = (Object**) argArray->contents; /* * Fill in the array. */ int srcIndex = 0; argCount = 0; while (*desc != '\0') { char descChar = *(desc++); JValue value; switch (descChar) { case 'Z': case 'C': case 'F': case 'B': case 'S': case 'I': value.i = args[srcIndex++]; argObjects[argCount] = (Object*) dvmWrapPrimitive(value, dvmFindPrimitiveClass(descChar)); /* argObjects is tracked, don't need to hold this too */ dvmReleaseTrackedAlloc(argObjects[argCount], NULL); argCount++; break; case 'D': case 'J': value.j = dvmGetArgLong(args, srcIndex); srcIndex += 2; argObjects[argCount] = (Object*) dvmWrapPrimitive(value, dvmFindPrimitiveClass(descChar)); dvmReleaseTrackedAlloc(argObjects[argCount], NULL); argCount++; break; case '[': case 'L': argObjects[argCount++] = (Object*) args[srcIndex++]; break; } } failed = false; bail: if (failed) { dvmReleaseTrackedAlloc((Object*)argArray, NULL); argArray = NULL; } return argArray; }
/* * Invoke a method, using the specified arguments and return type, through * one of the reflection interfaces. Could be a virtual or direct method * (including constructors). Used for reflection. * * Deals with boxing/unboxing primitives and performs widening conversions. * * "invokeObj" will be null for a static method. * * If the invocation returns with an exception raised, we have to wrap it. */ Object* dvmInvokeMethod(Object* obj, const Method* method, ArrayObject* argList, ArrayObject* params, ClassObject* returnType, bool noAccessCheck) { ClassObject* clazz; Object* retObj = NULL; Thread* self = dvmThreadSelf(); s4* ins; int verifyCount, argListLength; JValue retval; bool needPop = false; #ifdef WITH_TAINT_TRACKING u4 rtaint = TAINT_CLEAR; int slot_cnt = 0; bool nativeTarget = dvmIsNativeMethod(method); /* For simplicity, argument tags for native targets * are unioned. This may cause false positives, but * it is the easiest way to handle this for now. */ u4 nativeTag = TAINT_CLEAR; #endif /* verify arg count */ if (argList != NULL) argListLength = argList->length; else argListLength = 0; if (argListLength != (int) params->length) { LOGI("invoke: expected %d args, received %d args\n", params->length, argListLength); dvmThrowException("Ljava/lang/IllegalArgumentException;", "wrong number of arguments"); return NULL; } clazz = callPrep(self, method, obj, !noAccessCheck); if (clazz == NULL) return NULL; needPop = true; /* "ins" for new frame start at frame pointer plus locals */ #ifdef WITH_TAINT_TRACKING if (nativeTarget) { /* native target, no taint tag interleaving */ ins = ((s4*)self->curFrame) + (method->registersSize - method->insSize); } else { /* interpreted target, taint tags are interleaved */ ins = ((s4*)self->curFrame) + ((method->registersSize - method->insSize) << 1); } #else ins = ((s4*)self->curFrame) + (method->registersSize - method->insSize); #endif verifyCount = 0; //LOGD(" FP is %p, INs live at >= %p\n", self->curFrame, ins); /* put "this" pointer into in0 if appropriate */ if (!dvmIsStaticMethod(method)) { assert(obj != NULL); *ins++ = (s4) obj; #ifdef WITH_TAINT_TRACKING if (!nativeTarget) { *ins++ = TAINT_CLEAR; } slot_cnt++; #endif verifyCount++; } /* * Copy the args onto the stack. Primitive types are converted when * necessary, and object types are verified. */ DataObject** args; ClassObject** types; int i; args = (DataObject**) argList->contents; types = (ClassObject**) params->contents; for (i = 0; i < argListLength; i++) { int width; #ifdef WITH_TAINT_TRACKING int tag = dvmGetPrimitiveTaint(*args, *types); #endif width = dvmConvertArgument(*args++, *types++, ins); if (width < 0) { if (*(args-1) != NULL) { LOGV("invoke: type mismatch on arg %d ('%s' '%s')\n", i, (*(args-1))->obj.clazz->descriptor, (*(types-1))->descriptor); } dvmPopFrame(self); // throw wants to pull PC out of stack needPop = false; dvmThrowException("Ljava/lang/IllegalArgumentException;", "argument type mismatch"); goto bail; } #ifdef WITH_TAINT_TRACKING /* dvmConvertArgument() returns -1, 1, or 2 */ if (nativeTarget) { nativeTag |= tag; /* TODO: is there a better way to do this?*/ ins += width; } else { if (width == 2) { ins[2] = ins[1]; ins[1] = tag; ins[3] = tag; ins += 4; } else if (width == 1) { ins[1] = tag; ins += 2; } else { /* error condition duplicated from above */ dvmPopFrame(self); dvmThrowException("Ljava/lang/IllegalArgumentException;", "argument type mismatch"); goto bail_popped; } } slot_cnt += width; #else ins += width; #endif verifyCount += width; } #ifdef WITH_TAINT_TRACKING /* native hack spacer */ *ins++ = TAINT_CLEAR; /* if nativeTarget, this is return taint */ { int i; if (nativeTarget) { for (i = 0; i < slot_cnt; i++) { *ins++ = nativeTag; /* TODO: better way? */ } } } #endif if (verifyCount != method->insSize) { LOGE("Got vfycount=%d insSize=%d for %s.%s\n", verifyCount, method->insSize, clazz->descriptor, method->name); assert(false); goto bail; } //dvmDumpThreadStack(dvmThreadSelf()); if (dvmIsNativeMethod(method)) { TRACE_METHOD_ENTER(self, method); /* * Because we leave no space for local variables, "curFrame" points * directly at the method arguments. */ (*method->nativeFunc)(self->curFrame, &retval, method, self); TRACE_METHOD_EXIT(self, method); #ifdef WITH_TAINT_TRACKING rtaint = ((u4*)self->curFrame)[slot_cnt]; #endif } else { #ifdef WITH_TAINT_TRACKING dvmInterpret(self, method, &retval, &rtaint); #else dvmInterpret(self, method, &retval); #endif } /* * Pop the frame immediately. The "wrap" calls below can cause * allocations, and we don't want the GC to walk the now-dead frame. */ dvmPopFrame(self); needPop = false; /* * If an exception is raised, wrap and replace. This is necessary * because the invoked method could have thrown a checked exception * that the caller wasn't prepared for. * * We might be able to do this up in the interpreted code, but that will * leave us with a shortened stack trace in the top-level exception. */ if (dvmCheckException(self)) { dvmWrapException("Ljava/lang/reflect/InvocationTargetException;"); } else { /* * If this isn't a void method or constructor, convert the return type * to an appropriate object. * * We don't do this when an exception is raised because the value * in "retval" is undefined. */ if (returnType != NULL) { retObj = (Object*)dvmWrapPrimitive(retval, returnType); #ifdef WITH_TAINT_TRACKING dvmSetPrimitiveTaint((DataObject *)retObj, returnType, rtaint); #endif dvmReleaseTrackedAlloc(retObj, NULL); } } bail: if (needPop) { dvmPopFrame(self); } bail_popped: return retObj; }
/* * Invoke a method, using the specified arguments and return type, through * one of the reflection interfaces. Could be a virtual or direct method * (including constructors). Used for reflection. * * Deals with boxing/unboxing primitives and performs widening conversions. * * "invokeObj" will be null for a static method. * * If the invocation returns with an exception raised, we have to wrap it. */ Object* dvmInvokeMethod(Object* obj, const Method* method, ArrayObject* argList, ArrayObject* params, ClassObject* returnType, bool noAccessCheck) { ClassObject* clazz; Object* retObj = NULL; Thread* self = dvmThreadSelf(); s4* ins; int verifyCount, argListLength; JValue retval; /* verify arg count */ if (argList != NULL) argListLength = argList->length; else argListLength = 0; if (argListLength != (int) params->length) { LOGI("invoke: expected %d args, received %d args\n", params->length, argListLength); dvmThrowException("Ljava/lang/IllegalArgumentException;", "wrong number of arguments"); return NULL; } clazz = callPrep(self, method, obj, !noAccessCheck); if (clazz == NULL) return NULL; /* "ins" for new frame start at frame pointer plus locals */ ins = ((s4*)self->curFrame) + (method->registersSize - method->insSize); verifyCount = 0; //LOGD(" FP is %p, INs live at >= %p\n", self->curFrame, ins); /* put "this" pointer into in0 if appropriate */ if (!dvmIsStaticMethod(method)) { assert(obj != NULL); *ins++ = (s4) obj; verifyCount++; } /* * Copy the args onto the stack. Primitive types are converted when * necessary, and object types are verified. */ DataObject** args; ClassObject** types; int i; args = (DataObject**) argList->contents; types = (ClassObject**) params->contents; for (i = 0; i < argListLength; i++) { int width; width = dvmConvertArgument(*args++, *types++, ins); if (width < 0) { if (*(args-1) != NULL) { LOGV("invoke: type mismatch on arg %d ('%s' '%s')\n", i, (*(args-1))->obj.clazz->descriptor, (*(types-1))->descriptor); } dvmPopFrame(self); // throw wants to pull PC out of stack dvmThrowException("Ljava/lang/IllegalArgumentException;", "argument type mismatch"); goto bail_popped; } ins += width; verifyCount += width; } if (verifyCount != method->insSize) { LOGE("Got vfycount=%d insSize=%d for %s.%s\n", verifyCount, method->insSize, clazz->descriptor, method->name); assert(false); goto bail; } //dvmDumpThreadStack(dvmThreadSelf()); if (dvmIsNativeMethod(method)) { #ifdef WITH_PROFILER TRACE_METHOD_ENTER(self, method); #endif /* * Because we leave no space for local variables, "curFrame" points * directly at the method arguments. */ (*method->nativeFunc)(self->curFrame, &retval, method, self); #ifdef WITH_PROFILER TRACE_METHOD_EXIT(self, method); #endif } else { dvmInterpret(self, method, &retval); } /* * If an exception is raised, wrap and replace. This is necessary * because the invoked method could have thrown a checked exception * that the caller wasn't prepared for. * * We might be able to do this up in the interpreted code, but that will * leave us with a shortened stack trace in the top-level exception. */ if (dvmCheckException(self)) { dvmWrapException("Ljava/lang/reflect/InvocationTargetException;"); } else { /* * If this isn't a void method or constructor, convert the return type * to an appropriate object. * * We don't do this when an exception is raised because the value * in "retval" is undefined. */ if (returnType != NULL) { retObj = (Object*)dvmWrapPrimitive(retval, returnType); dvmReleaseTrackedAlloc(retObj, NULL); } } bail: dvmPopFrame(self); bail_popped: return retObj; }
/* * private Object getField(Object o, Class declaringClass, Class type, * int slot, boolean noAccessCheck) * * Primitive types need to be boxed. */ static void Dalvik_java_lang_reflect_Field_getField(const u4* args, JValue* pResult) { // ignore thisPtr in args[0] Object* obj = (Object*) args[1]; ClassObject* declaringClass = (ClassObject*) args[2]; ClassObject* fieldType = (ClassObject*) args[3]; int slot = args[4]; bool noAccessCheck = (args[5] != 0); #ifdef WITH_TAINT_TRACKING u4* rtaint = (u4*) &args[6]; /* return taint tag slot */ #endif JValue value; const JValue* fieldPtr; DataObject* result; //dvmDumpClass(obj->clazz, kDumpClassFullDetail); /* get a pointer to the field's data; performs access checks */ fieldPtr = getFieldDataAddr(obj, declaringClass, slot, false,noAccessCheck); if (fieldPtr == NULL) RETURN_VOID(); /* copy 4 or 8 bytes out */ if (fieldType->primitiveType == PRIM_LONG || fieldType->primitiveType == PRIM_DOUBLE) { value.j = fieldPtr->j; } else { value.i = fieldPtr->i; } result = dvmWrapPrimitive(value, fieldType); dvmReleaseTrackedAlloc((Object*) result, NULL); #ifdef WITH_TAINT_TRACKING /* If we got this far, we know the fields is okay to access and there * will not be a problem getting the field from the slot */ { Field* field = dvmSlotToField(declaringClass, slot); assert(field != NULL); if (dvmIsStaticField(field)) { StaticField* sfield = (StaticField*)field; *rtaint = dvmGetStaticFieldTaint(sfield); } else { /* Note, getFieldDataAddr() already checked that * obj is of type declaringClass, so no need to check here */ InstField* ifield = (InstField*)field; if (fieldType->primitiveType == PRIM_LONG || fieldType->primitiveType == PRIM_DOUBLE) { *rtaint = dvmGetFieldTaintWide(obj, ifield->byteOffset); } else { *rtaint = dvmGetFieldTaint(obj, ifield->byteOffset); } } } #endif RETURN_PTR(result); }