OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [gnu/] [classpath/] [jdwp/] [natVMVirtualMachine.cc] - Blame information for rev 791

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 756 jeremybenn
// natVMVirtualMachine.cc - native support for VMVirtualMachine
2
 
3
/* Copyright (C) 2006, 2007 Free Software Foundation
4
 
5
   This file is part of libgcj.
6
 
7
This software is copyrighted work licensed under the terms of the
8
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
9
details. */
10
 
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>
17
 
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>
31
 
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>
62
 
63
using namespace java::lang;
64
using namespace gnu::classpath::jdwp::event;
65
using namespace gnu::classpath::jdwp::util;
66
 
67
// Stepping information
68
struct step_info
69
{
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
74
};
75
 
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);
97
 
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;
107
 
108
jvmtiEnv *
109
_Jv_GetJDWP_JVMTIEnv (void)
110
{
111
  return _jdwp_jvmtiEnv;
112
}
113
 
114
void
115
gnu::classpath::jdwp::VMVirtualMachine::initialize ()
116
{
117
  _jdwp_suspend_counts = new ::java::util::Hashtable ();
118
  _stepping_threads = new ::java::util::Hashtable ();
119
  _event_list = new ::java::util::ArrayList ();
120
 
121
  JavaVM *vm = _Jv_GetJavaVM ();
122
  union
123
  {
124
    void *ptr;
125
    jvmtiEnv *env;
126
  } foo;
127
  vm->GetEnv (&(foo.ptr), JVMTI_VERSION_1_0);
128
  _jdwp_jvmtiEnv = foo.env;
129
 
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);
135
}
136
 
137
void
138
gnu::classpath::jdwp::VMVirtualMachine::suspendThread (Thread *thread)
139
{
140
  jint value;
141
  Integer *count;
142
  {
143
    JvSynchronize dummy (_jdwp_suspend_counts);
144
    count = reinterpret_cast<Integer *> (_jdwp_suspend_counts->get (thread));
145
    if (count == NULL)
146
      {
147
        // New -- suspend thread
148
        value = 0;
149
      }
150
    else
151
      {
152
        // Thread already suspended
153
        value = count->intValue ();
154
      }
155
 
156
    count = Integer::valueOf (++value);
157
    _jdwp_suspend_counts->put (thread, count);
158
  }
159
 
160
  if (value == 1)
161
    {
162
      // Suspend the thread
163
      jvmtiError err = _jdwp_jvmtiEnv->SuspendThread (thread);
164
      if (err != JVMTI_ERROR_NONE)
165
        {
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 ());
175
        }
176
    }
177
}
178
 
179
void
180
gnu::classpath::jdwp::VMVirtualMachine::resumeThread (Thread *thread)
181
{
182
  jint value;
183
  {
184
    JvSynchronize dummy (_jdwp_suspend_counts);
185
    Integer *count
186
      = reinterpret_cast<Integer *> (_jdwp_suspend_counts->get (thread));
187
    if (count == NULL)
188
      {
189
        // Thread not suspended: ThreadReference.Resume says to ignore it.
190
        return;
191
      }
192
    else
193
      {
194
        // Decrement suspend count
195
        value = count->intValue () - 1;
196
      }
197
 
198
    if (value == 0)
199
      {
200
        // Thread will be resumed, remove from table
201
        _jdwp_suspend_counts->remove (thread);
202
      }
203
    else
204
      {
205
        // Thread stays suspended: record new suspend count
206
        count = Integer::valueOf (value);
207
        _jdwp_suspend_counts->put (thread, count);
208
      }
209
  }
210
 
211
  if (value == 0)
212
    {
213
      jvmtiError err = _jdwp_jvmtiEnv->ResumeThread (thread);
214
      if (err != JVMTI_ERROR_NONE)
215
        {
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 ());
225
        }
226
    }
227
}
228
 
229
jint
230
gnu::classpath::jdwp::VMVirtualMachine::getSuspendCount (Thread *thread)
231
{
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;
238
}
239
 
240
void
241
gnu::classpath::jdwp::VMVirtualMachine::registerEvent (EventRequest *request)
242
{
243
  switch (request->getEventKind ())
244
    {
245
    case EventRequest::EVENT_SINGLE_STEP:
246
      {
247
        Thread *thread;
248
        filters::StepFilter *filter = get_request_step_filter (request);
249
        if (filter == NULL)
250
          {
251
            // No filter specified: report every step in every
252
            // thread.
253
            thread = NULL;
254
          }
255
        else
256
          {
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);
268
          }
269
 
270
        ENABLE_EVENT (SINGLE_STEP, thread);
271
      }
272
      break;
273
 
274
    case EventRequest::EVENT_BREAKPOINT:
275
      {
276
        using namespace ::gnu::gcj::jvmti;
277
        Location *loc = get_request_location (request);
278
        if (loc == NULL)
279
          {
280
            using namespace gnu::classpath::jdwp::exception;
281
            throw new InvalidLocationException ();
282
          }
283
 
284
        jlong method = loc->getMethod ()->getId ();
285
        jlocation index = loc->getIndex ();
286
        Breakpoint  *bp = BreakpointManager::getBreakpoint (method, index);
287
        if (bp == NULL)
288
          {
289
            // Breakpoint not in interpreter yet
290
            bp = BreakpointManager::newBreakpoint (method, index);
291
          }
292
        else
293
          {
294
            // Ignore the duplicate
295
          }
296
      }
297
      break;
298
 
299
    case EventRequest::EVENT_FRAME_POP:
300
      break;
301
 
302
    case EventRequest::EVENT_EXCEPTION:
303
      break;
304
 
305
    case EventRequest::EVENT_USER_DEFINED:
306
      break;
307
 
308
    case EventRequest::EVENT_THREAD_START:
309
      break;
310
 
311
    case EventRequest::EVENT_THREAD_END:
312
      break;
313
 
314
    case EventRequest::EVENT_CLASS_PREPARE:
315
      break;
316
 
317
    case EventRequest::EVENT_CLASS_LOAD:
318
      break;
319
 
320
    case EventRequest::EVENT_CLASS_UNLOAD:
321
      break;
322
 
323
    case EventRequest::EVENT_FIELD_ACCESS:
324
      break;
325
 
326
    case EventRequest::EVENT_FIELD_MODIFY:
327
      break;
328
 
329
    case EventRequest::EVENT_METHOD_ENTRY:
330
      break;
331
 
332
    case EventRequest::EVENT_METHOD_EXIT:
333
      break;
334
 
335
    case EventRequest::EVENT_VM_INIT:
336
      break;
337
 
338
    case EventRequest::EVENT_VM_DEATH:
339
      break;
340
    }
341
}
342
 
343
void
344
gnu::classpath::jdwp::VMVirtualMachine::unregisterEvent (EventRequest *request)
345
{
346
  switch (request->getEventKind ())
347
    {
348
    case EventRequest::EVENT_SINGLE_STEP:
349
      {
350
        Thread *thread;
351
        filters::StepFilter *filter = get_request_step_filter (request);
352
        if (filter == NULL)
353
          thread = NULL;
354
        else
355
          {
356
            thread = filter->getThread ()->getThread ();
357
            _stepping_threads->remove (thread);
358
          }
359
 
360
        DISABLE_EVENT (SINGLE_STEP, thread);
361
      }
362
      break;
363
 
364
    case EventRequest::EVENT_BREAKPOINT:
365
      {
366
        using namespace gnu::gcj::jvmti;
367
        ::java::util::Collection *breakpoints;
368
        EventManager *em = EventManager::getDefault ();
369
        breakpoints = em->getRequests (EventRequest::EVENT_BREAKPOINT);
370
 
371
        // Check for duplicates
372
        int matches = 0;
373
        Location *the_location = get_request_location (request);
374
 
375
        // This should not be possible: we REQUIRE a Location
376
        // to install a breakpoint
377
        JvAssert (the_location != NULL);
378
 
379
        ::java::util::Iterator *iter = breakpoints->iterator ();
380
        while (iter->hasNext ())
381
          {
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)
387
              {
388
                // Short-circuit: already more than one breakpoint
389
                return;
390
              }
391
          }
392
 
393
        if (matches == 0)
394
          {
395
            using namespace gnu::classpath::jdwp::exception;
396
            jstring msg
397
              = JvNewStringLatin1 ("attempt to remove unknown breakpoint");
398
            throw new JdwpInternalErrorException (msg);
399
          }
400
 
401
        jlong methodId = the_location->getMethod ()->getId ();
402
        BreakpointManager::deleteBreakpoint (methodId,
403
                                             the_location->getIndex ());
404
      }
405
      break;
406
 
407
    case EventRequest::EVENT_FRAME_POP:
408
      break;
409
 
410
    case EventRequest::EVENT_EXCEPTION:
411
      break;
412
 
413
    case EventRequest::EVENT_USER_DEFINED:
414
      break;
415
 
416
    case EventRequest::EVENT_THREAD_START:
417
      break;
418
 
419
    case EventRequest::EVENT_THREAD_END:
420
      break;
421
 
422
    case EventRequest::EVENT_CLASS_PREPARE:
423
      break;
424
 
425
    case EventRequest::EVENT_CLASS_LOAD:
426
      break;
427
 
428
    case EventRequest::EVENT_CLASS_UNLOAD:
429
      break;
430
 
431
    case EventRequest::EVENT_FIELD_ACCESS:
432
      break;
433
 
434
    case EventRequest::EVENT_FIELD_MODIFY:
435
      break;
436
 
437
    case EventRequest::EVENT_METHOD_ENTRY:
438
      break;
439
 
440
    case EventRequest::EVENT_METHOD_EXIT:
441
      break;
442
 
443
    case EventRequest::EVENT_VM_INIT:
444
      break;
445
 
446
    case EventRequest::EVENT_VM_DEATH:
447
      break;
448
    }
449
}
450
 
451
void
452
gnu::classpath::jdwp::VMVirtualMachine::clearEvents (MAYBE_UNUSED jbyte kind)
453
{
454
}
455
 
456
java::util::Collection *
457
gnu::classpath::jdwp::VMVirtualMachine::getAllLoadedClasses (void)
458
{
459
  using namespace ::java::util;
460
  return (Collection *) new ArrayList ();
461
}
462
 
463
jint
464
gnu::classpath::jdwp::VMVirtualMachine::
465
getClassStatus (jclass klass)
466
{
467
  jint flags = 0;
468
  jvmtiError err = _jdwp_jvmtiEnv->GetClassStatus (klass, &flags);
469
  if (err != JVMTI_ERROR_NONE)
470
    throw_jvmti_error (err);
471
 
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;
482
 
483
  return status;
484
}
485
 
486
JArray<gnu::classpath::jdwp::VMMethod *> *
487
gnu::classpath::jdwp::VMVirtualMachine::
488
getAllClassMethods (jclass klass)
489
{
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);
495
 
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)
501
    {
502
      jlong id = reinterpret_cast<jlong> (methods[i]);
503
      rmeth[i] = getClassMethod (klass, id);
504
    }
505
 
506
  _jdwp_jvmtiEnv->Deallocate ((unsigned char *) methods);
507
  return result;
508
}
509
 
510
gnu::classpath::jdwp::VMMethod *
511
gnu::classpath::jdwp::VMVirtualMachine::
512
getClassMethod (jclass klass, jlong id)
513
{
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);
519
 
520
  jmethodID meth_id = reinterpret_cast<jmethodID> (id);
521
 
522
  using namespace gnu::classpath::jdwp;
523
 
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++)
527
    {
528
      if (methods[i] == meth_id)
529
        return new VMMethod (klass, reinterpret_cast<jlong> (meth_id));
530
    }
531
 
532
  throw new exception::InvalidMethodException (id);
533
}
534
 
535
java::util::ArrayList *
536
gnu::classpath::jdwp::VMVirtualMachine::getFrames (Thread *thread, jint start,
537
                                                   jint length)
538
{
539
  jint frame_count = getFrameCount (thread);
540
  ::java::util::ArrayList *frame_list;
541
 
542
  // Calculate the max number of frames to be returned.
543
  jint num_frames = frame_count - start;
544
 
545
  // Check if num_frames is valid.
546
  if (num_frames < 0)
547
    num_frames = 0;
548
 
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;
553
 
554
  frame_list = new ::java::util::ArrayList (num_frames);
555
 
556
  _Jv_Frame *vm_frame = reinterpret_cast<_Jv_Frame *> (thread->frame);
557
 
558
  // Take start frames off the top of the stack
559
  while (vm_frame != NULL && start > 0)
560
    {
561
      start--;
562
      vm_frame = vm_frame->next;
563
    }
564
 
565
  // Use as a counter for the number of frames returned.
566
  num_frames = 0;
567
 
568
  while (vm_frame != NULL && (num_frames < length || length == -1))
569
    {
570
      jlong frameId = reinterpret_cast<jlong> (vm_frame);
571
 
572
      VMFrame *frame = getFrame (thread, frameId);
573
      frame_list->add (frame);
574
      vm_frame = vm_frame->next;
575
      num_frames++;
576
    }
577
 
578
  return frame_list;
579
}
580
 
581
gnu::classpath::jdwp::VMFrame *
582
gnu::classpath::jdwp::VMVirtualMachine::
583
getFrame (Thread *thread, jlong frameID)
584
{
585
  using namespace gnu::classpath::jdwp::exception;
586
 
587
  _Jv_Frame *vm_frame = (_Jv_Frame *) thread->frame;
588
  jint depth = 0;
589
  _Jv_Frame *frame = reinterpret_cast<_Jv_Frame *> (frameID);
590
 
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)
594
    {
595
      vm_frame = vm_frame->next;
596
      depth++;
597
      if (vm_frame == NULL)
598
        throw new InvalidFrameException (frameID);
599
    }
600
 
601
  Location *loc = NULL;
602
  jvmtiFrameInfo info;
603
  jvmtiError jerr;
604
  jint num_frames;
605
  jclass klass;
606
 
607
  // Get the info for the frame of interest
608
  jerr = _jdwp_jvmtiEnv->GetStackTrace (thread, depth, 1, &info, &num_frames);
609
 
610
  if (jerr != JVMTI_ERROR_NONE)
611
    throw_jvmti_error (jerr);
612
 
613
  jerr = _jdwp_jvmtiEnv->GetMethodDeclaringClass (info.method, &klass);
614
 
615
  if (jerr != JVMTI_ERROR_NONE)
616
    throw_jvmti_error (jerr);
617
 
618
  VMMethod *meth
619
    = getClassMethod (klass, reinterpret_cast<jlong> (info.method));
620
 
621
  jobject this_obj;
622
 
623
  if (info.location == -1)
624
    {
625
      loc = new Location (meth, 0);
626
      this_obj = NULL;
627
    }
628
  else
629
    {
630
      loc = new Location (meth, info.location);
631
      _Jv_InterpFrame *iframe = reinterpret_cast<_Jv_InterpFrame *> (vm_frame);
632
      this_obj = iframe->get_this_ptr ();
633
    }
634
 
635
  return new VMFrame (thread, reinterpret_cast<jlong> (vm_frame), loc,
636
                      this_obj);
637
}
638
 
639
jint
640
gnu::classpath::jdwp::VMVirtualMachine::
641
getFrameCount (Thread *thread)
642
{
643
  jint frame_count;
644
 
645
  jvmtiError jerr = _jdwp_jvmtiEnv->GetFrameCount (thread, &frame_count);
646
 
647
  if (jerr != JVMTI_ERROR_NONE)
648
    throw_jvmti_error (jerr);
649
 
650
  return frame_count;
651
}
652
 
653
jint
654
gnu::classpath::jdwp::VMVirtualMachine::
655
getThreadStatus (Thread *thread)
656
{
657
  jint thr_state, status;
658
 
659
  jvmtiError jerr = _jdwp_jvmtiEnv->GetThreadState (thread, &thr_state);
660
  if (jerr != JVMTI_ERROR_NONE)
661
    throw_jvmti_error (jerr);
662
 
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)
668
    {
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;
674
    }
675
  else
676
    {
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;
683
    }
684
 
685
  return status;
686
}
687
 
688
java::util::ArrayList *
689
gnu::classpath::jdwp::VMVirtualMachine::
690
getLoadRequests (MAYBE_UNUSED ClassLoader *cl)
691
{
692
  return new ::java::util::ArrayList ();
693
}
694
 
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)
701
{
702
  return NULL;
703
}
704
 
705
jstring
706
gnu::classpath::jdwp::VMVirtualMachine::
707
getSourceFile (jclass clazz)
708
{
709
  jstring file = _Jv_GetInterpClassSourceFile (clazz);
710
 
711
  // Check if the source file was found.
712
  if (file == NULL)
713
    throw new exception::AbsentInformationException (
714
                           _Jv_NewStringUTF("Source file not found"));
715
 
716
  return file;
717
}
718
 
719
void
720
gnu::classpath::jdwp::VMVirtualMachine::
721
redefineClasses (MAYBE_UNUSED JArray<jclass> *types,
722
                 MAYBE_UNUSED JArray<jbyteArray> *bytecodes)
723
{
724
}
725
 
726
void
727
gnu::classpath::jdwp::VMVirtualMachine::
728
setDefaultStratum (MAYBE_UNUSED jstring stratum)
729
{
730
}
731
 
732
jstring
733
gnu::classpath::jdwp::VMVirtualMachine::
734
getSourceDebugExtension (MAYBE_UNUSED jclass klass)
735
{
736
  return NULL;
737
}
738
 
739
jbyteArray
740
gnu::classpath::jdwp::VMVirtualMachine::
741
getBytecodes (MAYBE_UNUSED gnu::classpath::jdwp::VMMethod *method)
742
{
743
  return NULL;
744
}
745
 
746
gnu::classpath::jdwp::util::MonitorInfo *
747
gnu::classpath::jdwp::VMVirtualMachine::
748
getMonitorInfo (MAYBE_UNUSED jobject obj)
749
{
750
  return NULL;
751
}
752
 
753
jobjectArray
754
gnu::classpath::jdwp::VMVirtualMachine::
755
getOwnedMonitors (MAYBE_UNUSED ::java::lang::Thread *thread)
756
{
757
  return NULL;
758
}
759
 
760
jobject
761
gnu::classpath::jdwp::VMVirtualMachine::
762
getCurrentContendedMonitor (MAYBE_UNUSED ::java::lang::Thread *thread)
763
{
764
  return NULL;
765
}
766
 
767
void
768
gnu::classpath::jdwp::VMVirtualMachine::
769
popFrames (MAYBE_UNUSED ::java::lang::Thread *thread,
770
           MAYBE_UNUSED jlong frameId)
771
{
772
}
773
 
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)
778
{
779
  static jint last_count = 0;
780
  static jvmtiLineNumberEntry *last_table = NULL;
781
  static jmethodID last_method = 0;
782
 
783
  if (method == last_method)
784
    {
785
      *count_ptr = last_count;
786
      *table_ptr = last_table;
787
      return JVMTI_ERROR_NONE;
788
    }
789
 
790
  jvmtiError err;
791
  jint count;
792
  jvmtiLineNumberEntry *table;
793
  err = env->GetLineNumberTable (method, &count, &table);
794
  if (err != JVMTI_ERROR_NONE)
795
    {
796
      // Keep last table in cache
797
      return err;
798
    }
799
 
800
  env->Deallocate ((unsigned char *) last_table);
801
  last_table = *table_ptr = table;
802
  last_count = *count_ptr = count;
803
  return JVMTI_ERROR_NONE;
804
}
805
 
806
static gnu::classpath::jdwp::event::filters::StepFilter *
807
get_request_step_filter (EventRequest *request)
808
{
809
  ::java::util::Collection *filters = request->getFilters ();
810
  ::java::util::Iterator *iter = filters->iterator ();
811
  filters::StepFilter *filter = NULL;
812
  while (iter->hasNext ())
813
    {
814
      using namespace gnu::classpath::jdwp::event::filters;
815
      IEventFilter *next = (IEventFilter *) iter->next ();
816
      if (next->getClass () == &StepFilter::class$)
817
        {
818
          filter = reinterpret_cast<StepFilter *> (next);
819
          break;
820
        }
821
    }
822
 
823
  return filter;
824
}
825
 
826
static Location *
827
get_request_location (EventRequest *request)
828
{
829
  Location *loc = NULL;
830
  ::java::util::Collection *filters = request->getFilters ();
831
  ::java::util::Iterator *iter = filters->iterator ();
832
  while (iter->hasNext ())
833
    {
834
      using namespace gnu::classpath::jdwp::event::filters;
835
      IEventFilter *filter = (IEventFilter *) iter->next ();
836
      if (filter->getClass () == &LocationOnlyFilter::class$)
837
        {
838
          LocationOnlyFilter *lof
839
            = reinterpret_cast<LocationOnlyFilter *> (filter);
840
          loc = lof->getLocation ();
841
        }
842
    }
843
 
844
  return loc;
845
}
846
 
847
static void
848
handle_single_step (jvmtiEnv *env, struct step_info *sinfo, jthread thread,
849
                    jmethodID method, jlocation location)
850
{
851
  using namespace gnu::classpath::jdwp;
852
 
853
  if (sinfo == NULL || sinfo->size == JdwpConstants$StepSize::MIN)
854
    {
855
      // Stop now
856
      goto send_notification;
857
    }
858
  else
859
    {
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)
866
        {
867
          jint i;
868
          for (i = 0; i < count; ++i)
869
            {
870
              if (table[i].start_location == location)
871
                {
872
                  // This is the start of a new line -- stop
873
                  goto send_notification;
874
                }
875
            }
876
 
877
          // Not at a new source line -- just keep stepping
878
          return;
879
        }
880
      else
881
        {
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).
886
 
887
             Do what gdb does: just keep going. */
888
          return;
889
        }
890
    }
891
 
892
 send_notification:
893
  jclass klass;
894
  jvmtiError err = env->GetMethodDeclaringClass (method, &klass);
895
  if (err != JVMTI_ERROR_NONE)
896
    {
897
      fprintf (stderr, "libgcj: internal error: could not find class for method while single stepping -- continuing\n");
898
      return;
899
    }
900
 
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);
909
 
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))
914
    {
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);
919
    }
920
  else
921
    {
922
      // Next insn is not a breakpoint, so send notification
923
      // and enforce the suspend policy.
924
      Jdwp::notify (event);
925
    }
926
}
927
 
928
static void
929
throw_jvmti_error (jvmtiError err)
930
{
931
  char *error;
932
  jstring msg;
933
  if (_jdwp_jvmtiEnv->GetErrorName (err, &error) == JVMTI_ERROR_NONE)
934
    {
935
      msg = JvNewStringLatin1 (error);
936
      _jdwp_jvmtiEnv->Deallocate ((unsigned char *) error);
937
    }
938
  else
939
    msg = JvNewStringLatin1 ("out of memory");
940
 
941
  using namespace gnu::classpath::jdwp::exception;
942
  throw new JdwpInternalErrorException (msg);
943
}
944
 
945
static void JNICALL
946
jdwpBreakpointCB (jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
947
                  jthread thread, jmethodID method, jlocation location)
948
{
949
  jclass klass;
950
  jvmtiError err;
951
  err = env->GetMethodDeclaringClass (method, &klass);
952
  JvAssert (err == JVMTI_ERROR_NONE);
953
 
954
  using namespace gnu::classpath::jdwp;
955
  using namespace gnu::classpath::jdwp::event;
956
 
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);
965
 
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);
974
}
975
 
976
static void JNICALL
977
jdwpClassPrepareCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
978
                    jthread thread, jclass klass)
979
{
980
  using namespace gnu::classpath::jdwp;
981
 
982
  jint status = VMVirtualMachine::getClassStatus (klass);
983
  event::ClassPrepareEvent *event
984
    = new event::ClassPrepareEvent (thread, klass, status);
985
  Jdwp::notify (event);
986
}
987
 
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)
992
{
993
  using namespace gnu::classpath::jdwp;
994
  jclass throw_klass;
995
  jvmtiError err = env->GetMethodDeclaringClass (method, &throw_klass);
996
  if (err != JVMTI_ERROR_NONE)
997
    {
998
      fprintf (stderr, "libgcj: internal error: could not find class for ");
999
      fprintf (stderr, "method throwing exception -- continuing\n");
1000
      return;
1001
    }
1002
 
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
1010
    {
1011
      jclass catch_klass;
1012
      err = env->GetMethodDeclaringClass (catch_method, &catch_klass);
1013
      if (err != JVMTI_ERROR_NONE)
1014
        {
1015
          fprintf (stderr,
1016
                   "libgcj: internal error: could not find class for ");
1017
          fprintf (stderr,
1018
                   "method catching exception -- ignoring\n");
1019
        }
1020
      else
1021
        {
1022
          vmmethod = new VMMethod (catch_klass,
1023
                                   reinterpret_cast<jlong> (catch_method));
1024
          catch_loc = new Location (vmmethod, catch_location);
1025
        }
1026
    }
1027
 
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);
1036
}
1037
 
1038
static void JNICALL
1039
jdwpSingleStepCB (jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env, jthread thread,
1040
                  jmethodID method, jlocation location)
1041
{
1042
  jobject si =
1043
    gnu::classpath::jdwp::VMVirtualMachine::_stepping_threads->get (thread);
1044
  struct step_info *sinfo = reinterpret_cast<struct step_info *> (si);
1045
 
1046
  if (sinfo == NULL)
1047
    {
1048
      // no step filter for this thread - simply report it
1049
      handle_single_step (env, NULL, thread, method, location);
1050
    }
1051
  else
1052
    {
1053
      // A step filter exists for this thread
1054
      using namespace gnu::classpath::jdwp;
1055
 
1056
      _Jv_InterpFrame *frame
1057
        = reinterpret_cast<_Jv_InterpFrame *> (thread->interp_frame);
1058
 
1059
      switch (sinfo->depth)
1060
        {
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;
1067
 
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)
1075
            {
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);
1080
            }
1081
          else if (frame->depth () < sinfo->stack_depth)
1082
            {
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);
1086
            }
1087
          break;
1088
 
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;
1094
 
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;
1101
        }
1102
    }
1103
}
1104
 
1105
static void JNICALL
1106
jdwpThreadEndCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
1107
                 jthread thread)
1108
{
1109
  using namespace gnu::classpath::jdwp::event;
1110
 
1111
  ThreadEndEvent *e = new ThreadEndEvent (thread);
1112
  gnu::classpath::jdwp::Jdwp::notify (e);
1113
}
1114
 
1115
static void JNICALL
1116
jdwpThreadStartCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
1117
                   jthread thread)
1118
{
1119
  using namespace gnu::classpath::jdwp::event;
1120
 
1121
  ThreadStartEvent *e = new ThreadStartEvent (thread);
1122
  gnu::classpath::jdwp::Jdwp::notify (e);
1123
}
1124
 
1125
static void JNICALL
1126
jdwpVMDeathCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env)
1127
{
1128
  using namespace gnu::classpath::jdwp::event;
1129
  gnu::classpath::jdwp::Jdwp::notify (new VmDeathEvent ());
1130
}
1131
 
1132
static void JNICALL
1133
jdwpVMInitCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
1134
              jthread thread)
1135
{
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));
1146
 
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);
1155
 
1156
  // Send JDWP VMInit
1157
  using namespace gnu::classpath::jdwp::event;
1158
  gnu::classpath::jdwp::Jdwp::notify (new VmInitEvent (thread));
1159
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.