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;
}