diff --git a/dumper/format/mscoff.d b/dumper/format/mscoff.d index 3e94dc40..594cdb5f 100644 --- a/dumper/format/mscoff.d +++ b/dumper/format/mscoff.d @@ -15,19 +15,21 @@ import dumper; int dump_mscoff(adbg_object_t *o) { if (SELECTED(Select.headers)) - dump_mscoff_hdr(o); + dump_mscoff_header(o); return 0; } private: -void dump_mscoff_hdr(adbg_object_t *o) { +void dump_mscoff_header(adbg_object_t *o) { print_header("Header"); - switch (o.i.mscoff.import_header.Version) { + mscoff_import_header_t *header = cast(mscoff_import_header_t*)adbg_object_mscoff_header(o); + + switch (header.Version) { case MSCOFF_VERSION_IMPORT: // 0 - with (o.i.mscoff.import_header) { + with (header) { print_x16("Sig1", Sig1); print_x16("Sig2", Sig2); print_u16("Version", Version); @@ -39,7 +41,8 @@ void dump_mscoff_hdr(adbg_object_t *o) { } break; case MSCOFF_VERSION_ANON: // 1 - with (o.i.mscoff.anon_header) { + mscoff_anon_header_t *header1 = cast(mscoff_anon_header_t*)header; + with (header1) { print_x16("Sig1", Sig1); print_x16("Sig2", Sig2); print_u16("Version", Version); @@ -52,7 +55,8 @@ void dump_mscoff_hdr(adbg_object_t *o) { } break; case MSCOFF_VERSION_ANONV2: // 2 - with (o.i.mscoff.anon_v2_header) { + mscoff_anon_header_v2_t *header2 = cast(mscoff_anon_header_v2_t*)header; + with (header2) { print_x16("Sig1", Sig1); print_x16("Sig2", Sig2); print_u16("Version", Version); diff --git a/src/adbg/object/format/mscoff.d b/src/adbg/object/format/mscoff.d index e6988fd6..3ecb8c66 100644 --- a/src/adbg/object/format/mscoff.d +++ b/src/adbg/object/format/mscoff.d @@ -11,8 +11,11 @@ module adbg.object.format.mscoff; // NOTE: PE32/PE-COFF is an extension of COFF and MZ -import adbg.object.server : AdbgObject, adbg_object_t; +import adbg.object.server; import adbg.utils.uid; +import adbg.utils.math; +import adbg.error; +import core.stdc.stdlib; // // Non-COFF Object file headers (.obj from VS2002-VS2015, mscoff) @@ -44,7 +47,7 @@ enum { MSCOFF_IMPORT_NAME_EXPORTAS = 4, } -struct mscoff_import_header { // IMPORT_OBJECT_HEADER +struct mscoff_import_header_t { // IMPORT_OBJECT_HEADER /// Must be IMAGE_FILE_MACHINE_UNKNOWN. ushort Sig1; /// Must be 0xFFFF. @@ -64,7 +67,7 @@ struct mscoff_import_header { // IMPORT_OBJECT_HEADER ulong Flags; } -struct mscoff_anon_header { // ANON_OBJECT_HEADER +struct mscoff_anon_header_t { // ANON_OBJECT_HEADER ushort Sig1; // Must be IMAGE_FILE_MACHINE_UNKNOWN ushort Sig2; // Must be 0xffff ushort Version; // >= 1 (implies the CLSID field is present) @@ -75,7 +78,7 @@ struct mscoff_anon_header { // ANON_OBJECT_HEADER uint SizeOfData; // Size of data that follows the header } -struct mscoff_anon_header_v2 { // ANON_OBJECT_HEADER_V2 +struct mscoff_anon_header_v2_t { // ANON_OBJECT_HEADER_V2 ushort Sig1; // Must be IMAGE_FILE_MACHINE_UNKNOWN ushort Sig2; // Must be 0xffff ushort Version; // >= 2 (implies the Flags field is present - otherwise V1) @@ -89,7 +92,7 @@ struct mscoff_anon_header_v2 { // ANON_OBJECT_HEADER_V2 uint MetaDataOffset; // Offset of CLR metadata } -struct mscoff_anon_header_bigobj { // ANON_OBJECT_HEADER_BIGOBJ +struct mscoff_anon_header_bigobj_t { // ANON_OBJECT_HEADER_BIGOBJ /* same as ANON_OBJECT_HEADER_V2 */ ushort Sig1; // Must be IMAGE_FILE_MACHINE_UNKNOWN ushort Sig2; // Must be 0xffff @@ -112,7 +115,7 @@ struct mscoff_anon_header_bigobj { // ANON_OBJECT_HEADER_BIGOBJ // Same as PE32 enum SYMNMLEN = 8; -struct mscoff_anon_symbol_table32 { +struct mscoff_anon_symbol_table32_t { union { ubyte[SYMNMLEN] Name; struct { @@ -126,9 +129,9 @@ struct mscoff_anon_symbol_table32 { ubyte StorageClass; ubyte NumberOfAuxSymbols; } -static assert(mscoff_anon_symbol_table32.sizeof == 20); +static assert(mscoff_anon_symbol_table32_t.sizeof == 20); -struct mscoff_anon_symbol_table { align(1): +struct mscoff_anon_symbol_table_t { align(1): ubyte[SYMNMLEN] Name; uint Value; short SectionNumber; @@ -136,12 +139,60 @@ struct mscoff_anon_symbol_table { align(1): ubyte StorageClass; ubyte NumberOfAuxSymbols; } -static assert(mscoff_anon_symbol_table.sizeof == 18); +static assert(mscoff_anon_symbol_table_t.sizeof == 18); + +private +struct internal_mscoff_t { + union { + mscoff_import_header_t import_header; + mscoff_anon_header_t anon_header; + mscoff_anon_header_v2_t anonv2_header; + } +} + +private enum MAX1 = MAX!(mscoff_anon_header_t.sizeof, mscoff_anon_header_v2_t.sizeof); +private enum MAX2 = MAX!(MAX1, mscoff_import_header_t.sizeof); int adbg_object_mscoff_load(adbg_object_t *o) { + o.internal = calloc(1, internal_mscoff_t.sizeof); + if (o.internal == null) + return adbg_oops(AdbgError.crt); + if (adbg_object_read_at(o, 0, o.internal, MAX2)) + return adbg_errno(); + o.format = AdbgObject.mscoff; - // NOTE: No swapping is done because there is currently no sane way of detecting it + // TODO: Support swapping return 0; } +void adbg_object_mscoff_unload(adbg_object_t *o) { + if (o == null) return; + if (o.internal == null) return; + free(o.internal); +} + +uint adbg_object_mscoff_version(adbg_object_t *o) { + if (o == null) { + adbg_oops(AdbgError.invalidArgument); + return -1; + } + if (o.internal == null) { + adbg_oops(AdbgError.uninitiated); + return -1; + } + internal_mscoff_t *internal = cast(internal_mscoff_t*)o.internal; + return internal.anon_header.Version; +} + +void* adbg_object_mscoff_header(adbg_object_t *o) { + if (o == null) { + adbg_oops(AdbgError.invalidArgument); + return null; + } + if (o.internal == null) { + adbg_oops(AdbgError.uninitiated); + return null; + } + return o.internal; +} diff --git a/src/adbg/object/server.d b/src/adbg/object/server.d index a3de2618..b72dcede 100644 --- a/src/adbg/object/server.d +++ b/src/adbg/object/server.d @@ -43,13 +43,17 @@ extern (C): // (e.g., pe, elf, etc.) to make things consistent. This is why // auxiliary names are simply "adbg_object_offset", for example. -//TODO: Consider structure definition, using a template +// TODO: Consider structure definition, using a template // Uses: // - For swapping, uses less code than inlining it // - For displaying and using field offsets -//TODO: adbg_object_endiannes -// Why? Machine module do not include endianness. -// And would be beneficial when host has incompatible endianness. +// TODO: adbg_object_endiannes +// Why? Machine module do not include endianness. +// And would be beneficial when host has incompatible endianness. +// TODO: adbg_object_open_process(int pid, ...) +// TODO: adbg_object_open_buffer(void *buffer, size_t size, ...) +// TODO: Consider function to ease submodule setup +// adbg_object_setup(AdbgObject type, size_t internal_buffer_size, void function(adbg_object_t*) fclose) /// Executable or object file format. enum AdbgObject { @@ -87,16 +91,7 @@ enum AdbgObject { mscoff, } -// -/*enum AdbgObjectKind { - unknown, - executable, -}*/ - -// NOTE: This enum is a little weird but should be used as an I/O strategy -/// Object origin. (or "load mode") -/// -/// How was the object loaded or hooked. +/// Object origin. Used in adbg_object_read. private enum AdbgObjectOrigin { /// Object is unloaded, or the loading method is unknown. @@ -161,6 +156,10 @@ struct adbg_object_t { adbg_process_t *process; size_t location; } + struct { + void *user_buffer; + size_t user_size; + } } /// Object's loading origin. @@ -176,6 +175,11 @@ struct adbg_object_t { /// Managed by the object handler. void *internal; + package: + + /// Used to attach the unload function + void function(adbg_object_t*) func_unload; + //TODO: Deprecate *all* of this // Object properties. @@ -230,14 +234,6 @@ struct adbg_object_t { int firstentry; } omf_t omf; - - union mscoff_t { - mscoff_import_header *import_header; - mscoff_anon_header *anon_header; - mscoff_anon_header_v2 *anon_v2_header; - mscoff_anon_header_bigobj *anon_big_header; - } - mscoff_t mscoff; } /// Internal object definitions. deprecated @@ -389,11 +385,6 @@ adbg_object_t* adbg_object_open_file(const(char) *path, ...) { return o; } -/*adbg_object_t* adbg_object_open_process(adbg_process_t *proc) { - adbg_oops(AdbgError.unimplemented); - return null; -}*/ - /// Close object instance. /// Params: o = Object instance. export @@ -457,7 +448,9 @@ int adbg_object_read(adbg_object_t *o, void *buffer, size_t rdsize, int flags = return adbg_oops(AdbgError.unimplemented); } -//TODO: adbg_object_read_at: Add flag to allocate memory. Or make a new function (new signature) +//TODO: adbg_object_readalloc_at: Allocate memory and read. +// void* adbg_object_readalloc_at(adbg_object_t *o, long location, size_t rdsize, int flags) + /// Read raw data from object at absolute position. /// Params: /// o = Object instance. @@ -491,10 +484,13 @@ int adbg_object_read_at(adbg_object_t *o, long location, void *buffer, size_t rd return adbg_object_read(o, buffer, rdsize); } -/// +/// Size of signature buffer. +private enum SIGMAX = MAX!(PDB20_MAGIC.length, PDB70_MAGIC.length); + +/// Used in signature detection. private union SIGNATURE { - ubyte[64] buffer; + ubyte[SIGMAX] buffer; ulong u64; uint u32; ushort u16; @@ -509,14 +505,12 @@ int adbg_object_loadv(adbg_object_t *o) { return adbg_oops(AdbgError.invalidArgument); o.status = 0; - memset(&o.p, 0, o.p.sizeof); // Init object properties - memset(&o.i, 0, o.i.sizeof); // Init object internal structures // Load minimum for signature detection // Also tests seeking in case this is a streamed input SIGNATURE sig = void; int siglen = osfread(o.file, &sig, SIGNATURE.sizeof); /// signature size - version (Trace) trace("siglen=%d", siglen); + version (Trace) trace("siglen=%d sigmax=%u", siglen, cast(uint)SIGMAX); if (siglen < 0) return adbg_oops(AdbgError.os); if (siglen <= uint.sizeof) @@ -564,11 +558,9 @@ int adbg_object_loadv(adbg_object_t *o) { if (siglen > ushort.sizeof) switch (sig.u16) { // Anonymous MSCOFF case 0: - if (o.file_size < mscoff_anon_header_bigobj.sizeof) - return adbg_oops(AdbgError.objectUnknownFormat); - if (o.i.mscoff.import_header.Sig2 != 0xffff) - return adbg_oops(AdbgError.objectUnknownFormat); - return adbg_object_mscoff_load(o); + if (siglen > uint.sizeof && (sig.u32 >> 16) == 0xffff) + return adbg_object_mscoff_load(o); + break; // MZ executables case MAGIC_MZ: version (Trace) trace("e_lfarlc=%#x", sig.mzheader.e_lfarlc);