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
33 #include "native/jvmti/jvmti.h"
34 #include "native/jvmti/VMjdwp.h"
39 void printjvmtierror(char *desc, jvmtiError err) {
42 if (err == JVMTI_ERROR_NONE) return;
43 (*jvmtienv)->GetErrorName(jvmtienv,err, &errdesc);
44 fprintf(stderr,"%s: jvmti error %s\n",desc, errdesc);
46 (*jvmtienv)->Deallocate(jvmtienv,(unsigned char*)errdesc);
50 /* class and method IDs */
51 static jclass Jdwpclass, threadstartclass,threadendclass, classprepareclass, vmmethodclass, locationclass, breakpointclass;
52 static jmethodID notifymid, threadstartmid,threadendmid, classpreparemid,
53 vmmethodmid, locationmid, breakpointmid;
55 static void notify (JNIEnv* jni_env, jobject event){
56 fprintf(stderr,"VMjdwp notfiy called\n");
58 (*jni_env)->CallStaticVoidMethod(jni_env,Jdwpclass,notifymid,event);
59 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
60 fprintf(stderr,"Exception occourred in notify mehtod\n");
61 (*jni_env)->ExceptionDescribe(jni_env);
66 static void ThreadStart (jvmtiEnv *jvmti_env, JNIEnv* jni_env,
71 NewObject(jni_env, threadstartclass, threadstartmid, thread);
72 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
73 fprintf(stderr,"error calling ThreadStartEvent constructor\n");
74 (*jni_env)->ExceptionDescribe(jni_env);
78 fprintf(stderr,"VMjdwp:ThreadStart: thread %p\n",thread);
85 static void ThreadEnd (jvmtiEnv *jvmti_env, JNIEnv* jni_env,
90 obj = (*jni_env)->NewObject(jni_env, threadendclass, threadendmid, thread);
91 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
92 fprintf(stderr,"error calling ThreadEndEvent constructor\n");
93 (*jni_env)->ExceptionDescribe(jni_env);
97 fprintf(stderr,"VMjdwp:ThreadEnd: thread %p\n",thread);
100 notify (jni_env,obj);
104 static void ClassPrepare (jvmtiEnv *jvmti_env, JNIEnv* jni_env,
105 jthread thread, jclass klass) {
110 if (JVMTI_ERROR_NONE !=
111 (e = (*jvmtienv)->GetClassStatus(jvmtienv, klass, &classstatus))) {
112 printjvmtierror("unable to get class status", e);
116 obj = (*jni_env)->NewObject(jni_env, classprepareclass, classpreparemid, thread, klass, classstatus);
117 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
118 fprintf(stderr,"error calling ClassPrepareEvent constructor\n");
119 (*jni_env)->ExceptionDescribe(jni_env);
123 fprintf(stderr,"VMjdwp:ClassPrepareEvent: thread %p\n",thread);
126 notify (jni_env,obj);
129 static void Exception (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
130 jmethodID method, jlocation location, jobject exception,
131 jmethodID catch_method, jlocation catch_location) {
132 /* gnu classpath jdwp has no ExceptionEvent yet */
133 fprintf(stderr,"VMjdwp:Exception: thread %p\n",thread);
138 static void Breakpoint (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
139 jmethodID method, jlocation location) {
140 jobject vmmethod, loc, ev;
144 if (JVMTI_ERROR_NONE !=
145 (e = (*jvmtienv)->GetMethodDeclaringClass(jvmtienv,
148 printjvmtierror("unable to get declaring class", e);
152 vmmethod = (*jni_env)->NewObject(jni_env, vmmethodclass, vmmethodmid,
154 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
155 fprintf(stderr,"error calling VMMethod constructor\n");
156 (*jni_env)->ExceptionDescribe(jni_env);
160 loc = (*jni_env)->NewObject(jni_env, locationclass, locationmid,
162 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
163 fprintf(stderr,"error calling location constructor\n");
164 (*jni_env)->ExceptionDescribe(jni_env);
168 /* XXX todo: get object instance - needs jvmti local variable support */
169 ev = (*jni_env)->NewObject(jni_env, breakpointclass, breakpointmid,
171 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
172 fprintf(stderr,"error calling breakpoint constructor\n");
173 (*jni_env)->ExceptionDescribe(jni_env);
177 fprintf(stderr,"VMjdwp:Breakpoint: thread %p\n",thread);
184 static void MethodEntry (jvmtiEnv *jvmti_env, JNIEnv* jni_env,
185 jthread thread, jmethodID method) {
186 /* do not report gnu/classpath/jdwp method entries */
190 static void VMDeath (jvmtiEnv *jvmti_env,
192 fprintf(stderr,"JVMTI-Event: IMPLEMENT ME!!!");
196 /* setup_jdwp_thread **********************************************************
198 Helper function to start JDWP listening thread
200 *******************************************************************************/
202 static void setup_jdwp_thread(JNIEnv* jni_env) {
207 /* new gnu.classpath.jdwp.Jdwp() */
208 m = (*jni_env)->GetMethodID(jni_env,Jdwpclass,"<init>","()V");
209 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
210 fprintf(stderr,"could not get Jdwp constructor\n");
211 (*jni_env)->ExceptionDescribe(jni_env);
215 o = (*jni_env)->NewObject(jni_env, Jdwpclass, m);
216 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
217 fprintf(stderr,"error calling Jdwp constructor\n");
218 (*jni_env)->ExceptionDescribe(jni_env);
222 jdwpthread = (jthread)o;
225 /* configure(jdwpoptions) */
226 m = (*jni_env)->GetMethodID(jni_env,Jdwpclass,"configure",
227 "(Ljava/lang/String;)V");
228 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
229 fprintf(stderr,"could not get Jdwp configure method\n");
230 (*jni_env)->ExceptionDescribe(jni_env);
235 s = (*jni_env)->NewStringUTF(jni_env,jdwpoptions);
237 fprintf(stderr,"could not get new java string from jdwp options\n");
243 (*jni_env)->CallVoidMethod(jni_env,o,m,s);
244 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
245 fprintf(stderr,"Exception occourred in Jdwp configure\n");
246 (*jni_env)->ExceptionDescribe(jni_env);
250 m = (*jni_env)->GetMethodID(jni_env,Jdwpclass,"_doInitialization","()V");
251 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
252 fprintf(stderr,"could not get Jdwp _doInitialization method\n");
253 (*jni_env)->ExceptionDescribe(jni_env);
258 (*jni_env)->CallVoidMethod(jni_env,o,m);
259 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
260 fprintf(stderr,"Exception occourred in Jdwp _doInitialization\n");
261 (*jni_env)->ExceptionDescribe(jni_env);
266 #define FINDCLASSWITHEXCEPTION(CLASS,SIGNATURE) \
267 CLASS = (*jni_env)->FindClass(jni_env, SIGNATURE); \
268 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) { \
269 fprintf(stderr,"could not find %s\n", SIGNATURE); \
270 (*jni_env)->ExceptionDescribe(jni_env); \
273 #define GETMIDWITHEXCEPTION(CLASS, CLASSNAME, MID, METHODNAME, METHODSIG) \
274 FINDCLASSWITHEXCEPTION(CLASS, CLASSNAME); \
275 MID = (*jni_env)->GetMethodID(jni_env, CLASS, METHODNAME, METHODSIG); \
276 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) { \
277 fprintf(stderr,"could not get %s %s\n",CLASSNAME, METHODNAME); \
278 (*jni_env)->ExceptionDescribe(jni_env); \
283 static void fillidcache(JNIEnv* jni_env) {
284 FINDCLASSWITHEXCEPTION(Jdwpclass, "gnu/classpath/jdwp/Jdwp");
286 notifymid = (*jni_env)->
287 GetStaticMethodID(jni_env,Jdwpclass,
288 "notify","(Lgnu/classpath/jdwp/event/Event;)V");
289 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
290 fprintf(stderr,"could not get notify method\n");
291 (*jni_env)->ExceptionDescribe(jni_env);
295 GETMIDWITHEXCEPTION(threadstartclass,
296 "gnu/classpath/jdwp/event/ThreadStartEvent",
297 threadstartmid, "<init>", "(Ljava/lang/Thread;)V");
300 GETMIDWITHEXCEPTION(threadendclass,
301 "gnu/classpath/jdwp/event/ThreadEndEvent",
302 threadendmid, "<init>", "(Ljava/lang/Thread;)V");
305 GETMIDWITHEXCEPTION(classprepareclass,
306 "gnu/classpath/jdwp/event/ClassPrepareEvent",
307 classpreparemid, "<init>",
308 "(Ljava/lang/Thread;Ljava/lang/Class;I)V");
311 GETMIDWITHEXCEPTION(vmmethodclass, "gnu/classpath/jdwp/VMMethod",
312 vmmethodmid, "<init>", "(Ljava/lang/Class;J)V");
314 GETMIDWITHEXCEPTION(locationclass, "gnu/classpath/jdwp/util/Location",
315 locationmid, "<init>",
316 "(Lgnu/classpath/jdwp/VMMethod;J)V");
321 "gnu/classpath/jdwp/event/BreakpointEvent",
322 breakpointmid, "<init>",
323 "(Ljava/lang/Thread;Lgnu/classpath/jdwp/util/Location;Ljava/lang/Object;)V");
327 static void VMInit (jvmtiEnv *jvmti_env,
335 fprintf(stderr,"JDWP VMInit\n");
337 /* get needed jmethodIDs and jclasses for callbacks */
338 fillidcache(jni_env);
340 /* startup gnu classpath jdwp thread */
341 setup_jdwp_thread(jni_env);
343 fprintf(stderr,"JDWP listening thread started\n");
345 /* send VmInitEvent */
346 cl = (*jni_env)->FindClass(jni_env,
347 "gnu/classpath/jdwp/event/VmInitEvent");
348 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
349 fprintf(stderr,"could not find class VMInitEvent\n");
350 (*jni_env)->ExceptionDescribe(jni_env);
354 m = (*jni_env)->GetMethodID(jni_env,cl,"<init>",
355 "(Ljava/lang/Thread;)V");
356 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
357 fprintf(stderr,"could not get VmInitEvent constructor\n");
358 (*jni_env)->ExceptionDescribe(jni_env);
362 eventobj = (*jni_env)->NewObject(jni_env, cl, m, thread);
363 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
364 fprintf(stderr,"error calling VmInitEvent constructor\n");
365 (*jni_env)->ExceptionDescribe(jni_env);
370 notify (jni_env,eventobj);
373 fprintf(stderr,"suspend initial thread\n");
374 err = (*jvmti_env)->SuspendThread(jvmti_env,thread);
375 printjvmtierror("error suspending initial thread",err);
379 static void usage() {
380 puts("usage jdwp:[help]|(<option>=<value>),*");
381 puts(" transport=[dt_socket|...]");
382 puts(" address=<hostname:port>");
383 puts(" server=[y|n]");
384 puts(" suspend=[y|n]");
387 static bool processoptions(char *options) {
390 if (strncmp(options,"help",4) == 0) {
395 suspend = true; /* default value */
398 /* copy options for later use in java jdwp listen thread configure */
399 jdwpoptions = malloc(sizeof(char)*strlen(options));
400 strncpy(jdwpoptions, options, sizeof(char)*strlen(options));
402 len = strlen(options);
406 if (strncmp("suspend=",&options[i],8)==0) {
407 if (8>=strlen(&options[i])) {
408 if ((options[i+8]== 'y') || (options[i+8]== 'n')) {
409 suspend = options[i+8]== 'y';
411 printf("jdwp error argument: %s\n",options);
417 /* these options will be handled by jdwp java configure */
418 if ((strncmp("transport=",options,10)==0) ||
419 (strncmp("server=",options,7)==0)) {
421 printf("jdwp unkown argument: %s\n",options);
426 while ((options[i]!=',')&&(i<len)) i++;
433 JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved) {
435 jvmtiCapabilities cap;
439 fprintf(stderr,"jdwp Agent_OnLoad options: %s\n",options);
440 if (!processoptions(options)) return -1;
442 rc = (*vm)->GetEnv(vm, (void**)&jvmtienv, JVMTI_VERSION_1_0);
444 fprintf(stderr, "jdwp: Unable to get jvmtiEnv error=%d\n", rc);
448 /* set eventcallbacks */
449 if (JVMTI_ERROR_NONE !=
450 (e = (*jvmtienv)->SetEventCallbacks(jvmtienv,
451 &jvmti_jdwp_EventCallbacks,
452 sizeof(jvmtiEventCallbacks)))){
453 printjvmtierror("jdwp: unable to setup event callbacks", e);
457 e = (*jvmtienv)->GetPotentialCapabilities(jvmtienv, &cap);
458 printjvmtierror("jdwp: unable to get potential capabilities", e);
459 if (e == JVMTI_ERROR_NONE)
460 e = (*jvmtienv)->AddCapabilities(jvmtienv, &cap);
461 if (e != JVMTI_ERROR_NONE) {
462 printjvmtierror("jdwp: error adding jvmti capabilities", e);
466 /* only enable needed events. VMVirtualMachine.registerEvent will
467 be used to enable other events by need */
468 if (JVMTI_ERROR_NONE != (e = (*jvmtienv)->
469 SetEventNotificationMode(jvmtienv, JVMTI_ENABLE,
472 printjvmtierror("jdwp unable to enable vm init callback",e);
480 jvmtiEventCallbacks jvmti_jdwp_EventCallbacks = {
485 NULL, /* &ClassFileLoadHook, */
486 NULL, /* &ClassLoad, */
490 NULL, /* &ExceptionCatch, */
491 NULL, /* &SingleStep, */
492 NULL, /* &FramePop, */
494 NULL, /* &FieldAccess, */
495 NULL, /* &FieldModification, */
497 NULL, /* &MethodExit, */
498 NULL, /* &NativeMethodBind, */
499 NULL, /* &CompiledMethodLoad, */
500 NULL, /* &CompiledMethodUnload, */
501 NULL, /* &DynamicCodeGenerated, */
502 NULL, /* &DataDumpRequest, */
504 NULL, /* &MonitorWait, */
505 NULL, /* &MonitorWaited, */
506 NULL, /* &MonitorContendedEnter, */
507 NULL, /* &MonitorContendedEntered, */
512 NULL, /* &GarbageCollectionStart, */
513 NULL, /* &GarbageCollectionFinish, */
514 NULL, /* &ObjectFree, */
515 NULL, /* &VMObjectAlloc, */
520 * These are local overrides for various environment variables in Emacs.
521 * Please do not remove this and leave it at the end of the file, where
522 * Emacs will automagically detect them.
523 * ---------------------------------------------------------------------
526 * indent-tabs-mode: t