blob: 0ea9b027f95eeb9a6173ba15cc0117c110ba1333 [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"
14
15static int fork_exec_syscalls[][5] = {
Ian Wienand2d45b1a2006-02-20 22:48:07 +010016 {
Ian Wienand9a2ad352006-02-20 22:44:45 +010017#ifdef __NR_fork
Ian Wienand2d45b1a2006-02-20 22:48:07 +010018 __NR_fork,
Ian Wienand9a2ad352006-02-20 22:44:45 +010019#else
Ian Wienand2d45b1a2006-02-20 22:48:07 +010020 -1,
Ian Wienand9a2ad352006-02-20 22:44:45 +010021#endif
22#ifdef __NR_clone
Ian Wienand2d45b1a2006-02-20 22:48:07 +010023 __NR_clone,
Ian Wienand9a2ad352006-02-20 22:44:45 +010024#else
Ian Wienand2d45b1a2006-02-20 22:48:07 +010025 -1,
Ian Wienand9a2ad352006-02-20 22:44:45 +010026#endif
27#ifdef __NR_clone2
Ian Wienand2d45b1a2006-02-20 22:48:07 +010028 __NR_clone2,
Ian Wienand9a2ad352006-02-20 22:44:45 +010029#else
Ian Wienand2d45b1a2006-02-20 22:48:07 +010030 -1,
Ian Wienand9a2ad352006-02-20 22:44:45 +010031#endif
32#ifdef __NR_vfork
Ian Wienand2d45b1a2006-02-20 22:48:07 +010033 __NR_vfork,
Ian Wienand9a2ad352006-02-20 22:44:45 +010034#else
Ian Wienand2d45b1a2006-02-20 22:48:07 +010035 -1,
Ian Wienand9a2ad352006-02-20 22:44:45 +010036#endif
37#ifdef __NR_execve
Ian Wienand2d45b1a2006-02-20 22:48:07 +010038 __NR_execve,
Ian Wienand9a2ad352006-02-20 22:44:45 +010039#else
Ian Wienand2d45b1a2006-02-20 22:48:07 +010040 -1,
Ian Wienand9a2ad352006-02-20 22:44:45 +010041#endif
Ian Wienand2d45b1a2006-02-20 22:48:07 +010042 }
Ian Wienand9a2ad352006-02-20 22:44:45 +010043#ifdef FORK_EXEC_SYSCALLS
Ian Wienand2d45b1a2006-02-20 22:48:07 +010044 FORK_EXEC_SYSCALLS
Ian Wienand9a2ad352006-02-20 22:44:45 +010045#endif
46};
Juan Cespedes5e01f651998-03-08 22:31:44 +010047
Juan Cespedes81690ef1998-03-13 19:31:29 +010048/* Returns 1 if the sysnum may make a new child to be created
49 * (ie, with fork() or clone())
50 * Returns 0 otherwise.
51 */
Ian Wienand2d45b1a2006-02-20 22:48:07 +010052int fork_p(struct process *proc, int sysnum)
53{
Paul Gilliam3f1219f2006-04-24 18:25:38 +020054 unsigned int i;
Ian Wienand9a2ad352006-02-20 22:44:45 +010055 if (proc->personality
Ian Wienand2d45b1a2006-02-20 22:48:07 +010056 >= 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)
Ian Wienand9a2ad352006-02-20 22:44:45 +010059 if (sysnum == fork_exec_syscalls[proc->personality][i])
60 return 1;
61 return 0;
Juan Cespedes5e01f651998-03-08 22:31:44 +010062}
63
Juan Cespedes81690ef1998-03-13 19:31:29 +010064/* Returns 1 if the sysnum may make the process exec other program
65 */
Ian Wienand2d45b1a2006-02-20 22:48:07 +010066int exec_p(struct process *proc, int sysnum)
67{
Ian Wienand9a2ad352006-02-20 22:44:45 +010068 int i;
69 if (proc->personality
Ian Wienand2d45b1a2006-02-20 22:48:07 +010070 >= sizeof fork_exec_syscalls / sizeof(fork_exec_syscalls[0]))
71 return 0;
72 i = sizeof(fork_exec_syscalls[0]) / sizeof(int) - 1;
Ian Wienand9a2ad352006-02-20 22:44:45 +010073 if (sysnum == fork_exec_syscalls[proc->personality][i])
74 return 1;
75 return 0;
Juan Cespedes81690ef1998-03-13 19:31:29 +010076}
77
Ian Wienand2d45b1a2006-02-20 22:48:07 +010078void trace_me(void)
79{
80 if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) {
Juan Cespedes5e01f651998-03-08 22:31:44 +010081 perror("PTRACE_TRACEME");
82 exit(1);
83 }
84}
85
Ian Wienand2d45b1a2006-02-20 22:48:07 +010086int trace_pid(pid_t pid)
87{
Juan Cespedes1fe93d51998-03-13 00:29:21 +010088 if (ptrace(PTRACE_ATTACH, pid, 1, 0) < 0) {
Juan Cespedes273ea6d1998-03-14 23:02:40 +010089 return -1;
Juan Cespedes1fe93d51998-03-13 00:29:21 +010090 }
Petr Machata89a53602007-01-25 18:05:44 +010091
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
Juan Cespedes273ea6d1998-03-14 23:02:40 +0100101 return 0;
102}
103
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100104void trace_set_options(struct process *proc, pid_t pid)
105{
Ian Wienand9a2ad352006-02-20 22:44:45 +0100106#ifndef PTRACE_SETOPTIONS
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100107#define PTRACE_SETOPTIONS 0x4200
Ian Wienand9a2ad352006-02-20 22:44:45 +0100108#endif
109#ifndef PTRACE_OLDSETOPTIONS
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100110#define PTRACE_OLDSETOPTIONS 21
Ian Wienand9a2ad352006-02-20 22:44:45 +0100111#endif
112#ifndef PTRACE_O_TRACESYSGOOD
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100113#define PTRACE_O_TRACESYSGOOD 0x00000001
Ian Wienand9a2ad352006-02-20 22:44:45 +0100114#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
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100125void untrace_pid(pid_t pid)
126{
Juan Cespedes273ea6d1998-03-14 23:02:40 +0100127 ptrace(PTRACE_DETACH, pid, 1, 0);
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100128}
129
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100130void continue_after_signal(pid_t pid, int signum)
131{
Juan Cespedes5e01f651998-03-08 22:31:44 +0100132 /* We should always trace syscalls to be able to control fork(), clone(), execve()... */
Juan Cespedes5916fda2002-02-25 00:19:21 +0100133 ptrace(PTRACE_SYSCALL, pid, 0, signum);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100134}
135
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100136void continue_process(pid_t pid)
137{
Juan Cespedes5e01f651998-03-08 22:31:44 +0100138 continue_after_signal(pid, 0);
139}
140
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100141void continue_enabling_breakpoint(pid_t pid, struct breakpoint *sbp)
142{
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200143 enable_breakpoint(pid, sbp);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100144 continue_process(pid);
145}
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100146
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100147void continue_after_breakpoint(struct process *proc, struct breakpoint *sbp)
148{
149 if (sbp->enabled)
150 disable_breakpoint(proc->pid, sbp);
Juan Cespedes5c3fe062004-06-14 18:08:37 +0200151 set_instruction_pointer(proc, sbp->addr);
Juan Cespedes8f8282f2002-03-03 18:58:40 +0100152 if (sbp->enabled == 0) {
153 continue_process(proc->pid);
154 } else {
155 proc->breakpoint_being_enabled = sbp;
Ian Wienand9a2ad352006-02-20 22:44:45 +0100156#if defined __sparc__ || defined __ia64___
157 /* we don't want to singlestep here */
Juan Cespedes5c3fe062004-06-14 18:08:37 +0200158 continue_process(proc->pid);
159#else
Juan Cespedes8f8282f2002-03-03 18:58:40 +0100160 ptrace(PTRACE_SINGLESTEP, proc->pid, 0, 0);
Juan Cespedes5c3fe062004-06-14 18:08:37 +0200161#endif
Juan Cespedes8f8282f2002-03-03 18:58:40 +0100162 }
163}
164
Steve Fink7bafff02006-08-07 04:50:42 +0200165/* 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*/
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100183int umovestr(struct process *proc, void *addr, int len, void *laddr)
184{
185 union {
186 long a;
187 char c[sizeof(long)];
188 } a;
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100189 int i;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100190 int offset = 0;
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100191
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100192 while (offset < len) {
193 a.a = ptrace(PTRACE_PEEKTEXT, proc->pid, addr + offset, 0);
194 for (i = 0; i < sizeof(long); i++) {
Paul Gilliam3f1219f2006-04-24 18:25:38 +0200195 if (a.c[i] && offset + (signed)i < len) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100196 *(char *)(laddr + offset + i) = a.c[i];
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100197 } else {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100198 *(char *)(laddr + offset + i) = '\0';
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100199 return 0;
200 }
201 }
202 offset += sizeof(long);
203 }
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100204 *(char *)(laddr + offset) = '\0';
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +0100205 return 0;
206}