[interp] Make newarr lockfree
[mono-project.git] / mono / mini / unwind.c
blobc9b5c0a349fc1219f95a4414616e4f6adf85cc35
1 /**
2 * \file
3 * Stack Unwinding Interface
5 * Authors:
6 * Zoltan Varga (vargaz@gmail.com)
8 * (C) 2008 Novell, Inc.
9 */
11 #include "mini.h"
12 #include "mini-unwind.h"
14 #include <mono/utils/mono-counters.h>
15 #include <mono/utils/freebsd-dwarf.h>
16 #include <mono/utils/hazard-pointer.h>
17 #include <mono/utils/mono-logger-internals.h>
18 #include <mono/metadata/threads-types.h>
19 #include <mono/metadata/mono-endian.h>
21 typedef enum {
22 LOC_SAME,
23 LOC_OFFSET
24 } LocType;
26 typedef struct {
27 LocType loc_type;
28 int offset;
29 } Loc;
31 typedef struct {
32 guint32 len;
33 guint8 info [MONO_ZERO_LEN_ARRAY];
34 } MonoUnwindInfo;
36 static mono_mutex_t unwind_mutex;
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;
44 #define unwind_lock() mono_os_mutex_lock (&unwind_mutex)
45 #define unwind_unlock() mono_os_mutex_unlock (&unwind_mutex)
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_DWARF_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 (dwarf regs 264..271) */
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_DWARF_REGS 272
57 #define DWARF_DATA_ALIGN (-4)
58 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (ARMREG_LR))
59 #define IS_DOUBLE_REG(dwarf_reg) (((dwarf_reg) >= 264) && ((dwarf_reg) <= 271))
60 #elif defined(TARGET_ARM64)
61 #define NUM_DWARF_REGS 96
62 #define DWARF_DATA_ALIGN (-8)
63 /* LR */
64 #define DWARF_PC_REG 30
65 static int map_hw_reg_to_dwarf_reg [] = {
66 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
67 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
68 /* v8..v15 */
69 72, 73, 74, 75, 76, 77, 78, 79,
71 #elif defined (TARGET_X86)
73 * ebp and esp are swapped:
74 * http://lists.cs.uiuc.edu/pipermail/lldb-dev/2014-January/003101.html
76 static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 5, 4, 6, 7, 8 };
77 /* + 1 is for IP */
78 #define NUM_DWARF_REGS (X86_NREG + 1)
79 #define DWARF_DATA_ALIGN (-4)
80 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (X86_NREG))
81 #elif defined (TARGET_POWERPC)
82 // http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html
83 static int map_hw_reg_to_dwarf_reg [ppc_lr + 1] = { 0, 1, 2, 3, 4, 5, 6, 7, 8,
84 9, 10, 11, 12, 13, 14, 15, 16,
85 17, 18, 19, 20, 21, 22, 23, 24,
86 25, 26, 27, 28, 29, 30, 31 };
87 #define DWARF_DATA_ALIGN (-(gint32)sizeof (target_mgreg_t))
88 #if _CALL_ELF == 2
89 #define DWARF_PC_REG 65
90 #else
91 #define DWARF_PC_REG 108
92 #endif
93 #define NUM_DWARF_REGS (DWARF_PC_REG + 1)
94 #elif defined (TARGET_S390X)
96 * 0-15 = GR0-15
97 * 16-31 = FP0-15
99 static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 4, 5, 6, 7,
100 8, 9, 10, 11, 12, 13, 14, 15,
101 16, 17, 18, 19, 20, 21, 22, 23,
102 24, 25, 26, 27, 28, 29, 30, 31};
103 #define NUM_DWARF_REGS 32
104 #define DWARF_DATA_ALIGN (-8)
105 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (14))
106 #elif defined (TARGET_MIPS)
107 /* FIXME: */
108 static int map_hw_reg_to_dwarf_reg [32] = {
109 0, 1, 2, 3, 4, 5, 6, 7,
110 8, 9, 10, 11, 12, 13, 14, 15,
111 16, 17, 18, 19, 20, 21, 22, 23,
112 24, 25, 26, 27, 28, 29, 30, 31
114 #define NUM_DWARF_REGS 32
115 #define DWARF_DATA_ALIGN (-(gint32)sizeof (target_mgreg_t))
116 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (mips_ra))
117 #elif defined(TARGET_RISCV)
120 * These values have not currently been formalized in the RISC-V psABI. See
121 * instead gcc/config/riscv/riscv.h in the GCC source tree.
124 #define NUM_DWARF_REGS (RISCV_N_GREGS + RISCV_N_FREGS)
125 #define DWARF_DATA_ALIGN (-4)
126 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (RISCV_RA))
128 static int map_hw_reg_to_dwarf_reg [NUM_DWARF_REGS] = {
129 // x0..x31
130 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
131 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
132 // f0..f31
133 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
134 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
137 #else
138 static int map_hw_reg_to_dwarf_reg [16];
139 #define NUM_DWARF_REGS 16
140 #define DWARF_DATA_ALIGN 1
141 #define DWARF_PC_REG -1
142 #endif
144 #define NUM_HW_REGS (sizeof (map_hw_reg_to_dwarf_reg) / sizeof (int))
146 #ifndef IS_DOUBLE_REG
147 #define IS_DOUBLE_REG(dwarf_reg) (dwarf_reg ? 0 : 0)
148 #endif
150 static gboolean dwarf_reg_to_hw_reg_inited;
151 static gboolean hw_reg_to_dwarf_reg_inited;
153 static int map_dwarf_reg_to_hw_reg [NUM_DWARF_REGS];
155 static void
156 init_hw_reg_map (void)
158 #ifdef TARGET_POWERPC
159 map_hw_reg_to_dwarf_reg [ppc_lr] = DWARF_PC_REG;
160 #endif
161 mono_memory_barrier ();
162 hw_reg_to_dwarf_reg_inited = TRUE;
166 * mono_hw_reg_to_dwarf_reg:
168 * Map the hardware register number REG to the register number used by DWARF.
171 mono_hw_reg_to_dwarf_reg (int reg)
173 if (!hw_reg_to_dwarf_reg_inited)
174 init_hw_reg_map ();
176 if (NUM_HW_REGS == 0) {
177 g_assert_not_reached ();
178 return -1;
179 } else {
180 return map_hw_reg_to_dwarf_reg [reg];
184 static void
185 init_dwarf_reg_map (void)
187 int i;
189 g_assert (NUM_HW_REGS > 0);
190 for (i = 0; i < NUM_HW_REGS; ++i) {
191 map_dwarf_reg_to_hw_reg [mono_hw_reg_to_dwarf_reg (i)] = i;
194 mono_memory_barrier ();
195 dwarf_reg_to_hw_reg_inited = TRUE;
199 mono_dwarf_reg_to_hw_reg (int reg)
201 if (!dwarf_reg_to_hw_reg_inited)
202 init_dwarf_reg_map ();
204 return map_dwarf_reg_to_hw_reg [reg];
207 static G_GNUC_UNUSED void
208 encode_uleb128 (guint32 value, guint8 *buf, guint8 **endbuf)
210 guint8 *p = buf;
212 do {
213 guint8 b = value & 0x7f;
214 value >>= 7;
215 if (value != 0) /* more bytes to come */
216 b |= 0x80;
217 *p ++ = b;
218 } while (value);
220 *endbuf = p;
223 static G_GNUC_UNUSED void
224 encode_sleb128 (gint32 value, guint8 *buf, guint8 **endbuf)
226 gboolean more = 1;
227 gboolean negative = (value < 0);
228 guint32 size = 32;
229 guint8 byte;
230 guint8 *p = buf;
232 while (more) {
233 byte = value & 0x7f;
234 value >>= 7;
235 /* the following is unnecessary if the
236 * implementation of >>= uses an arithmetic rather
237 * than logical shift for a signed left operand
239 if (negative)
240 /* sign extend */
241 value |= - (1 <<(size - 7));
242 /* sign bit of byte is second high order bit (0x40) */
243 if ((value == 0 && !(byte & 0x40)) ||
244 (value == -1 && (byte & 0x40)))
245 more = 0;
246 else
247 byte |= 0x80;
248 *p ++= byte;
251 *endbuf = p;
254 static inline guint32
255 decode_uleb128 (guint8 *buf, guint8 **endbuf)
257 guint8 *p = buf;
258 guint32 res = 0;
259 int shift = 0;
261 while (TRUE) {
262 guint8 b = *p;
263 p ++;
265 res = res | (((int)(b & 0x7f)) << shift);
266 if (!(b & 0x80))
267 break;
268 shift += 7;
271 *endbuf = p;
273 return res;
276 static inline gint32
277 decode_sleb128 (guint8 *buf, guint8 **endbuf)
279 guint8 *p = buf;
280 gint32 res = 0;
281 int shift = 0;
283 while (TRUE) {
284 guint8 b = *p;
285 p ++;
287 res = res | (((int)(b & 0x7f)) << shift);
288 shift += 7;
289 if (!(b & 0x80)) {
290 if (shift < 32 && (b & 0x40))
291 res |= - (1 << shift);
292 break;
296 *endbuf = p;
298 return res;
301 void
302 mono_print_unwind_info (guint8 *unwind_info, int unwind_info_len)
304 guint8 *p;
305 int pos, reg, offset, cfa_reg, cfa_offset;
307 p = unwind_info;
308 pos = 0;
309 while (p < unwind_info + unwind_info_len) {
310 int op = *p & 0xc0;
312 switch (op) {
313 case DW_CFA_advance_loc:
314 pos += *p & 0x3f;
315 p ++;
316 break;
317 case DW_CFA_offset:
318 reg = *p & 0x3f;
319 p ++;
320 offset = decode_uleb128 (p, &p) * DWARF_DATA_ALIGN;
321 if (reg == DWARF_PC_REG)
322 printf ("CFA: [%x] offset: %s at cfa-0x%x\n", pos, "pc", -offset);
323 else
324 printf ("CFA: [%x] offset: %s at cfa-0x%x\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (reg)), -offset);
325 break;
326 case 0: {
327 int ext_op = *p;
328 p ++;
329 switch (ext_op) {
330 case DW_CFA_def_cfa:
331 cfa_reg = decode_uleb128 (p, &p);
332 cfa_offset = decode_uleb128 (p, &p);
333 printf ("CFA: [%x] def_cfa: %s+0x%x\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (cfa_reg)), cfa_offset);
334 break;
335 case DW_CFA_def_cfa_offset:
336 cfa_offset = decode_uleb128 (p, &p);
337 printf ("CFA: [%x] def_cfa_offset: 0x%x\n", pos, cfa_offset);
338 break;
339 case DW_CFA_def_cfa_register:
340 cfa_reg = decode_uleb128 (p, &p);
341 printf ("CFA: [%x] def_cfa_reg: %s\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (cfa_reg)));
342 break;
343 case DW_CFA_offset_extended_sf:
344 reg = decode_uleb128 (p, &p);
345 offset = decode_sleb128 (p, &p) * DWARF_DATA_ALIGN;
346 printf ("CFA: [%x] offset_extended_sf: %s at cfa-0x%x\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (reg)), -offset);
347 break;
348 case DW_CFA_same_value:
349 reg = decode_uleb128 (p, &p);
350 printf ("CFA: [%x] same_value: %s\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (reg)));
351 break;
352 case DW_CFA_remember_state:
353 printf ("CFA: [%x] remember_state\n", pos);
354 break;
355 case DW_CFA_restore_state:
356 printf ("CFA: [%x] restore_state\n", pos);
357 break;
358 case DW_CFA_mono_advance_loc:
359 printf ("CFA: [%x] mono_advance_loc\n", pos);
360 break;
361 case DW_CFA_advance_loc1:
362 printf ("CFA: [%x] advance_loc1\n", pos);
363 pos += *p;
364 p += 1;
365 break;
366 case DW_CFA_advance_loc2:
367 printf ("CFA: [%x] advance_loc2\n", pos);
368 pos += read16 (p);
369 p += 2;
370 break;
371 case DW_CFA_advance_loc4:
372 printf ("CFA: [%x] advance_loc4\n", pos);
373 pos += read32 (p);
374 p += 4;
375 break;
376 default:
377 g_assert_not_reached ();
379 break;
381 default:
382 g_assert_not_reached ();
388 * mono_unwind_ops_encode_full:
390 * Encode the unwind ops in UNWIND_OPS into the compact DWARF encoding.
391 * Return a pointer to malloc'ed memory.
392 * If ENABLE_EXTENSIONS is FALSE, avoid encoding the mono extension
393 * opcode (DW_CFA_mono_advance_loc).
395 guint8*
396 mono_unwind_ops_encode_full (GSList *unwind_ops, guint32 *out_len, gboolean enable_extensions)
398 GSList *l;
399 MonoUnwindOp *op;
400 int loc;
401 guint8 buf [4096];
402 guint8 *p, *res;
404 p = buf;
406 loc = 0;
407 l = unwind_ops;
408 for (; l; l = l->next) {
409 int reg;
411 op = (MonoUnwindOp *)l->data;
413 /* Convert the register from the hw encoding to the dwarf encoding */
414 reg = mono_hw_reg_to_dwarf_reg (op->reg);
416 if (op->op == DW_CFA_mono_advance_loc) {
417 /* This advances loc to its location */
418 loc = op->when;
421 /* Emit an advance_loc if neccesary */
422 while (op->when > loc) {
423 if (op->when - loc >= 65536) {
424 *p ++ = DW_CFA_advance_loc4;
425 guint32 v = (guint32)(op->when - loc);
426 memcpy (p, &v, 4);
427 g_assert (read32 (p) == (guint32)(op->when - loc));
428 p += 4;
429 loc = op->when;
430 } else if (op->when - loc >= 256) {
431 *p ++ = DW_CFA_advance_loc2;
432 guint16 v = (guint16)(op->when - loc);
433 memcpy (p, &v, 2);
434 g_assert (read16 (p) == (guint32)(op->when - loc));
435 p += 2;
436 loc = op->when;
437 } else if (op->when - loc >= 32) {
438 *p ++ = DW_CFA_advance_loc1;
439 *(guint8*)p = (guint8)(op->when - loc);
440 p += 1;
441 loc = op->when;
442 } else if (op->when - loc < 32) {
443 *p ++ = DW_CFA_advance_loc | (op->when - loc);
444 loc = op->when;
445 } else {
446 *p ++ = DW_CFA_advance_loc | (30);
447 loc += 30;
451 switch (op->op) {
452 case DW_CFA_def_cfa:
453 *p ++ = op->op;
454 encode_uleb128 (reg, p, &p);
455 encode_uleb128 (op->val, p, &p);
456 break;
457 case DW_CFA_def_cfa_offset:
458 *p ++ = op->op;
459 encode_uleb128 (op->val, p, &p);
460 break;
461 case DW_CFA_def_cfa_register:
462 *p ++ = op->op;
463 encode_uleb128 (reg, p, &p);
464 break;
465 case DW_CFA_same_value:
466 *p ++ = op->op;
467 encode_uleb128 (reg, p, &p);
468 break;
469 case DW_CFA_offset:
470 if (reg > 63) {
471 *p ++ = DW_CFA_offset_extended_sf;
472 encode_uleb128 (reg, p, &p);
473 encode_sleb128 (op->val / DWARF_DATA_ALIGN, p, &p);
474 } else {
475 *p ++ = DW_CFA_offset | reg;
476 encode_uleb128 (op->val / DWARF_DATA_ALIGN, p, &p);
478 break;
479 case DW_CFA_remember_state:
480 case DW_CFA_restore_state:
481 *p ++ = op->op;
482 break;
483 case DW_CFA_mono_advance_loc:
484 if (!enable_extensions)
485 break;
486 /* Only one location is supported */
487 g_assert (op->val == 0);
488 *p ++ = op->op;
489 break;
490 #if defined(TARGET_WIN32) && defined(TARGET_AMD64)
491 case DW_CFA_mono_sp_alloc_info_win64:
492 case DW_CFA_mono_fp_alloc_info_win64:
493 // Drop Windows specific unwind op's. These op's are currently
494 // only used when registering unwind info with Windows OS unwinder.
495 break;
496 #endif
497 default:
498 g_assert_not_reached ();
499 break;
503 g_assert (p - buf < 4096);
504 *out_len = p - buf;
505 res = (guint8 *)g_malloc (p - buf);
506 memcpy (res, buf, p - buf);
507 return res;
510 guint8*
511 mono_unwind_ops_encode (GSList *unwind_ops, guint32 *out_len)
513 return mono_unwind_ops_encode_full (unwind_ops, out_len, TRUE);
516 #if 0
517 #define UNW_DEBUG(stmt) do { stmt; } while (0)
518 #else
519 #define UNW_DEBUG(stmt) do { } while (0)
520 #endif
522 static G_GNUC_UNUSED void
523 print_dwarf_state (int cfa_reg, int cfa_offset, int ip, int nregs, Loc *locations, guint8 *reg_saved)
525 int i;
527 printf ("\t%x: cfa=r%d+%d ", ip, cfa_reg, cfa_offset);
529 for (i = 0; i < nregs; ++i)
530 if (reg_saved [i] && locations [i].loc_type == LOC_OFFSET)
531 printf ("r%d@%d(cfa) ", i, locations [i].offset);
532 printf ("\n");
535 typedef struct {
536 Loc locations [NUM_HW_REGS];
537 guint8 reg_saved [NUM_HW_REGS];
538 int cfa_reg, cfa_offset;
539 } UnwindState;
542 * Given the state of the current frame as stored in REGS, execute the unwind
543 * operations in unwind_info until the location counter reaches POS. The result is
544 * stored back into REGS. OUT_CFA will receive the value of the CFA.
545 * If SAVE_LOCATIONS is non-NULL, it should point to an array of size SAVE_LOCATIONS_LEN.
546 * On return, the nth entry will point to the address of the stack slot where register
547 * N was saved, or NULL, if it was not saved by this frame.
548 * MARK_LOCATIONS should contain the locations marked by mono_emit_unwind_op_mark_loc (), if any.
549 * This function is signal safe.
551 * It returns FALSE on failure
553 gboolean
554 mono_unwind_frame (guint8 *unwind_info, guint32 unwind_info_len,
555 guint8 *start_ip, guint8 *end_ip, guint8 *ip, guint8 **mark_locations,
556 mono_unwind_reg_t *regs, int nregs,
557 host_mgreg_t **save_locations, int save_locations_len,
558 guint8 **out_cfa)
560 Loc locations [NUM_HW_REGS];
561 guint8 reg_saved [NUM_HW_REGS];
562 int pos, reg, hwreg, cfa_reg = -1, cfa_offset = 0, offset;
563 guint8 *p;
564 guint8 *cfa_val;
565 UnwindState state_stack [1];
566 int state_stack_pos;
568 memset (reg_saved, 0, sizeof (reg_saved));
569 state_stack [0].cfa_reg = -1;
570 state_stack [0].cfa_offset = 0;
572 p = unwind_info;
573 pos = 0;
574 cfa_reg = -1;
575 cfa_offset = -1;
576 state_stack_pos = 0;
577 while (pos <= ip - start_ip && p < unwind_info + unwind_info_len) {
578 int op = *p & 0xc0;
580 switch (op) {
581 case DW_CFA_advance_loc:
582 UNW_DEBUG (print_dwarf_state (cfa_reg, cfa_offset, pos, nregs, locations));
583 pos += *p & 0x3f;
584 p ++;
585 break;
586 case DW_CFA_offset:
587 hwreg = mono_dwarf_reg_to_hw_reg (*p & 0x3f);
588 p ++;
589 reg_saved [hwreg] = TRUE;
590 locations [hwreg].loc_type = LOC_OFFSET;
591 locations [hwreg].offset = decode_uleb128 (p, &p) * DWARF_DATA_ALIGN;
592 break;
593 case 0: {
594 int ext_op = *p;
595 p ++;
596 switch (ext_op) {
597 case DW_CFA_def_cfa:
598 cfa_reg = decode_uleb128 (p, &p);
599 cfa_offset = decode_uleb128 (p, &p);
600 break;
601 case DW_CFA_def_cfa_offset:
602 cfa_offset = decode_uleb128 (p, &p);
603 break;
604 case DW_CFA_def_cfa_register:
605 cfa_reg = decode_uleb128 (p, &p);
606 break;
607 case DW_CFA_offset_extended_sf:
608 reg = decode_uleb128 (p, &p);
609 hwreg = mono_dwarf_reg_to_hw_reg (reg);
610 offset = decode_sleb128 (p, &p);
611 if (reg >= NUM_DWARF_REGS) {
612 mono_runtime_printf_err ("Unwind failure. Assertion at %s %d\n.", __FILE__, __LINE__);
613 return FALSE;
615 reg_saved [hwreg] = TRUE;
616 locations [hwreg].loc_type = LOC_OFFSET;
617 locations [hwreg].offset = offset * DWARF_DATA_ALIGN;
618 break;
619 case DW_CFA_offset_extended:
620 reg = decode_uleb128 (p, &p);
621 hwreg = mono_dwarf_reg_to_hw_reg (reg);
622 offset = decode_uleb128 (p, &p);
623 if (reg >= NUM_DWARF_REGS) {
624 mono_runtime_printf_err ("Unwind failure. Assertion at %s %d\n.", __FILE__, __LINE__);
625 return FALSE;
627 reg_saved [hwreg] = TRUE;
628 locations [hwreg].loc_type = LOC_OFFSET;
629 locations [hwreg].offset = offset * DWARF_DATA_ALIGN;
630 break;
631 case DW_CFA_same_value:
632 hwreg = mono_dwarf_reg_to_hw_reg (decode_uleb128 (p, &p));
633 locations [hwreg].loc_type = LOC_SAME;
634 break;
635 case DW_CFA_advance_loc1:
636 pos += *p;
637 p += 1;
638 break;
639 case DW_CFA_advance_loc2:
640 pos += read16 (p);
641 p += 2;
642 break;
643 case DW_CFA_advance_loc4:
644 pos += read32 (p);
645 p += 4;
646 break;
647 case DW_CFA_remember_state:
648 if (state_stack_pos != 0) {
649 mono_runtime_printf_err ("Unwind failure. Assertion at %s %d\n.", __FILE__, __LINE__);
650 return FALSE;
652 memcpy (&state_stack [0].locations, &locations, sizeof (locations));
653 memcpy (&state_stack [0].reg_saved, &reg_saved, sizeof (reg_saved));
654 state_stack [0].cfa_reg = cfa_reg;
655 state_stack [0].cfa_offset = cfa_offset;
656 state_stack_pos ++;
657 break;
658 case DW_CFA_restore_state:
659 if (state_stack_pos != 1) {
660 mono_runtime_printf_err ("Unwind failure. Assertion at %s %d\n.", __FILE__, __LINE__);
661 return FALSE;
663 state_stack_pos --;
664 memcpy (&locations, &state_stack [0].locations, sizeof (locations));
665 memcpy (&reg_saved, &state_stack [0].reg_saved, sizeof (reg_saved));
666 cfa_reg = state_stack [0].cfa_reg;
667 cfa_offset = state_stack [0].cfa_offset;
668 break;
669 case DW_CFA_mono_advance_loc:
670 if (!mark_locations [0]) {
671 mono_runtime_printf_err ("Unwind failure. Assertion at %s %d\n.", __FILE__, __LINE__);
672 return FALSE;
674 pos = mark_locations [0] - start_ip;
675 break;
676 default:
677 mono_runtime_printf_err ("Unwind failure. Illegal value for switch statement, assertion at %s %d\n.", __FILE__, __LINE__);
678 return FALSE;
680 break;
682 default:
683 mono_runtime_printf_err ("Unwind failure. Illegal value for switch statement, assertion at %s %d\n.", __FILE__, __LINE__);
684 return FALSE;
688 if (save_locations)
689 memset (save_locations, 0, save_locations_len * sizeof (host_mgreg_t*));
691 if (cfa_reg == -1) {
692 mono_runtime_printf_err ("Unset cfa_reg in method %s. Memory around ip (%p):", mono_get_method_from_ip (ip), ip);
693 mono_dump_mem (ip - 0x10, 0x40);
694 return FALSE;
696 cfa_val = (guint8*)regs [mono_dwarf_reg_to_hw_reg (cfa_reg)] + cfa_offset;
697 for (hwreg = 0; hwreg < NUM_HW_REGS; ++hwreg) {
698 if (reg_saved [hwreg] && locations [hwreg].loc_type == LOC_OFFSET) {
699 int dwarfreg = mono_hw_reg_to_dwarf_reg (hwreg);
700 if (hwreg >= nregs) {
701 mono_runtime_printf_err ("Unwind failure. Assertion at %s %d\n.", __FILE__, __LINE__);
702 return FALSE;
704 if (IS_DOUBLE_REG (dwarfreg))
705 regs [hwreg] = *(guint64*)(cfa_val + locations [hwreg].offset);
706 else
707 regs [hwreg] = *(host_mgreg_t*)(cfa_val + locations [hwreg].offset);
708 if (save_locations && hwreg < save_locations_len)
709 save_locations [hwreg] = (host_mgreg_t*)(cfa_val + locations [hwreg].offset);
713 *out_cfa = cfa_val;
715 // Success
716 return TRUE;
719 void
720 mono_unwind_init (void)
722 mono_os_mutex_init_recursive (&unwind_mutex);
724 mono_counters_register ("Unwind info size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &unwind_info_size);
727 void
728 mono_unwind_cleanup (void)
730 int i;
732 mono_os_mutex_destroy (&unwind_mutex);
734 if (!cached_info)
735 return;
737 for (i = 0; i < cached_info_next; ++i) {
738 MonoUnwindInfo *cached = cached_info [i];
740 g_free (cached);
742 g_free (cached_info);
744 for (GSList *cursor = cached_info_list; cursor != NULL; cursor = cursor->next)
745 g_free (cursor->data);
747 g_slist_free (cached_info_list);
751 * mono_cache_unwind_info
753 * Save UNWIND_INFO in the unwind info cache and return an id which can be passed
754 * to mono_get_cached_unwind_info to get a cached copy of the info.
755 * A copy is made of the unwind info.
756 * This function is useful for two reasons:
757 * - many methods have the same unwind info
758 * - MonoJitInfo->unwind_info is an int so it can't store the pointer to the unwind info
760 guint32
761 mono_cache_unwind_info (guint8 *unwind_info, guint32 unwind_info_len)
763 int i;
764 MonoUnwindInfo *info;
766 unwind_lock ();
768 if (cached_info == NULL) {
769 cached_info_size = 16;
770 cached_info = g_new0 (MonoUnwindInfo*, cached_info_size);
773 for (i = 0; i < cached_info_next; ++i) {
774 MonoUnwindInfo *cached = cached_info [i];
776 if (cached->len == unwind_info_len && memcmp (cached->info, unwind_info, unwind_info_len) == 0) {
777 unwind_unlock ();
778 return i;
782 info = (MonoUnwindInfo *)g_malloc (sizeof (MonoUnwindInfo) + unwind_info_len);
783 info->len = unwind_info_len;
784 memcpy (&info->info, unwind_info, unwind_info_len);
786 i = cached_info_next;
788 if (cached_info_next >= cached_info_size) {
789 MonoUnwindInfo **new_table;
792 * Avoid freeing the old table so mono_get_cached_unwind_info ()
793 * doesn't need locks/hazard pointers.
796 new_table = g_new0 (MonoUnwindInfo*, cached_info_size * 2);
798 memcpy (new_table, cached_info, cached_info_size * sizeof (MonoUnwindInfo*));
800 mono_memory_barrier ();
802 cached_info_list = g_slist_prepend (cached_info_list, cached_info);
804 cached_info = new_table;
806 cached_info_size *= 2;
809 cached_info [cached_info_next ++] = info;
811 unwind_info_size += sizeof (MonoUnwindInfo) + unwind_info_len;
813 unwind_unlock ();
814 return i;
818 * This function is signal safe.
820 guint8*
821 mono_get_cached_unwind_info (guint32 index, guint32 *unwind_info_len)
823 MonoUnwindInfo **table;
824 MonoUnwindInfo *info;
825 guint8 *data;
828 * This doesn't need any locks/hazard pointers,
829 * since new tables are copies of the old ones.
831 table = cached_info;
833 info = table [index];
835 *unwind_info_len = info->len;
836 data = info->info;
838 return data;
842 * mono_unwind_get_dwarf_data_align:
844 * Return the data alignment used by the encoded unwind information.
847 mono_unwind_get_dwarf_data_align (void)
849 return DWARF_DATA_ALIGN;
853 * mono_unwind_get_dwarf_pc_reg:
855 * Return the dwarf register number of the register holding the ip of the
856 * previous frame.
859 mono_unwind_get_dwarf_pc_reg (void)
861 return DWARF_PC_REG;
864 static void
865 decode_cie_op (guint8 *p, guint8 **endp)
867 int op = *p & 0xc0;
869 switch (op) {
870 case DW_CFA_advance_loc:
871 p ++;
872 break;
873 case DW_CFA_offset:
874 p ++;
875 decode_uleb128 (p, &p);
876 break;
877 case 0: {
878 int ext_op = *p;
879 p ++;
880 switch (ext_op) {
881 case DW_CFA_def_cfa:
882 decode_uleb128 (p, &p);
883 decode_uleb128 (p, &p);
884 break;
885 case DW_CFA_def_cfa_offset:
886 decode_uleb128 (p, &p);
887 break;
888 case DW_CFA_def_cfa_register:
889 decode_uleb128 (p, &p);
890 break;
891 case DW_CFA_advance_loc4:
892 p += 4;
893 break;
894 case DW_CFA_offset_extended_sf:
895 decode_uleb128 (p, &p);
896 decode_uleb128 (p, &p);
897 break;
898 default:
899 g_assert_not_reached ();
901 break;
903 default:
904 g_assert_not_reached ();
907 *endp = p;
910 static gint64
911 read_encoded_val (guint32 encoding, guint8 *p, guint8 **endp)
913 gint64 res;
915 switch (encoding & 0xf) {
916 case DW_EH_PE_sdata8:
917 res = *(gint64*)p;
918 p += 8;
919 break;
920 case DW_EH_PE_sdata4:
921 res = *(gint32*)p;
922 p += 4;
923 break;
924 default:
925 g_assert_not_reached ();
928 *endp = p;
929 return res;
933 * decode_lsda:
935 * Decode the Mono specific Language Specific Data Area generated by LLVM.
936 * This function is async safe.
938 static void
939 decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo *ex_info, gpointer *type_info, guint32 *ex_info_len, int *this_reg, int *this_offset)
941 guint8 *p;
942 int i, ncall_sites, this_encoding;
943 guint32 mono_magic, version;
945 p = lsda;
947 /* This is the modified LSDA generated by the LLVM mono branch */
948 mono_magic = decode_uleb128 (p, &p);
949 g_assert (mono_magic == 0x4d4fef4f);
950 version = decode_uleb128 (p, &p);
951 g_assert (version == 1);
952 this_encoding = *p;
953 p ++;
954 if (this_encoding == DW_EH_PE_udata4) {
955 gint32 op, reg, offset;
957 /* 'this' location */
958 op = *p;
959 g_assert (op == DW_OP_bregx);
960 p ++;
961 reg = decode_uleb128 (p, &p);
962 offset = decode_sleb128 (p, &p);
964 *this_reg = mono_dwarf_reg_to_hw_reg (reg);
965 *this_offset = offset;
966 } else {
967 g_assert (this_encoding == DW_EH_PE_omit);
969 *this_reg = -1;
970 *this_offset = -1;
972 ncall_sites = decode_uleb128 (p, &p);
973 p = (guint8*)ALIGN_TO ((gsize)p, 4);
975 if (ex_info_len)
976 *ex_info_len = ncall_sites;
978 for (i = 0; i < ncall_sites; ++i) {
979 int block_start_offset, block_size, landing_pad;
980 guint8 *tinfo;
982 block_start_offset = read32 (p);
983 p += sizeof (gint32);
984 block_size = read32 (p);
985 p += sizeof (gint32);
986 landing_pad = read32 (p);
987 p += sizeof (gint32);
988 tinfo = p;
989 p += sizeof (gint32);
991 g_assert (landing_pad);
992 g_assert (((size_t)tinfo % 4) == 0);
993 //printf ("X: %p %d\n", landing_pad, *(int*)tinfo);
995 if (ex_info) {
996 if (type_info)
997 type_info [i] = tinfo;
998 ex_info[i].try_start = code + block_start_offset;
999 ex_info[i].try_end = code + block_start_offset + block_size;
1000 ex_info[i].handler_start = code + landing_pad;
1006 * mono_unwind_decode_fde:
1008 * Decode a DWARF FDE entry, returning the unwind opcodes.
1009 * If not NULL, EX_INFO is set to a malloc-ed array of MonoJitExceptionInfo structures,
1010 * only try_start, try_end and handler_start is set.
1011 * If not NULL, TYPE_INFO is set to a malloc-ed array containing the ttype table from the
1012 * LSDA.
1014 guint8*
1015 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)
1017 guint8 *p, *cie, *fde_current, *fde_aug = NULL, *code, *fde_cfi, *cie_cfi;
1018 gint32 fde_len, cie_offset, pc_begin, pc_range, aug_len;
1019 gint32 cie_len, cie_id, cie_version, code_align, data_align, return_reg;
1020 gint32 i, cie_aug_len, buf_len;
1021 char *cie_aug_str;
1022 guint8 *buf;
1023 gboolean has_fde_augmentation = FALSE;
1026 * http://refspecs.freestandards.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
1029 /* This is generated by JITDwarfEmitter::EmitEHFrame () */
1031 *type_info = NULL;
1032 *this_reg = -1;
1033 *this_offset = -1;
1035 /* Decode FDE */
1037 p = fde;
1038 // FIXME: Endianess ?
1039 fde_len = *(guint32*)p;
1040 g_assert (fde_len != 0xffffffff && fde_len != 0);
1041 p += 4;
1042 cie_offset = *(guint32*)p;
1043 cie = p - cie_offset;
1044 p += 4;
1045 fde_current = p;
1047 /* Decode CIE */
1048 p = cie;
1049 cie_len = *(guint32*)p;
1050 p += 4;
1051 cie_id = *(guint32*)p;
1052 g_assert (cie_id == 0);
1053 p += 4;
1054 cie_version = *p;
1055 g_assert (cie_version == 1);
1056 p += 1;
1057 cie_aug_str = (char*)p;
1058 p += strlen (cie_aug_str) + 1;
1059 code_align = decode_uleb128 (p, &p);
1060 data_align = decode_sleb128 (p, &p);
1061 return_reg = decode_uleb128 (p, &p);
1062 if (strstr (cie_aug_str, "z")) {
1063 guint8 *cie_aug;
1064 guint32 p_encoding;
1066 cie_aug_len = decode_uleb128 (p, &p);
1068 has_fde_augmentation = TRUE;
1070 cie_aug = p;
1071 for (i = 0; cie_aug_str [i] != '\0'; ++i) {
1072 switch (cie_aug_str [i]) {
1073 case 'z':
1074 break;
1075 case 'P':
1076 p_encoding = *p;
1077 p ++;
1078 read_encoded_val (p_encoding, p, &p);
1079 break;
1080 case 'L':
1081 g_assert ((*p == (DW_EH_PE_sdata4|DW_EH_PE_pcrel)) || (*p == (DW_EH_PE_sdata8|DW_EH_PE_pcrel)));
1082 p ++;
1083 break;
1084 case 'R':
1085 g_assert (*p == (DW_EH_PE_sdata4|DW_EH_PE_pcrel));
1086 p ++;
1087 break;
1088 default:
1089 g_assert_not_reached ();
1090 break;
1094 p = cie_aug;
1095 p += cie_aug_len;
1097 cie_cfi = p;
1099 /* Continue decoding FDE */
1100 p = fde_current;
1101 /* DW_EH_PE_sdata4|DW_EH_PE_pcrel encoding */
1102 pc_begin = *(gint32*)p;
1103 code = p + pc_begin;
1104 p += 4;
1105 pc_range = *(guint32*)p;
1106 p += 4;
1107 if (has_fde_augmentation) {
1108 aug_len = decode_uleb128 (p, &p);
1109 fde_aug = p;
1110 p += aug_len;
1111 } else {
1112 aug_len = 0;
1114 fde_cfi = p;
1116 if (code_len)
1117 *code_len = pc_range;
1119 if (ex_info) {
1120 *ex_info = NULL;
1121 *ex_info_len = 0;
1124 /* Decode FDE augmention */
1125 if (aug_len) {
1126 gint32 lsda_offset;
1127 guint8 *lsda;
1129 /* sdata|pcrel encoding */
1130 if (aug_len == 4)
1131 lsda_offset = read32 (fde_aug);
1132 else if (aug_len == 8)
1133 lsda_offset = *(gint64*)fde_aug;
1134 else
1135 g_assert_not_reached ();
1136 if (lsda_offset != 0) {
1137 lsda = fde_aug + lsda_offset;
1139 /* Get the lengths first */
1140 guint32 len;
1141 decode_lsda (lsda, code, NULL, NULL, &len, this_reg, this_offset);
1143 if (ex_info)
1144 *ex_info = (MonoJitExceptionInfo *)g_malloc0 (len * sizeof (MonoJitExceptionInfo));
1145 if (type_info)
1146 *type_info = (gpointer *)g_malloc0 (len * sizeof (gpointer));
1148 decode_lsda (lsda, code, ex_info ? *ex_info : NULL, type_info ? *type_info : NULL, ex_info_len, this_reg, this_offset);
1152 /* Make sure the FDE uses the same constants as we do */
1153 g_assert (code_align == 1);
1154 g_assert (data_align == DWARF_DATA_ALIGN);
1155 g_assert (return_reg == DWARF_PC_REG);
1157 buf_len = (cie + cie_len + 4 - cie_cfi) + (fde + fde_len + 4 - fde_cfi);
1158 buf = (guint8 *)g_malloc0 (buf_len);
1160 i = 0;
1161 p = cie_cfi;
1162 while (p < cie + cie_len + 4) {
1163 if (*p == DW_CFA_nop)
1164 break;
1165 else
1166 decode_cie_op (p, &p);
1168 memcpy (buf + i, cie_cfi, p - cie_cfi);
1169 i += p - cie_cfi;
1171 p = fde_cfi;
1172 while (p < fde + fde_len + 4) {
1173 if (*p == DW_CFA_nop)
1174 break;
1175 else
1176 decode_cie_op (p, &p);
1178 memcpy (buf + i, fde_cfi, p - fde_cfi);
1179 i += p - fde_cfi;
1180 g_assert (i <= buf_len);
1182 *out_len = i;
1184 return (guint8 *)g_realloc (buf, i);
1188 * mono_unwind_decode_mono_fde:
1190 * Decode an FDE entry in the LLVM emitted mono EH frame.
1191 * If EI/TYPE_INFO/UNW_INFO are NULL, compute only the value of the scalar fields in INFO.
1192 * Otherwise:
1193 * - Fill out EX_INFO with try_start, try_end and handler_start.
1194 * - Fill out TYPE_INFO with the ttype table from the LSDA.
1195 * - Fill out UNW_INFO with the unwind info.
1196 * This function is async safe.
1198 void
1199 mono_unwind_decode_llvm_mono_fde (guint8 *fde, int fde_len, guint8 *cie, guint8 *code, MonoLLVMFDEInfo *res, MonoJitExceptionInfo *ex_info, gpointer *type_info, guint8 *unw_info)
1201 guint8 *p, *fde_aug, *cie_cfi, *fde_cfi, *buf;
1202 int has_aug, aug_len, cie_cfi_len, fde_cfi_len;
1203 gint32 code_align, data_align, return_reg, pers_encoding;
1205 memset (res, 0, sizeof (*res));
1206 res->this_reg = -1;
1207 res->this_offset = -1;
1209 /* fde points to data emitted by LLVM in DwarfMonoException::EmitMonoEHFrame () */
1210 p = fde;
1211 has_aug = *p;
1212 p ++;
1213 if (has_aug) {
1214 aug_len = read32 (p);
1215 p += 4;
1216 } else {
1217 aug_len = 0;
1219 fde_aug = p;
1220 p += aug_len;
1221 fde_cfi = p;
1223 if (has_aug) {
1224 guint8 *lsda;
1226 /* The LSDA is embedded directly into the FDE */
1227 lsda = fde_aug;
1229 /* Get the lengths first */
1230 decode_lsda (lsda, code, NULL, NULL, &res->ex_info_len, &res->this_reg, &res->this_offset);
1232 decode_lsda (lsda, code, ex_info, type_info, NULL, &res->this_reg, &res->this_offset);
1235 /* Decode CIE */
1236 p = cie;
1237 code_align = decode_uleb128 (p, &p);
1238 data_align = decode_sleb128 (p, &p);
1239 return_reg = decode_uleb128 (p, &p);
1240 pers_encoding = *p;
1241 p ++;
1242 if (pers_encoding != DW_EH_PE_omit)
1243 read_encoded_val (pers_encoding, p, &p);
1245 cie_cfi = p;
1247 /* Make sure the FDE uses the same constants as we do */
1248 g_assert (code_align == 1);
1249 g_assert (data_align == DWARF_DATA_ALIGN);
1250 g_assert (return_reg == DWARF_PC_REG);
1252 /* Compute size of CIE unwind info it is DW_CFA_nop terminated */
1253 p = cie_cfi;
1254 while (TRUE) {
1255 if (*p == DW_CFA_nop)
1256 break;
1257 else
1258 decode_cie_op (p, &p);
1260 cie_cfi_len = p - cie_cfi;
1261 fde_cfi_len = (fde + fde_len - fde_cfi);
1263 buf = unw_info;
1264 if (buf) {
1265 memcpy (buf, cie_cfi, cie_cfi_len);
1266 memcpy (buf + cie_cfi_len, fde_cfi, fde_cfi_len);
1269 res->unw_info_len = cie_cfi_len + fde_cfi_len;
1273 * mono_unwind_get_cie_program:
1275 * Get the unwind bytecode for the DWARF CIE.
1277 GSList*
1278 mono_unwind_get_cie_program (void)
1280 #if defined(TARGET_AMD64) || defined(TARGET_X86) || defined(TARGET_POWERPC) || defined(TARGET_ARM)
1281 return mono_arch_get_cie_program ();
1282 #else
1283 return NULL;
1284 #endif