17e16fca0SAli Bahrami /* 27e16fca0SAli Bahrami * CDDL HEADER START 37e16fca0SAli Bahrami * 47e16fca0SAli Bahrami * The contents of this file are subject to the terms of the 57e16fca0SAli Bahrami * Common Development and Distribution License (the "License"). 67e16fca0SAli Bahrami * You may not use this file except in compliance with the License. 77e16fca0SAli Bahrami * 87e16fca0SAli Bahrami * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97e16fca0SAli Bahrami * or http://www.opensolaris.org/os/licensing. 107e16fca0SAli Bahrami * See the License for the specific language governing permissions 117e16fca0SAli Bahrami * and limitations under the License. 127e16fca0SAli Bahrami * 137e16fca0SAli Bahrami * When distributing Covered Code, include this CDDL HEADER in each 147e16fca0SAli Bahrami * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157e16fca0SAli Bahrami * If applicable, add the following below this CDDL HEADER, with the 167e16fca0SAli Bahrami * fields enclosed by brackets "[]" replaced with your own identifying 177e16fca0SAli Bahrami * information: Portions Copyright [yyyy] [name of copyright owner] 187e16fca0SAli Bahrami * 197e16fca0SAli Bahrami * CDDL HEADER END 207e16fca0SAli Bahrami */ 217e16fca0SAli Bahrami 227e16fca0SAli Bahrami /* 237e16fca0SAli Bahrami * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247e16fca0SAli Bahrami * Use is subject to license terms. 257e16fca0SAli Bahrami */ 267e16fca0SAli Bahrami 277e16fca0SAli Bahrami #include <_libelf.h> 287e16fca0SAli Bahrami #include <dwarf.h> 297e16fca0SAli Bahrami #include <stdio.h> 307e16fca0SAli Bahrami #include <unistd.h> 317e16fca0SAli Bahrami #include <errno.h> 327e16fca0SAli Bahrami #include <strings.h> 337e16fca0SAli Bahrami #include <debug.h> 347e16fca0SAli Bahrami #include <conv.h> 357e16fca0SAli Bahrami #include <msg.h> 367e16fca0SAli Bahrami #include <_elfdump.h> 377e16fca0SAli Bahrami 387e16fca0SAli Bahrami 397e16fca0SAli Bahrami /* 407e16fca0SAli Bahrami * Data from eh_frame section used by dump_cfi() 417e16fca0SAli Bahrami */ 427e16fca0SAli Bahrami typedef struct { 43*37915d86SRichard Lowe const char *file; 44*37915d86SRichard Lowe const char *sh_name; 457e16fca0SAli Bahrami Half e_machine; /* ehdr->e_machine */ 467e16fca0SAli Bahrami uchar_t *e_ident; /* ehdr->e_ident */ 477e16fca0SAli Bahrami uint64_t sh_addr; /* Address of eh_frame section */ 487e16fca0SAli Bahrami int do_swap; /* True if object and system byte */ 497e16fca0SAli Bahrami /* order differs */ 507e16fca0SAli Bahrami int cieRflag; /* R flag from current CIE */ 517e16fca0SAli Bahrami uint64_t ciecalign; /* CIE code align factor */ 527e16fca0SAli Bahrami int64_t ciedalign; /* CIE data align factor */ 537e16fca0SAli Bahrami uint64_t fdeinitloc; /* FDE initial location */ 54965630c1SRichard Lowe uint64_t gotaddr; /* Address of the GOT */ 557e16fca0SAli Bahrami } dump_cfi_state_t; 567e16fca0SAli Bahrami 577e16fca0SAli Bahrami 587e16fca0SAli Bahrami /* 597e16fca0SAli Bahrami * Extract an unsigned integer value from an .eh_frame section, converting it 607e16fca0SAli Bahrami * from its native byte order to that of the running machine if necessary. 617e16fca0SAli Bahrami * 627e16fca0SAli Bahrami * entry: 637e16fca0SAli Bahrami * data - Base address from which to extract datum 647e16fca0SAli Bahrami * ndx - Address of variable giving index to start byte in data. 657e16fca0SAli Bahrami * size - # of bytes in datum. Must be one of: 1, 2, 4, 8 667e16fca0SAli Bahrami * do_swap - True if the data is in a different byte order than that 677e16fca0SAli Bahrami * of the host system. 687e16fca0SAli Bahrami * 697e16fca0SAli Bahrami * exit: 707e16fca0SAli Bahrami * *ndx is incremented by the size of the extracted datum. 717e16fca0SAli Bahrami * 727e16fca0SAli Bahrami * The requested datum is extracted, byte swapped if necessary, 737e16fca0SAli Bahrami * and returned. 747e16fca0SAli Bahrami */ 75*37915d86SRichard Lowe static dwarf_error_t 76*37915d86SRichard Lowe dwarf_extract_uint(uchar_t *data, size_t len, uint64_t *ndx, int size, 77*37915d86SRichard Lowe int do_swap, uint64_t *ret) 787e16fca0SAli Bahrami { 79*37915d86SRichard Lowe if (((*ndx + size) > len) || 80*37915d86SRichard Lowe ((*ndx + size) < *ndx)) 81*37915d86SRichard Lowe return (DW_OVERFLOW); 82*37915d86SRichard Lowe 837e16fca0SAli Bahrami switch (size) { 847e16fca0SAli Bahrami case 1: 85*37915d86SRichard Lowe *ret = (data[(*ndx)++]); 86*37915d86SRichard Lowe return (DW_SUCCESS); 877e16fca0SAli Bahrami case 2: 887e16fca0SAli Bahrami { 897e16fca0SAli Bahrami Half r; 907e16fca0SAli Bahrami uchar_t *p = (uchar_t *)&r; 917e16fca0SAli Bahrami 927e16fca0SAli Bahrami data += *ndx; 937e16fca0SAli Bahrami if (do_swap) 947e16fca0SAli Bahrami UL_ASSIGN_BSWAP_HALF(p, data); 957e16fca0SAli Bahrami else 967e16fca0SAli Bahrami UL_ASSIGN_HALF(p, data); 977e16fca0SAli Bahrami 987e16fca0SAli Bahrami (*ndx) += 2; 99*37915d86SRichard Lowe *ret = r; 100*37915d86SRichard Lowe return (DW_SUCCESS); 1017e16fca0SAli Bahrami } 1027e16fca0SAli Bahrami case 4: 1037e16fca0SAli Bahrami { 1047e16fca0SAli Bahrami Word r; 1057e16fca0SAli Bahrami uchar_t *p = (uchar_t *)&r; 1067e16fca0SAli Bahrami 1077e16fca0SAli Bahrami data += *ndx; 1087e16fca0SAli Bahrami if (do_swap) 1097e16fca0SAli Bahrami UL_ASSIGN_BSWAP_WORD(p, data); 1107e16fca0SAli Bahrami else 1117e16fca0SAli Bahrami UL_ASSIGN_WORD(p, data); 1127e16fca0SAli Bahrami 1137e16fca0SAli Bahrami (*ndx) += 4; 114*37915d86SRichard Lowe *ret = r; 115*37915d86SRichard Lowe return (DW_SUCCESS); 1167e16fca0SAli Bahrami } 1177e16fca0SAli Bahrami 1187e16fca0SAli Bahrami case 8: 1197e16fca0SAli Bahrami { 1207e16fca0SAli Bahrami uint64_t r; 1217e16fca0SAli Bahrami uchar_t *p = (uchar_t *)&r; 1227e16fca0SAli Bahrami 1237e16fca0SAli Bahrami data += *ndx; 1247e16fca0SAli Bahrami if (do_swap) 1257e16fca0SAli Bahrami UL_ASSIGN_BSWAP_LWORD(p, data); 1267e16fca0SAli Bahrami else 1277e16fca0SAli Bahrami UL_ASSIGN_LWORD(p, data); 1287e16fca0SAli Bahrami 1297e16fca0SAli Bahrami (*ndx) += 8; 130*37915d86SRichard Lowe *ret = r; 131*37915d86SRichard Lowe return (DW_SUCCESS); 1327e16fca0SAli Bahrami } 133*37915d86SRichard Lowe default: 134*37915d86SRichard Lowe return (DW_BAD_ENCODING); 1357e16fca0SAli Bahrami } 1367e16fca0SAli Bahrami 137*37915d86SRichard Lowe /* NOTREACHED */ 1387e16fca0SAli Bahrami } 1397e16fca0SAli Bahrami 1407e16fca0SAli Bahrami /* 1417e16fca0SAli Bahrami * Map a DWARF register constant to the machine register name it 1427e16fca0SAli Bahrami * corresponds to, formatting the result into buf. 1437e16fca0SAli Bahrami * 1447e16fca0SAli Bahrami * The assignment of DWARF register numbers is part of the system 1457e16fca0SAli Bahrami * specific ABI for each platform. 1467e16fca0SAli Bahrami * 1477e16fca0SAli Bahrami * entry: 1487e16fca0SAli Bahrami * regno - DWARF register number 1497e16fca0SAli Bahrami * mach - ELF machine code for platform 1507e16fca0SAli Bahrami * buf, bufsize - Buffer to receive the formatted result string 1517e16fca0SAli Bahrami * 1527e16fca0SAli Bahrami * exit: 1537e16fca0SAli Bahrami * The results are formatted into buf, and buf is returned. 1547e16fca0SAli Bahrami * If the generated output would exceed the size of the buffer 1557e16fca0SAli Bahrami * provided, it will be clipped to fit. 1567e16fca0SAli Bahrami */ 1577e16fca0SAli Bahrami static const char * 1587e16fca0SAli Bahrami dwarf_regname(Half mach, int regno, char *buf, size_t bufsize) 1597e16fca0SAli Bahrami { 1607e16fca0SAli Bahrami Conv_inv_buf_t inv_buf; 1617e16fca0SAli Bahrami const char *name; 1627e16fca0SAli Bahrami int good_name; 1637e16fca0SAli Bahrami 1647e16fca0SAli Bahrami name = conv_dwarf_regname(mach, regno, 0, &good_name, &inv_buf); 1657e16fca0SAli Bahrami 1667e16fca0SAli Bahrami /* 1677e16fca0SAli Bahrami * If there is a good mnemonic machine name for the register, 1687e16fca0SAli Bahrami * format the result as 'r# (mnemonic)'. If there is no good 1697e16fca0SAli Bahrami * name for it, then simply format the dwarf name as 'r#'. 1707e16fca0SAli Bahrami */ 1717e16fca0SAli Bahrami if (good_name) 1727e16fca0SAli Bahrami (void) snprintf(buf, bufsize, MSG_ORIG(MSG_REG_FMT_NAME), 1737e16fca0SAli Bahrami regno, name); 1747e16fca0SAli Bahrami else 1757e16fca0SAli Bahrami (void) snprintf(buf, bufsize, MSG_ORIG(MSG_REG_FMT_BASIC), 1767e16fca0SAli Bahrami regno); 1777e16fca0SAli Bahrami 1787e16fca0SAli Bahrami return (buf); 1797e16fca0SAli Bahrami } 1807e16fca0SAli Bahrami 1817e16fca0SAli Bahrami 1827e16fca0SAli Bahrami /* 1837e16fca0SAli Bahrami * Decode eh_frame Call Frame Instructions, printing each one on a 1847e16fca0SAli Bahrami * separate line. 1857e16fca0SAli Bahrami * 1867e16fca0SAli Bahrami * entry: 1877e16fca0SAli Bahrami * data - Address of base of eh_frame section being processed 1887e16fca0SAli Bahrami * off - Offset of current FDE within eh_frame 1897e16fca0SAli Bahrami * ndx - Index of current position within current FDE 190*37915d86SRichard Lowe * len - Length of FDE 1917e16fca0SAli Bahrami * state - Object, CIE, and FDE state for current request 1927e16fca0SAli Bahrami * msg - Header message to issue before producing output. 1937e16fca0SAli Bahrami * indent - # of indentation characters issued for each line of output. 1947e16fca0SAli Bahrami * 1957e16fca0SAli Bahrami * exit: 1967e16fca0SAli Bahrami * The Call Frame Instructions have been decoded and printed. 1977e16fca0SAli Bahrami * 1987e16fca0SAli Bahrami * *ndx has been incremented to contain the index of the next 1997e16fca0SAli Bahrami * byte of data to be processed in eh_frame. 2007e16fca0SAli Bahrami * 2017e16fca0SAli Bahrami * note: 2027e16fca0SAli Bahrami * The format of Call Frame Instructions in .eh_frame sections is based 2037e16fca0SAli Bahrami * on the DWARF specification. 2047e16fca0SAli Bahrami */ 2057e16fca0SAli Bahrami static void 2067e16fca0SAli Bahrami dump_cfi(uchar_t *data, uint64_t off, uint64_t *ndx, uint_t len, 2077e16fca0SAli Bahrami dump_cfi_state_t *state, const char *msg, int indent) 2087e16fca0SAli Bahrami { 2097e16fca0SAli Bahrami /* 2107e16fca0SAli Bahrami * We use %*s%s to insert leading whitespace and the op name. 2117e16fca0SAli Bahrami * PREFIX supplies these arguments. 2127e16fca0SAli Bahrami */ 2137e16fca0SAli Bahrami #define PREFIX indent, MSG_ORIG(MSG_STR_EMPTY), opname 2147e16fca0SAli Bahrami 2157e16fca0SAli Bahrami /* Hide boilerplate clutter in calls to dwarf_regname() */ 2167e16fca0SAli Bahrami #define REGNAME(_rnum, _buf) \ 2177e16fca0SAli Bahrami dwarf_regname(state->e_machine, _rnum, _buf, sizeof (_buf)) 2187e16fca0SAli Bahrami 2197e16fca0SAli Bahrami /* Extract the lower 6 bits from an op code */ 2207e16fca0SAli Bahrami #define LOW_OP(_op) (_op & 0x3f) 2217e16fca0SAli Bahrami 2227e16fca0SAli Bahrami char rbuf1[32], rbuf2[32]; 2237e16fca0SAli Bahrami Conv_inv_buf_t inv_buf; 2247e16fca0SAli Bahrami uchar_t op; 2257e16fca0SAli Bahrami const char *opname; 2267e16fca0SAli Bahrami uint64_t oper1, oper2, cur_pc; 2277e16fca0SAli Bahrami int64_t soper; 2287e16fca0SAli Bahrami const char *loc_str; 2297e16fca0SAli Bahrami int i; 2307e16fca0SAli Bahrami 2317e16fca0SAli Bahrami dbg_print(0, msg); 2327e16fca0SAli Bahrami 2337e16fca0SAli Bahrami /* 2347e16fca0SAli Bahrami * In a CIE/FDE, the length field does not include it's own 2357e16fca0SAli Bahrami * size. Hence, the value passed in is 4 less than the index 2367e16fca0SAli Bahrami * of the actual final location. 2377e16fca0SAli Bahrami */ 2387e16fca0SAli Bahrami len += 4; 2397e16fca0SAli Bahrami 2407e16fca0SAli Bahrami /* 2417e16fca0SAli Bahrami * There is a concept of the 'current location', which is the PC 2427e16fca0SAli Bahrami * to which the current item applies. It starts out set to the 2437e16fca0SAli Bahrami * FDE initial location, and can be set or incremented by 2447e16fca0SAli Bahrami * various OP codes. cur_pc is used to track this. 2457e16fca0SAli Bahrami * 2467e16fca0SAli Bahrami * We want to use 'initloc' in the output the first time the location 2477e16fca0SAli Bahrami * is referenced, and then switch to 'loc' for subsequent references. 2487e16fca0SAli Bahrami * loc_str is used to manage that. 2497e16fca0SAli Bahrami */ 2507e16fca0SAli Bahrami cur_pc = state->fdeinitloc; 2517e16fca0SAli Bahrami loc_str = MSG_ORIG(MSG_STR_INITLOC); 2527e16fca0SAli Bahrami 2537e16fca0SAli Bahrami while (*ndx < len) { 2547e16fca0SAli Bahrami /* 2557e16fca0SAli Bahrami * The first byte contains the primary op code in the top 2567e16fca0SAli Bahrami * 2 bits, so there are 4 of them. Primary OP code 2577e16fca0SAli Bahrami * 0 uses the lower 6 bits to specify a sub-opcode, allowing 2587e16fca0SAli Bahrami * for 64 of them. The other 3 primary op codes use the 2597e16fca0SAli Bahrami * lower 6 bits to hold an operand (a register #, or value). 2607e16fca0SAli Bahrami * 2617e16fca0SAli Bahrami * Check the primary OP code. If it's 1-3, handle it 2627e16fca0SAli Bahrami * and move to the next loop iteration. For OP code 0, 2637e16fca0SAli Bahrami * fall through to decode the sub-code. 2647e16fca0SAli Bahrami */ 2657e16fca0SAli Bahrami op = data[off + (*ndx)++]; 2667e16fca0SAli Bahrami opname = conv_dwarf_cfa(op, 0, &inv_buf); 2677e16fca0SAli Bahrami switch (op >> 6) { 2687e16fca0SAli Bahrami case 0x1: /* v2: DW_CFA_advance_loc, delta */ 2697e16fca0SAli Bahrami oper1 = state->ciecalign * LOW_OP(op); 2707e16fca0SAli Bahrami cur_pc += oper1; 2717e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX, 2727e16fca0SAli Bahrami loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc)); 2737e16fca0SAli Bahrami loc_str = MSG_ORIG(MSG_STR_LOC); 2747e16fca0SAli Bahrami continue; 2757e16fca0SAli Bahrami 2767e16fca0SAli Bahrami case 0x2: /* v2: DW_CFA_offset, reg, offset */ 277*37915d86SRichard Lowe if (uleb_extract(&data[off], ndx, len, &oper1) == 278*37915d86SRichard Lowe DW_OVERFLOW) { 279*37915d86SRichard Lowe (void) fprintf(stderr, 280*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 281*37915d86SRichard Lowe state->file, state->sh_name); 282*37915d86SRichard Lowe return; 283*37915d86SRichard Lowe } 284*37915d86SRichard Lowe 285*37915d86SRichard Lowe oper1 *= state->ciedalign; 2867e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX, 287*37915d86SRichard Lowe REGNAME(LOW_OP(op), rbuf1), EC_XWORD(oper1)); 2887e16fca0SAli Bahrami continue; 2897e16fca0SAli Bahrami 2907e16fca0SAli Bahrami case 0x3: /* v2: DW_CFA_restore, reg */ 2917e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_CFA_REG), PREFIX, 2927e16fca0SAli Bahrami REGNAME(LOW_OP(op), rbuf1)); 2937e16fca0SAli Bahrami continue; 2947e16fca0SAli Bahrami } 2957e16fca0SAli Bahrami 2967e16fca0SAli Bahrami /* 2977e16fca0SAli Bahrami * If we're here, the high order 2 bits are 0. The low 6 bits 2987e16fca0SAli Bahrami * specify a sub-opcode defining the operation. 2997e16fca0SAli Bahrami */ 3007e16fca0SAli Bahrami switch (op) { 3017e16fca0SAli Bahrami case 0x00: /* v2: DW_CFA_nop */ 3027e16fca0SAli Bahrami /* 3037e16fca0SAli Bahrami * No-ops are used to fill unused space required 3047e16fca0SAli Bahrami * for alignment. It is common for there to be 3057e16fca0SAli Bahrami * multiple adjacent nops. It saves space to report 3067e16fca0SAli Bahrami * them all with a single line of output. 3077e16fca0SAli Bahrami */ 3087e16fca0SAli Bahrami for (i = 1; 3097e16fca0SAli Bahrami (*ndx < len) && (data[off + *ndx] == 0); 3107e16fca0SAli Bahrami i++, (*ndx)++) 3117e16fca0SAli Bahrami ; 3127e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_CFA_SIMPLEREP), PREFIX, i); 3137e16fca0SAli Bahrami break; 3147e16fca0SAli Bahrami 3157e16fca0SAli Bahrami case 0x0a: /* v2: DW_CFA_remember_state */ 3167e16fca0SAli Bahrami case 0x0b: /* v2: DW_CFA_restore_state */ 3177e16fca0SAli Bahrami case 0x2d: /* GNU: DW_CFA_GNU_window_save */ 3187e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_CFA_SIMPLE), PREFIX); 3197e16fca0SAli Bahrami break; 3207e16fca0SAli Bahrami 3217e16fca0SAli Bahrami case 0x01: /* v2: DW_CFA_set_loc, address */ 322*37915d86SRichard Lowe switch (dwarf_ehe_extract(&data[off], len, ndx, 323*37915d86SRichard Lowe &cur_pc, state->cieRflag, state->e_ident, B_FALSE, 324*37915d86SRichard Lowe state->sh_addr, off + *ndx, state->gotaddr)) { 325*37915d86SRichard Lowe case DW_OVERFLOW: 326*37915d86SRichard Lowe (void) fprintf(stderr, 327*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 328*37915d86SRichard Lowe state->file, state->sh_name); 329*37915d86SRichard Lowe return; 330*37915d86SRichard Lowe case DW_BAD_ENCODING: 331*37915d86SRichard Lowe (void) fprintf(stderr, 332*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWBADENC), 333*37915d86SRichard Lowe state->file, state->sh_name, 334*37915d86SRichard Lowe state->cieRflag); 335*37915d86SRichard Lowe return; 336*37915d86SRichard Lowe case DW_SUCCESS: 337*37915d86SRichard Lowe break; 338*37915d86SRichard Lowe } 3397e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_CFA_CFASET), PREFIX, 3407e16fca0SAli Bahrami EC_XWORD(cur_pc)); 3417e16fca0SAli Bahrami break; 3427e16fca0SAli Bahrami 3437e16fca0SAli Bahrami case 0x02: /* v2: DW_CFA_advance_loc_1, 1-byte delta */ 3447e16fca0SAli Bahrami case 0x03: /* v2: DW_CFA_advance_loc_2, 2-byte delta */ 3457e16fca0SAli Bahrami case 0x04: /* v2: DW_CFA_advance_loc_4, 4-byte delta */ 3467e16fca0SAli Bahrami /* 3477e16fca0SAli Bahrami * Since the codes are contiguous, and the sizes are 3487e16fca0SAli Bahrami * powers of 2, we can compute the word width from 3497e16fca0SAli Bahrami * the code. 3507e16fca0SAli Bahrami */ 3517e16fca0SAli Bahrami i = 1 << (op - 0x02); 352*37915d86SRichard Lowe switch (dwarf_extract_uint(data + off, len, 353*37915d86SRichard Lowe ndx, i, state->do_swap, &oper1)) { 354*37915d86SRichard Lowe case DW_BAD_ENCODING: 355*37915d86SRichard Lowe (void) fprintf(stderr, 356*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWBADENC), 357*37915d86SRichard Lowe state->file, state->sh_name, 358*37915d86SRichard Lowe i); 359*37915d86SRichard Lowe return; 360*37915d86SRichard Lowe case DW_OVERFLOW: 361*37915d86SRichard Lowe (void) fprintf(stderr, 362*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 363*37915d86SRichard Lowe state->file, state->sh_name); 364*37915d86SRichard Lowe return; 365*37915d86SRichard Lowe case DW_SUCCESS: 366*37915d86SRichard Lowe break; 367*37915d86SRichard Lowe } 368*37915d86SRichard Lowe oper1 *= state->ciecalign; 3697e16fca0SAli Bahrami cur_pc += oper1; 3707e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX, 3717e16fca0SAli Bahrami loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc)); 3727e16fca0SAli Bahrami loc_str = MSG_ORIG(MSG_STR_LOC); 3737e16fca0SAli Bahrami break; 3747e16fca0SAli Bahrami 3757e16fca0SAli Bahrami case 0x05: /* v2: DW_CFA_offset_extended,reg,off */ 376*37915d86SRichard Lowe if (uleb_extract(&data[off], ndx, len, &oper1) == 377*37915d86SRichard Lowe DW_OVERFLOW) { 378*37915d86SRichard Lowe (void) fprintf(stderr, 379*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 380*37915d86SRichard Lowe state->file, state->sh_name); 381*37915d86SRichard Lowe return; 382*37915d86SRichard Lowe } 383*37915d86SRichard Lowe 384*37915d86SRichard Lowe if (sleb_extract(&data[off], ndx, len, &soper) == 385*37915d86SRichard Lowe DW_OVERFLOW) { 386*37915d86SRichard Lowe (void) fprintf(stderr, 387*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 388*37915d86SRichard Lowe state->file, state->sh_name); 389*37915d86SRichard Lowe return; 390*37915d86SRichard Lowe } 391*37915d86SRichard Lowe 392*37915d86SRichard Lowe soper *= state->ciedalign; 3937e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX, 3947e16fca0SAli Bahrami REGNAME(oper1, rbuf1), EC_SXWORD(soper)); 3957e16fca0SAli Bahrami break; 3967e16fca0SAli Bahrami 3977e16fca0SAli Bahrami case 0x06: /* v2: DW_CFA_restore_extended, reg */ 3987e16fca0SAli Bahrami case 0x0d: /* v2: DW_CFA_def_cfa_register, reg */ 3997e16fca0SAli Bahrami case 0x08: /* v2: DW_CFA_same_value, reg */ 4007e16fca0SAli Bahrami case 0x07: /* v2: DW_CFA_undefined, reg */ 401*37915d86SRichard Lowe if (uleb_extract(&data[off], ndx, len, &oper1) == 402*37915d86SRichard Lowe DW_OVERFLOW) { 403*37915d86SRichard Lowe (void) fprintf(stderr, 404*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 405*37915d86SRichard Lowe state->file, state->sh_name); 406*37915d86SRichard Lowe return; 407*37915d86SRichard Lowe } 408*37915d86SRichard Lowe 4097e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_CFA_REG), PREFIX, 4107e16fca0SAli Bahrami REGNAME(oper1, rbuf1)); 4117e16fca0SAli Bahrami break; 4127e16fca0SAli Bahrami 4137e16fca0SAli Bahrami 4147e16fca0SAli Bahrami case 0x09: /* v2: DW_CFA_register, reg, reg */ 415*37915d86SRichard Lowe if (uleb_extract(&data[off], ndx, len, &oper1) == 416*37915d86SRichard Lowe DW_OVERFLOW) { 417*37915d86SRichard Lowe (void) fprintf(stderr, 418*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 419*37915d86SRichard Lowe state->file, state->sh_name); 420*37915d86SRichard Lowe return; 421*37915d86SRichard Lowe } 422*37915d86SRichard Lowe 423*37915d86SRichard Lowe if (uleb_extract(&data[off], ndx, len, &oper2) == 424*37915d86SRichard Lowe DW_OVERFLOW) { 425*37915d86SRichard Lowe (void) fprintf(stderr, 426*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 427*37915d86SRichard Lowe state->file, state->sh_name); 428*37915d86SRichard Lowe return; 429*37915d86SRichard Lowe } 4307e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_CFA_REG_REG), PREFIX, 4317e16fca0SAli Bahrami REGNAME(oper1, rbuf1), REGNAME(oper2, rbuf2)); 4327e16fca0SAli Bahrami break; 4337e16fca0SAli Bahrami 4347e16fca0SAli Bahrami case 0x0c: /* v2: DW_CFA_def_cfa, reg, offset */ 435*37915d86SRichard Lowe if (uleb_extract(&data[off], ndx, len, &oper1) == 436*37915d86SRichard Lowe DW_OVERFLOW) { 437*37915d86SRichard Lowe (void) fprintf(stderr, 438*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 439*37915d86SRichard Lowe state->file, state->sh_name); 440*37915d86SRichard Lowe return; 441*37915d86SRichard Lowe } 442*37915d86SRichard Lowe 443*37915d86SRichard Lowe if (uleb_extract(&data[off], ndx, len, &oper2) == 444*37915d86SRichard Lowe DW_OVERFLOW) { 445*37915d86SRichard Lowe (void) fprintf(stderr, 446*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 447*37915d86SRichard Lowe state->file, state->sh_name); 448*37915d86SRichard Lowe return; 449*37915d86SRichard Lowe } 4507e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLU), PREFIX, 4517e16fca0SAli Bahrami REGNAME(oper1, rbuf1), EC_XWORD(oper2)); 4527e16fca0SAli Bahrami break; 4537e16fca0SAli Bahrami 4547e16fca0SAli Bahrami case 0x0e: /* v2: DW_CFA_def_cfa_offset, offset */ 455*37915d86SRichard Lowe if (uleb_extract(&data[off], ndx, len, &oper1) == 456*37915d86SRichard Lowe DW_OVERFLOW) { 457*37915d86SRichard Lowe (void) fprintf(stderr, 458*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 459*37915d86SRichard Lowe state->file, state->sh_name); 460*37915d86SRichard Lowe return; 461*37915d86SRichard Lowe } 4627e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_CFA_LLU), PREFIX, 4637e16fca0SAli Bahrami EC_XWORD(oper1)); 4647e16fca0SAli Bahrami break; 4657e16fca0SAli Bahrami 4667e16fca0SAli Bahrami case 0x0f: /* v3: DW_CFA_def_cfa_expression, blk */ 467*37915d86SRichard Lowe if (uleb_extract(&data[off], ndx, len, &oper1) == 468*37915d86SRichard Lowe DW_OVERFLOW) { 469*37915d86SRichard Lowe (void) fprintf(stderr, 470*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 471*37915d86SRichard Lowe state->file, state->sh_name); 472*37915d86SRichard Lowe return; 473*37915d86SRichard Lowe } 4747e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_CFA_EBLK), PREFIX, 4757e16fca0SAli Bahrami EC_XWORD(oper1)); 4767e16fca0SAli Bahrami /* We currently do not decode the expression block */ 4777e16fca0SAli Bahrami *ndx += oper1; 4787e16fca0SAli Bahrami break; 4797e16fca0SAli Bahrami 4807e16fca0SAli Bahrami case 0x10: /* v3: DW_CFA_expression, reg, blk */ 4817e16fca0SAli Bahrami case 0x16: /* v3: DW_CFA_val_expression,reg,blk */ 482*37915d86SRichard Lowe if (uleb_extract(&data[off], ndx, len, &oper1) == 483*37915d86SRichard Lowe DW_OVERFLOW) { 484*37915d86SRichard Lowe (void) fprintf(stderr, 485*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 486*37915d86SRichard Lowe state->file, state->sh_name); 487*37915d86SRichard Lowe return; 488*37915d86SRichard Lowe } 489*37915d86SRichard Lowe 490*37915d86SRichard Lowe if (uleb_extract(&data[off], ndx, len, &oper2) == 491*37915d86SRichard Lowe DW_OVERFLOW) { 492*37915d86SRichard Lowe (void) fprintf(stderr, 493*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 494*37915d86SRichard Lowe state->file, state->sh_name); 495*37915d86SRichard Lowe return; 496*37915d86SRichard Lowe } 4977e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_CFA_REG_EBLK), PREFIX, 4987e16fca0SAli Bahrami REGNAME(oper1, rbuf1), EC_XWORD(oper2)); 4997e16fca0SAli Bahrami /* We currently do not decode the expression block */ 5007e16fca0SAli Bahrami *ndx += oper2; 5017e16fca0SAli Bahrami break; 5027e16fca0SAli Bahrami 5037e16fca0SAli Bahrami case 0x11: /* v3: DW_CFA_offset_extended_sf, reg, off */ 504*37915d86SRichard Lowe if (uleb_extract(&data[off], ndx, len, &oper1) == 505*37915d86SRichard Lowe DW_OVERFLOW) { 506*37915d86SRichard Lowe (void) fprintf(stderr, 507*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 508*37915d86SRichard Lowe state->file, state->sh_name); 509*37915d86SRichard Lowe return; 510*37915d86SRichard Lowe } 511*37915d86SRichard Lowe 512*37915d86SRichard Lowe if (sleb_extract(&data[off], ndx, len, &soper) == 513*37915d86SRichard Lowe DW_OVERFLOW) { 514*37915d86SRichard Lowe (void) fprintf(stderr, 515*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 516*37915d86SRichard Lowe state->file, state->sh_name); 517*37915d86SRichard Lowe return; 518*37915d86SRichard Lowe } 519*37915d86SRichard Lowe 520*37915d86SRichard Lowe soper *= state->ciedalign; 5217e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX, 5227e16fca0SAli Bahrami REGNAME(oper1, rbuf1), EC_SXWORD(soper)); 5237e16fca0SAli Bahrami break; 5247e16fca0SAli Bahrami 5257e16fca0SAli Bahrami case 0x12: /* v3: DW_CFA_def_cfa_sf, reg, offset */ 526*37915d86SRichard Lowe if (uleb_extract(&data[off], ndx, len, &oper1) == 527*37915d86SRichard Lowe DW_OVERFLOW) { 528*37915d86SRichard Lowe (void) fprintf(stderr, 529*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 530*37915d86SRichard Lowe state->file, state->sh_name); 531*37915d86SRichard Lowe return; 532*37915d86SRichard Lowe } 533*37915d86SRichard Lowe 534*37915d86SRichard Lowe if (sleb_extract(&data[off], ndx, len, &soper) == 535*37915d86SRichard Lowe DW_OVERFLOW) { 536*37915d86SRichard Lowe (void) fprintf(stderr, 537*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 538*37915d86SRichard Lowe state->file, state->sh_name); 539*37915d86SRichard Lowe return; 540*37915d86SRichard Lowe } 541*37915d86SRichard Lowe 542*37915d86SRichard Lowe soper *= state->ciedalign; 5437e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX, 5447e16fca0SAli Bahrami REGNAME(oper1, rbuf1), EC_SXWORD(soper)); 5457e16fca0SAli Bahrami break; 5467e16fca0SAli Bahrami 5477e16fca0SAli Bahrami case 0x13: /* DW_CFA_def_cfa_offset_sf, offset */ 548*37915d86SRichard Lowe if (sleb_extract(&data[off], ndx, len, &soper) == 549*37915d86SRichard Lowe DW_OVERFLOW) { 550*37915d86SRichard Lowe (void) fprintf(stderr, 551*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 552*37915d86SRichard Lowe state->file, state->sh_name); 553*37915d86SRichard Lowe return; 554*37915d86SRichard Lowe } 555*37915d86SRichard Lowe 556*37915d86SRichard Lowe soper *= state->ciedalign; 5577e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_CFA_LLD), PREFIX, 5587e16fca0SAli Bahrami EC_SXWORD(soper)); 5597e16fca0SAli Bahrami break; 5607e16fca0SAli Bahrami 5617e16fca0SAli Bahrami case 0x14: /* v3: DW_CFA_val_offset, reg, offset */ 562*37915d86SRichard Lowe if (uleb_extract(&data[off], ndx, len, &oper1) == 563*37915d86SRichard Lowe DW_OVERFLOW) { 564*37915d86SRichard Lowe (void) fprintf(stderr, 565*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 566*37915d86SRichard Lowe state->file, state->sh_name); 567*37915d86SRichard Lowe return; 568*37915d86SRichard Lowe } 569*37915d86SRichard Lowe 570*37915d86SRichard Lowe if (sleb_extract(&data[off], ndx, len, &soper) == 571*37915d86SRichard Lowe DW_OVERFLOW) { 572*37915d86SRichard Lowe (void) fprintf(stderr, 573*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 574*37915d86SRichard Lowe state->file, state->sh_name); 575*37915d86SRichard Lowe return; 576*37915d86SRichard Lowe } 577*37915d86SRichard Lowe 578*37915d86SRichard Lowe soper *= state->ciedalign; 5797e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX, 5807e16fca0SAli Bahrami REGNAME(oper1, rbuf1), EC_SXWORD(soper)); 5817e16fca0SAli Bahrami break; 5827e16fca0SAli Bahrami 5837e16fca0SAli Bahrami case 0x15: /* v3: DW_CFA_val_offset_sf, reg, offset */ 584*37915d86SRichard Lowe if (uleb_extract(&data[off], ndx, len, &oper1) == 585*37915d86SRichard Lowe DW_OVERFLOW) { 586*37915d86SRichard Lowe (void) fprintf(stderr, 587*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 588*37915d86SRichard Lowe state->file, state->sh_name); 589*37915d86SRichard Lowe return; 590*37915d86SRichard Lowe } 591*37915d86SRichard Lowe 592*37915d86SRichard Lowe if (sleb_extract(&data[off], ndx, len, &soper) == 593*37915d86SRichard Lowe DW_OVERFLOW) { 594*37915d86SRichard Lowe (void) fprintf(stderr, 595*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 596*37915d86SRichard Lowe state->file, state->sh_name); 597*37915d86SRichard Lowe return; 598*37915d86SRichard Lowe } 599*37915d86SRichard Lowe 600*37915d86SRichard Lowe soper *= state->ciedalign; 6017e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX, 6027e16fca0SAli Bahrami REGNAME(oper1, rbuf1), EC_SXWORD(soper)); 6037e16fca0SAli Bahrami break; 6047e16fca0SAli Bahrami 6057e16fca0SAli Bahrami case 0x1d: /* GNU: DW_CFA_MIPS_advance_loc8, delta */ 606*37915d86SRichard Lowe switch (dwarf_extract_uint(data + off, len, 607*37915d86SRichard Lowe ndx, 8, state->do_swap, &oper1)) { 608*37915d86SRichard Lowe case DW_BAD_ENCODING: 609*37915d86SRichard Lowe (void) fprintf(stderr, 610*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWBADENC), 611*37915d86SRichard Lowe state->file, state->sh_name, 612*37915d86SRichard Lowe 8); 613*37915d86SRichard Lowe return; 614*37915d86SRichard Lowe case DW_OVERFLOW: 615*37915d86SRichard Lowe (void) fprintf(stderr, 616*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 617*37915d86SRichard Lowe state->file, state->sh_name); 618*37915d86SRichard Lowe return; 619*37915d86SRichard Lowe case DW_SUCCESS: 620*37915d86SRichard Lowe break; 621*37915d86SRichard Lowe } 622*37915d86SRichard Lowe oper1 *= state->ciecalign; 6237e16fca0SAli Bahrami cur_pc += oper1; 6247e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX, 6257e16fca0SAli Bahrami loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc)); 6267e16fca0SAli Bahrami loc_str = MSG_ORIG(MSG_STR_LOC); 6277e16fca0SAli Bahrami break; 6287e16fca0SAli Bahrami 6297e16fca0SAli Bahrami case 0x2e: /* GNU: DW_CFA_GNU_args_size, size */ 630*37915d86SRichard Lowe if (uleb_extract(&data[off], ndx, len, &oper1) == 631*37915d86SRichard Lowe DW_OVERFLOW) { 632*37915d86SRichard Lowe (void) fprintf(stderr, 633*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 634*37915d86SRichard Lowe state->file, state->sh_name); 635*37915d86SRichard Lowe return; 636*37915d86SRichard Lowe } 637*37915d86SRichard Lowe 6387e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_CFA_LLU), PREFIX, 6397e16fca0SAli Bahrami EC_XWORD(oper1)); 6407e16fca0SAli Bahrami 6417e16fca0SAli Bahrami break; 6427e16fca0SAli Bahrami 6437e16fca0SAli Bahrami case 0x2f: /* GNU:DW_CFA_GNU_negative_offset_extended,reg,off */ 644*37915d86SRichard Lowe if (uleb_extract(&data[off], ndx, len, &oper1) == 645*37915d86SRichard Lowe DW_OVERFLOW) { 646*37915d86SRichard Lowe (void) fprintf(stderr, 647*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 648*37915d86SRichard Lowe state->file, state->sh_name); 649*37915d86SRichard Lowe return; 650*37915d86SRichard Lowe } 651*37915d86SRichard Lowe 652*37915d86SRichard Lowe if (sleb_extract(&data[off], ndx, len, &soper) == 653*37915d86SRichard Lowe DW_OVERFLOW) { 654*37915d86SRichard Lowe (void) fprintf(stderr, 655*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 656*37915d86SRichard Lowe state->file, state->sh_name); 657*37915d86SRichard Lowe return; 658*37915d86SRichard Lowe } 659*37915d86SRichard Lowe soper = -soper * state->ciedalign; 660*37915d86SRichard Lowe soper *= state->ciedalign; 6617e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX, 6627e16fca0SAli Bahrami REGNAME(oper1, rbuf1), EC_SXWORD(soper)); 6637e16fca0SAli Bahrami break; 6647e16fca0SAli Bahrami 6657e16fca0SAli Bahrami default: 6667e16fca0SAli Bahrami /* 6677e16fca0SAli Bahrami * Unrecognized OP code: DWARF data is variable length, 6687e16fca0SAli Bahrami * so we don't know how many bytes to skip in order to 6697e16fca0SAli Bahrami * advance to the next item. We cannot decode beyond 6707e16fca0SAli Bahrami * this point, so dump the remainder in hex. 6717e16fca0SAli Bahrami */ 6727e16fca0SAli Bahrami (*ndx)--; /* Back up to unrecognized opcode */ 6737e16fca0SAli Bahrami dump_hex_bytes(data + off + *ndx, len - *ndx, 6747e16fca0SAli Bahrami indent, 8, 1); 6757e16fca0SAli Bahrami (*ndx) = len; 6767e16fca0SAli Bahrami break; 6777e16fca0SAli Bahrami } 6787e16fca0SAli Bahrami } 6797e16fca0SAli Bahrami 6807e16fca0SAli Bahrami #undef PREFIX 6817e16fca0SAli Bahrami #undef REGNAME 6827e16fca0SAli Bahrami #undef LOW_OP 6837e16fca0SAli Bahrami } 6847e16fca0SAli Bahrami 6857e16fca0SAli Bahrami void 686*37915d86SRichard Lowe dump_eh_frame(const char *file, char *sh_name, uchar_t *data, size_t datasize, 687*37915d86SRichard Lowe uint64_t sh_addr, Half e_machine, uchar_t *e_ident, uint64_t gotaddr) 6887e16fca0SAli Bahrami { 6897e16fca0SAli Bahrami Conv_dwarf_ehe_buf_t dwarf_ehe_buf; 6907e16fca0SAli Bahrami dump_cfi_state_t cfi_state; 691*37915d86SRichard Lowe uint64_t off, ndx, length, id; 6927e16fca0SAli Bahrami uint_t cieid, cielength, cieversion, cieretaddr; 693*37915d86SRichard Lowe int ciePflag = 0, cieZflag = 0, cieLflag = 0; 694*37915d86SRichard Lowe int cieLflag_present = 0; 695*37915d86SRichard Lowe uint_t cieaugndx; 696*37915d86SRichard Lowe char *cieaugstr = NULL; 697*37915d86SRichard Lowe boolean_t have_cie = B_FALSE; 6987e16fca0SAli Bahrami 699*37915d86SRichard Lowe cfi_state.file = file; 700*37915d86SRichard Lowe cfi_state.sh_name = sh_name; 7017e16fca0SAli Bahrami cfi_state.e_machine = e_machine; 7027e16fca0SAli Bahrami cfi_state.e_ident = e_ident; 7037e16fca0SAli Bahrami cfi_state.sh_addr = sh_addr; 7047e16fca0SAli Bahrami cfi_state.do_swap = _elf_sys_encoding() != e_ident[EI_DATA]; 705965630c1SRichard Lowe cfi_state.gotaddr = gotaddr; 7067e16fca0SAli Bahrami 7077e16fca0SAli Bahrami off = 0; 7087e16fca0SAli Bahrami while (off < datasize) { 7097e16fca0SAli Bahrami ndx = 0; 7107e16fca0SAli Bahrami 7117e16fca0SAli Bahrami /* 7127e16fca0SAli Bahrami * Extract length in native format. A zero length indicates 7137e16fca0SAli Bahrami * that this CIE is a terminator and that processing for this 7147e16fca0SAli Bahrami * unwind information should end. However, skip this entry and 7157e16fca0SAli Bahrami * keep processing, just in case there is any other information 7167e16fca0SAli Bahrami * remaining in this section. Note, ld(1) will terminate the 7177e16fca0SAli Bahrami * processing of the .eh_frame contents for this file after a 7187e16fca0SAli Bahrami * zero length CIE, thus any information that does follow is 7197e16fca0SAli Bahrami * ignored by ld(1), and is therefore questionable. 7207e16fca0SAli Bahrami */ 721*37915d86SRichard Lowe if (dwarf_extract_uint(data + off, datasize - off, 722*37915d86SRichard Lowe &ndx, 4, cfi_state.do_swap, &length) == DW_OVERFLOW) { 723*37915d86SRichard Lowe (void) fprintf(stderr, 724*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 725*37915d86SRichard Lowe file, sh_name); 726*37915d86SRichard Lowe return; 727*37915d86SRichard Lowe } 728*37915d86SRichard Lowe 7297e16fca0SAli Bahrami if (length == 0) { 7307e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_UNW_ZEROTERM)); 7317e16fca0SAli Bahrami off += 4; 7327e16fca0SAli Bahrami continue; 7337e16fca0SAli Bahrami } 7347e16fca0SAli Bahrami 735*37915d86SRichard Lowe if (length > (datasize - off)) { 736*37915d86SRichard Lowe (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADCIEFDELEN), 737*37915d86SRichard Lowe file, sh_name, EC_XWORD(length), 738*37915d86SRichard Lowe EC_XWORD(sh_addr + off)); 739*37915d86SRichard Lowe /* 740*37915d86SRichard Lowe * If length is wrong, we have no means to find the 741*37915d86SRichard Lowe * next entry, just give up 742*37915d86SRichard Lowe */ 743*37915d86SRichard Lowe return; 744*37915d86SRichard Lowe } 745*37915d86SRichard Lowe 7467e16fca0SAli Bahrami /* 7477e16fca0SAli Bahrami * extract CIE id in native format 7487e16fca0SAli Bahrami */ 749*37915d86SRichard Lowe if (dwarf_extract_uint(data + off, datasize - off, &ndx, 750*37915d86SRichard Lowe 4, cfi_state.do_swap, &id) == DW_OVERFLOW) { 751*37915d86SRichard Lowe (void) fprintf(stderr, 752*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 753*37915d86SRichard Lowe file, sh_name); 754*37915d86SRichard Lowe return; 755*37915d86SRichard Lowe } 7567e16fca0SAli Bahrami 7577e16fca0SAli Bahrami /* 7587e16fca0SAli Bahrami * A CIE record has an id of '0', otherwise this is a 7597e16fca0SAli Bahrami * FDE entry and the 'id' is the CIE pointer. 7607e16fca0SAli Bahrami */ 7617e16fca0SAli Bahrami if (id == 0) { 762*37915d86SRichard Lowe uint64_t persVal, ndx_save = 0; 763*37915d86SRichard Lowe uint64_t axsize; 7647e16fca0SAli Bahrami 765*37915d86SRichard Lowe 766*37915d86SRichard Lowe have_cie = B_TRUE; 7677e16fca0SAli Bahrami cielength = length; 7687e16fca0SAli Bahrami cieid = id; 7697e16fca0SAli Bahrami ciePflag = cfi_state.cieRflag = cieZflag = 0; 7707e16fca0SAli Bahrami cieLflag = cieLflag_present = 0; 7717e16fca0SAli Bahrami 7727e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_UNW_CIE), 7737e16fca0SAli Bahrami EC_XWORD(sh_addr + off)); 7747e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_UNW_CIELNGTH), 7757e16fca0SAli Bahrami cielength, cieid); 7767e16fca0SAli Bahrami 7777e16fca0SAli Bahrami cieversion = data[off + ndx]; 7787e16fca0SAli Bahrami ndx += 1; 7797e16fca0SAli Bahrami cieaugstr = (char *)(&data[off + ndx]); 7807e16fca0SAli Bahrami ndx += strlen(cieaugstr) + 1; 7817e16fca0SAli Bahrami 7827e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_UNW_CIEVERS), 7837e16fca0SAli Bahrami cieversion, cieaugstr); 7847e16fca0SAli Bahrami 785*37915d86SRichard Lowe if (uleb_extract(&data[off], &ndx, datasize - off, 786*37915d86SRichard Lowe &cfi_state.ciecalign) == DW_OVERFLOW) { 787*37915d86SRichard Lowe (void) fprintf(stderr, 788*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 789*37915d86SRichard Lowe file, sh_name); 790*37915d86SRichard Lowe return; 791*37915d86SRichard Lowe } 792*37915d86SRichard Lowe 793*37915d86SRichard Lowe if (sleb_extract(&data[off], &ndx, datasize - off, 794*37915d86SRichard Lowe &cfi_state.ciedalign) == DW_OVERFLOW) { 795*37915d86SRichard Lowe (void) fprintf(stderr, 796*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 797*37915d86SRichard Lowe file, sh_name); 798*37915d86SRichard Lowe return; 799*37915d86SRichard Lowe } 8007e16fca0SAli Bahrami cieretaddr = data[off + ndx]; 8017e16fca0SAli Bahrami ndx += 1; 8027e16fca0SAli Bahrami 8037e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_UNW_CIECALGN), 8047e16fca0SAli Bahrami EC_XWORD(cfi_state.ciecalign), 8057e16fca0SAli Bahrami EC_XWORD(cfi_state.ciedalign), cieretaddr); 8067e16fca0SAli Bahrami 8077e16fca0SAli Bahrami if (cieaugstr[0]) 8087e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_UNW_CIEAXVAL)); 8097e16fca0SAli Bahrami 8107e16fca0SAli Bahrami for (cieaugndx = 0; cieaugstr[cieaugndx]; cieaugndx++) { 8117e16fca0SAli Bahrami switch (cieaugstr[cieaugndx]) { 8127e16fca0SAli Bahrami case 'z': 813*37915d86SRichard Lowe if (uleb_extract(&data[off], &ndx, 814*37915d86SRichard Lowe datasize - off, &axsize) == 815*37915d86SRichard Lowe DW_OVERFLOW) { 816*37915d86SRichard Lowe (void) fprintf(stderr, 817*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 818*37915d86SRichard Lowe file, sh_name); 819*37915d86SRichard Lowe return; 820*37915d86SRichard Lowe } 821*37915d86SRichard Lowe 8227e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_UNW_CIEAXSIZ), 823*37915d86SRichard Lowe EC_XWORD(axsize)); 8247e16fca0SAli Bahrami cieZflag = 1; 8257e16fca0SAli Bahrami /* 8267e16fca0SAli Bahrami * The auxiliary section can contain 8277e16fca0SAli Bahrami * unused padding bytes at the end, so 8287e16fca0SAli Bahrami * save the current index. Along with 8297e16fca0SAli Bahrami * axsize, we will use it to set ndx to 8307e16fca0SAli Bahrami * the proper continuation index after 8317e16fca0SAli Bahrami * the aux data has been processed. 8327e16fca0SAli Bahrami */ 8337e16fca0SAli Bahrami ndx_save = ndx; 8347e16fca0SAli Bahrami break; 8357e16fca0SAli Bahrami case 'P': 8367e16fca0SAli Bahrami ciePflag = data[off + ndx]; 8377e16fca0SAli Bahrami ndx += 1; 8387e16fca0SAli Bahrami 839*37915d86SRichard Lowe switch (dwarf_ehe_extract(&data[off], 840*37915d86SRichard Lowe datasize - off, &ndx, &persVal, 841*37915d86SRichard Lowe ciePflag, e_ident, B_FALSE, sh_addr, 842*37915d86SRichard Lowe off + ndx, gotaddr)) { 843*37915d86SRichard Lowe case DW_OVERFLOW: 844*37915d86SRichard Lowe (void) fprintf(stderr, 845*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 846*37915d86SRichard Lowe file, sh_name); 847*37915d86SRichard Lowe return; 848*37915d86SRichard Lowe case DW_BAD_ENCODING: 849*37915d86SRichard Lowe (void) fprintf(stderr, 850*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWBADENC), 851*37915d86SRichard Lowe file, sh_name, ciePflag); 852*37915d86SRichard Lowe return; 853*37915d86SRichard Lowe case DW_SUCCESS: 854*37915d86SRichard Lowe break; 855*37915d86SRichard Lowe } 8567e16fca0SAli Bahrami dbg_print(0, 8577e16fca0SAli Bahrami MSG_ORIG(MSG_UNW_CIEAXPERS)); 8587e16fca0SAli Bahrami dbg_print(0, 8597e16fca0SAli Bahrami MSG_ORIG(MSG_UNW_CIEAXPERSENC), 8607e16fca0SAli Bahrami ciePflag, conv_dwarf_ehe(ciePflag, 8617e16fca0SAli Bahrami &dwarf_ehe_buf)); 8627e16fca0SAli Bahrami dbg_print(0, 8637e16fca0SAli Bahrami MSG_ORIG(MSG_UNW_CIEAXPERSRTN), 8647e16fca0SAli Bahrami EC_XWORD(persVal)); 8657e16fca0SAli Bahrami break; 8667e16fca0SAli Bahrami case 'R': 8677e16fca0SAli Bahrami cfi_state.cieRflag = data[off + ndx]; 8687e16fca0SAli Bahrami ndx += 1; 8697e16fca0SAli Bahrami dbg_print(0, 8707e16fca0SAli Bahrami MSG_ORIG(MSG_UNW_CIEAXCENC), 8717e16fca0SAli Bahrami cfi_state.cieRflag, 8727e16fca0SAli Bahrami conv_dwarf_ehe(cfi_state.cieRflag, 8737e16fca0SAli Bahrami &dwarf_ehe_buf)); 8747e16fca0SAli Bahrami break; 8757e16fca0SAli Bahrami case 'L': 8767e16fca0SAli Bahrami cieLflag_present = 1; 8777e16fca0SAli Bahrami cieLflag = data[off + ndx]; 8787e16fca0SAli Bahrami ndx += 1; 8797e16fca0SAli Bahrami dbg_print(0, 8807e16fca0SAli Bahrami MSG_ORIG(MSG_UNW_CIEAXLSDA), 8817e16fca0SAli Bahrami cieLflag, conv_dwarf_ehe( 8827e16fca0SAli Bahrami cieLflag, &dwarf_ehe_buf)); 8837e16fca0SAli Bahrami break; 8847e16fca0SAli Bahrami default: 8857e16fca0SAli Bahrami dbg_print(0, 8867e16fca0SAli Bahrami MSG_ORIG(MSG_UNW_CIEAXUNEC), 8877e16fca0SAli Bahrami cieaugstr[cieaugndx]); 8887e16fca0SAli Bahrami break; 8897e16fca0SAli Bahrami } 8907e16fca0SAli Bahrami } 8917e16fca0SAli Bahrami 8927e16fca0SAli Bahrami /* 8937e16fca0SAli Bahrami * If the z flag was present, reposition ndx using the 8947e16fca0SAli Bahrami * length given. This will safely move us past any 8957e16fca0SAli Bahrami * unaccessed padding bytes in the auxiliary section. 8967e16fca0SAli Bahrami */ 8977e16fca0SAli Bahrami if (cieZflag) 8987e16fca0SAli Bahrami ndx = ndx_save + axsize; 8997e16fca0SAli Bahrami 9007e16fca0SAli Bahrami /* 9017e16fca0SAli Bahrami * Any remaining data are Call Frame Instructions 9027e16fca0SAli Bahrami */ 9037e16fca0SAli Bahrami if ((cielength + 4) > ndx) 9047e16fca0SAli Bahrami dump_cfi(data, off, &ndx, cielength, &cfi_state, 9057e16fca0SAli Bahrami MSG_ORIG(MSG_UNW_CIECFI), 3); 9067e16fca0SAli Bahrami off += cielength + 4; 9077e16fca0SAli Bahrami 9087e16fca0SAli Bahrami } else { 9097e16fca0SAli Bahrami uint_t fdelength = length; 9107e16fca0SAli Bahrami int fdecieptr = id; 9117e16fca0SAli Bahrami uint64_t fdeaddrrange; 9127e16fca0SAli Bahrami 913*37915d86SRichard Lowe if (!have_cie) { 914*37915d86SRichard Lowe (void) fprintf(stderr, 915*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWNOCIE), file, sh_name); 916*37915d86SRichard Lowe return; 917*37915d86SRichard Lowe } 918*37915d86SRichard Lowe 9197e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_UNW_FDE), 9207e16fca0SAli Bahrami EC_XWORD(sh_addr + off)); 9217e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_UNW_FDELNGTH), 9227e16fca0SAli Bahrami fdelength, fdecieptr); 9237e16fca0SAli Bahrami 924*37915d86SRichard Lowe switch (dwarf_ehe_extract(&data[off], datasize - off, 925*37915d86SRichard Lowe &ndx, &cfi_state.fdeinitloc, cfi_state.cieRflag, 926*37915d86SRichard Lowe e_ident, B_FALSE, sh_addr, off + ndx, gotaddr)) { 927*37915d86SRichard Lowe case DW_OVERFLOW: 928*37915d86SRichard Lowe (void) fprintf(stderr, 929*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), file, sh_name); 930*37915d86SRichard Lowe return; 931*37915d86SRichard Lowe case DW_BAD_ENCODING: 932*37915d86SRichard Lowe (void) fprintf(stderr, 933*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWBADENC), file, sh_name, 934*37915d86SRichard Lowe cfi_state.cieRflag); 935*37915d86SRichard Lowe return; 936*37915d86SRichard Lowe case DW_SUCCESS: 937*37915d86SRichard Lowe break; 938*37915d86SRichard Lowe } 939*37915d86SRichard Lowe 940*37915d86SRichard Lowe switch (dwarf_ehe_extract(&data[off], datasize - off, 941*37915d86SRichard Lowe &ndx, &fdeaddrrange, 942*37915d86SRichard Lowe (cfi_state.cieRflag & ~DW_EH_PE_pcrel), e_ident, 943*37915d86SRichard Lowe B_FALSE, sh_addr, off + ndx, gotaddr)) { 944*37915d86SRichard Lowe case DW_OVERFLOW: 945*37915d86SRichard Lowe (void) fprintf(stderr, 946*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), file, sh_name); 947*37915d86SRichard Lowe return; 948*37915d86SRichard Lowe case DW_BAD_ENCODING: 949*37915d86SRichard Lowe (void) fprintf(stderr, 950*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWBADENC), file, sh_name, 951*37915d86SRichard Lowe (cfi_state.cieRflag & ~DW_EH_PE_pcrel)); 952*37915d86SRichard Lowe return; 953*37915d86SRichard Lowe case DW_SUCCESS: 954*37915d86SRichard Lowe break; 955*37915d86SRichard Lowe } 9567e16fca0SAli Bahrami 9577e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_UNW_FDEINITLOC), 9587e16fca0SAli Bahrami EC_XWORD(cfi_state.fdeinitloc), 9597e16fca0SAli Bahrami EC_XWORD(fdeaddrrange), 9607e16fca0SAli Bahrami EC_XWORD(cfi_state.fdeinitloc + fdeaddrrange - 1)); 9617e16fca0SAli Bahrami 962*37915d86SRichard Lowe if ((cieaugstr != NULL) && (cieaugstr[0] != '\0')) 9637e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_UNW_FDEAXVAL)); 9647e16fca0SAli Bahrami if (cieZflag) { 9657e16fca0SAli Bahrami uint64_t val; 9667e16fca0SAli Bahrami uint64_t lndx; 9677e16fca0SAli Bahrami 968*37915d86SRichard Lowe if (uleb_extract(&data[off], &ndx, 969*37915d86SRichard Lowe datasize - off, &val) == DW_OVERFLOW) { 970*37915d86SRichard Lowe (void) fprintf(stderr, 971*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 972*37915d86SRichard Lowe file, sh_name); 973*37915d86SRichard Lowe return; 974*37915d86SRichard Lowe } 9757e16fca0SAli Bahrami lndx = ndx; 9767e16fca0SAli Bahrami ndx += val; 9777e16fca0SAli Bahrami dbg_print(0, MSG_ORIG(MSG_UNW_FDEAXSIZE), 9787e16fca0SAli Bahrami EC_XWORD(val)); 9797e16fca0SAli Bahrami if (val && cieLflag_present) { 9807e16fca0SAli Bahrami uint64_t lsda; 9817e16fca0SAli Bahrami 982*37915d86SRichard Lowe switch (dwarf_ehe_extract(&data[off], 983*37915d86SRichard Lowe datasize - off, &lndx, &lsda, 984*37915d86SRichard Lowe cieLflag, e_ident, B_FALSE, sh_addr, 985*37915d86SRichard Lowe off + lndx, gotaddr)) { 986*37915d86SRichard Lowe case DW_OVERFLOW: 987*37915d86SRichard Lowe (void) fprintf(stderr, 988*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWOVRFLW), 989*37915d86SRichard Lowe file, sh_name); 990*37915d86SRichard Lowe return; 991*37915d86SRichard Lowe case DW_BAD_ENCODING: 992*37915d86SRichard Lowe (void) fprintf(stderr, 993*37915d86SRichard Lowe MSG_INTL(MSG_ERR_DWBADENC), 994*37915d86SRichard Lowe file, sh_name, cieLflag); 995*37915d86SRichard Lowe return; 996*37915d86SRichard Lowe case DW_SUCCESS: 997*37915d86SRichard Lowe break; 998*37915d86SRichard Lowe } 9997e16fca0SAli Bahrami dbg_print(0, 10007e16fca0SAli Bahrami MSG_ORIG(MSG_UNW_FDEAXLSDA), 10017e16fca0SAli Bahrami EC_XWORD(lsda)); 10027e16fca0SAli Bahrami } 10037e16fca0SAli Bahrami } 10047e16fca0SAli Bahrami if ((fdelength + 4) > ndx) 10057e16fca0SAli Bahrami dump_cfi(data, off, &ndx, fdelength, &cfi_state, 10067e16fca0SAli Bahrami MSG_ORIG(MSG_UNW_FDECFI), 6); 10077e16fca0SAli Bahrami off += fdelength + 4; 10087e16fca0SAli Bahrami } 10097e16fca0SAli Bahrami } 10107e16fca0SAli Bahrami } 1011