blob: d14d74a70df1bf5cd42e2f30d8503addc71b662d [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* 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 dasm;
import com.android.dx.dex.DexOptions;
import com.android.dx.dex.code.ArrayData;
import com.android.dx.dex.code.CodeAddress;
import com.android.dx.dex.code.CstInsn;
import com.android.dx.dex.code.DalvCode;
import com.android.dx.dex.code.DalvInsn;
import com.android.dx.dex.code.Dops;
import com.android.dx.dex.code.OddSpacer;
import com.android.dx.dex.code.OutputFinisher;
import com.android.dx.dex.code.PositionList;
import com.android.dx.dex.code.SimpleInsn;
import com.android.dx.dex.code.SwitchData;
import com.android.dx.dex.code.TargetInsn;
import com.android.dx.dex.code.form.Form51l;
import com.android.dx.dex.file.ClassDefItem;
import com.android.dx.dex.file.DexFile;
import com.android.dx.dex.file.EncodedField;
import com.android.dx.dex.file.EncodedMethod;
import com.android.dx.rop.code.AccessFlags;
import com.android.dx.rop.code.RegisterSpec;
import com.android.dx.rop.code.RegisterSpecList;
import com.android.dx.rop.code.SourcePosition;
import com.android.dx.rop.cst.Constant;
import com.android.dx.rop.cst.CstBoolean;
import com.android.dx.rop.cst.CstByte;
import com.android.dx.rop.cst.CstChar;
import com.android.dx.rop.cst.CstDouble;
import com.android.dx.rop.cst.CstFieldRef;
import com.android.dx.rop.cst.CstFloat;
import com.android.dx.rop.cst.CstInteger;
import com.android.dx.rop.cst.CstLong;
import com.android.dx.rop.cst.CstMethodRef;
import com.android.dx.rop.cst.CstNat;
import com.android.dx.rop.cst.CstShort;
import com.android.dx.rop.cst.CstString;
import com.android.dx.rop.cst.CstType;
import com.android.dx.rop.type.StdTypeList;
import com.android.dx.rop.type.Type;
import com.android.dx.rop.type.TypeList;
import com.android.dx.util.IntList;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
//TODO: copyright notice
/**
* This class represents the public API for Dasm. It has two main methods (readD
* and write) and few utility methods. To compile .d file: -create DAsm instance
* -call readD() to read and parse content of .d file -call write() to write out
* binary representation of .d file. .d file can contain several classes and/or
* intefaces declarations.
*/
public class DAsm {
private static final boolean PARSER_DEBUG = false;
// number of errors reported in a file.
int errors;
// options for dex output
DexOptions dexOptions = new DexOptions();
// file being processed
DexFile dexFile;
int line_num;
Scanner scanner;
// state info for the class being built
boolean class_header;
String class_name;
int class_acc;
String superclass_name;
String source_name;
String filename;
Vector<String> interfaces = new Vector<String>();
ClassDefItem classDef;
// method being built
EncodedMethod enc_method;
CstNat method_nat;
int method_acc;
int regs_count;
OutputFinisher output_finisher;
/**
* list of exceptions that method can throw.
*/
Vector<String> throw_list = new Vector<String>();
/**
* Constructor of CatchTable instances from method data.
*/
DasmCatchBuilder catch_builder;
/**
* Holds CodeAddress associated with particular label and <i>planted</i>
* attribute specifying that CodeAddress was added to instructions array.
* <i>planted</i> is false if this label is a target of forward branch and
* it was not added to instructions array yet.
*/
class LabelTableEntry {
LabelTableEntry(CodeAddress code_address, boolean planted) {
this.code_address = code_address;
this.planted = planted;
}
CodeAddress code_address;
boolean planted;
}
/**
* Hold a translation table "LabelX" -> CodeAddress, planted.
*/
Hashtable<String, LabelTableEntry> labels_table;
/**
* used by relative forward jumps. When relative forward offset is found,
* CodeAddress is placed into unprocessed_relative_goto_addr. When addInsn
* method is called, it checks if there was a jump to current instruction
* and moves CodeAddress from unprocessed_relative_goto_addr into
* output_finisher.
*/
int current_insn_number;
Hashtable<Integer, CodeAddress> unprocessed_relative_goto_addr =
new Hashtable<Integer, CodeAddress>();
// fill-array-data data
int fill_data_reg;
String fill_array_data_type;
Vector<Number> fill_array_data_values;
// packed-switch and sparse-switch data
int switch_reg;
Vector<Object> switch_targets;
IntList switch_keys;
int packed_switch_first_key;
int packed_switch_current_key;
/**
* holds sparse-switch, packed-switch and fill-array-data data blocks to be
* added at the end of method
*/
Vector<DalvInsn> data_blocks = new Vector<DalvInsn>();
/**
* Returns the number of warnings/errors encountered while parsing a file. 0
* if everything went OK.
*/
public int errorCount() {
return errors;
}
void report_error(String msg) {
errors++;
System.out.println("Line " + line_num + ": " + msg);
}
void throwDasmError(String msg) throws DasmError {
throw new DasmError("Line " + line_num + ": " + msg);
}
/**
* used by .line directive
*/
void addLineInfo(int line_num) throws DasmError {
throw new IllegalStateException(".line not implemented");
}
void addLine(int line_num) throws DasmError {
throw new IllegalStateException(".line not implemented");
}
/**
* used by the .var directive
*/
void addVar(String startLab, String endLab, String name, String desc,
String sign, int var_num) throws DasmError {
throw new IllegalStateException(".var is not implemented");
}
void addVar(int startOffset, int endOffset, String name, String desc,
String sign, int var_num) throws DasmError {
throw new IllegalStateException(".var is not implemented");
}
/**
* Used by the parser to tell DAsm what the line number for the next
* statement is. DAsm's autoNumber mechanism uses this info.
*/
void setLine(int l) {
if (PARSER_DEBUG) System.out.println("setLine(" + l + ")");
line_num = l;
}
/**
* called by the .inner directive
*/
void addInner(short iacc, String name, String inner, String outer) {
throw new IllegalStateException(".inner is not implemented");
}
/*
* ========================================================================
* === FILE HEADER
* ========================================================================
*/
/**
* called by the .source directive
*/
void setSource(String name) {
if (PARSER_DEBUG) System.out.println("setSource(" + name + ")");
source_name = name;
}
/**
* called by the .bytecode directive
*/
void setVersion(Number version) {
throw new IllegalStateException(".bytecode is not implemented");
}
/**
* called by the .class directive
*/
void setClass(String name, int acc) {
if (PARSER_DEBUG)
System.out.println("setClass(" + name + ", " + acc + ")");
class_name = name;
class_acc = acc;
class_header = true;
interfaces.clear();
superclass_name = null;
}
/**
* Returns the name of the class in the file (i.e. the string given to the
* .class parameter). If there're several classes in one file, returns name
* of last class.
*/
public String getClassName() {
return class_name;
}
/**
* called by the .super directive
*/
void setSuperClass(String name) {
if (PARSER_DEBUG) System.out.println("setSuperClass(" + name + ")");
superclass_name = name;
}
/**
* called by the .implements directive
*/
void addInterface(String name) {
if (PARSER_DEBUG) System.out.println("addInterface(" + name + ")");
int sz = interfaces.size();
boolean found = false;
// search for duplicates
for (int i = 0; i < sz; i++) {
String s = interfaces.elementAt(i);
if (s.compareTo(name) == 0) {
found = true;
break;
}
}
if (found == false) interfaces.add(name);
}
/**
* called by the .signature directive
*/
void setSignature(String str) throws DasmError {
throw new IllegalStateException(".signature is not implemented");
}
/**
* called by the .enclosing directive
*/
void setEnclosingMethod(String str) {
throw new IllegalStateException(".enclosing is not implemented");
}
/**
* called by the .attribute directive
*/
void addGenericAttr(String name, String file) throws DasmError {
throw new IllegalStateException(".attribute is not implemented");
}
/**
* called at end of dasm-header (resolve class variables)
*/
void endHeader() {
TypeList tl = createTypeListFromStrings(interfaces);
classDef = new ClassDefItem(CstType.intern(Type
.internClassName(class_name)), class_acc,
superclass_name != null ? CstType.intern(Type
.internClassName(superclass_name)) : null, tl,
new CstString(source_name));
dexFile.add(classDef);
class_header = false;
}
/*
* ========================================================================
* === FIELDS
* ========================================================================
*/
/**
* called by the .field directive to begin 'prompted' field
*/
void beginField(short access, String name, String desc, Object value)
throws DasmError {
throw new IllegalStateException(
"multiline fields are not implemented yet");
}
/**
* called by the .end field directive to end 'prompted' field
*/
void endField() throws DasmError {
throw new IllegalStateException(
"multiline fields are not implemented yet");
}
/**
* called by the .field directive
*/
void addField(short access, String name, String desc, String sig,
Object value) throws DasmError {
if (PARSER_DEBUG)
System.out.println("addField(" + name + ", " + desc + ", " + sig
+ ", " + access + ", "
+ (value == null ? "null" : value.toString()) + ")");
CstNat nat = new CstNat(new CstString(name), new CstString(desc));
CstFieldRef field = new CstFieldRef(classDef.getThisClass(), nat);
EncodedField ef = new EncodedField(field, access);
if ((access & AccessFlags.ACC_STATIC) != 0) {
// TODO: value?
if (value != null)
throw new IllegalStateException(
"addField: field initialization not implemented yet");
classDef.addStaticField(ef, null);
} else
classDef.addInstanceField(ef);
}
/*
* ========================================================================
* === METHODS
* ========================================================================
*/
/**
* called by the .method directive to start the definition for a method
*/
void newMethod(String name, String descriptor, int access) {
if (PARSER_DEBUG)
System.out.println("newMethod(" + name + ", " + descriptor + ", "
+ access + ")");
output_finisher = null;
throw_list.clear();
unprocessed_relative_goto_addr.clear();
labels_table = new Hashtable<String, LabelTableEntry>();
catch_builder = new DasmCatchBuilder(labels_table);
current_insn_number = 0;
regs_count = 1;
method_nat = new CstNat(new CstString(name), new CstString(descriptor));
if (method_nat.isClassInit()) access |= AccessFlags.ACC_STATIC;
if (method_nat.isInstanceInit()) access |= AccessFlags.ACC_CONSTRUCTOR;
method_acc = access;
}
/**
* called by the .end method directive to end the definition for a method
*/
void endMethod() throws DasmError {
if (PARSER_DEBUG) System.out.println("endMethod()");
// add packed-switch, sparse-switch, fill-array-data data blocks at the
// end of method
int sz = data_blocks.size();
for (int i = 0; i < sz; i++) {
addInsn(data_blocks.elementAt(i));
}
data_blocks.clear();
// check jump targets
if (unprocessed_relative_goto_addr.size() != 0) {
report_error("Relative forward jump offset too big.");
}
Enumeration<String> e = labels_table.keys();
while (e.hasMoreElements()) {
String key = e.nextElement();
LabelTableEntry lte = labels_table.get(key);
if (lte.planted == false) {
report_error("Label " + key + " not found.");
}
}
TypeList tl = createTypeListFromStrings(throw_list);
CstMethodRef meth = new CstMethodRef(classDef.getThisClass(),
method_nat);
DalvCode code = null;
// output_finisher may be null at this point if method is native
if (output_finisher != null)
code = new DalvCode(PositionList.NONE, output_finisher,
catch_builder);
enc_method = new EncodedMethod(meth, method_acc, code, tl);
if (meth.isInstanceInit() || meth.isClassInit()
|| (method_acc & AccessFlags.ACC_STATIC) != 0
|| (method_acc & AccessFlags.ACC_PRIVATE) != 0) {
classDef.addDirectMethod(enc_method);
} else {
classDef.addVirtualMethod(enc_method);
}
catch_builder = null;
labels_table = null;
}
/**
* used by the .limit regs directive
*/
void setRegsSize(int v) throws DasmError {
if (PARSER_DEBUG) System.out.println("setRegsSize(" + v + ")");
regs_count = v;
}
/**
* used by the .throws directive
*/
void addThrow(String name) throws DasmError {
if (PARSER_DEBUG) System.out.println("addThrow(" + name + ")");
throw_list.add(name);
}
/**
* used by the .catch directive
*/
void addCatch(String name, String start_lab, String end_lab,
String branch_lab) throws DasmError {
if (PARSER_DEBUG)
System.out.println("addCatch(" + name + ", " + start_lab + ", "
+ end_lab + ", " + branch_lab + ")");
catch_builder.add(name, start_lab, end_lab, branch_lab);
}
void addCatch(String name, int start_off, int end_off, int branch_off)
throws DasmError {
if (PARSER_DEBUG)
System.out.println("addCatch(" + name + ", " + start_off + ", "
+ end_off + ", " + branch_off + ")");
throw new IllegalStateException(
"addCatch(String, int, int, int) is not implemented yet");
}
/**
* defines a label
*/
void plantLabel(String name) throws DasmError {
if (PARSER_DEBUG) System.out.println("plantLabel(" + name + ")");
createOutputFinisher();
LabelTableEntry lte = labels_table.get(name);
if (lte != null) {
if (lte.planted == true)
report_error("Label " + name + " already defined");
else {
lte.planted = true;
addInsn(lte.code_address);
}
} else {
CodeAddress code_address = new CodeAddress(createSourcePosition());
addInsn(code_address);
labels_table.put(name, new LabelTableEntry(code_address, true));
}
}
/**
* used for instructions that take no arguments Format: 10x
*/
void addOpcode(String name) throws DasmError {
if (PARSER_DEBUG) System.out.println("addOpcode(" + name + ")");
createOutputFinisher();
DopInfo insn = DopInfo.get(name);
if (insn.args.equals("")) {
DalvInsn dalvInsn = new SimpleInsn(insn.opcode,
createSourcePosition(), RegisterSpecList.EMPTY);
addInsn(dalvInsn);
} else {
throwDasmError("Missing arguments for instruction " + name);
}
}
/**
* used for instructions that take a word as a parameter (register name is
* treated as word) Format: 11x, 10t, 20t, 30t
*/
void addOpcode(String name, String val) throws DasmError {
if (PARSER_DEBUG)
System.out.println("addOpcode(" + name + ", " + val + ")");
createOutputFinisher();
DopInfo insn = DopInfo.get(name);
if (insn.args.compareToIgnoreCase(DopInfo.ARG_REGISTER) == 0) {
int reg_num = -1;
try {
reg_num = getRegNumberFromString(val);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for instruction " + name + "("
+ val + ")");
}
// TODO: is Type.INT suitable for any opcodes? Or it should be
// Type.OBJECT for return-object, for example?
RegisterSpec reg_spec = RegisterSpec.make(reg_num, Type.INT);
DalvInsn dalvInsn = new SimpleInsn(insn.opcode,
createSourcePosition(), RegisterSpecList.make(reg_spec));
addInsn(dalvInsn);
} else if (insn.args.compareToIgnoreCase(DopInfo.ARG_ADDRESS) == 0) {
LabelTableEntry lte = labels_table.get(val);
if (lte == null) {
CodeAddress code_address = new CodeAddress(
SourcePosition.NO_INFO);
lte = new LabelTableEntry(code_address, false);
labels_table.put(val, lte);
}
DalvInsn dalvInsn = new TargetInsn(insn.opcode,
createSourcePosition(), RegisterSpecList.EMPTY,
lte.code_address);
addInsn(dalvInsn);
} else {
throwDasmError("Bad arguments for instruction " + name + "(" + val
+ ")");
}
}
/**
* used for relative branch targets (ie $+5, $-12, ...) Format: relative
* 10t, 20t, 30t
*/
void addRelativeGoto(String name, int val) throws DasmError {
if (PARSER_DEBUG)
System.out.println("addRelativeGoto(" + name + ", " + val + ")");
createOutputFinisher();
DopInfo insn = DopInfo.get(name);
if (insn.args.compareToIgnoreCase(DopInfo.ARG_ADDRESS) == 0) {
if (val == 0)
throwDasmError("Bad arguments for instruction " + name + "("
+ val + ")");
CodeAddress code_address = new CodeAddress(SourcePosition.NO_INFO);
if (val < 0) {
output_finisher.insert(current_insn_number + val, code_address);
current_insn_number++;
} else {
unprocessed_relative_goto_addr.put(current_insn_number + val,
code_address);
}
DalvInsn dalvInsn = new TargetInsn(insn.opcode,
createSourcePosition(), RegisterSpecList.EMPTY,
code_address);
addInsn(dalvInsn);
} else {
throwDasmError("Bad arguments for instruction " + name + "(" + val
+ ")");
}
}
/**
* used for instructions that take two word parameters (register name is
* treated as word) Format: 12x, 22x, 32x, 21t, 21c (string@, type@), 31c,
* 35c, 3rc
*/
void addOpcode(String name, String v1, String v2) throws DasmError {
if (PARSER_DEBUG)
System.out.println("addOpcode(" + name + ", " + v1 + ", " + v2
+ ")");
createOutputFinisher();
DopInfo insn = DopInfo.get(name);
if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_REG) == 0) {
int reg1_num = -1, reg2_num = -1;
try {
reg1_num = getRegNumberFromString(v1);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for instruction " + name + "("
+ v1 + ")");
}
try {
reg2_num = getRegNumberFromString(v2);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for instruction " + name + "("
+ v2 + ")");
}
// TODO: is Type.INT suitable for any opcodes?
RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
RegisterSpec reg2_spec = RegisterSpec.make(reg2_num, Type.INT);
DalvInsn dalvInsn = new SimpleInsn(insn.opcode,
createSourcePosition(), RegisterSpecList.make(reg1_spec,
reg2_spec));
addInsn(dalvInsn);
} else if (insn.args.compareToIgnoreCase(
DopInfo.ARG_REG_ADDRESS) == 0) {
int reg1_num = -1;
try {
reg1_num = getRegNumberFromString(v1);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for instruction " + name + "("
+ v1 + ")");
}
LabelTableEntry lte = labels_table.get(v2);
if (lte == null) {
CodeAddress code_address = new CodeAddress(
SourcePosition.NO_INFO);
lte = new LabelTableEntry(code_address, false);
labels_table.put(v2, lte);
}
RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
DalvInsn dalvInsn = new TargetInsn(insn.opcode,
createSourcePosition(), RegisterSpecList.make(reg1_spec),
lte.code_address);
addInsn(dalvInsn);
} else if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_STRING) == 0) {
int reg1_num = -1;
try {
reg1_num = getRegNumberFromString(v1);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for instruction " + name + "("
+ v1 + ")");
}
RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.STRING);
Constant constant = new CstString(v2);
DalvInsn dalvInsn = new CstInsn(insn.opcode,
createSourcePosition(), RegisterSpecList.make(reg1_spec),
constant);
addInsn(dalvInsn);
} else if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_TYPE) == 0) {
int reg1_num = -1;
try {
reg1_num = getRegNumberFromString(v1);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for instruction " + name + "("
+ v1 + ")");
}
Type type;
try {
// try to intern it as primitive type first
type = Type.intern(v2);
} catch (IllegalArgumentException e) {
type = Type.internClassName(v2);
}
RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, type);
Constant constant = CstType.intern(type);
DalvInsn dalvInsn = new CstInsn(insn.opcode,
createSourcePosition(), RegisterSpecList.make(reg1_spec),
constant);
addInsn(dalvInsn);
} else if (insn.args.compareToIgnoreCase(DopInfo.ARG_REGLIST_TYPE) == 0
|| insn.args.compareToIgnoreCase(
DopInfo.ARG_REGLIST_METHOD) == 0
|| insn.args.compareToIgnoreCase(
DopInfo.ARG_REGLIST_INTFMETHOD) == 0) {
RegisterSpecList reg_spec_list = RegisterSpecList.EMPTY;
String regs[] = Utils.splitRegList(v1);
if (regs != null) {
int rn = regs.length;
if (rn == 0 || rn > 5)
throwDasmError("Bad arguments for instruction " + name
+ "(" + v1 + ")");
int reg_num[] = new int[rn];
reg_spec_list = new RegisterSpecList(rn);
for (int i = 0; i < rn; i++) {
try {
reg_num[i] = getRegNumberFromString(regs[i]);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for instruction " + name
+ "(" + v1 + ")");
}
reg_spec_list.set(i, RegisterSpec
.make(reg_num[i], Type.INT));
}
}
Constant constant;
if (insn.args.compareToIgnoreCase(DopInfo.ARG_REGLIST_TYPE) == 0) {
// filled-new-array
Type type;
try {
type = Type.intern(v2);
} catch (IllegalArgumentException e) {
// in case of exception, try to intern type as a class name
// (Lclass_name;)
type = Type.internClassName(v2);
}
constant = CstType.intern(type);
} else {
// invoke-kind
String[] names = Utils.getClassMethodSignatureFromString(v2);
CstNat method_nat = new CstNat(new CstString(names[1]),
new CstString(names[2]));
/*
* if(insn.args.compareToIgnoreCase(
* DopInfo.ARG_REGLIST_INTFMETHOD
* ) == 0) constant = new
* CstInterfaceMethodRef(CstType.intern(Type
* .internClassName(names[0])), method_nat); else
*/
constant = new CstMethodRef(CstType.intern(Type
.internClassName(names[0])), method_nat);
}
DalvInsn dalvInsn = new CstInsn(insn.opcode,
createSourcePosition(), reg_spec_list, constant);
addInsn(dalvInsn);
} else if (insn.args.compareToIgnoreCase(
DopInfo.ARG_REGRANGE_TYPE) == 0
|| insn.args.compareToIgnoreCase(
DopInfo.ARG_REGRANGE_METHOD) == 0
|| insn.args.compareToIgnoreCase(
DopInfo.ARG_REGRANGE_INTFMETHOD) == 0) {
String regs[] = Utils.splitRegList(v1);
RegisterSpecList reg_spec_list;
if (regs != null && regs.length > 0) {
int regC = -1, regN = -1;
try {
regC = getRegNumberFromString(regs[0]);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for instruction " + name
+ "(" + v1 + ")");
}
if (regs.length > 1) {
try {
regN = getRegNumberFromString(regs[1]);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for instruction " + name
+ "(" + v1 + ")");
}
if (regC >= regN)
throwDasmError("Bad arguments for instruction " + name
+ "(" + v1 + ")");
} else
regN = regC;
int sz = regN - regC + 1;
reg_spec_list = new RegisterSpecList(sz);
for (int i = 0; i < sz; i++) {
reg_spec_list.set(i, RegisterSpec.make(regC + i, Type.INT));
}
} else
reg_spec_list = RegisterSpecList.EMPTY;
Constant constant;
if (insn.args.compareToIgnoreCase(DopInfo.ARG_REGRANGE_TYPE) == 0) {
// filled-new-array/range
Type type;
try {
type = Type.intern(v2);
} catch (IllegalArgumentException e) {
// in case of exception, try to intern type as a class name
// (Lclass_name;)
type = Type.internClassName(v2);
}
constant = CstType.intern(type);
} else {
// invoke-kind/range
String[] names = Utils.getClassMethodSignatureFromString(v2);
CstNat method_nat = new CstNat(new CstString(names[1]),
new CstString(names[2]));
/*
* if(insn.args.compareToIgnoreCase(
* DopInfo.ARG_REGRANGE_INTFMETHOD
* ) == 0) constant = new
* CstInterfaceMethodRef(CstType.intern(Type
* .internClassName(names[0])), method_nat); else
*/
constant = new CstMethodRef(CstType.intern(Type
.internClassName(names[0])), method_nat);
}
DalvInsn dalvInsn = new CstInsn(insn.opcode,
createSourcePosition(), reg_spec_list, constant);
addInsn(dalvInsn);
} else {
throwDasmError("Bad arguments for instruction " + name + "(" + v1
+ ", " + v2 + ")");
}
}
/**
* used for relative branch targets (ie $+5, $-12, ...) Format: relative 21t
*/
void addRelativeGoto(String name, String v1, int val) throws DasmError {
if (PARSER_DEBUG)
System.out.println("addRelativeGoto(" + name + ", " + v1 + ", "
+ val + ")");
createOutputFinisher();
DopInfo insn = DopInfo.get(name);
if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_ADDRESS) == 0) {
if (val == 0)
throwDasmError("Bad arguments for instruction " + name + "("
+ val + ")");
int reg1_num = -1;
try {
reg1_num = getRegNumberFromString(v1);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for instruction " + name + "("
+ v1 + ")");
}
RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
RegisterSpecList rsl = RegisterSpecList.make(reg1_spec);
CodeAddress code_address = new CodeAddress(SourcePosition.NO_INFO);
if (val < 0) {
output_finisher.insert(current_insn_number + val, code_address);
current_insn_number++;
} else {
unprocessed_relative_goto_addr.put(current_insn_number + val,
code_address);
}
DalvInsn dalvInsn = new TargetInsn(insn.opcode,
createSourcePosition(), rsl, code_address);
addInsn(dalvInsn);
} else {
throwDasmError("Bad arguments for instruction " + name + "(" + val
+ ")");
}
}
/**
* used for instructions that take one word parameter (register name is
* treated as word) and one literal Format: 11n, 21s, 31i, 21h, 51l
*/
void addOpcode(String name, String v1, Number v2) throws DasmError {
if (PARSER_DEBUG)
System.out.println("addOpcode(" + name + ", " + v1 + ", " + v2
+ ")");
createOutputFinisher();
DopInfo insn = DopInfo.get(name);
if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_LITERAL) == 0) {
int reg1_num = -1;
try {
reg1_num = getRegNumberFromString(v1);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for instruction " + name + "("
+ v1 + ")");
}
RegisterSpec reg1_spec;
Constant constant;
// create Constant of type suitable for value specified in
// instruction
if (v2 instanceof Long
|| (v2 instanceof Integer &&
insn.opcode.getFormat() == Form51l.THE_ONE)) {
reg1_spec = RegisterSpec.make(reg1_num, Type.LONG);
constant = CstLong.make(v2.longValue());
} else if (v2 instanceof Float
&& insn.opcode.getFormat() != Form51l.THE_ONE) {
reg1_spec = RegisterSpec.make(reg1_num, Type.FLOAT);
constant = CstFloat.make(Float.floatToIntBits(v2.floatValue()));
} else if (v2 instanceof Double
|| (v2 instanceof Float &&
insn.opcode.getFormat() == Form51l.THE_ONE)) {
reg1_spec = RegisterSpec.make(reg1_num, Type.DOUBLE);
constant = CstDouble.make(Double.doubleToLongBits(v2
.doubleValue()));
} else {
reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
constant = CstInteger.make(v2.intValue());
}
DalvInsn dalvInsn = new CstInsn(insn.opcode,
createSourcePosition(), RegisterSpecList.make(reg1_spec),
constant);
addInsn(dalvInsn);
} else {
throwDasmError("Bad arguments for instruction " + name + "(" + v1
+ ", " + v2 + ")");
}
}
/**
* used for instructions that take three word parameters (register name is
* treated as word) Format: 23x, 22t, 21c (field@), 22c (type@)
*/
void addOpcode(String name, String v1, String v2, String v3)
throws DasmError {
if (PARSER_DEBUG)
System.out.println("addOpcode(" + name + ", " + v1 + ", " + v2
+ ", " + v3 + ")");
createOutputFinisher();
DopInfo insn = DopInfo.get(name);
if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_REG_REG) == 0) {
int reg1_num = -1, reg2_num = -1, reg3_num = -1;
try {
reg1_num = getRegNumberFromString(v1);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for instruction " + name + "("
+ v1 + ")");
}
try {
reg2_num = getRegNumberFromString(v2);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for instruction " + name + "("
+ v2 + ")");
}
try {
reg3_num = getRegNumberFromString(v3);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for instruction " + name + "("
+ v3 + ")");
}
// TODO: is Type.INT suitable for any opcodes?
RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
RegisterSpec reg2_spec = RegisterSpec.make(reg2_num, Type.INT);
RegisterSpec reg3_spec = RegisterSpec.make(reg3_num, Type.INT);
DalvInsn dalvInsn = new SimpleInsn(insn.opcode,
createSourcePosition(), RegisterSpecList.make(reg1_spec,
reg2_spec, reg3_spec));
addInsn(dalvInsn);
} else if (insn.args.compareToIgnoreCase(
DopInfo.ARG_REG_REG_ADDRESS) == 0) {
int reg1_num = -1, reg2_num = -1;
try {
reg1_num = getRegNumberFromString(v1);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for instruction " + name + "("
+ v1 + ")");
}
try {
reg2_num = getRegNumberFromString(v2);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for instruction " + name + "("
+ v2 + ")");
}
LabelTableEntry lte = labels_table.get(v3);
if (lte == null) {
CodeAddress code_address = new CodeAddress(
SourcePosition.NO_INFO);
lte = new LabelTableEntry(code_address, false);
labels_table.put(v3, lte);
}
RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
RegisterSpec reg2_spec = RegisterSpec.make(reg2_num, Type.INT);
DalvInsn dalvInsn = new TargetInsn(insn.opcode,
createSourcePosition(), RegisterSpecList.make(reg1_spec,
reg2_spec), lte.code_address);
addInsn(dalvInsn);
} else if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_FIELD) == 0) {
int reg1_num = -1;
try {
reg1_num = getRegNumberFromString(v1);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for instruction " + name + "("
+ v1 + ")");
}
// TODO: is Type.INT suitable?
RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
String[] names = Utils.getClassFieldFromString(v2);
CstNat field_nat = new CstNat(new CstString(names[1]),
new CstString(v3));
Constant constant = new CstFieldRef(CstType.intern(Type
.internClassName(names[0])), field_nat);
DalvInsn dalvInsn = new CstInsn(insn.opcode,
createSourcePosition(), RegisterSpecList.make(reg1_spec),
constant);
addInsn(dalvInsn);
} else if (insn.args.compareToIgnoreCase(
DopInfo.ARG_REG_REG_TYPE) == 0) {
int reg1_num = -1, reg2_num = -1;
try {
reg1_num = getRegNumberFromString(v1);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for instruction " + name + "("
+ v1 + ")");
}
try {
reg2_num = getRegNumberFromString(v2);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for instruction " + name + "("
+ v2 + ")");
}
Type type = Type.internClassName(v3);
RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, type);
RegisterSpec reg2_spec = RegisterSpec.make(reg2_num, type);
Constant constant = CstType.intern(type);
DalvInsn dalvInsn = new CstInsn(insn.opcode,
createSourcePosition(), RegisterSpecList.make(reg1_spec,
reg2_spec), constant);
addInsn(dalvInsn);
} else {
throwDasmError("Bad arguments for instruction " + name + "(" + v1
+ ", " + v2 + ", " + v3 + ")");
}
}
/**
* Format: 22c (field@)
*/
void addOpcode(String name, String v1, String v2, String v3, String v4)
throws DasmError {
if (PARSER_DEBUG)
System.out.println("addOpcode(" + name + ", " + v1 + ", " + v2
+ ", " + v3 + ", " + v4 + ")");
createOutputFinisher();
DopInfo insn = DopInfo.get(name);
if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_REG_FIELD) == 0) {
int reg1_num = -1, reg2_num = -1;
try {
reg1_num = getRegNumberFromString(v1);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for instruction " + name + "("
+ v1 + ")");
}
try {
reg2_num = getRegNumberFromString(v2);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for instruction " + name + "("
+ v2 + ")");
}
// TODO: is Type.INT suitable?
RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
RegisterSpec reg2_spec = RegisterSpec.make(reg2_num, Type.INT);
String[] names = Utils.getClassFieldFromString(v3);
CstNat field_nat = new CstNat(new CstString(names[1]),
new CstString(v4));
Constant constant = new CstFieldRef(CstType.intern(Type
.internClassName(names[0])), field_nat);
DalvInsn dalvInsn = new CstInsn(insn.opcode,
createSourcePosition(), RegisterSpecList.make(reg1_spec,
reg2_spec), constant);
addInsn(dalvInsn);
} else if (insn.args.compareToIgnoreCase(
DopInfo.ARG_REGRANGE_TYPE) == 0) {
String regs[] = Utils.splitRegList(v1);
if (regs.length != 2)
throwDasmError("Bad arguments for instruction " + name + "("
+ v1 + ")");
int regC = -1, regN = -1;
try {
regC = getRegNumberFromString(regs[0]);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for instruction " + name + "("
+ v1 + ")");
}
try {
regN = getRegNumberFromString(regs[1]);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for instruction " + name + "("
+ v1 + ")");
}
if (regC >= regN)
throwDasmError("Bad arguments for instruction " + name + "("
+ v1 + ")");
int sz = regN - regC + 1;
RegisterSpecList reg_spec_list = new RegisterSpecList(sz);
for (int i = 0; i < sz; i++) {
reg_spec_list.set(i, RegisterSpec.make(regC + i, Type.INT));
}
Type type;
try {
type = Type.intern(v2);
} catch (IllegalArgumentException e) {
// in case of exception, try to intern type as a class name
// (Lclass_name;)
type = Type.internClassName(v2);
}
Constant constant = CstType.intern(type);
DalvInsn dalvInsn = new CstInsn(insn.opcode,
createSourcePosition(), reg_spec_list, constant);
addInsn(dalvInsn);
} else {
throwDasmError("Bad arguments for instruction " + name + "(" + v1
+ ", " + v2 + ", " + v3 + ", " + v4 + ")");
}
}
/**
* used for relative branch targets (ie $+5, $-12, ...) Format: relative 22t
*/
void addRelativeGoto(String name, String v1, String v2, int val)
throws DasmError {
if (PARSER_DEBUG)
System.out.println("addRelativeGoto(" + name + ", " + v1 + ", "
+ v2 + ", " + val + ")");
createOutputFinisher();
DopInfo insn = DopInfo.get(name);
if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_REG_ADDRESS) == 0) {
if (val == 0)
throwDasmError("Bad arguments for instruction " + name + "("
+ val + ")");
int reg1_num = -1, reg2_num = -1;
try {
reg1_num = getRegNumberFromString(v1);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for instruction " + name + "("
+ v1 + ")");
}
try {
reg2_num = getRegNumberFromString(v2);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for instruction " + name + "("
+ v2 + ")");
}
RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
RegisterSpec reg2_spec = RegisterSpec.make(reg2_num, Type.INT);
RegisterSpecList rsl = RegisterSpecList.make(reg1_spec, reg2_spec);
CodeAddress code_address = new CodeAddress(SourcePosition.NO_INFO);
if (val < 0) {
output_finisher.insert(current_insn_number + val, code_address);
current_insn_number++;
} else {
unprocessed_relative_goto_addr.put(current_insn_number + val,
code_address);
}
DalvInsn dalvInsn = new TargetInsn(insn.opcode,
createSourcePosition(), rsl, code_address);
addInsn(dalvInsn);
} else {
throwDasmError("Bad arguments for instruction " + name + "(" + val
+ ")");
}
}
/**
* used for instructions that take two word parameters (register name is
* treated as word) and one literal Format: 22b, 22s
*/
void addOpcode(String name, String v1, String v2, int v3) throws DasmError {
if (PARSER_DEBUG)
System.out.println("addOpcode(" + name + ", " + v1 + ", " + v2
+ ")");
createOutputFinisher();
DopInfo insn = DopInfo.get(name);
if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_REG_LITERAL) == 0) {
int reg1_num = -1, reg2_num = -1;
try {
reg1_num = getRegNumberFromString(v1);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for instruction " + name + "("
+ v1 + ")");
}
try {
reg2_num = getRegNumberFromString(v2);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for instruction " + name + "("
+ v2 + ")");
}
// TODO: is Type.INT suitable for any opcodes?
RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
RegisterSpec reg2_spec = RegisterSpec.make(reg2_num, Type.INT);
Constant constant = CstInteger.make(v3);
DalvInsn dalvInsn = new CstInsn(insn.opcode,
createSourcePosition(), RegisterSpecList.make(reg1_spec,
reg2_spec), constant);
addInsn(dalvInsn);
} else {
throwDasmError("Bad arguments for instruction " + name + "(" + v1
+ ", " + v2 + ", " + v3 + ")");
}
}
/**
* used for fill-array-data instruction Format: 31t fill-array-data
* instruction has the syntax: fill-array-data &lt;register&gt; &lt;type&gt;
* &lt;value1&gt; &lt;value2&gt; .... fill-array-data-end For example:
* fill-array-data v7 I 1 2 3 4 5 fill-array-data-end
*/
void newFillArrayData(String reg, String type) throws DasmError {
if (PARSER_DEBUG)
System.out.println("newFillArrayData(" + reg + ", " + type + ")");
try {
fill_data_reg = getRegNumberFromString(reg);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for fill-array-data (" + reg + ")");
}
fill_array_data_type = type;
fill_array_data_values = new Vector<Number>();
}
/**
* add new value to data block
*/
void addFillArrayData(Number num) throws DasmError {
if (PARSER_DEBUG) System.out.println("addFillArrayData(" + num + ")");
fill_array_data_values.add(num);
}
/**
* called by fill-array-data-end
*/
void endFillArrayData() throws DasmError {
if (PARSER_DEBUG) System.out.println("endFillArrayData");
int sz = fill_array_data_values.size();
ArrayList<Constant> values = new ArrayList<Constant>(sz);
CstType arrayType = CstType.intern(Type.intern("["
+ fill_array_data_type));
for (int i = 0; i < sz; i++) {
Constant constant;
Number num = fill_array_data_values.elementAt(i);
if (arrayType == CstType.LONG_ARRAY) {
constant = CstLong.make(num.longValue());
} else if (arrayType == CstType.FLOAT_ARRAY) {
constant = CstFloat
.make(Float.floatToIntBits(num.floatValue()));
} else if (arrayType == CstType.DOUBLE_ARRAY) {
constant = CstDouble.make(Double.doubleToLongBits(num
.doubleValue()));
} else if (arrayType == CstType.BOOLEAN_ARRAY) {
constant = CstBoolean.make(num.intValue());
} else if (arrayType == CstType.BYTE_ARRAY) {
constant = CstByte.make(num.intValue());
} else if (arrayType == CstType.CHAR_ARRAY) {
constant = CstChar.make(num.intValue());
} else if (arrayType == CstType.SHORT_ARRAY) {
constant = CstShort.make(num.intValue());
} else {
constant = CstInteger.make(num.intValue());
}
values.add(constant);
}
CodeAddress insn_addr = new CodeAddress(createSourcePosition());
CodeAddress data_addr = new CodeAddress(SourcePosition.NO_INFO);
DalvInsn dalvInsn = new TargetInsn(Dops.FILL_ARRAY_DATA,
createSourcePosition(), RegisterSpecList
.make(RegisterSpec.make(fill_data_reg, Type
.intern(fill_array_data_type))), data_addr);
OddSpacer spacer = new OddSpacer(SourcePosition.NO_INFO);
ArrayData array_data = new ArrayData(SourcePosition.NO_INFO, insn_addr,
values, arrayType);
addInsn(insn_addr);
addInsn(dalvInsn);
data_blocks.add(spacer);
data_blocks.add(data_addr);
data_blocks.add(array_data);
fill_array_data_values = null;
fill_array_data_type = null;
}
/**
* used for packed-switch instruction Format: 31t packed-switch instruction
* has the syntax: packed-switch &lt;register&gt; &lt;lowest&gt;
* &lt;label1&gt; &lt;label2&gt; .... packed-switch-end For example:
* packed-switch v3, -1 Label9 Label6 Label6 Label12 Label12
* packed-switch-end
*/
void newPackedSwitch(String reg, int first_key) throws DasmError {
if (PARSER_DEBUG)
System.out.println("newPackedSwitch(" + reg + ", " + first_key
+ ")");
try {
switch_reg = getRegNumberFromString(reg);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for packed-switch (" + reg + ")");
}
packed_switch_first_key = first_key;
packed_switch_current_key = 0;
switch_targets = new Vector<Object>();
switch_keys = new IntList();
}
/**
* add new target to packed-switch
*/
void addPackedSwitchData(String target) throws DasmError {
if (PARSER_DEBUG)
System.out.println("addPackedSwitchData(" + target + ")");
switch_targets.add(target);
switch_keys.add(packed_switch_first_key + packed_switch_current_key);
packed_switch_current_key++;
}
/**
* add new target to packed-switch
*/
void addPackedSwitchData(int target) throws DasmError {
if (PARSER_DEBUG)
System.out.println("addPackedSwitchData(" + target + ")");
switch_targets.add(new Integer(target));
switch_keys.add(packed_switch_first_key + packed_switch_current_key);
packed_switch_current_key++;
}
/**
* used for sparse-switch instruction Format: 31t sparse-switch instruction
* has the syntax: sparse-switch &lt;register&gt; &lt;lowest&gt;
* &lt;int1&gt; : &lt;label1&gt; &lt;int2&gt; : &lt;label2&gt; ....
* sparse-switch-end For example: sparse-switch v3 -1 : Label9 10 : Label12
* 15 : Label12 sparse-switch-end
*/
void newSparseSwitch(String reg) throws DasmError {
if (PARSER_DEBUG) System.out.println("newSparseSwitch(" + reg + ")");
try {
switch_reg = getRegNumberFromString(reg);
} catch (IllegalArgumentException e) {
throwDasmError("Bad arguments for sparse-switch (" + reg + ")");
}
switch_targets = new Vector<Object>();
switch_keys = new IntList();
}
/**
* add new target to sparse-switch
*/
void addSparseSwitchData(int key, String target) throws DasmError {
if (PARSER_DEBUG)
System.out.println("addSparseSwitchData(" + key + ", " + target
+ ")");
switch_targets.add(target);
switch_keys.add(key);
}
/**
* add new target to sparse-switch
*/
void addSparseSwitchData(int key, int target) throws DasmError {
if (PARSER_DEBUG)
System.out.println("addSparseSwitchData(" + key + ", " + target
+ ")");
switch_targets.add(new Integer(target));
switch_keys.add(key);
}
/**
* called by sparse-switch-end or packed-switch-end
*/
void endSwitch() throws DasmError {
if (PARSER_DEBUG) System.out.println("endSwitch");
int sz = switch_targets.size();
CodeAddress targets[] = new CodeAddress[sz];
for (int i = 0; i < sz; i++) {
Object o = switch_targets.elementAt(i);
CodeAddress addr;
if (o instanceof String) {
String t = (String) o;
LabelTableEntry lte = labels_table.get(t);
if (lte == null) {
CodeAddress code_address = new CodeAddress(
SourcePosition.NO_INFO);
lte = new LabelTableEntry(code_address, false);
labels_table.put(t, lte);
}
addr = lte.code_address;
} else {
Integer t = (Integer) o;
addr = new CodeAddress(SourcePosition.NO_INFO);
if (t < 0) {
output_finisher.insert(current_insn_number + t, addr);
current_insn_number++;
} else {
unprocessed_relative_goto_addr.put(current_insn_number + t,
addr);
}
}
targets[i] = addr;
}
CodeAddress insn_addr = new CodeAddress(createSourcePosition());
CodeAddress data_addr = new CodeAddress(SourcePosition.NO_INFO);
OddSpacer spacer = new OddSpacer(SourcePosition.NO_INFO);
SwitchData switch_data = new SwitchData(SourcePosition.NO_INFO,
insn_addr, switch_keys, targets);
DalvInsn dalvInsn = new TargetInsn(switch_data.isPacked()
? Dops.PACKED_SWITCH : Dops.SPARSE_SWITCH,
createSourcePosition(), RegisterSpecList.make(RegisterSpec
.make(switch_reg, Type.INT)), data_addr);
addInsn(insn_addr);
addInsn(dalvInsn);
data_blocks.add(spacer);
data_blocks.add(data_addr);
data_blocks.add(switch_data);
switch_targets = null;
switch_keys = null;
}
/*
* ========================================================================
* === UTILITY METHODS
* ========================================================================
*/
/**
* Creates instance of SourcePosition for current line
*/
protected SourcePosition createSourcePosition() {
return new SourcePosition(new CstString(filename), -1, line_num);
}
/**
* Creates TypeList from list of types
*/
protected TypeList createTypeListFromStrings(Vector<String> strings) {
StdTypeList tl;
if (strings.size() == 0)
tl = StdTypeList.EMPTY;
else {
int sz = strings.size();
tl = new StdTypeList(sz);
for (int i = 0; i < sz; i++) {
tl.set(i, Type.internClassName(strings.elementAt(i)));
}
}
return tl;
}
/**
* Creates processor of instruction list.
*/
private void createOutputFinisher() {
if (output_finisher == null)
output_finisher = new OutputFinisher(dexOptions, 5, regs_count);
}
/**
* Returns register number from "vX" string.
*/
private int getRegNumberFromString(String val)
throws IllegalArgumentException {
int reg_num;
int l = RegisterSpec.PREFIX.length();
if (val.length() <= l
|| val.substring(0, l).compareToIgnoreCase(
RegisterSpec.PREFIX) != 0)
throw new IllegalArgumentException("Wrong register name prefix");
try {
reg_num = Integer.parseInt(val.substring(l));
} catch (Exception e) {
throw new IllegalArgumentException("Wrong register name");
}
return reg_num;
}
/**
* Adds new instruction to instruction list.
*/
private void addInsn(DalvInsn insn) {
createOutputFinisher();
CodeAddress code_address = unprocessed_relative_goto_addr
.get(current_insn_number);
if (code_address != null) {
output_finisher.add(code_address);
unprocessed_relative_goto_addr.remove(current_insn_number);
current_insn_number++;
}
output_finisher.add(insn);
current_insn_number++;
}
/*
* ========================================================================
* === READER and WRITER
* ========================================================================
*/
/**
* Writes the binary data for the class represented by this ClassFile object
* to the specified output stream, using the Java Class File format. Throws
* either an IOException or a dasmError if something goes wrong.
*/
public void write(OutputStream outp, FileWriter human_readable)
throws IOException, DasmError {
dexFile.writeTo(outp, human_readable, true);
}
/**
* Parses a .d file, converting it internally into a binary representation.
* If something goes wrong, this throws one of an IOException, or a
* dasmError, or one of a few other exceptions.
*
* @param input
* is the stream containing the Dalvik assembly code for the
* class.
* @param name
* is the name of the stream. This name will be concatenated to
* error messages printed to System.err.
* @param numberLines
* true if you want DAsm to generate line numbers automatically,
* based on the assembly source, or false if you are using the
* ".line" directive and don't want DAsm to help out.
*/
public void readD(Reader input, String name, boolean numberLines)
throws IOException, Exception {
// TODO: numberLines?
errors = 0;
filename = name;
source_name = name;
class_header = false;
classDef = null;
dexFile = new DexFile();
scanner = new Scanner(input);
parser parse_obj = new parser(this, scanner);
if (PARSER_DEBUG) {
// for debugging
parse_obj.debug_parse();
} else {
parse_obj.parse();
}
}
}