diff --git a/.gitignore b/.gitignore
index 8bff2d2..8bca5f5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,13 +5,17 @@
__dummy.html
/bin/
/docs/
-/alicedbg
-alicedbg-test-*
*.json
*.log
*.lst
# Executable objects
+/alicedbg
+alicedbg-test-*
+/alicedump
+alicedump-test-*
+/simple
+simple-test-*
*.dll
*.dylib
*.so
diff --git a/app/common.d b/app/common.d
deleted file mode 100644
index db1619f..0000000
--- a/app/common.d
+++ /dev/null
@@ -1,138 +0,0 @@
-/// Common global variables and functions so they can be used throughout the
-/// entirety of the program.
-///
-/// Authors: dd86k
-/// Copyright: © dd86k
-/// License: BSD-3-Clause-Clear
-module common;
-
-import core.stdc.stdio : puts;
-import core.stdc.stdlib : exit;
-import core.stdc.string : strerror;
-import core.stdc.errno : errno;
-import adbg.error;
-import adbg.disassembler;
-import adbg.debugger.exception;
-import adbg.machines : AdbgMachine;
-import core.stdc.stdio : FILE;
-import core.stdc.stdlib : malloc;
-
-public:
-extern (C):
-
-// Platforms
-
-// temporary
-struct setting_platform_t {
- AdbgMachine val;
- const(char)* opt, alt, desc;
-}
-immutable setting_platform_t[] platforms = [
- { AdbgMachine.i8086, "x86_16", "8086", "x86 16-bit (real mode)" },
- { AdbgMachine.x86, "x86", "i386", "x86 32-bit (extended mode)" },
- { AdbgMachine.amd64, "x86_64", "amd64", "x86 64-bit (long mode)" },
-];
-
-// Syntaxes
-
-struct setting_syntax_t {
- AdbgDisSyntax val;
- const(char)* opt, desc;
-}
-immutable setting_syntax_t[] syntaxes = [
- { AdbgDisSyntax.att, "att", "AT&T syntax" },
- { AdbgDisSyntax.intel, "intel", "Intel syntax" },
-];
-
-//
-// Settings
-//
-
-/// Application operating mode
-enum SettingMode { debugger, dump, analyze }
-
-/// Debugger UIs
-enum SettingUI { cmd, loop, tcpserver }
-
-//TODO: globals should be moved to an internal app API
-// Dedicated shell/dump APIs to set global settings
-
-/// Settings structure for the application (only!)
-struct settings_t {
- /// CLI settings
- SettingMode mode; /// Application mode
- const(char) *file; /// Debuggee: file
- const(char) **args; /// Debuggee: argument vector
- const(char) **env; /// Debuggee: environement vector
- int pid; /// Debuggee: PID
- int dump_selections; /// Dumper selections
- int dump_options; /// Dumper options
- const(char) *dump_section; /// Section name to dump
- long dump_base_address; /// Dumper base address (org)
- AdbgMachine machine; /// Disassembler: Target machine
- AdbgDisSyntax syntax; /// Disassembler: Syntax
-}
-
-/// Global variables. Helps keeping track of app variables.
-__gshared settings_t globals;
-
-alias oops = show_error;
-
-int show_error(
- const(char)* func = cast(char*)__FUNCTION__,
- const(char)* mod = cast(char*)__MODULE__,
- int line = __LINE__) {
- import adbg.include.c.stdio : printf, puts;
- import adbg.error : adbg_error_current;
-
- const(adbg_error_t)* error = adbg_error_current;
-
- printf("ERROR-%u: ", adbg_errno);
- switch (error.code) with (AdbgError) {
- case crt: printf("(CRT:%d) ", adbg_errno_extern); break;
- case os: printf("(OS:"~ADBG_OS_ERROR_FORMAT~") ", adbg_errno_extern); break;
- case libCapstone: printf("(CS:%d) ", adbg_errno_extern); break;
- default:
- }
- puts(adbg_error_msg);
-
- debug {
- printf("in %s\n", func);
- printf(" %s:%d\n", mod, line);
- printf(" %s:%d\n", error.mod, error.line);
- }
-
- return error.code;
-}
-
-/// Quit program.
-/// Params:
-/// message = Quit message.
-/// code = Exit code.
-void quit(int code, const(char) *message) {
- puts(message);
- exit(code);
-}
-
-enum ErrSource {
- crt,
- adbg,
-}
-
-/// Quit due to external factor.
-void quitext(ErrSource src,
- const(char)* func = cast(char*)__FUNCTION__,
- const(char)* mod = cast(char*)__MODULE__,
- int line = __LINE__) {
- switch (src) {
- case ErrSource.crt:
- int code = errno;
- puts(strerror(code));
- exit(code);
- case ErrSource.adbg:
- exit(show_error());
- default:
- puts("(Unknown source)");
- exit(1);
- }
-}
diff --git a/app/dump/ar.d b/app/dump/ar.d
deleted file mode 100644
index 6d564be..0000000
--- a/app/dump/ar.d
+++ /dev/null
@@ -1,86 +0,0 @@
-/// Library archive dumper
-///
-/// Authors: dd86k
-/// Copyright: © dd86k
-/// License: BSD-3-Clause-Clear
-module dump.ar;
-
-import adbg.disassembler;
-import adbg.object.server;
-import adbg.machines;
-import adbg.object.format.ar;
-import adbg.utils.bit : adbg_bswap32;
-import core.stdc.ctype : isdigit;
-import dumper;
-import utils : realstring;
-
-extern (C):
-
-int dump_archive(ref Dumper dump, adbg_object_t *o) {
- if (dump.selected_headers())
- dump_archive_headers(dump, o);
-
- return 0;
-}
-
-private:
-
-void dump_archive_headers(ref Dumper dump, adbg_object_t *o) {
- print_header("Header");
-
- ar_member_header *rhdr = void; // Root headers
- for (size_t i; (rhdr = adbg_object_ar_header(o, i)) != null; ++i) {
- print_section(cast(uint)i);
- print_stringl("Name", rhdr.Name.ptr, rhdr.Name.sizeof);
- print_stringl("Date", rhdr.Date.ptr, rhdr.Date.sizeof);
- print_stringl("UserID", rhdr.UserID.ptr, rhdr.UserID.sizeof);
- print_stringl("GroupID", rhdr.GroupID.ptr, rhdr.GroupID.sizeof);
- print_stringl("Mode", rhdr.Mode.ptr, rhdr.Mode.sizeof);
- print_stringl("Size", rhdr.Size.ptr, rhdr.Size.sizeof);
-
- char[10] b = void;
- int l = realstring(b.ptr, 10, rhdr.End.ptr, 2);
- print_x16l("End", rhdr.EndMarker, b.ptr, l);
-
- /+void *data = adbg_object_ar_data(o, rhdr);
- if (data == null) {
- print_string("warning", "Could not get data pointer");
- continue;
- }
-
- int size = adbg_object_ar_header_size(o, rhdr);
- if (size <= 0) {
- print_string("warning", "Could not get size of data");
- continue;
- }
-
- import core.stdc.stdio : printf;
-
- int symcnt = *cast(int*)data;
- int *symoffs = cast(int*)data + 1;
- for (int isym; isym < symcnt; ++isym) {
- int off = adbg_bswap32(symoffs[isym]);
-
- ar_member_header *table = void;
- if (adbg_object_offset(o, cast(void**)&table, off)) {
- print_string("warning", "aaaaaaaaaaa cringe");
- printf("there was %d headers\n", isym);
- return;
- }
-
- print_stringl("Name", table.Name.ptr, table.Name.sizeof);
- print_stringl("Date", table.Date.ptr, table.Date.sizeof);
- print_stringl("UserID", table.UserID.ptr, table.UserID.sizeof);
- print_stringl("GroupID", table.GroupID.ptr, table.GroupID.sizeof);
- print_stringl("Mode", table.Mode.ptr, table.Mode.sizeof);
- print_stringl("Size", table.Size.ptr, table.Size.sizeof);
- l = realstring(b.ptr, 10, table.End.ptr, 2, '"', '"');
- print_x16l("End", table.EndMarker, b.ptr, l);
-
- if (table.Name[0] != '/' || isdigit(table.Name[1]) == 0)
- continue;
-
-
- }+/
- }
-}
\ No newline at end of file
diff --git a/app/dump/coff.d b/app/dump/coff.d
deleted file mode 100644
index c08b9ba..0000000
--- a/app/dump/coff.d
+++ /dev/null
@@ -1,47 +0,0 @@
-/// COFF dumper.
-///
-/// Authors: dd86k
-/// Copyright: © dd86k
-/// License: BSD-3-Clause-Clear
-module dump.coff;
-
-import adbg.disassembler;
-import adbg.object.server;
-import adbg.machines;
-import adbg.object.format.coff;
-import adbg.object.format.pe : adbg_object_pe_machine_string;
-import adbg.utils.bit : adbg_bswap32;
-import adbg.utils.uid;
-import core.stdc.ctype : isdigit;
-import dumper;
-import utils : realstring;
-
-int dump_coff(ref Dumper dump, adbg_object_t *o) {
- if (dump.selected_headers())
- dump_coff_hdr(dump, o);
-
- return 0;
-}
-
-private:
-
-void dump_coff_hdr(ref Dumper dump, adbg_object_t *o) {
- print_header("Header");
-
- with (o.i.coff.header) {
- print_x16("f_magic", f_magic, adbg_object_coff_magic_string(f_magic));
- print_u16("f_nscns", f_nscns);
- print_u32("f_timedat", f_timedat);
- print_u32("f_symptr", f_symptr);
- print_u32("f_nsyms", f_nsyms);
- print_u16("f_opthdr", f_opthdr);
- print_flags16("f_flags", f_flags,
- "RELFLG".ptr, COFF_F_RELFLG,
- "EXEC".ptr, COFF_F_EXEC,
- "LNNO".ptr, COFF_F_LNNO,
- "LSYMS".ptr, COFF_F_LSYMS,
- "LSB".ptr, COFF_F_LSB,
- "MSB".ptr, COFF_F_MSB,
- null);
- }
-}
\ No newline at end of file
diff --git a/app/dump/dmp.d b/app/dump/dmp.d
deleted file mode 100644
index 0026569..0000000
--- a/app/dump/dmp.d
+++ /dev/null
@@ -1,70 +0,0 @@
-/// Windows memory dump dumper.
-///
-/// Authors: dd86k
-/// Copyright: © dd86k
-/// License: BSD-3-Clause-Clear
-module dump.dmp;
-
-import adbg.disassembler;
-import adbg.object.server;
-import adbg.machines;
-import adbg.object.format.dmp;
-import adbg.object.format.pe : adbg_object_pe_machine_string;
-import dumper;
-
-extern (C):
-
-int dump_dmp(ref Dumper dump, adbg_object_t *o) {
- if (dump.selected_headers())
- dump_dmp_header(dump, o);
-
- return 0;
-}
-
-private:
-
-void dump_dmp_header(ref Dumper dump, adbg_object_t *o) {
- print_header("Header");
-
- bool is64 = o.i.dmp.header.ValidDumpInt == PAGEDUMP64_VALID;
-
- dmp64_header *hdr64 = cast(dmp64_header*)o.i.dmp.header;
- if (is64) with (hdr64) {
- print_x32l("Signature", SignatureInt, Signature.ptr, 4);
- print_x32l("ValidDump", ValidDumpInt, ValidDump.ptr, 4);
- print_u32("MajorVersion", MajorVersion);
- print_u32("MinorVersion", MinorVersion);
- print_x32("DirectoryTableBase", DirectoryTableBase);
- print_x32("PfnDatabase", PfnDatabase);
- print_x32("PsLoadedModuleList", PsLoadedModuleList);
- print_x32("PsActiveProcessHead", PsActiveProcessHead);
- print_x32("MachineImageType", MachineImageType,
- adbg_object_pe_machine_string(cast(ushort)MachineImageType));
- print_u32("NumberProcessors", NumberProcessors);
- print_x32("BugCheckCode", BugCheckCode);
- print_x32("BugCheckParameter1", BugCheckParameters[0]);
- print_x32("BugCheckParameter2", BugCheckParameters[1]);
- print_x32("BugCheckParameter3", BugCheckParameters[2]);
- print_x32("BugCheckParameter4", BugCheckParameters[3]);
- print_x64("KdDebuggerDataBlock", KdDebuggerDataBlock);
- } else with (o.i.dmp.header) {
- print_x32l("Signature", SignatureInt, Signature.ptr, 4);
- print_x32l("ValidDump", ValidDumpInt, ValidDump.ptr, 4);
- print_u32("MajorVersion", MajorVersion);
- print_u32("MinorVersion", MinorVersion);
- print_x32("DirectoryTableBase", DirectoryTableBase);
- print_x32("PfnDatabase", PfnDatabase);
- print_x32("PsLoadedModuleList", PsLoadedModuleList);
- print_x32("PsActiveProcessHead", PsActiveProcessHead);
- print_x32("MachineImageType", MachineImageType,
- adbg_object_pe_machine_string(cast(ushort)MachineImageType));
- print_u32("NumberProcessors", NumberProcessors);
- print_x32("BugCheckCode", BugCheckCode);
- print_x32("BugCheckParameter1", BugCheckParameters[0]);
- print_x32("BugCheckParameter2", BugCheckParameters[1]);
- print_x32("BugCheckParameter3", BugCheckParameters[2]);
- print_x32("BugCheckParameter4", BugCheckParameters[3]);
- print_u8("PaeEnabled", PaeEnabled);
- print_x32("KdDebuggerDataBlock", KdDebuggerDataBlock);
- }
-}
\ No newline at end of file
diff --git a/app/dump/elf.d b/app/dump/elf.d
deleted file mode 100644
index 58d6705..0000000
--- a/app/dump/elf.d
+++ /dev/null
@@ -1,603 +0,0 @@
-/// ELF dumper
-///
-/// Authors: dd86k
-/// Copyright: © dd86k
-/// License: BSD-3-Clause-Clear
-module dump.elf;
-
-import adbg.utils.bit : adbg_align4up;
-import adbg.disassembler;
-import adbg.object.server;
-import adbg.machines;
-import adbg.object.format.elf;
-import core.stdc.string : memcmp, strncmp;
-import common, dumper;
-import utils : realchar, hexstr;
-
-extern (C):
-
-int dump_elf(ref Dumper dump, adbg_object_t *o) {
- if (dump.selected_headers()) {
- dump_elf_ehdr(dump, o);
- dump_elf_phdr(dump, o);
- }
-
- if (dump.selected_sections())
- dump_elf_sections(dump, o);
-
- if (dump.selected_disasm_any())
- dump_elf_disasm(dump, o);
-
- return 0;
-}
-
-private:
-
-__gshared immutable(char)[] SIG_CORE = "CORE\0\0\0";
-
-void dump_elf_ehdr(ref Dumper dump, adbg_object_t *o) {
- print_header("Header");
-
- ubyte ei_class = o.i.elf32.ehdr.e_ident[ELF_EI_CLASS];
-
- with (o.i.elf32.ehdr) {
- ubyte ei_data = e_ident[ELF_EI_DATA];
- ubyte ei_version = e_ident[ELF_EI_VERSION];
- ubyte ei_osabi = e_ident[ELF_EI_OSABI];
- ubyte ei_abiversion = e_ident[ELF_EI_ABIVERSION];
-
- print_x8("e_ident[0]", '\x7f', `\x7f`);
- print_x8("e_ident[1]", 'E', `E`);
- print_x8("e_ident[2]", 'L', `L`);
- print_x8("e_ident[3]", 'F', `F`);
- print_u8("e_ident[EI_CLASS]", ei_class, adbg_object_elf_class_string(ei_class));
- print_u8("e_ident[EI_DATA]", ei_data, adbg_object_elf_data_string(ei_data));
- print_u8("e_ident[EI_VERSION]", ei_version);
- print_u8("e_ident[EI_OSABI]", ei_osabi, adbg_object_elf_abi_string(ei_osabi));
- print_u8("e_ident[EI_ABIVERSION]", ei_abiversion);
- print_u8("e_ident[9]", e_ident[9]);
- print_u8("e_ident[10]", e_ident[10]);
- print_u8("e_ident[11]", e_ident[11]);
- print_u8("e_ident[12]", e_ident[12]);
- print_u8("e_ident[13]", e_ident[13]);
- print_u8("e_ident[14]", e_ident[14]);
- print_u8("e_ident[15]", e_ident[15]);
- print_u16("e_type", e_type, adbg_object_elf_et_string(e_type));
- print_u16("e_machine", e_machine, adbg_object_elf_em_string(e_machine));
- }
-
- switch (ei_class) {
- case ELF_CLASS_32:
- with (o.i.elf32.ehdr) {
- print_x32("e_entry", e_entry);
- print_x32("e_phoff", e_phoff);
- print_x32("e_shoff", e_shoff);
- dump_elf_e_flags(e_machine, e_flags);
- print_u16("e_ehsize", e_ehsize);
- print_u16("e_phentsize", e_phentsize);
- print_u16("e_phnum", e_phnum);
- print_u16("e_shentsize", e_shentsize);
- print_u16("e_shnum", e_shnum);
- print_u16("e_shstrndx", e_shstrndx);
- }
- break;
- case ELF_CLASS_64:
- with (o.i.elf64.ehdr) {
- print_x64("e_entry", e_entry);
- print_x64("e_phoff", e_phoff);
- print_x64("e_shoff", e_shoff);
- dump_elf_e_flags(e_machine, e_flags);
- print_u16("e_ehsize", e_ehsize);
- print_u16("e_phentsize", e_phentsize);
- print_u16("e_phnum", e_phnum);
- print_u16("e_shentsize", e_shentsize);
- print_u16("e_shnum", e_shnum);
- print_u16("e_shstrndx", e_shstrndx);
- }
- break;
- default:
- }
-}
-
-void dump_elf_e_flags(ushort e_machine, uint e_flags) {
- switch (e_machine) {
- case ELF_EM_ARM:
- print_flags32("e_flags", e_flags,
- "EF_ARM_RELEXEC".ptr, ELF_EF_ARM_RELEXEC,
- "EF_ARM_HASENTRY".ptr, ELF_EF_ARM_HASENTRY,
- "EF_ARM_INTERWORK".ptr, ELF_EF_ARM_INTERWORK,
- "EF_ARM_APCS_26".ptr, ELF_EF_ARM_APCS_26,
- "EF_ARM_APCS_FLOAT".ptr, ELF_EF_ARM_APCS_FLOAT,
- "EF_ARM_PIC".ptr, ELF_EF_ARM_PIC,
- "EF_ARM_ALIGN8".ptr, ELF_EF_ARM_ALIGN8,
- "EF_ARM_NEW_ABI".ptr, ELF_EF_ARM_NEW_ABI,
- "EF_ARM_OLD_ABI".ptr, ELF_EF_ARM_OLD_ABI,
- "EF_ARM_SOFT_FLOAT".ptr, ELF_EF_ARM_SOFT_FLOAT,
- "EF_ARM_VFP_FLOAT".ptr, ELF_EF_ARM_VFP_FLOAT,
- "EF_ARM_MAVERICK_FLOAT".ptr, ELF_EF_ARM_MAVERICK_FLOAT,
- null);
- break;
- case ELF_EM_SPARC:
- case ELF_EM_SPARC32PLUS:
- case ELF_EM_SPARCV9:
- print_flags32("e_flags", e_flags,
- "EF_SPARC_32PLUS".ptr, ELF_EF_SPARC_32PLUS,
- "EF_SPARC_SUN_US1".ptr, ELF_EF_SPARC_SUN_US1,
- "EF_SPARC_HAL_R1".ptr, ELF_EF_SPARC_HAL_R1,
- "EF_SPARC_SUN_US3".ptr, ELF_EF_SPARC_SUN_US3,
- "EF_SPARCV9_MM".ptr, ELF_EF_SPARCV9_MM,
- "EF_SPARCV9_TSO".ptr, ELF_EF_SPARCV9_TSO,
- "EF_SPARCV9_PSO".ptr, ELF_EF_SPARCV9_PSO,
- "EF_SPARCV9_RMO".ptr, ELF_EF_SPARCV9_RMO,
- null);
- break;
- default:
- print_x32("e_flags", e_flags);
- }
-}
-
-void dump_elf_phdr(ref Dumper dump, adbg_object_t *o) {
- print_header("Program Headers");
-
- //TODO: Warn and set an upper number limit (e.g. 1000)
-
- switch (o.i.elf32.ehdr.e_ident[ELF_EI_CLASS]) {
- case ELF_CLASS_32:
- with (o.i.elf32) if (phdr == null || ehdr.e_phnum == 0)
- return;
-
- //TODO: adbg_object_elf32_phnum function?
- for (uint i; i < o.i.elf32.ehdr.e_phnum; ++i) {
- Elf32_Phdr *phdr = adbg_object_elf_phdr32(o, i);
- with (phdr) {
- print_section(i);
- print_u32("p_type", p_type, adbg_object_elf_pt_string(p_type));
- print_x32("p_offset", p_offset);
- print_x32("p_vaddr", p_vaddr);
- print_x32("p_paddr", p_paddr);
- print_x32("p_filesz", p_filesz);
- print_x32("p_memsz", p_memsz);
- print_flags32("p_flags", p_flags,
- "PF_R".ptr, ELF_PF_R,
- "PF_W".ptr, ELF_PF_W,
- "PF_X".ptr, ELF_PF_X,
- null);
- print_x32("p_align", p_align);
- }
-
- //TODO: coredump
- // if (p_type == ELF_PT_NOTE && p_pflags == 0)
- // Elf32_Nhdr (like NT_X86_XSTATE)
- }
- break;
- case ELF_CLASS_64:
- with (o.i.elf64) if (phdr == null || ehdr.e_phnum == 0)
- return;
-
- for (uint i; i < o.i.elf64.ehdr.e_phnum; ++i) {
- Elf64_Phdr *phdr = adbg_object_elf_phdr64(o, i);
- with (phdr) {
- print_section(i);
- print_u32("p_type", p_type, adbg_object_elf_pt_string(p_type));
- print_flags32("p_flags", p_flags,
- "PF_R".ptr, ELF_PF_R,
- "PF_W".ptr, ELF_PF_W,
- "PF_X".ptr, ELF_PF_X,
- null);
- print_x64("p_offset", p_offset);
- print_x64("p_vaddr", p_vaddr);
- print_x64("p_paddr", p_paddr);
- print_x64("p_filesz", p_filesz);
- print_x64("p_memsz", p_memsz);
- print_x64("p_align", p_align);
- }
-
- // ELF is a coredump and program header is a note?
- // Worth checking if it is really a coredump
- // Notes usually have no flags
- if (o.i.elf32.ehdr.e_type == ELF_ET_CORE &&
- phdr.p_type == ELF_PT_NOTE &&
- phdr.p_flags == 0) {
- dump_elf_coredump64(o, phdr);
- }
- }
- break;
- default:
- }
-}
-
-void dump_elf_coredump32(adbg_object_t *o, Elf32_Phdr *phdr) {
-
-}
-void dump_elf_coredump64(adbg_object_t *o, Elf64_Phdr *phdr) {
- // NOTE: 8-byte alignment?
-
- ulong noffset = phdr.p_offset;
- long nleft = phdr.p_filesz;
- uint idx;
-
- // Process new note header
-LNEWNHDR:
- if (nleft < Elf64_Nhdr.sizeof)
- return;
-
- void *note = void;
- if (adbg_object_offsetl(o, ¬e, noffset, cast(size_t)nleft)) {
- print_string("warning", "Elf64_Phdr::p_offset points outside of file bounds");
- return;
- }
-
- Elf64_Nhdr *nhdr = cast(Elf64_Nhdr*)note;
-
- // NOTE: Note names
- // If zero, it's reserved
- // If name is "CORE", standard coredump stuff, like NT_PRSTATUS
- // If name is "LINUX", Linux-specific note, like NT_X86_XSTATE
- if (nhdr.n_namesz == 0)
- return;
-
- print_section(++idx, cast(const(char)*)note + Elf64_Nhdr.sizeof, nhdr.n_namesz);
- print_u32l("n_namesz", nhdr.n_namesz);
- print_u32("n_descsz", nhdr.n_descsz);
- print_u32("n_type", nhdr.n_type, adbg_object_elf_nt_type_string(nhdr.n_type));
-
- size_t nnamesz = adbg_align4up(nhdr.n_namesz);
- void *data = note + Elf64_Nhdr.sizeof + nnamesz;
-
- // NOTE: Only for x86-64, for now
- switch (nhdr.n_type) {
- case ELF_NT_PRSTATUS:
- elf_prstatus64 *prstatus = cast(elf_prstatus64*)data;
- print_u32("pr_info.si_signo", prstatus.pr_info.si_signo);
- print_u32("pr_info.si_code", prstatus.pr_info.si_code);
- print_u32("pr_info.si_errno", prstatus.pr_info.si_errno);
- print_u16("pr_cursig", prstatus.pr_cursig);
- print_u64("pr_sigpend", prstatus.pr_sigpend);
- print_u64("pr_sighold", prstatus.pr_sighold);
- print_u32("pr_pid", prstatus.pr_pid);
- print_u32("pr_ppid", prstatus.pr_ppid);
- print_u32("pr_pgrp", prstatus.pr_pgrp);
- print_u32("pr_sid", prstatus.pr_sid);
- print_u64("pr_utime.tv_sec", prstatus.pr_utime.tv_sec);
- print_u64("pr_utime.tv_usec", prstatus.pr_utime.tv_usec);
- print_u64("pr_stime.tv_sec", prstatus.pr_stime.tv_sec);
- print_u64("pr_stime.tv_usec", prstatus.pr_stime.tv_usec);
- print_u64("pr_cutime.tv_sec", prstatus.pr_cutime.tv_sec);
- print_u64("pr_cutime.tv_usec", prstatus.pr_cutime.tv_usec);
- print_u64("pr_cstime.tv_sec", prstatus.pr_cstime.tv_sec);
- print_u64("pr_cstime.tv_usec", prstatus.pr_cstime.tv_usec);
- print_x64("pr_reg[r15]", prstatus.pr_reg[0]);
- print_x64("pr_reg[r14]", prstatus.pr_reg[1]);
- print_x64("pr_reg[r13]", prstatus.pr_reg[2]);
- print_x64("pr_reg[r12]", prstatus.pr_reg[3]);
- print_x64("pr_reg[rbp]", prstatus.pr_reg[4]);
- print_x64("pr_reg[rbx]", prstatus.pr_reg[5]);
- print_x64("pr_reg[r11]", prstatus.pr_reg[6]);
- print_x64("pr_reg[r10]", prstatus.pr_reg[7]);
- print_x64("pr_reg[r9]", prstatus.pr_reg[8]);
- print_x64("pr_reg[r8]", prstatus.pr_reg[9]);
- print_x64("pr_reg[rax]", prstatus.pr_reg[10]);
- print_x64("pr_reg[rcx]", prstatus.pr_reg[11]);
- print_x64("pr_reg[rdx]", prstatus.pr_reg[12]);
- print_x64("pr_reg[rsi]", prstatus.pr_reg[13]);
- print_x64("pr_reg[rdi]", prstatus.pr_reg[14]);
- print_x64("pr_reg[orig_rax]", prstatus.pr_reg[15]);
- print_x64("pr_reg[rip]", prstatus.pr_reg[16]);
- print_x64("pr_reg[cs]", prstatus.pr_reg[17]);
- print_x64("pr_reg[eflags]", prstatus.pr_reg[18]);
- print_x64("pr_reg[rsp]", prstatus.pr_reg[19]);
- print_x64("pr_reg[ss]", prstatus.pr_reg[20]);
- print_x64("pr_reg[fs_base]", prstatus.pr_reg[21]);
- print_x64("pr_reg[gs_base]", prstatus.pr_reg[22]);
- print_x64("pr_reg[ds]", prstatus.pr_reg[23]);
- print_x64("pr_reg[es]", prstatus.pr_reg[24]);
- print_x64("pr_reg[fs]", prstatus.pr_reg[25]);
- print_x64("pr_reg[gs]", prstatus.pr_reg[26]);
- print_u64("pr_fpvalid", prstatus.pr_fpvalid);
- break;
- case ELF_NT_PRPSINFO:
- elf_prpsinfo64 *prpsinfo = cast(elf_prpsinfo64*)data;
- char[4] pr_sname = void;
- int l = realchar(pr_sname.ptr, 4, prpsinfo.pr_sname);
- print_u8("pr_state", prpsinfo.pr_state);
- print_stringl("pr_sname", pr_sname.ptr, l);
- print_u8("pr_zomb", prpsinfo.pr_zomb);
- print_u8("pr_nice", prpsinfo.pr_nice);
- print_u64("pr_flag", prpsinfo.pr_flag);
- print_u32("pr_uid", prpsinfo.pr_uid);
- print_u32("pr_gid", prpsinfo.pr_gid);
- print_u32("pr_pid", prpsinfo.pr_pid);
- print_u32("pr_ppid", prpsinfo.pr_ppid);
- print_u32("pr_pgrp", prpsinfo.pr_pgrp);
- print_u32("pr_sid", prpsinfo.pr_sid);
- print_stringl("pr_fname", prpsinfo.pr_fname.ptr, prpsinfo.pr_fname.sizeof);
- print_stringl("pr_psargs", prpsinfo.pr_psargs.ptr, prpsinfo.pr_psargs.sizeof);
- break;
- case ELF_NT_SIGINFO: // siginfo
- // NOTE: SI_MAX_SIZE is defined with 128, must be same size
- goto default;
- case ELF_NT_FPREGSET:
- user_i387_struct64 *fregset = cast(user_i387_struct64*)data;
- char[2*16] fpbuf = void;
- int fplen = void;
- print_x16("cwd", fregset.cwd);
- print_x16("swd", fregset.swd);
- print_x16("twd", fregset.twd);
- print_x16("fop", fregset.fop);
- print_x64("rip", fregset.rip);
- print_x64("rdp", fregset.rdp);
- print_x32("mxcsr", fregset.mxcsr);
- print_x32("mxcsr_mask", fregset.mxcsr_mask);
- // x87
- fplen = hexstr(fpbuf.ptr, 32, fregset.st_space128[0].data.ptr, 16);
- print_stringl("st_space[0]", fpbuf.ptr, fplen);
- fplen = hexstr(fpbuf.ptr, 32, fregset.st_space128[1].data.ptr, 16);
- print_stringl("st_space[1]", fpbuf.ptr, fplen);
- fplen = hexstr(fpbuf.ptr, 32, fregset.st_space128[2].data.ptr, 16);
- print_stringl("st_space[2]", fpbuf.ptr, fplen);
- fplen = hexstr(fpbuf.ptr, 32, fregset.st_space128[3].data.ptr, 16);
- print_stringl("st_space[3]", fpbuf.ptr, fplen);
- fplen = hexstr(fpbuf.ptr, 32, fregset.st_space128[4].data.ptr, 16);
- print_stringl("st_space[4]", fpbuf.ptr, fplen);
- fplen = hexstr(fpbuf.ptr, 32, fregset.st_space128[5].data.ptr, 16);
- print_stringl("st_space[5]", fpbuf.ptr, fplen);
- fplen = hexstr(fpbuf.ptr, 32, fregset.st_space128[6].data.ptr, 16);
- print_stringl("st_space[6]", fpbuf.ptr, fplen);
- fplen = hexstr(fpbuf.ptr, 32, fregset.st_space128[7].data.ptr, 16);
- print_stringl("st_space[7]", fpbuf.ptr, fplen);
- // sse
- fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[0].data.ptr, 16);
- print_stringl("xmm_space[0]", fpbuf.ptr, fplen);
- fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[1].data.ptr, 16);
- print_stringl("xmm_space[1]", fpbuf.ptr, fplen);
- fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[2].data.ptr, 16);
- print_stringl("xmm_space[2]", fpbuf.ptr, fplen);
- fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[3].data.ptr, 16);
- print_stringl("xmm_space[3]", fpbuf.ptr, fplen);
- fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[4].data.ptr, 16);
- print_stringl("xmm_space[4]", fpbuf.ptr, fplen);
- fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[5].data.ptr, 16);
- print_stringl("xmm_space[5]", fpbuf.ptr, fplen);
- fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[6].data.ptr, 16);
- print_stringl("xmm_space[6]", fpbuf.ptr, fplen);
- fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[7].data.ptr, 16);
- print_stringl("xmm_space[7]", fpbuf.ptr, fplen);
- fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[8].data.ptr, 16);
- print_stringl("xmm_space[8]", fpbuf.ptr, fplen);
- fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[9].data.ptr, 16);
- print_stringl("xmm_space[9]", fpbuf.ptr, fplen);
- fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[10].data.ptr, 16);
- print_stringl("xmm_space[10]", fpbuf.ptr, fplen);
- fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[11].data.ptr, 16);
- print_stringl("xmm_space[11]", fpbuf.ptr, fplen);
- fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[12].data.ptr, 16);
- print_stringl("xmm_space[12]", fpbuf.ptr, fplen);
- fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[13].data.ptr, 16);
- print_stringl("xmm_space[13]", fpbuf.ptr, fplen);
- fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[14].data.ptr, 16);
- print_stringl("xmm_space[14]", fpbuf.ptr, fplen);
- fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[15].data.ptr, 16);
- print_stringl("xmm_space[15]", fpbuf.ptr, fplen);
- break;
- default:
- print_raw("Dump", data, nhdr.n_descsz,
- noffset + Elf64_Nhdr.sizeof + nnamesz);
- }
-
- // Adjust to next sub header
- ulong nsize =
- Elf64_Nhdr.sizeof +
- nnamesz +
- adbg_align4up(nhdr.n_descsz);
- noffset += nsize;
- nleft -= nsize;
-
- goto LNEWNHDR;
-}
-
-void dump_elf_sections(ref Dumper dump, adbg_object_t *o) {
- print_header("Sections");
-
- //TODO: Functions to get section + section name safely
-
- /// Arbritrary maximum section name length
- enum SNMLEN = 32;
- switch (o.i.elf32.ehdr.e_ident[ELF_EI_CLASS]) {
- case ELF_CLASS_32:
- if (o.i.elf32.ehdr == null)
- return;
-
- ushort section_count = o.i.elf32.ehdr.e_shnum;
- if (section_count == 0)
- return;
-
- // Check id is without section count
- ushort id = o.i.elf32.ehdr.e_shstrndx;
- if (id >= section_count) {
- print_string("error", "String table index out of bounds");
- return;
- }
-
- uint offset = o.i.elf32.shdr[id].sh_offset;
- if (offset < Elf32_Ehdr.sizeof || offset > o.file_size) {
- print_string("error", "String table offset out of bounds");
- return;
- }
-
- char *table = o.bufferc + offset; // string table
- for (uint i; i < section_count; ++i) {
- Elf32_Shdr *shdr = adbg_object_elf_shdr32(o, i);
-
- // If we're searching sections, don't print anything
- if (globals.dump_section) {
- if (strncmp(table + shdr.sh_name, globals.dump_section, SNMLEN) == 0) {
- print_raw(globals.dump_section, // Lazy as fuck
- o.buffer + shdr.sh_offset, shdr.sh_size, shdr.sh_offset);
- return;
- }
- continue;
- }
-
- with (shdr) {
- print_section(i, table + sh_name, SNMLEN);
- print_x32("sh_name", sh_name);
- print_x32("sh_type", sh_type, adbg_object_elf_sht_string(sh_type));
- print_x32("sh_flags", sh_flags);
- print_flags32("sh_flags", sh_flags,
- "SHF_WRITE".ptr, ELF_SHF_WRITE,
- "SHF_ALLOC".ptr, ELF_SHF_ALLOC,
- "SHF_EXECINSTR".ptr, ELF_SHF_EXECINSTR,
- "SHF_MERGE".ptr, ELF_SHF_MERGE,
- "SHF_STRINGS".ptr, ELF_SHF_STRINGS,
- "SHF_INFO_LINK".ptr, ELF_SHF_INFO_LINK,
- "SHF_LINK_ORDER".ptr, ELF_SHF_LINK_ORDER,
- "SHF_OS_NONCONFORMING".ptr, ELF_SHF_OS_NONCONFORMING,
- "SHF_GROUP".ptr, ELF_SHF_GROUP,
- "SHF_TLS".ptr, ELF_SHF_TLS,
- "SHF_COMPRESSED".ptr, ELF_SHF_COMPRESSED,
- null);
- print_x32("sh_addr", sh_addr);
- print_x32("sh_offset", sh_offset);
- print_x32("sh_size", sh_size);
- print_x32("sh_link", sh_link);
- print_x32("sh_info", sh_info);
- print_x32("sh_addralign", sh_addralign);
- print_x32("sh_entsize", sh_entsize);
- }
- }
- break;
- case ELF_CLASS_64:
- if (o.i.elf64.ehdr == null)
- return;
-
- ushort section_count = o.i.elf64.ehdr.e_shnum;
- if (section_count == 0)
- return;
-
- // Check id is without section count
- ushort id = o.i.elf64.ehdr.e_shstrndx;
- if (id >= section_count) {
- print_string("error", "String table index out of bounds");
- return;
- }
-
- ulong offset = o.i.elf64.shdr[id].sh_offset;
- if (offset < Elf64_Ehdr.sizeof || offset > o.file_size) {
- print_string("error", "String table offset out of bounds");
- return;
- }
-
- char *table = o.bufferc + offset; // string table
- for (uint i; i < section_count; ++i) {
- Elf64_Shdr *shdr = adbg_object_elf_shdr64(o, i);
-
- // If we're searching sections, don't print anything
- if (globals.dump_section) {
- if (strncmp(table + shdr.sh_name, globals.dump_section, SNMLEN) == 0) {
- print_raw(globals.dump_section, // Lazy as fuck
- o.buffer + shdr.sh_offset, shdr.sh_size, shdr.sh_offset);
- return;
- }
- continue;
- }
-
- with (shdr) {
- print_section(i, table + sh_name, SNMLEN);
- print_x32("sh_name", sh_name);
- print_x32("sh_type", sh_type, adbg_object_elf_sht_string(sh_type));
- print_flags64("sh_flags", sh_flags,
- "SHF_WRITE".ptr, ELF_SHF_WRITE,
- "SHF_ALLOC".ptr, ELF_SHF_ALLOC,
- "SHF_EXECINSTR".ptr, ELF_SHF_EXECINSTR,
- "SHF_MERGE".ptr, ELF_SHF_MERGE,
- "SHF_STRINGS".ptr, ELF_SHF_STRINGS,
- "SHF_INFO_LINK".ptr, ELF_SHF_INFO_LINK,
- "SHF_LINK_ORDER".ptr, ELF_SHF_LINK_ORDER,
- "SHF_OS_NONCONFORMING".ptr, ELF_SHF_OS_NONCONFORMING,
- "SHF_GROUP".ptr, ELF_SHF_GROUP,
- "SHF_TLS".ptr, ELF_SHF_TLS,
- "SHF_COMPRESSED".ptr, ELF_SHF_COMPRESSED,
- null);
- print_x64("sh_addr", sh_addr);
- print_x64("sh_offset", sh_offset);
- print_x64("sh_size", sh_size);
- print_x32("sh_link", sh_link);
- print_x32("sh_info", sh_info);
- print_x64("sh_addralign", sh_addralign);
- print_x64("sh_entsize", sh_entsize);
- }
- }
- break;
- default:
- }
-}
-
-//TODO: Section machine-specific flags (like SHF_X86_64_LARGE)
-
-void dump_elf_disasm(ref Dumper dump, adbg_object_t *o) {
- print_header("Disassembly");
-
- bool all = dump.selected_disasm_all();
-
- switch (o.i.elf32.ehdr.e_ident[ELF_EI_CLASS]) {
- case ELF_CLASS_32:
- ushort section_count = o.i.elf32.ehdr.e_shnum;
-
- if (section_count == 0)
- return;
-
- // Check id is without section count
- ushort id = o.i.elf32.ehdr.e_shstrndx;
- if (id >= section_count) {
- print_string("error", "String table index out of bounds");
- return;
- }
-
- Elf32_Shdr *shdr = o.i.elf32.shdr;
- uint offset = shdr[id].sh_offset;
- if (offset < Elf32_Ehdr.sizeof || offset > o.file_size) {
- print_string("error", "String table offset out of bounds");
- return;
- }
-
- Elf32_Shdr *max = shdr + section_count;
- char *table = o.bufferc + offset; // string table
- while (shdr++ < max) with (shdr) {
- if (all || sh_flags & ELF_SHF_EXECINSTR)
- dump_disassemble_object(dump, o,
- table + sh_name, 32,
- o.buffer8 + sh_offset, sh_size, 0);
- }
- break;
- case ELF_CLASS_64:
- ushort section_count = o.i.elf64.ehdr.e_shnum;
-
- if (section_count == 0)
- return;
-
- // Check id is without section count
- ushort id = o.i.elf64.ehdr.e_shstrndx;
- if (id >= section_count) {
- print_string("error", "String table index out of bounds");
- return;
- }
-
- Elf64_Shdr *shdr = o.i.elf64.shdr;
- ulong offset = shdr[id].sh_offset;
- if (offset < Elf64_Ehdr.sizeof || offset > o.file_size) {
- print_string("error", "String table offset out of bounds");
- return;
- }
-
- Elf64_Shdr *max = shdr + section_count;
- char *table = o.bufferc + offset; // string table
- while (shdr++ < max) with (shdr) {
- if (all || sh_flags & ELF_SHF_EXECINSTR)
- dump_disassemble_object(dump, o,
- table + sh_name, 32,
- o.buffer8 + sh_offset, sh_size, 0);
- }
- break;
- default:
- }
-}
diff --git a/app/dump/lx.d b/app/dump/lx.d
deleted file mode 100644
index cc90167..0000000
--- a/app/dump/lx.d
+++ /dev/null
@@ -1,113 +0,0 @@
-/// OS/2 / Windows 9x LX file dumper
-///
-/// Authors: dd86k
-/// Copyright: © dd86k
-/// License: BSD-3-Clause-Clear
-module dump.lx;
-
-import adbg.disassembler;
-import adbg.object.server;
-import adbg.machines : AdbgMachine;
-import adbg.object.format.lx;
-import dumper;
-
-extern (C):
-
-int dump_lx(ref Dumper dump, adbg_object_t *o) {
- if (dump.selected_headers())
- dump_lx_hdr(dump, o);
- return 0;
-}
-
-private:
-
-void dump_lx_hdr(ref Dumper dump, adbg_object_t *o) {
- print_header("Header");
-
- with (o.i.lx.header) {
- print_x16("e32_magic", magic, magic == LE_MAGIC ? "LE" : "LX");
- print_x8("e32_border", border);
- print_x8("e32_worder", worder);
- print_x32("e32_level", level);
- print_u16("e32_cpu", cpu, adbg_object_lx_cputype_string(cpu));
- print_u16("e32_os", os, adbg_object_lx_ostype_string(os));
- print_x32("e32_ver", ver);
- print_flags32("e32_mflags", mflags,
- "PROCLIBINIT".ptr, LX_FLAG_PROCLIBINIT,
- "INTFIXUPS".ptr, LX_FLAG_INTFIXUPS,
- "EXTFIXUPS".ptr, LX_FLAG_EXTFIXUPS,
- "INCOMPATPMWIN".ptr, LX_FLAG_INCOMPATPMWIN,
- "COMPATPMWIN".ptr, LX_FLAG_COMPATPMWIN,
- "USESPMWIN".ptr, LX_FLAG_USESPMWIN,
- "MODUNLOADABLE".ptr, LX_FLAG_MODUNLOADABLE,
- "PROCLIBTERM".ptr, LX_FLAG_PROCLIBTERM,
- null);
- print_x32("e32_mflags:ModuleType", mflags, adbg_object_lx_modtype_string(mflags));
- print_u32("e32_mpages", mpages);
- print_x32("e32_startobj", startobj);
- print_x32("e32_eip", eip);
- print_x32("e32_stackobj", stackobj);
- print_x32("e32_esp", esp);
- print_u32("e32_pagesize", pagesize);
- print_x32("e32_pageshift", pageshift);
- print_u32("e32_fixupsize", fixupsize);
- print_x32("e32_fixupsum", fixupsum);
- print_u32("e32_ldrsize", ldrsize);
- print_x32("e32_ldrsum", ldrsum);
- print_x32("e32_objtab", objtab);
- print_x32("e32_objcnt", objcnt);
- print_x32("e32_objmap", objmap);
- print_x32("e32_itermap", itermap);
- print_x32("e32_rsrctab", rsrctab);
- print_x32("e32_rsrccnt", rsrccnt);
- print_x32("e32_restab", restab);
- print_x32("e32_enttab", enttab);
- print_x32("e32_dirtab", dirtab);
- print_x32("e32_dircnt", dircnt);
- print_x32("e32_fpagetab", fpagetab);
- print_x32("e32_frectab", frectab);
- print_x32("e32_impmod", impmod);
- print_x32("e32_impmodcnt", impmodcnt);
- print_x32("e32_impproc", impproc);
- print_x32("e32_pagesum", pagesum);
- print_x32("e32_datapage", datapage);
- print_x32("e32_preload", preload);
- print_x32("e32_nrestab", nrestab);
- print_u32("e32_cbnrestab", cbnrestab);
- print_x32("e32_nressum", nressum);
- print_x32("e32_autodata", autodata);
- print_x32("e32_debuginfo", debuginfo);
- print_u32("e32_debuglen", debuglen);
- print_x32("e32_instpreload", instpreload);
- print_x32("e32_instdemand", instdemand);
- print_u32("e32_heapsize", heapsize);
- print_u32("e32_stacksize", stacksize);
- print_x8("e32_res[0]", res1[0]);
- print_x8("e32_res[1]", res1[1]);
- print_x8("e32_res[2]", res1[2]);
- print_x8("e32_res[3]", res1[3]);
- print_x8("e32_res[4]", res1[4]);
- print_x8("e32_res[5]", res1[5]);
- print_x8("e32_res[6]", res1[6]);
- print_x8("e32_res[7]", res1[7]);
- if (magic == LE_MAGIC) {
- print_x32("winresoff", winresoff);
- print_u32("winreslen", winreslen);
- print_x16("device_id", device_id);
- print_x16("ddk_version", ddk_version);
- } else {
- print_x8("e32_res[8]", res[8]);
- print_x8("e32_res[9]", res[9]);
- print_x8("e32_res[10]", res[10]);
- print_x8("e32_res[11]", res[11]);
- print_x8("e32_res[12]", res[12]);
- print_x8("e32_res[13]", res[13]);
- print_x8("e32_res[14]", res[14]);
- print_x8("e32_res[15]", res[15]);
- print_x8("e32_res[16]", res[16]);
- print_x8("e32_res[17]", res[17]);
- print_x8("e32_res[18]", res[18]);
- print_x8("e32_res[19]", res[19]);
- }
- }
-}
\ No newline at end of file
diff --git a/app/dump/macho.d b/app/dump/macho.d
deleted file mode 100644
index 1171ac8..0000000
--- a/app/dump/macho.d
+++ /dev/null
@@ -1,91 +0,0 @@
-/// Mach-O object dumper.
-///
-/// Authors: dd86k
-/// Copyright: © dd86k
-/// License: BSD-3-Clause-Clear
-module dump.macho;
-
-import adbg.disassembler;
-import adbg.object.server;
-import adbg.object.format.macho;
-import dumper;
-
-int dump_macho(ref Dumper dump, adbg_object_t *o) {
- if (dump.selected_headers)
- dump_macho_hdr(dump, o);
-
- return 0;
-}
-
-private:
-
-void dump_macho_hdr(ref Dumper dump, adbg_object_t *o) {
- if (o.i.macho.fat) {
- print_header("FAT Header");
-
- with (o.i.macho.fat_header) {
- print_x32("magic", magic, adbg_object_macho_magic_string(magic));
- print_u32("nfat_arch", nfat_arch);
- }
-
- print_header("FAT Arch Header");
-
- size_t i;
- macho_fat_arch *fa = void;
- while ((fa = adbg_object_macho_fat_arch(o, i++)) != null) with (fa) {
- print_x32("cputype", cputype, adbg_object_macho_cputype_string(cputype));
- print_x32("subtype", subtype, adbg_object_macho_subtype_string(cputype, subtype));
- print_x32("offset", offset);
- print_x32("size", size);
- print_x32("alignment", alignment);
- }
- } else {
- print_header("Header");
-
- with (o.i.macho.header) {
- print_x32("magic", magic, adbg_object_macho_magic_string(magic));
- print_x32("cputype", cputype, adbg_object_macho_cputype_string(cputype));
- print_x32("subtype", subtype, adbg_object_macho_subtype_string(cputype, subtype));
- print_x32("filetype", filetype, adbg_object_macho_filetype_string(filetype));
- print_u32("ncmds", ncmds);
- print_u32("sizeofcmds", sizeofcmds);
- print_flags32("flags", flags,
- "NOUNDEFS".ptr, MACHO_FLAG_NOUNDEFS,
- "INCRLINK".ptr, MACHO_FLAG_INCRLINK,
- "DYLDLINK".ptr, MACHO_FLAG_DYLDLINK,
- "BINDATLOAD".ptr, MACHO_FLAG_BINDATLOAD,
- "PREBOUND".ptr, MACHO_FLAG_PREBOUND,
- "SPLIT_SEGS".ptr, MACHO_FLAG_SPLIT_SEGS,
- "LAZY_INIT".ptr, MACHO_FLAG_LAZY_INIT,
- "TWOLEVEL".ptr, MACHO_FLAG_TWOLEVEL,
- "FORCE_FLAT".ptr, MACHO_FLAG_FORCE_FLAT,
- "NOMULTIDEFS".ptr, MACHO_FLAG_NOMULTIDEFS,
- "NOFIXPREBINDING".ptr, MACHO_FLAG_NOFIXPREBINDING,
- "PREBINDABLE".ptr, MACHO_FLAG_PREBINDABLE,
- "ALLMODSBOUND".ptr, MACHO_FLAG_ALLMODSBOUND,
- "SUBSECTIONS_VIA_SYMBOLS".ptr, MACHO_FLAG_SUBSECTIONS_VIA_SYMBOLS,
- "CANONICAL".ptr, MACHO_FLAG_CANONICAL,
- "WEAK_DEFINES".ptr, MACHO_FLAG_WEAK_DEFINES,
- "BINDS_TO_WEAK".ptr, MACHO_FLAG_BINDS_TO_WEAK,
- "ALLOW_STACK_EXECUTION".ptr, MACHO_FLAG_ALLOW_STACK_EXECUTION,
- "ROOT_SAFE".ptr, MACHO_FLAG_ROOT_SAFE,
- "SETUID_SAFE".ptr, MACHO_FLAG_SETUID_SAFE,
- "NO_REEXPORTED_DYLIBS".ptr, MACHO_FLAG_NO_REEXPORTED_DYLIBS,
- "PIE".ptr, MACHO_FLAG_PIE,
- "DEAD_STRIPPABLE_DYLIB".ptr, MACHO_FLAG_DEAD_STRIPPABLE_DYLIB,
- "HAS_TLV_DESCRIPTORS".ptr, MACHO_FLAG_HAS_TLV_DESCRIPTORS,
- "NO_HEAP_EXECUTION".ptr, MACHO_FLAG_NO_HEAP_EXECUTION,
- "APP_EXTENSION_SAFE".ptr, MACHO_FLAG_APP_EXTENSION_SAFE,
- null);
- }
-
- print_header("Load commands");
-
- size_t i;
- macho_load_command *command = void;
- while ((command = adbg_object_macho_load_command(o, i++)) != null) with (command) {
- print_x32("cmd", cmd, adbg_object_macho_command_string(cmd));
- print_x32("cmdsize", cmdsize);
- }
- }
-}
\ No newline at end of file
diff --git a/app/dump/mdmp.d b/app/dump/mdmp.d
deleted file mode 100644
index 635489a..0000000
--- a/app/dump/mdmp.d
+++ /dev/null
@@ -1,163 +0,0 @@
-/// Minidump dumper
-///
-/// Authors: dd86k
-/// Copyright: © dd86k
-/// License: BSD-3-Clause-Clear
-module dump.mdmp;
-
-import adbg.disassembler;
-import adbg.object.server;
-import adbg.machines;
-import adbg.object.format.mdmp;
-import adbg.utils.date : ctime32;
-import adbg.include.windows.winnt;
-import dumper;
-import utils : realstring;
-
-int dump_minidump(ref Dumper dump, adbg_object_t *o) {
- if (dump.selected_headers())
- dump_minidump_headers(dump, o);
-
- //if (dump.selected_debug())
- // dump_minidump_debug(dump, o);
-
- return 0;
-}
-
-private:
-
-void dump_minidump_headers(ref Dumper dump, adbg_object_t *o) {
- print_header("Header");
- with (o.i.mdmp.header) {
- print_x32("Signature", Signature);
- print_x16("Magic", Magic);
- print_u16("Version", Version);
- print_x32("StreamCount", StreamCount);
- print_x32("StreamRva", StreamRva);
- print_x32("Checksum", Checksum);
- print_x32("Timestamp", Timestamp, ctime32(Timestamp));
- print_flags64("Flags", Flags,
- "WithDataSegs".ptr, MiniDumpWithDataSegs,
- "WithFullMemory".ptr, MiniDumpWithFullMemory,
- "WithHandleData".ptr, MiniDumpWithHandleData,
- "FilterMemory".ptr, MiniDumpFilterMemory,
- "ScanMemory".ptr, MiniDumpScanMemory,
- "WithUnloadedModules".ptr, MiniDumpWithUnloadedModules,
- "WithIndirectlyReferencedMemory".ptr, MiniDumpWithIndirectlyReferencedMemory,
- "FilterModulePaths".ptr, MiniDumpFilterModulePaths,
- "WithProcessThreadData".ptr, MiniDumpWithProcessThreadData,
- "WithPrivateReadWriteMemory".ptr, MiniDumpWithPrivateReadWriteMemory,
- "WithoutOptionalData".ptr, MiniDumpWithoutOptionalData,
- "WithFullMemoryInfo".ptr, MiniDumpWithFullMemoryInfo,
- "WithThreadInfo".ptr, MiniDumpWithThreadInfo,
- "WithCodeSegs".ptr, MiniDumpWithCodeSegs,
- "WithoutAuxiliaryState".ptr, MiniDumpWithoutAuxiliaryState,
- "WithFullAuxiliaryState".ptr, MiniDumpWithFullAuxiliaryState,
- "WithPrivateWriteCopyMemory".ptr, MiniDumpWithPrivateWriteCopyMemory,
- "IgnoreInaccessibleMemory".ptr, MiniDumpIgnoreInaccessibleMemory,
- "WithTokenInformation".ptr, MiniDumpWithTokenInformation,
- "WithModuleHeaders".ptr, MiniDumpWithModuleHeaders,
- "FilterTriage".ptr, MiniDumpFilterTriage,
- "WithAvxXStateContext".ptr, MiniDumpWithAvxXStateContext,
- "WithIptTrace".ptr, MiniDumpWithIptTrace,
- "ScanInaccessiblePartialPages".ptr, MiniDumpScanInaccessiblePartialPages,
- "FilterWriteCombinedMemory".ptr, MiniDumpFilterWriteCombinedMemory,
- null);
- }
-}
-
-void dump_minidump_debug(ref Dumper dump, adbg_object_t *o) {
- print_header("Debug");
-
- uint cnt = o.i.mdmp.header.StreamCount;
- uint off = o.i.mdmp.header.StreamRva;
- mdmp_directory_entry *dir = void;
- if (adbg_object_offsetl(o, cast(void**)&dir, off, cnt * mdmp_directory_entry.sizeof)) {
- print_string("error", "Directory outside file bounds");
- return;
- }
-
- for (uint i; i < cnt; ++i) {
- mdmp_directory_entry *entry = &dir[i];
-
- with (entry) {
- print_x32("StreamType", StreamType);
- print_x32("Size", Size);
- print_x32("Rva", Rva);
- }
-
- switch (entry.StreamType) {
- case ThreadListStream:
- print_header("Threadlist");
-
- mdmp_threadlist *tlist = void;
- if (adbg_object_offsetl(o, cast(void**)&tlist,
- entry.Rva, uint.sizeof + mdmp_thread.sizeof)) {
- print_string("warning", "Threadlist.Rva points outbound");
- continue;
- }
- for (uint ti; ti < tlist.Count; ++ti) {
- mdmp_thread *thread = &tlist.Threads.ptr[ti];
- print_section(ti);
- print_x32("ID", thread.ID);
- print_x32("SuspendCount", thread.SuspendCount);
- print_x32("PriorityClass", thread.PriorityClass);
- print_x32("Priority", thread.Priority);
- print_x64("Teb", thread.Teb);
-
- X86_NT_CONTEXT *context = void;
- if (adbg_object_offsetl(o, cast(void**)&context,
- thread.ThreadContext.Rva, thread.ThreadContext.Size)) {
- print_string("warning", "Thread.Context.Rva points outbound");
- continue;
- }
-
- print_x32("Eip", context.Eip);
- }
- break;
- case ModuleListStream:
- break;
- case MemoryListStream:
- break;
- case ExceptionStream:
- break;
- case SystemInfoStream:
- break;
- case ThreadExListStream:
- break;
- case Memory64ListStream:
- break;
- case CommentStreamA:
- break;
- case CommentStreamW:
- break;
- case HandleDataStream:
- break;
- case FunctionTableStream:
- break;
- case UnloadedModuleListStream:
- break;
- case MiscInfoStream:
- break;
- case MemoryInfoListStream:
- break;
- case ThreadInfoListStream:
- break;
- case HandleOperationListStream:
- break;
- case TokenStream:
- break;
- case JavaScriptDataStream:
- break;
- case SystemMemoryInfoStream:
- break;
- case ProcessVmCountersStream:
- break;
- case IptTraceStream:
- break;
- case ThreadNamesStream:
- break;
- default: continue;
- }
- }
-}
\ No newline at end of file
diff --git a/app/dump/mscoff.d b/app/dump/mscoff.d
deleted file mode 100644
index 684e1ed..0000000
--- a/app/dump/mscoff.d
+++ /dev/null
@@ -1,71 +0,0 @@
-/// MS-COFF dumper
-///
-/// Authors: dd86k
-/// Copyright: © dd86k
-/// License: BSD-3-Clause-Clear
-module dump.mscoff;
-
-import adbg.disassembler;
-import adbg.object.server;
-import adbg.machines;
-import adbg.object.format.mscoff;
-import adbg.object.format.pe : adbg_object_pe_machine_string;
-import adbg.utils.uid;
-import dumper;
-
-int dump_mscoff(ref Dumper dump, adbg_object_t *o) {
- if (dump.selected_headers())
- dump_mscoff_hdr(dump, o);
-
- return 0;
-}
-
-private:
-
-void dump_mscoff_hdr(ref Dumper dump, adbg_object_t *o) {
- print_header("Header");
-
- switch (o.i.mscoff.import_header.Version) {
- case MSCOFF_VERSION_IMPORT: // 0
- with (o.i.mscoff.import_header) {
- print_x16("Sig1", Sig1);
- print_x16("Sig2", Sig2);
- print_u16("Version", Version);
- print_x16("Machine", Machine, adbg_object_pe_machine_string(Machine));
- print_x32("TimeStamp", TimeStamp);
- print_x32("Size", Size);
- print_x16("Ordinal", Ordinal);
- print_x64("Flags", Flags);
- }
- break;
- case MSCOFF_VERSION_ANON: // 1
- with (o.i.mscoff.anon_header) {
- print_x16("Sig1", Sig1);
- print_x16("Sig2", Sig2);
- print_u16("Version", Version);
- print_x16("Machine", Machine, adbg_object_pe_machine_string(Machine));
- print_x32("TimeDateStamp", TimeDateStamp);
- char[UID_TEXTLEN] uid = void;
- uid_text(ClassID, uid, UID_GUID);
- print_string("ClassID", uid.ptr);
- print_x32("SizeOfData", SizeOfData);
- }
- break;
- case MSCOFF_VERSION_ANONV2: // 2
- with (o.i.mscoff.anon_v2_header) {
- print_x16("Sig1", Sig1);
- print_x16("Sig2", Sig2);
- print_u16("Version", Version);
- print_x16("Machine", Machine, adbg_object_pe_machine_string(Machine));
- print_x32("TimeDateStamp", TimeDateStamp);
- char[UID_TEXTLEN] uid = void;
- uid_text(ClassID, uid, UID_GUID);
- print_string("ClassID", uid.ptr);
- print_x32("SizeOfData", SizeOfData);
- print_x32("Flags", Flags);
- print_x32("MetaDataSize", MetaDataSize);
- }
- break;
- default:
- }
-}
\ No newline at end of file
diff --git a/app/dump/mz.d b/app/dump/mz.d
deleted file mode 100644
index 21f9296..0000000
--- a/app/dump/mz.d
+++ /dev/null
@@ -1,85 +0,0 @@
-/// MS-DOS MZ file dumper
-///
-/// Authors: dd86k
-/// Copyright: © dd86k
-/// License: BSD-3-Clause-Clear
-module dump.mz;
-
-import adbg.disassembler;
-import adbg.object.server;
-import adbg.machines : AdbgMachine;
-import adbg.object.format.mz;
-import dumper;
-
-extern (C):
-
-/// Print MZ object.
-/// Params:
-/// dump = Dumper instance.
-/// o = Object instance.
-/// Returns: Non-zero on error.
-int dump_mz(ref Dumper dump, adbg_object_t *o) {
- if (dump.selected_headers())
- dump_mz_hdr(dump, o);
-
- if (dump.selected_relocations())
- dump_mz_relocs(dump, o);
-
- if (dump.selected_disasm_any())
- dump_mz_disasm(dump, o);
-
- return 0;
-}
-
-private:
-
-void dump_mz_hdr(ref Dumper dump, adbg_object_t *o) {
- print_header("Header");
-
- with (o.i.mz.header) {
- print_u16("e_cblp", e_cblp);
- print_u16("e_cp", e_cp);
- print_u16("e_crlc", e_crlc);
- print_u16("e_cparh", e_cparh);
- print_u16("e_minalloc", e_minalloc);
- print_u16("e_maxalloc", e_maxalloc);
- print_x16("e_ss", e_ss);
- print_x16("e_sp", e_sp);
- print_x16("e_csum", e_csum);
- print_x16("e_ip", e_ip);
- print_x16("e_cs", e_cs);
- print_x16("e_lfarlc", e_lfarlc);
- print_u16("e_ovno", e_ovno);
- }
-}
-
-void dump_mz_relocs(ref Dumper dump, adbg_object_t *o) {
- print_header("Relocations");
-
- mz_reloc *reloc = void;
- size_t i;
- while ((reloc = adbg_object_mz_reloc(o, i++)) != null) with (reloc)
- print_reloc16(cast(uint)i, segment, offset);
-}
-
-void dump_mz_disasm(ref Dumper dump, adbg_object_t *o) {
- // Get start of data
- uint start = (o.i.mz.header.e_cparh << 4) + o.i.mz.header.e_cblp; // paragraphs * 16
- if (start < mz_hdr.sizeof || start >= o.file_size) {
- print_string("error", "Data start outside of file buffer");
- return;
- }
-
- // Get data length
- uint len = (o.i.mz.header.e_cp << 4) + o.i.mz.header.e_cblp; // paragraphs * 16
- if (len == 0) {
- print_string("error", "Length is zero");
- return;
- }
- if (len > o.file_size) {
- print_string("error", "Data length cannot be bigger than file");
- return;
- }
-
- dump_disassemble_object(dump, o, null, 0, o.buffer + start, len, 0);
-}
diff --git a/app/dump/ne.d b/app/dump/ne.d
deleted file mode 100644
index 123810e..0000000
--- a/app/dump/ne.d
+++ /dev/null
@@ -1,64 +0,0 @@
-/// Windows 1.x NE file dumper
-///
-/// Authors: dd86k
-/// Copyright: © dd86k
-/// License: BSD-3-Clause-Clear
-module dump.ne;
-
-import adbg.disassembler;
-import adbg.object.server;
-import adbg.machines : AdbgMachine;
-import adbg.object.format.ne;
-import dumper;
-
-extern (C):
-
-int dump_ne(ref Dumper dump, adbg_object_t *o) {
- if (dump.selected_headers())
- dump_ne_hdr(dump, o);
- return 0;
-}
-
-private:
-
-void dump_ne_hdr(ref Dumper dump, adbg_object_t *o) {
- print_header("Header");
-
- with (o.i.ne.header) {
- print_x16("ne_magic", ne_magic);
- print_u8("ne_ver", ne_ver);
- print_u8("ne_rev", ne_rev);
- print_x16("ne_enttab", ne_enttab);
- print_u16("ne_cbenttab", ne_cbenttab);
- print_x32("ne_crc", ne_crc);
- print_flags16("ne_flags", ne_flags,
- "SINGLEDATA".ptr, NE_HFLAG_SINGLEDATA,
- "MULTIPLEDATA".ptr, NE_HFLAG_MULTIPLEDATA,
- "LINKERERROR".ptr, NE_HFLAG_LINKERERROR,
- "LIBMODULE".ptr, NE_HFLAG_LIBMODULE,
- null);
- print_u16("ne_autodata", ne_autodata);
- print_u16("ne_heap", ne_heap);
- print_u16("ne_stack", ne_stack);
- print_x32("ne_csip", ne_csip);
- print_x32("ne_sssp", ne_sssp);
- print_u16("ne_cseg", ne_cseg);
- print_u16("ne_cmod", ne_cmod);
- print_u16("ne_cbnrestab", ne_cbnrestab);
- print_x16("ne_segtab", ne_segtab);
- print_x16("ne_rsrctab", ne_rsrctab);
- print_x16("ne_restab", ne_restab);
- print_x16("ne_modtab", ne_modtab);
- print_x16("ne_imptab", ne_imptab);
- print_x32("ne_nrestab", ne_nrestab);
- print_u16("ne_cmovent", ne_cmovent);
- print_u16("ne_align", ne_align);
- print_u16("ne_cres", ne_cres);
- print_u8("ne_exetyp", ne_exetyp, adbg_object_ne_type(ne_exetyp));
- print_x8("ne_flagsothers", ne_flagsothers);
- print_x16("ne_pretthunks", ne_pretthunks);
- print_x16("ne_psegrefbytes", ne_psegrefbytes);
- print_x16("ne_swaparea", ne_swaparea);
- print_x16("ne_expver", ne_expver);
- }
-}
\ No newline at end of file
diff --git a/app/dump/package.d b/app/dump/package.d
deleted file mode 100644
index 2f958a4..0000000
--- a/app/dump/package.d
+++ /dev/null
@@ -1,23 +0,0 @@
-/**
- * Objects dump package
- *
- * Authors: dd86k
- * Copyright: © dd86k
- * License: BSD-3-Clause-Clear
- */
-module dump;
-
-public import
- dump.mz,
- dump.ne,
- dump.lx,
- dump.pe,
- dump.elf,
- dump.macho,
- dump.pdb70,
- dump.pdb20,
- dump.mdmp,
- dump.dmp,
- dump.ar,
- dump.coff,
- dump.mscoff;
\ No newline at end of file
diff --git a/app/dump/pdb20.d b/app/dump/pdb20.d
deleted file mode 100644
index 07c0973..0000000
--- a/app/dump/pdb20.d
+++ /dev/null
@@ -1,39 +0,0 @@
-/// PDB 2.00 dumper
-///
-/// Authors: dd86k
-/// Copyright: © dd86k
-/// License: BSD-3-Clause-Clear
-module dump.pdb20;
-
-import adbg.disassembler;
-import adbg.object.server;
-import adbg.machines;
-import adbg.object.format.pdb;
-import dumper;
-
-extern (C):
-
-int dump_pdb20(ref Dumper dump, adbg_object_t *o) {
- if (dump.selected_headers())
- dump_pdb20_header(dump, o);
-
- return 0;
-}
-
-private:
-
-void dump_pdb20_header(ref Dumper dump, adbg_object_t *o) {
- print_header("Header");
-
- pdb20_file_header *header = adbg_object_pdb20_header(o);
-
- with (header) {
- print_stringl("Magic", header.Magic.ptr, 37);
- print_u32("PageSize", PageSize);
- print_u16("StartPage", StartPage);
- print_u16("PageCount", PageCount);
- print_u32("RootSize", RootSize);
- print_x32("Reserved", Reserved);
- print_u16("RootNumber", RootNumber);
- }
-}
\ No newline at end of file
diff --git a/app/dump/pdb70.d b/app/dump/pdb70.d
deleted file mode 100644
index 9c040b3..0000000
--- a/app/dump/pdb70.d
+++ /dev/null
@@ -1,278 +0,0 @@
-/// PDB 7.00 dumper
-///
-/// Authors: dd86k
-/// Copyright: © dd86k
-/// License: BSD-3-Clause-Clear
-module dump.pdb70;
-
-import adbg.disassembler;
-import adbg.object.server;
-import adbg.machines;
-import adbg.object.format.pdb;
-import adbg.object.format.pe : adbg_object_pe_machine_string;
-import adbg.utils.uid;
-import adbg.utils.date;
-import adbg.include.c.stdio : printf, snprintf, putchar;
-import dumper;
-
-extern (C):
-
-int dump_pdb70(ref Dumper dump, adbg_object_t *o) {
- if (dump.selected_headers())
- dump_pdb70_header(dump, o);
-
- if (dump.selected_debug())
- dump_pdb70_debug(dump, o);
-
- return 0;
-}
-
-private:
-
-void dump_pdb70_header(ref Dumper dump, adbg_object_t *o) {
- print_header("Header");
-
- pdb70_file_header *header = adbg_object_pdb70_header(o);
-
- print_stringl("Magic", header.Magic.ptr, 24);
- print_u32("PageSize", header.PageSize);
- print_u32("FreeIndex", header.FreeIndex);
- print_u32("PageCount", header.PageCount);
- print_u32("DirectorySize", header.DirectorySize);
- print_x32("Unknown", header.Unknown);
- print_x32("DirectoryOffset", header.DirectoryOffset);
-
- print_header("FPM information");
- uint bitcnt = header.PageCount / 8;
- for (uint biti; biti < bitcnt; ++biti) {
- char[48] buf = void;
- uint blocknum = biti * 8;
- snprintf(buf.ptr, 48, "Block %u-%u", blocknum, blocknum + 7);
- print_x8(buf.ptr, o.i.pdb70.fpm[biti]);
- }
-
- print_header("Stream information");
- print_u32("Stream count", o.i.pdb70.strcnt);
- uint strcnt = o.i.pdb70.strcnt;
- uint blkoffi;
- // NOTE: Avoid using internal section map in case it changes
- for (uint stri; stri < strcnt; ++stri) {
- uint size = o.i.pdb70.strsize[stri];
-
- // Print field name
- char[48] buf = void;
- snprintf(buf.ptr, 48, "Stream %u", stri);
- print_name(buf.ptr);
-
- // Skip if empty
- //TODO: Check with FPM?
- if (size == 0 || size == PDB_BLOCK_SIZE_UNUSED) {
- putchar('\n');
- continue;
- }
-
- // Print size + associated blocks
- printf("%u\t(", size);
- uint blkcnt = (size + header.PageSize - 1) / header.PageSize;
- for (uint blki; blki < blkcnt; ++blki) {
- if (blki) putchar(',');
- printf("%u", o.i.pdb70.stroff[blkoffi++]);
- }
- printf(")\n");
- }
-}
-
-void dump_pdb70_debug(ref Dumper dump, adbg_object_t *o) {
- print_header("Debug");
-
- static immutable string[] StreamNames = [
- "Old MSF Directory",
- "PDB Stream",
- "TPI Stream",
- "DBI Stream",
- "IPI Stream",
- ];
-
- void *buffer;
- uint strsize;
-
- print_section(0, StreamNames[0].ptr, cast(int)StreamNames[0].length);
- if (adbg_object_pdb70_stream_open(o, &buffer, &strsize, PdbStream.pdb)) {
- print_string("error", "Couldn't read Stream 0");
- return;
- }
- if (strsize) {
- print_raw("Stream 0 Data", buffer, strsize);
- }
- adbg_object_pdb70_stream_close(o, &buffer);
-
- // Stream 1
-
- print_section(1, StreamNames[1].ptr, cast(int)StreamNames[1].length);
- if (adbg_object_pdb70_stream_open(o, &buffer, &strsize, PdbStream.pdb)) {
- print_string("error", "Couldn't read Stream 1");
- return;
- }
- if (strsize >= pdb70_pdb_header.sizeof) {
- pdb70_pdb_header *pdb = cast(pdb70_pdb_header*)buffer;
- const(char) *vcver = void;
- switch (pdb.Version) with (PdbRaw_PdbVersion) {
- case vc2: vcver = "VC2"; break;
- case vc4: vcver = "VC4"; break;
- case vc41: vcver = "VC41"; break;
- case vc50: vcver = "VC50"; break;
- case vc98: vcver = "VC98"; break;
- case vc70_old: vcver = "VC70_OLD"; break;
- case vc70: vcver = "VC70"; break;
- case vc80: vcver = "VC80"; break;
- case vc110: vcver = "VC110"; break;
- case vc140: vcver = "VC140"; break;
- default: vcver = "Unknown";
- }
-
- char[UID_TEXTLEN] uidstr = void;
- int uidlen = uid_string(pdb.UniqueId, uidstr.ptr, UID_TEXTLEN, UID_GUID);
- print_u32("Version", pdb.Version, vcver);
- print_x32("Signature", pdb.Signature);
- print_u32("Age", pdb.Age);
- print_stringl("UniqueID", uidstr.ptr, uidlen);
-
- /*void *leftover = buffer + pdb70_pdb_header.sizeof;
- size_t leftlen = strsize - pdb70_pdb_header.sizeof;
-
- print_raw("Stream 1 Data", leftover, leftlen);*/
- }
- adbg_object_pdb70_stream_close(o, &buffer);
-
- // Stream 2
-
- print_section(2, StreamNames[2].ptr, cast(int)StreamNames[2].length);
- if (adbg_object_pdb70_stream_open(o, &buffer, &strsize, PdbStream.tpi)) {
- print_string("error", "Couldn't read Stream 2");
- return;
- }
- if (strsize >= pdb70_tpi_header.sizeof) {
- pdb70_tpi_header *tpi = cast(pdb70_tpi_header*)buffer;
- const(char) *vcver = void;
- switch (tpi.Version) with (PdbRaw_TpiVer) {
- case v40: vcver = "v40"; break;
- case v41: vcver = "v41"; break;
- case v50: vcver = "v50"; break;
- case v70: vcver = "v70"; break;
- case v80: vcver = "v80"; break;
- default: vcver = "Unknown";
- }
-
- print_u32("Version", tpi.Version, vcver);
- print_u32("HeaderSize", tpi.HeaderSize);
- print_u32("TypeIndexBegin", tpi.TypeIndexBegin);
- print_u32("TypeIndexEnd", tpi.TypeIndexEnd);
- print_u32("TypeRecordBytes", tpi.TypeRecordBytes);
-
- print_u16("HashStreamIndex", tpi.HashStreamIndex);
- print_u16("HashAuxStreamIndex", tpi.HashAuxStreamIndex);
- print_u32("HashKeySize", tpi.HashKeySize);
- print_u32("NumHashBuckets", tpi.NumHashBuckets);
-
- print_u32("HashValueBufferOffset", tpi.HashValueBufferOffset);
- print_u32("HashValueBufferLength", tpi.HashValueBufferLength);
-
- print_u32("IndexOffsetBufferOffset", tpi.IndexOffsetBufferOffset);
- print_u32("IndexOffsetBufferLength", tpi.IndexOffsetBufferLength);
-
- print_u32("HashAdjBufferOffset", tpi.HashAdjBufferOffset);
- print_u32("HashAdjBufferLength", tpi.HashAdjBufferLength);
-
- /*void *leftover = buffer + pdb70_tpi_header.sizeof;
- size_t leftlen = strsize - pdb70_tpi_header.sizeof;
-
- print_raw("Stream 2 Data", leftover, leftlen);*/
- }
- adbg_object_pdb70_stream_close(o, &buffer);
-
- // Stream 3
-
- print_section(3, StreamNames[3].ptr, cast(int)StreamNames[3].length);
- if (adbg_object_pdb70_stream_open(o, &buffer, &strsize, PdbStream.dbi)) {
- print_string("error", "Couldn't read Stream 3");
- return;
- }
- if (strsize >= pdb70_dbi_header.sizeof) {
- pdb70_dbi_header *dbi = cast(pdb70_dbi_header*)buffer;
-
- const(char) *vcver = void;
- switch (dbi.VersionHeader) with (PdbRaw_DbiVer) {
- case v41: vcver = "v41"; break;
- case v50: vcver = "v50"; break;
- case v60: vcver = "v60"; break;
- case v70: vcver = "v70"; break;
- case v110: vcver = "v110"; break;
- default: vcver = "Unknown";
- }
-
- // 255.127-1
- char[16] buildnum = void;
- snprintf(buildnum.ptr, 16, "%u.%u-%u",
- dbi.BuildNumber >> 8 & 0x7f, // MajorVersion
- cast(ubyte)dbi.BuildNumber, // MinorVersion
- dbi.BuildNumber >> 15); // NewVersionFormat
-
- print_x32("VersonSignature", dbi.VersonSignature);
- print_u32("VersionHeader", dbi.VersionHeader, vcver);
- print_u32("Age", dbi.Age);
- print_u16("GlobalStreamIndex", dbi.GlobalStreamIndex);
- print_x16("BuildNumber", dbi.BuildNumber, buildnum.ptr);
- print_u16("PublicStreamIndex", dbi.PublicStreamIndex);
- print_u16("PdbDllVersion", dbi.PdbDllVersion);
- print_u16("SymRecordStream", dbi.SymRecordStream);
- print_u16("PdbDllRbld", dbi.PdbDllRbld);
- print_u32("ModInfoSize", dbi.ModInfoSize);
- print_u32("SectionContributionSize", dbi.SectionContributionSize);
- print_u32("SectionMapSize", dbi.SectionMapSize);
- print_u32("SourceInfoSize", dbi.SourceInfoSize);
- print_u32("TypeServerMapSize", dbi.TypeServerMapSize);
- print_u32("MFCTypeServerIndex", dbi.MFCTypeServerIndex);
- print_u32("OptionalDbgHeaderSize", dbi.OptionalDbgHeaderSize);
- print_u32("ECSubstreamSize", dbi.ECSubstreamSize);
- print_flags16("Flags", dbi.Flags,
- "IncrementallyLinked".ptr, PdbRaw_DbiFlags.IncrementallyLinked,
- "PrivateSymbolsStripped".ptr, PdbRaw_DbiFlags.PrivateSymbolsStripped,
- "ConflictingTypes".ptr, PdbRaw_DbiFlags.ConflictingTypes,
- null);
- print_x16("Machine", dbi.Machine, adbg_object_pe_machine_string(dbi.Machine));
- print_u32("Padding", dbi.Padding);
-
- /*void *leftover = buffer + pdb70_dbi_header.sizeof;
- size_t leftlen = strsize - pdb70_dbi_header.sizeof;
-
- print_raw("Stream 3 Data", leftover, leftlen);*/
- }
- adbg_object_pdb70_stream_close(o, &buffer);
-
- // Stream 4
- /+print_section(4, StreamNames[4].ptr, cast(int)StreamNames[4].length);
- if (adbg_object_pdb70_stream_open(o, &buffer, &strsize, PdbStream.dbi)) {
- print_string("error", "Couldn't read Stream 3");
- return;
- }
- if (strsize >= pdb70_subsection_header.sizeof) {
- pdb70_subsection_header *ipi = cast(pdb70_subsection_header*)buffer;
-
- enum LIMIT = 200; // Arbitrary
-
- size_t i;
- Lr:
- print_x32("Kind", ipi.Kind);
- print_x32("Length", ipi.Length);
-
- ipi = cast(pdb70_subsection_header*)((cast(void*)ipi) + ipi.Length);
- if (ipi.Kind && ipi.Length && ++i < LIMIT) goto Lr;
- }
- adbg_object_pdb70_stream_close(o, &buffer);+/
-
- /*uint strcnt = o.i.pdb70.strcnt;
- for (uint stridx = 5; stridx < strcnt; ++stridx) {
- char[32] buf = void;
- int l = snprintf(buf.ptr, 32, "Stream %u", stridx);
- }*/
-}
\ No newline at end of file
diff --git a/app/dump/pe.d b/app/dump/pe.d
deleted file mode 100644
index aef4181..0000000
--- a/app/dump/pe.d
+++ /dev/null
@@ -1,801 +0,0 @@
-/// PE32 file dumper
-///
-/// Authors: dd86k
-/// Copyright: © dd86k
-/// License: BSD-3-Clause-Clear
-module dump.pe;
-
-import adbg.disassembler;
-import adbg.object.server;
-import adbg.machines : AdbgMachine;
-import adbg.object.format.pe;
-import adbg.utils.date : ctime32;
-import adbg.utils.uid, adbg.utils.bit;
-import core.stdc.string : strncmp;
-import common, dumper;
-
-extern (C):
-
-/// Print PE object.
-/// Params:
-/// dump = Dumper instance.
-/// o = Object instance.
-/// Returns: Non-zero on error.
-int dump_pe(ref Dumper dump, adbg_object_t *o) {
- if (dump.selected_headers())
- dump_pe_hdr(dump, o);
-
- if (dump.selected_sections())
- dump_pe_sections(dump, o);
-
- if (dump.selected_exports())
- dump_pe_exports(dump, o);
-
- if (dump.selected_imports())
- dump_pe_imports(dump, o);
-
- if (dump.selected_debug())
- dump_pe_debug(dump, o);
-
- if (dump.selected_disasm_any())
- dump_pe_disasm(dump, o);
-
- return 0;
-}
-
-private:
-
-// Returns true if the machine value is unknown
-void dump_pe_hdr(ref Dumper dump, adbg_object_t *o) {
- print_header("Header");
-
- const(char) *str_mach = adbg_object_pe_machine_string(o.i.pe.header.Machine);
-
- if (str_mach == null)
- str_mach = "Unknown";
-
- with (o.i.pe.header) {
- print_x32("Machine", Machine, str_mach);
- print_u32("NumberOfSections", NumberOfSections);
- print_x32("TimeDateStamp", TimeDateStamp, ctime32(TimeDateStamp));
- print_x32("PointerToSymbolTable", PointerToSymbolTable);
- print_u32("NumberOfSymbols", NumberOfSymbols);
- print_u32("SizeOfOptionalHeader", SizeOfOptionalHeader);
- print_flags32("Characteristics", Characteristics,
- "RELOCS_STRIPPED".ptr, PE_CHARACTERISTIC_RELOCS_STRIPPED,
- "EXECUTABLE_IMAGE".ptr, PE_CHARACTERISTIC_EXECUTABLE_IMAGE,
- "LINE_NUMS_STRIPPED".ptr, PE_CHARACTERISTIC_LINE_NUMS_STRIPPED,
- "LOCAL_SYMS_STRIPPED".ptr, PE_CHARACTERISTIC_LOCAL_SYMS_STRIPPED,
- "AGGRESSIVE_WS_TRIM".ptr, PE_CHARACTERISTIC_AGGRESSIVE_WS_TRIM,
- "LARGE_ADDRESS_AWARE".ptr, PE_CHARACTERISTIC_LARGE_ADDRESS_AWARE,
- "16BIT_MACHINE".ptr, PE_CHARACTERISTIC_16BIT_MACHINE,
- "BYTES_REVERSED_LO".ptr, PE_CHARACTERISTIC_BYTES_REVERSED_LO,
- "32BIT_MACHINE".ptr, PE_CHARACTERISTIC_32BIT_MACHINE,
- "DEBUG_STRIPPED".ptr, PE_CHARACTERISTIC_DEBUG_STRIPPED,
- "REMOVABLE_RUN_FROM_SWAP".ptr, PE_CHARACTERISTIC_REMOVABLE_RUN_FROM_SWAP,
- "NET_RUN_FROM_SWAP".ptr, PE_CHARACTERISTIC_NET_RUN_FROM_SWAP,
- "SYSTEM".ptr, PE_CHARACTERISTIC_SYSTEM,
- "DLL".ptr, PE_CHARACTERISTIC_DLL,
- "UP_SYSTEM_ONLY".ptr, PE_CHARACTERISTIC_UP_SYSTEM_ONLY,
- "BYTES_REVERSED_HI".ptr, PE_CHARACTERISTIC_BYTES_REVERSED_HI,
- null);
- }
-
- if (str_mach == null)
- return;
- //TODO: Could be a server check
- if (o.i.pe.header.SizeOfOptionalHeader == 0)
- return;
-
- dump_pe_opthdr(dump, o);
-}
-
-void dump_pe_opthdr(ref Dumper dump, adbg_object_t *o) {
- print_header("Optional Header");
-
- // NOTE: Server already checks magic format
- const(char) *str_mag = adbg_object_pe_magic_string(o.i.pe.opt_header.Magic);
- const(char) *str_sys = adbg_object_pe_subsys_string(o.i.pe.opt_header.Subsystem);
- if (str_sys == null)
- str_sys = "Unknown";
-
- // Common in all magic formats
- with (o.i.pe.opt_header) {
- print_x16("Magic", Magic, str_mag);
- print_u8("MajorLinkerVersion", MajorLinkerVersion);
- print_u8("MinorLinkerVersion", MinorLinkerVersion);
- print_u32("SizeOfCode", SizeOfCode);
- print_u32("SizeOfInitializedData", SizeOfInitializedData);
- print_u32("SizeOfUninitializedData", SizeOfUninitializedData);
- print_x32("AddressOfEntryPoint", AddressOfEntryPoint);
- print_x32("BaseOfCode", BaseOfCode);
- }
-
- switch (o.i.pe.opt_header.Magic) {
- case PE_FMT_32: // 32
- with (o.i.pe.opt_header) {
- print_x32("BaseOfData", BaseOfData);
- print_x32("ImageBase", ImageBase);
- print_u32("SectionAlignment", SectionAlignment);
- print_u32("FileAlignment", FileAlignment);
- print_u16("MajorOperatingSystemVersion", MajorOperatingSystemVersion);
- print_u16("MinorOperatingSystemVersion", MinorOperatingSystemVersion);
- print_u16("MajorImageVersion", MajorImageVersion);
- print_u16("MinorImageVersion", MinorImageVersion);
- print_u16("MajorSubsystemVersion", MajorSubsystemVersion);
- print_u16("MinorSubsystemVersion", MinorSubsystemVersion);
- print_x32("Win32VersionValue", Win32VersionValue);
- print_u32("SizeOfImage", SizeOfImage);
- print_u32("SizeOfHeaders", SizeOfHeaders);
- print_x32("CheckSum", CheckSum);
- print_x16("Subsystem", Subsystem, str_sys);
- dump_pe_dllcharactiristics(DllCharacteristics);
- print_x32("SizeOfStackReserve", SizeOfStackReserve);
- print_x32("SizeOfStackCommit", SizeOfStackCommit);
- print_x32("SizeOfHeapReserve", SizeOfHeapReserve);
- print_x32("SizeOfHeapCommit", SizeOfHeapCommit);
- print_x32("LoaderFlags", LoaderFlags);
- print_u32("NumberOfRvaAndSizes", NumberOfRvaAndSizes);
- }
- break;
- case PE_FMT_64: // 64
- with (o.i.pe.opt_header64) {
- print_x64("ImageBase", ImageBase);
- print_x32("SectionAlignment", SectionAlignment);
- print_x32("FileAlignment", FileAlignment);
- print_u16("MajorOperatingSystemVersion", MajorOperatingSystemVersion);
- print_u16("MinorOperatingSystemVersion", MinorOperatingSystemVersion);
- print_u16("MajorImageVersion", MajorImageVersion);
- print_u16("MinorImageVersion", MinorImageVersion);
- print_u16("MajorSubsystemVersion", MajorSubsystemVersion);
- print_u16("MinorSubsystemVersion", MinorSubsystemVersion);
- print_x32("Win32VersionValue", Win32VersionValue);
- print_u32("SizeOfImage", SizeOfImage);
- print_u32("SizeOfHeaders", SizeOfHeaders);
- print_x32("CheckSum", CheckSum);
- print_u32("Subsystem", Subsystem, str_sys);
- dump_pe_dllcharactiristics(DllCharacteristics);
- print_u64("SizeOfStackReserve", SizeOfStackReserve);
- print_u64("SizeOfStackCommit", SizeOfStackCommit);
- print_u64("SizeOfHeapReserve", SizeOfHeapReserve);
- print_u64("SizeOfHeapCommit", SizeOfHeapCommit);
- print_x32("LoaderFlags", LoaderFlags);
- print_u32("NumberOfRvaAndSizes", NumberOfRvaAndSizes);
- }
- break;
- case PE_FMT_ROM: // ROM has no flags/directories
- with (o.i.pe.opt_headerrom) {
- print_x32("BaseOfData", BaseOfData);
- print_x32("BaseOfBss", BaseOfBss);
- print_x32("GprMask", GprMask);
- print_x32("CprMask[0]", CprMask[0]);
- print_x32("CprMask[1]", CprMask[1]);
- print_x32("CprMask[2]", CprMask[2]);
- print_x32("CprMask[3]", CprMask[3]);
- print_x32("GpValue", GpValue);
- }
- return;
- default:
- }
-
- dump_pe_dirs(dump, o);
-}
-
-void dump_pe_dllcharactiristics(ushort dllchars) {
- print_flags16("DllCharacteristics", dllchars,
- "HIGH_ENTROPY_VA".ptr, PE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA,
- "DYNAMIC_BASE".ptr, PE_DLLCHARACTERISTICS_DYNAMIC_BASE,
- "FORCE_INTEGRITY".ptr, PE_DLLCHARACTERISTICS_FORCE_INTEGRITY,
- "NX_COMPAT".ptr, PE_DLLCHARACTERISTICS_NX_COMPAT,
- "NO_ISOLATION".ptr, PE_DLLCHARACTERISTICS_NO_ISOLATION,
- "NO_SEH".ptr, PE_DLLCHARACTERISTICS_NO_SEH,
- "NO_BIND".ptr, PE_DLLCHARACTERISTICS_NO_BIND,
- "APPCONTAINER".ptr, PE_DLLCHARACTERISTICS_APPCONTAINER,
- "WDM_DRIVER".ptr, PE_DLLCHARACTERISTICS_WDM_DRIVER,
- "GUARD_CF".ptr, PE_DLLCHARACTERISTICS_GUARD_CF,
- "TERMINAL_SERVER_AWARE".ptr, PE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE,
- null);
-}
-
-void dump_pe_dirs(ref Dumper dump, adbg_object_t *o) {
- // ROM check
- //TODO: Make this a server check
- if (o.i.pe.directory == null)
- return;
-
- print_header("Directories");
-
- with (o.i.pe.directory) {
- print_directory_entry("ExportTable", ExportTable.rva, ExportTable.size);
- print_directory_entry("ImportTable", ImportTable.rva, ImportTable.size);
- print_directory_entry("ResourceTable", ResourceTable.rva, ResourceTable.size);
- print_directory_entry("ExceptionTable", ExceptionTable.rva, ExceptionTable.size);
- print_directory_entry("CertificateTable", CertificateTable.rva, CertificateTable.size);
- print_directory_entry("BaseRelocationTable", BaseRelocationTable.rva, BaseRelocationTable.size);
- print_directory_entry("DebugDirectory", DebugDirectory.rva, DebugDirectory.size);
- print_directory_entry("ArchitectureData", ArchitectureData.rva, ArchitectureData.size);
- print_directory_entry("GlobalPtr", GlobalPtr.rva, GlobalPtr.size);
- print_directory_entry("TLSTable", TLSTable.rva, TLSTable.size);
- print_directory_entry("LoadConfigurationTable", LoadConfigurationTable.rva, LoadConfigurationTable.size);
- print_directory_entry("BoundImportTable", BoundImportTable.rva, BoundImportTable.size);
- print_directory_entry("ImportAddressTable", ImportAddressTable.rva, ImportAddressTable.size);
- print_directory_entry("DelayImport", DelayImport.rva, DelayImport.size);
- print_directory_entry("CLRHeader", CLRHeader.rva, CLRHeader.size);
- print_directory_entry("Reserved", Reserved.rva, Reserved.size);
- }
-}
-
-void dump_pe_sections(ref Dumper dump, adbg_object_t *o) {
- print_header("Sections");
-
- PE_SECTION_ENTRY *section = void;
- size_t i;
- while ((section = adbg_object_pe_section(o, i++)) != null) with (section) {
- // If we're searching sections, don't print anything
- if (globals.dump_section) {
- if (strncmp(Name.ptr, globals.dump_section, Name.sizeof) == 0) {
- print_raw(globals.dump_section, // Lazy as fuck
- o.buffer + PointerToRawData, SizeOfRawData, PointerToRawData);
- return;
- }
- continue;
- }
-
- print_section(cast(uint)i, Name.ptr, 8);
- print_x32("VirtualAddress", VirtualAddress);
- print_x32("VirtualSize", VirtualSize);
- print_x32("PointerToRawData", PointerToRawData);
- print_x32("SizeOfRawData", SizeOfRawData);
- print_x32("PointerToRelocations", PointerToRelocations);
- print_x32("PointerToLinenumbers", PointerToLinenumbers);
- print_u16("NumberOfRelocations", NumberOfRelocations);
- print_u16("NumberOfLinenumbers", NumberOfLinenumbers);
- //TODO: Integrate with rest of Characteristics
- static immutable const(char)*[] pe32alignments = [
- "ALIGN_DEFAULT(16)", // PEDUMP (1997)
- "ALIGN_1BYTES",
- "ALIGN_2BYTES",
- "ALIGN_4BYTES",
- "ALIGN_8BYTES",
- "ALIGN_16BYTES",
- "ALIGN_32BYTES",
- "ALIGN_64BYTES",
- "ALIGN_128BYTES",
- "ALIGN_256BYTES",
- "ALIGN_512BYTES",
- "ALIGN_1024BYTES",
- "ALIGN_2048BYTES",
- "ALIGN_4096BYTES",
- "ALIGN_8192BYTES",
- "ALIGN_RESERVED",
- ];
- uint alignment = Characteristics & PE_SECTION_CHARACTERISTIC_ALIGN_MASK;
- print_x32("Alignment", alignment, pe32alignments[alignment >> 20]);
- print_flags32("Characteristics", Characteristics,
- "TYPE_DSECT".ptr, PE_SECTION_CHARACTERISTIC_TYPE_DSECT,
- "TYPE_NOLOAD".ptr, PE_SECTION_CHARACTERISTIC_TYPE_NOLOAD,
- "TYPE_GROUP".ptr, PE_SECTION_CHARACTERISTIC_TYPE_GROUP,
- "NO_PAD".ptr, PE_SECTION_CHARACTERISTIC_NO_PAD,
- "TYPE_COPY".ptr, PE_SECTION_CHARACTERISTIC_TYPE_COPY,
- "CODE".ptr, PE_SECTION_CHARACTERISTIC_CODE,
- "INITIALIZED_DATA".ptr, PE_SECTION_CHARACTERISTIC_INITIALIZED_DATA,
- "UNINITIALIZED_DATA".ptr, PE_SECTION_CHARACTERISTIC_UNINITIALIZED_DATA,
- "LNK_OTHER".ptr, PE_SECTION_CHARACTERISTIC_LNK_OTHER,
- "LNK_INFO".ptr, PE_SECTION_CHARACTERISTIC_LNK_INFO,
- "LNK_REMOVE".ptr, PE_SECTION_CHARACTERISTIC_LNK_REMOVE,
- "LNK_COMDAT".ptr, PE_SECTION_CHARACTERISTIC_LNK_COMDAT,
- "MEM_PROTECTED".ptr, PE_SECTION_CHARACTERISTIC_MEM_PROTECTED,
- "GPREL".ptr, PE_SECTION_CHARACTERISTIC_GPREL,
- "MEM_PURGEABLE".ptr, PE_SECTION_CHARACTERISTIC_MEM_PURGEABLE,
- "MEM_16BIT".ptr, PE_SECTION_CHARACTERISTIC_MEM_16BIT,
- "MEM_LOCKED".ptr, PE_SECTION_CHARACTERISTIC_MEM_LOCKED,
- "PRELOAD".ptr, PE_SECTION_CHARACTERISTIC_PRELOAD,
- "LNK_NRELOC_OVFL".ptr, PE_SECTION_CHARACTERISTIC_LNK_NRELOC_OVFL,
- "MEM_DISCARDABLE".ptr, PE_SECTION_CHARACTERISTIC_MEM_DISCARDABLE,
- "MEM_NOT_CACHED".ptr, PE_SECTION_CHARACTERISTIC_MEM_NOT_CACHED,
- "MEM_NOT_PAGED".ptr, PE_SECTION_CHARACTERISTIC_MEM_NOT_PAGED,
- "MEM_SHARED".ptr, PE_SECTION_CHARACTERISTIC_MEM_SHARED,
- "MEM_EXECUTE".ptr, PE_SECTION_CHARACTERISTIC_MEM_EXECUTE,
- "MEM_READ".ptr, PE_SECTION_CHARACTERISTIC_MEM_READ,
- "MEM_WRITE".ptr, PE_SECTION_CHARACTERISTIC_MEM_WRITE,
- null);
-
- }
-}
-
-/*void dump_pe_loadconfig(ref Dumper dump) {
-
- dump_h1("Load Configuration");
-
- if (dump.obj.pe.loadconfig == null) { // LOAD_CONFIGURATION
- puts("No
- }
- if (fseek(dump.obj.handle, fo_loadcf, SEEK_SET))
- return EXIT_FAILURE;
-
- PE_LOAD_CONFIG_META lconf = void;
- char[32] lcbuffer = void;
-
- if (fread(&lconf, 4, 1, obj.handle) == 0)
- return EXIT_FAILURE;
- if (fread(&lconf.dir32.TimeDateStamp, lconf.dir32.Size, 1, obj.handle) == 0)
- return EXIT_FAILURE;
-
- if (strftime(cast(char*)lcbuffer, 32, "%c",
- localtime(cast(time_t*)&lconf.dir64.TimeDateStamp)) == 0) {
- const(char)* l = cast(char*)&lcbuffer;
- l = "strftime:err";
- }
-
- with (lconf.dir32)
- printf( // Same sizes/offsets
- "\n*\n* Load Config\n*\n\n"~
- "Size %08X\t(%u)\n"~
- "TimeDateStamp %08X\t(%s)\n"~
- "MajorVersion %04X\t(%u)\n"~
- "MinorVersion %04X\t(%u)\n"~
- "GlobalFlagsClear %08X\n"~
- "GlobalFlagsSet %08X\n"~
- "CriticalSectionDefaultTimeout %08X\n",
- Size, Size,
- TimeDateStamp, &lcbuffer,
- MajorVersion, lconf.dir32.MajorVersion,
- MinorVersion, lconf.dir32.MinorVersion,
- GlobalFlagsClear,
- GlobalFlagsSet,
- CriticalSectionDefaultTimeout);
-
- if (dump.optMagic != PE_FMT_64) { // 32
- with (lconf.dir32)
- printf(
- "DeCommitFreeBlockThreshold %08X\n"~
- "DeCommitTotalBlockThreshold %08X\n"~
- "LockPrefixTable %08X\n"~
- "MaximumAllocationSize %08X\t(%u)\n"~
- "VirtualMemoryThreshold %08X\n"~
- "ProcessHeapFlags %08X\n"~
- "ProcessAffinityMask %08X\n"~
- "CSDVersion %04X\n"~
- "Reserved1 %04X\n"~
- "EditList %08X\n"~
- "SecurityCookie %08X\n",
- DeCommitFreeBlockThreshold,
- DeCommitTotalBlockThreshold,
- LockPrefixTable,
- MaximumAllocationSize, lconf.dir32.MaximumAllocationSize,
- VirtualMemoryThreshold,
- ProcessHeapFlags,
- ProcessAffinityMask,
- CSDVersion,
- Reserved1,
- EditList,
- SecurityCookie);
-
- if (lconf.dir32.Size <= PE_LOAD_CONFIG32_LIMIT_XP)
- goto L_LOADCFG_EXIT;
-
- with (lconf.dir32)
- printf(
- "SEHandlerTable %08X\n"~
- "SEHandlerCount %08X\n"~
- "GuardCFCheckFunctionPointer %08X\n"~
- "GuardCFDispatchFunctionPointer %08X\n"~
- "GuardCFFunctionTable %08X\n"~
- "GuardCFFunctionCount %08X\n"~
- "GuardFlags %08X\n",
- SEHandlerTable,
- SEHandlerCount,
- GuardCFCheckFunctionPointer,
- GuardCFDispatchFunctionPointer,
- GuardCFFunctionTable,
- GuardCFFunctionCount,
- GuardFlags);
-
- if (lconf.dir32.Size <= PE_LOAD_CONFIG32_LIMIT_VI)
- goto L_LOADCFG_EXIT;
-
- with (lconf.dir32)
- printf(
- "CodeIntegrity.Flags %04X\n"~
- "CodeIntegrity.Catalog %04X\n"~
- "CodeIntegrity.CatalogOffset %08X\n"~
- "CodeIntegrity.Reserved %08X\n"~
- "GuardAddressTakenIatEntryTable %08X\n"~
- "GuardAddressTakenIatEntryCount %08X\n"~
- "GuardLongJumpTargetTable %08X\n"~
- "GuardLongJumpTargetCount %08X\n",
- CodeIntegrity.Flags,
- CodeIntegrity.Catalog,
- CodeIntegrity.CatalogOffset,
- CodeIntegrity.Reserved,
- GuardAddressTakenIatEntryTable,
- GuardAddressTakenIatEntryCount,
- GuardLongJumpTargetTable,
- GuardLongJumpTargetCount);
-
- if (lconf.dir32.Size <= PE_LOAD_CONFIG32_LIMIT_8)
- goto L_LOADCFG_EXIT;
-
- with (lconf.dir32)
- printf(
- "DynamicValueRelocTable %08X\n"~
- "CHPEMetadataPointer %08X\n"~
- "GuardRFFailureRoutine %08X\n"~
- "GuardRFFailureRoutineFunctionPointer %08X\n"~
- "DynamicValueRelocTableOffset %08X\n"~
- "DynamicValueRelocTableSection %04X\n"~
- "Reserved2 %04X\n"~
- "GuardRFVerifyStackPointerFunctionPointer %08X\n"~
- "HotPatchTableOffset %08X\n"~
- "Reserved3 %08X\n"~
- "EnclaveConfigurationPointer %08X\n"~
- "VolatileMetadataPointer %08X\n",
- DynamicValueRelocTable,
- CHPEMetadataPointer,
- GuardRFFailureRoutine,
- GuardRFFailureRoutineFunctionPointer,
- DynamicValueRelocTableOffset,
- DynamicValueRelocTableSection,
- Reserved2,
- GuardRFVerifyStackPointerFunctionPointer,
- HotPatchTableOffset,
- Reserved3,
- EnclaveConfigurationPointer,
- VolatileMetadataPointer);
- } else { // 64
- with (lconf.dir64)
- printf(
- "DeCommitFreeBlockThreshold %016llX\n"~
- "DeCommitTotalBlockThreshold %016llX\n"~
- "LockPrefixTable %016llX\n"~
- "MaximumAllocationSize %016llX\t(%u)\n"~
- "VirtualMemoryThreshold %016llX\n"~
- "ProcessAffinityMask %016llX\n"~
- "ProcessHeapFlags %08X\n"~
- "CSDVersion %04X\n"~
- "Reserved1 %04X\n"~
- "EditList %016llX\n"~
- "SecurityCookie %016llX\n",
- DeCommitFreeBlockThreshold,
- DeCommitTotalBlockThreshold,
- LockPrefixTable,
- MaximumAllocationSize, MaximumAllocationSize,
- VirtualMemoryThreshold,
- ProcessAffinityMask,
- ProcessHeapFlags,
- CSDVersion,
- Reserved1,
- EditList,
- SecurityCookie);
-
- if (lconf.dir64.Size <= PE_LOAD_CONFIG64_LIMIT_XP)
- goto L_LOADCFG_EXIT;
-
- with (lconf.dir64)
- printf(
- "SEHandlerTable %016llX\n"~
- "SEHandlerCount %016llX\n"~
- "GuardCFCheckFunctionPointer %016llX\n"~
- "GuardCFDispatchFunctionPointer %016llX\n"~
- "GuardCFFunctionTable %016llX\n"~
- "GuardCFFunctionCount %016llX\n"~
- "GuardFlags %08X\n",
- SEHandlerTable,
- SEHandlerCount,
- GuardCFCheckFunctionPointer,
- GuardCFDispatchFunctionPointer,
- GuardCFFunctionTable,
- GuardCFFunctionCount,
- GuardFlags);
-
- if (lconf.dir64.Size <= PE_LOAD_CONFIG64_LIMIT_VI)
- goto L_LOADCFG_EXIT;
-
- with (lconf.dir64)
- printf(
- "CodeIntegrity.Flags %04X\n"~
- "CodeIntegrity.Catalog %04X\n"~
- "CodeIntegrity.CatalogOffset %08X\n"~
- "CodeIntegrity.Reserved %08X\n"~
- "GuardAddressTakenIatEntryTable %016llX\n"~
- "GuardAddressTakenIatEntryCount %016llX\n"~
- "GuardLongJumpTargetTable %016llX\n"~
- "GuardLongJumpTargetCount %016llX\n",
- CodeIntegrity.Flags,
- CodeIntegrity.Catalog,
- CodeIntegrity.CatalogOffset,
- CodeIntegrity.Reserved,
- GuardAddressTakenIatEntryTable,
- GuardAddressTakenIatEntryCount,
- GuardLongJumpTargetTable,
- GuardLongJumpTargetCount);
-
- if (lconf.dir64.Size <= PE_LOAD_CONFIG64_LIMIT_8)
- goto L_LOADCFG_EXIT;
-
- with (lconf.dir64)
- printf(
- "DynamicValueRelocTable %016llX\n"~
- "CHPEMetadataPointer %016llX\n"~
- "GuardRFFailureRoutine %016llX\n"~
- "GuardRFFailureRoutineFunctionPointer %016llX\n"~
- "DynamicValueRelocTableOffset %08X\n"~
- "DynamicValueRelocTableSection %04X\n"~
- "Reserved2 %04X\n"~
- "GuardRFVerifyStackPointerFunctionPointer %08X\n"~
- "HotPatchTableOffset %016llX\n"~
- "Reserved3 %08X\n"~
- "EnclaveConfigurationPointer %016llX\n"~
- "VolatileMetadataPointer %016llX\n",
- DynamicValueRelocTable,
- CHPEMetadataPointer,
- GuardRFFailureRoutine,
- GuardRFFailureRoutineFunctionPointer,
- DynamicValueRelocTableOffset,
- DynamicValueRelocTableSection,
- Reserved2,
- GuardRFVerifyStackPointerFunctionPointer,
- HotPatchTableOffset,
- Reserved3,
- EnclaveConfigurationPointer,
- VolatileMetadataPointer);
- }
- }
-}*/
-
-void dump_pe_exports(ref Dumper dump, adbg_object_t *o) {
- print_header("Exports");
-
- PE_EXPORT_DESCRIPTOR *export_ = adbg_object_pe_export(o);
- if (export_ == null)
- return;
-
- with (export_) {
- print_x32("ExportFlags", ExportFlags);
- print_x32("Timestamp", Timestamp);
- print_x16("MajorVersion", MajorVersion);
- print_x16("MinorVersion", MinorVersion);
- print_x32("Name", Name, adbg_object_pe_export_name(o, export_));
- print_x32("OrdinalBase", OrdinalBase);
- print_x32("AddressTableEntries", AddressTableEntries);
- print_x32("NumberOfNamePointers", NumberOfNamePointers);
- print_x32("ExportAddressTable", ExportAddressTable);
- print_x32("NamePointer", NamePointer);
- print_x32("OrdinalTable", OrdinalTable);
- }
-
- PE_EXPORT_ENTRY *entry = void;
- size_t ie;
- while ((entry = adbg_object_pe_export_name_entry(o, export_, ie++)) != null) {
- print_x32("Export", entry.Export, adbg_object_pe_export_name_string(o, export_, entry));
- }
-}
-
-void dump_pe_imports(ref Dumper dump, adbg_object_t *o) {
- print_header("Imports");
- PE_IMPORT_DESCRIPTOR *import_ = void;
- size_t i;
- while ((import_ = adbg_object_pe_import(o, i++)) != null) with (import_) {
- char* name = adbg_object_pe_import_name(o, import_);
- print_section(cast(uint)i, name, 128);
-
- print_x32("Characteristics", Characteristics);
- print_x32("TimeDateStamp", TimeDateStamp);
- print_x32("ForwarderChain", ForwarderChain);
- print_x32("Name", Name);
- print_x32("FirstThunk", FirstThunk);
-
- //TODO: Function to get import name+hint from lte directly
- // adbg_object_pe_import_entry_string(o, import_, i++);
-
- size_t il;
- switch (o.i.pe.opt_header.Magic) {
- case PE_FMT_32:
- PE_IMPORT_ENTRY32 *t32 = adbg_object_pe_import_entry32(o, import_, il);
- if (t32 == null) continue;
- do with (t32) {
- if (ordinal >= 0x8000_0000) { // Ordinal
- print_section(cast(uint)il);
- print_x16("Number", number);
- } else { // RVA
- ushort *hint = adbg_object_pe_import_entry32_hint(o, import_, t32);
- if (hint == null) {
- LBADINDEX32:
- print_string("warning", "String index outside buffer");
- continue;
- }
- const(char)* import_name = cast(const(char)*)hint + ushort.sizeof;
- if (adbg_object_outboundp(o, cast(void*)import_name))
- goto LBADINDEX32;
- print_x32("RVA", rva);
- print_x16l("Hint", *hint, import_name, 64);
- }
- } while ((t32 = adbg_object_pe_import_entry32(o, import_, ++il)) != null);
- continue;
- case PE_FMT_64:
- PE_IMPORT_ENTRY64 *t64 = adbg_object_pe_import_entry64(o, import_, il);
- if (t64 == null) continue;
- do with (t64) {
- if (ordinal >= 0x8000_0000_0000_0000) { // Ordinal
- print_section(cast(uint)il);
- print_x16("Number", number);
- } else { // RVA
- ushort *hint = adbg_object_pe_import_entry64_hint(o, import_, t64);
- if (hint == null) {
- LBADINDEX64:
- print_string("warning", "String index outside buffer");
- continue;
- }
- const(char)* import_name = cast(const(char)*)hint + ushort.sizeof;
- if (adbg_object_outboundp(o, cast(void*)import_name))
- goto LBADINDEX64;
- print_x32("RVA", rva);
- print_x16l("Hint", *hint, import_name, 64);
- }
- } while ((t64 = adbg_object_pe_import_entry64(o, import_, ++il)) != null);
- continue;
- default:
- }
- }
-}
-
-void dump_pe_debug(ref Dumper dump, adbg_object_t *o) {
- print_header("Debug");
-
- PE_DEBUG_DIRECTORY *debug_ = void;
- size_t i;
- while ((debug_ = adbg_object_pe_debug_directory(o, i++)) != null) with (debug_) {
- print_section(cast(uint)i);
- print_x32("Characteristics", Characteristics);
- print_x32("TimeDateStamp", TimeDateStamp);
- print_u16("MajorVersion", MajorVersion);
- print_u16("MinorVersion", MinorVersion);
- print_u32("Type", Type, adbg_object_pe_debug_type_string(Type));
- print_u32("SizeOfData", SizeOfData);
- print_x32("AddressOfRawData", AddressOfRawData);
- print_x32("PointerToRawData", PointerToRawData);
-
- uint sig = void;
- if (adbg_object_offsett!uint(o, &sig, PointerToRawData)) {
- print_string("error", "PointerToRawData out of bounds");
- return;
- }
-
- const(char) *sigstr = void;
- switch (Type) {
- case PE_IMAGE_DEBUG_TYPE_CODEVIEW:
- //TODO: Check MajorVersion/MinorVersion
- // For example, a modern D program use 0.0
- // Probably meaningless
-
- switch (sig) {
- case PE_IMAGE_DEBUG_MAGIC_CODEVIEW_CV410: // PDB 2.0+ / CodeView 4.10
- sigstr = "PDB 2.0+ / CodeView 4.10";
- goto L_DEBUG_PDB20;
- case PE_IMAGE_DEBUG_MAGIC_CODEVIEW_PDB20PLUS: // PDB 2.0+
- sigstr = "PDB 2.0+ / NB10";
- goto L_DEBUG_PDB20;
- case PE_IMAGE_DEBUG_MAGIC_CODEVIEW_CV500: // PDB 2.0+ / CodeView 5.0
- sigstr = "PDB 2.0+ / CodeView 5.0";
- L_DEBUG_PDB20:
- print_x32("Signature", sig, sigstr);
- PE_DEBUG_DATA_CODEVIEW_PDB20* pdb = void;
- if (adbg_object_offsetl(o, cast(void**)&pdb,
- PointerToRawData, PE_DEBUG_DATA_CODEVIEW_PDB20.sizeof + 256)) {
- print_string("error", "PE_DEBUG_DATA_CODEVIEW_PDB20 out of bounds");
- continue;
- }
- print_x32("Offset", pdb.Offset);
- print_x32("Timestamp", pdb.Timestamp, ctime32(pdb.Timestamp));
- print_u32("Age", pdb.Age);
- if (pdb.Offset == 0) print_stringl("Path", pdb.Path.ptr, 256);
- break;
- case PE_IMAGE_DEBUG_MAGIC_CODEVIEW_CV700: // PDB 7.0 / CodeView 7.0
- PE_DEBUG_DATA_CODEVIEW_PDB70* pdb = void;
- if (adbg_object_offsetl(o, cast(void**)&pdb,
- PointerToRawData, PE_DEBUG_DATA_CODEVIEW_PDB70.sizeof + 256)) {
- print_string("error", "PE_DEBUG_DATA_CODEVIEW_PDB70 out of bounds");
- continue;
- }
- char[UID_TEXTLEN] guid = void;
- uid_text(pdb.Guid, guid, UID_GUID);
- print_x32("Signature", sig, "PDB 7.0 / CodeView 7.0");
- print_stringl("GUID", guid.ptr, UID_TEXTLEN);
- print_u32("Age", pdb.Age); // ctime32?
- print_stringl("Path", pdb.Path.ptr, 256);
- break;
- case PE_IMAGE_DEBUG_MAGIC_EMBEDDED_PPDB: // Portable PDB
- // NOTE: major_version >= 0x100 && minor_version == 0x100
- print_x32("Signature", sig, "Embedded Portable PDB");
- break;
- case PE_IMAGE_DEBUG_MAGIC_PPDB:
- PE_DEBUG_DATA_PPDB *ppdb = void;
- if (adbg_object_offsetl(o, cast(void**)&ppdb,
- PointerToRawData, PE_DEBUG_DATA_PPDB.sizeof + 64)) {
- print_string("error", "PE_DEBUG_DATA_PPDB out of bounds");
- continue;
- }
- print_x32("Signature", sig, "Portable PDB");
- print_u16("MajorVersion", ppdb.MajorVersion);
- print_u16("MinorVersion", ppdb.MinorVersion);
- print_x32("Reserved", ppdb.Reserved);
- print_u32("Length", ppdb.Length);
- print_stringl("Version", ppdb.Version.ptr,
- ppdb.Length > 64 ? 64 : ppdb.Length);
- break;
- default:
- print_x32("Signature", sig, "Unknown");
- break;
- }
- break;
- case PE_IMAGE_DEBUG_TYPE_MISC:
- PE_DEBUG_DATA_MISC* misc = void;
- if (adbg_object_offsetl(o, cast(void**)&misc,
- PointerToRawData, PE_DEBUG_DATA_MISC.sizeof + 256)) {
- print_string("error", "PE_DEBUG_DATA_MISC out of bounds");
- continue;
- }
- if (misc.DataType != 1) { // IMAGE_DEBUG_MISC_EXENAME
- print_string("error", "PE_DEBUG_DATA_MISC.DataType is not set to 1.");
- continue;
- }
- print_x32("Signature", sig, "Misc. Debug Data");
- print_x32("DataType", misc.DataType);
- print_x32("Length", misc.Length);
- print_u8("Unicode", misc.Unicode);
- print_u8("Reserved[0]", misc.Reserved[0]);
- print_u8("Reserved[1]", misc.Reserved[1]);
- print_u8("Reserved[2]", misc.Reserved[2]);
- if (misc.Unicode == false)
- print_stringl("Data", cast(char*)misc.Data.ptr, 256);
- break;
- case PE_IMAGE_DEBUG_TYPE_FPO:
- // TODO: PE_IMAGE_DEBUG_TYPE_FPO
- break;
- case PE_IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS:
- // TODO: PE_IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS
- break;
- case PE_IMAGE_DEBUG_TYPE_POGO:
- const(char) *pgotypestr = void;
- switch (sig) {
- case PE_IMAGE_DEBUG_MAGIC_POGO_LTCG:
- pgotypestr = "POGO LTCG (Link-Time Code Generation)";
- break;
- case PE_IMAGE_DEBUG_MAGIC_POGO_PGU:
- pgotypestr = "POGO PGU (Profile Guided Update)";
- break;
- default:
- pgotypestr = "POGO (Unknown)";
- }
- print_x32("Signature", sig, pgotypestr);
-
- PE_DEBUG_POGO_ENTRY* pogoentry = void;
- if (adbg_object_offsetl(o, cast(void**)&pogoentry,
- PointerToRawData, PE_DEBUG_POGO_ENTRY.sizeof + 256)) { // Guess
- print_string("error", "PE_DEBUG_POGO_ENTRY out of bounds");
- }
-
- print_x32("RVA", pogoentry.Rva);
- print_x32("Size", pogoentry.Size);
- print_stringl("Size", pogoentry.Name.ptr, 256); // Guess
- break;
- case PE_IMAGE_DEBUG_TYPE_R2R_PERFMAP:
- break;
- default:
- }
- }
-}
-
-void dump_pe_disasm(ref Dumper dump, adbg_object_t *o) {
- print_header("Disassembly");
-
- bool all = dump.selected_disasm_all();
- PE_SECTION_ENTRY *section = void;
- size_t i;
- while ((section = adbg_object_pe_section(o, i++)) != null) with (section) {
- if (all || Characteristics & PE_SECTION_CHARACTERISTIC_MEM_EXECUTE) {
- dump_disassemble_object(dump, o, Name.ptr, 8,
- o.buffer + PointerToRawData, SizeOfRawData, 0);
- }
- }
-}
\ No newline at end of file
diff --git a/app/dumper.d b/app/dumper.d
deleted file mode 100644
index 0fcc3f1..0000000
--- a/app/dumper.d
+++ /dev/null
@@ -1,474 +0,0 @@
-/// Image/object dumper, imitates objdump
-///
-/// Authors: dd86k
-/// Copyright: © dd86k
-/// License: BSD-3-Clause-Clear
-module dumper;
-
-import adbg.error, adbg.disassembler, adbg.object;
-import adbg.include.c.stdio;
-import adbg.include.c.stdlib : EXIT_SUCCESS, EXIT_FAILURE, malloc, free;
-import adbg.include.c.stdarg;
-import adbg.machines;
-import adbg.utils.bit : BIT;
-import core.stdc.string;
-import core.stdc.ctype : isprint;
-import common, utils, dump;
-
-extern (C):
-
-/// Bitfield. Selects which information to display.
-enum DumpSelect {
- /// 'h' - Dump headers
- headers = BIT!0,
- /// 'd' - Dump directories (PE32)
- dirs = BIT!1,
- /// 'e' - Exports
- exports = BIT!2,
- /// 'i' - Imports
- imports = BIT!3,
- /// 'c' - Images, certificates, etc.
- resources = BIT!4,
- /// 't' - Structured Exception Handler
- seh = BIT!5,
- /// 't' - Symbol table(s)
- symbols = BIT!6,
- /// 'T' - Dynamic symbol table
- dynsymbols = BIT!7,
- /// 'g' - Debugging material
- debug_ = BIT!8,
- /// 'o' - Thread Local Storage
- tls = BIT!9,
- /// 'l' - Load configuration
- loadcfg = BIT!10,
- /// 's' - Sections
- sections = BIT!11,
- /// 'r' - Relocations
- relocs = BIT!12,
- /// 'R' - Dynamic relocations
- dynrelocs = BIT!13,
-
- // Bits 31-24: Disassembly
-
- /// Disassemble executable sections
- disasm = BIT!24,
- /// Disassembly statistics
- disasm_stats = BIT!25,
- /// Disassemble all sections
- disasm_all = BIT!26,
-
- ///
- all_but_disasm = 0xff_ffff,
- /// Any form of dissasembler is requested
- disasm_any = disasm | disasm_stats | disasm_all,
-}
-enum DumpOptions {
- /// File is raw, do not auto-detect
- raw = BIT!0,
-}
-
-struct Dumper {
- extern (C):
-
- int selections;
- int options;
-
- this(int selects, int opts) {
- // Default selections
- if (selects == 0)
- selects = DumpSelect.headers;
-
- selections = selects;
- options = opts;
- }
-
- pragma(inline, true):
-
- //
- // Selections
- //
-
- bool selected_headers() { return (selections & DumpSelect.headers) != 0; }
- bool selected_sections() { return (selections & DumpSelect.sections) != 0; }
- bool selected_relocations() { return (selections & DumpSelect.relocs) != 0; }
- bool selected_exports() { return (selections & DumpSelect.exports) != 0; }
- bool selected_imports() { return (selections & DumpSelect.imports) != 0; }
- bool selected_debug() { return (selections & DumpSelect.debug_) != 0; }
-
- bool selected_disasm() { return (selections & DumpSelect.disasm) != 0; }
- bool selected_disasm_stats() { return (selections & DumpSelect.disasm_stats) != 0; }
- bool selected_disasm_all() { return (selections & DumpSelect.disasm_all) != 0; }
- bool selected_disasm_any() { return (selections & DumpSelect.disasm_any) != 0; }
-
- //
- // Options
- //
-
- bool option_blob() { return (options & DumpOptions.raw) != 0; }
-}
-
-/// Dump given file to stdout.
-/// Returns: Error code if non-zero
-int app_dump() {
- Dumper dump = Dumper(globals.dump_selections, globals.dump_options);
-
- if (dump.option_blob()) {
- // NOTE: Program exits and memory is free'd
- size_t size = void;
- ubyte *buffer = readall(globals.file, &size);
- if (buffer == null)
- quitext(ErrSource.crt);
-
- if (size == 0) {
- puts("Warning: File is empty");
- return 0;
- }
-
- print_string("filename", basename(globals.file));
- print_u64("filesize", size);
- print_string("format", "Blob");
- print_string("short_name", "blob");
-
- return dump_disassemble(dump, globals.machine, buffer, size, globals.dump_base_address);
- }
-
- adbg_object_t *o = adbg_object_open_file(globals.file, 0);
- if (o == null)
- return show_error();
-
- print_string("filename", basename(globals.file));
- print_u64("filesize", o.file_size);
- print_string("format", adbg_object_name(o));
- print_string("short_name", adbg_object_short_name(o));
-
- final switch (o.format) with (AdbgObject) {
- case mz: return dump_mz(dump, o);
- case ne: return dump_ne(dump, o);
- case pe: return dump_pe(dump, o);
- case lx: return dump_lx(dump, o);
- case elf: return dump_elf(dump, o);
- case macho: return dump_macho(dump, o);
- case pdb20: return dump_pdb20(dump, o);
- case pdb70: return dump_pdb70(dump, o);
- case archive: return dump_archive(dump, o);
- case mdmp: return dump_minidump(dump, o);
- case dmp: return dump_dmp(dump, o);
- case coff: return dump_coff(dump, o);
- case mscoff: return dump_mscoff(dump, o);
- case unknown: assert(0, "Unknown object type"); // Raw/unknown
- }
-}
-
-private immutable {
- /// Padding spacing to use in characters
- // PE32 has fields like MinorOperatingSystemVersion (27 chars)
- int __field_padding = -28;
- /// Number of columns to produce in hexdumps.
- int __columns = 16;
-}
-
-void print_header(const(char)* name) {
- printf("\n# %s\n", name);
-}
-
-// Field name only
-void print_name(const(char)* name) {
- printf("%*s: ", __field_padding, name);
-}
-
-void print_section(uint i, const(char) *name = null, int len = 0) {
- putchar('\n');
- print_u32("index", i);
- if (name && len) print_stringl("name", name, len);
-}
-void print_disasm_line(adbg_opcode_t *op, const(char)* msg = null) {
- // Print address
- printf("%12llx ", op.address);
-
- // If opcode is empty, somehow, print message if available
- if (op.size == 0) {
- puts(msg ? msg : "empty");
- return;
- }
-
- // Format and print machine bytes
- enum MBFSZ = (16 * 3) + 2; // Enough for 16 bytes and spaces
- char[MBFSZ] machine = void;
- int left = MBFSZ; // Buffer left
- int tl; // Total length
- for (size_t bi; bi < op.size; ++bi) {
- int l = snprintf(machine.ptr + tl, left, " %02x", op.machine[bi]);
- if (l <= 0) break; // Ran out of buffer space
- tl += l;
- left -= l;
- }
- machine[tl] = 0;
- printf(" %*s ", -24, machine.ptr);
-
- // Print message or mnemonics
- if (msg) {
- puts(msg);
- return;
- }
- printf("%*s %s\n", -10, op.mnemonic, op.operands);
-}
-
-void print_u8(const(char)* name, ubyte val, const(char) *meaning = null) {
- print_u32(name, val, meaning);
-}
-void print_u16(const(char)* name, ushort val, const(char) *meaning = null) {
- print_u32(name, val, meaning);
-}
-void print_u32(const(char)* name, uint val, const(char) *meaning = null) {
- printf("%*s: %u", __field_padding, name, val);
- if (meaning) printf("\t(%s)", meaning);
- putchar('\n');
-}
-void print_u32l(const(char)* name, uint val, const(char) *meaning = null, int length = 0) {
- printf("%*s: %u", __field_padding, name, val);
- if (meaning && length) printf("\t(\"%.*s\")", length, meaning);
- putchar('\n');
-}
-void print_u64(const(char)* name, ulong val, const(char) *meaning = null) {
- printf("%*s: %llu", __field_padding, name, val);
- if (meaning) printf("\t(%s)", meaning);
- putchar('\n');
-}
-
-void print_x8(const(char)* name, ubyte val, const(char) *meaning = null) {
- printf("%*s: 0x%02x", __field_padding, name, val);
- if (meaning) printf("\t(%s)", meaning);
- putchar('\n');
-}
-void print_x16(const(char)* name, ushort val, const(char) *meaning = null) {
- printf("%*s: 0x%04x", __field_padding, name, val);
- if (meaning) printf("\t(%s)", meaning);
- putchar('\n');
-}
-void print_x16l(const(char)* name, ushort val, const(char) *meaning = null, int length = 0) {
- printf("%*s: 0x%04x", __field_padding, name, val);
- if (meaning) printf("\t(\"%.*s\")", length, meaning);
- putchar('\n');
-}
-void print_x32(const(char)* name, uint val, const(char) *meaning = null) {
- printf("%*s: 0x%08x", __field_padding, name, val);
- if (meaning) printf("\t(%s)", meaning);
- putchar('\n');
-}
-void print_x32l(const(char)* name, uint val, const(char) *meaning = null, int length = 0) {
- printf("%*s: 0x%08x", __field_padding, name, val);
- if (meaning) printf("\t(\"%.*s\")", length, meaning);
- putchar('\n');
-}
-void print_x64(const(char)* name, ulong val, const(char) *meaning = null) {
- printf("%*s: 0x%016llx", __field_padding, name, val);
- if (meaning) printf(`\t(%s)`, meaning);
- putchar('\n');
-}
-
-void print_f32(const(char)* name, float val, int pad = 2) {
- print_f64(name, val, pad);
-}
-void print_f64(const(char)* name, double val, int pad = 2) {
- printf("%*s: %.*f\n", __field_padding, name, pad, val);
-}
-
-void print_string(const(char)* name, const(char)* val) {
- printf("%*s: %s\n", __field_padding, name, val);
-}
-void print_stringl(const(char)* name, const(char)* val, int len) {
- printf("%*s: %.*s\n", __field_padding, name, len, val);
-}
-//TODO: print_stringf
-
-void print_flags16(const(char) *section, ushort flags, ...) {
- printf("%*s: 0x%04x\t(", __field_padding, section, flags);
-
- va_list args = void;
- va_start(args, flags);
- ushort count;
-L_START:
- const(char) *name = va_arg!(const(char)*)(args);
- if (name == null) {
- puts(")");
- return;
- }
-
- if ((flags & va_arg!int(args)) == 0) goto L_START; // condition
- if (count++) putchar(',');
- printf("%s", name);
- goto L_START;
-}
-void print_flags32(const(char) *section, uint flags, ...) {
- printf("%*s: 0x%08x\t(", __field_padding, section, flags);
-
- va_list args = void;
- va_start(args, flags);
- ushort count;
-L_START:
- const(char) *name = va_arg!(const(char)*)(args);
- if (name == null) {
- puts(")");
- return;
- }
-
- if ((flags & va_arg!int(args)) == 0) goto L_START; // condition
- if (count++) putchar(',');
- printf("%s", name);
- goto L_START;
-}
-void print_flags64(const(char) *section, ulong flags, ...) {
- printf("%*s: 0x%016llx\t(", __field_padding, section, flags);
-
- va_list args = void;
- va_start(args, flags);
- ushort count;
-L_START:
- const(char) *name = va_arg!(const(char)*)(args);
- if (name == null) {
- puts(")");
- return;
- }
-
- if ((flags & va_arg!long(args)) == 0) goto L_START; // condition
- if (count++) putchar(',');
- printf("%s", name);
- goto L_START;
-}
-
-void print_raw(const(char)* name, void *data, size_t dsize, ulong baseaddress = 0) {
- print_header(name);
-
- // Print header
- static immutable string _soff = "Offset ";
- printf(_soff.ptr);
- for (int ib; ib < __columns; ++ib)
- printf("%02x ", ib);
- putchar('\n');
-
- // Print data
- ubyte *d = cast(ubyte*)data;
- size_t afo; // Absolute file offset
- for (size_t id; id < dsize; id += __columns, baseaddress += __columns) {
- printf("%8llx ", baseaddress);
-
- // Adjust column for row
- size_t col = __columns;//id + __columns >= dsize ? dsize - __columns : __columns;
- size_t off = afo;
-
- // Print data bytes
- for (size_t ib; ib < col; ++ib, ++off)
- printf("%02x ", d[off]);
-
- // Adjust spacing between the two
- if (col < __columns) {
-
- } else
- putchar(' ');
-
- // Print printable characters
- off = afo;
- for (size_t ib; ib < col; ++ib, ++off)
- putchar(isprint(d[off]) ? d[off] : '.');
-
- // New row
- afo += col;
- putchar('\n');
- }
-}
-
-void print_directory_entry(const(char)* name, uint rva, uint size) {
- printf("%*s: 0x%08x %u\n", __field_padding, name, rva, size);
-}
-
-void print_reloc16(uint index, ushort seg, ushort off) {
- printf("%4u. 0x%04x:0x%04x\n", index, seg, off);
-}
-
-// name is typically section name or filename if raw
-int dump_disassemble_object(ref Dumper dump, adbg_object_t *o,
- const(char) *name, int namemax,
- void* data, ulong size, ulong base_address) {
-
- print_header("Disassembly");
-
- if (name && namemax)
- print_stringl("section", name, namemax);
-
- if (data + size >= o.buffer + o.file_size) {
- print_string("error", "data + size >= dump.o.buffer + dump.o.file_size");
- return EXIT_FAILURE;
- }
-
- if (data == null || size == 0) {
- print_string("error", "data is NULL or size is 0");
- return 0;
- }
-
- return dump_disassemble(dump, adbg_object_machine(o), data, size, base_address);
-}
-
-int dump_disassemble(ref Dumper dump, AdbgMachine machine,
- void* data, ulong size, ulong base_address) {
- adbg_disassembler_t *dis = adbg_dis_open(machine);
- if (dis == null)
- quitext(ErrSource.adbg);
- scope(exit) adbg_dis_close(dis);
-
- if (globals.syntax)
- adbg_dis_options(dis, AdbgDisOpt.syntax, globals.syntax, 0);
-
- adbg_opcode_t op = void;
- adbg_dis_start(dis, data, cast(size_t)size, base_address);
-
- // stats mode
- //TODO: attach shortest and longuest instructions found
- if (dump.selected_disasm_stats()) {
- uint stat_avg; /// instruction average size
- uint stat_min = uint.max; /// smallest instruction size
- uint stat_max; /// longest instruction size
- uint stat_total; /// total instruction count
- uint stat_illegal; /// Number of illegal instructions
-L_STAT:
- switch (adbg_dis_step(dis, &op)) with (AdbgError) {
- case success:
- stat_avg += op.size;
- ++stat_total;
- if (op.size > stat_max) stat_max = op.size;
- if (op.size < stat_min) stat_min = op.size;
- goto L_STAT;
- case disasmIllegalInstruction:
- stat_avg += op.size;
- ++stat_total;
- ++stat_illegal;
- goto L_STAT;
- case disasmEndOfData: break;
- default:
- quitext(ErrSource.adbg);
- }
-
- print_f32("average", cast(float)stat_avg / stat_total, 2);
- print_u32("shortest", stat_min);
- print_u32("largest", stat_max);
- print_u32("illegal", stat_illegal);
- print_u32("valid", stat_total - stat_illegal);
- print_u32("total", stat_total);
- return 0;
- }
-
- // normal disasm mode
-L_DISASM:
- switch (adbg_dis_step(dis, &op)) with (AdbgError) {
- case success:
- print_disasm_line(&op);
- goto L_DISASM;
- case disasmIllegalInstruction:
- print_disasm_line(&op, "illegal");
- goto L_DISASM;
- case disasmEndOfData:
- return 0;
- default:
- print_string("error", adbg_error_msg());
- return 1;
- }
-}
diff --git a/app/main.d b/app/main.d
deleted file mode 100644
index 669055f..0000000
--- a/app/main.d
+++ /dev/null
@@ -1,597 +0,0 @@
-/// Command line interface.
-///
-/// Authors: dd86k
-/// Copyright: © dd86k
-/// License: BSD-3-Clause-Clear
-module main;
-
-import adbg.platform;
-import adbg.include.c.stdlib : exit;
-import adbg.include.d.config : GDC_VERSION, GDC_EXCEPTION_MODE, LLVM_VERSION;
-import adbg.debugger.exception : adbg_exception_t, adbg_exception_name;
-import adbg.self;
-import adbg.machines : adbg_machine_default;
-import adbg.disassembler;
-import adbg.error;
-import adbg.debugger.process;
-import core.stdc.stdlib : strtol, EXIT_SUCCESS, EXIT_FAILURE;
-import core.stdc.string : strcmp;
-import core.stdc.stdio;
-import common, dumper, shell;
-import utils : unformat64;
-
-private:
-extern (C):
-
-enum COPYRIGHT = "Copyright (c) 2019-2024 dd86k ";
-
-__gshared immutable(char) *page_license =
-COPYRIGHT~`
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-3. Neither the name of the copyright holder nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.`;
-
-debug enum FULL_VERSION = ADBG_VERSION~"+"~__BUILDTYPE__;
-else enum FULL_VERSION = ADBG_VERSION;
-
-enum __D_VERSION__ = DSTRVER!__VERSION__;
-
-//NOTE: The CLI module is meh, waiting on some betterC getopt
-
-// if asking for help, so '?' and "help" are accepted
-bool wantsHelp(const(char) *query) {
- if (query[0] == '?') return true;
-
- return strcmp(query, "help") == 0;
-}
-
-struct option_t {
- align(4) char alt;
- immutable(char) *val;
- immutable(char) *desc;
- align(4) bool arg; /// if it takes an argument
- union {
- extern(C) int function() f;
- extern(C) int function(const(char)*) fa;
- }
-}
-//TODO: --dump-blob-offset/--dump-blob-seek/--dump-blob-start: Starting offset for raw blob
-//TODO: --dump-length/--dump-end: Length or end
-//TODO: --dump-imports-all: Dependency walker
-//TODO: --dump-section=name: Hex or raw dump section
-//TODO: --dump-stats: File statistics?
-// pdb: stream count, positions, etc.
-//TODO: --demangle
-immutable option_t[] options = [
- // general
- { 'a', "arch", "Select architecture for disassembler (default=platform)", true, fa: &cli_march },
- { 's', "syntax", "Select disassembler syntax (default=platform)", true, fa: &cli_syntax },
- // debugger
- { 0, "file", "Debugger: Spawn FILE for debugging", true, fa: &cli_file },
- { 0, "args", "Debugger: Supply arguments to executable", true, fa: &cli_args },
- { 'E', "env", "Debugger: Supply environment variables to executable", true, fa: &cli_env },
- { 'p', "attach", "Debugger: Attach to Process ID", true, fa: &cli_pid },
- // dumper
- { 'D', "dump", "Aliased to --dump-headers", false, &cli_dump_headers },
- { 0, "dump-headers", "Dump object's headers", false, &cli_dump_headers },
- { 0, "dump-section", "Dump object's section by name", true, fa: &cli_dump_section },
- { 0, "dump-sections", "Dump object's sections", false, &cli_dump_sections },
- { 0, "dump-imports", "Dump object's import information", false, &cli_dump_imports },
- { 0, "dump-exports", "Dump object's export information", false, &cli_dump_exports },
- { 0, "dump-loadcfg", "Dump object's load configuration", false, &cli_dump_loadcfg },
-// { 0, "dump-source", "Dump object's source with disassembly", false, &cli_dump_source },
- { 0, "dump-relocs", "Dump object's relocations", false, &cli_dump_reloc },
- { 0, "dump-debug", "Dump object's debug information", false, &cli_dump_debug },
- { 0, "dump-everything", "Dump everything except disassemblyn", false, &cli_dump_everything },
- { 0, "dump-disassembly", "Dump object's disassembly", false, &cli_dump_disasm },
- { 0, "dump-disassembly-all", "Dump object's disassembly for all sections", false, &cli_dump_disasm_all },
- { 0, "dump-disassembly-stats", "Dump object's disassembly statistics for executable sections", false, &cli_dump_disasm_stats },
- { 0, "dump-as-blob", "Dump as raw binary blob", false, &cli_dump_blob },
- { 0, "dump-origin", "Mark base address for disassembly", true, fa: &cli_dump_disasm_org },
- // pages
- { 'h', "help", "Show this help screen and exit", false, &cli_help },
- { 0, "version", "Show the version screen and exit", false, &cli_version },
- { 0, "build-info", "Show the build and debug information and exit", false, &cli_debug_version },
- { 0, "ver", "Show only the version string and exit", false, &cli_ver },
- { 0, "license", "Show the license page and exit", false, &cli_license },
- // secrets
- { 0, "meow", "Meow and exit", false, &cli_meow },
-];
-enum NUMBER_OF_SECRETS = 1;
-
-//
-// ANCHOR --march
-//
-
-int cli_march(const(char) *val) {
- if (wantsHelp(val)) {
- puts("Available machine architectures:");
- foreach (setting_platform_t p; platforms) {
- with (p)
- printf("%8s, %-10s %s\n", opt, alt, desc);
- }
- exit(0);
- }
- foreach (setting_platform_t p; platforms) {
- if (strcmp(val, p.opt) == 0 || strcmp(val, p.alt) == 0) {
- globals.machine = p.val;
- return EXIT_SUCCESS;
- }
- }
- return EXIT_FAILURE;
-}
-
-//
-// ANCHOR --syntax
-//
-
-int cli_syntax(const(char) *val) {
- if (wantsHelp(val)) {
- puts("Available disassembler syntaxes:");
- foreach (setting_syntax_t syntax; syntaxes) {
- with (syntax)
- printf("%-10s %s\n", opt, desc);
- }
- exit(0);
- }
- foreach (setting_syntax_t syntax; syntaxes) {
- if (strcmp(val, syntax.opt) == 0) {
- globals.syntax = syntax.val;
- return EXIT_SUCCESS;
- }
- }
- return EXIT_FAILURE;
-}
-
-//
-// ANCHOR --file
-//
-
-int cli_file(const(char) *val) {
- globals.file = val;
- return EXIT_SUCCESS;
-}
-
-//
-// ANCHOR --args/--
-//
-
-int cli_args_stop(int argi, int argc, const(char) **argv) { // --
- import adbg.utils.strings : adbg_util_move;
-
- enum MAX = 16;
- __gshared const(char) *[MAX] args;
-
- globals.args = cast(const(char)**)args;
-
- int left = argc - argi; /// to move
- void **s = cast(void**)(argv+argi);
-
- int m = adbg_util_move(
- cast(void**)&globals.args, MAX,
- cast(void**)&s, left);
-
- debug assert(m == left, "cli_argsdd: 'adbg_util_move' Failed due to small buffer");
-
- return EXIT_SUCCESS;
-}
-int cli_args(const(char) *val) { // --args
- import adbg.utils.strings : adbg_util_expand;
-
- int argc = void;
- char **argv = adbg_util_expand(val, &argc);
-
- if (argc == 0)
- return EXIT_FAILURE;
-
- globals.args = cast(const(char)**)argv;
- return EXIT_SUCCESS;
-}
-
-//
-// ANCHOR -E, --env
-//
-
-int cli_env(const(char) *val) {
- import adbg.utils.strings : adbg_util_env;
-
- globals.env = cast(const(char)**)adbg_util_env(val);
-
- if (globals.env == null) {
- printf("main: Parsing environment failed");
- return EXIT_FAILURE;
- }
-
- return EXIT_SUCCESS;
-}
-
-//
-// ANCHOR --attach
-//
-
-int cli_pid(const(char) *val) {
- globals.pid = cast(ushort)strtol(val, null, 10);
- return EXIT_SUCCESS;
-}
-
-//
-// ANCHOR -A/--analyze
-//
-
-int cli_analyze() {
- globals.mode = SettingMode.analyze;
- return EXIT_SUCCESS;
-}
-
-//
-// ANCHOR --dump-*
-//
-
-// Dump selectors
-
-int cli_dump_headers() {
- globals.mode = SettingMode.dump;
- globals.dump_selections |= DumpSelect.headers;
- return 0;
-}
-int cli_dump_section(const(char) *val) {
- globals.mode = SettingMode.dump;
- globals.dump_selections |= DumpSelect.sections;
- globals.dump_section = val;
- return 0;
-}
-int cli_dump_sections() {
- globals.mode = SettingMode.dump;
- globals.dump_selections |= DumpSelect.sections;
- return 0;
-}
-int cli_dump_imports() {
- globals.mode = SettingMode.dump;
- globals.dump_selections |= DumpSelect.imports;
- return 0;
-}
-int cli_dump_exports() {
- globals.mode = SettingMode.dump;
- globals.dump_selections |= DumpSelect.exports;
- return 0;
-}
-int cli_dump_loadcfg() {
- globals.mode = SettingMode.dump;
- globals.dump_selections |= DumpSelect.loadcfg;
- return 0;
-}
-int cli_dump_reloc() {
- globals.mode = SettingMode.dump;
- globals.dump_selections |= DumpSelect.relocs;
- return 0;
-}
-int cli_dump_debug() {
- globals.mode = SettingMode.dump;
- globals.dump_selections |= DumpSelect.debug_;
- return 0;
-}
-int cli_dump_disasm() {
- globals.mode = SettingMode.dump;
- globals.dump_selections |= DumpSelect.disasm;
- return 0;
-}
-int cli_dump_disasm_all() {
- globals.mode = SettingMode.dump;
- globals.dump_selections |= DumpSelect.disasm_all;
- return 0;
-}
-int cli_dump_disasm_stats() {
- globals.mode = SettingMode.dump;
- globals.dump_selections |= DumpSelect.disasm_stats;
- return 0;
-}
-
-int cli_dump_everything() {
- globals.mode = SettingMode.dump;
- globals.dump_selections |= DumpSelect.all_but_disasm;
- return 0;
-}
-
-// Dump options
-
-int cli_dump_blob() {
- globals.mode = SettingMode.dump;
- globals.dump_options |= DumpOptions.raw;
- return 0;
-}
-int cli_dump_disasm_org(const(char) *val) {
- return unformat64(&globals.dump_base_address, val);
-}
-
-//
-// ANCHOR --help
-//
-
-int cli_help() {
- puts(
- "alicedbg\n"~
- "Aiming to be a simple debugger.\n"~
- "\n"~
- "USAGE\n"~
- " Spawn new process to debug:\n"~
- " alicedbg FILE [OPTIONS...]\n"~
- " Attach debugger to existing process:\n"~
- " alicedbg --attach PID [OPTIONS...]\n"~
- " Dump executable image headers:\n"~
- " alicedbg --dump FILE [OPTIONS...]\n"~
- " Show information page and exit:\n"~
- " alicedbg {-h|--help|--version|--ver|--license}\n"~
- "\n"~
- "OPTIONS"
- );
- foreach (option_t opt; options[0..$-NUMBER_OF_SECRETS]) {
- if (opt.alt)
- printf(" -%c, --%-17s %s\n", opt.alt, opt.val, opt.desc);
- else
- printf(" --%-17s %s\n", opt.val, opt.desc);
- }
- puts("\nFor a list of values, for example a list of platforms, type '-m help'");
- exit(0);
- return 0;
-}
-
-//
-// ANCHOR --version
-//
-
-// Turns a __VERSION__ number into a string constant
-template DSTRVER(uint ver) {
- enum DSTRVER =
- cast(char)((ver / 1000) + '0') ~ "." ~
- cast(char)(((ver % 1000) / 100) + '0') ~
- cast(char)(((ver % 100) / 10) + '0') ~
- cast(char)((ver % 10) + '0');
-}
-
-int cli_debug_version() {
- __gshared immutable(char) *page =
- "Compiler "~__VENDOR__~" "~__D_VERSION__~"\n"~
- "Target "~TARGET_TRIPLE~"\n"~
- "Object "~TARGET_OBJFMT~"\n"~
- "FPU "~TARGET_FLTABI~"\n"~
- "CppRT "~TARGET_CPPRT~"\n"~
- "Config "~D_FEATURES;
- puts(page);
-
- static if (GDC_VERSION) {
- printf("GCC %d\n", GDC_VERSION);
- printf("GDC-EH %s\n", GDC_EXCEPTION_MODE);
- }
-
- version (CRuntime_Glibc) {
- import adbg.include.c.config : gnu_get_libc_version;
- printf("Glibc %s\n", gnu_get_libc_version());
- }
-
- static if (LLVM_VERSION)
- printf("LLVM %d\n", LLVM_VERSION);
-
- import adbg.include.capstone : libcapstone_dynload, cs_version;
- printf("Capstone ");
- if (libcapstone_dynload()) {
- puts("error");
- } else {
- int major = void, minor = void;
- cs_version(&major, &minor);
- printf("%d.%d\n", major, minor);
- }
-
- exit(0);
- return 0;
-}
-
-int cli_version() {
- __gshared immutable(char) *page_version =
- "alicedbg "~FULL_VERSION~"\n"~
- " Built "~__TIMESTAMP__~"\n"~
- " "~COPYRIGHT~"\n"~
- "License BSD-3-Clause-Clear\n"~
- " \n"~
- "Homepage https://git.dd86k.space/dd86k/alicedbg";
-
- puts(page_version);
-
- exit(0);
- return 0;
-}
-int cli_ver() {
- puts(FULL_VERSION);
- exit(0);
- return 0;
-}
-int cli_license() {
- puts(page_license);
- exit(0);
- return 0;
-}
-
-//
-// --meow
-//
-
-int cli_meow() {
- puts(
-`
-+-------------------+
-| I hate x86, meow. |
-+--- --------------+
- \| A_A
- (-.-)
- / \ _
- / \__/
- \_||__/
-`
- );
- exit(0);
- return 0;
-}
-
-//
-// Main
-//
-
-//TODO: Support --option=value syntax
-
-void crash_handler(adbg_exception_t *ex) {
- scope(exit) exit(ex.oscode);
-
- adbg_process_t *self = adbg_self_process();
-
- puts(
-r"
- _ _ _ _ _ _ _ _ _ _ _ _ _ _
- _|_|_|_| |_|_|_|_ _|_|_|_ _|_|_|_| |_| |_| |_|
-|_| |_|_ _|_| |_|_ _|_| |_|_ _ |_|_ _|_| |_|
-|_| |_|_|_|_ |_|_|_|_| |_|_|_ |_|_|_|_| |_|
-|_|_ _ _ |_| |_| |_| |_| _ _ _|_| |_| |_| _
- |_|_|_| |_| |_| |_| |_| |_|_|_| |_| |_| |_|
-"
- );
-
- printf(
- "Exception : %s\n"~
- "PID : %d\n",
- adbg_exception_name(ex), cast(int)self.pid); // casting is temp
-
- // Fault address & disasm if available
- if (ex.faultz) {
- printf("Address : %#zx\n", ex.faultz);
-
- adbg_opcode_t op = void;
- adbg_disassembler_t *dis = adbg_dis_open(adbg_machine_default());
- if (dis && adbg_dis_process_once(dis, &op, self, ex.fault_address) == 0) {
- // Print address
- printf("Instruction:");
- // Print machine bytes
- for (size_t bi; bi < op.size; ++bi)
- printf(" %02x", op.machine[bi]);
- //
- printf(" (%s", op.mnemonic);
- if (op.operands)
- printf(" %s", op.operands);
- //
- puts(")");
- } else {
- printf(" Unavailable (%s)\n", adbg_error_msg());
- }
- }
-}
-
-int main(int argc, const(char)** argv) {
- // Set crash handle, and ignore on error
- // Could do a warning, but it might be a little confusing
- adbg_self_set_crashhandler(&crash_handler);
-
- const(char) *arg = void;
- const(char) *val = void;
- CLI: for (int argi = 1; argi < argc; ++argi) {
- arg = argv[argi];
-
- if (arg[1] == '-') { // Long options
- const(char) *argLong = arg + 2;
-
- // test for "--" (extra args)
- if (argLong[0] == 0) {
- if (cli_args_stop(++argi, argc, argv))
- return EXIT_FAILURE;
- break CLI;
- }
-
- L_LONG: foreach (option_t opt; options) {
- if (strcmp(argLong, opt.val))
- continue L_LONG;
-
- // no argument
- if (opt.arg == false) {
- if (opt.f())
- return EXIT_FAILURE;
- continue CLI;
- }
-
- // with argument
- if (++argi >= argc) {
- printf("main: missing argument for --%s\n", opt.val);
- return EXIT_FAILURE;
- }
- val = argv[argi];
- if (opt.fa(val)) {
- printf("main: '%s' is an invalid value for --%s\n", val, argLong);
- return EXIT_FAILURE;
- }
- continue CLI;
- }
- } else if (arg[0] == '-') { // Short options
- // test for "-" (stdin)
- char argShort = arg[1];
- if (argShort == 0) { // "-"
- puts("main: standard input not supported");
- return EXIT_FAILURE;
- }
-
- L_SHORT: foreach (option_t opt; options) {
- if (argShort != opt.alt)
- continue L_SHORT;
-
- // no argument
- if (opt.arg == false) {
- if (opt.f())
- return EXIT_FAILURE;
- continue CLI;
- }
-
- // with argument
- if (++argi >= argc) {
- printf("main: missing argument for -%c\n", argShort);
- return EXIT_FAILURE;
- }
- val = argv[argi];
- if (opt.fa(val)) {
- printf("main: '%s' is an invalid value for -%c\n", val, argShort);
- return EXIT_FAILURE;
- }
- continue CLI;
- }
- } else if (globals.file == null) { // Default option value
- globals.file = arg;
- continue CLI;
- }
-
- printf("main: unknown option '%s'\n", arg);
- return EXIT_FAILURE;
- }
-
- switch (globals.mode) {
- case SettingMode.dump: return app_dump();
- case SettingMode.debugger:
- return shell_loop;
- default: assert(0, "Implement SettingMode");
- }
-}
diff --git a/app/shell.d b/app/shell.d
deleted file mode 100644
index fc73ccb..0000000
--- a/app/shell.d
+++ /dev/null
@@ -1,1196 +0,0 @@
-/// Command shell and interface to debugger.
-///
-/// Authors: dd86k
-/// Copyright: © dd86k
-/// License: BSD-3-Clause-Clear
-module shell;
-
-import adbg.error, adbg.debugger, adbg.disassembler, adbg.object;
-import adbg.include.c.stdio;
-import adbg.include.c.stdlib;
-import adbg.include.c.stdarg;
-import core.stdc.string;
-import common, utils;
-import term;
-
-// Enable new process name, although it is currently broken on Windows
-//version = UseNewProcessName
-
-extern (C):
-
-/// Application error
-enum ShellError {
- none = 0,
- invalidParameter = -1,
- invalidCommand = -2, // or action or sub-command
- unavailable = -3,
- loadFailed = -4,
- pauseRequired = -5,
- alreadyLoaded = -6,
- missingOption = -7,
- unformat = -8,
- invalidCount = -9,
- unattached = -10,
-
- scanMissingType = -20,
- scanMissingValue = -21,
- scanInputOutOfRange = -22,
- scanNoScan = -23,
- scanInvalidSubCommand = -24,
-
- crt = -1000,
- alicedbg = -1001,
-}
-
-const(char) *shell_error_string(int code) {
- switch (code) with (ShellError) {
- case alicedbg:
- return adbg_error_msg;
- case invalidParameter:
- return "Invalid command parameter.";
- case invalidCommand:
- return "Invalid command.";
- case unavailable:
- return "Feature unavailable.";
- case loadFailed:
- return "Failed to load file.";
- case pauseRequired:
- return "Debugger needs to be paused for this action.";
- case alreadyLoaded:
- return "File already loaded.";
- case missingOption:
- return "Missing option for command.";
- case unformat:
- return "Input is not a number.";
- case invalidCount:
- return "Count must be 1 or higher.";
- case unattached:
- return "Need to be attached to a process for this feature.";
-
- case scanMissingType:
- return "Missing type parameter.";
- case scanMissingValue:
- return "Missing value parameter.";
- case scanInputOutOfRange:
- return "Value out of range.";
- case scanNoScan:
- return "No prior scan were initiated.";
- case scanInvalidSubCommand:
- return "Invalid type or subcommand.";
-
- case none:
- return "No error occured.";
- default:
- return "Unknown error.";
- }
-}
-
-/*void registerError(void function(ref command2_help_t help)) {
-
-}
-void registerHelp(void function(ref command2_help_t help)) {
-
-}*/
-
-int shell_loop() {
- int ecode = void;
-
- if (loginit(null))
- return 1337;
-
- // Load or attach process if CLI specified it
- if (globals.file) {
- ecode = shell_proc_spawn(globals.file, globals.args);
- if (ecode) {
- printf("Error: %s\n", adbg_error_msg());
- return ecode;
- }
- } else if (globals.pid) {
- ecode = shell_proc_attach(globals.pid);
- if (ecode) {
- printf("Error: %s\n", adbg_error_msg());
- return ecode;
- }
- }
-
- coninit();
-
-LINPUT:
- printf("(adbg) ");
-
- // .ptr is temporary because a slice with a length of 0
- // also make its pointer null.
- char* line = conrdln().ptr;
-
- if (line == null || line[0] == 4) { // 4 == ^D
- return 0;
- }
-
- ecode = shell_exec(line);
- if (ecode)
- logerror(shell_error_string(ecode));
- goto LINPUT;
-}
-
-int shell_exec(const(char) *command) {
- import adbg.utils.strings : adbg_util_expand;
- if (command == null) return 0;
- int argc = void;
- char** argv = adbg_util_expand(command, &argc);
- return shell_execv(argc, cast(const(char)**)argv);
-}
-
-int shell_execv(int argc, const(char) **argv) {
- if (argc <= 0 || argv == null)
- return 0;
-
- const(char) *ucommand = argv[0];
- immutable(command2_t) *command = shell_findcommand(ucommand);
- if (command == null) {
- return ShellError.invalidCommand;
- }
- return command.entry(argc, argv);
-}
-
-private:
-__gshared:
-
-adbg_process_t *process;
-adbg_disassembler_t *dis;
-adbg_registers_t *registers;
-
-// NOTE: BetterC stderr bindings on Windows are broken
-// And don't allow re-opening the streams, so screw it
-
-FILE *logfd;
-int loginit(const(char) *path) {
- version (Windows) {
- // 1. HANDLE stdHandle = GetStdHandle(STD_ERROR_HANDLE);
- // 2. int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT);
- // 3. FILE* file = _fdopen(fileDescriptor, "w");
- // 4. int dup2Result = _dup2(_fileno(file), _fileno(stderr));
- // 5. setvbuf(stderr, NULL, _IONBF, 0);
- if (path == null) path = "CONOUT$";
- } else {
- if (path == null) path = "/dev/stderr";
- }
-
- logfd = fopen(path, "wb");
- if (logfd) {
- setvbuf(logfd, null, _IONBF, 0);
- }
- return logfd == null;
-}
-void logerror(const(char) *fmt, ...) {
- va_list args = void;
- va_start(args, fmt);
- logwrite("error", fmt, args);
-}
-void logwarn(const(char) *fmt, ...) {
- va_list args = void;
- va_start(args, fmt);
- logwrite("warning", fmt, args);
-}
-void loginfo(const(char) *fmt, ...) {
- va_list args = void;
- va_start(args, fmt);
- logwrite(null, fmt, args);
-}
-void logwrite(const(char) *level, const(char) *fmt, va_list args) {
- if (level) {
- fputs(level, logfd);
- fputs(": ", logfd);
- }
- vfprintf(logfd, fmt, args);
- putchar('\n');
-}
-
-immutable string RCFILE = ".adbgrc";
-
-immutable string MODULE_SHELL = "Shell";
-immutable string MODULE_DEBUGGER = "Debugger";
-immutable string MODULE_DISASSEMBLER = "Disassembler";
-immutable string MODULE_OBJECTSERVER = "Object Server";
-
-immutable string CATEGORY_SHELL = "Command-line";
-immutable string CATEGORY_PROCESS = "Process management";
-immutable string CATEGORY_CONTEXT = "Thread context management";
-immutable string CATEGORY_MEMORY = "Memory management";
-immutable string CATEGORY_EXCEPTION = "Exception management";
-
-immutable string SECTION_NAME = "NAME";
-immutable string SECTION_SYNOPSIS = "SYNOPSIS";
-immutable string SECTION_DESCRIPTION = "DESCRIPTION";
-immutable string SECTION_NOTES = "NOTES";
-immutable string SECTION_EXAMPLES = "EXAMPLES";
-
-struct command2_help_section_t {
- string name;
- string[] bodies;
-}
-struct command2_help_t {
- // Debugger, Disassembler, Object Server
- string module_;
- // Process management, Memory, etc.
- string category;
- // Short description.
- string description;
- //
- command2_help_section_t[] sections;
-}
-struct command2_t {
- string[] names;
- string description;
- string[] synopsis;
- string doc_module;
- string doc_category;
- command2_help_section_t[] doc_sections;
- int function(int, const(char)**) entry;
-}
-// NOTE: Called "commands_list" to avoid conflict with future "command_list" function
-//TODO: Commands
-// - !: Run host shell commands
-// - b|breakpoint: Breakpoint management
-// - t|thread: Thread management (e.g., selection, callstack)
-// - sym: Symbol management
-immutable command2_t[] shell_commands = [
- //
- // Debugger
- //
- {
- [ "status" ],
- "Get process status.",
- [],
- MODULE_DEBUGGER, CATEGORY_PROCESS,
- [
- {
- SECTION_DESCRIPTION,
- [ "Print the status of the debuggee process." ]
- }
- ],
- &command_status,
- },
- {
- [ "spawn" ],
- "Spawn a new process into debugger.",
- [
- "FILE [ARGS...]"
- ],
- MODULE_DEBUGGER, CATEGORY_PROCESS,
- [
- {
- SECTION_DESCRIPTION,
- [ "Spawns a new process from path with the debugger attached." ]
- }
- ],
- &command_spawn,
- },
- {
- [ "attach" ],
- "Attach debugger to live process.",
- [
- "PID"
- ],
- MODULE_DEBUGGER, CATEGORY_PROCESS,
- [
- {
- SECTION_DESCRIPTION,
- [ "Attaches debugger to an existing process by its Process ID." ]
- }
- ],
- &command_attach,
- },
- {
- [ "detach" ],
- "Detach debugger from process.",
- [],
- MODULE_DEBUGGER, CATEGORY_PROCESS,
- [
- {
- SECTION_DESCRIPTION,
- [ "If the debugger was attached to a live process, detach "~
- "the debugger." ]
- }
- ],
- &command_detach,
- },
- {
- [ "restart" ],
- "Restart the debugging process.",
- [],
- MODULE_DEBUGGER, CATEGORY_PROCESS,
- [
- {
- SECTION_DESCRIPTION,
- [ "The debugger will be re-attached or the process will be "~
- "killed and respawned." ]
- }
- ],
- &command_restart,
- },
- {
- [ "go" ],
- "Continue debugging process.",
- [],
- MODULE_DEBUGGER, CATEGORY_PROCESS,
- [
- {
- SECTION_DESCRIPTION,
- [ "The debugger will be re-attached or the process will be "~
- "killed and respawned." ]
- }
- ],
- &command_go,
- },
- {
- [ "kill" ],
- "Terminate process.",
- [],
- MODULE_DEBUGGER, CATEGORY_PROCESS,
- [
- {
- SECTION_DESCRIPTION,
- [ "The debugger will be re-attached or the process will be "~
- "killed and respawned." ]
- }
- ],
- &command_kill,
- },
- {
- [ "stepi" ],
- "Perform an instruction step.",
- [],
- MODULE_DEBUGGER, CATEGORY_PROCESS,
- [
- {
- SECTION_DESCRIPTION,
- [ "From a paused state, executes exactly one instruction." ]
- }
- ],
- &command_stepi,
- },
- //
- // Context
- //
- {
- [ "regs" ],
- "Lists register values.",
- [
- "[NAME]"
- ],
- MODULE_DEBUGGER, CATEGORY_CONTEXT,
- [
- {
- SECTION_DESCRIPTION,
- [ "Get list of registers and values from process." ]
- }
- ],
- &command_regs,
- },
- //
- // Memory
- //
- {
- [ "m", "memory" ],
- "Dump process memory from address.",
- [
- "ADDRESS [LENGTH=64]"
- ],
- MODULE_DEBUGGER, CATEGORY_MEMORY,
- [
- {
- SECTION_DESCRIPTION,
- [ "Print memory data from address as hexadecimal." ]
- }
- ],
- &command_memory,
- },
- {
- [ "maps" ],
- "List memory mapped items.",
- [],
- MODULE_DEBUGGER, CATEGORY_MEMORY,
- [
- {
- SECTION_DESCRIPTION,
- [ "Lists loaded modules and their memory regions." ]
- }
- ],
- &command_maps,
- },
- {
- [ "d", "disassemble" ],
- "Disassemble instructions at address.",
- [
- "ADDRESS [COUNT=1]"
- ],
- MODULE_DEBUGGER, CATEGORY_MEMORY,
- [
- {
- SECTION_DESCRIPTION,
- [ "Invoke the disassembler at the address. The debugger "~
- "will read process memory, if able, and will repeat "~
- "the operation COUNT times. By default, it will only "~
- "disassemble one instruction." ]
- }
- ],
- &command_disassemble,
- },
- {
- [ "scan" ],
- "Scan for value in memory.",
- [
- "TYPE VALUE",
- "show",
- "reset",
- ],
- MODULE_DEBUGGER, CATEGORY_MEMORY,
- [
- {
- SECTION_DESCRIPTION,
- [ "Scan memory maps for specified value. "~
- "No writing capability is available at the moment. "~
- "To list last scan results, use 'show' subcommand.",
- "To clear results, use 'reset' subcommand." ]
- }
- ],
- &command_scan,
- },
- //
- // Process management
- //
- {
- [ "plist" ],
- "List running programs.",
- [],
- MODULE_DEBUGGER, CATEGORY_PROCESS,
- [
- { SECTION_DESCRIPTION,
- [ "List active processes." ]
- }
- ],
- &command_plist,
- },
- //
- // Shell
- //
- {
- [ "help" ],
- "Show help or a command's help article.",
- [
- "[ITEM]"
- ],
- MODULE_SHELL, CATEGORY_SHELL,
- [
-
- ],
- &command_help,
- },
- {
- [ "q", "quit" ],
- "Quit shell session.",
- [],
- MODULE_SHELL, CATEGORY_SHELL,
- [
- {
- SECTION_DESCRIPTION,
- [ "Close the shell session along with the debugger and "~
- "application if it was spawned using the debugger." ]
- }
- ],
- &command_quit,
- },
-];
-
-immutable(command2_t)* shell_findcommand(const(char) *ucommand) {
-debug { // Crash command
- static immutable(command2_t) ucommand_crash = {
- [ "crash" ],
- null,
- [],
- null, null,
- [],
- &command_crash
- };
-
- if (strcmp(ucommand, ucommand_crash.names[0].ptr) == 0)
- return &ucommand_crash;
-}
- // NOTE: Can't use foreach for local var escape
- for (size_t i; i < shell_commands.length; ++i) {
- immutable(command2_t) *cmd = &shell_commands[i];
-
- for (size_t c; c < cmd.names.length; ++c) {
- if (strcmp(ucommand, cmd.names[c].ptr) == 0)
- return cmd;
- }
- }
-
- return null;
-}
-
-int shell_proc_spawn(const(char) *exec, const(char) **argv) {
- // Save for restart
- globals.file = exec;
- globals.args = argv;
-
- // Spawn process
- process = adbg_debugger_spawn(globals.file,
- AdbgSpawnOpt.argv, argv,
- 0);
- if (process == null) {
- return ShellError.alicedbg;
- }
-
- puts("Process created.");
-
- // Open disassembler for process machine type
- dis = adbg_dis_open(adbg_process_get_machine(process));
- if (dis == null) {
- logwarn("Disassembler not available (%s).", adbg_error_msg());
- }
-
- return 0;
-}
-
-int shell_proc_attach(int pid) {
- // Save for restart
- globals.pid = pid;
-
- // Attach to process
- process = adbg_debugger_attach(pid, 0);
- if (process == null) {
- return ShellError.alicedbg;
- }
-
- puts("Debugger attached.");
-
- // Open disassembler for process machine type
- dis = adbg_dis_open(adbg_process_get_machine(process));
- if (dis) {
- if (globals.syntax)
- adbg_dis_options(dis, AdbgDisOpt.syntax, globals.syntax, 0);
- } else {
- printf("warning: Disassembler not available (%s)\n",
- adbg_error_msg());
- }
-
- return 0;
-}
-
-void shell_event_disassemble(size_t address, int count = 1, bool showAddress = true) {
- if (dis == null)
- return;
-
- enum MBUFSZ = 64; /// Machine string buffer size
-
- ubyte[MAX_INSTR_SIZE] data = void;
- char[MBUFSZ] machbuf = void;
- for (int i; i < count; ++i) {
- if (adbg_memory_read(process, address, data.ptr, MAX_INSTR_SIZE)) {
- oops;
- return;
- }
- adbg_opcode_t op = void;
- if (adbg_dis_once(dis, &op, data.ptr, MAX_INSTR_SIZE)) {
- printf("%8llx (error:%s)\n", cast(ulong)address, adbg_error_msg);
- return;
- }
-
- // Print address
- if (showAddress)
- printf("%8zx ", address);
-
- // Print machine bytes into a dedicated buffer
- size_t bo;
- for (size_t bi; bi < op.size; ++bi) {
- bo += snprintf(machbuf.ptr + bo, MBUFSZ - bo, " %02x", op.machine[bi]);
- //printf(" %02x", op.machine[bi]);
- }
-
- // Print mnemonic & operands
- printf("%s \t%s", machbuf.ptr, op.mnemonic);
- if (op.operands)
- printf(" %s", op.operands);
-
- // Terminate line
- putchar('\n');
-
- address += op.size;
- }
-}
-
-void shell_event_exception(adbg_exception_t *ex) {
- printf("* Process %d (thread %d) stopped\n"~
- " Reason : %s ("~ADBG_OS_ERROR_FORMAT~")\n",
- ex.pid, ex.tid,
- adbg_exception_name(ex), ex.oscode);
-
- if (ex.faultz) {
- printf(" Address : 0x%llx\n", ex.fault_address);
-
- if (dis) {
- printf(" Machine :");
-
- // Print machine bytes
- ubyte[MAX_INSTR_SIZE] data = void;
- if (adbg_memory_read(process, ex.faultz, data.ptr, MAX_INSTR_SIZE)) {
- printf(" read error (%s)\n", adbg_error_msg());
- return; // Nothing else to do
- }
-
- adbg_opcode_t op = void;
- if (adbg_dis_once(dis, &op, data.ptr, MAX_INSTR_SIZE)) {
- printf(" disassembly error (%s)\n", adbg_error_msg());
- return;
- }
-
- // Print machine bytes
- for (size_t bi; bi < op.size; ++bi) {
- printf(" %02x", op.machine[bi]);
- }
- putchar('\n');
-
- // Print mnemonic
- printf(" Mnemonic: %s", op.mnemonic);
- if (op.operands)
- printf(" %s", op.operands);
- putchar('\n');
- }
- }
-}
-
-void shell_event_help(immutable(command2_t) *command) {
- // Print header
- int p = 34;
- for (size_t i; i < command.names.length; ++i) {
- if (i) {
- printf(", ");
- --p;
- }
- p -= printf("%s", command.names[i].ptr);
- }
- with (command) printf("%*s %*s\n\nNAME\n ", p, doc_module.ptr, 34, doc_category.ptr);
- for (size_t i; i < command.names.length; ++i) {
- if (i) putchar(',');
- printf(" %s", command.names[i].ptr);
- }
- printf(" - %s\n", command.description.ptr);
-
- if (command.synopsis.length) {
- printf("\n%s\n", SECTION_SYNOPSIS.ptr);
- foreach (s; command.synopsis) {
- printf(" %s %s\n", command.names[$-1].ptr, s.ptr);
- }
- }
-
- enum COL = 72;
- foreach (section; command.doc_sections) {
- printf("\n%s\n", section.name.ptr);
-
- //TODO: Better cut-offs
- // [0] spacing? remove
- // [$-1] non-spacing? put dash
- for (size_t i; i < section.bodies.length; ++i) {
- const(char) *b = section.bodies[i].ptr;
- if (i) putchar('\n');
- LPRINT:
- int o = printf(" %.*s\n", COL, b);
- if (o < COL)
- continue;
- b += COL;
- goto LPRINT;
- }
- }
-
- putchar('\n');
-}
-
-debug
-int command_crash(int, const(char) **) {
- void function() fnull;
- fnull();
- return 0;
-}
-
-int command_status(int argc, const(char) **argv) {
- AdbgProcStatus state = adbg_process_status(process);
- const(char) *m = void;
- switch (state) with (AdbgProcStatus) {
- case unloaded: m = "unloaded"; break;
- case standby: m = "standby"; break;
- case running: m = "running"; break;
- case paused: m = "paused"; break;
- default: m = "(unknown)";
- }
- puts(m);
- return 0;
-}
-
-//TODO: List per category
-// Comparing could be per pointer or enum
-int command_help(int argc, const(char) **argv) {
- if (argc > 1) { // Requesting help article for command
- const(char) *ucommand = argv[1];
- immutable(command2_t) *command = shell_findcommand(ucommand);
- if (command == null) {
- return ShellError.invalidParameter;
- }
-
- shell_event_help(command);
- return 0;
- }
-
- enum PADDING = 20;
- static immutable const(char) *liner = "..........................................";
- foreach (cmd; shell_commands) {
- int p;
- for (size_t i; i < cmd.names.length; ++i) {
- if (i) {
- putchar(',');
- ++p;
- }
- p += printf(" %s", cmd.names[i].ptr);
- }
-
- printf(" %.*s %s\n", PADDING - p, liner, cmd.description.ptr);
- }
-
- return 0;
-}
-
-int command_spawn(int argc, const(char) **argv) {
- if (argc < 2) {
- return ShellError.invalidParameter;
- }
-
- return shell_proc_spawn(argv[1], argc > 2 ? argv + 2: null);
-}
-
-int command_attach(int argc, const(char) **argv) {
- if (argc < 2) {
- return ShellError.invalidParameter;
- }
-
- return shell_proc_attach(atoi(argv[1]));
-}
-
-int command_detach(int argc, const(char) **argv) {
- if (adbg_debugger_detach(process)) {
- return ShellError.alicedbg;
- }
- adbg_dis_close(dis);
- free(registers);
-
- return 0;
-}
-
-int command_restart(int argc, const(char) **argv) {
- int e;
-
- switch (process.creation) with (AdbgCreation) {
- case spawned:
- // Terminate first, ignore on error (e.g., already gone)
- adbg_debugger_terminate(process);
-
- // Spawn, shell still messages status
- e = shell_proc_spawn(globals.file, globals.args);
- break;
- case attached:
- // Detach first, ignore on error (e.g., already detached)
- adbg_debugger_detach(process);
-
- // Attach, shell still messages status
- e = shell_proc_attach(globals.pid);
- break;
- default:
- return ShellError.unattached;
- }
-
- return e;
-}
-
-int command_go(int argc, const(char) **argv) {
- if (adbg_debugger_continue(process))
- return ShellError.alicedbg;
- if (adbg_debugger_wait(process, &shell_event_exception))
- return ShellError.alicedbg;
- // Temporary: Cheap hack for process exit
- if (adbg_process_status(process) == AdbgProcStatus.unloaded)
- printf("*\tProcess %d exited\n", process.pid);
- return 0;
-}
-
-int command_kill(int argc, const(char) **argv) {
- if (adbg_debugger_terminate(process))
- return ShellError.alicedbg;
- puts("Process killed");
- adbg_dis_close(dis);
- free(registers);
- return 0;
-}
-
-int command_stepi(int argc, const(char) **argv) {
- if (adbg_debugger_stepi(process))
- return ShellError.alicedbg;
- if (adbg_debugger_wait(process, &shell_event_exception))
- return ShellError.alicedbg;
- return 0;
-}
-
-int command_regs(int argc, const(char) **argv) {
- if (process == null)
- return ShellError.pauseRequired;
-
- if (registers == null) {
- registers = adbg_registers_new(adbg_process_get_machine(process));
- if (registers == null)
- return ShellError.alicedbg;
- }
-
- adbg_registers_fill(registers, process);
-
- if (registers.count == 0) {
- logerror("No registers available");
- return ShellError.unavailable;
- }
-
- adbg_register_t *reg = registers.items.ptr;
- const(char) *rselect = argc >= 2 ? argv[1] : null;
- bool found;
- for (size_t i; i < registers.count; ++i, ++reg) {
- bool show = rselect == null || strcmp(rselect, reg.info.name) == 0;
- if (show == false) continue;
- char[20] normal = void, hexdec = void;
- adbg_register_format(normal.ptr, 20, reg, AdbgRegFormat.dec);
- adbg_register_format(hexdec.ptr, 20, reg, AdbgRegFormat.hexPadded);
- printf("%-8s 0x%8s %s\n", reg.info.name, hexdec.ptr, normal.ptr);
- found = true;
- }
- if (rselect && found == false) {
- logerror("Register not found");
- return ShellError.invalidParameter;
- }
- return 0;
-}
-
-int command_memory(int argc, const(char) **argv) {
- if (argc < 2) {
- return ShellError.missingOption;
- }
-
- long uaddress = void;
- if (unformat64(&uaddress, argv[1]))
- return ShellError.unformat;
-
- int ulength = 64;
- if (argc >= 3) {
- if (unformat(&ulength, argv[2]))
- return ShellError.unformat;
- if (ulength <= 0)
- return 0;
- }
-
- ubyte *data = cast(ubyte*)malloc(ulength);
- if (data == null)
- return ShellError.crt;
-
- if (adbg_memory_read(process, cast(size_t)uaddress, data, ulength))
- return ShellError.alicedbg;
-
- enum COLS = 16; /// Columns in bytes
- enum PADD = 12; /// Address padding
-
- // Print column header
- for (int c; c < PADD; ++c)
- putchar(' ');
- putchar(' ');
- putchar(' ');
- for (int c; c < COLS; ++c)
- printf("%2x ", cast(uint)c);
- putchar('\n');
-
- // Print data rows
- size_t count = ulength / COLS;
- for (size_t c; c < count; ++c, uaddress += COLS) {
- // Print address
- printf("%.*llx ", PADD, uaddress);
-
- // Print data column
- for (size_t i; i < COLS && c * i < ulength; ++i)
- printf("%02x ", data[(c * COLS) + i]);
-
- // Print ascii column
- putchar(' ');
- for (size_t i; i < COLS && c * i < ulength; ++i)
- putchar(asciichar(data[(c * COLS) + i], '.'));
-
- putchar('\n');
- }
-
- return 0;
-}
-
-//TODO: optional arg: filter module by name (contains string)
-//TODO: max count to show or option to filter modules out
-int command_maps(int argc, const(char) **argv) {
- adbg_memory_map_t *mmaps = void;
- size_t mcount = void;
-
- if (adbg_memory_maps(process, &mmaps, &mcount, 0))
- return ShellError.alicedbg;
-
- puts("Region Size T Perm File");
- for (size_t i; i < mcount; ++i) {
- adbg_memory_map_t *map = &mmaps[i];
-
- char[4] perms = void;
- perms[0] = map.access & AdbgMemPerm.read ? 'r' : '-';
- perms[1] = map.access & AdbgMemPerm.write ? 'w' : '-';
- perms[2] = map.access & AdbgMemPerm.exec ? 'x' : '-';
- perms[3] = map.access & AdbgMemPerm.private_ ? 'p' : 's';
-
- char t = void;
- switch (map.type) {
- case AdbgPageUse.resident: t = 'R'; break;
- case AdbgPageUse.fileview: t = 'F'; break;
- case AdbgPageUse.module_: t = 'M'; break;
- default: t = '?';
- }
-
- with (map) printf("%16zx %10zd %c %.4s %s\n",
- cast(size_t)base, size, t, perms.ptr, name.ptr);
- }
-
- free(mmaps);
- return 0;
-}
-
-//TODO: start,+length start,end syntax
-int command_disassemble(int argc, const(char) **argv) {
- if (process == null)
- return ShellError.unattached;
- if (dis == null)
- return ShellError.unavailable;
- if (argc < 2)
- return ShellError.missingOption;
-
- long uaddress = void;
- if (unformat64(&uaddress, argv[1]))
- return ShellError.unformat;
-
- int ucount = 1;
- if (argc >= 3) {
- if (unformat(&ucount, argv[2]))
- return ShellError.unformat;
- if (ucount <= 0)
- return 0;
- }
- if (ucount < 1) {
- return ShellError.invalidCount;
- }
-
- shell_event_disassemble(cast(size_t)uaddress, ucount);
- return 0;
-}
-
-size_t last_scan_size;
-ulong last_scan_data;
-adbg_scan_t *last_scan;
-
-void shell_event_list_scan_results() {
- // super lazy hack
- long mask = void;
- switch (last_scan_size) {
- case 8: mask = 0; break;
- case 7: mask = 0xff_ffff_ffff_ffff; break;
- case 6: mask = 0xffff_ffff_ffff; break;
- case 5: mask = 0xff_ffff_ffff; break;
- case 4: mask = 0xffff_ffff; break;
- case 3: mask = 0xff_ffff; break;
- case 2: mask = 0xffff; break;
- case 1: mask = 0xff; break;
- default:
- puts("fatal: mask fail");
- return;
- }
- // 0000. ffffffffffffffff 18446744073709551615
- puts("No. Address Previous Current");
- adbg_scan_result_t *result = last_scan.results;
- uint count = cast(uint)last_scan.result_count + 1; // temp cast until better z printf
- for (uint i = 1; i < count; ++i, ++result) {
- printf("%4u. %-16llx %*llu ", i, result.address, -20, result.value_u64 & mask);
- ulong udata = void;
- if (adbg_memory_read(process, cast(size_t)result.address, &udata, cast(uint)last_scan_size))
- puts("???");
- else
- printf("%llu\n", udata & mask);
- }
-}
-
-int command_scan(int argc, const(char) **argv) {
- if (argc < 2)
- return ShellError.scanMissingType;
-
- const(char) *usub = argv[1];
-
- if (strcmp(usub, "show") == 0) {
- if (last_scan == null)
- return ShellError.scanNoScan;
-
- shell_event_list_scan_results;
- return 0;
- } else if (strcmp(usub, "reset") == 0) {
- if (last_scan == null)
- return 0;
-
- adbg_memory_scan_close(last_scan);
- last_scan = null;
- return 0;
- }
-
- if (argc < 3)
- return ShellError.scanMissingValue;
-
- const(char) *uin = argv[2];
-
- union u {
- long data64;
- int data;
- }
- u user = void;
- if (strcmp(usub, "byte") == 0) {
- last_scan_size = ubyte.sizeof;
- if (unformat(&user.data, uin))
- return ShellError.unformat;
- if (user.data > ubyte.max)
- return ShellError.scanInputOutOfRange;
- } else if (strcmp(usub, "short") == 0) {
- last_scan_size = short.sizeof;
- if (unformat(&user.data, uin))
- return ShellError.unformat;
- if (user.data > short.max)
- return ShellError.scanInputOutOfRange;
- } else if (strcmp(usub, "int") == 0) {
- last_scan_size = int.sizeof;
- if (unformat(&user.data, uin))
- return ShellError.unformat;
- } else if (strcmp(usub, "long") == 0) {
- last_scan_size = long.sizeof;
- if (unformat64(&user.data64, uin))
- return ShellError.unformat;
- } else
- return ShellError.scanInvalidSubCommand;
-
- if (last_scan)
- adbg_memory_scan_close(last_scan);
-
- last_scan_data = user.data64;
-
- if ((last_scan = adbg_memory_scan(process, &user, last_scan_size,
- AdbgScanOpt.capacity, 100,
- 0)) == null)
- return ShellError.alicedbg;
-
- printf("Scan completed with %u results.\n", cast(uint)last_scan.result_count);
- return 0;
-}
-
-int command_rescan(int argc, const(char) **argv) {
- if (argc < 2)
- return ShellError.scanMissingType;
- if (argc < 3)
- return ShellError.scanMissingValue;
-
- const(char) *usub = argv[1];
- const(char) *uin = argv[2];
-
- union u {
- long data64;
- int data;
- }
- u user = void;
- if (strcmp(usub, "byte") == 0) {
- last_scan_size = ubyte.sizeof;
- if (unformat(&user.data, uin))
- return ShellError.unformat;
- if (user.data > ubyte.max)
- return ShellError.scanInputOutOfRange;
- } else if (strcmp(usub, "short") == 0) {
- last_scan_size = short.sizeof;
- if (unformat(&user.data, uin))
- return ShellError.unformat;
- if (user.data > short.max)
- return ShellError.scanInputOutOfRange;
- } else if (strcmp(usub, "int") == 0) {
- last_scan_size = int.sizeof;
- if (unformat(&user.data, uin))
- return ShellError.unformat;
- } else if (strcmp(usub, "long") == 0) {
- last_scan_size = long.sizeof;
- if (unformat64(&user.data64, uin))
- return ShellError.unformat;
- } else
- return ShellError.scanInvalidSubCommand;
-
- if (adbg_memory_rescan(last_scan, &user, last_scan_size))
- return ShellError.alicedbg;
-
- last_scan_data = user.data64;
-
- printf("Scan completed with %u results.\n", cast(uint)last_scan.result_count);
- return 0;
-}
-
-int command_plist(int argc, const(char) **argv) {
- // Disabled until adbg_process_get_name works on Windows
-version (UseNewProcessName) {
- size_t count = void;
- int *plist = adbg_process_list(&count, 0);
- if (plist == null)
- return ShellError.alicedbg;
-
- enum BUFFERSIZE = 2048;
- char[BUFFERSIZE] buffer = void;
-
- version (Trace)
- trace("count=%zd", count);
-
- puts("PID Name");
- foreach (int pid; plist[0..count]) {
- printf("%10d ", pid);
- if (adbg_process_get_name(pid, buffer.ptr, BUFFERSIZE, true)) {
- puts(buffer.ptr);
- continue;
- }
- if (adbg_process_get_name(pid, buffer.ptr, BUFFERSIZE, false)) {
- puts(buffer.ptr);
- continue;
- }
- version (Trace)
- trace("error: %s", adbg_error_msg());
- putchar('\n');
- }
-
- free(plist);
-} else {
- adbg_process_list_t list = void;
- if (adbg_process_enumerate(&list, 0)) {
- return ShellError.alicedbg;
- }
-
- puts("PID Name");
- foreach (adbg_process_t proc; list.processes[0..list.count]) {
- printf("%10d %s\n", proc.pid, proc.name.ptr);
- }
-}
-
- return 0;
-}
-
-int command_quit(int argc, const(char) **argv) {
- //TODO: Quit confirmation if debuggee is alive
- // could do with optional "forced yes" type of optional
- exit(0);
- return 0;
-}
\ No newline at end of file
diff --git a/app/term.d b/app/term.d
deleted file mode 100644
index e3cbf24..0000000
--- a/app/term.d
+++ /dev/null
@@ -1,547 +0,0 @@
-/// In-house console/terminal library
-///
-/// Authors: dd86k
-/// Copyright: © dd86k
-/// License: BSD-3-Clause-Clear
-module term;
-
-import core.stdc.stdlib;
-import core.stdc.stdio;
-
-//TODO: Consider using PDCurses instead
-
-// NOTE: Functions prefixed with "con" to avoid clashing with the "tc" POSIX stuff
-
-extern (C):
-
-private int putchar(int);
-private int getchar();
-
-version (Windows) {
- private import core.sys.windows.windows;
- private enum ALT_PRESSED = RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED;
- private enum CTRL_PRESSED = RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED;
- private __gshared HANDLE handleIn, handleOut, handleOld;
-} else version (Posix) {
- private import core.sys.posix.sys.ioctl;
- private import core.sys.posix.unistd;
- private import core.sys.posix.termios;
- private import core.sys.posix.signal;
- private import core.sys.posix.ucontext;
-
- version (CRuntime_Musl) {
- alias uint tcflag_t;
- alias uint speed_t;
- alias char cc_t;
- private enum TCSANOW = 0;
- private enum NCCS = 32;
- private enum ICANON = 2;
- private enum ECHO = 10;
- private enum TIOCGWINSZ = 0x5413;
- private struct termios {
- tcflag_t c_iflag;
- tcflag_t c_oflag;
- tcflag_t c_cflag;
- tcflag_t c_lflag;
- cc_t c_line;
- cc_t[NCCS] c_cc;
- speed_t __c_ispeed;
- speed_t __c_ospeed;
- }
- private struct winsize {
- ushort ws_row;
- ushort ws_col;
- ushort ws_xpixel;
- ushort ws_ypixel;
- }
- private int tcgetattr(int fd, termios *termios_p);
- private int tcsetattr(int fd, int a, termios *termios_p);
- private int ioctl(int fd, ulong request, ...);
- }
- version (CRuntime_Bionic) {
- private int tcgetattr(int __fd, termios* __t);
- private int tcsetattr(int __fd, int __optional_actions, termios* __t);
- }
-
- private enum TERM_ATTR = ~(ICANON | ECHO);
- private enum SIGWINCH = 28;
- private __gshared termios old_tio = void, new_tio = void;
-}
-
-// Flags: CONFxyz
-
-private __gshared {
- /// User defined function for resize events
- void function(ushort,ushort) term_resize_handler;
- int term_opts; // default to 0
-}
-
-//
-// ANCHOR Initiation
-//
-
-/// Initiates terminal basics
-/// Returns: Error keyCode, non-zero on error
-int coninit(int flags = 0) {
-version (Posix) {
- tcgetattr(STDIN_FILENO, &old_tio);
- new_tio = old_tio;
- new_tio.c_lflag &= TERM_ATTR;
-
- //TODO: See flags we can put
- // tty_ioctl TIOCSETD
-} else {
- handleOut = GetStdHandle(STD_OUTPUT_HANDLE);
- handleIn = GetStdHandle(STD_INPUT_HANDLE);
-
- // Disable annoying mouse mode.
- DWORD mode = void;
- GetConsoleMode(handleIn, &mode);
- mode &= ~ENABLE_MOUSE_INPUT;
- SetConsoleMode(handleIn, mode);
-}
- return 0;
-}
-
-// Invert console color with defaultColor
-/*void thcolin() {
- version (Windows)
- SetConsoleTextAttribute(hOut, COMMON_LVB_REVERSE_VIDEO | defaultColor);
- version (Posix)
- fputs("\033[7m", stdout);
-}
-
-// Reset console color to defaultColor
-void thcolrst() {
- version (Windows)
- SetConsoleTextAttribute(hOut, defaultColor);
- version (Posix)
- fputs("\033[0m", stdout);
-}*/
-
-/// Clear screen
-void conclear() {
-version (Windows) {
- CONSOLE_SCREEN_BUFFER_INFO csbi = void;
- COORD c; // 0, 0
- GetConsoleScreenBufferInfo(handleOut, &csbi);
- //const int buflen = csbi.dwSize.X * csbi.dwSize.Y; buf buflen
- const int buflen = // window buflen
- (csbi.srWindow.Right - csbi.srWindow.Left + 1)* // width
- (csbi.srWindow.Bottom - csbi.srWindow.Top + 1); // height
- DWORD num = void; // kind of ala .NET
- FillConsoleOutputCharacterA(handleOut, ' ', buflen, c, &num);
- FillConsoleOutputAttribute(handleOut, csbi.wAttributes, buflen, c, &num);
- conmvcur(0, 0);
-} else version (Posix) {
- // "ESC [ 2 J" acts like clear(1)
- // "ESC c" is a full reset ala cls (Windows)
- printf("\033c");
-}
-else static assert(false, "Not implemented");
-}
-
-/// Get host console screen size.
-/// Params:
-/// w = Width (columns) pointer.
-/// h = Height (rows) pointer.
-void consize(int *w, int *h) {
- /// NOTE: A COORD uses SHORT (short) and Linux uses unsigned shorts.
-version (Windows) {
- CONSOLE_SCREEN_BUFFER_INFO c = void;
- GetConsoleScreenBufferInfo(handleOut, &c);
- *w = c.srWindow.Right - c.srWindow.Left + 1;
- *h = c.srWindow.Bottom - c.srWindow.Top + 1;
-} else version (Posix) {
- winsize win = void;
- ioctl(STDOUT_FILENO, TIOCGWINSZ, &win);
- *w = win.ws_col;
- *h = win.ws_row;
-}
-}
-
-/// Set cursor position.
-///
-/// Coordonates start at zero.
-/// Params:
-/// x = X position (horizontal, columns)
-/// y = Y position (vertical, rows)
-void conmvcur(int x, int y) {
-version (Windows) { // 0-based
- COORD c = { cast(SHORT)x, cast(SHORT)y };
- SetConsoleCursorPosition(handleOut, c);
-} else version (Posix) { // 1-based
- printf("\033[%d;%dH", y + 1, x + 1);
-}
-}
-
-/// Get cursor position.
-///
-/// Coordonates start at zero.
-/// Params:
-/// x = X position (horizontal, columns)
-/// y = Y position (vertical, rows)
-void congetxy(int *x, int *y) {
-version (Windows) { // 0-based
- CONSOLE_SCREEN_BUFFER_INFO csbi = void;
- GetConsoleScreenBufferInfo(handleOut, &csbi);
- *x = csbi.dwCursorPosition.X;
- *y = csbi.dwCursorPosition.Y;
-} else version (Posix) { // 1-based
- tcsetattr(STDIN_FILENO, TCSANOW, &new_tio);
- printf("\033[6n");
- scanf("\033[%d;%dR", y, x); // row, col
- tcsetattr(STDIN_FILENO, TCSANOW, &old_tio);
- --*x;
- --*y;
-}
-}
-
-//
-// ANCHOR Terminal input
-//
-
-/// Read a single immediate terminal/console event such as a keyboard or mouse.
-///
-/// Window resize events are handled externally.
-/// Windows: User handler function called if EventType is WINDOW_BUFFER_SIZE_EVENT.
-/// Posix: Handled externally via the SIGWINCH signal.
-/// Params: ii = InputInfo structure
-void conrdkey(InputInfo *ii) {
- ii.type = InputType.None;
-version (Windows) {
- INPUT_RECORD ir = void;
- DWORD d = void;
-L_READ_AGAIN:
- if (ReadConsoleInput(handleIn, &ir, 1, &d) == FALSE)
- return;
-
- switch (ir.EventType) {
- case KEY_EVENT:
- if (ir.KeyEvent.bKeyDown == FALSE)
- goto L_READ_AGAIN;
-
- with (ii) {
- type = InputType.Key;
- const DWORD state = ir.KeyEvent.dwControlKeyState;
- key.alt = (state & ALT_PRESSED) != 0;
- key.ctrl = (state & CTRL_PRESSED) != 0;
- key.shift = (state & SHIFT_PRESSED) != 0;
- key.keyChar = ir.KeyEvent.AsciiChar;
- key.keyCode = key.ctrl ?
- cast(Key)ir.KeyEvent.AsciiChar :
- cast(Key)ir.KeyEvent.wVirtualKeyCode;
- }
- break;
- case MOUSE_EVENT: //TODO: MOUSE_EVENT
- ii.type = InputType.Mouse;
- break;
- case WINDOW_BUFFER_SIZE_EVENT:
- with (ir)
- if (term_resize_handler)
- term_resize_handler(
- WindowBufferSizeEvent.dwSize.X,
- WindowBufferSizeEvent.dwSize.Y);
- FlushConsoleInputBuffer(handleIn);
- break;
- default: // Menu and Focus events
- goto L_READ_AGAIN;
- }
-} else version (Posix) {
- //TODO: Get modifier keys states
- //TODO: See console_ioctl for KDGETKEYCODE
- // https://linux.die.net/man/4/console_ioctl
-
- ii.type = InputType.Key;
-
- tcsetattr(STDIN_FILENO, TCSANOW, &new_tio);
- scope(exit) tcsetattr(STDIN_FILENO, TCSANOW, &old_tio);
-
- uint c = getchar;
-
- with (ii.key)
- switch (c) {
- case 0: keyCode = Key.Null; return;
- case 1: keyCode = Key.HeadingStart; return;
- case 2: keyCode = Key.TextStart; return;
- case 3: /* ^C */ keyCode = Key.TextEnd; return;
- case 4: /* ^D */ keyCode = Key.TransmissionEnd; return;
- case 5: keyCode = Key.Enquiry; return;
- case 6: keyCode = Key.Acknowledge; return;
- case 7: keyCode = Key.Bell; return;
- case '\n', '\r': // \n (RETURN) or \r (ENTER)
- keyCode = Key.Enter;
- return;
- case 27: // ESC
- switch (c = getchar) {
- case '[':
- switch (c = getchar) {
- case 'A': keyCode = Key.UpArrow; return;
- case 'B': keyCode = Key.DownArrow; return;
- case 'C': keyCode = Key.RightArrow; return;
- case 'D': keyCode = Key.LeftArrow; return;
- case 'F': keyCode = Key.End; return;
- case 'H': keyCode = Key.Home; return;
- // There is an additional getchar due to the pending '~'
- case '2': keyCode = Key.Insert; getchar; return;
- case '3': keyCode = Key.Delete; getchar; return;
- case '5': keyCode = Key.PageUp; getchar; return;
- case '6': keyCode = Key.PageDown; getchar; return;
- default: goto L_DEFAULT;
- } // [
- default: goto L_DEFAULT;
- } // ESC
- case 0x08, 0x7F: // backspace
- keyCode = Key.Backspace;
- return;
- case 23: // #
- keyCode = Key.NumSign;
- keyChar = '#';
- return;
- default:
- if (c >= 'a' && c <= 'z') {
- keyCode = cast(Key)(c - 32);
- keyChar = cast(char)c;
- return;
- } else if (c >= 20 && c <= 126) {
- keyCode = cast(Key)c;
- keyChar = cast(char)c;
- return;
- }
- }
-
-L_DEFAULT:
- ii.key.keyCode = cast(Key)c;
-} // version (Posix)
-}
-
-/// Read a line from stdin.
-/// Returns: Character slice; Or null on error.
-char[] conrdln() {
- import core.stdc.ctype : isprint;
-
- // GNU readline has this set to 512
- enum BUFFERSIZE = 1024;
-
- __gshared char* buffer;
-
- if (buffer == null) {
- buffer = cast(char*)malloc(BUFFERSIZE);
- if (buffer == null)
- return null;
- }
-
- // NOTE: stdin is line-buffered by the host console in their own buffer.
- // Hitting return or enter makes the console write its buffer to stdin.
- // Reading stdin, we copy until we see a newline.
- size_t len;
- while (len < BUFFERSIZE) {
- int c = getchar();
- if (c == '\n' || c == EOF)
- break;
- buffer[len++] = cast(char)c;
- }
- buffer[len] = 0;
- return buffer[0..len];
-}
-
-/// Key information structure
-struct KeyInfo {
- Key keyCode; /// Key keyCode.
- char keyChar; /// Character.
- bool ctrl; /// If either CTRL was held down.
- bool alt; /// If either ALT was held down.
- bool shift; /// If SHIFT was held down.
-}
-/// Mouse input event structure
-struct MouseInfo {
- ushort x, y;
-}
-/// Global input event structure
-struct InputInfo {
- InputType type; /// Input event type, can only be mouse or key
- union {
- KeyInfo key; /// Keyboard event structure
- MouseInfo mouse; /// Mouse event structure
- }
-}
-
-/// Input type for InputInfo structure
-enum InputType : ushort {
- None, Key, Mouse
-}
-/*
-enum MouseButton : ushort { // Windows compilant
- Left = 1, Right = 2, Middle = 4, Mouse4 = 8, Mouse5 = 16
-}
-
-enum MouseState : ushort { // Windows compilant
- RightAlt = 1, LeftAlt = 2, RightCtrl = 4,
- LeftCtrl = 8, Shift = 0x10, NumLock = 0x20,
- ScrollLock = 0x40, CapsLock = 0x80, EnhancedKey = 0x100
-}
-
-enum MouseEventType { // Windows compilant
- Moved = 1, DoubleClick = 2, Wheel = 4, HorizontalWheel = 8
-}
-*/
-/// Key codes mapping.
-//TODO: Redo keycodes
-// < 128: ascii map
-// >=128: special codes (e.g., arrow keys)
-enum Key : short {
- Null = 0, /// ^@, NUL
- HeadingStart = 1, // ^A, SOH
- TextStart = 2, /// ^B, STX
- TextEnd = 3, /// ^C, ETX
- TransmissionEnd = 4, /// ^D, EOT
- Enquiry = 5, /// ^E, ENQ
- Acknowledge = 6, /// ^F, ACK
- Bell = 7, /// ^G, BEL
- Backspace = 8, /// ^H, BS
- Tab = 9, /// ^I, HT
- LineFeed = 10, /// ^J, LF
- VerticalTab = 11, /// ^K, VT
- FormFeed = 12, /// ^L, FF
- Enter = 13, /// ^M, CR (return key)
- Pause = 19,
- Escape = 27,
- Spacebar = 32,
- PageUp = 33,
- PageDown = 34,
- End = 35,
- Home = 36,
- LeftArrow = 37,
- UpArrow = 38,
- RightArrow = 39,
- DownArrow = 40,
- Select = 41,
- Print = 42,
- Execute = 43,
- PrintScreen = 44,
- Insert = 45,
- Delete = 46,
- Help = 47,
- D0 = 48,
- D1 = 49,
- D2 = 50,
- D3 = 51,
- D4 = 52,
- D5 = 53,
- D6 = 54,
- D7 = 55,
- D8 = 56,
- D9 = 57,
- A = 65,
- B = 66,
- C = 67,
- D = 68,
- E = 69,
- F = 70,
- G = 71,
- H = 72,
- I = 73,
- J = 74,
- K = 75,
- L = 76,
- M = 77,
- N = 78,
- O = 79,
- P = 80,
- Q = 81,
- R = 82,
- S = 83,
- T = 84,
- U = 85,
- V = 86,
- W = 87,
- X = 88,
- Y = 89,
- Z = 90,
- LeftMeta = 91,
- RightMeta = 92,
- Applications = 93,
- Sleep = 95,
- NumPad0 = 96,
- NumPad1 = 97,
- NumPad2 = 98,
- NumPad3 = 99,
- NumPad4 = 100,
- NumPad5 = 101,
- NumPad6 = 102,
- NumPad7 = 103,
- NumPad8 = 104,
- NumPad9 = 105,
- Multiply = 106,
- Add = 107,
- Separator = 108,
- Subtract = 109,
- Decimal = 110,
- Divide = 111,
- F1 = 112,
- F2 = 113,
- F3 = 114,
- F4 = 115,
- F5 = 116,
- F6 = 117,
- F7 = 118,
- F8 = 119,
- F9 = 120,
- F10 = 121,
- F11 = 122,
- F12 = 123,
- F13 = 124,
- F14 = 125,
- F15 = 126,
- F16 = 127,
- F17 = 128,
- F18 = 129,
- F19 = 130,
- F20 = 131,
- F21 = 132,
- F22 = 133,
- F23 = 134,
- F24 = 135,
- BrowserBack = 166,
- BrowserForward = 167,
- BrowserRefresh = 168,
- BrowserStop = 169,
- BrowserSearch = 170,
- BrowserFavorites = 171,
- BrowserHome = 172,
- VolumeMute = 173,
- VolumeDown = 174,
- VolumeUp = 175,
- MediaNext = 176,
- MediaPrevious = 177,
- MediaStop = 178,
- MediaPlay = 179,
- LaunchMail = 180,
- LaunchMediaSelect = 181,
- LaunchApp1 = 182,
- LaunchApp2 = 183,
- Oem1 = 186,
- OemPlus = 187,
- OemComma = 188,
- OemMinus = 189,
- OemPeriod = 190,
- Oem2 = 191,
- Oem3 = 192,
- Oem4 = 219,
- Oem5 = 220,
- Oem6 = 221,
- Oem7 = 222,
- Oem8 = 223,
- Oem102 = 226,
- Process = 229,
- Packet = 231,
- Attention = 246,
- CrSel = 247,
- ExSel = 248,
- EraseEndOfFile = 249,
- Play = 250,
- Zoom = 251,
- NumSign = 252, /// #
- Pa1 = 253,
- OemClear = 254
-}
\ No newline at end of file
diff --git a/app/utils.d b/app/utils.d
deleted file mode 100644
index 746873d..0000000
--- a/app/utils.d
+++ /dev/null
@@ -1,223 +0,0 @@
-/// Application utilities.
-///
-/// Authors: dd86k
-/// Copyright: © dd86k
-/// License: BSD-3-Clause-Clear
-module utils;
-
-import core.stdc.stdio : sscanf;
-import core.stdc.ctype : isprint;
-
-char hexc0(ubyte upper) {
- ubyte h = upper >> 4;
- return cast(char)(h >= 0xa ? h + ('a' - 0xa) : h + '0');
-}
-unittest {
- assert(hexc0(0x00) == '0');
- assert(hexc0(0x10) == '1');
- assert(hexc0(0x20) == '2');
- assert(hexc0(0x30) == '3');
- assert(hexc0(0x40) == '4');
- assert(hexc0(0x50) == '5');
- assert(hexc0(0x60) == '6');
- assert(hexc0(0x70) == '7');
- assert(hexc0(0x80) == '8');
- assert(hexc0(0x90) == '9');
- assert(hexc0(0xa0) == 'a');
- assert(hexc0(0xb0) == 'b');
- assert(hexc0(0xc0) == 'c');
- assert(hexc0(0xd0) == 'd');
- assert(hexc0(0xe0) == 'e');
- assert(hexc0(0xf0) == 'f');
-}
-char hexc1(ubyte lower) {
- ubyte l = lower & 15;
- return cast(char)(l >= 0xa ? l + ('a' - 0xa) : l + '0');
-}
-unittest {
- assert(hexc1(0) == '0');
- assert(hexc1(1) == '1');
- assert(hexc1(2) == '2');
- assert(hexc1(3) == '3');
- assert(hexc1(4) == '4');
- assert(hexc1(5) == '5');
- assert(hexc1(6) == '6');
- assert(hexc1(7) == '7');
- assert(hexc1(8) == '8');
- assert(hexc1(9) == '9');
- assert(hexc1(0xa) == 'a');
- assert(hexc1(0xb) == 'b');
- assert(hexc1(0xc) == 'c');
- assert(hexc1(0xd) == 'd');
- assert(hexc1(0xe) == 'e');
- assert(hexc1(0xf) == 'f');
-}
-
-int hexstr(char *buffer, size_t bsize, ubyte *data, size_t dsize, char sep = 0) {
- int min = sep ? 3 : 2;
- int len;
- for (size_t i; i < dsize; ++i) {
- if (len + min > bsize)
- return len;
-
- if (sep && len) buffer[len++] = sep;
- ubyte b = data[i];
- buffer[len++] = hexc0(b);
- buffer[len++] = hexc1(b);
- }
- return len;
-}
-unittest {
- ubyte[4] data = [ 0x12, 0x34, 0x56, 0x78 ];
- char[8] buf = void;
- int len = hexstr(buf.ptr, 8, data.ptr, 4);
- assert(len == 8);
- assert(buf[0] == '1');
- assert(buf[1] == '2');
- assert(buf[2] == '3');
- assert(buf[3] == '4');
- assert(buf[4] == '5');
- assert(buf[5] == '6');
- assert(buf[6] == '7');
- assert(buf[7] == '8');
-}
-
-int realchar(char *buffer, size_t bsize, char c) {
- int len;
- if (isprint(c)) {
- if (len >= bsize) goto end;
- buffer[len++] = c;
- } else {
- if (len + 4 >= bsize) goto end;
- buffer[len++] = '\\';
- buffer[len++] = 'x';
- buffer[len++] = hexc0(c);
- buffer[len++] = hexc1(c);
- }
- end: return len;
-}
-
-int realstring(char *buffer, size_t bsize, const(char)* str, size_t ssize,
- char pre = 0, char post = 0) {
- int len; // total length
-
- if (bsize == 0)
- return 0;
-
- if (pre && bsize)
- buffer[len++] = pre;
-
- for (size_t i; i < ssize && len < bsize; ++i) {
- char c = str[i];
- if (isprint(c)) {
- if (len >= bsize) break;
- buffer[len++] = c;
- } else {
- if (len + 4 >= bsize) break;
- buffer[len++] = '\\';
- buffer[len++] = 'x';
- buffer[len++] = hexc0(c);
- buffer[len++] = hexc1(c);
- }
- }
-
- if (post && len < bsize)
- buffer[len++] = post;
-
- return len;
-}
-unittest {
- char[2] bi = "`\n";
- char[10] bo = void; // '`' '\\x0a'
- assert(realstring(bo.ptr, 10, bi.ptr, 2) == 5);
- assert(bo[0] == '`');
- assert(bo[1] == '\\');
- assert(bo[2] == 'x');
- assert(bo[3] == '0');
- assert(bo[4] == 'a');
-}
-
-/// Unformat text number.
-/// Params:
-/// result = Long pointer.
-/// str = Input.
-/// Returns: True if could not parse number.
-bool unformat(int *result, const(char) *str) {
- return sscanf(str, "%i", result) != 1;
-}
-
-/// Unformat text number.
-/// Params:
-/// result = Long pointer.
-/// str = Input.
-/// Returns: True if could not parse number.
-bool unformat64(long *result, const(char) *str) {
- return sscanf(str, "%lli", result) != 1;
-}
-
-/// Read entire file into memory using the C FILE API.
-///
-/// To release its buffer, call free(3).
-/// Params:
-/// path = File path.
-/// size = Pointer to hold file size.
-/// Returns: Buffer pointer. Null on CRT error.
-ubyte *readall(const(char) *path, size_t *size) {
- import core.stdc.stdio : SEEK_SET, SEEK_END, FILE, fopen, ftell, fseek, fread, fclose;
- import core.stdc.stdlib : malloc;
-
- FILE *fd = fopen(path, "rb");
- if (fd == null)
- return null;
- scope(exit) fclose(fd);
-
- if (fseek(fd, 0, SEEK_END))
- return null;
-
- *size = cast(size_t)ftell(fd);
- fseek(fd, 0, SEEK_SET); // rewind binding is broken
-
- ubyte *buffer = cast(ubyte*)malloc(*size);
- if (buffer == null)
- return null;
-
- if (fread(buffer, *size, 1, fd) == 0)
- return null;
-
- return buffer;
-}
-
-/// Return the pointer position at the file's basename.
-///
-/// On failure, returns original pointer.
-/// Params: path = File path.
-/// Returns: Non-null pointer
-const(char)* basename(const(char) *path) {
- enum MAX = 4096;
- size_t last, i;
- char c = void;
- for (; (c = path[i]) != 0 && i < MAX; ++i) {
- switch (c) {
- case '/', '\\': last = i + 1; continue;
- default:
- }
- }
- // "test/" -> invalid
- return last >= i ? path : path + last;
-}
-unittest {
- import core.stdc.string : strcmp;
- const(char) *path = "test/file.lib";
- const(char) *base = basename(path);
- assert(base);
- assert(strcmp(base, "file.lib") == 0);
-}
-
-/// Returns default character if given character is outside ASCII range.
-/// Params:
-/// c = Character to evaluate.
-/// d = Default character, fallback.
-/// Returns: Character.
-int asciichar(int c, int d) {
- return c < 32 || c > 126 ? d : c;
-}
\ No newline at end of file
diff --git a/common/cli.d b/common/cli.d
new file mode 100644
index 0000000..098cb3d
--- /dev/null
+++ b/common/cli.d
@@ -0,0 +1,409 @@
+/// Common command-line options
+///
+/// Authors: dd86k
+/// Copyright: © dd86k
+/// License: BSD-3-Clause-Clear
+module common.cli;
+
+import adbg.platform;
+import adbg.debugger.exception : adbg_exception_t, adbg_exception_name;
+import adbg.machines : AdbgMachine;
+import adbg.disassembler : AdbgDisSyntax;
+import adbg.include.capstone : libcapstone_dynload, cs_version;
+import adbg.include.c.stdlib : exit;
+import adbg.include.d.config : GDC_VERSION, GDC_EXCEPTION_MODE, LLVM_VERSION;
+import core.stdc.stdio;
+import core.stdc.stdlib;
+import core.stdc.string;
+import core.stdc.errno;
+
+enum COPYRIGHT = "Copyright (c) 2019-2024 dd86k ";
+
+immutable(char) *page_license =
+COPYRIGHT~`
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.`;
+
+debug enum FULL_VERSION = ADBG_VERSION~"+"~__BUILDTYPE__;
+else enum FULL_VERSION = ADBG_VERSION;
+
+/// Turns a __VERSION__ number into a string constant
+template DSTRVER(uint ver) {
+ enum DSTRVER =
+ cast(char)((ver / 1000) + '0') ~ "." ~
+ cast(char)(((ver % 1000) / 100) + '0') ~
+ cast(char)(((ver % 100) / 10) + '0') ~
+ cast(char)((ver % 10) + '0');
+}
+/// Compiler version string
+enum __D_VERSION__ = DSTRVER!__VERSION__;
+
+__gshared {
+ /// Machine option
+ AdbgMachine opt_machine;
+ /// Disassembler syntax option
+ AdbgDisSyntax opt_syntax;
+}
+
+private enum : ubyte {
+ ARG_NONE,
+ ARG_STRING,
+ //ARG_NUMBER, // %i
+ //ARG_LARGENUMBER, // %lli
+}
+
+struct option_t { align(1):
+ this (char oshort, string olong, string desc, int function() ufunc) {
+ shortname = oshort;
+ longname = olong;
+ description = desc;
+ argtype = ARG_NONE;
+ f = ufunc;
+ }
+ this (char oshort, string olong, string desc, int function(const(char)*) ufunc) {
+ shortname = oshort;
+ longname = olong;
+ description = desc;
+ argtype = ARG_STRING;
+ fa = ufunc;
+ }
+ string longname; /// Long switch name
+ string description; /// Option description
+ char shortname; /// Short switch name
+ ubyte argtype; /// Argument type
+ union {
+ int function() f;
+ int function(const(char)*) fa;
+ }
+}
+
+//NOTE: Can't make a template and pass a function pointer
+
+enum option_arch = option_t('a', "arch", "Select machine for disassembler (default=platform)", &cli_march);
+enum option_syntax = option_t('s', "syntax", "Select syntax for disassembler (default=platform)", &cli_syntax);
+enum option_version = option_t(0, "version", "Show the version screen and exit", &cli_version);
+enum option_build_info = option_t(0, "build-info", "Show the build and debug information and exit", &cli_build_info);
+enum option_ver = option_t(0, "ver", "Show only the version string and exit", &cli_ver);
+enum option_license = option_t(0, "license", "Show the license page and exit", &cli_license);
+
+//TODO: Return error
+// <0 -> error
+// 0 -> no args left
+// >0 -> args left
+//TODO: Make option functions return <0=error >0=ok, consumed arg(s)
+//TODO: !! move arguments around, adjust and return argc
+int getopt(int argc, const(char) **argv, immutable(option_t)[] options) {
+ const(char) *arg = void;
+ const(char) *val = void;
+ CLI: for (int argi = 1; argi < argc; ++argi) {
+ arg = argv[argi];
+
+ if (arg[1] == '-') { // Long options
+ const(char) *argLong = arg + 2;
+
+ // test for "--" (extra args)
+ /*if (argLong[0] == 0) {
+ if (cli_args_stop(++argi, argc, argv))
+ return EXIT_FAILURE;
+ break CLI;
+ }*/
+
+ // Check options
+ L_LONG: foreach (ref opt; options) {
+ //TODO: test for '='
+ // --example=value
+
+ if (strncmp(argLong, opt.longname.ptr, opt.longname.length))
+ continue L_LONG;
+
+ // no argument expected
+ if (opt.argtype == ARG_NONE) {
+ if (opt.f())
+ return EXIT_FAILURE;
+ continue CLI;
+ }
+
+ // with argument
+ if (++argi >= argc) {
+ getopt_err_missl(opt.longname.ptr);
+ return EXIT_FAILURE;
+ }
+ val = argv[argi];
+ if (opt.fa(val)) {
+ getopt_err_invl(opt.longname.ptr, val);
+ return EXIT_FAILURE;
+ }
+ continue CLI;
+ }
+ } else if (arg[0] == '-') { // Short options
+ // test for "-" (stdin)
+ char argShort = arg[1];
+ if (argShort == 0) { // "-"
+ puts("main: standard input not supported");
+ return EXIT_FAILURE;
+ }
+
+ L_SHORT: foreach (ref opt; options) {
+ if (argShort != opt.shortname)
+ continue L_SHORT;
+
+ // no argument
+ if (opt.argtype == ARG_NONE) {
+ if (opt.f())
+ return EXIT_FAILURE;
+ continue CLI;
+ }
+
+ // with argument
+ if (++argi >= argc) {
+ getopt_err_misss(argShort);
+ return EXIT_FAILURE;
+ }
+ val = argv[argi];
+ if (opt.fa(val)) {
+ getopt_err_invs(opt.shortname, val);
+ return EXIT_FAILURE;
+ }
+ continue CLI;
+ }
+ } /*else if (entry) { // Default option value
+ //*entry = arg;
+ continue CLI;
+ }*/
+
+ getopt_err_unkn(arg);
+ return EXIT_FAILURE;
+ }
+
+ return getopterrno;
+}
+//TODO: These unittests!
+unittest {
+}
+
+void getoptprinter(immutable(option_t)[] options, int skip = 0) {
+ static immutable int padding = -17;
+ foreach (ref option; options[skip..$]) { with (option)
+ if (shortname)
+ printf(" -%c, --%*s %s\n", shortname, padding, longname.ptr, description.ptr);
+ else
+ printf(" --%*s %s\n", padding, longname.ptr, description.ptr);
+ }
+}
+
+private enum GETOPTBFSZ = 2048;
+private __gshared char* getopterrbuf;
+private __gshared int getopterrno;
+
+const(char)* getopt_errmsg() {
+ return getopterrbuf;
+}
+int getopt_errno() {
+ return getopterrno;
+}
+
+private int getopt_prepbuf() {
+ getopterrno = -1;
+ if (getopterrbuf == null) {
+ getopterrbuf = cast(char*)malloc(GETOPTBFSZ);
+ if (getopterrbuf == null)
+ return 1;
+ }
+ return 0;
+}
+private void getopt_err_unkn(const(char)* opt) {
+ if (getopt_prepbuf()) return;
+ snprintf(getopterrbuf, GETOPTBFSZ,
+ "main: unknown option '%s'\n", opt);
+}
+private void getopt_err_invl(const(char)* opt, const(char)* val) {
+ if (getopt_prepbuf()) return;
+ snprintf(getopterrbuf, GETOPTBFSZ,
+ "main: '%s' is an invalid value for --%s\n", val, opt);
+}
+private void getopt_err_invs(char opt, const(char)* val) {
+ if (getopt_prepbuf()) return;
+ snprintf(getopterrbuf, GETOPTBFSZ,
+ "main: '%s' is an invalid value for -%c\n", val, opt);
+}
+private void getopt_err_missl(const(char)* opt) {
+ if (getopt_prepbuf()) return;
+ snprintf(getopterrbuf, GETOPTBFSZ,
+ "main: missing argument for --%s\n", opt);
+}
+private void getopt_err_misss(char opt) {
+ if (getopt_prepbuf()) return;
+ snprintf(getopterrbuf, GETOPTBFSZ,
+ "main: missing argument for -%c\n", opt);
+}
+
+const(char)* getopterr() {
+ return getopterrbuf;
+}
+
+bool wantsHelp(const(char) *query) {
+ return (query[0] == 'h' && query[1] == 0) ||
+ strcmp(query, "help") == 0;
+}
+
+//
+// --march
+//
+
+struct setting_platform_t {
+ AdbgMachine val;
+ const(char)* opt, alt, desc;
+}
+immutable setting_platform_t[] platforms = [
+ { AdbgMachine.i8086, "x86_16", "8086", "x86 16-bit (real mode)" },
+ { AdbgMachine.x86, "x86", "i386", "x86 32-bit (extended mode)" },
+ { AdbgMachine.amd64, "x86_64", "amd64", "x86 64-bit (long mode)" },
+];
+
+int cli_march(const(char) *val) {
+ if (wantsHelp(val)) {
+ puts("Available machine architectures:");
+ foreach (setting_platform_t p; platforms) {
+ with (p)
+ printf("%8s, %-10s %s\n", opt, alt, desc);
+ }
+ exit(0);
+ }
+ foreach (setting_platform_t p; platforms) {
+ if (strcmp(val, p.opt) == 0 || strcmp(val, p.alt) == 0) {
+ opt_machine = p.val;
+ return EXIT_SUCCESS;
+ }
+ }
+ return EXIT_FAILURE;
+}
+
+//
+// --syntax
+//
+
+struct setting_syntax_t {
+ AdbgDisSyntax val;
+ const(char)* opt, desc;
+}
+immutable setting_syntax_t[] syntaxes = [
+ { AdbgDisSyntax.att, "att", "AT&T syntax" },
+ { AdbgDisSyntax.intel, "intel", "Intel syntax" },
+];
+
+int cli_syntax(const(char) *val) {
+ if (wantsHelp(val)) {
+ puts("Available disassembler syntaxes:");
+ foreach (setting_syntax_t syntax; syntaxes) {
+ with (syntax)
+ printf("%-10s %s\n", opt, desc);
+ }
+ exit(0);
+ }
+ foreach (setting_syntax_t syntax; syntaxes) {
+ if (strcmp(val, syntax.opt) == 0) {
+ opt_syntax = syntax.val;
+ return EXIT_SUCCESS;
+ }
+ }
+ return EXIT_FAILURE;
+}
+
+int cli_build_info() {
+ __gshared immutable(char) *page =
+ "Compiler "~__VENDOR__~" "~__D_VERSION__~"\n"~
+ "Target "~TARGET_TRIPLE~"\n"~
+ "Object "~TARGET_OBJFMT~"\n"~
+ "FPU "~TARGET_FLTABI~"\n"~
+ "CppRT "~TARGET_CPPRT~"\n"~
+ "Config "~D_FEATURES;
+ puts(page);
+
+ static if (GDC_VERSION) {
+ printf("GCC %d\n", GDC_VERSION);
+ printf("GDC-EH %s\n", GDC_EXCEPTION_MODE);
+ }
+
+ version (CRuntime_Glibc) {
+ import adbg.include.c.config : gnu_get_libc_version;
+ printf("Glibc %s\n", gnu_get_libc_version());
+ }
+
+ static if (LLVM_VERSION)
+ printf("LLVM %d\n", LLVM_VERSION);
+
+ printf("Capstone ");
+ if (libcapstone_dynload()) {
+ puts("error");
+ } else {
+ int major = void, minor = void;
+ cs_version(&major, &minor);
+ printf("%d.%d\n", major, minor);
+ }
+
+ exit(0);
+ return 0;
+}
+
+//
+// --version
+//
+
+int cli_version() {
+ __gshared immutable(char) *page_version =
+ "alicedbg "~FULL_VERSION~"\n"~
+ " Built "~__TIMESTAMP__~"\n"~
+ " "~COPYRIGHT~"\n"~
+ "License BSD-3-Clause-Clear\n"~
+ " \n"~
+ "Homepage https://git.dd86k.space/dd86k/alicedbg";
+
+ puts(page_version);
+
+ exit(0);
+ return 0;
+}
+
+//
+// --ver
+//
+
+int cli_ver() {
+ puts(FULL_VERSION);
+ exit(0);
+ return 0;
+}
+
+//
+// --license
+//
+
+int cli_license() {
+ puts(page_license);
+ exit(0);
+ return 0;
+}
\ No newline at end of file
diff --git a/common/error.d b/common/error.d
new file mode 100644
index 0000000..8f81be6
--- /dev/null
+++ b/common/error.d
@@ -0,0 +1,44 @@
+/// Error handling, printing, and contracting
+///
+/// Authors: dd86k
+/// Copyright: © dd86k
+/// License: BSD-3-Clause-Clear
+module common.error;
+
+import core.stdc.stdlib : exit;
+import core.stdc.string : strerror;
+import core.stdc.errno : errno;
+import adbg.error;
+import adbg.disassembler;
+import adbg.debugger.exception;
+import adbg.machines : AdbgMachine;
+import core.stdc.stdio;
+import core.stdc.stdlib : malloc;
+
+void print_adbg_error(
+ const(char)* mod = cast(char*)__MODULE__,
+ int line = __LINE__) {
+ printf("%s", mod);
+ debug printf("@%u", line);
+ printf(": %s\n", mod, line, adbg_error_msg());
+ debug print_adbg_trace();
+}
+
+private
+void print_adbg_trace() {
+ const(adbg_error_t)* e = adbg_error_current();
+ printf(" %s@%u\n", e.mod, e.line);
+}
+
+void panic(int code, const(char)* message,
+ const(char)* mod = cast(char*)__MODULE__,
+ int line = __LINE__) {
+ printf("%s@%u: %s\n", mod, line, message);
+ exit(0);
+}
+void panic_crt() {
+ panic(errno, strerror(errno));
+}
+void panic_adbg() {
+ panic(adbg_errno(), adbg_error_msg());
+}
\ No newline at end of file
diff --git a/common/utils.d b/common/utils.d
new file mode 100644
index 0000000..0cec81d
--- /dev/null
+++ b/common/utils.d
@@ -0,0 +1,224 @@
+/// Application utilities.
+///
+/// Authors: dd86k
+/// Copyright: © dd86k
+/// License: BSD-3-Clause-Clear
+module common.utils;
+
+import core.stdc.stdio : sscanf;
+import core.stdc.ctype : isprint;
+
+char hexc0(ubyte upper) {
+ ubyte h = upper >> 4;
+ return cast(char)(h >= 0xa ? h + ('a' - 0xa) : h + '0');
+}
+unittest {
+ assert(hexc0(0x00) == '0');
+ assert(hexc0(0x10) == '1');
+ assert(hexc0(0x20) == '2');
+ assert(hexc0(0x30) == '3');
+ assert(hexc0(0x40) == '4');
+ assert(hexc0(0x50) == '5');
+ assert(hexc0(0x60) == '6');
+ assert(hexc0(0x70) == '7');
+ assert(hexc0(0x80) == '8');
+ assert(hexc0(0x90) == '9');
+ assert(hexc0(0xa0) == 'a');
+ assert(hexc0(0xb0) == 'b');
+ assert(hexc0(0xc0) == 'c');
+ assert(hexc0(0xd0) == 'd');
+ assert(hexc0(0xe0) == 'e');
+ assert(hexc0(0xf0) == 'f');
+}
+char hexc1(ubyte lower) {
+ ubyte l = lower & 15;
+ return cast(char)(l >= 0xa ? l + ('a' - 0xa) : l + '0');
+}
+unittest {
+ assert(hexc1(0) == '0');
+ assert(hexc1(1) == '1');
+ assert(hexc1(2) == '2');
+ assert(hexc1(3) == '3');
+ assert(hexc1(4) == '4');
+ assert(hexc1(5) == '5');
+ assert(hexc1(6) == '6');
+ assert(hexc1(7) == '7');
+ assert(hexc1(8) == '8');
+ assert(hexc1(9) == '9');
+ assert(hexc1(0xa) == 'a');
+ assert(hexc1(0xb) == 'b');
+ assert(hexc1(0xc) == 'c');
+ assert(hexc1(0xd) == 'd');
+ assert(hexc1(0xe) == 'e');
+ assert(hexc1(0xf) == 'f');
+}
+
+int hexstr(char *buffer, size_t bsize, ubyte *data, size_t dsize, char sep = 0) {
+ int min = sep ? 3 : 2;
+ int len;
+ for (size_t i; i < dsize; ++i) {
+ if (len + min > bsize)
+ return len;
+
+ if (sep && len) buffer[len++] = sep;
+ ubyte b = data[i];
+ //TODO: handle buffer length
+ buffer[len++] = hexc0(b);
+ buffer[len++] = hexc1(b);
+ }
+ return len;
+}
+unittest {
+ ubyte[4] data = [ 0x12, 0x34, 0x56, 0x78 ];
+ char[8] buf = void;
+ int len = hexstr(buf.ptr, 8, data.ptr, 4);
+ assert(len == 8);
+ assert(buf[0] == '1');
+ assert(buf[1] == '2');
+ assert(buf[2] == '3');
+ assert(buf[3] == '4');
+ assert(buf[4] == '5');
+ assert(buf[5] == '6');
+ assert(buf[6] == '7');
+ assert(buf[7] == '8');
+}
+
+int realchar(char *buffer, size_t bsize, char c) {
+ int len;
+ if (isprint(c)) {
+ if (len >= bsize) goto end;
+ buffer[len++] = c;
+ } else {
+ if (len + 4 >= bsize) goto end;
+ buffer[len++] = '\\';
+ buffer[len++] = 'x';
+ buffer[len++] = hexc0(c);
+ buffer[len++] = hexc1(c);
+ }
+ end: return len;
+}
+
+int realstring(char *buffer, size_t bsize, const(char)* str, size_t ssize,
+ char pre = 0, char post = 0) {
+ int len; // total length
+
+ if (bsize == 0)
+ return 0;
+
+ if (pre && bsize)
+ buffer[len++] = pre;
+
+ for (size_t i; i < ssize && len < bsize; ++i) {
+ char c = str[i];
+ if (isprint(c)) {
+ if (len >= bsize) break;
+ buffer[len++] = c;
+ } else {
+ if (len + 4 >= bsize) break;
+ buffer[len++] = '\\';
+ buffer[len++] = 'x';
+ buffer[len++] = hexc0(c);
+ buffer[len++] = hexc1(c);
+ }
+ }
+
+ if (post && len < bsize)
+ buffer[len++] = post;
+
+ return len;
+}
+unittest {
+ char[2] bi = "`\n";
+ char[10] bo = void; // '`' '\\x0a'
+ assert(realstring(bo.ptr, 10, bi.ptr, 2) == 5);
+ assert(bo[0] == '`');
+ assert(bo[1] == '\\');
+ assert(bo[2] == 'x');
+ assert(bo[3] == '0');
+ assert(bo[4] == 'a');
+}
+
+/// Unformat text number.
+/// Params:
+/// result = Long pointer.
+/// str = Input.
+/// Returns: True if could not parse number.
+bool unformat(int *result, const(char) *str) {
+ return sscanf(str, "%i", result) != 1;
+}
+
+/// Unformat text number.
+/// Params:
+/// result = Long pointer.
+/// str = Input.
+/// Returns: True if could not parse number.
+bool unformat64(long *result, const(char) *str) {
+ return sscanf(str, "%lli", result) != 1;
+}
+
+/// Read entire file into memory using the C FILE API.
+///
+/// To release its buffer, call free(3).
+/// Params:
+/// path = File path.
+/// size = Pointer to hold file size.
+/// Returns: Buffer pointer. Null on CRT error.
+ubyte *readall(const(char) *path, size_t *size) {
+ import core.stdc.stdio : SEEK_SET, SEEK_END, FILE, fopen, ftell, fseek, fread, fclose;
+ import core.stdc.stdlib : malloc;
+
+ FILE *fd = fopen(path, "rb");
+ if (fd == null)
+ return null;
+ scope(exit) fclose(fd);
+
+ if (fseek(fd, 0, SEEK_END))
+ return null;
+
+ *size = cast(size_t)ftell(fd);
+ fseek(fd, 0, SEEK_SET); // rewind binding is broken
+
+ ubyte *buffer = cast(ubyte*)malloc(*size);
+ if (buffer == null)
+ return null;
+
+ if (fread(buffer, *size, 1, fd) == 0)
+ return null;
+
+ return buffer;
+}
+
+/// Return the pointer position at the file's basename.
+///
+/// On failure, returns original pointer.
+/// Params: path = File path.
+/// Returns: Non-null pointer
+const(char)* basename(const(char) *path) {
+ enum MAX = 4096;
+ size_t last, i;
+ char c = void;
+ for (; (c = path[i]) != 0 && i < MAX; ++i) {
+ switch (c) {
+ case '/', '\\': last = i + 1; continue;
+ default:
+ }
+ }
+ // "test/" -> invalid
+ return last >= i ? path : path + last;
+}
+unittest {
+ import core.stdc.string : strcmp;
+ const(char) *path = "test/file.lib";
+ const(char) *base = basename(path);
+ assert(base);
+ assert(strcmp(base, "file.lib") == 0);
+}
+
+/// Returns default character if given character is outside ASCII range.
+/// Params:
+/// c = Character to evaluate.
+/// d = Default character, fallback.
+/// Returns: Character.
+int asciichar(int c, int d) {
+ return c < 32 || c > 126 ? d : c;
+}
\ No newline at end of file
diff --git a/debugger/debugger.d b/debugger/debugger.d
new file mode 100644
index 0000000..68d5675
--- /dev/null
+++ b/debugger/debugger.d
@@ -0,0 +1,29 @@
+/// Common global variables and functions so they can be used throughout the
+/// entirety of the program.
+///
+/// Authors: dd86k
+/// Copyright: © dd86k
+/// License: BSD-3-Clause-Clear
+module debugger;
+
+import core.stdc.stdio : puts;
+import core.stdc.stdlib : exit;
+import core.stdc.string : strerror;
+import core.stdc.errno : errno;
+import adbg.error;
+import adbg.disassembler;
+import adbg.debugger.exception;
+import adbg.machines : AdbgMachine;
+import core.stdc.stdio : FILE;
+import core.stdc.stdlib : malloc;
+
+public:
+extern (C):
+__gshared:
+
+///
+int opt_pid;
+///
+const(char) *opt_file;
+///
+const(char) **opt_file_argv;
\ No newline at end of file
diff --git a/debugger/main.d b/debugger/main.d
new file mode 100644
index 0000000..0adf2aa
--- /dev/null
+++ b/debugger/main.d
@@ -0,0 +1,223 @@
+/// Command line interface.
+///
+/// Authors: dd86k
+/// Copyright: © dd86k
+/// License: BSD-3-Clause-Clear
+module main;
+
+import adbg.platform;
+import adbg.include.c.stdlib : exit;
+import adbg.include.d.config : GDC_VERSION, GDC_EXCEPTION_MODE, LLVM_VERSION;
+import adbg.debugger.exception : adbg_exception_t, adbg_exception_name;
+import adbg.self;
+import adbg.machines : adbg_machine_default;
+import adbg.disassembler;
+import adbg.error;
+import adbg.debugger.process;
+import core.stdc.stdlib : strtol, EXIT_SUCCESS, EXIT_FAILURE;
+import core.stdc.string : strcmp;
+import core.stdc.stdio;
+import debugger, shell;
+import common.cli;
+import common.utils : unformat64;
+
+private:
+
+immutable option_t[] options = [
+ // secrets
+ cast(immutable)option_t(0, "meow", "Meow and exit", &cli_meow),
+ // common options
+ cast(immutable)option_arch,
+ cast(immutable)option_syntax,
+ // debugger options
+ cast(immutable)option_t(0, "file", "Debugger: Spawn FILE for debugging", &cli_file),
+ cast(immutable)option_t(0, "args", "Debugger: Supply arguments to executable", &cli_args),
+// option_t('E', "env", "Debugger: Supply environment variables to executable", &cli_env),
+ cast(immutable)option_t('p', "attach", "Debugger: Attach to Process ID", &cli_pid),
+ // pages
+ cast(immutable)option_t('h', "help", "Show this help screen and exit", &cli_help),
+ cast(immutable)option_version,
+ cast(immutable)option_build_info,
+ cast(immutable)option_ver,
+ cast(immutable)option_license,
+];
+enum NUMBER_OF_SECRETS = 1;
+
+//
+// ANCHOR --file
+//
+
+int cli_file(const(char) *val) {
+ opt_file = val;
+ return EXIT_SUCCESS;
+}
+
+//
+// ANCHOR --args/--
+//
+
+int cli_args_stop(int argi, int argc, const(char) **argv) { // --
+ import adbg.utils.strings : adbg_util_move;
+
+ //TODO: Allocate pointer buffer instead using calloc
+
+ enum MAX = 16;
+ __gshared const(char) *[MAX] args;
+
+ opt_file_argv = cast(const(char)**)args;
+
+ int left = argc - argi; /// to move
+ void **s = cast(void**)(argv+argi);
+
+ int m = adbg_util_move(
+ cast(void**)&opt_file_argv, MAX,
+ cast(void**)&s, left);
+
+ debug assert(m == left, "cli_argsdd: 'adbg_util_move' Failed due to small buffer");
+
+ return EXIT_SUCCESS;
+}
+int cli_args(const(char) *val) { // --args
+ import adbg.utils.strings : adbg_util_expand;
+
+ int argc = void;
+ char **argv = adbg_util_expand(val, &argc);
+
+ if (argc == 0)
+ return EXIT_FAILURE;
+
+ opt_file_argv = cast(const(char)**)argv;
+ return EXIT_SUCCESS;
+}
+
+//
+// ANCHOR -E, --env
+//
+
+/*int cli_env(const(char) *val) {
+ import adbg.utils.strings : adbg_util_env;
+
+ globals.env = cast(const(char)**)adbg_util_env(val);
+
+ if (globals.env == null) {
+ printf("main: Parsing environment failed");
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}*/
+
+//
+// ANCHOR --attach
+//
+
+int cli_pid(const(char) *val) {
+ opt_pid = cast(ushort)strtol(val, null, 10);
+ return EXIT_SUCCESS;
+}
+
+//
+// ANCHOR --help
+//
+
+int cli_help() {
+ puts(
+ "alicedbg: Aiming to be a simple debugger.\n"~
+ "\n"~
+ "USAGE\n"~
+ " Spawn new process to debug:\n"~
+ " alicedbg FILE [OPTIONS...]\n"~
+ " Attach debugger to existing process:\n"~
+ " alicedbg --attach PID [OPTIONS...]\n"~
+ " Show information page and exit:\n"~
+ " alicedbg {-h|--help|--version|--ver|--license}\n"~
+ "\n"~
+ "OPTIONS"
+ );
+ getoptprinter(options, NUMBER_OF_SECRETS);
+ puts("\nFor a list of values, for example a list of platforms, type '-m help'");
+ exit(0);
+ return 0;
+}
+
+// --meow: Secret
+int cli_meow() {
+ puts(
+`
++-------------------+
+| I hate x86, meow. |
++--. .--------------+
+ \| A_A
+ (-.-)
+ / \ _
+ / \__/
+ \_||__/
+`
+ );
+ exit(0);
+ return 0;
+}
+
+extern (C)
+void crash_handler(adbg_exception_t *ex) {
+ scope(exit) exit(ex.oscode);
+
+ adbg_process_t *self = adbg_self_process();
+
+ puts(
+r"
+ _ _ _ _ _ _ _ _ _ _ _ _ _ _
+ _|_|_|_| |_|_|_|_ _|_|_|_ _|_|_|_| |_| |_| |_|
+|_| |_|_ _|_| |_|_ _|_| |_|_ _ |_|_ _|_| |_|
+|_| |_|_|_|_ |_|_|_|_| |_|_|_ |_|_|_|_| |_|
+|_|_ _ _ |_| |_| |_| |_| _ _ _|_| |_| |_| _
+ |_|_|_| |_| |_| |_| |_| |_|_|_| |_| |_| |_|
+"
+ );
+
+ printf(
+ "Exception : %s\n"~
+ "PID : %d\n",
+ adbg_exception_name(ex), cast(int)self.pid); // casting is temp
+
+ // Fault address & disasm if available
+ if (ex.faultz) {
+ printf("Address : %#zx\n", ex.faultz);
+
+ adbg_opcode_t op = void;
+ adbg_disassembler_t *dis = adbg_dis_open(adbg_machine_default());
+ printf("Instruction:");
+ if (dis && adbg_dis_process_once(dis, &op, self, ex.fault_address) == 0) {
+ // Print address
+ // Print machine bytes
+ for (size_t bi; bi < op.size; ++bi)
+ printf(" %02x", op.machine[bi]);
+ //
+ printf(" (%s", op.mnemonic);
+ if (op.operands)
+ printf(" %s", op.operands);
+ //
+ puts(")");
+ } else {
+ printf(" Disassembly unavailable (%s)\n", adbg_error_msg());
+ }
+ }
+}
+
+extern (C)
+int main(int argc, const(char)** argv) {
+ // Set crash handle, and ignore on error
+ // Could do a warning, but it might be a little confusing
+ adbg_self_set_crashhandler(&crash_handler);
+
+ int e = getopt(argc, argv, options);
+ if (e < 0) {
+ puts(getopterr());
+ return EXIT_FAILURE;
+ }
+ /*if (e >= 1) {
+ opt_file = argv[0];
+ }*/
+
+ return shell_loop();
+}
diff --git a/debugger/shell.d b/debugger/shell.d
new file mode 100644
index 0000000..7570975
--- /dev/null
+++ b/debugger/shell.d
@@ -0,0 +1,1199 @@
+/// Command shell and interface to debugger.
+///
+/// Authors: dd86k
+/// Copyright: © dd86k
+/// License: BSD-3-Clause-Clear
+module shell;
+
+import adbg.error, adbg.debugger, adbg.disassembler, adbg.object;
+import adbg.include.c.stdio;
+import adbg.include.c.stdlib;
+import adbg.include.c.stdarg;
+import core.stdc.string;
+import debugger;
+import common.error;
+import common.cli : opt_syntax;
+import common.utils;
+import term;
+
+// Enable new process name, although it is currently broken on Windows
+//version = UseNewProcessName
+
+extern (C):
+
+/// Application error
+enum ShellError {
+ none = 0,
+ invalidParameter = -1,
+ invalidCommand = -2, // or action or sub-command
+ unavailable = -3,
+ loadFailed = -4,
+ pauseRequired = -5,
+ alreadyLoaded = -6,
+ missingOption = -7,
+ unformat = -8,
+ invalidCount = -9,
+ unattached = -10,
+
+ scanMissingType = -20,
+ scanMissingValue = -21,
+ scanInputOutOfRange = -22,
+ scanNoScan = -23,
+ scanInvalidSubCommand = -24,
+
+ crt = -1000,
+ alicedbg = -1001,
+}
+
+const(char) *shell_error_string(int code) {
+ switch (code) with (ShellError) {
+ case alicedbg:
+ return adbg_error_msg;
+ case invalidParameter:
+ return "Invalid command parameter.";
+ case invalidCommand:
+ return "Invalid command.";
+ case unavailable:
+ return "Feature unavailable.";
+ case loadFailed:
+ return "Failed to load file.";
+ case pauseRequired:
+ return "Debugger needs to be paused for this action.";
+ case alreadyLoaded:
+ return "File already loaded.";
+ case missingOption:
+ return "Missing option for command.";
+ case unformat:
+ return "Input is not a number.";
+ case invalidCount:
+ return "Count must be 1 or higher.";
+ case unattached:
+ return "Need to be attached to a process for this feature.";
+
+ case scanMissingType:
+ return "Missing type parameter.";
+ case scanMissingValue:
+ return "Missing value parameter.";
+ case scanInputOutOfRange:
+ return "Value out of range.";
+ case scanNoScan:
+ return "No prior scan were initiated.";
+ case scanInvalidSubCommand:
+ return "Invalid type or subcommand.";
+
+ case none:
+ return "No error occured.";
+ default:
+ return "Unknown error.";
+ }
+}
+
+/*void registerError(void function(ref command2_help_t help)) {
+
+}
+void registerHelp(void function(ref command2_help_t help)) {
+
+}*/
+
+int shell_loop() {
+ int ecode = void;
+
+ if (loginit(null))
+ return 1337;
+
+ // Load or attach process if CLI specified it
+ if (opt_file) {
+ ecode = shell_proc_spawn(opt_file, opt_file_argv);
+ if (ecode) {
+ printf("Error: %s\n", adbg_error_msg());
+ return ecode;
+ }
+ } else if (opt_pid) {
+ ecode = shell_proc_attach(opt_pid);
+ if (ecode) {
+ printf("Error: %s\n", adbg_error_msg());
+ return ecode;
+ }
+ }
+
+ coninit();
+
+LINPUT:
+ printf("(adbg) ");
+
+ // .ptr is temporary because a slice with a length of 0
+ // also make its pointer null.
+ char* line = conrdln().ptr;
+
+ if (line == null || line[0] == 4) { // 4 == ^D
+ return 0;
+ }
+
+ ecode = shell_exec(line);
+ if (ecode)
+ logerror(shell_error_string(ecode));
+ goto LINPUT;
+}
+
+int shell_exec(const(char) *command) {
+ import adbg.utils.strings : adbg_util_expand;
+ if (command == null) return 0;
+ int argc = void;
+ char** argv = adbg_util_expand(command, &argc);
+ return shell_execv(argc, cast(const(char)**)argv);
+}
+
+int shell_execv(int argc, const(char) **argv) {
+ if (argc <= 0 || argv == null)
+ return 0;
+
+ const(char) *ucommand = argv[0];
+ immutable(command2_t) *command = shell_findcommand(ucommand);
+ if (command == null) {
+ return ShellError.invalidCommand;
+ }
+ return command.entry(argc, argv);
+}
+
+private:
+__gshared:
+
+adbg_process_t *process;
+adbg_disassembler_t *dis;
+adbg_registers_t *registers;
+
+// NOTE: BetterC stderr bindings on Windows are broken
+// And don't allow re-opening the streams, so screw it
+
+FILE *logfd;
+int loginit(const(char) *path) {
+ version (Windows) {
+ // 1. HANDLE stdHandle = GetStdHandle(STD_ERROR_HANDLE);
+ // 2. int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT);
+ // 3. FILE* file = _fdopen(fileDescriptor, "w");
+ // 4. int dup2Result = _dup2(_fileno(file), _fileno(stderr));
+ // 5. setvbuf(stderr, NULL, _IONBF, 0);
+ if (path == null) path = "CONOUT$";
+ } else {
+ if (path == null) path = "/dev/stderr";
+ }
+
+ logfd = fopen(path, "wb");
+ if (logfd) {
+ setvbuf(logfd, null, _IONBF, 0);
+ }
+ return logfd == null;
+}
+void logerror(const(char) *fmt, ...) {
+ va_list args = void;
+ va_start(args, fmt);
+ logwrite("error", fmt, args);
+}
+void logwarn(const(char) *fmt, ...) {
+ va_list args = void;
+ va_start(args, fmt);
+ logwrite("warning", fmt, args);
+}
+void loginfo(const(char) *fmt, ...) {
+ va_list args = void;
+ va_start(args, fmt);
+ logwrite(null, fmt, args);
+}
+void logwrite(const(char) *level, const(char) *fmt, va_list args) {
+ if (level) {
+ fputs(level, logfd);
+ fputs(": ", logfd);
+ }
+ vfprintf(logfd, fmt, args);
+ putchar('\n');
+}
+
+immutable string RCFILE = ".adbgrc";
+
+immutable string MODULE_SHELL = "Shell";
+immutable string MODULE_DEBUGGER = "Debugger";
+immutable string MODULE_DISASSEMBLER = "Disassembler";
+immutable string MODULE_OBJECTSERVER = "Object Server";
+
+immutable string CATEGORY_SHELL = "Command-line";
+immutable string CATEGORY_PROCESS = "Process management";
+immutable string CATEGORY_CONTEXT = "Thread context management";
+immutable string CATEGORY_MEMORY = "Memory management";
+immutable string CATEGORY_EXCEPTION = "Exception management";
+
+immutable string SECTION_NAME = "NAME";
+immutable string SECTION_SYNOPSIS = "SYNOPSIS";
+immutable string SECTION_DESCRIPTION = "DESCRIPTION";
+immutable string SECTION_NOTES = "NOTES";
+immutable string SECTION_EXAMPLES = "EXAMPLES";
+
+struct command2_help_section_t {
+ string name;
+ string[] bodies;
+}
+struct command2_help_t {
+ // Debugger, Disassembler, Object Server
+ string module_;
+ // Process management, Memory, etc.
+ string category;
+ // Short description.
+ string description;
+ //
+ command2_help_section_t[] sections;
+}
+struct command2_t {
+ string[] names;
+ string description;
+ string[] synopsis;
+ string doc_module;
+ string doc_category;
+ command2_help_section_t[] doc_sections;
+ int function(int, const(char)**) entry;
+}
+// NOTE: Called "commands_list" to avoid conflict with future "command_list" function
+//TODO: Commands
+// - !: Run host shell commands
+// - b|breakpoint: Breakpoint management
+// - t|thread: Thread management (e.g., selection, callstack)
+// - sym: Symbol management
+immutable command2_t[] shell_commands = [
+ //
+ // Debugger
+ //
+ {
+ [ "status" ],
+ "Get process status.",
+ [],
+ MODULE_DEBUGGER, CATEGORY_PROCESS,
+ [
+ {
+ SECTION_DESCRIPTION,
+ [ "Print the status of the debuggee process." ]
+ }
+ ],
+ &command_status,
+ },
+ {
+ [ "spawn" ],
+ "Spawn a new process into debugger.",
+ [
+ "FILE [ARGS...]"
+ ],
+ MODULE_DEBUGGER, CATEGORY_PROCESS,
+ [
+ {
+ SECTION_DESCRIPTION,
+ [ "Spawns a new process from path with the debugger attached." ]
+ }
+ ],
+ &command_spawn,
+ },
+ {
+ [ "attach" ],
+ "Attach debugger to live process.",
+ [
+ "PID"
+ ],
+ MODULE_DEBUGGER, CATEGORY_PROCESS,
+ [
+ {
+ SECTION_DESCRIPTION,
+ [ "Attaches debugger to an existing process by its Process ID." ]
+ }
+ ],
+ &command_attach,
+ },
+ {
+ [ "detach" ],
+ "Detach debugger from process.",
+ [],
+ MODULE_DEBUGGER, CATEGORY_PROCESS,
+ [
+ {
+ SECTION_DESCRIPTION,
+ [ "If the debugger was attached to a live process, detach "~
+ "the debugger." ]
+ }
+ ],
+ &command_detach,
+ },
+ {
+ [ "restart" ],
+ "Restart the debugging process.",
+ [],
+ MODULE_DEBUGGER, CATEGORY_PROCESS,
+ [
+ {
+ SECTION_DESCRIPTION,
+ [ "The debugger will be re-attached or the process will be "~
+ "killed and respawned." ]
+ }
+ ],
+ &command_restart,
+ },
+ {
+ [ "go" ],
+ "Continue debugging process.",
+ [],
+ MODULE_DEBUGGER, CATEGORY_PROCESS,
+ [
+ {
+ SECTION_DESCRIPTION,
+ [ "The debugger will be re-attached or the process will be "~
+ "killed and respawned." ]
+ }
+ ],
+ &command_go,
+ },
+ {
+ [ "kill" ],
+ "Terminate process.",
+ [],
+ MODULE_DEBUGGER, CATEGORY_PROCESS,
+ [
+ {
+ SECTION_DESCRIPTION,
+ [ "The debugger will be re-attached or the process will be "~
+ "killed and respawned." ]
+ }
+ ],
+ &command_kill,
+ },
+ {
+ [ "stepi" ],
+ "Perform an instruction step.",
+ [],
+ MODULE_DEBUGGER, CATEGORY_PROCESS,
+ [
+ {
+ SECTION_DESCRIPTION,
+ [ "From a paused state, executes exactly one instruction." ]
+ }
+ ],
+ &command_stepi,
+ },
+ //
+ // Context
+ //
+ {
+ [ "regs" ],
+ "Lists register values.",
+ [
+ "[NAME]"
+ ],
+ MODULE_DEBUGGER, CATEGORY_CONTEXT,
+ [
+ {
+ SECTION_DESCRIPTION,
+ [ "Get list of registers and values from process." ]
+ }
+ ],
+ &command_regs,
+ },
+ //
+ // Memory
+ //
+ {
+ [ "m", "memory" ],
+ "Dump process memory from address.",
+ [
+ "ADDRESS [LENGTH=64]"
+ ],
+ MODULE_DEBUGGER, CATEGORY_MEMORY,
+ [
+ {
+ SECTION_DESCRIPTION,
+ [ "Print memory data from address as hexadecimal." ]
+ }
+ ],
+ &command_memory,
+ },
+ {
+ [ "maps" ],
+ "List memory mapped items.",
+ [],
+ MODULE_DEBUGGER, CATEGORY_MEMORY,
+ [
+ {
+ SECTION_DESCRIPTION,
+ [ "Lists loaded modules and their memory regions." ]
+ }
+ ],
+ &command_maps,
+ },
+ {
+ [ "d", "disassemble" ],
+ "Disassemble instructions at address.",
+ [
+ "ADDRESS [COUNT=1]"
+ ],
+ MODULE_DEBUGGER, CATEGORY_MEMORY,
+ [
+ {
+ SECTION_DESCRIPTION,
+ [ "Invoke the disassembler at the address. The debugger "~
+ "will read process memory, if able, and will repeat "~
+ "the operation COUNT times. By default, it will only "~
+ "disassemble one instruction." ]
+ }
+ ],
+ &command_disassemble,
+ },
+ {
+ [ "scan" ],
+ "Scan for value in memory.",
+ [
+ "TYPE VALUE",
+ "show",
+ "reset",
+ ],
+ MODULE_DEBUGGER, CATEGORY_MEMORY,
+ [
+ {
+ SECTION_DESCRIPTION,
+ [ "Scan memory maps for specified value. "~
+ "No writing capability is available at the moment. "~
+ "To list last scan results, use 'show' subcommand.",
+ "To clear results, use 'reset' subcommand." ]
+ }
+ ],
+ &command_scan,
+ },
+ //
+ // Process management
+ //
+ {
+ [ "plist" ],
+ "List running programs.",
+ [],
+ MODULE_DEBUGGER, CATEGORY_PROCESS,
+ [
+ { SECTION_DESCRIPTION,
+ [ "List active processes." ]
+ }
+ ],
+ &command_plist,
+ },
+ //
+ // Shell
+ //
+ {
+ [ "help" ],
+ "Show help or a command's help article.",
+ [
+ "[ITEM]"
+ ],
+ MODULE_SHELL, CATEGORY_SHELL,
+ [
+
+ ],
+ &command_help,
+ },
+ {
+ [ "q", "quit" ],
+ "Quit shell session.",
+ [],
+ MODULE_SHELL, CATEGORY_SHELL,
+ [
+ {
+ SECTION_DESCRIPTION,
+ [ "Close the shell session along with the debugger and "~
+ "application if it was spawned using the debugger." ]
+ }
+ ],
+ &command_quit,
+ },
+];
+
+immutable(command2_t)* shell_findcommand(const(char) *ucommand) {
+debug { // Crash command
+ static immutable(command2_t) ucommand_crash = {
+ [ "crash" ],
+ null,
+ [],
+ null, null,
+ [],
+ &command_crash
+ };
+
+ if (strcmp(ucommand, ucommand_crash.names[0].ptr) == 0)
+ return &ucommand_crash;
+}
+ // NOTE: Can't use foreach for local var escape
+ for (size_t i; i < shell_commands.length; ++i) {
+ immutable(command2_t) *cmd = &shell_commands[i];
+
+ for (size_t c; c < cmd.names.length; ++c) {
+ if (strcmp(ucommand, cmd.names[c].ptr) == 0)
+ return cmd;
+ }
+ }
+
+ return null;
+}
+
+int shell_proc_spawn(const(char) *exec, const(char) **argv) {
+ // Save for restart
+ opt_file = exec;
+ opt_file_argv = argv;
+
+ // Spawn process
+ process = adbg_debugger_spawn(opt_file,
+ AdbgSpawnOpt.argv, argv,
+ 0);
+ if (process == null) {
+ return ShellError.alicedbg;
+ }
+
+ puts("Process created.");
+
+ // Open disassembler for process machine type
+ dis = adbg_dis_open(adbg_process_get_machine(process));
+ if (dis == null) {
+ logwarn("Disassembler not available (%s).", adbg_error_msg());
+ }
+
+ return 0;
+}
+
+int shell_proc_attach(int pid) {
+ // Save for restart
+ opt_pid = pid;
+
+ // Attach to process
+ process = adbg_debugger_attach(pid, 0);
+ if (process == null) {
+ return ShellError.alicedbg;
+ }
+
+ puts("Debugger attached.");
+
+ // Open disassembler for process machine type
+ dis = adbg_dis_open(adbg_process_get_machine(process));
+ if (dis) {
+ if (opt_syntax)
+ adbg_dis_options(dis, AdbgDisOpt.syntax, opt_syntax, 0);
+ } else {
+ printf("warning: Disassembler not available (%s)\n",
+ adbg_error_msg());
+ }
+
+ return 0;
+}
+
+void shell_event_disassemble(size_t address, int count = 1, bool showAddress = true) {
+ if (dis == null)
+ return;
+
+ enum MBUFSZ = 64; /// Machine string buffer size
+
+ ubyte[MAX_INSTR_SIZE] data = void;
+ char[MBUFSZ] machbuf = void;
+ for (int i; i < count; ++i) {
+ if (adbg_memory_read(process, address, data.ptr, MAX_INSTR_SIZE)) {
+ print_adbg_error();
+ return;
+ }
+ adbg_opcode_t op = void;
+ if (adbg_dis_once(dis, &op, data.ptr, MAX_INSTR_SIZE)) {
+ printf("%8llx (error:%s)\n", cast(ulong)address, adbg_error_msg);
+ return;
+ }
+
+ // Print address
+ if (showAddress)
+ printf("%8zx ", address);
+
+ // Print machine bytes into a dedicated buffer
+ size_t bo;
+ for (size_t bi; bi < op.size; ++bi) {
+ bo += snprintf(machbuf.ptr + bo, MBUFSZ - bo, " %02x", op.machine[bi]);
+ //printf(" %02x", op.machine[bi]);
+ }
+
+ // Print mnemonic & operands
+ printf("%s \t%s", machbuf.ptr, op.mnemonic);
+ if (op.operands)
+ printf(" %s", op.operands);
+
+ // Terminate line
+ putchar('\n');
+
+ address += op.size;
+ }
+}
+
+void shell_event_exception(adbg_exception_t *ex) {
+ printf("* Process %d (thread %d) stopped\n"~
+ " Reason : %s ("~ADBG_OS_ERROR_FORMAT~")\n",
+ ex.pid, ex.tid,
+ adbg_exception_name(ex), ex.oscode);
+
+ if (ex.faultz) {
+ printf(" Address : 0x%llx\n", ex.fault_address);
+
+ if (dis) {
+ printf(" Machine :");
+
+ // Print machine bytes
+ ubyte[MAX_INSTR_SIZE] data = void;
+ if (adbg_memory_read(process, ex.faultz, data.ptr, MAX_INSTR_SIZE)) {
+ printf(" read error (%s)\n", adbg_error_msg());
+ return; // Nothing else to do
+ }
+
+ adbg_opcode_t op = void;
+ if (adbg_dis_once(dis, &op, data.ptr, MAX_INSTR_SIZE)) {
+ printf(" disassembly error (%s)\n", adbg_error_msg());
+ return;
+ }
+
+ // Print machine bytes
+ for (size_t bi; bi < op.size; ++bi) {
+ printf(" %02x", op.machine[bi]);
+ }
+ putchar('\n');
+
+ // Print mnemonic
+ printf(" Mnemonic: %s", op.mnemonic);
+ if (op.operands)
+ printf(" %s", op.operands);
+ putchar('\n');
+ }
+ }
+}
+
+void shell_event_help(immutable(command2_t) *command) {
+ // Print header
+ int p = 34;
+ for (size_t i; i < command.names.length; ++i) {
+ if (i) {
+ printf(", ");
+ --p;
+ }
+ p -= printf("%s", command.names[i].ptr);
+ }
+ with (command) printf("%*s %*s\n\nNAME\n ", p, doc_module.ptr, 34, doc_category.ptr);
+ for (size_t i; i < command.names.length; ++i) {
+ if (i) putchar(',');
+ printf(" %s", command.names[i].ptr);
+ }
+ printf(" - %s\n", command.description.ptr);
+
+ if (command.synopsis.length) {
+ printf("\n%s\n", SECTION_SYNOPSIS.ptr);
+ foreach (s; command.synopsis) {
+ printf(" %s %s\n", command.names[$-1].ptr, s.ptr);
+ }
+ }
+
+ enum COL = 72;
+ foreach (section; command.doc_sections) {
+ printf("\n%s\n", section.name.ptr);
+
+ //TODO: Better cut-offs
+ // [0] spacing? remove
+ // [$-1] non-spacing? put dash
+ for (size_t i; i < section.bodies.length; ++i) {
+ const(char) *b = section.bodies[i].ptr;
+ if (i) putchar('\n');
+ LPRINT:
+ int o = printf(" %.*s\n", COL, b);
+ if (o < COL)
+ continue;
+ b += COL;
+ goto LPRINT;
+ }
+ }
+
+ putchar('\n');
+}
+
+debug
+int command_crash(int, const(char) **) {
+ void function() fnull;
+ fnull();
+ return 0;
+}
+
+int command_status(int argc, const(char) **argv) {
+ AdbgProcStatus state = adbg_process_status(process);
+ const(char) *m = void;
+ switch (state) with (AdbgProcStatus) {
+ case unloaded: m = "unloaded"; break;
+ case standby: m = "standby"; break;
+ case running: m = "running"; break;
+ case paused: m = "paused"; break;
+ default: m = "(unknown)";
+ }
+ puts(m);
+ return 0;
+}
+
+//TODO: List per category
+// Comparing could be per pointer or enum
+int command_help(int argc, const(char) **argv) {
+ if (argc > 1) { // Requesting help article for command
+ const(char) *ucommand = argv[1];
+ immutable(command2_t) *command = shell_findcommand(ucommand);
+ if (command == null) {
+ return ShellError.invalidParameter;
+ }
+
+ shell_event_help(command);
+ return 0;
+ }
+
+ enum PADDING = 20;
+ static immutable const(char) *liner = "..........................................";
+ foreach (cmd; shell_commands) {
+ int p;
+ for (size_t i; i < cmd.names.length; ++i) {
+ if (i) {
+ putchar(',');
+ ++p;
+ }
+ p += printf(" %s", cmd.names[i].ptr);
+ }
+
+ printf(" %.*s %s\n", PADDING - p, liner, cmd.description.ptr);
+ }
+
+ return 0;
+}
+
+int command_spawn(int argc, const(char) **argv) {
+ if (argc < 2) {
+ return ShellError.invalidParameter;
+ }
+
+ return shell_proc_spawn(argv[1], argc > 2 ? argv + 2: null);
+}
+
+int command_attach(int argc, const(char) **argv) {
+ if (argc < 2) {
+ return ShellError.invalidParameter;
+ }
+
+ return shell_proc_attach(atoi(argv[1]));
+}
+
+int command_detach(int argc, const(char) **argv) {
+ if (adbg_debugger_detach(process)) {
+ return ShellError.alicedbg;
+ }
+ adbg_dis_close(dis);
+ free(registers);
+
+ return 0;
+}
+
+int command_restart(int argc, const(char) **argv) {
+ int e;
+
+ switch (process.creation) with (AdbgCreation) {
+ case spawned:
+ // Terminate first, ignore on error (e.g., already gone)
+ adbg_debugger_terminate(process);
+
+ // Spawn, shell still messages status
+ e = shell_proc_spawn(opt_file, opt_file_argv);
+ break;
+ case attached:
+ // Detach first, ignore on error (e.g., already detached)
+ adbg_debugger_detach(process);
+
+ // Attach, shell still messages status
+ e = shell_proc_attach(opt_pid);
+ break;
+ default:
+ return ShellError.unattached;
+ }
+
+ return e;
+}
+
+int command_go(int argc, const(char) **argv) {
+ if (adbg_debugger_continue(process))
+ return ShellError.alicedbg;
+ if (adbg_debugger_wait(process, &shell_event_exception))
+ return ShellError.alicedbg;
+ // Temporary: Cheap hack for process exit
+ if (adbg_process_status(process) == AdbgProcStatus.unloaded)
+ printf("*\tProcess %d exited\n", process.pid);
+ return 0;
+}
+
+int command_kill(int argc, const(char) **argv) {
+ if (adbg_debugger_terminate(process))
+ return ShellError.alicedbg;
+ puts("Process killed");
+ adbg_dis_close(dis);
+ free(registers);
+ return 0;
+}
+
+int command_stepi(int argc, const(char) **argv) {
+ if (adbg_debugger_stepi(process))
+ return ShellError.alicedbg;
+ if (adbg_debugger_wait(process, &shell_event_exception))
+ return ShellError.alicedbg;
+ return 0;
+}
+
+int command_regs(int argc, const(char) **argv) {
+ if (process == null)
+ return ShellError.pauseRequired;
+
+ if (registers == null) {
+ registers = adbg_registers_new(adbg_process_get_machine(process));
+ if (registers == null)
+ return ShellError.alicedbg;
+ }
+
+ adbg_registers_fill(registers, process);
+
+ if (registers.count == 0) {
+ logerror("No registers available");
+ return ShellError.unavailable;
+ }
+
+ adbg_register_t *reg = registers.items.ptr;
+ const(char) *rselect = argc >= 2 ? argv[1] : null;
+ bool found;
+ for (size_t i; i < registers.count; ++i, ++reg) {
+ bool show = rselect == null || strcmp(rselect, reg.info.name) == 0;
+ if (show == false) continue;
+ char[20] normal = void, hexdec = void;
+ adbg_register_format(normal.ptr, 20, reg, AdbgRegFormat.dec);
+ adbg_register_format(hexdec.ptr, 20, reg, AdbgRegFormat.hexPadded);
+ printf("%-8s 0x%8s %s\n", reg.info.name, hexdec.ptr, normal.ptr);
+ found = true;
+ }
+ if (rselect && found == false) {
+ logerror("Register not found");
+ return ShellError.invalidParameter;
+ }
+ return 0;
+}
+
+int command_memory(int argc, const(char) **argv) {
+ if (argc < 2) {
+ return ShellError.missingOption;
+ }
+
+ long uaddress = void;
+ if (unformat64(&uaddress, argv[1]))
+ return ShellError.unformat;
+
+ int ulength = 64;
+ if (argc >= 3) {
+ if (unformat(&ulength, argv[2]))
+ return ShellError.unformat;
+ if (ulength <= 0)
+ return 0;
+ }
+
+ ubyte *data = cast(ubyte*)malloc(ulength);
+ if (data == null)
+ return ShellError.crt;
+
+ if (adbg_memory_read(process, cast(size_t)uaddress, data, ulength))
+ return ShellError.alicedbg;
+
+ enum COLS = 16; /// Columns in bytes
+ enum PADD = 12; /// Address padding
+
+ // Print column header
+ for (int c; c < PADD; ++c)
+ putchar(' ');
+ putchar(' ');
+ putchar(' ');
+ for (int c; c < COLS; ++c)
+ printf("%2x ", cast(uint)c);
+ putchar('\n');
+
+ // Print data rows
+ size_t count = ulength / COLS;
+ for (size_t c; c < count; ++c, uaddress += COLS) {
+ // Print address
+ printf("%.*llx ", PADD, uaddress);
+
+ // Print data column
+ for (size_t i; i < COLS && c * i < ulength; ++i)
+ printf("%02x ", data[(c * COLS) + i]);
+
+ // Print ascii column
+ putchar(' ');
+ for (size_t i; i < COLS && c * i < ulength; ++i)
+ putchar(asciichar(data[(c * COLS) + i], '.'));
+
+ putchar('\n');
+ }
+
+ return 0;
+}
+
+//TODO: optional arg: filter module by name (contains string)
+//TODO: max count to show or option to filter modules out
+int command_maps(int argc, const(char) **argv) {
+ adbg_memory_map_t *mmaps = void;
+ size_t mcount = void;
+
+ if (adbg_memory_maps(process, &mmaps, &mcount, 0))
+ return ShellError.alicedbg;
+
+ puts("Region Size T Perm File");
+ for (size_t i; i < mcount; ++i) {
+ adbg_memory_map_t *map = &mmaps[i];
+
+ char[4] perms = void;
+ perms[0] = map.access & AdbgMemPerm.read ? 'r' : '-';
+ perms[1] = map.access & AdbgMemPerm.write ? 'w' : '-';
+ perms[2] = map.access & AdbgMemPerm.exec ? 'x' : '-';
+ perms[3] = map.access & AdbgMemPerm.private_ ? 'p' : 's';
+
+ char t = void;
+ switch (map.type) {
+ case AdbgPageUse.resident: t = 'R'; break;
+ case AdbgPageUse.fileview: t = 'F'; break;
+ case AdbgPageUse.module_: t = 'M'; break;
+ default: t = '?';
+ }
+
+ with (map) printf("%16zx %10zd %c %.4s %s\n",
+ cast(size_t)base, size, t, perms.ptr, name.ptr);
+ }
+
+ free(mmaps);
+ return 0;
+}
+
+//TODO: start,+length start,end syntax
+int command_disassemble(int argc, const(char) **argv) {
+ if (process == null)
+ return ShellError.unattached;
+ if (dis == null)
+ return ShellError.unavailable;
+ if (argc < 2)
+ return ShellError.missingOption;
+
+ long uaddress = void;
+ if (unformat64(&uaddress, argv[1]))
+ return ShellError.unformat;
+
+ int ucount = 1;
+ if (argc >= 3) {
+ if (unformat(&ucount, argv[2]))
+ return ShellError.unformat;
+ if (ucount <= 0)
+ return 0;
+ }
+ if (ucount < 1) {
+ return ShellError.invalidCount;
+ }
+
+ shell_event_disassemble(cast(size_t)uaddress, ucount);
+ return 0;
+}
+
+size_t last_scan_size;
+ulong last_scan_data;
+adbg_scan_t *last_scan;
+
+void shell_event_list_scan_results() {
+ // super lazy hack
+ long mask = void;
+ switch (last_scan_size) {
+ case 8: mask = 0; break;
+ case 7: mask = 0xff_ffff_ffff_ffff; break;
+ case 6: mask = 0xffff_ffff_ffff; break;
+ case 5: mask = 0xff_ffff_ffff; break;
+ case 4: mask = 0xffff_ffff; break;
+ case 3: mask = 0xff_ffff; break;
+ case 2: mask = 0xffff; break;
+ case 1: mask = 0xff; break;
+ default:
+ puts("fatal: mask fail");
+ return;
+ }
+ // 0000. ffffffffffffffff 18446744073709551615
+ puts("No. Address Previous Current");
+ adbg_scan_result_t *result = last_scan.results;
+ uint count = cast(uint)last_scan.result_count + 1; // temp cast until better z printf
+ for (uint i = 1; i < count; ++i, ++result) {
+ printf("%4u. %-16llx %*llu ", i, result.address, -20, result.value_u64 & mask);
+ ulong udata = void;
+ if (adbg_memory_read(process, cast(size_t)result.address, &udata, cast(uint)last_scan_size))
+ puts("???");
+ else
+ printf("%llu\n", udata & mask);
+ }
+}
+
+int command_scan(int argc, const(char) **argv) {
+ if (argc < 2)
+ return ShellError.scanMissingType;
+
+ const(char) *usub = argv[1];
+
+ if (strcmp(usub, "show") == 0) {
+ if (last_scan == null)
+ return ShellError.scanNoScan;
+
+ shell_event_list_scan_results;
+ return 0;
+ } else if (strcmp(usub, "reset") == 0) {
+ if (last_scan == null)
+ return 0;
+
+ adbg_memory_scan_close(last_scan);
+ last_scan = null;
+ return 0;
+ }
+
+ if (argc < 3)
+ return ShellError.scanMissingValue;
+
+ const(char) *uin = argv[2];
+
+ union u {
+ long data64;
+ int data;
+ }
+ u user = void;
+ if (strcmp(usub, "byte") == 0) {
+ last_scan_size = ubyte.sizeof;
+ if (unformat(&user.data, uin))
+ return ShellError.unformat;
+ if (user.data > ubyte.max)
+ return ShellError.scanInputOutOfRange;
+ } else if (strcmp(usub, "short") == 0) {
+ last_scan_size = short.sizeof;
+ if (unformat(&user.data, uin))
+ return ShellError.unformat;
+ if (user.data > short.max)
+ return ShellError.scanInputOutOfRange;
+ } else if (strcmp(usub, "int") == 0) {
+ last_scan_size = int.sizeof;
+ if (unformat(&user.data, uin))
+ return ShellError.unformat;
+ } else if (strcmp(usub, "long") == 0) {
+ last_scan_size = long.sizeof;
+ if (unformat64(&user.data64, uin))
+ return ShellError.unformat;
+ } else
+ return ShellError.scanInvalidSubCommand;
+
+ if (last_scan)
+ adbg_memory_scan_close(last_scan);
+
+ last_scan_data = user.data64;
+
+ if ((last_scan = adbg_memory_scan(process, &user, last_scan_size,
+ AdbgScanOpt.capacity, 100,
+ 0)) == null)
+ return ShellError.alicedbg;
+
+ printf("Scan completed with %u results.\n", cast(uint)last_scan.result_count);
+ return 0;
+}
+
+int command_rescan(int argc, const(char) **argv) {
+ if (argc < 2)
+ return ShellError.scanMissingType;
+ if (argc < 3)
+ return ShellError.scanMissingValue;
+
+ const(char) *usub = argv[1];
+ const(char) *uin = argv[2];
+
+ union u {
+ long data64;
+ int data;
+ }
+ u user = void;
+ if (strcmp(usub, "byte") == 0) {
+ last_scan_size = ubyte.sizeof;
+ if (unformat(&user.data, uin))
+ return ShellError.unformat;
+ if (user.data > ubyte.max)
+ return ShellError.scanInputOutOfRange;
+ } else if (strcmp(usub, "short") == 0) {
+ last_scan_size = short.sizeof;
+ if (unformat(&user.data, uin))
+ return ShellError.unformat;
+ if (user.data > short.max)
+ return ShellError.scanInputOutOfRange;
+ } else if (strcmp(usub, "int") == 0) {
+ last_scan_size = int.sizeof;
+ if (unformat(&user.data, uin))
+ return ShellError.unformat;
+ } else if (strcmp(usub, "long") == 0) {
+ last_scan_size = long.sizeof;
+ if (unformat64(&user.data64, uin))
+ return ShellError.unformat;
+ } else
+ return ShellError.scanInvalidSubCommand;
+
+ if (adbg_memory_rescan(last_scan, &user, last_scan_size))
+ return ShellError.alicedbg;
+
+ last_scan_data = user.data64;
+
+ printf("Scan completed with %u results.\n", cast(uint)last_scan.result_count);
+ return 0;
+}
+
+int command_plist(int argc, const(char) **argv) {
+ // Disabled until adbg_process_get_name works on Windows
+version (UseNewProcessName) {
+ size_t count = void;
+ int *plist = adbg_process_list(&count, 0);
+ if (plist == null)
+ return ShellError.alicedbg;
+
+ enum BUFFERSIZE = 2048;
+ char[BUFFERSIZE] buffer = void;
+
+ version (Trace)
+ trace("count=%zd", count);
+
+ puts("PID Name");
+ foreach (int pid; plist[0..count]) {
+ printf("%10d ", pid);
+ if (adbg_process_get_name(pid, buffer.ptr, BUFFERSIZE, true)) {
+ puts(buffer.ptr);
+ continue;
+ }
+ if (adbg_process_get_name(pid, buffer.ptr, BUFFERSIZE, false)) {
+ puts(buffer.ptr);
+ continue;
+ }
+ version (Trace)
+ trace("error: %s", adbg_error_msg());
+ putchar('\n');
+ }
+
+ free(plist);
+} else {
+ adbg_process_list_t list = void;
+ if (adbg_process_enumerate(&list, 0)) {
+ return ShellError.alicedbg;
+ }
+
+ puts("PID Name");
+ foreach (adbg_process_t proc; list.processes[0..list.count]) {
+ printf("%10d %s\n", proc.pid, proc.name.ptr);
+ }
+}
+
+ return 0;
+}
+
+int command_quit(int argc, const(char) **argv) {
+ //TODO: Quit confirmation if debuggee is alive
+ // could do with optional "forced yes" type of optional
+ exit(0);
+ return 0;
+}
\ No newline at end of file
diff --git a/debugger/term.d b/debugger/term.d
new file mode 100644
index 0000000..e3cbf24
--- /dev/null
+++ b/debugger/term.d
@@ -0,0 +1,547 @@
+/// In-house console/terminal library
+///
+/// Authors: dd86k
+/// Copyright: © dd86k
+/// License: BSD-3-Clause-Clear
+module term;
+
+import core.stdc.stdlib;
+import core.stdc.stdio;
+
+//TODO: Consider using PDCurses instead
+
+// NOTE: Functions prefixed with "con" to avoid clashing with the "tc" POSIX stuff
+
+extern (C):
+
+private int putchar(int);
+private int getchar();
+
+version (Windows) {
+ private import core.sys.windows.windows;
+ private enum ALT_PRESSED = RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED;
+ private enum CTRL_PRESSED = RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED;
+ private __gshared HANDLE handleIn, handleOut, handleOld;
+} else version (Posix) {
+ private import core.sys.posix.sys.ioctl;
+ private import core.sys.posix.unistd;
+ private import core.sys.posix.termios;
+ private import core.sys.posix.signal;
+ private import core.sys.posix.ucontext;
+
+ version (CRuntime_Musl) {
+ alias uint tcflag_t;
+ alias uint speed_t;
+ alias char cc_t;
+ private enum TCSANOW = 0;
+ private enum NCCS = 32;
+ private enum ICANON = 2;
+ private enum ECHO = 10;
+ private enum TIOCGWINSZ = 0x5413;
+ private struct termios {
+ tcflag_t c_iflag;
+ tcflag_t c_oflag;
+ tcflag_t c_cflag;
+ tcflag_t c_lflag;
+ cc_t c_line;
+ cc_t[NCCS] c_cc;
+ speed_t __c_ispeed;
+ speed_t __c_ospeed;
+ }
+ private struct winsize {
+ ushort ws_row;
+ ushort ws_col;
+ ushort ws_xpixel;
+ ushort ws_ypixel;
+ }
+ private int tcgetattr(int fd, termios *termios_p);
+ private int tcsetattr(int fd, int a, termios *termios_p);
+ private int ioctl(int fd, ulong request, ...);
+ }
+ version (CRuntime_Bionic) {
+ private int tcgetattr(int __fd, termios* __t);
+ private int tcsetattr(int __fd, int __optional_actions, termios* __t);
+ }
+
+ private enum TERM_ATTR = ~(ICANON | ECHO);
+ private enum SIGWINCH = 28;
+ private __gshared termios old_tio = void, new_tio = void;
+}
+
+// Flags: CONFxyz
+
+private __gshared {
+ /// User defined function for resize events
+ void function(ushort,ushort) term_resize_handler;
+ int term_opts; // default to 0
+}
+
+//
+// ANCHOR Initiation
+//
+
+/// Initiates terminal basics
+/// Returns: Error keyCode, non-zero on error
+int coninit(int flags = 0) {
+version (Posix) {
+ tcgetattr(STDIN_FILENO, &old_tio);
+ new_tio = old_tio;
+ new_tio.c_lflag &= TERM_ATTR;
+
+ //TODO: See flags we can put
+ // tty_ioctl TIOCSETD
+} else {
+ handleOut = GetStdHandle(STD_OUTPUT_HANDLE);
+ handleIn = GetStdHandle(STD_INPUT_HANDLE);
+
+ // Disable annoying mouse mode.
+ DWORD mode = void;
+ GetConsoleMode(handleIn, &mode);
+ mode &= ~ENABLE_MOUSE_INPUT;
+ SetConsoleMode(handleIn, mode);
+}
+ return 0;
+}
+
+// Invert console color with defaultColor
+/*void thcolin() {
+ version (Windows)
+ SetConsoleTextAttribute(hOut, COMMON_LVB_REVERSE_VIDEO | defaultColor);
+ version (Posix)
+ fputs("\033[7m", stdout);
+}
+
+// Reset console color to defaultColor
+void thcolrst() {
+ version (Windows)
+ SetConsoleTextAttribute(hOut, defaultColor);
+ version (Posix)
+ fputs("\033[0m", stdout);
+}*/
+
+/// Clear screen
+void conclear() {
+version (Windows) {
+ CONSOLE_SCREEN_BUFFER_INFO csbi = void;
+ COORD c; // 0, 0
+ GetConsoleScreenBufferInfo(handleOut, &csbi);
+ //const int buflen = csbi.dwSize.X * csbi.dwSize.Y; buf buflen
+ const int buflen = // window buflen
+ (csbi.srWindow.Right - csbi.srWindow.Left + 1)* // width
+ (csbi.srWindow.Bottom - csbi.srWindow.Top + 1); // height
+ DWORD num = void; // kind of ala .NET
+ FillConsoleOutputCharacterA(handleOut, ' ', buflen, c, &num);
+ FillConsoleOutputAttribute(handleOut, csbi.wAttributes, buflen, c, &num);
+ conmvcur(0, 0);
+} else version (Posix) {
+ // "ESC [ 2 J" acts like clear(1)
+ // "ESC c" is a full reset ala cls (Windows)
+ printf("\033c");
+}
+else static assert(false, "Not implemented");
+}
+
+/// Get host console screen size.
+/// Params:
+/// w = Width (columns) pointer.
+/// h = Height (rows) pointer.
+void consize(int *w, int *h) {
+ /// NOTE: A COORD uses SHORT (short) and Linux uses unsigned shorts.
+version (Windows) {
+ CONSOLE_SCREEN_BUFFER_INFO c = void;
+ GetConsoleScreenBufferInfo(handleOut, &c);
+ *w = c.srWindow.Right - c.srWindow.Left + 1;
+ *h = c.srWindow.Bottom - c.srWindow.Top + 1;
+} else version (Posix) {
+ winsize win = void;
+ ioctl(STDOUT_FILENO, TIOCGWINSZ, &win);
+ *w = win.ws_col;
+ *h = win.ws_row;
+}
+}
+
+/// Set cursor position.
+///
+/// Coordonates start at zero.
+/// Params:
+/// x = X position (horizontal, columns)
+/// y = Y position (vertical, rows)
+void conmvcur(int x, int y) {
+version (Windows) { // 0-based
+ COORD c = { cast(SHORT)x, cast(SHORT)y };
+ SetConsoleCursorPosition(handleOut, c);
+} else version (Posix) { // 1-based
+ printf("\033[%d;%dH", y + 1, x + 1);
+}
+}
+
+/// Get cursor position.
+///
+/// Coordonates start at zero.
+/// Params:
+/// x = X position (horizontal, columns)
+/// y = Y position (vertical, rows)
+void congetxy(int *x, int *y) {
+version (Windows) { // 0-based
+ CONSOLE_SCREEN_BUFFER_INFO csbi = void;
+ GetConsoleScreenBufferInfo(handleOut, &csbi);
+ *x = csbi.dwCursorPosition.X;
+ *y = csbi.dwCursorPosition.Y;
+} else version (Posix) { // 1-based
+ tcsetattr(STDIN_FILENO, TCSANOW, &new_tio);
+ printf("\033[6n");
+ scanf("\033[%d;%dR", y, x); // row, col
+ tcsetattr(STDIN_FILENO, TCSANOW, &old_tio);
+ --*x;
+ --*y;
+}
+}
+
+//
+// ANCHOR Terminal input
+//
+
+/// Read a single immediate terminal/console event such as a keyboard or mouse.
+///
+/// Window resize events are handled externally.
+/// Windows: User handler function called if EventType is WINDOW_BUFFER_SIZE_EVENT.
+/// Posix: Handled externally via the SIGWINCH signal.
+/// Params: ii = InputInfo structure
+void conrdkey(InputInfo *ii) {
+ ii.type = InputType.None;
+version (Windows) {
+ INPUT_RECORD ir = void;
+ DWORD d = void;
+L_READ_AGAIN:
+ if (ReadConsoleInput(handleIn, &ir, 1, &d) == FALSE)
+ return;
+
+ switch (ir.EventType) {
+ case KEY_EVENT:
+ if (ir.KeyEvent.bKeyDown == FALSE)
+ goto L_READ_AGAIN;
+
+ with (ii) {
+ type = InputType.Key;
+ const DWORD state = ir.KeyEvent.dwControlKeyState;
+ key.alt = (state & ALT_PRESSED) != 0;
+ key.ctrl = (state & CTRL_PRESSED) != 0;
+ key.shift = (state & SHIFT_PRESSED) != 0;
+ key.keyChar = ir.KeyEvent.AsciiChar;
+ key.keyCode = key.ctrl ?
+ cast(Key)ir.KeyEvent.AsciiChar :
+ cast(Key)ir.KeyEvent.wVirtualKeyCode;
+ }
+ break;
+ case MOUSE_EVENT: //TODO: MOUSE_EVENT
+ ii.type = InputType.Mouse;
+ break;
+ case WINDOW_BUFFER_SIZE_EVENT:
+ with (ir)
+ if (term_resize_handler)
+ term_resize_handler(
+ WindowBufferSizeEvent.dwSize.X,
+ WindowBufferSizeEvent.dwSize.Y);
+ FlushConsoleInputBuffer(handleIn);
+ break;
+ default: // Menu and Focus events
+ goto L_READ_AGAIN;
+ }
+} else version (Posix) {
+ //TODO: Get modifier keys states
+ //TODO: See console_ioctl for KDGETKEYCODE
+ // https://linux.die.net/man/4/console_ioctl
+
+ ii.type = InputType.Key;
+
+ tcsetattr(STDIN_FILENO, TCSANOW, &new_tio);
+ scope(exit) tcsetattr(STDIN_FILENO, TCSANOW, &old_tio);
+
+ uint c = getchar;
+
+ with (ii.key)
+ switch (c) {
+ case 0: keyCode = Key.Null; return;
+ case 1: keyCode = Key.HeadingStart; return;
+ case 2: keyCode = Key.TextStart; return;
+ case 3: /* ^C */ keyCode = Key.TextEnd; return;
+ case 4: /* ^D */ keyCode = Key.TransmissionEnd; return;
+ case 5: keyCode = Key.Enquiry; return;
+ case 6: keyCode = Key.Acknowledge; return;
+ case 7: keyCode = Key.Bell; return;
+ case '\n', '\r': // \n (RETURN) or \r (ENTER)
+ keyCode = Key.Enter;
+ return;
+ case 27: // ESC
+ switch (c = getchar) {
+ case '[':
+ switch (c = getchar) {
+ case 'A': keyCode = Key.UpArrow; return;
+ case 'B': keyCode = Key.DownArrow; return;
+ case 'C': keyCode = Key.RightArrow; return;
+ case 'D': keyCode = Key.LeftArrow; return;
+ case 'F': keyCode = Key.End; return;
+ case 'H': keyCode = Key.Home; return;
+ // There is an additional getchar due to the pending '~'
+ case '2': keyCode = Key.Insert; getchar; return;
+ case '3': keyCode = Key.Delete; getchar; return;
+ case '5': keyCode = Key.PageUp; getchar; return;
+ case '6': keyCode = Key.PageDown; getchar; return;
+ default: goto L_DEFAULT;
+ } // [
+ default: goto L_DEFAULT;
+ } // ESC
+ case 0x08, 0x7F: // backspace
+ keyCode = Key.Backspace;
+ return;
+ case 23: // #
+ keyCode = Key.NumSign;
+ keyChar = '#';
+ return;
+ default:
+ if (c >= 'a' && c <= 'z') {
+ keyCode = cast(Key)(c - 32);
+ keyChar = cast(char)c;
+ return;
+ } else if (c >= 20 && c <= 126) {
+ keyCode = cast(Key)c;
+ keyChar = cast(char)c;
+ return;
+ }
+ }
+
+L_DEFAULT:
+ ii.key.keyCode = cast(Key)c;
+} // version (Posix)
+}
+
+/// Read a line from stdin.
+/// Returns: Character slice; Or null on error.
+char[] conrdln() {
+ import core.stdc.ctype : isprint;
+
+ // GNU readline has this set to 512
+ enum BUFFERSIZE = 1024;
+
+ __gshared char* buffer;
+
+ if (buffer == null) {
+ buffer = cast(char*)malloc(BUFFERSIZE);
+ if (buffer == null)
+ return null;
+ }
+
+ // NOTE: stdin is line-buffered by the host console in their own buffer.
+ // Hitting return or enter makes the console write its buffer to stdin.
+ // Reading stdin, we copy until we see a newline.
+ size_t len;
+ while (len < BUFFERSIZE) {
+ int c = getchar();
+ if (c == '\n' || c == EOF)
+ break;
+ buffer[len++] = cast(char)c;
+ }
+ buffer[len] = 0;
+ return buffer[0..len];
+}
+
+/// Key information structure
+struct KeyInfo {
+ Key keyCode; /// Key keyCode.
+ char keyChar; /// Character.
+ bool ctrl; /// If either CTRL was held down.
+ bool alt; /// If either ALT was held down.
+ bool shift; /// If SHIFT was held down.
+}
+/// Mouse input event structure
+struct MouseInfo {
+ ushort x, y;
+}
+/// Global input event structure
+struct InputInfo {
+ InputType type; /// Input event type, can only be mouse or key
+ union {
+ KeyInfo key; /// Keyboard event structure
+ MouseInfo mouse; /// Mouse event structure
+ }
+}
+
+/// Input type for InputInfo structure
+enum InputType : ushort {
+ None, Key, Mouse
+}
+/*
+enum MouseButton : ushort { // Windows compilant
+ Left = 1, Right = 2, Middle = 4, Mouse4 = 8, Mouse5 = 16
+}
+
+enum MouseState : ushort { // Windows compilant
+ RightAlt = 1, LeftAlt = 2, RightCtrl = 4,
+ LeftCtrl = 8, Shift = 0x10, NumLock = 0x20,
+ ScrollLock = 0x40, CapsLock = 0x80, EnhancedKey = 0x100
+}
+
+enum MouseEventType { // Windows compilant
+ Moved = 1, DoubleClick = 2, Wheel = 4, HorizontalWheel = 8
+}
+*/
+/// Key codes mapping.
+//TODO: Redo keycodes
+// < 128: ascii map
+// >=128: special codes (e.g., arrow keys)
+enum Key : short {
+ Null = 0, /// ^@, NUL
+ HeadingStart = 1, // ^A, SOH
+ TextStart = 2, /// ^B, STX
+ TextEnd = 3, /// ^C, ETX
+ TransmissionEnd = 4, /// ^D, EOT
+ Enquiry = 5, /// ^E, ENQ
+ Acknowledge = 6, /// ^F, ACK
+ Bell = 7, /// ^G, BEL
+ Backspace = 8, /// ^H, BS
+ Tab = 9, /// ^I, HT
+ LineFeed = 10, /// ^J, LF
+ VerticalTab = 11, /// ^K, VT
+ FormFeed = 12, /// ^L, FF
+ Enter = 13, /// ^M, CR (return key)
+ Pause = 19,
+ Escape = 27,
+ Spacebar = 32,
+ PageUp = 33,
+ PageDown = 34,
+ End = 35,
+ Home = 36,
+ LeftArrow = 37,
+ UpArrow = 38,
+ RightArrow = 39,
+ DownArrow = 40,
+ Select = 41,
+ Print = 42,
+ Execute = 43,
+ PrintScreen = 44,
+ Insert = 45,
+ Delete = 46,
+ Help = 47,
+ D0 = 48,
+ D1 = 49,
+ D2 = 50,
+ D3 = 51,
+ D4 = 52,
+ D5 = 53,
+ D6 = 54,
+ D7 = 55,
+ D8 = 56,
+ D9 = 57,
+ A = 65,
+ B = 66,
+ C = 67,
+ D = 68,
+ E = 69,
+ F = 70,
+ G = 71,
+ H = 72,
+ I = 73,
+ J = 74,
+ K = 75,
+ L = 76,
+ M = 77,
+ N = 78,
+ O = 79,
+ P = 80,
+ Q = 81,
+ R = 82,
+ S = 83,
+ T = 84,
+ U = 85,
+ V = 86,
+ W = 87,
+ X = 88,
+ Y = 89,
+ Z = 90,
+ LeftMeta = 91,
+ RightMeta = 92,
+ Applications = 93,
+ Sleep = 95,
+ NumPad0 = 96,
+ NumPad1 = 97,
+ NumPad2 = 98,
+ NumPad3 = 99,
+ NumPad4 = 100,
+ NumPad5 = 101,
+ NumPad6 = 102,
+ NumPad7 = 103,
+ NumPad8 = 104,
+ NumPad9 = 105,
+ Multiply = 106,
+ Add = 107,
+ Separator = 108,
+ Subtract = 109,
+ Decimal = 110,
+ Divide = 111,
+ F1 = 112,
+ F2 = 113,
+ F3 = 114,
+ F4 = 115,
+ F5 = 116,
+ F6 = 117,
+ F7 = 118,
+ F8 = 119,
+ F9 = 120,
+ F10 = 121,
+ F11 = 122,
+ F12 = 123,
+ F13 = 124,
+ F14 = 125,
+ F15 = 126,
+ F16 = 127,
+ F17 = 128,
+ F18 = 129,
+ F19 = 130,
+ F20 = 131,
+ F21 = 132,
+ F22 = 133,
+ F23 = 134,
+ F24 = 135,
+ BrowserBack = 166,
+ BrowserForward = 167,
+ BrowserRefresh = 168,
+ BrowserStop = 169,
+ BrowserSearch = 170,
+ BrowserFavorites = 171,
+ BrowserHome = 172,
+ VolumeMute = 173,
+ VolumeDown = 174,
+ VolumeUp = 175,
+ MediaNext = 176,
+ MediaPrevious = 177,
+ MediaStop = 178,
+ MediaPlay = 179,
+ LaunchMail = 180,
+ LaunchMediaSelect = 181,
+ LaunchApp1 = 182,
+ LaunchApp2 = 183,
+ Oem1 = 186,
+ OemPlus = 187,
+ OemComma = 188,
+ OemMinus = 189,
+ OemPeriod = 190,
+ Oem2 = 191,
+ Oem3 = 192,
+ Oem4 = 219,
+ Oem5 = 220,
+ Oem6 = 221,
+ Oem7 = 222,
+ Oem8 = 223,
+ Oem102 = 226,
+ Process = 229,
+ Packet = 231,
+ Attention = 246,
+ CrSel = 247,
+ ExSel = 248,
+ EraseEndOfFile = 249,
+ Play = 250,
+ Zoom = 251,
+ NumSign = 252, /// #
+ Pa1 = 253,
+ OemClear = 254
+}
\ No newline at end of file
diff --git a/dub.sdl b/dub.sdl
index 6181075..1f13628 100644
--- a/dub.sdl
+++ b/dub.sdl
@@ -8,6 +8,7 @@
# NOTE: BetterC flag
# We explicitly specify the betterC flag to support older DUB releases
# Like v0.9.24
+
# NOTE: GDC 5.4
# Doesn't work, ld whines about missing _tlsstart/_tlsend (TLS) references
# value for C++/ObjC but not D:
@@ -18,6 +19,7 @@
# -fno-switch-errors: not a command-line option
# -nophoboslib: makes the linker complain more
# Tried with "-fno-moduleinfo" "-fno-emit-moduleinfo"
+
# NOTE: GDC and betterC
# Currently (even with GDC 10.3), when compiled with -fno-druntime
# (similar to -betterC), the linker will whine about an undefined reference
@@ -25,10 +27,16 @@
# Glibc (and subsequently, GCC) has a similiar function,
# __gcc_personality_v0, that is served when unwinding the stack, so to
# handle exceptions.
+
# NOTE: GDC 11.1 and betterC
# Yes, it works with -fno-druntime, so it can be possible to add
# -gdc-betterc build types in the future.
+# NOTE: Configurations and Sub-Packages
+# Sub-packages do not take build type options from root dub file.
+# But since configurations do, they are defined here, this is important
+# because on the reliance on betterC.
+
#TODO: Make docs/ddox builds only peek in src/
# Works with -c library
@@ -36,13 +44,32 @@
# ANCHOR Configurations
#
-# Not a subPackage because I want to avoid generating a seperate library
-configuration "application" {
+# Debugger applicaton
+configuration "debugger" {
targetType "executable"
- sourcePaths "app"
- importPaths "app"
- mainSourceFile "app/main.d"
+ targetName "alicedbg"
+ sourcePaths "debugger" "common"
+ importPaths "debugger" "common"
+ mainSourceFile "debugger/main.d"
}
+
+# Dumper application
+configuration "dumper" {
+ targetType "executable"
+ targetName "alicedump"
+ sourcePaths "dumper" "common"
+ importPaths "dumper" "common"
+ mainSourceFile "dumper/main.d"
+}
+
+# Simple example application
+configuration "simple" {
+ targetType "executable"
+ targetName "simple"
+ mainSourceFile "examples/simple.d"
+}
+
+# Library
configuration "library" {
sourcePaths "src"
}
@@ -176,32 +203,4 @@
buildRequirements "allowWarnings"
buildOptions "syntaxOnly"
dflags "-Dddocs" "-Df__dummy.html" "-Xfdocs.json"
-}
-
-#
-# ANCHOR Examples
-#
-
-subPackage {
- name "simple-legacy"
- targetType "executable"
- targetName "simple-legacy"
- sourcePaths "src"
- importPaths "src"
- mainSourceFile "examples/simple-legacy.d"
- dflags "-betterC" "-vgc" "-vtls" platform="dmd"
- dflags "-betterC" "--vgc" platform="ldc"
- dflags "-ftransition=nogc" "-ftransition=tls" platform="gdc"
-}
-
-subPackage {
- name "simple"
- targetType "executable"
- targetName "simple"
- sourcePaths "src"
- importPaths "src"
- mainSourceFile "examples/simple.d"
- dflags "-betterC" "-vgc" "-vtls" platform="dmd"
- dflags "-betterC" "--vgc" platform="ldc"
- dflags "-ftransition=nogc" "-ftransition=tls" platform="gdc"
}
\ No newline at end of file
diff --git a/dumper/dumper.d b/dumper/dumper.d
new file mode 100644
index 0000000..293fcaf
--- /dev/null
+++ b/dumper/dumper.d
@@ -0,0 +1,468 @@
+/// Image/object dumper, imitates objdump
+///
+/// Authors: dd86k
+/// Copyright: © dd86k
+/// License: BSD-3-Clause-Clear
+module dumper;
+
+import adbg.error, adbg.disassembler, adbg.object;
+import adbg.include.c.stdio;
+import adbg.include.c.stdlib : EXIT_SUCCESS, EXIT_FAILURE, malloc, free;
+import adbg.include.c.stdarg;
+import adbg.machines;
+import adbg.utils.bit : BIT;
+import core.stdc.string;
+import core.stdc.ctype : isprint;
+import core.stdc.errno;
+import format;
+import common.error;
+import common.cli : opt_machine, opt_syntax;
+import common.utils;
+
+extern (C):
+__gshared:
+
+enum Select {
+ headers = BIT!0,
+ /// Sections
+ sections = BIT!1,
+ /// Relocations
+ relocs = BIT!2,
+ /// Exported/dynamic symbols
+ exports = BIT!3,
+ /// Import symbols
+ imports = BIT!4,
+ /// Resources
+ rsrc = BIT!5,
+ /// Debug info
+ debug_ = BIT!6,
+
+ // Source
+// source =
+
+ /// PE32 directories
+ dirs = BIT!24,
+ /// PE32 load configuration
+ loadcfg = BIT!25,
+
+ ///
+ all = 0xffff_ffff,
+}
+enum Setting {
+ /// Input file or data is blob
+ blob = BIT!0,
+ /// Dump binary information as hex dump
+ hexdump = BIT!1,
+ /// Extract binary information into stdout
+ extract = BIT!2,
+ /// Disassemble selections (executable sections)
+ disasm = BIT!24,
+ /// Disassemble selections (all sections)
+ disasmAll = BIT!25,
+ /// Output disassembly statistics (sections)
+ disasmStats = BIT!26,
+
+ /// Any disassembly is requested
+ disasmAny = disasm | disasmAll | disasmStats,
+}
+
+const(char)* opt_file;
+int opt_selected;
+int opt_settings;
+const(char)* opt_section;
+long opt_baseaddress;
+
+int selected_headers() { return opt_selected & Select.headers; }
+int selected_sections() { return opt_selected & Select.sections; }
+int selected_relocs() { return opt_selected & Select.relocs; }
+int selected_exports() { return opt_selected & Select.exports; }
+int selected_imports() { return opt_selected & Select.imports; }
+int selected_rsrc() { return opt_selected & Select.rsrc; }
+int selected_debug() { return opt_selected & Select.debug_; }
+int selected_dirs() { return opt_selected & Select.dirs; }
+int selected_loadcfg() { return opt_selected & Select.loadcfg; }
+
+int setting_blob() { return opt_settings & Setting.blob; }
+int setting_hexdump() { return opt_settings & Setting.hexdump; }
+int setting_extract() { return opt_settings & Setting.extract; }
+
+int setting_disasm() { return opt_settings & Setting.disasm; }
+int setting_disasm_all() { return opt_settings & Setting.disasmAll; }
+int setting_disasm_stats() { return opt_settings & Setting.disasmStats; }
+int setting_disasm_any() { return opt_settings & Setting.disasmAny; }
+
+/// Dump given file to stdout.
+/// Returns: Error code if non-zero
+int app_dump() {
+ if (setting_blob()) {
+ // NOTE: Program exits and memory is free'd
+ size_t size = void;
+ ubyte *buffer = readall(opt_file, &size);
+ if (buffer == null)
+ panic_crt();
+
+ if (size == 0)
+ panic(0, "File is empty");
+
+ print_string("filename", opt_file);
+ print_u64("filesize", size);
+ print_string("format", "Blob");
+ print_string("short_name", "blob");
+
+ return dump_disassemble(opt_machine, buffer, size, opt_baseaddress);
+ }
+
+ adbg_object_t *o = adbg_object_open_file(opt_file, 0);
+ if (o == null)
+ panic_adbg();
+
+ // If anything was selected to dump specifically
+ if (opt_selected) {
+ print_string("filename", opt_file);
+ print_u64("filesize", o.file_size);
+ print_string("format", adbg_object_name(o));
+ print_string("short_name", adbg_object_short_name(o));
+ final switch (o.format) with (AdbgObject) {
+ case mz: return dump_mz(o);
+ case ne: return dump_ne(o);
+ case pe: return dump_pe(o);
+ case lx: return dump_lx(o);
+ case elf: return dump_elf(o);
+ case macho: return dump_macho(o);
+ case pdb20: return dump_pdb20(o);
+ case pdb70: return dump_pdb70(o);
+ case archive: return dump_archive(o);
+ case mdmp: return dump_minidump(o);
+ case dmp: return dump_dmp(o);
+ case coff: return dump_coff(o);
+ case mscoff: return dump_mscoff(o);
+ case unknown: assert(0, "Unknown object type"); // Raw/unknown
+ }
+ }
+
+ // Otherwise, make a basic summary
+ printf("%s: %s\n", opt_file, adbg_object_name(o));
+ return 0;
+}
+
+private immutable {
+ /// Padding spacing to use in characters
+ // PE32 has fields like MinorOperatingSystemVersion (27 chars)
+ int __field_padding = -28;
+ /// Number of columns to produce in hexdumps.
+ int __columns = 16;
+}
+
+void print_header(const(char)* name) {
+ printf("\n# %s\n", name);
+}
+
+// Field name only
+void print_name(const(char)* name) {
+ printf("%*s: ", __field_padding, name);
+}
+
+void print_section(uint i, const(char) *name = null, int len = 0) {
+ putchar('\n');
+ print_u32("index", i);
+ if (name && len) print_stringl("name", name, len);
+}
+void print_disasm_line(adbg_opcode_t *op, const(char)* msg = null) {
+ // Print address
+ printf("%12llx ", op.address);
+
+ // If opcode is empty, somehow, print message if available
+ if (op.size == 0) {
+ puts(msg ? msg : "empty");
+ return;
+ }
+
+ // Format and print machine bytes
+ enum MBFSZ = (16 * 3) + 2; // Enough for 16 bytes and spaces
+ char[MBFSZ] machine = void;
+ int left = MBFSZ; // Buffer left
+ int tl; // Total length
+ for (size_t bi; bi < op.size; ++bi) {
+ int l = snprintf(machine.ptr + tl, left, " %02x", op.machine[bi]);
+ if (l <= 0) break; // Ran out of buffer space
+ tl += l;
+ left -= l;
+ }
+ machine[tl] = 0;
+ printf(" %*s ", -24, machine.ptr);
+
+ // Print message or mnemonics
+ if (msg) {
+ puts(msg);
+ return;
+ }
+ printf("%*s %s\n", -10, op.mnemonic, op.operands);
+}
+
+void print_u8(const(char)* name, ubyte val, const(char) *meaning = null) {
+ print_u32(name, val, meaning);
+}
+void print_u16(const(char)* name, ushort val, const(char) *meaning = null) {
+ print_u32(name, val, meaning);
+}
+void print_u32(const(char)* name, uint val, const(char) *meaning = null) {
+ printf("%*s: %u", __field_padding, name, val);
+ if (meaning) printf("\t(%s)", meaning);
+ putchar('\n');
+}
+void print_u32l(const(char)* name, uint val, const(char) *meaning = null, int length = 0) {
+ printf("%*s: %u", __field_padding, name, val);
+ if (meaning && length) printf("\t(\"%.*s\")", length, meaning);
+ putchar('\n');
+}
+void print_u64(const(char)* name, ulong val, const(char) *meaning = null) {
+ printf("%*s: %llu", __field_padding, name, val);
+ if (meaning) printf("\t(%s)", meaning);
+ putchar('\n');
+}
+
+void print_x8(const(char)* name, ubyte val, const(char) *meaning = null) {
+ printf("%*s: 0x%02x", __field_padding, name, val);
+ if (meaning) printf("\t(%s)", meaning);
+ putchar('\n');
+}
+void print_x16(const(char)* name, ushort val, const(char) *meaning = null) {
+ printf("%*s: 0x%04x", __field_padding, name, val);
+ if (meaning) printf("\t(%s)", meaning);
+ putchar('\n');
+}
+void print_x16l(const(char)* name, ushort val, const(char) *meaning = null, int length = 0) {
+ printf("%*s: 0x%04x", __field_padding, name, val);
+ if (meaning) printf("\t(\"%.*s\")", length, meaning);
+ putchar('\n');
+}
+void print_x32(const(char)* name, uint val, const(char) *meaning = null) {
+ printf("%*s: 0x%08x", __field_padding, name, val);
+ if (meaning) printf("\t(%s)", meaning);
+ putchar('\n');
+}
+void print_x32l(const(char)* name, uint val, const(char) *meaning = null, int length = 0) {
+ printf("%*s: 0x%08x", __field_padding, name, val);
+ if (meaning) printf("\t(\"%.*s\")", length, meaning);
+ putchar('\n');
+}
+void print_x64(const(char)* name, ulong val, const(char) *meaning = null) {
+ printf("%*s: 0x%016llx", __field_padding, name, val);
+ if (meaning) printf(`\t(%s)`, meaning);
+ putchar('\n');
+}
+
+void print_f32(const(char)* name, float val, int pad = 2) {
+ print_f64(name, val, pad);
+}
+void print_f64(const(char)* name, double val, int pad = 2) {
+ printf("%*s: %.*f\n", __field_padding, name, pad, val);
+}
+
+void print_string(const(char)* name, const(char)* val) {
+ printf("%*s: %s\n", __field_padding, name, val);
+}
+void print_stringl(const(char)* name, const(char)* val, int len) {
+ printf("%*s: %.*s\n", __field_padding, name, len, val);
+}
+//TODO: print_stringf
+
+void print_flags16(const(char) *section, ushort flags, ...) {
+ printf("%*s: 0x%04x\t(", __field_padding, section, flags);
+
+ va_list args = void;
+ va_start(args, flags);
+ ushort count;
+L_START:
+ const(char) *name = va_arg!(const(char)*)(args);
+ if (name == null) {
+ puts(")");
+ return;
+ }
+
+ if ((flags & va_arg!int(args)) == 0) goto L_START; // condition
+ if (count++) putchar(',');
+ printf("%s", name);
+ goto L_START;
+}
+void print_flags32(const(char) *section, uint flags, ...) {
+ printf("%*s: 0x%08x\t(", __field_padding, section, flags);
+
+ va_list args = void;
+ va_start(args, flags);
+ ushort count;
+L_START:
+ const(char) *name = va_arg!(const(char)*)(args);
+ if (name == null) {
+ puts(")");
+ return;
+ }
+
+ if ((flags & va_arg!int(args)) == 0) goto L_START; // condition
+ if (count++) putchar(',');
+ printf("%s", name);
+ goto L_START;
+}
+void print_flags64(const(char) *section, ulong flags, ...) {
+ printf("%*s: 0x%016llx\t(", __field_padding, section, flags);
+
+ va_list args = void;
+ va_start(args, flags);
+ ushort count;
+L_START:
+ const(char) *name = va_arg!(const(char)*)(args);
+ if (name == null) {
+ puts(")");
+ return;
+ }
+
+ if ((flags & va_arg!long(args)) == 0) goto L_START; // condition
+ if (count++) putchar(',');
+ printf("%s", name);
+ goto L_START;
+}
+
+//TODO: if opt_extract_to defined, save to it
+// dump binary data to stdout, unformatted
+void print_rawdump(void* data, size_t size) {
+ while (size > 0) {
+
+ }
+}
+
+// pretty hex dump to stdout
+void print_hexdump(const(char)* name, void *data, size_t dsize, ulong baseaddress = 0) {
+ print_header(name);
+
+ // Print header
+ static immutable string _soff = "Offset ";
+ printf(_soff.ptr);
+ for (int ib; ib < __columns; ++ib)
+ printf("%02x ", ib);
+ putchar('\n');
+
+ // Print data
+ ubyte *d = cast(ubyte*)data;
+ size_t afo; // Absolute file offset
+ for (size_t id; id < dsize; id += __columns, baseaddress += __columns) {
+ printf("%8llx ", baseaddress);
+
+ // Adjust column for row
+ size_t col = __columns;//id + __columns >= dsize ? dsize - __columns : __columns;
+ size_t off = afo;
+
+ // Print data bytes
+ for (size_t ib; ib < col; ++ib, ++off)
+ printf("%02x ", d[off]);
+
+ // Adjust spacing between the two
+ if (col < __columns) {
+
+ } else
+ putchar(' ');
+
+ // Print printable characters
+ off = afo;
+ for (size_t ib; ib < col; ++ib, ++off)
+ putchar(isprint(d[off]) ? d[off] : '.');
+
+ // New row
+ afo += col;
+ putchar('\n');
+ }
+}
+
+void print_directory_entry(const(char)* name, uint rva, uint size) {
+ printf("%*s: 0x%08x %u\n", __field_padding, name, rva, size);
+}
+
+void print_reloc16(uint index, ushort seg, ushort off) {
+ printf("%4u. 0x%04x:0x%04x\n", index, seg, off);
+}
+
+// name is typically section name or filename if raw
+int dump_disassemble_object(adbg_object_t *o,
+ const(char) *name, int namemax,
+ void* data, ulong size, ulong base_address) {
+
+ print_header("Disassembly");
+
+ if (name && namemax)
+ print_stringl("section", name, namemax);
+
+ if (data + size >= o.buffer + o.file_size) {
+ print_string("error", "data + size >= dump.o.buffer + dump.o.file_size");
+ return EXIT_FAILURE;
+ }
+
+ if (data == null || size == 0) {
+ print_string("error", "data is NULL or size is 0");
+ return 0;
+ }
+
+ return dump_disassemble(adbg_object_machine(o), data, size, base_address);
+}
+
+int dump_disassemble(AdbgMachine machine, void* data, ulong size, ulong base_address) {
+ adbg_disassembler_t *dis = adbg_dis_open(machine);
+ if (dis == null)
+ panic_adbg();
+ scope(exit) adbg_dis_close(dis);
+
+ if (opt_syntax)
+ adbg_dis_options(dis, AdbgDisOpt.syntax, opt_syntax, 0);
+
+ adbg_opcode_t op = void;
+ adbg_dis_start(dis, data, cast(size_t)size, base_address);
+
+ // stats mode
+ //TODO: attach shortest and longuest instructions found
+ if (setting_disasm_stats()) {
+ uint stat_avg; /// instruction average size
+ uint stat_min = uint.max; /// smallest instruction size
+ uint stat_max; /// longest instruction size
+ uint stat_total; /// total instruction count
+ uint stat_illegal; /// Number of illegal instructions
+L_STAT:
+ switch (adbg_dis_step(dis, &op)) with (AdbgError) {
+ case success:
+ stat_avg += op.size;
+ ++stat_total;
+ if (op.size > stat_max) stat_max = op.size;
+ if (op.size < stat_min) stat_min = op.size;
+ goto L_STAT;
+ case disasmIllegalInstruction:
+ stat_avg += op.size;
+ ++stat_total;
+ ++stat_illegal;
+ goto L_STAT;
+ case disasmEndOfData: break;
+ default:
+ panic_adbg();
+ }
+
+ print_f32("average", cast(float)stat_avg / stat_total, 2);
+ print_u32("shortest", stat_min);
+ print_u32("largest", stat_max);
+ print_u32("illegal", stat_illegal);
+ print_u32("valid", stat_total - stat_illegal);
+ print_u32("total", stat_total);
+ return 0;
+ }
+
+ // normal disasm mode
+L_DISASM:
+ switch (adbg_dis_step(dis, &op)) with (AdbgError) {
+ case success:
+ print_disasm_line(&op);
+ goto L_DISASM;
+ case disasmIllegalInstruction:
+ print_disasm_line(&op, "illegal");
+ goto L_DISASM;
+ case disasmEndOfData:
+ return 0;
+ default:
+ print_string("error", adbg_error_msg());
+ return 1;
+ }
+}
diff --git a/dumper/format/ar.d b/dumper/format/ar.d
new file mode 100644
index 0000000..d25b68c
--- /dev/null
+++ b/dumper/format/ar.d
@@ -0,0 +1,86 @@
+/// Library archive dumper
+///
+/// Authors: dd86k
+/// Copyright: © dd86k
+/// License: BSD-3-Clause-Clear
+module format.ar;
+
+import adbg.disassembler;
+import adbg.object.server;
+import adbg.machines;
+import adbg.object.format.ar;
+import adbg.utils.bit : adbg_bswap32;
+import core.stdc.ctype : isdigit;
+import dumper;
+import common.utils : realstring;
+
+extern (C):
+
+int dump_archive(adbg_object_t *o) {
+ if (selected_headers())
+ dump_archive_headers(o);
+
+ return 0;
+}
+
+private:
+
+void dump_archive_headers(adbg_object_t *o) {
+ print_header("Header");
+
+ ar_member_header *rhdr = void; // Root headers
+ for (size_t i; (rhdr = adbg_object_ar_header(o, i)) != null; ++i) {
+ print_section(cast(uint)i);
+ print_stringl("Name", rhdr.Name.ptr, rhdr.Name.sizeof);
+ print_stringl("Date", rhdr.Date.ptr, rhdr.Date.sizeof);
+ print_stringl("UserID", rhdr.UserID.ptr, rhdr.UserID.sizeof);
+ print_stringl("GroupID", rhdr.GroupID.ptr, rhdr.GroupID.sizeof);
+ print_stringl("Mode", rhdr.Mode.ptr, rhdr.Mode.sizeof);
+ print_stringl("Size", rhdr.Size.ptr, rhdr.Size.sizeof);
+
+ char[10] b = void;
+ int l = realstring(b.ptr, 10, rhdr.End.ptr, 2);
+ print_x16l("End", rhdr.EndMarker, b.ptr, l);
+
+ /+void *data = adbg_object_ar_data(o, rhdr);
+ if (data == null) {
+ print_string("warning", "Could not get data pointer");
+ continue;
+ }
+
+ int size = adbg_object_ar_header_size(o, rhdr);
+ if (size <= 0) {
+ print_string("warning", "Could not get size of data");
+ continue;
+ }
+
+ import core.stdc.stdio : printf;
+
+ int symcnt = *cast(int*)data;
+ int *symoffs = cast(int*)data + 1;
+ for (int isym; isym < symcnt; ++isym) {
+ int off = adbg_bswap32(symoffs[isym]);
+
+ ar_member_header *table = void;
+ if (adbg_object_offset(o, cast(void**)&table, off)) {
+ print_string("warning", "aaaaaaaaaaa cringe");
+ printf("there was %d headers\n", isym);
+ return;
+ }
+
+ print_stringl("Name", table.Name.ptr, table.Name.sizeof);
+ print_stringl("Date", table.Date.ptr, table.Date.sizeof);
+ print_stringl("UserID", table.UserID.ptr, table.UserID.sizeof);
+ print_stringl("GroupID", table.GroupID.ptr, table.GroupID.sizeof);
+ print_stringl("Mode", table.Mode.ptr, table.Mode.sizeof);
+ print_stringl("Size", table.Size.ptr, table.Size.sizeof);
+ l = realstring(b.ptr, 10, table.End.ptr, 2, '"', '"');
+ print_x16l("End", table.EndMarker, b.ptr, l);
+
+ if (table.Name[0] != '/' || isdigit(table.Name[1]) == 0)
+ continue;
+
+
+ }+/
+ }
+}
\ No newline at end of file
diff --git a/dumper/format/coff.d b/dumper/format/coff.d
new file mode 100644
index 0000000..6491328
--- /dev/null
+++ b/dumper/format/coff.d
@@ -0,0 +1,47 @@
+/// COFF dumper.
+///
+/// Authors: dd86k
+/// Copyright: © dd86k
+/// License: BSD-3-Clause-Clear
+module format.coff;
+
+import adbg.disassembler;
+import adbg.object.server;
+import adbg.machines;
+import adbg.object.format.coff;
+import adbg.object.format.pe : adbg_object_pe_machine_string;
+import adbg.utils.bit : adbg_bswap32;
+import adbg.utils.uid;
+import core.stdc.ctype : isdigit;
+import dumper;
+import common.utils : realstring;
+
+int dump_coff(adbg_object_t *o) {
+ if (selected_headers())
+ dump_coff_hdr(o);
+
+ return 0;
+}
+
+private:
+
+void dump_coff_hdr(adbg_object_t *o) {
+ print_header("Header");
+
+ with (o.i.coff.header) {
+ print_x16("f_magic", f_magic, adbg_object_coff_magic_string(f_magic));
+ print_u16("f_nscns", f_nscns);
+ print_u32("f_timedat", f_timedat);
+ print_u32("f_symptr", f_symptr);
+ print_u32("f_nsyms", f_nsyms);
+ print_u16("f_opthdr", f_opthdr);
+ print_flags16("f_flags", f_flags,
+ "RELFLG".ptr, COFF_F_RELFLG,
+ "EXEC".ptr, COFF_F_EXEC,
+ "LNNO".ptr, COFF_F_LNNO,
+ "LSYMS".ptr, COFF_F_LSYMS,
+ "LSB".ptr, COFF_F_LSB,
+ "MSB".ptr, COFF_F_MSB,
+ null);
+ }
+}
\ No newline at end of file
diff --git a/dumper/format/dmp.d b/dumper/format/dmp.d
new file mode 100644
index 0000000..09aeee3
--- /dev/null
+++ b/dumper/format/dmp.d
@@ -0,0 +1,70 @@
+/// Windows memory dump dumper.
+///
+/// Authors: dd86k
+/// Copyright: © dd86k
+/// License: BSD-3-Clause-Clear
+module format.dmp;
+
+import adbg.disassembler;
+import adbg.object.server;
+import adbg.machines;
+import adbg.object.format.dmp;
+import adbg.object.format.pe : adbg_object_pe_machine_string;
+import dumper;
+
+extern (C):
+
+int dump_dmp(adbg_object_t *o) {
+ if (selected_headers())
+ dump_dmp_header(o);
+
+ return 0;
+}
+
+private:
+
+void dump_dmp_header(adbg_object_t *o) {
+ print_header("Header");
+
+ bool is64 = o.i.dmp.header.ValidDumpInt == PAGEDUMP64_VALID;
+
+ dmp64_header *hdr64 = cast(dmp64_header*)o.i.dmp.header;
+ if (is64) with (hdr64) {
+ print_x32l("Signature", SignatureInt, Signature.ptr, 4);
+ print_x32l("ValidDump", ValidDumpInt, ValidDump.ptr, 4);
+ print_u32("MajorVersion", MajorVersion);
+ print_u32("MinorVersion", MinorVersion);
+ print_x32("DirectoryTableBase", DirectoryTableBase);
+ print_x32("PfnDatabase", PfnDatabase);
+ print_x32("PsLoadedModuleList", PsLoadedModuleList);
+ print_x32("PsActiveProcessHead", PsActiveProcessHead);
+ print_x32("MachineImageType", MachineImageType,
+ adbg_object_pe_machine_string(cast(ushort)MachineImageType));
+ print_u32("NumberProcessors", NumberProcessors);
+ print_x32("BugCheckCode", BugCheckCode);
+ print_x32("BugCheckParameter1", BugCheckParameters[0]);
+ print_x32("BugCheckParameter2", BugCheckParameters[1]);
+ print_x32("BugCheckParameter3", BugCheckParameters[2]);
+ print_x32("BugCheckParameter4", BugCheckParameters[3]);
+ print_x64("KdDebuggerDataBlock", KdDebuggerDataBlock);
+ } else with (o.i.dmp.header) {
+ print_x32l("Signature", SignatureInt, Signature.ptr, 4);
+ print_x32l("ValidDump", ValidDumpInt, ValidDump.ptr, 4);
+ print_u32("MajorVersion", MajorVersion);
+ print_u32("MinorVersion", MinorVersion);
+ print_x32("DirectoryTableBase", DirectoryTableBase);
+ print_x32("PfnDatabase", PfnDatabase);
+ print_x32("PsLoadedModuleList", PsLoadedModuleList);
+ print_x32("PsActiveProcessHead", PsActiveProcessHead);
+ print_x32("MachineImageType", MachineImageType,
+ adbg_object_pe_machine_string(cast(ushort)MachineImageType));
+ print_u32("NumberProcessors", NumberProcessors);
+ print_x32("BugCheckCode", BugCheckCode);
+ print_x32("BugCheckParameter1", BugCheckParameters[0]);
+ print_x32("BugCheckParameter2", BugCheckParameters[1]);
+ print_x32("BugCheckParameter3", BugCheckParameters[2]);
+ print_x32("BugCheckParameter4", BugCheckParameters[3]);
+ print_u8("PaeEnabled", PaeEnabled);
+ print_x32("KdDebuggerDataBlock", KdDebuggerDataBlock);
+ }
+}
\ No newline at end of file
diff --git a/dumper/format/elf.d b/dumper/format/elf.d
new file mode 100644
index 0000000..eb05310
--- /dev/null
+++ b/dumper/format/elf.d
@@ -0,0 +1,615 @@
+/// ELF dumper
+///
+/// Authors: dd86k
+/// Copyright: © dd86k
+/// License: BSD-3-Clause-Clear
+module format.elf;
+
+import adbg.utils.bit : adbg_align4up;
+import adbg.disassembler;
+import adbg.object.server;
+import adbg.machines;
+import adbg.object.format.elf;
+import core.stdc.string : memcmp, strncmp;
+import dumper;
+import common.utils : realchar, hexstr;
+
+extern (C):
+
+int dump_elf(adbg_object_t *o) {
+ if (selected_headers()) {
+ dump_elf_ehdr(o);
+ dump_elf_phdr(o);
+ }
+
+ if (selected_sections())
+ dump_elf_sections(o);
+
+ if (setting_disasm_any())
+ dump_elf_disasm(o);
+
+ return 0;
+}
+
+private:
+
+__gshared immutable(char)[] SIG_CORE = "CORE\0\0\0";
+
+void dump_elf_ehdr(adbg_object_t *o) {
+ print_header("Header");
+
+ ubyte ei_class = o.i.elf32.ehdr.e_ident[ELF_EI_CLASS];
+
+ with (o.i.elf32.ehdr) {
+ ubyte ei_data = e_ident[ELF_EI_DATA];
+ ubyte ei_version = e_ident[ELF_EI_VERSION];
+ ubyte ei_osabi = e_ident[ELF_EI_OSABI];
+ ubyte ei_abiversion = e_ident[ELF_EI_ABIVERSION];
+
+ print_x8("e_ident[0]", '\x7f', `\x7f`);
+ print_x8("e_ident[1]", 'E', `E`);
+ print_x8("e_ident[2]", 'L', `L`);
+ print_x8("e_ident[3]", 'F', `F`);
+ print_u8("e_ident[EI_CLASS]", ei_class, adbg_object_elf_class_string(ei_class));
+ print_u8("e_ident[EI_DATA]", ei_data, adbg_object_elf_data_string(ei_data));
+ print_u8("e_ident[EI_VERSION]", ei_version);
+ print_u8("e_ident[EI_OSABI]", ei_osabi, adbg_object_elf_abi_string(ei_osabi));
+ print_u8("e_ident[EI_ABIVERSION]", ei_abiversion);
+ print_u8("e_ident[9]", e_ident[9]);
+ print_u8("e_ident[10]", e_ident[10]);
+ print_u8("e_ident[11]", e_ident[11]);
+ print_u8("e_ident[12]", e_ident[12]);
+ print_u8("e_ident[13]", e_ident[13]);
+ print_u8("e_ident[14]", e_ident[14]);
+ print_u8("e_ident[15]", e_ident[15]);
+ print_u16("e_type", e_type, adbg_object_elf_et_string(e_type));
+ print_u16("e_machine", e_machine, adbg_object_elf_em_string(e_machine));
+ }
+
+ switch (ei_class) {
+ case ELF_CLASS_32:
+ with (o.i.elf32.ehdr) {
+ print_x32("e_entry", e_entry);
+ print_x32("e_phoff", e_phoff);
+ print_x32("e_shoff", e_shoff);
+ dump_elf_e_flags(e_machine, e_flags);
+ print_u16("e_ehsize", e_ehsize);
+ print_u16("e_phentsize", e_phentsize);
+ print_u16("e_phnum", e_phnum);
+ print_u16("e_shentsize", e_shentsize);
+ print_u16("e_shnum", e_shnum);
+ print_u16("e_shstrndx", e_shstrndx);
+ }
+ break;
+ case ELF_CLASS_64:
+ with (o.i.elf64.ehdr) {
+ print_x64("e_entry", e_entry);
+ print_x64("e_phoff", e_phoff);
+ print_x64("e_shoff", e_shoff);
+ dump_elf_e_flags(e_machine, e_flags);
+ print_u16("e_ehsize", e_ehsize);
+ print_u16("e_phentsize", e_phentsize);
+ print_u16("e_phnum", e_phnum);
+ print_u16("e_shentsize", e_shentsize);
+ print_u16("e_shnum", e_shnum);
+ print_u16("e_shstrndx", e_shstrndx);
+ }
+ break;
+ default:
+ }
+}
+
+void dump_elf_e_flags(ushort e_machine, uint e_flags) {
+ switch (e_machine) {
+ case ELF_EM_ARM:
+ print_flags32("e_flags", e_flags,
+ "EF_ARM_RELEXEC".ptr, ELF_EF_ARM_RELEXEC,
+ "EF_ARM_HASENTRY".ptr, ELF_EF_ARM_HASENTRY,
+ "EF_ARM_INTERWORK".ptr, ELF_EF_ARM_INTERWORK,
+ "EF_ARM_APCS_26".ptr, ELF_EF_ARM_APCS_26,
+ "EF_ARM_APCS_FLOAT".ptr, ELF_EF_ARM_APCS_FLOAT,
+ "EF_ARM_PIC".ptr, ELF_EF_ARM_PIC,
+ "EF_ARM_ALIGN8".ptr, ELF_EF_ARM_ALIGN8,
+ "EF_ARM_NEW_ABI".ptr, ELF_EF_ARM_NEW_ABI,
+ "EF_ARM_OLD_ABI".ptr, ELF_EF_ARM_OLD_ABI,
+ "EF_ARM_SOFT_FLOAT".ptr, ELF_EF_ARM_SOFT_FLOAT,
+ "EF_ARM_VFP_FLOAT".ptr, ELF_EF_ARM_VFP_FLOAT,
+ "EF_ARM_MAVERICK_FLOAT".ptr, ELF_EF_ARM_MAVERICK_FLOAT,
+ null);
+ break;
+ case ELF_EM_SPARC:
+ case ELF_EM_SPARC32PLUS:
+ case ELF_EM_SPARCV9:
+ print_flags32("e_flags", e_flags,
+ "EF_SPARC_32PLUS".ptr, ELF_EF_SPARC_32PLUS,
+ "EF_SPARC_SUN_US1".ptr, ELF_EF_SPARC_SUN_US1,
+ "EF_SPARC_HAL_R1".ptr, ELF_EF_SPARC_HAL_R1,
+ "EF_SPARC_SUN_US3".ptr, ELF_EF_SPARC_SUN_US3,
+ "EF_SPARCV9_MM".ptr, ELF_EF_SPARCV9_MM,
+ "EF_SPARCV9_TSO".ptr, ELF_EF_SPARCV9_TSO,
+ "EF_SPARCV9_PSO".ptr, ELF_EF_SPARCV9_PSO,
+ "EF_SPARCV9_RMO".ptr, ELF_EF_SPARCV9_RMO,
+ null);
+ break;
+ default:
+ print_x32("e_flags", e_flags);
+ }
+}
+
+void dump_elf_phdr(adbg_object_t *o) {
+ print_header("Program Headers");
+
+ //TODO: Warn and set an upper number limit (e.g. 1000)
+
+ switch (o.i.elf32.ehdr.e_ident[ELF_EI_CLASS]) {
+ case ELF_CLASS_32:
+ with (o.i.elf32) if (phdr == null || ehdr.e_phnum == 0)
+ return;
+
+ //TODO: adbg_object_elf32_phnum function?
+ for (uint i; i < o.i.elf32.ehdr.e_phnum; ++i) {
+ Elf32_Phdr *phdr = adbg_object_elf_phdr32(o, i);
+ with (phdr) {
+ print_section(i);
+ print_u32("p_type", p_type, adbg_object_elf_pt_string(p_type));
+ print_x32("p_offset", p_offset);
+ print_x32("p_vaddr", p_vaddr);
+ print_x32("p_paddr", p_paddr);
+ print_x32("p_filesz", p_filesz);
+ print_x32("p_memsz", p_memsz);
+ print_flags32("p_flags", p_flags,
+ "PF_R".ptr, ELF_PF_R,
+ "PF_W".ptr, ELF_PF_W,
+ "PF_X".ptr, ELF_PF_X,
+ null);
+ print_x32("p_align", p_align);
+ }
+
+ //TODO: coredump
+ // if (p_type == ELF_PT_NOTE && p_pflags == 0)
+ // Elf32_Nhdr (like NT_X86_XSTATE)
+ }
+ break;
+ case ELF_CLASS_64:
+ with (o.i.elf64) if (phdr == null || ehdr.e_phnum == 0)
+ return;
+
+ for (uint i; i < o.i.elf64.ehdr.e_phnum; ++i) {
+ Elf64_Phdr *phdr = adbg_object_elf_phdr64(o, i);
+ with (phdr) {
+ print_section(i);
+ print_u32("p_type", p_type, adbg_object_elf_pt_string(p_type));
+ print_flags32("p_flags", p_flags,
+ "PF_R".ptr, ELF_PF_R,
+ "PF_W".ptr, ELF_PF_W,
+ "PF_X".ptr, ELF_PF_X,
+ null);
+ print_x64("p_offset", p_offset);
+ print_x64("p_vaddr", p_vaddr);
+ print_x64("p_paddr", p_paddr);
+ print_x64("p_filesz", p_filesz);
+ print_x64("p_memsz", p_memsz);
+ print_x64("p_align", p_align);
+ }
+
+ // ELF is a coredump and program header is a note?
+ // Worth checking if it is really a coredump
+ // Notes usually have no flags
+ if (o.i.elf32.ehdr.e_type == ELF_ET_CORE &&
+ phdr.p_type == ELF_PT_NOTE &&
+ phdr.p_flags == 0) {
+ dump_elf_coredump64(o, phdr);
+ }
+ }
+ break;
+ default:
+ }
+}
+
+void dump_elf_coredump32(adbg_object_t *o, Elf32_Phdr *phdr) {
+
+}
+void dump_elf_coredump64(adbg_object_t *o, Elf64_Phdr *phdr) {
+ // NOTE: 8-byte alignment?
+
+ ulong noffset = phdr.p_offset;
+ long nleft = phdr.p_filesz;
+ uint idx;
+
+ // Process new note header
+LNEWNHDR:
+ if (nleft < Elf64_Nhdr.sizeof)
+ return;
+
+ void *note = void;
+ if (adbg_object_offsetl(o, ¬e, noffset, cast(size_t)nleft)) {
+ print_string("warning", "Elf64_Phdr::p_offset points outside of file bounds");
+ return;
+ }
+
+ Elf64_Nhdr *nhdr = cast(Elf64_Nhdr*)note;
+
+ // NOTE: Note names
+ // If zero, it's reserved
+ // If name is "CORE", standard coredump stuff, like NT_PRSTATUS
+ // If name is "LINUX", Linux-specific note, like NT_X86_XSTATE
+ if (nhdr.n_namesz == 0)
+ return;
+
+ print_section(++idx, cast(const(char)*)note + Elf64_Nhdr.sizeof, nhdr.n_namesz);
+ print_u32l("n_namesz", nhdr.n_namesz);
+ print_u32("n_descsz", nhdr.n_descsz);
+ print_u32("n_type", nhdr.n_type, adbg_object_elf_nt_type_string(nhdr.n_type));
+
+ size_t nnamesz = adbg_align4up(nhdr.n_namesz);
+ void *data = note + Elf64_Nhdr.sizeof + nnamesz;
+
+ // NOTE: Only for x86-64, for now
+ switch (nhdr.n_type) {
+ case ELF_NT_PRSTATUS:
+ elf_prstatus64 *prstatus = cast(elf_prstatus64*)data;
+ print_u32("pr_info.si_signo", prstatus.pr_info.si_signo);
+ print_u32("pr_info.si_code", prstatus.pr_info.si_code);
+ print_u32("pr_info.si_errno", prstatus.pr_info.si_errno);
+ print_u16("pr_cursig", prstatus.pr_cursig);
+ print_u64("pr_sigpend", prstatus.pr_sigpend);
+ print_u64("pr_sighold", prstatus.pr_sighold);
+ print_u32("pr_pid", prstatus.pr_pid);
+ print_u32("pr_ppid", prstatus.pr_ppid);
+ print_u32("pr_pgrp", prstatus.pr_pgrp);
+ print_u32("pr_sid", prstatus.pr_sid);
+ print_u64("pr_utime.tv_sec", prstatus.pr_utime.tv_sec);
+ print_u64("pr_utime.tv_usec", prstatus.pr_utime.tv_usec);
+ print_u64("pr_stime.tv_sec", prstatus.pr_stime.tv_sec);
+ print_u64("pr_stime.tv_usec", prstatus.pr_stime.tv_usec);
+ print_u64("pr_cutime.tv_sec", prstatus.pr_cutime.tv_sec);
+ print_u64("pr_cutime.tv_usec", prstatus.pr_cutime.tv_usec);
+ print_u64("pr_cstime.tv_sec", prstatus.pr_cstime.tv_sec);
+ print_u64("pr_cstime.tv_usec", prstatus.pr_cstime.tv_usec);
+ print_x64("pr_reg[r15]", prstatus.pr_reg[0]);
+ print_x64("pr_reg[r14]", prstatus.pr_reg[1]);
+ print_x64("pr_reg[r13]", prstatus.pr_reg[2]);
+ print_x64("pr_reg[r12]", prstatus.pr_reg[3]);
+ print_x64("pr_reg[rbp]", prstatus.pr_reg[4]);
+ print_x64("pr_reg[rbx]", prstatus.pr_reg[5]);
+ print_x64("pr_reg[r11]", prstatus.pr_reg[6]);
+ print_x64("pr_reg[r10]", prstatus.pr_reg[7]);
+ print_x64("pr_reg[r9]", prstatus.pr_reg[8]);
+ print_x64("pr_reg[r8]", prstatus.pr_reg[9]);
+ print_x64("pr_reg[rax]", prstatus.pr_reg[10]);
+ print_x64("pr_reg[rcx]", prstatus.pr_reg[11]);
+ print_x64("pr_reg[rdx]", prstatus.pr_reg[12]);
+ print_x64("pr_reg[rsi]", prstatus.pr_reg[13]);
+ print_x64("pr_reg[rdi]", prstatus.pr_reg[14]);
+ print_x64("pr_reg[orig_rax]", prstatus.pr_reg[15]);
+ print_x64("pr_reg[rip]", prstatus.pr_reg[16]);
+ print_x64("pr_reg[cs]", prstatus.pr_reg[17]);
+ print_x64("pr_reg[eflags]", prstatus.pr_reg[18]);
+ print_x64("pr_reg[rsp]", prstatus.pr_reg[19]);
+ print_x64("pr_reg[ss]", prstatus.pr_reg[20]);
+ print_x64("pr_reg[fs_base]", prstatus.pr_reg[21]);
+ print_x64("pr_reg[gs_base]", prstatus.pr_reg[22]);
+ print_x64("pr_reg[ds]", prstatus.pr_reg[23]);
+ print_x64("pr_reg[es]", prstatus.pr_reg[24]);
+ print_x64("pr_reg[fs]", prstatus.pr_reg[25]);
+ print_x64("pr_reg[gs]", prstatus.pr_reg[26]);
+ print_u64("pr_fpvalid", prstatus.pr_fpvalid);
+ break;
+ case ELF_NT_PRPSINFO:
+ elf_prpsinfo64 *prpsinfo = cast(elf_prpsinfo64*)data;
+ char[4] pr_sname = void;
+ int l = realchar(pr_sname.ptr, 4, prpsinfo.pr_sname);
+ print_u8("pr_state", prpsinfo.pr_state);
+ print_stringl("pr_sname", pr_sname.ptr, l);
+ print_u8("pr_zomb", prpsinfo.pr_zomb);
+ print_u8("pr_nice", prpsinfo.pr_nice);
+ print_u64("pr_flag", prpsinfo.pr_flag);
+ print_u32("pr_uid", prpsinfo.pr_uid);
+ print_u32("pr_gid", prpsinfo.pr_gid);
+ print_u32("pr_pid", prpsinfo.pr_pid);
+ print_u32("pr_ppid", prpsinfo.pr_ppid);
+ print_u32("pr_pgrp", prpsinfo.pr_pgrp);
+ print_u32("pr_sid", prpsinfo.pr_sid);
+ print_stringl("pr_fname", prpsinfo.pr_fname.ptr, prpsinfo.pr_fname.sizeof);
+ print_stringl("pr_psargs", prpsinfo.pr_psargs.ptr, prpsinfo.pr_psargs.sizeof);
+ break;
+ case ELF_NT_SIGINFO: // siginfo
+ // NOTE: SI_MAX_SIZE is defined with 128, must be same size
+ goto default;
+ case ELF_NT_FPREGSET:
+ user_i387_struct64 *fregset = cast(user_i387_struct64*)data;
+ char[2*16] fpbuf = void;
+ int fplen = void;
+ print_x16("cwd", fregset.cwd);
+ print_x16("swd", fregset.swd);
+ print_x16("twd", fregset.twd);
+ print_x16("fop", fregset.fop);
+ print_x64("rip", fregset.rip);
+ print_x64("rdp", fregset.rdp);
+ print_x32("mxcsr", fregset.mxcsr);
+ print_x32("mxcsr_mask", fregset.mxcsr_mask);
+ // x87
+ fplen = hexstr(fpbuf.ptr, 32, fregset.st_space128[0].data.ptr, 16);
+ print_stringl("st_space[0]", fpbuf.ptr, fplen);
+ fplen = hexstr(fpbuf.ptr, 32, fregset.st_space128[1].data.ptr, 16);
+ print_stringl("st_space[1]", fpbuf.ptr, fplen);
+ fplen = hexstr(fpbuf.ptr, 32, fregset.st_space128[2].data.ptr, 16);
+ print_stringl("st_space[2]", fpbuf.ptr, fplen);
+ fplen = hexstr(fpbuf.ptr, 32, fregset.st_space128[3].data.ptr, 16);
+ print_stringl("st_space[3]", fpbuf.ptr, fplen);
+ fplen = hexstr(fpbuf.ptr, 32, fregset.st_space128[4].data.ptr, 16);
+ print_stringl("st_space[4]", fpbuf.ptr, fplen);
+ fplen = hexstr(fpbuf.ptr, 32, fregset.st_space128[5].data.ptr, 16);
+ print_stringl("st_space[5]", fpbuf.ptr, fplen);
+ fplen = hexstr(fpbuf.ptr, 32, fregset.st_space128[6].data.ptr, 16);
+ print_stringl("st_space[6]", fpbuf.ptr, fplen);
+ fplen = hexstr(fpbuf.ptr, 32, fregset.st_space128[7].data.ptr, 16);
+ print_stringl("st_space[7]", fpbuf.ptr, fplen);
+ // sse
+ fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[0].data.ptr, 16);
+ print_stringl("xmm_space[0]", fpbuf.ptr, fplen);
+ fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[1].data.ptr, 16);
+ print_stringl("xmm_space[1]", fpbuf.ptr, fplen);
+ fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[2].data.ptr, 16);
+ print_stringl("xmm_space[2]", fpbuf.ptr, fplen);
+ fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[3].data.ptr, 16);
+ print_stringl("xmm_space[3]", fpbuf.ptr, fplen);
+ fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[4].data.ptr, 16);
+ print_stringl("xmm_space[4]", fpbuf.ptr, fplen);
+ fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[5].data.ptr, 16);
+ print_stringl("xmm_space[5]", fpbuf.ptr, fplen);
+ fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[6].data.ptr, 16);
+ print_stringl("xmm_space[6]", fpbuf.ptr, fplen);
+ fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[7].data.ptr, 16);
+ print_stringl("xmm_space[7]", fpbuf.ptr, fplen);
+ fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[8].data.ptr, 16);
+ print_stringl("xmm_space[8]", fpbuf.ptr, fplen);
+ fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[9].data.ptr, 16);
+ print_stringl("xmm_space[9]", fpbuf.ptr, fplen);
+ fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[10].data.ptr, 16);
+ print_stringl("xmm_space[10]", fpbuf.ptr, fplen);
+ fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[11].data.ptr, 16);
+ print_stringl("xmm_space[11]", fpbuf.ptr, fplen);
+ fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[12].data.ptr, 16);
+ print_stringl("xmm_space[12]", fpbuf.ptr, fplen);
+ fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[13].data.ptr, 16);
+ print_stringl("xmm_space[13]", fpbuf.ptr, fplen);
+ fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[14].data.ptr, 16);
+ print_stringl("xmm_space[14]", fpbuf.ptr, fplen);
+ fplen = hexstr(fpbuf.ptr, 32, fregset.xmm_space128[15].data.ptr, 16);
+ print_stringl("xmm_space[15]", fpbuf.ptr, fplen);
+ break;
+ default:
+ print_hexdump("Dump", data, nhdr.n_descsz,
+ noffset + Elf64_Nhdr.sizeof + nnamesz);
+ }
+
+ // Adjust to next sub header
+ ulong nsize =
+ Elf64_Nhdr.sizeof +
+ nnamesz +
+ adbg_align4up(nhdr.n_descsz);
+ noffset += nsize;
+ nleft -= nsize;
+
+ goto LNEWNHDR;
+}
+
+void dump_elf_sections(adbg_object_t *o) {
+ print_header("Sections");
+
+ //TODO: Functions to get section + section name safely
+
+ /// Arbritrary maximum section name length
+ enum SNMLEN = 32;
+ switch (o.i.elf32.ehdr.e_ident[ELF_EI_CLASS]) {
+ case ELF_CLASS_32:
+ if (o.i.elf32.ehdr == null)
+ return;
+
+ ushort section_count = o.i.elf32.ehdr.e_shnum;
+ if (section_count == 0)
+ return;
+
+ // Check id is without section count
+ ushort id = o.i.elf32.ehdr.e_shstrndx;
+ if (id >= section_count) {
+ print_string("error", "String table index out of bounds");
+ return;
+ }
+
+ uint offset = o.i.elf32.shdr[id].sh_offset;
+ if (offset < Elf32_Ehdr.sizeof || offset > o.file_size) {
+ print_string("error", "String table offset out of bounds");
+ return;
+ }
+
+ char *table = o.bufferc + offset; // string table
+ for (uint i; i < section_count; ++i) {
+ Elf32_Shdr *shdr = adbg_object_elf_shdr32(o, i);
+
+ const(char) *sname = table + shdr.sh_name;
+
+ // If we're searching sections, match and don't print yet
+ if (opt_section) {
+ if (strncmp(sname, opt_section, SNMLEN))
+ continue;
+
+ void *data = o.buffer + shdr.sh_offset;
+
+ if (setting_hexdump())
+ print_hexdump(opt_section, data, shdr.sh_size, shdr.sh_offset);
+
+ if (setting_extract())
+ print_rawdump(data, shdr.sh_size);
+ }
+
+ with (shdr) {
+ print_section(i, sname, SNMLEN);
+ print_x32("sh_name", sh_name);
+ print_x32("sh_type", sh_type, adbg_object_elf_sht_string(sh_type));
+ print_x32("sh_flags", sh_flags);
+ print_flags32("sh_flags", sh_flags,
+ "SHF_WRITE".ptr, ELF_SHF_WRITE,
+ "SHF_ALLOC".ptr, ELF_SHF_ALLOC,
+ "SHF_EXECINSTR".ptr, ELF_SHF_EXECINSTR,
+ "SHF_MERGE".ptr, ELF_SHF_MERGE,
+ "SHF_STRINGS".ptr, ELF_SHF_STRINGS,
+ "SHF_INFO_LINK".ptr, ELF_SHF_INFO_LINK,
+ "SHF_LINK_ORDER".ptr, ELF_SHF_LINK_ORDER,
+ "SHF_OS_NONCONFORMING".ptr, ELF_SHF_OS_NONCONFORMING,
+ "SHF_GROUP".ptr, ELF_SHF_GROUP,
+ "SHF_TLS".ptr, ELF_SHF_TLS,
+ "SHF_COMPRESSED".ptr, ELF_SHF_COMPRESSED,
+ null);
+ print_x32("sh_addr", sh_addr);
+ print_x32("sh_offset", sh_offset);
+ print_x32("sh_size", sh_size);
+ print_x32("sh_link", sh_link);
+ print_x32("sh_info", sh_info);
+ print_x32("sh_addralign", sh_addralign);
+ print_x32("sh_entsize", sh_entsize);
+ }
+ }
+ break;
+ case ELF_CLASS_64:
+ if (o.i.elf64.ehdr == null)
+ return;
+
+ ushort section_count = o.i.elf64.ehdr.e_shnum;
+ if (section_count == 0)
+ return;
+
+ // Check id is without section count
+ ushort id = o.i.elf64.ehdr.e_shstrndx;
+ if (id >= section_count) {
+ print_string("error", "String table index out of bounds");
+ return;
+ }
+
+ ulong offset = o.i.elf64.shdr[id].sh_offset;
+ if (offset < Elf64_Ehdr.sizeof || offset > o.file_size) {
+ print_string("error", "String table offset out of bounds");
+ return;
+ }
+
+ char *table = o.bufferc + offset; // string table
+ for (uint i; i < section_count; ++i) {
+ Elf64_Shdr *shdr = adbg_object_elf_shdr64(o, i);
+
+ const(char) *sname = table + shdr.sh_name;
+
+ // If we're searching sections, match and don't print yet
+ if (opt_section) {
+ if (strncmp(sname, opt_section, SNMLEN))
+ continue;
+
+ void *data = o.buffer + shdr.sh_offset;
+
+ if (setting_hexdump())
+ print_hexdump(opt_section, data, shdr.sh_size, shdr.sh_offset);
+
+ if (setting_extract())
+ print_rawdump(data, shdr.sh_size);
+ }
+
+ with (shdr) {
+ print_section(i, table + sh_name, SNMLEN);
+ print_x32("sh_name", sh_name);
+ print_x32("sh_type", sh_type, adbg_object_elf_sht_string(sh_type));
+ print_flags64("sh_flags", sh_flags,
+ "SHF_WRITE".ptr, ELF_SHF_WRITE,
+ "SHF_ALLOC".ptr, ELF_SHF_ALLOC,
+ "SHF_EXECINSTR".ptr, ELF_SHF_EXECINSTR,
+ "SHF_MERGE".ptr, ELF_SHF_MERGE,
+ "SHF_STRINGS".ptr, ELF_SHF_STRINGS,
+ "SHF_INFO_LINK".ptr, ELF_SHF_INFO_LINK,
+ "SHF_LINK_ORDER".ptr, ELF_SHF_LINK_ORDER,
+ "SHF_OS_NONCONFORMING".ptr, ELF_SHF_OS_NONCONFORMING,
+ "SHF_GROUP".ptr, ELF_SHF_GROUP,
+ "SHF_TLS".ptr, ELF_SHF_TLS,
+ "SHF_COMPRESSED".ptr, ELF_SHF_COMPRESSED,
+ null);
+ print_x64("sh_addr", sh_addr);
+ print_x64("sh_offset", sh_offset);
+ print_x64("sh_size", sh_size);
+ print_x32("sh_link", sh_link);
+ print_x32("sh_info", sh_info);
+ print_x64("sh_addralign", sh_addralign);
+ print_x64("sh_entsize", sh_entsize);
+ }
+ }
+ break;
+ default:
+ }
+}
+
+//TODO: Section machine-specific flags (like SHF_X86_64_LARGE)
+
+void dump_elf_disasm(adbg_object_t *o) {
+ print_header("Disassembly");
+
+ int all = setting_disasm_all(); /// dump all
+
+ switch (o.i.elf32.ehdr.e_ident[ELF_EI_CLASS]) {
+ case ELF_CLASS_32:
+ ushort section_count = o.i.elf32.ehdr.e_shnum;
+
+ if (section_count == 0)
+ return;
+
+ // Check id is without section count
+ ushort id = o.i.elf32.ehdr.e_shstrndx;
+ if (id >= section_count) {
+ print_string("error", "String table index out of bounds");
+ return;
+ }
+
+ Elf32_Shdr *shdr = o.i.elf32.shdr;
+ uint offset = shdr[id].sh_offset;
+ if (offset < Elf32_Ehdr.sizeof || offset > o.file_size) {
+ print_string("error", "String table offset out of bounds");
+ return;
+ }
+
+ Elf32_Shdr *max = shdr + section_count;
+ char *table = o.bufferc + offset; // string table
+ while (shdr++ < max) with (shdr) {
+ if (all || sh_flags & ELF_SHF_EXECINSTR)
+ dump_disassemble_object(o,
+ table + sh_name, 32,
+ o.buffer8 + sh_offset, sh_size, 0);
+ }
+ break;
+ case ELF_CLASS_64:
+ ushort section_count = o.i.elf64.ehdr.e_shnum;
+
+ if (section_count == 0)
+ return;
+
+ // Check id is without section count
+ ushort id = o.i.elf64.ehdr.e_shstrndx;
+ if (id >= section_count) {
+ print_string("error", "String table index out of bounds");
+ return;
+ }
+
+ Elf64_Shdr *shdr = o.i.elf64.shdr;
+ ulong offset = shdr[id].sh_offset;
+ if (offset < Elf64_Ehdr.sizeof || offset > o.file_size) {
+ print_string("error", "String table offset out of bounds");
+ return;
+ }
+
+ Elf64_Shdr *max = shdr + section_count;
+ char *table = o.bufferc + offset; // string table
+ while (shdr++ < max) with (shdr) {
+ if (all || sh_flags & ELF_SHF_EXECINSTR)
+ dump_disassemble_object(o,
+ table + sh_name, 32,
+ o.buffer8 + sh_offset, sh_size, 0);
+ }
+ break;
+ default:
+ }
+}
diff --git a/dumper/format/lx.d b/dumper/format/lx.d
new file mode 100644
index 0000000..0cfc942
--- /dev/null
+++ b/dumper/format/lx.d
@@ -0,0 +1,113 @@
+/// OS/2 / Windows 9x LX file dumper
+///
+/// Authors: dd86k
+/// Copyright: © dd86k
+/// License: BSD-3-Clause-Clear
+module format.lx;
+
+import adbg.disassembler;
+import adbg.object.server;
+import adbg.machines : AdbgMachine;
+import adbg.object.format.lx;
+import dumper;
+
+extern (C):
+
+int dump_lx(adbg_object_t *o) {
+ if (selected_headers())
+ dump_lx_hdr(o);
+ return 0;
+}
+
+private:
+
+void dump_lx_hdr(adbg_object_t *o) {
+ print_header("Header");
+
+ with (o.i.lx.header) {
+ print_x16("e32_magic", magic, magic == LE_MAGIC ? "LE" : "LX");
+ print_x8("e32_border", border);
+ print_x8("e32_worder", worder);
+ print_x32("e32_level", level);
+ print_u16("e32_cpu", cpu, adbg_object_lx_cputype_string(cpu));
+ print_u16("e32_os", os, adbg_object_lx_ostype_string(os));
+ print_x32("e32_ver", ver);
+ print_flags32("e32_mflags", mflags,
+ "PROCLIBINIT".ptr, LX_FLAG_PROCLIBINIT,
+ "INTFIXUPS".ptr, LX_FLAG_INTFIXUPS,
+ "EXTFIXUPS".ptr, LX_FLAG_EXTFIXUPS,
+ "INCOMPATPMWIN".ptr, LX_FLAG_INCOMPATPMWIN,
+ "COMPATPMWIN".ptr, LX_FLAG_COMPATPMWIN,
+ "USESPMWIN".ptr, LX_FLAG_USESPMWIN,
+ "MODUNLOADABLE".ptr, LX_FLAG_MODUNLOADABLE,
+ "PROCLIBTERM".ptr, LX_FLAG_PROCLIBTERM,
+ null);
+ print_x32("e32_mflags:ModuleType", mflags, adbg_object_lx_modtype_string(mflags));
+ print_u32("e32_mpages", mpages);
+ print_x32("e32_startobj", startobj);
+ print_x32("e32_eip", eip);
+ print_x32("e32_stackobj", stackobj);
+ print_x32("e32_esp", esp);
+ print_u32("e32_pagesize", pagesize);
+ print_x32("e32_pageshift", pageshift);
+ print_u32("e32_fixupsize", fixupsize);
+ print_x32("e32_fixupsum", fixupsum);
+ print_u32("e32_ldrsize", ldrsize);
+ print_x32("e32_ldrsum", ldrsum);
+ print_x32("e32_objtab", objtab);
+ print_x32("e32_objcnt", objcnt);
+ print_x32("e32_objmap", objmap);
+ print_x32("e32_itermap", itermap);
+ print_x32("e32_rsrctab", rsrctab);
+ print_x32("e32_rsrccnt", rsrccnt);
+ print_x32("e32_restab", restab);
+ print_x32("e32_enttab", enttab);
+ print_x32("e32_dirtab", dirtab);
+ print_x32("e32_dircnt", dircnt);
+ print_x32("e32_fpagetab", fpagetab);
+ print_x32("e32_frectab", frectab);
+ print_x32("e32_impmod", impmod);
+ print_x32("e32_impmodcnt", impmodcnt);
+ print_x32("e32_impproc", impproc);
+ print_x32("e32_pagesum", pagesum);
+ print_x32("e32_datapage", datapage);
+ print_x32("e32_preload", preload);
+ print_x32("e32_nrestab", nrestab);
+ print_u32("e32_cbnrestab", cbnrestab);
+ print_x32("e32_nressum", nressum);
+ print_x32("e32_autodata", autodata);
+ print_x32("e32_debuginfo", debuginfo);
+ print_u32("e32_debuglen", debuglen);
+ print_x32("e32_instpreload", instpreload);
+ print_x32("e32_instdemand", instdemand);
+ print_u32("e32_heapsize", heapsize);
+ print_u32("e32_stacksize", stacksize);
+ print_x8("e32_res[0]", res1[0]);
+ print_x8("e32_res[1]", res1[1]);
+ print_x8("e32_res[2]", res1[2]);
+ print_x8("e32_res[3]", res1[3]);
+ print_x8("e32_res[4]", res1[4]);
+ print_x8("e32_res[5]", res1[5]);
+ print_x8("e32_res[6]", res1[6]);
+ print_x8("e32_res[7]", res1[7]);
+ if (magic == LE_MAGIC) {
+ print_x32("winresoff", winresoff);
+ print_u32("winreslen", winreslen);
+ print_x16("device_id", device_id);
+ print_x16("ddk_version", ddk_version);
+ } else {
+ print_x8("e32_res[8]", res[8]);
+ print_x8("e32_res[9]", res[9]);
+ print_x8("e32_res[10]", res[10]);
+ print_x8("e32_res[11]", res[11]);
+ print_x8("e32_res[12]", res[12]);
+ print_x8("e32_res[13]", res[13]);
+ print_x8("e32_res[14]", res[14]);
+ print_x8("e32_res[15]", res[15]);
+ print_x8("e32_res[16]", res[16]);
+ print_x8("e32_res[17]", res[17]);
+ print_x8("e32_res[18]", res[18]);
+ print_x8("e32_res[19]", res[19]);
+ }
+ }
+}
\ No newline at end of file
diff --git a/dumper/format/macho.d b/dumper/format/macho.d
new file mode 100644
index 0000000..bf523c8
--- /dev/null
+++ b/dumper/format/macho.d
@@ -0,0 +1,91 @@
+/// Mach-O object dumper.
+///
+/// Authors: dd86k
+/// Copyright: © dd86k
+/// License: BSD-3-Clause-Clear
+module format.macho;
+
+import adbg.disassembler;
+import adbg.object.server;
+import adbg.object.format.macho;
+import dumper;
+
+int dump_macho(adbg_object_t *o) {
+ if (selected_headers)
+ dump_macho_hdr(o);
+
+ return 0;
+}
+
+private:
+
+void dump_macho_hdr(adbg_object_t *o) {
+ if (o.i.macho.fat) {
+ print_header("FAT Header");
+
+ with (o.i.macho.fat_header) {
+ print_x32("magic", magic, adbg_object_macho_magic_string(magic));
+ print_u32("nfat_arch", nfat_arch);
+ }
+
+ print_header("FAT Arch Header");
+
+ size_t i;
+ macho_fat_arch *fa = void;
+ while ((fa = adbg_object_macho_fat_arch(o, i++)) != null) with (fa) {
+ print_x32("cputype", cputype, adbg_object_macho_cputype_string(cputype));
+ print_x32("subtype", subtype, adbg_object_macho_subtype_string(cputype, subtype));
+ print_x32("offset", offset);
+ print_x32("size", size);
+ print_x32("alignment", alignment);
+ }
+ } else {
+ print_header("Header");
+
+ with (o.i.macho.header) {
+ print_x32("magic", magic, adbg_object_macho_magic_string(magic));
+ print_x32("cputype", cputype, adbg_object_macho_cputype_string(cputype));
+ print_x32("subtype", subtype, adbg_object_macho_subtype_string(cputype, subtype));
+ print_x32("filetype", filetype, adbg_object_macho_filetype_string(filetype));
+ print_u32("ncmds", ncmds);
+ print_u32("sizeofcmds", sizeofcmds);
+ print_flags32("flags", flags,
+ "NOUNDEFS".ptr, MACHO_FLAG_NOUNDEFS,
+ "INCRLINK".ptr, MACHO_FLAG_INCRLINK,
+ "DYLDLINK".ptr, MACHO_FLAG_DYLDLINK,
+ "BINDATLOAD".ptr, MACHO_FLAG_BINDATLOAD,
+ "PREBOUND".ptr, MACHO_FLAG_PREBOUND,
+ "SPLIT_SEGS".ptr, MACHO_FLAG_SPLIT_SEGS,
+ "LAZY_INIT".ptr, MACHO_FLAG_LAZY_INIT,
+ "TWOLEVEL".ptr, MACHO_FLAG_TWOLEVEL,
+ "FORCE_FLAT".ptr, MACHO_FLAG_FORCE_FLAT,
+ "NOMULTIDEFS".ptr, MACHO_FLAG_NOMULTIDEFS,
+ "NOFIXPREBINDING".ptr, MACHO_FLAG_NOFIXPREBINDING,
+ "PREBINDABLE".ptr, MACHO_FLAG_PREBINDABLE,
+ "ALLMODSBOUND".ptr, MACHO_FLAG_ALLMODSBOUND,
+ "SUBSECTIONS_VIA_SYMBOLS".ptr, MACHO_FLAG_SUBSECTIONS_VIA_SYMBOLS,
+ "CANONICAL".ptr, MACHO_FLAG_CANONICAL,
+ "WEAK_DEFINES".ptr, MACHO_FLAG_WEAK_DEFINES,
+ "BINDS_TO_WEAK".ptr, MACHO_FLAG_BINDS_TO_WEAK,
+ "ALLOW_STACK_EXECUTION".ptr, MACHO_FLAG_ALLOW_STACK_EXECUTION,
+ "ROOT_SAFE".ptr, MACHO_FLAG_ROOT_SAFE,
+ "SETUID_SAFE".ptr, MACHO_FLAG_SETUID_SAFE,
+ "NO_REEXPORTED_DYLIBS".ptr, MACHO_FLAG_NO_REEXPORTED_DYLIBS,
+ "PIE".ptr, MACHO_FLAG_PIE,
+ "DEAD_STRIPPABLE_DYLIB".ptr, MACHO_FLAG_DEAD_STRIPPABLE_DYLIB,
+ "HAS_TLV_DESCRIPTORS".ptr, MACHO_FLAG_HAS_TLV_DESCRIPTORS,
+ "NO_HEAP_EXECUTION".ptr, MACHO_FLAG_NO_HEAP_EXECUTION,
+ "APP_EXTENSION_SAFE".ptr, MACHO_FLAG_APP_EXTENSION_SAFE,
+ null);
+ }
+
+ print_header("Load commands");
+
+ size_t i;
+ macho_load_command *command = void;
+ while ((command = adbg_object_macho_load_command(o, i++)) != null) with (command) {
+ print_x32("cmd", cmd, adbg_object_macho_command_string(cmd));
+ print_x32("cmdsize", cmdsize);
+ }
+ }
+}
\ No newline at end of file
diff --git a/dumper/format/mdmp.d b/dumper/format/mdmp.d
new file mode 100644
index 0000000..61f0e4e
--- /dev/null
+++ b/dumper/format/mdmp.d
@@ -0,0 +1,163 @@
+/// Minidump dumper
+///
+/// Authors: dd86k
+/// Copyright: © dd86k
+/// License: BSD-3-Clause-Clear
+module format.mdmp;
+
+import adbg.disassembler;
+import adbg.object.server;
+import adbg.machines;
+import adbg.object.format.mdmp;
+import adbg.utils.date : ctime32;
+import adbg.include.windows.winnt;
+import dumper;
+import common.utils : realstring;
+
+int dump_minidump(adbg_object_t *o) {
+ if (selected_headers())
+ dump_minidump_headers(o);
+
+ //if (selected_debug())
+ // dump_minidump_debug(o);
+
+ return 0;
+}
+
+private:
+
+void dump_minidump_headers(adbg_object_t *o) {
+ print_header("Header");
+ with (o.i.mdmp.header) {
+ print_x32("Signature", Signature);
+ print_x16("Magic", Magic);
+ print_u16("Version", Version);
+ print_x32("StreamCount", StreamCount);
+ print_x32("StreamRva", StreamRva);
+ print_x32("Checksum", Checksum);
+ print_x32("Timestamp", Timestamp, ctime32(Timestamp));
+ print_flags64("Flags", Flags,
+ "WithDataSegs".ptr, MiniDumpWithDataSegs,
+ "WithFullMemory".ptr, MiniDumpWithFullMemory,
+ "WithHandleData".ptr, MiniDumpWithHandleData,
+ "FilterMemory".ptr, MiniDumpFilterMemory,
+ "ScanMemory".ptr, MiniDumpScanMemory,
+ "WithUnloadedModules".ptr, MiniDumpWithUnloadedModules,
+ "WithIndirectlyReferencedMemory".ptr, MiniDumpWithIndirectlyReferencedMemory,
+ "FilterModulePaths".ptr, MiniDumpFilterModulePaths,
+ "WithProcessThreadData".ptr, MiniDumpWithProcessThreadData,
+ "WithPrivateReadWriteMemory".ptr, MiniDumpWithPrivateReadWriteMemory,
+ "WithoutOptionalData".ptr, MiniDumpWithoutOptionalData,
+ "WithFullMemoryInfo".ptr, MiniDumpWithFullMemoryInfo,
+ "WithThreadInfo".ptr, MiniDumpWithThreadInfo,
+ "WithCodeSegs".ptr, MiniDumpWithCodeSegs,
+ "WithoutAuxiliaryState".ptr, MiniDumpWithoutAuxiliaryState,
+ "WithFullAuxiliaryState".ptr, MiniDumpWithFullAuxiliaryState,
+ "WithPrivateWriteCopyMemory".ptr, MiniDumpWithPrivateWriteCopyMemory,
+ "IgnoreInaccessibleMemory".ptr, MiniDumpIgnoreInaccessibleMemory,
+ "WithTokenInformation".ptr, MiniDumpWithTokenInformation,
+ "WithModuleHeaders".ptr, MiniDumpWithModuleHeaders,
+ "FilterTriage".ptr, MiniDumpFilterTriage,
+ "WithAvxXStateContext".ptr, MiniDumpWithAvxXStateContext,
+ "WithIptTrace".ptr, MiniDumpWithIptTrace,
+ "ScanInaccessiblePartialPages".ptr, MiniDumpScanInaccessiblePartialPages,
+ "FilterWriteCombinedMemory".ptr, MiniDumpFilterWriteCombinedMemory,
+ null);
+ }
+}
+
+void dump_minidump_debug(adbg_object_t *o) {
+ print_header("Debug");
+
+ uint cnt = o.i.mdmp.header.StreamCount;
+ uint off = o.i.mdmp.header.StreamRva;
+ mdmp_directory_entry *dir = void;
+ if (adbg_object_offsetl(o, cast(void**)&dir, off, cnt * mdmp_directory_entry.sizeof)) {
+ print_string("error", "Directory outside file bounds");
+ return;
+ }
+
+ for (uint i; i < cnt; ++i) {
+ mdmp_directory_entry *entry = &dir[i];
+
+ with (entry) {
+ print_x32("StreamType", StreamType);
+ print_x32("Size", Size);
+ print_x32("Rva", Rva);
+ }
+
+ switch (entry.StreamType) {
+ case ThreadListStream:
+ print_header("Threadlist");
+
+ mdmp_threadlist *tlist = void;
+ if (adbg_object_offsetl(o, cast(void**)&tlist,
+ entry.Rva, uint.sizeof + mdmp_thread.sizeof)) {
+ print_string("warning", "Threadlist.Rva points outbound");
+ continue;
+ }
+ for (uint ti; ti < tlist.Count; ++ti) {
+ mdmp_thread *thread = &tlist.Threads.ptr[ti];
+ print_section(ti);
+ print_x32("ID", thread.ID);
+ print_x32("SuspendCount", thread.SuspendCount);
+ print_x32("PriorityClass", thread.PriorityClass);
+ print_x32("Priority", thread.Priority);
+ print_x64("Teb", thread.Teb);
+
+ X86_NT_CONTEXT *context = void;
+ if (adbg_object_offsetl(o, cast(void**)&context,
+ thread.ThreadContext.Rva, thread.ThreadContext.Size)) {
+ print_string("warning", "Thread.Context.Rva points outbound");
+ continue;
+ }
+
+ print_x32("Eip", context.Eip);
+ }
+ break;
+ case ModuleListStream:
+ break;
+ case MemoryListStream:
+ break;
+ case ExceptionStream:
+ break;
+ case SystemInfoStream:
+ break;
+ case ThreadExListStream:
+ break;
+ case Memory64ListStream:
+ break;
+ case CommentStreamA:
+ break;
+ case CommentStreamW:
+ break;
+ case HandleDataStream:
+ break;
+ case FunctionTableStream:
+ break;
+ case UnloadedModuleListStream:
+ break;
+ case MiscInfoStream:
+ break;
+ case MemoryInfoListStream:
+ break;
+ case ThreadInfoListStream:
+ break;
+ case HandleOperationListStream:
+ break;
+ case TokenStream:
+ break;
+ case JavaScriptDataStream:
+ break;
+ case SystemMemoryInfoStream:
+ break;
+ case ProcessVmCountersStream:
+ break;
+ case IptTraceStream:
+ break;
+ case ThreadNamesStream:
+ break;
+ default: continue;
+ }
+ }
+}
\ No newline at end of file
diff --git a/dumper/format/mscoff.d b/dumper/format/mscoff.d
new file mode 100644
index 0000000..924e8d1
--- /dev/null
+++ b/dumper/format/mscoff.d
@@ -0,0 +1,71 @@
+/// MS-COFF dumper
+///
+/// Authors: dd86k
+/// Copyright: © dd86k
+/// License: BSD-3-Clause-Clear
+module format.mscoff;
+
+import adbg.disassembler;
+import adbg.object.server;
+import adbg.machines;
+import adbg.object.format.mscoff;
+import adbg.object.format.pe : adbg_object_pe_machine_string;
+import adbg.utils.uid;
+import dumper;
+
+int dump_mscoff(adbg_object_t *o) {
+ if (selected_headers())
+ dump_mscoff_hdr(o);
+
+ return 0;
+}
+
+private:
+
+void dump_mscoff_hdr(adbg_object_t *o) {
+ print_header("Header");
+
+ switch (o.i.mscoff.import_header.Version) {
+ case MSCOFF_VERSION_IMPORT: // 0
+ with (o.i.mscoff.import_header) {
+ print_x16("Sig1", Sig1);
+ print_x16("Sig2", Sig2);
+ print_u16("Version", Version);
+ print_x16("Machine", Machine, adbg_object_pe_machine_string(Machine));
+ print_x32("TimeStamp", TimeStamp);
+ print_x32("Size", Size);
+ print_x16("Ordinal", Ordinal);
+ print_x64("Flags", Flags);
+ }
+ break;
+ case MSCOFF_VERSION_ANON: // 1
+ with (o.i.mscoff.anon_header) {
+ print_x16("Sig1", Sig1);
+ print_x16("Sig2", Sig2);
+ print_u16("Version", Version);
+ print_x16("Machine", Machine, adbg_object_pe_machine_string(Machine));
+ print_x32("TimeDateStamp", TimeDateStamp);
+ char[UID_TEXTLEN] uid = void;
+ uid_text(ClassID, uid, UID_GUID);
+ print_string("ClassID", uid.ptr);
+ print_x32("SizeOfData", SizeOfData);
+ }
+ break;
+ case MSCOFF_VERSION_ANONV2: // 2
+ with (o.i.mscoff.anon_v2_header) {
+ print_x16("Sig1", Sig1);
+ print_x16("Sig2", Sig2);
+ print_u16("Version", Version);
+ print_x16("Machine", Machine, adbg_object_pe_machine_string(Machine));
+ print_x32("TimeDateStamp", TimeDateStamp);
+ char[UID_TEXTLEN] uid = void;
+ uid_text(ClassID, uid, UID_GUID);
+ print_string("ClassID", uid.ptr);
+ print_x32("SizeOfData", SizeOfData);
+ print_x32("Flags", Flags);
+ print_x32("MetaDataSize", MetaDataSize);
+ }
+ break;
+ default:
+ }
+}
\ No newline at end of file
diff --git a/dumper/format/mz.d b/dumper/format/mz.d
new file mode 100644
index 0000000..0a52ea3
--- /dev/null
+++ b/dumper/format/mz.d
@@ -0,0 +1,85 @@
+/// MS-DOS MZ file dumper
+///
+/// Authors: dd86k
+/// Copyright: © dd86k
+/// License: BSD-3-Clause-Clear
+module format.mz;
+
+import adbg.disassembler;
+import adbg.object.server;
+import adbg.machines : AdbgMachine;
+import adbg.object.format.mz;
+import dumper;
+
+extern (C):
+
+/// Print MZ object.
+/// Params:
+/// dump = Dumper instance.
+/// o = Object instance.
+/// Returns: Non-zero on error.
+int dump_mz(adbg_object_t *o) {
+ if (selected_headers())
+ dump_mz_hdr(o);
+
+ if (selected_relocs())
+ dump_mz_relocs(o);
+
+ if (setting_disasm_any())
+ dump_mz_disasm(o);
+
+ return 0;
+}
+
+private:
+
+void dump_mz_hdr(adbg_object_t *o) {
+ print_header("Header");
+
+ with (o.i.mz.header) {
+ print_u16("e_cblp", e_cblp);
+ print_u16("e_cp", e_cp);
+ print_u16("e_crlc", e_crlc);
+ print_u16("e_cparh", e_cparh);
+ print_u16("e_minalloc", e_minalloc);
+ print_u16("e_maxalloc", e_maxalloc);
+ print_x16("e_ss", e_ss);
+ print_x16("e_sp", e_sp);
+ print_x16("e_csum", e_csum);
+ print_x16("e_ip", e_ip);
+ print_x16("e_cs", e_cs);
+ print_x16("e_lfarlc", e_lfarlc);
+ print_u16("e_ovno", e_ovno);
+ }
+}
+
+void dump_mz_relocs(adbg_object_t *o) {
+ print_header("Relocations");
+
+ mz_reloc *reloc = void;
+ size_t i;
+ while ((reloc = adbg_object_mz_reloc(o, i++)) != null) with (reloc)
+ print_reloc16(cast(uint)i, segment, offset);
+}
+
+void dump_mz_disasm(adbg_object_t *o) {
+ // Get start of data
+ uint start = (o.i.mz.header.e_cparh << 4) + o.i.mz.header.e_cblp; // paragraphs * 16
+ if (start < mz_hdr.sizeof || start >= o.file_size) {
+ print_string("error", "Data start outside of file buffer");
+ return;
+ }
+
+ // Get data length
+ uint len = (o.i.mz.header.e_cp << 4) + o.i.mz.header.e_cblp; // paragraphs * 16
+ if (len == 0) {
+ print_string("error", "Length is zero");
+ return;
+ }
+ if (len > o.file_size) {
+ print_string("error", "Data length cannot be bigger than file");
+ return;
+ }
+
+ dump_disassemble_object(o, null, 0, o.buffer + start, len, 0);
+}
diff --git a/dumper/format/ne.d b/dumper/format/ne.d
new file mode 100644
index 0000000..a7c2fad
--- /dev/null
+++ b/dumper/format/ne.d
@@ -0,0 +1,64 @@
+/// Windows 1.x NE file dumper
+///
+/// Authors: dd86k
+/// Copyright: © dd86k
+/// License: BSD-3-Clause-Clear
+module format.ne;
+
+import adbg.disassembler;
+import adbg.object.server;
+import adbg.machines : AdbgMachine;
+import adbg.object.format.ne;
+import dumper;
+
+extern (C):
+
+int dump_ne(adbg_object_t *o) {
+ if (selected_headers())
+ dump_ne_hdr(o);
+ return 0;
+}
+
+private:
+
+void dump_ne_hdr(adbg_object_t *o) {
+ print_header("Header");
+
+ with (o.i.ne.header) {
+ print_x16("ne_magic", ne_magic);
+ print_u8("ne_ver", ne_ver);
+ print_u8("ne_rev", ne_rev);
+ print_x16("ne_enttab", ne_enttab);
+ print_u16("ne_cbenttab", ne_cbenttab);
+ print_x32("ne_crc", ne_crc);
+ print_flags16("ne_flags", ne_flags,
+ "SINGLEDATA".ptr, NE_HFLAG_SINGLEDATA,
+ "MULTIPLEDATA".ptr, NE_HFLAG_MULTIPLEDATA,
+ "LINKERERROR".ptr, NE_HFLAG_LINKERERROR,
+ "LIBMODULE".ptr, NE_HFLAG_LIBMODULE,
+ null);
+ print_u16("ne_autodata", ne_autodata);
+ print_u16("ne_heap", ne_heap);
+ print_u16("ne_stack", ne_stack);
+ print_x32("ne_csip", ne_csip);
+ print_x32("ne_sssp", ne_sssp);
+ print_u16("ne_cseg", ne_cseg);
+ print_u16("ne_cmod", ne_cmod);
+ print_u16("ne_cbnrestab", ne_cbnrestab);
+ print_x16("ne_segtab", ne_segtab);
+ print_x16("ne_rsrctab", ne_rsrctab);
+ print_x16("ne_restab", ne_restab);
+ print_x16("ne_modtab", ne_modtab);
+ print_x16("ne_imptab", ne_imptab);
+ print_x32("ne_nrestab", ne_nrestab);
+ print_u16("ne_cmovent", ne_cmovent);
+ print_u16("ne_align", ne_align);
+ print_u16("ne_cres", ne_cres);
+ print_u8("ne_exetyp", ne_exetyp, adbg_object_ne_type(ne_exetyp));
+ print_x8("ne_flagsothers", ne_flagsothers);
+ print_x16("ne_pretthunks", ne_pretthunks);
+ print_x16("ne_psegrefbytes", ne_psegrefbytes);
+ print_x16("ne_swaparea", ne_swaparea);
+ print_x16("ne_expver", ne_expver);
+ }
+}
\ No newline at end of file
diff --git a/dumper/format/package.d b/dumper/format/package.d
new file mode 100644
index 0000000..239a892
--- /dev/null
+++ b/dumper/format/package.d
@@ -0,0 +1,21 @@
+// Format meta package
+//
+// Authors: dd86k
+// Copyright: © dd86k
+// License: BSD-3-Clause-Clear
+module format;
+
+public import
+ format.mz,
+ format.ne,
+ format.lx,
+ format.pe,
+ format.elf,
+ format.macho,
+ format.pdb70,
+ format.pdb20,
+ format.mdmp,
+ format.dmp,
+ format.ar,
+ format.coff,
+ format.mscoff;
\ No newline at end of file
diff --git a/dumper/format/pdb20.d b/dumper/format/pdb20.d
new file mode 100644
index 0000000..16da4dc
--- /dev/null
+++ b/dumper/format/pdb20.d
@@ -0,0 +1,39 @@
+/// PDB 2.00 dumper
+///
+/// Authors: dd86k
+/// Copyright: © dd86k
+/// License: BSD-3-Clause-Clear
+module format.pdb20;
+
+import adbg.disassembler;
+import adbg.object.server;
+import adbg.machines;
+import adbg.object.format.pdb;
+import dumper;
+
+extern (C):
+
+int dump_pdb20(adbg_object_t *o) {
+ if (selected_headers())
+ dump_pdb20_header(o);
+
+ return 0;
+}
+
+private:
+
+void dump_pdb20_header(adbg_object_t *o) {
+ print_header("Header");
+
+ pdb20_file_header *header = adbg_object_pdb20_header(o);
+
+ with (header) {
+ print_stringl("Magic", header.Magic.ptr, 37);
+ print_u32("PageSize", PageSize);
+ print_u16("StartPage", StartPage);
+ print_u16("PageCount", PageCount);
+ print_u32("RootSize", RootSize);
+ print_x32("Reserved", Reserved);
+ print_u16("RootNumber", RootNumber);
+ }
+}
\ No newline at end of file
diff --git a/dumper/format/pdb70.d b/dumper/format/pdb70.d
new file mode 100644
index 0000000..ca5cf91
--- /dev/null
+++ b/dumper/format/pdb70.d
@@ -0,0 +1,280 @@
+/// PDB 7.00 dumper
+///
+/// Authors: dd86k
+/// Copyright: © dd86k
+/// License: BSD-3-Clause-Clear
+module format.pdb70;
+
+import adbg.disassembler;
+import adbg.object.server;
+import adbg.machines;
+import adbg.object.format.pdb;
+import adbg.object.format.pe : adbg_object_pe_machine_string;
+import adbg.utils.uid;
+import adbg.utils.date;
+import adbg.include.c.stdio : printf, snprintf, putchar;
+import dumper;
+
+extern (C):
+
+int dump_pdb70(adbg_object_t *o) {
+ if (selected_headers())
+ dump_pdb70_header(o);
+
+ if (selected_debug())
+ dump_pdb70_debug(o);
+
+ return 0;
+}
+
+private:
+
+void dump_pdb70_header(adbg_object_t *o) {
+ print_header("Header");
+
+ pdb70_file_header *header = adbg_object_pdb70_header(o);
+
+ print_stringl("Magic", header.Magic.ptr, 24);
+ print_u32("PageSize", header.PageSize);
+ print_u32("FreeIndex", header.FreeIndex);
+ print_u32("PageCount", header.PageCount);
+ print_u32("DirectorySize", header.DirectorySize);
+ print_x32("Unknown", header.Unknown);
+ print_x32("DirectoryOffset", header.DirectoryOffset);
+
+ print_header("FPM information");
+ uint bitcnt = header.PageCount / 8;
+ for (uint biti; biti < bitcnt; ++biti) {
+ char[48] buf = void;
+ uint blocknum = biti * 8;
+ snprintf(buf.ptr, 48, "Block %u-%u", blocknum, blocknum + 7);
+ print_x8(buf.ptr, o.i.pdb70.fpm[biti]);
+ }
+
+ print_header("Stream information");
+ print_u32("Stream count", o.i.pdb70.strcnt);
+ uint strcnt = o.i.pdb70.strcnt;
+ uint blkoffi;
+ // NOTE: Avoid using internal section map in case it changes
+ for (uint stri; stri < strcnt; ++stri) {
+ uint size = o.i.pdb70.strsize[stri];
+
+ // Print field name
+ char[48] buf = void;
+ snprintf(buf.ptr, 48, "Stream %u", stri);
+ print_name(buf.ptr);
+
+ // Skip if empty
+ //TODO: Check with FPM?
+ if (size == 0 || size == PDB_BLOCK_SIZE_UNUSED) {
+ putchar('\n');
+ continue;
+ }
+
+ // Print size + associated blocks
+ printf("%u\t(", size);
+ uint blkcnt = (size + header.PageSize - 1) / header.PageSize;
+ for (uint blki; blki < blkcnt; ++blki) {
+ if (blki) putchar(',');
+ printf("%u", o.i.pdb70.stroff[blkoffi++]);
+ }
+ printf(")\n");
+ }
+}
+
+void dump_pdb70_debug(adbg_object_t *o) {
+ print_header("Debug");
+
+ static immutable string[] StreamNames = [
+ "Old MSF Directory",
+ "PDB Stream",
+ "TPI Stream",
+ "DBI Stream",
+ "IPI Stream",
+ ];
+
+ void *buffer;
+ uint strsize;
+
+ // Stream 0 - Old MSF directory
+
+ print_section(0, StreamNames[0].ptr, cast(int)StreamNames[0].length);
+ if (adbg_object_pdb70_stream_open(o, &buffer, &strsize, PdbStream.pdb)) {
+ print_string("error", "Couldn't read Stream 0");
+ return;
+ }
+ if (strsize) {
+ print_hexdump("Stream 0 Data", buffer, strsize);
+ }
+ adbg_object_pdb70_stream_close(o, &buffer);
+
+ // Stream 1
+
+ print_section(1, StreamNames[1].ptr, cast(int)StreamNames[1].length);
+ if (adbg_object_pdb70_stream_open(o, &buffer, &strsize, PdbStream.pdb)) {
+ print_string("error", "Couldn't read Stream 1");
+ return;
+ }
+ if (strsize >= pdb70_pdb_header.sizeof) {
+ pdb70_pdb_header *pdb = cast(pdb70_pdb_header*)buffer;
+ const(char) *vcver = void;
+ switch (pdb.Version) with (PdbRaw_PdbVersion) {
+ case vc2: vcver = "VC2"; break;
+ case vc4: vcver = "VC4"; break;
+ case vc41: vcver = "VC41"; break;
+ case vc50: vcver = "VC50"; break;
+ case vc98: vcver = "VC98"; break;
+ case vc70_old: vcver = "VC70_OLD"; break;
+ case vc70: vcver = "VC70"; break;
+ case vc80: vcver = "VC80"; break;
+ case vc110: vcver = "VC110"; break;
+ case vc140: vcver = "VC140"; break;
+ default: vcver = "Unknown";
+ }
+
+ char[UID_TEXTLEN] uidstr = void;
+ int uidlen = uid_string(pdb.UniqueId, uidstr.ptr, UID_TEXTLEN, UID_GUID);
+ print_u32("Version", pdb.Version, vcver);
+ print_x32("Signature", pdb.Signature);
+ print_u32("Age", pdb.Age);
+ print_stringl("UniqueID", uidstr.ptr, uidlen);
+
+ /*void *leftover = buffer + pdb70_pdb_header.sizeof;
+ size_t leftlen = strsize - pdb70_pdb_header.sizeof;
+
+ print_raw("Stream 1 Data", leftover, leftlen);*/
+ }
+ adbg_object_pdb70_stream_close(o, &buffer);
+
+ // Stream 2
+
+ print_section(2, StreamNames[2].ptr, cast(int)StreamNames[2].length);
+ if (adbg_object_pdb70_stream_open(o, &buffer, &strsize, PdbStream.tpi)) {
+ print_string("error", "Couldn't read Stream 2");
+ return;
+ }
+ if (strsize >= pdb70_tpi_header.sizeof) {
+ pdb70_tpi_header *tpi = cast(pdb70_tpi_header*)buffer;
+ const(char) *vcver = void;
+ switch (tpi.Version) with (PdbRaw_TpiVer) {
+ case v40: vcver = "v40"; break;
+ case v41: vcver = "v41"; break;
+ case v50: vcver = "v50"; break;
+ case v70: vcver = "v70"; break;
+ case v80: vcver = "v80"; break;
+ default: vcver = "Unknown";
+ }
+
+ print_u32("Version", tpi.Version, vcver);
+ print_u32("HeaderSize", tpi.HeaderSize);
+ print_u32("TypeIndexBegin", tpi.TypeIndexBegin);
+ print_u32("TypeIndexEnd", tpi.TypeIndexEnd);
+ print_u32("TypeRecordBytes", tpi.TypeRecordBytes);
+
+ print_u16("HashStreamIndex", tpi.HashStreamIndex);
+ print_u16("HashAuxStreamIndex", tpi.HashAuxStreamIndex);
+ print_u32("HashKeySize", tpi.HashKeySize);
+ print_u32("NumHashBuckets", tpi.NumHashBuckets);
+
+ print_u32("HashValueBufferOffset", tpi.HashValueBufferOffset);
+ print_u32("HashValueBufferLength", tpi.HashValueBufferLength);
+
+ print_u32("IndexOffsetBufferOffset", tpi.IndexOffsetBufferOffset);
+ print_u32("IndexOffsetBufferLength", tpi.IndexOffsetBufferLength);
+
+ print_u32("HashAdjBufferOffset", tpi.HashAdjBufferOffset);
+ print_u32("HashAdjBufferLength", tpi.HashAdjBufferLength);
+
+ /*void *leftover = buffer + pdb70_tpi_header.sizeof;
+ size_t leftlen = strsize - pdb70_tpi_header.sizeof;
+
+ print_raw("Stream 2 Data", leftover, leftlen);*/
+ }
+ adbg_object_pdb70_stream_close(o, &buffer);
+
+ // Stream 3
+
+ print_section(3, StreamNames[3].ptr, cast(int)StreamNames[3].length);
+ if (adbg_object_pdb70_stream_open(o, &buffer, &strsize, PdbStream.dbi)) {
+ print_string("error", "Couldn't read Stream 3");
+ return;
+ }
+ if (strsize >= pdb70_dbi_header.sizeof) {
+ pdb70_dbi_header *dbi = cast(pdb70_dbi_header*)buffer;
+
+ const(char) *vcver = void;
+ switch (dbi.VersionHeader) with (PdbRaw_DbiVer) {
+ case v41: vcver = "v41"; break;
+ case v50: vcver = "v50"; break;
+ case v60: vcver = "v60"; break;
+ case v70: vcver = "v70"; break;
+ case v110: vcver = "v110"; break;
+ default: vcver = "Unknown";
+ }
+
+ // 255.127-1
+ char[16] buildnum = void;
+ snprintf(buildnum.ptr, 16, "%u.%u-%u",
+ dbi.BuildNumber >> 8 & 0x7f, // MajorVersion
+ cast(ubyte)dbi.BuildNumber, // MinorVersion
+ dbi.BuildNumber >> 15); // NewVersionFormat
+
+ print_x32("VersonSignature", dbi.VersonSignature);
+ print_u32("VersionHeader", dbi.VersionHeader, vcver);
+ print_u32("Age", dbi.Age);
+ print_u16("GlobalStreamIndex", dbi.GlobalStreamIndex);
+ print_x16("BuildNumber", dbi.BuildNumber, buildnum.ptr);
+ print_u16("PublicStreamIndex", dbi.PublicStreamIndex);
+ print_u16("PdbDllVersion", dbi.PdbDllVersion);
+ print_u16("SymRecordStream", dbi.SymRecordStream);
+ print_u16("PdbDllRbld", dbi.PdbDllRbld);
+ print_u32("ModInfoSize", dbi.ModInfoSize);
+ print_u32("SectionContributionSize", dbi.SectionContributionSize);
+ print_u32("SectionMapSize", dbi.SectionMapSize);
+ print_u32("SourceInfoSize", dbi.SourceInfoSize);
+ print_u32("TypeServerMapSize", dbi.TypeServerMapSize);
+ print_u32("MFCTypeServerIndex", dbi.MFCTypeServerIndex);
+ print_u32("OptionalDbgHeaderSize", dbi.OptionalDbgHeaderSize);
+ print_u32("ECSubstreamSize", dbi.ECSubstreamSize);
+ print_flags16("Flags", dbi.Flags,
+ "IncrementallyLinked".ptr, PdbRaw_DbiFlags.IncrementallyLinked,
+ "PrivateSymbolsStripped".ptr, PdbRaw_DbiFlags.PrivateSymbolsStripped,
+ "ConflictingTypes".ptr, PdbRaw_DbiFlags.ConflictingTypes,
+ null);
+ print_x16("Machine", dbi.Machine, adbg_object_pe_machine_string(dbi.Machine));
+ print_u32("Padding", dbi.Padding);
+
+ /*void *leftover = buffer + pdb70_dbi_header.sizeof;
+ size_t leftlen = strsize - pdb70_dbi_header.sizeof;
+
+ print_raw("Stream 3 Data", leftover, leftlen);*/
+ }
+ adbg_object_pdb70_stream_close(o, &buffer);
+
+ // Stream 4
+ /+print_section(4, StreamNames[4].ptr, cast(int)StreamNames[4].length);
+ if (adbg_object_pdb70_stream_open(o, &buffer, &strsize, PdbStream.dbi)) {
+ print_string("error", "Couldn't read Stream 3");
+ return;
+ }
+ if (strsize >= pdb70_subsection_header.sizeof) {
+ pdb70_subsection_header *ipi = cast(pdb70_subsection_header*)buffer;
+
+ enum LIMIT = 200; // Arbitrary
+
+ size_t i;
+ Lr:
+ print_x32("Kind", ipi.Kind);
+ print_x32("Length", ipi.Length);
+
+ ipi = cast(pdb70_subsection_header*)((cast(void*)ipi) + ipi.Length);
+ if (ipi.Kind && ipi.Length && ++i < LIMIT) goto Lr;
+ }
+ adbg_object_pdb70_stream_close(o, &buffer);+/
+
+ /*uint strcnt = o.i.pdb70.strcnt;
+ for (uint stridx = 5; stridx < strcnt; ++stridx) {
+ char[32] buf = void;
+ int l = snprintf(buf.ptr, 32, "Stream %u", stridx);
+ }*/
+}
\ No newline at end of file
diff --git a/dumper/format/pe.d b/dumper/format/pe.d
new file mode 100644
index 0000000..d1996aa
--- /dev/null
+++ b/dumper/format/pe.d
@@ -0,0 +1,805 @@
+/// PE32 file dumper
+///
+/// Authors: dd86k
+/// Copyright: © dd86k
+/// License: BSD-3-Clause-Clear
+module format.pe;
+
+import adbg.disassembler;
+import adbg.object.server;
+import adbg.machines : AdbgMachine;
+import adbg.object.format.pe;
+import adbg.utils.date : ctime32;
+import adbg.utils.uid, adbg.utils.bit;
+import core.stdc.string : strncmp;
+import dumper;
+
+extern (C):
+
+/// Print PE object.
+/// Params:
+/// dump = Dumper instance.
+/// o = Object instance.
+/// Returns: Non-zero on error.
+int dump_pe(adbg_object_t *o) {
+ if (selected_headers())
+ dump_pe_hdr(o);
+
+ if (selected_sections())
+ dump_pe_sections(o);
+
+ if (selected_exports())
+ dump_pe_exports(o);
+
+ if (selected_imports())
+ dump_pe_imports(o);
+
+ if (selected_debug())
+ dump_pe_debug(o);
+
+ if (setting_disasm_any())
+ dump_pe_disasm(o);
+
+ return 0;
+}
+
+private:
+
+// Returns true if the machine value is unknown
+void dump_pe_hdr(adbg_object_t *o) {
+ print_header("Header");
+
+ const(char) *str_mach = adbg_object_pe_machine_string(o.i.pe.header.Machine);
+
+ if (str_mach == null)
+ str_mach = "Unknown";
+
+ with (o.i.pe.header) {
+ print_x32("Machine", Machine, str_mach);
+ print_u32("NumberOfSections", NumberOfSections);
+ print_x32("TimeDateStamp", TimeDateStamp, ctime32(TimeDateStamp));
+ print_x32("PointerToSymbolTable", PointerToSymbolTable);
+ print_u32("NumberOfSymbols", NumberOfSymbols);
+ print_u32("SizeOfOptionalHeader", SizeOfOptionalHeader);
+ print_flags32("Characteristics", Characteristics,
+ "RELOCS_STRIPPED".ptr, PE_CHARACTERISTIC_RELOCS_STRIPPED,
+ "EXECUTABLE_IMAGE".ptr, PE_CHARACTERISTIC_EXECUTABLE_IMAGE,
+ "LINE_NUMS_STRIPPED".ptr, PE_CHARACTERISTIC_LINE_NUMS_STRIPPED,
+ "LOCAL_SYMS_STRIPPED".ptr, PE_CHARACTERISTIC_LOCAL_SYMS_STRIPPED,
+ "AGGRESSIVE_WS_TRIM".ptr, PE_CHARACTERISTIC_AGGRESSIVE_WS_TRIM,
+ "LARGE_ADDRESS_AWARE".ptr, PE_CHARACTERISTIC_LARGE_ADDRESS_AWARE,
+ "16BIT_MACHINE".ptr, PE_CHARACTERISTIC_16BIT_MACHINE,
+ "BYTES_REVERSED_LO".ptr, PE_CHARACTERISTIC_BYTES_REVERSED_LO,
+ "32BIT_MACHINE".ptr, PE_CHARACTERISTIC_32BIT_MACHINE,
+ "DEBUG_STRIPPED".ptr, PE_CHARACTERISTIC_DEBUG_STRIPPED,
+ "REMOVABLE_RUN_FROM_SWAP".ptr, PE_CHARACTERISTIC_REMOVABLE_RUN_FROM_SWAP,
+ "NET_RUN_FROM_SWAP".ptr, PE_CHARACTERISTIC_NET_RUN_FROM_SWAP,
+ "SYSTEM".ptr, PE_CHARACTERISTIC_SYSTEM,
+ "DLL".ptr, PE_CHARACTERISTIC_DLL,
+ "UP_SYSTEM_ONLY".ptr, PE_CHARACTERISTIC_UP_SYSTEM_ONLY,
+ "BYTES_REVERSED_HI".ptr, PE_CHARACTERISTIC_BYTES_REVERSED_HI,
+ null);
+ }
+
+ if (str_mach == null)
+ return;
+ //TODO: Could be a server check
+ if (o.i.pe.header.SizeOfOptionalHeader == 0)
+ return;
+
+ dump_pe_opthdr(o);
+}
+
+void dump_pe_opthdr(adbg_object_t *o) {
+ print_header("Optional Header");
+
+ // NOTE: Server already checks magic format
+ const(char) *str_mag = adbg_object_pe_magic_string(o.i.pe.opt_header.Magic);
+ const(char) *str_sys = adbg_object_pe_subsys_string(o.i.pe.opt_header.Subsystem);
+ if (str_sys == null)
+ str_sys = "Unknown";
+
+ // Common in all magic formats
+ with (o.i.pe.opt_header) {
+ print_x16("Magic", Magic, str_mag);
+ print_u8("MajorLinkerVersion", MajorLinkerVersion);
+ print_u8("MinorLinkerVersion", MinorLinkerVersion);
+ print_u32("SizeOfCode", SizeOfCode);
+ print_u32("SizeOfInitializedData", SizeOfInitializedData);
+ print_u32("SizeOfUninitializedData", SizeOfUninitializedData);
+ print_x32("AddressOfEntryPoint", AddressOfEntryPoint);
+ print_x32("BaseOfCode", BaseOfCode);
+ }
+
+ switch (o.i.pe.opt_header.Magic) {
+ case PE_FMT_32: // 32
+ with (o.i.pe.opt_header) {
+ print_x32("BaseOfData", BaseOfData);
+ print_x32("ImageBase", ImageBase);
+ print_u32("SectionAlignment", SectionAlignment);
+ print_u32("FileAlignment", FileAlignment);
+ print_u16("MajorOperatingSystemVersion", MajorOperatingSystemVersion);
+ print_u16("MinorOperatingSystemVersion", MinorOperatingSystemVersion);
+ print_u16("MajorImageVersion", MajorImageVersion);
+ print_u16("MinorImageVersion", MinorImageVersion);
+ print_u16("MajorSubsystemVersion", MajorSubsystemVersion);
+ print_u16("MinorSubsystemVersion", MinorSubsystemVersion);
+ print_x32("Win32VersionValue", Win32VersionValue);
+ print_u32("SizeOfImage", SizeOfImage);
+ print_u32("SizeOfHeaders", SizeOfHeaders);
+ print_x32("CheckSum", CheckSum);
+ print_x16("Subsystem", Subsystem, str_sys);
+ dump_pe_dllcharactiristics(DllCharacteristics);
+ print_x32("SizeOfStackReserve", SizeOfStackReserve);
+ print_x32("SizeOfStackCommit", SizeOfStackCommit);
+ print_x32("SizeOfHeapReserve", SizeOfHeapReserve);
+ print_x32("SizeOfHeapCommit", SizeOfHeapCommit);
+ print_x32("LoaderFlags", LoaderFlags);
+ print_u32("NumberOfRvaAndSizes", NumberOfRvaAndSizes);
+ }
+ break;
+ case PE_FMT_64: // 64
+ with (o.i.pe.opt_header64) {
+ print_x64("ImageBase", ImageBase);
+ print_x32("SectionAlignment", SectionAlignment);
+ print_x32("FileAlignment", FileAlignment);
+ print_u16("MajorOperatingSystemVersion", MajorOperatingSystemVersion);
+ print_u16("MinorOperatingSystemVersion", MinorOperatingSystemVersion);
+ print_u16("MajorImageVersion", MajorImageVersion);
+ print_u16("MinorImageVersion", MinorImageVersion);
+ print_u16("MajorSubsystemVersion", MajorSubsystemVersion);
+ print_u16("MinorSubsystemVersion", MinorSubsystemVersion);
+ print_x32("Win32VersionValue", Win32VersionValue);
+ print_u32("SizeOfImage", SizeOfImage);
+ print_u32("SizeOfHeaders", SizeOfHeaders);
+ print_x32("CheckSum", CheckSum);
+ print_u32("Subsystem", Subsystem, str_sys);
+ dump_pe_dllcharactiristics(DllCharacteristics);
+ print_u64("SizeOfStackReserve", SizeOfStackReserve);
+ print_u64("SizeOfStackCommit", SizeOfStackCommit);
+ print_u64("SizeOfHeapReserve", SizeOfHeapReserve);
+ print_u64("SizeOfHeapCommit", SizeOfHeapCommit);
+ print_x32("LoaderFlags", LoaderFlags);
+ print_u32("NumberOfRvaAndSizes", NumberOfRvaAndSizes);
+ }
+ break;
+ case PE_FMT_ROM: // ROM has no flags/directories
+ with (o.i.pe.opt_headerrom) {
+ print_x32("BaseOfData", BaseOfData);
+ print_x32("BaseOfBss", BaseOfBss);
+ print_x32("GprMask", GprMask);
+ print_x32("CprMask[0]", CprMask[0]);
+ print_x32("CprMask[1]", CprMask[1]);
+ print_x32("CprMask[2]", CprMask[2]);
+ print_x32("CprMask[3]", CprMask[3]);
+ print_x32("GpValue", GpValue);
+ }
+ return;
+ default:
+ }
+
+ dump_pe_dirs(o);
+}
+
+void dump_pe_dllcharactiristics(ushort dllchars) {
+ print_flags16("DllCharacteristics", dllchars,
+ "HIGH_ENTROPY_VA".ptr, PE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA,
+ "DYNAMIC_BASE".ptr, PE_DLLCHARACTERISTICS_DYNAMIC_BASE,
+ "FORCE_INTEGRITY".ptr, PE_DLLCHARACTERISTICS_FORCE_INTEGRITY,
+ "NX_COMPAT".ptr, PE_DLLCHARACTERISTICS_NX_COMPAT,
+ "NO_ISOLATION".ptr, PE_DLLCHARACTERISTICS_NO_ISOLATION,
+ "NO_SEH".ptr, PE_DLLCHARACTERISTICS_NO_SEH,
+ "NO_BIND".ptr, PE_DLLCHARACTERISTICS_NO_BIND,
+ "APPCONTAINER".ptr, PE_DLLCHARACTERISTICS_APPCONTAINER,
+ "WDM_DRIVER".ptr, PE_DLLCHARACTERISTICS_WDM_DRIVER,
+ "GUARD_CF".ptr, PE_DLLCHARACTERISTICS_GUARD_CF,
+ "TERMINAL_SERVER_AWARE".ptr, PE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE,
+ null);
+}
+
+void dump_pe_dirs(adbg_object_t *o) {
+ // ROM check
+ //TODO: Make this a server check
+ if (o.i.pe.directory == null)
+ return;
+
+ print_header("Directories");
+
+ with (o.i.pe.directory) {
+ print_directory_entry("ExportTable", ExportTable.rva, ExportTable.size);
+ print_directory_entry("ImportTable", ImportTable.rva, ImportTable.size);
+ print_directory_entry("ResourceTable", ResourceTable.rva, ResourceTable.size);
+ print_directory_entry("ExceptionTable", ExceptionTable.rva, ExceptionTable.size);
+ print_directory_entry("CertificateTable", CertificateTable.rva, CertificateTable.size);
+ print_directory_entry("BaseRelocationTable", BaseRelocationTable.rva, BaseRelocationTable.size);
+ print_directory_entry("DebugDirectory", DebugDirectory.rva, DebugDirectory.size);
+ print_directory_entry("ArchitectureData", ArchitectureData.rva, ArchitectureData.size);
+ print_directory_entry("GlobalPtr", GlobalPtr.rva, GlobalPtr.size);
+ print_directory_entry("TLSTable", TLSTable.rva, TLSTable.size);
+ print_directory_entry("LoadConfigurationTable", LoadConfigurationTable.rva, LoadConfigurationTable.size);
+ print_directory_entry("BoundImportTable", BoundImportTable.rva, BoundImportTable.size);
+ print_directory_entry("ImportAddressTable", ImportAddressTable.rva, ImportAddressTable.size);
+ print_directory_entry("DelayImport", DelayImport.rva, DelayImport.size);
+ print_directory_entry("CLRHeader", CLRHeader.rva, CLRHeader.size);
+ print_directory_entry("Reserved", Reserved.rva, Reserved.size);
+ }
+}
+
+void dump_pe_sections(adbg_object_t *o) {
+ print_header("Sections");
+
+ PE_SECTION_ENTRY *section = void;
+ size_t i;
+ while ((section = adbg_object_pe_section(o, i++)) != null) with (section) {
+ // If we're searching sections, match and don't print yet
+ if (opt_section) {
+ if (strncmp(Name.ptr, opt_section, Name.sizeof))
+ continue;
+
+ void *data = o.buffer + PointerToRawData;
+
+ if (setting_hexdump())
+ print_hexdump(opt_section, data, SizeOfRawData, PointerToRawData);
+
+ if (setting_extract())
+ print_rawdump(data, SizeOfRawData);
+ }
+
+ print_section(cast(uint)i, Name.ptr, 8);
+ print_x32("VirtualAddress", VirtualAddress);
+ print_x32("VirtualSize", VirtualSize);
+ print_x32("PointerToRawData", PointerToRawData);
+ print_x32("SizeOfRawData", SizeOfRawData);
+ print_x32("PointerToRelocations", PointerToRelocations);
+ print_x32("PointerToLinenumbers", PointerToLinenumbers);
+ print_u16("NumberOfRelocations", NumberOfRelocations);
+ print_u16("NumberOfLinenumbers", NumberOfLinenumbers);
+ //TODO: Integrate with rest of Characteristics
+ static immutable const(char)*[] pe32alignments = [
+ "ALIGN_DEFAULT(16)", // PEDUMP (1997)
+ "ALIGN_1BYTES",
+ "ALIGN_2BYTES",
+ "ALIGN_4BYTES",
+ "ALIGN_8BYTES",
+ "ALIGN_16BYTES",
+ "ALIGN_32BYTES",
+ "ALIGN_64BYTES",
+ "ALIGN_128BYTES",
+ "ALIGN_256BYTES",
+ "ALIGN_512BYTES",
+ "ALIGN_1024BYTES",
+ "ALIGN_2048BYTES",
+ "ALIGN_4096BYTES",
+ "ALIGN_8192BYTES",
+ "ALIGN_RESERVED",
+ ];
+ uint alignment = Characteristics & PE_SECTION_CHARACTERISTIC_ALIGN_MASK;
+ print_x32("Alignment", alignment, pe32alignments[alignment >> 20]);
+ print_flags32("Characteristics", Characteristics,
+ "TYPE_DSECT".ptr, PE_SECTION_CHARACTERISTIC_TYPE_DSECT,
+ "TYPE_NOLOAD".ptr, PE_SECTION_CHARACTERISTIC_TYPE_NOLOAD,
+ "TYPE_GROUP".ptr, PE_SECTION_CHARACTERISTIC_TYPE_GROUP,
+ "NO_PAD".ptr, PE_SECTION_CHARACTERISTIC_NO_PAD,
+ "TYPE_COPY".ptr, PE_SECTION_CHARACTERISTIC_TYPE_COPY,
+ "CODE".ptr, PE_SECTION_CHARACTERISTIC_CODE,
+ "INITIALIZED_DATA".ptr, PE_SECTION_CHARACTERISTIC_INITIALIZED_DATA,
+ "UNINITIALIZED_DATA".ptr, PE_SECTION_CHARACTERISTIC_UNINITIALIZED_DATA,
+ "LNK_OTHER".ptr, PE_SECTION_CHARACTERISTIC_LNK_OTHER,
+ "LNK_INFO".ptr, PE_SECTION_CHARACTERISTIC_LNK_INFO,
+ "LNK_REMOVE".ptr, PE_SECTION_CHARACTERISTIC_LNK_REMOVE,
+ "LNK_COMDAT".ptr, PE_SECTION_CHARACTERISTIC_LNK_COMDAT,
+ "MEM_PROTECTED".ptr, PE_SECTION_CHARACTERISTIC_MEM_PROTECTED,
+ "GPREL".ptr, PE_SECTION_CHARACTERISTIC_GPREL,
+ "MEM_PURGEABLE".ptr, PE_SECTION_CHARACTERISTIC_MEM_PURGEABLE,
+ "MEM_16BIT".ptr, PE_SECTION_CHARACTERISTIC_MEM_16BIT,
+ "MEM_LOCKED".ptr, PE_SECTION_CHARACTERISTIC_MEM_LOCKED,
+ "PRELOAD".ptr, PE_SECTION_CHARACTERISTIC_PRELOAD,
+ "LNK_NRELOC_OVFL".ptr, PE_SECTION_CHARACTERISTIC_LNK_NRELOC_OVFL,
+ "MEM_DISCARDABLE".ptr, PE_SECTION_CHARACTERISTIC_MEM_DISCARDABLE,
+ "MEM_NOT_CACHED".ptr, PE_SECTION_CHARACTERISTIC_MEM_NOT_CACHED,
+ "MEM_NOT_PAGED".ptr, PE_SECTION_CHARACTERISTIC_MEM_NOT_PAGED,
+ "MEM_SHARED".ptr, PE_SECTION_CHARACTERISTIC_MEM_SHARED,
+ "MEM_EXECUTE".ptr, PE_SECTION_CHARACTERISTIC_MEM_EXECUTE,
+ "MEM_READ".ptr, PE_SECTION_CHARACTERISTIC_MEM_READ,
+ "MEM_WRITE".ptr, PE_SECTION_CHARACTERISTIC_MEM_WRITE,
+ null);
+
+ }
+}
+
+/*void dump_pe_loadconfig(ref Dumper dump) {
+
+ dump_h1("Load Configuration");
+
+ if (dump.obj.pe.loadconfig == null) { // LOAD_CONFIGURATION
+ puts("No
+ }
+ if (fseek(dump.obj.handle, fo_loadcf, SEEK_SET))
+ return EXIT_FAILURE;
+
+ PE_LOAD_CONFIG_META lconf = void;
+ char[32] lcbuffer = void;
+
+ if (fread(&lconf, 4, 1, obj.handle) == 0)
+ return EXIT_FAILURE;
+ if (fread(&lconf.dir32.TimeDateStamp, lconf.dir32.Size, 1, obj.handle) == 0)
+ return EXIT_FAILURE;
+
+ if (strftime(cast(char*)lcbuffer, 32, "%c",
+ localtime(cast(time_t*)&lconf.dir64.TimeDateStamp)) == 0) {
+ const(char)* l = cast(char*)&lcbuffer;
+ l = "strftime:err";
+ }
+
+ with (lconf.dir32)
+ printf( // Same sizes/offsets
+ "\n*\n* Load Config\n*\n\n"~
+ "Size %08X\t(%u)\n"~
+ "TimeDateStamp %08X\t(%s)\n"~
+ "MajorVersion %04X\t(%u)\n"~
+ "MinorVersion %04X\t(%u)\n"~
+ "GlobalFlagsClear %08X\n"~
+ "GlobalFlagsSet %08X\n"~
+ "CriticalSectionDefaultTimeout %08X\n",
+ Size, Size,
+ TimeDateStamp, &lcbuffer,
+ MajorVersion, lconf.dir32.MajorVersion,
+ MinorVersion, lconf.dir32.MinorVersion,
+ GlobalFlagsClear,
+ GlobalFlagsSet,
+ CriticalSectionDefaultTimeout);
+
+ if (dump.optMagic != PE_FMT_64) { // 32
+ with (lconf.dir32)
+ printf(
+ "DeCommitFreeBlockThreshold %08X\n"~
+ "DeCommitTotalBlockThreshold %08X\n"~
+ "LockPrefixTable %08X\n"~
+ "MaximumAllocationSize %08X\t(%u)\n"~
+ "VirtualMemoryThreshold %08X\n"~
+ "ProcessHeapFlags %08X\n"~
+ "ProcessAffinityMask %08X\n"~
+ "CSDVersion %04X\n"~
+ "Reserved1 %04X\n"~
+ "EditList %08X\n"~
+ "SecurityCookie %08X\n",
+ DeCommitFreeBlockThreshold,
+ DeCommitTotalBlockThreshold,
+ LockPrefixTable,
+ MaximumAllocationSize, lconf.dir32.MaximumAllocationSize,
+ VirtualMemoryThreshold,
+ ProcessHeapFlags,
+ ProcessAffinityMask,
+ CSDVersion,
+ Reserved1,
+ EditList,
+ SecurityCookie);
+
+ if (lconf.dir32.Size <= PE_LOAD_CONFIG32_LIMIT_XP)
+ goto L_LOADCFG_EXIT;
+
+ with (lconf.dir32)
+ printf(
+ "SEHandlerTable %08X\n"~
+ "SEHandlerCount %08X\n"~
+ "GuardCFCheckFunctionPointer %08X\n"~
+ "GuardCFDispatchFunctionPointer %08X\n"~
+ "GuardCFFunctionTable %08X\n"~
+ "GuardCFFunctionCount %08X\n"~
+ "GuardFlags %08X\n",
+ SEHandlerTable,
+ SEHandlerCount,
+ GuardCFCheckFunctionPointer,
+ GuardCFDispatchFunctionPointer,
+ GuardCFFunctionTable,
+ GuardCFFunctionCount,
+ GuardFlags);
+
+ if (lconf.dir32.Size <= PE_LOAD_CONFIG32_LIMIT_VI)
+ goto L_LOADCFG_EXIT;
+
+ with (lconf.dir32)
+ printf(
+ "CodeIntegrity.Flags %04X\n"~
+ "CodeIntegrity.Catalog %04X\n"~
+ "CodeIntegrity.CatalogOffset %08X\n"~
+ "CodeIntegrity.Reserved %08X\n"~
+ "GuardAddressTakenIatEntryTable %08X\n"~
+ "GuardAddressTakenIatEntryCount %08X\n"~
+ "GuardLongJumpTargetTable %08X\n"~
+ "GuardLongJumpTargetCount %08X\n",
+ CodeIntegrity.Flags,
+ CodeIntegrity.Catalog,
+ CodeIntegrity.CatalogOffset,
+ CodeIntegrity.Reserved,
+ GuardAddressTakenIatEntryTable,
+ GuardAddressTakenIatEntryCount,
+ GuardLongJumpTargetTable,
+ GuardLongJumpTargetCount);
+
+ if (lconf.dir32.Size <= PE_LOAD_CONFIG32_LIMIT_8)
+ goto L_LOADCFG_EXIT;
+
+ with (lconf.dir32)
+ printf(
+ "DynamicValueRelocTable %08X\n"~
+ "CHPEMetadataPointer %08X\n"~
+ "GuardRFFailureRoutine %08X\n"~
+ "GuardRFFailureRoutineFunctionPointer %08X\n"~
+ "DynamicValueRelocTableOffset %08X\n"~
+ "DynamicValueRelocTableSection %04X\n"~
+ "Reserved2 %04X\n"~
+ "GuardRFVerifyStackPointerFunctionPointer %08X\n"~
+ "HotPatchTableOffset %08X\n"~
+ "Reserved3 %08X\n"~
+ "EnclaveConfigurationPointer %08X\n"~
+ "VolatileMetadataPointer %08X\n",
+ DynamicValueRelocTable,
+ CHPEMetadataPointer,
+ GuardRFFailureRoutine,
+ GuardRFFailureRoutineFunctionPointer,
+ DynamicValueRelocTableOffset,
+ DynamicValueRelocTableSection,
+ Reserved2,
+ GuardRFVerifyStackPointerFunctionPointer,
+ HotPatchTableOffset,
+ Reserved3,
+ EnclaveConfigurationPointer,
+ VolatileMetadataPointer);
+ } else { // 64
+ with (lconf.dir64)
+ printf(
+ "DeCommitFreeBlockThreshold %016llX\n"~
+ "DeCommitTotalBlockThreshold %016llX\n"~
+ "LockPrefixTable %016llX\n"~
+ "MaximumAllocationSize %016llX\t(%u)\n"~
+ "VirtualMemoryThreshold %016llX\n"~
+ "ProcessAffinityMask %016llX\n"~
+ "ProcessHeapFlags %08X\n"~
+ "CSDVersion %04X\n"~
+ "Reserved1 %04X\n"~
+ "EditList %016llX\n"~
+ "SecurityCookie %016llX\n",
+ DeCommitFreeBlockThreshold,
+ DeCommitTotalBlockThreshold,
+ LockPrefixTable,
+ MaximumAllocationSize, MaximumAllocationSize,
+ VirtualMemoryThreshold,
+ ProcessAffinityMask,
+ ProcessHeapFlags,
+ CSDVersion,
+ Reserved1,
+ EditList,
+ SecurityCookie);
+
+ if (lconf.dir64.Size <= PE_LOAD_CONFIG64_LIMIT_XP)
+ goto L_LOADCFG_EXIT;
+
+ with (lconf.dir64)
+ printf(
+ "SEHandlerTable %016llX\n"~
+ "SEHandlerCount %016llX\n"~
+ "GuardCFCheckFunctionPointer %016llX\n"~
+ "GuardCFDispatchFunctionPointer %016llX\n"~
+ "GuardCFFunctionTable %016llX\n"~
+ "GuardCFFunctionCount %016llX\n"~
+ "GuardFlags %08X\n",
+ SEHandlerTable,
+ SEHandlerCount,
+ GuardCFCheckFunctionPointer,
+ GuardCFDispatchFunctionPointer,
+ GuardCFFunctionTable,
+ GuardCFFunctionCount,
+ GuardFlags);
+
+ if (lconf.dir64.Size <= PE_LOAD_CONFIG64_LIMIT_VI)
+ goto L_LOADCFG_EXIT;
+
+ with (lconf.dir64)
+ printf(
+ "CodeIntegrity.Flags %04X\n"~
+ "CodeIntegrity.Catalog %04X\n"~
+ "CodeIntegrity.CatalogOffset %08X\n"~
+ "CodeIntegrity.Reserved %08X\n"~
+ "GuardAddressTakenIatEntryTable %016llX\n"~
+ "GuardAddressTakenIatEntryCount %016llX\n"~
+ "GuardLongJumpTargetTable %016llX\n"~
+ "GuardLongJumpTargetCount %016llX\n",
+ CodeIntegrity.Flags,
+ CodeIntegrity.Catalog,
+ CodeIntegrity.CatalogOffset,
+ CodeIntegrity.Reserved,
+ GuardAddressTakenIatEntryTable,
+ GuardAddressTakenIatEntryCount,
+ GuardLongJumpTargetTable,
+ GuardLongJumpTargetCount);
+
+ if (lconf.dir64.Size <= PE_LOAD_CONFIG64_LIMIT_8)
+ goto L_LOADCFG_EXIT;
+
+ with (lconf.dir64)
+ printf(
+ "DynamicValueRelocTable %016llX\n"~
+ "CHPEMetadataPointer %016llX\n"~
+ "GuardRFFailureRoutine %016llX\n"~
+ "GuardRFFailureRoutineFunctionPointer %016llX\n"~
+ "DynamicValueRelocTableOffset %08X\n"~
+ "DynamicValueRelocTableSection %04X\n"~
+ "Reserved2 %04X\n"~
+ "GuardRFVerifyStackPointerFunctionPointer %08X\n"~
+ "HotPatchTableOffset %016llX\n"~
+ "Reserved3 %08X\n"~
+ "EnclaveConfigurationPointer %016llX\n"~
+ "VolatileMetadataPointer %016llX\n",
+ DynamicValueRelocTable,
+ CHPEMetadataPointer,
+ GuardRFFailureRoutine,
+ GuardRFFailureRoutineFunctionPointer,
+ DynamicValueRelocTableOffset,
+ DynamicValueRelocTableSection,
+ Reserved2,
+ GuardRFVerifyStackPointerFunctionPointer,
+ HotPatchTableOffset,
+ Reserved3,
+ EnclaveConfigurationPointer,
+ VolatileMetadataPointer);
+ }
+ }
+}*/
+
+void dump_pe_exports(adbg_object_t *o) {
+ print_header("Exports");
+
+ PE_EXPORT_DESCRIPTOR *export_ = adbg_object_pe_export(o);
+ if (export_ == null)
+ return;
+
+ with (export_) {
+ print_x32("ExportFlags", ExportFlags);
+ print_x32("Timestamp", Timestamp);
+ print_x16("MajorVersion", MajorVersion);
+ print_x16("MinorVersion", MinorVersion);
+ print_x32("Name", Name, adbg_object_pe_export_name(o, export_));
+ print_x32("OrdinalBase", OrdinalBase);
+ print_x32("AddressTableEntries", AddressTableEntries);
+ print_x32("NumberOfNamePointers", NumberOfNamePointers);
+ print_x32("ExportAddressTable", ExportAddressTable);
+ print_x32("NamePointer", NamePointer);
+ print_x32("OrdinalTable", OrdinalTable);
+ }
+
+ PE_EXPORT_ENTRY *entry = void;
+ size_t ie;
+ while ((entry = adbg_object_pe_export_name_entry(o, export_, ie++)) != null) {
+ print_x32("Export", entry.Export, adbg_object_pe_export_name_string(o, export_, entry));
+ }
+}
+
+void dump_pe_imports(adbg_object_t *o) {
+ print_header("Imports");
+ PE_IMPORT_DESCRIPTOR *import_ = void;
+ size_t i;
+ while ((import_ = adbg_object_pe_import(o, i++)) != null) with (import_) {
+ char* name = adbg_object_pe_import_name(o, import_);
+ print_section(cast(uint)i, name, 128);
+
+ print_x32("Characteristics", Characteristics);
+ print_x32("TimeDateStamp", TimeDateStamp);
+ print_x32("ForwarderChain", ForwarderChain);
+ print_x32("Name", Name);
+ print_x32("FirstThunk", FirstThunk);
+
+ //TODO: Function to get import name+hint from lte directly
+ // adbg_object_pe_import_entry_string(o, import_, i++);
+
+ size_t il;
+ switch (o.i.pe.opt_header.Magic) {
+ case PE_FMT_32:
+ PE_IMPORT_ENTRY32 *t32 = adbg_object_pe_import_entry32(o, import_, il);
+ if (t32 == null) continue;
+ do with (t32) {
+ if (ordinal >= 0x8000_0000) { // Ordinal
+ print_section(cast(uint)il);
+ print_x16("Number", number);
+ } else { // RVA
+ ushort *hint = adbg_object_pe_import_entry32_hint(o, import_, t32);
+ if (hint == null) {
+ LBADINDEX32:
+ print_string("warning", "String index outside buffer");
+ continue;
+ }
+ const(char)* import_name = cast(const(char)*)hint + ushort.sizeof;
+ if (adbg_object_outboundp(o, cast(void*)import_name))
+ goto LBADINDEX32;
+ print_x32("RVA", rva);
+ print_x16l("Hint", *hint, import_name, 64);
+ }
+ } while ((t32 = adbg_object_pe_import_entry32(o, import_, ++il)) != null);
+ continue;
+ case PE_FMT_64:
+ PE_IMPORT_ENTRY64 *t64 = adbg_object_pe_import_entry64(o, import_, il);
+ if (t64 == null) continue;
+ do with (t64) {
+ if (ordinal >= 0x8000_0000_0000_0000) { // Ordinal
+ print_section(cast(uint)il);
+ print_x16("Number", number);
+ } else { // RVA
+ ushort *hint = adbg_object_pe_import_entry64_hint(o, import_, t64);
+ if (hint == null) {
+ LBADINDEX64:
+ print_string("warning", "String index outside buffer");
+ continue;
+ }
+ const(char)* import_name = cast(const(char)*)hint + ushort.sizeof;
+ if (adbg_object_outboundp(o, cast(void*)import_name))
+ goto LBADINDEX64;
+ print_x32("RVA", rva);
+ print_x16l("Hint", *hint, import_name, 64);
+ }
+ } while ((t64 = adbg_object_pe_import_entry64(o, import_, ++il)) != null);
+ continue;
+ default:
+ }
+ }
+}
+
+void dump_pe_debug(adbg_object_t *o) {
+ print_header("Debug");
+
+ PE_DEBUG_DIRECTORY *debug_ = void;
+ size_t i;
+ while ((debug_ = adbg_object_pe_debug_directory(o, i++)) != null) with (debug_) {
+ print_section(cast(uint)i);
+ print_x32("Characteristics", Characteristics);
+ print_x32("TimeDateStamp", TimeDateStamp);
+ print_u16("MajorVersion", MajorVersion);
+ print_u16("MinorVersion", MinorVersion);
+ print_u32("Type", Type, adbg_object_pe_debug_type_string(Type));
+ print_u32("SizeOfData", SizeOfData);
+ print_x32("AddressOfRawData", AddressOfRawData);
+ print_x32("PointerToRawData", PointerToRawData);
+
+ uint sig = void;
+ if (adbg_object_offsett!uint(o, &sig, PointerToRawData)) {
+ print_string("error", "PointerToRawData out of bounds");
+ return;
+ }
+
+ const(char) *sigstr = void;
+ switch (Type) {
+ case PE_IMAGE_DEBUG_TYPE_CODEVIEW:
+ //TODO: Check MajorVersion/MinorVersion
+ // For example, a modern D program use 0.0
+ // Probably meaningless
+
+ switch (sig) {
+ case PE_IMAGE_DEBUG_MAGIC_CODEVIEW_CV410: // PDB 2.0+ / CodeView 4.10
+ sigstr = "PDB 2.0+ / CodeView 4.10";
+ goto L_DEBUG_PDB20;
+ case PE_IMAGE_DEBUG_MAGIC_CODEVIEW_PDB20PLUS: // PDB 2.0+
+ sigstr = "PDB 2.0+ / NB10";
+ goto L_DEBUG_PDB20;
+ case PE_IMAGE_DEBUG_MAGIC_CODEVIEW_CV500: // PDB 2.0+ / CodeView 5.0
+ sigstr = "PDB 2.0+ / CodeView 5.0";
+ L_DEBUG_PDB20:
+ print_x32("Signature", sig, sigstr);
+ PE_DEBUG_DATA_CODEVIEW_PDB20* pdb = void;
+ if (adbg_object_offsetl(o, cast(void**)&pdb,
+ PointerToRawData, PE_DEBUG_DATA_CODEVIEW_PDB20.sizeof + 256)) {
+ print_string("error", "PE_DEBUG_DATA_CODEVIEW_PDB20 out of bounds");
+ continue;
+ }
+ print_x32("Offset", pdb.Offset);
+ print_x32("Timestamp", pdb.Timestamp, ctime32(pdb.Timestamp));
+ print_u32("Age", pdb.Age);
+ if (pdb.Offset == 0) print_stringl("Path", pdb.Path.ptr, 256);
+ break;
+ case PE_IMAGE_DEBUG_MAGIC_CODEVIEW_CV700: // PDB 7.0 / CodeView 7.0
+ PE_DEBUG_DATA_CODEVIEW_PDB70* pdb = void;
+ if (adbg_object_offsetl(o, cast(void**)&pdb,
+ PointerToRawData, PE_DEBUG_DATA_CODEVIEW_PDB70.sizeof + 256)) {
+ print_string("error", "PE_DEBUG_DATA_CODEVIEW_PDB70 out of bounds");
+ continue;
+ }
+ char[UID_TEXTLEN] guid = void;
+ uid_text(pdb.Guid, guid, UID_GUID);
+ print_x32("Signature", sig, "PDB 7.0 / CodeView 7.0");
+ print_stringl("GUID", guid.ptr, UID_TEXTLEN);
+ print_u32("Age", pdb.Age); // ctime32?
+ print_stringl("Path", pdb.Path.ptr, 256);
+ break;
+ case PE_IMAGE_DEBUG_MAGIC_EMBEDDED_PPDB: // Portable PDB
+ // NOTE: major_version >= 0x100 && minor_version == 0x100
+ print_x32("Signature", sig, "Embedded Portable PDB");
+ break;
+ case PE_IMAGE_DEBUG_MAGIC_PPDB:
+ PE_DEBUG_DATA_PPDB *ppdb = void;
+ if (adbg_object_offsetl(o, cast(void**)&ppdb,
+ PointerToRawData, PE_DEBUG_DATA_PPDB.sizeof + 64)) {
+ print_string("error", "PE_DEBUG_DATA_PPDB out of bounds");
+ continue;
+ }
+ print_x32("Signature", sig, "Portable PDB");
+ print_u16("MajorVersion", ppdb.MajorVersion);
+ print_u16("MinorVersion", ppdb.MinorVersion);
+ print_x32("Reserved", ppdb.Reserved);
+ print_u32("Length", ppdb.Length);
+ print_stringl("Version", ppdb.Version.ptr,
+ ppdb.Length > 64 ? 64 : ppdb.Length);
+ break;
+ default:
+ print_x32("Signature", sig, "Unknown");
+ break;
+ }
+ break;
+ case PE_IMAGE_DEBUG_TYPE_MISC:
+ PE_DEBUG_DATA_MISC* misc = void;
+ if (adbg_object_offsetl(o, cast(void**)&misc,
+ PointerToRawData, PE_DEBUG_DATA_MISC.sizeof + 256)) {
+ print_string("error", "PE_DEBUG_DATA_MISC out of bounds");
+ continue;
+ }
+ if (misc.DataType != 1) { // IMAGE_DEBUG_MISC_EXENAME
+ print_string("error", "PE_DEBUG_DATA_MISC.DataType is not set to 1.");
+ continue;
+ }
+ print_x32("Signature", sig, "Misc. Debug Data");
+ print_x32("DataType", misc.DataType);
+ print_x32("Length", misc.Length);
+ print_u8("Unicode", misc.Unicode);
+ print_u8("Reserved[0]", misc.Reserved[0]);
+ print_u8("Reserved[1]", misc.Reserved[1]);
+ print_u8("Reserved[2]", misc.Reserved[2]);
+ if (misc.Unicode == false)
+ print_stringl("Data", cast(char*)misc.Data.ptr, 256);
+ break;
+ case PE_IMAGE_DEBUG_TYPE_FPO:
+ // TODO: PE_IMAGE_DEBUG_TYPE_FPO
+ break;
+ case PE_IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS:
+ // TODO: PE_IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS
+ break;
+ case PE_IMAGE_DEBUG_TYPE_POGO:
+ const(char) *pgotypestr = void;
+ switch (sig) {
+ case PE_IMAGE_DEBUG_MAGIC_POGO_LTCG:
+ pgotypestr = "POGO LTCG (Link-Time Code Generation)";
+ break;
+ case PE_IMAGE_DEBUG_MAGIC_POGO_PGU:
+ pgotypestr = "POGO PGU (Profile Guided Update)";
+ break;
+ default:
+ pgotypestr = "POGO (Unknown)";
+ }
+ print_x32("Signature", sig, pgotypestr);
+
+ PE_DEBUG_POGO_ENTRY* pogoentry = void;
+ if (adbg_object_offsetl(o, cast(void**)&pogoentry,
+ PointerToRawData, PE_DEBUG_POGO_ENTRY.sizeof + 256)) { // Guess
+ print_string("error", "PE_DEBUG_POGO_ENTRY out of bounds");
+ }
+
+ print_x32("RVA", pogoentry.Rva);
+ print_x32("Size", pogoentry.Size);
+ print_stringl("Size", pogoentry.Name.ptr, 256); // Guess
+ break;
+ case PE_IMAGE_DEBUG_TYPE_R2R_PERFMAP:
+ break;
+ default:
+ }
+ }
+}
+
+void dump_pe_disasm(adbg_object_t *o) {
+ print_header("Disassembly");
+
+ int all = setting_disasm_all();
+ PE_SECTION_ENTRY *section = void;
+ size_t i;
+ while ((section = adbg_object_pe_section(o, i++)) != null) with (section) {
+ if (all || Characteristics & PE_SECTION_CHARACTERISTIC_MEM_EXECUTE) {
+ dump_disassemble_object(o, Name.ptr, 8,
+ o.buffer + PointerToRawData, SizeOfRawData, 0);
+ }
+ }
+}
\ No newline at end of file
diff --git a/dumper/main.d b/dumper/main.d
new file mode 100644
index 0000000..5ce09cf
--- /dev/null
+++ b/dumper/main.d
@@ -0,0 +1,207 @@
+/// Command line interface.
+///
+/// Authors: dd86k
+/// Copyright: © dd86k
+/// License: BSD-3-Clause-Clear
+module main;
+
+import adbg.platform;
+import adbg.include.c.stdlib : exit;
+import adbg.include.d.config : GDC_VERSION, GDC_EXCEPTION_MODE, LLVM_VERSION;
+import adbg.debugger.exception : adbg_exception_t, adbg_exception_name;
+import adbg.self;
+import adbg.machines : adbg_machine_default;
+import adbg.disassembler;
+import adbg.error;
+import adbg.debugger.process;
+import core.stdc.stdlib : strtol, EXIT_SUCCESS, EXIT_FAILURE;
+import core.stdc.string : strcmp;
+import core.stdc.stdio;
+import dumper;
+import common.cli;
+import common.utils : unformat64;
+
+private:
+//TODO: --dump-blob-offset/--dump-blob-seek/--dump-blob-start: Starting offset for raw blob
+//TODO: --dump-length/--dump-end: Length or end
+//TODO: --dump-imports-all: Dependency walker
+//TODO: --dump-section=name: Hex or raw dump section
+//TODO: --dump-stats: File statistics?
+// pdb: stream count, positions, etc.
+//TODO: --demangle
+//TODO: --type-only: Returns short-name only for identification purposes
+immutable option_t[] options = [
+ // general
+ option_arch,
+ option_syntax,
+ // dumper
+ option_t('H', "headers", "Dump object's headers", &cli_dump_headers),
+ option_t(0, "section", "Dump object's section by name", &cli_dump_section),
+ option_t('S', "sections", "Dump object's sections", &cli_dump_sections),
+ option_t('I', "imports", "Dump object's import information", &cli_dump_imports),
+ option_t('E', "exports", "Dump object's export information", &cli_dump_exports),
+// option_t(0, "loadcfg", "Dump object's load configuration", &cli_dump_loadcfg),
+// option_t(0, "source", "Dump object's source with disassembly", &cli_dump_source),
+ option_t(0, "relocs", "Dump object's relocations", &cli_dump_reloc),
+ option_t(0, "debug", "Dump object's debug information", &cli_dump_debug),
+ option_t(0, "everything", "Dump everything except disassembly", &cli_dump_everything),
+ option_t(0, "disassembly", "Dump object's disassembly", &cli_dump_disasm),
+ option_t(0, "disassembly-all", "Dump object's disassembly for all sections", &cli_dump_disasm_all),
+ option_t(0, "disassembly-stats", "Dump object's disassembly statistics for executable sections", &cli_dump_disasm_stats),
+ option_t(0, "as-blob", "Dump as raw binary blob", &cli_dump_blob),
+ option_t(0, "origin", "Mark base address for disassembly", &cli_dump_disasm_org),
+ // pages
+ option_t('h', "help", "Show this help screen and exit", &cli_help),
+ option_version,
+ option_build_info,
+ option_ver,
+ option_license,
+];
+
+int cli_dump_headers() {
+ opt_selected |= Select.headers;
+ return 0;
+}
+int cli_dump_section(const(char) *val) {
+ opt_selected |= Select.sections;
+ opt_section = val;
+ return 0;
+}
+int cli_dump_sections() {
+ opt_selected |= Select.sections;
+ return 0;
+}
+int cli_dump_imports() {
+ opt_selected |= Select.imports;
+ return 0;
+}
+int cli_dump_exports() {
+ opt_selected |= Select.exports;
+ return 0;
+}
+int cli_dump_loadcfg() {
+ opt_selected |= Select.loadcfg;
+ return 0;
+}
+int cli_dump_reloc() {
+ opt_selected |= Select.relocs;
+ return 0;
+}
+int cli_dump_debug() {
+ opt_selected |= Select.debug_;
+ return 0;
+}
+int cli_dump_disasm() {
+ opt_settings |= Setting.disasm;
+ return 0;
+}
+int cli_dump_disasm_all() {
+ opt_settings |= Setting.disasmAll;
+ return 0;
+}
+int cli_dump_disasm_stats() {
+ opt_settings |= Setting.disasmStats;
+ return 0;
+}
+
+int cli_dump_everything() {
+ opt_selected |= Select.all;
+ return 0;
+}
+
+// Dump options
+
+int cli_dump_blob() {
+ opt_settings |= Setting.blob;
+ return 0;
+}
+int cli_dump_disasm_org(const(char) *val) {
+ return unformat64(&opt_baseaddress, val);
+}
+
+//
+// ANCHOR --help
+//
+
+int cli_help() {
+ puts(
+ "alicedump: Binary object dumper.\n"~
+ "\n"~
+ "USAGE\n"~
+ " Dump and summarize:\n"~
+ " alicedbg [OPTIONS...] FILE\n"~
+ " Dump headers:\n"~
+ " alicedbg --headers [OPTIONS...] FILE\n"~
+ " Show information page and exit:\n"~
+ " alicedbg {-h|--help|--version|--ver|--license}\n"~
+ "\n"~
+ "OPTIONS"
+ );
+ getoptprinter(options);
+ exit(0);
+ return 0;
+}
+
+extern (C)
+void crash_handler(adbg_exception_t *ex) {
+ scope(exit) exit(ex.oscode);
+
+ adbg_process_t *self = adbg_self_process();
+
+ puts(
+r"
+ _ _ _ _ _ _ _ _ _ _ _ _ _ _
+ _|_|_|_| |_|_|_|_ _|_|_|_ _|_|_|_| |_| |_| |_|
+|_| |_|_ _|_| |_|_ _|_| |_|_ _ |_|_ _|_| |_|
+|_| |_|_|_|_ |_|_|_|_| |_|_|_ |_|_|_|_| |_|
+|_|_ _ _ |_| |_| |_| |_| _ _ _|_| |_| |_| _
+ |_|_|_| |_| |_| |_| |_| |_|_|_| |_| |_| |_|
+"
+ );
+
+ printf(
+ "Exception : %s\n"~
+ "PID : %d\n",
+ adbg_exception_name(ex), cast(int)self.pid); // casting is temp
+
+ // Fault address & disasm if available
+ if (ex.faultz) {
+ printf("Address : %#zx\n", ex.faultz);
+
+ adbg_opcode_t op = void;
+ adbg_disassembler_t *dis = adbg_dis_open(adbg_machine_default());
+ if (dis && adbg_dis_process_once(dis, &op, self, ex.fault_address) == 0) {
+ // Print address
+ printf("Instruction:");
+ // Print machine bytes
+ for (size_t bi; bi < op.size; ++bi)
+ printf(" %02x", op.machine[bi]);
+ //
+ printf(" (%s", op.mnemonic);
+ if (op.operands)
+ printf(" %s", op.operands);
+ //
+ puts(")");
+ } else {
+ printf(" Unavailable (%s)\n", adbg_error_msg());
+ }
+ }
+}
+
+extern (C)
+int main(int argc, const(char)** argv) {
+ // Set crash handle, and ignore on error
+ // Could do a warning, but it might be a little confusing
+ adbg_self_set_crashhandler(&crash_handler);
+
+ int e = getopt(argc, argv, options);
+ if (e < 0) {
+ puts(getopterr());
+ return EXIT_FAILURE;
+ }
+ /*if (e >= 1) {
+ opt_file = argv[0];
+ }*/
+
+ return app_dump();
+}