tcp: Fix 64 bit build with debugging features enabled.
[haiku.git] / src / kits / debug / Image.cpp
blob239820ffbaff27eb2ae4cba506b006c372b0e587
1 /*
2 * Copyright 2005-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
6 #include "Image.h"
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>
15 #include <new>
17 #include <runtime_loader.h>
18 #include <syscalls.h>
21 using namespace BPrivate::Debug;
24 // #pragma mark - Image
27 Image::Image()
32 Image::~Image()
37 status_t
38 Image::GetSymbol(const char* name, int32 symbolType, void** _symbolLocation,
39 size_t* _symbolSize, int32* _symbolType) const
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;
62 return B_ENTRY_NOT_FOUND;
66 // #pragma mark - SymbolTableBasedImage
69 SymbolTableBasedImage::SymbolTableBasedImage()
71 fLoadDelta(0),
72 fSymbolTable(NULL),
73 fStringTable(NULL),
74 fSymbolCount(0),
75 fStringTableSize(0)
80 SymbolTableBasedImage::~SymbolTableBasedImage()
85 const elf_sym*
86 SymbolTableBasedImage::LookupSymbol(addr_t address, addr_t* _baseAddress,
87 const char** _symbolName, size_t *_symbolNameLen, bool *_exactMatch) const
89 const elf_sym* symbolFound = NULL;
90 const char* symbolName = NULL;
91 bool exactMatch = false;
92 addr_t deltaFound = ~(addr_t)0;
94 for (int32 i = 0; i < fSymbolCount; i++) {
95 const elf_sym* symbol = &fSymbolTable[i];
97 if (symbol->st_value == 0
98 || symbol->st_size >= (size_t)fInfo.text_size + fInfo.data_size) {
99 continue;
102 addr_t symbolAddress = symbol->st_value + fLoadDelta;
103 if (symbolAddress > address)
104 continue;
106 addr_t symbolDelta = address - symbolAddress;
107 if (symbolDelta >= 0 && symbolDelta < symbol->st_size)
108 exactMatch = true;
110 if (exactMatch || symbolDelta < deltaFound) {
111 deltaFound = symbolDelta;
112 symbolFound = symbol;
113 symbolName = fStringTable + symbol->st_name;
115 if (exactMatch)
116 break;
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);
131 return symbolFound;
135 status_t
136 SymbolTableBasedImage::NextSymbol(int32& iterator, const char** _symbolName,
137 size_t* _symbolNameLen, addr_t* _symbolAddress, size_t* _symbolSize,
138 int32* _symbolType) const
140 while (true) {
141 if (++iterator >= fSymbolCount)
142 return B_ENTRY_NOT_FOUND;
144 const elf_sym* symbol = &fSymbolTable[iterator];
146 if ((symbol->Type() != STT_FUNC && symbol->Type() != STT_OBJECT)
147 || symbol->st_value == 0) {
148 continue;
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;
158 return B_OK;
163 size_t
164 SymbolTableBasedImage::_SymbolNameLen(const char* symbolName) const
166 if (symbolName == NULL || (addr_t)symbolName < (addr_t)fStringTable
167 || (addr_t)symbolName >= (addr_t)fStringTable + fStringTableSize) {
168 return 0;
171 return strnlen(symbolName,
172 (addr_t)fStringTable + fStringTableSize - (addr_t)symbolName);
176 // #pragma mark - ImageFile
179 ImageFile::ImageFile()
181 fFD(-1),
182 fFileSize(0),
183 fMappedFile((uint8*)MAP_FAILED)
188 ImageFile::~ImageFile()
190 if (fMappedFile != MAP_FAILED)
191 munmap(fMappedFile, fFileSize);
193 if (fFD >= 0)
194 close(fFD);
198 status_t
199 ImageFile::Init(const image_info& info)
201 // just copy the image info
202 fInfo = info;
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;
214 // compute the load delta
215 fLoadDelta = (addr_t)fInfo.text - textAddress;
217 return B_OK;
221 status_t
222 ImageFile::Init(const char* path)
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;
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;
249 // the image isn't loaded, so no delta
250 fLoadDelta = 0;
252 return B_OK;
256 status_t
257 ImageFile::_LoadFile(const char* path, addr_t* _textAddress, size_t* _textSize,
258 addr_t* _dataAddress, size_t* _dataSize)
260 // open and stat() the file
261 fFD = open(path, O_RDONLY);
262 if (fFD < 0)
263 return errno;
265 struct stat st;
266 if (fstat(fFD, &st) < 0)
267 return errno;
269 fFileSize = st.st_size;
270 if (fFileSize < (off_t)sizeof(elf_ehdr))
271 return B_NOT_AN_EXECUTABLE;
273 // map it
274 fMappedFile = (uint8*)mmap(NULL, fFileSize, PROT_READ, MAP_PRIVATE, fFD, 0);
275 if (fMappedFile == MAP_FAILED)
276 return errno;
278 // examine the elf header
279 elf_ehdr* elfHeader = (elf_ehdr*)fMappedFile;
280 if (memcmp(elfHeader->e_ident, ELF_MAGIC, 4) != 0)
281 return B_NOT_AN_EXECUTABLE;
283 if (elfHeader->e_ident[4] != ELF_CLASS)
284 return B_NOT_AN_EXECUTABLE;
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;
296 elf_phdr* programHeaders
297 = (elf_phdr*)(fMappedFile + elfHeader->e_phoff);
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;
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;
328 status_t error = _FindTableInSection(elfHeader, SHT_SYMTAB);
329 if (error != B_OK)
330 error = _FindTableInSection(elfHeader, SHT_DYNSYM);
332 return error;
336 status_t
337 ImageFile::_FindTableInSection(elf_ehdr* elfHeader, uint16 sectionType)
339 elf_shdr* sectionHeaders
340 = (elf_shdr*)(fMappedFile + elfHeader->e_shoff);
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);
347 if (sectionHeader->sh_type == sectionType) {
348 elf_shdr& stringHeader = *(elf_shdr*)
349 ((uint8*)sectionHeaders
350 + sectionHeader->sh_link * elfHeader->e_shentsize);
352 if (stringHeader.sh_type != SHT_STRTAB)
353 return B_BAD_DATA;
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;
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;
367 return B_OK;
371 return B_BAD_DATA;
375 // #pragma mark - KernelImage
378 KernelImage::KernelImage()
383 KernelImage::~KernelImage()
385 delete[] fSymbolTable;
386 delete[] fStringTable;
390 status_t
391 KernelImage::Init(const image_info& info)
393 fInfo = info;
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;
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;
409 // get the info
410 return _kern_read_kernel_image_symbols(fInfo.id,
411 fSymbolTable, &fSymbolCount, fStringTable, &fStringTableSize,
412 &fLoadDelta);
416 CommPageImage::CommPageImage()
421 CommPageImage::~CommPageImage()
423 delete[] fSymbolTable;
424 delete[] fStringTable;
428 status_t
429 CommPageImage::Init(const image_info& info)
431 // find kernel image for commpage
432 image_id commPageID = -1;
433 image_info commPageInfo;
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;
443 if (commPageID < 0)
444 return B_ENTRY_NOT_FOUND;
446 fInfo = commPageInfo;
447 fInfo.text = info.text;
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;
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;
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;
472 fLoadDelta = (addr_t)info.text;
474 return B_OK;