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