/// Command line interface. /// /// Authors: dd86k <dd@dax.moe> /// Copyright: © dd86k <dd@dax.moe> /// License: BSD-3-Clause-Clear module main; import adbg.platform; import adbg.include.c.stdlib : exit; import adbg.include.d.config : GDC_VERSION, GDC_EXCEPTION_MODE, LLVM_VERSION; import adbg.debugger.exception : adbg_exception_t, adbg_exception_name; import adbg.self; import adbg.machines : adbg_machine_default; import adbg.disassembler; import adbg.error; import adbg.debugger.process; import core.stdc.stdlib : strtol, EXIT_SUCCESS, EXIT_FAILURE; import core.stdc.string : strcmp; import core.stdc.stdio; import debugger, shell; import common.cli; import common.utils : unformat64; private: immutable option_t[] options = [ // secrets cast(immutable)option_t(0, "meow", "Meow and exit", &cli_meow), // common options cast(immutable)option_arch, cast(immutable)option_syntax, // debugger options cast(immutable)option_t(0, "file", "Debugger: Spawn FILE for debugging", &cli_file), cast(immutable)option_t(0, "args", "Debugger: Supply arguments to executable", &cli_args), // option_t('E', "env", "Debugger: Supply environment variables to executable", &cli_env), cast(immutable)option_t('p', "attach", "Debugger: Attach to Process ID", &cli_pid), // pages cast(immutable)option_t('h', "help", "Show this help screen and exit", &cli_help), cast(immutable)option_version, cast(immutable)option_build_info, cast(immutable)option_ver, cast(immutable)option_license, ]; enum NUMBER_OF_SECRETS = 1; // // ANCHOR --file // int cli_file(const(char) *val) { opt_file = val; return EXIT_SUCCESS; } // // ANCHOR --args/-- // int cli_args_stop(int argi, int argc, const(char) **argv) { // -- import adbg.utils.strings : adbg_util_move; //TODO: Allocate pointer buffer instead using calloc enum MAX = 16; __gshared const(char) *[MAX] args; opt_file_argv = cast(const(char)**)args; int left = argc - argi; /// to move void **s = cast(void**)(argv+argi); int m = adbg_util_move( cast(void**)&opt_file_argv, MAX, cast(void**)&s, left); debug assert(m == left, "cli_argsdd: 'adbg_util_move' Failed due to small buffer"); return EXIT_SUCCESS; } int cli_args(const(char) *val) { // --args import adbg.utils.strings : adbg_util_expand; int argc = void; char **argv = adbg_util_expand(val, &argc); if (argc == 0) return EXIT_FAILURE; opt_file_argv = cast(const(char)**)argv; return EXIT_SUCCESS; } // // ANCHOR -E, --env // /*int cli_env(const(char) *val) { import adbg.utils.strings : adbg_util_env; globals.env = cast(const(char)**)adbg_util_env(val); if (globals.env == null) { printf("main: Parsing environment failed"); return EXIT_FAILURE; } return EXIT_SUCCESS; }*/ // // ANCHOR --attach // int cli_pid(const(char) *val) { opt_pid = cast(ushort)strtol(val, null, 10); return EXIT_SUCCESS; } // // ANCHOR --help // int cli_help() { puts( "alicedbg: Aiming to be a simple debugger.\n"~ "\n"~ "USAGE\n"~ " Spawn new process to debug:\n"~ " alicedbg FILE [OPTIONS...]\n"~ " Attach debugger to existing process:\n"~ " alicedbg --attach PID [OPTIONS...]\n"~ " Show information page and exit:\n"~ " alicedbg {-h|--help|--version|--ver|--license}\n"~ "\n"~ "OPTIONS" ); getoptprinter(options, NUMBER_OF_SECRETS); puts("\nFor a list of values, for example a list of platforms, type '-m help'"); exit(0); return 0; } // --meow: Secret int cli_meow() { puts( ` +-------------------+ | I hate x86, meow. | +--. .--------------+ \| A_A (-.-) / \ _ / \__/ \_||__/ ` ); exit(0); return 0; } extern (C) void crash_handler(adbg_exception_t *ex) { scope(exit) exit(ex.oscode); adbg_process_t *self = adbg_self_process(); puts( r" _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_|_|_| |_|_|_|_ _|_|_|_ _|_|_|_| |_| |_| |_| |_| |_|_ _|_| |_|_ _|_| |_|_ _ |_|_ _|_| |_| |_| |_|_|_|_ |_|_|_|_| |_|_|_ |_|_|_|_| |_| |_|_ _ _ |_| |_| |_| |_| _ _ _|_| |_| |_| _ |_|_|_| |_| |_| |_| |_| |_|_|_| |_| |_| |_| " ); printf( "Exception : %s\n"~ "PID : %d\n", adbg_exception_name(ex), cast(int)self.pid); // casting is temp // Fault address & disasm if available if (ex.faultz) { printf("Address : %#zx\n", ex.faultz); adbg_opcode_t op = void; adbg_disassembler_t *dis = adbg_dis_open(adbg_machine_default()); printf("Instruction:"); if (dis && adbg_dis_process_once(dis, &op, self, ex.fault_address) == 0) { // Print address // Print machine bytes for (size_t bi; bi < op.size; ++bi) printf(" %02x", op.machine[bi]); // printf(" (%s", op.mnemonic); if (op.operands) printf(" %s", op.operands); // puts(")"); } else { printf(" Disassembly unavailable (%s)\n", adbg_error_msg()); } } } extern (C) int main(int argc, const(char)** argv) { // Set crash handle, and ignore on error // Could do a warning, but it might be a little confusing adbg_self_set_crashhandler(&crash_handler); int e = getopt(argc, argv, options); if (e < 0) { puts(getopterr()); return EXIT_FAILURE; } /*if (e >= 1) { opt_file = argv[0]; }*/ return shell_loop(); }