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
21static const size_t kMaxNotesSize = 10 * 1024 * 1024;
22
23
24// pragma mark - CoreFileTeamInfo
25
26
27CoreFileTeamInfo::CoreFileTeamInfo()
28	:
29	fId(-1),
30	fUid(-1),
31	fGid(-1),
32	fArgs()
33{
34}
35
36
37void
38CoreFileTeamInfo::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
50CoreFileAreaInfo::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
68CoreFileImageInfo::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
96CoreFileImageInfo::~CoreFileImageInfo()
97{
98	SetSymbolsInfo(NULL);
99}
100
101
102void
103CoreFileImageInfo::SetSymbolsInfo(CoreFileSymbolsInfo* symbolsInfo)
104{
105	if (fSymbolsInfo != NULL)
106		delete fSymbolsInfo;
107
108	fSymbolsInfo = symbolsInfo;
109}
110
111
112// pragma mark - CoreFileSymbolsInfo
113
114CoreFileSymbolsInfo::CoreFileSymbolsInfo()
115	:
116	fSymbolTable(NULL),
117	fStringTable(NULL),
118	fSymbolCount(0),
119	fSymbolTableEntrySize(0),
120	fStringTableSize(0)
121{
122}
123
124
125CoreFileSymbolsInfo::~CoreFileSymbolsInfo()
126{
127	free(fSymbolTable);
128	free(fStringTable);
129}
130
131
132bool
133CoreFileSymbolsInfo::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
157CoreFileThreadInfo::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
172CoreFileThreadInfo::~CoreFileThreadInfo()
173{
174	free(fCpuState);
175}
176
177
178bool
179CoreFileThreadInfo::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
200CoreFile::CoreFile()
201	:
202	fElfFile(),
203	fTeamInfo(),
204	fAreaInfos(32, true),
205	fImageInfos(32, true),
206	fThreadInfos(32, true)
207{
208}
209
210
211CoreFile::~CoreFile()
212{
213}
214
215
216status_t
217CoreFile::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
229const CoreFileThreadInfo*
230CoreFile::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
243status_t
244CoreFile::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
281template<typename ElfClass>
282status_t
283CoreFile::_Init()
284{
285	status_t error = _ReadNotes<ElfClass>();
286	if (error != B_OK)
287		return error;
288printf("CoreFile::_Init(): got %" B_PRId32 " areas, %" B_PRId32 " images, %"
289B_PRId32 " threads\n", CountAreaInfos(), CountImageInfos(), CountThreadInfos());
290	// TODO: Verify that we actually read something!
291	return B_OK;
292}
293
294
295template<typename ElfClass>
296status_t
297CoreFile::_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
313template<typename ElfClass>
314status_t
315CoreFile::_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
391template<typename ElfClass>
392status_t
393CoreFile::_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
423template<typename ElfClass>
424status_t
425CoreFile::_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
467template<typename ElfClass>
468status_t
469CoreFile::_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
547template<typename ElfClass>
548status_t
549CoreFile::_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
631template<typename ElfClass>
632status_t
633CoreFile::_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
689template<typename ElfClass>
690status_t
691CoreFile::_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
776CoreFileAreaInfo*
777CoreFile::_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
792ElfSegment*
793CoreFile::_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
806CoreFileImageInfo*
807CoreFile::_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
820template<typename Type>
821Type
822CoreFile::_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
830template<typename Entry>
831void
832CoreFile::_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
840void
841CoreFile::_Advance(const void*& data, uint32& dataSize, size_t by)
842{
843	data = (const uint8*)data + by;
844	dataSize -= by;
845}
846