diff options
author | Ali Bahrami <Ali.Bahrami@Sun.COM> | 2009-03-18 13:28:28 -0600 |
---|---|---|
committer | Ali Bahrami <Ali.Bahrami@Sun.COM> | 2009-03-18 13:28:28 -0600 |
commit | 7e16fca05dfbcfd32c2ebc9e4d1abdac1cd8657c (patch) | |
tree | 5033ac748bcd6544a0981e069919df2d213acead /usr/src | |
parent | c13e065d8ffc8eafc02caf1091e66e146a2b2ce4 (diff) | |
download | illumos-gate-7e16fca05dfbcfd32c2ebc9e4d1abdac1cd8657c.tar.gz |
6813909 generalize eh_frame support to non-amd64 platforms
--HG--
rename : usr/src/cmd/sgs/libld/common/unwind.amd.c => usr/src/cmd/sgs/libld/common/unwind.c
Diffstat (limited to 'usr/src')
46 files changed, 1804 insertions, 663 deletions
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_gelf.c b/usr/src/cmd/mdb/common/mdb/mdb_gelf.c index bc680aad79..8cedd78014 100644 --- a/usr/src/cmd/mdb/common/mdb/mdb_gelf.c +++ b/usr/src/cmd/mdb/common/mdb/mdb_gelf.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -927,6 +927,10 @@ gelf32_symtab_sort(mdb_gelf_symtab_t *gst) static void gelf32_symtab_init(mdb_gelf_symtab_t *gst) { +#if STT_NUM != (STT_IFUNC + 1) +#error "STT_NUM has grown. update gelf32_symtab_init()" +#endif + const char *base = (const char *)gst->gst_ssect->gs_data; Elf32_Sym *sym = gst->gst_dsect->gs_data; mdb_nv_t *nv = &gst->gst_nv; @@ -950,7 +954,7 @@ gelf32_symtab_init(mdb_gelf_symtab_t *gst) const char *name = base + sym->st_name; uchar_t type = ELF32_ST_TYPE(sym->st_info); - if (type >= STT_NUM || type == STT_SECTION) + if (type >= STT_IFUNC || type == STT_SECTION) continue; /* skip sections and unknown types */ if (sym->st_name >= ss_size || name[0] < '!' || name[0] > '~') { @@ -1020,6 +1024,10 @@ gelf64_symtab_sort(mdb_gelf_symtab_t *gst) static void gelf64_symtab_init(mdb_gelf_symtab_t *gst) { +#if STT_NUM != (STT_IFUNC + 1) +#error "STT_NUM has grown. update gelf64_symtab_init()" +#endif + const char *base = (const char *)gst->gst_ssect->gs_data; Elf64_Sym *sym = gst->gst_dsect->gs_data; mdb_nv_t *nv = &gst->gst_nv; @@ -1043,7 +1051,7 @@ gelf64_symtab_init(mdb_gelf_symtab_t *gst) const char *name = base + sym->st_name; uchar_t type = ELF64_ST_TYPE(sym->st_info); - if (type >= STT_NUM || type == STT_SECTION) + if (type >= STT_IFUNC || type == STT_SECTION) continue; /* skip sections and unknown types */ if (sym->st_name >= ss_size || name[0] < '!' || name[0] > '~') { diff --git a/usr/src/cmd/mdb/common/mdb/mdb_target.c b/usr/src/cmd/mdb/common/mdb/mdb_target.c index cd05e72459..8720ae080e 100644 --- a/usr/src/cmd/mdb/common/mdb/mdb_target.c +++ b/usr/src/cmd/mdb/common/mdb/mdb_target.c @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * MDB Target Layer * @@ -1904,6 +1902,10 @@ mdb_tgt_xdata_delete(mdb_tgt_t *t, const char *name) int mdb_tgt_sym_match(const GElf_Sym *sym, uint_t mask) { +#if STT_NUM != (STT_IFUNC + 1) +#error "STT_NUM has grown. update mdb_tgt_sym_match()" +#endif + uchar_t s_bind = GELF_ST_BIND(sym->st_info); uchar_t s_type = GELF_ST_TYPE(sym->st_info); @@ -1911,10 +1913,10 @@ mdb_tgt_sym_match(const GElf_Sym *sym, uint_t mask) * In case you haven't already guessed, this relies on the bitmask * used by <mdb/mdb_target.h> and <libproc.h> for encoding symbol * type and binding matching the order of STB and STT constants - * in <sys/elf.h>. ELF can't change without breaking binary + * in <sys/elf.h>. Changes to ELF must maintain binary * compatibility, so I think this is reasonably fair game. */ - if (s_bind < STB_NUM && s_type < STT_NUM) { + if (s_bind < STB_NUM && s_type < STT_IFUNC) { uint_t type = (1 << (s_type + 8)) | (1 << s_bind); return ((type & ~mask) == 0); } diff --git a/usr/src/cmd/sgs/elfdump/Makefile.com b/usr/src/cmd/sgs/elfdump/Makefile.com index 81cc5c31c5..19c8c82ba5 100644 --- a/usr/src/cmd/sgs/elfdump/Makefile.com +++ b/usr/src/cmd/sgs/elfdump/Makefile.com @@ -20,20 +20,19 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" -# PROG= elfdump include $(SRC)/cmd/Makefile.cmd include $(SRC)/cmd/sgs/Makefile.com -COMOBJ = main.o corenote.o struct_layout.o \ - struct_layout_i386.o struct_layout_amd64.o \ - struct_layout_sparc.o struct_layout_sparcv9.o +COMOBJ = main.o corenote.o \ + dwarf.o struct_layout.o \ + struct_layout_i386.o struct_layout_amd64.o \ + struct_layout_sparc.o struct_layout_sparcv9.o COMOBJ32 = elfdump32.o fake_shdr32.o diff --git a/usr/src/cmd/sgs/elfdump/common/_elfdump.h b/usr/src/cmd/sgs/elfdump/common/_elfdump.h index 0bf02e33f2..50c96c7042 100644 --- a/usr/src/cmd/sgs/elfdump/common/_elfdump.h +++ b/usr/src/cmd/sgs/elfdump/common/_elfdump.h @@ -20,15 +20,13 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef __ELFDUMP_H #define __ELFDUMP_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <_machelf.h> #include <debug.h> @@ -224,7 +222,9 @@ typedef enum { #endif extern corenote_ret_t corenote(Half, int, Word, const char *, Word); -extern void dump_hex_bytes(const char *, size_t, int, int, int); +extern void dump_eh_frame(uchar_t *, size_t, uint64_t, Half e_machine, + uchar_t *e_ident); +extern void dump_hex_bytes(const void *, size_t, int, int, int); extern int fake_shdr_cache32(const char *, int, Elf *, Elf32_Ehdr *, Cache **, size_t *); diff --git a/usr/src/cmd/sgs/elfdump/common/dwarf.c b/usr/src/cmd/sgs/elfdump/common/dwarf.c new file mode 100644 index 0000000000..ae95e09630 --- /dev/null +++ b/usr/src/cmd/sgs/elfdump/common/dwarf.c @@ -0,0 +1,675 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <_libelf.h> +#include <dwarf.h> +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <strings.h> +#include <debug.h> +#include <conv.h> +#include <msg.h> +#include <_elfdump.h> + + +/* + * Data from eh_frame section used by dump_cfi() + */ +typedef struct { + Half e_machine; /* ehdr->e_machine */ + uchar_t *e_ident; /* ehdr->e_ident */ + uint64_t sh_addr; /* Address of eh_frame section */ + int do_swap; /* True if object and system byte */ + /* order differs */ + int cieRflag; /* R flag from current CIE */ + uint64_t ciecalign; /* CIE code align factor */ + int64_t ciedalign; /* CIE data align factor */ + uint64_t fdeinitloc; /* FDE initial location */ +} dump_cfi_state_t; + + +/* + * Extract an unsigned integer value from an .eh_frame section, converting it + * from its native byte order to that of the running machine if necessary. + * + * entry: + * data - Base address from which to extract datum + * ndx - Address of variable giving index to start byte in data. + * size - # of bytes in datum. Must be one of: 1, 2, 4, 8 + * do_swap - True if the data is in a different byte order than that + * of the host system. + * + * exit: + * *ndx is incremented by the size of the extracted datum. + * + * The requested datum is extracted, byte swapped if necessary, + * and returned. + */ +static uint64_t +dwarf_extract_uint(uchar_t *data, uint64_t *ndx, int size, int do_swap) +{ + switch (size) { + case 1: + return (data[(*ndx)++]); + case 2: + { + Half r; + uchar_t *p = (uchar_t *)&r; + + data += *ndx; + if (do_swap) + UL_ASSIGN_BSWAP_HALF(p, data); + else + UL_ASSIGN_HALF(p, data); + + (*ndx) += 2; + return (r); + } + case 4: + { + Word r; + uchar_t *p = (uchar_t *)&r; + + data += *ndx; + if (do_swap) + UL_ASSIGN_BSWAP_WORD(p, data); + else + UL_ASSIGN_WORD(p, data); + + (*ndx) += 4; + return (r); + } + + case 8: + { + uint64_t r; + uchar_t *p = (uchar_t *)&r; + + data += *ndx; + if (do_swap) + UL_ASSIGN_BSWAP_LWORD(p, data); + else + UL_ASSIGN_LWORD(p, data); + + (*ndx) += 8; + return (r); + } + } + + /* If here, an invalid size was specified */ + assert(0); + return (0); +} + +/* + * Map a DWARF register constant to the machine register name it + * corresponds to, formatting the result into buf. + * + * The assignment of DWARF register numbers is part of the system + * specific ABI for each platform. + * + * entry: + * regno - DWARF register number + * mach - ELF machine code for platform + * buf, bufsize - Buffer to receive the formatted result string + * + * exit: + * The results are formatted into buf, and buf is returned. + * If the generated output would exceed the size of the buffer + * provided, it will be clipped to fit. + */ +static const char * +dwarf_regname(Half mach, int regno, char *buf, size_t bufsize) +{ + Conv_inv_buf_t inv_buf; + const char *name; + int good_name; + + name = conv_dwarf_regname(mach, regno, 0, &good_name, &inv_buf); + + /* + * If there is a good mnemonic machine name for the register, + * format the result as 'r# (mnemonic)'. If there is no good + * name for it, then simply format the dwarf name as 'r#'. + */ + if (good_name) + (void) snprintf(buf, bufsize, MSG_ORIG(MSG_REG_FMT_NAME), + regno, name); + else + (void) snprintf(buf, bufsize, MSG_ORIG(MSG_REG_FMT_BASIC), + regno); + + return (buf); +} + + +/* + * Decode eh_frame Call Frame Instructions, printing each one on a + * separate line. + * + * entry: + * data - Address of base of eh_frame section being processed + * off - Offset of current FDE within eh_frame + * ndx - Index of current position within current FDE + * len - Length of eh_frame section + * state - Object, CIE, and FDE state for current request + * msg - Header message to issue before producing output. + * indent - # of indentation characters issued for each line of output. + * + * exit: + * The Call Frame Instructions have been decoded and printed. + * + * *ndx has been incremented to contain the index of the next + * byte of data to be processed in eh_frame. + * + * note: + * The format of Call Frame Instructions in .eh_frame sections is based + * on the DWARF specification. + */ +static void +dump_cfi(uchar_t *data, uint64_t off, uint64_t *ndx, uint_t len, + dump_cfi_state_t *state, const char *msg, int indent) +{ + /* + * We use %*s%s to insert leading whitespace and the op name. + * PREFIX supplies these arguments. + */ +#define PREFIX indent, MSG_ORIG(MSG_STR_EMPTY), opname + + /* Hide boilerplate clutter in calls to dwarf_regname() */ +#define REGNAME(_rnum, _buf) \ + dwarf_regname(state->e_machine, _rnum, _buf, sizeof (_buf)) + + /* Extract the lower 6 bits from an op code */ +#define LOW_OP(_op) (_op & 0x3f) + + char rbuf1[32], rbuf2[32]; + Conv_inv_buf_t inv_buf; + uchar_t op; + const char *opname; + uint64_t oper1, oper2, cur_pc; + int64_t soper; + const char *loc_str; + int i; + + dbg_print(0, msg); + + /* + * In a CIE/FDE, the length field does not include it's own + * size. Hence, the value passed in is 4 less than the index + * of the actual final location. + */ + len += 4; + + /* + * There is a concept of the 'current location', which is the PC + * to which the current item applies. It starts out set to the + * FDE initial location, and can be set or incremented by + * various OP codes. cur_pc is used to track this. + * + * We want to use 'initloc' in the output the first time the location + * is referenced, and then switch to 'loc' for subsequent references. + * loc_str is used to manage that. + */ + cur_pc = state->fdeinitloc; + loc_str = MSG_ORIG(MSG_STR_INITLOC); + + while (*ndx < len) { + /* + * The first byte contains the primary op code in the top + * 2 bits, so there are 4 of them. Primary OP code + * 0 uses the lower 6 bits to specify a sub-opcode, allowing + * for 64 of them. The other 3 primary op codes use the + * lower 6 bits to hold an operand (a register #, or value). + * + * Check the primary OP code. If it's 1-3, handle it + * and move to the next loop iteration. For OP code 0, + * fall through to decode the sub-code. + */ + op = data[off + (*ndx)++]; + opname = conv_dwarf_cfa(op, 0, &inv_buf); + switch (op >> 6) { + case 0x1: /* v2: DW_CFA_advance_loc, delta */ + oper1 = state->ciecalign * LOW_OP(op); + cur_pc += oper1; + dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX, + loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc)); + loc_str = MSG_ORIG(MSG_STR_LOC); + continue; + + case 0x2: /* v2: DW_CFA_offset, reg, offset */ + soper = uleb_extract(&data[off], ndx) * + state->ciedalign; + dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX, + REGNAME(LOW_OP(op), rbuf1), EC_SXWORD(soper)); + continue; + + case 0x3: /* v2: DW_CFA_restore, reg */ + dbg_print(0, MSG_ORIG(MSG_CFA_REG), PREFIX, + REGNAME(LOW_OP(op), rbuf1)); + continue; + } + + /* + * If we're here, the high order 2 bits are 0. The low 6 bits + * specify a sub-opcode defining the operation. + */ + switch (op) { + case 0x00: /* v2: DW_CFA_nop */ + /* + * No-ops are used to fill unused space required + * for alignment. It is common for there to be + * multiple adjacent nops. It saves space to report + * them all with a single line of output. + */ + for (i = 1; + (*ndx < len) && (data[off + *ndx] == 0); + i++, (*ndx)++) + ; + dbg_print(0, MSG_ORIG(MSG_CFA_SIMPLEREP), PREFIX, i); + break; + + case 0x0a: /* v2: DW_CFA_remember_state */ + case 0x0b: /* v2: DW_CFA_restore_state */ + case 0x2d: /* GNU: DW_CFA_GNU_window_save */ + dbg_print(0, MSG_ORIG(MSG_CFA_SIMPLE), PREFIX); + break; + + case 0x01: /* v2: DW_CFA_set_loc, address */ + cur_pc = dwarf_ehe_extract(&data[off], ndx, + state->cieRflag, state->e_ident, + state->sh_addr, off + *ndx); + dbg_print(0, MSG_ORIG(MSG_CFA_CFASET), PREFIX, + EC_XWORD(cur_pc)); + break; + + case 0x02: /* v2: DW_CFA_advance_loc_1, 1-byte delta */ + case 0x03: /* v2: DW_CFA_advance_loc_2, 2-byte delta */ + case 0x04: /* v2: DW_CFA_advance_loc_4, 4-byte delta */ + /* + * Since the codes are contiguous, and the sizes are + * powers of 2, we can compute the word width from + * the code. + */ + i = 1 << (op - 0x02); + oper1 = dwarf_extract_uint(data + off, ndx, i, + state->do_swap) * state->ciecalign; + cur_pc += oper1; + dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX, + loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc)); + loc_str = MSG_ORIG(MSG_STR_LOC); + break; + + case 0x05: /* v2: DW_CFA_offset_extended,reg,off */ + oper1 = uleb_extract(&data[off], ndx); + soper = uleb_extract(&data[off], ndx) * + state->ciedalign; + dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX, + REGNAME(oper1, rbuf1), EC_SXWORD(soper)); + break; + + case 0x06: /* v2: DW_CFA_restore_extended, reg */ + case 0x0d: /* v2: DW_CFA_def_cfa_register, reg */ + case 0x08: /* v2: DW_CFA_same_value, reg */ + case 0x07: /* v2: DW_CFA_undefined, reg */ + oper1 = uleb_extract(&data[off], ndx); + dbg_print(0, MSG_ORIG(MSG_CFA_REG), PREFIX, + REGNAME(oper1, rbuf1)); + break; + + + case 0x09: /* v2: DW_CFA_register, reg, reg */ + oper1 = uleb_extract(&data[off], ndx); + oper2 = uleb_extract(&data[off], ndx); + dbg_print(0, MSG_ORIG(MSG_CFA_REG_REG), PREFIX, + REGNAME(oper1, rbuf1), REGNAME(oper2, rbuf2)); + break; + + case 0x0c: /* v2: DW_CFA_def_cfa, reg, offset */ + oper1 = uleb_extract(&data[off], ndx); + oper2 = uleb_extract(&data[off], ndx); + dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLU), PREFIX, + REGNAME(oper1, rbuf1), EC_XWORD(oper2)); + break; + + case 0x0e: /* v2: DW_CFA_def_cfa_offset, offset */ + oper1 = uleb_extract(&data[off], ndx); + dbg_print(0, MSG_ORIG(MSG_CFA_LLU), PREFIX, + EC_XWORD(oper1)); + break; + + case 0x0f: /* v3: DW_CFA_def_cfa_expression, blk */ + oper1 = uleb_extract(&data[off], ndx); + dbg_print(0, MSG_ORIG(MSG_CFA_EBLK), PREFIX, + EC_XWORD(oper1)); + /* We currently do not decode the expression block */ + *ndx += oper1; + break; + + case 0x10: /* v3: DW_CFA_expression, reg, blk */ + case 0x16: /* v3: DW_CFA_val_expression,reg,blk */ + oper1 = uleb_extract(&data[off], ndx); + oper2 = uleb_extract(&data[off], ndx); + dbg_print(0, MSG_ORIG(MSG_CFA_REG_EBLK), PREFIX, + REGNAME(oper1, rbuf1), EC_XWORD(oper2)); + /* We currently do not decode the expression block */ + *ndx += oper2; + break; + + case 0x11: /* v3: DW_CFA_offset_extended_sf, reg, off */ + oper1 = uleb_extract(&data[off], ndx); + soper = sleb_extract(&data[off], ndx) * + state->ciedalign; + dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX, + REGNAME(oper1, rbuf1), EC_SXWORD(soper)); + break; + + case 0x12: /* v3: DW_CFA_def_cfa_sf, reg, offset */ + oper1 = uleb_extract(&data[off], ndx); + soper = sleb_extract(&data[off], ndx) * + state->ciedalign; + dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX, + REGNAME(oper1, rbuf1), EC_SXWORD(soper)); + break; + + case 0x13: /* DW_CFA_def_cfa_offset_sf, offset */ + soper = sleb_extract(&data[off], ndx) * + state->ciedalign; + dbg_print(0, MSG_ORIG(MSG_CFA_LLD), PREFIX, + EC_SXWORD(soper)); + break; + + case 0x14: /* v3: DW_CFA_val_offset, reg, offset */ + oper1 = uleb_extract(&data[off], ndx); + soper = uleb_extract(&data[off], ndx) * + state->ciedalign; + dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX, + REGNAME(oper1, rbuf1), EC_SXWORD(soper)); + break; + + case 0x15: /* v3: DW_CFA_val_offset_sf, reg, offset */ + oper1 = uleb_extract(&data[off], ndx); + soper = sleb_extract(&data[off], ndx) * + state->ciedalign; + dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX, + REGNAME(oper1, rbuf1), EC_SXWORD(soper)); + break; + + case 0x1d: /* GNU: DW_CFA_MIPS_advance_loc8, delta */ + oper1 = dwarf_extract_uint(data + off, ndx, i, + state->do_swap) * state->ciecalign; + cur_pc += oper1; + dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX, + loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc)); + loc_str = MSG_ORIG(MSG_STR_LOC); + break; + + case 0x2e: /* GNU: DW_CFA_GNU_args_size, size */ + oper1 = uleb_extract(&data[off], ndx); + dbg_print(0, MSG_ORIG(MSG_CFA_LLU), PREFIX, + EC_XWORD(oper1)); + + break; + + case 0x2f: /* GNU:DW_CFA_GNU_negative_offset_extended,reg,off */ + oper1 = uleb_extract(&data[off], ndx); + soper = -uleb_extract(&data[off], ndx) * + state->ciedalign; + dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX, + REGNAME(oper1, rbuf1), EC_SXWORD(soper)); + break; + + default: + /* + * Unrecognized OP code: DWARF data is variable length, + * so we don't know how many bytes to skip in order to + * advance to the next item. We cannot decode beyond + * this point, so dump the remainder in hex. + */ + (*ndx)--; /* Back up to unrecognized opcode */ + dump_hex_bytes(data + off + *ndx, len - *ndx, + indent, 8, 1); + (*ndx) = len; + break; + } + } + +#undef PREFIX +#undef REGNAME +#undef LOW_OP +} + +void +dump_eh_frame(uchar_t *data, size_t datasize, uint64_t sh_addr, + Half e_machine, uchar_t *e_ident) +{ + Conv_dwarf_ehe_buf_t dwarf_ehe_buf; + dump_cfi_state_t cfi_state; + uint64_t off, ndx; + uint_t cieid, cielength, cieversion, cieretaddr; + int ciePflag, cieZflag, cieLflag, cieLflag_present; + uint_t cieaugndx, length, id; + char *cieaugstr; + + cfi_state.e_machine = e_machine; + cfi_state.e_ident = e_ident; + cfi_state.sh_addr = sh_addr; + cfi_state.do_swap = _elf_sys_encoding() != e_ident[EI_DATA]; + + off = 0; + while (off < datasize) { + ndx = 0; + + /* + * Extract length in native format. A zero length indicates + * that this CIE is a terminator and that processing for this + * unwind information should end. However, skip this entry and + * keep processing, just in case there is any other information + * remaining in this section. Note, ld(1) will terminate the + * processing of the .eh_frame contents for this file after a + * zero length CIE, thus any information that does follow is + * ignored by ld(1), and is therefore questionable. + */ + length = (uint_t)dwarf_extract_uint(data + off, &ndx, + 4, cfi_state.do_swap); + if (length == 0) { + dbg_print(0, MSG_ORIG(MSG_UNW_ZEROTERM)); + off += 4; + continue; + } + + /* + * extract CIE id in native format + */ + id = (uint_t)dwarf_extract_uint(data + off, &ndx, + 4, cfi_state.do_swap); + + /* + * A CIE record has an id of '0', otherwise this is a + * FDE entry and the 'id' is the CIE pointer. + */ + if (id == 0) { + uint64_t persVal, ndx_save; + uint_t axsize; + + cielength = length; + cieid = id; + ciePflag = cfi_state.cieRflag = cieZflag = 0; + cieLflag = cieLflag_present = 0; + + dbg_print(0, MSG_ORIG(MSG_UNW_CIE), + EC_XWORD(sh_addr + off)); + dbg_print(0, MSG_ORIG(MSG_UNW_CIELNGTH), + cielength, cieid); + + cieversion = data[off + ndx]; + ndx += 1; + cieaugstr = (char *)(&data[off + ndx]); + ndx += strlen(cieaugstr) + 1; + + dbg_print(0, MSG_ORIG(MSG_UNW_CIEVERS), + cieversion, cieaugstr); + + cfi_state.ciecalign = uleb_extract(&data[off], &ndx); + cfi_state.ciedalign = sleb_extract(&data[off], &ndx); + cieretaddr = data[off + ndx]; + ndx += 1; + + dbg_print(0, MSG_ORIG(MSG_UNW_CIECALGN), + EC_XWORD(cfi_state.ciecalign), + EC_XWORD(cfi_state.ciedalign), cieretaddr); + + if (cieaugstr[0]) + dbg_print(0, MSG_ORIG(MSG_UNW_CIEAXVAL)); + + for (cieaugndx = 0; cieaugstr[cieaugndx]; cieaugndx++) { + switch (cieaugstr[cieaugndx]) { + case 'z': + axsize = uleb_extract(&data[off], &ndx); + dbg_print(0, MSG_ORIG(MSG_UNW_CIEAXSIZ), + axsize); + cieZflag = 1; + /* + * The auxiliary section can contain + * unused padding bytes at the end, so + * save the current index. Along with + * axsize, we will use it to set ndx to + * the proper continuation index after + * the aux data has been processed. + */ + ndx_save = ndx; + break; + case 'P': + ciePflag = data[off + ndx]; + ndx += 1; + + persVal = dwarf_ehe_extract(&data[off], + &ndx, ciePflag, e_ident, + sh_addr, off + ndx); + dbg_print(0, + MSG_ORIG(MSG_UNW_CIEAXPERS)); + dbg_print(0, + MSG_ORIG(MSG_UNW_CIEAXPERSENC), + ciePflag, conv_dwarf_ehe(ciePflag, + &dwarf_ehe_buf)); + dbg_print(0, + MSG_ORIG(MSG_UNW_CIEAXPERSRTN), + EC_XWORD(persVal)); + break; + case 'R': + cfi_state.cieRflag = data[off + ndx]; + ndx += 1; + dbg_print(0, + MSG_ORIG(MSG_UNW_CIEAXCENC), + cfi_state.cieRflag, + conv_dwarf_ehe(cfi_state.cieRflag, + &dwarf_ehe_buf)); + break; + case 'L': + cieLflag_present = 1; + cieLflag = data[off + ndx]; + ndx += 1; + dbg_print(0, + MSG_ORIG(MSG_UNW_CIEAXLSDA), + cieLflag, conv_dwarf_ehe( + cieLflag, &dwarf_ehe_buf)); + break; + default: + dbg_print(0, + MSG_ORIG(MSG_UNW_CIEAXUNEC), + cieaugstr[cieaugndx]); + break; + } + } + + /* + * If the z flag was present, reposition ndx using the + * length given. This will safely move us past any + * unaccessed padding bytes in the auxiliary section. + */ + if (cieZflag) + ndx = ndx_save + axsize; + + /* + * Any remaining data are Call Frame Instructions + */ + if ((cielength + 4) > ndx) + dump_cfi(data, off, &ndx, cielength, &cfi_state, + MSG_ORIG(MSG_UNW_CIECFI), 3); + off += cielength + 4; + + } else { + uint_t fdelength = length; + int fdecieptr = id; + uint64_t fdeaddrrange; + + dbg_print(0, MSG_ORIG(MSG_UNW_FDE), + EC_XWORD(sh_addr + off)); + dbg_print(0, MSG_ORIG(MSG_UNW_FDELNGTH), + fdelength, fdecieptr); + + cfi_state.fdeinitloc = dwarf_ehe_extract(&data[off], + &ndx, cfi_state.cieRflag, e_ident, + sh_addr, off + ndx); + fdeaddrrange = dwarf_ehe_extract(&data[off], &ndx, + (cfi_state.cieRflag & ~DW_EH_PE_pcrel), + e_ident, sh_addr, off + ndx); + + dbg_print(0, MSG_ORIG(MSG_UNW_FDEINITLOC), + EC_XWORD(cfi_state.fdeinitloc), + EC_XWORD(fdeaddrrange), + EC_XWORD(cfi_state.fdeinitloc + fdeaddrrange - 1)); + + if (cieaugstr[0]) + dbg_print(0, MSG_ORIG(MSG_UNW_FDEAXVAL)); + if (cieZflag) { + uint64_t val; + uint64_t lndx; + + val = uleb_extract(&data[off], &ndx); + lndx = ndx; + ndx += val; + dbg_print(0, MSG_ORIG(MSG_UNW_FDEAXSIZE), + EC_XWORD(val)); + if (val && cieLflag_present) { + uint64_t lsda; + + lsda = dwarf_ehe_extract(&data[off], + &lndx, cieLflag, e_ident, + sh_addr, off + lndx); + dbg_print(0, + MSG_ORIG(MSG_UNW_FDEAXLSDA), + EC_XWORD(lsda)); + } + } + if ((fdelength + 4) > ndx) + dump_cfi(data, off, &ndx, fdelength, &cfi_state, + MSG_ORIG(MSG_UNW_FDECFI), 6); + off += fdelength + 4; + } + } +} diff --git a/usr/src/cmd/sgs/elfdump/common/elfdump.c b/usr/src/cmd/sgs/elfdump/common/elfdump.c index d7c74f7bad..7d0668c64f 100644 --- a/usr/src/cmd/sgs/elfdump/common/elfdump.c +++ b/usr/src/cmd/sgs/elfdump/common/elfdump.c @@ -185,7 +185,7 @@ string(Cache *refsec, Word ndx, Cache *strsec, const char *file, Word name) /* * Do we have a empty string table? */ - if (strs == 0) { + if (strs == NULL) { if (!strsec_err) { (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), file, strsec->c_name); @@ -411,92 +411,109 @@ sections(const char *file, Cache *cache, Word shnum, Ehdr *ehdr) } /* - * A couple of instances of unwind data are printed as tables of 8 data items - * expressed as 0x?? integers. - */ -#define UNWINDTBLSZ 10 + (8 * 5) + 1 - -static void -unwindtbl(uint64_t *ndx, uint_t len, uchar_t *data, uint64_t doff, - const char *msg, const char *pre, size_t plen) -{ - char buffer[UNWINDTBLSZ]; - uint_t boff = plen, cnt = 0; - - dbg_print(0, msg); - (void) strncpy(buffer, pre, UNWINDTBLSZ); - - while (*ndx < (len + 4)) { - if (cnt == 8) { - dbg_print(0, buffer); - boff = plen; - cnt = 0; - } - (void) snprintf(&buffer[boff], UNWINDTBLSZ - boff, - MSG_ORIG(MSG_UNW_TBLENTRY), data[doff + (*ndx)++]); - boff += 5; - cnt++; - } - if (cnt) - dbg_print(0, buffer); -} - -/* * Obtain a specified Phdr entry. */ static Phdr * -getphdr(Word phnum, Word type, const char *file, Elf *elf) +getphdr(Word phnum, Word *type_arr, Word type_cnt, const char *file, Elf *elf) { - Word cnt; + Word cnt, tcnt; Phdr *phdr; if ((phdr = elf_getphdr(elf)) == NULL) { failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); - return (0); + return (NULL); } for (cnt = 0; cnt < phnum; phdr++, cnt++) { - if (phdr->p_type == type) - return (phdr); + for (tcnt = 0; tcnt < type_cnt; tcnt++) { + if (phdr->p_type == type_arr[tcnt]) + return (phdr); + } } - return (0); + return (NULL); } static void unwind(Cache *cache, Word shnum, Word phnum, Ehdr *ehdr, const char *file, Elf *elf) { +#if defined(_ELF64) +#define MSG_UNW_BINSRTAB2 MSG_UNW_BINSRTAB2_64 +#define MSG_UNW_BINSRTABENT MSG_UNW_BINSRTABENT_64 +#else +#define MSG_UNW_BINSRTAB2 MSG_UNW_BINSRTAB2_32 +#define MSG_UNW_BINSRTABENT MSG_UNW_BINSRTABENT_32 +#endif + + static Word phdr_types[] = { PT_SUNW_UNWIND, PT_SUNW_EH_FRAME }; + + int frame_cnt = 0, hdr_cnt = 0, frame_ndx, hdr_ndx; + uint64_t save_frame_ptr, save_frame_base; Conv_dwarf_ehe_buf_t dwarf_ehe_buf; - Word cnt; - Phdr *uphdr = 0; + Word cnt; + Phdr *uphdr = NULL; /* - * For the moment - UNWIND is only relevant for a AMD64 object. + * Historical background: .eh_frame and .eh_frame_hdr sections + * come from the GNU compilers (particularly C++), and are used + * under all architectures. Their format is based on DWARF. When + * the amd64 ABI was defined, these sections were adopted wholesale + * from the existing practice. + * + * When amd64 support was added to Solaris, support for these + * sections was added, using the SHT_AMD64_UNWIND section type + * to identify them. At first, we ignored them in objects for + * non-amd64 targets, but later broadened our support to include + * other architectures in order to better support gcc-generated + * objects. + * + * We match these sections by name, rather than section type, + * because they can come in as either SHT_AMD64_UNWIND, or as + * SHT_PROGBITS, and because we need to distinquish between + * the two types (.eh_frame and .eh_frame_hdr). */ - if (ehdr->e_machine != EM_AMD64) - return; if (phnum) - uphdr = getphdr(phnum, PT_SUNW_UNWIND, file, elf); + uphdr = getphdr(phnum, phdr_types, + sizeof (phdr_types) / sizeof (*phdr_types), file, elf); for (cnt = 1; cnt < shnum; cnt++) { Cache *_cache = &cache[cnt]; Shdr *shdr = _cache->c_shdr; uchar_t *data; size_t datasize; - uint64_t off, ndx, frame_ptr, fde_cnt, tabndx; + uint64_t ndx, frame_ptr, fde_cnt, tabndx; uint_t vers, frame_ptr_enc, fde_cnt_enc, table_enc; /* - * AMD64 - this is a strmcp() just to find the gcc produced - * sections. Soon gcc should be setting the section type - and - * we'll not need this strcmp(). + * Skip sections of the wrong type. On amd64, Solaris tags + * these as SHT_AMD64_UNWIND, while gcc started out issuing + * them as SHT_PROGBITS and switched over when the amd64 ABI + * was finalized. On non-amd64, they're all SHT_PROGBITS. */ - if ((shdr->sh_type != SHT_AMD64_UNWIND) && - (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRM), - MSG_SCN_FRM_SIZE) != 0) && - (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRMHDR), - MSG_SCN_FRMHDR_SIZE) != 0)) + switch (shdr->sh_type) { + case SHT_PROGBITS: + if (ehdr->e_machine == EM_AMD64) + continue; + break; + case SHT_AMD64_UNWIND: + if (ehdr->e_machine != EM_AMD64) + continue; + break; + default: + continue; + } + + /* + * Only sections with names starting with .eh_frame or + * .eh_frame_hdr are of interest. We do a prefix comparison, + * allowing for naming conventions like .eh_frame.foo, hence + * the use of strncmp() rather than strcmp(). This means that + * we only really need to test for .eh_frame, as it's a + * prefix of .eh_frame_hdr. + */ + if (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRM), + MSG_SCN_FRM_SIZE) != 0) continue; if (!match(MATCH_F_ALL, _cache->c_name, cnt, shdr->sh_type)) @@ -510,7 +527,6 @@ unwind(Cache *cache, Word shnum, Word phnum, Ehdr *ehdr, const char *file, data = (uchar_t *)(_cache->c_data->d_buf); datasize = _cache->c_data->d_size; - off = 0; /* * Is this a .eh_frame_hdr @@ -518,6 +534,15 @@ unwind(Cache *cache, Word shnum, Word phnum, Ehdr *ehdr, const char *file, if ((uphdr && (shdr->sh_addr == uphdr->p_vaddr)) || (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRMHDR), MSG_SCN_FRMHDR_SIZE) == 0)) { + /* + * There can only be a single .eh_frame_hdr. + * Flag duplicates. + */ + if (++hdr_cnt > 1) + (void) fprintf(stderr, + MSG_INTL(MSG_ERR_MULTEHFRMHDR), file, + EC_WORD(cnt), _cache->c_name); + dbg_print(0, MSG_ORIG(MSG_UNW_FRMHDR)); ndx = 0; @@ -529,14 +554,18 @@ unwind(Cache *cache, Word shnum, Word phnum, Ehdr *ehdr, const char *file, dbg_print(0, MSG_ORIG(MSG_UNW_FRMVERS), vers); frame_ptr = dwarf_ehe_extract(data, &ndx, frame_ptr_enc, - ehdr->e_ident, shdr->sh_addr + ndx); + ehdr->e_ident, shdr->sh_addr, ndx); + if (hdr_cnt == 1) { + hdr_ndx = cnt; + save_frame_ptr = frame_ptr; + } dbg_print(0, MSG_ORIG(MSG_UNW_FRPTRENC), conv_dwarf_ehe(frame_ptr_enc, &dwarf_ehe_buf), EC_XWORD(frame_ptr)); fde_cnt = dwarf_ehe_extract(data, &ndx, fde_cnt_enc, - ehdr->e_ident, shdr->sh_addr + ndx); + ehdr->e_ident, shdr->sh_addr, ndx); dbg_print(0, MSG_ORIG(MSG_UNW_FDCNENC), conv_dwarf_ehe(fde_cnt_enc, &dwarf_ehe_buf), @@ -549,197 +578,46 @@ unwind(Cache *cache, Word shnum, Word phnum, Ehdr *ehdr, const char *file, for (tabndx = 0; tabndx < fde_cnt; tabndx++) { dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTABENT), EC_XWORD(dwarf_ehe_extract(data, &ndx, - table_enc, ehdr->e_ident, shdr->sh_addr)), + table_enc, ehdr->e_ident, shdr->sh_addr, + ndx)), EC_XWORD(dwarf_ehe_extract(data, &ndx, - table_enc, ehdr->e_ident, shdr->sh_addr))); + table_enc, ehdr->e_ident, shdr->sh_addr, + ndx))); } - continue; + } else { /* Display the .eh_frame section */ + frame_cnt++; + if (frame_cnt == 1) { + frame_ndx = cnt; + save_frame_base = shdr->sh_addr; + } else if ((frame_cnt > 1) && + (ehdr->e_type != ET_REL)) { + Conv_inv_buf_t inv_buf; + + (void) fprintf(stderr, + MSG_INTL(MSG_WARN_MULTEHFRM), file, + EC_WORD(cnt), _cache->c_name, + conv_ehdr_type(ehdr->e_type, 0, &inv_buf)); + } + dump_eh_frame(data, datasize, shdr->sh_addr, + ehdr->e_machine, ehdr->e_ident); } /* - * Walk the Eh_frame's + * If we've seen the .eh_frame_hdr and the first + * .eh_frame section, compare the header frame_ptr + * to the address of the actual frame section to ensure + * the link-editor got this right. */ - while (off < datasize) { - uint_t cieid, cielength, cieversion; - uint_t cieretaddr; - int cieRflag, cieLflag, ciePflag, cieZflag; - uint_t cieaugndx, length, id; - uint64_t ciecalign, ciedalign; - char *cieaugstr; - - ndx = 0; - /* - * Extract length in lsb format. A zero length - * indicates that this CIE is a terminator and that - * processing for this unwind information should end. - * However, skip this entry and keep processing, just - * in case there is any other information remaining in - * this section. Note, ld(1) will terminate the - * processing of the .eh_frame contents for this file - * after a zero length CIE, thus any information that - * does follow is ignored by ld(1), and is therefore - * questionable. - */ - if ((length = LSB32EXTRACT(data + off + ndx)) == 0) { - dbg_print(0, MSG_ORIG(MSG_UNW_ZEROTERM)); - off += 4; - continue; - } - ndx += 4; - - /* - * extract CIE id in lsb format - */ - id = LSB32EXTRACT(data + off + ndx); - ndx += 4; - - /* - * A CIE record has a id of '0', otherwise this is a - * FDE entry and the 'id' is the CIE pointer. - */ - if (id == 0) { - uint64_t persVal; - - cielength = length; - cieid = id; - cieLflag = ciePflag = cieRflag = cieZflag = 0; - - dbg_print(0, MSG_ORIG(MSG_UNW_CIE), - EC_XWORD(shdr->sh_addr + off)); - dbg_print(0, MSG_ORIG(MSG_UNW_CIELNGTH), - cielength, cieid); - - cieversion = data[off + ndx]; - ndx += 1; - cieaugstr = (char *)(&data[off + ndx]); - ndx += strlen(cieaugstr) + 1; - - dbg_print(0, MSG_ORIG(MSG_UNW_CIEVERS), - cieversion, cieaugstr); - - ciecalign = uleb_extract(&data[off], &ndx); - ciedalign = sleb_extract(&data[off], &ndx); - cieretaddr = data[off + ndx]; - ndx += 1; - - dbg_print(0, MSG_ORIG(MSG_UNW_CIECALGN), - EC_XWORD(ciecalign), EC_XWORD(ciedalign), - cieretaddr); - - if (cieaugstr[0]) - dbg_print(0, - MSG_ORIG(MSG_UNW_CIEAXVAL)); - - for (cieaugndx = 0; cieaugstr[cieaugndx]; - cieaugndx++) { - uint_t val; - - switch (cieaugstr[cieaugndx]) { - case 'z': - val = uleb_extract(&data[off], - &ndx); - dbg_print(0, - MSG_ORIG(MSG_UNW_CIEAXSIZ), - val); - cieZflag = 1; - break; - case 'P': - ciePflag = data[off + ndx]; - ndx += 1; - - persVal = dwarf_ehe_extract( - &data[off], &ndx, ciePflag, - ehdr->e_ident, - shdr->sh_addr + off + ndx); - dbg_print(0, - MSG_ORIG(MSG_UNW_CIEAXPERS), - ciePflag, - conv_dwarf_ehe(ciePflag, - &dwarf_ehe_buf), - EC_XWORD(persVal)); - break; - case 'R': - val = data[off + ndx]; - ndx += 1; - dbg_print(0, - MSG_ORIG(MSG_UNW_CIEAXCENC), - val, conv_dwarf_ehe(val, - &dwarf_ehe_buf)); - cieRflag = val; - break; - case 'L': - val = data[off + ndx]; - ndx += 1; - dbg_print(0, - MSG_ORIG(MSG_UNW_CIEAXLSDA), - val, conv_dwarf_ehe(val, - &dwarf_ehe_buf)); - cieLflag = val; - break; - default: - dbg_print(0, - MSG_ORIG(MSG_UNW_CIEAXUNEC), - cieaugstr[cieaugndx]); - break; - } - } - if ((cielength + 4) > ndx) - unwindtbl(&ndx, cielength, data, off, - MSG_ORIG(MSG_UNW_CIECFI), - MSG_ORIG(MSG_UNW_CIEPRE), - MSG_UNW_CIEPRE_SIZE); - off += cielength + 4; - - } else { - uint_t fdelength = length; - int fdecieptr = id; - uint64_t fdeinitloc, fdeaddrrange; - - dbg_print(0, MSG_ORIG(MSG_UNW_FDE), - EC_XWORD(shdr->sh_addr + off)); - dbg_print(0, MSG_ORIG(MSG_UNW_FDELNGTH), - fdelength, fdecieptr); - - fdeinitloc = dwarf_ehe_extract(&data[off], - &ndx, cieRflag, ehdr->e_ident, - shdr->sh_addr + off + ndx); - fdeaddrrange = dwarf_ehe_extract(&data[off], - &ndx, (cieRflag & ~DW_EH_PE_pcrel), - ehdr->e_ident, - shdr->sh_addr + off + ndx); - - dbg_print(0, MSG_ORIG(MSG_UNW_FDEINITLOC), - EC_XWORD(fdeinitloc), - EC_XWORD(fdeaddrrange)); - - if (cieaugstr[0]) - dbg_print(0, - MSG_ORIG(MSG_UNW_FDEAXVAL)); - if (cieZflag) { - uint64_t val; - val = uleb_extract(&data[off], &ndx); - dbg_print(0, - MSG_ORIG(MSG_UNW_FDEAXSIZE), - EC_XWORD(val)); - if (val & cieLflag) { - fdeinitloc = dwarf_ehe_extract( - &data[off], &ndx, cieLflag, - ehdr->e_ident, - shdr->sh_addr + off + ndx); - dbg_print(0, - MSG_ORIG(MSG_UNW_FDEAXLSDA), - EC_XWORD(val)); - } - } - if ((fdelength + 4) > ndx) - unwindtbl(&ndx, fdelength, data, off, - MSG_ORIG(MSG_UNW_FDECFI), - MSG_ORIG(MSG_UNW_FDEPRE), - MSG_UNW_FDEPRE_SIZE); - off += fdelength + 4; - } - } + if ((hdr_cnt > 0) && (frame_cnt > 0) && + (save_frame_ptr != save_frame_base)) + (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADEHFRMPTR), + file, EC_WORD(hdr_ndx), cache[hdr_ndx].c_name, + EC_XWORD(save_frame_ptr), EC_WORD(frame_ndx), + cache[frame_ndx].c_name, EC_XWORD(save_frame_base)); } + +#undef MSG_UNW_BINSRTAB2 +#undef MSG_UNW_BINSRTABENT } /* @@ -864,8 +742,11 @@ cap(const char *file, Cache *cache, Word shnum, Word phnum, Ehdr *ehdr, static void interp(const char *file, Cache *cache, Word shnum, Word phnum, Elf *elf) { + static Word phdr_types[] = { PT_INTERP }; + + Word cnt; - Shdr *ishdr = 0; + Shdr *ishdr = NULL; Cache *icache; Off iphdr_off = 0; Xword iphdr_fsz; @@ -876,7 +757,9 @@ interp(const char *file, Cache *cache, Word shnum, Word phnum, Elf *elf) if (phnum) { Phdr *phdr; - if ((phdr = getphdr(phnum, PT_INTERP, file, elf)) != 0) { + phdr = getphdr(phnum, phdr_types, + sizeof (phdr_types) / sizeof (*phdr_types), file, elf); + if (phdr != NULL) { iphdr_off = phdr->p_offset; iphdr_fsz = phdr->p_filesz; } @@ -941,7 +824,7 @@ syminfo(Cache *cache, Word shnum, const char *file) Sym *syms; Dyn *dyns; Word infonum, cnt, ndx, symnum; - Cache *infocache = 0, *symsec, *strsec; + Cache *infocache = NULL, *symsec, *strsec; for (cnt = 1; cnt < shnum; cnt++) { if (cache[cnt].c_shdr->sh_type == SHT_SUNW_syminfo) { @@ -949,7 +832,7 @@ syminfo(Cache *cache, Word shnum, const char *file) break; } } - if (infocache == 0) + if (infocache == NULL) return; infoshdr = infocache->c_shdr; @@ -976,7 +859,7 @@ syminfo(Cache *cache, Word shnum, const char *file) return; dyns = cache[infoshdr->sh_info].c_data->d_buf; - if (dyns == 0) { + if (dyns == NULL) { (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), file, cache[infoshdr->sh_info].c_name); return; @@ -1000,7 +883,7 @@ syminfo(Cache *cache, Word shnum, const char *file) for (ndx = 1, info++; ndx < infonum; ndx++, info++) { Sym *sym; - const char *needed = 0, *name; + const char *needed = NULL, *name; if ((info->si_flags == 0) && (info->si_boundto == 0)) continue; @@ -1510,7 +1393,7 @@ output_symbol(SYMTBL_STATE *state, Word symndx, Word info, Word disp_symndx, * Symbol types for which we check that the specified * address/size land inside the target section. */ - static const int addr_symtype[STT_NUM] = { + static const int addr_symtype[] = { 0, /* STT_NOTYPE */ 1, /* STT_OBJECT */ 1, /* STT_FUNC */ @@ -1518,8 +1401,17 @@ output_symbol(SYMTBL_STATE *state, Word symndx, Word info, Word disp_symndx, 0, /* STT_FILE */ 1, /* STT_COMMON */ 0, /* STT_TLS */ + 0, /* STT_IFUNC */ + 0, /* 8 */ + 0, /* 9 */ + 0, /* 10 */ + 0, /* 11 */ + 0, /* 12 */ + 0, /* STT_SPARC_REGISTER */ + 0, /* 14 */ + 0, /* 15 */ }; -#if STT_NUM != (STT_TLS + 1) +#if STT_NUM != (STT_IFUNC + 1) #error "STT_NUM has grown. Update addr_symtype[]" #endif @@ -1551,7 +1443,7 @@ output_symbol(SYMTBL_STATE *state, Word symndx, Word info, Word disp_symndx, &state->cache[state->seccache->c_shdr->sh_link], state->file, sym->st_name); - tshdr = 0; + tshdr = NULL; sec = NULL; if (state->ehdr->e_type == ET_CORE) { @@ -2692,7 +2584,7 @@ static void move(Cache *cache, Word shnum, const char *file, uint_t flags) { Word cnt; - const char *fmt = 0; + const char *fmt = NULL; for (cnt = 1; cnt < shnum; cnt++) { Word movenum, symnum, ndx; @@ -2735,7 +2627,7 @@ move(Cache *cache, Word shnum, const char *file, uint_t flags) dbg_print(0, MSG_INTL(MSG_ELF_SCN_MOVE), _cache->c_name); dbg_print(0, MSG_INTL(MSG_MOVE_TITLE)); - if (fmt == 0) + if (fmt == NULL) fmt = MSG_INTL(MSG_MOVE_ENTRY); for (ndx = 0; ndx < movenum; move++, ndx++) { @@ -3589,7 +3481,7 @@ shdr_cache(const char *file, Elf *elf, Ehdr *ehdr, size_t shstrndx, Elf_Data *data; size_t ndx; Shdr *nameshdr; - char *names = 0; + char *names = NULL; Cache *cache, *_cache; size_t *shdr_ndx_arr, shdr_ndx_arr_cnt; @@ -3620,7 +3512,7 @@ shdr_cache(const char *file, Elf *elf, Ehdr *ehdr, size_t shstrndx, (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), EC_WORD(elf_ndxscn(scn))); - } else if ((names = data->d_buf) == 0) + } else if ((names = data->d_buf) == NULL) (void) fprintf(stderr, MSG_INTL(MSG_ERR_SHSTRNULL), file); /* @@ -3743,6 +3635,7 @@ shdr_cache(const char *file, Elf *elf, Ehdr *ehdr, size_t shstrndx, MSG_ORIG(MSG_FMT_SECSYM), EC_WORD(secsz), secname, symname); } + continue; } @@ -3938,7 +3831,7 @@ regular(const char *file, int fd, Elf *elf, uint_t flags, return (ret); } } else - shdr = 0; + shdr = NULL; /* * Print the elf header. @@ -4083,10 +3976,15 @@ regular(const char *file, int fd, Elf *elf, uint_t flags, case SHT_PROGBITS: /* * Heuristic time: It is usually bad form - * to assume that specific section names - * have a given meaning. However, the - * ELF ABI does specify a few such names. Try - * to match them: + * to assume the meaning/format of a PROGBITS + * section based on its name. However, there + * are exceptions: The ELF ABI specifies + * .interp and .got sections by name. Existing + * practice has similarly pinned down the + * meaning of unwind sections (.eh_frame and + * .eh_frame_hdr). + * + * Check for these special names. */ if (strcmp(_cache->c_name, MSG_ORIG(MSG_ELF_INTERP)) == 0) @@ -4094,6 +3992,10 @@ regular(const char *file, int fd, Elf *elf, uint_t flags, else if (strcmp(_cache->c_name, MSG_ORIG(MSG_ELF_GOT)) == 0) flags |= FLG_SHOW_GOT; + else if (strncmp(_cache->c_name, + MSG_ORIG(MSG_SCN_FRM), + MSG_SCN_FRM_SIZE) == 0) + flags |= FLG_SHOW_UNWIND; break; case SHT_SYMTAB: diff --git a/usr/src/cmd/sgs/elfdump/common/elfdump.msg b/usr/src/cmd/sgs/elfdump/common/elfdump.msg index f3c60c27cb..1f7d0ebc99 100644 --- a/usr/src/cmd/sgs/elfdump/common/elfdump.msg +++ b/usr/src/cmd/sgs/elfdump/common/elfdump.msg @@ -149,6 +149,10 @@ @ MSG_ERR_DYNSYMVAL "%s: %s: symbol value does not match \ DT_%s entry: %s: value: %#llx\n" @ MSG_ERR_MALSTR "%s: %s: malformed string table, initial or final byte\n" +@ MSG_ERR_MULTEHFRMHDR "%s: [%d: %s] multiple .eh_frame_hdr sections seen \ + (1 expected)\n" +@ MSG_ERR_BADEHFRMPTR "%s: section[%d: %s] FramePtr (%#llx) does not match \ + shdr[%d: %s].sh_addr (%#llx)\n" @ MSG_WARN_INVINTERP1 "%s: PT_INTERP header has no associated section\n" @@ -161,6 +165,8 @@ header have conflicting size or offsets\n" @ MSG_WARN_INADDR32SF1 "%s: capabilities section %s: software capability \ ADDR32: is ineffective within a 32-bit object\n" +@ MSG_WARN_MULTEHFRM "%s: section[%d: %s]: %s object has multiple \ + .eh_frame sections\n" # Elf Output Messages @@ -292,6 +298,8 @@ @ MSG_STR_8SP " " @ MSG_STR_EMPTY "" @ MSG_STR_CORE "CORE" +@ MSG_STR_LOC "loc" +@ MSG_STR_INITLOC "initloc" @ MSG_FMT_INDENT " %s" @ MSG_FMT_INDEX " [%lld]" @@ -319,37 +327,60 @@ @ MSG_UNW_FRMHDR "Frame Header:" @ MSG_UNW_FRMVERS " Version: %d" -@ MSG_UNW_FRPTRENC " FramePtrEnc: %-20s FramePtr: 0x%llx" +@ MSG_UNW_FRPTRENC " FramePtrEnc: %-20s FramePtr: %#llx" @ MSG_UNW_FDCNENC " FdeCntEnc: %-20s FdeCnt: %lld" @ MSG_UNW_TABENC " TableEnc: %-20s" @ MSG_UNW_BINSRTAB1 " Binary Search Table:" -@ MSG_UNW_BINSRTAB2 " InitialLoc FdeLoc" -@ MSG_UNW_BINSRTABENT " 0x%016llx 0x%016llx" +@ MSG_UNW_BINSRTAB2_32 " InitialLoc FdeLoc" +@ MSG_UNW_BINSRTAB2_64 " InitialLoc FdeLoc" +@ MSG_UNW_BINSRTABENT_32 " 0x%08llx 0x%08llx" +@ MSG_UNW_BINSRTABENT_64 " 0x%016llx 0x%016llx" @ MSG_UNW_ZEROTERM "ZERO terminator: [0x00000000]" -@ MSG_UNW_CIE "CIE: [0x%08llx]" +@ MSG_UNW_CIE "CIE: [%#llx]" @ MSG_UNW_CIELNGTH " length: 0x%02x cieid: %d" -@ MSG_UNW_CIEVERS " version: %d augstring: `%s'" -@ MSG_UNW_CIECALGN " codealign: 0x%llx dataalign: %lld \ +@ MSG_UNW_CIEVERS " version: %d augmentation: `%s'" +@ MSG_UNW_CIECALGN " codealign: %#llx dataalign: %lld \ retaddr: %d" -@ MSG_UNW_CIEAXVAL " Auxiliary vals:" +@ MSG_UNW_CIEAXVAL " Augmentation Data:" @ MSG_UNW_CIEAXSIZ " size: %d" -@ MSG_UNW_CIEAXPERS " pers: 0x%02x %s 0x%08llx" -@ MSG_UNW_CIEAXCENC " cenc: 0x%02x %s" -@ MSG_UNW_CIEAXLSDA " lsda: 0x%02x %s" +@ MSG_UNW_CIEAXPERS " personality:" +@ MSG_UNW_CIEAXPERSENC " encoding: 0x%02x %s" +@ MSG_UNW_CIEAXPERSRTN " routine: %#08llx" +@ MSG_UNW_CIEAXCENC " code pointer encoding: 0x%02x %s" +@ MSG_UNW_CIEAXLSDA " lsda encoding: 0x%02x %s" @ MSG_UNW_CIEAXUNEC " Unexpected aug val: %c" @ MSG_UNW_CIECFI " CallFrameInstructions:" -@ MSG_UNW_CIEPRE " " -@ MSG_UNW_FDE " FDE: [0x%08llx]" -@ MSG_UNW_FDELNGTH " length: 0x%02x cieptr: 0x%02x" -@ MSG_UNW_FDEINITLOC " initloc: 0x%08llx addrrange: 0x%04llx" -@ MSG_UNW_FDEAXVAL " Auxiliary vals:" -@ MSG_UNW_FDEAXSIZE " size: 0x%llx" -@ MSG_UNW_FDEAXLSDA " lsda: 0x%llx" -@ MSG_UNW_FDECFI " CallFrameInstructions:" -@ MSG_UNW_FDEPRE " " +@ MSG_UNW_FDE " FDE: [%#llx]" +@ MSG_UNW_FDELNGTH " length: %#x cieptr: %#x" +@ MSG_UNW_FDEINITLOC " initloc: %#llx addrrange: %#llx endloc: %#llx" +@ MSG_UNW_FDEAXVAL " Augmentation Data:" +@ MSG_UNW_FDEAXSIZE " size: %#llx" +@ MSG_UNW_FDEAXLSDA " lsda: %#llx" +@ MSG_UNW_FDECFI " CallFrameInstructions:" + +# Unwind section Call Frame Instructions. These all start with a leading +# "%*s%s", used to insert leading whitespace and the opcode name. + +@ MSG_CFA_ADV_LOC "%*s%s: %s + %llu => %#llx" +@ MSG_CFA_CFAOFF "%*s%s: %s, cfa%+lld" +@ MSG_CFA_CFASET "%*s%s: cfa=%#llx" +@ MSG_CFA_LLD "%*s%s: %lld" +@ MSG_CFA_LLU "%*s%s: %llu" +@ MSG_CFA_REG "%*s%s: %s" +@ MSG_CFA_REG_OFFLLD "%*s%s: %s, offset=%lld" +@ MSG_CFA_REG_OFFLLU "%*s%s: %s, offset=%llu" +@ MSG_CFA_REG_REG "%*s%s: %s, %s" +@ MSG_CFA_SIMPLE "%*s%s" +@ MSG_CFA_SIMPLEREP "%*s%s [%d]" +@ MSG_CFA_EBLK "%*s%s: expr(%llu bytes)" +@ MSG_CFA_REG_EBLK "%*s%s: %s, expr(%llu bytes)" + +# Architecture specific register name formats + +@ MSG_REG_FMT_BASIC "r%d" +@ MSG_REG_FMT_NAME "r%d (%s)" -@ MSG_UNW_TBLENTRY "0x%02x " # Note messages @@ -653,6 +684,8 @@ @ MSG_PT_TLS_ALT1 "tls" @ MSG_PT_SUNW_UNWIND "PT_SUNW_UNWIND" # 0x6464e550 @ MSG_PT_SUNW_UNWIND_ALT1 "sunw_unwind" +@ MSG_PT_SUNW_EH_FRAME "PT_SUNW_EH_FRAME" # 0x6474e550 +@ MSG_PT_SUNW_EH_FRAME_ALT1 "sunw_eh_frame" @ MSG_PT_SUNWBSS "PT_SUNWBSS" # 0x6ffffffa @ MSG_PT_SUNWBSS_ALT1 "sunwbss" @ MSG_PT_SUNWSTACK "PT_SUNWSTACK" # 0x6ffffffb diff --git a/usr/src/cmd/sgs/elfdump/common/fake_shdr.c b/usr/src/cmd/sgs/elfdump/common/fake_shdr.c index 64991a353b..29f7bc1c99 100644 --- a/usr/src/cmd/sgs/elfdump/common/fake_shdr.c +++ b/usr/src/cmd/sgs/elfdump/common/fake_shdr.c @@ -20,10 +20,9 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" /* * Generate a cache of section header information for an ELF @@ -1173,6 +1172,7 @@ fake_shdr_cache(const char *file, int fd, Elf *elf, Ehdr *ehdr, break; case PT_SUNW_UNWIND: + case PT_SUNW_EH_FRAME: sec.unwind.type = SINFO_T_UNWIND; sinfo = &sec.unwind; break; diff --git a/usr/src/cmd/sgs/elfdump/common/main.c b/usr/src/cmd/sgs/elfdump/common/main.c index f7dfc4c5cd..e58ddea7c2 100644 --- a/usr/src/cmd/sgs/elfdump/common/main.c +++ b/usr/src/cmd/sgs/elfdump/common/main.c @@ -20,10 +20,9 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" /* * Dump an elf file. @@ -250,6 +249,9 @@ static atoui_sym_t sym_pt[] = { { MSG_ORIG(MSG_PT_SUNW_UNWIND), PT_SUNW_UNWIND }, { MSG_ORIG(MSG_PT_SUNW_UNWIND_ALT1), PT_SUNW_UNWIND }, + { MSG_ORIG(MSG_PT_SUNW_EH_FRAME), PT_SUNW_EH_FRAME }, + { MSG_ORIG(MSG_PT_SUNW_EH_FRAME_ALT1), PT_SUNW_EH_FRAME }, + { MSG_ORIG(MSG_PT_SUNWBSS), PT_SUNWBSS }, { MSG_ORIG(MSG_PT_SUNWBSS_ALT1), PT_SUNWBSS }, @@ -348,9 +350,10 @@ detail_usage() * shows (bytes_per_col * col_per_row) bytes of data. */ void -dump_hex_bytes(const char *data, size_t n, int indent, +dump_hex_bytes(const void *data, size_t n, int indent, int bytes_per_col, int col_per_row) { + const uchar_t *ldata = data; int bytes_per_row = bytes_per_col * col_per_row; int ndx, byte, word; char string[128], *str = string; @@ -372,12 +375,12 @@ dump_hex_bytes(const char *data, size_t n, int indent, index_width = strlen(index); index_width = S_ROUND(index_width, 8); - for (ndx = byte = word = 0; n > 0; n--, data++) { + for (ndx = byte = word = 0; n > 0; n--, ldata++) { while (sp_prefix-- > 0) *str++ = ' '; (void) snprintf(str, sizeof (string), - MSG_ORIG(MSG_HEXDUMP_TOK), (int)*data); + MSG_ORIG(MSG_HEXDUMP_TOK), (int)*ldata); str += 2; sp_prefix = 1; @@ -741,9 +744,9 @@ archive(const char *file, int fd, Elf *elf, uint_t flags, { Elf_Cmd cmd = ELF_C_READ; Elf_Arhdr *arhdr; - Elf *_elf = 0; + Elf *_elf = NULL; size_t ptr; - Elf_Arsym *arsym = 0; + Elf_Arsym *arsym = NULL; /* * Determine if the archive symbol table itself is required. @@ -795,15 +798,15 @@ archive(const char *file, int fd, Elf *elf, uint_t flags, if (elf_rand(elf, arsym->as_off) != arsym->as_off) { failure(file, MSG_ORIG(MSG_ELF_RAND)); - arhdr = 0; + arhdr = NULL; } else if ((_elf = elf_begin(fd, ELF_C_READ, elf)) == 0) { failure(file, MSG_ORIG(MSG_ELF_BEGIN)); - arhdr = 0; + arhdr = NULL; } else if ((arhdr = elf_getarhdr(_elf)) == 0) { failure(file, MSG_ORIG(MSG_ELF_GETARHDR)); - arhdr = 0; + arhdr = NULL; } _offset = arsym->as_off; diff --git a/usr/src/cmd/sgs/elfedit/common/elfconst.c b/usr/src/cmd/sgs/elfedit/common/elfconst.c index 90cf71c4de..bf2edb792d 100644 --- a/usr/src/cmd/sgs/elfedit/common/elfconst.c +++ b/usr/src/cmd/sgs/elfedit/common/elfconst.c @@ -20,10 +20,9 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" #include <stdlib.h> #include <stdio.h> @@ -1133,6 +1132,9 @@ static elfedit_atoui_sym_t sym_pt[] = { { MSG_ORIG(MSG_PT_SUNW_UNWIND), PT_SUNW_UNWIND }, { MSG_ORIG(MSG_PT_SUNW_UNWIND_ALT1), PT_SUNW_UNWIND }, + { MSG_ORIG(MSG_PT_SUNW_EH_FRAME), PT_SUNW_EH_FRAME }, + { MSG_ORIG(MSG_PT_SUNW_EH_FRAME_ALT1), PT_SUNW_EH_FRAME }, + { MSG_ORIG(MSG_PT_SUNWBSS), PT_SUNWBSS }, { MSG_ORIG(MSG_PT_SUNWBSS_ALT1), PT_SUNWBSS }, diff --git a/usr/src/cmd/sgs/elfedit/common/elfedit.msg b/usr/src/cmd/sgs/elfedit/common/elfedit.msg index 4d9c66f203..8833187662 100644 --- a/usr/src/cmd/sgs/elfedit/common/elfedit.msg +++ b/usr/src/cmd/sgs/elfedit/common/elfedit.msg @@ -20,11 +20,9 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" -# @ _START_ @@ -1246,6 +1244,8 @@ @ MSG_PT_TLS_ALT1 "tls" @ MSG_PT_SUNW_UNWIND "PT_SUNW_UNWIND" # 0x6464e550 @ MSG_PT_SUNW_UNWIND_ALT1 "sunw_unwind" +@ MSG_PT_SUNW_EH_FRAME "PT_SUNW_EH_FRAME" # 0x6474e550 +@ MSG_PT_SUNW_EH_FRAME_ALT1 "sunw_eh_frame" @ MSG_PT_SUNWBSS "PT_SUNWBSS" # 0x6ffffffa @ MSG_PT_SUNWBSS_ALT1 "sunwbss" @ MSG_PT_SUNWSTACK "PT_SUNWSTACK" # 0x6ffffffb diff --git a/usr/src/cmd/sgs/include/conv.h b/usr/src/cmd/sgs/include/conv.h index d9fccb6a62..1facea96d1 100644 --- a/usr/src/cmd/sgs/include/conv.h +++ b/usr/src/cmd/sgs/include/conv.h @@ -23,7 +23,7 @@ * Copyright (c) 1988 AT&T * All Rights Reserved * - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -860,7 +860,11 @@ extern const char *conv_demangle_name(const char *); extern const char *conv_dl_flag(int, Conv_fmt_flags_t, Conv_dl_flag_buf_t *); extern const char *conv_dl_mode(int, int, Conv_dl_mode_buf_t *); +extern const char *conv_dwarf_cfa(uchar_t, Conv_fmt_flags_t, + Conv_inv_buf_t *); extern const char *conv_dwarf_ehe(uint_t, Conv_dwarf_ehe_buf_t *); +extern const char *conv_dwarf_regname(Half, Word, Conv_fmt_flags_t, + int *, Conv_inv_buf_t *); extern const char *conv_elfdata_type(Elf_Type, Conv_inv_buf_t *); extern const char *conv_grphdl_flags(uint_t, Conv_grphdl_flags_buf_t *); extern const char *conv_grpdesc_flags(uint_t, Conv_grpdesc_flags_buf_t *); diff --git a/usr/src/cmd/sgs/include/dwarf.h b/usr/src/cmd/sgs/include/dwarf.h index 980d059934..31c295d17c 100644 --- a/usr/src/cmd/sgs/include/dwarf.h +++ b/usr/src/cmd/sgs/include/dwarf.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -24,15 +23,13 @@ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _DWARF_H #define _DWARF_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> @@ -254,20 +251,7 @@ typedef enum _LANG { extern uint64_t uleb_extract(unsigned char *, uint64_t *); extern int64_t sleb_extract(unsigned char *, uint64_t *); extern uint64_t dwarf_ehe_extract(unsigned char *, uint64_t *, - uint_t, unsigned char *, uint64_t); - -/* - * LSB32EXTRACT() - * - * Extract a LSB encoded int which may or may not be - * aligned on a 4 byte boundary. This macro will work - * on either a MSB or LSB based system. - */ -#define LSB32EXTRACT(lsbptr) ((unsigned int)(\ - ((unsigned const char *)(lsbptr))[0] + \ - (((unsigned const char *)(lsbptr))[1] << 8) + \ - (((unsigned const char *)(lsbptr))[2] << 16) + \ - (((unsigned const char *)(lsbptr))[3] << 24))) + uint_t, unsigned char *, uint64_t, uint64_t); #ifdef __cplusplus } diff --git a/usr/src/cmd/sgs/include/i386/machdep_x86.h b/usr/src/cmd/sgs/include/i386/machdep_x86.h index eee31216c4..9904a8d7c6 100644 --- a/usr/src/cmd/sgs/include/i386/machdep_x86.h +++ b/usr/src/cmd/sgs/include/i386/machdep_x86.h @@ -267,24 +267,25 @@ extern "C" { #define M_ID_INTERP 0x03 /* SHF_ALLOC */ #define M_ID_CAP 0x04 -#define M_ID_UNWINDHDR 0x05 -#define M_ID_UNWIND 0x06 -#define M_ID_SYMINFO 0x07 -#define M_ID_HASH 0x08 -#define M_ID_LDYNSYM 0x09 /* always right before DYNSYM */ -#define M_ID_DYNSYM 0x0a -#define M_ID_DYNSTR 0x0b -#define M_ID_VERSION 0x0c -#define M_ID_DYNSORT 0x0d -#define M_ID_REL 0x0e -#define M_ID_PLT 0x0f /* SHF_ALLOC + SHF_EXECISNTR */ -#define M_ID_TEXT 0x10 +#define M_ID_UNWINDHDR 0x06 +#define M_ID_UNWIND 0x07 +#define M_ID_SYMINFO 0x08 +#define M_ID_HASH 0x09 +#define M_ID_LDYNSYM 0x0a /* always right before DYNSYM */ +#define M_ID_DYNSYM 0x0b +#define M_ID_DYNSTR 0x0c +#define M_ID_VERSION 0x0d +#define M_ID_DYNSORT 0x0e +#define M_ID_REL 0x0f +#define M_ID_PLT 0x10 /* SHF_ALLOC + SHF_EXECISNTR */ +#define M_ID_TEXT 0x11 #define M_ID_DATA 0x20 -/* M_ID_USER 0x02 dual entry - listed above */ +/* M_ID_USER 0x01 dual entry - listed above */ #define M_ID_GOT 0x03 /* SHF_ALLOC + SHF_WRITE */ #define M_ID_DYNAMIC 0x05 #define M_ID_ARRAY 0x06 +/* M_ID_UNWIND 0x07 dual entry - listed above */ #define M_ID_UNKNOWN 0xfb /* just before TLS */ diff --git a/usr/src/cmd/sgs/include/libld.h b/usr/src/cmd/sgs/include/libld.h index 2f7980e4ab..2403c1abdb 100644 --- a/usr/src/cmd/sgs/include/libld.h +++ b/usr/src/cmd/sgs/include/libld.h @@ -201,10 +201,8 @@ struct ofl_desc { List ofl_rtldinfo; /* list of rtldinfo syms */ List ofl_osgroups; /* list of output GROUP sections */ List ofl_ostlsseg; /* pointer to sections in TLS segment */ -#if defined(_ELF64) /* for amd64 target only */ - List ofl_unwind; /* list of unwind output sections */ + APlist *ofl_unwind; /* list of unwind output sections */ Os_desc *ofl_unwindhdr; /* Unwind hdr */ -#endif avl_tree_t ofl_symavl; /* pointer to head of Syms AVL tree */ Sym_desc **ofl_regsyms; /* array of potential register */ Word ofl_regsymsno; /* symbols and array count */ @@ -607,6 +605,7 @@ struct is_desc { /* input section descriptor */ #define FLG_IS_GROUPS 0x0200 /* section has groups to process */ #define FLG_IS_PLACE 0x0400 /* section requires to be placed */ #define FLG_IS_COMDAT 0x0800 /* section is COMDAT */ +#define FLG_IS_EHFRAME 0x1000 /* section is .eh_frame */ /* * Map file and output file processing structures diff --git a/usr/src/cmd/sgs/include/sparc/machdep_sparc.h b/usr/src/cmd/sgs/include/sparc/machdep_sparc.h index 2fc05ca4f5..22c8f512c6 100644 --- a/usr/src/cmd/sgs/include/sparc/machdep_sparc.h +++ b/usr/src/cmd/sgs/include/sparc/machdep_sparc.h @@ -271,16 +271,19 @@ extern "C" { #define M_ID_INTERP 0x02 /* SHF_ALLOC */ #define M_ID_CAP 0x03 -#define M_ID_SYMINFO 0x04 -#define M_ID_HASH 0x05 -#define M_ID_LDYNSYM 0x06 /* always right before DYNSYM */ -#define M_ID_DYNSYM 0x07 -#define M_ID_DYNSTR 0x08 -#define M_ID_VERSION 0x09 -#define M_ID_DYNSORT 0x0a -#define M_ID_REL 0x0b -#define M_ID_TEXT 0x0c /* SHF_ALLOC + SHF_EXECINSTR */ -#define M_ID_DATA 0x0d +#define M_ID_UNWINDHDR 0x06 +#define M_ID_UNWIND 0x07 + +#define M_ID_SYMINFO 0x08 +#define M_ID_HASH 0x09 +#define M_ID_LDYNSYM 0x0a /* always right before DYNSYM */ +#define M_ID_DYNSYM 0x0b +#define M_ID_DYNSTR 0x0c +#define M_ID_VERSION 0x0d +#define M_ID_DYNSORT 0x0e +#define M_ID_REL 0x0f +#define M_ID_TEXT 0x10 /* SHF_ALLOC + SHF_EXECINSTR */ +#define M_ID_DATA 0x20 /* M_ID_USER 0x01 dual entry - listed above */ #define M_ID_GOTDATA 0x02 /* SHF_ALLOC + SHF_WRITE */ @@ -288,6 +291,7 @@ extern "C" { #define M_ID_PLT 0x04 #define M_ID_DYNAMIC 0x05 #define M_ID_ARRAY 0x06 +/* M_ID_UNWIND 0x07 dual entry - listed above */ #define M_ID_UNKNOWN 0xfc /* just before TLS */ diff --git a/usr/src/cmd/sgs/libconv/Makefile.com b/usr/src/cmd/sgs/libconv/Makefile.com index e2c64589d2..bf4c15418d 100644 --- a/usr/src/cmd/sgs/libconv/Makefile.com +++ b/usr/src/cmd/sgs/libconv/Makefile.com @@ -20,11 +20,9 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" -# LIBRARY = libconv.a @@ -48,9 +46,9 @@ COMOBJS= arch.o c_literal.o \ config.o corenote.o \ data.o deftag.o \ demangle.o dl.o \ - dwarf_ehe.o group.o \ - lddstub.o segments.o \ - version.o + dwarf.o dwarf_ehe.o \ + group.o lddstub.o \ + segments.o version.o COMOBJS_NOMSG = tokens.o diff --git a/usr/src/cmd/sgs/libconv/common/dwarf.c b/usr/src/cmd/sgs/libconv/common/dwarf.c new file mode 100644 index 0000000000..c32eb9e322 --- /dev/null +++ b/usr/src/cmd/sgs/libconv/common/dwarf.c @@ -0,0 +1,222 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <strings.h> +#include <dwarf.h> +#include "_conv.h" +#include <dwarf_msg.h> + +/* + * This code is primarily of interest to elfdump. Separating it from dwarf_ehe + * allows other tools to use dwarf_ehe without also pulling this in. + */ + +/* Instantiate a local copy of conv_map2str() from _conv.h */ +DEFINE_conv_map2str + + +/* + * Translate DW_CFA_ codes, used to identify Call Frame Instructions. + */ +const char * +conv_dwarf_cfa(uchar_t op, Conv_fmt_flags_t fmt_flags, Conv_inv_buf_t *inv_buf) +{ + static const Msg cfa[] = { + MSG_DW_CFA_NOP, MSG_DW_CFA_SET_LOC, + MSG_DW_CFA_ADVANCE_LOC_1, MSG_DW_CFA_ADVANCE_LOC_2, + MSG_DW_CFA_ADVANCE_LOC_4, MSG_DW_CFA_OFFSET_EXTENDED, + MSG_DW_CFA_RESTORE_EXTENDED, MSG_DW_CFA_UNDEFINED, + MSG_DW_CFA_SAME_VALUE, MSG_DW_CFA_REGISTER, + MSG_DW_CFA_REMEMBER_STATE, MSG_DW_CFA_RESTORE_STATE, + MSG_DW_CFA_DEF_CFA, MSG_DW_CFA_DEF_CFA_REGISTER, + MSG_DW_CFA_DEF_CFA_OFFSET, MSG_DW_CFA_DEF_CFA_EXPRESSION, + MSG_DW_CFA_EXPRESSION, MSG_DW_CFA_OFFSET_EXTENDED_SF, + MSG_DW_CFA_DEF_CFA_SF, MSG_DW_CFA_DEF_CFA_OFFSET_SF, + MSG_DW_CFA_VAL_OFFSET, MSG_DW_CFA_VAL_OFFSET_SF, + MSG_DW_CFA_VAL_EXPRESSION + }; + static const Msg gnu[] = { + MSG_DW_CFA_GNU_WINDOW_SAVE, MSG_DW_CFA_GNU_ARGS_SIZE, + MSG_DW_CFA_GNU_NEGATIVE_OFF_X + }; + + /* + * DWARF CFA opcodes are bytes. The top 2 bits are a primary + * opcode, and if zero, the lower 6 bits specify a sub-opcode + */ + switch (op >> 6) { + case 0x1: + return (MSG_ORIG(MSG_DW_CFA_ADVANCE_LOC)); + case 0x2: + return (MSG_ORIG(MSG_DW_CFA_OFFSET)); + case 0x3: + return (MSG_ORIG(MSG_DW_CFA_RESTORE)); + } + + if (op == 0x1d) + return (MSG_ORIG(MSG_DW_CFA_MIPS_ADV_LOC8)); + + if ((op >= 0x2d) && (op <= 0x2f)) + return (conv_map2str(inv_buf, (op - 0x2d), + fmt_flags, ARRAY_NELTS(gnu), gnu)); + + return (conv_map2str(inv_buf, op, fmt_flags, ARRAY_NELTS(cfa), cfa)); +} + +/* + * Translate DWARF register numbers to hardware specific names + * + * If good_name is non-NULL, conv_dwarf_regname() will set the variable to + * True(1) if the returned string is considered to be a good name to + * display, and False(0) otherwise. To be considered "good": + * + * - The name must be a well known mnemonic for a register + * from the machine type in question. + * + * - The name must be different than the DWARF name for + * the same register. + * + * The returned string is usable, regardless of the value returned in + * *good_name. + */ +const char * +conv_dwarf_regname(Half mach, Word regno, Conv_fmt_flags_t fmt_flags, + int *good_name, Conv_inv_buf_t *inv_buf) +{ + static const Msg reg_amd64[67] = { + MSG_REG_RAX, MSG_REG_RDX, + MSG_REG_RCX, MSG_REG_RBX, + MSG_REG_RSI, MSG_REG_RDI, + MSG_REG_RBP, MSG_REG_RSP, + MSG_REG_R8, MSG_REG_R9, + MSG_REG_R10, MSG_REG_R11, + MSG_REG_R12, MSG_REG_R13, + MSG_REG_R14, MSG_REG_R15, + MSG_REG_RA, MSG_REG_PERXMM0, + MSG_REG_PERXMM1, MSG_REG_PERXMM2, + MSG_REG_PERXMM3, MSG_REG_PERXMM4, + MSG_REG_PERXMM5, MSG_REG_PERXMM6, + MSG_REG_PERXMM7, MSG_REG_PERXMM8, + MSG_REG_PERXMM9, MSG_REG_PERXMM10, + MSG_REG_PERXMM11, MSG_REG_PERXMM12, + MSG_REG_PERXMM13, MSG_REG_PERXMM14, + MSG_REG_PERXMM15, MSG_REG_PERST0, + MSG_REG_PERST1, MSG_REG_PERST2, + MSG_REG_PERST3, MSG_REG_PERST4, + MSG_REG_PERST5, MSG_REG_PERST6, + MSG_REG_PERST7, MSG_REG_PERMM0, + MSG_REG_PERMM1, MSG_REG_PERMM2, + MSG_REG_PERMM3, MSG_REG_PERMM4, + MSG_REG_PERMM5, MSG_REG_PERMM6, + MSG_REG_PERMM7, MSG_REG_PERRFLAGS, + MSG_REG_PERES, MSG_REG_PERCS, + MSG_REG_PERSS, MSG_REG_PERDS, + MSG_REG_PERFS, MSG_REG_PERGS, + MSG_REG_RESERVED, MSG_REG_RESERVED, + MSG_REG_PERFSDOTBASE, MSG_REG_PERGSDOTBASE, + MSG_REG_RESERVED, MSG_REG_RESERVED, + MSG_REG_PERTR, MSG_REG_PERLDTR, + MSG_REG_PERMXCSR, MSG_REG_PERFCW, + MSG_REG_PERFSW + }; + + static const Msg reg_i386[8] = { + MSG_REG_EAX, MSG_REG_ECX, + MSG_REG_EDX, MSG_REG_EBX, + MSG_REG_UESP, MSG_REG_EBP, + MSG_REG_ESI, MSG_REG_EDI + }; + + static const Msg reg_sparc[64] = { + MSG_REG_G0, MSG_REG_G1, + MSG_REG_G2, MSG_REG_G3, + MSG_REG_G4, MSG_REG_G5, + MSG_REG_G6, MSG_REG_G7, + MSG_REG_O0, MSG_REG_O1, + MSG_REG_O2, MSG_REG_O3, + MSG_REG_O4, MSG_REG_O5, + MSG_REG_O6, MSG_REG_O7, + MSG_REG_L0, MSG_REG_L1, + MSG_REG_L2, MSG_REG_L3, + MSG_REG_L4, MSG_REG_L5, + MSG_REG_L6, MSG_REG_L7, + MSG_REG_I0, MSG_REG_I1, + MSG_REG_I2, MSG_REG_I3, + MSG_REG_I4, MSG_REG_I5, + MSG_REG_I6, MSG_REG_I7, + MSG_REG_F0, MSG_REG_F1, + MSG_REG_F2, MSG_REG_F3, + MSG_REG_F4, MSG_REG_F5, + MSG_REG_F6, MSG_REG_F7, + MSG_REG_F8, MSG_REG_F9, + MSG_REG_F10, MSG_REG_F11, + MSG_REG_F12, MSG_REG_F13, + MSG_REG_F14, MSG_REG_F15, + MSG_REG_F16, MSG_REG_F17, + MSG_REG_F18, MSG_REG_F19, + MSG_REG_F20, MSG_REG_F21, + MSG_REG_F22, MSG_REG_F23, + MSG_REG_F24, MSG_REG_F25, + MSG_REG_F26, MSG_REG_F27, + MSG_REG_F28, MSG_REG_F29, + MSG_REG_F30, MSG_REG_F31 + }; + + switch (mach) { + case EM_AMD64: + /* + * amd64 has several in-bounds names we'd rather not + * use. R8-R15 have the same name as their DWARF counterparts. + * 56-57, and 60-61 are reserved, and don't have a good name. + */ + if (good_name) + *good_name = ((regno < 8) || (regno > 15)) && + (regno != 56) && (regno != 57) && + (regno != 60) && (regno != 61) && + (regno < ARRAY_NELTS(reg_amd64)); + return (conv_map2str(inv_buf, regno, + fmt_flags, ARRAY_NELTS(reg_amd64), reg_amd64)); + + case EM_386: + case EM_486: + if (good_name) + *good_name = (regno < ARRAY_NELTS(reg_i386)); + return (conv_map2str(inv_buf, regno, + fmt_flags, ARRAY_NELTS(reg_i386), reg_i386)); + + case EM_SPARC: + case EM_SPARC32PLUS: + case EM_SPARCV9: + if (good_name) + *good_name = (regno < ARRAY_NELTS(reg_sparc)); + return (conv_map2str(inv_buf, regno, + fmt_flags, ARRAY_NELTS(reg_sparc), reg_sparc)); + } + + if (good_name) + *good_name = 0; + return (conv_invalid_val(inv_buf, regno, 0)); +} diff --git a/usr/src/cmd/sgs/libconv/common/dwarf.msg b/usr/src/cmd/sgs/libconv/common/dwarf.msg new file mode 100644 index 0000000000..1a2cbaf30d --- /dev/null +++ b/usr/src/cmd/sgs/libconv/common/dwarf.msg @@ -0,0 +1,203 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# Call Frame Information op codes +# +@ MSG_DW_CFA_ADVANCE_LOC "DW_CFA_advance_loc" +@ MSG_DW_CFA_ADVANCE_LOC_1 "DW_CFA_advance_loc_1" +@ MSG_DW_CFA_ADVANCE_LOC_2 "DW_CFA_advance_loc_2" +@ MSG_DW_CFA_ADVANCE_LOC_4 "DW_CFA_advance_loc_4" +@ MSG_DW_CFA_DEF_CFA "DW_CFA_def_cfa" +@ MSG_DW_CFA_DEF_CFA_EXPRESSION "DW_CFA_def_cfa_expression" +@ MSG_DW_CFA_DEF_CFA_OFFSET "DW_CFA_def_cfa_offset" +@ MSG_DW_CFA_DEF_CFA_OFFSET_SF "DW_CFA_def_cfa_offset_sf" +@ MSG_DW_CFA_DEF_CFA_REGISTER "DW_CFA_def_cfa_register" +@ MSG_DW_CFA_DEF_CFA_SF "DW_CFA_def_cfa_sf" +@ MSG_DW_CFA_EXPRESSION "DW_CFA_expression" +@ MSG_DW_CFA_GNU_ARGS_SIZE "DW_CFA_GNU_args_size" +@ MSG_DW_CFA_GNU_NEGATIVE_OFF_X "DW_CFA_GNU_negative_offset_extended" +@ MSG_DW_CFA_GNU_WINDOW_SAVE "DW_CFA_GNU_window_save" +@ MSG_DW_CFA_MIPS_ADV_LOC8 "DW_CFA_MIPS_advance_loc8" +@ MSG_DW_CFA_NOP "DW_CFA_nop" +@ MSG_DW_CFA_OFFSET "DW_CFA_offset" +@ MSG_DW_CFA_OFFSET_EXTENDED "DW_CFA_offset_extended" +@ MSG_DW_CFA_OFFSET_EXTENDED_SF "DW_CFA_offset_extended_sf" +@ MSG_DW_CFA_REGISTER "DW_CFA_register" +@ MSG_DW_CFA_REMEMBER_STATE "DW_CFA_remember_state" +@ MSG_DW_CFA_RESTORE_STATE "DW_CFA_restore_state" +@ MSG_DW_CFA_RESTORE "DW_CFA_restore" +@ MSG_DW_CFA_RESTORE_EXTENDED "DW_CFA_restore_extended" +@ MSG_DW_CFA_SAME_VALUE "DW_CFA_same_value" +@ MSG_DW_CFA_SET_LOC "DW_CFA_set_loc" +@ MSG_DW_CFA_UNDEFINED "DW_CFA_undefined" +@ MSG_DW_CFA_VAL_EXPRESSION "DW_CFA_val_expression" +@ MSG_DW_CFA_VAL_OFFSET "DW_CFA_val_offset" +@ MSG_DW_CFA_VAL_OFFSET_SF "DW_CFA_val_offset_sf" + +# +# Names for registers on various machines +# +@ MSG_REG_EAX "eax" +@ MSG_REG_EBP "ebp" +@ MSG_REG_EBX "ebx" +@ MSG_REG_ECX "ecx" +@ MSG_REG_EDX "edx" +@ MSG_REG_EDI "edi" +@ MSG_REG_ESI "esi" +@ MSG_REG_F0 "f0" +@ MSG_REG_F1 "f1" +@ MSG_REG_F2 "f2" +@ MSG_REG_F3 "f3" +@ MSG_REG_F4 "f4" +@ MSG_REG_F5 "f5" +@ MSG_REG_F6 "f6" +@ MSG_REG_F7 "f7" +@ MSG_REG_F8 "f8" +@ MSG_REG_F9 "f9" +@ MSG_REG_F10 "f10" +@ MSG_REG_F11 "f11" +@ MSG_REG_F12 "f12" +@ MSG_REG_F13 "f13" +@ MSG_REG_F14 "f14" +@ MSG_REG_F15 "f15" +@ MSG_REG_F16 "f16" +@ MSG_REG_F17 "f17" +@ MSG_REG_F18 "f18" +@ MSG_REG_F19 "f19" +@ MSG_REG_F20 "f20" +@ MSG_REG_F21 "f21" +@ MSG_REG_F22 "f22" +@ MSG_REG_F23 "f23" +@ MSG_REG_F24 "f24" +@ MSG_REG_F25 "f25" +@ MSG_REG_F26 "f26" +@ MSG_REG_F27 "f27" +@ MSG_REG_F28 "f28" +@ MSG_REG_F29 "f29" +@ MSG_REG_F30 "f30" +@ MSG_REG_F31 "f31" +@ MSG_REG_G0 "g0" +@ MSG_REG_G1 "g1" +@ MSG_REG_G2 "g2" +@ MSG_REG_G3 "g3" +@ MSG_REG_G4 "g4" +@ MSG_REG_G5 "g5" +@ MSG_REG_G6 "g6" +@ MSG_REG_G7 "g7" +@ MSG_REG_I0 "i0" +@ MSG_REG_I1 "i1" +@ MSG_REG_I2 "i2" +@ MSG_REG_I3 "i3" +@ MSG_REG_I4 "i4" +@ MSG_REG_I5 "i5" +@ MSG_REG_I6 "i6" +@ MSG_REG_I7 "i7" +@ MSG_REG_L0 "l0" +@ MSG_REG_L1 "l1" +@ MSG_REG_L2 "l2" +@ MSG_REG_L3 "l3" +@ MSG_REG_L4 "l4" +@ MSG_REG_L5 "l5" +@ MSG_REG_L6 "l6" +@ MSG_REG_L7 "l7" +@ MSG_REG_O0 "o0" +@ MSG_REG_O1 "o1" +@ MSG_REG_O2 "o2" +@ MSG_REG_O3 "o3" +@ MSG_REG_O4 "o4" +@ MSG_REG_O5 "o5" +@ MSG_REG_O6 "o6" +@ MSG_REG_O7 "o7" +@ MSG_REG_PERCS "%%cs" +@ MSG_REG_PERDS "%%ds" +@ MSG_REG_PERES "%%es" +@ MSG_REG_PERFCW "%%fcw" +@ MSG_REG_PERFSW "%%fsw" +@ MSG_REG_PERFS "%%fs" +@ MSG_REG_PERFSDOTBASE "%%fs.base" +@ MSG_REG_PERGS "%%gs" +@ MSG_REG_PERGSDOTBASE "%%gs.base" +@ MSG_REG_PERLDTR "%%ldtr" +@ MSG_REG_PERMM0 "%%mm0" +@ MSG_REG_PERMM1 "%%mm1" +@ MSG_REG_PERMM2 "%%mm2" +@ MSG_REG_PERMM3 "%%mm3" +@ MSG_REG_PERMM4 "%%mm4" +@ MSG_REG_PERMM5 "%%mm5" +@ MSG_REG_PERMM6 "%%mm6" +@ MSG_REG_PERMM7 "%%mm7" +@ MSG_REG_PERMXCSR "%%mxcsr" +@ MSG_REG_PERRFLAGS "%%rFLAGS" +@ MSG_REG_PERSS "%%ss" +@ MSG_REG_PERST0 "%%st0" +@ MSG_REG_PERST1 "%%st1" +@ MSG_REG_PERST2 "%%st2" +@ MSG_REG_PERST3 "%%st3" +@ MSG_REG_PERST4 "%%st4" +@ MSG_REG_PERST5 "%%st5" +@ MSG_REG_PERST6 "%%st6" +@ MSG_REG_PERST7 "%%st7" +@ MSG_REG_PERTR "%%tr" +@ MSG_REG_PERXMM0 "%%xmm0" +@ MSG_REG_PERXMM1 "%%xmm1" +@ MSG_REG_PERXMM2 "%%xmm2" +@ MSG_REG_PERXMM3 "%%xmm3" +@ MSG_REG_PERXMM4 "%%xmm4" +@ MSG_REG_PERXMM5 "%%xmm5" +@ MSG_REG_PERXMM6 "%%xmm6" +@ MSG_REG_PERXMM7 "%%xmm7" +@ MSG_REG_PERXMM8 "%%xmm8" +@ MSG_REG_PERXMM9 "%%xmm9" +@ MSG_REG_PERXMM10 "%%xmm10" +@ MSG_REG_PERXMM11 "%%xmm11" +@ MSG_REG_PERXMM12 "%%xmm12" +@ MSG_REG_PERXMM13 "%%xmm13" +@ MSG_REG_PERXMM14 "%%xmm14" +@ MSG_REG_PERXMM15 "%%xmm15" +@ MSG_REG_R8 "r8" +@ MSG_REG_R9 "r9" +@ MSG_REG_R10 "r10" +@ MSG_REG_R11 "r11" +@ MSG_REG_R12 "r12" +@ MSG_REG_R13 "r13" +@ MSG_REG_R14 "r14" +@ MSG_REG_R15 "r15" +@ MSG_REG_RA "ra" +@ MSG_REG_RAX "rax" +@ MSG_REG_RBP "rbp" +@ MSG_REG_RBX "rbx" +@ MSG_REG_RCX "rcx" +@ MSG_REG_RDX "rdx" +@ MSG_REG_RDI "rdi" +@ MSG_REG_RESERVED "reserved" +@ MSG_REG_RSI "rsi" +@ MSG_REG_RSP "rsp" +@ MSG_REG_UESP "uesp" + + +@ MSG_GBL_OSQBRKT "[" +@ MSG_GBL_CSQBRKT "]" diff --git a/usr/src/cmd/sgs/libconv/common/phdr.c b/usr/src/cmd/sgs/libconv/common/phdr.c index cc32f6f8bc..233387f238 100644 --- a/usr/src/cmd/sgs/libconv/common/phdr.c +++ b/usr/src/cmd/sgs/libconv/common/phdr.c @@ -20,12 +20,10 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * String conversion routines for program header attributes. */ @@ -36,6 +34,7 @@ /* Instantiate a local copy of conv_map2str() from _conv.h */ DEFINE_conv_map2str +/*ARGSUSED*/ const char * conv_phdr_type(Half mach, Word type, Conv_fmt_flags_t fmt_flags, Conv_inv_buf_t *inv_buf) @@ -87,7 +86,7 @@ error "PT_NUM has grown. Update phdrs[]" return (conv_map2str(inv_buf, (type - PT_SUNWBSS), fmt_flags, ARRAY_NELTS(uphdrs), uphdrs)); } - } else if ((type == PT_SUNW_UNWIND) && (mach == EM_AMD64)) { + } else if (type == PT_SUNW_UNWIND) { switch (CONV_TYPE_FMT_ALT(fmt_flags)) { case CONV_FMT_ALT_DUMP: case CONV_FMT_ALT_FILE: @@ -95,6 +94,14 @@ error "PT_NUM has grown. Update phdrs[]" default: return (MSG_ORIG(MSG_PT_SUNW_UNWIND)); } + } else if (type == PT_SUNW_EH_FRAME) { + switch (CONV_TYPE_FMT_ALT(fmt_flags)) { + case CONV_FMT_ALT_DUMP: + case CONV_FMT_ALT_FILE: + return (MSG_ORIG(MSG_PT_SUNW_EH_FRAME_ALT)); + default: + return (MSG_ORIG(MSG_PT_SUNW_EH_FRAME)); + } } else return (conv_invalid_val(inv_buf, type, 0)); } diff --git a/usr/src/cmd/sgs/libconv/common/phdr.msg b/usr/src/cmd/sgs/libconv/common/phdr.msg index b1f1684f92..dbb251c560 100644 --- a/usr/src/cmd/sgs/libconv/common/phdr.msg +++ b/usr/src/cmd/sgs/libconv/common/phdr.msg @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -50,8 +50,10 @@ @ MSG_PT_SUNWCAP "[ PT_SUNWCAP ]" @ MSG_PT_SUNWCAP_ALT "PT_SUNWCAP" -@ MSG_PT_SUNW_UNWIND "[ PT_SUNW_UNWIND ]" +@ MSG_PT_SUNW_UNWIND "[ PT_SUNW_UNWIND ]" @ MSG_PT_SUNW_UNWIND_ALT "PT_SUNW_UNWIND" +@ MSG_PT_SUNW_EH_FRAME "[ PT_SUNW_EH_FRAME ]" +@ MSG_PT_SUNW_EH_FRAME_ALT "PT_SUNW_EH_FRAME" @ MSG_PF_X "PF_X" @ MSG_PF_W "PF_W" diff --git a/usr/src/cmd/sgs/libconv/common/symbols.c b/usr/src/cmd/sgs/libconv/common/symbols.c index fc29b70927..0ec4c04854 100644 --- a/usr/src/cmd/sgs/libconv/common/symbols.c +++ b/usr/src/cmd/sgs/libconv/common/symbols.c @@ -20,10 +20,9 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" /* * String conversion routines for symbol attributes. @@ -99,14 +98,14 @@ conv_sym_info_type(Half mach, uchar_t type, Conv_fmt_flags_t fmt_flags, MSG_STT_NOTYPE, MSG_STT_OBJECT, MSG_STT_FUNC, MSG_STT_SECTION, MSG_STT_FILE, MSG_STT_COMMON, - MSG_STT_TLS + MSG_STT_TLS, MSG_STT_IFUNC }; static const Msg types_alt[] = { MSG_STT_NOTYPE_ALT, MSG_STT_OBJECT_ALT, MSG_STT_FUNC_ALT, MSG_STT_SECTION_ALT, MSG_STT_FILE_ALT, MSG_STT_COMMON_ALT, - MSG_STT_TLS_ALT + MSG_STT_TLS_ALT, MSG_STT_IFUNC_ALT }; if (type < STT_NUM) { diff --git a/usr/src/cmd/sgs/libconv/common/symbols.msg b/usr/src/cmd/sgs/libconv/common/symbols.msg index 316ee1fa66..f14a159d69 100644 --- a/usr/src/cmd/sgs/libconv/common/symbols.msg +++ b/usr/src/cmd/sgs/libconv/common/symbols.msg @@ -19,11 +19,9 @@ # CDDL HEADER END # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" -# @ MSG_STT_NOTYPE "NOTY" @ MSG_STT_NOTYPE_ALT "STT_NOTYPE" @@ -37,8 +35,10 @@ @ MSG_STT_FILE_ALT "STT_FILE" @ MSG_STT_COMMON "COMM" @ MSG_STT_COMMON_ALT "STT_COMMON" -@ MSG_STT_TLS "TLS " +@ MSG_STT_TLS "TLS" @ MSG_STT_TLS_ALT "STT_TLS" +@ MSG_STT_IFUNC "IFUNC" +@ MSG_STT_IFUNC_ALT "STT_IFUNC" @ MSG_STT_SPARC_REGISTER "REGI" @ MSG_STT_SPARC_REGISTER_ALT "STT_SPARC_REGISTER" diff --git a/usr/src/cmd/sgs/libelf/demo/dispsyms.c b/usr/src/cmd/sgs/libelf/demo/dispsyms.c index baa56d0f5e..95a4304be8 100644 --- a/usr/src/cmd/sgs/libelf/demo/dispsyms.c +++ b/usr/src/cmd/sgs/libelf/demo/dispsyms.c @@ -19,10 +19,9 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" /* * dispsyms: Display Symbols @@ -62,8 +61,11 @@ static const char *symtype[STT_NUM] = { /* STT_FILE */ "FILE", /* STT_COMMON */ "COMM", /* STT_TLS */ "TLS" +/* STT_IFUNC */ "IFUNC" }; - +#if STT_NUM != (STT_IFUNC + 1) +#error "STT_NUM has grown. Update symtype[]." +#endif #define INTSTRLEN 32 @@ -79,13 +81,13 @@ print_symtab(Elf *elf, const char *file) if (gelf_getehdr(elf, &ehdr) == 0) { (void) fprintf(stderr, "%s: elf_getehdr() failed: %s\n", - file, elf_errmsg(0)); + file, elf_errmsg(0)); return; } if (elf_getshstrndx(elf, &shstrndx) == 0) { (void) fprintf(stderr, "%s: elf_getshstrndx() failed: %s\n", - file, elf_errmsg(0)); + file, elf_errmsg(0)); return; } @@ -99,8 +101,8 @@ print_symtab(Elf *elf, const char *file) if (gelf_getshdr(scn, &shdr) == 0) { (void) fprintf(stderr, - "%s: elf_getshdr() failed: %s\n", - file, elf_errmsg(0)); + "%s: elf_getshdr() failed: %s\n", + file, elf_errmsg(0)); return; } if ((shdr.sh_type != SHT_SYMTAB) && @@ -114,8 +116,8 @@ print_symtab(Elf *elf, const char *file) */ if ((symdata = elf_getdata(scn, 0)) == 0) { (void) fprintf(stderr, - "%s: elf_getdata() failed: %s\n", - file, elf_errmsg(0)); + "%s: elf_getdata() failed: %s\n", + file, elf_errmsg(0)); return; } @@ -123,9 +125,9 @@ print_symtab(Elf *elf, const char *file) * Print symbol table title and header for symbol display */ (void) printf("\nSymTab: %s:%s\n", file, - elf_strptr(elf, shstrndx, shdr.sh_name)); + elf_strptr(elf, shstrndx, shdr.sh_name)); (void) printf(" index value size type " - "bind oth shndx name\n"); + "bind oth shndx name\n"); /* * We now iterate over the full symbol table printing @@ -153,8 +155,8 @@ print_symtab(Elf *elf, const char *file) if (gelf_getsymshndx(symdata, shndxdata, ndx, &sym, &shndx) == NULL) { (void) fprintf(stderr, - "%s: gelf_getsymshndx() failed: %s\n", - file, elf_errmsg(0)); + "%s: gelf_getsymshndx() failed: %s\n", + file, elf_errmsg(0)); return; } /* @@ -200,9 +202,9 @@ print_symtab(Elf *elf, const char *file) (gelf_getsymshndx(symdata, shndxdata, ndx, &sym, &shndx) == NULL)) { (void) fprintf(stderr, - "%s: gelf_getsymshndx() " - "failed: %s\n", - file, elf_errmsg(0)); + "%s: gelf_getsymshndx() " + "failed: %s\n", + file, elf_errmsg(0)); return; } /* @@ -227,7 +229,7 @@ print_symtab(Elf *elf, const char *file) typestr = symtype[type]; else { (void) snprintf(typebuf, INTSTRLEN, - "%d", type); + "%d", type); typestr = typebuf; } @@ -235,7 +237,7 @@ print_symtab(Elf *elf, const char *file) bindstr = symbind[bind]; else { (void) snprintf(bindbuf, INTSTRLEN, - "%d", bind); + "%d", bind); bindstr = bindbuf; } @@ -261,12 +263,12 @@ print_symtab(Elf *elf, const char *file) shndxstr = (const char *)"XIND"; else { (void) snprintf(shndxbuf, INTSTRLEN, - "%ld", shndx); + "%ld", shndx); shndxstr = shndxbuf; } } else { (void) snprintf(shndxbuf, INTSTRLEN, - "%ld", shndx); + "%ld", shndx); shndxstr = shndxbuf; } @@ -274,10 +276,10 @@ print_symtab(Elf *elf, const char *file) * Display the symbol entry. */ (void) printf("[%3d] 0x%08llx 0x%08llx %-4s " - "%-6s %2d %5s %s\n", - ndx, sym.st_value, sym.st_size, - typestr, bindstr, sym.st_other, shndxstr, - elf_strptr(elf, shdr.sh_link, sym.st_name)); + "%-6s %2d %5s %s\n", + ndx, sym.st_value, sym.st_size, + typestr, bindstr, sym.st_other, shndxstr, + elf_strptr(elf, shdr.sh_link, sym.st_name)); } } } @@ -317,7 +319,7 @@ process_elf(Elf *elf, char *file, int fd, int member) * 'archivename(membername)'. */ (void) snprintf(buffer, 1024, "%s(%s)", - file, arhdr->ar_name); + file, arhdr->ar_name); /* * recursivly process the ELF members. @@ -330,8 +332,8 @@ process_elf(Elf *elf, char *file, int fd, int member) default: if (!member) (void) fprintf(stderr, - "%s: unexpected elf_kind(): 0x%x\n", - file, elf_kind(elf)); + "%s: unexpected elf_kind(): 0x%x\n", + file, elf_kind(elf)); return; } } @@ -354,7 +356,7 @@ main(int argc, char **argv) */ if (elf_version(EV_CURRENT) == EV_NONE) { (void) fprintf(stderr, - "elf_version() failed: %s\n", elf_errmsg(0)); + "elf_version() failed: %s\n", elf_errmsg(0)); return (1); } diff --git a/usr/src/cmd/sgs/libld/Makefile.com b/usr/src/cmd/sgs/libld/Makefile.com index 0e6d1a6c65..cfa5fc3b6b 100644 --- a/usr/src/cmd/sgs/libld/Makefile.com +++ b/usr/src/cmd/sgs/libld/Makefile.com @@ -33,14 +33,14 @@ COMOBJS32 = args32.o entry32.o exit32.o groups32.o \ libs32.o files32.o map32.o order32.o \ outfile32.o place32.o relocate32.o resolve32.o \ sections32.o sunwmove32.o support32.o syms32.o \ - update32.o version32.o + update32.o unwind32.o version32.o COMOBJS64 = args64.o entry64.o exit64.o groups64.o \ ldentry64.o ldlibs64.o ldmachdep64.o ldmain64.o \ libs64.o files64.o map64.o order64.o \ outfile64.o place64.o relocate64.o resolve64.o \ sections64.o sunwmove64.o support64.o syms64.o \ - update64.o version64.o + update64.o unwind64.o version64.o TOOLOBJS = alist.o assfail.o findprime.o string_table.o \ strhash.o @@ -58,7 +58,7 @@ L_SPARC_MACHOBJS64 = machrel.sparc64.o machsym.sparc64.o # Target specific objects (i386/amd64) E_X86_TOOLOBJS = leb128.o L_X86_MACHOBJS32 = machrel.intel32.o -L_X86_MACHOBJS64 = machrel.amd64.o unwind.amd64.o +L_X86_MACHOBJS64 = machrel.amd64.o # All target specific objects rolled together diff --git a/usr/src/cmd/sgs/libld/common/README.XLINK b/usr/src/cmd/sgs/libld/common/README.XLINK index 2eebe59ee2..5eba8e52f4 100644 --- a/usr/src/cmd/sgs/libld/common/README.XLINK +++ b/usr/src/cmd/sgs/libld/common/README.XLINK @@ -20,10 +20,9 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" @@ -72,8 +71,8 @@ In addition, the target-specific files usually include the target in their name (i.e. machrel.sparc.c). Although the target dependent and independent (common) code is well separated, -they are interdependent. For example, the common code is aware of -the target-specific section types that can occur only for some targets +they are interdependent. The common code is explicitly aware of +target-specific section types that can occur only for some targets (i.e. SHT_AMD64_UNWIND). This is not an architecture that allows for arbitrary target support to be dynamically plugged into an unchanged platform independent core. Rather, it is an organization that allows diff --git a/usr/src/cmd/sgs/libld/common/_libld.h b/usr/src/cmd/sgs/libld/common/_libld.h index 42a1dc82da..61d09a73a0 100644 --- a/usr/src/cmd/sgs/libld/common/_libld.h +++ b/usr/src/cmd/sgs/libld/common/_libld.h @@ -98,6 +98,9 @@ typedef struct { Word m_plt_reservsz; Word m_plt_shf_flags; + /* Section type of .eh_frame/.eh_frame_hdr sections */ + Word m_sht_unwind; + Word m_dt_register; } Target_mach; @@ -134,6 +137,7 @@ typedef struct { Word id_tlsbss; Word id_unknown; Word id_unwind; + Word id_unwindhdr; Word id_user; Word id_version; } Target_machid; @@ -218,26 +222,12 @@ typedef struct { int (* ms_reg_enter)(Sym_desc *, Ofl_desc *); } Target_machsym; -/* - * amd64 unwind header support - * - * These fields are allowed to be NULL for targets that do not support - * amd64 unwind headers. If any of these fields are non-NULL, all of them are - * required to be present (use empty stub routines if necessary). - */ -typedef struct { - uintptr_t (* uw_make_unwindhdr)(Ofl_desc *); - uintptr_t (* uw_populate_unwindhdr)(Ofl_desc *); - uintptr_t (* uw_append_unwind)(Os_desc *, Ofl_desc *); -} Target_unwind; - typedef struct { Target_mach t_m; Target_machid t_id; Target_nullfunc t_nf; Target_machrel t_mr; Target_machsym t_ms; - Target_unwind t_uw; } Target; @@ -330,16 +320,17 @@ typedef struct { /* * Define Alist initialization sizes. */ -#define AL_CNT_IFL_GROUPS 20 /* ifl_groups initial alist count */ -#define AL_CNT_OFL_DTSFLTRS 4 /* ofl_dtsfltrs initial alist count */ -#define AL_CNT_OFL_SYMFLTRS 20 /* ofl_symfltrs initial alist count */ +#define AL_CNT_IFL_GROUPS 20 /* ifl_groups */ +#define AL_CNT_OFL_DTSFLTRS 4 /* ofl_dtsfltrs */ +#define AL_CNT_OFL_SYMFLTRS 20 /* ofl_symfltrs */ #define AL_CNT_OS_MSTRISDESCS 10 /* os_mstrisdescs */ #define AL_CNT_OS_RELISDESCS 100 /* os_relisdescs */ #define AL_CNT_OS_COMDATS 20 /* os_comdats */ -#define AL_CNT_SG_OSDESC 40 /* sg_osdescs initial alist count */ -#define AL_CNT_SG_SECORDER 40 /* sg_secorder initial alist count */ +#define AL_CNT_SG_OSDESC 40 /* sg_osdescs */ +#define AL_CNT_SG_SECORDER 40 /* sg_secorder */ #define AL_CNT_STRMRGREL 500 /* ld_make_strmerge() reloc alist cnt */ #define AL_CNT_STRMRGSYM 20 /* ld_make_strmerge() sym alist cnt */ +#define AL_CNT_UNWIND 1 /* ofl_unwind */ /* * Return codes for {tls|got}_fixups() routines @@ -590,6 +581,9 @@ extern Sdf_desc *sdf_find(const char *, List *); #define ld_targ ld64_targ #define ld_targ_init_sparc ld64_targ_init_sparc #define ld_targ_init_x86 ld64_targ_init_x86 +#define ld_unwind_make_hdr ld64_unwind_make_hdr +#define ld_unwind_populate_hdr ld64_unwind_populate_hdr +#define ld_unwind_register ld64_unwind_register #define ld_vers_base ld64_vers_base #define ld_vers_check_defs ld64_vers_check_defs #define ld_vers_check_need ld64_vers_check_need @@ -673,6 +667,9 @@ extern Sdf_desc *sdf_find(const char *, List *); #define ld_targ ld32_targ #define ld_targ_init_sparc ld32_targ_init_sparc #define ld_targ_init_x86 ld32_targ_init_x86 +#define ld_unwind_make_hdr ld32_unwind_make_hdr +#define ld_unwind_populate_hdr ld32_unwind_populate_hdr +#define ld_unwind_register ld32_unwind_register #define ld_vers_base ld32_vers_base #define ld_vers_check_defs ld32_vers_check_defs #define ld_vers_check_need ld32_vers_check_need @@ -792,6 +789,10 @@ extern Target ld_targ; extern const Target *ld_targ_init_sparc(void); extern const Target *ld_targ_init_x86(void); +extern uintptr_t ld_unwind_make_hdr(Ofl_desc *); +extern uintptr_t ld_unwind_populate_hdr(Ofl_desc *); +extern uintptr_t ld_unwind_register(Os_desc *, Ofl_desc *); + extern Ver_desc *ld_vers_base(Ofl_desc *); extern uintptr_t ld_vers_check_defs(Ofl_desc *); extern uintptr_t ld_vers_check_need(Ofl_desc *); diff --git a/usr/src/cmd/sgs/libld/common/entry.c b/usr/src/cmd/sgs/libld/common/entry.c index d06df73030..175b0ac342 100644 --- a/usr/src/cmd/sgs/libld/common/entry.c +++ b/usr/src/cmd/sgs/libld/common/entry.c @@ -23,7 +23,7 @@ * Copyright (c) 1988 AT&T * All Rights Reserved * - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -53,9 +53,7 @@ typedef enum { LD_DYN, LD_DTRACE, LD_TLS, -#if defined(_ELF64) - LD_UNWIND, /* (amd64-only) */ -#endif + LD_UNWIND, LD_NOTE, LD_EXTRA, LD_NUM @@ -138,11 +136,9 @@ static const Sg_desc sg_desc[LD_NUM] = { SG_DESC_INIT(PT_TLS, PF_R, MSG_ORIG(MSG_ENT_TLS), (FLG_SG_TYPE | FLG_SG_FLAGS)), -#if defined(_ELF64) - /* LD_UNWIND (amd64-only) */ + /* LD_UNWIND */ SG_DESC_INIT(PT_SUNW_UNWIND, PF_R, MSG_ORIG(MSG_ENT_UNWIND), (FLG_SG_TYPE | FLG_SG_FLAGS)), -#endif /* LD_NOTE */ SG_DESC_INIT(PT_NOTE, 0, MSG_ORIG(MSG_ENT_NOTE), FLG_SG_TYPE), @@ -297,7 +293,6 @@ ld_ent_setup(Ofl_desc *ofl, Xword segalign) switch (idx) { case LD_LRODATA: case LD_LDATA: - case LD_UNWIND: if ((ld_targ.t_m.m_mach != EM_AMD64)) continue; } diff --git a/usr/src/cmd/sgs/libld/common/files.c b/usr/src/cmd/sgs/libld/common/files.c index 26700a1fed..63b3d565f0 100644 --- a/usr/src/cmd/sgs/libld/common/files.c +++ b/usr/src/cmd/sgs/libld/common/files.c @@ -555,7 +555,9 @@ static uintptr_t process_progbits(const char *name, Ifl_desc *ifl, Shdr *shdr, Elf_Scn *scn, Word ndx, int ident, Ofl_desc *ofl) { - int stab_index = 0; + int stab_index = 0; + Word is_flags = 0; + uintptr_t r; /* * Never include .stab.excl sections in any output file. @@ -587,37 +589,93 @@ process_progbits(const char *name, Ifl_desc *ifl, Shdr *shdr, Elf_Scn *scn, * our own version, so don't allow any input sections of these types to * be added to the output section list (why a relocatable object would * have a .plt or .got is a mystery, but stranger things have occurred). + * + * If there are any unwind sections, and this is a platform that uses + * SHT_PROGBITS for unwind sections, then set their ident to reflect + * that. */ if (ident) { - if (shdr->sh_flags & SHF_TLS) + if (shdr->sh_flags & SHF_TLS) { ident = ld_targ.t_id.id_tls; - else if ((shdr->sh_flags & ~ALL_SHF_IGNORE) == - (SHF_ALLOC | SHF_EXECINSTR)) + } else if ((shdr->sh_flags & ~ALL_SHF_IGNORE) == + (SHF_ALLOC | SHF_EXECINSTR)) { ident = ld_targ.t_id.id_text; - else if (shdr->sh_flags & SHF_ALLOC) { - if ((strcmp(name, MSG_ORIG(MSG_SCN_PLT)) == 0) || - (strcmp(name, MSG_ORIG(MSG_SCN_GOT)) == 0)) - ident = ld_targ.t_id.id_null; - else if (stab_index) { - /* - * This is a work-around for x86 compilers that - * have set SHF_ALLOC for the .stab.index - * section. - * - * Because of this, make sure that the - * .stab.index does not end up as the last - * section in the text segment. Older linkers - * can produce segmentation violations when they - * strip (ld -s) against a shared object whose - * last section in the text segment is a .stab. - */ - ident = ld_targ.t_id.id_interp; - } else - ident = ld_targ.t_id.id_data; + } else if (shdr->sh_flags & SHF_ALLOC) { + int done = 0; + + if (name[0] == '.') { + switch (name[1]) { + case 'e': + if ((ld_targ.t_m.m_sht_unwind == + SHT_PROGBITS) && + (strcmp(name, + MSG_ORIG(MSG_SCN_EHFRAME)) == 0)) { + ident = ld_targ.t_id.id_unwind; + is_flags = FLG_IS_EHFRAME; + done = 1; + } + break; + case 'g': + if (strcmp(name, + MSG_ORIG(MSG_SCN_GOT)) == 0) { + ident = ld_targ.t_id.id_null; + done = 1; + break; + } + if ((ld_targ.t_m.m_sht_unwind == + SHT_PROGBITS)&& + (strcmp(name, + MSG_ORIG(MSG_SCN_GCC_X_TBL)) == + 0)) { + ident = ld_targ.t_id.id_unwind; + done = 1; + break; + } + break; + case 'p': + if (strcmp(name, + MSG_ORIG(MSG_SCN_PLT)) == 0) { + ident = ld_targ.t_id.id_null; + done = 1; + } + break; + } + } + if (!done) { + if (stab_index) { + /* + * This is a work-around for x86 + * compilers that have set SHF_ALLOC + * for the .stab.index section. + * + * Because of this, make sure that the + * .stab.index does not end up as the + * last section in the text segment. + * Older linkers can produce + * segmentation violations when they + * strip (ld -s) against a shared + * object whose last section in the + * text segment is a .stab. + */ + ident = ld_targ.t_id.id_interp; + } else { + ident = ld_targ.t_id.id_data; + } + } } else ident = ld_targ.t_id.id_note; } - return (process_section(name, ifl, shdr, scn, ndx, ident, ofl)); + + r = process_section(name, ifl, shdr, scn, ndx, ident, ofl); + + /* + * On success, process_section() creates an input section descriptor. + * Now that it exists, we can add any pending input section flags. + */ + if ((is_flags != 0) && (r == 1)) + ifl->ifl_isdesc[ndx]->is_flags |= is_flags; + + return (r); } /* @@ -1277,6 +1335,21 @@ process_dynamic(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl) } /* + * Process a progbits section from a relocatable object (ET_REL). + * This is used on non-amd64 objects to recognize .eh_frame sections. + */ +/*ARGSUSED1*/ +static uintptr_t +process_progbits_final(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl) +{ + if (isc->is_osdesc && (isc->is_flags & FLG_IS_EHFRAME) && + (ld_unwind_register(isc->is_osdesc, ofl) == S_ERROR)) + return (S_ERROR); + + return (1); +} + +/* * Process a group section. */ static uintptr_t @@ -1415,8 +1488,10 @@ process_exclude(const char *name, Ifl_desc *ifl, Shdr *shdr, Elf_Scn *scn, * procedure (ie. things that can only be done when all required sections * have been collected). */ -static uintptr_t (*Initial[SHT_NUM][2])() = { +typedef uintptr_t (* initial_func_t)(const char *, Ifl_desc *, Shdr *, + Elf_Scn *, Word, int, Ofl_desc *); +static initial_func_t Initial[SHT_NUM][2] = { /* ET_REL ET_DYN */ /* SHT_NULL */ invalid_section, invalid_section, @@ -1440,10 +1515,13 @@ static uintptr_t (*Initial[SHT_NUM][2])() = { /* SHT_SYMTAB_SHNDX */ process_sym_shndx, NULL }; -static uintptr_t (*Final[SHT_NUM][2])() = { +typedef uintptr_t (* final_func_t)(Is_desc *, Ifl_desc *, Ofl_desc *); + +static final_func_t Final[SHT_NUM][2] = { +/* ET_REL ET_DYN */ /* SHT_NULL */ NULL, NULL, -/* SHT_PROGBITS */ NULL, NULL, +/* SHT_PROGBITS */ process_progbits_final, NULL, /* SHT_SYMTAB */ ld_sym_process, ld_sym_process, /* SHT_STRTAB */ NULL, NULL, /* SHT_RELA */ rel_process, NULL, @@ -1643,8 +1721,8 @@ process_elf(Ifl_desc *ifl, Elf *elf, Ofl_desc *ofl) return (S_ERROR); break; case SHT_SUNW_cap: - if (process_section(name, ifl, shdr, scn, - ndx, ld_targ.t_id.id_null, ofl) == S_ERROR) + if (process_section(name, ifl, shdr, scn, ndx, + ld_targ.t_id.id_null, ofl) == S_ERROR) return (S_ERROR); capisp = ifl->ifl_isdesc[ndx]; break; @@ -1655,13 +1733,13 @@ process_elf(Ifl_desc *ifl, Elf *elf, Ofl_desc *ofl) return (S_ERROR); break; case SHT_SUNW_move: - if (process_section(name, ifl, shdr, scn, - ndx, ld_targ.t_id.id_null, ofl) == S_ERROR) + if (process_section(name, ifl, shdr, scn, ndx, + ld_targ.t_id.id_null, ofl) == S_ERROR) return (S_ERROR); break; case SHT_SUNW_syminfo: - if (process_section(name, ifl, shdr, scn, - ndx, ld_targ.t_id.id_null, ofl) == S_ERROR) + if (process_section(name, ifl, shdr, scn, ndx, + ld_targ.t_id.id_null, ofl) == S_ERROR) return (S_ERROR); sifisp = ifl->ifl_isdesc[ndx]; break; @@ -1677,20 +1755,20 @@ process_elf(Ifl_desc *ifl, Elf *elf, Ofl_desc *ofl) ifl->ifl_isdesc[ndx]->is_flags |= FLG_IS_COMDAT; break; case SHT_SUNW_verdef: - if (process_section(name, ifl, shdr, scn, - ndx, ld_targ.t_id.id_null, ofl) == S_ERROR) + if (process_section(name, ifl, shdr, scn, ndx, + ld_targ.t_id.id_null, ofl) == S_ERROR) return (S_ERROR); vdfisp = ifl->ifl_isdesc[ndx]; break; case SHT_SUNW_verneed: - if (process_section(name, ifl, shdr, scn, - ndx, ld_targ.t_id.id_null, ofl) == S_ERROR) + if (process_section(name, ifl, shdr, scn, ndx, + ld_targ.t_id.id_null, ofl) == S_ERROR) return (S_ERROR); vndisp = ifl->ifl_isdesc[ndx]; break; case SHT_SUNW_versym: - if (process_section(name, ifl, shdr, scn, - ndx, ld_targ.t_id.id_null, ofl) == S_ERROR) + if (process_section(name, ifl, shdr, scn, ndx, + ld_targ.t_id.id_null, ofl) == S_ERROR) return (S_ERROR); vsyisp = ifl->ifl_isdesc[ndx]; break; @@ -1704,9 +1782,8 @@ process_elf(Ifl_desc *ifl, Elf *elf, Ofl_desc *ofl) if (ld_targ.t_m.m_mach != LD_TARG_BYCLASS(EM_SPARC, EM_SPARCV9)) goto do_default; - if (process_section(name, ifl, shdr, scn, - ndx, ld_targ.t_id.id_gotdata, ofl) == - S_ERROR) + if (process_section(name, ifl, shdr, scn, ndx, + ld_targ.t_id.id_gotdata, ofl) == S_ERROR) return (S_ERROR); break; #if defined(_ELF64) @@ -1732,15 +1809,17 @@ process_elf(Ifl_desc *ifl, Elf *elf, Ofl_desc *ofl) scn, ndx, ld_targ.t_id.id_unwind, ofl) == S_ERROR) return (S_ERROR); + ifl->ifl_isdesc[ndx]->is_flags |= + FLG_IS_EHFRAME; } break; #endif default: do_default: - if (ident != ld_targ.t_id.id_null) - ident = ld_targ.t_id.id_user; - if (process_section(name, ifl, shdr, scn, - ndx, ident, ofl) == S_ERROR) + if (process_section(name, ifl, shdr, scn, ndx, + ((ident == ld_targ.t_id.id_null) ? + ident : ld_targ.t_id.id_user), ofl) == + S_ERROR) return (S_ERROR); break; } @@ -1935,9 +2014,7 @@ process_elf(Ifl_desc *ifl, Elf *elf, Ofl_desc *ofl) * objects. */ if (osp && (ld_targ.t_m.m_mach == EM_AMD64) && - (ld_targ.t_uw.uw_append_unwind != NULL) && - ((*ld_targ.t_uw.uw_append_unwind)(osp, ofl) == - S_ERROR)) + (ld_unwind_register(osp, ofl) == S_ERROR)) return (S_ERROR); #endif } diff --git a/usr/src/cmd/sgs/libld/common/globals.c b/usr/src/cmd/sgs/libld/common/globals.c index 51e81ad867..b1dd5ed72e 100644 --- a/usr/src/cmd/sgs/libld/common/globals.c +++ b/usr/src/cmd/sgs/libld/common/globals.c @@ -90,7 +90,7 @@ ldynsym_symtype[] = { 1, /* STT_FILE */ 0, /* STT_COMMON */ 0, /* STT_TLS */ - 0, /* 7 */ + 0, /* STT_IFUNC */ 0, /* 8 */ 0, /* 9 */ 0, /* 10 */ @@ -100,7 +100,7 @@ ldynsym_symtype[] = { 0, /* 14 */ 0, /* 15 */ }; -#if STT_NUM != (STT_TLS + 1) +#if STT_NUM != (STT_IFUNC + 1) #error "STT_NUM has grown. Update ldynsym_symtype[]." #endif @@ -117,7 +117,7 @@ dynsymsort_symtype[] = { 0, /* STT_FILE */ 1, /* STT_COMMON */ 0, /* STT_TLS */ - 0, /* 7 */ + 0, /* STT_IFUNC */ 0, /* 8 */ 0, /* 9 */ 0, /* 10 */ @@ -127,6 +127,6 @@ dynsymsort_symtype[] = { 0, /* 14 */ 0, /* 15 */ }; -#if STT_NUM != (STT_TLS + 1) +#if STT_NUM != (STT_IFUNC + 1) #error "STT_NUM has grown. Update dynsymsort_symtype[]." #endif diff --git a/usr/src/cmd/sgs/libld/common/ldmain.c b/usr/src/cmd/sgs/libld/common/ldmain.c index 0f35378b11..e4f8fb731f 100644 --- a/usr/src/cmd/sgs/libld/common/ldmain.c +++ b/usr/src/cmd/sgs/libld/common/ldmain.c @@ -348,14 +348,11 @@ ld_main(int argc, char **argv, Half mach) if (ld_reloc_process(ofl) == S_ERROR) return (ld_exit(ofl)); -#if defined(_ELF64) /* - * Fill in contents for Unwind Header + * Fill in contents for unwind header (.eh_frame_hdr) */ - if ((ld_targ.t_uw.uw_populate_unwindhdr != NULL) && - ((*ld_targ.t_uw.uw_populate_unwindhdr)(ofl) == S_ERROR)) + if (ld_unwind_populate_hdr(ofl) == S_ERROR) return (ld_exit(ofl)); -#endif /* * Finally create the files elf checksum. diff --git a/usr/src/cmd/sgs/libld/common/machrel.amd.c b/usr/src/cmd/sgs/libld/common/machrel.amd.c index 151c29f9d3..a654c30c96 100644 --- a/usr/src/cmd/sgs/libld/common/machrel.amd.c +++ b/usr/src/cmd/sgs/libld/common/machrel.amd.c @@ -36,7 +36,6 @@ #include <i386/machdep_x86.h> #include "msg.h" #include "_libld.h" -#include "unwind.amd.h" /* Forward declarations */ @@ -1595,6 +1594,9 @@ ld_targ_init_x86(void) M_PLT_RESERVSZ, /* m_plt_reservsz */ M_PLT_SHF_FLAGS, /* m_plt_shf_flags */ + /* Section type of .eh_frame/.eh_frame_hdr sections */ + SHT_AMD64_UNWIND, /* m_sht_unwind */ + M_DT_REGISTER, /* m_dt_register */ }, { /* Target_machid */ @@ -1626,6 +1628,7 @@ ld_targ_init_x86(void) M_ID_TLSBSS, /* id_tlsbss */ M_ID_UNKNOWN, /* id_unknown */ M_ID_UNWIND, /* id_unwind */ + M_ID_UNWINDHDR, /* id_unwindhdr */ M_ID_USER, /* id_user */ M_ID_VERSION, /* id_version */ }, @@ -1662,11 +1665,6 @@ ld_targ_init_x86(void) NULL, /* ms_is_regsym */ NULL, /* ms_reg_find */ NULL /* ms_reg_enter */ - }, - { /* Target_unwind */ - make_amd64_unwindhdr, /* uw_make_unwindhdr */ - populate_amd64_unwindhdr, /* uw_populate_unwindhdr */ - append_amd64_unwind, /* uw_append_unwind */ } }; diff --git a/usr/src/cmd/sgs/libld/common/machrel.intel.c b/usr/src/cmd/sgs/libld/common/machrel.intel.c index 9de8c80fca..65f7c35c86 100644 --- a/usr/src/cmd/sgs/libld/common/machrel.intel.c +++ b/usr/src/cmd/sgs/libld/common/machrel.intel.c @@ -1670,6 +1670,9 @@ ld_targ_init_x86(void) M_PLT_RESERVSZ, /* m_plt_reservsz */ M_PLT_SHF_FLAGS, /* m_plt_shf_flags */ + /* Section type of .eh_frame/.eh_frame_hdr sections */ + SHT_PROGBITS, /* m_sht_unwind */ + M_DT_REGISTER, /* m_dt_register */ }, { /* Target_machid */ @@ -1701,6 +1704,7 @@ ld_targ_init_x86(void) M_ID_TLSBSS, /* id_tlsbss */ M_ID_UNKNOWN, /* id_unknown */ M_ID_UNWIND, /* id_unwind */ + M_ID_UNWINDHDR, /* id_unwindhdr */ M_ID_USER, /* id_user */ M_ID_VERSION, /* id_version */ }, @@ -1737,11 +1741,6 @@ ld_targ_init_x86(void) NULL, /* ms_is_regsym */ NULL, /* ms_reg_find */ NULL /* ms_reg_enter */ - }, - { /* Target_unwind */ - NULL, /* uw_make_unwindhdr */ - NULL, /* uw_populate_unwindhdr */ - NULL, /* uw_append_unwind */ } }; diff --git a/usr/src/cmd/sgs/libld/common/machrel.sparc.c b/usr/src/cmd/sgs/libld/common/machrel.sparc.c index 0d2774af8d..6f83983425 100644 --- a/usr/src/cmd/sgs/libld/common/machrel.sparc.c +++ b/usr/src/cmd/sgs/libld/common/machrel.sparc.c @@ -2247,6 +2247,9 @@ ld_targ_init_sparc(void) M_PLT_RESERVSZ, /* m_plt_reservsz */ M_PLT_SHF_FLAGS, /* m_plt_shf_flags */ + /* Section type of .eh_frame/.eh_frame_hdr sections */ + SHT_PROGBITS, /* m_sht_unwind */ + M_DT_REGISTER, /* m_dt_register */ }, { /* Target_machid */ @@ -2277,7 +2280,8 @@ ld_targ_init_sparc(void) M_ID_TLS, /* id_tls */ M_ID_TLSBSS, /* id_tlsbss */ M_ID_UNKNOWN, /* id_unknown */ - M_ID_UNKNOWN, /* id_unwind (unused) */ + M_ID_UNWIND, /* id_unwind */ + M_ID_UNWINDHDR, /* id_unwindhdr */ M_ID_USER, /* id_user */ M_ID_VERSION, /* id_version */ }, @@ -2314,11 +2318,6 @@ ld_targ_init_sparc(void) ld_is_regsym_sparc, /* ms_is_regsym */ ld_reg_find_sparc, /* ms_reg_find */ ld_reg_enter_sparc /* ms_reg_enter */ - }, - { /* Target_unwind */ - NULL, /* uw_make_unwindhdr */ - NULL, /* uw_populate_unwindhdr */ - NULL, /* uw_append_unwind */ } }; diff --git a/usr/src/cmd/sgs/libld/common/outfile.c b/usr/src/cmd/sgs/libld/common/outfile.c index d3d735f3fa..6b52f0febc 100644 --- a/usr/src/cmd/sgs/libld/common/outfile.c +++ b/usr/src/cmd/sgs/libld/common/outfile.c @@ -456,12 +456,9 @@ ld_create_outfile(Ofl_desc *ofl) } else if (ptype == PT_TLS) { if (flags & FLG_OF_TLSPHDR) nseg++; -#if defined(_ELF64) - } else if ((ld_targ.t_m.m_mach == EM_AMD64) && - (ptype == PT_SUNW_UNWIND)) { + } else if (ptype == PT_SUNW_UNWIND) { if (ofl->ofl_unwindhdr) nseg++; -#endif } else if (ptype == PT_SUNWDTRACE) { if (ofl->ofl_dtracesym) nseg++; diff --git a/usr/src/cmd/sgs/libld/common/sections.c b/usr/src/cmd/sgs/libld/common/sections.c index a4cd691c3b..a8119ecb61 100644 --- a/usr/src/cmd/sgs/libld/common/sections.c +++ b/usr/src/cmd/sgs/libld/common/sections.c @@ -2771,11 +2771,8 @@ ld_make_sections(Ofl_desc *ofl) return (S_ERROR); if (make_dynsym(ofl) == S_ERROR) return (S_ERROR); -#if defined(_ELF64) - if ((ld_targ.t_uw.uw_make_unwindhdr != NULL) && - ((*ld_targ.t_uw.uw_make_unwindhdr)(ofl) == S_ERROR)) + if (ld_unwind_make_hdr(ofl) == S_ERROR) return (S_ERROR); -#endif if (make_dynsort(ofl) == S_ERROR) return (S_ERROR); } diff --git a/usr/src/cmd/sgs/libld/common/unwind.amd.h b/usr/src/cmd/sgs/libld/common/unwind.amd.h deleted file mode 100644 index eeebb52182..0000000000 --- a/usr/src/cmd/sgs/libld/common/unwind.amd.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ - -/* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -/* - * amd64 unwind functionality - */ - -#ifndef _UNWIND_DOT_AMD_DOT_H -#define _UNWIND_DOT_AMD_DOT_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef __cplusplus -extern "C" { -#endif - -extern uintptr_t append_amd64_unwind(Os_desc *, Ofl_desc *); -extern uintptr_t make_amd64_unwindhdr(Ofl_desc *); -extern uintptr_t populate_amd64_unwindhdr(Ofl_desc *); - - -#ifdef __cplusplus -} -#endif - -#endif /* _UNWIND_DOT_AMD_DOT_H */ diff --git a/usr/src/cmd/sgs/libld/common/unwind.amd.c b/usr/src/cmd/sgs/libld/common/unwind.c index 14bcd12245..b2263e1e55 100644 --- a/usr/src/cmd/sgs/libld/common/unwind.amd.c +++ b/usr/src/cmd/sgs/libld/common/unwind.c @@ -24,18 +24,14 @@ * Use is subject to license terms. */ -#define ELF_TARGET_AMD64 - #include <string.h> #include <stdio.h> #include <sys/types.h> #include <sgs.h> #include <debug.h> -#include <i386/machdep_x86.h> #include <_libld.h> #include <dwarf.h> #include <stdlib.h> -#include "unwind.amd.h" /* * A EH_FRAME_HDR consists of the following: @@ -112,16 +108,16 @@ * ================= * * The call frame information needed for unwinding the stack is output in - * an ELF section(s) of type SHT_AMD64_UNWIND. In the simplest case there - * will be one such section per object file and it will be named - * ".eh_frame". An .eh_frame section consists of one or more + * an ELF section(s) of type SHT_AMD64_UNWIND (amd64) or SHT_PROGBITS (other). + * In the simplest case there will be one such section per object file and it + * will be named ".eh_frame". An .eh_frame section consists of one or more * subsections. Each subsection contains a CIE (Common Information Entry) * followed by varying number of FDEs (Frame Descriptor Entry). A FDE * corresponds to an explicit or compiler generated function in a * compilation unit, all FDEs can access the CIE that begins their * subsection for data. * - * If an object file contains C++ template instantiations there shall be + * If an object file contains C++ template instantiations, there shall be * a separate CIE immediately preceding each FDE corresponding to an * instantiation. * @@ -287,10 +283,28 @@ +static uint_t +extract_uint(const uchar_t *data, uint64_t *ndx, int do_swap) +{ + uint_t r; + uchar_t *p = (uchar_t *)&r; + + data += *ndx; + if (do_swap) + UL_ASSIGN_BSWAP_WORD(p, data); + else + UL_ASSIGN_WORD(p, data); + + (*ndx) += 4; + return (r); +} + /* - * The job of this function is to determine how much space - * will be required for the final table. We'll build - * it later. + * Create an unwind header (.eh_frame_hdr) output section. + * The section is created and space reserved, but the data + * is not copied into place. That is done by a later call + * to ld_unwind_populate(), after active relocations have been + * processed. * * When GNU linkonce processing is in effect, we can end up in a situation * where the FDEs related to discarded sections remain in the eh_frame @@ -303,21 +317,22 @@ * where all FDEs are valid. */ uintptr_t -make_amd64_unwindhdr(Ofl_desc *ofl) +ld_unwind_make_hdr(Ofl_desc *ofl) { + int bswap = (ofl->ofl_flags1 & FLG_OF1_ENCDIFF) != 0; Shdr *shdr; Elf_Data *elfdata; Is_desc *isp; size_t size; Xword fde_cnt; - Listnode *lnp; + Aliste idx; Os_desc *osp; /* * we only build a unwind header if we have * some unwind information in the file. */ - if (ofl->ofl_unwind.head == NULL) + if (aplist_nitems(ofl->ofl_unwind) == 0) return (1); /* @@ -326,7 +341,7 @@ make_amd64_unwindhdr(Ofl_desc *ofl) if ((elfdata = libld_calloc(sizeof (Elf_Data), 1)) == 0) return (S_ERROR); elfdata->d_type = ELF_T_BYTE; - elfdata->d_align = M_WORD_ALIGN; + elfdata->d_align = ld_targ.t_m.m_word_align; elfdata->d_version = ofl->ofl_dehdr->e_version; /* @@ -334,9 +349,9 @@ make_amd64_unwindhdr(Ofl_desc *ofl) */ if ((shdr = libld_calloc(sizeof (Shdr), 1)) == 0) return (S_ERROR); - shdr->sh_type = SHT_AMD64_UNWIND; + shdr->sh_type = ld_targ.t_m.m_sht_unwind; shdr->sh_flags = SHF_ALLOC; - shdr->sh_addralign = M_WORD_ALIGN; + shdr->sh_addralign = ld_targ.t_m.m_word_align; shdr->sh_entsize = 0; /* @@ -349,7 +364,7 @@ make_amd64_unwindhdr(Ofl_desc *ofl) isp->is_indata = elfdata; if ((ofl->ofl_unwindhdr = ld_place_section(ofl, isp, - M_ID_UNWINDHDR, 0)) == (Os_desc *)S_ERROR) + ld_targ.t_id.id_unwindhdr, 0)) == (Os_desc *)S_ERROR) return (S_ERROR); /* @@ -358,7 +373,7 @@ make_amd64_unwindhdr(Ofl_desc *ofl) * in the binary search table. */ fde_cnt = 0; - for (LIST_TRAVERSE(&ofl->ofl_unwind, lnp, osp)) { + for (APLIST_TRAVERSE(ofl->ofl_unwind, idx, osp)) { Listnode *_lnp; for (LIST_TRAVERSE(&osp->os_isdescs, _lnp, isp)) { @@ -370,7 +385,7 @@ make_amd64_unwindhdr(Ofl_desc *ofl) while (off < size) { uint_t length, id; - uint64_t ndx; + uint64_t ndx = 0; /* * Extract length in lsb format. A zero length @@ -378,15 +393,14 @@ make_amd64_unwindhdr(Ofl_desc *ofl) * that processing for unwind information is * complete. */ - if ((length = LSB32EXTRACT(data + off)) == 0) + length = extract_uint(data + off, &ndx, bswap); + if (length == 0) break; /* * Extract CIE id in lsb format. */ - ndx = 4; - id = LSB32EXTRACT(data + off + ndx); - ndx += 4; + id = extract_uint(data + off, &ndx, bswap); /* * A CIE record has a id of '0', otherwise @@ -470,12 +484,12 @@ bintabcompare(const void *p1, const void *p2) } uintptr_t -populate_amd64_unwindhdr(Ofl_desc *ofl) +ld_unwind_populate_hdr(Ofl_desc *ofl) { uchar_t *hdrdata; uint_t *binarytable; uint_t hdroff; - Listnode *lnp; + Aliste idx; Addr hdraddr; Os_desc *hdrosp; Os_desc *osp; @@ -524,7 +538,7 @@ populate_amd64_unwindhdr(Ofl_desc *ofl) first_unwind = 0; fde_count = 0; - for (LIST_TRAVERSE(&ofl->ofl_unwind, lnp, osp)) { + for (APLIST_TRAVERSE(ofl->ofl_unwind, idx, osp)) { uchar_t *data; size_t size; uint64_t off = 0; @@ -544,22 +558,21 @@ populate_amd64_unwindhdr(Ofl_desc *ofl) while (off < size) { uint_t length, id; - uint64_t ndx; + uint64_t ndx = 0; /* * Extract length in lsb format. A zero length * indicates that this CIE is a terminator and that * processing of unwind information is complete. */ - if ((length = LSB32EXTRACT(data + off)) == 0) + length = extract_uint(data + off, &ndx, bswap); + if (length == 0) goto done; /* * Extract CIE id in lsb format. */ - ndx = 4; - id = LSB32EXTRACT(data + off + ndx); - ndx += 4; + id = extract_uint(data + off, &ndx, bswap); /* * A CIE record has a id of '0'; otherwise @@ -627,7 +640,7 @@ populate_amd64_unwindhdr(Ofl_desc *ofl) &data[off + ndx], &ndx, ciePflag, ofl->ofl_dehdr->e_ident, - shdr->sh_addr + off + ndx); + shdr->sh_addr, off + ndx); break; case 'R': /* code encoding */ @@ -648,7 +661,7 @@ populate_amd64_unwindhdr(Ofl_desc *ofl) initloc = dwarf_ehe_extract(&data[off], &ndx, cieRflag, ofl->ofl_dehdr->e_ident, - shdr->sh_addr + off + ndx); + shdr->sh_addr, off + ndx); /* * Ignore FDEs with initloc set to 0. @@ -686,7 +699,7 @@ populate_amd64_unwindhdr(Ofl_desc *ofl) done: /* - * Do a quick sort on the binary table. If this is a cross + * Do a quicksort on the binary table. If this is a cross * link from a system with the opposite byte order, xlate * the resulting values into LSB order. */ @@ -710,7 +723,7 @@ done: /* LINTED */ uint_ptr = (uint_t *)(&hdrdata[hdroff]); *uint_ptr = first_unwind->os_shdr->sh_addr - - hdrosp->os_shdr->sh_addr + hdroff; + (hdrosp->os_shdr->sh_addr + hdroff); if (bswap) *uint_ptr = ld_bswap_Word(*uint_ptr); @@ -724,7 +737,7 @@ done: /* * If relaxed relocations are active, then there is a chance * that we didn't use all the space reserved for this section. - * For details, see the note at head of make_amd64_unwindhdr() above. + * For details, see the note at head of ld_unwind_make_hdr() above. * * Find the PT_SUNW_UNWIND program header, and change the size values * to the size of the subset of the section that was actually used. @@ -745,23 +758,34 @@ done: return (1); } +/* + * Append an .eh_frame section to our output list if not already present. + * + * Usually, there is a single .eh_frame output section. However, there can + * be more if there are incompatible section flags on incoming sections. + * If this does happen, the frame_ptr field of the eh_frame_hdr section + * will point at the base of the first output section, and the other + * sections will not be accessible via frame_ptr. However, the .eh_frame_hdr + * will be able to access all the data in the different .eh_frame sections, + * because the entries in sorted table are all encoded as DW_EH_PE_datarel. + */ uintptr_t -append_amd64_unwind(Os_desc *osp, Ofl_desc * ofl) +ld_unwind_register(Os_desc *osp, Ofl_desc * ofl) { - Listnode *lnp; - Os_desc *_osp; + Aliste idx; + Os_desc *_osp; /* * Check to see if this output section is already * on the list. */ - for (LIST_TRAVERSE(&ofl->ofl_unwind, lnp, _osp)) + for (APLIST_TRAVERSE(ofl->ofl_unwind, idx, _osp)) if (osp == _osp) return (1); /* * Append output section to unwind list */ - if (list_appendc(&ofl->ofl_unwind, osp) == 0) + if (aplist_append(&ofl->ofl_unwind, osp, AL_CNT_UNWIND) == NULL) return (S_ERROR); return (1); } diff --git a/usr/src/cmd/sgs/libld/common/update.c b/usr/src/cmd/sgs/libld/common/update.c index 63dda77127..7ee234fbf6 100644 --- a/usr/src/cmd/sgs/libld/common/update.c +++ b/usr/src/cmd/sgs/libld/common/update.c @@ -3383,17 +3383,15 @@ ld_update_outfile(Ofl_desc *ofl) } /* - * As the AMD unwind program header occurs after the loadable - * headers in the segment descriptor table, all the address - * information for the .eh_frame output section will have been - * figured out by now. + * As the unwind (.eh_frame_hdr) program header occurs after + * the loadable headers in the segment descriptor table, all + * the address information for the .eh_frame output section + * will have been figured out by now. */ -#if defined(_ELF64) - if ((ld_targ.t_m.m_mach == EM_AMD64) && - (phdr->p_type == PT_SUNW_UNWIND)) { + if (phdr->p_type == PT_SUNW_UNWIND) { Shdr *shdr; - if (ofl->ofl_unwindhdr == 0) + if (ofl->ofl_unwindhdr == NULL) continue; shdr = ofl->ofl_unwindhdr->os_shdr; @@ -3408,7 +3406,7 @@ ld_update_outfile(Ofl_desc *ofl) ofl->ofl_phdr[phdrndx++] = *phdr; continue; } -#endif + /* * As the TLS program header occurs after the loadable * headers in the segment descriptor table, all the address diff --git a/usr/src/cmd/sgs/packages/common/SUNWonld-README b/usr/src/cmd/sgs/packages/common/SUNWonld-README index 1fe0253dcd..82fc70dcf6 100644 --- a/usr/src/cmd/sgs/packages/common/SUNWonld-README +++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README @@ -1444,3 +1444,4 @@ Bugid Risk Synopsis 6807050 GNU linkonce sections can create duplicate and incompatible eh_frame FDE entries 6807864 ld.so.1 is susceptible to a fatal dlsym()/setlocale() race +6813909 generalize eh_frame support to non-amd64 platforms diff --git a/usr/src/cmd/sgs/rtld/common/elf.c b/usr/src/cmd/sgs/rtld/common/elf.c index 314e0625ff..1777894109 100644 --- a/usr/src/cmd/sgs/rtld/common/elf.c +++ b/usr/src/cmd/sgs/rtld/common/elf.c @@ -1673,6 +1673,7 @@ elf_new_lmp(Lm_list *lml, Aliste lmco, Fdesc *fdp, Addr addr, size_t msize, cap = (Cap *)((uintptr_t)phdr->p_vaddr + base); break; case PT_SUNW_UNWIND: + case PT_SUNW_EH_FRAME: uphdr = phdr; break; default: diff --git a/usr/src/cmd/sgs/tools/common/leb128.c b/usr/src/cmd/sgs/tools/common/leb128.c index a36ee7a249..1183e6f854 100644 --- a/usr/src/cmd/sgs/tools/common/leb128.c +++ b/usr/src/cmd/sgs/tools/common/leb128.c @@ -20,12 +20,10 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <stdio.h> #include <dwarf.h> #include <sys/types.h> @@ -183,9 +181,21 @@ sleb_extract(unsigned char *data, uint64_t *dotp) return (res); } +/* + * Extract a DWARF encoded datum + * + * entry: + * data - Base of data buffer containing encoded bytes + * dotp - Address of variable containing index within data + * at which the desired datum starts. + * ehe_flags - DWARF encoding + * eident - ELF header e_ident[] array for object being processed + * sh_base - Base address of ELF section containing desired datum + * sh_offset - Offset relative to sh_base of desired datum. + */ uint64_t dwarf_ehe_extract(unsigned char *data, uint64_t *dotp, uint_t ehe_flags, - unsigned char *eident, uint64_t pcaddr) + unsigned char *eident, uint64_t sh_base, uint64_t sh_offset) { uint64_t dot = *dotp; uint_t lsb; @@ -269,11 +279,18 @@ dwarf_ehe_extract(unsigned char *data, uint64_t *dotp, uint_t ehe_flags, } /* - * If pcrel and we have a value (ie: we've been - * relocated), then adjust the value. + * If value is relative to a base address, adjust it */ - if (result && (ehe_flags & DW_EH_PE_pcrel)) { - result = pcaddr + result; + if (result) { + switch (ehe_flags & 0xf0) { + case DW_EH_PE_pcrel: + result += sh_base + sh_offset; + break; + + case DW_EH_PE_datarel: + result += sh_base; + break; + } } *dotp = dot; return (result); diff --git a/usr/src/lib/libdtrace/common/dt_module.c b/usr/src/lib/libdtrace/common/dt_module.c index 25197031ce..51a1bdd0d1 100644 --- a/usr/src/lib/libdtrace/common/dt_module.c +++ b/usr/src/lib/libdtrace/common/dt_module.c @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <sys/modctl.h> #include <sys/kobj.h> @@ -66,6 +64,10 @@ dt_module_symhash_insert(dt_module_t *dmp, const char *name, uint_t id) static uint_t dt_module_syminit32(dt_module_t *dmp) { +#if STT_NUM != (STT_IFUNC + 1) +#error "STT_NUM has grown. update dt_module_syminit32()" +#endif + const Elf32_Sym *sym = dmp->dm_symtab.cts_data; const char *base = dmp->dm_strtab.cts_data; size_t ss_size = dmp->dm_strtab.cts_size; @@ -76,7 +78,7 @@ dt_module_syminit32(dt_module_t *dmp) const char *name = base + sym->st_name; uchar_t type = ELF32_ST_TYPE(sym->st_info); - if (type >= STT_NUM || type == STT_SECTION) + if (type >= STT_IFUNC || type == STT_SECTION) continue; /* skip sections and unknown types */ if (sym->st_name == 0 || sym->st_name >= ss_size) @@ -95,6 +97,10 @@ dt_module_syminit32(dt_module_t *dmp) static uint_t dt_module_syminit64(dt_module_t *dmp) { +#if STT_NUM != (STT_IFUNC + 1) +#error "STT_NUM has grown. update dt_module_syminit64()" +#endif + const Elf64_Sym *sym = dmp->dm_symtab.cts_data; const char *base = dmp->dm_strtab.cts_data; size_t ss_size = dmp->dm_strtab.cts_size; @@ -105,7 +111,7 @@ dt_module_syminit64(dt_module_t *dmp) const char *name = base + sym->st_name; uchar_t type = ELF64_ST_TYPE(sym->st_info); - if (type >= STT_NUM || type == STT_SECTION) + if (type >= STT_IFUNC || type == STT_SECTION) continue; /* skip sections and unknown types */ if (sym->st_name == 0 || sym->st_name >= ss_size) diff --git a/usr/src/lib/libproc/common/Psymtab.c b/usr/src/lib/libproc/common/Psymtab.c index 0a5c3dedd1..c279bdcd6a 100644 --- a/usr/src/lib/libproc/common/Psymtab.c +++ b/usr/src/lib/libproc/common/Psymtab.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -2753,6 +2753,10 @@ static int Psymbol_iter_com(struct ps_prochandle *P, Lmid_t lmid, const char *object_name, int which, int mask, pr_order_t order, proc_xsym_f *func, void *cd) { +#if STT_NUM != (STT_IFUNC + 1) +#error "STT_NUM has grown. update Psymbol_iter_com()" +#endif + GElf_Sym sym; GElf_Shdr shdr; map_info_t *mptr; @@ -2833,11 +2837,11 @@ Psymbol_iter_com(struct ps_prochandle *P, Lmid_t lmid, const char *object_name, * In case you haven't already guessed, this relies on * the bitmask used in <libproc.h> for encoding symbol * type and binding matching the order of STB and STT - * constants in <sys/elf.h>. ELF can't change without - * breaking binary compatibility, so I think this is + * constants in <sys/elf.h>. Changes to ELF must + * maintain binary compatibility, so I think this is * reasonably fair game. */ - if (s_bind < STB_NUM && s_type < STT_NUM) { + if (s_bind < STB_NUM && s_type < STT_IFUNC) { type = (1 << (s_type + 8)) | (1 << s_bind); if ((type & ~mask) != 0) continue; diff --git a/usr/src/uts/common/sys/elf.h b/usr/src/uts/common/sys/elf.h index 903af2e47c..bac5afceb4 100644 --- a/usr/src/uts/common/sys/elf.h +++ b/usr/src/uts/common/sys/elf.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -322,13 +322,22 @@ typedef struct { #define PT_LOOS 0x60000000 /* OS specific range */ /* - * Note: The amd64 psABI defines that the UNWIND program header - * should reside in the OS specific range of the program - * headers. + * PT_SUNW_UNWIND and PT_SUNW_EH_FRAME perform the same function, + * providing access to the .eh_frame_hdr section of the object. + * PT_SUNW_UNWIND is the original value, while PT_SUNW_EH_FRAME is + * required by the amd64 psABI. The Solaris link-editor (ld) tags output + * objects with PT_SUNW_UNWIND, but the Solaris runtime linker (ld.so.1) + * will accept and use either value. */ -#define PT_SUNW_UNWIND 0x6464e550 /* amd64 UNWIND program header */ -#define PT_GNU_EH_FRAME PT_SUNW_UNWIND +#define PT_SUNW_UNWIND 0x6464e550 +#define PT_SUNW_EH_FRAME 0x6474e550 +#define PT_GNU_EH_FRAME PT_SUNW_EH_FRAME +/* + * Linux specific program headers not currently used by Solaris + */ +#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ +#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ #define PT_LOSUNW 0x6ffffffa #define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment (unused) */ @@ -421,15 +430,24 @@ typedef struct { #define SHT_SUNW_COMDAT 0x6ffffffb #define SHT_SUNW_syminfo 0x6ffffffc #define SHT_SUNW_verdef 0x6ffffffd +#define SHT_GNU_verdef SHT_SUNW_verdef #define SHT_SUNW_verneed 0x6ffffffe +#define SHT_GNU_verneed SHT_SUNW_verneed #define SHT_SUNW_versym 0x6fffffff +#define SHT_GNU_versym SHT_SUNW_versym #define SHT_HISUNW 0x6fffffff #define SHT_HIOS 0x6fffffff -/* GNU/Linux ABI specific values */ -#define SHT_GNU_verdef 0x6ffffffd -#define SHT_GNU_verneed 0x6ffffffe -#define SHT_GNU_versym 0x6fffffff +/* + * GNU/Linux OSABI specific values with different meanings than under Solaris. + * Due to the overlap in assigned values with the Solaris OSABI, correct + * interpretation of these values requires knowledge of the OSABI used by + * the object. + */ +#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes */ +#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table */ +#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ +#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content */ #define SHT_LOPROC 0x70000000 /* processor specific range */ #define SHT_HIPROC 0x7fffffff @@ -520,15 +538,17 @@ typedef struct { #define STB_LOPROC 13 /* processor specific range */ #define STB_HIPROC 15 -#define STT_NOTYPE 0 /* TYPE */ -#define STT_OBJECT 1 -#define STT_FUNC 2 -#define STT_SECTION 3 -#define STT_FILE 4 -#define STT_COMMON 5 -#define STT_TLS 6 -#define STT_NUM 7 - +#define STT_NOTYPE 0 /* symbol type is unspecified */ +#define STT_OBJECT 1 /* data object */ +#define STT_FUNC 2 /* code object */ +#define STT_SECTION 3 /* symbol identifies an ELF section */ +#define STT_FILE 4 /* symbol's name is file name */ +#define STT_COMMON 5 /* common data object */ +#define STT_TLS 6 /* thread-local data object */ +#define STT_IFUNC 7 /* indirect code object (unused) */ +#define STT_NUM 8 /* # defined types in generic range */ +#define STT_LOOS 10 /* OS specific range */ +#define STT_HIOS 12 #define STT_LOPROC 13 /* processor specific range */ #define STT_HIPROC 15 diff --git a/usr/src/uts/common/sys/link.h b/usr/src/uts/common/sys/link.h index 597bc24baa..9d5401da2f 100644 --- a/usr/src/uts/common/sys/link.h +++ b/usr/src/uts/common/sys/link.h @@ -23,7 +23,7 @@ * Copyright (c) 1988 AT&T * All Rights Reserved * - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -172,6 +172,10 @@ typedef struct { * Dyn.d_un.d_val field of the Elf*_Dyn structure. */ #define DT_VALRNGLO 0x6ffffd00 + +#define DT_GNU_PRELINKED 0x6ffffdf5 /* prelinking timestamp (unused) */ +#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* size of conflict section (unused) */ +#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* size of library list (unused) */ #define DT_CHECKSUM 0x6ffffdf8 /* elf checksum */ #define DT_PLTPADSZ 0x6ffffdf9 /* pltpadding size */ #define DT_MOVEENT 0x6ffffdfa /* move table entry size */ @@ -192,6 +196,13 @@ typedef struct { * built, these entries will need to be adjusted. */ #define DT_ADDRRNGLO 0x6ffffe00 + +#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table (unused) */ +#define DT_TLSDESC_PLT 0x6ffffef6 /* GNU (unused) */ +#define DT_TLSDESC_GOT 0x6ffffef7 /* GNU (unused) */ +#define DT_GNU_CONFLICT 0x6ffffef8 /* start of conflict section (unused) */ +#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list (unused) */ + #define DT_CONFIG 0x6ffffefa /* configuration information */ #define DT_DEPAUDIT 0x6ffffefb /* dependency auditing */ #define DT_AUDIT 0x6ffffefc /* object auditing */ |