Skip to content

Commit

Permalink
Introduce stackframes, "error" command
Browse files Browse the repository at this point in the history
  • Loading branch information
dd86k committed Oct 31, 2024
1 parent 40531d8 commit c6ad0bb
Show file tree
Hide file tree
Showing 6 changed files with 283 additions and 55 deletions.
99 changes: 73 additions & 26 deletions debugger/shell.d
Original file line number Diff line number Diff line change
Expand Up @@ -241,10 +241,9 @@ struct command2_t {
command2_help_section_t[] doc_sections;
int function(int, const(char)**) entry;
}
// NOTE: Called "commands_list" to avoid conflict with future "command_list" function
// TODO: New commands
// - b|breakpoint: Breakpoint management
// - sym: Symbol management
// - sym|symbols: Symbol management
immutable command2_t[] shell_commands = [
//
// Debugger
Expand Down Expand Up @@ -476,17 +475,24 @@ immutable command2_t[] shell_commands = [
[ "[ITEM]" ],
MODULE_SHELL, CATEGORY_SHELL,
[

],
&command_help,
},
{
[ "error" ],
"Show last error in greater details",
[],
MODULE_SHELL, CATEGORY_SHELL,
[
],
&command_error,
},
{
[ "version" ],
"Show Alicedbg version.",
[],
MODULE_SHELL, CATEGORY_SHELL,
[

],
&command_version,
},
Expand Down Expand Up @@ -629,27 +635,39 @@ void shell_event_exception(adbg_process_t *proc, void *udata, adbg_exception_t *
event_tid = adbg_exception_tid(exception);

printf("* Process %d (thread %lld) stopped\n"~
" Reason : %s ("~ERR_OSFMT~")\n",
"* Reason : %s ("~ERR_OSFMT~")\n",
pid, event_tid,
adbg_exception_name(exception), adbg_exception_orig_code(exception));

// No fault address available
if (exception.fault_address == 0)
return;

printf(" Address : 0x%llx\n", exception.fault_address);

char[32] machbuf = void;
const(char)* mnemonic = void, operands = void;
if (shell_disassemble(cast(size_t)exception.fault_address,
null,
null, 0,
machbuf.ptr, 32,
&mnemonic, &operands))
return;
// Fault address available, print it
if (exception.fault_address) {
printf(" Address : 0x%llx\n", exception.fault_address);
char[32] machbuf = void;
const(char)* mnemonic = void, operands = void;
// Disassembling instruction at fault address passed
if (shell_disassemble(cast(size_t)exception.fault_address,
null,
null, 0,
machbuf.ptr, 32,
&mnemonic, &operands) == 0) {
printf("* Machine : %s\n", machbuf.ptr);
printf("* Mnemonic: %s %s\n", mnemonic, operands);
}
}

printf(" Machine : %s\n", machbuf.ptr);
printf(" Mnemonic: %s %s\n", mnemonic, operands);
// Print callstack, if available
adbg_thread_t *thread = adbg_thread_new(event_tid);
if (thread) {
void *frames = adbg_frame_list(process, thread);
if (frames) {
puts("\n* Callstack (WIP):");
adbg_stackframe_t *frame = void;
for (size_t i; (frame = adbg_frame_list_at(frames, i)) != null; ++i) {
printf("%3zu. %llx\n", i, frame.address);
}
adbg_frame_list_close(frames);
}
}
}
void shell_event_process_exit(adbg_process_t *proc, void *udata, int code) {
printf("* Process %d exited with code %d\n", adbg_process_id(proc), code);
Expand Down Expand Up @@ -1121,7 +1139,7 @@ int command_thread(int argc, const(char) **argv) {
// thread list - get a list of threads
if (strcmp(action, "list") == 0) {
printf("Threads:");
for (size_t i; (thread = adbg_thread_list_get(process, i)) != null; ++i) {
for (size_t i; (thread = adbg_thread_list_get(thrlist, i)) != null; ++i) {
if (i) putchar(',');
printf(" %lld", adbg_thread_id(thread));
}
Expand All @@ -1139,7 +1157,7 @@ int command_thread(int argc, const(char) **argv) {
return ShellError.alicedbg;

action = argv[2];
if (strcmp(action, "registers") == 0 || strcmp(action, "regs") == 0) {
if (*action == 'r' || strcmp(action, "registers") == 0) {
int id;
adbg_register_t *register = void;
while ((register = adbg_register_by_id(thread, id++)) != null) {
Expand All @@ -1151,10 +1169,28 @@ int command_thread(int argc, const(char) **argv) {
-16, hex.ptr,
dec.ptr);
}
} else
return ShellError.invalidParameter;
return 0;
} else if (*action == 's' || strcmp(action, "stack") == 0) {
if (argc < 4) // stack action
return ShellError.missingArgument;

action = argv[3];
if (strcmp(action, "show") == 0) { // show thread id stack
void *frames = adbg_frame_list(process, thread);
if (frames == null)
return ShellError.alicedbg;

adbg_stackframe_t *frame = void;
for (size_t i; (frame = adbg_frame_list_at(frames, i)) != null; ++i) {
printf("%3zu. %llx\n", i, frame.address);
}

adbg_frame_list_close(frames);
return 0;
}
}

return 0;
return ShellError.invalidCommand;
}

int command_cd(int argc, const(char) **argv) {
Expand All @@ -1174,6 +1210,17 @@ int command_pwd(int argc, const(char) **argv) {
return 0;
}

int command_error(int argc, const(char) **argv) {
printf(
"Message : %s\n"~
"Code : %d\n"~
"Caller : %s:L%d\n",
adbg_error_message(),
adbg_error_code(),
adbg_error_function(), adbg_error_line());
return 0;
}

int command_version(int argc, const(char) **argv) {
static immutable string LINE = `Alicedbg `~ADBG_VERSION~` `~TARGET_PLATFORM~`-`~TARGET_OS~`-`~TARGET_ENV;
puts(LINE.ptr);
Expand Down
4 changes: 2 additions & 2 deletions src/adbg/debugger.d
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ version (Windows) {
adbg_oops(AdbgError.assertion);
return null;
}
version(Trace) trace("args='%s'", proc.args);
version(Trace) trace("args='%s'", proc.orig_args);
}

// TODO: Parse envp
Expand Down Expand Up @@ -664,7 +664,7 @@ int adbg_debugger_udata(adbg_process_t *proc, void *udata) {
/// Params: proc = Process instancied by the debugger.
/// Returns: Error code.
int adbg_debugger_wait(adbg_process_t *proc) {
version(Trace) trace("proc=%p udata=%p", proc, udata);
version(Trace) trace("proc=%p", proc);

if (proc == null)
return adbg_oops(AdbgError.invalidArgument);
Expand Down
136 changes: 136 additions & 0 deletions src/adbg/process/frame.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/// Process frame management.
///
/// Stack frames, unwinding operations, etc.
///
/// Authors: dd86k <[email protected]>
/// Copyright: © dd86k <[email protected]>
/// License: BSD-3-Clause-Clear
module adbg.process.frame;

import adbg.error;
import adbg.machines;
import adbg.process.base; // for machine info
import adbg.process.thread; // for accessing thread information
import adbg.utils.list;

// NOTE: Stack frame layouts
//
// # Windows
//
// There are basically two layouts: EBP frames and FPO frames.
//
// With EBP, EBP points to the previous value, EBP+4 points to the return
// address, and EBP+8 points to the first stack argument.
//
// With FPO (POGO?)... To find out.
//
// # Linux
//

extern (C):

struct adbg_stackframe_t {
int level;
ulong address;
// TODO: Function information
// TODO: Line information
}

private
struct __machine_pc_reg {
AdbgMachine machine;
AdbgRegister[] set;
}
// Level 0: Current location, typically Program Counter
// Level 1: Frame Pointer if available
private
static immutable __machine_pc_reg[] stackregs = [
{ AdbgMachine.i386, [ AdbgRegister.x86_eip, AdbgRegister.x86_ebp ] },
{ AdbgMachine.amd64, [ AdbgRegister.amd64_rip, AdbgRegister.amd64_rbp ] },
{ AdbgMachine.arm, [ AdbgRegister.arm_pc, AdbgRegister.arm_fp ] },
{ AdbgMachine.aarch64, [ AdbgRegister.aarch64_pc, AdbgRegister.aarch64_fp ] },
];

void* adbg_frame_list(adbg_process_t *process, adbg_thread_t *thread) {
if (process == null || thread == null) {
adbg_oops(AdbgError.invalidArgument);
return null;
}

if (adbg_thread_context_update(process, thread))
return null;

// Map a set of registers to use at primary stackframe levels
AdbgMachine mach = adbg_process_machine(process);
immutable(AdbgRegister)[] registers;
foreach (ref regs; stackregs) {
if (mach == regs.machine) {
registers = regs.set;
break;
}
}
if (registers.length == 0) {
adbg_oops(AdbgError.unavailable);
return null;
}

// New frame list
list_t *list = adbg_list_new(adbg_stackframe_t.sizeof, 8);
if (list == null)
return null;

// Start with the first frame, which is always PC
// If we can't have that, then we cannot even obtain frames at all
adbg_register_t *reg = adbg_register_by_id(thread, registers[0]);
if (reg == null) {
adbg_oops(AdbgError.unavailable);
adbg_list_close(list);
return null;
}
ulong *address = cast(ulong*)adbg_register_value(reg);
if (address == null || *address == 0) {
adbg_list_close(list);
return null;
}
adbg_stackframe_t frame = void;
frame.level = 0;
frame.address = *address;
list = adbg_list_add(list, &frame);
if (list == null) {
adbg_list_close(list);
return null;
}

// Add additional frames from additional registers
// As best as we can, otherwise just return the list
foreach (AdbgRegister r; registers[1..$]) {
reg = adbg_register_by_id(thread, r);
if (reg == null)
break;
address = cast(ulong*)adbg_register_value(reg);
if (address == null || *address == 0)
break;

++frame.level; // frame[0] is level=0, so increment
frame.address = *address;
list = adbg_list_add(list, &frame);
if (list == null) {
adbg_list_close(list);
return null;
}
}

return list;
}

size_t adbg_frame_list_count(void *list) {
return adbg_list_count(cast(list_t*)list);
}

adbg_stackframe_t* adbg_frame_list_at(void *list, size_t index) {
return cast(adbg_stackframe_t*)adbg_list_get(cast(list_t*)list, index);
}

void adbg_frame_list_close(void *list) {
adbg_list_close(cast(list_t*)list);
}
1 change: 1 addition & 0 deletions src/adbg/process/package.d
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ public import
adbg.process.exception,
adbg.process.breakpoint,
adbg.process.memory,
adbg.process.frame,
adbg.process.thread;
Loading

0 comments on commit c6ad0bb

Please sign in to comment.