xref: /illumos-gate/usr/src/cmd/sgs/elfdump/common/dwarf.c (revision bbe876c07ed632b8f85e195d41e7948382064a95)
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 	const char	*file;
44 	const char	*sh_name;
45 	Half		e_machine;	/* ehdr->e_machine */
46 	uchar_t		*e_ident;	/* ehdr->e_ident */
47 	uint64_t	sh_addr;	/* Address of eh_frame section */
48 	int		do_swap;	/* True if object and system byte */
49 					/*	order differs */
50 	int		cieRflag;	/* R flag from current CIE */
51 	uint64_t	ciecalign;	/* CIE code align factor */
52 	int64_t		ciedalign;	/* CIE data align factor */
53 	uint64_t	fdeinitloc;	/* FDE initial location */
54 	uint64_t	gotaddr;	/* Address of the GOT */
55 } dump_cfi_state_t;
56 
57 
58 /*
59  * Extract an unsigned integer value from an .eh_frame section, converting it
60  * from its native byte order to that of the running machine if necessary.
61  *
62  * entry:
63  *	data - Base address from which to extract datum
64  *	ndx - Address of variable giving index to start byte in data.
65  *	size - # of bytes in datum. Must be one of: 1, 2, 4, 8
66  *	do_swap - True if the data is in a different byte order than that
67  *		of the host system.
68  *
69  * exit:
70  *	*ndx is incremented by the size of the extracted datum.
71  *
72  *	The requested datum is extracted, byte swapped if necessary,
73  *	and returned.
74  */
75 static dwarf_error_t
76 dwarf_extract_uint(uchar_t *data, size_t len, uint64_t *ndx, int size,
77     int do_swap, uint64_t *ret)
78 {
79 	if (((*ndx + size) > len) ||
80 	    ((*ndx + size) < *ndx))
81 		return (DW_OVERFLOW);
82 
83 	switch (size) {
84 	case 1:
85 		*ret = (data[(*ndx)++]);
86 		return (DW_SUCCESS);
87 	case 2:
88 		{
89 			Half	r;
90 			uchar_t	*p = (uchar_t *)&r;
91 
92 			data += *ndx;
93 			if (do_swap)
94 				UL_ASSIGN_BSWAP_HALF(p, data);
95 			else
96 				UL_ASSIGN_HALF(p, data);
97 
98 			(*ndx) += 2;
99 			*ret = r;
100 			return (DW_SUCCESS);
101 		}
102 	case 4:
103 		{
104 			Word	r;
105 			uchar_t *p = (uchar_t *)&r;
106 
107 			data += *ndx;
108 			if (do_swap)
109 				UL_ASSIGN_BSWAP_WORD(p, data);
110 			else
111 				UL_ASSIGN_WORD(p, data);
112 
113 			(*ndx) += 4;
114 			*ret = r;
115 			return (DW_SUCCESS);
116 		}
117 
118 	case 8:
119 		{
120 			uint64_t	r;
121 			uchar_t		*p = (uchar_t *)&r;
122 
123 			data += *ndx;
124 			if (do_swap)
125 				UL_ASSIGN_BSWAP_LWORD(p, data);
126 			else
127 				UL_ASSIGN_LWORD(p, data);
128 
129 			(*ndx) += 8;
130 			*ret = r;
131 			return (DW_SUCCESS);
132 		}
133 	default:
134 		return (DW_BAD_ENCODING);
135 	}
136 
137 	/* NOTREACHED */
138 }
139 
140 /*
141  * Map a DWARF register constant to the machine register name it
142  * corresponds to, formatting the result into buf.
143  *
144  * The assignment of DWARF register numbers is part of the system
145  * specific ABI for each platform.
146  *
147  * entry:
148  *	regno - DWARF register number
149  *	mach - ELF machine code for platform
150  *	buf, bufsize - Buffer to receive the formatted result string
151  *
152  * exit:
153  *	The results are formatted into buf, and buf is returned.
154  *	If the generated output would exceed the size of the buffer
155  *	provided, it will be clipped to fit.
156  */
157 static const char *
158 dwarf_regname(Half mach, int regno, char *buf, size_t bufsize)
159 {
160 	Conv_inv_buf_t	inv_buf;
161 	const char	*name;
162 	int		good_name;
163 
164 	name = conv_dwarf_regname(mach, regno, 0, &good_name, &inv_buf);
165 
166 	/*
167 	 * If there is a good mnemonic machine name for the register,
168 	 * format the result as 'r# (mnemonic)'.  If there is no good
169 	 * name for it, then simply format the dwarf name as 'r#'.
170 	 */
171 	if (good_name)
172 		(void) snprintf(buf, bufsize, MSG_ORIG(MSG_REG_FMT_NAME),
173 		    regno, name);
174 	else
175 		(void) snprintf(buf, bufsize, MSG_ORIG(MSG_REG_FMT_BASIC),
176 		    regno);
177 
178 	return (buf);
179 }
180 
181 
182 /*
183  * Decode eh_frame Call Frame Instructions, printing each one on a
184  * separate line.
185  *
186  * entry:
187  *	data - Address of base of eh_frame section being processed
188  *	off - Offset of current FDE within eh_frame
189  *	ndx - Index of current position within current FDE
190  *	len - Length of FDE
191  *	state - Object, CIE, and FDE state for current request
192  *	msg - Header message to issue before producing output.
193  *	indent - # of indentation characters issued for each line of output.
194  *
195  * exit:
196  *	The Call Frame Instructions have been decoded and printed.
197  *
198  *	*ndx has been incremented to contain the index of the next
199  *		byte of data to be processed in eh_frame.
200  *
201  * note:
202  *	The format of Call Frame Instructions in .eh_frame sections is based
203  *	on the DWARF specification.
204  */
205 static void
206 dump_cfi(uchar_t *data, uint64_t off, uint64_t *ndx, uint_t len,
207     dump_cfi_state_t *state, const char *msg, int indent)
208 {
209 	/*
210 	 * We use %*s%s to insert leading whitespace and the op name.
211 	 * PREFIX supplies these arguments.
212 	 */
213 #define	PREFIX	indent, MSG_ORIG(MSG_STR_EMPTY), opname
214 
215 	/* Hide boilerplate clutter in calls to dwarf_regname() */
216 #define	REGNAME(_rnum, _buf) \
217 	dwarf_regname(state->e_machine, _rnum, _buf, sizeof (_buf))
218 
219 	/* Extract the lower 6 bits from an op code */
220 #define	LOW_OP(_op) (_op & 0x3f)
221 
222 	char		rbuf1[32], rbuf2[32];
223 	Conv_inv_buf_t	inv_buf;
224 	uchar_t		op;
225 	const char	*opname;
226 	uint64_t	oper1, oper2, cur_pc;
227 	int64_t		soper;
228 	const char	*loc_str;
229 	int		i;
230 
231 	dbg_print(0, msg);
232 
233 	/*
234 	 * In a CIE/FDE, the length field does not include it's own
235 	 * size. Hence, the value passed in is 4 less than the index
236 	 * of the actual final location.
237 	 */
238 	len += 4;
239 
240 	/*
241 	 * There is a concept of the 'current location', which is the PC
242 	 * to which the current item applies. It starts out set to the
243 	 * FDE initial location, and can be set or incremented by
244 	 * various OP codes. cur_pc is used to track this.
245 	 *
246 	 * We want to use 'initloc' in the output the first time the location
247 	 * is referenced, and then switch to 'loc' for subsequent references.
248 	 * loc_str is used to manage that.
249 	 */
250 	cur_pc = state->fdeinitloc;
251 	loc_str = MSG_ORIG(MSG_STR_INITLOC);
252 
253 	while (*ndx < len) {
254 		/*
255 		 * The first byte contains the primary op code in the top
256 		 * 2 bits, so there are 4 of them. Primary OP code
257 		 * 0 uses the lower 6 bits to specify a sub-opcode, allowing
258 		 * for 64 of them. The other 3 primary op codes use the
259 		 * lower 6 bits to hold an operand (a register #, or value).
260 		 *
261 		 * Check the primary OP code. If it's 1-3, handle it
262 		 * and move to the next loop iteration. For OP code 0,
263 		 * fall through to decode the sub-code.
264 		 */
265 		op = data[off + (*ndx)++];
266 		opname = conv_dwarf_cfa(op, 0, &inv_buf);
267 		switch (op >> 6) {
268 		case 0x1:		/* v2: DW_CFA_advance_loc, delta */
269 			oper1 = state->ciecalign * LOW_OP(op);
270 			cur_pc += oper1;
271 			dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX,
272 			    loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc));
273 			loc_str = MSG_ORIG(MSG_STR_LOC);
274 			continue;
275 
276 		case 0x2:		/* v2: DW_CFA_offset, reg, offset */
277 			if (uleb_extract(&data[off], ndx, len, &oper1) ==
278 			    DW_OVERFLOW) {
279 				(void) fprintf(stderr,
280 				    MSG_INTL(MSG_ERR_DWOVRFLW),
281 				    state->file, state->sh_name);
282 				return;
283 			}
284 
285 			oper1 *= state->ciedalign;
286 			dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
287 			    REGNAME(LOW_OP(op), rbuf1), EC_XWORD(oper1));
288 			continue;
289 
290 		case 0x3:		/* v2: DW_CFA_restore, reg */
291 			dbg_print(0, MSG_ORIG(MSG_CFA_REG), PREFIX,
292 			    REGNAME(LOW_OP(op), rbuf1));
293 			continue;
294 		}
295 
296 		/*
297 		 * If we're here, the high order 2 bits are 0. The low 6 bits
298 		 * specify a sub-opcode defining the operation.
299 		 */
300 		switch (op) {
301 		case 0x00:		/* v2: DW_CFA_nop */
302 			/*
303 			 * No-ops are used to fill unused space required
304 			 * for alignment. It is common for there to be
305 			 * multiple adjacent nops. It saves space to report
306 			 * them all with a single line of output.
307 			 */
308 			for (i = 1;
309 			    (*ndx < len) && (data[off + *ndx] == 0);
310 			    i++, (*ndx)++)
311 				;
312 			dbg_print(0, MSG_ORIG(MSG_CFA_SIMPLEREP), PREFIX, i);
313 			break;
314 
315 		case 0x0a:		/* v2: DW_CFA_remember_state */
316 		case 0x0b:		/* v2: DW_CFA_restore_state */
317 		case 0x2d:		/* GNU: DW_CFA_GNU_window_save */
318 			dbg_print(0, MSG_ORIG(MSG_CFA_SIMPLE), PREFIX);
319 			break;
320 
321 		case 0x01:		/* v2: DW_CFA_set_loc, address */
322 			switch (dwarf_ehe_extract(&data[off], len, ndx,
323 			    &cur_pc, state->cieRflag, state->e_ident, B_FALSE,
324 			    state->sh_addr, off + *ndx, state->gotaddr)) {
325 			case DW_OVERFLOW:
326 				(void) fprintf(stderr,
327 				    MSG_INTL(MSG_ERR_DWOVRFLW),
328 				    state->file, state->sh_name);
329 				return;
330 			case DW_BAD_ENCODING:
331 				(void) fprintf(stderr,
332 				    MSG_INTL(MSG_ERR_DWBADENC),
333 				    state->file, state->sh_name,
334 				    state->cieRflag);
335 				return;
336 			case DW_SUCCESS:
337 				break;
338 			}
339 			dbg_print(0, MSG_ORIG(MSG_CFA_CFASET), PREFIX,
340 			    EC_XWORD(cur_pc));
341 			break;
342 
343 		case 0x02:	/* v2: DW_CFA_advance_loc_1, 1-byte delta */
344 		case 0x03:	/* v2: DW_CFA_advance_loc_2, 2-byte delta */
345 		case 0x04:	/* v2: DW_CFA_advance_loc_4, 4-byte delta */
346 			/*
347 			 * Since the codes are contiguous, and the sizes are
348 			 * powers of 2, we can compute the word width from
349 			 * the code.
350 			 */
351 			i = 1 << (op - 0x02);
352 			switch (dwarf_extract_uint(data + off, len,
353 			    ndx, i, state->do_swap, &oper1)) {
354 			case DW_BAD_ENCODING:
355 				(void) fprintf(stderr,
356 				    MSG_INTL(MSG_ERR_DWBADENC),
357 				    state->file, state->sh_name,
358 				    i);
359 				return;
360 			case DW_OVERFLOW:
361 				(void) fprintf(stderr,
362 				    MSG_INTL(MSG_ERR_DWOVRFLW),
363 				    state->file, state->sh_name);
364 				return;
365 			case DW_SUCCESS:
366 				break;
367 			}
368 			oper1 *= state->ciecalign;
369 			cur_pc += oper1;
370 			dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX,
371 			    loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc));
372 			loc_str = MSG_ORIG(MSG_STR_LOC);
373 			break;
374 
375 		case 0x05:		/* v2: DW_CFA_offset_extended,reg,off */
376 			if (uleb_extract(&data[off], ndx, len, &oper1) ==
377 			    DW_OVERFLOW) {
378 				(void) fprintf(stderr,
379 				    MSG_INTL(MSG_ERR_DWOVRFLW),
380 				    state->file, state->sh_name);
381 				return;
382 			}
383 
384 			if (sleb_extract(&data[off], ndx, len, &soper) ==
385 			    DW_OVERFLOW) {
386 				(void) fprintf(stderr,
387 				    MSG_INTL(MSG_ERR_DWOVRFLW),
388 				    state->file, state->sh_name);
389 				return;
390 			}
391 
392 			soper *= state->ciedalign;
393 			dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
394 			    REGNAME(oper1, rbuf1), EC_SXWORD(soper));
395 			break;
396 
397 		case 0x06:		/* v2: DW_CFA_restore_extended, reg */
398 		case 0x0d:		/* v2: DW_CFA_def_cfa_register, reg */
399 		case 0x08:		/* v2: DW_CFA_same_value, reg */
400 		case 0x07:		/* v2: DW_CFA_undefined, reg */
401 			if (uleb_extract(&data[off], ndx, len, &oper1) ==
402 			    DW_OVERFLOW) {
403 				(void) fprintf(stderr,
404 				    MSG_INTL(MSG_ERR_DWOVRFLW),
405 				    state->file, state->sh_name);
406 				return;
407 			}
408 
409 			dbg_print(0, MSG_ORIG(MSG_CFA_REG), PREFIX,
410 			    REGNAME(oper1, rbuf1));
411 			break;
412 
413 
414 		case 0x09:		/* v2: DW_CFA_register, reg, reg */
415 			if (uleb_extract(&data[off], ndx, len, &oper1) ==
416 			    DW_OVERFLOW) {
417 				(void) fprintf(stderr,
418 				    MSG_INTL(MSG_ERR_DWOVRFLW),
419 				    state->file, state->sh_name);
420 				return;
421 			}
422 
423 			if (uleb_extract(&data[off], ndx, len, &oper2) ==
424 			    DW_OVERFLOW) {
425 				(void) fprintf(stderr,
426 				    MSG_INTL(MSG_ERR_DWOVRFLW),
427 				    state->file, state->sh_name);
428 				return;
429 			}
430 			dbg_print(0, MSG_ORIG(MSG_CFA_REG_REG), PREFIX,
431 			    REGNAME(oper1, rbuf1), REGNAME(oper2, rbuf2));
432 			break;
433 
434 		case 0x0c:		/* v2: DW_CFA_def_cfa, reg, offset */
435 			if (uleb_extract(&data[off], ndx, len, &oper1) ==
436 			    DW_OVERFLOW) {
437 				(void) fprintf(stderr,
438 				    MSG_INTL(MSG_ERR_DWOVRFLW),
439 				    state->file, state->sh_name);
440 				return;
441 			}
442 
443 			if (uleb_extract(&data[off], ndx, len, &oper2) ==
444 			    DW_OVERFLOW) {
445 				(void) fprintf(stderr,
446 				    MSG_INTL(MSG_ERR_DWOVRFLW),
447 				    state->file, state->sh_name);
448 				return;
449 			}
450 			dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLU), PREFIX,
451 			    REGNAME(oper1, rbuf1), EC_XWORD(oper2));
452 			break;
453 
454 		case 0x0e:		/* v2: DW_CFA_def_cfa_offset, offset */
455 			if (uleb_extract(&data[off], ndx, len, &oper1) ==
456 			    DW_OVERFLOW) {
457 				(void) fprintf(stderr,
458 				    MSG_INTL(MSG_ERR_DWOVRFLW),
459 				    state->file, state->sh_name);
460 				return;
461 			}
462 			dbg_print(0, MSG_ORIG(MSG_CFA_LLU), PREFIX,
463 			    EC_XWORD(oper1));
464 			break;
465 
466 		case 0x0f:		/* v3: DW_CFA_def_cfa_expression, blk */
467 			if (uleb_extract(&data[off], ndx, len, &oper1) ==
468 			    DW_OVERFLOW) {
469 				(void) fprintf(stderr,
470 				    MSG_INTL(MSG_ERR_DWOVRFLW),
471 				    state->file, state->sh_name);
472 				return;
473 			}
474 			dbg_print(0, MSG_ORIG(MSG_CFA_EBLK), PREFIX,
475 			    EC_XWORD(oper1));
476 			/* We currently do not decode the expression block */
477 			*ndx += oper1;
478 			break;
479 
480 		case 0x10:		/* v3: DW_CFA_expression, reg, blk */
481 		case 0x16:		/* v3: DW_CFA_val_expression,reg,blk */
482 			if (uleb_extract(&data[off], ndx, len, &oper1) ==
483 			    DW_OVERFLOW) {
484 				(void) fprintf(stderr,
485 				    MSG_INTL(MSG_ERR_DWOVRFLW),
486 				    state->file, state->sh_name);
487 				return;
488 			}
489 
490 			if (uleb_extract(&data[off], ndx, len, &oper2) ==
491 			    DW_OVERFLOW) {
492 				(void) fprintf(stderr,
493 				    MSG_INTL(MSG_ERR_DWOVRFLW),
494 				    state->file, state->sh_name);
495 				return;
496 			}
497 			dbg_print(0, MSG_ORIG(MSG_CFA_REG_EBLK), PREFIX,
498 			    REGNAME(oper1, rbuf1), EC_XWORD(oper2));
499 			/* We currently do not decode the expression block */
500 			*ndx += oper2;
501 			break;
502 
503 		case 0x11:	/* v3: DW_CFA_offset_extended_sf, reg, off */
504 			if (uleb_extract(&data[off], ndx, len, &oper1) ==
505 			    DW_OVERFLOW) {
506 				(void) fprintf(stderr,
507 				    MSG_INTL(MSG_ERR_DWOVRFLW),
508 				    state->file, state->sh_name);
509 				return;
510 			}
511 
512 			if (sleb_extract(&data[off], ndx, len, &soper) ==
513 			    DW_OVERFLOW) {
514 				(void) fprintf(stderr,
515 				    MSG_INTL(MSG_ERR_DWOVRFLW),
516 				    state->file, state->sh_name);
517 				return;
518 			}
519 
520 			soper *= state->ciedalign;
521 			dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
522 			    REGNAME(oper1, rbuf1), EC_SXWORD(soper));
523 			break;
524 
525 		case 0x12:		/* v3: DW_CFA_def_cfa_sf, reg, offset */
526 			if (uleb_extract(&data[off], ndx, len, &oper1) ==
527 			    DW_OVERFLOW) {
528 				(void) fprintf(stderr,
529 				    MSG_INTL(MSG_ERR_DWOVRFLW),
530 				    state->file, state->sh_name);
531 				return;
532 			}
533 
534 			if (sleb_extract(&data[off], ndx, len, &soper) ==
535 			    DW_OVERFLOW) {
536 				(void) fprintf(stderr,
537 				    MSG_INTL(MSG_ERR_DWOVRFLW),
538 				    state->file, state->sh_name);
539 				return;
540 			}
541 
542 			soper *= state->ciedalign;
543 			dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX,
544 			    REGNAME(oper1, rbuf1), EC_SXWORD(soper));
545 			break;
546 
547 		case 0x13:		/* DW_CFA_def_cfa_offset_sf, offset */
548 			if (sleb_extract(&data[off], ndx, len, &soper) ==
549 			    DW_OVERFLOW) {
550 				(void) fprintf(stderr,
551 				    MSG_INTL(MSG_ERR_DWOVRFLW),
552 				    state->file, state->sh_name);
553 				return;
554 			}
555 
556 			soper *= state->ciedalign;
557 			dbg_print(0, MSG_ORIG(MSG_CFA_LLD), PREFIX,
558 			    EC_SXWORD(soper));
559 			break;
560 
561 		case 0x14:		/* v3: DW_CFA_val_offset, reg, offset */
562 			if (uleb_extract(&data[off], ndx, len, &oper1) ==
563 			    DW_OVERFLOW) {
564 				(void) fprintf(stderr,
565 				    MSG_INTL(MSG_ERR_DWOVRFLW),
566 				    state->file, state->sh_name);
567 				return;
568 			}
569 
570 			if (sleb_extract(&data[off], ndx, len, &soper) ==
571 			    DW_OVERFLOW) {
572 				(void) fprintf(stderr,
573 				    MSG_INTL(MSG_ERR_DWOVRFLW),
574 				    state->file, state->sh_name);
575 				return;
576 			}
577 
578 			soper *= state->ciedalign;
579 			dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX,
580 			    REGNAME(oper1, rbuf1), EC_SXWORD(soper));
581 			break;
582 
583 		case 0x15:	/* v3: DW_CFA_val_offset_sf, reg, offset */
584 			if (uleb_extract(&data[off], ndx, len, &oper1) ==
585 			    DW_OVERFLOW) {
586 				(void) fprintf(stderr,
587 				    MSG_INTL(MSG_ERR_DWOVRFLW),
588 				    state->file, state->sh_name);
589 				return;
590 			}
591 
592 			if (sleb_extract(&data[off], ndx, len, &soper) ==
593 			    DW_OVERFLOW) {
594 				(void) fprintf(stderr,
595 				    MSG_INTL(MSG_ERR_DWOVRFLW),
596 				    state->file, state->sh_name);
597 				return;
598 			}
599 
600 			soper *= state->ciedalign;
601 			dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX,
602 			    REGNAME(oper1, rbuf1), EC_SXWORD(soper));
603 			break;
604 
605 		case 0x1d:	/* GNU: DW_CFA_MIPS_advance_loc8, delta */
606 			switch (dwarf_extract_uint(data + off, len,
607 			    ndx, 8, state->do_swap, &oper1)) {
608 			case DW_BAD_ENCODING:
609 				(void) fprintf(stderr,
610 				    MSG_INTL(MSG_ERR_DWBADENC),
611 				    state->file, state->sh_name,
612 				    8);
613 				return;
614 			case DW_OVERFLOW:
615 				(void) fprintf(stderr,
616 				    MSG_INTL(MSG_ERR_DWOVRFLW),
617 				    state->file, state->sh_name);
618 				return;
619 			case DW_SUCCESS:
620 				break;
621 			}
622 			oper1 *= state->ciecalign;
623 			cur_pc += oper1;
624 			dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX,
625 			    loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc));
626 			loc_str = MSG_ORIG(MSG_STR_LOC);
627 			break;
628 
629 		case 0x2e:		/* GNU: DW_CFA_GNU_args_size, size */
630 			if (uleb_extract(&data[off], ndx, len, &oper1) ==
631 			    DW_OVERFLOW) {
632 				(void) fprintf(stderr,
633 				    MSG_INTL(MSG_ERR_DWOVRFLW),
634 				    state->file, state->sh_name);
635 				return;
636 			}
637 
638 			dbg_print(0, MSG_ORIG(MSG_CFA_LLU), PREFIX,
639 			    EC_XWORD(oper1));
640 
641 			break;
642 
643 		case 0x2f: /* GNU:DW_CFA_GNU_negative_offset_extended,reg,off */
644 			if (uleb_extract(&data[off], ndx, len, &oper1) ==
645 			    DW_OVERFLOW) {
646 				(void) fprintf(stderr,
647 				    MSG_INTL(MSG_ERR_DWOVRFLW),
648 				    state->file, state->sh_name);
649 				return;
650 			}
651 
652 			if (sleb_extract(&data[off], ndx, len, &soper) ==
653 			    DW_OVERFLOW) {
654 				(void) fprintf(stderr,
655 				    MSG_INTL(MSG_ERR_DWOVRFLW),
656 				    state->file, state->sh_name);
657 				return;
658 			}
659 			soper = -soper * state->ciedalign;
660 			soper *= state->ciedalign;
661 			dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
662 			    REGNAME(oper1, rbuf1), EC_SXWORD(soper));
663 			break;
664 
665 		default:
666 			/*
667 			 * Unrecognized OP code: DWARF data is variable length,
668 			 * so we don't know how many bytes to skip in order to
669 			 * advance to the next item. We cannot decode beyond
670 			 * this point, so dump the remainder in hex.
671 			 */
672 			(*ndx)--;	/* Back up to unrecognized opcode */
673 			dump_hex_bytes(data + off + *ndx, len - *ndx,
674 			    indent, 8, 1);
675 			(*ndx) = len;
676 			break;
677 		}
678 	}
679 
680 #undef PREFIX
681 #undef REGNAME
682 #undef LOW_OP
683 }
684 
685 void
686 dump_eh_frame(const char *file, char *sh_name, uchar_t *data, size_t datasize,
687     uint64_t sh_addr, Half e_machine, uchar_t *e_ident, uint64_t gotaddr)
688 {
689 	Conv_dwarf_ehe_buf_t	dwarf_ehe_buf;
690 	dump_cfi_state_t	cfi_state;
691 	uint64_t	off, ndx, length, id;
692 	uint_t		cieid, cielength, cieversion, cieretaddr;
693 	int		ciePflag = 0, cieZflag = 0, cieLflag = 0;
694 	int		cieLflag_present = 0;
695 	uint_t		cieaugndx;
696 	char		*cieaugstr = NULL;
697 	boolean_t	have_cie = B_FALSE;
698 
699 	cfi_state.file = file;
700 	cfi_state.sh_name = sh_name;
701 	cfi_state.e_machine = e_machine;
702 	cfi_state.e_ident = e_ident;
703 	cfi_state.sh_addr = sh_addr;
704 	cfi_state.do_swap = _elf_sys_encoding() != e_ident[EI_DATA];
705 	cfi_state.gotaddr = gotaddr;
706 
707 	off = 0;
708 	while (off < datasize) {
709 		ndx = 0;
710 
711 		/*
712 		 * Extract length in native format.  A zero length indicates
713 		 * that this CIE is a terminator and that processing for this
714 		 * unwind information should end. However, skip this entry and
715 		 * keep processing, just in case there is any other information
716 		 * remaining in this section.  Note, ld(1) will terminate the
717 		 * processing of the .eh_frame contents for this file after a
718 		 * zero length CIE, thus any information that does follow is
719 		 * ignored by ld(1), and is therefore questionable.
720 		 */
721 		if (dwarf_extract_uint(data + off, datasize - off,
722 		    &ndx, 4, cfi_state.do_swap, &length) == DW_OVERFLOW) {
723 			(void) fprintf(stderr,
724 			    MSG_INTL(MSG_ERR_DWOVRFLW),
725 			    file, sh_name);
726 			return;
727 		}
728 
729 		if (length == 0) {
730 			dbg_print(0, MSG_ORIG(MSG_UNW_ZEROTERM));
731 			off += 4;
732 			continue;
733 		}
734 
735 		if (length > (datasize - off)) {
736 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADCIEFDELEN),
737 			    file, sh_name, EC_XWORD(length),
738 			    EC_XWORD(sh_addr + off));
739 			/*
740 			 * If length is wrong, we have no means to find the
741 			 * next entry, just give up
742 			 */
743 			return;
744 		}
745 
746 		/*
747 		 * extract CIE id in native format
748 		 */
749 		if (dwarf_extract_uint(data + off, datasize - off, &ndx,
750 		    4, cfi_state.do_swap, &id) == DW_OVERFLOW) {
751 			(void) fprintf(stderr,
752 			    MSG_INTL(MSG_ERR_DWOVRFLW),
753 			    file, sh_name);
754 			return;
755 		}
756 
757 		/*
758 		 * A CIE record has an id of '0', otherwise this is a
759 		 * FDE entry and the 'id' is the CIE pointer.
760 		 */
761 		if (id == 0) {
762 			uint64_t	persVal, ndx_save = 0;
763 			uint64_t	axsize;
764 
765 
766 			have_cie = B_TRUE;
767 			cielength = length;
768 			cieid = id;
769 			ciePflag = cfi_state.cieRflag = cieZflag = 0;
770 			cieLflag = cieLflag_present = 0;
771 
772 			dbg_print(0, MSG_ORIG(MSG_UNW_CIE),
773 			    EC_XWORD(sh_addr + off));
774 			dbg_print(0, MSG_ORIG(MSG_UNW_CIELNGTH),
775 			    cielength, cieid);
776 
777 			cieversion = data[off + ndx];
778 			ndx += 1;
779 			cieaugstr = (char *)(&data[off + ndx]);
780 			ndx += strlen(cieaugstr) + 1;
781 
782 			dbg_print(0, MSG_ORIG(MSG_UNW_CIEVERS),
783 			    cieversion, cieaugstr);
784 
785 			if (uleb_extract(&data[off], &ndx, datasize - off,
786 			    &cfi_state.ciecalign) == DW_OVERFLOW) {
787 				(void) fprintf(stderr,
788 				    MSG_INTL(MSG_ERR_DWOVRFLW),
789 				    file, sh_name);
790 				return;
791 			}
792 
793 			if (sleb_extract(&data[off], &ndx, datasize - off,
794 			    &cfi_state.ciedalign) == DW_OVERFLOW) {
795 				(void) fprintf(stderr,
796 				    MSG_INTL(MSG_ERR_DWOVRFLW),
797 				    file, sh_name);
798 				return;
799 			}
800 			cieretaddr = data[off + ndx];
801 			ndx += 1;
802 
803 			dbg_print(0, MSG_ORIG(MSG_UNW_CIECALGN),
804 			    EC_XWORD(cfi_state.ciecalign),
805 			    EC_XWORD(cfi_state.ciedalign), cieretaddr);
806 
807 			if (cieaugstr[0])
808 				dbg_print(0, MSG_ORIG(MSG_UNW_CIEAXVAL));
809 
810 			for (cieaugndx = 0; cieaugstr[cieaugndx]; cieaugndx++) {
811 				switch (cieaugstr[cieaugndx]) {
812 				case 'z':
813 					if (uleb_extract(&data[off], &ndx,
814 					    datasize - off, &axsize) ==
815 					    DW_OVERFLOW) {
816 						(void) fprintf(stderr,
817 						    MSG_INTL(MSG_ERR_DWOVRFLW),
818 						    file, sh_name);
819 						return;
820 					}
821 
822 					dbg_print(0, MSG_ORIG(MSG_UNW_CIEAXSIZ),
823 					    EC_XWORD(axsize));
824 					cieZflag = 1;
825 					/*
826 					 * The auxiliary section can contain
827 					 * unused padding bytes at the end, so
828 					 * save the current index. Along with
829 					 * axsize, we will use it to set ndx to
830 					 * the proper continuation index after
831 					 * the aux data has been processed.
832 					 */
833 					ndx_save = ndx;
834 					break;
835 				case 'P':
836 					ciePflag = data[off + ndx];
837 					ndx += 1;
838 
839 					switch (dwarf_ehe_extract(&data[off],
840 					    datasize - off, &ndx, &persVal,
841 					    ciePflag, e_ident, B_FALSE, sh_addr,
842 					    off + ndx, gotaddr)) {
843 					case DW_OVERFLOW:
844 						(void) fprintf(stderr,
845 						    MSG_INTL(MSG_ERR_DWOVRFLW),
846 						    file, sh_name);
847 						return;
848 					case DW_BAD_ENCODING:
849 						(void) fprintf(stderr,
850 						    MSG_INTL(MSG_ERR_DWBADENC),
851 						    file, sh_name, ciePflag);
852 						return;
853 					case DW_SUCCESS:
854 						break;
855 					}
856 					dbg_print(0,
857 					    MSG_ORIG(MSG_UNW_CIEAXPERS));
858 					dbg_print(0,
859 					    MSG_ORIG(MSG_UNW_CIEAXPERSENC),
860 					    ciePflag, conv_dwarf_ehe(ciePflag,
861 					    &dwarf_ehe_buf));
862 					dbg_print(0,
863 					    MSG_ORIG(MSG_UNW_CIEAXPERSRTN),
864 					    EC_XWORD(persVal));
865 					break;
866 				case 'R':
867 					cfi_state.cieRflag = data[off + ndx];
868 					ndx += 1;
869 					dbg_print(0,
870 					    MSG_ORIG(MSG_UNW_CIEAXCENC),
871 					    cfi_state.cieRflag,
872 					    conv_dwarf_ehe(cfi_state.cieRflag,
873 					    &dwarf_ehe_buf));
874 					break;
875 				case 'L':
876 					cieLflag_present = 1;
877 					cieLflag = data[off + ndx];
878 					ndx += 1;
879 					dbg_print(0,
880 					    MSG_ORIG(MSG_UNW_CIEAXLSDA),
881 					    cieLflag, conv_dwarf_ehe(
882 					    cieLflag, &dwarf_ehe_buf));
883 					break;
884 				default:
885 					dbg_print(0,
886 					    MSG_ORIG(MSG_UNW_CIEAXUNEC),
887 					    cieaugstr[cieaugndx]);
888 					break;
889 				}
890 			}
891 
892 			/*
893 			 * If the z flag was present, reposition ndx using the
894 			 * length given. This will safely move us past any
895 			 * unaccessed padding bytes in the auxiliary section.
896 			 */
897 			if (cieZflag)
898 				ndx = ndx_save + axsize;
899 
900 			/*
901 			 * Any remaining data are Call Frame Instructions
902 			 */
903 			if ((cielength + 4) > ndx)
904 				dump_cfi(data, off, &ndx, cielength, &cfi_state,
905 				    MSG_ORIG(MSG_UNW_CIECFI), 3);
906 			off += cielength + 4;
907 
908 		} else {
909 			uint_t	    fdelength = length;
910 			int	    fdecieptr = id;
911 			uint64_t    fdeaddrrange;
912 
913 			if (!have_cie) {
914 				(void) fprintf(stderr,
915 				    MSG_INTL(MSG_ERR_DWNOCIE), file, sh_name);
916 				return;
917 			}
918 
919 			dbg_print(0, MSG_ORIG(MSG_UNW_FDE),
920 			    EC_XWORD(sh_addr + off));
921 			dbg_print(0, MSG_ORIG(MSG_UNW_FDELNGTH),
922 			    fdelength, fdecieptr);
923 
924 			switch (dwarf_ehe_extract(&data[off], datasize - off,
925 			    &ndx, &cfi_state.fdeinitloc, cfi_state.cieRflag,
926 			    e_ident, B_FALSE, sh_addr, off + ndx, gotaddr)) {
927 			case DW_OVERFLOW:
928 				(void) fprintf(stderr,
929 				    MSG_INTL(MSG_ERR_DWOVRFLW), file, sh_name);
930 				return;
931 			case DW_BAD_ENCODING:
932 				(void) fprintf(stderr,
933 				    MSG_INTL(MSG_ERR_DWBADENC), file, sh_name,
934 				    cfi_state.cieRflag);
935 				return;
936 			case DW_SUCCESS:
937 				break;
938 			}
939 
940 			switch (dwarf_ehe_extract(&data[off], datasize - off,
941 			    &ndx, &fdeaddrrange,
942 			    (cfi_state.cieRflag & ~DW_EH_PE_pcrel), e_ident,
943 			    B_FALSE, sh_addr, off + ndx, gotaddr)) {
944 			case DW_OVERFLOW:
945 				(void) fprintf(stderr,
946 				    MSG_INTL(MSG_ERR_DWOVRFLW), file, sh_name);
947 				return;
948 			case DW_BAD_ENCODING:
949 				(void) fprintf(stderr,
950 				    MSG_INTL(MSG_ERR_DWBADENC), file, sh_name,
951 				    (cfi_state.cieRflag & ~DW_EH_PE_pcrel));
952 				return;
953 			case DW_SUCCESS:
954 				break;
955 			}
956 
957 			dbg_print(0, MSG_ORIG(MSG_UNW_FDEINITLOC),
958 			    EC_XWORD(cfi_state.fdeinitloc),
959 			    EC_XWORD(fdeaddrrange),
960 			    EC_XWORD(cfi_state.fdeinitloc + fdeaddrrange - 1));
961 
962 			if ((cieaugstr != NULL) && (cieaugstr[0] != '\0'))
963 				dbg_print(0, MSG_ORIG(MSG_UNW_FDEAXVAL));
964 			if (cieZflag) {
965 				uint64_t    val;
966 				uint64_t    lndx;
967 
968 				if (uleb_extract(&data[off], &ndx,
969 				    datasize - off, &val) == DW_OVERFLOW) {
970 					(void) fprintf(stderr,
971 					    MSG_INTL(MSG_ERR_DWOVRFLW),
972 					    file, sh_name);
973 					return;
974 				}
975 				lndx = ndx;
976 				ndx += val;
977 				dbg_print(0, MSG_ORIG(MSG_UNW_FDEAXSIZE),
978 				    EC_XWORD(val));
979 				if (val && cieLflag_present) {
980 					uint64_t    lsda;
981 
982 					switch (dwarf_ehe_extract(&data[off],
983 					    datasize - off, &lndx, &lsda,
984 					    cieLflag, e_ident, B_FALSE, sh_addr,
985 					    off + lndx, gotaddr)) {
986 					case DW_OVERFLOW:
987 						(void) fprintf(stderr,
988 						    MSG_INTL(MSG_ERR_DWOVRFLW),
989 						    file, sh_name);
990 						return;
991 					case DW_BAD_ENCODING:
992 						(void) fprintf(stderr,
993 						    MSG_INTL(MSG_ERR_DWBADENC),
994 						    file, sh_name, cieLflag);
995 						return;
996 					case DW_SUCCESS:
997 						break;
998 					}
999 					dbg_print(0,
1000 					    MSG_ORIG(MSG_UNW_FDEAXLSDA),
1001 					    EC_XWORD(lsda));
1002 				}
1003 			}
1004 			if ((fdelength + 4) > ndx)
1005 				dump_cfi(data, off, &ndx, fdelength, &cfi_state,
1006 				    MSG_ORIG(MSG_UNW_FDECFI), 6);
1007 			off += fdelength + 4;
1008 		}
1009 	}
1010 }
1011