/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright 2012 Milan Jurik. All rights reserved.
*/
/*
* UNWIND - Unwind library
*/
/*
* ===================== stack walk ====================
*
* Stack walk-back starts with the user code at the top of the stack
* calling a language specific support routine which calls the generic
* unwind code. The unwind code captures
* information which can be used to partially build an _Unwind_Context
* for the user code containing:
*
* callee saves registers <current values>
* PC
* %rbp
* %rsp
*
* Using that pc location the unwind info for the function is found.
* Then the CFA operations encoded in the unwind info are interepreted to get
*
* callee saves registers <values on entry>
* the return address
* cannonical frame address
*
* completing the context for the user function (See
* _Unw_Rollback_Registers()) .
*
* The values computed above are equivalent to the info which would have been
* captured from the caller and are used to initialize the callers context
* (see _Unw_Propagate_Registers()) which can be completed.
*
* Using the same two-step procedure
* context records for each frame down the stack may be constructed
* in turn. The ABI defined interface to _Unwind_Context provides
* access to
*
* callee saves registers <current values>
* current PC
* frame pointer
*
* and allows changing
*
* PC
* values of integer argument registers
*
* (changed values take effect if context is "installed" - think
* setcontext(2))
*
*/
/*
*
* | |
* | local storage for start() | <FP == 0>
* | |
* --------------------------------.
* | |
* | .......... |
* | | <- CFA for bar()
* --------------------------------.
* | |
* | local storage for bar() |
* | | <- SP for bar(), CFA for foo()
* ................................
* | pc for bar() |
* --------------------------------
* | |
* | local storage for foo() |
* | | <- SP for foo(), CFA for ex_throw()
* ................................
* | pc for foo() - PC3 |
* ................................
* | saved RBP from foo() - BP3 | <- FP for ex_throw() == FP2
* --------------------------------
* | |
* | local storage for ex_throw() |
* | | <- SP for ex_throw(), CFA for Unw()
* ................................
* | pc for ex_throw() - PC2 |
* ................................
* | saved RBP from ex_throw() | <- FP for Unw() == FP1
* --------------------------------
* | |
* | local storage for Unw() |
* | | <- SP for Unw() == SP1
*
* We know that Unw() and ex_throw save and have an FP
*
*/
#ifdef _LIBCRUN_
#else
#endif
#include "lint.h"
#include <string.h>
#include "stack_unwind.h"
#include "reg_num.h"
#include "unwind_context.h"
static void
{
}
}
static _Unwind_Personality_Fn
{
}
/* ARGSUSED */
struct _Unwind_Exception *exception_object,
struct _Unwind_Context *ctx)
{
return (_URC_END_OF_STACK);
}
return (res);
}
/*
* The only static variables in this code - changed by debugging hook below
*/
void
{
}
static void
{
}
}
/*
* input: FP1 (or FP2 if from _Unwind_Resume (from_landing_pad))
*
* FP2 = FP1[0];
* BP3 = FP2[0];
* PC3 = FP2[1];
* SP3 = FP2 + 16;
*
* output: PC3, SP3, and BP3
*
* remaining callee saves registers are also captured in context
*/
static void
{
}
static int
{
return (1);
}
return (0);
}
/* now shift ----------------------------- */
}
return (0);
}
static void
{
}
/*
* Here starts the real work - the entry points from either a language
* runtime or directly from user code.
*
* The two ..._Body functions are intended as private interfaces for
* Sun code as well so should remain accessible.
*/
{
if (phase & _UA_SEARCH_PHASE) {
finish_capture(entry_ctx, 0);
for (;;) {
if (res != _URC_CONTINUE_UNWIND)
break;
return (_URC_FATAL_PHASE1_ERROR);
}
switch (res) {
case _URC_HANDLER_FOUND:
break;
default:
return (res);
}
} else {
return (_URC_FATAL_PHASE2_ERROR);
}
for (;;) {
}
return (_URC_FATAL_PHASE2_ERROR);
if (res != _URC_CONTINUE_UNWIND)
break;
return (_URC_FATAL_PHASE2_ERROR);
}
switch (res) {
case _URC_INSTALL_CONTEXT:
exception_object->private_1 = 0;
break;
default:
break;
}
return (res);
}
{
}
{
int again;
int doper;
return (_URC_FATAL_PHASE2_ERROR);
do {
again = 0;
doper = 0;
switch (res) {
case _URC_CONTINUE_UNWIND:
/* keep going - don't call personality */
again = 1;
break;
case _URC_NO_REASON:
/* keep going - do call personality */
again = 1;
doper = 1;
break;
case _URC_NORMAL_STOP: /* done */
break;
case _URC_INSTALL_CONTEXT: /* resume execution */
break;
default: /* failure */
break;
}
if (doper) {
}
switch (res) {
case _URC_INSTALL_CONTEXT:
break;
case _URC_CONTINUE_UNWIND:
case _URC_NO_REASON:
break;
case _URC_END_OF_STACK:
return (_URC_END_OF_STACK);
default:
again = 0;
break;
}
if (again) {
return (_URC_FATAL_PHASE2_ERROR);
}
}
} while (again);
return (res);
}
{
stop_parameter, ctx, 0));
}
void
{
if (exception_object->private_1)
(void *)exception_object->private_2,
else
}
/* Calls destructor function for exception object */
void
{
if (exception_object->exception_cleanup != 0)
}
/*
* stack frame context accessors defined in ABI
* Note: RA is handled as GR value
*/
{
}
return (res);
}
void
{
}
}
{
}
void
{
}
void *
{
}
{
}
{
}