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
152const _Unwind_Action _UA_SEARCH_PHASE = 1;
153const _Unwind_Action _UA_CLEANUP_PHASE = 2;
154const _Unwind_Action _UA_HANDLER_FRAME = 4;
155const _Unwind_Action _UA_FORCE_UNWIND = 8;
156
157void _Unw_capture_regs(uint64_t *regs);
158void _Unw_jmp(uint64_t pc, uint64_t *regs);
159
160static void
161copy_ctx(struct _Unwind_Context *ctx1, struct _Unwind_Context *ctx2)
162{
163	if (ctx1 != ctx2) {
164		(void) memcpy(ctx2, ctx1, sizeof (*ctx2));
165	}
166}
167
168static _Unwind_Personality_Fn
169ctx_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 */
193static int using_ehf = 1;
194static uintptr_t def_per_fcn = (uintptr_t)&_Unw_very_boring_personality;
195
196void
197_SUNW_Unw_set_defaults(int use, uintptr_t def_per)
198{
199	using_ehf = use;
200	def_per_fcn = def_per;
201}
202
203static void
204complete_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 */
232static void
233finish_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
244static int
245down_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
275static void
276jmp_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
447void
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 */
467void
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 */
481uint64_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
494void
495_Unwind_SetGR(struct _Unwind_Context *context, int index,
496uint64_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
506uint64_t
507_Unwind_GetIP(struct _Unwind_Context *context)
508{
509	return (context->pc);
510}
511
512void
513_Unwind_SetIP(struct _Unwind_Context *context, uint64_t new_value)
514{
515	context->pc = new_value;
516}
517
518
519void *
520_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context)
521{
522	return (context->lsda);
523}
524
525
526uint64_t
527_Unwind_GetRegionStart(struct _Unwind_Context *context)
528{
529	return (context->func);
530}
531
532uint64_t
533_Unwind_GetCFA(struct _Unwind_Context *context)
534{
535	return (context->cfa);
536}
537