stacktrace.cc 22 KB

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