/* * Reads a string index as encoded for the debug info format, * returning a string pointer or NULL as appropriate. */ static const char* readStringIdx(const DexFile* pDexFile, const u1** pStream) { u4 stringIdx = readUnsignedLeb128(pStream); // Remember, encoded string indicies have 1 added to them. if (stringIdx == 0) { return NULL; } else { return dexStringById(pDexFile, stringIdx - 1); } }
/* * Get information about a field. */ bool getFieldInfo(DexFile* pDexFile, u4 fieldIdx, FieldMethodInfo* pFieldInfo) { const DexFieldId* pFieldId; if (fieldIdx >= pDexFile->pHeader->fieldIdsSize) return false; pFieldId = dexGetFieldId(pDexFile, fieldIdx); pFieldInfo->name = dexStringById(pDexFile, pFieldId->nameIdx); pFieldInfo->signature = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx); pFieldInfo->classDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->classIdx); return true; }
/* Fill in the configuration Map from config file priority only*/ void dvmDexConfigMap(DvmDex* pDvmDex, DvmConfigMap* pconfigMap){ //ToDo: Handle this exception later if(pDvmDex==NULL) return; if(!pDvmDex->isConfigFile) return; const char* curMethodName =NULL; const char* sensitiveMethodName =NULL; unsigned int priority = 0; const DexClassDef* pDexClassDef = NULL; const DexMethodId* pDexMethodId = NULL; unsigned int methodIdsSize = pDvmDex->pDexFile->pHeader->methodIdsSize; DvmConfigFile* pConfigFile = pDvmDex->pConfigFile; //DvmConfigMap configMap; // it is already set in the previous function so we will access the pointer directly for(int i =0; i<pConfigFile->numSensitiveClasses; i++){ pDexClassDef = dexFindClass(pDvmDex->pDexFile,pConfigFile->sensitiveClasses.at(i).className.c_str() ); if(pDexClassDef==NULL){ ALOGE("dvmDexConfigMap: pDexClassDef == NULL"); return; } unsigned int classIdx = dexGetIndexForClassDef(pDvmDex->pDexFile,pDexClassDef); // ALOGD("dvmDexConfigMap: classIdx:%d",classIdx); //this is correct // 256 //sensitiveClassIdx.push_back(classIdx); //((DexClassDef)(pDvmDex->pDexFile->pClassDefs[classIdx])).isSensitiveClass = 1; // pDvmDex->pDexFile->pClassDefs[classIdx].isSensitiveClass = 1; for(int j=0; j< pConfigFile->sensitiveClasses.at(i).numSensitiveMethods; j++){ sensitiveMethodName = pConfigFile->sensitiveClasses.at(i).sensitiveMethods.at(j).methodName.c_str(); // ALOGD("sensitiveMethodName = %s",sensitiveMethodName); priority = pConfigFile->sensitiveClasses.at(i).sensitiveMethods.at(j).methodparam.priority; // ALOGD("priority =%d",priority ); for(unsigned int methodIdx=0; methodIdx<methodIdsSize; methodIdx++){ pDexMethodId = dexGetMethodId(pDvmDex->pDexFile,methodIdx); curMethodName = dexStringById(pDvmDex->pDexFile, pDexMethodId->nameIdx); //if(curMethodName) ALOGD("curMethodName = %s",curMethodName); if(curMethodName == NULL) return; if(strcmp(curMethodName,sensitiveMethodName) == 0){ pconfigMap->insert(std::make_pair(key(classIdx,methodIdx),priority)); // ALOGD("After mapping"); } } } } }
/* * Get information about a method. */ bool getMethodInfo(DexFile* pDexFile, u4 methodIdx, FieldMethodInfo* pMethInfo) { const DexMethodId* pMethodId; if (methodIdx >= pDexFile->pHeader->methodIdsSize) return false; pMethodId = dexGetMethodId(pDexFile, methodIdx); pMethInfo->name = dexStringById(pDexFile, pMethodId->nameIdx); pMethInfo->signature = dexCopyDescriptorFromMethodId(pDexFile, pMethodId); pMethInfo->classDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx); return true; }
/* Is called from vm/JarFile.cpp*/ void dvmDexConfigMethodMap(DvmDex* pDvmDex, DvmConfigMethodMap* pconfigMethodMap){ //ToDo: Handle this exception later if(pDvmDex==NULL) return; if(!pDvmDex->isConfigFile) return; const char* curMethodName =NULL; const char* sensitiveMethodName =NULL; const DexClassDef* pDexClassDef = NULL; const DexMethodId* pDexMethodId = NULL; unsigned int methodIdsSize = pDvmDex->pDexFile->pHeader->methodIdsSize; DvmConfigFile* pConfigFile = pDvmDex->pConfigFile; for(int i =0; i<pConfigFile->numSensitiveClasses; i++){ pDexClassDef = dexFindClass(pDvmDex->pDexFile,pConfigFile->sensitiveClasses.at(i).className.c_str() ); if(pDexClassDef==NULL){ ALOGE("dvmDexConfigMap: pDexClassDef == NULL"); return; } unsigned int classIdx = dexGetIndexForClassDef(pDvmDex->pDexFile,pDexClassDef); for(int j=0; j< pConfigFile->sensitiveClasses.at(i).numSensitiveMethods; j++){ sensitiveMethodName = pConfigFile->sensitiveClasses.at(i).sensitiveMethods.at(j).methodName.c_str(); for(unsigned int methodIdx=0; methodIdx<methodIdsSize; methodIdx++){ pDexMethodId = dexGetMethodId(pDvmDex->pDexFile,methodIdx); curMethodName = dexStringById(pDvmDex->pDexFile, pDexMethodId->nameIdx); if(curMethodName == NULL) return; if(strcmp(curMethodName,sensitiveMethodName) == 0){ pconfigMethodMap->insert(std::make_pair(key(classIdx,methodIdx), pConfigFile->sensitiveClasses.at(i).sensitiveMethods.at(j).methodparam)); } } } } //DEBUG // if(pDvmDex->pconfigMethodMap!=NULL){ // ALOGD("dvmDexConfigMapMethodDebug"); // if(pDvmDex->pconfigMethodMap==NULL) return; // if(pDvmDex->pconfigMethodMap->size() ==0 ) return; // // ALOGD("dvmDexConfigMapDebug: pDvmConfigMap exists and size = %d",pDvmDex->pconfigMethodMap->size() ); // // for(DvmConfigMethodMapIter it=pDvmDex->pconfigMethodMap->begin(); it!=pDvmDex->pconfigMethodMap->end(); ++it){ // ALOGD("ClassID:%d MethodID:%d ==> tag:%d, priority:%d, powerindex:%d, tempindex:%d, voltindex:%d ",it->first.first, it->first.second, it->second.tag, it->second.priority, it->second.ids.first, it->second.ids.second, it->second.ids.third); // } // } }
/* * Run through all direct and virtual methods in the class. */ void dumpClass(DexFile* pDexFile, int idx) { const DexClassDef* pClassDef; DexClassData* pClassData; const u1* pEncodedData; const char* fileName; int i; pClassDef = dexGetClassDef(pDexFile, idx); pEncodedData = dexGetClassData(pDexFile, pClassDef); pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL); if (pClassData == NULL) { fprintf(stderr, "Trouble reading class data\n"); return; } if (pClassDef->sourceFileIdx == 0xffffffff) { fileName = NULL; } else { fileName = dexStringById(pDexFile, pClassDef->sourceFileIdx); } /* * TODO: Each class def points at a sourceFile, so maybe that * should be printed out. However, this needs to be coordinated * with the tools that parse this output. */ for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) { dumpMethod(pDexFile, fileName, &pClassData->directMethods[i], i); } for (i = 0; i < (int) pClassData->header.virtualMethodsSize; i++) { dumpMethod(pDexFile, fileName, &pClassData->virtualMethods[i], i); } free(pClassData); }
/* * Dump an instance field. */ void dumpIField(const DexFile* pDexFile, const DexField* pIField, int i) { const DexFieldId* pFieldId; const char* backDescriptor; const char* name; const char* typeDescriptor; char* accessStr; pFieldId = dexGetFieldId(pDexFile, pIField->fieldIdx); name = dexStringById(pDexFile, pFieldId->nameIdx); typeDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx); backDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->classIdx); accessStr = createAccessFlagStr(pIField->accessFlags, kAccessForField); printf(" #%d : (in %s)\n", i, backDescriptor); printf(" name : '%s'\n", name); printf(" type : '%s'\n", typeDescriptor); printf(" access : 0x%04x (%s)\n", pIField->accessFlags, accessStr); free(accessStr); }
/* * Dump a method. */ void dumpMethod(DexFile* pDexFile, const DexMethod* pDexMethod, int i) { const DexMethodId* pMethodId; const char* backDescriptor; const char* name; char* typeDescriptor; char* accessStr; pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx); name = dexStringById(pDexFile, pMethodId->nameIdx); typeDescriptor = dexCopyDescriptorFromMethodId(pDexFile, pMethodId); backDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx); accessStr = createAccessFlagStr(pDexMethod->accessFlags, kAccessForMethod); printf(" #%d : (in %s)\n", i, backDescriptor); printf(" name : '%s'\n", name); printf(" type : '%s'\n", typeDescriptor); printf(" access : 0x%04x (%s)\n", pDexMethod->accessFlags, accessStr); if (pDexMethod->codeOff == 0) { printf(" code : (none)\n"); } else { printf(" code -\n"); dumpCode(pDexFile, pDexMethod); } if (gOptions.disassemble) putchar('\n'); free(typeDescriptor); free(accessStr); }
// Based on dvmResolveMethod. static void preloadDexCachesResolveMethod(DvmDex* pDvmDex, uint32_t methodIdx, MethodType methodType) { Method* method = dvmDexGetResolvedMethod(pDvmDex, methodIdx); if (method != NULL) { return; } const DexFile* pDexFile = pDvmDex->pDexFile; const DexMethodId* pMethodId = dexGetMethodId(pDexFile, methodIdx); ClassObject* clazz = dvmDexGetResolvedClass(pDvmDex, pMethodId->classIdx); if (clazz == NULL) { return; } // Skip static methods for uninitialized classes because a filled // cache entry implies the class is initialized. if ((methodType == METHOD_STATIC) && !dvmIsClassInitialized(clazz)) { return; } const char* methodName = dexStringById(pDexFile, pMethodId->nameIdx); DexProto proto; dexProtoSetFromMethodId(&proto, pDexFile, pMethodId); if (methodType == METHOD_DIRECT) { method = dvmFindDirectMethod(clazz, methodName, &proto); } else if (methodType == METHOD_STATIC) { method = dvmFindDirectMethodHier(clazz, methodName, &proto); } else { method = dvmFindVirtualMethodHier(clazz, methodName, &proto); } if (method == NULL) { return; } // ALOGI("VMRuntime.preloadDexCaches found method %s.%s", // clazz->descriptor, methodName); dvmDexSetResolvedMethod(pDvmDex, methodIdx, method); }
/* * Get the descriptor string associated with a given type index. * The caller should not free() the returned string. */ DEX_INLINE const char* dexStringByTypeIdx(const DexFile* pDexFile, u4 idx) { const DexTypeId* typeId = dexGetTypeId(pDexFile, idx); return dexStringById(pDexFile, typeId->descriptorIdx); }
//Dump LIR stmts stored in fu->lirList array. void dump_lir2(LIR * lir, DexFile * df, INT pos) { if (g_tfile == NULL || lir == NULL) return; if (pos < 0) { fprintf(g_tfile, "%s", LIR_name(lir)); } else { fprintf(g_tfile, "(%dth)%s", pos, LIR_name(lir)); } switch (LIR_opcode(lir)) { case LOP_NOP: break; case LOP_CONST: switch (LIR_dt(lir)) { case LIR_JDT_unknown: fprintf(g_tfile, ", INT"); if (is_s4(LIR_int_imm(lir)) && LIR_res(lir) < 16) { //AB fprintf(g_tfile, ", v%d <- %d", LIR_res(lir), (INT)LIR_int_imm(lir)); } else if (is_s16(LIR_int_imm(lir))) { //AABBBB fprintf(g_tfile, ", v%d <- %d", LIR_res(lir), (INT)LIR_int_imm(lir)); } else { //AABBBBBBBB fprintf(g_tfile, ", v%d <- %d", LIR_res(lir), (INT)LIR_int_imm(lir)); } break; case LIR_JDT_wide: fprintf(g_tfile, ", %s", get_dt_name(lir)); if (is_swide16(LIR_int_imm(lir))) { //AABBBB fprintf(g_tfile, ", (v%d,v%d) <- %d", LIR_res(lir), LIR_res(lir) + 1, (INT)LIR_int_imm(lir)); } else if (is_swide32(LIR_int_imm(lir))) { //AABBBBBBBB fprintf(g_tfile, ", (v%d,v%d) <- %d", LIR_res(lir), LIR_res(lir) + 1, (INT)LIR_int_imm(lir)); } else { //AABBBBBBBBBBBBBBBB fprintf(g_tfile, ", (v%d,v%d) <- %lld", LIR_res(lir), LIR_res(lir) + 1, LIR_int_imm(lir)); } break; default: /* It seems dex does not distinguish float and integer const. And regard float as 32bit integer, double will be 64bit integer. */ IS_TRUE0(0); } break; case LOP_RETURN: { switch (LIR_dt(lir)) { case LIR_JDT_unknown: //return preg. fprintf(g_tfile, ", INT"); fprintf(g_tfile, ", v%d", LIR_res(lir)); break; case LIR_JDT_void: //No return value. break; case LIR_JDT_object: //return object. fprintf(g_tfile, ", obj_ptr:v%d", LIR_res(lir)); break; case LIR_JDT_wide: fprintf(g_tfile, ", %s", get_dt_name(lir)); fprintf(g_tfile, ", (v%d,v%d)", LIR_res(lir), LIR_res(lir) + 1); break; default: IS_TRUE0(0); } } break; case LOP_THROW: //AA //Throws an exception object. //The reference of the exception object is in vx. fprintf(g_tfile, ", v%d", LIR_res(lir)); break; case LOP_MONITOR_ENTER : fprintf(g_tfile, ", v%d", LIR_res(lir)); break; case LOP_MONITOR_EXIT : break; case LOP_MOVE_RESULT : { //Move function return value to regisiter. //AA LIRAOp * p = (LIRAOp*)lir; switch (LIR_dt(lir)) { case LIR_JDT_unknown: //lexOpcode = lc_mov_result32; break; fprintf(g_tfile, ", INT"); fprintf(g_tfile, ", retval -> v%d", LIR_res(lir)); break; case LIR_JDT_wide: //lexOpcode = lc_mov_result64; break; fprintf(g_tfile, ", %s", get_dt_name(lir)); fprintf(g_tfile, ", retval -> (v%d,v%d)", LIR_res(lir), LIR_res(lir) + 1); break; case LIR_JDT_object: //lexOpcode = lc_mov_result_object; break; fprintf(g_tfile, ", obj-ptr"); fprintf(g_tfile, ", retval -> v%d", LIR_res(lir)); break; } } break; case LOP_MOVE_EXCEPTION : //AA fprintf(g_tfile, ", v%d", LIR_res(lir)); break; case LOP_GOTO : //AABBBBBBBB { LIRGOTOOp * p = (LIRGOTOOp*)lir; fprintf(g_tfile, ", (lirIdx)%dth", p->target); } break; case LOP_MOVE : switch (LIR_dt(lir)) { case LIR_JDT_unknown: fprintf(g_tfile, ", INT"); if ((LIR_op0(lir) | LIR_res(lir)) < 16) { //AB fprintf(g_tfile, ", v%d <- v%d", LIR_res(lir), LIR_op0(lir)); } else if (LIR_res(lir) < 256) { //AABBBB fprintf(g_tfile, ", v%d <- v%d", LIR_res(lir), LIR_op0(lir)); } else { //AAAABBBB fprintf(g_tfile, ", v%d <- v%d", LIR_res(lir), LIR_op0(lir)); } break; case LIR_JDT_wide: fprintf(g_tfile, ", %s", get_dt_name(lir)); if ((LIR_op0(lir) | LIR_res(lir)) < 16) { //AB fprintf(g_tfile, ", (v%d,v%d) <- (v%d,v%d)", LIR_res(lir), LIR_res(lir) + 1, LIR_op0(lir), LIR_op0(lir) + 1); } else if (LIR_res(lir) < 256) { //AABBBB fprintf(g_tfile, ", (v%d,v%d) <- (v%d,v%d)", LIR_res(lir), LIR_res(lir) + 1, LIR_op0(lir), LIR_op0(lir) + 1); } else { //AAAABBBB fprintf(g_tfile, ", (v%d,v%d) <- (v%d,v%d)", LIR_res(lir), LIR_res(lir) + 1, LIR_op0(lir), LIR_op0(lir) + 1); } break; case LIR_JDT_object: fprintf(g_tfile, ", obj-ptr"); if ((LIR_op0(lir) | LIR_res(lir)) < 16) { //AB fprintf(g_tfile, ", v%d <- v%d", LIR_res(lir), LIR_op0(lir)); } else if (LIR_res(lir) < 256) { //AABBBB fprintf(g_tfile, ", v%d <- v%d", LIR_res(lir), LIR_op0(lir)); } else { //AAAABBBB fprintf(g_tfile, ", v%d <- v%d", LIR_res(lir), LIR_op0(lir)); } break; } break; case LOP_NEG : //AB case LOP_NOT : //AB fprintf(g_tfile, ", %s", get_dt_name(lir)); if (is_wide(lir)) { fprintf(g_tfile, ", (v%d,v%d) <- (v%d,v%d)", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir), LIR_op0(lir)+1); } else { fprintf(g_tfile, ", v%d <- v%d", LIR_res(lir), LIR_op0(lir)); } break; case LOP_CONVERT : //AB switch (LIR_dt(lir)) { case LIR_convert_i2l: fprintf(g_tfile, ", INT->LONG"); fprintf(g_tfile, ", (v%d,v%d) <- v%d", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir)); break; case LIR_convert_i2f: fprintf(g_tfile, ", INT->FLOAT"); break; case LIR_convert_i2d: fprintf(g_tfile, ", INT->DOUBLE"); fprintf(g_tfile, ", (v%d,v%d) <- v%d", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir)); break; case LIR_convert_l2i: fprintf(g_tfile, ", LONG->INT"); fprintf(g_tfile, ", v%d <- (v%d,v%d)", LIR_res(lir), LIR_op0(lir), LIR_op0(lir)+1); break; case LIR_convert_l2f: fprintf(g_tfile, ", LONG->FLOAT"); fprintf(g_tfile, ", v%d <- (v%d,v%d)", LIR_res(lir), LIR_op0(lir), LIR_op0(lir)+1); break; case LIR_convert_l2d: fprintf(g_tfile, ", LONG->DOUBLE"); fprintf(g_tfile, ", (v%d,v%d) <- (v%d,v%d)", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir), LIR_op0(lir)+1); break; case LIR_convert_f2i: fprintf(g_tfile, ", FLOAT->INT"); break; case LIR_convert_f2l: fprintf(g_tfile, ", FLOAT->LONG"); fprintf(g_tfile, ", (v%d,v%d) <- v%d", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir)); break; case LIR_convert_f2d: fprintf(g_tfile, ", FLOAT->DOUBLE"); fprintf(g_tfile, ", (v%d,v%d) <- v%d", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir)); break; case LIR_convert_d2i: fprintf(g_tfile, ", DOUBLE->INT"); fprintf(g_tfile, ", v%d <- (v%d,v%d)", LIR_res(lir), LIR_op0(lir), LIR_op0(lir)+1); break; case LIR_convert_d2l: fprintf(g_tfile, ", DOUBLE->LONG"); fprintf(g_tfile, ", (v%d,v%d) <- (v%d,v%d)", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir), LIR_op0(lir)+1); break; case LIR_convert_d2f: fprintf(g_tfile, ", DOUBLE->FLOAT"); fprintf(g_tfile, ", v%d <- (v%d,v%d)", LIR_res(lir), LIR_op0(lir), LIR_op0(lir)+1); break; case LIR_convert_i2b: fprintf(g_tfile, ", INT->BOOL"); fprintf(g_tfile, ", v%d <- v%d", LIR_res(lir), LIR_op0(lir)); break; case LIR_convert_i2c: fprintf(g_tfile, ", INT->CHAR"); fprintf(g_tfile, ", v%d <- v%d", LIR_res(lir), LIR_op0(lir)); break; case LIR_convert_i2s: fprintf(g_tfile, ", INT->SHORT"); fprintf(g_tfile, ", v%d <- v%d", LIR_res(lir), LIR_op0(lir)); break; default: IS_TRUE0(0); } break; case LOP_ADD_ASSIGN : case LOP_SUB_ASSIGN : case LOP_MUL_ASSIGN : case LOP_DIV_ASSIGN : case LOP_REM_ASSIGN : case LOP_AND_ASSIGN : case LOP_OR_ASSIGN : case LOP_XOR_ASSIGN : case LOP_SHL_ASSIGN : case LOP_SHR_ASSIGN : case LOP_USHR_ASSIGN: fprintf(g_tfile, ", %s", get_dt_name(lir)); if (is_wide(lir)) { fprintf(g_tfile, ", (v%d,v%d) <- (v%d,v%d), (v%d,v%d)", LIR_res(lir), LIR_res(lir)+1, LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir), LIR_op0(lir)+1); } else { fprintf(g_tfile, ", v%d <- v%d, v%d", LIR_res(lir), LIR_res(lir), LIR_op0(lir)); } break; case LOP_ARRAY_LENGTH: //AABBBB //Calculates the number of elements of the array referenced by vy //and puts the length value into vx. fprintf(g_tfile, ", v%d <- v%d", LIR_res(lir), LIR_op0(lir)); break; case LOP_IFZ : //AABBBB switch (LIR_dt(lir)) { case LIR_cond_EQ: fprintf(g_tfile, ", =="); break; case LIR_cond_NE: fprintf(g_tfile, ", !="); break; case LIR_cond_LT: fprintf(g_tfile, ", <"); break; case LIR_cond_GE: fprintf(g_tfile, ", >="); break; case LIR_cond_GT: fprintf(g_tfile, ", >"); break; case LIR_cond_LE: fprintf(g_tfile, ", <="); break; } if (is_wide(lir)) { fprintf(g_tfile, ", (v%d,v%d), 0, (lirIdx)%dth", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir)); } else { fprintf(g_tfile, ", v%d, 0, (lirIdx)%dth", LIR_res(lir), LIR_op0(lir)); } break; case LOP_NEW_INSTANCE: //AABBBB //LIR_op0(lir) is class-type-id, not class-declaration-id. IS_TRUE0(df); fprintf(g_tfile, ", (obj_ptr)v%d <- (clsname<%d>)%s", LIR_res(lir), LIR_op0(lir), get_class_name(df, LIR_op0(lir))); break; case LOP_CONST_STRING: //AABBBB or AABBBBBBBB IS_TRUE0(df); fprintf(g_tfile, ", v%d <- (strofst<%d>)\"%s\"", LIR_res(lir), LIR_op0(lir), dexStringById(df, LIR_op0(lir))); break; case LOP_CONST_CLASS : //AABBBB //const-class vx,type_id //Moves the class object of a class identified by //type_id (e.g. Object.class) into vx. fprintf(g_tfile, ", v%d <- (clsname<%d>)%s", LIR_res(lir), LIR_op0(lir), dexStringByTypeIdx(df, LIR_op0(lir))); break; case LOP_SGET : //AABBBB fprintf(g_tfile, ", %s", get_dt_name(lir)); IS_TRUE0(df); fprintf(g_tfile, ", v%d <- (ofst<%d>)%s::%s", LIR_res(lir), LIR_op0(lir), get_field_class_name(df, LIR_op0(lir)), get_field_name(df, LIR_op0(lir))); break; case LOP_CHECK_CAST : //AABBBB IS_TRUE0(df); fprintf(g_tfile, ", v%d '%s'", LIR_res(lir), dexStringByTypeIdx(df, LIR_op0(lir))); break; case LOP_SPUT : { //AABBBB LIRABOp * p = (LIRABOp*)lir; fprintf(g_tfile, ", %s", get_dt_name(lir)); IS_TRUE0(df); if (is_wide(lir)) { fprintf(g_tfile, ", (v%d,v%d) -> %s::%s", LIR_res(lir), LIR_res(lir)+1, get_field_class_name(df, LIR_op0(lir)), get_field_name(df, LIR_op0(lir))); } else { fprintf(g_tfile, ", v%d -> %s::%s", LIR_res(lir), get_field_class_name(df, LIR_op0(lir)), get_field_name(df, LIR_op0(lir))); } } break; case LOP_APUT : //AABBCC fprintf(g_tfile, ", %s", get_dt_name(lir)); IS_TRUE0(df); if (is_wide(lir)) { fprintf(g_tfile, ", (v%d,v%d) -> (array_base_ptr)v%d, (array_elem)v%d", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir), (UINT)LIR_op1(lir)); } else { fprintf(g_tfile, ", v%d -> (array_base_ptr)v%d, (array_elem)v%d", LIR_res(lir), LIR_op0(lir), (UINT)LIR_op1(lir)); } break; case LOP_AGET : //AABBCC fprintf(g_tfile, ", %s", get_dt_name(lir)); IS_TRUE0(df); if (is_wide(lir)) { fprintf(g_tfile, ", (v%d,v%d) <- (array_base_ptr)v%d, (array_elem)v%d", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir), (UINT)LIR_op1(lir)); } else { fprintf(g_tfile, ", v%d <- (array_base_ptr)v%d, (array_elem)v%d", LIR_res(lir), LIR_op0(lir), (UINT)LIR_op1(lir)); } break; case LOP_CMPL : case LOP_CMP_LONG : //AABBCC IS_TRUE0(df); switch (LIR_dt(lir)) { case LIR_CMP_float: fprintf(g_tfile, ", FLOAT"); fprintf(g_tfile, ", v%d, v%d, %d", LIR_res(lir), LIR_op0(lir), (UINT)LIR_op1(lir)); break; case LIR_CMP_double: fprintf(g_tfile, ", DOUBLE"); fprintf(g_tfile, ", (v%d,v%d), (v%d,v%d), %d", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir), LIR_op0(lir)+1, (UINT)LIR_op1(lir)); break; default: IS_TRUE0(0); } break; case LOP_ADD : case LOP_SUB : case LOP_MUL : case LOP_DIV : case LOP_REM : case LOP_AND : case LOP_OR : case LOP_XOR : case LOP_SHL : case LOP_SHR : case LOP_USHR : { fprintf(g_tfile, ", %s", get_dt_name(lir)); LIRABCOp * p = (LIRABCOp*)lir; if (is_wide(lir)) { fprintf(g_tfile, ", (v%d,v%d) <- (v%d,v%d), (v%d,v%d)", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir), LIR_op0(lir)+1, (UINT)LIR_op1(lir), (UINT)LIR_op1(lir)+1); } else { fprintf(g_tfile, ", v%d <- v%d, v%d", LIR_res(lir), LIR_op0(lir), (UINT)LIR_op1(lir)); } } break; case LOP_IF : //ABCCCC switch (LIR_dt(lir)) { case LIR_cond_EQ: fprintf(g_tfile, ", =="); break; case LIR_cond_NE: fprintf(g_tfile, ", !="); break; case LIR_cond_LT: fprintf(g_tfile, ", <"); break; case LIR_cond_GE: fprintf(g_tfile, ", >="); break; case LIR_cond_GT: fprintf(g_tfile, ", >"); break; case LIR_cond_LE: fprintf(g_tfile, ", <="); break; } fprintf(g_tfile, ", v%d, v%d, (lirIdx)%dth", LIR_res(lir), LIR_op0(lir), (UINT)LIR_op1(lir)); break; case LOP_ADD_LIT : //AABBCC, AABBCCCC case LOP_SUB_LIT : //AABBCC, AABBCCCC case LOP_MUL_LIT : //AABBCC, AABBCCCC case LOP_DIV_LIT : //AABBCC, AABBCCCC case LOP_REM_LIT : //AABBCC, AABBCCCC case LOP_AND_LIT : //AABBCC, AABBCCCC case LOP_OR_LIT : //AABBCC, AABBCCCC case LOP_XOR_LIT : //AABBCC, AABBCCCC case LOP_SHL_LIT : //AABBCC case LOP_SHR_LIT : //AABBCC case LOP_USHR_LIT : //AABBCC { fprintf(g_tfile, ", %s", get_dt_name(lir)); LIRABCOp * p = (LIRABCOp*)lir; if (is_wide(lir)) { fprintf(g_tfile, ", (v%d,v%d) <- (v%d,v%d),", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir), LIR_op0(lir)+1); } else { fprintf(g_tfile, ", v%d <- v%d,", LIR_res(lir), LIR_op0(lir)); } if (is_s8((INT)LIR_op1(lir))) { //8bit imm fprintf(g_tfile, "(lit8)%d", (INT)LIR_op1(lir)); } else if (is_s16((INT)LIR_op1(lir))) { //16bit imm fprintf(g_tfile, "(lit16)%d", (INT)LIR_op1(lir)); } else { IS_TRUE0(0); } } break; case LOP_IPUT : fprintf(g_tfile, ", %s", get_dt_name(lir)); //ABCCCC IS_TRUE0(df); if (is_wide(lir)) { fprintf(g_tfile, ", (v%d,v%d) -> (obj_ptr)v%d, (ofst<%d>)%s::%s", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir), (UINT)LIR_op1(lir), get_field_class_name(df, (UINT)LIR_op1(lir)), get_field_name(df, (UINT)LIR_op1(lir))); } else { fprintf(g_tfile, ", v%d -> (obj_ptr)v%d, (ofst<%d>)%s::%s", LIR_res(lir), LIR_op0(lir), (UINT)LIR_op1(lir), get_field_class_name(df, (UINT)LIR_op1(lir)), get_field_name(df, (UINT)LIR_op1(lir))); } break; case LOP_IGET : fprintf(g_tfile, ", %s", get_dt_name(lir)); //ABCCCC IS_TRUE0(df); if (is_wide(lir)) { fprintf(g_tfile, ", (v%d,v%d) <- (obj_ptr)v%d, (ofst<%d>)%s::%s", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir), (UINT)LIR_op1(lir), get_field_class_name(df, (UINT)LIR_op1(lir)), get_field_name(df, (UINT)LIR_op1(lir))); } else { fprintf(g_tfile, ", v%d <- (obj_ptr)v%d, (ofst<%d>)%s::%s", LIR_res(lir), LIR_op0(lir), (UINT)LIR_op1(lir), get_field_class_name(df, (UINT)LIR_op1(lir)), get_field_name(df, (UINT)LIR_op1(lir))); } break; case LOP_INSTANCE_OF: fprintf(g_tfile, ", (pred)v%d <- v%d, (clsname<%d>)'%s'", LIR_res(lir), LIR_op0(lir), (UINT)LIR_op1(lir), dexStringByTypeIdx(df, (UINT)LIR_op1(lir))); break; case LOP_NEW_ARRAY : //ABCCCC //new-array v%d(res) <- v%d(op0), LCAnimal(op1) fprintf(g_tfile, ", %s", get_dt_name(lir)); //ABCCCC IS_TRUE0(df); fprintf(g_tfile, ", v%d <- (num_of_elem)v%d, (elem_type<%d>)'%s'", LIR_res(lir), LIR_op0(lir), (UINT)LIR_op1(lir), dexStringByTypeIdx(df, (UINT)LIR_op1(lir))); break; case LOP_TABLE_SWITCH: { LIRSwitchOp * p = (LIRSwitchOp*)lir; IS_TRUE0(LIR_dt(p) == 0x1); fprintf(g_tfile, ", v%d", p->value); USHORT * pdata = p->data; //data[0]: flag to indicate switch-table type: // 0x1 TABLE_SWITCH, 0x2 LOOKUP_SWITCH USHORT f = pdata[0]; IS_TRUE0(f == 0x100); //data[1]: the number of CASE entry. USHORT num_of_case = pdata[1]; //data[2..3]: the base value of case-table UINT base_val = *((UINT*)(&pdata[2])); fprintf(g_tfile, ", basev:%d", base_val); //((BYTE*)data)[4..num_of_case*4]: // the position of the index table is at current instruction. if (num_of_case > 0) { UINT * pcase_entry = (UINT*)&pdata[4]; fprintf(g_tfile, " tgtidx:"); for (USHORT i = 0; i < num_of_case; i++) { UINT idx_of_insn = pcase_entry[i]; fprintf(g_tfile, "%d", idx_of_insn); if (i != num_of_case - 1) { fprintf(g_tfile, ","); } } } } break; case LOP_LOOKUP_SWITCH: { LIRSwitchOp * p = (LIRSwitchOp*)lir; IS_TRUE0(LIR_dt(p) == 0x2); fprintf(g_tfile, ", v%d", p->value); USHORT * pdata = p->data; //pdata[0]: flag to indicate switch-table type: // 0x1 TABLE_SWITCH, 0x2 LOOKUP_SWITCH UINT f = pdata[0]; IS_TRUE0(f == 0x200); //pdata[1]: the number of CASE entry. UINT num_of_case = pdata[1]; if (num_of_case > 0) { BYTE * tp = (BYTE*)pdata; //((BYTE*)pdata)[4..4+num_of_case*4-1]: the case-value buffer. UINT * pcase_value = (UINT*)&tp[4]; //((BYTE*)pdata)[4+num_of_case*4, 4+num_of_case*8-1]: // the position of the index table is at current instruction. UINT * pcase_entry = (UINT*)&tp[4 + num_of_case * 4]; fprintf(g_tfile, " val2idx("); for (UINT i = 0; i < num_of_case; i++) { UINT idx_of_insn = pcase_entry[i]; fprintf(g_tfile, "%d:%d", pcase_value[i], idx_of_insn); if (i != num_of_case - 1) { fprintf(g_tfile, ","); } } fprintf(g_tfile, ")"); } } break; case LOP_FILL_ARRAY_DATA: { fprintf(g_tfile, ", %s", get_dt_name(lir)); //AABBBBBBBB //pdata[0]: the magic number of code //0x100 PACKED_SWITCH, 0x200 SPARSE_SWITCH, 0x300 FILL_ARRAY_DATA LIRSwitchOp * r = (LIRSwitchOp*)lir; UInt16 const* pdata = (UInt16 const*)r->data; IS_TRUE0(pdata[0] == 0x300); //pdata[1]: size of each element. //pdata[2]: the number of element. UINT size_of_elem = pdata[1]; UINT num_of_elem = pdata[2]; UINT data_size = num_of_elem * size_of_elem; //fprintf(g_tfile, ", (elem_sz<%d>), (elem_num<%d>), (data_ptr)0x%x", fprintf(g_tfile, ", (elem_sz<%d>), (elem_num<%d>)", size_of_elem, num_of_elem); } break; case LOP_INVOKE: { /* ABCCCCDDDD the layout clarifies: A(p4), B(argc), CCCC(method_id), DDDD(p0, p1, p2, p3) where p0,p1,p2,p3,p4 are five parameters. AABBBBCCCC the layout clarifies: AA(argc), BBBB(method_id), CCCC(p0,p1,...p(argc-1)) */ LIRInvokeOp * r = (LIRInvokeOp*)lir; UINT flags = LIR_dt(lir); UINT flag1 = flags & 0x0F; UINT flag2 = flags & 0xF0; IS_TRUE(flag1 != 0, ("means LIR is LOP_FILLED_NEW_ARRAY")); DexMethodId const* method_id = dexGetMethodId(df, r->ref); IS_TRUE0(method_id); CHAR const* method_name = dexStringById(df, method_id->nameIdx); CHAR const* class_name = dexStringByTypeIdx(df, method_id->classIdx); IS_TRUE0(method_name); DexProtoId const* proto_id = dexGetProtoId(df, method_id->protoIdx); CHAR const* shorty_name = dexStringById(df, proto_id->shortyIdx); fprintf(g_tfile, ", %s::%s", class_name, method_name); UINT k = LIR_dt(lir); bool is_range = HAVE_FLAG((k & 0xf0), LIR_Range); if (is_range) { switch (k & 0x0f) { case LIR_invoke_unknown: IS_TRUE0(0); break; case LIR_invoke_virtual: fprintf(g_tfile, ", virtual-range"); break; case LIR_invoke_direct: fprintf(g_tfile, ", direct-range"); break; case LIR_invoke_super: fprintf(g_tfile, ", super-range"); break; case LIR_invoke_interface: fprintf(g_tfile, ", interface-range"); break; case LIR_invoke_static: fprintf(g_tfile, ", static-range"); break; default: IS_TRUE0(0); } } else { switch (k & 0x0f) { case LIR_invoke_unknown: IS_TRUE0(0); break; case LIR_invoke_virtual: fprintf(g_tfile, ", virtual"); break; case LIR_invoke_direct: fprintf(g_tfile, ", direct"); break; case LIR_invoke_super: fprintf(g_tfile, ", super"); break; case LIR_invoke_interface: fprintf(g_tfile, ", interface"); break; case LIR_invoke_static: fprintf(g_tfile, ", static"); break; default: IS_TRUE0(0); } } if (r->argc != 0) { fprintf(g_tfile, ", arg("); for (USHORT i = 0; i < r->argc; i++) { fprintf(g_tfile, "v%d", r->args[i]); if (i != r->argc-1) { fprintf(g_tfile, ","); } } fprintf(g_tfile, ")"); } } break; case LOP_FILLED_NEW_ARRAY: { /* AABBBBCCCC or ABCCCCDEFG e.g: A(argc), B,D,E,F,G(parampters), CCCC(class_tyid) */ LIRInvokeOp * r = (LIRInvokeOp*)lir; UINT flags = LIR_dt(lir); CHAR const* class_name = dexStringByTypeIdx(df, r->ref); IS_TRUE0(class_name); fprintf(g_tfile, ", %s", class_name); if (r->argc != 0) { fprintf(g_tfile, ", arg("); for (USHORT i = 0; i < r->argc; i++) { fprintf(g_tfile, "v%d", r->args[i]); if (i != r->argc-1) { fprintf(g_tfile, ","); } } fprintf(g_tfile, ")"); } } break; case LOP_CMPG: //AABBCC IS_TRUE0(df); switch (LIR_dt(lir)) { case LIR_CMP_float: fprintf(g_tfile, ", FLOAT"); fprintf(g_tfile, ", v%d, v%d, %d", LIR_res(lir), LIR_op0(lir), (INT)LIR_op1(lir)); break; case LIR_CMP_double: fprintf(g_tfile, ", DOUBLE"); fprintf(g_tfile, ", (v%d,v%d), v%d, %d", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir), (INT)LIR_op1(lir)); break; default: IS_TRUE0(0); } break; case LOP_PHI: IS_TRUE0(0); break; default: IS_TRUE0(0); } //end switch fflush(g_tfile); }
/* * Dump a single instruction. */ void dumpInstruction(DexFile* pDexFile, const DexCode* pCode, int insnIdx, int insnWidth, const DecodedInstruction* pDecInsn) { static const float gSpecialTab[16] = { -2.0f, -1.0f, -0.5f, -0.25f, -0.1f, 0.1f, 0.25f, 0.5f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 10.0f, 100.0f, 1000.0f }; const u2* insns = pCode->insns; int i; printf("%06x:", ((u1*)insns - pDexFile->baseAddr) + insnIdx*2); for (i = 0; i < 8; i++) { if (i < insnWidth) { if (i == 7) { printf(" ... "); } else { /* print 16-bit value in little-endian order */ const u1* bytePtr = (const u1*) &insns[insnIdx+i]; printf(" %02x%02x", bytePtr[0], bytePtr[1]); } } else { fputs(" ", stdout); } } if (pDecInsn->opCode == OP_NOP) { u2 instr = get2LE((const u1*) &insns[insnIdx]); if (instr == kPackedSwitchSignature) { printf("|%04x: packed-switch-data (%d units)", insnIdx, insnWidth); } else if (instr == kSparseSwitchSignature) { printf("|%04x: sparse-switch-data (%d units)", insnIdx, insnWidth); } else if (instr == kArrayDataSignature) { printf("|%04x: array-data (%d units)", insnIdx, insnWidth); } else { printf("|%04x: nop // spacer", insnIdx); } } else { printf("|%04x: %s", insnIdx, getOpcodeName(pDecInsn->opCode)); } switch (dexGetInstrFormat(gInstrFormat, pDecInsn->opCode)) { case kFmt10x: // op break; case kFmt12x: // op vA, vB printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB); break; case kFmt11n: // op vA, #+B printf(" v%d, #int %d // #%x", pDecInsn->vA, (s4)pDecInsn->vB, (u1)pDecInsn->vB); break; case kFmt11x: // op vAA printf(" v%d", pDecInsn->vA); break; case kFmt10t: // op +AA case kFmt20t: // op +AAAA { s4 targ = (s4) pDecInsn->vA; printf(" %04x // %c%04x", insnIdx + targ, (targ < 0) ? '-' : '+', (targ < 0) ? -targ : targ); } break; case kFmt22x: // op vAA, vBBBB printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB); break; case kFmt21t: // op vAA, +BBBB { s4 targ = (s4) pDecInsn->vB; printf(" v%d, %04x // %c%04x", pDecInsn->vA, insnIdx + targ, (targ < 0) ? '-' : '+', (targ < 0) ? -targ : targ); } break; case kFmt21s: // op vAA, #+BBBB printf(" v%d, #int %d // #%x", pDecInsn->vA, (s4)pDecInsn->vB, (u2)pDecInsn->vB); break; case kFmt21h: // op vAA, #+BBBB0000[00000000] // The printed format varies a bit based on the actual opcode. if (pDecInsn->opCode == OP_CONST_HIGH16) { s4 value = pDecInsn->vB << 16; printf(" v%d, #int %d // #%x", pDecInsn->vA, value, (u2)pDecInsn->vB); } else { s8 value = ((s8) pDecInsn->vB) << 48; printf(" v%d, #long %lld // #%x", pDecInsn->vA, value, (u2)pDecInsn->vB); } break; case kFmt21c: // op vAA, thing@BBBB if (pDecInsn->opCode == OP_CONST_STRING) { printf(" v%d, \"%s\" // string@%04x", pDecInsn->vA, dexStringById(pDexFile, pDecInsn->vB), pDecInsn->vB); } else if (pDecInsn->opCode == OP_CHECK_CAST || pDecInsn->opCode == OP_NEW_INSTANCE || pDecInsn->opCode == OP_CONST_CLASS) { printf(" v%d, %s // class@%04x", pDecInsn->vA, getClassDescriptor(pDexFile, pDecInsn->vB), pDecInsn->vB); } else /* OP_SGET* */ { FieldMethodInfo fieldInfo; if (getFieldInfo(pDexFile, pDecInsn->vB, &fieldInfo)) { printf(" v%d, %s.%s:%s // field@%04x", pDecInsn->vA, fieldInfo.classDescriptor, fieldInfo.name, fieldInfo.signature, pDecInsn->vB); } else { printf(" v%d, ??? // field@%04x", pDecInsn->vA, pDecInsn->vB); } } break; case kFmt23x: // op vAA, vBB, vCC printf(" v%d, v%d, v%d", pDecInsn->vA, pDecInsn->vB, pDecInsn->vC); break; case kFmt22b: // op vAA, vBB, #+CC printf(" v%d, v%d, #int %d // #%02x", pDecInsn->vA, pDecInsn->vB, (s4)pDecInsn->vC, (u1)pDecInsn->vC); break; case kFmt22t: // op vA, vB, +CCCC { s4 targ = (s4) pDecInsn->vC; printf(" v%d, v%d, %04x // %c%04x", pDecInsn->vA, pDecInsn->vB, insnIdx + targ, (targ < 0) ? '-' : '+', (targ < 0) ? -targ : targ); } break; case kFmt22s: // op vA, vB, #+CCCC printf(" v%d, v%d, #int %d // #%04x", pDecInsn->vA, pDecInsn->vB, (s4)pDecInsn->vC, (u2)pDecInsn->vC); break; case kFmt22c: // op vA, vB, thing@CCCC if (pDecInsn->opCode >= OP_IGET && pDecInsn->opCode <= OP_IPUT_SHORT) { FieldMethodInfo fieldInfo; if (getFieldInfo(pDexFile, pDecInsn->vC, &fieldInfo)) { printf(" v%d, v%d, %s.%s:%s // field@%04x", pDecInsn->vA, pDecInsn->vB, fieldInfo.classDescriptor, fieldInfo.name, fieldInfo.signature, pDecInsn->vC); } else { printf(" v%d, v%d, ??? // field@%04x", pDecInsn->vA, pDecInsn->vB, pDecInsn->vC); } } else { printf(" v%d, v%d, %s // class@%04x", pDecInsn->vA, pDecInsn->vB, getClassDescriptor(pDexFile, pDecInsn->vC), pDecInsn->vC); } break; case kFmt22cs: // [opt] op vA, vB, field offset CCCC printf(" v%d, v%d, [obj+%04x]", pDecInsn->vA, pDecInsn->vB, pDecInsn->vC); break; case kFmt30t: printf(" #%08x", pDecInsn->vA); break; case kFmt31i: // op vAA, #+BBBBBBBB { /* this is often, but not always, a float */ union { float f; u4 i; } conv; conv.i = pDecInsn->vB; printf(" v%d, #float %f // #%08x", pDecInsn->vA, conv.f, pDecInsn->vB); } break; case kFmt31c: // op vAA, thing@BBBBBBBB printf(" v%d, \"%s\" // string@%08x", pDecInsn->vA, dexStringById(pDexFile, pDecInsn->vB), pDecInsn->vB); break; case kFmt31t: // op vAA, offset +BBBBBBBB printf(" v%d, %08x // +%08x", pDecInsn->vA, insnIdx + pDecInsn->vB, pDecInsn->vB); break; case kFmt32x: // op vAAAA, vBBBB printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB); break; case kFmt35c: // op vB, {vD, vE, vF, vG, vA}, thing@CCCC { /* NOTE: decoding of 35c doesn't quite match spec */ fputs(" {", stdout); for (i = 0; i < (int) pDecInsn->vA; i++) { if (i == 0) printf("v%d", pDecInsn->arg[i]); else printf(", v%d", pDecInsn->arg[i]); } if (pDecInsn->opCode == OP_FILLED_NEW_ARRAY) { printf("}, %s // class@%04x", getClassDescriptor(pDexFile, pDecInsn->vB), pDecInsn->vB); } else { FieldMethodInfo methInfo; if (getMethodInfo(pDexFile, pDecInsn->vB, &methInfo)) { printf("}, %s.%s:%s // method@%04x", methInfo.classDescriptor, methInfo.name, methInfo.signature, pDecInsn->vB); } else { printf("}, ??? // method@%04x", pDecInsn->vB); } } } break; case kFmt35ms: // [opt] invoke-virtual+super case kFmt35fs: // [opt] invoke-interface { fputs(" {", stdout); for (i = 0; i < (int) pDecInsn->vA; i++) { if (i == 0) printf("v%d", pDecInsn->arg[i]); else printf(", v%d", pDecInsn->arg[i]); } printf("}, [%04x] // vtable #%04x", pDecInsn->vB, pDecInsn->vB); } break; case kFmt3rc: // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB { /* * This doesn't match the "dx" output when some of the args are * 64-bit values -- dx only shows the first register. */ fputs(" {", stdout); for (i = 0; i < (int) pDecInsn->vA; i++) { if (i == 0) printf("v%d", pDecInsn->vC + i); else printf(", v%d", pDecInsn->vC + i); } if (pDecInsn->opCode == OP_FILLED_NEW_ARRAY_RANGE) { printf("}, %s // class@%04x", getClassDescriptor(pDexFile, pDecInsn->vB), pDecInsn->vB); } else { FieldMethodInfo methInfo; if (getMethodInfo(pDexFile, pDecInsn->vB, &methInfo)) { printf("}, %s.%s:%s // method@%04x", methInfo.classDescriptor, methInfo.name, methInfo.signature, pDecInsn->vB); } else { printf("}, ??? // method@%04x", pDecInsn->vB); } } } break; case kFmt3rms: // [opt] invoke-virtual+super/range case kFmt3rfs: // [opt] invoke-interface/range { /* * This doesn't match the "dx" output when some of the args are * 64-bit values -- dx only shows the first register. */ fputs(" {", stdout); for (i = 0; i < (int) pDecInsn->vA; i++) { if (i == 0) printf("v%d", pDecInsn->vC + i); else printf(", v%d", pDecInsn->vC + i); } printf("}, [%04x] // vtable #%04x", pDecInsn->vB, pDecInsn->vB); } break; case kFmt3inline: // [opt] inline invoke { #if 0 const InlineOperation* inlineOpsTable = dvmGetInlineOpsTable(); u4 tableLen = dvmGetInlineOpsTableLength(); #endif fputs(" {", stdout); for (i = 0; i < (int) pDecInsn->vA; i++) { if (i == 0) printf("v%d", pDecInsn->arg[i]); else printf(", v%d", pDecInsn->arg[i]); } #if 0 if (pDecInsn->vB < tableLen) { printf("}, %s.%s:%s // inline #%04x", inlineOpsTable[pDecInsn->vB].classDescriptor, inlineOpsTable[pDecInsn->vB].methodName, inlineOpsTable[pDecInsn->vB].methodSignature, pDecInsn->vB); } else { #endif printf("}, [%04x] // inline #%04x", pDecInsn->vB, pDecInsn->vB); #if 0 } #endif } break; case kFmt51l: // op vAA, #+BBBBBBBBBBBBBBBB { /* this is often, but not always, a double */ union { double d; u8 j; } conv; conv.j = pDecInsn->vB_wide; printf(" v%d, #double %f // #%016llx", pDecInsn->vA, conv.d, pDecInsn->vB_wide); } break; case kFmtUnknown: break; default: printf(" ???"); break; } putchar('\n'); }
CHAR const* get_func_name(DexFile * df, DexMethod const* dm) { IS_TRUE0(df && dm); DexMethodId const* pMethodId = dexGetMethodId(df, dm->methodIdx); return dexStringById(df, pMethodId->nameIdx); }
// //START AOC_DX_MGR // CHAR const* AOC_DX_MGR::get_string(UINT str_idx) { return dexStringById(m_df, str_idx); }
/* * Alternate version of dvmResolveInstField(). * * On failure, returns NULL, and sets *pFailure if pFailure is not NULL. */ InstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx, VerifyError* pFailure) { DvmDex* pDvmDex = referrer->pDvmDex; InstField* resField; resField = (InstField*) dvmDexGetResolvedField(pDvmDex, ifieldIdx); if (resField == NULL) { const DexFieldId* pFieldId; ClassObject* resClass; pFieldId = dexGetFieldId(pDvmDex->pDexFile, ifieldIdx); /* * Find the field's class. */ resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure); if (resClass == NULL) { //dvmClearOptException(dvmThreadSelf()); assert(!dvmCheckException(dvmThreadSelf())); if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); } return NULL; } resField = (InstField*)dvmFindFieldHier(resClass, dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx), dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx)); if (resField == NULL) { ALOGD("DexOpt: couldn't find field %s.%s", resClass->descriptor, dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx)); if (pFailure != NULL) *pFailure = VERIFY_ERROR_NO_FIELD; return NULL; } if (dvmIsStaticField(resField)) { ALOGD("DexOpt: wanted instance, got static for field %s.%s", resClass->descriptor, dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx)); if (pFailure != NULL) *pFailure = VERIFY_ERROR_CLASS_CHANGE; return NULL; } /* * Add it to the resolved table so we're faster on the next lookup. */ dvmDexSetResolvedField(pDvmDex, ifieldIdx, (Field*) resField); } /* access allowed? */ tweakLoader(referrer, resField->clazz); bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField); untweakLoader(referrer, resField->clazz); if (!allowed) { ALOGI("DexOpt: access denied from %s to field %s.%s", referrer->descriptor, resField->clazz->descriptor, resField->name); if (pFailure != NULL) *pFailure = VERIFY_ERROR_ACCESS_FIELD; return NULL; } return resField; }
/* * Dump the class. */ void dumpClass(DexFile* pDexFile, int idx) { const DexTypeList* pInterfaces; const DexClassDef* pClassDef; DexClassData* pClassData; const u1* pEncodedData; const char* fileName; const char* classDescriptor; const char* superclassDescriptor; char* accessStr; int i; pClassDef = dexGetClassDef(pDexFile, idx); printf("Class #%d -\n", idx); pEncodedData = dexGetClassData(pDexFile, pClassDef); pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL); if (pClassData == NULL) { printf("Trouble reading class data\n"); return; } classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx); printf(" Class descriptor : '%s'\n", classDescriptor); accessStr = createAccessFlagStr(pClassDef->accessFlags, kAccessForClass); printf(" Access flags : 0x%04x (%s)\n", pClassDef->accessFlags, accessStr); if (pClassDef->superclassIdx == kDexNoIndex) superclassDescriptor = "(none)"; else { superclassDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->superclassIdx); printf(" Superclass : '%s'\n", superclassDescriptor); } printf(" Interfaces -\n"); pInterfaces = dexGetInterfacesList(pDexFile, pClassDef); if (pInterfaces != NULL) { for (i = 0; i < (int) pInterfaces->size; i++) dumpInterface(pDexFile, dexGetTypeItem(pInterfaces, i), i); } printf(" Static fields -\n"); for (i = 0; i < (int) pClassData->header.staticFieldsSize; i++) { dumpSField(pDexFile, &pClassData->staticFields[i], i); } printf(" Instance fields -\n"); for (i = 0; i < (int) pClassData->header.instanceFieldsSize; i++) { dumpIField(pDexFile, &pClassData->instanceFields[i], i); } printf(" Direct methods -\n"); for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) { dumpMethod(pDexFile, &pClassData->directMethods[i], i); } printf(" Virtual methods -\n"); for (i = 0; i < (int) pClassData->header.virtualMethodsSize; i++) { dumpMethod(pDexFile, &pClassData->virtualMethods[i], i); } // TODO: Annotations. if (pClassDef->sourceFileIdx != kDexNoIndex) fileName = dexStringById(pDexFile, pClassDef->sourceFileIdx); else fileName = "unknown"; printf(" source_file_idx : %d (%s)\n", pClassDef->sourceFileIdx, fileName); printf("\n"); free(pClassData); free(accessStr); }
/* (documented in header file) */ const char* dexProtoGetShorty(const DexProto* pProto) { const DexProtoId* protoId = getProtoId(pProto); return dexStringById(pProto->dexFile, protoId->shortyIdx); }
/* * Resolve an interface method reference. * * Returns NULL with an exception raised on failure. */ Method* dvmResolveInterfaceMethod(const ClassObject* referrer, u4 methodIdx) { DvmDex* pDvmDex = referrer->pDvmDex; ClassObject* resClass; const DexMethodId* pMethodId; Method* resMethod; int i; LOGVV("--- resolving interface method %d (referrer=%s)\n", methodIdx, referrer->descriptor); pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx); resClass = dvmResolveClass(referrer, pMethodId->classIdx, false); if (resClass == NULL) { /* can't find the class that the method is a part of */ assert(dvmCheckException(dvmThreadSelf())); return NULL; } if (!dvmIsInterfaceClass(resClass)) { /* whoops */ dvmThrowExceptionWithClassMessage( "Ljava/lang/IncompatibleClassChangeError;", resClass->descriptor); return NULL; } /* * This is the first time the method has been resolved. Set it in our * resolved-method structure. It always resolves to the same thing, * so looking it up and storing it doesn't create a race condition. * * If we scan into the interface's superclass -- which is always * java/lang/Object -- we will catch things like: * interface I ... * I myobj = (something that implements I) * myobj.hashCode() * However, the Method->methodIndex will be an offset into clazz->vtable, * rather than an offset into clazz->iftable. The invoke-interface * code can test to see if the method returned is abstract or concrete, * and use methodIndex accordingly. I'm not doing this yet because * (a) we waste time in an unusual case, and (b) we're probably going * to fix it in the DEX optimizer. * * We do need to scan the superinterfaces, in case we're invoking a * superinterface method on an interface reference. The class in the * DexTypeId is for the static type of the object, not the class in * which the method is first defined. We have the full, flattened * list in "iftable". */ const char* methodName = dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx); DexProto proto; dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId); LOGVV("+++ looking for '%s' '%s' in resClass='%s'\n", methodName, methodSig, resClass->descriptor); resMethod = dvmFindVirtualMethod(resClass, methodName, &proto); if (resMethod == NULL) { LOGVV("+++ did not resolve immediately\n"); for (i = 0; i < resClass->iftableCount; i++) { resMethod = dvmFindVirtualMethod(resClass->iftable[i].clazz, methodName, &proto); if (resMethod != NULL) break; } if (resMethod == NULL) { dvmThrowException("Ljava/lang/NoSuchMethodError;", methodName); return NULL; } } else { LOGVV("+++ resolved immediately: %s (%s %d)\n", resMethod->name, resMethod->clazz->descriptor, (u4) resMethod->methodIndex); } LOGVV("--- found interface method %d (%s.%s)\n", methodIdx, resClass->descriptor, resMethod->name); /* we're expecting this to be abstract */ assert(dvmIsAbstractMethod(resMethod)); /* interface methods are always public; no need to check access */ /* * The interface class *may* be initialized. According to VM spec * v2 2.17.4, the interfaces a class refers to "need not" be initialized * when the class is initialized. * * It isn't necessary for an interface class to be initialized before * we resolve methods on that interface. * * We choose not to do the initialization now. */ //assert(dvmIsClassInitialized(resMethod->clazz)); /* * The class is initialized, the method has been found. Add a pointer * to our data structure so we don't have to jump through the hoops again. */ dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod); return resMethod; }
/* * Find the method corresponding to "methodRef". * * We use "referrer" to find the DexFile with the constant pool that * "methodRef" is an index into. We also use its class loader. The method * being resolved may very well be in a different DEX file. * * If this is a static method, we ensure that the method's class is * initialized. */ Method* dvmResolveMethod(const ClassObject* referrer, u4 methodIdx, MethodType methodType) { DvmDex* pDvmDex = referrer->pDvmDex; ClassObject* resClass; const DexMethodId* pMethodId; Method* resMethod; assert(methodType != METHOD_INTERFACE); LOGVV("--- resolving method %u (referrer=%s)\n", methodIdx, referrer->descriptor); pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx); resClass = dvmResolveClass(referrer, pMethodId->classIdx, false); if (resClass == NULL) { /* can't find the class that the method is a part of */ assert(dvmCheckException(dvmThreadSelf())); return NULL; } if (dvmIsInterfaceClass(resClass)) { /* method is part of an interface */ dvmThrowExceptionWithClassMessage( "Ljava/lang/IncompatibleClassChangeError;", resClass->descriptor); return NULL; } const char* name = dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx); DexProto proto; dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId); /* * We need to chase up the class hierarchy to find methods defined * in super-classes. (We only want to check the current class * if we're looking for a constructor; since DIRECT calls are only * for constructors and private methods, we don't want to walk up.) */ if (methodType == METHOD_DIRECT) { resMethod = dvmFindDirectMethod(resClass, name, &proto); } else if (methodType == METHOD_STATIC) { resMethod = dvmFindDirectMethodHier(resClass, name, &proto); } else { resMethod = dvmFindVirtualMethodHier(resClass, name, &proto); } if (resMethod == NULL) { dvmThrowException("Ljava/lang/NoSuchMethodError;", name); return NULL; } LOGVV("--- found method %d (%s.%s)\n", methodIdx, resClass->descriptor, resMethod->name); /* see if this is a pure-abstract method */ if (dvmIsAbstractMethod(resMethod) && !dvmIsAbstractClass(resClass)) { dvmThrowException("Ljava/lang/AbstractMethodError;", name); return NULL; } /* * If we're the first to resolve this class, we need to initialize * it now. Only necessary for METHOD_STATIC. */ if (methodType == METHOD_STATIC) { if (!dvmIsClassInitialized(resMethod->clazz) && !dvmInitClass(resMethod->clazz)) { assert(dvmCheckException(dvmThreadSelf())); return NULL; } else { assert(!dvmCheckException(dvmThreadSelf())); } } else { /* * Edge case: if the <clinit> for a class creates an instance * of itself, we will call <init> on a class that is still being * initialized by us. */ assert(dvmIsClassInitialized(resMethod->clazz) || dvmIsClassInitializing(resMethod->clazz)); } /* * The class is initialized, the method has been found. Add a pointer * to our data structure so we don't have to jump through the hoops again. */ dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod); return resMethod; }
/* * Alternate version of dvmResolveStaticField(). * * Does not force initialization of the resolved field's class. * * On failure, returns NULL, and sets *pFailure if pFailure is not NULL. */ StaticField* dvmOptResolveStaticField(ClassObject* referrer, u4 sfieldIdx, VerifyError* pFailure) { DvmDex* pDvmDex = referrer->pDvmDex; StaticField* resField; resField = (StaticField*)dvmDexGetResolvedField(pDvmDex, sfieldIdx); if (resField == NULL) { const DexFieldId* pFieldId; ClassObject* resClass; pFieldId = dexGetFieldId(pDvmDex->pDexFile, sfieldIdx); /* * Find the field's class. */ resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure); if (resClass == NULL) { //dvmClearOptException(dvmThreadSelf()); assert(!dvmCheckException(dvmThreadSelf())); if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); } return NULL; } const char* fieldName = dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx); resField = (StaticField*)dvmFindFieldHier(resClass, fieldName, dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx)); if (resField == NULL) { ALOGD("DexOpt: couldn't find static field %s.%s", resClass->descriptor, fieldName); if (pFailure != NULL) *pFailure = VERIFY_ERROR_NO_FIELD; return NULL; } if (!dvmIsStaticField(resField)) { ALOGD("DexOpt: wanted static, got instance for field %s.%s", resClass->descriptor, fieldName); if (pFailure != NULL) *pFailure = VERIFY_ERROR_CLASS_CHANGE; return NULL; } /* * Add it to the resolved table so we're faster on the next lookup. * * We can only do this if we're in "dexopt", because the presence * of a valid value in the resolution table implies that the class * containing the static field has been initialized. */ if (gDvm.optimizing) dvmDexSetResolvedField(pDvmDex, sfieldIdx, (Field*) resField); } /* access allowed? */ tweakLoader(referrer, resField->clazz); bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField); untweakLoader(referrer, resField->clazz); if (!allowed) { ALOGI("DexOpt: access denied from %s to field %s.%s", referrer->descriptor, resField->clazz->descriptor, resField->name); if (pFailure != NULL) *pFailure = VERIFY_ERROR_ACCESS_FIELD; return NULL; } return resField; }
/* * Alternate version of dvmResolveMethod(). * * Doesn't throw exceptions, and checks access on every lookup. * * On failure, returns NULL, and sets *pFailure if pFailure is not NULL. */ Method* dvmOptResolveMethod(ClassObject* referrer, u4 methodIdx, MethodType methodType, VerifyError* pFailure) { DvmDex* pDvmDex = referrer->pDvmDex; Method* resMethod; assert(methodType == METHOD_DIRECT || methodType == METHOD_VIRTUAL || methodType == METHOD_STATIC); LOGVV("--- resolving method %u (referrer=%s)", methodIdx, referrer->descriptor); resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx); if (resMethod == NULL) { const DexMethodId* pMethodId; ClassObject* resClass; pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx); resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, pFailure); if (resClass == NULL) { /* * Can't find the class that the method is a part of, or don't * have permission to access the class. */ ALOGV("DexOpt: can't find called method's class (?.%s)", dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx)); if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); } return NULL; } if (dvmIsInterfaceClass(resClass)) { /* method is part of an interface; this is wrong method for that */ ALOGW("DexOpt: method is in an interface"); if (pFailure != NULL) *pFailure = VERIFY_ERROR_GENERIC; return NULL; } /* * We need to chase up the class hierarchy to find methods defined * in super-classes. (We only want to check the current class * if we're looking for a constructor.) */ DexProto proto; dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId); if (methodType == METHOD_DIRECT) { resMethod = dvmFindDirectMethod(resClass, dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto); } else { /* METHOD_STATIC or METHOD_VIRTUAL */ resMethod = dvmFindMethodHier(resClass, dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto); } if (resMethod == NULL) { ALOGV("DexOpt: couldn't find method '%s'", dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx)); if (pFailure != NULL) *pFailure = VERIFY_ERROR_NO_METHOD; return NULL; } if (methodType == METHOD_STATIC) { if (!dvmIsStaticMethod(resMethod)) { ALOGD("DexOpt: wanted static, got instance for method %s.%s", resClass->descriptor, resMethod->name); if (pFailure != NULL) *pFailure = VERIFY_ERROR_CLASS_CHANGE; return NULL; } } else if (methodType == METHOD_VIRTUAL) { if (dvmIsStaticMethod(resMethod)) { ALOGD("DexOpt: wanted instance, got static for method %s.%s", resClass->descriptor, resMethod->name); if (pFailure != NULL) *pFailure = VERIFY_ERROR_CLASS_CHANGE; return NULL; } } /* see if this is a pure-abstract method */ if (dvmIsAbstractMethod(resMethod) && !dvmIsAbstractClass(resClass)) { ALOGW("DexOpt: pure-abstract method '%s' in %s", dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), resClass->descriptor); if (pFailure != NULL) *pFailure = VERIFY_ERROR_GENERIC; return NULL; } /* * Add it to the resolved table so we're faster on the next lookup. * * We can only do this for static methods if we're not in "dexopt", * because the presence of a valid value in the resolution table * implies that the class containing the static field has been * initialized. */ if (methodType != METHOD_STATIC || gDvm.optimizing) dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod); } LOGVV("--- found method %d (%s.%s)", methodIdx, resMethod->clazz->descriptor, resMethod->name); /* access allowed? */ tweakLoader(referrer, resMethod->clazz); bool allowed = dvmCheckMethodAccess(referrer, resMethod); untweakLoader(referrer, resMethod->clazz); if (!allowed) { IF_ALOGI() { char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype); ALOGI("DexOpt: illegal method access (call %s.%s %s from %s)", resMethod->clazz->descriptor, resMethod->name, desc, referrer->descriptor); free(desc); }