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"
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_stackframeinfo_add ***********************************************
88 Fills a stackframe info structure with the given or calculated
89 values and adds it to the chain.
91 *******************************************************************************/
93 void stacktrace_stackframeinfo_add(stackframeinfo *sfi, u1 *pv, u1 *sp, u1 *ra, u1 *xpc)
95 stackframeinfo **psfi;
97 #if !defined(__I386__) && !defined(__X86_64__) && !defined(__S390__) && !defined(__M68K__)
100 #if defined(ENABLE_JIT)
104 /* get current stackframe info pointer */
106 psfi = &STACKFRAMEINFO;
108 /* sometimes we don't have pv handy (e.g. in asmpart.S:
109 L_asm_call_jit_compiler_exception or in the interpreter). */
112 #if defined(ENABLE_INTRP)
114 pv = codegen_get_pv_from_pc(ra);
118 #if defined(ENABLE_JIT)
119 # if defined(__SPARC_64__)
120 pv = md_get_pv_from_stackframe(sp);
122 pv = md_codegen_get_pv_from_pc(ra);
128 /* Get methodinfo pointer for the parent Java method. */
130 m = code_get_methodinfo_for_pv(pv);
133 /* assert(m != NULL); */
135 #if defined(ENABLE_JIT)
136 # if defined(ENABLE_INTRP)
137 /* When using the interpreter, we pass RA to the function. */
141 # if defined(__I386__) || defined(__X86_64__) || defined(__S390__) || defined(__M68K__)
142 /* On i386 and x86_64 we always have to get the return address
144 /* m68k has return address on stack always */
145 /* On S390 we use REG_RA as REG_ITMP3, so we have always to get
146 the RA from stack. */
148 framesize = *((u4 *) (pv + FrameSize));
150 ra = md_stacktrace_get_returnaddress(sp, framesize);
152 /* If the method is a non-leaf function, we need to get the return
153 address from the stack. For leaf functions the return address
154 is set correctly. This makes the assembler and the signal
155 handler code simpler. */
157 isleafmethod = *((s4 *) (pv + IsLeaf));
160 framesize = *((u4 *) (pv + FrameSize));
162 ra = md_stacktrace_get_returnaddress(sp, framesize);
165 # if defined(ENABLE_INTRP)
170 /* Calculate XPC when not given. The XPC is then the return
171 address of the current method minus 1 because the RA points to
172 the instruction after the call instruction. This is required
173 e.g. for method stubs. */
176 xpc = (void *) (((intptr_t) ra) - 1);
179 /* Fill new stackframeinfo structure. */
188 /* Store new stackframeinfo pointer. */
192 /* set the native world flag for the current thread */
193 /* ATTENTION: This flag tells the GC how to treat this thread in case of
194 a collection. Set this flag _after_ a valid stackframe info was set. */
196 THREAD_NATIVEWORLD_ENTER;
200 /* stacktrace_stackframeinfo_remove ********************************************
202 Remove the given stackframeinfo from the chain in the current
205 *******************************************************************************/
207 void stacktrace_stackframeinfo_remove(stackframeinfo *sfi)
209 stackframeinfo **psfi;
211 /* clear the native world flag for the current thread */
212 /* ATTENTION: Clear this flag _before_ removing the stackframe info */
214 THREAD_NATIVEWORLD_EXIT;
216 /* get current stackframe info pointer */
218 psfi = &STACKFRAMEINFO;
220 /* restore the old pointer */
226 /* stacktrace_entry_add ********************************************************
228 Adds a new entry to the stacktrace buffer.
230 *******************************************************************************/
232 static inline stacktracebuffer *stacktrace_entry_add(stacktracebuffer *stb, methodinfo *m, u2 line)
234 stacktrace_entry *ste;
238 /* check if we already reached the buffer capacity */
240 if (stb->used >= stb->capacity) {
241 /* calculate size of stacktracebuffer */
243 stb_size_old = sizeof(stacktracebuffer) +
244 sizeof(stacktrace_entry) * stb->capacity -
245 sizeof(stacktrace_entry) * STACKTRACE_CAPACITY_DEFAULT;
247 stb_size_new = stb_size_old +
248 sizeof(stacktrace_entry) * STACKTRACE_CAPACITY_INCREMENT;
250 /* reallocate new memory */
252 stb = DMREALLOC(stb, u1, stb_size_old, stb_size_new);
254 /* set new buffer capacity */
256 stb->capacity = stb->capacity + STACKTRACE_CAPACITY_INCREMENT;
259 /* insert the current entry */
261 ste = &(stb->entries[stb->used]);
264 ste->linenumber = line;
266 /* increase entries used count */
274 /* stacktrace_method_add *******************************************************
276 Add stacktrace entries[1] for the given method to the stacktrace
280 stb....stacktracebuffer to fill
281 sfi....current stackframeinfo
283 stacktracebuffer after possible reallocation.
285 [1] In case of inlined methods there may be more than one stacktrace
286 entry for a codegen-level method. (see doc/inlining_stacktrace.txt)
288 *******************************************************************************/
290 static inline stacktracebuffer *stacktrace_method_add(stacktracebuffer *stb, stackframeinfo *sfi)
297 /* Get values from the stackframeinfo. */
303 /* Skip builtin methods. */
305 if (m->flags & ACC_METHOD_BUILTIN)
308 /* Search the line number table. */
310 linenumber = dseg_get_linenumber_from_pc(&m, pv, xpc);
312 /* Add a new entry to the staktrace. */
314 stb = stacktrace_entry_add(stb, m, linenumber);
320 /* stacktrace_stack_walk *******************************************************
322 Walk the stack (or the stackframeinfo-chain) to the next method.
325 sfi....stackframeinfo of current method
327 *******************************************************************************/
329 static inline void stacktrace_stack_walk(stackframeinfo *sfi)
338 /* Get values from the stackframeinfo. */
346 /* Get the current stack frame size. */
348 framesize = *((uint32_t *) (((intptr_t) pv) + FrameSize));
350 /* Get the RA of the current stack frame (RA to the parent Java
353 #if defined(ENABLE_JIT)
354 # if defined(ENABLE_INTRP)
356 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
359 ra = md_stacktrace_get_returnaddress(sp, framesize);
361 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
364 /* Get the PV for the parent Java method. */
366 #if defined(ENABLE_INTRP)
368 pv = codegen_get_pv_from_pc(ra);
372 #if defined(ENABLE_JIT)
373 # if defined(__SPARC_64__)
374 sp = md_get_framepointer(sp);
375 pv = md_get_pv_from_stackframe(sp);
377 pv = md_codegen_get_pv_from_pc(ra);
382 /* Get the methodinfo pointer for the parent Java method. */
384 m = code_get_methodinfo_for_pv(pv);
386 /* Calculate the SP for the parent Java method. */
388 #if defined(ENABLE_INTRP)
390 sp = *(u1 **) (sp - framesize);
394 #if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
395 sp = (void *) (((intptr_t) sp) + framesize + SIZEOF_VOID_P);
396 #elif defined(__SPARC_64__)
397 /* already has the new sp */
399 sp = (void *) (((intptr_t) sp) + framesize);
403 /* Store the new values in the stackframeinfo. NOTE: We subtract
404 1 from the RA to get the XPC, because the RA points to the
405 instruction after the call instruction. */
411 sfi->xpc = (void *) (((intptr_t) ra) - 1);
415 /* stacktrace_create ***********************************************************
417 Generates a stacktrace from the thread passed into a
418 stacktracebuffer. The stacktracebuffer is allocated on the
421 NOTE: The first element in the stackframe chain must always be a
422 native stackframeinfo (e.g. VMThrowable.fillInStackTrace() is
426 pointer to the stacktracebuffer, or
427 NULL if there is no stacktrace available for the
430 *******************************************************************************/
432 stacktracebuffer *stacktrace_create(stackframeinfo *sfi)
434 stacktracebuffer *stb;
435 stackframeinfo tmpsfi;
437 /* Create a stacktracebuffer in dump memory. */
439 stb = DNEW(stacktracebuffer);
441 stb->capacity = STACKTRACE_CAPACITY_DEFAULT;
445 if (opt_DebugStackTrace) {
446 printf("\n\n---> stacktrace creation start (fillInStackTrace):\n");
451 /* Put the data from the stackframeinfo into a temporary one. */
453 /* XXX This is not correct, but a workaround for threads-dump for
455 /* assert(sfi != NULL); */
459 tmpsfi.method = sfi->method;
463 tmpsfi.xpc = sfi->xpc;
465 /* Iterate till we're done. */
469 /* Print current method information. */
471 if (opt_DebugStackTrace) {
473 log_print("[stacktrace: method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
474 tmpsfi.method, tmpsfi.pv, tmpsfi.sp, tmpsfi.ra,
476 method_print(tmpsfi.method);
482 /* Check for Throwable.fillInStackTrace(). */
484 /* if (tmpsfi.method->name != utf_fillInStackTrace) { */
486 /* Add this method to the stacktrace. */
488 stb = stacktrace_method_add(stb, &tmpsfi);
491 /* Walk the stack (or the stackframeinfo chain) and get the
494 stacktrace_stack_walk(&tmpsfi);
496 /* If the new methodinfo pointer is NULL we reached a
497 asm_vm_call_method function. In this case we get the next
498 values from the previous stackframeinfo in the chain.
499 Otherwise the new values have been calculated before. */
501 if (tmpsfi.method == NULL) {
504 /* If the previous stackframeinfo in the chain is NULL we
505 reached the top of the stacktrace and leave the
511 /* Fill the temporary stackframeinfo with the new
514 tmpsfi.method = sfi->method;
518 tmpsfi.xpc = sfi->xpc;
523 if (opt_DebugStackTrace) {
524 printf("---> stacktrace creation finished.\n\n");
529 /* return the stacktracebuffer */
538 /* stacktrace_fillInStackTrace *************************************************
540 Generate a stacktrace from the current thread for
541 java.lang.VMThrowable.fillInStackTrace.
543 *******************************************************************************/
545 java_handle_bytearray_t *stacktrace_fillInStackTrace(void)
547 stacktracebuffer *stb;
548 java_handle_bytearray_t *ba;
551 CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
553 /* mark start of dump memory area */
555 dumpsize = dump_size();
557 /* create a stacktrace from the current thread */
559 stb = stacktrace_create(STACKFRAMEINFO);
564 /* allocate memory from the GC heap and copy the stacktrace buffer */
565 /* ATTENTION: use a bytearray for this to not confuse the GC */
567 ba_size = sizeof(stacktracebuffer) +
568 sizeof(stacktrace_entry) * stb->used -
569 sizeof(stacktrace_entry) * STACKTRACE_CAPACITY_DEFAULT;
570 ba = builtin_newarray_byte(ba_size);
575 MCOPY(LLNI_array_data(ba), stb, u1, ba_size);
577 /* release dump memory */
579 dump_release(dumpsize);
581 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
586 dump_release(dumpsize);
588 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
595 /* stacktrace_getClassContext **************************************************
597 Creates a Class context array.
600 the array of java.lang.Class objects, or
601 NULL if an exception has been thrown
603 *******************************************************************************/
605 java_handle_objectarray_t *stacktrace_getClassContext(void)
607 stacktracebuffer *stb;
608 stacktrace_entry *ste;
609 java_handle_objectarray_t *oa;
613 CYCLES_STATS_DECLARE_AND_START
615 /* mark start of dump memory area */
617 dumpsize = dump_size();
619 /* create a stacktrace for the current thread */
621 stb = stacktrace_create(STACKFRAMEINFO);
626 /* calculate the size of the Class array */
628 for (i = 0, oalength = 0; i < stb->used; i++)
629 if (stb->entries[i].method != NULL)
632 /* The first entry corresponds to the method whose implementation */
633 /* calls stacktrace_getClassContext. We remove that entry. */
635 ste = &(stb->entries[0]);
639 /* allocate the Class array */
641 oa = builtin_anewarray(oalength, class_java_lang_Class);
645 /* fill the Class array from the stacktracebuffer */
647 for(i = 0; i < oalength; i++, ste++) {
648 if (ste->method == NULL) {
653 LLNI_array_direct(oa, i) = (java_object_t *) ste->method->class;
656 /* release dump memory */
658 dump_release(dumpsize);
660 CYCLES_STATS_END(stacktrace_getClassContext)
665 dump_release(dumpsize);
667 CYCLES_STATS_END(stacktrace_getClassContext)
673 /* stacktrace_getCurrentClass **************************************************
675 Find the current class by walking the stack trace.
677 Quote from the JNI documentation:
679 In the Java 2 Platform, FindClass locates the class loader
680 associated with the current native method. If the native code
681 belongs to a system class, no class loader will be
682 involved. Otherwise, the proper class loader will be invoked to
683 load and link the named class. When FindClass is called through the
684 Invocation Interface, there is no current native method or its
685 associated class loader. In that case, the result of
686 ClassLoader.getBaseClassLoader is used."
688 *******************************************************************************/
690 #if defined(ENABLE_JAVASE)
691 classinfo *stacktrace_getCurrentClass(void)
693 stacktracebuffer *stb;
694 stacktrace_entry *ste;
698 CYCLES_STATS_DECLARE_AND_START
700 /* mark start of dump memory area */
702 dumpsize = dump_size();
704 /* create a stacktrace for the current thread */
706 stb = stacktrace_create(STACKFRAMEINFO);
709 goto return_NULL; /* XXX exception: how to distinguish from normal NULL return? */
711 /* iterate over all stacktrace entries and find the first suitable
714 for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
720 if (m->class == class_java_security_PrivilegedAction)
723 if (m->class != NULL) {
724 dump_release(dumpsize);
726 CYCLES_STATS_END(stacktrace_getCurrentClass)
732 /* no Java method found on the stack */
735 dump_release(dumpsize);
737 CYCLES_STATS_END(stacktrace_getCurrentClass)
741 #endif /* ENABLE_JAVASE */
744 /* stacktrace_getStack *********************************************************
746 Create a 2-dimensional array for java.security.VMAccessControler.
750 NULL if an exception has been thrown
752 *******************************************************************************/
754 #if defined(ENABLE_JAVASE)
755 java_handle_objectarray_t *stacktrace_getStack(void)
757 stacktracebuffer *stb;
758 stacktrace_entry *ste;
759 java_handle_objectarray_t *oa;
760 java_handle_objectarray_t *classes;
761 java_handle_objectarray_t *methodnames;
763 java_handle_t *string;
766 CYCLES_STATS_DECLARE_AND_START
768 /* mark start of dump memory area */
770 dumpsize = dump_size();
772 /* create a stacktrace for the current thread */
774 stb = stacktrace_create(STACKFRAMEINFO);
779 /* get the first stacktrace entry */
781 ste = &(stb->entries[0]);
783 /* allocate all required arrays */
785 oa = builtin_anewarray(2, arrayclass_java_lang_Object);
790 classes = builtin_anewarray(stb->used, class_java_lang_Class);
795 methodnames = builtin_anewarray(stb->used, class_java_lang_String);
797 if (methodnames == NULL)
800 /* set up the 2-dimensional array */
802 LLNI_objectarray_element_set(oa, 0, classes);
803 LLNI_objectarray_element_set(oa, 1, methodnames);
805 /* iterate over all stacktrace entries */
807 for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
808 c = ste->method->class;
810 LLNI_array_direct(classes, i) = (java_object_t *) c;
812 string = javastring_new(ste->method->name);
817 LLNI_objectarray_element_set(methodnames, i, string);
820 /* return the 2-dimensional array */
822 dump_release(dumpsize);
824 CYCLES_STATS_END(stacktrace_getStack)
829 dump_release(dumpsize);
831 CYCLES_STATS_END(stacktrace_getStack)
835 #endif /* ENABLE_JAVASE */
838 /* stacktrace_print_trace_from_buffer ******************************************
840 Print the stacktrace of a given stacktracebuffer with CACAO intern
841 methods (no Java help). This method is used by
842 stacktrace_dump_trace and builtin_trace_exception.
844 *******************************************************************************/
846 void stacktrace_print_trace_from_buffer(stacktracebuffer *stb)
848 stacktrace_entry *ste;
852 ste = &(stb->entries[0]);
854 for (i = 0; i < stb->used; i++, ste++) {
858 utf_display_printable_ascii_classname(m->class->name);
860 utf_display_printable_ascii(m->name);
861 utf_display_printable_ascii(m->descriptor);
863 if (m->flags & ACC_NATIVE) {
864 puts("(Native Method)");
868 utf_display_printable_ascii(m->class->sourcefile);
869 printf(":%d)\n", (u4) ste->linenumber);
873 /* just to be sure */
879 /* stacktrace_print_trace ******************************************************
881 Print the stacktrace of a given exception. More or less a wrapper
882 to stacktrace_print_trace_from_buffer.
884 *******************************************************************************/
886 void stacktrace_print_trace(java_handle_t *xptr)
888 java_lang_Throwable *t;
889 #if defined(WITH_CLASSPATH_GNU)
890 java_lang_VMThrowable *vmt;
892 java_handle_bytearray_t *ba;
893 stacktracebuffer *stb;
895 t = (java_lang_Throwable *) xptr;
900 /* now print the stacktrace */
902 #if defined(WITH_CLASSPATH_GNU)
903 LLNI_field_get_ref(t, vmState, vmt);
904 LLNI_field_get_ref(vmt, vmData, ba);
905 #elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
906 LLNI_field_get_ref(t, backtrace, ba);
908 # error unknown classpath configuration
912 stb = (stacktracebuffer *) LLNI_array_data(ba);
914 stacktrace_print_trace_from_buffer(stb);
918 #if defined(ENABLE_CYCLES_STATS)
919 void stacktrace_print_cycles_stats(FILE *file)
921 CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead,file);
922 CYCLES_STATS_PRINT(stacktrace_fillInStackTrace,file);
923 CYCLES_STATS_PRINT(stacktrace_getClassContext ,file);
924 CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,file);
925 CYCLES_STATS_PRINT(stacktrace_getStack ,file);
931 * These are local overrides for various environment variables in Emacs.
932 * Please do not remove this and leave it at the end of the file, where
933 * Emacs will automagically detect them.
934 * ---------------------------------------------------------------------
937 * indent-tabs-mode: t
941 * vim:noexpandtab:sw=4:ts=4: