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 3244 2005-09-21 14:58:47Z twisti $
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*);
81 #define BLOCK_INITIALSIZE 40
82 #define BLOCK_SIZEINCREMENT 40
85 /* global variables ***********************************************************/
87 #if defined(USE_THREADS)
88 #define STACKFRAMEINFO (stackframeinfo **) (&THREADINFO->_stackframeinfo)
90 THREADSPECIFIC stackframeinfo *_no_threads_stackframeinfo = NULL;
92 #define STACKFRAMEINFO (&_no_threads_stackframeinfo)
96 /* stacktrace_create_stackframeinfo ********************************************
98 Creates an stackframe info structure for inline code in the
101 *******************************************************************************/
103 #if defined(ENABLE_INTRP)
104 void stacktrace_create_stackframeinfo(stackframeinfo *sfi, u1 *pv,
105 u1 *sp, functionptr ra)
107 stackframeinfo **psfi;
110 /* get current stackframe info pointer */
112 psfi = STACKFRAMEINFO;
114 /* if we don't have pv handy */
117 pv = (u1 *) (ptrint) codegen_findmethod(ra);
119 /* get methodinfo pointer from data segment */
121 m = *((methodinfo **) (pv + MethodPointer));
123 /* fill new stackframe info structure */
131 /* xpc is the same as ra, but is required in fillInStackTrace */
135 /* store new stackframe info pointer */
139 #endif /* defined(ENABLE_INTRP) */
141 /* stacktrace_create_inline_stackframeinfo *************************************
143 Creates an stackframe info structure for an inline exception stub.
145 *******************************************************************************/
147 void stacktrace_create_inline_stackframeinfo(stackframeinfo *sfi, u1 *pv,
148 u1 *sp, functionptr ra,
151 stackframeinfo **psfi;
153 /* get current stackframe info pointer */
155 psfi = STACKFRAMEINFO;
157 #if defined(ENABLE_INTRP)
159 /* if we don't have pv handy */
162 pv = (u1 *) (ptrint) codegen_findmethod(ra);
167 /* fill new stackframe info structure */
176 /* store new stackframe info pointer */
182 /* stacktrace_create_extern_stackframeinfo *************************************
184 Creates an stackframe info structure for an extern exception
185 (hardware or assembler).
187 *******************************************************************************/
189 void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv,
190 u1 *sp, functionptr ra,
193 stackframeinfo **psfi;
194 #if !defined(__I386__) && !defined(__X86_64__)
199 /* get current stackframe info pointer */
201 psfi = STACKFRAMEINFO;
203 /* sometimes we don't have pv handy (e.g. in asmpart.S:
204 L_asm_call_jit_compiler_exception or in the interpreter). */
207 pv = (u1 *) (ptrint) codegen_findmethod(ra);
209 #if defined(ENABLE_INTRP)
210 /* When using the interpreter, we pass RA to the function. */
214 # if defined(__I386__) || defined(__X86_64__)
215 /* On i386 and x86_64 we always have to get the return address
218 framesize = *((u4 *) (pv + FrameSize));
220 ra = md_stacktrace_get_returnaddress(sp, framesize);
222 /* If the method is a non-leaf function, we need to get the return
223 address from the stack. For leaf functions the return address
224 is set correctly. This makes the assembler and the signal
225 handler code simpler. */
227 isleafmethod = *((s4 *) (pv + IsLeaf));
230 framesize = *((u4 *) (pv + FrameSize));
232 ra = md_stacktrace_get_returnaddress(sp, framesize);
235 #if defined(ENABLE_INTRP)
239 /* fill new stackframe info structure */
248 /* store new stackframe info pointer */
254 /* stacktrace_create_native_stackframeinfo *************************************
256 Creates a stackframe info structure for a native stub.
258 *******************************************************************************/
260 void stacktrace_create_native_stackframeinfo(stackframeinfo *sfi, u1 *pv,
261 u1 *sp, functionptr ra)
263 stackframeinfo **psfi;
266 /* get methodinfo pointer from data segment */
268 m = *((methodinfo **) (pv + MethodPointer));
270 /* get current stackframe info pointer */
272 psfi = STACKFRAMEINFO;
274 /* fill new stackframe info structure */
283 /* store new stackframe info pointer */
289 /* stacktrace_remove_stackframeinfo ********************************************
293 *******************************************************************************/
295 void stacktrace_remove_stackframeinfo(stackframeinfo *sfi)
297 stackframeinfo **psfi;
299 /* get current stackframe info pointer */
301 psfi = STACKFRAMEINFO;
303 /* restore the old pointer */
309 /* stacktrace_inline_arithmeticexception ***************************************
311 Creates an ArithemticException for inline stub.
313 *******************************************************************************/
315 java_objectheader *stacktrace_inline_arithmeticexception(u1 *pv, u1 *sp,
320 java_objectheader *o;
322 /* create stackframeinfo */
324 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
326 /* create exception */
328 o = new_arithmeticexception();
330 /* remove stackframeinfo */
332 stacktrace_remove_stackframeinfo(&sfi);
338 /* stacktrace_inline_arrayindexoutofboundsexception ****************************
340 Creates an ArrayIndexOutOfBoundsException for inline stub.
342 *******************************************************************************/
344 java_objectheader *stacktrace_inline_arrayindexoutofboundsexception(u1 *pv,
351 java_objectheader *o;
353 /* create stackframeinfo */
355 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
357 /* create exception */
359 o = new_arrayindexoutofboundsexception(index);
361 /* remove stackframeinfo */
363 stacktrace_remove_stackframeinfo(&sfi);
369 /* stacktrace_inline_arraystoreexception ***************************************
371 Creates an ArrayStoreException for inline stub.
373 *******************************************************************************/
375 java_objectheader *stacktrace_inline_arraystoreexception(u1 *pv, u1 *sp,
380 java_objectheader *o;
382 /* create stackframeinfo */
384 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
386 /* create exception */
388 o = new_arraystoreexception();
390 /* remove stackframeinfo */
392 stacktrace_remove_stackframeinfo(&sfi);
398 /* stacktrace_inline_classcastexception ****************************************
400 Creates an ClassCastException for inline stub.
402 *******************************************************************************/
404 java_objectheader *stacktrace_inline_classcastexception(u1 *pv, u1 *sp,
409 java_objectheader *o;
411 /* create stackframeinfo */
413 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
415 /* create exception */
417 o = new_classcastexception();
419 /* remove stackframeinfo */
421 stacktrace_remove_stackframeinfo(&sfi);
427 /* stacktrace_inline_negativearraysizeexception ********************************
429 Creates an NegativeArraySizeException for inline stub.
431 *******************************************************************************/
433 java_objectheader *stacktrace_inline_negativearraysizeexception(u1 *pv, u1 *sp,
438 java_objectheader *o;
440 /* create stackframeinfo */
442 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
444 /* create exception */
446 o = new_negativearraysizeexception();
448 /* remove stackframeinfo */
450 stacktrace_remove_stackframeinfo(&sfi);
456 /* stacktrace_inline_nullpointerexception **************************************
458 Creates an NullPointerException for inline stub.
460 *******************************************************************************/
462 java_objectheader *stacktrace_inline_nullpointerexception(u1 *pv, u1 *sp,
467 java_objectheader *o;
469 /* create stackframeinfo */
471 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
473 /* create exception */
475 o = new_nullpointerexception();
477 /* remove stackframeinfo */
479 stacktrace_remove_stackframeinfo(&sfi);
485 /* stacktrace_hardware_arithmeticexception *************************************
487 Creates an ArithemticException for inline stub.
489 *******************************************************************************/
491 java_objectheader *stacktrace_hardware_arithmeticexception(u1 *pv, u1 *sp,
496 java_objectheader *o;
498 /* create stackframeinfo */
500 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
502 /* create exception */
504 o = new_arithmeticexception();
506 /* remove stackframeinfo */
508 stacktrace_remove_stackframeinfo(&sfi);
514 /* stacktrace_hardware_nullpointerexception ************************************
516 Creates an NullPointerException for the SIGSEGV signal handler.
518 *******************************************************************************/
520 java_objectheader *stacktrace_hardware_nullpointerexception(u1 *pv, u1 *sp,
525 java_objectheader *o;
527 /* create stackframeinfo */
529 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
531 /* create exception */
533 o = new_nullpointerexception();
535 /* remove stackframeinfo */
537 stacktrace_remove_stackframeinfo(&sfi);
543 /* stacktrace_inline_fillInStackTrace ******************************************
545 Fills in the correct stacktrace into an existing exception object
546 (this one is for inline exception stubs).
548 *******************************************************************************/
550 java_objectheader *stacktrace_inline_fillInStackTrace(u1 *pv, u1 *sp,
555 java_objectheader *o;
558 /* create stackframeinfo */
560 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
566 /* clear exception */
568 *exceptionptr = NULL;
570 /* resolve methodinfo pointer from exception object */
572 m = class_resolvemethod(o->vftbl->class,
573 utf_fillInStackTrace,
574 utf_void__java_lang_Throwable);
578 asm_calljavafunction(m, o, NULL, NULL, NULL);
580 /* remove stackframeinfo */
582 stacktrace_remove_stackframeinfo(&sfi);
588 /* addEntry ********************************************************************
592 *******************************************************************************/
594 static void addEntry(stackTraceBuffer *buffer, methodinfo *method, u2 line)
596 if (buffer->size > buffer->full) {
597 stacktraceelement *tmp = &(buffer->start[buffer->full]);
599 tmp->method = method;
600 tmp->linenumber = line;
601 buffer->full = buffer->full + 1;
604 stacktraceelement *newBuffer;
607 (stacktraceelement *) malloc((buffer->size + BLOCK_SIZEINCREMENT) *
608 sizeof(stacktraceelement));
610 if (newBuffer == 0) {
611 log_text("OOM during stacktrace creation");
615 memcpy(newBuffer, buffer->start, buffer->size * sizeof(stacktraceelement));
616 if (buffer->needsFree)
619 buffer->start = newBuffer;
620 buffer->size = buffer->size + BLOCK_SIZEINCREMENT;
621 buffer->needsFree = 1;
623 addEntry(buffer, method, line);
628 /* stacktrace_fillInStackTrace_methodRecursive *********************************
632 *******************************************************************************/
634 static bool stacktrace_fillInStackTrace_methodRecursive(stackTraceBuffer *buffer,
636 lineNumberTableEntry *lntentry,
641 lineNumberTableEntryInlineBegin *lntinline;
644 /* find the line number for the specified pc (going backwards) */
646 for (; lntsize > 0; lntsize--, lntentry--) {
647 /* did we reach the current line? */
649 if (pc >= lntentry->pc) {
650 /* check for special inline entries */
652 switch (lntentry->line) {
654 /* XXX TWISTI we have to think about this inline stuff again */
656 case -1: /* begin of inlined method */
657 lntinline = (lineNumberTableEntryInlineBegin *) (--lntentry);
659 lntsize--; lntsize--;
660 if (stacktrace_fillInStackTrace_methodRecursive(buffer,
666 addEntry(buffer, m, ilStart->lineNrOuter);
672 case -2: /* end of inlined method */
674 *entriesAhead = ahead;
680 addEntry(buffer, m, lntentry->line);
686 /* check if we are before the actual JIT code */
688 if ((ptrint) pc < (ptrint) m->entrypoint) {
689 dolog("Current pc before start of code: %p < %p", pc, m->entrypoint);
693 /* otherwise just add line 0 */
695 addEntry(buffer, m, 0);
701 /* stacktrace_fillInStackTrace_method ******************************************
705 *******************************************************************************/
707 static void stacktrace_fillInStackTrace_method(stackTraceBuffer *buffer,
708 methodinfo *method, u1 *pv,
711 ptrint lntsize; /* size of line number table */
712 u1 *lntstart; /* start of line number table */
713 lineNumberTableEntry *lntentry; /* points to last entry in the table */
715 /* get size of line number table */
717 lntsize = *((ptrint *) (pv + LineNumberTableSize));
718 lntstart = *((u1 **) (pv + LineNumberTableStart));
720 /* subtract the size of the line number entry of the structure, since the */
721 /* line number table start points to the pc */
723 lntentry = (lineNumberTableEntry *) (lntstart - SIZEOF_VOID_P);
726 /* this happens when an exception is thrown in the native stub */
728 addEntry(buffer, method, 0);
731 if (!stacktrace_fillInStackTrace_methodRecursive(buffer,
736 log_text("Trace point not found in suspected method");
743 /* cacao_stacktrace_fillInStackTrace *******************************************
747 *******************************************************************************/
749 static bool cacao_stacktrace_fillInStackTrace(void **target,
750 CacaoStackTraceCollector coll)
752 stacktraceelement primaryBlock[BLOCK_INITIALSIZE*sizeof(stacktraceelement)];
753 stackTraceBuffer buffer;
763 /* prevent compiler warnings */
769 /* In most cases this should be enough -> one malloc less. I don't think */
770 /* temporary data should be allocated with the GC, only the result. */
772 buffer.needsFree = 0;
773 buffer.start = primaryBlock;
774 buffer.size = BLOCK_INITIALSIZE; /* *sizeof(stacktraceelement); */
777 /* the first element in the stackframe chain must always be a native */
778 /* stackframeinfo (VMThrowable.fillInStackTrace is a native function) */
780 sfi = *STACKFRAMEINFO;
787 #define PRINTMETHODS 0
790 printf("\n\nfillInStackTrace start:\n");
793 /* loop while we have a method pointer (asm_calljavafunction has NULL) or */
794 /* there is a stackframeinfo in the chain */
799 /* m == NULL should only happen for the first time and inline */
800 /* stackframe infos, like from the exception stubs or the patcher */
804 /* for native stub stackframe infos, pv is always NULL */
806 if (sfi->pv == NULL) {
807 /* get methodinfo, sp and ra from the current stackframe info */
810 sp = sfi->sp; /* sp of parent Java function */
814 addEntry(&buffer, m, 0);
817 utf_display_classname(m->class->name);
819 utf_display(m->name);
820 utf_display(m->descriptor);
821 printf(": native stub\n");
823 /* this is an native stub stackframe info, so we can get the */
824 /* parent pv from the return address (ICMD_INVOKE*) */
826 pv = (u1 *) (ptrint) codegen_findmethod(ra);
828 /* get methodinfo pointer from parent data segment */
830 m = *((methodinfo **) (pv + MethodPointer));
833 /* Inline stackframe infos are special: they have a xpc of */
834 /* the actual exception position and the return address saved */
835 /* since an inline stackframe info can also be in a leaf */
836 /* method (no return address saved on stack!!!). */
837 /* ATTENTION: This one is also for hardware exceptions!!! */
839 /* get methodinfo, sp and ra from the current stackframe info */
841 m = sfi->method; /* m == NULL */
842 pv = sfi->pv; /* pv of parent Java function */
843 sp = sfi->sp; /* sp of parent Java function */
844 ra = sfi->ra; /* ra of parent Java function */
845 xpc = sfi->xpc; /* actual exception position */
848 printf("NULL: inline stub\n");
851 /* get methodinfo from current Java method */
853 m = *((methodinfo **) (pv + MethodPointer));
855 /* if m == NULL, this is a asm_calljavafunction call */
859 utf_display_classname(m->class->name);
861 utf_display(m->name);
862 utf_display(m->descriptor);
863 printf(": inline stub parent\n");
866 #if defined(ENABLE_INTRP)
870 /* add it to the stacktrace */
872 stacktrace_fillInStackTrace_method(&buffer, m, pv,
873 (u1 *) ((ptrint) xpc));
875 /* get the current stack frame size */
877 framesize = *((u4 *) (pv + FrameSize));
879 /* set stack pointer to stackframe of parent Java */
880 /* function of the current Java function */
882 #if defined(__I386__) || defined (__X86_64__)
883 sp += framesize + SIZEOF_VOID_P;
888 /* get data segment and methodinfo pointer from parent */
891 pv = (u1 *) (ptrint) codegen_findmethod(ra);
892 m = *((methodinfo **) (pv + MethodPointer));
894 #if defined(ENABLE_INTRP)
900 /* get previous stackframeinfo in the chain */
906 utf_display_classname(m->class->name);
908 utf_display(m->name);
909 utf_display(m->descriptor);
913 /* JIT method found, add it to the stacktrace (we subtract 1 from */
914 /* the return address since it points the the instruction after */
917 stacktrace_fillInStackTrace_method(&buffer, m, pv,
918 (u1 *) ((ptrint) ra) - 1);
920 /* get the current stack frame size */
922 framesize = *((u4 *) (pv + FrameSize));
924 /* get return address of current stack frame */
926 ra = md_stacktrace_get_returnaddress(sp, framesize);
928 /* get data segment and methodinfo pointer from parent method */
930 pv = (u1 *) (ptrint) codegen_findmethod(ra);
931 m = *((methodinfo **) (pv + MethodPointer));
935 #if defined(ENABLE_INTRP)
937 sp = *(u1 **)(sp - framesize);
941 #if defined(__I386__) || defined (__X86_64__)
942 sp += framesize + SIZEOF_VOID_P;
951 result = coll(target, &buffer);
953 if (buffer.needsFree)
960 /* stackTraceCollector *********************************************************
964 *******************************************************************************/
966 static bool stackTraceCollector(void **target, stackTraceBuffer *buffer)
968 stackTraceBuffer *dest;
970 dest = *target = heap_allocate(sizeof(stackTraceBuffer) + buffer->full * sizeof(stacktraceelement), true, 0);
975 memcpy(*target, buffer, sizeof(stackTraceBuffer));
976 memcpy(dest + 1, buffer->start, buffer->full * sizeof(stacktraceelement));
979 dest->size = dest->full;
980 dest->start = (stacktraceelement *) (dest + 1);
986 bool cacao_stacktrace_NormalTrace(void **target)
988 return cacao_stacktrace_fillInStackTrace(target, &stackTraceCollector);
993 static bool classContextCollector(void **target, stackTraceBuffer *buffer)
995 java_objectarray *oa;
996 stacktraceelement *current;
997 stacktraceelement *start;
1002 size = buffer->full;
1005 for (i = 0; i < size; i++)
1006 if (buffer->start[i].method != 0)
1009 start = buffer->start;
1013 if (targetSize > 0) {
1014 if (start->method &&
1015 (start->method->class == class_java_lang_SecurityManager)) {
1021 oa = builtin_anewarray(targetSize, class_java_lang_Class);
1026 for(i = 0, current = start; i < targetSize; i++, current++) {
1027 if (!current->method) {
1032 use_class_as_object(current->method->class);
1034 oa->data[i] = (java_objectheader *) current->method->class;
1044 java_objectarray *cacao_createClassContextArray(void)
1046 java_objectarray *array = NULL;
1048 if (!cacao_stacktrace_fillInStackTrace((void **) &array,
1049 &classContextCollector))
1056 /* stacktrace_classLoaderCollector *********************************************
1060 *******************************************************************************/
1062 static bool stacktrace_classLoaderCollector(void **target,
1063 stackTraceBuffer *buffer)
1065 stacktraceelement *current;
1066 stacktraceelement *start;
1071 size = buffer->full;
1072 start = &(buffer->start[0]);
1074 for(i = 0, current = start; i < size; i++, current++) {
1075 m = current->method;
1080 if (m->class == class_java_security_PrivilegedAction) {
1085 if (m->class->classloader) {
1086 *target = (java_lang_ClassLoader *) m->class->classloader;
1097 /* cacao_currentClassLoader ****************************************************
1101 *******************************************************************************/
1103 java_objectheader *cacao_currentClassLoader(void)
1105 java_objectheader *header = NULL;
1107 if (!cacao_stacktrace_fillInStackTrace((void**)&header,
1108 &stacktrace_classLoaderCollector))
1115 static bool callingMethodCollector(void **target, stackTraceBuffer *buffer)
1117 if (buffer->full > 2)
1118 *target = buffer->start[2].method;
1126 methodinfo *cacao_callingMethod(void)
1130 if (!cacao_stacktrace_fillInStackTrace((void **) &method,
1131 &callingMethodCollector))
1138 static bool getStackCollector(void **target, stackTraceBuffer *buffer)
1140 java_objectarray *oa;
1141 java_objectarray *classes;
1142 java_objectarray *methodnames;
1143 java_lang_String *str;
1145 stacktraceelement *current;
1148 /* *result = (java_objectarray **) target; */
1150 size = buffer->full;
1152 oa = builtin_anewarray(2, arrayclass_java_lang_Object);
1157 classes = builtin_anewarray(size, class_java_lang_Class);
1162 methodnames = builtin_anewarray(size, class_java_lang_String);
1167 oa->data[0] = (java_objectheader *) classes;
1168 oa->data[1] = (java_objectheader *) methodnames;
1170 for (i = 0, current = &(buffer->start[0]); i < size; i++, current++) {
1171 c = current->method->class;
1173 use_class_as_object(c);
1175 classes->data[i] = (java_objectheader *) c;
1176 str = javastring_new(current->method->name);
1181 methodnames->data[i] = (java_objectheader *) str;
1190 java_objectarray *cacao_getStackForVMAccessController(void)
1192 java_objectarray *result = NULL;
1194 if (!cacao_stacktrace_fillInStackTrace((void **) &result,
1195 &getStackCollector))
1202 /* stacktrace_dump_trace *******************************************************
1204 This method is call from signal_handler_sigusr1 to dump the
1205 stacktrace of the current thread to stdout.
1207 *******************************************************************************/
1209 void stacktrace_dump_trace(void)
1211 stackTraceBuffer *buffer;
1212 stacktraceelement *element;
1217 /* get thread stackframeinfo */
1219 info = &THREADINFO->_stackframeinfo;
1221 /* fill stackframeinfo structure */
1223 tmp.oldThreadspecificHeadValue = *info;
1224 tmp.addressOfThreadspecificHead = info;
1227 tmp.ra = _mc->gregs[REG_RIP];
1232 /* generate stacktrace */
1234 cacao_stacktrace_NormalTrace((void **) &buffer);
1236 /* print stacktrace */
1239 element = buffer->start;
1241 for (i = 0; i < buffer->size; i++, element++) {
1242 m = element->method;
1245 utf_display_classname(m->class->name);
1247 utf_display(m->name);
1248 utf_display(m->descriptor);
1250 if (m->flags & ACC_NATIVE) {
1251 printf("(Native Method)\n");
1255 utf_display(m->class->sourcefile);
1256 printf(":%d)\n", (u4) element->linenumber);
1268 * These are local overrides for various environment variables in Emacs.
1269 * Please do not remove this and leave it at the end of the file, where
1270 * Emacs will automagically detect them.
1271 * ---------------------------------------------------------------------
1274 * indent-tabs-mode: t