Add support to dexlib2 for parameter names

This commit is contained in:
Ben Gruver 2012-10-27 14:52:34 -07:00
parent 005690e855
commit bfe20a295d
6 changed files with 91 additions and 26 deletions

View File

@ -36,7 +36,6 @@ 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;
@ -99,6 +98,18 @@ public class DexBackedMethod implements Method {
@Nonnull
@Override
public List<? extends MethodParameter> getParameters() {
if (parametersOffset > 0) {
DexBackedMethodImplementation methodImpl = getImplementation();
if (methodImpl != null) {
return methodImpl.getParametersWithNames();
}
return getParametersWithoutNames();
}
return ImmutableList.of();
}
@Nonnull
public List<? extends MethodParameter> getParametersWithoutNames() {
if (parametersOffset > 0) {
final int size = dexBuf.readSmallUint(parametersOffset);
@ -122,6 +133,10 @@ public class DexBackedMethod implements Method {
}
return ImmutableList.of();
}
@Nullable @Override public String getName() { return null; }
//TODO: iterate over the annotations to get the signature
@Nullable @Override public String getSignature() { return null; }
};
}
@ -140,7 +155,7 @@ public class DexBackedMethod implements Method {
@Nullable
@Override
public MethodImplementation getImplementation() {
public DexBackedMethodImplementation getImplementation() {
if (codeOffset > 0) {
return new DexBackedMethodImplementation(dexBuf, this, codeOffset);
}

View File

@ -35,17 +35,20 @@ import com.google.common.collect.ImmutableList;
import org.jf.dexlib2.dexbacked.instruction.DexBackedInstruction;
import org.jf.dexlib2.dexbacked.util.DebugItemList;
import org.jf.dexlib2.dexbacked.util.FixedSizeList;
import org.jf.dexlib2.dexbacked.util.VariableSizeList;
import org.jf.dexlib2.iface.Annotation;
import org.jf.dexlib2.iface.MethodImplementation;
import org.jf.dexlib2.iface.MethodParameter;
import org.jf.dexlib2.iface.TryBlock;
import org.jf.dexlib2.iface.debug.DebugItem;
import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.util.AlignmentUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
//TODO: consider making this extends DexBackedMethod, rather than passing in the associated DexBackedMethod
public class DexBackedMethodImplementation implements MethodImplementation {
@Nonnull public final DexBuffer dexBuf;
@Nonnull public final DexBackedMethod method;
@ -131,4 +134,40 @@ public class DexBackedMethodImplementation implements MethodImplementation {
return ImmutableList.copyOf(instructions);
}
public List<MethodParameter> getParametersWithNames() {
final int debugInfoOffset = dexBuf.readSmallUint(codeOffset + DEBUG_OFFSET_OFFSET);
if (debugInfoOffset > 0) {
DexReader reader = dexBuf.readerAt(debugInfoOffset);
reader.skipUleb128();
final int parameterNameCount = reader.readSmallUleb128();
final List<? extends MethodParameter> methodParametersWithoutNames = method.getParametersWithoutNames();
//TODO: make sure dalvik doesn't allow more parameter names than we have parameters
return new VariableSizeList<MethodParameter>(dexBuf, reader.getOffset()) {
@Nonnull
@Override
protected MethodParameter readItem(@Nonnull DexReader reader, int index) {
final MethodParameter methodParameter = methodParametersWithoutNames.get(index);
String _name = null;
if (index < parameterNameCount) {
_name = reader.getOptionalString(reader.readSmallUleb128() - 1);
}
final String name = _name;
return new MethodParameter() {
@Nonnull @Override public String getType() { return methodParameter.getType(); }
@Nullable @Override public String getName() { return name; }
@Nullable @Override public String getSignature() { return methodParameter.getSignature();}
@Nonnull @Override public List<? extends Annotation> getAnnotations() {
return methodParameter.getAnnotations();
}
};
}
@Override public int size() { return methodParametersWithoutNames.size(); }
};
}
return ImmutableList.of();
}
}

View File

@ -46,7 +46,6 @@ import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.List;
import java.util.NoSuchElementException;
public class DebugItemList extends VariableSizeListWithContext<DebugItem> {
@ -86,24 +85,17 @@ public class DebugItemList extends VariableSizeListWithContext<DebugItem> {
final LocalInfo[] locals = new LocalInfo[registerCount];
Arrays.fill(locals, EMPTY_LOCAL_INFO);
List<? extends MethodParameter> parameters = method.getParameters();
// getParameters returns a VariableSizeList when a method implementation is present. Since we're reading debug
// information, the method obviously has an implementation.
VariableSizeList<? extends MethodParameter> parameters =
(VariableSizeList<? extends MethodParameter>)method.getParameters();
VariableSizeList<? extends MethodParameter>.Iterator parameterIterator = parameters.listIterator();
//TODO: need to add parameter info to MethodParameter. Is there some way we could use the same reader for that?
int debugParametersSize = initialReader.readSmallUleb128();
if (debugParametersSize > parameters.size()) {
//TODO: make sure that dalvik doesn't allow this
throw new ExceptionWithContext("DebugInfoItem has more parameters than the method itself does. WTF?");
}
for (int i=0; i<parameters.size(); i++) {
// TODO: look for a signature annotation on the... method? parameter?, and get the parameter signature
final MethodParameter methodParameter = parameters.get(i);
final String parameterName = dexBuf.getOptionalString(initialReader.readSmallUleb128() - 1);
locals[i] = new LocalInfo() {
@Nullable @Override public String getName() { return parameterName; }
@Nullable @Override public String getType() { return methodParameter.getType(); }
@Nullable @Override public String getSignature() { return null; }
};
{ // local scope for i
int i=0;
while (parameterIterator.hasNext()) {
locals[i++] = parameterIterator.next();
}
}
if (parameters.size() < registerCount) {
@ -121,7 +113,7 @@ public class DebugItemList extends VariableSizeListWithContext<DebugItem> {
}
}
return new Iterator(dexBuf, initialReader.getOffset()) {
return new Iterator(dexBuf, parameterIterator.getReaderOffset()) {
private boolean finished = false;
private int codeAddress = 0;
private int lineNumber = lineNumberStart;

View File

@ -102,5 +102,9 @@ public abstract class VariableSizeList<T> extends AbstractSequentialList<T> {
checkBounds(index);
skipItem(reader, index++);
}
public int getReaderOffset() {
return reader.getOffset();
}
}
}

View File

@ -31,10 +31,15 @@
package org.jf.dexlib2.iface;
import org.jf.dexlib2.iface.debug.LocalInfo;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
public interface MethodParameter {
public interface MethodParameter extends LocalInfo {
@Nonnull String getType();
@Nonnull List<? extends Annotation> getAnnotations();
@Nullable String getName();
@Nullable String getSignature();
}

View File

@ -44,17 +44,22 @@ import java.util.List;
public class ImmutableMethodParameter implements MethodParameter {
@Nonnull public final String type;
@Nonnull public final ImmutableList<? extends ImmutableAnnotation> annotations;
@Nullable public final String name;
public ImmutableMethodParameter(@Nonnull String type,
@Nullable List<? extends Annotation> annotations) {
@Nullable List<? extends Annotation> annotations,
@Nullable String name) {
this.type = type;
this.annotations = ImmutableAnnotation.immutableListOf(annotations);
this.name = name;
}
public ImmutableMethodParameter(@Nonnull String type,
@Nullable ImmutableList<? extends ImmutableAnnotation> annotations) {
@Nullable ImmutableList<? extends ImmutableAnnotation> annotations,
@Nullable String name) {
this.type = type;
this.annotations = Objects.firstNonNull(annotations, ImmutableList.<ImmutableAnnotation>of());
this.name = name;
}
public static ImmutableMethodParameter of(MethodParameter methodParameter) {
@ -63,11 +68,16 @@ public class ImmutableMethodParameter implements MethodParameter {
}
return new ImmutableMethodParameter(
methodParameter.getType(),
methodParameter.getAnnotations());
methodParameter.getAnnotations(),
methodParameter.getName());
}
@Nonnull @Override public String getType() { return type; }
@Nonnull @Override public List<? extends Annotation> getAnnotations() { return annotations; }
@Nullable @Override public String getName() { return name; }
//TODO: iterate over the annotations to get the signature
@Nullable @Override public String getSignature() { return null; }
@Nonnull
public static ImmutableList<ImmutableMethodParameter> immutableListOf(List<? extends MethodParameter> list) {