summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith M Wesolowski <wesolows@foobazco.org>2013-08-20 00:07:29 +0000
committerKeith M Wesolowski <wesolows@foobazco.org>2013-08-20 00:07:38 +0000
commit1fbda5aea84129b7604f310ec37f429deda7f045 (patch)
tree81a1e43828abdeb106a45a914469eeff288179f5
parentfe1c7d3fa5e382d8e5a49fb8e2cd357101ba0fc7 (diff)
parent8a16d130bdea488abf40f6692135d3c5b462fda4 (diff)
downloadillumos-joyent-1fbda5aea84129b7604f310ec37f429deda7f045.tar.gz
[illumos-gate merge]
commit 8a16d130bdea488abf40f6692135d3c5b462fda4 4009 size(1) can't find sections in relocatable objects with extended sections commit f0a0736fb13261a73aa20b1516bcc521f0fb7f15 4011 ar does weird things with extended ELF sections commit c894effd15e1470607e79c76f273f4565720d0f6 4005 libctf can't deal with extended sections commit 27553b5c56d9e74e5a8c65c2338ad06e94ab3aed 4004 dis(1) can't deal with extended sections commit e4096c828807f6c3567ce43db2d79a924e397124 4003 dldump() can't deal with extended sections commit a0563a48b6bba0177dc249048ea515ca080c73af 4000 pvs can't deal with extended sections commit 8878595fcb30298d8ee1db0aee6e69e4dc15b318 3999 libld extended section handling is broken
-rw-r--r--usr/src/cmd/dis/dis_target.c12
-rw-r--r--usr/src/cmd/sgs/ar/common/ar.msg2
-rw-r--r--usr/src/cmd/sgs/ar/common/file.c33
-rw-r--r--usr/src/cmd/sgs/libld/common/syms.c4
-rw-r--r--usr/src/cmd/sgs/librtld/common/dldump.c55
-rw-r--r--usr/src/cmd/sgs/librtld/common/librtld.msg4
-rw-r--r--usr/src/cmd/sgs/packages/common/SUNWonld-README2
-rw-r--r--usr/src/cmd/sgs/pvs/common/pvs.c9
-rw-r--r--usr/src/cmd/sgs/pvs/common/pvs.msg1
-rw-r--r--usr/src/cmd/sgs/size/common/process.c90
-rw-r--r--usr/src/lib/libctf/common/ctf_lib.c57
11 files changed, 194 insertions, 75 deletions
diff --git a/usr/src/cmd/dis/dis_target.c b/usr/src/cmd/dis/dis_target.c
index e47d77fe8d..b8b4f17b5d 100644
--- a/usr/src/cmd/dis/dis_target.c
+++ b/usr/src/cmd/dis/dis_target.c
@@ -446,6 +446,7 @@ dis_tgt_create(const char *file)
current = tgt;
cmd = ELF_C_READ;
while ((elf = elf_begin(tgt->dt_fd, cmd, tgt->dt_elf_root)) != NULL) {
+ size_t shnum = 0;
if (elf_kind(tgt->dt_elf_root) == ELF_K_AR &&
(arhdr = elf_getarhdr(elf)) == NULL) {
@@ -501,9 +502,16 @@ dis_tgt_create(const char *file)
return (NULL);
}
+ if (elf_getshdrnum(elf, &shnum) == -1) {
+ warn("%s: failed to get number of sections in file",
+ file);
+ dis_tgt_destroy(tgt);
+ return (NULL);
+ }
+
current->dt_shnmap = safe_malloc(sizeof (dis_shnmap_t) *
- ehdr.e_shnum);
- current->dt_shncount = ehdr.e_shnum;
+ shnum);
+ current->dt_shncount = shnum;
idx = 0;
dis_tgt_section_iter(current, tgt_scn_init, &idx);
diff --git a/usr/src/cmd/sgs/ar/common/ar.msg b/usr/src/cmd/sgs/ar/common/ar.msg
index f82a689966..a0da94da04 100644
--- a/usr/src/cmd/sgs/ar/common/ar.msg
+++ b/usr/src/cmd/sgs/ar/common/ar.msg
@@ -70,6 +70,8 @@
@ MSG_ELF_GETSCN_FILE "ar: %s has no section header or bad elf format: %s\n"
@ MSG_ELF_GETSCN_AR "ar: %s(%s) has no section header or bad elf \
format: %s\n"
+@ MSG_ELF_GETSHSTRNDX_FILE "ar: %s has no string table index: %s\n"
+@ MSG_ELF_GETSHSTRNDX_AR "ar: %s(%s) has no string table index: %s\n"
@ MSG_ELF_MALARCHIVE "ar: %s: offset %lld: malformed archive: %s\n"
@ MSG_ELF_RAWFILE "ar: elf_rawfile() failed: %s\n"
@ MSG_ELF_VERSION "ar: libelf.a out of date: %s\n"
diff --git a/usr/src/cmd/sgs/ar/common/file.c b/usr/src/cmd/sgs/ar/common/file.c
index 0c48b9f622..e3aa7fa0a5 100644
--- a/usr/src/cmd/sgs/ar/common/file.c
+++ b/usr/src/cmd/sgs/ar/common/file.c
@@ -205,6 +205,7 @@ recover_padding(Elf *elf, ARFILE *file)
{
size_t extent;
size_t padding;
+ size_t shnum;
GElf_Ehdr ehdr;
@@ -222,8 +223,11 @@ recover_padding(Elf *elf, ARFILE *file)
* we've found the end, and the difference is padding (We assume
* that no ELF section can fit into PADSZ bytes).
*/
+ if (elf_getshdrnum(elf, &shnum) == -1)
+ return;
+
extent = gelf_getehdr(elf, &ehdr)
- ? (ehdr.e_shoff + (ehdr.e_shnum * ehdr.e_shentsize)) : 0;
+ ? (ehdr.e_shoff + (shnum * ehdr.e_shentsize)) : 0;
/*
* If the extent exceeds the end of the archive member
@@ -552,11 +556,33 @@ mksymtab(const char *arname, ARFILEP **symlist, int *found_obj)
exit(1);
}
if (gelf_getehdr(elf, &ehdr) != 0) {
+ size_t shstrndx = 0;
if ((class = gelf_getclass(elf)) == ELFCLASS64) {
fptr->ar_flag |= F_CLASS64;
} else if (class == ELFCLASS32)
fptr->ar_flag |= F_CLASS32;
- scn = elf_getscn(elf, ehdr.e_shstrndx);
+
+ if (elf_getshdrstrndx(elf, &shstrndx) == -1) {
+ if (fptr->ar_pathname != NULL) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ELF_GETSHSTRNDX_FILE),
+ fptr->ar_pathname, elf_errmsg(-1));
+ } else {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ELF_GETSHSTRNDX_AR),
+ arname, fptr->ar_longname,
+ elf_errmsg(-1));
+ }
+ num_errs++;
+ if (newfd) {
+ (void) close(newfd);
+ newfd = 0;
+ }
+ (void) elf_end(elf);
+ continue;
+ }
+
+ scn = elf_getscn(elf, shstrndx);
if (scn == NULL) {
if (fptr->ar_pathname != NULL)
(void) fprintf(stderr,
@@ -640,7 +666,7 @@ mksymtab(const char *arname, ARFILEP **symlist, int *found_obj)
continue;
}
*found_obj = 1;
- if (shdr.sh_type == SHT_SYMTAB)
+ if (shdr.sh_type == SHT_SYMTAB) {
if (search_sym_tab(arname, fptr, elf,
scn, &nsyms, symlist,
&num_errs) == -1) {
@@ -650,6 +676,7 @@ mksymtab(const char *arname, ARFILEP **symlist, int *found_obj)
}
continue;
}
+ }
}
}
mem_offset += sizeof (struct ar_hdr) + fptr->ar_size;
diff --git a/usr/src/cmd/sgs/libld/common/syms.c b/usr/src/cmd/sgs/libld/common/syms.c
index 3f43efe3f5..14455dfc42 100644
--- a/usr/src/cmd/sgs/libld/common/syms.c
+++ b/usr/src/cmd/sgs/libld/common/syms.c
@@ -2053,7 +2053,7 @@ ld_sym_process(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl)
shndx = symshndx[ndx];
} else if ((shndx = sym->st_shndx) >= SHN_LORESERVE) {
sdflags |= FLG_SY_SPECSEC;
- } else if (shndx > ifl->ifl_ehdr->e_shnum) {
+ } else if (shndx > ifl->ifl_shnum) {
/* We need the name before we can issue error */
shndx_bad = 1;
}
@@ -2368,7 +2368,7 @@ ld_sym_process(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl)
shndx = symshndx[ndx];
} else if ((shndx = nsym->st_shndx) >= SHN_LORESERVE) {
sdflags |= FLG_SY_SPECSEC;
- } else if (shndx > ifl->ifl_ehdr->e_shnum) {
+ } else if (shndx > ifl->ifl_shnum) {
/* We need the name before we can issue error */
shndx_bad = 1;
}
diff --git a/usr/src/cmd/sgs/librtld/common/dldump.c b/usr/src/cmd/sgs/librtld/common/dldump.c
index 6ac021e5e7..5149d12267 100644
--- a/usr/src/cmd/sgs/librtld/common/dldump.c
+++ b/usr/src/cmd/sgs/librtld/common/dldump.c
@@ -25,7 +25,6 @@
*
* dldump(3c) creates a new file image from the specified input file.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/param.h>
#include <sys/procfs.h>
@@ -158,7 +157,7 @@ rt_dldump(Rt_map *lmp, const char *opath, int flags, Addr addr)
Elf_Data *data;
Half endx = 1;
int fd = 0, err, num;
- size_t shstr_size = 1;
+ size_t shstr_size = 1, shndx;
Addr edata;
char *shstr, *_shstr, *ipath = NAME(lmp);
prstatus_t *status = 0, _status;
@@ -309,7 +308,13 @@ rt_dldump(Rt_map *lmp, const char *opath, int flags, Addr addr)
/*
* Obtain the input files section header string table.
*/
- if ((scn = elf_getscn(ielf, iehdr->e_shstrndx)) == NULL) {
+
+ if (elf_getshdrstrndx(ielf, &shndx) == -1) {
+ eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_GETSHDRSTRNDX), ipath);
+ cleanup(ielf, oelf, melf, icache, mcache, fd, opath);
+ return (1);
+ }
+ if ((scn = elf_getscn(ielf, shndx)) == NULL) {
eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_GETSCN), ipath);
cleanup(ielf, oelf, melf, icache, mcache, fd, opath);
return (1);
@@ -327,10 +332,18 @@ rt_dldump(Rt_map *lmp, const char *opath, int flags, Addr addr)
* add an additional entry (marked FLG_C_END) to make the processing of
* this cache easier.
*/
- num = iehdr->e_shnum;
+
+ if (elf_getshdrnum(ielf, &shndx) == -1) {
+ eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_GETSHDRNUM), opath);
+ cleanup(ielf, oelf, melf, icache, mcache, fd, opath);
+ return (1);
+ }
+
+ num = shndx;
+
if (status)
num++;
- if ((icache = malloc((num + 1) * sizeof (Cache))) == 0) {
+ if ((icache = calloc(num + 1, sizeof (Cache))) == 0) {
cleanup(ielf, oelf, melf, icache, mcache, fd, opath);
return (1);
}
@@ -420,7 +433,7 @@ rt_dldump(Rt_map *lmp, const char *opath, int flags, Addr addr)
if (status) {
_icache++;
_icache->c_name =
- (char *)MSG_ORIG(MSG_SCN_HEAP);
+ (char *)MSG_ORIG(MSG_SCN_HEAP);
_icache->c_flags = FLG_C_HEAP;
_icache->c_scn = 0;
@@ -624,7 +637,27 @@ rt_dldump(Rt_map *lmp, const char *opath, int flags, Addr addr)
_icache->c_info = shstr;
/* LINTED */
- oehdr->e_shstrndx = (Half)elf_ndxscn(scn);
+ if (elf_ndxscn(scn) >= SHN_LORESERVE) {
+ Elf_Scn *_scn;
+ Shdr *shdr0;
+
+ /*
+ * libelf deals with e_shnum for us, but we
+ * need to deal with e_shstrndx ourselves.
+ */
+ oehdr->e_shstrndx = SHN_XINDEX;
+ if ((_scn = elf_getscn(oelf, 0)) == NULL) {
+ eprintf(lml, ERR_ELF,
+ MSG_ORIG(MSG_ELF_GETSCN), opath);
+ cleanup(ielf, oelf, melf, icache,
+ mcache, fd, opath);
+ return (1);
+ }
+ shdr0 = elf_getshdr(_scn);
+ shdr0->sh_link = elf_ndxscn(scn);
+ } else {
+ oehdr->e_shstrndx = (Half)elf_ndxscn(scn);
+ }
} else if (_icache->c_flags == FLG_C_HEAP) {
/*
@@ -727,10 +760,16 @@ rt_dldump(Rt_map *lmp, const char *opath, int flags, Addr addr)
return (1);
}
+ if (elf_getshdrnum(melf, &shndx) == -1) {
+ eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_GETSHDRNUM), opath);
+ cleanup(ielf, oelf, melf, icache, mcache, fd, opath);
+ return (1);
+ }
+
/*
* Construct a cache to maintain the memory files section information.
*/
- if ((mcache = malloc(mehdr->e_shnum * sizeof (Cache))) == 0) {
+ if ((mcache = calloc(shndx, sizeof (Cache))) == 0) {
cleanup(ielf, oelf, melf, icache, mcache, fd, opath);
return (1);
}
diff --git a/usr/src/cmd/sgs/librtld/common/librtld.msg b/usr/src/cmd/sgs/librtld/common/librtld.msg
index 5b8a52886c..ecb4ab1e3b 100644
--- a/usr/src/cmd/sgs/librtld/common/librtld.msg
+++ b/usr/src/cmd/sgs/librtld/common/librtld.msg
@@ -22,8 +22,6 @@
#
# CDDL HEADER END
#
-# ident "%Z%%M% %I% %E% SMI"
-
@ _START_
@@ -70,6 +68,8 @@
@ MSG_ELF_GETPHDR "%s: elf_getphdr"
@ MSG_ELF_GETSCN "%s: elf_getscn"
@ MSG_ELF_GETSHDR "%s: elf_getshdr"
+@ MSG_ELF_GETSHDRNUM "%s: elf_getshdrnum"
+@ MSG_ELF_GETSHDRSTRNDX "%s: elf_getshdrstrndx"
@ MSG_ELF_NEWDATA "%s: elf_newdata"
@ MSG_ELF_NEWEHDR "%s: elf_newehdr"
@ MSG_ELF_NEWPHDR "%s: elf_newphdr"
diff --git a/usr/src/cmd/sgs/packages/common/SUNWonld-README b/usr/src/cmd/sgs/packages/common/SUNWonld-README
index 389f8706b6..71cb2a1743 100644
--- a/usr/src/cmd/sgs/packages/common/SUNWonld-README
+++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README
@@ -1648,3 +1648,5 @@ Bugid Risk Synopsis
3709 need sloppy relocation for GNU .debug_macro
3722 link-editor is over restrictive of R_AMD64_32 addends
3926 multiple extern map file definitions corrupt symbol table entry
+3999 libld extended section handling is broken
+4003 dldump() can't deal with extended sections
diff --git a/usr/src/cmd/sgs/pvs/common/pvs.c b/usr/src/cmd/sgs/pvs/common/pvs.c
index 2ca46e6e57..4d51ce300d 100644
--- a/usr/src/cmd/sgs/pvs/common/pvs.c
+++ b/usr/src/cmd/sgs/pvs/common/pvs.c
@@ -1090,6 +1090,7 @@ main(int argc, char **argv, char **envp)
for (; optind < argc; optind++) {
int derror = 0, nerror = 0, err;
const char *file = argv[optind];
+ size_t shnum = 0;
if ((var = open(file, O_RDONLY)) == -1) {
err = errno;
@@ -1154,7 +1155,13 @@ main(int argc, char **argv, char **envp)
* as elf_begin has already gone through all the overhead we
* might as well set up the cache for every section.
*/
- if ((cache = calloc(ehdr.e_shnum, sizeof (Cache))) == NULL) {
+ if (elf_getshdrnum(elf, &shnum) == -1) {
+ (void) fprintf(stderr, MSG_ORIG(MSG_ELF_GETSHDRNUM),
+ cname, file, elf_errmsg(elf_errno()));
+ exit(1);
+ }
+
+ if ((cache = calloc(shnum, sizeof (Cache))) == NULL) {
int err = errno;
(void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname,
file, strerror(err));
diff --git a/usr/src/cmd/sgs/pvs/common/pvs.msg b/usr/src/cmd/sgs/pvs/common/pvs.msg
index 30883b3336..82a61385cd 100644
--- a/usr/src/cmd/sgs/pvs/common/pvs.msg
+++ b/usr/src/cmd/sgs/pvs/common/pvs.msg
@@ -77,6 +77,7 @@
@ MSG_ELF_GETSCN "%s: %s: elf_getscn: %s\n"
@ MSG_ELF_GETSHDR "%s: %s: elf_getshdr: %s\n"
@ MSG_ELF_GETDATA "%s: %s: elf_getdata: %s\n"
+@ MSG_ELF_GETSHDRNUM "%s: %s: elf_getshdrnum: %s\n"
@ MSG_STR_EMPTY ""
@ MSG_STR_OPTIONS "CdI:lnorsvN:"
diff --git a/usr/src/cmd/sgs/size/common/process.c b/usr/src/cmd/sgs/size/common/process.c
index cae1a6de9a..42df906eaa 100644
--- a/usr/src/cmd/sgs/size/common/process.c
+++ b/usr/src/cmd/sgs/size/common/process.c
@@ -22,7 +22,7 @@
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-
+
/* Copyright (c) 1988 AT&T */
/* Copyright (c) 1989 AT&T */
/* All Rights Reserved */
@@ -68,9 +68,9 @@ void
process(Elf * elf)
{
/* EXTERNAL VARIABLES USED */
- extern int fflag, /* full format for sections */
- Fflag, /* full format for segments */
- nflag; /* include non-loadable segments or sections */
+ extern int fflag; /* full format for sections */
+ extern int Fflag; /* full format for segments */
+ extern int nflag; /* include non-loadable segments or sections */
extern int numbase; /* hex, octal, or decimal */
extern char *fname;
extern char *archive;
@@ -78,24 +78,25 @@ process(Elf * elf)
extern int oneflag;
/* LOCAL VARIABLES */
- GElf_Xword size, /* total size in non-default case for sections */
- /*
- * size of first, second, third number and total size
- * in default case for sections.
- */
- first,
- second,
- third,
- totsize;
+ GElf_Xword size; /* total size in non-default case for sections */
+ /*
+ * size of first, second, third number and total size
+ * in default case for sections.
+ */
+ GElf_Xword first;
+ GElf_Xword second;
+ GElf_Xword third;
+ GElf_Xword totsize;
GElf_Ehdr ehdr;
GElf_Shdr shdr;
Elf_Scn *scn;
- unsigned ndx = 0;
+ size_t ndx = 0, shnum = 0;
int numsect = 0;
int notfirst = 0;
int i;
char *name = 0;
+
/*
* If there is a program header and the -f flag requesting section infor-
* mation is not set, then process segments with the process_phdr function.
@@ -124,14 +125,19 @@ process(Elf * elf)
} else if (!oneflag && !is_archive) {
(void) printf("%s: ", fname);
}
- ndx = ehdr.e_shstrndx;
+ if (elf_getshdrstrndx(elf, &ndx) == -1)
+ error(fname, "no string table");
scn = 0;
size = 0;
first = second = third = totsize = 0;
- if (ehdr.e_shnum == 0) {
+
+ if (elf_getshdrnum(elf, &shnum) == -1)
+ error(fname, "can't get number of sections");
+
+ if (shnum == 0)
error(fname, "no section data");
- }
- numsect = ehdr.e_shnum;
+
+ numsect = shnum;
for (i = 0; i < numsect; i++) {
if ((scn = elf_nextscn(elf, scn)) == 0) {
break;
@@ -144,23 +150,23 @@ process(Elf * elf)
error(fname, "no segment data");
return;
} else if ((!(shdr.sh_flags & SHF_ALLOC)) &&
- fflag && !(nflag)) {
+ fflag && !(nflag)) {
continue;
} else if ((!(shdr.sh_flags & SHF_ALLOC)) && !(nflag)) {
continue;
} else if ((shdr.sh_flags & SHF_ALLOC) &&
- (!(shdr.sh_flags & SHF_WRITE)) &&
- (!(shdr.sh_type == SHT_NOBITS)) &&
- !(fflag) && !(nflag)) {
+ (!(shdr.sh_flags & SHF_WRITE)) &&
+ (!(shdr.sh_type == SHT_NOBITS)) &&
+ !(fflag) && !(nflag)) {
first += shdr.sh_size;
} else if ((shdr.sh_flags & SHF_ALLOC) &&
- (shdr.sh_flags & SHF_WRITE) &&
- (!(shdr.sh_type == SHT_NOBITS)) &&
- !(fflag) && !(nflag)) {
+ (shdr.sh_flags & SHF_WRITE) &&
+ (!(shdr.sh_type == SHT_NOBITS)) &&
+ !(fflag) && !(nflag)) {
second += shdr.sh_size;
} else if ((shdr.sh_flags & SHF_WRITE) &&
- (shdr.sh_type == SHT_NOBITS) &&
- !(fflag) && !(nflag)) {
+ (shdr.sh_type == SHT_NOBITS) &&
+ !(fflag) && !(nflag)) {
third += shdr.sh_size;
}
name = elf_strptr(elf, ndx, (size_t)shdr.sh_name);
@@ -182,7 +188,7 @@ process(Elf * elf)
if (!fflag && !nflag) {
totsize = first + second + third;
(void) printf(format[numbase],
- first, second, third, totsize);
+ first, second, third, totsize);
}
if (Fflag) {
@@ -215,19 +221,19 @@ process_phdr(Elf * elf, GElf_Half num)
int i;
int notfirst = 0;
GElf_Phdr p;
- GElf_Xword memsize,
- total,
- First,
- Second,
- Third,
- Totsize;
- extern int Fflag;
- extern int nflag;
- extern int numbase;
- extern char *fname;
- extern char *archive;
- extern int is_archive;
- extern int oneflag;
+ GElf_Xword memsize;
+ GElf_Xword total;
+ GElf_Xword First;
+ GElf_Xword Second;
+ GElf_Xword Third;
+ GElf_Xword Totsize;
+ extern int Fflag;
+ extern int nflag;
+ extern int numbase;
+ extern char *fname;
+ extern char *archive;
+ extern int is_archive;
+ extern int oneflag;
memsize = total = 0;
First = Second = Third = Totsize = 0;
@@ -301,6 +307,6 @@ process_phdr(Elf * elf, GElf_Half num)
if (!Fflag && !nflag) {
Totsize = First + Second + (Third - Second);
(void) printf(format[numbase],
- First, Second, Third - Second, Totsize);
+ First, Second, Third - Second, Totsize);
}
}
diff --git a/usr/src/lib/libctf/common/ctf_lib.c b/usr/src/lib/libctf/common/ctf_lib.c
index 1c5c3f1d5f..e71ebc6d9d 100644
--- a/usr/src/lib/libctf/common/ctf_lib.c
+++ b/usr/src/lib/libctf/common/ctf_lib.c
@@ -193,6 +193,7 @@ ctf_fdopen(int fd, int *errp)
{
ctf_sect_t ctfsect, symsect, strsect;
ctf_file_t *fp = NULL;
+ size_t shstrndx, shnum;
struct stat64 st;
ssize_t nbytes;
@@ -255,11 +256,10 @@ ctf_fdopen(int fd, int *errp)
#else
uchar_t order = ELFDATA2LSB;
#endif
- GElf_Half i, n;
GElf_Shdr *sp;
void *strs_map;
- size_t strs_mapsz;
+ size_t strs_mapsz, i;
const char *strs;
if (hdr.e32.e_ident[EI_DATA] != order)
@@ -275,11 +275,38 @@ ctf_fdopen(int fd, int *errp)
ehdr_to_gelf(&e32, &hdr.e64);
}
- if (hdr.e64.e_shstrndx >= hdr.e64.e_shnum)
+ shnum = hdr.e64.e_shnum;
+ shstrndx = hdr.e64.e_shstrndx;
+
+ /* Extended ELF sections */
+ if ((shstrndx == SHN_XINDEX) || (shnum == 0)) {
+ if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS32) {
+ Elf32_Shdr x32;
+
+ if (pread64(fd, &x32, sizeof (x32),
+ hdr.e64.e_shoff) != sizeof (x32))
+ return (ctf_set_open_errno(errp,
+ errno));
+
+ shnum = x32.sh_size;
+ shstrndx = x32.sh_link;
+ } else {
+ Elf64_Shdr x64;
+
+ if (pread64(fd, &x64, sizeof (x64),
+ hdr.e64.e_shoff) != sizeof (x64))
+ return (ctf_set_open_errno(errp,
+ errno));
+
+ shnum = x64.sh_size;
+ shstrndx = x64.sh_link;
+ }
+ }
+
+ if (shstrndx >= shnum)
return (ctf_set_open_errno(errp, ECTF_CORRUPT));
- n = hdr.e64.e_shnum;
- nbytes = sizeof (GElf_Shdr) * n;
+ nbytes = sizeof (GElf_Shdr) * shnum;
if ((sp = malloc(nbytes)) == NULL)
return (ctf_set_open_errno(errp, errno));
@@ -291,7 +318,7 @@ ctf_fdopen(int fd, int *errp)
if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS32) {
Elf32_Shdr *sp32;
- nbytes = sizeof (Elf32_Shdr) * n;
+ nbytes = sizeof (Elf32_Shdr) * shnum;
if ((sp32 = malloc(nbytes)) == NULL || pread64(fd,
sp32, nbytes, hdr.e64.e_shoff) != nbytes) {
@@ -299,7 +326,7 @@ ctf_fdopen(int fd, int *errp)
return (ctf_set_open_errno(errp, errno));
}
- for (i = 0; i < n; i++)
+ for (i = 0; i < shnum; i++)
shdr_to_gelf(&sp32[i], &sp[i]);
free(sp32);
@@ -313,14 +340,14 @@ ctf_fdopen(int fd, int *errp)
* Now mmap the section header strings section so that we can
* perform string comparison on the section names.
*/
- strs_mapsz = sp[hdr.e64.e_shstrndx].sh_size +
- (sp[hdr.e64.e_shstrndx].sh_offset & ~_PAGEMASK);
+ strs_mapsz = sp[shstrndx].sh_size +
+ (sp[shstrndx].sh_offset & ~_PAGEMASK);
strs_map = mmap64(NULL, strs_mapsz, PROT_READ, MAP_PRIVATE,
- fd, sp[hdr.e64.e_shstrndx].sh_offset & _PAGEMASK);
+ fd, sp[shstrndx].sh_offset & _PAGEMASK);
strs = (const char *)strs_map +
- (sp[hdr.e64.e_shstrndx].sh_offset & ~_PAGEMASK);
+ (sp[shstrndx].sh_offset & ~_PAGEMASK);
if (strs_map == MAP_FAILED) {
free(sp);
@@ -331,15 +358,15 @@ ctf_fdopen(int fd, int *errp)
* Iterate over the section header array looking for the CTF
* section and symbol table. The strtab is linked to symtab.
*/
- for (i = 0; i < n; i++) {
+ for (i = 0; i < shnum; i++) {
const GElf_Shdr *shp = &sp[i];
const GElf_Shdr *lhp = &sp[shp->sh_link];
- if (shp->sh_link >= hdr.e64.e_shnum)
+ if (shp->sh_link >= shnum)
continue; /* corrupt sh_link field */
- if (shp->sh_name >= sp[hdr.e64.e_shstrndx].sh_size ||
- lhp->sh_name >= sp[hdr.e64.e_shstrndx].sh_size)
+ if (shp->sh_name >= sp[shstrndx].sh_size ||
+ lhp->sh_name >= sp[shstrndx].sh_size)
continue; /* corrupt sh_name field */
if (shp->sh_type == SHT_PROGBITS &&