summaryrefslogtreecommitdiffstats
path: root/lib/libproc/proc_bkpt.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libproc/proc_bkpt.c')
-rw-r--r--lib/libproc/proc_bkpt.c88
1 files changed, 70 insertions, 18 deletions
diff --git a/lib/libproc/proc_bkpt.c b/lib/libproc/proc_bkpt.c
index c15e53c..2c2761a 100644
--- a/lib/libproc/proc_bkpt.c
+++ b/lib/libproc/proc_bkpt.c
@@ -37,8 +37,9 @@ __FBSDID("$FreeBSD$");
#include <assert.h>
#include <err.h>
-#include <stdio.h>
#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
#include "_libproc.h"
#if defined(__i386__) || defined(__amd64__)
@@ -54,12 +55,39 @@ __FBSDID("$FreeBSD$");
#error "Add support for your architecture"
#endif
+static void
+proc_cont(struct proc_handle *phdl)
+{
+
+ ptrace(PT_CONTINUE, proc_getpid(phdl), (caddr_t)1, 0);
+}
+
+static int
+proc_stop(struct proc_handle *phdl)
+{
+ int status;
+
+ if (kill(proc_getpid(phdl), SIGSTOP) == -1) {
+ DPRINTF("kill %d", proc_getpid(phdl));
+ return (-1);
+ } else if (waitpid(proc_getpid(phdl), &status, WSTOPPED) == -1) {
+ DPRINTF("waitpid %d", proc_getpid(phdl));
+ return (-1);
+ } else if (!WIFSTOPPED(status)) {
+ DPRINTFX("waitpid: unexpected status 0x%x", status);
+ return (-1);
+ }
+
+ return (0);
+}
+
int
proc_bkptset(struct proc_handle *phdl, uintptr_t address,
unsigned long *saved)
{
struct ptrace_io_desc piod;
unsigned long paddr, caddr;
+ int ret = 0;
*saved = 0;
if (phdl->status == PS_DEAD || phdl->status == PS_UNDEAD ||
@@ -68,6 +96,12 @@ proc_bkptset(struct proc_handle *phdl, uintptr_t address,
return (-1);
}
+ DPRINTFX("adding breakpoint at 0x%lx", address);
+
+ if (phdl->status != PS_STOP)
+ if (proc_stop(phdl) != 0)
+ return (-1);
+
/*
* Read the original instruction.
*/
@@ -78,9 +112,10 @@ proc_bkptset(struct proc_handle *phdl, uintptr_t address,
piod.piod_addr = &paddr;
piod.piod_len = BREAKPOINT_INSTR_SZ;
if (ptrace(PT_IO, proc_getpid(phdl), (caddr_t)&piod, 0) < 0) {
- DPRINTF("ERROR: couldn't read instruction at address 0x%" PRIuPTR,
- address);
- return (-1);
+ DPRINTF("ERROR: couldn't read instruction at address 0x%"
+ PRIuPTR, address);
+ ret = -1;
+ goto done;
}
*saved = paddr;
/*
@@ -93,12 +128,18 @@ proc_bkptset(struct proc_handle *phdl, uintptr_t address,
piod.piod_addr = &paddr;
piod.piod_len = BREAKPOINT_INSTR_SZ;
if (ptrace(PT_IO, proc_getpid(phdl), (caddr_t)&piod, 0) < 0) {
- warn("ERROR: couldn't write instruction at address 0x%" PRIuPTR,
- address);
- return (-1);
+ DPRINTF("ERROR: couldn't write instruction at address 0x%"
+ PRIuPTR, address);
+ ret = -1;
+ goto done;
}
- return (0);
+done:
+ if (phdl->status != PS_STOP)
+ /* Restart the process if we had to stop it. */
+ proc_cont(phdl);
+
+ return (ret);
}
int
@@ -107,13 +148,20 @@ proc_bkptdel(struct proc_handle *phdl, uintptr_t address,
{
struct ptrace_io_desc piod;
unsigned long paddr, caddr;
+ int ret = 0;
if (phdl->status == PS_DEAD || phdl->status == PS_UNDEAD ||
phdl->status == PS_IDLE) {
errno = ENOENT;
return (-1);
}
- DPRINTF("removing breakpoint at 0x%lx\n", address);
+
+ DPRINTFX("removing breakpoint at 0x%lx", address);
+
+ if (phdl->status != PS_STOP)
+ if (proc_stop(phdl) != 0)
+ return (-1);
+
/*
* Overwrite the breakpoint instruction that we setup previously.
*/
@@ -124,12 +172,16 @@ proc_bkptdel(struct proc_handle *phdl, uintptr_t address,
piod.piod_addr = &paddr;
piod.piod_len = BREAKPOINT_INSTR_SZ;
if (ptrace(PT_IO, proc_getpid(phdl), (caddr_t)&piod, 0) < 0) {
- DPRINTF("ERROR: couldn't write instruction at address 0x%" PRIuPTR,
- address);
- return (-1);
+ DPRINTF("ERROR: couldn't write instruction at address 0x%"
+ PRIuPTR, address);
+ ret = -1;
}
+
+ if (phdl->status != PS_STOP)
+ /* Restart the process if we had to stop it. */
+ proc_cont(phdl);
- return (0);
+ return (ret);
}
/*
@@ -153,12 +205,12 @@ proc_bkptexec(struct proc_handle *phdl, unsigned long saved)
int status;
if (proc_regget(phdl, REG_PC, &pc) < 0) {
- warn("ERROR: couldn't get PC register");
+ DPRINTFX("ERROR: couldn't get PC register");
return (-1);
}
proc_bkptregadj(&pc);
if (proc_bkptdel(phdl, pc, saved) < 0) {
- warn("ERROR: couldn't delete breakpoint");
+ DPRINTFX("ERROR: couldn't delete breakpoint");
return (-1);
}
/*
@@ -167,13 +219,13 @@ proc_bkptexec(struct proc_handle *phdl, unsigned long saved)
*/
proc_regset(phdl, REG_PC, pc);
if (ptrace(PT_STEP, proc_getpid(phdl), (caddr_t)1, 0) < 0) {
- warn("ERROR: ptrace step failed");
+ DPRINTFX("ERROR: ptrace step failed");
return (-1);
}
proc_wstatus(phdl);
status = proc_getwstat(phdl);
if (!WIFSTOPPED(status)) {
- warn("ERROR: don't know why process stopped");
+ DPRINTFX("ERROR: don't know why process stopped");
return (-1);
}
/*
@@ -181,7 +233,7 @@ proc_bkptexec(struct proc_handle *phdl, unsigned long saved)
* the same as the one that we were passed in.
*/
if (proc_bkptset(phdl, pc, &samesaved) < 0) {
- warn("ERROR: couldn't restore breakpoint");
+ DPRINTFX("ERROR: couldn't restore breakpoint");
return (-1);
}
assert(samesaved == saved);
OpenPOWER on IntegriCloud