7c11aafe180eaf76d6677db0f2571b609d974467
[cacao.git] / src / native / jvmti / cacaodbg.c
1 /* src/native/jvmti/cacaodbg.c - contains entry points for debugging support 
2                                  in cacao.
3
4    Copyright (C) 1996-2005, 2006, 2008
5    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
6
7    This file is part of CACAO.
8
9    This program is free software; you can redistribute it and/or
10    modify it under the terms of the GNU General Public License as
11    published by the Free Software Foundation; either version 2, or (at
12    your option) any later version.
13
14    This program is distributed in the hope that it will be useful, but
15    WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17    General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
22    02111-1307, USA.
23
24 */
25
26 #include "native/jvmti/jvmti.h"
27 #include "native/jvmti/cacaodbg.h"
28 #include "native/jvmti/dbg.h"
29 #include "vm/vm.hpp"
30 #include "vm/loader.h"
31 #include "vm/exceptions.h"
32 #include "vm/builtin.h"
33 #include "vm/jit/asmpart.h"
34 #include "vm/stringlocal.h"
35 #include "toolbox/logging.h"
36 #include "threads/mutex.h"
37 #include "threads/thread.h"
38
39 #include <sys/types.h>
40 #include <unistd.h>
41 #include <signal.h>
42 #include <stdlib.h>
43 #include <assert.h>
44 #include <sys/wait.h>
45
46
47 /* jvmti_get_all_threads ******************************************************
48
49    Gets an array of threadobjects of all threads
50
51 *******************************************************************************/
52 jvmtiError jvmti_get_all_threads (jint * threads_count_ptr, 
53                                                                   threadobject*** threads_ptr) {
54     int i = 0, cnt = 8; 
55     threadobject *thread, **tthreads;
56         
57 #if defined(ENABLE_THREADS)
58         tthreads = MNEW(threadobject*, (sizeof(threadobject*) * cnt));
59
60         thread = mainthreadobj;
61     do {
62         if(thread->o.thread != NULL) {
63                         fflush(stderr); 
64
65                    /* count and copy only live threads */
66                    if (i>=cnt) {
67                            MREALLOC(tthreads,threadobject*,cnt,cnt+8);
68                            cnt += 8;
69                    }
70                    tthreads[i] = thread;
71                    i++;
72                 }
73                 thread = thread->prev;
74
75                 /* repeat until we got the pointer to the mainthread twice */
76         } while (mainthreadobj != thread);
77
78         fflush(stderr); 
79
80     *threads_count_ptr = i;
81         *threads_ptr = tthreads;
82
83     return JVMTI_ERROR_NONE;
84 #else
85         return JVMTI_ERROR_NOT_AVAILABLE;
86 #endif
87 }
88
89
90 /* jvmti_get_current_thread ***************************************************
91
92    Get jthread structure of current thread. 
93
94 *******************************************************************************/
95 jthread jvmti_get_current_thread() {
96         return (jthread)(thread_get_current)->o.thread;
97 }
98
99
100
101 /*  breakpointtable_creator ***************************************************
102
103    helper function to enlarge the breakpoint table if needed
104
105 *******************************************************************************/
106
107 static void breakpointtable_creator() {
108         struct _brkpt* tmp;
109         struct brkpts *jvmtibrkpt;
110
111         jvmtibrkpt = &dbgcom->jvmtibrkpt;;
112         if (jvmtibrkpt->size == 0) {
113                 jvmtibrkpt->brk = MNEW(struct _brkpt, 16);
114                 memset(jvmtibrkpt->brk, 0, sizeof(struct _brkpt)*16);
115                 jvmtibrkpt->size = 16;
116                 jvmtibrkpt->num = BEGINUSERBRK;
117         } else {
118                 jvmtibrkpt->size += 16;
119                 tmp = jvmtibrkpt->brk;
120                 jvmtibrkpt->brk = MNEW(struct _brkpt, jvmtibrkpt->size);
121                 memset(jvmtibrkpt->brk, 0, sizeof(struct _brkpt)*(jvmtibrkpt->size));
122                 memcpy((void*)jvmtibrkpt->brk,(void*)tmp,jvmtibrkpt->size);
123                 MFREE(tmp,struct _brkpt,jvmtibrkpt->size-16);
124         }       
125 }
126
127
128 /* jvmti_set_system_breakpoint ************************************************
129
130    sets a system breakpoint in breakpoint table and calls set breakpoint
131
132 *******************************************************************************/
133
134 void jvmti_set_system_breakpoint(int sysbrk, bool mode) {       
135         struct brkpts *jvmtibrkpt;
136
137         mutex_lock(&dbgcomlock);
138         jvmtibrkpt = &dbgcom->jvmtibrkpt;
139
140         assert (sysbrk < BEGINUSERBRK); 
141         if (jvmtibrkpt->size == jvmtibrkpt->num)
142                 breakpointtable_creator();
143
144         if (mode) {
145                 /* add breakpoint*/
146                 if (jvmtibrkpt->brk[sysbrk].count > 0) {
147                         jvmtibrkpt->brk[sysbrk].count++;
148                         mutex_unlock(&dbgcomlock);
149                         return;
150                 }
151                 dbgcom->addbrkpt = true;
152                 dbgcom->brkaddr = jvmtibrkpt->brk[sysbrk].addr;
153         } else {
154                 /* remove breakpoint*/          
155                 if ((jvmtibrkpt->brk[sysbrk].count == 1) ) {
156                         jvmtibrkpt->brk[sysbrk].count--;
157                         /* remove breakpoint */
158                         dbgcom->addbrkpt = false;
159                         dbgcom->brkaddr = jvmtibrkpt->brk[sysbrk].addr;
160                 } else {
161                         /* avoid negative counter values */
162                         if (jvmtibrkpt->brk[sysbrk].count > 0) jvmtibrkpt->brk[sysbrk].count--;
163                         mutex_unlock(&dbgcomlock);
164                         return;
165                 }
166         }
167         mutex_unlock(&dbgcomlock);
168         /* call cacaodbgserver */
169         __asm__ ("setsysbrkpt:");
170         TRAP; 
171 }
172
173
174 /* jvmti_add_breakpoint *******************************************************
175
176    adds a breakpoint to breakpoint table and calls set breakpoint
177
178 *******************************************************************************/
179
180 void jvmti_add_breakpoint(void* addr, jmethodID method, jlocation location) {
181         struct brkpts *jvmtibrkpt;
182
183         mutex_lock(&dbgcomlock);
184         jvmtibrkpt = &dbgcom->jvmtibrkpt;;
185
186         if (jvmtibrkpt->size == jvmtibrkpt->num)
187                 breakpointtable_creator();
188
189         assert (jvmtibrkpt->size > jvmtibrkpt->num);
190         fprintf (stderr,"add brk add: %p\n",addr);
191         jvmtibrkpt->brk[jvmtibrkpt->num].addr = addr;
192         jvmtibrkpt->brk[jvmtibrkpt->num].method = method;
193         jvmtibrkpt->brk[jvmtibrkpt->num].location = location;
194
195         /* todo: set breakpoint */
196 /*      jvmtibrkpt.brk[jvmtibrkpt.num].orig = */
197         jvmtibrkpt->num++;
198         mutex_unlock(&dbgcomlock);
199
200         fprintf (stderr,"add brk done\n");
201 }
202
203
204
205
206 /* jvmti_cacaodbgserver_quit **************************************************
207
208    quits cacaodbgserver if the last jvmti environment gets disposed
209
210 *******************************************************************************/
211 void jvmti_cacaodbgserver_quit(){
212         mutex_lock(&dbgcomlock);
213         dbgcom->running--;
214         if (dbgcom->running  == 0) {
215                 __asm__ ("cacaodbgserver_quit:");
216                 TRAP;
217                 /* get cacaodbserver exit */
218                 wait(NULL);
219                 dbgcom = NULL;
220         }
221         mutex_unlock(&dbgcomlock);
222 }
223
224
225
226 /* jvmti_cacao_generic_breakpointhandler **************************************
227
228    convert cacao breakpoints in jvmti events and fire event
229
230 *******************************************************************************/
231
232 static void jvmti_cacao_generic_breakpointhandler(int kindofbrk){
233         genericEventData data; 
234
235         switch (kindofbrk) {
236         case THREADSTARTBRK:
237                 data.ev=JVMTI_EVENT_THREAD_START; 
238                 break;
239         case THREADENDBRK:
240                 data.ev=JVMTI_EVENT_THREAD_END; 
241                 break;
242         case CLASSLOADBRK:
243                 data.ev=JVMTI_EVENT_CLASS_LOAD; 
244                 break;
245         case CLASSPREPARERK:
246                 data.ev=JVMTI_EVENT_CLASS_PREPARE; 
247                 break;
248         case CLASSFILELOADHOOKBRK:
249                 data.ev=JVMTI_EVENT_CLASS_FILE_LOAD_HOOK; 
250                 break;
251         case COMPILEDMETHODLOADBRK:
252                 data.ev=JVMTI_EVENT_COMPILED_METHOD_LOAD; 
253                 break;
254         case COMPILEDMETHODUNLOADBRK:
255                 data.ev=JVMTI_EVENT_COMPILED_METHOD_UNLOAD; 
256                 break;
257         default:
258                 fprintf(stderr,"unhandled kind of cacao break %d\n",kindofbrk);
259                 return;
260         }
261         jvmti_fireEvent(&data);
262 }
263
264
265
266 /* jvmti_cacao_debug_init ***************************************************************
267
268    starts up a new cacaodbgserver process if needed
269
270 *******************************************************************************/
271
272 void jvmti_cacao_debug_init() {
273         pid_t dbgserver;        
274
275         /* start new cacaodbgserver if needed*/
276         mutex_lock(&dbgcomlock);
277         if (dbgcom == NULL) {
278                 dbgcom = heap_allocate(sizeof(cacaodbgcommunication),true,NULL);                
279                 dbgcom->running = 1;
280                 jvmti = true;
281
282                 breakpointtable_creator();
283                 /* set addresses of hard coded TRAPs */
284                 __asm__ ("movl $setsysbrkpt,%0;" 
285                          :"=m"(dbgcom->jvmtibrkpt.brk[SETSYSBRKPT].addr));
286                 __asm__ ("movl $cacaodbgserver_quit,%0;" 
287                          :"=m"(dbgcom->jvmtibrkpt.brk[CACAODBGSERVERQUIT].addr));
288
289                 dbgserver = fork();
290                 if (dbgserver  == (-1)) {
291                         log_text("cacaodbgserver fork error");
292                         exit(1);
293                 } else {
294                         if (dbgserver == 0) {
295                                 if (execlp("cacaodbgserver","cacaodbgserver",(char *) NULL) == -1) {
296                                         log_text("unable to execute cacaodbgserver");
297                                         exit(1);
298                                 }
299                         }
300                 }
301                 mutex_unlock(&dbgcomlock);
302                 /* let cacaodbgserver get ready */
303                 sleep(1);
304         } else {
305                 dbgcom->running++;
306                 mutex_unlock(&dbgcomlock);
307         }
308 }
309
310
311 /* jvmti_ClassFileLoadHook ****************************************************
312
313   prepares firing a new Class File Load Hook event
314
315 *******************************************************************************/
316
317 void jvmti_ClassFileLoadHook(utf* name, int class_data_len, 
318                                                          unsigned char* class_data, 
319                                                          java_objectheader* loader, 
320                                                          java_objectheader* protection_domain, 
321                                                          jint* new_class_data_len, 
322                                                          unsigned char** new_class_data) {
323         genericEventData d;
324         
325         d.ev = JVMTI_EVENT_CLASS_FILE_LOAD_HOOK;
326         d.klass = NULL; /* class is not redefined */
327         d.object = loader;
328         d.name = (char*)MNEW(char,(utf_bytes(name)+1));
329         utf_sprint_convert_to_latin1(d.name, name);
330         d.protection_domain = protection_domain;
331         d.class_data = class_data;
332         d.jint1 = class_data_len;
333         d.new_class_data_len = new_class_data_len;
334         d.new_class_data = new_class_data;
335
336         jvmti_fireEvent(&d);
337         MFREE(d.name,char,utf_bytes(name)+1);
338 }
339
340
341 /* jvmti_ClassFileLoadHook ****************************************************
342
343   prepares firing a new Class Prepare or Load event
344
345 *******************************************************************************/
346
347 void jvmti_ClassLoadPrepare(bool prepared, classinfo *c) {
348         genericEventData d;
349
350         if (prepared) 
351                 d.ev = JVMTI_EVENT_CLASS_PREPARE;
352         else 
353                 d.ev = JVMTI_EVENT_CLASS_LOAD;
354
355         d.klass = c;
356         jvmti_fireEvent(&d);    
357 }
358
359
360 /* jvmti_MonitorContendedEntering *********************************************
361
362   prepares firing a new Monitor Contended Enter or Entered event
363
364 *******************************************************************************/
365
366 void jvmti_MonitorContendedEntering(bool entered, jobject obj) {
367         genericEventData d;
368
369         if (entered) 
370                 d.ev = JVMTI_EVENT_MONITOR_CONTENDED_ENTERED;
371         else 
372                 d.ev = JVMTI_EVENT_MONITOR_CONTENDED_ENTER;
373
374         d.object = obj;
375
376         jvmti_fireEvent(&d);    
377 }
378
379 /* jvmti_MonitorWaiting ******************************************************
380
381   prepares firing a new Monitor Wait or Waited event
382
383 *******************************************************************************/
384
385 void jvmti_MonitorWaiting(bool wait, jobject obj, jlong timeout) {
386         genericEventData d;
387
388         if (wait) {
389                 d.ev = JVMTI_EVENT_MONITOR_WAIT;
390                 d.jlong = timeout;
391         } else {
392                 d.ev = JVMTI_EVENT_MONITOR_WAITED;
393                 d.b = timeout != 0;
394         }
395
396         d.object = obj;
397
398         jvmti_fireEvent(&d);    
399 }
400
401 /* jvmti_ThreadStartEnd ********************************************************
402
403   prepares firing a new Thread Start or End event
404
405 *******************************************************************************/
406
407 void jvmti_ThreadStartEnd(jvmtiEvent ev) {
408         genericEventData d;
409
410         d.ev = ev;
411         jvmti_fireEvent(&d);    
412 }
413
414 /* jvmti_NativeMethodBind *****************************************************
415
416   prepares firing a new Native Method Bind event
417
418 *******************************************************************************/
419
420 void jvmti_NativeMethodBind(jmethodID method, void* address, 
421                                                         void** new_address_ptr) {
422         genericEventData d;
423
424         d.ev = JVMTI_EVENT_NATIVE_METHOD_BIND;
425         d.method = method;
426         d.address = address;
427         d.new_address_ptr = new_address_ptr;
428         
429         jvmti_fireEvent(&d);    
430 }
431
432
433
434 /*
435  * These are local overrides for various environment variables in Emacs.
436  * Please do not remove this and leave it at the end of the file, where
437  * Emacs will automagically detect them.
438  * ---------------------------------------------------------------------
439  * Local variables:
440  * mode: c
441  * indent-tabs-mode: t
442  * c-basic-offset: 4
443  * tab-width: 4
444  * End:
445  * vim:noexpandtab:sw=4:ts=4:
446  */