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
CoreFileTeamInfo()27 CoreFileTeamInfo::CoreFileTeamInfo()
28 :
29 fId(-1),
30 fUid(-1),
31 fGid(-1),
32 fArgs()
33 {
34 }
35
36
37 void
Init(int32 id,int32 uid,int32 gid,const BString & args)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
CoreFileAreaInfo(ElfSegment * segment,int32 id,uint64 baseAddress,uint64 size,uint64 ramSize,uint32 locking,uint32 protection,const BString & name)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
CoreFileImageInfo(int32 id,int32 type,uint64 initRoutine,uint64 termRoutine,uint64 textBase,uint64 textSize,int64 textDelta,uint64 dataBase,uint64 dataSize,int32 deviceId,int64 nodeId,uint64 symbolTable,uint64 symbolHash,uint64 stringTable,CoreFileAreaInfo * textArea,CoreFileAreaInfo * dataArea,const BString & name)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
~CoreFileImageInfo()96 CoreFileImageInfo::~CoreFileImageInfo()
97 {
98 SetSymbolsInfo(NULL);
99 }
100
101
102 void
SetSymbolsInfo(CoreFileSymbolsInfo * symbolsInfo)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
CoreFileSymbolsInfo()114 CoreFileSymbolsInfo::CoreFileSymbolsInfo()
115 :
116 fSymbolTable(NULL),
117 fStringTable(NULL),
118 fSymbolCount(0),
119 fSymbolTableEntrySize(0),
120 fStringTableSize(0)
121 {
122 }
123
124
~CoreFileSymbolsInfo()125 CoreFileSymbolsInfo::~CoreFileSymbolsInfo()
126 {
127 free(fSymbolTable);
128 free(fStringTable);
129 }
130
131
132 bool
Init(const void * symbolTable,uint32 symbolCount,uint32 symbolTableEntrySize,const char * stringTable,uint32 stringTableSize)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
CoreFileThreadInfo(int32 id,int32 state,int32 priority,uint64 stackBase,uint64 stackEnd,const BString & name)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
~CoreFileThreadInfo()172 CoreFileThreadInfo::~CoreFileThreadInfo()
173 {
174 free(fCpuState);
175 }
176
177
178 bool
SetCpuState(const void * state,size_t size)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
CoreFile()200 CoreFile::CoreFile()
201 :
202 fElfFile(),
203 fTeamInfo(),
204 fAreaInfos(32, true),
205 fImageInfos(32, true),
206 fThreadInfos(32, true)
207 {
208 }
209
210
~CoreFile()211 CoreFile::~CoreFile()
212 {
213 }
214
215
216 status_t
Init(const char * fileName)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*
ThreadInfoForId(int32 id) const230 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
CreateSymbolLookup(const CoreFileImageInfo * imageInfo,ElfSymbolLookup * & _lookup)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
_Init()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
_ReadNotes()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
_ReadNotes(ElfSegment * segment)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
_ReadNote(const char * name,uint32 type,const void * data,uint32 dataSize)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
_ReadTeamNote(const void * data,uint32 dataSize)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
_ReadAreasNote(const void * data,uint32 dataSize)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
_ReadImagesNote(const void * data,uint32 dataSize)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
_ReadSymbolsNote(const void * data,uint32 dataSize)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
_ReadThreadsNote(const void * data,uint32 dataSize)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*
_FindArea(uint64 address) const777 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*
_FindAreaSegment(uint64 address) const793 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*
_ImageInfoForId(int32 id) const807 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
_ReadValue(const void * & data,uint32 & dataSize)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
_ReadEntry(const void * & data,uint32 & dataSize,Entry & entry,size_t entrySize)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
_Advance(const void * & data,uint32 & dataSize,size_t by)841 CoreFile::_Advance(const void*& data, uint32& dataSize, size_t by)
842 {
843 data = (const uint8*)data + by;
844 dataSize -= by;
845 }
846