Print this page
3265 link-editor builds bogus .eh_frame_hdr on ia32


  32 #include        <strings.h>
  33 #include        <debug.h>
  34 #include        <conv.h>
  35 #include        <msg.h>
  36 #include        <_elfdump.h>
  37 
  38 
  39 /*
  40  * Data from eh_frame section used by dump_cfi()
  41  */
  42 typedef struct {
  43         Half            e_machine;      /* ehdr->e_machine */
  44         uchar_t         *e_ident;       /* ehdr->e_ident */
  45         uint64_t        sh_addr;        /* Address of eh_frame section */
  46         int             do_swap;        /* True if object and system byte */
  47                                         /*      order differs */
  48         int             cieRflag;       /* R flag from current CIE */
  49         uint64_t        ciecalign;      /* CIE code align factor */
  50         int64_t         ciedalign;      /* CIE data align factor */
  51         uint64_t        fdeinitloc;     /* FDE initial location */

  52 } dump_cfi_state_t;
  53 
  54 
  55 /*
  56  * Extract an unsigned integer value from an .eh_frame section, converting it
  57  * from its native byte order to that of the running machine if necessary.
  58  *
  59  * entry:
  60  *      data - Base address from which to extract datum
  61  *      ndx - Address of variable giving index to start byte in data.
  62  *      size - # of bytes in datum. Must be one of: 1, 2, 4, 8
  63  *      do_swap - True if the data is in a different byte order than that
  64  *              of the host system.
  65  *
  66  * exit:
  67  *      *ndx is incremented by the size of the extracted datum.
  68  *
  69  *      The requested datum is extracted, byte swapped if necessary,
  70  *      and returned.
  71  */


 284                          * No-ops are used to fill unused space required
 285                          * for alignment. It is common for there to be
 286                          * multiple adjacent nops. It saves space to report
 287                          * them all with a single line of output.
 288                          */
 289                         for (i = 1;
 290                             (*ndx < len) && (data[off + *ndx] == 0);
 291                             i++, (*ndx)++)
 292                                 ;
 293                         dbg_print(0, MSG_ORIG(MSG_CFA_SIMPLEREP), PREFIX, i);
 294                         break;
 295 
 296                 case 0x0a:              /* v2: DW_CFA_remember_state */
 297                 case 0x0b:              /* v2: DW_CFA_restore_state */
 298                 case 0x2d:              /* GNU: DW_CFA_GNU_window_save */
 299                         dbg_print(0, MSG_ORIG(MSG_CFA_SIMPLE), PREFIX);
 300                         break;
 301 
 302                 case 0x01:              /* v2: DW_CFA_set_loc, address */
 303                         cur_pc = dwarf_ehe_extract(&data[off], ndx,
 304                             state->cieRflag, state->e_ident,
 305                             state->sh_addr, off + *ndx);
 306                         dbg_print(0, MSG_ORIG(MSG_CFA_CFASET), PREFIX,
 307                             EC_XWORD(cur_pc));
 308                         break;
 309 
 310                 case 0x02:      /* v2: DW_CFA_advance_loc_1, 1-byte delta */
 311                 case 0x03:      /* v2: DW_CFA_advance_loc_2, 2-byte delta */
 312                 case 0x04:      /* v2: DW_CFA_advance_loc_4, 4-byte delta */
 313                         /*
 314                          * Since the codes are contiguous, and the sizes are
 315                          * powers of 2, we can compute the word width from
 316                          * the code.
 317                          */
 318                         i = 1 << (op - 0x02);
 319                         oper1 = dwarf_extract_uint(data + off, ndx, i,
 320                             state->do_swap) * state->ciecalign;
 321                         cur_pc += oper1;
 322                         dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX,
 323                             loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc));
 324                         loc_str = MSG_ORIG(MSG_STR_LOC);
 325                         break;


 448                          * Unrecognized OP code: DWARF data is variable length,
 449                          * so we don't know how many bytes to skip in order to
 450                          * advance to the next item. We cannot decode beyond
 451                          * this point, so dump the remainder in hex.
 452                          */
 453                         (*ndx)--;       /* Back up to unrecognized opcode */
 454                         dump_hex_bytes(data + off + *ndx, len - *ndx,
 455                             indent, 8, 1);
 456                         (*ndx) = len;
 457                         break;
 458                 }
 459         }
 460 
 461 #undef PREFIX
 462 #undef REGNAME
 463 #undef LOW_OP
 464 }
 465 
 466 void
 467 dump_eh_frame(uchar_t *data, size_t datasize, uint64_t sh_addr,
 468     Half e_machine, uchar_t *e_ident)
 469 {
 470         Conv_dwarf_ehe_buf_t    dwarf_ehe_buf;
 471         dump_cfi_state_t        cfi_state;
 472         uint64_t        off, ndx;
 473         uint_t          cieid, cielength, cieversion, cieretaddr;
 474         int             ciePflag, cieZflag, cieLflag, cieLflag_present;
 475         uint_t          cieaugndx, length, id;
 476         char            *cieaugstr;
 477 
 478         cfi_state.e_machine = e_machine;
 479         cfi_state.e_ident = e_ident;
 480         cfi_state.sh_addr = sh_addr;
 481         cfi_state.do_swap = _elf_sys_encoding() != e_ident[EI_DATA];

 482 
 483         off = 0;
 484         while (off < datasize) {
 485                 ndx = 0;
 486 
 487                 /*
 488                  * Extract length in native format.  A zero length indicates
 489                  * that this CIE is a terminator and that processing for this
 490                  * unwind information should end. However, skip this entry and
 491                  * keep processing, just in case there is any other information
 492                  * remaining in this section.  Note, ld(1) will terminate the
 493                  * processing of the .eh_frame contents for this file after a
 494                  * zero length CIE, thus any information that does follow is
 495                  * ignored by ld(1), and is therefore questionable.
 496                  */
 497                 length = (uint_t)dwarf_extract_uint(data + off, &ndx,
 498                     4, cfi_state.do_swap);
 499                 if (length == 0) {
 500                         dbg_print(0, MSG_ORIG(MSG_UNW_ZEROTERM));
 501                         off += 4;


 551                                 case 'z':
 552                                         axsize = uleb_extract(&data[off], &ndx);
 553                                         dbg_print(0, MSG_ORIG(MSG_UNW_CIEAXSIZ),
 554                                             axsize);
 555                                         cieZflag = 1;
 556                                         /*
 557                                          * The auxiliary section can contain
 558                                          * unused padding bytes at the end, so
 559                                          * save the current index. Along with
 560                                          * axsize, we will use it to set ndx to
 561                                          * the proper continuation index after
 562                                          * the aux data has been processed.
 563                                          */
 564                                         ndx_save = ndx;
 565                                         break;
 566                                 case 'P':
 567                                         ciePflag = data[off + ndx];
 568                                         ndx += 1;
 569 
 570                                         persVal = dwarf_ehe_extract(&data[off],
 571                                             &ndx, ciePflag, e_ident,
 572                                             sh_addr, off + ndx);
 573                                         dbg_print(0,
 574                                             MSG_ORIG(MSG_UNW_CIEAXPERS));
 575                                         dbg_print(0,
 576                                             MSG_ORIG(MSG_UNW_CIEAXPERSENC),
 577                                             ciePflag, conv_dwarf_ehe(ciePflag,
 578                                             &dwarf_ehe_buf));
 579                                         dbg_print(0,
 580                                             MSG_ORIG(MSG_UNW_CIEAXPERSRTN),
 581                                             EC_XWORD(persVal));
 582                                         break;
 583                                 case 'R':
 584                                         cfi_state.cieRflag = data[off + ndx];
 585                                         ndx += 1;
 586                                         dbg_print(0,
 587                                             MSG_ORIG(MSG_UNW_CIEAXCENC),
 588                                             cfi_state.cieRflag,
 589                                             conv_dwarf_ehe(cfi_state.cieRflag,
 590                                             &dwarf_ehe_buf));
 591                                         break;
 592                                 case 'L':


 616 
 617                         /*
 618                          * Any remaining data are Call Frame Instructions
 619                          */
 620                         if ((cielength + 4) > ndx)
 621                                 dump_cfi(data, off, &ndx, cielength, &cfi_state,
 622                                     MSG_ORIG(MSG_UNW_CIECFI), 3);
 623                         off += cielength + 4;
 624 
 625                 } else {
 626                         uint_t      fdelength = length;
 627                         int         fdecieptr = id;
 628                         uint64_t    fdeaddrrange;
 629 
 630                         dbg_print(0, MSG_ORIG(MSG_UNW_FDE),
 631                             EC_XWORD(sh_addr + off));
 632                         dbg_print(0, MSG_ORIG(MSG_UNW_FDELNGTH),
 633                             fdelength, fdecieptr);
 634 
 635                         cfi_state.fdeinitloc = dwarf_ehe_extract(&data[off],
 636                             &ndx, cfi_state.cieRflag, e_ident,
 637                             sh_addr, off + ndx);
 638                         fdeaddrrange = dwarf_ehe_extract(&data[off], &ndx,
 639                             (cfi_state.cieRflag & ~DW_EH_PE_pcrel),
 640                             e_ident, sh_addr, off + ndx);
 641 
 642                         dbg_print(0, MSG_ORIG(MSG_UNW_FDEINITLOC),
 643                             EC_XWORD(cfi_state.fdeinitloc),
 644                             EC_XWORD(fdeaddrrange),
 645                             EC_XWORD(cfi_state.fdeinitloc + fdeaddrrange - 1));
 646 
 647                         if (cieaugstr[0])
 648                                 dbg_print(0, MSG_ORIG(MSG_UNW_FDEAXVAL));
 649                         if (cieZflag) {
 650                                 uint64_t    val;
 651                                 uint64_t    lndx;
 652 
 653                                 val = uleb_extract(&data[off], &ndx);
 654                                 lndx = ndx;
 655                                 ndx += val;
 656                                 dbg_print(0, MSG_ORIG(MSG_UNW_FDEAXSIZE),
 657                                     EC_XWORD(val));
 658                                 if (val && cieLflag_present) {
 659                                         uint64_t    lsda;
 660 
 661                                         lsda = dwarf_ehe_extract(&data[off],
 662                                             &lndx, cieLflag, e_ident,
 663                                             sh_addr, off + lndx);

 664                                         dbg_print(0,
 665                                             MSG_ORIG(MSG_UNW_FDEAXLSDA),
 666                                             EC_XWORD(lsda));
 667                                 }
 668                         }
 669                         if ((fdelength + 4) > ndx)
 670                                 dump_cfi(data, off, &ndx, fdelength, &cfi_state,
 671                                     MSG_ORIG(MSG_UNW_FDECFI), 6);
 672                         off += fdelength + 4;
 673                 }
 674         }
 675 }


  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  */


 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;


 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;


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


 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 }