mirror of
https://github.com/revanced/smali.git
synced 2025-05-18 23:17:05 +02:00
Changed the implementation details for the sparse-switch and packed-switch pseudo opcodes to use an int[], instead of a List<Integer>.
Also added additional validity checking to SparseSwitchData.make() git-svn-id: https://smali.googlecode.com/svn/trunk@36 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
parent
061ba3a71c
commit
8a116bba98
@ -54,9 +54,11 @@ tokens {
|
|||||||
I_ARRAY_ELEMENTS;
|
I_ARRAY_ELEMENTS;
|
||||||
I_PACKED_SWITCH_START_KEY;
|
I_PACKED_SWITCH_START_KEY;
|
||||||
I_PACKED_SWITCH_BASE_OFFSET;
|
I_PACKED_SWITCH_BASE_OFFSET;
|
||||||
|
I_PACKED_SWITCH_TARGET_COUNT;
|
||||||
I_PACKED_SWITCH_TARGETS;
|
I_PACKED_SWITCH_TARGETS;
|
||||||
I_SPARSE_SWITCH_BASE_OFFSET;
|
I_SPARSE_SWITCH_BASE_OFFSET;
|
||||||
I_SPARSE_SWITCH_KEYS;
|
I_SPARSE_SWITCH_KEYS;
|
||||||
|
I_SPARSE_SWITCH_TARGET_COUNT;
|
||||||
I_SPARSE_SWITCH_TARGETS;
|
I_SPARSE_SWITCH_TARGETS;
|
||||||
I_STATEMENTS;
|
I_STATEMENTS;
|
||||||
I_STATEMENT_FORMAT10t;
|
I_STATEMENT_FORMAT10t;
|
||||||
@ -261,6 +263,7 @@ instruction returns [int size]
|
|||||||
|
|
|
|
||||||
PACKED_SWITCH_DIRECTIVE
|
PACKED_SWITCH_DIRECTIVE
|
||||||
{
|
{
|
||||||
|
int targetCount = 0;
|
||||||
if (($statements::currentAddress \% 2) != 0) {
|
if (($statements::currentAddress \% 2) != 0) {
|
||||||
needsNop = true;
|
needsNop = true;
|
||||||
$size = 2;
|
$size = 2;
|
||||||
@ -273,18 +276,28 @@ instruction returns [int size]
|
|||||||
|
|
||||||
fixed_32bit_literal
|
fixed_32bit_literal
|
||||||
|
|
||||||
(switch_target += offset_or_label {$size+=4;})*
|
(switch_target += offset_or_label {$size+=4; targetCount++;})*
|
||||||
|
|
||||||
END_PACKED_SWITCH_DIRECTIVE {$size = $size + 8;}
|
END_PACKED_SWITCH_DIRECTIVE {$size = $size + 8;}
|
||||||
|
|
||||||
/*add a nop statement before this if needed to force the correct alignment*/
|
/*add a nop statement before this if needed to force the correct alignment*/
|
||||||
-> {needsNop}? ^(I_STATEMENT_FORMAT10x[$start, "I_STATEMENT_FORMAT10x"] INSTRUCTION_FORMAT10x[$start, "nop"])
|
-> {needsNop}? ^(I_STATEMENT_FORMAT10x[$start, "I_STATEMENT_FORMAT10x"] INSTRUCTION_FORMAT10x[$start, "nop"])
|
||||||
^(I_STATEMENT_PACKED_SWITCH ^(I_PACKED_SWITCH_BASE_OFFSET $base_offset) ^(I_PACKED_SWITCH_START_KEY fixed_32bit_literal) ^(I_PACKED_SWITCH_TARGETS $switch_target*))
|
^(I_STATEMENT_PACKED_SWITCH[$start, "I_STATEMENT_PACKED_SWITCH"]
|
||||||
-> ^(I_STATEMENT_PACKED_SWITCH ^(I_PACKED_SWITCH_BASE_OFFSET $base_offset) ^(I_PACKED_SWITCH_START_KEY fixed_32bit_literal) ^(I_PACKED_SWITCH_TARGETS $switch_target*))
|
^(I_PACKED_SWITCH_BASE_OFFSET[$start, "I_PACKED_SWITCH_BASE_OFFSET"] $base_offset)
|
||||||
|
^(I_PACKED_SWITCH_START_KEY[$start, "I_PACKED_SWITCH_START_KEY"] fixed_32bit_literal)
|
||||||
|
^(I_PACKED_SWITCH_TARGETS[$start, "I_PACKED_SWITCH_TARGETS"] I_PACKED_SWITCH_TARGET_COUNT[$start, Integer.toString(targetCount)] $switch_target*)
|
||||||
|
)
|
||||||
|
|
||||||
|
-> ^(I_STATEMENT_PACKED_SWITCH[$start, "I_STATEMENT_PACKED_SWITCH"]
|
||||||
|
^(I_PACKED_SWITCH_BASE_OFFSET[$start, "I_PACKED_SWITCH_BASE_OFFSET"] $base_offset)
|
||||||
|
^(I_PACKED_SWITCH_START_KEY[$start, "I_PACKED_SWITCH_START_KEY"] fixed_32bit_literal)
|
||||||
|
^(I_PACKED_SWITCH_TARGETS[$start, "I_PACKED_SWITCH_TARGETS"] I_PACKED_SWITCH_TARGET_COUNT[$start, Integer.toString(targetCount)] $switch_target*)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
|
|
||||||
SPARSE_SWITCH_DIRECTIVE
|
SPARSE_SWITCH_DIRECTIVE
|
||||||
{
|
{
|
||||||
|
int targetCount = 0;
|
||||||
if (($statements::currentAddress \% 2) != 0) {
|
if (($statements::currentAddress \% 2) != 0) {
|
||||||
needsNop = true;
|
needsNop = true;
|
||||||
$size = 2;
|
$size = 2;
|
||||||
@ -295,15 +308,22 @@ instruction returns [int size]
|
|||||||
|
|
||||||
base_offset = offset_or_label
|
base_offset = offset_or_label
|
||||||
|
|
||||||
(fixed_32bit_literal switch_target += offset_or_label {$size += 8;})*
|
(fixed_32bit_literal switch_target += offset_or_label {$size += 8; targetCount++;})*
|
||||||
|
|
||||||
END_SPARSE_SWITCH_DIRECTIVE {$size = $size + 4;}
|
END_SPARSE_SWITCH_DIRECTIVE {$size = $size + 4;}
|
||||||
|
|
||||||
/*add a nop statement before this if needed to force the correct alignment*/
|
/*add a nop statement before this if needed to force the correct alignment*/
|
||||||
-> {needsNop}? ^(I_STATEMENT_FORMAT10x[$start, "I_STATEMENT_FORMAT10x"] INSTRUCTION_FORMAT10x[$start, "nop"])
|
-> {needsNop}? ^(I_STATEMENT_FORMAT10x[$start, "I_STATEMENT_FORMAT10x"] INSTRUCTION_FORMAT10x[$start, "nop"])
|
||||||
^(I_STATEMENT_SPARSE_SWITCH ^(I_SPARSE_SWITCH_BASE_OFFSET $base_offset) ^(I_SPARSE_SWITCH_KEYS fixed_32bit_literal*) ^(I_SPARSE_SWITCH_TARGETS $switch_target*))
|
^(I_STATEMENT_SPARSE_SWITCH[$start, "I_STATEMENT_SPARSE_SWITCH"]
|
||||||
-> ^(I_STATEMENT_SPARSE_SWITCH ^(I_SPARSE_SWITCH_BASE_OFFSET $base_offset) ^(I_SPARSE_SWITCH_KEYS fixed_32bit_literal*) ^(I_SPARSE_SWITCH_TARGETS $switch_target*))
|
^(I_SPARSE_SWITCH_BASE_OFFSET[$start, "I_SPARSE_SWITCH_BASE_OFFSET"] $base_offset)
|
||||||
|
I_SPARSE_SWITCH_TARGET_COUNT[$start, Integer.toString(targetCount)]
|
||||||
|
^(I_SPARSE_SWITCH_KEYS[$start, "I_SPARSE_SWITCH_KEYS"] fixed_32bit_literal*)
|
||||||
|
^(I_SPARSE_SWITCH_TARGETS $switch_target*))
|
||||||
|
-> ^(I_STATEMENT_SPARSE_SWITCH[$start, "I_STATEMENT_SPARSE_SWITCH"]
|
||||||
|
^(I_SPARSE_SWITCH_BASE_OFFSET[$start, "I_SPARSE_SWITCH_BASE_OFFSET"] $base_offset)
|
||||||
|
I_SPARSE_SWITCH_TARGET_COUNT[$start, Integer.toString(targetCount)]
|
||||||
|
^(I_SPARSE_SWITCH_KEYS[$start, "I_SPARSE_SWITCH_KEYS"] fixed_32bit_literal*)
|
||||||
|
^(I_SPARSE_SWITCH_TARGETS $switch_target*))
|
||||||
;
|
;
|
||||||
|
|
||||||
offset_or_label
|
offset_or_label
|
||||||
|
@ -213,30 +213,49 @@ array_elements returns[List<byte[\]> values]
|
|||||||
$values.add($fixed_size_literal.value);
|
$values.add($fixed_size_literal.value);
|
||||||
})*);
|
})*);
|
||||||
|
|
||||||
packed_switch_targets[int baseOffset] returns[List<Integer> targets]
|
packed_switch_target_count returns[int targetCount]
|
||||||
: {$targets = new ArrayList<Integer>();}
|
: I_PACKED_SWITCH_TARGET_COUNT {$targetCount = Integer.parseInt($I_PACKED_SWITCH_TARGET_COUNT.text);};
|
||||||
|
|
||||||
|
packed_switch_targets[int baseOffset] returns[int[\] targets]
|
||||||
|
:
|
||||||
^(I_PACKED_SWITCH_TARGETS
|
^(I_PACKED_SWITCH_TARGETS
|
||||||
|
packed_switch_target_count
|
||||||
|
{
|
||||||
|
int targetCount = $packed_switch_target_count.targetCount;
|
||||||
|
$targets = new int[targetCount];
|
||||||
|
int targetsPosition = 0;
|
||||||
|
}
|
||||||
|
|
||||||
(offset_or_label
|
(offset_or_label
|
||||||
{
|
{
|
||||||
$targets.add($offset_or_label.offsetValue - $baseOffset);
|
targets[targetsPosition++] = $offset_or_label.offsetValue - $baseOffset;
|
||||||
})*
|
})*
|
||||||
);
|
);
|
||||||
|
|
||||||
sparse_switch_keys returns[List<Integer> keys]
|
sparse_switch_target_count returns[int targetCount]
|
||||||
: {$keys = new ArrayList<Integer>();}
|
: I_SPARSE_SWITCH_TARGET_COUNT {$targetCount = Integer.parseInt($I_SPARSE_SWITCH_TARGET_COUNT.text);};
|
||||||
|
|
||||||
|
sparse_switch_keys[int targetCount] returns[int[\] keys]
|
||||||
|
: {
|
||||||
|
$keys = new int[$targetCount];
|
||||||
|
int keysPosition = 0;
|
||||||
|
}
|
||||||
^(I_SPARSE_SWITCH_KEYS
|
^(I_SPARSE_SWITCH_KEYS
|
||||||
(fixed_32bit_literal
|
(fixed_32bit_literal
|
||||||
{
|
{
|
||||||
$keys.add($fixed_32bit_literal.value);
|
$keys[keysPosition++] = $fixed_32bit_literal.value;
|
||||||
})*
|
})*
|
||||||
);
|
);
|
||||||
|
|
||||||
sparse_switch_targets[int baseOffset] returns[List<Integer> targets]
|
sparse_switch_targets[int baseOffset, int targetCount] returns[int[\] targets]
|
||||||
: {$targets = new ArrayList<Integer>();}
|
: {
|
||||||
|
$targets = new int[$targetCount];
|
||||||
|
int targetsPosition = 0;
|
||||||
|
}
|
||||||
^(I_SPARSE_SWITCH_TARGETS
|
^(I_SPARSE_SWITCH_TARGETS
|
||||||
(offset_or_label
|
(offset_or_label
|
||||||
{
|
{
|
||||||
$targets.add($offset_or_label.offsetValue - $baseOffset);
|
$targets[targetsPosition++] = $offset_or_label.offsetValue - $baseOffset;
|
||||||
})*
|
})*
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -703,15 +722,15 @@ instruction returns[Instruction instruction]
|
|||||||
^(I_STATEMENT_PACKED_SWITCH ^(I_PACKED_SWITCH_BASE_OFFSET base_offset=offset_or_label) ^(I_PACKED_SWITCH_START_KEY fixed_32bit_literal) packed_switch_targets[$base_offset.offsetValue])
|
^(I_STATEMENT_PACKED_SWITCH ^(I_PACKED_SWITCH_BASE_OFFSET base_offset=offset_or_label) ^(I_PACKED_SWITCH_START_KEY fixed_32bit_literal) packed_switch_targets[$base_offset.offsetValue])
|
||||||
{
|
{
|
||||||
int startKey = $fixed_32bit_literal.value;
|
int startKey = $fixed_32bit_literal.value;
|
||||||
List<Integer> targets = $packed_switch_targets.targets;
|
int[] targets = $packed_switch_targets.targets;
|
||||||
|
|
||||||
$instruction = PackedSwitchData.make(dexFile, startKey, targets);
|
$instruction = PackedSwitchData.make(dexFile, startKey, targets);
|
||||||
}
|
}
|
||||||
|
|
|
|
||||||
^(I_STATEMENT_SPARSE_SWITCH ^(I_SPARSE_SWITCH_BASE_OFFSET base_offset=offset_or_label) sparse_switch_keys sparse_switch_targets[$base_offset.offsetValue])
|
^(I_STATEMENT_SPARSE_SWITCH ^(I_SPARSE_SWITCH_BASE_OFFSET base_offset=offset_or_label) sparse_switch_target_count sparse_switch_keys[$sparse_switch_target_count.targetCount] sparse_switch_targets[$base_offset.offsetValue, $sparse_switch_target_count.targetCount])
|
||||||
{
|
{
|
||||||
List<Integer> keys = $sparse_switch_keys.keys;
|
int[] keys = $sparse_switch_keys.keys;
|
||||||
List<Integer> targets = $sparse_switch_targets.targets;
|
int[] targets = $sparse_switch_targets.targets;
|
||||||
|
|
||||||
$instruction = SparseSwitchData.make(dexFile, keys, targets);
|
$instruction = SparseSwitchData.make(dexFile, keys, targets);
|
||||||
}
|
}
|
||||||
|
@ -36,16 +36,15 @@ import java.util.List;
|
|||||||
|
|
||||||
public class PackedSwitchData
|
public class PackedSwitchData
|
||||||
{
|
{
|
||||||
//TODO: switch from List<Integer> to int[]
|
public static Instruction make(DexFile dexFile, int firstKey, int[] targets) {
|
||||||
public static Instruction make(DexFile dexFile, int firstKey, List<Integer> targets) {
|
|
||||||
byte[] bytes;
|
byte[] bytes;
|
||||||
|
|
||||||
if (targets.size() > 0xFFFF) {
|
if (targets.length > 0xFFFF) {
|
||||||
throw new RuntimeException("The packed-switch data contains too many elements. " +
|
throw new RuntimeException("The packed-switch data contains too many elements. " +
|
||||||
"The maximum number of switch elements is 65535");
|
"The maximum number of switch elements is 65535");
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes = new byte[targets.size() * 4 + 8];
|
bytes = new byte[targets.length * 4 + 8];
|
||||||
int position = 8;
|
int position = 8;
|
||||||
|
|
||||||
for (int target: targets) {
|
for (int target: targets) {
|
||||||
@ -59,8 +58,8 @@ public class PackedSwitchData
|
|||||||
bytes[0] = 0x00;
|
bytes[0] = 0x00;
|
||||||
bytes[1] = 0x01;
|
bytes[1] = 0x01;
|
||||||
|
|
||||||
bytes[2] = (byte)targets.size();
|
bytes[2] = (byte)targets.length;
|
||||||
bytes[3] = (byte)(targets.size() >> 8);
|
bytes[3] = (byte)(targets.length >> 8);
|
||||||
|
|
||||||
bytes[4] = (byte)firstKey;
|
bytes[4] = (byte)firstKey;
|
||||||
bytes[5] = (byte)(firstKey >> 8);
|
bytes[5] = (byte)(firstKey >> 8);
|
||||||
|
@ -36,46 +36,60 @@ import java.util.List;
|
|||||||
|
|
||||||
public class SparseSwitchData
|
public class SparseSwitchData
|
||||||
{
|
{
|
||||||
//TODO: change from 2 List<Integer> to int[,]
|
public static Instruction make(DexFile dexFile, int[] keys, int[] targets) {
|
||||||
public static Instruction make(DexFile dexFile, List<Integer> keys, List<Integer> targets) {
|
|
||||||
byte[] bytes;
|
byte[] bytes;
|
||||||
|
|
||||||
if (keys.size() != targets.size()) {
|
if (keys.length != targets.length) {
|
||||||
throw new RuntimeException("The number of keys and offsets don't match");
|
throw new RuntimeException("The number of keys and offsets don't match");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (targets.length == 0) {
|
||||||
|
throw new RuntimeException("The sparse-switch data must contain at least 1 key/target");
|
||||||
|
}
|
||||||
|
|
||||||
if (targets.size() > 0xFFFF) {
|
if (targets.length > 0xFFFF) {
|
||||||
throw new RuntimeException("The sparse-switch data contains too many elements. " +
|
throw new RuntimeException("The sparse-switch data contains too many elements. " +
|
||||||
"The maximum number of switch elements is 65535");
|
"The maximum number of switch elements is 65535");
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: need to sort the switch elements based on key, in ascending order
|
bytes = new byte[targets.length * 8 + 4];
|
||||||
|
int position = 8;
|
||||||
|
|
||||||
bytes = new byte[targets.size() * 8 + 4];
|
//TODO: should we throw an error if there are no switch elements?
|
||||||
int position = 4;
|
if (targets.length > 0) {
|
||||||
|
int key = keys[0];
|
||||||
|
bytes[4] = (byte)key;
|
||||||
|
bytes[5] = (byte)(key >> 8);
|
||||||
|
bytes[6] = (byte)(key >> 16);
|
||||||
|
bytes[7] = (byte)(key >> 24);
|
||||||
|
|
||||||
|
for (int i=1; i<keys.length; i++) {
|
||||||
|
key = keys[i];
|
||||||
|
if (key <= keys[i-1]) {
|
||||||
|
throw new RuntimeException("The targets in a sparse switch block must be sorted in ascending" +
|
||||||
|
"order, by key");
|
||||||
|
}
|
||||||
|
|
||||||
for (int key: keys) {
|
bytes[position++] = (byte)key;
|
||||||
bytes[position++] = (byte)key;
|
bytes[position++] = (byte)(key >> 8);
|
||||||
bytes[position++] = (byte)(key >> 8);
|
bytes[position++] = (byte)(key >> 16);
|
||||||
bytes[position++] = (byte)(key >> 16);
|
bytes[position++] = (byte)(key >> 24);
|
||||||
bytes[position++] = (byte)(key >> 24);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (int target: targets) {
|
for (int target: targets) {
|
||||||
bytes[position++] = (byte)target;
|
bytes[position++] = (byte)target;
|
||||||
bytes[position++] = (byte)(target >> 8);
|
bytes[position++] = (byte)(target >> 8);
|
||||||
bytes[position++] = (byte)(target >> 16);
|
bytes[position++] = (byte)(target >> 16);
|
||||||
bytes[position++] = (byte)(target >> 24);
|
bytes[position++] = (byte)(target >> 24);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//sparse-switch psuedo-opcode
|
//sparse-switch psuedo-opcode
|
||||||
bytes[0] = 0x00;
|
bytes[0] = 0x00;
|
||||||
bytes[1] = 0x02;
|
bytes[1] = 0x02;
|
||||||
|
|
||||||
bytes[2] = (byte)targets.size();
|
bytes[2] = (byte)targets.length;
|
||||||
bytes[3] = (byte)(targets.size() >> 8);
|
bytes[3] = (byte)(targets.length >> 8);
|
||||||
|
|
||||||
return new Instruction(dexFile, bytes, null);
|
return new Instruction(dexFile, bytes, null);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user