trace.c revision 89a536028ab3b699b7f953b6b0fd7607917fc303
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
15static int fork_exec_syscalls[][5] = {
16	{
17#ifdef __NR_fork
18	 __NR_fork,
19#else
20	 -1,
21#endif
22#ifdef __NR_clone
23	 __NR_clone,
24#else
25	 -1,
26#endif
27#ifdef __NR_clone2
28	 __NR_clone2,
29#else
30	 -1,
31#endif
32#ifdef __NR_vfork
33	 __NR_vfork,
34#else
35	 -1,
36#endif
37#ifdef __NR_execve
38	 __NR_execve,
39#else
40	 -1,
41#endif
42	 }
43#ifdef FORK_EXEC_SYSCALLS
44	FORK_EXEC_SYSCALLS
45#endif
46};
47
48/* Returns 1 if the sysnum may make a new child to be created
49 * (ie, with fork() or clone())
50 * Returns 0 otherwise.
51 */
52int fork_p(struct process *proc, int sysnum)
53{
54	unsigned int i;
55	if (proc->personality
56	    >= sizeof fork_exec_syscalls / sizeof(fork_exec_syscalls[0]))
57		return 0;
58	for (i = 0; i < sizeof(fork_exec_syscalls[0]) / sizeof(int) - 1; ++i)
59		if (sysnum == fork_exec_syscalls[proc->personality][i])
60			return 1;
61	return 0;
62}
63
64/* Returns 1 if the sysnum may make the process exec other program
65 */
66int exec_p(struct process *proc, int sysnum)
67{
68	int i;
69	if (proc->personality
70	    >= sizeof fork_exec_syscalls / sizeof(fork_exec_syscalls[0]))
71		return 0;
72	i = sizeof(fork_exec_syscalls[0]) / sizeof(int) - 1;
73	if (sysnum == fork_exec_syscalls[proc->personality][i])
74		return 1;
75	return 0;
76}
77
78void trace_me(void)
79{
80	if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) {
81		perror("PTRACE_TRACEME");
82		exit(1);
83	}
84}
85
86int trace_pid(pid_t pid)
87{
88	if (ptrace(PTRACE_ATTACH, pid, 1, 0) < 0) {
89		return -1;
90	}
91
92	/* man ptrace: PTRACE_ATTACH attaches to the process specified
93	   in pid.  The child is sent a SIGSTOP, but will not
94	   necessarily have stopped by the completion of this call;
95	   use wait() to wait for the child to stop. */
96	if (waitpid (pid, NULL, 0) != pid) {
97		perror ("trace_pid: waitpid");
98		exit (1);
99	}
100
101	return 0;
102}
103
104void trace_set_options(struct process *proc, pid_t pid)
105{
106#ifndef PTRACE_SETOPTIONS
107#define PTRACE_SETOPTIONS 0x4200
108#endif
109#ifndef PTRACE_OLDSETOPTIONS
110#define PTRACE_OLDSETOPTIONS 21
111#endif
112#ifndef PTRACE_O_TRACESYSGOOD
113#define PTRACE_O_TRACESYSGOOD 0x00000001
114#endif
115	if (proc->tracesysgood & 0x80)
116		return;
117	if (ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_TRACESYSGOOD) < 0 &&
118	    ptrace(PTRACE_OLDSETOPTIONS, pid, 0, PTRACE_O_TRACESYSGOOD) < 0) {
119		perror("PTRACE_SETOPTIONS");
120		return;
121	}
122	proc->tracesysgood |= 0x80;
123}
124
125void untrace_pid(pid_t pid)
126{
127	ptrace(PTRACE_DETACH, pid, 1, 0);
128}
129
130void continue_after_signal(pid_t pid, int signum)
131{
132	/* We should always trace syscalls to be able to control fork(), clone(), execve()... */
133	ptrace(PTRACE_SYSCALL, pid, 0, signum);
134}
135
136void continue_process(pid_t pid)
137{
138	continue_after_signal(pid, 0);
139}
140
141void continue_enabling_breakpoint(pid_t pid, struct breakpoint *sbp)
142{
143	enable_breakpoint(pid, sbp);
144	continue_process(pid);
145}
146
147void continue_after_breakpoint(struct process *proc, struct breakpoint *sbp)
148{
149	if (sbp->enabled)
150		disable_breakpoint(proc->pid, sbp);
151	set_instruction_pointer(proc, sbp->addr);
152	if (sbp->enabled == 0) {
153		continue_process(proc->pid);
154	} else {
155		proc->breakpoint_being_enabled = sbp;
156#if defined __sparc__  || defined __ia64___
157		/* we don't want to singlestep here */
158		continue_process(proc->pid);
159#else
160		ptrace(PTRACE_SINGLESTEP, proc->pid, 0, 0);
161#endif
162	}
163}
164
165/* Read a single long from the process's memory address 'addr' */
166int umovelong(struct process *proc, void *addr, long *result)
167{
168	long pointed_to;
169
170        errno = 0;
171        pointed_to = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0);
172        if (pointed_to == -1 && errno)
173          return -errno;
174
175        *result = pointed_to;
176        return 0;
177}
178
179/* Read a series of bytes starting at the process's memory address
180   'addr' and continuing until a NUL ('\0') is seen or 'len' bytes
181   have been read.
182*/
183int umovestr(struct process *proc, void *addr, int len, void *laddr)
184{
185	union {
186		long a;
187		char c[sizeof(long)];
188	} a;
189	int i;
190	int offset = 0;
191
192	while (offset < len) {
193		a.a = ptrace(PTRACE_PEEKTEXT, proc->pid, addr + offset, 0);
194		for (i = 0; i < sizeof(long); i++) {
195			if (a.c[i] && offset + (signed)i < len) {
196				*(char *)(laddr + offset + i) = a.c[i];
197			} else {
198				*(char *)(laddr + offset + i) = '\0';
199				return 0;
200			}
201		}
202		offset += sizeof(long);
203	}
204	*(char *)(laddr + offset) = '\0';
205	return 0;
206}
207