@futpib/parser 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +24 -0
- package/.github/workflows/main.yml +1 -0
- package/build/androidPackageParser.js +30 -32
- package/build/arbitraryDalvikBytecode.d.ts +3 -3
- package/build/arbitraryDalvikBytecode.js +33 -27
- package/build/arbitraryDalvikExecutable.js +55 -17
- package/build/arbitraryJava.d.ts +31 -0
- package/build/arbitraryJava.js +532 -0
- package/build/arbitraryJavaScript.d.ts +3 -0
- package/build/arbitraryJavaScript.js +263 -0
- package/build/arbitraryJavascript.d.ts +3 -0
- package/build/arbitraryJavascript.js +263 -0
- package/build/arbitraryZig.d.ts +3 -0
- package/build/arbitraryZig.js +240 -0
- package/build/arbitraryZipStream.d.ts +1 -1
- package/build/arrayParser.js +72 -13
- package/build/backsmali.d.ts +4 -3
- package/build/backsmali.js +26 -6
- package/build/bash.d.ts +6 -1
- package/build/bashParser.js +131 -90
- package/build/bashParser.test.js +162 -0
- package/build/bashParserEdgeCases.test.d.ts +1 -0
- package/build/bashParserEdgeCases.test.js +117 -0
- package/build/dalvikBytecodeParser/addressConversion.d.ts +110 -0
- package/build/dalvikBytecodeParser/addressConversion.js +334 -0
- package/build/dalvikBytecodeParser/formatParsers.d.ts +7 -6
- package/build/dalvikBytecodeParser/formatParsers.js +13 -14
- package/build/dalvikBytecodeParser.d.ts +60 -31
- package/build/dalvikBytecodeParser.js +92 -35
- package/build/dalvikBytecodeParser.test-d.d.ts +1 -0
- package/build/dalvikBytecodeParser.test-d.js +268 -0
- package/build/dalvikBytecodeUnparser/formatUnparsers.d.ts +9 -8
- package/build/dalvikBytecodeUnparser/formatUnparsers.js +13 -12
- package/build/dalvikBytecodeUnparser.d.ts +2 -2
- package/build/dalvikBytecodeUnparser.js +23 -23
- package/build/dalvikBytecodeUnparser.test.js +7 -7
- package/build/dalvikExecutable.d.ts +3 -3
- package/build/dalvikExecutable.test-d.d.ts +1 -0
- package/build/dalvikExecutable.test-d.js +59 -0
- package/build/dalvikExecutableParser/typedNumbers.d.ts +18 -0
- package/build/dalvikExecutableParser/typedNumbers.js +3 -0
- package/build/dalvikExecutableParser.d.ts +2 -1
- package/build/dalvikExecutableParser.js +96 -77
- package/build/dalvikExecutableParser.test.js +24 -3
- package/build/dalvikExecutableParserAgainstSmaliParser.test.js +3 -0
- package/build/dalvikExecutableUnparser/poolScanners.d.ts +2 -2
- package/build/dalvikExecutableUnparser/sectionUnparsers.d.ts +3 -3
- package/build/dalvikExecutableUnparser/sectionUnparsers.js +26 -11
- package/build/dalvikExecutableUnparser.d.ts +2 -2
- package/build/dalvikExecutableUnparser.test.js +2 -1
- package/build/disjunctionParser.d.ts +5 -3
- package/build/disjunctionParser.js +79 -17
- package/build/disjunctionParser.test-d.d.ts +1 -0
- package/build/disjunctionParser.test-d.js +72 -0
- package/build/elementSwitchParser.d.ts +4 -0
- package/build/{exactElementSwitchParser.js → elementSwitchParser.js} +3 -4
- package/build/elementSwitchParser.test-d.d.ts +1 -0
- package/build/elementSwitchParser.test-d.js +44 -0
- package/build/exactSequenceParser.d.ts +4 -2
- package/build/exactSequenceParser.test-d.d.ts +1 -0
- package/build/exactSequenceParser.test-d.js +36 -0
- package/build/fetchCid.js +2 -66
- package/build/index.d.ts +3 -2
- package/build/index.js +2 -1
- package/build/index.test.js +16 -1
- package/build/inputReader.d.ts +10 -0
- package/build/inputReader.js +36 -0
- package/build/java.d.ts +502 -0
- package/build/java.js +2 -0
- package/build/javaKeyStoreParser.js +14 -17
- package/build/javaParser.d.ts +51 -0
- package/build/javaParser.js +1538 -0
- package/build/javaParser.test.d.ts +1 -0
- package/build/javaParser.test.js +1287 -0
- package/build/javaScript.d.ts +35 -0
- package/build/javaScript.js +1 -0
- package/build/javaScriptParser.d.ts +9 -0
- package/build/javaScriptParser.js +34 -0
- package/build/javaScriptUnparser.d.ts +3 -0
- package/build/javaScriptUnparser.js +4 -0
- package/build/javaScriptUnparser.test.d.ts +1 -0
- package/build/javaScriptUnparser.test.js +24 -0
- package/build/javaUnparser.d.ts +2 -0
- package/build/javaUnparser.js +519 -0
- package/build/javaUnparser.test.d.ts +1 -0
- package/build/javaUnparser.test.js +24 -0
- package/build/javascript.d.ts +35 -0
- package/build/javascript.js +1 -0
- package/build/javascriptParser.d.ts +9 -0
- package/build/javascriptParser.js +34 -0
- package/build/javascriptUnparser.d.ts +3 -0
- package/build/javascriptUnparser.js +4 -0
- package/build/javascriptUnparser.test.d.ts +1 -0
- package/build/javascriptUnparser.test.js +24 -0
- package/build/jsonParser.js +2 -12
- package/build/lazyMessageError.d.ts +3 -0
- package/build/lookaheadParser.js +60 -3
- package/build/negativeLookaheadParser.js +70 -11
- package/build/nonEmptyArrayParser.js +72 -13
- package/build/objectParser.d.ts +12 -0
- package/build/objectParser.js +31 -0
- package/build/objectParser.test-d.d.ts +1 -0
- package/build/objectParser.test-d.js +112 -0
- package/build/objectParser.test.d.ts +1 -0
- package/build/objectParser.test.js +55 -0
- package/build/optionalParser.js +69 -10
- package/build/parser.d.ts +4 -0
- package/build/parser.js +3 -1
- package/build/parser.test.js +114 -1
- package/build/parserConsumedSequenceParser.js +66 -7
- package/build/parserContext.d.ts +6 -0
- package/build/parserContext.js +20 -11
- package/build/parserError.d.ts +119 -27
- package/build/parserError.js +16 -8
- package/build/regexpParser.js +33 -3
- package/build/regexpParser.test.js +31 -0
- package/build/regularExpressionParser.js +35 -15
- package/build/separatedArrayParser.js +73 -14
- package/build/separatedNonEmptyArrayParser.js +73 -14
- package/build/sliceBoundedParser.js +62 -5
- package/build/smaliParser.d.ts +7 -7
- package/build/smaliParser.js +185 -268
- package/build/smaliParser.test.js +58 -0
- package/build/stringEscapes.d.ts +5 -0
- package/build/stringEscapes.js +244 -0
- package/build/symbolicExpression.d.ts +29 -0
- package/build/symbolicExpression.js +1 -0
- package/build/symbolicExpressionParser.d.ts +4 -0
- package/build/symbolicExpressionParser.js +123 -0
- package/build/symbolicExpressionParser.test.d.ts +1 -0
- package/build/symbolicExpressionParser.test.js +289 -0
- package/build/terminatedArrayParser.js +113 -38
- package/build/terminatedArrayParser.test.js +4 -2
- package/build/tupleParser.d.ts +7 -15
- package/build/tupleParser.js +1 -0
- package/build/unionParser.d.ts +5 -3
- package/build/unionParser.js +7 -2
- package/build/unionParser.test-d.d.ts +1 -0
- package/build/unionParser.test-d.js +72 -0
- package/build/unionParser.test.js +10 -11
- package/build/zig.d.ts +280 -0
- package/build/zig.js +2 -0
- package/build/zigParser.d.ts +3 -0
- package/build/zigParser.js +1119 -0
- package/build/zigParser.test.d.ts +1 -0
- package/build/zigParser.test.js +1590 -0
- package/build/zigUnparser.d.ts +2 -0
- package/build/zigUnparser.js +460 -0
- package/build/zigUnparser.test.d.ts +1 -0
- package/build/zigUnparser.test.js +24 -0
- package/build/zipParser.js +19 -32
- package/build/zipUnparser.js +19 -7
- package/build/zipUnparser.test.js +1 -1
- package/node_modules-@types/s-expression/index.d.ts +5 -0
- package/package.json +24 -6
- package/src/androidPackageParser.ts +33 -60
- package/src/arbitraryDalvikBytecode.ts +39 -31
- package/src/arbitraryDalvikExecutable.ts +65 -20
- package/src/arbitraryJava.ts +804 -0
- package/src/arbitraryJavaScript.ts +410 -0
- package/src/arbitraryZig.ts +380 -0
- package/src/arrayParser.ts +1 -3
- package/src/backsmali.ts +35 -4
- package/src/bash.ts +8 -1
- package/src/bashParser.test.ts +258 -0
- package/src/bashParser.ts +180 -143
- package/src/dalvikBytecodeParser/addressConversion.ts +496 -0
- package/src/dalvikBytecodeParser/formatParsers.ts +19 -29
- package/src/dalvikBytecodeParser.test-d.ts +310 -0
- package/src/dalvikBytecodeParser.ts +194 -69
- package/src/dalvikBytecodeUnparser/formatUnparsers.ts +27 -26
- package/src/dalvikBytecodeUnparser.test.ts +7 -7
- package/src/dalvikBytecodeUnparser.ts +31 -30
- package/src/dalvikExecutable.test-d.ts +132 -0
- package/src/dalvikExecutable.ts +3 -3
- package/src/dalvikExecutableParser/typedNumbers.ts +11 -0
- package/src/dalvikExecutableParser.test.ts +37 -3
- package/src/dalvikExecutableParser.test.ts.md +163 -2
- package/src/dalvikExecutableParser.test.ts.snap +0 -0
- package/src/dalvikExecutableParser.ts +121 -139
- package/src/dalvikExecutableParserAgainstSmaliParser.test.ts +4 -0
- package/src/dalvikExecutableUnparser/poolScanners.ts +6 -6
- package/src/dalvikExecutableUnparser/sectionUnparsers.ts +38 -14
- package/src/dalvikExecutableUnparser.test.ts +3 -2
- package/src/dalvikExecutableUnparser.ts +4 -4
- package/src/disjunctionParser.test-d.ts +105 -0
- package/src/disjunctionParser.ts +18 -15
- package/src/elementSwitchParser.test-d.ts +74 -0
- package/src/elementSwitchParser.ts +51 -0
- package/src/exactSequenceParser.test-d.ts +43 -0
- package/src/exactSequenceParser.ts +13 -8
- package/src/fetchCid.ts +2 -76
- package/src/index.test.ts +22 -1
- package/src/index.ts +7 -1
- package/src/inputReader.ts +53 -0
- package/src/java.ts +708 -0
- package/src/javaKeyStoreParser.ts +18 -32
- package/src/javaParser.test.ts +1592 -0
- package/src/javaParser.ts +2640 -0
- package/src/javaScript.ts +36 -0
- package/src/javaScriptParser.ts +57 -0
- package/src/javaScriptUnparser.test.ts +37 -0
- package/src/javaScriptUnparser.ts +7 -0
- package/src/javaUnparser.test.ts +37 -0
- package/src/javaUnparser.ts +640 -0
- package/src/jsonParser.ts +6 -27
- package/src/lookaheadParser.ts +2 -6
- package/src/negativeLookaheadParser.ts +1 -3
- package/src/nonEmptyArrayParser.ts +1 -3
- package/src/objectParser.test-d.ts +152 -0
- package/src/objectParser.test.ts +71 -0
- package/src/objectParser.ts +69 -0
- package/src/optionalParser.ts +1 -3
- package/src/parser.test.ts +151 -4
- package/src/parser.ts +11 -1
- package/src/parserConsumedSequenceParser.ts +2 -4
- package/src/parserContext.ts +26 -11
- package/src/parserError.ts +17 -3
- package/src/regexpParser.test.ts +78 -0
- package/src/regexpParser.ts +35 -3
- package/src/regularExpressionParser.ts +36 -37
- package/src/separatedArrayParser.ts +1 -3
- package/src/separatedNonEmptyArrayParser.ts +1 -3
- package/src/sliceBoundedParser.test.ts +2 -2
- package/src/sliceBoundedParser.ts +15 -19
- package/src/smaliParser.test.ts +64 -0
- package/src/smaliParser.test.ts.md +12 -12
- package/src/smaliParser.test.ts.snap +0 -0
- package/src/smaliParser.ts +246 -534
- package/src/stringEscapes.ts +253 -0
- package/src/symbolicExpression.ts +17 -0
- package/src/symbolicExpressionParser.test.ts +466 -0
- package/src/symbolicExpressionParser.ts +190 -0
- package/src/terminatedArrayParser.test.ts +9 -6
- package/src/terminatedArrayParser.ts +25 -29
- package/src/tupleParser.ts +21 -18
- package/src/unionParser.test-d.ts +105 -0
- package/src/unionParser.test.ts +18 -17
- package/src/unionParser.ts +28 -16
- package/src/zig.ts +411 -0
- package/src/zigParser.test.ts +1693 -0
- package/src/zigParser.ts +1745 -0
- package/src/zigUnparser.test.ts +37 -0
- package/src/zigUnparser.ts +615 -0
- package/src/zipParser.ts +20 -56
- package/src/zipUnparser.test.ts +1 -1
- package/src/zipUnparser.ts +22 -7
- package/tsconfig.json +2 -2
- package/build/exactElementSwitchParser.d.ts +0 -3
- package/src/exactElementSwitchParser.ts +0 -41
|
@@ -29,6 +29,24 @@ export type IndexIntoMethodIds = {} & Newtype<{
|
|
|
29
29
|
export declare const isoIndexIntoMethodIds: import("monocle-ts").Iso<Newtype<{
|
|
30
30
|
readonly IndexIntoMethodIds: unique symbol;
|
|
31
31
|
}, number>, number>;
|
|
32
|
+
export type IndexIntoCallSiteIds = {} & Newtype<{
|
|
33
|
+
readonly IndexIntoCallSiteIds: unique symbol;
|
|
34
|
+
}, number>;
|
|
35
|
+
export declare const isoIndexIntoCallSiteIds: import("monocle-ts").Iso<Newtype<{
|
|
36
|
+
readonly IndexIntoCallSiteIds: unique symbol;
|
|
37
|
+
}, number>, number>;
|
|
38
|
+
export type CodeUnit = {} & Newtype<{
|
|
39
|
+
readonly CodeUnit: unique symbol;
|
|
40
|
+
}, number>;
|
|
41
|
+
export declare const isoCodeUnit: import("monocle-ts").Iso<Newtype<{
|
|
42
|
+
readonly CodeUnit: unique symbol;
|
|
43
|
+
}, number>, number>;
|
|
44
|
+
export type InstructionIndex = {} & Newtype<{
|
|
45
|
+
readonly InstructionIndex: unique symbol;
|
|
46
|
+
}, number>;
|
|
47
|
+
export declare const isoInstructionIndex: import("monocle-ts").Iso<Newtype<{
|
|
48
|
+
readonly InstructionIndex: unique symbol;
|
|
49
|
+
}, number>, number>;
|
|
32
50
|
export type OffsetToStringDataItem = {} & Newtype<{
|
|
33
51
|
readonly OffsetToStringDataItem: unique symbol;
|
|
34
52
|
}, number>;
|
|
@@ -4,6 +4,9 @@ export const isoIndexIntoTypeIds = iso();
|
|
|
4
4
|
export const isoIndexIntoPrototypeIds = iso();
|
|
5
5
|
export const isoIndexIntoFieldIds = iso();
|
|
6
6
|
export const isoIndexIntoMethodIds = iso();
|
|
7
|
+
export const isoIndexIntoCallSiteIds = iso();
|
|
8
|
+
export const isoCodeUnit = iso();
|
|
9
|
+
export const isoInstructionIndex = iso();
|
|
7
10
|
export const isoOffsetToStringDataItem = iso();
|
|
8
11
|
export const isoOffsetToTypeList = iso();
|
|
9
12
|
export const isoOffsetToAnnotationsDirectoryItem = iso();
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type Parser } from './parser.js';
|
|
2
|
-
import { type DalvikBytecode } from './dalvikBytecodeParser.js';
|
|
2
|
+
import { type DalvikBytecode } from './dalvikBytecodeParser/addressConversion.js';
|
|
3
3
|
import { type DalvikExecutable } from './dalvikExecutable.js';
|
|
4
4
|
export declare const dalvikExecutableParser: Parser<DalvikExecutable<DalvikBytecode>, Uint8Array>;
|
|
5
|
+
export { type DalvikBytecodeOperation, type DalvikBytecode } from './dalvikBytecodeParser/addressConversion.js';
|
|
5
6
|
export declare const dalvikExecutableWithRawInstructionsParser: Parser<DalvikExecutable<Uint8Array>, Uint8Array>;
|
|
@@ -3,6 +3,7 @@ import { MUtf8Decoder } from 'mutf-8';
|
|
|
3
3
|
import { createExactElementParser } from './exactElementParser.js';
|
|
4
4
|
import { createExactSequenceParser } from './exactSequenceParser.js';
|
|
5
5
|
import { createFixedLengthSequenceParser } from './fixedLengthSequenceParser.js';
|
|
6
|
+
import { createObjectParser } from './objectParser.js';
|
|
6
7
|
import { cloneParser, setParserName } from './parser.js';
|
|
7
8
|
import { parserCreatorCompose } from './parserCreatorCompose.js';
|
|
8
9
|
import { promiseCompose } from './promiseCompose.js';
|
|
@@ -16,8 +17,11 @@ import { sleb128NumberParser, uleb128NumberParser } from './leb128Parser.js';
|
|
|
16
17
|
import { createDisjunctionParser } from './disjunctionParser.js';
|
|
17
18
|
import { createElementTerminatedSequenceParser } from './elementTerminatedSequenceParser.js';
|
|
18
19
|
import { createElementTerminatedArrayParserUnsafe } from './elementTerminatedArrayParser.js';
|
|
19
|
-
import {
|
|
20
|
+
import { createRawDalvikBytecodeParser, resolveRawDalvikBytecodeOperationIndices, } from './dalvikBytecodeParser.js';
|
|
21
|
+
import { buildCodeUnitToIndexMap, codeUnitToInstructionIndex, convertBranchOffsetsToInstructionOffsets, unwrapBranchOffsets, } from './dalvikBytecodeParser/addressConversion.js';
|
|
22
|
+
import { isoCodeUnit, isoInstructionIndex } from './dalvikExecutableParser/typedNumbers.js';
|
|
20
23
|
import { byteParser, ubyteParser, uintParser, uleb128p1NumberParser, ushortParser, } from './dalvikExecutableParser/typeParsers.js';
|
|
24
|
+
import { dalvikExecutableMethodEquals, } from './dalvikExecutable.js';
|
|
21
25
|
// https://source.android.com/docs/core/runtime/dex-format
|
|
22
26
|
const createByteAlignParser = (byteAlignment) => async (parserContext) => {
|
|
23
27
|
const toSkip = (byteAlignment - (parserContext.position % byteAlignment)) % byteAlignment;
|
|
@@ -34,43 +38,27 @@ const dalvikExecutableHeaderVersionParser = promiseCompose(createTupleParser([
|
|
|
34
38
|
const version = Number.parseInt(versionString, 10);
|
|
35
39
|
return version;
|
|
36
40
|
});
|
|
37
|
-
const sizeOffsetParser =
|
|
38
|
-
uintParser,
|
|
39
|
-
uintParser,
|
|
40
|
-
|
|
41
|
-
const dalvikExecutableHeaderItemParser =
|
|
42
|
-
dalvikExecutableHeaderVersionParser,
|
|
43
|
-
uintParser,
|
|
44
|
-
createFixedLengthSequenceParser(20),
|
|
45
|
-
uintParser,
|
|
46
|
-
uintParser,
|
|
47
|
-
uintParser,
|
|
48
|
-
sizeOffsetParser,
|
|
49
|
-
uintParser,
|
|
50
|
-
sizeOffsetParser,
|
|
51
|
-
sizeOffsetParser,
|
|
52
|
-
sizeOffsetParser,
|
|
53
|
-
sizeOffsetParser,
|
|
54
|
-
sizeOffsetParser,
|
|
55
|
-
sizeOffsetParser,
|
|
56
|
-
sizeOffsetParser,
|
|
57
|
-
|
|
58
|
-
version,
|
|
59
|
-
checksum,
|
|
60
|
-
sha1Hash,
|
|
61
|
-
fileSize,
|
|
62
|
-
headerSize,
|
|
63
|
-
endianTag,
|
|
64
|
-
link,
|
|
65
|
-
mapOffset,
|
|
66
|
-
stringIds,
|
|
67
|
-
typeIds,
|
|
68
|
-
prototypeIds,
|
|
69
|
-
fieldIds,
|
|
70
|
-
methodIds,
|
|
71
|
-
classDefinitions,
|
|
72
|
-
data,
|
|
73
|
-
}));
|
|
41
|
+
const sizeOffsetParser = createObjectParser({
|
|
42
|
+
size: uintParser,
|
|
43
|
+
offset: uintParser,
|
|
44
|
+
});
|
|
45
|
+
const dalvikExecutableHeaderItemParser = createObjectParser({
|
|
46
|
+
version: dalvikExecutableHeaderVersionParser,
|
|
47
|
+
checksum: uintParser,
|
|
48
|
+
sha1Hash: createFixedLengthSequenceParser(20),
|
|
49
|
+
fileSize: uintParser,
|
|
50
|
+
headerSize: uintParser,
|
|
51
|
+
endianTag: uintParser,
|
|
52
|
+
link: sizeOffsetParser,
|
|
53
|
+
mapOffset: uintParser,
|
|
54
|
+
stringIds: sizeOffsetParser,
|
|
55
|
+
typeIds: sizeOffsetParser,
|
|
56
|
+
prototypeIds: sizeOffsetParser,
|
|
57
|
+
fieldIds: sizeOffsetParser,
|
|
58
|
+
methodIds: sizeOffsetParser,
|
|
59
|
+
classDefinitions: sizeOffsetParser,
|
|
60
|
+
data: sizeOffsetParser,
|
|
61
|
+
});
|
|
74
62
|
const dalvikExecutableStringIdItemParser = promiseCompose(cloneParser(uintParser), offset => isoOffsetToStringDataItem.wrap(offset));
|
|
75
63
|
const isoDalvikExecutableStringIdItems = getIsoTypedNumberArray();
|
|
76
64
|
const createSkipToThenStringIdItemsParser = ({ size, offset }) => (size === 0
|
|
@@ -308,10 +296,10 @@ const createSkipToThenAnnotationsDirectoryItemsParser = (sizeOffset) => createSk
|
|
|
308
296
|
isoOffset: isoOffsetToAnnotationsDirectoryItem,
|
|
309
297
|
parserName: 'skipToThenAnnotationsDirectoryItemsParser',
|
|
310
298
|
});
|
|
311
|
-
const encodedFieldParser =
|
|
312
|
-
uleb128NumberParser,
|
|
313
|
-
uleb128FieldAccessFlagsParser,
|
|
314
|
-
|
|
299
|
+
const encodedFieldParser = createObjectParser({
|
|
300
|
+
fieldIndexDiff: uleb128NumberParser,
|
|
301
|
+
accessFlags: uleb128FieldAccessFlagsParser,
|
|
302
|
+
});
|
|
315
303
|
const createEncodedFieldsParser = (fieldsSize) => promiseCompose(createQuantifierParser(encodedFieldParser, fieldsSize), encodedFields => {
|
|
316
304
|
let previousFieldIndex = 0;
|
|
317
305
|
return encodedFields.map(({ fieldIndexDiff, accessFlags }) => {
|
|
@@ -375,10 +363,11 @@ const createByteWith5LeastSignificantBitsEqualParser = (leastSignificant5) => {
|
|
|
375
363
|
return byteWith5LeastSignificantBitsEqualParser;
|
|
376
364
|
};
|
|
377
365
|
const createEncodedValueArgParser = (valueType) => promiseCompose(createByteWith5LeastSignificantBitsEqualParser(valueType), byte => byte >> 5);
|
|
378
|
-
const encodedValueByteParser =
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
366
|
+
const encodedValueByteParser = createObjectParser({
|
|
367
|
+
type: 'byte',
|
|
368
|
+
_tag: createExactElementParser(0),
|
|
369
|
+
value: byteParser,
|
|
370
|
+
});
|
|
382
371
|
setParserName(encodedValueByteParser, 'encodedValueByteParser');
|
|
383
372
|
const encodedValueShortParser = parserCreatorCompose(() => createEncodedValueArgParser(0x02), sizeSubOne => {
|
|
384
373
|
const size = sizeSubOne + 1;
|
|
@@ -730,12 +719,13 @@ const encodedValueEnumParser = parserCreatorCompose(() => createEncodedValueArgP
|
|
|
730
719
|
setParserName(encodedValueEnumParser, 'encodedValueEnumParser');
|
|
731
720
|
const encodedArrayParser = parserCreatorCompose(() => uleb128NumberParser, size => createQuantifierParser(encodedValueParser, size))();
|
|
732
721
|
setParserName(encodedArrayParser, 'encodedArrayParser');
|
|
733
|
-
const encodedValueArrayParser =
|
|
734
|
-
|
|
722
|
+
const encodedValueArrayParser = createObjectParser({
|
|
723
|
+
type: 'array',
|
|
724
|
+
_tag: parserCreatorCompose(() => createEncodedValueArgParser(0x1C), valueArg => parserContext => {
|
|
735
725
|
parserContext.invariant(valueArg === 0, '(encodedValueArrayParser) valueArg: %s', valueArg);
|
|
736
726
|
})(),
|
|
737
|
-
encodedArrayParser,
|
|
738
|
-
|
|
727
|
+
value: encodedArrayParser,
|
|
728
|
+
});
|
|
739
729
|
setParserName(encodedValueArrayParser, 'encodedValueArrayParser');
|
|
740
730
|
const annotationElementParser = promiseCompose(createTupleParser([
|
|
741
731
|
uleb128NumberParser,
|
|
@@ -756,12 +746,13 @@ const encodedAnnotationParser = promiseCompose(parserCreatorCompose(() => create
|
|
|
756
746
|
elements,
|
|
757
747
|
}));
|
|
758
748
|
setParserName(encodedAnnotationParser, 'encodedAnnotationParser');
|
|
759
|
-
const encodedValueAnnotationParser =
|
|
760
|
-
|
|
749
|
+
const encodedValueAnnotationParser = createObjectParser({
|
|
750
|
+
type: 'annotation',
|
|
751
|
+
_tag: parserCreatorCompose(() => createEncodedValueArgParser(0x1D), valueArg => parserContext => {
|
|
761
752
|
parserContext.invariant(valueArg === 0, '(encodedValueAnnotationParser) valueArg: %s', valueArg);
|
|
762
753
|
})(),
|
|
763
|
-
encodedAnnotationParser,
|
|
764
|
-
|
|
754
|
+
value: encodedAnnotationParser,
|
|
755
|
+
});
|
|
765
756
|
setParserName(encodedValueAnnotationParser, 'encodedValueAnnotationParser');
|
|
766
757
|
const encodedValueNullParser = parserCreatorCompose(() => createEncodedValueArgParser(0x1E), valueArg => parserContext => {
|
|
767
758
|
parserContext.invariant(valueArg === 0, '(encodedValueNullParser) valueArg: %s', valueArg);
|
|
@@ -875,10 +866,16 @@ const createSkipToThenCodeItemsParser = ({ sizeOffset, createInstructionsParser,
|
|
|
875
866
|
const dalvikExecutableDebugByteCodeValueParser = parserCreatorCompose(() => ubyteParser, (value) => {
|
|
876
867
|
switch (value) {
|
|
877
868
|
case 0x01: {
|
|
878
|
-
return
|
|
869
|
+
return createObjectParser({
|
|
870
|
+
type: 'advancePc',
|
|
871
|
+
addressDiff: uleb128NumberParser,
|
|
872
|
+
});
|
|
879
873
|
}
|
|
880
874
|
case 0x02: {
|
|
881
|
-
return
|
|
875
|
+
return createObjectParser({
|
|
876
|
+
type: 'advanceLine',
|
|
877
|
+
lineDiff: sleb128NumberParser,
|
|
878
|
+
});
|
|
882
879
|
}
|
|
883
880
|
case 0x03: {
|
|
884
881
|
return promiseCompose(createTupleParser([
|
|
@@ -969,10 +966,10 @@ const dalvikExecutableAnnotationItemVisibilityParser = promiseCompose(ubyteParse
|
|
|
969
966
|
}
|
|
970
967
|
});
|
|
971
968
|
setParserName(dalvikExecutableAnnotationItemVisibilityParser, 'dalvikExecutableAnnotationItemVisibilityParser');
|
|
972
|
-
const dalvikExecutableAnnotationItemParser =
|
|
973
|
-
dalvikExecutableAnnotationItemVisibilityParser,
|
|
974
|
-
encodedAnnotationParser,
|
|
975
|
-
|
|
969
|
+
const dalvikExecutableAnnotationItemParser = createObjectParser({
|
|
970
|
+
visibility: dalvikExecutableAnnotationItemVisibilityParser,
|
|
971
|
+
encodedAnnotation: encodedAnnotationParser,
|
|
972
|
+
});
|
|
976
973
|
setParserName(dalvikExecutableAnnotationItemParser, 'dalvikExecutableAnnotationItemParser');
|
|
977
974
|
const createSkipToThenAnnotationItemsParser = (sizeOffset) => createSkipToThenItemByOffsetParser({
|
|
978
975
|
sizeOffset,
|
|
@@ -1078,12 +1075,12 @@ const dalvikExecutableMapItemTypeParser = promiseCompose(ushortParser, type => {
|
|
|
1078
1075
|
}
|
|
1079
1076
|
}
|
|
1080
1077
|
});
|
|
1081
|
-
const dalvikExecutableMapItemParser =
|
|
1082
|
-
dalvikExecutableMapItemTypeParser,
|
|
1083
|
-
ushortParser,
|
|
1084
|
-
uintParser,
|
|
1085
|
-
uintParser,
|
|
1086
|
-
|
|
1078
|
+
const dalvikExecutableMapItemParser = createObjectParser({
|
|
1079
|
+
type: dalvikExecutableMapItemTypeParser,
|
|
1080
|
+
_unused: ushortParser,
|
|
1081
|
+
size: uintParser,
|
|
1082
|
+
offset: uintParser,
|
|
1083
|
+
});
|
|
1087
1084
|
const dalvikExecutableMapListParser = parserCreatorCompose(() => uintParser, size => createQuantifierParser(dalvikExecutableMapItemParser, size))();
|
|
1088
1085
|
setParserName(dalvikExecutableMapListParser, 'dalvikExecutableMapListParser');
|
|
1089
1086
|
const createDalvikExecutableMapListParser = (mapOffset) => {
|
|
@@ -1358,29 +1355,49 @@ link, }) => {
|
|
|
1358
1355
|
]);
|
|
1359
1356
|
for (const [offset, codeItem] of codeItemByOffset) {
|
|
1360
1357
|
const debugInfo = debugInfoByOffset.get(codeItem.debugInfoOffset);
|
|
1358
|
+
// Build code unit to instruction index mapping for address conversion
|
|
1359
|
+
const rawInstructions = codeItem.instructions;
|
|
1360
|
+
const codeUnitToIndexMap = Array.isArray(rawInstructions) ? buildCodeUnitToIndexMap(rawInstructions) : undefined;
|
|
1361
|
+
// Convert branch offsets from code units to instruction offsets
|
|
1362
|
+
// Tier 1 (CodeUnit) -> Tier 2 (InstructionIndex) -> Tier 3 (plain numbers)
|
|
1363
|
+
const convertedInstructions = (Array.isArray(rawInstructions) && codeUnitToIndexMap)
|
|
1364
|
+
? unwrapBranchOffsets(convertBranchOffsetsToInstructionOffsets(rawInstructions))
|
|
1365
|
+
: codeItem.instructions;
|
|
1361
1366
|
codeByOffset.set(offset, {
|
|
1362
1367
|
registersSize: codeItem.registersSize,
|
|
1363
1368
|
insSize: codeItem.insSize,
|
|
1364
1369
|
outsSize: codeItem.outsSize,
|
|
1365
1370
|
debugInfo,
|
|
1366
|
-
instructions:
|
|
1371
|
+
instructions: convertedInstructions,
|
|
1367
1372
|
tries: codeItem.tryItems.map(tryItem => {
|
|
1368
1373
|
const handler_ = codeItem.handlers.get(tryItem.handlerOffset);
|
|
1369
1374
|
invariant(handler_, 'Handler must be there. Handler offset: %s', tryItem.handlerOffset);
|
|
1375
|
+
// Convert handler addresses from code units to instruction indices (unwrapped for Tier 3)
|
|
1370
1376
|
const handler = {
|
|
1371
1377
|
handlers: handler_.handlers.map(encodedHandler => {
|
|
1372
1378
|
const type = types.at(encodedHandler.typeIndex);
|
|
1373
1379
|
invariant(type, 'Type must be there. Type id: %s', encodedHandler.typeIndex);
|
|
1374
1380
|
return {
|
|
1375
1381
|
type,
|
|
1376
|
-
|
|
1382
|
+
handlerInstructionIndex: codeUnitToIndexMap
|
|
1383
|
+
? isoInstructionIndex.unwrap(codeUnitToInstructionIndex(isoCodeUnit.wrap(encodedHandler.address), codeUnitToIndexMap))
|
|
1384
|
+
: encodedHandler.address,
|
|
1377
1385
|
};
|
|
1378
1386
|
}),
|
|
1379
|
-
|
|
1387
|
+
catchAllInstructionIndex: (handler_.catchAllAddress !== undefined && codeUnitToIndexMap)
|
|
1388
|
+
? isoInstructionIndex.unwrap(codeUnitToInstructionIndex(isoCodeUnit.wrap(handler_.catchAllAddress), codeUnitToIndexMap))
|
|
1389
|
+
: handler_.catchAllAddress,
|
|
1380
1390
|
};
|
|
1391
|
+
// Convert try block addresses from code units to instruction indices (unwrapped for Tier 3)
|
|
1392
|
+
const startInstructionIndex = codeUnitToIndexMap
|
|
1393
|
+
? isoInstructionIndex.unwrap(codeUnitToInstructionIndex(isoCodeUnit.wrap(tryItem.startAddress), codeUnitToIndexMap))
|
|
1394
|
+
: tryItem.startAddress;
|
|
1395
|
+
const endInstructionIndex = codeUnitToIndexMap
|
|
1396
|
+
? isoInstructionIndex.unwrap(codeUnitToInstructionIndex(isoCodeUnit.wrap(tryItem.startAddress + tryItem.instructionCount), codeUnitToIndexMap))
|
|
1397
|
+
: tryItem.startAddress + tryItem.instructionCount;
|
|
1381
1398
|
return {
|
|
1382
|
-
|
|
1383
|
-
instructionCount:
|
|
1399
|
+
startInstructionIndex,
|
|
1400
|
+
instructionCount: endInstructionIndex - startInstructionIndex,
|
|
1384
1401
|
handler,
|
|
1385
1402
|
};
|
|
1386
1403
|
}),
|
|
@@ -1421,7 +1438,7 @@ link, }) => {
|
|
|
1421
1438
|
}
|
|
1422
1439
|
return {
|
|
1423
1440
|
...rest,
|
|
1424
|
-
instructions: instructions.map((instruction) =>
|
|
1441
|
+
instructions: instructions.map((instruction) => resolveRawDalvikBytecodeOperationIndices(instruction, resolvers)),
|
|
1425
1442
|
};
|
|
1426
1443
|
}
|
|
1427
1444
|
for (const [offset, classDataItem] of classDataItemByOffset) {
|
|
@@ -1735,10 +1752,8 @@ link, }) => {
|
|
|
1735
1752
|
if (classDef.annotations?.parameterAnnotations && classDef.classData) {
|
|
1736
1753
|
const allMethods = [...(classDef.classData.directMethods ?? []), ...(classDef.classData.virtualMethods ?? [])];
|
|
1737
1754
|
classDef.annotations.parameterAnnotations.sort((a, b) => {
|
|
1738
|
-
const indexA = allMethods.findIndex(m => m.method
|
|
1739
|
-
|
|
1740
|
-
const indexB = allMethods.findIndex(m => m.method.name === b.method.name &&
|
|
1741
|
-
m.method.prototype.shorty === b.method.prototype.shorty);
|
|
1755
|
+
const indexA = allMethods.findIndex(m => dalvikExecutableMethodEquals(m.method, a.method));
|
|
1756
|
+
const indexB = allMethods.findIndex(m => dalvikExecutableMethodEquals(m.method, b.method));
|
|
1742
1757
|
return indexA - indexB;
|
|
1743
1758
|
});
|
|
1744
1759
|
}
|
|
@@ -1748,8 +1763,12 @@ link, }) => {
|
|
|
1748
1763
|
link,
|
|
1749
1764
|
};
|
|
1750
1765
|
}))();
|
|
1766
|
+
// The factory creates a parser that outputs RawDalvikBytecode, but the parser internally transforms
|
|
1767
|
+
// instructions via unwrapBranchOffsets(convertBranchOffsetsToInstructionOffsets(...)) and
|
|
1768
|
+
// resolveRawDalvikBytecodeOperationIndices to produce DalvikBytecode with plain number indices.
|
|
1769
|
+
// The cast is required because TypeScript can't track this internal transformation.
|
|
1751
1770
|
export const dalvikExecutableParser = createDalvikExecutableParser({
|
|
1752
|
-
createInstructionsParser:
|
|
1771
|
+
createInstructionsParser: createRawDalvikBytecodeParser,
|
|
1753
1772
|
});
|
|
1754
1773
|
setParserName(dalvikExecutableParser, 'dalvikExecutableParser');
|
|
1755
1774
|
export const dalvikExecutableWithRawInstructionsParser = createDalvikExecutableParser({
|
|
@@ -54,8 +54,10 @@ const dexWithParsedInstructionsMacro = test.macro({
|
|
|
54
54
|
if (typeof key !== 'string') {
|
|
55
55
|
return;
|
|
56
56
|
}
|
|
57
|
-
t.false(key.endsWith('Offset')
|
|
58
|
-
|
|
57
|
+
t.false(key.endsWith('Offset'), 'All offsets should be resolved: ' + path.join('.'));
|
|
58
|
+
// InstructionIndex fields are expected in Tier 3
|
|
59
|
+
const allowedIndexFields = ['targetInstructionIndex', 'targetInstructionIndices', 'startInstructionIndex', 'handlerInstructionIndex', 'catchAllInstructionIndex'];
|
|
60
|
+
t.false(key.endsWith('Index') && !allowedIndexFields.includes(key) && key !== 'targetInstructionIndices', 'All indexes should be resolved: ' + path.join('.'));
|
|
59
61
|
});
|
|
60
62
|
if (shouldSnapshot) {
|
|
61
63
|
t.snapshot(actual);
|
|
@@ -66,7 +68,26 @@ const dexWithParsedInstructionsMacro = test.macro({
|
|
|
66
68
|
}
|
|
67
69
|
},
|
|
68
70
|
});
|
|
69
|
-
test.serial
|
|
71
|
+
test.serial(dexWithParsedInstructionsMacro, 'bafkreibb4gsprc3fvmnyqx6obswvm7e7wngnfj64gz65ey72r7xgyzymt4', true);
|
|
70
72
|
test.serial.skip(dexWithParsedInstructionsMacro, 'bafybeiebe27ylo53trgitu6fqfbmba43c4ivxj3nt4kumsilkucpbdxtqq', false);
|
|
71
73
|
test.serial.skip(dexWithParsedInstructionsMacro, 'bafybeibbupm7uzhuq4pa674rb2amxsenbdaoijigmaf4onaodaql4mh7yy', false);
|
|
72
74
|
test.serial.skip(dexWithParsedInstructionsMacro, 'bafybeicb3qajmwy6li7hche2nkucvytaxcyxhwhphmi73tgydjzmyoqoda', false);
|
|
75
|
+
const methodMacro = test.macro({
|
|
76
|
+
title: (providedTitle, dexCid, className, methodName) => providedTitle ?? `method ${className}.${methodName} from ${dexCid}`,
|
|
77
|
+
async exec(t, dexCid, className, methodName) {
|
|
78
|
+
const dexStream = await fetchCid(dexCid);
|
|
79
|
+
const dex = await runParser(dalvikExecutableParser, dexStream, uint8ArrayParserInputCompanion, {
|
|
80
|
+
errorJoinMode: 'all',
|
|
81
|
+
});
|
|
82
|
+
const classDef = dex.classDefinitions.find(c => c.class === className);
|
|
83
|
+
t.truthy(classDef, `Class ${className} not found`);
|
|
84
|
+
const allMethods = [
|
|
85
|
+
...(classDef.classData?.directMethods ?? []),
|
|
86
|
+
...(classDef.classData?.virtualMethods ?? []),
|
|
87
|
+
];
|
|
88
|
+
const method = allMethods.find(m => m.method.name === methodName);
|
|
89
|
+
t.truthy(method, `Method ${methodName} not found in ${className}`);
|
|
90
|
+
t.snapshot(method);
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
test.serial(methodMacro, 'bafkreifycfnx4xf3nlml4qavlyxr6bes66nxsow3iaqjghewfsozoj2h3q', 'Lpl/czak/minimal/MainActivity;', 'getPackedSwitchResult');
|
|
@@ -148,6 +148,9 @@ const parseAllClassesInDexAgainstSmaliMacro = test.macro({
|
|
|
148
148
|
},
|
|
149
149
|
});
|
|
150
150
|
const testCasesByCid = {
|
|
151
|
+
bafkreifycfnx4xf3nlml4qavlyxr6bes66nxsow3iaqjghewfsozoj2h3q: [
|
|
152
|
+
{ smaliFilePath: 'pl/czak/minimal/MainActivity', isolate: true },
|
|
153
|
+
],
|
|
151
154
|
bafybeicb3qajmwy6li7hche2nkucvytaxcyxhwhphmi73tgydjzmyoqoda: [
|
|
152
155
|
{ smaliFilePath: 'androidx/activity/ComponentActivity$1', isolate: true },
|
|
153
156
|
{ smaliFilePath: 'androidx/activity/R$id', isolate: true },
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { type DalvikExecutable } from '../dalvikExecutable.js';
|
|
2
|
-
import { type
|
|
2
|
+
import { type DalvikBytecodeOperation } from '../dalvikBytecodeParser/addressConversion.js';
|
|
3
3
|
import { type PoolBuilders } from './poolBuilders.js';
|
|
4
|
-
export declare function scanForPoolReferences(dalvikExecutable: DalvikExecutable<
|
|
4
|
+
export declare function scanForPoolReferences(dalvikExecutable: DalvikExecutable<DalvikBytecodeOperation[]>, poolBuilders: PoolBuilders): void;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type Unparser } from '../unparser.js';
|
|
2
2
|
import { type DalvikExecutableAccessFlags, type DalvikExecutableClassData, type DalvikExecutableCode, type DalvikExecutableDebugInfo, type DalvikExecutableEncodedValue, type DalvikExecutableField, type DalvikExecutableMethod, type DalvikExecutablePrototype } from '../dalvikExecutable.js';
|
|
3
|
-
import { type
|
|
3
|
+
import { type DalvikBytecodeOperation } from '../dalvikBytecodeParser/addressConversion.js';
|
|
4
4
|
import { type PoolBuilders } from './poolBuilders.js';
|
|
5
5
|
import { WriteLater } from '../unparserContext.js';
|
|
6
6
|
export declare function createSectionUnparsers(poolBuilders: PoolBuilders): {
|
|
@@ -14,8 +14,8 @@ export declare function createSectionUnparsers(poolBuilders: PoolBuilders): {
|
|
|
14
14
|
debugInfoUnparser: Unparser<DalvikExecutableDebugInfo, Uint8Array<ArrayBufferLike>>;
|
|
15
15
|
codeItemUnparser: (callback?: (result: {
|
|
16
16
|
debugInfoOffsetWriteLater?: WriteLater<Uint8Array, number>;
|
|
17
|
-
}) => void) => Unparser<DalvikExecutableCode<
|
|
18
|
-
classDataUnparser: (codeOffsetMap: Map<DalvikExecutableCode<
|
|
17
|
+
}) => void) => Unparser<DalvikExecutableCode<DalvikBytecodeOperation[]>, Uint8Array>;
|
|
18
|
+
classDataUnparser: (codeOffsetMap: Map<DalvikExecutableCode<DalvikBytecodeOperation[]>, number>) => Unparser<DalvikExecutableClassData<DalvikBytecodeOperation[]>, Uint8Array>;
|
|
19
19
|
accessFlagsToNumber: (accessFlags: DalvikExecutableAccessFlags) => number;
|
|
20
20
|
getStringIndex: (str: string | undefined) => number;
|
|
21
21
|
getTypeIndex: (typeDescriptor: string | undefined) => number;
|
|
@@ -5,7 +5,9 @@ async function* yieldAndCapture(gen) {
|
|
|
5
5
|
}
|
|
6
6
|
return value;
|
|
7
7
|
}
|
|
8
|
-
import {
|
|
8
|
+
import { rawDalvikBytecodeUnparser } from '../dalvikBytecodeUnparser.js';
|
|
9
|
+
import { buildIndexToCodeUnitMapFromResolved, instructionIndexToCodeUnit, wrapBranchOffsets, convertInstructionOffsetsToBranchOffsets, } from '../dalvikBytecodeParser/addressConversion.js';
|
|
10
|
+
import { isoCodeUnit, isoInstructionIndex } from '../dalvikExecutableParser/typedNumbers.js';
|
|
9
11
|
import { ubyteUnparser, ushortUnparser, uintUnparser } from '../dalvikBytecodeUnparser/formatUnparsers.js';
|
|
10
12
|
import { encodeModifiedUtf8, sleb128Unparser, uleb128p1Unparser, uleb128Unparser } from './utils.js';
|
|
11
13
|
export function createSectionUnparsers(poolBuilders) {
|
|
@@ -461,17 +463,26 @@ export function createSectionUnparsers(poolBuilders) {
|
|
|
461
463
|
if (callback) {
|
|
462
464
|
callback({ debugInfoOffsetWriteLater });
|
|
463
465
|
}
|
|
464
|
-
|
|
466
|
+
// Convert branch offsets from instruction offsets back to code units
|
|
467
|
+
// Tier 3 (plain numbers) -> Tier 2 (InstructionIndex) -> Tier 1 (CodeUnit)
|
|
468
|
+
const rawInstructions = convertInstructionOffsetsToBranchOffsets(wrapBranchOffsets(input.instructions));
|
|
469
|
+
const instructionsSizeInShorts = await calculateRawInstructionsSize(rawInstructions);
|
|
465
470
|
yield* uintUnparser(instructionsSizeInShorts, unparserContext);
|
|
466
|
-
yield*
|
|
471
|
+
yield* rawDalvikBytecodeUnparser(rawInstructions, unparserContext);
|
|
467
472
|
if (input.tries.length > 0 && instructionsSizeInShorts % 2 !== 0) {
|
|
468
473
|
yield* ushortUnparser(0, unparserContext);
|
|
469
474
|
}
|
|
470
475
|
if (input.tries.length > 0) {
|
|
476
|
+
// Build index to code unit mapping for address conversion
|
|
477
|
+
const indexToCodeUnitMap = buildIndexToCodeUnitMapFromResolved(input.instructions);
|
|
471
478
|
const handlerOffsetWriteLaters = [];
|
|
472
479
|
for (const tryBlock of input.tries) {
|
|
473
|
-
|
|
474
|
-
|
|
480
|
+
// Convert instruction indices back to code unit offsets
|
|
481
|
+
const startAddressCodeUnit = isoCodeUnit.unwrap(instructionIndexToCodeUnit(isoInstructionIndex.wrap(tryBlock.startInstructionIndex), indexToCodeUnitMap));
|
|
482
|
+
const endAddressCodeUnit = isoCodeUnit.unwrap(instructionIndexToCodeUnit(isoInstructionIndex.wrap(tryBlock.startInstructionIndex + tryBlock.instructionCount), indexToCodeUnitMap));
|
|
483
|
+
const instructionCountCodeUnits = endAddressCodeUnit - startAddressCodeUnit;
|
|
484
|
+
yield* uintUnparser(startAddressCodeUnit, unparserContext);
|
|
485
|
+
yield* ushortUnparser(instructionCountCodeUnits, unparserContext);
|
|
475
486
|
const handlerOffsetWriteLater = yield* yieldAndCapture(unparserContext.writeLater(2));
|
|
476
487
|
handlerOffsetWriteLaters.push(handlerOffsetWriteLater);
|
|
477
488
|
}
|
|
@@ -482,7 +493,7 @@ export function createSectionUnparsers(poolBuilders) {
|
|
|
482
493
|
const handler = tryBlock.handler;
|
|
483
494
|
const handlerOffset = unparserContext.position - handlersStartOffset;
|
|
484
495
|
yield* unparserContext.writeEarlier(handlerOffsetWriteLaters[i], ushortUnparser, handlerOffset);
|
|
485
|
-
if (handler.
|
|
496
|
+
if (handler.catchAllInstructionIndex !== undefined) {
|
|
486
497
|
yield* sleb128Unparser(-handler.handlers.length, unparserContext);
|
|
487
498
|
}
|
|
488
499
|
else {
|
|
@@ -491,23 +502,27 @@ export function createSectionUnparsers(poolBuilders) {
|
|
|
491
502
|
for (const handlerItem of handler.handlers) {
|
|
492
503
|
const typeIndex = getTypeIndex(handlerItem.type);
|
|
493
504
|
yield* uleb128Unparser(typeIndex, unparserContext);
|
|
494
|
-
|
|
505
|
+
// Convert handler address from instruction index to code unit offset
|
|
506
|
+
const handlerAddressCodeUnit = isoCodeUnit.unwrap(instructionIndexToCodeUnit(isoInstructionIndex.wrap(handlerItem.handlerInstructionIndex), indexToCodeUnitMap));
|
|
507
|
+
yield* uleb128Unparser(handlerAddressCodeUnit, unparserContext);
|
|
495
508
|
}
|
|
496
|
-
if (handler.
|
|
497
|
-
|
|
509
|
+
if (handler.catchAllInstructionIndex !== undefined) {
|
|
510
|
+
// Convert catchAllInstructionIndex from instruction index to code unit offset
|
|
511
|
+
const catchAllAddressCodeUnit = isoCodeUnit.unwrap(instructionIndexToCodeUnit(isoInstructionIndex.wrap(handler.catchAllInstructionIndex), indexToCodeUnitMap));
|
|
512
|
+
yield* uleb128Unparser(catchAllAddressCodeUnit, unparserContext);
|
|
498
513
|
}
|
|
499
514
|
}
|
|
500
515
|
}
|
|
501
516
|
};
|
|
502
517
|
};
|
|
503
|
-
async function
|
|
518
|
+
async function calculateRawInstructionsSize(instructions) {
|
|
504
519
|
let totalSize = 0;
|
|
505
520
|
const mockContext = {
|
|
506
521
|
position: 0,
|
|
507
522
|
writeLater: () => { throw new Error('Not supported'); },
|
|
508
523
|
writeEarlier: () => { throw new Error('Not supported'); },
|
|
509
524
|
};
|
|
510
|
-
for await (const chunk of
|
|
525
|
+
for await (const chunk of rawDalvikBytecodeUnparser(instructions, mockContext)) {
|
|
511
526
|
if (chunk instanceof Uint8Array) {
|
|
512
527
|
totalSize += chunk.length;
|
|
513
528
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { type Unparser } from './unparser.js';
|
|
2
2
|
import { type DalvikExecutable } from './dalvikExecutable.js';
|
|
3
|
-
import { type
|
|
4
|
-
export declare const dalvikExecutableUnparser: Unparser<DalvikExecutable<
|
|
3
|
+
import { type DalvikBytecodeOperation } from './dalvikBytecodeParser/addressConversion.js';
|
|
4
|
+
export declare const dalvikExecutableUnparser: Unparser<DalvikExecutable<DalvikBytecodeOperation[]>, Uint8Array>;
|
|
@@ -10,6 +10,7 @@ import { uint8ArrayUnparserOutputCompanion } from './unparserOutputCompanion.js'
|
|
|
10
10
|
import { uint8ArrayAsyncIterableToUint8Array } from './uint8Array.js';
|
|
11
11
|
const seed = process.env.SEED ? Number(process.env.SEED) : undefined;
|
|
12
12
|
// Use minimal bytecode for testing - simple nop and return-void instructions
|
|
13
|
+
// These operations have no branch offsets, so they work the same in all tiers
|
|
13
14
|
const arbitraryMinimalBytecode = fc.array(fc.oneof(fc.constant({
|
|
14
15
|
operation: 'nop',
|
|
15
16
|
}), fc.constant({
|
|
@@ -19,7 +20,7 @@ testProp('dalvikExecutableUnparser roundtrip', [createArbitraryDalvikExecutable(
|
|
|
19
20
|
// Unparse to bytes
|
|
20
21
|
const unparsedIterable = runUnparser(dalvikExecutableUnparser, dalvikExecutable, uint8ArrayUnparserOutputCompanion);
|
|
21
22
|
const bytes = await uint8ArrayAsyncIterableToUint8Array(unparsedIterable);
|
|
22
|
-
// Re-parse
|
|
23
|
+
// Re-parse (parser now outputs Tier 3 directly)
|
|
23
24
|
const reparsed = await runParser(dalvikExecutableParser, bytes, uint8ArrayParserInputCompanion, {
|
|
24
25
|
errorStack: true,
|
|
25
26
|
});
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
import { type Parser } from './parser.js';
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { type Parser, type ParserOutput, type ParserSequence } from './parser.js';
|
|
2
|
+
type DisjunctionParserOutput<Parsers extends readonly unknown[]> = ParserOutput<Parsers[number]>;
|
|
3
|
+
type InferSequenceFromParserArray<T extends readonly unknown[]> = ParserSequence<T[number]>;
|
|
4
|
+
export declare function createDisjunctionParser<const Parsers extends readonly Parser<any, any, any>[]>(childParsers: Parsers): Parser<DisjunctionParserOutput<Parsers>, InferSequenceFromParserArray<Parsers>>;
|
|
5
|
+
export {};
|