OSDN Git Service

* config/mips/mips.c (TARGET_SMALL_REGISTER_CLASSES_FOR_MODE_P): Undef.
[pf3gnuchains/gcc-fork.git] / libjava / stacktrace.cc
1 // 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 }