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