xref: /illumos-gate/usr/src/cmd/sgs/elfdump/common/dwarf.c (revision 37915d86)
17e16fca0SAli Bahrami /*
27e16fca0SAli Bahrami  * CDDL HEADER START
37e16fca0SAli Bahrami  *
47e16fca0SAli Bahrami  * The contents of this file are subject to the terms of the
57e16fca0SAli Bahrami  * Common Development and Distribution License (the "License").
67e16fca0SAli Bahrami  * You may not use this file except in compliance with the License.
77e16fca0SAli Bahrami  *
87e16fca0SAli Bahrami  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97e16fca0SAli Bahrami  * or http://www.opensolaris.org/os/licensing.
107e16fca0SAli Bahrami  * See the License for the specific language governing permissions
117e16fca0SAli Bahrami  * and limitations under the License.
127e16fca0SAli Bahrami  *
137e16fca0SAli Bahrami  * When distributing Covered Code, include this CDDL HEADER in each
147e16fca0SAli Bahrami  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157e16fca0SAli Bahrami  * If applicable, add the following below this CDDL HEADER, with the
167e16fca0SAli Bahrami  * fields enclosed by brackets "[]" replaced with your own identifying
177e16fca0SAli Bahrami  * information: Portions Copyright [yyyy] [name of copyright owner]
187e16fca0SAli Bahrami  *
197e16fca0SAli Bahrami  * CDDL HEADER END
207e16fca0SAli Bahrami  */
217e16fca0SAli Bahrami 
227e16fca0SAli Bahrami /*
237e16fca0SAli Bahrami  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247e16fca0SAli Bahrami  * Use is subject to license terms.
257e16fca0SAli Bahrami  */
267e16fca0SAli Bahrami 
277e16fca0SAli Bahrami #include	<_libelf.h>
287e16fca0SAli Bahrami #include	<dwarf.h>
297e16fca0SAli Bahrami #include	<stdio.h>
307e16fca0SAli Bahrami #include	<unistd.h>
317e16fca0SAli Bahrami #include	<errno.h>
327e16fca0SAli Bahrami #include	<strings.h>
337e16fca0SAli Bahrami #include	<debug.h>
347e16fca0SAli Bahrami #include	<conv.h>
357e16fca0SAli Bahrami #include	<msg.h>
367e16fca0SAli Bahrami #include	<_elfdump.h>
377e16fca0SAli Bahrami 
387e16fca0SAli Bahrami 
397e16fca0SAli Bahrami /*
407e16fca0SAli Bahrami  * Data from eh_frame section used by dump_cfi()
417e16fca0SAli Bahrami  */
427e16fca0SAli Bahrami typedef struct {
43*37915d86SRichard Lowe 	const char	*file;
44*37915d86SRichard Lowe 	const char	*sh_name;
457e16fca0SAli Bahrami 	Half		e_machine;	/* ehdr->e_machine */
467e16fca0SAli Bahrami 	uchar_t		*e_ident;	/* ehdr->e_ident */
477e16fca0SAli Bahrami 	uint64_t	sh_addr;	/* Address of eh_frame section */
487e16fca0SAli Bahrami 	int		do_swap;	/* True if object and system byte */
497e16fca0SAli Bahrami 					/*	order differs */
507e16fca0SAli Bahrami 	int		cieRflag;	/* R flag from current CIE */
517e16fca0SAli Bahrami 	uint64_t	ciecalign;	/* CIE code align factor */
527e16fca0SAli Bahrami 	int64_t		ciedalign;	/* CIE data align factor */
537e16fca0SAli Bahrami 	uint64_t	fdeinitloc;	/* FDE initial location */
54965630c1SRichard Lowe 	uint64_t	gotaddr;	/* Address of the GOT */
557e16fca0SAli Bahrami } dump_cfi_state_t;
567e16fca0SAli Bahrami 
577e16fca0SAli Bahrami 
587e16fca0SAli Bahrami /*
597e16fca0SAli Bahrami  * Extract an unsigned integer value from an .eh_frame section, converting it
607e16fca0SAli Bahrami  * from its native byte order to that of the running machine if necessary.
617e16fca0SAli Bahrami  *
627e16fca0SAli Bahrami  * entry:
637e16fca0SAli Bahrami  *	data - Base address from which to extract datum
647e16fca0SAli Bahrami  *	ndx - Address of variable giving index to start byte in data.
657e16fca0SAli Bahrami  *	size - # of bytes in datum. Must be one of: 1, 2, 4, 8
667e16fca0SAli Bahrami  *	do_swap - True if the data is in a different byte order than that
677e16fca0SAli Bahrami  *		of the host system.
687e16fca0SAli Bahrami  *
697e16fca0SAli Bahrami  * exit:
707e16fca0SAli Bahrami  *	*ndx is incremented by the size of the extracted datum.
717e16fca0SAli Bahrami  *
727e16fca0SAli Bahrami  *	The requested datum is extracted, byte swapped if necessary,
737e16fca0SAli Bahrami  *	and returned.
747e16fca0SAli Bahrami  */
75*37915d86SRichard Lowe static dwarf_error_t
dwarf_extract_uint(uchar_t * data,size_t len,uint64_t * ndx,int size,int do_swap,uint64_t * ret)76*37915d86SRichard Lowe dwarf_extract_uint(uchar_t *data, size_t len, uint64_t *ndx, int size,
77*37915d86SRichard Lowe     int do_swap, uint64_t *ret)
787e16fca0SAli Bahrami {
79*37915d86SRichard Lowe 	if (((*ndx + size) > len) ||
80*37915d86SRichard Lowe 	    ((*ndx + size) < *ndx))
81*37915d86SRichard Lowe 		return (DW_OVERFLOW);
82*37915d86SRichard Lowe 
837e16fca0SAli Bahrami 	switch (size) {
847e16fca0SAli Bahrami 	case 1:
85*37915d86SRichard Lowe 		*ret = (data[(*ndx)++]);
86*37915d86SRichard Lowe 		return (DW_SUCCESS);
877e16fca0SAli Bahrami 	case 2:
887e16fca0SAli Bahrami 		{
897e16fca0SAli Bahrami 			Half	r;
907e16fca0SAli Bahrami 			uchar_t	*p = (uchar_t *)&r;
917e16fca0SAli Bahrami 
927e16fca0SAli Bahrami 			data += *ndx;
937e16fca0SAli Bahrami 			if (do_swap)
947e16fca0SAli Bahrami 				UL_ASSIGN_BSWAP_HALF(p, data);
957e16fca0SAli Bahrami 			else
967e16fca0SAli Bahrami 				UL_ASSIGN_HALF(p, data);
977e16fca0SAli Bahrami 
987e16fca0SAli Bahrami 			(*ndx) += 2;
99*37915d86SRichard Lowe 			*ret = r;
100*37915d86SRichard Lowe 			return (DW_SUCCESS);
1017e16fca0SAli Bahrami 		}
1027e16fca0SAli Bahrami 	case 4:
1037e16fca0SAli Bahrami 		{
1047e16fca0SAli Bahrami 			Word	r;
1057e16fca0SAli Bahrami 			uchar_t *p = (uchar_t *)&r;
1067e16fca0SAli Bahrami 
1077e16fca0SAli Bahrami 			data += *ndx;
1087e16fca0SAli Bahrami 			if (do_swap)
1097e16fca0SAli Bahrami 				UL_ASSIGN_BSWAP_WORD(p, data);
1107e16fca0SAli Bahrami 			else
1117e16fca0SAli Bahrami 				UL_ASSIGN_WORD(p, data);
1127e16fca0SAli Bahrami 
1137e16fca0SAli Bahrami 			(*ndx) += 4;
114*37915d86SRichard Lowe 			*ret = r;
115*37915d86SRichard Lowe 			return (DW_SUCCESS);
1167e16fca0SAli Bahrami 		}
1177e16fca0SAli Bahrami 
1187e16fca0SAli Bahrami 	case 8:
1197e16fca0SAli Bahrami 		{
1207e16fca0SAli Bahrami 			uint64_t	r;
1217e16fca0SAli Bahrami 			uchar_t		*p = (uchar_t *)&r;
1227e16fca0SAli Bahrami 
1237e16fca0SAli Bahrami 			data += *ndx;
1247e16fca0SAli Bahrami 			if (do_swap)
1257e16fca0SAli Bahrami 				UL_ASSIGN_BSWAP_LWORD(p, data);
1267e16fca0SAli Bahrami 			else
1277e16fca0SAli Bahrami 				UL_ASSIGN_LWORD(p, data);
1287e16fca0SAli Bahrami 
1297e16fca0SAli Bahrami 			(*ndx) += 8;
130*37915d86SRichard Lowe 			*ret = r;
131*37915d86SRichard Lowe 			return (DW_SUCCESS);
1327e16fca0SAli Bahrami 		}
133*37915d86SRichard Lowe 	default:
134*37915d86SRichard Lowe 		return (DW_BAD_ENCODING);
1357e16fca0SAli Bahrami 	}
1367e16fca0SAli Bahrami 
137*37915d86SRichard Lowe 	/* NOTREACHED */
1387e16fca0SAli Bahrami }
1397e16fca0SAli Bahrami 
1407e16fca0SAli Bahrami /*
1417e16fca0SAli Bahrami  * Map a DWARF register constant to the machine register name it
1427e16fca0SAli Bahrami  * corresponds to, formatting the result into buf.
1437e16fca0SAli Bahrami  *
1447e16fca0SAli Bahrami  * The assignment of DWARF register numbers is part of the system
1457e16fca0SAli Bahrami  * specific ABI for each platform.
1467e16fca0SAli Bahrami  *
1477e16fca0SAli Bahrami  * entry:
1487e16fca0SAli Bahrami  *	regno - DWARF register number
1497e16fca0SAli Bahrami  *	mach - ELF machine code for platform
1507e16fca0SAli Bahrami  *	buf, bufsize - Buffer to receive the formatted result string
1517e16fca0SAli Bahrami  *
1527e16fca0SAli Bahrami  * exit:
1537e16fca0SAli Bahrami  *	The results are formatted into buf, and buf is returned.
1547e16fca0SAli Bahrami  *	If the generated output would exceed the size of the buffer
1557e16fca0SAli Bahrami  *	provided, it will be clipped to fit.
1567e16fca0SAli Bahrami  */
1577e16fca0SAli Bahrami static const char *
dwarf_regname(Half mach,int regno,char * buf,size_t bufsize)1587e16fca0SAli Bahrami dwarf_regname(Half mach, int regno, char *buf, size_t bufsize)
1597e16fca0SAli Bahrami {
1607e16fca0SAli Bahrami 	Conv_inv_buf_t	inv_buf;
1617e16fca0SAli Bahrami 	const char	*name;
1627e16fca0SAli Bahrami 	int		good_name;
1637e16fca0SAli Bahrami 
1647e16fca0SAli Bahrami 	name = conv_dwarf_regname(mach, regno, 0, &good_name, &inv_buf);
1657e16fca0SAli Bahrami 
1667e16fca0SAli Bahrami 	/*
1677e16fca0SAli Bahrami 	 * If there is a good mnemonic machine name for the register,
1687e16fca0SAli Bahrami 	 * format the result as 'r# (mnemonic)'.  If there is no good
1697e16fca0SAli Bahrami 	 * name for it, then simply format the dwarf name as 'r#'.
1707e16fca0SAli Bahrami 	 */
1717e16fca0SAli Bahrami 	if (good_name)
1727e16fca0SAli Bahrami 		(void) snprintf(buf, bufsize, MSG_ORIG(MSG_REG_FMT_NAME),
1737e16fca0SAli Bahrami 		    regno, name);
1747e16fca0SAli Bahrami 	else
1757e16fca0SAli Bahrami 		(void) snprintf(buf, bufsize, MSG_ORIG(MSG_REG_FMT_BASIC),
1767e16fca0SAli Bahrami 		    regno);
1777e16fca0SAli Bahrami 
1787e16fca0SAli Bahrami 	return (buf);
1797e16fca0SAli Bahrami }
1807e16fca0SAli Bahrami 
1817e16fca0SAli Bahrami 
1827e16fca0SAli Bahrami /*
1837e16fca0SAli Bahrami  * Decode eh_frame Call Frame Instructions, printing each one on a
1847e16fca0SAli Bahrami  * separate line.
1857e16fca0SAli Bahrami  *
1867e16fca0SAli Bahrami  * entry:
1877e16fca0SAli Bahrami  *	data - Address of base of eh_frame section being processed
1887e16fca0SAli Bahrami  *	off - Offset of current FDE within eh_frame
1897e16fca0SAli Bahrami  *	ndx - Index of current position within current FDE
190*37915d86SRichard Lowe  *	len - Length of FDE
1917e16fca0SAli Bahrami  *	state - Object, CIE, and FDE state for current request
1927e16fca0SAli Bahrami  *	msg - Header message to issue before producing output.
1937e16fca0SAli Bahrami  *	indent - # of indentation characters issued for each line of output.
1947e16fca0SAli Bahrami  *
1957e16fca0SAli Bahrami  * exit:
1967e16fca0SAli Bahrami  *	The Call Frame Instructions have been decoded and printed.
1977e16fca0SAli Bahrami  *
1987e16fca0SAli Bahrami  *	*ndx has been incremented to contain the index of the next
1997e16fca0SAli Bahrami  *		byte of data to be processed in eh_frame.
2007e16fca0SAli Bahrami  *
2017e16fca0SAli Bahrami  * note:
2027e16fca0SAli Bahrami  *	The format of Call Frame Instructions in .eh_frame sections is based
2037e16fca0SAli Bahrami  *	on the DWARF specification.
2047e16fca0SAli Bahrami  */
2057e16fca0SAli Bahrami static void
dump_cfi(uchar_t * data,uint64_t off,uint64_t * ndx,uint_t len,dump_cfi_state_t * state,const char * msg,int indent)2067e16fca0SAli Bahrami dump_cfi(uchar_t *data, uint64_t off, uint64_t *ndx, uint_t len,
2077e16fca0SAli Bahrami     dump_cfi_state_t *state, const char *msg, int indent)
2087e16fca0SAli Bahrami {
2097e16fca0SAli Bahrami 	/*
2107e16fca0SAli Bahrami 	 * We use %*s%s to insert leading whitespace and the op name.
2117e16fca0SAli Bahrami 	 * PREFIX supplies these arguments.
2127e16fca0SAli Bahrami 	 */
2137e16fca0SAli Bahrami #define	PREFIX	indent, MSG_ORIG(MSG_STR_EMPTY), opname
2147e16fca0SAli Bahrami 
2157e16fca0SAli Bahrami 	/* Hide boilerplate clutter in calls to dwarf_regname() */
2167e16fca0SAli Bahrami #define	REGNAME(_rnum, _buf) \
2177e16fca0SAli Bahrami 	dwarf_regname(state->e_machine, _rnum, _buf, sizeof (_buf))
2187e16fca0SAli Bahrami 
2197e16fca0SAli Bahrami 	/* Extract the lower 6 bits from an op code */
2207e16fca0SAli Bahrami #define	LOW_OP(_op) (_op & 0x3f)
2217e16fca0SAli Bahrami 
2227e16fca0SAli Bahrami 	char		rbuf1[32], rbuf2[32];
2237e16fca0SAli Bahrami 	Conv_inv_buf_t	inv_buf;
2247e16fca0SAli Bahrami 	uchar_t		op;
2257e16fca0SAli Bahrami 	const char	*opname;
2267e16fca0SAli Bahrami 	uint64_t	oper1, oper2, cur_pc;
2277e16fca0SAli Bahrami 	int64_t		soper;
2287e16fca0SAli Bahrami 	const char	*loc_str;
2297e16fca0SAli Bahrami 	int		i;
2307e16fca0SAli Bahrami 
2317e16fca0SAli Bahrami 	dbg_print(0, msg);
2327e16fca0SAli Bahrami 
2337e16fca0SAli Bahrami 	/*
2347e16fca0SAli Bahrami 	 * In a CIE/FDE, the length field does not include it's own
2357e16fca0SAli Bahrami 	 * size. Hence, the value passed in is 4 less than the index
2367e16fca0SAli Bahrami 	 * of the actual final location.
2377e16fca0SAli Bahrami 	 */
2387e16fca0SAli Bahrami 	len += 4;
2397e16fca0SAli Bahrami 
2407e16fca0SAli Bahrami 	/*
2417e16fca0SAli Bahrami 	 * There is a concept of the 'current location', which is the PC
2427e16fca0SAli Bahrami 	 * to which the current item applies. It starts out set to the
2437e16fca0SAli Bahrami 	 * FDE initial location, and can be set or incremented by
2447e16fca0SAli Bahrami 	 * various OP codes. cur_pc is used to track this.
2457e16fca0SAli Bahrami 	 *
2467e16fca0SAli Bahrami 	 * We want to use 'initloc' in the output the first time the location
2477e16fca0SAli Bahrami 	 * is referenced, and then switch to 'loc' for subsequent references.
2487e16fca0SAli Bahrami 	 * loc_str is used to manage that.
2497e16fca0SAli Bahrami 	 */
2507e16fca0SAli Bahrami 	cur_pc = state->fdeinitloc;
2517e16fca0SAli Bahrami 	loc_str = MSG_ORIG(MSG_STR_INITLOC);
2527e16fca0SAli Bahrami 
2537e16fca0SAli Bahrami 	while (*ndx < len) {
2547e16fca0SAli Bahrami 		/*
2557e16fca0SAli Bahrami 		 * The first byte contains the primary op code in the top
2567e16fca0SAli Bahrami 		 * 2 bits, so there are 4 of them. Primary OP code
2577e16fca0SAli Bahrami 		 * 0 uses the lower 6 bits to specify a sub-opcode, allowing
2587e16fca0SAli Bahrami 		 * for 64 of them. The other 3 primary op codes use the
2597e16fca0SAli Bahrami 		 * lower 6 bits to hold an operand (a register #, or value).
2607e16fca0SAli Bahrami 		 *
2617e16fca0SAli Bahrami 		 * Check the primary OP code. If it's 1-3, handle it
2627e16fca0SAli Bahrami 		 * and move to the next loop iteration. For OP code 0,
2637e16fca0SAli Bahrami 		 * fall through to decode the sub-code.
2647e16fca0SAli Bahrami 		 */
2657e16fca0SAli Bahrami 		op = data[off + (*ndx)++];
2667e16fca0SAli Bahrami 		opname = conv_dwarf_cfa(op, 0, &inv_buf);
2677e16fca0SAli Bahrami 		switch (op >> 6) {
2687e16fca0SAli Bahrami 		case 0x1:		/* v2: DW_CFA_advance_loc, delta */
2697e16fca0SAli Bahrami 			oper1 = state->ciecalign * LOW_OP(op);
2707e16fca0SAli Bahrami 			cur_pc += oper1;
2717e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX,
2727e16fca0SAli Bahrami 			    loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc));
2737e16fca0SAli Bahrami 			loc_str = MSG_ORIG(MSG_STR_LOC);
2747e16fca0SAli Bahrami 			continue;
2757e16fca0SAli Bahrami 
2767e16fca0SAli Bahrami 		case 0x2:		/* v2: DW_CFA_offset, reg, offset */
277*37915d86SRichard Lowe 			if (uleb_extract(&data[off], ndx, len, &oper1) ==
278*37915d86SRichard Lowe 			    DW_OVERFLOW) {
279*37915d86SRichard Lowe 				(void) fprintf(stderr,
280*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
281*37915d86SRichard Lowe 				    state->file, state->sh_name);
282*37915d86SRichard Lowe 				return;
283*37915d86SRichard Lowe 			}
284*37915d86SRichard Lowe 
285*37915d86SRichard Lowe 			oper1 *= state->ciedalign;
2867e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
287*37915d86SRichard Lowe 			    REGNAME(LOW_OP(op), rbuf1), EC_XWORD(oper1));
2887e16fca0SAli Bahrami 			continue;
2897e16fca0SAli Bahrami 
2907e16fca0SAli Bahrami 		case 0x3:		/* v2: DW_CFA_restore, reg */
2917e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_CFA_REG), PREFIX,
2927e16fca0SAli Bahrami 			    REGNAME(LOW_OP(op), rbuf1));
2937e16fca0SAli Bahrami 			continue;
2947e16fca0SAli Bahrami 		}
2957e16fca0SAli Bahrami 
2967e16fca0SAli Bahrami 		/*
2977e16fca0SAli Bahrami 		 * If we're here, the high order 2 bits are 0. The low 6 bits
2987e16fca0SAli Bahrami 		 * specify a sub-opcode defining the operation.
2997e16fca0SAli Bahrami 		 */
3007e16fca0SAli Bahrami 		switch (op) {
3017e16fca0SAli Bahrami 		case 0x00:		/* v2: DW_CFA_nop */
3027e16fca0SAli Bahrami 			/*
3037e16fca0SAli Bahrami 			 * No-ops are used to fill unused space required
3047e16fca0SAli Bahrami 			 * for alignment. It is common for there to be
3057e16fca0SAli Bahrami 			 * multiple adjacent nops. It saves space to report
3067e16fca0SAli Bahrami 			 * them all with a single line of output.
3077e16fca0SAli Bahrami 			 */
3087e16fca0SAli Bahrami 			for (i = 1;
3097e16fca0SAli Bahrami 			    (*ndx < len) && (data[off + *ndx] == 0);
3107e16fca0SAli Bahrami 			    i++, (*ndx)++)
3117e16fca0SAli Bahrami 				;
3127e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_CFA_SIMPLEREP), PREFIX, i);
3137e16fca0SAli Bahrami 			break;
3147e16fca0SAli Bahrami 
3157e16fca0SAli Bahrami 		case 0x0a:		/* v2: DW_CFA_remember_state */
3167e16fca0SAli Bahrami 		case 0x0b:		/* v2: DW_CFA_restore_state */
3177e16fca0SAli Bahrami 		case 0x2d:		/* GNU: DW_CFA_GNU_window_save */
3187e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_CFA_SIMPLE), PREFIX);
3197e16fca0SAli Bahrami 			break;
3207e16fca0SAli Bahrami 
3217e16fca0SAli Bahrami 		case 0x01:		/* v2: DW_CFA_set_loc, address */
322*37915d86SRichard Lowe 			switch (dwarf_ehe_extract(&data[off], len, ndx,
323*37915d86SRichard Lowe 			    &cur_pc, state->cieRflag, state->e_ident, B_FALSE,
324*37915d86SRichard Lowe 			    state->sh_addr, off + *ndx, state->gotaddr)) {
325*37915d86SRichard Lowe 			case DW_OVERFLOW:
326*37915d86SRichard Lowe 				(void) fprintf(stderr,
327*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
328*37915d86SRichard Lowe 				    state->file, state->sh_name);
329*37915d86SRichard Lowe 				return;
330*37915d86SRichard Lowe 			case DW_BAD_ENCODING:
331*37915d86SRichard Lowe 				(void) fprintf(stderr,
332*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWBADENC),
333*37915d86SRichard Lowe 				    state->file, state->sh_name,
334*37915d86SRichard Lowe 				    state->cieRflag);
335*37915d86SRichard Lowe 				return;
336*37915d86SRichard Lowe 			case DW_SUCCESS:
337*37915d86SRichard Lowe 				break;
338*37915d86SRichard Lowe 			}
3397e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_CFA_CFASET), PREFIX,
3407e16fca0SAli Bahrami 			    EC_XWORD(cur_pc));
3417e16fca0SAli Bahrami 			break;
3427e16fca0SAli Bahrami 
3437e16fca0SAli Bahrami 		case 0x02:	/* v2: DW_CFA_advance_loc_1, 1-byte delta */
3447e16fca0SAli Bahrami 		case 0x03:	/* v2: DW_CFA_advance_loc_2, 2-byte delta */
3457e16fca0SAli Bahrami 		case 0x04:	/* v2: DW_CFA_advance_loc_4, 4-byte delta */
3467e16fca0SAli Bahrami 			/*
3477e16fca0SAli Bahrami 			 * Since the codes are contiguous, and the sizes are
3487e16fca0SAli Bahrami 			 * powers of 2, we can compute the word width from
3497e16fca0SAli Bahrami 			 * the code.
3507e16fca0SAli Bahrami 			 */
3517e16fca0SAli Bahrami 			i = 1 << (op - 0x02);
352*37915d86SRichard Lowe 			switch (dwarf_extract_uint(data + off, len,
353*37915d86SRichard Lowe 			    ndx, i, state->do_swap, &oper1)) {
354*37915d86SRichard Lowe 			case DW_BAD_ENCODING:
355*37915d86SRichard Lowe 				(void) fprintf(stderr,
356*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWBADENC),
357*37915d86SRichard Lowe 				    state->file, state->sh_name,
358*37915d86SRichard Lowe 				    i);
359*37915d86SRichard Lowe 				return;
360*37915d86SRichard Lowe 			case DW_OVERFLOW:
361*37915d86SRichard Lowe 				(void) fprintf(stderr,
362*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
363*37915d86SRichard Lowe 				    state->file, state->sh_name);
364*37915d86SRichard Lowe 				return;
365*37915d86SRichard Lowe 			case DW_SUCCESS:
366*37915d86SRichard Lowe 				break;
367*37915d86SRichard Lowe 			}
368*37915d86SRichard Lowe 			oper1 *= state->ciecalign;
3697e16fca0SAli Bahrami 			cur_pc += oper1;
3707e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX,
3717e16fca0SAli Bahrami 			    loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc));
3727e16fca0SAli Bahrami 			loc_str = MSG_ORIG(MSG_STR_LOC);
3737e16fca0SAli Bahrami 			break;
3747e16fca0SAli Bahrami 
3757e16fca0SAli Bahrami 		case 0x05:		/* v2: DW_CFA_offset_extended,reg,off */
376*37915d86SRichard Lowe 			if (uleb_extract(&data[off], ndx, len, &oper1) ==
377*37915d86SRichard Lowe 			    DW_OVERFLOW) {
378*37915d86SRichard Lowe 				(void) fprintf(stderr,
379*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
380*37915d86SRichard Lowe 				    state->file, state->sh_name);
381*37915d86SRichard Lowe 				return;
382*37915d86SRichard Lowe 			}
383*37915d86SRichard Lowe 
384*37915d86SRichard Lowe 			if (sleb_extract(&data[off], ndx, len, &soper) ==
385*37915d86SRichard Lowe 			    DW_OVERFLOW) {
386*37915d86SRichard Lowe 				(void) fprintf(stderr,
387*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
388*37915d86SRichard Lowe 				    state->file, state->sh_name);
389*37915d86SRichard Lowe 				return;
390*37915d86SRichard Lowe 			}
391*37915d86SRichard Lowe 
392*37915d86SRichard Lowe 			soper *= state->ciedalign;
3937e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
3947e16fca0SAli Bahrami 			    REGNAME(oper1, rbuf1), EC_SXWORD(soper));
3957e16fca0SAli Bahrami 			break;
3967e16fca0SAli Bahrami 
3977e16fca0SAli Bahrami 		case 0x06:		/* v2: DW_CFA_restore_extended, reg */
3987e16fca0SAli Bahrami 		case 0x0d:		/* v2: DW_CFA_def_cfa_register, reg */
3997e16fca0SAli Bahrami 		case 0x08:		/* v2: DW_CFA_same_value, reg */
4007e16fca0SAli Bahrami 		case 0x07:		/* v2: DW_CFA_undefined, reg */
401*37915d86SRichard Lowe 			if (uleb_extract(&data[off], ndx, len, &oper1) ==
402*37915d86SRichard Lowe 			    DW_OVERFLOW) {
403*37915d86SRichard Lowe 				(void) fprintf(stderr,
404*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
405*37915d86SRichard Lowe 				    state->file, state->sh_name);
406*37915d86SRichard Lowe 				return;
407*37915d86SRichard Lowe 			}
408*37915d86SRichard Lowe 
4097e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_CFA_REG), PREFIX,
4107e16fca0SAli Bahrami 			    REGNAME(oper1, rbuf1));
4117e16fca0SAli Bahrami 			break;
4127e16fca0SAli Bahrami 
4137e16fca0SAli Bahrami 
4147e16fca0SAli Bahrami 		case 0x09:		/* v2: DW_CFA_register, reg, reg */
415*37915d86SRichard Lowe 			if (uleb_extract(&data[off], ndx, len, &oper1) ==
416*37915d86SRichard Lowe 			    DW_OVERFLOW) {
417*37915d86SRichard Lowe 				(void) fprintf(stderr,
418*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
419*37915d86SRichard Lowe 				    state->file, state->sh_name);
420*37915d86SRichard Lowe 				return;
421*37915d86SRichard Lowe 			}
422*37915d86SRichard Lowe 
423*37915d86SRichard Lowe 			if (uleb_extract(&data[off], ndx, len, &oper2) ==
424*37915d86SRichard Lowe 			    DW_OVERFLOW) {
425*37915d86SRichard Lowe 				(void) fprintf(stderr,
426*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
427*37915d86SRichard Lowe 				    state->file, state->sh_name);
428*37915d86SRichard Lowe 				return;
429*37915d86SRichard Lowe 			}
4307e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_CFA_REG_REG), PREFIX,
4317e16fca0SAli Bahrami 			    REGNAME(oper1, rbuf1), REGNAME(oper2, rbuf2));
4327e16fca0SAli Bahrami 			break;
4337e16fca0SAli Bahrami 
4347e16fca0SAli Bahrami 		case 0x0c:		/* v2: DW_CFA_def_cfa, reg, offset */
435*37915d86SRichard Lowe 			if (uleb_extract(&data[off], ndx, len, &oper1) ==
436*37915d86SRichard Lowe 			    DW_OVERFLOW) {
437*37915d86SRichard Lowe 				(void) fprintf(stderr,
438*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
439*37915d86SRichard Lowe 				    state->file, state->sh_name);
440*37915d86SRichard Lowe 				return;
441*37915d86SRichard Lowe 			}
442*37915d86SRichard Lowe 
443*37915d86SRichard Lowe 			if (uleb_extract(&data[off], ndx, len, &oper2) ==
444*37915d86SRichard Lowe 			    DW_OVERFLOW) {
445*37915d86SRichard Lowe 				(void) fprintf(stderr,
446*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
447*37915d86SRichard Lowe 				    state->file, state->sh_name);
448*37915d86SRichard Lowe 				return;
449*37915d86SRichard Lowe 			}
4507e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLU), PREFIX,
4517e16fca0SAli Bahrami 			    REGNAME(oper1, rbuf1), EC_XWORD(oper2));
4527e16fca0SAli Bahrami 			break;
4537e16fca0SAli Bahrami 
4547e16fca0SAli Bahrami 		case 0x0e:		/* v2: DW_CFA_def_cfa_offset, offset */
455*37915d86SRichard Lowe 			if (uleb_extract(&data[off], ndx, len, &oper1) ==
456*37915d86SRichard Lowe 			    DW_OVERFLOW) {
457*37915d86SRichard Lowe 				(void) fprintf(stderr,
458*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
459*37915d86SRichard Lowe 				    state->file, state->sh_name);
460*37915d86SRichard Lowe 				return;
461*37915d86SRichard Lowe 			}
4627e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_CFA_LLU), PREFIX,
4637e16fca0SAli Bahrami 			    EC_XWORD(oper1));
4647e16fca0SAli Bahrami 			break;
4657e16fca0SAli Bahrami 
4667e16fca0SAli Bahrami 		case 0x0f:		/* v3: DW_CFA_def_cfa_expression, blk */
467*37915d86SRichard Lowe 			if (uleb_extract(&data[off], ndx, len, &oper1) ==
468*37915d86SRichard Lowe 			    DW_OVERFLOW) {
469*37915d86SRichard Lowe 				(void) fprintf(stderr,
470*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
471*37915d86SRichard Lowe 				    state->file, state->sh_name);
472*37915d86SRichard Lowe 				return;
473*37915d86SRichard Lowe 			}
4747e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_CFA_EBLK), PREFIX,
4757e16fca0SAli Bahrami 			    EC_XWORD(oper1));
4767e16fca0SAli Bahrami 			/* We currently do not decode the expression block */
4777e16fca0SAli Bahrami 			*ndx += oper1;
4787e16fca0SAli Bahrami 			break;
4797e16fca0SAli Bahrami 
4807e16fca0SAli Bahrami 		case 0x10:		/* v3: DW_CFA_expression, reg, blk */
4817e16fca0SAli Bahrami 		case 0x16:		/* v3: DW_CFA_val_expression,reg,blk */
482*37915d86SRichard Lowe 			if (uleb_extract(&data[off], ndx, len, &oper1) ==
483*37915d86SRichard Lowe 			    DW_OVERFLOW) {
484*37915d86SRichard Lowe 				(void) fprintf(stderr,
485*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
486*37915d86SRichard Lowe 				    state->file, state->sh_name);
487*37915d86SRichard Lowe 				return;
488*37915d86SRichard Lowe 			}
489*37915d86SRichard Lowe 
490*37915d86SRichard Lowe 			if (uleb_extract(&data[off], ndx, len, &oper2) ==
491*37915d86SRichard Lowe 			    DW_OVERFLOW) {
492*37915d86SRichard Lowe 				(void) fprintf(stderr,
493*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
494*37915d86SRichard Lowe 				    state->file, state->sh_name);
495*37915d86SRichard Lowe 				return;
496*37915d86SRichard Lowe 			}
4977e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_CFA_REG_EBLK), PREFIX,
4987e16fca0SAli Bahrami 			    REGNAME(oper1, rbuf1), EC_XWORD(oper2));
4997e16fca0SAli Bahrami 			/* We currently do not decode the expression block */
5007e16fca0SAli Bahrami 			*ndx += oper2;
5017e16fca0SAli Bahrami 			break;
5027e16fca0SAli Bahrami 
5037e16fca0SAli Bahrami 		case 0x11:	/* v3: DW_CFA_offset_extended_sf, reg, off */
504*37915d86SRichard Lowe 			if (uleb_extract(&data[off], ndx, len, &oper1) ==
505*37915d86SRichard Lowe 			    DW_OVERFLOW) {
506*37915d86SRichard Lowe 				(void) fprintf(stderr,
507*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
508*37915d86SRichard Lowe 				    state->file, state->sh_name);
509*37915d86SRichard Lowe 				return;
510*37915d86SRichard Lowe 			}
511*37915d86SRichard Lowe 
512*37915d86SRichard Lowe 			if (sleb_extract(&data[off], ndx, len, &soper) ==
513*37915d86SRichard Lowe 			    DW_OVERFLOW) {
514*37915d86SRichard Lowe 				(void) fprintf(stderr,
515*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
516*37915d86SRichard Lowe 				    state->file, state->sh_name);
517*37915d86SRichard Lowe 				return;
518*37915d86SRichard Lowe 			}
519*37915d86SRichard Lowe 
520*37915d86SRichard Lowe 			soper *= state->ciedalign;
5217e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
5227e16fca0SAli Bahrami 			    REGNAME(oper1, rbuf1), EC_SXWORD(soper));
5237e16fca0SAli Bahrami 			break;
5247e16fca0SAli Bahrami 
5257e16fca0SAli Bahrami 		case 0x12:		/* v3: DW_CFA_def_cfa_sf, reg, offset */
526*37915d86SRichard Lowe 			if (uleb_extract(&data[off], ndx, len, &oper1) ==
527*37915d86SRichard Lowe 			    DW_OVERFLOW) {
528*37915d86SRichard Lowe 				(void) fprintf(stderr,
529*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
530*37915d86SRichard Lowe 				    state->file, state->sh_name);
531*37915d86SRichard Lowe 				return;
532*37915d86SRichard Lowe 			}
533*37915d86SRichard Lowe 
534*37915d86SRichard Lowe 			if (sleb_extract(&data[off], ndx, len, &soper) ==
535*37915d86SRichard Lowe 			    DW_OVERFLOW) {
536*37915d86SRichard Lowe 				(void) fprintf(stderr,
537*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
538*37915d86SRichard Lowe 				    state->file, state->sh_name);
539*37915d86SRichard Lowe 				return;
540*37915d86SRichard Lowe 			}
541*37915d86SRichard Lowe 
542*37915d86SRichard Lowe 			soper *= state->ciedalign;
5437e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX,
5447e16fca0SAli Bahrami 			    REGNAME(oper1, rbuf1), EC_SXWORD(soper));
5457e16fca0SAli Bahrami 			break;
5467e16fca0SAli Bahrami 
5477e16fca0SAli Bahrami 		case 0x13:		/* DW_CFA_def_cfa_offset_sf, offset */
548*37915d86SRichard Lowe 			if (sleb_extract(&data[off], ndx, len, &soper) ==
549*37915d86SRichard Lowe 			    DW_OVERFLOW) {
550*37915d86SRichard Lowe 				(void) fprintf(stderr,
551*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
552*37915d86SRichard Lowe 				    state->file, state->sh_name);
553*37915d86SRichard Lowe 				return;
554*37915d86SRichard Lowe 			}
555*37915d86SRichard Lowe 
556*37915d86SRichard Lowe 			soper *= state->ciedalign;
5577e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_CFA_LLD), PREFIX,
5587e16fca0SAli Bahrami 			    EC_SXWORD(soper));
5597e16fca0SAli Bahrami 			break;
5607e16fca0SAli Bahrami 
5617e16fca0SAli Bahrami 		case 0x14:		/* v3: DW_CFA_val_offset, reg, offset */
562*37915d86SRichard Lowe 			if (uleb_extract(&data[off], ndx, len, &oper1) ==
563*37915d86SRichard Lowe 			    DW_OVERFLOW) {
564*37915d86SRichard Lowe 				(void) fprintf(stderr,
565*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
566*37915d86SRichard Lowe 				    state->file, state->sh_name);
567*37915d86SRichard Lowe 				return;
568*37915d86SRichard Lowe 			}
569*37915d86SRichard Lowe 
570*37915d86SRichard Lowe 			if (sleb_extract(&data[off], ndx, len, &soper) ==
571*37915d86SRichard Lowe 			    DW_OVERFLOW) {
572*37915d86SRichard Lowe 				(void) fprintf(stderr,
573*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
574*37915d86SRichard Lowe 				    state->file, state->sh_name);
575*37915d86SRichard Lowe 				return;
576*37915d86SRichard Lowe 			}
577*37915d86SRichard Lowe 
578*37915d86SRichard Lowe 			soper *= state->ciedalign;
5797e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX,
5807e16fca0SAli Bahrami 			    REGNAME(oper1, rbuf1), EC_SXWORD(soper));
5817e16fca0SAli Bahrami 			break;
5827e16fca0SAli Bahrami 
5837e16fca0SAli Bahrami 		case 0x15:	/* v3: DW_CFA_val_offset_sf, reg, offset */
584*37915d86SRichard Lowe 			if (uleb_extract(&data[off], ndx, len, &oper1) ==
585*37915d86SRichard Lowe 			    DW_OVERFLOW) {
586*37915d86SRichard Lowe 				(void) fprintf(stderr,
587*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
588*37915d86SRichard Lowe 				    state->file, state->sh_name);
589*37915d86SRichard Lowe 				return;
590*37915d86SRichard Lowe 			}
591*37915d86SRichard Lowe 
592*37915d86SRichard Lowe 			if (sleb_extract(&data[off], ndx, len, &soper) ==
593*37915d86SRichard Lowe 			    DW_OVERFLOW) {
594*37915d86SRichard Lowe 				(void) fprintf(stderr,
595*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
596*37915d86SRichard Lowe 				    state->file, state->sh_name);
597*37915d86SRichard Lowe 				return;
598*37915d86SRichard Lowe 			}
599*37915d86SRichard Lowe 
600*37915d86SRichard Lowe 			soper *= state->ciedalign;
6017e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX,
6027e16fca0SAli Bahrami 			    REGNAME(oper1, rbuf1), EC_SXWORD(soper));
6037e16fca0SAli Bahrami 			break;
6047e16fca0SAli Bahrami 
6057e16fca0SAli Bahrami 		case 0x1d:	/* GNU: DW_CFA_MIPS_advance_loc8, delta */
606*37915d86SRichard Lowe 			switch (dwarf_extract_uint(data + off, len,
607*37915d86SRichard Lowe 			    ndx, 8, state->do_swap, &oper1)) {
608*37915d86SRichard Lowe 			case DW_BAD_ENCODING:
609*37915d86SRichard Lowe 				(void) fprintf(stderr,
610*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWBADENC),
611*37915d86SRichard Lowe 				    state->file, state->sh_name,
612*37915d86SRichard Lowe 				    8);
613*37915d86SRichard Lowe 				return;
614*37915d86SRichard Lowe 			case DW_OVERFLOW:
615*37915d86SRichard Lowe 				(void) fprintf(stderr,
616*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
617*37915d86SRichard Lowe 				    state->file, state->sh_name);
618*37915d86SRichard Lowe 				return;
619*37915d86SRichard Lowe 			case DW_SUCCESS:
620*37915d86SRichard Lowe 				break;
621*37915d86SRichard Lowe 			}
622*37915d86SRichard Lowe 			oper1 *= state->ciecalign;
6237e16fca0SAli Bahrami 			cur_pc += oper1;
6247e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX,
6257e16fca0SAli Bahrami 			    loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc));
6267e16fca0SAli Bahrami 			loc_str = MSG_ORIG(MSG_STR_LOC);
6277e16fca0SAli Bahrami 			break;
6287e16fca0SAli Bahrami 
6297e16fca0SAli Bahrami 		case 0x2e:		/* GNU: DW_CFA_GNU_args_size, size */
630*37915d86SRichard Lowe 			if (uleb_extract(&data[off], ndx, len, &oper1) ==
631*37915d86SRichard Lowe 			    DW_OVERFLOW) {
632*37915d86SRichard Lowe 				(void) fprintf(stderr,
633*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
634*37915d86SRichard Lowe 				    state->file, state->sh_name);
635*37915d86SRichard Lowe 				return;
636*37915d86SRichard Lowe 			}
637*37915d86SRichard Lowe 
6387e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_CFA_LLU), PREFIX,
6397e16fca0SAli Bahrami 			    EC_XWORD(oper1));
6407e16fca0SAli Bahrami 
6417e16fca0SAli Bahrami 			break;
6427e16fca0SAli Bahrami 
6437e16fca0SAli Bahrami 		case 0x2f: /* GNU:DW_CFA_GNU_negative_offset_extended,reg,off */
644*37915d86SRichard Lowe 			if (uleb_extract(&data[off], ndx, len, &oper1) ==
645*37915d86SRichard Lowe 			    DW_OVERFLOW) {
646*37915d86SRichard Lowe 				(void) fprintf(stderr,
647*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
648*37915d86SRichard Lowe 				    state->file, state->sh_name);
649*37915d86SRichard Lowe 				return;
650*37915d86SRichard Lowe 			}
651*37915d86SRichard Lowe 
652*37915d86SRichard Lowe 			if (sleb_extract(&data[off], ndx, len, &soper) ==
653*37915d86SRichard Lowe 			    DW_OVERFLOW) {
654*37915d86SRichard Lowe 				(void) fprintf(stderr,
655*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
656*37915d86SRichard Lowe 				    state->file, state->sh_name);
657*37915d86SRichard Lowe 				return;
658*37915d86SRichard Lowe 			}
659*37915d86SRichard Lowe 			soper = -soper * state->ciedalign;
660*37915d86SRichard Lowe 			soper *= state->ciedalign;
6617e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
6627e16fca0SAli Bahrami 			    REGNAME(oper1, rbuf1), EC_SXWORD(soper));
6637e16fca0SAli Bahrami 			break;
6647e16fca0SAli Bahrami 
6657e16fca0SAli Bahrami 		default:
6667e16fca0SAli Bahrami 			/*
6677e16fca0SAli Bahrami 			 * Unrecognized OP code: DWARF data is variable length,
6687e16fca0SAli Bahrami 			 * so we don't know how many bytes to skip in order to
6697e16fca0SAli Bahrami 			 * advance to the next item. We cannot decode beyond
6707e16fca0SAli Bahrami 			 * this point, so dump the remainder in hex.
6717e16fca0SAli Bahrami 			 */
6727e16fca0SAli Bahrami 			(*ndx)--;	/* Back up to unrecognized opcode */
6737e16fca0SAli Bahrami 			dump_hex_bytes(data + off + *ndx, len - *ndx,
6747e16fca0SAli Bahrami 			    indent, 8, 1);
6757e16fca0SAli Bahrami 			(*ndx) = len;
6767e16fca0SAli Bahrami 			break;
6777e16fca0SAli Bahrami 		}
6787e16fca0SAli Bahrami 	}
6797e16fca0SAli Bahrami 
6807e16fca0SAli Bahrami #undef PREFIX
6817e16fca0SAli Bahrami #undef REGNAME
6827e16fca0SAli Bahrami #undef LOW_OP
6837e16fca0SAli Bahrami }
6847e16fca0SAli Bahrami 
6857e16fca0SAli Bahrami void
dump_eh_frame(const char * file,char * sh_name,uchar_t * data,size_t datasize,uint64_t sh_addr,Half e_machine,uchar_t * e_ident,uint64_t gotaddr)686*37915d86SRichard Lowe dump_eh_frame(const char *file, char *sh_name, uchar_t *data, size_t datasize,
687*37915d86SRichard Lowe     uint64_t sh_addr, Half e_machine, uchar_t *e_ident, uint64_t gotaddr)
6887e16fca0SAli Bahrami {
6897e16fca0SAli Bahrami 	Conv_dwarf_ehe_buf_t	dwarf_ehe_buf;
6907e16fca0SAli Bahrami 	dump_cfi_state_t	cfi_state;
691*37915d86SRichard Lowe 	uint64_t	off, ndx, length, id;
6927e16fca0SAli Bahrami 	uint_t		cieid, cielength, cieversion, cieretaddr;
693*37915d86SRichard Lowe 	int		ciePflag = 0, cieZflag = 0, cieLflag = 0;
694*37915d86SRichard Lowe 	int		cieLflag_present = 0;
695*37915d86SRichard Lowe 	uint_t		cieaugndx;
696*37915d86SRichard Lowe 	char		*cieaugstr = NULL;
697*37915d86SRichard Lowe 	boolean_t	have_cie = B_FALSE;
698*37915d86SRichard Lowe 
699*37915d86SRichard Lowe 	cfi_state.file = file;
700*37915d86SRichard Lowe 	cfi_state.sh_name = sh_name;
7017e16fca0SAli Bahrami 	cfi_state.e_machine = e_machine;
7027e16fca0SAli Bahrami 	cfi_state.e_ident = e_ident;
7037e16fca0SAli Bahrami 	cfi_state.sh_addr = sh_addr;
7047e16fca0SAli Bahrami 	cfi_state.do_swap = _elf_sys_encoding() != e_ident[EI_DATA];
705965630c1SRichard Lowe 	cfi_state.gotaddr = gotaddr;
7067e16fca0SAli Bahrami 
7077e16fca0SAli Bahrami 	off = 0;
7087e16fca0SAli Bahrami 	while (off < datasize) {
7097e16fca0SAli Bahrami 		ndx = 0;
7107e16fca0SAli Bahrami 
7117e16fca0SAli Bahrami 		/*
7127e16fca0SAli Bahrami 		 * Extract length in native format.  A zero length indicates
7137e16fca0SAli Bahrami 		 * that this CIE is a terminator and that processing for this
7147e16fca0SAli Bahrami 		 * unwind information should end. However, skip this entry and
7157e16fca0SAli Bahrami 		 * keep processing, just in case there is any other information
7167e16fca0SAli Bahrami 		 * remaining in this section.  Note, ld(1) will terminate the
7177e16fca0SAli Bahrami 		 * processing of the .eh_frame contents for this file after a
7187e16fca0SAli Bahrami 		 * zero length CIE, thus any information that does follow is
7197e16fca0SAli Bahrami 		 * ignored by ld(1), and is therefore questionable.
7207e16fca0SAli Bahrami 		 */
721*37915d86SRichard Lowe 		if (dwarf_extract_uint(data + off, datasize - off,
722*37915d86SRichard Lowe 		    &ndx, 4, cfi_state.do_swap, &length) == DW_OVERFLOW) {
723*37915d86SRichard Lowe 			(void) fprintf(stderr,
724*37915d86SRichard Lowe 			    MSG_INTL(MSG_ERR_DWOVRFLW),
725*37915d86SRichard Lowe 			    file, sh_name);
726*37915d86SRichard Lowe 			return;
727*37915d86SRichard Lowe 		}
728*37915d86SRichard Lowe 
7297e16fca0SAli Bahrami 		if (length == 0) {
7307e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_UNW_ZEROTERM));
7317e16fca0SAli Bahrami 			off += 4;
7327e16fca0SAli Bahrami 			continue;
7337e16fca0SAli Bahrami 		}
7347e16fca0SAli Bahrami 
735*37915d86SRichard Lowe 		if (length > (datasize - off)) {
736*37915d86SRichard Lowe 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADCIEFDELEN),
737*37915d86SRichard Lowe 			    file, sh_name, EC_XWORD(length),
738*37915d86SRichard Lowe 			    EC_XWORD(sh_addr + off));
739*37915d86SRichard Lowe 			/*
740*37915d86SRichard Lowe 			 * If length is wrong, we have no means to find the
741*37915d86SRichard Lowe 			 * next entry, just give up
742*37915d86SRichard Lowe 			 */
743*37915d86SRichard Lowe 			return;
744*37915d86SRichard Lowe 		}
745*37915d86SRichard Lowe 
7467e16fca0SAli Bahrami 		/*
7477e16fca0SAli Bahrami 		 * extract CIE id in native format
7487e16fca0SAli Bahrami 		 */
749*37915d86SRichard Lowe 		if (dwarf_extract_uint(data + off, datasize - off, &ndx,
750*37915d86SRichard Lowe 		    4, cfi_state.do_swap, &id) == DW_OVERFLOW) {
751*37915d86SRichard Lowe 			(void) fprintf(stderr,
752*37915d86SRichard Lowe 			    MSG_INTL(MSG_ERR_DWOVRFLW),
753*37915d86SRichard Lowe 			    file, sh_name);
754*37915d86SRichard Lowe 			return;
755*37915d86SRichard Lowe 		}
7567e16fca0SAli Bahrami 
7577e16fca0SAli Bahrami 		/*
7587e16fca0SAli Bahrami 		 * A CIE record has an id of '0', otherwise this is a
7597e16fca0SAli Bahrami 		 * FDE entry and the 'id' is the CIE pointer.
7607e16fca0SAli Bahrami 		 */
7617e16fca0SAli Bahrami 		if (id == 0) {
762*37915d86SRichard Lowe 			uint64_t	persVal, ndx_save = 0;
763*37915d86SRichard Lowe 			uint64_t	axsize;
7647e16fca0SAli Bahrami 
765*37915d86SRichard Lowe 
766*37915d86SRichard Lowe 			have_cie = B_TRUE;
7677e16fca0SAli Bahrami 			cielength = length;
7687e16fca0SAli Bahrami 			cieid = id;
7697e16fca0SAli Bahrami 			ciePflag = cfi_state.cieRflag = cieZflag = 0;
7707e16fca0SAli Bahrami 			cieLflag = cieLflag_present = 0;
7717e16fca0SAli Bahrami 
7727e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_UNW_CIE),
7737e16fca0SAli Bahrami 			    EC_XWORD(sh_addr + off));
7747e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_UNW_CIELNGTH),
7757e16fca0SAli Bahrami 			    cielength, cieid);
7767e16fca0SAli Bahrami 
7777e16fca0SAli Bahrami 			cieversion = data[off + ndx];
7787e16fca0SAli Bahrami 			ndx += 1;
7797e16fca0SAli Bahrami 			cieaugstr = (char *)(&data[off + ndx]);
7807e16fca0SAli Bahrami 			ndx += strlen(cieaugstr) + 1;
7817e16fca0SAli Bahrami 
7827e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_UNW_CIEVERS),
7837e16fca0SAli Bahrami 			    cieversion, cieaugstr);
7847e16fca0SAli Bahrami 
785*37915d86SRichard Lowe 			if (uleb_extract(&data[off], &ndx, datasize - off,
786*37915d86SRichard Lowe 			    &cfi_state.ciecalign) == DW_OVERFLOW) {
787*37915d86SRichard Lowe 				(void) fprintf(stderr,
788*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
789*37915d86SRichard Lowe 				    file, sh_name);
790*37915d86SRichard Lowe 				return;
791*37915d86SRichard Lowe 			}
792*37915d86SRichard Lowe 
793*37915d86SRichard Lowe 			if (sleb_extract(&data[off], &ndx, datasize - off,
794*37915d86SRichard Lowe 			    &cfi_state.ciedalign) == DW_OVERFLOW) {
795*37915d86SRichard Lowe 				(void) fprintf(stderr,
796*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW),
797*37915d86SRichard Lowe 				    file, sh_name);
798*37915d86SRichard Lowe 				return;
799*37915d86SRichard Lowe 			}
8007e16fca0SAli Bahrami 			cieretaddr = data[off + ndx];
8017e16fca0SAli Bahrami 			ndx += 1;
8027e16fca0SAli Bahrami 
8037e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_UNW_CIECALGN),
8047e16fca0SAli Bahrami 			    EC_XWORD(cfi_state.ciecalign),
8057e16fca0SAli Bahrami 			    EC_XWORD(cfi_state.ciedalign), cieretaddr);
8067e16fca0SAli Bahrami 
8077e16fca0SAli Bahrami 			if (cieaugstr[0])
8087e16fca0SAli Bahrami 				dbg_print(0, MSG_ORIG(MSG_UNW_CIEAXVAL));
8097e16fca0SAli Bahrami 
8107e16fca0SAli Bahrami 			for (cieaugndx = 0; cieaugstr[cieaugndx]; cieaugndx++) {
8117e16fca0SAli Bahrami 				switch (cieaugstr[cieaugndx]) {
8127e16fca0SAli Bahrami 				case 'z':
813*37915d86SRichard Lowe 					if (uleb_extract(&data[off], &ndx,
814*37915d86SRichard Lowe 					    datasize - off, &axsize) ==
815*37915d86SRichard Lowe 					    DW_OVERFLOW) {
816*37915d86SRichard Lowe 						(void) fprintf(stderr,
817*37915d86SRichard Lowe 						    MSG_INTL(MSG_ERR_DWOVRFLW),
818*37915d86SRichard Lowe 						    file, sh_name);
819*37915d86SRichard Lowe 						return;
820*37915d86SRichard Lowe 					}
821*37915d86SRichard Lowe 
8227e16fca0SAli Bahrami 					dbg_print(0, MSG_ORIG(MSG_UNW_CIEAXSIZ),
823*37915d86SRichard Lowe 					    EC_XWORD(axsize));
8247e16fca0SAli Bahrami 					cieZflag = 1;
8257e16fca0SAli Bahrami 					/*
8267e16fca0SAli Bahrami 					 * The auxiliary section can contain
8277e16fca0SAli Bahrami 					 * unused padding bytes at the end, so
8287e16fca0SAli Bahrami 					 * save the current index. Along with
8297e16fca0SAli Bahrami 					 * axsize, we will use it to set ndx to
8307e16fca0SAli Bahrami 					 * the proper continuation index after
8317e16fca0SAli Bahrami 					 * the aux data has been processed.
8327e16fca0SAli Bahrami 					 */
8337e16fca0SAli Bahrami 					ndx_save = ndx;
8347e16fca0SAli Bahrami 					break;
8357e16fca0SAli Bahrami 				case 'P':
8367e16fca0SAli Bahrami 					ciePflag = data[off + ndx];
8377e16fca0SAli Bahrami 					ndx += 1;
8387e16fca0SAli Bahrami 
839*37915d86SRichard Lowe 					switch (dwarf_ehe_extract(&data[off],
840*37915d86SRichard Lowe 					    datasize - off, &ndx, &persVal,
841*37915d86SRichard Lowe 					    ciePflag, e_ident, B_FALSE, sh_addr,
842*37915d86SRichard Lowe 					    off + ndx, gotaddr)) {
843*37915d86SRichard Lowe 					case DW_OVERFLOW:
844*37915d86SRichard Lowe 						(void) fprintf(stderr,
845*37915d86SRichard Lowe 						    MSG_INTL(MSG_ERR_DWOVRFLW),
846*37915d86SRichard Lowe 						    file, sh_name);
847*37915d86SRichard Lowe 						return;
848*37915d86SRichard Lowe 					case DW_BAD_ENCODING:
849*37915d86SRichard Lowe 						(void) fprintf(stderr,
850*37915d86SRichard Lowe 						    MSG_INTL(MSG_ERR_DWBADENC),
851*37915d86SRichard Lowe 						    file, sh_name, ciePflag);
852*37915d86SRichard Lowe 						return;
853*37915d86SRichard Lowe 					case DW_SUCCESS:
854*37915d86SRichard Lowe 						break;
855*37915d86SRichard Lowe 					}
8567e16fca0SAli Bahrami 					dbg_print(0,
8577e16fca0SAli Bahrami 					    MSG_ORIG(MSG_UNW_CIEAXPERS));
8587e16fca0SAli Bahrami 					dbg_print(0,
8597e16fca0SAli Bahrami 					    MSG_ORIG(MSG_UNW_CIEAXPERSENC),
8607e16fca0SAli Bahrami 					    ciePflag, conv_dwarf_ehe(ciePflag,
8617e16fca0SAli Bahrami 					    &dwarf_ehe_buf));
8627e16fca0SAli Bahrami 					dbg_print(0,
8637e16fca0SAli Bahrami 					    MSG_ORIG(MSG_UNW_CIEAXPERSRTN),
8647e16fca0SAli Bahrami 					    EC_XWORD(persVal));
8657e16fca0SAli Bahrami 					break;
8667e16fca0SAli Bahrami 				case 'R':
8677e16fca0SAli Bahrami 					cfi_state.cieRflag = data[off + ndx];
8687e16fca0SAli Bahrami 					ndx += 1;
8697e16fca0SAli Bahrami 					dbg_print(0,
8707e16fca0SAli Bahrami 					    MSG_ORIG(MSG_UNW_CIEAXCENC),
8717e16fca0SAli Bahrami 					    cfi_state.cieRflag,
8727e16fca0SAli Bahrami 					    conv_dwarf_ehe(cfi_state.cieRflag,
8737e16fca0SAli Bahrami 					    &dwarf_ehe_buf));
8747e16fca0SAli Bahrami 					break;
8757e16fca0SAli Bahrami 				case 'L':
8767e16fca0SAli Bahrami 					cieLflag_present = 1;
8777e16fca0SAli Bahrami 					cieLflag = data[off + ndx];
8787e16fca0SAli Bahrami 					ndx += 1;
8797e16fca0SAli Bahrami 					dbg_print(0,
8807e16fca0SAli Bahrami 					    MSG_ORIG(MSG_UNW_CIEAXLSDA),
8817e16fca0SAli Bahrami 					    cieLflag, conv_dwarf_ehe(
8827e16fca0SAli Bahrami 					    cieLflag, &dwarf_ehe_buf));
8837e16fca0SAli Bahrami 					break;
8847e16fca0SAli Bahrami 				default:
8857e16fca0SAli Bahrami 					dbg_print(0,
8867e16fca0SAli Bahrami 					    MSG_ORIG(MSG_UNW_CIEAXUNEC),
8877e16fca0SAli Bahrami 					    cieaugstr[cieaugndx]);
8887e16fca0SAli Bahrami 					break;
8897e16fca0SAli Bahrami 				}
8907e16fca0SAli Bahrami 			}
8917e16fca0SAli Bahrami 
8927e16fca0SAli Bahrami 			/*
8937e16fca0SAli Bahrami 			 * If the z flag was present, reposition ndx using the
8947e16fca0SAli Bahrami 			 * length given. This will safely move us past any
8957e16fca0SAli Bahrami 			 * unaccessed padding bytes in the auxiliary section.
8967e16fca0SAli Bahrami 			 */
8977e16fca0SAli Bahrami 			if (cieZflag)
8987e16fca0SAli Bahrami 				ndx = ndx_save + axsize;
8997e16fca0SAli Bahrami 
9007e16fca0SAli Bahrami 			/*
9017e16fca0SAli Bahrami 			 * Any remaining data are Call Frame Instructions
9027e16fca0SAli Bahrami 			 */
9037e16fca0SAli Bahrami 			if ((cielength + 4) > ndx)
9047e16fca0SAli Bahrami 				dump_cfi(data, off, &ndx, cielength, &cfi_state,
9057e16fca0SAli Bahrami 				    MSG_ORIG(MSG_UNW_CIECFI), 3);
9067e16fca0SAli Bahrami 			off += cielength + 4;
9077e16fca0SAli Bahrami 
9087e16fca0SAli Bahrami 		} else {
9097e16fca0SAli Bahrami 			uint_t	    fdelength = length;
9107e16fca0SAli Bahrami 			int	    fdecieptr = id;
9117e16fca0SAli Bahrami 			uint64_t    fdeaddrrange;
9127e16fca0SAli Bahrami 
913*37915d86SRichard Lowe 			if (!have_cie) {
914*37915d86SRichard Lowe 				(void) fprintf(stderr,
915*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWNOCIE), file, sh_name);
916*37915d86SRichard Lowe 				return;
917*37915d86SRichard Lowe 			}
918*37915d86SRichard Lowe 
9197e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_UNW_FDE),
9207e16fca0SAli Bahrami 			    EC_XWORD(sh_addr + off));
9217e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_UNW_FDELNGTH),
9227e16fca0SAli Bahrami 			    fdelength, fdecieptr);
9237e16fca0SAli Bahrami 
924*37915d86SRichard Lowe 			switch (dwarf_ehe_extract(&data[off], datasize - off,
925*37915d86SRichard Lowe 			    &ndx, &cfi_state.fdeinitloc, cfi_state.cieRflag,
926*37915d86SRichard Lowe 			    e_ident, B_FALSE, sh_addr, off + ndx, gotaddr)) {
927*37915d86SRichard Lowe 			case DW_OVERFLOW:
928*37915d86SRichard Lowe 				(void) fprintf(stderr,
929*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW), file, sh_name);
930*37915d86SRichard Lowe 				return;
931*37915d86SRichard Lowe 			case DW_BAD_ENCODING:
932*37915d86SRichard Lowe 				(void) fprintf(stderr,
933*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWBADENC), file, sh_name,
934*37915d86SRichard Lowe 				    cfi_state.cieRflag);
935*37915d86SRichard Lowe 				return;
936*37915d86SRichard Lowe 			case DW_SUCCESS:
937*37915d86SRichard Lowe 				break;
938*37915d86SRichard Lowe 			}
939*37915d86SRichard Lowe 
940*37915d86SRichard Lowe 			switch (dwarf_ehe_extract(&data[off], datasize - off,
941*37915d86SRichard Lowe 			    &ndx, &fdeaddrrange,
942*37915d86SRichard Lowe 			    (cfi_state.cieRflag & ~DW_EH_PE_pcrel), e_ident,
943*37915d86SRichard Lowe 			    B_FALSE, sh_addr, off + ndx, gotaddr)) {
944*37915d86SRichard Lowe 			case DW_OVERFLOW:
945*37915d86SRichard Lowe 				(void) fprintf(stderr,
946*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWOVRFLW), file, sh_name);
947*37915d86SRichard Lowe 				return;
948*37915d86SRichard Lowe 			case DW_BAD_ENCODING:
949*37915d86SRichard Lowe 				(void) fprintf(stderr,
950*37915d86SRichard Lowe 				    MSG_INTL(MSG_ERR_DWBADENC), file, sh_name,
951*37915d86SRichard Lowe 				    (cfi_state.cieRflag & ~DW_EH_PE_pcrel));
952*37915d86SRichard Lowe 				return;
953*37915d86SRichard Lowe 			case DW_SUCCESS:
954*37915d86SRichard Lowe 				break;
955*37915d86SRichard Lowe 			}
9567e16fca0SAli Bahrami 
9577e16fca0SAli Bahrami 			dbg_print(0, MSG_ORIG(MSG_UNW_FDEINITLOC),
9587e16fca0SAli Bahrami 			    EC_XWORD(cfi_state.fdeinitloc),
9597e16fca0SAli Bahrami 			    EC_XWORD(fdeaddrrange),
9607e16fca0SAli Bahrami 			    EC_XWORD(cfi_state.fdeinitloc + fdeaddrrange - 1));
9617e16fca0SAli Bahrami 
962*37915d86SRichard Lowe 			if ((cieaugstr != NULL) && (cieaugstr[0] != '\0'))
9637e16fca0SAli Bahrami 				dbg_print(0, MSG_ORIG(MSG_UNW_FDEAXVAL));
9647e16fca0SAli Bahrami 			if (cieZflag) {
9657e16fca0SAli Bahrami 				uint64_t    val;
9667e16fca0SAli Bahrami 				uint64_t    lndx;
9677e16fca0SAli Bahrami 
968*37915d86SRichard Lowe 				if (uleb_extract(&data[off], &ndx,
969*37915d86SRichard Lowe 				    datasize - off, &val) == DW_OVERFLOW) {
970*37915d86SRichard Lowe 					(void) fprintf(stderr,
971*37915d86SRichard Lowe 					    MSG_INTL(MSG_ERR_DWOVRFLW),
972*37915d86SRichard Lowe 					    file, sh_name);
973*37915d86SRichard Lowe 					return;
974*37915d86SRichard Lowe 				}
9757e16fca0SAli Bahrami 				lndx = ndx;
9767e16fca0SAli Bahrami 				ndx += val;
9777e16fca0SAli Bahrami 				dbg_print(0, MSG_ORIG(MSG_UNW_FDEAXSIZE),
9787e16fca0SAli Bahrami 				    EC_XWORD(val));
9797e16fca0SAli Bahrami 				if (val && cieLflag_present) {
9807e16fca0SAli Bahrami 					uint64_t    lsda;
9817e16fca0SAli Bahrami 
982*37915d86SRichard Lowe 					switch (dwarf_ehe_extract(&data[off],
983*37915d86SRichard Lowe 					    datasize - off, &lndx, &lsda,
984*37915d86SRichard Lowe 					    cieLflag, e_ident, B_FALSE, sh_addr,
985*37915d86SRichard Lowe 					    off + lndx, gotaddr)) {
986*37915d86SRichard Lowe 					case DW_OVERFLOW:
987*37915d86SRichard Lowe 						(void) fprintf(stderr,
988*37915d86SRichard Lowe 						    MSG_INTL(MSG_ERR_DWOVRFLW),
989*37915d86SRichard Lowe 						    file, sh_name);
990*37915d86SRichard Lowe 						return;
991*37915d86SRichard Lowe 					case DW_BAD_ENCODING:
992*37915d86SRichard Lowe 						(void) fprintf(stderr,
993*37915d86SRichard Lowe 						    MSG_INTL(MSG_ERR_DWBADENC),
994*37915d86SRichard Lowe 						    file, sh_name, cieLflag);
995*37915d86SRichard Lowe 						return;
996*37915d86SRichard Lowe 					case DW_SUCCESS:
997*37915d86SRichard Lowe 						break;
998*37915d86SRichard Lowe 					}
9997e16fca0SAli Bahrami 					dbg_print(0,
10007e16fca0SAli Bahrami 					    MSG_ORIG(MSG_UNW_FDEAXLSDA),
10017e16fca0SAli Bahrami 					    EC_XWORD(lsda));
10027e16fca0SAli Bahrami 				}
10037e16fca0SAli Bahrami 			}
10047e16fca0SAli Bahrami 			if ((fdelength + 4) > ndx)
10057e16fca0SAli Bahrami 				dump_cfi(data, off, &ndx, fdelength, &cfi_state,
10067e16fca0SAli Bahrami 				    MSG_ORIG(MSG_UNW_FDECFI), 6);
10077e16fca0SAli Bahrami 			off += fdelength + 4;
10087e16fca0SAli Bahrami 		}
10097e16fca0SAli Bahrami 	}
10107e16fca0SAli Bahrami }
1011