Index: third_party/crazy_linker/crazy_linker/src/crazy_linker_elf_symbols.cpp |
diff --git a/third_party/crazy_linker/crazy_linker/src/crazy_linker_elf_symbols.cpp b/third_party/crazy_linker/crazy_linker/src/crazy_linker_elf_symbols.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..704076f1849b7a06b6a8e78bff40fd4c0a9e85ac |
--- /dev/null |
+++ b/third_party/crazy_linker/crazy_linker/src/crazy_linker_elf_symbols.cpp |
@@ -0,0 +1,146 @@ |
+// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "crazy_linker_elf_symbols.h" |
+ |
+#include "crazy_linker_debug.h" |
+#include "crazy_linker_elf_view.h" |
+ |
+namespace crazy { |
+ |
+namespace { |
+ |
+// Compute the ELF hash of a given symbol. |
+unsigned ElfHash(const char* name) { |
+ const uint8_t* ptr = reinterpret_cast<const uint8_t*>(name); |
+ unsigned h = 0; |
+ while (*ptr) { |
+ h = (h << 4) + *ptr++; |
+ unsigned g = h & 0xf0000000; |
+ h ^= g; |
+ h ^= g >> 24; |
+ } |
+ return h; |
+} |
+ |
+} // namespace |
+ |
+bool ElfSymbols::Init(const ElfView* view) { |
+ LOG("%s: Parsing dynamic table\n", __FUNCTION__); |
+ ElfView::DynamicIterator dyn(view); |
+ for (; dyn.HasNext(); dyn.GetNext()) { |
+ uintptr_t dyn_addr = dyn.GetAddress(view->load_bias()); |
+ switch (dyn.GetTag()) { |
+ case DT_HASH: |
+ LOG(" DT_HASH addr=%p\n", dyn_addr); |
+ { |
+ ELF::Addr* data = reinterpret_cast<uintptr_t*>(dyn_addr); |
+ hash_bucket_size_ = data[0]; |
+ hash_chain_size_ = data[1]; |
+ hash_bucket_ = data + 2; |
+ hash_chain_ = data + 2 + hash_bucket_size_; |
+ } |
+ break; |
+ case DT_STRTAB: |
+ LOG(" DT_STRTAB addr=%p\n", dyn_addr); |
+ string_table_ = reinterpret_cast<const char*>(dyn_addr); |
+ break; |
+ case DT_SYMTAB: |
+ LOG(" DT_SYMTAB addr=%p\n", dyn_addr); |
+ symbol_table_ = reinterpret_cast<const ELF::Sym*>(dyn_addr); |
+ break; |
+ default: |
+ ; |
+ } |
+ } |
+ if (symbol_table_ == NULL || string_table_ == NULL || hash_bucket_ == NULL) |
+ return false; |
+ |
+ return true; |
+} |
+ |
+const ELF::Sym* ElfSymbols::LookupByAddress(void* address, |
+ size_t load_bias) const { |
+ ELF::Addr elf_addr = |
+ reinterpret_cast<ELF::Addr>(address) - static_cast<ELF::Addr>(load_bias); |
+ |
+ for (size_t n = 0; n < hash_chain_size_; ++n) { |
+ const ELF::Sym* sym = &symbol_table_[n]; |
+ if (sym->st_shndx != SHN_UNDEF && elf_addr >= sym->st_value && |
+ elf_addr < sym->st_value + sym->st_size) { |
+ return sym; |
+ } |
+ } |
+ return NULL; |
+} |
+ |
+bool ElfSymbols::LookupNearestByAddress(void* address, |
+ size_t load_bias, |
+ const char** sym_name, |
+ void** sym_addr, |
+ size_t* sym_size) const { |
+ ELF::Addr elf_addr = |
+ reinterpret_cast<ELF::Addr>(address) - static_cast<ELF::Addr>(load_bias); |
+ |
+ const ELF::Sym* nearest_sym = NULL; |
+ size_t nearest_diff = ~size_t(0); |
+ |
+ for (size_t n = 0; n < hash_chain_size_; ++n) { |
+ const ELF::Sym* sym = &symbol_table_[n]; |
+ if (sym->st_shndx == SHN_UNDEF) |
+ continue; |
+ |
+ if (elf_addr >= sym->st_value && elf_addr < sym->st_value + sym->st_size) { |
+ // This is a perfect match. |
+ nearest_sym = sym; |
+ break; |
+ } |
+ |
+ // Otherwise, compute distance. |
+ size_t diff; |
+ if (elf_addr < sym->st_value) |
+ diff = sym->st_value - elf_addr; |
+ else |
+ diff = elf_addr - sym->st_value - sym->st_size; |
+ |
+ if (diff < nearest_diff) { |
+ nearest_sym = sym; |
+ nearest_diff = diff; |
+ } |
+ } |
+ |
+ if (!nearest_sym) |
+ return false; |
+ |
+ *sym_name = string_table_ + nearest_sym->st_name; |
+ *sym_addr = reinterpret_cast<void*>(nearest_sym->st_value + load_bias); |
+ *sym_size = nearest_sym->st_size; |
+ return true; |
+} |
+ |
+const ELF::Sym* ElfSymbols::LookupByName(const char* symbol_name) const { |
+ unsigned hash = ElfHash(symbol_name); |
+ |
+ for (unsigned n = hash_bucket_[hash % hash_bucket_size_]; n != 0; |
+ n = hash_chain_[n]) { |
+ const ELF::Sym* symbol = &symbol_table_[n]; |
+ // Check that the symbol has the appropriate name. |
+ if (strcmp(string_table_ + symbol->st_name, symbol_name)) |
+ continue; |
+ // Ignore undefined symbols. |
+ if (symbol->st_shndx == SHN_UNDEF) |
+ continue; |
+ // Ignore anything that isn't a global or weak definition. |
+ switch (ELF_ST_BIND(symbol->st_info)) { |
+ case STB_GLOBAL: |
+ case STB_WEAK: |
+ return symbol; |
+ default: |
+ ; |
+ } |
+ } |
+ return NULL; |
+} |
+ |
+} // namespace crazy |