Module Name: src
Committed By: pooka
Date: Tue Dec 11 21:16:23 UTC 2012
Modified Files:
src/lib/librumpuser: rumpuser_dl.c
Log Message:
Support binaries which use DT_GNU_HASH instead of DT_HASH.
To generate a diff of this commit:
cvs rdiff -u -r1.10 -r1.11 src/lib/librumpuser/rumpuser_dl.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/lib/librumpuser/rumpuser_dl.c
diff -u src/lib/librumpuser/rumpuser_dl.c:1.10 src/lib/librumpuser/rumpuser_dl.c:1.11
--- src/lib/librumpuser/rumpuser_dl.c:1.10 Mon Nov 26 17:55:11 2012
+++ src/lib/librumpuser/rumpuser_dl.c Tue Dec 11 21:16:22 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: rumpuser_dl.c,v 1.10 2012/11/26 17:55:11 pooka Exp $ */
+/* $NetBSD: rumpuser_dl.c,v 1.11 2012/12/11 21:16:22 pooka Exp $ */
/*
* Copyright (c) 2009 Antti Kantee. All Rights Reserved.
@@ -33,7 +33,7 @@
#include "rumpuser_port.h"
#if !defined(lint)
-__RCSID("$NetBSD: rumpuser_dl.c,v 1.10 2012/11/26 17:55:11 pooka Exp $");
+__RCSID("$NetBSD: rumpuser_dl.c,v 1.11 2012/12/11 21:16:22 pooka Exp $");
#endif /* !lint */
#include <sys/types.h>
@@ -213,6 +213,53 @@ getsymbols(struct link_map *map)
hashtab = (Elf_Symindx *)adjptr(map, edptr);
cursymcount = hashtab[1];
break;
+#ifdef DT_GNU_HASH
+ /*
+ * DT_GNU_HASH is a bit more complicated than DT_HASH
+ * in this regard since apparently there is no field
+ * telling us the total symbol count. Instead, we look
+ * for the last valid hash bucket and add its chain lenght
+ * to the bucket's base index.
+ */
+ case DT_GNU_HASH: {
+ Elf32_Word nbuck, symndx, maskwords, maxchain = 0;
+ Elf32_Word *gnuhash, *buckets, *ptr;
+ int bi;
+
+ DYNn_GETMEMBER(ed_base, i, d_un.d_ptr, edptr);
+ gnuhash = (Elf32_Word *)adjptr(map, edptr);
+
+ nbuck = gnuhash[0];
+ symndx = gnuhash[1];
+ maskwords = gnuhash[2];
+
+ /*
+ * First, find the last valid bucket and grab its index
+ */
+ if (eident == ELFCLASS64)
+ maskwords *= 2; /* sizeof(*buckets) == 4 */
+ buckets = gnuhash + 4 + maskwords;
+ for (bi = nbuck-1; bi >= 0; bi--) {
+ if (buckets[bi] != 0) {
+ maxchain = buckets[bi];
+ break;
+ }
+ }
+ if (maxchain == 0 || maxchain < symndx)
+ break;
+
+ /*
+ * Then, traverse the last chain and count symbols.
+ */
+
+ cursymcount = maxchain;
+ ptr = buckets + nbuck + (maxchain - symndx);
+ do {
+ cursymcount++;
+ } while ((*ptr++ & 1) == 0);
+ }
+ break;
+#endif
case DT_SYMENT:
DYNn_GETMEMBER(ed_base, i, d_un.d_val, edval);
assert(edval == SYM_GETSIZE());