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

View File

@ -93,6 +93,7 @@ tokens {
I_STATEMENT_FORMAT11n; I_STATEMENT_FORMAT11n;
I_STATEMENT_FORMAT11x; I_STATEMENT_FORMAT11x;
I_STATEMENT_FORMAT12x; I_STATEMENT_FORMAT12x;
I_STATEMENT_FORMAT20bc;
I_STATEMENT_FORMAT20t; I_STATEMENT_FORMAT20t;
I_STATEMENT_FORMAT21c_TYPE; I_STATEMENT_FORMAT21c_TYPE;
I_STATEMENT_FORMAT21c_FIELD; I_STATEMENT_FORMAT21c_FIELD;
@ -137,11 +138,16 @@ import org.jf.dexlib.Code.Format.*;
@members { @members {
private boolean verboseErrors = false; private boolean verboseErrors = false;
private boolean allowOdex = false;
public void setVerboseErrors(boolean verboseErrors) { public void setVerboseErrors(boolean verboseErrors) {
this.verboseErrors = verboseErrors; this.verboseErrors = verboseErrors;
} }
public void setAllowOdex(boolean allowOdex) {
this.allowOdex = allowOdex;
}
public String getErrorMessage(RecognitionException e, public String getErrorMessage(RecognitionException e,
String[] tokenNames) { String[] tokenNames) {
@ -594,6 +600,9 @@ register_list
register_range register_range
: REGISTER (DOTDOT REGISTER)? -> ^(I_REGISTER_RANGE[$start, "I_REGISTER_RANGE"] REGISTER REGISTER?); : 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
: 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 : 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); -> ^(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;} instruction_format12x REGISTER COMMA REGISTER {$size = Format.Format12x.size;}
-> ^(I_STATEMENT_FORMAT12x[$start, "I_STATEMENT_FORMAT12x"] instruction_format12x REGISTER REGISTER) -> ^(I_STATEMENT_FORMAT12x[$start, "I_STATEMENT_FORMAT12x"] instruction_format12x REGISTER REGISTER)
| //e.g. throw-verification-error generic-error, Lsome/class; | //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); throwOdexedInstructionException(input, $INSTRUCTION_FORMAT20bc.text);
} }
}
-> ^(I_STATEMENT_FORMAT20bc INSTRUCTION_FORMAT20bc VERIFICATION_ERROR_TYPE verification_error_reference)
| //e.g. goto/16 endloop: | //e.g. goto/16 endloop:
INSTRUCTION_FORMAT20t label_ref_or_offset {$size = Format.Format20t.size;} INSTRUCTION_FORMAT20t label_ref_or_offset {$size = Format.Format20t.size;}
-> ^(I_STATEMENT_FORMAT20t[$start, "I_STATEMENT_FORMAT20t"] INSTRUCTION_FORMAT20t label_ref_or_offset) -> ^(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!" | //e.g. const-string v1 "Hello World!"
INSTRUCTION_FORMAT21c_STRING REGISTER COMMA STRING_LITERAL {$size = Format.Format21c.size;} 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) -> ^(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;} 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) -> ^(I_STATEMENT_FORMAT21c_TYPE[$start, "I_STATEMENT_FORMAT21c"] INSTRUCTION_FORMAT21c_TYPE REGISTER reference_type_descriptor)
| //e.g. const/high16 v1, 1234 | //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] instruction[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters]
: //e.g. goto endloop: : //e.g. goto endloop:
{$outRegisters = 0;} {$outRegisters = 0;}
@ -959,6 +979,16 @@ instruction[int totalMethodRegisters, int methodParameterRegisters, List<Instruc
$instructions.add(new Instruction12x(opcode, regA, regB)); $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: | //e.g. goto/16 endloop:
^(I_STATEMENT_FORMAT20t INSTRUCTION_FORMAT20t offset_or_label) ^(I_STATEMENT_FORMAT20t INSTRUCTION_FORMAT20t offset_or_label)
{ {

View File

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