blob: 670a7003d4b68275b72a9165e11e97e2cbaf2c2c [file] [log] [blame]
Juan Cespedes5e01f651998-03-08 22:31:44 +01001#include <stdio.h>
Juan Cespedes504a3852003-02-04 23:24:38 +01002#include <stdlib.h>
Juan Cespedes1fe93d51998-03-13 00:29:21 +01003#include <string.h>
4#include <errno.h>
Juan Cespedes8f8282f2002-03-03 18:58:40 +01005#include <unistd.h>
Juan Cespedes5e01f651998-03-08 22:31:44 +01006#include <sys/types.h>
Petr Machata89a53602007-01-25 18:05:44 +01007#include <sys/wait.h>
Juan Cespedes5c3fe062004-06-14 18:08:37 +02008#include "ptrace.h"
Juan Cespedes5e01f651998-03-08 22:31:44 +01009#include <asm/unistd.h>
10
11#include "ltrace.h"
12#include "options.h"
Ian Wienand9a2ad352006-02-20 22:44:45 +010013#include "sysdep.h"
Petr Machata55ed83b2007-05-17 16:24:15 +020014#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 */
Ian Wienand9a2ad352006-02-20 22:44:45 +010042
43static int fork_exec_syscalls[][5] = {
Ian Wienand2d45b1a2006-02-20 22:48:07 +010044 {
Ian Wienand9a2ad352006-02-20 22:44:45 +010045#ifdef __NR_fork
Ian Wienand2d45b1a2006-02-20 22:48:07 +010046 __NR_fork,
Ian Wienand9a2ad352006-02-20 22:44:45 +010047#else
Ian Wienand2d45b1a2006-02-20 22:48:07 +010048 -1,
Ian Wienand9a2ad352006-02-20 22:44:45 +010049#endif
50#ifdef __NR_clone
Ian Wienand2d45b1a2006-02-20 22:48:07 +010051 __NR_clone,
Ian Wienand9a2ad352006-02-20 22:44:45 +010052#else
Ian Wienand2d45b1a2006-02-20 22:48:07 +010053 -1,
Ian Wienand9a2ad352006-02-20 22:44:45 +010054#endif
55#ifdef __NR_clone2
Ian Wienand2d45b1a2006-02-20 22:48:07 +010056 __NR_clone2,
Ian Wienand9a2ad352006-02-20 22:44:45 +010057#else
Ian Wienand2d45b1a2006-02-20 22:48:07 +010058 -1,
Ian Wienand9a2ad352006-02-20 22:44:45 +010059#endif
60#ifdef __NR_vfork
Ian Wienand2d45b1a2006-02-20 22:48:07 +010061 __NR_vfork,
Ian Wienand9a2ad352006-02-20 22:44:45 +010062#else
Ian Wienand2d45b1a2006-02-20 22:48:07 +010063 -1,
Ian Wienand9a2ad352006-02-20 22:44:45 +010064#endif
65#ifdef __NR_execve
Ian Wienand2d45b1a2006-02-20 22:48:07 +010066 __NR_execve,
Ian Wienand9a2ad352006-02-20 22:44:45 +010067#else
Ian Wienand2d45b1a2006-02-20 22:48:07 +010068 -1,
Ian Wienand9a2ad352006-02-20 22:44:45 +010069#endif
Ian Wienand2d45b1a2006-02-20 22:48:07 +010070 }
Ian Wienand9a2ad352006-02-20 22:44:45 +010071#ifdef FORK_EXEC_SYSCALLS
Ian Wienand2d45b1a2006-02-20 22:48:07 +010072 FORK_EXEC_SYSCALLS
Ian Wienand9a2ad352006-02-20 22:44:45 +010073#endif
74};
Juan Cespedes5e01f651998-03-08 22:31:44 +010075
Luis Machado55c5feb2008-03-12 15:56:01 +010076#ifdef ARCH_HAVE_UMOVELONG
Juan Cespedesa8909f72009-04-28 20:02:41 +020077extern int arch_umovelong (Process *, void *, long *, arg_type_info *);
Juan Cespedesf1350522008-12-16 18:19:58 +010078int
Juan Cespedesa8909f72009-04-28 20:02:41 +020079umovelong (Process *proc, void *addr, long *result, arg_type_info *info) {
Luis Machado55c5feb2008-03-12 15:56:01 +010080 return arch_umovelong (proc, addr, result, info);
81}
82#else
83/* Read a single long from the process's memory address 'addr' */
Juan Cespedesf1350522008-12-16 18:19:58 +010084int
Juan Cespedesa8909f72009-04-28 20:02:41 +020085umovelong (Process *proc, void *addr, long *result, arg_type_info *info) {
Luis Machado55c5feb2008-03-12 15:56:01 +010086 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
Juan Cespedes81690ef1998-03-13 19:31:29 +010099/* Returns 1 if the sysnum may make a new child to be created
100 * (ie, with fork() or clone())
101 * Returns 0 otherwise.
102 */
Juan Cespedesf1350522008-12-16 18:19:58 +0100103int
Juan Cespedesa8909f72009-04-28 20:02:41 +0200104fork_p(Process *proc, int sysnum) {
Paul Gilliam3f1219f2006-04-24 18:25:38 +0200105 unsigned int i;
Ian Wienand9a2ad352006-02-20 22:44:45 +0100106 if (proc->personality
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100107 >= 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)
Ian Wienand9a2ad352006-02-20 22:44:45 +0100110 if (sysnum == fork_exec_syscalls[proc->personality][i])
111 return 1;
112 return 0;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100113}
114
Juan Cespedes81690ef1998-03-13 19:31:29 +0100115/* Returns 1 if the sysnum may make the process exec other program
116 */
Juan Cespedesf1350522008-12-16 18:19:58 +0100117int
Juan Cespedesa8909f72009-04-28 20:02:41 +0200118exec_p(Process *proc, int sysnum) {
Ian Wienand9a2ad352006-02-20 22:44:45 +0100119 int i;
120 if (proc->personality
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100121 >= sizeof fork_exec_syscalls / sizeof(fork_exec_syscalls[0]))
122 return 0;
123 i = sizeof(fork_exec_syscalls[0]) / sizeof(int) - 1;
Ian Wienand9a2ad352006-02-20 22:44:45 +0100124 if (sysnum == fork_exec_syscalls[proc->personality][i])
125 return 1;
126 return 0;
Juan Cespedes81690ef1998-03-13 19:31:29 +0100127}
128
Petr Machata55ed83b2007-05-17 16:24:15 +0200129/* Check that we just hit an exec.
130 */
Juan Cespedesf1350522008-12-16 18:19:58 +0100131int
Juan Cespedesa8909f72009-04-28 20:02:41 +0200132was_exec(Process *proc, int status) {
Petr Machata55ed83b2007-05-17 16:24:15 +0200133 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
Juan Cespedesf1350522008-12-16 18:19:58 +0100162void
163trace_me(void) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100164 if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100165 perror("PTRACE_TRACEME");
166 exit(1);
167 }
168}
169
Juan Cespedesf1350522008-12-16 18:19:58 +0100170int
171trace_pid(pid_t pid) {
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100172 if (ptrace(PTRACE_ATTACH, pid, 1, 0) < 0) {
Juan Cespedes273ea6d1998-03-14 23:02:40 +0100173 return -1;
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100174 }
Petr Machata89a53602007-01-25 18:05:44 +0100175
Juan Cespedes714ee9d2009-04-07 13:28:54 +0200176 /* man ptrace: PTRACE_ATTACH attaches to the process specified
177 in pid. The child is sent a SIGSTOP, but will not
178 necessarily have stopped by the completion of this call;
179 use wait() to wait for the child to stop. */
180 if (waitpid (pid, NULL, 0) != pid) {
181 perror ("trace_pid: waitpid");
182 exit (1);
183 }
184
Juan Cespedes273ea6d1998-03-14 23:02:40 +0100185 return 0;
186}
187
Juan Cespedesf1350522008-12-16 18:19:58 +0100188void
Juan Cespedesa8909f72009-04-28 20:02:41 +0200189trace_set_options(Process *proc, pid_t pid) {
Ian Wienand9a2ad352006-02-20 22:44:45 +0100190 if (proc->tracesysgood & 0x80)
191 return;
Petr Machata55ed83b2007-05-17 16:24:15 +0200192
Juan Cespedes1e583132009-04-07 18:17:11 +0200193 long options = PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEFORK |
194 PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE |
195 PTRACE_O_TRACEEXEC;
Petr Machata55ed83b2007-05-17 16:24:15 +0200196 if (ptrace(PTRACE_SETOPTIONS, pid, 0, options) < 0 &&
197 ptrace(PTRACE_OLDSETOPTIONS, pid, 0, options) < 0) {
Ian Wienand9a2ad352006-02-20 22:44:45 +0100198 perror("PTRACE_SETOPTIONS");
199 return;
200 }
201 proc->tracesysgood |= 0x80;
202}
203
Juan Cespedesf1350522008-12-16 18:19:58 +0100204void
205untrace_pid(pid_t pid) {
Juan Cespedes273ea6d1998-03-14 23:02:40 +0100206 ptrace(PTRACE_DETACH, pid, 1, 0);
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100207}
208
Juan Cespedesf1350522008-12-16 18:19:58 +0100209void
210continue_after_signal(pid_t pid, int signum) {
Juan Cespedesa8909f72009-04-28 20:02:41 +0200211 Process *proc;
Juan Cespedese74c80d2009-02-11 11:32:31 +0100212
213 proc = pid2proc(pid);
214 if (proc && proc->breakpoint_being_enabled) {
215#if defined __sparc__ || defined __ia64___
216 ptrace(PTRACE_SYSCALL, pid, 0, signum);
217#else
218 ptrace(PTRACE_SINGLESTEP, pid, 0, signum);
219#endif
220 } else {
221 ptrace(PTRACE_SYSCALL, pid, 0, signum);
222 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100223}
224
Juan Cespedesf1350522008-12-16 18:19:58 +0100225void
226continue_process(pid_t pid) {
Juan Cespedese74c80d2009-02-11 11:32:31 +0100227 /* We always trace syscalls to control fork(), clone(), execve()... */
228
229 ptrace(PTRACE_SYSCALL, pid, 0, 0);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100230}
231
Juan Cespedesf1350522008-12-16 18:19:58 +0100232void
233continue_enabling_breakpoint(pid_t pid, struct breakpoint *sbp) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200234 enable_breakpoint(pid, sbp);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100235 continue_process(pid);
236}
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100237
Juan Cespedesf1350522008-12-16 18:19:58 +0100238void
Juan Cespedesa8909f72009-04-28 20:02:41 +0200239continue_after_breakpoint(Process *proc, struct breakpoint *sbp) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100240 if (sbp->enabled)
241 disable_breakpoint(proc->pid, sbp);
Juan Cespedes5c3fe062004-06-14 18:08:37 +0200242 set_instruction_pointer(proc, sbp->addr);
Juan Cespedes8f8282f2002-03-03 18:58:40 +0100243 if (sbp->enabled == 0) {
244 continue_process(proc->pid);
245 } else {
246 proc->breakpoint_being_enabled = sbp;
Ian Wienand9a2ad352006-02-20 22:44:45 +0100247#if defined __sparc__ || defined __ia64___
248 /* we don't want to singlestep here */
Juan Cespedes5c3fe062004-06-14 18:08:37 +0200249 continue_process(proc->pid);
250#else
Juan Cespedes8f8282f2002-03-03 18:58:40 +0100251 ptrace(PTRACE_SINGLESTEP, proc->pid, 0, 0);
Juan Cespedes5c3fe062004-06-14 18:08:37 +0200252#endif
Juan Cespedes8f8282f2002-03-03 18:58:40 +0100253 }
254}
255
Steve Fink7bafff02006-08-07 04:50:42 +0200256/* Read a series of bytes starting at the process's memory address
257 'addr' and continuing until a NUL ('\0') is seen or 'len' bytes
258 have been read.
259*/
Juan Cespedesf1350522008-12-16 18:19:58 +0100260int
Juan Cespedesa8909f72009-04-28 20:02:41 +0200261umovestr(Process *proc, void *addr, int len, void *laddr) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100262 union {
263 long a;
264 char c[sizeof(long)];
265 } a;
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100266 int i;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100267 int offset = 0;
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100268
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100269 while (offset < len) {
270 a.a = ptrace(PTRACE_PEEKTEXT, proc->pid, addr + offset, 0);
271 for (i = 0; i < sizeof(long); i++) {
Paul Gilliam3f1219f2006-04-24 18:25:38 +0200272 if (a.c[i] && offset + (signed)i < len) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100273 *(char *)(laddr + offset + i) = a.c[i];
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100274 } else {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100275 *(char *)(laddr + offset + i) = '\0';
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100276 return 0;
277 }
278 }
279 offset += sizeof(long);
280 }
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100281 *(char *)(laddr + offset) = '\0';
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100282 return 0;
283}