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