1 // natVMVirtualMachine.cc - native support for VMVirtualMachine
3 /* Copyright (C) 2006, 2007 Free Software Foundation
5 This file is part of libgcj.
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
13 #include <java-assert.h>
14 #include <java-interp.h>
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>
31 #include <gnu/classpath/jdwp/Jdwp.h>
32 #include <gnu/classpath/jdwp/JdwpConstants$StepDepth.h>
33 #include <gnu/classpath/jdwp/JdwpConstants$StepSize.h>
34 #include <gnu/classpath/jdwp/VMFrame.h>
35 #include <gnu/classpath/jdwp/VMMethod.h>
36 #include <gnu/classpath/jdwp/VMVirtualMachine.h>
37 #include <gnu/classpath/jdwp/event/BreakpointEvent.h>
38 #include <gnu/classpath/jdwp/event/ClassPrepareEvent.h>
39 #include <gnu/classpath/jdwp/event/EventManager.h>
40 #include <gnu/classpath/jdwp/event/EventRequest.h>
41 #include <gnu/classpath/jdwp/event/SingleStepEvent.h>
42 #include <gnu/classpath/jdwp/event/ThreadEndEvent.h>
43 #include <gnu/classpath/jdwp/event/ThreadStartEvent.h>
44 #include <gnu/classpath/jdwp/event/VmDeathEvent.h>
45 #include <gnu/classpath/jdwp/event/VmInitEvent.h>
46 #include <gnu/classpath/jdwp/event/filters/IEventFilter.h>
47 #include <gnu/classpath/jdwp/event/filters/LocationOnlyFilter.h>
48 #include <gnu/classpath/jdwp/event/filters/StepFilter.h>
49 #include <gnu/classpath/jdwp/exception/InvalidFrameException.h>
50 #include <gnu/classpath/jdwp/exception/InvalidLocationException.h>
51 #include <gnu/classpath/jdwp/exception/InvalidMethodException.h>
52 #include <gnu/classpath/jdwp/exception/JdwpInternalErrorException.h>
53 #include <gnu/classpath/jdwp/id/ThreadId.h>
54 #include <gnu/classpath/jdwp/util/Location.h>
55 #include <gnu/classpath/jdwp/util/MethodResult.h>
56 #include <gnu/gcj/jvmti/Breakpoint.h>
57 #include <gnu/gcj/jvmti/BreakpointManager.h>
59 using namespace java::lang;
60 using namespace gnu::classpath::jdwp::event;
61 using namespace gnu::classpath::jdwp::util;
63 // Stepping information
66 jint size; // See gnu.classpath.jdwp.JdwpConstants.StepSize
67 jint depth; // See gnu.classpath.jdwp.JdwpConstants.StepDepth
68 int stack_depth; // stack depth at start of stepping
69 jmethodID method; // method in which we are stepping
72 // Forward declarations
73 static jvmtiError get_linetable (jvmtiEnv *, jmethodID, jint *,
74 jvmtiLineNumberEntry **);
75 static Location *get_request_location (EventRequest *);
76 static gnu::classpath::jdwp::event::filters::StepFilter *
77 get_request_step_filter (EventRequest *);
78 static void handle_single_step (jvmtiEnv *, struct step_info *, jthread,
79 jmethodID, jlocation);
80 static void JNICALL jdwpBreakpointCB (jvmtiEnv *, JNIEnv *, jthread,
81 jmethodID, jlocation);
82 static void JNICALL jdwpClassPrepareCB (jvmtiEnv *, JNIEnv *, jthread, jclass);
83 static void JNICALL jdwpSingleStepCB (jvmtiEnv *, JNIEnv *, jthread,
84 jmethodID, jlocation);
85 static void JNICALL jdwpThreadEndCB (jvmtiEnv *, JNIEnv *, jthread);
86 static void JNICALL jdwpThreadStartCB (jvmtiEnv *, JNIEnv *, jthread);
87 static void JNICALL jdwpVMDeathCB (jvmtiEnv *, JNIEnv *);
88 static void JNICALL jdwpVMInitCB (jvmtiEnv *, JNIEnv *, jthread);
89 static void throw_jvmti_error (jvmtiError);
91 #define DEFINE_CALLBACK(Cb,Event) Cb.Event = jdwp ## Event ## CB
92 #define DISABLE_EVENT(Event,Thread) \
93 _jdwp_jvmtiEnv->SetEventNotificationMode (JVMTI_DISABLE, \
94 JVMTI_EVENT_ ## Event, Thread)
95 #define ENABLE_EVENT(Event,Thread) \
96 _jdwp_jvmtiEnv->SetEventNotificationMode (JVMTI_ENABLE, \
97 JVMTI_EVENT_ ## Event, Thread)
99 static jvmtiEnv *_jdwp_jvmtiEnv;
102 _Jv_GetJDWP_JVMTIEnv (void)
104 return _jdwp_jvmtiEnv;
108 gnu::classpath::jdwp::VMVirtualMachine::initialize ()
110 _jdwp_suspend_counts = new ::java::util::Hashtable ();
111 _stepping_threads = new ::java::util::Hashtable ();
113 JavaVM *vm = _Jv_GetJavaVM ();
114 vm->GetEnv (reinterpret_cast<void **> (&_jdwp_jvmtiEnv), JVMTI_VERSION_1_0);
116 // Wait for VM_INIT to do more initialization
117 jvmtiEventCallbacks callbacks;
118 DEFINE_CALLBACK (callbacks, VMInit);
119 _jdwp_jvmtiEnv->SetEventCallbacks (&callbacks, sizeof (callbacks));
120 ENABLE_EVENT (VM_INIT, NULL);
124 gnu::classpath::jdwp::VMVirtualMachine::suspendThread (Thread *thread)
129 JvSynchronize dummy (_jdwp_suspend_counts);
130 count = reinterpret_cast<Integer *> (_jdwp_suspend_counts->get (thread));
133 // New -- suspend thread
138 // Thread already suspended
139 value = count->intValue ();
142 count = Integer::valueOf (++value);
143 _jdwp_suspend_counts->put (thread, count);
148 // Suspend the thread
149 jvmtiError err = _jdwp_jvmtiEnv->SuspendThread (thread);
150 if (err != JVMTI_ERROR_NONE)
152 using namespace gnu::gcj::runtime;
153 using namespace gnu::classpath::jdwp::exception;
155 _jdwp_jvmtiEnv->GetErrorName (err, &reason);
156 String *txt = JvNewStringLatin1 ("could not suspend thread: ");
157 StringBuilder *msg = new StringBuilder (txt);
158 msg->append (JvNewStringLatin1 (reason));
159 _jdwp_jvmtiEnv->Deallocate ((unsigned char *) reason);
160 throw new JdwpInternalErrorException (msg->toString ());
166 gnu::classpath::jdwp::VMVirtualMachine::resumeThread (Thread *thread)
170 JvSynchronize dummy (_jdwp_suspend_counts);
172 = reinterpret_cast<Integer *> (_jdwp_suspend_counts->get (thread));
175 // Thread not suspended: ThreadReference.Resume says to ignore it.
180 // Decrement suspend count
181 value = count->intValue () - 1;
186 // Thread will be resumed, remove from table
187 _jdwp_suspend_counts->remove (thread);
191 // Thread stays suspended: record new suspend count
192 count = Integer::valueOf (value);
193 _jdwp_suspend_counts->put (thread, count);
199 jvmtiError err = _jdwp_jvmtiEnv->ResumeThread (thread);
200 if (err != JVMTI_ERROR_NONE)
202 using namespace gnu::gcj::runtime;
203 using namespace gnu::classpath::jdwp::exception;
205 _jdwp_jvmtiEnv->GetErrorName (err, &reason);
206 String *txt = JvNewStringLatin1 ("could not resume thread: ");
207 StringBuilder *msg = new StringBuilder (txt);
208 msg->append (JvNewStringLatin1 (reason));
209 _jdwp_jvmtiEnv->Deallocate ((unsigned char *) reason);
210 throw new JdwpInternalErrorException (msg->toString ());
216 gnu::classpath::jdwp::VMVirtualMachine::getSuspendCount (Thread *thread)
218 jint suspensions = 0;
220 = reinterpret_cast<Integer *> (_jdwp_suspend_counts->get (thread));
222 suspensions = count->intValue ();
227 gnu::classpath::jdwp::VMVirtualMachine::registerEvent (EventRequest *request)
229 switch (request->getEventKind ())
231 case EventRequest::EVENT_SINGLE_STEP:
234 filters::StepFilter *filter = get_request_step_filter (request);
237 // No filter specified: report every step in every
243 // Add stepping information to list of stepping threads
244 thread = filter->getThread ()->getThread ();
245 _Jv_InterpFrame *frame
246 = reinterpret_cast<_Jv_InterpFrame *> (thread->interp_frame);
247 struct step_info *sinfo
248 = (struct step_info *) JvAllocBytes (sizeof (struct step_info));
249 sinfo->size = filter->getSize ();
250 sinfo->depth = filter->getDepth ();
251 sinfo->stack_depth = frame->depth ();
252 sinfo->method = frame->self->get_method ();
253 _stepping_threads->put (thread, (jobject) sinfo);
256 ENABLE_EVENT (SINGLE_STEP, thread);
260 case EventRequest::EVENT_BREAKPOINT:
262 using namespace ::gnu::gcj::jvmti;
263 Location *loc = get_request_location (request);
266 using namespace gnu::classpath::jdwp::exception;
267 throw new InvalidLocationException ();
270 jlong method = loc->getMethod ()->getId ();
271 jlocation index = loc->getIndex ();
272 Breakpoint *bp = BreakpointManager::getBreakpoint (method, index);
275 // Breakpoint not in interpreter yet
276 bp = BreakpointManager::newBreakpoint (method, index);
280 // Ignore the duplicate
285 case EventRequest::EVENT_FRAME_POP:
288 case EventRequest::EVENT_EXCEPTION:
291 case EventRequest::EVENT_USER_DEFINED:
294 case EventRequest::EVENT_THREAD_START:
297 case EventRequest::EVENT_THREAD_END:
300 case EventRequest::EVENT_CLASS_PREPARE:
303 case EventRequest::EVENT_CLASS_LOAD:
306 case EventRequest::EVENT_CLASS_UNLOAD:
309 case EventRequest::EVENT_FIELD_ACCESS:
312 case EventRequest::EVENT_FIELD_MODIFY:
315 case EventRequest::EVENT_METHOD_ENTRY:
318 case EventRequest::EVENT_METHOD_EXIT:
321 case EventRequest::EVENT_VM_INIT:
324 case EventRequest::EVENT_VM_DEATH:
330 gnu::classpath::jdwp::VMVirtualMachine::unregisterEvent (EventRequest *request)
332 switch (request->getEventKind ())
334 case EventRequest::EVENT_SINGLE_STEP:
337 filters::StepFilter *filter = get_request_step_filter (request);
342 thread = filter->getThread ()->getThread ();
343 _stepping_threads->remove (thread);
346 DISABLE_EVENT (SINGLE_STEP, thread);
350 case EventRequest::EVENT_BREAKPOINT:
352 using namespace gnu::gcj::jvmti;
353 ::java::util::Collection *breakpoints;
354 EventManager *em = EventManager::getDefault ();
355 breakpoints = em->getRequests (EventRequest::EVENT_BREAKPOINT);
357 // Check for duplicates
359 Location *the_location = get_request_location (request);
361 // This should not be possible: we REQUIRE a Location
362 // to install a breakpoint
363 JvAssert (the_location != NULL);
365 ::java::util::Iterator *iter = breakpoints->iterator ();
366 while (iter->hasNext ())
369 = reinterpret_cast<EventRequest *> (iter->next ());
370 Location *loc = get_request_location (er);
371 JvAssert (loc != NULL);
372 if (loc->equals (the_location) && ++matches == 2)
374 // Short-circuit: already more than one breakpoint
381 using namespace gnu::classpath::jdwp::exception;
383 = JvNewStringLatin1 ("attempt to remove unknown breakpoint");
384 throw new JdwpInternalErrorException (msg);
387 jlong methodId = the_location->getMethod ()->getId ();
388 BreakpointManager::deleteBreakpoint (methodId,
389 the_location->getIndex ());
393 case EventRequest::EVENT_FRAME_POP:
396 case EventRequest::EVENT_EXCEPTION:
399 case EventRequest::EVENT_USER_DEFINED:
402 case EventRequest::EVENT_THREAD_START:
405 case EventRequest::EVENT_THREAD_END:
408 case EventRequest::EVENT_CLASS_PREPARE:
411 case EventRequest::EVENT_CLASS_LOAD:
414 case EventRequest::EVENT_CLASS_UNLOAD:
417 case EventRequest::EVENT_FIELD_ACCESS:
420 case EventRequest::EVENT_FIELD_MODIFY:
423 case EventRequest::EVENT_METHOD_ENTRY:
426 case EventRequest::EVENT_METHOD_EXIT:
429 case EventRequest::EVENT_VM_INIT:
432 case EventRequest::EVENT_VM_DEATH:
438 gnu::classpath::jdwp::VMVirtualMachine::clearEvents (MAYBE_UNUSED jbyte kind)
443 gnu::classpath::jdwp::VMVirtualMachine::getAllLoadedClassesCount (void)
448 java::util::Iterator *
449 gnu::classpath::jdwp::VMVirtualMachine::getAllLoadedClasses (void)
455 gnu::classpath::jdwp::VMVirtualMachine::
456 getClassStatus (MAYBE_UNUSED jclass klass)
461 JArray<gnu::classpath::jdwp::VMMethod *> *
462 gnu::classpath::jdwp::VMVirtualMachine::
463 getAllClassMethods (jclass klass)
467 jvmtiError err = _jdwp_jvmtiEnv->GetClassMethods (klass, &count, &methods);
468 if (err != JVMTI_ERROR_NONE)
469 throw_jvmti_error (err);
471 JArray<VMMethod *> *result
472 = (JArray<VMMethod *> *) JvNewObjectArray (count,
473 &VMMethod::class$, NULL);
474 VMMethod **rmeth = elements (result);
475 for (int i = 0; i < count; ++i)
477 jlong id = reinterpret_cast<jlong> (methods[i]);
478 rmeth[i] = getClassMethod (klass, id);
481 _jdwp_jvmtiEnv->Deallocate ((unsigned char *) methods);
485 gnu::classpath::jdwp::VMMethod *
486 gnu::classpath::jdwp::VMVirtualMachine::
487 getClassMethod (jclass klass, jlong id)
489 jmethodID method = reinterpret_cast<jmethodID> (id);
490 _Jv_MethodBase *bmeth = _Jv_FindInterpreterMethod (klass, method);
492 return new gnu::classpath::jdwp::VMMethod (klass, id);
494 throw new gnu::classpath::jdwp::exception::InvalidMethodException (id);
497 java::util::ArrayList *
498 gnu::classpath::jdwp::VMVirtualMachine::getFrames (Thread *thread, jint start,
501 jint frame_count = getFrameCount (thread);
502 ::java::util::ArrayList *frame_list;
504 // Calculate the max number of frames to be returned.
505 jint num_frames = frame_count - start;
507 // Check if num_frames is valid.
511 // Check if there are more than length frames left after start.
512 // If length ios -1 return all remaining frames.
513 if (length != -1 && num_frames > length)
516 frame_list = new ::java::util::ArrayList (num_frames);
518 _Jv_Frame *vm_frame = reinterpret_cast<_Jv_Frame *> (thread->frame);
520 // Take start frames off the top of the stack
521 while (vm_frame != NULL && start > 0)
524 vm_frame = vm_frame->next;
527 // Use as a counter for the number of frames returned.
530 while (vm_frame != NULL && (num_frames < length || length == -1))
532 jlong frameId = reinterpret_cast<jlong> (vm_frame);
534 VMFrame *frame = getFrame (thread, frameId);
535 frame_list->add (frame);
536 vm_frame = vm_frame->next;
543 gnu::classpath::jdwp::VMFrame *
544 gnu::classpath::jdwp::VMVirtualMachine::
545 getFrame (Thread *thread, jlong frameID)
547 using namespace gnu::classpath::jdwp::exception;
549 _Jv_Frame *vm_frame = (_Jv_Frame *) thread->frame;
551 _Jv_Frame *frame = reinterpret_cast<_Jv_Frame *> (frameID);
553 // We need to find the stack depth of the frame, so search through the call
554 // stack to find it. This also checks for a valid frameID.
555 while (vm_frame != frame)
557 vm_frame = vm_frame->next;
559 if (vm_frame == NULL)
560 throw new InvalidFrameException (frameID);
563 Location *loc = NULL;
569 // Get the info for the frame of interest
570 jerr = _jdwp_jvmtiEnv->GetStackTrace (thread, depth, 1, &info, &num_frames);
572 if (jerr != JVMTI_ERROR_NONE)
573 throw_jvmti_error (jerr);
575 jerr = _jdwp_jvmtiEnv->GetMethodDeclaringClass (info.method, &klass);
577 if (jerr != JVMTI_ERROR_NONE)
578 throw_jvmti_error (jerr);
581 = getClassMethod (klass, reinterpret_cast<jlong> (info.method));
583 if (info.location == -1)
584 loc = new Location (meth, 0);
586 loc = new Location (meth, info.location);
588 return new VMFrame (thread, reinterpret_cast<jlong> (vm_frame), loc);
592 gnu::classpath::jdwp::VMVirtualMachine::
593 getFrameCount (Thread *thread)
597 jvmtiError jerr = _jdwp_jvmtiEnv->GetFrameCount (thread, &frame_count);
599 if (jerr != JVMTI_ERROR_NONE)
600 throw_jvmti_error (jerr);
606 gnu::classpath::jdwp::VMVirtualMachine::
607 getThreadStatus (MAYBE_UNUSED Thread *thread)
612 java::util::ArrayList *
613 gnu::classpath::jdwp::VMVirtualMachine::
614 getLoadRequests (MAYBE_UNUSED ClassLoader *cl)
620 gnu::classpath::jdwp::VMVirtualMachine::
621 executeMethod (MAYBE_UNUSED jobject obj, MAYBE_UNUSED Thread *thread,
622 MAYBE_UNUSED jclass clazz, MAYBE_UNUSED reflect::Method *method,
623 MAYBE_UNUSED jobjectArray values,
624 MAYBE_UNUSED jboolean nonVirtual)
630 gnu::classpath::jdwp::VMVirtualMachine::
631 getSourceFile (MAYBE_UNUSED jclass clazz)
636 // A simple caching function used while single-stepping
638 get_linetable (jvmtiEnv *env, jmethodID method, jint *count_ptr,
639 jvmtiLineNumberEntry **table_ptr)
641 static jint last_count = 0;
642 static jvmtiLineNumberEntry *last_table = NULL;
643 static jmethodID last_method = 0;
645 if (method == last_method)
647 *count_ptr = last_count;
648 *table_ptr = last_table;
649 return JVMTI_ERROR_NONE;
654 jvmtiLineNumberEntry *table;
655 err = env->GetLineNumberTable (method, &count, &table);
656 if (err != JVMTI_ERROR_NONE)
658 // Keep last table in cache
662 env->Deallocate ((unsigned char *) last_table);
663 last_table = *table_ptr = table;
664 last_count = *count_ptr = count;
665 return JVMTI_ERROR_NONE;
668 static gnu::classpath::jdwp::event::filters::StepFilter *
669 get_request_step_filter (EventRequest *request)
671 ::java::util::Collection *filters = request->getFilters ();
672 ::java::util::Iterator *iter = filters->iterator ();
673 filters::StepFilter *filter = NULL;
674 while (iter->hasNext ())
676 using namespace gnu::classpath::jdwp::event::filters;
677 IEventFilter *next = (IEventFilter *) iter->next ();
678 if (next->getClass () == &StepFilter::class$)
680 filter = reinterpret_cast<StepFilter *> (next);
689 get_request_location (EventRequest *request)
691 Location *loc = NULL;
692 ::java::util::Collection *filters = request->getFilters ();
693 ::java::util::Iterator *iter = filters->iterator ();
694 while (iter->hasNext ())
696 using namespace gnu::classpath::jdwp::event::filters;
697 IEventFilter *filter = (IEventFilter *) iter->next ();
698 if (filter->getClass () == &LocationOnlyFilter::class$)
700 LocationOnlyFilter *lof
701 = reinterpret_cast<LocationOnlyFilter *> (filter);
702 loc = lof->getLocation ();
710 handle_single_step (jvmtiEnv *env, struct step_info *sinfo, jthread thread,
711 jmethodID method, jlocation location)
713 using namespace gnu::classpath::jdwp;
715 if (sinfo == NULL || sinfo->size == JdwpConstants$StepSize::MIN)
718 goto send_notification;
722 // Check if we're on a new source line
723 /* This is a little inefficient when we're stepping OVER,
724 but this must be done when stepping INTO. */
726 jvmtiLineNumberEntry *table;
727 if (get_linetable (env, method, &count, &table) == JVMTI_ERROR_NONE)
730 for (i = 0; i < count; ++i)
732 if (table[i].start_location == location)
734 // This is the start of a new line -- stop
735 goto send_notification;
739 // Not at a new source line -- just keep stepping
744 /* Something went wrong: either "absent information"
745 or "out of memory" ("invalid method id" and "native
746 method" aren't possible -- those are validated before
747 single stepping is enabled).
749 Do what gdb does: just keep going. */
756 jvmtiError err = env->GetMethodDeclaringClass (method, &klass);
757 if (err != JVMTI_ERROR_NONE)
759 fprintf (stderr, "libgcj: internal error: could not find class for method while single stepping -- continuing\n");
763 VMMethod *vmmethod = new VMMethod (klass, reinterpret_cast<jlong> (method));
764 Location *loc = new Location (vmmethod, location);
765 JvAssert (thread->frame.frame_type == frame_interpreter);
766 _Jv_InterpFrame *iframe
767 = reinterpret_cast<_Jv_InterpFrame *> (thread->interp_frame);
768 jobject instance = iframe->get_this_ptr ();
769 event::SingleStepEvent *event
770 = new event::SingleStepEvent (thread, loc, instance);
771 Jdwp::notify (event);
775 throw_jvmti_error (jvmtiError err)
779 if (_jdwp_jvmtiEnv->GetErrorName (err, &error) == JVMTI_ERROR_NONE)
781 msg = JvNewStringLatin1 (error);
782 _jdwp_jvmtiEnv->Deallocate ((unsigned char *) error);
785 msg = JvNewStringLatin1 ("out of memory");
787 using namespace gnu::classpath::jdwp::exception;
788 throw new JdwpInternalErrorException (msg);
792 jdwpBreakpointCB (jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
793 jthread thread, jmethodID method, jlocation location)
797 err = env->GetMethodDeclaringClass (method, &klass);
798 JvAssert (err == JVMTI_ERROR_NONE);
800 using namespace gnu::classpath::jdwp;
802 jlong methodId = reinterpret_cast<jlong> (method);
803 VMMethod *meth = VMVirtualMachine::getClassMethod (klass, methodId);
804 Location *loc = new Location (meth, location);
805 JvAssert (thread->frame.frame_type == frame_interpreter);
806 _Jv_InterpFrame *iframe
807 = reinterpret_cast<_Jv_InterpFrame *> (thread->interp_frame);
808 jobject instance = iframe->get_this_ptr ();
809 event::BreakpointEvent *event
810 = new event::BreakpointEvent (thread, loc, instance);
811 Jdwp::notify (event);
815 jdwpClassPrepareCB (jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
816 jthread thread, jclass klass)
818 using namespace gnu::classpath::jdwp;
821 jvmtiError err = env->GetClassStatus (klass, &flags);
822 if (err != JVMTI_ERROR_NONE)
823 throw_jvmti_error (err);
825 using namespace gnu::classpath::jdwp::event;
827 if (flags & JVMTI_CLASS_STATUS_VERIFIED)
828 status |= ClassPrepareEvent::STATUS_VERIFIED;
829 if (flags & JVMTI_CLASS_STATUS_PREPARED)
830 status |= ClassPrepareEvent::STATUS_PREPARED;
831 if (flags & JVMTI_CLASS_STATUS_ERROR)
832 status |= ClassPrepareEvent::STATUS_ERROR;
833 if (flags & JVMTI_CLASS_STATUS_INITIALIZED)
834 status |= ClassPrepareEvent::STATUS_INITIALIZED;
836 event::ClassPrepareEvent *event
837 = new event::ClassPrepareEvent (thread, klass, status);
838 Jdwp::notify (event);
842 jdwpSingleStepCB (jvmtiEnv *env, JNIEnv *jni_env, jthread thread,
843 jmethodID method, jlocation location)
846 gnu::classpath::jdwp::VMVirtualMachine::_stepping_threads->get (thread);
847 struct step_info *sinfo = reinterpret_cast<struct step_info *> (si);
851 // no step filter for this thread - simply report it
852 handle_single_step (env, NULL, thread, method, location);
856 // A step filter exists for this thread
857 using namespace gnu::classpath::jdwp;
859 _Jv_InterpFrame *frame
860 = reinterpret_cast<_Jv_InterpFrame *> (thread->interp_frame);
862 switch (sinfo->depth)
864 case JdwpConstants$StepDepth::INTO:
865 /* This is the easy case. We ignore the method and
866 simply stop at either the next insn, or the next source
868 handle_single_step (env, sinfo, thread, method, location);
871 case JdwpConstants$StepDepth::OVER:
872 /* This is also a pretty easy case. We just make sure that
873 the methods are the same and that we are at the same
874 stack depth, but we should also stop on the next
875 insn/line if the stack depth is LESS THAN it was when
876 we started stepping. */
877 if (method == sinfo->method)
879 // Still in the same method -- must be at same stack depth
880 // to avoid confusion with recursive methods.
881 if (frame->depth () == sinfo->stack_depth)
882 handle_single_step (env, sinfo, thread, method, location);
884 else if (frame->depth () < sinfo->stack_depth)
886 // The method in which we were stepping was popped off
887 // the stack. We simply need to stop at the next insn/line.
888 handle_single_step (env, sinfo, thread, method, location);
892 case JdwpConstants$StepDepth::OUT:
893 // All we need to do is check the stack depth
894 if (sinfo->stack_depth > frame->depth ())
895 handle_single_step (env, sinfo, thread, method, location);
899 /* This should not happen. The JDWP back-end should have
900 validated the StepFilter. */
902 "libgcj: unknown step depth while single stepping\n");
909 jdwpThreadEndCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
912 using namespace gnu::classpath::jdwp::event;
914 ThreadEndEvent *e = new ThreadEndEvent (thread);
915 gnu::classpath::jdwp::Jdwp::notify (e);
919 jdwpThreadStartCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
922 using namespace gnu::classpath::jdwp::event;
924 ThreadStartEvent *e = new ThreadStartEvent (thread);
925 gnu::classpath::jdwp::Jdwp::notify (e);
929 jdwpVMDeathCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env)
931 using namespace gnu::classpath::jdwp::event;
932 gnu::classpath::jdwp::Jdwp::notify (new VmDeathEvent ());
936 jdwpVMInitCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
939 // The VM is now initialized, add our callbacks
940 jvmtiEventCallbacks callbacks;
941 DEFINE_CALLBACK (callbacks, Breakpoint);
942 DEFINE_CALLBACK (callbacks, ClassPrepare);
943 DEFINE_CALLBACK (callbacks, SingleStep);
944 DEFINE_CALLBACK (callbacks, ThreadEnd);
945 DEFINE_CALLBACK (callbacks, ThreadStart);
946 DEFINE_CALLBACK (callbacks, VMDeath);
947 _jdwp_jvmtiEnv->SetEventCallbacks (&callbacks, sizeof (callbacks));
950 ENABLE_EVENT (BREAKPOINT, NULL);
951 ENABLE_EVENT (CLASS_PREPARE, NULL);
952 // SingleStep is enabled only when needed
953 ENABLE_EVENT (THREAD_END, NULL);
954 ENABLE_EVENT (THREAD_START, NULL);
955 ENABLE_EVENT (VM_DEATH, NULL);
958 using namespace gnu::classpath::jdwp::event;
959 gnu::classpath::jdwp::Jdwp::notify (new VmInitEvent (thread));