OSDN Git Service

71aa674054af41e03da4e22caa328e6a1871e88d
[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 (Thread *thread, jint start,
490                                                    jint length)
491 {
492   jint frame_count = getFrameCount (thread);
493   ::java::util::ArrayList *frame_list;
494   
495   // Calculate the max number of frames to be returned.
496   jint num_frames = frame_count - start;
497   
498   // Check if num_frames is valid.
499   if (num_frames < 0)
500     num_frames = 0;
501   
502   // Check if there are more than length frames left after start.
503   // If length ios -1 return all remaining frames.
504   if (length != -1 && num_frames > length)
505     num_frames = length;
506      
507   frame_list = new ::java::util::ArrayList (num_frames);
508   
509   _Jv_Frame *vm_frame = reinterpret_cast<_Jv_Frame *> (thread->frame);
510   
511   // Take start frames off the top of the stack
512   while (vm_frame != NULL && start > 0)
513     {
514       start--;
515       vm_frame = vm_frame->next;
516     }
517   
518   // Use as a counter for the number of frames returned.
519   num_frames = 0;
520   
521   while (vm_frame != NULL && (num_frames < length || length == -1))
522     {  
523       jlong frameId = reinterpret_cast<jlong> (vm_frame);
524       
525       VMFrame *frame = getFrame (thread, frameId);
526       frame_list->add (frame);
527       vm_frame = vm_frame->next;
528       num_frames++;
529     }
530   
531   return frame_list;
532 }
533
534 gnu::classpath::jdwp::VMFrame *
535 gnu::classpath::jdwp::VMVirtualMachine::
536 getFrame (Thread *thread, jlong frameID)
537 {
538   using namespace gnu::classpath::jdwp::exception;
539   
540   _Jv_Frame *vm_frame = (_Jv_Frame *) thread->frame;
541   jint depth = 0;
542   _Jv_Frame *frame = reinterpret_cast<_Jv_Frame *> (frameID); 
543   
544   // We need to find the stack depth of the frame, so search through the call
545   // stack to find it.  This also checks for a valid frameID.
546   while (vm_frame != frame)
547     {
548       vm_frame = vm_frame->next;
549       depth++;
550       if (vm_frame == NULL)
551         throw new InvalidFrameException (frameID);
552     }
553   
554   Location *loc = NULL;
555   jvmtiFrameInfo info;
556   jvmtiError jerr;
557   jint num_frames;
558   jclass klass;
559   
560   // Get the info for the frame of interest
561   jerr = _jdwp_jvmtiEnv->GetStackTrace (thread, depth, 1, &info, &num_frames);
562    
563   if (jerr != JVMTI_ERROR_NONE)
564     throw_jvmti_error (jerr);
565   
566   jerr = _jdwp_jvmtiEnv->GetMethodDeclaringClass (info.method, &klass);
567       
568   if (jerr != JVMTI_ERROR_NONE)
569     throw_jvmti_error (jerr);
570
571   VMMethod *meth 
572     = getClassMethod (klass, reinterpret_cast<jlong> (info.method));
573   
574   if (info.location == -1)
575     loc = new Location (meth, 0);
576   else
577     loc = new Location (meth, info.location);
578   
579   return new VMFrame (thread, reinterpret_cast<jlong> (vm_frame), loc); 
580 }
581
582 jint
583 gnu::classpath::jdwp::VMVirtualMachine::
584 getFrameCount (Thread *thread)
585 {
586   jint frame_count;
587   
588   jvmtiError jerr = _jdwp_jvmtiEnv->GetFrameCount (thread, &frame_count);
589   
590   if (jerr != JVMTI_ERROR_NONE)
591     throw_jvmti_error (jerr);
592   
593   return frame_count;
594 }
595
596 jint
597 gnu::classpath::jdwp::VMVirtualMachine::
598 getThreadStatus (MAYBE_UNUSED Thread *thread)
599 {
600   return 0;
601 }
602
603 java::util::ArrayList *
604 gnu::classpath::jdwp::VMVirtualMachine::
605 getLoadRequests (MAYBE_UNUSED ClassLoader *cl)
606 {
607   return NULL;
608 }
609
610 MethodResult *
611 gnu::classpath::jdwp::VMVirtualMachine::
612 executeMethod (MAYBE_UNUSED jobject obj, MAYBE_UNUSED Thread *thread,
613                MAYBE_UNUSED jclass clazz, MAYBE_UNUSED reflect::Method *method,
614                MAYBE_UNUSED jobjectArray values,
615                MAYBE_UNUSED jboolean nonVirtual)
616 {
617   return NULL;
618 }
619
620 jstring
621 gnu::classpath::jdwp::VMVirtualMachine::
622 getSourceFile (MAYBE_UNUSED jclass clazz)
623 {
624   return NULL;
625 }
626
627 static gnu::classpath::jdwp::event::filters::StepFilter *
628 get_request_step_filter (EventRequest *request)
629 {
630   ::java::util::Collection *filters = request->getFilters ();
631   ::java::util::Iterator *iter = filters->iterator ();
632   filters::StepFilter *filter = NULL;
633   while (iter->hasNext ())
634     {
635       using namespace gnu::classpath::jdwp::event::filters;
636       IEventFilter *next = (IEventFilter *) iter->next ();
637       if (next->getClass () == &StepFilter::class$)
638         {
639           filter = reinterpret_cast<StepFilter *> (next);
640           break;
641         }
642     }
643
644   return filter;
645 }
646
647 static Location *
648 get_request_location (EventRequest *request)
649 {
650   Location *loc = NULL;
651   ::java::util::Collection *filters = request->getFilters ();
652   ::java::util::Iterator *iter = filters->iterator ();
653   while (iter->hasNext ())
654     {
655       using namespace gnu::classpath::jdwp::event::filters;
656       IEventFilter *filter = (IEventFilter *) iter->next ();
657       if (filter->getClass () == &LocationOnlyFilter::class$)
658         {
659           LocationOnlyFilter *lof
660             = reinterpret_cast<LocationOnlyFilter *> (filter);
661           loc = lof->getLocation ();
662         }
663     }
664
665   return loc;
666 }
667
668 static void
669 throw_jvmti_error (jvmtiError err)
670 {
671   char *error;
672   jstring msg;
673   if (_jdwp_jvmtiEnv->GetErrorName (err, &error) == JVMTI_ERROR_NONE)
674     {
675       msg = JvNewStringLatin1 (error);
676       _jdwp_jvmtiEnv->Deallocate ((unsigned char *) error);
677     }
678   else
679     msg = JvNewStringLatin1 ("out of memory");
680
681   using namespace gnu::classpath::jdwp::exception;
682   throw new JdwpInternalErrorException (msg);
683 }
684
685 static void JNICALL
686 jdwpBreakpointCB (jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
687                   jthread thread, jmethodID method, jlocation location)
688 {
689   jclass klass;
690   jvmtiError err;
691   err = env->GetMethodDeclaringClass (method, &klass);
692   JvAssert (err == JVMTI_ERROR_NONE);
693
694   using namespace gnu::classpath::jdwp;
695
696   jlong methodId = reinterpret_cast<jlong> (method);
697   VMMethod *meth = VMVirtualMachine::getClassMethod (klass, methodId);
698   Location *loc = new Location (meth, location);
699   JvAssert (thread->frame.frame_type == frame_interpreter);
700   _Jv_InterpFrame *iframe
701     = reinterpret_cast<_Jv_InterpFrame *> (thread->interp_frame);
702   jobject instance = iframe->get_this_ptr ();
703   event::BreakpointEvent *event
704     = new event::BreakpointEvent (thread, loc, instance);
705   Jdwp::notify (event);
706 }
707
708 static void JNICALL
709 jdwpClassPrepareCB (jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
710                     jthread thread, jclass klass)
711 {
712   using namespace gnu::classpath::jdwp;
713
714   jint flags = 0;
715   jvmtiError err = env->GetClassStatus (klass, &flags);
716   if (err != JVMTI_ERROR_NONE)
717     throw_jvmti_error (err);
718
719   using namespace gnu::classpath::jdwp::event;
720   jint status = 0;
721   if (flags & JVMTI_CLASS_STATUS_VERIFIED)
722     status |= ClassPrepareEvent::STATUS_VERIFIED;
723   if (flags & JVMTI_CLASS_STATUS_PREPARED)
724     status |= ClassPrepareEvent::STATUS_PREPARED;
725   if (flags & JVMTI_CLASS_STATUS_ERROR)
726     status |= ClassPrepareEvent::STATUS_ERROR;
727   if (flags & JVMTI_CLASS_STATUS_INITIALIZED)
728     status |= ClassPrepareEvent::STATUS_INITIALIZED;
729
730   event::ClassPrepareEvent *event
731     = new event::ClassPrepareEvent (thread, klass, status);
732   Jdwp::notify (event);
733 }
734
735 static void JNICALL
736 jdwpThreadEndCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
737                  jthread thread)
738 {
739   using namespace gnu::classpath::jdwp::event;
740
741   ThreadEndEvent *e = new ThreadEndEvent (thread);
742   gnu::classpath::jdwp::Jdwp::notify (e);
743 }
744
745 static void JNICALL
746 jdwpThreadStartCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
747                    jthread thread)
748 {
749   using namespace gnu::classpath::jdwp::event;
750
751   ThreadStartEvent *e = new ThreadStartEvent (thread);
752   gnu::classpath::jdwp::Jdwp::notify (e);
753 }
754
755 static void JNICALL
756 jdwpVMDeathCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env)
757 {
758   using namespace gnu::classpath::jdwp::event;
759   gnu::classpath::jdwp::Jdwp::notify (new VmDeathEvent ());
760 }
761
762 static void JNICALL
763 jdwpVMInitCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
764               jthread thread)
765 {
766   // The VM is now initialized, add our callbacks
767   jvmtiEventCallbacks callbacks;
768   DEFINE_CALLBACK (callbacks, Breakpoint);
769   DEFINE_CALLBACK (callbacks, ClassPrepare);
770   DEFINE_CALLBACK (callbacks, ThreadEnd);
771   DEFINE_CALLBACK (callbacks, ThreadStart);
772   DEFINE_CALLBACK (callbacks, VMDeath);
773   _jdwp_jvmtiEnv->SetEventCallbacks (&callbacks, sizeof (callbacks));
774
775   // Enable callbacks
776   ENABLE_EVENT (BREAKPOINT, NULL);
777   ENABLE_EVENT (CLASS_PREPARE, NULL);
778   ENABLE_EVENT (THREAD_END, NULL);
779   ENABLE_EVENT (THREAD_START, NULL);
780   ENABLE_EVENT (VM_DEATH, NULL);
781
782   // Send JDWP VMInit
783   using namespace gnu::classpath::jdwp::event;
784   gnu::classpath::jdwp::Jdwp::notify (new VmInitEvent (thread));
785 }