* src/threads/native/threads.h (threads_sem_init): New function.
[cacao.git] / src / native / jvmti / cacaodbgserver.c
1 /* src/native/jvmti/cacaodbgserver.c - contains the cacaodbgserver process. This
2                                        process controls the debuggee.
3
4    Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
5    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
6    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
7    J. Wenninger, Institut f. Computersprachen - TU Wien
8
9    This file is part of CACAO.
10
11    This program is free software; you can redistribute it and/or
12    modify it under the terms of the GNU General Public License as
13    published by the Free Software Foundation; either version 2, or (at
14    your option) any later version.
15
16    This program is distributed in the hope that it will be useful, but
17    WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19    General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
24    02111-1307, USA.
25
26    Contact: cacao@complang.tuwien.ac.at
27
28    Authors: Martin Platter
29
30    Changes: Edwin Steiner
31
32
33    $Id: cacao.c,v 3.165 2006/01/03 23:44:38 twisti Exp $
34
35 */
36
37 #include "native/jvmti/cacaodbgserver.h"
38 #include "native/jvmti/cacaodbg.h"
39 #include "native/jvmti/dbg.h"
40 #include <sys/types.h>
41 #include <unistd.h>
42 #include <signal.h>
43 #include <sys/wait.h>
44 #include <stdlib.h>
45 #include <sys/ipc.h>
46 #include <sys/shm.h>
47 #include <semaphore.h>
48 #include <sys/msg.h>
49 #include <linux/user.h>
50
51
52 /* getchildprocptrace *********************************************************
53
54    Get data count number of bytes from address addr for child process address 
55    space. Requested  data is stored in the array pointed to by ptr.
56
57 *******************************************************************************/
58 static void getchildprocptrace (char *ptr, void* addr, int cnt) {
59         int i, longcnt;
60         long *p = (long*) ptr;
61         
62         longcnt = cnt/sizeof(long);
63         for (i=0; i<longcnt; i++) {
64                 p[i]=GETMEM(debuggee,addr);
65                 if (p[i]==-1) 
66                         perror("cacaodbgserver process: getchildprocptrace: ");
67                 addr+=sizeof(long);
68         }
69         longcnt = GETMEM(debuggee,addr);
70         memcpy(ptr,&longcnt,cnt%sizeof(long));
71 }
72
73 /* contchild ******************************************************************
74
75    Helper function to continue child process. 
76
77 *******************************************************************************/
78 static bool contchild(int signal) {
79         /* get lock for running state */ 
80         threads_sem_wait(&workingdata_lock);
81         fprintf(stderr,"cacaodbgserver: contchild called (hastostop: %d)\n",cdbgshmem->hastostop);
82         if(cdbgshmem->hastostop < 1) {
83                 fprintf(stderr,"cacaodbgserver: going to continue child\n");
84                 CONT(debuggee,signal);
85                 cdbgshmem->hastostop = 0;
86                 cdbgshmem->running=true;
87                 /* release lock for running state */ 
88                 threads_sem_post(&workingdata_lock);
89                 return true;
90         } else {
91                 threads_sem_post(&workingdata_lock);
92                 return false;           
93         }
94 }
95
96 /* msgqsendevent *******************************************************************
97
98    sends an event notification to the jdwp/debugger process through the 
99    message queue
100
101 *******************************************************************************/
102 static void msgqsendevent(basic_event *ev) {
103         ev->mtype = MSGQDEBUGGER;
104         
105         if (-1 == msgsnd(msgqid, ev, sizeof(basic_event), 0)) {
106                 perror("cacaodbgserver process: cacaodbglisten send error: ");
107                 exit(1);
108         }
109 }
110
111 /* waitloop *******************************************************************
112
113    waits and handles signals from debuggee/child process
114
115 *******************************************************************************/
116
117 static void waitloop() {
118     int status,retval,signal;
119     void* ip;
120         basic_event ev;
121
122         fprintf(stderr,"waitloop\n");
123     fflush (stderr); 
124
125     while (true) {
126                 retval = wait(&status);
127
128                 fprintf(stderr,"cacaodbgserver: waitloop we got something to do\n");
129                 if (retval == -1) {
130                         fprintf(stderr,"error in waitloop\n");
131                         perror("cacaodbgserver process: waitloop: ");
132                         exit(1);
133                 }
134
135                 if (retval != debuggee) {
136                         fprintf(stderr,"cacaodbgserver got signal from process other then debuggee\n");
137                         exit(1);
138                 }
139                 
140                 if (WIFEXITED(status)) {
141                         /* generate event VMDeath */
142                         ev.signal = SIGQUIT;
143                         ev.ip = NULL;
144                         msgqsendevent(&ev);
145                         return;
146                 }
147                 
148                 if (WIFSTOPPED(status)) {
149                         signal = WSTOPSIG(status);
150
151                         /* ignore SIGSEGV, SIGPWR, SIGBUS and SIGXCPU for now.
152                            todo: in future this signals can be used to detect Garbage 
153                            Collection Start/Finish or NullPointerException Events */
154                         if ((signal == SIGSEGV) || (signal == SIGPWR) || 
155                                 (signal == SIGBUS)      || (signal == SIGXCPU)) {
156                                 fprintf(stderr,"cacaodbgserver: ignore internal signal (%d)\n",signal);
157                                 contchild(signal);
158                                 continue;
159                         }
160
161                         if (signal == SIGABRT) {
162                                 fprintf(stderr,"cacaodbgserver: got SIGABRT from debugee - exit\n");
163                                 exit(1);
164                         }
165
166                         ip = getip(debuggee);
167                         ip--; /* EIP has already been incremented */
168                         fprintf(stderr,"got signal: %d IP %X\n",signal,ip);
169                         
170                         threads_sem_wait(&workingdata_lock);
171                         cdbgshmem->running = false;
172                         cdbgshmem->hastostop = 1;
173                         threads_sem_post(&workingdata_lock);
174
175                         if (signal==SIGUSR2) {
176                                 fprintf(stderr,"SIGUSR2 - debuggee has stopped by jdwp process\n");
177                                 return;
178                         }
179                         
180                         ev.signal = signal;
181                         ev.ip = ip;
182                         msgqsendevent(&ev);
183                         return;
184                 }
185         
186                 fprintf(stderr,"wait not handled(child not exited or stopped)\n");
187                 fprintf(stderr,"retval: %d status: %d\n",retval,status);
188         }
189 }
190
191 /* ptraceloop *****************************************************************
192
193    this function handles the ptrace request from the jdwp/debugger process.
194
195 *******************************************************************************/
196
197 void ptraceloop() {
198         bool contdebuggee=false;
199         ptrace_request pt;
200         ptrace_reply *buffer;
201         int size;
202     struct user_regs_struct *regs;
203
204         fprintf(stderr,"ptraceloop\n");
205     fflush (stderr); 
206         while (!contdebuggee) {
207                 if (-1 == msgrcv(msgqid, &pt, sizeof(ptrace_request), MSGQPTRACESND, 0))
208                         perror("cacaodbgserver process: cacaodbglisten receive error: ");
209
210                 switch(pt.kind){
211                 case PTCONT:
212                         /* continue debuggee process */
213                         size= sizeof(ptrace_reply);
214                         buffer =(ptrace_reply*) MNEW(char,size);
215
216                         contdebuggee = contchild(pt.data);
217
218                         buffer->mtype = MSGQPTRACERCV;
219                         buffer->successful=true;
220                         buffer->datasize=0;
221                         break;
222                 case PTPEEKDATA:
223                         /* get memory content from the debuggee process */
224                         size= sizeof(ptrace_reply)+pt.data;
225                         buffer =(ptrace_reply*) MNEW(char,size);
226
227                         buffer->mtype = MSGQPTRACERCV;
228                         buffer->datasize = size-sizeof(ptrace_reply);
229
230                         fprintf(stderr,"getchildprocptrace: pid %d get %p - %p cnt: %d (buffer %p buffer->data %p)\n",
231                                         debuggee, pt.addr,pt.addr+pt.data, buffer->datasize,buffer, buffer->data);
232                         fflush(stderr);
233
234                         getchildprocptrace(buffer->data,pt.addr,buffer->datasize);
235                         break;
236                 case PTSETBRK:
237                         size= sizeof(ptrace_reply)+sizeof(long);
238                         buffer =(ptrace_reply*) MNEW(char,size);
239
240                         /* set new breakpoint */
241                         buffer->mtype = MSGQPTRACERCV;
242                         buffer->successful=true;
243                         buffer->datasize=sizeof(long);
244                         
245                         setbrk(debuggee,pt.addr, (long*)(buffer->data));
246                         break;
247                 case PTDELBRK:
248                         /* delete breakpoint */
249                         size= sizeof(ptrace_reply);
250                         buffer =(ptrace_reply*) MNEW(char,size);
251                         
252                         DISABLEBRK(debuggee,pt.ldata,pt.addr);
253                         
254                         buffer->mtype = MSGQPTRACERCV;
255                         buffer->successful=true;
256                         buffer->datasize=0;
257                         break;
258                 case PTGETREG:
259                         /* get registers */
260                         size= sizeof(ptrace_reply)+sizeof(struct user_regs_struct);
261                         buffer =(ptrace_reply*) MNEW(char,size);
262                         regs=buffer->data;
263
264                         GETREGS(debuggee,*regs);
265                         
266                         buffer->mtype = MSGQPTRACERCV;
267                         buffer->successful=true;
268                         buffer->datasize=sizeof(struct user_regs_struct);
269                         break;
270                 default:
271                         fprintf(stderr,"unkown ptrace request %d\n",pt.kind);
272                         exit(1);
273                 }
274
275                 if (-1 == msgsnd(msgqid, buffer, size, 0)) {
276                         perror("cacaodbgserver process: cacaodbglisten send error: ");
277                         exit(1);
278                 }
279                 MFREE(buffer,char,size);
280         }
281 }
282
283 /* cacaodbgserver *************************************************************
284
285    waits for eventes from and issues ptrace calls to debuggee/child process
286
287 *******************************************************************************/
288
289 void cacaodbgserver() {
290         fprintf(stderr,"cacaodbgserver started\n");
291         fflush(stderr);
292         while(true) {
293                 /* wait until debuggee process gets stopped 
294                    and inform debugger process */
295                 waitloop();
296                 /* give the debugger process the opportunity to issue ptrace calls */
297                 ptraceloop();
298                 /* ptraceloop returns after a PTRACE_CONT call has been issued     */
299         }
300 }
301
302
303 /*
304  * These are local overrides for various environment variables in Emacs.
305  * Please do not remove this and leave it at the end of the file, where
306  * Emacs will automagically detect them.
307  * ---------------------------------------------------------------------
308  * Local variables:
309  * mode: c
310  * indent-tabs-mode: t
311  * c-basic-offset: 4
312  * tab-width: 4
313  * End:
314  * vim:noexpandtab:sw=4:ts=4:
315  */