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 6213 2006-12-18 17:36:06Z twisti $
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 /* XXX todo: get object instance - needs jvmti local variable support */
172 ev = (*jni_env)->NewObject(jni_env, breakpointclass, breakpointmid,
174 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
175 fprintf(stderr,"error calling breakpoint constructor\n");
176 (*jni_env)->ExceptionDescribe(jni_env);
180 fprintf(stderr,"VMjdwp:Breakpoint: thread %p\n",thread);
187 static void MethodEntry (jvmtiEnv *jvmti_env, JNIEnv* jni_env,
188 jthread thread, jmethodID method) {
189 /* do not report gnu/classpath/jdwp method entries */
193 static void VMDeath (jvmtiEnv *jvmti_env,
195 fprintf(stderr,"JVMTI-Event: IMPLEMENT ME!!!");
199 /* setup_jdwp_thread **********************************************************
201 Helper function to start JDWP listening thread
203 *******************************************************************************/
205 static void setup_jdwp_thread(JNIEnv* jni_env) {
210 /* new gnu.classpath.jdwp.Jdwp() */
211 m = (*jni_env)->GetMethodID(jni_env,Jdwpclass,"<init>","()V");
212 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
213 fprintf(stderr,"could not get Jdwp constructor\n");
214 (*jni_env)->ExceptionDescribe(jni_env);
218 o = (*jni_env)->NewObject(jni_env, Jdwpclass, m);
219 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
220 fprintf(stderr,"error calling Jdwp constructor\n");
221 (*jni_env)->ExceptionDescribe(jni_env);
225 jdwpthread = (jthread)o;
228 /* configure(jdwpoptions) */
229 m = (*jni_env)->GetMethodID(jni_env,Jdwpclass,"configure",
230 "(Ljava/lang/String;)V");
231 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
232 fprintf(stderr,"could not get Jdwp configure method\n");
233 (*jni_env)->ExceptionDescribe(jni_env);
238 s = (*jni_env)->NewStringUTF(jni_env,jdwpoptions);
240 fprintf(stderr,"could not get new java string from jdwp options\n");
246 (*jni_env)->CallVoidMethod(jni_env,o,m,s);
247 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
248 fprintf(stderr,"Exception occourred in Jdwp configure\n");
249 (*jni_env)->ExceptionDescribe(jni_env);
253 m = (*jni_env)->GetMethodID(jni_env,Jdwpclass,"_doInitialization","()V");
254 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
255 fprintf(stderr,"could not get Jdwp _doInitialization method\n");
256 (*jni_env)->ExceptionDescribe(jni_env);
261 (*jni_env)->CallVoidMethod(jni_env,o,m);
262 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
263 fprintf(stderr,"Exception occourred in Jdwp _doInitialization\n");
264 (*jni_env)->ExceptionDescribe(jni_env);
269 #define FINDCLASSWITHEXCEPTION(CLASS,SIGNATURE) \
270 CLASS = (*jni_env)->FindClass(jni_env, SIGNATURE); \
271 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) { \
272 fprintf(stderr,"could not find %s\n", SIGNATURE); \
273 (*jni_env)->ExceptionDescribe(jni_env); \
276 #define GETMIDWITHEXCEPTION(CLASS, CLASSNAME, MID, METHODNAME, METHODSIG) \
277 FINDCLASSWITHEXCEPTION(CLASS, CLASSNAME); \
278 MID = (*jni_env)->GetMethodID(jni_env, CLASS, METHODNAME, METHODSIG); \
279 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) { \
280 fprintf(stderr,"could not get %s %s\n",CLASSNAME, METHODNAME); \
281 (*jni_env)->ExceptionDescribe(jni_env); \
286 static void fillidcache(JNIEnv* jni_env) {
287 FINDCLASSWITHEXCEPTION(Jdwpclass, "gnu/classpath/jdwp/Jdwp");
289 notifymid = (*jni_env)->
290 GetStaticMethodID(jni_env,Jdwpclass,
291 "notify","(Lgnu/classpath/jdwp/event/Event;)V");
292 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
293 fprintf(stderr,"could not get notify method\n");
294 (*jni_env)->ExceptionDescribe(jni_env);
298 GETMIDWITHEXCEPTION(threadstartclass,
299 "gnu/classpath/jdwp/event/ThreadStartEvent",
300 threadstartmid, "<init>", "(Ljava/lang/Thread;)V");
303 GETMIDWITHEXCEPTION(threadendclass,
304 "gnu/classpath/jdwp/event/ThreadEndEvent",
305 threadendmid, "<init>", "(Ljava/lang/Thread;)V");
308 GETMIDWITHEXCEPTION(classprepareclass,
309 "gnu/classpath/jdwp/event/ClassPrepareEvent",
310 classpreparemid, "<init>",
311 "(Ljava/lang/Thread;Ljava/lang/Class;I)V");
314 GETMIDWITHEXCEPTION(vmmethodclass, "gnu/classpath/jdwp/VMMethod",
315 vmmethodmid, "<init>", "(Ljava/lang/Class;J)V");
317 GETMIDWITHEXCEPTION(locationclass, "gnu/classpath/jdwp/util/Location",
318 locationmid, "<init>",
319 "(Lgnu/classpath/jdwp/VMMethod;J)V");
324 "gnu/classpath/jdwp/event/BreakpointEvent",
325 breakpointmid, "<init>",
326 "(Ljava/lang/Thread;Lgnu/classpath/jdwp/util/Location;Ljava/lang/Object;)V");
330 static void VMInit (jvmtiEnv *jvmti_env,
338 fprintf(stderr,"JDWP VMInit\n");
340 /* get needed jmethodIDs and jclasses for callbacks */
341 fillidcache(jni_env);
343 /* startup gnu classpath jdwp thread */
344 setup_jdwp_thread(jni_env);
346 fprintf(stderr,"JDWP listening thread started\n");
348 /* send VmInitEvent */
349 cl = (*jni_env)->FindClass(jni_env,
350 "gnu/classpath/jdwp/event/VmInitEvent");
351 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
352 fprintf(stderr,"could not find class VMInitEvent\n");
353 (*jni_env)->ExceptionDescribe(jni_env);
357 m = (*jni_env)->GetMethodID(jni_env,cl,"<init>",
358 "(Ljava/lang/Thread;)V");
359 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
360 fprintf(stderr,"could not get VmInitEvent constructor\n");
361 (*jni_env)->ExceptionDescribe(jni_env);
365 eventobj = (*jni_env)->NewObject(jni_env, cl, m, thread);
366 if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
367 fprintf(stderr,"error calling VmInitEvent constructor\n");
368 (*jni_env)->ExceptionDescribe(jni_env);
373 notify (jni_env,eventobj);
376 fprintf(stderr,"suspend initial thread\n");
377 err = (*jvmti_env)->SuspendThread(jvmti_env,thread);
378 printjvmtierror("error suspending initial thread",err);
382 static void usage() {
383 puts("usage jdwp:[help]|(<option>=<value>),*");
384 puts(" transport=[dt_socket|...]");
385 puts(" address=<hostname:port>");
386 puts(" server=[y|n]");
387 puts(" suspend=[y|n]");
390 static bool processoptions(char *options) {
393 if (strncmp(options,"help",4) == 0) {
398 suspend = true; /* default value */
401 /* copy options for later use in java jdwp listen thread configure */
402 jdwpoptions = malloc(sizeof(char)*strlen(options));
403 strncpy(jdwpoptions, options, sizeof(char)*strlen(options));
405 len = strlen(options);
409 if (strncmp("suspend=",&options[i],8)==0) {
410 if (8>=strlen(&options[i])) {
411 if ((options[i+8]== 'y') || (options[i+8]== 'n')) {
412 suspend = options[i+8]== 'y';
414 printf("jdwp error argument: %s\n",options);
420 /* these options will be handled by jdwp java configure */
421 if ((strncmp("transport=",options,10)==0) ||
422 (strncmp("server=",options,7)==0)) {
424 printf("jdwp unkown argument: %s\n",options);
429 while ((options[i]!=',')&&(i<len)) i++;
436 JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved) {
438 jvmtiCapabilities cap;
442 fprintf(stderr,"jdwp Agent_OnLoad options: %s\n",options);
443 if (!processoptions(options)) return -1;
445 rc = (*vm)->GetEnv(vm, (void**)&jvmtienv, JVMTI_VERSION_1_0);
447 fprintf(stderr, "jdwp: Unable to get jvmtiEnv error=%d\n", rc);
451 /* set eventcallbacks */
452 if (JVMTI_ERROR_NONE !=
453 (e = (*jvmtienv)->SetEventCallbacks(jvmtienv,
454 &jvmti_jdwp_EventCallbacks,
455 sizeof(jvmtiEventCallbacks)))){
456 printjvmtierror("jdwp: unable to setup event callbacks", e);
460 e = (*jvmtienv)->GetPotentialCapabilities(jvmtienv, &cap);
461 printjvmtierror("jdwp: unable to get potential capabilities", e);
462 if (e == JVMTI_ERROR_NONE)
463 e = (*jvmtienv)->AddCapabilities(jvmtienv, &cap);
464 if (e != JVMTI_ERROR_NONE) {
465 printjvmtierror("jdwp: error adding jvmti capabilities", e);
469 /* only enable needed events. VMVirtualMachine.registerEvent will
470 be used to enable other events by need */
471 if (JVMTI_ERROR_NONE != (e = (*jvmtienv)->
472 SetEventNotificationMode(jvmtienv, JVMTI_ENABLE,
475 printjvmtierror("jdwp unable to enable vm init callback",e);
483 jvmtiEventCallbacks jvmti_jdwp_EventCallbacks = {
488 NULL, /* &ClassFileLoadHook, */
489 NULL, /* &ClassLoad, */
493 NULL, /* &ExceptionCatch, */
494 NULL, /* &SingleStep, */
495 NULL, /* &FramePop, */
497 NULL, /* &FieldAccess, */
498 NULL, /* &FieldModification, */
500 NULL, /* &MethodExit, */
501 NULL, /* &NativeMethodBind, */
502 NULL, /* &CompiledMethodLoad, */
503 NULL, /* &CompiledMethodUnload, */
504 NULL, /* &DynamicCodeGenerated, */
505 NULL, /* &DataDumpRequest, */
507 NULL, /* &MonitorWait, */
508 NULL, /* &MonitorWaited, */
509 NULL, /* &MonitorContendedEnter, */
510 NULL, /* &MonitorContendedEntered, */
515 NULL, /* &GarbageCollectionStart, */
516 NULL, /* &GarbageCollectionFinish, */
517 NULL, /* &ObjectFree, */
518 NULL, /* &VMObjectAlloc, */
523 * These are local overrides for various environment variables in Emacs.
524 * Please do not remove this and leave it at the end of the file, where
525 * Emacs will automagically detect them.
526 * ---------------------------------------------------------------------
529 * indent-tabs-mode: t