mirror of
https://github.com/revanced/smali.git
synced 2025-05-11 11:54:29 +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