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 | // Fill in this stack trace with MAXLEN elements starting at offset.
|
---|
49 | void
|
---|
50 | gnu::gcj::runtime::StackTrace::fillInStackTrace (jint maxlen, jint offset)
|
---|
51 | {
|
---|
52 | #ifdef HAVE_BACKTRACE
|
---|
53 | offset += 1;
|
---|
54 | void *_p[maxlen + offset];
|
---|
55 | len = backtrace (_p, maxlen + offset) - offset;
|
---|
56 | void **p = _p + offset;
|
---|
57 | _Jv_frame_info *frame;
|
---|
58 | if (len > 0)
|
---|
59 | {
|
---|
60 | #ifdef INTERPRETER
|
---|
61 | extern void _Jv_StartOfInterpreter (void);
|
---|
62 | extern void _Jv_EndOfInterpreter (void);
|
---|
63 |
|
---|
64 | java::lang::Thread *thread = java::lang::Thread::currentThread();
|
---|
65 | _Jv_MethodChain *interp_frame
|
---|
66 | = (thread ? reinterpret_cast<_Jv_MethodChain *> (thread->interp_frame)
|
---|
67 | : NULL);
|
---|
68 | #endif // INTERPRETER
|
---|
69 |
|
---|
70 | frame = (_Jv_frame_info *) _Jv_Malloc (len * sizeof (_Jv_frame_info));
|
---|
71 | for (int n = 0; n < len; n++)
|
---|
72 | {
|
---|
73 | frame[n].addr = p[n];
|
---|
74 | #ifdef INTERPRETER
|
---|
75 | if (p[n] >= &_Jv_StartOfInterpreter && p[n] <= &_Jv_EndOfInterpreter)
|
---|
76 | {
|
---|
77 | frame[n].interp = (void *) interp_frame->self;
|
---|
78 | interp_frame = interp_frame->next;
|
---|
79 | }
|
---|
80 | else
|
---|
81 | frame[n].interp = 0;
|
---|
82 | #endif // INTERPRETER
|
---|
83 | }
|
---|
84 | }
|
---|
85 | else
|
---|
86 | frame = NULL;
|
---|
87 |
|
---|
88 | addrs = reinterpret_cast<gnu::gcj::RawData *> (frame);
|
---|
89 | #else // HAVE_BACKTRACE
|
---|
90 | (void)maxlen;
|
---|
91 | (void)offset;
|
---|
92 | #endif // HAVE_BACKTRACE
|
---|
93 | }
|
---|
94 |
|
---|
95 | /* Obtain the next power-of-2 of some integer. */
|
---|
96 | static inline jint
|
---|
97 | nextpowerof2 (jint n)
|
---|
98 | {
|
---|
99 | n |= (n >> 1);
|
---|
100 | n |= (n >> 2);
|
---|
101 | n |= (n >> 4);
|
---|
102 | n |= (n >> 8);
|
---|
103 | n |= (n >> 16);
|
---|
104 | return n+1;
|
---|
105 | }
|
---|
106 |
|
---|
107 | #define GET_FRAME(N) \
|
---|
108 | ({ \
|
---|
109 | if ((N) >= len) \
|
---|
110 | fillInStackTrace (nextpowerof2 (N), 1); \
|
---|
111 | if ((N) < 0 || (N) >= len) \
|
---|
112 | throw new ::java::lang::ArrayIndexOutOfBoundsException (); \
|
---|
113 | \
|
---|
114 | _Jv_frame_info *frame = (_Jv_frame_info *)addrs; \
|
---|
115 | &frame[N]; \
|
---|
116 | })
|
---|
117 |
|
---|
118 | gnu::gcj::runtime::MethodRef *
|
---|
119 | gnu::gcj::runtime::StackTrace::getCompiledMethodRef (gnu::gcj::RawData *addr)
|
---|
120 | {
|
---|
121 | void *p = _Unwind_FindEnclosingFunction (addr);
|
---|
122 | return gnu::gcj::runtime::StackTrace
|
---|
123 | ::methodAtAddress ((gnu::gcj::RawData *)p);
|
---|
124 | }
|
---|
125 |
|
---|
126 | java::lang::Class *
|
---|
127 | gnu::gcj::runtime::StackTrace::classAt (jint n)
|
---|
128 | {
|
---|
129 | _Jv_frame_info *frame = GET_FRAME (n);
|
---|
130 |
|
---|
131 | #ifdef INTERPRETER
|
---|
132 | if (frame->interp)
|
---|
133 | {
|
---|
134 | _Jv_InterpMethod *meth
|
---|
135 | = reinterpret_cast<_Jv_InterpMethod *> (frame->interp);
|
---|
136 | return meth->defining_class;
|
---|
137 | }
|
---|
138 | #endif // INTERPRETER
|
---|
139 |
|
---|
140 | gnu::gcj::runtime::MethodRef *ref
|
---|
141 | = getCompiledMethodRef ((gnu::gcj::RawData *)frame->addr);
|
---|
142 | if (ref)
|
---|
143 | return ref->klass;
|
---|
144 | else
|
---|
145 | return NULL;
|
---|
146 | }
|
---|
147 |
|
---|
148 | java::lang::String*
|
---|
149 | gnu::gcj::runtime::StackTrace::methodAt (jint n)
|
---|
150 | {
|
---|
151 | _Jv_frame_info *frame = GET_FRAME (n);
|
---|
152 | _Jv_Method *meth = NULL;
|
---|
153 |
|
---|
154 | #ifdef INTERPRETER
|
---|
155 | if (frame->interp)
|
---|
156 | {
|
---|
157 | meth
|
---|
158 | = reinterpret_cast<_Jv_InterpMethod *> (frame->interp)
|
---|
159 | ->get_method();
|
---|
160 | }
|
---|
161 | #endif // INTERPRETER
|
---|
162 |
|
---|
163 | if (! meth)
|
---|
164 | {
|
---|
165 | gnu::gcj::runtime::MethodRef *ref
|
---|
166 | = getCompiledMethodRef ((gnu::gcj::RawData *)frame->addr);
|
---|
167 | if (ref)
|
---|
168 | meth = (_Jv_Method *)ref->method;
|
---|
169 | }
|
---|
170 |
|
---|
171 | return meth
|
---|
172 | ? _Jv_NewStringUtf8Const (meth->name)
|
---|
173 | : NULL ;
|
---|
174 | }
|
---|
175 |
|
---|
176 | void
|
---|
177 | gnu::gcj::runtime::StackTrace::update(void)
|
---|
178 | {
|
---|
179 | jclass klass;
|
---|
180 |
|
---|
181 | while ((klass = _Jv_PopClass ()))
|
---|
182 | {
|
---|
183 | for (int i=0; i<klass->method_count; i++)
|
---|
184 | {
|
---|
185 | JvSynchronize sync (map);
|
---|
186 | _Jv_Method *meth = &(klass->methods[i]);
|
---|
187 | if (meth->ncode) // i.e. if p is not abstract
|
---|
188 | {
|
---|
189 | gnu::gcj::runtime::MethodRef *ref
|
---|
190 | = new gnu::gcj::runtime::MethodRef
|
---|
191 | ((gnu::gcj::RawData *)meth, klass);
|
---|
192 | map->put ((java::lang::Object*)(meth->ncode), ref);
|
---|
193 | }
|
---|
194 | }
|
---|
195 | }
|
---|
196 | }
|
---|
197 |
|
---|
198 | void
|
---|
199 | gnu::gcj::runtime::StackTrace::finalize(void)
|
---|
200 | {
|
---|
201 | if (addrs != NULL)
|
---|
202 | _Jv_Free (addrs);
|
---|
203 | }
|
---|