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 8318 2007-08-16 10:05:34Z michi $
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/llni.h"
46 #include "native/include/java_lang_Throwable.h"
48 #if defined(WITH_CLASSPATH_GNU)
49 # include "native/include/java_lang_VMThrowable.h"
52 #if defined(ENABLE_THREADS)
53 # include "threads/native/threads.h"
55 # include "threads/none/threads.h"
58 #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 *_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_create_stackframeinfo ********************************************
89 Creates an stackframe info structure for inline code in the
92 *******************************************************************************/
94 #if defined(ENABLE_INTRP)
95 void stacktrace_create_stackframeinfo(stackframeinfo *sfi, u1 *pv, u1 *sp,
98 stackframeinfo **psfi;
102 /* get current stackframe info pointer */
104 psfi = &STACKFRAMEINFO;
106 /* if we don't have pv handy */
109 #if defined(ENABLE_INTRP)
111 pv = codegen_get_pv_from_pc(ra);
115 #if defined(ENABLE_JIT)
116 pv = md_codegen_get_pv_from_pc(ra);
121 /* get codeinfo pointer from data segment */
123 code = *((codeinfo **) (pv + CodeinfoPointer));
125 /* For asm_vm_call_method the codeinfo pointer is NULL. */
127 m = (code == NULL) ? NULL : code->m;
129 /* fill new stackframe info structure */
137 /* xpc is the same as ra, but is required in stacktrace_create */
141 /* store new stackframe info pointer */
145 #endif /* defined(ENABLE_INTRP) */
148 /* stacktrace_create_extern_stackframeinfo *************************************
150 Creates an stackframe info structure for an extern exception
151 (hardware or assembler).
153 *******************************************************************************/
155 void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv,
156 u1 *sp, u1 *ra, u1 *xpc)
158 stackframeinfo **psfi;
159 #if !defined(__I386__) && !defined(__X86_64__) && !defined(__S390__) && !defined(__M68K__)
162 #if defined(ENABLE_JIT)
166 /* get current stackframe info pointer */
168 psfi = &STACKFRAMEINFO;
170 /* sometimes we don't have pv handy (e.g. in asmpart.S:
171 L_asm_call_jit_compiler_exception or in the interpreter). */
174 #if defined(ENABLE_INTRP)
176 pv = codegen_get_pv_from_pc(ra);
180 #if defined(ENABLE_JIT)
181 # if defined(__SPARC_64__)
182 pv = md_get_pv_from_stackframe(sp);
184 pv = md_codegen_get_pv_from_pc(ra);
190 #if defined(ENABLE_JIT)
191 # if defined(ENABLE_INTRP)
192 /* When using the interpreter, we pass RA to the function. */
196 # if defined(__I386__) || defined(__X86_64__) || defined(__S390__) || defined(__M68K__)
197 /* On i386 and x86_64 we always have to get the return address
199 /* m68k has return address on stack always */
200 /* On S390 we use REG_RA as REG_ITMP3, so we have always to get
201 the RA from stack. */
203 framesize = *((u4 *) (pv + FrameSize));
205 ra = md_stacktrace_get_returnaddress(sp, framesize);
207 /* If the method is a non-leaf function, we need to get the return
208 address from the stack. For leaf functions the return address
209 is set correctly. This makes the assembler and the signal
210 handler code simpler. */
212 isleafmethod = *((s4 *) (pv + IsLeaf));
215 framesize = *((u4 *) (pv + FrameSize));
217 ra = md_stacktrace_get_returnaddress(sp, framesize);
220 # if defined(ENABLE_INTRP)
223 #endif /* defined(ENABLE_JIT) */
225 /* fill new stackframe info structure */
234 /* store new stackframe info pointer */
240 /* stacktrace_create_native_stackframeinfo *************************************
242 Creates a stackframe info structure for a native stub.
244 *******************************************************************************/
246 void stacktrace_create_native_stackframeinfo(stackframeinfo *sfi, u1 *pv,
249 stackframeinfo **psfi;
253 /* get codeinfo pointer from data segment */
255 code = *((codeinfo **) (pv + CodeinfoPointer));
257 /* For asm_vm_call_method the codeinfo pointer is NULL. */
259 m = (code == NULL) ? NULL : code->m;
261 /* get current stackframe info pointer */
263 psfi = &STACKFRAMEINFO;
265 /* fill new stackframe info structure */
274 /* store new stackframe info pointer */
280 /* stacktrace_remove_stackframeinfo ********************************************
282 Remove the topmost stackframeinfo in the current thread.
284 *******************************************************************************/
286 void stacktrace_remove_stackframeinfo(stackframeinfo *sfi)
288 stackframeinfo **psfi;
290 /* get current stackframe info pointer */
292 psfi = &STACKFRAMEINFO;
294 /* restore the old pointer */
300 /* stacktrace_add_entry ********************************************************
302 Adds a new entry to the stacktrace buffer.
304 *******************************************************************************/
306 static void stacktrace_add_entry(stacktracebuffer *stb, methodinfo *m, u2 line)
308 stacktrace_entry *ste;
310 /* check if we already reached the buffer capacity */
312 if (stb->used >= stb->capacity) {
313 /* reallocate new memory */
315 stb->entries = DMREALLOC(stb->entries, stacktrace_entry, stb->capacity,
316 stb->capacity + STACKTRACE_CAPACITY_INCREMENT);
318 /* set new buffer capacity */
320 stb->capacity = stb->capacity + STACKTRACE_CAPACITY_INCREMENT;
323 /* insert the current entry */
325 ste = &(stb->entries[stb->used]);
328 ste->linenumber = line;
330 /* increase entries used count */
336 /* stacktrace_add_method *******************************************************
338 Add stacktrace entries[1] for the given method to the stacktrace buffer.
341 stb.........stacktracebuffer to fill
342 m...........method for which entries should be created
343 pv..........pv of method
344 pc..........position of program counter within the method's code
347 true, if stacktrace entries were successfully created, false otherwise.
349 [1] In case of inlined methods there may be more than one stacktrace
350 entry for a codegen-level method. (see doc/inlining_stacktrace.txt)
352 *******************************************************************************/
354 static bool stacktrace_add_method(stacktracebuffer *stb, methodinfo *m, u1 *pv,
357 codeinfo *code; /* compiled realization of method */
360 /* find the realization of the method the pc is in */
362 code = *((codeinfo **) (pv + CodeinfoPointer));
364 /* search the line number table */
366 linenumber = dseg_get_linenumber_from_pc(&m, pv, pc);
368 /* now add a new entry to the staktrace */
370 stacktrace_add_entry(stb, m, linenumber);
376 /* stacktrace_create ***********************************************************
378 Generates a stacktrace from the thread passed into a
379 stacktracebuffer. The stacktracebuffer is allocated on the
382 NOTE: The first element in the stackframe chain must always be a
383 native stackframeinfo (e.g. VMThrowable.fillInStackTrace() is
387 pointer to the stacktracebuffer, or
388 NULL if there is no stacktrace available for the
391 *******************************************************************************/
393 stacktracebuffer *stacktrace_create(stackframeinfo *sfi)
395 stacktracebuffer *stb;
404 /* prevent compiler warnings */
410 /* create a stacktracebuffer in dump memory */
412 stb = DNEW(stacktracebuffer);
414 stb->capacity = STACKTRACE_CAPACITY_DEFAULT;
416 stb->entries = DMNEW(stacktrace_entry, STACKTRACE_CAPACITY_DEFAULT);
418 #define PRINTMETHODS 0
421 printf("\n\nfillInStackTrace start:\n");
425 /* Loop while we have a method pointer (asm_calljavafunction has
426 NULL) or there is a stackframeinfo in the chain. */
430 while ((m != NULL) || (sfi != NULL)) {
431 /* m == NULL should only happen for the first time and inline
432 stackframe infos, like from the exception stubs or the
436 /* for native stub stackframe infos, pv is always NULL */
438 if (sfi->pv == NULL) {
439 /* get methodinfo, sp and ra from the current stackframe info */
442 sp = sfi->sp; /* sp of parent Java function */
446 stacktrace_add_entry(stb, m, 0);
449 printf("ra=%p sp=%p, ", ra, sp);
451 printf(": native stub\n");
454 /* This is an native stub stackframe info, so we can
455 get the parent pv from the return address
458 #if defined(ENABLE_INTRP)
460 pv = codegen_get_pv_from_pc(ra);
464 #if defined(ENABLE_JIT)
465 pv = md_codegen_get_pv_from_pc(ra);
469 /* get methodinfo pointer from parent data segment */
471 code = *((codeinfo **) (pv + CodeinfoPointer));
473 /* For asm_vm_call_method the codeinfo pointer is
476 m = (code == NULL) ? NULL : code->m;
479 /* Inline stackframe infos are special: they have a
480 xpc of the actual exception position and the return
481 address saved since an inline stackframe info can
482 also be in a leaf method (no return address saved
483 on stack!!!). ATTENTION: This one is also for
484 hardware exceptions!!! */
486 /* get methodinfo, sp and ra from the current stackframe info */
488 m = sfi->method; /* m == NULL */
489 pv = sfi->pv; /* pv of parent Java function */
490 sp = sfi->sp; /* sp of parent Java function */
491 ra = sfi->ra; /* ra of parent Java function */
492 xpc = sfi->xpc; /* actual exception position */
495 printf("ra=%p sp=%p, ", ra, sp);
496 printf("NULL: inline stub\n");
500 /* get methodinfo from current Java method */
502 code = *((codeinfo **) (pv + CodeinfoPointer));
504 /* For asm_vm_call_method the codeinfo pointer is
507 m = (code == NULL) ? NULL : code->m;
509 /* if m == NULL, this is a asm_calljavafunction call */
513 printf("ra=%p sp=%p, ", ra, sp);
515 printf(": inline stub parent");
519 #if defined(ENABLE_INTRP)
523 /* add the method to the stacktrace */
525 stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) xpc));
527 /* get the current stack frame size */
529 framesize = *((u4 *) (pv + FrameSize));
532 printf(", framesize=%d\n", framesize);
536 /* Set stack pointer to stackframe of parent Java
537 function of the current Java function. */
539 #if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
540 sp += framesize + SIZEOF_VOID_P;
541 #elif defined(__SPARC_64__)
542 sp = md_get_framepointer(sp);
547 /* get data segment and methodinfo pointer from
550 #if defined(ENABLE_JIT)
551 pv = md_codegen_get_pv_from_pc(ra);
554 code = *((codeinfo **) (pv + CodeinfoPointer));
556 /* For asm_vm_call_method the codeinfo pointer is
559 m = (code == NULL) ? NULL : code->m;
561 #if defined(ENABLE_INTRP)
567 printf("ra=%p sp=%p, ", ra, sp);
568 printf("asm_calljavafunction\n");
574 /* get previous stackframeinfo in the chain */
580 printf("ra=%p sp=%p, ", ra, sp);
586 /* JIT method found, add it to the stacktrace (we subtract
587 1 from the return address since it points the the
588 instruction after call). */
590 stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) ra) - 1);
592 /* get the current stack frame size */
594 framesize = *((u4 *) (pv + FrameSize));
597 printf(", framesize=%d\n", framesize);
601 /* get return address of current stack frame */
603 #if defined(ENABLE_JIT)
604 # if defined(ENABLE_INTRP)
606 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
609 ra = md_stacktrace_get_returnaddress(sp, framesize);
611 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
614 /* get data segment and methodinfo pointer from parent method */
616 #if defined(ENABLE_INTRP)
618 pv = codegen_get_pv_from_pc(ra);
622 #if defined(ENABLE_JIT)
623 # if defined(__SPARC_64__)
624 sp = md_get_framepointer(sp);
625 pv = md_get_pv_from_stackframe(sp);
627 pv = md_codegen_get_pv_from_pc(ra);
632 code = *((codeinfo **) (pv + CodeinfoPointer));
634 /* For asm_vm_call_method the codeinfo pointer is NULL. */
636 m = (code == NULL) ? NULL : code->m;
640 #if defined(ENABLE_INTRP)
642 sp = *(u1 **) (sp - framesize);
646 #if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
647 sp += framesize + SIZEOF_VOID_P;
648 #elif defined(__SPARC_64__)
649 /* already has the new sp */
657 /* return the stacktracebuffer */
666 /* stacktrace_fillInStackTrace *************************************************
668 Generate a stacktrace from the current thread for
669 java.lang.VMThrowable.fillInStackTrace.
671 *******************************************************************************/
673 stacktracecontainer *stacktrace_fillInStackTrace(void)
675 stacktracebuffer *stb;
676 stacktracecontainer *gcstc;
679 CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
681 /* mark start of dump memory area */
683 dumpsize = dump_size();
685 /* create a stacktrace from the current thread */
687 stb = stacktrace_create(STACKFRAMEINFO);
692 /* allocate memory from the GC heap and copy the stacktrace buffer */
693 /* ATTENTION: use stacktracecontainer for this and make it look like
696 gcstc_size = sizeof(stacktracebuffer) +
697 sizeof(stacktrace_entry) * stb->used;
698 gcstc = (stacktracecontainer *) builtin_newarray_byte(gcstc_size);
703 gcstc->stb.capacity = stb->capacity;
704 gcstc->stb.used = stb->used;
705 gcstc->stb.entries = gcstc->data;
707 MCOPY(gcstc->data, stb->entries, stacktrace_entry, stb->used);
709 /* release dump memory */
711 dump_release(dumpsize);
713 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
718 dump_release(dumpsize);
720 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
727 /* stacktrace_getClassContext **************************************************
729 Creates a Class context array.
732 the array of java.lang.Class objects, or
733 NULL if an exception has been thrown
735 *******************************************************************************/
737 java_handle_objectarray_t *stacktrace_getClassContext(void)
739 stacktracebuffer *stb;
740 stacktrace_entry *ste;
741 java_handle_objectarray_t *oa;
745 CYCLES_STATS_DECLARE_AND_START
747 /* mark start of dump memory area */
749 dumpsize = dump_size();
751 /* create a stacktrace for the current thread */
753 stb = stacktrace_create(STACKFRAMEINFO);
758 /* calculate the size of the Class array */
760 for (i = 0, oalength = 0; i < stb->used; i++)
761 if (stb->entries[i].method != NULL)
764 /* The first entry corresponds to the method whose implementation */
765 /* calls stacktrace_getClassContext. We remove that entry. */
767 ste = &(stb->entries[0]);
771 /* allocate the Class array */
773 oa = builtin_anewarray(oalength, class_java_lang_Class);
777 /* fill the Class array from the stacktracebuffer */
779 for(i = 0; i < oalength; i++, ste++) {
780 if (ste->method == NULL) {
785 oa->data[i] = (java_object_t *) ste->method->class;
788 /* release dump memory */
790 dump_release(dumpsize);
792 CYCLES_STATS_END(stacktrace_getClassContext)
797 dump_release(dumpsize);
799 CYCLES_STATS_END(stacktrace_getClassContext)
805 /* stacktrace_getCurrentClass **************************************************
807 Find the current class by walking the stack trace.
809 Quote from the JNI documentation:
811 In the Java 2 Platform, FindClass locates the class loader
812 associated with the current native method. If the native code
813 belongs to a system class, no class loader will be
814 involved. Otherwise, the proper class loader will be invoked to
815 load and link the named class. When FindClass is called through the
816 Invocation Interface, there is no current native method or its
817 associated class loader. In that case, the result of
818 ClassLoader.getBaseClassLoader is used."
820 *******************************************************************************/
822 #if defined(ENABLE_JAVASE)
823 classinfo *stacktrace_getCurrentClass(void)
825 stacktracebuffer *stb;
826 stacktrace_entry *ste;
830 CYCLES_STATS_DECLARE_AND_START
832 /* mark start of dump memory area */
834 dumpsize = dump_size();
836 /* create a stacktrace for the current thread */
838 stb = stacktrace_create(STACKFRAMEINFO);
841 goto return_NULL; /* XXX exception: how to distinguish from normal NULL return? */
843 /* iterate over all stacktrace entries and find the first suitable
846 for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
852 if (m->class == class_java_security_PrivilegedAction)
855 if (m->class != NULL) {
856 dump_release(dumpsize);
858 CYCLES_STATS_END(stacktrace_getCurrentClass)
864 /* no Java method found on the stack */
867 dump_release(dumpsize);
869 CYCLES_STATS_END(stacktrace_getCurrentClass)
873 #endif /* ENABLE_JAVASE */
876 /* stacktrace_getStack *********************************************************
878 Create a 2-dimensional array for java.security.VMAccessControler.
882 NULL if an exception has been thrown
884 *******************************************************************************/
886 #if defined(ENABLE_JAVASE)
887 java_handle_objectarray_t *stacktrace_getStack(void)
889 stacktracebuffer *stb;
890 stacktrace_entry *ste;
891 java_handle_objectarray_t *oa;
892 java_handle_objectarray_t *classes;
893 java_handle_objectarray_t *methodnames;
895 java_handle_t *string;
898 CYCLES_STATS_DECLARE_AND_START
900 /* mark start of dump memory area */
902 dumpsize = dump_size();
904 /* create a stacktrace for the current thread */
906 stb = stacktrace_create(STACKFRAMEINFO);
911 /* get the first stacktrace entry */
913 ste = &(stb->entries[0]);
915 /* allocate all required arrays */
917 oa = builtin_anewarray(2, arrayclass_java_lang_Object);
922 classes = builtin_anewarray(stb->used, class_java_lang_Class);
927 methodnames = builtin_anewarray(stb->used, class_java_lang_String);
929 if (methodnames == NULL)
932 /* set up the 2-dimensional array */
934 oa->data[0] = (java_object_t *) classes;
935 oa->data[1] = (java_object_t *) methodnames;
937 /* iterate over all stacktrace entries */
939 for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
940 c = ste->method->class;
942 classes->data[i] = (java_object_t *) c;
944 string = javastring_new(ste->method->name);
949 methodnames->data[i] = string;
952 /* return the 2-dimensional array */
954 dump_release(dumpsize);
956 CYCLES_STATS_END(stacktrace_getStack)
961 dump_release(dumpsize);
963 CYCLES_STATS_END(stacktrace_getStack)
967 #endif /* ENABLE_JAVASE */
970 /* stacktrace_print_trace_from_buffer ******************************************
972 Print the stacktrace of a given stacktracebuffer with CACAO intern
973 methods (no Java help). This method is used by
974 stacktrace_dump_trace and builtin_trace_exception.
976 *******************************************************************************/
978 void stacktrace_print_trace_from_buffer(stacktracebuffer *stb)
980 stacktrace_entry *ste;
984 ste = &(stb->entries[0]);
986 for (i = 0; i < stb->used; i++, ste++) {
990 utf_display_printable_ascii_classname(m->class->name);
992 utf_display_printable_ascii(m->name);
993 utf_display_printable_ascii(m->descriptor);
995 if (m->flags & ACC_NATIVE) {
996 puts("(Native Method)");
1000 utf_display_printable_ascii(m->class->sourcefile);
1001 printf(":%d)\n", (u4) ste->linenumber);
1005 /* just to be sure */
1011 /* stacktrace_print_trace ******************************************************
1013 Print the stacktrace of a given exception. More or less a wrapper
1014 to stacktrace_print_trace_from_buffer.
1016 *******************************************************************************/
1018 void stacktrace_print_trace(java_handle_t *xptr)
1020 java_lang_Throwable *t;
1021 #if defined(WITH_CLASSPATH_GNU)
1022 java_lang_VMThrowable *vmt;
1024 stacktracecontainer *stc;
1025 stacktracebuffer *stb;
1027 t = (java_lang_Throwable *) xptr;
1032 /* now print the stacktrace */
1034 #if defined(WITH_CLASSPATH_GNU)
1035 LLNI_field_get_ref(t, vmState, vmt);
1036 stc = (stacktracecontainer *) LLNI_field_direct(vmt, vmData);
1037 #elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
1038 stc = (stacktracecontainer *) t->backtrace;
1040 # error unknown classpath configuration
1045 stacktrace_print_trace_from_buffer(stb);
1049 #if defined(ENABLE_CYCLES_STATS)
1050 void stacktrace_print_cycles_stats(FILE *file)
1052 CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead,file);
1053 CYCLES_STATS_PRINT(stacktrace_fillInStackTrace,file);
1054 CYCLES_STATS_PRINT(stacktrace_getClassContext ,file);
1055 CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,file);
1056 CYCLES_STATS_PRINT(stacktrace_getStack ,file);
1062 * These are local overrides for various environment variables in Emacs.
1063 * Please do not remove this and leave it at the end of the file, where
1064 * Emacs will automagically detect them.
1065 * ---------------------------------------------------------------------
1068 * indent-tabs-mode: t
1072 * vim:noexpandtab:sw=4:ts=4: