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 state
->frames
[pos
].interp
.meth
= state
->interp_frame
->self
;
135 state
->frames
[pos
].interp
.pc
= state
->interp_frame
->pc
;
136 state
->interp_frame
= state
->interp_frame
->next
;
140 // We handle proxies in the same way as interpreted classes
141 if (_Jv_is_proxy (func_addr
))
143 state
->frames
[pos
].type
= frame_proxy
;
144 state
->frames
[pos
].proxyClass
= state
->interp_frame
->proxyClass
;
145 state
->frames
[pos
].proxyMethod
= state
->interp_frame
->proxyMethod
;
146 state
->interp_frame
= state
->interp_frame
->next
;
150 #ifdef HAVE_GETIPINFO
152 int ip_before_insn
= 0;
153 ip
= _Unwind_GetIPInfo (context
, &ip_before_insn
);
155 // If the unwinder gave us a 'return' address, roll it back a little
156 // to ensure we get the correct line number for the call itself.
157 if (! ip_before_insn
)
160 state
->frames
[pos
].type
= frame_native
;
161 #ifdef HAVE_GETIPINFO
162 state
->frames
[pos
].ip
= (void *) ip
;
164 state
->frames
[pos
].ip
= (void *) _Unwind_GetIP (context
);
166 state
->frames
[pos
].start_ip
= func_addr
;
169 _Unwind_Reason_Code result
= _URC_NO_REASON
;
170 if (state
->trace_function
!= NULL
)
171 result
= (state
->trace_function
) (state
);
176 // Return a raw stack trace from the current point of execution. The raw
177 // trace will include all functions that have unwind info.
179 _Jv_StackTrace::GetStackTrace(void)
181 int trace_size
= 100;
182 _Jv_StackFrame frames
[trace_size
];
183 _Jv_UnwindState
state (trace_size
);
184 state
.frames
= (_Jv_StackFrame
*) &frames
;
186 _Unwind_Backtrace (UnwindTraceFn
, &state
);
188 // Copy the trace and return it.
189 int traceSize
= sizeof (_Jv_StackTrace
) +
190 (sizeof (_Jv_StackFrame
) * state
.pos
);
191 _Jv_StackTrace
*trace
= (_Jv_StackTrace
*) _Jv_AllocBytes (traceSize
);
192 trace
->length
= state
.pos
;
193 memcpy (trace
->frames
, state
.frames
, sizeof (_Jv_StackFrame
) * state
.pos
);
198 _Jv_StackTrace::getLineNumberForFrame(_Jv_StackFrame
*frame
, NameFinder
*finder
,
199 jstring
*sourceFileName
, jint
*lineNum
,
203 if (frame
->type
== frame_interpreter
)
205 _Jv_InterpMethod
*interp_meth
= frame
->interp
.meth
;
206 _Jv_InterpClass
*interp_class
=
207 (_Jv_InterpClass
*) interp_meth
->defining_class
->aux_info
;
208 *sourceFileName
= interp_class
->source_file_name
;
209 // The interpreter advances the PC before executing an instruction,
210 // so roll-back 1 byte to ensure the line number is accurate.
211 *lineNum
= interp_meth
->get_source_line(frame
->interp
.pc
- 1);
216 if (frame
->type
== frame_proxy
)
218 *sourceFileName
= NULL
;
223 // Use _Jv_platform_dladdr() to determine in which binary the address IP
226 jstring binaryName
= NULL
;
227 const char *argv0
= _Jv_GetSafeArg(0);
229 void *ip
= frame
->ip
;
230 _Unwind_Ptr offset
= 0;
232 if (_Jv_platform_dladdr (ip
, &info
))
235 binaryName
= JvNewStringUTF (info
.file_name
);
239 if (*methodName
== NULL
&& info
.sym_name
)
240 *methodName
= JvNewStringUTF (info
.sym_name
);
242 // addr2line expects relative addresses for shared libraries.
243 if (strcmp (info
.file_name
, argv0
) == 0)
244 offset
= (_Unwind_Ptr
) ip
;
246 offset
= (_Unwind_Ptr
) ip
- (_Unwind_Ptr
) info
.base
;
248 #ifndef HAVE_GETIPINFO
249 // The unwinder gives us the return address. In order to get the right
250 // line number for the stack trace, roll it back a little.
254 finder
->lookup (binaryName
, (jlong
) offset
);
255 *sourceFileName
= finder
->getSourceFile();
256 *lineNum
= finder
->getLineNum();
257 if (*lineNum
== -1 && NameFinder::showRaw())
259 gnu::gcj::runtime::StringBuffer
*t
=
260 new gnu::gcj::runtime::StringBuffer(binaryName
);
261 t
->append ((jchar
)' ');
262 t
->append ((jchar
)'[');
263 // + 1 to compensate for the - 1 adjustment above;
264 t
->append (Long::toHexString (offset
+ 1));
265 t
->append ((jchar
)']');
266 *sourceFileName
= t
->toString();
271 // Look up class and method info for the given stack frame, setting
272 // frame->klass and frame->meth if they are known.
274 _Jv_StackTrace::FillInFrameInfo (_Jv_StackFrame
*frame
)
277 _Jv_Method
*meth
= NULL
;
279 if (frame
->type
== frame_native
)
281 klass
= _Jv_StackTrace::ClassForFrame (frame
);
284 // Find method in class
285 for (int j
= 0; j
< klass
->method_count
; j
++)
287 void *wncode
= UNWRAP_FUNCTION_DESCRIPTOR (klass
->methods
[j
].ncode
);
288 if (wncode
== frame
->start_ip
)
290 meth
= &klass
->methods
[j
];
295 else if (frame
->type
== frame_proxy
)
297 klass
= frame
->proxyClass
;
298 meth
= frame
->proxyMethod
;
301 else if (frame
->type
== frame_interpreter
)
303 _Jv_InterpMethod
*interp_meth
= frame
->interp
.meth
;
304 klass
= interp_meth
->defining_class
;
305 meth
= interp_meth
->self
;
309 JvFail ("Unknown frame type");
311 frame
->klass
= klass
;
315 // Convert raw stack frames to a Java array of StackTraceElement objects.
316 JArray
< ::java::lang::StackTraceElement
*>*
317 _Jv_StackTrace::GetStackTraceElements (_Jv_StackTrace
*trace
,
318 Throwable
*throwable
__attribute__((unused
)))
320 ArrayList
*list
= new ArrayList ();
322 #if defined (SJLJ_EXCEPTIONS) && ! defined (WIN32)
323 // We can't use the nCodeMap without unwinder support. Instead,
324 // fake the method name by giving the IP in hex - better than nothing.
325 jstring hex
= JvNewStringUTF ("0x");
327 for (int i
= 0; i
< trace
->length
; i
++)
329 jstring sourceFileName
= NULL
;
331 _Jv_StackFrame
*frame
= &trace
->frames
[i
];
333 jstring className
= NULL
;
334 jstring methodName
= hex
->concat (Long::toHexString ((jlong
) frame
->ip
));
336 StackTraceElement
*element
= new StackTraceElement (sourceFileName
,
337 lineNum
, className
, methodName
, 0);
341 #else /* SJLJ_EXCEPTIONS && !WIN32 */
343 //JvSynchronized (ncodeMap);
346 NameFinder
*finder
= new NameFinder();
348 int end_idx
= trace
->length
- 1;
350 // First pass: strip superfluous frames from beginning and end of the trace.
351 for (int i
= 0; i
< trace
->length
; i
++)
353 _Jv_StackFrame
*frame
= &trace
->frames
[i
];
354 FillInFrameInfo (frame
);
356 if (!frame
->klass
|| !frame
->meth
)
360 // Throw away the top of the stack till we see:
361 // - the constructor(s) of this Throwable, or
362 // - the Throwable.fillInStackTrace call.
363 if (frame
->klass
== throwable
->getClass()
364 && strcmp (frame
->meth
->name
->chars(), "<init>") == 0)
367 if (frame
->klass
== &Throwable::class$
368 && strcmp (frame
->meth
->name
->chars(), "fillInStackTrace") == 0)
371 // End the trace at the application's main() method if we see call_main.
372 if (frame
->klass
== &gnu::java::lang::MainThread::class$
373 && strcmp (frame
->meth
->name
->chars(), "call_main") == 0)
377 const jboolean remove_unknown
378 = gnu::gcj::runtime::NameFinder::removeUnknown();
380 // Second pass: Look up line-number info for remaining frames.
381 for (int i
= start_idx
; i
<= end_idx
; i
++)
383 _Jv_StackFrame
*frame
= &trace
->frames
[i
];
385 if (frame
->klass
== NULL
&& remove_unknown
)
389 jstring className
= NULL
;
390 if (frame
->klass
!= NULL
)
391 className
= frame
->klass
->getName ();
393 jstring methodName
= NULL
;
395 methodName
= JvNewStringUTF (frame
->meth
->name
->chars());
397 jstring sourceFileName
= NULL
;
400 getLineNumberForFrame(frame
, finder
, &sourceFileName
, &lineNum
,
403 StackTraceElement
*element
= new StackTraceElement (sourceFileName
, lineNum
,
404 className
, methodName
, 0);
409 #endif /* SJLJ_EXCEPTIONS && !WIN32 */
411 JArray
<Object
*> *array
= JvNewObjectArray (list
->size (),
412 &StackTraceElement::class$
, NULL
);
414 return (JArray
<StackTraceElement
*>*) list
->toArray (array
);
417 struct CallingClassTraceData
421 _Jv_Method
*foundMeth
;
422 bool seen_checkClass
;
426 _Jv_StackTrace::calling_class_trace_fn (_Jv_UnwindState
*state
)
428 CallingClassTraceData
*trace_data
= (CallingClassTraceData
*)
430 _Jv_StackFrame
*frame
= &state
->frames
[state
->pos
];
431 FillInFrameInfo (frame
);
433 if (trace_data
->seen_checkClass
435 && frame
->klass
!= trace_data
->checkClass
)
437 trace_data
->foundClass
= frame
->klass
;
438 trace_data
->foundMeth
= frame
->meth
;
439 return _URC_NORMAL_STOP
;
442 if (frame
->klass
== trace_data
->checkClass
)
443 trace_data
->seen_checkClass
= true;
445 return _URC_NO_REASON
;
448 // Find the class immediately above the given class on the call stack. Any
449 // intermediate non-Java
450 // frames are ignored. If the calling class could not be determined (eg because
451 // the unwinder is not supported on this platform), NULL is returned.
452 // This function is used to implement calling-classloader checks and reflection
453 // accessibility checks.
454 // CHECKCLASS is typically the class calling GetCallingClass. The first class
455 // above CHECKCLASS on the call stack will be returned.
457 _Jv_StackTrace::GetCallingClass (jclass checkClass
)
459 jclass result
= NULL
;
460 GetCallerInfo (checkClass
, &result
, NULL
);
465 _Jv_StackTrace::GetCallerInfo (jclass checkClass
, jclass
*caller_class
,
466 _Jv_Method
**caller_meth
)
469 _Jv_StackFrame frames
[trace_size
];
470 _Jv_UnwindState
state (trace_size
);
471 state
.frames
= (_Jv_StackFrame
*) &frames
;
473 CallingClassTraceData trace_data
;
474 trace_data
.checkClass
= checkClass
;
475 trace_data
.seen_checkClass
= false;
476 trace_data
.foundClass
= NULL
;
477 trace_data
.foundMeth
= NULL
;
479 state
.trace_function
= calling_class_trace_fn
;
480 state
.trace_data
= (void *) &trace_data
;
482 //JvSynchronized (ncodeMap);
485 _Unwind_Backtrace (UnwindTraceFn
, &state
);
488 *caller_class
= trace_data
.foundClass
;
490 *caller_meth
= trace_data
.foundMeth
;
494 _Jv_StackTrace::non_system_trace_fn (_Jv_UnwindState
*state
)
496 _Jv_StackFrame
*frame
= &state
->frames
[state
->pos
];
497 FillInFrameInfo (frame
);
499 ClassLoader
*classLoader
= NULL
;
503 classLoader
= frame
->klass
->getClassLoaderInternal();
505 if (classLoader
!= NULL
)
507 state
->trace_data
= (void *) classLoader
;
508 return _URC_NORMAL_STOP
;
513 return _URC_NO_REASON
;
517 _Jv_StackTrace::GetFirstNonSystemClassLoader ()
520 _Jv_StackFrame frames
[trace_size
];
521 _Jv_UnwindState
state (trace_size
);
522 state
.frames
= (_Jv_StackFrame
*) &frames
;
523 state
.trace_function
= non_system_trace_fn
;
524 state
.trace_data
= NULL
;
526 //JvSynchronized (ncodeMap);
529 _Unwind_Backtrace (UnwindTraceFn
, &state
);
531 if (state
.trace_data
)
532 return (ClassLoader
*) state
.trace_data
;
537 struct AccessControlTraceData
544 _Jv_StackTrace::accesscontrol_trace_fn (_Jv_UnwindState
*state
)
546 AccessControlTraceData
*trace_data
= (AccessControlTraceData
*)
548 _Jv_StackFrame
*frame
= &state
->frames
[state
->pos
];
549 FillInFrameInfo (frame
);
551 if (!(frame
->klass
&& frame
->meth
))
552 return _URC_NO_REASON
;
554 trace_data
->length
++;
556 // If the previous frame was a call to doPrivileged, then this is
557 // the last frame we look at.
558 if (trace_data
->privileged
)
559 return _URC_NORMAL_STOP
;
561 if (frame
->klass
== &::java::security::AccessController::class$
562 && strcmp (frame
->meth
->name
->chars(), "doPrivileged") == 0)
563 trace_data
->privileged
= true;
565 return _URC_NO_REASON
;
569 _Jv_StackTrace::GetAccessControlStack (void)
571 int trace_size
= 100;
572 _Jv_StackFrame frames
[trace_size
];
573 _Jv_UnwindState
state (trace_size
);
574 state
.frames
= (_Jv_StackFrame
*) &frames
;
576 AccessControlTraceData trace_data
;
577 trace_data
.length
= 0;
578 trace_data
.privileged
= false;
580 state
.trace_function
= accesscontrol_trace_fn
;
581 state
.trace_data
= (void *) &trace_data
;
584 _Unwind_Backtrace (UnwindTraceFn
, &state
);
586 JArray
<jclass
> *classes
= (JArray
<jclass
> *)
587 _Jv_NewObjectArray (trace_data
.length
, &::java::lang::Class::class$
, NULL
);
588 jclass
*c
= elements (classes
);
590 for (int i
= 0, j
= 0; i
< state
.pos
; i
++)
592 _Jv_StackFrame
*frame
= &state
.frames
[i
];
593 if (!frame
->klass
|| !frame
->meth
)
599 jobjectArray result
=
600 (jobjectArray
) _Jv_NewObjectArray (2, &::java::lang::Object::class$
,
602 jobject
*r
= elements (result
);
603 r
[0] = (jobject
) classes
;
604 r
[1] = (jobject
) new Boolean (trace_data
.privileged
);
610 _Jv_StackTrace::GetStackWalkerStack ()
612 int trace_size
= 100;
613 _Jv_StackFrame frames
[trace_size
];
614 _Jv_UnwindState
state (trace_size
);
615 state
.frames
= (_Jv_StackFrame
*) &frames
;
618 _Unwind_Backtrace (UnwindTraceFn
, &state
);
620 int num_frames
= 0, start_frame
= -1;
623 VMSW_GETCLASSCONTEXT
,
624 JLRM_INVOKE_OR_USER_FN
,
627 expect
= VMSW_GETCLASSCONTEXT
;
628 for (int i
= 0; i
< state
.pos
; i
++)
630 _Jv_StackFrame
*frame
= &state
.frames
[i
];
631 FillInFrameInfo (frame
);
632 if (!frame
->klass
|| !frame
->meth
)
637 case VMSW_GETCLASSCONTEXT
:
639 frame
->klass
== &::gnu::classpath::VMStackWalker::class$
640 && strcmp (frame
->meth
->name
->chars(), "getClassContext") == 0);
641 expect
= JLRM_INVOKE_OR_USER_FN
;
644 case JLRM_INVOKE_OR_USER_FN
:
645 if (frame
->klass
!= &::java::lang::reflect::Method::class$
646 || strcmp (frame
->meth
->name
->chars(), "invoke") != 0)
652 if (start_frame
== -1)
657 if (start_frame
!= -1)
659 if (frame
->klass
== &::gnu::java::lang::MainThread::class$
)
664 JvAssert (num_frames
> 0 && start_frame
> 0);
666 JArray
<jclass
> *result
= (JArray
<jclass
> *)
667 _Jv_NewObjectArray (num_frames
, &::java::lang::Class::class$
, NULL
);
668 jclass
*c
= elements (result
);
670 for (int i
= start_frame
, j
= 0; i
< state
.pos
&& j
< num_frames
; i
++)
672 _Jv_StackFrame
*frame
= &state
.frames
[i
];
673 if (!frame
->klass
|| !frame
->meth
)
684 VMSW_GET_CALLING_ITEM
,
685 JLRM_INVOKE_OR_CALLER
,
690 struct StackWalkerTraceData
697 _Jv_StackTrace::stackwalker_trace_fn (_Jv_UnwindState
*state
)
699 StackWalkerTraceData
*trace_data
= (StackWalkerTraceData
*)
701 _Jv_StackFrame
*frame
= &state
->frames
[state
->pos
];
702 FillInFrameInfo (frame
);
704 if (!(frame
->klass
&& frame
->meth
))
705 return _URC_NO_REASON
;
707 switch (trace_data
->expect
)
709 case VMSW_GET_CALLING_ITEM
:
710 JvAssert (frame
->klass
== &::gnu::classpath::VMStackWalker::class$
);
711 trace_data
->expect
= JLRM_INVOKE_OR_CALLER
;
714 case JLRM_INVOKE_OR_CALLER
:
715 if (frame
->klass
== &::java::lang::reflect::Method::class$
716 && strcmp (frame
->meth
->name
->chars(), "invoke") == 0)
717 trace_data
->expect
= CALLER
;
719 trace_data
->expect
= CALLER_OF_CALLER
;
723 trace_data
->expect
= CALLER_OF_CALLER
;
726 case CALLER_OF_CALLER
:
727 trace_data
->result
= frame
->klass
;
728 return _URC_NORMAL_STOP
;
731 return _URC_NO_REASON
;
735 _Jv_StackTrace::GetStackWalkerCallingClass (void)
737 int trace_size
= 100;
738 _Jv_StackFrame frames
[trace_size
];
739 _Jv_UnwindState
state (trace_size
);
740 state
.frames
= (_Jv_StackFrame
*) &frames
;
742 StackWalkerTraceData trace_data
;
743 trace_data
.expect
= VMSW_GET_CALLING_ITEM
;
744 trace_data
.result
= NULL
;
746 state
.trace_function
= stackwalker_trace_fn
;
747 state
.trace_data
= (void *) &trace_data
;
750 _Unwind_Backtrace (UnwindTraceFn
, &state
);
752 return trace_data
.result
;
755 struct StackWalkerNNLTraceData
762 _Jv_StackTrace::stackwalker_nnl_trace_fn (_Jv_UnwindState
*state
)
764 StackWalkerNNLTraceData
*trace_data
= (StackWalkerNNLTraceData
*)
766 _Jv_StackFrame
*frame
= &state
->frames
[state
->pos
];
767 FillInFrameInfo (frame
);
769 if (!(frame
->klass
&& frame
->meth
))
770 return _URC_NO_REASON
;
772 switch (trace_data
->expect
)
774 case VMSW_GET_CALLING_ITEM
:
775 JvAssert (frame
->klass
== &::gnu::classpath::VMStackWalker::class$
);
776 trace_data
->expect
= JLRM_INVOKE_OR_CALLER
;
779 case JLRM_INVOKE_OR_CALLER
:
780 if (frame
->klass
== &::java::lang::reflect::Method::class$
781 && strcmp (frame
->meth
->name
->chars(), "invoke") == 0)
782 trace_data
->expect
= CALLER
;
784 trace_data
->expect
= CALLER_OF_CALLER
;
788 trace_data
->expect
= CALLER_OF_CALLER
;
791 case CALLER_OF_CALLER
:
792 ClassLoader
*cl
= frame
->klass
->getClassLoaderInternal ();
795 trace_data
->result
= cl
;
796 return _URC_NORMAL_STOP
;
800 return _URC_NO_REASON
;
804 _Jv_StackTrace::GetStackWalkerFirstNonNullLoader (void)
806 int trace_size
= 100;
807 _Jv_StackFrame frames
[trace_size
];
808 _Jv_UnwindState
state (trace_size
);
809 state
.frames
= (_Jv_StackFrame
*) &frames
;
811 StackWalkerNNLTraceData trace_data
;
812 trace_data
.expect
= VMSW_GET_CALLING_ITEM
;
813 trace_data
.result
= NULL
;
815 state
.trace_function
= stackwalker_nnl_trace_fn
;
816 state
.trace_data
= (void *) &trace_data
;
819 _Unwind_Backtrace (UnwindTraceFn
, &state
);
821 return trace_data
.result
;