headers/bsd: Add sys/queue.h.
[haiku.git] / src / kits / debugger / elf / ElfSymbolLookup.cpp
blob1d1474b95db035321c8daac7dbf32361dc0c0bd9
1 /*
2 * Copyright 2016, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "ElfSymbolLookup.h"
9 #include <algorithm>
11 #include <image.h>
14 static const size_t kMaxSymbolNameLength = 64 * 1024;
15 static const size_t kMaxReadStringChunkSize = 1024;
16 static const size_t kCacheBufferSize = 4 * 1024;
19 struct CachedSymbolLookupSource : public ElfSymbolLookupSource {
20 CachedSymbolLookupSource(ElfSymbolLookupSource* source)
22 fSource(source),
23 fBufferSize(0)
25 for (int i = 0; i < 2; i++) {
26 fBuffer[i] = 0;
27 fAddress[i] = 0;
28 fCachedSize[i] = 0;
29 fHitEnd[i] = true;
32 fSource->AcquireReference();
35 ~CachedSymbolLookupSource()
37 delete[] fBuffer[0];
39 fSource->ReleaseReference();
42 status_t Init(size_t bufferSize)
44 fBuffer[0] = new(std::nothrow) uint8[bufferSize * 2];
45 if (fBuffer[0] == NULL)
46 return B_NO_MEMORY;
48 fBuffer[1] = fBuffer[0] + bufferSize;
49 fBufferSize = bufferSize;
50 return B_OK;
53 virtual ssize_t Read(uint64 address, void* _buffer, size_t size)
55 uint8* buffer = (uint8*)_buffer;
56 size_t totalRead = 0;
58 while (size > 0) {
59 ssize_t bytesRead = _ReadPartial(address, buffer, size);
60 if (bytesRead < 0)
61 return totalRead == 0 ? bytesRead : totalRead;
62 if (bytesRead == 0)
63 return totalRead == 0 ? B_IO_ERROR : totalRead;
65 totalRead += bytesRead;
66 buffer += bytesRead;
67 size -= bytesRead;
70 return totalRead;
73 private:
74 ssize_t _ReadPartial(uint64 address, uint8* buffer, size_t size)
76 size_t bytesRead = _ReadCached(address, buffer, size);
77 if (bytesRead > 0)
78 return bytesRead;
80 status_t error = _Cache(address, size);
81 if (error != B_OK)
82 return error;
84 return (ssize_t)_ReadCached(address, buffer, size);
87 size_t _ReadCached(uint64 address, uint8* buffer, size_t size)
89 for (int i = 0; i < 2; i++) {
90 if (address >= fAddress[i]
91 && address < fAddress[i] + fCachedSize[i]) {
92 size_t toRead = std::min(size,
93 size_t(fAddress[i] + fCachedSize[i] - address));
94 memcpy(buffer, fBuffer[i] + (address - fAddress[i]), toRead);
95 fHitEnd[i] = address + toRead == fAddress[i] + fCachedSize[i];
96 return toRead;
99 return 0;
102 status_t _Cache(uint64 address, size_t size)
104 int i = 0;
105 if (!fHitEnd[i])
106 i++;
108 ssize_t bytesRead = fSource->Read(address, fBuffer[i], fBufferSize);
109 if (bytesRead < 0)
110 return bytesRead;
111 if (bytesRead == 0)
112 return B_IO_ERROR;
114 fAddress[i] = address;
115 fCachedSize[i] = bytesRead;
116 fHitEnd[i] = false;
117 return B_OK;
120 private:
121 ElfSymbolLookupSource* fSource;
122 uint8* fBuffer[2];
123 uint64 fAddress[2];
124 size_t fCachedSize[2];
125 bool fHitEnd[2];
126 size_t fBufferSize;
130 // #pragma mark - ElfSymbolLookupImpl
133 template<typename ElfClass>
134 class ElfSymbolLookupImpl : public ElfSymbolLookup {
135 public:
136 typedef typename ElfClass::Sym ElfSym;
138 ElfSymbolLookupImpl(ElfSymbolLookupSource* source, uint64 symbolTable,
139 uint64 symbolHash, uint64 stringTable, uint32 symbolCount,
140 uint32 symbolTableEntrySize, uint64 textDelta, bool swappedByteOrder)
142 fSource(NULL),
143 fSymbolTable(symbolTable),
144 fSymbolHash(symbolHash),
145 fStringTable(stringTable),
146 fSymbolCount(symbolCount),
147 fSymbolTableEntrySize(symbolTableEntrySize),
148 fTextDelta(textDelta),
149 fSwappedByteOrder(swappedByteOrder)
151 SetSource(source);
154 ~ElfSymbolLookupImpl()
156 SetSource(NULL);
159 template<typename Value>
160 Value Get(const Value& value) const
162 return ElfFile::StaticGet(value, fSwappedByteOrder);
165 void SetSource(ElfSymbolLookupSource* source)
167 if (source == fSource)
168 return;
170 if (fSource != NULL)
171 fSource->ReleaseReference();
173 fSource = source;
175 if (fSource != NULL)
176 fSource->AcquireReference();
179 virtual status_t Init(bool cacheSource)
181 if (fSymbolTableEntrySize < sizeof(ElfSym))
182 return B_BAD_DATA;
184 // Create a cached source, if requested.
185 if (cacheSource) {
186 CachedSymbolLookupSource* cachedSource
187 = new(std::nothrow) CachedSymbolLookupSource(fSource);
188 if (cachedSource == NULL)
189 return B_NO_MEMORY;
191 SetSource(cachedSource);
193 status_t error = cachedSource->Init(kCacheBufferSize);
194 if (error != B_OK)
195 return error;
198 if (fSymbolCount == kGetSymbolCountFromHash) {
199 // Read the number of symbols in the symbol table from the hash
200 // table entry 1.
201 uint32 symbolCount;
202 ssize_t bytesRead = fSource->Read(fSymbolHash + 4, &symbolCount, 4);
203 if (bytesRead < 0)
204 return bytesRead;
205 if (bytesRead != 4)
206 return B_IO_ERROR;
208 fSymbolCount = Get(symbolCount);
211 return B_OK;
214 virtual status_t NextSymbolInfo(uint32& index, SymbolInfo& _info)
216 uint64 symbolAddress = fSymbolTable + index * fSymbolTableEntrySize;
217 for (; index < fSymbolCount;
218 index++, symbolAddress += fSymbolTableEntrySize) {
219 // read the symbol structure
220 ElfSym symbol;
221 ssize_t bytesRead = fSource->Read(symbolAddress, &symbol,
222 sizeof(symbol));
223 if (bytesRead < 0)
224 return bytesRead;
225 if ((size_t)bytesRead != sizeof(symbol))
226 return B_IO_ERROR;
228 // check, if it is a function or a data object and defined
229 // Note: Type() operates on a uint8, so byte order is irrelevant.
230 if ((symbol.Type() != STT_FUNC && symbol.Type() != STT_OBJECT)
231 || symbol.st_value == 0) {
232 continue;
235 // get the values
236 target_addr_t address = Get(symbol.st_value) + fTextDelta;
237 target_size_t size = Get(symbol.st_size);
238 uint32 type = symbol.Type() == STT_FUNC
239 ? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA;
241 // get the symbol name
242 uint64 nameAddress = fStringTable + Get(symbol.st_name);
243 BString name;
244 status_t error = _ReadString(nameAddress, kMaxSymbolNameLength,
245 name);
246 if (error != B_OK)
247 return error;
249 _info.SetTo(address, size, type, name);
250 index++;
251 return B_OK;
254 return B_ENTRY_NOT_FOUND;
257 virtual status_t GetSymbolInfo(const char* name, uint32 symbolType,
258 SymbolInfo& _info)
260 // TODO: Optimize this by using the hash table.
261 uint32 index = 0;
262 SymbolInfo info;
263 while (NextSymbolInfo(index, info) == B_OK) {
264 if (strcmp(name, info.Name()) == 0) {
265 _info = info;
266 return B_OK;
270 return B_ENTRY_NOT_FOUND;
273 private:
274 status_t _ReadString(uint64 address, size_t size, BString& _string)
276 _string.Truncate(0);
278 char buffer[kMaxReadStringChunkSize];
279 while (size > 0) {
280 size_t toRead = std::min(size, sizeof(buffer));
281 ssize_t bytesRead = fSource->Read(address, buffer, toRead);
282 if (bytesRead < 0)
283 return bytesRead;
284 if (bytesRead == 0)
285 return B_IO_ERROR;
287 size_t chunkSize = strnlen(buffer, bytesRead);
288 int32 oldLength = _string.Length();
289 _string.Append(buffer, chunkSize);
290 if (_string.Length() <= oldLength)
291 return B_NO_MEMORY;
293 if (chunkSize < (size_t)bytesRead) {
294 // we found a terminating null
295 return B_OK;
298 address += bytesRead;
299 size -= bytesRead;
302 return B_BAD_DATA;
305 private:
306 ElfSymbolLookupSource* fSource;
307 uint64 fSymbolTable;
308 uint64 fSymbolHash;
309 uint64 fStringTable;
310 uint32 fSymbolCount;
311 uint32 fSymbolTableEntrySize;
312 uint64 fTextDelta;
313 bool fSwappedByteOrder;
317 // #pragma mark - ElfSymbolLookup
320 ElfSymbolLookup::~ElfSymbolLookup()
325 /*static*/ status_t
326 ElfSymbolLookup::Create(ElfSymbolLookupSource* source, uint64 symbolTable,
327 uint64 symbolHash, uint64 stringTable, uint32 symbolCount,
328 uint32 symbolTableEntrySize, uint64 textDelta, bool is64Bit,
329 bool swappedByteOrder, bool cacheSource, ElfSymbolLookup*& _lookup)
331 // create
332 ElfSymbolLookup* lookup;
333 if (is64Bit) {
334 lookup = new(std::nothrow) ElfSymbolLookupImpl<ElfClass64>(source,
335 symbolTable, symbolHash, stringTable, symbolCount,
336 symbolTableEntrySize, textDelta, swappedByteOrder);
337 } else {
338 lookup = new(std::nothrow) ElfSymbolLookupImpl<ElfClass32>(source,
339 symbolTable, symbolHash, stringTable, symbolCount,
340 symbolTableEntrySize, textDelta, swappedByteOrder);
343 if (lookup == NULL)
344 return B_NO_MEMORY;
346 // init
347 status_t error = lookup->Init(cacheSource);
348 if (error == B_OK)
349 _lookup = lookup;
350 else
351 delete lookup;
353 return error;