cd6cc4ff40cf3ff05c1c55dd7df428b1ca775eb0
[cacao.git] / src / native / jvmti / cacaodbgserver.c
1
2 /* src/native/jvmti/cacaodbgserver.c - contains the cacaodbgserver process. This
3                                        process controls the cacao vm through gdb
4
5    Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
6    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
7    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
8    J. Wenninger, Institut f. Computersprachen - TU Wien
9
10    This file is part of CACAO.
11
12    This program is free software; you can redistribute it and/or
13    modify it under the terms of the GNU General Public License as
14    published by the Free Software Foundation; either version 2, or (at
15    your option) any later version.
16
17    This program is distributed in the hope that it will be useful, but
18    WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20    General Public License for more details.
21
22    You should have received a copy of the GNU General Public License
23    along with this program; if not, write to the Free Software
24    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
25    02111-1307, USA.
26
27    Contact: cacao@complang.tuwien.ac.at
28
29    Authors: Martin Platter
30
31    Changes: Edwin Steiner
32             Samuel Vinson
33
34    $Id: cacaodbgserver.c $
35
36 */
37
38 #include "native/jvmti/cacaodbgserver.h"
39 #include "native/jvmti/cacaodbg.h"
40 #include "native/jvmti/dbg.h"
41 #include <sys/types.h>
42 #include <unistd.h>
43 #include <signal.h>
44 #include <sys/wait.h>
45 #include <stdlib.h>
46 #include <stdio.h>
47 #include <assert.h>
48 #include <string.h>
49
50 FILE *gdbin, *gdbout; /* file descriptor for gdb pipes */
51
52 struct _pending_brkpt {
53         int brknumber;
54         unsigned long threadid;
55         char* regs;
56 };
57
58 struct _pending_brkpt *pending_brkpts;
59 int pending_brkpts_size;
60
61
62 static void closepipeend (int fd) {
63         if (close(fd) == -1) {
64                 perror("unable to close pipe - ");
65                 exit(1);
66         }
67 }
68
69 /* startgdb *******************************************************************
70
71    starts a gdb session and creates two pipes connection gdb stdout/stdin to
72    gdbin/gdbout
73
74 *******************************************************************************/
75
76 static void startgdb() {
77         char gdbargs[20];
78         int cacao2gdbpipe[2],gdb2cacaopipe[2];
79
80         pipe(cacao2gdbpipe);
81         pipe(gdb2cacaopipe);
82
83         snprintf(gdbargs,20,"--pid=%d",getppid());              
84
85         switch(fork()) {
86         case -1:
87                 fprintf(stderr,"cacaodbgserver: fork error\n");
88                 exit(1);
89         case 0:         
90                 /* child */
91                 closepipeend(gdb2cacaopipe[0]); /* read end */
92                 closepipeend(cacao2gdbpipe[1]); /* write end */
93                 
94                 /* connect stdin of gdb to cacao2gdbpipe */
95                 dup2(cacao2gdbpipe[0],0);
96                 /* connect stdout of gdb to gdb2cacaopipe */
97                 dup2(gdb2cacaopipe[1],1);
98
99                 if (execlp("gdb","gdb","--interpreter=mi" ,gdbargs,(char *) NULL)==-1){
100                         fprintf(stderr,"cacaodbgserver: unable to start gdb\n");
101                         exit(1);
102                 }
103         default:
104                 /* parent */
105                 closepipeend(gdb2cacaopipe[1]); /* write end */
106                 closepipeend(cacao2gdbpipe[0]); /* read end */
107
108                 gdbin = fdopen(gdb2cacaopipe[0],"r");
109                 gdbout = fdopen(cacao2gdbpipe[1],"w");
110         }
111
112 }
113
114
115 #define SENDCMD(CMD) \
116         fprintf(gdbout,"%s",CMD); \
117         fflush(gdbout); \
118
119
120 static void getgdboutput(char *inbuf,int buflen) {
121         int i=0;
122         inbuf[0]='\0';
123         do {
124                 i += strlen(&inbuf[i]);
125                 if (fgets(&inbuf[i],buflen-i,gdbin)==NULL) {
126                         perror("cacaodbgserver: ");
127                         exit(1);
128                 }
129         } while(!(strncmp(OUTPUTEND,&inbuf[i],OUTPUTENDSIZE)==0));
130 }
131
132
133 /* dataevaluate ***************************************************************
134
135    evaluates expr returning long in gdb and returns the result 
136
137 *******************************************************************************/
138
139 static unsigned long dataevaluate(char *expr) {
140         char *match, inbuf[160];
141
142         fprintf(gdbout,"-data-evaluate-expression %s\n",expr); 
143         fflush(gdbout); 
144
145         getgdboutput(inbuf,160);
146         if ((match=strstr(inbuf,DATAEVALUATE)) == NULL) {
147                 fprintf(stderr,"dataevaluate: no matching value\n");
148                 return -1;
149         }
150         return strtoll(&match[strlen(DATAEVALUATE)], NULL, 16);
151 }
152
153
154 /* commonbreakpointhandler *****************************************************
155
156    called by gdb and hard coded breakpoint handler
157
158 *******************************************************************************/
159
160 static bool commonbreakpointhandler(char* sigbuf, int sigtrap) {
161         int numberofbreakpoints, i;
162         char tmp[INBUFLEN], *match;
163         unsigned long addr;
164
165         if ((match=strstr(sigbuf,SIGADDR))==NULL) {
166                 fprintf(stderr,"commonbreakpointhandler: no matching address(%s)\n",
167                                 sigbuf);
168                 return true;
169         }
170
171         addr = strtoll(&match[strlen(SIGADDR)],NULL,16);
172         if (sigtrap) addr--;
173
174
175         numberofbreakpoints = (int)dataevaluate("dbgcom->jvmtibrkpt.num");
176
177         i = -1;
178         do {
179                 i++; 
180                 snprintf(tmp,INBUFLEN,"dbgcom->jvmtibrkpt.brk[%d].addr",i);
181         } while ((i<numberofbreakpoints) && (dataevaluate(tmp) != addr));
182
183         assert(i<numberofbreakpoints);
184
185         /* handle system breakpoints */
186         switch(i) {
187         case SETSYSBRKPT:
188                 /* add a breakpoint */
189                 fprintf(gdbout,"break *0x%lx\n",dataevaluate("dbgcom->brkaddr"));
190                 fflush(gdbout);
191                 getgdboutput(tmp,INBUFLEN);
192                 break;
193         case CACAODBGSERVERQUIT:
194                 SENDCMD("-gdb-exit\n");
195                 return false;
196         default:
197                 /* other breakpoints -> call jvmti_cacao_generic_breakpointhandler 
198                    in the cacao vm */
199                 fprintf(gdbout,"call jvmti_cacao_generic_breakpointhandler(%d)\n",i);
200                 fflush(gdbout);
201                 getgdboutput(tmp,INBUFLEN);
202         }
203         SENDCMD(CONTINUE);
204         getgdboutput(tmp,INBUFLEN);
205         return true;
206 }
207
208 /* controlloop ****************************************************************
209
210    this function controls the gdb behaviour
211
212 *******************************************************************************/
213
214 static void controlloop() {
215         char inbuf[INBUFLEN], *match;
216         bool running = true;
217
218         pending_brkpts_size = 5;
219         pending_brkpts = malloc(sizeof(struct _pending_brkpt)*pending_brkpts_size);
220
221         getgdboutput(inbuf,INBUFLEN);   /* read gdb welcome message */
222
223         SENDCMD("handle SIGSEGV SIGPWR SIGXCPU SIGBUS noprint nostop\n");
224         getgdboutput(inbuf,INBUFLEN);
225
226         SENDCMD("print dbgcom\n");
227         getgdboutput(inbuf,INBUFLEN);
228
229         SENDCMD(CONTINUE);
230         getgdboutput(inbuf,INBUFLEN);
231
232         while(running) {
233                 getgdboutput(inbuf,INBUFLEN);
234
235                 if ((match=strstr(inbuf,HCSIGTRAP))!=NULL) {
236                         running = commonbreakpointhandler(match,1);
237                         continue;
238                         }
239
240                 if ((match=strstr(inbuf,GDBBREAKPOINT))!=NULL) {
241                         running = commonbreakpointhandler(match,0);
242                         continue;
243                 }
244
245                 if (strstr(inbuf,EXITEDNORMALLY) != NULL) {
246                         /* quit gdb */
247                         SENDCMD ("-gdb-exit");
248                         running = false;
249                         continue;
250                 }
251                         
252                 if ((inbuf[0]!=LOGSTREAMOUTPUT) && (inbuf[0]!=CONSOLESTREAMOUTPUT)) {
253                         fprintf(stderr,"gdbin not handled %s\n",inbuf);
254                         fprintf(gdbout,"bt\n");
255                         fflush(gdbout);
256                         fprintf(stderr,"not handled 1\n");
257                         fflush(stderr);
258                         getgdboutput(inbuf,INBUFLEN);
259                         fprintf(stderr,"gdbin: %s\n",inbuf);
260                         SENDCMD("-gdb-exit\n");
261                         return;
262                 }
263         }
264
265         free(pending_brkpts);
266 }
267
268 /* main (cacaodbgserver) ******************************************************
269
270    main function for cacaodbgserver process.
271
272 *******************************************************************************/
273
274 int main(int argc, char **argv) {
275         startgdb();
276
277         controlloop();
278
279         return 0;
280 }
281
282
283 /*
284  * These are local overrides for various environment variables in Emacs.
285  * Please do not remove this and leave it at the end of the file, where
286  * Emacs will automagically detect them.
287  * ---------------------------------------------------------------------
288  * Local variables:
289  * mode: c
290  * indent-tabs-mode: t
291  * c-basic-offset: 4
292  * tab-width: 4
293  * End:
294  * vim:noexpandtab:sw=4:ts=4:
295  */