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