1 /* src/vm/jit/stacktrace.cpp - machine independent stacktrace system
3 Copyright (C) 1996-2005, 2006, 2007, 2008
4 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5 Copyright (C) 2009 Theobroma Systems Ltd.
7 This file is part of CACAO.
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2, or (at
12 your option) any later version.
14 This program is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
39 #include "mm/memory.hpp"
41 #include "vm/jit/stacktrace.hpp"
43 #include "native/llni.h"
45 #include "threads/thread.hpp"
47 #include "toolbox/logging.hpp"
49 #include "vm/array.hpp"
50 #include "vm/jit/builtin.hpp"
51 #include "vm/class.hpp"
52 #include "vm/cycles-stats.h"
53 #include "vm/exceptions.hpp"
54 #include "vm/globals.hpp"
55 #include "vm/javaobjects.hpp"
56 #include "vm/loader.hpp"
57 #include "vm/method.hpp"
58 #include "vm/options.h"
59 #include "vm/string.hpp"
62 #include "vm/jit/asmpart.h"
63 #include "vm/jit/codegen-common.hpp"
64 #include "vm/jit/linenumbertable.hpp"
65 #include "vm/jit/methodheader.h"
66 #include "vm/jit/methodtree.h"
69 // FIXME Use C-linkage for now.
72 /* global variables ***********************************************************/
74 CYCLES_STATS_DECLARE(stacktrace_overhead , 100, 1)
75 CYCLES_STATS_DECLARE(stacktrace_fillInStackTrace, 40, 5000)
76 CYCLES_STATS_DECLARE(stacktrace_get, 40, 5000)
77 CYCLES_STATS_DECLARE(stacktrace_getClassContext , 40, 5000)
78 CYCLES_STATS_DECLARE(stacktrace_getCurrentClass , 40, 5000)
79 CYCLES_STATS_DECLARE(stacktrace_get_stack , 40, 10000)
82 /* stacktrace_stackframeinfo_add ***********************************************
84 Fills a stackframe info structure with the given or calculated
85 values and adds it to the chain.
87 *******************************************************************************/
89 void stacktrace_stackframeinfo_add(stackframeinfo_t* sfi, void* pv, void* sp, void* ra, void* xpc)
91 stackframeinfo_t *currentsfi;
93 #if defined(ENABLE_JIT)
97 /* Get current stackframe info. */
99 currentsfi = threads_get_current_stackframeinfo();
101 /* sometimes we don't have pv handy (e.g. in asmpart.S:
102 L_asm_call_jit_compiler_exception or in the interpreter). */
105 #if defined(ENABLE_INTRP)
107 pv = methodtree_find(ra);
111 #if defined(ENABLE_JIT)
112 # if defined(__SPARC_64__)
113 pv = md_get_pv_from_stackframe(sp);
115 pv = md_codegen_get_pv_from_pc(ra);
121 /* Get codeinfo pointer for the parent Java method. */
123 code = code_get_codeinfo_for_pv(pv);
126 /* assert(m != NULL); */
128 #if defined(ENABLE_JIT)
129 # if defined(ENABLE_INTRP)
130 /* When using the interpreter, we pass RA to the function. */
134 # if defined(__I386__) || defined(__X86_64__) || defined(__S390__) || defined(__M68K__)
135 /* On i386 and x86_64 we always have to get the return address
137 /* m68k has return address on stack always */
138 /* On S390 we use REG_RA as REG_ITMP3, so we have always to get
139 the RA from stack. */
141 framesize = *((u4 *) (((uintptr_t) pv) + FrameSize));
143 ra = md_stacktrace_get_returnaddress(sp, framesize);
145 /* If the method is a non-leaf function, we need to get the
146 return address from the stack. For leaf functions the
147 return address is set correctly. This makes the assembler
148 and the signal handler code simpler. The code is NULL is
149 the asm_vm_call_method special case. */
151 if ((code == NULL) || !code_is_leafmethod(code)) {
152 framesize = *((u4 *) (((uintptr_t) pv) + FrameSize));
154 ra = md_stacktrace_get_returnaddress(sp, framesize);
157 # if defined(ENABLE_INTRP)
162 /* Calculate XPC when not given. The XPC is then the return
163 address of the current method minus 1 because the RA points to
164 the instruction after the call instruction. This is required
165 e.g. for method stubs. */
168 xpc = (void *) (((intptr_t) ra) - 1);
171 /* Fill new stackframeinfo structure. */
173 sfi->prev = currentsfi;
181 if (opt_DebugStackFrameInfo) {
183 log_print("[stackframeinfo add : sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
184 sfi, sfi->code->m, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
185 method_print(sfi->code->m);
191 /* Store new stackframeinfo pointer. */
193 threads_set_current_stackframeinfo(sfi);
195 /* set the native world flag for the current thread */
196 /* ATTENTION: This flag tells the GC how to treat this thread in case of
197 a collection. Set this flag _after_ a valid stackframe info was set. */
199 THREAD_NATIVEWORLD_ENTER;
203 /* stacktrace_stackframeinfo_remove ********************************************
205 Remove the given stackframeinfo from the chain in the current
208 *******************************************************************************/
210 void stacktrace_stackframeinfo_remove(stackframeinfo_t *sfi)
212 /* Clear the native world flag for the current thread. */
213 /* ATTENTION: Clear this flag _before_ removing the stackframe info. */
215 THREAD_NATIVEWORLD_EXIT;
218 if (opt_DebugStackFrameInfo) {
220 log_print("[stackframeinfo remove: sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
221 sfi, sfi->code->m, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
222 method_print(sfi->code->m);
228 /* Set previous stackframe info. */
230 threads_set_current_stackframeinfo(sfi->prev);
234 /* stacktrace_stackframeinfo_fill **********************************************
236 Fill the temporary stackframeinfo structure with the values given
240 tmpsfi ... temporary stackframeinfo
241 sfi ...... stackframeinfo to be used in the next iteration
243 *******************************************************************************/
245 static inline void stacktrace_stackframeinfo_fill(stackframeinfo_t *tmpsfi, stackframeinfo_t *sfi)
249 assert(tmpsfi != NULL);
252 /* Fill the temporary stackframeinfo. */
254 tmpsfi->code = sfi->code;
255 tmpsfi->pv = sfi->pv;
256 tmpsfi->sp = sfi->sp;
257 tmpsfi->ra = sfi->ra;
258 tmpsfi->xpc = sfi->xpc;
260 /* Set the previous stackframe info of the temporary one to the
261 next in the chain. */
263 tmpsfi->prev = sfi->prev;
266 if (opt_DebugStackTrace)
267 log_println("[stacktrace fill]");
272 /* stacktrace_stackframeinfo_next **********************************************
274 Walk the stack (or the stackframeinfo-chain) to the next method and
275 return the new stackframe values in the temporary stackframeinfo
278 ATTENTION: This function does NOT skip builtin methods!
281 tmpsfi ... temporary stackframeinfo of current method
283 *******************************************************************************/
285 static inline void stacktrace_stackframeinfo_next(stackframeinfo_t *tmpsfi)
293 stackframeinfo_t *prevsfi;
297 assert(tmpsfi != NULL);
299 /* Get values from the stackframeinfo. */
307 /* Get the current stack frame size. */
309 framesize = *((uint32_t *) (((intptr_t) pv) + FrameSize));
311 /* Get the RA of the current stack frame (RA to the parent Java
312 method) if the current method is a non-leaf method. Otherwise
313 the value in the stackframeinfo is correct (from the signal
316 #if defined(ENABLE_JIT)
317 # if defined(ENABLE_INTRP)
319 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
323 if (!code_is_leafmethod(code))
324 ra = md_stacktrace_get_returnaddress(sp, framesize);
327 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
330 /* Get the PV for the parent Java method. */
332 #if defined(ENABLE_INTRP)
334 pv = methodtree_find(ra);
338 #if defined(ENABLE_JIT)
339 # if defined(__SPARC_64__)
340 sp = md_get_framepointer(sp);
341 pv = md_get_pv_from_stackframe(sp);
343 pv = md_codegen_get_pv_from_pc(ra);
348 /* Get the codeinfo pointer for the parent Java method. */
350 code = code_get_codeinfo_for_pv(pv);
352 /* Calculate the SP for the parent Java method. */
354 #if defined(ENABLE_INTRP)
356 sp = *(u1 **) (sp - framesize);
360 #if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
361 sp = (void *) (((intptr_t) sp) + framesize + SIZEOF_VOID_P);
362 #elif defined(__SPARC_64__)
363 /* already has the new sp */
365 sp = (void *) (((intptr_t) sp) + framesize);
369 /* If the new codeinfo pointer is NULL we reached a
370 asm_vm_call_method function. In this case we get the next
371 values from the previous stackframeinfo in the chain.
372 Otherwise the new values have been calculated before. */
375 prevsfi = tmpsfi->prev;
377 /* If the previous stackframeinfo in the chain is NULL we
378 reached the top of the stacktrace. We set code and prev to
379 NULL to mark the end, which is checked in
380 stacktrace_stackframeinfo_end_check. */
382 if (prevsfi == NULL) {
388 /* Fill the temporary stackframeinfo with the new values. */
390 stacktrace_stackframeinfo_fill(tmpsfi, prevsfi);
393 /* Store the new values in the stackframeinfo. NOTE: We
394 subtract 1 from the RA to get the XPC, because the RA
395 points to the instruction after the call instruction. */
401 tmpsfi->xpc = (void *) (((intptr_t) ra) - 1);
405 /* Print current method information. */
407 if (opt_DebugStackTrace) {
409 log_print("[stacktrace: method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
410 tmpsfi->code->m, tmpsfi->pv, tmpsfi->sp, tmpsfi->ra,
412 method_print(tmpsfi->code->m);
420 /* stacktrace_stackframeinfo_end_check *****************************************
422 Check if we reached the end of the stacktrace.
425 tmpsfi ... temporary stackframeinfo of current method
428 true .... the end is reached
429 false ... the end is not reached
431 *******************************************************************************/
433 static inline bool stacktrace_stackframeinfo_end_check(stackframeinfo_t *tmpsfi)
437 assert(tmpsfi != NULL);
439 if ((tmpsfi->code == NULL) && (tmpsfi->prev == NULL)) {
441 if (opt_DebugStackTrace)
442 log_println("[stacktrace stop]");
452 /* stacktrace_depth ************************************************************
454 Calculates and returns the depth of the current stacktrace.
457 sfi ... stackframeinfo where to start the stacktrace
460 depth of the stacktrace
462 *******************************************************************************/
464 static int stacktrace_depth(stackframeinfo_t *sfi)
466 stackframeinfo_t tmpsfi;
471 if (opt_DebugStackTrace)
472 log_println("[stacktrace_depth]");
475 /* XXX This is not correct, but a workaround for threads-dump for
477 /* assert(sfi != NULL); */
481 /* Iterate over all stackframes. */
485 for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
486 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
487 stacktrace_stackframeinfo_next(&tmpsfi)) {
488 /* Get methodinfo. */
492 /* Skip builtin methods. */
494 if (m->flags & ACC_METHOD_BUILTIN)
504 /* stacktrace_get **************************************************************
506 Builds and returns a stacktrace starting from the given stackframe
507 info and returns the stacktrace structure wrapped in a Java
508 byte-array to not confuse the GC.
511 sfi ... stackframe info to start stacktrace from
514 stacktrace as Java byte-array
516 *******************************************************************************/
518 java_handle_bytearray_t *stacktrace_get(stackframeinfo_t *sfi)
520 stackframeinfo_t tmpsfi;
524 stacktrace_entry_t *ste;
526 bool skip_fillInStackTrace;
529 CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
532 if (opt_DebugStackTrace)
533 log_println("[stacktrace_get]");
536 skip_fillInStackTrace = true;
539 depth = stacktrace_depth(sfi);
544 /* Allocate memory from the GC heap and copy the stacktrace
546 /* ATTENTION: Use a Java byte-array for this to not confuse the
548 /* FIXME: We waste some memory here as we skip some entries
551 ba_size = sizeof(stacktrace_t) + sizeof(stacktrace_entry_t) * depth;
553 ByteArray ba(ba_size);
558 /* Get a stacktrace entry pointer. */
559 /* ATTENTION: We need a critical section here because we use the
560 byte-array data pointer directly. */
564 st = (stacktrace_t *) ba.get_raw_data_ptr();
568 /* Iterate over the whole stack. */
570 for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
571 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
572 stacktrace_stackframeinfo_next(&tmpsfi)) {
573 /* Get the methodinfo. */
577 /* Skip builtin methods. */
579 if (m->flags & ACC_METHOD_BUILTIN)
582 /* This logic is taken from
583 hotspot/src/share/vm/classfile/javaClasses.cpp
584 (java_lang_Throwable::fill_in_stack_trace). */
586 if (skip_fillInStackTrace == true) {
587 /* Check "fillInStackTrace" only once, so we negate the
588 flag after the first time check. */
590 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
591 /* For GNU Classpath we also need to skip
592 VMThrowable.fillInStackTrace(). */
594 if ((m->clazz == class_java_lang_VMThrowable) &&
595 (m->name == utf_fillInStackTrace))
599 skip_fillInStackTrace = false;
601 if (m->name == utf_fillInStackTrace)
605 /* Skip <init> methods of the exceptions klass. If there is
606 <init> methods that belongs to a superclass of the
607 exception we are going to skipping them in stack trace. */
609 if (skip_init == true) {
610 if ((m->name == utf_init) &&
611 (class_issubclass(m->clazz, class_java_lang_Throwable))) {
615 /* If no "Throwable.init()" method found, we stop
616 checking it next time. */
622 /* Store the stacktrace entry and increment the pointer. */
624 ste->code = tmpsfi.code;
625 ste->pc = tmpsfi.xpc;
630 /* Store the number of entries in the stacktrace structure. */
632 st->length = ste - st->entries;
636 /* release dump memory */
638 /* dump_release(dumpsize); */
640 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
642 return ba.get_handle();
645 /* dump_release(dumpsize); */
647 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
654 /* stacktrace_get_current ******************************************************
656 Builds and returns a stacktrace from the current thread and returns
657 the stacktrace structure wrapped in a Java byte-array to not
661 stacktrace as Java byte-array
663 *******************************************************************************/
665 java_handle_bytearray_t *stacktrace_get_current(void)
667 stackframeinfo_t *sfi;
668 java_handle_bytearray_t *ba;
670 sfi = threads_get_current_stackframeinfo();
671 ba = stacktrace_get(sfi);
678 * Creates a java.lang.StackTraceElement for one element of the given
681 * @param st Given stacktrace.
682 * @param index Index of element inside stacktrace.
683 * @return The filled StackTraceElement object.
685 #if defined(ENABLE_JAVASE)
686 java_handle_t* stacktrace_get_StackTraceElement(stacktrace_t* st, int32_t index)
690 if ((index < 0) || (index >= st->length)) {
691 /* XXX This should be an IndexOutOfBoundsException (check this
693 exceptions_throw_arrayindexoutofboundsexception();
697 // Get the stacktrace entry.
698 stacktrace_entry_t* ste = &(st->entries[index]);
700 // Get the codeinfo, methodinfo and classinfo.
701 codeinfo* code = ste->code;
702 methodinfo* m = code->m;
703 classinfo* c = m->clazz;
706 java_handle_t* filename;
708 if (!(m->flags & ACC_NATIVE)) {
709 if (c->sourcefile != NULL)
710 filename = javastring_new(c->sourcefile);
720 if (m->flags & ACC_NATIVE) {
721 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
723 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
726 # error unknown classpath configuration
730 // FIXME linenumbertable->find could change the methodinfo
731 // pointer when hitting an inlined method.
732 linenumber = code->linenumbertable->find(&m, ste->pc);
733 linenumber = (linenumber == 0) ? -1 : linenumber;
736 // Get declaring class name.
737 java_handle_t* declaringclass = class_get_classname(c);
739 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
740 // Allocate a new StackTraceElement object.
741 java_handle_t* h = builtin_new(class_java_lang_StackTraceElement);
746 java_lang_StackTraceElement jlste(h, filename, linenumber, declaringclass, javastring_new(m->name), ((m->flags & ACC_NATIVE) ? 1 : 0));
747 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
748 // Allocate a new StackTraceElement object.
749 java_lang_StackTraceElement jlste(declaringclass, javastring_new(m->name), filename, linenumber);
754 # error unknown classpath configuration
757 return jlste.get_handle();
763 * Creates a complete array of java.lang.StackTraceElement objects
764 * for the given stacktrace.
766 * @param st Given stacktrace.
767 * @return Array of filled StackTraceElement objects.
769 #if defined(ENABLE_JAVASE)
770 java_handle_objectarray_t* stacktrace_get_StackTraceElements(stacktrace_t* st)
772 // Get length of stacktrace. If stacktrace is not available
773 // an empty array should be returned.
774 int32_t length = (st != NULL) ? st->length : 0;
776 // Create the stacktrace element array.
777 ObjectArray oa(length, class_java_lang_StackTraceElement);
782 // Iterate over all stacktrace elements.
783 for (int i = 0; i < length; i++) {
785 // Get stacktrace element at current index.
786 java_handle_t* h = stacktrace_get_StackTraceElement(st, i);
791 // Store stacktrace element in array.
792 oa.set_element(i, h);
795 return oa.get_handle();
800 /* stacktrace_get_caller_class *************************************************
802 Get the class on the stack at the given depth. This function skips
803 various special classes or methods.
806 depth ... depth to get caller class of
811 *******************************************************************************/
813 #if defined(ENABLE_JAVASE)
814 classinfo *stacktrace_get_caller_class(int depth)
816 stackframeinfo_t *sfi;
817 stackframeinfo_t tmpsfi;
823 if (opt_DebugStackTrace)
824 log_println("[stacktrace_get_caller_class]");
827 /* Get the stackframeinfo of the current thread. */
829 sfi = threads_get_current_stackframeinfo();
831 /* Iterate over the whole stack until we reached the requested
836 for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
837 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
838 stacktrace_stackframeinfo_next(&tmpsfi)) {
843 /* Skip builtin methods. */
845 if (m->flags & ACC_METHOD_BUILTIN)
848 #if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
849 /* NOTE: See hotspot/src/share/vm/runtime/vframe.cpp
850 (vframeStreamCommon::security_get_caller_frame). */
852 /* This is java.lang.reflect.Method.invoke(), skip it. */
854 if (m == method_java_lang_reflect_Method_invoke)
857 /* This is an auxiliary frame, skip it. */
859 if (class_issubclass(c, class_sun_reflect_MagicAccessorImpl))
863 /* We reached the requested depth. */
877 * Returns the first non-null (user-defined) classloader on the stack.
879 * @return The first non-null classloader or NULL if none is found.
881 classloader_t* stacktrace_first_nonnull_classloader(void)
883 stackframeinfo_t *sfi;
884 stackframeinfo_t tmpsfi;
889 if (opt_DebugStackTrace)
890 log_println("[stacktrace_first_nonnull_classloader]");
893 /* Get the stackframeinfo of the current thread. */
895 sfi = threads_get_current_stackframeinfo();
897 /* Iterate over the whole stack. */
899 for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
900 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
901 stacktrace_stackframeinfo_next(&tmpsfi)) {
904 cl = class_get_classloader(m->clazz);
915 * Checks if a given classloader is equal to the the second classloader
916 * or one of its ancestors (parents).
918 * XXX: This helper method should be moved to java_lang_Classloader.
920 #if defined(ENABLE_JAVASE)
921 static bool is_ancestor_of(classloader_t* loader, classloader_t* parent)
923 // Iterate over chain of possible parents.
924 while (parent != NULL) {
926 // Check if given loader is parent.
927 if (loader == parent)
930 // Jump to next parent.
931 java_lang_ClassLoader jlcl(parent);
932 parent = jlcl.get_parent();
937 #endif /* defined(ENABLE_JAVASE) */
941 * Returns the first non-system (user-defined) classloader on the stack.
942 * A non-system classloader is a non-null classloader being not equal to
943 * the system classloader (or one of its ancestors).
945 * @return The first non-system classloader or NULL if none is found.
947 #if defined(ENABLE_JAVASE)
948 classloader_t* stacktrace_first_nonsystem_classloader(void)
950 stackframeinfo_t *sfi;
951 stackframeinfo_t tmpsfi;
954 classloader_t *syscl;
957 if (opt_DebugStackTrace)
958 log_println("[stacktrace_first_nonsystem_classloader]");
961 // Get the stackframeinfo of the current thread.
962 sfi = threads_get_current_stackframeinfo();
964 // Get the system class class loader.
965 syscl = java_lang_ClassLoader::invoke_getSystemClassLoader();
967 // Iterate over the whole stack.
968 for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
969 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
970 stacktrace_stackframeinfo_next(&tmpsfi)) {
973 cl = class_get_classloader(m->clazz);
978 // XXX if a method in a class in a trusted loader is in a
979 // doPrivileged, return NULL (or break) here.
981 if (!is_ancestor_of(cl, syscl))
987 #endif /* defined(ENABLE_JAVASE) */
990 /* stacktrace_getClassContext **************************************************
992 Creates a Class context array.
995 the array of java.lang.Class objects, or
996 NULL if an exception has been thrown
998 *******************************************************************************/
1000 java_handle_objectarray_t *stacktrace_getClassContext(void)
1002 stackframeinfo_t *sfi;
1003 stackframeinfo_t tmpsfi;
1008 CYCLES_STATS_DECLARE_AND_START
1010 #if !defined(NDEBUG)
1011 if (opt_DebugStackTrace)
1012 log_println("[stacktrace_getClassContext]");
1015 sfi = threads_get_current_stackframeinfo();
1017 /* Get the depth of the current stack. */
1019 depth = stacktrace_depth(sfi);
1021 /* The first stackframe corresponds to the method whose
1022 implementation calls this native function. We remove that
1026 stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1027 stacktrace_stackframeinfo_next(&tmpsfi);
1029 /* Allocate the Class array. */
1031 ClassArray ca(depth);
1034 CYCLES_STATS_END(stacktrace_getClassContext);
1039 /* Fill the Class array from the stacktrace list. */
1040 /* Iterate over the whole stack. */
1045 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1046 stacktrace_stackframeinfo_next(&tmpsfi)) {
1047 /* Get methodinfo. */
1051 /* Skip builtin methods. */
1053 if (m->flags & ACC_METHOD_BUILTIN)
1056 /* Store the class in the array. */
1058 ca.set_element(i, m->clazz);
1065 CYCLES_STATS_END(stacktrace_getClassContext)
1067 return ca.get_handle();
1071 /* stacktrace_getCurrentClass **************************************************
1073 Find the current class by walking the stack trace.
1075 Quote from the JNI documentation:
1077 In the Java 2 Platform, FindClass locates the class loader
1078 associated with the current native method. If the native code
1079 belongs to a system class, no class loader will be
1080 involved. Otherwise, the proper class loader will be invoked to
1081 load and link the named class. When FindClass is called through the
1082 Invocation Interface, there is no current native method or its
1083 associated class loader. In that case, the result of
1084 ClassLoader.getBaseClassLoader is used."
1086 *******************************************************************************/
1088 #if defined(ENABLE_JAVASE)
1089 classinfo *stacktrace_get_current_class(void)
1091 stackframeinfo_t *sfi;
1092 stackframeinfo_t tmpsfi;
1095 CYCLES_STATS_DECLARE_AND_START;
1097 #if !defined(NDEBUG)
1098 if (opt_DebugStackTrace)
1099 log_println("[stacktrace_get_current_class]");
1102 /* Get the stackframeinfo of the current thread. */
1104 sfi = threads_get_current_stackframeinfo();
1106 /* If the stackframeinfo is NULL then FindClass is called through
1107 the Invocation Interface and we return NULL */
1110 CYCLES_STATS_END(stacktrace_getCurrentClass);
1115 /* Iterate over the whole stack. */
1117 for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1118 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1119 stacktrace_stackframeinfo_next(&tmpsfi)) {
1120 /* Get the methodinfo. */
1124 if (m->clazz == class_java_security_PrivilegedAction) {
1125 CYCLES_STATS_END(stacktrace_getCurrentClass);
1130 if (m->clazz != NULL) {
1131 CYCLES_STATS_END(stacktrace_getCurrentClass);
1137 /* No Java method found on the stack. */
1139 CYCLES_STATS_END(stacktrace_getCurrentClass);
1143 #endif /* ENABLE_JAVASE */
1146 /* stacktrace_get_stack ********************************************************
1148 Create a 2-dimensional array for java.security.VMAccessControler.
1152 NULL if an exception has been thrown
1154 *******************************************************************************/
1156 #if defined(ENABLE_JAVASE) && defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
1157 java_handle_objectarray_t *stacktrace_get_stack(void)
1159 stackframeinfo_t *sfi;
1160 stackframeinfo_t tmpsfi;
1163 java_handle_t *string;
1166 CYCLES_STATS_DECLARE_AND_START
1168 #if !defined(NDEBUG)
1169 if (opt_DebugStackTrace)
1170 log_println("[stacktrace_get_stack]");
1173 /* Get the stackframeinfo of the current thread. */
1175 sfi = threads_get_current_stackframeinfo();
1177 /* Get the depth of the current stack. */
1179 depth = stacktrace_depth(sfi);
1184 /* Allocate the required arrays. */
1186 ObjectArray oa(2, arrayclass_java_lang_Object);
1187 ClassArray classes(depth);
1188 ObjectArray methodnames(depth, class_java_lang_String);
1193 if (classes.is_null())
1196 if (methodnames.is_null())
1199 /* Set up the 2-dimensional array. */
1201 oa.set_element(0, (java_handle_t *) classes.get_handle());
1202 oa.set_element(1, (java_handle_t *) methodnames.get_handle());
1204 /* Iterate over the whole stack. */
1205 /* TODO We should use a critical section here to speed things
1210 for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1211 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1212 stacktrace_stackframeinfo_next(&tmpsfi)) {
1213 /* Get the methodinfo. */
1217 /* Skip builtin methods. */
1219 if (m->flags & ACC_METHOD_BUILTIN)
1222 /* Store the class in the array. */
1224 classes.set_element(i, m->clazz);
1226 /* Store the name in the array. */
1228 string = javastring_new(m->name);
1233 methodnames.set_element(i, string);
1238 CYCLES_STATS_END(stacktrace_get_stack)
1240 return oa.get_handle();
1243 CYCLES_STATS_END(stacktrace_get_stack)
1250 /* stacktrace_print_entry ****************************************************
1252 Print line for a stacktrace entry.
1255 m ............ methodinfo of the entry
1256 linenumber ... linenumber of the entry
1258 *******************************************************************************/
1260 static void stacktrace_print_entry(methodinfo *m, int32_t linenumber)
1268 if (m->flags & ACC_METHOD_BUILTIN)
1271 utf_display_printable_ascii_classname(m->clazz->name);
1274 utf_display_printable_ascii(m->name);
1275 utf_display_printable_ascii(m->descriptor);
1277 if (m->flags & ACC_NATIVE) {
1278 puts("(Native Method)");
1281 if (m->flags & ACC_METHOD_BUILTIN) {
1286 utf_display_printable_ascii(m->clazz->sourcefile);
1287 printf(":%d)\n", linenumber);
1295 /* stacktrace_print ************************************************************
1297 Print the given stacktrace with CACAO intern methods only (no Java
1300 This method is used by stacktrace_dump_trace and
1301 builtin_trace_exception.
1304 st ... stacktrace to print
1306 *******************************************************************************/
1308 void stacktrace_print(stacktrace_t *st)
1310 stacktrace_entry_t *ste;
1315 ste = &(st->entries[0]);
1317 for (i = 0; i < st->length; i++, ste++) {
1320 /* Get the line number. */
1322 linenumber = ste->code->linenumbertable->find(&m, ste->pc);
1324 stacktrace_print_entry(m, linenumber);
1329 /* stacktrace_print_current ****************************************************
1331 Print the current stacktrace of the current thread.
1333 NOTE: This function prints all frames of the stacktrace and does
1334 not skip frames like stacktrace_get.
1336 *******************************************************************************/
1338 void stacktrace_print_current(void)
1340 stackframeinfo_t *sfi;
1341 stackframeinfo_t tmpsfi;
1346 sfi = threads_get_current_stackframeinfo();
1349 puts("\t<<No stacktrace available>>");
1354 for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1355 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1356 stacktrace_stackframeinfo_next(&tmpsfi)) {
1357 /* Get the methodinfo. */
1362 // Get the line number.
1363 linenumber = code->linenumbertable->find(&m, tmpsfi.xpc);
1365 stacktrace_print_entry(m, linenumber);
1371 * Creates a stacktrace for the given thread.
1373 * @param t Given thread.
1374 * @return Current stacktrace of the given thread.
1376 * XXX: Creation of the stacktrace starts at the most recent
1377 * stackframeinfo block. If the thread is not inside the native
1378 * world, the created stacktrace is not complete!
1380 #if defined(ENABLE_THREADS)
1381 stacktrace_t* stacktrace_get_of_thread(threadobject* t)
1383 stackframeinfo_t* sfi;
1384 java_handle_bytearray_t* stba;
1387 sfi = t->_stackframeinfo;
1388 stba = stacktrace_get(sfi);
1395 st = (stacktrace_t*) ba.get_raw_data_ptr();
1402 /* stacktrace_print_of_thread **************************************************
1404 Print the current stacktrace of the given thread.
1409 *******************************************************************************/
1411 #if defined(ENABLE_THREADS)
1412 void stacktrace_print_of_thread(threadobject *t)
1414 stackframeinfo_t *sfi;
1415 stackframeinfo_t tmpsfi;
1420 /* Build a stacktrace for the passed thread. */
1422 sfi = t->_stackframeinfo;
1425 puts("\t<<No stacktrace available>>");
1430 for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1431 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1432 stacktrace_stackframeinfo_next(&tmpsfi)) {
1433 /* Get the methodinfo. */
1438 // Get the line number.
1439 linenumber = code->linenumbertable->find(&m, tmpsfi.xpc);
1441 stacktrace_print_entry(m, linenumber);
1447 /* stacktrace_print_exception **************************************************
1449 Print the stacktrace of a given exception (more or less a wrapper
1450 to stacktrace_print).
1453 h ... handle of exception to print
1455 *******************************************************************************/
1457 void stacktrace_print_exception(java_handle_t *h)
1462 java_lang_Throwable t(h);
1464 /* now print the stacktrace */
1466 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
1468 java_lang_VMThrowable vmt(t.get_vmState());
1469 ByteArray backtrace(vmt.get_vmdata());
1471 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) || defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
1473 ByteArray backtrace(t.get_backtrace());
1476 # error unknown classpath configuration
1481 assert(backtrace.is_non_null());
1483 /* We need a critical section here as we use the byte-array data
1484 pointer directly. */
1486 LLNI_CRITICAL_START;
1488 stacktrace_t* st = (stacktrace_t*) backtrace.get_raw_data_ptr();
1490 stacktrace_print(st);
1496 #if defined(ENABLE_CYCLES_STATS)
1497 void stacktrace_print_cycles_stats(FILE *file)
1499 CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead, file);
1500 CYCLES_STATS_PRINT(stacktrace_get, file);
1501 CYCLES_STATS_PRINT(stacktrace_getClassContext , file);
1502 CYCLES_STATS_PRINT(stacktrace_getCurrentClass , file);
1503 CYCLES_STATS_PRINT(stacktrace_get_stack, file);
1511 * These are local overrides for various environment variables in Emacs.
1512 * Please do not remove this and leave it at the end of the file, where
1513 * Emacs will automagically detect them.
1514 * ---------------------------------------------------------------------
1517 * indent-tabs-mode: t
1521 * vim:noexpandtab:sw=4:ts=4: