Implement single stepping on arm64. We need to set the single step bits in

the processor and debug state registers. A flag has been added to the pcb
to tell us when to enable single stepping for a given thread.

Reviewed by:	kib
Sponsored by:	ABT Systems Ltd
Differential Revision:	https://reviews.freebsd.org/D4730
This commit is contained in:
Andrew Turner 2016-02-02 10:28:56 +00:00
parent 6f95e9062b
commit 87e19994e1
7 changed files with 65 additions and 5 deletions

View File

@ -49,10 +49,12 @@ ASSYM(PC_CURTHREAD, offsetof(struct pcpu, pc_curthread));
/* Size of pcb, rounded to keep stack alignment */
ASSYM(PCB_SIZE, roundup2(sizeof(struct pcb), STACKALIGNBYTES + 1));
ASSYM(PCB_SINGLE_STEP_SHIFT, PCB_SINGLE_STEP_SHIFT);
ASSYM(PCB_REGS, offsetof(struct pcb, pcb_x));
ASSYM(PCB_SP, offsetof(struct pcb, pcb_sp));
ASSYM(PCB_L1ADDR, offsetof(struct pcb, pcb_l1addr));
ASSYM(PCB_ONFAULT, offsetof(struct pcb, pcb_onfault));
ASSYM(PCB_FLAGS, offsetof(struct pcb, pcb_flags));
ASSYM(SF_UC, offsetof(struct sigframe, sf_uc));

View File

@ -233,7 +233,8 @@ int
ptrace_single_step(struct thread *td)
{
/* TODO; */
td->td_frame->tf_spsr |= PSR_SS;
td->td_pcb->pcb_flags |= PCB_SINGLE_STEP;
return (0);
}
@ -241,7 +242,8 @@ int
ptrace_clear_single_step(struct thread *td)
{
/* TODO; */
td->td_frame->tf_spsr &= ~PSR_SS;
td->td_pcb->pcb_flags &= ~PCB_SINGLE_STEP;
return (0);
}

View File

@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
#include <vm/vm_extern.h>
#include <vm/vm_kern.h>
#include <machine/debug_monitor.h>
#include <machine/intr.h>
#include <machine/smp.h>
#ifdef VFP
@ -247,6 +248,8 @@ init_secondary(uint64_t cpu)
vfp_init();
#endif
dbg_monitor_init();
/* Enable interrupts */
intr_enable();

View File

@ -37,10 +37,37 @@
__FBSDID("$FreeBSD$");
.macro clear_step_flag pcbflags, tmp
tbz \pcbflags, #PCB_SINGLE_STEP_SHIFT, 999f
mrs \tmp, mdscr_el1
bic \tmp, \tmp, #1
msr mdscr_el1, \tmp
isb
999:
.endm
.macro set_step_flag pcbflags, tmp
tbz \pcbflags, #PCB_SINGLE_STEP_SHIFT, 999f
mrs \tmp, mdscr_el1
orr \tmp, \tmp, #1
msr mdscr_el1, \tmp
isb
999:
.endm
/*
* void cpu_throw(struct thread *old, struct thread *new)
*/
ENTRY(cpu_throw)
/* Of old == NULL skip disabling stepping */
cbz x0, 1f
/* If we were single stepping, disable it */
ldr x4, [x0, #TD_PCB]
ldr w5, [x4, #PCB_FLAGS]
clear_step_flag w5, x6
1:
#ifdef VFP
/* Backup the new thread pointer around a call to C code */
mov x19, x1
@ -69,6 +96,10 @@ ENTRY(cpu_throw)
dsb sy
isb
/* If we are single stepping, enable it */
ldr w5, [x4, #PCB_FLAGS]
set_step_flag w5, x6
/* Restore the registers */
ldp x5, x6, [x4, #PCB_SP]
mov sp, x5
@ -127,6 +158,10 @@ ENTRY(cpu_switch)
mrs x6, tpidr_el0
stp x5, x6, [x4, #PCB_SP]
/* If we were single stepping, disable it */
ldr w5, [x4, #PCB_FLAGS]
clear_step_flag w5, x6
#ifdef VFP
mov x19, x0
mov x20, x1
@ -174,6 +209,10 @@ ENTRY(cpu_switch)
b.eq 1b
#endif
/* If we are single stepping, enable it */
ldr w5, [x4, #PCB_FLAGS]
set_step_flag w5, x6
/* Restore the registers */
ldp x5, x6, [x4, #PCB_SP]
mov sp, x5

View File

@ -138,7 +138,6 @@ svc_handler(struct trapframe *frame)
int error;
td = curthread;
td->td_frame = frame;
error = syscallenter(td, &sa);
syscallret(td, error, &sa);
@ -338,6 +337,9 @@ do_el0_sync(struct trapframe *frame)
("Invalid pcpu address from userland: %p (tpidr %lx)",
get_pcpu(), READ_SPECIALREG(tpidr_el1)));
td = curthread;
td->td_frame = frame;
esr = READ_SPECIALREG(esr_el1);
exception = ESR_ELx_EXCEPTION(esr);
switch (exception) {
@ -373,15 +375,22 @@ do_el0_sync(struct trapframe *frame)
el0_excp_unknown(frame);
break;
case EXCP_PC_ALIGN:
td = curthread;
call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_elr);
userret(td, frame);
break;
case EXCP_BRK:
td = curthread;
call_trapsignal(td, SIGTRAP, TRAP_BRKPT, (void *)frame->tf_elr);
userret(td, frame);
break;
case EXCP_SOFTSTP_EL0:
td->td_frame->tf_spsr &= ~PSR_SS;
td->td_pcb->pcb_flags &= ~PCB_SINGLE_STEP;
WRITE_SPECIALREG(MDSCR_EL1,
READ_SPECIALREG(MDSCR_EL1) & ~DBG_MDSCR_SS);
call_trapsignal(td, SIGTRAP, TRAP_TRACE,
(void *)frame->tf_elr);
userret(td, frame);
break;
default:
print_registers(frame);
panic("Unknown userland exception %x esr_el1 %lx\n", exception,

View File

@ -101,6 +101,7 @@
#define EXCP_SP_ALIGN 0x26 /* SP slignment fault */
#define EXCP_TRAP_FP 0x2c /* Trapped FP exception */
#define EXCP_SERROR 0x2f /* SError interrupt */
#define EXCP_SOFTSTP_EL0 0x32 /* Software Step, from lower EL */
#define EXCP_SOFTSTP_EL1 0x33 /* Software Step, from same EL */
#define EXCP_WATCHPT_EL1 0x35 /* Watchpoint, from same EL */
#define EXCP_BRK 0x3c /* Breakpoint */

View File

@ -45,6 +45,10 @@ struct pcb {
/* Fault handler, the error value is passed in x0 */
vm_offset_t pcb_onfault;
u_int pcb_flags;
#define PCB_SINGLE_STEP_SHIFT 0
#define PCB_SINGLE_STEP (1 << PCB_SINGLE_STEP_SHIFT)
/* Place last to simplify the asm to access the rest if the struct */
__uint128_t pcb_vfp[32];
uint32_t pcb_fpcr;