using System; using System.Collections.Generic; using System.Runtime.InteropServices; namespace pkNX.Structures; [StructLayout(LayoutKind.Sequential)] public class AmxHeader { // Cell Size magic verification public const ushort MAGIC_32 = 0xf1e0; public const ushort MAGIC_64 = 0xf1e1; public const ushort MAGIC_16 = 0xf1e2; /// Size of the "file" public int Size; // 0x00 /// Signature public ushort Magic; // 0x04 /// File format version public byte FileVersion; // 0x06 /// Required version of the AMX public byte AMXVersion; // 0x07 /// Feature flags public AmxFlags Flags; // 0x08 /// Size of a definition record public short DefinitionSize; // 0x0A /// Initial value of COD - code block public int COD; // 0x0C /// initial value of DAT - data block public int Data; // 0x10 /// Initial value of HEA - start of the heap public int Heap; // 0x14 /// Initial value of STP - stack top public int StackTop; // 0x18 /// Initial value of CIP - the instruction pointer public int CurrentInstructionPointer; // 0x20 /// Offset to the "public functions" table public int Publics; // 0x24 /// Offset to the "native functions" table public int Natives; // 0x28 /// Offset to the table of libraries public int Libraries; // 0x2C /// Offset to the "public variables" table public int PublicVars; // 0x30 /// Offset to the "public tagnames" table public int Tags; // 0x34 /// Offset to the name table public int NameTable; // 0x38 /// Offset to the overlay table public int Overlays; // 0x3C public int CellSize { get { return Magic switch { MAGIC_16 => 16, MAGIC_32 => 32, MAGIC_64 => 64, _ => throw new ArgumentException("Invalid Magic identifier."), }; } } } /* File format version * 0 original version * 1 opcodes JUMP.pri, SWITCH and CASETBL * 2 compressed files * 3 public variables * 4 opcodes SWAP.pri/alt and PUSHADDR * 5 tagnames table * 6 reformatted header * 7 name table, opcodes SYMTAG & SYSREQ.D * 8 opcode BREAK, renewed debug interface * 9 macro opcodes * 10 position-independent code, overlays, packed instructions * 11 relocating instructions for the native interface, reorganized instruction set */ /// /// Debug data at the end of an amx /// [StructLayout(LayoutKind.Sequential)] public class AmxDebugHeader { public const ushort MAGIC_DEBUG = 0xf1ef; public int Size; public ushort Magic; public byte FileVersion; public byte AMXVersion; public AmxFlags Flags; public short Files; public short Lines; public short Symbols; public short Tags; public short Automatons; public short States; public const int SIZE = 36; } public class TableRecord { public TableRecord(string name, uint address) { Name = name; Address = address; } public string Name { get; } public uint Address { get; } } public class Tag { public Tag(string name, uint tagID) { TagID = tagID; Name = name; } public uint TagID { get; } public string Name { get; } } public class Dimension { public Dimension(int tagID, Tag tag, int size) { TagID = tagID; Tag = tag; Size = size; } public int TagID { get; } public Tag Tag { get; } public int Size { get; } } public class Argument { public Argument(VariableType type, string name, int tagID, Tag tag, Dimension[] dims) { Type = type; Name = name; TagID = tagID; Tag = tag; Dimensions = dims; } public int TagID { get; } public VariableType Type { get; } public string Name { get; } public Tag Tag { get; } public Dimension[] Dimensions { get; } } public enum Register : uint { Pri, Alt, } public enum Scope : uint { Global, Local, Static, } public class Variable { public Variable(int addr, int tagID, Tag tag, uint codeStart, uint codeEnd, VariableType type, Scope scope, string name, Dimension[] dims = null) { Address = addr; TagID = (uint)tagID; Tag = tag; CodeStart = codeStart; CodeEnd = codeEnd; Type = type; Scope = scope; Name = name; Dims = dims; } public int Address { get; } public uint CodeStart { get; } public uint CodeEnd { get; } public string Name { get; } public VariableType Type { get; } public Scope Scope { get; } public Tag Tag { get; set; } public uint TagID { get; } public Dimension[] Dims { get; } } public class Signature { public Signature(string name) => Name = name; public Tag ReturnType { get; set; } public uint TagID { get; protected set; } public string Name { get; } public Argument[] Args { get; protected set; } } public class Native : Signature { public Native(string name, int index) : base(name) => Index = index; public int Index { get; } public void SetDebugInfo(int tagID, Tag tag, Argument[] args) { TagID = (uint)tagID; ReturnType = tag; Args = args; } } public class Function : Signature { public Function(uint addr, uint codeStart, uint codeEnd, string name, Tag tag) : base(name) { Address = addr; CodeStart = codeStart; CodeEnd = codeEnd; ReturnType = tag; } public Function(uint addr, uint codeStart, uint codeEnd, string name, uint tagID) : base(name) { Address = addr; CodeStart = codeStart; CodeEnd = codeEnd; TagID = tagID; } public void SetArguments(List from) => Args = from.ToArray(); public uint Address { get; } public uint CodeStart { get; } public uint CodeEnd { get; } public bool Within(uint pc) => pc >= CodeStart && pc < CodeEnd; }