1 /* src/vm/jit/stacktrace.c - machine independet stacktrace system
3 Copyright (C) 1996-2005, 2006 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 Contact: cacao@cacaojvm.org
27 Authors: Joseph Wenninger
29 Changes: Christian Thalinger
32 $Id: stacktrace.c 4833 2006-04-25 12:00:58Z edwin $
46 #include "mm/memory.h"
47 #include "native/native.h"
49 #include "vm/global.h" /* required here for native includes */
50 #include "native/include/java_lang_ClassLoader.h"
51 #include "native/include/java_lang_Throwable.h"
52 #include "native/include/java_lang_VMThrowable.h"
54 #if defined(USE_THREADS)
55 # if defined(NATIVE_THREADS)
56 # include "threads/native/threads.h"
58 # include "threads/green/threads.h"
61 # include "threads/none/threads.h"
64 #include "toolbox/logging.h"
65 #include "vm/builtin.h"
67 #include "vm/exceptions.h"
68 #include "vm/loader.h"
69 #include "vm/options.h"
70 #include "vm/stringlocal.h"
72 #include "vm/jit/asmpart.h"
73 #include "vm/jit/codegen-common.h"
74 #include "vm/jit/methodheader.h"
75 #include "vm/cycles-stats.h"
78 /* linenumbertable_entry ******************************************************/
80 /* Keep the type of line the same as the pointer type, otherwise we
81 run into alignment troubles (like on MIPS64). */
83 typedef struct linenumbertable_entry linenumbertable_entry;
85 struct linenumbertable_entry {
86 ptrint line; /* NOTE: see doc/inlining_stacktrace.txt for */
87 u1 *pc; /* special meanings of line and pc. */
90 /* global variables ***********************************************************/
92 #if !defined(USE_THREADS)
93 stackframeinfo *_no_threads_stackframeinfo = NULL;
96 CYCLES_STATS_DECLARE(stacktrace_overhead ,100,1)
97 CYCLES_STATS_DECLARE(stacktrace_fillInStackTrace,40,5000)
98 CYCLES_STATS_DECLARE(stacktrace_getClassContext ,40,5000)
99 CYCLES_STATS_DECLARE(stacktrace_getCurrentClass ,40,5000)
100 CYCLES_STATS_DECLARE(stacktrace_getStack ,40,10000)
103 /* stacktrace_create_stackframeinfo ********************************************
105 Creates an stackframe info structure for inline code in the
108 *******************************************************************************/
110 #if defined(ENABLE_INTRP)
111 void stacktrace_create_stackframeinfo(stackframeinfo *sfi, u1 *pv, u1 *sp,
114 stackframeinfo **psfi;
117 /* get current stackframe info pointer */
119 psfi = STACKFRAMEINFO;
121 /* if we don't have pv handy */
124 #if defined(ENABLE_INTRP)
126 pv = codegen_findmethod(ra);
130 #if defined(ENABLE_JIT)
131 pv = md_codegen_findmethod(ra);
136 /* get methodinfo pointer from data segment */
138 m = *((methodinfo **) (pv + MethodPointer));
140 /* fill new stackframe info structure */
148 /* xpc is the same as ra, but is required in stacktrace_create */
152 /* store new stackframe info pointer */
156 #endif /* defined(ENABLE_INTRP) */
159 /* stacktrace_create_inline_stackframeinfo *************************************
161 Creates an stackframe info structure for an inline exception stub.
163 *******************************************************************************/
165 void stacktrace_create_inline_stackframeinfo(stackframeinfo *sfi, u1 *pv,
166 u1 *sp, u1 *ra, u1 *xpc)
168 stackframeinfo **psfi;
170 /* get current stackframe info pointer */
172 psfi = STACKFRAMEINFO;
174 #if defined(ENABLE_INTRP)
176 /* if we don't have pv handy */
179 pv = codegen_findmethod(ra);
184 /* fill new stackframe info structure */
193 /* store new stackframe info pointer */
199 /* stacktrace_create_extern_stackframeinfo *************************************
201 Creates an stackframe info structure for an extern exception
202 (hardware or assembler).
204 *******************************************************************************/
206 void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv,
207 u1 *sp, u1 *ra, u1 *xpc)
209 stackframeinfo **psfi;
210 #if !defined(__I386__) && !defined(__X86_64__)
213 #if defined(ENABLE_JIT)
217 /* get current stackframe info pointer */
219 psfi = STACKFRAMEINFO;
221 /* sometimes we don't have pv handy (e.g. in asmpart.S:
222 L_asm_call_jit_compiler_exception or in the interpreter). */
225 #if defined(ENABLE_INTRP)
227 pv = codegen_findmethod(ra);
231 #if defined(ENABLE_JIT)
232 pv = md_codegen_findmethod(ra);
237 #if defined(ENABLE_JIT)
238 # if defined(ENABLE_INTRP)
239 /* When using the interpreter, we pass RA to the function. */
243 # if defined(__I386__) || defined(__X86_64__)
244 /* On i386 and x86_64 we always have to get the return address
247 framesize = *((u4 *) (pv + FrameSize));
249 ra = md_stacktrace_get_returnaddress(sp, framesize);
251 /* If the method is a non-leaf function, we need to get the return
252 address from the stack. For leaf functions the return address
253 is set correctly. This makes the assembler and the signal
254 handler code simpler. */
256 isleafmethod = *((s4 *) (pv + IsLeaf));
259 framesize = *((u4 *) (pv + FrameSize));
261 ra = md_stacktrace_get_returnaddress(sp, framesize);
264 # if defined(ENABLE_INTRP)
267 #endif /* defined(ENABLE_JIT) */
269 /* fill new stackframe info structure */
278 /* store new stackframe info pointer */
284 /* stacktrace_create_native_stackframeinfo *************************************
286 Creates a stackframe info structure for a native stub.
288 *******************************************************************************/
290 void stacktrace_create_native_stackframeinfo(stackframeinfo *sfi, u1 *pv,
293 stackframeinfo **psfi;
296 /* get methodinfo pointer from data segment */
298 m = *((methodinfo **) (pv + MethodPointer));
300 /* get current stackframe info pointer */
302 psfi = STACKFRAMEINFO;
304 /* fill new stackframe info structure */
313 /* store new stackframe info pointer */
319 /* stacktrace_remove_stackframeinfo ********************************************
323 *******************************************************************************/
325 void stacktrace_remove_stackframeinfo(stackframeinfo *sfi)
327 stackframeinfo **psfi;
329 /* get current stackframe info pointer */
331 psfi = STACKFRAMEINFO;
333 /* restore the old pointer */
339 /* stacktrace_inline_arithmeticexception ***************************************
341 Creates an ArithemticException for inline stub.
343 *******************************************************************************/
345 java_objectheader *stacktrace_inline_arithmeticexception(u1 *pv, u1 *sp,
349 java_objectheader *o;
351 /* create stackframeinfo */
353 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
355 /* create exception */
357 o = new_arithmeticexception();
359 /* remove stackframeinfo */
361 stacktrace_remove_stackframeinfo(&sfi);
367 /* stacktrace_inline_arrayindexoutofboundsexception ****************************
369 Creates an ArrayIndexOutOfBoundsException for inline stub.
371 *******************************************************************************/
373 java_objectheader *stacktrace_inline_arrayindexoutofboundsexception(u1 *pv,
380 java_objectheader *o;
382 /* create stackframeinfo */
384 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
386 /* create exception */
388 o = new_arrayindexoutofboundsexception(index);
390 /* remove stackframeinfo */
392 stacktrace_remove_stackframeinfo(&sfi);
398 /* stacktrace_inline_arraystoreexception ***************************************
400 Creates an ArrayStoreException for inline stub.
402 *******************************************************************************/
404 java_objectheader *stacktrace_inline_arraystoreexception(u1 *pv, u1 *sp, u1 *ra,
408 java_objectheader *o;
410 /* create stackframeinfo */
412 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
414 /* create exception */
416 o = new_arraystoreexception();
418 /* remove stackframeinfo */
420 stacktrace_remove_stackframeinfo(&sfi);
426 /* stacktrace_inline_classcastexception ****************************************
428 Creates an ClassCastException for inline stub.
430 *******************************************************************************/
432 java_objectheader *stacktrace_inline_classcastexception(u1 *pv, u1 *sp, u1 *ra,
436 java_objectheader *o;
438 /* create stackframeinfo */
440 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
442 /* create exception */
444 o = new_classcastexception();
446 /* remove stackframeinfo */
448 stacktrace_remove_stackframeinfo(&sfi);
454 /* stacktrace_inline_nullpointerexception **************************************
456 Creates an NullPointerException for inline stub.
458 *******************************************************************************/
460 java_objectheader *stacktrace_inline_nullpointerexception(u1 *pv, u1 *sp,
464 java_objectheader *o;
466 /* create stackframeinfo */
468 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
470 /* create exception */
472 o = new_nullpointerexception();
474 /* remove stackframeinfo */
476 stacktrace_remove_stackframeinfo(&sfi);
482 /* stacktrace_inline_fillInStackTrace ******************************************
484 Fills in the correct stacktrace into an existing exception object
485 (this one is for inline exception stubs).
487 *******************************************************************************/
489 java_objectheader *stacktrace_inline_fillInStackTrace(u1 *pv, u1 *sp, u1 *ra,
493 java_objectheader *o;
496 /* create stackframeinfo */
498 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
505 /* clear exception */
507 *exceptionptr = NULL;
509 /* resolve methodinfo pointer from exception object */
511 m = class_resolvemethod(o->vftbl->class,
512 utf_fillInStackTrace,
513 utf_void__java_lang_Throwable);
517 (void) vm_call_method(m, o);
519 /* remove stackframeinfo */
521 stacktrace_remove_stackframeinfo(&sfi);
527 /* stacktrace_hardware_arithmeticexception *************************************
529 Creates an ArithemticException for inline stub.
531 *******************************************************************************/
533 java_objectheader *stacktrace_hardware_arithmeticexception(u1 *pv, u1 *sp,
537 java_objectheader *o;
539 /* create stackframeinfo */
541 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
543 /* create exception */
545 o = new_arithmeticexception();
547 /* remove stackframeinfo */
549 stacktrace_remove_stackframeinfo(&sfi);
555 /* stacktrace_hardware_nullpointerexception ************************************
557 Creates an NullPointerException for the SIGSEGV signal handler.
559 *******************************************************************************/
561 java_objectheader *stacktrace_hardware_nullpointerexception(u1 *pv, u1 *sp,
565 java_objectheader *o;
567 /* create stackframeinfo */
569 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
571 /* create exception */
573 o = new_nullpointerexception();
575 /* remove stackframeinfo */
577 stacktrace_remove_stackframeinfo(&sfi);
583 /* stacktrace_add_entry ********************************************************
585 Adds a new entry to the stacktrace buffer.
587 *******************************************************************************/
589 static void stacktrace_add_entry(stacktracebuffer *stb, methodinfo *m, u2 line)
591 stacktrace_entry *ste;
593 /* check if we already reached the buffer capacity */
595 if (stb->used >= stb->capacity) {
596 /* reallocate new memory */
598 stb->entries = DMREALLOC(stb->entries, stacktrace_entry, stb->capacity,
599 stb->capacity + STACKTRACE_CAPACITY_INCREMENT);
601 /* set new buffer capacity */
603 stb->capacity = stb->capacity + STACKTRACE_CAPACITY_INCREMENT;
606 /* insert the current entry */
608 ste = &(stb->entries[stb->used]);
611 ste->linenumber = line;
613 /* increase entries used count */
619 /* stacktrace_add_method_intern ************************************************
621 This function is used by stacktrace_add_method to search the line number
622 table for the line corresponding to a given pc. The function recurses for
625 *******************************************************************************/
627 static bool stacktrace_add_method_intern(stacktracebuffer *stb,
629 linenumbertable_entry *lntentry,
633 linenumbertable_entry *lntinline; /* special entry for inlined method */
638 /* Find the line number for the specified PC (going backwards
639 in the linenumber table). The linenumber table size is zero
642 for (; lntsize > 0; lntsize--, lntentry--) {
644 /* did we reach the current line? */
646 /* Note: In case of inlining this may actually compare the pc
647 against a methodinfo *, yielding a non-sensical
648 result. This is no problem, however, as we ignore such
649 entries in the switch below. This way we optimize for the
650 common case (ie. a real pc in lntentry->pc). */
652 if (pc >= lntentry->pc) {
654 /* check for special inline entries (see
655 doc/inlining_stacktrace.txt for details */
657 if ((s4)lntentry->line < 0) {
658 switch (lntentry->line) {
660 /* begin of inlined method (ie. INLINE_END
663 lntinline = --lntentry;/* get entry with methodinfo * */
664 lntentry--; /* skip the special entry */
667 /* search inside the inlined method */
668 if (stacktrace_add_method_intern(
670 (methodinfo*) lntinline->pc,
675 /* the inlined method contained the pc */
676 assert(lntinline->line <= -3);
677 stacktrace_add_entry(stb, m, (-3) - lntinline->line);
680 /* pc was not in inlined method, continue
681 search. Entries inside the inlined method
682 will be skipped because their lntentry->pc
683 is higher than pc. */
687 /* end of inlined method */
690 /* default: is only reached for an -3-line entry
691 after a skipped -2 entry. We can safely ignore
692 it and continue searching. */
696 /* found a normal entry */
697 stacktrace_add_entry(stb, m, lntentry->line);
707 /* stacktrace_add_method *******************************************************
709 Add stacktrace entries[1] for the given method to the stacktrace buffer.
712 stb.........stacktracebuffer to fill
713 m...........method for which entries should be created
714 pv..........pv of method
715 pc..........position of program counter within the method's code
718 true, if stacktrace entries were successfully created, false otherwise.
720 [1] In case of inlined methods there may be more than one stacktrace
721 entry for a codegen-level method. (see doc/inlining_stacktrace.txt)
723 *******************************************************************************/
725 static bool stacktrace_add_method(stacktracebuffer *stb, methodinfo *m, u1 *pv,
728 ptrint lntsize; /* size of line number table */
729 u1 *lntstart; /* start of line number table */
730 linenumbertable_entry *lntentry; /* points to last entry in the table */
731 codeinfo *code; /* compiled realization of method */
733 /* get size of line number table */
735 lntsize = *((ptrint *) (pv + LineNumberTableSize));
736 lntstart = *((u1 **) (pv + LineNumberTableStart));
738 /* Subtract the size of the line number entry of the structure,
739 since the line number table start points to the pc. */
741 lntentry = (linenumbertable_entry *) (lntstart - SIZEOF_VOID_P);
743 /* find the realization of the method the pc is in */
744 /* XXX Note: This is preliminary. It would be cleaner */
745 /* to get the codeinfo * from the PV */
752 dolog("Could not find codeinfo for Current PC: %p",(void*)pc);
757 if (((ptrint)pc >= (ptrint)code->entrypoint)
759 ( (pc - (u1*)code->entrypoint) < code->mcodelength ))
768 /* search the line number table */
770 if (stacktrace_add_method_intern(stb, m, lntentry, lntsize, pc))
773 /* If we get here, just add the entry with line number 0. */
775 stacktrace_add_entry(stb, m, 0);
781 /* stacktrace_create ***********************************************************
783 Generates a stacktrace from the thread passed into a
784 stacktracebuffer. The stacktracebuffer is allocated on the GC
788 pointer to the stacktracebuffer, or
789 NULL if an exception has been thrown
791 *******************************************************************************/
793 stacktracebuffer *stacktrace_create(threadobject* thread)
795 stacktracebuffer *stb;
804 /* prevent compiler warnings */
810 /* create a stacktracebuffer in dump memory */
812 stb = DNEW(stacktracebuffer);
814 stb->capacity = STACKTRACE_CAPACITY_DEFAULT;
816 stb->entries = DMNEW(stacktrace_entry, STACKTRACE_CAPACITY_DEFAULT);
818 /* The first element in the stackframe chain must always be a
819 native stackframeinfo (VMThrowable.fillInStackTrace is a native
822 #if defined(USE_THREADS)
823 sfi = thread->info._stackframeinfo;
825 sfi = _no_threads_stackframeinfo;
828 #define PRINTMETHODS 0
831 printf("\n\nfillInStackTrace start:\n");
835 /* Loop while we have a method pointer (asm_calljavafunction has
836 NULL) or there is a stackframeinfo in the chain. */
841 /* m == NULL should only happen for the first time and inline
842 stackframe infos, like from the exception stubs or the
846 /* for native stub stackframe infos, pv is always NULL */
848 if (sfi->pv == NULL) {
849 /* get methodinfo, sp and ra from the current stackframe info */
852 sp = sfi->sp; /* sp of parent Java function */
856 stacktrace_add_entry(stb, m, 0);
859 printf("ra=%p sp=%p, ", ra, sp);
861 printf(": native stub\n");
864 /* This is an native stub stackframe info, so we can
865 get the parent pv from the return address
868 #if defined(ENABLE_INTRP)
870 pv = codegen_findmethod(ra);
874 #if defined(ENABLE_JIT)
875 pv = md_codegen_findmethod(ra);
879 /* get methodinfo pointer from parent data segment */
881 m = *((methodinfo **) (pv + MethodPointer));
884 /* Inline stackframe infos are special: they have a
885 xpc of the actual exception position and the return
886 address saved since an inline stackframe info can
887 also be in a leaf method (no return address saved
888 on stack!!!). ATTENTION: This one is also for
889 hardware exceptions!!! */
891 /* get methodinfo, sp and ra from the current stackframe info */
893 m = sfi->method; /* m == NULL */
894 pv = sfi->pv; /* pv of parent Java function */
895 sp = sfi->sp; /* sp of parent Java function */
896 ra = sfi->ra; /* ra of parent Java function */
897 xpc = sfi->xpc; /* actual exception position */
900 printf("ra=%p sp=%p, ", ra, sp);
901 printf("NULL: inline stub\n");
905 /* get methodinfo from current Java method */
907 m = *((methodinfo **) (pv + MethodPointer));
909 /* if m == NULL, this is a asm_calljavafunction call */
913 printf("ra=%p sp=%p, ", ra, sp);
915 printf(": inline stub parent");
919 #if defined(ENABLE_INTRP)
923 /* add the method to the stacktrace */
925 stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) xpc));
927 /* get the current stack frame size */
929 framesize = *((u4 *) (pv + FrameSize));
932 printf(", framesize=%d\n", framesize);
936 /* set stack pointer to stackframe of parent Java */
937 /* function of the current Java function */
939 #if defined(__I386__) || defined (__X86_64__)
940 sp += framesize + SIZEOF_VOID_P;
945 /* get data segment and methodinfo pointer from parent */
948 #if defined(ENABLE_JIT)
949 pv = md_codegen_findmethod(ra);
952 m = *((methodinfo **) (pv + MethodPointer));
954 #if defined(ENABLE_INTRP)
960 printf("ra=%p sp=%p, ", ra, sp);
961 printf("asm_calljavafunction\n");
967 /* get previous stackframeinfo in the chain */
973 printf("ra=%p sp=%p, ", ra, sp);
979 /* JIT method found, add it to the stacktrace (we subtract
980 1 from the return address since it points the the
981 instruction after call). */
983 stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) ra) - 1);
985 /* get the current stack frame size */
987 framesize = *((u4 *) (pv + FrameSize));
990 printf(", framesize=%d\n", framesize);
994 /* get return address of current stack frame */
996 #if defined(ENABLE_JIT)
997 # if defined(ENABLE_INTRP)
999 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
1002 ra = md_stacktrace_get_returnaddress(sp, framesize);
1004 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
1007 /* get data segment and methodinfo pointer from parent method */
1009 #if defined(ENABLE_INTRP)
1011 pv = codegen_findmethod(ra);
1015 #if defined(ENABLE_JIT)
1016 pv = md_codegen_findmethod(ra);
1020 m = *((methodinfo **) (pv + MethodPointer));
1022 /* walk the stack */
1024 #if defined(ENABLE_INTRP)
1026 sp = *(u1 **) (sp - framesize);
1030 #if defined(__I386__) || defined (__X86_64__)
1031 sp += framesize + SIZEOF_VOID_P;
1039 /* return the stacktracebuffer */
1045 /* stacktrace_fillInStackTrace *************************************************
1047 Generate a stacktrace from the current thread for
1048 java.lang.VMThrowable.fillInStackTrace.
1050 *******************************************************************************/
1052 stacktracebuffer *stacktrace_fillInStackTrace(void)
1054 stacktracebuffer *stb;
1055 stacktracebuffer *gcstb;
1057 CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
1059 /* mark start of dump memory area */
1061 dumpsize = dump_size();
1063 /* create a stacktrace from the current thread */
1065 stb = stacktrace_create(THREADOBJECT);
1069 /* allocate memory from the GC heap and copy the stacktrace buffer */
1071 gcstb = GCNEW(stacktracebuffer);
1076 gcstb->capacity = stb->capacity;
1077 gcstb->used = stb->used;
1078 gcstb->entries = GCMNEW(stacktrace_entry, stb->used);
1080 if (gcstb->entries == NULL)
1083 MCOPY(gcstb->entries, stb->entries, stacktrace_entry, stb->used);
1085 /* release dump memory */
1087 dump_release(dumpsize);
1089 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
1090 stacktrace_overhead)
1094 dump_release(dumpsize);
1096 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
1097 stacktrace_overhead)
1103 /* stacktrace_getClassContext **************************************************
1105 Creates a Class context array.
1108 the array of java.lang.Class objects, or
1109 NULL if an exception has been thrown
1111 *******************************************************************************/
1113 java_objectarray *stacktrace_getClassContext(void)
1115 stacktracebuffer *stb;
1116 stacktrace_entry *ste;
1117 java_objectarray *oa;
1121 CYCLES_STATS_DECLARE_AND_START
1123 /* mark start of dump memory area */
1125 dumpsize = dump_size();
1127 /* create a stacktrace for the current thread */
1129 stb = stacktrace_create(THREADOBJECT);
1133 /* calculate the size of the Class array */
1135 for (i = 0, oalength = 0; i < stb->used; i++)
1136 if (stb->entries[i].method != NULL)
1139 ste = &(stb->entries[0]);
1143 /* XXX document me */
1147 (ste->method->class == class_java_lang_SecurityManager)) {
1153 /* allocate the Class array */
1155 oa = builtin_anewarray(oalength, class_java_lang_Class);
1159 /* fill the Class array from the stacktracebuffer */
1161 for(i = 0; i < oalength; i++, ste++) {
1162 if (ste->method == NULL) {
1167 oa->data[i] = (java_objectheader *) ste->method->class;
1170 /* release dump memory */
1172 dump_release(dumpsize);
1174 CYCLES_STATS_END(stacktrace_getClassContext)
1179 dump_release(dumpsize);
1181 CYCLES_STATS_END(stacktrace_getClassContext)
1187 /* stacktrace_getCurrentClass **************************************************
1189 Find the current class by walking the stack trace.
1191 Quote from the JNI documentation:
1193 In the Java 2 Platform, FindClass locates the class loader
1194 associated with the current native method. If the native code
1195 belongs to a system class, no class loader will be
1196 involved. Otherwise, the proper class loader will be invoked to
1197 load and link the named class. When FindClass is called through the
1198 Invocation Interface, there is no current native method or its
1199 associated class loader. In that case, the result of
1200 ClassLoader.getBaseClassLoader is used."
1202 *******************************************************************************/
1204 classinfo *stacktrace_getCurrentClass(void)
1206 stacktracebuffer *stb;
1207 stacktrace_entry *ste;
1211 CYCLES_STATS_DECLARE_AND_START
1213 /* mark start of dump memory area */
1215 dumpsize = dump_size();
1217 /* create a stacktrace for the current thread */
1219 stb = stacktrace_create(THREADOBJECT);
1221 goto return_NULL; /* XXX exception: how to distinguish from normal NULL return? */
1223 /* iterate over all stacktrace entries and find the first suitable
1226 for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
1232 if (m->class == class_java_security_PrivilegedAction)
1235 if (m->class != NULL) {
1236 dump_release(dumpsize);
1238 CYCLES_STATS_END(stacktrace_getCurrentClass)
1244 /* no Java method found on the stack */
1247 dump_release(dumpsize);
1249 CYCLES_STATS_END(stacktrace_getCurrentClass)
1255 /* stacktrace_getStack *********************************************************
1257 Create a 2-dimensional array for java.security.VMAccessControler.
1261 NULL if an exception has been thrown
1263 *******************************************************************************/
1265 java_objectarray *stacktrace_getStack(void)
1267 stacktracebuffer *stb;
1268 stacktrace_entry *ste;
1269 java_objectarray *oa;
1270 java_objectarray *classes;
1271 java_objectarray *methodnames;
1273 java_lang_String *str;
1276 CYCLES_STATS_DECLARE_AND_START
1278 /* mark start of dump memory area */
1280 dumpsize = dump_size();
1282 /* create a stacktrace for the current thread */
1284 stb = stacktrace_create(THREADOBJECT);
1288 /* get the first stacktrace entry */
1290 ste = &(stb->entries[0]);
1292 /* allocate all required arrays */
1294 oa = builtin_anewarray(2, arrayclass_java_lang_Object);
1299 classes = builtin_anewarray(stb->used, class_java_lang_Class);
1304 methodnames = builtin_anewarray(stb->used, class_java_lang_String);
1309 /* set up the 2-dimensional array */
1311 oa->data[0] = (java_objectheader *) classes;
1312 oa->data[1] = (java_objectheader *) methodnames;
1314 /* iterate over all stacktrace entries */
1316 for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
1317 c = ste->method->class;
1319 classes->data[i] = (java_objectheader *) c;
1320 str = javastring_new(ste->method->name);
1325 methodnames->data[i] = (java_objectheader *) str;
1328 /* return the 2-dimensional array */
1330 dump_release(dumpsize);
1332 CYCLES_STATS_END(stacktrace_getStack)
1337 dump_release(dumpsize);
1339 CYCLES_STATS_END(stacktrace_getStack)
1345 /* stacktrace_print_trace_from_buffer ******************************************
1347 Print the stacktrace of a given stacktracebuffer with CACAO intern
1348 methods (no Java help). This method is used by
1349 stacktrace_dump_trace and builtin_trace_exception.
1351 *******************************************************************************/
1353 static void stacktrace_print_trace_from_buffer(stacktracebuffer *stb)
1355 stacktrace_entry *ste;
1359 ste = &(stb->entries[0]);
1361 for (i = 0; i < stb->used; i++, ste++) {
1365 utf_display_classname(m->class->name);
1367 utf_display(m->name);
1368 utf_display(m->descriptor);
1370 if (m->flags & ACC_NATIVE) {
1371 puts("(Native Method)");
1375 utf_display(m->class->sourcefile);
1376 printf(":%d)\n", (u4) ste->linenumber);
1380 /* just to be sure */
1386 /* stacktrace_dump_trace *******************************************************
1388 This method is call from signal_handler_sigusr1 to dump the
1389 stacktrace of the current thread to stdout.
1391 *******************************************************************************/
1393 void stacktrace_dump_trace(void)
1395 stacktracebuffer *stb;
1399 /* get methodinfo pointer from data segment */
1401 m = *((methodinfo **) (pv + MethodPointer));
1403 /* get current stackframe info pointer */
1405 psfi = STACKFRAMEINFO;
1407 /* fill new stackframe info structure */
1415 /* store new stackframe info pointer */
1420 /* mark start of dump memory area */
1422 dumpsize = dump_size();
1424 /* create a stacktrace for the current thread */
1426 stb = stacktrace_create(THREADOBJECT);
1428 /* print stacktrace */
1431 stacktrace_print_trace_from_buffer(stb);
1434 puts("\t<<No stacktrace available>>");
1438 dump_release(dumpsize);
1442 /* stacktrace_print_trace ******************************************************
1444 Print the stacktrace of a given exception. More or less a wrapper
1445 to stacktrace_print_trace_from_buffer.
1447 *******************************************************************************/
1449 void stacktrace_print_trace(java_objectheader *xptr)
1451 java_lang_Throwable *t;
1452 java_lang_VMThrowable *vmt;
1453 stacktracebuffer *stb;
1455 t = (java_lang_Throwable *) xptr;
1460 /* now print the stacktrace */
1463 stb = (stacktracebuffer *) vmt->vmData;
1465 stacktrace_print_trace_from_buffer(stb);
1469 #if defined(ENABLE_CYCLES_STATS)
1470 void stacktrace_print_cycles_stats(FILE *file)
1472 CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead,file);
1473 CYCLES_STATS_PRINT(stacktrace_fillInStackTrace,file);
1474 CYCLES_STATS_PRINT(stacktrace_getClassContext ,file);
1475 CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,file);
1476 CYCLES_STATS_PRINT(stacktrace_getStack ,file);
1482 * These are local overrides for various environment variables in Emacs.
1483 * Please do not remove this and leave it at the end of the file, where
1484 * Emacs will automagically detect them.
1485 * ---------------------------------------------------------------------
1488 * indent-tabs-mode: t
1492 * vim:noexpandtab:sw=4:ts=4: