mirror of
https://github.com/revanced/smali.git
synced 2025-05-04 16:44:25 +02:00
Add initial support for allowing assembly of odex instructions
Initially, only throw-verification-error is supported
This commit is contained in:
parent
bbe539f2d2
commit
94e5a39ad2
@ -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:
|
||||||
|
@ -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;}
|
||||||
{
|
{
|
||||||
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT20bc.text);
|
if (!allowOdex) {
|
||||||
|
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
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user