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 */
238 /* stacktrace_create_native_stackframeinfo *************************************
240 Creates a stackframe info structure for a native stub.
242 *******************************************************************************/
244 void stacktrace_create_native_stackframeinfo(stackframeinfo *sfi, u1 *pv,
247 stackframeinfo **psfi;
251 /* get codeinfo pointer from data segment */
253 code = *((codeinfo **) (pv + CodeinfoPointer));
255 /* For asm_vm_call_method the codeinfo pointer is NULL. */
257 m = (code == NULL) ? NULL : code->m;
259 /* get current stackframe info pointer */
261 psfi = &STACKFRAMEINFO;
263 /* fill new stackframe info structure */
272 /* store new stackframe info pointer */
278 /* stacktrace_remove_stackframeinfo ********************************************
280 Remove the topmost stackframeinfo in the current thread.
282 *******************************************************************************/
284 void stacktrace_remove_stackframeinfo(stackframeinfo *sfi)
286 stackframeinfo **psfi;
288 /* get current stackframe info pointer */
290 psfi = &STACKFRAMEINFO;
292 /* restore the old pointer */
298 /* stacktrace_add_entry ********************************************************
300 Adds a new entry to the stacktrace buffer.
302 *******************************************************************************/
304 static void stacktrace_add_entry(stacktracebuffer *stb, methodinfo *m, u2 line)
306 stacktrace_entry *ste;
308 /* check if we already reached the buffer capacity */
310 if (stb->used >= stb->capacity) {
311 /* reallocate new memory */
313 stb->entries = DMREALLOC(stb->entries, stacktrace_entry, stb->capacity,
314 stb->capacity + STACKTRACE_CAPACITY_INCREMENT);
316 /* set new buffer capacity */
318 stb->capacity = stb->capacity + STACKTRACE_CAPACITY_INCREMENT;
321 /* insert the current entry */
323 ste = &(stb->entries[stb->used]);
326 ste->linenumber = line;
328 /* increase entries used count */
334 /* stacktrace_add_method *******************************************************
336 Add stacktrace entries[1] for the given method to the stacktrace buffer.
339 stb.........stacktracebuffer to fill
340 m...........method for which entries should be created
341 pv..........pv of method
342 pc..........position of program counter within the method's code
345 true, if stacktrace entries were successfully created, false otherwise.
347 [1] In case of inlined methods there may be more than one stacktrace
348 entry for a codegen-level method. (see doc/inlining_stacktrace.txt)
350 *******************************************************************************/
352 static bool stacktrace_add_method(stacktracebuffer *stb, methodinfo *m, u1 *pv,
355 codeinfo *code; /* compiled realization of method */
358 /* find the realization of the method the pc is in */
360 code = *((codeinfo **) (pv + CodeinfoPointer));
362 /* search the line number table */
364 linenumber = dseg_get_linenumber_from_pc(&m, pv, pc);
366 /* now add a new entry to the staktrace */
368 stacktrace_add_entry(stb, m, linenumber);
374 /* stacktrace_create ***********************************************************
376 Generates a stacktrace from the thread passed into a
377 stacktracebuffer. The stacktracebuffer is allocated on the
380 NOTE: The first element in the stackframe chain must always be a
381 native stackframeinfo (e.g. VMThrowable.fillInStackTrace() is
385 pointer to the stacktracebuffer, or
386 NULL if there is no stacktrace available for the
389 *******************************************************************************/
391 stacktracebuffer *stacktrace_create(stackframeinfo *sfi)
393 stacktracebuffer *stb;
402 /* prevent compiler warnings */
408 /* create a stacktracebuffer in dump memory */
410 stb = DNEW(stacktracebuffer);
412 stb->capacity = STACKTRACE_CAPACITY_DEFAULT;
414 stb->entries = DMNEW(stacktrace_entry, STACKTRACE_CAPACITY_DEFAULT);
416 #define PRINTMETHODS 0
419 printf("\n\nfillInStackTrace start:\n");
423 /* Loop while we have a method pointer (asm_calljavafunction has
424 NULL) or there is a stackframeinfo in the chain. */
428 while ((m != NULL) || (sfi != NULL)) {
429 /* m == NULL should only happen for the first time and inline
430 stackframe infos, like from the exception stubs or the
434 /* for native stub stackframe infos, pv is always NULL */
436 if (sfi->pv == NULL) {
437 /* get methodinfo, sp and ra from the current stackframe info */
440 sp = sfi->sp; /* sp of parent Java function */
444 stacktrace_add_entry(stb, m, 0);
447 printf("ra=%p sp=%p, ", ra, sp);
449 printf(": native stub\n");
452 /* This is an native stub stackframe info, so we can
453 get the parent pv from the return address
456 #if defined(ENABLE_INTRP)
458 pv = codegen_get_pv_from_pc(ra);
462 #if defined(ENABLE_JIT)
463 pv = md_codegen_get_pv_from_pc(ra);
467 /* get methodinfo pointer from parent data segment */
469 code = *((codeinfo **) (pv + CodeinfoPointer));
471 /* For asm_vm_call_method the codeinfo pointer is
474 m = (code == NULL) ? NULL : code->m;
477 /* Inline stackframe infos are special: they have a
478 xpc of the actual exception position and the return
479 address saved since an inline stackframe info can
480 also be in a leaf method (no return address saved
481 on stack!!!). ATTENTION: This one is also for
482 hardware exceptions!!! */
484 /* get methodinfo, sp and ra from the current stackframe info */
486 m = sfi->method; /* m == NULL */
487 pv = sfi->pv; /* pv of parent Java function */
488 sp = sfi->sp; /* sp of parent Java function */
489 ra = sfi->ra; /* ra of parent Java function */
490 xpc = sfi->xpc; /* actual exception position */
493 printf("ra=%p sp=%p, ", ra, sp);
494 printf("NULL: inline stub\n");
498 /* get methodinfo from current Java method */
500 code = *((codeinfo **) (pv + CodeinfoPointer));
502 /* For asm_vm_call_method the codeinfo pointer is
505 m = (code == NULL) ? NULL : code->m;
507 /* if m == NULL, this is a asm_calljavafunction call */
511 printf("ra=%p sp=%p, ", ra, sp);
513 printf(": inline stub parent");
517 #if defined(ENABLE_INTRP)
521 /* add the method to the stacktrace */
523 stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) xpc));
525 /* get the current stack frame size */
527 framesize = *((u4 *) (pv + FrameSize));
530 printf(", framesize=%d\n", framesize);
534 /* Set stack pointer to stackframe of parent Java
535 function of the current Java function. */
537 #if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
538 sp += framesize + SIZEOF_VOID_P;
539 #elif defined(__SPARC_64__)
540 sp = md_get_framepointer(sp);
545 /* get data segment and methodinfo pointer from
548 #if defined(ENABLE_JIT)
549 pv = md_codegen_get_pv_from_pc(ra);
552 code = *((codeinfo **) (pv + CodeinfoPointer));
554 /* For asm_vm_call_method the codeinfo pointer is
557 m = (code == NULL) ? NULL : code->m;
559 #if defined(ENABLE_INTRP)
565 printf("ra=%p sp=%p, ", ra, sp);
566 printf("asm_calljavafunction\n");
572 /* get previous stackframeinfo in the chain */
578 printf("ra=%p sp=%p, ", ra, sp);
584 /* JIT method found, add it to the stacktrace (we subtract
585 1 from the return address since it points the the
586 instruction after call). */
588 stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) ra) - 1);
590 /* get the current stack frame size */
592 framesize = *((u4 *) (pv + FrameSize));
595 printf(", framesize=%d\n", framesize);
599 /* get return address of current stack frame */
601 #if defined(ENABLE_JIT)
602 # if defined(ENABLE_INTRP)
604 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
607 ra = md_stacktrace_get_returnaddress(sp, framesize);
609 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
612 /* get data segment and methodinfo pointer from parent method */
614 #if defined(ENABLE_INTRP)
616 pv = codegen_get_pv_from_pc(ra);
620 #if defined(ENABLE_JIT)
621 # if defined(__SPARC_64__)
622 sp = md_get_framepointer(sp);
623 pv = md_get_pv_from_stackframe(sp);
625 pv = md_codegen_get_pv_from_pc(ra);
630 code = *((codeinfo **) (pv + CodeinfoPointer));
632 /* For asm_vm_call_method the codeinfo pointer is NULL. */
634 m = (code == NULL) ? NULL : code->m;
638 #if defined(ENABLE_INTRP)
640 sp = *(u1 **) (sp - framesize);
644 #if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
645 sp += framesize + SIZEOF_VOID_P;
646 #elif defined(__SPARC_64__)
647 /* already has the new sp */
655 /* return the stacktracebuffer */
664 /* stacktrace_fillInStackTrace *************************************************
666 Generate a stacktrace from the current thread for
667 java.lang.VMThrowable.fillInStackTrace.
669 *******************************************************************************/
671 stacktracecontainer *stacktrace_fillInStackTrace(void)
673 stacktracebuffer *stb;
674 stacktracecontainer *gcstc;
677 CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
679 /* mark start of dump memory area */
681 dumpsize = dump_size();
683 /* create a stacktrace from the current thread */
685 stb = stacktrace_create(STACKFRAMEINFO);
690 /* allocate memory from the GC heap and copy the stacktrace buffer */
691 /* ATTENTION: use stacktracecontainer for this and make it look like
694 gcstc_size = sizeof(stacktracebuffer) +
695 sizeof(stacktrace_entry) * stb->used;
696 gcstc = (stacktracecontainer *) builtin_newarray_byte(gcstc_size);
701 gcstc->stb.capacity = stb->capacity;
702 gcstc->stb.used = stb->used;
703 gcstc->stb.entries = gcstc->data;
705 MCOPY(gcstc->data, stb->entries, stacktrace_entry, stb->used);
707 /* release dump memory */
709 dump_release(dumpsize);
711 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
716 dump_release(dumpsize);
718 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
725 /* stacktrace_getClassContext **************************************************
727 Creates a Class context array.
730 the array of java.lang.Class objects, or
731 NULL if an exception has been thrown
733 *******************************************************************************/
735 java_handle_objectarray_t *stacktrace_getClassContext(void)
737 stacktracebuffer *stb;
738 stacktrace_entry *ste;
739 java_handle_objectarray_t *oa;
743 CYCLES_STATS_DECLARE_AND_START
745 /* mark start of dump memory area */
747 dumpsize = dump_size();
749 /* create a stacktrace for the current thread */
751 stb = stacktrace_create(STACKFRAMEINFO);
756 /* calculate the size of the Class array */
758 for (i = 0, oalength = 0; i < stb->used; i++)
759 if (stb->entries[i].method != NULL)
762 /* The first entry corresponds to the method whose implementation */
763 /* calls stacktrace_getClassContext. We remove that entry. */
765 ste = &(stb->entries[0]);
769 /* allocate the Class array */
771 oa = builtin_anewarray(oalength, class_java_lang_Class);
775 /* fill the Class array from the stacktracebuffer */
777 for(i = 0; i < oalength; i++, ste++) {
778 if (ste->method == NULL) {
783 oa->data[i] = (java_object_t *) ste->method->class;
786 /* release dump memory */
788 dump_release(dumpsize);
790 CYCLES_STATS_END(stacktrace_getClassContext)
795 dump_release(dumpsize);
797 CYCLES_STATS_END(stacktrace_getClassContext)
803 /* stacktrace_getCurrentClass **************************************************
805 Find the current class by walking the stack trace.
807 Quote from the JNI documentation:
809 In the Java 2 Platform, FindClass locates the class loader
810 associated with the current native method. If the native code
811 belongs to a system class, no class loader will be
812 involved. Otherwise, the proper class loader will be invoked to
813 load and link the named class. When FindClass is called through the
814 Invocation Interface, there is no current native method or its
815 associated class loader. In that case, the result of
816 ClassLoader.getBaseClassLoader is used."
818 *******************************************************************************/
820 #if defined(ENABLE_JAVASE)
821 classinfo *stacktrace_getCurrentClass(void)
823 stacktracebuffer *stb;
824 stacktrace_entry *ste;
828 CYCLES_STATS_DECLARE_AND_START
830 /* mark start of dump memory area */
832 dumpsize = dump_size();
834 /* create a stacktrace for the current thread */
836 stb = stacktrace_create(STACKFRAMEINFO);
839 goto return_NULL; /* XXX exception: how to distinguish from normal NULL return? */
841 /* iterate over all stacktrace entries and find the first suitable
844 for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
850 if (m->class == class_java_security_PrivilegedAction)
853 if (m->class != NULL) {
854 dump_release(dumpsize);
856 CYCLES_STATS_END(stacktrace_getCurrentClass)
862 /* no Java method found on the stack */
865 dump_release(dumpsize);
867 CYCLES_STATS_END(stacktrace_getCurrentClass)
871 #endif /* ENABLE_JAVASE */
874 /* stacktrace_getStack *********************************************************
876 Create a 2-dimensional array for java.security.VMAccessControler.
880 NULL if an exception has been thrown
882 *******************************************************************************/
884 #if defined(ENABLE_JAVASE)
885 java_handle_objectarray_t *stacktrace_getStack(void)
887 stacktracebuffer *stb;
888 stacktrace_entry *ste;
889 java_handle_objectarray_t *oa;
890 java_handle_objectarray_t *classes;
891 java_handle_objectarray_t *methodnames;
893 java_handle_t *string;
896 CYCLES_STATS_DECLARE_AND_START
898 /* mark start of dump memory area */
900 dumpsize = dump_size();
902 /* create a stacktrace for the current thread */
904 stb = stacktrace_create(STACKFRAMEINFO);
909 /* get the first stacktrace entry */
911 ste = &(stb->entries[0]);
913 /* allocate all required arrays */
915 oa = builtin_anewarray(2, arrayclass_java_lang_Object);
920 classes = builtin_anewarray(stb->used, class_java_lang_Class);
925 methodnames = builtin_anewarray(stb->used, class_java_lang_String);
927 if (methodnames == NULL)
930 /* set up the 2-dimensional array */
932 oa->data[0] = (java_object_t *) classes;
933 oa->data[1] = (java_object_t *) methodnames;
935 /* iterate over all stacktrace entries */
937 for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
938 c = ste->method->class;
940 classes->data[i] = (java_object_t *) c;
942 string = javastring_new(ste->method->name);
947 methodnames->data[i] = string;
950 /* return the 2-dimensional array */
952 dump_release(dumpsize);
954 CYCLES_STATS_END(stacktrace_getStack)
959 dump_release(dumpsize);
961 CYCLES_STATS_END(stacktrace_getStack)
965 #endif /* ENABLE_JAVASE */
968 /* stacktrace_print_trace_from_buffer ******************************************
970 Print the stacktrace of a given stacktracebuffer with CACAO intern
971 methods (no Java help). This method is used by
972 stacktrace_dump_trace and builtin_trace_exception.
974 *******************************************************************************/
976 void stacktrace_print_trace_from_buffer(stacktracebuffer *stb)
978 stacktrace_entry *ste;
982 ste = &(stb->entries[0]);
984 for (i = 0; i < stb->used; i++, ste++) {
988 utf_display_printable_ascii_classname(m->class->name);
990 utf_display_printable_ascii(m->name);
991 utf_display_printable_ascii(m->descriptor);
993 if (m->flags & ACC_NATIVE) {
994 puts("(Native Method)");
998 utf_display_printable_ascii(m->class->sourcefile);
999 printf(":%d)\n", (u4) ste->linenumber);
1003 /* just to be sure */
1009 /* stacktrace_print_trace ******************************************************
1011 Print the stacktrace of a given exception. More or less a wrapper
1012 to stacktrace_print_trace_from_buffer.
1014 *******************************************************************************/
1016 void stacktrace_print_trace(java_handle_t *xptr)
1018 java_lang_Throwable *t;
1019 #if defined(WITH_CLASSPATH_GNU)
1020 java_lang_VMThrowable *vmt;
1022 stacktracecontainer *stc;
1023 stacktracebuffer *stb;
1025 t = (java_lang_Throwable *) xptr;
1030 /* now print the stacktrace */
1032 #if defined(WITH_CLASSPATH_GNU)
1033 LLNI_field_get_ref(t, vmState, vmt);
1034 stc = (stacktracecontainer *) LLNI_field_direct(vmt, vmData);
1035 #elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
1036 stc = (stacktracecontainer *) t->backtrace;
1038 # error unknown classpath configuration
1043 stacktrace_print_trace_from_buffer(stb);
1047 #if defined(ENABLE_CYCLES_STATS)
1048 void stacktrace_print_cycles_stats(FILE *file)
1050 CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead,file);
1051 CYCLES_STATS_PRINT(stacktrace_fillInStackTrace,file);
1052 CYCLES_STATS_PRINT(stacktrace_getClassContext ,file);
1053 CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,file);
1054 CYCLES_STATS_PRINT(stacktrace_getStack ,file);
1060 * These are local overrides for various environment variables in Emacs.
1061 * Please do not remove this and leave it at the end of the file, where
1062 * Emacs will automagically detect them.
1063 * ---------------------------------------------------------------------
1066 * indent-tabs-mode: t
1070 * vim:noexpandtab:sw=4:ts=4: