mirror of
https://github.com/revanced/smali.git
synced 2025-05-08 02:14:32 +02:00
Merged in DebugInfoBuilder.java from the prior dexlib, and fixed it up to work with the new dexlib
git-svn-id: https://smali.googlecode.com/svn/trunk@407 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
parent
3080fb1bfc
commit
11503ec26e
451
dexlib/src/main/java/org/jf/dexlib/Util/DebugInfoBuilder.java
Normal file
451
dexlib/src/main/java/org/jf/dexlib/Util/DebugInfoBuilder.java
Normal file
@ -0,0 +1,451 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util;
|
||||
|
||||
import org.jf.dexlib.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class is intended to provide an easy to use container to build up a method's debug info. You can easily add
|
||||
* an "event" at a specific address, where an event is something like a line number, start/end local, etc.
|
||||
* The events must be added such that the code addresses increase monotonically. This matches how a parser would
|
||||
* generally behave, and is intended to increase performance.
|
||||
*/
|
||||
public class DebugInfoBuilder
|
||||
{
|
||||
private static final int LINE_BASE = -4;
|
||||
private static final int LINE_RANGE = 15;
|
||||
private static final int FIRST_SPECIAL = 0x0a;
|
||||
|
||||
private int lineStart = 0;
|
||||
private ArrayList<String> parameterNames = new ArrayList<String>();
|
||||
private ArrayList<Event> events = new ArrayList<Event>();
|
||||
private int lastAddress = 0;
|
||||
|
||||
private boolean hasData;
|
||||
|
||||
private int currentAddress;
|
||||
private int currentLine;
|
||||
|
||||
public DebugInfoBuilder() {
|
||||
}
|
||||
|
||||
private void checkAddress(int address) {
|
||||
if (lastAddress > address) {
|
||||
throw new RuntimeException("Cannot add an event with an address before the address of the prior event");
|
||||
}
|
||||
}
|
||||
|
||||
public void addParameterName(String parameterName) {
|
||||
if (parameterName != null) {
|
||||
hasData = true;
|
||||
}
|
||||
|
||||
parameterNames.add(parameterName);
|
||||
}
|
||||
|
||||
public void addLine(int address, int line) {
|
||||
hasData = true;
|
||||
|
||||
checkAddress(address);
|
||||
|
||||
if (lineStart == 0) {
|
||||
lineStart = line;
|
||||
}
|
||||
|
||||
events.add(new LineEvent(address, line));
|
||||
}
|
||||
|
||||
public void addLocal(int address, int registerNumber, String localName, String localType) {
|
||||
hasData = true;
|
||||
|
||||
checkAddress(address);
|
||||
|
||||
events.add(new StartLocalEvent(address, registerNumber, localName, localType));
|
||||
}
|
||||
|
||||
public void addLocalExtended(int address, int registerNumber, String localName, String localType,
|
||||
String signature) {
|
||||
hasData = true;
|
||||
|
||||
checkAddress(address);
|
||||
|
||||
events.add(new StartLocalExtendedEvent(address, registerNumber, localName, localType, signature));
|
||||
}
|
||||
|
||||
public void addEndLocal(int address, int registerNumber) {
|
||||
hasData = true;
|
||||
|
||||
checkAddress(address);
|
||||
|
||||
events.add(new EndLocalEvent(address, registerNumber));
|
||||
}
|
||||
|
||||
public void addRestartLocal(int address, int registerNumber) {
|
||||
hasData = true;
|
||||
|
||||
checkAddress(address);
|
||||
|
||||
events.add(new RestartLocalEvent(address, registerNumber));
|
||||
}
|
||||
|
||||
public void addPrologue(int address) {
|
||||
hasData = true;
|
||||
|
||||
checkAddress(address);
|
||||
|
||||
events.add(new PrologueEvent(address));
|
||||
}
|
||||
|
||||
public void addEpilogue(int address) {
|
||||
hasData = true;
|
||||
|
||||
checkAddress(address);
|
||||
|
||||
events.add(new EpilogueEvent(address));
|
||||
}
|
||||
|
||||
public void addSetFile(int address, String fileName) {
|
||||
hasData = true;
|
||||
|
||||
checkAddress(address);
|
||||
|
||||
events.add(new SetFileEvent(address, fileName));
|
||||
}
|
||||
|
||||
public int getParameterNameCount() {
|
||||
return parameterNames.size();
|
||||
}
|
||||
|
||||
public DebugInfoItem encodeDebugInfo(DexFile dexFile) {
|
||||
if (!hasData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ByteArrayOutput out = new ByteArrayOutput();
|
||||
StringIdItem[] parameterNamesArray = new StringIdItem[parameterNames.size()];
|
||||
ArrayList<Item> referencedItems = new ArrayList<Item>();
|
||||
|
||||
if (lineStart == 0) {
|
||||
lineStart = 1;
|
||||
}
|
||||
|
||||
currentLine = lineStart;
|
||||
|
||||
for (Event event: events) {
|
||||
event.emit(dexFile, out, referencedItems);
|
||||
}
|
||||
emitEndSequence(out);
|
||||
|
||||
int index = 0;
|
||||
for (String parameterName: parameterNames) {
|
||||
if (parameterName == null) {
|
||||
parameterNamesArray[index++] = null;
|
||||
} else {
|
||||
parameterNamesArray[index++] = StringIdItem.getInternedStringIdItem(dexFile, parameterName);
|
||||
}
|
||||
}
|
||||
|
||||
Item[] referencedItemsArray = new Item[referencedItems.size()];
|
||||
referencedItems.toArray(referencedItemsArray);
|
||||
return DebugInfoItem.getInternedDebugInfoItem(dexFile, lineStart, parameterNamesArray, out.getArray(),
|
||||
referencedItemsArray);
|
||||
}
|
||||
|
||||
private interface Event
|
||||
{
|
||||
int getAddress();
|
||||
void emit(DexFile dexFile, Output out, List<Item> referencedItems);
|
||||
}
|
||||
|
||||
private void emitEndSequence(Output out) {
|
||||
out.writeByte(0);
|
||||
}
|
||||
|
||||
private void emitAdvancePC(Output out, int address) {
|
||||
int addressDelta = address-currentAddress;
|
||||
|
||||
if (addressDelta > 0) {
|
||||
out.writeByte(1);
|
||||
out.writeUnsignedLeb128(addressDelta);
|
||||
currentAddress = address;
|
||||
}
|
||||
}
|
||||
|
||||
private void emitAdvanceLine(Output out, int lineDelta) {
|
||||
out.writeByte(2);
|
||||
out.writeSignedLeb128(lineDelta);
|
||||
}
|
||||
|
||||
private void emitStartLocal(Output out, int registerNum) {
|
||||
out.writeByte(3);
|
||||
out.writeUnsignedLeb128(registerNum);
|
||||
out.writeByte(1);
|
||||
out.writeByte(1);
|
||||
}
|
||||
|
||||
private void emitStartLocalExtended(Output out, int registerNum) {
|
||||
out.writeByte(4);
|
||||
out.writeUnsignedLeb128(registerNum);
|
||||
out.writeByte(1);
|
||||
out.writeByte(1);
|
||||
out.writeByte(1);
|
||||
}
|
||||
|
||||
private void emitEndLocal(Output out, int registerNum) {
|
||||
out.writeByte(5);
|
||||
out.writeUnsignedLeb128(registerNum);
|
||||
}
|
||||
|
||||
private void emitRestartLocal(Output out, int registerNum) {
|
||||
out.writeByte(6);
|
||||
out.writeUnsignedLeb128(registerNum);
|
||||
}
|
||||
|
||||
private void emitSetPrologueEnd(Output out) {
|
||||
out.writeByte(7);
|
||||
}
|
||||
|
||||
private void emitSetEpilogueBegin(Output out) {
|
||||
out.writeByte(8);
|
||||
}
|
||||
|
||||
private void emitSetFile(Output out) {
|
||||
out.writeByte(9);
|
||||
out.writeByte(1);
|
||||
}
|
||||
|
||||
private void emitSpecialOpcode(Output out, byte opcode) {
|
||||
out.writeByte(opcode);
|
||||
}
|
||||
|
||||
private class LineEvent implements Event
|
||||
{
|
||||
private final int address;
|
||||
private final int line;
|
||||
|
||||
public LineEvent(int address, int line) {
|
||||
this.address = address;
|
||||
this.line = line;
|
||||
}
|
||||
|
||||
public int getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void emit(DexFile dexFile, Output out, List<Item> referencedItems) {
|
||||
int lineDelta = line - currentLine;
|
||||
int addressDelta = address - currentAddress;
|
||||
|
||||
if (lineDelta < -4 || lineDelta > 10) {
|
||||
emitAdvanceLine(out, lineDelta);
|
||||
lineDelta = 0;
|
||||
}
|
||||
if (lineDelta < 2 && addressDelta > 16 || lineDelta > 1 && addressDelta > 15) {
|
||||
emitAdvancePC(out, addressDelta);
|
||||
addressDelta = 0;
|
||||
}
|
||||
|
||||
//TODO: need to handle the case when the line delta is larger than a signed int
|
||||
emitSpecialOpcode(out, calculateSpecialOpcode(lineDelta, addressDelta));
|
||||
|
||||
currentAddress = address;
|
||||
currentLine = line;
|
||||
}
|
||||
|
||||
private byte calculateSpecialOpcode(int lineDelta, int addressDelta) {
|
||||
return (byte)(FIRST_SPECIAL + (addressDelta * LINE_RANGE) + (lineDelta - LINE_BASE));
|
||||
}
|
||||
}
|
||||
|
||||
private class StartLocalEvent implements Event
|
||||
{
|
||||
private final int address;
|
||||
private final int registerNum;
|
||||
private final String localName;
|
||||
private final String localType;
|
||||
|
||||
public StartLocalEvent(int address, int registerNum, String localName, String localType) {
|
||||
this.address = address;
|
||||
this.registerNum = registerNum;
|
||||
this.localName = localName;
|
||||
this.localType = localType;
|
||||
}
|
||||
|
||||
public int getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void emit(DexFile dexFile, Output out, List<Item> referencedItems) {
|
||||
emitAdvancePC(out, address);
|
||||
emitStartLocal(out, registerNum);
|
||||
referencedItems.add(localName==null?null:StringIdItem.getInternedStringIdItem(dexFile, localName));
|
||||
referencedItems.add(localType==null?null:TypeIdItem.getInternedTypeIdItem(dexFile,
|
||||
StringIdItem.getInternedStringIdItem(dexFile, localType)));
|
||||
}
|
||||
}
|
||||
|
||||
private class StartLocalExtendedEvent implements Event
|
||||
{
|
||||
private final int address;
|
||||
private final int registerNum;
|
||||
private final String localName;
|
||||
private final String localType;
|
||||
private final String signature;
|
||||
|
||||
public StartLocalExtendedEvent(int address, int registerNum, String localName, String localType,
|
||||
String signature) {
|
||||
this.address = address;
|
||||
this.registerNum = registerNum;
|
||||
this.localName = localName;
|
||||
this.localType = localType;
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
public int getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void emit(DexFile dexFile, Output out, List<Item> referencedItems) {
|
||||
emitAdvancePC(out, address);
|
||||
emitStartLocalExtended(out, registerNum);
|
||||
if (localName != null) {
|
||||
referencedItems.add(StringIdItem.getInternedStringIdItem(dexFile, localName));
|
||||
}
|
||||
if (localType != null) {
|
||||
referencedItems.add(TypeIdItem.getInternedTypeIdItem(dexFile,
|
||||
StringIdItem.getInternedStringIdItem(dexFile, localType)));
|
||||
}
|
||||
if (signature != null) {
|
||||
referencedItems.add(StringIdItem.getInternedStringIdItem(dexFile, signature));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class EndLocalEvent implements Event
|
||||
{
|
||||
private final int address;
|
||||
private final int registerNum;
|
||||
|
||||
public EndLocalEvent(int address, int registerNum) {
|
||||
this.address = address;
|
||||
this.registerNum = registerNum;
|
||||
}
|
||||
|
||||
public int getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void emit(DexFile dexFile, Output out, List<Item> referencedItems) {
|
||||
emitAdvancePC(out, address);
|
||||
emitEndLocal(out, registerNum);
|
||||
}
|
||||
}
|
||||
|
||||
private class RestartLocalEvent implements Event
|
||||
{
|
||||
private final int address;
|
||||
private final int registerNum;
|
||||
|
||||
public RestartLocalEvent(int address, int registerNum) {
|
||||
this.address = address;
|
||||
this.registerNum = registerNum;
|
||||
}
|
||||
|
||||
public int getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void emit(DexFile dexFile, Output out, List<Item> referencedItems) {
|
||||
emitAdvancePC(out, address);
|
||||
emitRestartLocal(out, registerNum);
|
||||
}
|
||||
}
|
||||
|
||||
private class PrologueEvent implements Event
|
||||
{
|
||||
private final int address;
|
||||
|
||||
public PrologueEvent(int address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public int getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void emit(DexFile dexFile, Output out, List<Item> referencedItems) {
|
||||
emitAdvancePC(out, address);
|
||||
emitSetPrologueEnd(out);
|
||||
}
|
||||
}
|
||||
|
||||
private class EpilogueEvent implements Event
|
||||
{
|
||||
private final int address;
|
||||
|
||||
public EpilogueEvent(int address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public int getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void emit(DexFile dexFile, Output out, List<Item> referencedItems) {
|
||||
emitAdvancePC(out, address);
|
||||
emitSetEpilogueBegin(out);
|
||||
}
|
||||
}
|
||||
|
||||
private class SetFileEvent implements Event
|
||||
{
|
||||
private final int address;
|
||||
private final String fileName;
|
||||
|
||||
public SetFileEvent(int address, String fileName) {
|
||||
this.address = address;
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
public int getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void emit(DexFile dexFile, Output out, List<Item> referencedItems) {
|
||||
emitAdvancePC(out, address);
|
||||
emitSetFile(out);
|
||||
if (fileName != null) {
|
||||
referencedItems.add(StringIdItem.getInternedStringIdItem(dexFile, fileName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user