Search in sources :

Example 1 with Opcodes

use of org.jf.dexlib2.Opcodes in project smali by JesusFreke.

the class DebugInfoItem method makeAnnotator.

@Nonnull
public static SectionAnnotator makeAnnotator(@Nonnull DexAnnotator annotator, @Nonnull MapItem mapItem) {
    return new SectionAnnotator(annotator, mapItem) {

        @Nonnull
        @Override
        public String getItemName() {
            return "debug_info_item";
        }

        @Override
        public void annotateItem(@Nonnull AnnotatedBytes out, int itemIndex, @Nullable String itemIdentity) {
            DexReader reader = dexFile.readerAt(out.getCursor());
            int lineStart = reader.readSmallUleb128();
            out.annotateTo(reader.getOffset(), "line_start = %d", lineStart);
            int parametersSize = reader.readSmallUleb128();
            out.annotateTo(reader.getOffset(), "parameters_size = %d", parametersSize);
            if (parametersSize > 0) {
                out.annotate(0, "parameters:");
                out.indent();
                for (int i = 0; i < parametersSize; i++) {
                    int paramaterIndex = reader.readSmallUleb128() - 1;
                    out.annotateTo(reader.getOffset(), "%s", StringIdItem.getOptionalReferenceAnnotation(dexFile, paramaterIndex, true));
                }
                out.deindent();
            }
            out.annotate(0, "debug opcodes:");
            out.indent();
            int codeAddress = 0;
            int lineNumber = lineStart;
            loop: while (true) {
                int opcode = reader.readUbyte();
                switch(opcode) {
                    case DebugItemType.END_SEQUENCE:
                        {
                            out.annotateTo(reader.getOffset(), "DBG_END_SEQUENCE");
                            break loop;
                        }
                    case DebugItemType.ADVANCE_PC:
                        {
                            out.annotateTo(reader.getOffset(), "DBG_ADVANCE_PC");
                            out.indent();
                            int addressDiff = reader.readSmallUleb128();
                            codeAddress += addressDiff;
                            out.annotateTo(reader.getOffset(), "addr_diff = +0x%x: 0x%x", addressDiff, codeAddress);
                            out.deindent();
                            break;
                        }
                    case DebugItemType.ADVANCE_LINE:
                        {
                            out.annotateTo(reader.getOffset(), "DBG_ADVANCE_LINE");
                            out.indent();
                            int lineDiff = reader.readSleb128();
                            lineNumber += lineDiff;
                            out.annotateTo(reader.getOffset(), "line_diff = +%d: %d", Math.abs(lineDiff), lineNumber);
                            out.deindent();
                            break;
                        }
                    case DebugItemType.START_LOCAL:
                        {
                            out.annotateTo(reader.getOffset(), "DBG_START_LOCAL");
                            out.indent();
                            int registerNum = reader.readSmallUleb128();
                            out.annotateTo(reader.getOffset(), "register_num = v%d", registerNum);
                            int nameIndex = reader.readSmallUleb128() - 1;
                            out.annotateTo(reader.getOffset(), "name_idx = %s", StringIdItem.getOptionalReferenceAnnotation(dexFile, nameIndex, true));
                            int typeIndex = reader.readSmallUleb128() - 1;
                            out.annotateTo(reader.getOffset(), "type_idx = %s", TypeIdItem.getOptionalReferenceAnnotation(dexFile, typeIndex));
                            out.deindent();
                            break;
                        }
                    case DebugItemType.START_LOCAL_EXTENDED:
                        {
                            out.annotateTo(reader.getOffset(), "DBG_START_LOCAL_EXTENDED");
                            out.indent();
                            int registerNum = reader.readSmallUleb128();
                            out.annotateTo(reader.getOffset(), "register_num = v%d", registerNum);
                            int nameIndex = reader.readSmallUleb128() - 1;
                            out.annotateTo(reader.getOffset(), "name_idx = %s", StringIdItem.getOptionalReferenceAnnotation(dexFile, nameIndex, true));
                            int typeIndex = reader.readSmallUleb128() - 1;
                            out.annotateTo(reader.getOffset(), "type_idx = %s", TypeIdItem.getOptionalReferenceAnnotation(dexFile, typeIndex));
                            int sigIndex = reader.readSmallUleb128() - 1;
                            out.annotateTo(reader.getOffset(), "sig_idx = %s", StringIdItem.getOptionalReferenceAnnotation(dexFile, sigIndex, true));
                            out.deindent();
                            break;
                        }
                    case DebugItemType.END_LOCAL:
                        {
                            out.annotateTo(reader.getOffset(), "DBG_END_LOCAL");
                            out.indent();
                            int registerNum = reader.readSmallUleb128();
                            out.annotateTo(reader.getOffset(), "register_num = v%d", registerNum);
                            out.deindent();
                            break;
                        }
                    case DebugItemType.RESTART_LOCAL:
                        {
                            out.annotateTo(reader.getOffset(), "DBG_RESTART_LOCAL");
                            out.indent();
                            int registerNum = reader.readSmallUleb128();
                            out.annotateTo(reader.getOffset(), "register_num = v%d", registerNum);
                            out.deindent();
                            break;
                        }
                    case DebugItemType.PROLOGUE_END:
                        {
                            out.annotateTo(reader.getOffset(), "DBG_SET_PROLOGUE_END");
                            break;
                        }
                    case DebugItemType.EPILOGUE_BEGIN:
                        {
                            out.annotateTo(reader.getOffset(), "DBG_SET_EPILOGUE_BEGIN");
                            break;
                        }
                    case DebugItemType.SET_SOURCE_FILE:
                        {
                            out.annotateTo(reader.getOffset(), "DBG_SET_FILE");
                            out.indent();
                            int nameIdx = reader.readSmallUleb128() - 1;
                            out.annotateTo(reader.getOffset(), "name_idx = %s", StringIdItem.getOptionalReferenceAnnotation(dexFile, nameIdx));
                            out.deindent();
                            break;
                        }
                    default:
                        int adjusted = opcode - 0x0A;
                        int addressDiff = adjusted / 15;
                        int lineDiff = (adjusted % 15) - 4;
                        codeAddress += addressDiff;
                        lineNumber += lineDiff;
                        out.annotateTo(reader.getOffset(), "address_diff = +0x%x:0x%x, line_diff = +%d:%d, ", addressDiff, codeAddress, lineDiff, lineNumber);
                        break;
                }
            }
            out.deindent();
        }
    };
}
Also used : DexReader(org.jf.dexlib2.dexbacked.DexReader) Nonnull(javax.annotation.Nonnull) AnnotatedBytes(org.jf.dexlib2.util.AnnotatedBytes) Nullable(javax.annotation.Nullable) Nonnull(javax.annotation.Nonnull)

Example 2 with Opcodes

use of org.jf.dexlib2.Opcodes in project smali by JesusFreke.

the class AnalysisArguments method loadClassPathForDexFile.

@Nonnull
public ClassPath loadClassPathForDexFile(@Nonnull File dexFileDir, @Nonnull DexFile dexFile, boolean checkPackagePrivateAccess, int oatVersion) throws IOException {
    ClassPathResolver resolver;
    // regardless of the actual version of the oat file
    if (oatVersion == NOT_ART) {
        if (dexFile instanceof OatDexFile) {
            checkPackagePrivateAccess = true;
            oatVersion = ((OatDexFile) dexFile).getContainer().getOatVersion();
        }
    } else {
        // this should always be true for ART
        checkPackagePrivateAccess = true;
    }
    if (classPathDirectories == null || classPathDirectories.size() == 0) {
        classPathDirectories = Lists.newArrayList(dexFileDir.getPath());
    }
    List<String> filteredClassPathDirectories = Lists.newArrayList();
    if (classPathDirectories != null) {
        for (String dir : classPathDirectories) {
            File file = new File(dir);
            if (!file.exists()) {
                System.err.println(String.format("Warning: directory %s does not exist. Ignoring.", dir));
            } else if (!file.isDirectory()) {
                System.err.println(String.format("Warning: %s is not a directory. Ignoring.", dir));
            } else {
                filteredClassPathDirectories.add(dir);
            }
        }
    }
    if (bootClassPath == null) {
        // TODO: we should be able to get the api from the Opcodes object associated with the dexFile..
        // except that the oat version -> api mapping doesn't fully work yet
        resolver = new ClassPathResolver(filteredClassPathDirectories, classPath, dexFile);
    } else if (bootClassPath.size() == 1 && bootClassPath.get(0).length() == 0) {
        // --bootclasspath "" is a special case, denoting that no bootclasspath should be used
        resolver = new ClassPathResolver(ImmutableList.<String>of(), ImmutableList.<String>of(), classPath, dexFile);
    } else {
        resolver = new ClassPathResolver(filteredClassPathDirectories, bootClassPath, classPath, dexFile);
    }
    if (oatVersion == 0 && dexFile instanceof OatDexFile) {
        oatVersion = ((OatDexFile) dexFile).getContainer().getOatVersion();
    }
    return new ClassPath(resolver.getResolvedClassProviders(), checkPackagePrivateAccess, oatVersion);
}
Also used : ClassPath(org.jf.dexlib2.analysis.ClassPath) ClassPathResolver(org.jf.dexlib2.analysis.ClassPathResolver) OatDexFile(org.jf.dexlib2.dexbacked.OatFile.OatDexFile) File(java.io.File) DexFile(org.jf.dexlib2.iface.DexFile) OatDexFile(org.jf.dexlib2.dexbacked.OatFile.OatDexFile) Nonnull(javax.annotation.Nonnull)

Example 3 with Opcodes

use of org.jf.dexlib2.Opcodes in project dex2jar by pxb1988.

the class SmaliTest method dotest.

private void dotest(File dexFile) throws IOException {
    DexBackedDexFile dex = DexFileFactory.loadDexFile(dexFile, 14, false);
    Map<String, DexClassNode> map = readDex(dexFile);
    for (DexBackedClassDef def : dex.getClasses()) {
        String type = def.getType();
        System.out.println(type);
        DexClassNode dexClassNode = map.get(type);
        Assert.assertNotNull(dexClassNode);
        // original
        String smali = baksmali(def);
        Smali.smaliFile2Node("fake.smali", smali);
        {
            byte[] data = toDex(dexClassNode);
            DexBackedClassDef def2 = new DexBackedDexFile(new Opcodes(14, false), data).getClasses().iterator().next();
            // original
            String baksmali3 = baksmali(def2);
            Assert.assertEquals(smali, baksmali3);
        }
        String psmali = pbaksmali(dexClassNode);
        DexClassNode dexClassNode2 = Smali.smaliFile2Node("fake.smali", psmali);
        Assert.assertEquals("cmp smalip", psmali, pbaksmali(dexClassNode2));
        {
            byte[] data = toDex(dexClassNode2);
            DexBackedClassDef def2 = new DexBackedDexFile(new Opcodes(14, false), data).getClasses().iterator().next();
            // original
            String baksmali3 = baksmali(def2);
            Assert.assertEquals(smali, baksmali3);
        }
    }
}
Also used : DexClassNode(com.googlecode.d2j.node.DexClassNode) DexBackedDexFile(org.jf.dexlib2.dexbacked.DexBackedDexFile) Opcodes(org.jf.dexlib2.Opcodes) DexBackedClassDef(org.jf.dexlib2.dexbacked.DexBackedClassDef)

Example 4 with Opcodes

use of org.jf.dexlib2.Opcodes in project smali by JesusFreke.

the class DexFileFactory method loadDexContainer.

/**
     * Loads a file containing 1 or more dex files
     *
     * If the given file is a dex or odex file, it will return a MultiDexContainer containing that single entry.
     * Otherwise, for an oat or zip file, it will return an OatFile or ZipDexContainer respectively.
     *
     * @param file The file to open
     * @param opcodes The set of opcodes to use
     * @return A MultiDexContainer
     * @throws DexFileNotFoundException If the given file does not exist
     * @throws UnsupportedFileTypeException If the given file is not a valid dex/zip/odex/oat file
     */
public static MultiDexContainer<? extends DexBackedDexFile> loadDexContainer(@Nonnull File file, @Nonnull final Opcodes opcodes) throws IOException {
    if (!file.exists()) {
        throw new DexFileNotFoundException("%s does not exist", file.getName());
    }
    ZipDexContainer zipDexContainer = new ZipDexContainer(file, opcodes);
    if (zipDexContainer.isZipFile()) {
        return zipDexContainer;
    }
    InputStream inputStream = new BufferedInputStream(new FileInputStream(file));
    try {
        try {
            DexBackedDexFile dexFile = DexBackedDexFile.fromInputStream(opcodes, inputStream);
            return new SingletonMultiDexContainer(file.getPath(), dexFile);
        } catch (DexBackedDexFile.NotADexFile ex) {
        // just eat it
        }
        try {
            DexBackedOdexFile odexFile = DexBackedOdexFile.fromInputStream(opcodes, inputStream);
            return new SingletonMultiDexContainer(file.getPath(), odexFile);
        } catch (DexBackedOdexFile.NotAnOdexFile ex) {
        // just eat it
        }
        // Note: DexBackedDexFile.fromInputStream and DexBackedOdexFile.fromInputStream will reset inputStream
        // back to the same position, if they fails
        OatFile oatFile = null;
        try {
            oatFile = OatFile.fromInputStream(inputStream);
        } catch (NotAnOatFileException ex) {
        // just eat it
        }
        if (oatFile != null) {
            // TODO: we should support loading earlier oat files, just not deodexing them
            if (oatFile.isSupportedVersion() == OatFile.UNSUPPORTED) {
                throw new UnsupportedOatVersionException(oatFile);
            }
            return oatFile;
        }
    } finally {
        inputStream.close();
    }
    throw new UnsupportedFileTypeException("%s is not an apk, dex, odex or oat file.", file.getPath());
}
Also used : NotAnOatFileException(org.jf.dexlib2.dexbacked.OatFile.NotAnOatFileException) DexBackedDexFile(org.jf.dexlib2.dexbacked.DexBackedDexFile) OatFile(org.jf.dexlib2.dexbacked.OatFile) NotADexFile(org.jf.dexlib2.dexbacked.DexBackedDexFile.NotADexFile) ZipDexContainer(org.jf.dexlib2.dexbacked.ZipDexContainer) DexBackedOdexFile(org.jf.dexlib2.dexbacked.DexBackedOdexFile)

Example 5 with Opcodes

use of org.jf.dexlib2.Opcodes in project smali by JesusFreke.

the class DexWriter method writeCodeItem.

private int writeCodeItem(@Nonnull DexDataWriter writer, @Nonnull ByteArrayOutputStream ehBuf, @Nonnull MethodKey methodKey, @Nonnull List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks, @Nullable Iterable<? extends Instruction> instructions, int debugItemOffset) throws IOException {
    if (instructions == null && debugItemOffset == NO_OFFSET) {
        return -1;
    }
    numCodeItemItems++;
    writer.align();
    int codeItemOffset = writer.getPosition();
    writer.writeUshort(classSection.getRegisterCount(methodKey));
    boolean isStatic = AccessFlags.STATIC.isSet(classSection.getMethodAccessFlags(methodKey));
    Collection<? extends TypeKey> parameters = typeListSection.getTypes(protoSection.getParameters(methodSection.getPrototype(methodKey)));
    writer.writeUshort(MethodUtil.getParameterRegisterCount(parameters, isStatic));
    if (instructions != null) {
        tryBlocks = TryListBuilder.massageTryBlocks(tryBlocks);
        int outParamCount = 0;
        int codeUnitCount = 0;
        for (Instruction instruction : instructions) {
            codeUnitCount += instruction.getCodeUnits();
            if (instruction.getOpcode().referenceType == ReferenceType.METHOD) {
                ReferenceInstruction refInsn = (ReferenceInstruction) instruction;
                MethodReference methodRef = (MethodReference) refInsn.getReference();
                int paramCount = MethodUtil.getParameterRegisterCount(methodRef, InstructionUtil.isInvokeStatic(instruction.getOpcode()));
                if (paramCount > outParamCount) {
                    outParamCount = paramCount;
                }
            }
        }
        writer.writeUshort(outParamCount);
        writer.writeUshort(tryBlocks.size());
        writer.writeInt(debugItemOffset);
        InstructionWriter instructionWriter = InstructionWriter.makeInstructionWriter(opcodes, writer, stringSection, typeSection, fieldSection, methodSection, protoSection);
        writer.writeInt(codeUnitCount);
        int codeOffset = 0;
        for (Instruction instruction : instructions) {
            try {
                switch(instruction.getOpcode().format) {
                    case Format10t:
                        instructionWriter.write((Instruction10t) instruction);
                        break;
                    case Format10x:
                        instructionWriter.write((Instruction10x) instruction);
                        break;
                    case Format11n:
                        instructionWriter.write((Instruction11n) instruction);
                        break;
                    case Format11x:
                        instructionWriter.write((Instruction11x) instruction);
                        break;
                    case Format12x:
                        instructionWriter.write((Instruction12x) instruction);
                        break;
                    case Format20bc:
                        instructionWriter.write((Instruction20bc) instruction);
                        break;
                    case Format20t:
                        instructionWriter.write((Instruction20t) instruction);
                        break;
                    case Format21c:
                        instructionWriter.write((Instruction21c) instruction);
                        break;
                    case Format21ih:
                        instructionWriter.write((Instruction21ih) instruction);
                        break;
                    case Format21lh:
                        instructionWriter.write((Instruction21lh) instruction);
                        break;
                    case Format21s:
                        instructionWriter.write((Instruction21s) instruction);
                        break;
                    case Format21t:
                        instructionWriter.write((Instruction21t) instruction);
                        break;
                    case Format22b:
                        instructionWriter.write((Instruction22b) instruction);
                        break;
                    case Format22c:
                        instructionWriter.write((Instruction22c) instruction);
                        break;
                    case Format22s:
                        instructionWriter.write((Instruction22s) instruction);
                        break;
                    case Format22t:
                        instructionWriter.write((Instruction22t) instruction);
                        break;
                    case Format22x:
                        instructionWriter.write((Instruction22x) instruction);
                        break;
                    case Format23x:
                        instructionWriter.write((Instruction23x) instruction);
                        break;
                    case Format30t:
                        instructionWriter.write((Instruction30t) instruction);
                        break;
                    case Format31c:
                        instructionWriter.write((Instruction31c) instruction);
                        break;
                    case Format31i:
                        instructionWriter.write((Instruction31i) instruction);
                        break;
                    case Format31t:
                        instructionWriter.write((Instruction31t) instruction);
                        break;
                    case Format32x:
                        instructionWriter.write((Instruction32x) instruction);
                        break;
                    case Format35c:
                        instructionWriter.write((Instruction35c) instruction);
                        break;
                    case Format3rc:
                        instructionWriter.write((Instruction3rc) instruction);
                        break;
                    case Format45cc:
                        instructionWriter.write((Instruction45cc) instruction);
                        break;
                    case Format4rcc:
                        instructionWriter.write((Instruction4rcc) instruction);
                        break;
                    case Format51l:
                        instructionWriter.write((Instruction51l) instruction);
                        break;
                    case ArrayPayload:
                        instructionWriter.write((ArrayPayload) instruction);
                        break;
                    case PackedSwitchPayload:
                        instructionWriter.write((PackedSwitchPayload) instruction);
                        break;
                    case SparseSwitchPayload:
                        instructionWriter.write((SparseSwitchPayload) instruction);
                        break;
                    default:
                        throw new ExceptionWithContext("Unsupported instruction format: %s", instruction.getOpcode().format);
                }
            } catch (RuntimeException ex) {
                throw new ExceptionWithContext(ex, "Error while writing instruction at code offset 0x%x", codeOffset);
            }
            codeOffset += instruction.getCodeUnits();
        }
        if (tryBlocks.size() > 0) {
            writer.align();
            // filter out unique lists of exception handlers
            Map<List<? extends ExceptionHandler>, Integer> exceptionHandlerOffsetMap = Maps.newHashMap();
            for (TryBlock<? extends ExceptionHandler> tryBlock : tryBlocks) {
                exceptionHandlerOffsetMap.put(tryBlock.getExceptionHandlers(), 0);
            }
            DexDataWriter.writeUleb128(ehBuf, exceptionHandlerOffsetMap.size());
            for (TryBlock<? extends ExceptionHandler> tryBlock : tryBlocks) {
                int startAddress = tryBlock.getStartCodeAddress();
                int endAddress = startAddress + tryBlock.getCodeUnitCount();
                int tbCodeUnitCount = endAddress - startAddress;
                writer.writeInt(startAddress);
                writer.writeUshort(tbCodeUnitCount);
                if (tryBlock.getExceptionHandlers().size() == 0) {
                    throw new ExceptionWithContext("No exception handlers for the try block!");
                }
                Integer offset = exceptionHandlerOffsetMap.get(tryBlock.getExceptionHandlers());
                if (offset != 0) {
                    // exception handler has already been written out, just use it
                    writer.writeUshort(offset);
                } else {
                    // if offset has not been set yet, we are about to write out a new exception handler
                    offset = ehBuf.size();
                    writer.writeUshort(offset);
                    exceptionHandlerOffsetMap.put(tryBlock.getExceptionHandlers(), offset);
                    // check if the last exception handler is a catch-all and adjust the size accordingly
                    int ehSize = tryBlock.getExceptionHandlers().size();
                    ExceptionHandler ehLast = tryBlock.getExceptionHandlers().get(ehSize - 1);
                    if (ehLast.getExceptionType() == null) {
                        ehSize = ehSize * (-1) + 1;
                    }
                    // now let's layout the exception handlers, assuming that catch-all is always last
                    DexDataWriter.writeSleb128(ehBuf, ehSize);
                    for (ExceptionHandler eh : tryBlock.getExceptionHandlers()) {
                        TypeKey exceptionTypeKey = classSection.getExceptionType(eh);
                        int codeAddress = eh.getHandlerCodeAddress();
                        if (exceptionTypeKey != null) {
                            //regular exception handling
                            DexDataWriter.writeUleb128(ehBuf, typeSection.getItemIndex(exceptionTypeKey));
                            DexDataWriter.writeUleb128(ehBuf, codeAddress);
                        } else {
                            //catch-all
                            DexDataWriter.writeUleb128(ehBuf, codeAddress);
                        }
                    }
                }
            }
            if (ehBuf.size() > 0) {
                ehBuf.writeTo(writer);
                ehBuf.reset();
            }
        }
    } else {
        // no instructions, all we have is the debug item offset
        writer.writeUshort(0);
        writer.writeUshort(0);
        writer.writeInt(debugItemOffset);
        writer.writeInt(0);
    }
    return codeItemOffset;
}
Also used : ReferenceInstruction(org.jf.dexlib2.iface.instruction.ReferenceInstruction) OneRegisterInstruction(org.jf.dexlib2.iface.instruction.OneRegisterInstruction) Instruction(org.jf.dexlib2.iface.instruction.Instruction) ReferenceInstruction(org.jf.dexlib2.iface.instruction.ReferenceInstruction) ExceptionHandler(org.jf.dexlib2.iface.ExceptionHandler) ExceptionWithContext(org.jf.util.ExceptionWithContext)

Aggregations

Nonnull (javax.annotation.Nonnull)2 DexBackedDexFile (org.jf.dexlib2.dexbacked.DexBackedDexFile)2 DexClassNode (com.googlecode.d2j.node.DexClassNode)1 File (java.io.File)1 Nullable (javax.annotation.Nullable)1 Opcodes (org.jf.dexlib2.Opcodes)1 ClassPath (org.jf.dexlib2.analysis.ClassPath)1 ClassPathResolver (org.jf.dexlib2.analysis.ClassPathResolver)1 DexBackedClassDef (org.jf.dexlib2.dexbacked.DexBackedClassDef)1 NotADexFile (org.jf.dexlib2.dexbacked.DexBackedDexFile.NotADexFile)1 DexBackedOdexFile (org.jf.dexlib2.dexbacked.DexBackedOdexFile)1 DexReader (org.jf.dexlib2.dexbacked.DexReader)1 OatFile (org.jf.dexlib2.dexbacked.OatFile)1 NotAnOatFileException (org.jf.dexlib2.dexbacked.OatFile.NotAnOatFileException)1 OatDexFile (org.jf.dexlib2.dexbacked.OatFile.OatDexFile)1 ZipDexContainer (org.jf.dexlib2.dexbacked.ZipDexContainer)1 DexFile (org.jf.dexlib2.iface.DexFile)1 ExceptionHandler (org.jf.dexlib2.iface.ExceptionHandler)1 Instruction (org.jf.dexlib2.iface.instruction.Instruction)1 OneRegisterInstruction (org.jf.dexlib2.iface.instruction.OneRegisterInstruction)1