Skip to content

Commit

Permalink
debugger: add tid to continued callback, simplify new frame list
Browse files Browse the repository at this point in the history
  • Loading branch information
dd86k committed Nov 17, 2024
1 parent 5bec67b commit a5362a4
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 62 deletions.
2 changes: 1 addition & 1 deletion debugger/shell.d
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ void shell_event_exception(adbg_process_t *proc, void *udata, adbg_exception_t *
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);
}
void shell_event_process_continue(adbg_process_t *proc, void *udata) {
void shell_event_process_continue(adbg_process_t *proc, void *udata, int tid) {
printf("* Process %d continued\n", adbg_process_id(proc));
}

Expand Down
2 changes: 1 addition & 1 deletion examples/simple.d
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ void event_exception(adbg_process_t *proc, void *udata, adbg_exception_t *except
*(cast(int*)udata) = SIMPLE_STOP;
}
}
void event_process_continue(adbg_process_t *proc, void *udata) {
void event_process_continue(adbg_process_t *proc, void *udata, long tid) {
printf("* pid=%d event=\"continued\"\n", adbg_process_id(proc));
}
void event_process_exit(adbg_process_t *proc, void *udata, int code) {
Expand Down
8 changes: 4 additions & 4 deletions src/adbg/debugger.d
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,7 @@ version (Windows) {
private alias cbexeception = void function(adbg_process_t*, void*, adbg_exception_t*);
//private alias cbproccreate = void function(adbg_process_t*, void*);
private alias cbprocexited = void function(adbg_process_t*, void*, int);
private alias cbproccontinued = void function(adbg_process_t*, void*);
private alias cbproccontinued = void function(adbg_process_t*, void*, long);

/// Set an event handler for a particular debugging event for this process.
///
Expand Down Expand Up @@ -902,7 +902,7 @@ version (Windows) {
}

if (proc.event_process_continued)
proc.event_process_continued(proc, proc.udata);
proc.event_process_continued(proc, proc.udata, tid);
} else version (linux) {
version(Trace) trace("pid=%d state=%d", proc.pid, proc.state);
switch (proc.state) with (AdbgProcessState) {
Expand All @@ -913,7 +913,7 @@ version (Windows) {
return adbg_oops(AdbgError.os);
}
if (proc.event_process_continued)
proc.event_process_continued(proc, proc.udata);
proc.event_process_continued(proc, proc.udata, tid);
break;
default: return adbg_oops(AdbgError.debuggerUnpaused);
}
Expand All @@ -940,7 +940,7 @@ version (Windows) {
return adbg_oops(AdbgError.os);
}
if (proc.event_process_continued)
proc.event_process_continued(proc, proc.udata);
proc.event_process_continued(proc, proc.udata, tid);
break;
default: return adbg_oops(AdbgError.debuggerUnpaused);
}
Expand Down
11 changes: 6 additions & 5 deletions src/adbg/process/base.d
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ module adbg.process.base;

// TODO: Internal process flags
// - Debugger is active on this process
// - Debugger was attached to this process
// - Memory handle is opened
// - Debugger is attached to this process
// - Process is stopped from an external event (one or more threads are stopped)
// - Process is paused from debugger
// - Process exited
// - Memory handle is opened on this process
// TODO: Process Pause/Resume
// Windows: NtSuspendProcess/NtResumeProcess or SuspendThread/ResumeThread
// Linux: Send SIGSTOP/SIGCONT signals via kill(2)
Expand All @@ -35,8 +38,6 @@ version (Windows) {

extern (C):

// TODO: Add `exited` (replacing `unknown`?)
// TODO: Add `attached`
/// Process status
enum AdbgProcessState : ubyte {
unknown, /// Process status is not known.
Expand Down Expand Up @@ -87,7 +88,7 @@ version (linux) {
void function(adbg_process_t*, void *udata, adbg_exception_t *ex) event_exception;
// void function(adbg_process_t*, void *udata) event_process_created;
void function(adbg_process_t*, void *udata, int code) event_process_exited;
void function(adbg_process_t*, void *udata) event_process_continued;
void function(adbg_process_t*, void *udata, long tid) event_process_continued;

// HACK: Event user data (when attached in wait)
void *udata;
Expand Down
64 changes: 23 additions & 41 deletions src/adbg/process/frame.d
Original file line number Diff line number Diff line change
Expand Up @@ -13,42 +13,44 @@ import adbg.process.base; // for machine info
import adbg.process.thread; // for accessing thread information
import adbg.utils.list;

// NOTE: Stack frame layouts
// Stack frame layouts
//
// # Windows
// # x86-32
//
// There are basically two layouts: EBP frames and FPO frames.
// ## Frame Pointers
//
// ### Windows
//
// 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 EBP, [EBP] points to the previous EBP value, [EBP+4] points to the return
// address, and [EBP+8] points to the first stack argument. [EBP-n] have function
// parameters.
//
// With FPO (POGO?)... To find out.
// ## FPO
//
// # Linux
// TODO
//

extern (C):

struct adbg_stackframe_t {
int level;
// TODO: Frame type/function (e.g., points to memory, register, etc.)
ulong address;
// TODO: Function information
// TODO: Line information
}

private
struct __machine_pc_reg {
AdbgMachine machine;
AdbgRegister[] set;
AdbgRegister reg;
}
// 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 ] },
{ AdbgMachine.i386, AdbgRegister.x86_eip },
{ AdbgMachine.amd64, AdbgRegister.amd64_rip },
{ AdbgMachine.arm, AdbgRegister.arm_pc },
{ AdbgMachine.aarch64, AdbgRegister.aarch64_pc },
];

void* adbg_frame_list(adbg_process_t *process, adbg_thread_t *thread) {
Expand All @@ -62,17 +64,16 @@ void* adbg_frame_list(adbg_process_t *process, adbg_thread_t *thread) {

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

// New frame list
list_t *list = adbg_list_new(adbg_stackframe_t.sizeof, 8);
Expand All @@ -81,7 +82,7 @@ void* adbg_frame_list(adbg_process_t *process, adbg_thread_t *thread) {

// 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]);
adbg_register_t *reg = adbg_register_by_id(thread, register);
if (reg == null) {
adbg_oops(AdbgError.unavailable);
adbg_list_close(list);
Expand All @@ -101,25 +102,6 @@ void* adbg_frame_list(adbg_process_t *process, adbg_thread_t *thread) {
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;
}

Expand Down
21 changes: 11 additions & 10 deletions src/adbg/process/thread.d
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,34 @@ import adbg.utils.list;
import core.stdc.stdio; // snprintf
import core.stdc.stdlib;

// TODO: Consider NOT attaching thread list to process
// Affects: adbg_thread_list_update
// Since they are potentially short-lived, returning a new list when
// needed should be just fine.
// TODO: Thread ID type alias.

version (Windows) {
import core.sys.windows.winbase;
import adbg.include.windows.tlhelp32;
import adbg.include.windows.wow64apiset;
import adbg.include.windows.winnt;
import core.sys.windows.winbase;
} else version (linux) {
import adbg.include.linux.ptrace;
import adbg.include.linux.user;
import core.stdc.ctype : isdigit;
import core.stdc.stdlib : atoi;
import core.sys.posix.dirent;
import core.sys.posix.libgen : basename;
import adbg.include.linux.ptrace;
import adbg.include.linux.user;
} else version (FreeBSD) {
import core.stdc.stdlib : malloc, free;
import core.sys.posix.sys.types : pid_t;
import adbg.include.freebsd.ptrace;
import adbg.include.freebsd.reg;
import core.sys.posix.sys.types : pid_t;
}

extern (C):

// TODO: Thread models and types, for unwinding, SP context manipulation
// Helps interfacing with ELF coredumps, Windows Minidumps, FreeBSD LWPs, etc.
// e.g., a "Minidump thread" would get frames in its own way
// "OS" would be Win32/pthreads, then implementation can go by machine type

// TODO: status flags?
// - context initialized
struct adbg_thread_t {
long id;
adbg_thread_context_t context;
Expand Down

0 comments on commit a5362a4

Please sign in to comment.