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. */
189 /* Store new stackframeinfo pointer. */
193 /* set the native world flag for the current thread */
194 /* ATTENTION: This flag tells the GC how to treat this thread in case of
195 a collection. Set this flag _after_ a valid stackframe info was set. */
197 THREAD_NATIVEWORLD_ENTER;
201 /* stacktrace_stackframeinfo_remove ********************************************
203 Remove the given stackframeinfo from the chain in the current
206 *******************************************************************************/
208 void stacktrace_stackframeinfo_remove(stackframeinfo *sfi)
210 stackframeinfo **psfi;
212 /* clear the native world flag for the current thread */
213 /* ATTENTION: Clear this flag _before_ removing the stackframe info */
215 THREAD_NATIVEWORLD_EXIT;
217 /* get current stackframe info pointer */
219 psfi = &STACKFRAMEINFO;
221 /* restore the old pointer */
227 /* stacktrace_entry_add ********************************************************
229 Adds a new entry to the stacktrace buffer.
231 *******************************************************************************/
233 static inline stacktracebuffer *stacktrace_entry_add(stacktracebuffer *stb, methodinfo *m, u2 line)
235 stacktrace_entry *ste;
239 /* check if we already reached the buffer capacity */
241 if (stb->used >= stb->capacity) {
242 /* calculate size of stacktracebuffer */
244 stb_size_old = sizeof(stacktracebuffer) +
245 sizeof(stacktrace_entry) * stb->capacity -
246 sizeof(stacktrace_entry) * STACKTRACE_CAPACITY_DEFAULT;
248 stb_size_new = stb_size_old +
249 sizeof(stacktrace_entry) * STACKTRACE_CAPACITY_INCREMENT;
251 /* reallocate new memory */
253 stb = DMREALLOC(stb, u1, stb_size_old, stb_size_new);
255 /* set new buffer capacity */
257 stb->capacity = stb->capacity + STACKTRACE_CAPACITY_INCREMENT;
260 /* insert the current entry */
262 ste = &(stb->entries[stb->used]);
265 ste->linenumber = line;
267 /* increase entries used count */
275 /* stacktrace_method_add *******************************************************
277 Add stacktrace entries[1] for the given method to the stacktrace
281 stb....stacktracebuffer to fill
282 sfi....current stackframeinfo
284 stacktracebuffer after possible reallocation.
286 [1] In case of inlined methods there may be more than one stacktrace
287 entry for a codegen-level method. (see doc/inlining_stacktrace.txt)
289 *******************************************************************************/
291 static inline stacktracebuffer *stacktrace_method_add(stacktracebuffer *stb, stackframeinfo *sfi)
298 /* Get values from the stackframeinfo. */
304 /* Skip builtin methods. */
306 if (m->flags & ACC_METHOD_BUILTIN)
309 /* Search the line number table. */
311 linenumber = dseg_get_linenumber_from_pc(&m, pv, xpc);
313 /* Add a new entry to the staktrace. */
315 stb = stacktrace_entry_add(stb, m, linenumber);
321 /* stacktrace_stack_walk *******************************************************
323 Walk the stack (or the stackframeinfo-chain) to the next method.
326 sfi....stackframeinfo of current method
328 *******************************************************************************/
330 static inline void stacktrace_stack_walk(stackframeinfo *sfi)
339 /* Get values from the stackframeinfo. */
347 /* Get the current stack frame size. */
349 framesize = *((uint32_t *) (((intptr_t) pv) + FrameSize));
351 /* Get the RA of the current stack frame (RA to the parent Java
354 #if defined(ENABLE_JIT)
355 # if defined(ENABLE_INTRP)
357 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
360 ra = md_stacktrace_get_returnaddress(sp, framesize);
362 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
365 /* Get the PV for the parent Java method. */
367 #if defined(ENABLE_INTRP)
369 pv = codegen_get_pv_from_pc(ra);
373 #if defined(ENABLE_JIT)
374 # if defined(__SPARC_64__)
375 sp = md_get_framepointer(sp);
376 pv = md_get_pv_from_stackframe(sp);
378 pv = md_codegen_get_pv_from_pc(ra);
383 /* Get the methodinfo pointer for the parent Java method. */
385 m = code_get_methodinfo_for_pv(pv);
387 /* Calculate the SP for the parent Java method. */
389 #if defined(ENABLE_INTRP)
391 sp = *(u1 **) (sp - framesize);
395 #if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
396 sp = (void *) (((intptr_t) sp) + framesize + SIZEOF_VOID_P);
397 #elif defined(__SPARC_64__)
398 /* already has the new sp */
400 sp = (void *) (((intptr_t) sp) + framesize);
404 /* Store the new values in the stackframeinfo. NOTE: We subtract
405 1 from the RA to get the XPC, because the RA points to the
406 instruction after the call instruction. */
412 sfi->xpc = (void *) (((intptr_t) ra) - 1);
416 /* stacktrace_create ***********************************************************
418 Generates a stacktrace from the thread passed into a
419 stacktracebuffer. The stacktracebuffer is allocated on the
422 NOTE: The first element in the stackframe chain must always be a
423 native stackframeinfo (e.g. VMThrowable.fillInStackTrace() is
427 pointer to the stacktracebuffer, or
428 NULL if there is no stacktrace available for the
431 *******************************************************************************/
433 stacktracebuffer *stacktrace_create(stackframeinfo *sfi)
435 stacktracebuffer *stb;
436 stackframeinfo tmpsfi;
438 /* Create a stacktracebuffer in dump memory. */
440 stb = DNEW(stacktracebuffer);
442 stb->capacity = STACKTRACE_CAPACITY_DEFAULT;
446 if (opt_DebugStackTrace) {
447 printf("\n\n---> stacktrace creation start (fillInStackTrace):\n");
452 /* Put the data from the stackframeinfo into a temporary one. */
454 /* XXX This is not correct, but a workaround for threads-dump for
456 /* assert(sfi != NULL); */
460 tmpsfi.method = sfi->method;
464 tmpsfi.xpc = sfi->xpc;
466 /* Iterate till we're done. */
470 /* Print current method information. */
472 if (opt_DebugStackTrace) {
474 log_print("[stacktrace: method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
475 tmpsfi.method, tmpsfi.pv, tmpsfi.sp, tmpsfi.ra,
477 method_print(tmpsfi.method);
483 /* Check for Throwable.fillInStackTrace(). */
485 /* if (tmpsfi.method->name != utf_fillInStackTrace) { */
487 /* Add this method to the stacktrace. */
489 stb = stacktrace_method_add(stb, &tmpsfi);
492 /* Walk the stack (or the stackframeinfo chain) and get the
495 stacktrace_stack_walk(&tmpsfi);
497 /* If the new methodinfo pointer is NULL we reached a
498 asm_vm_call_method function. In this case we get the next
499 values from the previous stackframeinfo in the chain.
500 Otherwise the new values have been calculated before. */
502 if (tmpsfi.method == NULL) {
505 /* If the previous stackframeinfo in the chain is NULL we
506 reached the top of the stacktrace and leave the
512 /* Fill the temporary stackframeinfo with the new
515 tmpsfi.method = sfi->method;
519 tmpsfi.xpc = sfi->xpc;
524 if (opt_DebugStackTrace) {
525 printf("---> stacktrace creation finished.\n\n");
530 /* return the stacktracebuffer */
539 /* stacktrace_fillInStackTrace *************************************************
541 Generate a stacktrace from the current thread for
542 java.lang.VMThrowable.fillInStackTrace.
544 *******************************************************************************/
546 java_handle_bytearray_t *stacktrace_fillInStackTrace(void)
548 stacktracebuffer *stb;
549 java_handle_bytearray_t *ba;
552 CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
554 /* mark start of dump memory area */
556 dumpsize = dump_size();
558 /* create a stacktrace from the current thread */
560 stb = stacktrace_create(STACKFRAMEINFO);
565 /* allocate memory from the GC heap and copy the stacktrace buffer */
566 /* ATTENTION: use a bytearray for this to not confuse the GC */
568 ba_size = sizeof(stacktracebuffer) +
569 sizeof(stacktrace_entry) * stb->used -
570 sizeof(stacktrace_entry) * STACKTRACE_CAPACITY_DEFAULT;
571 ba = builtin_newarray_byte(ba_size);
576 MCOPY(LLNI_array_data(ba), stb, u1, ba_size);
578 /* release dump memory */
580 dump_release(dumpsize);
582 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
587 dump_release(dumpsize);
589 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
596 /* stacktrace_getClassContext **************************************************
598 Creates a Class context array.
601 the array of java.lang.Class objects, or
602 NULL if an exception has been thrown
604 *******************************************************************************/
606 java_handle_objectarray_t *stacktrace_getClassContext(void)
608 stacktracebuffer *stb;
609 stacktrace_entry *ste;
610 java_handle_objectarray_t *oa;
614 CYCLES_STATS_DECLARE_AND_START
616 /* mark start of dump memory area */
618 dumpsize = dump_size();
620 /* create a stacktrace for the current thread */
622 stb = stacktrace_create(STACKFRAMEINFO);
627 /* calculate the size of the Class array */
629 for (i = 0, oalength = 0; i < stb->used; i++)
630 if (stb->entries[i].method != NULL)
633 /* The first entry corresponds to the method whose implementation */
634 /* calls stacktrace_getClassContext. We remove that entry. */
636 ste = &(stb->entries[0]);
640 /* allocate the Class array */
642 oa = builtin_anewarray(oalength, class_java_lang_Class);
646 /* fill the Class array from the stacktracebuffer */
648 for(i = 0; i < oalength; i++, ste++) {
649 if (ste->method == NULL) {
654 LLNI_array_direct(oa, i) = (java_object_t *) ste->method->class;
657 /* release dump memory */
659 dump_release(dumpsize);
661 CYCLES_STATS_END(stacktrace_getClassContext)
666 dump_release(dumpsize);
668 CYCLES_STATS_END(stacktrace_getClassContext)
674 /* stacktrace_getCurrentClass **************************************************
676 Find the current class by walking the stack trace.
678 Quote from the JNI documentation:
680 In the Java 2 Platform, FindClass locates the class loader
681 associated with the current native method. If the native code
682 belongs to a system class, no class loader will be
683 involved. Otherwise, the proper class loader will be invoked to
684 load and link the named class. When FindClass is called through the
685 Invocation Interface, there is no current native method or its
686 associated class loader. In that case, the result of
687 ClassLoader.getBaseClassLoader is used."
689 *******************************************************************************/
691 #if defined(ENABLE_JAVASE)
692 classinfo *stacktrace_getCurrentClass(void)
694 stacktracebuffer *stb;
695 stacktrace_entry *ste;
699 CYCLES_STATS_DECLARE_AND_START
701 /* mark start of dump memory area */
703 dumpsize = dump_size();
705 /* create a stacktrace for the current thread */
707 stb = stacktrace_create(STACKFRAMEINFO);
710 goto return_NULL; /* XXX exception: how to distinguish from normal NULL return? */
712 /* iterate over all stacktrace entries and find the first suitable
715 for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
721 if (m->class == class_java_security_PrivilegedAction)
724 if (m->class != NULL) {
725 dump_release(dumpsize);
727 CYCLES_STATS_END(stacktrace_getCurrentClass)
733 /* no Java method found on the stack */
736 dump_release(dumpsize);
738 CYCLES_STATS_END(stacktrace_getCurrentClass)
742 #endif /* ENABLE_JAVASE */
745 /* stacktrace_getStack *********************************************************
747 Create a 2-dimensional array for java.security.VMAccessControler.
751 NULL if an exception has been thrown
753 *******************************************************************************/
755 #if defined(ENABLE_JAVASE)
756 java_handle_objectarray_t *stacktrace_getStack(void)
758 stacktracebuffer *stb;
759 stacktrace_entry *ste;
760 java_handle_objectarray_t *oa;
761 java_handle_objectarray_t *classes;
762 java_handle_objectarray_t *methodnames;
764 java_handle_t *string;
767 CYCLES_STATS_DECLARE_AND_START
769 /* mark start of dump memory area */
771 dumpsize = dump_size();
773 /* create a stacktrace for the current thread */
775 stb = stacktrace_create(STACKFRAMEINFO);
780 /* get the first stacktrace entry */
782 ste = &(stb->entries[0]);
784 /* allocate all required arrays */
786 oa = builtin_anewarray(2, arrayclass_java_lang_Object);
791 classes = builtin_anewarray(stb->used, class_java_lang_Class);
796 methodnames = builtin_anewarray(stb->used, class_java_lang_String);
798 if (methodnames == NULL)
801 /* set up the 2-dimensional array */
803 array_objectarray_element_set(oa, 0, (java_handle_t *) classes);
804 array_objectarray_element_set(oa, 1, (java_handle_t *) methodnames);
806 /* iterate over all stacktrace entries */
808 for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
809 c = ste->method->class;
811 LLNI_array_direct(classes, i) = (java_object_t *) c;
813 string = javastring_new(ste->method->name);
818 array_objectarray_element_set(methodnames, i, string);
821 /* return the 2-dimensional array */
823 dump_release(dumpsize);
825 CYCLES_STATS_END(stacktrace_getStack)
830 dump_release(dumpsize);
832 CYCLES_STATS_END(stacktrace_getStack)
836 #endif /* ENABLE_JAVASE */
839 /* stacktrace_print_trace_from_buffer ******************************************
841 Print the stacktrace of a given stacktracebuffer with CACAO intern
842 methods (no Java help). This method is used by
843 stacktrace_dump_trace and builtin_trace_exception.
845 *******************************************************************************/
847 void stacktrace_print_trace_from_buffer(stacktracebuffer *stb)
849 stacktrace_entry *ste;
853 ste = &(stb->entries[0]);
855 for (i = 0; i < stb->used; i++, ste++) {
859 utf_display_printable_ascii_classname(m->class->name);
861 utf_display_printable_ascii(m->name);
862 utf_display_printable_ascii(m->descriptor);
864 if (m->flags & ACC_NATIVE) {
865 puts("(Native Method)");
869 utf_display_printable_ascii(m->class->sourcefile);
870 printf(":%d)\n", (u4) ste->linenumber);
874 /* just to be sure */
880 /* stacktrace_print_trace ******************************************************
882 Print the stacktrace of a given exception. More or less a wrapper
883 to stacktrace_print_trace_from_buffer.
885 *******************************************************************************/
887 void stacktrace_print_trace(java_handle_t *xptr)
889 java_lang_Throwable *t;
890 #if defined(WITH_CLASSPATH_GNU)
891 java_lang_VMThrowable *vmt;
893 java_handle_bytearray_t *ba;
894 stacktracebuffer *stb;
896 t = (java_lang_Throwable *) xptr;
901 /* now print the stacktrace */
903 #if defined(WITH_CLASSPATH_GNU)
904 LLNI_field_get_ref(t, vmState, vmt);
905 LLNI_field_get_ref(vmt, vmData, ba);
906 #elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
907 LLNI_field_get_ref(t, backtrace, ba);
909 # error unknown classpath configuration
913 stb = (stacktracebuffer *) LLNI_array_data(ba);
915 stacktrace_print_trace_from_buffer(stb);
919 #if defined(ENABLE_CYCLES_STATS)
920 void stacktrace_print_cycles_stats(FILE *file)
922 CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead,file);
923 CYCLES_STATS_PRINT(stacktrace_fillInStackTrace,file);
924 CYCLES_STATS_PRINT(stacktrace_getClassContext ,file);
925 CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,file);
926 CYCLES_STATS_PRINT(stacktrace_getStack ,file);
932 * These are local overrides for various environment variables in Emacs.
933 * Please do not remove this and leave it at the end of the file, where
934 * Emacs will automagically detect them.
935 * ---------------------------------------------------------------------
938 * indent-tabs-mode: t
942 * vim:noexpandtab:sw=4:ts=4: