2 * Server-side ptrace support
4 * Copyright (C) 1999 Alexandre Julliard
13 #include <sys/types.h>
14 #include <sys/ptrace.h>
15 #ifdef HAVE_SYS_WAIT_H
25 #define PTRACE_CONT PT_CONTINUE
28 #define PTRACE_ATTACH PT_ATTACH
31 #define PTRACE_DETACH PT_DETACH
33 #ifndef PTRACE_PEEKDATA
34 #define PTRACE_PEEKDATA PT_READ_D
36 #ifndef PTRACE_POKEDATA
37 #define PTRACE_POKEDATA PT_WRITE_D
40 static const int use_ptrace
= 1; /* set to 0 to disable ptrace */
43 /* wait for a ptraced child to get a certain signal */
44 /* if the signal is 0, we simply check if anything is pending and return at once */
45 void wait4_thread( struct thread
*thread
, int signal
)
51 pid
= thread
? thread
->unix_pid
: -1;
52 if ((pid
= wait4( pid
, &status
, WUNTRACED
| (signal
? 0 : WNOHANG
), NULL
)) == -1)
57 if (WIFSTOPPED(status
))
59 int sig
= WSTOPSIG(status
);
60 if (debug_level
) fprintf( stderr
, "ptrace: pid %d got sig %d\n", pid
, sig
);
63 case SIGSTOP
: /* continue at once if not suspended */
65 if (!(thread
= get_thread_from_pid( pid
))) break;
66 if (!(thread
->process
->suspend
+ thread
->suspend
))
67 ptrace( PTRACE_CONT
, pid
, 1, sig
);
69 default: /* ignore other signals for now */
70 ptrace( PTRACE_CONT
, pid
, 1, sig
);
73 if (signal
&& sig
!= signal
) goto restart
;
75 else if (WIFSIGNALED(status
))
77 int exit_code
= WTERMSIG(status
);
79 fprintf( stderr
, "ptrace: pid %d killed by sig %d\n", pid
, exit_code
);
81 if (!(thread
= get_thread_from_pid( pid
))) return;
82 if (thread
->client
) remove_client( thread
->client
, exit_code
);
84 else if (WIFEXITED(status
))
86 int exit_code
= WEXITSTATUS(status
);
88 fprintf( stderr
, "ptrace: pid %d exited with status %d\n", pid
, exit_code
);
90 if (!(thread
= get_thread_from_pid( pid
))) return;
91 if (thread
->client
) remove_client( thread
->client
, exit_code
);
93 else fprintf( stderr
, "wait4: pid %d unknown status %x\n", pid
, status
);
96 /* attach to a Unix thread */
97 static int attach_thread( struct thread
*thread
)
99 /* this may fail if the client is already being debugged */
100 if (!use_ptrace
|| (ptrace( PTRACE_ATTACH
, thread
->unix_pid
, 0, 0 ) == -1)) return 0;
101 if (debug_level
) fprintf( stderr
, "ptrace: attached to pid %d\n", thread
->unix_pid
);
102 thread
->attached
= 1;
103 wait4_thread( thread
, SIGSTOP
);
107 /* detach from a Unix thread and kill it */
108 void detach_thread( struct thread
*thread
)
110 if (!thread
->unix_pid
) return;
111 kill( thread
->unix_pid
, SIGTERM
);
112 if (thread
->suspend
+ thread
->process
->suspend
) continue_thread( thread
);
113 if (thread
->attached
)
115 wait4_thread( thread
, SIGTERM
);
116 if (debug_level
) fprintf( stderr
, "ptrace: detaching from %d\n", thread
->unix_pid
);
117 ptrace( PTRACE_DETACH
, thread
->unix_pid
, 1, SIGTERM
);
118 thread
->attached
= 0;
122 /* stop a thread (at the Unix level) */
123 void stop_thread( struct thread
*thread
)
125 /* can't stop a thread while initialisation is in progress */
126 if (!thread
->unix_pid
|| thread
->process
->init_event
) return;
127 /* first try to attach to it */
128 if (!thread
->attached
)
129 if (attach_thread( thread
)) return; /* this will have stopped it */
130 /* attached already, or attach failed -> send a signal */
131 kill( thread
->unix_pid
, SIGSTOP
);
132 if (thread
->attached
) wait4_thread( thread
, SIGSTOP
);
135 /* make a thread continue (at the Unix level) */
136 void continue_thread( struct thread
*thread
)
138 if (!thread
->unix_pid
) return;
139 if (!thread
->attached
) kill( thread
->unix_pid
, SIGCONT
);
140 else ptrace( PTRACE_CONT
, thread
->unix_pid
, 1, SIGSTOP
);
143 /* read an int from a thread address space */
144 int read_thread_int( struct thread
*thread
, const int *addr
, int *data
)
146 if (((*data
= ptrace( PTRACE_PEEKDATA
, thread
->unix_pid
, addr
, 0 )) == -1) && errno
)
154 /* write an int to a thread address space */
155 int write_thread_int( struct thread
*thread
, int *addr
, int data
, unsigned int mask
)
160 if (read_thread_int( thread
, addr
, &res
) == -1) return -1;
161 data
= (data
& mask
) | (res
& ~mask
);
163 if ((res
= ptrace( PTRACE_POKEDATA
, thread
->unix_pid
, addr
, data
)) == -1) file_set_error();