The Pedigree Project 0.1
SymbolTable.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "pedigree/kernel/LockGuard.h"
21#include "pedigree/kernel/linker/SymbolTable.h"
22#include "pedigree/kernel/utilities/Iterator.h"
23
24#define RAII_LOCK ConstexprLockGuard<Mutex, THREADS> guard(m_Lock)
25
27 : m_LocalSymbols(),
28 m_GlobalSymbols(),
29 m_WeakSymbols(),
30 m_pOriginatingElf(pElf),
31 m_bPreallocated(false) {}
32
34
35void SymbolTable::copyTable(Elf* pNewElf, const SymbolTable& newSymtab) {
36 RAII_LOCK;
37
38 // Safe to do this, all members are SharedPointers and will be copy
39 // constructed by these operations.
40 m_LocalSymbols = newSymtab.m_LocalSymbols;
41 m_GlobalSymbols = newSymtab.m_GlobalSymbols;
42 m_WeakSymbols = newSymtab.m_WeakSymbols;
43}
44
45void SymbolTable::insert(const String& name, Binding binding, Elf* pParent, uintptr_t value) {
46 RAII_LOCK;
47
48 doInsert(name, binding, pParent, value);
49}
50
51void SymbolTable::insertMultiple(SymbolTable* pOther, const String& name, Binding binding,
52 Elf* pParent, uintptr_t value) {
53 RAII_LOCK;
54 ConstexprLockGuard<Mutex, THREADS> guard2(pOther->m_Lock);
55
56 SharedPointer<Symbol> ptr = doInsert(name, binding, pParent, value);
57 if (pOther)
58 pOther->insertShared(name, ptr);
59}
60
61void SymbolTable::preallocate(size_t numGlobal, size_t numWeak, Elf* localElf, size_t numLocal) {
62 RAII_LOCK;
63
64 auto tree = getOrInsertTree(localElf);
65 tree->reserve(numLocal);
66
67 tree = getOrInsertTree(localElf, Global);
68 tree->reserve(numGlobal);
69
70 tree = getOrInsertTree(localElf, Weak);
71 tree->reserve(numWeak);
72
73 m_bPreallocated = true;
74}
75
76void SymbolTable::preallocateAdditional(size_t numGlobal, size_t numWeak, Elf* localElf,
77 size_t numLocal) {
78 RAII_LOCK;
79
80 auto tree = getOrInsertTree(localElf, Global);
81 tree->reserve(tree->count() + numGlobal);
82
83 tree = getOrInsertTree(localElf, Weak);
84 tree->reserve(tree->count() + numWeak);
85
86 tree = getOrInsertTree(localElf);
87 tree->reserve(tree->count() + numLocal);
88
89 m_bPreallocated = true;
90}
91
93 RAII_LOCK;
94 return m_bPreallocated;
95}
96
98 Elf* pParent, uintptr_t value) {
99 Symbol* pSymbol = new Symbol(pParent, binding, value);
100 SharedPointer<Symbol> newSymbol(pSymbol);
101
102 insertShared(name, newSymbol);
103 return newSymbol;
104}
105
107 auto tree = getOrInsertTree(symbol->getParent(), symbol->getBinding());
108 tree->insert(name, symbol);
109}
110
111void SymbolTable::eraseByElf(Elf* pParent) {
112 RAII_LOCK;
113
114 // Will wipe out recursively by destroying the SharedPointers within.
115 m_LocalSymbols.remove(pParent);
116 m_GlobalSymbols.remove(pParent);
117 m_WeakSymbols.remove(pParent);
118}
119
120uintptr_t SymbolTable::lookup(const HashedStringView& name, Elf* pElf, Policy policy,
121 Binding* pBinding) {
122 RAII_LOCK;
123
124 // safe empty SharedPointer we can use for lookupRef()'s failed result
125 static SharedPointer<symbolTree_t> failedLookup;
126
127 uintptr_t lookupResult = 0;
128
129 // Local to the ELF file itself.
130 if (policy != NotOriginatingElf) {
131 const SharedPointer<symbolTree_t>& symbolTree = m_LocalSymbols.lookupRef(pElf, failedLookup);
132 if (symbolTree) {
133 symbolTree_t::LookupResult result = symbolTree->lookup(name);
134 if (result.hasValue()) {
135 lookupResult = result.value()->getValue();
136 }
137 }
138 }
139
140 // Global lookup across all ELFs that expose global symbols.
141 if (!lookupResult) {
142 for (parentedSymbolTree_t::Iterator it = m_GlobalSymbols.begin(); it != m_GlobalSymbols.end();
143 ++it) {
144 symbolTree_t::LookupResult result = it.value(failedLookup)->lookup(name);
145 if (result.hasValue()) {
146 lookupResult = result.value()->getValue();
147 break;
148 }
149 }
150 }
151
152 // Finally we try and find a usable weak symbol.
153 if (!lookupResult) {
154 for (parentedSymbolTree_t::Iterator it = m_WeakSymbols.begin(); it != m_WeakSymbols.end();
155 ++it) {
156 symbolTree_t::LookupResult result = it.value(failedLookup)->lookup(name);
157 if (result.hasValue()) {
158 lookupResult = result.value()->getValue();
159 break;
160 }
161 }
162 }
163
164 // NOTICE("SymbolTable::lookup(" << name << ", " << pElf->getName() << ")
165 // ==> " << Hex << lookupResult);
166
167 return lookupResult;
168}
169
170uintptr_t SymbolTable::lookupOwned(const HashedStringView& name, Elf* owner) {
171 RAII_LOCK;
172 static SharedPointer<symbolTree_t> missing;
173 const parentedSymbolTree_t* tables[] = {&m_GlobalSymbols, &m_WeakSymbols};
174 for (const auto* table : tables) {
175 const auto& symbols = table->lookupRef(owner, missing);
176 if (symbols) {
177 auto found = symbols->lookup(name);
178 if (found.hasValue()) {
179 return found.value()->getValue();
180 }
181 }
182 }
183 return 0;
184}
185
187 // safe empty SharedPointer we can use for lookupRef()'s failed result
189
191 switch (table) {
192 case Local:
193 tree = &m_LocalSymbols;
194 break;
195 case Global:
196 tree = &m_GlobalSymbols;
197 break;
198 default:
199 tree = &m_WeakSymbols;
200 break;
201 }
202
203 auto symbolTree = tree->lookupRef(p, v);
204 if (symbolTree) {
205 return symbolTree.get();
206 }
207
209 auto result = newTree.get();
210 tree->insert(p, pedigree_std::move(newTree));
211 return result;
212}
Definition Elf.h:201
static SharedPointer< T > allocate(Args...)
void insert(const String &name, Binding binding, Elf *pParent, uintptr_t value)
void preallocate(size_t numGlobal, size_t numWeak, Elf *localElf, size_t numLocal)
void insertMultiple(SymbolTable *pOther, const String &name, Binding binding, Elf *pParent, uintptr_t value)
uintptr_t lookupOwned(const HashedStringView &name, Elf *owner)
void copyTable(Elf *pNewElf, const SymbolTable &newSymtab)
SharedPointer< Symbol > doInsert(const String &name, Binding binding, Elf *pParent, uintptr_t value)
symbolTree_t * getOrInsertTree(Elf *, Binding table=Local)
void insertShared(const String &name, SharedPointer< Symbol > &symbol)
uintptr_t EXPORTED_PUBLIC lookup(const HashedStringView &name, Elf *pElf, Policy policy=LocalFirst, Binding *pBinding=0)
SymbolTable(Elf *pElf)
bool hasPreallocated() const
void preallocateAdditional(size_t numGlobal, size_t numWeak, Elf *localElf, size_t numLocal)
An iterator applicable for many data structures.
Definition Iterator.h:147
Iterator begin()
Definition Tree.h:402
void remove(const K &key)
Definition Tree.h:301
void insert(const K &key, const E &value)
Definition Tree.h:149
const E & lookupRef(const K &key, const E &failed=E()) const
Definition Tree.h:223
Iterator end()
Definition Tree.h:427