[sgen] Don't assert in GC.GetTotalMemory.
[mono.git] / mono / mini / unwind.c
1 /*
2  * unwind.c: Stack Unwinding Interface
3  *
4  * Authors:
5  *   Zoltan Varga (vargaz@gmail.com)
6  *
7  * (C) 2008 Novell, Inc.
8  */
9
10 #include "mini.h"
11 #include "mini-unwind.h"
12
13 #include <mono/utils/mono-counters.h>
14 #include <mono/utils/freebsd-dwarf.h>
15 #include <mono/utils/hazard-pointer.h>
16 #include <mono/metadata/threads-types.h>
17 #include <mono/metadata/mono-endian.h>
18
19 typedef enum {
20         LOC_SAME,
21         LOC_OFFSET
22 } LocType;
23
24 typedef struct {
25         LocType loc_type;
26         int offset;
27 } Loc;
28
29 typedef struct {
30         guint32 len;
31         guint8 info [MONO_ZERO_LEN_ARRAY];
32 } MonoUnwindInfo;
33
34 #define ALIGN_TO(val,align) ((((size_t)val) + ((align) - 1)) & ~((align) - 1))
35
36 static mono_mutex_t unwind_mutex;
37
38 static MonoUnwindInfo **cached_info;
39 static int cached_info_next, cached_info_size;
40 static GSList *cached_info_list;
41 /* Statistics */
42 static int unwind_info_size;
43
44 #define unwind_lock() mono_mutex_lock (&unwind_mutex)
45 #define unwind_unlock() mono_mutex_unlock (&unwind_mutex)
46
47 #ifdef TARGET_AMD64
48 static int map_hw_reg_to_dwarf_reg [] = { 0, 2, 1, 3, 7, 6, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
49 #define NUM_REGS AMD64_NREG
50 #define DWARF_DATA_ALIGN (-8)
51 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (AMD64_RIP))
52 #elif defined(TARGET_ARM)
53 // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0040a/IHI0040A_aadwarf.pdf
54 /* Assign d8..d15 to hregs 16..24 */
55 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 };
56 #define NUM_REGS 272
57 #define DWARF_DATA_ALIGN (-4)
58 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (ARMREG_LR))
59 #elif defined(TARGET_ARM64)
60 #define NUM_REGS 96
61 #define DWARF_DATA_ALIGN (-8)
62 /* LR */
63 #define DWARF_PC_REG 30
64 static int map_hw_reg_to_dwarf_reg [] = {
65         0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
66         16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
67         /* v8..v15 */
68         72, 73, 74, 75, 76, 77, 78, 79,
69 };
70 #elif defined (TARGET_X86)
71 #ifdef __APPLE__
72 /*
73  * LLVM seems to generate unwind info where esp is encoded as 5, and ebp as 4, ie see this line:
74  *   def ESP : RegisterWithSubRegs<"esp", [SP]>, DwarfRegNum<[-2, 5, 4]>;
75  * in lib/Target/X86/X86RegisterInfo.td in the llvm sources.
76  */
77 static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 5, 4, 6, 7, 8 };
78 #else
79 static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
80 #endif
81 /* + 1 is for IP */
82 #define NUM_REGS X86_NREG + 1
83 #define DWARF_DATA_ALIGN (-4)
84 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (X86_NREG))
85 #elif defined (TARGET_POWERPC)
86 // http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html
87 static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 
88                                                                                   9, 10, 11, 12, 13, 14, 15, 16,
89                                                                                   17, 18, 19, 20, 21, 22, 23, 24,
90                                                                                   25, 26, 27, 28, 29, 30, 31 };
91 #define NUM_REGS 110
92 #define DWARF_DATA_ALIGN (-(gint32)sizeof (mgreg_t))
93 #define DWARF_PC_REG 108
94 #elif defined (TARGET_S390X)
95 static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
96 #define NUM_REGS 16
97 #define DWARF_DATA_ALIGN (-8)
98 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (14))
99 #elif defined (TARGET_MIPS)
100 /* FIXME: */
101 static int map_hw_reg_to_dwarf_reg [32] = {
102         0, 1, 2, 3, 4, 5, 6, 7,
103         8, 9, 10, 11, 12, 13, 14, 15,
104         16, 17, 18, 19, 20, 21, 22, 23,
105         24, 25, 26, 27, 28, 29, 30, 31
106 };
107 #define NUM_REGS 32
108 #define DWARF_DATA_ALIGN (-(gint32)sizeof (mgreg_t))
109 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (mips_ra))
110 #else
111 static int map_hw_reg_to_dwarf_reg [16];
112 #define NUM_REGS 16
113 #define DWARF_DATA_ALIGN 0
114 #define DWARF_PC_REG -1
115 #endif
116
117 static gboolean dwarf_reg_to_hw_reg_inited;
118
119 static int map_dwarf_reg_to_hw_reg [NUM_REGS];
120
121 /*
122  * mono_hw_reg_to_dwarf_reg:
123  *
124  *   Map the hardware register number REG to the register number used by DWARF.
125  */
126 int
127 mono_hw_reg_to_dwarf_reg (int reg)
128 {
129 #ifdef TARGET_POWERPC
130         if (reg == ppc_lr)
131                 return 108;
132         else
133                 g_assert (reg < NUM_REGS);
134 #endif
135
136         if (NUM_REGS == 0) {
137                 g_assert_not_reached ();
138                 return -1;
139         } else {
140                 return map_hw_reg_to_dwarf_reg [reg];
141         }
142 }
143
144 static void
145 init_reg_map (void)
146 {
147         int i;
148
149         g_assert (NUM_REGS > 0);
150         for (i = 0; i < sizeof (map_hw_reg_to_dwarf_reg) / sizeof (int); ++i) {
151                 map_dwarf_reg_to_hw_reg [mono_hw_reg_to_dwarf_reg (i)] = i;
152         }
153
154 #ifdef TARGET_POWERPC
155         map_dwarf_reg_to_hw_reg [DWARF_PC_REG] = ppc_lr;
156 #endif
157
158         mono_memory_barrier ();
159         dwarf_reg_to_hw_reg_inited = TRUE;
160 }
161
162 int
163 mono_dwarf_reg_to_hw_reg (int reg)
164 {
165         if (!dwarf_reg_to_hw_reg_inited)
166                 init_reg_map ();
167
168         return map_dwarf_reg_to_hw_reg [reg];
169 }
170
171 static G_GNUC_UNUSED void
172 encode_uleb128 (guint32 value, guint8 *buf, guint8 **endbuf)
173 {
174         guint8 *p = buf;
175
176         do {
177                 guint8 b = value & 0x7f;
178                 value >>= 7;
179                 if (value != 0) /* more bytes to come */
180                         b |= 0x80;
181                 *p ++ = b;
182         } while (value);
183
184         *endbuf = p;
185 }
186
187 static G_GNUC_UNUSED void
188 encode_sleb128 (gint32 value, guint8 *buf, guint8 **endbuf)
189 {
190         gboolean more = 1;
191         gboolean negative = (value < 0);
192         guint32 size = 32;
193         guint8 byte;
194         guint8 *p = buf;
195
196         while (more) {
197                 byte = value & 0x7f;
198                 value >>= 7;
199                 /* the following is unnecessary if the
200                  * implementation of >>= uses an arithmetic rather
201                  * than logical shift for a signed left operand
202                  */
203                 if (negative)
204                         /* sign extend */
205                         value |= - (1 <<(size - 7));
206                 /* sign bit of byte is second high order bit (0x40) */
207                 if ((value == 0 && !(byte & 0x40)) ||
208                         (value == -1 && (byte & 0x40)))
209                         more = 0;
210                 else
211                         byte |= 0x80;
212                 *p ++= byte;
213         }
214
215         *endbuf = p;
216 }
217
218 static inline guint32
219 decode_uleb128 (guint8 *buf, guint8 **endbuf)
220 {
221         guint8 *p = buf;
222         guint32 res = 0;
223         int shift = 0;
224
225         while (TRUE) {
226                 guint8 b = *p;
227                 p ++;
228
229                 res = res | (((int)(b & 0x7f)) << shift);
230                 if (!(b & 0x80))
231                         break;
232                 shift += 7;
233         }
234
235         *endbuf = p;
236
237         return res;
238 }
239
240 static inline gint32
241 decode_sleb128 (guint8 *buf, guint8 **endbuf)
242 {
243         guint8 *p = buf;
244         gint32 res = 0;
245         int shift = 0;
246
247         while (TRUE) {
248                 guint8 b = *p;
249                 p ++;
250
251                 res = res | (((int)(b & 0x7f)) << shift);
252                 shift += 7;
253                 if (!(b & 0x80)) {
254                         if (shift < 32 && (b & 0x40))
255                                 res |= - (1 << shift);
256                         break;
257                 }
258         }
259
260         *endbuf = p;
261
262         return res;
263 }
264
265 void
266 mono_print_unwind_info (guint8 *unwind_info, int unwind_info_len)
267 {
268         guint8 *p;
269         int pos, reg, offset, cfa_reg, cfa_offset;
270
271         p = unwind_info;
272         pos = 0;
273         while (p < unwind_info + unwind_info_len) {
274                 int op = *p & 0xc0;
275
276                 switch (op) {
277                 case DW_CFA_advance_loc:
278                         pos += *p & 0x3f;
279                         p ++;
280                         break;
281                 case DW_CFA_offset:
282                         reg = *p & 0x3f;
283                         p ++;
284                         offset = decode_uleb128 (p, &p) * DWARF_DATA_ALIGN;
285                         if (reg == DWARF_PC_REG)
286                                 printf ("CFA: [%x] offset: %s at cfa-0x%x\n", pos, "pc", -offset);
287                         else
288                                 printf ("CFA: [%x] offset: %s at cfa-0x%x\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (reg)), -offset);
289                         break;
290                 case 0: {
291                         int ext_op = *p;
292                         p ++;
293                         switch (ext_op) {
294                         case DW_CFA_def_cfa:
295                                 cfa_reg = decode_uleb128 (p, &p);
296                                 cfa_offset = decode_uleb128 (p, &p);
297                                 printf ("CFA: [%x] def_cfa: %s+0x%x\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (cfa_reg)), cfa_offset);
298                                 break;
299                         case DW_CFA_def_cfa_offset:
300                                 cfa_offset = decode_uleb128 (p, &p);
301                                 printf ("CFA: [%x] def_cfa_offset: 0x%x\n", pos, cfa_offset);
302                                 break;
303                         case DW_CFA_def_cfa_register:
304                                 cfa_reg = decode_uleb128 (p, &p);
305                                 printf ("CFA: [%x] def_cfa_reg: %s\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (cfa_reg)));
306                                 break;
307                         case DW_CFA_offset_extended_sf:
308                                 reg = decode_uleb128 (p, &p);
309                                 offset = decode_sleb128 (p, &p) * DWARF_DATA_ALIGN;
310                                 printf ("CFA: [%x] offset_extended_sf: %s at cfa-0x%x\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (reg)), -offset);
311                                 break;
312                         case DW_CFA_same_value:
313                                 reg = decode_uleb128 (p, &p);
314                                 printf ("CFA: [%x] same_value: %s\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (reg)));
315                                 break;
316                         case DW_CFA_advance_loc4:
317                                 pos += read32 (p);
318                                 p += 4;
319                                 break;
320                         case DW_CFA_remember_state:
321                                 printf ("CFA: [%x] remember_state\n", pos);
322                                 break;
323                         case DW_CFA_restore_state:
324                                 printf ("CFA: [%x] restore_state\n", pos);
325                                 break;
326                         case DW_CFA_mono_advance_loc:
327                                 printf ("CFA: [%x] mono_advance_loc\n", pos);
328                                 break;
329                         default:
330                                 g_assert_not_reached ();
331                         }
332                         break;
333                 }
334                 default:
335                         g_assert_not_reached ();
336                 }
337         }
338 }
339
340 /*
341  * mono_unwind_ops_encode:
342  *
343  *   Encode the unwind ops in UNWIND_OPS into the compact DWARF encoding.
344  * Return a pointer to malloc'ed memory.
345  */
346 guint8*
347 mono_unwind_ops_encode (GSList *unwind_ops, guint32 *out_len)
348 {
349         GSList *l;
350         MonoUnwindOp *op;
351         int loc;
352         guint8 buf [4096];
353         guint8 *p, *res;
354
355         p = buf;
356
357         loc = 0;
358         l = unwind_ops;
359         for (; l; l = l->next) {
360                 int reg;
361
362                 op = l->data;
363
364                 /* Convert the register from the hw encoding to the dwarf encoding */
365                 reg = mono_hw_reg_to_dwarf_reg (op->reg);
366
367                 if (op->op == DW_CFA_mono_advance_loc) {
368                         /* This advances loc to its location */
369                         loc = op->when;
370                 }
371
372                 /* Emit an advance_loc if neccesary */
373                 while (op->when > loc) {
374                         if (op->when - loc > 65536) {
375                                 *p ++ = DW_CFA_advance_loc4;
376                                 *(guint32*)p = (guint32)(op->when - loc);
377                                 g_assert (read32 (p) == (guint32)(op->when - loc));
378                                 p += 4;
379                                 loc = op->when;
380                         } else if (op->when - loc > 256) {
381                                 *p ++ = DW_CFA_advance_loc2;
382                                 *(guint16*)p = (guint16)(op->when - loc);
383                                 g_assert (read16 (p) == (guint32)(op->when - loc));
384                                 p += 2;
385                                 loc = op->when;
386                         } else if (op->when - loc >= 32) {
387                                 *p ++ = DW_CFA_advance_loc1;
388                                 *(guint8*)p = (guint8)(op->when - loc);
389                                 p += 1;
390                                 loc = op->when;
391                         } else if (op->when - loc < 32) {
392                                 *p ++ = DW_CFA_advance_loc | (op->when - loc);
393                                 loc = op->when;
394                         } else {
395                                 *p ++ = DW_CFA_advance_loc | (30);
396                                 loc += 30;
397                         }
398                 }                       
399
400                 switch (op->op) {
401                 case DW_CFA_def_cfa:
402                         *p ++ = op->op;
403                         encode_uleb128 (reg, p, &p);
404                         encode_uleb128 (op->val, p, &p);
405                         break;
406                 case DW_CFA_def_cfa_offset:
407                         *p ++ = op->op;
408                         encode_uleb128 (op->val, p, &p);
409                         break;
410                 case DW_CFA_def_cfa_register:
411                         *p ++ = op->op;
412                         encode_uleb128 (reg, p, &p);
413                         break;
414                 case DW_CFA_same_value:
415                         *p ++ = op->op;
416                         encode_uleb128 (reg, p, &p);
417                         break;
418                 case DW_CFA_offset:
419                         if (reg > 63) {
420                                 *p ++ = DW_CFA_offset_extended_sf;
421                                 encode_uleb128 (reg, p, &p);
422                                 encode_sleb128 (op->val / DWARF_DATA_ALIGN, p, &p);
423                         } else {
424                                 *p ++ = DW_CFA_offset | reg;
425                                 encode_uleb128 (op->val / DWARF_DATA_ALIGN, p, &p);
426                         }
427                         break;
428                 case DW_CFA_remember_state:
429                 case DW_CFA_restore_state:
430                         *p ++ = op->op;
431                         break;
432                 case DW_CFA_mono_advance_loc:
433                         /* Only one location is supported */
434                         g_assert (op->val == 0);
435                         *p ++ = op->op;
436                         break;
437                 default:
438                         g_assert_not_reached ();
439                         break;
440                 }
441         }
442         
443         g_assert (p - buf < 4096);
444         *out_len = p - buf;
445         res = g_malloc (p - buf);
446         memcpy (res, buf, p - buf);
447         return res;
448 }
449
450 #if 0
451 #define UNW_DEBUG(stmt) do { stmt; } while (0)
452 #else
453 #define UNW_DEBUG(stmt) do { } while (0)
454 #endif
455
456 static G_GNUC_UNUSED void
457 print_dwarf_state (int cfa_reg, int cfa_offset, int ip, int nregs, Loc *locations, guint8 *reg_saved)
458 {
459         int i;
460
461         printf ("\t%x: cfa=r%d+%d ", ip, cfa_reg, cfa_offset);
462
463         for (i = 0; i < nregs; ++i)
464                 if (reg_saved [i] && locations [i].loc_type == LOC_OFFSET)
465                         printf ("r%d@%d(cfa) ", i, locations [i].offset);
466         printf ("\n");
467 }
468
469 typedef struct {
470         Loc locations [NUM_REGS];
471         guint8 reg_saved [NUM_REGS];
472         int cfa_reg, cfa_offset;
473 } UnwindState;
474
475 /*
476  * Given the state of the current frame as stored in REGS, execute the unwind 
477  * operations in unwind_info until the location counter reaches POS. The result is 
478  * stored back into REGS. OUT_CFA will receive the value of the CFA.
479  * If SAVE_LOCATIONS is non-NULL, it should point to an array of size SAVE_LOCATIONS_LEN.
480  * On return, the nth entry will point to the address of the stack slot where register
481  * N was saved, or NULL, if it was not saved by this frame.
482  * MARK_LOCATIONS should contain the locations marked by mono_emit_unwind_op_mark_loc (), if any.
483  * This function is signal safe.
484  */
485 void
486 mono_unwind_frame (guint8 *unwind_info, guint32 unwind_info_len, 
487                                    guint8 *start_ip, guint8 *end_ip, guint8 *ip, guint8 **mark_locations,
488                                    mgreg_t *regs, int nregs,
489                                    mgreg_t **save_locations, int save_locations_len,
490                                    guint8 **out_cfa)
491 {
492         Loc locations [NUM_REGS];
493         guint8 reg_saved [NUM_REGS];
494         int i, pos, reg, cfa_reg = -1, cfa_offset = 0, offset;
495         guint8 *p;
496         guint8 *cfa_val;
497         UnwindState state_stack [1];
498         int state_stack_pos;
499
500         memset (reg_saved, 0, sizeof (reg_saved));
501         state_stack [0].cfa_reg = -1;
502         state_stack [0].cfa_offset = 0;
503
504         p = unwind_info;
505         pos = 0;
506         cfa_reg = -1;
507         cfa_offset = -1;
508         state_stack_pos = 0;
509         while (pos <= ip - start_ip && p < unwind_info + unwind_info_len) {
510                 int op = *p & 0xc0;
511
512                 switch (op) {
513                 case DW_CFA_advance_loc:
514                         UNW_DEBUG (print_dwarf_state (cfa_reg, cfa_offset, pos, nregs, locations));
515                         pos += *p & 0x3f;
516                         p ++;
517                         break;
518                 case DW_CFA_offset:
519                         reg = *p & 0x3f;
520                         p ++;
521                         reg_saved [reg] = TRUE;
522                         locations [reg].loc_type = LOC_OFFSET;
523                         locations [reg].offset = decode_uleb128 (p, &p) * DWARF_DATA_ALIGN;
524                         break;
525                 case 0: {
526                         int ext_op = *p;
527                         p ++;
528                         switch (ext_op) {
529                         case DW_CFA_def_cfa:
530                                 cfa_reg = decode_uleb128 (p, &p);
531                                 cfa_offset = decode_uleb128 (p, &p);
532                                 break;
533                         case DW_CFA_def_cfa_offset:
534                                 cfa_offset = decode_uleb128 (p, &p);
535                                 break;
536                         case DW_CFA_def_cfa_register:
537                                 cfa_reg = decode_uleb128 (p, &p);
538                                 break;
539                         case DW_CFA_offset_extended_sf:
540                                 reg = decode_uleb128 (p, &p);
541                                 offset = decode_sleb128 (p, &p);
542                                 g_assert (reg < NUM_REGS);
543                                 reg_saved [reg] = TRUE;
544                                 locations [reg].loc_type = LOC_OFFSET;
545                                 locations [reg].offset = offset * DWARF_DATA_ALIGN;
546                                 break;
547                         case DW_CFA_offset_extended:
548                                 reg = decode_uleb128 (p, &p);
549                                 offset = decode_uleb128 (p, &p);
550                                 g_assert (reg < NUM_REGS);
551                                 reg_saved [reg] = TRUE;
552                                 locations [reg].loc_type = LOC_OFFSET;
553                                 locations [reg].offset = offset * DWARF_DATA_ALIGN;
554                                 break;
555                         case DW_CFA_same_value:
556                                 reg = decode_uleb128 (p, &p);
557                                 locations [reg].loc_type = LOC_SAME;
558                                 break;
559                         case DW_CFA_advance_loc1:
560                                 pos += *p;
561                                 p += 1;
562                                 break;
563                         case DW_CFA_advance_loc2:
564                                 pos += read16 (p);
565                                 p += 2;
566                                 break;
567                         case DW_CFA_advance_loc4:
568                                 pos += read32 (p);
569                                 p += 4;
570                                 break;
571                         case DW_CFA_remember_state:
572                                 g_assert (state_stack_pos == 0);
573                                 memcpy (&state_stack [0].locations, &locations, sizeof (locations));
574                                 memcpy (&state_stack [0].reg_saved, &reg_saved, sizeof (reg_saved));
575                                 state_stack [0].cfa_reg = cfa_reg;
576                                 state_stack [0].cfa_offset = cfa_offset;
577                                 state_stack_pos ++;
578                                 break;
579                         case DW_CFA_restore_state:
580                                 g_assert (state_stack_pos == 1);
581                                 state_stack_pos --;
582                                 memcpy (&locations, &state_stack [0].locations, sizeof (locations));
583                                 memcpy (&reg_saved, &state_stack [0].reg_saved, sizeof (reg_saved));
584                                 cfa_reg = state_stack [0].cfa_reg;
585                                 cfa_offset = state_stack [0].cfa_offset;
586                                 break;
587                         case DW_CFA_mono_advance_loc:
588                                 g_assert (mark_locations [0]);
589                                 pos = mark_locations [0] - start_ip;
590                                 break;
591                         default:
592                                 g_assert_not_reached ();
593                         }
594                         break;
595                 }
596                 default:
597                         g_assert_not_reached ();
598                 }
599         }
600
601         if (save_locations)
602                 memset (save_locations, 0, save_locations_len * sizeof (mgreg_t*));
603
604         g_assert (cfa_reg != -1);
605         cfa_val = (guint8*)regs [mono_dwarf_reg_to_hw_reg (cfa_reg)] + cfa_offset;
606         for (i = 0; i < NUM_REGS; ++i) {
607                 if (reg_saved [i] && locations [i].loc_type == LOC_OFFSET) {
608                         int hreg = mono_dwarf_reg_to_hw_reg (i);
609                         g_assert (hreg < nregs);
610                         regs [hreg] = *(mgreg_t*)(cfa_val + locations [i].offset);
611                         if (save_locations && hreg < save_locations_len)
612                                 save_locations [hreg] = (mgreg_t*)(cfa_val + locations [i].offset);
613                 }
614         }
615
616         *out_cfa = cfa_val;
617 }
618
619 void
620 mono_unwind_init (void)
621 {
622         mono_mutex_init_recursive (&unwind_mutex);
623
624         mono_counters_register ("Unwind info size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &unwind_info_size);
625 }
626
627 void
628 mono_unwind_cleanup (void)
629 {
630         int i;
631
632         mono_mutex_destroy (&unwind_mutex);
633
634         if (!cached_info)
635                 return;
636
637         for (i = 0; i < cached_info_next; ++i) {
638                 MonoUnwindInfo *cached = cached_info [i];
639
640                 g_free (cached);
641         }
642
643         g_free (cached_info);
644 }
645
646 /*
647  * mono_cache_unwind_info
648  *
649  *   Save UNWIND_INFO in the unwind info cache and return an id which can be passed
650  * to mono_get_cached_unwind_info to get a cached copy of the info.
651  * A copy is made of the unwind info.
652  * This function is useful for two reasons:
653  * - many methods have the same unwind info
654  * - MonoJitInfo->unwind_info is an int so it can't store the pointer to the unwind info
655  */
656 guint32
657 mono_cache_unwind_info (guint8 *unwind_info, guint32 unwind_info_len)
658 {
659         int i;
660         MonoUnwindInfo *info;
661
662         unwind_lock ();
663
664         if (cached_info == NULL) {
665                 cached_info_size = 16;
666                 cached_info = g_new0 (MonoUnwindInfo*, cached_info_size);
667         }
668
669         for (i = 0; i < cached_info_next; ++i) {
670                 MonoUnwindInfo *cached = cached_info [i];
671
672                 if (cached->len == unwind_info_len && memcmp (cached->info, unwind_info, unwind_info_len) == 0) {
673                         unwind_unlock ();
674                         return i;
675                 }
676         }
677
678         info = g_malloc (sizeof (MonoUnwindInfo) + unwind_info_len);
679         info->len = unwind_info_len;
680         memcpy (&info->info, unwind_info, unwind_info_len);
681
682         i = cached_info_next;
683         
684         if (cached_info_next >= cached_info_size) {
685                 MonoUnwindInfo **new_table;
686
687                 /*
688                  * Avoid freeing the old table so mono_get_cached_unwind_info ()
689                  * doesn't need locks/hazard pointers.
690                  */
691
692                 new_table = g_new0 (MonoUnwindInfo*, cached_info_size * 2);
693
694                 memcpy (new_table, cached_info, cached_info_size * sizeof (MonoUnwindInfo*));
695
696                 mono_memory_barrier ();
697
698                 cached_info = new_table;
699
700                 cached_info_list = g_slist_prepend (cached_info_list, cached_info);
701
702                 cached_info_size *= 2;
703         }
704
705         cached_info [cached_info_next ++] = info;
706
707         unwind_info_size += sizeof (MonoUnwindInfo) + unwind_info_len;
708
709         unwind_unlock ();
710         return i;
711 }
712
713 /*
714  * This function is signal safe.
715  */
716 guint8*
717 mono_get_cached_unwind_info (guint32 index, guint32 *unwind_info_len)
718 {
719         MonoUnwindInfo **table;
720         MonoUnwindInfo *info;
721         guint8 *data;
722
723         /*
724          * This doesn't need any locks/hazard pointers,
725          * since new tables are copies of the old ones.
726          */
727         table = cached_info;
728
729         info = table [index];
730
731         *unwind_info_len = info->len;
732         data = info->info;
733
734         return data;
735 }
736
737 /*
738  * mono_unwind_get_dwarf_data_align:
739  *
740  *   Return the data alignment used by the encoded unwind information.
741  */
742 int
743 mono_unwind_get_dwarf_data_align (void)
744 {
745         return DWARF_DATA_ALIGN;
746 }
747
748 /*
749  * mono_unwind_get_dwarf_pc_reg:
750  *
751  *   Return the dwarf register number of the register holding the ip of the
752  * previous frame.
753  */
754 int
755 mono_unwind_get_dwarf_pc_reg (void)
756 {
757         return DWARF_PC_REG;
758 }
759
760 static void
761 decode_cie_op (guint8 *p, guint8 **endp)
762 {
763         int op = *p & 0xc0;
764
765         switch (op) {
766         case DW_CFA_advance_loc:
767                 p ++;
768                 break;
769         case DW_CFA_offset:
770                 p ++;
771                 decode_uleb128 (p, &p);
772                 break;
773         case 0: {
774                 int ext_op = *p;
775                 p ++;
776                 switch (ext_op) {
777                 case DW_CFA_def_cfa:
778                         decode_uleb128 (p, &p);
779                         decode_uleb128 (p, &p);
780                         break;
781                 case DW_CFA_def_cfa_offset:
782                         decode_uleb128 (p, &p);
783                         break;
784                 case DW_CFA_def_cfa_register:
785                         decode_uleb128 (p, &p);
786                         break;
787                 case DW_CFA_advance_loc4:
788                         p += 4;
789                         break;
790                 case DW_CFA_offset_extended_sf:
791                         decode_uleb128 (p, &p);
792                         decode_uleb128 (p, &p);
793                         break;
794                 default:
795                         g_assert_not_reached ();
796                 }
797                 break;
798         }
799         default:
800                 g_assert_not_reached ();
801         }
802
803         *endp = p;
804 }
805
806 static gint64
807 read_encoded_val (guint32 encoding, guint8 *p, guint8 **endp)
808 {
809         gint64 res;
810
811         switch (encoding & 0xf) {
812         case DW_EH_PE_sdata8:
813                 res = *(gint64*)p;
814                 p += 8;
815                 break;
816         case DW_EH_PE_sdata4:
817                 res = *(gint32*)p;
818                 p += 4;
819                 break;
820         default:
821                 g_assert_not_reached ();
822         }
823
824         *endp = p;
825         return res;
826 }
827
828 /*
829  * decode_lsda:
830  *
831  *   Decode the Mono specific Language Specific Data Area generated by LLVM.
832  */
833 static void
834 decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo **ex_info, guint32 *ex_info_len, gpointer **type_info, int *this_reg, int *this_offset)
835 {
836         guint8 *p;
837         int i, ncall_sites, this_encoding;
838         guint32 mono_magic, version;
839
840         p = lsda;
841
842         /* This is the modified LSDA generated by the LLVM mono branch */
843         mono_magic = decode_uleb128 (p, &p);
844         g_assert (mono_magic == 0x4d4fef4f);
845         version = decode_uleb128 (p, &p);
846         g_assert (version == 1);
847         this_encoding = *p;
848         p ++;
849         if (this_encoding == DW_EH_PE_udata4) {
850                 gint32 op, reg, offset;
851
852                 /* 'this' location */
853                 op = *p;
854                 g_assert (op == DW_OP_bregx);
855                 p ++;
856                 reg = decode_uleb128 (p, &p);
857                 offset = decode_sleb128 (p, &p);
858
859                 *this_reg = mono_dwarf_reg_to_hw_reg (reg);
860                 *this_offset = offset;
861         } else {
862                 g_assert (this_encoding == DW_EH_PE_omit);
863
864                 *this_reg = -1;
865                 *this_offset = -1;
866         }
867         ncall_sites = decode_uleb128 (p, &p);
868         p = (guint8*)ALIGN_TO ((mgreg_t)p, 4);
869
870         if (ex_info) {
871                 *ex_info = g_malloc0 (ncall_sites * sizeof (MonoJitExceptionInfo));
872                 *ex_info_len = ncall_sites;
873         }
874         if (type_info)
875                 *type_info = g_malloc0 (ncall_sites * sizeof (gpointer));
876
877         for (i = 0; i < ncall_sites; ++i) {
878                 int block_start_offset, block_size, landing_pad;
879                 guint8 *tinfo;
880
881                 block_start_offset = read32 (p);
882                 p += sizeof (gint32);
883                 block_size = read32 (p);
884                 p += sizeof (gint32);
885                 landing_pad = read32 (p);
886                 p += sizeof (gint32);
887                 tinfo = p;
888                 p += sizeof (gint32);
889
890                 g_assert (landing_pad);
891                 g_assert (((size_t)tinfo % 4) == 0);
892                 //printf ("X: %p %d\n", landing_pad, *(int*)tinfo);
893
894                 if (ex_info) {
895                         if (*type_info)
896                                 (*type_info) [i] = tinfo;
897                         (*ex_info)[i].try_start = code + block_start_offset;
898                         (*ex_info)[i].try_end = code + block_start_offset + block_size;
899                         (*ex_info)[i].handler_start = code + landing_pad;
900                 }
901         }
902 }
903
904 /*
905  * mono_unwind_decode_fde:
906  *
907  *   Decode a DWARF FDE entry, returning the unwind opcodes.
908  * If not NULL, EX_INFO is set to a malloc-ed array of MonoJitExceptionInfo structures,
909  * only try_start, try_end and handler_start is set.
910  * If not NULL, TYPE_INFO is set to a malloc-ed array containing the ttype table from the
911  * LSDA.
912  */
913 guint8*
914 mono_unwind_decode_fde (guint8 *fde, guint32 *out_len, guint32 *code_len, MonoJitExceptionInfo **ex_info, guint32 *ex_info_len, gpointer **type_info, int *this_reg, int *this_offset)
915 {
916         guint8 *p, *cie, *fde_current, *fde_aug = NULL, *code, *fde_cfi, *cie_cfi;
917         gint32 fde_len, cie_offset, pc_begin, pc_range, aug_len;
918         gint32 cie_len, cie_id, cie_version, code_align, data_align, return_reg;
919         gint32 i, cie_aug_len, buf_len;
920         char *cie_aug_str;
921         guint8 *buf;
922         gboolean has_fde_augmentation = FALSE;
923
924         /* 
925          * http://refspecs.freestandards.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
926          */
927
928         /* This is generated by JITDwarfEmitter::EmitEHFrame () */
929
930         *type_info = NULL;
931         *this_reg = -1;
932         *this_offset = -1;
933
934         /* Decode FDE */
935
936         p = fde;
937         // FIXME: Endianess ?
938         fde_len = *(guint32*)p;
939         g_assert (fde_len != 0xffffffff && fde_len != 0);
940         p += 4;
941         cie_offset = *(guint32*)p;
942         cie = p - cie_offset;
943         p += 4;
944         fde_current = p;
945
946         /* Decode CIE */
947         p = cie;
948         cie_len = *(guint32*)p;
949         p += 4;
950         cie_id = *(guint32*)p;
951         g_assert (cie_id == 0);
952         p += 4;
953         cie_version = *p;
954         g_assert (cie_version == 1);
955         p += 1;
956         cie_aug_str = (char*)p;
957         p += strlen (cie_aug_str) + 1;
958         code_align = decode_uleb128 (p, &p);
959         data_align = decode_sleb128 (p, &p);
960         return_reg = decode_uleb128 (p, &p);
961         if (strstr (cie_aug_str, "z")) {
962                 guint8 *cie_aug;
963                 guint32 p_encoding;
964
965                 cie_aug_len = decode_uleb128 (p, &p);
966
967                 has_fde_augmentation = TRUE;
968
969                 cie_aug = p;
970                 for (i = 0; cie_aug_str [i] != '\0'; ++i) {
971                         switch (cie_aug_str [i]) {
972                         case 'z':
973                                 break;
974                         case 'P':
975                                 p_encoding = *p;
976                                 p ++;
977                                 read_encoded_val (p_encoding, p, &p);
978                                 break;
979                         case 'L':
980                                 g_assert ((*p == (DW_EH_PE_sdata4|DW_EH_PE_pcrel)) || (*p == (DW_EH_PE_sdata8|DW_EH_PE_pcrel)));
981                                 p ++;
982                                 break;
983                         case 'R':
984                                 g_assert (*p == (DW_EH_PE_sdata4|DW_EH_PE_pcrel));
985                                 p ++;
986                                 break;
987                         default:
988                                 g_assert_not_reached ();
989                                 break;
990                         }
991                 }
992                         
993                 p = cie_aug;
994                 p += cie_aug_len;
995         }
996         cie_cfi = p;
997
998         /* Continue decoding FDE */
999         p = fde_current;
1000         /* DW_EH_PE_sdata4|DW_EH_PE_pcrel encoding */
1001         pc_begin = *(gint32*)p;
1002         code = p + pc_begin;
1003         p += 4;
1004         pc_range = *(guint32*)p;
1005         p += 4;
1006         if (has_fde_augmentation) {
1007                 aug_len = decode_uleb128 (p, &p);
1008                 fde_aug = p;
1009                 p += aug_len;
1010         } else {
1011                 aug_len = 0;
1012         }
1013         fde_cfi = p;
1014
1015         if (code_len)
1016                 *code_len = pc_range;
1017
1018         if (ex_info) {
1019                 *ex_info = NULL;
1020                 *ex_info_len = 0;
1021         }
1022
1023         /* Decode FDE augmention */
1024         if (aug_len) {
1025                 gint32 lsda_offset;
1026                 guint8 *lsda;
1027
1028                 /* sdata|pcrel encoding */
1029                 if (aug_len == 4)
1030                         lsda_offset = read32 (fde_aug);
1031                 else if (aug_len == 8)
1032                         lsda_offset = *(gint64*)fde_aug;
1033                 else
1034                         g_assert_not_reached ();
1035                 if (lsda_offset != 0) {
1036                         lsda = fde_aug + lsda_offset;
1037
1038                         decode_lsda (lsda, code, ex_info, ex_info_len, type_info, this_reg, this_offset);
1039                 }
1040         }
1041
1042         /* Make sure the FDE uses the same constants as we do */
1043         g_assert (code_align == 1);
1044         g_assert (data_align == DWARF_DATA_ALIGN);
1045         g_assert (return_reg == DWARF_PC_REG);
1046
1047         buf_len = (cie + cie_len + 4 - cie_cfi) + (fde + fde_len + 4 - fde_cfi);
1048         buf = g_malloc0 (buf_len);
1049
1050         i = 0;
1051         p = cie_cfi;
1052         while (p < cie + cie_len + 4) {
1053                 if (*p == DW_CFA_nop)
1054                         break;
1055                 else
1056                         decode_cie_op (p, &p);
1057         }
1058         memcpy (buf + i, cie_cfi, p - cie_cfi);
1059         i += p - cie_cfi;
1060
1061         p = fde_cfi;
1062         while (p < fde + fde_len + 4) {
1063                 if (*p == DW_CFA_nop)
1064                         break;
1065                 else
1066                         decode_cie_op (p, &p);
1067         }
1068         memcpy (buf + i, fde_cfi, p - fde_cfi);
1069         i += p - fde_cfi;
1070         g_assert (i <= buf_len);
1071
1072         *out_len = i;
1073
1074         return g_realloc (buf, i);
1075 }
1076
1077 /*
1078  * mono_unwind_decode_mono_fde:
1079  *
1080  *   Decode an FDE entry in the LLVM emitted mono EH frame.
1081  * info->ex_info is set to a malloc-ed array of MonoJitExceptionInfo structures,
1082  * only try_start, try_end and handler_start is set.
1083  * info->type_info is set to a malloc-ed array containing the ttype table from the
1084  * LSDA.
1085  */
1086 void
1087 mono_unwind_decode_llvm_mono_fde (guint8 *fde, int fde_len, guint8 *cie, guint8 *code, MonoLLVMFDEInfo *res)
1088 {
1089         guint8 *p, *fde_aug, *cie_cfi, *fde_cfi, *buf;
1090         int has_aug, aug_len, cie_cfi_len, fde_cfi_len;
1091         gint32 code_align, data_align, return_reg, pers_encoding;
1092
1093         memset (res, 0, sizeof (*res));
1094         res->this_reg = -1;
1095         res->this_offset = -1;
1096
1097         /* fde points to data emitted by LLVM in DwarfMonoException::EmitMonoEHFrame () */
1098         p = fde;
1099         has_aug = *p;
1100         p ++;
1101         if (has_aug) {
1102                 aug_len = read32 (p);
1103                 p += 4;
1104         } else {
1105                 aug_len = 0;
1106         }
1107         fde_aug = p;
1108         p += aug_len;
1109         fde_cfi = p;
1110
1111         if (has_aug) {
1112                 guint8 *lsda;
1113
1114                 /* The LSDA is embedded directly into the FDE */
1115                 lsda = fde_aug;
1116
1117                 decode_lsda (lsda, code, &res->ex_info, &res->ex_info_len, &res->type_info, &res->this_reg, &res->this_offset);
1118         }
1119
1120         /* Decode CIE */
1121         p = cie;
1122         code_align = decode_uleb128 (p, &p);
1123         data_align = decode_sleb128 (p, &p);
1124         return_reg = decode_uleb128 (p, &p);
1125         pers_encoding = *p;
1126         p ++;
1127         if (pers_encoding != DW_EH_PE_omit)
1128                 read_encoded_val (pers_encoding, p, &p);
1129
1130         cie_cfi = p;
1131
1132         /* Make sure the FDE uses the same constants as we do */
1133         g_assert (code_align == 1);
1134         g_assert (data_align == DWARF_DATA_ALIGN);
1135         g_assert (return_reg == DWARF_PC_REG);
1136
1137         /* Compute size of CIE unwind info it is DW_CFA_nop terminated */
1138         p = cie_cfi;
1139         while (TRUE) {
1140                 if (*p == DW_CFA_nop)
1141                         break;
1142                 else
1143                         decode_cie_op (p, &p);
1144         }
1145         cie_cfi_len = p - cie_cfi;
1146         fde_cfi_len = (fde + fde_len - fde_cfi);
1147
1148         buf = g_malloc0 (cie_cfi_len + fde_cfi_len);
1149         memcpy (buf, cie_cfi, cie_cfi_len);
1150         memcpy (buf + cie_cfi_len, fde_cfi, fde_cfi_len);
1151
1152         res->unw_info_len = cie_cfi_len + fde_cfi_len;
1153         res->unw_info = buf;
1154 }
1155
1156 /*
1157  * mono_unwind_get_cie_program:
1158  *
1159  *   Get the unwind bytecode for the DWARF CIE.
1160  */
1161 GSList*
1162 mono_unwind_get_cie_program (void)
1163 {
1164 #if defined(TARGET_AMD64) || defined(TARGET_X86) || defined(TARGET_POWERPC)
1165         return mono_arch_get_cie_program ();
1166 #else
1167         return NULL;
1168 #endif
1169 }