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
25 $Id: stacktrace.c 8139 2007-06-24 10:12:27Z twisti $
38 #include "mm/gc-common.h"
39 #include "mm/memory.h"
41 #include "vm/jit/stacktrace.h"
43 #include "vm/global.h" /* required here for native includes */
44 #include "native/jni.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"
59 #include "vm/builtin.h"
60 #include "vm/cycles-stats.h"
61 #include "vm/exceptions.h"
62 #include "vm/stringlocal.h"
65 #include "vm/jit/asmpart.h"
66 #include "vm/jit/codegen-common.h"
67 #include "vm/jit/methodheader.h"
69 #include "vmcore/class.h"
70 #include "vmcore/loader.h"
71 #include "vmcore/options.h"
74 /* global variables ***********************************************************/
75 #if !defined(ENABLE_THREADS)
76 stackframeinfo *_no_threads_stackframeinfo = NULL;
79 CYCLES_STATS_DECLARE(stacktrace_overhead ,100,1)
80 CYCLES_STATS_DECLARE(stacktrace_fillInStackTrace,40,5000)
81 CYCLES_STATS_DECLARE(stacktrace_getClassContext ,40,5000)
82 CYCLES_STATS_DECLARE(stacktrace_getCurrentClass ,40,5000)
83 CYCLES_STATS_DECLARE(stacktrace_getStack ,40,10000)
86 /* stacktrace_create_stackframeinfo ********************************************
88 Creates an stackframe info structure for inline code in the
91 *******************************************************************************/
93 #if defined(ENABLE_INTRP)
94 void stacktrace_create_stackframeinfo(stackframeinfo *sfi, u1 *pv, u1 *sp,
97 stackframeinfo **psfi;
101 /* get current stackframe info pointer */
103 psfi = &STACKFRAMEINFO;
105 /* if we don't have pv handy */
108 #if defined(ENABLE_INTRP)
110 pv = codegen_get_pv_from_pc(ra);
114 #if defined(ENABLE_JIT)
115 pv = md_codegen_get_pv_from_pc(ra);
120 /* get codeinfo pointer from data segment */
122 code = *((codeinfo **) (pv + CodeinfoPointer));
124 /* For asm_vm_call_method the codeinfo pointer is NULL. */
126 m = (code == NULL) ? NULL : code->m;
128 /* fill new stackframe info structure */
136 /* xpc is the same as ra, but is required in stacktrace_create */
140 /* store new stackframe info pointer */
144 #endif /* defined(ENABLE_INTRP) */
147 /* stacktrace_create_extern_stackframeinfo *************************************
149 Creates an stackframe info structure for an extern exception
150 (hardware or assembler).
152 *******************************************************************************/
154 void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv,
155 u1 *sp, u1 *ra, u1 *xpc)
157 stackframeinfo **psfi;
158 #if !defined(__I386__) && !defined(__X86_64__) && !defined(__S390__) && !defined(__M68K__)
161 #if defined(ENABLE_JIT)
165 /* get current stackframe info pointer */
167 psfi = &STACKFRAMEINFO;
169 /* sometimes we don't have pv handy (e.g. in asmpart.S:
170 L_asm_call_jit_compiler_exception or in the interpreter). */
173 #if defined(ENABLE_INTRP)
175 pv = codegen_get_pv_from_pc(ra);
179 #if defined(ENABLE_JIT)
180 # if defined(__SPARC_64__)
181 pv = md_get_pv_from_stackframe(sp);
183 pv = md_codegen_get_pv_from_pc(ra);
189 #if defined(ENABLE_JIT)
190 # if defined(ENABLE_INTRP)
191 /* When using the interpreter, we pass RA to the function. */
195 # if defined(__I386__) || defined(__X86_64__) || defined(__S390__) || defined(__M68K__)
196 /* On i386 and x86_64 we always have to get the return address
198 /* m68k has return address on stack always */
199 /* On S390 we use REG_RA as REG_ITMP3, so we have always to get
200 the RA from stack. */
202 framesize = *((u4 *) (pv + FrameSize));
204 ra = md_stacktrace_get_returnaddress(sp, framesize);
206 /* If the method is a non-leaf function, we need to get the return
207 address from the stack. For leaf functions the return address
208 is set correctly. This makes the assembler and the signal
209 handler code simpler. */
211 isleafmethod = *((s4 *) (pv + IsLeaf));
214 framesize = *((u4 *) (pv + FrameSize));
216 ra = md_stacktrace_get_returnaddress(sp, framesize);
219 # if defined(ENABLE_INTRP)
222 #endif /* defined(ENABLE_JIT) */
224 /* fill new stackframe info structure */
233 /* store new stackframe info pointer */
239 /* stacktrace_create_native_stackframeinfo *************************************
241 Creates a stackframe info structure for a native stub.
243 *******************************************************************************/
245 void stacktrace_create_native_stackframeinfo(stackframeinfo *sfi, u1 *pv,
248 stackframeinfo **psfi;
252 /* get codeinfo pointer from data segment */
254 code = *((codeinfo **) (pv + CodeinfoPointer));
256 /* For asm_vm_call_method the codeinfo pointer is NULL. */
258 m = (code == NULL) ? NULL : code->m;
260 /* get current stackframe info pointer */
262 psfi = &STACKFRAMEINFO;
264 /* fill new stackframe info structure */
273 /* store new stackframe info pointer */
279 /* stacktrace_remove_stackframeinfo ********************************************
281 Remove the topmost stackframeinfo in the current thread.
283 *******************************************************************************/
285 void stacktrace_remove_stackframeinfo(stackframeinfo *sfi)
287 stackframeinfo **psfi;
289 /* get current stackframe info pointer */
291 psfi = &STACKFRAMEINFO;
293 /* restore the old pointer */
299 /* stacktrace_add_entry ********************************************************
301 Adds a new entry to the stacktrace buffer.
303 *******************************************************************************/
305 static void stacktrace_add_entry(stacktracebuffer *stb, methodinfo *m, u2 line)
307 stacktrace_entry *ste;
309 /* check if we already reached the buffer capacity */
311 if (stb->used >= stb->capacity) {
312 /* reallocate new memory */
314 stb->entries = DMREALLOC(stb->entries, stacktrace_entry, stb->capacity,
315 stb->capacity + STACKTRACE_CAPACITY_INCREMENT);
317 /* set new buffer capacity */
319 stb->capacity = stb->capacity + STACKTRACE_CAPACITY_INCREMENT;
322 /* insert the current entry */
324 ste = &(stb->entries[stb->used]);
327 ste->linenumber = line;
329 /* increase entries used count */
335 /* stacktrace_add_method *******************************************************
337 Add stacktrace entries[1] for the given method to the stacktrace buffer.
340 stb.........stacktracebuffer to fill
341 m...........method for which entries should be created
342 pv..........pv of method
343 pc..........position of program counter within the method's code
346 true, if stacktrace entries were successfully created, false otherwise.
348 [1] In case of inlined methods there may be more than one stacktrace
349 entry for a codegen-level method. (see doc/inlining_stacktrace.txt)
351 *******************************************************************************/
353 static bool stacktrace_add_method(stacktracebuffer *stb, methodinfo *m, u1 *pv,
356 codeinfo *code; /* compiled realization of method */
359 /* find the realization of the method the pc is in */
361 code = *((codeinfo **) (pv + CodeinfoPointer));
363 /* search the line number table */
365 linenumber = dseg_get_linenumber_from_pc(&m, pv, pc);
367 /* now add a new entry to the staktrace */
369 stacktrace_add_entry(stb, m, linenumber);
375 /* stacktrace_create ***********************************************************
377 Generates a stacktrace from the thread passed into a
378 stacktracebuffer. The stacktracebuffer is allocated on the
381 NOTE: The first element in the stackframe chain must always be a
382 native stackframeinfo (e.g. VMThrowable.fillInStackTrace() is
386 pointer to the stacktracebuffer, or
387 NULL if there is no stacktrace available for the
390 *******************************************************************************/
392 stacktracebuffer *stacktrace_create(stackframeinfo *sfi)
394 stacktracebuffer *stb;
403 /* prevent compiler warnings */
409 /* create a stacktracebuffer in dump memory */
411 stb = DNEW(stacktracebuffer);
413 stb->capacity = STACKTRACE_CAPACITY_DEFAULT;
415 stb->entries = DMNEW(stacktrace_entry, STACKTRACE_CAPACITY_DEFAULT);
417 #define PRINTMETHODS 0
420 printf("\n\nfillInStackTrace start:\n");
424 /* Loop while we have a method pointer (asm_calljavafunction has
425 NULL) or there is a stackframeinfo in the chain. */
429 while ((m != NULL) || (sfi != NULL)) {
430 /* m == NULL should only happen for the first time and inline
431 stackframe infos, like from the exception stubs or the
435 /* for native stub stackframe infos, pv is always NULL */
437 if (sfi->pv == NULL) {
438 /* get methodinfo, sp and ra from the current stackframe info */
441 sp = sfi->sp; /* sp of parent Java function */
445 stacktrace_add_entry(stb, m, 0);
448 printf("ra=%p sp=%p, ", ra, sp);
450 printf(": native stub\n");
453 /* This is an native stub stackframe info, so we can
454 get the parent pv from the return address
457 #if defined(ENABLE_INTRP)
459 pv = codegen_get_pv_from_pc(ra);
463 #if defined(ENABLE_JIT)
464 pv = md_codegen_get_pv_from_pc(ra);
468 /* get methodinfo pointer from parent data segment */
470 code = *((codeinfo **) (pv + CodeinfoPointer));
472 /* For asm_vm_call_method the codeinfo pointer is
475 m = (code == NULL) ? NULL : code->m;
478 /* Inline stackframe infos are special: they have a
479 xpc of the actual exception position and the return
480 address saved since an inline stackframe info can
481 also be in a leaf method (no return address saved
482 on stack!!!). ATTENTION: This one is also for
483 hardware exceptions!!! */
485 /* get methodinfo, sp and ra from the current stackframe info */
487 m = sfi->method; /* m == NULL */
488 pv = sfi->pv; /* pv of parent Java function */
489 sp = sfi->sp; /* sp of parent Java function */
490 ra = sfi->ra; /* ra of parent Java function */
491 xpc = sfi->xpc; /* actual exception position */
494 printf("ra=%p sp=%p, ", ra, sp);
495 printf("NULL: inline stub\n");
499 /* get methodinfo from current Java method */
501 code = *((codeinfo **) (pv + CodeinfoPointer));
503 /* For asm_vm_call_method the codeinfo pointer is
506 m = (code == NULL) ? NULL : code->m;
508 /* if m == NULL, this is a asm_calljavafunction call */
512 printf("ra=%p sp=%p, ", ra, sp);
514 printf(": inline stub parent");
518 #if defined(ENABLE_INTRP)
522 /* add the method to the stacktrace */
524 stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) xpc));
526 /* get the current stack frame size */
528 framesize = *((u4 *) (pv + FrameSize));
531 printf(", framesize=%d\n", framesize);
535 /* Set stack pointer to stackframe of parent Java
536 function of the current Java function. */
538 #if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
539 sp += framesize + SIZEOF_VOID_P;
540 #elif defined(__SPARC_64__)
541 sp = md_get_framepointer(sp);
546 /* get data segment and methodinfo pointer from
549 #if defined(ENABLE_JIT)
550 pv = md_codegen_get_pv_from_pc(ra);
553 code = *((codeinfo **) (pv + CodeinfoPointer));
555 /* For asm_vm_call_method the codeinfo pointer is
558 m = (code == NULL) ? NULL : code->m;
560 #if defined(ENABLE_INTRP)
566 printf("ra=%p sp=%p, ", ra, sp);
567 printf("asm_calljavafunction\n");
573 /* get previous stackframeinfo in the chain */
579 printf("ra=%p sp=%p, ", ra, sp);
585 /* JIT method found, add it to the stacktrace (we subtract
586 1 from the return address since it points the the
587 instruction after call). */
589 stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) ra) - 1);
591 /* get the current stack frame size */
593 framesize = *((u4 *) (pv + FrameSize));
596 printf(", framesize=%d\n", framesize);
600 /* get return address of current stack frame */
602 #if defined(ENABLE_JIT)
603 # if defined(ENABLE_INTRP)
605 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
608 ra = md_stacktrace_get_returnaddress(sp, framesize);
610 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
613 /* get data segment and methodinfo pointer from parent method */
615 #if defined(ENABLE_INTRP)
617 pv = codegen_get_pv_from_pc(ra);
621 #if defined(ENABLE_JIT)
622 # if defined(__SPARC_64__)
623 sp = md_get_framepointer(sp);
624 pv = md_get_pv_from_stackframe(sp);
626 pv = md_codegen_get_pv_from_pc(ra);
631 code = *((codeinfo **) (pv + CodeinfoPointer));
633 /* For asm_vm_call_method the codeinfo pointer is NULL. */
635 m = (code == NULL) ? NULL : code->m;
639 #if defined(ENABLE_INTRP)
641 sp = *(u1 **) (sp - framesize);
645 #if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
646 sp += framesize + SIZEOF_VOID_P;
647 #elif defined(__SPARC_64__)
648 /* already has the new sp */
656 /* return the stacktracebuffer */
665 /* stacktrace_fillInStackTrace *************************************************
667 Generate a stacktrace from the current thread for
668 java.lang.VMThrowable.fillInStackTrace.
670 *******************************************************************************/
672 stacktracecontainer *stacktrace_fillInStackTrace(void)
674 stacktracebuffer *stb;
675 stacktracecontainer *gcstc;
678 CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
680 /* mark start of dump memory area */
682 dumpsize = dump_size();
684 /* create a stacktrace from the current thread */
686 stb = stacktrace_create(STACKFRAMEINFO);
691 /* allocate memory from the GC heap and copy the stacktrace buffer */
692 /* ATTENTION: use stacktracecontainer for this and make it look like
695 gcstc_size = sizeof(stacktracebuffer) +
696 sizeof(stacktrace_entry) * stb->used;
697 gcstc = (stacktracecontainer *) builtin_newarray_byte(gcstc_size);
702 gcstc->stb.capacity = stb->capacity;
703 gcstc->stb.used = stb->used;
704 gcstc->stb.entries = gcstc->data;
706 MCOPY(gcstc->data, stb->entries, stacktrace_entry, stb->used);
708 /* release dump memory */
710 dump_release(dumpsize);
712 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
717 dump_release(dumpsize);
719 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
726 /* stacktrace_getClassContext **************************************************
728 Creates a Class context array.
731 the array of java.lang.Class objects, or
732 NULL if an exception has been thrown
734 *******************************************************************************/
736 java_objectarray *stacktrace_getClassContext(void)
738 stacktracebuffer *stb;
739 stacktrace_entry *ste;
740 java_objectarray *oa;
744 CYCLES_STATS_DECLARE_AND_START
746 /* mark start of dump memory area */
748 dumpsize = dump_size();
750 /* create a stacktrace for the current thread */
752 stb = stacktrace_create(STACKFRAMEINFO);
757 /* calculate the size of the Class array */
759 for (i = 0, oalength = 0; i < stb->used; i++)
760 if (stb->entries[i].method != NULL)
763 /* The first entry corresponds to the method whose implementation */
764 /* calls stacktrace_getClassContext. We remove that entry. */
766 ste = &(stb->entries[0]);
770 /* allocate the Class array */
772 oa = builtin_anewarray(oalength, class_java_lang_Class);
776 /* fill the Class array from the stacktracebuffer */
778 for(i = 0; i < oalength; i++, ste++) {
779 if (ste->method == NULL) {
784 oa->data[i] = (java_objectheader *) ste->method->class;
787 /* release dump memory */
789 dump_release(dumpsize);
791 CYCLES_STATS_END(stacktrace_getClassContext)
796 dump_release(dumpsize);
798 CYCLES_STATS_END(stacktrace_getClassContext)
804 /* stacktrace_getCurrentClass **************************************************
806 Find the current class by walking the stack trace.
808 Quote from the JNI documentation:
810 In the Java 2 Platform, FindClass locates the class loader
811 associated with the current native method. If the native code
812 belongs to a system class, no class loader will be
813 involved. Otherwise, the proper class loader will be invoked to
814 load and link the named class. When FindClass is called through the
815 Invocation Interface, there is no current native method or its
816 associated class loader. In that case, the result of
817 ClassLoader.getBaseClassLoader is used."
819 *******************************************************************************/
821 #if defined(ENABLE_JAVASE)
822 classinfo *stacktrace_getCurrentClass(void)
824 stacktracebuffer *stb;
825 stacktrace_entry *ste;
829 CYCLES_STATS_DECLARE_AND_START
831 /* mark start of dump memory area */
833 dumpsize = dump_size();
835 /* create a stacktrace for the current thread */
837 stb = stacktrace_create(STACKFRAMEINFO);
840 goto return_NULL; /* XXX exception: how to distinguish from normal NULL return? */
842 /* iterate over all stacktrace entries and find the first suitable
845 for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
851 if (m->class == class_java_security_PrivilegedAction)
854 if (m->class != NULL) {
855 dump_release(dumpsize);
857 CYCLES_STATS_END(stacktrace_getCurrentClass)
863 /* no Java method found on the stack */
866 dump_release(dumpsize);
868 CYCLES_STATS_END(stacktrace_getCurrentClass)
872 #endif /* ENABLE_JAVASE */
875 /* stacktrace_getStack *********************************************************
877 Create a 2-dimensional array for java.security.VMAccessControler.
881 NULL if an exception has been thrown
883 *******************************************************************************/
885 #if defined(ENABLE_JAVASE)
886 java_objectarray *stacktrace_getStack(void)
888 stacktracebuffer *stb;
889 stacktrace_entry *ste;
890 java_objectarray *oa;
891 java_objectarray *classes;
892 java_objectarray *methodnames;
894 java_objectheader *string;
897 CYCLES_STATS_DECLARE_AND_START
899 /* mark start of dump memory area */
901 dumpsize = dump_size();
903 /* create a stacktrace for the current thread */
905 stb = stacktrace_create(STACKFRAMEINFO);
910 /* get the first stacktrace entry */
912 ste = &(stb->entries[0]);
914 /* allocate all required arrays */
916 oa = builtin_anewarray(2, arrayclass_java_lang_Object);
921 classes = builtin_anewarray(stb->used, class_java_lang_Class);
926 methodnames = builtin_anewarray(stb->used, class_java_lang_String);
928 if (methodnames == NULL)
931 /* set up the 2-dimensional array */
933 oa->data[0] = (java_objectheader *) classes;
934 oa->data[1] = (java_objectheader *) methodnames;
936 /* iterate over all stacktrace entries */
938 for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
939 c = ste->method->class;
941 classes->data[i] = (java_objectheader *) c;
943 string = javastring_new(ste->method->name);
948 methodnames->data[i] = string;
951 /* return the 2-dimensional array */
953 dump_release(dumpsize);
955 CYCLES_STATS_END(stacktrace_getStack)
960 dump_release(dumpsize);
962 CYCLES_STATS_END(stacktrace_getStack)
966 #endif /* ENABLE_JAVASE */
969 /* stacktrace_print_trace_from_buffer ******************************************
971 Print the stacktrace of a given stacktracebuffer with CACAO intern
972 methods (no Java help). This method is used by
973 stacktrace_dump_trace and builtin_trace_exception.
975 *******************************************************************************/
977 void stacktrace_print_trace_from_buffer(stacktracebuffer *stb)
979 stacktrace_entry *ste;
983 ste = &(stb->entries[0]);
985 for (i = 0; i < stb->used; i++, ste++) {
989 utf_display_printable_ascii_classname(m->class->name);
991 utf_display_printable_ascii(m->name);
992 utf_display_printable_ascii(m->descriptor);
994 if (m->flags & ACC_NATIVE) {
995 puts("(Native Method)");
999 utf_display_printable_ascii(m->class->sourcefile);
1000 printf(":%d)\n", (u4) ste->linenumber);
1004 /* just to be sure */
1010 /* stacktrace_print_trace ******************************************************
1012 Print the stacktrace of a given exception. More or less a wrapper
1013 to stacktrace_print_trace_from_buffer.
1015 *******************************************************************************/
1017 void stacktrace_print_trace(java_objectheader *xptr)
1019 java_lang_Throwable *t;
1020 #if defined(WITH_CLASSPATH_GNU)
1021 java_lang_VMThrowable *vmt;
1023 stacktracecontainer *stc;
1024 stacktracebuffer *stb;
1026 t = (java_lang_Throwable *) xptr;
1031 /* now print the stacktrace */
1033 #if defined(WITH_CLASSPATH_GNU)
1035 stc = (stacktracecontainer *) vmt->vmData;
1036 #elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
1037 stc = (stacktracecontainer *) t->backtrace;
1039 # error unknown classpath configuration
1044 stacktrace_print_trace_from_buffer(stb);
1048 #if defined(ENABLE_CYCLES_STATS)
1049 void stacktrace_print_cycles_stats(FILE *file)
1051 CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead,file);
1052 CYCLES_STATS_PRINT(stacktrace_fillInStackTrace,file);
1053 CYCLES_STATS_PRINT(stacktrace_getClassContext ,file);
1054 CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,file);
1055 CYCLES_STATS_PRINT(stacktrace_getStack ,file);
1061 * These are local overrides for various environment variables in Emacs.
1062 * Please do not remove this and leave it at the end of the file, where
1063 * Emacs will automagically detect them.
1064 * ---------------------------------------------------------------------
1067 * indent-tabs-mode: t
1071 * vim:noexpandtab:sw=4:ts=4: