2 * Copyright 2016, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
15 #include <AutoDeleter.h>
17 #include "ElfSymbolLookup.h"
21 static const size_t kMaxNotesSize
= 10 * 1024 * 1024;
24 // pragma mark - CoreFileTeamInfo
27 CoreFileTeamInfo::CoreFileTeamInfo()
38 CoreFileTeamInfo::Init(int32 id
, int32 uid
, int32 gid
, const BString
& args
)
47 // pragma mark - CoreFileAreaInfo
50 CoreFileAreaInfo::CoreFileAreaInfo(ElfSegment
* segment
, int32 id
,
51 uint64 baseAddress
, uint64 size
, uint64 ramSize
, uint32 locking
,
52 uint32 protection
, const BString
& name
)
55 fBaseAddress(baseAddress
),
59 fProtection(protection
),
65 // pragma mark - CoreFileImageInfo
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
)
76 fInitRoutine(initRoutine
),
77 fTermRoutine(termRoutine
),
80 fTextDelta(textDelta
),
85 fSymbolTable(symbolTable
),
86 fSymbolHash(symbolHash
),
87 fStringTable(stringTable
),
96 CoreFileImageInfo::~CoreFileImageInfo()
103 CoreFileImageInfo::SetSymbolsInfo(CoreFileSymbolsInfo
* symbolsInfo
)
105 if (fSymbolsInfo
!= NULL
)
108 fSymbolsInfo
= symbolsInfo
;
112 // pragma mark - CoreFileSymbolsInfo
114 CoreFileSymbolsInfo::CoreFileSymbolsInfo()
119 fSymbolTableEntrySize(0),
125 CoreFileSymbolsInfo::~CoreFileSymbolsInfo()
133 CoreFileSymbolsInfo::Init(const void* symbolTable
, uint32 symbolCount
,
134 uint32 symbolTableEntrySize
, const char* stringTable
,
135 uint32 stringTableSize
)
137 fSymbolTable
= malloc(symbolCount
* symbolTableEntrySize
);
138 fStringTable
= (char*)malloc(stringTableSize
);
140 if (fSymbolTable
== NULL
|| fStringTable
== NULL
)
143 memcpy(fSymbolTable
, symbolTable
, symbolCount
* symbolTableEntrySize
);
144 memcpy(fStringTable
, stringTable
, stringTableSize
);
146 fSymbolCount
= symbolCount
;
147 fSymbolTableEntrySize
= symbolTableEntrySize
;
148 fStringTableSize
= stringTableSize
;
154 // pragma mark - CoreFileThreadInfo
157 CoreFileThreadInfo::CoreFileThreadInfo(int32 id
, int32 state
, int32 priority
,
158 uint64 stackBase
, uint64 stackEnd
, const BString
& name
)
163 fStackBase(stackBase
),
172 CoreFileThreadInfo::~CoreFileThreadInfo()
179 CoreFileThreadInfo::SetCpuState(const void* state
, size_t size
)
186 fCpuState
= malloc(size
);
187 if (fCpuState
== NULL
)
189 memcpy(fCpuState
, state
, size
);
190 fCpuStateSize
= size
;
197 // pragma mark - CoreFile
204 fAreaInfos(32, true),
205 fImageInfos(32, true),
206 fThreadInfos(32, true)
211 CoreFile::~CoreFile()
217 CoreFile::Init(const char* fileName
)
219 status_t error
= fElfFile
.Init(fileName
);
223 if (fElfFile
.Is64Bit())
224 return _Init
<ElfClass64
>();
225 return _Init
<ElfClass32
>();
229 const CoreFileThreadInfo
*
230 CoreFile::ThreadInfoForId(int32 id
) const
232 int32 count
= fThreadInfos
.CountItems();
233 for (int32 i
= 0; i
< count
; i
++) {
234 CoreFileThreadInfo
* info
= fThreadInfos
.ItemAt(i
);
235 if (info
->Id() == id
)
244 CoreFile::CreateSymbolLookup(const CoreFileImageInfo
* imageInfo
,
245 ElfSymbolLookup
*& _lookup
)
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
;
255 if (symbolTable
== 0 || symbolHash
== 0 || stringTable
== 0
256 || textSegment
== NULL
) {
257 return B_UNSUPPORTED
;
260 // create a data source for the text segment
261 ElfSymbolLookupSource
* source
= fElfFile
.CreateSymbolLookupSource(
262 textSegment
->FileOffset(), textSegment
->FileSize(),
263 textSegment
->LoadAddress());
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
);
273 // create the symbol lookup
274 return ElfSymbolLookup::Create(source
, symbolTable
, symbolHash
, stringTable
,
275 ElfSymbolLookup::kGetSymbolCountFromHash
, symbolTableEntrySize
,
276 textDelta
, fElfFile
.Is64Bit(), fElfFile
.IsByteOrderSwapped(), true,
281 template<typename ElfClass
>
285 status_t error
= _ReadNotes
<ElfClass
>();
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!
295 template<typename ElfClass
>
297 CoreFile::_ReadNotes()
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
);
313 template<typename ElfClass
>
315 CoreFile::_ReadNotes(ElfSegment
* segment
)
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
;
324 size_t notesSize
= (size_t)segment
->FileSize();
325 uint8
* notes
= (uint8
*)malloc(notesSize
);
328 MemoryDeleter
notesDeleter(notes
);
330 ssize_t bytesRead
= pread(fElfFile
.FD(), notes
, notesSize
,
331 (off_t
)segment
->FileOffset());
333 WARNING("Failed to read notes segment: %s\n", strerror(errno
));
336 if ((size_t)bytesRead
!= notesSize
) {
337 WARNING("Failed to read whole notes segment\n");
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");
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
);
354 notes
+= sizeof(Nhdr
);
355 notesSize
-= sizeof(Nhdr
);
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
);
364 const char* name
= (const char*)notes
;
365 size_t nameLen
= strnlen(name
, nameSize
);
366 if (nameLen
== nameSize
) {
367 WARNING("Unterminated note name\n");
371 notes
+= alignedNameSize
;
372 notesSize
-= alignedNameSize
;
374 size_t alignedDataSize
= (dataSize
+ 3) / 4 * 4;
375 if (alignedDataSize
> notesSize
) {
376 WARNING("Not enough bytes remaining in notes segment for note "
381 _ReadNote
<ElfClass
>(name
, type
, notes
, dataSize
);
383 notes
+= alignedDataSize
;
384 notesSize
-= alignedDataSize
;
391 template<typename ElfClass
>
393 CoreFile::_ReadNote(const char* name
, uint32 type
, const void* data
,
396 if (strcmp(name
, ELF_NOTE_CORE
) == 0) {
402 } else if (strcmp(name
, ELF_NOTE_HAIKU
) == 0) {
405 return _ReadTeamNote
<ElfClass
>(data
, dataSize
);
407 return _ReadAreasNote
<ElfClass
>(data
, dataSize
);
409 return _ReadImagesNote
<ElfClass
>(data
, dataSize
);
411 return _ReadSymbolsNote
<ElfClass
>(data
, dataSize
);
413 return _ReadThreadsNote
<ElfClass
>(data
, dataSize
);
418 WARNING("Unsupported note type %s/%#" B_PRIx32
"\n", name
, type
);
423 template<typename ElfClass
>
425 CoreFile::_ReadTeamNote(const void* data
, uint32 dataSize
)
427 typedef typename
ElfClass::NoteTeam NoteTeam
;
429 if (dataSize
< sizeof(uint32
)) {
430 WARNING("Team note too short\n");
433 uint32 entrySize
= Get(*(const uint32
*)data
);
434 data
= (const uint32
*)data
+ 1;
435 dataSize
-= sizeof(uint32
);
437 if (entrySize
== 0 || dataSize
== 0 || dataSize
- 1 < entrySize
) {
438 WARNING("Team note: too short or invalid entry size (%" B_PRIu32
")\n",
444 _ReadEntry(data
, dataSize
, note
, entrySize
);
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");
454 int32 id
= Get(note
.nt_id
);
455 int32 uid
= Get(note
.nt_uid
);
456 int32 gid
= Get(note
.nt_gid
);
458 BString
copiedArgs(args
);
459 if (args
[0] != '\0' && copiedArgs
.Length() == 0)
462 fTeamInfo
.Init(id
, uid
, gid
, copiedArgs
);
467 template<typename ElfClass
>
469 CoreFile::_ReadAreasNote(const void* data
, uint32 dataSize
)
471 if (dataSize
< 2 * sizeof(uint32
)) {
472 WARNING("Areas note too short\n");
475 uint32 areaCount
= _ReadValue
<uint32
>(data
, dataSize
);
476 uint32 entrySize
= _ReadValue
<uint32
>(data
, dataSize
);
478 typedef typename
ElfClass::NoteAreaEntry Entry
;
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",
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");
499 for (uint64 i
= 0; i
< areaCount
; i
++) {
502 _ReadEntry(data
, dataSize
, entry
, entrySize
);
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
);
512 if (stringsSize
== 0) {
513 WARNING("Area %" B_PRIu64
" (ID %#" B_PRIx32
" @ %#" B_PRIx64
514 ") has no name\n", i
, id
, baseAddress
);
517 const char* name
= strings
;
518 size_t nameSize
= strlen(name
) + 1;
520 stringsSize
-= nameSize
;
522 BString
copiedName(name
);
523 if (name
[0] != '\0' && copiedName
.Length() == 0)
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
)) {
540 template<typename ElfClass
>
542 CoreFile::_ReadImagesNote(const void* data
, uint32 dataSize
)
544 if (dataSize
< 2 * sizeof(uint32
)) {
545 WARNING("Images note too short\n");
548 uint32 imageCount
= _ReadValue
<uint32
>(data
, dataSize
);
549 uint32 entrySize
= _ReadValue
<uint32
>(data
, dataSize
);
551 typedef typename
ElfClass::NoteImageEntry Entry
;
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
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");
572 for (uint64 i
= 0; i
< imageCount
; i
++) {
575 _ReadEntry(data
, dataSize
, entry
, entrySize
);
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
);
593 if (stringsSize
== 0) {
594 WARNING("Image %" B_PRIu64
" (ID %#" B_PRIx32
") has no name\n",
598 const char* name
= strings
;
599 size_t nameSize
= strlen(name
) + 1;
601 stringsSize
-= nameSize
;
603 BString
copiedName(name
);
604 if (name
[0] != '\0' && copiedName
.Length() == 0)
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
)) {
624 template<typename ElfClass
>
626 CoreFile::_ReadSymbolsNote(const void* data
, uint32 dataSize
)
628 if (dataSize
< 3 * sizeof(uint32
)) {
629 WARNING("Symbols note too short\n");
632 int32 imageId
= _ReadValue
<int32
>(data
, dataSize
);
633 uint32 symbolCount
= _ReadValue
<uint32
>(data
, dataSize
);
634 uint32 entrySize
= _ReadValue
<uint32
>(data
, dataSize
);
636 typedef typename
ElfClass::Sym Sym
;
638 if (symbolCount
== 0)
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",
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
658 uint32 symbolTableSize
= symbolCount
* entrySize
;
659 uint32 stringTableSize
= dataSize
- symbolTableSize
;
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");
668 CoreFileSymbolsInfo
* symbolsInfo
= new(std::nothrow
) CoreFileSymbolsInfo
;
669 if (symbolsInfo
== NULL
670 || !symbolsInfo
->Init(data
, symbolCount
, entrySize
, stringTable
,
676 imageInfo
->SetSymbolsInfo(symbolsInfo
);
682 template<typename ElfClass
>
684 CoreFile::_ReadThreadsNote(const void* data
, uint32 dataSize
)
686 if (dataSize
< 3 * sizeof(uint32
)) {
687 WARNING("Threads note too short\n");
690 uint32 threadCount
= _ReadValue
<uint32
>(data
, dataSize
);
691 uint32 entrySize
= _ReadValue
<uint32
>(data
, dataSize
);
692 uint32 cpuStateSize
= _ReadValue
<uint32
>(data
, dataSize
);
694 if (cpuStateSize
> 1024 * 1024) {
695 WARNING("Threads note: unreasonable CPU state size: %" B_PRIu32
"\n",
700 typedef typename
ElfClass::NoteThreadEntry Entry
;
702 if (threadCount
== 0)
705 size_t totalEntrySize
= entrySize
+ cpuStateSize
;
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
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");
725 for (uint64 i
= 0; i
< threadCount
; i
++) {
728 _ReadEntry(data
, dataSize
, entry
, entrySize
);
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
);
737 if (stringsSize
== 0) {
738 WARNING("Thread %" B_PRIu64
" (ID %#" B_PRIx32
") has no name\n",
742 const char* name
= strings
;
743 size_t nameSize
= strlen(name
) + 1;
745 stringsSize
-= nameSize
;
747 BString
copiedName(name
);
748 if (name
[0] != '\0' && copiedName
.Length() == 0)
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
)) {
760 if (!thread
->SetCpuState(data
, cpuStateSize
))
762 _Advance(data
, dataSize
, cpuStateSize
);
770 CoreFile::_FindArea(uint64 address
) const
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()) {
786 CoreFile::_FindAreaSegment(uint64 address
) const
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
)
800 CoreFile::_ImageInfoForId(int32 id
) const
802 int32 count
= fImageInfos
.CountItems();
803 for (int32 i
= 0; i
< count
; i
++) {
804 CoreFileImageInfo
* info
= fImageInfos
.ItemAt(i
);
805 if (info
->Id() == id
)
813 template<typename Type
>
815 CoreFile::_ReadValue(const void*& data
, uint32
& dataSize
)
817 Type value
= Get(*(const Type
*)data
);
818 _Advance(data
, dataSize
, sizeof(Type
));
823 template<typename Entry
>
825 CoreFile::_ReadEntry(const void*& data
, uint32
& dataSize
, Entry
& entry
,
828 memcpy(&entry
, data
, std::min(sizeof(entry
), entrySize
));
829 _Advance(data
, dataSize
, entrySize
);
834 CoreFile::_Advance(const void*& data
, uint32
& dataSize
, size_t by
)
836 data
= (const uint8
*)data
+ by
;