CACAO
VMjdwp.cpp
Go to the documentation of this file.
1 /* src/native/vm/VMjdwp.c - jvmti->jdwp interface
2 
3  Copyright (C) 1996-2013
4  CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5 
6  This file is part of CACAO.
7 
8  This program is free software; you can redistribute it and/or
9  modify it under the terms of the GNU General Public License as
10  published by the Free Software Foundation; either version 2, or (at
11  your option) any later version.
12 
13  This program is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21  02110-1301, USA.
22 
23  Contact: cacao@cacaojvm.org
24 
25  Author: Martin Platter
26 
27  Changes:
28 
29 */
30 
31 #include "native/jvmti/jvmti.h"
32 #include "native/jvmti/VMjdwp.hpp"
33 
34 #include <stdlib.h>
35 #include <string.h>
36 
37 void printjvmtierror(char *desc, jvmtiError err) {
38  char* errdesc;
39 
40  if (err == JVMTI_ERROR_NONE) return;
41  (*jvmtienv)->GetErrorName(jvmtienv,err, &errdesc);
42  fprintf(stderr,"%s: jvmti error %s\n",desc, errdesc);
43  fflush(stderr);
44  (*jvmtienv)->Deallocate(jvmtienv,(unsigned char*)errdesc);
45 }
46 
47 
48 /* class and method IDs */
52 
53 static void notify (JNIEnv* jni_env, jobject event){
54  fprintf(stderr,"VMjdwp notfiy called\n");
55 
56  (*jni_env)->CallStaticVoidMethod(jni_env,Jdwpclass,notifymid,event);
57  if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
58  fprintf(stderr,"Exception occourred in notify mehtod\n");
59  (*jni_env)->ExceptionDescribe(jni_env);
60  }
61 
62 }
63 
64 static void ThreadStart (jvmtiEnv *jvmti_env, JNIEnv* jni_env,
65  jthread thread){
66  jobject obj;
67 
68  obj = (*jni_env)->
69  NewObject(jni_env, threadstartclass, threadstartmid, thread);
70  if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
71  fprintf(stderr,"error calling ThreadStartEvent constructor\n");
72  (*jni_env)->ExceptionDescribe(jni_env);
73  return;
74  }
75 
76  fprintf(stderr,"VMjdwp:ThreadStart: thread %p\n",thread);
77  fflush(stderr);
78 
79  notify (jni_env,obj);
80 }
81 
82 
83 static void ThreadEnd (jvmtiEnv *jvmti_env, JNIEnv* jni_env,
84  jthread thread){
85  jobject obj;
86 
87 
88  obj = (*jni_env)->NewObject(jni_env, threadendclass, threadendmid, thread);
89  if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
90  fprintf(stderr,"error calling ThreadEndEvent constructor\n");
91  (*jni_env)->ExceptionDescribe(jni_env);
92  return;
93  }
94 
95  fprintf(stderr,"VMjdwp:ThreadEnd: thread %p\n",thread);
96  fflush(stderr);
97 
98  notify (jni_env,obj);
99 }
100 
101 
102 static void ClassPrepare (jvmtiEnv *jvmti_env, JNIEnv* jni_env,
104  jobject obj;
105  int classstatus;
106  jvmtiError e;
107 
108  if (JVMTI_ERROR_NONE !=
109  (e = (*jvmtienv)->GetClassStatus(jvmtienv, klass, &classstatus))) {
110  printjvmtierror("unable to get class status", e);
111  return;
112  }
113 
114  obj = (*jni_env)->NewObject(jni_env, classprepareclass, classpreparemid, thread, klass, classstatus);
115  if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
116  fprintf(stderr,"error calling ClassPrepareEvent constructor\n");
117  (*jni_env)->ExceptionDescribe(jni_env);
118  return;
119  }
120 
121  fprintf(stderr,"VMjdwp:ClassPrepareEvent: thread %p\n",thread);
122  fflush(stderr);
123 
124  notify (jni_env,obj);
125 }
126 
127 static void Exception (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
130  /* gnu classpath jdwp has no ExceptionEvent yet */
131  fprintf(stderr,"VMjdwp:Exception: thread %p\n",thread);
132  fflush(stderr);
133 
134 }
135 
136 static void Breakpoint (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
137  jmethodID method, jlocation location) {
138  jobject vmmethod, loc, ev;
139  jclass mcl;
140  jvmtiError e;
141 
142  if (JVMTI_ERROR_NONE !=
143  (e = (*jvmtienv)->GetMethodDeclaringClass(jvmtienv,
144  method,
145  &mcl))){
146  printjvmtierror("unable to get declaring class", e);
147  return;
148  }
149 
150  vmmethod = (*jni_env)->NewObject(jni_env, vmmethodclass, vmmethodmid,
151  mcl, method);
152  if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
153  fprintf(stderr,"error calling VMMethod constructor\n");
154  (*jni_env)->ExceptionDescribe(jni_env);
155  return;
156  }
157 
158  loc = (*jni_env)->NewObject(jni_env, locationclass, locationmid,
159  vmmethod, location);
160  if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
161  fprintf(stderr,"error calling location constructor\n");
162  (*jni_env)->ExceptionDescribe(jni_env);
163  return;
164  }
165 
166  /* XXX todo: get object instance - needs jvmti local variable support */
167  ev = (*jni_env)->NewObject(jni_env, breakpointclass, breakpointmid,
168  thread, loc,NULL);
169  if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
170  fprintf(stderr,"error calling breakpoint constructor\n");
171  (*jni_env)->ExceptionDescribe(jni_env);
172  return;
173  }
174 
175  fprintf(stderr,"VMjdwp:Breakpoint: thread %p\n",thread);
176  fflush(stderr);
177 
178  notify (jni_env,ev);
179 }
180 
181 
182 static void MethodEntry (jvmtiEnv *jvmti_env, JNIEnv* jni_env,
183  jthread thread, jmethodID method) {
184  /* do not report gnu/classpath/jdwp method entries */
185 }
186 
187 
188 static void VMDeath (jvmtiEnv *jvmti_env,
189  JNIEnv* jni_env) {
190  fprintf(stderr,"JVMTI-Event: IMPLEMENT ME!!!");
191 }
192 
193 
194 /* setup_jdwp_thread **********************************************************
195 
196  Helper function to start JDWP listening thread
197 
198 *******************************************************************************/
199 
201  jobject o;
202  jmethodID m;
203  jstring s;
204 
205  /* new gnu.classpath.jdwp.Jdwp() */
206  m = (*jni_env)->GetMethodID(jni_env,Jdwpclass,"<init>","()V");
207  if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
208  fprintf(stderr,"could not get Jdwp constructor\n");
209  (*jni_env)->ExceptionDescribe(jni_env);
210  exit(1);
211  }
212 
213  o = (*jni_env)->NewObject(jni_env, Jdwpclass, m);
214  if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
215  fprintf(stderr,"error calling Jdwp constructor\n");
216  (*jni_env)->ExceptionDescribe(jni_env);
217  exit(1);
218  }
219 
220  jdwpthread = (jthread)o;
221 
222 
223  /* configure(jdwpoptions) */
224  m = (*jni_env)->GetMethodID(jni_env,Jdwpclass,"configure",
225  "(Ljava/lang/String;)V");
226  if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
227  fprintf(stderr,"could not get Jdwp configure method\n");
228  (*jni_env)->ExceptionDescribe(jni_env);
229  exit(1);
230  }
231 
232 
233  s = (*jni_env)->NewStringUTF(jni_env,jdwpoptions);
234  if (s == NULL) {
235  fprintf(stderr,"could not get new java string from jdwp options\n");
236  exit(1);
237  }
238 
239  free(jdwpoptions);
240 
241  (*jni_env)->CallVoidMethod(jni_env,o,m,s);
242  if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
243  fprintf(stderr,"Exception occourred in Jdwp configure\n");
244  (*jni_env)->ExceptionDescribe(jni_env);
245  exit(1);
246  }
247 
248  m = (*jni_env)->GetMethodID(jni_env,Jdwpclass,"_doInitialization","()V");
249  if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
250  fprintf(stderr,"could not get Jdwp _doInitialization method\n");
251  (*jni_env)->ExceptionDescribe(jni_env);
252  exit(1);
253  }
254 
255 
256  (*jni_env)->CallVoidMethod(jni_env,o,m);
257  if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
258  fprintf(stderr,"Exception occourred in Jdwp _doInitialization\n");
259  (*jni_env)->ExceptionDescribe(jni_env);
260  exit(1);
261  }
262 }
263 
264 #define FINDCLASSWITHEXCEPTION(CLASS,SIGNATURE) \
265  CLASS = (*jni_env)->FindClass(jni_env, SIGNATURE); \
266  if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) { \
267  fprintf(stderr,"could not find %s\n", SIGNATURE); \
268  (*jni_env)->ExceptionDescribe(jni_env); \
269  exit(1); \
270  }
271 #define GETMIDWITHEXCEPTION(CLASS, CLASSNAME, MID, METHODNAME, METHODSIG) \
272  FINDCLASSWITHEXCEPTION(CLASS, CLASSNAME); \
273  MID = (*jni_env)->GetMethodID(jni_env, CLASS, METHODNAME, METHODSIG); \
274  if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) { \
275  fprintf(stderr,"could not get %s %s\n",CLASSNAME, METHODNAME); \
276  (*jni_env)->ExceptionDescribe(jni_env); \
277  exit(1); \
278  }
279 
280 
281 static void fillidcache(JNIEnv* jni_env) {
282  FINDCLASSWITHEXCEPTION(Jdwpclass, "gnu/classpath/jdwp/Jdwp");
283 
284  notifymid = (*jni_env)->
285  GetStaticMethodID(jni_env,Jdwpclass,
286  "notify","(Lgnu/classpath/jdwp/event/Event;)V");
287  if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
288  fprintf(stderr,"could not get notify method\n");
289  (*jni_env)->ExceptionDescribe(jni_env);
290  exit(1);
291  }
292 
293  GETMIDWITHEXCEPTION(threadstartclass,
294  "gnu/classpath/jdwp/event/ThreadStartEvent",
295  threadstartmid, "<init>", "(Ljava/lang/Thread;)V");
296 
297 
298  GETMIDWITHEXCEPTION(threadendclass,
299  "gnu/classpath/jdwp/event/ThreadEndEvent",
300  threadendmid, "<init>", "(Ljava/lang/Thread;)V");
301 
302 
303  GETMIDWITHEXCEPTION(classprepareclass,
304  "gnu/classpath/jdwp/event/ClassPrepareEvent",
305  classpreparemid, "<init>",
306  "(Ljava/lang/Thread;Ljava/lang/Class;I)V");
307 
308 
309  GETMIDWITHEXCEPTION(vmmethodclass, "gnu/classpath/jdwp/VMMethod",
310  vmmethodmid, "<init>", "(Ljava/lang/Class;J)V");
311 
312  GETMIDWITHEXCEPTION(locationclass, "gnu/classpath/jdwp/util/Location",
313  locationmid, "<init>",
314  "(Lgnu/classpath/jdwp/VMMethod;J)V");
315 
316 
318  breakpointclass,
319  "gnu/classpath/jdwp/event/BreakpointEvent",
320  breakpointmid, "<init>",
321  "(Ljava/lang/Thread;Lgnu/classpath/jdwp/util/Location;Ljava/lang/Object;)V");
322 
323 }
324 
325 static void VMInit (jvmtiEnv *jvmti_env,
326  JNIEnv* jni_env,
327  jthread thread) {
328  jclass cl;
329  jmethodID m;
330  jobject eventobj;
331  jvmtiError err;
332 
333  fprintf(stderr,"JDWP VMInit\n");
334 
335  /* get needed jmethodIDs and jclasses for callbacks */
336  fillidcache(jni_env);
337 
338  /* startup gnu classpath jdwp thread */
339  setup_jdwp_thread(jni_env);
340 
341  fprintf(stderr,"JDWP listening thread started\n");
342 
343  /* send VmInitEvent */
344  cl = (*jni_env)->FindClass(jni_env,
345  "gnu/classpath/jdwp/event/VmInitEvent");
346  if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
347  fprintf(stderr,"could not find class VMInitEvent\n");
348  (*jni_env)->ExceptionDescribe(jni_env);
349  exit(1);
350  }
351 
352  m = (*jni_env)->GetMethodID(jni_env,cl,"<init>",
353  "(Ljava/lang/Thread;)V");
354  if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
355  fprintf(stderr,"could not get VmInitEvent constructor\n");
356  (*jni_env)->ExceptionDescribe(jni_env);
357  exit(1);
358  }
359 
360  eventobj = (*jni_env)->NewObject(jni_env, cl, m, thread);
361  if ((*jni_env)->ExceptionOccurred(jni_env) != NULL) {
362  fprintf(stderr,"error calling VmInitEvent constructor\n");
363  (*jni_env)->ExceptionDescribe(jni_env);
364  exit(1);
365  }
366 
367 
368  notify (jni_env,eventobj);
369 
370  if (suspend) {
371  fprintf(stderr,"suspend initial thread\n");
372  err = (*jvmti_env)->SuspendThread(jvmti_env,thread);
373  printjvmtierror("error suspending initial thread",err);
374  }
375 }
376 
377 static void usage() {
378  puts("usage jdwp:[help]|(<option>=<value>),*");
379  puts(" transport=[dt_socket|...]");
380  puts(" address=<hostname:port>");
381  puts(" server=[y|n]");
382  puts(" suspend=[y|n]");
383 }
384 
385 static bool processoptions(char *options) {
386  int i,len;
387 
388  if (strncmp(options,"help",4) == 0) {
389  usage();
390  return false;
391  }
392 
393  suspend = true; /* default value */
394 
395 
396  /* copy options for later use in java jdwp listen thread configure */
397  jdwpoptions = malloc(sizeof(char)*strlen(options));
398  strncpy(jdwpoptions, options, sizeof(char)*strlen(options));
399 
400  len = strlen(options);
401 
402  i=0;
403  while (i<len) {
404  if (strncmp("suspend=",&options[i],8)==0) {
405  if (8>=strlen(&options[i])) {
406  if ((options[i+8]== 'y') || (options[i+8]== 'n')) {
407  suspend = options[i+8]== 'y';
408  } else {
409  printf("jdwp error argument: %s\n",options);
410  usage();
411  return -1;
412  }
413  }
414  } else {
415  /* these options will be handled by jdwp java configure */
416  if ((strncmp("transport=",options,10)==0) ||
417  (strncmp("server=",options,7)==0)) {
418  } else {
419  printf("jdwp unkown argument: %s\n",options);
420  usage();
421  return false;
422  }
423  }
424  while ((options[i]!=',')&&(i<len)) i++;
425  i++;
426  }
427  return true;
428 }
429 
430 
431 JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved) {
432  jint rc;
433  jvmtiCapabilities cap;
434  jvmtiError e;
435 
436 
437  fprintf(stderr,"jdwp Agent_OnLoad options: %s\n",options);
438  if (!processoptions(options)) return -1;
439 
440  rc = (*vm)->GetEnv(vm, (void**)&jvmtienv, JVMTI_VERSION_1_0);
441  if (rc != JNI_OK) {
442  fprintf(stderr, "jdwp: Unable to get jvmtiEnv error=%d\n", rc);
443  return -1;
444  }
445 
446  /* set eventcallbacks */
447  if (JVMTI_ERROR_NONE !=
448  (e = (*jvmtienv)->SetEventCallbacks(jvmtienv,
450  sizeof(jvmtiEventCallbacks)))){
451  printjvmtierror("jdwp: unable to setup event callbacks", e);
452  return -1;
453  }
454 
455  e = (*jvmtienv)->GetPotentialCapabilities(jvmtienv, &cap);
456  printjvmtierror("jdwp: unable to get potential capabilities", e);
457  if (e == JVMTI_ERROR_NONE)
458  e = (*jvmtienv)->AddCapabilities(jvmtienv, &cap);
459  if (e != JVMTI_ERROR_NONE) {
460  printjvmtierror("jdwp: error adding jvmti capabilities", e);
461  return -1;
462  }
463 
464  /* only enable needed events. VMVirtualMachine.registerEvent will
465  be used to enable other events by need */
466  if (JVMTI_ERROR_NONE != (e = (*jvmtienv)->
469  NULL))) {
470  printjvmtierror("jdwp unable to enable vm init callback",e);
471  return -1;
472  }
473 
474  return 0;
475 }
476 
477 
479  &VMInit,
480  &VMDeath,
481  &ThreadStart,
482  &ThreadEnd,
483  NULL, /* &ClassFileLoadHook, */
484  NULL, /* &ClassLoad, */
485  &ClassPrepare,
486  NULL, /* &VMStart */
487  &Exception,
488  NULL, /* &ExceptionCatch, */
489  NULL, /* &SingleStep, */
490  NULL, /* &FramePop, */
491  &Breakpoint,
492  NULL, /* &FieldAccess, */
493  NULL, /* &FieldModification, */
494  &MethodEntry,
495  NULL, /* &MethodExit, */
496  NULL, /* &NativeMethodBind, */
497  NULL, /* &CompiledMethodLoad, */
498  NULL, /* &CompiledMethodUnload, */
499  NULL, /* &DynamicCodeGenerated, */
500  NULL, /* &DataDumpRequest, */
501  NULL,
502  NULL, /* &MonitorWait, */
503  NULL, /* &MonitorWaited, */
504  NULL, /* &MonitorContendedEnter, */
505  NULL, /* &MonitorContendedEntered, */
506  NULL,
507  NULL,
508  NULL,
509  NULL,
510  NULL, /* &GarbageCollectionStart, */
511  NULL, /* &GarbageCollectionFinish, */
512  NULL, /* &ObjectFree, */
513  NULL, /* &VMObjectAlloc, */
514 };
515 
516 
517 /*
518  * These are local overrides for various environment variables in Emacs.
519  * Please do not remove this and leave it at the end of the file, where
520  * Emacs will automagically detect them.
521  * ---------------------------------------------------------------------
522  * Local variables:
523  * mode: c++
524  * indent-tabs-mode: t
525  * c-basic-offset: 4
526  * tab-width: 4
527  * End:
528  */
static jmethodID notifymid
Definition: VMjdwp.cpp:50
static jmethodID threadendmid
Definition: VMjdwp.cpp:50
static jmethodID threadstartmid
Definition: VMjdwp.cpp:50
static jmethodID breakpointmid
Definition: VMjdwp.cpp:50
static jclass classprepareclass
Definition: VMjdwp.cpp:49
_Jv_JNIEnv JNIEnv
Definition: jni.hpp:112
static jclass Jdwpclass
Definition: VMjdwp.cpp:49
static void ClassPrepare(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thread, jclass klass)
Definition: VMjdwp.cpp:102
static jclass locationclass
Definition: VMjdwp.cpp:49
_Jv_JavaVM JavaVM
Definition: jni.hpp:114
struct Breakpoint Breakpoint
This structure contains information about a breakpoint.
static void usage()
Definition: VMjdwp.cpp:377
JNIEnv jthread jclass klass
Definition: jvmti.h:300
static jclass vmmethodclass
Definition: VMjdwp.cpp:49
static jvmtiError SetEventNotificationMode(jvmtiEnv *env, jvmtiEventMode mode, jvmtiEvent event_type, jthread event_thread,...)
Definition: jvmti.c:424
jobject jthread
Definition: jvmti.h:42
bool suspend
static void setup_jdwp_thread(JNIEnv *jni_env)
Definition: VMjdwp.cpp:200
jvmtiError
Definition: jvmti.h:49
static void ThreadEnd(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thread)
Definition: VMjdwp.cpp:83
JNIEnv jthread jmethodID jlocation jobject exception
Definition: jvmti.h:272
JNIEnv jthread jmethodID jlocation jobject jmethodID catch_method
Definition: jvmti.h:272
JNIEnv jthread jmethodID method
Definition: jvmti.h:207
void printjvmtierror(char *desc, jvmtiError err)
static jclass threadstartclass
Definition: VMjdwp.cpp:49
static void MethodEntry(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thread, jmethodID method)
Definition: VMjdwp.cpp:182
static void Exception(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thread, jmethodID method, jlocation location, jobject exception, jmethodID catch_method, jlocation catch_location)
Definition: VMjdwp.cpp:127
JNIEnv jthread thread
Definition: jvmti.h:207
static bool processoptions(char *options)
Definition: VMjdwp.cpp:385
#define GETMIDWITHEXCEPTION(CLASS, CLASSNAME, MID, METHODNAME, METHODSIG)
Definition: VMjdwp.cpp:271
MIIterator i
static jclass breakpointclass
Definition: VMjdwp.cpp:49
JNIEnv * jni_env
Definition: jvmti.h:207
JNIEnv jthread jmethodID jlocation jobject jmethodID jlocation catch_location
Definition: jvmti.h:272
static jmethodID classpreparemid
Definition: VMjdwp.cpp:50
OStream & err()
Definition: OStream.cpp:33
MIIterator e
#define JVMTI_VERSION_1_0
Definition: jvmti.h:38
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
Definition: VMjdwp.cpp:431
jlong jlocation
Definition: jvmti.h:44
#define FINDCLASSWITHEXCEPTION(CLASS, SIGNATURE)
Definition: VMjdwp.cpp:264
static void VMInit(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thread)
Definition: VMjdwp.cpp:325
static jmethodID vmmethodmid
Definition: VMjdwp.cpp:50
jthread jdwpthread
static void notify(JNIEnv *jni_env, jobject event)
Definition: VMjdwp.cpp:53
char * jdwpoptions
JNIEnv jthread jmethodID jlocation location
Definition: jvmti.h:207
static jmethodID locationmid
Definition: VMjdwp.cpp:50
static jclass threadendclass
Definition: VMjdwp.cpp:49
#define printf(...)
Definition: ssa2.cpp:40
static void ThreadStart(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thread)
Definition: VMjdwp.cpp:64
jvmtiEventCallbacks jvmti_jdwp_EventCallbacks
Definition: VMjdwp.cpp:478
static void VMDeath(jvmtiEnv *jvmti_env, JNIEnv *jni_env)
Definition: VMjdwp.cpp:188
static void fillidcache(JNIEnv *jni_env)
Definition: VMjdwp.cpp:281
jvmtiEnv * jvmtienv