trace.c revision f728123bd75a65a6a1536e198c3c30719e494e71
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <errno.h>
5#include <unistd.h>
6#include <sys/types.h>
7#include <sys/wait.h>
8#include "ptrace.h"
9#include <asm/unistd.h>
10
11#include "common.h"
12#include "options.h"
13#include "sysdep.h"
14#include "debug.h"
15
16/* If the system headers did not provide the constants, hard-code the normal
17   values.  */
18#ifndef PTRACE_EVENT_FORK
19
20#define PTRACE_OLDSETOPTIONS    21
21#define PTRACE_SETOPTIONS       0x4200
22#define PTRACE_GETEVENTMSG      0x4201
23
24/* options set using PTRACE_SETOPTIONS */
25#define PTRACE_O_TRACESYSGOOD   0x00000001
26#define PTRACE_O_TRACEFORK      0x00000002
27#define PTRACE_O_TRACEVFORK     0x00000004
28#define PTRACE_O_TRACECLONE     0x00000008
29#define PTRACE_O_TRACEEXEC      0x00000010
30#define PTRACE_O_TRACEVFORKDONE 0x00000020
31#define PTRACE_O_TRACEEXIT      0x00000040
32
33/* Wait extended result codes for the above trace options.  */
34#define PTRACE_EVENT_FORK       1
35#define PTRACE_EVENT_VFORK      2
36#define PTRACE_EVENT_CLONE      3
37#define PTRACE_EVENT_EXEC       4
38#define PTRACE_EVENT_VFORK_DONE 5
39#define PTRACE_EVENT_EXIT       6
40
41#endif /* PTRACE_EVENT_FORK */
42
43#ifdef ARCH_HAVE_UMOVELONG
44extern int arch_umovelong (Process *, void *, long *, arg_type_info *);
45int
46umovelong (Process *proc, void *addr, long *result, arg_type_info *info) {
47	return arch_umovelong (proc, addr, result, info);
48}
49#else
50/* Read a single long from the process's memory address 'addr' */
51int
52umovelong (Process *proc, void *addr, long *result, arg_type_info *info) {
53	long pointed_to;
54
55	errno = 0;
56	pointed_to = ptrace (PTRACE_PEEKTEXT, proc->pid, addr, 0);
57	if (pointed_to == -1 && errno)
58		return -errno;
59
60	*result = pointed_to;
61	return 0;
62}
63#endif
64
65void
66trace_me(void) {
67	debug(DEBUG_PROCESS, "trace_me: pid=%d\n", getpid());
68	if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) {
69		perror("PTRACE_TRACEME");
70		exit(1);
71	}
72}
73
74int
75trace_pid(pid_t pid) {
76	debug(DEBUG_PROCESS, "trace_pid: pid=%d\n", pid);
77	if (ptrace(PTRACE_ATTACH, pid, 1, 0) < 0) {
78		return -1;
79	}
80
81	/* man ptrace: PTRACE_ATTACH attaches to the process specified
82	   in pid.  The child is sent a SIGSTOP, but will not
83	   necessarily have stopped by the completion of this call;
84	   use wait() to wait for the child to stop. */
85	if (waitpid (pid, NULL, 0) != pid) {
86		perror ("trace_pid: waitpid");
87		exit (1);
88	}
89
90	return 0;
91}
92
93void
94trace_set_options(Process *proc, pid_t pid) {
95	if (proc->tracesysgood & 0x80)
96		return;
97
98	debug(DEBUG_PROCESS, "trace_set_options: pid=%d\n", pid);
99
100	long options = PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEFORK |
101		PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE |
102		PTRACE_O_TRACEEXEC;
103	if (ptrace(PTRACE_SETOPTIONS, pid, 0, options) < 0 &&
104	    ptrace(PTRACE_OLDSETOPTIONS, pid, 0, options) < 0) {
105		perror("PTRACE_SETOPTIONS");
106		return;
107	}
108	proc->tracesysgood |= 0x80;
109}
110
111void
112untrace_pid(pid_t pid) {
113	debug(DEBUG_PROCESS, "untrace_pid: pid=%d\n", pid);
114	ptrace(PTRACE_DETACH, pid, 1, 0);
115}
116
117void
118continue_after_signal(pid_t pid, int signum) {
119	Process *proc;
120
121	debug(DEBUG_PROCESS, "continue_after_signal: pid=%d, signum=%d", pid, signum);
122
123	proc = pid2proc(pid);
124	if (proc && proc->breakpoint_being_enabled) {
125#if defined __sparc__  || defined __ia64___
126		ptrace(PTRACE_SYSCALL, pid, 0, signum);
127#else
128		ptrace(PTRACE_SINGLESTEP, pid, 0, signum);
129#endif
130	} else {
131		ptrace(PTRACE_SYSCALL, pid, 0, signum);
132	}
133}
134
135void
136continue_process(pid_t pid) {
137	/* We always trace syscalls to control fork(), clone(), execve()... */
138
139	debug(DEBUG_PROCESS, "continue_process: pid=%d", pid);
140
141	ptrace(PTRACE_SYSCALL, pid, 0, 0);
142}
143
144void
145continue_enabling_breakpoint(pid_t pid, Breakpoint *sbp) {
146	enable_breakpoint(pid, sbp);
147	continue_process(pid);
148}
149
150void
151continue_after_breakpoint(Process *proc, Breakpoint *sbp) {
152	if (sbp->enabled)
153		disable_breakpoint(proc->pid, sbp);
154	set_instruction_pointer(proc, sbp->addr);
155	if (sbp->enabled == 0) {
156		continue_process(proc->pid);
157	} else {
158		debug(DEBUG_PROCESS, "continue_after_breakpoint: pid=%d, addr=%p", proc->pid, sbp->addr);
159		proc->breakpoint_being_enabled = sbp;
160#if defined __sparc__  || defined __ia64___
161		/* we don't want to singlestep here */
162		continue_process(proc->pid);
163#else
164		ptrace(PTRACE_SINGLESTEP, proc->pid, 0, 0);
165#endif
166	}
167}
168
169/* Read a series of bytes starting at the process's memory address
170   'addr' and continuing until a NUL ('\0') is seen or 'len' bytes
171   have been read.
172*/
173int
174umovestr(Process *proc, void *addr, int len, void *laddr) {
175	union {
176		long a;
177		char c[sizeof(long)];
178	} a;
179	int i;
180	int offset = 0;
181
182	while (offset < len) {
183		a.a = ptrace(PTRACE_PEEKTEXT, proc->pid, addr + offset, 0);
184		for (i = 0; i < sizeof(long); i++) {
185			if (a.c[i] && offset + (signed)i < len) {
186				*(char *)(laddr + offset + i) = a.c[i];
187			} else {
188				*(char *)(laddr + offset + i) = '\0';
189				return 0;
190			}
191		}
192		offset += sizeof(long);
193	}
194	*(char *)(laddr + offset) = '\0';
195	return 0;
196}
197