Newer
Older
alicedbg / src / adbg / object / format / lx.d
/// Linear Executable object format.
///
/// Sources:
/// - Windows SDK headers
/// - LX - Linear eXecutable Module Format Description, June 3, 1992
/// - IBM OS/2 16/32-BIT OBJECT MODULE FORMAT (OMF) AND LINEAR EXECUTABLE MODULE FORMAT (LX) Version 10, October 9, 1996
///
/// Authors: dd86k <dd@dax.moe>
/// Copyright: © dd86k <dd@dax.moe>
/// License: BSD-3-Clause-Clear
module adbg.object.format.lx;

import adbg.error;
import adbg.object.server : adbg_object_t, AdbgObject;
import adbg.machines;
import adbg.utils.bit;

// NOTE: LX is mainly 16-bit only and LE mixed 16/32-bit

extern (C):

/// LX magic for OS/2 binaries.
enum LX_MAGIC = CHAR16!"LX";
/// LE magic for Windows binaries.
enum LE_MAGIC = CHAR16!"LE";

enum : ushort {
	/// 80286 or better
	LX_CPU_80286	= 0x0001,
	/// 80386 or better
	LX_CPU_80386	= 0x0002,
	/// 80486 or better
	LX_CPU_80486	= 0x0003,
	
	/// OS/2
	LX_OS_OS2	= 0x0001,
	/// Windows
	LX_OS_WIN	= 0x0002,
	/// DOS 4.x
	LX_OS_DOS4	= 0x0003,
	/// Windows 386
	LX_OS_WINS386	= 0x0004,
	/// IBM Microkernel Personality Neutral (Workplace OS)
	LX_OS_NEUTRAL	= 0x0005,
}
enum : uint {
	/// Per-Process Library Initialization
	LX_FLAG_PROCLIBINIT	= 0x00000004,
	/// Internal fixups for the module have been applied.
	LX_FLAG_INTFIXUPS	= 0x00000010,
	/// External fixups for the module have been applied.
	LX_FLAG_EXTFIXUPS	= 0x00000020,
	/// Incompatible with PM windowing.
	LX_FLAG_INCOMPATPMWIN	= 0x00000100,
	/// Compatible with PM windowing.
	LX_FLAG_COMPATPMWIN	= 0x00000200,
	/// Uses PM windowing API.
	LX_FLAG_USESPMWIN	= 0x00000300, // Mask
	/// Module is not loadable.
	LX_FLAG_MODUNLOADABLE	= 0x00002000,
	/// Multiple-processor unsafe.
	LX_FLAG_MPUNSAFE	= 0x00080000,
	/// Per-process Library Termination.
	LX_FLAG_PROCLIBTERM	= 0x40000000, // Invalid for EXE
	
	/// Module type mask.
	LX_FLAG_MODTYPE_MASK	= 0x00038000,
	/// Program module.
	LX_FLAG_MODTYPE_PROG	= 0x00000000,
	/// Library module.
	LX_FLAG_MODTYPE_LIB	= 0x00008000,
	/// Protected Memory Library module.
	LX_FLAG_MODTYPE_PROTLIB	= 0x00018000,
	/// Physical Device Driver module.
	LX_FLAG_MODTYPE_PHYSDEV	= 0x00020000,
	/// Virtual Device Driver module (static).
	LX_FLAG_MODTYPE_VIRTDEV	= 0x00028000,
	/// Virtual Device Driver module (dynamic).
	LX_FLAG_MODTYPE_VXDDYN	= 0x00038000,
}

private enum E32RESBYTES3 = 196 - 176; // lx_header.sizeof

// winnt.h:_IMAGE_VXD_HEADER
/// LX/LE header
struct lx_header { // NOTE: Names are taken from spec except for its "e32_exe" name
	/// Header magic. "LX" or "LE"
	ushort magic;
	/// Byte Ordering.
	///
	/// 0 for little-endian, 1 for big-endian.
	ubyte border;
	/// Word Ordering.
	///
	/// 0 for little-endian, 1 for big-endian.
	ubyte worder;
	/// Linear EXE Format Level.
	///
	/// The  Linear EXE Format Level is set  to  0  for  the
	/// initial version  of  the 32-bit linear  EXE  format.
	/// Each  incompatible  change to the  linear EXE format
	/// must increment this value.  This  allows the  system
	/// to recognized future EXE file versions  so  that  an
	/// appropriate  error message  may  be displayed  if an
	/// attempt is made to load them.
	uint level;
	/// Module CPU Type.
	///
	/// 1=i286 and later, 2=i386 and later, 3=i486 and later
	ushort cpu;
	/// Module OS Type.
	ushort os;
	/// Version of the linear EXE module.
	uint ver;
	/// Flag bits for the module.
	uint mflags;
	/// Number of pages in module.
	uint mpages;
	/// The Object number to which the Entry Address is relative.
	uint startobj;
	/// Entry Address of module.
	uint eip;
	/// Starting stack address of module.
	uint stackobj;
	/// The size of one page for this system.
	uint esp;
	/// Module page size.
	uint pagesize;
	union {
		/// Size of last page. (LE)
		uint lastpage;
		/// The shift left bits for page offsets. (LX)
		uint pageshift;
	}
	/// Total size of the fixup information in bytes.
	uint fixupsize;
	/// Checksum for fixup information.
	uint fixupsum;
	/// Size of memory resident tables.
	uint ldrsize;
	/// Checksum for loader section.
	uint ldrsum;
	/// Object Table offset.
	uint objtab;
	/// Object Table Count.
	uint objcnt;
	/// Object Page Table offset.
	uint objmap;
	/// Object Iterated Pages offset.
	uint itermap;
	/// Resource Table offset.
	uint rsrctab;
	/// Number of entries in Resource Table.
	uint rsrccnt;
	/// Resident Name Table offset.
	uint restab;
	/// Entry Table offset.
	uint enttab;
	/// Module Format Directives Table offset.
	uint dirtab;
	/// Number of Module Format Directives in the Table.
	uint dircnt;
	/// Fixup Page Table offset.
	uint fpagetab;
	/// Fixup Record Table Offset
	uint frectab;
	/// Import Module Name Table offset.
	uint impmod;
	/// The number of entries in the Import Module Name Table.
	uint impmodcnt;
	/// Import Procedure Name Table offset.
	uint impproc;
	/// Per-Page Checksum Table offset.
	uint pagesum;
	/// Data Pages Offset.
	uint datapage;
	/// Number of Preload pages for this module.
	uint preload;
	/// Non-Resident Name Table offset.
	uint nrestab;
	/// Number of bytes in the Non-resident name table.
	uint cbnrestab;
	/// Non-Resident Name Table Checksum.
	uint nressum;
	/// The Auto Data Segment Object number.
	uint autodata;
	/// Debug Information offset.
	uint debuginfo;
	/// Debug Information length;
	uint debuglen;
	/// Instance pages in preload section.
	uint instpreload;
	/// Instance pages in demand section.
	uint instdemand;
	/// Heap size added to the Auto DS Object.
	uint heapsize;
	
	// NOTE: winnt.h defines
	//       - BYTE   e32_res3[12];
	//       - DWORD  e32_winresoff;
	//       - DWORD  e32_winreslen;
	//       - WORD   e32_devid;
	//       - WORD   e32_ddkver;
	
	/// Size of requested stack.
	uint stacksize;
	union {
		/// Pad structure to 196 bytes
		ubyte[E32RESBYTES3] res;
		struct { // LE specifics
			ubyte[8] res1;
			uint winresoff;	/// Windows VxD version info resource offset
			uint winreslen;	/// Windows VxD version info resource lenght
			ushort device_id;	/// Windows VxD device ID
			ushort ddk_version;	/// Windows VxD DDK version (usually 0x030A)
		}
	}
}

struct lx_record {
	uint size;	/// Object virtual size
	uint addr;	/// Base virtual address
	uint flags;
	uint mapidx;	/// Page map index
	uint mapsize;	/// Count of entries in page map
	uint reserved;
}

// Record flags
enum {
	LX_OBJ_READABLE        = 0x0001,
	LX_OBJ_WRITEABLE       = 0x0002,
	LX_OBJ_EXECUTABLE      = 0x0004,
	LX_OBJ_RESOURCE        = 0x0008,
	LX_OBJ_DISCARDABLE     = 0x0010,
	LX_OBJ_SHARABLE        = 0x0020,
	LX_OBJ_HAS_PRELOAD     = 0x0040,
	LX_OBJ_HAS_INVALID     = 0x0080,
	LX_OBJ_PERM_SWAPPABLE  = 0x0100,  /* LE */
	LX_OBJ_HAS_ZERO_FILL   = 0x0100,  /* LX */
	LX_OBJ_PERM_RESIDENT   = 0x0200,
	LX_OBJ_PERM_CONTIGUOUS = 0x0300,  /* LX */
	LX_OBJ_PERM_LOCKABLE   = 0x0400,
	LX_OBJ_ALIAS_REQUIRED  = 0x1000,
	LX_OBJ_BIG             = 0x2000,
	LX_OBJ_CONFORMING      = 0x4000,
	LX_OBJ_IOPL            = 0x8000,
}

struct lx_le_map_entry {  /* LE */
	ubyte[3] page_num;    /* 24-bit page number in .exe file */
	ubyte    flags;
}

struct lx_lx_map_entry { /* LX */
	/// Offset from Preload page start
	/// shifted by page_shift in hdr
	uint   page_offset;
	/// Size of entry in bytes.
	ushort data_size;
	ushort flags;
}

union lx_map_entry {
	lx_le_map_entry    le;
	lx_lx_map_entry    lx;
}

// Page entries
enum {
	PAGE_VALID      = 0,
	PAGE_ITERATED   = 1,
	PAGE_INVALID    = 2,
	PAGE_ZEROED     = 3,
	PAGE_RANGE      = 4,
}

struct lx_flat_bundle_prefix {
	ubyte  b32_cnt;
	ubyte  b32_type;
	ushort b32_obj;
}

struct flat_null_prefix {
	ubyte b32_cnt;
	ubyte b32_type;
}

/* values for the b32_type field */
alias bundle_types = int;
enum {
	FLT_BNDL_EMPTY  = 0,
	FLT_BNDL_ENTRY16,
	FLT_BNDL_GATE16,
	FLT_BNDL_ENTRY32,
	FLT_BNDL_ENTRYFWD
}

struct lx_flat_bundle_entry32 {
	ubyte e32_flags;      /* flag bits are same as in OS/2 1.x */
	uint  e32_offset;
}

struct lx_flat_bundle_gate16 {
	ubyte  e32_flags;      /* flag bits are same as in OS/2 1.x */
	ushort offset;
	ushort callgate;
}

/*
 * other, unused bundle types are:
 */

struct lx_flat_bundle_entry16 {
	ubyte  e32_flags;      /* flag bits are same as in OS/2 1.x */
	ushort e32_offset;
}

struct lx_flat_bundle_entryfwd {
	ubyte  e32_flags;      /* flag bits are same as in OS/2 1.x */
	ushort modord;
	uint   value;
}

struct lx_flat_res_table {
	ushort type_id;
	ushort name_id;
	uint   res_size;
	ushort object;
	uint   offset;
}

/* fixup record source flags */
enum {
	LX_OSF_SOURCE_MASK             = 0x0F,
	LX_OSF_SOURCE_BYTE             = 0x00,
	LX_OSF_SOURCE_UNDEFINED        = 0x01,
	LX_OSF_SOURCE_SEG              = 0x02,
	LX_OSF_SOURCE_PTR_32           = 0x03,
	LX_OSF_SOURCE_OFF_16           = 0x05,
	LX_OSF_SOURCE_PTR_48           = 0x06,
	LX_OSF_SOURCE_OFF_32           = 0x07,
	LX_OSF_SOURCE_OFF_32_REL       = 0x08,
	LX_OSF_SFLAG_FIXUP_TO_ALIAS    = 0x10,
	LX_OSF_SFLAG_LIST              = 0x20,
}

/* fixup record target flags */
enum {
	LX_OSF_TARGET_MASK             = 0x03,
	LX_OSF_TARGET_INTERNAL         = 0x00,
	LX_OSF_TARGET_EXT_ORD          = 0x01,
	LX_OSF_TARGET_EXT_NAME         = 0x02,
	LX_OSF_TARGET_INT_VIA_ENTRY    = 0x03,
	LX_OSF_TFLAG_ADDITIVE_VAL      = 0x04,
	LX_OSF_TFLAG_INT_CHAIN         = 0x08,
	LX_OSF_TFLAG_OFF_32BIT         = 0x10,
	LX_OSF_TFLAG_ADD_32BIT         = 0x20,
	LX_OSF_TFLAG_OBJ_MOD_16BIT     = 0x40,
	LX_OSF_TFLAG_ORDINAL_8BIT      = 0x80,
}

int adbg_object_lx_load(adbg_object_t *o) {
	
	o.format = AdbgObject.lx;
	o.i.lx.header = cast(lx_header*)o.i.mz.newbase;
	
	//TODO: Deal with word order
	
	return 0;
}

const(char)* adbg_object_lx_cputype_string(ushort cpu) {
	switch (cpu) {
	case LX_CPU_80286:	return "80286";
	case LX_CPU_80386:	return "80386";
	case LX_CPU_80486:	return "80486";
	default:	return "Unknown";
	}
}

const(char)* adbg_object_lx_ostype_string(ushort os) {
	switch (os) {
	case LX_OS_OS2:	return "OS/2";
	case LX_OS_WIN:	return "Windows";
	case LX_OS_DOS4:	return "DOS 4.x";
	case LX_OS_WINS386:	return "Windows 386";
	case LX_OS_NEUTRAL:	return "IBM Microkernel";
	default:	return "Unknown";
	}
}

const(char)* adbg_object_lx_modtype_string(uint flags) {
	switch (flags & LX_FLAG_MODTYPE_MASK) { // 17:15
	case LX_FLAG_MODTYPE_PROG:	return "Program";
	case LX_FLAG_MODTYPE_LIB:	return "Library";
	case LX_FLAG_MODTYPE_PROTLIB:	return "Protected Memory Library";
	case LX_FLAG_MODTYPE_PHYSDEV:	return "Physical Device Driver";
	case LX_FLAG_MODTYPE_VIRTDEV:	return "Static Virtual Device Driver";
	case LX_FLAG_MODTYPE_VXDDYN:	return "Dynamic Virtual Device Driver (VxD)";
	default:	return "Unkown";
	}
}