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
31 $Id: stacktrace.c 5935 2006-11-08 20:27:37Z twisti $
44 #include "mm/gc-common.h"
45 #include "mm/memory.h"
46 #include "native/native.h"
48 #include "vm/global.h" /* required here for native includes */
49 #include "native/include/java_lang_ClassLoader.h"
50 #include "native/include/java_lang_Throwable.h"
51 #include "native/include/java_lang_VMThrowable.h"
53 #if defined(ENABLE_THREADS)
54 # include "threads/native/threads.h"
56 # include "threads/none/threads.h"
59 #include "toolbox/logging.h"
60 #include "vm/builtin.h"
62 #include "vm/exceptions.h"
63 #include "vm/loader.h"
64 #include "vm/options.h"
65 #include "vm/stringlocal.h"
67 #include "vm/jit/asmpart.h"
68 #include "vm/jit/codegen-common.h"
69 #include "vm/jit/methodheader.h"
70 #include "vm/cycles-stats.h"
73 /* linenumbertable_entry ******************************************************/
75 /* Keep the type of line the same as the pointer type, otherwise we
76 run into alignment troubles (like on MIPS64). */
78 typedef struct linenumbertable_entry linenumbertable_entry;
80 struct linenumbertable_entry {
81 ptrint line; /* NOTE: see doc/inlining_stacktrace.txt for */
82 u1 *pc; /* special meanings of line and pc. */
85 /* global variables ***********************************************************/
87 #if !defined(ENABLE_THREADS)
88 stackframeinfo *_no_threads_stackframeinfo = NULL;
91 CYCLES_STATS_DECLARE(stacktrace_overhead ,100,1)
92 CYCLES_STATS_DECLARE(stacktrace_fillInStackTrace,40,5000)
93 CYCLES_STATS_DECLARE(stacktrace_getClassContext ,40,5000)
94 CYCLES_STATS_DECLARE(stacktrace_getCurrentClass ,40,5000)
95 CYCLES_STATS_DECLARE(stacktrace_getStack ,40,10000)
98 /* stacktrace_create_stackframeinfo ********************************************
100 Creates an stackframe info structure for inline code in the
103 *******************************************************************************/
105 #if defined(ENABLE_INTRP)
106 void stacktrace_create_stackframeinfo(stackframeinfo *sfi, u1 *pv, u1 *sp,
109 stackframeinfo **psfi;
113 /* get current stackframe info pointer */
115 psfi = STACKFRAMEINFO;
117 /* if we don't have pv handy */
120 #if defined(ENABLE_INTRP)
122 pv = codegen_get_pv_from_pc(ra);
126 #if defined(ENABLE_JIT)
127 pv = md_codegen_get_pv_from_pc(ra);
132 /* get codeinfo pointer from data segment */
134 code = *((codeinfo **) (pv + CodeinfoPointer));
136 /* For asm_vm_call_method the codeinfo pointer is NULL. */
138 m = (code == NULL) ? NULL : code->m;
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_get_pv_from_pc(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_get_pv_from_pc(ra);
231 #if defined(ENABLE_JIT)
232 pv = md_codegen_get_pv_from_pc(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;
297 /* get codeinfo pointer from data segment */
299 code = *((codeinfo **) (pv + CodeinfoPointer));
301 /* For asm_vm_call_method the codeinfo pointer is NULL. */
303 m = (code == NULL) ? NULL : code->m;
305 /* get current stackframe info pointer */
307 psfi = STACKFRAMEINFO;
309 /* fill new stackframe info structure */
318 /* store new stackframe info pointer */
324 /* stacktrace_remove_stackframeinfo ********************************************
326 Remove the topmost stackframeinfo in the current thread.
328 *******************************************************************************/
330 void stacktrace_remove_stackframeinfo(stackframeinfo *sfi)
332 stackframeinfo **psfi;
334 /* get current stackframe info pointer */
336 psfi = STACKFRAMEINFO;
338 /* restore the old pointer */
344 /* stacktrace_inline_arithmeticexception ***************************************
346 Creates an ArithemticException for inline stub.
348 *******************************************************************************/
350 java_objectheader *stacktrace_inline_arithmeticexception(u1 *pv, u1 *sp,
354 java_objectheader *o;
356 /* create stackframeinfo */
358 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
360 /* create exception */
362 o = new_arithmeticexception();
364 /* remove stackframeinfo */
366 stacktrace_remove_stackframeinfo(&sfi);
372 /* stacktrace_inline_arrayindexoutofboundsexception ****************************
374 Creates an ArrayIndexOutOfBoundsException for inline stub.
376 *******************************************************************************/
378 java_objectheader *stacktrace_inline_arrayindexoutofboundsexception(u1 *pv,
385 java_objectheader *o;
387 /* create stackframeinfo */
389 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
391 /* create exception */
393 o = new_arrayindexoutofboundsexception(index);
395 /* remove stackframeinfo */
397 stacktrace_remove_stackframeinfo(&sfi);
403 /* stacktrace_inline_arraystoreexception ***************************************
405 Creates an ArrayStoreException for inline stub.
407 *******************************************************************************/
409 java_objectheader *stacktrace_inline_arraystoreexception(u1 *pv, u1 *sp, u1 *ra,
413 java_objectheader *o;
415 /* create stackframeinfo */
417 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
419 /* create exception */
421 o = exceptions_new_arraystoreexception();
423 /* remove stackframeinfo */
425 stacktrace_remove_stackframeinfo(&sfi);
431 /* stacktrace_inline_classcastexception ****************************************
433 Creates an ClassCastException for inline stub.
435 *******************************************************************************/
437 java_objectheader *stacktrace_inline_classcastexception(u1 *pv, u1 *sp, u1 *ra,
439 java_objectheader *o)
442 java_objectheader *e;
444 /* create stackframeinfo */
446 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
448 /* create exception */
450 e = exceptions_new_classcastexception(o);
452 /* remove stackframeinfo */
454 stacktrace_remove_stackframeinfo(&sfi);
460 /* stacktrace_inline_nullpointerexception **************************************
462 Creates an NullPointerException for inline stub.
464 *******************************************************************************/
466 java_objectheader *stacktrace_inline_nullpointerexception(u1 *pv, u1 *sp,
470 java_objectheader *o;
472 /* create stackframeinfo */
474 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
476 /* create exception */
478 o = exceptions_new_nullpointerexception();
480 /* remove stackframeinfo */
482 stacktrace_remove_stackframeinfo(&sfi);
488 /* stacktrace_inline_fillInStackTrace ******************************************
490 Fills in the correct stacktrace into an existing exception object
491 (this one is for inline exception stubs).
493 *******************************************************************************/
495 java_objectheader *stacktrace_inline_fillInStackTrace(u1 *pv, u1 *sp, u1 *ra,
499 java_objectheader *o;
502 /* create stackframeinfo */
504 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
511 /* clear exception */
513 *exceptionptr = NULL;
515 /* resolve methodinfo pointer from exception object */
517 m = class_resolvemethod(o->vftbl->class,
518 utf_fillInStackTrace,
519 utf_void__java_lang_Throwable);
523 (void) vm_call_method(m, o);
525 /* remove stackframeinfo */
527 stacktrace_remove_stackframeinfo(&sfi);
533 /* stacktrace_hardware_arithmeticexception *************************************
535 Creates an ArithemticException for inline stub.
537 *******************************************************************************/
539 java_objectheader *stacktrace_hardware_arithmeticexception(u1 *pv, u1 *sp,
543 java_objectheader *o;
545 /* create stackframeinfo */
547 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
549 /* create exception */
551 o = new_arithmeticexception();
553 /* remove stackframeinfo */
555 stacktrace_remove_stackframeinfo(&sfi);
561 /* stacktrace_hardware_nullpointerexception ************************************
563 Creates an NullPointerException for the SIGSEGV signal handler.
565 *******************************************************************************/
567 java_objectheader *stacktrace_hardware_nullpointerexception(u1 *pv, u1 *sp,
571 java_objectheader *o;
573 /* create stackframeinfo */
575 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
577 /* create exception */
579 o = exceptions_new_nullpointerexception();
581 /* remove stackframeinfo */
583 stacktrace_remove_stackframeinfo(&sfi);
589 /* stacktrace_add_entry ********************************************************
591 Adds a new entry to the stacktrace buffer.
593 *******************************************************************************/
595 static void stacktrace_add_entry(stacktracebuffer *stb, methodinfo *m, u2 line)
597 stacktrace_entry *ste;
599 /* check if we already reached the buffer capacity */
601 if (stb->used >= stb->capacity) {
602 /* reallocate new memory */
604 stb->entries = DMREALLOC(stb->entries, stacktrace_entry, stb->capacity,
605 stb->capacity + STACKTRACE_CAPACITY_INCREMENT);
607 /* set new buffer capacity */
609 stb->capacity = stb->capacity + STACKTRACE_CAPACITY_INCREMENT;
612 /* insert the current entry */
614 ste = &(stb->entries[stb->used]);
617 ste->linenumber = line;
619 /* increase entries used count */
625 /* stacktrace_add_method_intern ************************************************
627 This function is used by stacktrace_add_method to search the line number
628 table for the line corresponding to a given pc. The function recurses for
631 *******************************************************************************/
633 static bool stacktrace_add_method_intern(stacktracebuffer *stb,
635 linenumbertable_entry *lntentry,
639 linenumbertable_entry *lntinline; /* special entry for inlined method */
644 /* Find the line number for the specified PC (going backwards
645 in the linenumber table). The linenumber table size is zero
648 for (; lntsize > 0; lntsize--, lntentry--) {
650 /* did we reach the current line? */
652 /* Note: In case of inlining this may actually compare the pc
653 against a methodinfo *, yielding a non-sensical
654 result. This is no problem, however, as we ignore such
655 entries in the switch below. This way we optimize for the
656 common case (ie. a real pc in lntentry->pc). */
658 if (pc >= lntentry->pc) {
660 /* check for special inline entries (see
661 doc/inlining_stacktrace.txt for details */
663 if ((s4)lntentry->line < 0) {
664 switch (lntentry->line) {
666 /* begin of inlined method (ie. INLINE_END
669 lntinline = --lntentry;/* get entry with methodinfo * */
670 lntentry--; /* skip the special entry */
673 /* search inside the inlined method */
674 if (stacktrace_add_method_intern(
676 (methodinfo*) lntinline->pc,
681 /* the inlined method contained the pc */
682 assert(lntinline->line <= -3);
683 stacktrace_add_entry(stb, m, (-3) - lntinline->line);
686 /* pc was not in inlined method, continue
687 search. Entries inside the inlined method
688 will be skipped because their lntentry->pc
689 is higher than pc. */
693 /* end of inlined method */
696 /* default: is only reached for an -3-line entry
697 after a skipped -2 entry. We can safely ignore
698 it and continue searching. */
702 /* found a normal entry */
703 stacktrace_add_entry(stb, m, lntentry->line);
713 /* stacktrace_add_method *******************************************************
715 Add stacktrace entries[1] for the given method to the stacktrace buffer.
718 stb.........stacktracebuffer to fill
719 m...........method for which entries should be created
720 pv..........pv of method
721 pc..........position of program counter within the method's code
724 true, if stacktrace entries were successfully created, false otherwise.
726 [1] In case of inlined methods there may be more than one stacktrace
727 entry for a codegen-level method. (see doc/inlining_stacktrace.txt)
729 *******************************************************************************/
731 static bool stacktrace_add_method(stacktracebuffer *stb, methodinfo *m, u1 *pv,
734 ptrint lntsize; /* size of line number table */
735 u1 *lntstart; /* start of line number table */
736 linenumbertable_entry *lntentry; /* points to last entry in the table */
737 codeinfo *code; /* compiled realization of method */
739 /* get size of line number table */
741 lntsize = *((ptrint *) (pv + LineNumberTableSize));
742 lntstart = *((u1 **) (pv + LineNumberTableStart));
744 /* Subtract the size of the line number entry of the structure,
745 since the line number table start points to the pc. */
747 lntentry = (linenumbertable_entry *) (lntstart - SIZEOF_VOID_P);
749 /* find the realization of the method the pc is in */
752 code = *((codeinfo **) (pv + CodeinfoPointer));
756 /* XXX Note: This is preliminary. It would be cleaner */
757 /* to get the codeinfo * from the PV */
764 dolog("Could not find codeinfo for Current PC: %p",(void*)pc);
769 if (((ptrint)pc >= (ptrint)code->entrypoint)
771 ( (pc - (u1*)code->entrypoint) < code->mcodelength ))
781 /* search the line number table */
783 if (stacktrace_add_method_intern(stb, m, lntentry, lntsize, pc))
786 /* If we get here, just add the entry with line number 0. */
788 stacktrace_add_entry(stb, m, 0);
794 /* stacktrace_create ***********************************************************
796 Generates a stacktrace from the thread passed into a
797 stacktracebuffer. The stacktracebuffer is allocated on the GC
801 pointer to the stacktracebuffer, or
802 NULL if an exception has been thrown
804 *******************************************************************************/
806 stacktracebuffer *stacktrace_create(threadobject* thread)
808 stacktracebuffer *stb;
818 /* prevent compiler warnings */
824 /* create a stacktracebuffer in dump memory */
826 stb = DNEW(stacktracebuffer);
828 stb->capacity = STACKTRACE_CAPACITY_DEFAULT;
830 stb->entries = DMNEW(stacktrace_entry, STACKTRACE_CAPACITY_DEFAULT);
832 /* The first element in the stackframe chain must always be a
833 native stackframeinfo (VMThrowable.fillInStackTrace is a native
836 /* We don't use the STACKFRAMEINFO macro here, as we have to use
837 the passed thread. */
839 #if defined(ENABLE_THREADS)
840 sfi = thread->_stackframeinfo;
842 sfi = _no_threads_stackframeinfo;
845 #define PRINTMETHODS 0
848 printf("\n\nfillInStackTrace start:\n");
852 /* Loop while we have a method pointer (asm_calljavafunction has
853 NULL) or there is a stackframeinfo in the chain. */
857 while ((m != NULL) || (sfi != NULL)) {
858 /* m == NULL should only happen for the first time and inline
859 stackframe infos, like from the exception stubs or the
863 /* for native stub stackframe infos, pv is always NULL */
865 if (sfi->pv == NULL) {
866 /* get methodinfo, sp and ra from the current stackframe info */
869 sp = sfi->sp; /* sp of parent Java function */
873 stacktrace_add_entry(stb, m, 0);
876 printf("ra=%p sp=%p, ", ra, sp);
878 printf(": native stub\n");
881 /* This is an native stub stackframe info, so we can
882 get the parent pv from the return address
885 #if defined(ENABLE_INTRP)
887 pv = codegen_get_pv_from_pc(ra);
891 #if defined(ENABLE_JIT)
892 pv = md_codegen_get_pv_from_pc(ra);
896 /* get methodinfo pointer from parent data segment */
898 code = *((codeinfo **) (pv + CodeinfoPointer));
900 /* For asm_vm_call_method the codeinfo pointer is
903 m = (code == NULL) ? NULL : code->m;
906 /* Inline stackframe infos are special: they have a
907 xpc of the actual exception position and the return
908 address saved since an inline stackframe info can
909 also be in a leaf method (no return address saved
910 on stack!!!). ATTENTION: This one is also for
911 hardware exceptions!!! */
913 /* get methodinfo, sp and ra from the current stackframe info */
915 m = sfi->method; /* m == NULL */
916 pv = sfi->pv; /* pv of parent Java function */
917 sp = sfi->sp; /* sp of parent Java function */
918 ra = sfi->ra; /* ra of parent Java function */
919 xpc = sfi->xpc; /* actual exception position */
922 printf("ra=%p sp=%p, ", ra, sp);
923 printf("NULL: inline stub\n");
927 /* get methodinfo from current Java method */
929 code = *((codeinfo **) (pv + CodeinfoPointer));
931 /* For asm_vm_call_method the codeinfo pointer is
934 m = (code == NULL) ? NULL : code->m;
936 /* if m == NULL, this is a asm_calljavafunction call */
940 printf("ra=%p sp=%p, ", ra, sp);
942 printf(": inline stub parent");
946 #if defined(ENABLE_INTRP)
950 /* add the method to the stacktrace */
952 stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) xpc));
954 /* get the current stack frame size */
956 framesize = *((u4 *) (pv + FrameSize));
959 printf(", framesize=%d\n", framesize);
963 /* Set stack pointer to stackframe of parent Java
964 function of the current Java function. */
966 #if defined(__I386__) || defined (__X86_64__)
967 sp += framesize + SIZEOF_VOID_P;
972 /* get data segment and methodinfo pointer from
975 #if defined(ENABLE_JIT)
976 pv = md_codegen_get_pv_from_pc(ra);
979 code = *((codeinfo **) (pv + CodeinfoPointer));
981 /* For asm_vm_call_method the codeinfo pointer is
984 m = (code == NULL) ? NULL : code->m;
986 #if defined(ENABLE_INTRP)
992 printf("ra=%p sp=%p, ", ra, sp);
993 printf("asm_calljavafunction\n");
999 /* get previous stackframeinfo in the chain */
1005 printf("ra=%p sp=%p, ", ra, sp);
1011 /* JIT method found, add it to the stacktrace (we subtract
1012 1 from the return address since it points the the
1013 instruction after call). */
1015 stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) ra) - 1);
1017 /* get the current stack frame size */
1019 framesize = *((u4 *) (pv + FrameSize));
1022 printf(", framesize=%d\n", framesize);
1026 /* get return address of current stack frame */
1028 #if defined(ENABLE_JIT)
1029 # if defined(ENABLE_INTRP)
1031 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
1034 ra = md_stacktrace_get_returnaddress(sp, framesize);
1036 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
1039 /* get data segment and methodinfo pointer from parent method */
1041 #if defined(ENABLE_INTRP)
1043 pv = codegen_get_pv_from_pc(ra);
1047 #if defined(ENABLE_JIT)
1048 pv = md_codegen_get_pv_from_pc(ra);
1052 code = *((codeinfo **) (pv + CodeinfoPointer));
1054 /* For asm_vm_call_method the codeinfo pointer is NULL. */
1056 m = (code == NULL) ? NULL : code->m;
1058 /* walk the stack */
1060 #if defined(ENABLE_INTRP)
1062 sp = *(u1 **) (sp - framesize);
1066 #if defined(__I386__) || defined (__X86_64__)
1067 sp += framesize + SIZEOF_VOID_P;
1075 /* return the stacktracebuffer */
1081 /* stacktrace_fillInStackTrace *************************************************
1083 Generate a stacktrace from the current thread for
1084 java.lang.VMThrowable.fillInStackTrace.
1086 *******************************************************************************/
1088 stacktracecontainer *stacktrace_fillInStackTrace(void)
1090 stacktracebuffer *stb;
1091 stacktracecontainer *gcstc;
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 */
1107 /* ATTENTION: use stacktracecontainer for this and make it look like
1110 gcstc_size = sizeof(stacktracebuffer) +
1111 sizeof(stacktrace_entry) * stb->used;
1112 gcstc = (stacktracecontainer *) builtin_newarray_byte(gcstc_size);
1117 gcstc->stb.capacity = stb->capacity;
1118 gcstc->stb.used = stb->used;
1119 gcstc->stb.entries = gcstc->data;
1121 MCOPY(gcstc->data, stb->entries, stacktrace_entry, stb->used);
1123 /* release dump memory */
1125 dump_release(dumpsize);
1127 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
1128 stacktrace_overhead)
1132 dump_release(dumpsize);
1134 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
1135 stacktrace_overhead)
1141 /* stacktrace_getClassContext **************************************************
1143 Creates a Class context array.
1146 the array of java.lang.Class objects, or
1147 NULL if an exception has been thrown
1149 *******************************************************************************/
1151 java_objectarray *stacktrace_getClassContext(void)
1153 stacktracebuffer *stb;
1154 stacktrace_entry *ste;
1155 java_objectarray *oa;
1159 CYCLES_STATS_DECLARE_AND_START
1161 /* mark start of dump memory area */
1163 dumpsize = dump_size();
1165 /* create a stacktrace for the current thread */
1167 stb = stacktrace_create(THREADOBJECT);
1171 /* calculate the size of the Class array */
1173 for (i = 0, oalength = 0; i < stb->used; i++)
1174 if (stb->entries[i].method != NULL)
1177 /* The first entry corresponds to the method whose implementation */
1178 /* calls stacktrace_getClassContext. We remove that entry. */
1180 ste = &(stb->entries[0]);
1184 /* allocate the Class array */
1186 oa = builtin_anewarray(oalength, class_java_lang_Class);
1190 /* fill the Class array from the stacktracebuffer */
1192 for(i = 0; i < oalength; i++, ste++) {
1193 if (ste->method == NULL) {
1198 oa->data[i] = (java_objectheader *) ste->method->class;
1201 /* release dump memory */
1203 dump_release(dumpsize);
1205 CYCLES_STATS_END(stacktrace_getClassContext)
1210 dump_release(dumpsize);
1212 CYCLES_STATS_END(stacktrace_getClassContext)
1218 /* stacktrace_getCurrentClass **************************************************
1220 Find the current class by walking the stack trace.
1222 Quote from the JNI documentation:
1224 In the Java 2 Platform, FindClass locates the class loader
1225 associated with the current native method. If the native code
1226 belongs to a system class, no class loader will be
1227 involved. Otherwise, the proper class loader will be invoked to
1228 load and link the named class. When FindClass is called through the
1229 Invocation Interface, there is no current native method or its
1230 associated class loader. In that case, the result of
1231 ClassLoader.getBaseClassLoader is used."
1233 *******************************************************************************/
1235 classinfo *stacktrace_getCurrentClass(void)
1237 stacktracebuffer *stb;
1238 stacktrace_entry *ste;
1242 CYCLES_STATS_DECLARE_AND_START
1244 /* mark start of dump memory area */
1246 dumpsize = dump_size();
1248 /* create a stacktrace for the current thread */
1250 stb = stacktrace_create(THREADOBJECT);
1252 goto return_NULL; /* XXX exception: how to distinguish from normal NULL return? */
1254 /* iterate over all stacktrace entries and find the first suitable
1257 for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
1263 if (m->class == class_java_security_PrivilegedAction)
1266 if (m->class != NULL) {
1267 dump_release(dumpsize);
1269 CYCLES_STATS_END(stacktrace_getCurrentClass)
1275 /* no Java method found on the stack */
1278 dump_release(dumpsize);
1280 CYCLES_STATS_END(stacktrace_getCurrentClass)
1286 /* stacktrace_getStack *********************************************************
1288 Create a 2-dimensional array for java.security.VMAccessControler.
1292 NULL if an exception has been thrown
1294 *******************************************************************************/
1296 java_objectarray *stacktrace_getStack(void)
1298 stacktracebuffer *stb;
1299 stacktrace_entry *ste;
1300 java_objectarray *oa;
1301 java_objectarray *classes;
1302 java_objectarray *methodnames;
1304 java_lang_String *str;
1307 CYCLES_STATS_DECLARE_AND_START
1309 /* mark start of dump memory area */
1311 dumpsize = dump_size();
1313 /* create a stacktrace for the current thread */
1315 stb = stacktrace_create(THREADOBJECT);
1319 /* get the first stacktrace entry */
1321 ste = &(stb->entries[0]);
1323 /* allocate all required arrays */
1325 oa = builtin_anewarray(2, arrayclass_java_lang_Object);
1330 classes = builtin_anewarray(stb->used, class_java_lang_Class);
1335 methodnames = builtin_anewarray(stb->used, class_java_lang_String);
1340 /* set up the 2-dimensional array */
1342 oa->data[0] = (java_objectheader *) classes;
1343 oa->data[1] = (java_objectheader *) methodnames;
1345 /* iterate over all stacktrace entries */
1347 for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
1348 c = ste->method->class;
1350 classes->data[i] = (java_objectheader *) c;
1351 str = javastring_new(ste->method->name);
1356 methodnames->data[i] = (java_objectheader *) str;
1359 /* return the 2-dimensional array */
1361 dump_release(dumpsize);
1363 CYCLES_STATS_END(stacktrace_getStack)
1368 dump_release(dumpsize);
1370 CYCLES_STATS_END(stacktrace_getStack)
1376 /* stacktrace_print_trace_from_buffer ******************************************
1378 Print the stacktrace of a given stacktracebuffer with CACAO intern
1379 methods (no Java help). This method is used by
1380 stacktrace_dump_trace and builtin_trace_exception.
1382 *******************************************************************************/
1384 static void stacktrace_print_trace_from_buffer(stacktracebuffer *stb)
1386 stacktrace_entry *ste;
1390 ste = &(stb->entries[0]);
1392 for (i = 0; i < stb->used; i++, ste++) {
1396 utf_display_printable_ascii_classname(m->class->name);
1398 utf_display_printable_ascii(m->name);
1399 utf_display_printable_ascii(m->descriptor);
1401 if (m->flags & ACC_NATIVE) {
1402 puts("(Native Method)");
1406 utf_display_printable_ascii(m->class->sourcefile);
1407 printf(":%d)\n", (u4) ste->linenumber);
1411 /* just to be sure */
1417 /* stacktrace_dump_trace *******************************************************
1419 This method is call from signal_handler_sigusr1 to dump the
1420 stacktrace of the current thread to stdout.
1422 *******************************************************************************/
1424 void stacktrace_dump_trace(threadobject *thread)
1426 stacktracebuffer *stb;
1430 /* get methodinfo pointer from data segment */
1432 m = *((methodinfo **) (pv + MethodPointer));
1434 /* get current stackframe info pointer */
1436 psfi = STACKFRAMEINFO;
1438 /* fill new stackframe info structure */
1446 /* store new stackframe info pointer */
1451 /* mark start of dump memory area */
1453 dumpsize = dump_size();
1455 /* create a stacktrace for the current thread */
1457 stb = stacktrace_create(thread);
1459 /* print stacktrace */
1462 stacktrace_print_trace_from_buffer(stb);
1464 puts("\t<<No stacktrace available>>");
1468 dump_release(dumpsize);
1472 /* stacktrace_print_trace ******************************************************
1474 Print the stacktrace of a given exception. More or less a wrapper
1475 to stacktrace_print_trace_from_buffer.
1477 *******************************************************************************/
1479 void stacktrace_print_trace(java_objectheader *xptr)
1481 java_lang_Throwable *t;
1482 java_lang_VMThrowable *vmt;
1483 stacktracecontainer *stc;
1484 stacktracebuffer *stb;
1486 t = (java_lang_Throwable *) xptr;
1491 /* now print the stacktrace */
1494 stc = (stacktracecontainer *) vmt->vmData;
1497 stacktrace_print_trace_from_buffer(stb);
1501 #if defined(ENABLE_CYCLES_STATS)
1502 void stacktrace_print_cycles_stats(FILE *file)
1504 CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead,file);
1505 CYCLES_STATS_PRINT(stacktrace_fillInStackTrace,file);
1506 CYCLES_STATS_PRINT(stacktrace_getClassContext ,file);
1507 CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,file);
1508 CYCLES_STATS_PRINT(stacktrace_getStack ,file);
1514 * These are local overrides for various environment variables in Emacs.
1515 * Please do not remove this and leave it at the end of the file, where
1516 * Emacs will automagically detect them.
1517 * ---------------------------------------------------------------------
1520 * indent-tabs-mode: t
1524 * vim:noexpandtab:sw=4:ts=4: