support PTRACE_SINGLESTEP.

support debug/int3 exception.
This commit is contained in:
Susumu Komae
2015-01-29 15:48:05 +09:00
committed by postpeta
parent f97f8dbab3
commit bd5f43b119
5 changed files with 95 additions and 3 deletions

View File

@ -107,6 +107,7 @@ void reload_idt(void)
static struct list_head handlers[256 - 32]; static struct list_head handlers[256 - 32];
extern char page_fault[], general_protection_exception[]; extern char page_fault[], general_protection_exception[];
extern char debug_exception[], int3_exception[];
static void init_idt(void) 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(13, (unsigned long)general_protection_exception);
set_idt_entry(14, (unsigned long)page_fault); 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(); reload_idt();
} }
@ -467,6 +471,50 @@ void gpe_handler(struct x86_regs *regs)
// panic("GPF"); // 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) void x86_issue_ipi(unsigned int apicid, unsigned int low)
{ {
lapic_icr_write(apicid << LAPIC_ICR_ID_SHIFT, low); lapic_icr_write(apicid << LAPIC_ICR_ID_SHIFT, low);

View File

@ -34,6 +34,14 @@
#define RFLAGS_VIP (1 << 20) #define RFLAGS_VIP (1 << 20)
#define RFLAGS_ID (1 << 21) #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_EFER 0xc0000080
#define MSR_STAR 0xc0000081 #define MSR_STAR 0xc0000081
#define MSR_LSTAR 0xc0000082 #define MSR_LSTAR 0xc0000082

View File

@ -154,3 +154,25 @@ enter_user_mode:
POP_ALL_REGS POP_ALL_REGS
addq $8, %rsp addq $8, %rsp
iretq 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

View File

@ -384,6 +384,11 @@ void clear_single_step(struct process *proc)
proc->uctx->rflags &= ~RFLAGS_TF; 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); extern void coredump(struct process *proc, void *regs);
static void ptrace_report_signal(struct process *proc, struct x86_regs *regs, int sig) static void ptrace_report_signal(struct process *proc, struct x86_regs *regs, int sig)

View File

@ -2557,6 +2557,8 @@ SYSCALL_DECLARE(getrlimit)
} }
extern int ptrace_traceme(void); 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) { static int ptrace_wakeup_sig(int pid, long request, long data) {
dkprintf("ptrace_wakeup_sig,pid=%d,data=%08x\n", pid, 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; break;
case PTRACE_CONT: 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) { if(data != 0 && data != SIGSTOP) {
struct process *proc; struct process *proc;
@ -2823,8 +2833,6 @@ out:
return ret; return ret;
} }
extern void clear_single_step(struct process *proc);
static int ptrace_detach(int pid, int data) static int ptrace_detach(int pid, int data)
{ {
int error; int error;
@ -2991,7 +2999,8 @@ SYSCALL_DECLARE(ptrace)
dkprintf("PTRACE_POKEDATA: addr=%p data=%p\n", addr, data); dkprintf("PTRACE_POKEDATA: addr=%p data=%p\n", addr, data);
break; break;
case PTRACE_SINGLESTEP: 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; break;
case PTRACE_GETFPREGS: case PTRACE_GETFPREGS:
dkprintf("ptrace: unimplemented ptrace(PTRACE_GETFPREGS) called.\n"); dkprintf("ptrace: unimplemented ptrace(PTRACE_GETFPREGS) called.\n");