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(); +}