changeset 942:8cf53d6a7d2e

PSARC 2005/689 ELF Extended Program Headers 6317969 elfheader limited to 65535 segments 6317980 coredump elfheader doesn't reflect the correct number of dumped segments 6343698 p-tools affected by 6317980 : coredump elfheader incorrectly states number of dumped segments 6350070 stub for shmgetid() returns the wrong default value
author ahl
date Thu, 17 Nov 2005 11:42:26 -0800
parents 49d0d4c2eea8
children 19aae6d81452
files usr/src/cmd/mdb/common/mdb/mdb_gelf.c usr/src/cmd/mdb/common/mdb/mdb_gelf.h usr/src/cmd/sgs/elfdump/common/elfdump.c usr/src/cmd/sgs/elfdump/common/elfdump.msg usr/src/cmd/sgs/libelf/Makefile.com usr/src/cmd/sgs/libelf/common/gelf.c usr/src/cmd/sgs/libelf/common/getphnum.c usr/src/cmd/sgs/libelf/common/llib-lelf usr/src/cmd/sgs/libelf/demo/dcom.c usr/src/cmd/sgs/libelf/spec/elf.spec usr/src/cmd/sgs/libelf/spec/versions usr/src/cmd/sgs/liblddbg/common/elf.c usr/src/cmd/sgs/liblddbg/common/liblddbg.msg usr/src/cmd/sgs/packages/common/SUNWonld-README usr/src/head/libelf.h usr/src/lib/libproc/common/Pcontrol.h usr/src/lib/libproc/common/Pcore.c usr/src/lib/libproc/common/Pgcore.c usr/src/lib/libproc/common/Pidle.c usr/src/lib/libproc/common/Psymtab.c usr/src/uts/common/exec/elf/elf.c usr/src/uts/common/sys/elf.h usr/src/uts/intel/ia32/ml/modstubs.s usr/src/uts/sparc/ml/modstubs.s
diffstat 24 files changed, 795 insertions(+), 291 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/mdb/common/mdb/mdb_gelf.c	Thu Nov 17 08:46:01 2005 -0800
+++ b/usr/src/cmd/mdb/common/mdb/mdb_gelf.c	Thu Nov 17 11:42:26 2005 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -48,15 +48,15 @@
 static mdb_gelf_file_t *
 gelf_sect_init(mdb_gelf_file_t *gf)
 {
-	mdb_gelf_sect_t *gsp, *shstr = &gf->gf_sects[gf->gf_ehdr.e_shstrndx];
+	mdb_gelf_sect_t *gsp, *shstr = &gf->gf_sects[gf->gf_shstrndx];
 	GElf_Half i, npbit = 0;
 	GElf_Shdr *shp;
 	GElf_Phdr *gpp;
 
 	if (gf->gf_mode == GF_PROGRAM)
-		gf->gf_ehdr.e_shnum = 0; /* Simplifies other code paths */
+		gf->gf_shnum = 0; /* Simplifies other code paths */
 
-	if (gf->gf_ehdr.e_shnum == 0)
+	if (gf->gf_shnum == 0)
 		return (gf); /* If no section headers we're done here */
 
 	if (IOP_SEEK(gf->gf_io, shstr->gs_shdr.sh_offset, SEEK_SET) == -1) {
@@ -73,7 +73,7 @@
 		return (NULL);
 	}
 
-	for (gsp = gf->gf_sects, i = 0; i < gf->gf_ehdr.e_shnum; i++, gsp++) {
+	for (gsp = gf->gf_sects, i = 0; i < gf->gf_shnum; i++, gsp++) {
 		shp = &gsp->gs_shdr;
 		gsp->gs_name = (const char *)shstr->gs_data + shp->sh_name;
 
@@ -101,13 +101,13 @@
 	 */
 	if (gf->gf_ehdr.e_type == ET_REL && npbit != 0) {
 		gf->gf_phdrs = mdb_zalloc(sizeof (GElf_Phdr) * npbit, UM_SLEEP);
-		gf->gf_ehdr.e_phnum = npbit;
+		gf->gf_phnum = npbit;
 		gf->gf_npload = npbit;
 
 		gpp = gf->gf_phdrs;
 		gsp = gf->gf_sects;
 
-		for (i = 0; i < gf->gf_ehdr.e_shnum; i++, gsp++) {
+		for (i = 0; i < gf->gf_shnum; i++, gsp++) {
 			shp = &gsp->gs_shdr;
 
 			if ((shp->sh_type == SHT_PROGBITS) &&
@@ -238,9 +238,9 @@
 	size_t nbytes;
 
 	mdb_dprintf(MDB_DBG_ELF, "loading %s section headers (%hu entries)\n",
-	    IOP_NAME(gf->gf_io), gf->gf_ehdr.e_shnum);
+	    IOP_NAME(gf->gf_io), gf->gf_shnum);
 
-	if (gf->gf_ehdr.e_shnum == 0)
+	if (gf->gf_shnum == 0)
 		return (gf);
 
 	if (IOP_SEEK(gf->gf_io, (off64_t)gf->gf_ehdr.e_shoff, SEEK_SET) == -1) {
@@ -248,7 +248,7 @@
 		return (NULL);
 	}
 
-	nbytes = shdr_size * gf->gf_ehdr.e_shnum;
+	nbytes = shdr_size * gf->gf_shnum;
 	shdrs = mdb_alloc(nbytes, UM_SLEEP);
 
 	if (IOP_READ(gf->gf_io, shdrs, nbytes) != nbytes) {
@@ -257,13 +257,13 @@
 		return (NULL);
 	}
 
-	gf->gf_sects = mdb_zalloc(sizeof (mdb_gelf_sect_t) *
-	    gf->gf_ehdr.e_shnum, UM_SLEEP);
+	gf->gf_sects = mdb_zalloc(sizeof (mdb_gelf_sect_t) * gf->gf_shnum,
+	    UM_SLEEP);
 
 	shp = shdrs;
 	gsp = gf->gf_sects;
 
-	for (i = 0; i < gf->gf_ehdr.e_shnum; i++, shp += shdr_size, gsp++)
+	for (i = 0; i < gf->gf_shnum; i++, shp += shdr_size, gsp++)
 		(void) elf2gelf(shp, &gsp->gs_shdr);
 
 	mdb_free(shdrs, nbytes);
@@ -359,10 +359,10 @@
 	GElf_Phdr *gpp;
 	size_t nbytes;
 
-	mdb_dprintf(MDB_DBG_ELF, "loading %s program headers (%hu entries)\n",
-	    IOP_NAME(gf->gf_io), gf->gf_ehdr.e_phnum);
+	mdb_dprintf(MDB_DBG_ELF, "loading %s program headers (%lu entries)\n",
+	    IOP_NAME(gf->gf_io), gf->gf_phnum);
 
-	if (gf->gf_ehdr.e_phnum == 0)
+	if (gf->gf_phnum == 0)
 		return (gf);
 
 	if (IOP_SEEK(gf->gf_io, (off64_t)gf->gf_ehdr.e_phoff, SEEK_SET) == -1) {
@@ -370,7 +370,7 @@
 		return (NULL);
 	}
 
-	nbytes = phdr_size * gf->gf_ehdr.e_phnum;
+	nbytes = phdr_size * gf->gf_phnum;
 	phdrs = mdb_alloc(nbytes, UM_SLEEP);
 
 	if (IOP_READ(gf->gf_io, phdrs, nbytes) != nbytes) {
@@ -379,8 +379,7 @@
 		return (NULL);
 	}
 
-	gf->gf_phdrs = mdb_zalloc(sizeof (GElf_Phdr) *
-	    gf->gf_ehdr.e_phnum, UM_SLEEP);
+	gf->gf_phdrs = mdb_zalloc(sizeof (GElf_Phdr) * gf->gf_phnum, UM_SLEEP);
 
 	php = phdrs;
 	gpp = gf->gf_phdrs;
@@ -389,7 +388,7 @@
 	 * Iterate through the list of phdrs locating those that are of type
 	 * PT_LOAD; increment gf_npload so we know how many are loadable.
 	 */
-	for (i = 0; i < gf->gf_ehdr.e_phnum; i++, php += phdr_size, gpp++) {
+	for (i = 0; i < gf->gf_phnum; i++, php += phdr_size, gpp++) {
 		(void) elf2gelf(php, gpp);
 		if (gpp->p_type != PT_LOAD)
 			continue;
@@ -407,18 +406,18 @@
 	 * arranges for the PT_LOAD phdrs with non-zero virtual addresses
 	 * to come first sorted by virtual address.  This means that we
 	 * can access the complete phdr table by examining the array
-	 * gf->gf_phdrs[0 .. gf->gf_ehdr.e_phnum - 1], and we can access a
-	 * sorted array of valid PT_LOAD pdhrs by examining the array
+	 * gf->gf_phdrs[0 .. gf->gf_phnum - 1], and we can access a sorted
+	 * array of valid PT_LOAD pdhrs by examining the array
 	 * gf->gf_phdrs[0 .. gf->gf_npload - 1].
 	 */
-	qsort(gf->gf_phdrs, gf->gf_ehdr.e_phnum, sizeof (GElf_Phdr),
+	qsort(gf->gf_phdrs, gf->gf_phnum, sizeof (GElf_Phdr),
 	    gelf_phdr_compare);
 
 	/*
 	 * Locate the PT_DYNAMIC Phdr if one is present; we save this
 	 * Phdr pointer in gf->gf_dynp for future use.
 	 */
-	for (gpp = gf->gf_phdrs, i = 0; i < gf->gf_ehdr.e_phnum; i++, gpp++) {
+	for (gpp = gf->gf_phdrs, i = 0; i < gf->gf_phnum; i++, gpp++) {
 		if (gpp->p_type == PT_DYNAMIC) {
 			mdb_dprintf(MDB_DBG_ELF, "PT_DYNAMIC "
 			    "filesize = %lluULL off=%lluULL\n",
@@ -502,14 +501,14 @@
 	} else {
 		mdb_gelf_sect_t *gsp = gf->gf_sects;
 
-		for (i = 0; i < gf->gf_ehdr.e_shnum; i++, gsp++) {
+		for (i = 0; i < gf->gf_shnum; i++, gsp++) {
 			if (gsp->gs_shdr.sh_type == SHT_DYNAMIC) {
 				dyn_addr = gsp->gs_shdr.sh_offset;
 				break;
 			}
 		}
 
-		if (i == gf->gf_ehdr.e_shnum)
+		if (i == gf->gf_shnum)
 			return (NULL); /* No SHT_DYNAMIC entry was found */
 	}
 
@@ -543,7 +542,7 @@
 }
 
 static mdb_gelf_file_t *
-gelf32_init(mdb_gelf_file_t *gf, const Elf32_Ehdr *ehdr)
+gelf32_init(mdb_gelf_file_t *gf, mdb_io_t *io, const Elf32_Ehdr *ehdr)
 {
 	/*
 	 * Convert the Elf32_Ehdr to a GElf_Ehdr
@@ -564,6 +563,38 @@
 	gf->gf_ehdr.e_shnum = ehdr->e_shnum;
 	gf->gf_ehdr.e_shstrndx = ehdr->e_shstrndx;
 
+	gf->gf_shnum = gf->gf_ehdr.e_shnum;
+	gf->gf_shstrndx = gf->gf_ehdr.e_shstrndx;
+	gf->gf_phnum = gf->gf_ehdr.e_phnum;
+
+	if ((gf->gf_shnum == 0 && ehdr->e_shoff != 0) ||
+	    gf->gf_shstrndx == SHN_XINDEX || gf->gf_phnum == PN_XNUM) {
+		Elf32_Shdr shdr0;
+
+		if (ehdr->e_shoff == 0)
+			return (NULL);
+
+		if (IOP_SEEK(io, (off64_t)ehdr->e_shoff, SEEK_SET) == -1) {
+			warn("failed to seek %s", IOP_NAME(io));
+			return (NULL);
+		}
+
+		if (IOP_READ(io, &shdr0, sizeof (shdr0)) != sizeof (shdr0)) {
+			warn("failed to read extended ELF header from %s",
+			    IOP_NAME(io));
+			return (NULL);
+		}
+
+		if (gf->gf_shnum == 0)
+			gf->gf_shnum = shdr0.sh_size;
+
+		if (gf->gf_shstrndx == SHN_XINDEX)
+			gf->gf_shstrndx = shdr0.sh_link;
+
+		if (gf->gf_phnum == PN_XNUM)
+			gf->gf_phnum = shdr0.sh_info;
+	}
+
 	/*
 	 * Initialize the section and program headers.  We skip initializing
 	 * the section headers if this is a program image because they are
@@ -584,13 +615,45 @@
 }
 
 static mdb_gelf_file_t *
-gelf64_init(mdb_gelf_file_t *gf, Elf64_Ehdr *ehdr)
+gelf64_init(mdb_gelf_file_t *gf, mdb_io_t *io, Elf64_Ehdr *ehdr)
 {
 	/*
 	 * Save a copy of the ELF file header
 	 */
 	bcopy(ehdr, &gf->gf_ehdr, sizeof (Elf64_Ehdr));
 
+	gf->gf_shnum = gf->gf_ehdr.e_shnum;
+	gf->gf_shstrndx = gf->gf_ehdr.e_shstrndx;
+	gf->gf_phnum = gf->gf_ehdr.e_phnum;
+
+	if ((gf->gf_shnum == 0 && ehdr->e_shoff != 0) ||
+	    gf->gf_shstrndx == SHN_XINDEX || gf->gf_phnum == PN_XNUM) {
+		Elf64_Shdr shdr0;
+
+		if (ehdr->e_shoff == 0)
+			return (NULL);
+
+		if (IOP_SEEK(io, (off64_t)ehdr->e_shoff, SEEK_SET) == -1) {
+			warn("failed to seek %s", IOP_NAME(io));
+			return (NULL);
+		}
+
+		if (IOP_READ(io, &shdr0, sizeof (shdr0)) != sizeof (shdr0)) {
+			warn("failed to read extended ELF header from %s",
+			    IOP_NAME(io));
+			return (NULL);
+		}
+
+		if (gf->gf_shnum == 0)
+			gf->gf_shnum = shdr0.sh_size;
+
+		if (gf->gf_shstrndx == SHN_XINDEX)
+			gf->gf_shstrndx = shdr0.sh_link;
+
+		if (gf->gf_phnum == PN_XNUM)
+			gf->gf_phnum = shdr0.sh_info;
+	}
+
 	/*
 	 * Initialize the section and program headers.  We skip initializing
 	 * the section headers if this is a program image because they are
@@ -682,7 +745,7 @@
 
 	switch (ehdr.h32.e_ident[EI_CLASS]) {
 	case ELFCLASS32:
-		gf = gelf32_init(gf, &ehdr.h32);
+		gf = gelf32_init(gf, io, &ehdr.h32);
 		break;
 
 	case ELFCLASS64:
@@ -697,7 +760,7 @@
 			goto err;
 		}
 
-		gf = gelf64_init(gf, &ehdr.h64);
+		gf = gelf64_init(gf, io, &ehdr.h64);
 		break;
 
 	default:
@@ -714,7 +777,7 @@
 err:
 	if (gf != NULL) {
 		if (gf->gf_sects != NULL) {
-			mdb_free(gf->gf_sects, gf->gf_ehdr.e_shnum *
+			mdb_free(gf->gf_sects, gf->gf_shnum *
 			    sizeof (mdb_gelf_sect_t));
 		}
 		mdb_free(gf, sizeof (mdb_gelf_file_t));
@@ -728,16 +791,15 @@
 	mdb_gelf_sect_t *gsp;
 	GElf_Half i;
 
-	for (gsp = gf->gf_sects, i = 0; i < gf->gf_ehdr.e_shnum; i++, gsp++) {
+	for (gsp = gf->gf_sects, i = 0; i < gf->gf_shnum; i++, gsp++) {
 		if (gsp->gs_data != NULL)
 			mdb_free(gsp->gs_data, gsp->gs_shdr.sh_size);
 	}
 
 	mdb_free(gf->gf_sects,
-	    gf->gf_ehdr.e_shnum * sizeof (mdb_gelf_sect_t));
+	    gf->gf_shnum * sizeof (mdb_gelf_sect_t));
 
-	mdb_free(gf->gf_phdrs,
-	    gf->gf_ehdr.e_phnum * sizeof (GElf_Phdr));
+	mdb_free(gf->gf_phdrs, gf->gf_phnum * sizeof (GElf_Phdr));
 
 	mdb_io_rele(gf->gf_io);
 	mdb_free(gf, sizeof (mdb_gelf_file_t));
@@ -871,7 +933,7 @@
 	}
 
 	if (gst->gst_ehdr->e_type == ET_REL && gst->gst_file != NULL) {
-		GElf_Word smax = gst->gst_ehdr->e_shnum;
+		GElf_Word smax = gst->gst_file->gf_shnum;
 		mdb_gelf_sect_t *gsp;
 
 		for (sym = gst->gst_dsect->gs_data, i = 0; i < n; i++, sym++) {
@@ -964,7 +1026,7 @@
 	}
 
 	if (gst->gst_ehdr->e_type == ET_REL && gst->gst_file != NULL) {
-		GElf_Word smax = gst->gst_ehdr->e_shnum;
+		GElf_Word smax = gst->gst_file->gf_shnum;
 		mdb_gelf_sect_t *gsp;
 
 		for (sym = gst->gst_dsect->gs_data, i = 0; i < n; i++, sym++) {
@@ -999,7 +1061,7 @@
 	 * Examine the sh_link field in the the Elf header to get the name
 	 * of the corresponding strings section
 	 */
-	for (gsp = gf->gf_sects, i = 0; i < gf->gf_ehdr.e_shnum; i++, gsp++) {
+	for (gsp = gf->gf_sects, i = 0; i < gf->gf_shnum; i++, gsp++) {
 		if (gsp->gs_shdr.sh_type == elftype) {
 			dsname = gsp->gs_name;
 			link = gsp->gs_shdr.sh_link;
@@ -1010,12 +1072,12 @@
 	if (dsname == NULL)
 		return (NULL);
 
-	if (link > gf->gf_ehdr.e_shnum) {
+	if (link > gf->gf_shnum) {
 		/*
 		 * Invalid link number due to corrupt elf file.
 		 */
 		warn("link number %ud larger than number of sections %d\n",
-		    link, gf->gf_ehdr.e_shnum);
+		    link, gf->gf_shnum);
 		return (NULL);
 	}
 
@@ -1045,14 +1107,14 @@
 	gst->gst_id = 0;
 	gst->gst_tabid = tabid;
 
-	for (gsp = gf->gf_sects, i = 0; i < gf->gf_ehdr.e_shnum; i++, gsp++) {
+	for (gsp = gf->gf_sects, i = 0; i < gf->gf_shnum; i++, gsp++) {
 		if (strcmp(gsp->gs_name, dsname) == 0) {
 			gst->gst_dsect = gsp;
 			break;
 		}
 	}
 
-	for (gsp = gf->gf_sects, i = 0; i < gf->gf_ehdr.e_shnum; i++, gsp++) {
+	for (gsp = gf->gf_sects, i = 0; i < gf->gf_shnum; i++, gsp++) {
 		if (strcmp(gsp->gs_name, ssname) == 0) {
 			gst->gst_ssect = gsp;
 			break;
--- a/usr/src/cmd/mdb/common/mdb/mdb_gelf.h	Thu Nov 17 08:46:01 2005 -0800
+++ b/usr/src/cmd/mdb/common/mdb/mdb_gelf.h	Thu Nov 17 11:42:26 2005 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -61,6 +61,9 @@
 	GElf_Phdr *gf_dynp;		/* Pointer to PT_DYNAMIC phdr */
 	GElf_Dyn *gf_dyns;		/* Array of dynamic entries */
 	size_t gf_ndyns;		/* Number of dynamic entries */
+	size_t gf_shnum;		/* Number of section headers */
+	size_t gf_shstrndx;		/* Index of section string table */
+	size_t gf_phnum;		/* Number of program headers */
 	mdb_gelf_sect_t *gf_sects;	/* Array of section structs */
 	mdb_io_t *gf_io;		/* I/o backend for ELF file */
 	int gf_mode;			/* Mode flag (see above) */
--- a/usr/src/cmd/sgs/elfdump/common/elfdump.c	Thu Nov 17 08:46:01 2005 -0800
+++ b/usr/src/cmd/sgs/elfdump/common/elfdump.c	Thu Nov 17 11:42:26 2005 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
@@ -309,8 +309,8 @@
  * Print section headers.
  */
 static void
-sections(const char *file, Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr,
-    const char *name)
+sections(const char *file, Cache *cache, GElf_Word shnum, GElf_Word phnum,
+    GElf_Ehdr *ehdr, const char *name)
 {
 	GElf_Word	cnt;
 	Cache *		_cache;
@@ -354,8 +354,8 @@
 }
 
 static void
-unwind(Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr, const char *name,
-    const char *file, Elf *elf)
+unwind(Cache *cache, GElf_Word shnum, GElf_Word phnum, GElf_Ehdr *ehdr,
+    const char *name, const char *file, Elf *elf)
 {
 	GElf_Word	cnt;
 	GElf_Phdr	unwind_phdr;
@@ -368,7 +368,7 @@
 
 	unwind_phdr.p_type = PT_NULL;
 
-	for (cnt = 0; cnt < ehdr->e_phnum; cnt++) {
+	for (cnt = 0; cnt < phnum; cnt++) {
 		GElf_Phdr	phdr;
 
 		if (gelf_getphdr(elf, cnt, &phdr) == NULL) {
@@ -661,8 +661,8 @@
  * this should be accompanied with a program header.
  */
 static void
-cap(const char *file, Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr,
-    Elf *elf)
+cap(const char *file, Cache *cache, GElf_Word shnum, GElf_Word phnum,
+    GElf_Ehdr *ehdr, Elf *elf)
 {
 	GElf_Word	cnt;
 	GElf_Shdr *	cshdr = 0;
@@ -673,7 +673,7 @@
 	/*
 	 * Determine if a hardware/software capabilities header exists.
 	 */
-	for (cnt = 0; cnt < ehdr->e_phnum; cnt++) {
+	for (cnt = 0; cnt < phnum; cnt++) {
 		GElf_Phdr	phdr;
 
 		if (gelf_getphdr(elf, cnt, &phdr) == NULL) {
@@ -763,8 +763,8 @@
  * Print the interpretor.
  */
 static void
-interp(const char *file, Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr,
-    Elf *elf)
+interp(const char *file, Cache *cache, GElf_Word shnum, GElf_Word phnum,
+    GElf_Ehdr *ehdr, Elf *elf)
 {
 	GElf_Word	cnt;
 	GElf_Shdr *	ishdr = 0;
@@ -775,7 +775,7 @@
 	/*
 	 * Determine if an interp header exists.
 	 */
-	for (cnt = 0; cnt < ehdr->e_phnum; cnt++) {
+	for (cnt = 0; cnt < phnum; cnt++) {
 		GElf_Phdr	phdr;
 
 		if (gelf_getphdr(elf, cnt, &phdr) == NULL) {
@@ -1151,8 +1151,8 @@
  * Search for and process any symbol tables.
  */
 static void
-symbols(Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr, const char *name,
-    Cache *versymcache, const char *file)
+symbols(Cache *cache, GElf_Word shnum, GElf_Word phnum, GElf_Ehdr *ehdr,
+    const char *name, Cache *versymcache, const char *file)
 {
 	GElf_Word	cnt;
 	char		is_core = (ehdr->e_type == ET_CORE);
@@ -1371,8 +1371,8 @@
  * Search for and process any relocation sections.
  */
 static void
-reloc(Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr, const char *name,
-    const char *file, uint32_t flags)
+reloc(Cache *cache, GElf_Word shnum, GElf_Word phnum, GElf_Ehdr *ehdr,
+    const char *name, const char *file, uint32_t flags)
 {
 	GElf_Word	cnt;
 
@@ -2281,7 +2281,8 @@
 
 
 static void
-got(Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr, const char *file)
+got(Cache *cache, GElf_Word shnum, GElf_Word phnum, GElf_Ehdr *ehdr,
+    const char *file)
 {
 	Cache		*gotcache = 0, *symtab = 0, *_cache;
 	GElf_Addr	gotbgn, gotend;
@@ -2524,8 +2525,8 @@
 	GElf_Ehdr	ehdr;
 	Elf_Data	*data;
 	uint_t		cnt;
-	GElf_Word	shnum;
-	size_t		shstrndx, _shnum;
+	GElf_Word	shnum, phnum;
+	size_t		shstrndx, _shnum, _phnum;
 	GElf_Shdr	nameshdr;
 	GElf_Shdr	shdr0;
 	GElf_Shdr	*_shdr0;
@@ -2538,17 +2539,25 @@
 		return;
 	}
 
-	if (elf_getshnum(elf, &_shnum) == NULL) {
+	if (elf_getshnum(elf, &_shnum) == 0) {
 		failure(file, MSG_ORIG(MSG_ELF_GETSHNUM));
 		return;
 	}
 	/* LINTED */
 	shnum = (GElf_Word)_shnum;
 
-	if (elf_getshstrndx(elf, &shstrndx) == NULL) {
+	if (elf_getshstrndx(elf, &shstrndx) == 0) {
 		failure(file, MSG_ORIG(MSG_ELF_GETSHSTRNDX));
 		return;
 	}
+
+	if (elf_getphnum(elf, &_phnum) == 0) {
+		failure(file, MSG_ORIG(MSG_ELF_GETPHNUM));
+		return;
+	}
+	/* LINTED */
+	phnum = (GElf_Word)_phnum;
+
 	if ((scn = elf_getscn(elf, 0)) != NULL) {
 		if ((_shdr0 = gelf_getshdr(scn, &shdr0)) == NULL) {
 			failure(file, MSG_ORIG(MSG_ELF_GETSHDR));
@@ -2568,10 +2577,10 @@
 	/*
 	 * Print the program headers.
 	 */
-	if ((flags & FLG_PHDR) && ehdr.e_phnum) {
+	if ((flags & FLG_PHDR) && phnum != 0) {
 		GElf_Phdr phdr;
 
-		for (cnt = 0; cnt < ehdr.e_phnum; cnt++) {
+		for (cnt = 0; cnt < phnum; cnt++) {
 			if (gelf_getphdr(elf, cnt, &phdr) == NULL) {
 				failure(file, MSG_ORIG(MSG_ELF_GETPHDR));
 				return;
@@ -2585,16 +2594,16 @@
 
 
 	/*
-	 * If there are no sections (core files), or if we don't want
-	 * any section information we might as well return now.
+	 * Return now if there are no section, if there's just one section to
+	 * act as an extension of the ELF header, or if on section information
+	 * was requested.
 	 */
-	if ((shnum == 0) || (flags && (flags & ~(FLG_EHDR | FLG_PHDR)) == 0)) {
+	if ((shnum <= 1) || (flags && (flags & ~(FLG_EHDR | FLG_PHDR)) == 0)) {
 		if ((ehdr.e_type == ET_CORE) && (flags & FLG_NOTE))
 			note(0, shnum, 0, file);
 		return;
 	}
 
-
 	/*
 	 * Obtain the .shstrtab data buffer to provide the required section
 	 * name strings.
@@ -2704,21 +2713,21 @@
 	}
 
 	if (flags & FLG_SHDR)
-		sections(file, cache, shnum, &ehdr, Nname);
+		sections(file, cache, shnum, phnum, &ehdr, Nname);
 
 	if (flags & FLG_INTERP)
-		interp(file, cache, shnum, &ehdr, elf);
+		interp(file, cache, shnum, phnum, &ehdr, elf);
 
 	versymcache = versions(cache, shnum, file, flags);
 
 	if (flags & FLG_SYMBOLS)
-		symbols(cache, shnum, &ehdr, Nname, versymcache, file);
+		symbols(cache, shnum, phnum, &ehdr, Nname, versymcache, file);
 
 	if (flags & FLG_HASH)
 		hash(cache, shnum, Nname, file, flags);
 
 	if (flags & FLG_GOT)
-		got(cache, shnum, &ehdr, file);
+		got(cache, shnum, phnum, &ehdr, file);
 
 	if (flags & FLG_GROUP)
 		group(cache, shnum, Nname, file, flags);
@@ -2727,7 +2736,7 @@
 		syminfo(cache, shnum, file);
 
 	if (flags & FLG_RELOC)
-		reloc(cache, shnum, &ehdr, Nname, file, flags);
+		reloc(cache, shnum, phnum, &ehdr, Nname, file, flags);
 
 	if (flags & FLG_DYNAMIC)
 		dynamic(cache, shnum, &ehdr, file);
@@ -2742,10 +2751,10 @@
 		checksum(elf);
 
 	if (flags & FLG_CAP)
-		cap(file, cache, shnum, &ehdr, elf);
+		cap(file, cache, shnum, phnum, &ehdr, elf);
 
 	if (flags & FLG_UNWIND)
-		unwind(cache, shnum, &ehdr, Nname, file, elf);
+		unwind(cache, shnum, phnum, &ehdr, Nname, file, elf);
 
 	free(cache);
 }
--- a/usr/src/cmd/sgs/elfdump/common/elfdump.msg	Thu Nov 17 08:46:01 2005 -0800
+++ b/usr/src/cmd/sgs/elfdump/common/elfdump.msg	Thu Nov 17 11:42:26 2005 -0800
@@ -229,6 +229,7 @@
 @ MSG_ELF_GETARSYM	"elf_getarsym"
 @ MSG_ELF_RAND		"elf_rand"
 @ MSG_ELF_BEGIN		"elf_begin"
+@ MSG_ELF_GETPHNUM	"elf_getphnum"
 @ MSG_ELF_GETSHNUM	"elf_getshnum"
 @ MSG_ELF_GETSHSTRNDX	"elf_getshstrndx"
 @ MSG_ELF_ARSYM		"ARSYM"
--- a/usr/src/cmd/sgs/libelf/Makefile.com	Thu Nov 17 08:46:01 2005 -0800
+++ b/usr/src/cmd/sgs/libelf/Makefile.com	Thu Nov 17 11:42:26 2005 -0800
@@ -20,7 +20,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -36,7 +36,7 @@
 		getarhdr.o	getarsym.o	getbase.o	getdata.o \
 		getehdr.o	getident.o	getphdr.o	getscn.o \
 		getshdr.o \
-		getshnum.o	getshstrndx.o \
+		getphnum.o	getshnum.o	getshstrndx.o \
 		hash.o		input.o		kind.o \
 		ndxscn.o	newdata.o	newehdr.o	newphdr.o \
 		newscn.o	next.o		nextscn.o	output.o \
--- a/usr/src/cmd/sgs/libelf/common/gelf.c	Thu Nov 17 08:46:01 2005 -0800
+++ b/usr/src/cmd/sgs/libelf/common/gelf.c	Thu Nov 17 11:42:26 2005 -0800
@@ -219,15 +219,15 @@
 gelf_getphdr(Elf *elf, int ndx, GElf_Phdr *dst)
 {
 	int		class;
-	GElf_Ehdr	ehdr;
+	size_t		phnum;
 
 	if (elf == NULL)
 		return (NULL);
 
-	if (gelf_getehdr(elf, &ehdr) == NULL)
+	if (elf_getphnum(elf, &phnum) == 0)
 		return (NULL);
 
-	if (ehdr.e_phnum < ndx) {
+	if (phnum <= ndx) {
 		_elf_seterr(EREQ_RAND, 0);
 		return (NULL);
 	}
@@ -266,15 +266,15 @@
 gelf_update_phdr(Elf *elf, int ndx, GElf_Phdr *src)
 {
 	int		class;
-	GElf_Ehdr	ehdr;
+	size_t		phnum;
 
 	if (elf == NULL)
 		return (0);
 
-	if (gelf_getehdr(elf, &ehdr) == NULL)
-		return (0);
+	if (elf_getphnum(elf, &phnum) == 0)
+		return (NULL);
 
-	if (ehdr.e_phnum < ndx) {
+	if (phnum < ndx) {
 		_elf_seterr(EREQ_RAND, 0);
 		return (0);
 	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/sgs/libelf/common/getphnum.c	Thu Nov 17 11:42:26 2005 -0800
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ *
+ * 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 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <string.h>
+#include <gelf.h>
+#include <decl.h>
+#include <msg.h>
+
+int
+elf_getphnum(Elf *elf, size_t *phnum)
+{
+	GElf_Ehdr	ehdr;
+	Elf_Scn		*scn;
+	GElf_Shdr	shdr0;
+
+	if (gelf_getehdr(elf, &ehdr) == NULL)
+		return (0);
+
+	if (ehdr.e_phnum != PN_XNUM) {
+		*phnum = ehdr.e_phnum;
+		return (1);
+	}
+
+	if ((scn = elf_getscn(elf, 0)) == NULL ||
+	    gelf_getshdr(scn, &shdr0) == NULL)
+		return (0);
+
+	if (shdr0.sh_info == 0)
+		*phnum = ehdr.e_phnum;
+	else
+		*phnum = shdr0.sh_info;
+
+	return (1);
+}
--- a/usr/src/cmd/sgs/libelf/common/llib-lelf	Thu Nov 17 08:46:01 2005 -0800
+++ b/usr/src/cmd/sgs/libelf/common/llib-lelf	Thu Nov 17 11:42:26 2005 -0800
@@ -23,7 +23,7 @@
 /* PROTOLIB1 */
 
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved. 
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved. 
  * Use is subject to license terms.
  */ 
 
@@ -144,6 +144,7 @@
 Elf_Data *	_elf_getdata(Elf_Scn *, Elf_Data *);
 char *		elf_getident(Elf *, size_t *);
 char *		_elf_getident(Elf *, size_t *);
+int		elf_getphnum(Elf *, size_t *);
 int		elf_getshnum(Elf *, size_t *);
 int		elf_getshstrndx(Elf *, size_t *);
 Elf_Scn *	elf_getscn(Elf *elf, size_t);
--- a/usr/src/cmd/sgs/libelf/demo/dcom.c	Thu Nov 17 08:46:01 2005 -0800
+++ b/usr/src/cmd/sgs/libelf/demo/dcom.c	Thu Nov 17 11:42:26 2005 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
@@ -101,6 +101,7 @@
 	GElf_Phdr	tphdr;
 	size_t		shstrndx;
 	size_t		shnum;
+	size_t		phnum;
 	int		*shndx;
 	int		ndx = 1;
 	int		off = 0;
@@ -124,6 +125,12 @@
 		return;
 	}
 
+	if (elf_getphnum(elf, &phnum) == 0) {
+		(void) fprintf(stderr, "%s: elf_getphnum() failed: %s\n",
+			file, elf_errmsg(0));
+		return;
+	}
+
 	/*
 	 * shndx is an array used to map the current section
 	 * indexes to the new section indexes.
@@ -313,14 +320,14 @@
 	/*
 	 * Duplicate all program headers contained in the ELF file.
 	 */
-	if (ehdr.e_phnum) {
-		if (gelf_newphdr(telf, ehdr.e_phnum) == 0) {
+	if (phnum != 0) {
+		if (gelf_newphdr(telf, phnum) == 0) {
 			(void) fprintf(stderr,
 				"%s: elf_newphdr() failed: %s\n",
 				file, elf_errmsg(0));
 			return;
 		}
-		for (ndx = 0; ndx < (int)ehdr.e_phnum; ndx++) {
+		for (ndx = 0; ndx < (int)phnum; ndx++) {
 			if (gelf_getphdr(elf, ndx, &phdr) == 0 ||
 			    gelf_getphdr(telf, ndx, &tphdr) == 0) {
 				(void) fprintf(stderr,
--- a/usr/src/cmd/sgs/libelf/spec/elf.spec	Thu Nov 17 08:46:01 2005 -0800
+++ b/usr/src/cmd/sgs/libelf/spec/elf.spec	Thu Nov 17 11:42:26 2005 -0800
@@ -27,6 +27,12 @@
 # cmd/sgs/libelf/spec/elf.spec
 
 
+function	elf_getphnum
+include		<libelf.h>
+declaration	int elf_getphnum(Elf *elf, size_t *phnum)
+version		SUNW_1.6
+end		
+
 function	elf_getshnum
 include		<libelf.h>
 declaration	int elf_getshnum(Elf *elf, size_t *shnum)
--- a/usr/src/cmd/sgs/libelf/spec/versions	Thu Nov 17 08:46:01 2005 -0800
+++ b/usr/src/cmd/sgs/libelf/spec/versions	Thu Nov 17 11:42:26 2005 -0800
@@ -30,6 +30,7 @@
 # (when it did contain symbols explicitly) may depend on it.
 #
 sparc {
+	SUNW_1.6:	{SUNW_1.5};
 	SUNW_1.5:	{SUNW_1.4};
 	SUNW_1.4:	{SUNW_1.3};
 	SUNW_1.3:	{SUNW_1.2};
@@ -39,6 +40,7 @@
 	SUNWprivate_1.1;
 }
 sparcv9 {
+	SUNW_1.6:	{SUNW_1.5};
 	SUNW_1.5:	{SUNW_1.4};
 	SUNW_1.4:	{SUNW_1.3};
 	SUNW_1.3:	{SUNW_1.2};
@@ -48,6 +50,7 @@
 	SUNWprivate_1.1;
 }
 i386 {
+	SUNW_1.6:	{SUNW_1.5};
 	SUNW_1.5:	{SUNW_1.4};
 	SUNW_1.4:	{SUNW_1.3};
 	SUNW_1.3:	{SUNW_1.2};
@@ -57,6 +60,7 @@
 	SUNWprivate_1.1;
 }
 amd64 {
+	SUNW_1.6:	{SUNW_1.5};
 	SUNW_1.5:	{SUNW_1.4};
 	SUNW_1.4:	{SUNW_1.3};
 	SUNW_1.3:	{SUNW_1.2};
--- a/usr/src/cmd/sgs/liblddbg/common/elf.c	Thu Nov 17 08:46:01 2005 -0800
+++ b/usr/src/cmd/sgs/liblddbg/common/elf.c	Thu Nov 17 11:42:26 2005 -0800
@@ -20,8 +20,8 @@
  * CDDL HEADER END
  */
 /*
- *	Copyright 1998-2003 Sun Microsystems, Inc.  All rights reserved.
- *	Use is subject to license terms.
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
  */
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
 
@@ -124,11 +124,16 @@
 		dbg_print(MSG_ORIG(MSG_ELF_SHOFF), EC_OFF(ehdr->e_shoff),
 		    ehdr->e_shentsize, ehdr->e_shnum);
 
-	dbg_print(MSG_ORIG(MSG_ELF_PHOFF), EC_OFF(ehdr->e_phoff),
-	    ehdr->e_phentsize, ehdr->e_phnum);
+	if (ehdr->e_phnum == PN_XNUM)
+		dbg_print(MSG_ORIG(MSG_ELFX_PHOFF), EC_OFF(ehdr->e_phoff),
+		    ehdr->e_phentsize);
+	else
+		dbg_print(MSG_ORIG(MSG_ELF_PHOFF), EC_OFF(ehdr->e_phoff),
+		    ehdr->e_phentsize, ehdr->e_phnum);
 
-	if ((ehdr->e_shnum != 0) || (shdr0 == NULL) ||
-	    (shdr0->sh_size == 0))
+	if (shdr0 == NULL ||
+	    (ehdr->e_phnum != PN_XNUM &&
+	    (ehdr->e_shnum != 0 || shdr0->sh_size)))
 		return;
 
 	/*
@@ -138,17 +143,27 @@
 	dbg_print(MSG_ORIG(MSG_SHD_ADDR), EC_ADDR(shdr0->sh_addr),
 	    /* LINTED */
 	    conv_secflg_str(ehdr->e_machine, shdr0->sh_flags));
-	dbg_print(MSG_ORIG(MSG_SHD0_SIZE), EC_XWORD(shdr0->sh_size),
-		conv_sectyp_str(ehdr->e_machine, shdr0->sh_type));
+	if (ehdr->e_shnum == 0)
+		dbg_print(MSG_ORIG(MSG_SHD0_SIZE), EC_XWORD(shdr0->sh_size),
+		    conv_sectyp_str(ehdr->e_machine, shdr0->sh_type));
+	else
+		dbg_print(MSG_ORIG(MSG_SHD_SIZE), EC_XWORD(shdr0->sh_size),
+		    conv_sectyp_str(ehdr->e_machine, shdr0->sh_type));
 	dbg_print(MSG_ORIG(MSG_SHD_OFFSET), EC_OFF(shdr0->sh_offset),
 	    EC_XWORD(shdr0->sh_entsize));
-	if (ehdr->e_shstrndx == SHN_XINDEX)
-		dbg_print(MSG_ORIG(MSG_SHD0_LINK), EC_WORD(shdr0->sh_link),
-		    /* LINTED */
-		    conv_secinfo_str(shdr0->sh_info, shdr0->sh_flags));
+
+	if (ehdr->e_shstrndx == SHN_XINDEX && ehdr->e_phnum == PN_XNUM)
+		dbg_print(MSG_ORIG(MSG_SHD0_LINK1), EC_WORD(shdr0->sh_link),
+		    EC_WORD(shdr0->sh_info));
+	else if (ehdr->e_shstrndx == SHN_XINDEX)
+		dbg_print(MSG_ORIG(MSG_SHD0_LINK2), EC_WORD(shdr0->sh_link),
+		    EC_WORD(shdr0->sh_info));
+	else if (ehdr->e_phnum == PN_XNUM)
+		dbg_print(MSG_ORIG(MSG_SHD0_LINK3), EC_WORD(shdr0->sh_link),
+		    EC_WORD(shdr0->sh_info));
 	else
-		dbg_print(MSG_ORIG(MSG_SHD_LINK), EC_WORD(shdr0->sh_link),
-		    /* LINTED */
-		    conv_secinfo_str(shdr0->sh_info, shdr0->sh_flags));
+		dbg_print(MSG_ORIG(MSG_SHD0_LINK4), EC_WORD(shdr0->sh_link),
+		    EC_WORD(shdr0->sh_info));
+
 	dbg_print(MSG_ORIG(MSG_SHD_ALIGN), EC_XWORD(shdr0->sh_addralign));
 }
--- a/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg	Thu Nov 17 08:46:01 2005 -0800
+++ b/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg	Thu Nov 17 11:42:26 2005 -0800
@@ -793,11 +793,16 @@
 			 e_shnum:    [sh[0].sh_size]"
 @ MSG_ELF_PHOFF		"  e_phoff:    %#18llx  e_phentsize:  %2d  \
 			 e_phnum:      %2d"
+@ MSG_ELFX_PHOFF	"  e_phoff:    %#18llx  e_phentsize:  %2d  \
+			 e_phnum:    [sh[0].sh_info]"
 
 # Shdr[0] messages
 @ MSG_SHD0_TITLE	"Section Header[0]: {ELF Ehdr extensions}"
 @ MSG_SHD0_SIZE		"    sh_size:      %-6lld [shnum]  sh_type:    %s"
-@ MSG_SHD0_LINK		"    sh_link:      %-6d [strndx] sh_info:    %s"
+@ MSG_SHD0_LINK1	"    sh_link:      %-6d [strndx] sh_info:    %d [phnum]"
+@ MSG_SHD0_LINK2	"    sh_link:      %-6d [strndx] sh_info:    %d"
+@ MSG_SHD0_LINK3	"    sh_link:      %-14d  sh_info:    %d [phnum]"
+@ MSG_SHD0_LINK4	"    sh_link:      %-14d  sh_info:    %d"
 
 # Section header messages
 
--- a/usr/src/cmd/sgs/packages/common/SUNWonld-README	Thu Nov 17 08:46:01 2005 -0800
+++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README	Thu Nov 17 11:42:26 2005 -0800
@@ -1068,3 +1068,4 @@
     Solaris/SunOS 5.8_x86	patch T109148-40
 --------------------------------------------------------------------------------
 6307274 crle bug with LD_LIBRARY_PATH
+6317969 elfheader limited to 65535 segments (link-editor components only)
--- a/usr/src/head/libelf.h	Thu Nov 17 08:46:01 2005 -0800
+++ b/usr/src/head/libelf.h	Thu Nov 17 11:42:26 2005 -0800
@@ -22,10 +22,9 @@
 /*	Copyright (c) 1988 AT&T	*/
 /*	  All Rights Reserved  	*/
 
-
 /*
- *	Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
- *	Use is subject to license terms.
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
  */
 
 #ifndef _LIBELF_H
@@ -192,6 +191,7 @@
 Elf32_Phdr	*elf32_getphdr	_((Elf *));
 Elf_Scn		*elf_getscn	_((Elf *elf, size_t));
 Elf32_Shdr	*elf32_getshdr	_((Elf_Scn *));
+int		elf_getphnum	_((Elf *, size_t *));
 int		elf_getshnum	_((Elf *, size_t *));
 int		elf_getshstrndx	_((Elf *, size_t *));
 unsigned long	elf_hash	_((const char *));
--- a/usr/src/lib/libproc/common/Pcontrol.h	Thu Nov 17 08:46:01 2005 -0800
+++ b/usr/src/lib/libproc/common/Pcontrol.h	Thu Nov 17 11:42:26 2005 -0800
@@ -53,15 +53,15 @@
  * These may change without affecting clients of libproc.
  */
 
-typedef struct {		/* symbol table */
+typedef struct sym_tbl {	/* symbol table */
 	Elf_Data *sym_data;	/* start of table */
 	size_t	sym_symn;	/* number of entries */
 	char	*sym_strs;	/* ptr to strings */
 	size_t	sym_strsz;	/* size of string table */
 	GElf_Shdr sym_hdr;	/* symbol table section header */
 	GElf_Shdr sym_strhdr;	/* string table section header */
-	Elf	*sym_elf;	/* faked-up elf handle from core file */
-	void	*sym_elfmem;	/* data for faked-up elf handle */
+	Elf	*sym_elf;	/* faked-up ELF handle from core file */
+	void	*sym_elfmem;	/* data for faked-up ELF handle */
 	uint_t	*sym_byname;	/* symbols sorted by name */
 	uint_t	*sym_byaddr;	/* symbols sorted by addr */
 	size_t	sym_count;	/* number of symbols in each sorted list */
@@ -79,8 +79,8 @@
 	rd_loadobj_t *file_lo;	/* load object structure from rtld_db */
 	char	*file_lname;	/* load object name from rtld_db */
 	char	*file_lbase;	/* pointer to basename of file_lname */
-	Elf	*file_elf;	/* elf handle so we can close */
-	void	*file_elfmem;	/* data for faked-up elf handle */
+	Elf	*file_elf;	/* ELF handle so we can close */
+	void	*file_elfmem;	/* data for faked-up ELF handle */
 	sym_tbl_t file_symtab;	/* symbol table */
 	sym_tbl_t file_dynsym;	/* dynamic symbol table */
 	uintptr_t file_dyn_base;	/* load address for ET_DYN files */
@@ -135,8 +135,25 @@
 #endif
 } core_info_t;
 
+typedef struct elf_file_header { /* extended ELF header */
+	unsigned char e_ident[EI_NIDENT];
+	Elf64_Half e_type;
+	Elf64_Half e_machine;
+	Elf64_Word e_version;
+	Elf64_Addr e_entry;
+	Elf64_Off e_phoff;
+	Elf64_Off e_shoff;
+	Elf64_Word e_flags;
+	Elf64_Half e_ehsize;
+	Elf64_Half e_phentsize;
+	Elf64_Half e_shentsize;
+	Elf64_Word e_phnum;	/* phdr count extended to 32 bits */
+	Elf64_Word e_shnum;	/* shdr count extended to 32 bits */
+	Elf64_Word e_shstrndx;	/* shdr string index extended to 32 bits */
+} elf_file_header_t;
+
 typedef struct elf_file {	/* convenience for managing ELF files */
-	GElf_Ehdr e_hdr;	/* ELF file header information */
+	elf_file_header_t e_hdr; /* Extended ELF header */
 	Elf *e_elf;		/* ELF library handle */
 	int e_fd;		/* file descriptor */
 } elf_file_t;
--- a/usr/src/lib/libproc/common/Pcore.c	Thu Nov 17 08:46:01 2005 -0800
+++ b/usr/src/lib/libproc/common/Pcore.c	Thu Nov 17 11:42:26 2005 -0800
@@ -800,7 +800,7 @@
  * in a memory backed elf file.
  */
 static void
-fake_up_symtab(struct ps_prochandle *P, GElf_Ehdr *ehdr,
+fake_up_symtab(struct ps_prochandle *P, const elf_file_header_t *ehdr,
     GElf_Shdr *symtab, GElf_Shdr *strtab)
 {
 	size_t size;
@@ -829,7 +829,12 @@
 		if ((b = calloc(1, size)) == NULL)
 			return;
 
-		(void) memcpy(&b->ehdr, ehdr, offsetof(GElf_Ehdr, e_entry));
+		(void) memcpy(b->ehdr.e_ident, ehdr->e_ident,
+		    sizeof (ehdr->e_ident));
+		b->ehdr.e_type = ehdr->e_type;
+		b->ehdr.e_machine = ehdr->e_machine;
+		b->ehdr.e_version = ehdr->e_version;
+		b->ehdr.e_flags = ehdr->e_flags;
 		b->ehdr.e_ehsize = sizeof (b->ehdr);
 		b->ehdr.e_shoff = sizeof (b->ehdr);
 		b->ehdr.e_shentsize = sizeof (b->shdr[0]);
@@ -888,7 +893,12 @@
 		if ((b = calloc(1, size)) == NULL)
 			return;
 
-		(void) memcpy(&b->ehdr, ehdr, offsetof(GElf_Ehdr, e_entry));
+		(void) memcpy(b->ehdr.e_ident, ehdr->e_ident,
+		    sizeof (ehdr->e_ident));
+		b->ehdr.e_type = ehdr->e_type;
+		b->ehdr.e_machine = ehdr->e_machine;
+		b->ehdr.e_version = ehdr->e_version;
+		b->ehdr.e_flags = ehdr->e_flags;
 		b->ehdr.e_ehsize = sizeof (b->ehdr);
 		b->ehdr.e_shoff = sizeof (b->ehdr);
 		b->ehdr.e_shentsize = sizeof (b->shdr[0]);
@@ -959,25 +969,6 @@
 }
 
 static void
-core_ehdr_to_gelf(const Elf32_Ehdr *src, GElf_Ehdr *dst)
-{
-	(void) memcpy(dst->e_ident, src->e_ident, EI_NIDENT);
-	dst->e_type = src->e_type;
-	dst->e_machine = src->e_machine;
-	dst->e_version = src->e_version;
-	dst->e_entry = (Elf64_Addr)src->e_entry;
-	dst->e_phoff = (Elf64_Off)src->e_phoff;
-	dst->e_shoff = (Elf64_Off)src->e_shoff;
-	dst->e_flags = src->e_flags;
-	dst->e_ehsize = src->e_ehsize;
-	dst->e_phentsize = src->e_phentsize;
-	dst->e_phnum = src->e_phnum;
-	dst->e_shentsize = src->e_shentsize;
-	dst->e_shnum = src->e_shnum;
-	dst->e_shstrndx = src->e_shstrndx;
-}
-
-static void
 core_phdr_to_gelf(const Elf32_Phdr *src, GElf_Phdr *dst)
 {
 	dst->p_type = src->p_type;
@@ -1044,24 +1035,180 @@
 
 	/*
 	 * If the file is 64-bit and we are 32-bit, fail with G_LP64.  If the
-	 * file is 64-bit and we are 64-bit, re-read the header as a Elf64_Ehdr.
-	 * Otherwise, the file is 32-bit, so convert e32 to a GElf_Ehdr.
+	 * file is 64-bit and we are 64-bit, re-read the header as a Elf64_Ehdr,
+	 * and convert it to a elf_file_header_t.  Otherwise, the file is
+	 * 32-bit, so convert e32 to a elf_file_header_t.
 	 */
 	if (e32.e_ident[EI_CLASS] == ELFCLASS64) {
 #ifdef _LP64
-		if (pread64(efp->e_fd, &efp->e_hdr,
-		    sizeof (GElf_Ehdr), 0) != sizeof (GElf_Ehdr)) {
+		Elf64_Ehdr e64;
+
+		if (pread64(efp->e_fd, &e64, sizeof (e64), 0) != sizeof (e64)) {
 			if (perr != NULL)
 				*perr = G_FORMAT;
 			goto err;
 		}
+
+		(void) memcpy(efp->e_hdr.e_ident, e64.e_ident, EI_NIDENT);
+		efp->e_hdr.e_type = e64.e_type;
+		efp->e_hdr.e_machine = e64.e_machine;
+		efp->e_hdr.e_version = e64.e_version;
+		efp->e_hdr.e_entry = e64.e_entry;
+		efp->e_hdr.e_phoff = e64.e_phoff;
+		efp->e_hdr.e_shoff = e64.e_shoff;
+		efp->e_hdr.e_flags = e64.e_flags;
+		efp->e_hdr.e_ehsize = e64.e_ehsize;
+		efp->e_hdr.e_phentsize = e64.e_phentsize;
+		efp->e_hdr.e_phnum = (Elf64_Word)e64.e_phnum;
+		efp->e_hdr.e_shentsize = e64.e_shentsize;
+		efp->e_hdr.e_shnum = (Elf64_Word)e64.e_shnum;
+		efp->e_hdr.e_shstrndx = (Elf64_Word)e64.e_shstrndx;
 #else	/* _LP64 */
 		if (perr != NULL)
 			*perr = G_LP64;
 		goto err;
 #endif	/* _LP64 */
-	} else
-		core_ehdr_to_gelf(&e32, &efp->e_hdr);
+	} else {
+		(void) memcpy(efp->e_hdr.e_ident, e32.e_ident, EI_NIDENT);
+		efp->e_hdr.e_type = e32.e_type;
+		efp->e_hdr.e_machine = e32.e_machine;
+		efp->e_hdr.e_version = e32.e_version;
+		efp->e_hdr.e_entry = (Elf64_Addr)e32.e_entry;
+		efp->e_hdr.e_phoff = (Elf64_Off)e32.e_phoff;
+		efp->e_hdr.e_shoff = (Elf64_Off)e32.e_shoff;
+		efp->e_hdr.e_flags = e32.e_flags;
+		efp->e_hdr.e_ehsize = e32.e_ehsize;
+		efp->e_hdr.e_phentsize = e32.e_phentsize;
+		efp->e_hdr.e_phnum = (Elf64_Word)e32.e_phnum;
+		efp->e_hdr.e_shentsize = e32.e_shentsize;
+		efp->e_hdr.e_shnum = (Elf64_Word)e32.e_shnum;
+		efp->e_hdr.e_shstrndx = (Elf64_Word)e32.e_shstrndx;
+	}
+
+	/*
+	 * If the number of section headers or program headers or the section
+	 * header string table index would overflow their respective fields
+	 * in the ELF header, they're stored in the section header at index
+	 * zero. To simplify use elsewhere, we look for those sentinel values
+	 * here.
+	 */
+	if ((efp->e_hdr.e_shnum == 0 && efp->e_hdr.e_shoff != 0) ||
+	    efp->e_hdr.e_shstrndx == SHN_XINDEX ||
+	    efp->e_hdr.e_phnum == PN_XNUM) {
+		GElf_Shdr shdr;
+
+		dprintf("extended ELF header\n");
+
+		if (efp->e_hdr.e_shoff == 0) {
+			if (perr != NULL)
+				*perr = G_FORMAT;
+			goto err;
+		}
+
+		if (efp->e_hdr.e_ident[EI_CLASS] == ELFCLASS32) {
+			Elf32_Shdr shdr32;
+
+			if (pread64(efp->e_fd, &shdr32, sizeof (shdr32),
+			    efp->e_hdr.e_shoff) != sizeof (shdr32)) {
+				if (perr != NULL)
+					*perr = G_FORMAT;
+				goto err;
+			}
+
+			core_shdr_to_gelf(&shdr32, &shdr);
+		} else {
+			if (pread64(efp->e_fd, &shdr, sizeof (shdr),
+			    efp->e_hdr.e_shoff) != sizeof (shdr)) {
+				if (perr != NULL)
+					*perr = G_FORMAT;
+				goto err;
+			}
+		}
+
+		if (efp->e_hdr.e_shnum == 0) {
+			efp->e_hdr.e_shnum = shdr.sh_size;
+			dprintf("section header count %lu\n",
+			    (ulong_t)shdr.sh_size);
+		}
+
+		if (efp->e_hdr.e_shstrndx == SHN_XINDEX) {
+			efp->e_hdr.e_shstrndx = shdr.sh_link;
+			dprintf("section string index %u\n", shdr.sh_link);
+		}
+
+		if (efp->e_hdr.e_phnum == PN_XNUM && shdr.sh_info != 0) {
+			efp->e_hdr.e_phnum = shdr.sh_info;
+			dprintf("program header count %u\n", shdr.sh_info);
+		}
+
+	} else if (efp->e_hdr.e_phoff != 0) {
+		GElf_Phdr phdr;
+		uint64_t phnum;
+
+		/*
+		 * It's possible this core file came from a system that
+		 * accidentally truncated the e_phnum field without correctly
+		 * using the extended format in the section header at index
+		 * zero. We try to detect and correct that specific type of
+		 * corruption by using the knowledge that the core dump
+		 * routines usually place the data referenced by the first
+		 * program header immediately after the last header element.
+		 */
+		if (efp->e_hdr.e_ident[EI_CLASS] == ELFCLASS32) {
+			Elf32_Phdr phdr32;
+
+			if (pread64(efp->e_fd, &phdr32, sizeof (phdr32),
+			    efp->e_hdr.e_phoff) != sizeof (phdr32)) {
+				if (perr != NULL)
+					*perr = G_FORMAT;
+				goto err;
+			}
+
+			core_phdr_to_gelf(&phdr32, &phdr);
+		} else {
+			if (pread64(efp->e_fd, &phdr, sizeof (phdr),
+			    efp->e_hdr.e_phoff) != sizeof (phdr)) {
+				if (perr != NULL)
+					*perr = G_FORMAT;
+				goto err;
+			}
+		}
+
+		phnum = phdr.p_offset - efp->e_hdr.e_ehsize -
+		    (uint64_t)efp->e_hdr.e_shnum * efp->e_hdr.e_shentsize;
+		phnum /= efp->e_hdr.e_phentsize;
+
+		if (phdr.p_offset != 0 && phnum != efp->e_hdr.e_phnum) {
+			dprintf("suspicious program header count %u %u\n",
+			    (uint_t)phnum, efp->e_hdr.e_phnum);
+
+			/*
+			 * If the new program header count we computed doesn't
+			 * jive with count in the ELF header, we'll use the
+			 * data that's there and hope for the best.
+			 *
+			 * If it does, it's also possible that the section
+			 * header offset is incorrect; we'll check that and
+			 * possibly try to fix it.
+			 */
+			if (phnum <= INT_MAX &&
+			    (uint16_t)phnum == efp->e_hdr.e_phnum) {
+
+				if (efp->e_hdr.e_shoff == efp->e_hdr.e_phoff +
+				    efp->e_hdr.e_phentsize *
+				    (uint_t)efp->e_hdr.e_phnum) {
+					efp->e_hdr.e_shoff =
+					    efp->e_hdr.e_phoff +
+					    efp->e_hdr.e_phentsize * phnum;
+				}
+
+				efp->e_hdr.e_phnum = (Elf64_Word)phnum;
+				dprintf("using new program header count\n");
+			} else {
+				dprintf("inconsistent program header count\n");
+			}
+		}
+	}
 
 	/*
 	 * The libelf implementation was never ported to be large-file aware.
@@ -1132,17 +1279,18 @@
 static map_info_t *
 core_find_text(struct ps_prochandle *P, Elf *elf, rd_loadobj_t *rlp)
 {
-	GElf_Ehdr ehdr;
 	GElf_Phdr phdr;
 	uint_t i;
+	size_t nphdrs;
 
-	if (gelf_getehdr(elf, &ehdr) != NULL) {
-		for (i = 0; i < ehdr.e_phnum; i++) {
-			if (gelf_getphdr(elf, i, &phdr) != NULL &&
-			    phdr.p_type == PT_LOAD && (phdr.p_flags & PF_X)) {
-				rlp->rl_base = phdr.p_vaddr;
-				return (Paddr2mptr(P, rlp->rl_base));
-			}
+	if (elf_getphnum(elf, &nphdrs) == 0)
+		return (NULL);
+
+	for (i = 0; i < nphdrs; i++) {
+		if (gelf_getphdr(elf, i, &phdr) != NULL &&
+		    phdr.p_type == PT_LOAD && (phdr.p_flags & PF_X)) {
+			rlp->rl_base = phdr.p_vaddr;
+			return (Paddr2mptr(P, rlp->rl_base));
 		}
 	}
 
@@ -1159,9 +1307,9 @@
 {
 	GElf_Ehdr ehdr;
 	GElf_Phdr phdr;
-
 	map_info_t *mp;
 	uint_t i, pagemask;
+	size_t nphdrs;
 
 	rlp->rl_data_base = NULL;
 
@@ -1169,16 +1317,17 @@
 	 * Find the first loadable, writeable Phdr and compute rl_data_base
 	 * as the virtual address at which is was loaded.
 	 */
-	if (gelf_getehdr(elf, &ehdr) != NULL) {
-		for (i = 0; i < ehdr.e_phnum; i++) {
-			if (gelf_getphdr(elf, i, &phdr) != NULL &&
-			    phdr.p_type == PT_LOAD && (phdr.p_flags & PF_W)) {
+	if (gelf_getehdr(elf, &ehdr) == NULL ||
+	    elf_getphnum(elf, &nphdrs) == 0)
+		return (NULL);
 
-				rlp->rl_data_base = phdr.p_vaddr;
-				if (ehdr.e_type == ET_DYN)
-					rlp->rl_data_base += rlp->rl_base;
-				break;
-			}
+	for (i = 0; i < nphdrs; i++) {
+		if (gelf_getphdr(elf, i, &phdr) != NULL &&
+		    phdr.p_type == PT_LOAD && (phdr.p_flags & PF_W)) {
+			rlp->rl_data_base = phdr.p_vaddr;
+			if (ehdr.e_type == ET_DYN)
+				rlp->rl_data_base += rlp->rl_base;
+			break;
 		}
 	}
 
@@ -1357,7 +1506,7 @@
 
 	if (efp->e_hdr.e_shstrndx >= efp->e_hdr.e_shnum) {
 		dprintf("corrupt shstrndx (%u) exceeds shnum (%u)\n",
-		    (uint_t)efp->e_hdr.e_shstrndx, (uint_t)efp->e_hdr.e_shnum);
+		    efp->e_hdr.e_shstrndx, efp->e_hdr.e_shnum);
 		return;
 	}
 
--- a/usr/src/lib/libproc/common/Pgcore.c	Thu Nov 17 08:46:01 2005 -0800
+++ b/usr/src/lib/libproc/common/Pgcore.c	Thu Nov 17 11:42:26 2005 -0800
@@ -46,6 +46,7 @@
 #include "P32ton.h"
 
 typedef enum {
+	STR_NONE,
 	STR_CTF,
 	STR_SYMTAB,
 	STR_DYNSYM,
@@ -56,6 +57,7 @@
 } shstrtype_t;
 
 static const char *shstrtab_data[] = {
+	"",
 	".SUNW_ctf",
 	".symtab",
 	".dynsym",
@@ -94,7 +96,7 @@
 {
 	int ret;
 
-	if ((ret = s->sst_ndx[type]) != 0)
+	if ((ret = s->sst_ndx[type]) != 0 || type == STR_NONE)
 		return (ret);
 
 	ret = s->sst_ndx[type] = s->sst_cur;
@@ -908,15 +910,12 @@
 	(void) shstrtab_ndx(&pgc->pgc_shstrtab, STR_SHSTRTAB);
 	size = shstrtab_size(s);
 
-	if (pwrite64(pgc->pgc_fd, "", 1, off) != 1)
-		return (1);
-
 	/*
 	 * Dump all the strings that we used being sure we include the
 	 * terminating null character.
 	 */
 	for (i = 0; i < STR_NUM; i++) {
-		if ((ndx = s->sst_ndx[i]) != 0) {
+		if ((ndx = s->sst_ndx[i]) != 0 || i == STR_NONE) {
 			const char *str = shstrtab_data[i];
 			size_t len = strlen(str) + 1;
 			if (pwrite64(pgc->pgc_fd, str, len, off + ndx) != len)
@@ -1020,6 +1019,14 @@
 		zonename[0] = '\0';
 
 	/*
+	 * The core file contents may required zero section headers, but if we
+	 * overflow the 16 bits allotted to the program header count in the ELF
+	 * header, we'll need that program header at index zero.
+	 */
+	if (nshdrs == 0 && nphdrs >= PN_XNUM)
+		nshdrs = 1;
+
+	/*
 	 * Set up the ELF header.
 	 */
 	if (P->status.pr_dmodel == PR_MODEL_ILP32) {
@@ -1046,26 +1053,38 @@
 
 		ehdr.e_version = EV_CURRENT;
 		ehdr.e_ehsize = sizeof (ehdr);
+
+		if (nphdrs >= PN_XNUM)
+			ehdr.e_phnum = PN_XNUM;
+		else
+			ehdr.e_phnum = (unsigned short)nphdrs;
+
 		ehdr.e_phentsize = sizeof (Elf32_Phdr);
-		ehdr.e_phnum = (unsigned short)nphdrs;
 		ehdr.e_phoff = ehdr.e_ehsize;
 
-		if (nshdrs != 0) {
+		if (nshdrs > 0) {
+			if (nshdrs >= SHN_LORESERVE)
+				ehdr.e_shnum = 0;
+			else
+				ehdr.e_shnum = (unsigned short)nshdrs;
+
+			if (nshdrs - 1 >= SHN_LORESERVE)
+				ehdr.e_shstrndx = SHN_XINDEX;
+			else
+				ehdr.e_shstrndx = (unsigned short)(nshdrs - 1);
+
 			ehdr.e_shentsize = sizeof (Elf32_Shdr);
-			ehdr.e_shnum = (unsigned short)nshdrs;
-			ehdr.e_shoff = ehdr.e_phoff +
-			    ehdr.e_phentsize * ehdr.e_phnum;
-			ehdr.e_shstrndx = nshdrs - 1;
+			ehdr.e_shoff = ehdr.e_phoff + ehdr.e_phentsize * nphdrs;
 		}
 
 		if (pwrite64(fd, &ehdr, sizeof (ehdr), 0) != sizeof (ehdr))
 			goto err;
 
 		poff = ehdr.e_phoff;
-		soff = ehdr.e_shoff + ehdr.e_shentsize;
+		soff = ehdr.e_shoff;
 		doff = boff = ehdr.e_ehsize +
-		    ehdr.e_phentsize * ehdr.e_phnum +
-		    ehdr.e_shentsize * ehdr.e_shnum;
+		    ehdr.e_phentsize * nphdrs +
+		    ehdr.e_shentsize * nshdrs;
 
 #ifdef _LP64
 	} else {
@@ -1092,31 +1111,52 @@
 
 		ehdr.e_version = EV_CURRENT;
 		ehdr.e_ehsize = sizeof (ehdr);
+
+		if (nphdrs >= PN_XNUM)
+			ehdr.e_phnum = PN_XNUM;
+		else
+			ehdr.e_phnum = (unsigned short)nphdrs;
+
 		ehdr.e_phentsize = sizeof (Elf64_Phdr);
-		ehdr.e_phnum = (unsigned short)nphdrs;
 		ehdr.e_phoff = ehdr.e_ehsize;
 
-		if (nshdrs != 0) {
+		if (nshdrs > 0) {
+			if (nshdrs >= SHN_LORESERVE)
+				ehdr.e_shnum = 0;
+			else
+				ehdr.e_shnum = (unsigned short)nshdrs;
+
+			if (nshdrs - 1 >= SHN_LORESERVE)
+				ehdr.e_shstrndx = SHN_XINDEX;
+			else
+				ehdr.e_shstrndx = (unsigned short)(nshdrs - 1);
+
 			ehdr.e_shentsize = sizeof (Elf64_Shdr);
-			ehdr.e_shnum = (unsigned short)nshdrs;
-			ehdr.e_shoff = ehdr.e_phoff +
-			    ehdr.e_phentsize * ehdr.e_phnum;
-			ehdr.e_shstrndx = nshdrs - 1;
+			ehdr.e_shoff = ehdr.e_phoff + ehdr.e_phentsize * nphdrs;
 		}
 
 		if (pwrite64(fd, &ehdr, sizeof (ehdr), 0) != sizeof (ehdr))
 			goto err;
 
 		poff = ehdr.e_phoff;
-		soff = ehdr.e_shoff + ehdr.e_shentsize;
-		doff = boff = sizeof (ehdr) +
-		    ehdr.e_phentsize * ehdr.e_phnum +
-		    ehdr.e_shentsize * ehdr.e_shnum;
+		soff = ehdr.e_shoff;
+		doff = boff = ehdr.e_ehsize +
+		    ehdr.e_phentsize * nphdrs +
+		    ehdr.e_shentsize * nshdrs;
 
 #endif	/* _LP64 */
 	}
 
 	/*
+	 * Write the zero indexed section if it exists.
+	 */
+	if (nshdrs > 0 && write_shdr(&pgc, STR_NONE, 0, 0, 0, 0,
+	    nshdrs >= SHN_LORESERVE ? nshdrs : 0,
+	    nshdrs - 1 >= SHN_LORESERVE ? nshdrs - 1 : 0,
+	    nphdrs >= PN_XNUM ? nphdrs : 0, 0, 0) != 0)
+		goto err;
+
+	/*
 	 * Construct the old-style note header and section.
 	 */
 
--- a/usr/src/lib/libproc/common/Pidle.c	Thu Nov 17 08:46:01 2005 -0800
+++ b/usr/src/lib/libproc/common/Pidle.c	Thu Nov 17 11:42:26 2005 -0800
@@ -113,6 +113,7 @@
 	struct ps_prochandle *P = NULL;
 	GElf_Ehdr ehdr;
 	Elf *elf = NULL;
+	size_t phnum;
 	file_info_t *fp = NULL;
 	int fd;
 	int i;
@@ -195,12 +196,17 @@
 		goto err;
 	}
 
-	dprintf("Pgrab_file: ehdr.e_phnum = %d\n", ehdr.e_phnum);
+	if (elf_getphnum(elf, &phnum) == 0) {
+		*perr = G_STRANGE;
+		goto err;
+	}
+
+	dprintf("Pgrab_file: program header count = %lu\n", (ulong_t)phnum);
 
 	/*
 	 * Sift through the program headers making the relevant maps.
 	 */
-	for (i = 0; i < ehdr.e_phnum; i++) {
+	for (i = 0; i < phnum; i++) {
 		GElf_Phdr phdr, *php;
 
 		if ((php = gelf_getphdr(elf, i, &phdr)) == NULL) {
--- a/usr/src/lib/libproc/common/Psymtab.c	Thu Nov 17 08:46:01 2005 -0800
+++ b/usr/src/lib/libproc/common/Psymtab.c	Thu Nov 17 11:42:26 2005 -0800
@@ -56,9 +56,11 @@
 static map_info_t *object_name_to_map(struct ps_prochandle *,
 	Lmid_t, const char *);
 static GElf_Sym *sym_by_name(sym_tbl_t *, const char *, GElf_Sym *, uint_t *);
-static int read_ehdr32(struct ps_prochandle *, Elf32_Ehdr *, uintptr_t);
+static int read_ehdr32(struct ps_prochandle *, Elf32_Ehdr *, uint_t *,
+    uintptr_t);
 #ifdef _LP64
-static int read_ehdr64(struct ps_prochandle *, Elf64_Ehdr *, uintptr_t);
+static int read_ehdr64(struct ps_prochandle *, Elf64_Ehdr *, uint_t *,
+    uintptr_t);
 #endif
 
 #define	DATA_TYPES	\
@@ -121,13 +123,14 @@
 	if (P->status.pr_dmodel == PR_MODEL_ILP32) {
 		Elf32_Ehdr ehdr;
 		Elf32_Phdr phdr;
-
-		if (read_ehdr32(P, &ehdr, mptr->map_pmap.pr_vaddr) != 0)
+		uint_t phnum;
+
+		if (read_ehdr32(P, &ehdr, &phnum, mptr->map_pmap.pr_vaddr) != 0)
 			return (fptr);
 
-		addrs = malloc(sizeof (uintptr_t) * ehdr.e_phnum * 2);
+		addrs = malloc(sizeof (uintptr_t) * phnum * 2);
 		a = mptr->map_pmap.pr_vaddr + ehdr.e_phoff;
-		for (i = 0; i < ehdr.e_phnum; i++, a += ehdr.e_phentsize) {
+		for (i = 0; i < phnum; i++, a += ehdr.e_phentsize) {
 			if (Pread(P, &phdr, sizeof (phdr), a) != sizeof (phdr))
 				goto out;
 			if (phdr.p_type != PT_LOAD || phdr.p_memsz == 0)
@@ -145,13 +148,14 @@
 	} else {
 		Elf64_Ehdr ehdr;
 		Elf64_Phdr phdr;
-
-		if (read_ehdr64(P, &ehdr, mptr->map_pmap.pr_vaddr) != 0)
+		uint_t phnum;
+
+		if (read_ehdr64(P, &ehdr, &phnum, mptr->map_pmap.pr_vaddr) != 0)
 			return (fptr);
 
-		addrs = malloc(sizeof (uintptr_t) * ehdr.e_phnum * 2);
+		addrs = malloc(sizeof (uintptr_t) * phnum * 2);
 		a = mptr->map_pmap.pr_vaddr + ehdr.e_phoff;
-		for (i = 0; i < ehdr.e_phnum; i++, a += ehdr.e_phentsize) {
+		for (i = 0; i < phnum; i++, a += ehdr.e_phentsize) {
 			if (Pread(P, &phdr, sizeof (phdr), a) != sizeof (phdr))
 				goto out;
 			if (phdr.p_type != PT_LOAD || phdr.p_memsz == 0)
@@ -935,7 +939,8 @@
 }
 
 static int
-read_ehdr32(struct ps_prochandle *P, Elf32_Ehdr *ehdr, uintptr_t addr)
+read_ehdr32(struct ps_prochandle *P, Elf32_Ehdr *ehdr, uint_t *phnum,
+    uintptr_t addr)
 {
 	if (Pread(P, ehdr, sizeof (*ehdr), addr) != sizeof (*ehdr))
 		return (-1);
@@ -953,16 +958,28 @@
 	    ehdr->e_ident[EI_VERSION] != EV_CURRENT)
 		return (-1);
 
+	if ((*phnum = ehdr->e_phnum) == PN_XNUM) {
+		Elf32_Shdr shdr0;
+
+		if (ehdr->e_shoff == 0 || ehdr->e_shentsize < sizeof (shdr0) ||
+		    Pread(P, &shdr0, sizeof (shdr0), addr + ehdr->e_shoff) !=
+		    sizeof (shdr0))
+			return (-1);
+
+		if (shdr0.sh_info != 0)
+			*phnum = shdr0.sh_info;
+	}
+
 	return (0);
 }
 
 static int
 read_dynamic_phdr32(struct ps_prochandle *P, const Elf32_Ehdr *ehdr,
-    Elf32_Phdr *phdr, uintptr_t addr)
+    uint_t phnum, Elf32_Phdr *phdr, uintptr_t addr)
 {
 	uint_t i;
 
-	for (i = 0; i < ehdr->e_phnum; i++) {
+	for (i = 0; i < phnum; i++) {
 		uintptr_t a = addr + ehdr->e_phoff + i * ehdr->e_phentsize;
 		if (Pread(P, phdr, sizeof (*phdr), a) != sizeof (*phdr))
 			return (-1);
@@ -976,7 +993,8 @@
 
 #ifdef _LP64
 static int
-read_ehdr64(struct ps_prochandle *P, Elf64_Ehdr *ehdr, uintptr_t addr)
+read_ehdr64(struct ps_prochandle *P, Elf64_Ehdr *ehdr, uint_t *phnum,
+    uintptr_t addr)
 {
 	if (Pread(P, ehdr, sizeof (Elf64_Ehdr), addr) != sizeof (Elf64_Ehdr))
 		return (-1);
@@ -994,16 +1012,28 @@
 	    ehdr->e_ident[EI_VERSION] != EV_CURRENT)
 		return (-1);
 
+	if ((*phnum = ehdr->e_phnum) == PN_XNUM) {
+		Elf64_Shdr shdr0;
+
+		if (ehdr->e_shoff == 0 || ehdr->e_shentsize < sizeof (shdr0) ||
+		    Pread(P, &shdr0, sizeof (shdr0), addr + ehdr->e_shoff) !=
+		    sizeof (shdr0))
+			return (-1);
+
+		if (shdr0.sh_info != 0)
+			*phnum = shdr0.sh_info;
+	}
+
 	return (0);
 }
 
 static int
 read_dynamic_phdr64(struct ps_prochandle *P, const Elf64_Ehdr *ehdr,
-    Elf64_Phdr *phdr, uintptr_t addr)
+    uint_t phnum, Elf64_Phdr *phdr, uintptr_t addr)
 {
 	uint_t i;
 
-	for (i = 0; i < ehdr->e_phnum; i++) {
+	for (i = 0; i < phnum; i++) {
 		uintptr_t a = addr + ehdr->e_phoff + i * ehdr->e_phentsize;
 		if (Pread(P, phdr, sizeof (*phdr), a) != sizeof (*phdr))
 			return (-1);
@@ -1113,10 +1143,10 @@
 		Elf32_Ehdr ehdr;
 		Elf32_Phdr phdr;
 		Elf32_Dyn dync, *dynp;
-		uint_t i;
-
-		if (read_ehdr32(P, &ehdr, addr) != 0 ||
-		    read_dynamic_phdr32(P, &ehdr, &phdr, addr) != 0)
+		uint_t phnum, i;
+
+		if (read_ehdr32(P, &ehdr, &phnum, addr) != 0 ||
+		    read_dynamic_phdr32(P, &ehdr, phnum, &phdr, addr) != 0)
 			return (0);
 
 		if (ehdr.e_type == ET_DYN)
@@ -1148,10 +1178,10 @@
 		Elf64_Ehdr ehdr;
 		Elf64_Phdr phdr;
 		Elf64_Dyn dync, *dynp;
-		uint_t i;
-
-		if (read_ehdr64(P, &ehdr, addr) != 0 ||
-		    read_dynamic_phdr64(P, &ehdr, &phdr, addr) != 0)
+		uint_t phnum, i;
+
+		if (read_ehdr64(P, &ehdr, &phnum, addr) != 0 ||
+		    read_dynamic_phdr64(P, &ehdr, phnum, &phdr, addr) != 0)
 			return (0);
 
 		if (ehdr.e_type == ET_DYN)
@@ -1287,12 +1317,12 @@
 		Elf32_Shdr *sp;
 		Elf32_Dyn *dp;
 		Elf32_Dyn *d[DI_NENT] = { 0 };
-		uint_t i, dcount = 0;
+		uint_t phnum, i, dcount = 0;
 		uint32_t off;
 		size_t pltsz = 0, pltentsz;
 
-		if (read_ehdr32(P, &ehdr, addr) != 0 ||
-		    read_dynamic_phdr32(P, &ehdr, &phdr, addr) != 0)
+		if (read_ehdr32(P, &ehdr, &phnum, addr) != 0 ||
+		    read_dynamic_phdr32(P, &ehdr, phnum, &phdr, addr) != 0)
 			return (NULL);
 
 		if (ehdr.e_type == ET_DYN)
@@ -1382,7 +1412,7 @@
 		size = sizeof (Elf32_Ehdr);
 
 		/* program headers from in-core elf fragment */
-		size += ehdr.e_phnum * ehdr.e_phentsize;
+		size += phnum * ehdr.e_phentsize;
 
 		/* unused shdr, and .shstrtab section */
 		size += sizeof (Elf32_Shdr);
@@ -1457,8 +1487,8 @@
 		ep->e_ehsize = sizeof (Elf32_Ehdr);
 		ep->e_phoff = sizeof (Elf32_Ehdr);
 		ep->e_phentsize = ehdr.e_phentsize;
-		ep->e_phnum = ehdr.e_phnum;
-		ep->e_shoff = ep->e_phoff + ep->e_phnum * ep->e_phentsize;
+		ep->e_phnum = phnum;
+		ep->e_shoff = ep->e_phoff + phnum * ep->e_phentsize;
 		ep->e_shentsize = sizeof (Elf32_Shdr);
 		ep->e_shnum = (pltsz == 0) ? 5 : 6;
 		ep->e_shstrndx = 1;
@@ -1472,9 +1502,8 @@
 		 * address space is a little suspect, but since we only
 		 * use them for their address and size values, this is fine.
 		 */
-		if (Pread(P, &elfdata[ep->e_phoff],
-		    ep->e_phnum * ep->e_phentsize, addr + ehdr.e_phoff) !=
-		    ep->e_phnum * ep->e_phentsize) {
+		if (Pread(P, &elfdata[ep->e_phoff], phnum * ep->e_phentsize,
+		    addr + ehdr.e_phoff) != phnum * ep->e_phentsize) {
 			free(elfdata);
 			goto bad32;
 		}
@@ -1610,12 +1639,12 @@
 		Elf64_Shdr *sp;
 		Elf64_Dyn *dp;
 		Elf64_Dyn *d[DI_NENT] = { 0 };
-		uint_t i, dcount = 0;
+		uint_t phnum, i, dcount = 0;
 		uint64_t off;
 		size_t pltsz = 0, pltentsz;
 
-		if (read_ehdr64(P, &ehdr, addr) != 0 ||
-		    read_dynamic_phdr64(P, &ehdr, &phdr, addr) != 0)
+		if (read_ehdr64(P, &ehdr, &phnum, addr) != 0 ||
+		    read_dynamic_phdr64(P, &ehdr, phnum, &phdr, addr) != 0)
 			return (NULL);
 
 		if (ehdr.e_type == ET_DYN)
@@ -1705,7 +1734,7 @@
 		size = sizeof (Elf64_Ehdr);
 
 		/* program headers from in-core elf fragment */
-		size += ehdr.e_phnum * ehdr.e_phentsize;
+		size += phnum * ehdr.e_phentsize;
 
 		/* unused shdr, and .shstrtab section */
 		size += sizeof (Elf64_Shdr);
@@ -1780,8 +1809,8 @@
 		ep->e_ehsize = sizeof (Elf64_Ehdr);
 		ep->e_phoff = sizeof (Elf64_Ehdr);
 		ep->e_phentsize = ehdr.e_phentsize;
-		ep->e_phnum = ehdr.e_phnum;
-		ep->e_shoff = ep->e_phoff + ep->e_phnum * ep->e_phentsize;
+		ep->e_phnum = phnum;
+		ep->e_shoff = ep->e_phoff + phnum * ep->e_phentsize;
 		ep->e_shentsize = sizeof (Elf64_Shdr);
 		ep->e_shnum = (pltsz == 0) ? 5 : 6;
 		ep->e_shstrndx = 1;
@@ -1795,9 +1824,8 @@
 		 * address space is a little suspect, but since we only
 		 * use them for their address and size values, this is fine.
 		 */
-		if (Pread(P, &elfdata[ep->e_phoff],
-		    ep->e_phnum * ep->e_phentsize, addr + ehdr.e_phoff) !=
-		    ep->e_phnum * ep->e_phentsize) {
+		if (Pread(P, &elfdata[ep->e_phoff], phnum * ep->e_phentsize,
+		    addr + ehdr.e_phoff) != phnum * ep->e_phentsize) {
 			free(elfdata);
 			goto bad64;
 		}
@@ -2100,6 +2128,7 @@
 	Elf_Data *shdata;
 	Elf_Scn *scn;
 	Elf *elf;
+	size_t nshdrs, shstrndx;
 
 	struct {
 		GElf_Shdr c_shdr;
@@ -2150,7 +2179,9 @@
 		if ((elf = fake_elf(P, fptr)) == NULL ||
 		    elf_kind(elf) != ELF_K_ELF ||
 		    gelf_getehdr(elf, &ehdr) == NULL ||
-		    (scn = elf_getscn(elf, ehdr.e_shstrndx)) == NULL ||
+		    elf_getshnum(elf, &nshdrs) == 0 ||
+		    elf_getshstrndx(elf, &shstrndx) == 0 ||
+		    (scn = elf_getscn(elf, shstrndx)) == NULL ||
 		    (shdata = elf_getdata(scn, NULL)) == NULL) {
 			dprintf("failed to fake up ELF file\n");
 			return;
@@ -2159,7 +2190,9 @@
 	} else if ((elf = elf_begin(fptr->file_fd, ELF_C_READ, NULL)) == NULL ||
 	    elf_kind(elf) != ELF_K_ELF ||
 	    gelf_getehdr(elf, &ehdr) == NULL ||
-	    (scn = elf_getscn(elf, ehdr.e_shstrndx)) == NULL ||
+	    elf_getshnum(elf, &nshdrs) == 0 ||
+	    elf_getshstrndx(elf, &shstrndx) == 0 ||
+	    (scn = elf_getscn(elf, shstrndx)) == NULL ||
 	    (shdata = elf_getdata(scn, NULL)) == NULL) {
 		dprintf("failed to process ELF file %s: %s\n",
 		    objectfile, elf_errmsg(elf_errno()));
@@ -2167,7 +2200,9 @@
 		if ((elf = fake_elf(P, fptr)) == NULL ||
 		    elf_kind(elf) != ELF_K_ELF ||
 		    gelf_getehdr(elf, &ehdr) == NULL ||
-		    (scn = elf_getscn(elf, ehdr.e_shstrndx)) == NULL ||
+		    elf_getshnum(elf, &nshdrs) == 0 ||
+		    elf_getshstrndx(elf, &shstrndx) == 0 ||
+		    (scn = elf_getscn(elf, shstrndx)) == NULL ||
 		    (shdata = elf_getdata(scn, NULL)) == NULL) {
 			dprintf("failed to fake up ELF file\n");
 			goto bad;
@@ -2190,7 +2225,9 @@
 		if ((newelf = fake_elf(P, fptr)) == NULL ||
 		    elf_kind(newelf) != ELF_K_ELF ||
 		    gelf_getehdr(newelf, &ehdr) == NULL ||
-		    (scn = elf_getscn(newelf, ehdr.e_shstrndx)) == NULL ||
+		    elf_getshnum(newelf, &nshdrs) == 0 ||
+		    elf_getshstrndx(newelf, &shstrndx) == 0 ||
+		    (scn = elf_getscn(newelf, shstrndx)) == NULL ||
 		    (shdata = elf_getdata(scn, NULL)) == NULL) {
 			dprintf("failed to fake up ELF file\n");
 		} else {
@@ -2201,7 +2238,7 @@
 		}
 	}
 
-	if ((cache = malloc(ehdr.e_shnum * sizeof (*cache))) == NULL) {
+	if ((cache = malloc(nshdrs * sizeof (*cache))) == NULL) {
 		dprintf("failed to malloc section cache for %s\n", objectfile);
 		goto bad;
 	}
@@ -2232,7 +2269,7 @@
 	 * Now iterate through the section cache in order to locate info
 	 * for the .symtab, .dynsym, .dynamic, .plt, and .SUNW_ctf sections:
 	 */
-	for (i = 1, cp = cache + 1; i < ehdr.e_shnum; i++, cp++) {
+	for (i = 1, cp = cache + 1; i < nshdrs; i++, cp++) {
 		GElf_Shdr *shp = &cp->c_shdr;
 
 		if (shp->sh_type == SHT_SYMTAB || shp->sh_type == SHT_DYNSYM) {
@@ -2272,7 +2309,7 @@
 			 * to haunt us later.
 			 */
 			if (shp->sh_link == 0 ||
-			    shp->sh_link > ehdr.e_shnum ||
+			    shp->sh_link >= nshdrs ||
 			    (cache[shp->sh_link].c_shdr.sh_type != SHT_DYNSYM &&
 			    cache[shp->sh_link].c_shdr.sh_type != SHT_SYMTAB)) {
 				dprintf("Bad sh_link %d for "
--- a/usr/src/uts/common/exec/elf/elf.c	Thu Nov 17 08:46:01 2005 -0800
+++ b/usr/src/uts/common/exec/elf/elf.c	Thu Nov 17 11:42:26 2005 -0800
@@ -69,12 +69,13 @@
 #define	ORIGIN_STR	"ORIGIN"
 #define	ORIGIN_STR_SIZE	6
 
-static int getelfhead(vnode_t *, cred_t *, Ehdr *);
-static int getelfphdr(vnode_t *, cred_t *, const Ehdr *, caddr_t *, ssize_t *);
-static int getelfshdr(vnode_t *, cred_t *, const Ehdr *, caddr_t *, ssize_t *,
-    caddr_t *, ssize_t *);
-static size_t elfsize(Ehdr *, caddr_t, uintptr_t *);
-static int mapelfexec(vnode_t *, Ehdr *, caddr_t,
+static int getelfhead(vnode_t *, cred_t *, Ehdr *, int *, int *, int *);
+static int getelfphdr(vnode_t *, cred_t *, const Ehdr *, int, caddr_t *,
+    ssize_t *);
+static int getelfshdr(vnode_t *, cred_t *, const Ehdr *, int, int, caddr_t *,
+    ssize_t *, caddr_t *, ssize_t *);
+static size_t elfsize(Ehdr *, int, caddr_t, uintptr_t *);
+static int mapelfexec(vnode_t *, Ehdr *, int, caddr_t,
     Phdr **, Phdr **, Phdr **, Phdr **, Phdr *,
     caddr_t *, caddr_t *, intptr_t *, size_t, long *, size_t *);
 
@@ -199,7 +200,8 @@
 		struct vattr	vattr;
 		struct execenv	exenv;
 	} *bigwad;	/* kmem_alloc this behemoth so we don't blow stack */
-	Ehdr	*ehdrp;
+	Ehdr		*ehdrp;
+	int		nshdrs, shstrndx, nphdrs;
 	char		*dlnp;
 	char		*pathbufp;
 	rlim64_t	limit;
@@ -215,8 +217,10 @@
 	/*
 	 * Obtain ELF and program header information.
 	 */
-	if ((error = getelfhead(vp, CRED(), ehdrp)) != 0 ||
-	    (error = getelfphdr(vp, CRED(), ehdrp, &phdrbase, &phdrsize)) != 0)
+	if ((error = getelfhead(vp, CRED(), ehdrp, &nshdrs, &shstrndx,
+	    &nphdrs)) != 0 ||
+	    (error = getelfphdr(vp, CRED(), ehdrp, nphdrs, &phdrbase,
+	    &phdrsize)) != 0)
 		goto out;
 
 	/*
@@ -250,7 +254,7 @@
 	 */
 	hsize = ehdrp->e_phentsize;
 	phdrp = (Phdr *)phdrbase;
-	for (i = ehdrp->e_phnum; i > 0; i--) {
+	for (i = nphdrs; i > 0; i--) {
 		switch (phdrp->p_type) {
 		case PT_INTERP:
 			hasauxv = hasdy = 1;
@@ -358,15 +362,15 @@
 	 * determine its memory size so that mapelfexec() can load it.
 	 */
 	if (ehdrp->e_type == ET_DYN)
-		len = elfsize(ehdrp, phdrbase, NULL);
+		len = elfsize(ehdrp, nphdrs, phdrbase, NULL);
 	else
 		len = 0;
 
 	dtrphdr = NULL;
 
-	if ((error = mapelfexec(vp, ehdrp, phdrbase, &uphdr, &dyphdr, &stphdr,
-	    &dtrphdr, dataphdrp, &bssbase, &brkbase, &voffset, len, execsz,
-	    &brksize)) != 0)
+	if ((error = mapelfexec(vp, ehdrp, nphdrs, phdrbase, &uphdr, &dyphdr,
+	    &stphdr, &dtrphdr, dataphdrp, &bssbase, &brkbase, &voffset, len,
+	    execsz, &brksize)) != 0)
 		goto bad;
 
 	if (uphdr != NULL && dyphdr == NULL)
@@ -483,7 +487,7 @@
 
 			ADDAUX(aux, AT_PHDR, uphdr->p_vaddr + voffset)
 			ADDAUX(aux, AT_PHENT, ehdrp->e_phentsize)
-			ADDAUX(aux, AT_PHNUM, ehdrp->e_phnum)
+			ADDAUX(aux, AT_PHNUM, nphdrs)
 			ADDAUX(aux, AT_ENTRY, ehdrp->e_entry + voffset)
 		} else {
 			if ((error = execopen(&vp, &fd)) != 0) {
@@ -506,8 +510,9 @@
 		 */
 		kmem_free(phdrbase, phdrsize);
 		phdrbase = NULL;
-		if ((error = getelfhead(nvp, CRED(), ehdrp)) != 0 ||
-		    (error = getelfphdr(nvp, CRED(), ehdrp, &phdrbase,
+		if ((error = getelfhead(nvp, CRED(), ehdrp, &nshdrs,
+		    &shstrndx, &nphdrs)) != 0 ||
+		    (error = getelfphdr(nvp, CRED(), ehdrp, nphdrs, &phdrbase,
 		    &phdrsize)) != 0) {
 			VN_RELE(nvp);
 			uprintf("%s: Cannot read %s\n", exec_file, dlnp);
@@ -520,7 +525,7 @@
 		 * address of a hole, in the user's address space, large
 		 * enough to map the "interpreter".
 		 */
-		if ((len = elfsize(ehdrp, phdrbase, &lddata)) == 0) {
+		if ((len = elfsize(ehdrp, nphdrs, phdrbase, &lddata)) == 0) {
 			VN_RELE(nvp);
 			uprintf("%s: Nothing to load in %s\n", exec_file, dlnp);
 			goto bad;
@@ -528,8 +533,9 @@
 
 		dtrphdr = NULL;
 
-		error = mapelfexec(nvp, ehdrp, phdrbase, &junk, &junk, &junk,
-		    &dtrphdr, NULL, NULL, NULL, &voffset, len, execsz, NULL);
+		error = mapelfexec(nvp, ehdrp, nphdrs, phdrbase, &junk, &junk,
+		    &junk, &dtrphdr, NULL, NULL, NULL, &voffset, len, execsz,
+		    NULL);
 		if (error || junk != NULL) {
 			VN_RELE(nvp);
 			uprintf("%s: Cannot map %s\n", exec_file, dlnp);
@@ -681,7 +687,7 @@
  * Compute the memory size requirement for the ELF file.
  */
 static size_t
-elfsize(Ehdr *ehdrp, caddr_t phdrbase, uintptr_t *lddata)
+elfsize(Ehdr *ehdrp, int nphdrs, caddr_t phdrbase, uintptr_t *lddata)
 {
 	size_t	len;
 	Phdr	*phdrp = (Phdr *)phdrbase;
@@ -693,7 +699,7 @@
 	uintptr_t lo, hi;
 	int	i;
 
-	for (i = ehdrp->e_phnum; i > 0; i--) {
+	for (i = nphdrs; i > 0; i--) {
 		if (phdrp->p_type == PT_LOAD) {
 			lo = phdrp->p_vaddr;
 			hi = lo + phdrp->p_memsz;
@@ -735,7 +741,8 @@
  *	EINVAL	Format recognized but execution not supported
  */
 static int
-getelfhead(vnode_t *vp, cred_t *credp, Ehdr *ehdr)
+getelfhead(vnode_t *vp, cred_t *credp, Ehdr *ehdr, int *nshdrs, int *shstrndx,
+    int *nphdrs)
 {
 	int error;
 	ssize_t resid;
@@ -758,6 +765,7 @@
 	    ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
 	    ehdr->e_ident[EI_MAG3] != ELFMAG3)
 		return (ENOEXEC);
+
 	if ((ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) ||
 #if defined(_ILP32) || defined(_ELF32_COMPAT)
 	    ehdr->e_ident[EI_CLASS] != ELFCLASS32 ||
@@ -765,9 +773,38 @@
 	    ehdr->e_ident[EI_CLASS] != ELFCLASS64 ||
 #endif
 	    !elfheadcheck(ehdr->e_ident[EI_DATA], ehdr->e_machine,
-		ehdr->e_flags))
+	    ehdr->e_flags))
 		return (EINVAL);
 
+	*nshdrs = ehdr->e_shnum;
+	*shstrndx = ehdr->e_shstrndx;
+	*nphdrs = ehdr->e_phnum;
+
+	/*
+	 * If e_shnum, e_shstrndx, or e_phnum is its sentinel value, we need
+	 * to read in the section header at index zero to acces the true
+	 * values for those fields.
+	 */
+	if ((*nshdrs == 0 && ehdr->e_shoff != 0) ||
+	    *shstrndx == SHN_XINDEX || *nphdrs == PN_XNUM) {
+		Shdr shdr;
+
+		if (ehdr->e_shoff == 0)
+			return (EINVAL);
+
+		if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)&shdr,
+		    sizeof (shdr), (offset_t)ehdr->e_shoff, UIO_SYSSPACE, 0,
+		    (rlim64_t)0, credp, &resid)) != 0)
+			return (error);
+
+		if (*nshdrs == 0)
+			*nshdrs = shdr.sh_size;
+		if (*shstrndx == SHN_XINDEX)
+			*shstrndx = shdr.sh_link;
+		if (*nphdrs == PN_XNUM && shdr.sh_info != 0)
+			*nphdrs = shdr.sh_info;
+	}
+
 	return (0);
 }
 
@@ -778,7 +815,7 @@
 #endif
 
 static int
-getelfphdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr,
+getelfphdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr, int nphdrs,
     caddr_t *phbasep, ssize_t *phsizep)
 {
 	ssize_t resid, minsize;
@@ -800,7 +837,7 @@
 	if (ehdr->e_phentsize < minsize || (ehdr->e_phentsize & 3))
 		return (EINVAL);
 
-	*phsizep = ehdr->e_phnum * ehdr->e_phentsize;
+	*phsizep = nphdrs * ehdr->e_phentsize;
 
 	if (*phsizep > sizeof (Phdr) * elf_nphdr_max) {
 		if ((*phbasep = kmem_alloc(*phsizep, KM_NOSLEEP)) == NULL)
@@ -831,7 +868,7 @@
 
 static int
 getelfshdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr,
-    caddr_t *shbasep, ssize_t *shsizep,
+    int nshdrs, int shstrndx, caddr_t *shbasep, ssize_t *shsizep,
     char **shstrbasep, ssize_t *shstrsizep)
 {
 	ssize_t resid, minsize;
@@ -843,15 +880,15 @@
 	 * array of section headers, it must be 8-byte aligned or else
 	 * a we might cause a misaligned access. We use all members through
 	 * sh_entsize (on both 32- and 64-bit ELF files) so e_shentsize
-	 * must be at least large enough to include that member. The
-	 * index of the string table section must be valid.
+	 * must be at least large enough to include that member. The index
+	 * of the string table section must also be valid.
 	 */
 	minsize = offsetof(Shdr, sh_entsize) + sizeof (shdr->sh_entsize);
 	if (ehdr->e_shentsize < minsize || (ehdr->e_shentsize & 3) ||
-	    ehdr->e_shstrndx >= ehdr->e_shnum)
+	    shstrndx >= nshdrs)
 		return (EINVAL);
 
-	*shsizep = ehdr->e_shnum * ehdr->e_shentsize;
+	*shsizep = nshdrs * ehdr->e_shentsize;
 
 	if (*shsizep > sizeof (Shdr) * elf_nshdr_max) {
 		if ((*shbasep = kmem_alloc(*shsizep, KM_NOSLEEP)) == NULL)
@@ -871,7 +908,7 @@
 	 * Pull the section string table out of the vnode; fail if the size
 	 * is zero.
 	 */
-	shdr = (Shdr *)(*shbasep + ehdr->e_shstrndx * ehdr->e_shentsize);
+	shdr = (Shdr *)(*shbasep + shstrndx * ehdr->e_shentsize);
 	if ((*shstrsizep = shdr->sh_size) == 0) {
 		kmem_free(*shbasep, *shsizep);
 		return (EINVAL);
@@ -908,6 +945,7 @@
 mapelfexec(
 	vnode_t *vp,
 	Ehdr *ehdr,
+	int nphdrs,
 	caddr_t phdrbase,
 	Phdr **uphdr,
 	Phdr **dyphdr,
@@ -943,7 +981,7 @@
 		*voffset = 0;
 	}
 	phdr = (Phdr *)phdrbase;
-	for (i = (int)ehdr->e_phnum; i > 0; i--) {
+	for (i = nphdrs; i > 0; i--) {
 		switch (phdr->p_type) {
 		case PT_LOAD:
 			if ((*dyphdr != NULL) && (*uphdr == NULL))
@@ -1175,6 +1213,7 @@
 		size_t segsize;
 
 		Ehdr ehdr;
+		int nshdrs, shstrndx, nphdrs;
 		caddr_t shbase;
 		ssize_t shsize;
 		char *shstrbase;
@@ -1212,13 +1251,14 @@
 		if ((prot & (PROT_WRITE | PROT_EXEC)) != PROT_EXEC)
 			continue;
 
-		if (getelfhead(mvp, credp, &ehdr) != 0 ||
-		    getelfshdr(mvp, credp, &ehdr, &shbase, &shsize,
-		    &shstrbase, &shstrsize) != 0)
+		if (getelfhead(mvp, credp, &ehdr, &nshdrs, &shstrndx,
+		    &nphdrs) != 0 ||
+		    getelfshdr(mvp, credp, &ehdr, nshdrs, shstrndx,
+		    &shbase, &shsize, &shstrbase, &shstrsize) != 0)
 			continue;
 
 		off = ehdr.e_shentsize;
-		for (j = 1; j < ehdr.e_shnum; j++, off += ehdr.e_shentsize) {
+		for (j = 1; j < nshdrs; j++, off += ehdr.e_shentsize) {
 			Shdr *symtab = NULL, *strtab;
 
 			shdr = (Shdr *)(shbase + off);
@@ -1234,7 +1274,7 @@
 					continue;
 
 				if (shdr->sh_link > 0 &&
-				    shdr->sh_link < ehdr.e_shnum) {
+				    shdr->sh_link < nshdrs) {
 					symtab = (Shdr *)(shbase +
 					    shdr->sh_link * ehdr.e_shentsize);
 				}
@@ -1298,7 +1338,7 @@
 				if ((symtab->sh_type != SHT_DYNSYM &&
 				    symtab->sh_type != SHT_SYMTAB) ||
 				    symtab->sh_link == 0 ||
-				    symtab->sh_link >= ehdr.e_shnum)
+				    symtab->sh_link >= nshdrs)
 					continue;
 
 				strtab = (Shdr *)(shbase +
@@ -1476,6 +1516,16 @@
 	}
 	AS_LOCK_EXIT(as, &as->a_lock);
 
+	ASSERT(nshdrs == 0 || nshdrs > 1);
+
+	/*
+	 * The core file contents may required zero section headers, but if
+	 * we overflow the 16 bits allotted to the program header count in
+	 * the ELF header, we'll need that program header at index zero.
+	 */
+	if (nshdrs == 0 && nphdrs >= PN_XNUM)
+		nshdrs = 1;
+
 	phdrsz = nphdrs * sizeof (Phdr);
 	shdrsz = nshdrs * sizeof (Shdr);
 
@@ -1518,18 +1568,37 @@
 
 #endif	/* !defined(_LP64) || defined(_ELF32_COMPAT) */
 
+	/*
+	 * If the count of program headers or section headers or the index
+	 * of the section string table can't fit in the mere 16 bits
+	 * shortsightedly allotted to them in the ELF header, we use the
+	 * extended formats and put the real values in the section header
+	 * as index 0.
+	 */
 	ehdr->e_version = EV_CURRENT;
-	ehdr->e_phoff = sizeof (Ehdr);
 	ehdr->e_ehsize = sizeof (Ehdr);
+
+	if (nphdrs >= PN_XNUM)
+		ehdr->e_phnum = PN_XNUM;
+	else
+		ehdr->e_phnum = (unsigned short)nphdrs;
+
+	ehdr->e_phoff = sizeof (Ehdr);
 	ehdr->e_phentsize = sizeof (Phdr);
-	ehdr->e_phnum = (unsigned short)nphdrs;
 
 	if (nshdrs > 0) {
-		ehdr->e_shstrndx = (unsigned short)(nshdrs - 1);
+		if (nshdrs >= SHN_LORESERVE)
+			ehdr->e_shnum = 0;
+		else
+			ehdr->e_shnum = (unsigned short)nshdrs;
+
+		if (nshdrs - 1 >= SHN_LORESERVE)
+			ehdr->e_shstrndx = SHN_XINDEX;
+		else
+			ehdr->e_shstrndx = (unsigned short)(nshdrs - 1);
+
+		ehdr->e_shoff = ehdr->e_phoff + ehdr->e_phentsize * nphdrs;
 		ehdr->e_shentsize = sizeof (Shdr);
-		ehdr->e_shnum = (unsigned short)nshdrs;
-		ehdr->e_shoff = ehdr->e_phoff +
-		    ehdr->e_phentsize * ehdr->e_phnum;
 	}
 
 	if (error = core_write(vp, UIO_SYSSPACE, (offset_t)0, ehdr,
@@ -1723,14 +1792,25 @@
 	if (nshdrs > 0) {
 		bzero(&bigwad->shdr[0], shdrsz);
 
-		AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER);
-		if ((error = process_scns(content, p, credp, vp,
-		    &bigwad->shdr[0], nshdrs, rlimit, &doffset, NULL)) != 0) {
+		if (nshdrs >= SHN_LORESERVE)
+			bigwad->shdr[0].sh_size = nshdrs;
+
+		if (nshdrs - 1 >= SHN_LORESERVE)
+			bigwad->shdr[0].sh_link = nshdrs - 1;
+
+		if (nphdrs >= PN_XNUM)
+			bigwad->shdr[0].sh_info = nphdrs;
+
+		if (nshdrs > 1) {
+			AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER);
+			if ((error = process_scns(content, p, credp, vp,
+			    &bigwad->shdr[0], nshdrs, rlimit, &doffset,
+			    NULL)) != 0) {
+				AS_LOCK_EXIT(as, &as->a_lock);
+				goto done;
+			}
 			AS_LOCK_EXIT(as, &as->a_lock);
-			goto done;
 		}
-		AS_LOCK_EXIT(as, &as->a_lock);
-
 
 		if ((error = core_write(vp, UIO_SYSSPACE, soffset,
 		    &bigwad->shdr[0], shdrsz, rlimit, credp)) != 0)
--- a/usr/src/uts/common/sys/elf.h	Thu Nov 17 08:46:01 2005 -0800
+++ b/usr/src/uts/common/sys/elf.h	Thu Nov 17 11:42:26 2005 -0800
@@ -346,6 +346,8 @@
 
 #define	PF_SUNW_FAILURE	0x00100000	/* mapping absent due to failure */
 
+#define	PN_XNUM		0xffff		/* extended program header index */
+
 /*
  *	Section header
  */
--- a/usr/src/uts/intel/ia32/ml/modstubs.s	Thu Nov 17 08:46:01 2005 -0800
+++ b/usr/src/uts/intel/ia32/ml/modstubs.s	Thu Nov 17 11:42:26 2005 -0800
@@ -845,7 +845,7 @@
 	MODULE(shmsys,sys);
 	WSTUB(shmsys, shmexit,		nomod_zero);
 	WSTUB(shmsys, shmfork,		nomod_zero);
-	WSTUB(shmsys, shmgetid,		nomod_zero);
+	WSTUB(shmsys, shmgetid,		nomod_minus_one);
 	END_MODULE(shmsys);
 #endif
 
--- a/usr/src/uts/sparc/ml/modstubs.s	Thu Nov 17 08:46:01 2005 -0800
+++ b/usr/src/uts/sparc/ml/modstubs.s	Thu Nov 17 11:42:26 2005 -0800
@@ -765,7 +765,7 @@
 	MODULE(shmsys,sys);
 	WSTUB(shmsys, shmexit,		nomod_zero);
 	WSTUB(shmsys, shmfork,		nomod_zero);
-	WSTUB(shmsys, shmgetid,		nomod_zero);
+	WSTUB(shmsys, shmgetid,		nomod_minus_one);
 	END_MODULE(shmsys);
 #endif