2015-01-14 Richard Biener <rguenther@suse.de>
[official-gcc.git] / libjava / gnu / classpath / jdwp / natVMVirtualMachine.cc
blob7bd300b79c8a9a9f39e9661c1fafbdec6d27e890
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
9 details. */
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>
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
68 struct step_info
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)
105 // JVMTI environment
106 static jvmtiEnv *_jdwp_jvmtiEnv;
108 jvmtiEnv *
109 _Jv_GetJDWP_JVMTIEnv (void)
111 return _jdwp_jvmtiEnv;
114 void
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 ();
122 union
124 void *ptr;
125 jvmtiEnv *env;
126 } foo;
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);
137 void
138 gnu::classpath::jdwp::VMVirtualMachine::suspendThread (Thread *thread)
140 jint value;
141 Integer *count;
143 JvSynchronize dummy (_jdwp_suspend_counts);
144 count = reinterpret_cast<Integer *> (_jdwp_suspend_counts->get (thread));
145 if (count == NULL)
147 // New -- suspend thread
148 value = 0;
150 else
152 // Thread already suspended
153 value = count->intValue ();
156 count = Integer::valueOf (++value);
157 _jdwp_suspend_counts->put (thread, count);
160 if (value == 1)
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;
168 char *reason;
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 ());
179 void
180 gnu::classpath::jdwp::VMVirtualMachine::resumeThread (Thread *thread)
182 jint value;
184 JvSynchronize dummy (_jdwp_suspend_counts);
185 Integer *count
186 = reinterpret_cast<Integer *> (_jdwp_suspend_counts->get (thread));
187 if (count == NULL)
189 // Thread not suspended: ThreadReference.Resume says to ignore it.
190 return;
192 else
194 // Decrement suspend count
195 value = count->intValue () - 1;
198 if (value == 0)
200 // Thread will be resumed, remove from table
201 _jdwp_suspend_counts->remove (thread);
203 else
205 // Thread stays suspended: record new suspend count
206 count = Integer::valueOf (value);
207 _jdwp_suspend_counts->put (thread, count);
211 if (value == 0)
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;
218 char *reason;
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 ());
229 jint
230 gnu::classpath::jdwp::VMVirtualMachine::getSuspendCount (Thread *thread)
232 jint suspensions = 0;
233 Integer *count
234 = reinterpret_cast<Integer *> (_jdwp_suspend_counts->get (thread));
235 if (count != NULL)
236 suspensions = count->intValue ();
237 return suspensions;
240 void
241 gnu::classpath::jdwp::VMVirtualMachine::registerEvent (EventRequest *request)
243 switch (request->getEventKind ())
245 case EventRequest::EVENT_SINGLE_STEP:
247 Thread *thread;
248 filters::StepFilter *filter = get_request_step_filter (request);
249 if (filter == NULL)
251 // No filter specified: report every step in every
252 // thread.
253 thread = NULL;
255 else
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);
272 break;
274 case EventRequest::EVENT_BREAKPOINT:
276 using namespace ::gnu::gcj::jvmti;
277 Location *loc = get_request_location (request);
278 if (loc == NULL)
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);
287 if (bp == NULL)
289 // Breakpoint not in interpreter yet
290 bp = BreakpointManager::newBreakpoint (method, index);
292 else
294 // Ignore the duplicate
297 break;
299 case EventRequest::EVENT_FRAME_POP:
300 break;
302 case EventRequest::EVENT_EXCEPTION:
303 break;
305 case EventRequest::EVENT_USER_DEFINED:
306 break;
308 case EventRequest::EVENT_THREAD_START:
309 break;
311 case EventRequest::EVENT_THREAD_END:
312 break;
314 case EventRequest::EVENT_CLASS_PREPARE:
315 break;
317 case EventRequest::EVENT_CLASS_LOAD:
318 break;
320 case EventRequest::EVENT_CLASS_UNLOAD:
321 break;
323 case EventRequest::EVENT_FIELD_ACCESS:
324 break;
326 case EventRequest::EVENT_FIELD_MODIFY:
327 break;
329 case EventRequest::EVENT_METHOD_ENTRY:
330 break;
332 case EventRequest::EVENT_METHOD_EXIT:
333 break;
335 case EventRequest::EVENT_VM_INIT:
336 break;
338 case EventRequest::EVENT_VM_DEATH:
339 break;
343 void
344 gnu::classpath::jdwp::VMVirtualMachine::unregisterEvent (EventRequest *request)
346 switch (request->getEventKind ())
348 case EventRequest::EVENT_SINGLE_STEP:
350 Thread *thread;
351 filters::StepFilter *filter = get_request_step_filter (request);
352 if (filter == NULL)
353 thread = NULL;
354 else
356 thread = filter->getThread ()->getThread ();
357 _stepping_threads->remove (thread);
360 DISABLE_EVENT (SINGLE_STEP, thread);
362 break;
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
372 int matches = 0;
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 ())
382 EventRequest *er
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
389 return;
393 if (matches == 0)
395 using namespace gnu::classpath::jdwp::exception;
396 jstring msg
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 ());
405 break;
407 case EventRequest::EVENT_FRAME_POP:
408 break;
410 case EventRequest::EVENT_EXCEPTION:
411 break;
413 case EventRequest::EVENT_USER_DEFINED:
414 break;
416 case EventRequest::EVENT_THREAD_START:
417 break;
419 case EventRequest::EVENT_THREAD_END:
420 break;
422 case EventRequest::EVENT_CLASS_PREPARE:
423 break;
425 case EventRequest::EVENT_CLASS_LOAD:
426 break;
428 case EventRequest::EVENT_CLASS_UNLOAD:
429 break;
431 case EventRequest::EVENT_FIELD_ACCESS:
432 break;
434 case EventRequest::EVENT_FIELD_MODIFY:
435 break;
437 case EventRequest::EVENT_METHOD_ENTRY:
438 break;
440 case EventRequest::EVENT_METHOD_EXIT:
441 break;
443 case EventRequest::EVENT_VM_INIT:
444 break;
446 case EventRequest::EVENT_VM_DEATH:
447 break;
451 void
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 ();
463 jint
464 gnu::classpath::jdwp::VMVirtualMachine::
465 getClassStatus (jclass klass)
467 jint flags = 0;
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;
473 jint status = 0;
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;
483 return status;
486 JArray<gnu::classpath::jdwp::VMMethod *> *
487 gnu::classpath::jdwp::VMVirtualMachine::
488 getAllClassMethods (jclass klass)
490 jint count;
491 jmethodID *methods;
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);
507 return result;
510 gnu::classpath::jdwp::VMMethod *
511 gnu::classpath::jdwp::VMVirtualMachine::
512 getClassMethod (jclass klass, jlong id)
514 jint count;
515 jmethodID *methods;
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,
537 jint length)
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.
546 if (num_frames < 0)
547 num_frames = 0;
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)
552 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)
561 start--;
562 vm_frame = vm_frame->next;
565 // Use as a counter for the number of frames returned.
566 num_frames = 0;
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;
575 num_frames++;
578 return frame_list;
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;
588 jint depth = 0;
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;
596 depth++;
597 if (vm_frame == NULL)
598 throw new InvalidFrameException (frameID);
601 Location *loc = NULL;
602 jvmtiFrameInfo info;
603 jvmtiError jerr;
604 jint num_frames;
605 jclass klass;
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);
618 VMMethod *meth
619 = getClassMethod (klass, reinterpret_cast<jlong> (info.method));
621 jobject this_obj;
623 if (info.location == -1)
625 loc = new Location (meth, 0);
626 this_obj = NULL;
628 else
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,
636 this_obj);
639 jint
640 gnu::classpath::jdwp::VMVirtualMachine::
641 getFrameCount (Thread *thread)
643 jint frame_count;
645 jvmtiError jerr = _jdwp_jvmtiEnv->GetFrameCount (thread, &frame_count);
647 if (jerr != JVMTI_ERROR_NONE)
648 throw_jvmti_error (jerr);
650 return frame_count;
653 jint
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;
672 else
673 status = gnu::classpath::jdwp::JdwpConstants$ThreadStatus::WAIT;
675 else
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;
685 return status;
688 java::util::ArrayList *
689 gnu::classpath::jdwp::VMVirtualMachine::
690 getLoadRequests (MAYBE_UNUSED ClassLoader *cl)
692 return new ::java::util::ArrayList ();
695 MethodResult *
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)
702 return NULL;
705 jstring
706 gnu::classpath::jdwp::VMVirtualMachine::
707 getSourceFile (jclass clazz)
709 jstring file = _Jv_GetInterpClassSourceFile (clazz);
711 // Check if the source file was found.
712 if (file == NULL)
713 throw new exception::AbsentInformationException (
714 _Jv_NewStringUTF("Source file not found"));
716 return file;
719 void
720 gnu::classpath::jdwp::VMVirtualMachine::
721 redefineClasses (MAYBE_UNUSED JArray<jclass> *types,
722 MAYBE_UNUSED JArray<jbyteArray> *bytecodes)
726 void
727 gnu::classpath::jdwp::VMVirtualMachine::
728 setDefaultStratum (MAYBE_UNUSED jstring stratum)
732 jstring
733 gnu::classpath::jdwp::VMVirtualMachine::
734 getSourceDebugExtension (MAYBE_UNUSED jclass klass)
736 return NULL;
739 jbyteArray
740 gnu::classpath::jdwp::VMVirtualMachine::
741 getBytecodes (MAYBE_UNUSED gnu::classpath::jdwp::VMMethod *method)
743 return NULL;
746 gnu::classpath::jdwp::util::MonitorInfo *
747 gnu::classpath::jdwp::VMVirtualMachine::
748 getMonitorInfo (MAYBE_UNUSED jobject obj)
750 return NULL;
753 jobjectArray
754 gnu::classpath::jdwp::VMVirtualMachine::
755 getOwnedMonitors (MAYBE_UNUSED ::java::lang::Thread *thread)
757 return NULL;
760 jobject
761 gnu::classpath::jdwp::VMVirtualMachine::
762 getCurrentContendedMonitor (MAYBE_UNUSED ::java::lang::Thread *thread)
764 return NULL;
767 void
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
775 static jvmtiError
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;
790 jvmtiError err;
791 jint count;
792 jvmtiLineNumberEntry *table;
793 err = env->GetLineNumberTable (method, &count, &table);
794 if (err != JVMTI_ERROR_NONE)
796 // Keep last table in cache
797 return err;
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);
819 break;
823 return filter;
826 static Location *
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 ();
844 return loc;
847 static void
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)
855 // Stop now
856 goto send_notification;
858 else
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. */
863 jint count;
864 jvmtiLineNumberEntry *table;
865 if (get_linetable (env, method, &count, &table) == JVMTI_ERROR_NONE)
867 jint i;
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
878 return;
880 else
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. */
888 return;
892 send_notification:
893 jclass klass;
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");
898 return;
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);
920 else
922 // Next insn is not a breakpoint, so send notification
923 // and enforce the suspend policy.
924 Jdwp::notify (event);
928 static void
929 throw_jvmti_error (jvmtiError err)
931 char *error;
932 jstring msg;
933 if (_jdwp_jvmtiEnv->GetErrorName (err, &error) == JVMTI_ERROR_NONE)
935 msg = JvNewStringLatin1 (error);
936 _jdwp_jvmtiEnv->Deallocate ((unsigned char *) error);
938 else
939 msg = JvNewStringLatin1 ("out of memory");
941 using namespace gnu::classpath::jdwp::exception;
942 throw new JdwpInternalErrorException (msg);
945 static void JNICALL
946 jdwpBreakpointCB (jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
947 jthread thread, jmethodID method, jlocation location)
949 jclass klass;
950 jvmtiError err;
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);
976 static void JNICALL
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);
988 static void JNICALL
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;
994 jclass throw_klass;
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");
1000 return;
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 ();
1009 else
1011 jclass catch_klass;
1012 err = env->GetMethodDeclaringClass (catch_method, &catch_klass);
1013 if (err != JVMTI_ERROR_NONE)
1015 fprintf (stderr,
1016 "libgcj: internal error: could not find class for ");
1017 fprintf (stderr,
1018 "method catching exception -- ignoring\n");
1020 else
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);
1035 Jdwp::notify (e);
1038 static void JNICALL
1039 jdwpSingleStepCB (jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env, jthread thread,
1040 jmethodID method, jlocation location)
1042 jobject si =
1043 gnu::classpath::jdwp::VMVirtualMachine::_stepping_threads->get (thread);
1044 struct step_info *sinfo = reinterpret_cast<struct step_info *> (si);
1046 if (sinfo == NULL)
1048 // no step filter for this thread - simply report it
1049 handle_single_step (env, NULL, thread, method, location);
1051 else
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
1064 line. */
1065 handle_single_step (env, sinfo, thread, method, location);
1066 break;
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);
1087 break;
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);
1093 break;
1095 default:
1096 /* This should not happen. The JDWP back-end should have
1097 validated the StepFilter. */
1098 fprintf (stderr,
1099 "libgcj: unknown step depth while single stepping\n");
1100 return;
1105 static void JNICALL
1106 jdwpThreadEndCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
1107 jthread thread)
1109 using namespace gnu::classpath::jdwp::event;
1111 ThreadEndEvent *e = new ThreadEndEvent (thread);
1112 gnu::classpath::jdwp::Jdwp::notify (e);
1115 static void JNICALL
1116 jdwpThreadStartCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
1117 jthread thread)
1119 using namespace gnu::classpath::jdwp::event;
1121 ThreadStartEvent *e = new ThreadStartEvent (thread);
1122 gnu::classpath::jdwp::Jdwp::notify (e);
1125 static void JNICALL
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 ());
1132 static void JNICALL
1133 jdwpVMInitCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
1134 jthread thread)
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));
1147 // Enable 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);
1156 // Send JDWP VMInit
1157 using namespace gnu::classpath::jdwp::event;
1158 gnu::classpath::jdwp::Jdwp::notify (new VmInitEvent (thread));