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