src/native/vm/VMVirtualMachine.c (suspendThread): print error message with printjvmti...
[cacao.git] / src / native / jvmti / VMjdwp.c
1 /* src/native/vm/VMjdwp.c - jvmti->jdwp interface
2
3    Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25    Contact: cacao@cacaojvm.org
26
27    Author: Martin Platter
28
29    Changes:             
30
31
32    $Id: VMjdwp.c 4996 2006-05-31 13:53:16Z motse $
33
34 */
35
36 #include "native/jvmti/jvmti.h"
37 #include "native/jvmti/VMjdwp.h"
38
39 #include <stdlib.h>
40 #include <string.h>
41
42 void printjvmtierror(char *desc, jvmtiError err) {
43     char* errdesc;
44         
45         if (err == JVMTI_ERROR_NONE) return;
46         (*jvmtienv)->GetErrorName(jvmtienv,err, &errdesc);
47         fprintf(stderr,"%s: jvmti error %s\n",desc, errdesc);
48         fflush(stderr);
49         (*jvmtienv)->Deallocate(jvmtienv,(unsigned char*)errdesc);
50 }
51
52
53
54 static jmethodID notifymid = NULL;
55 static jclass Jdwpclass = NULL;
56
57 static void notify (JNIEnv* jni_env, jobject event){
58         fprintf(stderr,"VMjdwp notfiy called");
59
60     if (notifymid == NULL) {
61                 notifymid = (*jni_env)->
62                         GetStaticMethodID(jni_env,Jdwpclass,
63                                                           "notify","(Lgnu/classpath/jdwp/event/Event;)V");
64                         if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
65                                 fprintf(stderr,"could not get notify method\n");
66                                 (*jni_env)->ExceptionDescribe(jni_env);
67                                 exit(1); 
68                         }
69     }
70     
71         (*jni_env)->CallStaticVoidMethod(jni_env,Jdwpclass,notifymid,event);
72     if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
73         fprintf(stderr,"Exception occourred in notify mehtod\n");
74                 (*jni_env)->ExceptionDescribe(jni_env);
75                 exit(1); 
76         }
77
78 }
79
80 /*static void ThreadStart (jvmtiEnv *jvmti_env,
81                          JNIEnv* jni_env,
82                          jthread thread){
83         jclass cl;
84         jmethodID cc;
85         jobject obj;
86
87         GETJNIMETHOD(jni_env,cl,"gnu/classpath/jdwp/event/ThreadStartEvent",cc,"<init>","(Ljava/lang/Thread;)V"); 
88
89         obj = builtin_new(cl);
90         if (!obj) throw_main_exception_exit();
91
92         fprintf(stderr,"VMjdwp:ThreadStart: thread %p\n",thread);
93         fflush(stderr);
94
95         vm_call_method((methodinfo*)cc, obj, thread);
96
97         if (*exceptionptr)
98                 throw_main_exception_exit();
99
100         notify (jni_env,obj);
101         } */
102
103
104 /* setup_jdwp_thread **********************************************************
105
106    Helper function to start JDWP listening thread
107
108 *******************************************************************************/
109
110 static void setup_jdwp_thread(JNIEnv* jni_env) {
111         jobject o;
112         jmethodID m;
113         jstring  s;
114
115         /* new gnu.classpath.jdwp.Jdwp() */
116     Jdwpclass = (*jni_env)->FindClass(jni_env, "gnu/classpath/jdwp/Jdwp"); 
117     if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
118         fprintf(stderr,"could not find gnu/classpath/jdwp/Jdwp\n");
119                 (*jni_env)->ExceptionDescribe(jni_env);
120                 exit(1); 
121         }
122
123         
124         m = (*jni_env)->GetMethodID(jni_env,Jdwpclass,"<init>","()V");
125     if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
126         fprintf(stderr,"could not get Jdwp constructor\n");
127                 (*jni_env)->ExceptionDescribe(jni_env);
128                 exit(1); 
129         }
130         
131         o = (*jni_env)->NewObject(jni_env, Jdwpclass, m);
132     if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
133         fprintf(stderr,"error calling Jdwp constructor\n");
134                 (*jni_env)->ExceptionDescribe(jni_env);
135                 exit(1); 
136         }
137         
138         
139         /* configure(jdwpoptions) */
140         m = (*jni_env)->GetMethodID(jni_env,Jdwpclass,"configure",
141                                                                 "(Ljava/lang/String;)V");
142     if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
143         fprintf(stderr,"could not get Jdwp configure method\n");
144                 (*jni_env)->ExceptionDescribe(jni_env);
145                 exit(1); 
146         }
147
148
149         s = (*jni_env)->NewStringUTF(jni_env,jdwpoptions);
150     if (s == NULL) {
151         fprintf(stderr,"could not get new java string from jdwp options\n");
152                 exit(1); 
153         }
154
155         free(jdwpoptions);
156         
157         (*jni_env)->CallVoidMethod(jni_env,o,m,s);
158     if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
159         fprintf(stderr,"Exception occourred in Jdwp configure\n");
160                 (*jni_env)->ExceptionDescribe(jni_env);
161                 exit(1); 
162         }
163
164         m = (*jni_env)->GetMethodID(jni_env,Jdwpclass,"_doInitialization","()V");
165     if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
166         fprintf(stderr,"could not get Jdwp _doInitialization method\n");
167                 (*jni_env)->ExceptionDescribe(jni_env);
168                 exit(1); 
169         }
170
171
172         (*jni_env)->CallVoidMethod(jni_env,o,m);
173     if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
174         fprintf(stderr,"Exception occourred in Jdwp _doInitialization\n");
175                 (*jni_env)->ExceptionDescribe(jni_env);
176                 exit(1); 
177         }
178 }
179
180
181 static void VMInit (jvmtiEnv *jvmti_env, 
182                     JNIEnv* jni_env,
183                     jthread thread) {
184         jclass cl;
185         jmethodID m;
186         jobject eventobj;
187         jvmtiError err; 
188
189         fprintf(stderr,"JDWP VMInit\n");
190
191         /* startup gnu classpath jdwp thread */
192         setup_jdwp_thread(jni_env);
193
194         fprintf(stderr,"JDWP listening thread started\n");
195
196     cl = (*jni_env)->FindClass(jni_env, 
197                                                                           "gnu/classpath/jdwp/event/VmInitEvent");
198     if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
199         fprintf(stderr,"could not find class VMInitEvent\n");
200                 (*jni_env)->ExceptionDescribe(jni_env);
201                 exit(1); 
202         }
203
204         m = (*jni_env)->GetMethodID(jni_env,cl,"<init>",
205                                                                 "(Ljava/lang/Thread;)V");
206     if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
207         fprintf(stderr,"could not get VmInitEvent constructor\n");
208                 (*jni_env)->ExceptionDescribe(jni_env);
209                 exit(1); 
210         }
211
212         eventobj = (*jni_env)->NewObject(jni_env, cl, m, thread);
213     if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
214         fprintf(stderr,"error calling VmInitEvent constructor\n");
215                 (*jni_env)->ExceptionDescribe(jni_env);
216                 exit(1); 
217         }
218
219
220         notify (jni_env,eventobj);
221
222         if (suspend) {
223                 fprintf(stderr,"suspend initial thread\n");
224                 err = (*jvmti_env)->SuspendThread(jvmti_env,thread);
225                 printjvmtierror("error suspending initial thread",err);
226         }
227 }
228
229 static void VMDeath (jvmtiEnv *jvmti_env,
230                      JNIEnv* jni_env) {
231   fprintf(stderr,"JVMTI-Event: IMPLEMENT ME!!!");
232 }
233
234 static void usage() {   
235         puts("usage jdwp:[help]|(<option>=<value>),*");
236         puts("   transport=[dt_socket|...]");
237         puts("   address=<hostname:port>");
238         puts("   server=[y|n]");
239         puts("   suspend=[y|n]");
240 }
241
242 static bool processoptions(char *options) {
243         int i,len;
244         
245         if (strncmp(options,"help",4) == 0) {
246                 usage();
247                 return false;
248         }
249
250         suspend = true;         /* default value */
251
252
253         /* copy options for later use in java jdwp listen thread configure */
254         jdwpoptions = malloc(sizeof(char)*strlen(options));
255         strncpy(jdwpoptions, options, sizeof(char)*strlen(options));
256
257         len = strlen(options);
258         
259         i=0;
260         while (i<len) {
261                 if (strncmp("suspend=",&options[i],8)==0) {
262                         if (8>=strlen(&options[i])) {
263                                 if ((options[i+8]== 'y') || (options[i+8]== 'n')) {
264                                         suspend = options[i+8]== 'y';
265                                 } else {
266                                         printf("jdwp error argument: %s\n",options);
267                                         usage();
268                                         return -1;
269                                 }
270                         }
271                 } else {
272                         /* these options will be handled by jdwp java configure */
273                         if ((strncmp("transport=",options,10)==0) ||
274                                 (strncmp("server=",options,7)==0)) {
275                         } else {
276                                 printf("jdwp unkown argument: %s\n",options);
277                                 usage();
278                                 return false;
279                         }
280                 }
281                 while ((options[i]!=',')&&(i<len)) i++;
282                 i++;
283         }
284         return true;    
285 }
286
287
288 JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved) { 
289         jint rc;
290         int end, i=0;
291         jvmtiCapabilities cap;
292         jvmtiError e;
293
294
295         fprintf(stderr,"jdwp Agent_OnLoad options: %s\n",options);
296         if (!processoptions(options)) return -1;
297         
298         rc = (*vm)->GetEnv(vm, (void**)&jvmtienv, JVMTI_VERSION_1_0);
299         if (rc != JNI_OK) {         
300                 fprintf(stderr, "jdwp: Unable to get jvmtiEnv error=%d\n", rc);
301                 return -1;              
302         }
303         
304         /* set eventcallbacks */
305         if (JVMTI_ERROR_NONE != 
306                 (e = (*jvmtienv)->SetEventCallbacks(jvmtienv,
307                                                                            &jvmti_jdwp_EventCallbacks,
308                                                                            sizeof(jvmtiEventCallbacks)))){
309                 printjvmtierror("jdwp: unable to setup event callbacks", e);
310                 return -1;
311         }
312
313         e = (*jvmtienv)->GetPotentialCapabilities(jvmtienv, &cap);
314         printjvmtierror("jdwp: unable to get potential capabilities", e);
315         if (e == JVMTI_ERROR_NONE) 
316                 e = (*jvmtienv)->AddCapabilities(jvmtienv, &cap);
317         if (e != JVMTI_ERROR_NONE) {
318                 printjvmtierror("jdwp: error adding jvmti capabilities", e);
319                 return -1;
320         }
321         
322
323         end = sizeof(jvmtiEventCallbacks) / sizeof(void*);
324         for (i = 0; i < end; i++) {
325                 /* enable VM callbacks  */
326                 if (((void**)&jvmti_jdwp_EventCallbacks)[i] != NULL) {
327                         e = (*jvmtienv)->SetEventNotificationMode(jvmtienv,
328                                                                                                           JVMTI_ENABLE,
329                                                                                                           JVMTI_EVENT_START_ENUM+i,
330                                                                                                           NULL);
331                         
332                         if (JVMTI_ERROR_NONE != e) {
333                                 printjvmtierror("jdwp: unable to setup event notification mode",e);
334                                 return -1;
335                         }
336                 }
337         }
338
339         return 0;
340 }
341         
342
343 jvmtiEventCallbacks jvmti_jdwp_EventCallbacks = {
344     &VMInit,
345     &VMDeath,
346     NULL, /*    &ThreadStart,*/
347     NULL, /*    &ThreadEnd, */
348     NULL, /* &ClassFileLoadHook, */
349     NULL, /* &ClassLoad, */
350     NULL, /* &ClassPrepare,*/
351     NULL, /* &VMStart */
352     NULL, /* &Exception, */
353     NULL, /* &ExceptionCatch, */
354     NULL, /* &SingleStep, */
355     NULL, /* &FramePop, */
356     NULL, /* &Breakpoint, */
357     NULL, /* &FieldAccess, */
358     NULL, /* &FieldModification, */
359     NULL, /* &MethodEntry, */
360     NULL, /* &MethodExit, */
361     NULL, /* &NativeMethodBind, */
362     NULL, /* &CompiledMethodLoad, */
363     NULL, /* &CompiledMethodUnload, */
364     NULL, /* &DynamicCodeGenerated, */
365     NULL, /* &DataDumpRequest, */
366     NULL,
367     NULL, /* &MonitorWait, */
368     NULL, /* &MonitorWaited, */
369     NULL, /* &MonitorContendedEnter, */
370     NULL, /* &MonitorContendedEntered, */
371     NULL,
372     NULL,
373     NULL,
374     NULL,
375     NULL, /* &GarbageCollectionStart, */
376     NULL, /* &GarbageCollectionFinish, */
377     NULL, /* &ObjectFree, */
378     NULL, /* &VMObjectAlloc, */
379 };
380
381
382 /*
383  * These are local overrides for various environment variables in Emacs.
384  * Please do not remove this and leave it at the end of the file, where
385  * Emacs will automagically detect them.
386  * ---------------------------------------------------------------------
387  * Local variables:
388  * mode: c
389  * indent-tabs-mode: t
390  * c-basic-offset: 4
391  * tab-width: 4
392  * End:
393  */