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
36 #include "mm/gc-common.h"
37 #include "mm/memory.h"
39 #include "vm/jit/stacktrace.h"
41 #include "vm/global.h" /* required here for native includes */
42 #include "native/jni.h"
43 #include "native/llni.h"
44 #include "native/include/java_lang_Throwable.h"
46 #if defined(WITH_CLASSPATH_GNU)
47 # include "native/include/java_lang_VMThrowable.h"
50 #if defined(ENABLE_THREADS)
51 # include "threads/native/threads.h"
53 # include "threads/none/threads.h"
56 #include "toolbox/logging.h"
58 #include "vm/builtin.h"
59 #include "vm/cycles-stats.h"
60 #include "vm/exceptions.h"
61 #include "vm/stringlocal.h"
64 #include "vm/jit/asmpart.h"
65 #include "vm/jit/codegen-common.h"
66 #include "vm/jit/methodheader.h"
68 #include "vmcore/class.h"
69 #include "vmcore/loader.h"
70 #include "vmcore/options.h"
73 /* global variables ***********************************************************/
74 #if !defined(ENABLE_THREADS)
75 stackframeinfo *_no_threads_stackframeinfo = NULL;
78 CYCLES_STATS_DECLARE(stacktrace_overhead ,100,1)
79 CYCLES_STATS_DECLARE(stacktrace_fillInStackTrace,40,5000)
80 CYCLES_STATS_DECLARE(stacktrace_getClassContext ,40,5000)
81 CYCLES_STATS_DECLARE(stacktrace_getCurrentClass ,40,5000)
82 CYCLES_STATS_DECLARE(stacktrace_getStack ,40,10000)
85 /* stacktrace_create_stackframeinfo ********************************************
87 Creates an stackframe info structure for inline code in the
90 *******************************************************************************/
92 #if defined(ENABLE_INTRP)
93 void stacktrace_create_stackframeinfo(stackframeinfo *sfi, u1 *pv, u1 *sp,
96 stackframeinfo **psfi;
100 /* get current stackframe info pointer */
102 psfi = &STACKFRAMEINFO;
104 /* if we don't have pv handy */
107 #if defined(ENABLE_INTRP)
109 pv = codegen_get_pv_from_pc(ra);
113 #if defined(ENABLE_JIT)
114 pv = md_codegen_get_pv_from_pc(ra);
119 /* get codeinfo pointer from data segment */
121 code = *((codeinfo **) (pv + CodeinfoPointer));
123 /* For asm_vm_call_method the codeinfo pointer is NULL. */
125 m = (code == NULL) ? NULL : code->m;
127 /* fill new stackframe info structure */
135 /* xpc is the same as ra, but is required in stacktrace_create */
139 /* store new stackframe info pointer */
143 #endif /* defined(ENABLE_INTRP) */
146 /* stacktrace_create_extern_stackframeinfo *************************************
148 Creates an stackframe info structure for an extern exception
149 (hardware or assembler).
151 *******************************************************************************/
153 void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv,
154 u1 *sp, u1 *ra, u1 *xpc)
156 stackframeinfo **psfi;
157 #if !defined(__I386__) && !defined(__X86_64__) && !defined(__S390__) && !defined(__M68K__)
160 #if defined(ENABLE_JIT)
164 /* get current stackframe info pointer */
166 psfi = &STACKFRAMEINFO;
168 /* sometimes we don't have pv handy (e.g. in asmpart.S:
169 L_asm_call_jit_compiler_exception or in the interpreter). */
172 #if defined(ENABLE_INTRP)
174 pv = codegen_get_pv_from_pc(ra);
178 #if defined(ENABLE_JIT)
179 # if defined(__SPARC_64__)
180 pv = md_get_pv_from_stackframe(sp);
182 pv = md_codegen_get_pv_from_pc(ra);
188 #if defined(ENABLE_JIT)
189 # if defined(ENABLE_INTRP)
190 /* When using the interpreter, we pass RA to the function. */
194 # if defined(__I386__) || defined(__X86_64__) || defined(__S390__) || defined(__M68K__)
195 /* On i386 and x86_64 we always have to get the return address
197 /* m68k has return address on stack always */
198 /* On S390 we use REG_RA as REG_ITMP3, so we have always to get
199 the RA from stack. */
201 framesize = *((u4 *) (pv + FrameSize));
203 ra = md_stacktrace_get_returnaddress(sp, framesize);
205 /* If the method is a non-leaf function, we need to get the return
206 address from the stack. For leaf functions the return address
207 is set correctly. This makes the assembler and the signal
208 handler code simpler. */
210 isleafmethod = *((s4 *) (pv + IsLeaf));
213 framesize = *((u4 *) (pv + FrameSize));
215 ra = md_stacktrace_get_returnaddress(sp, framesize);
218 # if defined(ENABLE_INTRP)
221 #endif /* defined(ENABLE_JIT) */
223 /* fill new stackframe info structure */
232 /* store new stackframe info pointer */
236 /* set the native world flag for the current thread */
237 /* ATTENTION: This flag tells the GC how to treat this thread in case of
238 a collection. Set this flag _after_ a valid stackframe info was set. */
240 THREAD_NATIVEWORLD_ENTER;
244 /* stacktrace_create_native_stackframeinfo *************************************
246 Creates a stackframe info structure for a native stub.
248 *******************************************************************************/
250 void stacktrace_create_native_stackframeinfo(stackframeinfo *sfi, u1 *pv,
253 stackframeinfo **psfi;
257 /* get codeinfo pointer from data segment */
259 code = *((codeinfo **) (pv + CodeinfoPointer));
261 /* For asm_vm_call_method the codeinfo pointer is NULL. */
263 m = (code == NULL) ? NULL : code->m;
265 /* get current stackframe info pointer */
267 psfi = &STACKFRAMEINFO;
269 /* fill new stackframe info structure */
278 /* store new stackframe info pointer */
282 /* set the native world flag for the current thread */
283 /* ATTENTION: This flag tells the GC how to treat this thread in case of
284 a collection. Set this flag _after_ a valid stackframe info was set. */
286 THREAD_NATIVEWORLD_ENTER;
290 /* stacktrace_remove_stackframeinfo ********************************************
292 Remove the topmost stackframeinfo in the current thread.
294 *******************************************************************************/
296 void stacktrace_remove_stackframeinfo(stackframeinfo *sfi)
298 stackframeinfo **psfi;
300 /* clear the native world flag for the current thread */
301 /* ATTENTION: Clear this flag _before_ removing the stackframe info */
303 THREAD_NATIVEWORLD_EXIT;
305 /* get current stackframe info pointer */
307 psfi = &STACKFRAMEINFO;
309 /* restore the old pointer */
315 /* stacktrace_add_entry ********************************************************
317 Adds a new entry to the stacktrace buffer.
319 *******************************************************************************/
321 static void stacktrace_add_entry(stacktracebuffer *stb, methodinfo *m, u2 line)
323 stacktrace_entry *ste;
325 /* check if we already reached the buffer capacity */
327 if (stb->used >= stb->capacity) {
328 /* reallocate new memory */
330 stb->entries = DMREALLOC(stb->entries, stacktrace_entry, stb->capacity,
331 stb->capacity + STACKTRACE_CAPACITY_INCREMENT);
333 /* set new buffer capacity */
335 stb->capacity = stb->capacity + STACKTRACE_CAPACITY_INCREMENT;
338 /* insert the current entry */
340 ste = &(stb->entries[stb->used]);
343 ste->linenumber = line;
345 /* increase entries used count */
351 /* stacktrace_add_method *******************************************************
353 Add stacktrace entries[1] for the given method to the stacktrace buffer.
356 stb.........stacktracebuffer to fill
357 m...........method for which entries should be created
358 pv..........pv of method
359 pc..........position of program counter within the method's code
362 true, if stacktrace entries were successfully created, false otherwise.
364 [1] In case of inlined methods there may be more than one stacktrace
365 entry for a codegen-level method. (see doc/inlining_stacktrace.txt)
367 *******************************************************************************/
369 static bool stacktrace_add_method(stacktracebuffer *stb, methodinfo *m, u1 *pv,
372 codeinfo *code; /* compiled realization of method */
375 /* find the realization of the method the pc is in */
377 code = *((codeinfo **) (pv + CodeinfoPointer));
379 /* search the line number table */
381 linenumber = dseg_get_linenumber_from_pc(&m, pv, pc);
383 /* now add a new entry to the staktrace */
385 stacktrace_add_entry(stb, m, linenumber);
391 /* stacktrace_create ***********************************************************
393 Generates a stacktrace from the thread passed into a
394 stacktracebuffer. The stacktracebuffer is allocated on the
397 NOTE: The first element in the stackframe chain must always be a
398 native stackframeinfo (e.g. VMThrowable.fillInStackTrace() is
402 pointer to the stacktracebuffer, or
403 NULL if there is no stacktrace available for the
406 *******************************************************************************/
408 stacktracebuffer *stacktrace_create(stackframeinfo *sfi)
410 stacktracebuffer *stb;
419 /* prevent compiler warnings */
425 /* create a stacktracebuffer in dump memory */
427 stb = DNEW(stacktracebuffer);
429 stb->capacity = STACKTRACE_CAPACITY_DEFAULT;
431 stb->entries = DMNEW(stacktrace_entry, STACKTRACE_CAPACITY_DEFAULT);
433 #define PRINTMETHODS 0
436 printf("\n\nfillInStackTrace start:\n");
440 /* Loop while we have a method pointer (asm_calljavafunction has
441 NULL) or there is a stackframeinfo in the chain. */
445 while ((m != NULL) || (sfi != NULL)) {
446 /* m == NULL should only happen for the first time and inline
447 stackframe infos, like from the exception stubs or the
451 /* for native stub stackframe infos, pv is always NULL */
453 if (sfi->pv == NULL) {
454 /* get methodinfo, sp and ra from the current stackframe info */
457 sp = sfi->sp; /* sp of parent Java function */
461 stacktrace_add_entry(stb, m, 0);
464 printf("ra=%p sp=%p, ", ra, sp);
466 printf(": native stub\n");
469 /* This is an native stub stackframe info, so we can
470 get the parent pv from the return address
473 #if defined(ENABLE_INTRP)
475 pv = codegen_get_pv_from_pc(ra);
479 #if defined(ENABLE_JIT)
480 pv = md_codegen_get_pv_from_pc(ra);
484 /* get methodinfo pointer from parent data segment */
486 code = *((codeinfo **) (pv + CodeinfoPointer));
488 /* For asm_vm_call_method the codeinfo pointer is
491 m = (code == NULL) ? NULL : code->m;
494 /* Inline stackframe infos are special: they have a
495 xpc of the actual exception position and the return
496 address saved since an inline stackframe info can
497 also be in a leaf method (no return address saved
498 on stack!!!). ATTENTION: This one is also for
499 hardware exceptions!!! */
501 /* get methodinfo, sp and ra from the current stackframe info */
503 m = sfi->method; /* m == NULL */
504 pv = sfi->pv; /* pv of parent Java function */
505 sp = sfi->sp; /* sp of parent Java function */
506 ra = sfi->ra; /* ra of parent Java function */
507 xpc = sfi->xpc; /* actual exception position */
510 printf("ra=%p sp=%p, ", ra, sp);
511 printf("NULL: inline stub\n");
515 /* get methodinfo from current Java method */
517 code = *((codeinfo **) (pv + CodeinfoPointer));
519 /* For asm_vm_call_method the codeinfo pointer is
522 m = (code == NULL) ? NULL : code->m;
524 /* if m == NULL, this is a asm_calljavafunction call */
528 printf("ra=%p sp=%p, ", ra, sp);
530 printf(": inline stub parent");
534 #if defined(ENABLE_INTRP)
538 /* add the method to the stacktrace */
540 stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) xpc));
542 /* get the current stack frame size */
544 framesize = *((u4 *) (pv + FrameSize));
547 printf(", framesize=%d\n", framesize);
551 /* Set stack pointer to stackframe of parent Java
552 function of the current Java function. */
554 #if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
555 sp += framesize + SIZEOF_VOID_P;
556 #elif defined(__SPARC_64__)
557 sp = md_get_framepointer(sp);
562 /* get data segment and methodinfo pointer from
565 #if defined(ENABLE_JIT)
566 pv = md_codegen_get_pv_from_pc(ra);
569 code = *((codeinfo **) (pv + CodeinfoPointer));
571 /* For asm_vm_call_method the codeinfo pointer is
574 m = (code == NULL) ? NULL : code->m;
576 #if defined(ENABLE_INTRP)
582 printf("ra=%p sp=%p, ", ra, sp);
583 printf("asm_calljavafunction\n");
589 /* get previous stackframeinfo in the chain */
595 printf("ra=%p sp=%p, ", ra, sp);
601 /* JIT method found, add it to the stacktrace (we subtract
602 1 from the return address since it points the the
603 instruction after call). */
605 stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) ra) - 1);
607 /* get the current stack frame size */
609 framesize = *((u4 *) (pv + FrameSize));
612 printf(", framesize=%d\n", framesize);
616 /* get return address of current stack frame */
618 #if defined(ENABLE_JIT)
619 # if defined(ENABLE_INTRP)
621 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
624 ra = md_stacktrace_get_returnaddress(sp, framesize);
626 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
629 /* get data segment and methodinfo pointer from parent method */
631 #if defined(ENABLE_INTRP)
633 pv = codegen_get_pv_from_pc(ra);
637 #if defined(ENABLE_JIT)
638 # if defined(__SPARC_64__)
639 sp = md_get_framepointer(sp);
640 pv = md_get_pv_from_stackframe(sp);
642 pv = md_codegen_get_pv_from_pc(ra);
647 code = *((codeinfo **) (pv + CodeinfoPointer));
649 /* For asm_vm_call_method the codeinfo pointer is NULL. */
651 m = (code == NULL) ? NULL : code->m;
655 #if defined(ENABLE_INTRP)
657 sp = *(u1 **) (sp - framesize);
661 #if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
662 sp += framesize + SIZEOF_VOID_P;
663 #elif defined(__SPARC_64__)
664 /* already has the new sp */
672 /* return the stacktracebuffer */
681 /* stacktrace_fillInStackTrace *************************************************
683 Generate a stacktrace from the current thread for
684 java.lang.VMThrowable.fillInStackTrace.
686 *******************************************************************************/
688 stacktracecontainer *stacktrace_fillInStackTrace(void)
690 stacktracebuffer *stb;
691 stacktracecontainer *gcstc;
694 CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
696 /* mark start of dump memory area */
698 dumpsize = dump_size();
700 /* create a stacktrace from the current thread */
702 stb = stacktrace_create(STACKFRAMEINFO);
707 /* allocate memory from the GC heap and copy the stacktrace buffer */
708 /* ATTENTION: use stacktracecontainer for this and make it look like
711 gcstc_size = sizeof(stacktracebuffer) +
712 sizeof(stacktrace_entry) * stb->used;
713 gcstc = (stacktracecontainer *) builtin_newarray_byte(gcstc_size);
718 gcstc->stb.capacity = stb->capacity;
719 gcstc->stb.used = stb->used;
720 gcstc->stb.entries = gcstc->data;
722 MCOPY(gcstc->data, stb->entries, stacktrace_entry, stb->used);
724 /* release dump memory */
726 dump_release(dumpsize);
728 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
733 dump_release(dumpsize);
735 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
742 /* stacktrace_getClassContext **************************************************
744 Creates a Class context array.
747 the array of java.lang.Class objects, or
748 NULL if an exception has been thrown
750 *******************************************************************************/
752 java_handle_objectarray_t *stacktrace_getClassContext(void)
754 stacktracebuffer *stb;
755 stacktrace_entry *ste;
756 java_handle_objectarray_t *oa;
760 CYCLES_STATS_DECLARE_AND_START
762 /* mark start of dump memory area */
764 dumpsize = dump_size();
766 /* create a stacktrace for the current thread */
768 stb = stacktrace_create(STACKFRAMEINFO);
773 /* calculate the size of the Class array */
775 for (i = 0, oalength = 0; i < stb->used; i++)
776 if (stb->entries[i].method != NULL)
779 /* The first entry corresponds to the method whose implementation */
780 /* calls stacktrace_getClassContext. We remove that entry. */
782 ste = &(stb->entries[0]);
786 /* allocate the Class array */
788 oa = builtin_anewarray(oalength, class_java_lang_Class);
792 /* fill the Class array from the stacktracebuffer */
794 for(i = 0; i < oalength; i++, ste++) {
795 if (ste->method == NULL) {
800 oa->data[i] = (java_object_t *) ste->method->class;
803 /* release dump memory */
805 dump_release(dumpsize);
807 CYCLES_STATS_END(stacktrace_getClassContext)
812 dump_release(dumpsize);
814 CYCLES_STATS_END(stacktrace_getClassContext)
820 /* stacktrace_getCurrentClass **************************************************
822 Find the current class by walking the stack trace.
824 Quote from the JNI documentation:
826 In the Java 2 Platform, FindClass locates the class loader
827 associated with the current native method. If the native code
828 belongs to a system class, no class loader will be
829 involved. Otherwise, the proper class loader will be invoked to
830 load and link the named class. When FindClass is called through the
831 Invocation Interface, there is no current native method or its
832 associated class loader. In that case, the result of
833 ClassLoader.getBaseClassLoader is used."
835 *******************************************************************************/
837 #if defined(ENABLE_JAVASE)
838 classinfo *stacktrace_getCurrentClass(void)
840 stacktracebuffer *stb;
841 stacktrace_entry *ste;
845 CYCLES_STATS_DECLARE_AND_START
847 /* mark start of dump memory area */
849 dumpsize = dump_size();
851 /* create a stacktrace for the current thread */
853 stb = stacktrace_create(STACKFRAMEINFO);
856 goto return_NULL; /* XXX exception: how to distinguish from normal NULL return? */
858 /* iterate over all stacktrace entries and find the first suitable
861 for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
867 if (m->class == class_java_security_PrivilegedAction)
870 if (m->class != NULL) {
871 dump_release(dumpsize);
873 CYCLES_STATS_END(stacktrace_getCurrentClass)
879 /* no Java method found on the stack */
882 dump_release(dumpsize);
884 CYCLES_STATS_END(stacktrace_getCurrentClass)
888 #endif /* ENABLE_JAVASE */
891 /* stacktrace_getStack *********************************************************
893 Create a 2-dimensional array for java.security.VMAccessControler.
897 NULL if an exception has been thrown
899 *******************************************************************************/
901 #if defined(ENABLE_JAVASE)
902 java_handle_objectarray_t *stacktrace_getStack(void)
904 stacktracebuffer *stb;
905 stacktrace_entry *ste;
906 java_handle_objectarray_t *oa;
907 java_handle_objectarray_t *classes;
908 java_handle_objectarray_t *methodnames;
910 java_handle_t *string;
913 CYCLES_STATS_DECLARE_AND_START
915 /* mark start of dump memory area */
917 dumpsize = dump_size();
919 /* create a stacktrace for the current thread */
921 stb = stacktrace_create(STACKFRAMEINFO);
926 /* get the first stacktrace entry */
928 ste = &(stb->entries[0]);
930 /* allocate all required arrays */
932 oa = builtin_anewarray(2, arrayclass_java_lang_Object);
937 classes = builtin_anewarray(stb->used, class_java_lang_Class);
942 methodnames = builtin_anewarray(stb->used, class_java_lang_String);
944 if (methodnames == NULL)
947 /* set up the 2-dimensional array */
949 oa->data[0] = (java_object_t *) classes;
950 oa->data[1] = (java_object_t *) methodnames;
952 /* iterate over all stacktrace entries */
954 for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
955 c = ste->method->class;
957 classes->data[i] = (java_object_t *) c;
959 string = javastring_new(ste->method->name);
964 methodnames->data[i] = string;
967 /* return the 2-dimensional array */
969 dump_release(dumpsize);
971 CYCLES_STATS_END(stacktrace_getStack)
976 dump_release(dumpsize);
978 CYCLES_STATS_END(stacktrace_getStack)
982 #endif /* ENABLE_JAVASE */
985 /* stacktrace_print_trace_from_buffer ******************************************
987 Print the stacktrace of a given stacktracebuffer with CACAO intern
988 methods (no Java help). This method is used by
989 stacktrace_dump_trace and builtin_trace_exception.
991 *******************************************************************************/
993 void stacktrace_print_trace_from_buffer(stacktracebuffer *stb)
995 stacktrace_entry *ste;
999 ste = &(stb->entries[0]);
1001 for (i = 0; i < stb->used; i++, ste++) {
1005 utf_display_printable_ascii_classname(m->class->name);
1007 utf_display_printable_ascii(m->name);
1008 utf_display_printable_ascii(m->descriptor);
1010 if (m->flags & ACC_NATIVE) {
1011 puts("(Native Method)");
1015 utf_display_printable_ascii(m->class->sourcefile);
1016 printf(":%d)\n", (u4) ste->linenumber);
1020 /* just to be sure */
1026 /* stacktrace_print_trace ******************************************************
1028 Print the stacktrace of a given exception. More or less a wrapper
1029 to stacktrace_print_trace_from_buffer.
1031 *******************************************************************************/
1033 void stacktrace_print_trace(java_handle_t *xptr)
1035 java_lang_Throwable *t;
1036 #if defined(WITH_CLASSPATH_GNU)
1037 java_lang_VMThrowable *vmt;
1039 stacktracecontainer *stc;
1040 stacktracebuffer *stb;
1042 t = (java_lang_Throwable *) xptr;
1047 /* now print the stacktrace */
1049 #if defined(WITH_CLASSPATH_GNU)
1050 LLNI_field_get_ref(t, vmState, vmt);
1051 stc = (stacktracecontainer *) LLNI_field_direct(vmt, vmData);
1052 #elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
1053 stc = (stacktracecontainer *) t->backtrace;
1055 # error unknown classpath configuration
1060 stacktrace_print_trace_from_buffer(stb);
1064 #if defined(ENABLE_CYCLES_STATS)
1065 void stacktrace_print_cycles_stats(FILE *file)
1067 CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead,file);
1068 CYCLES_STATS_PRINT(stacktrace_fillInStackTrace,file);
1069 CYCLES_STATS_PRINT(stacktrace_getClassContext ,file);
1070 CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,file);
1071 CYCLES_STATS_PRINT(stacktrace_getStack ,file);
1077 * These are local overrides for various environment variables in Emacs.
1078 * Please do not remove this and leave it at the end of the file, where
1079 * Emacs will automagically detect them.
1080 * ---------------------------------------------------------------------
1083 * indent-tabs-mode: t
1087 * vim:noexpandtab:sw=4:ts=4: