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.
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.
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]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2012 Milan Jurik. All rights reserved.
29 * UNWIND - Unwind library
33 * ===================== stack walk ====================
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:
41 * callee saves registers <current values>
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
49 * callee saves registers <values on entry>
51 * cannonical frame address
53 * completing the context for the user function (See
54 * _Unw_Rollback_Registers()) .
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.
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
65 * callee saves registers <current values>
72 * values of integer argument registers
74 * (changed values take effect if context is "installed" - think
82 * | local storage for start() | <FP == 0>
84 * --------------------------------.
87 * | | <- CFA for bar()
88 * --------------------------------.
90 * | local storage for bar() |
91 * | | <- SP for bar(), CFA for foo()
92 * ................................
94 * --------------------------------
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 * --------------------------------
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 * --------------------------------
112 * | local storage for Unw() |
113 * | | <- SP for Unw() == SP1
115 * We know that Unw() and ex_throw save and have an FP
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
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
148 #include "stack_unwind.h"
150 #include "unwind_context.h"
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;
157 void _Unw_capture_regs(uint64_t *regs
);
158 void _Unw_jmp(uint64_t pc
, uint64_t *regs
);
161 copy_ctx(struct _Unwind_Context
*ctx1
, struct _Unwind_Context
*ctx2
)
164 (void) memcpy(ctx2
, ctx1
, sizeof (*ctx2
));
168 static _Unwind_Personality_Fn
169 ctx_who(struct _Unwind_Context
*ctx
)
176 _Unw_very_boring_personality(int version
, int actions
, uint64_t exclass
,
177 struct _Unwind_Exception
*exception_object
,
178 struct _Unwind_Context
*ctx
)
180 _Unwind_Reason_Code res
= _URC_CONTINUE_UNWIND
;
183 fp
= _Unwind_GetCFA(ctx
);
184 if (fp
== 0 || _Unwind_GetIP(ctx
) == 0) {
185 return (_URC_END_OF_STACK
);
191 * The only static variables in this code - changed by debugging hook below
193 static int using_ehf
= 1;
194 static uintptr_t def_per_fcn
= (uintptr_t)&_Unw_very_boring_personality
;
197 _SUNW_Unw_set_defaults(int use
, uintptr_t def_per
)
200 def_per_fcn
= def_per
;
204 complete_context(struct _Unwind_Context
*ctx
)
206 struct eh_frame_fields sf
;
207 struct eh_frame_fields
*sfp
= 0;
209 ctx
->pfn
= (_Unwind_Personality_Fn
)def_per_fcn
;
214 if (using_ehf
&& (0 != _Unw_EhfhLookup(ctx
))) {
215 sfp
= _Unw_Decode_FDE(&sf
, ctx
);
217 (void) _Unw_Rollback_Registers(sfp
, ctx
);
221 * input: FP1 (or FP2 if from _Unwind_Resume (from_landing_pad))
228 * output: PC3, SP3, and BP3
230 * remaining callee saves registers are also captured in context
233 finish_capture(struct _Unwind_Context
*ctx
, int from_landing_pad
)
235 uint64_t fp1
= ctx
->current_regs
[FP_RBP
];
236 uint64_t fp2
= from_landing_pad
? fp1
: ((uint64_t *)fp1
)[0];
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
);
245 down_one(struct _Unwind_Context
*old_ctx
, struct _Unwind_Context
*new_ctx
)
247 uint64_t old_cfa
= old_ctx
->cfa
;
248 uint64_t old_pc
= old_ctx
->pc
;
251 if (old_cfa
== 0 || old_pc
== 0) {
257 if (old_ctx
->ra
== 0) {
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)) {
276 jmp_ctx(struct _Unwind_Context
*ctx
)
278 _Unw_jmp(ctx
->pc
, ctx
->current_regs
);
282 * Here starts the real work - the entry points from either a language
283 * runtime or directly from user code.
285 * The two ..._Body functions are intended as private interfaces for
286 * Sun code as well so should remain accessible.
289 _Unwind_RaiseException_Body(struct _Unwind_Exception
*exception_object
,
290 struct _Unwind_Context
*entry_ctx
, int phase
)
292 struct _Unwind_Context context
;
293 struct _Unwind_Context
*ctx
= &context
;
294 _Unwind_Reason_Code res
;
296 if (phase
& _UA_SEARCH_PHASE
) {
297 finish_capture(entry_ctx
, 0);
298 copy_ctx(entry_ctx
, ctx
);
301 res
= (*ctx_who(ctx
))(1, phase
,
302 exception_object
->exception_class
,
303 exception_object
, ctx
);
304 if (res
!= _URC_CONTINUE_UNWIND
)
306 if (down_one(ctx
, ctx
))
307 return (_URC_FATAL_PHASE1_ERROR
);
310 case _URC_HANDLER_FOUND
:
311 exception_object
->private_2
= _Unwind_GetCFA(ctx
);
317 finish_capture(entry_ctx
, 1);
318 if (down_one(entry_ctx
, entry_ctx
))
319 return (_URC_FATAL_PHASE2_ERROR
);
322 phase
= _UA_CLEANUP_PHASE
;
323 copy_ctx(entry_ctx
, ctx
);
326 if (exception_object
->private_2
== _Unwind_GetCFA(ctx
)) {
327 phase
|= _UA_HANDLER_FRAME
;
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
)
336 if (down_one(ctx
, ctx
))
337 return (_URC_FATAL_PHASE2_ERROR
);
340 case _URC_INSTALL_CONTEXT
:
341 exception_object
->private_1
= 0;
342 jmp_ctx(ctx
); /* does not return */
351 _Unwind_RaiseException(struct _Unwind_Exception
*exception_object
)
353 struct _Unwind_Context entry_context
;
354 struct _Unwind_Context
*entry_ctx
= &entry_context
;
356 _Unw_capture_regs(entry_ctx
->current_regs
);
358 return (_Unwind_RaiseException_Body(exception_object
, entry_ctx
,
363 _Unwind_ForcedUnwind_Body(struct _Unwind_Exception
*exception_object
,
364 _Unwind_Stop_Fn stop
, void *stop_parameter
,
365 struct _Unwind_Context
*ctx
, int resume
)
367 _Unwind_Reason_Code res
;
368 int phase
= _UA_CLEANUP_PHASE
| _UA_FORCE_UNWIND
;
373 finish_capture(ctx
, resume
);
374 if (resume
&& down_one(ctx
, ctx
))
375 return (_URC_FATAL_PHASE2_ERROR
);
380 res
= (*stop
)(1, phase
,
381 exception_object
->exception_class
,
382 exception_object
, ctx
, stop_parameter
);
384 case _URC_CONTINUE_UNWIND
:
385 /* keep going - don't call personality */
389 /* keep going - do call personality */
393 case _URC_NORMAL_STOP
: /* done */
395 case _URC_INSTALL_CONTEXT
: /* resume execution */
397 default: /* failure */
401 res
= (*ctx_who(ctx
))(1, phase
,
402 exception_object
->exception_class
,
403 exception_object
, ctx
);
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 */
411 case _URC_CONTINUE_UNWIND
:
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
);
425 if (down_one(ctx
, ctx
)) {
426 return (_URC_FATAL_PHASE2_ERROR
);
435 _Unwind_ForcedUnwind(struct _Unwind_Exception
*exception_object
,
436 _Unwind_Stop_Fn stop
, void *stop_parameter
)
438 struct _Unwind_Context context
;
439 struct _Unwind_Context
*ctx
= &context
;
441 _Unw_capture_regs(ctx
->current_regs
);
443 return (_Unwind_ForcedUnwind_Body(exception_object
, stop
,
444 stop_parameter
, ctx
, 0));
448 _Unwind_Resume(struct _Unwind_Exception
*exception_object
)
451 struct _Unwind_Context context
;
452 struct _Unwind_Context
*ctx
= &context
;
454 _Unw_capture_regs(ctx
->current_regs
);
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
,
462 (void) _Unwind_RaiseException_Body(exception_object
, ctx
,
466 /* Calls destructor function for exception object */
468 _Unwind_DeleteException(struct _Unwind_Exception
*exception_object
)
470 if (exception_object
->exception_cleanup
!= 0)
471 (*(exception_object
->exception_cleanup
))(_URC_NO_REASON
,
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
482 _Unwind_GetGR(struct _Unwind_Context
*context
, int index
)
485 if (index
<= EIR_R15
) {
486 res
= context
->current_regs
[index
];
487 } else if (index
== RET_ADD
) {
495 _Unwind_SetGR(struct _Unwind_Context
*context
, int index
,
498 if (index
<= EIR_R15
) {
499 context
->current_regs
[index
] = new_value
;
500 } else if (index
== RET_ADD
) {
501 context
->ra
= new_value
;
507 _Unwind_GetIP(struct _Unwind_Context
*context
)
509 return (context
->pc
);
513 _Unwind_SetIP(struct _Unwind_Context
*context
, uint64_t new_value
)
515 context
->pc
= new_value
;
520 _Unwind_GetLanguageSpecificData(struct _Unwind_Context
*context
)
522 return (context
->lsda
);
527 _Unwind_GetRegionStart(struct _Unwind_Context
*context
)
529 return (context
->func
);
533 _Unwind_GetCFA(struct _Unwind_Context
*context
)
535 return (context
->cfa
);