OSDN Git Service

d219f5889567a9e02a0a0e3144c81aa914febf7d
[pf3gnuchains/gcc-fork.git] / libjava / gnu / classpath / jdwp / natVMVirtualMachine.cc
1 // natVMVirtualMachine.cc - native support for VMVirtualMachine
2
3 /* Copyright (C) 2006, 2007 Free Software Foundation
4
5    This file is part of libgcj.
6
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
9 details. */
10
11 #include <config.h>
12 #include <gcj/cni.h>
13 #include <java-assert.h>
14 #include <java-interp.h>
15 #include <jvm.h>
16 #include <jvmti.h>
17
18 #include <java/lang/Class.h>
19 #include <java/lang/ClassLoader.h>
20 #include <java/lang/Integer.h>
21 #include <java/lang/String.h>
22 #include <java/lang/StringBuilder.h>
23 #include <java/lang/Thread.h>
24 #include <java/nio/ByteBuffer.h>
25 #include <java/nio/ByteBufferImpl.h>
26 #include <java/util/ArrayList.h>
27 #include <java/util/Collection.h>
28 #include <java/util/Hashtable.h>
29 #include <java/util/Iterator.h>
30
31 #include <gnu/classpath/jdwp/Jdwp.h>
32 #include <gnu/classpath/jdwp/VMFrame.h>
33 #include <gnu/classpath/jdwp/VMMethod.h>
34 #include <gnu/classpath/jdwp/VMVirtualMachine.h>
35 #include <gnu/classpath/jdwp/event/BreakpointEvent.h>
36 #include <gnu/classpath/jdwp/event/ClassPrepareEvent.h>
37 #include <gnu/classpath/jdwp/event/EventManager.h>
38 #include <gnu/classpath/jdwp/event/EventRequest.h>
39 #include <gnu/classpath/jdwp/event/ThreadEndEvent.h>
40 #include <gnu/classpath/jdwp/event/ThreadStartEvent.h>
41 #include <gnu/classpath/jdwp/event/VmDeathEvent.h>
42 #include <gnu/classpath/jdwp/event/VmInitEvent.h>
43 #include <gnu/classpath/jdwp/event/filters/IEventFilter.h>
44 #include <gnu/classpath/jdwp/event/filters/LocationOnlyFilter.h>
45 #include <gnu/classpath/jdwp/event/filters/StepFilter.h>
46 #include <gnu/classpath/jdwp/exception/InvalidFrameException.h>
47 #include <gnu/classpath/jdwp/exception/InvalidLocationException.h>
48 #include <gnu/classpath/jdwp/exception/InvalidMethodException.h>
49 #include <gnu/classpath/jdwp/exception/JdwpInternalErrorException.h>
50 #include <gnu/classpath/jdwp/id/ThreadId.h>
51 #include <gnu/classpath/jdwp/util/Location.h>
52 #include <gnu/classpath/jdwp/util/MethodResult.h>
53 #include <gnu/gcj/jvmti/Breakpoint.h>
54 #include <gnu/gcj/jvmti/BreakpointManager.h>
55
56 using namespace java::lang;
57 using namespace gnu::classpath::jdwp::event;
58 using namespace gnu::classpath::jdwp::util;
59
60 // Stepping information
61 struct step_info
62 {
63   jint size;   // See gnu.classpath.jdwp.JdwpConstants.StepSize
64   jint depth;  // See gnu.classpath.jdwp.JdwpConstants.StepDepth
65   int stack_depth;  // stack depth at start of stepping
66   jmethodID method; // method in which we are stepping
67 };
68
69 // Forward declarations
70 static Location *get_request_location (EventRequest *);
71 static gnu::classpath::jdwp::event::filters::StepFilter *
72 get_request_step_filter (EventRequest *);
73 static void JNICALL jdwpBreakpointCB (jvmtiEnv *, JNIEnv *, jthread,
74                                       jmethodID, jlocation);
75 static void JNICALL jdwpClassPrepareCB (jvmtiEnv *, JNIEnv *, jthread, jclass);
76 static void JNICALL jdwpThreadEndCB (jvmtiEnv *, JNIEnv *, jthread);
77 static void JNICALL jdwpThreadStartCB (jvmtiEnv *, JNIEnv *, jthread);
78 static void JNICALL jdwpVMDeathCB (jvmtiEnv *, JNIEnv *);
79 static void JNICALL jdwpVMInitCB (jvmtiEnv *, JNIEnv *, jthread);
80 static void throw_jvmti_error (jvmtiError);
81
82 #define DEFINE_CALLBACK(Cb,Event) Cb.Event = jdwp ## Event ## CB
83 #define DISABLE_EVENT(Event,Thread)                                     \
84   _jdwp_jvmtiEnv->SetEventNotificationMode (JVMTI_DISABLE,              \
85                                             JVMTI_EVENT_ ## Event, Thread)
86 #define ENABLE_EVENT(Event,Thread)                                      \
87   _jdwp_jvmtiEnv->SetEventNotificationMode (JVMTI_ENABLE,               \
88                                             JVMTI_EVENT_ ## Event, Thread)
89 // JVMTI environment
90 static jvmtiEnv *_jdwp_jvmtiEnv;
91
92 jvmtiEnv *
93 _Jv_GetJDWP_JVMTIEnv (void)
94 {
95   return _jdwp_jvmtiEnv;
96 }
97
98 void
99 gnu::classpath::jdwp::VMVirtualMachine::initialize ()
100 {
101   _jdwp_suspend_counts = new ::java::util::Hashtable ();
102   _stepping_threads = new ::java::util::Hashtable ();
103
104   JavaVM *vm = _Jv_GetJavaVM ();
105   vm->GetEnv (reinterpret_cast<void **> (&_jdwp_jvmtiEnv), JVMTI_VERSION_1_0);
106
107   // Wait for VM_INIT to do more initialization
108   jvmtiEventCallbacks callbacks;
109   DEFINE_CALLBACK (callbacks, VMInit);
110   _jdwp_jvmtiEnv->SetEventCallbacks (&callbacks, sizeof (callbacks));
111   ENABLE_EVENT (VM_INIT, NULL);
112 }
113
114 void
115 gnu::classpath::jdwp::VMVirtualMachine::suspendThread (Thread *thread)
116 {
117   jint value;
118   Integer *count;
119   {
120     JvSynchronize dummy (_jdwp_suspend_counts);
121     count = reinterpret_cast<Integer *> (_jdwp_suspend_counts->get (thread));
122     if (count == NULL)
123       {
124         // New -- suspend thread
125         value = 0;
126       }
127     else
128       {
129         // Thread already suspended
130         value = count->intValue ();
131       }
132
133     count = Integer::valueOf (++value);
134     _jdwp_suspend_counts->put (thread, count);
135   }
136
137   if (value == 1)
138     {
139       // Suspend the thread
140       jvmtiError err = _jdwp_jvmtiEnv->SuspendThread (thread);
141       if (err != JVMTI_ERROR_NONE)
142         {
143           using namespace gnu::gcj::runtime;
144           using namespace gnu::classpath::jdwp::exception;
145           char *reason;
146           _jdwp_jvmtiEnv->GetErrorName (err, &reason);
147           String *txt = JvNewStringLatin1 ("could not suspend thread: ");
148           StringBuilder *msg = new StringBuilder (txt);
149           msg->append (JvNewStringLatin1 (reason));
150           _jdwp_jvmtiEnv->Deallocate ((unsigned char *) reason);
151           throw new JdwpInternalErrorException (msg->toString ());
152         }
153     }
154 }
155
156 void
157 gnu::classpath::jdwp::VMVirtualMachine::resumeThread (Thread *thread)
158 {
159   jint value;
160   {
161     JvSynchronize dummy (_jdwp_suspend_counts);
162     Integer *count
163       = reinterpret_cast<Integer *> (_jdwp_suspend_counts->get (thread));
164     if (count == NULL)
165       {
166         // Thread not suspended: ThreadReference.Resume says to ignore it.
167         return;
168       }
169     else
170       {
171         // Decrement suspend count
172         value = count->intValue () - 1;
173       }
174
175     if (value == 0)
176       {
177         // Thread will be resumed, remove from table
178         _jdwp_suspend_counts->remove (thread);
179       }
180     else
181       {
182         // Thread stays suspended: record new suspend count
183         count = Integer::valueOf (value);
184         _jdwp_suspend_counts->put (thread, count);
185       }
186   }
187
188   if (value == 0)
189     {
190       jvmtiError err = _jdwp_jvmtiEnv->ResumeThread (thread);
191       if (err != JVMTI_ERROR_NONE)
192         {
193           using namespace gnu::gcj::runtime;
194           using namespace gnu::classpath::jdwp::exception;
195           char *reason;
196           _jdwp_jvmtiEnv->GetErrorName (err, &reason);
197           String *txt = JvNewStringLatin1 ("could not resume thread: ");
198           StringBuilder *msg = new StringBuilder (txt);
199           msg->append (JvNewStringLatin1 (reason));
200           _jdwp_jvmtiEnv->Deallocate ((unsigned char *) reason);
201           throw new JdwpInternalErrorException (msg->toString ());
202         }
203     }
204 }
205
206 jint
207 gnu::classpath::jdwp::VMVirtualMachine::getSuspendCount (Thread *thread)
208 {
209   jint suspensions = 0;
210   Integer *count
211     = reinterpret_cast<Integer *> (_jdwp_suspend_counts->get (thread));
212   if (count != NULL)
213     suspensions = count->intValue ();
214   return suspensions;
215 }
216
217 void
218 gnu::classpath::jdwp::VMVirtualMachine::registerEvent (EventRequest *request)
219 {
220   switch (request->getEventKind ())
221     {
222     case EventRequest::EVENT_SINGLE_STEP:
223       {
224         Thread *thread;
225         filters::StepFilter *filter = get_request_step_filter (request);
226         if (filter == NULL)
227           {
228             // No filter specified: report every step in every
229             // thread.
230             thread = NULL;
231           }
232         else
233           {
234             // Add stepping information to list of stepping threads
235             thread = filter->getThread ()->getThread ();
236             _Jv_InterpFrame *frame
237               = reinterpret_cast<_Jv_InterpFrame *> (thread->interp_frame);
238             struct step_info *sinfo
239               = (struct step_info *) JvAllocBytes (sizeof (struct step_info));
240             sinfo->size = filter->getSize ();
241             sinfo->depth = filter->getDepth ();
242             sinfo->stack_depth = frame->depth ();
243             sinfo->method = frame->self->get_method ();
244             _stepping_threads->put (thread, (jobject) sinfo);
245           }
246
247         ENABLE_EVENT (SINGLE_STEP, thread);
248       }
249       break;
250
251     case EventRequest::EVENT_BREAKPOINT:
252       {
253         using namespace ::gnu::gcj::jvmti;
254         Location *loc = get_request_location (request);
255         if (loc == NULL)
256           {
257             using namespace gnu::classpath::jdwp::exception;
258             throw new InvalidLocationException ();
259           }
260
261         jlong method = loc->getMethod ()->getId ();
262         jlocation index = loc->getIndex ();
263         Breakpoint  *bp = BreakpointManager::getBreakpoint (method, index);
264         if (bp == NULL)
265           {
266             // Breakpoint not in interpreter yet
267             bp = BreakpointManager::newBreakpoint (method, index);
268           }
269         else
270           {
271             // Ignore the duplicate
272           }
273       }
274       break;
275
276     case EventRequest::EVENT_FRAME_POP:
277       break;
278
279     case EventRequest::EVENT_EXCEPTION:
280       break;
281
282     case EventRequest::EVENT_USER_DEFINED:
283       break;
284
285     case EventRequest::EVENT_THREAD_START:
286       break;
287
288     case EventRequest::EVENT_THREAD_END:
289       break;
290
291     case EventRequest::EVENT_CLASS_PREPARE:
292       break;
293
294     case EventRequest::EVENT_CLASS_LOAD:
295       break;
296
297     case EventRequest::EVENT_CLASS_UNLOAD:
298       break;
299
300     case EventRequest::EVENT_FIELD_ACCESS:
301       break;
302
303     case EventRequest::EVENT_FIELD_MODIFY:
304       break;
305
306     case EventRequest::EVENT_METHOD_ENTRY:
307       break;
308
309     case EventRequest::EVENT_METHOD_EXIT:
310       break;
311
312     case EventRequest::EVENT_VM_INIT:
313       break;
314
315     case EventRequest::EVENT_VM_DEATH:
316       break;
317     }
318 }
319
320 void
321 gnu::classpath::jdwp::VMVirtualMachine::unregisterEvent (EventRequest *request)
322 {
323   switch (request->getEventKind ())
324     {
325     case EventRequest::EVENT_SINGLE_STEP:
326       {
327         Thread *thread;
328         filters::StepFilter *filter = get_request_step_filter (request);
329         if (filter == NULL)
330           thread = NULL;
331         else
332           {
333             thread = filter->getThread ()->getThread ();
334             _stepping_threads->remove (thread);
335           }
336
337         DISABLE_EVENT (SINGLE_STEP, thread);
338       }
339       break;
340
341     case EventRequest::EVENT_BREAKPOINT:
342       {
343         using namespace gnu::gcj::jvmti;
344         ::java::util::Collection *breakpoints;
345         EventManager *em = EventManager::getDefault ();
346         breakpoints = em->getRequests (EventRequest::EVENT_BREAKPOINT);
347
348         // Check for duplicates
349         int matches = 0;
350         Location *the_location = get_request_location (request);
351
352         // This should not be possible: we REQUIRE a Location
353         // to install a breakpoint
354         JvAssert (the_location != NULL);
355
356         ::java::util::Iterator *iter = breakpoints->iterator ();
357         while (iter->hasNext ())
358           {
359             EventRequest *er
360               = reinterpret_cast<EventRequest *> (iter->next ());
361             Location *loc = get_request_location (er);
362             JvAssert (loc != NULL);
363             if (loc->equals (the_location) && ++matches == 2)
364               {
365                 // Short-circuit: already more than one breakpoint
366                 return;
367               }
368           }
369
370         if (matches == 0)
371           {
372             using namespace gnu::classpath::jdwp::exception;
373             jstring msg
374               = JvNewStringLatin1 ("attempt to remove unknown breakpoint");
375             throw new JdwpInternalErrorException (msg);
376           }
377
378         jlong methodId = the_location->getMethod ()->getId ();
379         BreakpointManager::deleteBreakpoint (methodId,
380                                              the_location->getIndex ());
381       }
382       break;
383
384     case EventRequest::EVENT_FRAME_POP:
385       break;
386
387     case EventRequest::EVENT_EXCEPTION:
388       break;
389
390     case EventRequest::EVENT_USER_DEFINED:
391       break;
392
393     case EventRequest::EVENT_THREAD_START:
394       break;
395
396     case EventRequest::EVENT_THREAD_END:
397       break;
398
399     case EventRequest::EVENT_CLASS_PREPARE:
400       break;
401
402     case EventRequest::EVENT_CLASS_LOAD:
403       break;
404
405     case EventRequest::EVENT_CLASS_UNLOAD:
406       break;
407
408     case EventRequest::EVENT_FIELD_ACCESS:
409       break;
410
411     case EventRequest::EVENT_FIELD_MODIFY:
412       break;
413
414     case EventRequest::EVENT_METHOD_ENTRY:
415       break;
416
417     case EventRequest::EVENT_METHOD_EXIT:
418       break;
419
420     case EventRequest::EVENT_VM_INIT:
421       break;
422
423     case EventRequest::EVENT_VM_DEATH:
424       break;
425     }
426 }
427
428 void
429 gnu::classpath::jdwp::VMVirtualMachine::clearEvents (MAYBE_UNUSED jbyte kind)
430 {
431 }
432
433 jint
434 gnu::classpath::jdwp::VMVirtualMachine::getAllLoadedClassesCount (void)
435 {
436   return 0;
437 }
438
439 java::util::Iterator *
440 gnu::classpath::jdwp::VMVirtualMachine::getAllLoadedClasses (void)
441 {
442   return NULL;
443 }
444
445 jint
446 gnu::classpath::jdwp::VMVirtualMachine::
447 getClassStatus (MAYBE_UNUSED jclass klass)
448 {
449   return 0;
450 }
451
452 JArray<gnu::classpath::jdwp::VMMethod *> *
453 gnu::classpath::jdwp::VMVirtualMachine::
454 getAllClassMethods (jclass klass)
455 {
456   jint count;
457   jmethodID *methods;
458   jvmtiError err = _jdwp_jvmtiEnv->GetClassMethods (klass, &count, &methods);
459   if (err != JVMTI_ERROR_NONE)
460     throw_jvmti_error (err);
461
462   JArray<VMMethod *> *result
463     = (JArray<VMMethod *> *) JvNewObjectArray (count,
464                                                &VMMethod::class$, NULL);
465   VMMethod **rmeth = elements (result);
466   for (int i = 0; i < count; ++i)
467     {
468       jlong id = reinterpret_cast<jlong> (methods[i]);
469       rmeth[i] = getClassMethod (klass, id);
470     }
471
472   _jdwp_jvmtiEnv->Deallocate ((unsigned char *) methods);
473   return result;
474 }
475
476 gnu::classpath::jdwp::VMMethod *
477 gnu::classpath::jdwp::VMVirtualMachine::
478 getClassMethod (jclass klass, jlong id)
479 {
480   jmethodID method = reinterpret_cast<jmethodID> (id);
481   _Jv_MethodBase *bmeth = _Jv_FindInterpreterMethod (klass, method);
482   if (bmeth != NULL)
483     return new gnu::classpath::jdwp::VMMethod (klass, id);
484
485   throw new gnu::classpath::jdwp::exception::InvalidMethodException (id);
486 }
487
488 java::util::ArrayList *
489 gnu::classpath::jdwp::VMVirtualMachine::getFrames (MAYBE_UNUSED Thread *thread,
490                                                    MAYBE_UNUSED jint start,
491                                                    MAYBE_UNUSED jint length)
492 {
493   return NULL;
494 }
495
496 gnu::classpath::jdwp::VMFrame *
497 gnu::classpath::jdwp::VMVirtualMachine::
498 getFrame (Thread *thread, jlong frameID)
499 {
500   using namespace gnu::classpath::jdwp::exception;
501   
502   _Jv_Frame *vm_frame = (_Jv_Frame *) thread->frame;
503   jint depth = 0;
504   _Jv_Frame *frame = reinterpret_cast<_Jv_Frame *> (frameID); 
505   
506   // We need to find the stack depth of the frame, so search through the call
507   // stack to find it.  This also checks for a valid frameID.
508   while (vm_frame != frame)
509     {
510       vm_frame = vm_frame->next;
511       depth++;
512       if (vm_frame == NULL)
513         throw new InvalidFrameException (frameID);
514     }
515   
516   Location *loc = NULL;
517   jvmtiFrameInfo info;
518   jvmtiError jerr;
519   jint num_frames;
520   jclass klass;
521   
522   // Get the info for the frame of interest
523   jerr = _jdwp_jvmtiEnv->GetStackTrace (thread, depth, 1, &info, &num_frames);
524    
525   if (jerr != JVMTI_ERROR_NONE)
526     throw_jvmti_error (jerr);
527   
528   jerr = _jdwp_jvmtiEnv->GetMethodDeclaringClass (info.method, &klass);
529       
530   if (jerr != JVMTI_ERROR_NONE)
531     throw_jvmti_error (jerr);
532
533   VMMethod *meth 
534     = getClassMethod (klass, reinterpret_cast<jlong> (info.method));
535   
536   if (info.location == -1)
537     loc = new Location (meth, 0);
538   else
539     loc = new Location (meth, info.location);
540   
541   return new VMFrame (thread, reinterpret_cast<jlong> (vm_frame), loc); 
542 }
543
544 jint
545 gnu::classpath::jdwp::VMVirtualMachine::
546 getFrameCount (Thread *thread)
547 {
548   jint frame_count;
549   
550   jvmtiError jerr = _jdwp_jvmtiEnv->GetFrameCount (thread, &frame_count);
551   
552   if (jerr != JVMTI_ERROR_NONE)
553     throw_jvmti_error (jerr);
554   
555   return frame_count;
556 }
557
558 jint
559 gnu::classpath::jdwp::VMVirtualMachine::
560 getThreadStatus (MAYBE_UNUSED Thread *thread)
561 {
562   return 0;
563 }
564
565 java::util::ArrayList *
566 gnu::classpath::jdwp::VMVirtualMachine::
567 getLoadRequests (MAYBE_UNUSED ClassLoader *cl)
568 {
569   return NULL;
570 }
571
572 MethodResult *
573 gnu::classpath::jdwp::VMVirtualMachine::
574 executeMethod (MAYBE_UNUSED jobject obj, MAYBE_UNUSED Thread *thread,
575                MAYBE_UNUSED jclass clazz, MAYBE_UNUSED reflect::Method *method,
576                MAYBE_UNUSED jobjectArray values,
577                MAYBE_UNUSED jboolean nonVirtual)
578 {
579   return NULL;
580 }
581
582 jstring
583 gnu::classpath::jdwp::VMVirtualMachine::
584 getSourceFile (MAYBE_UNUSED jclass clazz)
585 {
586   return NULL;
587 }
588
589 static gnu::classpath::jdwp::event::filters::StepFilter *
590 get_request_step_filter (EventRequest *request)
591 {
592   ::java::util::Collection *filters = request->getFilters ();
593   ::java::util::Iterator *iter = filters->iterator ();
594   filters::StepFilter *filter = NULL;
595   while (iter->hasNext ())
596     {
597       using namespace gnu::classpath::jdwp::event::filters;
598       IEventFilter *next = (IEventFilter *) iter->next ();
599       if (next->getClass () == &StepFilter::class$)
600         {
601           filter = reinterpret_cast<StepFilter *> (next);
602           break;
603         }
604     }
605
606   return filter;
607 }
608
609 static Location *
610 get_request_location (EventRequest *request)
611 {
612   Location *loc = NULL;
613   ::java::util::Collection *filters = request->getFilters ();
614   ::java::util::Iterator *iter = filters->iterator ();
615   while (iter->hasNext ())
616     {
617       using namespace gnu::classpath::jdwp::event::filters;
618       IEventFilter *filter = (IEventFilter *) iter->next ();
619       if (filter->getClass () == &LocationOnlyFilter::class$)
620         {
621           LocationOnlyFilter *lof
622             = reinterpret_cast<LocationOnlyFilter *> (filter);
623           loc = lof->getLocation ();
624         }
625     }
626
627   return loc;
628 }
629
630 static void
631 throw_jvmti_error (jvmtiError err)
632 {
633   char *error;
634   jstring msg;
635   if (_jdwp_jvmtiEnv->GetErrorName (err, &error) == JVMTI_ERROR_NONE)
636     {
637       msg = JvNewStringLatin1 (error);
638       _jdwp_jvmtiEnv->Deallocate ((unsigned char *) error);
639     }
640   else
641     msg = JvNewStringLatin1 ("out of memory");
642
643   using namespace gnu::classpath::jdwp::exception;
644   throw new JdwpInternalErrorException (msg);
645 }
646
647 static void JNICALL
648 jdwpBreakpointCB (jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
649                   jthread thread, jmethodID method, jlocation location)
650 {
651   jclass klass;
652   jvmtiError err;
653   err = env->GetMethodDeclaringClass (method, &klass);
654   JvAssert (err == JVMTI_ERROR_NONE);
655
656   using namespace gnu::classpath::jdwp;
657
658   jlong methodId = reinterpret_cast<jlong> (method);
659   VMMethod *meth = VMVirtualMachine::getClassMethod (klass, methodId);
660   Location *loc = new Location (meth, location);
661   JvAssert (thread->frame.frame_type == frame_interpreter);
662   _Jv_InterpFrame *iframe
663     = reinterpret_cast<_Jv_InterpFrame *> (thread->interp_frame);
664   jobject instance = iframe->get_this_ptr ();
665   event::BreakpointEvent *event
666     = new event::BreakpointEvent (thread, loc, instance);
667   Jdwp::notify (event);
668 }
669
670 static void JNICALL
671 jdwpClassPrepareCB (jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
672                     jthread thread, jclass klass)
673 {
674   using namespace gnu::classpath::jdwp;
675
676   jint flags = 0;
677   jvmtiError err = env->GetClassStatus (klass, &flags);
678   if (err != JVMTI_ERROR_NONE)
679     throw_jvmti_error (err);
680
681   using namespace gnu::classpath::jdwp::event;
682   jint status = 0;
683   if (flags & JVMTI_CLASS_STATUS_VERIFIED)
684     status |= ClassPrepareEvent::STATUS_VERIFIED;
685   if (flags & JVMTI_CLASS_STATUS_PREPARED)
686     status |= ClassPrepareEvent::STATUS_PREPARED;
687   if (flags & JVMTI_CLASS_STATUS_ERROR)
688     status |= ClassPrepareEvent::STATUS_ERROR;
689   if (flags & JVMTI_CLASS_STATUS_INITIALIZED)
690     status |= ClassPrepareEvent::STATUS_INITIALIZED;
691
692   event::ClassPrepareEvent *event
693     = new event::ClassPrepareEvent (thread, klass, status);
694   Jdwp::notify (event);
695 }
696
697 static void JNICALL
698 jdwpThreadEndCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
699                  jthread thread)
700 {
701   using namespace gnu::classpath::jdwp::event;
702
703   ThreadEndEvent *e = new ThreadEndEvent (thread);
704   gnu::classpath::jdwp::Jdwp::notify (e);
705 }
706
707 static void JNICALL
708 jdwpThreadStartCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
709                    jthread thread)
710 {
711   using namespace gnu::classpath::jdwp::event;
712
713   ThreadStartEvent *e = new ThreadStartEvent (thread);
714   gnu::classpath::jdwp::Jdwp::notify (e);
715 }
716
717 static void JNICALL
718 jdwpVMDeathCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env)
719 {
720   using namespace gnu::classpath::jdwp::event;
721   gnu::classpath::jdwp::Jdwp::notify (new VmDeathEvent ());
722 }
723
724 static void JNICALL
725 jdwpVMInitCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
726               jthread thread)
727 {
728   // The VM is now initialized, add our callbacks
729   jvmtiEventCallbacks callbacks;
730   DEFINE_CALLBACK (callbacks, Breakpoint);
731   DEFINE_CALLBACK (callbacks, ClassPrepare);
732   DEFINE_CALLBACK (callbacks, ThreadEnd);
733   DEFINE_CALLBACK (callbacks, ThreadStart);
734   DEFINE_CALLBACK (callbacks, VMDeath);
735   _jdwp_jvmtiEnv->SetEventCallbacks (&callbacks, sizeof (callbacks));
736
737   // Enable callbacks
738   ENABLE_EVENT (BREAKPOINT, NULL);
739   ENABLE_EVENT (CLASS_PREPARE, NULL);
740   ENABLE_EVENT (THREAD_END, NULL);
741   ENABLE_EVENT (THREAD_START, NULL);
742   ENABLE_EVENT (VM_DEATH, NULL);
743
744   // Send JDWP VMInit
745   using namespace gnu::classpath::jdwp::event;
746   gnu::classpath::jdwp::Jdwp::notify (new VmInitEvent (thread));
747 }