xref: /haiku/src/kits/debugger/elf/CoreFile.cpp (revision e433b3cfc3f089f7681f6d4e81d43f950ca6a440)
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 		CoreFileAreaInfo* area = new(std::nothrow) CoreFileAreaInfo(segment, id,
529 			baseAddress, size, ramSize, lock, protection, copiedName);
530 		if (area == NULL || !fAreaInfos.AddItem(area)) {
531 			delete area;
532 			return B_NO_MEMORY;
533 		}
534 	}
535 
536 	return B_OK;
537 }
538 
539 
540 template<typename ElfClass>
541 status_t
542 CoreFile::_ReadImagesNote(const void* data, uint32 dataSize)
543 {
544 	if (dataSize < 2 * sizeof(uint32)) {
545 		WARNING("Images note too short\n");
546 		return B_BAD_DATA;
547 	}
548 	uint32 imageCount = _ReadValue<uint32>(data, dataSize);
549 	uint32 entrySize = _ReadValue<uint32>(data, dataSize);
550 
551 	typedef typename ElfClass::NoteImageEntry Entry;
552 
553 	if (imageCount == 0)
554 		return B_OK;
555 
556 	// check entry size and image count
557 	if (entrySize == 0 || dataSize == 0 || imageCount > dataSize
558 			|| dataSize - 1 < entrySize || imageCount * entrySize >= dataSize) {
559 		WARNING("Images note: too short or invalid entry size (%" B_PRIu32
560 			")\n", entrySize);
561 		return B_BAD_DATA;
562 	}
563 
564 	// check, if strings are null-terminated
565 	const char* strings = (const char*)data + imageCount * entrySize;
566 	size_t stringsSize = dataSize - imageCount * entrySize;
567 	if (stringsSize == 0 || strings[stringsSize - 1] != '\0') {
568 		WARNING("Images note strings not terminated\n");
569 		return B_BAD_DATA;
570 	}
571 
572 	for (uint64 i = 0; i < imageCount; i++) {
573 		// get entry values
574 		Entry entry = {};
575 		_ReadEntry(data, dataSize, entry, entrySize);
576 
577 		int32 id = Get(entry.ni_id);
578 		int32 type = Get(entry.ni_type);
579 		uint64 initRoutine = Get(entry.ni_init_routine);
580 		uint64 termRoutine = Get(entry.ni_term_routine);
581 		uint64 textBase = Get(entry.ni_text_base);
582 		uint64 textSize = Get(entry.ni_text_size);
583 		int64 textDelta = Get(entry.ni_text_delta);
584 		uint64 dataBase = Get(entry.ni_data_base);
585 		uint64 dataSize = Get(entry.ni_data_size);
586 		int32 deviceId = Get(entry.ni_device);
587 		int64 nodeId = Get(entry.ni_node);
588 		uint64 symbolTable = Get(entry.ni_symbol_table);
589 		uint64 symbolHash = Get(entry.ni_symbol_hash);
590 		uint64 stringTable = Get(entry.ni_string_table);
591 
592 		// get name
593 		if (stringsSize == 0) {
594 			WARNING("Image %" B_PRIu64 " (ID %#" B_PRIx32 ") has no name\n",
595 				i, id);
596 			continue;
597 		}
598 		const char* name = strings;
599 		size_t nameSize = strlen(name) + 1;
600 		strings += nameSize;
601 		stringsSize -= nameSize;
602 
603 		BString copiedName(name);
604 		if (name[0] != '\0' && copiedName.Length() == 0)
605 			return B_NO_MEMORY;
606 
607 		// create and add image
608 		CoreFileAreaInfo* textArea = _FindArea(textBase);
609 		CoreFileAreaInfo* dataArea = _FindArea(dataBase);
610 		CoreFileImageInfo* image = new(std::nothrow) CoreFileImageInfo(id, type,
611 			initRoutine, termRoutine, textBase, textSize, textDelta, dataBase,
612 			dataSize, deviceId, nodeId, symbolTable, symbolHash, stringTable,
613 			textArea, dataArea, copiedName);
614 		if (image == NULL || !fImageInfos.AddItem(image)) {
615 			delete image;
616 			return B_NO_MEMORY;
617 		}
618 	}
619 
620 	return B_OK;
621 }
622 
623 
624 template<typename ElfClass>
625 status_t
626 CoreFile::_ReadSymbolsNote(const void* data, uint32 dataSize)
627 {
628 	if (dataSize < 3 * sizeof(uint32)) {
629 		WARNING("Symbols note too short\n");
630 		return B_BAD_DATA;
631 	}
632 	int32 imageId = _ReadValue<int32>(data, dataSize);
633 	uint32 symbolCount = _ReadValue<uint32>(data, dataSize);
634 	uint32 entrySize = _ReadValue<uint32>(data, dataSize);
635 
636 	typedef typename ElfClass::Sym Sym;
637 
638 	if (symbolCount == 0)
639 		return B_OK;
640 
641 	// get the corresponding image
642 	CoreFileImageInfo* imageInfo = _ImageInfoForId(imageId);
643 	if (imageInfo == NULL) {
644 		WARNING("Symbols note: image (ID %" B_PRId32 ") not found\n",
645 			entrySize);
646 		return B_BAD_DATA;
647 	}
648 
649 	// check entry size and symbol count
650 	if (entrySize < sizeof(Sym) || symbolCount > dataSize
651 			|| dataSize - 1 < entrySize
652 			|| symbolCount * entrySize >= dataSize - 1) {
653 		WARNING("Symbols note: too short or invalid entry size (%" B_PRIu32
654 			")\n", entrySize);
655 		return B_BAD_DATA;
656 	}
657 
658 	uint32 symbolTableSize = symbolCount * entrySize;
659 	uint32 stringTableSize = dataSize - symbolTableSize;
660 
661 	// check, if the string table is null-terminated
662 	const char* stringTable = (const char*)data + symbolTableSize;
663 	if (stringTableSize == 0 || stringTable[stringTableSize - 1] != '\0') {
664 		WARNING("Symbols note string table not terminated\n");
665 		return B_BAD_DATA;
666 	}
667 
668 	CoreFileSymbolsInfo* symbolsInfo = new(std::nothrow) CoreFileSymbolsInfo;
669 	if (symbolsInfo == NULL
670 			|| !symbolsInfo->Init(data, symbolCount, entrySize, stringTable,
671 					stringTableSize)) {
672 		delete symbolsInfo;
673 		return B_NO_MEMORY;
674 	}
675 
676 	imageInfo->SetSymbolsInfo(symbolsInfo);
677 
678 	return B_OK;
679 }
680 
681 
682 template<typename ElfClass>
683 status_t
684 CoreFile::_ReadThreadsNote(const void* data, uint32 dataSize)
685 {
686 	if (dataSize < 3 * sizeof(uint32)) {
687 		WARNING("Threads note too short\n");
688 		return B_BAD_DATA;
689 	}
690 	uint32 threadCount = _ReadValue<uint32>(data, dataSize);
691 	uint32 entrySize = _ReadValue<uint32>(data, dataSize);
692 	uint32 cpuStateSize = _ReadValue<uint32>(data, dataSize);
693 
694 	if (cpuStateSize > 1024 * 1024) {
695 		WARNING("Threads note: unreasonable CPU state size: %" B_PRIu32 "\n",
696 			cpuStateSize);
697 		return B_BAD_DATA;
698 	}
699 
700 	typedef typename ElfClass::NoteThreadEntry Entry;
701 
702 	if (threadCount == 0)
703 		return B_OK;
704 
705 	size_t totalEntrySize = entrySize + cpuStateSize;
706 
707 	// check entry size and thread count
708 	if (entrySize == 0 || dataSize == 0 || threadCount > dataSize
709 			|| entrySize > dataSize || cpuStateSize > dataSize
710 			|| dataSize - 1 < totalEntrySize
711 			|| threadCount * totalEntrySize >= dataSize) {
712 		WARNING("Threads note: too short or invalid entry size (%" B_PRIu32
713 			")\n", entrySize);
714 		return B_BAD_DATA;
715 	}
716 
717 	// check, if strings are null-terminated
718 	const char* strings = (const char*)data + threadCount * totalEntrySize;
719 	size_t stringsSize = dataSize - threadCount * totalEntrySize;
720 	if (stringsSize == 0 || strings[stringsSize - 1] != '\0') {
721 		WARNING("Threads note strings not terminated\n");
722 		return B_BAD_DATA;
723 	}
724 
725 	for (uint64 i = 0; i < threadCount; i++) {
726 		// get entry values
727 		Entry entry = {};
728 		_ReadEntry(data, dataSize, entry, entrySize);
729 
730 		int32 id = Get(entry.nth_id);
731 		int32 state = Get(entry.nth_state);
732 		int32 priority = Get(entry.nth_priority);
733 		uint64 stackBase = Get(entry.nth_stack_base);
734 		uint64 stackEnd = Get(entry.nth_stack_end);
735 
736 		// get name
737 		if (stringsSize == 0) {
738 			WARNING("Thread %" B_PRIu64 " (ID %#" B_PRIx32 ") has no name\n",
739 				i, id);
740 			continue;
741 		}
742 		const char* name = strings;
743 		size_t nameSize = strlen(name) + 1;
744 		strings += nameSize;
745 		stringsSize -= nameSize;
746 
747 		BString copiedName(name);
748 		if (name[0] != '\0' && copiedName.Length() == 0)
749 			return B_NO_MEMORY;
750 
751 		// create and add thread
752 		CoreFileThreadInfo* thread = new(std::nothrow) CoreFileThreadInfo(id,
753 			state, priority, stackBase, stackEnd, copiedName);
754 		if (thread == NULL || !fThreadInfos.AddItem(thread)) {
755 			delete thread;
756 			return B_NO_MEMORY;
757 		}
758 
759 		// get CPU state
760 		if (!thread->SetCpuState(data, cpuStateSize))
761 			return B_NO_MEMORY;
762 		_Advance(data, dataSize, cpuStateSize);
763 	}
764 
765 	return B_OK;
766 }
767 
768 
769 CoreFileAreaInfo*
770 CoreFile::_FindArea(uint64 address) const
771 {
772 	int32 count = fAreaInfos.CountItems();
773 	for (int32 i = 0; i < count; i++) {
774 		CoreFileAreaInfo* area = fAreaInfos.ItemAt(i);
775 		if (address >= area->BaseAddress()
776 				&& address < area->EndAddress()) {
777 			return area;
778 		}
779 	}
780 
781 	return NULL;
782 }
783 
784 
785 ElfSegment*
786 CoreFile::_FindAreaSegment(uint64 address) const
787 {
788 	int32 count = fElfFile.CountSegments();
789 	for (int32 i = 0; i < count; i++) {
790 		ElfSegment* segment = fElfFile.SegmentAt(i);
791 		if (segment->Type() == PT_LOAD && segment->LoadAddress() == address)
792 			return segment;
793 	}
794 
795 	return NULL;
796 }
797 
798 
799 CoreFileImageInfo*
800 CoreFile::_ImageInfoForId(int32 id) const
801 {
802 	int32 count = fImageInfos.CountItems();
803 	for (int32 i = 0; i < count; i++) {
804 		CoreFileImageInfo* info = fImageInfos.ItemAt(i);
805 		if (info->Id() == id)
806 			return info;
807 	}
808 
809 	return NULL;
810 }
811 
812 
813 template<typename Type>
814 Type
815 CoreFile::_ReadValue(const void*& data, uint32& dataSize)
816 {
817 	Type value = Get(*(const Type*)data);
818 	_Advance(data, dataSize, sizeof(Type));
819 	return value;
820 }
821 
822 
823 template<typename Entry>
824 void
825 CoreFile::_ReadEntry(const void*& data, uint32& dataSize, Entry& entry,
826 	size_t entrySize)
827 {
828 	memcpy(&entry, data, std::min(sizeof(entry), entrySize));
829 	_Advance(data, dataSize, entrySize);
830 }
831 
832 
833 void
834 CoreFile::_Advance(const void*& data, uint32& dataSize, size_t by)
835 {
836 	data = (const uint8*)data + by;
837 	dataSize -= by;
838 }
839