10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*6812Sraf * Common Development and Distribution License (the "License").
6*6812Sraf * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
21*6812Sraf
220Sstevel@tonic-gate /*
23*6812Sraf * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
280Sstevel@tonic-gate
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate * interface used by unwind support to query frame descriptor info
310Sstevel@tonic-gate */
320Sstevel@tonic-gate
330Sstevel@tonic-gate #ifndef _LIBCRUN_
34*6812Sraf #include "lint.h"
350Sstevel@tonic-gate #endif
360Sstevel@tonic-gate #include <sys/types.h>
370Sstevel@tonic-gate #include "stack_unwind.h"
380Sstevel@tonic-gate #include "unwind_context.h"
390Sstevel@tonic-gate #include "reg_num.h"
400Sstevel@tonic-gate
410Sstevel@tonic-gate enum CFA_ops {
420Sstevel@tonic-gate DW_CFA_nop = 0x00,
430Sstevel@tonic-gate DW_CFA_set_loc = 0x01,
440Sstevel@tonic-gate DW_CFA_advance_loc1 = 0x02,
450Sstevel@tonic-gate DW_CFA_advance_loc2 = 0x03,
460Sstevel@tonic-gate DW_CFA_advance_loc4 = 0x04,
470Sstevel@tonic-gate DW_CFA_offset_extended = 0x05,
480Sstevel@tonic-gate DW_CFA_restore_extended = 0x06,
490Sstevel@tonic-gate DW_CFA_undefined = 0x07,
500Sstevel@tonic-gate DW_CFA_same_value = 0x08,
510Sstevel@tonic-gate DW_CFA_register = 0x09,
520Sstevel@tonic-gate DW_CFA_remember_state = 0x0a,
530Sstevel@tonic-gate DW_CFA_restore_state = 0x0b,
540Sstevel@tonic-gate DW_CFA_def_cfa = 0x0c,
550Sstevel@tonic-gate DW_CFA_def_cfa_register = 0x0d,
560Sstevel@tonic-gate DW_CFA_def_cfa_offset = 0x0e,
570Sstevel@tonic-gate DW_CFA_def_cfa_expression = 0x0f,
580Sstevel@tonic-gate DW_CFA_expression = 0x10,
590Sstevel@tonic-gate DW_CFA_offset_extended_sf = 0x11,
600Sstevel@tonic-gate DW_CFA_def_cfa_sf = 0x12,
610Sstevel@tonic-gate DW_CFA_def_cfa_offset_sf = 0x13,
620Sstevel@tonic-gate /* skip 9 values */
630Sstevel@tonic-gate DW_CFA_SUNW_advance_loc = 0x1d,
640Sstevel@tonic-gate DW_CFA_SUNW_offset = 0x1e,
650Sstevel@tonic-gate DW_CFA_SUNW_restore = 0x1f,
660Sstevel@tonic-gate DW_CFA_advance_loc = 0x40,
670Sstevel@tonic-gate DW_CFA_offset = 0x80,
680Sstevel@tonic-gate DW_CFA_restore = 0xc0
690Sstevel@tonic-gate };
700Sstevel@tonic-gate
710Sstevel@tonic-gate struct operation_desc {
720Sstevel@tonic-gate enum operand_desc op1;
730Sstevel@tonic-gate enum operand_desc op2;
740Sstevel@tonic-gate };
750Sstevel@tonic-gate
760Sstevel@tonic-gate struct operation_desc cfa_operations[] = {
770Sstevel@tonic-gate {NO_OPR, NO_OPR}, /* DW_CFA_nop */
780Sstevel@tonic-gate {ADDR, NO_OPR}, /* DW_CFA_set_loc - address */
790Sstevel@tonic-gate {UNUM8, NO_OPR}, /* DW_CFA_advance_loc1 - delta */
800Sstevel@tonic-gate {UNUM16, NO_OPR}, /* DW_CFA_advance_loc2 - delta */
810Sstevel@tonic-gate {UNUM32, NO_OPR}, /* DW_CFA_advance_loc4 - delta */
820Sstevel@tonic-gate {ULEB128, ULEB128_FAC}, /* DW_CFA_offset_extended - reg, */
830Sstevel@tonic-gate /* data factored offset */
840Sstevel@tonic-gate {ULEB128, NO_OPR}, /* DW_CFA_restore_extended - register */
850Sstevel@tonic-gate {ULEB128, NO_OPR}, /* DW_CFA_undefined - register */
860Sstevel@tonic-gate {ULEB128, NO_OPR}, /* DW_CFA_same_value - register */
870Sstevel@tonic-gate {ULEB128, ULEB128_SREG}, /* DW_CFA_register - register, register */
880Sstevel@tonic-gate {NO_OPR, NO_OPR}, /* DW_CFA_remember_state */
890Sstevel@tonic-gate {NO_OPR, NO_OPR}, /* DW_CFA_restore_state */
900Sstevel@tonic-gate {ULEB128_SREG, ULEB128}, /* DW_CFA_def_cfa - register, offset */
910Sstevel@tonic-gate {ULEB128_SREG, NO_OPR}, /* DW_CFA_def_cfa_register - register */
920Sstevel@tonic-gate {ULEB128, NO_OPR}, /* DW_CFA_def_cfa_offset - offset */
930Sstevel@tonic-gate {BLOCK, NO_OPR}, /* DW_CFA_def_cfa_expression - expression */
940Sstevel@tonic-gate {ULEB128, BLOCK}, /* DW_CFA_expression - reg, expression */
950Sstevel@tonic-gate {ULEB128, SLEB128_FAC}, /* DW_CFA_offset_extended_sf - reg, */
960Sstevel@tonic-gate /* data factored offset */
970Sstevel@tonic-gate {ULEB128_SREG, SLEB128_FAC}, /* DW_CFA_def_cfa_sf - reg, */
980Sstevel@tonic-gate /* data factored offset */
990Sstevel@tonic-gate {SLEB128_FAC, NO_OPR}, /* DW_CFA_def_cfa_offset_sf - */
1000Sstevel@tonic-gate /* data fctored offset */
1010Sstevel@tonic-gate {NO_OPR, NO_OPR},
1020Sstevel@tonic-gate {NO_OPR, NO_OPR},
1030Sstevel@tonic-gate {NO_OPR, NO_OPR},
1040Sstevel@tonic-gate {NO_OPR, NO_OPR},
1050Sstevel@tonic-gate {NO_OPR, NO_OPR},
1060Sstevel@tonic-gate {NO_OPR, NO_OPR},
1070Sstevel@tonic-gate {NO_OPR, NO_OPR},
1080Sstevel@tonic-gate {NO_OPR, NO_OPR},
1090Sstevel@tonic-gate {NO_OPR, NO_OPR},
1100Sstevel@tonic-gate {UNUM6_CFAC, NO_OPR}, /* DW_CFA_SUNW_advance_loc - */
1110Sstevel@tonic-gate /* code factored delta */
1120Sstevel@tonic-gate {UNUM6, ULEB128_FAC}, /* DW_CFA_SUNW_offset - reg */
1130Sstevel@tonic-gate /* data factored offset */
1140Sstevel@tonic-gate {UNUM6, NO_OPR} /* DW_CFA_SUNW_restore */
1150Sstevel@tonic-gate };
1160Sstevel@tonic-gate
1170Sstevel@tonic-gate uint64_t interpret_ops(void *data, void *data_end,
1180Sstevel@tonic-gate ptrdiff_t reloc, uint64_t current_loc, uint64_t pc,
1190Sstevel@tonic-gate struct register_state f_state[],
1200Sstevel@tonic-gate struct register_state f_start_state[],
1210Sstevel@tonic-gate int daf, int caf, int enc);
1220Sstevel@tonic-gate
1230Sstevel@tonic-gate /*
1240Sstevel@tonic-gate * The entry-point state of old_ctx defines the current
1250Sstevel@tonic-gate * suspended state of the caller (in new_ctx). If the old info
1260Sstevel@tonic-gate * will not be refered to again, old_ctx == new_ctx is OK
1270Sstevel@tonic-gate */
1280Sstevel@tonic-gate void
_Unw_Propagate_Registers(struct _Unwind_Context * old_ctx,struct _Unwind_Context * new_ctx)1290Sstevel@tonic-gate _Unw_Propagate_Registers(struct _Unwind_Context *old_ctx,
1300Sstevel@tonic-gate struct _Unwind_Context *new_ctx)
1310Sstevel@tonic-gate {
1320Sstevel@tonic-gate new_ctx->current_regs[SP_RSP] = old_ctx->cfa;
1330Sstevel@tonic-gate new_ctx->pc = old_ctx->ra;
1340Sstevel@tonic-gate new_ctx->current_regs[FP_RBP] = old_ctx->entry_regs[FP_RBP];
1350Sstevel@tonic-gate new_ctx->current_regs[GPR_RBX] = old_ctx->entry_regs[GPR_RBX];
1360Sstevel@tonic-gate new_ctx->current_regs[EIR_R12] = old_ctx->entry_regs[EIR_R12];
1370Sstevel@tonic-gate new_ctx->current_regs[EIR_R13] = old_ctx->entry_regs[EIR_R13];
1380Sstevel@tonic-gate new_ctx->current_regs[EIR_R14] = old_ctx->entry_regs[EIR_R14];
1390Sstevel@tonic-gate new_ctx->current_regs[EIR_R15] = old_ctx->entry_regs[EIR_R15];
1400Sstevel@tonic-gate }
1410Sstevel@tonic-gate
1420Sstevel@tonic-gate void
fix_cfa(struct _Unwind_Context * ctx,struct register_state * rs)1430Sstevel@tonic-gate fix_cfa(struct _Unwind_Context *ctx, struct register_state *rs)
1440Sstevel@tonic-gate {
1450Sstevel@tonic-gate switch (rs[CF_ADDR].rule) {
1460Sstevel@tonic-gate default:
147*6812Sraf ctx->cfa = 0;
1480Sstevel@tonic-gate break;
1490Sstevel@tonic-gate case register_rule: /* CFA = offset + source_reg */
1500Sstevel@tonic-gate ctx->cfa = (ctx->current_regs)[rs[CF_ADDR].source_reg] +
151*6812Sraf rs[CF_ADDR].offset;
1520Sstevel@tonic-gate break;
1530Sstevel@tonic-gate case constant_rule: /* CFA = offset */
1540Sstevel@tonic-gate ctx->cfa = rs[CF_ADDR].offset;
1550Sstevel@tonic-gate break;
1560Sstevel@tonic-gate case indirect_rule: /* CFA = *(offset + source_reg) */
1570Sstevel@tonic-gate ctx->cfa = *(uint64_t *)
158*6812Sraf (ctx->current_regs[rs[CF_ADDR].source_reg] +
159*6812Sraf rs[CF_ADDR].offset);
1600Sstevel@tonic-gate break;
1610Sstevel@tonic-gate }
1620Sstevel@tonic-gate ctx->entry_regs[SP_RSP] = ctx->cfa;
1630Sstevel@tonic-gate }
1640Sstevel@tonic-gate
1650Sstevel@tonic-gate void
fix_ra(struct _Unwind_Context * ctx,struct register_state * rs)1660Sstevel@tonic-gate fix_ra(struct _Unwind_Context *ctx, struct register_state *rs)
1670Sstevel@tonic-gate {
1680Sstevel@tonic-gate switch (rs[RET_ADD].rule) {
1690Sstevel@tonic-gate case undefined_rule:
1700Sstevel@tonic-gate default:
171*6812Sraf ctx->ra = 0;
1720Sstevel@tonic-gate break;
1730Sstevel@tonic-gate case offset_rule: /* RA = *(offset + CFA) */
1740Sstevel@tonic-gate ctx->ra = *(uint64_t *)(ctx->cfa + rs[RET_ADD].offset);
1750Sstevel@tonic-gate break;
1760Sstevel@tonic-gate case register_rule: /* RA = offset + source_reg */
1770Sstevel@tonic-gate ctx->ra = ctx->current_regs[rs[RET_ADD].source_reg] +
178*6812Sraf rs[RET_ADD].offset;
1790Sstevel@tonic-gate break;
1800Sstevel@tonic-gate case indirect_rule: /* RA = *(offset + source_reg) */
1810Sstevel@tonic-gate ctx->ra = *(uint64_t *)
182*6812Sraf (ctx->current_regs[rs[RET_ADD].source_reg] +
183*6812Sraf rs[RET_ADD].offset);
1840Sstevel@tonic-gate break;
1850Sstevel@tonic-gate }
1860Sstevel@tonic-gate }
1870Sstevel@tonic-gate
1880Sstevel@tonic-gate void
fix_reg(struct _Unwind_Context * ctx,struct register_state * rs,int index)1890Sstevel@tonic-gate fix_reg(struct _Unwind_Context *ctx, struct register_state *rs, int index)
1900Sstevel@tonic-gate {
1910Sstevel@tonic-gate switch (rs[index].rule) {
1920Sstevel@tonic-gate default:
1930Sstevel@tonic-gate ctx->entry_regs[index] = ctx->current_regs[index];
1940Sstevel@tonic-gate break;
1950Sstevel@tonic-gate case offset_rule: /* target_reg = *(offset + CFA) */
1960Sstevel@tonic-gate ctx->entry_regs[index] = *(uint64_t *)
197*6812Sraf (ctx->cfa + rs[index].offset);
1980Sstevel@tonic-gate break;
1990Sstevel@tonic-gate case is_offset_rule: /* target_reg = offset + CFA */
2000Sstevel@tonic-gate ctx->entry_regs[index] = ctx->cfa + rs[index].offset;
2010Sstevel@tonic-gate break;
2020Sstevel@tonic-gate case register_rule: /* target_reg = offset + source_reg */
2030Sstevel@tonic-gate ctx->entry_regs[index] =
204*6812Sraf ctx->current_regs[rs[index].source_reg] +
205*6812Sraf rs[index].offset;
2060Sstevel@tonic-gate break;
2070Sstevel@tonic-gate case constant_rule: /* target_reg = offset */
2080Sstevel@tonic-gate ctx->entry_regs[index] = rs[index].offset;
2090Sstevel@tonic-gate break;
2100Sstevel@tonic-gate case indirect_rule: /* target_reg = *(offset + source_reg) */
2110Sstevel@tonic-gate ctx->entry_regs[index] = *(uint64_t *)
212*6812Sraf (ctx->current_regs[rs[index].source_reg] +
213*6812Sraf rs[index].offset);
2140Sstevel@tonic-gate break;
2150Sstevel@tonic-gate }
2160Sstevel@tonic-gate }
2170Sstevel@tonic-gate
2180Sstevel@tonic-gate
2190Sstevel@tonic-gate /*
2200Sstevel@tonic-gate * Input: f->{cie_ops, cie_ops_end, fde_ops, fde_ops_end}
2210Sstevel@tonic-gate * + location of DWARF opcodes
2220Sstevel@tonic-gate * ctx->{current_regs, pc}
2230Sstevel@tonic-gate * + register values and pc at point of suspension
2240Sstevel@tonic-gate * Output: ctx->{entry_regs, cfa, ra}
2250Sstevel@tonic-gate * + register values when function was entered
2260Sstevel@tonic-gate * + Cannonical Frame Address
2270Sstevel@tonic-gate * + return address
2280Sstevel@tonic-gate */
2290Sstevel@tonic-gate uint64_t
_Unw_Rollback_Registers(struct eh_frame_fields * f,struct _Unwind_Context * ctx)2300Sstevel@tonic-gate _Unw_Rollback_Registers(struct eh_frame_fields *f,
2310Sstevel@tonic-gate struct _Unwind_Context *ctx)
2320Sstevel@tonic-gate {
2330Sstevel@tonic-gate /* GPRs, RET_ADD, and CF_ADDR */
2340Sstevel@tonic-gate struct register_state func_state[18];
2350Sstevel@tonic-gate struct register_state func_start_state[18];
2360Sstevel@tonic-gate struct register_state nop = { 0, undefined_rule, 0 };
2370Sstevel@tonic-gate int i;
2380Sstevel@tonic-gate uint64_t first_pc;
2390Sstevel@tonic-gate
2400Sstevel@tonic-gate if (f == 0) {
2410Sstevel@tonic-gate /*
2420Sstevel@tonic-gate * When no FDE we assume all routines have a frame pointer
2430Sstevel@tonic-gate * and pass back existing callee saves registers
2440Sstevel@tonic-gate */
2450Sstevel@tonic-gate if (ctx->current_regs[FP_RBP] < ctx->current_regs[SP_RSP]) {
2460Sstevel@tonic-gate ctx->cfa = 0;
2470Sstevel@tonic-gate ctx->ra = 0;
2480Sstevel@tonic-gate ctx->pc = 0;
2490Sstevel@tonic-gate return (0);
2500Sstevel@tonic-gate }
2510Sstevel@tonic-gate ctx->entry_regs[FP_RBP] = ((uint64_t *)
252*6812Sraf (ctx->current_regs[FP_RBP]))[0];
2530Sstevel@tonic-gate ctx->cfa = ctx->current_regs[FP_RBP] + 16;
2540Sstevel@tonic-gate ctx->entry_regs[SP_RSP] = ctx->cfa;
2550Sstevel@tonic-gate ctx->entry_regs[GPR_RBX] = ctx->current_regs[GPR_RBX];
2560Sstevel@tonic-gate ctx->entry_regs[EIR_R12] = ctx->current_regs[EIR_R12];
2570Sstevel@tonic-gate ctx->entry_regs[EIR_R13] = ctx->current_regs[EIR_R13];
2580Sstevel@tonic-gate ctx->entry_regs[EIR_R14] = ctx->current_regs[EIR_R14];
2590Sstevel@tonic-gate ctx->entry_regs[EIR_R15] = ctx->current_regs[EIR_R15];
2600Sstevel@tonic-gate ctx->ra = ((uint64_t *)ctx->cfa)[-1];
2610Sstevel@tonic-gate return (ctx->cfa);
2620Sstevel@tonic-gate }
2630Sstevel@tonic-gate
2640Sstevel@tonic-gate for (i = 0; i < 18; i++)
2650Sstevel@tonic-gate func_start_state[i] = nop;
2660Sstevel@tonic-gate first_pc = interpret_ops(f->cie_ops, f->cie_ops_end,
267*6812Sraf f->cie_reloc, ctx->func, ctx->pc, func_start_state, 0,
268*6812Sraf f->data_align, f->code_align, f->code_enc);
2690Sstevel@tonic-gate for (i = 0; i < 18; i++)
2700Sstevel@tonic-gate func_state[i] = func_start_state[i];
2710Sstevel@tonic-gate (void) interpret_ops(f->fde_ops, f->fde_ops_end,
272*6812Sraf f->fde_reloc, first_pc, ctx->pc, func_state, func_start_state,
273*6812Sraf f->data_align, f->code_align, f->code_enc);
2740Sstevel@tonic-gate
2750Sstevel@tonic-gate fix_cfa(ctx, func_state);
2760Sstevel@tonic-gate if (ctx->cfa < ctx->current_regs[SP_RSP]) {
2770Sstevel@tonic-gate ctx->cfa = 0;
2780Sstevel@tonic-gate ctx->ra = 0;
2790Sstevel@tonic-gate ctx->pc = 0;
2800Sstevel@tonic-gate return (0);
2810Sstevel@tonic-gate }
2820Sstevel@tonic-gate fix_ra(ctx, func_state);
2830Sstevel@tonic-gate fix_reg(ctx, func_state, GPR_RBX);
2840Sstevel@tonic-gate fix_reg(ctx, func_state, FP_RBP);
2850Sstevel@tonic-gate fix_reg(ctx, func_state, EIR_R12);
2860Sstevel@tonic-gate fix_reg(ctx, func_state, EIR_R13);
2870Sstevel@tonic-gate fix_reg(ctx, func_state, EIR_R14);
2880Sstevel@tonic-gate fix_reg(ctx, func_state, EIR_R15);
2890Sstevel@tonic-gate
2900Sstevel@tonic-gate return (ctx->cfa);
2910Sstevel@tonic-gate }
2920Sstevel@tonic-gate
2930Sstevel@tonic-gate /*
2940Sstevel@tonic-gate * remap two-bit opcodes into a separate range or grab eight-bit opcode
2950Sstevel@tonic-gate * and advance pointer past it.
2960Sstevel@tonic-gate */
2970Sstevel@tonic-gate static enum CFA_ops
separate_op(void ** pp)2980Sstevel@tonic-gate separate_op(void **pp)
2990Sstevel@tonic-gate {
3000Sstevel@tonic-gate uint8_t c = **((uint8_t **)pp);
3010Sstevel@tonic-gate
3020Sstevel@tonic-gate if (c & 0xc0) {
3030Sstevel@tonic-gate switch (c & 0xc0) {
3040Sstevel@tonic-gate case DW_CFA_advance_loc:
3050Sstevel@tonic-gate return (DW_CFA_SUNW_advance_loc);
3060Sstevel@tonic-gate case DW_CFA_offset:
3070Sstevel@tonic-gate return (DW_CFA_SUNW_offset);
3080Sstevel@tonic-gate case DW_CFA_restore:
3090Sstevel@tonic-gate return (DW_CFA_SUNW_restore);
3100Sstevel@tonic-gate }
3110Sstevel@tonic-gate } else {
3120Sstevel@tonic-gate *pp = (void *)((*(intptr_t *)pp) + 1);
3130Sstevel@tonic-gate }
3140Sstevel@tonic-gate return (c);
3150Sstevel@tonic-gate }
3160Sstevel@tonic-gate
3170Sstevel@tonic-gate static uint64_t
extractuleb(void ** datap)3180Sstevel@tonic-gate extractuleb(void **datap)
3190Sstevel@tonic-gate {
3200Sstevel@tonic-gate uint8_t *data = *(uint8_t **)datap;
3210Sstevel@tonic-gate uint64_t res = 0;
3220Sstevel@tonic-gate int more = 1;
3230Sstevel@tonic-gate int shift = 0;
3240Sstevel@tonic-gate int val;
3250Sstevel@tonic-gate
3260Sstevel@tonic-gate while (more) {
3270Sstevel@tonic-gate val = (*data) & 0x7f;
3280Sstevel@tonic-gate more = ((*data++) & 0x80) >> 7;
3290Sstevel@tonic-gate res = res | val << shift;
3300Sstevel@tonic-gate shift += 7;
3310Sstevel@tonic-gate }
3320Sstevel@tonic-gate *datap = (void *)data;
3330Sstevel@tonic-gate return (res);
3340Sstevel@tonic-gate }
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate static uint64_t
extractsleb(void ** datap)3370Sstevel@tonic-gate extractsleb(void** datap)
3380Sstevel@tonic-gate {
3390Sstevel@tonic-gate uint8_t *data = *datap;
3400Sstevel@tonic-gate int64_t res = 0;
3410Sstevel@tonic-gate int more = 1;
3420Sstevel@tonic-gate int shift = 0;
3430Sstevel@tonic-gate unsigned int val;
3440Sstevel@tonic-gate
3450Sstevel@tonic-gate while (more) {
3460Sstevel@tonic-gate val = (*data) & 0x7f;
3470Sstevel@tonic-gate more = ((*data++) & 0x80) >> 7;
3480Sstevel@tonic-gate res = res | val<< shift;
3490Sstevel@tonic-gate shift += 7;
3500Sstevel@tonic-gate }
3510Sstevel@tonic-gate *datap = (void*) data;
3520Sstevel@tonic-gate res = (res << (64 - shift)) >> (64 - shift);
3530Sstevel@tonic-gate return (res);
3540Sstevel@tonic-gate }
3550Sstevel@tonic-gate
3560Sstevel@tonic-gate static uint64_t get_encoded_val(void **datap, ptrdiff_t reloc, int enc);
3570Sstevel@tonic-gate
3580Sstevel@tonic-gate /*
3590Sstevel@tonic-gate * do all field extractions needed for CFA operands and encoded FDE
3600Sstevel@tonic-gate * fields
3610Sstevel@tonic-gate */
3620Sstevel@tonic-gate uint64_t
_Unw_get_val(void ** datap,ptrdiff_t reloc,enum operand_desc opr,int daf,int caf,int enc)3630Sstevel@tonic-gate _Unw_get_val(void **datap, ptrdiff_t reloc,
3640Sstevel@tonic-gate enum operand_desc opr, int daf, int caf, int enc)
3650Sstevel@tonic-gate {
3660Sstevel@tonic-gate intptr_t data = (intptr_t)*datap;
3670Sstevel@tonic-gate uint64_t res;
3680Sstevel@tonic-gate char *dp, *rp;
3690Sstevel@tonic-gate
3700Sstevel@tonic-gate switch (opr) {
3710Sstevel@tonic-gate case NO_OPR:
3720Sstevel@tonic-gate res = 0;
3730Sstevel@tonic-gate break;
3740Sstevel@tonic-gate case ULEB128_FAC:
3750Sstevel@tonic-gate return (daf * extractuleb(datap));
3760Sstevel@tonic-gate break;
3770Sstevel@tonic-gate case ULEB128:
3780Sstevel@tonic-gate return (extractuleb(datap));
3790Sstevel@tonic-gate break;
3800Sstevel@tonic-gate case ULEB128_SREG:
3810Sstevel@tonic-gate res = (uint64_t)(*((uint8_t *)data));
3820Sstevel@tonic-gate data += 1;
3830Sstevel@tonic-gate switch (res) {
3840Sstevel@tonic-gate /* verify that register is one which is being tracked */
3850Sstevel@tonic-gate case GPR_RBX:
3860Sstevel@tonic-gate case FP_RBP:
3870Sstevel@tonic-gate case SP_RSP:
3880Sstevel@tonic-gate case EIR_R12:
3890Sstevel@tonic-gate case EIR_R13:
3900Sstevel@tonic-gate case EIR_R14:
3910Sstevel@tonic-gate case EIR_R15:
3920Sstevel@tonic-gate break;
3930Sstevel@tonic-gate default:
3940Sstevel@tonic-gate res = BAD_REG;
3950Sstevel@tonic-gate break;
3960Sstevel@tonic-gate }
3970Sstevel@tonic-gate break;
3980Sstevel@tonic-gate case UNUM6:
3990Sstevel@tonic-gate res = (uint64_t)(0x3f & *((uint8_t *)data));
4000Sstevel@tonic-gate data += 1;
4010Sstevel@tonic-gate break;
4020Sstevel@tonic-gate case UNUM8:
4030Sstevel@tonic-gate res = (uint64_t)(*((uint8_t *)data));
4040Sstevel@tonic-gate data += 1;
4050Sstevel@tonic-gate break;
4060Sstevel@tonic-gate case UNUM16:
4070Sstevel@tonic-gate res = (uint64_t)(*((uint16_t *)data));
4080Sstevel@tonic-gate data += 2;
4090Sstevel@tonic-gate break;
4100Sstevel@tonic-gate case UNUM32:
4110Sstevel@tonic-gate res = (uint64_t)(*((uint32_t *)data));
4120Sstevel@tonic-gate data += 4;
4130Sstevel@tonic-gate break;
4140Sstevel@tonic-gate case UNUM6_CFAC:
4150Sstevel@tonic-gate res = caf * (uint64_t)(0x3f & *((uint8_t *)data));
4160Sstevel@tonic-gate data += 1;
4170Sstevel@tonic-gate break;
4180Sstevel@tonic-gate case UNUM8_CFAC:
4190Sstevel@tonic-gate res = caf * (uint64_t)(*((uint8_t *)data));
4200Sstevel@tonic-gate data += 1;
4210Sstevel@tonic-gate break;
4220Sstevel@tonic-gate case UNUM16_CFAC:
4230Sstevel@tonic-gate res = caf * (uint64_t)(*((uint16_t *)data));
4240Sstevel@tonic-gate data += 2;
4250Sstevel@tonic-gate break;
4260Sstevel@tonic-gate case UNUM32_CFAC:
4270Sstevel@tonic-gate res = caf * (uint64_t)(*((uint32_t *)data));
4280Sstevel@tonic-gate data += 4;
4290Sstevel@tonic-gate break;
4300Sstevel@tonic-gate case UNUM64:
4310Sstevel@tonic-gate res = (uint64_t)(*((uint64_t *)data));
4320Sstevel@tonic-gate data += 8;
4330Sstevel@tonic-gate break;
4340Sstevel@tonic-gate case SNUM8:
4350Sstevel@tonic-gate res = (uint64_t)(int64_t)(*((int8_t *)data));
4360Sstevel@tonic-gate data += 1;
4370Sstevel@tonic-gate break;
4380Sstevel@tonic-gate case SNUM16:
4390Sstevel@tonic-gate res = (uint64_t)(int64_t)(*((int16_t *)data));
4400Sstevel@tonic-gate data += 2;
4410Sstevel@tonic-gate break;
4420Sstevel@tonic-gate case SNUM32:
4430Sstevel@tonic-gate res = (uint64_t)(int64_t)(*((int32_t *)data));
4440Sstevel@tonic-gate data += 4;
4450Sstevel@tonic-gate break;
4460Sstevel@tonic-gate case SNUM64:
4470Sstevel@tonic-gate res = (uint64_t)(*((int64_t *)data));
4480Sstevel@tonic-gate data += 8;
4490Sstevel@tonic-gate break;
4500Sstevel@tonic-gate case SLEB128_FAC:
4510Sstevel@tonic-gate return (daf * extractsleb(datap));
4520Sstevel@tonic-gate break;
4530Sstevel@tonic-gate case SLEB128:
4540Sstevel@tonic-gate return (extractsleb(datap));
4550Sstevel@tonic-gate break;
4560Sstevel@tonic-gate case ZTSTRING:
4570Sstevel@tonic-gate /* max length of augmentation string is 4 */
4580Sstevel@tonic-gate rp = (char *)&res;
4590Sstevel@tonic-gate dp = (char *)data;
4600Sstevel@tonic-gate while (*rp++ = *dp++)
4610Sstevel@tonic-gate ;
4620Sstevel@tonic-gate data = (intptr_t)dp;
4630Sstevel@tonic-gate break;
4640Sstevel@tonic-gate case ADDR:
4650Sstevel@tonic-gate return (get_encoded_val(datap, reloc, enc));
4660Sstevel@tonic-gate break;
4670Sstevel@tonic-gate case SIZE:
4680Sstevel@tonic-gate return (get_encoded_val(datap, reloc, enc & 0x7));
4690Sstevel@tonic-gate case BLOCK:
4700Sstevel@tonic-gate res = 0; /* not implemented */
4710Sstevel@tonic-gate break;
4720Sstevel@tonic-gate }
4730Sstevel@tonic-gate *datap = (void*)data;
4740Sstevel@tonic-gate return (res);
4750Sstevel@tonic-gate }
4760Sstevel@tonic-gate
4770Sstevel@tonic-gate static uint64_t
get_encoded_val(void ** datap,ptrdiff_t reloc,int enc)4780Sstevel@tonic-gate get_encoded_val(void **datap, ptrdiff_t reloc, int enc)
4790Sstevel@tonic-gate {
4800Sstevel@tonic-gate int val = enc & 0xf;
4810Sstevel@tonic-gate int rel = (enc >> 4) & 0xf;
4820Sstevel@tonic-gate intptr_t loc = ((intptr_t)*datap) + reloc;
4830Sstevel@tonic-gate uint64_t res = 0;
4840Sstevel@tonic-gate
4850Sstevel@tonic-gate switch (val) {
4860Sstevel@tonic-gate case 0x01:
4870Sstevel@tonic-gate res = _Unw_get_val(datap, reloc, ULEB128, 1, 1, 0);
4880Sstevel@tonic-gate break;
4890Sstevel@tonic-gate case 0x2:
4900Sstevel@tonic-gate res = _Unw_get_val(datap, reloc, UNUM16, 1, 1, 0);
4910Sstevel@tonic-gate break;
4920Sstevel@tonic-gate case 0x3:
4930Sstevel@tonic-gate res = _Unw_get_val(datap, reloc, UNUM32, 1, 1, 0);
4940Sstevel@tonic-gate break;
4950Sstevel@tonic-gate case 0x04:
4960Sstevel@tonic-gate res = _Unw_get_val(datap, reloc, UNUM64, 1, 1, 0);
4970Sstevel@tonic-gate break;
4980Sstevel@tonic-gate case 0x09:
4990Sstevel@tonic-gate res = _Unw_get_val(datap, reloc, SLEB128, 1, 1, 0);
5000Sstevel@tonic-gate break;
5010Sstevel@tonic-gate case 0x0a:
5020Sstevel@tonic-gate res = _Unw_get_val(datap, reloc, SNUM16, 1, 1, 0);
5030Sstevel@tonic-gate break;
5040Sstevel@tonic-gate case 0x0b:
5050Sstevel@tonic-gate res = _Unw_get_val(datap, reloc, SNUM32, 1, 1, 0);
5060Sstevel@tonic-gate break;
5070Sstevel@tonic-gate case 0x0c:
5080Sstevel@tonic-gate res = _Unw_get_val(datap, reloc, SNUM64, 1, 1, 0);
5090Sstevel@tonic-gate break;
5100Sstevel@tonic-gate }
5110Sstevel@tonic-gate
5120Sstevel@tonic-gate switch (rel) {
5130Sstevel@tonic-gate case 0:
5140Sstevel@tonic-gate break;
5150Sstevel@tonic-gate case 1:
5160Sstevel@tonic-gate if (res != 0)
5170Sstevel@tonic-gate res += loc;
5180Sstevel@tonic-gate break;
5190Sstevel@tonic-gate default:
5200Sstevel@tonic-gate /* remainder not implemented */
5210Sstevel@tonic-gate break;
5220Sstevel@tonic-gate }
5230Sstevel@tonic-gate return (res);
5240Sstevel@tonic-gate }
5250Sstevel@tonic-gate
5260Sstevel@tonic-gate
5270Sstevel@tonic-gate int interpret_op(void **datap, ptrdiff_t reloc,
5280Sstevel@tonic-gate uint64_t *reached_pc_p, uint64_t pc,
5290Sstevel@tonic-gate struct register_state f_state[],
5300Sstevel@tonic-gate struct register_state f_start_state[],
5310Sstevel@tonic-gate int daf, int caf, int enc);
5320Sstevel@tonic-gate
5330Sstevel@tonic-gate uint64_t
interpret_ops(void * data,void * data_end,ptrdiff_t reloc,uint64_t start_pc,uint64_t pc,struct register_state f_state[],struct register_state f_start_state[],int daf,int caf,int enc)5340Sstevel@tonic-gate interpret_ops(void *data, void *data_end,
5350Sstevel@tonic-gate ptrdiff_t reloc,
5360Sstevel@tonic-gate uint64_t start_pc, uint64_t pc,
5370Sstevel@tonic-gate struct register_state f_state[],
5380Sstevel@tonic-gate struct register_state f_start_state[],
5390Sstevel@tonic-gate int daf, int caf, int enc)
5400Sstevel@tonic-gate {
5410Sstevel@tonic-gate void *d = data;
5420Sstevel@tonic-gate uint64_t reached_pc = start_pc;
5430Sstevel@tonic-gate
5440Sstevel@tonic-gate while (d < data_end) {
5450Sstevel@tonic-gate if (interpret_op(&d, reloc, &reached_pc, pc,
5460Sstevel@tonic-gate f_state, f_start_state, daf, caf, enc))
5470Sstevel@tonic-gate break;
5480Sstevel@tonic-gate }
5490Sstevel@tonic-gate return (reached_pc);
5500Sstevel@tonic-gate }
5510Sstevel@tonic-gate
5520Sstevel@tonic-gate int
interpret_op(void ** datap,ptrdiff_t reloc,uint64_t * reached_pc_p,uint64_t pc,struct register_state f_state[],struct register_state f_start_state[],int daf,int caf,int enc)5530Sstevel@tonic-gate interpret_op(void **datap, ptrdiff_t reloc,
5540Sstevel@tonic-gate uint64_t *reached_pc_p, uint64_t pc,
5550Sstevel@tonic-gate struct register_state f_state[],
5560Sstevel@tonic-gate struct register_state f_start_state[],
5570Sstevel@tonic-gate int daf, int caf, int enc)
5580Sstevel@tonic-gate {
5590Sstevel@tonic-gate enum CFA_ops op = separate_op(datap);
5600Sstevel@tonic-gate enum operand_desc opr1 = (cfa_operations[op]).op1;
5610Sstevel@tonic-gate enum operand_desc opr2 = (cfa_operations[op]).op2;
5620Sstevel@tonic-gate
5630Sstevel@tonic-gate uint64_t val1 = _Unw_get_val(datap, reloc, opr1, daf, caf, enc);
5640Sstevel@tonic-gate uint64_t val2 = _Unw_get_val(datap, reloc, opr2, daf, caf, enc);
5650Sstevel@tonic-gate if ((opr1 == ULEB128_SREG && val1 == BAD_REG) ||
5660Sstevel@tonic-gate (opr2 == ULEB128_SREG && val2 == BAD_REG))
5670Sstevel@tonic-gate return (0);
5680Sstevel@tonic-gate switch (op) {
5690Sstevel@tonic-gate case DW_CFA_nop:
5700Sstevel@tonic-gate break;
5710Sstevel@tonic-gate case DW_CFA_set_loc:
5720Sstevel@tonic-gate if (val1 > pc)
5730Sstevel@tonic-gate return (1);
5740Sstevel@tonic-gate *reached_pc_p = val1;
5750Sstevel@tonic-gate break;
5760Sstevel@tonic-gate case DW_CFA_advance_loc1:
5770Sstevel@tonic-gate case DW_CFA_advance_loc2:
5780Sstevel@tonic-gate case DW_CFA_advance_loc4:
5790Sstevel@tonic-gate if (*reached_pc_p + val1 > pc)
5800Sstevel@tonic-gate return (1);
5810Sstevel@tonic-gate *reached_pc_p += val1;
5820Sstevel@tonic-gate break;
5830Sstevel@tonic-gate case DW_CFA_offset_extended:
5840Sstevel@tonic-gate f_state[val1].rule = offset_rule;
5850Sstevel@tonic-gate f_state[val1].source_reg = CF_ADDR;
5860Sstevel@tonic-gate f_state[val1].offset = val2;
5870Sstevel@tonic-gate break;
5880Sstevel@tonic-gate case DW_CFA_restore_extended:
5890Sstevel@tonic-gate if (f_start_state != 0)
5900Sstevel@tonic-gate f_state[val1] = f_start_state[val1];
5910Sstevel@tonic-gate break;
5920Sstevel@tonic-gate case DW_CFA_undefined:
5930Sstevel@tonic-gate f_state[val1].rule = undefined_rule;
5940Sstevel@tonic-gate break;
5950Sstevel@tonic-gate case DW_CFA_same_value:
5960Sstevel@tonic-gate f_state[val1].rule = same_value_rule;
5970Sstevel@tonic-gate break;
5980Sstevel@tonic-gate case DW_CFA_register:
5990Sstevel@tonic-gate f_state[val1].rule = register_rule;
6000Sstevel@tonic-gate f_state[val1].source_reg = val2;
6010Sstevel@tonic-gate f_state[val1].offset = 0;
6020Sstevel@tonic-gate break;
6030Sstevel@tonic-gate case DW_CFA_remember_state:
6040Sstevel@tonic-gate break;
6050Sstevel@tonic-gate case DW_CFA_restore_state:
6060Sstevel@tonic-gate break;
6070Sstevel@tonic-gate case DW_CFA_def_cfa:
6080Sstevel@tonic-gate f_state[CF_ADDR].rule = register_rule;
6090Sstevel@tonic-gate f_state[CF_ADDR].source_reg = val1;
6100Sstevel@tonic-gate f_state[CF_ADDR].offset = val2;
6110Sstevel@tonic-gate break;
6120Sstevel@tonic-gate case DW_CFA_def_cfa_register:
6130Sstevel@tonic-gate f_state[CF_ADDR].source_reg = val1;
6140Sstevel@tonic-gate break;
6150Sstevel@tonic-gate case DW_CFA_def_cfa_offset:
6160Sstevel@tonic-gate f_state[CF_ADDR].offset = val1;
6170Sstevel@tonic-gate break;
6180Sstevel@tonic-gate case DW_CFA_def_cfa_expression:
6190Sstevel@tonic-gate break;
6200Sstevel@tonic-gate case DW_CFA_expression:
6210Sstevel@tonic-gate break;
6220Sstevel@tonic-gate case DW_CFA_offset_extended_sf:
6230Sstevel@tonic-gate f_state[val1].rule = offset_rule;
6240Sstevel@tonic-gate f_state[val1].source_reg = CF_ADDR;
6250Sstevel@tonic-gate f_state[val1].offset = val2;
6260Sstevel@tonic-gate break;
6270Sstevel@tonic-gate case DW_CFA_def_cfa_sf:
6280Sstevel@tonic-gate f_state[CF_ADDR].rule = register_rule;
6290Sstevel@tonic-gate f_state[CF_ADDR].source_reg = val1;
6300Sstevel@tonic-gate f_state[CF_ADDR].offset = val2;
6310Sstevel@tonic-gate break;
6320Sstevel@tonic-gate case DW_CFA_def_cfa_offset_sf:
6330Sstevel@tonic-gate f_state[CF_ADDR].offset = val1;
6340Sstevel@tonic-gate break;
6350Sstevel@tonic-gate case DW_CFA_SUNW_advance_loc:
6360Sstevel@tonic-gate if (*reached_pc_p + val1 > pc)
6370Sstevel@tonic-gate return (1);
6380Sstevel@tonic-gate *reached_pc_p += val1;
6390Sstevel@tonic-gate break;
6400Sstevel@tonic-gate case DW_CFA_SUNW_offset:
6410Sstevel@tonic-gate f_state[val1].rule = offset_rule;
6420Sstevel@tonic-gate f_state[val1].source_reg = CF_ADDR;
6430Sstevel@tonic-gate f_state[val1].offset = val2;
6440Sstevel@tonic-gate break;
6450Sstevel@tonic-gate case DW_CFA_SUNW_restore:
6460Sstevel@tonic-gate if (f_start_state != 0)
6470Sstevel@tonic-gate f_state[val1] = f_start_state[val1];
6480Sstevel@tonic-gate break;
6490Sstevel@tonic-gate }
6500Sstevel@tonic-gate return (0);
6510Sstevel@tonic-gate }
652