PageRenderTime 809ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/mono/mini/exceptions-arm.c

https://github.com/mantasp/mono
C | 537 lines | 284 code | 86 blank | 167 comment | 26 complexity | 9fad6e7e924e78813934a3aab9b62062 MD5 | raw file
  1. /*
  2. * exceptions-arm.c: exception support for ARM
  3. *
  4. * Authors:
  5. * Dietmar Maurer (dietmar@ximian.com)
  6. * Paolo Molaro (lupus@ximian.com)
  7. *
  8. * (C) 2001 Ximian, Inc.
  9. */
  10. #include <config.h>
  11. #include <glib.h>
  12. #include <signal.h>
  13. #include <string.h>
  14. #ifdef HAVE_ASM_SIGCONTEXT_H
  15. #include <asm/sigcontext.h>
  16. #endif /* def HAVE_ASM_SIGCONTEXT_H */
  17. #ifdef HAVE_UCONTEXT_H
  18. #include <ucontext.h>
  19. #endif /* def HAVE_UCONTEXT_H */
  20. #include <mono/arch/arm/arm-codegen.h>
  21. #include <mono/metadata/appdomain.h>
  22. #include <mono/metadata/tabledefs.h>
  23. #include <mono/metadata/threads.h>
  24. #include <mono/metadata/debug-helpers.h>
  25. #include <mono/metadata/exception.h>
  26. #include <mono/metadata/mono-debug.h>
  27. #include "mini.h"
  28. #include "mini-arm.h"
  29. /*
  30. struct sigcontext {
  31. unsigned long trap_no;
  32. unsigned long error_code;
  33. unsigned long oldmask;
  34. unsigned long arm_r0;
  35. unsigned long arm_r1;
  36. unsigned long arm_r2;
  37. unsigned long arm_r3;
  38. unsigned long arm_r4;
  39. unsigned long arm_r5;
  40. unsigned long arm_r6;
  41. unsigned long arm_r7;
  42. unsigned long arm_r8;
  43. unsigned long arm_r9;
  44. unsigned long arm_r10;
  45. unsigned long arm_fp;
  46. unsigned long arm_ip;
  47. unsigned long arm_sp;
  48. unsigned long arm_lr;
  49. unsigned long arm_pc;
  50. unsigned long arm_cpsr;
  51. unsigned long fault_address;
  52. };
  53. gregs below is this struct
  54. struct user_regs {
  55. unsigned long int uregs[18];
  56. };
  57. the companion user_fpregs has just 8 double registers
  58. (it's valid for FPA mode, will need changes for VFP)
  59. typedef struct {
  60. gregset_t gregs;
  61. fpregset_t fpregs;
  62. } mcontext_t;
  63. typedef struct ucontext {
  64. unsigned long int uc_flags;
  65. struct ucontext *uc_link;
  66. __sigset_t uc_sigmask;
  67. stack_t uc_stack;
  68. mcontext_t uc_mcontext;
  69. long int uc_filler[5];
  70. } ucontext_t;
  71. */
  72. /*
  73. * So, it turns out that the ucontext struct defined by libc is incorrect.
  74. * We define our own version here and use it instead.
  75. */
  76. #if __APPLE__
  77. #define my_ucontext ucontext_t
  78. #else
  79. typedef struct my_ucontext {
  80. unsigned long uc_flags;
  81. struct my_ucontext *uc_link;
  82. struct {
  83. void *p;
  84. int flags;
  85. size_t size;
  86. } sstack_data;
  87. struct sigcontext sig_ctx;
  88. /* some 2.6.x kernel has fp data here after a few other fields
  89. * we don't use them for now...
  90. */
  91. } my_ucontext;
  92. #endif
  93. /*
  94. * arch_get_restore_context:
  95. *
  96. * Returns a pointer to a method which restores a previously saved sigcontext.
  97. * The first argument in r0 is the pointer to the context.
  98. */
  99. gpointer
  100. mono_arch_get_restore_context_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
  101. {
  102. guint8 *code;
  103. guint8 *start;
  104. int ctx_reg;
  105. *ji = NULL;
  106. start = code = mono_global_codeman_reserve (128);
  107. /*
  108. * Move things to their proper place so we can restore all the registers with
  109. * one instruction.
  110. */
  111. ctx_reg = ARMREG_R0;
  112. /* move eip to PC */
  113. ARM_LDR_IMM (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET (MonoContext, eip));
  114. ARM_STR_IMM (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET (MonoContext, regs) + (ARMREG_PC * 4));
  115. /* move sp to SP */
  116. ARM_LDR_IMM (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET (MonoContext, esp));
  117. ARM_STR_IMM (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET (MonoContext, regs) + (ARMREG_SP * 4));
  118. /* move ebp to FP */
  119. ARM_LDR_IMM (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET (MonoContext, ebp));
  120. ARM_STR_IMM (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET (MonoContext, regs) + (ARMREG_FP * 4));
  121. /* restore everything */
  122. ARM_ADD_REG_IMM8 (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET(MonoContext, regs));
  123. ARM_LDM (code, ARMREG_IP, 0xffff);
  124. /* never reached */
  125. ARM_DBRK (code);
  126. g_assert ((code - start) < 128);
  127. mono_arch_flush_icache (start, code - start);
  128. *code_size = code - start;
  129. return start;
  130. }
  131. /*
  132. * arch_get_call_filter:
  133. *
  134. * Returns a pointer to a method which calls an exception filter. We
  135. * also use this function to call finally handlers (we pass NULL as
  136. * @exc object in this case).
  137. */
  138. gpointer
  139. mono_arch_get_call_filter_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
  140. {
  141. guint8 *code;
  142. guint8* start;
  143. int ctx_reg;
  144. *ji = NULL;
  145. /* call_filter (MonoContext *ctx, unsigned long eip, gpointer exc) */
  146. start = code = mono_global_codeman_reserve (320);
  147. /* save all the regs on the stack */
  148. ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_SP);
  149. ARM_PUSH (code, MONO_ARM_REGSAVE_MASK);
  150. /* restore all the regs from ctx (in r0), but not sp, the stack pointer */
  151. ctx_reg = ARMREG_R0;
  152. ARM_LDR_IMM (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET (MonoContext, eip));
  153. ARM_ADD_REG_IMM8 (code, ARMREG_LR, ctx_reg, G_STRUCT_OFFSET(MonoContext, regs) + (4 * 4));
  154. ARM_LDM (code, ARMREG_LR, MONO_ARM_REGSAVE_MASK);
  155. /* call handler at eip (r1) and set the first arg with the exception (r2) */
  156. ARM_MOV_REG_REG (code, ARMREG_R0, ARMREG_R2);
  157. ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
  158. ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_R1);
  159. /* epilog */
  160. ARM_POP_NWB (code, 0xff0 | ((1 << ARMREG_SP) | (1 << ARMREG_PC)));
  161. g_assert ((code - start) < 320);
  162. mono_arch_flush_icache (start, code - start);
  163. *code_size = code - start;
  164. return start;
  165. }
  166. void
  167. mono_arm_throw_exception (MonoObject *exc, unsigned long eip, unsigned long esp, gulong *int_regs, gdouble *fp_regs)
  168. {
  169. static void (*restore_context) (MonoContext *);
  170. MonoContext ctx;
  171. gboolean rethrow = eip & 1;
  172. if (!restore_context)
  173. restore_context = mono_get_restore_context ();
  174. eip &= ~1; /* clear the optional rethrow bit */
  175. /* adjust eip so that it point into the call instruction */
  176. eip -= 4;
  177. /*printf ("stack in throw: %p\n", esp);*/
  178. MONO_CONTEXT_SET_BP (&ctx, int_regs [ARMREG_FP - 4]);
  179. MONO_CONTEXT_SET_SP (&ctx, esp);
  180. MONO_CONTEXT_SET_IP (&ctx, eip);
  181. memcpy (((guint8*)&ctx.regs) + (4 * 4), int_regs, sizeof (gulong) * 8);
  182. /* memcpy (&ctx.fregs, fp_regs, sizeof (double) * MONO_SAVED_FREGS); */
  183. if (mono_object_isinst (exc, mono_defaults.exception_class)) {
  184. MonoException *mono_ex = (MonoException*)exc;
  185. if (!rethrow)
  186. mono_ex->stack_trace = NULL;
  187. }
  188. mono_handle_exception (&ctx, exc, (gpointer)(eip + 4), FALSE);
  189. restore_context (&ctx);
  190. g_assert_not_reached ();
  191. }
  192. void
  193. mono_arm_throw_exception_by_token (guint32 type_token, unsigned long eip, unsigned long esp, gulong *int_regs, gdouble *fp_regs)
  194. {
  195. mono_arm_throw_exception ((MonoObject*)mono_exception_from_token (mono_defaults.corlib, type_token), eip, esp, int_regs, fp_regs);
  196. }
  197. /**
  198. * arch_get_throw_exception_generic:
  199. *
  200. * Returns a function pointer which can be used to raise
  201. * exceptions. The returned function has the following
  202. * signature: void (*func) (MonoException *exc); or
  203. * void (*func) (guint32 ex_token, guint8* ip);
  204. *
  205. */
  206. static gpointer
  207. mono_arch_get_throw_exception_generic (int size, int by_token, gboolean rethrow, guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
  208. {
  209. guint8 *start;
  210. guint8 *code;
  211. *ji = NULL;
  212. code = start = mono_global_codeman_reserve (size);
  213. /* save all the regs on the stack */
  214. ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_SP);
  215. ARM_PUSH (code, MONO_ARM_REGSAVE_MASK);
  216. /* call throw_exception (exc, ip, sp, int_regs, fp_regs) */
  217. /* caller sp */
  218. ARM_ADD_REG_IMM8 (code, ARMREG_R2, ARMREG_SP, 10 * 4); /* 10 saved regs */
  219. /* exc is already in place in r0 */
  220. if (by_token) {
  221. /* The caller ip is already in R1 */
  222. } else {
  223. ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_LR); /* caller ip */
  224. }
  225. /* FIXME: pointer to the saved fp regs */
  226. /*pos = alloc_size - sizeof (double) * MONO_SAVED_FREGS;
  227. ppc_addi (code, ppc_r7, ppc_sp, pos);*/
  228. /* pointer to the saved int regs */
  229. ARM_MOV_REG_REG (code, ARMREG_R3, ARMREG_SP); /* the pushed regs */
  230. /* we encode rethrow in the ip, so we avoid args on the stack */
  231. ARM_ORR_REG_IMM8 (code, ARMREG_R1, ARMREG_R1, rethrow);
  232. if (aot) {
  233. *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_JIT_ICALL_ADDR, by_token ? "mono_arm_throw_exception_by_token" : "mono_arm_throw_exception");
  234. ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
  235. ARM_B (code, 0);
  236. *(gpointer*)(gpointer)code = NULL;
  237. code += 4;
  238. ARM_LDR_REG_REG (code, ARMREG_IP, ARMREG_PC, ARMREG_IP);
  239. } else {
  240. code = mono_arm_emit_load_imm (code, ARMREG_IP, GPOINTER_TO_UINT (by_token ? (gpointer)mono_arm_throw_exception_by_token : (gpointer)mono_arm_throw_exception));
  241. }
  242. ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
  243. ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
  244. /* we should never reach this breakpoint */
  245. ARM_DBRK (code);
  246. g_assert ((code - start) < size);
  247. mono_arch_flush_icache (start, code - start);
  248. *code_size = code - start;
  249. return start;
  250. }
  251. /**
  252. * mono_arch_get_rethrow_exception:
  253. *
  254. * Returns a function pointer which can be used to rethrow
  255. * exceptions. The returned function has the following
  256. * signature: void (*func) (MonoException *exc);
  257. *
  258. */
  259. gpointer
  260. mono_arch_get_rethrow_exception_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
  261. {
  262. return mono_arch_get_throw_exception_generic (132, FALSE, TRUE, code_size, ji, aot);
  263. }
  264. /**
  265. * arch_get_throw_exception:
  266. *
  267. * Returns a function pointer which can be used to raise
  268. * exceptions. The returned function has the following
  269. * signature: void (*func) (MonoException *exc);
  270. * For example to raise an arithmetic exception you can use:
  271. *
  272. * x86_push_imm (code, mono_get_exception_arithmetic ());
  273. * x86_call_code (code, arch_get_throw_exception ());
  274. *
  275. */
  276. gpointer
  277. mono_arch_get_throw_exception_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
  278. {
  279. return mono_arch_get_throw_exception_generic (132, FALSE, FALSE, code_size, ji, aot);
  280. }
  281. gpointer
  282. mono_arch_get_throw_exception_by_name_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
  283. {
  284. guint8* start;
  285. guint8 *code;
  286. *ji = NULL;
  287. start = code = mono_global_codeman_reserve (64);
  288. /* Not used on ARM */
  289. ARM_DBRK (code);
  290. *code_size = code - start;
  291. return start;
  292. }
  293. /**
  294. * mono_arch_get_throw_corlib_exception:
  295. *
  296. * Returns a function pointer which can be used to raise
  297. * corlib exceptions. The returned function has the following
  298. * signature: void (*func) (guint32 ex_token, guint32 offset);
  299. * Here, offset is the offset which needs to be substracted from the caller IP
  300. * to get the IP of the throw. Passing the offset has the advantage that it
  301. * needs no relocations in the caller.
  302. * On ARM, the ip is passed instead of an offset.
  303. */
  304. gpointer
  305. mono_arch_get_throw_corlib_exception_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
  306. {
  307. return mono_arch_get_throw_exception_generic (168, TRUE, FALSE, code_size, ji, aot);
  308. }
  309. /*
  310. * mono_arch_find_jit_info_ext:
  311. *
  312. * See exceptions-amd64.c for docs;
  313. */
  314. gboolean
  315. mono_arch_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls,
  316. MonoJitInfo *ji, MonoContext *ctx,
  317. MonoContext *new_ctx, MonoLMF **lmf,
  318. StackFrameInfo *frame)
  319. {
  320. gpointer ip = MONO_CONTEXT_GET_IP (ctx);
  321. memset (frame, 0, sizeof (StackFrameInfo));
  322. frame->ji = ji;
  323. frame->managed = FALSE;
  324. *new_ctx = *ctx;
  325. if (ji != NULL) {
  326. int i;
  327. gssize regs [MONO_MAX_IREGS + 1];
  328. guint8 *cfa;
  329. guint32 unwind_info_len;
  330. guint8 *unwind_info;
  331. frame->type = FRAME_TYPE_MANAGED;
  332. if (!ji->method->wrapper_type || ji->method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
  333. frame->managed = TRUE;
  334. if (ji->from_aot)
  335. unwind_info = mono_aot_get_unwind_info (ji, &unwind_info_len);
  336. else
  337. unwind_info = mono_get_cached_unwind_info (ji->used_regs, &unwind_info_len);
  338. for (i = 0; i < 16; ++i)
  339. regs [i] = new_ctx->regs [i];
  340. regs [ARMREG_SP] = new_ctx->esp;
  341. mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start,
  342. (guint8*)ji->code_start + ji->code_size,
  343. ip, regs, MONO_MAX_IREGS, &cfa);
  344. for (i = 0; i < 16; ++i)
  345. new_ctx->regs [i] = regs [i];
  346. new_ctx->eip = regs [ARMREG_LR];
  347. new_ctx->esp = (gsize)cfa;
  348. new_ctx->ebp = new_ctx->esp;
  349. if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
  350. /* remove any unused lmf */
  351. *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);
  352. }
  353. /* we substract 1, so that the IP points into the call instruction */
  354. new_ctx->eip--;
  355. return TRUE;
  356. } else if (*lmf) {
  357. if (((gsize)(*lmf)->previous_lmf) & 2) {
  358. /*
  359. * This LMF entry is created by the soft debug code to mark transitions to
  360. * managed code done during invokes.
  361. */
  362. MonoLMFExt *ext = (MonoLMFExt*)(*lmf);
  363. g_assert (ext->debugger_invoke);
  364. memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));
  365. *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);
  366. frame->type = FRAME_TYPE_DEBUGGER_INVOKE;
  367. return TRUE;
  368. }
  369. frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;
  370. if ((ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->eip, NULL))) {
  371. frame->ji = ji;
  372. } else {
  373. if (!(*lmf)->method)
  374. return FALSE;
  375. frame->method = (*lmf)->method;
  376. }
  377. memcpy (&new_ctx->regs [0], &(*lmf)->iregs [0], sizeof (gulong) * 13);
  378. /* SP is skipped */
  379. new_ctx->regs [ARMREG_LR] = (*lmf)->iregs [ARMREG_LR - 1];
  380. /* This is the sp for the current frame */
  381. new_ctx->esp = (*lmf)->iregs [ARMREG_FP];
  382. new_ctx->eip = (*lmf)->iregs [13];
  383. new_ctx->ebp = new_ctx->esp;
  384. *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);
  385. return TRUE;
  386. }
  387. return FALSE;
  388. }
  389. void
  390. mono_arch_sigctx_to_monoctx (void *sigctx, MonoContext *mctx)
  391. {
  392. #if BROKEN_LINUX || defined(MONO_CROSS_COMPILE)
  393. g_assert_not_reached ();
  394. #else
  395. my_ucontext *my_uc = sigctx;
  396. mctx->eip = UCONTEXT_REG_PC (my_uc);
  397. mctx->esp = UCONTEXT_REG_SP (my_uc);
  398. memcpy (&mctx->regs, &UCONTEXT_REG_R0 (my_uc), sizeof (gulong) * 16);
  399. #endif
  400. mctx->ebp = mctx->regs [ARMREG_FP];
  401. }
  402. void
  403. mono_arch_monoctx_to_sigctx (MonoContext *mctx, void *ctx)
  404. {
  405. #if BROKEN_LINUX || defined(MONO_CROSS_COMPILE)
  406. g_assert_not_reached ();
  407. #else
  408. my_ucontext *my_uc = ctx;
  409. UCONTEXT_REG_PC (my_uc) = mctx->eip;
  410. UCONTEXT_REG_SP (my_uc) = mctx->ebp;
  411. /* The upper registers are not guaranteed to be valid */
  412. memcpy (&UCONTEXT_REG_R0 (my_uc), &mctx->regs, sizeof (gulong) * 12);
  413. #endif
  414. }
  415. /*
  416. * This is the function called from the signal handler
  417. */
  418. gboolean
  419. mono_arch_handle_exception (void *ctx, gpointer obj, gboolean test_only)
  420. {
  421. MonoContext mctx;
  422. gboolean result;
  423. mono_arch_sigctx_to_monoctx (ctx, &mctx);
  424. result = mono_handle_exception (&mctx, obj, (gpointer)mctx.eip, test_only);
  425. /* restore the context so that returning from the signal handler will invoke
  426. * the catch clause
  427. */
  428. mono_arch_monoctx_to_sigctx (&mctx, ctx);
  429. return result;
  430. }
  431. gpointer
  432. mono_arch_ip_from_context (void *sigctx)
  433. {
  434. #if BROKEN_LINUX || defined(MONO_CROSS_COMPILE)
  435. g_assert_not_reached ();
  436. #else
  437. my_ucontext *my_uc = sigctx;
  438. return (void*) UCONTEXT_REG_PC (my_uc);
  439. #endif
  440. }
  441. gboolean
  442. mono_arch_has_unwind_info (gconstpointer addr)
  443. {
  444. return FALSE;
  445. }