/*
* Copyright (c) 2009-2012 Panxiaobo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.googlecode.dex2jar.reader;
import com.googlecode.dex2jar.reader.io.DataIn;
import com.googlecode.dex2jar.visitors.DexCodeVisitor;
/**
* 读取debug信息
*
* @author <a href="mailto:pxb1988@gmail.com">Panxiaobo</a>
* @version $Rev$
*/
/* default */class DexDebugInfoReader {
public static final int DBG_END_SEQUENCE = 0;
public static final int DBG_ADVANCE_PC = 1;
public static final int DBG_ADVANCE_LINE = 2;
public static final int DBG_START_LOCAL = 3;
public static final int DBG_START_LOCAL_EXTENDED = 4;
public static final int DBG_END_LOCAL = 5;
public static final int DBG_RESTART_LOCAL = 6;
public static final int DBG_SET_PROLOGUE_END = 7;
public static final int DBG_SET_EPILOGUE_BEGIN = 8;
public static final int DBG_SET_FILE = 9;
public static final int DBG_FIRST_SPECIAL = 10;
public static final int DBG_LINE_BASE = -4;
public static final int DBG_LINE_RANGE = 15;
private DataIn in;
private DexFileReader dex;
private int instruction_size;
private DexCodeReader codeReader;
LocalVariable variableList[];
int args[];
/**
* @param in
* @param dex
*/
public DexDebugInfoReader(DataIn in, DexFileReader dex, int instruction_size, DexCodeReader codeReader,
LocalVariable localVariables[], int args[]) {
super();
this.in = in;
this.dex = dex;
this.instruction_size = instruction_size;
this.codeReader = codeReader;
this.variableList = localVariables;
this.args = args;
}
public static class LocalVariable {
public int start;
public int end;
public String name;
public String type;
public String signature;
public int reg;
/**
* @param start
* @param end
* @param name
* @param type
* @param signature
*/
public LocalVariable(int reg, int start, int end, String name, String type, String signature) {
super();
this.reg = reg;
this.start = start;
this.end = end;
this.name = name;
this.type = type;
this.signature = signature;
}
}
/**
* 处理
*
* @param dcv
*/
public void accept(DexCodeVisitor dcv) {
// System.out.println("==");
DataIn in = this.in;
int line = (int) in.readULeb128();
{
int szParams = (int) in.readULeb128();
int offset = szParams == this.args.length ? 0 : 1;
for (int i = 0; i < szParams; i++) {
int string_offset = (int) in.readULeb128() - 1;
if (string_offset < 0) {// NO_INDEX
this.variableList[this.args[i + offset]] = null;// remove the variable
} else {
String psName = dex.getString(string_offset);
this.variableList[this.args[i + offset]].name = psName;
}
}
}
int pcOffset = 0;
{// init line
codeReader.order(pcOffset);
dcv.visitLineNumber(line, codeReader.labels.get(pcOffset));
}
l1: while (true) {
int opcode = in.readUByte();
switch (opcode) {
case DBG_END_SEQUENCE:
break l1;
case DBG_ADVANCE_PC: {
int offset = (int) in.readULeb128();
pcOffset += offset;
}
break;
case DBG_ADVANCE_LINE: {
int offset = (int) in.readLeb128();
line += offset;
}
break;
case DBG_START_LOCAL: {
int regNum = (int) in.readULeb128();
int nameIdx = (int) in.readULeb128() - 1;
int typeIdx = (int) in.readULeb128() - 1;
if ((nameIdx >= 0) && (typeIdx >= 0)) {
codeReader.order(pcOffset);
LocalVariable localVariable = new LocalVariable(regNum, pcOffset, -1, dex.getString(nameIdx),
dex.getType(typeIdx), null);
variableList[regNum] = localVariable;
}
}
break;
case DBG_START_LOCAL_EXTENDED: {
int regNum = (int) in.readULeb128();
int nameIdx = (int) in.readULeb128() - 1;
int typeIdx = (int) in.readULeb128() - 1;
int sigIdx = (int) in.readULeb128() - 1;
if ((nameIdx >= 0) && (typeIdx >= 0)) {
codeReader.order(pcOffset);
LocalVariable localVariable = new LocalVariable(regNum, pcOffset, -1, dex.getString(nameIdx),
dex.getType(typeIdx), dex.getString(sigIdx));
variableList[regNum] = localVariable;
}
}
break;
case DBG_END_LOCAL: {
int regNum = (int) in.readULeb128();
LocalVariable v = variableList[regNum];
codeReader.order(pcOffset);
v.end = pcOffset;
// System.out.println(v.start + " - " + pcOffset);
dcv.visitLocalVariable(v.name, v.type, v.signature, codeReader.labels.get(v.start),
codeReader.labels.get(pcOffset), v.reg);
}
break;
case DBG_RESTART_LOCAL: {
int regNum = (int) in.readULeb128();
LocalVariable v = variableList[regNum];
v.start = pcOffset;
v.end = -1;
codeReader.order(pcOffset);
}
break;
case DBG_SET_PROLOGUE_END: {
}
break;
case DBG_SET_EPILOGUE_BEGIN: {
}
break;
case DBG_SET_FILE: {
in.readULeb128();// skip source file in debug
// int sourceFileIdx = (int) in.readULeb128() - 1;
}
break;
default: {
int adjustedOpcode = opcode - DBG_FIRST_SPECIAL;
line += DBG_LINE_BASE + (adjustedOpcode % DBG_LINE_RANGE);
if (adjustedOpcode / DBG_LINE_RANGE != 0) {
pcOffset += (adjustedOpcode / DBG_LINE_RANGE);
codeReader.order(pcOffset);
dcv.visitLineNumber(line, codeReader.labels.get(pcOffset));
}
}
}
}
for (LocalVariable v : variableList) {
if (v != null && v.end < 0) {
codeReader.order(this.instruction_size);
// System.out.println(v.start + " - " + instruction_size);
dcv.visitLocalVariable(v.name, v.type, v.signature, codeReader.labels.get(v.start),
codeReader.labels.get(instruction_size), v.reg);
}
}
}
}