blob: 38b4839d6e3fef99fe019e677d6af8bcc1099553 [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
Juan Cespedes81690ef1998-03-13 19:31:29 +010076/* Returns 1 if the sysnum may make a new child to be created
77 * (ie, with fork() or clone())
78 * Returns 0 otherwise.
79 */
Ian Wienand2d45b1a2006-02-20 22:48:07 +010080int fork_p(struct process *proc, int sysnum)
81{
Paul Gilliam3f1219f2006-04-24 18:25:38 +020082 unsigned int i;
Ian Wienand9a2ad352006-02-20 22:44:45 +010083 if (proc->personality
Ian Wienand2d45b1a2006-02-20 22:48:07 +010084 >= 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)
Ian Wienand9a2ad352006-02-20 22:44:45 +010087 if (sysnum == fork_exec_syscalls[proc->personality][i])
88 return 1;
89 return 0;
Juan Cespedes5e01f651998-03-08 22:31:44 +010090}
91
Juan Cespedes81690ef1998-03-13 19:31:29 +010092/* Returns 1 if the sysnum may make the process exec other program
93 */
Ian Wienand2d45b1a2006-02-20 22:48:07 +010094int exec_p(struct process *proc, int sysnum)
95{
Ian Wienand9a2ad352006-02-20 22:44:45 +010096 int i;
97 if (proc->personality
Ian Wienand2d45b1a2006-02-20 22:48:07 +010098 >= sizeof fork_exec_syscalls / sizeof(fork_exec_syscalls[0]))
99 return 0;
100 i = sizeof(fork_exec_syscalls[0]) / sizeof(int) - 1;
Ian Wienand9a2ad352006-02-20 22:44:45 +0100101 if (sysnum == fork_exec_syscalls[proc->personality][i])
102 return 1;
103 return 0;
Juan Cespedes81690ef1998-03-13 19:31:29 +0100104}
105
Petr Machata55ed83b2007-05-17 16:24:15 +0200106/* 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
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100139void trace_me(void)
140{
141 if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100142 perror("PTRACE_TRACEME");
143 exit(1);
144 }
145}
146
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100147int trace_pid(pid_t pid)
148{
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100149 if (ptrace(PTRACE_ATTACH, pid, 1, 0) < 0) {
Juan Cespedes273ea6d1998-03-14 23:02:40 +0100150 return -1;
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100151 }
Petr Machata89a53602007-01-25 18:05:44 +0100152
Juan Cespedes273ea6d1998-03-14 23:02:40 +0100153 return 0;
154}
155
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100156void trace_set_options(struct process *proc, pid_t pid)
157{
Ian Wienand9a2ad352006-02-20 22:44:45 +0100158 if (proc->tracesysgood & 0x80)
159 return;
Petr Machata55ed83b2007-05-17 16:24:15 +0200160
161 long options = PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXEC;
162 if (ptrace(PTRACE_SETOPTIONS, pid, 0, options) < 0 &&
163 ptrace(PTRACE_OLDSETOPTIONS, pid, 0, options) < 0) {
Ian Wienand9a2ad352006-02-20 22:44:45 +0100164 perror("PTRACE_SETOPTIONS");
165 return;
166 }
167 proc->tracesysgood |= 0x80;
168}
169
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100170void untrace_pid(pid_t pid)
171{
Juan Cespedes273ea6d1998-03-14 23:02:40 +0100172 ptrace(PTRACE_DETACH, pid, 1, 0);
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100173}
174
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100175void continue_after_signal(pid_t pid, int signum)
176{
Juan Cespedes5e01f651998-03-08 22:31:44 +0100177 /* We should always trace syscalls to be able to control fork(), clone(), execve()... */
Juan Cespedes5916fda2002-02-25 00:19:21 +0100178 ptrace(PTRACE_SYSCALL, pid, 0, signum);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100179}
180
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100181void continue_process(pid_t pid)
182{
Juan Cespedes5e01f651998-03-08 22:31:44 +0100183 continue_after_signal(pid, 0);
184}
185
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100186void continue_enabling_breakpoint(pid_t pid, struct breakpoint *sbp)
187{
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200188 enable_breakpoint(pid, sbp);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100189 continue_process(pid);
190}
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100191
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100192void continue_after_breakpoint(struct process *proc, struct breakpoint *sbp)
193{
194 if (sbp->enabled)
195 disable_breakpoint(proc->pid, sbp);
Juan Cespedes5c3fe062004-06-14 18:08:37 +0200196 set_instruction_pointer(proc, sbp->addr);
Juan Cespedes8f8282f2002-03-03 18:58:40 +0100197 if (sbp->enabled == 0) {
198 continue_process(proc->pid);
199 } else {
200 proc->breakpoint_being_enabled = sbp;
Ian Wienand9a2ad352006-02-20 22:44:45 +0100201#if defined __sparc__ || defined __ia64___
202 /* we don't want to singlestep here */
Juan Cespedes5c3fe062004-06-14 18:08:37 +0200203 continue_process(proc->pid);
204#else
Juan Cespedes8f8282f2002-03-03 18:58:40 +0100205 ptrace(PTRACE_SINGLESTEP, proc->pid, 0, 0);
Juan Cespedes5c3fe062004-06-14 18:08:37 +0200206#endif
Juan Cespedes8f8282f2002-03-03 18:58:40 +0100207 }
208}
209
Steve Fink7bafff02006-08-07 04:50:42 +0200210/* Read a single long from the process's memory address 'addr' */
211int umovelong(struct process *proc, void *addr, long *result)
212{
213 long pointed_to;
214
215 errno = 0;
216 pointed_to = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0);
217 if (pointed_to == -1 && errno)
218 return -errno;
219
220 *result = pointed_to;
221 return 0;
222}
223
224/* Read a series of bytes starting at the process's memory address
225 'addr' and continuing until a NUL ('\0') is seen or 'len' bytes
226 have been read.
227*/
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100228int umovestr(struct process *proc, void *addr, int len, void *laddr)
229{
230 union {
231 long a;
232 char c[sizeof(long)];
233 } a;
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100234 int i;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100235 int offset = 0;
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100236
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100237 while (offset < len) {
238 a.a = ptrace(PTRACE_PEEKTEXT, proc->pid, addr + offset, 0);
239 for (i = 0; i < sizeof(long); i++) {
Paul Gilliam3f1219f2006-04-24 18:25:38 +0200240 if (a.c[i] && offset + (signed)i < len) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100241 *(char *)(laddr + offset + i) = a.c[i];
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100242 } else {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100243 *(char *)(laddr + offset + i) = '\0';
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100244 return 0;
245 }
246 }
247 offset += sizeof(long);
248 }
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100249 *(char *)(laddr + offset) = '\0';
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100250 return 0;
251}