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