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 5900 2006-11-04 17:30:44Z michi $
45 #include "mm/gc-common.h"
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(ENABLE_THREADS)
55 # include "threads/native/threads.h"
57 # include "threads/none/threads.h"
60 #include "toolbox/logging.h"
61 #include "vm/builtin.h"
63 #include "vm/exceptions.h"
64 #include "vm/loader.h"
65 #include "vm/options.h"
66 #include "vm/stringlocal.h"
68 #include "vm/jit/asmpart.h"
69 #include "vm/jit/codegen-common.h"
70 #include "vm/jit/methodheader.h"
71 #include "vm/cycles-stats.h"
74 /* linenumbertable_entry ******************************************************/
76 /* Keep the type of line the same as the pointer type, otherwise we
77 run into alignment troubles (like on MIPS64). */
79 typedef struct linenumbertable_entry linenumbertable_entry;
81 struct linenumbertable_entry {
82 ptrint line; /* NOTE: see doc/inlining_stacktrace.txt for */
83 u1 *pc; /* special meanings of line and pc. */
86 /* global variables ***********************************************************/
88 #if !defined(ENABLE_THREADS)
89 stackframeinfo *_no_threads_stackframeinfo = NULL;
92 CYCLES_STATS_DECLARE(stacktrace_overhead ,100,1)
93 CYCLES_STATS_DECLARE(stacktrace_fillInStackTrace,40,5000)
94 CYCLES_STATS_DECLARE(stacktrace_getClassContext ,40,5000)
95 CYCLES_STATS_DECLARE(stacktrace_getCurrentClass ,40,5000)
96 CYCLES_STATS_DECLARE(stacktrace_getStack ,40,10000)
99 /* stacktrace_create_stackframeinfo ********************************************
101 Creates an stackframe info structure for inline code in the
104 *******************************************************************************/
106 #if defined(ENABLE_INTRP)
107 void stacktrace_create_stackframeinfo(stackframeinfo *sfi, u1 *pv, u1 *sp,
110 stackframeinfo **psfi;
114 /* get current stackframe info pointer */
116 psfi = STACKFRAMEINFO;
118 /* if we don't have pv handy */
121 #if defined(ENABLE_INTRP)
123 pv = codegen_get_pv_from_pc(ra);
127 #if defined(ENABLE_JIT)
128 pv = md_codegen_get_pv_from_pc(ra);
133 /* get codeinfo pointer from data segment */
135 code = *((codeinfo **) (pv + CodeinfoPointer));
137 /* For asm_vm_call_method the codeinfo pointer is NULL. */
139 m = (code == NULL) ? NULL : code->m;
141 /* fill new stackframe info structure */
149 /* xpc is the same as ra, but is required in stacktrace_create */
153 /* store new stackframe info pointer */
157 #endif /* defined(ENABLE_INTRP) */
160 /* stacktrace_create_inline_stackframeinfo *************************************
162 Creates an stackframe info structure for an inline exception stub.
164 *******************************************************************************/
166 void stacktrace_create_inline_stackframeinfo(stackframeinfo *sfi, u1 *pv,
167 u1 *sp, u1 *ra, u1 *xpc)
169 stackframeinfo **psfi;
171 /* get current stackframe info pointer */
173 psfi = STACKFRAMEINFO;
175 #if defined(ENABLE_INTRP)
177 /* if we don't have pv handy */
180 pv = codegen_get_pv_from_pc(ra);
185 /* fill new stackframe info structure */
194 /* store new stackframe info pointer */
200 /* stacktrace_create_extern_stackframeinfo *************************************
202 Creates an stackframe info structure for an extern exception
203 (hardware or assembler).
205 *******************************************************************************/
207 void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv,
208 u1 *sp, u1 *ra, u1 *xpc)
210 stackframeinfo **psfi;
211 #if !defined(__I386__) && !defined(__X86_64__)
214 #if defined(ENABLE_JIT)
218 /* get current stackframe info pointer */
220 psfi = STACKFRAMEINFO;
222 /* sometimes we don't have pv handy (e.g. in asmpart.S:
223 L_asm_call_jit_compiler_exception or in the interpreter). */
226 #if defined(ENABLE_INTRP)
228 pv = codegen_get_pv_from_pc(ra);
232 #if defined(ENABLE_JIT)
233 pv = md_codegen_get_pv_from_pc(ra);
238 #if defined(ENABLE_JIT)
239 # if defined(ENABLE_INTRP)
240 /* When using the interpreter, we pass RA to the function. */
244 # if defined(__I386__) || defined(__X86_64__)
245 /* On i386 and x86_64 we always have to get the return address
248 framesize = *((u4 *) (pv + FrameSize));
250 ra = md_stacktrace_get_returnaddress(sp, framesize);
252 /* If the method is a non-leaf function, we need to get the return
253 address from the stack. For leaf functions the return address
254 is set correctly. This makes the assembler and the signal
255 handler code simpler. */
257 isleafmethod = *((s4 *) (pv + IsLeaf));
260 framesize = *((u4 *) (pv + FrameSize));
262 ra = md_stacktrace_get_returnaddress(sp, framesize);
265 # if defined(ENABLE_INTRP)
268 #endif /* defined(ENABLE_JIT) */
270 /* fill new stackframe info structure */
279 /* store new stackframe info pointer */
285 /* stacktrace_create_native_stackframeinfo *************************************
287 Creates a stackframe info structure for a native stub.
289 *******************************************************************************/
291 void stacktrace_create_native_stackframeinfo(stackframeinfo *sfi, u1 *pv,
294 stackframeinfo **psfi;
298 /* get codeinfo pointer from data segment */
300 code = *((codeinfo **) (pv + CodeinfoPointer));
302 /* For asm_vm_call_method the codeinfo pointer is NULL. */
304 m = (code == NULL) ? NULL : code->m;
306 /* get current stackframe info pointer */
308 psfi = STACKFRAMEINFO;
310 /* fill new stackframe info structure */
319 /* store new stackframe info pointer */
325 /* stacktrace_remove_stackframeinfo ********************************************
327 Remove the topmost stackframeinfo in the current thread.
329 *******************************************************************************/
331 void stacktrace_remove_stackframeinfo(stackframeinfo *sfi)
333 stackframeinfo **psfi;
335 /* get current stackframe info pointer */
337 psfi = STACKFRAMEINFO;
339 /* restore the old pointer */
345 /* stacktrace_inline_arithmeticexception ***************************************
347 Creates an ArithemticException for inline stub.
349 *******************************************************************************/
351 java_objectheader *stacktrace_inline_arithmeticexception(u1 *pv, u1 *sp,
355 java_objectheader *o;
357 /* create stackframeinfo */
359 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
361 /* create exception */
363 o = new_arithmeticexception();
365 /* remove stackframeinfo */
367 stacktrace_remove_stackframeinfo(&sfi);
373 /* stacktrace_inline_arrayindexoutofboundsexception ****************************
375 Creates an ArrayIndexOutOfBoundsException for inline stub.
377 *******************************************************************************/
379 java_objectheader *stacktrace_inline_arrayindexoutofboundsexception(u1 *pv,
386 java_objectheader *o;
388 /* create stackframeinfo */
390 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
392 /* create exception */
394 o = new_arrayindexoutofboundsexception(index);
396 /* remove stackframeinfo */
398 stacktrace_remove_stackframeinfo(&sfi);
404 /* stacktrace_inline_arraystoreexception ***************************************
406 Creates an ArrayStoreException for inline stub.
408 *******************************************************************************/
410 java_objectheader *stacktrace_inline_arraystoreexception(u1 *pv, u1 *sp, u1 *ra,
414 java_objectheader *o;
416 /* create stackframeinfo */
418 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
420 /* create exception */
422 o = exceptions_new_arraystoreexception();
424 /* remove stackframeinfo */
426 stacktrace_remove_stackframeinfo(&sfi);
432 /* stacktrace_inline_classcastexception ****************************************
434 Creates an ClassCastException for inline stub.
436 *******************************************************************************/
438 java_objectheader *stacktrace_inline_classcastexception(u1 *pv, u1 *sp, u1 *ra,
440 java_objectheader *o)
443 java_objectheader *e;
445 /* create stackframeinfo */
447 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
449 /* create exception */
451 e = exceptions_new_classcastexception(o);
453 /* remove stackframeinfo */
455 stacktrace_remove_stackframeinfo(&sfi);
461 /* stacktrace_inline_nullpointerexception **************************************
463 Creates an NullPointerException for inline stub.
465 *******************************************************************************/
467 java_objectheader *stacktrace_inline_nullpointerexception(u1 *pv, u1 *sp,
471 java_objectheader *o;
473 /* create stackframeinfo */
475 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
477 /* create exception */
479 o = new_nullpointerexception();
481 /* remove stackframeinfo */
483 stacktrace_remove_stackframeinfo(&sfi);
489 /* stacktrace_inline_fillInStackTrace ******************************************
491 Fills in the correct stacktrace into an existing exception object
492 (this one is for inline exception stubs).
494 *******************************************************************************/
496 java_objectheader *stacktrace_inline_fillInStackTrace(u1 *pv, u1 *sp, u1 *ra,
500 java_objectheader *o;
503 /* create stackframeinfo */
505 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
512 /* clear exception */
514 *exceptionptr = NULL;
516 /* resolve methodinfo pointer from exception object */
518 m = class_resolvemethod(o->vftbl->class,
519 utf_fillInStackTrace,
520 utf_void__java_lang_Throwable);
524 (void) vm_call_method(m, o);
526 /* remove stackframeinfo */
528 stacktrace_remove_stackframeinfo(&sfi);
534 /* stacktrace_hardware_arithmeticexception *************************************
536 Creates an ArithemticException for inline stub.
538 *******************************************************************************/
540 java_objectheader *stacktrace_hardware_arithmeticexception(u1 *pv, u1 *sp,
544 java_objectheader *o;
546 /* create stackframeinfo */
548 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
550 /* create exception */
552 o = new_arithmeticexception();
554 /* remove stackframeinfo */
556 stacktrace_remove_stackframeinfo(&sfi);
562 /* stacktrace_hardware_nullpointerexception ************************************
564 Creates an NullPointerException for the SIGSEGV signal handler.
566 *******************************************************************************/
568 java_objectheader *stacktrace_hardware_nullpointerexception(u1 *pv, u1 *sp,
572 java_objectheader *o;
574 /* create stackframeinfo */
576 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
578 /* create exception */
580 o = new_nullpointerexception();
582 /* remove stackframeinfo */
584 stacktrace_remove_stackframeinfo(&sfi);
590 /* stacktrace_add_entry ********************************************************
592 Adds a new entry to the stacktrace buffer.
594 *******************************************************************************/
596 static void stacktrace_add_entry(stacktracebuffer *stb, methodinfo *m, u2 line)
598 stacktrace_entry *ste;
600 /* check if we already reached the buffer capacity */
602 if (stb->used >= stb->capacity) {
603 /* reallocate new memory */
605 stb->entries = DMREALLOC(stb->entries, stacktrace_entry, stb->capacity,
606 stb->capacity + STACKTRACE_CAPACITY_INCREMENT);
608 /* set new buffer capacity */
610 stb->capacity = stb->capacity + STACKTRACE_CAPACITY_INCREMENT;
613 /* insert the current entry */
615 ste = &(stb->entries[stb->used]);
618 ste->linenumber = line;
620 /* increase entries used count */
626 /* stacktrace_add_method_intern ************************************************
628 This function is used by stacktrace_add_method to search the line number
629 table for the line corresponding to a given pc. The function recurses for
632 *******************************************************************************/
634 static bool stacktrace_add_method_intern(stacktracebuffer *stb,
636 linenumbertable_entry *lntentry,
640 linenumbertable_entry *lntinline; /* special entry for inlined method */
645 /* Find the line number for the specified PC (going backwards
646 in the linenumber table). The linenumber table size is zero
649 for (; lntsize > 0; lntsize--, lntentry--) {
651 /* did we reach the current line? */
653 /* Note: In case of inlining this may actually compare the pc
654 against a methodinfo *, yielding a non-sensical
655 result. This is no problem, however, as we ignore such
656 entries in the switch below. This way we optimize for the
657 common case (ie. a real pc in lntentry->pc). */
659 if (pc >= lntentry->pc) {
661 /* check for special inline entries (see
662 doc/inlining_stacktrace.txt for details */
664 if ((s4)lntentry->line < 0) {
665 switch (lntentry->line) {
667 /* begin of inlined method (ie. INLINE_END
670 lntinline = --lntentry;/* get entry with methodinfo * */
671 lntentry--; /* skip the special entry */
674 /* search inside the inlined method */
675 if (stacktrace_add_method_intern(
677 (methodinfo*) lntinline->pc,
682 /* the inlined method contained the pc */
683 assert(lntinline->line <= -3);
684 stacktrace_add_entry(stb, m, (-3) - lntinline->line);
687 /* pc was not in inlined method, continue
688 search. Entries inside the inlined method
689 will be skipped because their lntentry->pc
690 is higher than pc. */
694 /* end of inlined method */
697 /* default: is only reached for an -3-line entry
698 after a skipped -2 entry. We can safely ignore
699 it and continue searching. */
703 /* found a normal entry */
704 stacktrace_add_entry(stb, m, lntentry->line);
714 /* stacktrace_add_method *******************************************************
716 Add stacktrace entries[1] for the given method to the stacktrace buffer.
719 stb.........stacktracebuffer to fill
720 m...........method for which entries should be created
721 pv..........pv of method
722 pc..........position of program counter within the method's code
725 true, if stacktrace entries were successfully created, false otherwise.
727 [1] In case of inlined methods there may be more than one stacktrace
728 entry for a codegen-level method. (see doc/inlining_stacktrace.txt)
730 *******************************************************************************/
732 static bool stacktrace_add_method(stacktracebuffer *stb, methodinfo *m, u1 *pv,
735 ptrint lntsize; /* size of line number table */
736 u1 *lntstart; /* start of line number table */
737 linenumbertable_entry *lntentry; /* points to last entry in the table */
738 codeinfo *code; /* compiled realization of method */
740 /* get size of line number table */
742 lntsize = *((ptrint *) (pv + LineNumberTableSize));
743 lntstart = *((u1 **) (pv + LineNumberTableStart));
745 /* Subtract the size of the line number entry of the structure,
746 since the line number table start points to the pc. */
748 lntentry = (linenumbertable_entry *) (lntstart - SIZEOF_VOID_P);
750 /* find the realization of the method the pc is in */
753 code = *((codeinfo **) (pv + CodeinfoPointer));
757 /* XXX Note: This is preliminary. It would be cleaner */
758 /* to get the codeinfo * from the PV */
765 dolog("Could not find codeinfo for Current PC: %p",(void*)pc);
770 if (((ptrint)pc >= (ptrint)code->entrypoint)
772 ( (pc - (u1*)code->entrypoint) < code->mcodelength ))
782 /* search the line number table */
784 if (stacktrace_add_method_intern(stb, m, lntentry, lntsize, pc))
787 /* If we get here, just add the entry with line number 0. */
789 stacktrace_add_entry(stb, m, 0);
795 /* stacktrace_create ***********************************************************
797 Generates a stacktrace from the thread passed into a
798 stacktracebuffer. The stacktracebuffer is allocated on the GC
802 pointer to the stacktracebuffer, or
803 NULL if an exception has been thrown
805 *******************************************************************************/
807 stacktracebuffer *stacktrace_create(threadobject* thread)
809 stacktracebuffer *stb;
819 /* prevent compiler warnings */
825 /* create a stacktracebuffer in dump memory */
827 stb = DNEW(stacktracebuffer);
829 stb->capacity = STACKTRACE_CAPACITY_DEFAULT;
831 stb->entries = DMNEW(stacktrace_entry, STACKTRACE_CAPACITY_DEFAULT);
833 /* The first element in the stackframe chain must always be a
834 native stackframeinfo (VMThrowable.fillInStackTrace is a native
837 /* We don't use the STACKFRAMEINFO macro here, as we have to use
838 the passed thread. */
840 #if defined(ENABLE_THREADS)
841 sfi = thread->_stackframeinfo;
843 sfi = _no_threads_stackframeinfo;
846 #define PRINTMETHODS 0
849 printf("\n\nfillInStackTrace start:\n");
853 /* Loop while we have a method pointer (asm_calljavafunction has
854 NULL) or there is a stackframeinfo in the chain. */
858 while ((m != NULL) || (sfi != NULL)) {
859 /* m == NULL should only happen for the first time and inline
860 stackframe infos, like from the exception stubs or the
864 /* for native stub stackframe infos, pv is always NULL */
866 if (sfi->pv == NULL) {
867 /* get methodinfo, sp and ra from the current stackframe info */
870 sp = sfi->sp; /* sp of parent Java function */
874 stacktrace_add_entry(stb, m, 0);
877 printf("ra=%p sp=%p, ", ra, sp);
879 printf(": native stub\n");
882 /* This is an native stub stackframe info, so we can
883 get the parent pv from the return address
886 #if defined(ENABLE_INTRP)
888 pv = codegen_get_pv_from_pc(ra);
892 #if defined(ENABLE_JIT)
893 pv = md_codegen_get_pv_from_pc(ra);
897 /* get methodinfo pointer from parent data segment */
899 code = *((codeinfo **) (pv + CodeinfoPointer));
901 /* For asm_vm_call_method the codeinfo pointer is
904 m = (code == NULL) ? NULL : code->m;
907 /* Inline stackframe infos are special: they have a
908 xpc of the actual exception position and the return
909 address saved since an inline stackframe info can
910 also be in a leaf method (no return address saved
911 on stack!!!). ATTENTION: This one is also for
912 hardware exceptions!!! */
914 /* get methodinfo, sp and ra from the current stackframe info */
916 m = sfi->method; /* m == NULL */
917 pv = sfi->pv; /* pv of parent Java function */
918 sp = sfi->sp; /* sp of parent Java function */
919 ra = sfi->ra; /* ra of parent Java function */
920 xpc = sfi->xpc; /* actual exception position */
923 printf("ra=%p sp=%p, ", ra, sp);
924 printf("NULL: inline stub\n");
928 /* get methodinfo from current Java method */
930 code = *((codeinfo **) (pv + CodeinfoPointer));
932 /* For asm_vm_call_method the codeinfo pointer is
935 m = (code == NULL) ? NULL : code->m;
937 /* if m == NULL, this is a asm_calljavafunction call */
941 printf("ra=%p sp=%p, ", ra, sp);
943 printf(": inline stub parent");
947 #if defined(ENABLE_INTRP)
951 /* add the method to the stacktrace */
953 stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) xpc));
955 /* get the current stack frame size */
957 framesize = *((u4 *) (pv + FrameSize));
960 printf(", framesize=%d\n", framesize);
964 /* Set stack pointer to stackframe of parent Java
965 function of the current Java function. */
967 #if defined(__I386__) || defined (__X86_64__)
968 sp += framesize + SIZEOF_VOID_P;
973 /* get data segment and methodinfo pointer from
976 #if defined(ENABLE_JIT)
977 pv = md_codegen_get_pv_from_pc(ra);
980 code = *((codeinfo **) (pv + CodeinfoPointer));
982 /* For asm_vm_call_method the codeinfo pointer is
985 m = (code == NULL) ? NULL : code->m;
987 #if defined(ENABLE_INTRP)
993 printf("ra=%p sp=%p, ", ra, sp);
994 printf("asm_calljavafunction\n");
1000 /* get previous stackframeinfo in the chain */
1006 printf("ra=%p sp=%p, ", ra, sp);
1012 /* JIT method found, add it to the stacktrace (we subtract
1013 1 from the return address since it points the the
1014 instruction after call). */
1016 stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) ra) - 1);
1018 /* get the current stack frame size */
1020 framesize = *((u4 *) (pv + FrameSize));
1023 printf(", framesize=%d\n", framesize);
1027 /* get return address of current stack frame */
1029 #if defined(ENABLE_JIT)
1030 # if defined(ENABLE_INTRP)
1032 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
1035 ra = md_stacktrace_get_returnaddress(sp, framesize);
1037 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
1040 /* get data segment and methodinfo pointer from parent method */
1042 #if defined(ENABLE_INTRP)
1044 pv = codegen_get_pv_from_pc(ra);
1048 #if defined(ENABLE_JIT)
1049 pv = md_codegen_get_pv_from_pc(ra);
1053 code = *((codeinfo **) (pv + CodeinfoPointer));
1055 /* For asm_vm_call_method the codeinfo pointer is NULL. */
1057 m = (code == NULL) ? NULL : code->m;
1059 /* walk the stack */
1061 #if defined(ENABLE_INTRP)
1063 sp = *(u1 **) (sp - framesize);
1067 #if defined(__I386__) || defined (__X86_64__)
1068 sp += framesize + SIZEOF_VOID_P;
1076 /* return the stacktracebuffer */
1082 /* stacktrace_fillInStackTrace *************************************************
1084 Generate a stacktrace from the current thread for
1085 java.lang.VMThrowable.fillInStackTrace.
1087 *******************************************************************************/
1089 stacktracebuffer *stacktrace_fillInStackTrace(void)
1091 stacktracebuffer *stb;
1092 stacktracebuffer *gcstb;
1094 CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
1096 /* mark start of dump memory area */
1098 dumpsize = dump_size();
1100 /* create a stacktrace from the current thread */
1102 stb = stacktrace_create(THREADOBJECT);
1106 /* allocate memory from the GC heap and copy the stacktrace buffer */
1108 gcstb = GCNEW(stacktracebuffer);
1113 gcstb->capacity = stb->capacity;
1114 gcstb->used = stb->used;
1115 gcstb->entries = GCMNEW(stacktrace_entry, stb->used);
1117 if (gcstb->entries == NULL)
1120 MCOPY(gcstb->entries, stb->entries, stacktrace_entry, stb->used);
1122 /* release dump memory */
1124 dump_release(dumpsize);
1126 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
1127 stacktrace_overhead)
1131 dump_release(dumpsize);
1133 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
1134 stacktrace_overhead)
1140 /* stacktrace_getClassContext **************************************************
1142 Creates a Class context array.
1145 the array of java.lang.Class objects, or
1146 NULL if an exception has been thrown
1148 *******************************************************************************/
1150 java_objectarray *stacktrace_getClassContext(void)
1152 stacktracebuffer *stb;
1153 stacktrace_entry *ste;
1154 java_objectarray *oa;
1158 CYCLES_STATS_DECLARE_AND_START
1160 /* mark start of dump memory area */
1162 dumpsize = dump_size();
1164 /* create a stacktrace for the current thread */
1166 stb = stacktrace_create(THREADOBJECT);
1170 /* calculate the size of the Class array */
1172 for (i = 0, oalength = 0; i < stb->used; i++)
1173 if (stb->entries[i].method != NULL)
1176 /* The first entry corresponds to the method whose implementation */
1177 /* calls stacktrace_getClassContext. We remove that entry. */
1179 ste = &(stb->entries[0]);
1183 /* allocate the Class array */
1185 oa = builtin_anewarray(oalength, class_java_lang_Class);
1189 /* fill the Class array from the stacktracebuffer */
1191 for(i = 0; i < oalength; i++, ste++) {
1192 if (ste->method == NULL) {
1197 oa->data[i] = (java_objectheader *) ste->method->class;
1200 /* release dump memory */
1202 dump_release(dumpsize);
1204 CYCLES_STATS_END(stacktrace_getClassContext)
1209 dump_release(dumpsize);
1211 CYCLES_STATS_END(stacktrace_getClassContext)
1217 /* stacktrace_getCurrentClass **************************************************
1219 Find the current class by walking the stack trace.
1221 Quote from the JNI documentation:
1223 In the Java 2 Platform, FindClass locates the class loader
1224 associated with the current native method. If the native code
1225 belongs to a system class, no class loader will be
1226 involved. Otherwise, the proper class loader will be invoked to
1227 load and link the named class. When FindClass is called through the
1228 Invocation Interface, there is no current native method or its
1229 associated class loader. In that case, the result of
1230 ClassLoader.getBaseClassLoader is used."
1232 *******************************************************************************/
1234 classinfo *stacktrace_getCurrentClass(void)
1236 stacktracebuffer *stb;
1237 stacktrace_entry *ste;
1241 CYCLES_STATS_DECLARE_AND_START
1243 /* mark start of dump memory area */
1245 dumpsize = dump_size();
1247 /* create a stacktrace for the current thread */
1249 stb = stacktrace_create(THREADOBJECT);
1251 goto return_NULL; /* XXX exception: how to distinguish from normal NULL return? */
1253 /* iterate over all stacktrace entries and find the first suitable
1256 for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
1262 if (m->class == class_java_security_PrivilegedAction)
1265 if (m->class != NULL) {
1266 dump_release(dumpsize);
1268 CYCLES_STATS_END(stacktrace_getCurrentClass)
1274 /* no Java method found on the stack */
1277 dump_release(dumpsize);
1279 CYCLES_STATS_END(stacktrace_getCurrentClass)
1285 /* stacktrace_getStack *********************************************************
1287 Create a 2-dimensional array for java.security.VMAccessControler.
1291 NULL if an exception has been thrown
1293 *******************************************************************************/
1295 java_objectarray *stacktrace_getStack(void)
1297 stacktracebuffer *stb;
1298 stacktrace_entry *ste;
1299 java_objectarray *oa;
1300 java_objectarray *classes;
1301 java_objectarray *methodnames;
1303 java_lang_String *str;
1306 CYCLES_STATS_DECLARE_AND_START
1308 /* mark start of dump memory area */
1310 dumpsize = dump_size();
1312 /* create a stacktrace for the current thread */
1314 stb = stacktrace_create(THREADOBJECT);
1318 /* get the first stacktrace entry */
1320 ste = &(stb->entries[0]);
1322 /* allocate all required arrays */
1324 oa = builtin_anewarray(2, arrayclass_java_lang_Object);
1329 classes = builtin_anewarray(stb->used, class_java_lang_Class);
1334 methodnames = builtin_anewarray(stb->used, class_java_lang_String);
1339 /* set up the 2-dimensional array */
1341 oa->data[0] = (java_objectheader *) classes;
1342 oa->data[1] = (java_objectheader *) methodnames;
1344 /* iterate over all stacktrace entries */
1346 for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
1347 c = ste->method->class;
1349 classes->data[i] = (java_objectheader *) c;
1350 str = javastring_new(ste->method->name);
1355 methodnames->data[i] = (java_objectheader *) str;
1358 /* return the 2-dimensional array */
1360 dump_release(dumpsize);
1362 CYCLES_STATS_END(stacktrace_getStack)
1367 dump_release(dumpsize);
1369 CYCLES_STATS_END(stacktrace_getStack)
1375 /* stacktrace_print_trace_from_buffer ******************************************
1377 Print the stacktrace of a given stacktracebuffer with CACAO intern
1378 methods (no Java help). This method is used by
1379 stacktrace_dump_trace and builtin_trace_exception.
1381 *******************************************************************************/
1383 static void stacktrace_print_trace_from_buffer(stacktracebuffer *stb)
1385 stacktrace_entry *ste;
1389 ste = &(stb->entries[0]);
1391 for (i = 0; i < stb->used; i++, ste++) {
1395 utf_display_printable_ascii_classname(m->class->name);
1397 utf_display_printable_ascii(m->name);
1398 utf_display_printable_ascii(m->descriptor);
1400 if (m->flags & ACC_NATIVE) {
1401 puts("(Native Method)");
1405 utf_display_printable_ascii(m->class->sourcefile);
1406 printf(":%d)\n", (u4) ste->linenumber);
1410 /* just to be sure */
1416 /* stacktrace_dump_trace *******************************************************
1418 This method is call from signal_handler_sigusr1 to dump the
1419 stacktrace of the current thread to stdout.
1421 *******************************************************************************/
1423 void stacktrace_dump_trace(threadobject *thread)
1425 stacktracebuffer *stb;
1429 /* get methodinfo pointer from data segment */
1431 m = *((methodinfo **) (pv + MethodPointer));
1433 /* get current stackframe info pointer */
1435 psfi = STACKFRAMEINFO;
1437 /* fill new stackframe info structure */
1445 /* store new stackframe info pointer */
1450 /* mark start of dump memory area */
1452 dumpsize = dump_size();
1454 /* create a stacktrace for the current thread */
1456 stb = stacktrace_create(thread);
1458 /* print stacktrace */
1461 stacktrace_print_trace_from_buffer(stb);
1463 puts("\t<<No stacktrace available>>");
1467 dump_release(dumpsize);
1471 /* stacktrace_print_trace ******************************************************
1473 Print the stacktrace of a given exception. More or less a wrapper
1474 to stacktrace_print_trace_from_buffer.
1476 *******************************************************************************/
1478 void stacktrace_print_trace(java_objectheader *xptr)
1480 java_lang_Throwable *t;
1481 java_lang_VMThrowable *vmt;
1482 stacktracebuffer *stb;
1484 t = (java_lang_Throwable *) xptr;
1489 /* now print the stacktrace */
1492 stb = (stacktracebuffer *) vmt->vmData;
1494 stacktrace_print_trace_from_buffer(stb);
1498 #if defined(ENABLE_CYCLES_STATS)
1499 void stacktrace_print_cycles_stats(FILE *file)
1501 CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead,file);
1502 CYCLES_STATS_PRINT(stacktrace_fillInStackTrace,file);
1503 CYCLES_STATS_PRINT(stacktrace_getClassContext ,file);
1504 CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,file);
1505 CYCLES_STATS_PRINT(stacktrace_getStack ,file);
1511 * These are local overrides for various environment variables in Emacs.
1512 * Please do not remove this and leave it at the end of the file, where
1513 * Emacs will automagically detect them.
1514 * ---------------------------------------------------------------------
1517 * indent-tabs-mode: t
1521 * vim:noexpandtab:sw=4:ts=4: