mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-11-14 02:03:27 -08:00
linux_demon: PTRACE_EVENT_STOPs can sometimes be reported even if a thread has already hit a trap (e.g. a trap net or breakpoint trap). this would sometimes cause spurious SIGTRAPs after issuing a PTRACE_INTERRUPT - so we need to flag halted threads to not treat that as a 'real' trap. furthermore, even though that trap was hit, it does not guarantee that the debugger would next see a SIGTRAP. that would cause spurious SIGILLs, because we'd resume threads *after* the trap, despite not seeing the trap, so they'd just see a malformed instruction (the bytes subsequent the initial trap). so in those cases, we need to roll such threads back, so that they re-execute the trap, and so that we see a regular SIGTRAP, and handle the trap correctly.
This commit is contained in:
1 parent
2933143b08
commit
0b91cab00a
3 files changed
+75
-47
No files matched your search
@@ -1770,6 +1770,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
{
|
||||
if(n->v != thread && n->v->state == LNX_DMN_ThreadState_Running)
|
||||
{
|
||||
n->v->ghost_trap = 1;
|
||||
if(LNX_RETRY_ON_EINTR(ptrace(PTRACE_INTERRUPT, n->v->tid, 0, 0)) < 0)
|
||||
{
|
||||
log_infof("ptrace error: Couldn't send PTRACE_INTERRUPT to TID %I64u.", n->v->tid);
|
||||
@@ -2029,16 +2030,23 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
if(hit_user_trap)
|
||||
{
|
||||
U64 ip = lnx_dmn_ip_from_thread(thread);
|
||||
lnx_dmn_thread_write_ip(thread, ip - 1);
|
||||
lnx_dmn_thread_write_ip(thread, ip - arch_info->trap_instruction.size);
|
||||
}
|
||||
|
||||
// rjf: generate event
|
||||
DMN_Event *e = dmn_event_list_push(arena, &events);
|
||||
e->kind = hit_user_trap ? DMN_EventKind_Breakpoint : DMN_EventKind_Trap;
|
||||
e->process = lnx_dmn_handle_from_process(process);
|
||||
e->thread = lnx_dmn_handle_from_thread(thread);
|
||||
e->instruction_pointer = lnx_dmn_ip_from_thread(thread);
|
||||
e->user_data = hit_user_trap ? hit_user_trap->id : 0;
|
||||
// rjf: generate event, if this isn't a ghost trap
|
||||
if(thread->ghost_trap)
|
||||
{
|
||||
thread->ghost_trap = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
DMN_Event *e = dmn_event_list_push(arena, &events);
|
||||
e->kind = hit_user_trap ? DMN_EventKind_Breakpoint : DMN_EventKind_Trap;
|
||||
e->process = lnx_dmn_handle_from_process(process);
|
||||
e->thread = lnx_dmn_handle_from_thread(thread);
|
||||
e->instruction_pointer = lnx_dmn_ip_from_thread(thread);
|
||||
e->user_data = hit_user_trap ? hit_user_trap->id : 0;
|
||||
}
|
||||
}
|
||||
}break;
|
||||
|
||||
@@ -2223,6 +2231,26 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
e->tls_root_vaddr = thread->dtv_base_vaddr;
|
||||
}
|
||||
|
||||
// rjf: stop event for other threads we're attached to, due to a stop in
|
||||
// another thread - check if this hit a trap and roll back
|
||||
else if(thread != 0 && thread->state == LNX_DMN_ThreadState_Stopped)
|
||||
{
|
||||
//- rjf: unpack thread IP / process
|
||||
U64 ip = lnx_dmn_ip_from_thread(thread);
|
||||
DMN_Handle process_handle = lnx_dmn_handle_from_process(process);
|
||||
|
||||
//- rjf: check previous bytes against trap instruction. if this thread
|
||||
// executed a trap, we need to roll back before continuing this thread.
|
||||
// we CANNOT RELY on there being a subsequently-queued SIGTRAP.
|
||||
U8 *hit_trap_bytes_maybe = push_array(scratch.arena, U8, arch_info->trap_instruction.size);
|
||||
dmn_process_read(process_handle, r1u64(ip - arch_info->trap_instruction.size, ip), hit_trap_bytes_maybe);
|
||||
String8 hit_trap_data_maybe = str8(hit_trap_bytes_maybe, arch_info->trap_instruction.size);
|
||||
if(str8_match(hit_trap_data_maybe, arch_info->trap_instruction, 0))
|
||||
{
|
||||
lnx_dmn_thread_write_ip(thread, ip - arch_info->trap_instruction.size);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: stop event for unrecognized thread -> this references a thread we
|
||||
// haven't seen cloned yet (we cannot rely on the order of clone/stop). so,
|
||||
// we will gather the ID, and increase the pending threads count, and stop
|
||||
@@ -2263,44 +2291,42 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
//
|
||||
else
|
||||
{
|
||||
LNX_DMN_Thread *thread = lnx_dmn_thread_from_pid(wait_id);
|
||||
thread->pass_through_signal = 1;
|
||||
thread->pass_through_signo = wstopsig;
|
||||
local_persist B8 is_repeatable[] =
|
||||
{
|
||||
0, // null
|
||||
1, // 1 SIGHUP
|
||||
1, // 2 SIGINT
|
||||
1, // 3 SIGQUIT
|
||||
1, // 4 SIGTRAP
|
||||
1, // 5 SIGABRT
|
||||
1, // 6 SIGIOT
|
||||
1, // 7 SIGBUS
|
||||
1, // 8 SIGFPE
|
||||
1, // 9 SIGKILL
|
||||
1, // 10 SIGUSR1
|
||||
1, // 11 SIGSEGV
|
||||
1, // 12 SIGUSR2
|
||||
1, // 13 SIGPIPE
|
||||
1, // 14 SIGALRM
|
||||
1, // 15 SIGTERM
|
||||
1, // 16 SIGTKFLT
|
||||
0, // 17 SIGCHLD
|
||||
0, // 18 SIGCONT
|
||||
1, // 19 SIGSTOP
|
||||
1, // 20 SIGTSP
|
||||
1, // 21 SIGTTIN
|
||||
1, // 22 SIGTTOU
|
||||
0, // 23 SIGURG
|
||||
1, // 24 SIGXCPU
|
||||
1, // 25 SIGXFSZ
|
||||
1, // 26 SIGVTALRM
|
||||
1, // 27 SIGPROF
|
||||
0, // 28 SIGWINCH
|
||||
1, // 29 SIGIO
|
||||
1, // 30 SIGPWR
|
||||
1, // 31 SIGSYS
|
||||
1, // 32 SIGUNUSED
|
||||
1, // SIGHUP 1
|
||||
1, // SIGINT 2
|
||||
1, // SIGQUIT 3
|
||||
1, // SIGILL 4
|
||||
1, // SIGTRAP 5
|
||||
1, // SIGABRT/SIGIOT 6
|
||||
1, // SIGBUS 7
|
||||
1, // SIGFPE 8
|
||||
1, // SIGKILL 9
|
||||
1, // SIGUSR1 10
|
||||
1, // SIGSEGV 11
|
||||
1, // SIGUSR2 12
|
||||
1, // SIGPIPE 13
|
||||
1, // SIGALRM 14
|
||||
1, // SIGTERM 15
|
||||
1, // SIGSTKFLT 16
|
||||
0, // SIGCHLD 17
|
||||
0, // SIGCONT 18
|
||||
1, // SIGSTOP 19
|
||||
1, // SIGTSTP 20
|
||||
1, // SIGTTIN 21
|
||||
1, // SIGTTOU 22
|
||||
0, // SIGURG 23
|
||||
1, // SIGXCPU 24
|
||||
1, // SIGXFSZ 25
|
||||
1, // SIGVTALRM 26
|
||||
1, // SIGPROF 27
|
||||
0, // SIGWINCH 28
|
||||
1, // SIGIO 29
|
||||
1, // SIGPWR 30
|
||||
1, // SIGSYS/SIGUNUSED31
|
||||
};
|
||||
DMN_Event *e = dmn_event_list_push(arena, &events);
|
||||
e->kind = DMN_EventKind_Exception;
|
||||
|
||||
@@ -178,6 +178,7 @@ struct LNX_DMN_Thread
|
||||
void *reg_block;
|
||||
B32 is_reg_block_dirty;
|
||||
B32 pass_through_signal;
|
||||
B32 ghost_trap;
|
||||
U64 pass_through_signo;
|
||||
U64 orig_rax;
|
||||
U64 dtv_base_vaddr;
|
||||
|
||||
@@ -7,23 +7,24 @@
|
||||
// initial alpha:
|
||||
// [x] .so loading/debugging - missing debug info
|
||||
// [x] missing disasm
|
||||
// [ ] recycling semaphore files - or alt strat?
|
||||
// [ ] control
|
||||
// [ ] multithreaded stepping - trap hits reported on other threads.
|
||||
// [ ] stale memory - things evaluating to stale values that are definitely not zero
|
||||
// [ ] support
|
||||
// [ ] .eh_frame unwinding without .eh_frame_hdr
|
||||
// [ ] asan
|
||||
// [ ] stale memory - things evaluating to stale values that are definitely not zero
|
||||
// [ ] rendering
|
||||
// [ ] bitmaps / geometry
|
||||
// [ ] bitmaps / geometry
|
||||
//
|
||||
// post initial alpha:
|
||||
// [ ] windowing
|
||||
// [ ] wayland
|
||||
// [ ] support
|
||||
// [ ] .eh_frame unwinding without .eh_frame_hdr
|
||||
//
|
||||
// [x] clipboard
|
||||
// [x] jai exes - busted call stacks / unwind info / paths?
|
||||
// [x] statically linked EXEs - busted unwinding
|
||||
// [x] statically linked EXEs, not parsing maps file correctly
|
||||
// [x] asan
|
||||
// [x] multithreaded stepping - trap hits reported on other threads.
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: evaluation system pass TODO notes
|
||||
|
||||
Reference in new issue
Block a user