1 /* src/vm/jit/stacktrace.c - machine independet stacktrace system
3 Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
4 R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
5 C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
6 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., 59 Temple Place - Suite 330, Boston, MA
25 Contact: cacao@complang.tuwien.ac.at
27 Authors: Joseph Wenninger
29 Changes: Christian Thalinger
31 $Id: stacktrace.c 3570 2005-11-04 16:58:36Z motse $
43 #include "native/native.h"
45 #include "vm/global.h" /* required here for native includes */
46 #include "native/include/java_lang_ClassLoader.h"
48 #include "toolbox/logging.h"
49 #include "vm/builtin.h"
51 #include "vm/exceptions.h"
52 #include "vm/loader.h"
53 #include "vm/options.h"
54 #include "vm/stringlocal.h"
55 #include "vm/tables.h"
56 #include "vm/jit/asmpart.h"
57 #include "vm/jit/codegen.inc.h"
58 #include "vm/jit/methodheader.h"
61 /* lineNumberTableEntry *******************************************************/
63 /* Keep the type of line the same as the pointer type, otherwise we run into */
64 /* alignment troubles (like on MIPS64). */
66 typedef struct lineNumberTableEntry {
69 } lineNumberTableEntry;
72 typedef struct lineNumberTableEntryInlineBegin {
73 /* this should have the same layout and size as the lineNumberTableEntry */
76 } lineNumberTableEntryInlineBegin;
79 typedef bool(*CacaoStackTraceCollector)(void **, stackTraceBuffer*);
82 #define BLOCK_INITIALSIZE 40
83 #define BLOCK_SIZEINCREMENT 40
86 /* global variables ***********************************************************/
88 #if !defined(USE_THREADS)
89 stackframeinfo *_no_threads_stackframeinfo = NULL;
93 /* stacktrace_create_stackframeinfo ********************************************
95 Creates an stackframe info structure for inline code in the
98 *******************************************************************************/
100 #if defined(ENABLE_INTRP)
101 void stacktrace_create_stackframeinfo(stackframeinfo *sfi, u1 *pv,
102 u1 *sp, functionptr ra)
104 stackframeinfo **psfi;
107 /* get current stackframe info pointer */
109 psfi = STACKFRAMEINFO;
111 /* if we don't have pv handy */
114 pv = (u1 *) (ptrint) codegen_findmethod(ra);
116 /* get methodinfo pointer from data segment */
118 m = *((methodinfo **) (pv + MethodPointer));
120 /* fill new stackframe info structure */
128 /* xpc is the same as ra, but is required in fillInStackTrace */
132 /* store new stackframe info pointer */
136 #endif /* defined(ENABLE_INTRP) */
138 /* stacktrace_create_inline_stackframeinfo *************************************
140 Creates an stackframe info structure for an inline exception stub.
142 *******************************************************************************/
144 void stacktrace_create_inline_stackframeinfo(stackframeinfo *sfi, u1 *pv,
145 u1 *sp, functionptr ra,
148 stackframeinfo **psfi;
150 /* get current stackframe info pointer */
152 psfi = STACKFRAMEINFO;
154 #if defined(ENABLE_INTRP)
156 /* if we don't have pv handy */
159 pv = (u1 *) (ptrint) codegen_findmethod(ra);
164 /* fill new stackframe info structure */
173 /* store new stackframe info pointer */
179 /* stacktrace_create_extern_stackframeinfo *************************************
181 Creates an stackframe info structure for an extern exception
182 (hardware or assembler).
184 *******************************************************************************/
186 void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv,
187 u1 *sp, functionptr ra,
190 stackframeinfo **psfi;
191 #if !defined(__I386__) && !defined(__X86_64__)
196 /* get current stackframe info pointer */
198 psfi = STACKFRAMEINFO;
200 /* sometimes we don't have pv handy (e.g. in asmpart.S:
201 L_asm_call_jit_compiler_exception or in the interpreter). */
204 pv = (u1 *) (ptrint) codegen_findmethod(ra);
206 #if defined(ENABLE_INTRP)
207 /* When using the interpreter, we pass RA to the function. */
211 # if defined(__I386__) || defined(__X86_64__)
212 /* On i386 and x86_64 we always have to get the return address
215 framesize = *((u4 *) (pv + FrameSize));
217 ra = md_stacktrace_get_returnaddress(sp, framesize);
219 /* If the method is a non-leaf function, we need to get the return
220 address from the stack. For leaf functions the return address
221 is set correctly. This makes the assembler and the signal
222 handler code simpler. */
224 isleafmethod = *((s4 *) (pv + IsLeaf));
227 framesize = *((u4 *) (pv + FrameSize));
229 ra = md_stacktrace_get_returnaddress(sp, framesize);
232 #if defined(ENABLE_INTRP)
236 /* fill new stackframe info structure */
245 /* store new stackframe info pointer */
251 /* stacktrace_create_native_stackframeinfo *************************************
253 Creates a stackframe info structure for a native stub.
255 *******************************************************************************/
257 void stacktrace_create_native_stackframeinfo(stackframeinfo *sfi, u1 *pv,
258 u1 *sp, functionptr ra)
260 stackframeinfo **psfi;
263 /* get methodinfo pointer from data segment */
265 m = *((methodinfo **) (pv + MethodPointer));
267 /* get current stackframe info pointer */
269 psfi = STACKFRAMEINFO;
271 /* fill new stackframe info structure */
280 /* store new stackframe info pointer */
286 /* stacktrace_remove_stackframeinfo ********************************************
290 *******************************************************************************/
292 void stacktrace_remove_stackframeinfo(stackframeinfo *sfi)
294 stackframeinfo **psfi;
296 /* get current stackframe info pointer */
298 psfi = STACKFRAMEINFO;
300 /* restore the old pointer */
306 /* stacktrace_inline_arithmeticexception ***************************************
308 Creates an ArithemticException for inline stub.
310 *******************************************************************************/
312 java_objectheader *stacktrace_inline_arithmeticexception(u1 *pv, u1 *sp,
317 java_objectheader *o;
319 /* create stackframeinfo */
321 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
323 /* create exception */
325 o = new_arithmeticexception();
327 /* remove stackframeinfo */
329 stacktrace_remove_stackframeinfo(&sfi);
335 /* stacktrace_inline_arrayindexoutofboundsexception ****************************
337 Creates an ArrayIndexOutOfBoundsException for inline stub.
339 *******************************************************************************/
341 java_objectheader *stacktrace_inline_arrayindexoutofboundsexception(u1 *pv,
348 java_objectheader *o;
350 /* create stackframeinfo */
352 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
354 /* create exception */
356 o = new_arrayindexoutofboundsexception(index);
358 /* remove stackframeinfo */
360 stacktrace_remove_stackframeinfo(&sfi);
366 /* stacktrace_inline_arraystoreexception ***************************************
368 Creates an ArrayStoreException for inline stub.
370 *******************************************************************************/
372 java_objectheader *stacktrace_inline_arraystoreexception(u1 *pv, u1 *sp,
377 java_objectheader *o;
379 /* create stackframeinfo */
381 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
383 /* create exception */
385 o = new_arraystoreexception();
387 /* remove stackframeinfo */
389 stacktrace_remove_stackframeinfo(&sfi);
395 /* stacktrace_inline_classcastexception ****************************************
397 Creates an ClassCastException for inline stub.
399 *******************************************************************************/
401 java_objectheader *stacktrace_inline_classcastexception(u1 *pv, u1 *sp,
406 java_objectheader *o;
408 /* create stackframeinfo */
410 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
412 /* create exception */
414 o = new_classcastexception();
416 /* remove stackframeinfo */
418 stacktrace_remove_stackframeinfo(&sfi);
424 /* stacktrace_inline_nullpointerexception **************************************
426 Creates an NullPointerException for inline stub.
428 *******************************************************************************/
430 java_objectheader *stacktrace_inline_nullpointerexception(u1 *pv, u1 *sp,
435 java_objectheader *o;
437 /* create stackframeinfo */
439 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
441 /* create exception */
443 o = new_nullpointerexception();
445 /* remove stackframeinfo */
447 stacktrace_remove_stackframeinfo(&sfi);
453 /* stacktrace_hardware_arithmeticexception *************************************
455 Creates an ArithemticException for inline stub.
457 *******************************************************************************/
459 java_objectheader *stacktrace_hardware_arithmeticexception(u1 *pv, u1 *sp,
464 java_objectheader *o;
466 /* create stackframeinfo */
468 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
470 /* create exception */
472 o = new_arithmeticexception();
474 /* remove stackframeinfo */
476 stacktrace_remove_stackframeinfo(&sfi);
482 /* stacktrace_hardware_nullpointerexception ************************************
484 Creates an NullPointerException for the SIGSEGV signal handler.
486 *******************************************************************************/
488 java_objectheader *stacktrace_hardware_nullpointerexception(u1 *pv, u1 *sp,
493 java_objectheader *o;
495 /* create stackframeinfo */
497 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
499 /* create exception */
501 o = new_nullpointerexception();
503 /* remove stackframeinfo */
505 stacktrace_remove_stackframeinfo(&sfi);
511 /* stacktrace_inline_fillInStackTrace ******************************************
513 Fills in the correct stacktrace into an existing exception object
514 (this one is for inline exception stubs).
516 *******************************************************************************/
518 java_objectheader *stacktrace_inline_fillInStackTrace(u1 *pv, u1 *sp,
523 java_objectheader *o;
526 /* create stackframeinfo */
528 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
534 /* clear exception */
536 *exceptionptr = NULL;
538 /* resolve methodinfo pointer from exception object */
540 m = class_resolvemethod(o->vftbl->class,
541 utf_fillInStackTrace,
542 utf_void__java_lang_Throwable);
546 asm_calljavafunction(m, o, NULL, NULL, NULL);
548 /* remove stackframeinfo */
550 stacktrace_remove_stackframeinfo(&sfi);
556 /* addEntry ********************************************************************
560 *******************************************************************************/
562 static void addEntry(stackTraceBuffer *buffer, methodinfo *method, u2 line)
564 if (buffer->size > buffer->full) {
565 stacktraceelement *tmp = &(buffer->start[buffer->full]);
567 tmp->method = method;
568 tmp->linenumber = line;
569 buffer->full = buffer->full + 1;
572 stacktraceelement *newBuffer;
575 (stacktraceelement *) malloc((buffer->size + BLOCK_SIZEINCREMENT) *
576 sizeof(stacktraceelement));
578 if (newBuffer == 0) {
579 log_text("OOM during stacktrace creation");
583 memcpy(newBuffer, buffer->start, buffer->size * sizeof(stacktraceelement));
584 if (buffer->needsFree)
587 buffer->start = newBuffer;
588 buffer->size = buffer->size + BLOCK_SIZEINCREMENT;
589 buffer->needsFree = 1;
591 addEntry(buffer, method, line);
596 /* stacktrace_fillInStackTrace_methodRecursive *********************************
600 *******************************************************************************/
602 static bool stacktrace_fillInStackTrace_methodRecursive(stackTraceBuffer *buffer,
604 lineNumberTableEntry *lntentry,
609 lineNumberTableEntryInlineBegin *lntinline;
612 /* find the line number for the specified pc (going backwards) */
614 for (; lntsize > 0; lntsize--, lntentry--) {
615 /* did we reach the current line? */
617 if (pc >= lntentry->pc) {
618 /* check for special inline entries */
620 switch (lntentry->line) {
622 /* XXX TWISTI we have to think about this inline stuff again */
624 case -1: /* begin of inlined method */
625 lntinline = (lineNumberTableEntryInlineBegin *) (--lntentry);
627 lntsize--; lntsize--;
628 if (stacktrace_fillInStackTrace_methodRecursive(buffer,
634 addEntry(buffer, m, ilStart->lineNrOuter);
640 case -2: /* end of inlined method */
642 *entriesAhead = ahead;
648 addEntry(buffer, m, lntentry->line);
654 /* check if we are before the actual JIT code */
656 if ((ptrint) pc < (ptrint) m->entrypoint) {
657 dolog("Current pc before start of code: %p < %p", pc, m->entrypoint);
661 /* otherwise just add line 0 */
663 addEntry(buffer, m, 0);
669 /* stacktrace_fillInStackTrace_method ******************************************
673 *******************************************************************************/
675 static void stacktrace_fillInStackTrace_method(stackTraceBuffer *buffer,
676 methodinfo *method, u1 *pv,
679 ptrint lntsize; /* size of line number table */
680 u1 *lntstart; /* start of line number table */
681 lineNumberTableEntry *lntentry; /* points to last entry in the table */
683 /* get size of line number table */
685 lntsize = *((ptrint *) (pv + LineNumberTableSize));
686 lntstart = *((u1 **) (pv + LineNumberTableStart));
688 /* subtract the size of the line number entry of the structure, since the */
689 /* line number table start points to the pc */
691 lntentry = (lineNumberTableEntry *) (lntstart - SIZEOF_VOID_P);
694 /* this happens when an exception is thrown in the native stub */
696 addEntry(buffer, method, 0);
699 if (!stacktrace_fillInStackTrace_methodRecursive(buffer,
704 log_text("Trace point not found in suspected method");
711 /* cacao_stacktrace_fillInStackTrace *******************************************
715 *******************************************************************************/
717 bool cacao_stacktrace_fillInStackTrace(void **target,
718 CacaoStackTraceCollector coll,
719 threadobject* thread)
721 static bool cacao_stacktrace_fillInStackTrace(void **target,
722 CacaoStackTraceCollector coll)
726 stacktraceelement primaryBlock[BLOCK_INITIALSIZE*sizeof(stacktraceelement)];
727 stackTraceBuffer buffer;
737 /* prevent compiler warnings */
743 /* In most cases this should be enough -> one malloc less. I don't think */
744 /* temporary data should be allocated with the GC, only the result. */
746 buffer.needsFree = 0;
747 buffer.start = primaryBlock;
748 buffer.size = BLOCK_INITIALSIZE; /* *sizeof(stacktraceelement); */
751 /* the first element in the stackframe chain must always be a native */
752 /* stackframeinfo (VMThrowable.fillInStackTrace is a native function) */
756 sfi = *STACKFRAMEINFO; /* invocation from Throwable */
758 sfi = thread->info._stackframeinfo; /* invocation from JVMTI */
760 sfi = *STACKFRAMEINFO;
768 #define PRINTMETHODS 0
771 printf("\n\nfillInStackTrace start:\n");
775 /* loop while we have a method pointer (asm_calljavafunction has NULL) or */
776 /* there is a stackframeinfo in the chain */
781 /* m == NULL should only happen for the first time and inline */
782 /* stackframe infos, like from the exception stubs or the patcher */
786 /* for native stub stackframe infos, pv is always NULL */
788 if (sfi->pv == NULL) {
789 /* get methodinfo, sp and ra from the current stackframe info */
792 sp = sfi->sp; /* sp of parent Java function */
796 addEntry(&buffer, m, 0);
799 utf_display_classname(m->class->name);
801 utf_display(m->name);
802 utf_display(m->descriptor);
803 printf(": native stub\n");
806 /* this is an native stub stackframe info, so we can get the */
807 /* parent pv from the return address (ICMD_INVOKE*) */
809 pv = (u1 *) (ptrint) codegen_findmethod(ra);
811 /* get methodinfo pointer from parent data segment */
813 m = *((methodinfo **) (pv + MethodPointer));
816 /* Inline stackframe infos are special: they have a xpc of */
817 /* the actual exception position and the return address saved */
818 /* since an inline stackframe info can also be in a leaf */
819 /* method (no return address saved on stack!!!). */
820 /* ATTENTION: This one is also for hardware exceptions!!! */
822 /* get methodinfo, sp and ra from the current stackframe info */
824 m = sfi->method; /* m == NULL */
825 pv = sfi->pv; /* pv of parent Java function */
826 sp = sfi->sp; /* sp of parent Java function */
827 ra = sfi->ra; /* ra of parent Java function */
828 xpc = sfi->xpc; /* actual exception position */
831 printf("NULL: inline stub\n");
835 /* get methodinfo from current Java method */
837 m = *((methodinfo **) (pv + MethodPointer));
839 /* if m == NULL, this is a asm_calljavafunction call */
843 utf_display_classname(m->class->name);
845 utf_display(m->name);
846 utf_display(m->descriptor);
847 printf(": inline stub parent\n");
851 #if defined(ENABLE_INTRP)
855 /* add it to the stacktrace */
857 stacktrace_fillInStackTrace_method(&buffer, m, pv,
858 (u1 *) ((ptrint) xpc));
860 /* get the current stack frame size */
862 framesize = *((u4 *) (pv + FrameSize));
864 /* set stack pointer to stackframe of parent Java */
865 /* function of the current Java function */
867 #if defined(__I386__) || defined (__X86_64__)
868 sp += framesize + SIZEOF_VOID_P;
873 /* get data segment and methodinfo pointer from parent */
876 pv = (u1 *) (ptrint) codegen_findmethod(ra);
877 m = *((methodinfo **) (pv + MethodPointer));
879 #if defined(ENABLE_INTRP)
885 printf("asm_calljavafunction\n");
891 /* get previous stackframeinfo in the chain */
897 utf_display_classname(m->class->name);
899 utf_display(m->name);
900 utf_display(m->descriptor);
904 /* JIT method found, add it to the stacktrace (we subtract 1 from */
905 /* the return address since it points the the instruction after */
908 stacktrace_fillInStackTrace_method(&buffer, m, pv,
909 (u1 *) ((ptrint) ra) - 1);
911 /* get the current stack frame size */
913 framesize = *((u4 *) (pv + FrameSize));
915 /* get return address of current stack frame */
917 ra = md_stacktrace_get_returnaddress(sp, framesize);
919 /* get data segment and methodinfo pointer from parent method */
921 pv = (u1 *) (ptrint) codegen_findmethod(ra);
922 m = *((methodinfo **) (pv + MethodPointer));
926 #if defined(ENABLE_INTRP)
928 sp = *(u1 **)(sp - framesize);
932 #if defined(__I386__) || defined (__X86_64__)
933 sp += framesize + SIZEOF_VOID_P;
942 result = coll(target, &buffer);
944 if (buffer.needsFree)
951 /* stackTraceCollector *********************************************************
955 *******************************************************************************/
957 bool stackTraceCollector(void **target, stackTraceBuffer *buffer)
959 static bool stackTraceCollector(void **target, stackTraceBuffer *buffer)
962 stackTraceBuffer *dest;
964 dest = *target = heap_allocate(sizeof(stackTraceBuffer) + buffer->full * sizeof(stacktraceelement), true, 0);
969 memcpy(*target, buffer, sizeof(stackTraceBuffer));
970 memcpy(dest + 1, buffer->start, buffer->full * sizeof(stacktraceelement));
973 dest->size = dest->full;
974 dest->start = (stacktraceelement *) (dest + 1);
980 bool cacao_stacktrace_NormalTrace(void **target)
983 return cacao_stacktrace_fillInStackTrace(target, &stackTraceCollector, NULL);
985 return cacao_stacktrace_fillInStackTrace(target, &stackTraceCollector);
992 static bool classContextCollector(void **target, stackTraceBuffer *buffer)
994 java_objectarray *oa;
995 stacktraceelement *current;
996 stacktraceelement *start;
1001 size = buffer->full;
1004 for (i = 0; i < size; i++)
1005 if (buffer->start[i].method != 0)
1008 start = buffer->start;
1012 if (targetSize > 0) {
1013 if (start->method &&
1014 (start->method->class == class_java_lang_SecurityManager)) {
1020 oa = builtin_anewarray(targetSize, class_java_lang_Class);
1025 for(i = 0, current = start; i < targetSize; i++, current++) {
1026 if (!current->method) {
1031 use_class_as_object(current->method->class);
1033 oa->data[i] = (java_objectheader *) current->method->class;
1043 java_objectarray *cacao_createClassContextArray(void)
1045 java_objectarray *array = NULL;
1048 if (!cacao_stacktrace_fillInStackTrace((void **) &array,
1049 &classContextCollector, NULL))
1051 if (!cacao_stacktrace_fillInStackTrace((void **) &array,
1052 &classContextCollector))
1060 /* stacktrace_classLoaderCollector *********************************************
1064 *******************************************************************************/
1066 static bool stacktrace_classLoaderCollector(void **target,
1067 stackTraceBuffer *buffer)
1069 stacktraceelement *current;
1070 stacktraceelement *start;
1075 size = buffer->full;
1076 start = &(buffer->start[0]);
1078 for(i = 0, current = start; i < size; i++, current++) {
1079 m = current->method;
1084 if (m->class == class_java_security_PrivilegedAction) {
1089 if (m->class->classloader) {
1090 *target = (java_lang_ClassLoader *) m->class->classloader;
1101 /* cacao_currentClassLoader ****************************************************
1105 *******************************************************************************/
1107 java_objectheader *cacao_currentClassLoader(void)
1109 java_objectheader *header = NULL;
1113 if (!cacao_stacktrace_fillInStackTrace((void**)&header,
1114 &stacktrace_classLoaderCollector,
1117 if (!cacao_stacktrace_fillInStackTrace((void**)&header,
1118 &stacktrace_classLoaderCollector))
1126 static bool getStackCollector(void **target, stackTraceBuffer *buffer)
1128 java_objectarray *oa;
1129 java_objectarray *classes;
1130 java_objectarray *methodnames;
1131 java_lang_String *str;
1133 stacktraceelement *current;
1136 /* *result = (java_objectarray **) target; */
1138 size = buffer->full;
1140 oa = builtin_anewarray(2, arrayclass_java_lang_Object);
1145 classes = builtin_anewarray(size, class_java_lang_Class);
1150 methodnames = builtin_anewarray(size, class_java_lang_String);
1155 oa->data[0] = (java_objectheader *) classes;
1156 oa->data[1] = (java_objectheader *) methodnames;
1158 for (i = 0, current = &(buffer->start[0]); i < size; i++, current++) {
1159 c = current->method->class;
1161 use_class_as_object(c);
1163 classes->data[i] = (java_objectheader *) c;
1164 str = javastring_new(current->method->name);
1169 methodnames->data[i] = (java_objectheader *) str;
1178 java_objectarray *cacao_getStackForVMAccessController(void)
1180 java_objectarray *result = NULL;
1183 if (!cacao_stacktrace_fillInStackTrace((void **) &result,
1184 &getStackCollector,NULL))
1186 if (!cacao_stacktrace_fillInStackTrace((void **) &result,
1187 &getStackCollector))
1195 /* stacktrace_dump_trace *******************************************************
1197 This method is call from signal_handler_sigusr1 to dump the
1198 stacktrace of the current thread to stdout.
1200 *******************************************************************************/
1202 void stacktrace_dump_trace(void)
1204 stackTraceBuffer *buffer;
1207 /* get thread stackframeinfo */
1209 info = &THREADINFO->_stackframeinfo;
1211 /* fill stackframeinfo structure */
1213 tmp.oldThreadspecificHeadValue = *info;
1214 tmp.addressOfThreadspecificHead = info;
1217 tmp.ra = _mc->gregs[REG_RIP];
1222 /* generate stacktrace */
1224 cacao_stacktrace_NormalTrace((void **) &buffer);
1226 /* print stacktrace */
1229 stacktrace_print_trace(buffer);
1232 puts("\t<<No stacktrace available>>");
1238 /* stacktrace_print_trace ******************************************************
1240 Print the stacktrace of a given stackTraceBuffer with CACAO intern
1241 methods (no Java help). This method is used by
1242 stacktrace_dump_trace and builtin_trace_exception.
1244 *******************************************************************************/
1246 void stacktrace_print_trace(stackTraceBuffer *stb)
1248 stacktraceelement *ste;
1254 for (i = 0; i < stb->size; i++, ste++) {
1258 utf_display_classname(m->class->name);
1260 utf_display(m->name);
1261 utf_display(m->descriptor);
1263 if (m->flags & ACC_NATIVE) {
1264 puts("(Native Method)");
1268 utf_display(m->class->sourcefile);
1269 printf(":%d)\n", (u4) ste->linenumber);
1273 /* just to be sure */
1280 * These are local overrides for various environment variables in Emacs.
1281 * Please do not remove this and leave it at the end of the file, where
1282 * Emacs will automagically detect them.
1283 * ---------------------------------------------------------------------
1286 * indent-tabs-mode: t