1 /*
2 * Copyright 2005-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6 #include "Image.h"
7
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/mman.h>
13 #include <unistd.h>
14
15 #include <new>
16
17 #include <runtime_loader.h>
18 #include <syscalls.h>
19
20
21 using namespace BPrivate::Debug;
22
23
24 // #pragma mark - Image
25
26
Image()27 Image::Image()
28 {
29 }
30
31
~Image()32 Image::~Image()
33 {
34 }
35
36
37 status_t
GetSymbol(const char * name,int32 symbolType,void ** _symbolLocation,size_t * _symbolSize,int32 * _symbolType) const38 Image::GetSymbol(const char* name, int32 symbolType, void** _symbolLocation,
39 size_t* _symbolSize, int32* _symbolType) const
40 {
41 // TODO: At least for ImageFile we could do hash lookups!
42 int32 iterator = 0;
43 const char* foundName;
44 size_t foundNameLen;
45 addr_t foundAddress;
46 size_t foundSize;
47 int32 foundType;
48 while (NextSymbol(iterator, &foundName, &foundNameLen, &foundAddress,
49 &foundSize, &foundType) == B_OK) {
50 if ((symbolType == B_SYMBOL_TYPE_ANY || symbolType == foundType)
51 && strcmp(name, foundName) == 0) {
52 if (_symbolLocation != NULL)
53 *_symbolLocation = (void*)foundAddress;
54 if (_symbolSize != NULL)
55 *_symbolSize = foundSize;
56 if (_symbolType != NULL)
57 *_symbolType = foundType;
58 return B_OK;
59 }
60 }
61
62 return B_ENTRY_NOT_FOUND;
63 }
64
65
66 // #pragma mark - SymbolTableBasedImage
67
68
SymbolTableBasedImage()69 SymbolTableBasedImage::SymbolTableBasedImage()
70 :
71 fLoadDelta(0),
72 fSymbolTable(NULL),
73 fStringTable(NULL),
74 fSymbolCount(0),
75 fStringTableSize(0)
76 {
77 }
78
79
~SymbolTableBasedImage()80 SymbolTableBasedImage::~SymbolTableBasedImage()
81 {
82 }
83
84
85 const elf_sym*
LookupSymbol(addr_t address,addr_t * _baseAddress,const char ** _symbolName,size_t * _symbolNameLen,bool * _exactMatch) const86 SymbolTableBasedImage::LookupSymbol(addr_t address, addr_t* _baseAddress,
87 const char** _symbolName, size_t *_symbolNameLen, bool *_exactMatch) const
88 {
89 const elf_sym* symbolFound = NULL;
90 const char* symbolName = NULL;
91 bool exactMatch = false;
92 addr_t deltaFound = ~(addr_t)0;
93
94 for (int32 i = 0; i < fSymbolCount; i++) {
95 const elf_sym* symbol = &fSymbolTable[i];
96
97 if (symbol->st_value == 0
98 || symbol->st_size >= (size_t)fInfo.text_size + fInfo.data_size) {
99 continue;
100 }
101
102 addr_t symbolAddress = symbol->st_value + fLoadDelta;
103 if (symbolAddress > address)
104 continue;
105
106 addr_t symbolDelta = address - symbolAddress;
107 if (symbolDelta >= 0 && symbolDelta < symbol->st_size)
108 exactMatch = true;
109
110 if (exactMatch || symbolDelta < deltaFound) {
111 deltaFound = symbolDelta;
112 symbolFound = symbol;
113 symbolName = fStringTable + symbol->st_name;
114
115 if (exactMatch)
116 break;
117 }
118 }
119
120 if (symbolFound != NULL) {
121 if (_baseAddress != NULL)
122 *_baseAddress = symbolFound->st_value + fLoadDelta;
123 if (_symbolName != NULL)
124 *_symbolName = symbolName;
125 if (_exactMatch != NULL)
126 *_exactMatch = exactMatch;
127 if (_symbolNameLen != NULL)
128 *_symbolNameLen = _SymbolNameLen(symbolName);
129 }
130
131 return symbolFound;
132 }
133
134
135 status_t
NextSymbol(int32 & iterator,const char ** _symbolName,size_t * _symbolNameLen,addr_t * _symbolAddress,size_t * _symbolSize,int32 * _symbolType) const136 SymbolTableBasedImage::NextSymbol(int32& iterator, const char** _symbolName,
137 size_t* _symbolNameLen, addr_t* _symbolAddress, size_t* _symbolSize,
138 int32* _symbolType) const
139 {
140 while (true) {
141 if (++iterator >= fSymbolCount)
142 return B_ENTRY_NOT_FOUND;
143
144 const elf_sym* symbol = &fSymbolTable[iterator];
145
146 if ((symbol->Type() != STT_FUNC && symbol->Type() != STT_OBJECT)
147 || symbol->st_value == 0) {
148 continue;
149 }
150
151 *_symbolName = fStringTable + symbol->st_name;
152 *_symbolNameLen = _SymbolNameLen(*_symbolName);
153 *_symbolAddress = symbol->st_value + fLoadDelta;
154 *_symbolSize = symbol->st_size;
155 *_symbolType = symbol->Type() == STT_FUNC ? B_SYMBOL_TYPE_TEXT
156 : B_SYMBOL_TYPE_DATA;
157
158 return B_OK;
159 }
160 }
161
162
163 size_t
_SymbolNameLen(const char * symbolName) const164 SymbolTableBasedImage::_SymbolNameLen(const char* symbolName) const
165 {
166 if (symbolName == NULL || (addr_t)symbolName < (addr_t)fStringTable
167 || (addr_t)symbolName >= (addr_t)fStringTable + fStringTableSize) {
168 return 0;
169 }
170
171 return strnlen(symbolName,
172 (addr_t)fStringTable + fStringTableSize - (addr_t)symbolName);
173 }
174
175
176 // #pragma mark - ImageFile
177
178
ImageFile()179 ImageFile::ImageFile()
180 :
181 fFD(-1),
182 fFileSize(0),
183 fMappedFile((uint8*)MAP_FAILED)
184 {
185 }
186
187
~ImageFile()188 ImageFile::~ImageFile()
189 {
190 if (fMappedFile != MAP_FAILED)
191 munmap(fMappedFile, fFileSize);
192
193 if (fFD >= 0)
194 close(fFD);
195 }
196
197
198 status_t
Init(const image_info & info)199 ImageFile::Init(const image_info& info)
200 {
201 // just copy the image info
202 fInfo = info;
203
204 // load the file
205 addr_t textAddress;
206 size_t textSize;
207 addr_t dataAddress;
208 size_t dataSize;
209 status_t error = _LoadFile(info.name, &textAddress, &textSize, &dataAddress,
210 &dataSize);
211 if (error != B_OK)
212 return error;
213
214 // compute the load delta
215 fLoadDelta = (addr_t)fInfo.text - textAddress;
216
217 return B_OK;
218 }
219
220
221 status_t
Init(const char * path)222 ImageFile::Init(const char* path)
223 {
224 // load the file
225 addr_t textAddress;
226 size_t textSize;
227 addr_t dataAddress;
228 size_t dataSize;
229 status_t error = _LoadFile(path, &textAddress, &textSize, &dataAddress,
230 &dataSize);
231 if (error != B_OK)
232 return error;
233
234 // init the image info
235 fInfo.id = -1;
236 fInfo.type = B_LIBRARY_IMAGE;
237 fInfo.sequence = 0;
238 fInfo.init_order = 0;
239 fInfo.init_routine = 0;
240 fInfo.term_routine = 0;
241 fInfo.device = -1;
242 fInfo.node = -1;
243 strlcpy(fInfo.name, path, sizeof(fInfo.name));
244 fInfo.text = (void*)textAddress;
245 fInfo.data = (void*)dataAddress;
246 fInfo.text_size = textSize;
247 fInfo.data_size = dataSize;
248
249 // the image isn't loaded, so no delta
250 fLoadDelta = 0;
251
252 return B_OK;
253 }
254
255
256 status_t
_LoadFile(const char * path,addr_t * _textAddress,size_t * _textSize,addr_t * _dataAddress,size_t * _dataSize)257 ImageFile::_LoadFile(const char* path, addr_t* _textAddress, size_t* _textSize,
258 addr_t* _dataAddress, size_t* _dataSize)
259 {
260 // open and stat() the file
261 fFD = open(path, O_RDONLY);
262 if (fFD < 0)
263 return errno;
264
265 struct stat st;
266 if (fstat(fFD, &st) < 0)
267 return errno;
268
269 fFileSize = st.st_size;
270 if (fFileSize < (off_t)sizeof(elf_ehdr))
271 return B_NOT_AN_EXECUTABLE;
272
273 // map it
274 fMappedFile = (uint8*)mmap(NULL, fFileSize, PROT_READ, MAP_PRIVATE, fFD, 0);
275 if (fMappedFile == MAP_FAILED)
276 return errno;
277
278 // examine the elf header
279 elf_ehdr* elfHeader = (elf_ehdr*)fMappedFile;
280 if (memcmp(elfHeader->e_ident, ELFMAG, 4) != 0)
281 return B_NOT_AN_EXECUTABLE;
282
283 if (elfHeader->e_ident[4] != ELF_CLASS)
284 return B_NOT_AN_EXECUTABLE;
285
286 // verify the location of the program headers
287 int32 programHeaderCount = elfHeader->e_phnum;
288 if (elfHeader->e_phoff < sizeof(elf_ehdr)
289 || elfHeader->e_phentsize < sizeof(elf_phdr)
290 || (off_t)(elfHeader->e_phoff + programHeaderCount
291 * elfHeader->e_phentsize)
292 > fFileSize) {
293 return B_NOT_AN_EXECUTABLE;
294 }
295
296 elf_phdr* programHeaders
297 = (elf_phdr*)(fMappedFile + elfHeader->e_phoff);
298
299 // verify the location of the section headers
300 int32 sectionCount = elfHeader->e_shnum;
301 if (elfHeader->e_shoff < sizeof(elf_ehdr)
302 || elfHeader->e_shentsize < sizeof(elf_shdr)
303 || (off_t)(elfHeader->e_shoff + sectionCount * elfHeader->e_shentsize)
304 > fFileSize) {
305 return B_NOT_AN_EXECUTABLE;
306 }
307
308 // find the text and data segment -- we need load address and size
309 *_textAddress = 0;
310 *_textSize = 0;
311 *_dataAddress = 0;
312 *_dataSize = 0;
313 for (int32 i = 0; i < programHeaderCount; i++) {
314 elf_phdr* header = (elf_phdr*)
315 ((uint8*)programHeaders + i * elfHeader->e_phentsize);
316 if (header->p_type == PT_LOAD) {
317 if ((header->p_flags & PF_WRITE) == 0) {
318 *_textAddress = header->p_vaddr;
319 *_textSize = header->p_memsz;
320 } else {
321 *_dataAddress = header->p_vaddr;
322 *_dataSize = header->p_memsz;
323 break;
324 }
325 }
326 }
327
328 status_t error = _FindTableInSection(elfHeader, SHT_SYMTAB);
329 if (error != B_OK)
330 error = _FindTableInSection(elfHeader, SHT_DYNSYM);
331
332 return error;
333 }
334
335
336 status_t
_FindTableInSection(elf_ehdr * elfHeader,uint16 sectionType)337 ImageFile::_FindTableInSection(elf_ehdr* elfHeader, uint16 sectionType)
338 {
339 elf_shdr* sectionHeaders
340 = (elf_shdr*)(fMappedFile + elfHeader->e_shoff);
341
342 // find the symbol table
343 for (int32 i = 0; i < elfHeader->e_shnum; i++) {
344 elf_shdr* sectionHeader = (elf_shdr*)
345 ((uint8*)sectionHeaders + i * elfHeader->e_shentsize);
346
347 if (sectionHeader->sh_type == sectionType) {
348 elf_shdr& stringHeader = *(elf_shdr*)
349 ((uint8*)sectionHeaders
350 + sectionHeader->sh_link * elfHeader->e_shentsize);
351
352 if (stringHeader.sh_type != SHT_STRTAB)
353 return B_BAD_DATA;
354
355 if ((off_t)(sectionHeader->sh_offset + sectionHeader->sh_size)
356 > fFileSize
357 || (off_t)(stringHeader.sh_offset + stringHeader.sh_size)
358 > fFileSize) {
359 return B_BAD_DATA;
360 }
361
362 fSymbolTable = (elf_sym*)(fMappedFile + sectionHeader->sh_offset);
363 fStringTable = (char*)(fMappedFile + stringHeader.sh_offset);
364 fSymbolCount = sectionHeader->sh_size / sizeof(elf_sym);
365 fStringTableSize = stringHeader.sh_size;
366
367 return B_OK;
368 }
369 }
370
371 return B_BAD_DATA;
372 }
373
374
375 // #pragma mark - KernelImage
376
377
KernelImage()378 KernelImage::KernelImage()
379 {
380 }
381
382
~KernelImage()383 KernelImage::~KernelImage()
384 {
385 delete[] fSymbolTable;
386 delete[] fStringTable;
387 }
388
389
390 status_t
Init(const image_info & info)391 KernelImage::Init(const image_info& info)
392 {
393 fInfo = info;
394
395 // get the table sizes
396 fSymbolCount = 0;
397 fStringTableSize = 0;
398 status_t error = _kern_read_kernel_image_symbols(fInfo.id,
399 NULL, &fSymbolCount, NULL, &fStringTableSize, NULL);
400 if (error != B_OK)
401 return error;
402
403 // allocate the tables
404 fSymbolTable = new(std::nothrow) elf_sym[fSymbolCount];
405 fStringTable = new(std::nothrow) char[fStringTableSize];
406 if (fSymbolTable == NULL || fStringTable == NULL)
407 return B_NO_MEMORY;
408
409 // get the info
410 return _kern_read_kernel_image_symbols(fInfo.id,
411 fSymbolTable, &fSymbolCount, fStringTable, &fStringTableSize,
412 &fLoadDelta);
413 }
414
415
CommPageImage()416 CommPageImage::CommPageImage()
417 {
418 }
419
420
~CommPageImage()421 CommPageImage::~CommPageImage()
422 {
423 delete[] fSymbolTable;
424 delete[] fStringTable;
425 }
426
427
428 status_t
Init(const image_info & info)429 CommPageImage::Init(const image_info& info)
430 {
431 // find kernel image for commpage
432 image_id commPageID = -1;
433 image_info commPageInfo;
434
435 int32 cookie = 0;
436 while (_kern_get_next_image_info(B_SYSTEM_TEAM, &cookie, &commPageInfo,
437 sizeof(image_info)) == B_OK) {
438 if (!strcmp("commpage", commPageInfo.name)) {
439 commPageID = commPageInfo.id;
440 break;
441 }
442 }
443 if (commPageID < 0)
444 return B_ENTRY_NOT_FOUND;
445
446 fInfo = commPageInfo;
447 fInfo.text = info.text;
448
449 // get the table sizes
450 fSymbolCount = 0;
451 fStringTableSize = 0;
452 status_t error = _kern_read_kernel_image_symbols(commPageID, NULL,
453 &fSymbolCount, NULL, &fStringTableSize, NULL);
454 if (error != B_OK)
455 return error;
456
457 // allocate the tables
458 fSymbolTable = new(std::nothrow) elf_sym[fSymbolCount];
459 fStringTable = new(std::nothrow) char[fStringTableSize];
460 if (fSymbolTable == NULL || fStringTable == NULL)
461 return B_NO_MEMORY;
462
463 // get the info
464 error = _kern_read_kernel_image_symbols(commPageID,
465 fSymbolTable, &fSymbolCount, fStringTable, &fStringTableSize, NULL);
466 if (error != B_OK) {
467 delete[] fSymbolTable;
468 delete[] fStringTable;
469 return error;
470 }
471
472 fLoadDelta = (addr_t)info.text;
473
474 return B_OK;
475 }
476