OSDN Git Service

* include/java-stack.h (ncodeMap): Declare.
[pf3gnuchains/gcc-fork.git] / libjava / stacktrace.cc
1 // stacktrace.cc - Functions for unwinding & inspecting the call stack.
2
3 /* Copyright (C) 2005, 2006  Free Software Foundation
4
5    This file is part of libgcj.
6
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
9 details.  */
10
11 #include <config.h>
12 #include <platform.h>
13
14 #include <jvm.h>
15 #include <gcj/cni.h>
16 #include <java-interp.h>
17 #include <java-stack.h>
18
19 #include <stdio.h>
20
21 #include <java/lang/Boolean.h>
22 #include <java/lang/Class.h>
23 #include <java/lang/Long.h>
24 #include <java/security/AccessController.h>
25 #include <java/util/ArrayList.h>
26 #include <gnu/classpath/jdwp/Jdwp.h>
27 #include <gnu/java/lang/MainThread.h>
28 #include <gnu/gcj/runtime/NameFinder.h>
29 #include <gnu/gcj/runtime/StringBuffer.h>
30
31 #include <sysdep/backtrace.h>
32 #include <sysdep/descriptor.h>
33
34 using namespace java::lang;
35 using namespace java::lang::reflect;
36 using namespace java::util;
37 using namespace gnu::gcj::runtime;
38
39 // Maps ncode values to their containing native class.
40 // NOTE: Currently this Map contradicts class GC for native classes. This map
41 // (and the "new class stack") will need to use WeakReferences in order to 
42 // enable native class GC.
43 java::util::IdentityHashMap *_Jv_StackTrace::ncodeMap;
44
45 // Check the "class stack" for any classes initialized since we were last 
46 // called, and add them to ncodeMap.
47 void 
48 _Jv_StackTrace::UpdateNCodeMap ()
49 {
50   // The Map should be large enough so that a typical Java app doesn't cause 
51   // it to rehash, without using too much memory. ~5000 entries should be 
52   // enough.
53   if (ncodeMap == NULL)
54     ncodeMap = new java::util::IdentityHashMap (5087);
55   
56   jclass klass;
57   while ((klass = _Jv_PopClass ()))
58     {
59       //printf ("got %s\n", klass->name->data);
60       for (int i = 0; i < klass->method_count; i++)
61         {
62           _Jv_Method *method = &klass->methods[i];
63           void *ncode = method->ncode;
64           // Add non-abstract methods to ncodeMap.
65           if (ncode)
66             {
67               ncode = UNWRAP_FUNCTION_DESCRIPTOR (ncode);
68               ncodeMap->put ((java::lang::Object *) ncode, klass);
69             }
70         }
71     }
72 }
73
74 // Given a native frame, return the class which this code belongs 
75 // to. Returns NULL if this IP is not associated with a native Java class.
76 // If NCODE is supplied, it will be set with the ip for the entry point of the 
77 // enclosing method.
78 jclass
79 _Jv_StackTrace::ClassForFrame (_Jv_StackFrame *frame)
80 {
81   JvAssert (frame->type == frame_native);
82   jclass klass = NULL;
83
84   // look it up in ncodeMap
85   if (frame->start_ip)
86     {
87       klass = (jclass) ncodeMap->get ((jobject) frame->start_ip);
88
89       // Exclude interpreted classes
90       if (klass != NULL && _Jv_IsInterpretedClass (klass))
91         klass = NULL;
92     }
93
94   return klass;
95 }
96
97 _Unwind_Reason_Code
98 _Jv_StackTrace::UnwindTraceFn (struct _Unwind_Context *context, void *state_ptr)
99 {
100   _Jv_UnwindState *state = (_Jv_UnwindState *) state_ptr;
101   jint pos = state->pos;
102
103   // Check if the trace buffer needs to be extended.
104   if (pos == state->length)
105     {
106       int newLength = state->length * 2;
107       void *newFrames = _Jv_AllocBytes (newLength * sizeof(_Jv_StackFrame));
108       memcpy (newFrames, state->frames, state->length * sizeof(_Jv_StackFrame));      
109       state->frames = (_Jv_StackFrame *) newFrames;
110       state->length = newLength;
111     }
112
113   void *func_addr = (void *) _Unwind_GetRegionStart (context);
114
115   // If we see the interpreter's main function, "pop" an entry off the 
116   // interpreter stack and use that instead, so that the trace goes through 
117   // the java code and not the interpreter itself. This assumes a 1:1 
118   // correspondance between call frames in the interpreted stack and occurances
119   // of _Jv_InterpMethod::run() on the native stack.
120 #ifdef INTERPRETER
121   void *interp_run = NULL;
122   
123   if (::gnu::classpath::jdwp::Jdwp::isDebugging)
124         interp_run = (void *) &_Jv_InterpMethod::run_debug;
125   else
126     interp_run = (void *) &_Jv_InterpMethod::run;
127         
128   if (func_addr == UNWRAP_FUNCTION_DESCRIPTOR (interp_run))
129     {
130       state->frames[pos].type = frame_interpreter;
131       state->frames[pos].interp.meth = state->interp_frame->self;
132       state->frames[pos].interp.pc = state->interp_frame->pc;
133       state->interp_frame = state->interp_frame->next;
134     }
135   else
136 #endif
137     {
138 #ifdef HAVE_GETIPINFO
139       _Unwind_Ptr ip;
140       int ip_before_insn = 0;
141       ip = _Unwind_GetIPInfo (context, &ip_before_insn);
142
143       // If the unwinder gave us a 'return' address, roll it back a little
144       // to ensure we get the correct line number for the call itself.
145       if (! ip_before_insn)
146         --ip;
147 #endif
148       state->frames[pos].type = frame_native;
149 #ifdef HAVE_GETIPINFO
150       state->frames[pos].ip = (void *) ip;
151 #else
152       state->frames[pos].ip = (void *) _Unwind_GetIP (context);
153 #endif
154       state->frames[pos].start_ip = func_addr;
155     }
156
157   _Unwind_Reason_Code result = _URC_NO_REASON;
158   if (state->trace_function != NULL)
159     result = (state->trace_function) (state);
160   state->pos++;
161   return result;
162 }
163
164 // Return a raw stack trace from the current point of execution. The raw 
165 // trace will include all functions that have unwind info.
166 _Jv_StackTrace *
167 _Jv_StackTrace::GetStackTrace(void)
168 {
169   int trace_size = 100;
170   _Jv_StackFrame frames[trace_size];
171   _Jv_UnwindState state (trace_size);
172   state.frames = (_Jv_StackFrame *) &frames;
173
174   _Unwind_Backtrace (UnwindTraceFn, &state);
175   
176   // Copy the trace and return it.
177   int traceSize = sizeof (_Jv_StackTrace) + 
178     (sizeof (_Jv_StackFrame) * state.pos);
179   _Jv_StackTrace *trace = (_Jv_StackTrace *) _Jv_AllocBytes (traceSize);
180   trace->length = state.pos;
181   memcpy (trace->frames, state.frames, sizeof (_Jv_StackFrame) * state.pos);  
182   return trace;
183 }
184
185 void
186 _Jv_StackTrace::getLineNumberForFrame(_Jv_StackFrame *frame, NameFinder *finder, 
187                                       jstring *sourceFileName, jint *lineNum,
188                                       jstring *methodName)
189 {
190 #ifdef INTERPRETER
191   if (frame->type == frame_interpreter)
192     {
193       _Jv_InterpMethod *interp_meth = frame->interp.meth;
194       _Jv_InterpClass *interp_class = 
195          (_Jv_InterpClass *) interp_meth->defining_class->aux_info;
196       *sourceFileName = interp_class->source_file_name;
197       // The interpreter advances the PC before executing an instruction,
198       // so roll-back 1 byte to ensure the line number is accurate.
199       *lineNum = interp_meth->get_source_line(frame->interp.pc - 1);
200       return;
201     }
202 #endif
203
204   // Use _Jv_platform_dladdr() to determine in which binary the address IP
205   // resides.
206   _Jv_AddrInfo info;
207   jstring binaryName = NULL;
208   const char *argv0 = _Jv_GetSafeArg(0);
209
210   void *ip = frame->ip;
211   _Unwind_Ptr offset = 0;
212
213   if (_Jv_platform_dladdr (ip, &info))
214     {
215       if (info.file_name)
216         binaryName = JvNewStringUTF (info.file_name);
217       else
218         return;
219
220       if (*methodName == NULL && info.sym_name)
221         *methodName = JvNewStringUTF (info.sym_name);
222
223       // addr2line expects relative addresses for shared libraries.
224       if (strcmp (info.file_name, argv0) == 0)
225         offset = (_Unwind_Ptr) ip;
226       else
227         offset = (_Unwind_Ptr) ip - (_Unwind_Ptr) info.base;
228
229 #ifndef HAVE_GETIPINFO
230       // The unwinder gives us the return address. In order to get the right
231       // line number for the stack trace, roll it back a little.
232       offset -= 1;
233 #endif
234
235       finder->lookup (binaryName, (jlong) offset);
236       *sourceFileName = finder->getSourceFile();
237       *lineNum = finder->getLineNum();
238       if (*lineNum == -1 && NameFinder::showRaw())
239         {
240           gnu::gcj::runtime::StringBuffer *t =
241             new gnu::gcj::runtime::StringBuffer(binaryName);
242           t->append ((jchar)' ');
243           t->append ((jchar)'[');
244           // + 1 to compensate for the - 1 adjustment above;
245           t->append (Long::toHexString (offset + 1));
246           t->append ((jchar)']');
247           *sourceFileName = t->toString();
248         }
249     }
250 }
251
252 // Look up class and method info for the given stack frame, setting 
253 // frame->klass and frame->meth if they are known.
254 void
255 _Jv_StackTrace::FillInFrameInfo (_Jv_StackFrame *frame)
256 {
257   jclass klass = NULL;
258   _Jv_Method *meth = NULL;
259   
260   if (frame->type == frame_native)
261     {
262       klass = _Jv_StackTrace::ClassForFrame (frame);
263
264       if (klass != NULL)
265         // Find method in class
266         for (int j = 0; j < klass->method_count; j++)
267           {
268             void *wncode = UNWRAP_FUNCTION_DESCRIPTOR (klass->methods[j].ncode);
269             if (wncode == frame->start_ip)
270               {
271                 meth = &klass->methods[j];
272                 break;
273               }
274           }
275     }
276 #ifdef INTERPRETER
277   else if (frame->type == frame_interpreter)
278     {
279       _Jv_InterpMethod *interp_meth = frame->interp.meth;
280       klass = interp_meth->defining_class;
281       meth = interp_meth->self;
282     }
283 #endif
284   else
285     JvFail ("Unknown frame type");
286   
287   frame->klass = klass;
288   frame->meth = meth;
289 }
290
291 // Convert raw stack frames to a Java array of StackTraceElement objects.
292 JArray< ::java::lang::StackTraceElement *>*
293 _Jv_StackTrace::GetStackTraceElements (_Jv_StackTrace *trace, 
294   Throwable *throwable __attribute__((unused)))
295 {
296   ArrayList *list = new ArrayList ();
297
298 #if defined (SJLJ_EXCEPTIONS) && ! defined (WIN32)
299   // We can't use the nCodeMap without unwinder support. Instead,
300   // fake the method name by giving the IP in hex - better than nothing.  
301   jstring hex = JvNewStringUTF ("0x");
302
303   for (int i = 0; i < trace->length; i++)
304     {
305       jstring sourceFileName = NULL;
306       jint lineNum = -1;
307       _Jv_StackFrame *frame = &trace->frames[i];
308       
309       jstring className = NULL;
310       jstring methodName = hex->concat (Long::toHexString ((jlong) frame->ip));
311
312       StackTraceElement *element = new StackTraceElement (sourceFileName, 
313         lineNum, className, methodName, 0);    
314       list->add (element);
315     }
316
317 #else /* SJLJ_EXCEPTIONS && !WIN32 */
318
319   //JvSynchronized (ncodeMap);
320   UpdateNCodeMap ();
321
322   NameFinder *finder = new NameFinder();
323   int start_idx = 0;
324   int end_idx = trace->length - 1;
325
326   // First pass: strip superfluous frames from beginning and end of the trace.  
327   for (int i = 0; i < trace->length; i++)
328     {
329       _Jv_StackFrame *frame = &trace->frames[i];
330       FillInFrameInfo (frame);
331
332       if (!frame->klass || !frame->meth)
333         // Not a Java frame.
334         continue;
335
336       // Throw away the top of the stack till we see:
337       //  - the constructor(s) of this Throwable, or
338       //  - the Throwable.fillInStackTrace call.
339       if (frame->klass == throwable->getClass()
340           && strcmp (frame->meth->name->chars(), "<init>") == 0)
341         start_idx = i + 1;
342
343       if (frame->klass == &Throwable::class$
344           && strcmp (frame->meth->name->chars(), "fillInStackTrace") == 0)
345         start_idx = i + 1;
346
347       // End the trace at the application's main() method if we see call_main.
348       if (frame->klass == &gnu::java::lang::MainThread::class$
349           && strcmp (frame->meth->name->chars(), "call_main") == 0)
350         end_idx = i - 1;
351     }
352   
353   const jboolean remove_unknown 
354     = gnu::gcj::runtime::NameFinder::removeUnknown();
355
356   // Second pass: Look up line-number info for remaining frames.
357   for (int i = start_idx; i <= end_idx; i++)
358     {
359       _Jv_StackFrame *frame = &trace->frames[i];
360       
361       if (frame->klass == NULL && remove_unknown)
362         // Not a Java frame.
363         continue;
364
365       jstring className = NULL;
366       if (frame->klass != NULL)
367         className = frame->klass->getName ();
368
369       jstring methodName = NULL;
370       if (frame->meth)
371         methodName = JvNewStringUTF (frame->meth->name->chars());
372       
373       jstring sourceFileName = NULL;
374       jint lineNum = -1;
375       
376       getLineNumberForFrame(frame, finder, &sourceFileName, &lineNum, 
377                             &methodName);
378       
379       StackTraceElement *element = new StackTraceElement (sourceFileName, lineNum,
380         className, methodName, 0);
381       list->add (element);
382     }
383   
384   finder->close();
385 #endif /* SJLJ_EXCEPTIONS && !WIN32 */
386
387   JArray<Object *> *array = JvNewObjectArray (list->size (), 
388     &StackTraceElement::class$, NULL);
389
390   return (JArray<StackTraceElement *>*) list->toArray (array);
391 }
392
393 struct CallingClassTraceData
394 {
395   jclass checkClass;    
396   jclass foundClass;
397   _Jv_Method *foundMeth;
398   bool seen_checkClass;
399 };
400
401 _Unwind_Reason_Code
402 _Jv_StackTrace::calling_class_trace_fn (_Jv_UnwindState *state)
403 {
404   CallingClassTraceData *trace_data = (CallingClassTraceData *)
405     state->trace_data;
406   _Jv_StackFrame *frame = &state->frames[state->pos];
407   FillInFrameInfo (frame);
408
409   if (trace_data->seen_checkClass
410       && frame->klass
411       && frame->klass != trace_data->checkClass)
412     {
413       trace_data->foundClass = frame->klass;
414       trace_data->foundMeth = frame->meth;
415       return _URC_NORMAL_STOP;
416     }
417   
418   if (frame->klass == trace_data->checkClass)
419     trace_data->seen_checkClass = true;
420     
421   return _URC_NO_REASON;
422 }
423
424 // Find the class immediately above the given class on the call stack. Any 
425 // intermediate non-Java 
426 // frames are ignored. If the calling class could not be determined (eg because 
427 // the unwinder is not supported on this platform), NULL is returned.
428 // This function is used to implement calling-classloader checks and reflection
429 // accessibility checks.
430 // CHECKCLASS is typically the class calling GetCallingClass. The first class
431 // above CHECKCLASS on the call stack will be returned.
432 jclass
433 _Jv_StackTrace::GetCallingClass (jclass checkClass)
434 {
435   jclass result = NULL;
436   GetCallerInfo (checkClass, &result, NULL);
437   return result;
438 }
439
440 void
441 _Jv_StackTrace::GetCallerInfo (jclass checkClass, jclass *caller_class,
442   _Jv_Method **caller_meth)
443 {
444   int trace_size = 20;
445   _Jv_StackFrame frames[trace_size];
446   _Jv_UnwindState state (trace_size);
447   state.frames = (_Jv_StackFrame *) &frames;
448
449   CallingClassTraceData trace_data;
450   trace_data.checkClass = checkClass;
451   trace_data.seen_checkClass = false;
452   trace_data.foundClass = NULL;
453   trace_data.foundMeth = NULL;
454
455   state.trace_function = calling_class_trace_fn;
456   state.trace_data = (void *) &trace_data;
457
458   //JvSynchronized (ncodeMap);
459   UpdateNCodeMap ();
460
461   _Unwind_Backtrace (UnwindTraceFn, &state);
462   
463   if (caller_class)
464     *caller_class = trace_data.foundClass;
465   if (caller_meth)
466     *caller_meth = trace_data.foundMeth;
467 }
468
469 // Return a java array containing the Java classes on the stack above CHECKCLASS.
470 JArray<jclass> *
471 _Jv_StackTrace::GetClassContext (jclass checkClass)
472 {
473   JArray<jclass> *result = NULL;
474
475   int trace_size = 100;
476   _Jv_StackFrame frames[trace_size];
477   _Jv_UnwindState state (trace_size);
478   state.frames = (_Jv_StackFrame *) &frames;
479
480   //JvSynchronized (ncodeMap);
481   UpdateNCodeMap ();
482
483   _Unwind_Backtrace (UnwindTraceFn, &state);
484
485   // Count the number of Java frames on the stack.
486   int jframe_count = 0;
487   bool seen_checkClass = false;
488   int start_pos = -1;
489   for (int i = 0; i < state.pos; i++)
490     {
491       _Jv_StackFrame *frame = &state.frames[i];
492       FillInFrameInfo (frame);
493       
494       if (seen_checkClass)
495         {
496           if (frame->klass)
497             {
498               jframe_count++;
499               if (start_pos == -1)
500                 start_pos = i;
501             }
502         }
503       else
504         seen_checkClass = frame->klass == checkClass;
505     }
506   result = (JArray<jclass> *) _Jv_NewObjectArray (jframe_count, &Class::class$, NULL);
507   int pos = 0;
508   
509   for (int i = start_pos; i < state.pos; i++)
510     {
511       _Jv_StackFrame *frame = &state.frames[i];
512       if (frame->klass)
513         elements(result)[pos++] = frame->klass;
514     }
515   return result;
516 }
517
518 _Unwind_Reason_Code
519 _Jv_StackTrace::non_system_trace_fn (_Jv_UnwindState *state)
520 {
521   _Jv_StackFrame *frame = &state->frames[state->pos];
522   FillInFrameInfo (frame);
523   
524   ClassLoader *classLoader = NULL;
525
526   if (frame->klass)
527     {
528       classLoader = frame->klass->getClassLoaderInternal();
529 #ifdef INTERPRETER
530       if (classLoader != NULL)
531         {
532           state->trace_data = (void *) classLoader;
533           return _URC_NORMAL_STOP;
534         }
535 #endif
536     }
537
538   return _URC_NO_REASON;
539 }
540
541 ClassLoader *
542 _Jv_StackTrace::GetFirstNonSystemClassLoader ()
543 {
544   int trace_size = 32;
545   _Jv_StackFrame frames[trace_size];
546   _Jv_UnwindState state (trace_size);
547   state.frames = (_Jv_StackFrame *) &frames;
548   state.trace_function = non_system_trace_fn;
549   state.trace_data = NULL;
550
551   //JvSynchronized (ncodeMap);
552   UpdateNCodeMap ();
553   
554   _Unwind_Backtrace (UnwindTraceFn, &state);
555
556   if (state.trace_data)
557     return (ClassLoader *) state.trace_data;
558   
559   return NULL;
560 }
561
562 struct AccessControlTraceData
563 {
564   jint length;
565   jboolean privileged;
566 };
567
568 _Unwind_Reason_Code
569 _Jv_StackTrace::accesscontrol_trace_fn (_Jv_UnwindState *state)
570 {
571   AccessControlTraceData *trace_data = (AccessControlTraceData *)
572     state->trace_data;
573   _Jv_StackFrame *frame = &state->frames[state->pos];
574   FillInFrameInfo (frame);
575
576   if (!(frame->klass && frame->meth))
577     return _URC_NO_REASON;
578
579   trace_data->length++;
580
581   // If the previous frame was a call to doPrivileged, then this is
582   // the last frame we look at.
583   if (trace_data->privileged)
584     return _URC_NORMAL_STOP;
585   
586   if (frame->klass == &::java::security::AccessController::class$
587       && strcmp (frame->meth->name->chars(), "doPrivileged") == 0)
588     trace_data->privileged = true;
589
590   return _URC_NO_REASON;
591 }
592
593 jobjectArray
594 _Jv_StackTrace::GetAccessControlStack (void)
595 {
596   int trace_size = 100;
597   _Jv_StackFrame frames[trace_size];
598   _Jv_UnwindState state (trace_size);
599   state.frames = (_Jv_StackFrame *) &frames;
600
601   AccessControlTraceData trace_data;
602   trace_data.length = 0;
603   trace_data.privileged = false;
604   
605   state.trace_function = accesscontrol_trace_fn;
606   state.trace_data = (void *) &trace_data;
607
608   UpdateNCodeMap();
609   _Unwind_Backtrace (UnwindTraceFn, &state);
610
611   JArray<jclass> *classes = (JArray<jclass> *)
612     _Jv_NewObjectArray (trace_data.length, &::java::lang::Class::class$, NULL);
613   jclass *c = elements (classes);
614
615   for (int i = 0, j = 0; i < state.pos; i++)
616     {
617       _Jv_StackFrame *frame = &state.frames[i];
618       if (!frame->klass || !frame->meth)
619         continue;
620       c[j] = frame->klass;
621       j++;
622     }
623
624   jobjectArray result =
625     (jobjectArray) _Jv_NewObjectArray (2, &::java::lang::Object::class$,
626                                          NULL);
627   jobject *r = elements (result);
628   r[0] = (jobject) classes;
629   r[1] = (jobject) new Boolean (trace_data.privileged);
630   
631   return result;
632 }