2 * Copyright 2016, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
7 #include "ElfSymbolLookup.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
)
25 for (int i
= 0; i
< 2; i
++) {
32 fSource
->AcquireReference();
35 ~CachedSymbolLookupSource()
39 fSource
->ReleaseReference();
42 status_t
Init(size_t bufferSize
)
44 fBuffer
[0] = new(std::nothrow
) uint8
[bufferSize
* 2];
45 if (fBuffer
[0] == NULL
)
48 fBuffer
[1] = fBuffer
[0] + bufferSize
;
49 fBufferSize
= bufferSize
;
53 virtual ssize_t
Read(uint64 address
, void* _buffer
, size_t size
)
55 uint8
* buffer
= (uint8
*)_buffer
;
59 ssize_t bytesRead
= _ReadPartial(address
, buffer
, size
);
61 return totalRead
== 0 ? bytesRead
: totalRead
;
63 return totalRead
== 0 ? B_IO_ERROR
: totalRead
;
65 totalRead
+= bytesRead
;
74 ssize_t
_ReadPartial(uint64 address
, uint8
* buffer
, size_t size
)
76 size_t bytesRead
= _ReadCached(address
, buffer
, size
);
80 status_t error
= _Cache(address
, size
);
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
];
102 status_t
_Cache(uint64 address
, size_t size
)
108 ssize_t bytesRead
= fSource
->Read(address
, fBuffer
[i
], fBufferSize
);
114 fAddress
[i
] = address
;
115 fCachedSize
[i
] = bytesRead
;
121 ElfSymbolLookupSource
* fSource
;
124 size_t fCachedSize
[2];
130 // #pragma mark - ElfSymbolLookupImpl
133 template<typename ElfClass
>
134 class ElfSymbolLookupImpl
: public ElfSymbolLookup
{
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
)
143 fSymbolTable(symbolTable
),
144 fSymbolHash(symbolHash
),
145 fStringTable(stringTable
),
146 fSymbolCount(symbolCount
),
147 fSymbolTableEntrySize(symbolTableEntrySize
),
148 fTextDelta(textDelta
),
149 fSwappedByteOrder(swappedByteOrder
)
154 ~ElfSymbolLookupImpl()
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
)
171 fSource
->ReleaseReference();
176 fSource
->AcquireReference();
179 virtual status_t
Init(bool cacheSource
)
181 if (fSymbolTableEntrySize
< sizeof(ElfSym
))
184 // Create a cached source, if requested.
186 CachedSymbolLookupSource
* cachedSource
187 = new(std::nothrow
) CachedSymbolLookupSource(fSource
);
188 if (cachedSource
== NULL
)
191 SetSource(cachedSource
);
193 status_t error
= cachedSource
->Init(kCacheBufferSize
);
198 if (fSymbolCount
== kGetSymbolCountFromHash
) {
199 // Read the number of symbols in the symbol table from the hash
202 ssize_t bytesRead
= fSource
->Read(fSymbolHash
+ 4, &symbolCount
, 4);
208 fSymbolCount
= Get(symbolCount
);
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
221 ssize_t bytesRead
= fSource
->Read(symbolAddress
, &symbol
,
225 if ((size_t)bytesRead
!= sizeof(symbol
))
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) {
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
);
244 status_t error
= _ReadString(nameAddress
, kMaxSymbolNameLength
,
249 _info
.SetTo(address
, size
, type
, name
);
254 return B_ENTRY_NOT_FOUND
;
257 virtual status_t
GetSymbolInfo(const char* name
, uint32 symbolType
,
260 // TODO: Optimize this by using the hash table.
263 while (NextSymbolInfo(index
, info
) == B_OK
) {
264 if (strcmp(name
, info
.Name()) == 0) {
270 return B_ENTRY_NOT_FOUND
;
274 status_t
_ReadString(uint64 address
, size_t size
, BString
& _string
)
278 char buffer
[kMaxReadStringChunkSize
];
280 size_t toRead
= std::min(size
, sizeof(buffer
));
281 ssize_t bytesRead
= fSource
->Read(address
, buffer
, toRead
);
287 size_t chunkSize
= strnlen(buffer
, bytesRead
);
288 int32 oldLength
= _string
.Length();
289 _string
.Append(buffer
, chunkSize
);
290 if (_string
.Length() <= oldLength
)
293 if (chunkSize
< (size_t)bytesRead
) {
294 // we found a terminating null
298 address
+= bytesRead
;
306 ElfSymbolLookupSource
* fSource
;
311 uint32 fSymbolTableEntrySize
;
313 bool fSwappedByteOrder
;
317 // #pragma mark - ElfSymbolLookup
320 ElfSymbolLookup::~ElfSymbolLookup()
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
)
332 ElfSymbolLookup
* lookup
;
334 lookup
= new(std::nothrow
) ElfSymbolLookupImpl
<ElfClass64
>(source
,
335 symbolTable
, symbolHash
, stringTable
, symbolCount
,
336 symbolTableEntrySize
, textDelta
, swappedByteOrder
);
338 lookup
= new(std::nothrow
) ElfSymbolLookupImpl
<ElfClass32
>(source
,
339 symbolTable
, symbolHash
, stringTable
, symbolCount
,
340 symbolTableEntrySize
, textDelta
, swappedByteOrder
);
347 status_t error
= lookup
->Init(cacheSource
);