trace.c revision 9a2ad351a1c3215dc596ff3e2e3fd4bc24445a6b
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
43FORK_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
52fork_p(struct process * proc, int sysnum) {
53	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
66exec_p(struct process * proc, int sysnum) {
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
78trace_me(void) {
79	if (ptrace(PTRACE_TRACEME, 0, 1, 0)<0) {
80		perror("PTRACE_TRACEME");
81		exit(1);
82	}
83}
84
85int
86trace_pid(pid_t pid) {
87	if (ptrace(PTRACE_ATTACH, pid, 1, 0) < 0) {
88		return -1;
89	}
90	return 0;
91}
92
93void
94trace_set_options(struct process * proc, pid_t pid) {
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
115untrace_pid(pid_t pid) {
116	ptrace(PTRACE_DETACH, pid, 1, 0);
117}
118
119void
120continue_after_signal(pid_t pid, int signum) {
121	/* We should always trace syscalls to be able to control fork(), clone(), execve()... */
122	ptrace(PTRACE_SYSCALL, pid, 0, signum);
123}
124
125void
126continue_process(pid_t pid) {
127	continue_after_signal(pid, 0);
128}
129
130void
131continue_enabling_breakpoint(pid_t pid, struct breakpoint * sbp) {
132	enable_breakpoint(pid, sbp);
133	continue_process(pid);
134}
135
136void
137continue_after_breakpoint(struct process *proc, struct breakpoint * sbp) {
138	if (sbp->enabled) disable_breakpoint(proc->pid, sbp);
139	set_instruction_pointer(proc, sbp->addr);
140	if (sbp->enabled == 0) {
141		continue_process(proc->pid);
142	} else {
143		proc->breakpoint_being_enabled = sbp;
144#if defined __sparc__  || defined __ia64___
145		/* we don't want to singlestep here */
146		continue_process(proc->pid);
147#else
148		ptrace(PTRACE_SINGLESTEP, proc->pid, 0, 0);
149#endif
150	}
151}
152
153int
154umovestr(struct process * proc, void * addr, int len, void * laddr) {
155	union { long a; char c[sizeof(long)]; } a;
156	int i;
157	int offset=0;
158
159	while(offset<len) {
160		a.a = ptrace(PTRACE_PEEKTEXT, proc->pid, addr+offset, 0);
161		for(i=0; i<sizeof(long); i++) {
162			if (a.c[i] && offset+i < len) {
163				*(char *)(laddr+offset+i) = a.c[i];
164			} else {
165				*(char *)(laddr+offset+i) = '\0';
166				return 0;
167			}
168		}
169		offset += sizeof(long);
170	}
171	*(char *)(laddr+offset) = '\0';
172	return 0;
173}
174