xref: /illumos-gate/usr/src/lib/libc/amd64/unwind/unwind.c (revision 33f5ff17)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  * Copyright 2012 Milan Jurik. All rights reserved.
26  */
27 
28 /*
29  * UNWIND - Unwind library
30  */
31 
32 /*
33  * ===================== stack walk ====================
34  *
35  * Stack walk-back starts with the user code at the top of the stack
36  * calling a language specific support routine which calls the generic
37  * unwind code. The unwind code captures
38  * information which can be used to partially build an _Unwind_Context
39  * for the user code containing:
40  *
41  *    callee saves registers <current values>
42  *    PC
43  *    %rbp
44  *    %rsp
45  *
46  * Using that pc location the unwind info for the function is found.
47  * Then the CFA operations encoded in the unwind info are interepreted to get
48  *
49  *    callee saves registers <values on entry>
50  *    the return address
51  *    cannonical frame address
52  *
53  * completing the context for the user function (See
54  * _Unw_Rollback_Registers()) .
55  *
56  * The values computed above are equivalent to the info which would have been
57  * captured from the caller and are used to initialize the callers context
58  * (see _Unw_Propagate_Registers()) which can be completed.
59  *
60  * Using the same two-step procedure
61  * context records for each frame down the stack may be constructed
62  * in turn.  The ABI defined interface to _Unwind_Context provides
63  * access to
64  *
65  *    callee saves registers <current values>
66  *    current PC
67  *    frame pointer
68  *
69  * and allows changing
70  *
71  *    PC
72  *    values of integer argument registers
73  *
74  * (changed values take effect if context is "installed" - think
75  * setcontext(2))
76  *
77  */
78 
79 /*
80  *
81  * |                              |
82  * | local storage for start()    | <FP == 0>
83  * |                              |
84  * --------------------------------.
85  * |                              |
86  * |     ..........               |
87  * |                              | <-  CFA for bar()
88  * --------------------------------.
89  * |                              |
90  * | local storage for bar()      |
91  * |                              | <-  SP for bar(), CFA for foo()
92  * ................................
93  * |  pc for bar()                |
94  * --------------------------------
95  * |                              |
96  * | local storage for foo()      |
97  * |                              | <-  SP for foo(), CFA for ex_throw()
98  * ................................
99  * | pc for foo() - PC3           |
100  * ................................
101  * | saved RBP from foo() - BP3   | <-  FP for ex_throw() == FP2
102  * --------------------------------
103  * |                              |
104  * | local storage for ex_throw() |
105  * |                              | <- SP for ex_throw(), CFA for Unw()
106  * ................................
107  * | pc for ex_throw() - PC2      |
108  * ................................
109  * | saved RBP from ex_throw()    | <- FP for Unw() == FP1
110  * --------------------------------
111  * |                              |
112  * | local storage for Unw()      |
113  * |                              | <- SP for Unw() == SP1
114  *
115  * We know that Unw() and ex_throw save and have an FP
116  *
117  */
118 
119 #ifdef _LIBCRUN_
120 #define	_Unwind_DeleteException  _SUNW_Unwind_DeleteException
121 #define	_Unwind_ForcedUnwind  _SUNW_Unwind_ForcedUnwind
122 #define	_Unwind_GetCFA  _SUNW_Unwind_GetCFA
123 #define	_Unwind_GetGR  _SUNW_Unwind_GetGR
124 #define	_Unwind_GetIP  _SUNW_Unwind_GetIP
125 #define	_Unwind_GetLanguageSpecificData _SUNW_Unwind_GetLanguageSpecificData
126 #define	_Unwind_GetRegionStart  _SUNW_Unwind_GetRegionStart
127 #define	_Unwind_RaiseException  _SUNW_Unwind_RaiseException
128 #define	_Unwind_Resume  _SUNW_Unwind_Resume
129 #define	_Unwind_SetGR  _SUNW_Unwind_SetGR
130 #define	_Unwind_SetIP  _SUNW_Unwind_SetIP
131 #else
132 #pragma weak _SUNW_Unwind_DeleteException = _Unwind_DeleteException
133 #pragma weak _SUNW_Unwind_ForcedUnwind = _Unwind_ForcedUnwind
134 #pragma weak _SUNW_Unwind_GetCFA = _Unwind_GetCFA
135 #pragma weak _SUNW_Unwind_GetGR = _Unwind_GetGR
136 #pragma weak _SUNW_Unwind_GetIP = _Unwind_GetIP
137 #pragma weak _SUNW_Unwind_GetLanguageSpecificData = \
138 		_Unwind_GetLanguageSpecificData
139 #pragma weak _SUNW_Unwind_GetRegionStart = _Unwind_GetRegionStart
140 #pragma weak _SUNW_Unwind_RaiseException = _Unwind_RaiseException
141 #pragma weak _SUNW_Unwind_Resume = _Unwind_Resume
142 #pragma weak _SUNW_Unwind_SetGR = _Unwind_SetGR
143 #pragma weak _SUNW_Unwind_SetIP = _Unwind_SetIP
144 #endif
145 
146 #include "lint.h"
147 #include <string.h>
148 #include "stack_unwind.h"
149 #include "reg_num.h"
150 #include "unwind_context.h"
151 
152 const _Unwind_Action _UA_SEARCH_PHASE = 1;
153 const _Unwind_Action _UA_CLEANUP_PHASE = 2;
154 const _Unwind_Action _UA_HANDLER_FRAME = 4;
155 const _Unwind_Action _UA_FORCE_UNWIND = 8;
156 
157 void _Unw_capture_regs(uint64_t *regs);
158 void _Unw_jmp(uint64_t pc, uint64_t *regs);
159 
160 static void
161 copy_ctx(struct _Unwind_Context *ctx1, struct _Unwind_Context *ctx2)
162 {
163 	if (ctx1 != ctx2) {
164 		(void) memcpy(ctx2, ctx1, sizeof (*ctx2));
165 	}
166 }
167 
168 static _Unwind_Personality_Fn
169 ctx_who(struct _Unwind_Context *ctx)
170 {
171 	return (ctx->pfn);
172 }
173 
174 /* ARGSUSED */
175 _Unwind_Reason_Code
176 _Unw_very_boring_personality(int version, int actions, uint64_t exclass,
177 	struct _Unwind_Exception *exception_object,
178 	struct _Unwind_Context *ctx)
179 {
180 	_Unwind_Reason_Code res = _URC_CONTINUE_UNWIND;
181 	uint64_t fp;
182 
183 	fp =  _Unwind_GetCFA(ctx);
184 	if (fp == 0 || _Unwind_GetIP(ctx) == 0) {
185 		return (_URC_END_OF_STACK);
186 	}
187 	return (res);
188 }
189 
190 /*
191  * The only static variables in this code - changed by debugging hook below
192  */
193 static int using_ehf = 1;
194 static uintptr_t def_per_fcn = (uintptr_t)&_Unw_very_boring_personality;
195 
196 void
197 _SUNW_Unw_set_defaults(int use, uintptr_t def_per)
198 {
199 	using_ehf = use;
200 	def_per_fcn = def_per;
201 }
202 
203 static void
204 complete_context(struct _Unwind_Context *ctx)
205 {
206 	struct eh_frame_fields sf;
207 	struct eh_frame_fields *sfp = 0;
208 
209 	ctx->pfn = (_Unwind_Personality_Fn)def_per_fcn;
210 	ctx->lsda = 0;
211 	ctx->func = 0;
212 	ctx->range = 0;
213 	ctx->fde = 0;
214 	if (using_ehf && (0 != _Unw_EhfhLookup(ctx))) {
215 		sfp = _Unw_Decode_FDE(&sf, ctx);
216 	}
217 	(void) _Unw_Rollback_Registers(sfp, ctx);
218 }
219 
220 /*
221  * input: FP1 (or FP2 if from _Unwind_Resume (from_landing_pad))
222  *
223  * FP2 = FP1[0];
224  * BP3 = FP2[0];
225  * PC3 = FP2[1];
226  * SP3 = FP2 + 16;
227  *
228  * output: PC3, SP3, and BP3
229  *
230  * remaining callee saves registers are also captured in context
231  */
232 static void
233 finish_capture(struct _Unwind_Context *ctx, int from_landing_pad)
234 {
235 	uint64_t fp1 = ctx->current_regs[FP_RBP];
236 	uint64_t fp2 = from_landing_pad ? fp1 : ((uint64_t *)fp1)[0];
237 
238 	ctx->pc = ((uint64_t *)fp2)[1];
239 	ctx->current_regs[SP_RSP] = fp2 + 16;
240 	ctx->current_regs[FP_RBP] = ((uint64_t *)fp2)[0];
241 	complete_context(ctx);
242 }
243 
244 static int
245 down_one(struct _Unwind_Context *old_ctx, struct _Unwind_Context *new_ctx)
246 {
247 	uint64_t old_cfa = old_ctx->cfa;
248 	uint64_t old_pc = old_ctx->pc;
249 	uint64_t new_cfa;
250 
251 	if (old_cfa == 0 || old_pc == 0) {
252 		new_ctx->pc = 0;
253 		new_ctx->cfa = 0;
254 		new_ctx->ra = 0;
255 		return (1);
256 	}
257 	if (old_ctx->ra == 0) {
258 		new_ctx->pc = 0;
259 		new_ctx->cfa = 0;
260 		new_ctx->ra = 0;
261 		return (0);
262 	}
263 	/* now shift ----------------------------- */
264 	_Unw_Propagate_Registers(old_ctx, new_ctx);
265 	complete_context(new_ctx);
266 	new_cfa = new_ctx->cfa;
267 	if ((new_cfa < old_cfa) || (new_cfa & 7)) {
268 		new_ctx->pc = 0;
269 		new_ctx->cfa = 0;
270 		new_ctx->ra = 0;
271 	}
272 	return (0);
273 }
274 
275 static void
276 jmp_ctx(struct _Unwind_Context *ctx)
277 {
278 	_Unw_jmp(ctx->pc, ctx->current_regs);
279 }
280 
281 /*
282  * Here starts the real work - the entry points from either a language
283  * runtime or directly from user code.
284  *
285  * The two ..._Body functions are intended as private interfaces for
286  * Sun code as well so should remain accessible.
287  */
288 _Unwind_Reason_Code
289 _Unwind_RaiseException_Body(struct _Unwind_Exception *exception_object,
290 	struct _Unwind_Context *entry_ctx, int phase)
291 {
292 	struct _Unwind_Context context;
293 	struct _Unwind_Context *ctx = &context;
294 	_Unwind_Reason_Code res;
295 
296 	if (phase & _UA_SEARCH_PHASE) {
297 		finish_capture(entry_ctx, 0);
298 		copy_ctx(entry_ctx, ctx);
299 
300 		for (;;) {
301 			res = (*ctx_who(ctx))(1, phase,
302 			    exception_object->exception_class,
303 			    exception_object, ctx);
304 			if (res != _URC_CONTINUE_UNWIND)
305 				break;
306 			if (down_one(ctx, ctx))
307 				return (_URC_FATAL_PHASE1_ERROR);
308 		}
309 		switch (res) {
310 		case _URC_HANDLER_FOUND:
311 			exception_object->private_2 = _Unwind_GetCFA(ctx);
312 			break;
313 		default:
314 			return (res);
315 		}
316 	} else {
317 		finish_capture(entry_ctx, 1);
318 		if (down_one(entry_ctx, entry_ctx))
319 			return (_URC_FATAL_PHASE2_ERROR);
320 	}
321 
322 	phase = _UA_CLEANUP_PHASE;
323 	copy_ctx(entry_ctx, ctx);
324 
325 	for (;;) {
326 		if (exception_object->private_2 == _Unwind_GetCFA(ctx)) {
327 			phase |= _UA_HANDLER_FRAME;
328 		}
329 		res = (*ctx_who(ctx))(1, phase,
330 		    exception_object->exception_class,
331 		    exception_object, ctx);
332 		if ((phase & _UA_HANDLER_FRAME) && res != _URC_INSTALL_CONTEXT)
333 			return (_URC_FATAL_PHASE2_ERROR);
334 		if (res != _URC_CONTINUE_UNWIND)
335 			break;
336 		if (down_one(ctx, ctx))
337 			return (_URC_FATAL_PHASE2_ERROR);
338 	}
339 	switch (res) {
340 	case _URC_INSTALL_CONTEXT:
341 		exception_object->private_1 = 0;
342 		jmp_ctx(ctx); /* does not return */
343 		break;
344 	default:
345 		break;
346 	}
347 	return (res);
348 }
349 
350 _Unwind_Reason_Code
351 _Unwind_RaiseException(struct _Unwind_Exception *exception_object)
352 {
353 	struct _Unwind_Context entry_context;
354 	struct _Unwind_Context *entry_ctx = &entry_context;
355 
356 	_Unw_capture_regs(entry_ctx->current_regs);
357 
358 	return (_Unwind_RaiseException_Body(exception_object, entry_ctx,
359 	    _UA_SEARCH_PHASE));
360 }
361 
362 _Unwind_Reason_Code
363 _Unwind_ForcedUnwind_Body(struct _Unwind_Exception *exception_object,
364 	_Unwind_Stop_Fn stop, void *stop_parameter,
365 	struct _Unwind_Context *ctx, int resume)
366 {
367 	_Unwind_Reason_Code res;
368 	int phase = _UA_CLEANUP_PHASE | _UA_FORCE_UNWIND;
369 
370 	int again;
371 	int doper;
372 
373 	finish_capture(ctx, resume);
374 	if (resume && down_one(ctx, ctx))
375 		return (_URC_FATAL_PHASE2_ERROR);
376 
377 	do {
378 		again = 0;
379 		doper = 0;
380 		res = (*stop)(1, phase,
381 		    exception_object->exception_class,
382 		    exception_object, ctx, stop_parameter);
383 		switch (res) {
384 		case _URC_CONTINUE_UNWIND:
385 			/* keep going - don't call personality */
386 			again = 1;
387 			break;
388 		case _URC_NO_REASON:
389 			/* keep going - do call personality */
390 			again = 1;
391 			doper = 1;
392 			break;
393 		case _URC_NORMAL_STOP:  /* done */
394 			break;
395 		case _URC_INSTALL_CONTEXT:  /* resume execution */
396 			break;
397 		default:		/* failure */
398 			break;
399 		}
400 		if (doper) {
401 			res = (*ctx_who(ctx))(1, phase,
402 			    exception_object->exception_class,
403 			    exception_object, ctx);
404 		}
405 		switch (res) {
406 		case _URC_INSTALL_CONTEXT:
407 			exception_object->private_1 = (uint64_t)stop;
408 			exception_object->private_2 = (uint64_t)stop_parameter;
409 			jmp_ctx(ctx); /* does not return */
410 			break;
411 		case _URC_CONTINUE_UNWIND:
412 		case _URC_NO_REASON:
413 			break;
414 		case _URC_END_OF_STACK:
415 			ctx->cfa = ctx->ra = ctx->pc = 0;
416 			res = (*stop)(1, phase,
417 			    exception_object->exception_class,
418 			    exception_object, ctx, stop_parameter);
419 			return (_URC_END_OF_STACK);
420 		default:
421 			again = 0;
422 			break;
423 		}
424 		if (again) {
425 			if (down_one(ctx, ctx)) {
426 				return (_URC_FATAL_PHASE2_ERROR);
427 			}
428 		}
429 	} while (again);
430 
431 	return (res);
432 }
433 
434 _Unwind_Reason_Code
435 _Unwind_ForcedUnwind(struct _Unwind_Exception *exception_object,
436 	_Unwind_Stop_Fn stop, void *stop_parameter)
437 {
438 	struct _Unwind_Context context;
439 	struct _Unwind_Context *ctx = &context;
440 
441 	_Unw_capture_regs(ctx->current_regs);
442 
443 	return (_Unwind_ForcedUnwind_Body(exception_object, stop,
444 	    stop_parameter, ctx, 0));
445 }
446 
447 void
448 _Unwind_Resume(struct _Unwind_Exception *exception_object)
449 {
450 
451 	struct _Unwind_Context context;
452 	struct _Unwind_Context *ctx = &context;
453 
454 	_Unw_capture_regs(ctx->current_regs);
455 
456 	if (exception_object->private_1)
457 		(void) _Unwind_ForcedUnwind_Body(exception_object,
458 		    (_Unwind_Stop_Fn)exception_object->private_1,
459 		    (void *)exception_object->private_2,
460 		    ctx, 1);
461 	else
462 		(void) _Unwind_RaiseException_Body(exception_object, ctx,
463 		    _UA_CLEANUP_PHASE);
464 }
465 
466 /* Calls destructor function for exception object */
467 void
468 _Unwind_DeleteException(struct _Unwind_Exception *exception_object)
469 {
470 	if (exception_object->exception_cleanup != 0)
471 		(*(exception_object->exception_cleanup))(_URC_NO_REASON,
472 		    exception_object);
473 }
474 
475 
476 /*
477  * stack frame context accessors defined in ABI
478  * (despite all the dire text in the ABI these are reliable Get/Set routines)
479  * Note: RA is handled as GR value
480  */
481 uint64_t
482 _Unwind_GetGR(struct _Unwind_Context *context, int index)
483 {
484 	uint64_t res = 0;
485 	if (index <= EIR_R15) {
486 		res = context->current_regs[index];
487 	} else if (index == RET_ADD) {
488 		res = context->ra;
489 	}
490 	return (res);
491 }
492 
493 
494 void
495 _Unwind_SetGR(struct _Unwind_Context *context, int index,
496 uint64_t new_value)
497 {
498 	if (index <= EIR_R15) {
499 		context->current_regs[index] = new_value;
500 	} else if (index == RET_ADD) {
501 		context->ra = new_value;
502 	}
503 }
504 
505 
506 uint64_t
507 _Unwind_GetIP(struct _Unwind_Context *context)
508 {
509 	return (context->pc);
510 }
511 
512 void
513 _Unwind_SetIP(struct _Unwind_Context *context, uint64_t new_value)
514 {
515 	context->pc = new_value;
516 }
517 
518 
519 void *
520 _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context)
521 {
522 	return (context->lsda);
523 }
524 
525 
526 uint64_t
527 _Unwind_GetRegionStart(struct _Unwind_Context *context)
528 {
529 	return (context->func);
530 }
531 
532 uint64_t
533 _Unwind_GetCFA(struct _Unwind_Context *context)
534 {
535 	return (context->cfa);
536 }
537