From d8d4bb37a9428173bcd97687fe7d7c546e2118a1 Mon Sep 17 00:00:00 2001 From: dd86k Date: Fri, 8 Mar 2024 14:03:19 -0500 Subject: [PATCH] New Disassembler API --- app/common.d | 8 +-- app/dumper.d | 18 +++--- app/shell.d | 63 +++++++++------------ examples/simple.d | 36 ++++++------ src/adbg/disassembler.d | 118 +++++++++++++++++++--------------------- 5 files changed, 109 insertions(+), 134 deletions(-) diff --git a/app/common.d b/app/common.d index 03e6ed5f..859d27d1 100644 --- a/app/common.d +++ b/app/common.d @@ -51,12 +51,12 @@ immutable setting_platform_t[] platforms = [ // Syntaxes struct setting_syntax_t { - AdbgDasmSyntax val; + AdbgDisSyntax val; const(char)* opt, desc; } immutable setting_syntax_t[] syntaxes = [ - { AdbgDasmSyntax.att, "att", "AT&T syntax" }, - { AdbgDasmSyntax.intel, "intel", "Intel syntax" }, + { AdbgDisSyntax.att, "att", "AT&T syntax" }, + { AdbgDisSyntax.intel, "intel", "Intel syntax" }, ]; // @@ -84,7 +84,7 @@ struct settings_t { int dump_options; /// Dumper options long dump_base_address; /// Dumper base address (org) AdbgMachine machine; /// Disassembler: Target machine - AdbgDasmSyntax syntax; /// Disassembler: Syntax + AdbgDisSyntax syntax; /// Disassembler: Syntax } /// Global variables. Helps keeping track of app variables. diff --git a/app/dumper.d b/app/dumper.d index fe2b227b..982dda35 100644 --- a/app/dumper.d +++ b/app/dumper.d @@ -416,20 +416,16 @@ int dump_disassemble_object(ref Dumper dump, adbg_object_t *o, int dump_disassemble(ref Dumper dump, AdbgMachine machine, void* data, ulong size, ulong base_address) { - adbg_disassembler_t *dasm = cast(adbg_disassembler_t*)malloc(adbg_disassembler_t.sizeof); - if (dasm == null) - quitext(ErrSource.crt); - scope(exit) free(dasm); - - if (adbg_dasm_open(dasm, machine)) + adbg_disassembler_t *dis = adbg_dis_open(machine); + if (dis == null) quitext(ErrSource.adbg); - scope(exit) adbg_dasm_close(dasm); + scope(exit) adbg_dis_close(dis); if (globals.syntax) - adbg_dasm_options(dasm, AdbgDasmOption.syntax, globals.syntax, 0); + adbg_dis_options(dis, AdbgDisOpt.syntax, globals.syntax, 0); adbg_opcode_t op = void; - adbg_dasm_start(dasm, data, cast(size_t)size, base_address); + adbg_dis_start(dis, data, cast(size_t)size, base_address); // stats mode if (dump.selected_disasm_stats()) { @@ -439,7 +435,7 @@ int dump_disassemble(ref Dumper dump, AdbgMachine machine, uint stat_total; /// total instruction count uint stat_illegal; /// Number of illegal instructions L_STAT: - switch (adbg_dasm(dasm, &op)) with (AdbgError) { + switch (adbg_dis_step(dis, &op)) with (AdbgError) { case success: stat_avg += op.size; ++stat_total; @@ -467,7 +463,7 @@ L_STAT: // normal disasm mode L_DISASM: - switch (adbg_dasm(dasm, &op)) with (AdbgError) { + switch (adbg_dis_step(dis, &op)) with (AdbgError) { case success: print_disasm_line(&op); goto L_DISASM; diff --git a/app/shell.d b/app/shell.d index 52fa4c73..49e0611f 100644 --- a/app/shell.d +++ b/app/shell.d @@ -110,14 +110,14 @@ int shell_loop() { } if (globals.file || globals.pid) { - if (adbg_dasm_open(&dasm, adbg_process_get_machine(process))) { - dasm_available = false; + dis = adbg_dis_open(adbg_process_get_machine(process)); + if (dis == null) { printf("warning: Disassembler not available (%s)\n", adbg_error_msg()); - } else dasm_available = true; + } - if (globals.syntax && dasm_available) - adbg_dasm_options(&dasm, AdbgDasmOption.syntax, globals.syntax, 0); + if (globals.syntax && dis) + adbg_dis_options(dis, AdbgDisOpt.syntax, globals.syntax, 0); } coninit(); @@ -163,12 +163,8 @@ int shell_execv(int argc, const(char) **argv) { private: __gshared: -adbg_process_t* process; -//TODO: Make disassembler return instance pointer -adbg_disassembler_t dasm; - -//TODO: Rely on disassembler pointer instead -bool dasm_available; +adbg_process_t *process; +adbg_disassembler_t *dis; void function(const(char)* sev, const(char)* msg) userlog; @@ -497,7 +493,7 @@ immutable(command2_t)* shell_findcommand(const(char) *ucommand) { //TODO: shell_attach void shell_event_disassemble(size_t address, int count = 1, bool showAddress = true) { - if (dasm_available == false) + if (dis == null) return; for (int i; i < count; ++i) { @@ -508,7 +504,7 @@ void shell_event_disassemble(size_t address, int count = 1, bool showAddress = t return; } adbg_opcode_t op = void; - if (adbg_dasm_once(&dasm, &op, data.ptr, RDSZ)) { + if (adbg_dis_once(dis, &op, data.ptr, RDSZ)) { printf("%8llx (error:%s)\n", cast(ulong)address, adbg_error_msg); return; } @@ -655,11 +651,11 @@ int command_spawn(int argc, const(char) **argv) { serror("Could not spawn process."); return ShellError.alicedbg; } - if (adbg_dasm_open(&dasm, adbg_process_get_machine(process))) { - dasm_available = false; + dis = adbg_dis_open(adbg_process_get_machine(process)); + if (dis == null) { printf("warning: Disassembler not available (%s)\n", adbg_error_msg()); - } else dasm_available = true; + } return 0; } @@ -679,11 +675,11 @@ int command_attach(int argc, const(char) **argv) { serror("Could not attach to process."); return ShellError.alicedbg; } - if (adbg_dasm_open(&dasm, adbg_process_get_machine(process))) { - dasm_available = false; + dis = adbg_dis_open(adbg_process_get_machine(process)); + if (dis == null) { printf("warning: Disassembler not available (%s)\n", adbg_error_msg()); - } else dasm_available = true; + } return 0; } @@ -693,8 +689,7 @@ int command_detach(int argc, const(char) **argv) { serror("Could not detach process."); return ShellError.alicedbg; } - if (dasm_available) - adbg_dasm_close(&dasm); + adbg_dis_close(dis); return 0; } @@ -712,13 +707,6 @@ int command_restart(int argc, const(char) **argv) { serror("Could not attach process."); return ShellError.alicedbg; } - if (dasm_available) - adbg_dasm_close(&dasm); - if (adbg_dasm_open(&dasm, adbg_process_get_machine(process))) { - dasm_available = false; - printf("warning: Disassembler not available (%s)\n", - adbg_error_msg()); - } else dasm_available = true; puts("Debugger re-attached"); break; case spawned: @@ -733,13 +721,6 @@ int command_restart(int argc, const(char) **argv) { serror("Could not spawn process."); return ShellError.alicedbg; } - if (dasm_available) - adbg_dasm_close(&dasm); - if (adbg_dasm_open(&dasm, adbg_process_get_machine(process))) { - dasm_available = false; - printf("warning: Disassembler not available (%s)\n", - adbg_error_msg()); - } else dasm_available = true; puts("Process respawned"); break; default: @@ -747,6 +728,13 @@ int command_restart(int argc, const(char) **argv) { return 0; } + adbg_dis_close(dis); + dis = adbg_dis_open(adbg_process_get_machine(process)); + if (dis == null) { + printf("warning: Disassembler not available (%s)\n", + adbg_error_msg()); + } + return 0; } @@ -885,11 +873,10 @@ int command_maps(int argc, const(char) **argv) { //TODO: start,+length start,end syntax int command_disassemble(int argc, const(char) **argv) { - if (dasm_available == false) + if (dis == null) return ShellError.unavailable; - if (argc < 2) { + if (argc < 2) return ShellError.missingOption; - } long uaddress = void; if (unformat64(&uaddress, argv[1])) diff --git a/examples/simple.d b/examples/simple.d index 4ab8475f..f15b5418 100644 --- a/examples/simple.d +++ b/examples/simple.d @@ -7,6 +7,7 @@ module examples.simple; import core.stdc.stdio; import core.stdc.stdlib; +import core.stdc.ctype : isprint; import adbg; extern (C): @@ -19,12 +20,11 @@ int main(int argc, const(char) **argv) { if (process == null) die; - feature_disasm = adbg_dasm_open(&dasm, adbg_process_get_machine(process)) == 0; - if (feature_disasm == false) - printf("warning: Disassembler unavailable (%s)", adbg_error_msg); + dis = adbg_dis_open(adbg_process_get_machine(process)); + if (dis == null) + printf("warning: Disassembler unavailable (%s)\n", adbg_error_msg()); - // Process input -LOOP: +LOOP: // Process input switch (choice("Action [?=Help]")) { case '?': puts( @@ -61,40 +61,36 @@ void die(int code = 0, const(char) *reason = null) { } int choice(const(char) *msg) { - import core.stdc.ctype : isprint; printf("\n%s: ", msg); -INPUT: - int c = getchar; +LINPUT: int c = getchar; if (isprint(c)) return c; - goto INPUT; + goto LINPUT; } __gshared adbg_process_t *process; -__gshared adbg_disassembler_t dasm; -__gshared bool feature_disasm; +__gshared adbg_disassembler_t *dis; void loop_handler(adbg_exception_t *ex) { - __gshared uint ex_num; /// Exception counter printf( "\n----------------------------------------\n"~ - "* EXCEPTION #%u: %s ("~ADBG_OS_ERROR_FORMAT~")\n"~ + "* EXCEPTION ("~ADBG_OS_ERROR_FORMAT~"): %s\n"~ "* PID=%u TID=%u\n"~ - "* FAULT=%8llx ", - ex_num++, adbg_exception_name(ex), ex.oscode, + "* FAULT=%8llx", + ex.oscode, adbg_exception_name(ex), ex.pid, ex.tid, ex.fault_address ); // Print disassembly if available - if (feature_disasm && ex.faultz) { + if (dis && ex.faultz) { adbg_opcode_t op = void; - if (adbg_dasm_process_once(&dasm, &op, process, ex.fault_address)) { - printf(" (error:%s)\n", adbg_error_msg); + if (adbg_dis_process_once(dis, &op, process, ex.fault_address)) { + printf(" (error:%s)\n", adbg_error_msg); return; } if (op.operands) - printf(" (%s %s)\n", op.mnemonic, op.operands); + printf(" (%s %s)\n", op.mnemonic, op.operands); else - printf(" (%s)\n", op.mnemonic); + printf(" (%s)\n", op.mnemonic); } } \ No newline at end of file diff --git a/src/adbg/disassembler.d b/src/adbg/disassembler.d index 255b7354..1398379e 100644 --- a/src/adbg/disassembler.d +++ b/src/adbg/disassembler.d @@ -17,6 +17,7 @@ import adbg.object.machines : AdbgMachine, adbg_object_machine_alias; import adbg.debugger.exception : adbg_exception_t; import adbg.debugger.memory : adbg_memory_read; import core.stdc.string : memcpy; +import core.stdc.stdlib : malloc, free; //TODO: Capstone CS_MODE_BIG_ENDIAN // Depending on target endianness, Capstone may need this bit @@ -60,11 +61,12 @@ version (X86) { // CS_OPT_SYNTAX_DEFAULT static assert(0, "Set DEFAULT_PLATFORM and DEFAULT_SYNTAX"); } -/// Maximum instruction size. +/// Maximum instruction size in bytes. +/// Currently, this title goes to x86. Congrats! enum MAX_INSTR_SIZE = 16; private { - enum ADBG_DASM_MAGIC = 0xcafebabe; + enum ADBG_MAGIC = 0xcafebabe; } extern (C): @@ -122,7 +124,7 @@ struct adbg_opcode_t { } /// Assembler syntax. -enum AdbgDasmSyntax { +enum AdbgDisSyntax { /// Default option for platform. native, /// Intel syntax @@ -153,7 +155,7 @@ enum AdbgDasmSyntax { } /// Disassembler options. -enum AdbgDasmOption { +enum AdbgDisOpt { /// Change syntax. /// Type: int /// Default: AdbgDasmSyntax.native @@ -164,7 +166,7 @@ enum AdbgDasmOption { // Platform to CS' ARCH and MODE types private -int adbg_dasm_lib_a2cs(ref int cs_arch, ref int cs_mode, AdbgMachine platform) { +int adbg_dis_lib_a2cs(ref int cs_arch, ref int cs_mode, AdbgMachine platform) { switch (platform) with (AdbgMachine) { case native: // equals 0 cs_arch = CS_DEFAULT_PLATFORM; @@ -218,57 +220,53 @@ int adbg_dasm_lib_a2cs(ref int cs_arch, ref int cs_mode, AdbgMachine platform) { /// dasm = Reference to disassembler instance. /// machine = Machine architecture. /// Returns: Error code. -int adbg_dasm_open(adbg_disassembler_t *dasm, - AdbgMachine machine = AdbgMachine.native) { +adbg_disassembler_t* adbg_dis_open(AdbgMachine machine = AdbgMachine.native) { //TODO: static if (CAPSTONE_DYNAMIC) if (libcapstone_dynload()) - return adbg_errno; + return null; version (Trace) trace("machine=%u (%s)", machine, adbg_object_machine_alias(machine)); int cs_arch = void, cs_mode = void; - if (adbg_dasm_lib_a2cs(cs_arch, cs_mode, machine)) - return adbg_errno; + if (adbg_dis_lib_a2cs(cs_arch, cs_mode, machine)) + return null; - //TODO: If already opened, close - if (cs_open(cs_arch, cs_mode, &dasm.cs_handle)) - return adbg_oops(AdbgError.libCapstone, &dasm.cs_handle); + adbg_disassembler_t *dasm = cast(adbg_disassembler_t*)malloc(adbg_disassembler_t.sizeof); + if (dasm == null) { + adbg_oops(AdbgError.crt); + return null; + } + + if (cs_open(cs_arch, cs_mode, &dasm.cs_handle)) { + free(dasm); + adbg_oops(AdbgError.libCapstone, &dasm.cs_handle); + return null; + } dasm.cs_inst = cs_malloc(dasm.cs_handle); - if (dasm.cs_inst == null) - return adbg_oops(AdbgError.libCapstone, &dasm.cs_handle); + if (dasm.cs_inst == null) { + free(dasm); + adbg_oops(AdbgError.libCapstone, &dasm.cs_handle); + return null; + } - dasm.decoded_count = - dasm.address_base = - dasm.buffer_size = 0; + dasm.decoded_count = 0; + dasm.address_base = 0; + dasm.buffer_size = 0; dasm.buffer = null; - - dasm.magic = ADBG_DASM_MAGIC; - return 0; -} - -/// Re-open a disassembler instance by closing it and opening it again. -/// Params: -/// dasm = Reference to disassembler instance. -/// machine = Machine architecture. -/// Returns: Error code. -int adbg_dasm_reopen(adbg_disassembler_t *dasm, AdbgMachine machine) { - if (dasm == null) - return adbg_oops(AdbgError.nullArgument); - adbg_dasm_close(dasm); - return adbg_dasm_open(dasm, machine); + dasm.magic = ADBG_MAGIC; + return dasm; } /// Closes a disassembler instance. /// Params: dasm = Reference to disassembler instance. -void adbg_dasm_close(adbg_disassembler_t *dasm) { - import core.stdc.stdlib : free; - if (dasm == null || dasm.magic != ADBG_DASM_MAGIC) +void adbg_dis_close(adbg_disassembler_t *dasm) { + if (dasm == null || dasm.magic != ADBG_MAGIC) return; if (dasm.cs_inst) cs_free(dasm.cs_inst, 1); cs_close(&dasm.cs_handle); - //free(dasm); Uncomment when _open uses mallocs + free(dasm); } /// Configure an option to the disassembler. @@ -277,7 +275,7 @@ void adbg_dasm_close(adbg_disassembler_t *dasm) { /// /// Example: /// --- -/// adbg_dasm_options(dasm, +/// adbg_dis_options(dasm, /// AdbgDasmOption.syntax, AdbgDasmSyntax.intel, /// 0); /// --- @@ -285,29 +283,27 @@ void adbg_dasm_close(adbg_disassembler_t *dasm) { /// dasm = Reference to disassembler instance. /// ... = Options. /// Returns: Error code. -int adbg_dasm_options(adbg_disassembler_t *dasm, ...) { +int adbg_dis_options(adbg_disassembler_t *dasm, ...) { if (dasm == null) - return adbg_oops(AdbgError.nullArgument); - - if (dasm.magic != ADBG_DASM_MAGIC && - adbg_dasm_open(dasm)) - return adbg_errno; + return adbg_oops(AdbgError.invalidArgument); + if (dasm.magic != ADBG_MAGIC) + return adbg_oops(AdbgError.uninitiated); va_list args = void; va_start(args, dasm); L_OPTION: switch (va_arg!int(args)) { case 0: break; - case AdbgDasmOption.syntax: + case AdbgDisOpt.syntax: int cs_syntax = void; switch (va_arg!int(args)) { - case AdbgDasmSyntax.native: + case AdbgDisSyntax.native: cs_syntax = CS_OPT_SYNTAX_DEFAULT; break; - case AdbgDasmSyntax.intel: + case AdbgDisSyntax.intel: cs_syntax = CS_OPT_SYNTAX_INTEL; break; - case AdbgDasmSyntax.att: + case AdbgDisSyntax.att: cs_syntax = CS_OPT_SYNTAX_ATT; break; default: @@ -332,9 +328,9 @@ L_OPTION: /// size = Size of the user data. /// base_address = Base address. /// Returns: Error code. -int adbg_dasm_start(adbg_disassembler_t *dasm, void *data, size_t size, ulong base_address = 0) { +int adbg_dis_start(adbg_disassembler_t *dasm, void *data, size_t size, ulong base_address = 0) { if (dasm == null || data == null) - return adbg_oops(AdbgError.nullArgument); + return adbg_oops(AdbgError.invalidArgument); dasm.address_base = base_address; dasm.buffer = data; dasm.buffer_size = size; @@ -347,10 +343,10 @@ int adbg_dasm_start(adbg_disassembler_t *dasm, void *data, size_t size, ulong ba /// dasm = Disassembler instance. /// opcode = Opcode instance. /// Returns: Error code. -int adbg_dasm(adbg_disassembler_t *dasm, adbg_opcode_t *opcode) { +int adbg_dis_step(adbg_disassembler_t *dasm, adbg_opcode_t *opcode) { if (dasm == null || opcode == null) - return adbg_oops(AdbgError.nullArgument); - if (dasm.magic != ADBG_DASM_MAGIC) + return adbg_oops(AdbgError.invalidArgument); + if (dasm.magic != ADBG_MAGIC) return adbg_oops(AdbgError.uninitiated); version (Trace) trace("buffer_size=%u", cast(uint)dasm.buffer_size); @@ -400,17 +396,17 @@ int adbg_dasm(adbg_disassembler_t *dasm, adbg_opcode_t *opcode) { /// data = Pointer to user buffer. /// size = Size of user buffer. /// Returns: Error code. -int adbg_dasm_once(adbg_disassembler_t *dasm, adbg_opcode_t *opcode, void *data, size_t size, +int adbg_dis_once(adbg_disassembler_t *dasm, adbg_opcode_t *opcode, void *data, size_t size, ulong base_address = 0) { - int e = adbg_dasm_start(dasm, data, size, base_address); - return e ? e : adbg_dasm(dasm, opcode); + int e = adbg_dis_start(dasm, data, size, base_address); + return e ? e : adbg_dis_step(dasm, opcode); } // // Process wrappers // -int adbg_dasm_start_process(adbg_disassembler_t *dasm, adbg_process_t *process, ulong location) { +int adbg_dis_process_start(adbg_disassembler_t *dasm, adbg_process_t *process, ulong location) { if (dasm == null || process == null) return adbg_oops(AdbgError.nullArgument); dasm.address_base = location; @@ -418,7 +414,7 @@ int adbg_dasm_start_process(adbg_disassembler_t *dasm, adbg_process_t *process, return 0; } -int adbg_dasm_process(adbg_disassembler_t *dasm, adbg_opcode_t *opcode) { +int adbg_dis_process_step(adbg_disassembler_t *dasm, adbg_opcode_t *opcode) { if (dasm == null || opcode == null) return adbg_oops(AdbgError.invalidArgument); @@ -428,7 +424,7 @@ int adbg_dasm_process(adbg_disassembler_t *dasm, adbg_opcode_t *opcode) { dasm.buffer = opcode.machine.ptr; dasm.buffer_size = MAX_INSTR_SIZE; - return adbg_dasm(dasm, opcode); + return adbg_dis_step(dasm, opcode); } /// Wrapper that reads memory from process that disassembles one instruction. @@ -438,13 +434,13 @@ int adbg_dasm_process(adbg_disassembler_t *dasm, adbg_opcode_t *opcode) { /// tracee = Debuggee process. /// address = Process virtual memory location. /// Returns: Error code. -int adbg_dasm_process_once(adbg_disassembler_t *dasm, adbg_opcode_t *opcode, adbg_process_t *tracee, ulong address) { +int adbg_dis_process_once(adbg_disassembler_t *dasm, adbg_opcode_t *opcode, adbg_process_t *tracee, ulong address) { if (dasm == null || tracee == null || opcode == null) return adbg_oops(AdbgError.invalidArgument); if (adbg_memory_read(tracee, address, opcode.machine.ptr, MAX_INSTR_SIZE)) return adbg_errno; - if (adbg_dasm_once(dasm, opcode, opcode.machine.ptr, MAX_INSTR_SIZE)) + if (adbg_dis_once(dasm, opcode, opcode.machine.ptr, MAX_INSTR_SIZE)) return adbg_errno; return 0; }