1 // stacktrace.cc - Functions for unwinding & inspecting the call stack.
3 /* Copyright (C) 2005, 2006 Free Software Foundation
5 This file is part of libgcj.
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
16 #include <java-interp.h>
17 #include <java-stack.h>
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>
34 #include <sysdep/backtrace.h>
35 #include <sysdep/descriptor.h>
37 using namespace java::lang
;
38 using namespace java::lang::reflect
;
39 using namespace java::util
;
40 using namespace gnu::gcj::runtime
;
42 #ifdef __ARM_EABI_UNWINDER__
43 #define _URC_NORMAL_STOP _URC_FAILURE
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
;
52 // Check the "class stack" for any classes initialized since we were last
53 // called, and add them to ncodeMap.
55 _Jv_StackTrace::UpdateNCodeMap ()
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
61 ncodeMap
= new java::util::IdentityHashMap (5087);
64 while ((klass
= _Jv_PopClass ()))
66 //printf ("got %s\n", klass->name->data);
67 for (int i
= 0; i
< klass
->method_count
; i
++)
69 _Jv_Method
*method
= &klass
->methods
[i
];
70 void *ncode
= method
->ncode
;
71 // Add non-abstract methods to ncodeMap.
74 ncode
= UNWRAP_FUNCTION_DESCRIPTOR (ncode
);
75 ncodeMap
->put ((java::lang::Object
*) ncode
, klass
);
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
86 _Jv_StackTrace::ClassForFrame (_Jv_StackFrame
*frame
)
88 JvAssert (frame
->type
== frame_native
);
91 // look it up in ncodeMap
94 klass
= (jclass
) ncodeMap
->get ((jobject
) frame
->start_ip
);
96 // Exclude interpreted classes
97 if (klass
!= NULL
&& _Jv_IsInterpretedClass (klass
))
105 _Jv_StackTrace::UnwindTraceFn (struct _Unwind_Context
*context
, void *state_ptr
)
107 _Jv_UnwindState
*state
= (_Jv_UnwindState
*) state_ptr
;
108 jint pos
= state
->pos
;
110 // Check if the trace buffer needs to be extended.
111 if (pos
== state
->length
)
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
;
120 void *func_addr
= (void *) _Unwind_GetRegionStart (context
);
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.
128 void *interp_run
= NULL
;
130 if (::gnu::classpath::jdwp::Jdwp::isDebugging
)
131 interp_run
= (void *) &_Jv_InterpMethod::run_debug
;
133 interp_run
= (void *) &_Jv_InterpMethod::run
;
135 if (func_addr
== UNWRAP_FUNCTION_DESCRIPTOR (interp_run
))
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
;
145 // We handle proxies in the same way as interpreted classes
146 if (_Jv_is_proxy (func_addr
))
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
;
156 #ifdef HAVE_GETIPINFO
158 int ip_before_insn
= 0;
159 ip
= _Unwind_GetIPInfo (context
, &ip_before_insn
);
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
)
166 state
->frames
[pos
].type
= frame_native
;
167 #ifdef HAVE_GETIPINFO
168 state
->frames
[pos
].ip
= (void *) ip
;
170 state
->frames
[pos
].ip
= (void *) _Unwind_GetIP (context
);
172 state
->frames
[pos
].start_ip
= func_addr
;
175 _Unwind_Reason_Code result
= _URC_NO_REASON
;
176 if (state
->trace_function
!= NULL
)
177 result
= (state
->trace_function
) (state
);
182 // Return a raw stack trace from the current point of execution. The raw
183 // trace will include all functions that have unwind info.
185 _Jv_StackTrace::GetStackTrace(void)
187 int trace_size
= 100;
188 _Jv_StackFrame frames
[trace_size
];
189 _Jv_UnwindState
state (trace_size
);
190 state
.frames
= (_Jv_StackFrame
*) &frames
;
192 _Unwind_Backtrace (UnwindTraceFn
, &state
);
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
);
204 _Jv_StackTrace::getLineNumberForFrame(_Jv_StackFrame
*frame
, NameFinder
*finder
,
205 jstring
*sourceFileName
, jint
*lineNum
,
209 if (frame
->type
== frame_interpreter
)
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);
222 if (frame
->type
== frame_proxy
)
224 *sourceFileName
= NULL
;
229 // Use _Jv_platform_dladdr() to determine in which binary the address IP
232 jstring binaryName
= NULL
;
233 const char *argv0
= _Jv_GetSafeArg(0);
235 void *ip
= frame
->ip
;
236 _Unwind_Ptr offset
= 0;
238 if (_Jv_platform_dladdr (ip
, &info
))
241 binaryName
= JvNewStringUTF (info
.file_name
);
245 if (*methodName
== NULL
&& info
.sym_name
)
246 *methodName
= JvNewStringUTF (info
.sym_name
);
248 // addr2line expects relative addresses for shared libraries.
249 if (strcmp (info
.file_name
, argv0
) == 0)
250 offset
= (_Unwind_Ptr
) ip
;
252 offset
= (_Unwind_Ptr
) ip
- (_Unwind_Ptr
) info
.base
;
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.
260 finder
->lookup (binaryName
, (jlong
) offset
);
261 *sourceFileName
= finder
->getSourceFile();
262 *lineNum
= finder
->getLineNum();
263 if (*lineNum
== -1 && NameFinder::showRaw())
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();
277 // Look up class and method info for the given stack frame, setting
278 // frame->klass and frame->meth if they are known.
280 _Jv_StackTrace::FillInFrameInfo (_Jv_StackFrame
*frame
)
283 _Jv_Method
*meth
= NULL
;
285 if (frame
->type
== frame_native
)
287 klass
= _Jv_StackTrace::ClassForFrame (frame
);
290 // Find method in class
291 for (int j
= 0; j
< klass
->method_count
; j
++)
293 void *wncode
= UNWRAP_FUNCTION_DESCRIPTOR (klass
->methods
[j
].ncode
);
294 if (wncode
== frame
->start_ip
)
296 meth
= &klass
->methods
[j
];
301 else if (frame
->type
== frame_proxy
)
303 klass
= frame
->proxyClass
;
304 meth
= frame
->proxyMethod
;
307 else if (frame
->type
== frame_interpreter
)
309 _Jv_InterpMethod
*interp_meth
= frame
->interp
.meth
;
310 klass
= interp_meth
->defining_class
;
311 meth
= interp_meth
->self
;
315 JvFail ("Unknown frame type");
317 frame
->klass
= klass
;
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
)))
326 ArrayList
*list
= new ArrayList ();
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");
333 for (int i
= 0; i
< trace
->length
; i
++)
335 jstring sourceFileName
= NULL
;
337 _Jv_StackFrame
*frame
= &trace
->frames
[i
];
339 jstring className
= NULL
;
340 jstring methodName
= hex
->concat (Long::toHexString ((jlong
) frame
->ip
));
342 StackTraceElement
*element
= new StackTraceElement (sourceFileName
,
343 lineNum
, className
, methodName
, 0);
347 #else /* SJLJ_EXCEPTIONS && !WIN32 */
349 //JvSynchronized (ncodeMap);
352 NameFinder
*finder
= new NameFinder();
354 int end_idx
= trace
->length
- 1;
356 // First pass: strip superfluous frames from beginning and end of the trace.
357 for (int i
= 0; i
< trace
->length
; i
++)
359 _Jv_StackFrame
*frame
= &trace
->frames
[i
];
360 FillInFrameInfo (frame
);
362 if (!frame
->klass
|| !frame
->meth
)
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)
373 if (frame
->klass
== &Throwable::class$
374 && strcmp (frame
->meth
->name
->chars(), "fillInStackTrace") == 0)
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)
383 const jboolean remove_unknown
384 = gnu::gcj::runtime::NameFinder::removeUnknown();
386 // Second pass: Look up line-number info for remaining frames.
387 for (int i
= start_idx
; i
<= end_idx
; i
++)
389 _Jv_StackFrame
*frame
= &trace
->frames
[i
];
391 if (frame
->klass
== NULL
&& remove_unknown
)
395 jstring className
= NULL
;
396 if (frame
->klass
!= NULL
)
397 className
= frame
->klass
->getName ();
399 jstring methodName
= NULL
;
401 methodName
= JvNewStringUTF (frame
->meth
->name
->chars());
403 jstring sourceFileName
= NULL
;
406 getLineNumberForFrame(frame
, finder
, &sourceFileName
, &lineNum
,
409 StackTraceElement
*element
= new StackTraceElement (sourceFileName
, lineNum
,
410 className
, methodName
, 0);
415 #endif /* SJLJ_EXCEPTIONS && !WIN32 */
417 JArray
<Object
*> *array
= JvNewObjectArray (list
->size (),
418 &StackTraceElement::class$
, NULL
);
420 return (JArray
<StackTraceElement
*>*) list
->toArray (array
);
423 struct CallingClassTraceData
427 _Jv_Method
*foundMeth
;
428 bool seen_checkClass
;
432 _Jv_StackTrace::calling_class_trace_fn (_Jv_UnwindState
*state
)
434 CallingClassTraceData
*trace_data
= (CallingClassTraceData
*)
436 _Jv_StackFrame
*frame
= &state
->frames
[state
->pos
];
437 FillInFrameInfo (frame
);
439 if (trace_data
->seen_checkClass
441 && frame
->klass
!= trace_data
->checkClass
)
443 trace_data
->foundClass
= frame
->klass
;
444 trace_data
->foundMeth
= frame
->meth
;
445 return _URC_NORMAL_STOP
;
448 if (frame
->klass
== trace_data
->checkClass
)
449 trace_data
->seen_checkClass
= true;
451 return _URC_NO_REASON
;
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.
463 _Jv_StackTrace::GetCallingClass (jclass checkClass
)
465 jclass result
= NULL
;
466 GetCallerInfo (checkClass
, &result
, NULL
);
471 _Jv_StackTrace::GetCallerInfo (jclass checkClass
, jclass
*caller_class
,
472 _Jv_Method
**caller_meth
)
475 _Jv_StackFrame frames
[trace_size
];
476 _Jv_UnwindState
state (trace_size
);
477 state
.frames
= (_Jv_StackFrame
*) &frames
;
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
;
485 state
.trace_function
= calling_class_trace_fn
;
486 state
.trace_data
= (void *) &trace_data
;
488 //JvSynchronized (ncodeMap);
491 _Unwind_Backtrace (UnwindTraceFn
, &state
);
494 *caller_class
= trace_data
.foundClass
;
496 *caller_meth
= trace_data
.foundMeth
;
500 _Jv_StackTrace::non_system_trace_fn (_Jv_UnwindState
*state
)
502 _Jv_StackFrame
*frame
= &state
->frames
[state
->pos
];
503 FillInFrameInfo (frame
);
505 ClassLoader
*classLoader
= NULL
;
509 classLoader
= frame
->klass
->getClassLoaderInternal();
511 if (classLoader
!= NULL
)
513 state
->trace_data
= (void *) classLoader
;
514 return _URC_NORMAL_STOP
;
519 return _URC_NO_REASON
;
523 _Jv_StackTrace::GetFirstNonSystemClassLoader ()
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
;
532 //JvSynchronized (ncodeMap);
535 _Unwind_Backtrace (UnwindTraceFn
, &state
);
537 if (state
.trace_data
)
538 return (ClassLoader
*) state
.trace_data
;
543 struct AccessControlTraceData
550 _Jv_StackTrace::accesscontrol_trace_fn (_Jv_UnwindState
*state
)
552 AccessControlTraceData
*trace_data
= (AccessControlTraceData
*)
554 _Jv_StackFrame
*frame
= &state
->frames
[state
->pos
];
555 FillInFrameInfo (frame
);
557 if (!(frame
->klass
&& frame
->meth
))
558 return _URC_NO_REASON
;
560 trace_data
->length
++;
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
;
567 if (frame
->klass
== &::java::security::AccessController::class$
568 && strcmp (frame
->meth
->name
->chars(), "doPrivileged") == 0)
569 trace_data
->privileged
= true;
571 return _URC_NO_REASON
;
575 _Jv_StackTrace::GetAccessControlStack (void)
577 int trace_size
= 100;
578 _Jv_StackFrame frames
[trace_size
];
579 _Jv_UnwindState
state (trace_size
);
580 state
.frames
= (_Jv_StackFrame
*) &frames
;
582 AccessControlTraceData trace_data
;
583 trace_data
.length
= 0;
584 trace_data
.privileged
= false;
586 state
.trace_function
= accesscontrol_trace_fn
;
587 state
.trace_data
= (void *) &trace_data
;
590 _Unwind_Backtrace (UnwindTraceFn
, &state
);
592 JArray
<jclass
> *classes
= (JArray
<jclass
> *)
593 _Jv_NewObjectArray (trace_data
.length
, &::java::lang::Class::class$
, NULL
);
594 jclass
*c
= elements (classes
);
596 for (int i
= 0, j
= 0; i
< state
.pos
; i
++)
598 _Jv_StackFrame
*frame
= &state
.frames
[i
];
599 if (!frame
->klass
|| !frame
->meth
)
605 jobjectArray result
=
606 (jobjectArray
) _Jv_NewObjectArray (2, &::java::lang::Object::class$
,
608 jobject
*r
= elements (result
);
609 r
[0] = (jobject
) classes
;
610 r
[1] = (jobject
) new Boolean (trace_data
.privileged
);
616 _Jv_StackTrace::GetStackWalkerStack ()
618 int trace_size
= 100;
619 _Jv_StackFrame frames
[trace_size
];
620 _Jv_UnwindState
state (trace_size
);
621 state
.frames
= (_Jv_StackFrame
*) &frames
;
624 _Unwind_Backtrace (UnwindTraceFn
, &state
);
626 int num_frames
= 0, start_frame
= -1;
629 VMSW_GETCLASSCONTEXT
,
630 JLRM_INVOKE_OR_USER_FN
,
633 expect
= VMSW_GETCLASSCONTEXT
;
634 for (int i
= 0; i
< state
.pos
; i
++)
636 _Jv_StackFrame
*frame
= &state
.frames
[i
];
637 FillInFrameInfo (frame
);
638 if (!frame
->klass
|| !frame
->meth
)
643 case VMSW_GETCLASSCONTEXT
:
645 frame
->klass
== &::gnu::classpath::VMStackWalker::class$
646 && strcmp (frame
->meth
->name
->chars(), "getClassContext") == 0);
647 expect
= JLRM_INVOKE_OR_USER_FN
;
650 case JLRM_INVOKE_OR_USER_FN
:
651 if (frame
->klass
!= &::java::lang::reflect::Method::class$
652 || strcmp (frame
->meth
->name
->chars(), "invoke") != 0)
658 if (start_frame
== -1)
663 if (start_frame
!= -1)
665 if (frame
->klass
== &::gnu::java::lang::MainThread::class$
)
670 JvAssert (num_frames
> 0 && start_frame
> 0);
672 JArray
<jclass
> *result
= (JArray
<jclass
> *)
673 _Jv_NewObjectArray (num_frames
, &::java::lang::Class::class$
, NULL
);
674 jclass
*c
= elements (result
);
676 for (int i
= start_frame
, j
= 0; i
< state
.pos
&& j
< num_frames
; i
++)
678 _Jv_StackFrame
*frame
= &state
.frames
[i
];
679 if (!frame
->klass
|| !frame
->meth
)
690 VMSW_GET_CALLING_ITEM
,
691 JLRM_INVOKE_OR_CALLER
,
696 struct StackWalkerTraceData
703 _Jv_StackTrace::stackwalker_trace_fn (_Jv_UnwindState
*state
)
705 StackWalkerTraceData
*trace_data
= (StackWalkerTraceData
*)
707 _Jv_StackFrame
*frame
= &state
->frames
[state
->pos
];
708 FillInFrameInfo (frame
);
710 if (!(frame
->klass
&& frame
->meth
))
711 return _URC_NO_REASON
;
713 switch (trace_data
->expect
)
715 case VMSW_GET_CALLING_ITEM
:
716 JvAssert (frame
->klass
== &::gnu::classpath::VMStackWalker::class$
);
717 trace_data
->expect
= JLRM_INVOKE_OR_CALLER
;
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
;
725 trace_data
->expect
= CALLER_OF_CALLER
;
729 trace_data
->expect
= CALLER_OF_CALLER
;
732 case CALLER_OF_CALLER
:
733 trace_data
->result
= frame
->klass
;
734 return _URC_NORMAL_STOP
;
737 return _URC_NO_REASON
;
741 _Jv_StackTrace::GetStackWalkerCallingClass (void)
743 int trace_size
= 100;
744 _Jv_StackFrame frames
[trace_size
];
745 _Jv_UnwindState
state (trace_size
);
746 state
.frames
= (_Jv_StackFrame
*) &frames
;
748 StackWalkerTraceData trace_data
;
749 trace_data
.expect
= VMSW_GET_CALLING_ITEM
;
750 trace_data
.result
= NULL
;
752 state
.trace_function
= stackwalker_trace_fn
;
753 state
.trace_data
= (void *) &trace_data
;
756 _Unwind_Backtrace (UnwindTraceFn
, &state
);
758 return trace_data
.result
;
761 struct StackWalkerNNLTraceData
768 _Jv_StackTrace::stackwalker_nnl_trace_fn (_Jv_UnwindState
*state
)
770 StackWalkerNNLTraceData
*trace_data
= (StackWalkerNNLTraceData
*)
772 _Jv_StackFrame
*frame
= &state
->frames
[state
->pos
];
773 FillInFrameInfo (frame
);
775 if (!(frame
->klass
&& frame
->meth
))
776 return _URC_NO_REASON
;
778 switch (trace_data
->expect
)
780 case VMSW_GET_CALLING_ITEM
:
781 JvAssert (frame
->klass
== &::gnu::classpath::VMStackWalker::class$
);
782 trace_data
->expect
= JLRM_INVOKE_OR_CALLER
;
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
;
790 trace_data
->expect
= CALLER_OF_CALLER
;
794 trace_data
->expect
= CALLER_OF_CALLER
;
797 case CALLER_OF_CALLER
:
798 ClassLoader
*cl
= frame
->klass
->getClassLoaderInternal ();
801 trace_data
->result
= cl
;
802 return _URC_NORMAL_STOP
;
806 return _URC_NO_REASON
;
810 _Jv_StackTrace::GetStackWalkerFirstNonNullLoader (void)
812 int trace_size
= 100;
813 _Jv_StackFrame frames
[trace_size
];
814 _Jv_UnwindState
state (trace_size
);
815 state
.frames
= (_Jv_StackFrame
*) &frames
;
817 StackWalkerNNLTraceData trace_data
;
818 trace_data
.expect
= VMSW_GET_CALLING_ITEM
;
819 trace_data
.result
= NULL
;
821 state
.trace_function
= stackwalker_nnl_trace_fn
;
822 state
.trace_data
= (void *) &trace_data
;
825 _Unwind_Backtrace (UnwindTraceFn
, &state
);
827 return trace_data
.result
;