xref: /haiku/src/kits/debug/Image.cpp (revision 3be9edf8da228afd9fec0390f408c964766122aa)
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 Elf32_Sym*
86 SymbolTableBasedImage::LookupSymbol(addr_t address, addr_t* _baseAddress,
87 	const char** _symbolName, size_t *_symbolNameLen, bool *_exactMatch) const
88 {
89 	const Elf32_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 Elf32_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 Elf32_Sym* symbol = &fSymbolTable[iterator];
145 
146 		if ((ELF32_ST_TYPE(symbol->st_info) != STT_FUNC
147 				&& ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT)
148 			|| symbol->st_value == 0) {
149 			continue;
150 		}
151 
152 		*_symbolName = fStringTable + symbol->st_name;
153 		*_symbolNameLen = _SymbolNameLen(*_symbolName);
154 		*_symbolAddress = symbol->st_value + fLoadDelta;
155 		*_symbolSize = symbol->st_size;
156 		*_symbolType = ELF32_ST_TYPE(symbol->st_info) == STT_FUNC
157 			? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA;
158 
159 		return B_OK;
160 	}
161 }
162 
163 
164 size_t
165 SymbolTableBasedImage::_SymbolNameLen(const char* symbolName) const
166 {
167 	if (symbolName == NULL || (addr_t)symbolName < (addr_t)fStringTable
168 		|| (addr_t)symbolName >= (addr_t)fStringTable + fStringTableSize) {
169 		return 0;
170 	}
171 
172 	return strnlen(symbolName,
173 		(addr_t)fStringTable + fStringTableSize - (addr_t)symbolName);
174 }
175 
176 
177 // #pragma mark - ImageFile
178 
179 
180 ImageFile::ImageFile()
181 	:
182 	fFD(-1),
183 	fFileSize(0),
184 	fMappedFile((uint8*)MAP_FAILED)
185 {
186 }
187 
188 
189 ImageFile::~ImageFile()
190 {
191 	if (fMappedFile != MAP_FAILED)
192 		munmap(fMappedFile, fFileSize);
193 
194 	if (fFD >= 0)
195 		close(fFD);
196 }
197 
198 
199 status_t
200 ImageFile::Init(const image_info& info)
201 {
202 	// just copy the image info
203 	fInfo = info;
204 
205 	// load the file
206 	addr_t textAddress;
207 	size_t textSize;
208 	addr_t dataAddress;
209 	size_t dataSize;
210 	status_t error = _LoadFile(info.name, &textAddress, &textSize, &dataAddress,
211 		&dataSize);
212 	if (error != B_OK)
213 		return error;
214 
215 	// compute the load delta
216 	fLoadDelta = (addr_t)fInfo.text - textAddress;
217 
218 	return B_OK;
219 }
220 
221 
222 status_t
223 ImageFile::Init(const char* path)
224 {
225 	// load the file
226 	addr_t textAddress;
227 	size_t textSize;
228 	addr_t dataAddress;
229 	size_t dataSize;
230 	status_t error = _LoadFile(path, &textAddress, &textSize, &dataAddress,
231 		&dataSize);
232 	if (error != B_OK)
233 		return error;
234 
235 	// init the image info
236 	fInfo.id = -1;
237 	fInfo.type = B_LIBRARY_IMAGE;
238 	fInfo.sequence = 0;
239 	fInfo.init_order = 0;
240 	fInfo.init_routine = 0;
241 	fInfo.term_routine = 0;
242 	fInfo.device = -1;
243 	fInfo.node = -1;
244 	strlcpy(fInfo.name, path, sizeof(fInfo.name));
245 	fInfo.text = (void*)textAddress;
246 	fInfo.data = (void*)dataAddress;
247 	fInfo.text_size = textSize;
248 	fInfo.data_size = dataSize;
249 
250 	// the image isn't loaded, so no delta
251 	fLoadDelta = 0;
252 
253 	return B_OK;
254 }
255 
256 
257 status_t
258 ImageFile::_LoadFile(const char* path, addr_t* _textAddress, size_t* _textSize,
259 	addr_t* _dataAddress, size_t* _dataSize)
260 {
261 	// open and stat() the file
262 	fFD = open(path, O_RDONLY);
263 	if (fFD < 0)
264 		return errno;
265 
266 	struct stat st;
267 	if (fstat(fFD, &st) < 0)
268 		return errno;
269 
270 	fFileSize = st.st_size;
271 	if (fFileSize < sizeof(Elf32_Ehdr))
272 		return B_NOT_AN_EXECUTABLE;
273 
274 	// map it
275 	fMappedFile = (uint8*)mmap(NULL, fFileSize, PROT_READ, MAP_PRIVATE, fFD, 0);
276 	if (fMappedFile == MAP_FAILED)
277 		return errno;
278 
279 	// examine the elf header
280 	Elf32_Ehdr* elfHeader = (Elf32_Ehdr*)fMappedFile;
281 	if (memcmp(elfHeader->e_ident, ELF_MAGIC, 4) != 0)
282 		return B_NOT_AN_EXECUTABLE;
283 
284 	if (elfHeader->e_ident[4] != ELFCLASS32)
285 		return B_NOT_AN_EXECUTABLE;
286 
287 	// verify the location of the program headers
288 	int32 programHeaderCount = elfHeader->e_phnum;
289 	if (elfHeader->e_phoff < sizeof(Elf32_Ehdr)
290 		|| elfHeader->e_phentsize < sizeof(Elf32_Phdr)
291 		|| elfHeader->e_phoff + programHeaderCount * elfHeader->e_phentsize
292 			> fFileSize) {
293 		return B_NOT_AN_EXECUTABLE;
294 	}
295 
296 	Elf32_Phdr* programHeaders
297 		= (Elf32_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(Elf32_Ehdr)
302 		|| elfHeader->e_shentsize < sizeof(Elf32_Shdr)
303 		|| elfHeader->e_shoff + sectionCount * elfHeader->e_shentsize
304 			> fFileSize) {
305 		return B_NOT_AN_EXECUTABLE;
306 	}
307 
308 	Elf32_Shdr* sectionHeaders
309 		= (Elf32_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 		Elf32_Phdr* header = (Elf32_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 		Elf32_Shdr* sectionHeader = (Elf32_Shdr*)
334 			((uint8*)sectionHeaders + i * elfHeader->e_shentsize);
335 
336 		if (sectionHeader->sh_type == SHT_SYMTAB) {
337 			Elf32_Shdr& stringHeader = *(Elf32_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 (sectionHeader->sh_offset + sectionHeader->sh_size > fFileSize
345 				|| stringHeader.sh_offset + stringHeader.sh_size > fFileSize) {
346 				return B_BAD_DATA;
347 			}
348 
349 			fSymbolTable = (Elf32_Sym*)(fMappedFile + sectionHeader->sh_offset);
350 			fStringTable = (char*)(fMappedFile + stringHeader.sh_offset);
351 			fSymbolCount = sectionHeader->sh_size / sizeof(Elf32_Sym);
352 			fStringTableSize = stringHeader.sh_size;
353 
354 			return B_OK;
355 		}
356 	}
357 
358 	return B_BAD_DATA;
359 }
360 
361 
362 // #pragma mark - KernelImage
363 
364 
365 KernelImage::KernelImage()
366 {
367 }
368 
369 
370 KernelImage::~KernelImage()
371 {
372 	delete[] fSymbolTable;
373 	delete[] fStringTable;
374 }
375 
376 
377 status_t
378 KernelImage::Init(const image_info& info)
379 {
380 	fInfo = info;
381 
382 	// get the table sizes
383 	fSymbolCount = 0;
384 	fStringTableSize = 0;
385 	status_t error = _kern_read_kernel_image_symbols(fInfo.id,
386 		NULL, &fSymbolCount, NULL, &fStringTableSize, NULL);
387 	if (error != B_OK)
388 		return error;
389 
390 	// allocate the tables
391 	fSymbolTable = new(std::nothrow) Elf32_Sym[fSymbolCount];
392 	fStringTable = new(std::nothrow) char[fStringTableSize];
393 	if (fSymbolTable == NULL || fStringTable == NULL)
394 		return B_NO_MEMORY;
395 
396 	// get the info
397 	return _kern_read_kernel_image_symbols(fInfo.id,
398 		fSymbolTable, &fSymbolCount, fStringTable, &fStringTableSize,
399 		&fLoadDelta);
400 }
401