Changeset View
Changeset View
Standalone View
Standalone View
head/lib/libproc/proc_bkpt.c
Show First 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | |||||
#define BREAKPOINT_INSTR_SZ 4 | #define BREAKPOINT_INSTR_SZ 4 | ||||
#elif defined(__riscv__) | #elif defined(__riscv__) | ||||
#define BREAKPOINT_INSTR 0x00100073 /* sbreak */ | #define BREAKPOINT_INSTR 0x00100073 /* sbreak */ | ||||
#define BREAKPOINT_INSTR_SZ 4 | #define BREAKPOINT_INSTR_SZ 4 | ||||
#else | #else | ||||
#error "Add support for your architecture" | #error "Add support for your architecture" | ||||
#endif | #endif | ||||
/* | |||||
* Use 4-bytes holder for breakpoint instruction on all the platforms. | |||||
* Works for x86 as well until it is endian-little platform. | |||||
* (We are coping one byte only on x86 from this 4-bytes piece of | |||||
* memory). | |||||
*/ | |||||
typedef uint32_t instr_t; | |||||
static int | static int | ||||
proc_stop(struct proc_handle *phdl) | proc_stop(struct proc_handle *phdl) | ||||
{ | { | ||||
int status; | int status; | ||||
if (kill(proc_getpid(phdl), SIGSTOP) == -1) { | if (kill(proc_getpid(phdl), SIGSTOP) == -1) { | ||||
DPRINTF("kill %d", proc_getpid(phdl)); | DPRINTF("kill %d", proc_getpid(phdl)); | ||||
return (-1); | return (-1); | ||||
} else if (waitpid(proc_getpid(phdl), &status, WSTOPPED) == -1) { | } else if (waitpid(proc_getpid(phdl), &status, WSTOPPED) == -1) { | ||||
DPRINTF("waitpid %d", proc_getpid(phdl)); | DPRINTF("waitpid %d", proc_getpid(phdl)); | ||||
return (-1); | return (-1); | ||||
} else if (!WIFSTOPPED(status)) { | } else if (!WIFSTOPPED(status)) { | ||||
DPRINTFX("waitpid: unexpected status 0x%x", status); | DPRINTFX("waitpid: unexpected status 0x%x", status); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
proc_bkptset(struct proc_handle *phdl, uintptr_t address, | proc_bkptset(struct proc_handle *phdl, uintptr_t address, | ||||
unsigned long *saved) | unsigned long *saved) | ||||
{ | { | ||||
struct ptrace_io_desc piod; | struct ptrace_io_desc piod; | ||||
unsigned long paddr, caddr; | unsigned long caddr; | ||||
int ret = 0, stopped; | int ret = 0, stopped; | ||||
instr_t instr; | |||||
*saved = 0; | *saved = 0; | ||||
if (phdl->status == PS_DEAD || phdl->status == PS_UNDEAD || | if (phdl->status == PS_DEAD || phdl->status == PS_UNDEAD || | ||||
phdl->status == PS_IDLE) { | phdl->status == PS_IDLE) { | ||||
errno = ENOENT; | errno = ENOENT; | ||||
return (-1); | return (-1); | ||||
} | } | ||||
DPRINTFX("adding breakpoint at 0x%lx", address); | DPRINTFX("adding breakpoint at 0x%lx", address); | ||||
stopped = 0; | stopped = 0; | ||||
if (phdl->status != PS_STOP) { | if (phdl->status != PS_STOP) { | ||||
if (proc_stop(phdl) != 0) | if (proc_stop(phdl) != 0) | ||||
return (-1); | return (-1); | ||||
stopped = 1; | stopped = 1; | ||||
} | } | ||||
/* | /* | ||||
* Read the original instruction. | * Read the original instruction. | ||||
*/ | */ | ||||
caddr = address; | caddr = address; | ||||
paddr = 0; | instr = 0; | ||||
piod.piod_op = PIOD_READ_I; | piod.piod_op = PIOD_READ_I; | ||||
piod.piod_offs = (void *)caddr; | piod.piod_offs = (void *)caddr; | ||||
piod.piod_addr = &paddr; | piod.piod_addr = &instr; | ||||
piod.piod_len = BREAKPOINT_INSTR_SZ; | piod.piod_len = BREAKPOINT_INSTR_SZ; | ||||
if (ptrace(PT_IO, proc_getpid(phdl), (caddr_t)&piod, 0) < 0) { | if (ptrace(PT_IO, proc_getpid(phdl), (caddr_t)&piod, 0) < 0) { | ||||
DPRINTF("ERROR: couldn't read instruction at address 0x%" | DPRINTF("ERROR: couldn't read instruction at address 0x%" | ||||
PRIuPTR, address); | PRIuPTR, address); | ||||
ret = -1; | ret = -1; | ||||
goto done; | goto done; | ||||
} | } | ||||
*saved = paddr; | *saved = instr; | ||||
/* | /* | ||||
* Write a breakpoint instruction to that address. | * Write a breakpoint instruction to that address. | ||||
*/ | */ | ||||
caddr = address; | caddr = address; | ||||
paddr = BREAKPOINT_INSTR; | instr = BREAKPOINT_INSTR; | ||||
piod.piod_op = PIOD_WRITE_I; | piod.piod_op = PIOD_WRITE_I; | ||||
piod.piod_offs = (void *)caddr; | piod.piod_offs = (void *)caddr; | ||||
piod.piod_addr = &paddr; | piod.piod_addr = &instr; | ||||
piod.piod_len = BREAKPOINT_INSTR_SZ; | piod.piod_len = BREAKPOINT_INSTR_SZ; | ||||
if (ptrace(PT_IO, proc_getpid(phdl), (caddr_t)&piod, 0) < 0) { | if (ptrace(PT_IO, proc_getpid(phdl), (caddr_t)&piod, 0) < 0) { | ||||
DPRINTF("ERROR: couldn't write instruction at address 0x%" | DPRINTF("ERROR: couldn't write instruction at address 0x%" | ||||
PRIuPTR, address); | PRIuPTR, address); | ||||
ret = -1; | ret = -1; | ||||
goto done; | goto done; | ||||
} | } | ||||
done: | done: | ||||
if (stopped) | if (stopped) | ||||
/* Restart the process if we had to stop it. */ | /* Restart the process if we had to stop it. */ | ||||
proc_continue(phdl); | proc_continue(phdl); | ||||
return (ret); | return (ret); | ||||
} | } | ||||
int | int | ||||
proc_bkptdel(struct proc_handle *phdl, uintptr_t address, | proc_bkptdel(struct proc_handle *phdl, uintptr_t address, | ||||
unsigned long saved) | unsigned long saved) | ||||
{ | { | ||||
struct ptrace_io_desc piod; | struct ptrace_io_desc piod; | ||||
unsigned long paddr, caddr; | unsigned long caddr; | ||||
int ret = 0, stopped; | int ret = 0, stopped; | ||||
instr_t instr; | |||||
if (phdl->status == PS_DEAD || phdl->status == PS_UNDEAD || | if (phdl->status == PS_DEAD || phdl->status == PS_UNDEAD || | ||||
phdl->status == PS_IDLE) { | phdl->status == PS_IDLE) { | ||||
errno = ENOENT; | errno = ENOENT; | ||||
return (-1); | return (-1); | ||||
} | } | ||||
DPRINTFX("removing breakpoint at 0x%lx", address); | DPRINTFX("removing breakpoint at 0x%lx", address); | ||||
stopped = 0; | stopped = 0; | ||||
if (phdl->status != PS_STOP) { | if (phdl->status != PS_STOP) { | ||||
if (proc_stop(phdl) != 0) | if (proc_stop(phdl) != 0) | ||||
return (-1); | return (-1); | ||||
stopped = 1; | stopped = 1; | ||||
} | } | ||||
/* | /* | ||||
* Overwrite the breakpoint instruction that we setup previously. | * Overwrite the breakpoint instruction that we setup previously. | ||||
*/ | */ | ||||
caddr = address; | caddr = address; | ||||
paddr = saved; | instr = saved; | ||||
piod.piod_op = PIOD_WRITE_I; | piod.piod_op = PIOD_WRITE_I; | ||||
piod.piod_offs = (void *)caddr; | piod.piod_offs = (void *)caddr; | ||||
piod.piod_addr = &paddr; | piod.piod_addr = &instr; | ||||
piod.piod_len = BREAKPOINT_INSTR_SZ; | piod.piod_len = BREAKPOINT_INSTR_SZ; | ||||
if (ptrace(PT_IO, proc_getpid(phdl), (caddr_t)&piod, 0) < 0) { | if (ptrace(PT_IO, proc_getpid(phdl), (caddr_t)&piod, 0) < 0) { | ||||
DPRINTF("ERROR: couldn't write instruction at address 0x%" | DPRINTF("ERROR: couldn't write instruction at address 0x%" | ||||
PRIuPTR, address); | PRIuPTR, address); | ||||
ret = -1; | ret = -1; | ||||
} | } | ||||
if (stopped) | if (stopped) | ||||
▲ Show 20 Lines • Show All 70 Lines • Show Last 20 Lines |