Add support for translating sections of type ELF_T_GNUHASH.

Obtained from:	elftoolchain
MFC after:		1 month
This commit is contained in:
Kai Wang 2010-07-21 10:57:22 +00:00
parent fff07a4233
commit 1d69e83ddd
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=210341
2 changed files with 208 additions and 2 deletions

View File

@ -46,6 +46,7 @@ define(`ELF_TYPE_LIST',
`CAP, Cap, 700025',
`DYN, Dyn, 600102',
`EHDR, Ehdr, 600102',
`GNUHASH, -, 800062',
`HALF, Half, 600102',
`LWORD, Lword, 700025',
`MOVE, Move, 700025',

View File

@ -234,6 +234,7 @@ define(`IGNORE',
IGNORE(MOVEP)
IGNORE(NOTE)
IGNORE(GNUHASH)
define(IGNORE_BYTE, 1) /* 'lator, leave 'em bytes alone */
define(IGNORE_GNUHASH, 1)
@ -504,12 +505,209 @@ libelf_cvt_BYTE_tox(char *dst, size_t dsz, char *src, size_t count,
return (1);
}
MAKE_TYPE_CONVERTERS(ELF_TYPE_LIST)
/*
* Sections of type ELF_T_GNUHASH start with a header containing 4 32-bit
* words. Bloom filter data comes next, followed by hash buckets and the
* hash chain.
*
* Bloom filter words are 64 bit wide on ELFCLASS64 objects and are 32 bit
* wide on ELFCLASS32 objects. The other objects in this section are 32
* bits wide.
*
* Argument `srcsz' denotes the number of bytes to be converted. In the
* 32-bit case we need to translate `srcsz' to a count of 32-bit words.
*/
static int
libelf_cvt32_GNUHASH_tom(char *dst, size_t dsz, char *src, size_t srcsz,
int byteswap)
{
return (libelf_cvt_WORD_tom(dst, dsz, src, srcsz / sizeof(uint32_t),
byteswap));
}
static int
libelf_cvt32_GNUHASH_tof(char *dst, size_t dsz, char *src, size_t srcsz,
int byteswap)
{
return (libelf_cvt_WORD_tof(dst, dsz, src, srcsz / sizeof(uint32_t),
byteswap));
}
static int
libelf_cvt64_GNUHASH_tom(char *dst, size_t dsz, char *src, size_t srcsz,
int byteswap)
{
size_t sz;
uint64_t t64, *bloom64;
Elf_GNU_Hash_Header *gh;
uint32_t n, nbuckets, nchains, maskwords, shift2, symndx, t32;
uint32_t *buckets, *chains;
sz = 4 * sizeof(uint32_t); /* File header is 4 words long. */
if (dsz < sizeof(Elf_GNU_Hash_Header) || srcsz < sz)
return (0);
/* Read in the section header and byteswap if needed. */
READ_WORD(src, nbuckets);
READ_WORD(src, symndx);
READ_WORD(src, maskwords);
READ_WORD(src, shift2);
srcsz -= sz;
if (byteswap) {
SWAP_WORD(nbuckets);
SWAP_WORD(symndx);
SWAP_WORD(maskwords);
SWAP_WORD(shift2);
}
/* Check source buffer and destination buffer sizes. */
sz = nbuckets * sizeof(uint32_t) + maskwords * sizeof(uint64_t);
if (srcsz < sz || dsz < sz + sizeof(Elf_GNU_Hash_Header))
return (0);
gh = (Elf_GNU_Hash_Header *) (uintptr_t) dst;
gh->gh_nbuckets = nbuckets;
gh->gh_symndx = symndx;
gh->gh_maskwords = maskwords;
gh->gh_shift2 = shift2;
dsz -= sizeof(Elf_GNU_Hash_Header);
dst += sizeof(Elf_GNU_Hash_Header);
bloom64 = (uint64_t *) (uintptr_t) dst;
/* Copy bloom filter data. */
for (n = 0; n < maskwords; n++) {
READ_XWORD(src, t64);
if (byteswap)
SWAP_XWORD(t64);
bloom64[n] = t64;
}
/* The hash buckets follows the bloom filter. */
dst += maskwords * sizeof(uint64_t);
buckets = (uint32_t *) (uintptr_t) dst;
for (n = 0; n < nbuckets; n++) {
READ_WORD(src, t32);
if (byteswap)
SWAP_WORD(t32);
buckets[n] = t32;
}
dst += nbuckets * sizeof(uint32_t);
/* The hash chain follows the hash buckets. */
dsz -= sz;
srcsz -= sz;
if (dsz < srcsz) /* Destination lacks space. */
return (0);
nchains = srcsz / sizeof(uint32_t);
chains = (uint32_t *) (uintptr_t) dst;
for (n = 0; n < nchains; n++) {
READ_WORD(src, t32);
if (byteswap)
SWAP_WORD(t32);
*chains++ = t32;
}
return (1);
}
static int
libelf_cvt64_GNUHASH_tof(char *dst, size_t dsz, char *src, size_t srcsz,
int byteswap)
{
uint32_t *s32;
size_t sz, hdrsz;
uint64_t *s64, t64;
Elf_GNU_Hash_Header *gh;
uint32_t maskwords, n, nbuckets, nchains, t0, t1, t2, t3, t32;
hdrsz = 4 * sizeof(uint32_t); /* Header is 4x32 bits. */
if (dsz < hdrsz || srcsz < sizeof(Elf_GNU_Hash_Header))
return (0);
gh = (Elf_GNU_Hash_Header *) (uintptr_t) src;
t0 = nbuckets = gh->gh_nbuckets;
t1 = gh->gh_symndx;
t2 = maskwords = gh->gh_maskwords;
t3 = gh->gh_shift2;
src += sizeof(Elf_GNU_Hash_Header);
srcsz -= sizeof(Elf_GNU_Hash_Header);
dsz -= hdrsz;
sz = gh->gh_nbuckets * sizeof(uint32_t) + gh->gh_maskwords *
sizeof(uint64_t);
if (srcsz < sz || dsz < sz)
return (0);
/* Write out the header. */
if (byteswap) {
SWAP_WORD(t0);
SWAP_WORD(t1);
SWAP_WORD(t2);
SWAP_WORD(t3);
}
WRITE_WORD(dst, t0);
WRITE_WORD(dst, t1);
WRITE_WORD(dst, t2);
WRITE_WORD(dst, t3);
/* Copy the bloom filter and the hash table. */
s64 = (uint64_t *) (uintptr_t) src;
for (n = 0; n < maskwords; n++) {
t64 = *s64++;
if (byteswap)
SWAP_XWORD(t64);
WRITE_WORD64(dst, t64);
}
s32 = (uint32_t *) s64;
for (n = 0; n < nbuckets; n++) {
t32 = *s32++;
if (byteswap)
SWAP_WORD(t32);
WRITE_WORD(dst, t32);
}
srcsz -= sz;
dsz -= sz;
/* Copy out the hash chains. */
if (dsz < srcsz)
return (0);
nchains = srcsz / sizeof(uint32_t);
for (n = 0; n < nchains; n++) {
t32 = *s32++;
if (byteswap)
SWAP_WORD(t32);
WRITE_WORD(dst, t32);
}
return (1);
}
/*
* Elf_Note structures comprise a fixed size header followed by variable
* length strings. The fixed size header needs to be byte swapped, but
* not the strings.
*
* Argument `count' denotes the total number of bytes to be converted.
* The destination buffer needs to be at least `count' bytes in size.
*/
static int
libelf_cvt_NOTE_tom(char *dst, size_t dsz, char *src, size_t count,
@ -567,6 +765,7 @@ libelf_cvt_NOTE_tom(char *dst, size_t dsz, char *src, size_t count,
dst += sz;
count -= sz;
dsz -= sz;
}
return (1);
@ -623,8 +822,6 @@ libelf_cvt_NOTE_tof(char *dst, size_t dsz, char *src, size_t count,
return (1);
}
MAKE_TYPE_CONVERTERS(ELF_TYPE_LIST)
struct converters {
int (*tof32)(char *dst, size_t dsz, char *src, size_t cnt,
int byteswap);
@ -675,6 +872,14 @@ CONVERTER_NAMES(ELF_TYPE_LIST)
.tof64 = libelf_cvt_BYTE_tox,
.tom64 = libelf_cvt_BYTE_tox
},
[ELF_T_GNUHASH] = {
.tof32 = libelf_cvt32_GNUHASH_tof,
.tom32 = libelf_cvt32_GNUHASH_tom,
.tof64 = libelf_cvt64_GNUHASH_tof,
.tom64 = libelf_cvt64_GNUHASH_tom
},
[ELF_T_NOTE] = {
.tof32 = libelf_cvt_NOTE_tof,
.tom32 = libelf_cvt_NOTE_tom,