Mercurial > hg > icedrobot > daneel
changeset 80:817b7941153f
Fixed debug information for method parameters.
* dex/ClassData.java: Pass method identifier to code parser.
* dex/Code.java: Take method identifier as argument.
* dex/DebugInfo.java (interpret): Also emit locals for method parameters.
* util/TypeUtil.java (isWideType): New utility method.
author | Michael Starzinger <michi@complang.tuwien.ac.at> |
---|---|
date | Fri, 25 Mar 2011 23:59:09 +0100 |
parents | 68531618d334 |
children | 96c63feb973c |
files | src/main/java/org/icedrobot/daneel/dex/ClassData.java src/main/java/org/icedrobot/daneel/dex/Code.java src/main/java/org/icedrobot/daneel/dex/DebugInfo.java src/main/java/org/icedrobot/daneel/util/TypeUtil.java |
diffstat | 4 files changed, 98 insertions(+), 48 deletions(-) [+] |
line wrap: on
line diff
--- a/src/main/java/org/icedrobot/daneel/dex/ClassData.java Fri Mar 25 16:08:30 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/ClassData.java Fri Mar 25 23:59:09 2011 +0100 @@ -123,12 +123,13 @@ int directMethodsIdx = 0; for (int i = 0; i < directMethodsSize; i++) { directMethodsIdx += BufferUtil.getULEB128(buffer); - directMethodsIds[i] = dex.getMethodId(directMethodsIdx); + MethodId method = dex.getMethodId(directMethodsIdx); + directMethodsIds[i] = method; directMethodsFlags[i] = BufferUtil.getULEB128(buffer); int codeOff = BufferUtil.getULEB128(buffer); if (codeOff != 0) directMethodsCode[i] = Code.parse(dex.getDataBuffer(codeOff), - dex); + dex, method); } // Parse encoded_method structures in virtual_methods array. @@ -138,12 +139,13 @@ int virtualMethodsIdx = 0; for (int i = 0; i < virtualMethodsSize; i++) { virtualMethodsIdx += BufferUtil.getULEB128(buffer); - virtualMethodsIds[i] = dex.getMethodId(virtualMethodsIdx); + MethodId method = dex.getMethodId(virtualMethodsIdx); + virtualMethodsIds[i] = method; virtualMethodsFlags[i] = BufferUtil.getULEB128(buffer); int codeOff = BufferUtil.getULEB128(buffer); if (codeOff != 0) virtualMethodsCode[i] = Code.parse(dex.getDataBuffer(codeOff), - dex); + dex, method); } // Parse encoded_array_item and contained encoded_value structures.
--- a/src/main/java/org/icedrobot/daneel/dex/Code.java Fri Mar 25 16:08:30 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/Code.java Fri Mar 25 23:59:09 2011 +0100 @@ -61,14 +61,17 @@ * * @param buffer The byte buffer to read from. * @param dex The DEX file currently being parsed. + * @param method The method identifier this code belongs to. * @return An object representing the parsed data. */ - public static Code parse(ByteBuffer buffer, DexFile dex) { - return new Code(buffer, dex); + public static Code parse(ByteBuffer buffer, DexFile dex, MethodId method) { + return new Code(buffer, dex, method); } private final DexFile dex; + private final MethodId method; + private final int registersSize; private final int insSize; @@ -85,8 +88,9 @@ private final List<TryCatchInfo> tryCatchInfos; - private Code(ByteBuffer buffer, DexFile dex) { + private Code(ByteBuffer buffer, DexFile dex, MethodId method) { this.dex = dex; + this.method = method; registersSize = buffer.getShort(); insSize = buffer.getShort(); outsSize = buffer.getShort(); @@ -152,6 +156,15 @@ } /** + * Returns the method identifier of the method this code belongs to. + * + * @return The method identifier object. + */ + public MethodId getMethod() { + return method; + } + + /** * Returns the number of registers used by the code as specified in the DEX * file. * @@ -168,25 +181,21 @@ */ public void accept(DexMethodVisitor visitor) { visitor.visitCode(registersSize, insSize, outsSize); - + // Visit try-catch block information if available. for (TryCatchInfo tryCatch : tryCatchInfos) visitor.visitTryCatch(tryCatch.startLabel, tryCatch.endLabel, tryCatch.handlerLabel, tryCatch.type); - - // visit instructions + + // Visit instructions. acceptInsns(visitor); // Visit local variable information if available. if (debugInfo != null) - for (LocalVariable local : debugInfo.getLocalVariables()) { - String name = (local.nameIdx != DexFile.NO_INDEX) ? dex - .getString(local.nameIdx) : null; - String desc = (local.typeIdx != DexFile.NO_INDEX) ? dex - .getTypeDescriptor(local.typeIdx) : null; - visitor.visitLocalVariable(name, desc, local.startLabel, - local.endLabel, local.regNum); - } + for (LocalVariable local : debugInfo.getLocalVariables()) + visitor.visitLocalVariable(local.name, local.type, + local.startLabel, local.endLabel, local.regNum); + } /**
--- a/src/main/java/org/icedrobot/daneel/dex/DebugInfo.java Fri Mar 25 16:08:30 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/DebugInfo.java Fri Mar 25 23:59:09 2011 +0100 @@ -43,6 +43,7 @@ import org.icedrobot.daneel.dex.Code.DebugLabel; import org.icedrobot.daneel.util.BufferUtil; +import org.icedrobot.daneel.util.TypeUtil; /** * A parser class capable of parsing {@code debug_info_item} structures as part @@ -75,6 +76,8 @@ return new DebugInfo(buffer, dex, code); } + private final DexFile dex; + private final Code code; private final int lineStart; @@ -86,6 +89,7 @@ private final List<LocalVariable> localVariables; private DebugInfo(ByteBuffer buffer, DexFile dex, Code code) { + this.dex = dex; this.code = code; lineStart = BufferUtil.getULEB128(buffer); parametersSize = BufferUtil.getULEB128(buffer); @@ -146,10 +150,26 @@ int maxRegs = code.getRegistersSize(); LocalVariable[] regs = new LocalVariable[maxRegs]; + // Emit local variables for method parameters. + String[] parameterTypes = code.getMethod().getProtoId().getParameters(); + if (parameterTypes != null) { + if (parametersSize != parameterTypes.length) + throw new DexParseException("Parameter count does not match."); + int regNum = maxRegs - 1; + for (int i = parametersSize - 1; i >= 0; i--, regNum--) { + String name = parameterNames[i]; + String type = parameterTypes[i]; + if (TypeUtil.isWideType(type)) + regNum--; + regs[regNum] = emitLocalVariable(regNum, 0, name, type, null); + } + } + // Iterate over all state machine bytecodes. while (buffer.hasRemaining()) { int opcode = buffer.get() & 0xff; int regNum, nameIdx, typeIdx, sigIdx; + String name, type, sig; LocalVariable local; // Switch over all possible bytecodes. @@ -169,11 +189,12 @@ regNum = BufferUtil.getULEB128(buffer); nameIdx = BufferUtil.getULEB128(buffer) - 1; typeIdx = BufferUtil.getULEB128(buffer) - 1; + name = resolveString(nameIdx); + type = resolveType(typeIdx); local = regs[regNum]; if (local != null && local.endLabel == null) throw new DexParseException("Live local in register."); - regs[regNum] = emitLocalVariable(regNum, addr, nameIdx, - typeIdx, DexFile.NO_INDEX); + regs[regNum] = emitLocalVariable(regNum, addr, name, type, null); break; case DBG_START_LOCAL_EXTENDED: @@ -181,30 +202,34 @@ nameIdx = BufferUtil.getULEB128(buffer) - 1; typeIdx = BufferUtil.getULEB128(buffer) - 1; sigIdx = BufferUtil.getULEB128(buffer) - 1; + name = resolveString(nameIdx); + type = resolveType(typeIdx); + sig = resolveString(sigIdx); local = regs[regNum]; if (local != null && local.endLabel == null) throw new DexParseException("Live local in register."); - regs[regNum] = emitLocalVariable(regNum, addr, nameIdx, - typeIdx, sigIdx); + regs[regNum] = emitLocalVariable(regNum, addr, name, type, sig); break; case DBG_END_LOCAL: regNum = BufferUtil.getULEB128(buffer); local = regs[regNum]; if (local == null || local.endLabel != null) - // XXX Check why this happens, this shouldn't happen. - //throw new DexParseException("No live local in register."); - break; - local.setEnd(code.putLabel(addr, false)); + throw new DexParseException("No live local in register."); + local.endLabel = code.putLabel(addr, false); break; case DBG_RESTART_LOCAL: regNum = BufferUtil.getULEB128(buffer); local = regs[regNum]; if (local == null || local.endLabel == null) - throw new DexParseException("No local to re-introduce."); - regs[regNum] = emitLocalVariable(regNum, addr, local.nameIdx, - local.typeIdx, local.sigIdx); + // XXX Check why this happens, this shouldn't happen. + //throw new DexParseException("No local to re-introduce."); + break; + name = local.name; + type = local.type; + sig = local.sig; + regs[regNum] = emitLocalVariable(regNum, addr, name, type, sig); break; case DBG_SET_PROLOGUE_END: @@ -230,6 +255,14 @@ throw new DexParseException("Premature end of state machine."); } + private String resolveString(int idx) { + return (idx != DexFile.NO_INDEX) ? dex.getString(idx) : null; + } + + private String resolveType(int idx) { + return (idx != DexFile.NO_INDEX) ? dex.getTypeDescriptor(idx) : null; + } + /** * Emits a new local variable information. The returned object has all * information set correctly, except for the label at which the local @@ -237,16 +270,16 @@ * * @param regNum The register number that will contain the local variable. * @param startAddr The instruction offset where the local variable starts. - * @param nameIdx The index of the variable name or {@code NO_INDEX}. - * @param typeIdx The index of the type descriptor or {@code NO_INDEX}. - * @param sigIdx The index of the type signature or {@code NO_INDEX}. + * @param name The local variable's name or {@code null}. + * @param type The local variable's type descriptor or {@code null}. + * @param sig The local variable's type signature or {@code null}. * @return The object representing the local variable information. */ private LocalVariable emitLocalVariable(int regNum, int startAddr, - int nameIdx, int typeIdx, int sigIdx) { + String name, String type, String sig) { Label startLabel = code.putLabel(startAddr, false); - LocalVariable local = new LocalVariable(regNum, nameIdx, typeIdx, - sigIdx, startLabel); + LocalVariable local = new LocalVariable(regNum, name, type, sig, + startLabel); localVariables.add(local); return local; } @@ -276,26 +309,20 @@ */ static class LocalVariable { final int regNum; - final int nameIdx; - final int typeIdx; - final int sigIdx; + final String name; + final String type; + final String sig; final Label startLabel; Label endLabel; - public LocalVariable(int regNum, int nameIdx, int typeIdx, int sigIdx, + public LocalVariable(int regNum, String name, String type, String sig, Label startLabel) { this.regNum = regNum; - this.nameIdx = nameIdx; - this.typeIdx = typeIdx; - this.sigIdx = sigIdx; + this.name = name; + this.type = type; + this.sig = sig; this.startLabel = startLabel; } - - public void setEnd(Label endLabel) { - if (this.endLabel != null) - throw new DexParseException("Local variable is dead."); - this.endLabel = endLabel; - } }; /**
--- a/src/main/java/org/icedrobot/daneel/util/TypeUtil.java Fri Mar 25 16:08:30 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/util/TypeUtil.java Fri Mar 25 23:59:09 2011 +0100 @@ -107,4 +107,16 @@ } return internalNames; } + + /** + * Checks whether the given type descriptor is a wide type. That means that + * it requires two machine words (e.g. register pair, two local variable + * slots) to store such a value. + * + * @param desc The given type descriptor. + * @return True if the type is wide, false otherwise. + */ + public static boolean isWideType(String desc) { + return desc.equals("J") || desc.equals("D"); + } }