Add initial support for allowing assembly of odex instructions

Initially, only throw-verification-error is supported
This commit is contained in:
Ben Gruver 2011-10-09 22:33:37 -04:00
parent bbe539f2d2
commit 94e5a39ad2
4 changed files with 73 additions and 5 deletions

View File

@ -28,6 +28,8 @@
package org.jf.dexlib.Code;
import java.util.HashMap;
public enum VerificationErrorType {
None(0, "no-error"),
Generic(1, "generic-error"),
@ -40,6 +42,16 @@ public enum VerificationErrorType {
ClassChange(8, "class-change-error"),
Instantiation(9, "instantiation-error");
private static HashMap<String, VerificationErrorType> verificationErrorTypesByName;
static {
verificationErrorTypesByName = new HashMap<String, VerificationErrorType>();
for (VerificationErrorType verificationErrorType: VerificationErrorType.values()) {
verificationErrorTypesByName.put(verificationErrorType.getName(), verificationErrorType);
}
}
private int value;
private String name;
private VerificationErrorType(int value, String name) {
@ -55,6 +67,10 @@ public enum VerificationErrorType {
return name;
}
public static VerificationErrorType fromString(String validationErrorType) {
return verificationErrorTypesByName.get(validationErrorType);
}
public static VerificationErrorType getValidationErrorType(int validationErrorType) {
switch (validationErrorType) {
case 0:

View File

@ -93,6 +93,7 @@ tokens {
I_STATEMENT_FORMAT11n;
I_STATEMENT_FORMAT11x;
I_STATEMENT_FORMAT12x;
I_STATEMENT_FORMAT20bc;
I_STATEMENT_FORMAT20t;
I_STATEMENT_FORMAT21c_TYPE;
I_STATEMENT_FORMAT21c_FIELD;
@ -137,11 +138,16 @@ import org.jf.dexlib.Code.Format.*;
@members {
private boolean verboseErrors = false;
private boolean allowOdex = false;
public void setVerboseErrors(boolean verboseErrors) {
this.verboseErrors = verboseErrors;
}
public void setAllowOdex(boolean allowOdex) {
this.allowOdex = allowOdex;
}
public String getErrorMessage(RecognitionException e,
String[] tokenNames) {
@ -594,6 +600,9 @@ register_list
register_range
: REGISTER (DOTDOT REGISTER)? -> ^(I_REGISTER_RANGE[$start, "I_REGISTER_RANGE"] REGISTER REGISTER?);
verification_error_reference
: CLASS_DESCRIPTOR | fully_qualified_field | fully_qualified_method;
catch_directive
: CATCH_DIRECTIVE nonvoid_type_descriptor OPEN_BRACE from=label_ref_or_offset DOTDOT to=label_ref_or_offset CLOSE_BRACE using=label_ref_or_offset
-> ^(I_CATCH[$start, "I_CATCH"] I_ADDRESS[$start, Integer.toString($method::currentAddress)] nonvoid_type_descriptor $from $to $using);
@ -686,10 +695,13 @@ instruction returns [int size]
instruction_format12x REGISTER COMMA REGISTER {$size = Format.Format12x.size;}
-> ^(I_STATEMENT_FORMAT12x[$start, "I_STATEMENT_FORMAT12x"] instruction_format12x REGISTER REGISTER)
| //e.g. throw-verification-error generic-error, Lsome/class;
INSTRUCTION_FORMAT20bc VERIFICATION_ERROR_TYPE COMMA (CLASS_DESCRIPTOR | fully_qualified_field | fully_qualified_method)
INSTRUCTION_FORMAT20bc VERIFICATION_ERROR_TYPE COMMA verification_error_reference {$size += Format.Format20bc.size;}
{
if (!allowOdex) {
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT20bc.text);
}
}
-> ^(I_STATEMENT_FORMAT20bc INSTRUCTION_FORMAT20bc VERIFICATION_ERROR_TYPE verification_error_reference)
| //e.g. goto/16 endloop:
INSTRUCTION_FORMAT20t label_ref_or_offset {$size = Format.Format20t.size;}
-> ^(I_STATEMENT_FORMAT20t[$start, "I_STATEMENT_FORMAT20t"] INSTRUCTION_FORMAT20t label_ref_or_offset)
@ -704,7 +716,7 @@ instruction returns [int size]
| //e.g. const-string v1 "Hello World!"
INSTRUCTION_FORMAT21c_STRING REGISTER COMMA STRING_LITERAL {$size = Format.Format21c.size;}
-> ^(I_STATEMENT_FORMAT21c_STRING[$start, "I_STATEMENT_FORMAT21c_STRING"] INSTRUCTION_FORMAT21c_STRING REGISTER STRING_LITERAL)
| //e.g. const-class v2 org/jf/HelloWorld2/HelloWorld2
| //e.g. const-class v2 Lorg/jf/HelloWorld2/HelloWorld2;
INSTRUCTION_FORMAT21c_TYPE REGISTER COMMA reference_type_descriptor {$size = Format.Format21c.size;}
-> ^(I_STATEMENT_FORMAT21c_TYPE[$start, "I_STATEMENT_FORMAT21c"] INSTRUCTION_FORMAT21c_TYPE REGISTER reference_type_descriptor)
| //e.g. const/high16 v1, 1234

View File

@ -914,6 +914,26 @@ register_range[int totalMethodRegisters, int methodParameterRegisters] returns[i
}
;
verification_error_reference returns[Item item]
: CLASS_DESCRIPTOR
{
$item = TypeIdItem.internTypeIdItem(dexFile, $start.getText());
}
| fully_qualified_field
{
$item = $fully_qualified_field.fieldIdItem;
}
| fully_qualified_method
{
$item = $fully_qualified_method.methodIdItem;
};
verification_error_type returns[VerificationErrorType verificationErrorType]
: VERIFICATION_ERROR_TYPE
{
$verificationErrorType = VerificationErrorType.fromString($VERIFICATION_ERROR_TYPE.text);
};
instruction[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
: //e.g. goto endloop:
{$outRegisters = 0;}
@ -959,6 +979,16 @@ instruction[int totalMethodRegisters, int methodParameterRegisters, List<Instruc
$instructions.add(new Instruction12x(opcode, regA, regB));
}
| //e.g. throw-verification-error generic-error, Lsome/class;
^(I_STATEMENT_FORMAT20bc INSTRUCTION_FORMAT20bc verification_error_type verification_error_reference)
{
Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT20bc.text);
VerificationErrorType verificationErrorType = $verification_error_type.verificationErrorType;
Item referencedItem = $verification_error_reference.item;
$instructions.add(new Instruction20bc(opcode, verificationErrorType, referencedItem));
}
| //e.g. goto/16 endloop:
^(I_STATEMENT_FORMAT20t INSTRUCTION_FORMAT20t offset_or_label)
{

View File

@ -98,6 +98,7 @@ public class main {
return;
}
boolean allowOdex = false;
boolean sort = false;
boolean fixStringConst = true;
boolean fixGoto = true;
@ -132,6 +133,9 @@ public class main {
case 'o':
outputDexFile = commandLine.getOptionValue("o");
break;
case 'x':
allowOdex = true;
break;
case 'D':
dumpFileName = commandLine.getOptionValue("D", outputDexFile + ".dump");
break;
@ -185,7 +189,7 @@ public class main {
boolean errors = false;
for (File file: filesToProcess) {
if (!assembleSmaliFile(file, dexFile, verboseErrors, oldLexer, printTokens)) {
if (!assembleSmaliFile(file, dexFile, verboseErrors, oldLexer, printTokens, allowOdex)) {
errors = true;
}
}
@ -262,7 +266,7 @@ public class main {
}
private static boolean assembleSmaliFile(File smaliFile, DexFile dexFile, boolean verboseErrors, boolean oldLexer,
boolean printTokens)
boolean printTokens, boolean allowOdex)
throws Exception {
CommonTokenStream tokens;
@ -300,6 +304,7 @@ public class main {
smaliParser parser = new smaliParser(tokens);
parser.setVerboseErrors(verboseErrors);
parser.setAllowOdex(allowOdex);
smaliParser.smali_file_return result = parser.smali_file();
@ -374,6 +379,10 @@ public class main {
.withArgName("FILE")
.create("o");
Option allowOdexOption = OptionBuilder.withLongOpt("allow-odex-instructions")
.withDescription("allow odex instructions to be compiled into the dex file")
.create("x");
Option dumpOption = OptionBuilder.withLongOpt("dump-to")
.withDescription("additionally writes a dump of written dex file to FILE (<dexfile>.dump by default)")
.hasOptionalArg()
@ -407,6 +416,7 @@ public class main {
basicOptions.addOption(versionOption);
basicOptions.addOption(helpOption);
basicOptions.addOption(outputOption);
basicOptions.addOption(allowOdexOption);
debugOptions.addOption(dumpOption);
debugOptions.addOption(sortOption);