Print this page
5688 ELF tools need to be more careful with dwarf data


  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 *


 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.


 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':


 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 }


  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 *


 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.


 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':


 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 }