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

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/sgs/elfdump/common/dwarf.c
          +++ new/usr/src/cmd/sgs/elfdump/common/dwarf.c
↓ open down ↓ 32 lines elided ↑ open up ↑
  33   33  #include        <debug.h>
  34   34  #include        <conv.h>
  35   35  #include        <msg.h>
  36   36  #include        <_elfdump.h>
  37   37  
  38   38  
  39   39  /*
  40   40   * Data from eh_frame section used by dump_cfi()
  41   41   */
  42   42  typedef struct {
       43 +        const char      *file;
       44 +        const char      *sh_name;
  43   45          Half            e_machine;      /* ehdr->e_machine */
  44   46          uchar_t         *e_ident;       /* ehdr->e_ident */
  45   47          uint64_t        sh_addr;        /* Address of eh_frame section */
  46   48          int             do_swap;        /* True if object and system byte */
  47   49                                          /*      order differs */
  48   50          int             cieRflag;       /* R flag from current CIE */
  49   51          uint64_t        ciecalign;      /* CIE code align factor */
  50   52          int64_t         ciedalign;      /* CIE data align factor */
  51   53          uint64_t        fdeinitloc;     /* FDE initial location */
  52   54          uint64_t        gotaddr;        /* Address of the GOT */
↓ open down ↓ 10 lines elided ↑ open up ↑
  63   65   *      size - # of bytes in datum. Must be one of: 1, 2, 4, 8
  64   66   *      do_swap - True if the data is in a different byte order than that
  65   67   *              of the host system.
  66   68   *
  67   69   * exit:
  68   70   *      *ndx is incremented by the size of the extracted datum.
  69   71   *
  70   72   *      The requested datum is extracted, byte swapped if necessary,
  71   73   *      and returned.
  72   74   */
  73      -static uint64_t
  74      -dwarf_extract_uint(uchar_t *data, uint64_t *ndx, int size, int do_swap)
       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)
  75   78  {
       79 +        if (((*ndx + size) > len) ||
       80 +            ((*ndx + size) < *ndx))
       81 +                return (DW_OVERFLOW);
       82 +
  76   83          switch (size) {
  77   84          case 1:
  78      -                return (data[(*ndx)++]);
       85 +                *ret = (data[(*ndx)++]);
       86 +                return (DW_SUCCESS);
  79   87          case 2:
  80   88                  {
  81   89                          Half    r;
  82   90                          uchar_t *p = (uchar_t *)&r;
  83   91  
  84   92                          data += *ndx;
  85   93                          if (do_swap)
  86   94                                  UL_ASSIGN_BSWAP_HALF(p, data);
  87   95                          else
  88   96                                  UL_ASSIGN_HALF(p, data);
  89   97  
  90   98                          (*ndx) += 2;
  91      -                        return (r);
       99 +                        *ret = r;
      100 +                        return (DW_SUCCESS);
  92  101                  }
  93  102          case 4:
  94  103                  {
  95  104                          Word    r;
  96  105                          uchar_t *p = (uchar_t *)&r;
  97  106  
  98  107                          data += *ndx;
  99  108                          if (do_swap)
 100  109                                  UL_ASSIGN_BSWAP_WORD(p, data);
 101  110                          else
 102  111                                  UL_ASSIGN_WORD(p, data);
 103  112  
 104  113                          (*ndx) += 4;
 105      -                        return (r);
      114 +                        *ret = r;
      115 +                        return (DW_SUCCESS);
 106  116                  }
 107  117  
 108  118          case 8:
 109  119                  {
 110  120                          uint64_t        r;
 111  121                          uchar_t         *p = (uchar_t *)&r;
 112  122  
 113  123                          data += *ndx;
 114  124                          if (do_swap)
 115  125                                  UL_ASSIGN_BSWAP_LWORD(p, data);
 116  126                          else
 117  127                                  UL_ASSIGN_LWORD(p, data);
 118  128  
 119  129                          (*ndx) += 8;
 120      -                        return (r);
      130 +                        *ret = r;
      131 +                        return (DW_SUCCESS);
 121  132                  }
      133 +        default:
      134 +                return (DW_BAD_ENCODING);
 122  135          }
 123  136  
 124      -        /* If here, an invalid size was specified */
 125      -        assert(0);
 126      -        return (0);
      137 +        /* NOTREACHED */
 127  138  }
 128  139  
 129  140  /*
 130  141   * Map a DWARF register constant to the machine register name it
 131  142   * corresponds to, formatting the result into buf.
 132  143   *
 133  144   * The assignment of DWARF register numbers is part of the system
 134  145   * specific ABI for each platform.
 135  146   *
 136  147   * entry:
↓ open down ↓ 32 lines elided ↑ open up ↑
 169  180  
 170  181  
 171  182  /*
 172  183   * Decode eh_frame Call Frame Instructions, printing each one on a
 173  184   * separate line.
 174  185   *
 175  186   * entry:
 176  187   *      data - Address of base of eh_frame section being processed
 177  188   *      off - Offset of current FDE within eh_frame
 178  189   *      ndx - Index of current position within current FDE
 179      - *      len - Length of eh_frame section
      190 + *      len - Length of FDE
 180  191   *      state - Object, CIE, and FDE state for current request
 181  192   *      msg - Header message to issue before producing output.
 182  193   *      indent - # of indentation characters issued for each line of output.
 183  194   *
 184  195   * exit:
 185  196   *      The Call Frame Instructions have been decoded and printed.
 186  197   *
 187  198   *      *ndx has been incremented to contain the index of the next
 188  199   *              byte of data to be processed in eh_frame.
 189  200   *
↓ open down ↓ 66 lines elided ↑ open up ↑
 256  267                  switch (op >> 6) {
 257  268                  case 0x1:               /* v2: DW_CFA_advance_loc, delta */
 258  269                          oper1 = state->ciecalign * LOW_OP(op);
 259  270                          cur_pc += oper1;
 260  271                          dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX,
 261  272                              loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc));
 262  273                          loc_str = MSG_ORIG(MSG_STR_LOC);
 263  274                          continue;
 264  275  
 265  276                  case 0x2:               /* v2: DW_CFA_offset, reg, offset */
 266      -                        soper = uleb_extract(&data[off], ndx) *
 267      -                            state->ciedalign;
      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;
 268  286                          dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
 269      -                            REGNAME(LOW_OP(op), rbuf1), EC_SXWORD(soper));
      287 +                            REGNAME(LOW_OP(op), rbuf1), EC_XWORD(oper1));
 270  288                          continue;
 271  289  
 272  290                  case 0x3:               /* v2: DW_CFA_restore, reg */
 273  291                          dbg_print(0, MSG_ORIG(MSG_CFA_REG), PREFIX,
 274  292                              REGNAME(LOW_OP(op), rbuf1));
 275  293                          continue;
 276  294                  }
 277  295  
 278  296                  /*
 279  297                   * If we're here, the high order 2 bits are 0. The low 6 bits
↓ open down ↓ 14 lines elided ↑ open up ↑
 294  312                          dbg_print(0, MSG_ORIG(MSG_CFA_SIMPLEREP), PREFIX, i);
 295  313                          break;
 296  314  
 297  315                  case 0x0a:              /* v2: DW_CFA_remember_state */
 298  316                  case 0x0b:              /* v2: DW_CFA_restore_state */
 299  317                  case 0x2d:              /* GNU: DW_CFA_GNU_window_save */
 300  318                          dbg_print(0, MSG_ORIG(MSG_CFA_SIMPLE), PREFIX);
 301  319                          break;
 302  320  
 303  321                  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);
      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 +                        }
 307  339                          dbg_print(0, MSG_ORIG(MSG_CFA_CFASET), PREFIX,
 308  340                              EC_XWORD(cur_pc));
 309  341                          break;
 310  342  
 311  343                  case 0x02:      /* v2: DW_CFA_advance_loc_1, 1-byte delta */
 312  344                  case 0x03:      /* v2: DW_CFA_advance_loc_2, 2-byte delta */
 313  345                  case 0x04:      /* v2: DW_CFA_advance_loc_4, 4-byte delta */
 314  346                          /*
 315  347                           * Since the codes are contiguous, and the sizes are
 316  348                           * powers of 2, we can compute the word width from
 317  349                           * the code.
 318  350                           */
 319  351                          i = 1 << (op - 0x02);
 320      -                        oper1 = dwarf_extract_uint(data + off, ndx, i,
 321      -                            state->do_swap) * state->ciecalign;
      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;
 322  369                          cur_pc += oper1;
 323  370                          dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX,
 324  371                              loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc));
 325  372                          loc_str = MSG_ORIG(MSG_STR_LOC);
 326  373                          break;
 327  374  
 328  375                  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;
      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;
 332  393                          dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
 333  394                              REGNAME(oper1, rbuf1), EC_SXWORD(soper));
 334  395                          break;
 335  396  
 336  397                  case 0x06:              /* v2: DW_CFA_restore_extended, reg */
 337  398                  case 0x0d:              /* v2: DW_CFA_def_cfa_register, reg */
 338  399                  case 0x08:              /* v2: DW_CFA_same_value, reg */
 339  400                  case 0x07:              /* v2: DW_CFA_undefined, reg */
 340      -                        oper1 = uleb_extract(&data[off], ndx);
      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 +
 341  409                          dbg_print(0, MSG_ORIG(MSG_CFA_REG), PREFIX,
 342  410                              REGNAME(oper1, rbuf1));
 343  411                          break;
 344  412  
 345  413  
 346  414                  case 0x09:              /* v2: DW_CFA_register, reg, reg */
 347      -                        oper1 = uleb_extract(&data[off], ndx);
 348      -                        oper2 = uleb_extract(&data[off], ndx);
      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 +                        }
 349  430                          dbg_print(0, MSG_ORIG(MSG_CFA_REG_REG), PREFIX,
 350  431                              REGNAME(oper1, rbuf1), REGNAME(oper2, rbuf2));
 351  432                          break;
 352  433  
 353  434                  case 0x0c:              /* v2: DW_CFA_def_cfa, reg, offset */
 354      -                        oper1 = uleb_extract(&data[off], ndx);
 355      -                        oper2 = uleb_extract(&data[off], ndx);
      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 +                        }
 356  450                          dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLU), PREFIX,
 357  451                              REGNAME(oper1, rbuf1), EC_XWORD(oper2));
 358  452                          break;
 359  453  
 360  454                  case 0x0e:              /* v2: DW_CFA_def_cfa_offset, offset */
 361      -                        oper1 = uleb_extract(&data[off], ndx);
      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 +                        }
 362  462                          dbg_print(0, MSG_ORIG(MSG_CFA_LLU), PREFIX,
 363  463                              EC_XWORD(oper1));
 364  464                          break;
 365  465  
 366  466                  case 0x0f:              /* v3: DW_CFA_def_cfa_expression, blk */
 367      -                        oper1 = uleb_extract(&data[off], ndx);
      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 +                        }
 368  474                          dbg_print(0, MSG_ORIG(MSG_CFA_EBLK), PREFIX,
 369  475                              EC_XWORD(oper1));
 370  476                          /* We currently do not decode the expression block */
 371  477                          *ndx += oper1;
 372  478                          break;
 373  479  
 374  480                  case 0x10:              /* v3: DW_CFA_expression, reg, blk */
 375  481                  case 0x16:              /* v3: DW_CFA_val_expression,reg,blk */
 376      -                        oper1 = uleb_extract(&data[off], ndx);
 377      -                        oper2 = uleb_extract(&data[off], ndx);
      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 +                        }
 378  497                          dbg_print(0, MSG_ORIG(MSG_CFA_REG_EBLK), PREFIX,
 379  498                              REGNAME(oper1, rbuf1), EC_XWORD(oper2));
 380  499                          /* We currently do not decode the expression block */
 381  500                          *ndx += oper2;
 382  501                          break;
 383  502  
 384  503                  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;
      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;
 388  521                          dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
 389  522                              REGNAME(oper1, rbuf1), EC_SXWORD(soper));
 390  523                          break;
 391  524  
 392  525                  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;
      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;
 396  543                          dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX,
 397  544                              REGNAME(oper1, rbuf1), EC_SXWORD(soper));
 398  545                          break;
 399  546  
 400  547                  case 0x13:              /* DW_CFA_def_cfa_offset_sf, offset */
 401      -                        soper = sleb_extract(&data[off], ndx) *
 402      -                            state->ciedalign;
      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;
 403  557                          dbg_print(0, MSG_ORIG(MSG_CFA_LLD), PREFIX,
 404  558                              EC_SXWORD(soper));
 405  559                          break;
 406  560  
 407  561                  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;
      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;
 411  579                          dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX,
 412  580                              REGNAME(oper1, rbuf1), EC_SXWORD(soper));
 413  581                          break;
 414  582  
 415  583                  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;
      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;
 419  601                          dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX,
 420  602                              REGNAME(oper1, rbuf1), EC_SXWORD(soper));
 421  603                          break;
 422  604  
 423  605                  case 0x1d:      /* GNU: DW_CFA_MIPS_advance_loc8, delta */
 424      -                        oper1 = dwarf_extract_uint(data + off, ndx, i,
 425      -                            state->do_swap) * state->ciecalign;
      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;
 426  623                          cur_pc += oper1;
 427  624                          dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX,
 428  625                              loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc));
 429  626                          loc_str = MSG_ORIG(MSG_STR_LOC);
 430  627                          break;
 431  628  
 432  629                  case 0x2e:              /* GNU: DW_CFA_GNU_args_size, size */
 433      -                        oper1 = uleb_extract(&data[off], ndx);
      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 +
 434  638                          dbg_print(0, MSG_ORIG(MSG_CFA_LLU), PREFIX,
 435  639                              EC_XWORD(oper1));
 436  640  
 437  641                          break;
 438  642  
 439  643                  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;
      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;
 443  661                          dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
 444  662                              REGNAME(oper1, rbuf1), EC_SXWORD(soper));
 445  663                          break;
 446  664  
 447  665                  default:
 448  666                          /*
 449  667                           * Unrecognized OP code: DWARF data is variable length,
 450  668                           * so we don't know how many bytes to skip in order to
 451  669                           * advance to the next item. We cannot decode beyond
 452  670                           * this point, so dump the remainder in hex.
↓ open down ↓ 5 lines elided ↑ open up ↑
 458  676                          break;
 459  677                  }
 460  678          }
 461  679  
 462  680  #undef PREFIX
 463  681  #undef REGNAME
 464  682  #undef LOW_OP
 465  683  }
 466  684  
 467  685  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)
      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)
 470  688  {
 471  689          Conv_dwarf_ehe_buf_t    dwarf_ehe_buf;
 472  690          dump_cfi_state_t        cfi_state;
 473      -        uint64_t        off, ndx;
      691 +        uint64_t        off, ndx, length, id;
 474  692          uint_t          cieid, cielength, cieversion, cieretaddr;
 475      -        int             ciePflag, cieZflag, cieLflag, cieLflag_present;
 476      -        uint_t          cieaugndx, length, id;
 477      -        char            *cieaugstr;
      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;
 478  698  
      699 +        cfi_state.file = file;
      700 +        cfi_state.sh_name = sh_name;
 479  701          cfi_state.e_machine = e_machine;
 480  702          cfi_state.e_ident = e_ident;
 481  703          cfi_state.sh_addr = sh_addr;
 482  704          cfi_state.do_swap = _elf_sys_encoding() != e_ident[EI_DATA];
 483  705          cfi_state.gotaddr = gotaddr;
 484  706  
 485  707          off = 0;
 486  708          while (off < datasize) {
 487  709                  ndx = 0;
 488  710  
 489  711                  /*
 490  712                   * Extract length in native format.  A zero length indicates
 491  713                   * that this CIE is a terminator and that processing for this
 492  714                   * unwind information should end. However, skip this entry and
 493  715                   * keep processing, just in case there is any other information
 494  716                   * remaining in this section.  Note, ld(1) will terminate the
 495  717                   * processing of the .eh_frame contents for this file after a
 496  718                   * zero length CIE, thus any information that does follow is
 497  719                   * ignored by ld(1), and is therefore questionable.
 498  720                   */
 499      -                length = (uint_t)dwarf_extract_uint(data + off, &ndx,
 500      -                    4, cfi_state.do_swap);
      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 +
 501  729                  if (length == 0) {
 502  730                          dbg_print(0, MSG_ORIG(MSG_UNW_ZEROTERM));
 503  731                          off += 4;
 504  732                          continue;
 505  733                  }
 506  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 +
 507  746                  /*
 508  747                   * extract CIE id in native format
 509  748                   */
 510      -                id = (uint_t)dwarf_extract_uint(data + off, &ndx,
 511      -                    4, cfi_state.do_swap);
      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 +                }
 512  756  
 513  757                  /*
 514  758                   * A CIE record has an id of '0', otherwise this is a
 515  759                   * FDE entry and the 'id' is the CIE pointer.
 516  760                   */
 517  761                  if (id == 0) {
 518      -                        uint64_t        persVal, ndx_save;
 519      -                        uint_t          axsize;
      762 +                        uint64_t        persVal, ndx_save = 0;
      763 +                        uint64_t        axsize;
 520  764  
      765 +
      766 +                        have_cie = B_TRUE;
 521  767                          cielength = length;
 522  768                          cieid = id;
 523  769                          ciePflag = cfi_state.cieRflag = cieZflag = 0;
 524  770                          cieLflag = cieLflag_present = 0;
 525  771  
 526  772                          dbg_print(0, MSG_ORIG(MSG_UNW_CIE),
 527  773                              EC_XWORD(sh_addr + off));
 528  774                          dbg_print(0, MSG_ORIG(MSG_UNW_CIELNGTH),
 529  775                              cielength, cieid);
 530  776  
 531  777                          cieversion = data[off + ndx];
 532  778                          ndx += 1;
 533  779                          cieaugstr = (char *)(&data[off + ndx]);
 534  780                          ndx += strlen(cieaugstr) + 1;
 535  781  
 536  782                          dbg_print(0, MSG_ORIG(MSG_UNW_CIEVERS),
 537  783                              cieversion, cieaugstr);
 538  784  
 539      -                        cfi_state.ciecalign = uleb_extract(&data[off], &ndx);
 540      -                        cfi_state.ciedalign = sleb_extract(&data[off], &ndx);
      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 +                        }
 541  800                          cieretaddr = data[off + ndx];
 542  801                          ndx += 1;
 543  802  
 544  803                          dbg_print(0, MSG_ORIG(MSG_UNW_CIECALGN),
 545  804                              EC_XWORD(cfi_state.ciecalign),
 546  805                              EC_XWORD(cfi_state.ciedalign), cieretaddr);
 547  806  
 548  807                          if (cieaugstr[0])
 549  808                                  dbg_print(0, MSG_ORIG(MSG_UNW_CIEAXVAL));
 550  809  
 551  810                          for (cieaugndx = 0; cieaugstr[cieaugndx]; cieaugndx++) {
 552  811                                  switch (cieaugstr[cieaugndx]) {
 553  812                                  case 'z':
 554      -                                        axsize = uleb_extract(&data[off], &ndx);
      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 +
 555  822                                          dbg_print(0, MSG_ORIG(MSG_UNW_CIEAXSIZ),
 556      -                                            axsize);
      823 +                                            EC_XWORD(axsize));
 557  824                                          cieZflag = 1;
 558  825                                          /*
 559  826                                           * The auxiliary section can contain
 560  827                                           * unused padding bytes at the end, so
 561  828                                           * save the current index. Along with
 562  829                                           * axsize, we will use it to set ndx to
 563  830                                           * the proper continuation index after
 564  831                                           * the aux data has been processed.
 565  832                                           */
 566  833                                          ndx_save = ndx;
 567  834                                          break;
 568  835                                  case 'P':
 569  836                                          ciePflag = data[off + ndx];
 570  837                                          ndx += 1;
 571  838  
 572      -                                        persVal = dwarf_ehe_extract(&data[off],
 573      -                                            &ndx, ciePflag, e_ident, B_FALSE,
 574      -                                            sh_addr, off + ndx, gotaddr);
      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 +                                        }
 575  856                                          dbg_print(0,
 576  857                                              MSG_ORIG(MSG_UNW_CIEAXPERS));
 577  858                                          dbg_print(0,
 578  859                                              MSG_ORIG(MSG_UNW_CIEAXPERSENC),
 579  860                                              ciePflag, conv_dwarf_ehe(ciePflag,
 580  861                                              &dwarf_ehe_buf));
 581  862                                          dbg_print(0,
 582  863                                              MSG_ORIG(MSG_UNW_CIEAXPERSRTN),
 583  864                                              EC_XWORD(persVal));
 584  865                                          break;
↓ open down ↓ 37 lines elided ↑ open up ↑
 622  903                          if ((cielength + 4) > ndx)
 623  904                                  dump_cfi(data, off, &ndx, cielength, &cfi_state,
 624  905                                      MSG_ORIG(MSG_UNW_CIECFI), 3);
 625  906                          off += cielength + 4;
 626  907  
 627  908                  } else {
 628  909                          uint_t      fdelength = length;
 629  910                          int         fdecieptr = id;
 630  911                          uint64_t    fdeaddrrange;
 631  912  
      913 +                        if (!have_cie) {
      914 +                                (void) fprintf(stderr,
      915 +                                    MSG_INTL(MSG_ERR_DWNOCIE), file, sh_name);
      916 +                                return;
      917 +                        }
      918 +
 632  919                          dbg_print(0, MSG_ORIG(MSG_UNW_FDE),
 633  920                              EC_XWORD(sh_addr + off));
 634  921                          dbg_print(0, MSG_ORIG(MSG_UNW_FDELNGTH),
 635  922                              fdelength, fdecieptr);
 636  923  
 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);
      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 +                        }
 643  956  
 644  957                          dbg_print(0, MSG_ORIG(MSG_UNW_FDEINITLOC),
 645  958                              EC_XWORD(cfi_state.fdeinitloc),
 646  959                              EC_XWORD(fdeaddrrange),
 647  960                              EC_XWORD(cfi_state.fdeinitloc + fdeaddrrange - 1));
 648  961  
 649      -                        if (cieaugstr[0])
      962 +                        if ((cieaugstr != NULL) && (cieaugstr[0] != '\0'))
 650  963                                  dbg_print(0, MSG_ORIG(MSG_UNW_FDEAXVAL));
 651  964                          if (cieZflag) {
 652  965                                  uint64_t    val;
 653  966                                  uint64_t    lndx;
 654  967  
 655      -                                val = uleb_extract(&data[off], &ndx);
      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 +                                }
 656  975                                  lndx = ndx;
 657  976                                  ndx += val;
 658  977                                  dbg_print(0, MSG_ORIG(MSG_UNW_FDEAXSIZE),
 659  978                                      EC_XWORD(val));
 660  979                                  if (val && cieLflag_present) {
 661  980                                          uint64_t    lsda;
 662  981  
 663      -                                        lsda = dwarf_ehe_extract(&data[off],
 664      -                                            &lndx, cieLflag, e_ident,
 665      -                                            B_FALSE, sh_addr, off + lndx,
 666      -                                            gotaddr);
      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 +                                        }
 667  999                                          dbg_print(0,
 668 1000                                              MSG_ORIG(MSG_UNW_FDEAXLSDA),
 669 1001                                              EC_XWORD(lsda));
 670 1002                                  }
 671 1003                          }
 672 1004                          if ((fdelength + 4) > ndx)
 673 1005                                  dump_cfi(data, off, &ndx, fdelength, &cfi_state,
 674 1006                                      MSG_ORIG(MSG_UNW_FDECFI), 6);
 675 1007                          off += fdelength + 4;
 676 1008                  }
 677 1009          }
 678 1010  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX