1 /* src/vm/jit/stacktrace.c
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 2681 2005-06-14 17:14:44Z twisti $
40 #include "asmoffsets.h"
42 #include "native/native.h"
43 #include "vm/global.h" /* required here for native includes */
44 #include "native/include/java_lang_ClassLoader.h"
45 #include "toolbox/logging.h"
46 #include "vm/builtin.h"
48 #include "vm/tables.h"
49 #include "vm/jit/codegen.inc.h"
50 #include "vm/loader.h"
51 #include "vm/stringlocal.h"
52 #include "vm/exceptions.h"
58 /*JoWenn: simplify collectors (trace doesn't contain internal methods)*/
60 /* the line number is only u2, but to avoid alignment problems it is made the same size as a native
61 pointer. In the structures where this is used, values of -1 or -2 have a special meainging, so
62 if java bytecode is ever extended to support more than 65535 lines/file, this could will have to
65 #if defined(_ALPHA_) || defined(__X86_64__)
71 typedef struct lineNumberTableEntry {
72 /* The special value of -1 means that a inlined function starts, a value of -2 means that an inlined function ends*/
75 } lineNumberTableEntry;
77 typedef struct lineNumberTableEntryInlineBegin {
78 /*this should have the same layout and size as the lineNumberTableEntry*/
79 LineNumber lineNrOuter;
81 } lineNumberTableEntryInlineBegin;
84 typedef void(*CacaoStackTraceCollector)(void **,stackTraceBuffer*);
86 #define BLOCK_INITIALSIZE 40
87 #define BLOCK_SIZEINCREMENT 40
89 static void addEntry(stackTraceBuffer* buffer,methodinfo*method ,LineNumber line) {
90 if (buffer->size>buffer->full) {
91 stacktraceelement *tmp=&(buffer->start[buffer->full]);
94 buffer->full = buffer->full + 1;
95 #if (defined(JWDEBUG) || defined (JWDEBUG2))
96 log_text("addEntry (stacktrace):");
97 printf("method %p\n",method);
98 if (method) printf("method->name %p\n",method->name);
99 if (method) utf_display(method->name); else printf("Native");
100 if (method) {printf("\n");utf_display(method->class->name);}
101 printf("\nnext buffer item %d\nLine:%ld\n",buffer->full,line);
104 stacktraceelement *newBuffer;
107 log_text("stacktrace buffer full, resizing");
111 (stacktraceelement *) malloc((buffer->size + BLOCK_SIZEINCREMENT) *
112 sizeof(stacktraceelement));
115 log_text("OOM during stacktrace creation");
119 memcpy(newBuffer,buffer->start,buffer->size*sizeof(stacktraceelement));
120 if (buffer->needsFree) free(buffer->start);
121 buffer->start=newBuffer;
122 buffer->size=buffer->size+BLOCK_SIZEINCREMENT;
124 addEntry(buffer,method,line);
128 static int fillInStackTrace_methodRecursive(stackTraceBuffer *buffer,methodinfo
129 *method,lineNumberTableEntry *startEntry, lineNumberTableEntry **entry, size_t *entriesAhead,u1 *adress) {
131 size_t ahead=*entriesAhead;
132 lineNumberTableEntry *ent=*entry;
133 lineNumberTableEntryInlineBegin *ilStart;
135 for (;ahead>0;ahead--,ent++) {
136 if (adress>=ent->pc) {
137 switch (ent->lineNr) {
138 case -1: /*begin of inlined method */
139 ilStart=(lineNumberTableEntryInlineBegin*)(++ent);
142 if (fillInStackTrace_methodRecursive(buffer,ilStart->method,ent,&ent,&ahead,adress)) {
143 addEntry(buffer,method,ilStart->lineNrOuter);
147 case -2: /*end of inlined method*/
153 if (adress==ent->pc) {
154 addEntry(buffer,method,ent->lineNr);
160 if (adress>startEntry->pc) {
162 addEntry(buffer,method,ent->lineNr);
166 printf("trace point: %p\n",adress);
168 log_text("trace point before method");
174 addEntry(buffer,method,ent->lineNr);
179 static void fillInStackTrace_method(stackTraceBuffer *buffer,methodinfo *method,u1 *dataSeg, u1* adress) {
180 size_t lineNumberTableSize=(*((size_t*)(dataSeg+LineNumberTableSize)));
183 if ( lineNumberTableSize == 0) {
184 /*right now this happens only on
185 i386,if the native stub causes an exception in a <clinit> invocation (jowenn)*/
186 addEntry(buffer,method,0);
189 lineNumberTableEntry *ent; /*=(lineNumberTableEntry*) ((*((char**)(dataSeg+LineNumberTableStart))) - (sizeof(lineNumberTableEntry)-sizeof(void*)));*/
191 lineNumberTableEntry *startEntry;
193 /* printf("dataSeg: %p\n",dataSeg);*/
194 calc=(void**)(dataSeg+LineNumberTableStart);
195 /* printf("position of line number table start reference in data segment: %p\n",calc);
196 printf("line number table start as found in table: %p\n",*calc);*/
197 ent=(lineNumberTableEntry *) (((char*)(*calc) - (sizeof(lineNumberTableEntry)-sizeof(void*))));
198 /* printf("line number table start as calculated: %p\n",ent);*/
199 ent-=(lineNumberTableSize-1);
201 /* printf("line number table real start (bottom end) as calculated(2): %p\n",startEntry);*/
203 if (!fillInStackTrace_methodRecursive(buffer,method,startEntry,&ent,&lineNumberTableSize,adress)) {
204 log_text("Trace point not found in suspected method");
215 } u1ptr_functionptr_union;
217 #define cast_funcptr_u1ptr(dest,src) \
221 #define cast_u1ptr_funcptr(dest,src) \
225 void cacao_stacktrace_fillInStackTrace(void **target,CacaoStackTraceCollector coll)
228 stacktraceelement primaryBlock[BLOCK_INITIALSIZE*sizeof(stacktraceelement)];
229 /*In most cases this should be enough -> one malloc less. I don't think temporary data should be
230 allocated with the GC, only the result*/
231 stackTraceBuffer buffer;
233 buffer.start=primaryBlock;
234 buffer.size=BLOCK_INITIALSIZE; /* *sizeof(stacktraceelement); */
237 log_text("entering cacao_stacktrace_fillInStacktrace");
240 struct native_stackframeinfo *tmpinfo;
241 for (tmpinfo=(*(((void**)(builtin_asm_get_stackframeinfo()))));tmpinfo;tmpinfo=tmpinfo->oldThreadspecificHeadValue)
243 printf("native function depth:%d\n",i);
248 struct native_stackframeinfo *info=(*(((void**)(builtin_asm_get_stackframeinfo()))));
250 log_text("info ==0");
255 u1 *dataseg; /*make it byte addressable*/
256 methodinfo *currentMethod=0;
257 /*void*/ functionptr returnAdress;
259 u1ptr_functionptr_union u1f;
261 /* utf_display(info->method->class->name);
262 utf_display(info->method->name);*/
264 while ((currentMethod!=0) || (info!=0)) {
265 if (currentMethod==0) { /*some builtin native */
266 currentMethod=info->method;
267 returnAdress=(functionptr)info->returnToFromNative;
270 printf("return to %p\n",returnAdress);
274 log_text("real native (not an internal helper)\n");
275 printf("returnaddress %p, methodpointer %p, stackframe begin %p\n",info->returnToFromNative,info->method, info->beginOfJavaStackframe);
277 utf_display(currentMethod->class->name);
278 utf_display(currentMethod->name);
281 addEntry(&buffer,currentMethod,0);
283 #if defined(__ALPHA__)
284 if (info->savedpv!=0)
285 dataseg=info->savedpv;
287 dataseg=codegen_findmethod(returnAdress);
288 #elif defined(__I386__) || defined (__X86_64__)
289 cast_funcptr_u1ptr(dataseg,codegen_findmethod(returnAdress));
291 currentMethod=(*((methodinfo**)(dataseg+MethodPointer)));
292 if (info->beginOfJavaStackframe==0)
293 stackPtr=((u1*)info)+sizeof(native_stackframeinfo);
295 #if defined(__ALPHA__)
296 stackPtr=(u1*)(info->beginOfJavaStackframe);
297 #elif defined(__I386__) || defined (__X86_64__)
298 stackPtr=(u1*)(info->beginOfJavaStackframe)+sizeof(void*);
300 info=info->oldThreadspecificHeadValue;
301 } else { /*method created by jit*/
306 #if defined (__ALPHA__)
307 if (currentMethod->isleafmethod) {
309 printf("class.method:%s.%s\n",currentMethod->class->name->text,currentMethod->name->text);
311 log_text("How could that happen ??? A leaf method in the middle of a stacktrace ??");
315 /*utf_display(currentMethod->class->name);
316 utf_display(currentMethod->name);*/
317 cast_funcptr_u1ptr(tmp,returnAdress);
318 fillInStackTrace_method(&buffer,currentMethod,dataseg,tmp-1);
319 frameSize=*((u4*)(dataseg+FrameSize));
320 #if defined(__ALPHA__)
321 /* cacao saves the return adress as the first element of the stack frame on alphas*/
322 cast_funcptr_u1ptr (dataseg,codegen_findmethod(*((void**)(stackPtr+frameSize-sizeof(void*)))));
323 returnAdress=(*((void**)(stackPtr+frameSize-sizeof(void*))));
324 #elif defined(__I386__) || defined (__x86_64__)
325 /* on i386 the return adress is the first element before the stack frme*/
326 cast_u1ptr_funcptr(returnAdress,*((u1**)(stackPtr+frameSize)));
327 cast_funcptr_u1ptr(dataseg,codegen_findmethod(returnAdress));
329 /* printf ("threadrootmethod %p\n",builtin_asm_get_threadrootmethod());
330 if (currentMethod==builtin_asm_get_threadrootmethod()) break;*/
331 currentMethod=(*((methodinfo**)(dataseg+MethodPointer)));
332 #if defined(__ALPHA__)
334 #elif defined(__I386__) || defined (__x86_64__)
335 stackPtr+=frameSize+sizeof(void*);
340 if (coll) coll(target,&buffer);
341 if (buffer.needsFree) free(buffer.start);
343 log_text("leaving cacao_stacktrace_fillInStacktrace");
348 /*log_text("\n=========================================================");*/
352 log_text("leaving(2) cacao_stacktrace_fillInStacktrace");
359 void stackTraceCollector(void **target, stackTraceBuffer *buffer) {
360 stackTraceBuffer *dest=*target=heap_allocate(sizeof(stackTraceBuffer)+buffer->full*sizeof(stacktraceelement),true,0);
361 memcpy(*target,buffer,sizeof(stackTraceBuffer));
362 memcpy(dest+1,buffer->start,buffer->full*sizeof(stacktraceelement));
365 dest->size=dest->full;
366 dest->start=(stacktraceelement*)(dest+1);
369 if (buffer->full>0) {
370 printf("SOURCE BUFFER:%s\n",buffer->start[0].method->name->text);
371 printf("DEST BUFFER:%s\n",dest->start[0].method->name->text);
372 } else printf("Buffer is empty\n");
377 void cacao_stacktrace_NormalTrace(void **target) {
378 cacao_stacktrace_fillInStackTrace(target,&stackTraceCollector);
384 void classContextCollector(void **target, stackTraceBuffer *buffer) {
385 java_objectarray *tmpArray;
387 stacktraceelement *current;
388 stacktraceelement *start;
395 if (buffer->start[i].method!=0) targetSize++;
399 if (targetSize > 0) {
400 if ((start->method) && (start->method->class== class_java_lang_SecurityManager)) {
401 #if (defined(JWDEBUG) || defined(JWDEBUG3))
402 printf("removing one frame");
409 tmpArray = builtin_anewarray(targetSize, class_java_lang_Class);
411 #if (defined(JWDEBUG) || defined(JWDEBUG3))
412 printf("==========================================================================================================\n");
414 for(i = 0, current = start; i < targetSize; i++, current++) {
415 if (current->method==0) { i--; /*printf("Skipping\n");*/ continue;}
416 #if (defined(JWDEBUG) || defined(JWDEBUG3))
418 printf("after current->method check\n");
419 if (current->method->class==0) printf("Error method defining class i null\n");
420 else printf("method defining class is not null :)\n");
421 printf("adding item to class context array:%s\n",current->method->class->name->text);
422 printf("method for class: :%s\n",current->method->name->text);
425 use_class_as_object(current->method->class);
428 printf("use_class_as_object_finished\n");
431 tmpArray->data[i] = (java_objectheader *) current->method->class;
433 printf("array item has been set\n");
436 #if (defined(JWDEBUG) || defined(JWDEBUG3))
437 printf("leaving classContextCollector");
444 java_objectarray *cacao_createClassContextArray() {
445 java_objectarray *array=0;
446 cacao_stacktrace_fillInStackTrace((void**)&array,&classContextCollector);
452 static void classLoaderCollector(void **target, stackTraceBuffer *buffer)
454 stacktraceelement *current;
455 stacktraceelement *start;
461 start = &(buffer->start[0]);
463 for(i = 0, current = start; i < size; i++, current++) {
469 if (m->class == class_java_security_PrivilegedAction) {
474 if (m->class->classloader) {
475 *target = (java_lang_ClassLoader *) m->class->classloader;
484 java_objectheader *cacao_currentClassLoader() {
485 java_objectheader *header=0;
486 cacao_stacktrace_fillInStackTrace((void**)&header,&classLoaderCollector);
492 void callingMethodCollector(void **target, stackTraceBuffer *buffer) {
493 if (buffer->full >2) (*target)=buffer->start[2].method;
497 methodinfo *cacao_callingMethod() {
499 cacao_stacktrace_fillInStackTrace((void**)&method,&callingMethodCollector);
505 void getStackCollector(void **target, stackTraceBuffer *buffer)
507 java_objectarray *classes;
508 java_objectarray *methodnames;
509 java_objectarray **result=(java_objectarray**)target;
510 java_lang_String *str;
512 stacktraceelement *current;
515 /*log_text("getStackCollector");*/
519 *result = builtin_anewarray(2, arrayclass_java_lang_Object);
524 classes = builtin_anewarray(size, class_java_lang_Class);
529 methodnames = builtin_anewarray(size, class_java_lang_String);
534 (*result)->data[0] = (java_objectheader *) classes;
535 (*result)->data[1] = (java_objectheader *) methodnames;
537 /*log_text("Before for loop");*/
538 for (i = 0, current = &(buffer->start[0]); i < size; i++, current++) {
539 /*log_text("In loop");*/
540 c = current->method->class;
541 use_class_as_object(c);
542 classes->data[i] = (java_objectheader *) c;
543 str = javastring_new(current->method->name);
546 methodnames->data[i] = (java_objectheader *) str;
547 /*printf("getStackCollector: %s.%s\n",c->name->text,current->method->name->text);*/
550 /*if (*exceptionptr) panic("Exception in getStackCollector");*/
552 /*log_text("loop left");*/
558 java_objectarray *cacao_getStackForVMAccessController()
560 java_objectarray *result=0;
561 cacao_stacktrace_fillInStackTrace((void**)&result,&getStackCollector);
567 * These are local overrides for various environment variables in Emacs.
568 * Please do not remove this and leave it at the end of the file, where
569 * Emacs will automagically detect them.
570 * ---------------------------------------------------------------------
573 * indent-tabs-mode: t