1 /* src/native/vm/VMjdwp.c - jvmti->jdwp interface
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
8 This file is part of CACAO.
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.
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.
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
25 Contact: cacao@cacaojvm.org
27 Author: Martin Platter
32 $Id: VMjdwp.c 5019 2006-06-06 21:13:41Z motse $
36 #include "native/jvmti/jvmti.h"
37 #include "native/jvmti/VMjdwp.h"
42 void printjvmtierror(char *desc, jvmtiError err) {
45 if (err == JVMTI_ERROR_NONE) return;
46 (*jvmtienv)->GetErrorName(jvmtienv,err, &errdesc);
47 fprintf(stderr,"%s: jvmti error %s\n",desc, errdesc);
49 (*jvmtienv)->Deallocate(jvmtienv,(unsigned char*)errdesc);
53 /* class and method IDs */
54 static jclass Jdwpclass, threadstartclass,threadendclass, classprepareclass, vmmethodclass, locationclass, breakpointclass;
55 static jmethodID notifymid, threadstartmid,threadendmid, classpreparemid,
56 vmmethodmid, locationmid, breakpointmid;
58 static void notify (JNIEnv* jni_env, jobject event){
59 fprintf(stderr,"VMjdwp notfiy called\n");
61 (*jni_env)->CallStaticVoidMethod(jni_env,Jdwpclass,notifymid,event);
62 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
63 fprintf(stderr,"Exception occourred in notify mehtod\n");
64 (*jni_env)->ExceptionDescribe(jni_env);
69 static void ThreadStart (jvmtiEnv *jvmti_env, JNIEnv* jni_env,
74 NewObject(jni_env, threadstartclass, threadstartmid, thread);
75 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
76 fprintf(stderr,"error calling ThreadStartEvent constructor\n");
77 (*jni_env)->ExceptionDescribe(jni_env);
81 fprintf(stderr,"VMjdwp:ThreadStart: thread %p\n",thread);
88 static void ThreadEnd (jvmtiEnv *jvmti_env, JNIEnv* jni_env,
93 obj = (*jni_env)->NewObject(jni_env, threadendclass, threadendmid, thread);
94 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
95 fprintf(stderr,"error calling ThreadEndEvent constructor\n");
96 (*jni_env)->ExceptionDescribe(jni_env);
100 fprintf(stderr,"VMjdwp:ThreadEnd: thread %p\n",thread);
103 notify (jni_env,obj);
107 static void ClassPrepare (jvmtiEnv *jvmti_env, JNIEnv* jni_env,
108 jthread thread, jclass klass) {
113 if (JVMTI_ERROR_NONE !=
114 (e = (*jvmtienv)->GetClassStatus(jvmtienv, klass, &classstatus))) {
115 printjvmtierror("unable to get class status", e);
119 obj = (*jni_env)->NewObject(jni_env, classprepareclass, classpreparemid, thread, klass, classstatus);
120 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
121 fprintf(stderr,"error calling ClassPrepareEvent constructor\n");
122 (*jni_env)->ExceptionDescribe(jni_env);
126 fprintf(stderr,"VMjdwp:ClassPrepareEvent: thread %p\n",thread);
129 notify (jni_env,obj);
132 static void Exception (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
133 jmethodID method, jlocation location, jobject exception,
134 jmethodID catch_method, jlocation catch_location) {
135 /* gnu classpath jdwp has no ExceptionEvent yet */
136 fprintf(stderr,"VMjdwp:Exception: thread %p\n",thread);
141 static void Breakpoint (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
142 jmethodID method, jlocation location) {
143 jobject vmmethod, loc, ev;
147 if (JVMTI_ERROR_NONE !=
148 (e = (*jvmtienv)->GetMethodDeclaringClass(jvmtienv,
151 printjvmtierror("unable to get declaring class", e);
155 vmmethod = (*jni_env)->NewObject(jni_env, vmmethodclass, vmmethodmid,
157 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
158 fprintf(stderr,"error calling VMMethod constructor\n");
159 (*jni_env)->ExceptionDescribe(jni_env);
163 loc = (*jni_env)->NewObject(jni_env, locationclass, locationmid,
165 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
166 fprintf(stderr,"error calling location constructor\n");
167 (*jni_env)->ExceptionDescribe(jni_env);
171 ev = (*jni_env)->NewObject(jni_env, breakpointclass, breakpointmid,
173 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
174 fprintf(stderr,"error calling breakpoint constructor\n");
175 (*jni_env)->ExceptionDescribe(jni_env);
179 fprintf(stderr,"VMjdwp:Breakpoint: thread %p\n",thread);
186 static void MethodEntry (jvmtiEnv *jvmti_env, JNIEnv* jni_env,
187 jthread thread, jmethodID method) {
188 /* do not report gnu/classpath/jdwp method entries */
192 static void VMDeath (jvmtiEnv *jvmti_env,
194 fprintf(stderr,"JVMTI-Event: IMPLEMENT ME!!!");
198 /* setup_jdwp_thread **********************************************************
200 Helper function to start JDWP listening thread
202 *******************************************************************************/
204 static void setup_jdwp_thread(JNIEnv* jni_env) {
209 /* new gnu.classpath.jdwp.Jdwp() */
210 m = (*jni_env)->GetMethodID(jni_env,Jdwpclass,"<init>","()V");
211 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
212 fprintf(stderr,"could not get Jdwp constructor\n");
213 (*jni_env)->ExceptionDescribe(jni_env);
217 o = (*jni_env)->NewObject(jni_env, Jdwpclass, m);
218 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
219 fprintf(stderr,"error calling Jdwp constructor\n");
220 (*jni_env)->ExceptionDescribe(jni_env);
224 jdwpthread = (jthread)o;
227 /* configure(jdwpoptions) */
228 m = (*jni_env)->GetMethodID(jni_env,Jdwpclass,"configure",
229 "(Ljava/lang/String;)V");
230 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
231 fprintf(stderr,"could not get Jdwp configure method\n");
232 (*jni_env)->ExceptionDescribe(jni_env);
237 s = (*jni_env)->NewStringUTF(jni_env,jdwpoptions);
239 fprintf(stderr,"could not get new java string from jdwp options\n");
245 (*jni_env)->CallVoidMethod(jni_env,o,m,s);
246 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
247 fprintf(stderr,"Exception occourred in Jdwp configure\n");
248 (*jni_env)->ExceptionDescribe(jni_env);
252 m = (*jni_env)->GetMethodID(jni_env,Jdwpclass,"_doInitialization","()V");
253 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
254 fprintf(stderr,"could not get Jdwp _doInitialization method\n");
255 (*jni_env)->ExceptionDescribe(jni_env);
260 (*jni_env)->CallVoidMethod(jni_env,o,m);
261 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
262 fprintf(stderr,"Exception occourred in Jdwp _doInitialization\n");
263 (*jni_env)->ExceptionDescribe(jni_env);
268 #define FINDCLASSWITHEXCEPTION(CLASS,SIGNATURE) \
269 CLASS = (*jni_env)->FindClass(jni_env, SIGNATURE); \
270 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) { \
271 fprintf(stderr,"could not find %s\n", SIGNATURE); \
272 (*jni_env)->ExceptionDescribe(jni_env); \
275 #define GETMIDWITHEXCEPTION(CLASS, CLASSNAME, MID, METHODNAME, METHODSIG) \
276 FINDCLASSWITHEXCEPTION(CLASS, CLASSNAME); \
277 MID = (*jni_env)->GetMethodID(jni_env, CLASS, METHODNAME, METHODSIG); \
278 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) { \
279 fprintf(stderr,"could not get %s %s\n",CLASSNAME, METHODNAME); \
280 (*jni_env)->ExceptionDescribe(jni_env); \
285 static void fillidcache(JNIEnv* jni_env) {
286 FINDCLASSWITHEXCEPTION(Jdwpclass, "gnu/classpath/jdwp/Jdwp");
288 notifymid = (*jni_env)->
289 GetStaticMethodID(jni_env,Jdwpclass,
290 "notify","(Lgnu/classpath/jdwp/event/Event;)V");
291 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
292 fprintf(stderr,"could not get notify method\n");
293 (*jni_env)->ExceptionDescribe(jni_env);
297 GETMIDWITHEXCEPTION(threadstartclass,
298 "gnu/classpath/jdwp/event/ThreadStartEvent",
299 threadstartmid, "<init>", "(Ljava/lang/Thread;)V");
302 GETMIDWITHEXCEPTION(threadendclass,
303 "gnu/classpath/jdwp/event/ThreadEndEvent",
304 threadendmid, "<init>", "(Ljava/lang/Thread;)V");
307 GETMIDWITHEXCEPTION(classprepareclass,
308 "gnu/classpath/jdwp/event/ClassPrepareEvent",
309 classpreparemid, "<init>",
310 "(Ljava/lang/Thread;Ljava/lang/Class;I)V");
313 GETMIDWITHEXCEPTION(vmmethodclass, "gnu/classpath/jdwp/VMMethod",
314 vmmethodmid, "<init>", "(Ljava/lang/Class;J)V");
316 GETMIDWITHEXCEPTION(locationclass, "gnu/classpath/jdwp/util/Location",
317 locationmid, "<init>",
318 "(Lgnu/classpath/jdwp/VMMethod;J)V");
323 "gnu/classpath/jdwp/event/BreakpointEvent",
324 breakpointmid, "<init>",
325 "(Ljava/lang/Thread;Lgnu/classpath/jdwp/util/Location;)V");
329 static void VMInit (jvmtiEnv *jvmti_env,
337 fprintf(stderr,"JDWP VMInit\n");
339 /* get needed jmethodIDs and jclasses for callbacks */
340 fillidcache(jni_env);
342 /* startup gnu classpath jdwp thread */
343 setup_jdwp_thread(jni_env);
345 fprintf(stderr,"JDWP listening thread started\n");
347 /* send VmInitEvent */
348 cl = (*jni_env)->FindClass(jni_env,
349 "gnu/classpath/jdwp/event/VmInitEvent");
350 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
351 fprintf(stderr,"could not find class VMInitEvent\n");
352 (*jni_env)->ExceptionDescribe(jni_env);
356 m = (*jni_env)->GetMethodID(jni_env,cl,"<init>",
357 "(Ljava/lang/Thread;)V");
358 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
359 fprintf(stderr,"could not get VmInitEvent constructor\n");
360 (*jni_env)->ExceptionDescribe(jni_env);
364 eventobj = (*jni_env)->NewObject(jni_env, cl, m, thread);
365 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
366 fprintf(stderr,"error calling VmInitEvent constructor\n");
367 (*jni_env)->ExceptionDescribe(jni_env);
372 notify (jni_env,eventobj);
375 fprintf(stderr,"suspend initial thread\n");
376 err = (*jvmti_env)->SuspendThread(jvmti_env,thread);
377 printjvmtierror("error suspending initial thread",err);
381 static void usage() {
382 puts("usage jdwp:[help]|(<option>=<value>),*");
383 puts(" transport=[dt_socket|...]");
384 puts(" address=<hostname:port>");
385 puts(" server=[y|n]");
386 puts(" suspend=[y|n]");
389 static bool processoptions(char *options) {
392 if (strncmp(options,"help",4) == 0) {
397 suspend = true; /* default value */
400 /* copy options for later use in java jdwp listen thread configure */
401 jdwpoptions = malloc(sizeof(char)*strlen(options));
402 strncpy(jdwpoptions, options, sizeof(char)*strlen(options));
404 len = strlen(options);
408 if (strncmp("suspend=",&options[i],8)==0) {
409 if (8>=strlen(&options[i])) {
410 if ((options[i+8]== 'y') || (options[i+8]== 'n')) {
411 suspend = options[i+8]== 'y';
413 printf("jdwp error argument: %s\n",options);
419 /* these options will be handled by jdwp java configure */
420 if ((strncmp("transport=",options,10)==0) ||
421 (strncmp("server=",options,7)==0)) {
423 printf("jdwp unkown argument: %s\n",options);
428 while ((options[i]!=',')&&(i<len)) i++;
435 JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved) {
437 jvmtiCapabilities cap;
441 fprintf(stderr,"jdwp Agent_OnLoad options: %s\n",options);
442 if (!processoptions(options)) return -1;
444 rc = (*vm)->GetEnv(vm, (void**)&jvmtienv, JVMTI_VERSION_1_0);
446 fprintf(stderr, "jdwp: Unable to get jvmtiEnv error=%d\n", rc);
450 /* set eventcallbacks */
451 if (JVMTI_ERROR_NONE !=
452 (e = (*jvmtienv)->SetEventCallbacks(jvmtienv,
453 &jvmti_jdwp_EventCallbacks,
454 sizeof(jvmtiEventCallbacks)))){
455 printjvmtierror("jdwp: unable to setup event callbacks", e);
459 e = (*jvmtienv)->GetPotentialCapabilities(jvmtienv, &cap);
460 printjvmtierror("jdwp: unable to get potential capabilities", e);
461 if (e == JVMTI_ERROR_NONE)
462 e = (*jvmtienv)->AddCapabilities(jvmtienv, &cap);
463 if (e != JVMTI_ERROR_NONE) {
464 printjvmtierror("jdwp: error adding jvmti capabilities", e);
468 /* only enable needed events. VMVirtualMachine.registerEvent will
469 be used to enable other events by need */
470 if (JVMTI_ERROR_NONE != (e = (*jvmtienv)->
471 SetEventNotificationMode(jvmtienv, JVMTI_ENABLE,
474 printjvmtierror("jdwp unable to enable vm init callback",e);
482 jvmtiEventCallbacks jvmti_jdwp_EventCallbacks = {
487 NULL, /* &ClassFileLoadHook, */
488 NULL, /* &ClassLoad, */
492 NULL, /* &ExceptionCatch, */
493 NULL, /* &SingleStep, */
494 NULL, /* &FramePop, */
496 NULL, /* &FieldAccess, */
497 NULL, /* &FieldModification, */
499 NULL, /* &MethodExit, */
500 NULL, /* &NativeMethodBind, */
501 NULL, /* &CompiledMethodLoad, */
502 NULL, /* &CompiledMethodUnload, */
503 NULL, /* &DynamicCodeGenerated, */
504 NULL, /* &DataDumpRequest, */
506 NULL, /* &MonitorWait, */
507 NULL, /* &MonitorWaited, */
508 NULL, /* &MonitorContendedEnter, */
509 NULL, /* &MonitorContendedEntered, */
514 NULL, /* &GarbageCollectionStart, */
515 NULL, /* &GarbageCollectionFinish, */
516 NULL, /* &ObjectFree, */
517 NULL, /* &VMObjectAlloc, */
522 * These are local overrides for various environment variables in Emacs.
523 * Please do not remove this and leave it at the end of the file, where
524 * Emacs will automagically detect them.
525 * ---------------------------------------------------------------------
528 * indent-tabs-mode: t