[arm] Fix the handling of callee saved fp registers during unwinding, previously...
authorZoltan Varga <vargaz@gmail.com>
Mon, 25 May 2015 15:00:32 +0000 (11:00 -0400)
committerZoltan Varga <vargaz@gmail.com>
Mon, 25 May 2015 15:00:37 +0000 (11:00 -0400)
mono/mini/exceptions-arm.c
mono/mini/mini-arm.h
mono/mini/mini-unwind.h
mono/mini/unwind.c

index 7f57eea44ecc7b2d2e469e996297d4aa32e9f87f..091122262bb7cadcb4d300cda30b5e1915a09fa2 100644 (file)
@@ -403,7 +403,7 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls,
 
        if (ji != NULL) {
                int i;
-               gssize regs [MONO_MAX_IREGS + 1 + 8];
+               mono_unwind_reg_t regs [MONO_MAX_IREGS + 1 + 8];
                guint8 *cfa;
                guint32 unwind_info_len;
                guint8 *unwind_info;
@@ -422,7 +422,7 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls,
 #ifdef TARGET_IOS
                /* On IOS, d8..d15 are callee saved. They are mapped to 8..15 in unwind.c */
                for (i = 0; i < 8; ++i)
-                       regs [MONO_MAX_IREGS + i] = new_ctx->fregs [8 + i];
+                       regs [MONO_MAX_IREGS + i] = *(guint64*)&(new_ctx->fregs [8 + i]);
 #endif
 
                mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start, 
@@ -436,7 +436,7 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls,
                new_ctx->regs [ARMREG_SP] = (gsize)cfa;
 #ifdef TARGET_IOS
                for (i = 0; i < 8; ++i)
-                       new_ctx->fregs [8 + i] = regs [MONO_MAX_IREGS + i];
+                       new_ctx->fregs [8 + i] = *(double*)&(regs [MONO_MAX_IREGS + i]);
 #endif
 
                /* Clear thumb bit */
index 0757138a56354cc706a41530700a891eab4589c7..47806592b6d2ca0891422fdbee669a64a83a02b7 100644 (file)
  * reproduceable results for benchmarks */
 #define MONO_ARCH_CODE_ALIGNMENT 32
 
+/* This needs to hold both a 32 bit int and a 64 bit double */
+#define mono_unwind_reg_t guint64
+
 /* Argument marshallings for calls between gsharedvt and normal code */
 typedef enum {
        GSHAREDVT_ARG_NONE = 0,
index 5cb56383b22f01204cb196a468f784e2835d5129..657cc7708733634fb42208d8378dda25d6af5e53 100644 (file)
 
 #include "mini.h"
 
+/* This is the same as mgreg_t, except on 32 bit bit platforms with callee saved fp regs */
+#ifndef mono_unwind_reg_t
+#define mono_unwind_reg_t mgreg_t
+#endif
+
 /*
  * This is a platform-independent interface for unwinding through stack frames 
  * based on the Dwarf unwinding interface.
@@ -145,7 +150,7 @@ mono_unwind_ops_encode (GSList *unwind_ops, guint32 *out_len);
 void
 mono_unwind_frame (guint8 *unwind_info, guint32 unwind_info_len, 
                                   guint8 *start_ip, guint8 *end_ip, guint8 *ip, guint8 **mark_locations,
-                                  mgreg_t *regs, int nregs,
+                                  mono_unwind_reg_t *regs, int nregs,
                                   mgreg_t **save_locations, int save_locations_len,
                                   guint8 **out_cfa);
 
index 17bf3ad8962d35d90c07c8602049fe59a2b73a9b..52b292ef0808a7d2b96920791df7d7584af5f6f7 100644 (file)
@@ -51,11 +51,12 @@ static int map_hw_reg_to_dwarf_reg [] = { 0, 2, 1, 3, 7, 6, 4, 5, 8, 9, 10, 11,
 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (AMD64_RIP))
 #elif defined(TARGET_ARM)
 // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0040a/IHI0040A_aadwarf.pdf
-/* Assign d8..d15 to hregs 16..24 */
+/* Assign d8..d15 to hregs 16..24 (dwarf regs 264..271) */
 static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 264, 265, 266, 267, 268, 269, 270, 271 };
 #define NUM_REGS 272
 #define DWARF_DATA_ALIGN (-4)
 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (ARMREG_LR))
+#define IS_DOUBLE_REG(dwarf_reg) (((dwarf_reg) >= 264) && ((dwarf_reg) <= 271))
 #elif defined(TARGET_ARM64)
 #define NUM_REGS 96
 #define DWARF_DATA_ALIGN (-8)
@@ -109,6 +110,10 @@ static int map_hw_reg_to_dwarf_reg [16];
 #define DWARF_PC_REG -1
 #endif
 
+#ifndef IS_DOUBLE_REG
+#define IS_DOUBLE_REG(dwarf_reg) 0
+#endif
+
 static gboolean dwarf_reg_to_hw_reg_inited;
 
 static int map_dwarf_reg_to_hw_reg [NUM_REGS];
@@ -480,7 +485,7 @@ typedef struct {
 void
 mono_unwind_frame (guint8 *unwind_info, guint32 unwind_info_len, 
                                   guint8 *start_ip, guint8 *end_ip, guint8 *ip, guint8 **mark_locations,
-                                  mgreg_t *regs, int nregs,
+                                  mono_unwind_reg_t *regs, int nregs,
                                   mgreg_t **save_locations, int save_locations_len,
                                   guint8 **out_cfa)
 {
@@ -602,7 +607,10 @@ mono_unwind_frame (guint8 *unwind_info, guint32 unwind_info_len,
                if (reg_saved [i] && locations [i].loc_type == LOC_OFFSET) {
                        int hreg = mono_dwarf_reg_to_hw_reg (i);
                        g_assert (hreg < nregs);
-                       regs [hreg] = *(mgreg_t*)(cfa_val + locations [i].offset);
+                       if (IS_DOUBLE_REG (i))
+                               regs [hreg] = *(guint64*)(cfa_val + locations [i].offset);
+                       else
+                               regs [hreg] = *(mgreg_t*)(cfa_val + locations [i].offset);
                        if (save_locations && hreg < save_locations_len)
                                save_locations [hreg] = (mgreg_t*)(cfa_val + locations [i].offset);
                }