support PTRACE_SINGLESTEP.
support debug/int3 exception.
This commit is contained in:
@ -107,6 +107,7 @@ void reload_idt(void)
|
||||
|
||||
static struct list_head handlers[256 - 32];
|
||||
extern char page_fault[], general_protection_exception[];
|
||||
extern char debug_exception[], int3_exception[];
|
||||
|
||||
static void init_idt(void)
|
||||
{
|
||||
@ -125,6 +126,9 @@ static void init_idt(void)
|
||||
set_idt_entry(13, (unsigned long)general_protection_exception);
|
||||
set_idt_entry(14, (unsigned long)page_fault);
|
||||
|
||||
set_idt_entry_trap_gate(1, (unsigned long)debug_exception);
|
||||
set_idt_entry_trap_gate(3, (unsigned long)int3_exception);
|
||||
|
||||
reload_idt();
|
||||
}
|
||||
|
||||
@ -467,6 +471,50 @@ void gpe_handler(struct x86_regs *regs)
|
||||
// panic("GPF");
|
||||
}
|
||||
|
||||
void debug_handler(struct x86_regs *regs)
|
||||
{
|
||||
unsigned long db6;
|
||||
int si_code = 0;
|
||||
struct siginfo info;
|
||||
|
||||
#ifdef DEBUG_PRINT_CPU
|
||||
kprintf("debug exception (err: %lx, %lx:%lx)\n",
|
||||
regs->error, regs->cs, regs->rip);
|
||||
arch_show_interrupt_context(regs);
|
||||
#endif
|
||||
|
||||
asm("mov %%db6, %0" :"=r" (db6));
|
||||
if (db6 & DB6_BS) {
|
||||
regs->rflags &= ~RFLAGS_TF;
|
||||
si_code = TRAP_TRACE;
|
||||
} else if (db6 & (DB6_B3|DB6_B2|DB6_B1|DB6_B0)) {
|
||||
si_code = TRAP_HWBKPT;
|
||||
}
|
||||
|
||||
memset(&info, '\0', sizeof info);
|
||||
info.si_code = si_code;
|
||||
set_signal(SIGTRAP, regs, &info);
|
||||
check_signal(0, regs);
|
||||
check_need_resched();
|
||||
}
|
||||
|
||||
void int3_handler(struct x86_regs *regs)
|
||||
{
|
||||
struct siginfo info;
|
||||
|
||||
#ifdef DEBUG_PRINT_CPU
|
||||
kprintf("int3 exception (err: %lx, %lx:%lx)\n",
|
||||
regs->error, regs->cs, regs->rip);
|
||||
arch_show_interrupt_context(regs);
|
||||
#endif
|
||||
|
||||
memset(&info, '\0', sizeof info);
|
||||
info.si_code = TRAP_BRKPT;
|
||||
set_signal(SIGTRAP, regs, &info);
|
||||
check_signal(0, regs);
|
||||
check_need_resched();
|
||||
}
|
||||
|
||||
void x86_issue_ipi(unsigned int apicid, unsigned int low)
|
||||
{
|
||||
lapic_icr_write(apicid << LAPIC_ICR_ID_SHIFT, low);
|
||||
|
||||
@ -34,6 +34,14 @@
|
||||
#define RFLAGS_VIP (1 << 20)
|
||||
#define RFLAGS_ID (1 << 21)
|
||||
|
||||
#define DB6_B0 (1 << 0)
|
||||
#define DB6_B1 (1 << 1)
|
||||
#define DB6_B2 (1 << 2)
|
||||
#define DB6_B3 (1 << 3)
|
||||
#define DB6_BD (1 << 13)
|
||||
#define DB6_BS (1 << 14)
|
||||
#define DB6_BT (1 << 15)
|
||||
|
||||
#define MSR_EFER 0xc0000080
|
||||
#define MSR_STAR 0xc0000081
|
||||
#define MSR_LSTAR 0xc0000082
|
||||
|
||||
@ -154,3 +154,25 @@ enter_user_mode:
|
||||
POP_ALL_REGS
|
||||
addq $8, %rsp
|
||||
iretq
|
||||
|
||||
.globl debug_exception
|
||||
debug_exception:
|
||||
cld
|
||||
pushq $0 /* error */
|
||||
PUSH_ALL_REGS
|
||||
movq %rsp, %rdi
|
||||
call debug_handler
|
||||
POP_ALL_REGS
|
||||
addq $8, %rsp
|
||||
iretq
|
||||
|
||||
.globl int3_exception
|
||||
int3_exception:
|
||||
cld
|
||||
pushq $0 /* error */
|
||||
PUSH_ALL_REGS
|
||||
movq %rsp, %rdi
|
||||
call int3_handler
|
||||
POP_ALL_REGS
|
||||
addq $8, %rsp
|
||||
iretq
|
||||
|
||||
@ -384,6 +384,11 @@ void clear_single_step(struct process *proc)
|
||||
proc->uctx->rflags &= ~RFLAGS_TF;
|
||||
}
|
||||
|
||||
void set_single_step(struct process *proc)
|
||||
{
|
||||
proc->uctx->rflags |= RFLAGS_TF;
|
||||
}
|
||||
|
||||
extern void coredump(struct process *proc, void *regs);
|
||||
|
||||
static void ptrace_report_signal(struct process *proc, struct x86_regs *regs, int sig)
|
||||
|
||||
@ -2557,6 +2557,8 @@ SYSCALL_DECLARE(getrlimit)
|
||||
}
|
||||
|
||||
extern int ptrace_traceme(void);
|
||||
extern void clear_single_step(struct process *proc);
|
||||
extern void set_single_step(struct process *proc);
|
||||
|
||||
static int ptrace_wakeup_sig(int pid, long request, long data) {
|
||||
dkprintf("ptrace_wakeup_sig,pid=%d,data=%08x\n", pid, data);
|
||||
@ -2588,6 +2590,14 @@ static int ptrace_wakeup_sig(int pid, long request, long data) {
|
||||
}
|
||||
break;
|
||||
case PTRACE_CONT:
|
||||
case PTRACE_SINGLESTEP:
|
||||
case PTRACE_SYSCALL:
|
||||
if (request == PTRACE_SINGLESTEP) {
|
||||
set_single_step(child);
|
||||
}
|
||||
if (request == PTRACE_SYSCALL) {
|
||||
/* TODO: may set PTRACE_SYSCALL flag */
|
||||
}
|
||||
if(data != 0 && data != SIGSTOP) {
|
||||
struct process *proc;
|
||||
|
||||
@ -2823,8 +2833,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern void clear_single_step(struct process *proc);
|
||||
|
||||
static int ptrace_detach(int pid, int data)
|
||||
{
|
||||
int error;
|
||||
@ -2991,7 +2999,8 @@ SYSCALL_DECLARE(ptrace)
|
||||
dkprintf("PTRACE_POKEDATA: addr=%p data=%p\n", addr, data);
|
||||
break;
|
||||
case PTRACE_SINGLESTEP:
|
||||
dkprintf("ptrace: unimplemented ptrace(PTRACE_SINGLESTEP) called.\n");
|
||||
dkprintf("ptrace: PTRACE_SINGLESTEP: data=%d\n", data);
|
||||
error = ptrace_wakeup_sig(pid, request, data);
|
||||
break;
|
||||
case PTRACE_GETFPREGS:
|
||||
dkprintf("ptrace: unimplemented ptrace(PTRACE_GETFPREGS) called.\n");
|
||||
|
||||
Reference in New Issue
Block a user