UNPKG

3.08 kBPlain TextView Raw
1// tslint:disable prefer-switch
2import { assertByteCode, Byte, Op, OpCode } from '@neo-one/client-common-esnext-esm';
3import { BinaryReader, utils } from './utils';
4
5const createHexString = (bytes: Buffer): string => {
6 let mutableResult = '';
7 bytes.forEach((byte) => {
8 mutableResult += `${byte.toString(16).padStart(2, '0')}`;
9 });
10
11 return `0x${mutableResult}`;
12};
13
14interface Line {
15 readonly pc: number;
16 readonly value: string;
17}
18
19export const disassembleByteCode = (bytes: Buffer): ReadonlyArray<Line> => {
20 const reader = new BinaryReader(bytes);
21
22 const mutableResult: Array<[number, OpCode | 'UNKNOWN', string | undefined]> = [];
23 // tslint:disable-next-line no-loop-statement
24 while (reader.hasMore()) {
25 const pc = reader.index;
26 const byte = assertByteCode(reader.readUInt8());
27
28 const pushBytes = byte >= Op.PUSHBYTES1 && byte <= Op.PUSHBYTES75;
29 const pushData1 = byte === Op.PUSHDATA1;
30 const pushData2 = byte === Op.PUSHDATA2;
31 const pushData4 = byte === Op.PUSHDATA4;
32
33 const opCode = Byte[byte];
34
35 if (pushBytes || pushData1 || pushData2 || pushData4) {
36 let numBytes;
37 if (pushBytes) {
38 numBytes = byte;
39 } else if (pushData1) {
40 numBytes = reader.readUInt8();
41 } else if (pushData2) {
42 numBytes = reader.readUInt16LE();
43 } else {
44 numBytes = reader.readInt32LE();
45 }
46 mutableResult.push([pc, opCode, createHexString(reader.readBytes(numBytes))]);
47 } else if (byte === Op.JMP || byte === Op.JMPIF || byte === Op.JMPIFNOT || byte === Op.CALL) {
48 mutableResult.push([pc, opCode, `${reader.readInt16LE()}`]);
49 } else if (byte === Op.APPCALL || byte === Op.TAILCALL) {
50 const mutableAppBytes = [...reader.readBytes(20)];
51 mutableAppBytes.reverse();
52 mutableResult.push([pc, opCode, createHexString(Buffer.from(mutableAppBytes))]);
53 } else if (byte === Op.SYSCALL) {
54 mutableResult.push([pc, opCode, utils.toASCII(reader.readVarBytesLE(252))]);
55 // tslint:disable-next-line strict-type-predicate
56 } else if (byte === Op.CALL_E || byte === Op.CALL_ET) {
57 const returnValueCount = reader.readBytes(1);
58 const parametersCount = reader.readBytes(1);
59 const mutableAppBytes = [...reader.readBytes(20)];
60 mutableAppBytes.reverse();
61 mutableResult.push([
62 pc,
63 opCode,
64 `${createHexString(returnValueCount)} ${createHexString(parametersCount)} ${createHexString(
65 Buffer.from(mutableAppBytes),
66 )}`,
67 ]);
68 } else if (byte === Op.CALL_ED || byte === Op.CALL_EDT || byte === Op.CALL_I) {
69 const returnValueCount = reader.readBytes(1);
70 const parametersCount = reader.readBytes(1);
71 mutableResult.push([pc, opCode, `${createHexString(returnValueCount)} ${createHexString(parametersCount)}`]);
72 } else {
73 mutableResult.push([pc, opCode, undefined]);
74 }
75 }
76
77 return mutableResult.map(([index, opCode, val]) => ({
78 pc: index,
79 value: `${index.toString().padStart(4, '0')}:${opCode}${val === undefined ? '' : ` ${val}`}`,
80 }));
81};
82
\No newline at end of file