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