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 // Maps ncode values to their containing native class.
43 // NOTE: Currently this Map contradicts class GC for native classes. This map
44 // (and the "new class stack") will need to use WeakReferences in order to
45 // enable native class GC.
46 java::util::IdentityHashMap
*_Jv_StackTrace::ncodeMap
;
48 // Check the "class stack" for any classes initialized since we were last
49 // called, and add them to ncodeMap.
51 _Jv_StackTrace::UpdateNCodeMap ()
53 // The Map should be large enough so that a typical Java app doesn't cause
54 // it to rehash, without using too much memory. ~5000 entries should be
57 ncodeMap
= new java::util::IdentityHashMap (5087);
60 while ((klass
= _Jv_PopClass ()))
62 //printf ("got %s\n", klass->name->data);
63 for (int i
= 0; i
< klass
->method_count
; i
++)
65 _Jv_Method
*method
= &klass
->methods
[i
];
66 void *ncode
= method
->ncode
;
67 // Add non-abstract methods to ncodeMap.
70 ncode
= UNWRAP_FUNCTION_DESCRIPTOR (ncode
);
71 ncodeMap
->put ((java::lang::Object
*) ncode
, klass
);
77 // Given a native frame, return the class which this code belongs
78 // to. Returns NULL if this IP is not associated with a native Java class.
79 // If NCODE is supplied, it will be set with the ip for the entry point of the
82 _Jv_StackTrace::ClassForFrame (_Jv_StackFrame
*frame
)
84 JvAssert (frame
->type
== frame_native
);
87 // look it up in ncodeMap
90 klass
= (jclass
) ncodeMap
->get ((jobject
) frame
->start_ip
);
92 // Exclude interpreted classes
93 if (klass
!= NULL
&& _Jv_IsInterpretedClass (klass
))
101 _Jv_StackTrace::UnwindTraceFn (struct _Unwind_Context
*context
, void *state_ptr
)
103 _Jv_UnwindState
*state
= (_Jv_UnwindState
*) state_ptr
;
104 jint pos
= state
->pos
;
106 // Check if the trace buffer needs to be extended.
107 if (pos
== state
->length
)
109 int newLength
= state
->length
* 2;
110 void *newFrames
= _Jv_AllocBytes (newLength
* sizeof(_Jv_StackFrame
));
111 memcpy (newFrames
, state
->frames
, state
->length
* sizeof(_Jv_StackFrame
));
112 state
->frames
= (_Jv_StackFrame
*) newFrames
;
113 state
->length
= newLength
;
116 void *func_addr
= (void *) _Unwind_GetRegionStart (context
);
118 // If we see the interpreter's main function, "pop" an entry off the
119 // interpreter stack and use that instead, so that the trace goes through
120 // the java code and not the interpreter itself. This assumes a 1:1
121 // correspondance between call frames in the interpreted stack and occurances
122 // of _Jv_InterpMethod::run() on the native stack.
124 void *interp_run
= NULL
;
126 if (::gnu::classpath::jdwp::Jdwp::isDebugging
)
127 interp_run
= (void *) &_Jv_InterpMethod::run_debug
;
129 interp_run
= (void *) &_Jv_InterpMethod::run
;
131 if (func_addr
== UNWRAP_FUNCTION_DESCRIPTOR (interp_run
))
133 state
->frames
[pos
].type
= frame_interpreter
;
134 _Jv_Frame
*frame
= static_cast<_Jv_Frame
*> (state
->interp_frame
);
135 state
->frames
[pos
].interp
.meth
136 = static_cast<_Jv_InterpMethod
*> (frame
->self
);
137 state
->frames
[pos
].interp
.pc
= state
->interp_frame
->pc
;
138 state
->interp_frame
= state
->interp_frame
->next_interp
;
142 // We handle proxies in the same way as interpreted classes
143 if (_Jv_is_proxy (func_addr
))
145 state
->frames
[pos
].type
= frame_proxy
;
146 state
->frames
[pos
].proxyClass
= state
->interp_frame
->proxyClass
;
147 state
->frames
[pos
].proxyMethod
= state
->interp_frame
->proxyMethod
;
148 state
->interp_frame
= state
->interp_frame
->next_interp
;
152 #ifdef HAVE_GETIPINFO
154 int ip_before_insn
= 0;
155 ip
= _Unwind_GetIPInfo (context
, &ip_before_insn
);
157 // If the unwinder gave us a 'return' address, roll it back a little
158 // to ensure we get the correct line number for the call itself.
159 if (! ip_before_insn
)
162 state
->frames
[pos
].type
= frame_native
;
163 #ifdef HAVE_GETIPINFO
164 state
->frames
[pos
].ip
= (void *) ip
;
166 state
->frames
[pos
].ip
= (void *) _Unwind_GetIP (context
);
168 state
->frames
[pos
].start_ip
= func_addr
;
171 _Unwind_Reason_Code result
= _URC_NO_REASON
;
172 if (state
->trace_function
!= NULL
)
173 result
= (state
->trace_function
) (state
);
178 // Return a raw stack trace from the current point of execution. The raw
179 // trace will include all functions that have unwind info.
181 _Jv_StackTrace::GetStackTrace(void)
183 int trace_size
= 100;
184 _Jv_StackFrame frames
[trace_size
];
185 _Jv_UnwindState
state (trace_size
);
186 state
.frames
= (_Jv_StackFrame
*) &frames
;
188 _Unwind_Backtrace (UnwindTraceFn
, &state
);
190 // Copy the trace and return it.
191 int traceSize
= sizeof (_Jv_StackTrace
) +
192 (sizeof (_Jv_StackFrame
) * state
.pos
);
193 _Jv_StackTrace
*trace
= (_Jv_StackTrace
*) _Jv_AllocBytes (traceSize
);
194 trace
->length
= state
.pos
;
195 memcpy (trace
->frames
, state
.frames
, sizeof (_Jv_StackFrame
) * state
.pos
);
200 _Jv_StackTrace::getLineNumberForFrame(_Jv_StackFrame
*frame
, NameFinder
*finder
,
201 jstring
*sourceFileName
, jint
*lineNum
,
205 if (frame
->type
== frame_interpreter
)
207 _Jv_InterpMethod
*interp_meth
= frame
->interp
.meth
;
208 _Jv_InterpClass
*interp_class
=
209 (_Jv_InterpClass
*) interp_meth
->defining_class
->aux_info
;
210 *sourceFileName
= interp_class
->source_file_name
;
211 // The interpreter advances the PC before executing an instruction,
212 // so roll-back 1 byte to ensure the line number is accurate.
213 *lineNum
= interp_meth
->get_source_line(frame
->interp
.pc
- 1);
218 if (frame
->type
== frame_proxy
)
220 *sourceFileName
= NULL
;
225 // Use _Jv_platform_dladdr() to determine in which binary the address IP
228 jstring binaryName
= NULL
;
229 const char *argv0
= _Jv_GetSafeArg(0);
231 void *ip
= frame
->ip
;
232 _Unwind_Ptr offset
= 0;
234 if (_Jv_platform_dladdr (ip
, &info
))
237 binaryName
= JvNewStringUTF (info
.file_name
);
241 if (*methodName
== NULL
&& info
.sym_name
)
242 *methodName
= JvNewStringUTF (info
.sym_name
);
244 // addr2line expects relative addresses for shared libraries.
245 if (strcmp (info
.file_name
, argv0
) == 0)
246 offset
= (_Unwind_Ptr
) ip
;
248 offset
= (_Unwind_Ptr
) ip
- (_Unwind_Ptr
) info
.base
;
250 #ifndef HAVE_GETIPINFO
251 // The unwinder gives us the return address. In order to get the right
252 // line number for the stack trace, roll it back a little.
256 finder
->lookup (binaryName
, (jlong
) offset
);
257 *sourceFileName
= finder
->getSourceFile();
258 *lineNum
= finder
->getLineNum();
259 if (*lineNum
== -1 && NameFinder::showRaw())
261 gnu::gcj::runtime::StringBuffer
*t
=
262 new gnu::gcj::runtime::StringBuffer(binaryName
);
263 t
->append ((jchar
)' ');
264 t
->append ((jchar
)'[');
265 // + 1 to compensate for the - 1 adjustment above;
266 t
->append (Long::toHexString (offset
+ 1));
267 t
->append ((jchar
)']');
268 *sourceFileName
= t
->toString();
273 // Look up class and method info for the given stack frame, setting
274 // frame->klass and frame->meth if they are known.
276 _Jv_StackTrace::FillInFrameInfo (_Jv_StackFrame
*frame
)
279 _Jv_Method
*meth
= NULL
;
281 if (frame
->type
== frame_native
)
283 klass
= _Jv_StackTrace::ClassForFrame (frame
);
286 // Find method in class
287 for (int j
= 0; j
< klass
->method_count
; j
++)
289 void *wncode
= UNWRAP_FUNCTION_DESCRIPTOR (klass
->methods
[j
].ncode
);
290 if (wncode
== frame
->start_ip
)
292 meth
= &klass
->methods
[j
];
297 else if (frame
->type
== frame_proxy
)
299 klass
= frame
->proxyClass
;
300 meth
= frame
->proxyMethod
;
303 else if (frame
->type
== frame_interpreter
)
305 _Jv_InterpMethod
*interp_meth
= frame
->interp
.meth
;
306 klass
= interp_meth
->defining_class
;
307 meth
= interp_meth
->self
;
311 JvFail ("Unknown frame type");
313 frame
->klass
= klass
;
317 // Convert raw stack frames to a Java array of StackTraceElement objects.
318 JArray
< ::java::lang::StackTraceElement
*>*
319 _Jv_StackTrace::GetStackTraceElements (_Jv_StackTrace
*trace
,
320 Throwable
*throwable
__attribute__((unused
)))
322 ArrayList
*list
= new ArrayList ();
324 #if defined (SJLJ_EXCEPTIONS) && ! defined (WIN32)
325 // We can't use the nCodeMap without unwinder support. Instead,
326 // fake the method name by giving the IP in hex - better than nothing.
327 jstring hex
= JvNewStringUTF ("0x");
329 for (int i
= 0; i
< trace
->length
; i
++)
331 jstring sourceFileName
= NULL
;
333 _Jv_StackFrame
*frame
= &trace
->frames
[i
];
335 jstring className
= NULL
;
336 jstring methodName
= hex
->concat (Long::toHexString ((jlong
) frame
->ip
));
338 StackTraceElement
*element
= new StackTraceElement (sourceFileName
,
339 lineNum
, className
, methodName
, 0);
343 #else /* SJLJ_EXCEPTIONS && !WIN32 */
345 //JvSynchronized (ncodeMap);
348 NameFinder
*finder
= new NameFinder();
350 int end_idx
= trace
->length
- 1;
352 // First pass: strip superfluous frames from beginning and end of the trace.
353 for (int i
= 0; i
< trace
->length
; i
++)
355 _Jv_StackFrame
*frame
= &trace
->frames
[i
];
356 FillInFrameInfo (frame
);
358 if (!frame
->klass
|| !frame
->meth
)
362 // Throw away the top of the stack till we see:
363 // - the constructor(s) of this Throwable, or
364 // - the Throwable.fillInStackTrace call.
365 if (frame
->klass
== throwable
->getClass()
366 && strcmp (frame
->meth
->name
->chars(), "<init>") == 0)
369 if (frame
->klass
== &Throwable::class$
370 && strcmp (frame
->meth
->name
->chars(), "fillInStackTrace") == 0)
373 // End the trace at the application's main() method if we see call_main.
374 if (frame
->klass
== &gnu::java::lang::MainThread::class$
375 && strcmp (frame
->meth
->name
->chars(), "call_main") == 0)
379 const jboolean remove_unknown
380 = gnu::gcj::runtime::NameFinder::removeUnknown();
382 // Second pass: Look up line-number info for remaining frames.
383 for (int i
= start_idx
; i
<= end_idx
; i
++)
385 _Jv_StackFrame
*frame
= &trace
->frames
[i
];
387 if (frame
->klass
== NULL
&& remove_unknown
)
391 jstring className
= NULL
;
392 if (frame
->klass
!= NULL
)
393 className
= frame
->klass
->getName ();
395 jstring methodName
= NULL
;
397 methodName
= JvNewStringUTF (frame
->meth
->name
->chars());
399 jstring sourceFileName
= NULL
;
402 getLineNumberForFrame(frame
, finder
, &sourceFileName
, &lineNum
,
405 StackTraceElement
*element
= new StackTraceElement (sourceFileName
, lineNum
,
406 className
, methodName
, 0);
411 #endif /* SJLJ_EXCEPTIONS && !WIN32 */
413 JArray
<Object
*> *array
= JvNewObjectArray (list
->size (),
414 &StackTraceElement::class$
, NULL
);
416 return (JArray
<StackTraceElement
*>*) list
->toArray (array
);
419 struct CallingClassTraceData
423 _Jv_Method
*foundMeth
;
424 bool seen_checkClass
;
428 _Jv_StackTrace::calling_class_trace_fn (_Jv_UnwindState
*state
)
430 CallingClassTraceData
*trace_data
= (CallingClassTraceData
*)
432 _Jv_StackFrame
*frame
= &state
->frames
[state
->pos
];
433 FillInFrameInfo (frame
);
435 if (trace_data
->seen_checkClass
437 && frame
->klass
!= trace_data
->checkClass
)
439 trace_data
->foundClass
= frame
->klass
;
440 trace_data
->foundMeth
= frame
->meth
;
441 return _URC_NORMAL_STOP
;
444 if (frame
->klass
== trace_data
->checkClass
)
445 trace_data
->seen_checkClass
= true;
447 return _URC_NO_REASON
;
450 // Find the class immediately above the given class on the call stack. Any
451 // intermediate non-Java
452 // frames are ignored. If the calling class could not be determined (eg because
453 // the unwinder is not supported on this platform), NULL is returned.
454 // This function is used to implement calling-classloader checks and reflection
455 // accessibility checks.
456 // CHECKCLASS is typically the class calling GetCallingClass. The first class
457 // above CHECKCLASS on the call stack will be returned.
459 _Jv_StackTrace::GetCallingClass (jclass checkClass
)
461 jclass result
= NULL
;
462 GetCallerInfo (checkClass
, &result
, NULL
);
467 _Jv_StackTrace::GetCallerInfo (jclass checkClass
, jclass
*caller_class
,
468 _Jv_Method
**caller_meth
)
471 _Jv_StackFrame frames
[trace_size
];
472 _Jv_UnwindState
state (trace_size
);
473 state
.frames
= (_Jv_StackFrame
*) &frames
;
475 CallingClassTraceData trace_data
;
476 trace_data
.checkClass
= checkClass
;
477 trace_data
.seen_checkClass
= false;
478 trace_data
.foundClass
= NULL
;
479 trace_data
.foundMeth
= NULL
;
481 state
.trace_function
= calling_class_trace_fn
;
482 state
.trace_data
= (void *) &trace_data
;
484 //JvSynchronized (ncodeMap);
487 _Unwind_Backtrace (UnwindTraceFn
, &state
);
490 *caller_class
= trace_data
.foundClass
;
492 *caller_meth
= trace_data
.foundMeth
;
496 _Jv_StackTrace::non_system_trace_fn (_Jv_UnwindState
*state
)
498 _Jv_StackFrame
*frame
= &state
->frames
[state
->pos
];
499 FillInFrameInfo (frame
);
501 ClassLoader
*classLoader
= NULL
;
505 classLoader
= frame
->klass
->getClassLoaderInternal();
507 if (classLoader
!= NULL
)
509 state
->trace_data
= (void *) classLoader
;
510 return _URC_NORMAL_STOP
;
515 return _URC_NO_REASON
;
519 _Jv_StackTrace::GetFirstNonSystemClassLoader ()
522 _Jv_StackFrame frames
[trace_size
];
523 _Jv_UnwindState
state (trace_size
);
524 state
.frames
= (_Jv_StackFrame
*) &frames
;
525 state
.trace_function
= non_system_trace_fn
;
526 state
.trace_data
= NULL
;
528 //JvSynchronized (ncodeMap);
531 _Unwind_Backtrace (UnwindTraceFn
, &state
);
533 if (state
.trace_data
)
534 return (ClassLoader
*) state
.trace_data
;
539 struct AccessControlTraceData
546 _Jv_StackTrace::accesscontrol_trace_fn (_Jv_UnwindState
*state
)
548 AccessControlTraceData
*trace_data
= (AccessControlTraceData
*)
550 _Jv_StackFrame
*frame
= &state
->frames
[state
->pos
];
551 FillInFrameInfo (frame
);
553 if (!(frame
->klass
&& frame
->meth
))
554 return _URC_NO_REASON
;
556 trace_data
->length
++;
558 // If the previous frame was a call to doPrivileged, then this is
559 // the last frame we look at.
560 if (trace_data
->privileged
)
561 return _URC_NORMAL_STOP
;
563 if (frame
->klass
== &::java::security::AccessController::class$
564 && strcmp (frame
->meth
->name
->chars(), "doPrivileged") == 0)
565 trace_data
->privileged
= true;
567 return _URC_NO_REASON
;
571 _Jv_StackTrace::GetAccessControlStack (void)
573 int trace_size
= 100;
574 _Jv_StackFrame frames
[trace_size
];
575 _Jv_UnwindState
state (trace_size
);
576 state
.frames
= (_Jv_StackFrame
*) &frames
;
578 AccessControlTraceData trace_data
;
579 trace_data
.length
= 0;
580 trace_data
.privileged
= false;
582 state
.trace_function
= accesscontrol_trace_fn
;
583 state
.trace_data
= (void *) &trace_data
;
586 _Unwind_Backtrace (UnwindTraceFn
, &state
);
588 JArray
<jclass
> *classes
= (JArray
<jclass
> *)
589 _Jv_NewObjectArray (trace_data
.length
, &::java::lang::Class::class$
, NULL
);
590 jclass
*c
= elements (classes
);
592 for (int i
= 0, j
= 0; i
< state
.pos
; i
++)
594 _Jv_StackFrame
*frame
= &state
.frames
[i
];
595 if (!frame
->klass
|| !frame
->meth
)
601 jobjectArray result
=
602 (jobjectArray
) _Jv_NewObjectArray (2, &::java::lang::Object::class$
,
604 jobject
*r
= elements (result
);
605 r
[0] = (jobject
) classes
;
606 r
[1] = (jobject
) new Boolean (trace_data
.privileged
);
612 _Jv_StackTrace::GetStackWalkerStack ()
614 int trace_size
= 100;
615 _Jv_StackFrame frames
[trace_size
];
616 _Jv_UnwindState
state (trace_size
);
617 state
.frames
= (_Jv_StackFrame
*) &frames
;
620 _Unwind_Backtrace (UnwindTraceFn
, &state
);
622 int num_frames
= 0, start_frame
= -1;
625 VMSW_GETCLASSCONTEXT
,
626 JLRM_INVOKE_OR_USER_FN
,
629 expect
= VMSW_GETCLASSCONTEXT
;
630 for (int i
= 0; i
< state
.pos
; i
++)
632 _Jv_StackFrame
*frame
= &state
.frames
[i
];
633 FillInFrameInfo (frame
);
634 if (!frame
->klass
|| !frame
->meth
)
639 case VMSW_GETCLASSCONTEXT
:
641 frame
->klass
== &::gnu::classpath::VMStackWalker::class$
642 && strcmp (frame
->meth
->name
->chars(), "getClassContext") == 0);
643 expect
= JLRM_INVOKE_OR_USER_FN
;
646 case JLRM_INVOKE_OR_USER_FN
:
647 if (frame
->klass
!= &::java::lang::reflect::Method::class$
648 || strcmp (frame
->meth
->name
->chars(), "invoke") != 0)
654 if (start_frame
== -1)
659 if (start_frame
!= -1)
661 if (frame
->klass
== &::gnu::java::lang::MainThread::class$
)
666 JvAssert (num_frames
> 0 && start_frame
> 0);
668 JArray
<jclass
> *result
= (JArray
<jclass
> *)
669 _Jv_NewObjectArray (num_frames
, &::java::lang::Class::class$
, NULL
);
670 jclass
*c
= elements (result
);
672 for (int i
= start_frame
, j
= 0; i
< state
.pos
&& j
< num_frames
; i
++)
674 _Jv_StackFrame
*frame
= &state
.frames
[i
];
675 if (!frame
->klass
|| !frame
->meth
)
686 VMSW_GET_CALLING_ITEM
,
687 JLRM_INVOKE_OR_CALLER
,
692 struct StackWalkerTraceData
699 _Jv_StackTrace::stackwalker_trace_fn (_Jv_UnwindState
*state
)
701 StackWalkerTraceData
*trace_data
= (StackWalkerTraceData
*)
703 _Jv_StackFrame
*frame
= &state
->frames
[state
->pos
];
704 FillInFrameInfo (frame
);
706 if (!(frame
->klass
&& frame
->meth
))
707 return _URC_NO_REASON
;
709 switch (trace_data
->expect
)
711 case VMSW_GET_CALLING_ITEM
:
712 JvAssert (frame
->klass
== &::gnu::classpath::VMStackWalker::class$
);
713 trace_data
->expect
= JLRM_INVOKE_OR_CALLER
;
716 case JLRM_INVOKE_OR_CALLER
:
717 if (frame
->klass
== &::java::lang::reflect::Method::class$
718 && strcmp (frame
->meth
->name
->chars(), "invoke") == 0)
719 trace_data
->expect
= CALLER
;
721 trace_data
->expect
= CALLER_OF_CALLER
;
725 trace_data
->expect
= CALLER_OF_CALLER
;
728 case CALLER_OF_CALLER
:
729 trace_data
->result
= frame
->klass
;
730 return _URC_NORMAL_STOP
;
733 return _URC_NO_REASON
;
737 _Jv_StackTrace::GetStackWalkerCallingClass (void)
739 int trace_size
= 100;
740 _Jv_StackFrame frames
[trace_size
];
741 _Jv_UnwindState
state (trace_size
);
742 state
.frames
= (_Jv_StackFrame
*) &frames
;
744 StackWalkerTraceData trace_data
;
745 trace_data
.expect
= VMSW_GET_CALLING_ITEM
;
746 trace_data
.result
= NULL
;
748 state
.trace_function
= stackwalker_trace_fn
;
749 state
.trace_data
= (void *) &trace_data
;
752 _Unwind_Backtrace (UnwindTraceFn
, &state
);
754 return trace_data
.result
;
757 struct StackWalkerNNLTraceData
764 _Jv_StackTrace::stackwalker_nnl_trace_fn (_Jv_UnwindState
*state
)
766 StackWalkerNNLTraceData
*trace_data
= (StackWalkerNNLTraceData
*)
768 _Jv_StackFrame
*frame
= &state
->frames
[state
->pos
];
769 FillInFrameInfo (frame
);
771 if (!(frame
->klass
&& frame
->meth
))
772 return _URC_NO_REASON
;
774 switch (trace_data
->expect
)
776 case VMSW_GET_CALLING_ITEM
:
777 JvAssert (frame
->klass
== &::gnu::classpath::VMStackWalker::class$
);
778 trace_data
->expect
= JLRM_INVOKE_OR_CALLER
;
781 case JLRM_INVOKE_OR_CALLER
:
782 if (frame
->klass
== &::java::lang::reflect::Method::class$
783 && strcmp (frame
->meth
->name
->chars(), "invoke") == 0)
784 trace_data
->expect
= CALLER
;
786 trace_data
->expect
= CALLER_OF_CALLER
;
790 trace_data
->expect
= CALLER_OF_CALLER
;
793 case CALLER_OF_CALLER
:
794 ClassLoader
*cl
= frame
->klass
->getClassLoaderInternal ();
797 trace_data
->result
= cl
;
798 return _URC_NORMAL_STOP
;
802 return _URC_NO_REASON
;
806 _Jv_StackTrace::GetStackWalkerFirstNonNullLoader (void)
808 int trace_size
= 100;
809 _Jv_StackFrame frames
[trace_size
];
810 _Jv_UnwindState
state (trace_size
);
811 state
.frames
= (_Jv_StackFrame
*) &frames
;
813 StackWalkerNNLTraceData trace_data
;
814 trace_data
.expect
= VMSW_GET_CALLING_ITEM
;
815 trace_data
.result
= NULL
;
817 state
.trace_function
= stackwalker_nnl_trace_fn
;
818 state
.trace_data
= (void *) &trace_data
;
821 _Unwind_Backtrace (UnwindTraceFn
, &state
);
823 return trace_data
.result
;