mirror of
https://github.com/revanced/smali.git
synced 2025-05-08 10:24:31 +02:00
Added caching for the rest of the deodexerant commands
git-svn-id: https://smali.googlecode.com/svn/trunk@443 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
parent
f0e3677538
commit
6fa95185b7
@ -46,6 +46,9 @@ public class Deodexerant {
|
||||
private final int port;
|
||||
|
||||
private final HashMap<TypeIdItem, ClassData> vtableMap = new HashMap<TypeIdItem, ClassData>();
|
||||
private final HashMap<CommonSuperclassLookup, String> cachedCommonSuperclassLookup =
|
||||
new HashMap<CommonSuperclassLookup, String>();
|
||||
private InlineMethod[] inlineMethods;
|
||||
|
||||
public final DexFile dexFile;
|
||||
|
||||
@ -59,30 +62,34 @@ public class Deodexerant {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public InlineMethod lookupInlineMethod(int inlineMethodIndex) {
|
||||
connectIfNeeded();
|
||||
private void loadInlineMethods() {
|
||||
List<String> responseLines = sendMultilineCommand("I");
|
||||
|
||||
String response = sendCommand("I " + inlineMethodIndex);
|
||||
inlineMethods = new InlineMethod[responseLines.size()];
|
||||
for (int i=0; i<inlineMethods.length; i++) {
|
||||
String response = responseLines.get(i);
|
||||
if (!response.startsWith("inline: ")) {
|
||||
throw new RuntimeException("Invalid response from deodexerant");
|
||||
}
|
||||
|
||||
String[] parts = response.substring(8).split(" ");
|
||||
if (parts.length != 2) {
|
||||
throw new RuntimeException("Invalid response from deodexerant");
|
||||
}
|
||||
|
||||
String methodType = parts[0];
|
||||
InlineMethodType type;
|
||||
|
||||
if (response.startsWith("virtual")) {
|
||||
if (methodType.equals("virtual")) {
|
||||
type = InlineMethodType.Virtual;
|
||||
} else if (response.startsWith("direct")) {
|
||||
} else if (methodType.equals("direct")) {
|
||||
type = InlineMethodType.Direct;
|
||||
} else if (response.startsWith("static")) {
|
||||
} else if (methodType.equals("static")) {
|
||||
type = InlineMethodType.Static;
|
||||
} else {
|
||||
throw new RuntimeException("Invalid response from deodexerant");
|
||||
}
|
||||
|
||||
|
||||
int colon = response.indexOf(':');
|
||||
if (colon == -1) {
|
||||
throw new RuntimeException("Invalid response from deodexerant");
|
||||
}
|
||||
|
||||
String methodDescriptor = response.substring(colon+2);
|
||||
String methodDescriptor = parts[1];
|
||||
|
||||
Matcher m = fullMethodPattern.matcher(methodDescriptor);
|
||||
if (!m.matches()) {
|
||||
@ -96,30 +103,36 @@ public class Deodexerant {
|
||||
|
||||
TypeIdItem classTypeItem = TypeIdItem.getInternedTypeIdItem(dexFile, classType);
|
||||
if (classTypeItem == null) {
|
||||
throw new RuntimeException("Could not find type " + classType + " in the dex file");
|
||||
inlineMethods[i] = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
MethodIdItem method = parseAndResolveMethod(classTypeItem, methodName, methodParams, methodRet);
|
||||
if (method == null) {
|
||||
throw new RuntimeException("Could not find method " + methodDescriptor + " in the dex file");
|
||||
inlineMethods[i] = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
return new InlineMethod(method, type);
|
||||
inlineMethods[i] = new InlineMethod(method, type);
|
||||
}
|
||||
}
|
||||
|
||||
public InlineMethod lookupInlineMethod(int inlineMethodIndex) {
|
||||
if (inlineMethods == null) {
|
||||
loadInlineMethods();
|
||||
}
|
||||
|
||||
if (inlineMethodIndex >= inlineMethods.length) {
|
||||
throw new RuntimeException("Invalid inline method index " + inlineMethodIndex + ". Too big.");
|
||||
}
|
||||
|
||||
return inlineMethods[inlineMethodIndex];
|
||||
}
|
||||
|
||||
public FieldIdItem lookupField(TypeIdItem type, int fieldOffset) {
|
||||
connectIfNeeded();
|
||||
ClassData classData = getClassData(type);
|
||||
|
||||
String response = sendCommand("F " + type.getTypeDescriptor() + " " + fieldOffset);
|
||||
|
||||
int colon = response.indexOf(':');
|
||||
if (colon == -1) {
|
||||
throw new RuntimeException("Invalid response from deodexerant");
|
||||
}
|
||||
|
||||
String fieldDescriptor = response.substring(colon+2);
|
||||
|
||||
return parseAndLookupField(fieldDescriptor);
|
||||
return classData.lookupField(fieldOffset);
|
||||
}
|
||||
|
||||
private ClassData getClassData(TypeIdItem type) {
|
||||
@ -168,15 +181,20 @@ public class Deodexerant {
|
||||
}
|
||||
|
||||
public String lookupCommonSuperclass(String typeDescriptor1, String typeDescriptor2) {
|
||||
connectIfNeeded();
|
||||
|
||||
CommonSuperclassLookup lookup = new CommonSuperclassLookup(typeDescriptor1, typeDescriptor2);
|
||||
String result = cachedCommonSuperclassLookup.get(lookup);
|
||||
if (result == null) {
|
||||
String response = sendCommand("C " + typeDescriptor1 + " " + typeDescriptor2);
|
||||
int colon = response.indexOf(':');
|
||||
if (colon == -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return response.substring(colon+2);
|
||||
result = response.substring(colon+2);
|
||||
|
||||
cachedCommonSuperclassLookup.put(lookup, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private String sendCommand(String cmd) {
|
||||
@ -199,7 +217,7 @@ public class Deodexerant {
|
||||
//The command is still just a single line, but we're expecting a multi-line
|
||||
//response. The repsonse is considered finished when a line starting with "err"
|
||||
//or with "done" is encountered
|
||||
private List<String> sendMultlineCommand(String cmd) {
|
||||
private List<String> sendMultilineCommand(String cmd) {
|
||||
try {
|
||||
connectIfNeeded();
|
||||
|
||||
@ -208,6 +226,9 @@ public class Deodexerant {
|
||||
|
||||
ArrayList<String> responseLines = new ArrayList<String>();
|
||||
String response = in.readLine();
|
||||
if (response == null) {
|
||||
throw new RuntimeException("Error talking to deodexerant");
|
||||
}
|
||||
while (!response.startsWith("done"))
|
||||
{
|
||||
if (response.startsWith("err")) {
|
||||
@ -344,23 +365,28 @@ public class Deodexerant {
|
||||
|
||||
private static final Pattern fullMethodPattern = Pattern.compile("(\\[*(?:L[^;]+;|[ZBSCIJFD]))->([^(]+)\\(([^)]*)\\)(.+)");
|
||||
private static final Pattern shortMethodPattern = Pattern.compile("([^(]+)\\(([^)]*)\\)(.+)");
|
||||
//private static final Pattern fieldPattern = Pattern.compile("(\\[*L[^;]+;)->([^:]+):(.+)");
|
||||
|
||||
private static final Pattern fieldPattern = Pattern.compile("(\\[*L[^;]+;)->([^:]+):(.+)");
|
||||
private FieldIdItem parseAndLookupField(String field) {
|
||||
//expecting a string like Lsome/class;->someField:Lfield/type;
|
||||
|
||||
Matcher m = fieldPattern.matcher(field);
|
||||
if (!m.matches()) {
|
||||
throw new RuntimeException("invalid field string: " + field);
|
||||
private FieldIdItem parseAndResolveField(TypeIdItem classType, String field) {
|
||||
//expecting a string like someField:Lfield/type;
|
||||
String[] parts = field.split(":");
|
||||
if (parts.length != 2) {
|
||||
throw new RuntimeException("Invalid field descriptor " + field);
|
||||
}
|
||||
|
||||
String clazz = m.group(1);
|
||||
String fieldName = m.group(2);
|
||||
String fieldType = m.group(3);
|
||||
String fieldName = parts[0];
|
||||
String fieldType = parts[1];
|
||||
|
||||
TypeIdItem classType = TypeIdItem.getInternedTypeIdItem(dexFile, clazz);
|
||||
StringIdItem fieldNameItem = StringIdItem.getInternedStringIdItem(dexFile, fieldName);
|
||||
if (fieldNameItem == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TypeIdItem fieldTypeItem = TypeIdItem.getInternedTypeIdItem(dexFile, fieldType);
|
||||
if (fieldTypeItem == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
FieldIdItem fieldIdItem;
|
||||
|
||||
@ -408,13 +434,17 @@ public class Deodexerant {
|
||||
|
||||
|
||||
private class ClassData {
|
||||
public final TypeIdItem ClassType;
|
||||
private final TypeIdItem ClassType;
|
||||
|
||||
public boolean vtableLoaded;
|
||||
public String[] MethodNames;
|
||||
public String[] MethodParams;
|
||||
public String[] MethodRets;
|
||||
public MethodIdItem[] resolvedMethods;
|
||||
private boolean vtableLoaded = false;
|
||||
private String[] methodNames;
|
||||
private String[] methodParams;
|
||||
private String[] methodRets;
|
||||
private MethodIdItem[] resolvedMethods;
|
||||
|
||||
private boolean fieldsLoaded = false;
|
||||
private SparseArray<String> instanceFields;
|
||||
private SparseArray<FieldIdItem> resolvedFields;
|
||||
|
||||
|
||||
public ClassData(TypeIdItem classType) {
|
||||
@ -430,18 +460,38 @@ public class Deodexerant {
|
||||
throw new RuntimeException("Invalid vtable index " + index + ". Too large.");
|
||||
}
|
||||
if (resolvedMethods[index] == null) {
|
||||
resolvedMethods[index] = parseAndResolveMethod(ClassType, MethodNames[index], MethodParams[index],
|
||||
MethodRets[index]);
|
||||
resolvedMethods[index] = parseAndResolveMethod(ClassType, methodNames[index], methodParams[index],
|
||||
methodRets[index]);
|
||||
}
|
||||
return resolvedMethods[index];
|
||||
}
|
||||
|
||||
private void loadvtable() {
|
||||
List<String> responseLines = sendMultlineCommand("V " + ClassType.getTypeDescriptor());
|
||||
public FieldIdItem lookupField(int fieldOffset) {
|
||||
if (!fieldsLoaded) {
|
||||
loadFields();
|
||||
}
|
||||
|
||||
MethodNames = new String[responseLines.size()];
|
||||
MethodParams = new String[responseLines.size()];
|
||||
MethodRets = new String[responseLines.size()];
|
||||
FieldIdItem fieldIdItem = resolvedFields.get(fieldOffset);
|
||||
if (fieldIdItem == null) {
|
||||
String field = instanceFields.get(fieldOffset);
|
||||
if (field == null) {
|
||||
throw new RuntimeException("Invalid field offset " + fieldOffset);
|
||||
}
|
||||
fieldIdItem = parseAndResolveField(ClassType, field);
|
||||
if (fieldIdItem != null) {
|
||||
resolvedFields.put(fieldOffset, fieldIdItem);
|
||||
}
|
||||
}
|
||||
return fieldIdItem;
|
||||
|
||||
}
|
||||
|
||||
private void loadvtable() {
|
||||
List<String> responseLines = sendMultilineCommand("V " + ClassType.getTypeDescriptor());
|
||||
|
||||
methodNames = new String[responseLines.size()];
|
||||
methodParams = new String[responseLines.size()];
|
||||
methodRets = new String[responseLines.size()];
|
||||
resolvedMethods = new MethodIdItem[responseLines.size()];
|
||||
|
||||
int index = 0;
|
||||
@ -456,13 +506,62 @@ public class Deodexerant {
|
||||
throw new RuntimeException("invalid method string: " + method);
|
||||
}
|
||||
|
||||
MethodNames[index] = m.group(1);
|
||||
MethodParams[index] = m.group(2);
|
||||
MethodRets[index] = m.group(3);
|
||||
methodNames[index] = m.group(1);
|
||||
methodParams[index] = m.group(2);
|
||||
methodRets[index] = m.group(3);
|
||||
index++;
|
||||
}
|
||||
|
||||
vtableLoaded = true;
|
||||
}
|
||||
|
||||
private void loadFields() {
|
||||
List<String> responseLines = sendMultilineCommand("F " + ClassType.getTypeDescriptor());
|
||||
|
||||
instanceFields = new SparseArray<String>(responseLines.size());
|
||||
resolvedFields = new SparseArray<FieldIdItem>(responseLines.size());
|
||||
|
||||
for (String fieldLine: responseLines) {
|
||||
if (!fieldLine.startsWith("field: ")) {
|
||||
throw new RuntimeException("Invalid response from deodexerant");
|
||||
}
|
||||
|
||||
String field = fieldLine.substring(7);
|
||||
String[] parts = field.split(" ");
|
||||
if (parts.length != 2) {
|
||||
throw new RuntimeException("Invalid response from deodexerant");
|
||||
}
|
||||
|
||||
int fieldOffset = Integer.parseInt(parts[0]);
|
||||
instanceFields.put(fieldOffset, parts[1]);
|
||||
}
|
||||
|
||||
fieldsLoaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static class CommonSuperclassLookup {
|
||||
public final String Type1;
|
||||
public final String Type2;
|
||||
|
||||
public CommonSuperclassLookup(String type1, String type2) {
|
||||
this.Type1 = type1;
|
||||
this.Type2 = type2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
CommonSuperclassLookup that = (CommonSuperclassLookup) o;
|
||||
|
||||
return Type1.equals(that.Type1) && Type2.equals(that.Type2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Type1.hashCode() + 31 * Type2.hashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user