Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 21 Jul 2010 10:57:22 +0000 (UTC)
From:      Kai Wang <kaiw@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r210341 - head/lib/libelf
Message-ID:  <201007211057.o6LAvMCf095386@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kaiw
Date: Wed Jul 21 10:57:22 2010
New Revision: 210341
URL: http://svn.freebsd.org/changeset/base/210341

Log:
  Add support for translating sections of type ELF_T_GNUHASH.
  
  Obtained from:	elftoolchain
  MFC after:		1 month

Modified:
  head/lib/libelf/elf_types.m4
  head/lib/libelf/libelf_convert.m4

Modified: head/lib/libelf/elf_types.m4
==============================================================================
--- head/lib/libelf/elf_types.m4	Wed Jul 21 10:39:29 2010	(r210340)
+++ head/lib/libelf/elf_types.m4	Wed Jul 21 10:57:22 2010	(r210341)
@@ -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',

Modified: head/lib/libelf/libelf_convert.m4
==============================================================================
--- head/lib/libelf/libelf_convert.m4	Wed Jul 21 10:39:29 2010	(r210340)
+++ head/lib/libelf/libelf_convert.m4	Wed Jul 21 10:57:22 2010	(r210341)
@@ -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 ds
 	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 ds
 		dst += sz;
 
 		count -= sz;
+		dsz -= sz;
 	}
 
 	return (1);
@@ -623,8 +822,6 @@ libelf_cvt_NOTE_tof(char *dst, size_t ds
 	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,



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201007211057.o6LAvMCf095386>