* use_class_as_object removed, link_class added where required.
[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 3801 2005-11-26 19:15:45Z 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                 oa->data[i] = (java_objectheader *) current->method->class;
1083         }
1084
1085         *target = oa;
1086
1087         return true;
1088 }
1089
1090
1091
1092 java_objectarray *cacao_createClassContextArray(void)
1093 {
1094         java_objectarray *array = NULL;
1095
1096 #ifdef ENABLE_JVMTI
1097         if (!cacao_stacktrace_fillInStackTrace((void **) &array,
1098                                                                                    &classContextCollector, NULL))
1099 #else
1100         if (!cacao_stacktrace_fillInStackTrace((void **) &array,
1101                                                                                    &classContextCollector))
1102 #endif
1103                 return NULL;
1104
1105         return array;
1106 }
1107
1108
1109 /* stacktrace_classLoaderCollector *********************************************
1110
1111    XXX
1112
1113 *******************************************************************************/
1114
1115 static bool stacktrace_classLoaderCollector(void **target,
1116                                                                                         stackTraceBuffer *buffer)
1117 {
1118         stacktraceelement *current;
1119         stacktraceelement *start;
1120         methodinfo        *m;
1121         ptrint             size;
1122         s4                 i;
1123
1124         size = buffer->full;
1125         start = &(buffer->start[0]);
1126
1127         for(i = 0, current = start; i < size; i++, current++) {
1128                 m = current->method;
1129
1130                 if (!m)
1131                         continue;
1132
1133                 if (m->class == class_java_security_PrivilegedAction) {
1134                         *target = NULL;
1135                         return true;
1136                 }
1137
1138                 if (m->class->classloader) {
1139                         *target = (java_lang_ClassLoader *) m->class->classloader;
1140                         return true;
1141                 }
1142         }
1143
1144         *target = NULL;
1145
1146         return true;
1147 }
1148
1149
1150 /* cacao_currentClassLoader ****************************************************
1151
1152    XXX
1153
1154 *******************************************************************************/
1155
1156 java_objectheader *cacao_currentClassLoader(void)
1157 {
1158         java_objectheader *header = NULL;
1159
1160
1161 #ifdef ENABLE_JVMTI
1162         if (!cacao_stacktrace_fillInStackTrace((void**)&header,
1163                                                                                    &stacktrace_classLoaderCollector,
1164                                                                                    NULL))
1165 #else
1166         if (!cacao_stacktrace_fillInStackTrace((void**)&header,
1167                                                                                    &stacktrace_classLoaderCollector))
1168 #endif
1169                 return NULL;
1170
1171         return header;
1172 }
1173
1174
1175 static bool getStackCollector(void **target, stackTraceBuffer *buffer)
1176 {
1177         java_objectarray  *oa;
1178         java_objectarray  *classes;
1179         java_objectarray  *methodnames;
1180         java_lang_String  *str;
1181         classinfo         *c;
1182         stacktraceelement *current;
1183         s4                 i, size;
1184
1185 /*      *result = (java_objectarray **) target; */
1186
1187         size = buffer->full;
1188
1189         oa = builtin_anewarray(2, arrayclass_java_lang_Object);
1190
1191         if (!oa)
1192                 return false;
1193
1194         classes = builtin_anewarray(size, class_java_lang_Class);
1195
1196         if (!classes)
1197                 return false;
1198
1199         methodnames = builtin_anewarray(size, class_java_lang_String);
1200
1201         if (!methodnames)
1202                 return false;
1203
1204         oa->data[0] = (java_objectheader *) classes;
1205         oa->data[1] = (java_objectheader *) methodnames;
1206
1207         for (i = 0, current = &(buffer->start[0]); i < size; i++, current++) {
1208                 c = current->method->class;
1209
1210                 classes->data[i] = (java_objectheader *) c;
1211                 str = javastring_new(current->method->name);
1212
1213                 if (!str)
1214                         return false;
1215
1216                 methodnames->data[i] = (java_objectheader *) str;
1217         }
1218
1219         *target = oa;
1220
1221         return true;
1222 }
1223
1224
1225 java_objectarray *cacao_getStackForVMAccessController(void)
1226 {
1227         java_objectarray *result = NULL;
1228
1229 #ifdef ENABLE_JVMTI
1230         if (!cacao_stacktrace_fillInStackTrace((void **) &result,
1231                                                                                    &getStackCollector,NULL))
1232 #else
1233         if (!cacao_stacktrace_fillInStackTrace((void **) &result,
1234                                                                                    &getStackCollector))
1235 #endif
1236                 return NULL;
1237
1238         return result;
1239 }
1240
1241
1242 /* stacktrace_print_trace_from_buffer ******************************************
1243
1244    Print the stacktrace of a given stackTraceBuffer with CACAO intern
1245    methods (no Java help). This method is used by
1246    stacktrace_dump_trace and builtin_trace_exception.
1247
1248 *******************************************************************************/
1249
1250 static void stacktrace_print_trace_from_buffer(stackTraceBuffer *stb)
1251 {
1252         stacktraceelement *ste;
1253         methodinfo        *m;
1254         s4                 i;
1255
1256         ste = stb->start;
1257
1258         for (i = 0; i < stb->size; i++, ste++) {
1259                 m = ste->method;
1260
1261                 printf("\tat ");
1262                 utf_display_classname(m->class->name);
1263                 printf(".");
1264                 utf_display(m->name);
1265                 utf_display(m->descriptor);
1266
1267                 if (m->flags & ACC_NATIVE) {
1268                         puts("(Native Method)");
1269
1270                 } else {
1271                         printf("(");
1272                         utf_display(m->class->sourcefile);
1273                         printf(":%d)\n", (u4) ste->linenumber);
1274                 }
1275         }
1276
1277         /* just to be sure */
1278
1279         fflush(stdout);
1280 }
1281
1282
1283 /* stacktrace_dump_trace *******************************************************
1284
1285    This method is call from signal_handler_sigusr1 to dump the
1286    stacktrace of the current thread to stdout.
1287
1288 *******************************************************************************/
1289
1290 void stacktrace_dump_trace(void)
1291 {
1292         stackTraceBuffer      *buffer;
1293
1294 #if 0
1295         /* get thread stackframeinfo */
1296
1297         info = &THREADINFO->_stackframeinfo;
1298
1299         /* fill stackframeinfo structure */
1300
1301         tmp.oldThreadspecificHeadValue = *info;
1302         tmp.addressOfThreadspecificHead = info;
1303         tmp.method = NULL;
1304         tmp.sp = NULL;
1305         tmp.ra = _mc->gregs[REG_RIP];
1306
1307         *info = &tmp;
1308 #endif
1309
1310         /* generate stacktrace */
1311
1312         cacao_stacktrace_NormalTrace((void **) &buffer);
1313
1314         /* print stacktrace */
1315
1316         if (buffer) {
1317                 stacktrace_print_trace_from_buffer(buffer);
1318
1319         } else {
1320                 puts("\t<<No stacktrace available>>");
1321                 fflush(stdout);
1322         }
1323 }
1324
1325
1326 /* stacktrace_print_trace ******************************************************
1327
1328    Print the stacktrace of a given exception. More or less a wrapper
1329    to stacktrace_print_trace_from_buffer.
1330
1331 *******************************************************************************/
1332
1333 void stacktrace_print_trace(java_objectheader *xptr)
1334 {
1335         java_lang_Throwable   *t;
1336         java_lang_VMThrowable *vmt;
1337         stackTraceBuffer      *stb;
1338
1339         t = (java_lang_Throwable *) xptr;
1340
1341         /* now print the stacktrace */
1342
1343         vmt = t->vmState;
1344         stb = (stackTraceBuffer *) vmt->vmData;
1345
1346         stacktrace_print_trace_from_buffer(stb);
1347 }
1348
1349
1350 /*
1351  * These are local overrides for various environment variables in Emacs.
1352  * Please do not remove this and leave it at the end of the file, where
1353  * Emacs will automagically detect them.
1354  * ---------------------------------------------------------------------
1355  * Local variables:
1356  * mode: c
1357  * indent-tabs-mode: t
1358  * c-basic-offset: 4
1359  * tab-width: 4
1360  * End:
1361  */