java annotations support for dalvik

This commit is contained in:
Julian Dolby 2015-03-04 13:49:58 -05:00
parent 3cd36c904b
commit de26484098
16 changed files with 547 additions and 182 deletions

View File

@ -13,22 +13,17 @@ package com.ibm.wala.core.tests.ir;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import com.ibm.wala.classLoader.BytecodeClass;
import com.ibm.wala.classLoader.IBytecodeMethod;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IField;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.classLoader.ShrikeCTMethod;
import com.ibm.wala.classLoader.ShrikeClass;
import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil;
import com.ibm.wala.core.tests.util.TestConstants;
import com.ibm.wala.core.tests.util.WalaTestCase;
import com.ibm.wala.ipa.callgraph.AnalysisScope;
import com.ibm.wala.ipa.cha.ClassHierarchy;
import com.ibm.wala.ipa.cha.ClassHierarchyException;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.shrikeCT.InvalidClassFileException;
@ -39,30 +34,13 @@ import com.ibm.wala.types.Selector;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.types.annotations.Annotation;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.config.AnalysisScopeReader;
import com.ibm.wala.util.io.FileProvider;
import com.ibm.wala.util.collections.Pair;
import com.ibm.wala.util.strings.Atom;
public class AnnotationTest extends WalaTestCase {
public abstract class AnnotationTest extends WalaTestCase {
public static void main(String[] args) {
justThisTest(AnnotationTest.class);
}
private static IClassHierarchy cha;
protected static IClassHierarchy cha;
@BeforeClass
public static void before() throws IOException, ClassHierarchyException {
AnalysisScope scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA,
(new FileProvider()).getFile(CallGraphTestUtil.REGRESSION_EXCLUSIONS), AnnotationTest.class.getClassLoader());
cha = ClassHierarchy.make(scope);
}
@AfterClass
public static void after() {
cha = null;
}
@Test
public void testClassAnnotations1() throws Exception {
TypeReference typeUnderTest = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/AnnotatedClass1");
@ -104,13 +82,13 @@ public class AnnotationTest extends WalaTestCase {
InvalidClassFileException {
IClass classUnderTest = cha.lookupClass(typeUnderTest);
Assert.assertNotNull(typeUnderTest.toString() + " not found", classUnderTest);
Assert.assertTrue(classUnderTest instanceof ShrikeClass);
ShrikeClass shrikeClassUnderTest = (ShrikeClass) classUnderTest;
Assert.assertTrue(classUnderTest instanceof BytecodeClass);
BytecodeClass<?> bcClassUnderTest = (BytecodeClass<?>) classUnderTest;
Collection<Annotation> runtimeInvisibleAnnotations = shrikeClassUnderTest.getRuntimeInvisibleAnnotations();
Collection<Annotation> runtimeInvisibleAnnotations = bcClassUnderTest.getAnnotations(true);
assertEqualCollections(expectedRuntimeInvisibleAnnotations, runtimeInvisibleAnnotations);
Collection<Annotation> runtimeVisibleAnnotations = shrikeClassUnderTest.getRuntimeVisibleAnnotations();
Collection<Annotation> runtimeVisibleAnnotations = bcClassUnderTest.getAnnotations(false);
assertEqualCollections(expectedRuntimeVisibleAnnotations, runtimeVisibleAnnotations);
}
@ -130,13 +108,14 @@ public class AnnotationTest extends WalaTestCase {
}
}
@SuppressWarnings("unchecked")
@Test
public void testClassAnnotations3() throws Exception {
TypeReference typeRef = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/AnnotatedClass3");
IClass klass = cha.lookupClass(typeRef);
Assert.assertNotNull(klass);
ShrikeClass shrikeClass = (ShrikeClass) klass;
BytecodeClass<?> shrikeClass = (BytecodeClass<?>) klass;
Collection<Annotation> classAnnotations = shrikeClass.getAnnotations(true);
Assert.assertEquals("[Annotation type <Application,Lannotations/AnnotationWithParams> {strParam=classStrParam}]",
classAnnotations.toString());
@ -145,16 +124,23 @@ public class AnnotationTest extends WalaTestCase {
IMethod methodUnderTest = cha.resolveMethod(methodRefUnderTest);
Assert.assertNotNull(methodRefUnderTest.toString() + " not found", methodUnderTest);
Assert.assertTrue(methodUnderTest instanceof ShrikeCTMethod);
ShrikeCTMethod shrikeCTMethodUnderTest = (ShrikeCTMethod) methodUnderTest;
Assert.assertTrue(methodUnderTest instanceof IBytecodeMethod);
IBytecodeMethod bcMethodUnderTest = (IBytecodeMethod) methodUnderTest;
Collection<Annotation> runtimeInvisibleAnnotations = shrikeCTMethodUnderTest.getAnnotations(true);
Assert
.assertEquals(
"[Annotation type <Application,Lannotations/AnnotationWithParams> {enumParam=EnumElementValue [type=Lannotations/AnnotationEnum;, val=VAL1], strArrParam=ArrayElementValue [vals=[biz, boz]], annotParam=AnnotationElementValue [type=Lannotations/AnnotationWithSingleParam;, elementValues={value=sdfevs}], strParam=sdfsevs, intParam=25, klassParam=Ljava/lang/Integer;}]",
runtimeInvisibleAnnotations.toString());
}
Collection<Annotation> runtimeInvisibleAnnotations = bcMethodUnderTest.getAnnotations(true);
Assert.assertEquals(1, runtimeInvisibleAnnotations.size());
Annotation x = runtimeInvisibleAnnotations.iterator().next();
Assert.assertEquals(TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/AnnotationWithParams"), x.getType());
for(Pair<String,String> n : new Pair[]{Pair.make("enumParam", "EnumElementValue [type=Lannotations/AnnotationEnum;, val=VAL1]"),
Pair.make("strArrParam", "ArrayElementValue [vals=[biz, boz]]"),
Pair.make("annotParam", "AnnotationElementValue [type=Lannotations/AnnotationWithSingleParam;, elementValues={value=sdfevs}]"),
Pair.make("strParam", "sdfsevs"),
Pair.make("intParam", "25"),
Pair.make("klassParam", "Ljava/lang/Integer;")}) {
Assert.assertEquals(n.snd, x.getNamedArguments().get(n.fst).toString());
}
}
@Test
public void testClassAnnotations4() throws Exception {
@ -179,35 +165,47 @@ public class AnnotationTest extends WalaTestCase {
TypeReference typeRef = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/ParameterAnnotations1");
checkParameterAnnots(typeRef, "foo(Ljava/lang/String;)V",
"[Annotation type <Application,Lannotations/RuntimeVisableAnnotation>]");
new String[]{"Annotation type <Application,Lannotations/RuntimeVisableAnnotation>"});
checkParameterAnnots(
typeRef,
"bar(Ljava/lang/Integer;)V",
"[Annotation type <Application,Lannotations/AnnotationWithParams> {enumParam=EnumElementValue [type=Lannotations/AnnotationEnum;, val=VAL1], strArrParam=ArrayElementValue [vals=[biz, boz]], annotParam=AnnotationElementValue [type=Lannotations/AnnotationWithSingleParam;, elementValues={value=sdfevs}], strParam=sdfsevs, intParam=25, klassParam=Ljava/lang/Integer;}]");
new String[]{"Annotation type <Application,Lannotations/AnnotationWithParams> {annotParam=AnnotationElementValue [type=Lannotations/AnnotationWithSingleParam;, elementValues={value=sdfevs}], enumParam=EnumElementValue [type=Lannotations/AnnotationEnum;, val=VAL1], intParam=25, klassParam=Ljava/lang/Integer;, strArrParam=ArrayElementValue [vals=[biz, boz]], strParam=sdfsevs}"});
checkParameterAnnots(typeRef, "foo2(Ljava/lang/String;Ljava/lang/Integer;)V",
"[Annotation type <Application,Lannotations/RuntimeVisableAnnotation>]",
"[Annotation type <Application,Lannotations/RuntimeInvisableAnnotation>]");
new String[]{"Annotation type <Application,Lannotations/RuntimeVisableAnnotation>"},
new String[]{"Annotation type <Application,Lannotations/RuntimeInvisableAnnotation>"});
checkParameterAnnots(typeRef, "foo3(Ljava/lang/String;Ljava/lang/Integer;)V",
"[Annotation type <Application,Lannotations/RuntimeVisableAnnotation>]",
"[Annotation type <Application,Lannotations/RuntimeInvisableAnnotation>]");
new String[]{"Annotation type <Application,Lannotations/RuntimeVisableAnnotation>"},
new String[]{"Annotation type <Application,Lannotations/RuntimeInvisableAnnotation>"});
checkParameterAnnots(typeRef, "foo4(Ljava/lang/String;Ljava/lang/Integer;)V",
"[Annotation type <Application,Lannotations/RuntimeInvisableAnnotation>, Annotation type <Application,Lannotations/RuntimeVisableAnnotation>]",
"[]");
new String[]{"Annotation type <Application,Lannotations/RuntimeInvisableAnnotation>", "Annotation type <Application,Lannotations/RuntimeVisableAnnotation>"},
new String[0]);
}
protected void checkParameterAnnots(TypeReference typeRef, String selector, String... expected) {
protected void checkParameterAnnots(TypeReference typeRef, String selector, String[]... expected) {
MethodReference methodRefUnderTest = MethodReference.findOrCreate(typeRef, Selector.make(selector));
IMethod methodUnderTest = cha.resolveMethod(methodRefUnderTest);
Assert.assertNotNull(methodRefUnderTest.toString() + " not found", methodUnderTest);
Assert.assertTrue(methodUnderTest instanceof ShrikeCTMethod);
ShrikeCTMethod shrikeCTMethodUnderTest = (ShrikeCTMethod) methodUnderTest;
Assert.assertTrue(methodUnderTest instanceof IBytecodeMethod);
IBytecodeMethod IBytecodeMethodUnderTest = (IBytecodeMethod) methodUnderTest;
Collection<Annotation>[] parameterAnnotations = shrikeCTMethodUnderTest.getParameterAnnotations();
Collection<Annotation>[] parameterAnnotations = IBytecodeMethodUnderTest.getParameterAnnotations();
Assert.assertEquals(expected.length, parameterAnnotations.length);
for (int i = 0; i < expected.length; i++) {
Assert.assertEquals(expected[i], parameterAnnotations[i].toString());
Set<String> e = HashSetFactory.make();
for(String s : expected[i]) {
e.add(s);
}
Set<String> a = HashSetFactory.make();
if (parameterAnnotations[i] != null) {
for(Annotation x : parameterAnnotations[i]) {
a.add(x.toString());
}
}
Assert.assertEquals(e, a);
}
}

View File

@ -0,0 +1,34 @@
package com.ibm.wala.core.tests.ir;
import java.io.IOException;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil;
import com.ibm.wala.core.tests.util.TestConstants;
import com.ibm.wala.ipa.callgraph.AnalysisScope;
import com.ibm.wala.ipa.cha.ClassHierarchy;
import com.ibm.wala.ipa.cha.ClassHierarchyException;
import com.ibm.wala.util.config.AnalysisScopeReader;
import com.ibm.wala.util.io.FileProvider;
public class JVMLAnnotationTest extends AnnotationTest {
public static void main(String[] args) {
justThisTest(JVMLAnnotationTest.class);
}
@BeforeClass
public static void before() throws IOException, ClassHierarchyException {
AnalysisScope scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA,
(new FileProvider()).getFile(CallGraphTestUtil.REGRESSION_EXCLUSIONS), AnnotationTest.class.getClassLoader());
cha = ClassHierarchy.make(scope);
}
@AfterClass
public static void after() {
cha = null;
}
}

View File

@ -590,4 +590,7 @@ public abstract class BytecodeClass<T extends IClassLoader> implements IClass {
}
}
}
public abstract Collection<Annotation> getAnnotations(boolean runtimeVisible) throws InvalidClassFileException;
}

View File

@ -16,6 +16,7 @@ import com.ibm.wala.shrikeBT.ExceptionHandler;
import com.ibm.wala.shrikeBT.IInstruction;
import com.ibm.wala.shrikeBT.IndirectionData;
import com.ibm.wala.shrikeCT.InvalidClassFileException;
import com.ibm.wala.types.annotations.Annotation;
/**
* A method which originated in bytecode, decoded by Shrike
@ -47,4 +48,8 @@ public interface IBytecodeMethod extends IMethod {
*/
IndirectionData getIndirectionData();
Collection<Annotation>[] getParameterAnnotations();
Collection<Annotation> getAnnotations(boolean runtimeVisible) throws InvalidClassFileException;
}

View File

@ -183,5 +183,5 @@ public interface IClass extends IClassHierarchyDweller {
* get annotations, if any
*/
Collection<Annotation> getAnnotations();
}

View File

@ -446,6 +446,7 @@ public final class ShrikeCTMethod extends ShrikeBTMethod implements IBytecodeMet
return getAnnotations(false);
}
@Override
public Collection<Annotation> getAnnotations(boolean runtimeInvisible) throws InvalidClassFileException {
AnnotationsReader r = getAnnotationsReader(runtimeInvisible ? AnnotationType.RuntimeInvisibleAnnotations
: AnnotationType.RuntimeVisibleAnnotations);

View File

@ -244,6 +244,7 @@ public final class ShrikeClass extends JVMClass<IClassLoader> {
return result;
}
@Override
public Collection<Annotation> getAnnotations(boolean runtimeInvisible) throws InvalidClassFileException {
AnnotationsReader r = getAnnotationsReader(runtimeInvisible);
return Annotation.getAnnotationsFromReader(r, getClassLoader().getReference());

View File

@ -14,6 +14,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.TreeMap;
import com.ibm.wala.shrikeCT.AnnotationsReader;
import com.ibm.wala.shrikeCT.AnnotationsReader.AnnotationAttribute;
@ -121,7 +122,7 @@ public class Annotation {
sb.append(" ]");
}
if (!namedArguments.isEmpty()) {
sb.append(" " + namedArguments);
sb.append(" " + new TreeMap<String, ElementValue>(namedArguments));
}
return sb.toString();
}

View File

@ -0,0 +1,120 @@
package com.ibm.wala.dalvik.test;
import static com.ibm.wala.properties.WalaProperties.ANDROID_RT_JAR;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import com.ibm.wala.classLoader.JarFileModule;
import com.ibm.wala.classLoader.Module;
import com.ibm.wala.classLoader.NestedJarFileModule;
import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil;
import com.ibm.wala.core.tests.shrike.DynamicCallGraphTestBase;
import com.ibm.wala.dalvik.test.callGraph.DalvikCallGraphTestBase;
import com.ibm.wala.dalvik.util.AndroidAnalysisScope;
import com.ibm.wala.ipa.callgraph.AnalysisScope;
import com.ibm.wala.properties.WalaProperties;
import com.ibm.wala.util.WalaException;
import com.ibm.wala.util.io.TemporaryFile;
public abstract class DalvikTestBase extends DynamicCallGraphTestBase {
public static Properties walaProperties;
static {
try {
walaProperties = WalaProperties.loadProperties();
} catch (WalaException e) {
walaProperties = null;
}
}
public static String getJavaJar(AnalysisScope javaScope) throws IOException {
Module javaJar = javaScope.getModules(javaScope.getApplicationLoader()).iterator().next();
if (javaJar instanceof JarFileModule) {
String javaJarPath = ((JarFileModule)javaJar).getAbsolutePath();
return javaJarPath;
} else {
assert javaJar instanceof NestedJarFileModule : javaJar;
File F = File.createTempFile("android", ".jar");
//F.deleteOnExit();
System.err.println(F.getAbsolutePath());
TemporaryFile.streamToFile(F, ((NestedJarFileModule)javaJar).getNestedContents());
return F.getAbsolutePath();
}
}
public static File convertJarToDex(String jarFile) throws IOException {
File f = File.createTempFile("convert", ".dex");
//f.deleteOnExit();
System.err.println(f);
com.android.dx.command.Main.main(new String[]{"--dex", "--output=" + f.getAbsolutePath(), jarFile});
return f;
}
public static URI[] androidLibs() {
if ("Dalvik".equals(System.getProperty("java.vm.name"))) {
try {
return new URI[]{
new URL("file:///system/framework/core.jar").toURI(),
new URL("file:///system/framework/framework.jar").toURI(),
new URL("file:///system/framework/framework2.jar").toURI(),
new URL("file:///system/framework/framework3.jar").toURI()
};
} catch (MalformedURLException e) {
assert false : e;
return null;
} catch (URISyntaxException e) {
assert false : e;
return null;
}
} else {
List<URI> libs = new ArrayList<URI>();
try {
for(File lib : new File(walaProperties.getProperty(ANDROID_RT_JAR)).listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith("dex") || name.endsWith("jar");
}
})) {
libs.add(lib.toURI());
}
} catch (Exception e) {
for(String l : WalaProperties.getJ2SEJarFiles()) {
libs.add(new File(l).toURI());
}
try {
File jarFile = TemporaryFile.urlToFile("android.jar", DalvikCallGraphTestBase.class.getClassLoader().getResource("android.jar"));
libs.add(jarFile.toURI());
} catch (IOException e1) {
assert false : e1;
}
}
return libs.toArray(new URI[ libs.size() ]);
}
}
public static AnalysisScope makeDalvikScope(boolean useAndroidLib, String dexFileName) throws IOException {
AnalysisScope scope =
useAndroidLib?
AndroidAnalysisScope.setUpAndroidAnalysisScope(
new File(dexFileName).toURI(),
CallGraphTestUtil.REGRESSION_EXCLUSIONS,
CallGraphTestUtil.class.getClassLoader(),
androidLibs()):
AndroidAnalysisScope.setUpAndroidAnalysisScope(
new File(dexFileName).toURI(),
CallGraphTestUtil.REGRESSION_EXCLUSIONS,
CallGraphTestUtil.class.getClassLoader());
return scope;
}
}

View File

@ -10,32 +10,20 @@
*******************************************************************************/
package com.ibm.wala.dalvik.test.callGraph;
import static com.ibm.wala.properties.WalaProperties.ANDROID_RT_JAR;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.JarFileModule;
import com.ibm.wala.classLoader.Module;
import com.ibm.wala.classLoader.NestedJarFileModule;
import com.ibm.wala.classLoader.NewSiteReference;
import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil;
import com.ibm.wala.core.tests.shrike.DynamicCallGraphTestBase;
import com.ibm.wala.dalvik.classLoader.DexIRFactory;
import com.ibm.wala.dalvik.test.DalvikTestBase;
import com.ibm.wala.dalvik.util.AndroidAnalysisScope;
import com.ibm.wala.dalvik.util.AndroidEntryPointLocator;
import com.ibm.wala.dalvik.util.AndroidEntryPointLocator.LocatorFlags;
@ -75,17 +63,7 @@ import com.ibm.wala.util.collections.Pair;
import com.ibm.wala.util.functions.Function;
import com.ibm.wala.util.io.TemporaryFile;
public class DalvikCallGraphTestBase extends DynamicCallGraphTestBase {
public static Properties walaProperties;
static {
try {
walaProperties = WalaProperties.loadProperties();
} catch (WalaException e) {
walaProperties = null;
}
}
public class DalvikCallGraphTestBase extends DalvikTestBase {
protected static <T> Set<T> processCG(CallGraph cg, Predicate<CGNode> filter, Function<CGNode,T> map) {
Set<T> result = HashSetFactory.make();
@ -114,29 +92,6 @@ public class DalvikCallGraphTestBase extends DynamicCallGraphTestBase {
}
protected static String getJavaJar(AnalysisScope javaScope) throws IOException {
Module javaJar = javaScope.getModules(javaScope.getApplicationLoader()).iterator().next();
if (javaJar instanceof JarFileModule) {
String javaJarPath = ((JarFileModule)javaJar).getAbsolutePath();
return javaJarPath;
} else {
assert javaJar instanceof NestedJarFileModule : javaJar;
File F = File.createTempFile("android", ".jar");
//F.deleteOnExit();
System.err.println(F.getAbsolutePath());
TemporaryFile.streamToFile(F, ((NestedJarFileModule)javaJar).getNestedContents());
return F.getAbsolutePath();
}
}
public static File convertJarToDex(String jarFile) throws IOException, InterruptedException {
File f = File.createTempFile("convert", ".dex");
//f.deleteOnExit();
System.err.println(f);
com.android.dx.command.Main.main(new String[]{"--dex", "--output=" + f.getAbsolutePath(), jarFile});
return f;
}
public void dynamicCG(File javaJarPath, String mainClass, String... args) throws FileNotFoundException, IOException, ClassNotFoundException, InvalidClassFileException, FailureException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, InterruptedException {
File F = TemporaryFile.streamToFile(new File("test_jar.jar"), new FileInputStream(javaJarPath));
F.deleteOnExit();
@ -216,60 +171,8 @@ public class DalvikCallGraphTestBase extends DynamicCallGraphTestBase {
return Pair.make(callGraph, ptrAnalysis);
}
public static URI[] androidLibs() {
if ("Dalvik".equals(System.getProperty("java.vm.name"))) {
try {
return new URI[]{
new URL("file:///system/framework/core.jar").toURI(),
new URL("file:///system/framework/framework.jar").toURI(),
new URL("file:///system/framework/framework2.jar").toURI(),
new URL("file:///system/framework/framework3.jar").toURI()
};
} catch (MalformedURLException e) {
assert false : e;
return null;
} catch (URISyntaxException e) {
assert false : e;
return null;
}
} else {
List<URI> libs = new ArrayList<URI>();
try {
for(File lib : new File(walaProperties.getProperty(ANDROID_RT_JAR)).listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith("dex") || name.endsWith("jar");
}
})) {
libs.add(lib.toURI());
}
} catch (Exception e) {
for(String l : WalaProperties.getJ2SEJarFiles()) {
libs.add(new File(l).toURI());
}
try {
File jarFile = TemporaryFile.urlToFile("android.jar", DalvikCallGraphTestBase.class.getClassLoader().getResource("android.jar"));
libs.add(jarFile.toURI());
} catch (IOException e1) {
assert false : e1;
}
}
return libs.toArray(new URI[ libs.size() ]);
}
}
public static Pair<CallGraph, PointerAnalysis<InstanceKey>> makeDalvikCallGraph(boolean useAndroidLib, String mainClassName, String dexFileName) throws IOException, ClassHierarchyException, IllegalArgumentException, CancelException {
AnalysisScope scope =
useAndroidLib?
AndroidAnalysisScope.setUpAndroidAnalysisScope(
new File(dexFileName).toURI(),
CallGraphTestUtil.REGRESSION_EXCLUSIONS,
CallGraphTestUtil.class.getClassLoader(),
androidLibs()):
AndroidAnalysisScope.setUpAndroidAnalysisScope(
new File(dexFileName).toURI(),
CallGraphTestUtil.REGRESSION_EXCLUSIONS,
CallGraphTestUtil.class.getClassLoader());
AnalysisScope scope = makeDalvikScope(useAndroidLib, dexFileName);
final IClassHierarchy cha = ClassHierarchy.make(scope);

View File

@ -0,0 +1,40 @@
package com.ibm.wala.dalvik.test.ir;
import static com.ibm.wala.dalvik.test.DalvikTestBase.convertJarToDex;
import static com.ibm.wala.dalvik.test.DalvikTestBase.makeDalvikScope;
import java.io.File;
import java.io.IOException;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import com.ibm.wala.core.tests.ir.AnnotationTest;
import com.ibm.wala.core.tests.ir.JVMLAnnotationTest;
import com.ibm.wala.ipa.callgraph.AnalysisScope;
import com.ibm.wala.ipa.cha.ClassHierarchy;
import com.ibm.wala.ipa.cha.ClassHierarchyException;
import com.ibm.wala.util.io.TemporaryFile;
public class DalvikAnnotationsTest extends AnnotationTest {
public static void main(String[] args) {
justThisTest(JVMLAnnotationTest.class);
}
@BeforeClass
public static void before() throws IOException, ClassHierarchyException {
File F = File.createTempFile("waladata", ".jar");
F.deleteOnExit();
TemporaryFile.streamToFile(F, DalvikAnnotationsTest.class.getClassLoader().getResourceAsStream("com.ibm.wala.core.testdata_1.0.0a.jar"));
File androidDex = convertJarToDex(F.getAbsolutePath());
AnalysisScope dalvikScope = makeDalvikScope(true, androidDex.getAbsolutePath());
cha = ClassHierarchy.make(dalvikScope);
}
@AfterClass
public static void after() {
cha = null;
}
}

View File

@ -47,8 +47,6 @@
package com.ibm.wala.dalvik.classLoader;
import static org.jf.dexlib.ItemType.TYPE_CLASS_DEF_ITEM;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
@ -90,9 +88,7 @@ public class DexFileModule implements Module {
// create ModuleEntries from ClassDefItem
entries = new HashSet<ModuleEntry>();
@SuppressWarnings("unchecked")
Section<ClassDefItem> cldeff = dexfile.getSectionForType(TYPE_CLASS_DEF_ITEM);
Section<ClassDefItem> cldeff = dexfile.ClassDefsSection;
for (ClassDefItem cdefitems : cldeff.getItems()) {
logger.debug("DexFileModule adding class: " + cdefitems.getConciseIdentity());
entries.add(new DexModuleEntry(cdefitems));

View File

@ -54,12 +54,21 @@ import static org.jf.dexlib.Util.AccessFlags.PUBLIC;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jf.dexlib.AnnotationDirectoryItem;
import org.jf.dexlib.AnnotationItem;
import org.jf.dexlib.AnnotationSetItem;
import org.jf.dexlib.AnnotationVisibility;
import org.jf.dexlib.ClassDataItem;
import org.jf.dexlib.ClassDataItem.EncodedField;
import org.jf.dexlib.ClassDataItem.EncodedMethod;
import org.jf.dexlib.ClassDefItem;
import org.jf.dexlib.FieldIdItem;
import org.jf.dexlib.MethodIdItem;
import org.jf.dexlib.TypeIdItem;
import org.jf.dexlib.TypeListItem;
import org.slf4j.Logger;
@ -71,9 +80,12 @@ import com.ibm.wala.classLoader.IField;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.classLoader.Module;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.shrikeCT.AnnotationsReader.AnnotationType;
import com.ibm.wala.shrikeCT.InvalidClassFileException;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.types.annotations.Annotation;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.strings.ImmutableByteArray;
public class DexIClass extends BytecodeClass<IClassLoader> {
@ -258,6 +270,79 @@ public class DexIClass extends BytecodeClass<IClassLoader> {
return hashCode;
}
Collection<Annotation> getAnnotations(Set<AnnotationVisibility> types) {
Set<Annotation> result = HashSetFactory.make();
AnnotationDirectoryItem d = dexModuleEntry.getClassDefItem().getAnnotations();
if (d.getClassAnnotations() != null) {
for(AnnotationItem a : d.getClassAnnotations().getAnnotations()) {
if (types == null || types.contains(a.getVisibility())) {
result.add(DexUtil.getAnnotation(a, getClassLoader().getReference()));
}
}
}
return result;
}
public Collection<Annotation> getAnnotations() {
return getAnnotations((Set<AnnotationVisibility>)null);
}
public Collection<Annotation> getAnnotations(boolean runtimeInvisible) throws InvalidClassFileException {
return getAnnotations(getTypes(runtimeInvisible));
}
static Set<AnnotationVisibility> getTypes(boolean runtimeInvisible) {
Set<AnnotationVisibility> types = HashSetFactory.make();
types.add(AnnotationVisibility.SYSTEM);
if (runtimeInvisible) {
types.add(AnnotationVisibility.BUILD);
} else {
types.add(AnnotationVisibility.RUNTIME);
}
return types;
}
List<AnnotationItem> getAnnotations(MethodIdItem m, Set<AnnotationVisibility> types) {
List<AnnotationItem> result = new ArrayList<AnnotationItem>();
AnnotationDirectoryItem d = dexModuleEntry.getClassDefItem().getAnnotations();
if (d != null) {
for(AnnotationItem a : d.getMethodAnnotations(m).getAnnotations()) {
if (types == null || types.contains(a.getVisibility())) {
result.add(a);
}
}
}
return result;
}
List<AnnotationItem> getAnnotations(FieldIdItem m) {
List<AnnotationItem> result = new ArrayList<AnnotationItem>();
AnnotationDirectoryItem d = dexModuleEntry.getClassDefItem().getAnnotations();
if (d != null) {
for(AnnotationItem a : d.getFieldAnnotations(m).getAnnotations()) {
result.add(a);
}
}
return result;
}
Map<Integer,List<AnnotationItem>> getParameterAnnotations(MethodIdItem m) {
Map<Integer,List<AnnotationItem>> result = HashMapFactory.make();
AnnotationDirectoryItem d = dexModuleEntry.getClassDefItem().getAnnotations();
if (d != null) {
int i = 0;
for(AnnotationSetItem as : d.getParameterAnnotations(m).getAnnotationSets()) {
for(AnnotationItem a : as.getAnnotations()) {
if (! result.containsKey(i)) {
result.put(i, new ArrayList<AnnotationItem>());
}
result.get(i).add(a);
}
i++;
}
}
return result;
}
/*
* (non-Javadoc)
@ -339,11 +424,6 @@ public class DexIClass extends BytecodeClass<IClassLoader> {
return clinitId!=-1?methods[clinitId]:null;
}
@Override
public Collection<Annotation> getAnnotations() {
throw new UnsupportedOperationException();
}
@Override
public Module getContainer() {
return dexModuleEntry.asModule();

View File

@ -58,6 +58,8 @@ import static org.jf.dexlib.Util.AccessFlags.VOLATILE;
import java.util.Collection;
import org.jf.dexlib.ClassDataItem.EncodedField;
import org.jf.dexlib.StringIdItem;
import org.jf.dexlib.TypeIdItem;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IField;
@ -67,7 +69,6 @@ import com.ibm.wala.types.TypeName;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.types.annotations.Annotation;
import com.ibm.wala.util.strings.Atom;
import com.ibm.wala.util.strings.ImmutableByteArray;
public class DexIField implements IField {
@ -100,20 +101,16 @@ public class DexIField implements IField {
//public DexIField(EncodedField encodedField) {
eField = encodedField;
myClass = klass;
name = Atom.findOrCreateUnicodeAtom(eField.field.getFieldName().getStringValue());
StringIdItem fieldName = eField.field.getFieldName();
name = Atom.findOrCreateUnicodeAtom(fieldName.getStringValue());
ImmutableByteArray fieldType = ImmutableByteArray.make(eField.field.getFieldType().getTypeDescriptor());
TypeName T = null;
if (fieldType.get(fieldType.length() - 1) == ';') {
T = TypeName.findOrCreate(fieldType, 0, fieldType.length() - 1);
} else {
T = TypeName.findOrCreate(fieldType);
}
TypeIdItem fieldType = eField.field.getFieldType();
TypeName T = DexUtil.getTypeName(fieldType);
TypeReference type = TypeReference.findOrCreate(myClass.getClassLoader().getReference(), T);
myFieldRef = FieldReference.findOrCreate(myClass.getReference(), name, type);
}
public TypeReference getFieldTypeReference() {
public TypeReference getFieldTypeReference() {
//compute the typeReference from the EncodedField
// if (typeReference == null) {
@ -176,7 +173,7 @@ public class DexIField implements IField {
@Override
public Collection<Annotation> getAnnotations() {
throw new UnsupportedOperationException();
return DexUtil.getAnnotations(myClass.getAnnotations(eField.field), myClass.getClassLoader().getReference());
}
}

View File

@ -61,6 +61,9 @@ import static org.jf.dexlib.Util.AccessFlags.VOLATILE;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jf.dexlib.AnnotationItem;
import org.jf.dexlib.AnnotationSetItem;
@ -191,9 +194,6 @@ public class DexIMethod implements IBytecodeMethod {
public DexIMethod(EncodedMethod encodedMethod, DexIClass klass) {
eMethod = encodedMethod;
myClass = klass;
//XXX TEST
//myClass.iterateMethodAnnotations(this);
}
public static int getTotalInsts() {
@ -3357,7 +3357,24 @@ public class DexIMethod implements IBytecodeMethod {
@Override
public Collection<Annotation> getAnnotations() {
throw new UnsupportedOperationException();
return DexUtil.getAnnotations(myClass.getAnnotations(eMethod.method, null), myClass.getClassLoader().getReference());
}
@Override
public Collection<Annotation> getAnnotations(boolean runtimeInvisible) {
return DexUtil.getAnnotations(myClass.getAnnotations(eMethod.method, DexIClass.getTypes(runtimeInvisible)), myClass.getClassLoader().getReference());
}
@Override
public Collection<Annotation>[] getParameterAnnotations() {
Map<Integer, List<AnnotationItem>> raw = myClass.getParameterAnnotations(eMethod.method);
@SuppressWarnings("unchecked")
Collection<Annotation>[] result = new Collection[ getReference().getNumberOfParameters() ];
for(Map.Entry<Integer, List<AnnotationItem>> x : raw.entrySet()) {
result[x.getKey()] = DexUtil.getAnnotations(x.getValue(), myClass.getClassLoader().getReference());
}
return result;
}
}

View File

@ -0,0 +1,169 @@
package com.ibm.wala.dalvik.classLoader;
import java.util.Collection;
import java.util.Map;
import org.jf.dexlib.AnnotationItem;
import org.jf.dexlib.FieldIdItem;
import org.jf.dexlib.MethodIdItem;
import org.jf.dexlib.TypeIdItem;
import org.jf.dexlib.EncodedValue.AnnotationEncodedSubValue;
import org.jf.dexlib.EncodedValue.ArrayEncodedValue;
import org.jf.dexlib.EncodedValue.BooleanEncodedValue;
import org.jf.dexlib.EncodedValue.ByteEncodedValue;
import org.jf.dexlib.EncodedValue.CharEncodedValue;
import org.jf.dexlib.EncodedValue.DoubleEncodedValue;
import org.jf.dexlib.EncodedValue.EncodedValue;
import org.jf.dexlib.EncodedValue.EnumEncodedValue;
import org.jf.dexlib.EncodedValue.FieldEncodedValue;
import org.jf.dexlib.EncodedValue.FloatEncodedValue;
import org.jf.dexlib.EncodedValue.IntEncodedValue;
import org.jf.dexlib.EncodedValue.LongEncodedValue;
import org.jf.dexlib.EncodedValue.MethodEncodedValue;
import org.jf.dexlib.EncodedValue.ShortEncodedValue;
import org.jf.dexlib.EncodedValue.StringEncodedValue;
import org.jf.dexlib.EncodedValue.TypeEncodedValue;
import org.jf.dexlib.EncodedValue.ValueType;
import com.ibm.wala.shrikeCT.AnnotationsReader.AnnotationAttribute;
import com.ibm.wala.shrikeCT.AnnotationsReader.ArrayElementValue;
import com.ibm.wala.shrikeCT.AnnotationsReader.ConstantElementValue;
import com.ibm.wala.shrikeCT.AnnotationsReader.ElementValue;
import com.ibm.wala.shrikeCT.AnnotationsReader.EnumElementValue;
import com.ibm.wala.types.ClassLoaderReference;
import com.ibm.wala.types.Descriptor;
import com.ibm.wala.types.FieldReference;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.TypeName;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.types.annotations.Annotation;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.strings.Atom;
import com.ibm.wala.util.strings.ImmutableByteArray;
public class DexUtil {
static Collection<Annotation> getAnnotations(Collection<AnnotationItem> as, ClassLoaderReference clr) {
Collection<Annotation> result = HashSetFactory.make();
for(AnnotationItem a : as) {
result.add(getAnnotation(a, clr));
}
return result;
}
static Annotation getAnnotation(AnnotationItem a, ClassLoaderReference clr) {
return getAnnotation(a.getEncodedAnnotation(), clr);
}
static Annotation getAnnotation(AnnotationEncodedSubValue ea, ClassLoaderReference clr) {
Map<String,ElementValue> values = HashMapFactory.make();
TypeReference at = getTypeRef(ea.annotationType, clr);
for(int i = 0; i < ea.names.length; i++) {
String name = ea.names[i].getStringValue();
EncodedValue v = ea.values[i];
ElementValue value = getValue(clr, v);
values.put(name, value);
}
return Annotation.makeWithNamed(at, values);
}
static ElementValue getValue(ClassLoaderReference clr, EncodedValue v) {
switch (v.getValueType()) {
case VALUE_ANNOTATION:
Annotation a = getAnnotation((AnnotationEncodedSubValue)v, clr);
return new AnnotationAttribute(a.getType().getName().toString() +";", a.getNamedArguments());
case VALUE_ARRAY:
EncodedValue[] vs = ((ArrayEncodedValue)v).values;
ElementValue rs[] = new ElementValue[ vs.length ];
for(int idx = 0; idx < vs.length; idx++) {
rs[idx] = getValue(clr, vs[idx]);
}
return new ArrayElementValue(rs);
case VALUE_BOOLEAN:
Boolean bl = ((BooleanEncodedValue)v).value;
return new ConstantElementValue(bl);
case VALUE_BYTE:
Byte bt = ((ByteEncodedValue)v).value;
return new ConstantElementValue(bt);
case VALUE_CHAR:
Character c = ((CharEncodedValue)v).value;
return new ConstantElementValue(c);
case VALUE_DOUBLE:
Double d = ((DoubleEncodedValue)v).value;
return new ConstantElementValue(d);
case VALUE_ENUM:
FieldIdItem o = ((EnumEncodedValue)v).value;
return new EnumElementValue(o.getFieldType().getTypeDescriptor(), o.getFieldName().getStringValue());
case VALUE_FIELD:
o = v.getValueType()==ValueType.VALUE_ENUM? ((EnumEncodedValue)v).value: ((FieldEncodedValue)v).value;
String fieldName = o.getFieldName().getStringValue();
TypeReference ft = getTypeRef(o.getFieldType(), clr);
TypeReference ct = getTypeRef(o.getContainingClass(), clr);
return new ConstantElementValue(FieldReference.findOrCreate(ct, Atom.findOrCreateUnicodeAtom(fieldName), ft));
case VALUE_FLOAT:
Float f = ((FloatEncodedValue)v).value;
return new ConstantElementValue(f);
case VALUE_INT:
Integer iv = ((IntEncodedValue)v).value;
return new ConstantElementValue(iv);
case VALUE_LONG:
Long l = ((LongEncodedValue)v).value;
return new ConstantElementValue(l);
case VALUE_METHOD:
MethodIdItem m = ((MethodEncodedValue)v).value;
ct = getTypeRef(m.getContainingClass(), clr);
String methodName = m.getMethodName().getStringValue();
String methodSig = m.getPrototype().getPrototypeString();
return new ConstantElementValue(MethodReference.findOrCreate(ct, Atom.findOrCreateUnicodeAtom(methodName), Descriptor.findOrCreateUTF8(methodSig)));
case VALUE_NULL:
return new ConstantElementValue(null);
case VALUE_SHORT:
Short s = ((ShortEncodedValue)v).value;
return new ConstantElementValue(s);
case VALUE_STRING:
String str = ((StringEncodedValue)v).value.getStringValue();
return new ConstantElementValue(str);
case VALUE_TYPE:
TypeIdItem t = ((TypeEncodedValue)v).value;
return new ConstantElementValue(getTypeName(t) + ";");
default:
assert false : v;
return null;
}
}
static TypeReference getTypeRef(TypeIdItem type, ClassLoaderReference clr) {
return TypeReference.findOrCreate(clr, getTypeName(type));
}
static TypeName getTypeName(TypeIdItem fieldType) {
ImmutableByteArray fieldTypeArray = ImmutableByteArray.make(fieldType.getTypeDescriptor());
TypeName T = null;
if (fieldTypeArray.get(fieldTypeArray.length() - 1) == ';') {
T = TypeName.findOrCreate(fieldTypeArray, 0, fieldTypeArray.length() - 1);
} else {
T = TypeName.findOrCreate(fieldTypeArray);
}
return T;
}
}