-/* vm/jit/stacktrace.c
+/* src/vm/jit/stacktrace.c - machine independet stacktrace system
Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
Authors: Joseph Wenninger
- $Id: stacktrace.c 2430 2005-05-03 19:25:52Z twisti $
+ Changes: Christian Thalinger
+
+ $Id: stacktrace.c 3540 2005-11-03 20:33:20Z twisti $
*/
+#include <assert.h>
#include <stdlib.h>
#include <string.h>
-#include "asmoffsets.h"
+#include "config.h"
+
#include "mm/boehm.h"
#include "native/native.h"
+
#include "vm/global.h" /* required here for native includes */
#include "native/include/java_lang_ClassLoader.h"
+
#include "toolbox/logging.h"
#include "vm/builtin.h"
#include "vm/class.h"
+#include "vm/exceptions.h"
+#include "vm/loader.h"
+#include "vm/options.h"
+#include "vm/stringlocal.h"
#include "vm/tables.h"
+#include "vm/jit/asmpart.h"
#include "vm/jit/codegen.inc.h"
-#include "vm/loader.h"
-
-#undef JWDEBUG
+#include "vm/jit/methodheader.h"
-/*JoWenn: simplify collectors (trace doesn't contain internal methods)*/
-/* the line number is only u2, but to avoid alignment problems it is made the same size as a native
- pointer. In the structures where this is used, values of -1 or -2 have a special meainging, so
- if java bytecode is ever extended to support more than 65535 lines/file, this could will have to
- be changed.*/
+/* lineNumberTableEntry *******************************************************/
-#if defined(_ALPHA_) || defined(__X86_64__)
- #define LineNumber u8
-#else
- #define LineNumber u4
-#endif
+/* Keep the type of line the same as the pointer type, otherwise we run into */
+/* alignment troubles (like on MIPS64). */
typedef struct lineNumberTableEntry {
-/* The special value of -1 means that a inlined function starts, a value of -2 means that an inlined function ends*/
- LineNumber lineNr;
- u1 *pc;
+ ptrint line;
+ u1 *pc;
} lineNumberTableEntry;
+
typedef struct lineNumberTableEntryInlineBegin {
-/*this should have the same layout and size as the lineNumberTableEntry*/
- LineNumber lineNrOuter;
+ /* this should have the same layout and size as the lineNumberTableEntry */
+ ptrint lineNrOuter;
methodinfo *method;
} lineNumberTableEntryInlineBegin;
-typedef void(*CacaoStackTraceCollector)(void **,stackTraceBuffer*);
+typedef bool(*CacaoStackTraceCollector)(void **, stackTraceBuffer*);
#define BLOCK_INITIALSIZE 40
#define BLOCK_SIZEINCREMENT 40
-static void addEntry(stackTraceBuffer* buffer,methodinfo*method ,LineNumber line) {
- if (buffer->size>buffer->full) {
- stacktraceelement *tmp=&(buffer->start[buffer->full]);
- tmp->method=method;
- tmp->linenumber=line;
- buffer->full = buffer->full + 1;
-#ifdef JWDEBUG
- log_text("addEntry (stacktrace):");
- printf("method %p\n",method);
- if (method) printf("method->name %p\n",method->name);
- if (method) utf_display(method->name); else printf("Native");
- if (method) {printf("\n");utf_display(method->class->name);}
- printf("\nnext buffer item %d\nLine:%ld\n",buffer->full,line);
+
+/* global variables ***********************************************************/
+
+#if !defined(USE_THREADS)
+stackframeinfo *_no_threads_stackframeinfo = NULL;
#endif
+
+
+/* stacktrace_create_stackframeinfo ********************************************
+
+ Creates an stackframe info structure for inline code in the
+ interpreter.
+
+*******************************************************************************/
+
+#if defined(ENABLE_INTRP)
+void stacktrace_create_stackframeinfo(stackframeinfo *sfi, u1 *pv,
+ u1 *sp, functionptr ra)
+{
+ stackframeinfo **psfi;
+ methodinfo *m;
+
+ /* get current stackframe info pointer */
+
+ psfi = STACKFRAMEINFO;
+
+ /* if we don't have pv handy */
+
+ if (pv == NULL)
+ pv = (u1 *) (ptrint) codegen_findmethod(ra);
+
+ /* get methodinfo pointer from data segment */
+
+ m = *((methodinfo **) (pv + MethodPointer));
+
+ /* fill new stackframe info structure */
+
+ sfi->prev = *psfi;
+ sfi->method = m;
+ sfi->pv = pv;
+ sfi->sp = sp;
+ sfi->ra = ra;
+
+ /* xpc is the same as ra, but is required in fillInStackTrace */
+
+ sfi->xpc = ra;
+
+ /* store new stackframe info pointer */
+
+ *psfi = sfi;
+}
+#endif /* defined(ENABLE_INTRP) */
+
+/* stacktrace_create_inline_stackframeinfo *************************************
+
+ Creates an stackframe info structure for an inline exception stub.
+
+*******************************************************************************/
+
+void stacktrace_create_inline_stackframeinfo(stackframeinfo *sfi, u1 *pv,
+ u1 *sp, functionptr ra,
+ functionptr xpc)
+{
+ stackframeinfo **psfi;
+
+ /* get current stackframe info pointer */
+
+ psfi = STACKFRAMEINFO;
+
+#if defined(ENABLE_INTRP)
+ if (opt_intrp) {
+ /* if we don't have pv handy */
+
+ if (pv == NULL)
+ pv = (u1 *) (ptrint) codegen_findmethod(ra);
+
+ }
+#endif
+
+ /* fill new stackframe info structure */
+
+ sfi->prev = *psfi;
+ sfi->method = NULL;
+ sfi->pv = pv;
+ sfi->sp = sp;
+ sfi->ra = ra;
+ sfi->xpc = xpc;
+
+ /* store new stackframe info pointer */
+
+ *psfi = sfi;
+}
+
+
+/* stacktrace_create_extern_stackframeinfo *************************************
+
+ Creates an stackframe info structure for an extern exception
+ (hardware or assembler).
+
+*******************************************************************************/
+
+void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv,
+ u1 *sp, functionptr ra,
+ functionptr xpc)
+{
+ stackframeinfo **psfi;
+#if !defined(__I386__) && !defined(__X86_64__)
+ bool isleafmethod;
+#endif
+ s4 framesize;
+
+ /* get current stackframe info pointer */
+
+ psfi = STACKFRAMEINFO;
+
+ /* sometimes we don't have pv handy (e.g. in asmpart.S:
+ L_asm_call_jit_compiler_exception or in the interpreter). */
+
+ if (pv == NULL)
+ pv = (u1 *) (ptrint) codegen_findmethod(ra);
+
+#if defined(ENABLE_INTRP)
+ /* When using the interpreter, we pass RA to the function. */
+
+ if (!opt_intrp) {
+#endif
+# if defined(__I386__) || defined(__X86_64__)
+ /* On i386 and x86_64 we always have to get the return address
+ from the stack. */
+
+ framesize = *((u4 *) (pv + FrameSize));
+
+ ra = md_stacktrace_get_returnaddress(sp, framesize);
+# else
+ /* If the method is a non-leaf function, we need to get the return
+ address from the stack. For leaf functions the return address
+ is set correctly. This makes the assembler and the signal
+ handler code simpler. */
+
+ isleafmethod = *((s4 *) (pv + IsLeaf));
+
+ if (!isleafmethod) {
+ framesize = *((u4 *) (pv + FrameSize));
+
+ ra = md_stacktrace_get_returnaddress(sp, framesize);
+ }
+# endif
+#if defined(ENABLE_INTRP)
+ }
+#endif
+
+ /* fill new stackframe info structure */
+
+ sfi->prev = *psfi;
+ sfi->method = NULL;
+ sfi->pv = pv;
+ sfi->sp = sp;
+ sfi->ra = ra;
+ sfi->xpc = xpc;
+
+ /* store new stackframe info pointer */
+
+ *psfi = sfi;
+}
+
+
+/* stacktrace_create_native_stackframeinfo *************************************
+
+ Creates a stackframe info structure for a native stub.
+
+*******************************************************************************/
+
+void stacktrace_create_native_stackframeinfo(stackframeinfo *sfi, u1 *pv,
+ u1 *sp, functionptr ra)
+{
+ stackframeinfo **psfi;
+ methodinfo *m;
+
+ /* get methodinfo pointer from data segment */
+
+ m = *((methodinfo **) (pv + MethodPointer));
+
+ /* get current stackframe info pointer */
+
+ psfi = STACKFRAMEINFO;
+
+ /* fill new stackframe info structure */
+
+ sfi->prev = *psfi;
+ sfi->method = m;
+ sfi->pv = NULL;
+ sfi->sp = sp;
+ sfi->ra = ra;
+ sfi->xpc = NULL;
+
+ /* store new stackframe info pointer */
+
+ *psfi = sfi;
+}
+
+
+/* stacktrace_remove_stackframeinfo ********************************************
+
+ XXX
+
+*******************************************************************************/
+
+void stacktrace_remove_stackframeinfo(stackframeinfo *sfi)
+{
+ stackframeinfo **psfi;
+
+ /* get current stackframe info pointer */
+
+ psfi = STACKFRAMEINFO;
+
+ /* restore the old pointer */
+
+ *psfi = sfi->prev;
+}
+
+
+/* stacktrace_inline_arithmeticexception ***************************************
+
+ Creates an ArithemticException for inline stub.
+
+*******************************************************************************/
+
+java_objectheader *stacktrace_inline_arithmeticexception(u1 *pv, u1 *sp,
+ functionptr ra,
+ functionptr xpc)
+{
+ stackframeinfo sfi;
+ java_objectheader *o;
+
+ /* create stackframeinfo */
+
+ stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
+
+ /* create exception */
+
+ o = new_arithmeticexception();
+
+ /* remove stackframeinfo */
+
+ stacktrace_remove_stackframeinfo(&sfi);
+
+ return o;
+}
+
+
+/* stacktrace_inline_arrayindexoutofboundsexception ****************************
+
+ Creates an ArrayIndexOutOfBoundsException for inline stub.
+
+*******************************************************************************/
+
+java_objectheader *stacktrace_inline_arrayindexoutofboundsexception(u1 *pv,
+ u1 *sp,
+ functionptr ra,
+ functionptr xpc,
+ s4 index)
+{
+ stackframeinfo sfi;
+ java_objectheader *o;
+
+ /* create stackframeinfo */
+
+ stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
+
+ /* create exception */
+
+ o = new_arrayindexoutofboundsexception(index);
+
+ /* remove stackframeinfo */
+
+ stacktrace_remove_stackframeinfo(&sfi);
+
+ return o;
+}
+
+
+/* stacktrace_inline_arraystoreexception ***************************************
+
+ Creates an ArrayStoreException for inline stub.
+
+*******************************************************************************/
+
+java_objectheader *stacktrace_inline_arraystoreexception(u1 *pv, u1 *sp,
+ functionptr ra,
+ functionptr xpc)
+{
+ stackframeinfo sfi;
+ java_objectheader *o;
+
+ /* create stackframeinfo */
+
+ stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
+
+ /* create exception */
+
+ o = new_arraystoreexception();
+
+ /* remove stackframeinfo */
+
+ stacktrace_remove_stackframeinfo(&sfi);
+
+ return o;
+}
+
+
+/* stacktrace_inline_classcastexception ****************************************
+
+ Creates an ClassCastException for inline stub.
+
+*******************************************************************************/
+
+java_objectheader *stacktrace_inline_classcastexception(u1 *pv, u1 *sp,
+ functionptr ra,
+ functionptr xpc)
+{
+ stackframeinfo sfi;
+ java_objectheader *o;
+
+ /* create stackframeinfo */
+
+ stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
+
+ /* create exception */
+
+ o = new_classcastexception();
+
+ /* remove stackframeinfo */
+
+ stacktrace_remove_stackframeinfo(&sfi);
+
+ return o;
+}
+
+
+/* stacktrace_inline_nullpointerexception **************************************
+
+ Creates an NullPointerException for inline stub.
+
+*******************************************************************************/
+
+java_objectheader *stacktrace_inline_nullpointerexception(u1 *pv, u1 *sp,
+ functionptr ra,
+ functionptr xpc)
+{
+ stackframeinfo sfi;
+ java_objectheader *o;
+
+ /* create stackframeinfo */
+
+ stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
+
+ /* create exception */
+
+ o = new_nullpointerexception();
+
+ /* remove stackframeinfo */
+
+ stacktrace_remove_stackframeinfo(&sfi);
+
+ return o;
+}
+
+
+/* stacktrace_hardware_arithmeticexception *************************************
+
+ Creates an ArithemticException for inline stub.
+
+*******************************************************************************/
+
+java_objectheader *stacktrace_hardware_arithmeticexception(u1 *pv, u1 *sp,
+ functionptr ra,
+ functionptr xpc)
+{
+ stackframeinfo sfi;
+ java_objectheader *o;
+
+ /* create stackframeinfo */
+
+ stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
+
+ /* create exception */
+
+ o = new_arithmeticexception();
+
+ /* remove stackframeinfo */
+
+ stacktrace_remove_stackframeinfo(&sfi);
+
+ return o;
+}
+
+
+/* stacktrace_hardware_nullpointerexception ************************************
+
+ Creates an NullPointerException for the SIGSEGV signal handler.
+
+*******************************************************************************/
+
+java_objectheader *stacktrace_hardware_nullpointerexception(u1 *pv, u1 *sp,
+ functionptr ra,
+ functionptr xpc)
+{
+ stackframeinfo sfi;
+ java_objectheader *o;
+
+ /* create stackframeinfo */
+
+ stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
+
+ /* create exception */
+
+ o = new_nullpointerexception();
+
+ /* remove stackframeinfo */
+
+ stacktrace_remove_stackframeinfo(&sfi);
+
+ return o;
+}
+
+
+/* stacktrace_inline_fillInStackTrace ******************************************
+
+ Fills in the correct stacktrace into an existing exception object
+ (this one is for inline exception stubs).
+
+*******************************************************************************/
+
+java_objectheader *stacktrace_inline_fillInStackTrace(u1 *pv, u1 *sp,
+ functionptr ra,
+ functionptr xpc)
+{
+ stackframeinfo sfi;
+ java_objectheader *o;
+ methodinfo *m;
+
+ /* create stackframeinfo */
+
+ stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
+
+ /* get exception */
+
+ o = *exceptionptr;
+
+ /* clear exception */
+
+ *exceptionptr = NULL;
+
+ /* resolve methodinfo pointer from exception object */
+
+ m = class_resolvemethod(o->vftbl->class,
+ utf_fillInStackTrace,
+ utf_void__java_lang_Throwable);
+
+ /* call function */
+
+ asm_calljavafunction(m, o, NULL, NULL, NULL);
+
+ /* remove stackframeinfo */
+
+ stacktrace_remove_stackframeinfo(&sfi);
+
+ return o;
+}
+
+
+/* addEntry ********************************************************************
+
+ XXX
+
+*******************************************************************************/
+
+static void addEntry(stackTraceBuffer *buffer, methodinfo *method, u2 line)
+{
+ if (buffer->size > buffer->full) {
+ stacktraceelement *tmp = &(buffer->start[buffer->full]);
+
+ tmp->method = method;
+ tmp->linenumber = line;
+ buffer->full = buffer->full + 1;
+
} else {
stacktraceelement *newBuffer;
- log_text("stacktrace buffer full, resizing");
-
newBuffer =
(stacktraceelement *) malloc((buffer->size + BLOCK_SIZEINCREMENT) *
sizeof(stacktraceelement));
- if (newBuffer==0) panic("OOM during stacktrace creation");
- memcpy(newBuffer,buffer->start,buffer->size*sizeof(stacktraceelement));
- if (buffer->needsFree) free(buffer->start);
- buffer->start=newBuffer;
- buffer->size=buffer->size+BLOCK_SIZEINCREMENT;
- buffer->needsFree=1;
- addEntry(buffer,method,line);
+ if (newBuffer == 0) {
+ log_text("OOM during stacktrace creation");
+ assert(0);
+ }
+
+ memcpy(newBuffer, buffer->start, buffer->size * sizeof(stacktraceelement));
+ if (buffer->needsFree)
+ free(buffer->start);
+
+ buffer->start = newBuffer;
+ buffer->size = buffer->size + BLOCK_SIZEINCREMENT;
+ buffer->needsFree = 1;
+
+ addEntry(buffer, method, line);
}
}
-static int fillInStackTrace_methodRecursive(stackTraceBuffer *buffer,methodinfo
- *method,lineNumberTableEntry *startEntry, lineNumberTableEntry **entry, size_t *entriesAhead,u1 *adress) {
-
- size_t ahead=*entriesAhead;
- lineNumberTableEntry *ent=*entry;
- lineNumberTableEntryInlineBegin *ilStart;
-
- for (;ahead>0;ahead--,ent++) {
- if (adress>=ent->pc) {
- switch (ent->lineNr) {
- case -1: /*begin of inlined method */
- ilStart=(lineNumberTableEntryInlineBegin*)(++ent);
- ent ++;
- ahead--; ahead--;
- if (fillInStackTrace_methodRecursive(buffer,ilStart->method,ent,&ent,&ahead,adress)) {
- addEntry(buffer,method,ilStart->lineNrOuter);
- return 1;
- }
- break;
- case -2: /*end of inlined method*/
- *entry=ent;
- *entriesAhead=ahead;
- return 0;
- break;
- default:
- if (adress==ent->pc) {
- addEntry(buffer,method,ent->lineNr);
- return 1;
- }
- break;
- }
- } else {
- if (adress>startEntry->pc) {
- ent--;
- addEntry(buffer,method,ent->lineNr);
- return 1;
- } else {
-#ifdef JWDEBUG
- printf("trace point: %p\n",adress);
+
+/* stacktrace_fillInStackTrace_methodRecursive *********************************
+
+ XXX
+
+*******************************************************************************/
+
+static bool stacktrace_fillInStackTrace_methodRecursive(stackTraceBuffer *buffer,
+ methodinfo *m,
+ lineNumberTableEntry *lntentry,
+ s4 lntsize,
+ u1 *pc)
+{
+#if 0
+ lineNumberTableEntryInlineBegin *lntinline;
#endif
- panic("trace point before method");
+
+ /* find the line number for the specified pc (going backwards) */
+
+ for (; lntsize > 0; lntsize--, lntentry--) {
+ /* did we reach the current line? */
+
+ if (pc >= lntentry->pc) {
+ /* check for special inline entries */
+
+ switch (lntentry->line) {
+#if 0
+ /* XXX TWISTI we have to think about this inline stuff again */
+
+ case -1: /* begin of inlined method */
+ lntinline = (lineNumberTableEntryInlineBegin *) (--lntentry);
+ lntentry++;
+ lntsize--; lntsize--;
+ if (stacktrace_fillInStackTrace_methodRecursive(buffer,
+ ilStart->method,
+ ent,
+ &ent,
+ &ahead,
+ pc)) {
+ addEntry(buffer, m, ilStart->lineNrOuter);
+
+ return true;
+ }
+ break;
+
+ case -2: /* end of inlined method */
+ *entry = ent;
+ *entriesAhead = ahead;
+ return false;
+ break;
+#endif
+
+ default:
+ addEntry(buffer, m, lntentry->line);
+ return true;
}
}
}
- ent--;
- addEntry(buffer,method,ent->lineNr);
- return 1;
-
+
+ /* check if we are before the actual JIT code */
+
+ if ((ptrint) pc < (ptrint) m->entrypoint) {
+ dolog("Current pc before start of code: %p < %p", pc, m->entrypoint);
+ assert(0);
+ }
+
+ /* otherwise just add line 0 */
+
+ addEntry(buffer, m, 0);
+
+ return true;
}
-static void fillInStackTrace_method(stackTraceBuffer *buffer,methodinfo *method,u1 *dataSeg, u1* adress) {
- size_t lineNumberTableSize=(*((size_t*)(dataSeg+LineNumberTableSize)));
+/* stacktrace_fillInStackTrace_method ******************************************
+
+ XXX
+
+*******************************************************************************/
+
+static void stacktrace_fillInStackTrace_method(stackTraceBuffer *buffer,
+ methodinfo *method, u1 *pv,
+ u1 *pc)
+{
+ ptrint lntsize; /* size of line number table */
+ u1 *lntstart; /* start of line number table */
+ lineNumberTableEntry *lntentry; /* points to last entry in the table */
+
+ /* get size of line number table */
+
+ lntsize = *((ptrint *) (pv + LineNumberTableSize));
+ lntstart = *((u1 **) (pv + LineNumberTableStart));
+
+ /* subtract the size of the line number entry of the structure, since the */
+ /* line number table start points to the pc */
+
+ lntentry = (lineNumberTableEntry *) (lntstart - SIZEOF_VOID_P);
+
+ if (lntsize == 0) {
+ /* this happens when an exception is thrown in the native stub */
+
+ addEntry(buffer, method, 0);
- if ( lineNumberTableSize == 0) {
- /*right now this happens only on
- i386,if the native stub causes an exception in a <clinit> invocation (jowenn)*/
- addEntry(buffer,method,0);
- return;
} else {
- lineNumberTableEntry *ent; /*=(lineNumberTableEntry*) ((*((char**)(dataSeg+LineNumberTableStart))) - (sizeof(lineNumberTableEntry)-sizeof(void*)));*/
- void **calc;
- lineNumberTableEntry *startEntry;
-
- /* printf("dataSeg: %p\n",dataSeg);*/
- calc=(void**)(dataSeg+LineNumberTableStart);
- /* printf("position of line number table start reference in data segment: %p\n",calc);
- printf("line number table start as found in table: %p\n",*calc);*/
- ent=(lineNumberTableEntry *) (((char*)(*calc) - (sizeof(lineNumberTableEntry)-sizeof(void*))));
- /* printf("line number table start as calculated: %p\n",ent);*/
- ent-=(lineNumberTableSize-1);
- startEntry=ent;
- /* printf("line number table real start (bottom end) as calculated(2): %p\n",startEntry);*/
-
- if (!fillInStackTrace_methodRecursive(buffer,method,startEntry,&ent,&lineNumberTableSize,adress)) {
- panic("Trace point not found in suspected method");
+ if (!stacktrace_fillInStackTrace_methodRecursive(buffer,
+ method,
+ lntentry,
+ lntsize,
+ pc)) {
+ log_text("Trace point not found in suspected method");
+ assert(0);
}
}
}
-typedef union {
- u1* u1ptr;
- functionptr funcptr;
- void* voidptr;
-} u1ptr_functionptr_union;
+/* cacao_stacktrace_fillInStackTrace *******************************************
-#define cast_funcptr_u1ptr(dest,src) \
- { u1f.funcptr=src;\
- dest=u1f.u1ptr; }
+ XXX
-#define cast_u1ptr_funcptr(dest,src) \
- { u1f.u1ptr=src;\
- dest=u1f.funcptr; }
+*******************************************************************************/
-void cacao_stacktrace_fillInStackTrace(void **target,CacaoStackTraceCollector coll)
+static bool cacao_stacktrace_fillInStackTrace(void **target,
+ CacaoStackTraceCollector coll)
{
-
- stacktraceelement primaryBlock[BLOCK_INITIALSIZE*sizeof(stacktraceelement)];
- /*In most cases this should be enough -> one malloc less. I don't think temporary data should be
- allocated with the GC, only the result*/
- stackTraceBuffer buffer;
- buffer.needsFree=0;
- buffer.start=primaryBlock;
- buffer.size=BLOCK_INITIALSIZE*sizeof(stacktraceelement);
- buffer.full=0;
-#ifdef JWDEBUG
- log_text("entering cacao_stacktrace_fillInStacktrace");
- {
- int i=0;
- struct native_stackframeinfo *tmpinfo;
- for (tmpinfo=(*(((void**)(builtin_asm_get_stackframeinfo()))));tmpinfo;tmpinfo=tmpinfo->oldThreadspecificHeadValue)
- i++;
- printf("native function depth:%d\n",i);
-
+ stacktraceelement primaryBlock[BLOCK_INITIALSIZE*sizeof(stacktraceelement)];
+ stackTraceBuffer buffer;
+ stackframeinfo *sfi;
+ methodinfo *m;
+ u1 *pv;
+ u1 *sp;
+ u4 framesize;
+ functionptr ra;
+ functionptr xpc;
+ bool result;
+
+ /* prevent compiler warnings */
+
+ pv = NULL;
+ sp = NULL;
+ ra = NULL;
+
+ /* In most cases this should be enough -> one malloc less. I don't think */
+ /* temporary data should be allocated with the GC, only the result. */
+
+ buffer.needsFree = 0;
+ buffer.start = primaryBlock;
+ buffer.size = BLOCK_INITIALSIZE; /* *sizeof(stacktraceelement); */
+ buffer.full = 0;
+
+ /* the first element in the stackframe chain must always be a native */
+ /* stackframeinfo (VMThrowable.fillInStackTrace is a native function) */
+
+ sfi = *STACKFRAMEINFO;
+
+ if (!sfi) {
+ *target = NULL;
+ return true;
}
+
+#define PRINTMETHODS 0
+
+#if PRINTMETHODS
+ printf("\n\nfillInStackTrace start:\n");
+ fflush(stdout);
#endif
- {
- struct native_stackframeinfo *info=(*(((void**)(builtin_asm_get_stackframeinfo()))));
- if (!info) {
- log_text("info ==0");
- *target=0;
- return;
- } else {
- u1 *tmp;
- u1 *dataseg; /*make it byte addressable*/
- methodinfo *currentMethod=0;
- /*void*/ functionptr returnAdress;
- u1* stackPtr;
- u1ptr_functionptr_union u1f;
-
-/* utf_display(info->method->class->name);
- utf_display(info->method->name);*/
-
- while ((currentMethod!=0) || (info!=0)) {
- if (currentMethod==0) { /*some builtin native */
- currentMethod=info->method;
- returnAdress=(functionptr)info->returnToFromNative;
-#ifdef JWDEBUG
- log_text("native");
- printf("return to %p\n",returnAdress);
-#endif
- if (currentMethod) {
-#ifdef JWDEBUG
- log_text("real native (not an internal helper)\n");
- printf("returnaddress %p, methodpointer %p, stackframe begin %p\n",info->returnToFromNative,info->method, info->beginOfJavaStackframe);
-#if 0
- utf_display(currentMethod->class->name);
- utf_display(currentMethod->name);
-#endif
+
+ /* loop while we have a method pointer (asm_calljavafunction has NULL) or */
+ /* there is a stackframeinfo in the chain */
+
+ m = NULL;
+
+ while (m || sfi) {
+ /* m == NULL should only happen for the first time and inline */
+ /* stackframe infos, like from the exception stubs or the patcher */
+ /* wrapper */
+
+ if (m == NULL) {
+ /* for native stub stackframe infos, pv is always NULL */
+
+ if (sfi->pv == NULL) {
+ /* get methodinfo, sp and ra from the current stackframe info */
+
+ m = sfi->method;
+ sp = sfi->sp; /* sp of parent Java function */
+ ra = sfi->ra;
+
+ if (m)
+ addEntry(&buffer, m, 0);
+
+#if PRINTMETHODS
+ utf_display_classname(m->class->name);
+ printf(".");
+ utf_display(m->name);
+ utf_display(m->descriptor);
+ printf(": native stub\n");
+ fflush(stdout);
#endif
- addEntry(&buffer,currentMethod,0);
- }
-#if defined(__ALPHA__)
- if (info->savedpv!=0)
- dataseg=info->savedpv;
- else
- dataseg=codegen_findmethod(returnAdress);
-#elif defined(__I386__) || defined (__X86_64__)
- cast_funcptr_u1ptr(dataseg,codegen_findmethod(returnAdress));
+ /* this is an native stub stackframe info, so we can get the */
+ /* parent pv from the return address (ICMD_INVOKE*) */
+
+ pv = (u1 *) (ptrint) codegen_findmethod(ra);
+
+ /* get methodinfo pointer from parent data segment */
+
+ m = *((methodinfo **) (pv + MethodPointer));
+
+ } else {
+ /* Inline stackframe infos are special: they have a xpc of */
+ /* the actual exception position and the return address saved */
+ /* since an inline stackframe info can also be in a leaf */
+ /* method (no return address saved on stack!!!). */
+ /* ATTENTION: This one is also for hardware exceptions!!! */
+
+ /* get methodinfo, sp and ra from the current stackframe info */
+
+ m = sfi->method; /* m == NULL */
+ pv = sfi->pv; /* pv of parent Java function */
+ sp = sfi->sp; /* sp of parent Java function */
+ ra = sfi->ra; /* ra of parent Java function */
+ xpc = sfi->xpc; /* actual exception position */
+
+#if PRINTMETHODS
+ printf("NULL: inline stub\n");
+ fflush(stdout);
#endif
- currentMethod=(*((methodinfo**)(dataseg+MethodPointer)));
- if (info->beginOfJavaStackframe==0)
- stackPtr=((u1*)info)+sizeof(native_stackframeinfo);
- else
-#if defined(__ALPHA__)
- stackPtr=(u1*)(info->beginOfJavaStackframe);
-#elif defined(__I386__) || defined (__X86_64__)
- stackPtr=(u1*)(info->beginOfJavaStackframe)+sizeof(void*);
+
+ /* get methodinfo from current Java method */
+
+ m = *((methodinfo **) (pv + MethodPointer));
+
+ /* if m == NULL, this is a asm_calljavafunction call */
+
+ if (m != NULL) {
+#if PRINTMETHODS
+ utf_display_classname(m->class->name);
+ printf(".");
+ utf_display(m->name);
+ utf_display(m->descriptor);
+ printf(": inline stub parent\n");
+ fflush(stdout);
#endif
- info=info->oldThreadspecificHeadValue;
- } else { /*method created by jit*/
- u4 frameSize;
-#ifdef JWDEBUG
- log_text("JIT");
+
+#if defined(ENABLE_INTRP)
+ if (!opt_intrp) {
#endif
-#if defined (__ALPHA__)
- if (currentMethod->isleafmethod) {
-#ifdef JWDEBUG
- printf("class.method:%s.%s\n",currentMethod->class->name->text,currentMethod->name->text);
+
+ /* add it to the stacktrace */
+
+ stacktrace_fillInStackTrace_method(&buffer, m, pv,
+ (u1 *) ((ptrint) xpc));
+
+ /* get the current stack frame size */
+
+ framesize = *((u4 *) (pv + FrameSize));
+
+ /* set stack pointer to stackframe of parent Java */
+ /* function of the current Java function */
+
+#if defined(__I386__) || defined (__X86_64__)
+ sp += framesize + SIZEOF_VOID_P;
+#else
+ sp += framesize;
#endif
- panic("How could that happen ??? A leaf method in the middle of a stacktrace ??");
+
+ /* get data segment and methodinfo pointer from parent */
+ /* method */
+
+ pv = (u1 *) (ptrint) codegen_findmethod(ra);
+ m = *((methodinfo **) (pv + MethodPointer));
+
+#if defined(ENABLE_INTRP)
}
-#endif
- /*utf_display(currentMethod->class->name);
- utf_display(currentMethod->name);*/
- cast_funcptr_u1ptr(tmp,returnAdress);
- fillInStackTrace_method(&buffer,currentMethod,dataseg,tmp-1);
- frameSize=*((u4*)(dataseg+FrameSize));
-#if defined(__ALPHA__)
- /* cacao saves the return adress as the first element of the stack frame on alphas*/
- cast_funcptr_u1ptr (dataseg,codegen_findmethod(*((void**)(stackPtr+frameSize-sizeof(void*)))));
- returnAdress=(*((void**)(stackPtr+frameSize-sizeof(void*))));
-#elif defined(__I386__) || defined (__x86_64__)
- /* on i386 the return adress is the first element before the stack frme*/
- cast_u1ptr_funcptr(returnAdress,*((u1**)(stackPtr+frameSize)));
- cast_funcptr_u1ptr(dataseg,codegen_findmethod(returnAdress));
-#endif
-/* printf ("threadrootmethod %p\n",builtin_asm_get_threadrootmethod());
- if (currentMethod==builtin_asm_get_threadrootmethod()) break;*/
- currentMethod=(*((methodinfo**)(dataseg+MethodPointer)));
-#if defined(__ALPHA__)
- stackPtr+=frameSize;
-#elif defined(__I386__) || defined (__x86_64__)
- stackPtr+=frameSize+sizeof(void*);
#endif
}
+#if PRINTMETHODS
+ else {
+ printf("asm_calljavafunction\n");
+ fflush(stdout);
+ }
+#endif
}
-
- if (coll) coll(target,&buffer);
- if (buffer.needsFree) free(buffer.start);
-#ifdef JWDEBUG
- log_text("leaving cacao_stacktrace_fillInStacktrace");
+
+ /* get previous stackframeinfo in the chain */
+
+ sfi = sfi->prev;
+
+ } else {
+#if PRINTMETHODS
+ utf_display_classname(m->class->name);
+ printf(".");
+ utf_display(m->name);
+ utf_display(m->descriptor);
+ printf(": JIT\n");
#endif
- return;
+ /* JIT method found, add it to the stacktrace (we subtract 1 from */
+ /* the return address since it points the the instruction after */
+ /* call) */
+
+ stacktrace_fillInStackTrace_method(&buffer, m, pv,
+ (u1 *) ((ptrint) ra) - 1);
+
+ /* get the current stack frame size */
+
+ framesize = *((u4 *) (pv + FrameSize));
+
+ /* get return address of current stack frame */
+
+ ra = md_stacktrace_get_returnaddress(sp, framesize);
+
+ /* get data segment and methodinfo pointer from parent method */
+
+ pv = (u1 *) (ptrint) codegen_findmethod(ra);
+ m = *((methodinfo **) (pv + MethodPointer));
+
+ /* walk the stack */
+
+#if defined(ENABLE_INTRP)
+ if (opt_intrp)
+ sp = *(u1 **)(sp - framesize);
+ else
+#endif
+ {
+#if defined(__I386__) || defined (__X86_64__)
+ sp += framesize + SIZEOF_VOID_P;
+#else
+ sp += framesize;
+#endif
+ }
}
- /*log_text("\n=========================================================");*/
}
- *target=0;
-#ifdef JWDEBUG
- log_text("leaving(2) cacao_stacktrace_fillInStacktrace");
-#endif
+
+ if (coll)
+ result = coll(target, &buffer);
+ if (buffer.needsFree)
+ free(buffer.start);
+
+ return result;
}
-static
-void stackTraceCollector(void **target, stackTraceBuffer *buffer) {
- stackTraceBuffer *dest=*target=heap_allocate(sizeof(stackTraceBuffer)+buffer->full*sizeof(stacktraceelement),true,0);
- memcpy(*target,buffer,sizeof(stackTraceBuffer));
- memcpy(dest+1,buffer->start,buffer->full*sizeof(stacktraceelement));
+/* stackTraceCollector *********************************************************
+
+ XXX
+
+*******************************************************************************/
- dest->needsFree=0;
- dest->size=dest->full;
- dest->start=(stacktraceelement*)(dest+1);
+static bool stackTraceCollector(void **target, stackTraceBuffer *buffer)
+{
+ stackTraceBuffer *dest;
+
+ dest = *target = heap_allocate(sizeof(stackTraceBuffer) + buffer->full * sizeof(stacktraceelement), true, 0);
+
+ if (!dest)
+ return false;
+
+ memcpy(*target, buffer, sizeof(stackTraceBuffer));
+ memcpy(dest + 1, buffer->start, buffer->full * sizeof(stacktraceelement));
- /*
- if (buffer->full>0) {
- printf("SOURCE BUFFER:%s\n",buffer->start[0].method->name->text);
- printf("DEST BUFFER:%s\n",dest->start[0].method->name->text);
- } else printf("Buffer is empty\n");
- */
+ dest->needsFree = 0;
+ dest->size = dest->full;
+ dest->start = (stacktraceelement *) (dest + 1);
+
+ return true;
}
-void cacao_stacktrace_NormalTrace(void **target) {
- cacao_stacktrace_fillInStackTrace(target,&stackTraceCollector);
+bool cacao_stacktrace_NormalTrace(void **target)
+{
+ return cacao_stacktrace_fillInStackTrace(target, &stackTraceCollector);
}
-static
-void classContextCollector(void **target, stackTraceBuffer *buffer) {
- java_objectarray *tmpArray;
- int i;
- stacktraceelement *current;
- stacktraceelement *start;
- size_t size;
+static bool classContextCollector(void **target, stackTraceBuffer *buffer)
+{
+ java_objectarray *oa;
+ stacktraceelement *current;
+ stacktraceelement *start;
+ size_t size;
size_t targetSize;
+ s4 i;
- size=buffer->full;
- targetSize=0;
- for (i=0;i<size;i++)
- if (buffer->start[i].method!=0) targetSize++;
- start=buffer->start;
+ size = buffer->full;
+ targetSize = 0;
+
+ for (i = 0; i < size; i++)
+ if (buffer->start[i].method != 0)
+ targetSize++;
+
+ start = buffer->start;
start++;
targetSize--;
- if (targetSize > 0) {
- if ((start->method) && (start->method->class== class_java_lang_SecurityManager)) {
- targetSize--;
- start++;
- }
- }
-
- tmpArray = builtin_anewarray(targetSize, class_java_lang_Class);
-
- for(i = 0, current = start; i < targetSize; i++, current++) {
- if (current->method==0) { i--; /*printf("Skipping\n");*/ continue;}
-#ifdef JWDEBUG
- {
- printf("after current->method check\n");
- if (current->method->class==0) printf("Error method defining class i null\n");
- else printf("method defining class is not null :)\n");
- printf("adding item to class context array:%s\n",current->method->class->name->text);
- printf("method for class: :%s\n",current->method->name->text);
+ if (targetSize > 0) {
+ if (start->method &&
+ (start->method->class == class_java_lang_SecurityManager)) {
+ targetSize--;
+ start++;
}
-#endif
- use_class_as_object(current->method->class);
-#ifdef JWDEBUG
- {
- printf("use_class_as_object_finished\n");
+ }
+
+ oa = builtin_anewarray(targetSize, class_java_lang_Class);
+
+ if (!oa)
+ return false;
+
+ for(i = 0, current = start; i < targetSize; i++, current++) {
+ if (!current->method) {
+ i--;
+ continue;
}
-#endif
- tmpArray->data[i] = (java_objectheader *) current->method->class;
-#ifdef JWDEBUG
- printf("array item has been set\n");
-#endif
- }
-#ifdef JWDEBUG
- printf("leaving classContextCollector");
-#endif
- *target=tmpArray;
+
+ use_class_as_object(current->method->class);
+
+ oa->data[i] = (java_objectheader *) current->method->class;
+ }
+
+ *target = oa;
+
+ return true;
}
-java_objectarray *cacao_createClassContextArray() {
- java_objectarray *array=0;
- cacao_stacktrace_fillInStackTrace((void**)&array,&classContextCollector);
+java_objectarray *cacao_createClassContextArray(void)
+{
+ java_objectarray *array = NULL;
+
+ if (!cacao_stacktrace_fillInStackTrace((void **) &array,
+ &classContextCollector))
+ return NULL;
+
return array;
-
}
-static
-void classLoaderCollector(void **target, stackTraceBuffer *buffer) {
- int i;
- stacktraceelement *current;
- stacktraceelement *start;
- methodinfo *m;
- classinfo *privilegedAction;
- size_t size;
-
- size = buffer->full;
-
- if (size > 1) {
- size--;
- start=&(buffer->start[1]);
- if (start->method && (start->method->class == class_java_lang_SecurityManager)) {
- size--;
- start--;
- }
- } else {
- start=0;
- size=0;
- }
+/* stacktrace_classLoaderCollector *********************************************
+
+ XXX
+
+*******************************************************************************/
- if (!load_class_bootstrap(utf_new_char("java/security/PrivilegedAction"),&privilegedAction))
- /* XXX handle exception */;
+static bool stacktrace_classLoaderCollector(void **target,
+ stackTraceBuffer *buffer)
+{
+ stacktraceelement *current;
+ stacktraceelement *start;
+ methodinfo *m;
+ ptrint size;
+ s4 i;
+
+ size = buffer->full;
+ start = &(buffer->start[0]);
- for(i=0, current = start; i < size; i++, current++) {
- m=start->method;
- if (!m) continue;
+ for(i = 0, current = start; i < size; i++, current++) {
+ m = current->method;
- if (m->class == privilegedAction) {
- *target=NULL;
- return;
+ if (!m)
+ continue;
+
+ if (m->class == class_java_security_PrivilegedAction) {
+ *target = NULL;
+ return true;
}
- if (m->class->classloader) {
- *target= (java_lang_ClassLoader *) m->class->classloader;
- return;
+ if (m->class->classloader) {
+ *target = (java_lang_ClassLoader *) m->class->classloader;
+ return true;
}
- }
+ }
- *target=NULL;
+ *target = NULL;
+
+ return true;
}
-java_objectheader *cacao_currentClassLoader() {
- java_objectheader *header=0;
- cacao_stacktrace_fillInStackTrace((void**)&header,&classLoaderCollector);
+
+/* cacao_currentClassLoader ****************************************************
+
+ XXX
+
+*******************************************************************************/
+
+java_objectheader *cacao_currentClassLoader(void)
+{
+ java_objectheader *header = NULL;
+
+ if (!cacao_stacktrace_fillInStackTrace((void**)&header,
+ &stacktrace_classLoaderCollector))
+ return NULL;
+
return header;
}
-static
-void callingMethodCollector(void **target, stackTraceBuffer *buffer) {
- if (buffer->full >2) (*target)=buffer->start[2].method;
- else (*target=0);
+static bool getStackCollector(void **target, stackTraceBuffer *buffer)
+{
+ java_objectarray *oa;
+ java_objectarray *classes;
+ java_objectarray *methodnames;
+ java_lang_String *str;
+ classinfo *c;
+ stacktraceelement *current;
+ s4 i, size;
+
+/* *result = (java_objectarray **) target; */
+
+ size = buffer->full;
+
+ oa = builtin_anewarray(2, arrayclass_java_lang_Object);
+
+ if (!oa)
+ return false;
+
+ classes = builtin_anewarray(size, class_java_lang_Class);
+
+ if (!classes)
+ return false;
+
+ methodnames = builtin_anewarray(size, class_java_lang_String);
+
+ if (!methodnames)
+ return false;
+
+ oa->data[0] = (java_objectheader *) classes;
+ oa->data[1] = (java_objectheader *) methodnames;
+
+ for (i = 0, current = &(buffer->start[0]); i < size; i++, current++) {
+ c = current->method->class;
+
+ use_class_as_object(c);
+
+ classes->data[i] = (java_objectheader *) c;
+ str = javastring_new(current->method->name);
+
+ if (!str)
+ return false;
+
+ methodnames->data[i] = (java_objectheader *) str;
+ }
+
+ *target = oa;
+
+ return true;
}
-methodinfo *cacao_callingMethod() {
- methodinfo *method;
- cacao_stacktrace_fillInStackTrace((void**)&method,&callingMethodCollector);
- return method;
+
+java_objectarray *cacao_getStackForVMAccessController(void)
+{
+ java_objectarray *result = NULL;
+
+ if (!cacao_stacktrace_fillInStackTrace((void **) &result,
+ &getStackCollector))
+ return NULL;
+
+ return result;
+}
+
+
+/* stacktrace_dump_trace *******************************************************
+
+ This method is call from signal_handler_sigusr1 to dump the
+ stacktrace of the current thread to stdout.
+
+*******************************************************************************/
+
+void stacktrace_dump_trace(void)
+{
+ stackTraceBuffer *buffer;
+
+#if 0
+ /* get thread stackframeinfo */
+
+ info = &THREADINFO->_stackframeinfo;
+
+ /* fill stackframeinfo structure */
+
+ tmp.oldThreadspecificHeadValue = *info;
+ tmp.addressOfThreadspecificHead = info;
+ tmp.method = NULL;
+ tmp.sp = NULL;
+ tmp.ra = _mc->gregs[REG_RIP];
+
+ *info = &tmp;
+#endif
+
+ /* generate stacktrace */
+
+ cacao_stacktrace_NormalTrace((void **) &buffer);
+
+ /* print stacktrace */
+
+ if (buffer) {
+ stacktrace_print_trace(buffer);
+
+ } else {
+ puts("\t<<No stacktrace available>>");
+ fflush(stdout);
+ }
}
+
+/* stacktrace_print_trace ******************************************************
+
+ Print the stacktrace of a given stackTraceBuffer with CACAO intern
+ methods (no Java help). This method is used by
+ stacktrace_dump_trace and builtin_trace_exception.
+
+*******************************************************************************/
+
+void stacktrace_print_trace(stackTraceBuffer *stb)
+{
+ stacktraceelement *ste;
+ methodinfo *m;
+ s4 i;
+
+ ste = stb->start;
+
+ for (i = 0; i < stb->size; i++, ste++) {
+ m = ste->method;
+
+ printf("\tat ");
+ utf_display_classname(m->class->name);
+ printf(".");
+ utf_display(m->name);
+ utf_display(m->descriptor);
+
+ if (m->flags & ACC_NATIVE) {
+ puts("(Native Method)");
+
+ } else {
+ printf("(");
+ utf_display(m->class->sourcefile);
+ printf(":%d)\n", (u4) ste->linenumber);
+ }
+ }
+
+ /* just to be sure */
+
+ fflush(stdout);
+}
+
+
/*
* These are local overrides for various environment variables in Emacs.
* Please do not remove this and leave it at the end of the file, where