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"
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_stackframeinfo_add ***********************************************
89 Fills a stackframe info structure with the given or calculated
90 values and adds it to the chain.
92 *******************************************************************************/
94 void stacktrace_stackframeinfo_add(stackframeinfo *sfi, u1 *pv, u1 *sp, u1 *ra, u1 *xpc)
96 stackframeinfo **psfi;
98 #if !defined(__I386__) && !defined(__X86_64__) && !defined(__S390__) && !defined(__M68K__)
101 #if defined(ENABLE_JIT)
105 /* get current stackframe info pointer */
107 psfi = &STACKFRAMEINFO;
109 /* sometimes we don't have pv handy (e.g. in asmpart.S:
110 L_asm_call_jit_compiler_exception or in the interpreter). */
113 #if defined(ENABLE_INTRP)
115 pv = codegen_get_pv_from_pc(ra);
119 #if defined(ENABLE_JIT)
120 # if defined(__SPARC_64__)
121 pv = md_get_pv_from_stackframe(sp);
123 pv = md_codegen_get_pv_from_pc(ra);
129 /* Get methodinfo pointer for the parent Java method. */
131 m = code_get_methodinfo_for_pv(pv);
134 /* assert(m != NULL); */
136 #if defined(ENABLE_JIT)
137 # if defined(ENABLE_INTRP)
138 /* When using the interpreter, we pass RA to the function. */
142 # if defined(__I386__) || defined(__X86_64__) || defined(__S390__) || defined(__M68K__)
143 /* On i386 and x86_64 we always have to get the return address
145 /* m68k has return address on stack always */
146 /* On S390 we use REG_RA as REG_ITMP3, so we have always to get
147 the RA from stack. */
149 framesize = *((u4 *) (pv + FrameSize));
151 ra = md_stacktrace_get_returnaddress(sp, framesize);
153 /* If the method is a non-leaf function, we need to get the return
154 address from the stack. For leaf functions the return address
155 is set correctly. This makes the assembler and the signal
156 handler code simpler. */
158 isleafmethod = *((s4 *) (pv + IsLeaf));
161 framesize = *((u4 *) (pv + FrameSize));
163 ra = md_stacktrace_get_returnaddress(sp, framesize);
166 # if defined(ENABLE_INTRP)
171 /* Calculate XPC when not given. The XPC is then the return
172 address of the current method minus 1 because the RA points to
173 the instruction after the call instruction. This is required
174 e.g. for method stubs. */
177 xpc = (void *) (((intptr_t) ra) - 1);
180 /* Fill new stackframeinfo structure. */
190 if (opt_DebugStackFrameInfo) {
192 log_print("[stackframeinfo add : sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
193 sfi, sfi->method, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
194 method_print(sfi->method);
200 /* Store new stackframeinfo pointer. */
204 /* set the native world flag for the current thread */
205 /* ATTENTION: This flag tells the GC how to treat this thread in case of
206 a collection. Set this flag _after_ a valid stackframe info was set. */
208 THREAD_NATIVEWORLD_ENTER;
212 /* stacktrace_stackframeinfo_remove ********************************************
214 Remove the given stackframeinfo from the chain in the current
217 *******************************************************************************/
219 void stacktrace_stackframeinfo_remove(stackframeinfo *sfi)
221 stackframeinfo **psfi;
223 /* clear the native world flag for the current thread */
224 /* ATTENTION: Clear this flag _before_ removing the stackframe info */
226 THREAD_NATIVEWORLD_EXIT;
228 /* get current stackframe info pointer */
230 psfi = &STACKFRAMEINFO;
233 if (opt_DebugStackFrameInfo) {
235 log_print("[stackframeinfo remove: sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
236 sfi, sfi->method, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
237 method_print(sfi->method);
243 /* restore the old pointer */
249 /* stacktrace_entry_add ********************************************************
251 Adds a new entry to the stacktrace buffer.
253 *******************************************************************************/
255 static inline stacktracebuffer *stacktrace_entry_add(stacktracebuffer *stb, methodinfo *m, u2 line)
257 stacktrace_entry *ste;
261 /* check if we already reached the buffer capacity */
263 if (stb->used >= stb->capacity) {
264 /* calculate size of stacktracebuffer */
266 stb_size_old = sizeof(stacktracebuffer) +
267 sizeof(stacktrace_entry) * stb->capacity -
268 sizeof(stacktrace_entry) * STACKTRACE_CAPACITY_DEFAULT;
270 stb_size_new = stb_size_old +
271 sizeof(stacktrace_entry) * STACKTRACE_CAPACITY_INCREMENT;
273 /* reallocate new memory */
275 stb = DMREALLOC(stb, u1, stb_size_old, stb_size_new);
277 /* set new buffer capacity */
279 stb->capacity = stb->capacity + STACKTRACE_CAPACITY_INCREMENT;
282 /* insert the current entry */
284 ste = &(stb->entries[stb->used]);
287 ste->linenumber = line;
289 /* increase entries used count */
297 /* stacktrace_method_add *******************************************************
299 Add stacktrace entries[1] for the given method to the stacktrace
303 stb....stacktracebuffer to fill
304 sfi....current stackframeinfo
306 stacktracebuffer after possible reallocation.
308 [1] In case of inlined methods there may be more than one stacktrace
309 entry for a codegen-level method. (see doc/inlining_stacktrace.txt)
311 *******************************************************************************/
313 static inline stacktracebuffer *stacktrace_method_add(stacktracebuffer *stb, stackframeinfo *sfi)
320 /* Get values from the stackframeinfo. */
326 /* Skip builtin methods. */
328 if (m->flags & ACC_METHOD_BUILTIN)
331 /* Search the line number table. */
333 linenumber = dseg_get_linenumber_from_pc(&m, pv, xpc);
335 /* Add a new entry to the staktrace. */
337 stb = stacktrace_entry_add(stb, m, linenumber);
343 /* stacktrace_stack_walk *******************************************************
345 Walk the stack (or the stackframeinfo-chain) to the next method.
348 sfi....stackframeinfo of current method
350 *******************************************************************************/
352 static inline void stacktrace_stack_walk(stackframeinfo *sfi)
361 /* Get values from the stackframeinfo. */
369 /* Get the current stack frame size. */
371 framesize = *((uint32_t *) (((intptr_t) pv) + FrameSize));
373 /* Get the RA of the current stack frame (RA to the parent Java
374 method) if the current method is a non-leaf method. Otherwise
375 the value in the stackframeinfo is correct (from the signal
378 #if defined(ENABLE_JIT)
379 # if defined(ENABLE_INTRP)
381 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
385 /* TODO Remove jd->isleafmethod and use the flags in
388 /* if (!CODE_IS_LEAFMETHOD(m->code)) { */
389 int32_t isleafmethod = *((int32_t *) (((intptr_t) pv) + IsLeaf));
391 ra = md_stacktrace_get_returnaddress(sp, framesize);
395 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
398 /* Get the PV for the parent Java method. */
400 #if defined(ENABLE_INTRP)
402 pv = codegen_get_pv_from_pc(ra);
406 #if defined(ENABLE_JIT)
407 # if defined(__SPARC_64__)
408 sp = md_get_framepointer(sp);
409 pv = md_get_pv_from_stackframe(sp);
411 pv = md_codegen_get_pv_from_pc(ra);
416 /* Get the methodinfo pointer for the parent Java method. */
418 m = code_get_methodinfo_for_pv(pv);
420 /* Calculate the SP for the parent Java method. */
422 #if defined(ENABLE_INTRP)
424 sp = *(u1 **) (sp - framesize);
428 #if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
429 sp = (void *) (((intptr_t) sp) + framesize + SIZEOF_VOID_P);
430 #elif defined(__SPARC_64__)
431 /* already has the new sp */
433 sp = (void *) (((intptr_t) sp) + framesize);
437 /* Store the new values in the stackframeinfo. NOTE: We subtract
438 1 from the RA to get the XPC, because the RA points to the
439 instruction after the call instruction. */
445 sfi->xpc = (void *) (((intptr_t) ra) - 1);
449 /* stacktrace_create ***********************************************************
451 Generates a stacktrace from the thread passed into a
452 stacktracebuffer. The stacktracebuffer is allocated on the
455 NOTE: The first element in the stackframe chain must always be a
456 native stackframeinfo (e.g. VMThrowable.fillInStackTrace() is
460 pointer to the stacktracebuffer, or
461 NULL if there is no stacktrace available for the
464 *******************************************************************************/
466 stacktracebuffer *stacktrace_create(stackframeinfo *sfi)
468 stacktracebuffer *stb;
469 stackframeinfo tmpsfi;
471 /* Create a stacktracebuffer in dump memory. */
473 stb = DNEW(stacktracebuffer);
475 stb->capacity = STACKTRACE_CAPACITY_DEFAULT;
479 if (opt_DebugStackTrace) {
480 printf("\n\n---> stacktrace creation start (fillInStackTrace):\n");
485 /* Put the data from the stackframeinfo into a temporary one. */
487 /* XXX This is not correct, but a workaround for threads-dump for
489 /* assert(sfi != NULL); */
493 tmpsfi.method = sfi->method;
497 tmpsfi.xpc = sfi->xpc;
499 /* Iterate till we're done. */
503 /* Print current method information. */
505 if (opt_DebugStackTrace) {
507 log_print("[stacktrace: method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
508 tmpsfi.method, tmpsfi.pv, tmpsfi.sp, tmpsfi.ra,
510 method_print(tmpsfi.method);
516 /* Check for Throwable.fillInStackTrace(). */
518 /* if (tmpsfi.method->name != utf_fillInStackTrace) { */
520 /* Add this method to the stacktrace. */
522 stb = stacktrace_method_add(stb, &tmpsfi);
525 /* Walk the stack (or the stackframeinfo chain) and get the
528 stacktrace_stack_walk(&tmpsfi);
530 /* If the new methodinfo pointer is NULL we reached a
531 asm_vm_call_method function. In this case we get the next
532 values from the previous stackframeinfo in the chain.
533 Otherwise the new values have been calculated before. */
535 if (tmpsfi.method == NULL) {
538 /* If the previous stackframeinfo in the chain is NULL we
539 reached the top of the stacktrace and leave the
545 /* Fill the temporary stackframeinfo with the new
548 tmpsfi.method = sfi->method;
552 tmpsfi.xpc = sfi->xpc;
557 if (opt_DebugStackTrace) {
558 printf("---> stacktrace creation finished.\n\n");
563 /* return the stacktracebuffer */
572 /* stacktrace_fillInStackTrace *************************************************
574 Generate a stacktrace from the current thread for
575 java.lang.VMThrowable.fillInStackTrace.
577 *******************************************************************************/
579 java_handle_bytearray_t *stacktrace_fillInStackTrace(void)
581 stacktracebuffer *stb;
582 java_handle_bytearray_t *ba;
585 CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
587 /* mark start of dump memory area */
589 dumpsize = dump_size();
591 /* create a stacktrace from the current thread */
593 stb = stacktrace_create(STACKFRAMEINFO);
598 /* allocate memory from the GC heap and copy the stacktrace buffer */
599 /* ATTENTION: use a bytearray for this to not confuse the GC */
601 ba_size = sizeof(stacktracebuffer) +
602 sizeof(stacktrace_entry) * stb->used -
603 sizeof(stacktrace_entry) * STACKTRACE_CAPACITY_DEFAULT;
604 ba = builtin_newarray_byte(ba_size);
609 MCOPY(LLNI_array_data(ba), stb, u1, ba_size);
611 /* release dump memory */
613 dump_release(dumpsize);
615 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
620 dump_release(dumpsize);
622 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
629 /* stacktrace_getClassContext **************************************************
631 Creates a Class context array.
634 the array of java.lang.Class objects, or
635 NULL if an exception has been thrown
637 *******************************************************************************/
639 java_handle_objectarray_t *stacktrace_getClassContext(void)
641 stacktracebuffer *stb;
642 stacktrace_entry *ste;
643 java_handle_objectarray_t *oa;
647 CYCLES_STATS_DECLARE_AND_START
649 /* mark start of dump memory area */
651 dumpsize = dump_size();
653 /* create a stacktrace for the current thread */
655 stb = stacktrace_create(STACKFRAMEINFO);
660 /* calculate the size of the Class array */
662 for (i = 0, oalength = 0; i < stb->used; i++)
663 if (stb->entries[i].method != NULL)
666 /* The first entry corresponds to the method whose implementation */
667 /* calls stacktrace_getClassContext. We remove that entry. */
669 ste = &(stb->entries[0]);
673 /* allocate the Class array */
675 oa = builtin_anewarray(oalength, class_java_lang_Class);
679 /* fill the Class array from the stacktracebuffer */
681 for(i = 0; i < oalength; i++, ste++) {
682 if (ste->method == NULL) {
687 LLNI_array_direct(oa, i) = (java_object_t *) ste->method->class;
690 /* release dump memory */
692 dump_release(dumpsize);
694 CYCLES_STATS_END(stacktrace_getClassContext)
699 dump_release(dumpsize);
701 CYCLES_STATS_END(stacktrace_getClassContext)
707 /* stacktrace_getCurrentClass **************************************************
709 Find the current class by walking the stack trace.
711 Quote from the JNI documentation:
713 In the Java 2 Platform, FindClass locates the class loader
714 associated with the current native method. If the native code
715 belongs to a system class, no class loader will be
716 involved. Otherwise, the proper class loader will be invoked to
717 load and link the named class. When FindClass is called through the
718 Invocation Interface, there is no current native method or its
719 associated class loader. In that case, the result of
720 ClassLoader.getBaseClassLoader is used."
722 *******************************************************************************/
724 #if defined(ENABLE_JAVASE)
725 classinfo *stacktrace_getCurrentClass(void)
727 stacktracebuffer *stb;
728 stacktrace_entry *ste;
732 CYCLES_STATS_DECLARE_AND_START
734 /* mark start of dump memory area */
736 dumpsize = dump_size();
738 /* create a stacktrace for the current thread */
740 stb = stacktrace_create(STACKFRAMEINFO);
743 goto return_NULL; /* XXX exception: how to distinguish from normal NULL return? */
745 /* iterate over all stacktrace entries and find the first suitable
748 for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
754 if (m->class == class_java_security_PrivilegedAction)
757 if (m->class != NULL) {
758 dump_release(dumpsize);
760 CYCLES_STATS_END(stacktrace_getCurrentClass)
766 /* no Java method found on the stack */
769 dump_release(dumpsize);
771 CYCLES_STATS_END(stacktrace_getCurrentClass)
775 #endif /* ENABLE_JAVASE */
778 /* stacktrace_getStack *********************************************************
780 Create a 2-dimensional array for java.security.VMAccessControler.
784 NULL if an exception has been thrown
786 *******************************************************************************/
788 #if defined(ENABLE_JAVASE)
789 java_handle_objectarray_t *stacktrace_getStack(void)
791 stacktracebuffer *stb;
792 stacktrace_entry *ste;
793 java_handle_objectarray_t *oa;
794 java_handle_objectarray_t *classes;
795 java_handle_objectarray_t *methodnames;
797 java_handle_t *string;
800 CYCLES_STATS_DECLARE_AND_START
802 /* mark start of dump memory area */
804 dumpsize = dump_size();
806 /* create a stacktrace for the current thread */
808 stb = stacktrace_create(STACKFRAMEINFO);
813 /* get the first stacktrace entry */
815 ste = &(stb->entries[0]);
817 /* allocate all required arrays */
819 oa = builtin_anewarray(2, arrayclass_java_lang_Object);
824 classes = builtin_anewarray(stb->used, class_java_lang_Class);
829 methodnames = builtin_anewarray(stb->used, class_java_lang_String);
831 if (methodnames == NULL)
834 /* set up the 2-dimensional array */
836 array_objectarray_element_set(oa, 0, (java_handle_t *) classes);
837 array_objectarray_element_set(oa, 1, (java_handle_t *) methodnames);
839 /* iterate over all stacktrace entries */
841 for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
842 c = ste->method->class;
844 LLNI_array_direct(classes, i) = (java_object_t *) c;
846 string = javastring_new(ste->method->name);
851 array_objectarray_element_set(methodnames, i, string);
854 /* return the 2-dimensional array */
856 dump_release(dumpsize);
858 CYCLES_STATS_END(stacktrace_getStack)
863 dump_release(dumpsize);
865 CYCLES_STATS_END(stacktrace_getStack)
869 #endif /* ENABLE_JAVASE */
872 /* stacktrace_print_trace_from_buffer ******************************************
874 Print the stacktrace of a given stacktracebuffer with CACAO intern
875 methods (no Java help). This method is used by
876 stacktrace_dump_trace and builtin_trace_exception.
878 *******************************************************************************/
880 void stacktrace_print_trace_from_buffer(stacktracebuffer *stb)
882 stacktrace_entry *ste;
886 ste = &(stb->entries[0]);
888 for (i = 0; i < stb->used; i++, ste++) {
892 utf_display_printable_ascii_classname(m->class->name);
894 utf_display_printable_ascii(m->name);
895 utf_display_printable_ascii(m->descriptor);
897 if (m->flags & ACC_NATIVE) {
898 puts("(Native Method)");
902 utf_display_printable_ascii(m->class->sourcefile);
903 printf(":%d)\n", (u4) ste->linenumber);
907 /* just to be sure */
913 /* stacktrace_print_trace ******************************************************
915 Print the stacktrace of a given exception. More or less a wrapper
916 to stacktrace_print_trace_from_buffer.
918 *******************************************************************************/
920 void stacktrace_print_trace(java_handle_t *xptr)
922 java_lang_Throwable *t;
923 #if defined(WITH_CLASSPATH_GNU)
924 java_lang_VMThrowable *vmt;
926 java_handle_bytearray_t *ba;
927 stacktracebuffer *stb;
929 t = (java_lang_Throwable *) xptr;
934 /* now print the stacktrace */
936 #if defined(WITH_CLASSPATH_GNU)
937 LLNI_field_get_ref(t, vmState, vmt);
938 LLNI_field_get_ref(vmt, vmData, ba);
939 #elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
940 LLNI_field_get_ref(t, backtrace, ba);
942 # error unknown classpath configuration
946 stb = (stacktracebuffer *) LLNI_array_data(ba);
948 stacktrace_print_trace_from_buffer(stb);
952 #if defined(ENABLE_CYCLES_STATS)
953 void stacktrace_print_cycles_stats(FILE *file)
955 CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead,file);
956 CYCLES_STATS_PRINT(stacktrace_fillInStackTrace,file);
957 CYCLES_STATS_PRINT(stacktrace_getClassContext ,file);
958 CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,file);
959 CYCLES_STATS_PRINT(stacktrace_getStack ,file);
965 * These are local overrides for various environment variables in Emacs.
966 * Please do not remove this and leave it at the end of the file, where
967 * Emacs will automagically detect them.
968 * ---------------------------------------------------------------------
971 * indent-tabs-mode: t
975 * vim:noexpandtab:sw=4:ts=4: