summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorahl <none@none>2005-11-17 11:42:26 -0800
committerahl <none@none>2005-11-17 11:42:26 -0800
commit30da143285931291f495cc20b5a1b8869f0618a6 (patch)
tree5a2c0cc9c0956756f9ba0abf8a2a7b205671626f
parent186507a7cf6e4b4155e9ef89631777a96633ac0e (diff)
downloadillumos-joyent-30da143285931291f495cc20b5a1b8869f0618a6.tar.gz
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
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_gelf.c146
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_gelf.h5
-rw-r--r--usr/src/cmd/sgs/elfdump/common/elfdump.c77
-rw-r--r--usr/src/cmd/sgs/elfdump/common/elfdump.msg1
-rw-r--r--usr/src/cmd/sgs/libelf/Makefile.com4
-rw-r--r--usr/src/cmd/sgs/libelf/common/gelf.c14
-rw-r--r--usr/src/cmd/sgs/libelf/common/getphnum.c59
-rw-r--r--usr/src/cmd/sgs/libelf/common/llib-lelf3
-rw-r--r--usr/src/cmd/sgs/libelf/demo/dcom.c15
-rw-r--r--usr/src/cmd/sgs/libelf/spec/elf.spec6
-rw-r--r--usr/src/cmd/sgs/libelf/spec/versions4
-rw-r--r--usr/src/cmd/sgs/liblddbg/common/elf.c45
-rw-r--r--usr/src/cmd/sgs/liblddbg/common/liblddbg.msg7
-rw-r--r--usr/src/cmd/sgs/packages/common/SUNWonld-README1
-rw-r--r--usr/src/head/libelf.h6
-rw-r--r--usr/src/lib/libproc/common/Pcontrol.h29
-rw-r--r--usr/src/lib/libproc/common/Pcore.c245
-rw-r--r--usr/src/lib/libproc/common/Pgcore.c88
-rw-r--r--usr/src/lib/libproc/common/Pidle.c10
-rw-r--r--usr/src/lib/libproc/common/Psymtab.c127
-rw-r--r--usr/src/uts/common/exec/elf/elf.c182
-rw-r--r--usr/src/uts/common/sys/elf.h2
-rw-r--r--usr/src/uts/intel/ia32/ml/modstubs.s2
-rw-r--r--usr/src/uts/sparc/ml/modstubs.s2
24 files changed, 792 insertions, 288 deletions
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_gelf.c b/usr/src/cmd/mdb/common/mdb/mdb_gelf.c
index 95c96c24a0..f334a018e0 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_gelf.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_gelf.c
@@ -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 const char *gelf_strtab; /* Active string table for qsort callbacks */
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 @@ gelf_sect_init(mdb_gelf_file_t *gf)
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 @@ gelf_sect_init(mdb_gelf_file_t *gf)
*/
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 @@ gelf_shdrs_init(mdb_gelf_file_t *gf, size_t shdr_size,
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 @@ gelf_shdrs_init(mdb_gelf_file_t *gf, size_t shdr_size,
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 @@ gelf_shdrs_init(mdb_gelf_file_t *gf, size_t shdr_size,
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_phdrs_init(mdb_gelf_file_t *gf, size_t phdr_size,
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 @@ gelf_phdrs_init(mdb_gelf_file_t *gf, size_t phdr_size,
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 @@ gelf_phdrs_init(mdb_gelf_file_t *gf, size_t phdr_size,
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 @@ gelf_phdrs_init(mdb_gelf_file_t *gf, size_t phdr_size,
* 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 @@ gelf_phdrs_init(mdb_gelf_file_t *gf, size_t phdr_size,
* 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 @@ gelf_dyns_init(mdb_gelf_file_t *gf, size_t dyn_size,
} 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 @@ gelf_dyns_init(mdb_gelf_file_t *gf, size_t dyn_size,
}
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 @@ gelf32_init(mdb_gelf_file_t *gf, const Elf32_Ehdr *ehdr)
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 @@ gelf32_init(mdb_gelf_file_t *gf, const Elf32_Ehdr *ehdr)
}
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 @@ mdb_gelf_create(mdb_io_t *io, GElf_Half etype, int mode)
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 @@ mdb_gelf_create(mdb_io_t *io, GElf_Half etype, int mode)
goto err;
}
- gf = gelf64_init(gf, &ehdr.h64);
+ gf = gelf64_init(gf, io, &ehdr.h64);
break;
default:
@@ -714,7 +777,7 @@ mdb_gelf_create(mdb_io_t *io, GElf_Half etype, int mode)
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_destroy(mdb_gelf_file_t *gf)
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 @@ gelf32_symtab_init(mdb_gelf_symtab_t *gst)
}
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 @@ gelf64_symtab_init(mdb_gelf_symtab_t *gst)
}
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 @@ mdb_gelf_symtab_create_file(mdb_gelf_file_t *gf, GElf_Word elftype,
* 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 @@ mdb_gelf_symtab_create_file(mdb_gelf_file_t *gf, GElf_Word elftype,
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 @@ mdb_gelf_symtab_create_file_by_name(mdb_gelf_file_t *gf,
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;
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_gelf.h b/usr/src/cmd/mdb/common/mdb/mdb_gelf.h
index e6d18a5ea9..5f7629cfcc 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_gelf.h
+++ b/usr/src/cmd/mdb/common/mdb/mdb_gelf.h
@@ -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 @@ typedef struct mdb_gelf_file {
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) */
diff --git a/usr/src/cmd/sgs/elfdump/common/elfdump.c b/usr/src/cmd/sgs/elfdump/common/elfdump.c
index 266597a32f..0ad3884bee 100644
--- a/usr/src/cmd/sgs/elfdump/common/elfdump.c
+++ b/usr/src/cmd/sgs/elfdump/common/elfdump.c
@@ -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 @@ detail_usage()
* 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 @@ sections(const char *file, Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr,
}
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(Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr, const char *name,
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 @@ unwind(Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr, const char *name,
* 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 @@ cap(const char *file, Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr,
/*
* 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 @@ cap(const char *file, Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr,
* 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 @@ interp(const char *file, Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr,
/*
* 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 @@ versions(Cache *cache, GElf_Word shnum, const char *file, uint32_t flags)
* 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 @@ symbols(Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr, const char *name,
* 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 @@ group(Cache *cache, GElf_Word shnum, const char *name, const char *file,
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 @@ regular(const char *file, Elf *elf, uint32_t flags, char *Nname, int wfd)
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 @@ regular(const char *file, Elf *elf, uint32_t flags, char *Nname, int wfd)
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 @@ regular(const char *file, Elf *elf, uint32_t flags, char *Nname, int wfd)
/*
* 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 @@ regular(const char *file, Elf *elf, uint32_t flags, char *Nname, int wfd)
/*
- * 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 @@ regular(const char *file, Elf *elf, uint32_t flags, char *Nname, int wfd)
}
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 @@ regular(const char *file, Elf *elf, uint32_t flags, char *Nname, int wfd)
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 @@ regular(const char *file, Elf *elf, uint32_t flags, char *Nname, int wfd)
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);
}
diff --git a/usr/src/cmd/sgs/elfdump/common/elfdump.msg b/usr/src/cmd/sgs/elfdump/common/elfdump.msg
index 4a686ebe9e..99fe4591e7 100644
--- a/usr/src/cmd/sgs/elfdump/common/elfdump.msg
+++ b/usr/src/cmd/sgs/elfdump/common/elfdump.msg
@@ -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"
diff --git a/usr/src/cmd/sgs/libelf/Makefile.com b/usr/src/cmd/sgs/libelf/Makefile.com
index b2d8f98f24..70d75d4a47 100644
--- a/usr/src/cmd/sgs/libelf/Makefile.com
+++ b/usr/src/cmd/sgs/libelf/Makefile.com
@@ -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 @@ COMOBJS= ar.o begin.o cntl.o cook.o \
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 \
diff --git a/usr/src/cmd/sgs/libelf/common/gelf.c b/usr/src/cmd/sgs/libelf/common/gelf.c
index f8b5804e88..b446bbba4c 100644
--- a/usr/src/cmd/sgs/libelf/common/gelf.c
+++ b/usr/src/cmd/sgs/libelf/common/gelf.c
@@ -219,15 +219,15 @@ GElf_Phdr *
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 @@ int
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);
}
diff --git a/usr/src/cmd/sgs/libelf/common/getphnum.c b/usr/src/cmd/sgs/libelf/common/getphnum.c
new file mode 100644
index 0000000000..914cb847b1
--- /dev/null
+++ b/usr/src/cmd/sgs/libelf/common/getphnum.c
@@ -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);
+}
diff --git a/usr/src/cmd/sgs/libelf/common/llib-lelf b/usr/src/cmd/sgs/libelf/common/llib-lelf
index f22be38a3e..895f834393 100644
--- a/usr/src/cmd/sgs/libelf/common/llib-lelf
+++ b/usr/src/cmd/sgs/libelf/common/llib-lelf
@@ -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 *);
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);
diff --git a/usr/src/cmd/sgs/libelf/demo/dcom.c b/usr/src/cmd/sgs/libelf/demo/dcom.c
index 8986e7c88b..35c9c710c7 100644
--- a/usr/src/cmd/sgs/libelf/demo/dcom.c
+++ b/usr/src/cmd/sgs/libelf/demo/dcom.c
@@ -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 @@ delete_comment(Elf *elf, int fd, const char *file)
GElf_Phdr tphdr;
size_t shstrndx;
size_t shnum;
+ size_t phnum;
int *shndx;
int ndx = 1;
int off = 0;
@@ -124,6 +125,12 @@ delete_comment(Elf *elf, int fd, const char *file)
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 @@ delete_comment(Elf *elf, int fd, const char *file)
/*
* 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,
diff --git a/usr/src/cmd/sgs/libelf/spec/elf.spec b/usr/src/cmd/sgs/libelf/spec/elf.spec
index 9660833361..ae88a0aac2 100644
--- a/usr/src/cmd/sgs/libelf/spec/elf.spec
+++ b/usr/src/cmd/sgs/libelf/spec/elf.spec
@@ -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)
diff --git a/usr/src/cmd/sgs/libelf/spec/versions b/usr/src/cmd/sgs/libelf/spec/versions
index cd5a186252..fa6f63a757 100644
--- a/usr/src/cmd/sgs/libelf/spec/versions
+++ b/usr/src/cmd/sgs/libelf/spec/versions
@@ -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 @@ sparc {
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 @@ sparcv9 {
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 @@ i386 {
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};
diff --git a/usr/src/cmd/sgs/liblddbg/common/elf.c b/usr/src/cmd/sgs/liblddbg/common/elf.c
index d5704fe5a0..91cabd9e21 100644
--- a/usr/src/cmd/sgs/liblddbg/common/elf.c
+++ b/usr/src/cmd/sgs/liblddbg/common/elf.c
@@ -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 @@ Gelf_elf_header(GElf_Ehdr *ehdr, GElf_Shdr *shdr0)
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 @@ Gelf_elf_header(GElf_Ehdr *ehdr, GElf_Shdr *shdr0)
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));
}
diff --git a/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg b/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg
index 9e729169ae..4877fe419c 100644
--- a/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg
+++ b/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg
@@ -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
diff --git a/usr/src/cmd/sgs/packages/common/SUNWonld-README b/usr/src/cmd/sgs/packages/common/SUNWonld-README
index edd47a46a1..424208a5d8 100644
--- a/usr/src/cmd/sgs/packages/common/SUNWonld-README
+++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README
@@ -1068,3 +1068,4 @@ All the above change is incorporated in the following patches:
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)
diff --git a/usr/src/head/libelf.h b/usr/src/head/libelf.h
index 7193a508ad..f1b7856923 100644
--- a/usr/src/head/libelf.h
+++ b/usr/src/head/libelf.h
@@ -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 @@ char *elf_getident _((Elf *, size_t *));
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 *));
diff --git a/usr/src/lib/libproc/common/Pcontrol.h b/usr/src/lib/libproc/common/Pcontrol.h
index 44d9e43904..9dadd50064 100644
--- a/usr/src/lib/libproc/common/Pcontrol.h
+++ b/usr/src/lib/libproc/common/Pcontrol.h
@@ -53,15 +53,15 @@ extern "C" {
* 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 @@ typedef struct file_info { /* symbol information for a mapped file */
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 @@ typedef struct core_info { /* information specific to core files */
#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;
diff --git a/usr/src/lib/libproc/common/Pcore.c b/usr/src/lib/libproc/common/Pcore.c
index 99feb87ac4..eb55e20894 100644
--- a/usr/src/lib/libproc/common/Pcore.c
+++ b/usr/src/lib/libproc/common/Pcore.c
@@ -800,7 +800,7 @@ core_name_mapping(struct ps_prochandle *P, uintptr_t addr, const char *name)
* 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 @@ fake_up_symtab(struct ps_prochandle *P, GElf_Ehdr *ehdr,
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 @@ fake_up_symtab(struct ps_prochandle *P, GElf_Ehdr *ehdr,
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 @@ err:
}
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 @@ core_elf_fdopen(elf_file_t *efp, GElf_Half type, int *perr)
/*
* 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 @@ core_elf_close(elf_file_t *efp)
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 @@ core_find_data(struct ps_prochandle *P, Elf *elf, rd_loadobj_t *rlp)
{
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 @@ core_find_data(struct ps_prochandle *P, Elf *elf, rd_loadobj_t *rlp)
* 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)) {
-
- rlp->rl_data_base = phdr.p_vaddr;
- if (ehdr.e_type == ET_DYN)
- rlp->rl_data_base += rlp->rl_base;
- break;
- }
+ if (gelf_getehdr(elf, &ehdr) == NULL ||
+ 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_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 @@ core_load_shdrs(struct ps_prochandle *P, elf_file_t *efp)
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;
}
diff --git a/usr/src/lib/libproc/common/Pgcore.c b/usr/src/lib/libproc/common/Pgcore.c
index aa374a71af..cf60653e1d 100644
--- a/usr/src/lib/libproc/common/Pgcore.c
+++ b/usr/src/lib/libproc/common/Pgcore.c
@@ -46,6 +46,7 @@
#include "P32ton.h"
typedef enum {
+ STR_NONE,
STR_CTF,
STR_SYMTAB,
STR_DYNSYM,
@@ -56,6 +57,7 @@ typedef enum {
} shstrtype_t;
static const char *shstrtab_data[] = {
+ "",
".SUNW_ctf",
".symtab",
".dynsym",
@@ -94,7 +96,7 @@ shstrtab_ndx(shstrtab_t *s, shstrtype_t type)
{
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 @@ write_shstrtab(struct ps_prochandle *P, pgcore_t *pgc)
(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 @@ Pfgcore(struct ps_prochandle *P, int fd, core_content_t content)
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 @@ Pfgcore(struct ps_prochandle *P, int fd, core_content_t content)
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 @@ Pfgcore(struct ps_prochandle *P, int fd, core_content_t content)
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.
*/
diff --git a/usr/src/lib/libproc/common/Pidle.c b/usr/src/lib/libproc/common/Pidle.c
index bf05e6a2e9..4e23112152 100644
--- a/usr/src/lib/libproc/common/Pidle.c
+++ b/usr/src/lib/libproc/common/Pidle.c
@@ -113,6 +113,7 @@ Pgrab_file(const char *fname, int *perr)
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 @@ Pgrab_file(const char *fname, int *perr)
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) {
diff --git a/usr/src/lib/libproc/common/Psymtab.c b/usr/src/lib/libproc/common/Psymtab.c
index 71e4f258f8..5ee4eaaeaa 100644
--- a/usr/src/lib/libproc/common/Psymtab.c
+++ b/usr/src/lib/libproc/common/Psymtab.c
@@ -56,9 +56,11 @@ static map_info_t *object_to_map(struct ps_prochandle *, Lmid_t, const char *);
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 @@ file_info_new(struct ps_prochandle *P, map_info_t *mptr)
if (P->status.pr_dmodel == PR_MODEL_ILP32) {
Elf32_Ehdr ehdr;
Elf32_Phdr phdr;
+ uint_t phnum;
- if (read_ehdr32(P, &ehdr, mptr->map_pmap.pr_vaddr) != 0)
+ 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 @@ file_info_new(struct ps_prochandle *P, map_info_t *mptr)
} else {
Elf64_Ehdr ehdr;
Elf64_Phdr phdr;
+ uint_t phnum;
- if (read_ehdr64(P, &ehdr, mptr->map_pmap.pr_vaddr) != 0)
+ 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 @@ build_map_symtab(struct ps_prochandle *P, map_info_t *mptr)
}
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 @@ read_ehdr32(struct ps_prochandle *P, Elf32_Ehdr *ehdr, uintptr_t addr)
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 @@ read_dynamic_phdr32(struct ps_prochandle *P, const Elf32_Ehdr *ehdr,
#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 @@ read_ehdr64(struct ps_prochandle *P, Elf64_Ehdr *ehdr, uintptr_t addr)
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 @@ found_cksum:
Elf32_Ehdr ehdr;
Elf32_Phdr phdr;
Elf32_Dyn dync, *dynp;
- uint_t i;
+ uint_t phnum, i;
- 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 (0);
if (ehdr.e_type == ET_DYN)
@@ -1148,10 +1178,10 @@ found_cksum:
Elf64_Ehdr ehdr;
Elf64_Phdr phdr;
Elf64_Dyn dync, *dynp;
- uint_t i;
+ uint_t phnum, i;
- 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 (0);
if (ehdr.e_type == ET_DYN)
@@ -1287,12 +1317,12 @@ fake_elf(struct ps_prochandle *P, file_info_t *fptr)
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 @@ fake_elf(struct ps_prochandle *P, file_info_t *fptr)
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 @@ fake_elf(struct ps_prochandle *P, file_info_t *fptr)
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 @@ fake_elf(struct ps_prochandle *P, file_info_t *fptr)
* 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 @@ bad32:
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 @@ bad32:
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 @@ bad32:
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 @@ bad32:
* 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 @@ Pbuild_file_symtab(struct ps_prochandle *P, file_info_t *fptr)
Elf_Data *shdata;
Elf_Scn *scn;
Elf *elf;
+ size_t nshdrs, shstrndx;
struct {
GElf_Shdr c_shdr;
@@ -2150,7 +2179,9 @@ Pbuild_file_symtab(struct ps_prochandle *P, file_info_t *fptr)
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 @@ Pbuild_file_symtab(struct ps_prochandle *P, file_info_t *fptr)
} 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 @@ Pbuild_file_symtab(struct ps_prochandle *P, file_info_t *fptr)
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 @@ Pbuild_file_symtab(struct ps_prochandle *P, file_info_t *fptr)
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 @@ Pbuild_file_symtab(struct ps_prochandle *P, file_info_t *fptr)
}
}
- 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 @@ Pbuild_file_symtab(struct ps_prochandle *P, file_info_t *fptr)
* 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 @@ Pbuild_file_symtab(struct ps_prochandle *P, file_info_t *fptr)
* 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 "
diff --git a/usr/src/uts/common/exec/elf/elf.c b/usr/src/uts/common/exec/elf/elf.c
index f334acb324..685c15bcc9 100644
--- a/usr/src/uts/common/exec/elf/elf.c
+++ b/usr/src/uts/common/exec/elf/elf.c
@@ -69,12 +69,13 @@ extern int at_flags;
#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 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
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 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
/*
* 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 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
*/
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 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
* 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 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
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 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
*/
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 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
* 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 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
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 @@ out:
* 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 @@ elfsize(Ehdr *ehdrp, caddr_t phdrbase, uintptr_t *lddata)
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 @@ elfsize(Ehdr *ehdrp, caddr_t phdrbase, uintptr_t *lddata)
* 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 @@ getelfhead(vnode_t *vp, cred_t *credp, Ehdr *ehdr)
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 @@ getelfhead(vnode_t *vp, cred_t *credp, Ehdr *ehdr)
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 @@ size_t elf_nphdr_max = 1000;
#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 @@ getelfphdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr,
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 @@ size_t elf_shstrtab_max = 100 * 1024;
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 @@ getelfshdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr,
* 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 @@ getelfshdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr,
* 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 @@ static int
mapelfexec(
vnode_t *vp,
Ehdr *ehdr,
+ int nphdrs,
caddr_t phdrbase,
Phdr **uphdr,
Phdr **dyphdr,
@@ -943,7 +981,7 @@ mapelfexec(
*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 @@ process_scns(core_content_t content, proc_t *p, cred_t *credp, vnode_t *vp,
size_t segsize;
Ehdr ehdr;
+ int nshdrs, shstrndx, nphdrs;
caddr_t shbase;
ssize_t shsize;
char *shstrbase;
@@ -1212,13 +1251,14 @@ process_scns(core_content_t content, proc_t *p, cred_t *credp, vnode_t *vp,
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 @@ process_scns(core_content_t content, proc_t *p, cred_t *credp, vnode_t *vp,
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 @@ process_scns(core_content_t content, proc_t *p, cred_t *credp, vnode_t *vp,
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 @@ top:
}
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 @@ top:
#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 @@ exclude:
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)
diff --git a/usr/src/uts/common/sys/elf.h b/usr/src/uts/common/sys/elf.h
index 4154354bcb..a1658fc229 100644
--- a/usr/src/uts/common/sys/elf.h
+++ b/usr/src/uts/common/sys/elf.h
@@ -346,6 +346,8 @@ typedef struct {
#define PF_SUNW_FAILURE 0x00100000 /* mapping absent due to failure */
+#define PN_XNUM 0xffff /* extended program header index */
+
/*
* Section header
*/
diff --git a/usr/src/uts/intel/ia32/ml/modstubs.s b/usr/src/uts/intel/ia32/ml/modstubs.s
index 288aebd1d3..f4b6ea3c16 100644
--- a/usr/src/uts/intel/ia32/ml/modstubs.s
+++ b/usr/src/uts/intel/ia32/ml/modstubs.s
@@ -845,7 +845,7 @@ fcnname/**/_info: \
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
diff --git a/usr/src/uts/sparc/ml/modstubs.s b/usr/src/uts/sparc/ml/modstubs.s
index d66a133a1d..2f2bdb9508 100644
--- a/usr/src/uts/sparc/ml/modstubs.s
+++ b/usr/src/uts/sparc/ml/modstubs.s
@@ -765,7 +765,7 @@ stubs_base:
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