src/native/vm/VMVirtualMachine.c (unregisterEvent): print error message
[cacao.git] / src / native / jvmti / cacaodbgserver.c
1 /* src/native/jvmti/cacaodbgserver.c - contains the cacaodbgserver process. This
2                                        process controls the cacao vm through gdb
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             Samuel Vinson
32
33    $Id$
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 <stdio.h>
46 #include <assert.h>
47 #include <string.h>
48
49 FILE *gdbin, *gdbout; /* file descriptor for gdb pipes */
50
51 struct _pending_brkpt {
52         int brknumber;
53         unsigned long threadid;
54         char* regs;
55 };
56
57 struct _pending_brkpt *pending_brkpts;
58 int pending_brkpts_size;
59
60
61 static void closepipeend (int fd) {
62         if (close(fd) == -1) {
63                 perror("unable to close pipe - ");
64                 exit(1);
65         }
66 }
67
68 /* startgdb *******************************************************************
69
70    starts a gdb session and creates two pipes connection gdb stdout/stdin to
71    gdbin/gdbout
72
73 *******************************************************************************/
74
75 static void startgdb() {
76         char gdbargs[20];
77         int cacao2gdbpipe[2],gdb2cacaopipe[2];
78
79         pipe(cacao2gdbpipe);
80         pipe(gdb2cacaopipe);
81
82         snprintf(gdbargs,20,"--pid=%d",getppid());              
83
84         switch(fork()) {
85         case -1:
86                 fprintf(stderr,"cacaodbgserver: fork error\n");
87                 exit(1);
88         case 0:         
89                 /* child */
90                 closepipeend(gdb2cacaopipe[0]); /* read end */
91                 closepipeend(cacao2gdbpipe[1]); /* write end */
92                 
93                 /* connect stdin of gdb to cacao2gdbpipe */
94                 dup2(cacao2gdbpipe[0],0);
95                 /* connect stdout of gdb to gdb2cacaopipe */
96                 dup2(gdb2cacaopipe[1],1);
97
98                 if (execlp("gdb","gdb","--interpreter=mi" ,gdbargs,(char *) NULL)==-1){
99                         fprintf(stderr,"cacaodbgserver: unable to start gdb\n");
100                         exit(1);
101                 }
102         default:
103                 /* parent */
104                 closepipeend(gdb2cacaopipe[1]); /* write end */
105                 closepipeend(cacao2gdbpipe[0]); /* read end */
106
107                 gdbin = fdopen(gdb2cacaopipe[0],"r");
108                 gdbout = fdopen(cacao2gdbpipe[1],"w");
109         }
110
111 }
112
113
114 #define SENDCMD(CMD) \
115         fprintf(gdbout,"%s",CMD); \
116         fflush(gdbout); \
117
118
119 static void getgdboutput(char *inbuf,int buflen) {
120         int i=0;
121         inbuf[0]='\0';
122         do {
123                 i += strlen(&inbuf[i]);
124                 if (fgets(&inbuf[i],buflen-i,gdbin)==NULL) {
125                         perror("cacaodbgserver: ");
126                         exit(1);
127                 }
128         } while(!(strncmp(OUTPUTEND,&inbuf[i],OUTPUTENDSIZE)==0));
129 }
130
131
132 /* dataevaluate ***************************************************************
133
134    evaluates expr returning long in gdb and returns the result 
135
136 *******************************************************************************/
137
138 static unsigned long dataevaluate(char *expr) {
139         char *match, inbuf[160];
140
141         fprintf(gdbout,"-data-evaluate-expression %s\n",expr); 
142         fflush(gdbout); 
143
144         getgdboutput(inbuf,160);
145         if ((match=strstr(inbuf,DATAEVALUATE)) == NULL) {
146                 fprintf(stderr,"dataevaluate: no matching value\n");
147                 return -1;
148         }
149         return strtoll(&match[strlen(DATAEVALUATE)], NULL, 16);
150 }
151
152
153 /* commonbreakpointhandler *****************************************************
154
155    called by gdb and hard coded breakpoint handler
156
157 *******************************************************************************/
158
159 static bool commonbreakpointhandler(char* sigbuf, int sigtrap) {
160         int numberofbreakpoints, i;
161         char tmp[INBUFLEN], *match;
162         unsigned long addr;
163
164         if ((match=strstr(sigbuf,SIGADDR))==NULL) {
165                 fprintf(stderr,"commonbreakpointhandler: no matching address(%s)\n",
166                                 sigbuf);
167                 return true;
168         }
169
170         addr = strtoll(&match[strlen(SIGADDR)],NULL,16);
171         if (sigtrap) addr--;
172
173
174         numberofbreakpoints = (int)dataevaluate("dbgcom->jvmtibrkpt.num");
175
176         i = -1;
177         do {
178                 i++; 
179                 snprintf(tmp,INBUFLEN,"dbgcom->jvmtibrkpt.brk[%d].addr",i);
180         } while ((i<numberofbreakpoints) && (dataevaluate(tmp) != addr));
181
182         assert(i<numberofbreakpoints);
183
184         /* handle system breakpoints */
185         switch(i) {
186         case SETSYSBRKPT:
187                 /* add a breakpoint */
188                 fprintf(gdbout,"break *0x%lx\n",dataevaluate("dbgcom->brkaddr"));
189                 fflush(gdbout);
190                 getgdboutput(tmp,INBUFLEN);
191                 break;
192         case CACAODBGSERVERQUIT:
193                 SENDCMD("-gdb-exit\n");
194                 return false;
195         default:
196                 /* other breakpoints -> call jvmti_cacao_generic_breakpointhandler 
197                    in the cacao vm */
198                 fprintf(gdbout,"call jvmti_cacao_generic_breakpointhandler(%d)\n",i);
199                 fflush(gdbout);
200                 getgdboutput(tmp,INBUFLEN);
201         }
202         SENDCMD(CONTINUE);
203         getgdboutput(tmp,INBUFLEN);
204         return true;
205 }
206
207 /* controlloop ****************************************************************
208
209    this function controls the gdb behaviour
210
211 *******************************************************************************/
212
213 static void controlloop() {
214         char inbuf[INBUFLEN], *match;
215         bool running = true;
216
217         pending_brkpts_size = 5;
218         pending_brkpts = malloc(sizeof(struct _pending_brkpt)*pending_brkpts_size);
219
220         getgdboutput(inbuf,INBUFLEN);   /* read gdb welcome message */
221
222         SENDCMD("handle SIGSEGV SIGPWR SIGXCPU SIGBUS noprint nostop\n");
223         getgdboutput(inbuf,INBUFLEN);
224
225         SENDCMD("print dbgcom\n");
226         getgdboutput(inbuf,INBUFLEN);
227
228         SENDCMD(CONTINUE);
229         getgdboutput(inbuf,INBUFLEN);
230
231         while(running) {
232                 getgdboutput(inbuf,INBUFLEN);
233
234                 if ((match=strstr(inbuf,HCSIGTRAP))!=NULL) {
235                         running = commonbreakpointhandler(match,1);
236                         continue;
237                         }
238
239                 if ((match=strstr(inbuf,GDBBREAKPOINT))!=NULL) {
240                         running = commonbreakpointhandler(match,0);
241                         continue;
242                 }
243
244                 if (strstr(inbuf,EXITEDNORMALLY) != NULL) {
245                         /* quit gdb */
246                         SENDCMD ("-gdb-exit");
247                         running = false;
248                         continue;
249                 }
250                         
251                 if ((inbuf[0]!=LOGSTREAMOUTPUT) && (inbuf[0]!=CONSOLESTREAMOUTPUT)) {
252                         fprintf(stderr,"gdbin not handled %s\n",inbuf);
253                         fprintf(gdbout,"bt\n");
254                         fflush(gdbout);
255                         fprintf(stderr,"not handled 1\n");
256                         fflush(stderr);
257                         getgdboutput(inbuf,INBUFLEN);
258                         fprintf(stderr,"gdbin: %s\n",inbuf);
259                         SENDCMD("-gdb-exit\n");
260                         return;
261                 }
262         }
263
264         free(pending_brkpts);
265 }
266
267 /* main (cacaodbgserver) ******************************************************
268
269    main function for cacaodbgserver process.
270
271 *******************************************************************************/
272
273 int main(int argc, char **argv) {
274         startgdb();
275
276         controlloop();
277
278         return 0;
279 }
280
281
282 /*
283  * These are local overrides for various environment variables in Emacs.
284  * Please do not remove this and leave it at the end of the file, where
285  * Emacs will automagically detect them.
286  * ---------------------------------------------------------------------
287  * Local variables:
288  * mode: c
289  * indent-tabs-mode: t
290  * c-basic-offset: 4
291  * tab-width: 4
292  * End:
293  * vim:noexpandtab:sw=4:ts=4:
294  */