/* (documented in header file) */ const char* dexProtoGetParameterDescriptors(const DexProto* pProto, DexStringCache* pCache) { DexParameterIterator iterator; size_t length = 1; /* +1 for the terminating '\0' */ dexParameterIteratorInit(&iterator, pProto); for (;;) { const char* descriptor = dexParameterIteratorNextDescriptor(&iterator); if (descriptor == NULL) { break; } length += strlen(descriptor); } dexParameterIteratorInit(&iterator, pProto); dexStringCacheAlloc(pCache, length); char *at = (char*) pCache->value; for (;;) { const char* descriptor = dexParameterIteratorNextDescriptor(&iterator); if (descriptor == NULL) { break; } strcpy(at, descriptor); at += strlen(descriptor); } return pCache->value; }
/* (documented in header file) */ size_t dexProtoGetParameterCount(const DexProto* pProto) { #ifdef FASTIVA DexParameterIterator it; dexParameterIteratorInit(&it, pProto); return it.parameterCount; #else const DexProtoId* protoId = getProtoId(pProto); const DexTypeList* typeList = dexGetProtoParameters(pProto->dexFile, protoId); return (typeList == NULL) ? 0 : typeList->size; #endif }
/* * 比较名称。以较特定的方法,参数、内容和返回值,如果他们相等或者不等于0,则返回0 * */ static inline int compareMethodHelper(Method* method, const char* methodName, const char* returnType, size_t argCount, const char** argTypes) { DexParameterIterator iterator; const DexProto* proto; if (strcmp(methodName, method->name) != 0) { return 1; } proto = &method->prototype; if (strcmp(returnType, dexProtoGetReturnType(proto)) != 0) { return 1; } if (dexProtoGetParameterCount(proto) != argCount) { return 1; } dexParameterIteratorInit(&iterator, proto); for (/*argCount*/; argCount != 0; argCount--, argTypes++) { const char* argType = *argTypes; const char* paramType = dexParameterIteratorNextDescriptor(&iterator); if (paramType == NULL) { /* Param list ended early; no match */ break; } else if (strcmp(argType, paramType) != 0) { /* Types aren't the same; no match. */ break; } } if (argCount == 0) { /* We ran through all the given arguments... */ if (dexParameterIteratorNextDescriptor(&iterator) == NULL) { /* ...and through all the method's arguments; success! */ return 0; } } return 1; }
/* Returns the index in args[] corresponding to the parameter * string entry. * - It doesn't matter if the entry has multiple parts, e.g., * "param1.foo.bar", as long as the variable name after the first * "." is not a number. Since the signature comes next, we can * safely assume this is the case. * - returns -1 on parsing error * - If descriptor is not NULL, it will point to a newly allocated * descriptor that needs to be free()'d (unless there was an error) */ int paramToArgIndex(const char* entry, const Method* method, char** descriptor) { int pIdx, aIdx, i; char* endptr; const char* num = entry + 5; /* "param" is the first 5 characters */ const DexProto* proto = &method->prototype; DexParameterIterator pIterator; /* Step 1: determine the parameter index (pIdx) */ pIdx = strtol(num, &endptr, 10); if (num == endptr) { /* error parsing */ return -1; } /* Step 2: translate parameter index into args array index */ dexParameterIteratorInit(&pIterator, proto); aIdx = (dvmIsStaticMethod(method)?0:1); /* index where params start */ for (i=0; i<=pIdx ; i++) { const char* desc = dexParameterIteratorNextDescriptor(&pIterator); if (desc == NULL) { /* This index doesn't exist, error */ return -1; } if (i == pIdx) { /* This is the index */ if (descriptor != NULL) { *descriptor = strdup(desc); } break; } /* increment the args array index */ aIdx++; if (desc[0] == 'J' || desc[0] == 'D') { /* wide argument, increment index one more */ aIdx++; } } return aIdx; }
/* Used to propagate taint for JNI methods * Two types of propagation: * 1) simple conservative propagation based on parameters * 2) propagation based on function profile policies */ void dvmTaintPropJniMethod(const u4* args, JValue* pResult, const Method* method, const int nativeTaint) { const DexProto* proto = &method->prototype; DexParameterIterator pIterator; int nParams = dexProtoGetParameterCount(proto); int pStart = (dvmIsStaticMethod(method)?0:1); /* index where params start */ /* Consider 3 arguments. [x] indicates return taint index * 0 1 2 [3] 4 5 6 */ int nArgs = method->insSize; u4* rtaint = (u4*) &args[nArgs]; /* The return taint value */ int tStart = nArgs+1; /* index of args[] where taint values start */ int tEnd = nArgs*2; /* index of args[] where taint values end */ u4 tag = TAINT_CLEAR; int i; #if 0 { char *desc = dexProtoCopyMethodDescriptor(proto); ALOGW("Jni: %s.%s%s, descriptor: %s", method->clazz->descriptor, method->name, dvmIsStaticMethod(method)?"[static]":"", desc); free(desc); } #endif #ifdef TAINT_JNI_LOG /* JNI logging for debugging purposes */ if (gJniLog) { u4 hash; int len; char *inStr, *outStr; len = strlen(method->clazz->descriptor) + 1 + strlen(method->name); inStr = (char*) malloc(len+1); strcpy(inStr, method->clazz->descriptor); strcat(inStr, "."); strcat(inStr, method->name); hash = dvmComputeUtf8Hash(inStr); dvmHashTableLock(gJniLogSeen); outStr = (char*) dvmHashTableLookup(gJniLogSeen, hash, inStr, (HashCompareFunc) strcmp, false); if (outStr == NULL) { /* New method! */ /* add it */ dvmHashTableLookup(gJniLogSeen, hash, inStr, (HashCompareFunc) strcmp, true); } else { free(inStr); /* don't need this anymore */ } dvmHashTableUnlock(gJniLogSeen); } #endif /* Union the taint tags, this includes object ref tags * - we don't need to worry about static vs. not static, because getting * the taint tag on the "this" object reference is a good * - we don't need to worry about wide registers, because the stack * interleaving of taint tags makes it transparent */ /*for (i = tStart; i <= tEnd; i++) { tag |= args[i]; if (args[i]!=0 && args[i]!=TAINT_ACCELEROMETER) //found a taint, and its not the accelerometer spam either ALOGD("dvmTaintPropJNIMethod found taint %08x in method=%s:%s(%s) for arg[%d]=%08x", args[i], method->clazz->descriptor, method->name, method->shorty, i-nArgs, args[i-nArgs]); }*/ /* If not static, pull any taint from the "this" object */ /*if (!dvmIsStaticMethod(method)) { tag |= getObjectTaint((Object*)args[0], method->clazz->descriptor); }*/ /* Union taint from Objects we care about */ dexParameterIteratorInit(&pIterator, proto); for (i=pStart; ; i++) { const char* desc = dexParameterIteratorNextDescriptor(&pIterator); if (desc == NULL) { break; } if (desc[0] == '[' || desc[0] == 'L') { tag |= getObjectTaint((Object*) args[i], desc); } if (desc[0] == 'J' || desc[0] == 'D') { /* wide argument, increment index one more */ i++; } } /* Look at the taint policy profiles (may have return taint) */ //tag |= propMethodProfile(args, method); /* Update return taint according to the return type */ //Native Tainting: get taint Value from native code //if (tag) { if (nativeTaint) { const char* desc = dexProtoGetReturnType(proto); //setReturnTaint(tag, rtaint, pResult, desc); ALOGD("dvmTaintPropJniMethod: setting result taint to %x", nativeTaint); setReturnTaint(nativeTaint, rtaint, pResult, desc); } }
// TODO optimize localCb == NULL case void dexDecodeDebugInfo( const DexFile* pDexFile, const DexCode* pCode, const char* classDescriptor, u4 protoIdx, u4 accessFlags, DexDebugNewPositionCb posCb, DexDebugNewLocalCb localCb, void* cnxt) { const u1 *stream = dexGetDebugInfoStream(pDexFile, pCode); u4 line; u4 parametersSize; u4 address = 0; LocalInfo localInReg[pCode->registersSize]; u4 insnsSize = pCode->insnsSize; DexProto proto = { pDexFile, protoIdx }; memset(localInReg, 0, sizeof(LocalInfo) * pCode->registersSize); if (stream == NULL) { goto end; } line = readUnsignedLeb128(&stream); parametersSize = readUnsignedLeb128(&stream); u2 argReg = pCode->registersSize - pCode->insSize; if ((accessFlags & ACC_STATIC) == 0) { /* * The code is an instance method, which means that there is * an initial this parameter. Also, the proto list should * contain exactly one fewer argument word than the insSize * indicates. */ assert(pCode->insSize == (dexProtoComputeArgsSize(&proto) + 1)); localInReg[argReg].name = "this"; localInReg[argReg].descriptor = classDescriptor; localInReg[argReg].startAddress = 0; localInReg[argReg].live = true; argReg++; } else { assert(pCode->insSize == dexProtoComputeArgsSize(&proto)); } DexParameterIterator iterator; dexParameterIteratorInit(&iterator, &proto); while (parametersSize-- != 0) { const char* descriptor = dexParameterIteratorNextDescriptor(&iterator); const char *name; int reg; if ((argReg >= pCode->registersSize) || (descriptor == NULL)) { goto invalid_stream; } name = readStringIdx(pDexFile, &stream); reg = argReg; switch (descriptor[0]) { case 'D': case 'J': argReg += 2; break; default: argReg += 1; break; } if (name != NULL) { localInReg[reg].name = name; localInReg[reg].descriptor = descriptor; localInReg[reg].signature = NULL; localInReg[reg].startAddress = address; localInReg[reg].live = true; } } for (;;) { u1 opcode = *stream++; u2 reg; switch (opcode) { case DBG_END_SEQUENCE: goto end; case DBG_ADVANCE_PC: address += readUnsignedLeb128(&stream); break; case DBG_ADVANCE_LINE: line += readSignedLeb128(&stream); break; case DBG_START_LOCAL: case DBG_START_LOCAL_EXTENDED: reg = readUnsignedLeb128(&stream); if (reg > pCode->registersSize) goto invalid_stream; // Emit what was previously there, if anything emitLocalCbIfLive (cnxt, reg, address, localInReg, localCb); localInReg[reg].name = readStringIdx(pDexFile, &stream); localInReg[reg].descriptor = readTypeIdx(pDexFile, &stream); if (opcode == DBG_START_LOCAL_EXTENDED) { localInReg[reg].signature = readStringIdx(pDexFile, &stream); } else { localInReg[reg].signature = NULL; } localInReg[reg].startAddress = address; localInReg[reg].live = true; break; case DBG_END_LOCAL: reg = readUnsignedLeb128(&stream); if (reg > pCode->registersSize) goto invalid_stream; emitLocalCbIfLive (cnxt, reg, address, localInReg, localCb); localInReg[reg].live = false; break; case DBG_RESTART_LOCAL: reg = readUnsignedLeb128(&stream); if (reg > pCode->registersSize) goto invalid_stream; if (localInReg[reg].name == NULL || localInReg[reg].descriptor == NULL) { goto invalid_stream; } /* * If the register is live, the "restart" is superfluous, * and we don't want to mess with the existing start address. */ if (!localInReg[reg].live) { localInReg[reg].startAddress = address; localInReg[reg].live = true; } break; case DBG_SET_PROLOGUE_END: case DBG_SET_EPILOGUE_BEGIN: case DBG_SET_FILE: break; default: { int adjopcode = opcode - DBG_FIRST_SPECIAL; address += adjopcode / DBG_LINE_RANGE; line += DBG_LINE_BASE + (adjopcode % DBG_LINE_RANGE); if (posCb != NULL) { int done; done = posCb(cnxt, address, line); if (done) { // early exit goto end; } } break; } } } end: { int reg; for (reg = 0; reg < pCode->registersSize; reg++) { emitLocalCbIfLive (cnxt, reg, insnsSize, localInReg, localCb); } } return; invalid_stream: IF_LOGE() { char* methodDescriptor = dexProtoCopyMethodDescriptor(&proto); LOGE("Invalid debug info stream. class %s; proto %s", classDescriptor, methodDescriptor); free(methodDescriptor); } }
/* * Common implementation for dexProtoCompareToDescriptor() and * dexProtoCompareToParameterDescriptors(). The descriptor argument * can be either a full method descriptor (with parens and a return * type) or an unadorned concatenation of types (e.g. a list of * argument types). */ static int protoCompareToParameterDescriptors(const DexProto* proto, const char* descriptor, bool expectParens) { char expectedEndChar = expectParens ? ')' : '\0'; DexParameterIterator iterator; dexParameterIteratorInit(&iterator, proto); if (expectParens) { // Skip the '('. assert (*descriptor == '('); descriptor++; } for (;;) { const char* protoDesc = dexParameterIteratorNextDescriptor(&iterator); if (*descriptor == expectedEndChar) { // It's the end of the descriptor string. if (protoDesc == NULL) { // It's also the end of the prototype's arguments. return 0; } else { // The prototype still has more arguments. return 1; } } if (protoDesc == NULL) { /* * The prototype doesn't have arguments left, but the * descriptor string does. */ return -1; } // Both prototype and descriptor have arguments. Compare them. const char* nextDesc = methodDescriptorNextType(descriptor); assert(nextDesc != NULL); for (;;) { char c1 = *(protoDesc++); char c2 = (descriptor < nextDesc) ? *(descriptor++) : '\0'; if (c1 < c2) { // This includes the case where the proto is shorter. return -1; } else if (c1 > c2) { // This includes the case where the desc is shorter. return 1; } else if (c1 == '\0') { // The two types are equal in length. (c2 necessarily == '\0'.) break; } } /* * If we made it here, the two arguments matched, and * descriptor == nextDesc. */ } }
/* * Common implementation for dexProtoCompare() and dexProtoCompareParameters(). */ static int protoCompare(const DexProto* pProto1, const DexProto* pProto2, bool compareReturnType) { if (pProto1 == pProto2) { // Easy out. return 0; } else { #ifdef FASTIVA DexParameterIterator list1; dexParameterIteratorInit(&list1, pProto1); //const DexFile* dexFile1 = pProto1->dexFile; //const DexProtoId* protoId1 = getProtoId(pProto1); //const DexTypeList* typeList1 = // dexGetProtoParameters(dexFile1, protoId1); int paramCount1 = list1.parameterCount; DexParameterIterator list2; dexParameterIteratorInit(&list2, pProto2); //const DexFile* dexFile2 = pProto2->dexFile; //const DexProtoId* protoId2 = getProtoId(pProto2); //const DexTypeList* typeList2 = // dexGetProtoParameters(dexFile2, protoId2); int paramCount2 = list2.parameterCount; // Compare return types. if (compareReturnType) { int result = strcmp(fastiva_dexGetReturnTypeDescriptor(pProto1), fastiva_dexGetReturnTypeDescriptor(pProto2)); if (result != 0) { return result; } } if (list1.parameters == list2.parameters) { // @Zee must after return type comparing. return 0; } // Compare parameters. int minParam = (paramCount1 > paramCount2) ? paramCount2 : paramCount1; int i; for (i = 0; i < minParam; i++) { int result = strcmp(dexParameterIteratorNextDescriptor(&list1), dexParameterIteratorNextDescriptor(&list2)); if (result != 0) { return result; } } #else const DexFile* dexFile1 = pProto1->dexFile; const DexProtoId* protoId1 = getProtoId(pProto1); const DexTypeList* typeList1 = dexGetProtoParameters(dexFile1, protoId1); int paramCount1 = (typeList1 == NULL) ? 0 : typeList1->size; const DexFile* dexFile2 = pProto2->dexFile; const DexProtoId* protoId2 = getProtoId(pProto2); const DexTypeList* typeList2 = dexGetProtoParameters(dexFile2, protoId2); int paramCount2 = (typeList2 == NULL) ? 0 : typeList2->size; if (protoId1 == protoId2) { // Another easy out. return 0; } // Compare return types. if (compareReturnType) { int result = strcmp(dexStringByTypeIdx(dexFile1, protoId1->returnTypeIdx), dexStringByTypeIdx(dexFile2, protoId2->returnTypeIdx)); if (result != 0) { return result; } } // Compare parameters. int minParam = (paramCount1 > paramCount2) ? paramCount2 : paramCount1; int i; for (i = 0; i < minParam; i++) { u4 idx1 = dexTypeListGetIdx(typeList1, i); u4 idx2 = dexTypeListGetIdx(typeList2, i); int result = strcmp(dexStringByTypeIdx(dexFile1, idx1), dexStringByTypeIdx(dexFile2, idx2)); if (result != 0) { return result; } } #endif if (paramCount1 < paramCount2) { return -1; } else if (paramCount1 > paramCount2) { return 1; } else { return 0; } } }