mirror of
https://github.com/revanced/smali.git
synced 2025-06-13 04:27:38 +02:00
Add helper comments for synthetic member accessors
This adds a comment before a synthetic member accessor is called, which mentions what member in the parent is being accessed Kudos to jasta for suggesting this feature! git-svn-id: https://smali.googlecode.com/svn/trunk@809 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
@ -29,6 +29,8 @@
|
|||||||
package org.jf.baksmali.Adaptors;
|
package org.jf.baksmali.Adaptors;
|
||||||
|
|
||||||
import org.jf.baksmali.Adaptors.Format.InstructionMethodItemFactory;
|
import org.jf.baksmali.Adaptors.Format.InstructionMethodItemFactory;
|
||||||
|
import org.jf.dexlib.Code.Analysis.SyntheticAccessorResolver;
|
||||||
|
import org.jf.dexlib.Code.InstructionWithReference;
|
||||||
import org.jf.util.IndentingWriter;
|
import org.jf.util.IndentingWriter;
|
||||||
import org.jf.baksmali.baksmali;
|
import org.jf.baksmali.baksmali;
|
||||||
import org.jf.dexlib.*;
|
import org.jf.dexlib.*;
|
||||||
@ -343,6 +345,21 @@ public class MethodDefinition {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (instruction instanceof InstructionWithReference) {
|
||||||
|
if (instruction.opcode == Opcode.INVOKE_STATIC || instruction.opcode == Opcode.INVOKE_STATIC_RANGE) {
|
||||||
|
MethodIdItem methodIdItem =
|
||||||
|
(MethodIdItem)((InstructionWithReference) instruction).getReferencedItem();
|
||||||
|
|
||||||
|
if (SyntheticAccessorResolver.looksLikeSyntheticAccessor(methodIdItem)) {
|
||||||
|
SyntheticAccessorResolver.AccessedMember accessedMember =
|
||||||
|
baksmali.syntheticAccessorResolver.getAccessedMember(methodIdItem);
|
||||||
|
if (accessedMember != null) {
|
||||||
|
methodItems.add(new SyntheticAccessCommentMethodItem(accessedMember, currentCodeAddress));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
currentCodeAddress += instruction.getSize(currentCodeAddress);
|
currentCodeAddress += instruction.getSize(currentCodeAddress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* [The "BSD licence"]
|
||||||
|
* Copyright (c) 2011 Ben Gruver
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jf.baksmali.Adaptors;
|
||||||
|
|
||||||
|
import org.jf.dexlib.Code.Analysis.SyntheticAccessorResolver;
|
||||||
|
import static org.jf.dexlib.Code.Analysis.SyntheticAccessorResolver.AccessedMember;
|
||||||
|
import org.jf.util.IndentingWriter;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class SyntheticAccessCommentMethodItem extends MethodItem {
|
||||||
|
private final AccessedMember accessedMember;
|
||||||
|
|
||||||
|
public SyntheticAccessCommentMethodItem(AccessedMember accessedMember, int codeAddress) {
|
||||||
|
super(codeAddress);
|
||||||
|
this.accessedMember = accessedMember;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getSortOrder() {
|
||||||
|
//just before the pre-instruction register information, if any
|
||||||
|
return 99.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean writeTo(IndentingWriter writer) throws IOException {
|
||||||
|
writer.write('#');
|
||||||
|
if (accessedMember.getAccessedMemberType() == SyntheticAccessorResolver.METHOD) {
|
||||||
|
writer.write("calls: ");
|
||||||
|
} else if (accessedMember.getAccessedMemberType() == SyntheticAccessorResolver.GETTER) {
|
||||||
|
writer.write("getter for: ");
|
||||||
|
} else {
|
||||||
|
writer.write("setter for: ");
|
||||||
|
}
|
||||||
|
ReferenceFormatter.writeReference(writer, accessedMember.getAccessedMember());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -31,6 +31,7 @@ package org.jf.baksmali;
|
|||||||
import org.jf.baksmali.Adaptors.ClassDefinition;
|
import org.jf.baksmali.Adaptors.ClassDefinition;
|
||||||
import org.jf.dexlib.ClassDefItem;
|
import org.jf.dexlib.ClassDefItem;
|
||||||
import org.jf.dexlib.Code.Analysis.ClassPath;
|
import org.jf.dexlib.Code.Analysis.ClassPath;
|
||||||
|
import org.jf.dexlib.Code.Analysis.SyntheticAccessorResolver;
|
||||||
import org.jf.dexlib.DexFile;
|
import org.jf.dexlib.DexFile;
|
||||||
import org.jf.util.ClassFileNameHandler;
|
import org.jf.util.ClassFileNameHandler;
|
||||||
import org.jf.util.IndentingWriter;
|
import org.jf.util.IndentingWriter;
|
||||||
@ -48,22 +49,27 @@ public class baksmali {
|
|||||||
public static boolean useSequentialLabels = false;
|
public static boolean useSequentialLabels = false;
|
||||||
public static boolean outputDebugInfo = true;
|
public static boolean outputDebugInfo = true;
|
||||||
public static boolean addCodeOffsets = false;
|
public static boolean addCodeOffsets = false;
|
||||||
|
public static boolean noAccessorComments = false;
|
||||||
public static boolean deodex = false;
|
public static boolean deodex = false;
|
||||||
public static boolean verify = false;
|
public static boolean verify = false;
|
||||||
public static int registerInfo = 0;
|
public static int registerInfo = 0;
|
||||||
public static String bootClassPath;
|
public static String bootClassPath;
|
||||||
|
|
||||||
|
public static SyntheticAccessorResolver syntheticAccessorResolver = null;
|
||||||
|
|
||||||
public static void disassembleDexFile(String dexFilePath, DexFile dexFile, boolean deodex, String outputDirectory,
|
public static void disassembleDexFile(String dexFilePath, DexFile dexFile, boolean deodex, String outputDirectory,
|
||||||
String[] classPathDirs, String bootClassPath, String extraBootClassPath,
|
String[] classPathDirs, String bootClassPath, String extraBootClassPath,
|
||||||
boolean noParameterRegisters, boolean useLocalsDirective,
|
boolean noParameterRegisters, boolean useLocalsDirective,
|
||||||
boolean useSequentialLabels, boolean outputDebugInfo, boolean addCodeOffsets,
|
boolean useSequentialLabels, boolean outputDebugInfo, boolean addCodeOffsets,
|
||||||
int registerInfo, boolean verify, boolean ignoreErrors)
|
boolean noAccessorComments, int registerInfo, boolean verify,
|
||||||
|
boolean ignoreErrors)
|
||||||
{
|
{
|
||||||
baksmali.noParameterRegisters = noParameterRegisters;
|
baksmali.noParameterRegisters = noParameterRegisters;
|
||||||
baksmali.useLocalsDirective = useLocalsDirective;
|
baksmali.useLocalsDirective = useLocalsDirective;
|
||||||
baksmali.useSequentialLabels = useSequentialLabels;
|
baksmali.useSequentialLabels = useSequentialLabels;
|
||||||
baksmali.outputDebugInfo = outputDebugInfo;
|
baksmali.outputDebugInfo = outputDebugInfo;
|
||||||
baksmali.addCodeOffsets = addCodeOffsets;
|
baksmali.addCodeOffsets = addCodeOffsets;
|
||||||
|
baksmali.noAccessorComments = noAccessorComments;
|
||||||
baksmali.deodex = deodex;
|
baksmali.deodex = deodex;
|
||||||
baksmali.registerInfo = registerInfo;
|
baksmali.registerInfo = registerInfo;
|
||||||
baksmali.bootClassPath = bootClassPath;
|
baksmali.bootClassPath = bootClassPath;
|
||||||
@ -120,6 +126,10 @@ public class baksmali {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!noAccessorComments) {
|
||||||
|
syntheticAccessorResolver = new SyntheticAccessorResolver(dexFile);
|
||||||
|
}
|
||||||
|
|
||||||
//sort the classes, so that if we're on a case-insensitive file system and need to handle classes with file
|
//sort the classes, so that if we're on a case-insensitive file system and need to handle classes with file
|
||||||
//name collisions, then we'll use the same name for each class, if the dex file goes through multiple
|
//name collisions, then we'll use the same name for each class, if the dex file goes through multiple
|
||||||
//baksmali/smali cycles for some reason. If a class with a colliding name is added or removed, the filenames
|
//baksmali/smali cycles for some reason. If a class with a colliding name is added or removed, the filenames
|
||||||
|
@ -103,6 +103,7 @@ public class main {
|
|||||||
boolean useSequentialLabels = false;
|
boolean useSequentialLabels = false;
|
||||||
boolean outputDebugInfo = true;
|
boolean outputDebugInfo = true;
|
||||||
boolean addCodeOffsets = false;
|
boolean addCodeOffsets = false;
|
||||||
|
boolean noAccessorComments = false;
|
||||||
boolean deodex = false;
|
boolean deodex = false;
|
||||||
boolean verify = false;
|
boolean verify = false;
|
||||||
boolean ignoreErrors = false;
|
boolean ignoreErrors = false;
|
||||||
@ -204,6 +205,9 @@ public class main {
|
|||||||
case 'x':
|
case 'x':
|
||||||
deodex = true;
|
deodex = true;
|
||||||
break;
|
break;
|
||||||
|
case 'm':
|
||||||
|
noAccessorComments = true;
|
||||||
|
break;
|
||||||
case 'N':
|
case 'N':
|
||||||
disassemble = false;
|
disassemble = false;
|
||||||
break;
|
break;
|
||||||
@ -278,7 +282,7 @@ public class main {
|
|||||||
baksmali.disassembleDexFile(dexFileFile.getPath(), dexFile, deodex, outputDirectory,
|
baksmali.disassembleDexFile(dexFileFile.getPath(), dexFile, deodex, outputDirectory,
|
||||||
bootClassPathDirsArray, bootClassPath, extraBootClassPathEntries.toString(),
|
bootClassPathDirsArray, bootClassPath, extraBootClassPathEntries.toString(),
|
||||||
noParameterRegisters, useLocalsDirective, useSequentialLabels, outputDebugInfo, addCodeOffsets,
|
noParameterRegisters, useLocalsDirective, useSequentialLabels, outputDebugInfo, addCodeOffsets,
|
||||||
registerInfo, verify, ignoreErrors);
|
noAccessorComments, registerInfo, verify, ignoreErrors);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((doDump || write) && !dexFile.isOdex()) {
|
if ((doDump || write) && !dexFile.isOdex()) {
|
||||||
@ -407,7 +411,9 @@ public class main {
|
|||||||
.withDescription("add comments to the disassembly containing the code offset for each address")
|
.withDescription("add comments to the disassembly containing the code offset for each address")
|
||||||
.create("f");
|
.create("f");
|
||||||
|
|
||||||
|
Option noAccessorCommentsOption = OptionBuilder.withLongOpt("no-accessor-comments")
|
||||||
|
.withDescription("don't output helper comments for synthetic accessors")
|
||||||
|
.create("m");
|
||||||
|
|
||||||
Option dumpOption = OptionBuilder.withLongOpt("dump-to")
|
Option dumpOption = OptionBuilder.withLongOpt("dump-to")
|
||||||
.withDescription("dumps the given dex file into a single annotated dump file named FILE" +
|
.withDescription("dumps the given dex file into a single annotated dump file named FILE" +
|
||||||
@ -457,6 +463,7 @@ public class main {
|
|||||||
basicOptions.addOption(classPathOption);
|
basicOptions.addOption(classPathOption);
|
||||||
basicOptions.addOption(classPathDirOption);
|
basicOptions.addOption(classPathDirOption);
|
||||||
basicOptions.addOption(codeOffsetOption);
|
basicOptions.addOption(codeOffsetOption);
|
||||||
|
basicOptions.addOption(noAccessorCommentsOption);
|
||||||
|
|
||||||
debugOptions.addOption(dumpOption);
|
debugOptions.addOption(dumpOption);
|
||||||
debugOptions.addOption(ignoreErrorsOption);
|
debugOptions.addOption(ignoreErrorsOption);
|
||||||
|
@ -343,6 +343,60 @@ public class ClassDataItem extends Item<ClassDataItem> {
|
|||||||
return virtualMethods;
|
return virtualMethods;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a binary search for the definition of the specified direct method
|
||||||
|
* @param methodIdItem The MethodIdItem of the direct method to search for
|
||||||
|
* @return The EncodedMethod for the specified direct method, or null if not found
|
||||||
|
*/
|
||||||
|
public EncodedMethod findDirectMethodByMethodId(MethodIdItem methodIdItem) {
|
||||||
|
return findMethodByMethodIdInternal(methodIdItem.index, directMethods);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a binary search for the definition of the specified virtual method
|
||||||
|
* @param methodIdItem The MethodIdItem of the virtual method to search for
|
||||||
|
* @return The EncodedMethod for the specified virtual method, or null if not found
|
||||||
|
*/
|
||||||
|
public EncodedMethod findVirtualMethodByMethodId(MethodIdItem methodIdItem) {
|
||||||
|
return findMethodByMethodIdInternal(methodIdItem.index, virtualMethods);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a binary search for the definition of the specified method. It can be either direct or virtual
|
||||||
|
* @param methodIdItem The MethodIdItem of the virtual method to search for
|
||||||
|
* @return The EncodedMethod for the specified virtual method, or null if not found
|
||||||
|
*/
|
||||||
|
public EncodedMethod findMethodByMethodId(MethodIdItem methodIdItem) {
|
||||||
|
EncodedMethod encodedMethod = findMethodByMethodIdInternal(methodIdItem.index, directMethods);
|
||||||
|
if (encodedMethod != null) {
|
||||||
|
return encodedMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
return findMethodByMethodIdInternal(methodIdItem.index, virtualMethods);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static EncodedMethod findMethodByMethodIdInternal(int methodIdItemIndex, EncodedMethod[] encodedMethods) {
|
||||||
|
int min = 0;
|
||||||
|
int max = encodedMethods.length;
|
||||||
|
|
||||||
|
while (min<max) {
|
||||||
|
int index = (min+max)>>1;
|
||||||
|
|
||||||
|
EncodedMethod encodedMethod = encodedMethods[index];
|
||||||
|
|
||||||
|
int encodedMethodIndex = encodedMethod.method.getIndex();
|
||||||
|
if (encodedMethodIndex == methodIdItemIndex) {
|
||||||
|
return encodedMethod;
|
||||||
|
} else if (encodedMethodIndex < methodIdItemIndex) {
|
||||||
|
min = index;
|
||||||
|
} else {
|
||||||
|
max = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public static class EncodedField implements Comparable<EncodedField> {
|
public static class EncodedField implements Comparable<EncodedField> {
|
||||||
/**
|
/**
|
||||||
* The <code>FieldIdItem</code> that this <code>EncodedField</code> is associated with
|
* The <code>FieldIdItem</code> that this <code>EncodedField</code> is associated with
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* [The "BSD licence"]
|
||||||
|
* Copyright (c) 2011 Ben Gruver
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jf.dexlib.Code.Analysis;
|
||||||
|
|
||||||
|
import org.jf.dexlib.ClassDefItem;
|
||||||
|
import org.jf.dexlib.DexFile;
|
||||||
|
import org.jf.dexlib.TypeIdItem;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keeps a simple map of classes defined in a dex file, allowing you to look them up by TypeIdItem or name
|
||||||
|
*/
|
||||||
|
public class DexFileClassMap {
|
||||||
|
private final HashMap<String, ClassDefItem> definedClasses = new HashMap<String, ClassDefItem>();
|
||||||
|
|
||||||
|
public DexFileClassMap(DexFile dexFile) {
|
||||||
|
for (ClassDefItem classDefItem: dexFile.ClassDefsSection.getItems()) {
|
||||||
|
definedClasses.put(classDefItem.getClassType().getTypeDescriptor(), classDefItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassDefItem getClassDefByName(String typeName) {
|
||||||
|
return definedClasses.get(typeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassDefItem getClassDefByType(TypeIdItem typeIdItem) {
|
||||||
|
return definedClasses.get(typeIdItem.getTypeDescriptor());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* [The "BSD licence"]
|
||||||
|
* Copyright (c) 2011 Ben Gruver
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jf.dexlib.Code.Analysis;
|
||||||
|
|
||||||
|
import org.jf.dexlib.*;
|
||||||
|
import org.jf.dexlib.Code.Format.Instruction22c;
|
||||||
|
import org.jf.dexlib.Code.Instruction;
|
||||||
|
import org.jf.dexlib.Code.InstructionWithReference;
|
||||||
|
import org.jf.dexlib.Util.AccessFlags;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class SyntheticAccessorResolver {
|
||||||
|
public static final int METHOD = 0;
|
||||||
|
public static final int GETTER = 1;
|
||||||
|
public static final int SETTER = 2;
|
||||||
|
|
||||||
|
private final DexFileClassMap classMap;
|
||||||
|
private final HashMap<MethodIdItem, AccessedMember> resolvedAccessors = new HashMap<MethodIdItem, AccessedMember>();
|
||||||
|
|
||||||
|
public SyntheticAccessorResolver(DexFile dexFile) {
|
||||||
|
classMap = new DexFileClassMap(dexFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean looksLikeSyntheticAccessor(MethodIdItem methodIdItem) {
|
||||||
|
return methodIdItem.getMethodName().getStringValue().startsWith("access$");
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccessedMember getAccessedMember(MethodIdItem methodIdItem) {
|
||||||
|
AccessedMember accessedMember = resolvedAccessors.get(methodIdItem);
|
||||||
|
if (accessedMember != null) {
|
||||||
|
return accessedMember;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassDefItem classDefItem = classMap.getClassDefByType(methodIdItem.getContainingClass());
|
||||||
|
if (classDefItem == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassDataItem.EncodedMethod encodedMethod = classDefItem.getClassData().findDirectMethodByMethodId(methodIdItem);
|
||||||
|
if (encodedMethod == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//A synthetic accessor will be marked synthetic
|
||||||
|
if ((encodedMethod.accessFlags & AccessFlags.SYNTHETIC.getValue()) == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Instruction[] instructions = encodedMethod.codeItem.getInstructions();
|
||||||
|
|
||||||
|
//TODO: add support for odexed formats
|
||||||
|
switch (instructions[0].opcode.format) {
|
||||||
|
case Format35c:
|
||||||
|
case Format3rc: {
|
||||||
|
//a synthetic method access should be either 2 or 3 instructions, depending on if the method returns
|
||||||
|
//anything or not
|
||||||
|
if (instructions.length < 2 || instructions.length > 3) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
InstructionWithReference instruction = (InstructionWithReference)instructions[0];
|
||||||
|
MethodIdItem referencedMethodIdItem = (MethodIdItem)instruction.getReferencedItem();
|
||||||
|
|
||||||
|
accessedMember = new AccessedMember(METHOD, referencedMethodIdItem);
|
||||||
|
resolvedAccessors.put(methodIdItem, accessedMember);
|
||||||
|
return accessedMember;
|
||||||
|
}
|
||||||
|
case Format22c: {
|
||||||
|
//a synthetic field access should be exactly 2 instructions. The set/put, and then the return
|
||||||
|
if (instructions.length != 2) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Instruction22c instruction = (Instruction22c)instructions[0];
|
||||||
|
FieldIdItem referencedFieldIdItem = (FieldIdItem)instruction.getReferencedItem();
|
||||||
|
|
||||||
|
if (instruction.opcode.setsRegister() || instruction.opcode.setsWideRegister()) {
|
||||||
|
accessedMember = new AccessedMember(GETTER, referencedFieldIdItem);
|
||||||
|
} else {
|
||||||
|
accessedMember = new AccessedMember(SETTER, referencedFieldIdItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
resolvedAccessors.put(methodIdItem, accessedMember);
|
||||||
|
return accessedMember;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AccessedMember {
|
||||||
|
private final int accessedMemberType;
|
||||||
|
private final Item accessedMember;
|
||||||
|
|
||||||
|
public AccessedMember(int accessedMemberType, Item accessedMember) {
|
||||||
|
this.accessedMemberType = accessedMemberType;
|
||||||
|
this.accessedMember = accessedMember;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAccessedMemberType() {
|
||||||
|
return accessedMemberType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Item getAccessedMember() {
|
||||||
|
return accessedMember;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user