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/lang/Throwable.h>
25 #include <java/nio/ByteBuffer.h>
26 #include <java/nio/ByteBufferImpl.h>
27 #include <java/util/ArrayList.h>
28 #include <java/util/Collection.h>
29 #include <java/util/Hashtable.h>
30 #include <java/util/Iterator.h>
32 #include <gnu/classpath/jdwp/Jdwp.h>
33 #include <gnu/classpath/jdwp/JdwpConstants$StepDepth.h>
34 #include <gnu/classpath/jdwp/JdwpConstants$StepSize.h>
35 #include <gnu/classpath/jdwp/JdwpConstants$ThreadStatus.h>
36 #include <gnu/classpath/jdwp/VMFrame.h>
37 #include <gnu/classpath/jdwp/VMMethod.h>
38 #include <gnu/classpath/jdwp/VMVirtualMachine.h>
39 #include <gnu/classpath/jdwp/event/BreakpointEvent.h>
40 #include <gnu/classpath/jdwp/event/ClassPrepareEvent.h>
41 #include <gnu/classpath/jdwp/event/ExceptionEvent.h>
42 #include <gnu/classpath/jdwp/event/EventManager.h>
43 #include <gnu/classpath/jdwp/event/EventRequest.h>
44 #include <gnu/classpath/jdwp/event/SingleStepEvent.h>
45 #include <gnu/classpath/jdwp/event/ThreadEndEvent.h>
46 #include <gnu/classpath/jdwp/event/ThreadStartEvent.h>
47 #include <gnu/classpath/jdwp/event/VmDeathEvent.h>
48 #include <gnu/classpath/jdwp/event/VmInitEvent.h>
49 #include <gnu/classpath/jdwp/event/filters/IEventFilter.h>
50 #include <gnu/classpath/jdwp/event/filters/LocationOnlyFilter.h>
51 #include <gnu/classpath/jdwp/event/filters/StepFilter.h>
52 #include <gnu/classpath/jdwp/exception/AbsentInformationException.h>
53 #include <gnu/classpath/jdwp/exception/InvalidFrameException.h>
54 #include <gnu/classpath/jdwp/exception/InvalidLocationException.h>
55 #include <gnu/classpath/jdwp/exception/InvalidMethodException.h>
56 #include <gnu/classpath/jdwp/exception/JdwpInternalErrorException.h>
57 #include <gnu/classpath/jdwp/id/ThreadId.h>
58 #include <gnu/classpath/jdwp/util/Location.h>
59 #include <gnu/classpath/jdwp/util/MethodResult.h>
60 #include <gnu/gcj/jvmti/Breakpoint.h>
61 #include <gnu/gcj/jvmti/BreakpointManager.h>
63 using namespace java::lang;
64 using namespace gnu::classpath::jdwp::event;
65 using namespace gnu::classpath::jdwp::util;
67 // Stepping information
70 jint size; // See gnu.classpath.jdwp.JdwpConstants.StepSize
71 jint depth; // See gnu.classpath.jdwp.JdwpConstants.StepDepth
72 int stack_depth; // stack depth at start of stepping
73 jmethodID method; // method in which we are stepping
76 // Forward declarations
77 static jvmtiError get_linetable (jvmtiEnv *, jmethodID, jint *,
78 jvmtiLineNumberEntry **);
79 static Location *get_request_location (EventRequest *);
80 static gnu::classpath::jdwp::event::filters::StepFilter *
81 get_request_step_filter (EventRequest *);
82 static void handle_single_step (jvmtiEnv *, struct step_info *, jthread,
83 jmethodID, jlocation);
84 static void JNICALL jdwpBreakpointCB (jvmtiEnv *, JNIEnv *, jthread,
85 jmethodID, jlocation);
86 static void JNICALL jdwpClassPrepareCB (jvmtiEnv *, JNIEnv *, jthread, jclass);
87 static void JNICALL jdwpExceptionCB (jvmtiEnv *, JNIEnv *jni_env, jthread,
88 jmethodID, jlocation, jobject,
89 jmethodID, jlocation);
90 static void JNICALL jdwpSingleStepCB (jvmtiEnv *, JNIEnv *, jthread,
91 jmethodID, jlocation);
92 static void JNICALL jdwpThreadEndCB (jvmtiEnv *, JNIEnv *, jthread);
93 static void JNICALL jdwpThreadStartCB (jvmtiEnv *, JNIEnv *, jthread);
94 static void JNICALL jdwpVMDeathCB (jvmtiEnv *, JNIEnv *);
95 static void JNICALL jdwpVMInitCB (jvmtiEnv *, JNIEnv *, jthread);
96 static void throw_jvmti_error (jvmtiError);
98 #define DEFINE_CALLBACK(Cb,Event) Cb.Event = jdwp ## Event ## CB
99 #define DISABLE_EVENT(Event,Thread) \
100 _jdwp_jvmtiEnv->SetEventNotificationMode (JVMTI_DISABLE, \
101 JVMTI_EVENT_ ## Event, Thread)
102 #define ENABLE_EVENT(Event,Thread) \
103 _jdwp_jvmtiEnv->SetEventNotificationMode (JVMTI_ENABLE, \
104 JVMTI_EVENT_ ## Event, Thread)
106 static jvmtiEnv *_jdwp_jvmtiEnv;
109 _Jv_GetJDWP_JVMTIEnv (void)
111 return _jdwp_jvmtiEnv;
115 gnu::classpath::jdwp::VMVirtualMachine::initialize ()
117 _jdwp_suspend_counts = new ::java::util::Hashtable ();
118 _stepping_threads = new ::java::util::Hashtable ();
119 _event_list = new ::java::util::ArrayList ();
121 JavaVM *vm = _Jv_GetJavaVM ();
127 vm->GetEnv (&(foo.ptr), JVMTI_VERSION_1_0);
128 _jdwp_jvmtiEnv = foo.env;
130 // Wait for VM_INIT to do more initialization
131 jvmtiEventCallbacks callbacks;
132 DEFINE_CALLBACK (callbacks, VMInit);
133 _jdwp_jvmtiEnv->SetEventCallbacks (&callbacks, sizeof (callbacks));
134 ENABLE_EVENT (VM_INIT, NULL);
138 gnu::classpath::jdwp::VMVirtualMachine::suspendThread (Thread *thread)
143 JvSynchronize dummy (_jdwp_suspend_counts);
144 count = reinterpret_cast<Integer *> (_jdwp_suspend_counts->get (thread));
147 // New -- suspend thread
152 // Thread already suspended
153 value = count->intValue ();
156 count = Integer::valueOf (++value);
157 _jdwp_suspend_counts->put (thread, count);
162 // Suspend the thread
163 jvmtiError err = _jdwp_jvmtiEnv->SuspendThread (thread);
164 if (err != JVMTI_ERROR_NONE)
166 using namespace gnu::gcj::runtime;
167 using namespace gnu::classpath::jdwp::exception;
169 _jdwp_jvmtiEnv->GetErrorName (err, &reason);
170 String *txt = JvNewStringLatin1 ("could not suspend thread: ");
171 StringBuilder *msg = new StringBuilder (txt);
172 msg->append (JvNewStringLatin1 (reason));
173 _jdwp_jvmtiEnv->Deallocate ((unsigned char *) reason);
174 throw new JdwpInternalErrorException (msg->toString ());
180 gnu::classpath::jdwp::VMVirtualMachine::resumeThread (Thread *thread)
184 JvSynchronize dummy (_jdwp_suspend_counts);
186 = reinterpret_cast<Integer *> (_jdwp_suspend_counts->get (thread));
189 // Thread not suspended: ThreadReference.Resume says to ignore it.
194 // Decrement suspend count
195 value = count->intValue () - 1;
200 // Thread will be resumed, remove from table
201 _jdwp_suspend_counts->remove (thread);
205 // Thread stays suspended: record new suspend count
206 count = Integer::valueOf (value);
207 _jdwp_suspend_counts->put (thread, count);
213 jvmtiError err = _jdwp_jvmtiEnv->ResumeThread (thread);
214 if (err != JVMTI_ERROR_NONE)
216 using namespace gnu::gcj::runtime;
217 using namespace gnu::classpath::jdwp::exception;
219 _jdwp_jvmtiEnv->GetErrorName (err, &reason);
220 String *txt = JvNewStringLatin1 ("could not resume thread: ");
221 StringBuilder *msg = new StringBuilder (txt);
222 msg->append (JvNewStringLatin1 (reason));
223 _jdwp_jvmtiEnv->Deallocate ((unsigned char *) reason);
224 throw new JdwpInternalErrorException (msg->toString ());
230 gnu::classpath::jdwp::VMVirtualMachine::getSuspendCount (Thread *thread)
232 jint suspensions = 0;
234 = reinterpret_cast<Integer *> (_jdwp_suspend_counts->get (thread));
236 suspensions = count->intValue ();
241 gnu::classpath::jdwp::VMVirtualMachine::registerEvent (EventRequest *request)
243 switch (request->getEventKind ())
245 case EventRequest::EVENT_SINGLE_STEP:
248 filters::StepFilter *filter = get_request_step_filter (request);
251 // No filter specified: report every step in every
257 // Add stepping information to list of stepping threads
258 thread = filter->getThread ()->getThread ();
259 _Jv_InterpFrame *frame
260 = reinterpret_cast<_Jv_InterpFrame *> (thread->interp_frame);
261 struct step_info *sinfo
262 = (struct step_info *) JvAllocBytes (sizeof (struct step_info));
263 sinfo->size = filter->getSize ();
264 sinfo->depth = filter->getDepth ();
265 sinfo->stack_depth = frame->depth ();
266 sinfo->method = frame->self->get_method ();
267 _stepping_threads->put (thread, (jobject) sinfo);
270 ENABLE_EVENT (SINGLE_STEP, thread);
274 case EventRequest::EVENT_BREAKPOINT:
276 using namespace ::gnu::gcj::jvmti;
277 Location *loc = get_request_location (request);
280 using namespace gnu::classpath::jdwp::exception;
281 throw new InvalidLocationException ();
284 jlong method = loc->getMethod ()->getId ();
285 jlocation index = loc->getIndex ();
286 Breakpoint *bp = BreakpointManager::getBreakpoint (method, index);
289 // Breakpoint not in interpreter yet
290 bp = BreakpointManager::newBreakpoint (method, index);
294 // Ignore the duplicate
299 case EventRequest::EVENT_FRAME_POP:
302 case EventRequest::EVENT_EXCEPTION:
305 case EventRequest::EVENT_USER_DEFINED:
308 case EventRequest::EVENT_THREAD_START:
311 case EventRequest::EVENT_THREAD_END:
314 case EventRequest::EVENT_CLASS_PREPARE:
317 case EventRequest::EVENT_CLASS_LOAD:
320 case EventRequest::EVENT_CLASS_UNLOAD:
323 case EventRequest::EVENT_FIELD_ACCESS:
326 case EventRequest::EVENT_FIELD_MODIFY:
329 case EventRequest::EVENT_METHOD_ENTRY:
332 case EventRequest::EVENT_METHOD_EXIT:
335 case EventRequest::EVENT_VM_INIT:
338 case EventRequest::EVENT_VM_DEATH:
344 gnu::classpath::jdwp::VMVirtualMachine::unregisterEvent (EventRequest *request)
346 switch (request->getEventKind ())
348 case EventRequest::EVENT_SINGLE_STEP:
351 filters::StepFilter *filter = get_request_step_filter (request);
356 thread = filter->getThread ()->getThread ();
357 _stepping_threads->remove (thread);
360 DISABLE_EVENT (SINGLE_STEP, thread);
364 case EventRequest::EVENT_BREAKPOINT:
366 using namespace gnu::gcj::jvmti;
367 ::java::util::Collection *breakpoints;
368 EventManager *em = EventManager::getDefault ();
369 breakpoints = em->getRequests (EventRequest::EVENT_BREAKPOINT);
371 // Check for duplicates
373 Location *the_location = get_request_location (request);
375 // This should not be possible: we REQUIRE a Location
376 // to install a breakpoint
377 JvAssert (the_location != NULL);
379 ::java::util::Iterator *iter = breakpoints->iterator ();
380 while (iter->hasNext ())
383 = reinterpret_cast<EventRequest *> (iter->next ());
384 Location *loc = get_request_location (er);
385 JvAssert (loc != NULL);
386 if (loc->equals (the_location) && ++matches == 2)
388 // Short-circuit: already more than one breakpoint
395 using namespace gnu::classpath::jdwp::exception;
397 = JvNewStringLatin1 ("attempt to remove unknown breakpoint");
398 throw new JdwpInternalErrorException (msg);
401 jlong methodId = the_location->getMethod ()->getId ();
402 BreakpointManager::deleteBreakpoint (methodId,
403 the_location->getIndex ());
407 case EventRequest::EVENT_FRAME_POP:
410 case EventRequest::EVENT_EXCEPTION:
413 case EventRequest::EVENT_USER_DEFINED:
416 case EventRequest::EVENT_THREAD_START:
419 case EventRequest::EVENT_THREAD_END:
422 case EventRequest::EVENT_CLASS_PREPARE:
425 case EventRequest::EVENT_CLASS_LOAD:
428 case EventRequest::EVENT_CLASS_UNLOAD:
431 case EventRequest::EVENT_FIELD_ACCESS:
434 case EventRequest::EVENT_FIELD_MODIFY:
437 case EventRequest::EVENT_METHOD_ENTRY:
440 case EventRequest::EVENT_METHOD_EXIT:
443 case EventRequest::EVENT_VM_INIT:
446 case EventRequest::EVENT_VM_DEATH:
452 gnu::classpath::jdwp::VMVirtualMachine::clearEvents (MAYBE_UNUSED jbyte kind)
456 java::util::Collection *
457 gnu::classpath::jdwp::VMVirtualMachine::getAllLoadedClasses (void)
459 using namespace ::java::util;
460 return (Collection *) new ArrayList ();
464 gnu::classpath::jdwp::VMVirtualMachine::
465 getClassStatus (jclass klass)
468 jvmtiError err = _jdwp_jvmtiEnv->GetClassStatus (klass, &flags);
469 if (err != JVMTI_ERROR_NONE)
470 throw_jvmti_error (err);
472 using namespace gnu::classpath::jdwp::event;
474 if (flags & JVMTI_CLASS_STATUS_VERIFIED)
475 status |= ClassPrepareEvent::STATUS_VERIFIED;
476 if (flags & JVMTI_CLASS_STATUS_PREPARED)
477 status |= ClassPrepareEvent::STATUS_PREPARED;
478 if (flags & JVMTI_CLASS_STATUS_ERROR)
479 status |= ClassPrepareEvent::STATUS_ERROR;
480 if (flags & JVMTI_CLASS_STATUS_INITIALIZED)
481 status |= ClassPrepareEvent::STATUS_INITIALIZED;
486 JArray<gnu::classpath::jdwp::VMMethod *> *
487 gnu::classpath::jdwp::VMVirtualMachine::
488 getAllClassMethods (jclass klass)
492 jvmtiError err = _jdwp_jvmtiEnv->GetClassMethods (klass, &count, &methods);
493 if (err != JVMTI_ERROR_NONE)
494 throw_jvmti_error (err);
496 JArray<VMMethod *> *result
497 = (JArray<VMMethod *> *) JvNewObjectArray (count,
498 &VMMethod::class$, NULL);
499 VMMethod **rmeth = elements (result);
500 for (int i = 0; i < count; ++i)
502 jlong id = reinterpret_cast<jlong> (methods[i]);
503 rmeth[i] = getClassMethod (klass, id);
506 _jdwp_jvmtiEnv->Deallocate ((unsigned char *) methods);
510 gnu::classpath::jdwp::VMMethod *
511 gnu::classpath::jdwp::VMVirtualMachine::
512 getClassMethod (jclass klass, jlong id)
516 jvmtiError err = _jdwp_jvmtiEnv->GetClassMethods (klass, &count, &methods);
517 if (err != JVMTI_ERROR_NONE)
518 throw_jvmti_error (err);
520 jmethodID meth_id = reinterpret_cast<jmethodID> (id);
522 using namespace gnu::classpath::jdwp;
524 // Check if this method is defined for the given class and if so return a
525 // VMMethod representing it.
526 for (int i = 0; i < count; i++)
528 if (methods[i] == meth_id)
529 return new VMMethod (klass, reinterpret_cast<jlong> (meth_id));
532 throw new exception::InvalidMethodException (id);
535 java::util::ArrayList *
536 gnu::classpath::jdwp::VMVirtualMachine::getFrames (Thread *thread, jint start,
539 jint frame_count = getFrameCount (thread);
540 ::java::util::ArrayList *frame_list;
542 // Calculate the max number of frames to be returned.
543 jint num_frames = frame_count - start;
545 // Check if num_frames is valid.
549 // Check if there are more than length frames left after start.
550 // If length ios -1 return all remaining frames.
551 if (length != -1 && num_frames > length)
554 frame_list = new ::java::util::ArrayList (num_frames);
556 _Jv_Frame *vm_frame = reinterpret_cast<_Jv_Frame *> (thread->frame);
558 // Take start frames off the top of the stack
559 while (vm_frame != NULL && start > 0)
562 vm_frame = vm_frame->next;
565 // Use as a counter for the number of frames returned.
568 while (vm_frame != NULL && (num_frames < length || length == -1))
570 jlong frameId = reinterpret_cast<jlong> (vm_frame);
572 VMFrame *frame = getFrame (thread, frameId);
573 frame_list->add (frame);
574 vm_frame = vm_frame->next;
581 gnu::classpath::jdwp::VMFrame *
582 gnu::classpath::jdwp::VMVirtualMachine::
583 getFrame (Thread *thread, jlong frameID)
585 using namespace gnu::classpath::jdwp::exception;
587 _Jv_Frame *vm_frame = (_Jv_Frame *) thread->frame;
589 _Jv_Frame *frame = reinterpret_cast<_Jv_Frame *> (frameID);
591 // We need to find the stack depth of the frame, so search through the call
592 // stack to find it. This also checks for a valid frameID.
593 while (vm_frame != frame)
595 vm_frame = vm_frame->next;
597 if (vm_frame == NULL)
598 throw new InvalidFrameException (frameID);
601 Location *loc = NULL;
607 // Get the info for the frame of interest
608 jerr = _jdwp_jvmtiEnv->GetStackTrace (thread, depth, 1, &info, &num_frames);
610 if (jerr != JVMTI_ERROR_NONE)
611 throw_jvmti_error (jerr);
613 jerr = _jdwp_jvmtiEnv->GetMethodDeclaringClass (info.method, &klass);
615 if (jerr != JVMTI_ERROR_NONE)
616 throw_jvmti_error (jerr);
619 = getClassMethod (klass, reinterpret_cast<jlong> (info.method));
623 if (info.location == -1)
625 loc = new Location (meth, 0);
630 loc = new Location (meth, info.location);
631 _Jv_InterpFrame *iframe = reinterpret_cast<_Jv_InterpFrame *> (vm_frame);
632 this_obj = iframe->get_this_ptr ();
635 return new VMFrame (thread, reinterpret_cast<jlong> (vm_frame), loc,
640 gnu::classpath::jdwp::VMVirtualMachine::
641 getFrameCount (Thread *thread)
645 jvmtiError jerr = _jdwp_jvmtiEnv->GetFrameCount (thread, &frame_count);
647 if (jerr != JVMTI_ERROR_NONE)
648 throw_jvmti_error (jerr);
654 gnu::classpath::jdwp::VMVirtualMachine::
655 getThreadStatus (Thread *thread)
657 jint thr_state, status;
659 jvmtiError jerr = _jdwp_jvmtiEnv->GetThreadState (thread, &thr_state);
660 if (jerr != JVMTI_ERROR_NONE)
661 throw_jvmti_error (jerr);
663 if (thr_state & JVMTI_THREAD_STATE_SLEEPING)
664 status = gnu::classpath::jdwp::JdwpConstants$ThreadStatus::SLEEPING;
665 else if (thr_state & JVMTI_THREAD_STATE_RUNNABLE)
666 status = gnu::classpath::jdwp::JdwpConstants$ThreadStatus::RUNNING;
667 else if (thr_state & JVMTI_THREAD_STATE_WAITING)
669 if (thr_state & (JVMTI_THREAD_STATE_IN_OBJECT_WAIT
670 | JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER))
671 status = gnu::classpath::jdwp::JdwpConstants$ThreadStatus::MONITOR;
673 status = gnu::classpath::jdwp::JdwpConstants$ThreadStatus::WAIT;
677 // The thread is not SLEEPING, MONITOR, or WAIT. It may, however, be
678 // alive but not yet started.
679 if (!(thr_state & (JVMTI_THREAD_STATE_ALIVE
680 | JVMTI_THREAD_STATE_TERMINATED)))
681 status = gnu::classpath::jdwp::JdwpConstants$ThreadStatus::RUNNING;
682 status = gnu::classpath::jdwp::JdwpConstants$ThreadStatus::ZOMBIE;
688 java::util::ArrayList *
689 gnu::classpath::jdwp::VMVirtualMachine::
690 getLoadRequests (MAYBE_UNUSED ClassLoader *cl)
692 return new ::java::util::ArrayList ();
696 gnu::classpath::jdwp::VMVirtualMachine::
697 executeMethod (MAYBE_UNUSED jobject obj, MAYBE_UNUSED Thread *thread,
698 MAYBE_UNUSED jclass clazz, MAYBE_UNUSED VMMethod *method,
699 MAYBE_UNUSED JArray<value::Value *> *values,
700 MAYBE_UNUSED jint options)
706 gnu::classpath::jdwp::VMVirtualMachine::
707 getSourceFile (jclass clazz)
709 jstring file = _Jv_GetInterpClassSourceFile (clazz);
711 // Check if the source file was found.
713 throw new exception::AbsentInformationException (
714 _Jv_NewStringUTF("Source file not found"));
720 gnu::classpath::jdwp::VMVirtualMachine::
721 redefineClasses (MAYBE_UNUSED JArray<jclass> *types,
722 MAYBE_UNUSED JArray<jbyteArray> *bytecodes)
727 gnu::classpath::jdwp::VMVirtualMachine::
728 setDefaultStratum (MAYBE_UNUSED jstring stratum)
733 gnu::classpath::jdwp::VMVirtualMachine::
734 getSourceDebugExtension (MAYBE_UNUSED jclass klass)
740 gnu::classpath::jdwp::VMVirtualMachine::
741 getBytecodes (MAYBE_UNUSED gnu::classpath::jdwp::VMMethod *method)
746 gnu::classpath::jdwp::util::MonitorInfo *
747 gnu::classpath::jdwp::VMVirtualMachine::
748 getMonitorInfo (MAYBE_UNUSED jobject obj)
754 gnu::classpath::jdwp::VMVirtualMachine::
755 getOwnedMonitors (MAYBE_UNUSED ::java::lang::Thread *thread)
761 gnu::classpath::jdwp::VMVirtualMachine::
762 getCurrentContendedMonitor (MAYBE_UNUSED ::java::lang::Thread *thread)
768 gnu::classpath::jdwp::VMVirtualMachine::
769 popFrames (MAYBE_UNUSED ::java::lang::Thread *thread,
770 MAYBE_UNUSED jlong frameId)
774 // A simple caching function used while single-stepping
776 get_linetable (jvmtiEnv *env, jmethodID method, jint *count_ptr,
777 jvmtiLineNumberEntry **table_ptr)
779 static jint last_count = 0;
780 static jvmtiLineNumberEntry *last_table = NULL;
781 static jmethodID last_method = 0;
783 if (method == last_method)
785 *count_ptr = last_count;
786 *table_ptr = last_table;
787 return JVMTI_ERROR_NONE;
792 jvmtiLineNumberEntry *table;
793 err = env->GetLineNumberTable (method, &count, &table);
794 if (err != JVMTI_ERROR_NONE)
796 // Keep last table in cache
800 env->Deallocate ((unsigned char *) last_table);
801 last_table = *table_ptr = table;
802 last_count = *count_ptr = count;
803 return JVMTI_ERROR_NONE;
806 static gnu::classpath::jdwp::event::filters::StepFilter *
807 get_request_step_filter (EventRequest *request)
809 ::java::util::Collection *filters = request->getFilters ();
810 ::java::util::Iterator *iter = filters->iterator ();
811 filters::StepFilter *filter = NULL;
812 while (iter->hasNext ())
814 using namespace gnu::classpath::jdwp::event::filters;
815 IEventFilter *next = (IEventFilter *) iter->next ();
816 if (next->getClass () == &StepFilter::class$)
818 filter = reinterpret_cast<StepFilter *> (next);
827 get_request_location (EventRequest *request)
829 Location *loc = NULL;
830 ::java::util::Collection *filters = request->getFilters ();
831 ::java::util::Iterator *iter = filters->iterator ();
832 while (iter->hasNext ())
834 using namespace gnu::classpath::jdwp::event::filters;
835 IEventFilter *filter = (IEventFilter *) iter->next ();
836 if (filter->getClass () == &LocationOnlyFilter::class$)
838 LocationOnlyFilter *lof
839 = reinterpret_cast<LocationOnlyFilter *> (filter);
840 loc = lof->getLocation ();
848 handle_single_step (jvmtiEnv *env, struct step_info *sinfo, jthread thread,
849 jmethodID method, jlocation location)
851 using namespace gnu::classpath::jdwp;
853 if (sinfo == NULL || sinfo->size == JdwpConstants$StepSize::MIN)
856 goto send_notification;
860 // Check if we're on a new source line
861 /* This is a little inefficient when we're stepping OVER,
862 but this must be done when stepping INTO. */
864 jvmtiLineNumberEntry *table;
865 if (get_linetable (env, method, &count, &table) == JVMTI_ERROR_NONE)
868 for (i = 0; i < count; ++i)
870 if (table[i].start_location == location)
872 // This is the start of a new line -- stop
873 goto send_notification;
877 // Not at a new source line -- just keep stepping
882 /* Something went wrong: either "absent information"
883 or "out of memory" ("invalid method id" and "native
884 method" aren't possible -- those are validated before
885 single stepping is enabled).
887 Do what gdb does: just keep going. */
894 jvmtiError err = env->GetMethodDeclaringClass (method, &klass);
895 if (err != JVMTI_ERROR_NONE)
897 fprintf (stderr, "libgcj: internal error: could not find class for method while single stepping -- continuing\n");
901 VMMethod *vmmethod = new VMMethod (klass, reinterpret_cast<jlong> (method));
902 Location *loc = new Location (vmmethod, location);
903 _Jv_InterpFrame *iframe
904 = reinterpret_cast<_Jv_InterpFrame *> (thread->interp_frame);
905 JvAssert (iframe->frame_type == frame_interpreter);
906 jobject instance = iframe->get_this_ptr ();
907 event::SingleStepEvent *event
908 = new event::SingleStepEvent (thread, loc, instance);
910 // We only want to send the notification (and consequently
911 // suspend) if we are not about to execute a breakpoint.
912 _Jv_InterpMethod *im = reinterpret_cast<_Jv_InterpMethod *> (iframe->self);
913 if (im->breakpoint_at (location))
915 // Next insn is a breakpoint -- record event and
916 // wait for the JVMTI breakpoint notification to
917 // enforce a suspension policy.
918 VMVirtualMachine::_event_list->add (event);
922 // Next insn is not a breakpoint, so send notification
923 // and enforce the suspend policy.
924 Jdwp::notify (event);
929 throw_jvmti_error (jvmtiError err)
933 if (_jdwp_jvmtiEnv->GetErrorName (err, &error) == JVMTI_ERROR_NONE)
935 msg = JvNewStringLatin1 (error);
936 _jdwp_jvmtiEnv->Deallocate ((unsigned char *) error);
939 msg = JvNewStringLatin1 ("out of memory");
941 using namespace gnu::classpath::jdwp::exception;
942 throw new JdwpInternalErrorException (msg);
946 jdwpBreakpointCB (jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
947 jthread thread, jmethodID method, jlocation location)
951 err = env->GetMethodDeclaringClass (method, &klass);
952 JvAssert (err == JVMTI_ERROR_NONE);
954 using namespace gnu::classpath::jdwp;
955 using namespace gnu::classpath::jdwp::event;
957 jlong methodId = reinterpret_cast<jlong> (method);
958 VMMethod *meth = VMVirtualMachine::getClassMethod (klass, methodId);
959 Location *loc = new Location (meth, location);
960 _Jv_InterpFrame *iframe
961 = reinterpret_cast<_Jv_InterpFrame *> (thread->interp_frame);
962 JvAssert (iframe->frame_type == frame_interpreter);
963 jobject instance = iframe->get_this_ptr ();
964 BreakpointEvent *event = new BreakpointEvent (thread, loc, instance);
966 VMVirtualMachine::_event_list->add (event);
967 JArray<Event *> *events
968 = ((JArray<Event *> *)
969 JvNewObjectArray (VMVirtualMachine::_event_list->size (),
970 &Event::class$, NULL));
971 VMVirtualMachine::_event_list->toArray ((jobjectArray) events);
972 VMVirtualMachine::_event_list->clear ();
973 Jdwp::notify (events);
977 jdwpClassPrepareCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
978 jthread thread, jclass klass)
980 using namespace gnu::classpath::jdwp;
982 jint status = VMVirtualMachine::getClassStatus (klass);
983 event::ClassPrepareEvent *event
984 = new event::ClassPrepareEvent (thread, klass, status);
985 Jdwp::notify (event);
989 jdwpExceptionCB (jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env, jthread thread,
990 jmethodID method, jlocation location, jobject exception,
991 jmethodID catch_method, jlocation catch_location)
993 using namespace gnu::classpath::jdwp;
995 jvmtiError err = env->GetMethodDeclaringClass (method, &throw_klass);
996 if (err != JVMTI_ERROR_NONE)
998 fprintf (stderr, "libgcj: internal error: could not find class for ");
999 fprintf (stderr, "method throwing exception -- continuing\n");
1003 VMMethod *vmmethod = new VMMethod (throw_klass,
1004 reinterpret_cast<jlong> (method));
1005 Location *throw_loc = new Location (vmmethod, location);
1006 Location *catch_loc = NULL;
1007 if (catch_method == 0)
1008 catch_loc = Location::getEmptyLocation ();
1012 err = env->GetMethodDeclaringClass (catch_method, &catch_klass);
1013 if (err != JVMTI_ERROR_NONE)
1016 "libgcj: internal error: could not find class for ");
1018 "method catching exception -- ignoring\n");
1022 vmmethod = new VMMethod (catch_klass,
1023 reinterpret_cast<jlong> (catch_method));
1024 catch_loc = new Location (vmmethod, catch_location);
1028 _Jv_InterpFrame *iframe
1029 = reinterpret_cast<_Jv_InterpFrame *> (thread->interp_frame);
1030 jobject instance = (iframe == NULL) ? NULL : iframe->get_this_ptr ();
1031 Throwable *throwable = reinterpret_cast<Throwable *> (exception);
1032 event::ExceptionEvent *e = new ExceptionEvent (throwable, thread,
1033 throw_loc, catch_loc,
1034 throw_klass, instance);
1039 jdwpSingleStepCB (jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env, jthread thread,
1040 jmethodID method, jlocation location)
1043 gnu::classpath::jdwp::VMVirtualMachine::_stepping_threads->get (thread);
1044 struct step_info *sinfo = reinterpret_cast<struct step_info *> (si);
1048 // no step filter for this thread - simply report it
1049 handle_single_step (env, NULL, thread, method, location);
1053 // A step filter exists for this thread
1054 using namespace gnu::classpath::jdwp;
1056 _Jv_InterpFrame *frame
1057 = reinterpret_cast<_Jv_InterpFrame *> (thread->interp_frame);
1059 switch (sinfo->depth)
1061 case JdwpConstants$StepDepth::INTO:
1062 /* This is the easy case. We ignore the method and
1063 simply stop at either the next insn, or the next source
1065 handle_single_step (env, sinfo, thread, method, location);
1068 case JdwpConstants$StepDepth::OVER:
1069 /* This is also a pretty easy case. We just make sure that
1070 the methods are the same and that we are at the same
1071 stack depth, but we should also stop on the next
1072 insn/line if the stack depth is LESS THAN it was when
1073 we started stepping. */
1074 if (method == sinfo->method)
1076 // Still in the same method -- must be at same stack depth
1077 // to avoid confusion with recursive methods.
1078 if (frame->depth () == sinfo->stack_depth)
1079 handle_single_step (env, sinfo, thread, method, location);
1081 else if (frame->depth () < sinfo->stack_depth)
1083 // The method in which we were stepping was popped off
1084 // the stack. We simply need to stop at the next insn/line.
1085 handle_single_step (env, sinfo, thread, method, location);
1089 case JdwpConstants$StepDepth::OUT:
1090 // All we need to do is check the stack depth
1091 if (sinfo->stack_depth > frame->depth ())
1092 handle_single_step (env, sinfo, thread, method, location);
1096 /* This should not happen. The JDWP back-end should have
1097 validated the StepFilter. */
1099 "libgcj: unknown step depth while single stepping\n");
1106 jdwpThreadEndCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
1109 using namespace gnu::classpath::jdwp::event;
1111 ThreadEndEvent *e = new ThreadEndEvent (thread);
1112 gnu::classpath::jdwp::Jdwp::notify (e);
1116 jdwpThreadStartCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
1119 using namespace gnu::classpath::jdwp::event;
1121 ThreadStartEvent *e = new ThreadStartEvent (thread);
1122 gnu::classpath::jdwp::Jdwp::notify (e);
1126 jdwpVMDeathCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env)
1128 using namespace gnu::classpath::jdwp::event;
1129 gnu::classpath::jdwp::Jdwp::notify (new VmDeathEvent ());
1133 jdwpVMInitCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
1136 // The VM is now initialized, add our callbacks
1137 jvmtiEventCallbacks callbacks;
1138 DEFINE_CALLBACK (callbacks, Breakpoint);
1139 DEFINE_CALLBACK (callbacks, ClassPrepare);
1140 DEFINE_CALLBACK (callbacks, Exception);
1141 DEFINE_CALLBACK (callbacks, SingleStep);
1142 DEFINE_CALLBACK (callbacks, ThreadEnd);
1143 DEFINE_CALLBACK (callbacks, ThreadStart);
1144 DEFINE_CALLBACK (callbacks, VMDeath);
1145 _jdwp_jvmtiEnv->SetEventCallbacks (&callbacks, sizeof (callbacks));
1148 ENABLE_EVENT (BREAKPOINT, NULL);
1149 ENABLE_EVENT (CLASS_PREPARE, NULL);
1150 ENABLE_EVENT (EXCEPTION, NULL);
1151 // SingleStep is enabled only when needed
1152 ENABLE_EVENT (THREAD_END, NULL);
1153 ENABLE_EVENT (THREAD_START, NULL);
1154 ENABLE_EVENT (VM_DEATH, NULL);
1157 using namespace gnu::classpath::jdwp::event;
1158 gnu::classpath::jdwp::Jdwp::notify (new VmInitEvent (thread));