xref: /haiku/src/kits/debug/Image.cpp (revision 1b80286772b529a3d6de3bbeb0720c62e6a32fed)
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 // #pragma mark - SymbolTableBasedImage
38 
39 
40 SymbolTableBasedImage::SymbolTableBasedImage()
41 	:
42 	fLoadDelta(0),
43 	fSymbolTable(NULL),
44 	fStringTable(NULL),
45 	fSymbolCount(0),
46 	fStringTableSize(0)
47 {
48 }
49 
50 
51 SymbolTableBasedImage::~SymbolTableBasedImage()
52 {
53 }
54 
55 
56 const Elf32_Sym*
57 SymbolTableBasedImage::LookupSymbol(addr_t address, addr_t* _baseAddress,
58 	const char** _symbolName, size_t *_symbolNameLen, bool *_exactMatch) const
59 {
60 	const Elf32_Sym* symbolFound = NULL;
61 	const char* symbolName = NULL;
62 	bool exactMatch = false;
63 	addr_t deltaFound = ~(addr_t)0;
64 
65 	for (int32 i = 0; i < fSymbolCount; i++) {
66 		const Elf32_Sym* symbol = &fSymbolTable[i];
67 
68 		if (symbol->st_value == 0
69 			|| symbol->st_size >= (size_t)fInfo.text_size + fInfo.data_size) {
70 			continue;
71 		}
72 
73 		addr_t symbolAddress = symbol->st_value + fLoadDelta;
74 		if (symbolAddress > address)
75 			continue;
76 
77 		addr_t symbolDelta = address - symbolAddress;
78 		if (symbolDelta >= 0 && symbolDelta < symbol->st_size)
79 			exactMatch = true;
80 
81 		if (exactMatch || symbolDelta < deltaFound) {
82 			deltaFound = symbolDelta;
83 			symbolFound = symbol;
84 			symbolName = fStringTable + symbol->st_name;
85 
86 			if (exactMatch)
87 				break;
88 		}
89 	}
90 
91 	if (symbolFound != NULL) {
92 		if (_baseAddress != NULL)
93 			*_baseAddress = symbolFound->st_value + fLoadDelta;
94 		if (_symbolName != NULL)
95 			*_symbolName = symbolName;
96 		if (_exactMatch != NULL)
97 			*_exactMatch = exactMatch;
98 		if (_symbolNameLen != NULL)
99 			*_symbolNameLen = _SymbolNameLen(symbolName);
100 	}
101 
102 	return symbolFound;
103 }
104 
105 
106 status_t
107 SymbolTableBasedImage::NextSymbol(int32& iterator, const char** _symbolName,
108 	size_t* _symbolNameLen, addr_t* _symbolAddress, size_t* _symbolSize,
109 	int32* _symbolType) const
110 {
111 	while (true) {
112 		if (++iterator >= fSymbolCount)
113 			return B_ENTRY_NOT_FOUND;
114 
115 		const Elf32_Sym* symbol = &fSymbolTable[iterator];
116 
117 		if ((ELF32_ST_TYPE(symbol->st_info) != STT_FUNC
118 				&& ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT)
119 			|| symbol->st_value == 0) {
120 			continue;
121 		}
122 
123 		*_symbolName = fStringTable + symbol->st_name;
124 		*_symbolNameLen = _SymbolNameLen(*_symbolName);
125 		*_symbolAddress = symbol->st_value + fLoadDelta;
126 		*_symbolSize = symbol->st_size;
127 		*_symbolType = ELF32_ST_TYPE(symbol->st_info) == STT_FUNC
128 			? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA;
129 
130 		return B_OK;
131 	}
132 }
133 
134 
135 size_t
136 SymbolTableBasedImage::_SymbolNameLen(const char* symbolName) const
137 {
138 	if (symbolName == NULL || (addr_t)symbolName < (addr_t)fStringTable
139 		|| (addr_t)symbolName >= (addr_t)fStringTable + fStringTableSize) {
140 		return 0;
141 	}
142 
143 	return strnlen(symbolName,
144 		(addr_t)fStringTable + fStringTableSize - (addr_t)symbolName);
145 }
146 
147 
148 // #pragma mark - ImageFile
149 
150 
151 ImageFile::ImageFile()
152 	:
153 	fFD(-1),
154 	fFileSize(0),
155 	fMappedFile((uint8*)MAP_FAILED)
156 {
157 }
158 
159 
160 ImageFile::~ImageFile()
161 {
162 	if (fMappedFile != MAP_FAILED)
163 		munmap(fMappedFile, fFileSize);
164 
165 	if (fFD >= 0)
166 		close(fFD);
167 }
168 
169 
170 status_t
171 ImageFile::Init(const image_info& info)
172 {
173 	// just copy the image info
174 	fInfo = info;
175 
176 	// load the file
177 	addr_t textAddress;
178 	size_t textSize;
179 	addr_t dataAddress;
180 	size_t dataSize;
181 	status_t error = _LoadFile(info.name, &textAddress, &textSize, &dataAddress,
182 		&dataSize);
183 	if (error != B_OK)
184 		return error;
185 
186 	// compute the load delta
187 	fLoadDelta = (addr_t)fInfo.text - textAddress;
188 
189 	return B_OK;
190 }
191 
192 
193 status_t
194 ImageFile::Init(const char* path)
195 {
196 	// load the file
197 	addr_t textAddress;
198 	size_t textSize;
199 	addr_t dataAddress;
200 	size_t dataSize;
201 	status_t error = _LoadFile(path, &textAddress, &textSize, &dataAddress,
202 		&dataSize);
203 	if (error != B_OK)
204 		return error;
205 
206 	// init the image info
207 	fInfo.id = -1;
208 	fInfo.type = B_LIBRARY_IMAGE;
209 	fInfo.sequence = 0;
210 	fInfo.init_order = 0;
211 	fInfo.init_routine = 0;
212 	fInfo.term_routine = 0;
213 	fInfo.device = -1;
214 	fInfo.node = -1;
215 	strlcpy(fInfo.name, path, sizeof(fInfo.name));
216 	fInfo.text = (void*)textAddress;
217 	fInfo.data = (void*)dataAddress;
218 	fInfo.text_size = textSize;
219 	fInfo.data_size = dataSize;
220 
221 	// the image isn't loaded, so no delta
222 	fLoadDelta = 0;
223 
224 	return B_OK;
225 }
226 
227 
228 status_t
229 ImageFile::_LoadFile(const char* path, addr_t* _textAddress, size_t* _textSize,
230 	addr_t* _dataAddress, size_t* _dataSize)
231 {
232 	// open and stat() the file
233 	fFD = open(path, O_RDONLY);
234 	if (fFD < 0)
235 		return errno;
236 
237 	struct stat st;
238 	if (fstat(fFD, &st) < 0)
239 		return errno;
240 
241 	fFileSize = st.st_size;
242 	if (fFileSize < sizeof(Elf32_Ehdr))
243 		return B_NOT_AN_EXECUTABLE;
244 
245 	// map it
246 	fMappedFile = (uint8*)mmap(NULL, fFileSize, PROT_READ, MAP_PRIVATE, fFD, 0);
247 	if (fMappedFile == MAP_FAILED)
248 		return errno;
249 
250 	// examine the elf header
251 	Elf32_Ehdr* elfHeader = (Elf32_Ehdr*)fMappedFile;
252 	if (memcmp(elfHeader->e_ident, ELF_MAGIC, 4) != 0)
253 		return B_NOT_AN_EXECUTABLE;
254 
255 	if (elfHeader->e_ident[4] != ELFCLASS32)
256 		return B_NOT_AN_EXECUTABLE;
257 
258 	// verify the location of the program headers
259 	int32 programHeaderCount = elfHeader->e_phnum;
260 	if (elfHeader->e_phoff < sizeof(Elf32_Ehdr)
261 		|| elfHeader->e_phentsize < sizeof(Elf32_Phdr)
262 		|| elfHeader->e_phoff + programHeaderCount * elfHeader->e_phentsize
263 			> fFileSize) {
264 		return B_NOT_AN_EXECUTABLE;
265 	}
266 
267 	Elf32_Phdr* programHeaders
268 		= (Elf32_Phdr*)(fMappedFile + elfHeader->e_phoff);
269 
270 	// verify the location of the section headers
271 	int32 sectionCount = elfHeader->e_shnum;
272 	if (elfHeader->e_shoff < sizeof(Elf32_Ehdr)
273 		|| elfHeader->e_shentsize < sizeof(Elf32_Shdr)
274 		|| elfHeader->e_shoff + sectionCount * elfHeader->e_shentsize
275 			> fFileSize) {
276 		return B_NOT_AN_EXECUTABLE;
277 	}
278 
279 	Elf32_Shdr* sectionHeaders
280 		= (Elf32_Shdr*)(fMappedFile + elfHeader->e_shoff);
281 
282 	// find the text and data segment -- we need load address and size
283 	*_textAddress = 0;
284 	*_textSize = 0;
285 	*_dataAddress = 0;
286 	*_dataSize = 0;
287 	for (int32 i = 0; i < programHeaderCount; i++) {
288 		Elf32_Phdr* header = (Elf32_Phdr*)
289 			((uint8*)programHeaders + i * elfHeader->e_phentsize);
290 		if (header->p_type == PT_LOAD) {
291 			if ((header->p_flags & PF_WRITE) == 0) {
292 				*_textAddress = header->p_vaddr;
293 				*_textSize = header->p_memsz;
294 			} else {
295 				*_dataAddress = header->p_vaddr;
296 				*_dataSize = header->p_memsz;
297 				break;
298 			}
299 		}
300 	}
301 
302 	// find the symbol table
303 	for (int32 i = 0; i < elfHeader->e_shnum; i++) {
304 		Elf32_Shdr* sectionHeader = (Elf32_Shdr*)
305 			((uint8*)sectionHeaders + i * elfHeader->e_shentsize);
306 
307 		if (sectionHeader->sh_type == SHT_SYMTAB) {
308 			Elf32_Shdr& stringHeader = *(Elf32_Shdr*)
309 				((uint8*)sectionHeaders
310 					+ sectionHeader->sh_link * elfHeader->e_shentsize);
311 
312 			if (stringHeader.sh_type != SHT_STRTAB)
313 				return B_BAD_DATA;
314 
315 			if (sectionHeader->sh_offset + sectionHeader->sh_size > fFileSize
316 				|| stringHeader.sh_offset + stringHeader.sh_size > fFileSize) {
317 				return B_BAD_DATA;
318 			}
319 
320 			fSymbolTable = (Elf32_Sym*)(fMappedFile + sectionHeader->sh_offset);
321 			fStringTable = (char*)(fMappedFile + stringHeader.sh_offset);
322 			fSymbolCount = sectionHeader->sh_size / sizeof(Elf32_Sym);
323 			fStringTableSize = stringHeader.sh_size;
324 
325 			return B_OK;
326 		}
327 	}
328 
329 	return B_BAD_DATA;
330 }
331 
332 
333 // #pragma mark - KernelImage
334 
335 
336 KernelImage::KernelImage()
337 {
338 }
339 
340 
341 KernelImage::~KernelImage()
342 {
343 	delete[] fSymbolTable;
344 	delete[] fStringTable;
345 }
346 
347 
348 status_t
349 KernelImage::Init(const image_info& info)
350 {
351 	fInfo = info;
352 
353 	// get the table sizes
354 	fSymbolCount = 0;
355 	fStringTableSize = 0;
356 	status_t error = _kern_read_kernel_image_symbols(fInfo.id,
357 		NULL, &fSymbolCount, NULL, &fStringTableSize, NULL);
358 	if (error != B_OK)
359 		return error;
360 
361 	// allocate the tables
362 	fSymbolTable = new(std::nothrow) Elf32_Sym[fSymbolCount];
363 	fStringTable = new(std::nothrow) char[fStringTableSize];
364 	if (fSymbolTable == NULL || fStringTable == NULL)
365 		return B_NO_MEMORY;
366 
367 	// get the info
368 	return _kern_read_kernel_image_symbols(fInfo.id,
369 		fSymbolTable, &fSymbolCount, fStringTable, &fStringTableSize,
370 		&fLoadDelta);
371 }
372