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, &reg_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 (&reg_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