1 // natStackTrace.cc - native helper methods for Throwable
3 /* Copyright (C) 2000, 2002, 2003 Free Software Foundation, Inc
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
12 * @author Andrew Haley <aph@cygnus.com>
13 * @author Mark Wielaard <mark@klomp.org>
15 * Native helper methods for VM specific Throwable support.
25 #include <gnu/gcj/RawData.h>
26 #include <java/lang/Object.h>
27 #include <java-threads.h>
28 #include <gnu/gcj/runtime/MethodRef.h>
29 #include <gnu/gcj/runtime/StackTrace.h>
30 #include <java/lang/Thread.h>
31 #include <java-interp.h>
32 #include <java/util/IdentityHashMap.h>
33 #include <java/lang/ArrayIndexOutOfBoundsException.h>
35 #include <sys/types.h>
41 #ifdef HAVE_EXECINFO_H
49 extern "C" void *_Unwind_FindEnclosingFunction (void *pc
)
50 __attribute__((pure
));
53 // Fill in this stack trace with MAXLEN elements starting at offset.
55 gnu::gcj::runtime::StackTrace::fillInStackTrace (jint maxlen
, jint offset
)
59 void *_p
[maxlen
+ offset
];
60 len
= backtrace (_p
, maxlen
+ offset
) - offset
;
61 void **p
= _p
+ offset
;
62 _Jv_frame_info
*frame
;
66 extern void *const _Jv_StartOfInterpreter
;
67 extern void * _Jv_EndOfInterpreter
;
69 java::lang::Thread
*thread
= java::lang::Thread::currentThread();
70 _Jv_MethodChain
*interp_frame
71 = (thread
? reinterpret_cast<_Jv_MethodChain
*> (thread
->interp_frame
)
75 frame
= (_Jv_frame_info
*) _Jv_Malloc (len
* sizeof (_Jv_frame_info
));
76 for (int n
= 0; n
< len
; n
++)
84 // If _Jv_StartOfInterpreter is NULL either we've never
85 // entered the intepreter or _Unwind_FindEnclosingFunction
87 if (__builtin_expect (_Jv_StartOfInterpreter
!= NULL
, false))
89 // _Jv_StartOfInterpreter marks the very first
90 // instruction in the interpreter, but
91 // _Jv_EndOfInterpreter is an upper bound. If PC is
92 // less than _Jv_EndOfInterpreter it might be in the
93 // interpreter: we call _Unwind_FindEnclosingFunction to
95 if (pc
>= _Jv_StartOfInterpreter
96 && (pc
< _Jv_EndOfInterpreter
97 || _Jv_EndOfInterpreter
== NULL
))
99 if (_Unwind_FindEnclosingFunction (pc
)
100 == _Jv_StartOfInterpreter
)
102 frame
[n
].interp
= (void *) interp_frame
->self
;
103 interp_frame
= interp_frame
->next
;
107 // We've found an address that we know is not within
108 // the interpreter. We use that to refine our upper
109 // bound on where the interpreter ends.
110 _Jv_EndOfInterpreter
= pc
;
114 #endif // INTERPRETER
121 addrs
= reinterpret_cast<gnu::gcj::RawData
*> (frame
);
122 #else // HAVE_BACKTRACE
125 #endif // HAVE_BACKTRACE
128 /* Obtain the next power-of-2 of some integer. */
130 nextpowerof2 (jint n
)
140 #define GET_FRAME(N) \
143 fillInStackTrace (nextpowerof2 (N), 1); \
144 if ((N) < 0 || (N) >= len) \
145 throw new ::java::lang::ArrayIndexOutOfBoundsException (); \
147 _Jv_frame_info *frame = (_Jv_frame_info *)addrs; \
151 gnu::gcj::runtime::MethodRef
*
152 gnu::gcj::runtime::StackTrace::getCompiledMethodRef (gnu::gcj::RawData
*addr
)
154 void *p
= _Unwind_FindEnclosingFunction (addr
);
155 return gnu::gcj::runtime::StackTrace
156 ::methodAtAddress ((gnu::gcj::RawData
*)p
);
160 gnu::gcj::runtime::StackTrace::getClass (gnu::gcj::RawData
*p
)
162 gnu::gcj::runtime::MethodRef
*ref
= getCompiledMethodRef (p
);
170 gnu::gcj::runtime::StackTrace::classAt (jint n
)
172 _Jv_frame_info
*frame
= GET_FRAME (n
);
177 _Jv_InterpMethod
*meth
178 = reinterpret_cast<_Jv_InterpMethod
*> (frame
->interp
);
179 return meth
->defining_class
;
181 #endif // INTERPRETER
183 return getClass ((gnu::gcj::RawData
*)frame
->addr
);
187 gnu::gcj::runtime::StackTrace::methodAt (jint n
)
189 _Jv_frame_info
*frame
= GET_FRAME (n
);
190 _Jv_Method
*meth
= NULL
;
196 = reinterpret_cast<_Jv_InterpMethod
*> (frame
->interp
)
199 #endif // INTERPRETER
203 gnu::gcj::runtime::MethodRef
*ref
204 = getCompiledMethodRef ((gnu::gcj::RawData
*)frame
->addr
);
206 meth
= (_Jv_Method
*)ref
->method
;
210 ? _Jv_NewStringUtf8Const (meth
->name
)
215 gnu::gcj::runtime::StackTrace::update(void)
219 while ((klass
= _Jv_PopClass ()))
221 for (int i
=0; i
<klass
->method_count
; i
++)
223 JvSynchronize
sync (map
);
224 _Jv_Method
*meth
= &(klass
->methods
[i
]);
225 if (meth
->ncode
) // i.e. if p is not abstract
227 gnu::gcj::runtime::MethodRef
*ref
228 = new gnu::gcj::runtime::MethodRef
229 ((gnu::gcj::RawData
*)meth
, klass
);
230 map
->put ((java::lang::Object
*)(meth
->ncode
), ref
);
237 gnu::gcj::runtime::StackTrace::finalize(void)