/* * Dump a method. */ void dumpMethod(DexFile* pDexFile, const char* fileName, const DexMethod* pDexMethod, int i) { const DexMethodId* pMethodId; const DexCode* pCode; const char* classDescriptor; const char* methodName; int firstLine; /* abstract and native methods don't get listed */ if (pDexMethod->codeOff == 0) return; pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx); methodName = dexStringById(pDexFile, pMethodId->nameIdx); classDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx); pCode = dexGetCode(pDexFile, pDexMethod); assert(pCode != NULL); /* * If the filename is empty, then set it to something printable * so that it is easier to parse. * * TODO: A method may override its class's default source file by * specifying a different one in its debug info. This possibility * should be handled here. */ if (fileName == NULL || fileName[0] == 0) { fileName = "(none)"; } firstLine = -1; dexDecodeDebugInfo(pDexFile, pCode, classDescriptor, pMethodId->protoIdx, pDexMethod->accessFlags, positionsCallback, NULL, &firstLine); char* className = descriptorToDot(classDescriptor); char* desc = dexCopyDescriptorFromMethodId(pDexFile, pMethodId); u4 insnsOff = pDexMethod->codeOff + offsetof(DexCode, insns); if (gParms.methodToFind != NULL && (strcmp(gParms.classToFind, className) != 0 || strcmp(gParms.methodToFind, methodName) != 0)) { goto skip; } printf("0x%08x %d %s %s %s %s %d\n", insnsOff, pCode->insnsSize * 2, className, methodName, desc, fileName, firstLine); skip: free(desc); free(className); }
/* * Dump a bytecode disassembly. */ void dumpBytecodes(DexFile* pDexFile, const DexMethod* pDexMethod) { const DexCode* pCode = dexGetCode(pDexFile, pDexMethod); const u2* insns; int insnIdx; FieldMethodInfo methInfo; int startAddr; char* className = NULL; assert(pCode->insnsSize > 0); insns = pCode->insns; getMethodInfo(pDexFile, pDexMethod->methodIdx, &methInfo); startAddr = ((u1*)pCode - pDexFile->baseAddr); className = descriptorToDot(methInfo.classDescriptor); printf("%06x: |[%06x] %s.%s:%s\n", startAddr, startAddr, className, methInfo.name, methInfo.signature); insnIdx = 0; while (insnIdx < (int) pCode->insnsSize) { int insnWidth; OpCode opCode; DecodedInstruction decInsn; u2 instr; instr = get2LE((const u1*)insns); if (instr == kPackedSwitchSignature) { insnWidth = 4 + get2LE((const u1*)(insns+1)) * 2; } else if (instr == kSparseSwitchSignature) { insnWidth = 2 + get2LE((const u1*)(insns+1)) * 4; } else if (instr == kArrayDataSignature) { int width = get2LE((const u1*)(insns+1)); int size = get2LE((const u1*)(insns+2)) | (get2LE((const u1*)(insns+3))<<16); // The plus 1 is to round up for odd size and width insnWidth = 4 + ((size * width) + 1) / 2; } else { opCode = instr & 0xff; insnWidth = dexGetInstrWidthAbs(gInstrWidth, opCode); if (insnWidth == 0) { fprintf(stderr, "GLITCH: zero-width instruction at idx=0x%04x\n", insnIdx); break; } } dexDecodeInstruction(gInstrFormat, insns, &decInsn); dumpInstruction(pDexFile, pCode, insnIdx, insnWidth, &decInsn); insns += insnWidth; insnIdx += insnWidth; } free(className); }