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 }