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 $Id: stacktrace.c 1774 2004-12-20 20:16:57Z jowenn $
37 #include "asmoffsets.h"
39 #include "native/native.h"
40 #include "vm/global.h" /* required here for native includes */
41 #include "native/include/java_lang_ClassLoader.h"
42 #include "toolbox/logging.h"
43 #include "vm/builtin.h"
44 #include "vm/tables.h"
45 #include "vm/jit/codegen.inc.h"
49 /*JoWenn: simplify collectors (trace doesn't contain internal methods)*/
51 extern classinfo *class_java_lang_Class;
52 extern classinfo *class_java_lang_SecurityManager;
54 /* the line number is only u2, but to avoid alignment problems it is made the same size as a native
55 pointer. In the structures where this is used, values of -1 or -2 have a special meainging, so
56 if java bytecode is ever extended to support more than 65535 lines/file, this could will have to
65 typedef struct lineNumberTableEntry {
66 /* The special value of -1 means that a inlined function starts, a value of -2 means that an inlined function ends*/
69 } lineNumberTableEntry;
71 typedef struct lineNumberTableEntryInlineBegin {
72 /*this should have the same layout and size as the lineNumberTableEntry*/
73 LineNumber lineNrOuter;
75 } lineNumberTableEntryInlineBegin;
78 typedef void(*CacaoStackTraceCollector)(void **,stackTraceBuffer*);
80 #define BLOCK_INITIALSIZE 40
81 #define BLOCK_SIZEINCREMENT 40
83 static void addEntry(stackTraceBuffer* buffer,methodinfo*method ,LineNumber line) {
84 if (buffer->size>buffer->full) {
85 stacktraceelement *tmp=&(buffer->start[buffer->full]);
88 buffer->full = buffer->full + 1;
90 log_text("addEntry (stacktrace):");
91 if (method) utf_display(method->name); else printf("Native");
92 if (method) {printf("\n");utf_display(method->class->name);}
93 printf("\nLine:%ld\n",line);
96 stacktraceelement *newBuffer=(stacktraceelement*)
97 malloc((buffer->size+BLOCK_SIZEINCREMENT)*sizeof(stacktraceelement));
98 if (newBuffer==0) panic("OOM during stacktrace creation");
99 memcpy(newBuffer,buffer->start,buffer->size*sizeof(stacktraceelement));
100 if (buffer->needsFree) free(buffer->start);
101 buffer->start=newBuffer;
102 buffer->size=buffer->size+BLOCK_SIZEINCREMENT;
104 addEntry(buffer,method,line);
108 static int fillInStackTrace_methodRecursive(stackTraceBuffer *buffer,methodinfo
109 *method,lineNumberTableEntry *startEntry, lineNumberTableEntry **entry, size_t *entriesAhead,void *adress) {
111 size_t ahead=*entriesAhead;
112 lineNumberTableEntry *ent=*entry;
113 lineNumberTableEntryInlineBegin *ilStart;
115 for (;ahead>0;ahead--,ent++) {
116 if (adress>=ent->pc) {
117 switch (ent->lineNr) {
118 case -1: /*begin of inlined method */
119 ilStart=(lineNumberTableEntryInlineBegin*)(++ent);
122 if (fillInStackTrace_methodRecursive(buffer,ilStart->method,ent,&ent,&ahead,adress)) {
123 addEntry(buffer,method,ilStart->lineNrOuter);
127 case -2: /*end of inlined method*/
133 if (adress==ent->pc) {
134 addEntry(buffer,method,ent->lineNr);
140 if (adress>startEntry->pc) {
142 addEntry(buffer,method,ent->lineNr);
144 } else panic("trace point before method");
148 addEntry(buffer,method,ent->lineNr);
153 static void fillInStackTrace_method(stackTraceBuffer *buffer,methodinfo *method,char *dataSeg, void* adress) {
154 size_t lineNumberTableSize=(*((size_t*)(dataSeg+LineNumberTableSize)));
157 if ( lineNumberTableSize == 0) {
158 /*right now this happens only on
159 i386,if the native stub causes an exception in a <clinit> invocation (jowenn)*/
160 addEntry(buffer,method,0);
163 lineNumberTableEntry *ent; /*=(lineNumberTableEntry*) ((*((char**)(dataSeg+LineNumberTableStart))) - (sizeof(lineNumberTableEntry)-sizeof(void*)));*/
165 lineNumberTableEntry *startEntry;
167 /* printf("dataSeg: %p\n",dataSeg);*/
168 calc=dataSeg+LineNumberTableStart;
169 /* printf("position of line number table start reference in data segment: %p\n",calc);
170 printf("line number table start as found in table: %p\n",*calc);*/
171 ent=(lineNumberTableEntry *) (((char*)(*calc) - (sizeof(lineNumberTableEntry)-sizeof(void*))));
172 /* printf("line number table start as calculated: %p\n",ent);*/
173 ent-=(lineNumberTableSize-1);
175 /* printf("line number table real start (bottom end) as calculated(2): %p\n",startEntry);*/
177 if (!fillInStackTrace_methodRecursive(buffer,method,startEntry,&ent,&lineNumberTableSize,adress)) {
178 panic("Trace point not found in suspected method");
184 void cacao_stacktrace_fillInStackTrace(void **target,CacaoStackTraceCollector coll)
187 stacktraceelement primaryBlock[BLOCK_INITIALSIZE*sizeof(stacktraceelement)];
188 /*In most cases this should be enough -> one malloc less. I don't think temporary data should be
189 allocated with the GC, only the result*/
190 stackTraceBuffer buffer;
192 buffer.start=primaryBlock;
193 buffer.size=BLOCK_INITIALSIZE*sizeof(stacktraceelement);
198 struct native_stackframeinfo *info=(*(((void**)(builtin_asm_get_stackframeinfo()))));
200 log_text("info ==0");
204 char *dataseg; /*make it byte addressable*/
205 methodinfo *currentMethod=0;
209 /* utf_display(info->method->class->name);
210 utf_display(info->method->name);*/
212 while ((currentMethod!=0) || (info!=0)) {
213 if (currentMethod==0) { /*some builtin native */
214 currentMethod=info->method;
215 returnAdress=info->returnToFromNative;
216 /*log_text("native");*/
218 /*utf_display(currentMethod->class->name);
219 utf_display(currentMethod->name);*/
220 addEntry(&buffer,currentMethod,0);
222 #if defined(__ALPHA__)
223 if (info->savedpv!=0)
224 dataseg=info->savedpv;
226 dataseg=codegen_findmethod(returnAdress);
227 #elif defined(__I386__)
228 dataseg=codegen_findmethod(returnAdress);
230 currentMethod=(*((methodinfo**)(dataseg+MethodPointer)));
231 if (info->beginOfJavaStackframe==0)
232 stackPtr=((char*)info)+sizeof(native_stackframeinfo);
234 #if defined(__ALPHA__)
235 stackPtr=(char*)(info->beginOfJavaStackframe);
236 #elif defined(__I386__)
237 stackPtr=(char*)(info->beginOfJavaStackframe)+sizeof(void*);
239 info=info->oldThreadspecificHeadValue;
240 } else { /*method created by jit*/
243 #if defined (__ALPHA__)
244 if (currentMethod->isleafmethod) {
246 printf("class.method:%s.%s\n",currentMethod->class->name->text,currentMethod->name->text);
248 panic("How could that happen ??? A leaf method in the middle of a stacktrace ??");
251 /*utf_display(currentMethod->class->name);
252 utf_display(currentMethod->name);*/
253 fillInStackTrace_method(&buffer,currentMethod,dataseg,returnAdress);
254 frameSize=*((u4*)(dataseg+FrameSize));
255 #if defined(__ALPHA__)
256 /* cacao saves the return adress as the first element of the stack frame on alphas*/
257 dataseg=codegen_findmethod(*((void**)(stackPtr+frameSize-sizeof(void*))));
258 returnAdress=(*((void**)(stackPtr+frameSize-sizeof(void*))));
259 #elif defined(__I386__)
260 /* on i386 the return adress is the first element before the stack frme*/
261 returnAdress=(*((void**)(stackPtr+frameSize)));
262 dataseg=codegen_findmethod(*((void**)(stackPtr+frameSize)));
264 /* printf ("threadrootmethod %p\n",builtin_asm_get_threadrootmethod());
265 if (currentMethod==builtin_asm_get_threadrootmethod()) break;*/
266 currentMethod=(*((methodinfo**)(dataseg+MethodPointer)));
267 #if defined(__ALPHA__)
269 #elif defined(__I386__)
270 stackPtr+=frameSize+sizeof(void*);
275 if (coll) coll(target,&buffer);
276 if (buffer.needsFree) free(buffer.start);
279 /*log_text("\n=========================================================");*/
287 void stackTraceCollector(void **target, stackTraceBuffer *buffer) {
288 stackTraceBuffer *dest=*target=heap_allocate(sizeof(stackTraceBuffer)+buffer->full*sizeof(stacktraceelement),true,0);
289 memcpy(*target,buffer,sizeof(stackTraceBuffer));
290 memcpy(dest+1,buffer->start,buffer->full*sizeof(stacktraceelement));
293 dest->size=dest->full;
297 if (buffer->full>0) {
298 printf("SOURCE BUFFER:%s\n",buffer->start[0].method->name->text);
299 printf("DEST BUFFER:%s\n",dest->start[0].method->name->text);
300 } else printf("Buffer is empty\n");
305 void cacao_stacktrace_NormalTrace(void **target) {
306 cacao_stacktrace_fillInStackTrace(target,&stackTraceCollector);
312 void classContextCollector(void **target, stackTraceBuffer *buffer) {
313 java_objectarray *tmpArray;
315 stacktraceelement *current;
316 stacktraceelement *start;
324 if (buffer->start[i].method!=0) targetSize++;
328 if (!class_java_lang_Class)
329 class_java_lang_Class = class_new(utf_new_char("java/lang/Class"));
331 if (!class_java_lang_SecurityManager)
332 class_java_lang_SecurityManager =
333 class_new(utf_new_char("java/lang/SecurityManager"));
335 if (targetSize > 0) {
336 if ((start->method) && (start->method->class== class_java_lang_SecurityManager)) {
343 builtin_newarray(targetSize, class_array_of(class_java_lang_Class)->vftbl);
345 for(i = 0, current = start; i < targetSize; i++, current++) {
346 if (current->method==0) { i--; continue;}
347 /*printf("adding item to class context array:%s\n",current->method->class->name->text);
348 printf("method for class: :%s\n",current->method->name->text);*/
349 use_class_as_object(current->method->class);
350 tmpArray->data[i] = (java_objectheader *) current->method->class;
358 java_objectarray *cacao_createClassContextArray() {
359 java_objectarray *array=0;
360 cacao_stacktrace_fillInStackTrace(&array,&classContextCollector);
367 void classLoaderCollector(void **target, stackTraceBuffer *buffer) {
369 stacktraceelement *current;
370 stacktraceelement *start;
372 classinfo *privilegedAction;
378 if (!class_java_lang_SecurityManager)
379 class_java_lang_SecurityManager =
380 class_new(utf_new_char("java/lang/SecurityManager"));
384 start=&(buffer->start[1]);
385 if (start == class_java_lang_SecurityManager) {
393 privilegedAction=class_new(utf_new_char("java/security/PrivilegedAction"));
395 for(i=0, current = start; i < size; i++, current++) {
399 if (m->class == privilegedAction) {
404 if (m->class->classloader) {
405 *target= (java_lang_ClassLoader *) m->class->classloader;
413 java_objectheader *cacao_currentClassLoader() {
414 java_objectheader *header=0;
415 cacao_stacktrace_fillInStackTrace(&header,&classLoaderCollector);
421 void callingMethodCollector(void **target, stackTraceBuffer *buffer) {
422 if (buffer->full >2) (*target)=buffer->start[2].method;
426 methodinfo *cacao_callingMethod() {
428 cacao_stacktrace_fillInStackTrace(&method,&callingMethodCollector);
433 * These are local overrides for various environment variables in Emacs.
434 * Please do not remove this and leave it at the end of the file, where
435 * Emacs will automagically detect them.
436 * ---------------------------------------------------------------------
439 * indent-tabs-mode: t