OSDN Git Service

2004-10-18 Andrew Haley <aph@redhat.com>
[pf3gnuchains/gcc-fork.git] / libjava / gnu / gcj / runtime / natStackTrace.cc
1 // natStackTrace.cc - native helper methods for Throwable
2
3 /* Copyright (C) 2000, 2002, 2003  Free Software Foundation, Inc
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 /**
12  * @author Andrew Haley <aph@cygnus.com>
13  * @author Mark Wielaard <mark@klomp.org>
14  *
15  * Native helper methods for VM specific Throwable support.
16  */
17
18 #include <config.h>
19 #include <platform.h>
20
21 #include <string.h>
22
23 #include <jvm.h>
24 #include <gcj/cni.h>
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>
34
35 #include <sys/types.h>
36
37 #include <stdlib.h>
38
39 #include <unistd.h>
40
41 #ifdef HAVE_EXECINFO_H
42 #include <execinfo.h>
43 #endif
44
45 #include <unwind.h>
46
47
48 #ifdef INTERPRETER
49 extern "C" void *_Unwind_FindEnclosingFunction (void *pc)
50   __attribute__((pure));
51 #endif // INTERPRETER
52
53 // Fill in this stack trace with MAXLEN elements starting at offset.
54 void
55 gnu::gcj::runtime::StackTrace::fillInStackTrace (jint maxlen, jint offset)
56 {
57 #ifdef HAVE_BACKTRACE
58   offset += 1;
59   void *_p[maxlen + offset];
60   len = backtrace (_p, maxlen + offset) - offset;
61   void **p = _p + offset;
62   _Jv_frame_info *frame;
63   if (len > 0)
64     {
65 #ifdef INTERPRETER
66       extern void *const _Jv_StartOfInterpreter;
67       extern void * _Jv_EndOfInterpreter;
68
69       java::lang::Thread *thread = java::lang::Thread::currentThread();
70       _Jv_MethodChain *interp_frame
71         = (thread ? reinterpret_cast<_Jv_MethodChain *> (thread->interp_frame)
72            : NULL);
73 #endif // INTERPRETER
74
75       frame = (_Jv_frame_info *) _Jv_Malloc (len * sizeof (_Jv_frame_info));
76       for (int n = 0; n < len; n++)
77         {
78           void *pc = p[n];
79           frame[n].addr = pc;
80
81 #ifdef INTERPRETER
82           frame[n].interp = 0;
83
84           // If _Jv_StartOfInterpreter is NULL either we've never
85           // entered the intepreter or _Unwind_FindEnclosingFunction
86           // is broken.
87           if (__builtin_expect (_Jv_StartOfInterpreter != NULL, false))
88             {
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
94               // find out.
95               if (pc >= _Jv_StartOfInterpreter
96                   && (pc < _Jv_EndOfInterpreter
97                       || _Jv_EndOfInterpreter == NULL))
98                 {
99                   if (_Unwind_FindEnclosingFunction (pc) 
100                       == _Jv_StartOfInterpreter)
101                     {
102                       frame[n].interp = (void *) interp_frame->self;
103                       interp_frame = interp_frame->next;
104                     }
105                   else
106                     {
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;
111                     }
112                 }
113             }
114 #endif // INTERPRETER
115
116         }
117     }
118   else
119     frame = NULL;
120
121   addrs = reinterpret_cast<gnu::gcj::RawData *> (frame);
122 #else // HAVE_BACKTRACE
123   (void)maxlen;
124   (void)offset;
125 #endif // HAVE_BACKTRACE
126 }
127
128 /* Obtain the next power-of-2 of some integer.  */
129 static inline jint
130 nextpowerof2 (jint n)
131 {
132   n |= (n >> 1);
133   n |= (n >> 2);
134   n |= (n >> 4);
135   n |= (n >> 8);
136   n |= (n >> 16);
137   return n+1;
138 }
139
140 #define GET_FRAME(N)                                            \
141 ({                                                              \
142   if ((N) >= len)                                               \
143     fillInStackTrace (nextpowerof2 (N), 1);                     \
144   if ((N) < 0 || (N) >= len)                                    \
145     throw new ::java::lang::ArrayIndexOutOfBoundsException ();  \
146                                                                 \
147   _Jv_frame_info *frame = (_Jv_frame_info *)addrs;              \
148   &frame[N];                                                    \
149 })
150
151 gnu::gcj::runtime::MethodRef *
152 gnu::gcj::runtime::StackTrace::getCompiledMethodRef (gnu::gcj::RawData *addr)
153 {
154   void *p = _Unwind_FindEnclosingFunction (addr);
155   return gnu::gcj::runtime::StackTrace
156     ::methodAtAddress ((gnu::gcj::RawData *)p);
157 }
158
159 java::lang::Class *
160 gnu::gcj::runtime::StackTrace::getClass (gnu::gcj::RawData *p)
161 {
162   gnu::gcj::runtime::MethodRef *ref = getCompiledMethodRef (p);
163   if (ref)
164     return ref->klass;
165   else
166     return NULL;
167 }
168
169 java::lang::Class *
170 gnu::gcj::runtime::StackTrace::classAt (jint n)
171 {
172   _Jv_frame_info *frame = GET_FRAME (n);
173
174 #ifdef INTERPRETER
175   if (frame->interp)
176     {
177       _Jv_InterpMethod *meth
178         = reinterpret_cast<_Jv_InterpMethod *> (frame->interp);
179       return meth->defining_class;
180     }
181 #endif // INTERPRETER
182   
183   return getClass ((gnu::gcj::RawData *)frame->addr);
184 }
185
186 java::lang::String*
187 gnu::gcj::runtime::StackTrace::methodAt (jint n)
188 {
189   _Jv_frame_info *frame = GET_FRAME (n);
190   _Jv_Method *meth = NULL;
191
192 #ifdef INTERPRETER
193   if (frame->interp)
194     {
195       meth
196         = reinterpret_cast<_Jv_InterpMethod *> (frame->interp)
197         ->get_method();
198     }
199 #endif // INTERPRETER
200   
201   if (! meth)
202     {
203       gnu::gcj::runtime::MethodRef *ref
204         = getCompiledMethodRef ((gnu::gcj::RawData *)frame->addr);
205       if (ref)
206         meth = (_Jv_Method *)ref->method;
207     }
208
209   return meth 
210     ? _Jv_NewStringUtf8Const (meth->name)
211     : NULL ;
212 }
213
214 void
215 gnu::gcj::runtime::StackTrace::update(void)
216 {
217   jclass klass;
218
219   while ((klass = _Jv_PopClass ()))
220     {
221       for (int i=0; i<klass->method_count; i++)
222         {
223           JvSynchronize sync (map);
224           _Jv_Method *meth = &(klass->methods[i]);
225           if (meth->ncode) // i.e. if p is not abstract
226             {
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);
231             }
232         }
233     }
234 }
235
236 void
237 gnu::gcj::runtime::StackTrace::finalize(void)
238 {
239   if (addrs != NULL)
240     _Jv_Free (addrs);
241 }