changeset 9085:ff7eb0bace56

6813909 generalize eh_frame support to non-amd64 platforms
author Ali Bahrami <Ali.Bahrami@Sun.COM>
date Wed, 18 Mar 2009 13:28:28 -0600
parents 8d7e237edfe9
children d01fbcc0eff6
files usr/src/cmd/mdb/common/mdb/mdb_gelf.c usr/src/cmd/mdb/common/mdb/mdb_target.c usr/src/cmd/sgs/elfdump/Makefile.com usr/src/cmd/sgs/elfdump/common/_elfdump.h usr/src/cmd/sgs/elfdump/common/dwarf.c usr/src/cmd/sgs/elfdump/common/elfdump.c usr/src/cmd/sgs/elfdump/common/elfdump.msg usr/src/cmd/sgs/elfdump/common/fake_shdr.c usr/src/cmd/sgs/elfdump/common/main.c usr/src/cmd/sgs/elfedit/common/elfconst.c usr/src/cmd/sgs/elfedit/common/elfedit.msg usr/src/cmd/sgs/include/conv.h usr/src/cmd/sgs/include/dwarf.h usr/src/cmd/sgs/include/i386/machdep_x86.h usr/src/cmd/sgs/include/libld.h usr/src/cmd/sgs/include/sparc/machdep_sparc.h usr/src/cmd/sgs/libconv/Makefile.com usr/src/cmd/sgs/libconv/common/dwarf.c usr/src/cmd/sgs/libconv/common/dwarf.msg usr/src/cmd/sgs/libconv/common/phdr.c usr/src/cmd/sgs/libconv/common/phdr.msg usr/src/cmd/sgs/libconv/common/symbols.c usr/src/cmd/sgs/libconv/common/symbols.msg usr/src/cmd/sgs/libelf/demo/dispsyms.c usr/src/cmd/sgs/libld/Makefile.com usr/src/cmd/sgs/libld/common/README.XLINK usr/src/cmd/sgs/libld/common/_libld.h usr/src/cmd/sgs/libld/common/entry.c usr/src/cmd/sgs/libld/common/files.c usr/src/cmd/sgs/libld/common/globals.c usr/src/cmd/sgs/libld/common/ldmain.c usr/src/cmd/sgs/libld/common/machrel.amd.c usr/src/cmd/sgs/libld/common/machrel.intel.c usr/src/cmd/sgs/libld/common/machrel.sparc.c usr/src/cmd/sgs/libld/common/outfile.c usr/src/cmd/sgs/libld/common/sections.c usr/src/cmd/sgs/libld/common/unwind.amd.c usr/src/cmd/sgs/libld/common/unwind.amd.h usr/src/cmd/sgs/libld/common/unwind.c usr/src/cmd/sgs/libld/common/update.c usr/src/cmd/sgs/packages/common/SUNWonld-README usr/src/cmd/sgs/rtld/common/elf.c usr/src/cmd/sgs/tools/common/leb128.c usr/src/lib/libdtrace/common/dt_module.c usr/src/lib/libproc/common/Psymtab.c usr/src/uts/common/sys/elf.h usr/src/uts/common/sys/link.h
diffstat 47 files changed, 2529 insertions(+), 1388 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/mdb/common/mdb/mdb_gelf.c	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/mdb/common/mdb/mdb_gelf.c	Wed Mar 18 13:28:28 2009 -0600
@@ -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 @@
 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 @@
 		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 @@
 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 @@
 		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] > '~') {
--- a/usr/src/cmd/mdb/common/mdb/mdb_target.c	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/mdb/common/mdb/mdb_target.c	Wed Mar 18 13:28:28 2009 -0600
@@ -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 @@
 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 @@
 	 * 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);
 	}
--- a/usr/src/cmd/sgs/elfdump/Makefile.com	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/elfdump/Makefile.com	Wed Mar 18 13:28:28 2009 -0600
@@ -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
 
--- a/usr/src/cmd/sgs/elfdump/common/_elfdump.h	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/elfdump/common/_elfdump.h	Wed Mar 18 13:28:28 2009 -0600
@@ -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 @@
 #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 *);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/sgs/elfdump/common/dwarf.c	Wed Mar 18 13:28:28 2009 -0600
@@ -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;
+		}
+	}
+}
--- a/usr/src/cmd/sgs/elfdump/common/elfdump.c	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/elfdump/common/elfdump.c	Wed Mar 18 13:28:28 2009 -0600
@@ -185,7 +185,7 @@
 		/*
 		 * 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 @@
 }
 
 /*
- * 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 @@
 
 		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 @@
 		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 @@
 			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 @@
 			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 @@
 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 @@
 	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 @@
 	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 @@
 			break;
 		}
 	}
-	if (infocache == 0)
+	if (infocache == NULL)
 		return;
 
 	infoshdr = infocache->c_shdr;
@@ -976,7 +859,7 @@
 		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 @@
 
 	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 @@
 	 * 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 @@
 		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 @@
 	    &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 @@
 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 @@
 		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 @@
 	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 @@
 		(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 @@
 					    MSG_ORIG(MSG_FMT_SECSYM),
 					    EC_WORD(secsz), secname, symname);
 				}
+
 				continue;
 			}
 
@@ -3938,7 +3831,7 @@
 			return (ret);
 		}
 	} else
-		shdr = 0;
+		shdr = NULL;
 
 	/*
 	 * Print the elf header.
@@ -4083,10 +3976,15 @@
 			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 @@
 				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:
--- a/usr/src/cmd/sgs/elfdump/common/elfdump.msg	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/elfdump/common/elfdump.msg	Wed Mar 18 13:28:28 2009 -0600
@@ -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: [%#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_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_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)"
 
-@ MSG_UNW_TBLENTRY	"0x%02x "
+# Architecture specific register name formats
+
+@ MSG_REG_FMT_BASIC	"r%d"
+@ MSG_REG_FMT_NAME	"r%d (%s)"
+
 
 # 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
--- a/usr/src/cmd/sgs/elfdump/common/fake_shdr.c	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/elfdump/common/fake_shdr.c	Wed Mar 18 13:28:28 2009 -0600
@@ -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 @@
 			break;
 
 		case PT_SUNW_UNWIND:
+		case PT_SUNW_EH_FRAME:
 			sec.unwind.type = SINFO_T_UNWIND;
 			sinfo = &sec.unwind;
 			break;
--- a/usr/src/cmd/sgs/elfdump/common/main.c	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/elfdump/common/main.c	Wed Mar 18 13:28:28 2009 -0600
@@ -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 @@
 	{ 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 @@
  *	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 @@
 	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 @@
 {
 	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 @@
 				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;
--- a/usr/src/cmd/sgs/elfedit/common/elfconst.c	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/elfedit/common/elfconst.c	Wed Mar 18 13:28:28 2009 -0600
@@ -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 @@
 	{ 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 },
 
--- a/usr/src/cmd/sgs/elfedit/common/elfedit.msg	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/elfedit/common/elfedit.msg	Wed Mar 18 13:28:28 2009 -0600
@@ -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
--- a/usr/src/cmd/sgs/include/conv.h	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/include/conv.h	Wed Mar 18 13:28:28 2009 -0600
@@ -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_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 *);
--- a/usr/src/cmd/sgs/include/dwarf.h	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/include/dwarf.h	Wed Mar 18 13:28:28 2009 -0600
@@ -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 @@
 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
 }
--- a/usr/src/cmd/sgs/include/i386/machdep_x86.h	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/include/i386/machdep_x86.h	Wed Mar 18 13:28:28 2009 -0600
@@ -267,24 +267,25 @@
 
 #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 */
 
--- a/usr/src/cmd/sgs/include/libld.h	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/include/libld.h	Wed Mar 18 13:28:28 2009 -0600
@@ -201,10 +201,8 @@
 	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 @@
 #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
--- a/usr/src/cmd/sgs/include/sparc/machdep_sparc.h	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/include/sparc/machdep_sparc.h	Wed Mar 18 13:28:28 2009 -0600
@@ -271,16 +271,19 @@
 
 #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 @@
 #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 */
 
--- a/usr/src/cmd/sgs/libconv/Makefile.com	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/libconv/Makefile.com	Wed Mar 18 13:28:28 2009 -0600
@@ -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 @@
 		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
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/sgs/libconv/common/dwarf.c	Wed Mar 18 13:28:28 2009 -0600
@@ -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));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/sgs/libconv/common/dwarf.msg	Wed Mar 18 13:28:28 2009 -0600
@@ -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	"]"
--- a/usr/src/cmd/sgs/libconv/common/phdr.c	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/libconv/common/phdr.c	Wed Mar 18 13:28:28 2009 -0600
@@ -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 @@
 			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 @@
 		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));
 }
--- a/usr/src/cmd/sgs/libconv/common/phdr.msg	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/libconv/common/phdr.msg	Wed Mar 18 13:28:28 2009 -0600
@@ -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"
--- a/usr/src/cmd/sgs/libconv/common/symbols.c	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/libconv/common/symbols.c	Wed Mar 18 13:28:28 2009 -0600
@@ -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 @@
 		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) {
--- a/usr/src/cmd/sgs/libconv/common/symbols.msg	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/libconv/common/symbols.msg	Wed Mar 18 13:28:28 2009 -0600
@@ -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"
 
--- a/usr/src/cmd/sgs/libelf/demo/dispsyms.c	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/libelf/demo/dispsyms.c	Wed Mar 18 13:28:28 2009 -0600
@@ -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 @@
 /* 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 @@
 
 	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 @@
 
 		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 @@
 		 */
 		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 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 @@
 			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 @@
 				    (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 @@
 				typestr = symtype[type];
 			else {
 				(void) snprintf(typebuf, INTSTRLEN,
-					"%d", type);
+				    "%d", type);
 				typestr = typebuf;
 			}
 
@@ -235,7 +237,7 @@
 				bindstr = symbind[bind];
 			else {
 				(void) snprintf(bindbuf, INTSTRLEN,
-					"%d", bind);
+				    "%d", bind);
 				bindstr = bindbuf;
 			}
 
@@ -261,12 +263,12 @@
 					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 @@
 			 * 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 @@
 			 * '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 @@
 	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 @@
 	 */
 	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);
 	}
 
--- a/usr/src/cmd/sgs/libld/Makefile.com	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/libld/Makefile.com	Wed Mar 18 13:28:28 2009 -0600
@@ -33,14 +33,14 @@
 		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 @@
 # 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
--- a/usr/src/cmd/sgs/libld/common/README.XLINK	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/libld/common/README.XLINK	Wed Mar 18 13:28:28 2009 -0600
@@ -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 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
--- a/usr/src/cmd/sgs/libld/common/_libld.h	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/libld/common/_libld.h	Wed Mar 18 13:28:28 2009 -0600
@@ -98,6 +98,9 @@
 	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 @@
 	Word		id_tlsbss;
 	Word		id_unknown;
 	Word		id_unwind;
+	Word		id_unwindhdr;
 	Word		id_user;
 	Word		id_version;
 } Target_machid;
@@ -218,26 +222,12 @@
 	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 @@
 /*
  * 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 @@
 #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 @@
 #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 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 *);
--- a/usr/src/cmd/sgs/libld/common/entry.c	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/libld/common/entry.c	Wed Mar 18 13:28:28 2009 -0600
@@ -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 @@
 	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 @@
 	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 @@
 		switch (idx) {
 		case LD_LRODATA:
 		case LD_LDATA:
-		case LD_UNWIND:
 			if ((ld_targ.t_m.m_mach != EM_AMD64))
 				continue;
 		}
--- a/usr/src/cmd/sgs/libld/common/files.c	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/libld/common/files.c	Wed Mar 18 13:28:28 2009 -0600
@@ -555,7 +555,9 @@
 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 @@
 	 * 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 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 @@
  * 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 @@
 /* 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 @@
 					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 @@
 					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 @@
 				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 @@
 				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 @@
 					    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 @@
 			 * 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
 		}
--- a/usr/src/cmd/sgs/libld/common/globals.c	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/libld/common/globals.c	Wed Mar 18 13:28:28 2009 -0600
@@ -90,7 +90,7 @@
 		1,			/* STT_FILE */
 		0,			/* STT_COMMON */
 		0,			/* STT_TLS */
-		0,			/* 7 */
+		0,			/* STT_IFUNC */
 		0,			/* 8 */
 		0,			/* 9 */
 		0,			/* 10 */
@@ -100,7 +100,7 @@
 		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 @@
 		0,			/* STT_FILE */
 		1,			/* STT_COMMON */
 		0,			/* STT_TLS */
-		0,			/* 7 */
+		0,			/* STT_IFUNC */
 		0,			/* 8 */
 		0,			/* 9 */
 		0,			/* 10 */
@@ -127,6 +127,6 @@
 		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
--- a/usr/src/cmd/sgs/libld/common/ldmain.c	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/libld/common/ldmain.c	Wed Mar 18 13:28:28 2009 -0600
@@ -348,14 +348,11 @@
 	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.
--- a/usr/src/cmd/sgs/libld/common/machrel.amd.c	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/libld/common/machrel.amd.c	Wed Mar 18 13:28:28 2009 -0600
@@ -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 @@
 			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 @@
 			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 @@
 			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 */
 		}
 	};
 
--- a/usr/src/cmd/sgs/libld/common/machrel.intel.c	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/libld/common/machrel.intel.c	Wed Mar 18 13:28:28 2009 -0600
@@ -1670,6 +1670,9 @@
 			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 @@
 			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 @@
 			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 */
 		}
 	};
 
--- a/usr/src/cmd/sgs/libld/common/machrel.sparc.c	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/libld/common/machrel.sparc.c	Wed Mar 18 13:28:28 2009 -0600
@@ -2247,6 +2247,9 @@
 			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 @@
 			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_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 */
 		}
 	};
 
--- a/usr/src/cmd/sgs/libld/common/outfile.c	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/libld/common/outfile.c	Wed Mar 18 13:28:28 2009 -0600
@@ -456,12 +456,9 @@
 			} 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++;
--- a/usr/src/cmd/sgs/libld/common/sections.c	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/libld/common/sections.c	Wed Mar 18 13:28:28 2009 -0600
@@ -2771,11 +2771,8 @@
 				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);
 		}
--- a/usr/src/cmd/sgs/libld/common/unwind.amd.c	Wed Mar 18 11:09:59 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,767 +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 2009 Sun Microsystems, Inc.  All rights reserved.
- * 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:
- *
- *	Encoding	Field
- *	--------------------------------
- *	unsigned byte	version
- *	unsigned byte	eh_frame_ptr_enc
- *	unsigned byte	fde_count_enc
- *	unsigned byte	table_enc
- *	encoded		eh_frame_ptr
- *	encoded		fde_count
- *	[ binary search table ]
- *
- * The binary search table entries each consists of:
- *
- *	encoded		initial_func_loc
- *	encoded		FDE_address
- *
- * The entries in the binary search table are sorted
- * in a increasing order by the initial location.
- *
- *
- * version
- *
- *   Version of the .eh_frame_hdr format. This value shall be 1.
- *
- * eh_frame_ptr_enc
- *
- *    The encoding format of the eh_frame_ptr field.  For shared
- *    libraries the encoding must be
- *    DW_EH_PE_sdata4|DW_EH_PE_pcrel or
- *    DW_EH_PE_sdata4|DW_EH_PE_datarel.
- *
- *
- * fde_count_enc
- *
- *    The encoding format of the fde_count field. A value of
- *    DW_EH_PE_omit indicates the binary search table is not
- *    present.
- *
- * table_enc
- *
- *    The encoding format of the entries in the binary search
- *    table. A value of DW_EH_PE_omit indicates the binary search
- *    table is not present. For shared libraries the encoding
- *    must be DW_EH_PE_sdata4|DW_EH_PE_pcrel or
- *    DW_EH_PE_sdata4|DW_EH_PE_datarel.
- *
- *
- * eh_frame_ptr
- *
- *    The encoded value of the pointer to the start of the
- *    .eh_frame section.
- *
- * fde_count
- *
- *    The encoded value of the count of entries in the binary
- *    search table.
- *
- * binary search table
- *
- *    A binary search table containing fde_count entries. Each
- *    entry of the table consist of two encoded values, the
- *    initial location of the function to which an FDE applies,
- *    and the address of the FDE. The entries are sorted in an
- *    increasing order by the initial location value.
- *
- */
-
-
-/*
- * EH_FRAME sections
- * =================
- *
- * 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
- * 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
- * a separate CIE immediately preceding each FDE corresponding to an
- * instantiation.
- *
- * Using the preferred encoding specified below, the .eh_frame section can
- * be entirely resolved at link time and thus can become part of the
- * text segment.
- *
- * .eh_frame Section Layout
- * ------------------------
- *
- * EH_PE encoding below refers to the pointer encoding as specified in the
- * enhanced LSB Chapter 7 for Eh_Frame_Hdr.
- *
- * Common Information Entry (CIE)
- * ------------------------------
- * CIE has the following format:
- *
- *                           Length
- *                              in
- *     Field                   Byte      Description
- *     -----                  ------     -----------
- *  1. Length                   4        Length of CIE (not including
- *					 this 4-byte field).
- *
- *  2. CIE id                   4        Value Zero (0) for .eh_frame
- *					 (used to distinguish CIEs and
- *					 FDEs when scanning the section)
- *
- *  3. Version                  1        Value One (1)
- *
- *  4. CIE Augmentation       string     Null-terminated string with legal
- *					 values being "" or 'z' optionally
- *					 followed by single occurrances of
- *					 'P', 'L', or 'R' in any order.
- *     String                            The presence of character(s) in the
- *                                       string dictates the content of
- *                                       field 8, the Augmentation Section.
- *					 Each character has one or two
- *					 associated operands in the AS.
- *					 Operand order depends on
- *					 position in the string ('z' must
- *					 be first).
- *
- *  5. Code Align Factor      uleb128    To be multiplied with the
- *					 "Advance Location" instructions in
- *                                       the Call Frame Instructions
- *
- *  6. Data Align Factor      sleb128    To be multiplied with all offset
- *                                       in the Call Frame Instructions
- *
- *  7. Ret Address Reg          1        A "virtual" register representation
- *                                       of the return address. In Dwarf V2,
- *                                       this is a byte, otherwise it is
- *                                       uleb128. It is a byte in gcc 3.3.x
- *
- *  8. Optional CIE           varying    Present if Augmentation String in
- *     Augmentation Section              field 4 is not 0.
- *
- *     z:
- * 	size		   uleb128       Length of the remainder of the
- *				         Augmentation Section
- *
- *     P:
- * 	personality_enc    1	         Encoding specifier - preferred
- *					 value is a pc-relative, signed
- *				         4-byte
- *
- *
- *        personality routine (encoded)  Encoded pointer to personality
- *					 routine (actually to the PLT
- *				         entry for the personality
- *				         routine)
- *     R:
- * 	code_enc           1	      Non-default encoding for the
- *				      code-pointers (FDE members
- *				      "initial_location" and "address_range"
- *				      and the operand for DW_CFA_set_loc)
- *				      - preferred value is pc-relative,
- *				      signed 4-byte.
- *     L:
- * 	lsda_enc	   1	      FDE augmentation bodies may contain
- *				      LSDA pointers. If so they are
- *				      encoded as specified here -
- *				      preferred value is pc-relative,
- *				      signed 4-byte possibly indirect
- *				      thru a GOT entry.
- *
- *
- *  9. Optional Call Frame varying
- *     Instructions
- *
- * The size of the optional call frame instruction area must be computed
- * based on the overall size and the offset reached while scanning the
- * preceding fields of the CIE.
- *
- *
- * Frame Descriptor Entry (FDE)
- * ----------------------------
- * FDE has the following format:
- *
- *                            Length
- *                              in
- *     Field                   Byte      Description
- *     -----                  ------     -----------
- *  1. Length                   4        Length of remainder of this FDE
- *
- *  2. CIE Pointer              4        Distance from this field to the
- *				         nearest preceding CIE
- *				         (uthe value is subtracted from the
- *					 current address). This value
- *				         can never be zero and thus can
- *				         be used to distinguish CIE's and
- *				         FDE's when scanning the
- *				         .eh_frame section
- *
- *  3. Initial Location       varying    Reference to the function code
- *                                       corresponding to this FDE.
- *                                       If 'R' is missing from the CIE
- *                                       Augmentation String, the field is an
- *                                       8-byte absolute pointer. Otherwise,
- *                                       the corresponding EH_PE encoding in the
- *                                       CIE Augmentation Section is used to
- *                                       interpret the reference.
- *
- *  4. Address Range          varying    Size of the function code corresponding
- *                                       to this FDE.
- *                                       If 'R' is missing from the CIE
- *                                       Augmentation String, the field is an
- *                                       8-byte unsigned number. Otherwise,
- *                                       the size is determined by the
- *				         corresponding EH_PE encoding in the
- *                                       CIE Augmentation Section (the
- *				         value is always absolute).
- *
- *  5. Optional FDE           varying    present if CIE augmentation
- *     Augmentation Section	         string is non-empty.
- *
- *
- *     'z':
- * 	length		   uleb128       length of the remainder of the
- *				         FDE augmentation section
- *
- *
- *     'L' (and length > 0):
- *         LSDA               varying    LSDA pointer, encoded in the
- *				         format specified by the
- *				         corresponding operand in the CIE's
- *				         augmentation body.
- *
- *  6. Optional Call          varying
- *     Frame Instructions
- *
- * The size of the optional call frame instruction area must be computed
- * based on the overall size and the offset reached while scanning the
- * preceding fields of the FDE.
- *
- * The overall size of a .eh_frame section is given in the ELF section
- * header.  The only way to determine the number of entries is to scan
- * the section till the end and count.
- *
- */
-
-
-
-
-/*
- * The job of this function is to determine how much space
- * will be required for the final table.  We'll build
- * it later.
- *
- * 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
- * section. Ideally, we would remove these dead entries from eh_frame.
- * However, that optimization has not yet been implemented. In the current
- * implementation, the number of dead FDEs cannot be determined until
- * active relocations are processed, and that processing follows the
- * call to this function. This means that we are unable to detect dead FDEs
- * here, and the section created by this routine is sized for maximum case
- * where all FDEs are valid.
- */
-uintptr_t
-make_amd64_unwindhdr(Ofl_desc *ofl)
-{
-	Shdr		*shdr;
-	Elf_Data	*elfdata;
-	Is_desc		*isp;
-	size_t		size;
-	Xword		fde_cnt;
-	Listnode	*lnp;
-	Os_desc		*osp;
-
-	/*
-	 * we only build a unwind header if we have
-	 * some unwind information in the file.
-	 */
-	if (ofl->ofl_unwind.head == NULL)
-		return (1);
-
-	/*
-	 * Allocate and initialize the Elf_Data structure.
-	 */
-	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_version = ofl->ofl_dehdr->e_version;
-
-	/*
-	 * Allocate and initialize the Shdr structure.
-	 */
-	if ((shdr = libld_calloc(sizeof (Shdr), 1)) == 0)
-		return (S_ERROR);
-	shdr->sh_type = SHT_AMD64_UNWIND;
-	shdr->sh_flags = SHF_ALLOC;
-	shdr->sh_addralign = M_WORD_ALIGN;
-	shdr->sh_entsize = 0;
-
-	/*
-	 * Allocate and initialize the Is_desc structure.
-	 */
-	if ((isp = libld_calloc(1, sizeof (Is_desc))) == 0)
-		return (S_ERROR);
-	isp->is_name = MSG_ORIG(MSG_SCN_UNWINDHDR);
-	isp->is_shdr = shdr;
-	isp->is_indata = elfdata;
-
-	if ((ofl->ofl_unwindhdr = ld_place_section(ofl, isp,
-	    M_ID_UNWINDHDR, 0)) == (Os_desc *)S_ERROR)
-		return (S_ERROR);
-
-	/*
-	 * Scan through all of the input Frame information, counting each FDE
-	 * that requires an index.  Each fde_entry gets a corresponding entry
-	 * in the binary search table.
-	 */
-	fde_cnt = 0;
-	for (LIST_TRAVERSE(&ofl->ofl_unwind, lnp, osp)) {
-		Listnode    *_lnp;
-
-		for (LIST_TRAVERSE(&osp->os_isdescs, _lnp, isp)) {
-			uchar_t		*data;
-			uint64_t	off = 0;
-
-			data = isp->is_indata->d_buf;
-			size = isp->is_indata->d_size;
-
-			while (off < size) {
-				uint_t		length, id;
-				uint64_t	ndx;
-
-				/*
-				 * Extract length in lsb format.  A zero length
-				 * indicates that this CIE is a terminator and
-				 * that processing for unwind information is
-				 * complete.
-				 */
-				if ((length = LSB32EXTRACT(data + off)) == 0)
-					break;
-
-				/*
-				 * Extract CIE id in lsb format.
-				 */
-				ndx = 4;
-				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) {
-					uint_t	cieversion;
-					/*
-					 * The only CIE version supported
-					 * is '1' - quick sanity check
-					 * here.
-					 */
-					cieversion = data[off + ndx];
-					ndx += 1;
-					/* BEGIN CSTYLED */
-					if (cieversion != 1) {
-					    eprintf(ofl->ofl_lml, ERR_FATAL,
-						MSG_INTL(MSG_UNW_BADCIEVERS),
-						isp->is_file->ifl_name,
-						isp->is_name, off);
-					    return (S_ERROR);
-					}
-					/* END CSTYLED */
-				} else {
-					fde_cnt++;
-				}
-				off += length + 4;
-			}
-		}
-	}
-
-	/*
-	 * section size:
-	 *	byte	    version		+1
-	 *	byte	    eh_frame_ptr_enc	+1
-	 *	byte	    fde_count_enc	+1
-	 *	byte	    table_enc		+1
-	 *	4 bytes	    eh_frame_ptr	+4
-	 *	4 bytes	    fde_count		+4
-	 *	[4 bytes] [4bytes] * fde_count	...
-	 */
-	size = 12 + (8 * fde_cnt);
-
-	if ((elfdata->d_buf = libld_calloc(size, 1)) == 0)
-		return (S_ERROR);
-	elfdata->d_size = size;
-	shdr->sh_size = (Xword)size;
-
-	return (1);
-}
-
-/*
- * the comparator function needs to calculate
- * the actual 'initloc' of a bintab entry - to
- * do this we initialize the following global to point
- * to it.
- */
-static Addr framehdr_addr;
-
-static int
-bintabcompare(const void *p1, const void *p2)
-{
-	uint_t	    *bintab1, *bintab2;
-	uint_t	    ent1, ent2;
-
-	bintab1 = (uint_t *)p1;
-	bintab2 = (uint_t *)p2;
-
-	assert(bintab1 != 0);
-	assert(bintab2 != 0);
-
-	ent1 = *bintab1 + framehdr_addr;
-	ent2 = *bintab2 + framehdr_addr;
-
-	if (ent1 > ent2)
-		return (1);
-	if (ent1 < ent2)
-		return (-1);
-	return (0);
-}
-
-uintptr_t
-populate_amd64_unwindhdr(Ofl_desc *ofl)
-{
-	uchar_t		*hdrdata;
-	uint_t		*binarytable;
-	uint_t		hdroff;
-	Listnode	*lnp;
-	Addr		hdraddr;
-	Os_desc		*hdrosp;
-	Os_desc		*osp;
-	Os_desc		*first_unwind;
-	uint_t		fde_count;
-	uint_t		*uint_ptr;
-	int		bswap = (ofl->ofl_flags1 & FLG_OF1_ENCDIFF) != 0;
-
-	/*
-	 * Are we building the unwind hdr?
-	 */
-	if ((hdrosp = ofl->ofl_unwindhdr) == 0)
-		return (1);
-
-	hdrdata = hdrosp->os_outdata->d_buf;
-	hdraddr = hdrosp->os_shdr->sh_addr;
-	hdroff = 0;
-
-	/*
-	 * version == 1
-	 */
-	hdrdata[hdroff++] = 1;
-	/*
-	 * The encodings are:
-	 *
-	 *  eh_frameptr_enc	sdata4 | pcrel
-	 *  fde_count_enc	udata4
-	 *  table_enc		sdata4 | datarel
-	 */
-	hdrdata[hdroff++] = DW_EH_PE_sdata4 | DW_EH_PE_pcrel;
-	hdrdata[hdroff++] = DW_EH_PE_udata4;
-	hdrdata[hdroff++] = DW_EH_PE_sdata4 | DW_EH_PE_datarel;
-
-	/*
-	 *	Header Offsets
-	 *	-----------------------------------
-	 *	byte	    version		+1
-	 *	byte	    eh_frame_ptr_enc	+1
-	 *	byte	    fde_count_enc	+1
-	 *	byte	    table_enc		+1
-	 *	4 bytes	    eh_frame_ptr	+4
-	 *	4 bytes	    fde_count		+4
-	 */
-	/* LINTED */
-	binarytable =  (uint_t *)(hdrdata + 12);
-	first_unwind = 0;
-	fde_count = 0;
-
-	for (LIST_TRAVERSE(&ofl->ofl_unwind, lnp, osp)) {
-		uchar_t		*data;
-		size_t		size;
-		uint64_t	off = 0;
-		uint_t		cieRflag = 0, ciePflag = 0;
-		Shdr		*shdr;
-
-		/*
-		 * remember first UNWIND section to
-		 * point to in the frame_ptr entry.
-		 */
-		if (first_unwind == 0)
-			first_unwind = osp;
-
-		data = osp->os_outdata->d_buf;
-		shdr = osp->os_shdr;
-		size = shdr->sh_size;
-
-		while (off < size) {
-			uint_t	    length, id;
-			uint64_t    ndx;
-
-			/*
-			 * 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)
-				goto done;
-
-			/*
-			 * Extract CIE id in lsb format.
-			 */
-			ndx = 4;
-			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) {
-				char	*cieaugstr;
-				uint_t	cieaugndx;
-
-				ciePflag = 0;
-				cieRflag = 0;
-				/*
-				 * We need to drill through the CIE
-				 * to find the Rflag.  It's the Rflag
-				 * which describes how the FDE code-pointers
-				 * are encoded.
-				 */
-
-				/*
-				 * burn through version
-				 */
-				ndx++;
-
-				/*
-				 * augstr
-				 */
-				cieaugstr = (char *)(&data[off + ndx]);
-				ndx += strlen(cieaugstr) + 1;
-
-				/*
-				 * calign & dalign
-				 */
-				(void) uleb_extract(&data[off], &ndx);
-				(void) sleb_extract(&data[off], &ndx);
-
-				/*
-				 * retreg
-				 */
-				ndx++;
-
-				/*
-				 * we walk through the augmentation
-				 * section now looking for the Rflag
-				 */
-				for (cieaugndx = 0; cieaugstr[cieaugndx];
-				    cieaugndx++) {
-					/* BEGIN CSTYLED */
-					switch (cieaugstr[cieaugndx]) {
-					case 'z':
-					    /* size */
-					    (void) uleb_extract(&data[off],
-						&ndx);
-					    break;
-					case 'P':
-					    /* personality */
-					    ciePflag = data[off + ndx];
-					    ndx++;
-						/*
-						 * Just need to extract the
-						 * value to move on to the next
-						 * field.
-						 */
-					    (void) dwarf_ehe_extract(
-						&data[off + ndx],
-						&ndx, ciePflag,
-						ofl->ofl_dehdr->e_ident,
-						shdr->sh_addr + off + ndx);
-					    break;
-					case 'R':
-					    /* code encoding */
-					    cieRflag = data[off + ndx];
-					    ndx++;
-					    break;
-					case 'L':
-					    /* lsda encoding */
-					    ndx++;
-					    break;
-					}
-					/* END CSTYLED */
-				}
-			} else {
-				uint_t	    bintabndx;
-				uint64_t    initloc;
-				uint64_t    fdeaddr;
-
-				initloc = dwarf_ehe_extract(&data[off],
-				    &ndx, cieRflag, ofl->ofl_dehdr->e_ident,
-				    shdr->sh_addr + off + ndx);
-
-				/*
-				 * Ignore FDEs with initloc set to 0.
-				 * initloc will not be 0 unless this FDE was
-				 * abandoned due to GNU linkonce processing.
-				 * The 0 value occurs because we don't resolve
-				 * sloppy relocations for unwind header target
-				 * sections.
-				 */
-				if (initloc != 0) {
-					bintabndx = fde_count * 2;
-					fde_count++;
-
-					/*
-					 * FDEaddr is adjusted
-					 * to account for the length & id which
-					 * have already been consumed.
-					 */
-					fdeaddr = shdr->sh_addr + off;
-
-					binarytable[bintabndx] =
-					    (uint_t)(initloc - hdraddr);
-					binarytable[bintabndx + 1] =
-					    (uint_t)(fdeaddr - hdraddr);
-				}
-			}
-
-			/*
-			 * the length does not include the length
-			 * itself - so account for that too.
-			 */
-			off += length + 4;
-		}
-	}
-
-done:
-	/*
-	 * Do a quick sort 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.
-	 */
-	framehdr_addr = hdraddr;
-	qsort((void *)binarytable, (size_t)fde_count,
-	    (size_t)(sizeof (uint_t) * 2), bintabcompare);
-	if (bswap) {
-		uint_t	*btable = binarytable;
-		uint_t	cnt;
-
-		for (cnt = fde_count * 2; cnt-- > 0; btable++)
-			*btable = ld_bswap_Word(*btable);
-	}
-
-	/*
-	 * Fill in:
-	 *	first_frame_ptr
-	 *	fde_count
-	 */
-	hdroff = 4;
-	/* LINTED */
-	uint_ptr = (uint_t *)(&hdrdata[hdroff]);
-	*uint_ptr = first_unwind->os_shdr->sh_addr -
-	    hdrosp->os_shdr->sh_addr + hdroff;
-	if (bswap)
-		*uint_ptr = ld_bswap_Word(*uint_ptr);
-
-	hdroff += 4;
-	/* LINTED */
-	uint_ptr = (uint_t *)&hdrdata[hdroff];
-	*uint_ptr = fde_count;
-	if (bswap)
-		*uint_ptr = ld_bswap_Word(*uint_ptr);
-
-	/*
-	 * 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.
-	 *
-	 * 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.
-	 */
-	if (ofl->ofl_flags1 & FLG_OF1_RLXREL) {
-		Word	phnum = ofl->ofl_nehdr->e_phnum;
-		Phdr	*phdr = ofl->ofl_phdr;
-
-		for (; phnum-- > 0; phdr++) {
-			if (phdr->p_type == PT_SUNW_UNWIND) {
-				phdr->p_memsz = 12 + (8 * fde_count);
-				phdr->p_filesz = phdr->p_memsz;
-				break;
-			}
-		}
-	}
-
-	return (1);
-}
-
-uintptr_t
-append_amd64_unwind(Os_desc *osp, Ofl_desc * ofl)
-{
-	Listnode    *lnp;
-	Os_desc	    *_osp;
-	/*
-	 * Check to see if this output section is already
-	 * on the list.
-	 */
-	for (LIST_TRAVERSE(&ofl->ofl_unwind, lnp, _osp))
-		if (osp == _osp)
-			return (1);
-
-	/*
-	 * Append output section to unwind list
-	 */
-	if (list_appendc(&ofl->ofl_unwind, osp) == 0)
-		return (S_ERROR);
-	return (1);
-}
--- a/usr/src/cmd/sgs/libld/common/unwind.amd.h	Wed Mar 18 11:09:59 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/sgs/libld/common/unwind.c	Wed Mar 18 13:28:28 2009 -0600
@@ -0,0 +1,791 @@
+/*
+ * 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	<string.h>
+#include	<stdio.h>
+#include	<sys/types.h>
+#include	<sgs.h>
+#include	<debug.h>
+#include	<_libld.h>
+#include	<dwarf.h>
+#include	<stdlib.h>
+
+/*
+ * A EH_FRAME_HDR consists of the following:
+ *
+ *	Encoding	Field
+ *	--------------------------------
+ *	unsigned byte	version
+ *	unsigned byte	eh_frame_ptr_enc
+ *	unsigned byte	fde_count_enc
+ *	unsigned byte	table_enc
+ *	encoded		eh_frame_ptr
+ *	encoded		fde_count
+ *	[ binary search table ]
+ *
+ * The binary search table entries each consists of:
+ *
+ *	encoded		initial_func_loc
+ *	encoded		FDE_address
+ *
+ * The entries in the binary search table are sorted
+ * in a increasing order by the initial location.
+ *
+ *
+ * version
+ *
+ *   Version of the .eh_frame_hdr format. This value shall be 1.
+ *
+ * eh_frame_ptr_enc
+ *
+ *    The encoding format of the eh_frame_ptr field.  For shared
+ *    libraries the encoding must be
+ *    DW_EH_PE_sdata4|DW_EH_PE_pcrel or
+ *    DW_EH_PE_sdata4|DW_EH_PE_datarel.
+ *
+ *
+ * fde_count_enc
+ *
+ *    The encoding format of the fde_count field. A value of
+ *    DW_EH_PE_omit indicates the binary search table is not
+ *    present.
+ *
+ * table_enc
+ *
+ *    The encoding format of the entries in the binary search
+ *    table. A value of DW_EH_PE_omit indicates the binary search
+ *    table is not present. For shared libraries the encoding
+ *    must be DW_EH_PE_sdata4|DW_EH_PE_pcrel or
+ *    DW_EH_PE_sdata4|DW_EH_PE_datarel.
+ *
+ *
+ * eh_frame_ptr
+ *
+ *    The encoded value of the pointer to the start of the
+ *    .eh_frame section.
+ *
+ * fde_count
+ *
+ *    The encoded value of the count of entries in the binary
+ *    search table.
+ *
+ * binary search table
+ *
+ *    A binary search table containing fde_count entries. Each
+ *    entry of the table consist of two encoded values, the
+ *    initial location of the function to which an FDE applies,
+ *    and the address of the FDE. The entries are sorted in an
+ *    increasing order by the initial location value.
+ *
+ */
+
+
+/*
+ * EH_FRAME sections
+ * =================
+ *
+ * The call frame information needed for unwinding the stack is output in
+ * 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
+ * a separate CIE immediately preceding each FDE corresponding to an
+ * instantiation.
+ *
+ * Using the preferred encoding specified below, the .eh_frame section can
+ * be entirely resolved at link time and thus can become part of the
+ * text segment.
+ *
+ * .eh_frame Section Layout
+ * ------------------------
+ *
+ * EH_PE encoding below refers to the pointer encoding as specified in the
+ * enhanced LSB Chapter 7 for Eh_Frame_Hdr.
+ *
+ * Common Information Entry (CIE)
+ * ------------------------------
+ * CIE has the following format:
+ *
+ *                           Length
+ *                              in
+ *     Field                   Byte      Description
+ *     -----                  ------     -----------
+ *  1. Length                   4        Length of CIE (not including
+ *					 this 4-byte field).
+ *
+ *  2. CIE id                   4        Value Zero (0) for .eh_frame
+ *					 (used to distinguish CIEs and
+ *					 FDEs when scanning the section)
+ *
+ *  3. Version                  1        Value One (1)
+ *
+ *  4. CIE Augmentation       string     Null-terminated string with legal
+ *					 values being "" or 'z' optionally
+ *					 followed by single occurrances of
+ *					 'P', 'L', or 'R' in any order.
+ *     String                            The presence of character(s) in the
+ *                                       string dictates the content of
+ *                                       field 8, the Augmentation Section.
+ *					 Each character has one or two
+ *					 associated operands in the AS.
+ *					 Operand order depends on
+ *					 position in the string ('z' must
+ *					 be first).
+ *
+ *  5. Code Align Factor      uleb128    To be multiplied with the
+ *					 "Advance Location" instructions in
+ *                                       the Call Frame Instructions
+ *
+ *  6. Data Align Factor      sleb128    To be multiplied with all offset
+ *                                       in the Call Frame Instructions
+ *
+ *  7. Ret Address Reg          1        A "virtual" register representation
+ *                                       of the return address. In Dwarf V2,
+ *                                       this is a byte, otherwise it is
+ *                                       uleb128. It is a byte in gcc 3.3.x
+ *
+ *  8. Optional CIE           varying    Present if Augmentation String in
+ *     Augmentation Section              field 4 is not 0.
+ *
+ *     z:
+ * 	size		   uleb128       Length of the remainder of the
+ *				         Augmentation Section
+ *
+ *     P:
+ * 	personality_enc    1	         Encoding specifier - preferred
+ *					 value is a pc-relative, signed
+ *				         4-byte
+ *
+ *
+ *        personality routine (encoded)  Encoded pointer to personality
+ *					 routine (actually to the PLT
+ *				         entry for the personality
+ *				         routine)
+ *     R:
+ * 	code_enc           1	      Non-default encoding for the
+ *				      code-pointers (FDE members
+ *				      "initial_location" and "address_range"
+ *				      and the operand for DW_CFA_set_loc)
+ *				      - preferred value is pc-relative,
+ *				      signed 4-byte.
+ *     L:
+ * 	lsda_enc	   1	      FDE augmentation bodies may contain
+ *				      LSDA pointers. If so they are
+ *				      encoded as specified here -
+ *				      preferred value is pc-relative,
+ *				      signed 4-byte possibly indirect
+ *				      thru a GOT entry.
+ *
+ *
+ *  9. Optional Call Frame varying
+ *     Instructions
+ *
+ * The size of the optional call frame instruction area must be computed
+ * based on the overall size and the offset reached while scanning the
+ * preceding fields of the CIE.
+ *
+ *
+ * Frame Descriptor Entry (FDE)
+ * ----------------------------
+ * FDE has the following format:
+ *
+ *                            Length
+ *                              in
+ *     Field                   Byte      Description
+ *     -----                  ------     -----------
+ *  1. Length                   4        Length of remainder of this FDE
+ *
+ *  2. CIE Pointer              4        Distance from this field to the
+ *				         nearest preceding CIE
+ *				         (uthe value is subtracted from the
+ *					 current address). This value
+ *				         can never be zero and thus can
+ *				         be used to distinguish CIE's and
+ *				         FDE's when scanning the
+ *				         .eh_frame section
+ *
+ *  3. Initial Location       varying    Reference to the function code
+ *                                       corresponding to this FDE.
+ *                                       If 'R' is missing from the CIE
+ *                                       Augmentation String, the field is an
+ *                                       8-byte absolute pointer. Otherwise,
+ *                                       the corresponding EH_PE encoding in the
+ *                                       CIE Augmentation Section is used to
+ *                                       interpret the reference.
+ *
+ *  4. Address Range          varying    Size of the function code corresponding
+ *                                       to this FDE.
+ *                                       If 'R' is missing from the CIE
+ *                                       Augmentation String, the field is an
+ *                                       8-byte unsigned number. Otherwise,
+ *                                       the size is determined by the
+ *				         corresponding EH_PE encoding in the
+ *                                       CIE Augmentation Section (the
+ *				         value is always absolute).
+ *
+ *  5. Optional FDE           varying    present if CIE augmentation
+ *     Augmentation Section	         string is non-empty.
+ *
+ *
+ *     'z':
+ * 	length		   uleb128       length of the remainder of the
+ *				         FDE augmentation section
+ *
+ *
+ *     'L' (and length > 0):
+ *         LSDA               varying    LSDA pointer, encoded in the
+ *				         format specified by the
+ *				         corresponding operand in the CIE's
+ *				         augmentation body.
+ *
+ *  6. Optional Call          varying
+ *     Frame Instructions
+ *
+ * The size of the optional call frame instruction area must be computed
+ * based on the overall size and the offset reached while scanning the
+ * preceding fields of the FDE.
+ *
+ * The overall size of a .eh_frame section is given in the ELF section
+ * header.  The only way to determine the number of entries is to scan
+ * the section till the end and count.
+ *
+ */
+
+
+
+
+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);
+}
+
+/*
+ * 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
+ * section. Ideally, we would remove these dead entries from eh_frame.
+ * However, that optimization has not yet been implemented. In the current
+ * implementation, the number of dead FDEs cannot be determined until
+ * active relocations are processed, and that processing follows the
+ * call to this function. This means that we are unable to detect dead FDEs
+ * here, and the section created by this routine is sized for maximum case
+ * where all FDEs are valid.
+ */
+uintptr_t
+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;
+	Aliste		idx;
+	Os_desc		*osp;
+
+	/*
+	 * we only build a unwind header if we have
+	 * some unwind information in the file.
+	 */
+	if (aplist_nitems(ofl->ofl_unwind) == 0)
+		return (1);
+
+	/*
+	 * Allocate and initialize the Elf_Data structure.
+	 */
+	if ((elfdata = libld_calloc(sizeof (Elf_Data), 1)) == 0)
+		return (S_ERROR);
+	elfdata->d_type = ELF_T_BYTE;
+	elfdata->d_align = ld_targ.t_m.m_word_align;
+	elfdata->d_version = ofl->ofl_dehdr->e_version;
+
+	/*
+	 * Allocate and initialize the Shdr structure.
+	 */
+	if ((shdr = libld_calloc(sizeof (Shdr), 1)) == 0)
+		return (S_ERROR);
+	shdr->sh_type = ld_targ.t_m.m_sht_unwind;
+	shdr->sh_flags = SHF_ALLOC;
+	shdr->sh_addralign = ld_targ.t_m.m_word_align;
+	shdr->sh_entsize = 0;
+
+	/*
+	 * Allocate and initialize the Is_desc structure.
+	 */
+	if ((isp = libld_calloc(1, sizeof (Is_desc))) == 0)
+		return (S_ERROR);
+	isp->is_name = MSG_ORIG(MSG_SCN_UNWINDHDR);
+	isp->is_shdr = shdr;
+	isp->is_indata = elfdata;
+
+	if ((ofl->ofl_unwindhdr = ld_place_section(ofl, isp,
+	    ld_targ.t_id.id_unwindhdr, 0)) == (Os_desc *)S_ERROR)
+		return (S_ERROR);
+
+	/*
+	 * Scan through all of the input Frame information, counting each FDE
+	 * that requires an index.  Each fde_entry gets a corresponding entry
+	 * in the binary search table.
+	 */
+	fde_cnt = 0;
+	for (APLIST_TRAVERSE(ofl->ofl_unwind, idx, osp)) {
+		Listnode    *_lnp;
+
+		for (LIST_TRAVERSE(&osp->os_isdescs, _lnp, isp)) {
+			uchar_t		*data;
+			uint64_t	off = 0;
+
+			data = isp->is_indata->d_buf;
+			size = isp->is_indata->d_size;
+
+			while (off < size) {
+				uint_t		length, id;
+				uint64_t	ndx = 0;
+
+				/*
+				 * Extract length in lsb format.  A zero length
+				 * indicates that this CIE is a terminator and
+				 * that processing for unwind information is
+				 * complete.
+				 */
+				length = extract_uint(data + off, &ndx, bswap);
+				if (length == 0)
+					break;
+
+				/*
+				 * Extract CIE id in lsb format.
+				 */
+				id = extract_uint(data + off, &ndx, bswap);
+
+				/*
+				 * A CIE record has a id of '0', otherwise
+				 * this is a FDE entry and the 'id' is the
+				 * CIE pointer.
+				 */
+				if (id == 0) {
+					uint_t	cieversion;
+					/*
+					 * The only CIE version supported
+					 * is '1' - quick sanity check
+					 * here.
+					 */
+					cieversion = data[off + ndx];
+					ndx += 1;
+					/* BEGIN CSTYLED */
+					if (cieversion != 1) {
+					    eprintf(ofl->ofl_lml, ERR_FATAL,
+						MSG_INTL(MSG_UNW_BADCIEVERS),
+						isp->is_file->ifl_name,
+						isp->is_name, off);
+					    return (S_ERROR);
+					}
+					/* END CSTYLED */
+				} else {
+					fde_cnt++;
+				}
+				off += length + 4;
+			}
+		}
+	}
+
+	/*
+	 * section size:
+	 *	byte	    version		+1
+	 *	byte	    eh_frame_ptr_enc	+1
+	 *	byte	    fde_count_enc	+1
+	 *	byte	    table_enc		+1
+	 *	4 bytes	    eh_frame_ptr	+4
+	 *	4 bytes	    fde_count		+4
+	 *	[4 bytes] [4bytes] * fde_count	...
+	 */
+	size = 12 + (8 * fde_cnt);
+
+	if ((elfdata->d_buf = libld_calloc(size, 1)) == 0)
+		return (S_ERROR);
+	elfdata->d_size = size;
+	shdr->sh_size = (Xword)size;
+
+	return (1);
+}
+
+/*
+ * the comparator function needs to calculate
+ * the actual 'initloc' of a bintab entry - to
+ * do this we initialize the following global to point
+ * to it.
+ */
+static Addr framehdr_addr;
+
+static int
+bintabcompare(const void *p1, const void *p2)
+{
+	uint_t	    *bintab1, *bintab2;
+	uint_t	    ent1, ent2;
+
+	bintab1 = (uint_t *)p1;
+	bintab2 = (uint_t *)p2;
+
+	assert(bintab1 != 0);
+	assert(bintab2 != 0);
+
+	ent1 = *bintab1 + framehdr_addr;
+	ent2 = *bintab2 + framehdr_addr;
+
+	if (ent1 > ent2)
+		return (1);
+	if (ent1 < ent2)
+		return (-1);
+	return (0);
+}
+
+uintptr_t
+ld_unwind_populate_hdr(Ofl_desc *ofl)
+{
+	uchar_t		*hdrdata;
+	uint_t		*binarytable;
+	uint_t		hdroff;
+	Aliste		idx;
+	Addr		hdraddr;
+	Os_desc		*hdrosp;
+	Os_desc		*osp;
+	Os_desc		*first_unwind;
+	uint_t		fde_count;
+	uint_t		*uint_ptr;
+	int		bswap = (ofl->ofl_flags1 & FLG_OF1_ENCDIFF) != 0;
+
+	/*
+	 * Are we building the unwind hdr?
+	 */
+	if ((hdrosp = ofl->ofl_unwindhdr) == 0)
+		return (1);
+
+	hdrdata = hdrosp->os_outdata->d_buf;
+	hdraddr = hdrosp->os_shdr->sh_addr;
+	hdroff = 0;
+
+	/*
+	 * version == 1
+	 */
+	hdrdata[hdroff++] = 1;
+	/*
+	 * The encodings are:
+	 *
+	 *  eh_frameptr_enc	sdata4 | pcrel
+	 *  fde_count_enc	udata4
+	 *  table_enc		sdata4 | datarel
+	 */
+	hdrdata[hdroff++] = DW_EH_PE_sdata4 | DW_EH_PE_pcrel;
+	hdrdata[hdroff++] = DW_EH_PE_udata4;
+	hdrdata[hdroff++] = DW_EH_PE_sdata4 | DW_EH_PE_datarel;
+
+	/*
+	 *	Header Offsets
+	 *	-----------------------------------
+	 *	byte	    version		+1
+	 *	byte	    eh_frame_ptr_enc	+1
+	 *	byte	    fde_count_enc	+1
+	 *	byte	    table_enc		+1
+	 *	4 bytes	    eh_frame_ptr	+4
+	 *	4 bytes	    fde_count		+4
+	 */
+	/* LINTED */
+	binarytable =  (uint_t *)(hdrdata + 12);
+	first_unwind = 0;
+	fde_count = 0;
+
+	for (APLIST_TRAVERSE(ofl->ofl_unwind, idx, osp)) {
+		uchar_t		*data;
+		size_t		size;
+		uint64_t	off = 0;
+		uint_t		cieRflag = 0, ciePflag = 0;
+		Shdr		*shdr;
+
+		/*
+		 * remember first UNWIND section to
+		 * point to in the frame_ptr entry.
+		 */
+		if (first_unwind == 0)
+			first_unwind = osp;
+
+		data = osp->os_outdata->d_buf;
+		shdr = osp->os_shdr;
+		size = shdr->sh_size;
+
+		while (off < size) {
+			uint_t	    length, id;
+			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.
+			 */
+			length = extract_uint(data + off, &ndx, bswap);
+			if (length == 0)
+				goto done;
+
+			/*
+			 * Extract CIE id in lsb format.
+			 */
+			id = extract_uint(data + off, &ndx, bswap);
+
+			/*
+			 * A CIE record has a id of '0'; otherwise
+			 * this is a FDE entry and the 'id' is the
+			 * CIE pointer.
+			 */
+			if (id == 0) {
+				char	*cieaugstr;
+				uint_t	cieaugndx;
+
+				ciePflag = 0;
+				cieRflag = 0;
+				/*
+				 * We need to drill through the CIE
+				 * to find the Rflag.  It's the Rflag
+				 * which describes how the FDE code-pointers
+				 * are encoded.
+				 */
+
+				/*
+				 * burn through version
+				 */
+				ndx++;
+
+				/*
+				 * augstr
+				 */
+				cieaugstr = (char *)(&data[off + ndx]);
+				ndx += strlen(cieaugstr) + 1;
+
+				/*
+				 * calign & dalign
+				 */
+				(void) uleb_extract(&data[off], &ndx);
+				(void) sleb_extract(&data[off], &ndx);
+
+				/*
+				 * retreg
+				 */
+				ndx++;
+
+				/*
+				 * we walk through the augmentation
+				 * section now looking for the Rflag
+				 */
+				for (cieaugndx = 0; cieaugstr[cieaugndx];
+				    cieaugndx++) {
+					/* BEGIN CSTYLED */
+					switch (cieaugstr[cieaugndx]) {
+					case 'z':
+					    /* size */
+					    (void) uleb_extract(&data[off],
+						&ndx);
+					    break;
+					case 'P':
+					    /* personality */
+					    ciePflag = data[off + ndx];
+					    ndx++;
+						/*
+						 * Just need to extract the
+						 * value to move on to the next
+						 * field.
+						 */
+					    (void) dwarf_ehe_extract(
+						&data[off + ndx],
+						&ndx, ciePflag,
+						ofl->ofl_dehdr->e_ident,
+						shdr->sh_addr, off + ndx);
+					    break;
+					case 'R':
+					    /* code encoding */
+					    cieRflag = data[off + ndx];
+					    ndx++;
+					    break;
+					case 'L':
+					    /* lsda encoding */
+					    ndx++;
+					    break;
+					}
+					/* END CSTYLED */
+				}
+			} else {
+				uint_t	    bintabndx;
+				uint64_t    initloc;
+				uint64_t    fdeaddr;
+
+				initloc = dwarf_ehe_extract(&data[off],
+				    &ndx, cieRflag, ofl->ofl_dehdr->e_ident,
+				    shdr->sh_addr, off + ndx);
+
+				/*
+				 * Ignore FDEs with initloc set to 0.
+				 * initloc will not be 0 unless this FDE was
+				 * abandoned due to GNU linkonce processing.
+				 * The 0 value occurs because we don't resolve
+				 * sloppy relocations for unwind header target
+				 * sections.
+				 */
+				if (initloc != 0) {
+					bintabndx = fde_count * 2;
+					fde_count++;
+
+					/*
+					 * FDEaddr is adjusted
+					 * to account for the length & id which
+					 * have already been consumed.
+					 */
+					fdeaddr = shdr->sh_addr + off;
+
+					binarytable[bintabndx] =
+					    (uint_t)(initloc - hdraddr);
+					binarytable[bintabndx + 1] =
+					    (uint_t)(fdeaddr - hdraddr);
+				}
+			}
+
+			/*
+			 * the length does not include the length
+			 * itself - so account for that too.
+			 */
+			off += length + 4;
+		}
+	}
+
+done:
+	/*
+	 * 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.
+	 */
+	framehdr_addr = hdraddr;
+	qsort((void *)binarytable, (size_t)fde_count,
+	    (size_t)(sizeof (uint_t) * 2), bintabcompare);
+	if (bswap) {
+		uint_t	*btable = binarytable;
+		uint_t	cnt;
+
+		for (cnt = fde_count * 2; cnt-- > 0; btable++)
+			*btable = ld_bswap_Word(*btable);
+	}
+
+	/*
+	 * Fill in:
+	 *	first_frame_ptr
+	 *	fde_count
+	 */
+	hdroff = 4;
+	/* LINTED */
+	uint_ptr = (uint_t *)(&hdrdata[hdroff]);
+	*uint_ptr = first_unwind->os_shdr->sh_addr -
+	    (hdrosp->os_shdr->sh_addr + hdroff);
+	if (bswap)
+		*uint_ptr = ld_bswap_Word(*uint_ptr);
+
+	hdroff += 4;
+	/* LINTED */
+	uint_ptr = (uint_t *)&hdrdata[hdroff];
+	*uint_ptr = fde_count;
+	if (bswap)
+		*uint_ptr = ld_bswap_Word(*uint_ptr);
+
+	/*
+	 * 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 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.
+	 */
+	if (ofl->ofl_flags1 & FLG_OF1_RLXREL) {
+		Word	phnum = ofl->ofl_nehdr->e_phnum;
+		Phdr	*phdr = ofl->ofl_phdr;
+
+		for (; phnum-- > 0; phdr++) {
+			if (phdr->p_type == PT_SUNW_UNWIND) {
+				phdr->p_memsz = 12 + (8 * fde_count);
+				phdr->p_filesz = phdr->p_memsz;
+				break;
+			}
+		}
+	}
+
+	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
+ld_unwind_register(Os_desc *osp, Ofl_desc * ofl)
+{
+	Aliste	idx;
+	Os_desc	*_osp;
+	/*
+	 * Check to see if this output section is already
+	 * on the list.
+	 */
+	for (APLIST_TRAVERSE(ofl->ofl_unwind, idx, _osp))
+		if (osp == _osp)
+			return (1);
+
+	/*
+	 * Append output section to unwind list
+	 */
+	if (aplist_append(&ofl->ofl_unwind, osp, AL_CNT_UNWIND) == NULL)
+		return (S_ERROR);
+	return (1);
+}
--- a/usr/src/cmd/sgs/libld/common/update.c	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/libld/common/update.c	Wed Mar 18 13:28:28 2009 -0600
@@ -3383,17 +3383,15 @@
 		}
 
 		/*
-		 * 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 @@
 			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
--- a/usr/src/cmd/sgs/packages/common/SUNWonld-README	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README	Wed Mar 18 13:28:28 2009 -0600
@@ -1444,3 +1444,4 @@
 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
--- a/usr/src/cmd/sgs/rtld/common/elf.c	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/rtld/common/elf.c	Wed Mar 18 13:28:28 2009 -0600
@@ -1673,6 +1673,7 @@
 			cap = (Cap *)((uintptr_t)phdr->p_vaddr + base);
 			break;
 		case PT_SUNW_UNWIND:
+		case PT_SUNW_EH_FRAME:
 			uphdr = phdr;
 			break;
 		default:
--- a/usr/src/cmd/sgs/tools/common/leb128.c	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/cmd/sgs/tools/common/leb128.c	Wed Mar 18 13:28:28 2009 -0600
@@ -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 @@
 	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 @@
 	}
 
 	/*
-	 * 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);
--- a/usr/src/lib/libdtrace/common/dt_module.c	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/lib/libdtrace/common/dt_module.c	Wed Mar 18 13:28:28 2009 -0600
@@ -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 @@
 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 @@
 		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 @@
 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 @@
 		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)
--- a/usr/src/lib/libproc/common/Psymtab.c	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/lib/libproc/common/Psymtab.c	Wed Mar 18 13:28:28 2009 -0600
@@ -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 @@
 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 @@
 			 * 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;
--- a/usr/src/uts/common/sys/elf.h	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/uts/common/sys/elf.h	Wed Mar 18 13:28:28 2009 -0600
@@ -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 @@
 #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 @@
 #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 @@
 #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
 
--- a/usr/src/uts/common/sys/link.h	Wed Mar 18 11:09:59 2009 -0700
+++ b/usr/src/uts/common/sys/link.h	Wed Mar 18 13:28:28 2009 -0600
@@ -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 @@
  * 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 @@
  * 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 */