using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyMetadata("IsTrimmable", "True")] [assembly: AssemblyCompany("Samboy063")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Simple, zero-dependency disassembler for WebAssembly bytecode")] [assembly: AssemblyFileVersion("2022.1.0.0")] [assembly: AssemblyInformationalVersion("2022.1.0-development.866+f87ccd1")] [assembly: AssemblyProduct("WasmDisassembler")] [assembly: AssemblyTitle("WasmDisassembler")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/SamboyCoding/Cpp2IL.git")] [assembly: AssemblyVersion("2022.1.0.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace WasmDisassembler { public static class Disassembler { public static List Disassemble(byte[] body, uint virtualAddress) { List list = new List(); using MemoryStream memoryStream = new MemoryStream(body); using BinaryReader binaryReader = new BinaryReader(memoryStream); while (memoryStream.Position < memoryStream.Length) { uint num = virtualAddress + (uint)(int)memoryStream.Position; WasmMnemonic wasmMnemonic = (WasmMnemonic)binaryReader.ReadByte(); if ((int)wasmMnemonic > 191) { throw new Exception($"Encountered invalid mnemonic {wasmMnemonic} at ip 0x{num:X}, byte array position {memoryStream.Position}."); } WasmInstruction item = binaryReader.ReadInstruction(wasmMnemonic); item.Ip = num; item.NextIp = virtualAddress + (uint)(int)memoryStream.Position; list.Add(item); } return list; } private static WasmInstruction ReadInstruction(this BinaryReader reader, WasmMnemonic mnemonic) { WasmInstruction wasmInstruction = default(WasmInstruction); wasmInstruction.Mnemonic = mnemonic; WasmInstruction result = wasmInstruction; Type[] operandTypes = mnemonic.GetOperandTypes(); if (operandTypes.Length == 0) { result.Operands = Array.Empty(); return result; } result.Operands = operandTypes.Select(reader.ReadPrimitive).ToArray(); return result; } private static Type[] GetOperandTypes(this WasmMnemonic mnemonic) { if ((int)mnemonic >= 40 && (int)mnemonic <= 62) { return new Type[2] { typeof(LEB128), typeof(LEB128) }; } switch (mnemonic) { case WasmMnemonic.Block: case WasmMnemonic.Loop: case WasmMnemonic.If: case WasmMnemonic.Br: case WasmMnemonic.BrIf: case WasmMnemonic.LocalGet: case WasmMnemonic.LocalSet: case WasmMnemonic.LocalTee: case WasmMnemonic.GlobalGet: case WasmMnemonic.GlobalSet: return new Type[1] { typeof(byte) }; case WasmMnemonic.Call: case WasmMnemonic.I32Const: case WasmMnemonic.I64Const: return new Type[1] { typeof(LEB128) }; case WasmMnemonic.F32Const: return new Type[1] { typeof(float) }; case WasmMnemonic.F64Const: return new Type[1] { typeof(double) }; case WasmMnemonic.CallIndirect: return new Type[2] { typeof(LEB128), typeof(byte) }; default: return Array.Empty(); } } internal static object ReadPrimitive(this BinaryReader reader, Type type) { if (type == typeof(bool)) { return reader.ReadBoolean(); } if (type == typeof(char)) { return reader.ReadChar(); } if (type == typeof(int)) { return reader.ReadInt32(); } if (type == typeof(uint)) { return reader.ReadUInt32(); } if (type == typeof(short)) { return reader.ReadInt16(); } if (type == typeof(ushort)) { return reader.ReadUInt16(); } if (type == typeof(sbyte)) { return reader.ReadSByte(); } if (type == typeof(byte)) { return reader.ReadByte(); } if (type == typeof(long)) { return reader.ReadInt64(); } if (type == typeof(ulong)) { return reader.ReadUInt64(); } if (type == typeof(float)) { return reader.ReadSingle(); } if (type == typeof(double)) { return reader.ReadDouble(); } if (type == typeof(LEB128)) { return reader.BaseStream.ReadLEB128Unsigned(); } throw new Exception($"Bad primitive type: {type}"); } } public static class LEB128 { private const long SIGN_EXTEND_MASK = -1L; private const int INT64_BITSIZE = 64; public static void WriteLEB128Signed(this Stream stream, long value) { stream.WriteLEB128Signed(value, out var _); } public static void WriteLEB128Signed(this Stream stream, long value, out int bytes) { bytes = 0; bool flag = true; while (flag) { byte b = (byte)(value & 0x7F); value >>= 7; bool flag2 = (b & 0x40) != 0; flag = (value != 0L || flag2) && !(value == -1 && flag2); if (flag) { b = (byte)(b | 0x80u); } stream.WriteByte(b); bytes++; } } public static void WriteLEB128Unsigned(this Stream stream, ulong value) { stream.WriteLEB128Unsigned(value, out var _); } public static void WriteLEB128Unsigned(this Stream stream, ulong value, out int bytes) { bytes = 0; bool flag = true; while (flag) { byte b = (byte)(value & 0x7F); value >>= 7; flag = value != 0; if (flag) { b = (byte)(b | 0x80u); } stream.WriteByte(b); bytes++; } } public static long ReadLEB128Signed(this Stream stream) { int bytes; return stream.ReadLEB128Signed(out bytes); } public static long ReadLEB128Signed(this Stream stream, out int bytes) { bytes = 0; long num = 0L; int num2 = 0; bool flag = true; bool flag2 = false; while (flag) { int num3 = stream.ReadByte(); if (num3 < 0) { throw new InvalidOperationException("Unexpected end of stream"); } byte num4 = (byte)num3; bytes++; flag = (num4 & 0x80) != 0; flag2 = (num4 & 0x40) != 0; long num5 = (long)num4 & 0x7FL; num |= num5 << num2; num2 += 7; } if (num2 < 64 && flag2) { num |= -1L << num2; } return num; } public static ulong ReadLEB128Unsigned(this Stream stream) { int bytes; return stream.ReadLEB128Unsigned(out bytes); } public static ulong ReadLEB128Unsigned(this Stream stream, out int bytes) { bytes = 0; ulong num = 0uL; int num2 = 0; bool flag = true; while (flag) { int num3 = stream.ReadByte(); if (num3 < 0) { throw new InvalidOperationException("Unexpected end of stream"); } byte num4 = (byte)num3; bytes++; flag = (num4 & 0x80) != 0; ulong num5 = (ulong)num4 & 0x7FuL; num |= num5 << num2; num2 += 7; } return num; } } public struct WasmInstruction { public uint Ip; public uint NextIp; public WasmMnemonic Mnemonic; public object[] Operands; public override string ToString() { if (Operands.Length != 0) { return $"0x{Ip:X} {Mnemonic} {string.Join(", ", Operands)}"; } return $"0x{Ip:X} {Mnemonic}"; } } public enum WasmMnemonic : byte { Unreachable = 0, Nop = 1, Block = 2, Loop = 3, If = 4, Else = 5, Proposed_Try = 6, Proposed_Catch = 7, Proposed_Throw = 8, Proposed_Rethrow = 9, Proposed_BrOnExn = 10, End = 11, Br = 12, BrIf = 13, BrTable = 14, Return = 15, Call = 16, CallIndirect = 17, Proposed_ReturnCall = 18, Proposed_ReturnCallIndirect = 19, Reserved_14 = 20, Reserved_15 = 21, Reserved_16 = 22, Reserved_17 = 23, Reserved_18 = 24, Reserved_19 = 25, Drop = 26, Select = 27, Proposed_SelectT = 28, Reserved_1D = 29, Reserved_1E = 30, Reserved_1F = 31, LocalGet = 32, LocalSet = 33, LocalTee = 34, GlobalGet = 35, GlobalSet = 36, Proposed_TableGet = 37, Proposed_TableSet = 38, Reserved_27 = 39, I32Load = 40, I64Load = 41, F32Load = 42, F64Load = 43, I32Load8_S = 44, I32Load8_U = 45, I32Load16_S = 46, I32Load16_U = 47, I64Load8_S = 48, I64Load8_U = 49, I64Load16_S = 50, I64Load16_U = 51, I64Load32_S = 52, I64Load32_U = 53, I32Store = 54, I64Store = 55, F32Store = 56, F64Store = 57, I32Store8 = 58, I32Store16 = 59, I64Store8 = 60, I64Store16 = 61, I64Store32 = 62, MemorySize = 63, MemoryGrow = 64, I32Const = 65, I64Const = 66, F32Const = 67, F64Const = 68, I32Eqz = 69, I32Eq = 70, I32Ne = 71, I32Lt_S = 72, I32Lt_U = 73, I32Gt_S = 74, I32Gt_U = 75, I32Le_S = 76, I32Le_U = 77, I32Ge_S = 78, I32Ge_U = 79, I64Eqz = 80, I64Eq = 81, I64Ne = 82, I64Lt_S = 83, I64Lt_U = 84, I64Gt_S = 85, I64Gt_U = 86, I64Le_S = 87, I64Le_U = 88, I64Ge_S = 89, I64Ge_U = 90, F32Eq = 91, F32Ne = 92, F32Lt = 93, F32Gt = 94, F32Le = 95, F32Ge = 96, F64Eq = 97, F64Ne = 98, F64Lt = 99, F64Gt = 100, F64Le = 101, F64Ge = 102, I32Clz = 103, I32Ctz = 104, I32PopCnt = 105, I32Add = 106, I32Sub = 107, I32Mul = 108, I32Div_S = 109, I32Div_U = 110, I32Rem_S = 111, I32Rem_U = 112, I32And = 113, I32Or = 114, I32Xor = 115, I32Shl = 116, I32Shr_S = 117, I32Shr_U = 118, I32Rotl = 119, I32Rotr = 120, I64Clz = 121, I64Ctz = 122, I64PopCnt = 123, I64Add = 124, I64Sub = 125, I64Mul = 126, I64Div_S = 127, I64Div_U = 128, I64Rem_S = 129, I64Rem_U = 130, I64And = 131, I64Or = 132, I64Xor = 133, I64Shl = 134, I64Shr_S = 135, I64Shr_U = 136, I64Rotl = 137, I64Rotr = 138, F32Abs = 139, F32Neg = 140, F32Ceil = 141, F32Floor = 142, F32Trunc = 143, F32Nearest = 144, F32Sqrt = 145, F32Add = 146, F32Sub = 147, F32Mul = 148, F32Div = 149, F32Min = 150, F32Max = 151, F32Copysign = 152, F64Abs = 153, F64Neg = 154, F64Ceil = 155, F64Floor = 156, F64Trunc = 157, F64Nearest = 158, F64Sqrt = 159, F64Add = 160, F64Sub = 161, F64Mul = 162, F64Div = 163, F64Min = 164, F64Max = 165, F64Copysign = 166, I32Wrap_I64 = 167, I32Trunc_F32_S = 168, I32Trunc_F32_U = 169, I32Trunc_F64_S = 170, I32Trunc_F64_U = 171, I64Extend_I32_S = 172, I64Extend_I32_U = 173, I64Trunc_F32_S = 174, I64Trunc_F32_U = 175, I64Trunc_F64_S = 176, I64Trunc_F64_U = 177, F32Convert_I32_S = 178, F32Convert_I32_U = 179, F32Convert_I64_S = 180, F32Convert_I64_U = 181, F32Demote_F64 = 182, F64Convert_I32_S = 183, F64Convert_I32_U = 184, F64Convert_I64_S = 185, F64Convert_I64_U = 186, F64Promote_F32 = 187, I32Reinterpret_F32 = 188, I64Reinterpret_F64 = 189, F32Reinterpret_I32 = 190, F64Reinterpret_I64 = 191, LastValid = 191, Proposed_I32Extend8_S = 192, Proposed_I32Extend16_S = 193, Proposed_I64Extend8_S = 194, Proposed_I64Extend16_S = 195, Proposed_I64Extend32_S = 196, Proposed_RefNull = 208, Proposed_RefIsNull = 209, Proposed_RefFunc = 210, Proposed_FC_Extensions = 252, Proposed_SIMD = 253 } }