1 /* src/vm/jit/stacktrace.c - machine independent stacktrace system
3 Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2, or (at
13 your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
37 #include "mm/gc-common.h"
38 #include "mm/memory.h"
40 #include "vm/jit/stacktrace.h"
42 #include "vm/global.h" /* required here for native includes */
43 #include "native/jni.h"
44 #include "native/llni.h"
45 #include "native/include/java_lang_Throwable.h"
47 #if defined(WITH_CLASSPATH_GNU)
48 # include "native/include/java_lang_VMThrowable.h"
51 #if defined(ENABLE_THREADS)
52 # include "threads/native/threads.h"
54 # include "threads/none/threads.h"
57 #include "toolbox/logging.h"
60 #include "vm/builtin.h"
61 #include "vm/cycles-stats.h"
62 #include "vm/exceptions.h"
63 #include "vm/stringlocal.h"
66 #include "vm/jit/asmpart.h"
67 #include "vm/jit/codegen-common.h"
68 #include "vm/jit/methodheader.h"
70 #include "vmcore/class.h"
71 #include "vmcore/loader.h"
72 #include "vmcore/options.h"
75 /* global variables ***********************************************************/
76 #if !defined(ENABLE_THREADS)
77 stackframeinfo_t *_no_threads_stackframeinfo = NULL;
80 CYCLES_STATS_DECLARE(stacktrace_overhead ,100,1)
81 CYCLES_STATS_DECLARE(stacktrace_fillInStackTrace,40,5000)
82 CYCLES_STATS_DECLARE(stacktrace_getClassContext ,40,5000)
83 CYCLES_STATS_DECLARE(stacktrace_getCurrentClass ,40,5000)
84 CYCLES_STATS_DECLARE(stacktrace_getStack ,40,10000)
87 /* stacktrace_stackframeinfo_add ***********************************************
89 Fills a stackframe info structure with the given or calculated
90 values and adds it to the chain.
92 *******************************************************************************/
94 void stacktrace_stackframeinfo_add(stackframeinfo_t *sfi, u1 *pv, u1 *sp, u1 *ra, u1 *xpc)
96 stackframeinfo_t **psfi;
98 #if !defined(__I386__) && !defined(__X86_64__) && !defined(__S390__) && !defined(__M68K__)
101 #if defined(ENABLE_JIT)
105 /* get current stackframe info pointer */
107 psfi = &STACKFRAMEINFO;
109 /* sometimes we don't have pv handy (e.g. in asmpart.S:
110 L_asm_call_jit_compiler_exception or in the interpreter). */
113 #if defined(ENABLE_INTRP)
115 pv = codegen_get_pv_from_pc(ra);
119 #if defined(ENABLE_JIT)
120 # if defined(__SPARC_64__)
121 pv = md_get_pv_from_stackframe(sp);
123 pv = md_codegen_get_pv_from_pc(ra);
129 /* Get codeinfo pointer for the parent Java method. */
131 code = code_get_codeinfo_for_pv(pv);
134 /* assert(m != NULL); */
136 #if defined(ENABLE_JIT)
137 # if defined(ENABLE_INTRP)
138 /* When using the interpreter, we pass RA to the function. */
142 # if defined(__I386__) || defined(__X86_64__) || defined(__S390__) || defined(__M68K__)
143 /* On i386 and x86_64 we always have to get the return address
145 /* m68k has return address on stack always */
146 /* On S390 we use REG_RA as REG_ITMP3, so we have always to get
147 the RA from stack. */
149 framesize = *((u4 *) (pv + FrameSize));
151 ra = md_stacktrace_get_returnaddress(sp, framesize);
153 /* If the method is a non-leaf function, we need to get the return
154 address from the stack. For leaf functions the return address
155 is set correctly. This makes the assembler and the signal
156 handler code simpler. */
158 isleafmethod = *((s4 *) (pv + IsLeaf));
161 framesize = *((u4 *) (pv + FrameSize));
163 ra = md_stacktrace_get_returnaddress(sp, framesize);
166 # if defined(ENABLE_INTRP)
171 /* Calculate XPC when not given. The XPC is then the return
172 address of the current method minus 1 because the RA points to
173 the instruction after the call instruction. This is required
174 e.g. for method stubs. */
177 xpc = (void *) (((intptr_t) ra) - 1);
180 /* Fill new stackframeinfo structure. */
190 if (opt_DebugStackFrameInfo) {
192 log_print("[stackframeinfo add : sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
193 sfi, sfi->code->m, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
194 method_print(sfi->code->m);
200 /* Store new stackframeinfo pointer. */
204 /* set the native world flag for the current thread */
205 /* ATTENTION: This flag tells the GC how to treat this thread in case of
206 a collection. Set this flag _after_ a valid stackframe info was set. */
208 THREAD_NATIVEWORLD_ENTER;
212 /* stacktrace_stackframeinfo_remove ********************************************
214 Remove the given stackframeinfo from the chain in the current
217 *******************************************************************************/
219 void stacktrace_stackframeinfo_remove(stackframeinfo_t *sfi)
221 stackframeinfo_t **psfi;
223 /* clear the native world flag for the current thread */
224 /* ATTENTION: Clear this flag _before_ removing the stackframe info */
226 THREAD_NATIVEWORLD_EXIT;
228 /* get current stackframe info pointer */
230 psfi = &STACKFRAMEINFO;
233 if (opt_DebugStackFrameInfo) {
235 log_print("[stackframeinfo remove: sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
236 sfi, sfi->code->m, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
237 method_print(sfi->code->m);
243 /* restore the old pointer */
249 /* stacktrace_entry_add ********************************************************
251 Adds a new entry to the stacktrace buffer.
253 *******************************************************************************/
255 static inline stacktracebuffer *stacktrace_entry_add(stacktracebuffer *stb, methodinfo *m, u2 line)
257 stacktrace_entry *ste;
261 /* check if we already reached the buffer capacity */
263 if (stb->used >= stb->capacity) {
264 /* calculate size of stacktracebuffer */
266 stb_size_old = sizeof(stacktracebuffer) +
267 sizeof(stacktrace_entry) * stb->capacity -
268 sizeof(stacktrace_entry) * STACKTRACE_CAPACITY_DEFAULT;
270 stb_size_new = stb_size_old +
271 sizeof(stacktrace_entry) * STACKTRACE_CAPACITY_INCREMENT;
273 /* reallocate new memory */
275 stb = DMREALLOC(stb, u1, stb_size_old, stb_size_new);
277 /* set new buffer capacity */
279 stb->capacity = stb->capacity + STACKTRACE_CAPACITY_INCREMENT;
282 /* insert the current entry */
284 ste = &(stb->entries[stb->used]);
287 ste->linenumber = line;
289 /* increase entries used count */
297 /* stacktrace_method_add *******************************************************
299 Add stacktrace entries[1] for the given method to the stacktrace
303 stb....stacktracebuffer to fill
304 sfi....current stackframeinfo
306 stacktracebuffer after possible reallocation.
308 [1] In case of inlined methods there may be more than one stacktrace
309 entry for a codegen-level method. (see doc/inlining_stacktrace.txt)
311 *******************************************************************************/
313 static inline stacktracebuffer *stacktrace_method_add(stacktracebuffer *stb, stackframeinfo_t *sfi)
321 /* Get values from the stackframeinfo. */
329 /* Skip builtin methods. */
331 if (m->flags & ACC_METHOD_BUILTIN)
334 /* Search the line number table. */
336 linenumber = dseg_get_linenumber_from_pc(&m, pv, xpc);
338 /* Add a new entry to the staktrace. */
340 stb = stacktrace_entry_add(stb, m, linenumber);
346 /* stacktrace_stack_walk *******************************************************
348 Walk the stack (or the stackframeinfo-chain) to the next method.
351 tmpsfi ... stackframeinfo of current method
354 true .... the sfi is filled with the new values
355 false ... we reached the top of the stacktrace
357 *******************************************************************************/
359 static inline bool stacktrace_stack_walk(stackframeinfo_t *tmpsfi)
367 stackframeinfo_t *prevsfi;
369 /* Get values from the stackframeinfo. */
377 /* Get the current stack frame size. */
379 framesize = *((uint32_t *) (((intptr_t) pv) + FrameSize));
381 /* Get the RA of the current stack frame (RA to the parent Java
382 method) if the current method is a non-leaf method. Otherwise
383 the value in the stackframeinfo is correct (from the signal
386 #if defined(ENABLE_JIT)
387 # if defined(ENABLE_INTRP)
389 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
393 if (!code_is_leafmethod(code))
394 ra = md_stacktrace_get_returnaddress(sp, framesize);
397 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
400 /* Get the PV for the parent Java method. */
402 #if defined(ENABLE_INTRP)
404 pv = codegen_get_pv_from_pc(ra);
408 #if defined(ENABLE_JIT)
409 # if defined(__SPARC_64__)
410 sp = md_get_framepointer(sp);
411 pv = md_get_pv_from_stackframe(sp);
413 pv = md_codegen_get_pv_from_pc(ra);
418 /* Get the codeinfo pointer for the parent Java method. */
420 code = code_get_codeinfo_for_pv(pv);
422 /* Calculate the SP for the parent Java method. */
424 #if defined(ENABLE_INTRP)
426 sp = *(u1 **) (sp - framesize);
430 #if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
431 sp = (void *) (((intptr_t) sp) + framesize + SIZEOF_VOID_P);
432 #elif defined(__SPARC_64__)
433 /* already has the new sp */
435 sp = (void *) (((intptr_t) sp) + framesize);
439 /* If the new codeinfo pointer is NULL we reached a
440 asm_vm_call_method function. In this case we get the next
441 values from the previous stackframeinfo in the chain.
442 Otherwise the new values have been calculated before. */
445 prevsfi = tmpsfi->prev;
447 /* If the previous stackframeinfo in the chain is NULL we
448 reached the top of the stacktrace and return false. */
453 /* Fill the temporary stackframeinfo with the new values. */
455 tmpsfi->code = prevsfi->code;
456 tmpsfi->pv = prevsfi->pv;
457 tmpsfi->sp = prevsfi->sp;
458 tmpsfi->ra = prevsfi->ra;
459 tmpsfi->xpc = prevsfi->xpc;
461 /* Set the previous stackframe info of the temporary one to
462 the next in the chain. */
464 tmpsfi->prev = prevsfi->prev;
467 /* Store the new values in the stackframeinfo. NOTE: We
468 subtract 1 from the RA to get the XPC, because the RA
469 points to the instruction after the call instruction. */
475 tmpsfi->xpc = (void *) (((intptr_t) ra) - 1);
482 /* stacktrace_create ***********************************************************
484 Generates a stacktrace from the thread passed into a
485 stacktracebuffer. The stacktracebuffer is allocated on the
488 NOTE: The first element in the stackframe chain must always be a
489 native stackframeinfo (e.g. VMThrowable.fillInStackTrace() is
493 pointer to the stacktracebuffer, or
494 NULL if there is no stacktrace available for the
497 *******************************************************************************/
499 stacktracebuffer *stacktrace_create(stackframeinfo_t *sfi)
501 stacktracebuffer *stb;
502 stackframeinfo_t tmpsfi;
503 bool skip_fillInStackTrace;
506 skip_fillInStackTrace = true;
509 /* Create a stacktracebuffer in dump memory. */
511 stb = DNEW(stacktracebuffer);
513 stb->capacity = STACKTRACE_CAPACITY_DEFAULT;
517 if (opt_DebugStackTrace) {
518 printf("\n\n---> stacktrace creation start (fillInStackTrace):\n");
523 /* Put the data from the stackframeinfo into a temporary one. */
525 /* XXX This is not correct, but a workaround for threads-dump for
527 /* assert(sfi != NULL); */
531 tmpsfi.code = sfi->code;
535 tmpsfi.xpc = sfi->xpc;
537 /* Initially set the previous stackframe info of the temporary one
538 to the next in the chain. */
540 tmpsfi.prev = sfi->prev;
542 /* Iterate till we're done. */
546 /* Print current method information. */
548 if (opt_DebugStackTrace) {
550 log_print("[stacktrace: method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
551 tmpsfi.code->m, tmpsfi.pv, tmpsfi.sp, tmpsfi.ra,
553 method_print(tmpsfi.code->m);
559 /* This logic is taken from
560 hotspot/src/share/vm/classfile/javaClasses.cpp
561 (java_lang_Throwable::fill_in_stack_trace). */
563 if (skip_fillInStackTrace == true) {
564 /* Check "fillInStackTrace" only once, so we negate the
565 flag after the first time check. */
567 #if defined(WITH_CLASSPATH_GNU)
568 /* For GNU Classpath we also need to skip
569 VMThrowable.fillInStackTrace(). */
571 if ((tmpsfi.code->m->class == class_java_lang_VMThrowable) &&
572 (tmpsfi.code->m->name == utf_fillInStackTrace))
576 skip_fillInStackTrace = false;
578 if (tmpsfi.code->m->name == utf_fillInStackTrace)
582 /* Skip <init> methods of the exceptions klass. If there is
583 <init> methods that belongs to a superclass of the
584 exception we are going to skipping them in stack trace. */
586 if (skip_init == true) {
587 if (tmpsfi.code->m->name == utf_init) {
588 /* throwable->is_a(method->method_holder())) { */
592 /* If no "Throwable.init()" method found, we stop
593 checking it next time. */
599 /* Add this method to the stacktrace. */
601 stb = stacktrace_method_add(stb, &tmpsfi);
602 } while (stacktrace_stack_walk(&tmpsfi) == true);
605 if (opt_DebugStackTrace) {
606 printf("---> stacktrace creation finished.\n\n");
611 /* return the stacktracebuffer */
620 /* stacktrace_fillInStackTrace *************************************************
622 Generate a stacktrace from the current thread for
623 java.lang.VMThrowable.fillInStackTrace.
625 *******************************************************************************/
627 java_handle_bytearray_t *stacktrace_fillInStackTrace(void)
629 stacktracebuffer *stb;
630 java_handle_bytearray_t *ba;
633 CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
635 /* mark start of dump memory area */
637 dumpsize = dump_size();
639 /* create a stacktrace from the current thread */
641 stb = stacktrace_create(STACKFRAMEINFO);
646 /* allocate memory from the GC heap and copy the stacktrace buffer */
647 /* ATTENTION: use a bytearray for this to not confuse the GC */
649 ba_size = sizeof(stacktracebuffer) +
650 sizeof(stacktrace_entry) * stb->used -
651 sizeof(stacktrace_entry) * STACKTRACE_CAPACITY_DEFAULT;
652 ba = builtin_newarray_byte(ba_size);
657 MCOPY(LLNI_array_data(ba), stb, u1, ba_size);
659 /* release dump memory */
661 dump_release(dumpsize);
663 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
668 dump_release(dumpsize);
670 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
677 /* stacktrace_getClassContext **************************************************
679 Creates a Class context array.
682 the array of java.lang.Class objects, or
683 NULL if an exception has been thrown
685 *******************************************************************************/
687 java_handle_objectarray_t *stacktrace_getClassContext(void)
689 stacktracebuffer *stb;
690 stacktrace_entry *ste;
691 java_handle_objectarray_t *oa;
695 CYCLES_STATS_DECLARE_AND_START
697 /* mark start of dump memory area */
699 dumpsize = dump_size();
701 /* create a stacktrace for the current thread */
703 stb = stacktrace_create(STACKFRAMEINFO);
708 /* calculate the size of the Class array */
710 for (i = 0, oalength = 0; i < stb->used; i++)
711 if (stb->entries[i].method != NULL)
714 /* The first entry corresponds to the method whose implementation */
715 /* calls stacktrace_getClassContext. We remove that entry. */
717 ste = &(stb->entries[0]);
721 /* allocate the Class array */
723 oa = builtin_anewarray(oalength, class_java_lang_Class);
727 /* fill the Class array from the stacktracebuffer */
729 for(i = 0; i < oalength; i++, ste++) {
730 if (ste->method == NULL) {
735 LLNI_array_direct(oa, i) = (java_object_t *) ste->method->class;
738 /* release dump memory */
740 dump_release(dumpsize);
742 CYCLES_STATS_END(stacktrace_getClassContext)
747 dump_release(dumpsize);
749 CYCLES_STATS_END(stacktrace_getClassContext)
755 /* stacktrace_getCurrentClass **************************************************
757 Find the current class by walking the stack trace.
759 Quote from the JNI documentation:
761 In the Java 2 Platform, FindClass locates the class loader
762 associated with the current native method. If the native code
763 belongs to a system class, no class loader will be
764 involved. Otherwise, the proper class loader will be invoked to
765 load and link the named class. When FindClass is called through the
766 Invocation Interface, there is no current native method or its
767 associated class loader. In that case, the result of
768 ClassLoader.getBaseClassLoader is used."
770 *******************************************************************************/
772 #if defined(ENABLE_JAVASE)
773 classinfo *stacktrace_getCurrentClass(void)
775 stacktracebuffer *stb;
776 stacktrace_entry *ste;
780 CYCLES_STATS_DECLARE_AND_START
782 /* mark start of dump memory area */
784 dumpsize = dump_size();
786 /* create a stacktrace for the current thread */
788 stb = stacktrace_create(STACKFRAMEINFO);
791 goto return_NULL; /* XXX exception: how to distinguish from normal NULL return? */
793 /* iterate over all stacktrace entries and find the first suitable
796 for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
802 if (m->class == class_java_security_PrivilegedAction)
805 if (m->class != NULL) {
806 dump_release(dumpsize);
808 CYCLES_STATS_END(stacktrace_getCurrentClass)
814 /* no Java method found on the stack */
817 dump_release(dumpsize);
819 CYCLES_STATS_END(stacktrace_getCurrentClass)
823 #endif /* ENABLE_JAVASE */
826 /* stacktrace_getStack *********************************************************
828 Create a 2-dimensional array for java.security.VMAccessControler.
832 NULL if an exception has been thrown
834 *******************************************************************************/
836 #if defined(ENABLE_JAVASE)
837 java_handle_objectarray_t *stacktrace_getStack(void)
839 stacktracebuffer *stb;
840 stacktrace_entry *ste;
841 java_handle_objectarray_t *oa;
842 java_handle_objectarray_t *classes;
843 java_handle_objectarray_t *methodnames;
845 java_handle_t *string;
848 CYCLES_STATS_DECLARE_AND_START
850 /* mark start of dump memory area */
852 dumpsize = dump_size();
854 /* create a stacktrace for the current thread */
856 stb = stacktrace_create(STACKFRAMEINFO);
861 /* get the first stacktrace entry */
863 ste = &(stb->entries[0]);
865 /* allocate all required arrays */
867 oa = builtin_anewarray(2, arrayclass_java_lang_Object);
872 classes = builtin_anewarray(stb->used, class_java_lang_Class);
877 methodnames = builtin_anewarray(stb->used, class_java_lang_String);
879 if (methodnames == NULL)
882 /* set up the 2-dimensional array */
884 array_objectarray_element_set(oa, 0, (java_handle_t *) classes);
885 array_objectarray_element_set(oa, 1, (java_handle_t *) methodnames);
887 /* iterate over all stacktrace entries */
889 for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
890 c = ste->method->class;
892 LLNI_array_direct(classes, i) = (java_object_t *) c;
894 string = javastring_new(ste->method->name);
899 array_objectarray_element_set(methodnames, i, string);
902 /* return the 2-dimensional array */
904 dump_release(dumpsize);
906 CYCLES_STATS_END(stacktrace_getStack)
911 dump_release(dumpsize);
913 CYCLES_STATS_END(stacktrace_getStack)
917 #endif /* ENABLE_JAVASE */
920 /* stacktrace_print_trace_from_buffer ******************************************
922 Print the stacktrace of a given stacktracebuffer with CACAO intern
923 methods (no Java help). This method is used by
924 stacktrace_dump_trace and builtin_trace_exception.
926 *******************************************************************************/
928 void stacktrace_print_trace_from_buffer(stacktracebuffer *stb)
930 stacktrace_entry *ste;
934 ste = &(stb->entries[0]);
936 for (i = 0; i < stb->used; i++, ste++) {
940 utf_display_printable_ascii_classname(m->class->name);
942 utf_display_printable_ascii(m->name);
943 utf_display_printable_ascii(m->descriptor);
945 if (m->flags & ACC_NATIVE) {
946 puts("(Native Method)");
950 utf_display_printable_ascii(m->class->sourcefile);
951 printf(":%d)\n", (u4) ste->linenumber);
955 /* just to be sure */
961 /* stacktrace_print_trace ******************************************************
963 Print the stacktrace of a given exception. More or less a wrapper
964 to stacktrace_print_trace_from_buffer.
966 *******************************************************************************/
968 void stacktrace_print_trace(java_handle_t *xptr)
970 java_lang_Throwable *t;
971 #if defined(WITH_CLASSPATH_GNU)
972 java_lang_VMThrowable *vmt;
974 java_handle_bytearray_t *ba;
975 stacktracebuffer *stb;
977 t = (java_lang_Throwable *) xptr;
982 /* now print the stacktrace */
984 #if defined(WITH_CLASSPATH_GNU)
985 LLNI_field_get_ref(t, vmState, vmt);
986 LLNI_field_get_ref(vmt, vmData, ba);
987 #elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
988 LLNI_field_get_ref(t, backtrace, ba);
990 # error unknown classpath configuration
994 stb = (stacktracebuffer *) LLNI_array_data(ba);
996 stacktrace_print_trace_from_buffer(stb);
1000 #if defined(ENABLE_CYCLES_STATS)
1001 void stacktrace_print_cycles_stats(FILE *file)
1003 CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead,file);
1004 CYCLES_STATS_PRINT(stacktrace_fillInStackTrace,file);
1005 CYCLES_STATS_PRINT(stacktrace_getClassContext ,file);
1006 CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,file);
1007 CYCLES_STATS_PRINT(stacktrace_getStack ,file);
1013 * These are local overrides for various environment variables in Emacs.
1014 * Please do not remove this and leave it at the end of the file, where
1015 * Emacs will automagically detect them.
1016 * ---------------------------------------------------------------------
1019 * indent-tabs-mode: t
1023 * vim:noexpandtab:sw=4:ts=4: