xref: /haiku/src/kits/debugger/elf/CoreFile.cpp (revision 13581b3d2a71545960b98fefebc5225b5bf29072)
1 /*
2  * Copyright 2016, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "CoreFile.h"
8 
9 #include <errno.h>
10 
11 #include <algorithm>
12 
13 #include <OS.h>
14 
15 #include <AutoDeleter.h>
16 
17 #include "ElfSymbolLookup.h"
18 #include "Tracing.h"
19 
20 
21 static const size_t kMaxNotesSize = 10 * 1024 * 1024;
22 
23 
24 // pragma mark - CoreFileTeamInfo
25 
26 
27 CoreFileTeamInfo::CoreFileTeamInfo()
28 	:
29 	fId(-1),
30 	fUid(-1),
31 	fGid(-1),
32 	fArgs()
33 {
34 }
35 
36 
37 void
38 CoreFileTeamInfo::Init(int32 id, int32 uid, int32 gid, const BString& args)
39 {
40 	fId = id;
41 	fUid = uid;
42 	fGid = gid;
43 	fArgs = args;
44 }
45 
46 
47 // pragma mark - CoreFileAreaInfo
48 
49 
50 CoreFileAreaInfo::CoreFileAreaInfo(ElfSegment* segment, int32 id,
51 	uint64 baseAddress, uint64 size, uint64 ramSize, uint32 locking,
52 	uint32 protection, const BString& name)
53 	:
54 	fSegment(segment),
55 	fBaseAddress(baseAddress),
56 	fSize(size),
57 	fRamSize(ramSize),
58 	fLocking(locking),
59 	fProtection(protection),
60 	fId(-1)
61 {
62 }
63 
64 
65 // pragma mark - CoreFileImageInfo
66 
67 
68 CoreFileImageInfo::CoreFileImageInfo(int32 id, int32 type, uint64 initRoutine,
69 	uint64 termRoutine, uint64 textBase, uint64 textSize, int64 textDelta,
70 	uint64 dataBase, uint64 dataSize, int32 deviceId, int64 nodeId,
71 	uint64 symbolTable, uint64 symbolHash, uint64 stringTable,
72 	CoreFileAreaInfo* textArea, CoreFileAreaInfo* dataArea, const BString& name)
73 	:
74 	fId(id),
75 	fType(type),
76 	fInitRoutine(initRoutine),
77 	fTermRoutine(termRoutine),
78 	fTextBase(textBase),
79 	fTextSize(textSize),
80 	fTextDelta(textDelta),
81 	fDataBase(dataBase),
82 	fDataSize(dataSize),
83 	fDeviceId(deviceId),
84 	fNodeId(nodeId),
85 	fSymbolTable(symbolTable),
86 	fSymbolHash(symbolHash),
87 	fStringTable(stringTable),
88 	fTextArea(textArea),
89 	fDataArea(dataArea),
90 	fName(name),
91 	fSymbolsInfo(NULL)
92 {
93 }
94 
95 
96 CoreFileImageInfo::~CoreFileImageInfo()
97 {
98 	SetSymbolsInfo(NULL);
99 }
100 
101 
102 void
103 CoreFileImageInfo::SetSymbolsInfo(CoreFileSymbolsInfo* symbolsInfo)
104 {
105 	if (fSymbolsInfo != NULL)
106 		delete fSymbolsInfo;
107 
108 	fSymbolsInfo = symbolsInfo;
109 }
110 
111 
112 // pragma mark - CoreFileSymbolsInfo
113 
114 CoreFileSymbolsInfo::CoreFileSymbolsInfo()
115 	:
116 	fSymbolTable(NULL),
117 	fStringTable(NULL),
118 	fSymbolCount(0),
119 	fSymbolTableEntrySize(0),
120 	fStringTableSize(0)
121 {
122 }
123 
124 
125 CoreFileSymbolsInfo::~CoreFileSymbolsInfo()
126 {
127 	free(fSymbolTable);
128 	free(fStringTable);
129 }
130 
131 
132 bool
133 CoreFileSymbolsInfo::Init(const void* symbolTable, uint32 symbolCount,
134 	uint32 symbolTableEntrySize, const char* stringTable,
135 	uint32 stringTableSize)
136 {
137 	fSymbolTable = malloc(symbolCount * symbolTableEntrySize);
138 	fStringTable = (char*)malloc(stringTableSize);
139 
140 	if (fSymbolTable == NULL || fStringTable == NULL)
141 		return false;
142 
143 	memcpy(fSymbolTable, symbolTable, symbolCount * symbolTableEntrySize);
144 	memcpy(fStringTable, stringTable, stringTableSize);
145 
146 	fSymbolCount = symbolCount;
147 	fSymbolTableEntrySize = symbolTableEntrySize;
148 	fStringTableSize = stringTableSize;
149 
150 	return true;
151 }
152 
153 
154 // pragma mark - CoreFileThreadInfo
155 
156 
157 CoreFileThreadInfo::CoreFileThreadInfo(int32 id, int32 state, int32 priority,
158 	uint64 stackBase, uint64 stackEnd, const BString& name)
159 	:
160 	fId(id),
161 	fState(state),
162 	fPriority(priority),
163 	fStackBase(stackBase),
164 	fStackEnd(stackEnd),
165 	fName(name),
166 	fCpuState(NULL),
167 	fCpuStateSize(0)
168 {
169 }
170 
171 
172 CoreFileThreadInfo::~CoreFileThreadInfo()
173 {
174 	free(fCpuState);
175 }
176 
177 
178 bool
179 CoreFileThreadInfo::SetCpuState(const void* state, size_t size)
180 {
181 	free(fCpuState);
182 	fCpuState = NULL;
183 	fCpuStateSize = 0;
184 
185 	if (state != NULL) {
186 		fCpuState = malloc(size);
187 		if (fCpuState == NULL)
188 			return false;
189 		memcpy(fCpuState, state, size);
190 		fCpuStateSize = size;
191 	}
192 
193 	return true;
194 }
195 
196 
197 // pragma mark - CoreFile
198 
199 
200 CoreFile::CoreFile()
201 	:
202 	fElfFile(),
203 	fTeamInfo(),
204 	fAreaInfos(32, true),
205 	fImageInfos(32, true),
206 	fThreadInfos(32, true)
207 {
208 }
209 
210 
211 CoreFile::~CoreFile()
212 {
213 }
214 
215 
216 status_t
217 CoreFile::Init(const char* fileName)
218 {
219 	status_t error = fElfFile.Init(fileName);
220 	if (error != B_OK)
221 		return error;
222 
223 	if (fElfFile.Is64Bit())
224 		return _Init<ElfClass64>();
225 	return _Init<ElfClass32>();
226 }
227 
228 
229 const CoreFileThreadInfo*
230 CoreFile::ThreadInfoForId(int32 id) const
231 {
232 	int32 count = fThreadInfos.CountItems();
233 	for (int32 i = 0; i < count; i++) {
234 		CoreFileThreadInfo* info = fThreadInfos.ItemAt(i);
235 		if (info->Id() == id)
236 			return info;
237 	}
238 
239 	return NULL;
240 }
241 
242 
243 status_t
244 CoreFile::CreateSymbolLookup(const CoreFileImageInfo* imageInfo,
245 	ElfSymbolLookup*& _lookup)
246 {
247 	// get the needed data
248 	uint64 textDelta = imageInfo->TextDelta();
249 	uint64 symbolTable = imageInfo->SymbolTable();
250 	uint64 symbolHash = imageInfo->SymbolHash();
251 	uint64 stringTable = imageInfo->StringTable();
252 	CoreFileAreaInfo* textArea = imageInfo->TextArea();
253 	ElfSegment* textSegment = textArea != NULL ? textArea->Segment() : NULL;
254 
255 	if (symbolTable == 0 || symbolHash == 0 || stringTable == 0
256 			|| textSegment == NULL) {
257 		return B_UNSUPPORTED;
258 	}
259 
260 	// create a data source for the text segment
261 	ElfSymbolLookupSource* source = fElfFile.CreateSymbolLookupSource(
262 		textSegment->FileOffset(), textSegment->FileSize(),
263 		textSegment->LoadAddress());
264 	if (source == NULL)
265 		return B_NO_MEMORY;
266 
267 	// get the symbol table entry size
268 	// TODO: This is not actually correct, since at least theoretically the
269 	// entry size may differ (cf. DT_SYMENT in the dynamic segment).
270 	size_t symbolTableEntrySize = fElfFile.Is64Bit()
271 		? sizeof(ElfClass64::Sym) : sizeof(ElfClass32::Sym);
272 
273 	// create the symbol lookup
274 	return ElfSymbolLookup::Create(source, symbolTable, symbolHash, stringTable,
275 		ElfSymbolLookup::kGetSymbolCountFromHash, symbolTableEntrySize,
276 		textDelta, fElfFile.Is64Bit(), fElfFile.IsByteOrderSwapped(), true,
277 		_lookup);
278 }
279 
280 
281 template<typename ElfClass>
282 status_t
283 CoreFile::_Init()
284 {
285 	status_t error = _ReadNotes<ElfClass>();
286 	if (error != B_OK)
287 		return error;
288 printf("CoreFile::_Init(): got %" B_PRId32 " areas, %" B_PRId32 " images, %"
289 B_PRId32 " threads\n", CountAreaInfos(), CountImageInfos(), CountThreadInfos());
290 	// TODO: Verify that we actually read something!
291 	return B_OK;
292 }
293 
294 
295 template<typename ElfClass>
296 status_t
297 CoreFile::_ReadNotes()
298 {
299 	int32 count = fElfFile.CountSegments();
300 	for (int32 i = 0; i < count; i++) {
301 		ElfSegment* segment = fElfFile.SegmentAt(i);
302 		if (segment->Type() == PT_NOTE) {
303 			status_t error = _ReadNotes<ElfClass>(segment);
304 			if (error != B_OK)
305 				return error;
306 		}
307 	}
308 
309 	return B_OK;
310 }
311 
312 
313 template<typename ElfClass>
314 status_t
315 CoreFile::_ReadNotes(ElfSegment* segment)
316 {
317 	// read the whole segment into memory
318 	if ((uint64)segment->FileSize() > kMaxNotesSize) {
319 		WARNING("Notes segment too large (%" B_PRIdOFF ")\n",
320 			segment->FileSize());
321 		return B_UNSUPPORTED;
322 	}
323 
324 	size_t notesSize = (size_t)segment->FileSize();
325 	uint8* notes = (uint8*)malloc(notesSize);
326 	if (notes == NULL)
327 		return B_NO_MEMORY;
328 	MemoryDeleter notesDeleter(notes);
329 
330 	ssize_t bytesRead = pread(fElfFile.FD(), notes, notesSize,
331 		(off_t)segment->FileOffset());
332 	if (bytesRead < 0) {
333 		WARNING("Failed to read notes segment: %s\n", strerror(errno));
334 		return errno;
335 	}
336 	if ((size_t)bytesRead != notesSize) {
337 		WARNING("Failed to read whole notes segment\n");
338 		return B_IO_ERROR;
339 	}
340 
341 	// iterate through notes
342 	typedef typename ElfClass::Nhdr Nhdr;
343 	while (notesSize > 0) {
344 		if (notesSize < sizeof(Nhdr)) {
345 			WARNING("Remaining bytes in notes segment too short for header\n");
346 			return B_BAD_DATA;
347 		}
348 
349 		const Nhdr* header = (const Nhdr*)notes;
350 		uint32 nameSize = Get(header->n_namesz);
351 		uint32 dataSize = Get(header->n_descsz);
352 		uint32 type = Get(header->n_type);
353 
354 		notes += sizeof(Nhdr);
355 		notesSize -= sizeof(Nhdr);
356 
357 		size_t alignedNameSize = (nameSize + 3) / 4 * 4;
358 		if (alignedNameSize > notesSize) {
359 			WARNING("Not enough bytes remaining in notes segment for note "
360 				"name (%zu / %zu)\n", notesSize, alignedNameSize);
361 			return B_BAD_DATA;
362 		}
363 
364 		const char* name = (const char*)notes;
365 		size_t nameLen = strnlen(name, nameSize);
366 		if (nameLen == nameSize) {
367 			WARNING("Unterminated note name\n");
368 			return B_BAD_DATA;
369 		}
370 
371 		notes += alignedNameSize;
372 		notesSize -= alignedNameSize;
373 
374 		size_t alignedDataSize = (dataSize + 3) / 4 * 4;
375 		if (alignedDataSize > notesSize) {
376 			WARNING("Not enough bytes remaining in notes segment for note "
377 				"data\n");
378 			return B_BAD_DATA;
379 		}
380 
381 		_ReadNote<ElfClass>(name, type, notes, dataSize);
382 
383 		notes += alignedDataSize;
384 		notesSize -= alignedDataSize;
385 	}
386 
387 	return B_OK;
388 }
389 
390 
391 template<typename ElfClass>
392 status_t
393 CoreFile::_ReadNote(const char* name, uint32 type, const void* data,
394 	uint32 dataSize)
395 {
396 	if (strcmp(name, ELF_NOTE_CORE) == 0) {
397 		switch (type) {
398 			case NT_FILE:
399 				// not needed
400 				return B_OK;
401 		}
402 	} else if (strcmp(name, ELF_NOTE_HAIKU) == 0) {
403 		switch (type) {
404 			case NT_TEAM:
405 				return _ReadTeamNote<ElfClass>(data, dataSize);
406 			case NT_AREAS:
407 				return _ReadAreasNote<ElfClass>(data, dataSize);
408 			case NT_IMAGES:
409 				return _ReadImagesNote<ElfClass>(data, dataSize);
410 			case NT_SYMBOLS:
411 				return _ReadSymbolsNote<ElfClass>(data, dataSize);
412 			case NT_THREADS:
413 				return _ReadThreadsNote<ElfClass>(data, dataSize);
414 			break;
415 		}
416 	}
417 
418 	WARNING("Unsupported note type %s/%#" B_PRIx32 "\n", name, type);
419 	return B_OK;
420 }
421 
422 
423 template<typename ElfClass>
424 status_t
425 CoreFile::_ReadTeamNote(const void* data, uint32 dataSize)
426 {
427 	typedef typename ElfClass::NoteTeam NoteTeam;
428 
429 	if (dataSize < sizeof(uint32)) {
430 		WARNING("Team note too short\n");
431 		return B_BAD_DATA;
432 	}
433 	uint32 entrySize = Get(*(const uint32*)data);
434 	data = (const uint32*)data + 1;
435 	dataSize -= sizeof(uint32);
436 
437 	if (entrySize == 0 || dataSize == 0 || dataSize - 1 < entrySize) {
438 		WARNING("Team note: too short or invalid entry size (%" B_PRIu32 ")\n",
439 			entrySize);
440 		return B_BAD_DATA;
441 	}
442 
443 	NoteTeam note = {};
444 	_ReadEntry(data, dataSize, note, entrySize);
445 
446 	// check, if args are null-terminated
447 	const char* args = (const char*)data;
448 	size_t argsSize = dataSize;
449 	if (args[argsSize - 1] != '\0') {
450 		WARNING("Team note args not terminated\n");
451 		return B_BAD_DATA;
452 	}
453 
454 	int32 id = Get(note.nt_id);
455 	int32 uid = Get(note.nt_uid);
456 	int32 gid = Get(note.nt_gid);
457 
458 	BString copiedArgs(args);
459 	if (args[0] != '\0' && copiedArgs.Length() == 0)
460 		return B_NO_MEMORY;
461 
462 	fTeamInfo.Init(id, uid, gid, copiedArgs);
463 	return B_OK;
464 }
465 
466 
467 template<typename ElfClass>
468 status_t
469 CoreFile::_ReadAreasNote(const void* data, uint32 dataSize)
470 {
471 	if (dataSize < 2 * sizeof(uint32)) {
472 		WARNING("Areas note too short\n");
473 		return B_BAD_DATA;
474 	}
475 	uint32 areaCount = _ReadValue<uint32>(data, dataSize);
476 	uint32 entrySize = _ReadValue<uint32>(data, dataSize);
477 
478 	typedef typename ElfClass::NoteAreaEntry Entry;
479 
480 	if (areaCount == 0)
481 		return B_OK;
482 
483 	// check entry size and area count
484 	if (entrySize == 0 || dataSize == 0 || areaCount > dataSize
485 			|| dataSize - 1 < entrySize || areaCount * entrySize >= dataSize) {
486 		WARNING("Areas note: too short or invalid entry size (%" B_PRIu32 ")\n",
487 			entrySize);
488 		return B_BAD_DATA;
489 	}
490 
491 	// check, if strings are null-terminated
492 	const char* strings = (const char*)data + areaCount * entrySize;
493 	size_t stringsSize = dataSize - areaCount * entrySize;
494 	if (stringsSize == 0 || strings[stringsSize - 1] != '\0') {
495 		WARNING("Areas note strings not terminated\n");
496 		return B_BAD_DATA;
497 	}
498 
499 	for (uint64 i = 0; i < areaCount; i++) {
500 		// get entry values
501 		Entry entry = {};
502 		_ReadEntry(data, dataSize, entry, entrySize);
503 
504 		int32 id = Get(entry.na_id);
505 		uint64 baseAddress = Get(entry.na_base);
506 		uint64 size = Get(entry.na_size);
507 		uint64 ramSize = Get(entry.na_ram_size);
508 		uint32 lock = Get(entry.na_lock);
509 		uint32 protection = Get(entry.na_protection);
510 
511 		// get name
512 		if (stringsSize == 0) {
513 			WARNING("Area %" B_PRIu64 " (ID %#" B_PRIx32 " @ %#" B_PRIx64
514 				") has no name\n", i, id, baseAddress);
515 			continue;
516 		}
517 		const char* name = strings;
518 		size_t nameSize = strlen(name) + 1;
519 		strings += nameSize;
520 		stringsSize -= nameSize;
521 
522 		BString copiedName(name);
523 		if (name[0] != '\0' && copiedName.Length() == 0)
524 			return B_NO_MEMORY;
525 
526 		// create and add area
527 		ElfSegment* segment = _FindAreaSegment(baseAddress);
528 		if (segment == NULL) {
529 			WARNING("No matching segment found for area %" B_PRIu64 " (ID %#"
530 				B_PRIx32 " @ %#" B_PRIx64 ", name: '%s')", i, id, baseAddress,
531 				name);
532 			continue;
533 		}
534 
535 		CoreFileAreaInfo* area = new(std::nothrow) CoreFileAreaInfo(segment, id,
536 			baseAddress, size, ramSize, lock, protection, copiedName);
537 		if (area == NULL || !fAreaInfos.AddItem(area)) {
538 			delete area;
539 			return B_NO_MEMORY;
540 		}
541 	}
542 
543 	return B_OK;
544 }
545 
546 
547 template<typename ElfClass>
548 status_t
549 CoreFile::_ReadImagesNote(const void* data, uint32 dataSize)
550 {
551 	if (dataSize < 2 * sizeof(uint32)) {
552 		WARNING("Images note too short\n");
553 		return B_BAD_DATA;
554 	}
555 	uint32 imageCount = _ReadValue<uint32>(data, dataSize);
556 	uint32 entrySize = _ReadValue<uint32>(data, dataSize);
557 
558 	typedef typename ElfClass::NoteImageEntry Entry;
559 
560 	if (imageCount == 0)
561 		return B_OK;
562 
563 	// check entry size and image count
564 	if (entrySize == 0 || dataSize == 0 || imageCount > dataSize
565 			|| dataSize - 1 < entrySize || imageCount * entrySize >= dataSize) {
566 		WARNING("Images note: too short or invalid entry size (%" B_PRIu32
567 			")\n", entrySize);
568 		return B_BAD_DATA;
569 	}
570 
571 	// check, if strings are null-terminated
572 	const char* strings = (const char*)data + imageCount * entrySize;
573 	size_t stringsSize = dataSize - imageCount * entrySize;
574 	if (stringsSize == 0 || strings[stringsSize - 1] != '\0') {
575 		WARNING("Images note strings not terminated\n");
576 		return B_BAD_DATA;
577 	}
578 
579 	for (uint64 i = 0; i < imageCount; i++) {
580 		// get entry values
581 		Entry entry = {};
582 		_ReadEntry(data, dataSize, entry, entrySize);
583 
584 		int32 id = Get(entry.ni_id);
585 		int32 type = Get(entry.ni_type);
586 		uint64 initRoutine = Get(entry.ni_init_routine);
587 		uint64 termRoutine = Get(entry.ni_term_routine);
588 		uint64 textBase = Get(entry.ni_text_base);
589 		uint64 textSize = Get(entry.ni_text_size);
590 		int64 textDelta = Get(entry.ni_text_delta);
591 		uint64 dataBase = Get(entry.ni_data_base);
592 		uint64 dataSize = Get(entry.ni_data_size);
593 		int32 deviceId = Get(entry.ni_device);
594 		int64 nodeId = Get(entry.ni_node);
595 		uint64 symbolTable = Get(entry.ni_symbol_table);
596 		uint64 symbolHash = Get(entry.ni_symbol_hash);
597 		uint64 stringTable = Get(entry.ni_string_table);
598 
599 		// get name
600 		if (stringsSize == 0) {
601 			WARNING("Image %" B_PRIu64 " (ID %#" B_PRIx32 ") has no name\n",
602 				i, id);
603 			continue;
604 		}
605 		const char* name = strings;
606 		size_t nameSize = strlen(name) + 1;
607 		strings += nameSize;
608 		stringsSize -= nameSize;
609 
610 		BString copiedName(name);
611 		if (name[0] != '\0' && copiedName.Length() == 0)
612 			return B_NO_MEMORY;
613 
614 		// create and add image
615 		CoreFileAreaInfo* textArea = _FindArea(textBase);
616 		CoreFileAreaInfo* dataArea = _FindArea(dataBase);
617 		CoreFileImageInfo* image = new(std::nothrow) CoreFileImageInfo(id, type,
618 			initRoutine, termRoutine, textBase, textSize, textDelta, dataBase,
619 			dataSize, deviceId, nodeId, symbolTable, symbolHash, stringTable,
620 			textArea, dataArea, copiedName);
621 		if (image == NULL || !fImageInfos.AddItem(image)) {
622 			delete image;
623 			return B_NO_MEMORY;
624 		}
625 	}
626 
627 	return B_OK;
628 }
629 
630 
631 template<typename ElfClass>
632 status_t
633 CoreFile::_ReadSymbolsNote(const void* data, uint32 dataSize)
634 {
635 	if (dataSize < 3 * sizeof(uint32)) {
636 		WARNING("Symbols note too short\n");
637 		return B_BAD_DATA;
638 	}
639 	int32 imageId = _ReadValue<int32>(data, dataSize);
640 	uint32 symbolCount = _ReadValue<uint32>(data, dataSize);
641 	uint32 entrySize = _ReadValue<uint32>(data, dataSize);
642 
643 	typedef typename ElfClass::Sym Sym;
644 
645 	if (symbolCount == 0)
646 		return B_OK;
647 
648 	// get the corresponding image
649 	CoreFileImageInfo* imageInfo = _ImageInfoForId(imageId);
650 	if (imageInfo == NULL) {
651 		WARNING("Symbols note: image (ID %" B_PRId32 ") not found\n",
652 			entrySize);
653 		return B_BAD_DATA;
654 	}
655 
656 	// check entry size and symbol count
657 	if (entrySize < sizeof(Sym) || symbolCount > dataSize
658 			|| dataSize - 1 < entrySize
659 			|| symbolCount * entrySize >= dataSize - 1) {
660 		WARNING("Symbols note: too short or invalid entry size (%" B_PRIu32
661 			")\n", entrySize);
662 		return B_BAD_DATA;
663 	}
664 
665 	uint32 symbolTableSize = symbolCount * entrySize;
666 	uint32 stringTableSize = dataSize - symbolTableSize;
667 
668 	// check, if the string table is null-terminated
669 	const char* stringTable = (const char*)data + symbolTableSize;
670 	if (stringTableSize == 0 || stringTable[stringTableSize - 1] != '\0') {
671 		WARNING("Symbols note string table not terminated\n");
672 		return B_BAD_DATA;
673 	}
674 
675 	CoreFileSymbolsInfo* symbolsInfo = new(std::nothrow) CoreFileSymbolsInfo;
676 	if (symbolsInfo == NULL
677 			|| !symbolsInfo->Init(data, symbolCount, entrySize, stringTable,
678 					stringTableSize)) {
679 		delete symbolsInfo;
680 		return B_NO_MEMORY;
681 	}
682 
683 	imageInfo->SetSymbolsInfo(symbolsInfo);
684 
685 	return B_OK;
686 }
687 
688 
689 template<typename ElfClass>
690 status_t
691 CoreFile::_ReadThreadsNote(const void* data, uint32 dataSize)
692 {
693 	if (dataSize < 3 * sizeof(uint32)) {
694 		WARNING("Threads note too short\n");
695 		return B_BAD_DATA;
696 	}
697 	uint32 threadCount = _ReadValue<uint32>(data, dataSize);
698 	uint32 entrySize = _ReadValue<uint32>(data, dataSize);
699 	uint32 cpuStateSize = _ReadValue<uint32>(data, dataSize);
700 
701 	if (cpuStateSize > 1024 * 1024) {
702 		WARNING("Threads note: unreasonable CPU state size: %" B_PRIu32 "\n",
703 			cpuStateSize);
704 		return B_BAD_DATA;
705 	}
706 
707 	typedef typename ElfClass::NoteThreadEntry Entry;
708 
709 	if (threadCount == 0)
710 		return B_OK;
711 
712 	size_t totalEntrySize = entrySize + cpuStateSize;
713 
714 	// check entry size and thread count
715 	if (entrySize == 0 || dataSize == 0 || threadCount > dataSize
716 			|| entrySize > dataSize || cpuStateSize > dataSize
717 			|| dataSize - 1 < totalEntrySize
718 			|| threadCount * totalEntrySize >= dataSize) {
719 		WARNING("Threads note: too short or invalid entry size (%" B_PRIu32
720 			")\n", entrySize);
721 		return B_BAD_DATA;
722 	}
723 
724 	// check, if strings are null-terminated
725 	const char* strings = (const char*)data + threadCount * totalEntrySize;
726 	size_t stringsSize = dataSize - threadCount * totalEntrySize;
727 	if (stringsSize == 0 || strings[stringsSize - 1] != '\0') {
728 		WARNING("Threads note strings not terminated\n");
729 		return B_BAD_DATA;
730 	}
731 
732 	for (uint64 i = 0; i < threadCount; i++) {
733 		// get entry values
734 		Entry entry = {};
735 		_ReadEntry(data, dataSize, entry, entrySize);
736 
737 		int32 id = Get(entry.nth_id);
738 		int32 state = Get(entry.nth_state);
739 		int32 priority = Get(entry.nth_priority);
740 		uint64 stackBase = Get(entry.nth_stack_base);
741 		uint64 stackEnd = Get(entry.nth_stack_end);
742 
743 		// get name
744 		if (stringsSize == 0) {
745 			WARNING("Thread %" B_PRIu64 " (ID %#" B_PRIx32 ") has no name\n",
746 				i, id);
747 			continue;
748 		}
749 		const char* name = strings;
750 		size_t nameSize = strlen(name) + 1;
751 		strings += nameSize;
752 		stringsSize -= nameSize;
753 
754 		BString copiedName(name);
755 		if (name[0] != '\0' && copiedName.Length() == 0)
756 			return B_NO_MEMORY;
757 
758 		// create and add thread
759 		CoreFileThreadInfo* thread = new(std::nothrow) CoreFileThreadInfo(id,
760 			state, priority, stackBase, stackEnd, copiedName);
761 		if (thread == NULL || !fThreadInfos.AddItem(thread)) {
762 			delete thread;
763 			return B_NO_MEMORY;
764 		}
765 
766 		// get CPU state
767 		if (!thread->SetCpuState(data, cpuStateSize))
768 			return B_NO_MEMORY;
769 		_Advance(data, dataSize, cpuStateSize);
770 	}
771 
772 	return B_OK;
773 }
774 
775 
776 CoreFileAreaInfo*
777 CoreFile::_FindArea(uint64 address) const
778 {
779 	int32 count = fAreaInfos.CountItems();
780 	for (int32 i = 0; i < count; i++) {
781 		CoreFileAreaInfo* area = fAreaInfos.ItemAt(i);
782 		if (address >= area->BaseAddress()
783 				&& address < area->EndAddress()) {
784 			return area;
785 		}
786 	}
787 
788 	return NULL;
789 }
790 
791 
792 ElfSegment*
793 CoreFile::_FindAreaSegment(uint64 address) const
794 {
795 	int32 count = fElfFile.CountSegments();
796 	for (int32 i = 0; i < count; i++) {
797 		ElfSegment* segment = fElfFile.SegmentAt(i);
798 		if (segment->Type() == PT_LOAD && segment->LoadAddress() == address)
799 			return segment;
800 	}
801 
802 	return NULL;
803 }
804 
805 
806 CoreFileImageInfo*
807 CoreFile::_ImageInfoForId(int32 id) const
808 {
809 	int32 count = fImageInfos.CountItems();
810 	for (int32 i = 0; i < count; i++) {
811 		CoreFileImageInfo* info = fImageInfos.ItemAt(i);
812 		if (info->Id() == id)
813 			return info;
814 	}
815 
816 	return NULL;
817 }
818 
819 
820 template<typename Type>
821 Type
822 CoreFile::_ReadValue(const void*& data, uint32& dataSize)
823 {
824 	Type value = Get(*(const Type*)data);
825 	_Advance(data, dataSize, sizeof(Type));
826 	return value;
827 }
828 
829 
830 template<typename Entry>
831 void
832 CoreFile::_ReadEntry(const void*& data, uint32& dataSize, Entry& entry,
833 	size_t entrySize)
834 {
835 	memcpy(&entry, data, std::min(sizeof(entry), entrySize));
836 	_Advance(data, dataSize, entrySize);
837 }
838 
839 
840 void
841 CoreFile::_Advance(const void*& data, uint32& dataSize, size_t by)
842 {
843 	data = (const uint8*)data + by;
844 	dataSize -= by;
845 }
846