├── .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 | }
--------------------------------------------------------------------------------