xref: /haiku/src/kits/debug/Image.cpp (revision 820dca4df6c7bf955c46e8f6521b9408f50b2900)
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 
27 Image::Image()
28 {
29 }
30 
31 
32 Image::~Image()
33 {
34 }
35 
36 
37 status_t
38 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 
69 SymbolTableBasedImage::SymbolTableBasedImage()
70 	:
71 	fLoadDelta(0),
72 	fSymbolTable(NULL),
73 	fStringTable(NULL),
74 	fSymbolCount(0),
75 	fStringTableSize(0)
76 {
77 }
78 
79 
80 SymbolTableBasedImage::~SymbolTableBasedImage()
81 {
82 }
83 
84 
85 const elf_sym*
86 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
136 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
164 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 
179 ImageFile::ImageFile()
180 	:
181 	fFD(-1),
182 	fFileSize(0),
183 	fMappedFile((uint8*)MAP_FAILED)
184 {
185 }
186 
187 
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
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
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
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, ELF_MAGIC, 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 	elf_shdr* sectionHeaders
309 		= (elf_shdr*)(fMappedFile + elfHeader->e_shoff);
310 
311 	// find the text and data segment -- we need load address and size
312 	*_textAddress = 0;
313 	*_textSize = 0;
314 	*_dataAddress = 0;
315 	*_dataSize = 0;
316 	for (int32 i = 0; i < programHeaderCount; i++) {
317 		elf_phdr* header = (elf_phdr*)
318 			((uint8*)programHeaders + i * elfHeader->e_phentsize);
319 		if (header->p_type == PT_LOAD) {
320 			if ((header->p_flags & PF_WRITE) == 0) {
321 				*_textAddress = header->p_vaddr;
322 				*_textSize = header->p_memsz;
323 			} else {
324 				*_dataAddress = header->p_vaddr;
325 				*_dataSize = header->p_memsz;
326 				break;
327 			}
328 		}
329 	}
330 
331 	// find the symbol table
332 	for (int32 i = 0; i < elfHeader->e_shnum; i++) {
333 		elf_shdr* sectionHeader = (elf_shdr*)
334 			((uint8*)sectionHeaders + i * elfHeader->e_shentsize);
335 
336 		if (sectionHeader->sh_type == SHT_SYMTAB) {
337 			elf_shdr& stringHeader = *(elf_shdr*)
338 				((uint8*)sectionHeaders
339 					+ sectionHeader->sh_link * elfHeader->e_shentsize);
340 
341 			if (stringHeader.sh_type != SHT_STRTAB)
342 				return B_BAD_DATA;
343 
344 			if ((off_t)(sectionHeader->sh_offset + sectionHeader->sh_size)
345 					> fFileSize
346 				|| (off_t)(stringHeader.sh_offset + stringHeader.sh_size)
347 					> fFileSize) {
348 				return B_BAD_DATA;
349 			}
350 
351 			fSymbolTable = (elf_sym*)(fMappedFile + sectionHeader->sh_offset);
352 			fStringTable = (char*)(fMappedFile + stringHeader.sh_offset);
353 			fSymbolCount = sectionHeader->sh_size / sizeof(elf_sym);
354 			fStringTableSize = stringHeader.sh_size;
355 
356 			return B_OK;
357 		}
358 	}
359 
360 	return B_BAD_DATA;
361 }
362 
363 
364 // #pragma mark - KernelImage
365 
366 
367 KernelImage::KernelImage()
368 {
369 }
370 
371 
372 KernelImage::~KernelImage()
373 {
374 	delete[] fSymbolTable;
375 	delete[] fStringTable;
376 }
377 
378 
379 status_t
380 KernelImage::Init(const image_info& info)
381 {
382 	fInfo = info;
383 
384 	// get the table sizes
385 	fSymbolCount = 0;
386 	fStringTableSize = 0;
387 	status_t error = _kern_read_kernel_image_symbols(fInfo.id,
388 		NULL, &fSymbolCount, NULL, &fStringTableSize, NULL);
389 	if (error != B_OK)
390 		return error;
391 
392 	// allocate the tables
393 	fSymbolTable = new(std::nothrow) elf_sym[fSymbolCount];
394 	fStringTable = new(std::nothrow) char[fStringTableSize];
395 	if (fSymbolTable == NULL || fStringTable == NULL)
396 		return B_NO_MEMORY;
397 
398 	// get the info
399 	return _kern_read_kernel_image_symbols(fInfo.id,
400 		fSymbolTable, &fSymbolCount, fStringTable, &fStringTableSize,
401 		&fLoadDelta);
402 }
403