Skip to content

Commit 1278ee9

Browse files
MaskRaycopybara-github
authored andcommitted
vdso_support: support DT_GNU_HASH
This library provides `LookupSymbol` and `LookupSymbolByAddress`. The latter needs `GetNumSymbols` support. An object file needs either .hash (DT_HASH) or .gnu.hash (DT_GNU_HASH). This patch adds DT_GNU_HASH support. Note: glibc has been supporting DT_GNU_HASH since 2006 and .hash has been quite obsoleted in the Linux communities. PiperOrigin-RevId: 648459622 Change-Id: I3aa1274cd4617990844258175715e3be2343afd2
1 parent 37ebde5 commit 1278ee9

File tree

2 files changed

+51
-23
lines changed

2 files changed

+51
-23
lines changed

absl/debugging/internal/elf_mem_image.cc

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,11 @@
2020
#ifdef ABSL_HAVE_ELF_MEM_IMAGE // defined in elf_mem_image.h
2121

2222
#include <string.h>
23+
2324
#include <cassert>
2425
#include <cstddef>
26+
#include <cstdint>
27+
2528
#include "absl/base/config.h"
2629
#include "absl/base/internal/raw_logging.h"
2730

@@ -86,20 +89,14 @@ ElfMemImage::ElfMemImage(const void *base) {
8689
Init(base);
8790
}
8891

89-
int ElfMemImage::GetNumSymbols() const {
90-
if (!hash_) {
91-
return 0;
92-
}
93-
// See http://www.caldera.com/developers/gabi/latest/ch5.dynamic.html#hash
94-
return static_cast<int>(hash_[1]);
95-
}
92+
uint32_t ElfMemImage::GetNumSymbols() const { return num_syms_; }
9693

97-
const ElfW(Sym) *ElfMemImage::GetDynsym(int index) const {
94+
const ElfW(Sym) * ElfMemImage::GetDynsym(uint32_t index) const {
9895
ABSL_RAW_CHECK(index < GetNumSymbols(), "index out of range");
9996
return dynsym_ + index;
10097
}
10198

102-
const ElfW(Versym) *ElfMemImage::GetVersym(int index) const {
99+
const ElfW(Versym) *ElfMemImage::GetVersym(uint32_t index) const {
103100
ABSL_RAW_CHECK(index < GetNumSymbols(), "index out of range");
104101
return versym_ + index;
105102
}
@@ -154,7 +151,7 @@ void ElfMemImage::Init(const void *base) {
154151
dynstr_ = nullptr;
155152
versym_ = nullptr;
156153
verdef_ = nullptr;
157-
hash_ = nullptr;
154+
num_syms_ = 0;
158155
strsize_ = 0;
159156
verdefnum_ = 0;
160157
// Sentinel: PT_LOAD .p_vaddr can't possibly be this.
@@ -219,12 +216,17 @@ void ElfMemImage::Init(const void *base) {
219216
base_as_char - reinterpret_cast<const char *>(link_base_);
220217
ElfW(Dyn)* dynamic_entry = reinterpret_cast<ElfW(Dyn)*>(
221218
static_cast<intptr_t>(dynamic_program_header->p_vaddr) + relocation);
219+
uint32_t *sysv_hash = nullptr;
220+
uint32_t *gnu_hash = nullptr;
222221
for (; dynamic_entry->d_tag != DT_NULL; ++dynamic_entry) {
223222
const auto value =
224223
static_cast<intptr_t>(dynamic_entry->d_un.d_val) + relocation;
225224
switch (dynamic_entry->d_tag) {
226225
case DT_HASH:
227-
hash_ = reinterpret_cast<ElfW(Word) *>(value);
226+
sysv_hash = reinterpret_cast<uint32_t *>(value);
227+
break;
228+
case DT_GNU_HASH:
229+
gnu_hash = reinterpret_cast<uint32_t *>(value);
228230
break;
229231
case DT_SYMTAB:
230232
dynsym_ = reinterpret_cast<ElfW(Sym) *>(value);
@@ -249,13 +251,38 @@ void ElfMemImage::Init(const void *base) {
249251
break;
250252
}
251253
}
252-
if (!hash_ || !dynsym_ || !dynstr_ || !versym_ ||
254+
if ((!sysv_hash && !gnu_hash) || !dynsym_ || !dynstr_ || !versym_ ||
253255
!verdef_ || !verdefnum_ || !strsize_) {
254256
assert(false); // invalid VDSO
255257
// Mark this image as not present. Can not recur infinitely.
256258
Init(nullptr);
257259
return;
258260
}
261+
if (sysv_hash) {
262+
num_syms_ = sysv_hash[1];
263+
} else {
264+
assert(gnu_hash);
265+
// Compute the number of symbols for DT_GNU_HASH, which is specified by
266+
// https://sourceware.org/gnu-gabi/program-loading-and-dynamic-linking.txt
267+
uint32_t nbuckets = gnu_hash[0];
268+
// The buckets array is located after the header (4 uint32) and the bloom
269+
// filter (size_t array of gnu_hash[2] elements).
270+
uint32_t *buckets = gnu_hash + 4 + sizeof(size_t) / 4 * gnu_hash[2];
271+
// Find the chain of the last non-empty bucket.
272+
uint32_t idx = 0;
273+
for (uint32_t i = nbuckets; i > 0;) {
274+
idx = buckets[--i];
275+
if (idx != 0) break;
276+
}
277+
if (idx != 0) {
278+
// Find the last element of the chain, which has an odd value.
279+
// Add one to get the number of symbols.
280+
uint32_t *chain = buckets + nbuckets - gnu_hash[1];
281+
while (chain[idx++] % 2 == 0) {
282+
}
283+
}
284+
num_syms_ = idx;
285+
}
259286
}
260287

261288
bool ElfMemImage::LookupSymbol(const char *name,
@@ -300,9 +327,9 @@ bool ElfMemImage::LookupSymbolByAddress(const void *address,
300327
return false;
301328
}
302329

303-
ElfMemImage::SymbolIterator::SymbolIterator(const void *const image, int index)
304-
: index_(index), image_(image) {
305-
}
330+
ElfMemImage::SymbolIterator::SymbolIterator(const void *const image,
331+
uint32_t index)
332+
: index_(index), image_(image) {}
306333

307334
const ElfMemImage::SymbolInfo *ElfMemImage::SymbolIterator::operator->() const {
308335
return &info_;
@@ -335,7 +362,7 @@ ElfMemImage::SymbolIterator ElfMemImage::end() const {
335362
return SymbolIterator(this, GetNumSymbols());
336363
}
337364

338-
void ElfMemImage::SymbolIterator::Update(int increment) {
365+
void ElfMemImage::SymbolIterator::Update(uint32_t increment) {
339366
const ElfMemImage *image = reinterpret_cast<const ElfMemImage *>(image_);
340367
ABSL_RAW_CHECK(image->IsPresent() || increment == 0, "");
341368
if (!image->IsPresent()) {

absl/debugging/internal/elf_mem_image.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
// Including this will define the __GLIBC__ macro if glibc is being
2323
// used.
2424
#include <climits>
25+
#include <cstdint>
2526

2627
#include "absl/base/config.h"
2728

@@ -82,10 +83,10 @@ class ElfMemImage {
8283
bool operator!=(const SymbolIterator &rhs) const;
8384
bool operator==(const SymbolIterator &rhs) const;
8485
private:
85-
SymbolIterator(const void *const image, int index);
86-
void Update(int incr);
86+
SymbolIterator(const void *const image, uint32_t index);
87+
void Update(uint32_t incr);
8788
SymbolInfo info_;
88-
int index_;
89+
uint32_t index_;
8990
const void *const image_;
9091
};
9192

@@ -94,14 +95,14 @@ class ElfMemImage {
9495
void Init(const void *base);
9596
bool IsPresent() const { return ehdr_ != nullptr; }
9697
const ElfW(Phdr)* GetPhdr(int index) const;
97-
const ElfW(Sym)* GetDynsym(int index) const;
98-
const ElfW(Versym)* GetVersym(int index) const;
98+
const ElfW(Sym) * GetDynsym(uint32_t index) const;
99+
const ElfW(Versym)* GetVersym(uint32_t index) const;
99100
const ElfW(Verdef)* GetVerdef(int index) const;
100101
const ElfW(Verdaux)* GetVerdefAux(const ElfW(Verdef) *verdef) const;
101102
const char* GetDynstr(ElfW(Word) offset) const;
102103
const void* GetSymAddr(const ElfW(Sym) *sym) const;
103104
const char* GetVerstr(ElfW(Word) offset) const;
104-
int GetNumSymbols() const;
105+
uint32_t GetNumSymbols() const;
105106

106107
SymbolIterator begin() const;
107108
SymbolIterator end() const;
@@ -124,8 +125,8 @@ class ElfMemImage {
124125
const ElfW(Sym) *dynsym_;
125126
const ElfW(Versym) *versym_;
126127
const ElfW(Verdef) *verdef_;
127-
const ElfW(Word) *hash_;
128128
const char *dynstr_;
129+
uint32_t num_syms_;
129130
size_t strsize_;
130131
size_t verdefnum_;
131132
ElfW(Addr) link_base_; // Link-time base (p_vaddr of first PT_LOAD).

0 commit comments

Comments
 (0)