xref: /illumos-gate/usr/src/cmd/sgs/elfdump/common/dwarf.c (revision b6805bf78d2bbbeeaea8909a05623587b42d58b3)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include	<_libelf.h>
28 #include	<dwarf.h>
29 #include	<stdio.h>
30 #include	<unistd.h>
31 #include	<errno.h>
32 #include	<strings.h>
33 #include	<debug.h>
34 #include	<conv.h>
35 #include	<msg.h>
36 #include	<_elfdump.h>
37 
38 
39 /*
40  * Data from eh_frame section used by dump_cfi()
41  */
42 typedef struct {
43 	Half		e_machine;	/* ehdr->e_machine */
44 	uchar_t		*e_ident;	/* ehdr->e_ident */
45 	uint64_t	sh_addr;	/* Address of eh_frame section */
46 	int		do_swap;	/* True if object and system byte */
47 					/*	order differs */
48 	int		cieRflag;	/* R flag from current CIE */
49 	uint64_t	ciecalign;	/* CIE code align factor */
50 	int64_t		ciedalign;	/* CIE data align factor */
51 	uint64_t	fdeinitloc;	/* FDE initial location */
52 	uint64_t	gotaddr;	/* Address of the GOT */
53 } dump_cfi_state_t;
54 
55 
56 /*
57  * Extract an unsigned integer value from an .eh_frame section, converting it
58  * from its native byte order to that of the running machine if necessary.
59  *
60  * entry:
61  *	data - Base address from which to extract datum
62  *	ndx - Address of variable giving index to start byte in data.
63  *	size - # of bytes in datum. Must be one of: 1, 2, 4, 8
64  *	do_swap - True if the data is in a different byte order than that
65  *		of the host system.
66  *
67  * exit:
68  *	*ndx is incremented by the size of the extracted datum.
69  *
70  *	The requested datum is extracted, byte swapped if necessary,
71  *	and returned.
72  */
73 static uint64_t
74 dwarf_extract_uint(uchar_t *data, uint64_t *ndx, int size, int do_swap)
75 {
76 	switch (size) {
77 	case 1:
78 		return (data[(*ndx)++]);
79 	case 2:
80 		{
81 			Half	r;
82 			uchar_t	*p = (uchar_t *)&r;
83 
84 			data += *ndx;
85 			if (do_swap)
86 				UL_ASSIGN_BSWAP_HALF(p, data);
87 			else
88 				UL_ASSIGN_HALF(p, data);
89 
90 			(*ndx) += 2;
91 			return (r);
92 		}
93 	case 4:
94 		{
95 			Word	r;
96 			uchar_t *p = (uchar_t *)&r;
97 
98 			data += *ndx;
99 			if (do_swap)
100 				UL_ASSIGN_BSWAP_WORD(p, data);
101 			else
102 				UL_ASSIGN_WORD(p, data);
103 
104 			(*ndx) += 4;
105 			return (r);
106 		}
107 
108 	case 8:
109 		{
110 			uint64_t	r;
111 			uchar_t		*p = (uchar_t *)&r;
112 
113 			data += *ndx;
114 			if (do_swap)
115 				UL_ASSIGN_BSWAP_LWORD(p, data);
116 			else
117 				UL_ASSIGN_LWORD(p, data);
118 
119 			(*ndx) += 8;
120 			return (r);
121 		}
122 	}
123 
124 	/* If here, an invalid size was specified */
125 	assert(0);
126 	return (0);
127 }
128 
129 /*
130  * Map a DWARF register constant to the machine register name it
131  * corresponds to, formatting the result into buf.
132  *
133  * The assignment of DWARF register numbers is part of the system
134  * specific ABI for each platform.
135  *
136  * entry:
137  *	regno - DWARF register number
138  *	mach - ELF machine code for platform
139  *	buf, bufsize - Buffer to receive the formatted result string
140  *
141  * exit:
142  *	The results are formatted into buf, and buf is returned.
143  *	If the generated output would exceed the size of the buffer
144  *	provided, it will be clipped to fit.
145  */
146 static const char *
147 dwarf_regname(Half mach, int regno, char *buf, size_t bufsize)
148 {
149 	Conv_inv_buf_t	inv_buf;
150 	const char	*name;
151 	int		good_name;
152 
153 	name = conv_dwarf_regname(mach, regno, 0, &good_name, &inv_buf);
154 
155 	/*
156 	 * If there is a good mnemonic machine name for the register,
157 	 * format the result as 'r# (mnemonic)'.  If there is no good
158 	 * name for it, then simply format the dwarf name as 'r#'.
159 	 */
160 	if (good_name)
161 		(void) snprintf(buf, bufsize, MSG_ORIG(MSG_REG_FMT_NAME),
162 		    regno, name);
163 	else
164 		(void) snprintf(buf, bufsize, MSG_ORIG(MSG_REG_FMT_BASIC),
165 		    regno);
166 
167 	return (buf);
168 }
169 
170 
171 /*
172  * Decode eh_frame Call Frame Instructions, printing each one on a
173  * separate line.
174  *
175  * entry:
176  *	data - Address of base of eh_frame section being processed
177  *	off - Offset of current FDE within eh_frame
178  *	ndx - Index of current position within current FDE
179  *	len - Length of eh_frame section
180  *	state - Object, CIE, and FDE state for current request
181  *	msg - Header message to issue before producing output.
182  *	indent - # of indentation characters issued for each line of output.
183  *
184  * exit:
185  *	The Call Frame Instructions have been decoded and printed.
186  *
187  *	*ndx has been incremented to contain the index of the next
188  *		byte of data to be processed in eh_frame.
189  *
190  * note:
191  *	The format of Call Frame Instructions in .eh_frame sections is based
192  *	on the DWARF specification.
193  */
194 static void
195 dump_cfi(uchar_t *data, uint64_t off, uint64_t *ndx, uint_t len,
196     dump_cfi_state_t *state, const char *msg, int indent)
197 {
198 	/*
199 	 * We use %*s%s to insert leading whitespace and the op name.
200 	 * PREFIX supplies these arguments.
201 	 */
202 #define	PREFIX	indent, MSG_ORIG(MSG_STR_EMPTY), opname
203 
204 	/* Hide boilerplate clutter in calls to dwarf_regname() */
205 #define	REGNAME(_rnum, _buf) \
206 	dwarf_regname(state->e_machine, _rnum, _buf, sizeof (_buf))
207 
208 	/* Extract the lower 6 bits from an op code */
209 #define	LOW_OP(_op) (_op & 0x3f)
210 
211 	char		rbuf1[32], rbuf2[32];
212 	Conv_inv_buf_t	inv_buf;
213 	uchar_t		op;
214 	const char	*opname;
215 	uint64_t	oper1, oper2, cur_pc;
216 	int64_t		soper;
217 	const char	*loc_str;
218 	int		i;
219 
220 	dbg_print(0, msg);
221 
222 	/*
223 	 * In a CIE/FDE, the length field does not include it's own
224 	 * size. Hence, the value passed in is 4 less than the index
225 	 * of the actual final location.
226 	 */
227 	len += 4;
228 
229 	/*
230 	 * There is a concept of the 'current location', which is the PC
231 	 * to which the current item applies. It starts out set to the
232 	 * FDE initial location, and can be set or incremented by
233 	 * various OP codes. cur_pc is used to track this.
234 	 *
235 	 * We want to use 'initloc' in the output the first time the location
236 	 * is referenced, and then switch to 'loc' for subsequent references.
237 	 * loc_str is used to manage that.
238 	 */
239 	cur_pc = state->fdeinitloc;
240 	loc_str = MSG_ORIG(MSG_STR_INITLOC);
241 
242 	while (*ndx < len) {
243 		/*
244 		 * The first byte contains the primary op code in the top
245 		 * 2 bits, so there are 4 of them. Primary OP code
246 		 * 0 uses the lower 6 bits to specify a sub-opcode, allowing
247 		 * for 64 of them. The other 3 primary op codes use the
248 		 * lower 6 bits to hold an operand (a register #, or value).
249 		 *
250 		 * Check the primary OP code. If it's 1-3, handle it
251 		 * and move to the next loop iteration. For OP code 0,
252 		 * fall through to decode the sub-code.
253 		 */
254 		op = data[off + (*ndx)++];
255 		opname = conv_dwarf_cfa(op, 0, &inv_buf);
256 		switch (op >> 6) {
257 		case 0x1:		/* v2: DW_CFA_advance_loc, delta */
258 			oper1 = state->ciecalign * LOW_OP(op);
259 			cur_pc += oper1;
260 			dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX,
261 			    loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc));
262 			loc_str = MSG_ORIG(MSG_STR_LOC);
263 			continue;
264 
265 		case 0x2:		/* v2: DW_CFA_offset, reg, offset */
266 			soper = uleb_extract(&data[off], ndx) *
267 			    state->ciedalign;
268 			dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
269 			    REGNAME(LOW_OP(op), rbuf1), EC_SXWORD(soper));
270 			continue;
271 
272 		case 0x3:		/* v2: DW_CFA_restore, reg */
273 			dbg_print(0, MSG_ORIG(MSG_CFA_REG), PREFIX,
274 			    REGNAME(LOW_OP(op), rbuf1));
275 			continue;
276 		}
277 
278 		/*
279 		 * If we're here, the high order 2 bits are 0. The low 6 bits
280 		 * specify a sub-opcode defining the operation.
281 		 */
282 		switch (op) {
283 		case 0x00:		/* v2: DW_CFA_nop */
284 			/*
285 			 * No-ops are used to fill unused space required
286 			 * for alignment. It is common for there to be
287 			 * multiple adjacent nops. It saves space to report
288 			 * them all with a single line of output.
289 			 */
290 			for (i = 1;
291 			    (*ndx < len) && (data[off + *ndx] == 0);
292 			    i++, (*ndx)++)
293 				;
294 			dbg_print(0, MSG_ORIG(MSG_CFA_SIMPLEREP), PREFIX, i);
295 			break;
296 
297 		case 0x0a:		/* v2: DW_CFA_remember_state */
298 		case 0x0b:		/* v2: DW_CFA_restore_state */
299 		case 0x2d:		/* GNU: DW_CFA_GNU_window_save */
300 			dbg_print(0, MSG_ORIG(MSG_CFA_SIMPLE), PREFIX);
301 			break;
302 
303 		case 0x01:		/* v2: DW_CFA_set_loc, address */
304 			cur_pc = dwarf_ehe_extract(&data[off], ndx,
305 			    state->cieRflag, state->e_ident, B_FALSE,
306 			    state->sh_addr, off + *ndx, state->gotaddr);
307 			dbg_print(0, MSG_ORIG(MSG_CFA_CFASET), PREFIX,
308 			    EC_XWORD(cur_pc));
309 			break;
310 
311 		case 0x02:	/* v2: DW_CFA_advance_loc_1, 1-byte delta */
312 		case 0x03:	/* v2: DW_CFA_advance_loc_2, 2-byte delta */
313 		case 0x04:	/* v2: DW_CFA_advance_loc_4, 4-byte delta */
314 			/*
315 			 * Since the codes are contiguous, and the sizes are
316 			 * powers of 2, we can compute the word width from
317 			 * the code.
318 			 */
319 			i = 1 << (op - 0x02);
320 			oper1 = dwarf_extract_uint(data + off, ndx, i,
321 			    state->do_swap) * state->ciecalign;
322 			cur_pc += oper1;
323 			dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX,
324 			    loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc));
325 			loc_str = MSG_ORIG(MSG_STR_LOC);
326 			break;
327 
328 		case 0x05:		/* v2: DW_CFA_offset_extended,reg,off */
329 			oper1 = uleb_extract(&data[off], ndx);
330 			soper = uleb_extract(&data[off], ndx) *
331 			    state->ciedalign;
332 			dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
333 			    REGNAME(oper1, rbuf1), EC_SXWORD(soper));
334 			break;
335 
336 		case 0x06:		/* v2: DW_CFA_restore_extended, reg */
337 		case 0x0d:		/* v2: DW_CFA_def_cfa_register, reg */
338 		case 0x08:		/* v2: DW_CFA_same_value, reg */
339 		case 0x07:		/* v2: DW_CFA_undefined, reg */
340 			oper1 = uleb_extract(&data[off], ndx);
341 			dbg_print(0, MSG_ORIG(MSG_CFA_REG), PREFIX,
342 			    REGNAME(oper1, rbuf1));
343 			break;
344 
345 
346 		case 0x09:		/* v2: DW_CFA_register, reg, reg */
347 			oper1 = uleb_extract(&data[off], ndx);
348 			oper2 = uleb_extract(&data[off], ndx);
349 			dbg_print(0, MSG_ORIG(MSG_CFA_REG_REG), PREFIX,
350 			    REGNAME(oper1, rbuf1), REGNAME(oper2, rbuf2));
351 			break;
352 
353 		case 0x0c:		/* v2: DW_CFA_def_cfa, reg, offset */
354 			oper1 = uleb_extract(&data[off], ndx);
355 			oper2 = uleb_extract(&data[off], ndx);
356 			dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLU), PREFIX,
357 			    REGNAME(oper1, rbuf1), EC_XWORD(oper2));
358 			break;
359 
360 		case 0x0e:		/* v2: DW_CFA_def_cfa_offset, offset */
361 			oper1 = uleb_extract(&data[off], ndx);
362 			dbg_print(0, MSG_ORIG(MSG_CFA_LLU), PREFIX,
363 			    EC_XWORD(oper1));
364 			break;
365 
366 		case 0x0f:		/* v3: DW_CFA_def_cfa_expression, blk */
367 			oper1 = uleb_extract(&data[off], ndx);
368 			dbg_print(0, MSG_ORIG(MSG_CFA_EBLK), PREFIX,
369 			    EC_XWORD(oper1));
370 			/* We currently do not decode the expression block */
371 			*ndx += oper1;
372 			break;
373 
374 		case 0x10:		/* v3: DW_CFA_expression, reg, blk */
375 		case 0x16:		/* v3: DW_CFA_val_expression,reg,blk */
376 			oper1 = uleb_extract(&data[off], ndx);
377 			oper2 = uleb_extract(&data[off], ndx);
378 			dbg_print(0, MSG_ORIG(MSG_CFA_REG_EBLK), PREFIX,
379 			    REGNAME(oper1, rbuf1), EC_XWORD(oper2));
380 			/* We currently do not decode the expression block */
381 			*ndx += oper2;
382 			break;
383 
384 		case 0x11:	/* v3: DW_CFA_offset_extended_sf, reg, off */
385 			oper1 = uleb_extract(&data[off], ndx);
386 			soper = sleb_extract(&data[off], ndx) *
387 			    state->ciedalign;
388 			dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
389 			    REGNAME(oper1, rbuf1), EC_SXWORD(soper));
390 			break;
391 
392 		case 0x12:		/* v3: DW_CFA_def_cfa_sf, reg, offset */
393 			oper1 = uleb_extract(&data[off], ndx);
394 			soper = sleb_extract(&data[off], ndx) *
395 			    state->ciedalign;
396 			dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX,
397 			    REGNAME(oper1, rbuf1), EC_SXWORD(soper));
398 			break;
399 
400 		case 0x13:		/* DW_CFA_def_cfa_offset_sf, offset */
401 			soper = sleb_extract(&data[off], ndx) *
402 			    state->ciedalign;
403 			dbg_print(0, MSG_ORIG(MSG_CFA_LLD), PREFIX,
404 			    EC_SXWORD(soper));
405 			break;
406 
407 		case 0x14:		/* v3: DW_CFA_val_offset, reg, offset */
408 			oper1 = uleb_extract(&data[off], ndx);
409 			soper = uleb_extract(&data[off], ndx) *
410 			    state->ciedalign;
411 			dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX,
412 			    REGNAME(oper1, rbuf1), EC_SXWORD(soper));
413 			break;
414 
415 		case 0x15:	/* v3: DW_CFA_val_offset_sf, reg, offset */
416 			oper1 = uleb_extract(&data[off], ndx);
417 			soper = sleb_extract(&data[off], ndx) *
418 			    state->ciedalign;
419 			dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX,
420 			    REGNAME(oper1, rbuf1), EC_SXWORD(soper));
421 			break;
422 
423 		case 0x1d:	/* GNU: DW_CFA_MIPS_advance_loc8, delta */
424 			oper1 = dwarf_extract_uint(data + off, ndx, i,
425 			    state->do_swap) * state->ciecalign;
426 			cur_pc += oper1;
427 			dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX,
428 			    loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc));
429 			loc_str = MSG_ORIG(MSG_STR_LOC);
430 			break;
431 
432 		case 0x2e:		/* GNU: DW_CFA_GNU_args_size, size */
433 			oper1 = uleb_extract(&data[off], ndx);
434 			dbg_print(0, MSG_ORIG(MSG_CFA_LLU), PREFIX,
435 			    EC_XWORD(oper1));
436 
437 			break;
438 
439 		case 0x2f: /* GNU:DW_CFA_GNU_negative_offset_extended,reg,off */
440 			oper1 = uleb_extract(&data[off], ndx);
441 			soper = -uleb_extract(&data[off], ndx) *
442 			    state->ciedalign;
443 			dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
444 			    REGNAME(oper1, rbuf1), EC_SXWORD(soper));
445 			break;
446 
447 		default:
448 			/*
449 			 * Unrecognized OP code: DWARF data is variable length,
450 			 * so we don't know how many bytes to skip in order to
451 			 * advance to the next item. We cannot decode beyond
452 			 * this point, so dump the remainder in hex.
453 			 */
454 			(*ndx)--;	/* Back up to unrecognized opcode */
455 			dump_hex_bytes(data + off + *ndx, len - *ndx,
456 			    indent, 8, 1);
457 			(*ndx) = len;
458 			break;
459 		}
460 	}
461 
462 #undef PREFIX
463 #undef REGNAME
464 #undef LOW_OP
465 }
466 
467 void
468 dump_eh_frame(uchar_t *data, size_t datasize, uint64_t sh_addr,
469     Half e_machine, uchar_t *e_ident, uint64_t gotaddr)
470 {
471 	Conv_dwarf_ehe_buf_t	dwarf_ehe_buf;
472 	dump_cfi_state_t	cfi_state;
473 	uint64_t	off, ndx;
474 	uint_t		cieid, cielength, cieversion, cieretaddr;
475 	int		ciePflag, cieZflag, cieLflag, cieLflag_present;
476 	uint_t		cieaugndx, length, id;
477 	char		*cieaugstr;
478 
479 	cfi_state.e_machine = e_machine;
480 	cfi_state.e_ident = e_ident;
481 	cfi_state.sh_addr = sh_addr;
482 	cfi_state.do_swap = _elf_sys_encoding() != e_ident[EI_DATA];
483 	cfi_state.gotaddr = gotaddr;
484 
485 	off = 0;
486 	while (off < datasize) {
487 		ndx = 0;
488 
489 		/*
490 		 * Extract length in native format.  A zero length indicates
491 		 * that this CIE is a terminator and that processing for this
492 		 * unwind information should end. However, skip this entry and
493 		 * keep processing, just in case there is any other information
494 		 * remaining in this section.  Note, ld(1) will terminate the
495 		 * processing of the .eh_frame contents for this file after a
496 		 * zero length CIE, thus any information that does follow is
497 		 * ignored by ld(1), and is therefore questionable.
498 		 */
499 		length = (uint_t)dwarf_extract_uint(data + off, &ndx,
500 		    4, cfi_state.do_swap);
501 		if (length == 0) {
502 			dbg_print(0, MSG_ORIG(MSG_UNW_ZEROTERM));
503 			off += 4;
504 			continue;
505 		}
506 
507 		/*
508 		 * extract CIE id in native format
509 		 */
510 		id = (uint_t)dwarf_extract_uint(data + off, &ndx,
511 		    4, cfi_state.do_swap);
512 
513 		/*
514 		 * A CIE record has an id of '0', otherwise this is a
515 		 * FDE entry and the 'id' is the CIE pointer.
516 		 */
517 		if (id == 0) {
518 			uint64_t	persVal, ndx_save;
519 			uint_t		axsize;
520 
521 			cielength = length;
522 			cieid = id;
523 			ciePflag = cfi_state.cieRflag = cieZflag = 0;
524 			cieLflag = cieLflag_present = 0;
525 
526 			dbg_print(0, MSG_ORIG(MSG_UNW_CIE),
527 			    EC_XWORD(sh_addr + off));
528 			dbg_print(0, MSG_ORIG(MSG_UNW_CIELNGTH),
529 			    cielength, cieid);
530 
531 			cieversion = data[off + ndx];
532 			ndx += 1;
533 			cieaugstr = (char *)(&data[off + ndx]);
534 			ndx += strlen(cieaugstr) + 1;
535 
536 			dbg_print(0, MSG_ORIG(MSG_UNW_CIEVERS),
537 			    cieversion, cieaugstr);
538 
539 			cfi_state.ciecalign = uleb_extract(&data[off], &ndx);
540 			cfi_state.ciedalign = sleb_extract(&data[off], &ndx);
541 			cieretaddr = data[off + ndx];
542 			ndx += 1;
543 
544 			dbg_print(0, MSG_ORIG(MSG_UNW_CIECALGN),
545 			    EC_XWORD(cfi_state.ciecalign),
546 			    EC_XWORD(cfi_state.ciedalign), cieretaddr);
547 
548 			if (cieaugstr[0])
549 				dbg_print(0, MSG_ORIG(MSG_UNW_CIEAXVAL));
550 
551 			for (cieaugndx = 0; cieaugstr[cieaugndx]; cieaugndx++) {
552 				switch (cieaugstr[cieaugndx]) {
553 				case 'z':
554 					axsize = uleb_extract(&data[off], &ndx);
555 					dbg_print(0, MSG_ORIG(MSG_UNW_CIEAXSIZ),
556 					    axsize);
557 					cieZflag = 1;
558 					/*
559 					 * The auxiliary section can contain
560 					 * unused padding bytes at the end, so
561 					 * save the current index. Along with
562 					 * axsize, we will use it to set ndx to
563 					 * the proper continuation index after
564 					 * the aux data has been processed.
565 					 */
566 					ndx_save = ndx;
567 					break;
568 				case 'P':
569 					ciePflag = data[off + ndx];
570 					ndx += 1;
571 
572 					persVal = dwarf_ehe_extract(&data[off],
573 					    &ndx, ciePflag, e_ident, B_FALSE,
574 					    sh_addr, off + ndx, gotaddr);
575 					dbg_print(0,
576 					    MSG_ORIG(MSG_UNW_CIEAXPERS));
577 					dbg_print(0,
578 					    MSG_ORIG(MSG_UNW_CIEAXPERSENC),
579 					    ciePflag, conv_dwarf_ehe(ciePflag,
580 					    &dwarf_ehe_buf));
581 					dbg_print(0,
582 					    MSG_ORIG(MSG_UNW_CIEAXPERSRTN),
583 					    EC_XWORD(persVal));
584 					break;
585 				case 'R':
586 					cfi_state.cieRflag = data[off + ndx];
587 					ndx += 1;
588 					dbg_print(0,
589 					    MSG_ORIG(MSG_UNW_CIEAXCENC),
590 					    cfi_state.cieRflag,
591 					    conv_dwarf_ehe(cfi_state.cieRflag,
592 					    &dwarf_ehe_buf));
593 					break;
594 				case 'L':
595 					cieLflag_present = 1;
596 					cieLflag = data[off + ndx];
597 					ndx += 1;
598 					dbg_print(0,
599 					    MSG_ORIG(MSG_UNW_CIEAXLSDA),
600 					    cieLflag, conv_dwarf_ehe(
601 					    cieLflag, &dwarf_ehe_buf));
602 					break;
603 				default:
604 					dbg_print(0,
605 					    MSG_ORIG(MSG_UNW_CIEAXUNEC),
606 					    cieaugstr[cieaugndx]);
607 					break;
608 				}
609 			}
610 
611 			/*
612 			 * If the z flag was present, reposition ndx using the
613 			 * length given. This will safely move us past any
614 			 * unaccessed padding bytes in the auxiliary section.
615 			 */
616 			if (cieZflag)
617 				ndx = ndx_save + axsize;
618 
619 			/*
620 			 * Any remaining data are Call Frame Instructions
621 			 */
622 			if ((cielength + 4) > ndx)
623 				dump_cfi(data, off, &ndx, cielength, &cfi_state,
624 				    MSG_ORIG(MSG_UNW_CIECFI), 3);
625 			off += cielength + 4;
626 
627 		} else {
628 			uint_t	    fdelength = length;
629 			int	    fdecieptr = id;
630 			uint64_t    fdeaddrrange;
631 
632 			dbg_print(0, MSG_ORIG(MSG_UNW_FDE),
633 			    EC_XWORD(sh_addr + off));
634 			dbg_print(0, MSG_ORIG(MSG_UNW_FDELNGTH),
635 			    fdelength, fdecieptr);
636 
637 			cfi_state.fdeinitloc = dwarf_ehe_extract(&data[off],
638 			    &ndx, cfi_state.cieRflag, e_ident, B_FALSE,
639 			    sh_addr, off + ndx, gotaddr);
640 			fdeaddrrange = dwarf_ehe_extract(&data[off], &ndx,
641 			    (cfi_state.cieRflag & ~DW_EH_PE_pcrel),
642 			    e_ident, B_FALSE, sh_addr, off + ndx, gotaddr);
643 
644 			dbg_print(0, MSG_ORIG(MSG_UNW_FDEINITLOC),
645 			    EC_XWORD(cfi_state.fdeinitloc),
646 			    EC_XWORD(fdeaddrrange),
647 			    EC_XWORD(cfi_state.fdeinitloc + fdeaddrrange - 1));
648 
649 			if (cieaugstr[0])
650 				dbg_print(0, MSG_ORIG(MSG_UNW_FDEAXVAL));
651 			if (cieZflag) {
652 				uint64_t    val;
653 				uint64_t    lndx;
654 
655 				val = uleb_extract(&data[off], &ndx);
656 				lndx = ndx;
657 				ndx += val;
658 				dbg_print(0, MSG_ORIG(MSG_UNW_FDEAXSIZE),
659 				    EC_XWORD(val));
660 				if (val && cieLflag_present) {
661 					uint64_t    lsda;
662 
663 					lsda = dwarf_ehe_extract(&data[off],
664 					    &lndx, cieLflag, e_ident,
665 					    B_FALSE, sh_addr, off + lndx,
666 					    gotaddr);
667 					dbg_print(0,
668 					    MSG_ORIG(MSG_UNW_FDEAXLSDA),
669 					    EC_XWORD(lsda));
670 				}
671 			}
672 			if ((fdelength + 4) > ndx)
673 				dump_cfi(data, off, &ndx, fdelength, &cfi_state,
674 				    MSG_ORIG(MSG_UNW_FDECFI), 6);
675 			off += fdelength + 4;
676 		}
677 	}
678 }
679