mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			1160 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			1160 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C++
		
	
	
	
// natVMVirtualMachine.cc - native support for VMVirtualMachine
 | 
						|
 | 
						|
/* Copyright (C) 2006, 2007 Free Software Foundation
 | 
						|
 | 
						|
   This file is part of libgcj.
 | 
						|
 | 
						|
This software is copyrighted work licensed under the terms of the
 | 
						|
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
 | 
						|
details. */
 | 
						|
 | 
						|
#include <config.h>
 | 
						|
#include <gcj/cni.h>
 | 
						|
#include <java-assert.h>
 | 
						|
#include <java-interp.h>
 | 
						|
#include <jvm.h>
 | 
						|
#include <jvmti.h>
 | 
						|
 | 
						|
#include <java/lang/Class.h>
 | 
						|
#include <java/lang/ClassLoader.h>
 | 
						|
#include <java/lang/Integer.h>
 | 
						|
#include <java/lang/String.h>
 | 
						|
#include <java/lang/StringBuilder.h>
 | 
						|
#include <java/lang/Thread.h>
 | 
						|
#include <java/lang/Throwable.h>
 | 
						|
#include <java/nio/ByteBuffer.h>
 | 
						|
#include <java/nio/ByteBufferImpl.h>
 | 
						|
#include <java/util/ArrayList.h>
 | 
						|
#include <java/util/Collection.h>
 | 
						|
#include <java/util/Hashtable.h>
 | 
						|
#include <java/util/Iterator.h>
 | 
						|
 | 
						|
#include <gnu/classpath/jdwp/Jdwp.h>
 | 
						|
#include <gnu/classpath/jdwp/JdwpConstants$StepDepth.h>
 | 
						|
#include <gnu/classpath/jdwp/JdwpConstants$StepSize.h>
 | 
						|
#include <gnu/classpath/jdwp/JdwpConstants$ThreadStatus.h>
 | 
						|
#include <gnu/classpath/jdwp/VMFrame.h>
 | 
						|
#include <gnu/classpath/jdwp/VMMethod.h>
 | 
						|
#include <gnu/classpath/jdwp/VMVirtualMachine.h>
 | 
						|
#include <gnu/classpath/jdwp/event/BreakpointEvent.h>
 | 
						|
#include <gnu/classpath/jdwp/event/ClassPrepareEvent.h>
 | 
						|
#include <gnu/classpath/jdwp/event/ExceptionEvent.h>
 | 
						|
#include <gnu/classpath/jdwp/event/EventManager.h>
 | 
						|
#include <gnu/classpath/jdwp/event/EventRequest.h>
 | 
						|
#include <gnu/classpath/jdwp/event/SingleStepEvent.h>
 | 
						|
#include <gnu/classpath/jdwp/event/ThreadEndEvent.h>
 | 
						|
#include <gnu/classpath/jdwp/event/ThreadStartEvent.h>
 | 
						|
#include <gnu/classpath/jdwp/event/VmDeathEvent.h>
 | 
						|
#include <gnu/classpath/jdwp/event/VmInitEvent.h>
 | 
						|
#include <gnu/classpath/jdwp/event/filters/IEventFilter.h>
 | 
						|
#include <gnu/classpath/jdwp/event/filters/LocationOnlyFilter.h>
 | 
						|
#include <gnu/classpath/jdwp/event/filters/StepFilter.h>
 | 
						|
#include <gnu/classpath/jdwp/exception/AbsentInformationException.h>
 | 
						|
#include <gnu/classpath/jdwp/exception/InvalidFrameException.h>
 | 
						|
#include <gnu/classpath/jdwp/exception/InvalidLocationException.h>
 | 
						|
#include <gnu/classpath/jdwp/exception/InvalidMethodException.h>
 | 
						|
#include <gnu/classpath/jdwp/exception/JdwpInternalErrorException.h>
 | 
						|
#include <gnu/classpath/jdwp/id/ThreadId.h>
 | 
						|
#include <gnu/classpath/jdwp/util/Location.h>
 | 
						|
#include <gnu/classpath/jdwp/util/MethodResult.h>
 | 
						|
#include <gnu/gcj/jvmti/Breakpoint.h>
 | 
						|
#include <gnu/gcj/jvmti/BreakpointManager.h>
 | 
						|
 | 
						|
using namespace java::lang;
 | 
						|
using namespace gnu::classpath::jdwp::event;
 | 
						|
using namespace gnu::classpath::jdwp::util;
 | 
						|
 | 
						|
// Stepping information
 | 
						|
struct step_info
 | 
						|
{
 | 
						|
  jint size;   // See gnu.classpath.jdwp.JdwpConstants.StepSize
 | 
						|
  jint depth;  // See gnu.classpath.jdwp.JdwpConstants.StepDepth
 | 
						|
  int stack_depth;  // stack depth at start of stepping
 | 
						|
  jmethodID method; // method in which we are stepping
 | 
						|
};
 | 
						|
 | 
						|
// Forward declarations
 | 
						|
static jvmtiError get_linetable (jvmtiEnv *, jmethodID, jint *,
 | 
						|
				 jvmtiLineNumberEntry **);
 | 
						|
static Location *get_request_location (EventRequest *);
 | 
						|
static gnu::classpath::jdwp::event::filters::StepFilter *
 | 
						|
get_request_step_filter (EventRequest *);
 | 
						|
static void handle_single_step (jvmtiEnv *, struct step_info *, jthread,
 | 
						|
				jmethodID, jlocation);
 | 
						|
static void JNICALL jdwpBreakpointCB (jvmtiEnv *, JNIEnv *, jthread,
 | 
						|
				      jmethodID, jlocation);
 | 
						|
static void JNICALL jdwpClassPrepareCB (jvmtiEnv *, JNIEnv *, jthread, jclass);
 | 
						|
static void JNICALL jdwpExceptionCB (jvmtiEnv *, JNIEnv *jni_env, jthread,
 | 
						|
				     jmethodID, jlocation, jobject,
 | 
						|
				     jmethodID, jlocation);
 | 
						|
static void JNICALL jdwpSingleStepCB (jvmtiEnv *, JNIEnv *, jthread,
 | 
						|
				      jmethodID, jlocation);
 | 
						|
static void JNICALL jdwpThreadEndCB (jvmtiEnv *, JNIEnv *, jthread);
 | 
						|
static void JNICALL jdwpThreadStartCB (jvmtiEnv *, JNIEnv *, jthread);
 | 
						|
static void JNICALL jdwpVMDeathCB (jvmtiEnv *, JNIEnv *);
 | 
						|
static void JNICALL jdwpVMInitCB (jvmtiEnv *, JNIEnv *, jthread);
 | 
						|
static void throw_jvmti_error (jvmtiError);
 | 
						|
 | 
						|
#define DEFINE_CALLBACK(Cb,Event) Cb.Event = jdwp ## Event ## CB
 | 
						|
#define DISABLE_EVENT(Event,Thread)					\
 | 
						|
  _jdwp_jvmtiEnv->SetEventNotificationMode (JVMTI_DISABLE,		\
 | 
						|
					    JVMTI_EVENT_ ## Event, Thread)
 | 
						|
#define ENABLE_EVENT(Event,Thread)					\
 | 
						|
  _jdwp_jvmtiEnv->SetEventNotificationMode (JVMTI_ENABLE,		\
 | 
						|
					    JVMTI_EVENT_ ## Event, Thread)
 | 
						|
// JVMTI environment
 | 
						|
static jvmtiEnv *_jdwp_jvmtiEnv;
 | 
						|
 | 
						|
jvmtiEnv *
 | 
						|
_Jv_GetJDWP_JVMTIEnv (void)
 | 
						|
{
 | 
						|
  return _jdwp_jvmtiEnv;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
gnu::classpath::jdwp::VMVirtualMachine::initialize ()
 | 
						|
{
 | 
						|
  _jdwp_suspend_counts = new ::java::util::Hashtable ();
 | 
						|
  _stepping_threads = new ::java::util::Hashtable ();
 | 
						|
  _event_list = new ::java::util::ArrayList ();
 | 
						|
 | 
						|
  JavaVM *vm = _Jv_GetJavaVM ();
 | 
						|
  union
 | 
						|
  {
 | 
						|
    void *ptr;
 | 
						|
    jvmtiEnv *env;
 | 
						|
  } foo;
 | 
						|
  vm->GetEnv (&(foo.ptr), JVMTI_VERSION_1_0);
 | 
						|
  _jdwp_jvmtiEnv = foo.env;
 | 
						|
 | 
						|
  // Wait for VM_INIT to do more initialization
 | 
						|
  jvmtiEventCallbacks callbacks;
 | 
						|
  DEFINE_CALLBACK (callbacks, VMInit);
 | 
						|
  _jdwp_jvmtiEnv->SetEventCallbacks (&callbacks, sizeof (callbacks));
 | 
						|
  ENABLE_EVENT (VM_INIT, NULL);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
gnu::classpath::jdwp::VMVirtualMachine::suspendThread (Thread *thread)
 | 
						|
{
 | 
						|
  jint value;
 | 
						|
  Integer *count;
 | 
						|
  {
 | 
						|
    JvSynchronize dummy (_jdwp_suspend_counts);
 | 
						|
    count = reinterpret_cast<Integer *> (_jdwp_suspend_counts->get (thread));
 | 
						|
    if (count == NULL)
 | 
						|
      {
 | 
						|
	// New -- suspend thread
 | 
						|
	value = 0;
 | 
						|
      }
 | 
						|
    else
 | 
						|
      {
 | 
						|
	// Thread already suspended
 | 
						|
	value = count->intValue ();
 | 
						|
      }
 | 
						|
 | 
						|
    count = Integer::valueOf (++value);
 | 
						|
    _jdwp_suspend_counts->put (thread, count);
 | 
						|
  }
 | 
						|
 | 
						|
  if (value == 1)
 | 
						|
    {
 | 
						|
      // Suspend the thread
 | 
						|
      jvmtiError err = _jdwp_jvmtiEnv->SuspendThread (thread);
 | 
						|
      if (err != JVMTI_ERROR_NONE)
 | 
						|
	{
 | 
						|
	  using namespace gnu::gcj::runtime;
 | 
						|
	  using namespace gnu::classpath::jdwp::exception;
 | 
						|
	  char *reason;
 | 
						|
	  _jdwp_jvmtiEnv->GetErrorName (err, &reason);
 | 
						|
	  String *txt = JvNewStringLatin1 ("could not suspend thread: ");
 | 
						|
	  StringBuilder *msg = new StringBuilder (txt);
 | 
						|
	  msg->append (JvNewStringLatin1 (reason));
 | 
						|
	  _jdwp_jvmtiEnv->Deallocate ((unsigned char *) reason);
 | 
						|
	  throw new JdwpInternalErrorException (msg->toString ());
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
gnu::classpath::jdwp::VMVirtualMachine::resumeThread (Thread *thread)
 | 
						|
{
 | 
						|
  jint value;
 | 
						|
  {
 | 
						|
    JvSynchronize dummy (_jdwp_suspend_counts);
 | 
						|
    Integer *count
 | 
						|
      = reinterpret_cast<Integer *> (_jdwp_suspend_counts->get (thread));
 | 
						|
    if (count == NULL)
 | 
						|
      {
 | 
						|
	// Thread not suspended: ThreadReference.Resume says to ignore it.
 | 
						|
	return;
 | 
						|
      }
 | 
						|
    else
 | 
						|
      {
 | 
						|
	// Decrement suspend count
 | 
						|
	value = count->intValue () - 1;
 | 
						|
      }
 | 
						|
 | 
						|
    if (value == 0)
 | 
						|
      {
 | 
						|
	// Thread will be resumed, remove from table
 | 
						|
	_jdwp_suspend_counts->remove (thread);
 | 
						|
      }
 | 
						|
    else
 | 
						|
      {
 | 
						|
	// Thread stays suspended: record new suspend count
 | 
						|
	count = Integer::valueOf (value);
 | 
						|
	_jdwp_suspend_counts->put (thread, count);
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  if (value == 0)
 | 
						|
    {
 | 
						|
      jvmtiError err = _jdwp_jvmtiEnv->ResumeThread (thread);
 | 
						|
      if (err != JVMTI_ERROR_NONE)
 | 
						|
	{
 | 
						|
	  using namespace gnu::gcj::runtime;
 | 
						|
	  using namespace gnu::classpath::jdwp::exception;
 | 
						|
	  char *reason;
 | 
						|
	  _jdwp_jvmtiEnv->GetErrorName (err, &reason);
 | 
						|
	  String *txt = JvNewStringLatin1 ("could not resume thread: ");
 | 
						|
	  StringBuilder *msg = new StringBuilder (txt);
 | 
						|
	  msg->append (JvNewStringLatin1 (reason));
 | 
						|
	  _jdwp_jvmtiEnv->Deallocate ((unsigned char *) reason);
 | 
						|
	  throw new JdwpInternalErrorException (msg->toString ());
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
jint
 | 
						|
gnu::classpath::jdwp::VMVirtualMachine::getSuspendCount (Thread *thread)
 | 
						|
{
 | 
						|
  jint suspensions = 0;
 | 
						|
  Integer *count
 | 
						|
    = reinterpret_cast<Integer *> (_jdwp_suspend_counts->get (thread));
 | 
						|
  if (count != NULL)
 | 
						|
    suspensions = count->intValue ();
 | 
						|
  return suspensions;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
gnu::classpath::jdwp::VMVirtualMachine::registerEvent (EventRequest *request)
 | 
						|
{
 | 
						|
  switch (request->getEventKind ())
 | 
						|
    {
 | 
						|
    case EventRequest::EVENT_SINGLE_STEP:
 | 
						|
      {
 | 
						|
	Thread *thread;
 | 
						|
	filters::StepFilter *filter = get_request_step_filter (request);
 | 
						|
	if (filter == NULL)
 | 
						|
	  {
 | 
						|
	    // No filter specified: report every step in every
 | 
						|
	    // thread.
 | 
						|
	    thread = NULL;
 | 
						|
	  }
 | 
						|
	else
 | 
						|
	  {
 | 
						|
	    // Add stepping information to list of stepping threads
 | 
						|
	    thread = filter->getThread ()->getThread ();
 | 
						|
	    _Jv_InterpFrame *frame
 | 
						|
	      = reinterpret_cast<_Jv_InterpFrame *> (thread->interp_frame);
 | 
						|
	    struct step_info *sinfo
 | 
						|
	      = (struct step_info *) JvAllocBytes (sizeof (struct step_info));
 | 
						|
	    sinfo->size = filter->getSize ();
 | 
						|
	    sinfo->depth = filter->getDepth ();
 | 
						|
	    sinfo->stack_depth = frame->depth ();
 | 
						|
	    sinfo->method = frame->self->get_method ();
 | 
						|
	    _stepping_threads->put (thread, (jobject) sinfo);
 | 
						|
	  }
 | 
						|
 | 
						|
	ENABLE_EVENT (SINGLE_STEP, thread);
 | 
						|
      }
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_BREAKPOINT:
 | 
						|
      {
 | 
						|
	using namespace ::gnu::gcj::jvmti;
 | 
						|
	Location *loc = get_request_location (request);
 | 
						|
	if (loc == NULL)
 | 
						|
	  {
 | 
						|
	    using namespace gnu::classpath::jdwp::exception;
 | 
						|
	    throw new InvalidLocationException ();
 | 
						|
	  }
 | 
						|
 | 
						|
	jlong method = loc->getMethod ()->getId ();
 | 
						|
	jlocation index = loc->getIndex ();
 | 
						|
	Breakpoint  *bp = BreakpointManager::getBreakpoint (method, index);
 | 
						|
	if (bp == NULL)
 | 
						|
	  {
 | 
						|
	    // Breakpoint not in interpreter yet
 | 
						|
	    bp = BreakpointManager::newBreakpoint (method, index);
 | 
						|
	  }
 | 
						|
	else
 | 
						|
	  {
 | 
						|
	    // Ignore the duplicate
 | 
						|
	  }
 | 
						|
      }
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_FRAME_POP:
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_EXCEPTION:
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_USER_DEFINED:
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_THREAD_START:
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_THREAD_END:
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_CLASS_PREPARE:
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_CLASS_LOAD:
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_CLASS_UNLOAD:
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_FIELD_ACCESS:
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_FIELD_MODIFY:
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_METHOD_ENTRY:
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_METHOD_EXIT:
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_VM_INIT:
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_VM_DEATH:
 | 
						|
      break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
gnu::classpath::jdwp::VMVirtualMachine::unregisterEvent (EventRequest *request)
 | 
						|
{
 | 
						|
  switch (request->getEventKind ())
 | 
						|
    {
 | 
						|
    case EventRequest::EVENT_SINGLE_STEP:
 | 
						|
      {
 | 
						|
	Thread *thread;
 | 
						|
	filters::StepFilter *filter = get_request_step_filter (request);
 | 
						|
	if (filter == NULL)
 | 
						|
	  thread = NULL;
 | 
						|
	else
 | 
						|
	  {
 | 
						|
	    thread = filter->getThread ()->getThread ();
 | 
						|
	    _stepping_threads->remove (thread);
 | 
						|
	  }
 | 
						|
 | 
						|
	DISABLE_EVENT (SINGLE_STEP, thread);
 | 
						|
      }
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_BREAKPOINT:
 | 
						|
      {
 | 
						|
	using namespace gnu::gcj::jvmti;
 | 
						|
	::java::util::Collection *breakpoints;
 | 
						|
	EventManager *em = EventManager::getDefault ();
 | 
						|
	breakpoints = em->getRequests (EventRequest::EVENT_BREAKPOINT);
 | 
						|
 | 
						|
	// Check for duplicates
 | 
						|
	int matches = 0;
 | 
						|
	Location *the_location = get_request_location (request);
 | 
						|
 | 
						|
	// This should not be possible: we REQUIRE a Location
 | 
						|
	// to install a breakpoint
 | 
						|
	JvAssert (the_location != NULL);
 | 
						|
 | 
						|
	::java::util::Iterator *iter = breakpoints->iterator ();
 | 
						|
	while (iter->hasNext ())
 | 
						|
	  {
 | 
						|
	    EventRequest *er
 | 
						|
	      = reinterpret_cast<EventRequest *> (iter->next ());
 | 
						|
	    Location *loc = get_request_location (er);
 | 
						|
	    JvAssert (loc != NULL);
 | 
						|
	    if (loc->equals (the_location) && ++matches == 2)
 | 
						|
	      {
 | 
						|
		// Short-circuit: already more than one breakpoint
 | 
						|
		return;
 | 
						|
	      }
 | 
						|
	  }
 | 
						|
 | 
						|
	if (matches == 0)
 | 
						|
	  {
 | 
						|
	    using namespace gnu::classpath::jdwp::exception;
 | 
						|
	    jstring msg
 | 
						|
	      = JvNewStringLatin1 ("attempt to remove unknown breakpoint");
 | 
						|
	    throw new JdwpInternalErrorException (msg);
 | 
						|
	  }
 | 
						|
 | 
						|
	jlong methodId = the_location->getMethod ()->getId ();
 | 
						|
	BreakpointManager::deleteBreakpoint (methodId,
 | 
						|
					     the_location->getIndex ());
 | 
						|
      }
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_FRAME_POP:
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_EXCEPTION:
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_USER_DEFINED:
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_THREAD_START:
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_THREAD_END:
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_CLASS_PREPARE:
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_CLASS_LOAD:
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_CLASS_UNLOAD:
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_FIELD_ACCESS:
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_FIELD_MODIFY:
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_METHOD_ENTRY:
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_METHOD_EXIT:
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_VM_INIT:
 | 
						|
      break;
 | 
						|
 | 
						|
    case EventRequest::EVENT_VM_DEATH:
 | 
						|
      break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
gnu::classpath::jdwp::VMVirtualMachine::clearEvents (MAYBE_UNUSED jbyte kind)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
java::util::Collection *
 | 
						|
gnu::classpath::jdwp::VMVirtualMachine::getAllLoadedClasses (void)
 | 
						|
{
 | 
						|
  using namespace ::java::util;
 | 
						|
  return (Collection *) new ArrayList ();
 | 
						|
}
 | 
						|
 | 
						|
jint
 | 
						|
gnu::classpath::jdwp::VMVirtualMachine::
 | 
						|
getClassStatus (jclass klass)
 | 
						|
{
 | 
						|
  jint flags = 0;
 | 
						|
  jvmtiError err = _jdwp_jvmtiEnv->GetClassStatus (klass, &flags);
 | 
						|
  if (err != JVMTI_ERROR_NONE)
 | 
						|
    throw_jvmti_error (err);
 | 
						|
 | 
						|
  using namespace gnu::classpath::jdwp::event;
 | 
						|
  jint status = 0;
 | 
						|
  if (flags & JVMTI_CLASS_STATUS_VERIFIED)
 | 
						|
    status |= ClassPrepareEvent::STATUS_VERIFIED;
 | 
						|
  if (flags & JVMTI_CLASS_STATUS_PREPARED)
 | 
						|
    status |= ClassPrepareEvent::STATUS_PREPARED;
 | 
						|
  if (flags & JVMTI_CLASS_STATUS_ERROR)
 | 
						|
    status |= ClassPrepareEvent::STATUS_ERROR;
 | 
						|
  if (flags & JVMTI_CLASS_STATUS_INITIALIZED)
 | 
						|
    status |= ClassPrepareEvent::STATUS_INITIALIZED;
 | 
						|
 | 
						|
  return status;
 | 
						|
}
 | 
						|
 | 
						|
JArray<gnu::classpath::jdwp::VMMethod *> *
 | 
						|
gnu::classpath::jdwp::VMVirtualMachine::
 | 
						|
getAllClassMethods (jclass klass)
 | 
						|
{
 | 
						|
  jint count;
 | 
						|
  jmethodID *methods;
 | 
						|
  jvmtiError err = _jdwp_jvmtiEnv->GetClassMethods (klass, &count, &methods);
 | 
						|
  if (err != JVMTI_ERROR_NONE)
 | 
						|
    throw_jvmti_error (err);
 | 
						|
 | 
						|
  JArray<VMMethod *> *result
 | 
						|
    = (JArray<VMMethod *> *) JvNewObjectArray (count,
 | 
						|
					       &VMMethod::class$, NULL);
 | 
						|
  VMMethod **rmeth = elements (result);
 | 
						|
  for (int i = 0; i < count; ++i)
 | 
						|
    {
 | 
						|
      jlong id = reinterpret_cast<jlong> (methods[i]);
 | 
						|
      rmeth[i] = getClassMethod (klass, id);
 | 
						|
    }
 | 
						|
 | 
						|
  _jdwp_jvmtiEnv->Deallocate ((unsigned char *) methods);
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
gnu::classpath::jdwp::VMMethod *
 | 
						|
gnu::classpath::jdwp::VMVirtualMachine::
 | 
						|
getClassMethod (jclass klass, jlong id)
 | 
						|
{
 | 
						|
  jint count;
 | 
						|
  jmethodID *methods;
 | 
						|
  jvmtiError err = _jdwp_jvmtiEnv->GetClassMethods (klass, &count, &methods);
 | 
						|
  if (err != JVMTI_ERROR_NONE)
 | 
						|
    throw_jvmti_error (err);
 | 
						|
 | 
						|
  jmethodID meth_id = reinterpret_cast<jmethodID> (id);
 | 
						|
 | 
						|
  using namespace gnu::classpath::jdwp;
 | 
						|
 | 
						|
  // Check if this method is defined for the given class and if so return a
 | 
						|
  // VMMethod representing it.
 | 
						|
  for (int i = 0; i < count; i++)
 | 
						|
    {
 | 
						|
      if (methods[i] == meth_id)
 | 
						|
        return new VMMethod (klass, reinterpret_cast<jlong> (meth_id));
 | 
						|
    }
 | 
						|
 | 
						|
  throw new exception::InvalidMethodException (id);
 | 
						|
}
 | 
						|
 | 
						|
java::util::ArrayList *
 | 
						|
gnu::classpath::jdwp::VMVirtualMachine::getFrames (Thread *thread, jint start,
 | 
						|
                                                   jint length)
 | 
						|
{
 | 
						|
  jint frame_count = getFrameCount (thread);
 | 
						|
  ::java::util::ArrayList *frame_list;
 | 
						|
  
 | 
						|
  // Calculate the max number of frames to be returned.
 | 
						|
  jint num_frames = frame_count - start;
 | 
						|
  
 | 
						|
  // Check if num_frames is valid.
 | 
						|
  if (num_frames < 0)
 | 
						|
    num_frames = 0;
 | 
						|
  
 | 
						|
  // Check if there are more than length frames left after start.
 | 
						|
  // If length ios -1 return all remaining frames.
 | 
						|
  if (length != -1 && num_frames > length)
 | 
						|
    num_frames = length;
 | 
						|
     
 | 
						|
  frame_list = new ::java::util::ArrayList (num_frames);
 | 
						|
  
 | 
						|
  _Jv_Frame *vm_frame = reinterpret_cast<_Jv_Frame *> (thread->frame);
 | 
						|
  
 | 
						|
  // Take start frames off the top of the stack
 | 
						|
  while (vm_frame != NULL && start > 0)
 | 
						|
    {
 | 
						|
      start--;
 | 
						|
      vm_frame = vm_frame->next;
 | 
						|
    }
 | 
						|
  
 | 
						|
  // Use as a counter for the number of frames returned.
 | 
						|
  num_frames = 0;
 | 
						|
  
 | 
						|
  while (vm_frame != NULL && (num_frames < length || length == -1))
 | 
						|
    {  
 | 
						|
      jlong frameId = reinterpret_cast<jlong> (vm_frame);
 | 
						|
      
 | 
						|
      VMFrame *frame = getFrame (thread, frameId);
 | 
						|
      frame_list->add (frame);
 | 
						|
      vm_frame = vm_frame->next;
 | 
						|
      num_frames++;
 | 
						|
    }
 | 
						|
  
 | 
						|
  return frame_list;
 | 
						|
}
 | 
						|
 | 
						|
gnu::classpath::jdwp::VMFrame *
 | 
						|
gnu::classpath::jdwp::VMVirtualMachine::
 | 
						|
getFrame (Thread *thread, jlong frameID)
 | 
						|
{
 | 
						|
  using namespace gnu::classpath::jdwp::exception;
 | 
						|
  
 | 
						|
  _Jv_Frame *vm_frame = (_Jv_Frame *) thread->frame;
 | 
						|
  jint depth = 0;
 | 
						|
  _Jv_Frame *frame = reinterpret_cast<_Jv_Frame *> (frameID); 
 | 
						|
  
 | 
						|
  // We need to find the stack depth of the frame, so search through the call
 | 
						|
  // stack to find it.  This also checks for a valid frameID.
 | 
						|
  while (vm_frame != frame)
 | 
						|
    {
 | 
						|
      vm_frame = vm_frame->next;
 | 
						|
      depth++;
 | 
						|
      if (vm_frame == NULL)
 | 
						|
        throw new InvalidFrameException (frameID);
 | 
						|
    }
 | 
						|
  
 | 
						|
  Location *loc = NULL;
 | 
						|
  jvmtiFrameInfo info;
 | 
						|
  jvmtiError jerr;
 | 
						|
  jint num_frames;
 | 
						|
  jclass klass;
 | 
						|
  
 | 
						|
  // Get the info for the frame of interest
 | 
						|
  jerr = _jdwp_jvmtiEnv->GetStackTrace (thread, depth, 1, &info, &num_frames);
 | 
						|
   
 | 
						|
  if (jerr != JVMTI_ERROR_NONE)
 | 
						|
    throw_jvmti_error (jerr);
 | 
						|
  
 | 
						|
  jerr = _jdwp_jvmtiEnv->GetMethodDeclaringClass (info.method, &klass);
 | 
						|
      
 | 
						|
  if (jerr != JVMTI_ERROR_NONE)
 | 
						|
    throw_jvmti_error (jerr);
 | 
						|
 | 
						|
  VMMethod *meth 
 | 
						|
    = getClassMethod (klass, reinterpret_cast<jlong> (info.method));
 | 
						|
  
 | 
						|
  jobject this_obj;
 | 
						|
  
 | 
						|
  if (info.location == -1)
 | 
						|
    {
 | 
						|
      loc = new Location (meth, 0);
 | 
						|
      this_obj = NULL;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      loc = new Location (meth, info.location);
 | 
						|
      _Jv_InterpFrame *iframe = reinterpret_cast<_Jv_InterpFrame *> (vm_frame);
 | 
						|
      this_obj = iframe->get_this_ptr ();
 | 
						|
    }
 | 
						|
  
 | 
						|
  return new VMFrame (thread, reinterpret_cast<jlong> (vm_frame), loc,
 | 
						|
                      this_obj); 
 | 
						|
}
 | 
						|
 | 
						|
jint
 | 
						|
gnu::classpath::jdwp::VMVirtualMachine::
 | 
						|
getFrameCount (Thread *thread)
 | 
						|
{
 | 
						|
  jint frame_count;
 | 
						|
  
 | 
						|
  jvmtiError jerr = _jdwp_jvmtiEnv->GetFrameCount (thread, &frame_count);
 | 
						|
  
 | 
						|
  if (jerr != JVMTI_ERROR_NONE)
 | 
						|
    throw_jvmti_error (jerr);
 | 
						|
  
 | 
						|
  return frame_count;
 | 
						|
}
 | 
						|
 | 
						|
jint
 | 
						|
gnu::classpath::jdwp::VMVirtualMachine::
 | 
						|
getThreadStatus (Thread *thread)
 | 
						|
{
 | 
						|
  jint thr_state, status;
 | 
						|
  
 | 
						|
  jvmtiError jerr = _jdwp_jvmtiEnv->GetThreadState (thread, &thr_state);
 | 
						|
  if (jerr != JVMTI_ERROR_NONE)
 | 
						|
    throw_jvmti_error (jerr);
 | 
						|
  
 | 
						|
  if (thr_state & JVMTI_THREAD_STATE_SLEEPING)
 | 
						|
    status = gnu::classpath::jdwp::JdwpConstants$ThreadStatus::SLEEPING;
 | 
						|
  else if (thr_state & JVMTI_THREAD_STATE_RUNNABLE)
 | 
						|
    status = gnu::classpath::jdwp::JdwpConstants$ThreadStatus::RUNNING;
 | 
						|
  else if (thr_state & JVMTI_THREAD_STATE_WAITING)
 | 
						|
    {
 | 
						|
      if (thr_state & (JVMTI_THREAD_STATE_IN_OBJECT_WAIT
 | 
						|
                       | JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER))
 | 
						|
        status = gnu::classpath::jdwp::JdwpConstants$ThreadStatus::MONITOR;
 | 
						|
      else
 | 
						|
        status = gnu::classpath::jdwp::JdwpConstants$ThreadStatus::WAIT;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      // The thread is not SLEEPING, MONITOR, or WAIT.  It may, however, be
 | 
						|
      // alive but not yet started.
 | 
						|
      if (!(thr_state & (JVMTI_THREAD_STATE_ALIVE 
 | 
						|
                         | JVMTI_THREAD_STATE_TERMINATED)))
 | 
						|
        status = gnu::classpath::jdwp::JdwpConstants$ThreadStatus::RUNNING;
 | 
						|
      status = gnu::classpath::jdwp::JdwpConstants$ThreadStatus::ZOMBIE;     
 | 
						|
    }   
 | 
						|
 | 
						|
  return status;
 | 
						|
}
 | 
						|
 | 
						|
java::util::ArrayList *
 | 
						|
gnu::classpath::jdwp::VMVirtualMachine::
 | 
						|
getLoadRequests (MAYBE_UNUSED ClassLoader *cl)
 | 
						|
{
 | 
						|
  return new ::java::util::ArrayList ();
 | 
						|
}
 | 
						|
 | 
						|
MethodResult *
 | 
						|
gnu::classpath::jdwp::VMVirtualMachine::
 | 
						|
executeMethod (MAYBE_UNUSED jobject obj, MAYBE_UNUSED Thread *thread,
 | 
						|
	       MAYBE_UNUSED jclass clazz, MAYBE_UNUSED VMMethod *method,
 | 
						|
	       MAYBE_UNUSED JArray<value::Value *> *values,
 | 
						|
	       MAYBE_UNUSED jint options)
 | 
						|
{
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
jstring
 | 
						|
gnu::classpath::jdwp::VMVirtualMachine::
 | 
						|
getSourceFile (jclass clazz)
 | 
						|
{
 | 
						|
  jstring file = _Jv_GetInterpClassSourceFile (clazz);
 | 
						|
  
 | 
						|
  // Check if the source file was found.
 | 
						|
  if (file == NULL)
 | 
						|
    throw new exception::AbsentInformationException (
 | 
						|
                           _Jv_NewStringUTF("Source file not found"));
 | 
						|
  
 | 
						|
  return file;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
gnu::classpath::jdwp::VMVirtualMachine::
 | 
						|
redefineClasses (MAYBE_UNUSED JArray<jclass> *types,
 | 
						|
		 MAYBE_UNUSED JArray<jbyteArray> *bytecodes)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
gnu::classpath::jdwp::VMVirtualMachine::
 | 
						|
setDefaultStratum (MAYBE_UNUSED jstring stratum)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
jstring
 | 
						|
gnu::classpath::jdwp::VMVirtualMachine::
 | 
						|
getSourceDebugExtension (MAYBE_UNUSED jclass klass)
 | 
						|
{
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
jbyteArray
 | 
						|
gnu::classpath::jdwp::VMVirtualMachine::
 | 
						|
getBytecodes (MAYBE_UNUSED gnu::classpath::jdwp::VMMethod *method)
 | 
						|
{
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
gnu::classpath::jdwp::util::MonitorInfo *
 | 
						|
gnu::classpath::jdwp::VMVirtualMachine::
 | 
						|
getMonitorInfo (MAYBE_UNUSED jobject obj)
 | 
						|
{
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
jobjectArray
 | 
						|
gnu::classpath::jdwp::VMVirtualMachine::
 | 
						|
getOwnedMonitors (MAYBE_UNUSED ::java::lang::Thread *thread)
 | 
						|
{
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
jobject
 | 
						|
gnu::classpath::jdwp::VMVirtualMachine::
 | 
						|
getCurrentContendedMonitor (MAYBE_UNUSED ::java::lang::Thread *thread)
 | 
						|
{
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
gnu::classpath::jdwp::VMVirtualMachine::
 | 
						|
popFrames (MAYBE_UNUSED ::java::lang::Thread *thread,
 | 
						|
	   MAYBE_UNUSED jlong frameId)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
// A simple caching function used while single-stepping
 | 
						|
static jvmtiError
 | 
						|
get_linetable (jvmtiEnv *env, jmethodID method, jint *count_ptr,
 | 
						|
	       jvmtiLineNumberEntry **table_ptr)
 | 
						|
{
 | 
						|
  static jint last_count = 0;
 | 
						|
  static jvmtiLineNumberEntry *last_table = NULL;
 | 
						|
  static jmethodID last_method = 0;
 | 
						|
 | 
						|
  if (method == last_method)
 | 
						|
    {
 | 
						|
      *count_ptr = last_count;
 | 
						|
      *table_ptr = last_table;
 | 
						|
      return JVMTI_ERROR_NONE;
 | 
						|
    }
 | 
						|
 | 
						|
  jvmtiError err;
 | 
						|
  jint count;
 | 
						|
  jvmtiLineNumberEntry *table;
 | 
						|
  err = env->GetLineNumberTable (method, &count, &table);
 | 
						|
  if (err != JVMTI_ERROR_NONE)
 | 
						|
    {
 | 
						|
      // Keep last table in cache
 | 
						|
      return err;
 | 
						|
    }
 | 
						|
 | 
						|
  env->Deallocate ((unsigned char *) last_table);
 | 
						|
  last_table = *table_ptr = table;
 | 
						|
  last_count = *count_ptr = count;
 | 
						|
  return JVMTI_ERROR_NONE;
 | 
						|
}
 | 
						|
 | 
						|
static gnu::classpath::jdwp::event::filters::StepFilter *
 | 
						|
get_request_step_filter (EventRequest *request)
 | 
						|
{
 | 
						|
  ::java::util::Collection *filters = request->getFilters ();
 | 
						|
  ::java::util::Iterator *iter = filters->iterator ();
 | 
						|
  filters::StepFilter *filter = NULL;
 | 
						|
  while (iter->hasNext ())
 | 
						|
    {
 | 
						|
      using namespace gnu::classpath::jdwp::event::filters;
 | 
						|
      IEventFilter *next = (IEventFilter *) iter->next ();
 | 
						|
      if (next->getClass () == &StepFilter::class$)
 | 
						|
	{
 | 
						|
	  filter = reinterpret_cast<StepFilter *> (next);
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  return filter;
 | 
						|
}
 | 
						|
 | 
						|
static Location *
 | 
						|
get_request_location (EventRequest *request)
 | 
						|
{
 | 
						|
  Location *loc = NULL;
 | 
						|
  ::java::util::Collection *filters = request->getFilters ();
 | 
						|
  ::java::util::Iterator *iter = filters->iterator ();
 | 
						|
  while (iter->hasNext ())
 | 
						|
    {
 | 
						|
      using namespace gnu::classpath::jdwp::event::filters;
 | 
						|
      IEventFilter *filter = (IEventFilter *) iter->next ();
 | 
						|
      if (filter->getClass () == &LocationOnlyFilter::class$)
 | 
						|
	{
 | 
						|
	  LocationOnlyFilter *lof
 | 
						|
	    = reinterpret_cast<LocationOnlyFilter *> (filter);
 | 
						|
	  loc = lof->getLocation ();
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  return loc;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
handle_single_step (jvmtiEnv *env, struct step_info *sinfo, jthread thread,
 | 
						|
		    jmethodID method, jlocation location)
 | 
						|
{
 | 
						|
  using namespace gnu::classpath::jdwp;
 | 
						|
 | 
						|
  if (sinfo == NULL || sinfo->size == JdwpConstants$StepSize::MIN)
 | 
						|
    {
 | 
						|
      // Stop now
 | 
						|
      goto send_notification;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      // Check if we're on a new source line
 | 
						|
      /* This is a little inefficient when we're stepping OVER,
 | 
						|
	 but this must be done when stepping INTO. */
 | 
						|
      jint count;
 | 
						|
      jvmtiLineNumberEntry *table;
 | 
						|
      if (get_linetable (env, method, &count, &table) == JVMTI_ERROR_NONE)
 | 
						|
	{
 | 
						|
	  jint i;
 | 
						|
	  for (i = 0; i < count; ++i)
 | 
						|
	    {
 | 
						|
	      if (table[i].start_location == location)
 | 
						|
		{
 | 
						|
		  // This is the start of a new line -- stop
 | 
						|
		  goto send_notification;
 | 
						|
		}
 | 
						|
	    }
 | 
						|
 | 
						|
	  // Not at a new source line -- just keep stepping
 | 
						|
	  return;
 | 
						|
	}
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  /* Something went wrong: either "absent information"
 | 
						|
	     or "out of memory" ("invalid method id" and "native
 | 
						|
	     method" aren't possible -- those are validated before
 | 
						|
	     single stepping is enabled).
 | 
						|
 | 
						|
	     Do what gdb does: just keep going. */
 | 
						|
	  return;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
 send_notification:
 | 
						|
  jclass klass;
 | 
						|
  jvmtiError err = env->GetMethodDeclaringClass (method, &klass);
 | 
						|
  if (err != JVMTI_ERROR_NONE)
 | 
						|
    {
 | 
						|
      fprintf (stderr, "libgcj: internal error: could not find class for method while single stepping -- continuing\n");
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
  VMMethod *vmmethod = new VMMethod (klass, reinterpret_cast<jlong> (method));
 | 
						|
  Location *loc = new Location (vmmethod, location);
 | 
						|
  _Jv_InterpFrame *iframe
 | 
						|
    = reinterpret_cast<_Jv_InterpFrame *> (thread->interp_frame);  
 | 
						|
  JvAssert (iframe->frame_type == frame_interpreter);
 | 
						|
  jobject instance = iframe->get_this_ptr ();
 | 
						|
  event::SingleStepEvent *event
 | 
						|
    = new event::SingleStepEvent (thread, loc, instance);
 | 
						|
 | 
						|
  // We only want to send the notification (and consequently
 | 
						|
  // suspend) if we are not about to execute a breakpoint.
 | 
						|
  _Jv_InterpMethod *im = reinterpret_cast<_Jv_InterpMethod *> (iframe->self);
 | 
						|
  if (im->breakpoint_at (location))
 | 
						|
    {
 | 
						|
      // Next insn is a breakpoint -- record event and
 | 
						|
      // wait for the JVMTI breakpoint notification to
 | 
						|
      // enforce a suspension policy.
 | 
						|
      VMVirtualMachine::_event_list->add (event);
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      // Next insn is not a breakpoint, so send notification
 | 
						|
      // and enforce the suspend policy.
 | 
						|
      Jdwp::notify (event);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
throw_jvmti_error (jvmtiError err)
 | 
						|
{
 | 
						|
  char *error;
 | 
						|
  jstring msg;
 | 
						|
  if (_jdwp_jvmtiEnv->GetErrorName (err, &error) == JVMTI_ERROR_NONE)
 | 
						|
    {
 | 
						|
      msg = JvNewStringLatin1 (error);
 | 
						|
      _jdwp_jvmtiEnv->Deallocate ((unsigned char *) error);
 | 
						|
    }
 | 
						|
  else
 | 
						|
    msg = JvNewStringLatin1 ("out of memory");
 | 
						|
 | 
						|
  using namespace gnu::classpath::jdwp::exception;
 | 
						|
  throw new JdwpInternalErrorException (msg);
 | 
						|
}
 | 
						|
 | 
						|
static void JNICALL
 | 
						|
jdwpBreakpointCB (jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
 | 
						|
		  jthread thread, jmethodID method, jlocation location)
 | 
						|
{
 | 
						|
  jclass klass;
 | 
						|
  jvmtiError err;
 | 
						|
  err = env->GetMethodDeclaringClass (method, &klass);
 | 
						|
  JvAssert (err == JVMTI_ERROR_NONE);
 | 
						|
 | 
						|
  using namespace gnu::classpath::jdwp;
 | 
						|
  using namespace gnu::classpath::jdwp::event;
 | 
						|
 | 
						|
  jlong methodId = reinterpret_cast<jlong> (method);
 | 
						|
  VMMethod *meth = VMVirtualMachine::getClassMethod (klass, methodId);
 | 
						|
  Location *loc = new Location (meth, location);
 | 
						|
  _Jv_InterpFrame *iframe
 | 
						|
    = reinterpret_cast<_Jv_InterpFrame *> (thread->interp_frame);
 | 
						|
  JvAssert (iframe->frame_type == frame_interpreter);
 | 
						|
  jobject instance = iframe->get_this_ptr ();
 | 
						|
  BreakpointEvent *event = new BreakpointEvent (thread, loc, instance);
 | 
						|
  
 | 
						|
  VMVirtualMachine::_event_list->add (event);
 | 
						|
  JArray<Event *> *events
 | 
						|
    = ((JArray<Event *> *)
 | 
						|
       JvNewObjectArray (VMVirtualMachine::_event_list->size (),
 | 
						|
			 &Event::class$, NULL));
 | 
						|
  VMVirtualMachine::_event_list->toArray ((jobjectArray) events);
 | 
						|
  VMVirtualMachine::_event_list->clear ();
 | 
						|
  Jdwp::notify (events);
 | 
						|
}
 | 
						|
 | 
						|
static void JNICALL
 | 
						|
jdwpClassPrepareCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
 | 
						|
		    jthread thread, jclass klass)
 | 
						|
{
 | 
						|
  using namespace gnu::classpath::jdwp;
 | 
						|
 | 
						|
  jint status = VMVirtualMachine::getClassStatus (klass);
 | 
						|
  event::ClassPrepareEvent *event
 | 
						|
    = new event::ClassPrepareEvent (thread, klass, status);
 | 
						|
  Jdwp::notify (event);
 | 
						|
}
 | 
						|
 | 
						|
static void JNICALL
 | 
						|
jdwpExceptionCB (jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env, jthread thread,
 | 
						|
		 jmethodID method, jlocation location, jobject exception,
 | 
						|
		 jmethodID catch_method, jlocation catch_location)
 | 
						|
{
 | 
						|
  using namespace gnu::classpath::jdwp;
 | 
						|
  jclass throw_klass;
 | 
						|
  jvmtiError err = env->GetMethodDeclaringClass (method, &throw_klass);
 | 
						|
  if (err != JVMTI_ERROR_NONE)
 | 
						|
    {
 | 
						|
      fprintf (stderr, "libgcj: internal error: could not find class for ");
 | 
						|
      fprintf (stderr, "method throwing exception -- continuing\n");
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
  VMMethod *vmmethod = new VMMethod (throw_klass,
 | 
						|
				     reinterpret_cast<jlong> (method));
 | 
						|
  Location *throw_loc = new Location (vmmethod, location);  
 | 
						|
  Location *catch_loc = NULL;
 | 
						|
  if (catch_method == 0)
 | 
						|
    catch_loc = Location::getEmptyLocation ();
 | 
						|
  else
 | 
						|
    {
 | 
						|
      jclass catch_klass;
 | 
						|
      err = env->GetMethodDeclaringClass (catch_method, &catch_klass);
 | 
						|
      if (err != JVMTI_ERROR_NONE)
 | 
						|
	{
 | 
						|
	  fprintf (stderr,
 | 
						|
		   "libgcj: internal error: could not find class for ");
 | 
						|
	  fprintf (stderr,
 | 
						|
		   "method catching exception -- ignoring\n");
 | 
						|
	}
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  vmmethod = new VMMethod (catch_klass,
 | 
						|
				   reinterpret_cast<jlong> (catch_method));
 | 
						|
	  catch_loc = new Location (vmmethod, catch_location);
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  _Jv_InterpFrame *iframe
 | 
						|
    = reinterpret_cast<_Jv_InterpFrame *> (thread->interp_frame);
 | 
						|
  jobject instance = (iframe == NULL) ? NULL : iframe->get_this_ptr ();
 | 
						|
  Throwable *throwable = reinterpret_cast<Throwable *> (exception);
 | 
						|
  event::ExceptionEvent *e = new ExceptionEvent (throwable, thread,
 | 
						|
						 throw_loc, catch_loc,
 | 
						|
						 throw_klass, instance);
 | 
						|
  Jdwp::notify (e);
 | 
						|
}
 | 
						|
 | 
						|
static void JNICALL
 | 
						|
jdwpSingleStepCB (jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env, jthread thread,
 | 
						|
		  jmethodID method, jlocation location)
 | 
						|
{
 | 
						|
  jobject si =
 | 
						|
    gnu::classpath::jdwp::VMVirtualMachine::_stepping_threads->get (thread);
 | 
						|
  struct step_info *sinfo = reinterpret_cast<struct step_info *> (si);
 | 
						|
 | 
						|
  if (sinfo == NULL)
 | 
						|
    {
 | 
						|
      // no step filter for this thread - simply report it
 | 
						|
      handle_single_step (env, NULL, thread, method, location);
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      // A step filter exists for this thread
 | 
						|
      using namespace gnu::classpath::jdwp;
 | 
						|
 | 
						|
      _Jv_InterpFrame *frame
 | 
						|
	= reinterpret_cast<_Jv_InterpFrame *> (thread->interp_frame);
 | 
						|
 | 
						|
      switch (sinfo->depth)
 | 
						|
	{
 | 
						|
	case JdwpConstants$StepDepth::INTO:
 | 
						|
	  /* This is the easy case. We ignore the method and
 | 
						|
	     simply stop at either the next insn, or the next source
 | 
						|
	     line. */
 | 
						|
	  handle_single_step (env, sinfo, thread, method, location);
 | 
						|
	  break;
 | 
						|
 | 
						|
	case JdwpConstants$StepDepth::OVER:
 | 
						|
	  /* This is also a pretty easy case. We just make sure that
 | 
						|
	     the methods are the same and that we are at the same
 | 
						|
	     stack depth, but we should also stop on the next
 | 
						|
	     insn/line if the stack depth is LESS THAN it was when
 | 
						|
	     we started stepping. */
 | 
						|
	  if (method == sinfo->method)
 | 
						|
	    {
 | 
						|
	      // Still in the same method -- must be at same stack depth
 | 
						|
	      // to avoid confusion with recursive methods.
 | 
						|
	      if (frame->depth () == sinfo->stack_depth)
 | 
						|
		handle_single_step (env, sinfo, thread, method, location);
 | 
						|
	    }
 | 
						|
	  else if (frame->depth () < sinfo->stack_depth)
 | 
						|
	    {
 | 
						|
	      // The method in which we were stepping was popped off
 | 
						|
	      // the stack. We simply need to stop at the next insn/line.
 | 
						|
	      handle_single_step (env, sinfo, thread, method, location);
 | 
						|
	    }
 | 
						|
	  break;
 | 
						|
 | 
						|
	case JdwpConstants$StepDepth::OUT:
 | 
						|
	  // All we need to do is check the stack depth
 | 
						|
	  if (sinfo->stack_depth > frame->depth ())
 | 
						|
	    handle_single_step (env, sinfo, thread, method, location);
 | 
						|
	  break;
 | 
						|
 | 
						|
	default:
 | 
						|
	  /* This should not happen. The JDWP back-end should have
 | 
						|
	     validated the StepFilter. */
 | 
						|
	  fprintf (stderr,
 | 
						|
		   "libgcj: unknown step depth while single stepping\n");
 | 
						|
	  return;
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void JNICALL
 | 
						|
jdwpThreadEndCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
 | 
						|
		 jthread thread)
 | 
						|
{
 | 
						|
  using namespace gnu::classpath::jdwp::event;
 | 
						|
 | 
						|
  ThreadEndEvent *e = new ThreadEndEvent (thread);
 | 
						|
  gnu::classpath::jdwp::Jdwp::notify (e);
 | 
						|
}
 | 
						|
 | 
						|
static void JNICALL
 | 
						|
jdwpThreadStartCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
 | 
						|
		   jthread thread)
 | 
						|
{
 | 
						|
  using namespace gnu::classpath::jdwp::event;
 | 
						|
 | 
						|
  ThreadStartEvent *e = new ThreadStartEvent (thread);
 | 
						|
  gnu::classpath::jdwp::Jdwp::notify (e);
 | 
						|
}
 | 
						|
 | 
						|
static void JNICALL
 | 
						|
jdwpVMDeathCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env)
 | 
						|
{
 | 
						|
  using namespace gnu::classpath::jdwp::event;
 | 
						|
  gnu::classpath::jdwp::Jdwp::notify (new VmDeathEvent ());
 | 
						|
}
 | 
						|
 | 
						|
static void JNICALL
 | 
						|
jdwpVMInitCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
 | 
						|
	      jthread thread)
 | 
						|
{
 | 
						|
  // The VM is now initialized, add our callbacks
 | 
						|
  jvmtiEventCallbacks callbacks;
 | 
						|
  DEFINE_CALLBACK (callbacks, Breakpoint);
 | 
						|
  DEFINE_CALLBACK (callbacks, ClassPrepare);
 | 
						|
  DEFINE_CALLBACK (callbacks, Exception);
 | 
						|
  DEFINE_CALLBACK (callbacks, SingleStep);
 | 
						|
  DEFINE_CALLBACK (callbacks, ThreadEnd);
 | 
						|
  DEFINE_CALLBACK (callbacks, ThreadStart);
 | 
						|
  DEFINE_CALLBACK (callbacks, VMDeath);
 | 
						|
  _jdwp_jvmtiEnv->SetEventCallbacks (&callbacks, sizeof (callbacks));
 | 
						|
 | 
						|
  // Enable callbacks
 | 
						|
  ENABLE_EVENT (BREAKPOINT, NULL);
 | 
						|
  ENABLE_EVENT (CLASS_PREPARE, NULL);
 | 
						|
  ENABLE_EVENT (EXCEPTION, NULL);
 | 
						|
  // SingleStep is enabled only when needed
 | 
						|
  ENABLE_EVENT (THREAD_END, NULL);
 | 
						|
  ENABLE_EVENT (THREAD_START, NULL);
 | 
						|
  ENABLE_EVENT (VM_DEATH, NULL);
 | 
						|
 | 
						|
  // Send JDWP VMInit
 | 
						|
  using namespace gnu::classpath::jdwp::event;
 | 
						|
  gnu::classpath::jdwp::Jdwp::notify (new VmInitEvent (thread));
 | 
						|
}
 |