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/security/AccessController.h>
25 #include <java/util/ArrayList.h>
26 #include <gnu/classpath/jdwp/Jdwp.h>
27 #include <gnu/java/lang/MainThread.h>
28 #include <gnu/gcj/runtime/NameFinder.h>
29 #include <gnu/gcj/runtime/StringBuffer.h>
31 #include <sysdep/backtrace.h>
32 #include <sysdep/descriptor.h>
34 using namespace java::lang
;
35 using namespace java::lang::reflect
;
36 using namespace java::util
;
37 using namespace gnu::gcj::runtime
;
39 // Maps ncode values to their containing native class.
40 // NOTE: Currently this Map contradicts class GC for native classes. This map
41 // (and the "new class stack") will need to use WeakReferences in order to
42 // enable native class GC.
43 java::util::IdentityHashMap
*_Jv_StackTrace::ncodeMap
;
45 // Check the "class stack" for any classes initialized since we were last
46 // called, and add them to ncodeMap.
48 _Jv_StackTrace::UpdateNCodeMap ()
50 // The Map should be large enough so that a typical Java app doesn't cause
51 // it to rehash, without using too much memory. ~5000 entries should be
54 ncodeMap
= new java::util::IdentityHashMap (5087);
57 while ((klass
= _Jv_PopClass ()))
59 //printf ("got %s\n", klass->name->data);
60 for (int i
= 0; i
< klass
->method_count
; i
++)
62 _Jv_Method
*method
= &klass
->methods
[i
];
63 void *ncode
= method
->ncode
;
64 // Add non-abstract methods to ncodeMap.
67 ncode
= UNWRAP_FUNCTION_DESCRIPTOR (ncode
);
68 ncodeMap
->put ((java::lang::Object
*) ncode
, klass
);
74 // Given a native frame, return the class which this code belongs
75 // to. Returns NULL if this IP is not associated with a native Java class.
76 // If NCODE is supplied, it will be set with the ip for the entry point of the
79 _Jv_StackTrace::ClassForFrame (_Jv_StackFrame
*frame
)
81 JvAssert (frame
->type
== frame_native
);
84 // look it up in ncodeMap
87 klass
= (jclass
) ncodeMap
->get ((jobject
) frame
->start_ip
);
89 // Exclude interpreted classes
90 if (klass
!= NULL
&& _Jv_IsInterpretedClass (klass
))
98 _Jv_StackTrace::UnwindTraceFn (struct _Unwind_Context
*context
, void *state_ptr
)
100 _Jv_UnwindState
*state
= (_Jv_UnwindState
*) state_ptr
;
101 jint pos
= state
->pos
;
103 // Check if the trace buffer needs to be extended.
104 if (pos
== state
->length
)
106 int newLength
= state
->length
* 2;
107 void *newFrames
= _Jv_AllocBytes (newLength
* sizeof(_Jv_StackFrame
));
108 memcpy (newFrames
, state
->frames
, state
->length
* sizeof(_Jv_StackFrame
));
109 state
->frames
= (_Jv_StackFrame
*) newFrames
;
110 state
->length
= newLength
;
113 void *func_addr
= (void *) _Unwind_GetRegionStart (context
);
115 // If we see the interpreter's main function, "pop" an entry off the
116 // interpreter stack and use that instead, so that the trace goes through
117 // the java code and not the interpreter itself. This assumes a 1:1
118 // correspondance between call frames in the interpreted stack and occurances
119 // of _Jv_InterpMethod::run() on the native stack.
121 void *interp_run
= NULL
;
123 if (::gnu::classpath::jdwp::Jdwp::isDebugging
)
124 interp_run
= (void *) &_Jv_InterpMethod::run_debug
;
126 interp_run
= (void *) &_Jv_InterpMethod::run
;
128 if (func_addr
== UNWRAP_FUNCTION_DESCRIPTOR (interp_run
))
130 state
->frames
[pos
].type
= frame_interpreter
;
131 state
->frames
[pos
].interp
.meth
= state
->interp_frame
->self
;
132 state
->frames
[pos
].interp
.pc
= state
->interp_frame
->pc
;
133 state
->interp_frame
= state
->interp_frame
->next
;
138 #ifdef HAVE_GETIPINFO
140 int ip_before_insn
= 0;
141 ip
= _Unwind_GetIPInfo (context
, &ip_before_insn
);
143 // If the unwinder gave us a 'return' address, roll it back a little
144 // to ensure we get the correct line number for the call itself.
145 if (! ip_before_insn
)
148 state
->frames
[pos
].type
= frame_native
;
149 #ifdef HAVE_GETIPINFO
150 state
->frames
[pos
].ip
= (void *) ip
;
152 state
->frames
[pos
].ip
= (void *) _Unwind_GetIP (context
);
154 state
->frames
[pos
].start_ip
= func_addr
;
157 _Unwind_Reason_Code result
= _URC_NO_REASON
;
158 if (state
->trace_function
!= NULL
)
159 result
= (state
->trace_function
) (state
);
164 // Return a raw stack trace from the current point of execution. The raw
165 // trace will include all functions that have unwind info.
167 _Jv_StackTrace::GetStackTrace(void)
169 int trace_size
= 100;
170 _Jv_StackFrame frames
[trace_size
];
171 _Jv_UnwindState
state (trace_size
);
172 state
.frames
= (_Jv_StackFrame
*) &frames
;
174 _Unwind_Backtrace (UnwindTraceFn
, &state
);
176 // Copy the trace and return it.
177 int traceSize
= sizeof (_Jv_StackTrace
) +
178 (sizeof (_Jv_StackFrame
) * state
.pos
);
179 _Jv_StackTrace
*trace
= (_Jv_StackTrace
*) _Jv_AllocBytes (traceSize
);
180 trace
->length
= state
.pos
;
181 memcpy (trace
->frames
, state
.frames
, sizeof (_Jv_StackFrame
) * state
.pos
);
186 _Jv_StackTrace::getLineNumberForFrame(_Jv_StackFrame
*frame
, NameFinder
*finder
,
187 jstring
*sourceFileName
, jint
*lineNum
,
191 if (frame
->type
== frame_interpreter
)
193 _Jv_InterpMethod
*interp_meth
= frame
->interp
.meth
;
194 _Jv_InterpClass
*interp_class
=
195 (_Jv_InterpClass
*) interp_meth
->defining_class
->aux_info
;
196 *sourceFileName
= interp_class
->source_file_name
;
197 // The interpreter advances the PC before executing an instruction,
198 // so roll-back 1 byte to ensure the line number is accurate.
199 *lineNum
= interp_meth
->get_source_line(frame
->interp
.pc
- 1);
204 // Use _Jv_platform_dladdr() to determine in which binary the address IP
207 jstring binaryName
= NULL
;
208 const char *argv0
= _Jv_GetSafeArg(0);
210 void *ip
= frame
->ip
;
211 _Unwind_Ptr offset
= 0;
213 if (_Jv_platform_dladdr (ip
, &info
))
216 binaryName
= JvNewStringUTF (info
.file_name
);
220 if (*methodName
== NULL
&& info
.sym_name
)
221 *methodName
= JvNewStringUTF (info
.sym_name
);
223 // addr2line expects relative addresses for shared libraries.
224 if (strcmp (info
.file_name
, argv0
) == 0)
225 offset
= (_Unwind_Ptr
) ip
;
227 offset
= (_Unwind_Ptr
) ip
- (_Unwind_Ptr
) info
.base
;
229 #ifndef HAVE_GETIPINFO
230 // The unwinder gives us the return address. In order to get the right
231 // line number for the stack trace, roll it back a little.
235 finder
->lookup (binaryName
, (jlong
) offset
);
236 *sourceFileName
= finder
->getSourceFile();
237 *lineNum
= finder
->getLineNum();
238 if (*lineNum
== -1 && NameFinder::showRaw())
240 gnu::gcj::runtime::StringBuffer
*t
=
241 new gnu::gcj::runtime::StringBuffer(binaryName
);
242 t
->append ((jchar
)' ');
243 t
->append ((jchar
)'[');
244 // + 1 to compensate for the - 1 adjustment above;
245 t
->append (Long::toHexString (offset
+ 1));
246 t
->append ((jchar
)']');
247 *sourceFileName
= t
->toString();
252 // Look up class and method info for the given stack frame, setting
253 // frame->klass and frame->meth if they are known.
255 _Jv_StackTrace::FillInFrameInfo (_Jv_StackFrame
*frame
)
258 _Jv_Method
*meth
= NULL
;
260 if (frame
->type
== frame_native
)
262 klass
= _Jv_StackTrace::ClassForFrame (frame
);
265 // Find method in class
266 for (int j
= 0; j
< klass
->method_count
; j
++)
268 void *wncode
= UNWRAP_FUNCTION_DESCRIPTOR (klass
->methods
[j
].ncode
);
269 if (wncode
== frame
->start_ip
)
271 meth
= &klass
->methods
[j
];
277 else if (frame
->type
== frame_interpreter
)
279 _Jv_InterpMethod
*interp_meth
= frame
->interp
.meth
;
280 klass
= interp_meth
->defining_class
;
281 meth
= interp_meth
->self
;
285 JvFail ("Unknown frame type");
287 frame
->klass
= klass
;
291 // Convert raw stack frames to a Java array of StackTraceElement objects.
292 JArray
< ::java::lang::StackTraceElement
*>*
293 _Jv_StackTrace::GetStackTraceElements (_Jv_StackTrace
*trace
,
294 Throwable
*throwable
__attribute__((unused
)))
296 ArrayList
*list
= new ArrayList ();
298 #if defined (SJLJ_EXCEPTIONS) && ! defined (WIN32)
299 // We can't use the nCodeMap without unwinder support. Instead,
300 // fake the method name by giving the IP in hex - better than nothing.
301 jstring hex
= JvNewStringUTF ("0x");
303 for (int i
= 0; i
< trace
->length
; i
++)
305 jstring sourceFileName
= NULL
;
307 _Jv_StackFrame
*frame
= &trace
->frames
[i
];
309 jstring className
= NULL
;
310 jstring methodName
= hex
->concat (Long::toHexString ((jlong
) frame
->ip
));
312 StackTraceElement
*element
= new StackTraceElement (sourceFileName
,
313 lineNum
, className
, methodName
, 0);
317 #else /* SJLJ_EXCEPTIONS && !WIN32 */
319 //JvSynchronized (ncodeMap);
322 NameFinder
*finder
= new NameFinder();
324 int end_idx
= trace
->length
- 1;
326 // First pass: strip superfluous frames from beginning and end of the trace.
327 for (int i
= 0; i
< trace
->length
; i
++)
329 _Jv_StackFrame
*frame
= &trace
->frames
[i
];
330 FillInFrameInfo (frame
);
332 if (!frame
->klass
|| !frame
->meth
)
336 // Throw away the top of the stack till we see:
337 // - the constructor(s) of this Throwable, or
338 // - the Throwable.fillInStackTrace call.
339 if (frame
->klass
== throwable
->getClass()
340 && strcmp (frame
->meth
->name
->chars(), "<init>") == 0)
343 if (frame
->klass
== &Throwable::class$
344 && strcmp (frame
->meth
->name
->chars(), "fillInStackTrace") == 0)
347 // End the trace at the application's main() method if we see call_main.
348 if (frame
->klass
== &gnu::java::lang::MainThread::class$
349 && strcmp (frame
->meth
->name
->chars(), "call_main") == 0)
353 const jboolean remove_unknown
354 = gnu::gcj::runtime::NameFinder::removeUnknown();
356 // Second pass: Look up line-number info for remaining frames.
357 for (int i
= start_idx
; i
<= end_idx
; i
++)
359 _Jv_StackFrame
*frame
= &trace
->frames
[i
];
361 if (frame
->klass
== NULL
&& remove_unknown
)
365 jstring className
= NULL
;
366 if (frame
->klass
!= NULL
)
367 className
= frame
->klass
->getName ();
369 jstring methodName
= NULL
;
371 methodName
= JvNewStringUTF (frame
->meth
->name
->chars());
373 jstring sourceFileName
= NULL
;
376 getLineNumberForFrame(frame
, finder
, &sourceFileName
, &lineNum
,
379 StackTraceElement
*element
= new StackTraceElement (sourceFileName
, lineNum
,
380 className
, methodName
, 0);
385 #endif /* SJLJ_EXCEPTIONS && !WIN32 */
387 JArray
<Object
*> *array
= JvNewObjectArray (list
->size (),
388 &StackTraceElement::class$
, NULL
);
390 return (JArray
<StackTraceElement
*>*) list
->toArray (array
);
393 struct CallingClassTraceData
397 _Jv_Method
*foundMeth
;
398 bool seen_checkClass
;
402 _Jv_StackTrace::calling_class_trace_fn (_Jv_UnwindState
*state
)
404 CallingClassTraceData
*trace_data
= (CallingClassTraceData
*)
406 _Jv_StackFrame
*frame
= &state
->frames
[state
->pos
];
407 FillInFrameInfo (frame
);
409 if (trace_data
->seen_checkClass
411 && frame
->klass
!= trace_data
->checkClass
)
413 trace_data
->foundClass
= frame
->klass
;
414 trace_data
->foundMeth
= frame
->meth
;
415 return _URC_NORMAL_STOP
;
418 if (frame
->klass
== trace_data
->checkClass
)
419 trace_data
->seen_checkClass
= true;
421 return _URC_NO_REASON
;
424 // Find the class immediately above the given class on the call stack. Any
425 // intermediate non-Java
426 // frames are ignored. If the calling class could not be determined (eg because
427 // the unwinder is not supported on this platform), NULL is returned.
428 // This function is used to implement calling-classloader checks and reflection
429 // accessibility checks.
430 // CHECKCLASS is typically the class calling GetCallingClass. The first class
431 // above CHECKCLASS on the call stack will be returned.
433 _Jv_StackTrace::GetCallingClass (jclass checkClass
)
435 jclass result
= NULL
;
436 GetCallerInfo (checkClass
, &result
, NULL
);
441 _Jv_StackTrace::GetCallerInfo (jclass checkClass
, jclass
*caller_class
,
442 _Jv_Method
**caller_meth
)
445 _Jv_StackFrame frames
[trace_size
];
446 _Jv_UnwindState
state (trace_size
);
447 state
.frames
= (_Jv_StackFrame
*) &frames
;
449 CallingClassTraceData trace_data
;
450 trace_data
.checkClass
= checkClass
;
451 trace_data
.seen_checkClass
= false;
452 trace_data
.foundClass
= NULL
;
453 trace_data
.foundMeth
= NULL
;
455 state
.trace_function
= calling_class_trace_fn
;
456 state
.trace_data
= (void *) &trace_data
;
458 //JvSynchronized (ncodeMap);
461 _Unwind_Backtrace (UnwindTraceFn
, &state
);
464 *caller_class
= trace_data
.foundClass
;
466 *caller_meth
= trace_data
.foundMeth
;
469 // Return a java array containing the Java classes on the stack above CHECKCLASS.
471 _Jv_StackTrace::GetClassContext (jclass checkClass
)
473 JArray
<jclass
> *result
= NULL
;
475 int trace_size
= 100;
476 _Jv_StackFrame frames
[trace_size
];
477 _Jv_UnwindState
state (trace_size
);
478 state
.frames
= (_Jv_StackFrame
*) &frames
;
480 //JvSynchronized (ncodeMap);
483 _Unwind_Backtrace (UnwindTraceFn
, &state
);
485 // Count the number of Java frames on the stack.
486 int jframe_count
= 0;
487 bool seen_checkClass
= false;
489 for (int i
= 0; i
< state
.pos
; i
++)
491 _Jv_StackFrame
*frame
= &state
.frames
[i
];
492 FillInFrameInfo (frame
);
504 seen_checkClass
= frame
->klass
== checkClass
;
506 result
= (JArray
<jclass
> *) _Jv_NewObjectArray (jframe_count
, &Class::class$
, NULL
);
509 for (int i
= start_pos
; i
< state
.pos
; i
++)
511 _Jv_StackFrame
*frame
= &state
.frames
[i
];
513 elements(result
)[pos
++] = frame
->klass
;
519 _Jv_StackTrace::non_system_trace_fn (_Jv_UnwindState
*state
)
521 _Jv_StackFrame
*frame
= &state
->frames
[state
->pos
];
522 FillInFrameInfo (frame
);
524 ClassLoader
*classLoader
= NULL
;
528 classLoader
= frame
->klass
->getClassLoaderInternal();
530 if (classLoader
!= NULL
)
532 state
->trace_data
= (void *) classLoader
;
533 return _URC_NORMAL_STOP
;
538 return _URC_NO_REASON
;
542 _Jv_StackTrace::GetFirstNonSystemClassLoader ()
545 _Jv_StackFrame frames
[trace_size
];
546 _Jv_UnwindState
state (trace_size
);
547 state
.frames
= (_Jv_StackFrame
*) &frames
;
548 state
.trace_function
= non_system_trace_fn
;
549 state
.trace_data
= NULL
;
551 //JvSynchronized (ncodeMap);
554 _Unwind_Backtrace (UnwindTraceFn
, &state
);
556 if (state
.trace_data
)
557 return (ClassLoader
*) state
.trace_data
;
562 struct AccessControlTraceData
569 _Jv_StackTrace::accesscontrol_trace_fn (_Jv_UnwindState
*state
)
571 AccessControlTraceData
*trace_data
= (AccessControlTraceData
*)
573 _Jv_StackFrame
*frame
= &state
->frames
[state
->pos
];
574 FillInFrameInfo (frame
);
576 if (!(frame
->klass
&& frame
->meth
))
577 return _URC_NO_REASON
;
579 trace_data
->length
++;
581 // If the previous frame was a call to doPrivileged, then this is
582 // the last frame we look at.
583 if (trace_data
->privileged
)
584 return _URC_NORMAL_STOP
;
586 if (frame
->klass
== &::java::security::AccessController::class$
587 && strcmp (frame
->meth
->name
->chars(), "doPrivileged") == 0)
588 trace_data
->privileged
= true;
590 return _URC_NO_REASON
;
594 _Jv_StackTrace::GetAccessControlStack (void)
596 int trace_size
= 100;
597 _Jv_StackFrame frames
[trace_size
];
598 _Jv_UnwindState
state (trace_size
);
599 state
.frames
= (_Jv_StackFrame
*) &frames
;
601 AccessControlTraceData trace_data
;
602 trace_data
.length
= 0;
603 trace_data
.privileged
= false;
605 state
.trace_function
= accesscontrol_trace_fn
;
606 state
.trace_data
= (void *) &trace_data
;
609 _Unwind_Backtrace (UnwindTraceFn
, &state
);
611 JArray
<jclass
> *classes
= (JArray
<jclass
> *)
612 _Jv_NewObjectArray (trace_data
.length
, &::java::lang::Class::class$
, NULL
);
613 jclass
*c
= elements (classes
);
615 for (int i
= 0, j
= 0; i
< state
.pos
; i
++)
617 _Jv_StackFrame
*frame
= &state
.frames
[i
];
618 if (!frame
->klass
|| !frame
->meth
)
624 jobjectArray result
=
625 (jobjectArray
) _Jv_NewObjectArray (2, &::java::lang::Object::class$
,
627 jobject
*r
= elements (result
);
628 r
[0] = (jobject
) classes
;
629 r
[1] = (jobject
) new Boolean (trace_data
.privileged
);