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/AbsentInformationException.h>
50 #include <gnu/classpath/jdwp/exception/InvalidFrameException.h>
51 #include <gnu/classpath/jdwp/exception/InvalidLocationException.h>
52 #include <gnu/classpath/jdwp/exception/InvalidMethodException.h>
53 #include <gnu/classpath/jdwp/exception/JdwpInternalErrorException.h>
54 #include <gnu/classpath/jdwp/id/ThreadId.h>
55 #include <gnu/classpath/jdwp/util/Location.h>
56 #include <gnu/classpath/jdwp/util/MethodResult.h>
57 #include <gnu/gcj/jvmti/Breakpoint.h>
58 #include <gnu/gcj/jvmti/BreakpointManager.h>
60 using namespace java::lang
;
61 using namespace gnu::classpath::jdwp::event
;
62 using namespace gnu::classpath::jdwp::util
;
64 // Stepping information
67 jint size
; // See gnu.classpath.jdwp.JdwpConstants.StepSize
68 jint depth
; // See gnu.classpath.jdwp.JdwpConstants.StepDepth
69 int stack_depth
; // stack depth at start of stepping
70 jmethodID method
; // method in which we are stepping
73 // Forward declarations
74 static jvmtiError
get_linetable (jvmtiEnv
*, jmethodID
, jint
*,
75 jvmtiLineNumberEntry
**);
76 static Location
*get_request_location (EventRequest
*);
77 static gnu::classpath::jdwp::event::filters::StepFilter
*
78 get_request_step_filter (EventRequest
*);
79 static void handle_single_step (jvmtiEnv
*, struct step_info
*, jthread
,
80 jmethodID
, jlocation
);
81 static void JNICALL
jdwpBreakpointCB (jvmtiEnv
*, JNIEnv
*, jthread
,
82 jmethodID
, jlocation
);
83 static void JNICALL
jdwpClassPrepareCB (jvmtiEnv
*, JNIEnv
*, jthread
, jclass
);
84 static void JNICALL
jdwpSingleStepCB (jvmtiEnv
*, JNIEnv
*, jthread
,
85 jmethodID
, jlocation
);
86 static void JNICALL
jdwpThreadEndCB (jvmtiEnv
*, JNIEnv
*, jthread
);
87 static void JNICALL
jdwpThreadStartCB (jvmtiEnv
*, JNIEnv
*, jthread
);
88 static void JNICALL
jdwpVMDeathCB (jvmtiEnv
*, JNIEnv
*);
89 static void JNICALL
jdwpVMInitCB (jvmtiEnv
*, JNIEnv
*, jthread
);
90 static void throw_jvmti_error (jvmtiError
);
92 #define DEFINE_CALLBACK(Cb,Event) Cb.Event = jdwp ## Event ## CB
93 #define DISABLE_EVENT(Event,Thread) \
94 _jdwp_jvmtiEnv->SetEventNotificationMode (JVMTI_DISABLE, \
95 JVMTI_EVENT_ ## Event, Thread)
96 #define ENABLE_EVENT(Event,Thread) \
97 _jdwp_jvmtiEnv->SetEventNotificationMode (JVMTI_ENABLE, \
98 JVMTI_EVENT_ ## Event, Thread)
100 static jvmtiEnv
*_jdwp_jvmtiEnv
;
103 _Jv_GetJDWP_JVMTIEnv (void)
105 return _jdwp_jvmtiEnv
;
109 gnu::classpath::jdwp::VMVirtualMachine::initialize ()
111 _jdwp_suspend_counts
= new ::java::util::Hashtable ();
112 _stepping_threads
= new ::java::util::Hashtable ();
114 JavaVM
*vm
= _Jv_GetJavaVM ();
120 vm
->GetEnv (&(foo
.ptr
), JVMTI_VERSION_1_0
);
121 _jdwp_jvmtiEnv
= foo
.env
;
123 // Wait for VM_INIT to do more initialization
124 jvmtiEventCallbacks callbacks
;
125 DEFINE_CALLBACK (callbacks
, VMInit
);
126 _jdwp_jvmtiEnv
->SetEventCallbacks (&callbacks
, sizeof (callbacks
));
127 ENABLE_EVENT (VM_INIT
, NULL
);
131 gnu::classpath::jdwp::VMVirtualMachine::suspendThread (Thread
*thread
)
136 JvSynchronize
dummy (_jdwp_suspend_counts
);
137 count
= reinterpret_cast<Integer
*> (_jdwp_suspend_counts
->get (thread
));
140 // New -- suspend thread
145 // Thread already suspended
146 value
= count
->intValue ();
149 count
= Integer::valueOf (++value
);
150 _jdwp_suspend_counts
->put (thread
, count
);
155 // Suspend the thread
156 jvmtiError err
= _jdwp_jvmtiEnv
->SuspendThread (thread
);
157 if (err
!= JVMTI_ERROR_NONE
)
159 using namespace gnu::gcj::runtime
;
160 using namespace gnu::classpath::jdwp::exception
;
162 _jdwp_jvmtiEnv
->GetErrorName (err
, &reason
);
163 String
*txt
= JvNewStringLatin1 ("could not suspend thread: ");
164 StringBuilder
*msg
= new StringBuilder (txt
);
165 msg
->append (JvNewStringLatin1 (reason
));
166 _jdwp_jvmtiEnv
->Deallocate ((unsigned char *) reason
);
167 throw new JdwpInternalErrorException (msg
->toString ());
173 gnu::classpath::jdwp::VMVirtualMachine::resumeThread (Thread
*thread
)
177 JvSynchronize
dummy (_jdwp_suspend_counts
);
179 = reinterpret_cast<Integer
*> (_jdwp_suspend_counts
->get (thread
));
182 // Thread not suspended: ThreadReference.Resume says to ignore it.
187 // Decrement suspend count
188 value
= count
->intValue () - 1;
193 // Thread will be resumed, remove from table
194 _jdwp_suspend_counts
->remove (thread
);
198 // Thread stays suspended: record new suspend count
199 count
= Integer::valueOf (value
);
200 _jdwp_suspend_counts
->put (thread
, count
);
206 jvmtiError err
= _jdwp_jvmtiEnv
->ResumeThread (thread
);
207 if (err
!= JVMTI_ERROR_NONE
)
209 using namespace gnu::gcj::runtime
;
210 using namespace gnu::classpath::jdwp::exception
;
212 _jdwp_jvmtiEnv
->GetErrorName (err
, &reason
);
213 String
*txt
= JvNewStringLatin1 ("could not resume thread: ");
214 StringBuilder
*msg
= new StringBuilder (txt
);
215 msg
->append (JvNewStringLatin1 (reason
));
216 _jdwp_jvmtiEnv
->Deallocate ((unsigned char *) reason
);
217 throw new JdwpInternalErrorException (msg
->toString ());
223 gnu::classpath::jdwp::VMVirtualMachine::getSuspendCount (Thread
*thread
)
225 jint suspensions
= 0;
227 = reinterpret_cast<Integer
*> (_jdwp_suspend_counts
->get (thread
));
229 suspensions
= count
->intValue ();
234 gnu::classpath::jdwp::VMVirtualMachine::registerEvent (EventRequest
*request
)
236 switch (request
->getEventKind ())
238 case EventRequest::EVENT_SINGLE_STEP
:
241 filters::StepFilter
*filter
= get_request_step_filter (request
);
244 // No filter specified: report every step in every
250 // Add stepping information to list of stepping threads
251 thread
= filter
->getThread ()->getThread ();
252 _Jv_InterpFrame
*frame
253 = reinterpret_cast<_Jv_InterpFrame
*> (thread
->interp_frame
);
254 struct step_info
*sinfo
255 = (struct step_info
*) JvAllocBytes (sizeof (struct step_info
));
256 sinfo
->size
= filter
->getSize ();
257 sinfo
->depth
= filter
->getDepth ();
258 sinfo
->stack_depth
= frame
->depth ();
259 sinfo
->method
= frame
->self
->get_method ();
260 _stepping_threads
->put (thread
, (jobject
) sinfo
);
263 ENABLE_EVENT (SINGLE_STEP
, thread
);
267 case EventRequest::EVENT_BREAKPOINT
:
269 using namespace ::gnu::gcj::jvmti
;
270 Location
*loc
= get_request_location (request
);
273 using namespace gnu::classpath::jdwp::exception
;
274 throw new InvalidLocationException ();
277 jlong method
= loc
->getMethod ()->getId ();
278 jlocation index
= loc
->getIndex ();
279 Breakpoint
*bp
= BreakpointManager::getBreakpoint (method
, index
);
282 // Breakpoint not in interpreter yet
283 bp
= BreakpointManager::newBreakpoint (method
, index
);
287 // Ignore the duplicate
292 case EventRequest::EVENT_FRAME_POP
:
295 case EventRequest::EVENT_EXCEPTION
:
298 case EventRequest::EVENT_USER_DEFINED
:
301 case EventRequest::EVENT_THREAD_START
:
304 case EventRequest::EVENT_THREAD_END
:
307 case EventRequest::EVENT_CLASS_PREPARE
:
310 case EventRequest::EVENT_CLASS_LOAD
:
313 case EventRequest::EVENT_CLASS_UNLOAD
:
316 case EventRequest::EVENT_FIELD_ACCESS
:
319 case EventRequest::EVENT_FIELD_MODIFY
:
322 case EventRequest::EVENT_METHOD_ENTRY
:
325 case EventRequest::EVENT_METHOD_EXIT
:
328 case EventRequest::EVENT_VM_INIT
:
331 case EventRequest::EVENT_VM_DEATH
:
337 gnu::classpath::jdwp::VMVirtualMachine::unregisterEvent (EventRequest
*request
)
339 switch (request
->getEventKind ())
341 case EventRequest::EVENT_SINGLE_STEP
:
344 filters::StepFilter
*filter
= get_request_step_filter (request
);
349 thread
= filter
->getThread ()->getThread ();
350 _stepping_threads
->remove (thread
);
353 DISABLE_EVENT (SINGLE_STEP
, thread
);
357 case EventRequest::EVENT_BREAKPOINT
:
359 using namespace gnu::gcj::jvmti
;
360 ::java::util::Collection
*breakpoints
;
361 EventManager
*em
= EventManager::getDefault ();
362 breakpoints
= em
->getRequests (EventRequest::EVENT_BREAKPOINT
);
364 // Check for duplicates
366 Location
*the_location
= get_request_location (request
);
368 // This should not be possible: we REQUIRE a Location
369 // to install a breakpoint
370 JvAssert (the_location
!= NULL
);
372 ::java::util::Iterator
*iter
= breakpoints
->iterator ();
373 while (iter
->hasNext ())
376 = reinterpret_cast<EventRequest
*> (iter
->next ());
377 Location
*loc
= get_request_location (er
);
378 JvAssert (loc
!= NULL
);
379 if (loc
->equals (the_location
) && ++matches
== 2)
381 // Short-circuit: already more than one breakpoint
388 using namespace gnu::classpath::jdwp::exception
;
390 = JvNewStringLatin1 ("attempt to remove unknown breakpoint");
391 throw new JdwpInternalErrorException (msg
);
394 jlong methodId
= the_location
->getMethod ()->getId ();
395 BreakpointManager::deleteBreakpoint (methodId
,
396 the_location
->getIndex ());
400 case EventRequest::EVENT_FRAME_POP
:
403 case EventRequest::EVENT_EXCEPTION
:
406 case EventRequest::EVENT_USER_DEFINED
:
409 case EventRequest::EVENT_THREAD_START
:
412 case EventRequest::EVENT_THREAD_END
:
415 case EventRequest::EVENT_CLASS_PREPARE
:
418 case EventRequest::EVENT_CLASS_LOAD
:
421 case EventRequest::EVENT_CLASS_UNLOAD
:
424 case EventRequest::EVENT_FIELD_ACCESS
:
427 case EventRequest::EVENT_FIELD_MODIFY
:
430 case EventRequest::EVENT_METHOD_ENTRY
:
433 case EventRequest::EVENT_METHOD_EXIT
:
436 case EventRequest::EVENT_VM_INIT
:
439 case EventRequest::EVENT_VM_DEATH
:
445 gnu::classpath::jdwp::VMVirtualMachine::clearEvents (MAYBE_UNUSED jbyte kind
)
449 java::util::Collection
*
450 gnu::classpath::jdwp::VMVirtualMachine::getAllLoadedClasses (void)
452 using namespace ::java::util
;
453 return (Collection
*) new ArrayList ();
457 gnu::classpath::jdwp::VMVirtualMachine::
458 getClassStatus (jclass klass
)
461 jvmtiError err
= _jdwp_jvmtiEnv
->GetClassStatus (klass
, &flags
);
462 if (err
!= JVMTI_ERROR_NONE
)
463 throw_jvmti_error (err
);
465 using namespace gnu::classpath::jdwp::event
;
467 if (flags
& JVMTI_CLASS_STATUS_VERIFIED
)
468 status
|= ClassPrepareEvent::STATUS_VERIFIED
;
469 if (flags
& JVMTI_CLASS_STATUS_PREPARED
)
470 status
|= ClassPrepareEvent::STATUS_PREPARED
;
471 if (flags
& JVMTI_CLASS_STATUS_ERROR
)
472 status
|= ClassPrepareEvent::STATUS_ERROR
;
473 if (flags
& JVMTI_CLASS_STATUS_INITIALIZED
)
474 status
|= ClassPrepareEvent::STATUS_INITIALIZED
;
479 JArray
<gnu::classpath::jdwp::VMMethod
*> *
480 gnu::classpath::jdwp::VMVirtualMachine::
481 getAllClassMethods (jclass klass
)
485 jvmtiError err
= _jdwp_jvmtiEnv
->GetClassMethods (klass
, &count
, &methods
);
486 if (err
!= JVMTI_ERROR_NONE
)
487 throw_jvmti_error (err
);
489 JArray
<VMMethod
*> *result
490 = (JArray
<VMMethod
*> *) JvNewObjectArray (count
,
491 &VMMethod::class$
, NULL
);
492 VMMethod
**rmeth
= elements (result
);
493 for (int i
= 0; i
< count
; ++i
)
495 jlong id
= reinterpret_cast<jlong
> (methods
[i
]);
496 rmeth
[i
] = getClassMethod (klass
, id
);
499 _jdwp_jvmtiEnv
->Deallocate ((unsigned char *) methods
);
503 gnu::classpath::jdwp::VMMethod
*
504 gnu::classpath::jdwp::VMVirtualMachine::
505 getClassMethod (jclass klass
, jlong id
)
507 jmethodID method
= reinterpret_cast<jmethodID
> (id
);
508 _Jv_MethodBase
*bmeth
= _Jv_FindInterpreterMethod (klass
, method
);
510 return new gnu::classpath::jdwp::VMMethod (klass
, id
);
512 throw new gnu::classpath::jdwp::exception::InvalidMethodException (id
);
515 java::util::ArrayList
*
516 gnu::classpath::jdwp::VMVirtualMachine::getFrames (Thread
*thread
, jint start
,
519 jint frame_count
= getFrameCount (thread
);
520 ::java::util::ArrayList
*frame_list
;
522 // Calculate the max number of frames to be returned.
523 jint num_frames
= frame_count
- start
;
525 // Check if num_frames is valid.
529 // Check if there are more than length frames left after start.
530 // If length ios -1 return all remaining frames.
531 if (length
!= -1 && num_frames
> length
)
534 frame_list
= new ::java::util::ArrayList (num_frames
);
536 _Jv_Frame
*vm_frame
= reinterpret_cast<_Jv_Frame
*> (thread
->frame
);
538 // Take start frames off the top of the stack
539 while (vm_frame
!= NULL
&& start
> 0)
542 vm_frame
= vm_frame
->next
;
545 // Use as a counter for the number of frames returned.
548 while (vm_frame
!= NULL
&& (num_frames
< length
|| length
== -1))
550 jlong frameId
= reinterpret_cast<jlong
> (vm_frame
);
552 VMFrame
*frame
= getFrame (thread
, frameId
);
553 frame_list
->add (frame
);
554 vm_frame
= vm_frame
->next
;
561 gnu::classpath::jdwp::VMFrame
*
562 gnu::classpath::jdwp::VMVirtualMachine::
563 getFrame (Thread
*thread
, jlong frameID
)
565 using namespace gnu::classpath::jdwp::exception
;
567 _Jv_Frame
*vm_frame
= (_Jv_Frame
*) thread
->frame
;
569 _Jv_Frame
*frame
= reinterpret_cast<_Jv_Frame
*> (frameID
);
571 // We need to find the stack depth of the frame, so search through the call
572 // stack to find it. This also checks for a valid frameID.
573 while (vm_frame
!= frame
)
575 vm_frame
= vm_frame
->next
;
577 if (vm_frame
== NULL
)
578 throw new InvalidFrameException (frameID
);
581 Location
*loc
= NULL
;
587 // Get the info for the frame of interest
588 jerr
= _jdwp_jvmtiEnv
->GetStackTrace (thread
, depth
, 1, &info
, &num_frames
);
590 if (jerr
!= JVMTI_ERROR_NONE
)
591 throw_jvmti_error (jerr
);
593 jerr
= _jdwp_jvmtiEnv
->GetMethodDeclaringClass (info
.method
, &klass
);
595 if (jerr
!= JVMTI_ERROR_NONE
)
596 throw_jvmti_error (jerr
);
599 = getClassMethod (klass
, reinterpret_cast<jlong
> (info
.method
));
601 if (info
.location
== -1)
602 loc
= new Location (meth
, 0);
604 loc
= new Location (meth
, info
.location
);
606 return new VMFrame (thread
, reinterpret_cast<jlong
> (vm_frame
), loc
);
610 gnu::classpath::jdwp::VMVirtualMachine::
611 getFrameCount (Thread
*thread
)
615 jvmtiError jerr
= _jdwp_jvmtiEnv
->GetFrameCount (thread
, &frame_count
);
617 if (jerr
!= JVMTI_ERROR_NONE
)
618 throw_jvmti_error (jerr
);
624 gnu::classpath::jdwp::VMVirtualMachine::
625 getThreadStatus (MAYBE_UNUSED Thread
*thread
)
630 java::util::ArrayList
*
631 gnu::classpath::jdwp::VMVirtualMachine::
632 getLoadRequests (MAYBE_UNUSED ClassLoader
*cl
)
634 return new ::java::util::ArrayList ();
638 gnu::classpath::jdwp::VMVirtualMachine::
639 executeMethod (MAYBE_UNUSED jobject obj
, MAYBE_UNUSED Thread
*thread
,
640 MAYBE_UNUSED jclass clazz
, MAYBE_UNUSED
reflect::Method
*method
,
641 MAYBE_UNUSED jobjectArray values
,
642 MAYBE_UNUSED jboolean nonVirtual
)
648 gnu::classpath::jdwp::VMVirtualMachine::
649 getSourceFile (jclass clazz
)
651 jstring file
= _Jv_GetInterpClassSourceFile (clazz
);
653 // Check if the source file was found.
655 throw new exception::AbsentInformationException (
656 _Jv_NewStringUTF("Source file not found"));
662 gnu::classpath::jdwp::VMVirtualMachine::
663 redefineClasses (MAYBE_UNUSED JArray
<jclass
> *types
,
664 MAYBE_UNUSED JArray
<jbyteArray
> *bytecodes
)
669 gnu::classpath::jdwp::VMVirtualMachine::
670 setDefaultStratum (MAYBE_UNUSED jstring stratum
)
675 gnu::classpath::jdwp::VMVirtualMachine::
676 getSourceDebugExtension (MAYBE_UNUSED jclass klass
)
682 gnu::classpath::jdwp::VMVirtualMachine::
683 getBytecodes (MAYBE_UNUSED
gnu::classpath::jdwp::VMMethod
*method
)
688 gnu::classpath::jdwp::util::MonitorInfo
*
689 gnu::classpath::jdwp::VMVirtualMachine::
690 getMonitorInfo (MAYBE_UNUSED jobject obj
)
696 gnu::classpath::jdwp::VMVirtualMachine::
697 getOwnedMonitors (MAYBE_UNUSED ::java::lang::Thread
*thread
)
703 gnu::classpath::jdwp::VMVirtualMachine::
704 getCurrentContendedMonitor (MAYBE_UNUSED ::java::lang::Thread
*thread
)
710 gnu::classpath::jdwp::VMVirtualMachine::
711 popFrames (MAYBE_UNUSED ::java::lang::Thread
*thread
,
712 MAYBE_UNUSED jlong frameId
)
716 // A simple caching function used while single-stepping
718 get_linetable (jvmtiEnv
*env
, jmethodID method
, jint
*count_ptr
,
719 jvmtiLineNumberEntry
**table_ptr
)
721 static jint last_count
= 0;
722 static jvmtiLineNumberEntry
*last_table
= NULL
;
723 static jmethodID last_method
= 0;
725 if (method
== last_method
)
727 *count_ptr
= last_count
;
728 *table_ptr
= last_table
;
729 return JVMTI_ERROR_NONE
;
734 jvmtiLineNumberEntry
*table
;
735 err
= env
->GetLineNumberTable (method
, &count
, &table
);
736 if (err
!= JVMTI_ERROR_NONE
)
738 // Keep last table in cache
742 env
->Deallocate ((unsigned char *) last_table
);
743 last_table
= *table_ptr
= table
;
744 last_count
= *count_ptr
= count
;
745 return JVMTI_ERROR_NONE
;
748 static gnu::classpath::jdwp::event::filters::StepFilter
*
749 get_request_step_filter (EventRequest
*request
)
751 ::java::util::Collection
*filters
= request
->getFilters ();
752 ::java::util::Iterator
*iter
= filters
->iterator ();
753 filters::StepFilter
*filter
= NULL
;
754 while (iter
->hasNext ())
756 using namespace gnu::classpath::jdwp::event::filters
;
757 IEventFilter
*next
= (IEventFilter
*) iter
->next ();
758 if (next
->getClass () == &StepFilter::class$
)
760 filter
= reinterpret_cast<StepFilter
*> (next
);
769 get_request_location (EventRequest
*request
)
771 Location
*loc
= NULL
;
772 ::java::util::Collection
*filters
= request
->getFilters ();
773 ::java::util::Iterator
*iter
= filters
->iterator ();
774 while (iter
->hasNext ())
776 using namespace gnu::classpath::jdwp::event::filters
;
777 IEventFilter
*filter
= (IEventFilter
*) iter
->next ();
778 if (filter
->getClass () == &LocationOnlyFilter::class$
)
780 LocationOnlyFilter
*lof
781 = reinterpret_cast<LocationOnlyFilter
*> (filter
);
782 loc
= lof
->getLocation ();
790 handle_single_step (jvmtiEnv
*env
, struct step_info
*sinfo
, jthread thread
,
791 jmethodID method
, jlocation location
)
793 using namespace gnu::classpath::jdwp
;
795 if (sinfo
== NULL
|| sinfo
->size
== JdwpConstants$
StepSize::MIN
)
798 goto send_notification
;
802 // Check if we're on a new source line
803 /* This is a little inefficient when we're stepping OVER,
804 but this must be done when stepping INTO. */
806 jvmtiLineNumberEntry
*table
;
807 if (get_linetable (env
, method
, &count
, &table
) == JVMTI_ERROR_NONE
)
810 for (i
= 0; i
< count
; ++i
)
812 if (table
[i
].start_location
== location
)
814 // This is the start of a new line -- stop
815 goto send_notification
;
819 // Not at a new source line -- just keep stepping
824 /* Something went wrong: either "absent information"
825 or "out of memory" ("invalid method id" and "native
826 method" aren't possible -- those are validated before
827 single stepping is enabled).
829 Do what gdb does: just keep going. */
836 jvmtiError err
= env
->GetMethodDeclaringClass (method
, &klass
);
837 if (err
!= JVMTI_ERROR_NONE
)
839 fprintf (stderr
, "libgcj: internal error: could not find class for method while single stepping -- continuing\n");
843 VMMethod
*vmmethod
= new VMMethod (klass
, reinterpret_cast<jlong
> (method
));
844 Location
*loc
= new Location (vmmethod
, location
);
845 JvAssert (thread
->frame
.frame_type
== frame_interpreter
);
846 _Jv_InterpFrame
*iframe
847 = reinterpret_cast<_Jv_InterpFrame
*> (thread
->interp_frame
);
848 jobject instance
= iframe
->get_this_ptr ();
849 event::SingleStepEvent
*event
850 = new event::SingleStepEvent (thread
, loc
, instance
);
851 Jdwp::notify (event
);
855 throw_jvmti_error (jvmtiError err
)
859 if (_jdwp_jvmtiEnv
->GetErrorName (err
, &error
) == JVMTI_ERROR_NONE
)
861 msg
= JvNewStringLatin1 (error
);
862 _jdwp_jvmtiEnv
->Deallocate ((unsigned char *) error
);
865 msg
= JvNewStringLatin1 ("out of memory");
867 using namespace gnu::classpath::jdwp::exception
;
868 throw new JdwpInternalErrorException (msg
);
872 jdwpBreakpointCB (jvmtiEnv
*env
, MAYBE_UNUSED JNIEnv
*jni_env
,
873 jthread thread
, jmethodID method
, jlocation location
)
877 err
= env
->GetMethodDeclaringClass (method
, &klass
);
878 JvAssert (err
== JVMTI_ERROR_NONE
);
880 using namespace gnu::classpath::jdwp
;
882 jlong methodId
= reinterpret_cast<jlong
> (method
);
883 VMMethod
*meth
= VMVirtualMachine::getClassMethod (klass
, methodId
);
884 Location
*loc
= new Location (meth
, location
);
885 JvAssert (thread
->frame
.frame_type
== frame_interpreter
);
886 _Jv_InterpFrame
*iframe
887 = reinterpret_cast<_Jv_InterpFrame
*> (thread
->interp_frame
);
888 jobject instance
= iframe
->get_this_ptr ();
889 event::BreakpointEvent
*event
890 = new event::BreakpointEvent (thread
, loc
, instance
);
891 Jdwp::notify (event
);
895 jdwpClassPrepareCB (MAYBE_UNUSED jvmtiEnv
*env
, MAYBE_UNUSED JNIEnv
*jni_env
,
896 jthread thread
, jclass klass
)
898 using namespace gnu::classpath::jdwp
;
900 jint status
= VMVirtualMachine::getClassStatus (klass
);
901 event::ClassPrepareEvent
*event
902 = new event::ClassPrepareEvent (thread
, klass
, status
);
903 Jdwp::notify (event
);
907 jdwpSingleStepCB (jvmtiEnv
*env
, JNIEnv
*jni_env
, jthread thread
,
908 jmethodID method
, jlocation location
)
911 gnu::classpath::jdwp::VMVirtualMachine::_stepping_threads
->get (thread
);
912 struct step_info
*sinfo
= reinterpret_cast<struct step_info
*> (si
);
916 // no step filter for this thread - simply report it
917 handle_single_step (env
, NULL
, thread
, method
, location
);
921 // A step filter exists for this thread
922 using namespace gnu::classpath::jdwp
;
924 _Jv_InterpFrame
*frame
925 = reinterpret_cast<_Jv_InterpFrame
*> (thread
->interp_frame
);
927 switch (sinfo
->depth
)
929 case JdwpConstants$
StepDepth::INTO
:
930 /* This is the easy case. We ignore the method and
931 simply stop at either the next insn, or the next source
933 handle_single_step (env
, sinfo
, thread
, method
, location
);
936 case JdwpConstants$
StepDepth::OVER
:
937 /* This is also a pretty easy case. We just make sure that
938 the methods are the same and that we are at the same
939 stack depth, but we should also stop on the next
940 insn/line if the stack depth is LESS THAN it was when
941 we started stepping. */
942 if (method
== sinfo
->method
)
944 // Still in the same method -- must be at same stack depth
945 // to avoid confusion with recursive methods.
946 if (frame
->depth () == sinfo
->stack_depth
)
947 handle_single_step (env
, sinfo
, thread
, method
, location
);
949 else if (frame
->depth () < sinfo
->stack_depth
)
951 // The method in which we were stepping was popped off
952 // the stack. We simply need to stop at the next insn/line.
953 handle_single_step (env
, sinfo
, thread
, method
, location
);
957 case JdwpConstants$
StepDepth::OUT
:
958 // All we need to do is check the stack depth
959 if (sinfo
->stack_depth
> frame
->depth ())
960 handle_single_step (env
, sinfo
, thread
, method
, location
);
964 /* This should not happen. The JDWP back-end should have
965 validated the StepFilter. */
967 "libgcj: unknown step depth while single stepping\n");
974 jdwpThreadEndCB (MAYBE_UNUSED jvmtiEnv
*env
, MAYBE_UNUSED JNIEnv
*jni_env
,
977 using namespace gnu::classpath::jdwp::event
;
979 ThreadEndEvent
*e
= new ThreadEndEvent (thread
);
980 gnu::classpath::jdwp::Jdwp::notify (e
);
984 jdwpThreadStartCB (MAYBE_UNUSED jvmtiEnv
*env
, MAYBE_UNUSED JNIEnv
*jni_env
,
987 using namespace gnu::classpath::jdwp::event
;
989 ThreadStartEvent
*e
= new ThreadStartEvent (thread
);
990 gnu::classpath::jdwp::Jdwp::notify (e
);
994 jdwpVMDeathCB (MAYBE_UNUSED jvmtiEnv
*env
, MAYBE_UNUSED JNIEnv
*jni_env
)
996 using namespace gnu::classpath::jdwp::event
;
997 gnu::classpath::jdwp::Jdwp::notify (new VmDeathEvent ());
1001 jdwpVMInitCB (MAYBE_UNUSED jvmtiEnv
*env
, MAYBE_UNUSED JNIEnv
*jni_env
,
1004 // The VM is now initialized, add our callbacks
1005 jvmtiEventCallbacks callbacks
;
1006 DEFINE_CALLBACK (callbacks
, Breakpoint
);
1007 DEFINE_CALLBACK (callbacks
, ClassPrepare
);
1008 DEFINE_CALLBACK (callbacks
, SingleStep
);
1009 DEFINE_CALLBACK (callbacks
, ThreadEnd
);
1010 DEFINE_CALLBACK (callbacks
, ThreadStart
);
1011 DEFINE_CALLBACK (callbacks
, VMDeath
);
1012 _jdwp_jvmtiEnv
->SetEventCallbacks (&callbacks
, sizeof (callbacks
));
1015 ENABLE_EVENT (BREAKPOINT
, NULL
);
1016 ENABLE_EVENT (CLASS_PREPARE
, NULL
);
1017 // SingleStep is enabled only when needed
1018 ENABLE_EVENT (THREAD_END
, NULL
);
1019 ENABLE_EVENT (THREAD_START
, NULL
);
1020 ENABLE_EVENT (VM_DEATH
, NULL
);
1023 using namespace gnu::classpath::jdwp::event
;
1024 gnu::classpath::jdwp::Jdwp::notify (new VmInitEvent (thread
));