1593bd2fa4ba22a8b67b26f37c5060713ead3818
[cacao.git] / src / vm / jit / stacktrace.cpp
1 /* src/vm/jit/stacktrace.cpp - machine independent stacktrace system
2
3    Copyright (C) 1996-2011
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5    Copyright (C) 2009 Theobroma Systems Ltd.
6
7    This file is part of CACAO.
8
9    This program is free software; you can redistribute it and/or
10    modify it under the terms of the GNU General Public License as
11    published by the Free Software Foundation; either version 2, or (at
12    your option) any later version.
13
14    This program is distributed in the hope that it will be useful, but
15    WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17    General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22    02110-1301, USA.
23
24 */
25
26
27 #include "config.h"
28
29 #include <assert.h>
30 #include <stdint.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include "vm/types.h"
35
36 #include "arch.h"
37 #include "md.h"
38
39 #include "mm/gc.hpp"
40 #include "mm/memory.hpp"
41
42 #include "vm/jit/stacktrace.hpp"
43
44 #include "native/llni.h"
45
46 #include "threads/thread.hpp"
47
48 #include "toolbox/logging.hpp"
49
50 #include "vm/array.hpp"
51 #include "vm/jit/builtin.hpp"
52 #include "vm/class.hpp"
53 #include "vm/cycles-stats.h"
54 #include "vm/exceptions.hpp"
55 #include "vm/globals.hpp"
56 #include "vm/javaobjects.hpp"
57 #include "vm/loader.hpp"
58 #include "vm/method.hpp"
59 #include "vm/options.h"
60 #include "vm/string.hpp"
61 #include "vm/vm.hpp"
62
63 #include "vm/jit/asmpart.h"
64 #include "vm/jit/codegen-common.hpp"
65 #include "vm/jit/linenumbertable.hpp"
66 #include "vm/jit/methodheader.h"
67 #include "vm/jit/methodtree.h"
68
69
70 // FIXME Use C-linkage for now.
71 extern "C" {
72
73 /* global variables ***********************************************************/
74
75 CYCLES_STATS_DECLARE(stacktrace_overhead        , 100, 1)
76 CYCLES_STATS_DECLARE(stacktrace_fillInStackTrace, 40,  5000)
77 CYCLES_STATS_DECLARE(stacktrace_get,              40,  5000)
78 CYCLES_STATS_DECLARE(stacktrace_getClassContext , 40,  5000)
79 CYCLES_STATS_DECLARE(stacktrace_getCurrentClass , 40,  5000)
80 CYCLES_STATS_DECLARE(stacktrace_get_stack       , 40,  10000)
81
82
83 /* stacktrace_stackframeinfo_add ***********************************************
84
85    Fills a stackframe info structure with the given or calculated
86    values and adds it to the chain.
87
88 *******************************************************************************/
89
90 void stacktrace_stackframeinfo_add(stackframeinfo_t* sfi, void* pv, void* sp, void* ra, void* xpc)
91 {
92         stackframeinfo_t *currentsfi;
93         codeinfo         *code;
94 #if defined(ENABLE_JIT)
95         s4                 framesize;
96 #endif
97
98         /* Get current stackframe info. */
99
100         currentsfi = threads_get_current_stackframeinfo();
101
102         /* sometimes we don't have pv handy (e.g. in asmpart.S:
103        L_asm_call_jit_compiler_exception or in the interpreter). */
104
105         if (pv == NULL) {
106 #if defined(ENABLE_INTRP)
107                 if (opt_intrp)
108                         pv = methodtree_find(ra);
109                 else
110 #endif
111                         {
112 #if defined(ENABLE_JIT)
113 # if defined(__SPARC_64__)
114                                 pv = md_get_pv_from_stackframe(sp);
115 # else
116                                 pv = md_codegen_get_pv_from_pc(ra);
117 # endif
118 #endif
119                         }
120         }
121
122         /* Get codeinfo pointer for the parent Java method. */
123
124         code = code_get_codeinfo_for_pv(pv);
125
126         /* XXX */
127         /*      assert(m != NULL); */
128
129 #if defined(ENABLE_JIT)
130 # if defined(ENABLE_INTRP)
131         /* When using the interpreter, we pass RA to the function. */
132
133         if (!opt_intrp) {
134 # endif
135 # if defined(__I386__) || defined(__X86_64__) || defined(__S390__) || defined(__M68K__)
136                 /* On i386 and x86_64 we always have to get the return address
137                    from the stack. */
138                 /* m68k has return address on stack always */
139                 /* On S390 we use REG_RA as REG_ITMP3, so we have always to get
140                    the RA from stack. */
141
142                 framesize = md_stacktrace_get_framesize(code);
143
144                 ra = md_stacktrace_get_returnaddress(sp, framesize);
145 # else
146                 /* If the method is a non-leaf function, we need to get the
147                    return address from the stack.  For leaf functions the
148                    return address is set correctly.  This makes the assembler
149                    and the signal handler code simpler.  The code is NULL is
150                    the asm_vm_call_method special case. */
151
152                 if ((code == NULL) || !code_is_leafmethod(code)) {
153                         framesize = md_stacktrace_get_framesize(code);
154
155                         ra = md_stacktrace_get_returnaddress(sp, framesize);
156                 }
157 # endif
158 # if defined(ENABLE_INTRP)
159         }
160 # endif
161 #endif
162
163         /* Calculate XPC when not given.  The XPC is then the return
164            address of the current method minus 1 because the RA points to
165            the instruction after the call instruction.  This is required
166            e.g. for method stubs. */
167
168         if (xpc == NULL) {
169                 xpc = (void *) (((intptr_t) ra) - 1);
170         }
171
172         /* Fill new stackframeinfo structure. */
173
174         sfi->prev = currentsfi;
175         sfi->code = code;
176         sfi->pv   = pv;
177         sfi->sp   = sp;
178         sfi->ra   = ra;
179         sfi->xpc  = xpc;
180
181 #if !defined(NDEBUG)
182         if (opt_DebugStackFrameInfo) {
183                 log_start();
184                 log_print("[stackframeinfo add   : sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
185                                   sfi, sfi->code->m, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
186                 method_print(sfi->code->m);
187                 log_print("]");
188                 log_finish();
189         }
190 #endif
191
192         /* Store new stackframeinfo pointer. */
193
194         threads_set_current_stackframeinfo(sfi);
195
196         /* set the native world flag for the current thread */
197         /* ATTENTION: This flag tells the GC how to treat this thread in case of
198            a collection. Set this flag _after_ a valid stackframe info was set. */
199
200         THREAD_NATIVEWORLD_ENTER;
201 }
202
203
204 /* stacktrace_stackframeinfo_remove ********************************************
205
206    Remove the given stackframeinfo from the chain in the current
207    thread.
208
209 *******************************************************************************/
210
211 void stacktrace_stackframeinfo_remove(stackframeinfo_t *sfi)
212 {
213         /* Clear the native world flag for the current thread. */
214         /* ATTENTION: Clear this flag _before_ removing the stackframe info. */
215
216         THREAD_NATIVEWORLD_EXIT;
217
218 #if !defined(NDEBUG)
219         if (opt_DebugStackFrameInfo) {
220                 log_start();
221                 log_print("[stackframeinfo remove: sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
222                                   sfi, sfi->code->m, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
223                 method_print(sfi->code->m);
224                 log_print("]");
225                 log_finish();
226         }
227 #endif
228
229         /* Set previous stackframe info. */
230
231         threads_set_current_stackframeinfo(sfi->prev);
232 }
233
234
235 /* stacktrace_stackframeinfo_fill **********************************************
236
237    Fill the temporary stackframeinfo structure with the values given
238    in sfi.
239
240    IN:
241        tmpsfi ... temporary stackframeinfo
242        sfi ...... stackframeinfo to be used in the next iteration
243
244 *******************************************************************************/
245
246 static inline void stacktrace_stackframeinfo_fill(stackframeinfo_t *tmpsfi, stackframeinfo_t *sfi)
247 {
248         /* Sanity checks. */
249
250         assert(tmpsfi != NULL);
251         assert(sfi != NULL);
252
253         /* Fill the temporary stackframeinfo. */
254
255         tmpsfi->code = sfi->code;
256         tmpsfi->pv   = sfi->pv;
257         tmpsfi->sp   = sfi->sp;
258         tmpsfi->ra   = sfi->ra;
259         tmpsfi->xpc  = sfi->xpc;
260
261         /* Set the previous stackframe info of the temporary one to the
262            next in the chain. */
263
264         tmpsfi->prev = sfi->prev;
265
266 #if !defined(NDEBUG)
267         if (opt_DebugStackTrace)
268                 log_println("[stacktrace fill]");
269 #endif
270 }
271
272
273 /* stacktrace_stackframeinfo_next **********************************************
274
275    Walk the stack (or the stackframeinfo-chain) to the next method and
276    return the new stackframe values in the temporary stackframeinfo
277    passed.
278
279    ATTENTION: This function does NOT skip builtin methods!
280
281    IN:
282        tmpsfi ... temporary stackframeinfo of current method
283
284 *******************************************************************************/
285
286 static inline void stacktrace_stackframeinfo_next(stackframeinfo_t *tmpsfi)
287 {
288         codeinfo         *code;
289         void             *pv;
290         void             *sp;
291         void             *ra;
292         void             *xpc;
293         uint32_t          framesize;
294         stackframeinfo_t *prevsfi;
295
296         /* Sanity check. */
297
298         assert(tmpsfi != NULL);
299
300         /* Get values from the stackframeinfo. */
301
302         code = tmpsfi->code;
303         pv   = tmpsfi->pv;
304         sp   = tmpsfi->sp;
305         ra   = tmpsfi->ra;
306         xpc  = tmpsfi->xpc;
307  
308         /* Get the current stack frame size. */
309
310         framesize = md_stacktrace_get_framesize(code);
311
312         /* Get the RA of the current stack frame (RA to the parent Java
313            method) if the current method is a non-leaf method.  Otherwise
314            the value in the stackframeinfo is correct (from the signal
315            handler). */
316
317 #if defined(ENABLE_JIT)
318 # if defined(ENABLE_INTRP)
319         if (opt_intrp)
320                 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
321         else
322 # endif
323                 {
324                         if (!code_is_leafmethod(code))
325                                 ra = md_stacktrace_get_returnaddress(sp, framesize);
326                 }
327 #else
328         ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
329 #endif
330
331         /* Get the PV for the parent Java method. */
332
333 #if defined(ENABLE_INTRP)
334         if (opt_intrp)
335                 pv = methodtree_find(ra);
336         else
337 #endif
338                 {
339 #if defined(ENABLE_JIT)
340 # if defined(__SPARC_64__)
341                         sp = md_get_framepointer(sp);
342                         pv = md_get_pv_from_stackframe(sp);
343 # else
344                         pv = md_codegen_get_pv_from_pc(ra);
345 # endif
346 #endif
347                 }
348
349         /* Get the codeinfo pointer for the parent Java method. */
350
351         code = code_get_codeinfo_for_pv(pv);
352
353         /* Calculate the SP for the parent Java method. */
354
355 #if defined(ENABLE_INTRP)
356         if (opt_intrp)
357                 sp = *(u1 **) (sp - framesize);
358         else
359 #endif
360                 {
361 #if STACKFRMAE_RA_BETWEEN_FRAMES
362                         sp = (void *) (((intptr_t) sp) + framesize + SIZEOF_VOID_P);
363 #elif defined(__SPARC_64__)
364                         /* already has the new sp */
365 #else
366                         sp = (void *) (((intptr_t) sp) + framesize);
367 #endif
368                 }
369
370         /* If the new codeinfo pointer is NULL we reached a
371            asm_vm_call_method function.  In this case we get the next
372            values from the previous stackframeinfo in the chain.
373            Otherwise the new values have been calculated before. */
374
375         if (code == NULL) {
376                 prevsfi = tmpsfi->prev;
377
378                 /* If the previous stackframeinfo in the chain is NULL we
379                    reached the top of the stacktrace.  We set code and prev to
380                    NULL to mark the end, which is checked in
381                    stacktrace_stackframeinfo_end_check. */
382
383                 if (prevsfi == NULL) {
384                         tmpsfi->code = NULL;
385                         tmpsfi->prev = NULL;
386                         return;
387                 }
388
389                 /* Fill the temporary stackframeinfo with the new values. */
390
391                 stacktrace_stackframeinfo_fill(tmpsfi, prevsfi);
392         }
393         else {
394                 /* Store the new values in the stackframeinfo.  NOTE: We
395                    subtract 1 from the RA to get the XPC, because the RA
396                    points to the instruction after the call instruction. */
397
398                 tmpsfi->code = code;
399                 tmpsfi->pv   = pv;
400                 tmpsfi->sp   = sp;
401                 tmpsfi->ra   = ra;
402                 tmpsfi->xpc  = (void *) (((intptr_t) ra) - 1);
403         }
404
405 #if !defined(NDEBUG)
406         /* Print current method information. */
407
408         if (opt_DebugStackTrace) {
409                 log_start();
410                 log_print("[stacktrace: method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
411                                   tmpsfi->code->m, tmpsfi->pv, tmpsfi->sp, tmpsfi->ra,
412                                   tmpsfi->xpc);
413                 method_print(tmpsfi->code->m);
414                 log_print("]");
415                 log_finish();
416         }
417 #endif
418 }
419
420
421 /* stacktrace_stackframeinfo_end_check *****************************************
422
423    Check if we reached the end of the stacktrace.
424
425    IN:
426        tmpsfi ... temporary stackframeinfo of current method
427
428    RETURN:
429        true .... the end is reached
430            false ... the end is not reached
431
432 *******************************************************************************/
433
434 static inline bool stacktrace_stackframeinfo_end_check(stackframeinfo_t *tmpsfi)
435 {
436         /* Sanity check. */
437
438         assert(tmpsfi != NULL);
439
440         if ((tmpsfi->code == NULL) && (tmpsfi->prev == NULL)) {
441 #if !defined(NDEBUG)
442                 if (opt_DebugStackTrace)
443                         log_println("[stacktrace stop]");
444 #endif
445
446                 return true;
447         }
448
449         return false;
450 }
451
452
453 /* stacktrace_depth ************************************************************
454
455    Calculates and returns the depth of the current stacktrace.
456
457    IN:
458        sfi ... stackframeinfo where to start the stacktrace
459
460    RETURN:
461        depth of the stacktrace
462
463 *******************************************************************************/
464
465 static int stacktrace_depth(stackframeinfo_t *sfi)
466 {
467         stackframeinfo_t  tmpsfi;
468         int               depth;
469         methodinfo       *m;
470
471 #if !defined(NDEBUG)
472         if (opt_DebugStackTrace)
473                 log_println("[stacktrace_depth]");
474 #endif
475
476         /* XXX This is not correct, but a workaround for threads-dump for
477            now. */
478 /*      assert(sfi != NULL); */
479         if (sfi == NULL)
480                 return 0;
481
482         /* Iterate over all stackframes. */
483
484         depth = 0;
485
486         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
487                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
488                  stacktrace_stackframeinfo_next(&tmpsfi)) {
489                 /* Get methodinfo. */
490
491                 m = tmpsfi.code->m;
492
493                 /* Skip builtin methods. */
494
495                 if (m->flags & ACC_METHOD_BUILTIN)
496                         continue;
497
498                 depth++;
499         }
500
501         return depth;
502 }
503
504
505 /* stacktrace_get **************************************************************
506
507    Builds and returns a stacktrace starting from the given stackframe
508    info and returns the stacktrace structure wrapped in a Java
509    byte-array to not confuse the GC.
510
511    IN:
512        sfi ... stackframe info to start stacktrace from
513
514    RETURN:
515        stacktrace as Java byte-array
516
517 *******************************************************************************/
518
519 java_handle_bytearray_t *stacktrace_get(stackframeinfo_t *sfi)
520 {
521         stackframeinfo_t    tmpsfi;
522         int                 depth;
523         int32_t             ba_size;
524         stacktrace_t       *st;
525         stacktrace_entry_t *ste;
526         methodinfo         *m;
527         bool                skip_fillInStackTrace;
528         bool                skip_init;
529
530         CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
531
532 #if !defined(NDEBUG)
533         if (opt_DebugStackTrace)
534                 log_println("[stacktrace_get]");
535 #endif
536
537         skip_fillInStackTrace = true;
538         skip_init             = true;
539
540         depth = stacktrace_depth(sfi);
541
542         if (depth == 0)
543                 return NULL;
544
545         /* Allocate memory from the GC heap and copy the stacktrace
546            buffer. */
547         /* ATTENTION: Use a Java byte-array for this to not confuse the
548            GC. */
549         /* FIXME: We waste some memory here as we skip some entries
550            later. */
551
552         ba_size = sizeof(stacktrace_t) + sizeof(stacktrace_entry_t) * depth;
553
554         ByteArray ba(ba_size);
555
556         if (ba.is_null())
557                 goto return_NULL;
558
559         /* Get a stacktrace entry pointer. */
560         /* ATTENTION: We need a critical section here because we use the
561            byte-array data pointer directly. */
562
563         LLNI_CRITICAL_START;
564
565         st = (stacktrace_t *) ba.get_raw_data_ptr();
566
567         ste = st->entries;
568
569         /* Iterate over the whole stack. */
570
571         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
572                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
573                  stacktrace_stackframeinfo_next(&tmpsfi)) {
574                 /* Get the methodinfo. */
575
576                 m = tmpsfi.code->m;
577
578                 /* Skip builtin methods. */
579
580                 if (m->flags & ACC_METHOD_BUILTIN)
581                         continue;
582
583                 /* This logic is taken from
584                    hotspot/src/share/vm/classfile/javaClasses.cpp
585                    (java_lang_Throwable::fill_in_stack_trace). */
586
587                 if (skip_fillInStackTrace == true) {
588                         /* Check "fillInStackTrace" only once, so we negate the
589                            flag after the first time check. */
590
591 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
592                         /* For GNU Classpath we also need to skip
593                            VMThrowable.fillInStackTrace(). */
594
595                         if ((m->clazz == class_java_lang_VMThrowable) &&
596                                 (m->name  == utf_fillInStackTrace))
597                                 continue;
598 #endif
599
600                         skip_fillInStackTrace = false;
601
602                         if (m->name == utf_fillInStackTrace)
603                                 continue;
604                 }
605
606                 /* Skip <init> methods of the exceptions klass.  If there is
607                    <init> methods that belongs to a superclass of the
608                    exception we are going to skipping them in stack trace. */
609
610                 if (skip_init == true) {
611                         if ((m->name == utf_init) &&
612                                 (class_issubclass(m->clazz, class_java_lang_Throwable))) {
613                                 continue;
614                         }
615                         else {
616                                 /* If no "Throwable.init()" method found, we stop
617                                    checking it next time. */
618
619                                 skip_init = false;
620                         }
621                 }
622
623                 /* Store the stacktrace entry and increment the pointer. */
624
625                 ste->code = tmpsfi.code;
626                 ste->pc   = tmpsfi.xpc;
627
628                 ste++;
629         }
630
631         /* Store the number of entries in the stacktrace structure. */
632
633         st->length = ste - st->entries;
634
635         LLNI_CRITICAL_END;
636
637         /* release dump memory */
638
639 /*      dump_release(dumpsize); */
640
641         CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
642                                                                    stacktrace_overhead)
643         return ba.get_handle();
644
645 return_NULL:
646 /*      dump_release(dumpsize); */
647
648         CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
649                                                                    stacktrace_overhead)
650
651         return NULL;
652 }
653
654
655 /* stacktrace_get_current ******************************************************
656
657    Builds and returns a stacktrace from the current thread and returns
658    the stacktrace structure wrapped in a Java byte-array to not
659    confuse the GC.
660
661    RETURN:
662        stacktrace as Java byte-array
663
664 *******************************************************************************/
665
666 java_handle_bytearray_t *stacktrace_get_current(void)
667 {
668         stackframeinfo_t        *sfi;
669         java_handle_bytearray_t *ba;
670
671         sfi = threads_get_current_stackframeinfo();
672         ba  = stacktrace_get(sfi);
673
674         return ba;
675 }
676
677
678 /**
679  * Creates a java.lang.StackTraceElement for one element of the given
680  * stacktrace.
681  *
682  * @param st Given stacktrace.
683  * @param index Index of element inside stacktrace.
684  * @return The filled StackTraceElement object.
685  */
686 #if defined(ENABLE_JAVASE)
687 java_handle_t* stacktrace_get_StackTraceElement(stacktrace_t* st, int32_t index)
688 {
689         assert(st != NULL);
690
691         if ((index < 0) || (index >= st->length)) {
692                 /* XXX This should be an IndexOutOfBoundsException (check this
693                    again). */
694                 exceptions_throw_arrayindexoutofboundsexception();
695                 return NULL;
696         }
697
698         // Get the stacktrace entry.
699         stacktrace_entry_t* ste = &(st->entries[index]);
700
701         // Get the codeinfo, methodinfo and classinfo.
702         codeinfo*   code = ste->code;
703         methodinfo* m    = code->m;
704         classinfo*  c    = m->clazz;
705
706         // Get filename.
707         java_handle_t* filename;
708
709         if (!(m->flags & ACC_NATIVE)) {
710                 if (c->sourcefile != NULL)
711                         filename = javastring_new(c->sourcefile);
712                 else
713                         filename = NULL;
714         }
715         else
716                 filename = NULL;
717
718         // Get line number.
719         int32_t linenumber;
720
721         if (m->flags & ACC_NATIVE) {
722 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
723                 linenumber = -1;
724 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
725                 linenumber = -2;
726 #else
727 # error unknown classpath configuration
728 #endif
729         }
730         else {
731                 // FIXME linenumbertable->find could change the methodinfo
732                 // pointer when hitting an inlined method.
733                 linenumber = code->linenumbertable->find(&m, ste->pc);
734                 linenumber = (linenumber == 0) ? -1 : linenumber;
735         }
736
737         // Get declaring class name.
738         java_handle_t* declaringclass = class_get_classname(c);
739
740 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
741         // Allocate a new StackTraceElement object.
742         java_handle_t* h = builtin_new(class_java_lang_StackTraceElement);
743
744         if (h == NULL)
745                         return NULL;
746
747         java_lang_StackTraceElement jlste(h, filename, linenumber, declaringclass, javastring_new(m->name), ((m->flags & ACC_NATIVE) ? 1 : 0));
748 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
749         // Allocate a new StackTraceElement object.
750         java_lang_StackTraceElement jlste(declaringclass, javastring_new(m->name), filename, linenumber);
751
752         if (jlste.is_null())
753                 return NULL;
754 #else
755 # error unknown classpath configuration
756 #endif
757
758         return jlste.get_handle();
759 }
760 #endif
761
762
763 /**
764  * Creates a complete array of java.lang.StackTraceElement objects
765  * for the given stacktrace.
766  *
767  * @param st Given stacktrace.
768  * @return Array of filled StackTraceElement objects.
769  */
770 #if defined(ENABLE_JAVASE)
771 java_handle_objectarray_t* stacktrace_get_StackTraceElements(stacktrace_t* st)
772 {
773         // Get length of stacktrace. If stacktrace is not available
774         // an empty array should be returned.
775         int32_t length = (st != NULL) ? st->length : 0;
776
777         // Create the stacktrace element array.
778         ObjectArray oa(length, class_java_lang_StackTraceElement);
779
780         if (oa.is_null())
781                 return NULL;
782
783         // Iterate over all stacktrace elements.
784         for (int i = 0; i < length; i++) {
785
786                 // Get stacktrace element at current index.
787                 java_handle_t* h = stacktrace_get_StackTraceElement(st, i);
788
789                 if (h == NULL)
790                         return NULL;
791
792                 // Store stacktrace element in array.
793                 oa.set_element(i, h);
794         }
795
796         return oa.get_handle();
797 }
798 #endif
799
800
801 /* stacktrace_get_caller_class *************************************************
802
803    Get the class on the stack at the given depth.  This function skips
804    various special classes or methods.
805
806    ARGUMENTS:
807        depth ... depth to get caller class of
808
809    RETURN:
810        caller class
811
812 *******************************************************************************/
813
814 #if defined(ENABLE_JAVASE)
815 classinfo *stacktrace_get_caller_class(int depth)
816 {
817         stackframeinfo_t *sfi;
818         stackframeinfo_t  tmpsfi;
819         methodinfo       *m;
820         classinfo        *c;
821         int               i;
822
823 #if !defined(NDEBUG)
824         if (opt_DebugStackTrace)
825                 log_println("[stacktrace_get_caller_class]");
826 #endif
827
828         /* Get the stackframeinfo of the current thread. */
829
830         sfi = threads_get_current_stackframeinfo();
831
832         /* Iterate over the whole stack until we reached the requested
833            depth. */
834
835         i = 0;
836
837         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
838                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
839                  stacktrace_stackframeinfo_next(&tmpsfi)) {
840
841                 m = tmpsfi.code->m;
842                 c = m->clazz;
843
844                 /* Skip builtin methods. */
845
846                 if (m->flags & ACC_METHOD_BUILTIN)
847                         continue;
848
849 #if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
850                 /* NOTE: See hotspot/src/share/vm/runtime/vframe.cpp
851                    (vframeStreamCommon::security_get_caller_frame). */
852
853                 /* This is java.lang.reflect.Method.invoke(), skip it. */
854
855                 if (m == method_java_lang_reflect_Method_invoke)
856                         continue;
857
858                 /* This is an auxiliary frame, skip it. */
859
860                 if (class_issubclass(c, class_sun_reflect_MagicAccessorImpl))
861                         continue;
862 #endif
863
864                 /* We reached the requested depth. */
865
866                 if (i >= depth)
867                         return c;
868
869                 i++;
870         }
871
872         return NULL;
873 }
874 #endif
875
876
877 /**
878  * Returns the first non-null (user-defined) classloader on the stack.
879  *
880  * @return The first non-null classloader or NULL if none is found.
881  */
882 classloader_t* stacktrace_first_nonnull_classloader(void)
883 {
884         stackframeinfo_t *sfi;
885         stackframeinfo_t  tmpsfi;
886         methodinfo       *m;
887         classloader_t    *cl;
888
889 #if !defined(NDEBUG)
890         if (opt_DebugStackTrace)
891                 log_println("[stacktrace_first_nonnull_classloader]");
892 #endif
893
894         /* Get the stackframeinfo of the current thread. */
895
896         sfi = threads_get_current_stackframeinfo();
897
898         /* Iterate over the whole stack. */
899
900         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
901                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
902                  stacktrace_stackframeinfo_next(&tmpsfi)) {
903
904                 m  = tmpsfi.code->m;
905                 cl = class_get_classloader(m->clazz);
906
907                 if (cl != NULL)
908                         return cl;
909         }
910
911         return NULL;
912 }
913
914
915 /**
916  * Checks if a given classloader is equal to the the second classloader
917  * or one of its ancestors (parents).
918  *
919  * XXX: This helper method should be moved to java_lang_Classloader.
920  */
921 #if defined(ENABLE_JAVASE)
922 static bool is_ancestor_of(classloader_t* loader, classloader_t* parent)
923 {
924         // Iterate over chain of possible parents.
925         while (parent != NULL) {
926
927                 // Check if given loader is parent.
928                 if (loader == parent)
929                         return true;
930
931                 // Jump to next parent.
932                 java_lang_ClassLoader jlcl(parent);
933                 parent = jlcl.get_parent();
934         }
935
936         return false;
937 }
938 #endif /* defined(ENABLE_JAVASE) */
939
940
941 /**
942  * Returns the first non-system (user-defined) classloader on the stack.
943  * A non-system classloader is a non-null classloader being not equal to
944  * the system classloader (or one of its ancestors).
945  *
946  * @return The first non-system classloader or NULL if none is found.
947  */
948 #if defined(ENABLE_JAVASE)
949 classloader_t* stacktrace_first_nonsystem_classloader(void)
950 {
951         stackframeinfo_t *sfi;
952         stackframeinfo_t  tmpsfi;
953         methodinfo       *m;
954         classloader_t    *cl;
955         classloader_t    *syscl;
956
957 #if !defined(NDEBUG)
958         if (opt_DebugStackTrace)
959                 log_println("[stacktrace_first_nonsystem_classloader]");
960 #endif
961
962         // Get the stackframeinfo of the current thread.
963         sfi = threads_get_current_stackframeinfo();
964
965         // Get the system class class loader.
966         syscl = java_lang_ClassLoader::invoke_getSystemClassLoader();
967
968         // Iterate over the whole stack.
969         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
970                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
971                  stacktrace_stackframeinfo_next(&tmpsfi)) {
972
973                 m  = tmpsfi.code->m;
974                 cl = class_get_classloader(m->clazz);
975
976                 if (cl == NULL)
977                         continue;
978
979                 // XXX if a method in a class in a trusted loader is in a
980                 // doPrivileged, return NULL (or break) here.
981
982                 if (!is_ancestor_of(cl, syscl))
983                         return cl;
984         }
985
986         return NULL;
987 }
988 #endif /* defined(ENABLE_JAVASE) */
989
990
991 /* stacktrace_getClassContext **************************************************
992
993    Creates a Class context array.
994
995    RETURN VALUE:
996       the array of java.lang.Class objects, or
997           NULL if an exception has been thrown
998
999 *******************************************************************************/
1000
1001 java_handle_objectarray_t *stacktrace_getClassContext(void)
1002 {
1003         stackframeinfo_t           *sfi;
1004         stackframeinfo_t            tmpsfi;
1005         int                         depth;
1006         int                         i;
1007         methodinfo                 *m;
1008
1009         CYCLES_STATS_DECLARE_AND_START
1010
1011 #if !defined(NDEBUG)
1012         if (opt_DebugStackTrace)
1013                 log_println("[stacktrace_getClassContext]");
1014 #endif
1015
1016         sfi = threads_get_current_stackframeinfo();
1017
1018         /* Get the depth of the current stack. */
1019
1020         depth = stacktrace_depth(sfi);
1021
1022         /* The first stackframe corresponds to the method whose
1023            implementation calls this native function.  We remove that
1024            entry. */
1025
1026         depth--;
1027         stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1028         stacktrace_stackframeinfo_next(&tmpsfi);
1029
1030         /* Allocate the Class array. */
1031
1032         ClassArray ca(depth);
1033
1034         if (ca.is_null()) {
1035                 CYCLES_STATS_END(stacktrace_getClassContext);
1036
1037                 return NULL;
1038         }
1039
1040         /* Fill the Class array from the stacktrace list. */
1041         /* Iterate over the whole stack. */
1042
1043         i = 0;
1044
1045         for (;
1046                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1047                  stacktrace_stackframeinfo_next(&tmpsfi)) {
1048                 /* Get methodinfo. */
1049
1050                 m = tmpsfi.code->m;
1051
1052                 /* Skip builtin methods. */
1053
1054                 if (m->flags & ACC_METHOD_BUILTIN)
1055                         continue;
1056
1057                 /* Store the class in the array. */
1058
1059                 ca.set_element(i, m->clazz);
1060
1061                 i++;
1062         }
1063
1064         LLNI_CRITICAL_END;
1065
1066         CYCLES_STATS_END(stacktrace_getClassContext)
1067
1068         return ca.get_handle();
1069 }
1070
1071
1072 /* stacktrace_getCurrentClass **************************************************
1073
1074    Find the current class by walking the stack trace.
1075
1076    Quote from the JNI documentation:
1077          
1078    In the Java 2 Platform, FindClass locates the class loader
1079    associated with the current native method.  If the native code
1080    belongs to a system class, no class loader will be
1081    involved. Otherwise, the proper class loader will be invoked to
1082    load and link the named class. When FindClass is called through the
1083    Invocation Interface, there is no current native method or its
1084    associated class loader. In that case, the result of
1085    ClassLoader.getBaseClassLoader is used."
1086
1087 *******************************************************************************/
1088
1089 #if defined(ENABLE_JAVASE)
1090 classinfo *stacktrace_get_current_class(void)
1091 {
1092         stackframeinfo_t *sfi;
1093         stackframeinfo_t  tmpsfi;
1094         methodinfo       *m;
1095
1096         CYCLES_STATS_DECLARE_AND_START;
1097
1098 #if !defined(NDEBUG)
1099         if (opt_DebugStackTrace)
1100                 log_println("[stacktrace_get_current_class]");
1101 #endif
1102
1103         /* Get the stackframeinfo of the current thread. */
1104
1105         sfi = threads_get_current_stackframeinfo();
1106
1107         /* If the stackframeinfo is NULL then FindClass is called through
1108            the Invocation Interface and we return NULL */
1109
1110         if (sfi == NULL) {
1111                 CYCLES_STATS_END(stacktrace_getCurrentClass);
1112
1113                 return NULL;
1114         }
1115
1116         /* Iterate over the whole stack. */
1117
1118         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1119                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1120                  stacktrace_stackframeinfo_next(&tmpsfi)) {
1121                 /* Get the methodinfo. */
1122
1123                 m = tmpsfi.code->m;
1124
1125                 if (m->clazz == class_java_security_PrivilegedAction) {
1126                         CYCLES_STATS_END(stacktrace_getCurrentClass);
1127
1128                         return NULL;
1129                 }
1130
1131                 if (m->clazz != NULL) {
1132                         CYCLES_STATS_END(stacktrace_getCurrentClass);
1133
1134                         return m->clazz;
1135                 }
1136         }
1137
1138         /* No Java method found on the stack. */
1139
1140         CYCLES_STATS_END(stacktrace_getCurrentClass);
1141
1142         return NULL;
1143 }
1144 #endif /* ENABLE_JAVASE */
1145
1146
1147 /* stacktrace_get_stack ********************************************************
1148
1149    Create a 2-dimensional array for java.security.VMAccessControler.
1150
1151    RETURN VALUE:
1152       the arrary, or
1153          NULL if an exception has been thrown
1154
1155 *******************************************************************************/
1156
1157 #if defined(ENABLE_JAVASE) && defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
1158 java_handle_objectarray_t *stacktrace_get_stack(void)
1159 {
1160         stackframeinfo_t *sfi;
1161         stackframeinfo_t  tmpsfi;
1162         int               depth;
1163         methodinfo       *m;
1164         java_handle_t    *string;
1165         int               i;
1166
1167         CYCLES_STATS_DECLARE_AND_START
1168
1169 #if !defined(NDEBUG)
1170         if (opt_DebugStackTrace)
1171                 log_println("[stacktrace_get_stack]");
1172 #endif
1173
1174         /* Get the stackframeinfo of the current thread. */
1175
1176         sfi = threads_get_current_stackframeinfo();
1177
1178         /* Get the depth of the current stack. */
1179
1180         depth = stacktrace_depth(sfi);
1181
1182         if (depth == 0)
1183                 return NULL;
1184
1185         /* Allocate the required arrays. */
1186
1187         ObjectArray oa(2, arrayclass_java_lang_Object);
1188         ClassArray  classes(depth);
1189         ObjectArray methodnames(depth, class_java_lang_String);
1190
1191         if (oa.is_null())
1192                 goto return_NULL;
1193
1194         if (classes.is_null())
1195                 goto return_NULL;
1196
1197         if (methodnames.is_null())
1198                 goto return_NULL;
1199
1200         /* Set up the 2-dimensional array. */
1201
1202         oa.set_element(0, (java_handle_t *) classes.get_handle());
1203         oa.set_element(1, (java_handle_t *) methodnames.get_handle());
1204
1205         /* Iterate over the whole stack. */
1206         /* TODO We should use a critical section here to speed things
1207            up. */
1208
1209         i = 0;
1210
1211         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1212                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1213                  stacktrace_stackframeinfo_next(&tmpsfi)) {
1214                 /* Get the methodinfo. */
1215
1216                 m = tmpsfi.code->m;
1217
1218                 /* Skip builtin methods. */
1219
1220                 if (m->flags & ACC_METHOD_BUILTIN)
1221                         continue;
1222
1223                 /* Store the class in the array. */
1224
1225                 classes.set_element(i, m->clazz);
1226
1227                 /* Store the name in the array. */
1228
1229                 string = javastring_new(m->name);
1230
1231                 if (string == NULL)
1232                         goto return_NULL;
1233
1234                 methodnames.set_element(i, string);
1235
1236                 i++;
1237         }
1238
1239         CYCLES_STATS_END(stacktrace_get_stack)
1240
1241         return oa.get_handle();
1242
1243 return_NULL:
1244         CYCLES_STATS_END(stacktrace_get_stack)
1245
1246         return NULL;
1247 }
1248 #endif
1249
1250
1251 /* stacktrace_print_entry ****************************************************
1252
1253    Print line for a stacktrace entry.
1254
1255    ARGUMENTS:
1256        m ............ methodinfo of the entry
1257        linenumber ... linenumber of the entry
1258
1259 *******************************************************************************/
1260
1261 static void stacktrace_print_entry(methodinfo *m, int32_t linenumber)
1262 {
1263         /* Sanity check. */
1264
1265         assert(m != NULL);
1266
1267         printf("\tat ");
1268
1269         if (m->flags & ACC_METHOD_BUILTIN)
1270                 printf("NULL");
1271         else
1272                 utf_display_printable_ascii_classname(m->clazz->name);
1273
1274         printf(".");
1275         utf_display_printable_ascii(m->name);
1276         utf_display_printable_ascii(m->descriptor);
1277
1278         if (m->flags & ACC_NATIVE) {
1279                 puts("(Native Method)");
1280         }
1281         else {
1282                 if (m->flags & ACC_METHOD_BUILTIN) {
1283                         puts("(builtin)");
1284                 }
1285                 else {
1286                         printf("(");
1287                         utf_display_printable_ascii(m->clazz->sourcefile);
1288                         printf(":%d)\n", linenumber);
1289                 }
1290         }
1291
1292         fflush(stdout);
1293 }
1294
1295
1296 /* stacktrace_print ************************************************************
1297
1298    Print the given stacktrace with CACAO intern methods only (no Java
1299    code required).
1300
1301    This method is used by stacktrace_dump_trace and
1302    builtin_trace_exception.
1303
1304    IN:
1305        st ... stacktrace to print
1306
1307 *******************************************************************************/
1308
1309 void stacktrace_print(stacktrace_t *st)
1310 {
1311         stacktrace_entry_t *ste;
1312         methodinfo         *m;
1313         int32_t             linenumber;
1314         int                 i;
1315
1316         ste = &(st->entries[0]);
1317
1318         for (i = 0; i < st->length; i++, ste++) {
1319                 m = ste->code->m;
1320
1321                 /* Get the line number. */
1322
1323                 linenumber = ste->code->linenumbertable->find(&m, ste->pc);
1324
1325                 stacktrace_print_entry(m, linenumber);
1326         }
1327 }
1328
1329
1330 /* stacktrace_print_current ****************************************************
1331
1332    Print the current stacktrace of the current thread.
1333
1334    NOTE: This function prints all frames of the stacktrace and does
1335    not skip frames like stacktrace_get.
1336
1337 *******************************************************************************/
1338
1339 void stacktrace_print_current(void)
1340 {
1341         stackframeinfo_t *sfi;
1342         stackframeinfo_t  tmpsfi;
1343         codeinfo         *code;
1344         methodinfo       *m;
1345         int32_t           linenumber;
1346
1347         sfi = threads_get_current_stackframeinfo();
1348
1349         if (sfi == NULL) {
1350                 puts("\t<<No stacktrace available>>");
1351                 fflush(stdout);
1352                 return;
1353         }
1354
1355         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1356                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1357                  stacktrace_stackframeinfo_next(&tmpsfi)) {
1358                 /* Get the methodinfo. */
1359
1360                 code = tmpsfi.code;
1361                 m    = code->m;
1362
1363                 // Get the line number.
1364                 linenumber = code->linenumbertable->find(&m, tmpsfi.xpc);
1365
1366                 stacktrace_print_entry(m, linenumber);
1367         }
1368 }
1369
1370
1371 /**
1372  * Creates a stacktrace for the given thread.
1373  *
1374  * @param t Given thread.
1375  * @return Current stacktrace of the given thread.
1376  *
1377  * XXX: Creation of the stacktrace starts at the most recent
1378  * stackframeinfo block. If the thread is not inside the native
1379  * world, the created stacktrace is not complete!
1380  */
1381 #if defined(ENABLE_THREADS)
1382 stacktrace_t* stacktrace_get_of_thread(threadobject* t)
1383 {
1384         stackframeinfo_t*        sfi;
1385         java_handle_bytearray_t* stba;
1386         stacktrace_t*            st;
1387
1388         sfi  = t->_stackframeinfo;
1389         stba = stacktrace_get(sfi);
1390
1391         ByteArray ba(stba);
1392
1393         if (ba.is_null())
1394                 return NULL;
1395
1396         st  = (stacktrace_t*) ba.get_raw_data_ptr();
1397
1398         return st;
1399 }
1400 #endif
1401
1402
1403 /* stacktrace_print_of_thread **************************************************
1404
1405    Print the current stacktrace of the given thread. It will only work
1406    for suspended threads.
1407
1408    ARGUMENTS:
1409        t ... thread
1410
1411 *******************************************************************************/
1412
1413 #if defined(ENABLE_THREADS)
1414 void stacktrace_print_of_thread(threadobject *t)
1415 {
1416         stackframeinfo_t *sfi;
1417         stackframeinfo_t  tmpsfi;
1418         codeinfo         *code;
1419         methodinfo       *m;
1420         int32_t           linenumber;
1421
1422         /* Build a stacktrace for the passed thread. */
1423
1424         sfi = t->_stackframeinfo;
1425         
1426         if (!t->suspended || sfi == NULL) {
1427                 puts("\t<<No stacktrace available>>");
1428                 fflush(stdout);
1429                 return;
1430         }
1431
1432         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1433                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1434                  stacktrace_stackframeinfo_next(&tmpsfi)) {
1435                 /* Get the methodinfo. */
1436
1437                 code = tmpsfi.code;
1438                 m    = code->m;
1439
1440                 // Get the line number.
1441                 linenumber = code->linenumbertable->find(&m, tmpsfi.xpc);
1442
1443                 stacktrace_print_entry(m, linenumber);
1444         }
1445 }
1446 #endif
1447
1448
1449 /* stacktrace_print_exception **************************************************
1450
1451    Print the stacktrace of a given exception (more or less a wrapper
1452    to stacktrace_print).
1453
1454    IN:
1455        h ... handle of exception to print
1456
1457 *******************************************************************************/
1458
1459 void stacktrace_print_exception(java_handle_t *h)
1460 {
1461         if (h == NULL)
1462                 return;
1463
1464         java_lang_Throwable t(h);
1465
1466         /* now print the stacktrace */
1467
1468 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
1469
1470         java_lang_VMThrowable vmt(t.get_vmState());
1471         ByteArray backtrace(vmt.get_vmdata());
1472
1473 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) || defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
1474
1475         ByteArray backtrace(t.get_backtrace());
1476
1477 #else
1478 # error unknown classpath configuration
1479 #endif
1480
1481         // Sanity check.
1482
1483         assert(backtrace.is_non_null());
1484
1485         /* We need a critical section here as we use the byte-array data
1486            pointer directly. */
1487
1488         LLNI_CRITICAL_START;
1489         
1490         stacktrace_t* st = (stacktrace_t*) backtrace.get_raw_data_ptr();
1491
1492         stacktrace_print(st);
1493
1494         LLNI_CRITICAL_END;
1495 }
1496
1497
1498 #if defined(ENABLE_CYCLES_STATS)
1499 void stacktrace_print_cycles_stats(FILE *file)
1500 {
1501         CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead, file);
1502         CYCLES_STATS_PRINT(stacktrace_get,               file);
1503         CYCLES_STATS_PRINT(stacktrace_getClassContext ,  file);
1504         CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,  file);
1505         CYCLES_STATS_PRINT(stacktrace_get_stack,         file);
1506 }
1507 #endif
1508
1509 } // extern "C"
1510
1511
1512 /*
1513  * These are local overrides for various environment variables in Emacs.
1514  * Please do not remove this and leave it at the end of the file, where
1515  * Emacs will automagically detect them.
1516  * ---------------------------------------------------------------------
1517  * Local variables:
1518  * mode: c++
1519  * indent-tabs-mode: t
1520  * c-basic-offset: 4
1521  * tab-width: 4
1522  * End:
1523  * vim:noexpandtab:sw=4:ts=4:
1524  */