Search in sources :

Example 31 with MethodImplementation

use of org.jf.dexlib2.iface.MethodImplementation in project smali by JesusFreke.

the class ClassPool method internCode.

private void internCode(@Nonnull Method method) {
    // this also handles parameter names, which aren't directly tied to the MethodImplementation, even though the debug items are
    boolean hasInstruction = false;
    MethodImplementation methodImpl = method.getImplementation();
    if (methodImpl != null) {
        for (Instruction instruction : methodImpl.getInstructions()) {
            hasInstruction = true;
            if (instruction instanceof ReferenceInstruction) {
                Reference reference = ((ReferenceInstruction) instruction).getReference();
                switch(instruction.getOpcode().referenceType) {
                    case ReferenceType.STRING:
                        dexPool.stringSection.intern((StringReference) reference);
                        break;
                    case ReferenceType.TYPE:
                        dexPool.typeSection.intern(((TypeReference) reference).getType());
                        break;
                    case ReferenceType.FIELD:
                        dexPool.fieldSection.intern((FieldReference) reference);
                        break;
                    case ReferenceType.METHOD:
                        dexPool.methodSection.intern((MethodReference) reference);
                        break;
                    case ReferenceType.CALL_SITE:
                        dexPool.callSiteSection.intern((CallSiteReference) reference);
                        break;
                    default:
                        throw new ExceptionWithContext("Unrecognized reference type: %d", instruction.getOpcode().referenceType);
                }
            }
        }
        List<? extends TryBlock> tryBlocks = methodImpl.getTryBlocks();
        if (!hasInstruction && tryBlocks.size() > 0) {
            throw new ExceptionWithContext("Method %s has no instructions, but has try blocks.", method);
        }
        for (TryBlock<? extends ExceptionHandler> tryBlock : methodImpl.getTryBlocks()) {
            for (ExceptionHandler handler : tryBlock.getExceptionHandlers()) {
                dexPool.typeSection.internNullable(handler.getExceptionType());
            }
        }
    }
}
Also used : MutableMethodImplementation(org.jf.dexlib2.builder.MutableMethodImplementation) ExceptionWithContext(org.jf.util.ExceptionWithContext) ReferenceInstruction(org.jf.dexlib2.iface.instruction.ReferenceInstruction) Instruction(org.jf.dexlib2.iface.instruction.Instruction) ReferenceInstruction(org.jf.dexlib2.iface.instruction.ReferenceInstruction)

Example 32 with MethodImplementation

use of org.jf.dexlib2.iface.MethodImplementation in project smali by JesusFreke.

the class ClassPool method internDebug.

private void internDebug(@Nonnull Method method) {
    for (MethodParameter param : method.getParameters()) {
        String paramName = param.getName();
        if (paramName != null) {
            dexPool.stringSection.intern(paramName);
        }
    }
    MethodImplementation methodImpl = method.getImplementation();
    if (methodImpl != null) {
        for (DebugItem debugItem : methodImpl.getDebugItems()) {
            switch(debugItem.getDebugItemType()) {
                case DebugItemType.START_LOCAL:
                    StartLocal startLocal = (StartLocal) debugItem;
                    dexPool.stringSection.internNullable(startLocal.getName());
                    dexPool.typeSection.internNullable(startLocal.getType());
                    dexPool.stringSection.internNullable(startLocal.getSignature());
                    break;
                case DebugItemType.SET_SOURCE_FILE:
                    dexPool.stringSection.internNullable(((SetSourceFile) debugItem).getSourceFile());
                    break;
            }
        }
    }
}
Also used : MutableMethodImplementation(org.jf.dexlib2.builder.MutableMethodImplementation)

Example 33 with MethodImplementation

use of org.jf.dexlib2.iface.MethodImplementation in project tinker by Tencent.

the class DexDiffDecoder method generateChangedClassesDexFile.

@SuppressWarnings("NewApi")
private void generateChangedClassesDexFile() throws IOException {
    final String dexMode = config.mDexRaw ? "raw" : "jar";
    List<File> oldDexList = new ArrayList<>();
    List<File> newDexList = new ArrayList<>();
    for (AbstractMap.SimpleEntry<File, File> oldAndNewDexFilePair : oldAndNewDexFilePairList) {
        File oldDexFile = oldAndNewDexFilePair.getKey();
        File newDexFile = oldAndNewDexFilePair.getValue();
        if (oldDexFile != null) {
            oldDexList.add(oldDexFile);
        }
        if (newDexFile != null) {
            newDexList.add(newDexFile);
        }
    }
    DexGroup oldDexGroup = DexGroup.wrap(oldDexList);
    DexGroup newDexGroup = DexGroup.wrap(newDexList);
    ChangedClassesDexClassInfoCollector collector = new ChangedClassesDexClassInfoCollector();
    collector.setExcludedClassPatterns(config.mDexLoaderPattern);
    collector.setLogger(dexPatcherLoggerBridge);
    collector.setIncludeRefererToRefererAffectedClasses(true);
    Set<DexClassInfo> classInfosInChangedClassesDex = collector.doCollect(oldDexGroup, newDexGroup);
    Set<Dex> owners = new HashSet<>();
    Map<Dex, Set<String>> ownerToDescOfChangedClassesMap = new HashMap<>();
    for (DexClassInfo classInfo : classInfosInChangedClassesDex) {
        owners.add(classInfo.owner);
        Set<String> descOfChangedClasses = ownerToDescOfChangedClassesMap.get(classInfo.owner);
        if (descOfChangedClasses == null) {
            descOfChangedClasses = new HashSet<>();
            ownerToDescOfChangedClassesMap.put(classInfo.owner, descOfChangedClasses);
        }
        descOfChangedClasses.add(classInfo.classDesc);
    }
    StringBuilder metaBuilder = new StringBuilder();
    int changedDexId = 1;
    for (Dex dex : owners) {
        Set<String> descOfChangedClassesInCurrDex = ownerToDescOfChangedClassesMap.get(dex);
        DexFile dexFile = new DexBackedDexFile(org.jf.dexlib2.Opcodes.forApi(20), dex.getBytes());
        boolean isCurrentDexHasChangedClass = false;
        for (org.jf.dexlib2.iface.ClassDef classDef : dexFile.getClasses()) {
            if (descOfChangedClassesInCurrDex.contains(classDef.getType())) {
                isCurrentDexHasChangedClass = true;
                break;
            }
        }
        if (!isCurrentDexHasChangedClass) {
            continue;
        }
        DexBuilder dexBuilder = new DexBuilder(Opcodes.forApi(23));
        for (org.jf.dexlib2.iface.ClassDef classDef : dexFile.getClasses()) {
            if (!descOfChangedClassesInCurrDex.contains(classDef.getType())) {
                continue;
            }
            Logger.d("Class %s will be added into changed classes dex ...", classDef.getType());
            List<BuilderField> builderFields = new ArrayList<>();
            for (Field field : classDef.getFields()) {
                final BuilderField builderField = dexBuilder.internField(field.getDefiningClass(), field.getName(), field.getType(), field.getAccessFlags(), field.getInitialValue(), field.getAnnotations());
                builderFields.add(builderField);
            }
            List<BuilderMethod> builderMethods = new ArrayList<>();
            for (Method method : classDef.getMethods()) {
                MethodImplementation methodImpl = method.getImplementation();
                if (methodImpl != null) {
                    methodImpl = new BuilderMutableMethodImplementation(dexBuilder, methodImpl);
                }
                BuilderMethod builderMethod = dexBuilder.internMethod(method.getDefiningClass(), method.getName(), method.getParameters(), method.getReturnType(), method.getAccessFlags(), method.getAnnotations(), methodImpl);
                builderMethods.add(builderMethod);
            }
            dexBuilder.internClassDef(classDef.getType(), classDef.getAccessFlags(), classDef.getSuperclass(), classDef.getInterfaces(), classDef.getSourceFile(), classDef.getAnnotations(), builderFields, builderMethods);
        }
        // Write constructed changed classes dex to file and record it in meta file.
        String changedDexName = null;
        if (changedDexId == 1) {
            changedDexName = "classes.dex";
        } else {
            changedDexName = "classes" + changedDexId + ".dex";
        }
        final File dest = new File(config.mTempResultDir + "/" + changedDexName);
        final FileDataStore fileDataStore = new FileDataStore(dest);
        dexBuilder.writeTo(fileDataStore);
        final String md5 = MD5.getMD5(dest);
        appendMetaLine(metaBuilder, changedDexName, "", md5, md5, 0, 0, 0, dexMode);
        ++changedDexId;
    }
    final String meta = metaBuilder.toString();
    Logger.d("\nDexDecoder:write changed classes dex meta file data:\n%s", meta);
    metaWriter.writeLineToInfoFile(meta);
}
Also used : DexGroup(com.tencent.tinker.build.util.DexClassesComparator.DexGroup) MethodImplementation(org.jf.dexlib2.iface.MethodImplementation) BuilderMutableMethodImplementation(org.jf.dexlib2.builder.BuilderMutableMethodImplementation) Set(java.util.Set) HashSet(java.util.HashSet) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) AbstractMap(java.util.AbstractMap) BuilderField(org.jf.dexlib2.writer.builder.BuilderField) Field(org.jf.dexlib2.iface.Field) BuilderField(org.jf.dexlib2.writer.builder.BuilderField) FileDataStore(org.jf.dexlib2.writer.io.FileDataStore) HashSet(java.util.HashSet) DexBackedDexFile(org.jf.dexlib2.dexbacked.DexBackedDexFile) ChangedClassesDexClassInfoCollector(com.tencent.tinker.build.dexpatcher.util.ChangedClassesDexClassInfoCollector) BuilderMutableMethodImplementation(org.jf.dexlib2.builder.BuilderMutableMethodImplementation) Method(org.jf.dexlib2.iface.Method) BuilderMethod(org.jf.dexlib2.writer.builder.BuilderMethod) DexFile(org.jf.dexlib2.iface.DexFile) DexBackedDexFile(org.jf.dexlib2.dexbacked.DexBackedDexFile) DexBuilder(org.jf.dexlib2.writer.builder.DexBuilder) Dex(com.tencent.tinker.android.dex.Dex) BuilderMethod(org.jf.dexlib2.writer.builder.BuilderMethod) JarFile(java.util.jar.JarFile) DexFile(org.jf.dexlib2.iface.DexFile) DexBackedDexFile(org.jf.dexlib2.dexbacked.DexBackedDexFile) File(java.io.File) DexClassInfo(com.tencent.tinker.build.util.DexClassesComparator.DexClassInfo)

Example 34 with MethodImplementation

use of org.jf.dexlib2.iface.MethodImplementation in project tinker by Tencent.

the class DexDiffDecoder method checkIfLoaderClassesReferToNonLoaderClasses.

private void checkIfLoaderClassesReferToNonLoaderClasses() throws IOException, TinkerPatchException {
    boolean hasInvalidCases = false;
    for (File dexFile : oldDexFiles) {
        Logger.d("Check if loader classes in " + dexFile.getName() + " refer to any classes that is not in loader class patterns.");
        final DexFile dex = DexFileFactory.loadDexFile(dexFile, Opcodes.forApi(29));
        for (org.jf.dexlib2.iface.ClassDef classDef : dex.getClasses()) {
            final String currClassDesc = classDef.getType();
            if (!Utils.isStringMatchesPatterns(currClassDesc, loaderClassPatterns)) {
                continue;
            }
            for (Field field : classDef.getFields()) {
                final String currFieldTypeDesc = field.getType();
                if (!isReferenceFromLoaderClassValid(currFieldTypeDesc)) {
                    Logger.e("FATAL: field '%s' in loader class '%s' refers to class '%s' which " + "is not loader class, this may cause crash when patch is loaded.", field.getName(), currClassDesc, currFieldTypeDesc);
                    hasInvalidCases = true;
                }
            }
            for (Method method : classDef.getMethods()) {
                boolean isCurrentMethodInvalid = false;
                final String currMethodRetTypeDesc = method.getReturnType();
                if (!isReferenceFromLoaderClassValid(currMethodRetTypeDesc)) {
                    Logger.e("FATAL: method '%s:%s' in loader class '%s' refers to class '%s' which " + "is not loader class, this may cause crash when patch is loaded.", method.getName(), MethodUtil.getShorty(method.getParameterTypes(), currMethodRetTypeDesc), currClassDesc, currMethodRetTypeDesc);
                    isCurrentMethodInvalid = true;
                } else {
                    for (CharSequence paramTypeDesc : method.getParameterTypes()) {
                        if (!isReferenceFromLoaderClassValid(paramTypeDesc.toString())) {
                            Logger.e("FATAL: method '%s:%s' in loader class '%s' refers to class '%s' which " + "is not loader class, this may cause crash when patch is loaded.", method.getName(), MethodUtil.getShorty(method.getParameterTypes(), currMethodRetTypeDesc), currClassDesc, paramTypeDesc);
                            isCurrentMethodInvalid = true;
                            break;
                        }
                    }
                }
                check_method_impl: {
                    final MethodImplementation methodImpl = method.getImplementation();
                    if (methodImpl == null) {
                        break check_method_impl;
                    }
                    final Iterable<? extends Instruction> insns = methodImpl.getInstructions();
                    if (!insns.iterator().hasNext()) {
                        break check_method_impl;
                    }
                    for (Instruction insn : insns) {
                        if (insn instanceof ReferenceInstruction) {
                            final ReferenceInstruction refInsn = (ReferenceInstruction) insn;
                            switch(refInsn.getReferenceType()) {
                                case ReferenceType.TYPE:
                                    {
                                        final TypeReference typeRefInsn = (TypeReference) refInsn.getReference();
                                        final String refereeTypeDesc = typeRefInsn.getType();
                                        if (isReferenceFromLoaderClassValid(refereeTypeDesc)) {
                                            break;
                                        }
                                        Logger.e("FATAL: method '%s:%s' in loader class '%s' refers to class '%s' which " + "is not loader class, this may cause crash when patch is loaded.", method.getName(), MethodUtil.getShorty(method.getParameterTypes(), currMethodRetTypeDesc), currClassDesc, refereeTypeDesc);
                                        isCurrentMethodInvalid = true;
                                        break;
                                    }
                                case ReferenceType.FIELD:
                                    {
                                        final FieldReference fieldRefInsn = (FieldReference) refInsn.getReference();
                                        final String refereeFieldName = fieldRefInsn.getName();
                                        final String refereeFieldDefTypeDesc = fieldRefInsn.getDefiningClass();
                                        if (isReferenceFromLoaderClassValid(refereeFieldDefTypeDesc)) {
                                            break;
                                        }
                                        Logger.e("FATAL: method '%s:%s' in loader class '%s' refers to field '%s' in class '%s' which " + "is not in loader class, this may cause crash when patch is loaded.", method.getName(), MethodUtil.getShorty(method.getParameterTypes(), currMethodRetTypeDesc), currClassDesc, refereeFieldName, refereeFieldDefTypeDesc);
                                        isCurrentMethodInvalid = true;
                                        break;
                                    }
                                case ReferenceType.METHOD:
                                    {
                                        final MethodReference methodRefInsn = (MethodReference) refInsn.getReference();
                                        final String refereeMethodName = methodRefInsn.getName();
                                        final Collection<? extends CharSequence> refereeMethodParamTypes = methodRefInsn.getParameterTypes();
                                        final String refereeMethodRetType = methodRefInsn.getReturnType();
                                        final String refereeMethodDefClassDesc = methodRefInsn.getDefiningClass();
                                        if (isReferenceFromLoaderClassValid(refereeMethodDefClassDesc)) {
                                            break;
                                        }
                                        Logger.e("FATAL: method '%s:%s' in loader class '%s' refers to method '%s:%s' in class '%s' which " + "is not in loader class, this may cause crash when patch is loaded.", method.getName(), MethodUtil.getShorty(method.getParameterTypes(), currMethodRetTypeDesc), currClassDesc, refereeMethodName, MethodUtil.getShorty(refereeMethodParamTypes, refereeMethodRetType), refereeMethodDefClassDesc);
                                        isCurrentMethodInvalid = true;
                                        break;
                                    }
                                default:
                                    {
                                        break;
                                    }
                            }
                        }
                    }
                }
                if (isCurrentMethodInvalid) {
                    hasInvalidCases = true;
                }
            }
        }
    }
    if (hasInvalidCases) {
        throw new TinkerPatchException("There are fatal reasons that cause Tinker interrupt" + " patch generating procedure, see logs above.");
    }
}
Also used : MethodImplementation(org.jf.dexlib2.iface.MethodImplementation) BuilderMutableMethodImplementation(org.jf.dexlib2.builder.BuilderMutableMethodImplementation) FieldReference(org.jf.dexlib2.iface.reference.FieldReference) ReferenceInstruction(org.jf.dexlib2.iface.instruction.ReferenceInstruction) Method(org.jf.dexlib2.iface.Method) BuilderMethod(org.jf.dexlib2.writer.builder.BuilderMethod) Instruction(org.jf.dexlib2.iface.instruction.Instruction) ReferenceInstruction(org.jf.dexlib2.iface.instruction.ReferenceInstruction) DexFile(org.jf.dexlib2.iface.DexFile) DexBackedDexFile(org.jf.dexlib2.dexbacked.DexBackedDexFile) TinkerPatchException(com.tencent.tinker.build.util.TinkerPatchException) Field(org.jf.dexlib2.iface.Field) BuilderField(org.jf.dexlib2.writer.builder.BuilderField) Collection(java.util.Collection) MethodReference(org.jf.dexlib2.iface.reference.MethodReference) TypeReference(org.jf.dexlib2.iface.reference.TypeReference) JarFile(java.util.jar.JarFile) DexFile(org.jf.dexlib2.iface.DexFile) DexBackedDexFile(org.jf.dexlib2.dexbacked.DexBackedDexFile) File(java.io.File)

Example 35 with MethodImplementation

use of org.jf.dexlib2.iface.MethodImplementation in project smali by JesusFreke.

the class InstructionMethodItemTest method testInvalidReference.

@Test
public void testInvalidReference() throws IOException {
    Instruction21c instruction = new Instruction21c() {

        @Override
        public int getRegisterA() {
            return 0;
        }

        @Nonnull
        @Override
        public Reference getReference() {
            return new BaseStringReference() {

                @Override
                public void validateReference() throws InvalidReferenceException {
                    throw new InvalidReferenceException("blahblahblah");
                }

                @Nonnull
                @Override
                public String getString() {
                    throw new RuntimeException("invalid reference");
                }
            };
        }

        @Override
        public int getReferenceType() {
            return ReferenceType.STRING;
        }

        @Override
        public Opcode getOpcode() {
            return Opcode.CONST_STRING;
        }

        @Override
        public int getCodeUnits() {
            return Format.Format21c.size / 2;
        }
    };
    MethodImplementation methodImplementation = new MethodImplementation() {

        @Override
        public int getRegisterCount() {
            return 1;
        }

        @Nonnull
        @Override
        public Iterable<? extends Instruction> getInstructions() {
            return ImmutableList.of(instruction);
        }

        @Nonnull
        @Override
        public List<? extends TryBlock<? extends ExceptionHandler>> getTryBlocks() {
            return ImmutableList.of();
        }

        @Nonnull
        @Override
        public Iterable<? extends DebugItem> getDebugItems() {
            return ImmutableList.of();
        }
    };
    Method method = new TestMethod(methodImplementation);
    ClassDefinition classDefinition = new ClassDefinition(new BaksmaliOptions(), new TestClassDef());
    MethodDefinition methodDefinition = new MethodDefinition(classDefinition, method, methodImplementation);
    methodDefinition.registerFormatter = new RegisterFormatter(new BaksmaliOptions(), 1, 0);
    InstructionMethodItem methodItem = new InstructionMethodItem<Instruction21c>(methodDefinition, 0, instruction);
    StringWriter stringWriter = new StringWriter();
    BaksmaliWriter writer = new BaksmaliWriter(stringWriter);
    methodItem.writeTo(writer);
    Assert.assertEquals("#Invalid reference\n#const-string v0, blahblahblah\nnop", stringWriter.toString());
}
Also used : Instruction21c(org.jf.dexlib2.iface.instruction.formats.Instruction21c) ClassDefinition(org.jf.baksmali.Adaptors.ClassDefinition) RegisterFormatter(org.jf.baksmali.Adaptors.RegisterFormatter) BaseStringReference(org.jf.dexlib2.base.reference.BaseStringReference) InstructionMethodItem(org.jf.baksmali.Adaptors.Format.InstructionMethodItem) StringWriter(java.io.StringWriter) MethodDefinition(org.jf.baksmali.Adaptors.MethodDefinition) BaksmaliWriter(org.jf.baksmali.formatter.BaksmaliWriter) Test(org.junit.Test)

Aggregations

MethodImplementation (org.jf.dexlib2.iface.MethodImplementation)29 Test (org.junit.Test)18 Method (org.jf.dexlib2.iface.Method)17 BuilderInstruction10x (org.jf.dexlib2.builder.instruction.BuilderInstruction10x)13 ClassDef (org.jf.dexlib2.iface.ClassDef)12 Instruction (org.jf.dexlib2.iface.instruction.Instruction)12 DexFile (org.jf.dexlib2.iface.DexFile)11 ImmutableMethod (org.jf.dexlib2.immutable.ImmutableMethod)11 MutableMethodImplementation (org.jf.dexlib2.builder.MutableMethodImplementation)9 MethodImplementationBuilder (org.jf.dexlib2.builder.MethodImplementationBuilder)8 DexBackedClassDef (org.jf.dexlib2.dexbacked.DexBackedClassDef)8 ImmutableClassDef (org.jf.dexlib2.immutable.ImmutableClassDef)8 ImmutableMethodParameter (org.jf.dexlib2.immutable.ImmutableMethodParameter)7 HashSet (java.util.HashSet)6 BuilderInstruction21c (org.jf.dexlib2.builder.instruction.BuilderInstruction21c)6 BuilderInstruction21t (org.jf.dexlib2.builder.instruction.BuilderInstruction21t)6 BuilderInstruction22c (org.jf.dexlib2.builder.instruction.BuilderInstruction22c)6 ReferenceInstruction (org.jf.dexlib2.iface.instruction.ReferenceInstruction)6 ImmutableDexFile (org.jf.dexlib2.immutable.ImmutableDexFile)6 ImmutableTypeReference (org.jf.dexlib2.immutable.reference.ImmutableTypeReference)6