#include <sys/elf_amd64.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <strings.h>
#include <conv.h>
#include <msg.h>
#include <_elfdump.h>
typedef struct {
const char *file;
int fd;
Ehdr *ehdr;
Phdr *phdr;
size_t phnum;
} FSTATE;
typedef enum {
SINFO_T_NULL = 0,
SINFO_T_DYN = 1,
SINFO_T_DYNSTR = 2,
SINFO_T_DYNSYM = 3,
SINFO_T_LDYNSYM = 4,
SINFO_T_HASH = 5,
SINFO_T_SYMINFO = 6,
SINFO_T_SYMSORT = 7,
SINFO_T_TLSSORT = 8,
SINFO_T_VERNEED = 9,
SINFO_T_VERDEF = 10,
SINFO_T_VERSYM = 11,
SINFO_T_INTERP = 12,
SINFO_T_CAP = 13,
SINFO_T_CAPINFO = 14,
SINFO_T_CAPCHAIN = 15,
SINFO_T_UNWIND = 16,
SINFO_T_MOVE = 17,
SINFO_T_REL = 18,
SINFO_T_RELA = 19,
SINFO_T_PREINITARR = 20,
SINFO_T_INITARR = 21,
SINFO_T_FINIARR = 22,
SINFO_T_NOTE = 23,
SINFO_T_NUM = 24
} SINFO_TYPE;
typedef struct {
const char *name;
Word sh_type;
Word sh_flags;
Word sh_addralign;
Word sh_entsize;
Elf_Type libelf_type;
} SINFO_DATA;
#ifdef _ELF64
#define FAKE_M_WORD_ALIGN 8
#else
#define FAKE_M_WORD_ALIGN 4
#endif
static SINFO_DATA sinfo_data[SINFO_T_NUM] = {
{ 0 },
{ MSG_ORIG(MSG_PHDRNAM_DYN), SHT_DYNAMIC, SHF_ALLOC,
FAKE_M_WORD_ALIGN, sizeof (Dyn), ELF_T_DYN },
{ MSG_ORIG(MSG_PHDRNAM_DYNSTR), SHT_STRTAB, SHF_ALLOC,
1, 0, ELF_T_BYTE },
{ MSG_ORIG(MSG_PHDRNAM_DYNSYM), SHT_DYNSYM, SHF_ALLOC,
FAKE_M_WORD_ALIGN, sizeof (Sym), ELF_T_SYM },
{ MSG_ORIG(MSG_PHDRNAM_LDYNSYM), SHT_SUNW_LDYNSYM, SHF_ALLOC,
FAKE_M_WORD_ALIGN, sizeof (Sym), ELF_T_SYM },
{ MSG_ORIG(MSG_PHDRNAM_HASH), SHT_HASH, SHF_ALLOC,
FAKE_M_WORD_ALIGN, sizeof (Word), ELF_T_WORD },
{ MSG_ORIG(MSG_PHDRNAM_SYMINFO), SHT_SUNW_syminfo, SHF_ALLOC,
FAKE_M_WORD_ALIGN, sizeof (Syminfo), ELF_T_SYMINFO },
{ MSG_ORIG(MSG_PHDRNAM_SYMSORT), SHT_SUNW_symsort, SHF_ALLOC,
FAKE_M_WORD_ALIGN, sizeof (Word), ELF_T_WORD },
{ MSG_ORIG(MSG_PHDRNAM_TLSSORT), SHT_SUNW_tlssort, SHF_ALLOC,
FAKE_M_WORD_ALIGN, sizeof (Word), ELF_T_WORD },
{ MSG_ORIG(MSG_PHDRNAM_VER), SHT_SUNW_verneed, SHF_ALLOC,
FAKE_M_WORD_ALIGN, 1, ELF_T_VNEED },
{ MSG_ORIG(MSG_PHDRNAM_VER), SHT_SUNW_verdef, SHF_ALLOC,
FAKE_M_WORD_ALIGN, 1, ELF_T_VDEF },
{ MSG_ORIG(MSG_PHDRNAM_VER), SHT_SUNW_versym, SHF_ALLOC,
FAKE_M_WORD_ALIGN, sizeof (Versym), ELF_T_HALF },
{ MSG_ORIG(MSG_PHDRNAM_INTERP), SHT_PROGBITS, SHF_ALLOC,
1, 0, ELF_T_BYTE },
{ MSG_ORIG(MSG_PHDRNAM_CAP), SHT_SUNW_cap, SHF_ALLOC,
sizeof (Addr), sizeof (Cap), ELF_T_CAP },
{ MSG_ORIG(MSG_PHDRNAM_CAPINFO), SHT_SUNW_capinfo, SHF_ALLOC,
FAKE_M_WORD_ALIGN, sizeof (Capinfo), ELF_T_WORD },
{ MSG_ORIG(MSG_PHDRNAM_CAPCHAIN), SHT_SUNW_capchain, SHF_ALLOC,
FAKE_M_WORD_ALIGN, sizeof (Capchain), ELF_T_WORD },
{ MSG_ORIG(MSG_PHDRNAM_UNWIND), SHT_AMD64_UNWIND, SHF_ALLOC,
sizeof (Addr), 0, ELF_T_BYTE },
{ MSG_ORIG(MSG_PHDRNAM_MOVE), SHT_SUNW_move, SHF_ALLOC,
sizeof (Lword), sizeof (Move), ELF_T_MOVE },
{ MSG_ORIG(MSG_PHDRNAM_REL), SHT_REL, SHF_ALLOC,
FAKE_M_WORD_ALIGN, sizeof (Rel), ELF_T_REL },
{ MSG_ORIG(MSG_PHDRNAM_RELA), SHT_RELA, SHF_ALLOC,
FAKE_M_WORD_ALIGN, sizeof (Rela), ELF_T_RELA },
{ MSG_ORIG(MSG_PHDRNAM_PREINITARR), SHT_PREINIT_ARRAY, SHF_ALLOC,
sizeof (Addr), sizeof (Addr), ELF_T_ADDR },
{ MSG_ORIG(MSG_PHDRNAM_INITARR), SHT_INIT_ARRAY, SHF_ALLOC,
sizeof (Addr), sizeof (Addr), ELF_T_ADDR },
{ MSG_ORIG(MSG_PHDRNAM_FINIARR), SHT_FINI_ARRAY, SHF_ALLOC,
sizeof (Addr), sizeof (Addr), ELF_T_ADDR },
{ MSG_ORIG(MSG_PHDRNAM_NOTE), SHT_NOTE, 0,
FAKE_M_WORD_ALIGN, 1, ELF_T_NOTE }
};
typedef struct {
SINFO_TYPE type;
Addr vaddr;
Off offset;
size_t size;
size_t vercnt;
Shdr *shdr;
Elf_Data *data;
} SINFO;
typedef struct _sinfo_listelt {
struct _sinfo_listelt *next;
struct _sinfo_listelt *prev;
SINFO sinfo;
} SINFO_LISTELT;
static void
sinfo_free(SINFO *sinfo, size_t n)
{
for (; n-- > 0; sinfo++) {
if (sinfo->data != NULL) {
if (sinfo->data->d_buf != NULL)
free(sinfo->data->d_buf);
free(sinfo->data);
sinfo->data = NULL;
}
if (sinfo->shdr) {
free(sinfo->shdr);
sinfo->shdr = NULL;
}
sinfo->type = SINFO_T_NULL;
}
}
static SINFO *
sinfo_list_alloc(FSTATE *fstate, SINFO_LISTELT *root)
{
SINFO_LISTELT *elt;
if ((elt = malloc(sizeof (*elt))) == NULL) {
int err = errno;
(void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
fstate->file, strerror(err));
return (0);
}
elt->next = root;
elt->prev = root->prev;
root->prev = elt;
elt->prev->next = elt;
bzero(&elt->sinfo, sizeof (elt->sinfo));
return (&elt->sinfo);
}
static void
sinfo_list_free_all(SINFO_LISTELT *root)
{
SINFO_LISTELT *elt;
for (elt = root->next; elt != root; elt = elt->next)
sinfo_free(&elt->sinfo, 1);
root->next = root->prev = root;
}
static Off
map_addr_to_offset(FSTATE *fstate, Addr addr, size_t size, size_t *zero_bytes,
Phdr **phdr_ret)
{
Off offset;
Addr end_addr = addr + size;
size_t avail_file;
Phdr *phdr = fstate->phdr;
size_t phnum = fstate->phnum;
for (; phnum--; phdr++) {
if (phdr->p_type != PT_LOAD)
continue;
if ((addr >= phdr->p_vaddr) &&
(end_addr <= (phdr->p_vaddr + phdr->p_memsz))) {
offset = addr - phdr->p_vaddr;
avail_file = phdr->p_filesz - offset;
if (zero_bytes == NULL) {
if (size > avail_file)
continue;
} else {
*zero_bytes = (size > avail_file) ?
(size - avail_file) : 0;
}
if (phdr_ret != NULL)
*phdr_ret = phdr;
return (phdr->p_offset + offset);
}
}
return (0);
}
static Addr
map_offset_to_addr(FSTATE *fstate, Off offset, size_t size, size_t *zero_bytes,
Phdr **phdr_ret)
{
Off end_offset = offset + size;
size_t avail_file;
Phdr *phdr = fstate->phdr;
size_t phnum = fstate->phnum;
for (; phnum--; phdr++) {
if (phdr->p_type != PT_LOAD)
continue;
if ((offset >= phdr->p_offset) &&
(end_offset <= (phdr->p_offset + phdr->p_memsz))) {
offset -= phdr->p_offset;
avail_file = phdr->p_filesz - offset;
if (zero_bytes == NULL) {
if (size > avail_file)
continue;
} else {
*zero_bytes = (size > avail_file) ?
(size - avail_file) : 0;
}
if (phdr_ret != NULL)
*phdr_ret = phdr;
return (phdr->p_vaddr + offset);
}
}
return (0);
}
static int
xlate_data(FSTATE *fstate, void *buf, size_t nbyte, Elf_Type xlate_type)
{
Elf_Data data;
data.d_type = xlate_type;
data.d_size = nbyte;
data.d_off = 0;
data.d_align = 0;
data.d_version = fstate->ehdr->e_version;
data.d_buf = buf;
if (elf_xlatetom(&data, &data,
fstate->ehdr->e_ident[EI_DATA]) == NULL) {
failure(fstate->file, MSG_ORIG(MSG_ELF_XLATETOM));
return (0);
}
return (1);
}
static int
read_data(FSTATE *fstate, Off offset, void *buf, size_t nbyte,
Elf_Type xlate_type)
{
if (pread(fstate->fd, buf, nbyte, offset) != nbyte) {
int err = errno;
(void) fprintf(stderr, MSG_INTL(MSG_ERR_READ),
fstate->file, strerror(err));
return (0);
}
if (xlate_type != ELF_T_BYTE)
return (xlate_data(fstate, buf, nbyte, xlate_type));
return (1);
}
static int
hash_size(FSTATE *fstate, SINFO *hash_sinfo,
Word *nbucket, Word *nchain, size_t *total)
{
Off offset;
Word buf[2];
offset = map_addr_to_offset(fstate, hash_sinfo->vaddr,
sizeof (buf), NULL, NULL);
if (offset == 0)
return (0);
if (read_data(fstate, offset, buf, sizeof (buf), ELF_T_WORD) == 0)
return (0);
*nbucket = buf[0];
*nchain = buf[1];
*total = 2 + *nbucket + *nchain;
return (1);
}
static int
read_verdef(FSTATE *fstate, Off offset, Half *cnt, Word *aux, Word *next)
{
Verdef verdef;
if (read_data(fstate, offset, &verdef, sizeof (verdef),
ELF_T_BYTE) == 0)
return (0);
if (xlate_data(fstate, &verdef.vd_cnt, sizeof (verdef.vd_cnt),
ELF_T_HALF) == 0)
return (0);
if (xlate_data(fstate, &verdef.vd_aux,
2 * sizeof (Word), ELF_T_WORD) == 0)
return (0);
*cnt = verdef.vd_cnt;
*aux = verdef.vd_aux;
*next = verdef.vd_next;
return (1);
}
static int
read_verdaux(FSTATE *fstate, Off offset, Word *next)
{
Verdaux verdaux;
if (read_data(fstate, offset, &verdaux, sizeof (verdaux),
ELF_T_BYTE) == 0)
return (0);
if (xlate_data(fstate, &verdaux.vda_next, sizeof (verdaux.vda_next),
ELF_T_WORD) == 0)
return (0);
*next = verdaux.vda_next;
return (1);
}
static int
read_verneed(FSTATE *fstate, Off offset, Half *cnt, Word *aux, Word *next)
{
Verneed verneed;
if (read_data(fstate, offset, &verneed, sizeof (verneed),
ELF_T_BYTE) == 0)
return (0);
if (xlate_data(fstate, &verneed.vn_cnt, sizeof (verneed.vn_cnt),
ELF_T_HALF) == 0)
return (0);
if (xlate_data(fstate, &verneed.vn_aux,
2 * sizeof (Word), ELF_T_WORD) == 0)
return (0);
*cnt = verneed.vn_cnt;
*aux = verneed.vn_aux;
*next = verneed.vn_next;
return (1);
}
static int
read_vernaux(FSTATE *fstate, Off offset, Word *next)
{
Vernaux vernaux;
if (read_data(fstate, offset, &vernaux, sizeof (vernaux),
ELF_T_BYTE) == 0)
return (0);
if (xlate_data(fstate, &vernaux.vna_next, sizeof (vernaux.vna_next),
ELF_T_WORD) == 0)
return (0);
*next = vernaux.vna_next;
return (1);
}
static int
verdefneed_size(FSTATE *fstate, SINFO *sec)
{
int (* read_main)(FSTATE *, Off, Half *, Word *, Word *);
int (* read_aux)(FSTATE *, Off, Word *);
size_t size_main, size_aux;
Off offset, aux_offset;
Off highwater, extent;
size_t num_main = sec->vercnt;
Half v_cnt;
Word v_aux, v_next, va_next;
if (sec->type == SINFO_T_VERDEF) {
read_main = read_verdef;
read_aux = read_verdaux;
size_main = sizeof (Verdef);
size_aux = sizeof (Verdaux);
} else {
read_main = read_verneed;
read_aux = read_vernaux;
size_main = sizeof (Verneed);
size_aux = sizeof (Vernaux);
}
offset = highwater = map_addr_to_offset(fstate, sec->vaddr,
size_main * num_main, NULL, NULL);
if (offset == 0)
return (0);
sec->size = offset;
for (; num_main-- > 0; offset += v_next) {
extent = offset + size_main;
if (extent > highwater)
highwater = extent;
if ((*read_main)(fstate, offset, &v_cnt, &v_aux, &v_next) == 0)
return (0);
aux_offset = offset + v_aux;
for (; v_cnt-- > 0; aux_offset += va_next) {
extent = aux_offset + size_aux;
if (extent > highwater)
highwater = extent;
if ((*read_aux)(fstate, aux_offset, &va_next) == 0)
return (0);
}
}
sec->size = highwater - sec->size;
return (1);
}
static int
get_data(FSTATE *fstate, SINFO *sec)
{
SINFO_DATA *tinfo;
size_t read_bytes, zero_bytes;
Phdr *phdr = NULL;
if ((sec->type == SINFO_T_NULL) || (sec->shdr != NULL))
return (1);
if (((sec->shdr = malloc(sizeof (*sec->shdr))) == NULL) ||
((sec->data = malloc(sizeof (*sec->data))) == NULL)) {
int err = errno;
sinfo_free(sec, 1);
(void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
fstate->file, strerror(err));
return (0);
}
tinfo = &sinfo_data[sec->type];
sec->shdr->sh_name = 0;
sec->shdr->sh_type = tinfo->sh_type;
sec->shdr->sh_flags = tinfo->sh_flags;
if ((tinfo->sh_flags & SHF_ALLOC) == 0) {
sec->shdr->sh_addr = sec->vaddr;
sec->shdr->sh_offset = sec->offset;
zero_bytes = 0;
} else if (sec->vaddr == 0) {
sec->shdr->sh_addr = map_offset_to_addr(fstate, sec->offset,
sec->size, &zero_bytes, &phdr);
sec->shdr->sh_offset = sec->offset;
} else {
sec->shdr->sh_addr = sec->vaddr;
sec->shdr->sh_offset = map_addr_to_offset(fstate,
sec->vaddr, sec->size, &zero_bytes, &phdr);
}
if (sec->shdr->sh_offset == 0) {
sinfo_free(sec, 1);
return (0);
}
if (phdr && ((phdr->p_flags & PF_W) != 0))
sec->shdr->sh_flags |= SHF_WRITE;
sec->shdr->sh_size = sec->size;
sec->shdr->sh_link = 0;
sec->shdr->sh_info = 0;
sec->shdr->sh_addralign = tinfo->sh_addralign;
sec->shdr->sh_entsize = tinfo->sh_entsize;
switch (tinfo->sh_type) {
case SHT_DYNAMIC:
sec->shdr->sh_link = SINFO_T_DYNSTR;
break;
case SHT_DYNSYM:
sec->shdr->sh_link = SINFO_T_DYNSTR;
sec->shdr->sh_info = 1;
break;
case SHT_SUNW_LDYNSYM:
sec->shdr->sh_link = SINFO_T_DYNSTR;
sec->shdr->sh_info = sec->shdr->sh_size / sizeof (Sym);
break;
case SHT_HASH:
case SHT_SUNW_move:
case SHT_REL:
case SHT_RELA:
case SHT_SUNW_versym:
sec->shdr->sh_link = SINFO_T_DYNSYM;
break;
case SHT_SUNW_verdef:
case SHT_SUNW_verneed:
sec->shdr->sh_link = SINFO_T_DYNSTR;
sec->shdr->sh_info = sec->vercnt;
break;
case SHT_SUNW_syminfo:
sec->shdr->sh_link = SINFO_T_DYNSYM;
sec->shdr->sh_info = SINFO_T_DYN;
break;
case SHT_SUNW_symsort:
case SHT_SUNW_tlssort:
sec->shdr->sh_link = SINFO_T_LDYNSYM;
break;
}
sec->data->d_type = tinfo->libelf_type;
sec->data->d_size = sec->size;
sec->data->d_off = 0;
sec->data->d_align = tinfo->sh_addralign;
sec->data->d_version = fstate->ehdr->e_version;
if (sec->size == 0) {
sec->data->d_buf = NULL;
return (1);
}
if ((sec->data->d_buf = malloc(sec->size)) == NULL) {
int err = errno;
sinfo_free(sec, 1);
(void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
fstate->file, strerror(err));
return (0);
}
read_bytes = sec->size - zero_bytes;
if ((read_bytes > 0) &&
(read_data(fstate, sec->shdr->sh_offset, sec->data->d_buf,
read_bytes, ELF_T_BYTE) == 0)) {
sinfo_free(sec, 1);
return (0);
}
if (zero_bytes > 0)
bzero(read_bytes + (char *)sec->data->d_buf, zero_bytes);
if ((tinfo->libelf_type != ELF_T_BYTE) &&
(elf_xlatetom(sec->data, sec->data,
fstate->ehdr->e_ident[EI_DATA]) == NULL)) {
sinfo_free(sec, 1);
failure(fstate->file, MSG_ORIG(MSG_ELF_XLATETOM));
return (0);
}
return (1);
}
int
fake_shdr_cache(const char *file, int fd, Elf *elf, Ehdr *ehdr,
Cache **cache, size_t *shnum)
{
struct {
SINFO dyn;
SINFO dynstr;
SINFO dynsym;
SINFO ldynsym;
SINFO hash;
SINFO syminfo;
SINFO symsort;
SINFO tlssort;
SINFO verneed;
SINFO verdef;
SINFO versym;
SINFO interp;
SINFO cap;
SINFO capinfo;
SINFO capchain;
SINFO unwind;
SINFO move;
SINFO rel;
SINFO rela;
SINFO preinitarr;
SINFO initarr;
SINFO finiarr;
} sec;
static const size_t sinfo_n = sizeof (sec) / sizeof (sec.dyn);
SINFO *secarr = (SINFO *) &sec;
SINFO_LISTELT seclist;
FSTATE fstate;
size_t ndx;
size_t num_sinfo, num_list_sinfo;
SINFO *sinfo;
SINFO_LISTELT *sinfo_list;
Cache *_cache;
fstate.file = file;
fstate.fd = fd;
fstate.ehdr = ehdr;
if (elf_getphdrnum(elf, &fstate.phnum) == -1) {
failure(file, MSG_ORIG(MSG_ELF_GETPHDRNUM));
return (0);
}
if ((fstate.phdr = elf_getphdr(elf)) == NULL) {
failure(file, MSG_ORIG(MSG_ELF_GETPHDR));
return (0);
}
bzero(&sec, sizeof (sec));
seclist.next = seclist.prev = &seclist;
for (ndx = 0; ndx < fstate.phnum; ndx++) {
if (fstate.phdr[ndx].p_filesz == 0)
continue;
switch (fstate.phdr[ndx].p_type) {
default:
continue;
case PT_DYNAMIC:
sec.dyn.type = SINFO_T_DYN;
sinfo = &sec.dyn;
break;
case PT_INTERP:
sec.interp.type = SINFO_T_INTERP;
sinfo = &sec.interp;
break;
case PT_NOTE:
if ((sinfo = sinfo_list_alloc(&fstate, &seclist)) ==
NULL)
continue;
sinfo->type = SINFO_T_NOTE;
break;
case PT_SUNW_UNWIND:
case PT_SUNW_EH_FRAME:
sec.unwind.type = SINFO_T_UNWIND;
sinfo = &sec.unwind;
break;
case PT_SUNWCAP:
sec.cap.type = SINFO_T_CAP;
sinfo = &sec.cap;
break;
}
sinfo->vaddr = fstate.phdr[ndx].p_vaddr;
sinfo->offset = fstate.phdr[ndx].p_offset;
sinfo->size = fstate.phdr[ndx].p_filesz;
}
if (sec.dyn.type == SINFO_T_DYN)
(void) get_data(&fstate, &sec.dyn);
if ((sec.dyn.type == SINFO_T_DYN) && (sec.dyn.data->d_buf != NULL)) {
Dyn *dyn;
for (dyn = sec.dyn.data->d_buf; dyn->d_tag != DT_NULL; dyn++) {
switch (dyn->d_tag) {
case DT_HASH:
sec.hash.type = SINFO_T_HASH;
sec.hash.vaddr = dyn->d_un.d_ptr;
break;
case DT_STRTAB:
sec.dynstr.type = SINFO_T_DYNSTR;
sec.dynstr.vaddr = dyn->d_un.d_ptr;
break;
case DT_SYMTAB:
sec.dynsym.type = SINFO_T_DYNSYM;
sec.dynsym.vaddr = dyn->d_un.d_ptr;
break;
case DT_RELA:
sec.rela.type = SINFO_T_RELA;
sec.rela.vaddr = dyn->d_un.d_ptr;
break;
case DT_RELASZ:
sec.rela.size = dyn->d_un.d_val;
break;
case DT_STRSZ:
sec.dynstr.size = dyn->d_un.d_val;
break;
case DT_REL:
sec.rel.type = SINFO_T_REL;
sec.rel.vaddr = dyn->d_un.d_ptr;
break;
case DT_RELSZ:
sec.rel.size = dyn->d_un.d_val;
break;
case DT_INIT_ARRAY:
sec.initarr.type = SINFO_T_INITARR;
sec.initarr.vaddr = dyn->d_un.d_ptr;
break;
case DT_INIT_ARRAYSZ:
sec.initarr.size = dyn->d_un.d_val;
break;
case DT_FINI_ARRAY:
sec.finiarr.type = SINFO_T_FINIARR;
sec.finiarr.vaddr = dyn->d_un.d_ptr;
break;
case DT_FINI_ARRAYSZ:
sec.finiarr.size = dyn->d_un.d_val;
break;
case DT_PREINIT_ARRAY:
sec.preinitarr.type = SINFO_T_PREINITARR;
sec.preinitarr.vaddr = dyn->d_un.d_ptr;
break;
case DT_PREINIT_ARRAYSZ:
sec.preinitarr.size = dyn->d_un.d_val;
break;
case DT_SUNW_CAPINFO:
sec.capinfo.type = SINFO_T_CAPINFO;
sec.capinfo.vaddr = dyn->d_un.d_ptr;
break;
case DT_SUNW_CAPCHAIN:
sec.capchain.type = SINFO_T_CAPCHAIN;
sec.capchain.vaddr = dyn->d_un.d_ptr;
break;
case DT_SUNW_SYMTAB:
sec.ldynsym.type = SINFO_T_LDYNSYM;
sec.ldynsym.vaddr = dyn->d_un.d_ptr;
break;
case DT_SUNW_SYMSZ:
sec.ldynsym.size = dyn->d_un.d_val;
break;
case DT_SUNW_SYMSORT:
sec.symsort.type = SINFO_T_SYMSORT;
sec.symsort.vaddr = dyn->d_un.d_ptr;
break;
case DT_SUNW_SYMSORTSZ:
sec.symsort.size = dyn->d_un.d_val;
break;
case DT_SUNW_TLSSORT:
sec.tlssort.type = SINFO_T_TLSSORT;
sec.tlssort.vaddr = dyn->d_un.d_ptr;
break;
case DT_SUNW_TLSSORTSZ:
sec.tlssort.size = dyn->d_un.d_val;
break;
case DT_MOVETAB:
sec.move.type = SINFO_T_MOVE;
sec.move.vaddr = dyn->d_un.d_ptr;
break;
case DT_MOVESZ:
sec.move.size = dyn->d_un.d_val;
break;
case DT_SYMINFO:
sec.syminfo.type = SINFO_T_SYMINFO;
sec.syminfo.vaddr = dyn->d_un.d_ptr;
break;
case DT_SYMINSZ:
sec.syminfo.size = dyn->d_un.d_val;
break;
case DT_VERSYM:
sec.versym.type = SINFO_T_VERSYM;
sec.versym.vaddr = dyn->d_un.d_ptr;
break;
case DT_VERDEF:
sec.verdef.type = SINFO_T_VERDEF;
sec.verdef.vaddr = dyn->d_un.d_ptr;
break;
case DT_VERDEFNUM:
sec.verdef.vercnt = dyn->d_un.d_val;
sec.verdef.size = sizeof (Verdef) *
dyn->d_un.d_val;
break;
case DT_VERNEED:
sec.verneed.type = SINFO_T_VERNEED;
sec.verneed.vaddr = dyn->d_un.d_ptr;
break;
case DT_VERNEEDNUM:
sec.verneed.vercnt = dyn->d_un.d_val;
sec.verneed.size = sizeof (Verneed) *
dyn->d_un.d_val;
break;
}
}
}
if (sec.dynstr.size == 0)
sec.dynstr.type = SINFO_T_NULL;
if (sec.dynstr.type != SINFO_T_DYNSTR) {
sinfo_free(&sec.dyn, 1);
sec.dynsym.type = SINFO_T_NULL;
sec.dynsym.type = SINFO_T_NULL;
sec.verdef.type = SINFO_T_NULL;
sec.verneed.type = SINFO_T_NULL;
}
if (sec.hash.type == SINFO_T_HASH) {
Word nbucket;
Word nchain;
size_t total;
if (hash_size(&fstate, &sec.hash,
&nbucket, &nchain, &total) == 0) {
sec.hash.type = SINFO_T_NULL;
} else {
sec.hash.size = total * sizeof (Word);
sec.dynsym.size = nchain * sizeof (Sym);
sec.versym.size = nchain * sizeof (Versym);
if (sec.ldynsym.size > sec.dynsym.size)
sec.ldynsym.size -= sec.dynsym.size;
}
}
if (sec.hash.type != SINFO_T_HASH) {
sec.dynsym.type = SINFO_T_NULL;
sec.ldynsym.type = SINFO_T_NULL;
sec.versym.type = SINFO_T_NULL;
}
if ((sec.verdef.type == SINFO_T_VERDEF) &&
(verdefneed_size(&fstate, &sec.verdef) == 0))
sec.verdef.type = SINFO_T_NULL;
if ((sec.verneed.type == SINFO_T_VERNEED) &&
(verdefneed_size(&fstate, &sec.verneed) == 0))
sec.verneed.type = SINFO_T_NULL;
ndx = sinfo_n;
for (sinfo = secarr; ndx-- > 0; sinfo++)
if ((sinfo->type != SINFO_T_NULL) && (sinfo->size == 0))
sinfo->type = SINFO_T_NULL;
if (sec.dynsym.type != SINFO_T_DYNSYM) {
sec.ldynsym.type = SINFO_T_NULL;
sec.hash.type = SINFO_T_NULL;
sec.syminfo.type = SINFO_T_NULL;
sec.versym.type = SINFO_T_NULL;
sec.move.type = SINFO_T_NULL;
sec.rel.type = SINFO_T_NULL;
sec.rela.type = SINFO_T_NULL;
}
if (sec.ldynsym.type != SINFO_T_DYNSYM) {
sec.symsort.type = SINFO_T_NULL;
sec.tlssort.type = SINFO_T_NULL;
}
num_sinfo = num_list_sinfo = 0;
ndx = sinfo_n;
for (sinfo = secarr; ndx-- > 0; sinfo++) {
if ((sinfo->type != SINFO_T_NULL) && (sinfo->data == NULL))
(void) get_data(&fstate, sinfo);
if (sinfo->data != NULL)
num_sinfo++;
}
for (sinfo_list = seclist.next; sinfo_list != &seclist;
sinfo_list = sinfo_list->next) {
sinfo = &sinfo_list->sinfo;
if ((sinfo->type != SINFO_T_NULL) && (sinfo->data == NULL))
(void) get_data(&fstate, sinfo);
if (sinfo->data != NULL)
num_list_sinfo++;
}
*shnum = num_sinfo + num_list_sinfo + 1;
if ((*cache = _cache = malloc((*shnum) * sizeof (Cache))) == NULL) {
int err = errno;
(void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
file, strerror(err));
sinfo_free(secarr, num_sinfo);
sinfo_list_free_all(&seclist);
return (0);
}
*_cache = cache_init;
_cache++;
ndx = 1;
for (sinfo = secarr; num_sinfo > 0; sinfo++) {
if (sinfo->data != NULL) {
_cache->c_scn = NULL;
_cache->c_shdr = sinfo->shdr;
_cache->c_data = sinfo->data;
_cache->c_name = (char *)sinfo_data[sinfo->type].name;
_cache->c_ndx = ndx++;
_cache++;
num_sinfo--;
}
}
for (sinfo_list = seclist.next; num_list_sinfo > 0;
sinfo_list = sinfo_list->next) {
sinfo = &sinfo_list->sinfo;
if (sinfo->data != NULL) {
_cache->c_scn = NULL;
_cache->c_shdr = sinfo->shdr;
_cache->c_data = sinfo->data;
_cache->c_name = (char *)sinfo_data[sinfo->type].name;
_cache->c_ndx = ndx++;
_cache++;
num_list_sinfo--;
}
}
return (1);
}
void
fake_shdr_cache_free(Cache *cache, size_t shnum)
{
Cache *_cache;
for (_cache = cache; shnum--; _cache++) {
if (_cache->c_data != NULL) {
if (_cache->c_data->d_buf != NULL)
free(_cache->c_data->d_buf);
free(_cache->c_data);
}
if (_cache->c_shdr)
free(_cache->c_shdr);
}
free(cache);
}