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