trace.c revision 85f7d7616f2736de79f6b7f77bceedbc97c83406
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 "ltrace.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
43static int fork_exec_syscalls[][5] = {
44	{
45#ifdef __NR_fork
46	 __NR_fork,
47#else
48	 -1,
49#endif
50#ifdef __NR_clone
51	 __NR_clone,
52#else
53	 -1,
54#endif
55#ifdef __NR_clone2
56	 __NR_clone2,
57#else
58	 -1,
59#endif
60#ifdef __NR_vfork
61	 __NR_vfork,
62#else
63	 -1,
64#endif
65#ifdef __NR_execve
66	 __NR_execve,
67#else
68	 -1,
69#endif
70	 }
71#ifdef FORK_EXEC_SYSCALLS
72	FORK_EXEC_SYSCALLS
73#endif
74};
75
76#ifdef ARCH_HAVE_UMOVELONG
77extern int arch_umovelong (Process *, void *, long *, arg_type_info *);
78int
79umovelong (Process *proc, void *addr, long *result, arg_type_info *info) {
80	return arch_umovelong (proc, addr, result, info);
81}
82#else
83/* Read a single long from the process's memory address 'addr' */
84int
85umovelong (Process *proc, void *addr, long *result, arg_type_info *info) {
86	long pointed_to;
87
88	errno = 0;
89	pointed_to = ptrace (PTRACE_PEEKTEXT, proc->pid, addr, 0);
90	if (pointed_to == -1 && errno)
91		return -errno;
92
93	*result = pointed_to;
94	return 0;
95}
96#endif
97
98
99/* Returns 1 if the sysnum may make a new child to be created
100 * (ie, with fork() or clone())
101 * Returns 0 otherwise.
102 */
103int
104fork_p(Process *proc, int sysnum) {
105	unsigned int i;
106	if (proc->personality
107	    >= sizeof fork_exec_syscalls / sizeof(fork_exec_syscalls[0]))
108		return 0;
109	for (i = 0; i < sizeof(fork_exec_syscalls[0]) / sizeof(int) - 1; ++i)
110		if (sysnum == fork_exec_syscalls[proc->personality][i])
111			return 1;
112	return 0;
113}
114
115/* Returns 1 if the sysnum may make the process exec other program
116 */
117int
118exec_p(Process *proc, int sysnum) {
119	int i;
120	if (proc->personality
121	    >= sizeof fork_exec_syscalls / sizeof(fork_exec_syscalls[0]))
122		return 0;
123	i = sizeof(fork_exec_syscalls[0]) / sizeof(int) - 1;
124	if (sysnum == fork_exec_syscalls[proc->personality][i])
125		return 1;
126	return 0;
127}
128
129/* Check that we just hit an exec.
130 */
131int
132was_exec(Process *proc, int status) {
133	if (!WIFSTOPPED (status))
134		return 0;
135
136	if (WSTOPSIG (status) == SIGTRAP
137	    && (status >> 16) == PTRACE_EVENT_EXEC) {
138		debug (1, "detected exec (PTRACE_EVENT_EXEC)");
139		return 1;
140	}
141
142	if (WSTOPSIG (status) == SIGTRAP
143	    && proc->callstack_depth > 0) {
144		/* Check whether this SIGTRAP is received just after
145		   execve is called for this process.  Ideally we'd
146		   like to check that the exec succeeded, but e.g. on
147		   s390 we have no way of knowing, because return
148		   value is not set to -1 (as it should).  Never mind,
149		   reseting breakpoints for current process doesn't
150		   hurt. */
151		struct callstack_element *elem;
152		elem = &proc->callstack[proc->callstack_depth - 1];
153		if (elem && elem->is_syscall &&  exec_p(proc, elem->c_un.syscall)) {
154			debug (1, "detected exec (callstack)");
155			return 1;
156		}
157	}
158
159	return 0;
160}
161
162void
163trace_me(void) {
164	debug(DEBUG_PROCESS, "trace_me: pid=%d\n", getpid());
165	if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) {
166		perror("PTRACE_TRACEME");
167		exit(1);
168	}
169}
170
171int
172trace_pid(pid_t pid) {
173	debug(DEBUG_PROCESS, "trace_pid: pid=%d\n", pid);
174	if (ptrace(PTRACE_ATTACH, pid, 1, 0) < 0) {
175		return -1;
176	}
177
178	/* man ptrace: PTRACE_ATTACH attaches to the process specified
179	   in pid.  The child is sent a SIGSTOP, but will not
180	   necessarily have stopped by the completion of this call;
181	   use wait() to wait for the child to stop. */
182	if (waitpid (pid, NULL, 0) != pid) {
183		perror ("trace_pid: waitpid");
184		exit (1);
185	}
186
187	return 0;
188}
189
190void
191trace_set_options(Process *proc, pid_t pid) {
192	if (proc->tracesysgood & 0x80)
193		return;
194
195	debug(DEBUG_PROCESS, "trace_set_options: pid=%d\n", pid);
196
197	long options = PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEFORK |
198		PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE |
199		PTRACE_O_TRACEEXEC;
200	if (ptrace(PTRACE_SETOPTIONS, pid, 0, options) < 0 &&
201	    ptrace(PTRACE_OLDSETOPTIONS, pid, 0, options) < 0) {
202		perror("PTRACE_SETOPTIONS");
203		return;
204	}
205	proc->tracesysgood |= 0x80;
206}
207
208void
209untrace_pid(pid_t pid) {
210	debug(DEBUG_PROCESS, "untrace_pid: pid=%d\n", pid);
211	ptrace(PTRACE_DETACH, pid, 1, 0);
212}
213
214void
215continue_after_signal(pid_t pid, int signum) {
216	Process *proc;
217
218	debug(DEBUG_PROCESS, "continue_after_signal: pid=%d, signum=%d", pid, signum);
219
220	proc = pid2proc(pid);
221	if (proc && proc->breakpoint_being_enabled) {
222#if defined __sparc__  || defined __ia64___
223		ptrace(PTRACE_SYSCALL, pid, 0, signum);
224#else
225		ptrace(PTRACE_SINGLESTEP, pid, 0, signum);
226#endif
227	} else {
228		ptrace(PTRACE_SYSCALL, pid, 0, signum);
229	}
230}
231
232void
233continue_process(pid_t pid) {
234	/* We always trace syscalls to control fork(), clone(), execve()... */
235
236	debug(DEBUG_PROCESS, "continue_process: pid=%d", pid);
237
238	ptrace(PTRACE_SYSCALL, pid, 0, 0);
239}
240
241void
242continue_enabling_breakpoint(pid_t pid, Breakpoint *sbp) {
243	enable_breakpoint(pid, sbp);
244	continue_process(pid);
245}
246
247void
248continue_after_breakpoint(Process *proc, Breakpoint *sbp) {
249	if (sbp->enabled)
250		disable_breakpoint(proc->pid, sbp);
251	set_instruction_pointer(proc, sbp->addr);
252	if (sbp->enabled == 0) {
253		continue_process(proc->pid);
254	} else {
255		debug(DEBUG_PROCESS, "continue_after_breakpoint: pid=%d, addr=%p", proc->pid, sbp->addr);
256		proc->breakpoint_being_enabled = sbp;
257#if defined __sparc__  || defined __ia64___
258		/* we don't want to singlestep here */
259		continue_process(proc->pid);
260#else
261		ptrace(PTRACE_SINGLESTEP, proc->pid, 0, 0);
262#endif
263	}
264}
265
266/* Read a series of bytes starting at the process's memory address
267   'addr' and continuing until a NUL ('\0') is seen or 'len' bytes
268   have been read.
269*/
270int
271umovestr(Process *proc, void *addr, int len, void *laddr) {
272	union {
273		long a;
274		char c[sizeof(long)];
275	} a;
276	int i;
277	int offset = 0;
278
279	while (offset < len) {
280		a.a = ptrace(PTRACE_PEEKTEXT, proc->pid, addr + offset, 0);
281		for (i = 0; i < sizeof(long); i++) {
282			if (a.c[i] && offset + (signed)i < len) {
283				*(char *)(laddr + offset + i) = a.c[i];
284			} else {
285				*(char *)(laddr + offset + i) = '\0';
286				return 0;
287			}
288		}
289		offset += sizeof(long);
290	}
291	*(char *)(laddr + offset) = '\0';
292	return 0;
293}
294