├── .github ├── FUNDING.yaml └── workflows │ └── tests.yaml ├── .gitignore ├── LICENSE ├── README.md ├── common ├── dub.sdl └── src │ ├── cli.d │ ├── errormgmt.d │ ├── getopt.d │ └── utils.d ├── debugger ├── dub.sdl └── src │ ├── main.d │ ├── shell.d │ └── term.d ├── dscanner.ini ├── dub.sdl ├── dumper ├── dub.sdl └── src │ ├── dumper.d │ ├── format_ar.d │ ├── format_coff.d │ ├── format_dmp.d │ ├── format_elf.d │ ├── format_lx.d │ ├── format_macho.d │ ├── format_mdmp.d │ ├── format_mscoff.d │ ├── format_mz.d │ ├── format_ne.d │ ├── format_omf.d │ ├── format_pdb.d │ ├── format_pe.d │ └── main.d ├── examples └── simple.d ├── src └── adbg │ ├── build.d │ ├── debugger.d │ ├── disassembler.d │ ├── error.d │ ├── include │ ├── c │ │ ├── config.d │ │ ├── setjmp.d │ │ ├── stdarg.d │ │ ├── stdio.d │ │ └── stdlib.d │ ├── capstone │ │ ├── arm.d │ │ ├── arm64.d │ │ ├── evm.d │ │ ├── m680x.d │ │ ├── m68k.d │ │ ├── mips.d │ │ ├── package.d │ │ ├── ppc.d │ │ ├── sparc.d │ │ ├── systemz.d │ │ ├── tms320c64x.d │ │ ├── v4.d │ │ ├── x86.d │ │ └── xcore.d │ ├── d │ │ └── config.d │ ├── freebsd │ │ ├── ptrace.d │ │ └── reg.d │ ├── linux │ │ ├── personality.d │ │ ├── ptrace.d │ │ └── user.d │ ├── macos │ │ └── ptrace.d │ ├── posix │ │ ├── mann.d │ │ ├── ptrace.d │ │ ├── signal.d │ │ ├── sys │ │ │ └── wait.d │ │ └── unistd.d │ └── windows │ │ ├── ntdll.d │ │ ├── psapi_dyn.d │ │ ├── tlhelp32.d │ │ ├── winbase.d │ │ ├── winnt.d │ │ └── wow64apiset.d │ ├── machines.d │ ├── objects │ ├── ar.d │ ├── coff.d │ ├── dmp.d │ ├── elf.d │ ├── lx.d │ ├── macho.d │ ├── mdmp.d │ ├── mscoff.d │ ├── mz.d │ ├── ne.d │ ├── omf.d │ ├── package.d │ ├── pdb.d │ └── pe.d │ ├── objectserver.d │ ├── os │ ├── file.d │ └── path.d │ ├── package.d │ ├── platform.d │ ├── process │ ├── base.d │ ├── breakpoint.d │ ├── exception.d │ ├── frame.d │ ├── memory.d │ ├── package.d │ └── thread.d │ ├── scanner.d │ ├── self.d │ ├── symbols.d │ ├── system.d │ ├── types │ └── cv.d │ └── utils │ ├── bit.d │ ├── date.d │ ├── list.d │ ├── math.d │ ├── strings.d │ └── uid.d └── tests ├── readkey.d ├── readln.d └── setjmp.d /.github/FUNDING.yaml: -------------------------------------------------------------------------------- 1 | github: dd86k 2 | patreon: dd86k 3 | ko_fi: dd86k 4 | liberapay: dd86k 5 | -------------------------------------------------------------------------------- /.github/workflows/tests.yaml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: [ push, pull_request ] 4 | 5 | # Tests ensures the project builds and executes unittest. 6 | # The entry points are rather minimal. 7 | jobs: 8 | Alicedbg: 9 | strategy: 10 | matrix: 11 | os: [ ubuntu-22.04, windows-2022 ] 12 | dc: [ dmd-latest, ldc-latest ] 13 | runs-on: ${{ matrix.os }} 14 | steps: 15 | - uses: actions/checkout@v4 16 | - name: Setup D compiler 17 | uses: dlang-community/setup-dlang@v2 18 | with: 19 | compiler: ${{ matrix.dc }} 20 | - name: Test Alicedbg 21 | run: dub test :debugger 22 | Alicedump: 23 | strategy: 24 | matrix: 25 | os: [ ubuntu-22.04, windows-2022 ] 26 | dc: [ dmd-latest, ldc-latest ] 27 | runs-on: ${{ matrix.os }} 28 | steps: 29 | - uses: actions/checkout@v4 30 | - name: Setup D compiler 31 | uses: dlang-community/setup-dlang@v2 32 | with: 33 | compiler: ${{ matrix.dc }} 34 | - name: Test Alicedump 35 | run: dub test :dumper -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Project 2 | .vscode/ 3 | .dub/ 4 | dub*.s 5 | __dummy.html 6 | /bin/ 7 | /docs/ 8 | *.json 9 | *.log 10 | *.lst 11 | *.exp 12 | 13 | # Executable objects 14 | /alicedbg 15 | alicedbg-test-* 16 | alicedbg-*-test-* 17 | /alicedump 18 | alicedump-*-test-* 19 | /simple 20 | *.dll 21 | *.dylib 22 | *.so 23 | *.exe 24 | 25 | # Debug objects 26 | *.pdb 27 | *.dbg 28 | 29 | # Library archives and objects 30 | *.lib 31 | *.a 32 | *.obj 33 | *.o 34 | 35 | # Archives 36 | *.zip 37 | *.tar.* 38 | 39 | # C headers 40 | /include/ 41 | 42 | # Personal stuff 43 | /notes/ 44 | /o/ 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019-2024, dd86k 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted (subject to the limitations in the disclaimer 6 | below) provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from this 17 | software without specific prior written permission. 18 | 19 | NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY 20 | THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 21 | CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 23 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 24 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 27 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 28 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Alice Debugger Project 2 | 3 | Aiming to be a simple cross-platform framework for debugging and object inspection. 4 | 5 | Fully written in D's [BetterC mode](https://dlang.org/spec/betterc.html), 6 | and available as a DUB package. 7 | 8 | It is currently available for Windows, Linux, and FreeBSD, under x86, x86-64, Armv7, and AArch64. 9 | 10 | Written from scratch for educational purposes. 11 | 12 | ## Warnings 13 | 14 | ⚠️ This is a toy project with barely any features! ⚠️ 15 | 16 | There are currently no stable APIs. Every releases pre-1.0 will see frequent 17 | changes to the API. 18 | 19 | None of the functions are currently thread-safe. 20 | 21 | Compiling a static binary on one C runtime may not work on another due to 22 | specific behaviors when using ptrace(2). 23 | 24 | # Usage 25 | 26 | Usage for `alicedbg` (debugger) and `alicedump` (dumper) can be looked in the 27 | repository Wiki, or invoking the `--help` argument. 28 | 29 | The disassembly feature is provided by Capstone 4.0.2 when it is available on 30 | the system. For Windows, the dynamic library can be 31 | [downloaded on GitHub](https://github.com/capstone-engine/capstone/releases/tag/4.0.2). 32 | 33 | For other platforms, package names are typically: 34 | - Debian, Ubuntu 22.04 and later, SUSE: `libcapstone4` 35 | - Ubuntu 20.04: `libcapstone3` (4.0.1) 36 | - RHEL: `capstone-devel` 37 | - Alpine: `capstone-dev` 38 | 39 | Capstone is licensed under the BSD 3-Clause license. 40 | 41 | # Hacking 42 | 43 | There are two main branches: 44 | - `marisa`: Main development branch. Very unstable. 45 | - `stable`: Last released branch. 46 | 47 | This project primarily uses [DUB](https://dub.pm/cli-reference/dub/) 48 | for compilation and unittesting. 49 | 50 | Wiki contains more information on structure, features, and compilation 51 | instructions. 52 | 53 | # Contributing 54 | 55 | Because I'm not very good at managing people and I tend to be a little too 56 | pedantic, I am currently not looking for contributors, sorry. 57 | 58 | However, feel free to provide feedback regarding contributor management, 59 | features, enhancements, and fixes. It's appreciated. 60 | 61 | # License 62 | 63 | This project is licensed under the BSD 3-Clause Clear license. -------------------------------------------------------------------------------- /common/dub.sdl: -------------------------------------------------------------------------------- 1 | name "common" 2 | targetType "sourceLibrary" -------------------------------------------------------------------------------- /common/src/cli.d: -------------------------------------------------------------------------------- 1 | /// Common command-line options 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module common.cli; 7 | 8 | import adbg.platform; 9 | import adbg.machines; 10 | import adbg.disassembler; 11 | import adbg.include.capstone : libcapstone_dynload, cs_version; 12 | import adbg.include.c.stdlib : exit; 13 | import adbg.include.d.config : GDC_VERSION, GDC_EXCEPTION_MODE, LLVM_VERSION; 14 | import adbg.include.c.stdio; 15 | import core.stdc.stdlib; 16 | import core.stdc.string; 17 | public import getopt; 18 | 19 | /// Copyright string 20 | enum COPYRIGHT = "Copyright (c) 2019-2024 dd86k "; 21 | 22 | /// License string 23 | immutable char *page_license = 24 | COPYRIGHT~` 25 | All rights reserved. 26 | 27 | Redistribution and use in source and binary forms, with or without 28 | modification, are permitted provided that the following conditions are met: 29 | 30 | 1. Redistributions of source code must retain the above copyright notice, this 31 | list of conditions and the following disclaimer. 32 | 33 | 2. Redistributions in binary form must reproduce the above copyright notice, 34 | this list of conditions and the following disclaimer in the documentation 35 | and/or other materials provided with the distribution. 36 | 37 | 3. Neither the name of the copyright holder nor the names of its 38 | contributors may be used to endorse or promote products derived from 39 | this software without specific prior written permission. 40 | 41 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 42 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 44 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 45 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 47 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 48 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 49 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 50 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.`; 51 | 52 | debug enum FULL_VERSION = ADBG_VERSION~"+"~__BUILDTYPE__; /// Full version string 53 | else enum FULL_VERSION = ADBG_VERSION; /// Ditto 54 | 55 | /// Turns a __VERSION__ number into a string constant 56 | /// Params: ver = version value 57 | template DSTRVER(uint ver) { 58 | enum DSTRVER = 59 | cast(char)((ver / 1000) + '0') ~ "." ~ 60 | cast(char)(((ver % 1000) / 100) + '0') ~ 61 | cast(char)(((ver % 100) / 10) + '0') ~ 62 | cast(char)((ver % 10) + '0'); 63 | } 64 | /// Compiler version string 65 | enum __D_VERSION__ = DSTRVER!__VERSION__; 66 | 67 | __gshared { 68 | /// Machine option 69 | AdbgMachine opt_machine; 70 | /// Disassembler syntax option 71 | AdbgDisassemblerSyntax opt_syntax; 72 | } 73 | 74 | /// Default option for --machine 75 | enum option_arch = option_t('m', "machine", "Select machine for disassembler (default=platform)", &cli_march); 76 | /// Default option for --syntax 77 | enum option_syntax = option_t('s', "syntax", "Select syntax for disassembler (default=platform)", &cli_syntax); 78 | /// Default option for --version 79 | enum option_version = option_t(0, "version", "Show the version screen and exit", &cli_version); 80 | /// Default option for --build-info 81 | enum option_build_info = option_t(0, "build-info", "Show the build and debug information and exit", &cli_build_info); 82 | /// Default option for --ver 83 | enum option_ver = option_t(0, "ver", "Show only the version string and exit", &cli_ver); 84 | /// Default option for --license 85 | enum option_license = option_t(0, "license", "Show the license page and exit", &cli_license); 86 | 87 | /// Is user asking for help with this option? 88 | /// Params: query = Value input. 89 | /// Returns: true on "help". 90 | bool wantsHelp(const(char) *query) { 91 | return strcmp(query, "help") == 0; 92 | } 93 | 94 | private: 95 | 96 | // 97 | // -m|--machine 98 | // 99 | 100 | int cli_march(const(char) *val) { 101 | if (wantsHelp(val)) { 102 | puts("Available machine architectures for disassembly:"); 103 | immutable(AdbgMachine)* disasm_list = adbg_disassembler_machines(); 104 | for (size_t i; disasm_list[i]; ++i) { 105 | immutable(adbg_machine_t) *machine = adbg_machine(disasm_list[i]); 106 | printf("- %*s: ", -20, adbg_machine_fullname(machine)); 107 | 108 | const(char)** aliases = adbg_machine_aliases(machine); 109 | for (size_t a; aliases[a]; ++a) { 110 | if (a) printf(", "); 111 | printf(`"%s"`, aliases[a]); 112 | } 113 | putchar('\n'); 114 | } 115 | exit(0); 116 | } 117 | 118 | immutable(adbg_machine_t)* machine = adbg_machine_select(val); 119 | if (machine == null) 120 | return EXIT_FAILURE; 121 | 122 | opt_machine = machine.id; 123 | return EXIT_SUCCESS; 124 | } 125 | 126 | // 127 | // --syntax 128 | // 129 | 130 | struct setting_syntax_t { 131 | AdbgDisassemblerSyntax val; 132 | const(char)* opt, desc; 133 | } 134 | immutable setting_syntax_t[] syntaxes = [ 135 | { AdbgDisassemblerSyntax.att, "att", "AT&T syntax" }, 136 | { AdbgDisassemblerSyntax.intel, "intel", "Intel syntax" }, 137 | ]; 138 | 139 | int cli_syntax(const(char) *val) { 140 | if (wantsHelp(val)) { 141 | puts("Available disassembler syntaxes:"); 142 | foreach (setting_syntax_t syntax; syntaxes) { 143 | with (syntax) 144 | printf("%-10s %s\n", opt, desc); 145 | } 146 | exit(0); 147 | } 148 | foreach (setting_syntax_t syntax; syntaxes) { 149 | if (strcmp(val, syntax.opt) == 0) { 150 | opt_syntax = syntax.val; 151 | return EXIT_SUCCESS; 152 | } 153 | } 154 | return EXIT_FAILURE; 155 | } 156 | 157 | int cli_build_info() { 158 | static immutable char *page = 159 | "Compiler "~__VENDOR__~" "~__D_VERSION__~"\n"~ 160 | "Target "~TARGET_TRIPLE~"\n"~ 161 | "Object "~TARGET_OBJFMT~"\n"~ 162 | "FPU "~TARGET_FLTABI~"\n"~ 163 | "CppRT "~TARGET_CPPRT~"\n"~ 164 | "Config "~D_FEATURES; 165 | puts(page); 166 | 167 | static if (GDC_VERSION) { 168 | printf("GCC %d\n", GDC_VERSION); 169 | printf("GDC-EH %s\n", GDC_EXCEPTION_MODE); 170 | } 171 | 172 | version (CRuntime_Glibc) { 173 | import adbg.include.c.config : gnu_get_libc_version; 174 | printf("Glibc %s\n", gnu_get_libc_version()); 175 | } 176 | 177 | static if (LLVM_VERSION) 178 | printf("LLVM %d\n", LLVM_VERSION); 179 | 180 | printf("Capstone "); 181 | if (libcapstone_dynload()) { 182 | puts("error"); 183 | } else { 184 | int major = void, minor = void; 185 | cs_version(&major, &minor); 186 | printf("%d.%d\n", major, minor); 187 | } 188 | 189 | exit(0); 190 | return 0; 191 | } 192 | 193 | // 194 | // --version 195 | // 196 | 197 | int cli_version() { 198 | static immutable const(char) *page_version = // avoid TLS 199 | "Version "~FULL_VERSION~"\n"~ 200 | " Built "~__TIMESTAMP__~"\n"~ 201 | " "~COPYRIGHT~"\n"~ 202 | "License BSD-3-Clause-Clear\n"~ 203 | " \n"~ 204 | "Homepage https://github.com/dd86k/alicedbg"; 205 | puts(page_version); 206 | exit(0); 207 | return 0; 208 | } 209 | 210 | // 211 | // --ver 212 | // 213 | 214 | int cli_ver() { 215 | puts(FULL_VERSION); 216 | exit(0); 217 | return 0; 218 | } 219 | 220 | // 221 | // --license 222 | // 223 | 224 | int cli_license() { 225 | puts(page_license); 226 | exit(0); 227 | return 0; 228 | } -------------------------------------------------------------------------------- /common/src/errormgmt.d: -------------------------------------------------------------------------------- 1 | /// Error handling, printing, and contracting 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module common.errormgmt; 7 | 8 | import adbg.self; 9 | import adbg.machines : adbg_machine_current; 10 | import adbg.disassembler; 11 | import adbg.process.base; 12 | import adbg.process.exception; 13 | import adbg.process.memory; 14 | import adbg.error; 15 | import core.stdc.string : strerror; 16 | import core.stdc.errno : errno; 17 | import core.stdc.stdio; 18 | import core.stdc.stdlib : exit; 19 | 20 | extern (C): 21 | 22 | void print_error(const(char) *message, int code, 23 | const(char)* prefix = null, const(char)* mod = cast(char*)__MODULE__, int line = __LINE__) { 24 | debug fprintf(stderr, "[%s@%d] ", mod, line); 25 | fputs("error: ", stderr); 26 | if (prefix) { 27 | fputs(prefix, stderr); 28 | fputs(": ", stderr); 29 | } 30 | fprintf(stderr, "(%d) %s\n", code, message); 31 | } 32 | void print_error_adbg( 33 | const(char)* mod = __FILE__.ptr, int line = __LINE__) { 34 | debug fprintf(stderr, "[%s@%d] ", mod, line); 35 | print_error(adbg_error_message(), adbg_error_code(), null, adbg_error_function(), adbg_error_line()); 36 | } 37 | 38 | void panic(int code, const(char)* message, 39 | const(char)* prefix = null, const(char)* mod = __MODULE__.ptr, int line = __LINE__) { 40 | print_error(message, code, prefix, mod, line); 41 | // NOTE: If a code returned is used as a special signal (like on Windows), 42 | // it could mean something bad, so only return 1 (EXIT_FAILURE) or 2. 43 | exit(2); 44 | } 45 | void panic_crt(const(char)* prefix = null, const(char)* mod = __MODULE__.ptr, int line = __LINE__) { 46 | panic(errno, strerror(errno), prefix, mod, line); 47 | } 48 | void panic_adbg(const(char)* prefix = null, const(char)* mod = __MODULE__.ptr) { 49 | panic(adbg_error_code(), adbg_error_message(), prefix, adbg_error_function(), adbg_error_line()); 50 | } 51 | 52 | void reset_error() { 53 | adbg_error_reset(); 54 | } 55 | int errorcode() { 56 | return adbg_error_code(); 57 | } 58 | 59 | void crashed(adbg_process_t *proc, adbg_exception_t *ex) { 60 | fputs( 61 | ` 62 | _ _ _ _ _ _ _ _ _ _ _ _ _ _ 63 | _|_|_|_| |_|_|_|_ _|_|_|_ _|_|_|_| |_| |_| |_| 64 | |_| |_|_ _|_| |_|_ _|_| |_|_ _ |_|_ _|_| |_| 65 | |_| |_|_|_|_ |_|_|_|_| |_|_|_ |_|_|_|_| |_| 66 | |_|_ _ _ |_| |_| |_| |_| _ _ _|_| |_| |_| _ 67 | |_|_|_| |_| |_| |_| |_| |_|_|_| |_| |_| |_| 68 | `, 69 | stderr); 70 | 71 | // NOTE: Any future call could make the app crash harder, 72 | // so, print one line at at time 73 | fprintf(stderr, "PID : %d\n", adbg_process_id(proc)); 74 | fprintf(stderr, "Code : "~ERR_OSFMT~"\n", ex.oscode); 75 | fprintf(stderr, "Exception : %s\n", adbg_exception_name(ex)); 76 | 77 | // TODO: Get thread context 78 | 79 | // Fault address & disasm if available 80 | if (ex.fault_address) { 81 | fprintf(stderr, "Address : %#llx\n", ex.fault_address); 82 | 83 | ubyte[OPCODE_BUFSIZE] buffer = void; 84 | adbg_opcode_t op = void; 85 | adbg_disassembler_t *dis = adbg_disassembler_open(adbg_machine_current()); 86 | if (dis == null) 87 | goto Lunavail; 88 | if (adbg_memory_read(proc, cast(size_t)ex.fault_address, buffer.ptr, OPCODE_BUFSIZE)) 89 | goto Lunavail; 90 | if (adbg_disassemble(dis, &op, buffer.ptr, OPCODE_BUFSIZE)) 91 | goto Lunavail; 92 | 93 | fprintf(stderr, "Instruction:"); 94 | for (size_t bi; bi < op.size; ++bi) 95 | fprintf(stderr, " %02x", op.data[bi]); 96 | fprintf(stderr, " (%s", op.mnemonic); 97 | if (op.operands) fprintf(stderr, " %s", op.operands); 98 | fputs(")", stderr); 99 | 100 | goto Lcont; 101 | 102 | Lunavail: 103 | fprintf(stderr, " Disassembly unavailable (%s)\n", adbg_error_message()); 104 | Lcont: 105 | } 106 | 107 | // TODO: Option to attach debugger to this process 108 | exit(ex.oscode); 109 | } 110 | -------------------------------------------------------------------------------- /common/src/utils.d: -------------------------------------------------------------------------------- 1 | /// Application utilities. 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module common.utils; 7 | 8 | import adbg.include.c.stdio : sscanf; 9 | import core.stdc.ctype : isprint; 10 | 11 | char hexc0(ubyte upper) { 12 | ubyte h = upper >> 4; 13 | return cast(char)(h >= 0xa ? h + ('a' - 0xa) : h + '0'); 14 | } 15 | extern (D) unittest { 16 | assert(hexc0(0x00) == '0'); 17 | assert(hexc0(0x10) == '1'); 18 | assert(hexc0(0x20) == '2'); 19 | assert(hexc0(0x30) == '3'); 20 | assert(hexc0(0x40) == '4'); 21 | assert(hexc0(0x50) == '5'); 22 | assert(hexc0(0x60) == '6'); 23 | assert(hexc0(0x70) == '7'); 24 | assert(hexc0(0x80) == '8'); 25 | assert(hexc0(0x90) == '9'); 26 | assert(hexc0(0xa0) == 'a'); 27 | assert(hexc0(0xb0) == 'b'); 28 | assert(hexc0(0xc0) == 'c'); 29 | assert(hexc0(0xd0) == 'd'); 30 | assert(hexc0(0xe0) == 'e'); 31 | assert(hexc0(0xf0) == 'f'); 32 | } 33 | char hexc1(ubyte lower) { 34 | ubyte l = lower & 15; 35 | return cast(char)(l >= 0xa ? l + ('a' - 0xa) : l + '0'); 36 | } 37 | extern (D) unittest { 38 | assert(hexc1(0) == '0'); 39 | assert(hexc1(1) == '1'); 40 | assert(hexc1(2) == '2'); 41 | assert(hexc1(3) == '3'); 42 | assert(hexc1(4) == '4'); 43 | assert(hexc1(5) == '5'); 44 | assert(hexc1(6) == '6'); 45 | assert(hexc1(7) == '7'); 46 | assert(hexc1(8) == '8'); 47 | assert(hexc1(9) == '9'); 48 | assert(hexc1(0xa) == 'a'); 49 | assert(hexc1(0xb) == 'b'); 50 | assert(hexc1(0xc) == 'c'); 51 | assert(hexc1(0xd) == 'd'); 52 | assert(hexc1(0xe) == 'e'); 53 | assert(hexc1(0xf) == 'f'); 54 | } 55 | 56 | int hexstr(char *buffer, size_t bsize, ubyte *data, size_t dsize, char sep = 0) { 57 | int min = sep ? 3 : 2; // single byte size in characters 58 | assert(min * dsize <= bsize, "Buffer overflow"); 59 | int len; 60 | for (size_t i; i < dsize; ++i) { 61 | if (len + min > bsize) 62 | return len; 63 | 64 | if (sep && len) buffer[len++] = sep; 65 | ubyte b = data[i]; 66 | buffer[len++] = hexc0(b); 67 | buffer[len++] = hexc1(b); 68 | } 69 | return len; 70 | } 71 | extern (D) unittest { 72 | ubyte[4] data = [ 0x12, 0x34, 0x56, 0x78 ]; 73 | char[8] buf = void; 74 | int len = hexstr(buf.ptr, 8, data.ptr, 4); 75 | assert(len == 8); 76 | assert(buf[0] == '1'); 77 | assert(buf[1] == '2'); 78 | assert(buf[2] == '3'); 79 | assert(buf[3] == '4'); 80 | assert(buf[4] == '5'); 81 | assert(buf[5] == '6'); 82 | assert(buf[6] == '7'); 83 | assert(buf[7] == '8'); 84 | } 85 | 86 | int realchar(char *buffer, size_t bsize, char c) { 87 | int len; 88 | if (isprint(c)) { 89 | if (len >= bsize) goto end; 90 | buffer[len++] = c; 91 | } else { 92 | if (len + 4 >= bsize) goto end; 93 | buffer[len++] = '\\'; 94 | buffer[len++] = 'x'; 95 | buffer[len++] = hexc0(c); 96 | buffer[len++] = hexc1(c); 97 | } 98 | end: return len; 99 | } 100 | 101 | int realstring(char *buffer, size_t bsize, const(char)* str, size_t ssize, 102 | char pre = 0, char post = 0) { 103 | int len; // total length 104 | 105 | // No buffer, nothing to process 106 | if (bsize == 0) 107 | return 0; 108 | 109 | // Pre-string character 110 | if (pre && bsize) 111 | buffer[len++] = pre; 112 | 113 | for (size_t i; i < ssize && len < bsize; ++i) { 114 | char c = str[i]; 115 | if (isprint(c)) { 116 | if (len >= bsize) break; 117 | buffer[len++] = c; 118 | } else { 119 | if (len + 4 >= bsize) break; 120 | buffer[len++] = '\\'; 121 | buffer[len++] = 'x'; 122 | buffer[len++] = hexc0(c); 123 | buffer[len++] = hexc1(c); 124 | } 125 | } 126 | 127 | // Post-string character 128 | if (post && len < bsize) 129 | buffer[len++] = post; 130 | 131 | return len; 132 | } 133 | extern (D) unittest { 134 | char[2] bi = "`\n"; 135 | char[10] bo = void; // '`' '\\x0a' 136 | assert(realstring(bo.ptr, 10, bi.ptr, 2) == 5); 137 | assert(bo[0] == '`'); 138 | assert(bo[1] == '\\'); 139 | assert(bo[2] == 'x'); 140 | assert(bo[3] == '0'); 141 | assert(bo[4] == 'a'); 142 | } 143 | 144 | /// Unformat text number. 145 | /// Params: 146 | /// result = Long pointer. 147 | /// str = Input. 148 | /// Returns: True if could not parse number. 149 | bool parse32(int *result, const(char) *str) { 150 | return sscanf(str, "%i", result) != 1; 151 | } 152 | 153 | /// Unformat text number. 154 | /// Params: 155 | /// result = Long pointer. 156 | /// str = Input. 157 | /// Returns: True if could not parse number. 158 | bool parse64(long *result, const(char) *str) { 159 | return sscanf(str, "%lli", result) != 1; 160 | } 161 | 162 | /// Read entire file into memory using the C FILE API. 163 | /// 164 | /// To release its buffer, call free(3). 165 | /// Params: 166 | /// path = File path. 167 | /// size = Pointer to hold file size. 168 | /// Returns: Buffer pointer. Null on CRT error. 169 | ubyte *readall(const(char) *path, size_t *size) { 170 | import core.stdc.stdio : SEEK_SET, SEEK_END, FILE, fopen, ftell, fseek, fread, fclose; 171 | import core.stdc.stdlib : malloc; 172 | 173 | FILE *fd = fopen(path, "rb"); 174 | if (fd == null) 175 | return null; 176 | scope(exit) fclose(fd); 177 | 178 | if (fseek(fd, 0, SEEK_END)) 179 | return null; 180 | 181 | *size = cast(size_t)ftell(fd); 182 | fseek(fd, 0, SEEK_SET); // rewind binding is broken 183 | 184 | ubyte *buffer = cast(ubyte*)malloc(*size); 185 | if (buffer == null) 186 | return null; 187 | 188 | if (fread(buffer, *size, 1, fd) == 0) 189 | return null; 190 | 191 | return buffer; 192 | } 193 | 194 | /// Return the pointer position at the file's basename. 195 | /// 196 | /// On failure, returns original pointer. 197 | /// Params: path = File path. 198 | /// Returns: Non-null pointer 199 | const(char)* basename(const(char) *path) { 200 | enum MAX = 4096; 201 | size_t last, i; 202 | char c = void; 203 | for (; (c = path[i]) != 0 && i < MAX; ++i) { 204 | switch (c) { 205 | case '/', '\\': last = i + 1; continue; 206 | default: 207 | } 208 | } 209 | // "test/" -> invalid 210 | return last >= i ? path : path + last; 211 | } 212 | extern (D) unittest { 213 | import core.stdc.string : strcmp; 214 | const(char) *path = "test/file.lib"; 215 | const(char) *base = basename(path); 216 | assert(base); 217 | assert(strcmp(base, "file.lib") == 0); 218 | } 219 | 220 | /// Returns default character if given character is outside ASCII range. 221 | /// Params: 222 | /// c = Character to evaluate. 223 | /// d = Default character, fallback. 224 | /// Returns: Character. 225 | int asciichar(int c, int d) { 226 | return c < 32 || c > 126 ? d : c; 227 | } -------------------------------------------------------------------------------- /debugger/dub.sdl: -------------------------------------------------------------------------------- 1 | name "debugger" 2 | targetName "alicedbg" 3 | targetType "executable" 4 | targetPath ".." 5 | 6 | dependency "alicedbg" version="*" 7 | dependency "alicedbg:common" version="*" 8 | 9 | # 10 | # ANCHOR Build types 11 | # 12 | 13 | ## Debug builds 14 | 15 | # Debug build with tracing enabled. This will be extremely verbose and the 16 | # output will be cryptid. 17 | # Only to be used with small reproductible bugs. 18 | buildType "trace" { 19 | versions "Trace" "AdbgTrace" 20 | buildOptions "debugMode" "debugInfo" 21 | dflags "-betterC" "-vgc" "-vtls" platform="dmd" 22 | dflags "-betterC" "--vgc" platform="ldc" 23 | dflags "-ftransition=nogc" "-ftransition=tls" platform="gdc" 24 | } 25 | 26 | # Make the compiler print GC and TLS usage, and target information. 27 | buildType "debugv" { 28 | versions "DebugV" "PrintTargetInfo" 29 | buildOptions "debugMode" "debugInfo" 30 | dflags "-betterC" "-vgc" "-vtls" platform="dmd" 31 | dflags "-betterC" "--vgc" platform="ldc" 32 | dflags "-ftransition=nogc" "-ftransition=tls" platform="gdc" 33 | } 34 | 35 | # Ditto but aimed for older compiler version 36 | # Like older dmd versions, ldc 0.17.1, and gdc 6.0 37 | buildType "debugv0" { 38 | versions "DebugV0" "PrintTargetInfo" 39 | buildOptions "debugMode" "debugInfo" 40 | dflags "-vgc" "-vtls" platform="dmd" 41 | dflags "--vgc" platform="ldc" 42 | dflags "-ftransition=nogc" "-ftransition=tls" "-fno-exceptions" "-fno-bounds-check" "-fno-assert" "-fno-builtin" platform="gdc" 43 | } 44 | 45 | # Make the compiler verbose instead of DUB. 46 | buildType "debugvv" { 47 | versions "DebugVV" 48 | buildOptions "debugMode" "debugInfo" 49 | dflags "-betterC" "-v" platform="dmd" 50 | dflags "-betterC" "-v" platform="ldc" 51 | dflags "-v" platform="gdc" 52 | } 53 | 54 | # Compile in debug mode. 55 | buildType "debug" { 56 | versions "Debug" 57 | buildOptions "debugMode" "debugInfo" 58 | dflags "-betterC" platform="dmd" 59 | dflags "-betterC" platform="ldc" 60 | } 61 | 62 | ## Release builds 63 | 64 | # Compile in release mode. 65 | buildType "release" { 66 | versions "Release" 67 | buildOptions "releaseMode" "optimize" "noBoundsCheck" 68 | dflags "-betterC" platform="dmd" 69 | dflags "-betterC" platform="ldc" 70 | } 71 | 72 | # Compile in release mode with debug info. 73 | buildType "release-debug" { 74 | versions "Release" 75 | buildOptions "releaseMode" "optimize" "noBoundsCheck" "debugInfo" 76 | dflags "-betterC" platform="dmd" 77 | dflags "-betterC" platform="ldc" 78 | } 79 | 80 | ## Release-Static builds 81 | 82 | # NOTE: DMD and GDC static builds tend to work better under glibc environments. 83 | 84 | # Compile in release mode as statically linked. 85 | buildType "release-static" { 86 | versions "Release" 87 | buildOptions "releaseMode" "optimize" "noBoundsCheck" 88 | dflags "-betterC" "-L=-static" platform="dmd" 89 | dflags "-fno-druntime" "-Wl,-static" platform="gdc" 90 | dflags "-betterC" "--static" platform="ldc" 91 | } 92 | 93 | # Compile in release mode as statically linked. 94 | buildType "release-debug-static" { 95 | versions "Release" 96 | buildOptions "releaseMode" "optimize" "noBoundsCheck" "debugInfo" 97 | dflags "-betterC" "-L=-static" platform="dmd" 98 | dflags "-fno-druntime" "-Wl,-static" platform="gdc" 99 | dflags "-betterC" "--static" platform="ldc" 100 | } -------------------------------------------------------------------------------- /debugger/src/main.d: -------------------------------------------------------------------------------- 1 | /// Command line interface. 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module main; 7 | 8 | import adbg.self; 9 | import adbg.error; 10 | import core.stdc.stdlib : strtol, EXIT_SUCCESS, EXIT_FAILURE, exit; 11 | import core.stdc.stdio; 12 | import shell, term; 13 | import common.errormgmt; 14 | import common.cli; 15 | import common.utils; 16 | 17 | private: 18 | 19 | immutable option_t[] options = [ 20 | // secrets 21 | option_t(0, "meow", null, &cli_meow), 22 | // common options 23 | option_arch, 24 | option_syntax, 25 | // debugger options 26 | // option_t('E', "env", "Debugger: Supply environment variables to executable", &cli_env), 27 | option_t('p', "attach", "Debugger: Attach to Process ID", &cli_pid), 28 | // pages 29 | option_t('h', "help", "Show this help screen and exit", &cli_help), 30 | option_version, 31 | option_build_info, 32 | option_ver, 33 | option_license, 34 | ]; 35 | enum NUMBER_OF_SECRETS = 1; 36 | 37 | // 38 | // ANCHOR -E, --env 39 | // 40 | 41 | /*int cli_env(const(char) *val) { 42 | import adbg.utils.strings : adbg_util_env; 43 | 44 | globals.env = cast(const(char)**)adbg_util_env(val); 45 | 46 | if (globals.env == null) { 47 | printf("main: Parsing environment failed"); 48 | return EXIT_FAILURE; 49 | } 50 | 51 | return EXIT_SUCCESS; 52 | }*/ 53 | 54 | // 55 | // ANCHOR --attach 56 | // 57 | 58 | int cli_pid(const(char) *val) { 59 | opt_pid = cast(ushort)strtol(val, null, 10); 60 | return EXIT_SUCCESS; 61 | } 62 | 63 | // 64 | // ANCHOR --help 65 | // 66 | 67 | int cli_help() { 68 | puts( 69 | "alicedbg: Aiming to be a simple debugger.\n"~ 70 | "\n"~ 71 | "USAGE\n"~ 72 | " Spawn new process to debug:\n"~ 73 | " alicedbg FILE [OPTIONS...]\n"~ 74 | " Attach debugger to existing process:\n"~ 75 | " alicedbg --attach=PID [OPTIONS...]\n"~ 76 | " Show information page and exit:\n"~ 77 | " alicedbg {-h|--help|--version|--ver|--license}\n"~ 78 | "\n"~ 79 | "OPTIONS" 80 | ); 81 | getoptprinter(options[NUMBER_OF_SECRETS..$]); 82 | puts("\nFor a list of values, for example a list of platforms, type '-a help'"); 83 | exit(0); 84 | return 0; 85 | } 86 | 87 | // --meow: Secret 88 | int cli_meow() { 89 | puts( 90 | ` 91 | +-------------------+ 92 | | I hate x86, meow. | 93 | +--. .--------------+ 94 | \| A_A 95 | (-.-) 96 | / \ _ 97 | / \__/ 98 | \_||__/ 99 | ` 100 | ); 101 | exit(0); 102 | return 0; 103 | } 104 | 105 | extern (C) 106 | int main(int argc, const(char)** argv) { 107 | // Set crash handle, and ignore on error 108 | // Could do a warning, but it might be a little confusing 109 | adbg_self_set_crashhandler(&crashed); 110 | 111 | coninit(); 112 | 113 | argc = getoptions(argc, argv, options); 114 | if (argc < 0) { 115 | logerror(getopterror()); 116 | return EXIT_FAILURE; 117 | } 118 | 119 | // Start or attach to process if specified 120 | if (argc > 0 && argv && shell_spawn(*argv, argc > 1 ? argv + 1 : null)) { 121 | logerror("Could not spawn process: %s", adbg_error_message()); 122 | return 1; 123 | } else if (opt_pid && shell_attach(opt_pid)) { 124 | logerror("Could not attach to process: %s", adbg_error_message()); 125 | return 1; 126 | } 127 | 128 | return shell_start(argc, getoptleftovers()); 129 | } 130 | -------------------------------------------------------------------------------- /dscanner.ini: -------------------------------------------------------------------------------- 1 | ; Configure which static analysis checks are enabled 2 | [analysis.config.StaticAnalysisConfig] 3 | ; Check variable, class, struct, interface, union, and function names against t 4 | ; he Phobos style guide 5 | style_check="disabled" 6 | ; Check for array literals that cause unnecessary allocation 7 | enum_array_literal_check="enabled" 8 | ; Check for poor exception handling practices 9 | exception_check="enabled" 10 | ; Check for use of the deprecated 'delete' keyword 11 | delete_check="enabled" 12 | ; Check for use of the deprecated floating point operators 13 | float_operator_check="enabled" 14 | ; Check number literals for readability 15 | number_style_check="disabled" 16 | ; Checks that opEquals, opCmp, toHash, and toString are either const, immutable 17 | ; , or inout. 18 | object_const_check="enabled" 19 | ; Checks for .. expressions where the left side is larger than the right. 20 | backwards_range_check="enabled" 21 | ; Checks for if statements whose 'then' block is the same as the 'else' block 22 | if_else_same_check="enabled" 23 | ; Checks for some problems with constructors 24 | constructor_check="enabled" 25 | ; Checks for unused variables and function parameters 26 | unused_variable_check="disabled" 27 | ; Checks for unused labels 28 | unused_label_check="enabled" 29 | ; Checks for duplicate attributes 30 | duplicate_attribute="enabled" 31 | ; Checks that opEquals and toHash are both defined or neither are defined 32 | opequals_tohash_check="enabled" 33 | ; Checks for subtraction from .length properties 34 | length_subtraction_check="enabled" 35 | ; Checks for methods or properties whose names conflict with built-in propertie 36 | ; s 37 | builtin_property_names_check="enabled" 38 | ; Checks for confusing code in inline asm statements 39 | asm_style_check="enabled" 40 | ; Checks for confusing logical operator precedence 41 | logical_precedence_check="enabled" 42 | ; Checks for undocumented public declarations 43 | undocumented_declaration_check="disabled" 44 | ; Checks for poor placement of function attributes 45 | function_attribute_check="enabled" 46 | ; Checks for use of the comma operator 47 | comma_expression_check="enabled" 48 | ; Checks for local imports that are too broad 49 | local_import_check="enabled" 50 | ; Checks for variables that could be declared immutable 51 | could_be_immutable_check="disabled" 52 | ; Checks for redundant expressions in if statements 53 | redundant_if_check="enabled" 54 | ; Checks for redundant parenthesis 55 | redundant_parens_check="enabled" 56 | ; Checks for mismatched argument and parameter names 57 | mismatched_args_check="enabled" 58 | ; Checks for labels with the same name as variables 59 | label_var_same_name_check="disabled" 60 | ; Checks for lines longer than 120 characters 61 | long_line_check="enabled" 62 | ; Checks for assignment to auto-ref function parameters 63 | auto_ref_assignment_check="enabled" 64 | ; Checks for incorrect infinite range definitions 65 | incorrect_infinite_range_check="enabled" 66 | ; Checks for asserts that are always true 67 | useless_assert_check="enabled" 68 | ; Check for uses of the old-style alias syntax 69 | alias_syntax_check="disabled" 70 | ; Checks for else if that should be else static if 71 | static_if_else_check="enabled" 72 | ; Check for unclear lambda syntax 73 | lambda_return_check="enabled" 74 | ; Check for auto function without return statement 75 | auto_function_check="enabled" 76 | ; Check for sortedness of imports 77 | imports_sortedness="disabled" 78 | ; Check for explicitly annotated unittests 79 | explicitly_annotated_unittests="disabled" 80 | ; Check for properly documented public functions (Returns, Params) 81 | properly_documented_public_functions="enabled" 82 | ; Check for useless usage of the final attribute 83 | final_attribute_check="enabled" 84 | ; Check for virtual calls in the class constructors 85 | vcall_in_ctor="enabled" 86 | ; Check for useless user defined initializers 87 | useless_initializer="disabled" 88 | ; Check allman brace style 89 | allman_braces_check="disabled" 90 | ; Check for redundant attributes 91 | redundant_attributes_check="enabled" 92 | ; Check public declarations without a documented unittest 93 | has_public_example="disabled" 94 | ; Check for asserts without an explanatory message 95 | assert_without_msg="disabled" 96 | ; Check indent of if constraints 97 | if_constraints_indent="disabled" 98 | ; Check for @trusted applied to a bigger scope than a single function 99 | trust_too_much="enabled" 100 | ; Check for redundant storage classes on variable declarations 101 | redundant_storage_classes="enabled" 102 | ; Check for discarded return values 103 | unused_result="disabled" 104 | ; ModuleFilters for selectively enabling (+std) and disabling (-std.internal) i 105 | ; ndividual checks 106 | [analysis.config.ModuleFilters] 107 | ; Exclude/Import modules 108 | style_check="" 109 | ; Exclude/Import modules 110 | enum_array_literal_check="" 111 | ; Exclude/Import modules 112 | exception_check="" 113 | ; Exclude/Import modules 114 | delete_check="" 115 | ; Exclude/Import modules 116 | float_operator_check="" 117 | ; Exclude/Import modules 118 | number_style_check="" 119 | ; Exclude/Import modules 120 | object_const_check="" 121 | ; Exclude/Import modules 122 | backwards_range_check="" 123 | ; Exclude/Import modules 124 | if_else_same_check="" 125 | ; Exclude/Import modules 126 | constructor_check="" 127 | ; Exclude/Import modules 128 | unused_variable_check="" 129 | ; Exclude/Import modules 130 | unused_label_check="" 131 | ; Exclude/Import modules 132 | duplicate_attribute="" 133 | ; Exclude/Import modules 134 | opequals_tohash_check="" 135 | ; Exclude/Import modules 136 | length_subtraction_check="" 137 | ; Exclude/Import modules 138 | builtin_property_names_check="" 139 | ; Exclude/Import modules 140 | asm_style_check="" 141 | ; Exclude/Import modules 142 | logical_precedence_check="" 143 | ; Exclude/Import modules 144 | undocumented_declaration_check="" 145 | ; Exclude/Import modules 146 | function_attribute_check="" 147 | ; Exclude/Import modules 148 | comma_expression_check="" 149 | ; Exclude/Import modules 150 | local_import_check="" 151 | ; Exclude/Import modules 152 | could_be_immutable_check="" 153 | ; Exclude/Import modules 154 | redundant_if_check="" 155 | ; Exclude/Import modules 156 | redundant_parens_check="" 157 | ; Exclude/Import modules 158 | mismatched_args_check="" 159 | ; Exclude/Import modules 160 | label_var_same_name_check="" 161 | ; Exclude/Import modules 162 | long_line_check="" 163 | ; Exclude/Import modules 164 | auto_ref_assignment_check="" 165 | ; Exclude/Import modules 166 | incorrect_infinite_range_check="" 167 | ; Exclude/Import modules 168 | useless_assert_check="" 169 | ; Exclude/Import modules 170 | alias_syntax_check="" 171 | ; Exclude/Import modules 172 | static_if_else_check="" 173 | ; Exclude/Import modules 174 | lambda_return_check="" 175 | ; Exclude/Import modules 176 | auto_function_check="" 177 | ; Exclude/Import modules 178 | imports_sortedness="" 179 | ; Exclude/Import modules 180 | explicitly_annotated_unittests="" 181 | ; Exclude/Import modules 182 | properly_documented_public_functions="" 183 | ; Exclude/Import modules 184 | final_attribute_check="" 185 | ; Exclude/Import modules 186 | vcall_in_ctor="" 187 | ; Exclude/Import modules 188 | useless_initializer="" 189 | ; Exclude/Import modules 190 | allman_braces_check="" 191 | ; Exclude/Import modules 192 | redundant_attributes_check="" 193 | ; Exclude/Import modules 194 | has_public_example="" 195 | ; Exclude/Import modules 196 | assert_without_msg="" 197 | ; Exclude/Import modules 198 | if_constraints_indent="" 199 | ; Exclude/Import modules 200 | trust_too_much="" 201 | ; Exclude/Import modules 202 | redundant_storage_classes="" 203 | -------------------------------------------------------------------------------- /dub.sdl: -------------------------------------------------------------------------------- 1 | name "alicedbg" 2 | description "Aiming to be a simple debugger" 3 | homepage "http://github.com/dd86k/alicedbg" 4 | authors "dd86k " 5 | copyright "Copyright © dd86k " 6 | license "BSD-3-Clause-Clear" 7 | 8 | # NOTE: BetterC flag 9 | # We explicitly specify the betterC flag to support older DUB releases 10 | # Like v0.9.24 11 | 12 | # NOTE: GDC 5.4 13 | # Doesn't work, ld whines about missing _tlsstart/_tlsend (TLS) references 14 | # value for C++/ObjC but not D: 15 | # -fno-rtti 16 | # -fno-weak 17 | # -fno-threadsafe-statics 18 | # -fextern-tls-init 19 | # -fno-switch-errors: not a command-line option 20 | # -nophoboslib: makes the linker complain more 21 | # Tried with "-fno-moduleinfo" "-fno-emit-moduleinfo" 22 | 23 | # NOTE: GDC and betterC 24 | # Currently (even with GDC 10.3), when compiled with -fno-druntime 25 | # (similar to -betterC), the linker will whine about an undefined reference 26 | # to __gdc_personality_v0, because the gdc-druntime defines this reference. 27 | # Glibc (and subsequently, GCC) has a similiar function, 28 | # __gcc_personality_v0, that is served when unwinding the stack, so to 29 | # handle exceptions. 30 | 31 | # NOTE: GDC 11.1 and betterC 32 | # Yes, it works with -fno-druntime, so it can be possible to add 33 | # "*-gdc-betterc" build types in the future. 34 | 35 | subPackage "common" 36 | subPackage "debugger" 37 | subPackage "dumper" 38 | subPackage { 39 | name "simple" 40 | targetName "simple" 41 | targetType "executable" 42 | sourceFiles "examples/simple.d" 43 | dependency "alicedbg" version="*" 44 | dflags "-betterC" platform="dmd" 45 | dflags "-betterC" platform="ldc" 46 | dflags "-ftransition=nogc" "-ftransition=tls" platform="gdc" 47 | } 48 | 49 | # 50 | # ANCHOR Configurations 51 | # 52 | 53 | # Library 54 | # NOTE: DUB names it "alicedbg.lib" on Windows and "libalicedbg.a" elsewhere 55 | configuration "library" { 56 | versions "StaticLib" 57 | sourcePaths "src" 58 | } 59 | 60 | # Dynamic library/Shared object 61 | # NOTE: DUB names it "alicedbg.dll" on Windows and "libalicedbg.so" elsewhere 62 | # NOTE: MSVC Linker can't find vcruntime140.lib with libs declaration 63 | # LIBPATH isn't compiler-provided one, but Windows SDK 64 | configuration "shared" { 65 | targetType "dynamicLibrary" 66 | versions "SharedLib" # "Shared" might confuse druntime 67 | sourcePaths "src" 68 | } 69 | 70 | # 71 | # ANCHOR Build types 72 | # 73 | 74 | ## Debug builds 75 | 76 | # Debug build with tracing enabled. This will be extremely verbose and the 77 | # output will be cryptid. 78 | # Only to be used with small reproductible bugs. 79 | buildType "trace" { 80 | versions "Trace" "AdbgTrace" 81 | buildOptions "debugMode" "debugInfo" 82 | dflags "-betterC" "-vgc" "-vtls" platform="dmd" 83 | dflags "-betterC" "--vgc" platform="ldc" 84 | dflags "-ftransition=nogc" "-ftransition=tls" platform="gdc" 85 | } 86 | 87 | # Make the compiler print GC and TLS usage, and target information. 88 | buildType "debugv" { 89 | versions "DebugV" "PrintTargetInfo" 90 | buildOptions "debugMode" "debugInfo" 91 | dflags "-betterC" "-vgc" "-vtls" platform="dmd" 92 | dflags "-betterC" "--vgc" platform="ldc" 93 | dflags "-ftransition=nogc" "-ftransition=tls" platform="gdc" 94 | } 95 | 96 | # Ditto but aimed for older compiler version 97 | # Like older dmd versions, ldc 0.17.1, and gdc 6.0 98 | buildType "debugv0" { 99 | versions "DebugV0" "PrintTargetInfo" 100 | buildOptions "debugMode" "debugInfo" 101 | dflags "-vgc" "-vtls" platform="dmd" 102 | dflags "--vgc" platform="ldc" 103 | dflags "-ftransition=nogc" "-ftransition=tls" "-fno-exceptions" "-fno-bounds-check" "-fno-assert" "-fno-builtin" platform="gdc" 104 | } 105 | 106 | # Make the compiler verbose instead of DUB. 107 | buildType "debugvv" { 108 | versions "DebugVV" 109 | buildOptions "debugMode" "debugInfo" 110 | dflags "-betterC" "-v" platform="dmd" 111 | dflags "-betterC" "-v" platform="ldc" 112 | dflags "-v" platform="gdc" 113 | } 114 | 115 | # Compile in debug mode. 116 | buildType "debug" { 117 | versions "Debug" 118 | buildOptions "debugMode" "debugInfo" 119 | dflags "-betterC" platform="dmd" 120 | dflags "-betterC" platform="ldc" 121 | } 122 | 123 | ## Release builds 124 | 125 | # Compile in release mode. 126 | buildType "release" { 127 | versions "Release" 128 | buildOptions "releaseMode" "optimize" "noBoundsCheck" 129 | dflags "-betterC" platform="dmd" 130 | dflags "-betterC" platform="ldc" 131 | } 132 | 133 | # Compile in release mode with debug info. 134 | buildType "release-debug" { 135 | versions "Release" 136 | buildOptions "releaseMode" "optimize" "noBoundsCheck" "debugInfo" 137 | dflags "-betterC" platform="dmd" 138 | dflags "-betterC" platform="ldc" 139 | } 140 | 141 | ## Release-Static builds 142 | 143 | # NOTE: DMD and GDC static builds tend to work better under glibc environments. 144 | 145 | # Compile in release mode as statically linked. 146 | buildType "release-static" { 147 | versions "Release" 148 | buildOptions "releaseMode" "optimize" "noBoundsCheck" 149 | dflags "-betterC" "-L=-static" platform="dmd" 150 | dflags "-fno-druntime" "-Wl,-static" platform="gdc" 151 | dflags "-betterC" "--static" platform="ldc" 152 | } 153 | 154 | # Compile in release mode as statically linked. 155 | buildType "release-debug-static" { 156 | versions "Release" 157 | buildOptions "releaseMode" "optimize" "noBoundsCheck" "debugInfo" 158 | dflags "-betterC" "-L=-static" platform="dmd" 159 | dflags "-fno-druntime" "-Wl,-static" platform="gdc" 160 | dflags "-betterC" "--static" platform="ldc" 161 | } 162 | 163 | # 164 | # ANCHOR Integration tests 165 | # 166 | # NOTE: These MUST be ran as "dub test -b TEST" 167 | # NOTE: Dedicated tests must only exist if one of these conditions are met 168 | # - Requires user input (e.g., readline) 169 | # - Are prone to crashing application (e.g., longjmp on Windows) 170 | # 171 | 172 | buildType "setjmp" { 173 | buildOptions "unittests" 174 | sourceFiles "tests/setjmp.d" 175 | sourcePaths "src" 176 | } 177 | buildType "readkey" { 178 | buildOptions "unittests" 179 | sourceFiles "tests/readkey.d" "app/term.d" 180 | } 181 | buildType "readln" { 182 | buildOptions "unittests" 183 | sourceFiles "tests/readln.d" "app/term.d" 184 | } 185 | 186 | # 187 | # ANCHOR Documentation build types 188 | # 189 | # NOTE: Documentation (docs/ddox) builds 190 | # Works best with the "library" configuration (-c|--configuration) 191 | # to avoid DUB peek in other import directories. 192 | # 193 | 194 | buildType "docs" { 195 | buildRequirements "allowWarnings" 196 | buildOptions "syntaxOnly" 197 | dflags "-Dddocs" 198 | } 199 | buildType "ddox" { 200 | buildRequirements "allowWarnings" 201 | buildOptions "syntaxOnly" 202 | dflags "-Dddocs" "-Df__dummy.html" "-Xfdocs.json" 203 | } -------------------------------------------------------------------------------- /dumper/dub.sdl: -------------------------------------------------------------------------------- 1 | name "dumper" 2 | targetName "alicedump" 3 | targetType "executable" 4 | targetPath ".." 5 | 6 | dependency "alicedbg" version="*" 7 | dependency "alicedbg:common" version="*" 8 | 9 | # 10 | # ANCHOR Build types 11 | # 12 | 13 | ## Debug builds 14 | 15 | # Debug build with tracing enabled. This will be extremely verbose and the 16 | # output will be cryptid. 17 | # Only to be used with small reproductible bugs. 18 | buildType "trace" { 19 | versions "Trace" "AdbgTrace" 20 | buildOptions "debugMode" "debugInfo" 21 | dflags "-betterC" "-vgc" "-vtls" platform="dmd" 22 | dflags "-betterC" "--vgc" platform="ldc" 23 | dflags "-ftransition=nogc" "-ftransition=tls" platform="gdc" 24 | } 25 | 26 | # Make the compiler print GC and TLS usage, and target information. 27 | buildType "debugv" { 28 | versions "DebugV" "PrintTargetInfo" 29 | buildOptions "debugMode" "debugInfo" 30 | dflags "-betterC" "-vgc" "-vtls" platform="dmd" 31 | dflags "-betterC" "--vgc" platform="ldc" 32 | dflags "-ftransition=nogc" "-ftransition=tls" platform="gdc" 33 | } 34 | 35 | # Ditto but aimed for older compiler version 36 | # Like older dmd versions, ldc 0.17.1, and gdc 6.0 37 | buildType "debugv0" { 38 | versions "DebugV0" "PrintTargetInfo" 39 | buildOptions "debugMode" "debugInfo" 40 | dflags "-vgc" "-vtls" platform="dmd" 41 | dflags "--vgc" platform="ldc" 42 | dflags "-ftransition=nogc" "-ftransition=tls" "-fno-exceptions" "-fno-bounds-check" "-fno-assert" "-fno-builtin" platform="gdc" 43 | } 44 | 45 | # Make the compiler verbose instead of DUB. 46 | buildType "debugvv" { 47 | versions "DebugVV" 48 | buildOptions "debugMode" "debugInfo" 49 | dflags "-betterC" "-v" platform="dmd" 50 | dflags "-betterC" "-v" platform="ldc" 51 | dflags "-v" platform="gdc" 52 | } 53 | 54 | # Compile in debug mode. 55 | buildType "debug" { 56 | versions "Debug" 57 | buildOptions "debugMode" "debugInfo" 58 | dflags "-betterC" platform="dmd" 59 | dflags "-betterC" platform="ldc" 60 | } 61 | 62 | ## Release builds 63 | 64 | # Compile in release mode. 65 | buildType "release" { 66 | versions "Release" 67 | buildOptions "releaseMode" "optimize" "noBoundsCheck" 68 | dflags "-betterC" platform="dmd" 69 | dflags "-betterC" platform="ldc" 70 | } 71 | 72 | # Compile in release mode with debug info. 73 | buildType "release-debug" { 74 | versions "Release" 75 | buildOptions "releaseMode" "optimize" "noBoundsCheck" "debugInfo" 76 | dflags "-betterC" platform="dmd" 77 | dflags "-betterC" platform="ldc" 78 | } 79 | 80 | ## Release-Static builds 81 | 82 | # NOTE: DMD and GDC static builds tend to work better under glibc environments. 83 | 84 | # Compile in release mode as statically linked. 85 | buildType "release-static" { 86 | versions "Release" 87 | buildOptions "releaseMode" "optimize" "noBoundsCheck" 88 | dflags "-betterC" "-L=-static" platform="dmd" 89 | dflags "-fno-druntime" "-Wl,-static" platform="gdc" 90 | dflags "-betterC" "--static" platform="ldc" 91 | } 92 | 93 | # Compile in release mode as statically linked. 94 | buildType "release-debug-static" { 95 | versions "Release" 96 | buildOptions "releaseMode" "optimize" "noBoundsCheck" "debugInfo" 97 | dflags "-betterC" "-L=-static" platform="dmd" 98 | dflags "-fno-druntime" "-Wl,-static" platform="gdc" 99 | dflags "-betterC" "--static" platform="ldc" 100 | } -------------------------------------------------------------------------------- /dumper/src/format_ar.d: -------------------------------------------------------------------------------- 1 | /// Library archive dumper 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module format_ar; 7 | 8 | import adbg.disassembler; 9 | import adbg.objectserver; 10 | import adbg.machines; 11 | import adbg.objects.ar; 12 | import adbg.error; 13 | import adbg.utils.bit : adbg_bswap32; 14 | import core.stdc.ctype : isdigit; 15 | import dumper; 16 | import common.utils : realstring; 17 | import common.errormgmt; 18 | 19 | extern (C): 20 | 21 | int dump_archive(adbg_object_t *o) { 22 | if (SELECTED(Select.headers)) 23 | dump_archive_firstheader(o); 24 | if (SELECTED(Select.debug_)) 25 | dump_archive_allheaders(o); 26 | if (SELECTED(Select.exports)) 27 | dump_archive_symbols(o); 28 | return 0; 29 | } 30 | 31 | private: 32 | 33 | void dump_archive_header(ar_member_header_t *member) { 34 | with (member) { 35 | print_stringl("Name", Name.ptr, Name.sizeof); 36 | print_stringl("Date", Date.ptr, Date.sizeof); 37 | print_stringl("UserID", UserID.ptr, UserID.sizeof); 38 | print_stringl("GroupID", GroupID.ptr, GroupID.sizeof); 39 | print_stringl("Mode", Mode.ptr, Mode.sizeof); 40 | print_stringl("Size", Size.ptr, Size.sizeof); 41 | // NOTE: Printing the end marker is pretty pointless 42 | } 43 | } 44 | 45 | // First header only 46 | void dump_archive_firstheader(adbg_object_t *o) { 47 | print_header("Header"); 48 | 49 | ar_member_header_t *member = adbg_object_ar_first_member(o); 50 | if (member == null) 51 | panic_adbg(); 52 | dump_archive_header(member); 53 | } 54 | 55 | void dump_archive_memberdata(adbg_object_t *o, ar_member_header_t *member) { 56 | if (SETTING(Setting.extractAny) == false) 57 | return; 58 | 59 | ar_member_data_t *m = adbg_object_ar_member_data(o, member); 60 | if (m == null) 61 | panic_adbg(); 62 | print_data("data", m.pointer, m.size); 63 | adbg_object_ar_member_data_close(m); 64 | } 65 | 66 | void dump_archive_allheaders(adbg_object_t *o) { 67 | print_header("Debug data"); 68 | 69 | ar_member_header_t *member = adbg_object_ar_first_member(o); 70 | if (member == null) 71 | panic_adbg(); 72 | 73 | uint i; 74 | do { 75 | print_section(i++); 76 | dump_archive_header(member); 77 | dump_archive_memberdata(o, member); 78 | } while ((member = adbg_object_ar_next_member(o)) != null); 79 | } 80 | 81 | void dump_archive_symbols(adbg_object_t *o) { 82 | print_header("Symbols"); 83 | 84 | ar_member_header_t *member = adbg_object_ar_first_member(o); 85 | if (member == null) 86 | panic_adbg(); 87 | 88 | uint i; 89 | do { 90 | // HACK: Ignore special members, doing it here saves some filtering headaches 91 | // This should include "/", "//", "/EXAMPLE/", "__.SYMDEF" stuff 92 | // And exclude "/70" (long name member entry) 93 | // TODO: Check by Archive kind instead, or member kind 94 | if (member.Name[0] == '/' && isdigit( member.Name[1] ) == 0) { 95 | i++; 96 | continue; 97 | } 98 | 99 | // Resolve long-name 100 | char[120] namebuf = void; 101 | if (adbg_object_ar_member_name(namebuf.ptr, namebuf.sizeof, o, member) < 0) { 102 | print_warningf("Member index #%d name issue: %s", i++, adbg_error_message()); 103 | continue; 104 | } 105 | 106 | /* 107 | // Get member object data buffer 108 | ar_member_data_t *memdat = adbg_object_ar_member_data(o, member); 109 | if (memdat == null) { 110 | print_warningf("Member index #%d data issue: %s", i++, adbg_error_message()); 111 | continue; 112 | } 113 | scope(exit) adbg_object_ar_member_data_close(memdat); // closed later 114 | 115 | // Open it, it could be COFF, ELF, anything as a relocatable object 116 | adbg_object_t *obj = adbg_object_open_buffer(memdat.pointer, memdat.size, 0); 117 | if (memdat == null) { 118 | print_warningf("Member index #%d object issue: %s", i++, adbg_error_message()); 119 | continue; 120 | } 121 | scope(exit) adbg_object_close(obj); // closed first 122 | */ 123 | 124 | print_section(i++, namebuf.ptr); 125 | } while ((member = adbg_object_ar_next_member(o)) != null); 126 | } 127 | -------------------------------------------------------------------------------- /dumper/src/format_coff.d: -------------------------------------------------------------------------------- 1 | /// COFF dumper. 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module format_coff; 7 | 8 | import adbg.disassembler; 9 | import adbg.objectserver; 10 | import adbg.machines; 11 | import adbg.objects.coff; 12 | import adbg.error : adbg_error_message; 13 | import core.stdc.ctype : isdigit; 14 | import dumper; 15 | import common.errormgmt; 16 | import common.utils : realstring; 17 | 18 | int dump_coff(adbg_object_t *o) { 19 | if (SELECTED(Select.headers)) 20 | dump_coff_headers(o); 21 | if (SELECTED(Select.sections)) 22 | dump_coff_sections(o); 23 | // TODO: SELECTED(Select.debug_) ("--debug") -> .debug$T (CodeView) 24 | if (SELECTED(Select.exports)) 25 | dump_coff_symbols(o); 26 | if (SETTING(Setting.disasmAny)) 27 | dump_coff_disasm(o); 28 | return 0; 29 | } 30 | 31 | private: 32 | 33 | void dump_coff_headers(adbg_object_t *o) { 34 | print_header("Header"); 35 | 36 | coff_header_t *header = adbg_object_coff_header(o); 37 | 38 | with (header) { 39 | print_x16("f_magic", f_magic, adbg_object_coff_magic_string(f_magic)); 40 | print_u16("f_nscns", f_nscns); 41 | print_u32("f_timedat", f_timedat); 42 | print_u32("f_symptr", f_symptr); 43 | print_u32("f_nsyms", f_nsyms); 44 | print_u16("f_opthdr", f_opthdr); 45 | print_flags16("f_flags", f_flags, 46 | "RELFLG".ptr, COFF_F_RELFLG, 47 | "EXEC".ptr, COFF_F_EXEC, 48 | "LNNO".ptr, COFF_F_LNNO, 49 | "LSYMS".ptr, COFF_F_LSYMS, 50 | "LSB".ptr, COFF_F_LSB, 51 | "MSB".ptr, COFF_F_MSB, 52 | null); 53 | } 54 | 55 | coff_opt_header_t *optheader = adbg_object_coff_optional_header(o); 56 | if (optheader) { 57 | print_header("Optional Header"); 58 | 59 | with (optheader) { 60 | print_x16("magic", magic); 61 | print_x16("vstamp", vstamp); 62 | print_u32("textsize", textsize); 63 | print_u32("datasize", datasize); 64 | print_u32("bss_size", bss_size); 65 | print_x32("entry", entry); 66 | print_x32("text_start", text_start); 67 | print_x32("data_start", data_start); 68 | } 69 | } 70 | } 71 | 72 | void dump_coff_sections(adbg_object_t *o) { 73 | print_header("Sections"); 74 | 75 | coff_section_header_t *section = adbg_object_coff_section_first(o); 76 | if (section == null) 77 | panic_adbg(); 78 | 79 | uint i; 80 | do with (section) { 81 | print_section(++i); 82 | print_stringl("s_name", s_name.ptr, s_name.sizeof); 83 | print_x32("s_paddr", s_paddr); 84 | print_x32("s_vaddr", s_vaddr); 85 | print_u32("s_size", s_size); 86 | print_x32("s_scnptr", s_scnptr); 87 | print_x32("s_relptr", s_relptr); 88 | print_x32("s_lnnoptr", s_lnnoptr); 89 | print_u16("s_nreloc", s_nreloc); 90 | print_u16("s_nlnno", s_nlnno); 91 | print_flags32("s_flags", s_flags, 92 | "STYPE_TEXT".ptr, COFF_STYPE_TEXT, 93 | "STYPE_DATA".ptr, COFF_STYPE_DATA, 94 | "STYPE_BSS".ptr, COFF_STYPE_BSS, 95 | null); 96 | 97 | if (SETTING(Setting.extractAny)) { 98 | void *buf = adbg_object_coff_section_open_data(o, section); 99 | if (buf == null) { 100 | print_warningf("Open failed: %s", adbg_error_message()); 101 | continue; 102 | } 103 | 104 | print_data("section data", buf, s_size); 105 | adbg_object_coff_section_close_data(buf); 106 | } 107 | } while ((section = adbg_object_coff_section_next(o)) != null); 108 | } 109 | 110 | void dump_coff_symbols(adbg_object_t *o) { 111 | print_header("Symbols"); 112 | 113 | coff_symbol_entry_t *symbol = adbg_object_coff_first_symbol(o); 114 | if (symbol == null) 115 | panic_adbg(); 116 | 117 | uint i; 118 | do with (symbol) { 119 | print_section(i++); 120 | const(char) *e_name = adbg_object_coff_symbol_name(o, symbol); 121 | if (e_name == null) { 122 | print_warningf("e_name null: %s", adbg_error_message()); 123 | continue; 124 | } 125 | 126 | print_string("e_name", e_name); 127 | print_x32("e_zeroes", entry.zeroes); 128 | print_x32("e_offset", entry.offset); 129 | print_x32("e_value", e_value); 130 | print_d16("e_scnum", e_scnum); 131 | print_u16("e_type", e_type); 132 | print_u8("e_sclass", e_sclass); 133 | print_u8("e_numaux", e_numaux); 134 | 135 | // Auxiliary entries 136 | // TODO: continuous data dump 137 | for (ubyte a; a < e_numaux; ++a) { 138 | // assume pure binary data 139 | symbol = adbg_object_coff_next_symbol(o); 140 | if (symbol == null) 141 | continue; 142 | 143 | if (SETTING(Setting.extractAny)) 144 | print_data("auxiliary symbol", symbol, coff_symbol_entry_t.sizeof); 145 | } 146 | } while ((symbol = adbg_object_coff_next_symbol(o)) != null); 147 | } 148 | 149 | 150 | void dump_coff_disasm(adbg_object_t *o) { 151 | coff_section_header_t *section = adbg_object_coff_section_first(o); 152 | if (section == null) 153 | panic_adbg(); 154 | 155 | ushort flg = SETTING(Setting.disasmAny) ? 0x00f0 : COFF_STYPE_TEXT; 156 | 157 | uint i; 158 | do with (section) { 159 | if ((s_flags & flg) == 0) 160 | continue; 161 | 162 | void *secdata = adbg_object_coff_section_open_data(o, section); 163 | if (secdata == null) { 164 | print_warningf("section null: %s", adbg_error_message()); 165 | continue; 166 | } 167 | 168 | dump_disassemble_object(o, s_name.ptr, s_name.sizeof, secdata, s_size, 0); 169 | adbg_object_coff_section_close_data(secdata); 170 | } while ((section = adbg_object_coff_section_next(o)) != null); 171 | } -------------------------------------------------------------------------------- /dumper/src/format_dmp.d: -------------------------------------------------------------------------------- 1 | /// Windows memory dump dumper. 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module format_dmp; 7 | 8 | import adbg.disassembler; 9 | import adbg.objectserver; 10 | import adbg.machines; 11 | import adbg.objects.dmp; 12 | import adbg.objects.pe : adbg_object_pe_machine_value_string; 13 | import dumper; 14 | import common.utils; 15 | 16 | extern (C): 17 | 18 | int dump_dmp(adbg_object_t *o) { 19 | if (SELECTED(Select.headers)) 20 | dump_dmp_header(o); 21 | 22 | return 0; 23 | } 24 | 25 | private: 26 | 27 | void dump_dmp_header(adbg_object_t *o) { 28 | print_header("Header"); 29 | 30 | void *header = adbg_object_dmp_header(o); 31 | 32 | char[16] realbuf = void; 33 | 34 | if (adbg_object_dmp_is_64bit(o)) { 35 | dmp64_header_t *header64 = cast(dmp64_header_t*)header; 36 | with (header64) { 37 | int l = realstring(realbuf.ptr, 16, Signature.ptr, Signature.sizeof); 38 | print_x32l("Signature", Signature32, realbuf.ptr, l); 39 | l = realstring(realbuf.ptr, 16, ValidDump.ptr, ValidDump.sizeof); 40 | print_x32l("ValidDump", ValidDump32, realbuf.ptr, l); 41 | print_u32("MajorVersion", MajorVersion); 42 | print_u32("MinorVersion", MinorVersion); 43 | print_x64("DirectoryTableBase", DirectoryTableBase); 44 | print_x64("PfnDatabase", PfnDatabase); 45 | print_x64("PsLoadedModuleList", PsLoadedModuleList); 46 | print_x64("PsActiveProcessHead", PsActiveProcessHead); 47 | print_x32("MachineImageType", MachineImageType, 48 | adbg_object_pe_machine_value_string(cast(ushort)MachineImageType)); 49 | print_u32("NumberProcessors", NumberProcessors); 50 | print_x32("BugCheckCode", BugCheckCode); 51 | print_x32("BugCheckParameter1", BugCheckParameters[0]); 52 | print_x32("BugCheckParameter2", BugCheckParameters[1]); 53 | print_x32("BugCheckParameter3", BugCheckParameters[2]); 54 | print_x32("BugCheckParameter4", BugCheckParameters[3]); 55 | print_x64("KdDebuggerDataBlock", KdDebuggerDataBlock); 56 | 57 | /* 58 | print_stringl("Comment", Comment.ptr, Comment.sizeof); 59 | dump_dmp_attributes(Attributes); 60 | print_x64("BootId", BootId); 61 | print_x32("DumpType", DumpType, SAFEVAL(adbg_object_dmp_dumptype_string(DumpType))); 62 | print_x32("MiniDumpFields", MiniDumpFields); 63 | print_x32("SecondaryDataState", SecondaryDataState); 64 | print_x32("ProductType", ProductType); 65 | print_x32("SuiteMask", SuiteMask); 66 | print_x32("WriterStatus", WriterStatus); 67 | print_x64("RequiredDumpSpace", RequiredDumpSpace); 68 | print_x64("SystemUpTime", SystemUpTime); 69 | print_x64("SystemTime", SystemTime); 70 | */ 71 | } 72 | } else { 73 | dmp32_header_t *header32 = cast(dmp32_header_t*)header; 74 | with (header32) { 75 | int l = realstring(realbuf.ptr, 16, Signature.ptr, Signature.sizeof); 76 | print_x32l("Signature", Signature32, realbuf.ptr, l); 77 | l = realstring(realbuf.ptr, 16, ValidDump.ptr, ValidDump.sizeof); 78 | print_x32l("ValidDump", ValidDump32, realbuf.ptr, l); 79 | print_u32("MajorVersion", MajorVersion); 80 | print_u32("MinorVersion", MinorVersion); 81 | print_x32("DirectoryTableBase", DirectoryTableBase); 82 | print_x32("PfnDatabase", PfnDatabase); 83 | print_x32("PsLoadedModuleList", PsLoadedModuleList); 84 | print_x32("PsActiveProcessHead", PsActiveProcessHead); 85 | print_x32("MachineImageType", MachineImageType, 86 | adbg_object_pe_machine_value_string(cast(ushort)MachineImageType)); 87 | print_u32("NumberProcessors", NumberProcessors); 88 | print_x32("BugCheckCode", BugCheckCode); 89 | print_x32("BugCheckParameter1", BugCheckParameters[0]); 90 | print_x32("BugCheckParameter2", BugCheckParameters[1]); 91 | print_x32("BugCheckParameter3", BugCheckParameters[2]); 92 | print_x32("BugCheckParameter4", BugCheckParameters[3]); 93 | print_stringl("VersionUser", VersionUser.ptr + 1, VersionUser.sizeof); 94 | print_u8("PaeEnabled", PaeEnabled); 95 | print_u8("KdSecondaryVersion", KdSecondaryVersion); 96 | print_x32("KdDebuggerDataBlock", KdDebuggerDataBlock); 97 | 98 | /* 99 | print_stringl("Comment", Comment.ptr, Comment.sizeof); 100 | dump_dmp_attributes(Attributes); 101 | print_x32("BootId", BootId); 102 | print_x32("DumpType", DumpType, SAFEVAL(adbg_object_dmp_dumptype_string(DumpType))); 103 | print_x32("MiniDumpFields", MiniDumpFields); 104 | print_x32("SecondaryDataState", SecondaryDataState); 105 | print_x32("ProductType", ProductType); 106 | print_x32("SuiteMask", SuiteMask); 107 | print_x32("WriterStatus", WriterStatus); 108 | print_x64("RequiredDumpSpace", RequiredDumpSpace); 109 | print_x64("SystemUpTime", SystemUpTime); 110 | print_x64("SystemTime", SystemTime); 111 | */ 112 | } 113 | } 114 | } 115 | 116 | void dump_dmp_attributes(uint Attributes) { 117 | print_flags32("Attributes", Attributes, 118 | "HiberCrash".ptr, HiberCrash, 119 | "DumpDevicePowerOff".ptr, DumpDevicePowerOff, 120 | "InsufficientDumpfileSize".ptr, InsufficientDumpfileSize, 121 | "KernelGeneratedTriageDump".ptr, KernelGeneratedTriageDump, 122 | "LiveDumpGeneratedDump".ptr, LiveDumpGeneratedDump, 123 | "DumpIsGeneratedOffline".ptr, DumpIsGeneratedOffline, 124 | "FilterDumpFile".ptr, FilterDumpFile, 125 | "EarlyBootCrash".ptr, EarlyBootCrash, 126 | "EncryptedDumpData".ptr, EncryptedDumpData, 127 | "DecryptedDump".ptr, DecryptedDump, 128 | null); 129 | } -------------------------------------------------------------------------------- /dumper/src/format_lx.d: -------------------------------------------------------------------------------- 1 | /// OS/2 / Windows 9x LX file dumper 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module format_lx; 7 | 8 | import adbg.disassembler; 9 | import adbg.objectserver; 10 | import adbg.machines : AdbgMachine; 11 | import adbg.objects.lx; 12 | import dumper; 13 | import format_mz; 14 | 15 | extern (C): 16 | 17 | int dump_lx(adbg_object_t *o) { 18 | if (SELECTED(Select.headers)) 19 | dump_lx_hdr(o); 20 | return 0; 21 | } 22 | 23 | private: 24 | 25 | void dump_lx_hdr(adbg_object_t *o) { 26 | // Print legacy header 27 | dump_mz_ext_header(adbg_object_lx_mz_header(o)); 28 | 29 | print_header("Header"); 30 | 31 | lx_header_t* header = adbg_object_lx_header(o); 32 | with (header) { 33 | print_x16("e32_magic", magic, magic == LE_MAGIC ? "LE" : "LX"); 34 | print_x8("e32_border", border); 35 | print_x8("e32_worder", worder); 36 | print_x32("e32_level", level); 37 | print_u16("e32_cpu", cpu, adbg_object_lx_cputype_string(cpu)); 38 | print_u16("e32_os", os, adbg_object_lx_ostype_string(os)); 39 | print_x32("e32_ver", ver); 40 | print_flags32("e32_mflags", mflags, 41 | "PROCLIBINIT".ptr, LX_FLAG_PROCLIBINIT, 42 | "INTFIXUPS".ptr, LX_FLAG_INTFIXUPS, 43 | "EXTFIXUPS".ptr, LX_FLAG_EXTFIXUPS, 44 | "INCOMPATPMWIN".ptr, LX_FLAG_INCOMPATPMWIN, 45 | "COMPATPMWIN".ptr, LX_FLAG_COMPATPMWIN, 46 | "USESPMWIN".ptr, LX_FLAG_USESPMWIN, 47 | "MODUNLOADABLE".ptr, LX_FLAG_MODUNLOADABLE, 48 | "MPUNSAFE".ptr, LX_FLAG_MPUNSAFE, 49 | "PROCLIBTERM".ptr, LX_FLAG_PROCLIBTERM, 50 | null); 51 | print_x32("e32_mflags:ModuleType", mflags, adbg_object_lx_modtype_string(mflags)); 52 | print_u32("e32_mpages", mpages); 53 | print_x32("e32_startobj", startobj); 54 | print_x32("e32_eip", eip); 55 | print_x32("e32_stackobj", stackobj); 56 | print_x32("e32_esp", esp); 57 | print_u32("e32_pagesize", pagesize); 58 | print_x32("e32_pageshift", pageshift); 59 | print_u32("e32_fixupsize", fixupsize); 60 | print_x32("e32_fixupsum", fixupsum); 61 | print_u32("e32_ldrsize", ldrsize); 62 | print_x32("e32_ldrsum", ldrsum); 63 | print_x32("e32_objtab", objtab); 64 | print_x32("e32_objcnt", objcnt); 65 | print_x32("e32_objmap", objmap); 66 | print_x32("e32_itermap", itermap); 67 | print_x32("e32_rsrctab", rsrctab); 68 | print_x32("e32_rsrccnt", rsrccnt); 69 | print_x32("e32_restab", restab); 70 | print_x32("e32_enttab", enttab); 71 | print_x32("e32_dirtab", dirtab); 72 | print_x32("e32_dircnt", dircnt); 73 | print_x32("e32_fpagetab", fpagetab); 74 | print_x32("e32_frectab", frectab); 75 | print_x32("e32_impmod", impmod); 76 | print_x32("e32_impmodcnt", impmodcnt); 77 | print_x32("e32_impproc", impproc); 78 | print_x32("e32_pagesum", pagesum); 79 | print_x32("e32_datapage", datapage); 80 | print_x32("e32_preload", preload); 81 | print_x32("e32_nrestab", nrestab); 82 | print_u32("e32_cbnrestab", cbnrestab); 83 | print_x32("e32_nressum", nressum); 84 | print_x32("e32_autodata", autodata); 85 | print_x32("e32_debuginfo", debuginfo); 86 | print_u32("e32_debuglen", debuglen); 87 | print_x32("e32_instpreload", instpreload); 88 | print_x32("e32_instdemand", instdemand); 89 | print_u32("e32_heapsize", heapsize); 90 | print_u32("e32_stacksize", stacksize); 91 | print_x8("e32_res[0]", res1[0]); 92 | print_x8("e32_res[1]", res1[1]); 93 | print_x8("e32_res[2]", res1[2]); 94 | print_x8("e32_res[3]", res1[3]); 95 | print_x8("e32_res[4]", res1[4]); 96 | print_x8("e32_res[5]", res1[5]); 97 | print_x8("e32_res[6]", res1[6]); 98 | print_x8("e32_res[7]", res1[7]); 99 | if (magic == LE_MAGIC) { 100 | print_x32("winresoff", winresoff); 101 | print_u32("winreslen", winreslen); 102 | print_x16("device_id", device_id); 103 | print_x16("ddk_version", ddk_version); 104 | return; 105 | } 106 | print_x8("e32_res[8]", res[8]); 107 | print_x8("e32_res[9]", res[9]); 108 | print_x8("e32_res[10]", res[10]); 109 | print_x8("e32_res[11]", res[11]); 110 | print_x8("e32_res[12]", res[12]); 111 | print_x8("e32_res[13]", res[13]); 112 | print_x8("e32_res[14]", res[14]); 113 | print_x8("e32_res[15]", res[15]); 114 | print_x8("e32_res[16]", res[16]); 115 | print_x8("e32_res[17]", res[17]); 116 | print_x8("e32_res[18]", res[18]); 117 | print_x8("e32_res[19]", res[19]); 118 | } 119 | } -------------------------------------------------------------------------------- /dumper/src/format_macho.d: -------------------------------------------------------------------------------- 1 | /// Mach-O object dumper. 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module format_macho; 7 | 8 | import adbg.disassembler; 9 | import adbg.objectserver; 10 | import adbg.objects.macho; 11 | import dumper; 12 | import common.errormgmt; 13 | 14 | int dump_macho(adbg_object_t *o) { 15 | if (SELECTED(Select.headers)) 16 | adbg_object_macho_is_fat(o) ? 17 | dump_macho_header_fat(o) : dump_macho_header_regular(o); 18 | if (SELECTED(Select.segments)) 19 | dump_macho_segments(o); 20 | if (SELECTED(Select.sections)) 21 | dump_macho_sections(o); 22 | 23 | return 0; 24 | } 25 | 26 | private: 27 | 28 | void dump_macho_header_fat(adbg_object_t *o) { 29 | print_header("FAT Header"); 30 | 31 | macho_fat_header_t *header = adbg_object_macho_fat_header(o); 32 | 33 | print_x32("magic", header.magic, adbg_object_macho_magic_string(header.magic)); 34 | print_u32("nfat_arch", header.nfat_arch); 35 | 36 | print_header("FAT Arch Headers"); 37 | 38 | size_t i; 39 | macho_fat_arch_entry_t *arch = void; 40 | while ((arch = adbg_object_macho_fat_arch(o, i++)) != null) with (arch) { 41 | print_section(cast(uint)i); 42 | print_x32("cputype", cputype, adbg_object_macho_cputype_string(cputype)); 43 | print_x32("subtype", subtype, adbg_object_macho_subtype_string(cputype, subtype)); 44 | print_x32("offset", offset); 45 | print_x32("size", size); 46 | print_x32("alignment", alignment); 47 | } 48 | } 49 | 50 | void dump_macho_header_regular(adbg_object_t *o) { 51 | print_header("Header"); 52 | 53 | macho_header_t *header = adbg_object_macho_header(o); 54 | 55 | with (header) { 56 | print_x32("magic", magic, adbg_object_macho_magic_string(magic)); 57 | print_x32("cputype", cputype, adbg_object_macho_cputype_string(cputype)); 58 | print_x32("subtype", subtype, adbg_object_macho_subtype_string(cputype, subtype)); 59 | print_x32("filetype", filetype, adbg_object_macho_filetype_string(filetype)); 60 | print_u32("ncmds", ncmds); 61 | print_u32("sizeofcmds", sizeofcmds); 62 | print_flags32("flags", flags, 63 | "NOUNDEFS".ptr, MACHO_FLAG_NOUNDEFS, 64 | "INCRLINK".ptr, MACHO_FLAG_INCRLINK, 65 | "DYLDLINK".ptr, MACHO_FLAG_DYLDLINK, 66 | "BINDATLOAD".ptr, MACHO_FLAG_BINDATLOAD, 67 | "PREBOUND".ptr, MACHO_FLAG_PREBOUND, 68 | "SPLIT_SEGS".ptr, MACHO_FLAG_SPLIT_SEGS, 69 | "LAZY_INIT".ptr, MACHO_FLAG_LAZY_INIT, 70 | "TWOLEVEL".ptr, MACHO_FLAG_TWOLEVEL, 71 | "FORCE_FLAT".ptr, MACHO_FLAG_FORCE_FLAT, 72 | "NOMULTIDEFS".ptr, MACHO_FLAG_NOMULTIDEFS, 73 | "NOFIXPREBINDING".ptr, MACHO_FLAG_NOFIXPREBINDING, 74 | "PREBINDABLE".ptr, MACHO_FLAG_PREBINDABLE, 75 | "ALLMODSBOUND".ptr, MACHO_FLAG_ALLMODSBOUND, 76 | "SUBSECTIONS_VIA_SYMBOLS".ptr, MACHO_FLAG_SUBSECTIONS_VIA_SYMBOLS, 77 | "CANONICAL".ptr, MACHO_FLAG_CANONICAL, 78 | "WEAK_DEFINES".ptr, MACHO_FLAG_WEAK_DEFINES, 79 | "BINDS_TO_WEAK".ptr, MACHO_FLAG_BINDS_TO_WEAK, 80 | "ALLOW_STACK_EXECUTION".ptr, MACHO_FLAG_ALLOW_STACK_EXECUTION, 81 | "ROOT_SAFE".ptr, MACHO_FLAG_ROOT_SAFE, 82 | "SETUID_SAFE".ptr, MACHO_FLAG_SETUID_SAFE, 83 | "NO_REEXPORTED_DYLIBS".ptr, MACHO_FLAG_NO_REEXPORTED_DYLIBS, 84 | "PIE".ptr, MACHO_FLAG_PIE, 85 | "DEAD_STRIPPABLE_DYLIB".ptr, MACHO_FLAG_DEAD_STRIPPABLE_DYLIB, 86 | "HAS_TLV_DESCRIPTORS".ptr, MACHO_FLAG_HAS_TLV_DESCRIPTORS, 87 | "NO_HEAP_EXECUTION".ptr, MACHO_FLAG_NO_HEAP_EXECUTION, 88 | "APP_EXTENSION_SAFE".ptr, MACHO_FLAG_APP_EXTENSION_SAFE, 89 | null); 90 | } 91 | } 92 | 93 | void dump_macho_segments(adbg_object_t *o) { 94 | // NOTE: These are load commands but using segments for all of them 95 | // just makes naming shorter and simpler 96 | print_header("Segments"); 97 | 98 | size_t i; 99 | macho_load_command_t *command = void; 100 | for (; (command = adbg_object_macho_load_command(o, i)) != null; ++i) { 101 | print_section(cast(uint)i); 102 | print_x32("cmd", command.cmd, SAFEVAL(adbg_object_macho_command_string(command.cmd))); 103 | print_x32("cmdsize", command.cmdsize); 104 | 105 | switch (command.cmd) { 106 | case MACHO_LC_SEGMENT: 107 | macho_segment_command_t *seg = cast(macho_segment_command_t*)command; 108 | print_stringl("segname", seg.segname.ptr, cast(uint)seg.segname.sizeof); 109 | print_x32("vmaddr", seg.vmaddr); 110 | print_u32("vmsize", seg.vmsize); 111 | print_x32("fileoff", seg.fileoff); 112 | print_x32("filesize", seg.filesize); 113 | print_u32("maxprot", seg.maxprot); 114 | print_u32("initprot", seg.initprot); 115 | print_u32("nsects", seg.nsects); 116 | print_x32("flags", seg.flags); 117 | continue; 118 | case MACHO_LC_SEGMENT_64: 119 | macho_segment_command_64_t *seg = cast(macho_segment_command_64_t*)command; 120 | print_stringl("segname", seg.segname.ptr, cast(uint)seg.segname.sizeof); 121 | print_x64("vmaddr", seg.vmaddr); 122 | print_u64("vmsize", seg.vmsize); 123 | print_x64("fileoff", seg.fileoff); 124 | print_x64("filesize", seg.filesize); 125 | print_u32("maxprot", seg.maxprot); 126 | print_u32("initprot", seg.initprot); 127 | print_u32("nsects", seg.nsects); 128 | print_x32("flags", seg.flags); 129 | continue; 130 | default: continue; 131 | } 132 | } 133 | if (i == 0) 134 | panic_adbg(); 135 | } 136 | 137 | void dump_macho_sections(adbg_object_t *o) { 138 | print_header("Sections"); 139 | 140 | void function(void*) dumpsection = 141 | adbg_object_macho_is_64bit(o) ? 142 | cast(void function(void*))&dump_macho_section64 : 143 | cast(void function(void*))&dump_macho_section32; 144 | size_t i; 145 | uint t; 146 | macho_load_command_t *command = void; 147 | for (; (command = adbg_object_macho_load_command(o, i)) != null; ++i) { 148 | size_t si; 149 | void *section = void; 150 | for (; (section = adbg_object_macho_segment_section(o, command, si)) != null; ++si) { 151 | print_section(t++); 152 | dumpsection(section); 153 | } 154 | } 155 | } 156 | void dump_macho_section32(macho_section_t *section) { 157 | print_stringl("sectname", section.sectname.ptr, section.sectname.sizeof); 158 | print_stringl("segname", section.segname.ptr, section.segname.sizeof); 159 | print_x32("addr", section.addr); 160 | print_u32("size", section.size); 161 | print_x32("offset", section.offset); 162 | print_x32("align", section.align_); 163 | print_x32("reloff", section.reloff); 164 | print_x32("nrelocs", section.nrelocs); 165 | print_x32("flags", section.flags); 166 | print_x32("reserved1", section.reserved1); 167 | print_x32("reserved2", section.reserved2); 168 | } 169 | void dump_macho_section64(macho_section64_t *section) { 170 | print_stringl("sectname", section.sectname.ptr, section.sectname.sizeof); 171 | print_stringl("segname", section.segname.ptr, section.segname.sizeof); 172 | print_x64("addr", section.addr); 173 | print_u64("size", section.size); 174 | print_x32("offset", section.offset); 175 | print_x32("align", section.align_); 176 | print_x32("reloff", section.reloff); 177 | print_x32("nrelocs", section.nrelocs); 178 | print_x32("flags", section.flags); 179 | print_x32("reserved1", section.reserved1); 180 | print_x32("reserved2", section.reserved2); 181 | print_x32("reserved3", section.reserved3); 182 | 183 | } -------------------------------------------------------------------------------- /dumper/src/format_mdmp.d: -------------------------------------------------------------------------------- 1 | /// Minidump dumper 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module format_mdmp; 7 | 8 | import adbg.disassembler; 9 | import adbg.objectserver; 10 | import adbg.machines; 11 | import adbg.objects.mdmp; 12 | import adbg.utils.date : ctime32; 13 | import adbg.include.windows.winnt; 14 | import dumper; 15 | import common.utils : realstring; 16 | import common.errormgmt; 17 | 18 | int dump_minidump(adbg_object_t *o) { 19 | if (SELECTED(Select.headers)) 20 | dump_minidump_headers(o); 21 | 22 | if (SELECTED(Select.debug_)) 23 | dump_minidump_debug(o); 24 | 25 | return 0; 26 | } 27 | 28 | private: 29 | 30 | void dump_minidump_headers(adbg_object_t *o) { 31 | print_header("Header"); 32 | 33 | mdmp_header_t *header = adbg_object_mdmp_header(o); 34 | 35 | with (header) { 36 | print_x32("Signature", Signature); 37 | print_x16("Magic", Magic); 38 | print_u16("Version", Version); 39 | print_u32("StreamCount", StreamCount); 40 | print_x32("StreamRva", StreamRva); 41 | print_x32("Checksum", Checksum); 42 | print_x32("Timestamp", Timestamp, ctime32(Timestamp)); 43 | print_flags64("Flags", Flags, 44 | "WithDataSegs".ptr, MiniDumpWithDataSegs, 45 | "WithFullMemory".ptr, MiniDumpWithFullMemory, 46 | "WithHandleData".ptr, MiniDumpWithHandleData, 47 | "FilterMemory".ptr, MiniDumpFilterMemory, 48 | "ScanMemory".ptr, MiniDumpScanMemory, 49 | "WithUnloadedModules".ptr, MiniDumpWithUnloadedModules, 50 | "WithIndirectlyReferencedMemory".ptr, MiniDumpWithIndirectlyReferencedMemory, 51 | "FilterModulePaths".ptr, MiniDumpFilterModulePaths, 52 | "WithProcessThreadData".ptr, MiniDumpWithProcessThreadData, 53 | "WithPrivateReadWriteMemory".ptr, MiniDumpWithPrivateReadWriteMemory, 54 | "WithoutOptionalData".ptr, MiniDumpWithoutOptionalData, 55 | "WithFullMemoryInfo".ptr, MiniDumpWithFullMemoryInfo, 56 | "WithThreadInfo".ptr, MiniDumpWithThreadInfo, 57 | "WithCodeSegs".ptr, MiniDumpWithCodeSegs, 58 | "WithoutAuxiliaryState".ptr, MiniDumpWithoutAuxiliaryState, 59 | "WithFullAuxiliaryState".ptr, MiniDumpWithFullAuxiliaryState, 60 | "WithPrivateWriteCopyMemory".ptr, MiniDumpWithPrivateWriteCopyMemory, 61 | "IgnoreInaccessibleMemory".ptr, MiniDumpIgnoreInaccessibleMemory, 62 | "WithTokenInformation".ptr, MiniDumpWithTokenInformation, 63 | "WithModuleHeaders".ptr, MiniDumpWithModuleHeaders, 64 | "FilterTriage".ptr, MiniDumpFilterTriage, 65 | "WithAvxXStateContext".ptr, MiniDumpWithAvxXStateContext, 66 | "WithIptTrace".ptr, MiniDumpWithIptTrace, 67 | "ScanInaccessiblePartialPages".ptr, MiniDumpScanInaccessiblePartialPages, 68 | "FilterWriteCombinedMemory".ptr, MiniDumpFilterWriteCombinedMemory, 69 | null); 70 | } 71 | } 72 | 73 | void dump_minidump_debug(adbg_object_t *o) { 74 | print_header("Debug"); 75 | 76 | reset_error(); 77 | size_t i; 78 | for (mdmp_directory_entry_t *entry; (entry = adbg_object_mdmp_dir_entry(o, i)) != null; ++i) { 79 | print_section(cast(uint)i); 80 | print_u32("StreamType", entry.StreamType, adbg_object_mdmp_dir_entry_type_string(entry)); 81 | print_x32("Size", entry.Size); 82 | print_x32("Rva", entry.Rva); 83 | 84 | switch (entry.StreamType) { 85 | case ThreadListStream: 86 | print_header("Threadlist"); 87 | 88 | mdmp_threadlist_t *threads = 89 | cast(mdmp_threadlist_t*)adbg_object_mdmp_dir_entry_data(o, entry); 90 | if (threads == null) 91 | panic_adbg(); 92 | 93 | for (uint ti; ti < threads.Count; ++ti) { 94 | mdmp_thread_t *thread = &threads.Threads.ptr[ti]; 95 | print_section(ti); 96 | print_x32("ID", thread.ID); 97 | print_x32("SuspendCount", thread.SuspendCount); 98 | print_x32("PriorityClass", thread.PriorityClass); 99 | print_x32("Priority", thread.Priority); 100 | print_x64("Teb", thread.Teb); 101 | 102 | /* 103 | X86_NT_CONTEXT *context = void; 104 | if (adbg_object_offsetl(o, cast(void**)&context, 105 | thread.ThreadContext.Rva, thread.ThreadContext.Size)) { 106 | print_warningf("Thread.Context.Rva points outbound"); 107 | continue; 108 | } 109 | 110 | print_x32("Eip", context.Eip); 111 | */ 112 | } 113 | 114 | adbg_object_mdmp_dir_entry_data_close(threads); 115 | break; 116 | case ModuleListStream: 117 | break; 118 | case MemoryListStream: 119 | break; 120 | case ExceptionStream: 121 | break; 122 | case SystemInfoStream: 123 | break; 124 | case ThreadExListStream: 125 | break; 126 | case Memory64ListStream: 127 | break; 128 | case CommentStreamA: 129 | break; 130 | case CommentStreamW: 131 | break; 132 | case HandleDataStream: 133 | break; 134 | case FunctionTableStream: 135 | break; 136 | case UnloadedModuleListStream: 137 | break; 138 | case MiscInfoStream: 139 | break; 140 | case MemoryInfoListStream: 141 | break; 142 | case ThreadInfoListStream: 143 | break; 144 | case HandleOperationListStream: 145 | break; 146 | case TokenStream: 147 | break; 148 | case JavaScriptDataStream: 149 | break; 150 | case SystemMemoryInfoStream: 151 | break; 152 | case ProcessVmCountersStream: 153 | break; 154 | case IptTraceStream: 155 | break; 156 | case ThreadNamesStream: 157 | break; 158 | default: continue; 159 | } 160 | } 161 | if (i == 0 && errorcode()) 162 | panic_adbg(); 163 | } -------------------------------------------------------------------------------- /dumper/src/format_mscoff.d: -------------------------------------------------------------------------------- 1 | /// MS-COFF dumper 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module format_mscoff; 7 | 8 | import adbg.disassembler; 9 | import adbg.objectserver; 10 | import adbg.machines; 11 | import adbg.objects.mscoff; 12 | import adbg.objects.pe : adbg_object_pe_machine_value_string; 13 | import adbg.utils.uid; 14 | import dumper; 15 | 16 | int dump_mscoff(adbg_object_t *o) { 17 | if (SELECTED(Select.headers)) 18 | dump_mscoff_header(o); 19 | 20 | return 0; 21 | } 22 | 23 | private: 24 | 25 | void dump_mscoff_header(adbg_object_t *o) { 26 | print_header("Header"); 27 | 28 | mscoff_import_header_t *header = cast(mscoff_import_header_t*)adbg_object_mscoff_header(o); 29 | 30 | switch (header.Version) { 31 | case MSCOFF_VERSION_IMPORT: // 0 32 | with (header) { 33 | print_x16("Sig1", Sig1); 34 | print_x16("Sig2", Sig2); 35 | print_u16("Version", Version); 36 | print_x16("Machine", Machine, adbg_object_pe_machine_value_string(Machine)); 37 | print_x32("TimeStamp", TimeStamp); 38 | print_x32("Size", Size); 39 | print_x16("Ordinal", Ordinal); 40 | print_x64("Flags", Flags); 41 | } 42 | break; 43 | case MSCOFF_VERSION_ANON: // 1 44 | mscoff_anon_header_t *header1 = cast(mscoff_anon_header_t*)header; 45 | with (header1) { 46 | print_x16("Sig1", Sig1); 47 | print_x16("Sig2", Sig2); 48 | print_u16("Version", Version); 49 | print_x16("Machine", Machine, adbg_object_pe_machine_value_string(Machine)); 50 | print_x32("TimeDateStamp", TimeDateStamp); 51 | char[UID_TEXTLEN] uid = void; 52 | uid_text(ClassID, uid, UID_GUID); 53 | print_string("ClassID", uid.ptr); 54 | print_x32("SizeOfData", SizeOfData); 55 | } 56 | break; 57 | case MSCOFF_VERSION_ANONV2: // 2 58 | mscoff_anon_header_v2_t *header2 = cast(mscoff_anon_header_v2_t*)header; 59 | with (header2) { 60 | print_x16("Sig1", Sig1); 61 | print_x16("Sig2", Sig2); 62 | print_u16("Version", Version); 63 | print_x16("Machine", Machine, adbg_object_pe_machine_value_string(Machine)); 64 | print_x32("TimeDateStamp", TimeDateStamp); 65 | char[UID_TEXTLEN] uid = void; 66 | uid_text(ClassID, uid, UID_GUID); 67 | print_string("ClassID", uid.ptr); 68 | print_x32("SizeOfData", SizeOfData); 69 | print_x32("Flags", Flags); 70 | print_x32("MetaDataSize", MetaDataSize); 71 | } 72 | break; 73 | default: 74 | } 75 | } -------------------------------------------------------------------------------- /dumper/src/format_mz.d: -------------------------------------------------------------------------------- 1 | /// MS-DOS MZ file dumper 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module format_mz; 7 | 8 | import adbg.disassembler; 9 | import adbg.objectserver; 10 | import adbg.machines : AdbgMachine; 11 | import adbg.objects.mz; 12 | import core.stdc.stdlib; 13 | import dumper; 14 | import common.errormgmt; 15 | 16 | extern (C): 17 | 18 | /// Print MZ object. 19 | /// Params: o = Object instance. 20 | /// Returns: Non-zero on error. 21 | int dump_mz(adbg_object_t *o) { 22 | if (SELECTED(Select.headers)) 23 | dump_mz_hdr(o); 24 | if (SELECTED(Select.relocs)) 25 | dump_mz_relocs(o); 26 | if (SETTING(Setting.disasmAny)) 27 | dump_mz_disasm(o); 28 | return 0; 29 | } 30 | 31 | // Print extended MZ header for NE/LX/PE32 32 | void dump_mz_ext_header(mz_header_t *header) { 33 | print_header("Legacy Header"); 34 | 35 | with (header) { 36 | print_u16("e_cblp", e_cblp); 37 | print_u16("e_cp", e_cp); 38 | print_u16("e_crlc", e_crlc); 39 | print_u16("e_cparh", e_cparh); 40 | print_u16("e_minalloc", e_minalloc); 41 | print_u16("e_maxalloc", e_maxalloc); 42 | print_x16("e_ss", e_ss); 43 | print_x16("e_sp", e_sp); 44 | print_x16("e_csum", e_csum); 45 | print_x16("e_ip", e_ip); 46 | print_x16("e_cs", e_cs); 47 | print_x16("e_lfarlc", e_lfarlc); 48 | print_u16("e_ovno", e_ovno); 49 | for (size_t i; i < e_res.length; ++i) 50 | printf_x16("e_res[%u]", e_res[i], cast(uint)i); 51 | print_x32("e_lfanew", e_lfanew); 52 | } 53 | } 54 | 55 | private: 56 | 57 | void dump_mz_hdr(adbg_object_t *o) { 58 | print_header("Header"); 59 | 60 | //TODO: If start of code or relocs start within extended header, 61 | // manually cut it off from the header prints (reserved words and newloc) 62 | mz_header_t* header = adbg_object_mz_header(o); 63 | 64 | with (header) { 65 | print_u16("e_cblp", e_cblp); 66 | print_u16("e_cp", e_cp); 67 | print_u16("e_crlc", e_crlc); 68 | print_u16("e_cparh", e_cparh); 69 | print_u16("e_minalloc", e_minalloc); 70 | print_u16("e_maxalloc", e_maxalloc); 71 | print_x16("e_ss", e_ss); 72 | print_x16("e_sp", e_sp); 73 | print_x16("e_csum", e_csum); 74 | print_x16("e_ip", e_ip); 75 | print_x16("e_cs", e_cs); 76 | print_x16("e_lfarlc", e_lfarlc); 77 | print_u16("e_ovno", e_ovno); 78 | } 79 | } 80 | 81 | void dump_mz_relocs(adbg_object_t *o) { 82 | print_header("Relocations"); 83 | 84 | mz_reloc_t *reloc = void; 85 | size_t i; 86 | while ((reloc = adbg_object_mz_reloc(o, i++)) != null) 87 | with (reloc) print_reloc16(cast(uint)i, segment, offset); 88 | } 89 | 90 | void dump_mz_disasm(adbg_object_t *o) { 91 | mz_header_t* header = adbg_object_mz_header(o); 92 | 93 | // Get data location 94 | uint start = (header.e_cparh << 4) + header.e_cblp; // (paragraphs * 16) + rest 95 | if (start < mz_header_t.sizeof) 96 | panic(1, "Data start outside of file buffer"); 97 | 98 | // Get data length 99 | uint len = (header.e_cp << 4) + header.e_cblp; // (paragraphs * 16) + rest 100 | 101 | void* buffer = malloc(len); 102 | if (buffer == null) 103 | panic_crt(); 104 | if (adbg_object_read_at(o, start, buffer, len)) 105 | panic_adbg(); 106 | 107 | dump_disassemble_object(o, null, 0, buffer, len, 0); 108 | } 109 | -------------------------------------------------------------------------------- /dumper/src/format_ne.d: -------------------------------------------------------------------------------- 1 | /// Windows 1.x NE file dumper 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module format_ne; 7 | 8 | import adbg.disassembler; 9 | import adbg.objectserver; 10 | import adbg.machines : AdbgMachine; 11 | import adbg.objects.ne; 12 | import dumper; 13 | import format_mz : dump_mz_ext_header; 14 | 15 | extern (C): 16 | 17 | int dump_ne(adbg_object_t *o) { 18 | if (SELECTED(Select.headers)) 19 | dump_ne_hdr(o); 20 | return 0; 21 | } 22 | 23 | private: 24 | 25 | void dump_ne_hdr(adbg_object_t *o) { 26 | // Print legacy header 27 | dump_mz_ext_header(adbg_object_ne_mz_header(o)); 28 | 29 | print_header("Header"); 30 | 31 | ne_header_t* header = adbg_object_ne_header(o); 32 | with (header) { 33 | print_x16("ne_magic", ne_magic); 34 | print_u8("ne_ver", ne_ver); 35 | print_u8("ne_rev", ne_rev); 36 | print_x16("ne_enttab", ne_enttab); 37 | print_u16("ne_cbenttab", ne_cbenttab); 38 | print_x32("ne_crc", ne_crc); 39 | print_flags16("ne_flags", ne_flags, 40 | "GLOBALINIT".ptr, NE_HFLAG_GLOBALINIT, 41 | "PROTECTED".ptr, NE_HFLAG_PROTECTED, 42 | "INT8086".ptr, NE_HFLAG_INT8086, 43 | "INTI286".ptr, NE_HFLAG_INTI286, 44 | "INTI386".ptr, NE_HFLAG_INTI386, 45 | "INTX87".ptr, NE_HFLAG_INTX87, 46 | "OS2".ptr, NE_HFLAG_OS2, 47 | "LINKERERROR".ptr, NE_HFLAG_LINKERERROR, 48 | "LIBMODULE".ptr, NE_HFLAG_LIBMODULE, 49 | null); 50 | ushort dgroup = ne_flags & NE_HFLAG_DGROUP_MASK; 51 | switch (dgroup) { 52 | case NE_HFLAG_DGROUP_SINGLEDATA: 53 | print_x16("ne_flags:dgroup", dgroup, "SINGLEDATA"); 54 | break; 55 | case NE_HFLAG_DGROUP_MULTIPLEDATA: 56 | print_x16("ne_flags:dgroup", dgroup, "MULTIPLEDATA"); 57 | break; 58 | default: 59 | } 60 | ushort app = ne_flags & NE_HFLAG_APP_MASK; 61 | switch (app) { 62 | case NE_HFLAG_APP_FULLSCREEN: 63 | print_x16("ne_flags:app", app, "FULLSCREEN"); 64 | break; 65 | case NE_HFLAG_APP_COMPATPM: 66 | print_x16("ne_flags:app", app, "COMPATPM"); 67 | break; 68 | case NE_HFLAG_APP_USINGPM: 69 | print_x16("ne_flags:app", app, "USINGPM"); 70 | break; 71 | default: 72 | } 73 | print_u16("ne_autodata", ne_autodata); 74 | print_u16("ne_heap", ne_heap); 75 | print_u16("ne_stack", ne_stack); 76 | print_x32("ne_csip", ne_csip); 77 | print_x32("ne_sssp", ne_sssp); 78 | print_u16("ne_cseg", ne_cseg); 79 | print_u16("ne_cmod", ne_cmod); 80 | print_u16("ne_cbnrestab", ne_cbnrestab); 81 | print_x16("ne_segtab", ne_segtab); 82 | print_x16("ne_rsrctab", ne_rsrctab); 83 | print_x16("ne_restab", ne_restab); 84 | print_x16("ne_modtab", ne_modtab); 85 | print_x16("ne_imptab", ne_imptab); 86 | print_x32("ne_nrestab", ne_nrestab); 87 | print_u16("ne_cmovent", ne_cmovent); 88 | print_u16("ne_align", ne_align); 89 | print_u16("ne_cres", ne_cres); 90 | print_u8("ne_exetyp", ne_exetyp, adbg_object_ne_type(ne_exetyp)); 91 | print_x8("ne_flagsothers", ne_flagsothers); 92 | print_x16("ne_pretthunks", ne_pretthunks); 93 | print_x16("ne_psegrefbytes", ne_psegrefbytes); 94 | print_x16("ne_swaparea", ne_swaparea); 95 | print_x16("ne_expver", ne_expver); 96 | } 97 | } -------------------------------------------------------------------------------- /dumper/src/format_omf.d: -------------------------------------------------------------------------------- 1 | /// OMF dumper. 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module format_omf; 7 | 8 | import adbg.objectserver; 9 | import adbg.objects.omf; 10 | import dumper; 11 | import common.errormgmt; 12 | 13 | extern (C): 14 | 15 | int dump_omf(adbg_object_t *o) { 16 | if (SELECTED(Select.headers)) 17 | dump_omf_header(o); 18 | if (SELECTED(Select.debug_)) 19 | dump_omf_debug(o); 20 | return 0; 21 | } 22 | 23 | private: 24 | 25 | void dump_omf_header(adbg_object_t *o) { 26 | print_header("Library Header"); 27 | 28 | omf_lib_header_t *libheader = adbg_object_omf_library_header(o); 29 | 30 | if (libheader == null) { 31 | print_warningf("Not a library, so no header"); 32 | return; 33 | } 34 | 35 | with (libheader) { 36 | print_x8("Type", type); 37 | print_u16("RecordLength", size); 38 | print_x32("DictionaryOffset", dicoff); 39 | print_u16("DictionarySize", dicsize); 40 | print_flags8("Flags", flags, 41 | "CaseSensitive".ptr, OMF_LF_CS, 42 | null); 43 | } 44 | 45 | /* 46 | print_header("First Object Entry"); 47 | omf_entry* entry = adbg_object_omf_entry(o, 0); 48 | dump_omf_print_entry(entry); 49 | adbg_object_omf_entry_close(o, entry); 50 | */ 51 | } 52 | 53 | void dump_omf_debug(adbg_object_t *o) { 54 | omf_entry_t *entry = adbg_object_omf_entry_first(o); 55 | if (entry == null) 56 | panic_adbg(); 57 | 58 | do { 59 | dump_omf_print_entry(entry); 60 | adbg_object_omf_entry_close(entry); 61 | } while ((entry = adbg_object_omf_entry_next(o)) != null); 62 | } 63 | 64 | // print entry 65 | int dump_omf_print_entry(omf_entry_t *entry) { 66 | __gshared uint i; 67 | print_section(i++); 68 | print_x8("Type", entry.type, adbg_object_omf_type_string(entry)); 69 | print_u16("Size", entry.size); 70 | print_x8("Checksum", entry.checksum); 71 | switch (entry.type) with (OMFRecord) { 72 | case THEADR, LHEADR: 73 | int len = (cast(ubyte*)entry.data)[0]; // string size 74 | if (len >= entry.size) 75 | panic(3, "String length outside bounds"); 76 | const(char)* str = cast(const(char)*)entry.data + 1; 77 | print_stringl("Name", str, len); 78 | break; 79 | default: 80 | } 81 | return 0; 82 | } 83 | -------------------------------------------------------------------------------- /dumper/src/main.d: -------------------------------------------------------------------------------- 1 | /// Command line interface. 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module main; 7 | 8 | import adbg.platform; 9 | import adbg.include.c.stdlib : exit; 10 | import adbg.process.base : adbg_process_t; 11 | import adbg.process.exception : adbg_exception_t, adbg_exception_name; 12 | import adbg.self; 13 | import adbg.disassembler; 14 | import adbg.error; 15 | import core.stdc.stdlib : EXIT_FAILURE; 16 | import core.stdc.stdio; 17 | import dumper; 18 | import common.errormgmt; 19 | import common.cli; 20 | import common.utils; 21 | 22 | private: 23 | 24 | // TODO: --dump-blob-offset/--dump-blob-seek/--dump-blob-start: Starting offset for raw blob 25 | // TODO: --dump-length/--dump-end: Length or end 26 | // TODO: --dump-stats: File statistics? 27 | // pdb: stream count, positions, etc. 28 | // TODO: --type-only: Returns short-name only for identification purposes 29 | // TODO: --section-contains=name: Like --section=name, but not exact name, with search 30 | // TODO: --all (to complement --headers) 31 | immutable option_t[] options = [ 32 | // secrets 33 | option_t(0, "woof", null, &cliopt_woof), 34 | // common options 35 | option_arch, 36 | option_syntax, 37 | // selections 38 | option_t('H', "headers", "Dump headers", &cliopt_headers), 39 | option_t('S', "sections", "Dump sections", &cliopt_sections), 40 | option_t(0, "section", "Dump section by name", &cliopt_section), 41 | option_t(0, "segments", "Dump segments", &cliopt_segments), 42 | option_t('I', "imports", "Dump import information", &cliopt_imports), 43 | option_t('E', "exports", "Dump export information", &cliopt_exports), 44 | option_t(0, "loadconfig", "Dump load configuration", &cliopt_loadcfg), 45 | // option_t(0, "source", "Dump source with disassembly", &cliopt_source), 46 | option_t(0, "relocs", "Dump relocations", &cliopt_relocs), 47 | option_t(0, "debug", "Dump debug information", &cliopt_debug), 48 | option_t(0, "everything", "Dump everything except disassembly", &cliopt_everything), 49 | option_t(0, "pdb-stream", "Dump given PDB stream", &cliopt_pdb_stream), 50 | // settings 51 | option_t(0, "as-blob", "Setting: Input is headless binary blob", &cliopt_as_blob), 52 | option_t(0, "disassemble", "Setting: Disassemble executable sections", &cliopt_disasm), 53 | option_t(0, "disassemble-all", "Setting: Disassemble all sections", &cliopt_disasm_all), 54 | option_t(0, "disassemble-stats", "Setting: Provide disassembly statistics", &cliopt_disasm_stats), 55 | option_t(0, "origin", "Setting: Mark base address for disassembly", &cliopt_origin), 56 | option_t(0, "extract", "Setting: Output selected portion to stdout", &cliopt_extract), 57 | option_t(0, "extract-to", "Setting: Output selected portion to file", &cliopt_extract_to), 58 | option_t(0, "hexdump", "Setting: Output selected portion to stdout as hexdump", &cliopt_hexdump), 59 | option_t(0, "no-prefix", "Setting: Remove file path prefix of output", &cliopt_no_prefix), 60 | option_t(0, "shortname", "Setting: Instead of a summary, only print short machine name", &cliopt_shortname), 61 | // pages 62 | option_t('h', "help", "Show this help screen and exit", &cliopt_help), 63 | option_version, 64 | option_build_info, 65 | option_ver, 66 | option_license, 67 | ]; 68 | enum NUMBER_OF_SECRETS = 1; 69 | 70 | // 71 | // Selections 72 | // 73 | 74 | int cliopt_headers() { 75 | opt_selected |= Select.headers; 76 | return 0; 77 | } 78 | int cliopt_section(const(char) *val) { 79 | opt_selected |= Select.sections; 80 | opt_section_name = val; 81 | return 0; 82 | } 83 | int cliopt_sections() { 84 | opt_selected |= Select.sections; 85 | return 0; 86 | } 87 | int cliopt_segments() { 88 | opt_selected |= Select.segments; 89 | return 0; 90 | } 91 | int cliopt_imports() { 92 | opt_selected |= Select.imports; 93 | return 0; 94 | } 95 | int cliopt_exports() { 96 | opt_selected |= Select.exports; 97 | return 0; 98 | } 99 | int cliopt_loadcfg() { 100 | opt_selected |= Select.loadconfig; 101 | return 0; 102 | } 103 | int cliopt_relocs() { 104 | opt_selected |= Select.relocs; 105 | return 0; 106 | } 107 | int cliopt_debug() { 108 | opt_selected |= Select.debug_; 109 | return 0; 110 | } 111 | 112 | int cliopt_everything() { 113 | opt_selected |= Select.all; 114 | return 0; 115 | } 116 | 117 | int cliopt_pdb_stream(const(char) *num) { 118 | opt_selected |= Select.any; 119 | opt_pdb_stream = num; 120 | return 0; 121 | } 122 | 123 | // 124 | // Settings 125 | // 126 | 127 | int cliopt_as_blob() { 128 | opt_settings |= Setting.blob; 129 | return 0; 130 | } 131 | int cliopt_disasm() { 132 | opt_settings |= Setting.disasm; 133 | return 0; 134 | } 135 | int cliopt_disasm_all() { 136 | opt_settings |= Setting.disasmAll; 137 | return 0; 138 | } 139 | int cliopt_disasm_stats() { 140 | opt_settings |= Setting.disasmStats; 141 | return 0; 142 | } 143 | int cliopt_origin(const(char) *val) { 144 | return parse64(&opt_baseaddress, val); 145 | } 146 | 147 | int cliopt_extract() { 148 | opt_settings |= Setting.extract; 149 | return 0; 150 | } 151 | int cliopt_extract_to(const(char)* fname) { 152 | opt_settings |= Setting.extract; 153 | opt_extractfile = fname; 154 | return 0; 155 | } 156 | int cliopt_hexdump() { 157 | opt_settings |= Setting.hexdump; 158 | return 0; 159 | } 160 | 161 | int cliopt_no_prefix() { 162 | opt_settings |= Setting.noPrefix; 163 | return 0; 164 | } 165 | 166 | int cliopt_shortname() { 167 | opt_settings |= Setting.shortName; 168 | return 0; 169 | } 170 | 171 | // 172 | // ANCHOR --help 173 | // 174 | 175 | int cliopt_help() { 176 | puts( 177 | "alicedump: Binary object dumper.\n"~ 178 | "\n"~ 179 | "USAGE\n"~ 180 | " Summarize object file:\n"~ 181 | " alicedump [OPTIONS...] FILE\n"~ 182 | " Dump specific information:\n"~ 183 | " alicedump {-H|--headers} {-S|--sections} {-I|--imports} {-E|--exports} [OPTIONS...] FILE\n"~ 184 | " Show application information and exit:\n"~ 185 | " alicedump {-h|--help|--version|--ver|--license}\n"~ 186 | "\n"~ 187 | "OPTIONS" 188 | ); 189 | getoptprinter(options[NUMBER_OF_SECRETS..$]); 190 | exit(0); 191 | return 0; 192 | } 193 | 194 | int cliopt_woof() { 195 | puts( 196 | r" 197 | +---------------------+ , 198 | | Are you SystemReady | .__,-/| 199 | | compliant yet? Woof | \_ ` \ 200 | +---------------------+ `==== 201 | { \ 202 | \ / \ 203 | /// `\ / 204 | //_\ /` 205 | " 206 | ); 207 | exit(0); 208 | return 0; 209 | } 210 | 211 | extern (C) 212 | int main(int argc, const(char)** argv) { 213 | // Set crash handle, and ignore on error 214 | // Could do a warning, but it might be a little confusing 215 | adbg_self_set_crashhandler(&crashed); 216 | 217 | int e = getoptions(argc, argv, options); 218 | if (e < 0) { 219 | puts(getopterror()); 220 | return EXIT_FAILURE; 221 | } 222 | if (e == 0) { 223 | puts("error: No file specified"); 224 | return EXIT_FAILURE; 225 | } 226 | 227 | return dump_file(*getoptleftovers()); // First argument as file 228 | } 229 | -------------------------------------------------------------------------------- /examples/simple.d: -------------------------------------------------------------------------------- 1 | /// Minimal example that loops until the first fault is fault. 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module examples.simple; 7 | 8 | import core.stdc.stdio; 9 | import core.stdc.stdlib : exit, EXIT_FAILURE, EXIT_SUCCESS; 10 | import adbg; 11 | 12 | extern (C): __gshared: private: 13 | 14 | enum { 15 | SIMPLE_STOP = 0, 16 | SIMPLE_CONTINUE = 1, 17 | } 18 | 19 | int putchar(int); 20 | 21 | adbg_disassembler_t *disassembler; 22 | int status = SIMPLE_CONTINUE; 23 | 24 | void oops(int code = 0, const(char) *reason = null) { 25 | printf("* error=\"%s\" code=\"%d\"\n", 26 | reason ? reason : adbg_error_message(), 27 | code ? code : adbg_error_code() 28 | ); 29 | exit(EXIT_FAILURE); 30 | } 31 | 32 | void event_exception(adbg_process_t *process, void *udata, adbg_exception_t *exception) { 33 | adbg_process_thread_t *thread = adbg_exception_thread(exception); 34 | long tid = thread ? adbg_process_thread_id(thread) : 0; 35 | 36 | printf(`* pid=%d tid=%lld event=\"exception\" name="%s" oscode=`~ERR_OSFMT, 37 | adbg_process_id(process), tid, 38 | adbg_exception_name(exception), adbg_exception_orig_code(exception)); 39 | 40 | // Print fault address if available 41 | ulong faultaddr = adbg_exception_fault_address(exception); 42 | if (faultaddr) 43 | printf(" address=%#llx", faultaddr); 44 | 45 | // If disassembler is available, disassemble one instruction 46 | if (faultaddr && disassembler) { 47 | enum BSZ = 32; 48 | ubyte[BSZ] buffer = void; 49 | adbg_opcode_t opcode = void; 50 | if (adbg_memory_read(process, cast(size_t)faultaddr, buffer.ptr, BSZ) || 51 | adbg_disassemble(disassembler, &opcode, buffer.ptr, BSZ, faultaddr)) 52 | goto Lnodisasm; 53 | 54 | goto Ldisasm; 55 | Lnodisasm: 56 | printf(` nodisasm="%s"`, adbg_error_message()); 57 | goto Ldone; 58 | Ldisasm: 59 | printf(` disasm="%s`, opcode.mnemonic); 60 | if (opcode.operands) printf(` %s`, opcode.operands); 61 | putchar('"'); 62 | Ldone: 63 | } 64 | 65 | // Print thread's context 66 | adbg_thread_context_t *ctx = adbg_process_thread_context(thread); 67 | if (ctx) { 68 | adbg_register_t *reg = void; 69 | for (int id; (reg = adbg_register_by_id(ctx, id)) != null; id++) { 70 | char[20] hex = void; 71 | adbg_register_format(hex.ptr, 20, reg, AdbgRegisterFormat.hex); 72 | printf(` %s=0x%s`, adbg_register_name(reg), hex.ptr); 73 | } 74 | } 75 | 76 | putchar('\n'); 77 | 78 | switch (adbg_exception_type(exception)) with (AdbgException) { 79 | case Breakpoint, Step: 80 | adbg_debugger_continue(process, tid); 81 | break; 82 | default: // Quit at first fault 83 | *(cast(int*)udata) = SIMPLE_STOP; 84 | } 85 | } 86 | void event_process_continue(adbg_process_t *process, void *udata, long tid) { 87 | printf("* pid=%d tid=%lld event=\"continued\"\n", adbg_process_id(process), tid); 88 | } 89 | void event_process_exit(adbg_process_t *process, void *udata, int code) { 90 | printf("* pid=%d event=\"exited\" code=%d\n", adbg_process_id(process), code); 91 | *(cast(int*)udata) = SIMPLE_STOP; 92 | } 93 | 94 | int main(int argc, const(char) **argv) { 95 | if (argc < 2) 96 | oops(1, "Missing path to executable"); 97 | 98 | // Additional arguments for debuggee 99 | const(char) **pargv = argc > 2 ? argv + 2 : null; 100 | 101 | // Launch process 102 | adbg_process_t *process = 103 | adbg_debugger_spawn(argv[1], 104 | AdbgSpawnOpt.argv, pargv, 105 | 0); 106 | if (process == null) 107 | oops; 108 | 109 | // Setup 110 | adbg_debugger_on_exception(process, &event_exception); 111 | adbg_debugger_on_process_continue(process, &event_process_continue); 112 | adbg_debugger_on_process_exit(process, &event_process_exit); 113 | adbg_debugger_udata(process, &status); 114 | 115 | // New disassembler instance, if able 116 | disassembler = adbg_disassembler_open(adbg_process_machine(process)); 117 | if (disassembler == null) 118 | printf("* warning=\"Disassembler unavailable: %s\"\n", adbg_error_message()); 119 | 120 | // Start and listen to events 121 | while (status) { 122 | if (adbg_debugger_wait(process)) 123 | oops; 124 | } 125 | puts("* quitting"); 126 | return 0; 127 | } -------------------------------------------------------------------------------- /src/adbg/build.d: -------------------------------------------------------------------------------- 1 | /// Experimental module for building and internal configurations. 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module adbg.build; 7 | -------------------------------------------------------------------------------- /src/adbg/include/c/config.d: -------------------------------------------------------------------------------- 1 | /// Missing definitions in core.stdc.config. 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module adbg.include.c.config; 7 | 8 | public import core.stdc.config; 9 | 10 | /// Maps to a C "long int" type. 11 | alias c_longint = c_long; 12 | /// Maps to a C "unsigned long int" type. 13 | alias c_ulongint = c_ulong; 14 | /// Maps to a C "short int" type. 15 | alias c_short_int = short; 16 | /// Maps to a C "unsigned short int" type. 17 | alias c_ushort_int = ushort; 18 | 19 | // This is a thing because D compilers come with an older MSVCRT version, 20 | // and they are not compatible with the z prefix. 21 | // NOTE: pragma(printf) does not recognize the "I" specifier 22 | version (CRuntime_Microsoft) { // MSVC v13.0 and earlier (VS2015) 23 | /// Unsigned integer printf specifier for size_t 24 | enum PRIzu = "Iu"; 25 | /// Hexadecimal integer printf specifier for size_t 26 | enum PRIzx = "Ix"; 27 | } else { 28 | /// Ditto 29 | enum PRIzu = "zu"; 30 | /// Ditto 31 | enum PRIzx = "zx"; 32 | } 33 | 34 | version (CRuntime_Glibc) 35 | extern (C) const(char) *gnu_get_libc_version(); 36 | -------------------------------------------------------------------------------- /src/adbg/include/c/setjmp.d: -------------------------------------------------------------------------------- 1 | /// setjmp.h binding. 2 | /// 3 | /// While there are bindings for posix (core.sys.posix.setjmp), there are none 4 | /// for Windows. 5 | /// 6 | /// Authors: dd86k 7 | /// Copyright: © dd86k 8 | /// License: BSD-3-Clause-Clear 9 | module adbg.include.c.setjmp; 10 | 11 | import adbg.include.c.config : c_long, c_ulong, c_longint, c_ulongint; 12 | import adbg.include.d.config : D_FEATURE_NORETURN; 13 | 14 | extern (C): 15 | @system: 16 | @nogc: 17 | nothrow: 18 | 19 | // {VisualStudio}\VC\Tools\MSVC\14.32.31326\include\setjmp.h 20 | version (Windows) { 21 | version (X86) { 22 | private enum _JBLEN = 16; 23 | private alias int _JBTYPE; 24 | 25 | struct _JUMP_BUFFER { 26 | int Ebp, Ebx, Edi, Esi, Esp, Eip, Registration, 27 | TryLevel, Cookie, UnwindFunc; 28 | int[6] UnwindData; 29 | } 30 | 31 | static assert (_JUMP_BUFFER.sizeof == _JBTYPE.sizeof * _JBLEN); 32 | } else version (X86_64) { 33 | //TODO: Fix C0000028 (__chkstk) issue 34 | // "An invalid or unaligned stack was encountered during 35 | // an unwind operation." 36 | // Fine on: 37 | // - dmd-x86_omf 38 | // - dmd-x86_mscoff 39 | // - ldc-x86 40 | // - ldc-x86_64 with setjmpex 41 | // Crashes on: 42 | // - dmd-x86_64 43 | private enum _JBLEN = 16; 44 | private alias _SETJMP_FLOAT128 _JBTYPE; 45 | 46 | struct _SETJMP_FLOAT128 { 47 | long[2] Part; 48 | } 49 | 50 | struct _JUMP_BUFFER { 51 | align (1): 52 | ulong Frame, Rbx, Rsp, Rbp, Rsi, Rdi, 53 | R12, R13, R14, R15, Rip; 54 | c_ulong MxCsr; 55 | ushort FpCsr; 56 | ushort Spare; 57 | 58 | align (16): 59 | _SETJMP_FLOAT128 Xmm6, Xmm7, Xmm8, Xmm9, Xmm10, 60 | Xmm11, Xmm12, Xmm13, Xmm14, Xmm15; 61 | } 62 | 63 | static assert (_JUMP_BUFFER.sizeof == _JBTYPE.sizeof * _JBLEN); 64 | } else version (ARM) { 65 | private enum _JBLEN = 28; 66 | private alias int _JTYPE; 67 | 68 | struct _JUMP_BUFFER { 69 | int Frame, R4, R5, R6, R7, R8, R9, R10, R11, 70 | Sp, Pc, Fpscr; 71 | long[8] D; // D8-D15 VFP/NEON regs 72 | } 73 | 74 | static assert (_JUMP_BUFFER.sizeof == _JBTYPE.sizeof * _JBLEN); 75 | } else version (AArch64) { 76 | private enum _JBLEN = 24; 77 | private alias int _JTYPE; 78 | 79 | struct _JUMP_BUFFER { 80 | long Frame, Reserved, 81 | X19, X20, X21, X22, X23, // x19 -- x28 82 | X24, X25, X26, X27, X28, // callee saved registers 83 | Fp, // x29 frame pointer 84 | Lr, // x30 link register 85 | Sp; // x31 stack pointer 86 | int Fpcr; // fp control register 87 | int Fpsr; // fp status register 88 | double[8] D; // D8-D15 FP regs 89 | } 90 | 91 | static assert (_JUMP_BUFFER.sizeof == _JBTYPE.sizeof * _JBLEN); 92 | } else static assert(0, "Missing setjmp definitions (Windows)"); 93 | 94 | public alias _JUMP_BUFFER jmp_buf; // typedef _JBTYPE jmp_buf[_JBLEN]; 95 | } else version (CRuntime_Glibc) { // 2.25 96 | version (X86) { // sysdeps/x86/bits/setjmp.h 97 | struct __jmp_buf { 98 | int ebx, esi, edi, ebp, esp, eip; 99 | } 100 | // typedef int __jmp_buf[6]; 101 | } else version (X86_64) { // sysdeps/x86_64/jmpbuf-offsets.h 102 | struct __jmp_buf { 103 | long rbx, rbp, r12, r13, r14, r15, rsp, rip; 104 | } 105 | // typedef unsigned long long __jmp_buf[8] 106 | } else version (ARM) { 107 | // sysdeps/arm/bits/setjmp.h 108 | // sysdebs/arm/include/bits/setjmp.h 109 | // sysdebs/arm/setjmp.S 110 | 111 | // "The exact set of registers saved may depend on the particular core 112 | // in use, as some coprocessor registers may need to be saved. The C 113 | // Library ABI requires that the buffer be 8-byte aligned, and 114 | // recommends that the buffer contain 64 words. The first 26 words 115 | // are occupied by sp, lr, v1-v6, sl, fp, and d8-d15." 116 | union __jmp_buf { 117 | alias buf this; 118 | align(8) int[64] buf; 119 | struct { 120 | int sp, lr; 121 | float v1, v2, v3, v4, v5, v6; // VFP registers 122 | int sl, fp; 123 | double d8, d9, d10, d11, d12, d13, d14, d15; 124 | } 125 | } 126 | // typedef int __jmp_buf[64] __attribute__((__aligned__ (8))); 127 | static assert(__jmp_buf.sizeof == int.sizeof * 64); 128 | } else version (AArch64) { // sysdeps/aarch64/jmpbuf-offsets.h 129 | struct __jmp_buf { 130 | ulong x19, x20, x21, x22, x23, x24, x25, x26, 131 | x27, x28, x29, reserved_, lr, sp; 132 | double d8, d9, d10, d11, d12, d13, d14, d15; 133 | } 134 | // __extension__ typedef unsigned long long __jmp_buf [22]; 135 | static assert(__jmp_buf.sizeof == ulong.sizeof * 22); 136 | } else static assert(0, "Missing setjmp definitions (Glibc)"); 137 | 138 | // setjmp/setjmp.h 139 | // bits/sigset.h 140 | struct __jmp_buf_tag { 141 | __jmp_buf __jmpbuf; 142 | int __mask_was_saved; 143 | c_ulongint __saved_mask; // typedef unsigned long int __sigset_t; 144 | } 145 | 146 | public alias __jmp_buf_tag jmp_buf; 147 | } else version (CRuntime_Musl) { // 1.20 148 | version (X86) { 149 | alias c_ulong[6] __jmp_buf; // typedef unsigned long __jmp_buf[6]; 150 | } else version (X86_64) { 151 | alias c_ulong[8] __jmp_buf; // typedef unsigned long __jmp_buf[8]; 152 | } else version (ARM) { 153 | alias ulong[32] __jmp_buf; // typedef unsigned long long __jmp_buf[32]; 154 | } else version (AArch64) { 155 | alias c_ulong[22] __jmp_buf; // typedef unsigned long __jmp_buf[22]; 156 | } else static assert(0, "Missing setjmp definitions (Musl)"); 157 | 158 | struct __jmp_buf_tag { 159 | __jmp_buf __jb; 160 | ulong __fl; 161 | ulong[128 / c_long.sizeof] __ss; 162 | } 163 | alias __jmp_buf_tag jmp_buf; 164 | } else version (CRuntime_Bionic) { 165 | version (X86) { 166 | enum _JBLEN = 10; 167 | } else version (X86_64) { 168 | enum _JBLEN = 11; 169 | } else version (ARM) { 170 | enum _JBLEN = 64; 171 | } else version (AArch64) { 172 | enum _JBLEN = 32; 173 | } 174 | 175 | alias jmp_buf = c_long[_JBLEN]; 176 | } else version (FreeBSD) { 177 | import core.sys.posix.setjmp : jmp_buf; 178 | } else static assert(0, "Missing setjmp definitions"); 179 | 180 | version (Win32) { // Required by DMD, works with LDC 181 | /// 182 | int _setjmp(ref jmp_buf); 183 | alias setjmp = _setjmp; 184 | } else version (Win64) { // Required by LDC, doesn't work with DMD 185 | /// 186 | int _setjmpex(ref jmp_buf); 187 | alias setjmp = _setjmpex; 188 | } else { 189 | /// 190 | int setjmp(ref jmp_buf); 191 | } 192 | 193 | static if (D_FEATURE_NORETURN) { 194 | /// 195 | noreturn longjmp(ref jmp_buf, int); 196 | } else { 197 | /// 198 | void longjmp(ref jmp_buf, int); 199 | } -------------------------------------------------------------------------------- /src/adbg/include/c/stdarg.d: -------------------------------------------------------------------------------- 1 | /** 2 | * Missing or incorrect core.stdc.stdarg definitions. 3 | * 4 | * Fixes missing __va_tag_list on Posix platforms. 5 | * 6 | * Authors: dd86k 7 | * Copyright: © dd86k 8 | * License: BSD-3-Clause-Clear 9 | */ 10 | module adbg.include.c.stdarg; 11 | 12 | extern (C): 13 | @system: 14 | @nogc: 15 | nothrow: 16 | 17 | version (Posix) 18 | version (DigitalMars) 19 | public struct __va_list_tag 20 | { 21 | uint offset_regs = 6 * 8; // no regs 22 | uint offset_fpregs = 6 * 8 + 8 * 16; // no fp regs 23 | void* stack_args; 24 | void* reg_args; 25 | } 26 | 27 | public import core.stdc.stdarg; -------------------------------------------------------------------------------- /src/adbg/include/c/stdio.d: -------------------------------------------------------------------------------- 1 | /** 2 | * Missing or incorrect core.stdc.stdio definitions. 3 | * 4 | * For example, when compiled with -betterC, `putchar` from core.stdc.stdio 5 | * still mangles to `_D4core4stdc5stdio7putcharFiZi` due to the D extern, so 6 | * the function links up with the version from the druntime (or itself). 7 | * On top of that, stdout isn't initialized since that's done in the Druntime. 8 | * So when executed, boom, crash. 9 | * 10 | * Authors: dd86k 11 | * Copyright: © dd86k 12 | * License: BSD-3-Clause-Clear 13 | */ 14 | module adbg.include.c.stdio; 15 | 16 | import adbg.include.d.config : D_FEATURE_PRAGMA_PRINTF, GDC_11; 17 | 18 | extern (C): 19 | @system: 20 | @nogc: 21 | nothrow: 22 | 23 | // NOTE: Wrong extern. 24 | // Should be C, but they're defined as D. 25 | // This is wrong for symbol mangling, affecting linking. 26 | // (e.g., _putchar vs. _D4core4stdc5stdio7putcharFiZi) 27 | 28 | /// 29 | int putchar(int); 30 | /// 31 | int getchar(); 32 | 33 | // NOTE: I really don't know why dmd's lld-link (win64) wouldn't pick up snprintf 34 | // from core.stdc.stdio._snprintf, so this is one of those copy-paste fix. 35 | 36 | version (Windows) { 37 | static if (D_FEATURE_PRAGMA_PRINTF) { 38 | /// 39 | pragma(printf) 40 | int _snprintf(scope char* s, size_t n, scope const char* fmt, scope const ...); 41 | alias _snprintf snprintf; 42 | } else { 43 | /// 44 | int _snprintf(scope char* s, size_t n, scope const char* fmt, scope const ...); 45 | alias _snprintf snprintf; 46 | } 47 | } else { 48 | static if (D_FEATURE_PRAGMA_PRINTF) { 49 | /// 50 | pragma(printf) 51 | int snprintf(scope char* s, size_t n, scope const char* fmt, scope const ...); 52 | } else { 53 | /// 54 | int snprintf(scope char* s, size_t n, scope const char* fmt, scope const ...); 55 | } 56 | } 57 | 58 | // NOTE: Wrong printf/scanf detection for GDC 11 and lower. 59 | // scanf conditions were the same for printf 60 | 61 | version (GNU) { 62 | static if (__VERSION__ <= GDC_11) { // GDC 11.3 63 | /// 64 | int __isoc99_sscanf(scope const char* s, scope const char* format, scope ...); 65 | /// 66 | alias sscanf = __isoc99_sscanf; 67 | /// 68 | int __isoc99_scanf(scope const char* format, scope ...); 69 | /// 70 | alias scanf = __isoc99_scanf; 71 | } 72 | } 73 | 74 | public import core.stdc.stdio; -------------------------------------------------------------------------------- /src/adbg/include/c/stdlib.d: -------------------------------------------------------------------------------- 1 | /** 2 | * Older core.stdc.stdlib definitions. 3 | * 4 | * Authors: dd86k 5 | * Copyright: © dd86k 6 | * License: BSD-3-Clause-Clear 7 | */ 8 | module adbg.include.c.stdlib; 9 | 10 | extern (C): 11 | 12 | void exit(int); 13 | void _Exit(int); 14 | 15 | public import core.stdc.stdlib; -------------------------------------------------------------------------------- /src/adbg/include/capstone/evm.d: -------------------------------------------------------------------------------- 1 | module adbg.include.capstone.evm; 2 | 3 | extern (C): 4 | 5 | /* Capstone Disassembly Engine */ 6 | /* By Nguyen Anh Quynh , 2013-2018 */ 7 | 8 | /// Instruction structure 9 | struct cs_evm 10 | { 11 | ubyte pop; ///< number of items popped from the stack 12 | ubyte push; ///< number of items pushed into the stack 13 | uint fee; ///< gas fee for the instruction 14 | } 15 | 16 | /// EVM instruction 17 | enum evm_insn 18 | { 19 | EVM_INS_STOP = 0, 20 | EVM_INS_ADD = 1, 21 | EVM_INS_MUL = 2, 22 | EVM_INS_SUB = 3, 23 | EVM_INS_DIV = 4, 24 | EVM_INS_SDIV = 5, 25 | EVM_INS_MOD = 6, 26 | EVM_INS_SMOD = 7, 27 | EVM_INS_ADDMOD = 8, 28 | EVM_INS_MULMOD = 9, 29 | EVM_INS_EXP = 10, 30 | EVM_INS_SIGNEXTEND = 11, 31 | EVM_INS_LT = 16, 32 | EVM_INS_GT = 17, 33 | EVM_INS_SLT = 18, 34 | EVM_INS_SGT = 19, 35 | EVM_INS_EQ = 20, 36 | EVM_INS_ISZERO = 21, 37 | EVM_INS_AND = 22, 38 | EVM_INS_OR = 23, 39 | EVM_INS_XOR = 24, 40 | EVM_INS_NOT = 25, 41 | EVM_INS_BYTE = 26, 42 | EVM_INS_SHA3 = 32, 43 | EVM_INS_ADDRESS = 48, 44 | EVM_INS_BALANCE = 49, 45 | EVM_INS_ORIGIN = 50, 46 | EVM_INS_CALLER = 51, 47 | EVM_INS_CALLVALUE = 52, 48 | EVM_INS_CALLDATALOAD = 53, 49 | EVM_INS_CALLDATASIZE = 54, 50 | EVM_INS_CALLDATACOPY = 55, 51 | EVM_INS_CODESIZE = 56, 52 | EVM_INS_CODECOPY = 57, 53 | EVM_INS_GASPRICE = 58, 54 | EVM_INS_EXTCODESIZE = 59, 55 | EVM_INS_EXTCODECOPY = 60, 56 | EVM_INS_RETURNDATASIZE = 61, 57 | EVM_INS_RETURNDATACOPY = 62, 58 | EVM_INS_BLOCKHASH = 64, 59 | EVM_INS_COINBASE = 65, 60 | EVM_INS_TIMESTAMP = 66, 61 | EVM_INS_NUMBER = 67, 62 | EVM_INS_DIFFICULTY = 68, 63 | EVM_INS_GASLIMIT = 69, 64 | EVM_INS_POP = 80, 65 | EVM_INS_MLOAD = 81, 66 | EVM_INS_MSTORE = 82, 67 | EVM_INS_MSTORE8 = 83, 68 | EVM_INS_SLOAD = 84, 69 | EVM_INS_SSTORE = 85, 70 | EVM_INS_JUMP = 86, 71 | EVM_INS_JUMPI = 87, 72 | EVM_INS_PC = 88, 73 | EVM_INS_MSIZE = 89, 74 | EVM_INS_GAS = 90, 75 | EVM_INS_JUMPDEST = 91, 76 | EVM_INS_PUSH1 = 96, 77 | EVM_INS_PUSH2 = 97, 78 | EVM_INS_PUSH3 = 98, 79 | EVM_INS_PUSH4 = 99, 80 | EVM_INS_PUSH5 = 100, 81 | EVM_INS_PUSH6 = 101, 82 | EVM_INS_PUSH7 = 102, 83 | EVM_INS_PUSH8 = 103, 84 | EVM_INS_PUSH9 = 104, 85 | EVM_INS_PUSH10 = 105, 86 | EVM_INS_PUSH11 = 106, 87 | EVM_INS_PUSH12 = 107, 88 | EVM_INS_PUSH13 = 108, 89 | EVM_INS_PUSH14 = 109, 90 | EVM_INS_PUSH15 = 110, 91 | EVM_INS_PUSH16 = 111, 92 | EVM_INS_PUSH17 = 112, 93 | EVM_INS_PUSH18 = 113, 94 | EVM_INS_PUSH19 = 114, 95 | EVM_INS_PUSH20 = 115, 96 | EVM_INS_PUSH21 = 116, 97 | EVM_INS_PUSH22 = 117, 98 | EVM_INS_PUSH23 = 118, 99 | EVM_INS_PUSH24 = 119, 100 | EVM_INS_PUSH25 = 120, 101 | EVM_INS_PUSH26 = 121, 102 | EVM_INS_PUSH27 = 122, 103 | EVM_INS_PUSH28 = 123, 104 | EVM_INS_PUSH29 = 124, 105 | EVM_INS_PUSH30 = 125, 106 | EVM_INS_PUSH31 = 126, 107 | EVM_INS_PUSH32 = 127, 108 | EVM_INS_DUP1 = 128, 109 | EVM_INS_DUP2 = 129, 110 | EVM_INS_DUP3 = 130, 111 | EVM_INS_DUP4 = 131, 112 | EVM_INS_DUP5 = 132, 113 | EVM_INS_DUP6 = 133, 114 | EVM_INS_DUP7 = 134, 115 | EVM_INS_DUP8 = 135, 116 | EVM_INS_DUP9 = 136, 117 | EVM_INS_DUP10 = 137, 118 | EVM_INS_DUP11 = 138, 119 | EVM_INS_DUP12 = 139, 120 | EVM_INS_DUP13 = 140, 121 | EVM_INS_DUP14 = 141, 122 | EVM_INS_DUP15 = 142, 123 | EVM_INS_DUP16 = 143, 124 | EVM_INS_SWAP1 = 144, 125 | EVM_INS_SWAP2 = 145, 126 | EVM_INS_SWAP3 = 146, 127 | EVM_INS_SWAP4 = 147, 128 | EVM_INS_SWAP5 = 148, 129 | EVM_INS_SWAP6 = 149, 130 | EVM_INS_SWAP7 = 150, 131 | EVM_INS_SWAP8 = 151, 132 | EVM_INS_SWAP9 = 152, 133 | EVM_INS_SWAP10 = 153, 134 | EVM_INS_SWAP11 = 154, 135 | EVM_INS_SWAP12 = 155, 136 | EVM_INS_SWAP13 = 156, 137 | EVM_INS_SWAP14 = 157, 138 | EVM_INS_SWAP15 = 158, 139 | EVM_INS_SWAP16 = 159, 140 | EVM_INS_LOG0 = 160, 141 | EVM_INS_LOG1 = 161, 142 | EVM_INS_LOG2 = 162, 143 | EVM_INS_LOG3 = 163, 144 | EVM_INS_LOG4 = 164, 145 | EVM_INS_CREATE = 240, 146 | EVM_INS_CALL = 241, 147 | EVM_INS_CALLCODE = 242, 148 | EVM_INS_RETURN = 243, 149 | EVM_INS_DELEGATECALL = 244, 150 | EVM_INS_CALLBLACKBOX = 245, 151 | EVM_INS_STATICCALL = 250, 152 | EVM_INS_REVERT = 253, 153 | EVM_INS_SUICIDE = 255, 154 | 155 | EVM_INS_INVALID = 512, 156 | EVM_INS_ENDING = 513 // <-- mark the end of the list of instructions 157 | } 158 | 159 | /// Group of EVM instructions 160 | enum evm_insn_group 161 | { 162 | EVM_GRP_INVALID = 0, ///< = CS_GRP_INVALID 163 | 164 | EVM_GRP_JUMP = 1, ///< all jump instructions 165 | 166 | EVM_GRP_MATH = 8, ///< math instructions 167 | EVM_GRP_STACK_WRITE = 9, ///< instructions write to stack 168 | EVM_GRP_STACK_READ = 10, ///< instructions read from stack 169 | EVM_GRP_MEM_WRITE = 11, ///< instructions write to memory 170 | EVM_GRP_MEM_READ = 12, ///< instructions read from memory 171 | EVM_GRP_STORE_WRITE = 13, ///< instructions write to storage 172 | EVM_GRP_STORE_READ = 14, ///< instructions read from storage 173 | EVM_GRP_HALT = 15, ///< instructions halt execution 174 | 175 | EVM_GRP_ENDING = 16 ///< <-- mark the end of the list of groups 176 | } 177 | -------------------------------------------------------------------------------- /src/adbg/include/capstone/package.d: -------------------------------------------------------------------------------- 1 | module adbg.include.capstone; 2 | 3 | public import adbg.include.capstone.v4; -------------------------------------------------------------------------------- /src/adbg/include/capstone/xcore.d: -------------------------------------------------------------------------------- 1 | module adbg.include.capstone.xcore; 2 | 3 | extern (C): 4 | 5 | /* Capstone Disassembly Engine */ 6 | /* By Nguyen Anh Quynh , 2014-2015 */ 7 | 8 | /// Operand type for instruction's operands 9 | enum xcore_op_type 10 | { 11 | XCORE_OP_INVALID = 0, ///< = CS_OP_INVALID (Uninitialized). 12 | XCORE_OP_REG = 1, ///< = CS_OP_REG (Register operand). 13 | XCORE_OP_IMM = 2, ///< = CS_OP_IMM (Immediate operand). 14 | XCORE_OP_MEM = 3 ///< = CS_OP_MEM (Memory operand). 15 | } 16 | 17 | /// XCore registers 18 | enum xcore_reg 19 | { 20 | XCORE_REG_INVALID = 0, 21 | 22 | XCORE_REG_CP = 1, 23 | XCORE_REG_DP = 2, 24 | XCORE_REG_LR = 3, 25 | XCORE_REG_SP = 4, 26 | XCORE_REG_R0 = 5, 27 | XCORE_REG_R1 = 6, 28 | XCORE_REG_R2 = 7, 29 | XCORE_REG_R3 = 8, 30 | XCORE_REG_R4 = 9, 31 | XCORE_REG_R5 = 10, 32 | XCORE_REG_R6 = 11, 33 | XCORE_REG_R7 = 12, 34 | XCORE_REG_R8 = 13, 35 | XCORE_REG_R9 = 14, 36 | XCORE_REG_R10 = 15, 37 | XCORE_REG_R11 = 16, 38 | 39 | // pseudo registers 40 | XCORE_REG_PC = 17, ///< pc 41 | 42 | // internal thread registers 43 | // see The-XMOS-XS1-Architecture(X7879A).pdf 44 | XCORE_REG_SCP = 18, ///< save pc 45 | XCORE_REG_SSR = 19, //< save status 46 | XCORE_REG_ET = 20, //< exception type 47 | XCORE_REG_ED = 21, //< exception data 48 | XCORE_REG_SED = 22, //< save exception data 49 | XCORE_REG_KEP = 23, //< kernel entry pointer 50 | XCORE_REG_KSP = 24, //< kernel stack pointer 51 | XCORE_REG_ID = 25, //< thread ID 52 | 53 | XCORE_REG_ENDING = 26 // <-- mark the end of the list of registers 54 | } 55 | 56 | /// Instruction's operand referring to memory 57 | /// This is associated with XCORE_OP_MEM operand type above 58 | struct xcore_op_mem 59 | { 60 | ubyte base; ///< base register, can be safely interpreted as 61 | ///< a value of type `xcore_reg`, but it is only 62 | ///< one byte wide 63 | ubyte index; ///< index register, same conditions apply here 64 | int disp; ///< displacement/offset value 65 | int direct; ///< +1: forward, -1: backward 66 | } 67 | 68 | /// Instruction operand 69 | struct cs_xcore_op 70 | { 71 | xcore_op_type type; ///< operand type 72 | union 73 | { 74 | xcore_reg reg; ///< register value for REG operand 75 | int imm; ///< immediate value for IMM operand 76 | xcore_op_mem mem; ///< base/disp value for MEM operand 77 | } 78 | } 79 | 80 | /// Instruction structure 81 | struct cs_xcore 82 | { 83 | /// Number of operands of this instruction, 84 | /// or 0 when instruction has no operand. 85 | ubyte op_count; 86 | cs_xcore_op[8] operands; ///< operands for this instruction. 87 | } 88 | 89 | /// XCore instruction 90 | enum xcore_insn 91 | { 92 | XCORE_INS_INVALID = 0, 93 | 94 | XCORE_INS_ADD = 1, 95 | XCORE_INS_ANDNOT = 2, 96 | XCORE_INS_AND = 3, 97 | XCORE_INS_ASHR = 4, 98 | XCORE_INS_BAU = 5, 99 | XCORE_INS_BITREV = 6, 100 | XCORE_INS_BLA = 7, 101 | XCORE_INS_BLAT = 8, 102 | XCORE_INS_BL = 9, 103 | XCORE_INS_BF = 10, 104 | XCORE_INS_BT = 11, 105 | XCORE_INS_BU = 12, 106 | XCORE_INS_BRU = 13, 107 | XCORE_INS_BYTEREV = 14, 108 | XCORE_INS_CHKCT = 15, 109 | XCORE_INS_CLRE = 16, 110 | XCORE_INS_CLRPT = 17, 111 | XCORE_INS_CLRSR = 18, 112 | XCORE_INS_CLZ = 19, 113 | XCORE_INS_CRC8 = 20, 114 | XCORE_INS_CRC32 = 21, 115 | XCORE_INS_DCALL = 22, 116 | XCORE_INS_DENTSP = 23, 117 | XCORE_INS_DGETREG = 24, 118 | XCORE_INS_DIVS = 25, 119 | XCORE_INS_DIVU = 26, 120 | XCORE_INS_DRESTSP = 27, 121 | XCORE_INS_DRET = 28, 122 | XCORE_INS_ECALLF = 29, 123 | XCORE_INS_ECALLT = 30, 124 | XCORE_INS_EDU = 31, 125 | XCORE_INS_EEF = 32, 126 | XCORE_INS_EET = 33, 127 | XCORE_INS_EEU = 34, 128 | XCORE_INS_ENDIN = 35, 129 | XCORE_INS_ENTSP = 36, 130 | XCORE_INS_EQ = 37, 131 | XCORE_INS_EXTDP = 38, 132 | XCORE_INS_EXTSP = 39, 133 | XCORE_INS_FREER = 40, 134 | XCORE_INS_FREET = 41, 135 | XCORE_INS_GETD = 42, 136 | XCORE_INS_GET = 43, 137 | XCORE_INS_GETN = 44, 138 | XCORE_INS_GETR = 45, 139 | XCORE_INS_GETSR = 46, 140 | XCORE_INS_GETST = 47, 141 | XCORE_INS_GETTS = 48, 142 | XCORE_INS_INCT = 49, 143 | XCORE_INS_INIT = 50, 144 | XCORE_INS_INPW = 51, 145 | XCORE_INS_INSHR = 52, 146 | XCORE_INS_INT = 53, 147 | XCORE_INS_IN = 54, 148 | XCORE_INS_KCALL = 55, 149 | XCORE_INS_KENTSP = 56, 150 | XCORE_INS_KRESTSP = 57, 151 | XCORE_INS_KRET = 58, 152 | XCORE_INS_LADD = 59, 153 | XCORE_INS_LD16S = 60, 154 | XCORE_INS_LD8U = 61, 155 | XCORE_INS_LDA16 = 62, 156 | XCORE_INS_LDAP = 63, 157 | XCORE_INS_LDAW = 64, 158 | XCORE_INS_LDC = 65, 159 | XCORE_INS_LDW = 66, 160 | XCORE_INS_LDIVU = 67, 161 | XCORE_INS_LMUL = 68, 162 | XCORE_INS_LSS = 69, 163 | XCORE_INS_LSUB = 70, 164 | XCORE_INS_LSU = 71, 165 | XCORE_INS_MACCS = 72, 166 | XCORE_INS_MACCU = 73, 167 | XCORE_INS_MJOIN = 74, 168 | XCORE_INS_MKMSK = 75, 169 | XCORE_INS_MSYNC = 76, 170 | XCORE_INS_MUL = 77, 171 | XCORE_INS_NEG = 78, 172 | XCORE_INS_NOT = 79, 173 | XCORE_INS_OR = 80, 174 | XCORE_INS_OUTCT = 81, 175 | XCORE_INS_OUTPW = 82, 176 | XCORE_INS_OUTSHR = 83, 177 | XCORE_INS_OUTT = 84, 178 | XCORE_INS_OUT = 85, 179 | XCORE_INS_PEEK = 86, 180 | XCORE_INS_REMS = 87, 181 | XCORE_INS_REMU = 88, 182 | XCORE_INS_RETSP = 89, 183 | XCORE_INS_SETCLK = 90, 184 | XCORE_INS_SET = 91, 185 | XCORE_INS_SETC = 92, 186 | XCORE_INS_SETD = 93, 187 | XCORE_INS_SETEV = 94, 188 | XCORE_INS_SETN = 95, 189 | XCORE_INS_SETPSC = 96, 190 | XCORE_INS_SETPT = 97, 191 | XCORE_INS_SETRDY = 98, 192 | XCORE_INS_SETSR = 99, 193 | XCORE_INS_SETTW = 100, 194 | XCORE_INS_SETV = 101, 195 | XCORE_INS_SEXT = 102, 196 | XCORE_INS_SHL = 103, 197 | XCORE_INS_SHR = 104, 198 | XCORE_INS_SSYNC = 105, 199 | XCORE_INS_ST16 = 106, 200 | XCORE_INS_ST8 = 107, 201 | XCORE_INS_STW = 108, 202 | XCORE_INS_SUB = 109, 203 | XCORE_INS_SYNCR = 110, 204 | XCORE_INS_TESTCT = 111, 205 | XCORE_INS_TESTLCL = 112, 206 | XCORE_INS_TESTWCT = 113, 207 | XCORE_INS_TSETMR = 114, 208 | XCORE_INS_START = 115, 209 | XCORE_INS_WAITEF = 116, 210 | XCORE_INS_WAITET = 117, 211 | XCORE_INS_WAITEU = 118, 212 | XCORE_INS_XOR = 119, 213 | XCORE_INS_ZEXT = 120, 214 | 215 | XCORE_INS_ENDING = 121 // <-- mark the end of the list of instructions 216 | } 217 | 218 | /// Group of XCore instructions 219 | enum xcore_insn_group 220 | { 221 | XCORE_GRP_INVALID = 0, ///< = CS_GRP_INVALID 222 | 223 | // Generic groups 224 | // all jump instructions (conditional+direct+indirect jumps) 225 | XCORE_GRP_JUMP = 1, ///< = CS_GRP_JUMP 226 | 227 | XCORE_GRP_ENDING = 2 // <-- mark the end of the list of groups 228 | } 229 | -------------------------------------------------------------------------------- /src/adbg/include/d/config.d: -------------------------------------------------------------------------------- 1 | /// D configuration constants. 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module adbg.include.d.config; 7 | 8 | // 9 | // ANCHOR GDC versioning from DMD-FE 10 | // 11 | 12 | /// GDC 4.x front-end version 13 | enum GDC_4 = 2_055; // 2.055.x: 4.6 (Debian 7) 14 | /// GDC 5.x front-end version 15 | enum GDC_5 = 2_067; // 2.067.x: 5.4 (Ubuntu 16.04) 16 | /// GDC 8.x front-end version 17 | enum GDC_8 = 2_068; // 2.068.1: 8.4 (Ubuntu 18.04), 8.3 (Debian 10.7) 18 | /// GDC 9.x front-end version 19 | enum GDC_9 = 2_076; // 2.076.1: 9.5 (Ubuntu 22.04:gdc-9) 20 | /// GDC 10.x front-end version 21 | enum GDC_10 = 2_076; // 2.076.1: 10.3,10.5 (Ubuntu 20.04) 22 | /// GDC 11.x front-end version 23 | enum GDC_11 = 2_076; // 2.076.1: 11.2,11.4 (Ubuntu 22.04) 24 | /// GDC 12.x front-end version 25 | //enum GDC_12 = 2_098; // Tested on 12.1, 2.098.0-beta.1 (or 2.098.1 at release) 26 | enum GDC_12 = 2_100; // 2.100.x: 12.1 (Ubuntu 22.04), 12.2 (Debian 12) 27 | /// GDC 13.x front-end version 28 | enum GDC_13 = 2_103; // 2.103.x: 13.1.1,13.2 (OpenSUSE Tumbleweed 202307178, Artix Linux 20230711, Ubuntu 23.10) 29 | 30 | // Source: gcc/d/d-builtins.cc::d_init_versions 31 | 32 | version (GNU) { 33 | static if (__VERSION__ == GDC_13) 34 | /// GCC back-end major version for GDC. Starts at version 10 minimum. 35 | enum GDC_VERSION = 13; 36 | else static if (__VERSION__ == GDC_12) 37 | /// Ditto 38 | enum GDC_VERSION = 12; 39 | else static if (__VERSION__ == GDC_11) // 11..9 40 | /// Ditto 41 | enum GDC_VERSION = 9; 42 | else static if (__VERSION__ == GDC_8) 43 | /// Ditto 44 | enum GDC_VERSION = 8; 45 | else static if (__VERSION__ == GDC_5) 46 | /// Ditto 47 | enum GDC_VERSION = 5; 48 | else static if (__VERSION__ == GDC_4) 49 | /// Ditto 50 | enum GDC_VERSION = 4; 51 | else // Unknown 52 | /// Ditto 53 | enum GDC_VERSION = 0; 54 | 55 | version (GNU_SjLj_Exceptions) 56 | /// GDC exception implementation. 57 | enum const(char)* GDC_EXCEPTION_MODE = "SjLj"; 58 | else version (GNU_SEH_Exceptions) 59 | /// Ditto 60 | enum const(char)* GDC_EXCEPTION_MODE = "SEH"; 61 | else version (GNU_DWARF2_Exceptions) 62 | /// Ditto 63 | enum const(char)* GDC_EXCEPTION_MODE = "DWARF2"; 64 | else 65 | /// Ditto 66 | enum const(char)* GDC_EXCEPTION_MODE = "Unknown"; 67 | } else { 68 | /// Ditto 69 | enum GDC_VERSION = 0; 70 | /// Ditto 71 | enum const(char)* GDC_EXCEPTION_MODE = null; 72 | } 73 | 74 | // 75 | // ANCHOR LDC LLVM versioning 76 | // 77 | 78 | version (LDC) { 79 | // NOTE: LDC doesn't seem to fill in for minor versions 80 | // Last tested with ldc 1.32.2 (dmdfe 2.102.2, llvm 15.0.7) 81 | // See driver/main.cpp::registerPredefinedVersions. 82 | // No traits to get LDC/LLVM versions. 83 | // LDC started in 2009, supporting LLVM 2.0. 84 | version (LDC_LLVM_1800) 85 | enum LLVM_VERSION = 18; /// LLVM version used to compile. 86 | else version (LDC_LLVM_1700) 87 | enum LLVM_VERSION = 17; /// Ditto 88 | else version (LDC_LLVM_1600) 89 | enum LLVM_VERSION = 16; /// Ditto 90 | else version (LDC_LLVM_1500) 91 | enum LLVM_VERSION = 15; /// Ditto 92 | else version (LDC_LLVM_1400) 93 | enum LLVM_VERSION = 14; /// Ditto 94 | else version (LDC_LLVM_1300) 95 | enum LLVM_VERSION = 13; /// Ditto 96 | else version (LDC_LLVM_1200) 97 | enum LLVM_VERSION = 12; /// Ditto 98 | else version (LDC_LLVM_1100) 99 | enum LLVM_VERSION = 11; /// Ditto 100 | else version (LDC_LLVM_1000) 101 | enum LLVM_VERSION = 10; /// Ditto 102 | else version (LDC_LLVM_900) 103 | enum LLVM_VERSION = 9; /// Ditto 104 | else version (LDC_LLVM_800) 105 | enum LLVM_VERSION = 8; /// Ditto 106 | else version (LDC_LLVM_700) 107 | enum LLVM_VERSION = 7; /// Ditto 108 | else version (LDC_LLVM_600) 109 | enum LLVM_VERSION = 6; /// Ditto 110 | else version (LDC_LLVM_500) 111 | enum LLVM_VERSION = 5; /// Ditto 112 | else version (LDC_LLVM_400) 113 | enum LLVM_VERSION = 4; /// Ditto 114 | else version (LDC_LLVM_300) 115 | enum LLVM_VERSION = 3; /// Ditto 116 | else version (LDC_LLVM_200) 117 | enum LLVM_VERSION = 2; /// Ditto 118 | else 119 | enum LLVM_VERSION = 0; /// Ditto 120 | } else { 121 | enum LLVM_VERSION = 0; /// Ditto 122 | } 123 | 124 | // 125 | // ANCHOR Compiler support enumerations 126 | // 127 | 128 | /// core.bitop.bswap supports ulong. 129 | // Added in druntime/d07e682f21b0043354fc4b9ca6d5d2b176a63539 130 | // git describe --contains says v2.071.0-b1 131 | // but successfully compiled on GDC 6.3 (DMD-2.068) 132 | enum D_FEATURE_BSWAP64 = __VERSION__ >= 2_068; 133 | /// If set, the compiler supports the getTargetInfo trait. 134 | enum D_FEATURE_TARGETINFO = __VERSION__ >= 2_083; 135 | /// If set, the compiler supports the printf and scanf pragmas. 136 | enum D_FEATURE_PRAGMA_PRINTF = __VERSION__ >= 2_092; 137 | /// Compiler supports DIP1034 (bottom type, includes noreturn). 138 | enum D_FEATURE_NORETURN = __VERSION__ >= 2_096; 139 | /// Compiler has support for core.int128. 140 | enum D_FEATURE_INT128 = __VERSION__ >= 2_100; 141 | /// Compiler supports @mustuse function attribute. 142 | enum D_FEATURE_MUSTUSE = __VERSION__ >= 2_100; -------------------------------------------------------------------------------- /src/adbg/include/freebsd/reg.d: -------------------------------------------------------------------------------- 1 | /// FreeBSD thread context. 2 | /// 3 | /// Required for PTRACE_GETREGS. 4 | /// 5 | /// Authors: dd86k 6 | /// Copyright: © dd86k 7 | /// License: BSD-3-Clause-Clear 8 | module adbg.include.freebsd.reg; 9 | 10 | version (FreeBSD): 11 | 12 | struct __uint128_t { ulong[2] u; } 13 | union __fp80_t { ubyte[10] u; } 14 | 15 | version (X86) { 16 | // sys/x86/include/reg.h 17 | 18 | struct x86reg32 { // __reg32 19 | uint r_fs; 20 | uint r_es; 21 | uint r_ds; 22 | uint r_edi; 23 | uint r_esi; 24 | uint r_ebp; 25 | uint r_isp; 26 | uint r_ebx; 27 | uint r_edx; 28 | uint r_ecx; 29 | uint r_eax; 30 | uint r_trapno; 31 | uint r_err; 32 | uint r_eip; 33 | uint r_cs; 34 | uint r_eflags; 35 | uint r_esp; 36 | uint r_ss; 37 | uint r_gs; 38 | } 39 | struct x86fpreg32 { // __fpreg32 40 | uint[7] fpr_env; // __uint32_t fpr_env[7]; 41 | __fp80_t[8] fpr_acc; // __uint8_t fpr_acc[8][10]; 42 | uint fpr_ex_sw; // __uint32_t fpr_ex_sw; 43 | ubyte[64] fpr_pad; // __uint8_t fpr_pad[64]; 44 | } 45 | struct x86dbreg32 { // __dbreg32 46 | /* Index 0-3: debug address registers */ 47 | /* Index 4-5: reserved */ 48 | /* Index 6: debug status */ 49 | /* Index 7: debug control */ 50 | uint[8] dr; /* debug registers */ 51 | } 52 | 53 | alias reg = x86reg32; 54 | alias fpreg = x86fpreg32; 55 | } else version (X86_64) { 56 | // sys/x86/include/reg.h 57 | 58 | struct x86reg64 { // __reg64 59 | long r_r15; 60 | long r_r14; 61 | long r_r13; 62 | long r_r12; 63 | long r_r11; 64 | long r_r10; 65 | long r_r9; 66 | long r_r8; 67 | long r_rdi; 68 | long r_rsi; 69 | long r_rbp; 70 | long r_rbx; 71 | long r_rdx; 72 | long r_rcx; 73 | long r_rax; 74 | uint r_trapno; 75 | ushort r_fs; 76 | ushort r_gs; 77 | uint r_err; 78 | ushort r_es; 79 | ushort r_ds; 80 | long r_rip; 81 | long r_cs; 82 | long r_rflags; 83 | long r_rsp; 84 | long r_ss; 85 | } 86 | struct x86fpreg64 { // __fpreg64 87 | ulong[4] fpr_env; // __uint64_t fpr_env[4]; 88 | __uint128_t[8] fpr_acc; // __uint8_t fpr_acc[8][16]; 89 | __uint128_t[16] fpr_xacc; // __uint8_t fpr_xacc[16][16]; 90 | ulong[12] fpr_spare; // __uint64_t fpr_spare[12]; 91 | } 92 | struct x86dbreg64 { // __dbreg64 93 | /* Index 0-3: debug address registers */ 94 | /* Index 4-5: reserved */ 95 | /* Index 6: debug status */ 96 | /* Index 7: debug control */ 97 | /* Index 8-15: reserved */ 98 | ulong[16] dr; /* debug registers */ 99 | } 100 | 101 | // Available with PT_GETXMMREGS 102 | struct xmmreg { 103 | uint[8] xmm_env; // xmm_env[8]; 104 | __uint128_t[8] xmm_acc; // xmm_acc[8][16]; 105 | __uint128_t[8] xmm_reg; // xmm_reg[8][16]; 106 | ubyte[224] xmm_pad; // xmm_pad[224]; 107 | } 108 | 109 | alias reg = x86reg64; 110 | alias fpreg = x86fpreg64; 111 | } else version (Arm) { 112 | // sys/arm/include/reg.h 113 | 114 | struct arm32reg { // reg32 115 | uint[13] r; 116 | uint r_sp; 117 | uint r_lr; 118 | uint r_pc; 119 | uint r_cpsr; 120 | } 121 | struct fp_extended_precision { 122 | uint fp_exponent; 123 | uint fp_mantissa_hi; 124 | uint fp_mantissa_lo; 125 | } 126 | alias fp_extended_precision fp_reg_t; 127 | struct arm32fpreg { // fpreg 128 | uint fpr_fpsr; 129 | fp_reg_t[8] fpr; 130 | } 131 | enum ARM_WR_MAX = 16; /* Maximum number of watchpoint registers */ 132 | struct arm32dbreg { 133 | uint[ARM_WR_MAX] dbg_wcr; /* Watchpoint Control Registers */ 134 | uint[ARM_WR_MAX] dbg_wvr; /* Watchpoint Value Registers */ 135 | } 136 | 137 | alias reg = arm32reg; 138 | alias fpreg = arm32fpreg; 139 | } else version (AArch64) { 140 | // sys/arm64/include/reg.h 141 | 142 | struct arm64reg { // reg 143 | ulong[30] x; 144 | ulong lr; /// Link Register 145 | ulong sp; /// Stack Pointer 146 | ulong elr; /// Exception Link Register 147 | ulong spsr; /// Saved Program Status Registers 148 | } 149 | struct arm64fpreg { // fpreg 150 | __uint128_t[32] fp_q; 151 | uint fp_sr; 152 | uint fp_cr; 153 | } 154 | struct arm64dbreg { //dbreg 155 | ubyte db_debug_ver; 156 | ubyte db_nbkpts; 157 | ubyte db_nwtpts; 158 | ubyte[5] db_pad; 159 | 160 | struct _db_breakregs { 161 | ulong dbr_addr; 162 | uint dbr_ctrl; 163 | uint dbr_pad; 164 | } 165 | _db_breakregs[16] db_breakregs; 166 | struct _db_watchregs { 167 | ulong dbw_addr; 168 | uint dbw_ctrl; 169 | uint dbw_pad; 170 | } 171 | _db_watchregs[16] db_watchregs; 172 | } 173 | 174 | alias reg = arm64reg; 175 | alias fpreg = arm64fpreg; 176 | } -------------------------------------------------------------------------------- /src/adbg/include/linux/personality.d: -------------------------------------------------------------------------------- 1 | /// Bindings for personality header (personality.h). 2 | /// 3 | /// Source: include/uapi/linux/personality.h 4 | /// 5 | /// Authors: dd86k 6 | /// Copyright: © dd86k 7 | /// License: BSD-3-Clause-Clear 8 | module adbg.include.linux.personality; 9 | 10 | version (linux): 11 | 12 | /* 13 | * Flags for bug emulation. 14 | * 15 | * These occupy the top three bytes. 16 | */ 17 | enum { 18 | UNAME26 = 0x0020000, 19 | ADDR_NO_RANDOMIZE = 0x0040000, /* disable randomization of VA space */ 20 | FDPIC_FUNCPTRS = 0x0080000, /* userspace function ptrs point to descriptors 21 | * (signal handling) 22 | */ 23 | MMAP_PAGE_ZERO = 0x0100000, 24 | ADDR_COMPAT_LAYOUT = 0x0200000, 25 | READ_IMPLIES_EXEC = 0x0400000, 26 | ADDR_LIMIT_32BIT = 0x0800000, 27 | SHORT_INODE = 0x1000000, 28 | WHOLE_SECONDS = 0x2000000, 29 | STICKY_TIMEOUTS = 0x4000000, 30 | ADDR_LIMIT_3GB = 0x8000000, 31 | } 32 | 33 | /* 34 | * Security-relevant compatibility flags that must be 35 | * cleared upon setuid or setgid exec: 36 | */ 37 | enum PER_CLEAR_ON_SETID = READ_IMPLIES_EXEC | ADDR_NO_RANDOMIZE | 38 | ADDR_COMPAT_LAYOUT | MMAP_PAGE_ZERO; 39 | 40 | /* 41 | * Personality types. 42 | * 43 | * These go in the low byte. Avoid using the top bit, it will 44 | * conflict with error returns. 45 | */ 46 | enum { 47 | PER_LINUX = 0x0000, 48 | PER_LINUX_32BIT = 0x0000 | ADDR_LIMIT_32BIT, 49 | PER_LINUX_FDPIC = 0x0000 | FDPIC_FUNCPTRS, 50 | PER_SVR4 = 0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO, 51 | PER_SVR3 = 0x0002 | STICKY_TIMEOUTS | SHORT_INODE, 52 | PER_SCOSVR3 = 0x0003 | STICKY_TIMEOUTS | 53 | WHOLE_SECONDS | SHORT_INODE, 54 | PER_OSR5 = 0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS, 55 | PER_WYSEV386 = 0x0004 | STICKY_TIMEOUTS | SHORT_INODE, 56 | PER_ISCR4 = 0x0005 | STICKY_TIMEOUTS, 57 | PER_BSD = 0x0006, 58 | PER_SUNOS = 0x0006 | STICKY_TIMEOUTS, 59 | PER_XENIX = 0x0007 | STICKY_TIMEOUTS | SHORT_INODE, 60 | PER_LINUX32 = 0x0008, 61 | PER_LINUX32_3GB = 0x0008 | ADDR_LIMIT_3GB, 62 | PER_IRIX32 = 0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */ 63 | PER_IRIXN32 = 0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */ 64 | PER_IRIX64 = 0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */ 65 | PER_RISCOS = 0x000c, 66 | PER_SOLARIS = 0x000d | STICKY_TIMEOUTS, 67 | PER_UW7 = 0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO, 68 | PER_OSF4 = 0x000f, /* OSF/1 v4 */ 69 | PER_HPUX = 0x0010, 70 | PER_MASK = 0x00ff, 71 | } -------------------------------------------------------------------------------- /src/adbg/include/linux/ptrace.d: -------------------------------------------------------------------------------- 1 | /// ptrace(3) bindings for Linux. 2 | /// 3 | /// x32 is not supported. 4 | /// 5 | /// Source: Linux 6.5.7 6 | /// 7 | /// Authors: dd86k 8 | /// Copyright: © dd86k 9 | /// License: BSD-3-Clause-Clear 10 | module adbg.include.linux.ptrace; 11 | 12 | version (linux): 13 | 14 | import adbg.include.c.config; 15 | 16 | extern (C): 17 | 18 | // include/uapi/linux/ptrace.h 19 | enum PTRACE_MODE_READ = 0x01; 20 | enum PTRACE_MODE_ATTACH = 0x02; 21 | enum PTRACE_MODE_NOAUDIT = 0x04; 22 | enum PTRACE_MODE_FSCREDS = 0x08; 23 | enum PTRACE_MODE_REALCREDS = 0x10; 24 | 25 | /* shorthands for READ/ATTACH and FSCREDS/REALCREDS combinations */ 26 | enum PTRACE_MODE_READ_FSCREDS = PTRACE_MODE_READ | PTRACE_MODE_FSCREDS; 27 | enum PTRACE_MODE_READ_REALCREDS = PTRACE_MODE_READ | PTRACE_MODE_REALCREDS; 28 | enum PTRACE_MODE_ATTACH_FSCREDS = PTRACE_MODE_ATTACH | PTRACE_MODE_FSCREDS; 29 | enum PTRACE_MODE_ATTACH_REALCREDS = PTRACE_MODE_ATTACH | PTRACE_MODE_REALCREDS; 30 | 31 | enum PTRACE_TRACEME = 0; 32 | enum PTRACE_PEEKTEXT = 1; 33 | enum PTRACE_PEEKDATA = 2; 34 | enum PTRACE_PEEKUSR = 3; 35 | enum PTRACE_POKETEXT = 4; 36 | enum PTRACE_POKEDATA = 5; 37 | enum PTRACE_POKEUSR = 6; 38 | enum PTRACE_CONT = 7; 39 | enum PTRACE_KILL = 8; 40 | enum PTRACE_SINGLESTEP = 9; 41 | enum PTRACE_ATTACH = 16; 42 | enum PTRACE_DETACH = 17; 43 | enum PTRACE_SYSCALL = 24; 44 | enum PTRACE_SETOPTIONS = 0x4200; 45 | enum PTRACE_GETEVENTMSG = 0x4201; 46 | enum PTRACE_GETSIGINFO = 0x4202; 47 | enum PTRACE_SETSIGINFO = 0x4203; 48 | enum PTRACE_GETREGSET = 0x4204; 49 | enum PTRACE_SETREGSET = 0x4205; 50 | enum PTRACE_SEIZE = 0x4206; 51 | enum PTRACE_INTERRUPT = 0x4207; 52 | enum PTRACE_LISTEN = 0x4208; 53 | enum PTRACE_PEEKSIGINFO = 0x4209; 54 | enum PTRACE_GETSIGMASK = 0x420a; 55 | enum PTRACE_SETSIGMASK = 0x420b; 56 | enum PTRACE_SECCOMP_GET_FILTER = 0x420c; 57 | enum PTRACE_SECCOMP_GET_METADATA = 0x420d; 58 | enum PTRACE_GET_SYSCALL_INFO = 0x420e; 59 | enum PTRACE_SYSCALL_INFO_NONE = 0; 60 | enum PTRACE_SYSCALL_INFO_ENTRY = 1; 61 | enum PTRACE_SYSCALL_INFO_EXIT = 2; 62 | enum PTRACE_SYSCALL_INFO_SECCOMP =3; 63 | enum PTRACE_GET_RSEQ_CONFIGURATION = 0x420f; 64 | enum PTRACE_SET_SYSCALL_USER_DISPATCH_CONFIG = 0x4210; 65 | enum PTRACE_GET_SYSCALL_USER_DISPATCH_CONFIG = 0x4211; 66 | enum PTRACE_EVENTMSG_SYSCALL_ENTRY = 1; 67 | enum PTRACE_EVENTMSG_SYSCALL_EXIT = 2; 68 | enum PTRACE_PEEKSIGINFO_SHARED = 1 << 0; 69 | enum PTRACE_EVENT_FORK = 1; 70 | enum PTRACE_EVENT_VFORK = 2; 71 | enum PTRACE_EVENT_CLONE = 3; 72 | enum PTRACE_EVENT_EXEC = 4; 73 | enum PTRACE_EVENT_VFORK_DONE = 5; 74 | enum PTRACE_EVENT_EXIT = 6; 75 | enum PTRACE_EVENT_SECCOMP = 7; 76 | enum PTRACE_EVENT_STOP = 128; 77 | enum PTRACE_O_TRACESYSGOOD = 1; 78 | enum PTRACE_O_TRACEFORK = 1 << PTRACE_EVENT_FORK; 79 | enum PTRACE_O_TRACEVFORK = 1 << PTRACE_EVENT_VFORK; 80 | enum PTRACE_O_TRACECLONE = 1 << PTRACE_EVENT_CLONE; 81 | enum PTRACE_O_TRACEEXEC = 1 << PTRACE_EVENT_EXEC; 82 | enum PTRACE_O_TRACEVFORKDONE = 1 << PTRACE_EVENT_VFORK_DONE; 83 | enum PTRACE_O_TRACEEXIT = 1 << PTRACE_EVENT_EXIT; 84 | enum PTRACE_O_TRACESECCOMP = 1 << PTRACE_EVENT_SECCOMP; 85 | enum PTRACE_O_EXITKILL = 1 << 20; 86 | enum PTRACE_O_SUSPEND_SECCOMP = 1 << 21; 87 | enum PTRACE_O_MASK = 0x000000ff | PTRACE_O_EXITKILL | PTRACE_O_SUSPEND_SECCOMP; 88 | 89 | // arch/x86/include/uapi/asm/ptrace-abi.h 90 | version (X86) version = X86_Any; 91 | version (X86_64) { 92 | version = X86_Any; 93 | enum PTRACE_ARCH_PRCTL = 30; 94 | } 95 | version (X86_Any) { 96 | enum PTRACE_GETREGS = 12; 97 | enum PTRACE_SETREGS = 13; 98 | enum PTRACE_GETFPREGS = 14; 99 | enum PTRACE_SETFPREGS = 15; 100 | enum PTRACE_GETFPXREGS = 18; 101 | enum PTRACE_SETFPXREGS = 19; 102 | 103 | enum PTRACE_OLDSETOPTIONS = 21; 104 | 105 | // only useful for access 32bit programs / kernels 106 | enum PTRACE_GET_THREAD_AREA = 25; 107 | enum PTRACE_SET_THREAD_AREA = 26; 108 | 109 | enum PTRACE_SYSEMU = 31; 110 | enum PTRACE_SYSEMU_SINGLESTEP = 32; 111 | 112 | enum PTRACE_SINGLEBLOCK = 33; /* resume execution until next branch */ 113 | } 114 | 115 | // arch/arm/include/asm/ptrace.h 116 | // arch/arm64/include/asm/ptrace.h 117 | version (ARM) version = ARM_Any; 118 | version (AArch64) { 119 | version = ARM_Any; 120 | // These are 'magic' values for PTRACE_PEEKUSR that return info about 121 | // where a process is located in memory. 122 | enum COMPAT_PT_TEXT_ADDR = 0x10000; 123 | enum COMPAT_PT_DATA_ADDR = 0x10004; 124 | enum COMPAT_PT_TEXT_END_ADDR = 0x10008; 125 | } 126 | version (ARM_Any) { 127 | enum PTRACE_GETREGS = 12; // + aarch32 128 | enum PTRACE_SETREGS = 13; // + aarch32 129 | enum PTRACE_GETFPREGS = 14; 130 | enum PTRACE_SETFPREGS = 15; 131 | enum PTRACE_GETWMMXREGS = 18; 132 | enum PTRACE_SETWMMXREGS = 19; 133 | enum PTRACE_OLDSETOPTIONS = 21; 134 | enum PTRACE_GET_THREAD_AREA = 22; // + aarch32 135 | enum PTRACE_SET_SYSCALL = 23; // + aarch32 136 | enum PTRACE_GETCRUNCHREGS = 25; /* obsolete */ 137 | enum PTRACE_SETCRUNCHREGS = 26; /* obsolete */ 138 | enum PTRACE_GETVFPREGS = 27; // + aarch32 139 | enum PTRACE_SETVFPREGS = 28; // + aarch32 140 | enum PTRACE_GETHBPREGS = 29; // + aarch32 141 | enum PTRACE_SETHBPREGS = 30; // + aarch32 142 | enum PTRACE_GETFDPIC = 31; 143 | 144 | enum PTRACE_GETFDPIC_EXEC = 0; 145 | enum PTRACE_GETFDPIC_INTERP = 1; 146 | } 147 | 148 | // arch/powerpc/include/uapi/ptrace.h 149 | version (PPC) version = PPC_Any; 150 | version (PPC64) version = PPC_Any; 151 | version (PPC_Any) { 152 | enum PTRACE_GETVRREGS = 0x12; 153 | enum PTRACE_SETVRREGS = 0x13; 154 | enum PTRACE_GETEVRREGS = 0x14; 155 | enum PTRACE_SETEVRREGS = 0x15; 156 | enum PTRACE_GETVSRREGS = 0x1b; 157 | enum PTRACE_SETVSRREGS = 0x1c; 158 | enum PTRACE_SYSEMU = 0x1d; 159 | enum PTRACE_SYSEMU_SINGLESTEP = 0x1e; 160 | enum PTRACE_GET_DEBUGREG = 0x19; 161 | enum PTRACE_SET_DEBUGREG = 0x1a; 162 | 163 | enum PTRACE_GETREGS = 0xc; 164 | enum PTRACE_SETREGS = 0xd; 165 | enum PTRACE_GETFPREGS = 0xe; 166 | enum PTRACE_SETFPREGS = 0xf; 167 | enum PTRACE_GETREGS64 = 0x16; 168 | enum PTRACE_SETREGS64 = 0x17; 169 | 170 | enum PPC_PTRACE_PEEKTEXT_3264 = 0x95; 171 | enum PPC_PTRACE_PEEKDATA_3264 = 0x94; 172 | enum PPC_PTRACE_POKETEXT_3264 = 0x93; 173 | enum PPC_PTRACE_POKEDATA_3264 = 0x92; 174 | enum PPC_PTRACE_PEEKUSR_3264 = 0x91; 175 | enum PPC_PTRACE_POKEUSR_3264 = 0x90; 176 | 177 | enum PTRACE_SINGLEBLOCK = 0x100; /* resume execution until next branch */ 178 | 179 | enum PPC_PTRACE_GETHWDBGINFO = 0x89; 180 | enum PPC_PTRACE_SETHWDEBUG = 0x88; 181 | enum PPC_PTRACE_DELHWDEBUG = 0x87; 182 | 183 | } 184 | 185 | /// The ptrace() system call provides a means by which one process (the 186 | /// "tracer") may observe and control the execution of another process 187 | /// (the "tracee"), and examine and change the tracee's memory and 188 | /// registers. It is primarily used to implement breakpoint debugging 189 | /// and system call tracing. 190 | /// 191 | /// Although arguments to ptrace() are interpreted according to the 192 | /// prototype given, glibc currently declares ptrace() as a variadic 193 | /// function with only the request argument fixed. It is recommended 194 | /// to always supply four arguments, even if the requested operation 195 | /// does not use them, setting unused/ignored arguments to 0L or 196 | /// (void *) 0. 197 | /// 198 | /// Params: 199 | /// req = PTRACE request 200 | /// pid = Process ID number (On Linux, that's a thread ID) 201 | /// addr = Memory pointer 202 | /// data = Data pointer 203 | /// 204 | /// Returns: 0 on success; -1 on error. For PT_PEEK requests, check errno 205 | /// first 206 | c_long ptrace(int req, ...); -------------------------------------------------------------------------------- /src/adbg/include/macos/ptrace.d: -------------------------------------------------------------------------------- 1 | /// ptrace(3) bindings for macOS. 2 | /// 3 | /// Sources: 4 | /// - https://github.com/apple-oss-distributions/xnu/blob/master/bsd/sys/ptrace.h 5 | /// 6 | /// Authors: dd86k 7 | /// Copyright: © dd86k 8 | /// License: BSD-3-Clause-Clear 9 | module adbg.include.macos.ptrace; 10 | 11 | version (OSX): 12 | 13 | import core.sys.posix.unistd : pid_t; 14 | 15 | alias caddr_t = void*; 16 | 17 | extern (C): 18 | 19 | enum { 20 | PT_TRACE_ME = 0, /// Child declares it's being traced 21 | PT_READ_I = 1, /// Read word in child's I space 22 | PT_READ_D = 2, /// Read word in child's D space 23 | PT_READ_U = 3, /// Read word in child's user structure 24 | PT_WRITE_I = 4, /// Write word in child's I space 25 | PT_WRITE_D = 5, /// Write word in child's D space 26 | PT_WRITE_U = 6, /// Write word in child's user structure 27 | PT_CONTINUE = 7, /// Continue the child 28 | PT_KILL = 8, /// Kill the child process 29 | PT_STEP = 9, /// Single step the child 30 | PT_DETACH = 11, /// Stop tracing a process 31 | PT_SIGEXC = 12, /// Signals as exceptions for current_proc 32 | PT_THUPDATE = 13, /// Signal for thread# 33 | PT_ATTACHEXC = 14, /// Attach to running process with signal exception 34 | 35 | PT_FORCEQUOTA = 30, /// Enforce quota for root 36 | PT_DENY_ATTACH = 31, 37 | 38 | PT_FIRSTMACH = 32, /// For machine-specific requests 39 | } 40 | 41 | deprecated("PT_ATTACH is deprecated. See PT_ATTACHEXC") 42 | enum PT_ATTACH = 10; /// Trace some running process 43 | 44 | int ptrace(int _request, pid_t _pid, caddr_t _addr, int _data); -------------------------------------------------------------------------------- /src/adbg/include/posix/mann.d: -------------------------------------------------------------------------------- 1 | /** 2 | * Mapping for sys/mman.h. 3 | * 4 | * Authors: dd86k 5 | * Copyright: © dd86k 6 | * License: BSD-3-Clause-Clear 7 | */ 8 | module adbg.include.posix.mann; 9 | 10 | version (Posix): 11 | 12 | public import core.sys.posix.stdlib : ssize_t, off_t; 13 | 14 | extern (C): 15 | 16 | enum MAP_SHARED = 0x01; /// Share changes 17 | enum MAP_PRIVATE = 0x02; /// Changes are private 18 | enum MAP_SHARED_VALIDATE = 0x03; /// share + validate extension flags 19 | enum MAP_TYPE = 0x0f; /// Mask for type of mapping 20 | enum MAP_FIXED = 0x10; /// Interpret addr exactly 21 | enum MAP_ANONYMOUS = 0x20; /// don't use a file 22 | 23 | version (linux) { 24 | enum MAP_GROWSDOWN = 0x01000; /// stack-like segment 25 | enum MAP_DENYWRITE = 0x02000; /// ETXTBSY 26 | enum MAP_EXECUTABLE = 0x04000; /// mark it as an executable 27 | enum MAP_LOCKED = 0x08000; /// lock the mapping 28 | enum MAP_NORESERVE = 0x10000; /// don't check for reservations 29 | enum MAP_POPULATE = 0x20000; /// populate (prefault) pagetables 30 | enum MAP_NONBLOCK = 0x40000; /// do not block on IO 31 | enum MAP_STACK = 0x80000; /// give out an address that is best suited for process/thread stacks 32 | enum MAP_HUGETLB = 0x100000; /// create a huge page mapping 33 | enum MAP_FIXED_NOREPLACE = 0x200000; /// MAP_FIXED which doesn't unmap underlying mapping 34 | } 35 | 36 | enum MAP_FAILED = cast(void*)-1; /// mmap returns MAP_FAILED when it failed to allocate 37 | 38 | enum PROT_READ = 0x1; /// page can be read 39 | enum PROT_WRITE = 0x2; /// page can be written 40 | enum PROT_EXEC = 0x4; /// page can be executed 41 | enum PROT_SEM = 0x8; /// page may be used for atomic ops 42 | enum PROT_NONE = 0x0; /// page can not be accessed 43 | enum PROT_GROWSDOWN = 0x01000000; /// mprotect flag: extend change to start of growsdown vma 44 | enum PROT_GROWSUP = 0x02000000; /// mprotect flag: extend change to end of growsup vma 45 | 46 | void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); 47 | int munmap(void *addr, size_t length); 48 | -------------------------------------------------------------------------------- /src/adbg/include/posix/ptrace.d: -------------------------------------------------------------------------------- 1 | /// ptrace(3) bindings. 2 | /// 3 | /// This module is only available where ptrace is available, and is currently 4 | /// based on Glibc 2.25 and Musl 1.20. 5 | /// 6 | /// x32 is not supported. 7 | /// 8 | /// Authors: dd86k 9 | /// Copyright: © dd86k 10 | /// License: BSD-3-Clause-Clear 11 | module adbg.include.posix.ptrace; 12 | 13 | version (Posix): 14 | 15 | version (linux) 16 | public import adbg.include.linux.ptrace; 17 | else version (OSX) 18 | public import adbg.include.macos.ptrace; 19 | else version (FreeBSD) 20 | public import adbg.include.freebsd.ptrace; -------------------------------------------------------------------------------- /src/adbg/include/posix/signal.d: -------------------------------------------------------------------------------- 1 | /// Missing POSIX signal definitions. 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module adbg.include.posix.signal; 7 | 8 | version (CRuntime_Glibc) { // 2.25 9 | public import core.sys.posix.signal : 10 | siginfo_t, 11 | SIGSEGV, SIGFPE, SIGILL, SIGINT, SIGTERM, SIGABRT, 12 | SIGTRAP, SIGBUS; 13 | } else version (CRuntime_Musl) { // 1.20 14 | enum SIGHUP = 1; /// 15 | enum SIGINT = 2; /// 16 | enum SIGQUIT = 3; /// 17 | enum SIGILL = 4; /// 18 | enum SIGTRAP = 5; /// 19 | enum SIGABRT = 6; /// 20 | enum SIGIOT = SIGABRT; /// 21 | enum SIGBUS = 7; /// 22 | enum SIGFPE = 8; /// 23 | enum SIGKILL = 9; /// 24 | enum SIGUSR1 = 10; /// 25 | enum SIGSEGV = 11; /// 26 | enum SIGUSR2 = 12; /// 27 | enum SIGPIPE = 13; /// 28 | enum SIGALRM = 14; /// 29 | enum SIGTERM = 15; /// 30 | enum SIGSTKFLT = 16; /// 31 | enum SIGCHLD = 17; /// 32 | enum SIGCONT = 18; /// 33 | enum SIGSTOP = 19; /// 34 | enum SIGTSTP = 20; /// 35 | enum SIGTTIN = 21; /// 36 | enum SIGTTOU = 22; /// 37 | enum SIGURG = 23; /// 38 | enum SIGXCPU = 24; /// 39 | enum SIGXFSZ = 25; /// 40 | enum SIGVTALRM = 26; /// 41 | enum SIGPROF = 27; /// 42 | enum SIGWINCH = 28; /// 43 | enum SIGIO = 29; /// 44 | enum SIGPOLL = 29; /// 45 | enum SIGPWR = 30; /// 46 | enum SIGSYS = 31; /// 47 | enum SIGUNUSED = SIGSYS; /// 48 | } 49 | 50 | public import core.sys.posix.signal; -------------------------------------------------------------------------------- /src/adbg/include/posix/sys/wait.d: -------------------------------------------------------------------------------- 1 | /// Fixing improper sys/wait.h definitions. 2 | /// 3 | /// Existing definitions are defined with extern (D), which tricks the 4 | /// compiler to define it as an external function, leading to linking issues. 5 | /// 6 | /// This module defines these macros, as inlined functions: 7 | /// WEXITSTATUS, WTERMSIG, WSTOPSIG, WIFEXITED, WIFSIGNALED, WIFSTOPPED, 8 | /// WIFCONTINUED, and WCOREDUMP. 9 | /// 10 | /// It also defines these values to be used in wait(2) functions: 11 | /// WNOHANG, WUNTRACED, WSTOPPED, WCONTINUED, WNOWAIT, WEXITED, and WTRAPPED 12 | /// 13 | /// Authors: dd86k 14 | /// Copyright: © dd86k 15 | /// License: BSD-3-Clause-Clear 16 | module adbg.include.posix.sys.wait; 17 | 18 | version (Posix): 19 | 20 | public import core.sys.posix.sys.wait; 21 | 22 | pragma(inline, true): 23 | 24 | version (linux) { 25 | // NOTE: wstatus 26 | // Bits Description (Linux) 27 | // 6:0 Signo that caused child to exit 28 | // 0x7f if child stopped/continued 29 | // or zero if child exited without signal 30 | // 7 Core dumped 31 | // 15:8 exit value (or returned main value) 32 | // or signal that cause child to stop/continue 33 | 34 | // Shared at least across Glibc and Musl 35 | enum WNOHANG = 1; 36 | enum WUNTRACED = 2; 37 | 38 | enum WSTOPPED = 2; 39 | enum WEXITED = 4; 40 | enum WCONTINUED = 8; 41 | enum WNOWAIT = 0x1000000; 42 | 43 | enum __WNOTHREAD = 0x20000000; 44 | enum __WALL = 0x40000000; 45 | enum __WCLONE = 0x80000000; 46 | 47 | int WEXITSTATUS(int s) { return (s & 0xff00) >> 8; } 48 | int WTERMSIG(int s) { return s & 0x7f; } 49 | int WSTOPSIG(int s) { return WEXITSTATUS(s); } 50 | 51 | bool WIFCONTINUED(int s) { return s == 0xffff; } 52 | 53 | int WCOREDUMP(int s) { return s & 0x80; } 54 | 55 | version (CRuntime_Glibc) { 56 | // bits/waitstatus.h 57 | // sysdeps/unix/sysv/linux/bits/waitflags.h 58 | 59 | bool WIFEXITED(int s) { return WTERMSIG(s) == 0; } 60 | bool WIFSIGNALED(int s) { return (cast(byte)((s & 0x7f) + 1) >> 1) > 0; } 61 | bool WIFSTOPPED(int s) { return (s & 0xff) == 0x7f; } 62 | 63 | /* 64 | #define __W_EXITCODE(ret, sig) ((ret) << 8 | (sig)) 65 | #define __W_STOPCODE(sig) ((sig) << 8 | 0x7f) 66 | */ 67 | } else version (CRuntime_Musl) { 68 | // include/sys/wait.h 69 | 70 | bool WIFEXITED(int s) { return !WTERMSIG(s); } 71 | bool WIFSIGNALED(int s) { return (s&0xffff)-1U < 0xffu; } 72 | bool WIFSTOPPED(int s) { return cast(short)(((s&0xffff)*0x10001U)>>8) > 0x7f00; } 73 | } else version (CRuntime_Bionic) { 74 | // libc/include/bits/wait.h 75 | 76 | bool WIFEXITED(int s) { return WTERMSIG(s) == 0; } 77 | bool WIFSIGNALED(int s) { return WTERMSIG(s+1) >= 2; } 78 | bool WIFSTOPPED(int s) { return WTERMSIG(s) == 0x7f; } 79 | } else static assert(0, "Define wait.h macros (Linux)"); 80 | } else version (FreeBSD) { 81 | // Source: sys/sys/wait.h 82 | 83 | enum WNOHANG = 1; 84 | enum WUNTRACED = 2; 85 | enum WSTOPPED = WUNTRACED; 86 | enum WCONTINUED = 4; 87 | enum WNOWAIT = 8; 88 | enum WEXITED = 16; 89 | enum WTRAPPED = 32; 90 | 91 | enum WLINUXCLONE = 0x80000000; // Wait for kthread spawned from linux_clone. 92 | 93 | enum _WSTOPPED = 0x7f; // 0177, _WSTATUS if process is stopped 94 | 95 | int _WSTATUS(int x) { return x & 0x7f; } // 0177 96 | 97 | int WEXITSTATUS(int x) { return x >> 8; } 98 | int WTERMSIG(int x) { return _WSTATUS(x); } 99 | alias WSTOPSIG = WEXITSTATUS; 100 | 101 | bool WIFSTOPPED(int x) { return _WSTATUS(x) == _WSTOPPED; } 102 | bool WIFSIGNALED(int x) { return _WSTATUS(x) != _WSTOPPED && _WSTATUS(x) != 0 && x != 0x13; } 103 | bool WIFEXITED(int x) { return _WSTATUS(x) == 0; } 104 | 105 | bool WIFCONTINUED(int x) { return x == 0x13; } // 0x13 == SIGCONT 106 | 107 | // #if __BSD_VISIBLE 108 | int WCOREDUMP(int x) { return x & 0x80; } 109 | 110 | /* 111 | #define W_EXITCODE(ret, sig) ((ret) << 8 | (sig)) 112 | #define W_STOPCODE(sig) ((sig) << 8 | _WSTOPPED) 113 | */ 114 | } else static assert(0, "Define wait.h macros"); -------------------------------------------------------------------------------- /src/adbg/include/posix/unistd.d: -------------------------------------------------------------------------------- 1 | /// Up to date Posix universal standard defitions (unistd.h) and other utilities. 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module adbg.include.posix.unistd; 7 | 8 | version (Posix): 9 | 10 | public import core.sys.posix.unistd; 11 | 12 | extern (C): 13 | 14 | // Missing XOpen (XSI) definitions for Musl 15 | version (CRuntime_Musl) { 16 | public import core.sys.posix.stdlib : ssize_t, off_t; 17 | public ssize_t pread(int, void *, size_t, off_t); 18 | public ssize_t pwrite(int, const(void)*, size_t, off_t); 19 | } 20 | 21 | // Only Linux has clone(2), BSDs still have fork(2) 22 | version (linux): 23 | 24 | // Cloning flags 25 | enum CSIGNAL = 0x000000ff; /// signal mask to be sent at exit 26 | enum CLONE_VM = 0x00000100; /// set if VM shared between processes 27 | enum CLONE_FS = 0x00000200; /// set if fs info shared between processes 28 | enum CLONE_FILES = 0x00000400; /// set if open files shared between processes 29 | enum CLONE_SIGHAND = 0x00000800; /// set if signal handlers and blocked signals shared 30 | enum CLONE_PTRACE = 0x00002000; /// set if we want to let tracing continue on the child too 31 | enum CLONE_VFORK = 0x00004000; /// set if the parent wants the child to wake it up on mm_release 32 | enum CLONE_PARENT = 0x00008000; /// set if we want to have the same parent as the cloner 33 | enum CLONE_THREAD = 0x00010000; /// Same thread group? 34 | enum CLONE_NEWNS = 0x00020000; /// New mount namespace group 35 | enum CLONE_SYSVSEM = 0x00040000; /// share system V SEM_UNDO semantics 36 | enum CLONE_SETTLS = 0x00080000; /// create a new TLS for the child 37 | enum CLONE_PARENT_SETTID = 0x00100000; /// set the TID in the parent 38 | enum CLONE_CHILD_CLEARTID = 0x00200000; /// clear the TID in the child 39 | enum CLONE_DETACHED = 0x00400000; /// Unused, ignored 40 | enum CLONE_UNTRACED = 0x00800000; /// set if the tracing process can't force CLONE_PTRACE on this clone 41 | enum CLONE_CHILD_SETTID = 0x01000000; /// set the TID in the child 42 | enum CLONE_NEWCGROUP = 0x02000000; /// New cgroup namespace 43 | enum CLONE_NEWUTS = 0x04000000; /// New utsname namespace 44 | enum CLONE_NEWIPC = 0x08000000; /// New ipc namespace 45 | enum CLONE_NEWUSER = 0x10000000; /// New user namespace 46 | enum CLONE_NEWPID = 0x20000000; /// New pid namespace 47 | enum CLONE_NEWNET = 0x40000000; /// New network namespace 48 | enum CLONE_IO = 0x80000000; /// Clone io context 49 | 50 | // shed.h 51 | int clone(int function(void *), void *stack, int flags, void *arg, ... 52 | /* pid_t *parent_tid, void *tls, pid_t *child_tid */ ); -------------------------------------------------------------------------------- /src/adbg/include/windows/tlhelp32.d: -------------------------------------------------------------------------------- 1 | /// Tool help library. 2 | /// 3 | /// Header: tlhelp32.h 4 | /// Library: Kernel32.lib 5 | /// DLL: Kernel32.dll 6 | /// 7 | /// Authors: dd86k 8 | /// Copyright: © dd86k 9 | /// License: BSD-3-Clause-Clear 10 | module adbg.include.windows.tlhelp32; 11 | 12 | version (Windows): 13 | 14 | import core.sys.windows.windef : BOOL, BYTE, DWORD, LONG, HMODULE, MAX_PATH, CHAR, WCHAR; 15 | import core.sys.windows.basetsd : HANDLE, ULONG_PTR, SIZE_T; 16 | 17 | extern (Windows): 18 | 19 | enum MAX_MODULE_NAME32 = 255; 20 | 21 | enum { 22 | /// Indicates that the snapshot handle is to be inheritable. 23 | TH32CS_INHERIT = 0x80000000, 24 | 25 | /// Includes all heaps of the process specified in th32ProcessID in the 26 | /// snapshot. To enumerate the heaps, see Heap32ListFirst. 27 | TH32CS_SNAPHEAPLIST = 0x00000001, 28 | 29 | /// Includes all modules of the process specified in th32ProcessID in 30 | /// the snapshot. To enumerate the modules, see Module32First. If the 31 | /// function fails with ERROR_BAD_LENGTH, retry the function until it 32 | /// succeeds. 33 | /// 34 | /// 64-bit Windows: Using this flag in a 32-bit process includes the 35 | /// 32-bit modules of the process specified in th32ProcessID, while 36 | /// using it in a 64-bit process includes the 64-bit modules. To include 37 | /// the 32-bit modules of the process specified in th32ProcessID from a 38 | /// 64-bit process, use the TH32CS_SNAPMODULE32 flag. 39 | TH32CS_SNAPMODULE = 0x00000008, 40 | 41 | /// Includes all 32-bit modules of the process specified in th32ProcessID 42 | /// in the snapshot when called from a 64-bit process. This flag can be 43 | /// combined with TH32CS_SNAPMODULE or TH32CS_SNAPALL. If the function 44 | /// fails with ERROR_BAD_LENGTH, retry the function until it succeeds. 45 | TH32CS_SNAPMODULE32 = 0x00000010, 46 | 47 | /// Includes all processes in the system in the snapshot. To enumerate 48 | /// the processes, see Process32First. 49 | TH32CS_SNAPPROCESS = 0x00000002, 50 | 51 | /// Includes all threads in the system in the snapshot. To enumerate 52 | /// the threads, see Thread32First. 53 | /// 54 | /// To identify the threads that belong to a specific process, compare 55 | /// its process identifier to the th32OwnerProcessID member of the 56 | /// THREADENTRY32 structure when enumerating the threads. 57 | TH32CS_SNAPTHREAD = 0x00000004, 58 | 59 | /// Includes all processes and threads in the system, plus the heaps and modules of the process specified in th32ProcessID. Equivalent to specifying the TH32CS_SNAPHEAPLIST, TH32CS_SNAPMODULE, TH32CS_SNAPPROCESS, and TH32CS_SNAPTHREAD values combined using an OR operation ('|'). 60 | TH32CS_SNAPALL = 61 | TH32CS_SNAPHEAPLIST | TH32CS_SNAPMODULE | 62 | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD, 63 | } 64 | 65 | HANDLE CreateToolhelp32Snapshot(DWORD dwFlags, DWORD th32ProcessID); 66 | /* 67 | BOOL Toolhelp32ReadProcessMemory(DWORD th32ProcessID, 68 | LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T cbRead, SIZE_T *lpNumberOfBytesRead); 69 | */ 70 | 71 | struct HEAPENTRY32 { 72 | SIZE_T dwSize; 73 | HANDLE hHandle; 74 | ULONG_PTR dwAddress; 75 | SIZE_T dwBlockSize; 76 | DWORD dwFlags; 77 | DWORD dwLockCount; 78 | DWORD dwResvd; 79 | DWORD th32ProcessID; 80 | ULONG_PTR th32HeapID; 81 | } 82 | alias LPHEAPENTRY32 = HEAPENTRY32*; 83 | 84 | BOOL Heap32First(LPHEAPENTRY32 lphe, DWORD th32ProcessID, ULONG_PTR th32HeapID); 85 | BOOL Heap32Next(LPHEAPENTRY32 lphe); 86 | 87 | struct HEAPLIST32 { 88 | SIZE_T dwSize; 89 | DWORD th32ProcessID; 90 | ULONG_PTR th32HeapID; 91 | DWORD dwFlags; 92 | } 93 | alias LPHEAPLIST32 = HEAPLIST32*; 94 | 95 | BOOL Heap32ListFirst(HANDLE hSnapshot, LPHEAPLIST32 lphl); 96 | BOOL Heap32ListNext(HANDLE hSnapshot, LPHEAPLIST32 lphl); 97 | 98 | struct MODULEENTRY32 { 99 | DWORD dwSize; 100 | DWORD th32ModuleID; 101 | DWORD th32ProcessID; 102 | DWORD GlblcntUsage; 103 | DWORD ProccntUsage; 104 | BYTE *modBaseAddr; 105 | DWORD modBaseSize; 106 | HMODULE hModule; 107 | char[MAX_MODULE_NAME32 + 1] szModule; 108 | char[MAX_PATH] szExePath; 109 | } 110 | alias LPMODULEENTRY32 = MODULEENTRY32*; 111 | 112 | BOOL Module32First(HANDLE hSnapshot, LPMODULEENTRY32 lpme); 113 | BOOL Module32Next(HANDLE hSnapshot, LPMODULEENTRY32 lpme); 114 | 115 | struct MODULEENTRY32W { 116 | DWORD dwSize; 117 | DWORD th32ModuleID; 118 | DWORD th32ProcessID; 119 | DWORD GlblcntUsage; 120 | DWORD ProccntUsage; 121 | BYTE *modBaseAddr; 122 | DWORD modBaseSize; 123 | HMODULE hModule; 124 | WCHAR[MAX_MODULE_NAME32 + 1] szModule; 125 | WCHAR[MAX_PATH] szExePath; 126 | } 127 | alias LPMODULEENTRY32W = MODULEENTRY32W*; 128 | 129 | BOOL Module32FirstW(HANDLE hSnapshot, LPMODULEENTRY32W lpme); 130 | BOOL Module32NextW(HANDLE hSnapshot, LPMODULEENTRY32W lpme); 131 | 132 | struct PROCESSENTRY32 { 133 | DWORD dwSize; 134 | DWORD cntUsage; 135 | DWORD th32ProcessID; 136 | ULONG_PTR th32DefaultHeapID; 137 | DWORD th32ModuleID; 138 | DWORD cntThreads; 139 | DWORD th32ParentProcessID; 140 | LONG pcPriClassBase; 141 | DWORD dwFlags; 142 | CHAR[MAX_PATH] szExeFile; 143 | } 144 | alias LPPROCESSENTRY32 = PROCESSENTRY32*; 145 | 146 | BOOL Process32First(HANDLE hSnapshot, LPPROCESSENTRY32 lppe); 147 | BOOL Process32Next(HANDLE hSnapshot, LPPROCESSENTRY32 lppe); 148 | 149 | struct PROCESSENTRY32W { 150 | DWORD dwSize; 151 | DWORD cntUsage; 152 | DWORD th32ProcessID; 153 | ULONG_PTR th32DefaultHeapID; 154 | DWORD th32ModuleID; 155 | DWORD cntThreads; 156 | DWORD th32ParentProcessID; 157 | LONG pcPriClassBase; 158 | DWORD dwFlags; 159 | WCHAR[MAX_PATH] szExeFile; 160 | } 161 | alias LPPROCESSENTRY32W = PROCESSENTRY32W*; 162 | 163 | BOOL Process32FirstW(HANDLE hSnapshot, LPPROCESSENTRY32W lppe); 164 | BOOL Process32NextW(HANDLE hSnapshot, LPPROCESSENTRY32W lppe); 165 | 166 | struct THREADENTRY32 { 167 | DWORD dwSize; 168 | DWORD cntUsage; 169 | DWORD th32ThreadID; 170 | DWORD th32OwnerProcessID; 171 | LONG tpBasePri; 172 | LONG tpDeltaPri; 173 | DWORD dwFlags; 174 | } 175 | alias LPTHREADENTRY32 = THREADENTRY32*; 176 | 177 | BOOL Thread32First(HANDLE hSnapshot, LPTHREADENTRY32 lpte); 178 | BOOL Thread32Next(HANDLE hSnapshot, LPTHREADENTRY32 lpte); -------------------------------------------------------------------------------- /src/adbg/include/windows/winbase.d: -------------------------------------------------------------------------------- 1 | /// Extra definitions for winbase.h. 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module adbg.include.windows.winbase; 7 | 8 | version (Windows): 9 | 10 | public import core.sys.windows.winbase; 11 | public import core.sys.windows.winnt; // For types 12 | 13 | // Vista and up 14 | extern (Windows) 15 | BOOL QueryFullProcessImageNameA( 16 | HANDLE hProcess, // [in] 17 | DWORD dwFlags, // [in] 18 | LPSTR lpExeName, // [out] 19 | PDWORD lpdwSize // [in, out 20 | ); -------------------------------------------------------------------------------- /src/adbg/include/windows/wow64apiset.d: -------------------------------------------------------------------------------- 1 | /// wow64apiset bindings 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module adbg.include.windows.wow64apiset; 7 | 8 | version (Win64): 9 | 10 | private import adbg.include.windows.winnt; 11 | 12 | extern (Windows): 13 | 14 | BOOL Wow64GetThreadContext(HANDLE, WOW64_CONTEXT*); 15 | BOOL Wow64SetThreadContext(HANDLE, WOW64_CONTEXT*); 16 | 17 | -------------------------------------------------------------------------------- /src/adbg/objects/mscoff.d: -------------------------------------------------------------------------------- 1 | /// MS-COFF Import Library format. 2 | /// 3 | /// Libraries typically built for the exporting application. 4 | /// 5 | /// Sources: 6 | /// - Microsoft Portable Executable and Common Object File Format Specification 7 | // Revision 11 – January 23, 2017 8 | /// - https://github.com/dlang/dmd/blob/master/compiler/src/dmd/backend/mscoff.d 9 | /// 10 | /// Authors: dd86k 11 | /// Copyright: © dd86k 12 | /// License: BSD-3-Clause-Clear 13 | module adbg.objects.mscoff; 14 | 15 | // Layout: 16 | // - UNIX Archive member header 17 | // - Import Header 18 | // - Null-terminated import name string 19 | // - Null-terminated DLL name string 20 | 21 | import adbg.objectserver; 22 | import adbg.utils.uid; 23 | import adbg.utils.math; 24 | import adbg.error; 25 | import core.stdc.stdlib; 26 | 27 | extern (C): 28 | 29 | enum { 30 | MSCOFF_VERSION_IMPORT = 0, 31 | MSCOFF_VERSION_ANON = 1, 32 | MSCOFF_VERSION_ANONV2 = 2, 33 | } 34 | 35 | enum { 36 | MSCOFF_OBJECT_CODE = 0, 37 | MSCOFF_OBJECT_DATA = 1, 38 | MSCOFF_OBJECT_CONST = 2, 39 | } 40 | 41 | enum { 42 | /// Import by ordinal 43 | MSCOFF_IMPORT_NAME_ORDINAL = 0, 44 | /// Import name is public symbol name. 45 | MSCOFF_IMPORT_NAME = 1, 46 | /// Import name is public symbol name skipping leading "?", "@", or optionally "_". 47 | MSCOFF_IMPORT_NAME_NO_PREFIX = 2, 48 | /// Import name is public symbol name skipping leading "?", "@", or optionally "_" 49 | /// and truncating at first "@". 50 | MSCOFF_IMPORT_NAME_UNDECORATE = 3, 51 | /// Import name is a name is explicitly provided after the DLL name. 52 | MSCOFF_IMPORT_NAME_EXPORTAS = 4, 53 | } 54 | 55 | struct mscoff_import_header_t { // IMPORT_OBJECT_HEADER 56 | /// Must be IMAGE_FILE_MACHINE_UNKNOWN. 57 | ushort Sig1; 58 | /// Must be 0xFFFF. 59 | ushort Sig2; 60 | /// Must be 0. 61 | ushort Version; 62 | /// PE32 machine. 63 | ushort Machine; 64 | /// Seconds since 1970. 65 | uint TimeStamp; 66 | 67 | uint Size; 68 | ushort Ordinal; // or Hint 69 | // Type : 2 -> IMPORT_TYPE 70 | // NameType : 3 -> IMPORT_NAME_TYPE 71 | // Reserved : 11 72 | ulong Flags; 73 | } 74 | 75 | struct mscoff_anon_header_t { // ANON_OBJECT_HEADER 76 | ushort Sig1; // Must be IMAGE_FILE_MACHINE_UNKNOWN 77 | ushort Sig2; // Must be 0xffff 78 | ushort Version; // >= 1 (implies the CLSID field is present) 79 | ushort Machine; 80 | uint TimeDateStamp; 81 | 82 | /*CLSID*/ UID ClassID; // Used to invoke CoCreateInstance 83 | uint SizeOfData; // Size of data that follows the header 84 | } 85 | 86 | struct mscoff_anon_header_v2_t { // ANON_OBJECT_HEADER_V2 87 | ushort Sig1; // Must be IMAGE_FILE_MACHINE_UNKNOWN 88 | ushort Sig2; // Must be 0xffff 89 | ushort Version; // >= 2 (implies the Flags field is present - otherwise V1) 90 | ushort Machine; 91 | uint TimeDateStamp; 92 | 93 | /* CLSID */ UID ClassID; // Used to invoke CoCreateInstance 94 | uint SizeOfData; // Size of data that follows the header 95 | uint Flags; // 0x1 -> contains metadata 96 | uint MetaDataSize; // Size of CLR metadata 97 | uint MetaDataOffset; // Offset of CLR metadata 98 | } 99 | 100 | struct mscoff_anon_header_bigobj_t { // ANON_OBJECT_HEADER_BIGOBJ 101 | /* same as ANON_OBJECT_HEADER_V2 */ 102 | ushort Sig1; // Must be IMAGE_FILE_MACHINE_UNKNOWN 103 | ushort Sig2; // Must be 0xffff 104 | ushort Version; // >= 2 (implies the Flags field is present) 105 | ushort Machine; // Actual machine - IMAGE_FILE_MACHINE_xxx 106 | uint TimeDateStamp; 107 | 108 | /* CLSID */ UID ClassID; // {D1BAA1C7-BAEE-4ba9-AF20-FAF66AA4DCB8} 109 | uint SizeOfData; // Size of data that follows the header, could be zero 110 | uint Flags; // 0x1 -> contains metadata 111 | uint MetaDataSize; // Size of CLR metadata 112 | uint MetaDataOffset; // Offset of CLR metadata 113 | 114 | /* bigobj specifics */ 115 | uint NumberOfSections; // extended from WORD 116 | uint PointerToSymbolTable; 117 | uint NumberOfSymbols; 118 | } 119 | 120 | // Same as PE32 121 | enum SYMNMLEN = 8; 122 | 123 | struct mscoff_anon_symbol_table32_t { 124 | union { 125 | ubyte[SYMNMLEN] Name; 126 | struct { 127 | uint Zeros; 128 | uint Offset; 129 | } 130 | } 131 | uint Value; 132 | int SectionNumber; 133 | ushort Type; 134 | ubyte StorageClass; 135 | ubyte NumberOfAuxSymbols; 136 | } 137 | static assert(mscoff_anon_symbol_table32_t.sizeof == 20); 138 | 139 | struct mscoff_anon_symbol_table_t { align(1): 140 | ubyte[SYMNMLEN] Name; 141 | uint Value; 142 | short SectionNumber; 143 | ushort Type; 144 | ubyte StorageClass; 145 | ubyte NumberOfAuxSymbols; 146 | } 147 | static assert(mscoff_anon_symbol_table_t.sizeof == 18); 148 | 149 | private 150 | struct internal_mscoff_t { 151 | union { 152 | mscoff_import_header_t import_header; 153 | mscoff_anon_header_t anon_header; 154 | mscoff_anon_header_v2_t anonv2_header; 155 | } 156 | } 157 | 158 | private enum HDRSZ = MAX!( 159 | MAX!(mscoff_anon_header_t.sizeof, mscoff_anon_header_v2_t.sizeof), 160 | mscoff_import_header_t.sizeof); 161 | 162 | int adbg_object_mscoff_load(adbg_object_t *o) { 163 | int e = adbg_object_impl_setup(o, AdbgObject.mscoff, 164 | internal_mscoff_t.sizeof, 165 | &adbg_object_mscoff_unload); 166 | if (e) return e; 167 | 168 | internal_mscoff_t *mscoff = cast(internal_mscoff_t*)adbg_object_impl_get_buffer(o); 169 | 170 | e = adbg_object_read_at(o, 0, &mscoff.anon_header, HDRSZ); 171 | if (e) return e; 172 | 173 | // TODO: Support swapping 174 | 175 | return 0; 176 | } 177 | void adbg_object_mscoff_unload(adbg_object_t *o, void *u) { 178 | 179 | } 180 | 181 | uint adbg_object_mscoff_version(adbg_object_t *o) { 182 | internal_mscoff_t *mscoff = cast(internal_mscoff_t*)adbg_object_impl_get_buffer(o); 183 | if (mscoff == null) return 0; 184 | return mscoff.anon_header.Version; 185 | } 186 | 187 | void* adbg_object_mscoff_header(adbg_object_t *o) { 188 | internal_mscoff_t *mscoff = cast(internal_mscoff_t*)adbg_object_impl_get_buffer(o); 189 | if (mscoff == null) return null; 190 | return &mscoff.anon_header; 191 | } 192 | -------------------------------------------------------------------------------- /src/adbg/objects/mz.d: -------------------------------------------------------------------------------- 1 | /// MZ executable object format. 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module adbg.objects.mz; 7 | 8 | import adbg.error; 9 | import adbg.objectserver; 10 | import adbg.utils.bit; 11 | import adbg.objects.ne : NE_MAGIC, adbg_object_ne_load; 12 | import adbg.objects.lx : LX_MAGIC, LE_MAGIC, adbg_object_lx_load; 13 | import adbg.objects.pe : PE_MAGIC, adbg_object_pe_load; 14 | import adbg.utils.math : MiB; 15 | import core.stdc.stdlib : malloc, calloc, free; 16 | 17 | extern (C): 18 | 19 | // TODO: Support compressed MZ files? 20 | 21 | /// Minimum file size for an MZ EXE. 22 | // NOTE: Borland EXE about 6K (includes a CRT?). 23 | private enum MINIMUM_SIZE = mz_header_t.sizeof + PAGE; 24 | 25 | /// Minimum, non-extended, header size. 26 | enum MZMHSZ = 28; 27 | 28 | /// Magic number for MZ objects. 29 | enum MAGIC_MZ = CHAR16!"MZ"; 30 | /// Swappged magic for MZ objects. 31 | enum MAGIC_ZM = CHAR16!"ZM"; 32 | 33 | /// Number of reserved words for e_res. 34 | enum ERESWDS = 16; 35 | /// Size of a MZ paragraph. 36 | enum PARAGRAPH = 16; 37 | /// Size of a MZ page. 38 | enum PAGE = 512; 39 | 40 | /// Offset to e_lfanew field in the MZ header, added 41 | /// in NE, LE, and PE32 executable images. 42 | enum LFANEW_OFFSET = 0x3c; 43 | 44 | /// MZ header structure. 45 | struct mz_header_t { 46 | ushort e_magic; /// Magic number 47 | ushort e_cblp; /// Bytes on last page of file 48 | ushort e_cp; /// Pages in file 49 | ushort e_crlc; /// Number of relocation entries in the table 50 | ushort e_cparh; /// Size of header in paragraphs 51 | ushort e_minalloc; /// Minimum extra paragraphs needed 52 | ushort e_maxalloc; /// Maximum extra paragraphs needed 53 | ushort e_ss; /// Initial (relative) SS value 54 | ushort e_sp; /// Initial SP value 55 | ushort e_csum; /// Checksum 56 | ushort e_ip; /// Initial IP value 57 | ushort e_cs; /// Initial (relative) CS value 58 | ushort e_lfarlc; /// File address of relocation table 59 | ushort e_ovno; /// Overlay number 60 | // Extended MZ header fields for newer executables (NE, LX, PE). 61 | ushort[ERESWDS] e_res; /// Reserved words 62 | uint e_lfanew; /// 63 | } 64 | static assert(mz_header_t.e_lfanew.offsetof == LFANEW_OFFSET); 65 | 66 | /// MZ relocation entry 67 | struct mz_reloc_t { 68 | ushort offset; 69 | ushort segment; 70 | } 71 | 72 | private enum { 73 | INTERNAL_REVERSED = 1, 74 | } 75 | private 76 | struct internal_mz_t { 77 | mz_header_t header; 78 | mz_reloc_t *relocs; 79 | int status; 80 | } 81 | 82 | int adbg_object_mz_load(adbg_object_t *o) { 83 | version (Trace) trace("o=%p", o); 84 | uint newsig = void; 85 | 86 | // Read MZ header to detect if we're dealing with a newer executable format 87 | mz_header_t header = void; 88 | int e = adbg_object_read_at(o, 0, &header, mz_header_t.sizeof); 89 | if (e) return e; 90 | version (Trace) trace("e_lfarlc=%#x", header.e_lfarlc); 91 | 92 | // If e_lfarlc (relocation table) starts lower than e_lfanew, 93 | // then assume old MZ, since e_lfarlc can point to 0x40. 94 | if (header.e_lfarlc < 0x40) 95 | goto Lmz; 96 | 97 | // If e_lfanew points within (extended) MZ header, 98 | // assume invalid offset 99 | if (header.e_lfanew <= mz_header_t.sizeof) 100 | goto Lmz; 101 | 102 | // ReactOS checks if NtHeaderOffset is not higher than 256 MiB. 103 | // If it is higher, it considers the executable to be invalid. 104 | // See: sdk/lib/rtl/image.c:RtlpImageNtHeaderEx 105 | if (header.e_lfanew >= MiB!256) 106 | return adbg_oops(AdbgError.objectMalformed); 107 | 108 | e = adbg_object_read_at(o, header.e_lfanew, &newsig, newsig.sizeof); 109 | if (e) return e; 110 | 111 | // 32-bit signature check 112 | version (Trace) trace("newsig=%#x", newsig); 113 | switch (newsig) { 114 | case PE_MAGIC: 115 | return adbg_object_pe_load(o, &header); 116 | default: 117 | } 118 | 119 | // 16-bit signature check 120 | switch (cast(ushort)newsig) { 121 | case NE_MAGIC: 122 | return adbg_object_ne_load(o, &header); 123 | case LX_MAGIC, LE_MAGIC: 124 | return adbg_object_lx_load(o, &header); 125 | default: 126 | // Because e_lfanew is set and reloc 127 | return adbg_oops(AdbgError.objectMalformed); 128 | } 129 | 130 | Lmz: // Nothing else came up, load as MZ 131 | e = adbg_object_impl_setup(o, AdbgObject.mz, 132 | internal_mz_t.sizeof, 133 | &adbg_object_mz_unload); 134 | if (e) return e; 135 | 136 | internal_mz_t *mz = cast(internal_mz_t*)adbg_object_impl_get_buffer(o); 137 | 138 | // Read header 139 | e = adbg_object_read_at(o, 0, &mz.header, mz_header_t.sizeof); 140 | if (e) return e; 141 | 142 | // HACK: Bad hack to check word endian 143 | if (mz.header.e_magic == MAGIC_ZM) 144 | mz.status = INTERNAL_REVERSED; 145 | 146 | // Inverse header if required 147 | if (mz.status & INTERNAL_REVERSED) with (mz.header) { 148 | e_magic = adbg_bswap16(e_magic); 149 | e_cblp = adbg_bswap16(e_cblp); 150 | e_cp = adbg_bswap16(e_cp); 151 | e_crlc = adbg_bswap16(e_crlc); 152 | e_cparh = adbg_bswap16(e_cparh); 153 | e_minalloc = adbg_bswap16(e_minalloc); 154 | e_maxalloc = adbg_bswap16(e_maxalloc); 155 | e_ss = adbg_bswap16(e_ss); 156 | e_sp = adbg_bswap16(e_sp); 157 | e_csum = adbg_bswap16(e_csum); 158 | e_ip = adbg_bswap16(e_ip); 159 | e_cs = adbg_bswap16(e_cs); 160 | e_lfarlc = adbg_bswap16(e_lfarlc); 161 | e_ovno = adbg_bswap16(e_ovno); 162 | } 163 | 164 | return 0; 165 | } 166 | 167 | void adbg_object_mz_unload(adbg_object_t *o, void *buffer) { 168 | internal_mz_t *mz = cast(internal_mz_t*)buffer; 169 | if (mz.relocs) free(mz.relocs); 170 | } 171 | 172 | mz_header_t* adbg_object_mz_header(adbg_object_t *o) { 173 | internal_mz_t *mz = cast(internal_mz_t*)adbg_object_impl_get_buffer(o); 174 | if (mz == null) return null; 175 | return &mz.header; 176 | } 177 | 178 | mz_reloc_t* adbg_object_mz_reloc(adbg_object_t *o, size_t index) { 179 | internal_mz_t *mz = cast(internal_mz_t*)adbg_object_impl_get_buffer(o); 180 | if (mz == null) return null; 181 | 182 | // Initiate relocation buffer 183 | if (mz.relocs == null) { 184 | // Any relocations in object and after header? 185 | if (mz.header.e_crlc == 0 || mz.header.e_lfarlc < MZMHSZ) { 186 | adbg_oops(AdbgError.unavailable); 187 | return null; 188 | } 189 | 190 | // Allocate portion to hold relocations 191 | size_t size = mz.header.e_crlc * mz_reloc_t.sizeof; 192 | mz.relocs = cast(mz_reloc_t*)malloc(size); 193 | if (mz.relocs == null) { 194 | adbg_oops(AdbgError.crt); 195 | return null; 196 | } 197 | 198 | // Error set by function 199 | if (adbg_object_read_at(o, mz.header.e_lfarlc, mz.relocs, size)) { 200 | free(mz.relocs); 201 | mz.relocs = null; 202 | return null; 203 | } 204 | 205 | // Byteswap all relocation entries 206 | if (mz.status & INTERNAL_REVERSED) { 207 | for (ushort i; i < mz.header.e_crlc; ++i) { 208 | mz_reloc_t *reloc = &mz.relocs[index]; 209 | reloc.offset = adbg_bswap16(reloc.offset); 210 | reloc.segment = adbg_bswap16(reloc.segment); 211 | } 212 | } 213 | } 214 | 215 | // Check index bounds 216 | if (index >= mz.header.e_crlc) { 217 | adbg_oops(AdbgError.indexBounds); 218 | return null; 219 | } 220 | 221 | // Get relocation 222 | return &mz.relocs[index]; 223 | } 224 | 225 | const(char)* adbg_object_mz_kind_string(adbg_object_t *o) { 226 | internal_mz_t *mz = cast(internal_mz_t*)adbg_object_impl_get_buffer(o); 227 | if (mz == null) return null; 228 | 229 | return mz.header.e_ovno ? `Overlayed Executable` : `Executable`; 230 | } -------------------------------------------------------------------------------- /src/adbg/objects/package.d: -------------------------------------------------------------------------------- 1 | /// Objects metapackage. 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module adbg.objects; 7 | 8 | public import 9 | adbg.objects.elf, 10 | adbg.objects.macho, 11 | adbg.objects.mz, 12 | adbg.objects.ne, 13 | adbg.objects.lx, 14 | adbg.objects.pe, 15 | adbg.objects.pdb, 16 | adbg.objects.mdmp, 17 | adbg.objects.dmp, 18 | adbg.objects.omf, 19 | adbg.objects.ar, 20 | adbg.objects.coff, 21 | adbg.objects.mscoff; -------------------------------------------------------------------------------- /src/adbg/os/file.d: -------------------------------------------------------------------------------- 1 | /// OS file handling. 2 | /// 3 | /// No user code should be using this directly, as it is used internally. 4 | /// 5 | /// Authors: dd86k 6 | /// Copyright: © dd86k 7 | /// License: BSD-3-Clause-Clear 8 | module adbg.os.file; 9 | 10 | //TODO: wchar_t support 11 | 12 | version (Windows) { 13 | import core.sys.windows.winnt; 14 | import core.sys.windows.winbase; 15 | 16 | private alias OSHANDLE = HANDLE; 17 | private alias SEEK_SET = FILE_BEGIN; 18 | private alias SEEK_CUR = FILE_CURRENT; 19 | private alias SEEK_END = FILE_END; 20 | 21 | private enum OFLAG_OPENONLY = OPEN_EXISTING; 22 | } else version (Posix) { 23 | import core.sys.posix.unistd; 24 | import core.sys.posix.sys.types; 25 | import core.sys.posix.sys.stat; 26 | import core.sys.posix.fcntl; 27 | import core.stdc.stdio : SEEK_SET, SEEK_CUR, SEEK_END; 28 | import core.stdc.stdlib : malloc, free; 29 | 30 | private enum _IOC_NRBITS = 8; 31 | private enum _IOC_TYPEBITS = 8; 32 | private enum _IOC_SIZEBITS = 14; 33 | private enum _IOC_NRSHIFT = 0; 34 | private enum _IOC_TYPESHIFT = _IOC_NRSHIFT + _IOC_NRBITS; 35 | private enum _IOC_SIZESHIFT = _IOC_TYPESHIFT + _IOC_TYPEBITS; 36 | private enum _IOC_DIRSHIFT = _IOC_SIZESHIFT + _IOC_SIZEBITS; 37 | private enum _IOC_READ = 2; 38 | private enum _IOC(int dir,int type,int nr,size_t size) = 39 | (dir << _IOC_DIRSHIFT) | 40 | (type << _IOC_TYPESHIFT) | 41 | (nr << _IOC_NRSHIFT) | 42 | (size << _IOC_SIZESHIFT); 43 | //TODO: _IOR!(0x12,114,size_t.sizeof) results in ulong.max 44 | // I don't know why, so I'm casting it to int to let it compile. 45 | // Fix later. 46 | private enum _IOR(int type,int nr,size_t size) = 47 | cast(int)_IOC!(_IOC_READ,type,nr,size); 48 | 49 | // BLKGETSIZE64 missing from dmd 2.098.1 and ldc 1.24.0 50 | // ldc 1.24 missing core.sys.linux.fs 51 | // musl 1.2.0 and glibc 2.25 sources have the same settings. 52 | private enum BLKGETSIZE64 = cast(int)_IOR!(0x12,114,size_t.sizeof); 53 | private alias BLOCKSIZE = BLKGETSIZE64; 54 | 55 | // Platforms that lack the lseek64 symbol 56 | version (OSX) 57 | version = LACKS_LSEEK64; 58 | else version (FreeBSD) 59 | version = LACKS_LSEEK64; 60 | else version (Android) 61 | version = LACKS_LSEEK64; 62 | 63 | // TODO: Likely invalid, or only valid for ioctl, so check! 64 | version (Android) 65 | alias off_t = int; 66 | else 67 | alias off_t = long; 68 | 69 | private extern (C) int ioctl(int,off_t,...); 70 | 71 | private alias OSHANDLE = int; 72 | 73 | version (FreeBSD) { 74 | // Because core.sys.posix.sys.stat.fstat is marked with 75 | // pragma(mangle, "fstat@FBSD_1.5") 76 | // it leads to incorrect linked version, it is redefined here 77 | extern (C) int fstat(int, stat_t*); 78 | } 79 | } 80 | 81 | version (Trace) import adbg.error : trace; 82 | 83 | /// File seek origin. 84 | enum OSFileSeek { 85 | start = SEEK_SET, /// Seek from start of file. 86 | current = SEEK_CUR, /// Seek from current position. 87 | end = SEEK_END, /// Seek from end of file. 88 | } 89 | 90 | /// 91 | enum OSFileOFlags { 92 | read = 1, 93 | write = 2, 94 | readWrite = read | write, 95 | } 96 | 97 | struct OSFILE { 98 | OSHANDLE handle; 99 | int status; 100 | } 101 | 102 | OSFILE* osfopen(const(char) *path, int flags) { 103 | version (Windows) { 104 | OSFILE* file = cast(OSFILE*)VirtualAlloc(null, OSFILE.sizeof, MEM_COMMIT, PAGE_READWRITE); 105 | if (file == null) { 106 | version (Trace) trace("VirtualAlloc=%#x", GetLastError()); 107 | return null; 108 | } 109 | 110 | uint dwAccess; 111 | if (flags & OSFileOFlags.read) dwAccess |= GENERIC_READ; 112 | if (flags & OSFileOFlags.write) dwAccess |= GENERIC_WRITE; 113 | 114 | file.handle = CreateFileA(path, // lpFileName 115 | dwAccess, // dwDesiredAccess 116 | FILE_SHARE_READ, // dwShareMode 117 | null, // lpSecurityAttributes 118 | OPEN_EXISTING, // dwCreationDisposition 119 | 0, // dwFlagsAndAttributes 120 | null // hTemplateFile 121 | ); 122 | if (file.handle == INVALID_HANDLE_VALUE) { 123 | version (Trace) trace("CreateFileA=%#x", GetLastError()); 124 | VirtualFree(cast(void*)file, 0, MEM_RELEASE); 125 | return null; 126 | } 127 | } else version (Posix) { 128 | OSFILE* file = cast(OSFILE*)malloc(OSFILE.sizeof); 129 | if (file == null) 130 | return null; 131 | 132 | int oflags = void; 133 | final switch (flags & OSFileOFlags.readWrite) { 134 | case OSFileOFlags.readWrite: 135 | oflags = O_RDWR; 136 | break; 137 | case OSFileOFlags.write: 138 | oflags = O_WRONLY; 139 | break; 140 | case OSFileOFlags.read: 141 | oflags = O_RDONLY; 142 | break; 143 | } 144 | 145 | file.handle = .open(path, oflags); 146 | if (file.handle < 0) { 147 | free(file); 148 | return null; 149 | } 150 | } 151 | file.status = 0; 152 | return file; 153 | } 154 | 155 | long osfseek(OSFILE* file, long position, OSFileSeek origin) { 156 | version (Windows) { 157 | LARGE_INTEGER i = void; 158 | i.QuadPart = position; 159 | if (SetFilePointerEx(file.handle, i, &i, origin) == FALSE) 160 | return -1; 161 | return i.QuadPart; 162 | } else version (LACKS_LSEEK64) { 163 | // TODO: Check for off_t=64b 164 | position = lseek(file.handle, position, origin); // Lacks lseek64 165 | if (position < 0) 166 | return -1; 167 | return position; 168 | } else version (Posix) { 169 | position = lseek64(file.handle, position, origin); 170 | if (position < 0) 171 | return -1; 172 | return position; 173 | } 174 | } 175 | 176 | long osftell(OSFILE* file) { 177 | version (Windows) { 178 | LARGE_INTEGER i; 179 | SetFilePointerEx(file.handle, i, &i, FILE_CURRENT); 180 | return i.QuadPart; 181 | } else version (LACKS_LSEEK64) { 182 | return lseek(file.handle, 0, SEEK_CUR); 183 | } else version (Posix) { 184 | return lseek64(file.handle, 0, SEEK_CUR); 185 | } 186 | } 187 | 188 | long osfsize(OSFILE* file) { 189 | version (Windows) { 190 | LARGE_INTEGER li = void; 191 | if (GetFileSizeEx(file.handle, &li) == FALSE) 192 | return -1; 193 | return li.QuadPart; 194 | } else version (Posix) { 195 | stat_t stats = void; 196 | if (fstat(file.handle, &stats) < 0) 197 | return -1; 198 | // NOTE: fstat(2) sets st_size to 0 on block devices 199 | switch (stats.st_mode & S_IFMT) { 200 | case S_IFREG: // File 201 | case S_IFLNK: // Link 202 | return stats.st_size; 203 | case S_IFBLK: // Block devices (like a disk) 204 | //TODO: BSD variants 205 | long s = void; 206 | return ioctl(file.handle, BLOCKSIZE, &s) < 0 ? -1 : s; 207 | default: 208 | return -1; 209 | } 210 | } 211 | } 212 | 213 | int osfread(OSFILE* file, void* buffer, int size) { 214 | version (Windows) { 215 | if (ReadFile(file.handle, buffer, size, cast(uint*)&size, null) == FALSE) 216 | return -1; 217 | return size; 218 | } else version (Posix) { 219 | ssize_t len = .read(file.handle, buffer, size); 220 | if (len < 0) 221 | return -1; 222 | return cast(int)len; 223 | } 224 | } 225 | 226 | int osfwrite(OSFILE* file, void* buffer, int size) { 227 | version (Windows) { 228 | if (WriteFile(file.handle, buffer, size, cast(uint*)&size, null) == FALSE) 229 | return -1; 230 | return size; 231 | } else version (Posix) { 232 | ssize_t len = .write(file.handle, buffer, size); 233 | if (len < 0) 234 | return -1; 235 | return cast(int)len; 236 | } 237 | } 238 | 239 | void osfflush(OSFILE* file) { 240 | version (Windows) { 241 | FlushFileBuffers(file.handle); 242 | } else version (Posix) { 243 | .fsync(file.handle); 244 | } 245 | } 246 | 247 | void osfclose(OSFILE* file) { 248 | version (Windows) { 249 | CloseHandle(file.handle); 250 | VirtualFree(cast(void*)file, 0, MEM_RELEASE); 251 | } else version (Posix) { 252 | .close(file.handle); 253 | free(file); 254 | } 255 | } 256 | -------------------------------------------------------------------------------- /src/adbg/os/path.d: -------------------------------------------------------------------------------- 1 | /// OS path handling. 2 | /// 3 | /// No user code should be using this directly, as it is used internally. 4 | /// 5 | /// Authors: dd86k 6 | /// Copyright: © dd86k 7 | /// License: BSD-3-Clause-Clear 8 | module adbg.os.path; 9 | 10 | version (Windows) { 11 | import core.sys.windows.windef : FALSE; 12 | import core.sys.windows.winbase : GetCurrentDirectoryA, SetCurrentDirectoryA; 13 | } else version (Posix) { 14 | import core.sys.posix.unistd : chdir, getcwd; 15 | } 16 | 17 | import adbg.error; 18 | 19 | // Returns: null on error. 20 | const(char)* adbg_os_pwd(char *buffer, uint bsize) { 21 | version (Windows) { 22 | if (GetCurrentDirectoryA(bsize, buffer) == 0) { 23 | adbg_oops(AdbgError.os); 24 | return null; 25 | } 26 | return buffer; 27 | } else version (Posix) { 28 | const(char) *p = getcwd(buffer, bsize); // includes null 29 | if (p == null) adbg_oops(AdbgError.crt); 30 | return p; 31 | } else { 32 | adbg_oops(AdbgError.unimplemented); 33 | return null; 34 | } 35 | } 36 | 37 | int adbg_os_chdir(const(char) *path) { 38 | version (Windows) { 39 | if (SetCurrentDirectoryA(path) == FALSE) 40 | return adbg_oops(AdbgError.os); 41 | return 0; 42 | } else version (Posix) { 43 | if (chdir(path) < 0) 44 | return adbg_oops(AdbgError.os); 45 | return 0; 46 | } else { 47 | return adbg_oops(AdbgError.unimplemented); 48 | } 49 | } -------------------------------------------------------------------------------- /src/adbg/package.d: -------------------------------------------------------------------------------- 1 | /// Package for whole library. 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module adbg; 7 | 8 | public import 9 | adbg.error, 10 | adbg.process, 11 | adbg.debugger, 12 | adbg.disassembler, 13 | adbg.objectserver, 14 | adbg.scanner; -------------------------------------------------------------------------------- /src/adbg/process/breakpoint.d: -------------------------------------------------------------------------------- 1 | /// Process breakpoint management and evaluation. 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module adbg.process.breakpoint; 7 | 8 | import adbg.process.base; 9 | import adbg.process.memory; 10 | import adbg.error; 11 | import adbg.utils.list; 12 | import adbg.utils.bit; 13 | 14 | extern (C): 15 | 16 | // NOTE: When a breakpoint is hit by the debugger, the address should 17 | // be checked against the process' breakpoint list. 18 | 19 | // TODO: Test Thumb BKPT 20 | // TODO: Test AArch32 BKPT 21 | // TODO: Test AArch64 BRK 22 | 23 | // TODO: Move opcode bits to dedicated module 24 | version (X86) { 25 | private alias ubyte opcode_t; 26 | private immutable ubyte[] bpdata = [ 0xcc ]; // int3 27 | } else version (X86_64) { 28 | private alias ubyte opcode_t; 29 | private immutable ubyte[] bpdata = [ 0xcc ]; // int3 30 | } else version (ARM_Thumb) { 31 | // 1 0 Thumb BKPT 32 | // 5432 1098 7654 3210 bit 33 | // 1011 1110 | | 34 | // +-imm8--+ 35 | private template T16BKPT(ubyte n) { 36 | enum T16BKPT = ARRAY16!(0xbe << 8 | n); 37 | /* 38 | version (BigEndian) 39 | enum ubyte[2] T16BKPT = [ 0xbe, n ]; 40 | else 41 | enum ubyte[2] T16BKPT = [ n, 0xbe ]; 42 | */ 43 | } 44 | private alias ushort opcode_t; 45 | private immutable ubyte[] bpdata = T16BKPT!(0xdd); 46 | //private immutable ubyte[] bpdata = [ 0xbe, 0xdd ]; // BRK #221 47 | } else version (ARM) { 48 | // 3 2 1 AArch32 BKPT 49 | // 1098 7654 3210 9876 5432 1098 7654 3210 bit 50 | // | | 0001 0010 | | 0111 | | 51 | // cond(!=1110) +---imm12----+ imm4 - imm12:imm4 52 | private template A32BKPT(ushort n) { 53 | enum A32BKPT = ARRAY32!(0xe12 << 20 | (n >> 4) << 8 | 7 << 4 | n & 15); 54 | /* 55 | version (BigEndian) 56 | enum ubyte[4] A32BKPT = [ 0xe1, 0x20 | (n >> 12), (n >> 4) & 255, 0x70 | (n & 15) ]; 57 | else 58 | enum ubyte[4] A32BKPT = [ 0x70 | (n & 15), (n >> 4) & 255, 0x20 | (n >> 12), 0xe1 ]; 59 | */ 60 | } 61 | private alias uint opcode_t; 62 | private immutable ubyte[] bpdata = A32BKPT!(0xdd); 63 | //private immutable ubyte[] bpdata = [ 0xe1, 0x20, 0x0d, 0x7d ]; // BRK #221 64 | } else version (AArch64) { 65 | // 3 2 1 AArch64 BRK 66 | // 1098 7654 3210 9876 5432 1098 7654 3210 bit 67 | // 1101 0100 001| |0 0000 68 | // +-------imm16------+ 69 | private template A64BRK(ushort n) { 70 | enum A64BRK = ARRAY32!(0xd42 << 21 | n << 5); 71 | /* 72 | version (BigEndian) 73 | enum ubyte[4] A64BRK = [ 0xd4, n >> 11, (n >> 3) & 255, (n & 7) << 5 ]; 74 | else 75 | enum ubyte[4] A64BRK = [ (n & 7) << 5, (n >> 3) & 255, n >> 11, 0xd4 ]; 76 | */ 77 | } 78 | private alias uint opcode_t; 79 | private immutable ubyte[] bpdata = A64BRK!(0xdd); 80 | //private immutable ubyte[] bpdata = [ 0xa0, 0x1b, 0x20, 0xd4 ]; // BRK #221 81 | } else 82 | static assert(0, "Missing BREAKPOINT value for target platform"); 83 | 84 | private enum bplength = bpdata.length; 85 | 86 | // Breakpoint layout in memory 87 | struct adbg_breakpoint_t { align(1): 88 | union { 89 | opcode_t opcode; 90 | ubyte[bplength] opdata; 91 | } 92 | int magic; // cookie 93 | int id; // in process breakpoint list 94 | int type; // regular, source, etc. 95 | } 96 | 97 | struct adbg_breakpoint_entry_t { 98 | size_t address; 99 | } 100 | 101 | // TODO: Breakpoint API 102 | // Add, remove, get list, etc. + initiate function -------------------------------------------------------------------------------- /src/adbg/process/frame.d: -------------------------------------------------------------------------------- 1 | /// Process frame management. 2 | /// 3 | /// Stack frames, unwinding operations, etc. 4 | /// 5 | /// Authors: dd86k 6 | /// Copyright: © dd86k 7 | /// License: BSD-3-Clause-Clear 8 | module adbg.process.frame; 9 | 10 | import adbg.error; 11 | import adbg.machines; 12 | import adbg.process.base; // for machine info 13 | import adbg.process.thread; // for accessing thread information 14 | import adbg.utils.list; 15 | 16 | extern (C): 17 | 18 | struct adbg_stackframe_t { 19 | int level; 20 | // TODO: Frame type/function (e.g., points to memory, register, etc.) 21 | ulong address; 22 | } 23 | 24 | private 25 | struct __machine_pc_reg { 26 | AdbgMachine machine; 27 | AdbgRegister reg; 28 | } 29 | // Level 0: Current location, typically Program Counter 30 | // Level 1: Frame Pointer if available 31 | private 32 | static immutable __machine_pc_reg[] stackregs = [ 33 | { AdbgMachine.i386, AdbgRegister.x86_eip }, 34 | { AdbgMachine.amd64, AdbgRegister.amd64_rip }, 35 | { AdbgMachine.arm, AdbgRegister.arm_pc }, 36 | { AdbgMachine.aarch64, AdbgRegister.aarch64_pc }, 37 | ]; 38 | 39 | void* adbg_frame_list(adbg_process_thread_t *thread) { 40 | if (thread == null) { 41 | adbg_oops(AdbgError.invalidArgument); 42 | return null; 43 | } 44 | 45 | // No process attached 46 | if (thread.process == null) { 47 | adbg_oops(AdbgError.assertion); 48 | return null; 49 | } 50 | 51 | // Get (updated) context because PC/IP being the first frame is 52 | // important 53 | adbg_thread_context_t *ctx = adbg_process_thread_context(thread); 54 | if (ctx == null) 55 | return null; 56 | 57 | // Get register denoting PC depending on machine 58 | AdbgMachine mach = adbg_process_machine(thread.process); 59 | AdbgRegister register = void; 60 | foreach (ref regs; stackregs) { 61 | // Found it 62 | if (mach == regs.machine) { 63 | register = regs.reg; 64 | goto Lfound; 65 | } 66 | } 67 | 68 | adbg_oops(AdbgError.unavailable); 69 | return null; 70 | 71 | Lfound: 72 | // New frame list 73 | list_t *list = adbg_list_new(adbg_stackframe_t.sizeof, 8); 74 | if (list == null) 75 | return null; 76 | 77 | // Start with the first frame, which is always PC 78 | // If we can't have that, then we cannot even obtain frames at all 79 | adbg_register_t *reg = adbg_register_by_id(&thread.context, register); 80 | if (reg == null) { 81 | adbg_oops(AdbgError.unavailable); 82 | adbg_list_close(list); 83 | return null; 84 | } 85 | 86 | void *address = adbg_register_value(reg); 87 | if (address == null) { 88 | adbg_list_close(list); 89 | return null; 90 | } 91 | 92 | adbg_stackframe_t frame = void; 93 | frame.level = 0; 94 | 95 | // Get its value 96 | switch (mach) { 97 | // 32-bit PC 98 | case AdbgMachine.i386, AdbgMachine.arm: 99 | frame.address = *cast(uint*)address; 100 | break; 101 | // 64-bit PC 102 | case AdbgMachine.amd64, AdbgMachine.aarch64: 103 | frame.address = *cast(ulong*)address; 104 | break; 105 | default: 106 | adbg_oops(AdbgError.assertion); 107 | adbg_list_close(list); 108 | return null; 109 | } 110 | 111 | list = adbg_list_add(list, &frame); 112 | if (list == null) { 113 | adbg_list_close(list); 114 | return null; 115 | } 116 | 117 | // TODO: Next frame 118 | // 119 | // Frame pointers (EBP: x86, RBP: amd64, FP: arm) usually 120 | // designate the next stack frame. 121 | // Typically, for example under Linux (amd64), RBP is assigned 122 | // for segmentation faults, but not breakpoints (in the parent 123 | // process, at least, like a debugger). 124 | // 125 | // Otherwise, the next frame will have to be obtained from 126 | // debugging information (FPO, etc.) 127 | 128 | return list; 129 | } 130 | 131 | size_t adbg_frame_list_count(void *list) { 132 | return adbg_list_count(cast(list_t*)list); 133 | } 134 | 135 | adbg_stackframe_t* adbg_frame_list_at(void *list, size_t index) { 136 | return cast(adbg_stackframe_t*)adbg_list_get(cast(list_t*)list, index); 137 | } 138 | 139 | void adbg_frame_list_close(void *list) { 140 | adbg_list_close(cast(list_t*)list); 141 | } -------------------------------------------------------------------------------- /src/adbg/process/package.d: -------------------------------------------------------------------------------- 1 | /// Process meta package. 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module adbg.process; 7 | 8 | public import 9 | adbg.process.base, 10 | adbg.process.exception, 11 | adbg.process.breakpoint, 12 | adbg.process.memory, 13 | adbg.process.frame, 14 | adbg.process.thread; -------------------------------------------------------------------------------- /src/adbg/scanner.d: -------------------------------------------------------------------------------- 1 | /// Memory scanner. 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module adbg.scanner; 7 | 8 | import adbg.error; 9 | import adbg.process.base; 10 | import adbg.process.memory; 11 | import adbg.include.c.stdlib; 12 | import adbg.include.c.stdarg; 13 | import adbg.utils.list; 14 | import core.stdc.string; 15 | 16 | extern (C): 17 | 18 | /// Options for adbg_memory_scan. 19 | enum AdbgScanOption { 20 | /// Unaligned memory scans take a lot more time. 21 | /// Type: int 22 | /// Default: 0 (false) 23 | unaligned = 1, 24 | /// Include all process modules in the scan. 25 | /// Type: int 26 | /// Default: 0 (false) 27 | allModules = 2, 28 | // TODO: result limit/maximum 29 | // TODO: comparison callback 30 | // TODO: progress callback 31 | } 32 | 33 | struct adbg_scanner_t { 34 | adbg_process_t *process; 35 | //void *pmaps; 36 | list_t *results; 37 | size_t datasize; /// size of initial data 38 | int options; 39 | } 40 | struct adbg_scanner_result_t { 41 | ulong address; 42 | union { 43 | ulong u64; 44 | } 45 | } 46 | 47 | // TODO: Consider separating scanner creation and initial scan as two functions. 48 | /// Launch a new scan. 49 | /// 50 | /// Create a new memory scanner and associate it with data (needle) to search 51 | /// with. Entries are added to 52 | /// 53 | /// This immediately launches a new scan. To rescan with the same search 54 | /// parameter (needle), use `adbg_scanner_rescan`. 55 | /// Params: 56 | /// process = Process instance. 57 | /// data = Search data (needle). 58 | /// datasize = Search data size in Bytes. 59 | /// ... = Scanner parameters. Must end with 0. 60 | /// Returns: Scanner instance, or null on error. 61 | adbg_scanner_t* adbg_scanner_scan(adbg_process_t *process, void* data, size_t datasize, ...) { 62 | if (process == null || data == null) { 63 | adbg_oops(AdbgError.invalidArgument); 64 | return null; 65 | } 66 | if (datasize == 0) { 67 | adbg_oops(AdbgError.scannerDataEmpty); 68 | return null; 69 | } 70 | if (datasize > ulong.sizeof) { 71 | adbg_oops(AdbgError.scannerDataLimit); 72 | return null; 73 | } 74 | 75 | enum { 76 | OPTION_UNALIGNED = 1, 77 | OPTION_ALLMODULES = 2, 78 | } 79 | 80 | // TODO: Consider separating options for scanner. 81 | // Useful if we want to rescan with different options. 82 | // Get options 83 | va_list list = void; 84 | va_start(list, datasize); 85 | int options; 86 | Loption: 87 | switch (va_arg!int(list)) { 88 | case 0: break; 89 | case AdbgScanOption.unaligned: 90 | if (va_arg!int(list)) options |= OPTION_UNALIGNED; 91 | goto Loption; 92 | case AdbgScanOption.allModules: 93 | if (va_arg!int(list)) options |= OPTION_ALLMODULES; 94 | goto Loption; 95 | default: 96 | adbg_oops(AdbgError.invalidOption); 97 | return null; 98 | } 99 | 100 | // Allocate enough for struct instance 101 | adbg_scanner_t *scanner = cast(adbg_scanner_t*)calloc(1, adbg_scanner_t.sizeof); 102 | if (scanner == null) { 103 | adbg_oops(AdbgError.crt); 104 | return null; 105 | } 106 | 107 | // Get memory mapping for process 108 | void *pmaps = adbg_memory_mapping(process, 109 | AdbgMappingOption.allModules, options & OPTION_ALLMODULES, 110 | 0); 111 | if (pmaps == null) { // error already set 112 | free(scanner); 113 | return null; 114 | } 115 | 116 | // Setup 117 | scanner.results = adbg_list_new(adbg_scanner_result_t.sizeof, 128); 118 | if (scanner.results == null) { // error set 119 | free(scanner); 120 | return null; 121 | } 122 | scanner.process = process; 123 | 124 | // Buffer for reading from process memory 125 | void *mbuffer = malloc(datasize); 126 | if (mbuffer == null) { 127 | adbg_oops(AdbgError.crt); 128 | adbg_list_close(scanner.results); 129 | free(scanner); 130 | return null; 131 | } 132 | scanner.datasize = datasize; 133 | scanner.options = options; 134 | 135 | // TODO: Consider reading a page's worth instead of datasize 136 | // TODO: Consider performing aligned reads (LP32=4,LP64=8) 137 | // New scan: Scan per memory region 138 | size_t al = options & OPTION_UNALIGNED ? 1 : datasize; /// alignment 139 | adbg_memory_map_t *map = void; 140 | Lmap: for (size_t i; (map = adbg_memory_mapping_at(pmaps, i)) != null; ++i) { 141 | size_t mbase = cast(size_t)map.base; 142 | size_t msize = map.size; 143 | 144 | // while input fits memory range 145 | for (size_t pos = mbase; pos + datasize < mbase + msize; pos += al) { 146 | // can't read? move to next range 147 | if (adbg_memory_read(process, pos, mbuffer, datasize)) 148 | continue Lmap; 149 | 150 | // data different than input? jump to next alignment 151 | if (memcmp(mbuffer, data, datasize)) 152 | continue; 153 | 154 | // add result 155 | adbg_scanner_result_t result = void; 156 | result.address = pos; 157 | memcpy(&result.u64, mbuffer, datasize); 158 | with(scanner) results = adbg_list_add(results, &result); 159 | if (scanner.results == null) { 160 | adbg_scanner_close(scanner); 161 | return null; 162 | } 163 | } 164 | } 165 | 166 | return scanner; 167 | } 168 | 169 | // rescan/update entries by scanning results and removing entries that 170 | // do not match the previous value 171 | /// Perform a rescan using the same, or different, search data (needle). 172 | /// 173 | /// Entries are automatically removed if they do not match the provided 174 | /// search data. 175 | /// Params: 176 | /// scanner = Scanner instance. 177 | /// data = Search data (needle). 178 | /// Returns: Error code. 179 | int adbg_scanner_rescan(adbg_scanner_t *scanner, void* data) { 180 | if (scanner == null || data == null) 181 | return adbg_oops(AdbgError.invalidArgument); 182 | if (scanner.results == null || scanner.process == null || scanner.datasize == 0) 183 | return adbg_oops(AdbgError.uninitiated); 184 | 185 | size_t count = adbg_scanner_result_count(scanner); 186 | if (count == 0) 187 | return 0; 188 | 189 | //adbg_memory_mapping_close(scanner.pmaps); 190 | //scanner.pmaps = adbg_memory_mapping(scanner.process, 191 | 192 | // Buffer for reading from process memory 193 | void *mbuffer = malloc(scanner.datasize); 194 | if (mbuffer == null) { 195 | adbg_list_close(scanner.results); 196 | free(scanner); 197 | return adbg_oops(AdbgError.crt); 198 | } 199 | 200 | size_t i = count; 201 | do { 202 | adbg_scanner_result_t *result = adbg_scanner_result(scanner, --i); 203 | 204 | // unreadable, remove 205 | if (adbg_memory_read(scanner.process, cast(size_t)result.address, mbuffer, scanner.datasize)) { 206 | adbg_list_remove_at(scanner.results, i); 207 | continue; 208 | } 209 | 210 | // value changed, remove 211 | if (memcpy(mbuffer, data, scanner.datasize)) { 212 | adbg_list_remove_at(scanner.results, i); 213 | continue; 214 | } 215 | } while (i > 0); 216 | 217 | return 0; 218 | } 219 | 220 | size_t adbg_scanner_result_count(adbg_scanner_t *scanner) { 221 | if (scanner == null) 222 | return 0; 223 | return adbg_list_count(scanner.results); 224 | } 225 | 226 | // get address for result 227 | adbg_scanner_result_t* adbg_scanner_result(adbg_scanner_t *scanner, size_t index) { 228 | if (scanner == null) { 229 | adbg_oops(AdbgError.invalidArgument); 230 | return null; 231 | } 232 | return cast(adbg_scanner_result_t*)adbg_list_get(scanner.results, index); 233 | } 234 | 235 | // get memory map for result 236 | version (none) 237 | adbg_memory_map_t* adbg_scanner_result_map(adbg_scanner_t *scanner, size_t index) { 238 | if (scanner == null) { 239 | adbg_oops(AdbgError.invalidArgument); 240 | return null; 241 | } 242 | return adbg_memory_mapping_at(scanner.pmaps, index); 243 | } 244 | 245 | void adbg_scanner_close(adbg_scanner_t *scanner) { 246 | if (scanner == null) return; 247 | adbg_list_close(scanner.results); 248 | free(scanner); 249 | } 250 | -------------------------------------------------------------------------------- /src/adbg/system.d: -------------------------------------------------------------------------------- 1 | /// System interface. 2 | /// 3 | /// So far contains a dynamic library loader. 4 | /// Authors: dd86k 5 | /// Copyright: © dd86k 6 | /// License: BSD-3-Clause-Clear 7 | module adbg.system; 8 | 9 | version (Windows) { 10 | import core.sys.windows.winbase; // LoadLibraryA, FreeLibrary, GetLastError 11 | } else version (Posix) { 12 | import core.sys.posix.dlfcn; // dlopen, dlclose, dlsym, dladdr, dlinfo, dlerror 13 | } 14 | 15 | import adbg.symbols; 16 | import adbg.error; 17 | import core.stdc.stdlib : calloc, free; 18 | import core.stdc.string : strncpy; 19 | 20 | // NOTE: Calling dlerror(3) clears the last error 21 | 22 | //TODO: Consider versioning support 23 | // Some libraries, like Capstone, can be found in various versions 24 | // depending on the distrobution. 25 | // Can try loading version-attached shared libraries and fallback to a default 26 | // where maybe a callback can be checked against for a specific major version? 27 | //TODO: Format requested symbol into new structure buffer. 28 | // Should be same size of missing symbols' entry buffer. 29 | 30 | extern (C): 31 | 32 | // 33 | // Dynamic library loader. 34 | // 35 | // Shared libraries are often known as Dynamic-Link Library (DLL) on Windows 36 | // and Shared Objects (SO) on POSIX platforms. 37 | // 38 | // This is an enhancement made to fix some annoying BindBC issues. 39 | // The structure is kept under 4 KiB per instance with static buffers. 40 | // 41 | // Issue 1: Assertion usage. 42 | // On error, debug builds stop the whole program on an assertion performed 43 | // against user data. Unoptimal for optional features. 44 | // 45 | // Issue 2: Error handling. 46 | // On error, errorCount or SharedLib both need to be checked. Creates pitfalls. 47 | // This also allocates memory using malloc which is never freed. 48 | // 49 | 50 | private enum SYMBOL_BUFSIZE = 128; 51 | private enum SYMBOL_BUFCOUNT = 10; 52 | 53 | struct adbg_system_library_t { 54 | void *handle; 55 | 56 | size_t missingcnt; 57 | union { 58 | char[SYMBOL_BUFSIZE][SYMBOL_BUFCOUNT] missing; 59 | } 60 | } 61 | 62 | /// Load a shared library into memory using OS functions. 63 | /// 64 | /// The list is tried in the given order. Returns on the first library loaded. 65 | /// Params: libraries = List of dynamic system libraries to try loading. 66 | /// Returns: Loaded library, or null on error. 67 | adbg_system_library_t* adbg_system_library_load(const(char)*[] libraries...) { 68 | if (libraries.length == 0) { 69 | adbg_oops(AdbgError.emptyArgument); 70 | return null; 71 | } 72 | 73 | // Allocate necessary and clear all fields 74 | adbg_system_library_t *lib = cast(adbg_system_library_t*) 75 | calloc(1, adbg_system_library_t.sizeof); 76 | if (lib == null) { 77 | adbg_oops(AdbgError.crt); 78 | return null; 79 | } 80 | 81 | // Try to load libraries. 82 | // First one to successfully load is returned 83 | foreach (libname; libraries) { 84 | version (Windows) 85 | lib.handle = LoadLibraryA(libname); 86 | else version (Posix) 87 | lib.handle = dlopen(libname, RTLD_LAZY); 88 | else 89 | static assert(0, "Implement adbg_os_dynload"); 90 | 91 | if (lib.handle) 92 | return lib; 93 | } 94 | 95 | // No libraries could be loaded 96 | free(lib); 97 | adbg_oops(AdbgError.systemLoadError); 98 | return null; 99 | } 100 | 101 | /// Bind a symbol from the shared library. 102 | /// Params: 103 | /// lib = Shared library instance. 104 | /// proc = Function pointer instance. 105 | /// symbol = Name of the function to bind. 106 | /// mangling = Symbol mangling (TODO). 107 | /// Returns: Error code. 108 | int adbg_system_library_bind(adbg_system_library_t *lib, void** proc, const(char) *symbol, 109 | AdbgSymbolMangling mangling = AdbgSymbolMangling.exact) { 110 | if (lib == null || lib.handle == null || proc == null) 111 | return adbg_oops(AdbgError.invalidArgument); 112 | 113 | *proc = null; 114 | version (Windows) { 115 | *proc = GetProcAddress(lib.handle, symbol); 116 | } else version (Posix) { 117 | *proc = dlsym(lib.handle, symbol); 118 | } 119 | if (*proc == null) { 120 | // Add symbol to count of missed symbols. 121 | adbg_system_library_addmissing(lib, symbol); 122 | return adbg_oops(AdbgError.systemBindError); 123 | } 124 | 125 | return 0; 126 | } 127 | private 128 | void adbg_system_library_addmissing(adbg_system_library_t *lib, const(char) *symbol) { 129 | // Check if we can fit more into the buffer. 130 | if (lib.missingcnt >= SYMBOL_BUFCOUNT) 131 | return; 132 | 133 | strncpy(cast(char*)&lib.missing[lib.missingcnt++], symbol, SYMBOL_BUFSIZE); 134 | } 135 | 136 | /// Returns the missing symbol count. 137 | /// Params: lib = Library instance. 138 | /// Returns: Missed symbol count. 139 | size_t adbg_system_library_missingcnt(adbg_system_library_t *lib) { 140 | if (lib == null) return 0; 141 | return lib.missingcnt; 142 | } 143 | /// Get missing symbol name by index. 144 | /// Params: 145 | /// lib = Library instance. 146 | /// index = Index. 147 | /// Returns: Missing symbol. 148 | const(char)* adbg_system_library_missing(adbg_system_library_t *lib, size_t index) { 149 | if (lib == null || index >= lib.missingcnt) return null; 150 | return cast(const(char)*)&lib.missing[index]; 151 | } 152 | extern (D) unittest { 153 | adbg_system_library_t lib; 154 | adbg_system_library_addmissing(&lib, "test"); 155 | adbg_system_library_addmissing(&lib, "some_long_name_that_should_fit_the_buffer_anyway"); 156 | 157 | assert(adbg_system_library_missing(&lib, 0)); 158 | assert(adbg_system_library_missing(&lib, 1)); 159 | assert(adbg_system_library_missing(&lib, 2) == null); 160 | assert(adbg_system_library_missing(null, 2) == null); 161 | } 162 | 163 | void adbg_system_library_close(adbg_system_library_t *lib) { 164 | if (lib == null) return; 165 | 166 | if (lib.handle) { 167 | version (Windows) 168 | FreeLibrary(lib.handle); 169 | else version (Posix) 170 | dlclose(lib.handle); 171 | else 172 | static assert(0, "Implement adbg_os_dynunload"); 173 | lib.handle = null; 174 | } 175 | 176 | free(lib); 177 | } -------------------------------------------------------------------------------- /src/adbg/utils/date.d: -------------------------------------------------------------------------------- 1 | /// Minimal date utility. 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module adbg.utils.date; 7 | 8 | extern (C): 9 | 10 | /// Convert a 32-bit time_t into a datetime string formatted as "Www Mmm dd hh:mm:ss yyyy". 11 | /// 12 | /// This was created because the Microsoft's Visual C Runtime (msvcrt v130) crashed 13 | /// on strftime with a value higher than 0x8000000 with 0xC0000409 14 | /// (STATUS_STACK_BUFFER_OVERRUN). Mostly used for PE32's TimeDateStamp field. 15 | /// 16 | /// Params: timestamp = Timestamp. 17 | /// Returns: Formatted string 18 | /// Note: Doesn't check for leak year. 19 | const(char)* ctime32(uint timestamp) { 20 | // NOTE: Notable values 21 | // windbg x64: 0xB8A65683 (2068-03-02, crashing) 22 | // windbg x86: 0x2F269970 (1995-01-25) 23 | // putty x64: 0x5D873EBE (Sun Sep 22 15:28:30 2019) 24 | // NOTE: PeInternals is also affected by the weird dates in x86 windbg builds 25 | import adbg.include.c.stdio : snprintf; 26 | 27 | enum S_YEAR = 31557600; 28 | enum S_MONTH = 2629800; 29 | enum S_DAY = 86400; 30 | enum S_HOUR = 3600; 31 | enum S_MINUTE = 60; 32 | enum BSZ = 32; // Typically 24 chars, but 32 is safer with alignment 33 | enum BASE_YEAR = 1970; 34 | enum BASE_DOW = 3; // Thursday, starts with Monday 35 | 36 | __gshared char[BSZ] _buffer; 37 | __gshared const(char)*[] DOW = [ // Day of Week 38 | "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", 39 | ]; 40 | __gshared const(char)*[] MON = [ // Month 41 | "Jan", "Feb", "Mar", "Apr", 42 | "May", "Jun", "Jul", "Aug", 43 | "Sep", "Oct", "Nov", "Dec", 44 | ]; 45 | __gshared const(char)* error_s = "(error)"; 46 | 47 | // day of the week 48 | int dow = ((timestamp / S_DAY) + BASE_DOW) % 7; 49 | if (dow < 0) dow += 7; 50 | const(char) *dow_s = dow > 7 ? error_s : DOW[dow]; 51 | 52 | // year 53 | int year = timestamp / S_YEAR; 54 | timestamp -= year * S_YEAR; 55 | year += BASE_YEAR; 56 | 57 | // month 58 | int month = timestamp / S_MONTH; 59 | timestamp -= month * S_MONTH; 60 | month += 1; 61 | 62 | // days 63 | int day = timestamp / S_DAY; 64 | timestamp -= day * S_DAY; 65 | day += month & 1 ? 2 : 1; 66 | 67 | // hours 68 | int hours = timestamp / S_HOUR; 69 | timestamp -= hours * S_HOUR; 70 | 71 | // minutes 72 | int mins = timestamp / S_MINUTE; 73 | timestamp -= mins * S_MINUTE; 74 | 75 | // seconds 76 | int secs = timestamp; 77 | 78 | // month name 79 | const(char) *mon_s = 80 | month < 1 || month > 12 ? error_s : MON[month - 1]; 81 | 82 | // WeekDay Month day hour:minutes:seconds year 83 | return snprintf(cast(char*)_buffer, BSZ, 84 | "%s %s %2d %2d:%02d:%02d %d", 85 | dow_s, mon_s, day, hours, mins, secs, year) < 0 ? 86 | error_s : cast(char*)_buffer; 87 | } -------------------------------------------------------------------------------- /src/adbg/utils/math.d: -------------------------------------------------------------------------------- 1 | /// Math utilities. 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module adbg.utils.math; 7 | 8 | /// Choose the highest number. 9 | /// Params: 10 | /// a = Number 1. 11 | /// b = Number 2. 12 | template MAX(size_t a, size_t b) { 13 | enum MAX = a >= b ? a : b; 14 | } 15 | /// Choose the lowest number. 16 | /// Params: 17 | /// a = Number 1. 18 | /// b = Number 2. 19 | template MIN(size_t a, size_t b) { 20 | enum MIN = a <= b ? a : b; 21 | } 22 | extern (D) unittest { 23 | static assert(MAX!(1, 2) == 2); 24 | static assert(MAX!(2, 2) == 2); 25 | static assert(MIN!(1, 2) == 1); 26 | static assert(MIN!(1, 1) == 1); 27 | } 28 | 29 | /// Select the highest number between two choices. 30 | /// Params: 31 | /// a = Choice 1. 32 | /// b = Choice 2. 33 | /// Returns: The highest value. 34 | size_t max(size_t a, size_t b) { 35 | return a >= b ? a : b; 36 | } 37 | extern (D) unittest { 38 | assert(max(1, 3) == 3); 39 | assert(max(2, 3) == 3); 40 | assert(max(3, 3) == 3); 41 | assert(max(4, 3) == 4); 42 | } 43 | 44 | /// Select the lowest number between two choices. 45 | /// Params: 46 | /// a = Choice 1. 47 | /// b = Choice 2. 48 | /// Returns: The lowest value. 49 | size_t min(size_t a, size_t b) { 50 | return a <= b ? a : b; 51 | } 52 | extern (D) unittest { 53 | assert(min(1, 3) == 1); 54 | assert(min(2, 3) == 2); 55 | assert(min(3, 3) == 3); 56 | assert(min(4, 3) == 3); 57 | } 58 | 59 | /// Make a constant binary size (base 1024^3). 60 | /// Params: a = Base size. 61 | template GiB(int a) { 62 | enum ulong GiB = a * 1024L * 1024L * 1024L; 63 | } 64 | /// Make a constant binary size (base 1024^2). 65 | /// Params: a = Base size. 66 | template MiB(int a) { 67 | enum ulong MiB = a * 1024L * 1024L; 68 | } 69 | /// Make a constant binary size (base 1024^1). 70 | /// Params: a = Base size. 71 | template KiB(int a) { 72 | enum ulong KiB = a * 1024L; 73 | } 74 | 75 | extern (D) unittest { 76 | static assert(KiB!1 == 1024); 77 | static assert(KiB!2 == 1024 * 2); 78 | static assert(MiB!1 == 1024 * 1024); 79 | static assert(MiB!3 == 1024 * 1024 * 3); 80 | static assert(GiB!1 == 1024 * 1024 * 1024); 81 | static assert(GiB!4 == 1024L * 1024 * 1024 * 4); 82 | } 83 | 84 | /// Perform a division and round the result upwards. 85 | /// 86 | /// Initially created for PDB to get the number of blocks from a stream size and blocksize. 87 | /// Params: 88 | /// a = Numerator. 89 | /// b = Denominator. 90 | /// Returns: Result. 91 | uint ceildiv32(uint a, uint b) pure { 92 | return (a + b + 1) / b; 93 | } 94 | extern (D) unittest { 95 | assert(ceildiv32(0, 512) == 1); 96 | assert(ceildiv32(50, 512) == 1); 97 | assert(ceildiv32(512, 512) == 2); 98 | assert(ceildiv32(768, 512) == 2); 99 | assert(ceildiv32(1024, 512) == 3); 100 | } -------------------------------------------------------------------------------- /src/adbg/utils/uid.d: -------------------------------------------------------------------------------- 1 | /// Mostly internal module that deals with GUIDs and UUIDs. 2 | /// 3 | /// Authors: dd86k 4 | /// Copyright: © dd86k 5 | /// License: BSD-3-Clause-Clear 6 | module adbg.utils.uid; 7 | 8 | import adbg.include.c.stdio; 9 | import adbg.utils.bit; 10 | 11 | extern (C): 12 | 13 | enum { 14 | UID_GUID = 0, /// Global UID (little-endian, ala Microsoft) 15 | UID_UUID = 1, /// Universal UID (big-endian) 16 | UID_TEXTLEN = 36, /// Text buffer length 17 | } 18 | 19 | /// UUID/GUID structure 20 | union UID { 21 | this (ubyte p0, ubyte p1, ubyte p2, ubyte p3, 22 | ubyte p4, ubyte p5, ubyte p6, ubyte p7, 23 | ubyte p8, ubyte p9, ubyte p10, ubyte p11, 24 | ubyte p12, ubyte p13, ubyte p14, ubyte p15) { 25 | data[0] = p0; 26 | data[1] = p1; 27 | data[2] = p2; 28 | data[3] = p3; 29 | data[4] = p4; 30 | data[5] = p5; 31 | data[6] = p6; 32 | data[7] = p7; 33 | data[8] = p8; 34 | data[9] = p9; 35 | data[10] = p10; 36 | data[11] = p11; 37 | data[12] = p12; 38 | data[13] = p13; 39 | data[14] = p14; 40 | data[15] = p15; 41 | } 42 | ubyte[16] data; 43 | ushort[8] u16; 44 | uint[4] u32; 45 | ulong[2] u64; // Preferred to use when size width = 64 46 | struct { 47 | uint time_low; 48 | ushort time_mid; 49 | ushort time_ver; // and time_hi 50 | ushort clock; // seq_hi and res_clock_low 51 | ubyte[6] node; 52 | } 53 | } 54 | 55 | /// Format the UID into a text buffer. 56 | /// 57 | /// If the target endianness does not match the compile target, this function 58 | /// will automatically performs a swap. This function does not terminate the string. 59 | /// Params: 60 | /// uid = UID structure. 61 | /// buffer = Text buffer of UID_TEXTLEN in size. 62 | /// target = UID_GUID or UID_UUID. 63 | /// Returns: Whatever snprintf returns 64 | int uid_text(ref UID uid, ref char[UID_TEXTLEN] buffer, int target) { 65 | return uid_string(uid, buffer.ptr, UID_TEXTLEN, target); 66 | } 67 | 68 | /// Format the UID into a text buffer. 69 | /// 70 | /// If the target endianness does not match the compile target, this function 71 | /// will automatically performs a swap. This function does not terminate the string. 72 | /// Params: 73 | /// uid = UID structure. 74 | /// buf = Text buffer. 75 | /// buflen = Text buffer length. 76 | /// target = UID_GUID or UID_UUID. 77 | /// Returns: Whatever snprintf returns 78 | int uid_string(ref UID uid, char *buf, size_t buflen, int target) { 79 | version (LittleEndian) { 80 | if (target == UID_UUID) uid_swap(uid); 81 | } else { 82 | if (target == UID_GUID) uid_swap(uid); 83 | } 84 | return snprintf(buf, buflen, 85 | "%08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X", 86 | uid.time_low, uid.time_mid, uid.time_ver, uid.clock, 87 | uid.data[10], uid.data[11], uid.data[12], 88 | uid.data[13], uid.data[14], uid.data[15]); 89 | } 90 | 91 | /// Swap endianness of a UID. GUID (LSB) becomes UUID (MSB) and vice-versa. 92 | /// Params: uid = UID structure 93 | void uid_swap(ref UID uid) { 94 | uid.time_low = adbg_bswap32(uid.time_low); 95 | uid.time_mid = adbg_bswap16(uid.time_mid); 96 | uid.time_ver = adbg_bswap16(uid.time_ver); 97 | uid.clock = adbg_bswap16(uid.clock); 98 | } 99 | extern (D) unittest { 100 | UID uid; 101 | uid.time_low = 0x01_000000; 102 | uid.time_mid = 0x02_00; 103 | uid.time_ver = 0x03_00; 104 | uid.clock = 0x04_00; 105 | uid_swap(uid); 106 | assert(uid.time_low == 1); 107 | assert(uid.time_mid == 2); 108 | assert(uid.time_ver == 3); 109 | assert(uid.clock == 4); 110 | } 111 | 112 | /// Return zero if UID is NIL. 113 | /// Params: uid = UID structure 114 | /// Returns: Non-zero if non-empty. 115 | bool uid_nil(ref UID uid) { 116 | return uid.u64[0] == 0 && uid.u64[1] == 0; 117 | } 118 | extern (D) unittest { 119 | UID uid; 120 | assert(uid_nil(uid)); 121 | } -------------------------------------------------------------------------------- /tests/readkey.d: -------------------------------------------------------------------------------- 1 | module tests.readkey; 2 | 3 | import term; 4 | import core.stdc.stdio; 5 | 6 | unittest { 7 | coninit(); 8 | InputInfo input = void; 9 | puts("Press ^C to quit"); 10 | puts("Reading keys..."); 11 | loop: 12 | conrdkey(&input); 13 | switch (input.type) { 14 | case InputType.Key: 15 | with (input.key) 16 | printf("key: v=%3d:%3d k=%3d ctrl=%d shift=%d alt=%d\n", 17 | keyCode, keyChar, keyCode, ctrl, shift, alt); 18 | break; 19 | case InputType.Mouse: 20 | puts("mouse"); 21 | break; 22 | case InputType.None: 23 | puts("none"); 24 | break; 25 | default: 26 | puts("unknown"); 27 | } 28 | goto loop; 29 | } -------------------------------------------------------------------------------- /tests/readln.d: -------------------------------------------------------------------------------- 1 | module tests.readln; 2 | 3 | import core.stdc.stdio; 4 | import core.stdc.ctype : isprint; 5 | import term; 6 | 7 | extern (C) int putchar(int); 8 | 9 | unittest { 10 | while (true) { 11 | printf("prompt: "); 12 | char[] input = conrdln(); 13 | foreach (char c; input) 14 | if (isprint(c)) 15 | putchar(c); 16 | else 17 | printf("\\x%02x", c); 18 | putchar('\n'); 19 | printf("buffer had %d characters\n", cast(int)input.length); 20 | } 21 | } -------------------------------------------------------------------------------- /tests/setjmp.d: -------------------------------------------------------------------------------- 1 | module tests.sys.setjmp; 2 | 3 | import adbg.include.c.setjmp; 4 | 5 | /// 6 | unittest { 7 | jmp_buf j = void; 8 | int e = setjmp(j); 9 | if (e) { 10 | assert(e == 0xdd, "e != 0xdd"); 11 | } else { 12 | longjmp(j, 0xdd); 13 | assert(0, "longjmp"); 14 | } 15 | } --------------------------------------------------------------------------------