1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #include        <_libelf.h>
  28 #include        <dwarf.h>
  29 #include        <stdio.h>
  30 #include        <unistd.h>
  31 #include        <errno.h>
  32 #include        <strings.h>
  33 #include        <debug.h>
  34 #include        <conv.h>
  35 #include        <msg.h>
  36 #include        <_elfdump.h>
  37 
  38 
  39 /*
  40  * Data from eh_frame section used by dump_cfi()
  41  */
  42 typedef struct {
  43         Half            e_machine;      /* ehdr->e_machine */
  44         uchar_t         *e_ident;       /* ehdr->e_ident */
  45         uint64_t        sh_addr;        /* Address of eh_frame section */
  46         int             do_swap;        /* True if object and system byte */
  47                                         /*      order differs */
  48         int             cieRflag;       /* R flag from current CIE */
  49         uint64_t        ciecalign;      /* CIE code align factor */
  50         int64_t         ciedalign;      /* CIE data align factor */
  51         uint64_t        fdeinitloc;     /* FDE initial location */
  52 } 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  */
  72 static uint64_t
  73 dwarf_extract_uint(uchar_t *data, uint64_t *ndx, int size, int do_swap)
  74 {
  75         switch (size) {
  76         case 1:
  77                 return (data[(*ndx)++]);
  78         case 2:
  79                 {
  80                         Half    r;
  81                         uchar_t *p = (uchar_t *)&r;
  82 
  83                         data += *ndx;
  84                         if (do_swap)
  85                                 UL_ASSIGN_BSWAP_HALF(p, data);
  86                         else
  87                                 UL_ASSIGN_HALF(p, data);
  88 
  89                         (*ndx) += 2;
  90                         return (r);
  91                 }
  92         case 4:
  93                 {
  94                         Word    r;
  95                         uchar_t *p = (uchar_t *)&r;
  96 
  97                         data += *ndx;
  98                         if (do_swap)
  99                                 UL_ASSIGN_BSWAP_WORD(p, data);
 100                         else
 101                                 UL_ASSIGN_WORD(p, data);
 102 
 103                         (*ndx) += 4;
 104                         return (r);
 105                 }
 106 
 107         case 8:
 108                 {
 109                         uint64_t        r;
 110                         uchar_t         *p = (uchar_t *)&r;
 111 
 112                         data += *ndx;
 113                         if (do_swap)
 114                                 UL_ASSIGN_BSWAP_LWORD(p, data);
 115                         else
 116                                 UL_ASSIGN_LWORD(p, data);
 117 
 118                         (*ndx) += 8;
 119                         return (r);
 120                 }
 121         }
 122 
 123         /* If here, an invalid size was specified */
 124         assert(0);
 125         return (0);
 126 }
 127 
 128 /*
 129  * Map a DWARF register constant to the machine register name it
 130  * corresponds to, formatting the result into buf.
 131  *
 132  * The assignment of DWARF register numbers is part of the system
 133  * specific ABI for each platform.
 134  *
 135  * entry:
 136  *      regno - DWARF register number
 137  *      mach - ELF machine code for platform
 138  *      buf, bufsize - Buffer to receive the formatted result string
 139  *
 140  * exit:
 141  *      The results are formatted into buf, and buf is returned.
 142  *      If the generated output would exceed the size of the buffer
 143  *      provided, it will be clipped to fit.
 144  */
 145 static const char *
 146 dwarf_regname(Half mach, int regno, char *buf, size_t bufsize)
 147 {
 148         Conv_inv_buf_t  inv_buf;
 149         const char      *name;
 150         int             good_name;
 151 
 152         name = conv_dwarf_regname(mach, regno, 0, &good_name, &inv_buf);
 153 
 154         /*
 155          * If there is a good mnemonic machine name for the register,
 156          * format the result as 'r# (mnemonic)'.  If there is no good
 157          * name for it, then simply format the dwarf name as 'r#'.
 158          */
 159         if (good_name)
 160                 (void) snprintf(buf, bufsize, MSG_ORIG(MSG_REG_FMT_NAME),
 161                     regno, name);
 162         else
 163                 (void) snprintf(buf, bufsize, MSG_ORIG(MSG_REG_FMT_BASIC),
 164                     regno);
 165 
 166         return (buf);
 167 }
 168 
 169 
 170 /*
 171  * Decode eh_frame Call Frame Instructions, printing each one on a
 172  * separate line.
 173  *
 174  * entry:
 175  *      data - Address of base of eh_frame section being processed
 176  *      off - Offset of current FDE within eh_frame
 177  *      ndx - Index of current position within current FDE
 178  *      len - Length of eh_frame section
 179  *      state - Object, CIE, and FDE state for current request
 180  *      msg - Header message to issue before producing output.
 181  *      indent - # of indentation characters issued for each line of output.
 182  *
 183  * exit:
 184  *      The Call Frame Instructions have been decoded and printed.
 185  *
 186  *      *ndx has been incremented to contain the index of the next
 187  *              byte of data to be processed in eh_frame.
 188  *
 189  * note:
 190  *      The format of Call Frame Instructions in .eh_frame sections is based
 191  *      on the DWARF specification.
 192  */
 193 static void
 194 dump_cfi(uchar_t *data, uint64_t off, uint64_t *ndx, uint_t len,
 195     dump_cfi_state_t *state, const char *msg, int indent)
 196 {
 197         /*
 198          * We use %*s%s to insert leading whitespace and the op name.
 199          * PREFIX supplies these arguments.
 200          */
 201 #define PREFIX  indent, MSG_ORIG(MSG_STR_EMPTY), opname
 202 
 203         /* Hide boilerplate clutter in calls to dwarf_regname() */
 204 #define REGNAME(_rnum, _buf) \
 205         dwarf_regname(state->e_machine, _rnum, _buf, sizeof (_buf))
 206 
 207         /* Extract the lower 6 bits from an op code */
 208 #define LOW_OP(_op) (_op & 0x3f)
 209 
 210         char            rbuf1[32], rbuf2[32];
 211         Conv_inv_buf_t  inv_buf;
 212         uchar_t         op;
 213         const char      *opname;
 214         uint64_t        oper1, oper2, cur_pc;
 215         int64_t         soper;
 216         const char      *loc_str;
 217         int             i;
 218 
 219         dbg_print(0, msg);
 220 
 221         /*
 222          * In a CIE/FDE, the length field does not include it's own
 223          * size. Hence, the value passed in is 4 less than the index
 224          * of the actual final location.
 225          */
 226         len += 4;
 227 
 228         /*
 229          * There is a concept of the 'current location', which is the PC
 230          * to which the current item applies. It starts out set to the
 231          * FDE initial location, and can be set or incremented by
 232          * various OP codes. cur_pc is used to track this.
 233          *
 234          * We want to use 'initloc' in the output the first time the location
 235          * is referenced, and then switch to 'loc' for subsequent references.
 236          * loc_str is used to manage that.
 237          */
 238         cur_pc = state->fdeinitloc;
 239         loc_str = MSG_ORIG(MSG_STR_INITLOC);
 240 
 241         while (*ndx < len) {
 242                 /*
 243                  * The first byte contains the primary op code in the top
 244                  * 2 bits, so there are 4 of them. Primary OP code
 245                  * 0 uses the lower 6 bits to specify a sub-opcode, allowing
 246                  * for 64 of them. The other 3 primary op codes use the
 247                  * lower 6 bits to hold an operand (a register #, or value).
 248                  *
 249                  * Check the primary OP code. If it's 1-3, handle it
 250                  * and move to the next loop iteration. For OP code 0,
 251                  * fall through to decode the sub-code.
 252                  */
 253                 op = data[off + (*ndx)++];
 254                 opname = conv_dwarf_cfa(op, 0, &inv_buf);
 255                 switch (op >> 6) {
 256                 case 0x1:               /* v2: DW_CFA_advance_loc, delta */
 257                         oper1 = state->ciecalign * LOW_OP(op);
 258                         cur_pc += oper1;
 259                         dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX,
 260                             loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc));
 261                         loc_str = MSG_ORIG(MSG_STR_LOC);
 262                         continue;
 263 
 264                 case 0x2:               /* v2: DW_CFA_offset, reg, offset */
 265                         soper = uleb_extract(&data[off], ndx) *
 266                             state->ciedalign;
 267                         dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
 268                             REGNAME(LOW_OP(op), rbuf1), EC_SXWORD(soper));
 269                         continue;
 270 
 271                 case 0x3:               /* v2: DW_CFA_restore, reg */
 272                         dbg_print(0, MSG_ORIG(MSG_CFA_REG), PREFIX,
 273                             REGNAME(LOW_OP(op), rbuf1));
 274                         continue;
 275                 }
 276 
 277                 /*
 278                  * If we're here, the high order 2 bits are 0. The low 6 bits
 279                  * specify a sub-opcode defining the operation.
 280                  */
 281                 switch (op) {
 282                 case 0x00:              /* v2: DW_CFA_nop */
 283                         /*
 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;
 326 
 327                 case 0x05:              /* v2: DW_CFA_offset_extended,reg,off */
 328                         oper1 = uleb_extract(&data[off], ndx);
 329                         soper = uleb_extract(&data[off], ndx) *
 330                             state->ciedalign;
 331                         dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
 332                             REGNAME(oper1, rbuf1), EC_SXWORD(soper));
 333                         break;
 334 
 335                 case 0x06:              /* v2: DW_CFA_restore_extended, reg */
 336                 case 0x0d:              /* v2: DW_CFA_def_cfa_register, reg */
 337                 case 0x08:              /* v2: DW_CFA_same_value, reg */
 338                 case 0x07:              /* v2: DW_CFA_undefined, reg */
 339                         oper1 = uleb_extract(&data[off], ndx);
 340                         dbg_print(0, MSG_ORIG(MSG_CFA_REG), PREFIX,
 341                             REGNAME(oper1, rbuf1));
 342                         break;
 343 
 344 
 345                 case 0x09:              /* v2: DW_CFA_register, reg, reg */
 346                         oper1 = uleb_extract(&data[off], ndx);
 347                         oper2 = uleb_extract(&data[off], ndx);
 348                         dbg_print(0, MSG_ORIG(MSG_CFA_REG_REG), PREFIX,
 349                             REGNAME(oper1, rbuf1), REGNAME(oper2, rbuf2));
 350                         break;
 351 
 352                 case 0x0c:              /* v2: DW_CFA_def_cfa, reg, offset */
 353                         oper1 = uleb_extract(&data[off], ndx);
 354                         oper2 = uleb_extract(&data[off], ndx);
 355                         dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLU), PREFIX,
 356                             REGNAME(oper1, rbuf1), EC_XWORD(oper2));
 357                         break;
 358 
 359                 case 0x0e:              /* v2: DW_CFA_def_cfa_offset, offset */
 360                         oper1 = uleb_extract(&data[off], ndx);
 361                         dbg_print(0, MSG_ORIG(MSG_CFA_LLU), PREFIX,
 362                             EC_XWORD(oper1));
 363                         break;
 364 
 365                 case 0x0f:              /* v3: DW_CFA_def_cfa_expression, blk */
 366                         oper1 = uleb_extract(&data[off], ndx);
 367                         dbg_print(0, MSG_ORIG(MSG_CFA_EBLK), PREFIX,
 368                             EC_XWORD(oper1));
 369                         /* We currently do not decode the expression block */
 370                         *ndx += oper1;
 371                         break;
 372 
 373                 case 0x10:              /* v3: DW_CFA_expression, reg, blk */
 374                 case 0x16:              /* v3: DW_CFA_val_expression,reg,blk */
 375                         oper1 = uleb_extract(&data[off], ndx);
 376                         oper2 = uleb_extract(&data[off], ndx);
 377                         dbg_print(0, MSG_ORIG(MSG_CFA_REG_EBLK), PREFIX,
 378                             REGNAME(oper1, rbuf1), EC_XWORD(oper2));
 379                         /* We currently do not decode the expression block */
 380                         *ndx += oper2;
 381                         break;
 382 
 383                 case 0x11:      /* v3: DW_CFA_offset_extended_sf, reg, off */
 384                         oper1 = uleb_extract(&data[off], ndx);
 385                         soper = sleb_extract(&data[off], ndx) *
 386                             state->ciedalign;
 387                         dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
 388                             REGNAME(oper1, rbuf1), EC_SXWORD(soper));
 389                         break;
 390 
 391                 case 0x12:              /* v3: DW_CFA_def_cfa_sf, reg, offset */
 392                         oper1 = uleb_extract(&data[off], ndx);
 393                         soper = sleb_extract(&data[off], ndx) *
 394                             state->ciedalign;
 395                         dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX,
 396                             REGNAME(oper1, rbuf1), EC_SXWORD(soper));
 397                         break;
 398 
 399                 case 0x13:              /* DW_CFA_def_cfa_offset_sf, offset */
 400                         soper = sleb_extract(&data[off], ndx) *
 401                             state->ciedalign;
 402                         dbg_print(0, MSG_ORIG(MSG_CFA_LLD), PREFIX,
 403                             EC_SXWORD(soper));
 404                         break;
 405 
 406                 case 0x14:              /* v3: DW_CFA_val_offset, reg, offset */
 407                         oper1 = uleb_extract(&data[off], ndx);
 408                         soper = uleb_extract(&data[off], ndx) *
 409                             state->ciedalign;
 410                         dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX,
 411                             REGNAME(oper1, rbuf1), EC_SXWORD(soper));
 412                         break;
 413 
 414                 case 0x15:      /* v3: DW_CFA_val_offset_sf, reg, offset */
 415                         oper1 = uleb_extract(&data[off], ndx);
 416                         soper = sleb_extract(&data[off], ndx) *
 417                             state->ciedalign;
 418                         dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX,
 419                             REGNAME(oper1, rbuf1), EC_SXWORD(soper));
 420                         break;
 421 
 422                 case 0x1d:      /* GNU: DW_CFA_MIPS_advance_loc8, delta */
 423                         oper1 = dwarf_extract_uint(data + off, ndx, i,
 424                             state->do_swap) * state->ciecalign;
 425                         cur_pc += oper1;
 426                         dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX,
 427                             loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc));
 428                         loc_str = MSG_ORIG(MSG_STR_LOC);
 429                         break;
 430 
 431                 case 0x2e:              /* GNU: DW_CFA_GNU_args_size, size */
 432                         oper1 = uleb_extract(&data[off], ndx);
 433                         dbg_print(0, MSG_ORIG(MSG_CFA_LLU), PREFIX,
 434                             EC_XWORD(oper1));
 435 
 436                         break;
 437 
 438                 case 0x2f: /* GNU:DW_CFA_GNU_negative_offset_extended,reg,off */
 439                         oper1 = uleb_extract(&data[off], ndx);
 440                         soper = -uleb_extract(&data[off], ndx) *
 441                             state->ciedalign;
 442                         dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
 443                             REGNAME(oper1, rbuf1), EC_SXWORD(soper));
 444                         break;
 445 
 446                 default:
 447                         /*
 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;
 502                         continue;
 503                 }
 504 
 505                 /*
 506                  * extract CIE id in native format
 507                  */
 508                 id = (uint_t)dwarf_extract_uint(data + off, &ndx,
 509                     4, cfi_state.do_swap);
 510 
 511                 /*
 512                  * A CIE record has an id of '0', otherwise this is a
 513                  * FDE entry and the 'id' is the CIE pointer.
 514                  */
 515                 if (id == 0) {
 516                         uint64_t        persVal, ndx_save;
 517                         uint_t          axsize;
 518 
 519                         cielength = length;
 520                         cieid = id;
 521                         ciePflag = cfi_state.cieRflag = cieZflag = 0;
 522                         cieLflag = cieLflag_present = 0;
 523 
 524                         dbg_print(0, MSG_ORIG(MSG_UNW_CIE),
 525                             EC_XWORD(sh_addr + off));
 526                         dbg_print(0, MSG_ORIG(MSG_UNW_CIELNGTH),
 527                             cielength, cieid);
 528 
 529                         cieversion = data[off + ndx];
 530                         ndx += 1;
 531                         cieaugstr = (char *)(&data[off + ndx]);
 532                         ndx += strlen(cieaugstr) + 1;
 533 
 534                         dbg_print(0, MSG_ORIG(MSG_UNW_CIEVERS),
 535                             cieversion, cieaugstr);
 536 
 537                         cfi_state.ciecalign = uleb_extract(&data[off], &ndx);
 538                         cfi_state.ciedalign = sleb_extract(&data[off], &ndx);
 539                         cieretaddr = data[off + ndx];
 540                         ndx += 1;
 541 
 542                         dbg_print(0, MSG_ORIG(MSG_UNW_CIECALGN),
 543                             EC_XWORD(cfi_state.ciecalign),
 544                             EC_XWORD(cfi_state.ciedalign), cieretaddr);
 545 
 546                         if (cieaugstr[0])
 547                                 dbg_print(0, MSG_ORIG(MSG_UNW_CIEAXVAL));
 548 
 549                         for (cieaugndx = 0; cieaugstr[cieaugndx]; cieaugndx++) {
 550                                 switch (cieaugstr[cieaugndx]) {
 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':
 593                                         cieLflag_present = 1;
 594                                         cieLflag = data[off + ndx];
 595                                         ndx += 1;
 596                                         dbg_print(0,
 597                                             MSG_ORIG(MSG_UNW_CIEAXLSDA),
 598                                             cieLflag, conv_dwarf_ehe(
 599                                             cieLflag, &dwarf_ehe_buf));
 600                                         break;
 601                                 default:
 602                                         dbg_print(0,
 603                                             MSG_ORIG(MSG_UNW_CIEAXUNEC),
 604                                             cieaugstr[cieaugndx]);
 605                                         break;
 606                                 }
 607                         }
 608 
 609                         /*
 610                          * If the z flag was present, reposition ndx using the
 611                          * length given. This will safely move us past any
 612                          * unaccessed padding bytes in the auxiliary section.
 613                          */
 614                         if (cieZflag)
 615                                 ndx = ndx_save + axsize;
 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 }