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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [stacktrace.cc] - Blame information for rev 818

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

Line No. Rev Author Line
1 753 jeremybenn
// stacktrace.cc - Functions for unwinding & inspecting the call stack.
2
 
3
/* Copyright (C) 2005, 2006  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 <platform.h>
13
 
14
#include <jvm.h>
15
#include <gcj/cni.h>
16
#include <java-interp.h>
17
#include <java-stack.h>
18
 
19
#include <stdio.h>
20
 
21
#include <java/lang/Boolean.h>
22
#include <java/lang/Class.h>
23
#include <java/lang/Long.h>
24
#include <java/lang/reflect/Method.h>
25
#include <java/security/AccessController.h>
26
#include <java/util/ArrayList.h>
27
#include <java/util/IdentityHashMap.h>
28
#include <gnu/classpath/jdwp/Jdwp.h>
29
#include <gnu/classpath/VMStackWalker.h>
30
#include <gnu/java/lang/MainThread.h>
31
#include <gnu/gcj/runtime/NameFinder.h>
32
#include <gnu/gcj/runtime/StringBuffer.h>
33
 
34
#include <sysdep/backtrace.h>
35
#include <sysdep/descriptor.h>
36
 
37
using namespace java::lang;
38
using namespace java::lang::reflect;
39
using namespace java::util;
40
using namespace gnu::gcj::runtime;
41
 
42
#ifdef __ARM_EABI_UNWINDER__
43
#define _URC_NORMAL_STOP _URC_FAILURE
44
#endif
45
 
46
// Maps ncode values to their containing native class.
47
// NOTE: Currently this Map contradicts class GC for native classes. This map
48
// (and the "new class stack") will need to use WeakReferences in order to 
49
// enable native class GC.
50
java::util::IdentityHashMap *_Jv_StackTrace::ncodeMap;
51
 
52
// Check the "class stack" for any classes initialized since we were last 
53
// called, and add them to ncodeMap.
54
void
55
_Jv_StackTrace::UpdateNCodeMap ()
56
{
57
  // The Map should be large enough so that a typical Java app doesn't cause 
58
  // it to rehash, without using too much memory. ~5000 entries should be 
59
  // enough.
60
  if (ncodeMap == NULL)
61
    ncodeMap = new java::util::IdentityHashMap (5087);
62
 
63
  jclass klass;
64
  while ((klass = _Jv_PopClass ()))
65
    {
66
      //printf ("got %s\n", klass->name->data);
67
      for (int i = 0; i < klass->method_count; i++)
68
        {
69
          _Jv_Method *method = &klass->methods[i];
70
          void *ncode = method->ncode;
71
          // Add non-abstract methods to ncodeMap.
72
          if (ncode)
73
            {
74
              ncode = UNWRAP_FUNCTION_DESCRIPTOR (ncode);
75
              ncodeMap->put ((java::lang::Object *) ncode, klass);
76
            }
77
        }
78
    }
79
}
80
 
81
// Given a native frame, return the class which this code belongs 
82
// to. Returns NULL if this IP is not associated with a native Java class.
83
// If NCODE is supplied, it will be set with the ip for the entry point of the 
84
// enclosing method.
85
jclass
86
_Jv_StackTrace::ClassForFrame (_Jv_StackFrame *frame)
87
{
88
  JvAssert (frame->type == frame_native);
89
  jclass klass = NULL;
90
 
91
  // look it up in ncodeMap
92
  if (frame->start_ip)
93
    {
94
      klass = (jclass) ncodeMap->get ((jobject) frame->start_ip);
95
 
96
      // Exclude interpreted classes
97
      if (klass != NULL && _Jv_IsInterpretedClass (klass))
98
        klass = NULL;
99
    }
100
 
101
  return klass;
102
}
103
 
104
_Unwind_Reason_Code
105
_Jv_StackTrace::UnwindTraceFn (struct _Unwind_Context *context, void *state_ptr)
106
{
107
  _Jv_UnwindState *state = (_Jv_UnwindState *) state_ptr;
108
  jint pos = state->pos;
109
 
110
  // Check if the trace buffer needs to be extended.
111
  if (pos == state->length)
112
    {
113
      int newLength = state->length * 2;
114
      void *newFrames = _Jv_AllocBytes (newLength * sizeof(_Jv_StackFrame));
115
      memcpy (newFrames, state->frames, state->length * sizeof(_Jv_StackFrame));
116
      state->frames = (_Jv_StackFrame *) newFrames;
117
      state->length = newLength;
118
    }
119
 
120
  void *func_addr = (void *) _Unwind_GetRegionStart (context);
121
 
122
  // If we see the interpreter's main function, "pop" an entry off the 
123
  // interpreter stack and use that instead, so that the trace goes through 
124
  // the java code and not the interpreter itself. This assumes a 1:1 
125
  // correspondance between call frames in the interpreted stack and occurances
126
  // of _Jv_InterpMethod::run() on the native stack.
127
#ifdef INTERPRETER
128
  void *interp_run = NULL;
129
 
130
  if (::gnu::classpath::jdwp::Jdwp::isDebugging)
131
        interp_run = (void *) &_Jv_InterpMethod::run_debug;
132
  else
133
    interp_run = (void *) &_Jv_InterpMethod::run;
134
 
135
  if (func_addr == UNWRAP_FUNCTION_DESCRIPTOR (interp_run))
136
    {
137
      state->frames[pos].type = frame_interpreter;
138
      _Jv_Frame *frame = static_cast<_Jv_Frame *> (state->interp_frame);
139
      state->frames[pos].interp.meth
140
        = static_cast<_Jv_InterpMethod *> (frame->self);
141
      state->frames[pos].interp.pc = state->interp_frame->pc;
142
      state->interp_frame = state->interp_frame->next_interp;
143
    }
144
  else
145
  // We handle proxies in the same way as interpreted classes
146
  if (_Jv_is_proxy (func_addr))
147
    {
148
      state->frames[pos].type = frame_proxy;
149
      state->frames[pos].proxyClass = state->interp_frame->proxyClass;
150
      state->frames[pos].proxyMethod = state->interp_frame->proxyMethod;
151
      state->interp_frame = state->interp_frame->next_interp;
152
    }
153
  else
154
#endif
155
    {
156
#ifdef HAVE_GETIPINFO
157
      _Unwind_Ptr ip;
158
      int ip_before_insn = 0;
159
      ip = _Unwind_GetIPInfo (context, &ip_before_insn);
160
 
161
      // If the unwinder gave us a 'return' address, roll it back a little
162
      // to ensure we get the correct line number for the call itself.
163
      if (! ip_before_insn)
164
        --ip;
165
#endif
166
      state->frames[pos].type = frame_native;
167
#ifdef HAVE_GETIPINFO
168
      state->frames[pos].ip = (void *) ip;
169
#else
170
      state->frames[pos].ip = (void *) _Unwind_GetIP (context);
171
#endif
172
      state->frames[pos].start_ip = func_addr;
173
    }
174
 
175
  _Unwind_Reason_Code result = _URC_NO_REASON;
176
  if (state->trace_function != NULL)
177
    result = (state->trace_function) (state);
178
  state->pos++;
179
  return result;
180
}
181
 
182
// Return a raw stack trace from the current point of execution. The raw 
183
// trace will include all functions that have unwind info.
184
_Jv_StackTrace *
185
_Jv_StackTrace::GetStackTrace(void)
186
{
187
  int trace_size = 100;
188
  _Jv_StackFrame frames[trace_size];
189
  _Jv_UnwindState state (trace_size);
190
  state.frames = (_Jv_StackFrame *) &frames;
191
 
192
  _Unwind_Backtrace (UnwindTraceFn, &state);
193
 
194
  // Copy the trace and return it.
195
  int traceSize = sizeof (_Jv_StackTrace) +
196
    (sizeof (_Jv_StackFrame) * state.pos);
197
  _Jv_StackTrace *trace = (_Jv_StackTrace *) _Jv_AllocBytes (traceSize);
198
  trace->length = state.pos;
199
  memcpy (trace->frames, state.frames, sizeof (_Jv_StackFrame) * state.pos);
200
  return trace;
201
}
202
 
203
void
204
_Jv_StackTrace::getLineNumberForFrame(_Jv_StackFrame *frame, NameFinder *finder,
205
                                      jstring *sourceFileName, jint *lineNum,
206
                                      jstring *methodName)
207
{
208
#ifdef INTERPRETER
209
  if (frame->type == frame_interpreter)
210
    {
211
      _Jv_InterpMethod *interp_meth = frame->interp.meth;
212
      _Jv_InterpClass *interp_class =
213
         (_Jv_InterpClass *) interp_meth->defining_class->aux_info;
214
      *sourceFileName = interp_class->source_file_name;
215
      // The interpreter advances the PC before executing an instruction,
216
      // so roll-back 1 byte to ensure the line number is accurate.
217
      *lineNum = interp_meth->get_source_line(frame->interp.pc - 1);
218
      return;
219
    }
220
#endif
221
 
222
  if (frame->type == frame_proxy)
223
    {
224
      *sourceFileName = NULL;
225
      *lineNum = 0;
226
      return;
227
    }
228
 
229
  // Use _Jv_platform_dladdr() to determine in which binary the address IP
230
  // resides.
231
  _Jv_AddrInfo info;
232
  jstring binaryName = NULL;
233
  const char *argv0 = _Jv_GetSafeArg(0);
234
 
235
  void *ip = frame->ip;
236
  _Unwind_Ptr offset = 0;
237
 
238
  if (_Jv_platform_dladdr (ip, &info))
239
    {
240
      if (info.file_name)
241
        binaryName = JvNewStringUTF (info.file_name);
242
      else
243
        return;
244
 
245
      if (*methodName == NULL && info.sym_name)
246
        *methodName = JvNewStringUTF (info.sym_name);
247
 
248
      // addr2line expects relative addresses for shared libraries.
249
      if (strcmp (info.file_name, argv0) == 0)
250
        offset = (_Unwind_Ptr) ip;
251
      else
252
        offset = (_Unwind_Ptr) ip - (_Unwind_Ptr) info.base;
253
 
254
#ifndef HAVE_GETIPINFO
255
      // The unwinder gives us the return address. In order to get the right
256
      // line number for the stack trace, roll it back a little.
257
      offset -= 1;
258
#endif
259
 
260
      finder->lookup (binaryName, (jlong) offset);
261
      *sourceFileName = finder->getSourceFile();
262
      *lineNum = finder->getLineNum();
263
      if (*lineNum == -1 && NameFinder::showRaw())
264
        {
265
          gnu::gcj::runtime::StringBuffer *t =
266
            new gnu::gcj::runtime::StringBuffer(binaryName);
267
          t->append ((jchar)' ');
268
          t->append ((jchar)'[');
269
          // + 1 to compensate for the - 1 adjustment above;
270
          t->append (Long::toHexString (offset + 1));
271
          t->append ((jchar)']');
272
          *sourceFileName = t->toString();
273
        }
274
    }
275
}
276
 
277
// Look up class and method info for the given stack frame, setting 
278
// frame->klass and frame->meth if they are known.
279
void
280
_Jv_StackTrace::FillInFrameInfo (_Jv_StackFrame *frame)
281
{
282
  jclass klass = NULL;
283
  _Jv_Method *meth = NULL;
284
 
285
  if (frame->type == frame_native)
286
    {
287
      klass = _Jv_StackTrace::ClassForFrame (frame);
288
 
289
      if (klass != NULL)
290
        // Find method in class
291
        for (int j = 0; j < klass->method_count; j++)
292
          {
293
            void *wncode = UNWRAP_FUNCTION_DESCRIPTOR (klass->methods[j].ncode);
294
            if (wncode == frame->start_ip)
295
              {
296
                meth = &klass->methods[j];
297
                break;
298
              }
299
          }
300
    }
301
  else if (frame->type == frame_proxy)
302
    {
303
      klass = frame->proxyClass;
304
      meth = frame->proxyMethod;
305
    }
306
#ifdef INTERPRETER
307
  else if (frame->type == frame_interpreter)
308
    {
309
      _Jv_InterpMethod *interp_meth = frame->interp.meth;
310
      klass = interp_meth->defining_class;
311
      meth = interp_meth->self;
312
    }
313
#endif
314
  else
315
    JvFail ("Unknown frame type");
316
 
317
  frame->klass = klass;
318
  frame->meth = meth;
319
}
320
 
321
// Convert raw stack frames to a Java array of StackTraceElement objects.
322
JArray< ::java::lang::StackTraceElement *>*
323
_Jv_StackTrace::GetStackTraceElements (_Jv_StackTrace *trace,
324
  Throwable *throwable __attribute__((unused)))
325
{
326
  ArrayList *list = new ArrayList ();
327
 
328
#if defined (SJLJ_EXCEPTIONS) && ! defined (WIN32)
329
  // We can't use the nCodeMap without unwinder support. Instead,
330
  // fake the method name by giving the IP in hex - better than nothing.  
331
  jstring hex = JvNewStringUTF ("0x");
332
 
333
  for (int i = 0; i < trace->length; i++)
334
    {
335
      jstring sourceFileName = NULL;
336
      jint lineNum = -1;
337
      _Jv_StackFrame *frame = &trace->frames[i];
338
 
339
      jstring className = NULL;
340
      jstring methodName = hex->concat (Long::toHexString ((jlong) frame->ip));
341
 
342
      StackTraceElement *element = new StackTraceElement (sourceFileName,
343
        lineNum, className, methodName, 0);
344
      list->add (element);
345
    }
346
 
347
#else /* SJLJ_EXCEPTIONS && !WIN32 */
348
 
349
  //JvSynchronized (ncodeMap);
350
  UpdateNCodeMap ();
351
 
352
  NameFinder *finder = new NameFinder();
353
  int start_idx = 0;
354
  int end_idx = trace->length - 1;
355
 
356
  // First pass: strip superfluous frames from beginning and end of the trace.  
357
  for (int i = 0; i < trace->length; i++)
358
    {
359
      _Jv_StackFrame *frame = &trace->frames[i];
360
      FillInFrameInfo (frame);
361
 
362
      if (!frame->klass || !frame->meth)
363
        // Not a Java frame.
364
        continue;
365
 
366
      // Throw away the top of the stack till we see:
367
      //  - the constructor(s) of this Throwable, or
368
      //  - the Throwable.fillInStackTrace call.
369
      if (frame->klass == throwable->getClass()
370
          && strcmp (frame->meth->name->chars(), "<init>") == 0)
371
        start_idx = i + 1;
372
 
373
      if (frame->klass == &Throwable::class$
374
          && strcmp (frame->meth->name->chars(), "fillInStackTrace") == 0)
375
        start_idx = i + 1;
376
 
377
      // End the trace at the application's main() method if we see call_main.
378
      if (frame->klass == &gnu::java::lang::MainThread::class$
379
          && strcmp (frame->meth->name->chars(), "call_main") == 0)
380
        end_idx = i - 1;
381
    }
382
 
383
  const jboolean remove_unknown
384
    = gnu::gcj::runtime::NameFinder::removeUnknown();
385
 
386
  // Second pass: Look up line-number info for remaining frames.
387
  for (int i = start_idx; i <= end_idx; i++)
388
    {
389
      _Jv_StackFrame *frame = &trace->frames[i];
390
 
391
      if (frame->klass == NULL && remove_unknown)
392
        // Not a Java frame.
393
        continue;
394
 
395
      jstring className = NULL;
396
      if (frame->klass != NULL)
397
        className = frame->klass->getName ();
398
 
399
      jstring methodName = NULL;
400
      if (frame->meth)
401
        methodName = JvNewStringUTF (frame->meth->name->chars());
402
 
403
      jstring sourceFileName = NULL;
404
      jint lineNum = -1;
405
 
406
      getLineNumberForFrame(frame, finder, &sourceFileName, &lineNum,
407
                            &methodName);
408
 
409
      StackTraceElement *element = new StackTraceElement (sourceFileName, lineNum,
410
        className, methodName, 0);
411
      list->add (element);
412
    }
413
 
414
  finder->close();
415
#endif /* SJLJ_EXCEPTIONS && !WIN32 */
416
 
417
  JArray<Object *> *array = JvNewObjectArray (list->size (),
418
    &StackTraceElement::class$, NULL);
419
 
420
  return (JArray<StackTraceElement *>*) list->toArray (array);
421
}
422
 
423
struct CallingClassTraceData
424
{
425
  jclass checkClass;
426
  jclass foundClass;
427
  _Jv_Method *foundMeth;
428
  bool seen_checkClass;
429
};
430
 
431
_Unwind_Reason_Code
432
_Jv_StackTrace::calling_class_trace_fn (_Jv_UnwindState *state)
433
{
434
  CallingClassTraceData *trace_data = (CallingClassTraceData *)
435
    state->trace_data;
436
  _Jv_StackFrame *frame = &state->frames[state->pos];
437
  FillInFrameInfo (frame);
438
 
439
  if (trace_data->seen_checkClass
440
      && frame->klass
441
      && frame->klass != trace_data->checkClass)
442
    {
443
      trace_data->foundClass = frame->klass;
444
      trace_data->foundMeth = frame->meth;
445
      return _URC_NORMAL_STOP;
446
    }
447
 
448
  if (frame->klass == trace_data->checkClass)
449
    trace_data->seen_checkClass = true;
450
 
451
  return _URC_NO_REASON;
452
}
453
 
454
// Find the class immediately above the given class on the call stack. Any 
455
// intermediate non-Java 
456
// frames are ignored. If the calling class could not be determined (eg because 
457
// the unwinder is not supported on this platform), NULL is returned.
458
// This function is used to implement calling-classloader checks and reflection
459
// accessibility checks.
460
// CHECKCLASS is typically the class calling GetCallingClass. The first class
461
// above CHECKCLASS on the call stack will be returned.
462
jclass
463
_Jv_StackTrace::GetCallingClass (jclass checkClass)
464
{
465
  jclass result = NULL;
466
  GetCallerInfo (checkClass, &result, NULL);
467
  return result;
468
}
469
 
470
void
471
_Jv_StackTrace::GetCallerInfo (jclass checkClass, jclass *caller_class,
472
  _Jv_Method **caller_meth)
473
{
474
  int trace_size = 20;
475
  _Jv_StackFrame frames[trace_size];
476
  _Jv_UnwindState state (trace_size);
477
  state.frames = (_Jv_StackFrame *) &frames;
478
 
479
  CallingClassTraceData trace_data;
480
  trace_data.checkClass = checkClass;
481
  trace_data.seen_checkClass = false;
482
  trace_data.foundClass = NULL;
483
  trace_data.foundMeth = NULL;
484
 
485
  state.trace_function = calling_class_trace_fn;
486
  state.trace_data = (void *) &trace_data;
487
 
488
  //JvSynchronized (ncodeMap);
489
  UpdateNCodeMap ();
490
 
491
  _Unwind_Backtrace (UnwindTraceFn, &state);
492
 
493
  if (caller_class)
494
    *caller_class = trace_data.foundClass;
495
  if (caller_meth)
496
    *caller_meth = trace_data.foundMeth;
497
}
498
 
499
_Unwind_Reason_Code
500
_Jv_StackTrace::non_system_trace_fn (_Jv_UnwindState *state)
501
{
502
  _Jv_StackFrame *frame = &state->frames[state->pos];
503
  FillInFrameInfo (frame);
504
 
505
  ClassLoader *classLoader = NULL;
506
 
507
  if (frame->klass)
508
    {
509
      classLoader = frame->klass->getClassLoaderInternal();
510
#ifdef INTERPRETER
511
      if (classLoader != NULL)
512
        {
513
          state->trace_data = (void *) classLoader;
514
          return _URC_NORMAL_STOP;
515
        }
516
#endif
517
    }
518
 
519
  return _URC_NO_REASON;
520
}
521
 
522
ClassLoader *
523
_Jv_StackTrace::GetFirstNonSystemClassLoader ()
524
{
525
  int trace_size = 32;
526
  _Jv_StackFrame frames[trace_size];
527
  _Jv_UnwindState state (trace_size);
528
  state.frames = (_Jv_StackFrame *) &frames;
529
  state.trace_function = non_system_trace_fn;
530
  state.trace_data = NULL;
531
 
532
  //JvSynchronized (ncodeMap);
533
  UpdateNCodeMap ();
534
 
535
  _Unwind_Backtrace (UnwindTraceFn, &state);
536
 
537
  if (state.trace_data)
538
    return (ClassLoader *) state.trace_data;
539
 
540
  return NULL;
541
}
542
 
543
struct AccessControlTraceData
544
{
545
  jint length;
546
  jboolean privileged;
547
};
548
 
549
_Unwind_Reason_Code
550
_Jv_StackTrace::accesscontrol_trace_fn (_Jv_UnwindState *state)
551
{
552
  AccessControlTraceData *trace_data = (AccessControlTraceData *)
553
    state->trace_data;
554
  _Jv_StackFrame *frame = &state->frames[state->pos];
555
  FillInFrameInfo (frame);
556
 
557
  if (!(frame->klass && frame->meth))
558
    return _URC_NO_REASON;
559
 
560
  trace_data->length++;
561
 
562
  // If the previous frame was a call to doPrivileged, then this is
563
  // the last frame we look at.
564
  if (trace_data->privileged)
565
    return _URC_NORMAL_STOP;
566
 
567
  if (frame->klass == &::java::security::AccessController::class$
568
      && strcmp (frame->meth->name->chars(), "doPrivileged") == 0)
569
    trace_data->privileged = true;
570
 
571
  return _URC_NO_REASON;
572
}
573
 
574
jobjectArray
575
_Jv_StackTrace::GetAccessControlStack (void)
576
{
577
  int trace_size = 100;
578
  _Jv_StackFrame frames[trace_size];
579
  _Jv_UnwindState state (trace_size);
580
  state.frames = (_Jv_StackFrame *) &frames;
581
 
582
  AccessControlTraceData trace_data;
583
  trace_data.length = 0;
584
  trace_data.privileged = false;
585
 
586
  state.trace_function = accesscontrol_trace_fn;
587
  state.trace_data = (void *) &trace_data;
588
 
589
  UpdateNCodeMap();
590
  _Unwind_Backtrace (UnwindTraceFn, &state);
591
 
592
  JArray<jclass> *classes = (JArray<jclass> *)
593
    _Jv_NewObjectArray (trace_data.length, &::java::lang::Class::class$, NULL);
594
  jclass *c = elements (classes);
595
 
596
  for (int i = 0, j = 0; i < state.pos; i++)
597
    {
598
      _Jv_StackFrame *frame = &state.frames[i];
599
      if (!frame->klass || !frame->meth)
600
        continue;
601
      c[j] = frame->klass;
602
      j++;
603
    }
604
 
605
  jobjectArray result =
606
    (jobjectArray) _Jv_NewObjectArray (2, &::java::lang::Object::class$,
607
                                         NULL);
608
  jobject *r = elements (result);
609
  r[0] = (jobject) classes;
610
  r[1] = (jobject) new Boolean (trace_data.privileged);
611
 
612
  return result;
613
}
614
 
615
JArray<jclass> *
616
_Jv_StackTrace::GetStackWalkerStack ()
617
{
618
  int trace_size = 100;
619
  _Jv_StackFrame frames[trace_size];
620
  _Jv_UnwindState state (trace_size);
621
  state.frames = (_Jv_StackFrame *) &frames;
622
 
623
  UpdateNCodeMap ();
624
  _Unwind_Backtrace (UnwindTraceFn, &state);
625
 
626
  int num_frames = 0, start_frame = -1;
627
  enum
628
    {
629
      VMSW_GETCLASSCONTEXT,
630
      JLRM_INVOKE_OR_USER_FN,
631
      USER_FN
632
    }
633
  expect = VMSW_GETCLASSCONTEXT;
634
  for (int i = 0; i < state.pos; i++)
635
    {
636
      _Jv_StackFrame *frame = &state.frames[i];
637
      FillInFrameInfo (frame);
638
      if (!frame->klass || !frame->meth)
639
        continue;
640
 
641
      switch (expect)
642
        {
643
        case VMSW_GETCLASSCONTEXT:
644
          JvAssert (
645
            frame->klass == &::gnu::classpath::VMStackWalker::class$
646
            && strcmp (frame->meth->name->chars(), "getClassContext") == 0);
647
          expect = JLRM_INVOKE_OR_USER_FN;
648
          break;
649
 
650
        case JLRM_INVOKE_OR_USER_FN:
651
          if (frame->klass != &::java::lang::reflect::Method::class$
652
              || strcmp (frame->meth->name->chars(), "invoke") != 0)
653
            start_frame = i;
654
          expect = USER_FN;
655
          break;
656
 
657
        case USER_FN:
658
          if (start_frame == -1)
659
            start_frame = i;
660
          break;
661
        }
662
 
663
      if (start_frame != -1)
664
        {
665
          if (frame->klass == &::gnu::java::lang::MainThread::class$)
666
            break;
667
          num_frames++;
668
        }
669
    }
670
  JvAssert (num_frames > 0 && start_frame > 0);
671
 
672
  JArray<jclass> *result = (JArray<jclass> *)
673
    _Jv_NewObjectArray (num_frames, &::java::lang::Class::class$, NULL);
674
  jclass *c = elements (result);
675
 
676
  for (int i = start_frame, j = 0; i < state.pos && j < num_frames; i++)
677
    {
678
      _Jv_StackFrame *frame = &state.frames[i];
679
      if (!frame->klass || !frame->meth)
680
        continue;
681
      c[j] = frame->klass;
682
      j++;
683
    }
684
 
685
  return result;
686
}
687
 
688
typedef enum
689
  {
690
    VMSW_GET_CALLING_ITEM,
691
    JLRM_INVOKE_OR_CALLER,
692
    CALLER,
693
    CALLER_OF_CALLER
694
  } gswcc_expect;
695
 
696
struct StackWalkerTraceData
697
{
698
  gswcc_expect expect;
699
  jclass result;
700
};
701
 
702
_Unwind_Reason_Code
703
_Jv_StackTrace::stackwalker_trace_fn (_Jv_UnwindState *state)
704
{
705
  StackWalkerTraceData *trace_data = (StackWalkerTraceData *)
706
    state->trace_data;
707
  _Jv_StackFrame *frame = &state->frames[state->pos];
708
  FillInFrameInfo (frame);
709
 
710
  if (!(frame->klass && frame->meth))
711
    return _URC_NO_REASON;
712
 
713
  switch (trace_data->expect)
714
    {
715
    case VMSW_GET_CALLING_ITEM:
716
      JvAssert (frame->klass == &::gnu::classpath::VMStackWalker::class$);
717
      trace_data->expect = JLRM_INVOKE_OR_CALLER;
718
      break;
719
 
720
    case JLRM_INVOKE_OR_CALLER:
721
      if (frame->klass == &::java::lang::reflect::Method::class$
722
          && strcmp (frame->meth->name->chars(), "invoke") == 0)
723
        trace_data->expect = CALLER;
724
      else
725
        trace_data->expect = CALLER_OF_CALLER;
726
      break;
727
 
728
    case CALLER:
729
      trace_data->expect = CALLER_OF_CALLER;
730
      break;
731
 
732
    case CALLER_OF_CALLER:
733
      trace_data->result = frame->klass;
734
      return _URC_NORMAL_STOP;
735
    }
736
 
737
  return _URC_NO_REASON;
738
}
739
 
740
jclass
741
_Jv_StackTrace::GetStackWalkerCallingClass (void)
742
{
743
  int trace_size = 100;
744
  _Jv_StackFrame frames[trace_size];
745
  _Jv_UnwindState state (trace_size);
746
  state.frames = (_Jv_StackFrame *) &frames;
747
 
748
  StackWalkerTraceData trace_data;
749
  trace_data.expect = VMSW_GET_CALLING_ITEM;
750
  trace_data.result = NULL;
751
 
752
  state.trace_function = stackwalker_trace_fn;
753
  state.trace_data = (void *) &trace_data;
754
 
755
  UpdateNCodeMap();
756
  _Unwind_Backtrace (UnwindTraceFn, &state);
757
 
758
  return trace_data.result;
759
}
760
 
761
struct StackWalkerNNLTraceData
762
{
763
  gswcc_expect expect;
764
  ClassLoader *result;
765
};
766
 
767
_Unwind_Reason_Code
768
_Jv_StackTrace::stackwalker_nnl_trace_fn (_Jv_UnwindState *state)
769
{
770
  StackWalkerNNLTraceData *trace_data = (StackWalkerNNLTraceData *)
771
    state->trace_data;
772
  _Jv_StackFrame *frame = &state->frames[state->pos];
773
  FillInFrameInfo (frame);
774
 
775
  if (!(frame->klass && frame->meth))
776
    return _URC_NO_REASON;
777
 
778
  switch (trace_data->expect)
779
    {
780
    case VMSW_GET_CALLING_ITEM:
781
      JvAssert (frame->klass == &::gnu::classpath::VMStackWalker::class$);
782
      trace_data->expect = JLRM_INVOKE_OR_CALLER;
783
      break;
784
 
785
    case JLRM_INVOKE_OR_CALLER:
786
      if (frame->klass == &::java::lang::reflect::Method::class$
787
          && strcmp (frame->meth->name->chars(), "invoke") == 0)
788
        trace_data->expect = CALLER;
789
      else
790
        trace_data->expect = CALLER_OF_CALLER;
791
      break;
792
 
793
    case CALLER:
794
      trace_data->expect = CALLER_OF_CALLER;
795
      break;
796
 
797
    case CALLER_OF_CALLER:
798
      ClassLoader *cl = frame->klass->getClassLoaderInternal ();
799
      if (cl != NULL)
800
        {
801
          trace_data->result = cl;
802
          return _URC_NORMAL_STOP;
803
        }
804
    }
805
 
806
  return _URC_NO_REASON;
807
}
808
 
809
ClassLoader *
810
_Jv_StackTrace::GetStackWalkerFirstNonNullLoader (void)
811
{
812
  int trace_size = 100;
813
  _Jv_StackFrame frames[trace_size];
814
  _Jv_UnwindState state (trace_size);
815
  state.frames = (_Jv_StackFrame *) &frames;
816
 
817
  StackWalkerNNLTraceData trace_data;
818
  trace_data.expect = VMSW_GET_CALLING_ITEM;
819
  trace_data.result = NULL;
820
 
821
  state.trace_function = stackwalker_nnl_trace_fn;
822
  state.trace_data = (void *) &trace_data;
823
 
824
  UpdateNCodeMap();
825
  _Unwind_Backtrace (UnwindTraceFn, &state);
826
 
827
  return trace_data.result;
828
}

powered by: WebSVN 2.1.0

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