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