Add DexBacked implementation of Method

This commit is contained in:
Ben Gruver 2012-10-18 21:58:58 -07:00
parent f3e03c0a94
commit 63d8406703
5 changed files with 346 additions and 8 deletions

View File

@ -54,6 +54,14 @@ public class DexFileReader {
return 0; return 0;
} }
public int getMethodIdItemOffset(int methodIndex) {
return 0;
}
public int getProtoIdItemOffset(int methodIndex) {
return 0;
}
public String getType(int typeIndex) { public String getType(int typeIndex) {
return null; return null;
} }

View File

@ -163,6 +163,52 @@ public class DexBackedClassDef implements ClassDef {
@Nonnull @Nonnull
@Override @Override
public List<? extends Method> getMethods() { public List<? extends Method> getMethods() {
return null; if (classDataOffset > 0) {
DexFileReader reader = dexFile.readerAt(classDataOffset);
int staticFieldCount = reader.readSmallUleb128();
int instanceFieldCount = reader.readSmallUleb128();
int directMethodCount = reader.readSmallUleb128();
int virtualMethodCount = reader.readSmallUleb128();
final int methodCount = directMethodCount + virtualMethodCount;
if (methodCount > 0) {
DexBackedField.skipAllFields(reader, staticFieldCount + instanceFieldCount);
final int methodsStartOffset = reader.getOffset();
return new VariableSizeListWithContext<DexBackedMethod>() {
@Nonnull
@Override
public Iterator listIterator() {
return new Iterator(dexFile, methodsStartOffset) {
private int previousMethodIndex = 0;
@Nonnull private final AnnotationsDirectory.AnnotationIterator methodAnnotationIterator =
annotationsDirectory.getMethodAnnotationIterator();
@Nonnull private final AnnotationsDirectory.AnnotationIterator parameterAnnotationIterator =
annotationsDirectory.getParameterAnnotationIterator();
@Nonnull private final StaticInitialValueIterator staticInitialValueIterator =
StaticInitialValueIterator.newOrEmpty(dexFile, staticInitialValuesOffset);
@Nonnull
@Override
protected DexBackedMethod readItem(DexFileReader reader, int index) {
DexBackedMethod item = new DexBackedMethod(reader, previousMethodIndex,
methodAnnotationIterator, parameterAnnotationIterator);
previousMethodIndex = item.methodIndex;
return item;
}
@Override
protected void skipItem(DexFileReader reader, int index) {
previousMethodIndex = DexBackedMethod.skipEncodedMethod(reader, previousMethodIndex);
staticInitialValueIterator.skipNext();
}
};
}
@Override public int size() { return methodCount; }
};
}
}
return ImmutableList.of();
} }
} }

View File

@ -0,0 +1,163 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "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 COPYRIGHT
* OWNER OR CONTRIBUTORS 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.dexlib2.dexbacked;
import com.google.common.collect.ImmutableList;
import org.jf.dexlib2.DexFile;
import org.jf.dexlib2.DexFileReader;
import org.jf.dexlib2.dexbacked.util.AnnotationsDirectory;
import org.jf.dexlib2.dexbacked.util.FixedSizeList;
import org.jf.dexlib2.iface.Annotation;
import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.MethodImplementation;
import org.jf.dexlib2.iface.MethodParameter;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
public class DexBackedMethod implements Method {
@Nonnull public final DexFile dexFile;
@Nonnull public final String name;
public final int accessFlags;
@Nonnull public final String returnType;
private final int codeOffset;
private final int parametersOffset;
private final int methodAnnotationSetOffset;
private final List<List<? extends DexBackedAnnotation>> parameterAnnotations;
public final int methodIndex;
// method_id_item offsets
private static final int PROTO_OFFSET = 2;
private static final int NAME_OFFSET = 4;
// proto_id_item offsets
private static final int RETURN_TYPE_OFFSET = 4;
private static final int PARAMETERS_OFFSET = 8;
public DexBackedMethod(@Nonnull DexFileReader dexFileReader,
int previousMethodIndex,
@Nonnull AnnotationsDirectory.AnnotationIterator methodAnnotationIterator,
@Nonnull AnnotationsDirectory.AnnotationIterator paramaterAnnotationIterator) {
this.dexFile = dexFileReader.getDexFile();
int methodIndexDiff = dexFileReader.readSmallUleb128();
this.methodIndex = methodIndexDiff + previousMethodIndex;
this.accessFlags = dexFileReader.readSmallUleb128();
this.codeOffset = dexFileReader.readSmallUleb128();
this.methodAnnotationSetOffset = methodAnnotationIterator.seekTo(methodIndex);
int parameterAnnotationSetListOffset = paramaterAnnotationIterator.seekTo(methodIndex);
this.parameterAnnotations =
AnnotationsDirectory.getParameterAnnotations(dexFile, parameterAnnotationSetListOffset);
int methodIdItemOffset = dexFileReader.getMethodIdItemOffset(methodIndex);
int protoIndex = dexFileReader.readUshort(methodIdItemOffset + PROTO_OFFSET);
int protoIdItemOffset = dexFileReader.getProtoIdItemOffset(protoIndex);
this.name = dexFileReader.getString(dexFileReader.readSmallUint(methodIdItemOffset + NAME_OFFSET));
this.returnType = dexFileReader.getString(dexFileReader.readSmallUint(protoIdItemOffset + RETURN_TYPE_OFFSET));
this.parametersOffset = dexFileReader.readSmallUint(protoIdItemOffset + PARAMETERS_OFFSET);
}
@Nonnull @Override public String getName() { return name; }
@Override public int getAccessFlags() { return accessFlags; }
@Nonnull @Override public String getReturnType() { return returnType; }
@Nonnull
@Override
public List<? extends MethodParameter> getParameters() {
if (parametersOffset > 0) {
final int size = dexFile.readSmallUint(parametersOffset);
return new FixedSizeList<MethodParameter>() {
@Override
public MethodParameter readItem(final int index) {
return new MethodParameter() {
@Nonnull
@Override
public String getType() {
int typeIndex = dexFile.readUshort(parametersOffset + 4 + (index * 2));
return dexFile.getType(typeIndex);
}
@Nonnull
@Override
public List<? extends Annotation> getAnnotations() {
if (index < parameterAnnotations.size()) {
return parameterAnnotations.get(index);
}
return ImmutableList.of();
}
};
}
@Override public int size() { return size; }
};
}
return ImmutableList.of();
}
@Nonnull
@Override
public List<? extends Annotation> getAnnotations() {
return AnnotationsDirectory.getAnnotations(dexFile, methodAnnotationSetOffset);
}
@Nullable
@Override
public MethodImplementation getImplementation() {
if (codeOffset > 0) {
return new DexBackedMethodImplementation(dexFile, codeOffset);
}
return null;
}
/**
* Skips the reader over a single encoded_method structure.
* @param dexFileReader The {@code DexFileReader} to skip
* @param previousMethodIndex The method index of the previous field, or 0 if this is the first
* @return The method index of the field that was skipped
*/
public static int skipEncodedMethod(@Nonnull DexFileReader dexFileReader, int previousMethodIndex) {
int idxDiff = dexFileReader.readSmallUleb128();
dexFileReader.skipUleb128();
dexFileReader.skipUleb128();
return previousMethodIndex + idxDiff;
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "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 COPYRIGHT
* OWNER OR CONTRIBUTORS 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.dexlib2.dexbacked;
import org.jf.dexlib2.DexFile;
import org.jf.dexlib2.iface.MethodImplementation;
import org.jf.dexlib2.iface.TryBlock;
import org.jf.dexlib2.iface.instruction.Instruction;
import javax.annotation.Nonnull;
import java.util.List;
public class DexBackedMethodImplementation implements MethodImplementation {
@Nonnull public final DexFile dexFile;
public DexBackedMethodImplementation(@Nonnull DexFile dexFile,
int codeOffset) {
this.dexFile = dexFile;
}
@Override
public int getRegisterCount() {
return 0;
}
@Nonnull
@Override
public List<? extends Instruction> getInstructions() {
return null;
}
@Nonnull
@Override
public List<? extends TryBlock> getTryBlocks() {
return null;
}
}

View File

@ -43,11 +43,15 @@ public abstract class AnnotationsDirectory {
@Override public int getFieldAnnotationCount() { return 0; } @Override public int getFieldAnnotationCount() { return 0; }
@Nonnull @Override public List<? extends DexBackedAnnotation> getClassAnnotations() {return ImmutableList.of();} @Nonnull @Override public List<? extends DexBackedAnnotation> getClassAnnotations() {return ImmutableList.of();}
@Nonnull @Override public AnnotationIterator getFieldAnnotationIterator() { return AnnotationIterator.EMPTY; } @Nonnull @Override public AnnotationIterator getFieldAnnotationIterator() { return AnnotationIterator.EMPTY; }
@Nonnull @Override public AnnotationIterator getMethodAnnotationIterator() { return AnnotationIterator.EMPTY; }
@Nonnull @Override public AnnotationIterator getParameterAnnotationIterator() {return AnnotationIterator.EMPTY;}
}; };
public abstract int getFieldAnnotationCount(); public abstract int getFieldAnnotationCount();
@Nonnull public abstract List<? extends DexBackedAnnotation> getClassAnnotations(); @Nonnull public abstract List<? extends DexBackedAnnotation> getClassAnnotations();
@Nonnull public abstract AnnotationIterator getFieldAnnotationIterator(); @Nonnull public abstract AnnotationIterator getFieldAnnotationIterator();
@Nonnull public abstract AnnotationIterator getMethodAnnotationIterator();
@Nonnull public abstract AnnotationIterator getParameterAnnotationIterator();
public static AnnotationsDirectory newOrEmpty(@Nonnull DexFile dexFile, public static AnnotationsDirectory newOrEmpty(@Nonnull DexFile dexFile,
int directoryAnnotationsOffset) { int directoryAnnotationsOffset) {
@ -85,14 +89,38 @@ public abstract class AnnotationsDirectory {
return ImmutableList.of(); return ImmutableList.of();
} }
public static List<List<? extends DexBackedAnnotation>> getParameterAnnotations(@Nonnull final DexFile dexFile,
final int annotationSetListOffset) {
if (annotationSetListOffset > 0) {
final int size = dexFile.readSmallUint(annotationSetListOffset);
return new FixedSizeList<List<? extends DexBackedAnnotation>>() {
@Override
public List<? extends DexBackedAnnotation> readItem(int index) {
int annotationSetOffset = dexFile.readSmallUint(annotationSetListOffset + 4 + index * 4);
return getAnnotations(dexFile, annotationSetOffset);
}
@Override public int size() { return size; }
};
}
return ImmutableList.of();
}
private static class AnnotationsDirectoryImpl extends AnnotationsDirectory { private static class AnnotationsDirectoryImpl extends AnnotationsDirectory {
@Nonnull public final DexFile dexFile; @Nonnull public final DexFile dexFile;
private final int directoryOffset; private final int directoryOffset;
private static final int FIELD_COUNT_OFFSET = 4; private static final int FIELD_COUNT_OFFSET = 4;
private static final int METHOD_COUNT_OFFSET = 8;
private static final int PARAMETER_COUNT_OFFSET = 12;
private static final int ANNOTATIONS_START_OFFSET = 16; private static final int ANNOTATIONS_START_OFFSET = 16;
/** The size of a field_annotation structure */
private static final int FIELD_ANNOTATION_SIZE = 8;
/** The size of a method_annotation structure */
private static final int METHOD_ANNOTATION_SIZE = 8;
public AnnotationsDirectoryImpl(@Nonnull DexFile dexFile, public AnnotationsDirectoryImpl(@Nonnull DexFile dexFile,
int directoryOffset) { int directoryOffset) {
this.dexFile = dexFile; this.dexFile = dexFile;
@ -103,6 +131,14 @@ public abstract class AnnotationsDirectory {
return dexFile.readSmallUint(directoryOffset + FIELD_COUNT_OFFSET); return dexFile.readSmallUint(directoryOffset + FIELD_COUNT_OFFSET);
} }
public int getMethodAnnotationCount() {
return dexFile.readSmallUint(directoryOffset + METHOD_COUNT_OFFSET);
}
public int getParameterAnnotationCount() {
return dexFile.readSmallUint(directoryOffset + PARAMETER_COUNT_OFFSET);
}
@Nonnull @Nonnull
public List<? extends DexBackedAnnotation> getClassAnnotations() { public List<? extends DexBackedAnnotation> getClassAnnotations() {
return getAnnotations(dexFile, dexFile.readSmallUint(directoryOffset)); return getAnnotations(dexFile, dexFile.readSmallUint(directoryOffset));
@ -113,31 +149,49 @@ public abstract class AnnotationsDirectory {
return new AnnotationIteratorImpl(directoryOffset + ANNOTATIONS_START_OFFSET, getFieldAnnotationCount()); return new AnnotationIteratorImpl(directoryOffset + ANNOTATIONS_START_OFFSET, getFieldAnnotationCount());
} }
@Nonnull
public AnnotationIterator getMethodAnnotationIterator() {
int fieldCount = getFieldAnnotationCount();
int methodAnnotationsOffset = directoryOffset + ANNOTATIONS_START_OFFSET +
fieldCount * FIELD_ANNOTATION_SIZE;
return new AnnotationIteratorImpl(methodAnnotationsOffset, getMethodAnnotationCount());
}
@Nonnull
public AnnotationIterator getParameterAnnotationIterator() {
int fieldCount = getFieldAnnotationCount();
int methodCount = getMethodAnnotationCount();
int parameterAnnotationsOffset = directoryOffset + ANNOTATIONS_START_OFFSET +
fieldCount * FIELD_ANNOTATION_SIZE +
methodCount + METHOD_ANNOTATION_SIZE;
return new AnnotationIteratorImpl(parameterAnnotationsOffset, getParameterAnnotationCount());
}
private class AnnotationIteratorImpl implements AnnotationIterator { private class AnnotationIteratorImpl implements AnnotationIterator {
private final int startOffset; private final int startOffset;
private final int size; private final int size;
private int currentIndex; private int currentIndex;
private int currentFieldIndex; private int currentItemIndex;
public AnnotationIteratorImpl(int startOffset, int size) { public AnnotationIteratorImpl(int startOffset, int size) {
this.startOffset = startOffset; this.startOffset = startOffset;
this.size = size; this.size = size;
if (size > 0) { if (size > 0) {
currentFieldIndex = dexFile.readSmallUint(startOffset); currentItemIndex = dexFile.readSmallUint(startOffset);
this.currentIndex = 0; this.currentIndex = 0;
} else { } else {
currentFieldIndex = -1; currentItemIndex = -1;
this.currentIndex = -1; this.currentIndex = -1;
} }
} }
public int seekTo(int fieldIndex) { public int seekTo(int itemIndex) {
while (currentFieldIndex < fieldIndex && (currentIndex+1) < size) { while (currentItemIndex < itemIndex && (currentIndex+1) < size) {
currentIndex++; currentIndex++;
currentFieldIndex = dexFile.readSmallUint(startOffset + (currentIndex*8)); currentItemIndex = dexFile.readSmallUint(startOffset + (currentIndex*8));
} }
if (currentFieldIndex == fieldIndex) { if (currentItemIndex == itemIndex) {
return dexFile.readSmallUint(startOffset + (currentIndex*8)+4); return dexFile.readSmallUint(startOffset + (currentIndex*8)+4);
} }
return 0; return 0;