root/usr/src/lib/libc/amd64/unwind/unwind_context.h
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (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
 * or http://www.opensolaris.org/os/licensing.
 * 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 2004 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*
 * Public interface for AMD64 Unwind context
 */

#ifndef _UNWIND_CONTEXT_H
#define _UNWIND_CONTEXT_H

/*
 * implementation of context structure
 *
 * Register arrays are indexed as specified in reg_num.h
 */
struct _Unwind_Context {
        uint64_t        entry_regs[16];
        uint64_t        current_regs[16];
        uint64_t        cfa;
        uint64_t        pc;
        uint64_t        ra;
        void            *fde;
        _Unwind_Personality_Fn  pfn;
        uint64_t        func;
        void            *lsda;
        uint64_t        range;
};

enum register_rule {
        undefined_rule,
        same_value_rule,        /* target_reg = target_reg */
        offset_rule,            /* target_reg = *(offset + CFA) */
        is_offset_rule,         /* target_reg = offset + CFA */
        register_rule,          /* target_reg = offset + source_reg */
        constant_rule,          /* target_reg = offset */
        indirect_rule           /* target_reg = *(offset + source_reg) */
};

struct register_state {
        uint64_t        offset;
        enum register_rule      rule;
        unsigned char   source_reg;
};

struct eh_frame_fields {
        void            *cie_ops;
        void            *cie_ops_end;
        ptrdiff_t       cie_reloc;
        int             code_align;
        int             data_align;
        int             code_enc;
        void            *fde_ops;
        void            *fde_ops_end;
        ptrdiff_t       fde_reloc;
};

_Unwind_Reason_Code
_Unw_very_boring_personality(int version, int actions, uint64_t exclass,
                struct _Unwind_Exception *exception_object,
                struct _Unwind_Context *ctx);
/*
 * Starting withe an initialized context (from a ucontext)
 * the following routines are sufficient to implement a non-destructive
 * stack walk if modified to access the target processes memory. These
 * routines refer to the local address of an item using names containing
 * `data' names containing `reloc' give the correction to get target
 * process location.
 */

/* ================== find function ====================== */

/*
 * Computes the func and fde fields using pc as the lookup key.
 * Return is 0 or address of fde
 *
 * This is the only function that look into .eh_frame_hdr
 */
void *_Unw_EhfhLookup(struct _Unwind_Context *ctx);

/* =================== analyze function ================== */

/*
 * Fills in personality_fn and lsda fields of the context based
 * the fde entry which must be valid and also partially unpacks
 * fde and cie into *f
 *
 * This is one of two functions that look inside fde's
 */
struct eh_frame_fields *_Unw_Decode_FDE(struct eh_frame_fields *f,
                struct _Unwind_Context *ctx);

/*
 * Computes register values at entry to function based on current
 * register values, pc and fde values in a context
 *
 * This is the other function which looks inside fde's and
 * the only one to look at CFA operations
 *
 * If 'f' is NULL (because no fde was found), a default calculation
 * assuming an FP is done.
 */
uint64_t _Unw_Rollback_Registers(struct eh_frame_fields *f,
                struct _Unwind_Context *ctx);

/* ================= register propagation =============== */

/*
 * Fills in the current register context for the caller
 * based on computed at-entry state of callee
 */
void
_Unw_Propagate_Registers(struct _Unwind_Context *old_ctx,
                struct _Unwind_Context *new_ctx);

/* ================================================= */
enum operand_desc {
        NO_OPR,
        ULEB128_FAC,
        ULEB128,
        ULEB128_SREG,
        SLEB128,
        SLEB128_FAC,
        ADDR,
        SIZE,
        ZTSTRING,
        UNUM6,
        UNUM6_CFAC,
        UNUM8,
        UNUM8_CFAC,
        UNUM16,
        UNUM16_CFAC,
        UNUM32,
        UNUM32_CFAC,
        UNUM64,
        SNUM8,
        SNUM16,
        SNUM32,
        SNUM64,
        BLOCK
};

uint64_t _Unw_get_val(void **datap, ptrdiff_t reloc,
                enum operand_desc opr,
                int daf, int caf, int enc);

#endif  /* _UNWIND_CONTEXT_H */