3df7342283dd98e63829a00a47915547448402af
[cacao.git] / src / vm / jit / stacktrace.c
1 /* src/vm/jit/stacktrace.c - machine independent stacktrace system
2
3    Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, 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., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25 */
26
27
28 #include "config.h"
29
30 #include <assert.h>
31 #include <stdint.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include "vm/types.h"
36
37 #include "mm/gc-common.h"
38 #include "mm/memory.h"
39
40 #include "vm/jit/stacktrace.h"
41
42 #include "vm/global.h"                   /* required here for native includes */
43 #include "native/jni.h"
44 #include "native/llni.h"
45 #include "native/include/java_lang_Throwable.h"
46
47 #if defined(WITH_CLASSPATH_GNU)
48 # include "native/include/java_lang_VMThrowable.h"
49 #endif
50
51 #if defined(ENABLE_THREADS)
52 # include "threads/native/threads.h"
53 #else
54 # include "threads/none/threads.h"
55 #endif
56
57 #include "toolbox/logging.h"
58
59 #include "vm/array.h"
60 #include "vm/builtin.h"
61 #include "vm/cycles-stats.h"
62 #include "vm/exceptions.h"
63 #include "vm/stringlocal.h"
64 #include "vm/vm.h"
65
66 #include "vm/jit/asmpart.h"
67 #include "vm/jit/codegen-common.h"
68 #include "vm/jit/methodheader.h"
69
70 #include "vmcore/class.h"
71 #include "vmcore/loader.h"
72 #include "vmcore/options.h"
73
74
75 /* global variables ***********************************************************/
76 #if !defined(ENABLE_THREADS)
77 stackframeinfo_t *_no_threads_stackframeinfo = NULL;
78 #endif
79
80 CYCLES_STATS_DECLARE(stacktrace_overhead        ,100,1)
81 CYCLES_STATS_DECLARE(stacktrace_fillInStackTrace,40,5000)
82 CYCLES_STATS_DECLARE(stacktrace_getClassContext ,40,5000)
83 CYCLES_STATS_DECLARE(stacktrace_getCurrentClass ,40,5000)
84 CYCLES_STATS_DECLARE(stacktrace_getStack        ,40,10000)
85
86
87 /* stacktrace_stackframeinfo_add ***********************************************
88
89    Fills a stackframe info structure with the given or calculated
90    values and adds it to the chain.
91
92 *******************************************************************************/
93
94 void stacktrace_stackframeinfo_add(stackframeinfo_t *sfi, u1 *pv, u1 *sp, u1 *ra, u1 *xpc)
95 {
96         stackframeinfo_t **psfi;
97         codeinfo          *code;
98 #if !defined(__I386__) && !defined(__X86_64__) && !defined(__S390__) && !defined(__M68K__)
99         bool               isleafmethod;
100 #endif
101 #if defined(ENABLE_JIT)
102         s4                 framesize;
103 #endif
104
105         /* get current stackframe info pointer */
106
107         psfi = &STACKFRAMEINFO;
108
109         /* sometimes we don't have pv handy (e.g. in asmpart.S:
110        L_asm_call_jit_compiler_exception or in the interpreter). */
111
112         if (pv == NULL) {
113 #if defined(ENABLE_INTRP)
114                 if (opt_intrp)
115                         pv = codegen_get_pv_from_pc(ra);
116                 else
117 #endif
118                         {
119 #if defined(ENABLE_JIT)
120 # if defined(__SPARC_64__)
121                                 pv = md_get_pv_from_stackframe(sp);
122 # else
123                                 pv = md_codegen_get_pv_from_pc(ra);
124 # endif
125 #endif
126                         }
127         }
128
129         /* Get codeinfo pointer for the parent Java method. */
130
131         code = code_get_codeinfo_for_pv(pv);
132
133         /* XXX */
134 /*      assert(m != NULL); */
135
136 #if defined(ENABLE_JIT)
137 # if defined(ENABLE_INTRP)
138         /* When using the interpreter, we pass RA to the function. */
139
140         if (!opt_intrp) {
141 # endif
142 # if defined(__I386__) || defined(__X86_64__) || defined(__S390__) || defined(__M68K__)
143                 /* On i386 and x86_64 we always have to get the return address
144                    from the stack. */
145                 /* m68k has return address on stack always */
146                 /* On S390 we use REG_RA as REG_ITMP3, so we have always to get
147                    the RA from stack. */
148
149                 framesize = *((u4 *) (pv + FrameSize));
150
151                 ra = md_stacktrace_get_returnaddress(sp, framesize);
152 # else
153                 /* If the method is a non-leaf function, we need to get the return
154                    address from the stack. For leaf functions the return address
155                    is set correctly. This makes the assembler and the signal
156                    handler code simpler. */
157
158                 isleafmethod = *((s4 *) (pv + IsLeaf));
159
160                 if (!isleafmethod) {
161                         framesize = *((u4 *) (pv + FrameSize));
162
163                         ra = md_stacktrace_get_returnaddress(sp, framesize);
164                 }
165 # endif
166 # if defined(ENABLE_INTRP)
167         }
168 # endif
169 #endif
170
171         /* Calculate XPC when not given.  The XPC is then the return
172            address of the current method minus 1 because the RA points to
173            the instruction after the call instruction.  This is required
174            e.g. for method stubs. */
175
176         if (xpc == NULL) {
177                 xpc = (void *) (((intptr_t) ra) - 1);
178         }
179
180         /* Fill new stackframeinfo structure. */
181
182         sfi->prev = *psfi;
183         sfi->code = code;
184         sfi->pv   = pv;
185         sfi->sp   = sp;
186         sfi->ra   = ra;
187         sfi->xpc  = xpc;
188
189 #if !defined(NDEBUG)
190         if (opt_DebugStackFrameInfo) {
191                 log_start();
192                 log_print("[stackframeinfo add   : sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
193                                   sfi, sfi->code->m, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
194                 method_print(sfi->code->m);
195                 log_print("]");
196                 log_finish();
197         }
198 #endif
199
200         /* Store new stackframeinfo pointer. */
201
202         *psfi = sfi;
203
204         /* set the native world flag for the current thread */
205         /* ATTENTION: This flag tells the GC how to treat this thread in case of
206            a collection. Set this flag _after_ a valid stackframe info was set. */
207
208         THREAD_NATIVEWORLD_ENTER;
209 }
210
211
212 /* stacktrace_stackframeinfo_remove ********************************************
213
214    Remove the given stackframeinfo from the chain in the current
215    thread.
216
217 *******************************************************************************/
218
219 void stacktrace_stackframeinfo_remove(stackframeinfo_t *sfi)
220 {
221         stackframeinfo_t **psfi;
222
223         /* clear the native world flag for the current thread */
224         /* ATTENTION: Clear this flag _before_ removing the stackframe info */
225
226         THREAD_NATIVEWORLD_EXIT;
227
228         /* get current stackframe info pointer */
229
230         psfi = &STACKFRAMEINFO;
231
232 #if !defined(NDEBUG)
233         if (opt_DebugStackFrameInfo) {
234                 log_start();
235                 log_print("[stackframeinfo remove: sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
236                                   sfi, sfi->code->m, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
237                 method_print(sfi->code->m);
238                 log_print("]");
239                 log_finish();
240         }
241 #endif
242
243         /* restore the old pointer */
244
245         *psfi = sfi->prev;
246 }
247
248
249 /* stacktrace_entry_add ********************************************************
250
251    Adds a new entry to the stacktrace buffer.
252
253 *******************************************************************************/
254
255 static inline stacktracebuffer *stacktrace_entry_add(stacktracebuffer *stb, methodinfo *m, u2 line)
256 {
257         stacktrace_entry *ste;
258         u4                stb_size_old;
259         u4                stb_size_new;
260
261         /* check if we already reached the buffer capacity */
262
263         if (stb->used >= stb->capacity) {
264                 /* calculate size of stacktracebuffer */
265
266                 stb_size_old = sizeof(stacktracebuffer) +
267                                            sizeof(stacktrace_entry) * stb->capacity -
268                                            sizeof(stacktrace_entry) * STACKTRACE_CAPACITY_DEFAULT;
269
270                 stb_size_new = stb_size_old +
271                                            sizeof(stacktrace_entry) * STACKTRACE_CAPACITY_INCREMENT;
272
273                 /* reallocate new memory */
274
275                 stb = DMREALLOC(stb, u1, stb_size_old, stb_size_new);
276
277                 /* set new buffer capacity */
278
279                 stb->capacity = stb->capacity + STACKTRACE_CAPACITY_INCREMENT;
280         }
281
282         /* insert the current entry */
283
284         ste = &(stb->entries[stb->used]);
285
286         ste->method     = m;
287         ste->linenumber = line;
288
289         /* increase entries used count */
290
291         stb->used += 1;
292
293         return stb;
294 }
295
296
297 /* stacktrace_method_add *******************************************************
298
299    Add stacktrace entries[1] for the given method to the stacktrace
300    buffer.
301
302    IN:
303        stb....stacktracebuffer to fill
304            sfi....current stackframeinfo
305    OUT:
306        stacktracebuffer after possible reallocation.
307
308    [1] In case of inlined methods there may be more than one stacktrace
309        entry for a codegen-level method. (see doc/inlining_stacktrace.txt)
310
311 *******************************************************************************/
312
313 static inline stacktracebuffer *stacktrace_method_add(stacktracebuffer *stb, stackframeinfo_t *sfi)
314 {
315         codeinfo   *code;
316         void       *pv;
317         void       *xpc;
318         methodinfo *m;
319         int32_t     linenumber;
320
321         /* Get values from the stackframeinfo. */
322
323         code = sfi->code;
324         pv   = sfi->pv;
325         xpc  = sfi->xpc;
326
327         m = code->m;
328
329         /* Skip builtin methods. */
330
331         if (m->flags & ACC_METHOD_BUILTIN)
332                 return stb;
333
334         /* Search the line number table. */
335
336         linenumber = dseg_get_linenumber_from_pc(&m, pv, xpc);
337
338         /* Add a new entry to the staktrace. */
339
340         stb = stacktrace_entry_add(stb, m, linenumber);
341
342         return stb;
343 }
344
345
346 /* stacktrace_stack_walk *******************************************************
347
348    Walk the stack (or the stackframeinfo-chain) to the next method.
349
350    IN:
351        tmpsfi ... stackframeinfo of current method
352
353    RETURN:
354        true .... the sfi is filled with the new values
355        false ... we reached the top of the stacktrace
356
357 *******************************************************************************/
358
359 static inline bool stacktrace_stack_walk(stackframeinfo_t *tmpsfi)
360 {
361         codeinfo         *code;
362         void             *pv;
363         void             *sp;
364         void             *ra;
365         void             *xpc;
366         uint32_t          framesize;
367         stackframeinfo_t *prevsfi;
368
369         /* Get values from the stackframeinfo. */
370
371         code = tmpsfi->code;
372         pv   = tmpsfi->pv;
373         sp   = tmpsfi->sp;
374         ra   = tmpsfi->ra;
375         xpc  = tmpsfi->xpc;
376
377         /* Get the current stack frame size. */
378
379         framesize = *((uint32_t *) (((intptr_t) pv) + FrameSize));
380
381         /* Get the RA of the current stack frame (RA to the parent Java
382            method) if the current method is a non-leaf method.  Otherwise
383            the value in the stackframeinfo is correct (from the signal
384            handler). */
385
386 #if defined(ENABLE_JIT)
387 # if defined(ENABLE_INTRP)
388         if (opt_intrp)
389                 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
390         else
391 # endif
392                 {
393                         if (!code_is_leafmethod(code))
394                                 ra = md_stacktrace_get_returnaddress(sp, framesize);
395                 }
396 #else
397         ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
398 #endif
399
400         /* Get the PV for the parent Java method. */
401
402 #if defined(ENABLE_INTRP)
403         if (opt_intrp)
404                 pv = codegen_get_pv_from_pc(ra);
405         else
406 #endif
407                 {
408 #if defined(ENABLE_JIT)
409 # if defined(__SPARC_64__)
410                         sp = md_get_framepointer(sp);
411                         pv = md_get_pv_from_stackframe(sp);
412 # else
413                         pv = md_codegen_get_pv_from_pc(ra);
414 # endif
415 #endif
416                 }
417
418         /* Get the codeinfo pointer for the parent Java method. */
419
420         code = code_get_codeinfo_for_pv(pv);
421
422         /* Calculate the SP for the parent Java method. */
423
424 #if defined(ENABLE_INTRP)
425         if (opt_intrp)
426                 sp = *(u1 **) (sp - framesize);
427         else
428 #endif
429                 {
430 #if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
431                         sp = (void *) (((intptr_t) sp) + framesize + SIZEOF_VOID_P);
432 #elif defined(__SPARC_64__)
433                         /* already has the new sp */
434 #else
435                         sp = (void *) (((intptr_t) sp) + framesize);
436 #endif
437                 }
438
439         /* If the new codeinfo pointer is NULL we reached a
440            asm_vm_call_method function.  In this case we get the next
441            values from the previous stackframeinfo in the chain.
442            Otherwise the new values have been calculated before. */
443
444         if (code == NULL) {
445                 prevsfi = tmpsfi->prev;
446
447                 /* If the previous stackframeinfo in the chain is NULL we
448                    reached the top of the stacktrace and return false. */
449
450                 if (prevsfi == NULL)
451                         return false;
452
453                 /* Fill the temporary stackframeinfo with the new values. */
454
455                 tmpsfi->code = prevsfi->code;
456                 tmpsfi->pv   = prevsfi->pv;
457                 tmpsfi->sp   = prevsfi->sp;
458                 tmpsfi->ra   = prevsfi->ra;
459                 tmpsfi->xpc  = prevsfi->xpc;
460
461                 /* Set the previous stackframe info of the temporary one to
462                    the next in the chain. */
463
464                 tmpsfi->prev = prevsfi->prev;
465         }
466         else {
467                 /* Store the new values in the stackframeinfo.  NOTE: We
468                    subtract 1 from the RA to get the XPC, because the RA
469                    points to the instruction after the call instruction. */
470
471                 tmpsfi->code = code;
472                 tmpsfi->pv   = pv;
473                 tmpsfi->sp   = sp;
474                 tmpsfi->ra   = ra;
475                 tmpsfi->xpc  = (void *) (((intptr_t) ra) - 1);
476         }
477
478         return true;
479 }
480
481
482 /* stacktrace_create ***********************************************************
483
484    Generates a stacktrace from the thread passed into a
485    stacktracebuffer.  The stacktracebuffer is allocated on the
486    dump memory.
487    
488    NOTE: The first element in the stackframe chain must always be a
489          native stackframeinfo (e.g. VMThrowable.fillInStackTrace() is
490          a native function).
491
492    RETURN VALUE:
493       pointer to the stacktracebuffer, or
494       NULL if there is no stacktrace available for the
495       given thread.
496
497 *******************************************************************************/
498
499 stacktracebuffer *stacktrace_create(stackframeinfo_t *sfi)
500 {
501         stacktracebuffer *stb;
502         stackframeinfo_t  tmpsfi;
503         bool              skip_fillInStackTrace;
504         bool              skip_init;
505
506         skip_fillInStackTrace = true;
507         skip_init             = true;
508
509         /* Create a stacktracebuffer in dump memory. */
510
511         stb = DNEW(stacktracebuffer);
512
513         stb->capacity = STACKTRACE_CAPACITY_DEFAULT;
514         stb->used     = 0;
515
516 #if !defined(NDEBUG)
517         if (opt_DebugStackTrace) {
518                 printf("\n\n---> stacktrace creation start (fillInStackTrace):\n");
519                 fflush(stdout);
520         }
521 #endif
522
523         /* Put the data from the stackframeinfo into a temporary one. */
524
525         /* XXX This is not correct, but a workaround for threads-dump for
526            now. */
527 /*      assert(sfi != NULL); */
528         if (sfi == NULL)
529                 return NULL;
530
531         tmpsfi.code = sfi->code;
532         tmpsfi.pv   = sfi->pv;
533         tmpsfi.sp   = sfi->sp;
534         tmpsfi.ra   = sfi->ra;
535         tmpsfi.xpc  = sfi->xpc;
536
537         /* Initially set the previous stackframe info of the temporary one
538            to the next in the chain. */
539
540         tmpsfi.prev = sfi->prev;
541
542         /* Iterate till we're done. */
543
544         do {
545 #if !defined(NDEBUG)
546                 /* Print current method information. */
547
548                 if (opt_DebugStackTrace) {
549                         log_start();
550                         log_print("[stacktrace: method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
551                                           tmpsfi.code->m, tmpsfi.pv, tmpsfi.sp, tmpsfi.ra,
552                                           tmpsfi.xpc);
553                         method_print(tmpsfi.code->m);
554                         log_print("]");
555                         log_finish();
556                 }
557 #endif
558
559                 /* This logic is taken from
560                    hotspot/src/share/vm/classfile/javaClasses.cpp
561                    (java_lang_Throwable::fill_in_stack_trace). */
562
563                 if (skip_fillInStackTrace == true) {
564                         /* Check "fillInStackTrace" only once, so we negate the
565                            flag after the first time check. */
566
567 #if defined(WITH_CLASSPATH_GNU)
568                         /* For GNU Classpath we also need to skip
569                            VMThrowable.fillInStackTrace(). */
570
571                         if ((tmpsfi.code->m->class == class_java_lang_VMThrowable) &&
572                                 (tmpsfi.code->m->name  == utf_fillInStackTrace))
573                                 continue;
574 #endif
575
576                         skip_fillInStackTrace = false;
577
578                         if (tmpsfi.code->m->name == utf_fillInStackTrace)
579                                 continue;
580                 }
581
582                 /* Skip <init> methods of the exceptions klass.  If there is
583                    <init> methods that belongs to a superclass of the
584                    exception we are going to skipping them in stack trace. */
585
586                 if (skip_init == true) {
587                         if (tmpsfi.code->m->name == utf_init) {
588 /*                              throwable->is_a(method->method_holder())) { */
589                                 continue;
590                         }
591                         else {
592                                 /* If no "Throwable.init()" method found, we stop
593                                    checking it next time. */
594
595                                 skip_init = false;
596                         }
597                 }
598
599                 /* Add this method to the stacktrace. */
600
601                 stb = stacktrace_method_add(stb, &tmpsfi);
602         } while (stacktrace_stack_walk(&tmpsfi) == true);
603
604 #if !defined(NDEBUG)
605         if (opt_DebugStackTrace) {
606                 printf("---> stacktrace creation finished.\n\n");
607                 fflush(stdout);
608         }
609 #endif
610
611         /* return the stacktracebuffer */
612
613         if (stb->used == 0)
614                 return NULL;
615         else
616                 return stb;
617 }
618
619
620 /* stacktrace_fillInStackTrace *************************************************
621
622    Generate a stacktrace from the current thread for
623    java.lang.VMThrowable.fillInStackTrace.
624
625 *******************************************************************************/
626
627 java_handle_bytearray_t *stacktrace_fillInStackTrace(void)
628 {
629         stacktracebuffer        *stb;
630         java_handle_bytearray_t *ba;
631         s4                       ba_size;
632         s4                       dumpsize;
633         CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
634
635         /* mark start of dump memory area */
636
637         dumpsize = dump_size();
638
639         /* create a stacktrace from the current thread */
640
641         stb = stacktrace_create(STACKFRAMEINFO);
642
643         if (stb == NULL)
644                 goto return_NULL;
645
646         /* allocate memory from the GC heap and copy the stacktrace buffer */
647         /* ATTENTION: use a bytearray for this to not confuse the GC */
648
649         ba_size = sizeof(stacktracebuffer) +
650                   sizeof(stacktrace_entry) * stb->used -
651                   sizeof(stacktrace_entry) * STACKTRACE_CAPACITY_DEFAULT;
652         ba = builtin_newarray_byte(ba_size);
653
654         if (ba == NULL)
655                 goto return_NULL;
656
657         MCOPY(LLNI_array_data(ba), stb, u1, ba_size);
658
659         /* release dump memory */
660
661         dump_release(dumpsize);
662
663         CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
664                                                                    stacktrace_overhead)
665         return ba;
666
667 return_NULL:
668         dump_release(dumpsize);
669
670         CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
671                                                                    stacktrace_overhead)
672
673         return NULL;
674 }
675
676
677 /* stacktrace_getClassContext **************************************************
678
679    Creates a Class context array.
680
681    RETURN VALUE:
682       the array of java.lang.Class objects, or
683           NULL if an exception has been thrown
684
685 *******************************************************************************/
686
687 java_handle_objectarray_t *stacktrace_getClassContext(void)
688 {
689         stacktracebuffer          *stb;
690         stacktrace_entry          *ste;
691         java_handle_objectarray_t *oa;
692         s4                         oalength;
693         s4                         i;
694         s4                         dumpsize;
695         CYCLES_STATS_DECLARE_AND_START
696
697         /* mark start of dump memory area */
698
699         dumpsize = dump_size();
700
701         /* create a stacktrace for the current thread */
702
703         stb = stacktrace_create(STACKFRAMEINFO);
704
705         if (stb == NULL)
706                 goto return_NULL;
707
708         /* calculate the size of the Class array */
709
710         for (i = 0, oalength = 0; i < stb->used; i++)
711                 if (stb->entries[i].method != NULL)
712                         oalength++;
713
714         /* The first entry corresponds to the method whose implementation */
715         /* calls stacktrace_getClassContext. We remove that entry.        */
716
717         ste = &(stb->entries[0]);
718         ste++;
719         oalength--;
720
721         /* allocate the Class array */
722
723         oa = builtin_anewarray(oalength, class_java_lang_Class);
724         if (!oa)
725                 goto return_NULL;
726
727         /* fill the Class array from the stacktracebuffer */
728
729         for(i = 0; i < oalength; i++, ste++) {
730                 if (ste->method == NULL) {
731                         i--;
732                         continue;
733                 }
734
735                 LLNI_array_direct(oa, i) = (java_object_t *) ste->method->class;
736         }
737
738         /* release dump memory */
739
740         dump_release(dumpsize);
741
742         CYCLES_STATS_END(stacktrace_getClassContext)
743
744         return oa;
745
746 return_NULL:
747         dump_release(dumpsize);
748
749         CYCLES_STATS_END(stacktrace_getClassContext)
750
751         return NULL;
752 }
753
754
755 /* stacktrace_getCurrentClass **************************************************
756
757    Find the current class by walking the stack trace.
758
759    Quote from the JNI documentation:
760          
761    In the Java 2 Platform, FindClass locates the class loader
762    associated with the current native method.  If the native code
763    belongs to a system class, no class loader will be
764    involved. Otherwise, the proper class loader will be invoked to
765    load and link the named class. When FindClass is called through the
766    Invocation Interface, there is no current native method or its
767    associated class loader. In that case, the result of
768    ClassLoader.getBaseClassLoader is used."
769
770 *******************************************************************************/
771
772 #if defined(ENABLE_JAVASE)
773 classinfo *stacktrace_getCurrentClass(void)
774 {
775         stacktracebuffer  *stb;
776         stacktrace_entry  *ste;
777         methodinfo        *m;
778         s4                 i;
779         s4                 dumpsize;
780         CYCLES_STATS_DECLARE_AND_START
781
782         /* mark start of dump memory area */
783
784         dumpsize = dump_size();
785
786         /* create a stacktrace for the current thread */
787
788         stb = stacktrace_create(STACKFRAMEINFO);
789
790         if (stb == NULL)
791                 goto return_NULL; /* XXX exception: how to distinguish from normal NULL return? */
792
793         /* iterate over all stacktrace entries and find the first suitable
794            class */
795
796         for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
797                 m = ste->method;
798
799                 if (m == NULL)
800                         continue;
801
802                 if (m->class == class_java_security_PrivilegedAction)
803                         goto return_NULL;
804
805                 if (m->class != NULL) {
806                         dump_release(dumpsize);
807
808                         CYCLES_STATS_END(stacktrace_getCurrentClass)
809
810                         return m->class;
811                 }
812         }
813
814         /* no Java method found on the stack */
815
816 return_NULL:
817         dump_release(dumpsize);
818
819         CYCLES_STATS_END(stacktrace_getCurrentClass)
820
821         return NULL;
822 }
823 #endif /* ENABLE_JAVASE */
824
825
826 /* stacktrace_getStack *********************************************************
827
828    Create a 2-dimensional array for java.security.VMAccessControler.
829
830    RETURN VALUE:
831       the arrary, or
832           NULL if an exception has been thrown
833
834 *******************************************************************************/
835
836 #if defined(ENABLE_JAVASE)
837 java_handle_objectarray_t *stacktrace_getStack(void)
838 {
839         stacktracebuffer          *stb;
840         stacktrace_entry          *ste;
841         java_handle_objectarray_t *oa;
842         java_handle_objectarray_t *classes;
843         java_handle_objectarray_t *methodnames;
844         classinfo                 *c;
845         java_handle_t             *string;
846         s4                         i;
847         s4                         dumpsize;
848         CYCLES_STATS_DECLARE_AND_START
849
850         /* mark start of dump memory area */
851
852         dumpsize = dump_size();
853
854         /* create a stacktrace for the current thread */
855
856         stb = stacktrace_create(STACKFRAMEINFO);
857
858         if (stb == NULL)
859                 goto return_NULL;
860
861         /* get the first stacktrace entry */
862
863         ste = &(stb->entries[0]);
864
865         /* allocate all required arrays */
866
867         oa = builtin_anewarray(2, arrayclass_java_lang_Object);
868
869         if (oa == NULL)
870                 goto return_NULL;
871
872         classes = builtin_anewarray(stb->used, class_java_lang_Class);
873
874         if (classes == NULL)
875                 goto return_NULL;
876
877         methodnames = builtin_anewarray(stb->used, class_java_lang_String);
878
879         if (methodnames == NULL)
880                 goto return_NULL;
881
882         /* set up the 2-dimensional array */
883
884         array_objectarray_element_set(oa, 0, (java_handle_t *) classes);
885         array_objectarray_element_set(oa, 1, (java_handle_t *) methodnames);
886
887         /* iterate over all stacktrace entries */
888
889         for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
890                 c = ste->method->class;
891
892                 LLNI_array_direct(classes, i) = (java_object_t *) c;
893
894                 string = javastring_new(ste->method->name);
895
896                 if (string == NULL)
897                         goto return_NULL;
898
899                 array_objectarray_element_set(methodnames, i, string);
900         }
901
902         /* return the 2-dimensional array */
903
904         dump_release(dumpsize);
905
906         CYCLES_STATS_END(stacktrace_getStack)
907
908         return oa;
909
910 return_NULL:
911         dump_release(dumpsize);
912
913         CYCLES_STATS_END(stacktrace_getStack)
914
915         return NULL;
916 }
917 #endif /* ENABLE_JAVASE */
918
919
920 /* stacktrace_print_trace_from_buffer ******************************************
921
922    Print the stacktrace of a given stacktracebuffer with CACAO intern
923    methods (no Java help). This method is used by
924    stacktrace_dump_trace and builtin_trace_exception.
925
926 *******************************************************************************/
927
928 void stacktrace_print_trace_from_buffer(stacktracebuffer *stb)
929 {
930         stacktrace_entry *ste;
931         methodinfo       *m;
932         s4                i;
933
934         ste = &(stb->entries[0]);
935
936         for (i = 0; i < stb->used; i++, ste++) {
937                 m = ste->method;
938
939                 printf("\tat ");
940                 utf_display_printable_ascii_classname(m->class->name);
941                 printf(".");
942                 utf_display_printable_ascii(m->name);
943                 utf_display_printable_ascii(m->descriptor);
944
945                 if (m->flags & ACC_NATIVE) {
946                         puts("(Native Method)");
947
948                 } else {
949                         printf("(");
950                         utf_display_printable_ascii(m->class->sourcefile);
951                         printf(":%d)\n", (u4) ste->linenumber);
952                 }
953         }
954
955         /* just to be sure */
956
957         fflush(stdout);
958 }
959
960
961 /* stacktrace_print_trace ******************************************************
962
963    Print the stacktrace of a given exception. More or less a wrapper
964    to stacktrace_print_trace_from_buffer.
965
966 *******************************************************************************/
967
968 void stacktrace_print_trace(java_handle_t *xptr)
969 {
970         java_lang_Throwable     *t;
971 #if defined(WITH_CLASSPATH_GNU)
972         java_lang_VMThrowable   *vmt;
973 #endif
974         java_handle_bytearray_t *ba;
975         stacktracebuffer        *stb;
976
977         t = (java_lang_Throwable *) xptr;
978
979         if (t == NULL)
980                 return;
981
982         /* now print the stacktrace */
983
984 #if defined(WITH_CLASSPATH_GNU)
985         LLNI_field_get_ref(t, vmState, vmt);
986         LLNI_field_get_ref(vmt, vmData, ba);
987 #elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
988         LLNI_field_get_ref(t, backtrace, ba);
989 #else
990 # error unknown classpath configuration
991 #endif
992
993         assert(ba);
994         stb = (stacktracebuffer *) LLNI_array_data(ba);
995
996         stacktrace_print_trace_from_buffer(stb);
997 }
998
999
1000 #if defined(ENABLE_CYCLES_STATS)
1001 void stacktrace_print_cycles_stats(FILE *file)
1002 {
1003         CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead,file);
1004         CYCLES_STATS_PRINT(stacktrace_fillInStackTrace,file);
1005         CYCLES_STATS_PRINT(stacktrace_getClassContext ,file);
1006         CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,file);
1007         CYCLES_STATS_PRINT(stacktrace_getStack        ,file);
1008 }
1009 #endif
1010
1011
1012 /*
1013  * These are local overrides for various environment variables in Emacs.
1014  * Please do not remove this and leave it at the end of the file, where
1015  * Emacs will automagically detect them.
1016  * ---------------------------------------------------------------------
1017  * Local variables:
1018  * mode: c
1019  * indent-tabs-mode: t
1020  * c-basic-offset: 4
1021  * tab-width: 4
1022  * End:
1023  * vim:noexpandtab:sw=4:ts=4:
1024  */