| 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 <[email protected]>
|
|---|
| 13 | * @author Mark Wielaard <[email protected]>
|
|---|
| 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 | }
|
|---|