2
* Copyright (C) 2010 Simon Kagstrom, Thomas Neumann
4
* See COPYING for license details
6
* Taken from bcov:Debugger.cpp:
8
* Copyright (C) 2007 Thomas Neumann
10
#include <sys/ptrace.h>
13
#include <sys/errno.h>
18
static pid_t active_child, child;
20
static unsigned char peek_byte(const void *ptr)
22
unsigned long addr = (unsigned long)ptr;
23
unsigned long aligned = (addr / sizeof(long)) * sizeof(long);
24
union { long val; unsigned char data[sizeof(long)]; } data;
26
data.val = ptrace(PTRACE_PEEKTEXT, active_child, aligned, 0);
28
return data.data[addr - aligned];
31
static void poke_byte(unsigned long addr, unsigned char c)
33
unsigned long aligned = (addr / sizeof(long)) * sizeof(long);
34
union { long val; unsigned char data[sizeof(long)]; } data;
36
data.val = ptrace(PTRACE_PEEKTEXT, active_child, aligned, 0);
37
data.data[addr - aligned] = c;
39
ptrace(PTRACE_POKETEXT, active_child, aligned, data.val);
42
static void *ptrace_get_ip(void)
44
struct user_regs_struct regs;
46
memset(®s, 0, sizeof(regs));
47
ptrace(PTRACE_GETREGS, active_child, 0, ®s);
49
#if defined(__x86_64__)
50
return (void*)(regs.rip);
51
#elif defined(__i386__)
52
return (void*)(regs.eip);
54
#error specify how to read the IP
58
void* ptrace_get_ip_before_trap(void)
60
#if defined(__x86_64__) || defined(__i386__)
61
return (char*)(ptrace_get_ip()) - 1;
63
#error specify how to adjust the IP after a breakpoint
67
static void ptrace_setup_breakpoints(struct kc *kc)
73
g_hash_table_iter_init(&iter, kc->addrs);
74
while (g_hash_table_iter_next(&iter,
75
(gpointer*)&key, (gpointer*)&addr)) {
76
uint8_t old_byte = peek_byte((void *)addr->addr);
78
addr->saved_code = old_byte;
79
#if defined(__x86_64__)||defined(__i386__)
80
poke_byte(addr->addr, 0xCC);
82
#error specify how to set a breakpoint
87
void ptrace_eliminate_breakpoint(struct kc_addr *addr)
89
struct user_regs_struct regs;
90
memset(®s, 0, sizeof(regs));
93
ptrace(PTRACE_GETREGS, active_child, 0, ®s);
94
#if defined(__x86_64__)
95
ptr = (unsigned long)(--regs.rip);
96
#elif defined(__i386__)
97
ptr = (unsigned long)(--regs.eip);
99
#error specify how to adjust the IP after a breakpoint
101
ptrace(PTRACE_SETREGS, active_child, 0, ®s);
103
poke_byte(ptr, addr->saved_code);
104
kc_addr_register_hit(addr);
113
static int do_ptrace_run(struct kc *kc)
115
// Continue the stopped child
116
ptrace(PTRACE_CONT, active_child, 0, 0);
122
pid_t r = waitpid(-1, &status, __WALL);
124
// Got no one? Child probably died
130
if (WIFSTOPPED(status)) {
132
if (WSTOPSIG(status) == SIGTRAP)
134
// No, deliver it directly
135
ptrace(PTRACE_CONT, active_child, 0, WSTOPSIG(status));
139
if (WIFSIGNALED(status) || WIFEXITED(status)) {
140
if (active_child == child)
145
if (WIFSTOPPED(status)) {
146
// A new clone? Ignore the stop event
147
if ((status >> 8) == PTRACE_EVENT_CLONE) {
148
ptrace(PTRACE_CONT, active_child, 0, 0);
151
// Hm, why did we stop? Ignore the event and continue
152
ptrace(PTRACE_CONT, active_child, 0, 0);
157
return PT_CODE_ERROR;
161
static void ptrace_run_debugger(struct kc *kc)
164
int err = do_ptrace_run(kc);
168
fprintf(stderr, "Error while tracing\n");
173
void *where = ptrace_get_ip_before_trap();
174
struct kc_addr *addr = kc_lookup_addr(kc, (unsigned long)where);
177
ptrace_eliminate_breakpoint(addr);
184
static pid_t fork_child(const char *executable, char *const argv[])
186
/* Basic check first */
187
if (access(executable, X_OK) != 0)
190
/* Executable exists, try to launch it */
191
if ((child = fork()) == 0) {
193
/* And launch the process */
194
ptrace(PTRACE_TRACEME, 0, 0, 0);
195
execv(executable, argv);
205
/* Wait for the initial stop */
207
if ((waitpid(child, &status, 0) == -1) || (!WIFSTOPPED(status)))
209
ptrace(PTRACE_SETOPTIONS, child, 0, PTRACE_O_TRACECLONE | PTRACE_O_TRACEFORK);
216
int ptrace_run(struct kc *kc, char *const argv[])
218
active_child = fork_child(argv[0], &argv[0]);
220
if (active_child < 0) {
221
fprintf(stderr, "Can't fork child!\n");
225
ptrace_setup_breakpoints(kc);
227
ptrace_run_debugger(kc);
232
int ptrace_pid_run(struct kc *kc, pid_t pid)
234
active_child = child = pid;
237
ptrace(PTRACE_ATTACH, active_child, 0, 0);
239
const char *err = strerror(errno);
241
fprintf(stderr, "Can't attach to %d. Error %s\n", pid, err);
244
ptrace(PTRACE_SETOPTIONS, child, 0, PTRACE_O_TRACECLONE | PTRACE_O_TRACEFORK);
246
ptrace_setup_breakpoints(kc);
248
ptrace_run_debugger(kc);
253
int ptrace_detach(struct kc *kc)
259
/* Eliminate all unhit breakpoints */
260
g_hash_table_iter_init(&iter, kc->addrs);
261
while (g_hash_table_iter_next(&iter, (gpointer*)&key, (gpointer*)&val)) {
263
ptrace_eliminate_breakpoint(val);
266
ptrace(PTRACE_DETACH, active_child, 0, 0);