summaryrefslogtreecommitdiffstats
path: root/lib/libelf/libelf_convert.m4
diff options
context:
space:
mode:
authorkaiw <kaiw@FreeBSD.org>2010-07-21 10:57:22 +0000
committerkaiw <kaiw@FreeBSD.org>2010-07-21 10:57:22 +0000
commit8207e8cd23029b6bb700c58b2c33090d110866b2 (patch)
treeb377806e338037e4cc7c12def46d86b25c9eca17 /lib/libelf/libelf_convert.m4
parentd137ff16e759f7c0a6acea318e5bd3c932082d79 (diff)
downloadFreeBSD-src-8207e8cd23029b6bb700c58b2c33090d110866b2.zip
FreeBSD-src-8207e8cd23029b6bb700c58b2c33090d110866b2.tar.gz
Add support for translating sections of type ELF_T_GNUHASH.
Obtained from: elftoolchain MFC after: 1 month
Diffstat (limited to 'lib/libelf/libelf_convert.m4')
-rw-r--r--lib/libelf/libelf_convert.m4209
1 files changed, 207 insertions, 2 deletions
diff --git a/lib/libelf/libelf_convert.m4 b/lib/libelf/libelf_convert.m4
index e7f6950..f4d63fd 100644
--- a/lib/libelf/libelf_convert.m4
+++ b/lib/libelf/libelf_convert.m4
@@ -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,
OpenPOWER on IntegriCloud