63828028d7bc137a05ff209b8f8dd4819644555c
[cacao.git] / src / vm / jit / stacktrace.c
1 /* src/vm/jit/stacktrace.c - machine independet stacktrace system
2
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
7
8    This file is part of CACAO.
9
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.
14
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.
19
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
23    02111-1307, USA.
24
25    Contact: cacao@complang.tuwien.ac.at
26
27    Authors: Joseph Wenninger
28
29    Changes: Christian Thalinger
30
31    $Id: stacktrace.c 3244 2005-09-21 14:58:47Z twisti $
32
33 */
34
35
36 #include <assert.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 #include "config.h"
41
42 #include "mm/boehm.h"
43 #include "native/native.h"
44
45 #include "vm/global.h"                   /* required here for native includes */
46 #include "native/include/java_lang_ClassLoader.h"
47
48 #include "toolbox/logging.h"
49 #include "vm/builtin.h"
50 #include "vm/class.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"
59
60
61 /* lineNumberTableEntry *******************************************************/
62
63 /* Keep the type of line the same as the pointer type, otherwise we run into  */
64 /* alignment troubles (like on MIPS64).                                       */
65
66 typedef struct lineNumberTableEntry {
67         ptrint  line;
68         u1     *pc;
69 } lineNumberTableEntry;
70
71
72 typedef struct lineNumberTableEntryInlineBegin {
73         /* this should have the same layout and size as the lineNumberTableEntry */
74         ptrint      lineNrOuter;
75         methodinfo *method;
76 } lineNumberTableEntryInlineBegin;
77
78
79 typedef bool(*CacaoStackTraceCollector)(void **, stackTraceBuffer*);
80
81 #define BLOCK_INITIALSIZE 40
82 #define BLOCK_SIZEINCREMENT 40
83
84
85 /* global variables ***********************************************************/
86
87 #if defined(USE_THREADS)
88 #define STACKFRAMEINFO    (stackframeinfo **) (&THREADINFO->_stackframeinfo)
89 #else
90 THREADSPECIFIC stackframeinfo *_no_threads_stackframeinfo = NULL;
91
92 #define STACKFRAMEINFO    (&_no_threads_stackframeinfo)
93 #endif
94
95
96 /* stacktrace_create_stackframeinfo ********************************************
97
98    Creates an stackframe info structure for inline code in the
99    interpreter.
100
101 *******************************************************************************/
102
103 #if defined(ENABLE_INTRP)
104 void stacktrace_create_stackframeinfo(stackframeinfo *sfi, u1 *pv,
105                                                                           u1 *sp, functionptr ra)
106 {
107         stackframeinfo **psfi;
108         methodinfo      *m;
109
110         /* get current stackframe info pointer */
111
112         psfi = STACKFRAMEINFO;
113
114         /* if we don't have pv handy */
115
116         if (pv == NULL)
117                 pv = (u1 *) (ptrint) codegen_findmethod(ra);
118
119         /* get methodinfo pointer from data segment */
120
121         m = *((methodinfo **) (pv + MethodPointer));
122
123         /* fill new stackframe info structure */
124
125         sfi->prev = *psfi;
126         sfi->method = m;
127         sfi->pv = pv;
128         sfi->sp = sp;
129         sfi->ra = ra;
130
131         /* xpc is the same as ra, but is required in fillInStackTrace */
132
133         sfi->xpc = ra;
134
135         /* store new stackframe info pointer */
136
137         *psfi = sfi;
138 }
139 #endif /* defined(ENABLE_INTRP) */
140
141 /* stacktrace_create_inline_stackframeinfo *************************************
142
143    Creates an stackframe info structure for an inline exception stub.
144
145 *******************************************************************************/
146
147 void stacktrace_create_inline_stackframeinfo(stackframeinfo *sfi, u1 *pv,
148                                                                                          u1 *sp, functionptr ra,
149                                                                                          functionptr xpc)
150 {
151         stackframeinfo **psfi;
152
153         /* get current stackframe info pointer */
154
155         psfi = STACKFRAMEINFO;
156
157 #if defined(ENABLE_INTRP)
158         if (opt_intrp) {
159                 /* if we don't have pv handy */
160
161                 if (pv == NULL)
162                         pv = (u1 *) (ptrint) codegen_findmethod(ra);
163
164         }
165 #endif
166
167         /* fill new stackframe info structure */
168
169         sfi->prev = *psfi;
170         sfi->method = NULL;
171         sfi->pv = pv;
172         sfi->sp = sp;
173         sfi->ra = ra;
174         sfi->xpc = xpc;
175
176         /* store new stackframe info pointer */
177
178         *psfi = sfi;
179 }
180
181
182 /* stacktrace_create_extern_stackframeinfo *************************************
183
184    Creates an stackframe info structure for an extern exception
185    (hardware or assembler).
186
187 *******************************************************************************/
188
189 void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv,
190                                                                                          u1 *sp, functionptr ra,
191                                                                                          functionptr xpc)
192 {
193         stackframeinfo **psfi;
194 #if !defined(__I386__) && !defined(__X86_64__)
195         bool             isleafmethod;
196 #endif
197         s4               framesize;
198
199         /* get current stackframe info pointer */
200
201         psfi = STACKFRAMEINFO;
202
203         /* sometimes we don't have pv handy (e.g. in asmpart.S:
204        L_asm_call_jit_compiler_exception or in the interpreter). */
205
206         if (pv == NULL)
207                 pv = (u1 *) (ptrint) codegen_findmethod(ra);
208
209 #if defined(ENABLE_INTRP)
210         /* When using the interpreter, we pass RA to the function. */
211
212         if (!opt_intrp) {
213 #endif
214 # if defined(__I386__) || defined(__X86_64__)
215                 /* On i386 and x86_64 we always have to get the return address
216                    from the stack. */
217
218                 framesize = *((u4 *) (pv + FrameSize));
219
220                 ra = md_stacktrace_get_returnaddress(sp, framesize);
221 # else
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. */
226
227                 isleafmethod = *((s4 *) (pv + IsLeaf));
228
229                 if (!isleafmethod) {
230                         framesize = *((u4 *) (pv + FrameSize));
231
232                         ra = md_stacktrace_get_returnaddress(sp, framesize);
233                 }
234 # endif
235 #if defined(ENABLE_INTRP)
236         }
237 #endif
238
239         /* fill new stackframe info structure */
240
241         sfi->prev = *psfi;
242         sfi->method = NULL;
243         sfi->pv = pv;
244         sfi->sp = sp;
245         sfi->ra = ra;
246         sfi->xpc = xpc;
247
248         /* store new stackframe info pointer */
249
250         *psfi = sfi;
251 }
252
253
254 /* stacktrace_create_native_stackframeinfo *************************************
255
256    Creates a stackframe info structure for a native stub.
257
258 *******************************************************************************/
259
260 void stacktrace_create_native_stackframeinfo(stackframeinfo *sfi, u1 *pv,
261                                                                                          u1 *sp, functionptr ra)
262 {
263         stackframeinfo **psfi;
264         methodinfo      *m;
265
266         /* get methodinfo pointer from data segment */
267
268         m = *((methodinfo **) (pv + MethodPointer));
269
270         /* get current stackframe info pointer */
271
272         psfi = STACKFRAMEINFO;
273
274         /* fill new stackframe info structure */
275
276         sfi->prev = *psfi;
277         sfi->method = m;
278         sfi->pv = NULL;
279         sfi->sp = sp;
280         sfi->ra = ra;
281         sfi->xpc = NULL;
282
283         /* store new stackframe info pointer */
284
285         *psfi = sfi;
286 }
287
288
289 /* stacktrace_remove_stackframeinfo ********************************************
290
291    XXX
292
293 *******************************************************************************/
294
295 void stacktrace_remove_stackframeinfo(stackframeinfo *sfi)
296 {
297         stackframeinfo **psfi;
298
299         /* get current stackframe info pointer */
300
301         psfi = STACKFRAMEINFO;
302
303         /* restore the old pointer */
304
305         *psfi = sfi->prev;
306 }
307
308
309 /* stacktrace_inline_arithmeticexception ***************************************
310
311    Creates an ArithemticException for inline stub.
312
313 *******************************************************************************/
314
315 java_objectheader *stacktrace_inline_arithmeticexception(u1 *pv, u1 *sp,
316                                                                                                                  functionptr ra,
317                                                                                                                  functionptr xpc)
318 {
319         stackframeinfo     sfi;
320         java_objectheader *o;
321
322         /* create stackframeinfo */
323
324         stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
325
326         /* create exception */
327
328         o = new_arithmeticexception();
329
330         /* remove stackframeinfo */
331
332         stacktrace_remove_stackframeinfo(&sfi);
333
334         return o;
335 }
336
337
338 /* stacktrace_inline_arrayindexoutofboundsexception ****************************
339
340    Creates an ArrayIndexOutOfBoundsException for inline stub.
341
342 *******************************************************************************/
343
344 java_objectheader *stacktrace_inline_arrayindexoutofboundsexception(u1 *pv,
345                                                                                                                                         u1 *sp,
346                                                                                                                                         functionptr ra,
347                                                                                                                                         functionptr xpc,
348                                                                                                                                         s4 index)
349 {
350         stackframeinfo     sfi;
351         java_objectheader *o;
352
353         /* create stackframeinfo */
354
355         stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
356
357         /* create exception */
358
359         o = new_arrayindexoutofboundsexception(index);
360
361         /* remove stackframeinfo */
362
363         stacktrace_remove_stackframeinfo(&sfi);
364
365         return o;
366 }
367
368
369 /* stacktrace_inline_arraystoreexception ***************************************
370
371    Creates an ArrayStoreException for inline stub.
372
373 *******************************************************************************/
374
375 java_objectheader *stacktrace_inline_arraystoreexception(u1 *pv, u1 *sp,
376                                                                                                                  functionptr ra,
377                                                                                                                  functionptr xpc)
378 {
379         stackframeinfo     sfi;
380         java_objectheader *o;
381
382         /* create stackframeinfo */
383
384         stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
385
386         /* create exception */
387
388         o = new_arraystoreexception();
389
390         /* remove stackframeinfo */
391
392         stacktrace_remove_stackframeinfo(&sfi);
393
394         return o;
395 }
396
397
398 /* stacktrace_inline_classcastexception ****************************************
399
400    Creates an ClassCastException for inline stub.
401
402 *******************************************************************************/
403
404 java_objectheader *stacktrace_inline_classcastexception(u1 *pv, u1 *sp,
405                                                                                                                 functionptr ra,
406                                                                                                                 functionptr xpc)
407 {
408         stackframeinfo     sfi;
409         java_objectheader *o;
410
411         /* create stackframeinfo */
412
413         stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
414
415         /* create exception */
416
417         o = new_classcastexception();
418
419         /* remove stackframeinfo */
420
421         stacktrace_remove_stackframeinfo(&sfi);
422
423         return o;
424 }
425
426
427 /* stacktrace_inline_negativearraysizeexception ********************************
428
429    Creates an NegativeArraySizeException for inline stub.
430
431 *******************************************************************************/
432
433 java_objectheader *stacktrace_inline_negativearraysizeexception(u1 *pv, u1 *sp,
434                                                                                                                                 functionptr ra,
435                                                                                                                                 functionptr xpc)
436 {
437         stackframeinfo     sfi;
438         java_objectheader *o;
439
440         /* create stackframeinfo */
441
442         stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
443
444         /* create exception */
445
446         o = new_negativearraysizeexception();
447
448         /* remove stackframeinfo */
449
450         stacktrace_remove_stackframeinfo(&sfi);
451
452         return o;
453 }
454
455
456 /* stacktrace_inline_nullpointerexception **************************************
457
458    Creates an NullPointerException for inline stub.
459
460 *******************************************************************************/
461
462 java_objectheader *stacktrace_inline_nullpointerexception(u1 *pv, u1 *sp,
463                                                                                                                   functionptr ra,
464                                                                                                                   functionptr xpc)
465 {
466         stackframeinfo     sfi;
467         java_objectheader *o;
468
469         /* create stackframeinfo */
470
471         stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
472
473         /* create exception */
474
475         o = new_nullpointerexception();
476
477         /* remove stackframeinfo */
478
479         stacktrace_remove_stackframeinfo(&sfi);
480
481         return o;
482 }
483
484
485 /* stacktrace_hardware_arithmeticexception *************************************
486
487    Creates an ArithemticException for inline stub.
488
489 *******************************************************************************/
490
491 java_objectheader *stacktrace_hardware_arithmeticexception(u1 *pv, u1 *sp,
492                                                                                                                    functionptr ra,
493                                                                                                                    functionptr xpc)
494 {
495         stackframeinfo     sfi;
496         java_objectheader *o;
497
498         /* create stackframeinfo */
499
500         stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
501
502         /* create exception */
503
504         o = new_arithmeticexception();
505
506         /* remove stackframeinfo */
507
508         stacktrace_remove_stackframeinfo(&sfi);
509
510         return o;
511 }
512
513
514 /* stacktrace_hardware_nullpointerexception ************************************
515
516    Creates an NullPointerException for the SIGSEGV signal handler.
517
518 *******************************************************************************/
519
520 java_objectheader *stacktrace_hardware_nullpointerexception(u1 *pv, u1 *sp,
521                                                                                                                         functionptr ra,
522                                                                                                                         functionptr xpc)
523 {
524         stackframeinfo     sfi;
525         java_objectheader *o;
526
527         /* create stackframeinfo */
528
529         stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
530
531         /* create exception */
532
533         o = new_nullpointerexception();
534
535         /* remove stackframeinfo */
536
537         stacktrace_remove_stackframeinfo(&sfi);
538
539         return o;
540 }
541
542
543 /* stacktrace_inline_fillInStackTrace ******************************************
544
545    Fills in the correct stacktrace into an existing exception object
546    (this one is for inline exception stubs).
547
548 *******************************************************************************/
549
550 java_objectheader *stacktrace_inline_fillInStackTrace(u1 *pv, u1 *sp,
551                                                                                                           functionptr ra,
552                                                                                                           functionptr xpc)
553 {
554         stackframeinfo     sfi;
555         java_objectheader *o;
556         methodinfo        *m;
557
558         /* create stackframeinfo */
559
560         stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
561
562         /* get exception */
563
564         o = *exceptionptr;
565
566         /* clear exception */
567
568         *exceptionptr = NULL;
569
570         /* resolve methodinfo pointer from exception object */
571
572         m = class_resolvemethod(o->vftbl->class,
573                                                         utf_fillInStackTrace,
574                                                         utf_void__java_lang_Throwable);
575
576         /* call function */
577
578         asm_calljavafunction(m, o, NULL, NULL, NULL);
579
580         /* remove stackframeinfo */
581
582         stacktrace_remove_stackframeinfo(&sfi);
583
584         return o;
585 }
586
587
588 /* addEntry ********************************************************************
589
590    XXX
591
592 *******************************************************************************/
593
594 static void addEntry(stackTraceBuffer *buffer, methodinfo *method, u2 line)
595 {
596         if (buffer->size > buffer->full) {
597                 stacktraceelement *tmp = &(buffer->start[buffer->full]);
598
599                 tmp->method = method;
600                 tmp->linenumber = line;
601                 buffer->full = buffer->full + 1;
602
603         } else {
604                 stacktraceelement *newBuffer;
605
606                 newBuffer =
607                         (stacktraceelement *) malloc((buffer->size + BLOCK_SIZEINCREMENT) *
608                                                                                  sizeof(stacktraceelement));
609
610                 if (newBuffer == 0) {
611                         log_text("OOM during stacktrace creation");
612                         assert(0);
613                 }
614
615                 memcpy(newBuffer, buffer->start, buffer->size * sizeof(stacktraceelement));
616                 if (buffer->needsFree)
617                         free(buffer->start);
618
619                 buffer->start = newBuffer;
620                 buffer->size = buffer->size + BLOCK_SIZEINCREMENT;
621                 buffer->needsFree = 1;
622
623                 addEntry(buffer, method, line);
624         }
625 }
626
627
628 /* stacktrace_fillInStackTrace_methodRecursive *********************************
629
630    XXX
631
632 *******************************************************************************/
633
634 static bool stacktrace_fillInStackTrace_methodRecursive(stackTraceBuffer *buffer,
635                                                                                                                 methodinfo *m,
636                                                                                                                 lineNumberTableEntry *lntentry,
637                                                                                                                 s4 lntsize,
638                                                                                                                 u1 *pc)
639 {
640 #if 0
641         lineNumberTableEntryInlineBegin *lntinline;
642 #endif
643
644         /* find the line number for the specified pc (going backwards) */
645
646         for (; lntsize > 0; lntsize--, lntentry--) {
647                 /* did we reach the current line? */
648
649                 if (pc >= lntentry->pc) {
650                         /* check for special inline entries */
651
652                         switch (lntentry->line) {
653 #if 0
654                         /* XXX TWISTI we have to think about this inline stuff again */
655
656                         case -1: /* begin of inlined method */
657                                 lntinline = (lineNumberTableEntryInlineBegin *) (--lntentry);
658                                 lntentry++;
659                                 lntsize--; lntsize--;
660                                 if (stacktrace_fillInStackTrace_methodRecursive(buffer,
661                                                                                                                                 ilStart->method,
662                                                                                                                                 ent,
663                                                                                                                                 &ent,
664                                                                                                                                 &ahead,
665                                                                                                                                 pc)) {
666                                         addEntry(buffer, m, ilStart->lineNrOuter);
667
668                                         return true;
669                                 }
670                                 break;
671
672                         case -2: /* end of inlined method */
673                                 *entry = ent;
674                                 *entriesAhead = ahead;
675                                 return false;
676                                 break;
677 #endif
678
679                         default:
680                                 addEntry(buffer, m, lntentry->line);
681                                 return true;
682                         }
683                 }
684         }
685
686         /* check if we are before the actual JIT code */
687
688         if ((ptrint) pc < (ptrint) m->entrypoint) {
689                 dolog("Current pc before start of code: %p < %p", pc, m->entrypoint);
690                 assert(0);
691         }
692
693         /* otherwise just add line 0 */
694
695         addEntry(buffer, m, 0);
696
697         return true;
698 }
699
700
701 /* stacktrace_fillInStackTrace_method ******************************************
702
703    XXX
704
705 *******************************************************************************/
706
707 static void stacktrace_fillInStackTrace_method(stackTraceBuffer *buffer,
708                                                                                            methodinfo *method, u1 *pv,
709                                                                                            u1 *pc)
710 {
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  */
714
715         /* get size of line number table */
716
717         lntsize  = *((ptrint *) (pv + LineNumberTableSize));
718         lntstart = *((u1 **)    (pv + LineNumberTableStart));
719
720         /* subtract the size of the line number entry of the structure, since the */
721         /* line number table start points to the pc */
722
723         lntentry = (lineNumberTableEntry *) (lntstart - SIZEOF_VOID_P);
724
725         if (lntsize == 0) {
726                 /* this happens when an exception is thrown in the native stub */
727
728                 addEntry(buffer, method, 0);
729
730         } else {
731                 if (!stacktrace_fillInStackTrace_methodRecursive(buffer,
732                                                                                                                  method,
733                                                                                                                  lntentry,
734                                                                                                                  lntsize,
735                                                                                                                  pc)) {
736                         log_text("Trace point not found in suspected method");
737                         assert(0);
738                 }
739         }
740 }
741
742
743 /* cacao_stacktrace_fillInStackTrace *******************************************
744
745    XXX
746
747 *******************************************************************************/
748
749 static bool cacao_stacktrace_fillInStackTrace(void **target,
750                                                                                           CacaoStackTraceCollector coll)
751 {
752         stacktraceelement primaryBlock[BLOCK_INITIALSIZE*sizeof(stacktraceelement)];
753         stackTraceBuffer  buffer;
754         stackframeinfo   *sfi;
755         methodinfo       *m;
756         u1               *pv;
757         u1               *sp;
758         u4                framesize;
759         functionptr       ra;
760         functionptr       xpc;
761         bool              result;
762
763         /* prevent compiler warnings */
764
765         pv = NULL;
766         sp = NULL;
767         ra = NULL;
768
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.       */
771
772         buffer.needsFree = 0;
773         buffer.start = primaryBlock;
774         buffer.size = BLOCK_INITIALSIZE; /*  *sizeof(stacktraceelement); */
775         buffer.full = 0;
776
777         /* the first element in the stackframe chain must always be a native      */
778         /* stackframeinfo (VMThrowable.fillInStackTrace is a native function)     */
779
780         sfi = *STACKFRAMEINFO;
781
782         if (!sfi) {
783                 *target = NULL;
784                 return true;
785         }
786
787 #define PRINTMETHODS 0
788
789 #if PRINTMETHODS
790         printf("\n\nfillInStackTrace start:\n");
791 #endif
792
793         /* loop while we have a method pointer (asm_calljavafunction has NULL) or */
794         /* there is a stackframeinfo in the chain                                 */
795
796         m = NULL;
797
798         while (m || sfi) {
799                 /* m == NULL should only happen for the first time and inline         */
800                 /* stackframe infos, like from the exception stubs or the patcher     */
801                 /* wrapper                                                            */
802
803                 if (m == NULL) {
804                         /* for native stub stackframe infos, pv is always NULL */
805
806                         if (sfi->pv == NULL) {
807                                 /* get methodinfo, sp and ra from the current stackframe info */
808
809                                 m  = sfi->method;
810                                 sp = sfi->sp;           /* sp of parent Java function         */
811                                 ra = sfi->ra;
812
813                                 if (m)
814                                         addEntry(&buffer, m, 0);
815
816 #if PRINTMETHODS
817                                 utf_display_classname(m->class->name);
818                                 printf(".");
819                                 utf_display(m->name);
820                                 utf_display(m->descriptor);
821                                 printf(": native stub\n");
822 #endif
823                                 /* this is an native stub stackframe info, so we can get the */
824                                 /* parent pv from the return address (ICMD_INVOKE*) */
825
826                                 pv = (u1 *) (ptrint) codegen_findmethod(ra);
827
828                                 /* get methodinfo pointer from parent data segment */
829
830                                 m = *((methodinfo **) (pv + MethodPointer));
831
832                         } else {
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!!!     */
838
839                                 /* get methodinfo, sp and ra from the current stackframe info */
840
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          */
846
847 #if PRINTMETHODS
848                                 printf("NULL: inline stub\n");
849 #endif
850
851                                 /* get methodinfo from current Java method */
852
853                                 m = *((methodinfo **) (pv + MethodPointer));
854
855                                 /* if m == NULL, this is a asm_calljavafunction call */
856
857                                 if (m != NULL) {
858 #if PRINTMETHODS
859                                         utf_display_classname(m->class->name);
860                                         printf(".");
861                                         utf_display(m->name);
862                                         utf_display(m->descriptor);
863                                         printf(": inline stub parent\n");
864 #endif
865
866 #if defined(ENABLE_INTRP)
867                                         if (!opt_intrp) {
868 #endif
869
870                                         /* add it to the stacktrace */
871
872                                         stacktrace_fillInStackTrace_method(&buffer, m, pv,
873                                                                                                            (u1 *) ((ptrint) xpc));
874
875                                         /* get the current stack frame size */
876
877                                         framesize = *((u4 *) (pv + FrameSize));
878
879                                         /* set stack pointer to stackframe of parent Java */
880                                         /* function of the current Java function */
881
882 #if defined(__I386__) || defined (__X86_64__)
883                                         sp += framesize + SIZEOF_VOID_P;
884 #else
885                                         sp += framesize;
886 #endif
887
888                                         /* get data segment and methodinfo pointer from parent */
889                                         /* method */
890
891                                         pv = (u1 *) (ptrint) codegen_findmethod(ra);
892                                         m = *((methodinfo **) (pv + MethodPointer));
893
894 #if defined(ENABLE_INTRP)
895                                         }
896 #endif
897                                 }
898                         }
899
900                         /* get previous stackframeinfo in the chain */
901
902                         sfi = sfi->prev;
903
904                 } else {
905 #if PRINTMETHODS
906                         utf_display_classname(m->class->name);
907                         printf(".");
908                         utf_display(m->name);
909                         utf_display(m->descriptor);
910                         printf(": JIT\n");
911 #endif
912
913                         /* JIT method found, add it to the stacktrace (we subtract 1 from */
914                         /* the return address since it points the the instruction after */
915                         /* call) */
916
917                         stacktrace_fillInStackTrace_method(&buffer, m, pv,
918                                                                                            (u1 *) ((ptrint) ra) - 1);
919
920                         /* get the current stack frame size */
921
922                         framesize = *((u4 *) (pv + FrameSize));
923
924                         /* get return address of current stack frame */
925
926                         ra = md_stacktrace_get_returnaddress(sp, framesize);
927
928                         /* get data segment and methodinfo pointer from parent method */
929
930                         pv = (u1 *) (ptrint) codegen_findmethod(ra);
931                         m = *((methodinfo **) (pv + MethodPointer));
932
933                         /* walk the stack */
934
935 #if defined(ENABLE_INTRP)
936                         if (opt_intrp)
937                                 sp = *(u1 **)(sp - framesize);
938                         else
939 #endif
940                                 {
941 #if defined(__I386__) || defined (__X86_64__)
942                                         sp += framesize + SIZEOF_VOID_P;
943 #else
944                                         sp += framesize;
945 #endif
946                                 }
947                 }
948         }
949                         
950         if (coll)
951                 result = coll(target, &buffer);
952
953         if (buffer.needsFree)
954                 free(buffer.start);
955
956         return result;
957 }
958
959
960 /* stackTraceCollector *********************************************************
961
962    XXX
963
964 *******************************************************************************/
965
966 static bool stackTraceCollector(void **target, stackTraceBuffer *buffer)
967 {
968         stackTraceBuffer *dest;
969
970         dest = *target = heap_allocate(sizeof(stackTraceBuffer) + buffer->full * sizeof(stacktraceelement), true, 0);
971
972         if (!dest)
973                 return false;
974
975         memcpy(*target, buffer, sizeof(stackTraceBuffer));
976         memcpy(dest + 1, buffer->start, buffer->full * sizeof(stacktraceelement));
977
978         dest->needsFree = 0;
979         dest->size = dest->full;
980         dest->start = (stacktraceelement *) (dest + 1);
981
982         return true;
983 }
984
985
986 bool cacao_stacktrace_NormalTrace(void **target)
987 {
988         return cacao_stacktrace_fillInStackTrace(target, &stackTraceCollector);
989 }
990
991
992
993 static bool classContextCollector(void **target, stackTraceBuffer *buffer)
994 {
995         java_objectarray  *oa;
996         stacktraceelement *current;
997         stacktraceelement *start;
998         size_t size;
999         size_t targetSize;
1000         s4 i;
1001
1002         size = buffer->full;
1003         targetSize = 0;
1004
1005         for (i = 0; i < size; i++)
1006                 if (buffer->start[i].method != 0)
1007                         targetSize++;
1008
1009         start = buffer->start;
1010         start++;
1011         targetSize--;
1012
1013         if (targetSize > 0) {
1014                 if (start->method &&
1015                         (start->method->class == class_java_lang_SecurityManager)) {
1016                         targetSize--;
1017                         start++;
1018                 }
1019         }
1020
1021         oa = builtin_anewarray(targetSize, class_java_lang_Class);
1022
1023         if (!oa)
1024                 return false;
1025
1026         for(i = 0, current = start; i < targetSize; i++, current++) {
1027                 if (!current->method) {
1028                         i--;
1029                         continue;
1030                 }
1031
1032                 use_class_as_object(current->method->class);
1033
1034                 oa->data[i] = (java_objectheader *) current->method->class;
1035         }
1036
1037         *target = oa;
1038
1039         return true;
1040 }
1041
1042
1043
1044 java_objectarray *cacao_createClassContextArray(void)
1045 {
1046         java_objectarray *array = NULL;
1047
1048         if (!cacao_stacktrace_fillInStackTrace((void **) &array,
1049                                                                                    &classContextCollector))
1050                 return NULL;
1051
1052         return array;
1053 }
1054
1055
1056 /* stacktrace_classLoaderCollector *********************************************
1057
1058    XXX
1059
1060 *******************************************************************************/
1061
1062 static bool stacktrace_classLoaderCollector(void **target,
1063                                                                                         stackTraceBuffer *buffer)
1064 {
1065         stacktraceelement *current;
1066         stacktraceelement *start;
1067         methodinfo        *m;
1068         ptrint             size;
1069         s4                 i;
1070
1071         size = buffer->full;
1072         start = &(buffer->start[0]);
1073
1074         for(i = 0, current = start; i < size; i++, current++) {
1075                 m = current->method;
1076
1077                 if (!m)
1078                         continue;
1079
1080                 if (m->class == class_java_security_PrivilegedAction) {
1081                         *target = NULL;
1082                         return true;
1083                 }
1084
1085                 if (m->class->classloader) {
1086                         *target = (java_lang_ClassLoader *) m->class->classloader;
1087                         return true;
1088                 }
1089         }
1090
1091         *target = NULL;
1092
1093         return true;
1094 }
1095
1096
1097 /* cacao_currentClassLoader ****************************************************
1098
1099    XXX
1100
1101 *******************************************************************************/
1102
1103 java_objectheader *cacao_currentClassLoader(void)
1104 {
1105         java_objectheader *header = NULL;
1106
1107         if (!cacao_stacktrace_fillInStackTrace((void**)&header,
1108                                                                                    &stacktrace_classLoaderCollector))
1109                 return NULL;
1110
1111         return header;
1112 }
1113
1114
1115 static bool callingMethodCollector(void **target, stackTraceBuffer *buffer)
1116 {
1117         if (buffer->full > 2)
1118                 *target = buffer->start[2].method;
1119         else
1120                 *target = NULL;
1121
1122         return true;
1123 }
1124
1125
1126 methodinfo *cacao_callingMethod(void)
1127 {
1128         methodinfo *method;
1129
1130         if (!cacao_stacktrace_fillInStackTrace((void **) &method,
1131                                                                                    &callingMethodCollector))
1132                 return NULL;
1133
1134         return method;
1135 }
1136
1137
1138 static bool getStackCollector(void **target, stackTraceBuffer *buffer)
1139 {
1140         java_objectarray  *oa;
1141         java_objectarray  *classes;
1142         java_objectarray  *methodnames;
1143         java_lang_String  *str;
1144         classinfo         *c;
1145         stacktraceelement *current;
1146         s4                 i, size;
1147
1148 /*      *result = (java_objectarray **) target; */
1149
1150         size = buffer->full;
1151
1152         oa = builtin_anewarray(2, arrayclass_java_lang_Object);
1153
1154         if (!oa)
1155                 return false;
1156
1157         classes = builtin_anewarray(size, class_java_lang_Class);
1158
1159         if (!classes)
1160                 return false;
1161
1162         methodnames = builtin_anewarray(size, class_java_lang_String);
1163
1164         if (!methodnames)
1165                 return false;
1166
1167         oa->data[0] = (java_objectheader *) classes;
1168         oa->data[1] = (java_objectheader *) methodnames;
1169
1170         for (i = 0, current = &(buffer->start[0]); i < size; i++, current++) {
1171                 c = current->method->class;
1172
1173                 use_class_as_object(c);
1174
1175                 classes->data[i] = (java_objectheader *) c;
1176                 str = javastring_new(current->method->name);
1177
1178                 if (!str)
1179                         return false;
1180
1181                 methodnames->data[i] = (java_objectheader *) str;
1182         }
1183
1184         *target = oa;
1185
1186         return true;
1187 }
1188
1189
1190 java_objectarray *cacao_getStackForVMAccessController(void)
1191 {
1192         java_objectarray *result = NULL;
1193
1194         if (!cacao_stacktrace_fillInStackTrace((void **) &result,
1195                                                                                    &getStackCollector))
1196                 return NULL;
1197
1198         return result;
1199 }
1200
1201
1202 /* stacktrace_dump_trace *******************************************************
1203
1204    This method is call from signal_handler_sigusr1 to dump the
1205    stacktrace of the current thread to stdout.
1206
1207 *******************************************************************************/
1208
1209 void stacktrace_dump_trace(void)
1210 {
1211         stackTraceBuffer      *buffer;
1212         stacktraceelement     *element;
1213         methodinfo            *m;
1214         s4                     i;
1215
1216 #if 0
1217         /* get thread stackframeinfo */
1218
1219         info = &THREADINFO->_stackframeinfo;
1220
1221         /* fill stackframeinfo structure */
1222
1223         tmp.oldThreadspecificHeadValue = *info;
1224         tmp.addressOfThreadspecificHead = info;
1225         tmp.method = NULL;
1226         tmp.sp = NULL;
1227         tmp.ra = _mc->gregs[REG_RIP];
1228
1229         *info = &tmp;
1230 #endif
1231
1232         /* generate stacktrace */
1233
1234         cacao_stacktrace_NormalTrace((void **) &buffer);
1235
1236         /* print stacktrace */
1237
1238         if (buffer) {
1239                 element = buffer->start;
1240
1241                 for (i = 0; i < buffer->size; i++, element++) {
1242                         m = element->method;
1243
1244                         printf("\tat ");
1245                         utf_display_classname(m->class->name);
1246                         printf(".");
1247                         utf_display(m->name);
1248                         utf_display(m->descriptor);
1249
1250                         if (m->flags & ACC_NATIVE) {
1251                                 printf("(Native Method)\n");
1252
1253                         } else {
1254                                 printf("(");
1255                                 utf_display(m->class->sourcefile);
1256                                 printf(":%d)\n", (u4) element->linenumber);
1257                         }
1258                 }
1259         }
1260
1261         /* flush stdout */
1262
1263         fflush(stdout);
1264 }
1265
1266
1267 /*
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  * ---------------------------------------------------------------------
1272  * Local variables:
1273  * mode: c
1274  * indent-tabs-mode: t
1275  * c-basic-offset: 4
1276  * tab-width: 4
1277  * End:
1278  */