mirror of
https://github.com/revanced/smali.git
synced 2025-06-01 05:00:12 +02:00
Add support for unresolved types. This isn't fatal in all cases
git-svn-id: https://smali.googlecode.com/svn/trunk@622 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
parent
c9be5e1303
commit
1ed567427b
@ -94,7 +94,8 @@ public class ClassPath {
|
|||||||
if (classType.charAt(0) == '[') {
|
if (classType.charAt(0) == '[') {
|
||||||
return theClassPath.createArrayClassDef(classType);
|
return theClassPath.createArrayClassDef(classType);
|
||||||
} else {
|
} else {
|
||||||
throw new ClassNotFoundException("Class " + classType + " cannot be found");
|
//TODO: we should output a warning
|
||||||
|
return theClassPath.createUnresolvedClassDef(classType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return classDef;
|
return classDef;
|
||||||
@ -112,7 +113,15 @@ public class ClassPath {
|
|||||||
return getClassDef(arrayPrefix.substring(256 - arrayDimension) + classDef.classType);
|
return getClassDef(arrayPrefix.substring(256 - arrayDimension) + classDef.classType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ClassDef createArrayClassDef(String arrayClassName) {
|
private ClassDef createUnresolvedClassDef(String classType) {
|
||||||
|
assert classType.charAt(0) == 'L';
|
||||||
|
|
||||||
|
UnresolvedClassDef unresolvedClassDef = new UnresolvedClassDef(classType);
|
||||||
|
classDefs.put(classType, unresolvedClassDef);
|
||||||
|
return unresolvedClassDef;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClassDef createArrayClassDef(String arrayClassName) {
|
||||||
assert arrayClassName != null;
|
assert arrayClassName != null;
|
||||||
assert arrayClassName.charAt(0) == '[';
|
assert arrayClassName.charAt(0) == '[';
|
||||||
|
|
||||||
@ -121,7 +130,7 @@ public class ClassPath {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
theClassPath.classDefs.put(arrayClassName, arrayClassDef);
|
classDefs.put(arrayClassName, arrayClassDef);
|
||||||
return arrayClassDef;
|
return arrayClassDef;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,7 +225,7 @@ public class ClassPath {
|
|||||||
private final int arrayDimensions;
|
private final int arrayDimensions;
|
||||||
|
|
||||||
protected ArrayClassDef(String arrayClassType) {
|
protected ArrayClassDef(String arrayClassType) {
|
||||||
super(arrayClassType, true);
|
super(arrayClassType, ClassDef.ArrayClassDef);
|
||||||
assert arrayClassType.charAt(0) == '[';
|
assert arrayClassType.charAt(0) == '[';
|
||||||
|
|
||||||
int i=0;
|
int i=0;
|
||||||
@ -299,17 +308,53 @@ public class ClassPath {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean implementsInterface(ClassDef interfaceDef) {
|
|
||||||
return interfaceDef.classType.equals("Ljava/lang/Cloneable;") ||
|
|
||||||
interfaceDef.classType.equals("Ljava/io/Serializable;");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class PrimitiveClassDef extends ClassDef {
|
public static class PrimitiveClassDef extends ClassDef {
|
||||||
protected PrimitiveClassDef(String primitiveClassType) {
|
protected PrimitiveClassDef(String primitiveClassType) {
|
||||||
super(primitiveClassType, false);
|
super(primitiveClassType, ClassDef.PrimitiveClassDef);
|
||||||
|
assert primitiveClassType.charAt(0) != 'L' && primitiveClassType.charAt(0) != '[';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class UnresolvedClassDef extends ClassDef {
|
||||||
|
protected UnresolvedClassDef(String unresolvedClassDef) {
|
||||||
|
super(unresolvedClassDef, ClassDef.UnresolvedClassDef);
|
||||||
|
assert unresolvedClassDef.charAt(0) == 'L';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ValidationException unresolvedValidationException() {
|
||||||
|
return new ValidationException(String.format("class %s cannot be resolved.", this.getClassType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassDef getSuperclass() {
|
||||||
|
throw unresolvedValidationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getClassDepth() {
|
||||||
|
throw unresolvedValidationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInterface() {
|
||||||
|
throw unresolvedValidationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean extendsClass(ClassDef superclassDef) {
|
||||||
|
if (superclassDef != theClassPath.javaLangObjectClassDef && superclassDef != this) {
|
||||||
|
throw unresolvedValidationException();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean implementsInterface(ClassDef interfaceDef) {
|
||||||
|
throw unresolvedValidationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasVirtualMethod(String method) {
|
||||||
|
if (!super.hasVirtualMethod(method)) {
|
||||||
|
throw unresolvedValidationException();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,14 +378,18 @@ public class ClassPath {
|
|||||||
private final SparseArray<String> instanceFields;
|
private final SparseArray<String> instanceFields;
|
||||||
private final HashMap<String, Integer> instanceFieldLookup;
|
private final HashMap<String, Integer> instanceFieldLookup;
|
||||||
|
|
||||||
|
public final static int ArrayClassDef = 0;
|
||||||
|
public final static int PrimitiveClassDef = 1;
|
||||||
|
public final static int UnresolvedClassDef = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor is used for the ArrayClassDef and PrimitiveClassDef subclasses
|
* This constructor is used for the ArrayClassDef, PrimitiveClassDef and UnresolvedClassDef subclasses
|
||||||
* @param classType the class type
|
* @param classType the class type
|
||||||
* @param isArrayType whether this is an array ClassDef or a primitive ClassDef
|
* @param classFlavor one of ArrayClassDef, PrimitiveClassDef or UnresolvedClassDef
|
||||||
*/
|
*/
|
||||||
protected ClassDef(String classType, boolean isArrayType) {
|
protected ClassDef(String classType, int classFlavor) {
|
||||||
if (isArrayType) {
|
if (classFlavor == ArrayClassDef) {
|
||||||
assert (classType.charAt(0) == '[');
|
assert classType.charAt(0) == '[';
|
||||||
this.classType = classType;
|
this.classType = classType;
|
||||||
this.superclass = ClassPath.theClassPath.javaLangObjectClassDef;
|
this.superclass = ClassPath.theClassPath.javaLangObjectClassDef;
|
||||||
implementedInterfaces = new TreeSet<ClassDef>();
|
implementedInterfaces = new TreeSet<ClassDef>();
|
||||||
@ -354,8 +403,10 @@ public class ClassPath {
|
|||||||
instanceFields = superclass.instanceFields;
|
instanceFields = superclass.instanceFields;
|
||||||
instanceFieldLookup = superclass.instanceFieldLookup;
|
instanceFieldLookup = superclass.instanceFieldLookup;
|
||||||
classDepth = 1; //1 off from java.lang.Object
|
classDepth = 1; //1 off from java.lang.Object
|
||||||
} else {
|
} else if (classFlavor == PrimitiveClassDef) {
|
||||||
//primitive type
|
//primitive type
|
||||||
|
assert classType.charAt(0) != '[' && classType.charAt(0) != 'L';
|
||||||
|
|
||||||
this.classType = classType;
|
this.classType = classType;
|
||||||
this.superclass = null;
|
this.superclass = null;
|
||||||
implementedInterfaces = null;
|
implementedInterfaces = null;
|
||||||
@ -365,6 +416,19 @@ public class ClassPath {
|
|||||||
instanceFields = null;
|
instanceFields = null;
|
||||||
instanceFieldLookup = null;
|
instanceFieldLookup = null;
|
||||||
classDepth = 0; //TODO: maybe use -1 to indicate not applicable?
|
classDepth = 0; //TODO: maybe use -1 to indicate not applicable?
|
||||||
|
} else /*if (classFlavor == UnresolvedClassDef)*/ {
|
||||||
|
assert classType.charAt(0) == 'L';
|
||||||
|
this.classType = classType;
|
||||||
|
this.superclass = ClassPath.theClassPath.javaLangObjectClassDef;
|
||||||
|
implementedInterfaces = new TreeSet<ClassDef>();
|
||||||
|
isInterface = false;
|
||||||
|
|
||||||
|
vtable = superclass.vtable;
|
||||||
|
virtualMethodLookup = superclass.virtualMethodLookup;
|
||||||
|
|
||||||
|
instanceFields = superclass.instanceFields;
|
||||||
|
instanceFieldLookup = superclass.instanceFieldLookup;
|
||||||
|
classDepth = 1; //1 off from java.lang.Object
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -420,6 +484,10 @@ public class ClassPath {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (superclassDef instanceof UnresolvedClassDef) {
|
||||||
|
throw ((UnresolvedClassDef)superclassDef).unresolvedValidationException();
|
||||||
|
}
|
||||||
|
|
||||||
int superclassDepth = superclassDef.classDepth;
|
int superclassDepth = superclassDef.classDepth;
|
||||||
ClassDef ancestor = this;
|
ClassDef ancestor = this;
|
||||||
while (ancestor.classDepth > superclassDepth) {
|
while (ancestor.classDepth > superclassDepth) {
|
||||||
@ -437,6 +505,7 @@ public class ClassPath {
|
|||||||
* @return true if this class implements the given interface
|
* @return true if this class implements the given interface
|
||||||
*/
|
*/
|
||||||
public boolean implementsInterface(ClassDef interfaceDef) {
|
public boolean implementsInterface(ClassDef interfaceDef) {
|
||||||
|
assert !(interfaceDef instanceof UnresolvedClassDef);
|
||||||
return implementedInterfaces.contains(interfaceDef);
|
return implementedInterfaces.contains(interfaceDef);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -444,25 +513,6 @@ public class ClassPath {
|
|||||||
return virtualMethodLookup.containsKey(method);
|
return virtualMethodLookup.containsKey(method);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: GROT
|
|
||||||
/*public void dumpVtable() {
|
|
||||||
System.out.println(classType + " methods:");
|
|
||||||
int i=0;
|
|
||||||
for (String method: vtable) {
|
|
||||||
System.out.println(i + ":\t" + method);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
//TODO: GROT
|
|
||||||
/*public void dumpFields() {
|
|
||||||
System.out.println(classType + " fields:");
|
|
||||||
for (int i=0; i<instanceFields.size(); i++) {
|
|
||||||
int fieldOffset = instanceFields.keyAt(i);
|
|
||||||
System.out.println(fieldOffset + ":\t" + instanceFields.valueAt(i));
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
private void swap(byte[] fieldTypes, String[] fields, int position1, int position2) {
|
private void swap(byte[] fieldTypes, String[] fields, int position1, int position2) {
|
||||||
byte tempType = fieldTypes[position1];
|
byte tempType = fieldTypes[position1];
|
||||||
fieldTypes[position1] = fieldTypes[position2];
|
fieldTypes[position1] = fieldTypes[position2];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user