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