btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / system / kernel / debug / core_dump.cpp
blob664d6cba9f91e107af947cf25251017408a1cb8a
1 /*
2 * Copyright 2016, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <core_dump.h>
9 #include <errno.h>
10 #include <string.h>
12 #include <algorithm>
13 #include <new>
15 #include <BeBuild.h>
16 #include <ByteOrder.h>
18 #include <AutoDeleter.h>
20 #include <commpage.h>
21 #include <condition_variable.h>
22 #include <elf.h>
23 #include <kimage.h>
24 #include <ksignal.h>
25 #include <team.h>
26 #include <thread.h>
27 #include <user_debugger.h>
28 #include <util/AutoLock.h>
29 #include <util/DoublyLinkedList.h>
30 #include <vm/vm.h>
31 #include <vm/VMArea.h>
32 #include <vm/VMCache.h>
34 #include "../cache/vnode_store.h"
35 #include "../vm/VMAddressSpaceLocking.h"
38 //#define TRACE_CORE_DUMP
39 #ifdef TRACE_CORE_DUMP
40 # define TRACE(...) dprintf(__VA_ARGS__)
41 #else
42 # define TRACE(...) do {} while (false)
43 #endif
46 namespace {
49 static const size_t kBufferSize = 1024 * 1024;
50 static const char* const kCoreNote = ELF_NOTE_CORE;
51 static const char* const kHaikuNote = ELF_NOTE_HAIKU;
54 struct Allocator {
55 Allocator()
57 fAligned(NULL),
58 fStrings(NULL),
59 fAlignedCapacity(0),
60 fStringCapacity(0),
61 fAlignedSize(0),
62 fStringSize(0)
66 ~Allocator()
68 free(fAligned);
71 bool HasMissingAllocations() const
73 return fAlignedSize > fAlignedCapacity || fStringSize > fStringCapacity;
76 bool Reallocate()
78 free(fAligned);
80 fAlignedCapacity = fAlignedSize;
81 fStringCapacity = fStringSize;
82 fAlignedSize = 0;
83 fStringSize = 0;
85 fAligned = (uint8*)malloc(fAlignedCapacity + fStringCapacity);
86 if (fAligned == NULL)
87 return false;
88 fStrings = (char*)(fAligned + fAlignedCapacity);
90 return true;
93 void* AllocateAligned(size_t size)
95 size_t offset = fAlignedSize;
96 fAlignedSize += (size + 7) / 8 * 8;
97 if (fAlignedSize <= fAlignedCapacity)
98 return fAligned + offset;
99 return NULL;
102 char* AllocateString(size_t length)
104 size_t offset = fStringSize;
105 fStringSize += length + 1;
106 if (fStringSize <= fStringCapacity)
107 return fStrings + offset;
108 return NULL;
111 template <typename Type>
112 Type* New()
114 void* buffer = AllocateAligned(sizeof(Type));
115 if (buffer == NULL)
116 return NULL;
117 return new(buffer) Type;
120 char* DuplicateString(const char* string)
122 if (string == NULL)
123 return NULL;
124 char* newString = AllocateString(strlen(string));
125 if (newString != NULL)
126 strcpy(newString, string);
127 return newString;
130 private:
131 uint8* fAligned;
132 char* fStrings;
133 size_t fAlignedCapacity;
134 size_t fStringCapacity;
135 size_t fAlignedSize;
136 size_t fStringSize;
140 struct TeamInfo : team_info {
144 struct ThreadState : DoublyLinkedListLinkImpl<ThreadState> {
145 ThreadState()
147 fThread(NULL),
148 fComplete(false)
152 ~ThreadState()
154 SetThread(NULL);
157 static ThreadState* Create()
159 ThreadState* state = new(std::nothrow) ThreadState;
160 if (state == NULL)
161 return NULL;
162 return state;
165 Thread* GetThread() const
167 return fThread;
170 void SetThread(Thread* thread)
172 if (fThread != NULL)
173 fThread->ReleaseReference();
175 fThread = thread;
177 if (fThread != NULL)
178 fThread->AcquireReference();
181 /*! Invoke with thread lock and scheduler lock being held. */
182 void GetState()
184 fState = fThread->state;
185 fPriority = fThread->priority;
186 fStackBase = fThread->user_stack_base;
187 fStackEnd = fStackBase + fThread->user_stack_size;
188 strlcpy(fName, fThread->name, sizeof(fName));
189 if (arch_get_thread_debug_cpu_state(fThread, &fCpuState) != B_OK)
190 memset(&fCpuState, 0, sizeof(fCpuState));
193 bool IsComplete() const
195 return fComplete;
198 void SetComplete(bool complete)
200 fComplete = complete;
203 int32 State() const
205 return fState;
208 int32 Priority() const
210 return fPriority;
213 addr_t StackBase() const
215 return fStackBase;
218 addr_t StackEnd() const
220 return fStackEnd;
223 const char* Name() const
225 return fName;
228 const debug_cpu_state* CpuState() const
230 return &fCpuState;
233 private:
234 Thread* fThread;
235 int32 fState;
236 int32 fPriority;
237 addr_t fStackBase;
238 addr_t fStackEnd;
239 char fName[B_OS_NAME_LENGTH];
240 debug_cpu_state fCpuState;
241 bool fComplete;
245 typedef DoublyLinkedList<ThreadState> ThreadStateList;
248 struct ImageInfo : DoublyLinkedListLinkImpl<ImageInfo> {
249 ImageInfo(struct image* image)
251 fId(image->info.basic_info.id),
252 fType(image->info.basic_info.type),
253 fDeviceId(image->info.basic_info.device),
254 fNodeId(image->info.basic_info.node),
255 fName(strdup(image->info.basic_info.name)),
256 fInitRoutine((addr_t)image->info.basic_info.init_routine),
257 fTermRoutine((addr_t)image->info.basic_info.term_routine),
258 fText((addr_t)image->info.basic_info.text),
259 fData((addr_t)image->info.basic_info.data),
260 fTextSize(image->info.basic_info.text_size),
261 fDataSize(image->info.basic_info.data_size),
262 fTextDelta(image->info.text_delta),
263 fSymbolTable((addr_t)image->info.symbol_table),
264 fSymbolHash((addr_t)image->info.symbol_hash),
265 fStringTable((addr_t)image->info.string_table),
266 fSymbolTableData(NULL),
267 fStringTableData(NULL),
268 fSymbolCount(0),
269 fStringTableSize(0)
271 if (fName != NULL && strcmp(fName, "commpage") == 0)
272 _GetCommpageSymbols();
275 ~ImageInfo()
277 free(fName);
278 _FreeSymbolData();
281 static ImageInfo* Create(struct image* image)
283 ImageInfo* imageInfo = new(std::nothrow) ImageInfo(image);
284 if (imageInfo == NULL || imageInfo->fName == NULL) {
285 delete imageInfo;
286 return NULL;
289 return imageInfo;
292 image_id Id() const
294 return fId;
297 image_type Type() const
299 return fType;
302 const char* Name() const
304 return fName;
307 dev_t DeviceId() const
309 return fDeviceId;
312 ino_t NodeId() const
314 return fNodeId;
317 addr_t InitRoutine() const
319 return fInitRoutine;
322 addr_t TermRoutine() const
324 return fTermRoutine;
327 addr_t TextBase() const
329 return fText;
332 size_t TextSize() const
334 return fTextSize;
337 ssize_t TextDelta() const
339 return fTextDelta;
342 addr_t DataBase() const
344 return fData;
347 size_t DataSize() const
349 return fDataSize;
352 addr_t SymbolTable() const
354 return fSymbolTable;
357 addr_t SymbolHash() const
359 return fSymbolHash;
362 addr_t StringTable() const
364 return fStringTable;
367 elf_sym* SymbolTableData() const
369 return fSymbolTableData;
372 char* StringTableData() const
374 return fStringTableData;
377 uint32 SymbolCount() const
379 return fSymbolCount;
382 size_t StringTableSize() const
384 return fStringTableSize;
387 private:
388 void _GetCommpageSymbols()
390 image_id commpageId = get_commpage_image();
392 // get the size of the tables
393 int32 symbolCount = 0;
394 size_t stringTableSize = 0;
395 status_t error = elf_read_kernel_image_symbols(commpageId, NULL,
396 &symbolCount, NULL, &stringTableSize,
397 NULL, true);
398 if (error != B_OK)
399 return;
400 if (symbolCount == 0 || stringTableSize == 0)
401 return;
403 // allocate the tables
404 fSymbolTableData = (elf_sym*)malloc(sizeof(elf_sym) * symbolCount);
405 fStringTableData = (char*)malloc(stringTableSize);
406 if (fSymbolTableData == NULL || fStringTableData == NULL) {
407 _FreeSymbolData();
408 return;
411 fSymbolCount = symbolCount;
412 fStringTableSize = stringTableSize;
414 // get the data
415 error = elf_read_kernel_image_symbols(commpageId,
416 fSymbolTableData, &symbolCount, fStringTableData, &stringTableSize,
417 NULL, true);
418 if (error != B_OK)
419 _FreeSymbolData();
422 void _FreeSymbolData()
424 free(fSymbolTableData);
425 free(fStringTableData);
427 fSymbolTableData = NULL;
428 fStringTableData = NULL;
429 fSymbolCount = 0;
430 fStringTableSize = 0;
433 private:
434 image_id fId;
435 image_type fType;
436 dev_t fDeviceId;
437 ino_t fNodeId;
438 char* fName;
439 addr_t fInitRoutine;
440 addr_t fTermRoutine;
441 addr_t fText;
442 addr_t fData;
443 size_t fTextSize;
444 size_t fDataSize;
445 ssize_t fTextDelta;
446 addr_t fSymbolTable;
447 addr_t fSymbolHash;
448 addr_t fStringTable;
449 // for commpage image
450 elf_sym* fSymbolTableData;
451 char* fStringTableData;
452 uint32 fSymbolCount;
453 size_t fStringTableSize;
457 typedef DoublyLinkedList<ImageInfo> ImageInfoList;
460 struct AreaInfo : DoublyLinkedListLinkImpl<AreaInfo> {
461 static AreaInfo* Create(Allocator& allocator, VMArea* area, size_t ramSize,
462 dev_t deviceId, ino_t nodeId)
464 AreaInfo* areaInfo = allocator.New<AreaInfo>();
465 const char* name = allocator.DuplicateString(area->name);
467 if (areaInfo != NULL) {
468 areaInfo->fId = area->id;
469 areaInfo->fName = name;
470 areaInfo->fBase = area->Base();
471 areaInfo->fSize = area->Size();
472 areaInfo->fLock = B_FULL_LOCK;
473 areaInfo->fProtection = area->protection;
474 areaInfo->fRamSize = ramSize;
475 areaInfo->fDeviceId = deviceId;
476 areaInfo->fNodeId = nodeId;
477 areaInfo->fCacheOffset = area->cache_offset;
478 areaInfo->fImageInfo = NULL;
481 return areaInfo;
484 area_id Id() const
486 return fId;
489 const char* Name() const
491 return fName;
494 addr_t Base() const
496 return fBase;
499 size_t Size() const
501 return fSize;
504 uint32 Lock() const
506 return fLock;
509 uint32 Protection() const
511 return fProtection;
514 size_t RamSize() const
516 return fRamSize;
519 off_t CacheOffset() const
521 return fCacheOffset;
524 dev_t DeviceId() const
526 return fDeviceId;
529 ino_t NodeId() const
531 return fNodeId;
534 ImageInfo* GetImageInfo() const
536 return fImageInfo;
539 void SetImageInfo(ImageInfo* imageInfo)
541 fImageInfo = imageInfo;
544 private:
545 area_id fId;
546 const char* fName;
547 addr_t fBase;
548 size_t fSize;
549 uint32 fLock;
550 uint32 fProtection;
551 size_t fRamSize;
552 dev_t fDeviceId;
553 ino_t fNodeId;
554 off_t fCacheOffset;
555 ImageInfo* fImageInfo;
559 typedef DoublyLinkedList<AreaInfo> AreaInfoList;
562 struct BufferedFile {
563 BufferedFile()
565 fFd(-1),
566 fBuffer(NULL),
567 fCapacity(0),
568 fOffset(0),
569 fBuffered(0),
570 fStatus(B_NO_INIT)
574 ~BufferedFile()
576 if (fFd >= 0)
577 close(fFd);
579 free(fBuffer);
582 status_t Init(const char* path)
584 fCapacity = kBufferSize;
585 fBuffer = (uint8*)malloc(fCapacity);
586 if (fBuffer == NULL)
587 return B_NO_MEMORY;
589 fFd = open(path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR);
590 if (fFd < 0)
591 return errno;
593 fStatus = B_OK;
594 return B_OK;
597 status_t Status() const
599 return fStatus;
602 off_t EndOffset() const
604 return fOffset + (off_t)fBuffered;
607 status_t Flush()
609 if (fStatus != B_OK)
610 return fStatus;
612 if (fBuffered == 0)
613 return B_OK;
615 ssize_t written = pwrite(fFd, fBuffer, fBuffered, fOffset);
616 if (written < 0)
617 return fStatus = errno;
618 if ((size_t)written != fBuffered)
619 return fStatus = B_IO_ERROR;
621 fOffset += (off_t)fBuffered;
622 fBuffered = 0;
623 return B_OK;
626 status_t Seek(off_t offset)
628 if (fStatus != B_OK)
629 return fStatus;
631 if (fBuffered == 0) {
632 fOffset = offset;
633 } else if (offset != fOffset + (off_t)fBuffered) {
634 status_t error = Flush();
635 if (error != B_OK)
636 return fStatus = error;
637 fOffset = offset;
640 return B_OK;
643 status_t Write(const void* data, size_t size)
645 if (fStatus != B_OK)
646 return fStatus;
648 if (size == 0)
649 return B_OK;
651 while (size > 0) {
652 size_t toWrite = std::min(size, fCapacity - fBuffered);
653 if (toWrite == 0) {
654 status_t error = Flush();
655 if (error != B_OK)
656 return fStatus = error;
657 continue;
660 memcpy(fBuffer + fBuffered, data, toWrite);
661 fBuffered += toWrite;
662 size -= toWrite;
665 return B_OK;
668 template<typename Data>
669 status_t Write(const Data& data)
671 return Write(&data, sizeof(data));
674 status_t WriteAt(off_t offset, const void* data, size_t size)
676 if (Seek(offset) != B_OK)
677 return fStatus;
679 return Write(data, size);
682 status_t WriteUserArea(addr_t base, size_t size)
684 uint8* data = (uint8*)base;
685 size = size / B_PAGE_SIZE * B_PAGE_SIZE;
687 // copy the area page-wise into the buffer, flushing when necessary
688 while (size > 0) {
689 if (fBuffered + B_PAGE_SIZE > fCapacity) {
690 status_t error = Flush();
691 if (error != B_OK)
692 return error;
695 if (user_memcpy(fBuffer + fBuffered, data, B_PAGE_SIZE) != B_OK)
696 memset(fBuffer + fBuffered, 0, B_PAGE_SIZE);
698 fBuffered += B_PAGE_SIZE;
699 data += B_PAGE_SIZE;
700 size -= B_PAGE_SIZE;
703 return B_OK;
706 private:
707 int fFd;
708 uint8* fBuffer;
709 size_t fCapacity;
710 off_t fOffset;
711 size_t fBuffered;
712 status_t fStatus;
716 struct DummyWriter {
717 DummyWriter()
719 fWritten(0)
723 status_t Status() const
725 return B_OK;
728 size_t BytesWritten() const
730 return fWritten;
733 status_t Write(const void* data, size_t size)
735 fWritten += size;
736 return B_OK;
739 template<typename Data>
740 status_t Write(const Data& data)
742 return Write(&data, sizeof(data));
745 private:
746 size_t fWritten;
750 struct CoreDumper {
751 CoreDumper()
753 fCurrentThread(thread_get_current_thread()),
754 fTeam(fCurrentThread->team),
755 fFile(),
756 fThreadCount(0),
757 fThreadStates(),
758 fPreAllocatedThreadStates(),
759 fAreaInfoAllocator(),
760 fAreaInfos(),
761 fImageInfos(),
762 fThreadBlockCondition()
764 fThreadBlockCondition.Init(this, "core dump");
767 ~CoreDumper()
769 while (ThreadState* state = fThreadStates.RemoveHead())
770 delete state;
771 while (ThreadState* state = fPreAllocatedThreadStates.RemoveHead())
772 delete state;
773 while (ImageInfo* info = fImageInfos.RemoveHead())
774 delete info;
777 status_t Dump(const char* path, bool killTeam)
779 // the path must be absolute
780 if (path[0] != '/')
781 return B_BAD_VALUE;
783 AutoLocker<Team> teamLocker(fTeam);
785 // indicate that we're dumping core
786 if ((atomic_or(&fTeam->flags, TEAM_FLAG_DUMP_CORE)
787 & TEAM_FLAG_DUMP_CORE) != 0) {
788 return B_BUSY;
791 fTeam->SetCoreDumpCondition(&fThreadBlockCondition);
793 int32 threadCount = _SetThreadsCoreDumpFlag(true);
795 teamLocker.Unlock();
797 // write the core file
798 status_t error = _Dump(path, threadCount);
800 // send kill signal, if requested
801 if (killTeam)
802 kill_team(fTeam->id);
804 // clean up the team state and wake up waiting threads
805 teamLocker.Lock();
807 fTeam->SetCoreDumpCondition(NULL);
809 atomic_and(&fTeam->flags, ~(int32)TEAM_FLAG_DUMP_CORE);
811 _SetThreadsCoreDumpFlag(false);
813 fThreadBlockCondition.NotifyAll();
815 return error;
818 private:
819 status_t _Dump(const char* path, int32 threadCount)
821 status_t error = _GetTeamInfo();
822 if (error != B_OK)
823 return error;
825 // pre-allocate a list of thread states
826 if (!_AllocateThreadStates(threadCount))
827 return B_NO_MEMORY;
829 // collect the threads states
830 _GetThreadStates();
832 // collect the other team information
833 if (!_GetAreaInfos() || !_GetImageInfos())
834 return B_NO_MEMORY;
836 // open the file
837 error = fFile.Init(path);
838 if (error != B_OK)
839 return error;
841 _PrepareCoreFileInfo();
843 // write ELF header
844 error = _WriteElfHeader();
845 if (error != B_OK)
846 return error;
848 // write note segment
849 error = _WriteNotes();
850 if (error != B_OK)
851 return error;
853 size_t notesEndOffset = (size_t)fFile.EndOffset();
854 fNoteSegmentSize = notesEndOffset - fNoteSegmentOffset;
855 fFirstAreaSegmentOffset = (notesEndOffset + B_PAGE_SIZE - 1)
856 / B_PAGE_SIZE * B_PAGE_SIZE;
858 error = _WriteProgramHeaders();
859 if (error != B_OK)
860 return error;
862 // write area segments
863 error = _WriteAreaSegments();
864 if (error != B_OK)
865 return error;
867 return _WriteElfHeader();
870 int32 _SetThreadsCoreDumpFlag(bool setFlag)
872 int32 count = 0;
874 for (Thread* thread = fTeam->thread_list; thread != NULL;
875 thread = thread->team_next) {
876 count++;
877 if (setFlag) {
878 atomic_or(&thread->flags, THREAD_FLAGS_TRAP_FOR_CORE_DUMP);
879 } else {
880 atomic_and(&thread->flags,
881 ~(int32)THREAD_FLAGS_TRAP_FOR_CORE_DUMP);
885 return count;
888 status_t _GetTeamInfo()
890 return get_team_info(fTeam->id, &fTeamInfo);
893 bool _AllocateThreadStates(int32 count)
895 if (!_PreAllocateThreadStates(count))
896 return false;
898 TeamLocker teamLocker(fTeam);
900 for (;;) {
901 fThreadCount = 0;
902 int32 missing = 0;
904 for (Thread* thread = fTeam->thread_list; thread != NULL;
905 thread = thread->team_next) {
906 fThreadCount++;
907 ThreadState* state = fPreAllocatedThreadStates.RemoveHead();
908 if (state != NULL) {
909 state->SetThread(thread);
910 fThreadStates.Insert(state);
911 } else
912 missing++;
915 if (missing == 0)
916 break;
918 teamLocker.Unlock();
920 fPreAllocatedThreadStates.MoveFrom(&fThreadStates);
921 if (!_PreAllocateThreadStates(missing))
922 return false;
924 teamLocker.Lock();
927 return true;
930 bool _PreAllocateThreadStates(int32 count)
932 for (int32 i = 0; i < count; i++) {
933 ThreadState* state = ThreadState::Create();
934 if (state == NULL)
935 return false;
936 fPreAllocatedThreadStates.Insert(state);
939 return true;
942 void _GetThreadStates()
944 for (;;) {
945 bool missing = false;
946 for (ThreadStateList::Iterator it = fThreadStates.GetIterator();
947 ThreadState* state = it.Next();) {
948 if (state->IsComplete())
949 continue;
951 Thread* thread = state->GetThread();
952 AutoLocker<Thread> threadLocker(thread);
953 if (thread->team != fTeam) {
954 // no longer in our team -- i.e. dying and transferred to
955 // the kernel team
956 threadLocker.Unlock();
957 it.Remove();
958 delete state;
959 fThreadCount--;
960 continue;
963 InterruptsSpinLocker schedulerLocker(&thread->scheduler_lock);
964 if (thread != fCurrentThread
965 && thread->state == B_THREAD_RUNNING) {
966 missing = true;
967 continue;
970 state->GetState();
971 state->SetComplete(true);
974 if (!missing)
975 break;
977 // We still haven't got a state for all threads. Wait a moment and
978 // try again.
979 snooze(10000);
983 bool _GetAreaInfos()
985 for (;;) {
986 AddressSpaceReadLocker addressSpaceLocker(fTeam->address_space,
987 true);
989 for (VMAddressSpace::AreaIterator it
990 = addressSpaceLocker.AddressSpace()->GetAreaIterator();
991 VMArea* area = it.Next();) {
993 VMCache* cache = vm_area_get_locked_cache(area);
994 size_t ramSize = (size_t)cache->page_count * B_PAGE_SIZE;
995 // simplified, but what the kernel uses as well ATM
997 // iterate to the root cache and, if it is a mapped file, get
998 // the file's node_ref
999 while (VMCache* source = cache->source) {
1000 source->Lock();
1001 source->AcquireRefLocked();
1002 cache->ReleaseRefAndUnlock();
1003 cache = source;
1006 dev_t deviceId = -1;
1007 ino_t nodeId = -1;
1008 if (cache->type == CACHE_TYPE_VNODE) {
1009 VMVnodeCache* vnodeCache = (VMVnodeCache*)cache;
1010 deviceId = vnodeCache->DeviceId();
1011 nodeId = vnodeCache->InodeId();
1014 cache->ReleaseRefAndUnlock();
1016 AreaInfo* areaInfo = AreaInfo::Create(fAreaInfoAllocator, area,
1017 ramSize, deviceId, nodeId);
1019 if (areaInfo != NULL)
1020 fAreaInfos.Insert(areaInfo);
1023 addressSpaceLocker.Unlock();
1025 if (!fAreaInfoAllocator.HasMissingAllocations())
1026 return true;
1028 if (!fAreaInfoAllocator.Reallocate())
1029 return false;
1033 bool _GetImageInfos()
1035 return image_iterate_through_team_images(fTeam->id,
1036 &_GetImageInfoCallback, this) == NULL;
1039 static bool _GetImageInfoCallback(struct image* image, void* cookie)
1041 return ((CoreDumper*)cookie)->_GetImageInfo(image);
1044 bool _GetImageInfo(struct image* image)
1046 ImageInfo* info = ImageInfo::Create(image);
1047 if (info == NULL)
1048 return true;
1050 fImageInfos.Insert(info);
1051 return false;
1054 void _PrepareCoreFileInfo()
1056 // assign image infos to area infos where possible
1057 fAreaCount = 0;
1058 fMappedFilesCount = 0;
1059 for (AreaInfoList::Iterator it = fAreaInfos.GetIterator();
1060 AreaInfo* areaInfo = it.Next();) {
1061 fAreaCount++;
1062 dev_t deviceId = areaInfo->DeviceId();
1063 if (deviceId < 0)
1064 continue;
1065 ImageInfo* imageInfo = _FindImageInfo(deviceId, areaInfo->NodeId());
1066 if (imageInfo != NULL) {
1067 areaInfo->SetImageInfo(imageInfo);
1068 fMappedFilesCount++;
1072 fImageCount = fImageInfos.Count();
1073 fSegmentCount = 1 + fAreaCount;
1074 fProgramHeadersOffset = sizeof(elf_ehdr);
1075 fNoteSegmentOffset = fProgramHeadersOffset
1076 + sizeof(elf_phdr) * fSegmentCount;
1079 ImageInfo* _FindImageInfo(dev_t deviceId, ino_t nodeId) const
1081 for (ImageInfoList::ConstIterator it = fImageInfos.GetIterator();
1082 ImageInfo* info = it.Next();) {
1083 if (info->DeviceId() == deviceId && info->NodeId() == nodeId)
1084 return info;
1087 return NULL;
1090 status_t _WriteElfHeader()
1092 elf_ehdr header;
1093 memset(&header, 0, sizeof(header));
1095 // e_ident
1096 header.e_ident[EI_MAG0] = ELFMAG[0];
1097 header.e_ident[EI_MAG1] = ELFMAG[1];
1098 header.e_ident[EI_MAG2] = ELFMAG[2];
1099 header.e_ident[EI_MAG3] = ELFMAG[3];
1100 #ifdef B_HAIKU_64_BIT
1101 header.e_ident[EI_CLASS] = ELFCLASS64;
1102 #else
1103 header.e_ident[EI_CLASS] = ELFCLASS32;
1104 #endif
1105 #if B_HOST_IS_LENDIAN
1106 header.e_ident[EI_DATA] = ELFDATA2LSB;
1107 #else
1108 header.e_ident[EI_DATA] = ELFDATA2MSB;
1109 #endif
1110 header.e_ident[EI_VERSION] = EV_CURRENT;
1112 // e_type
1113 header.e_type = ET_CORE;
1115 // e_machine
1116 #if defined(__HAIKU_ARCH_X86)
1117 header.e_machine = EM_386;
1118 #elif defined(__HAIKU_ARCH_X86_64)
1119 header.e_machine = EM_X86_64;
1120 #elif defined(__HAIKU_ARCH_PPC)
1121 header.e_machine = EM_PPC64;
1122 #elif defined(__HAIKU_ARCH_M68K)
1123 header.e_machine = EM_68K;
1124 #elif defined(__HAIKU_ARCH_MIPSEL)
1125 header.e_machine = EM_MIPS;
1126 #elif defined(__HAIKU_ARCH_ARM)
1127 header.e_machine = EM_ARM;
1128 #else
1129 # error Unsupported architecture!
1130 #endif
1132 header.e_version = EV_CURRENT;
1133 header.e_entry = 0;
1134 header.e_phoff = sizeof(header);
1135 header.e_shoff = 0;
1136 header.e_flags = 0;
1137 header.e_ehsize = sizeof(header);
1138 header.e_phentsize = sizeof(elf_phdr);
1139 header.e_phnum = fSegmentCount;
1140 header.e_shentsize = sizeof(elf_shdr);
1141 header.e_shnum = 0;
1142 header.e_shstrndx = SHN_UNDEF;
1144 return fFile.WriteAt(0, &header, sizeof(header));
1147 status_t _WriteProgramHeaders()
1149 fFile.Seek(fProgramHeadersOffset);
1151 // write the header for the notes segment
1152 elf_phdr header;
1153 memset(&header, 0, sizeof(header));
1154 header.p_type = PT_NOTE;
1155 header.p_flags = 0;
1156 header.p_offset = fNoteSegmentOffset;
1157 header.p_vaddr = 0;
1158 header.p_paddr = 0;
1159 header.p_filesz = fNoteSegmentSize;
1160 header.p_memsz = 0;
1161 header.p_align = 0;
1162 fFile.Write(header);
1164 // write the headers for the area segments
1165 size_t segmentOffset = fFirstAreaSegmentOffset;
1166 for (AreaInfoList::Iterator it = fAreaInfos.GetIterator();
1167 AreaInfo* areaInfo = it.Next();) {
1168 memset(&header, 0, sizeof(header));
1169 header.p_type = PT_LOAD;
1170 header.p_flags = 0;
1171 uint32 protection = areaInfo->Protection();
1172 if ((protection & B_READ_AREA) != 0)
1173 header.p_flags |= PF_READ;
1174 if ((protection & B_WRITE_AREA) != 0)
1175 header.p_flags |= PF_WRITE;
1176 if ((protection & B_EXECUTE_AREA) != 0)
1177 header.p_flags |= PF_EXECUTE;
1178 header.p_offset = segmentOffset;
1179 header.p_vaddr = areaInfo->Base();
1180 header.p_paddr = 0;
1181 header.p_filesz = areaInfo->Size();
1182 header.p_memsz = areaInfo->Size();
1183 header.p_align = 0;
1184 fFile.Write(header);
1186 segmentOffset += areaInfo->Size();
1189 return fFile.Status();
1192 status_t _WriteAreaSegments()
1194 fFile.Seek(fFirstAreaSegmentOffset);
1196 for (AreaInfoList::Iterator it = fAreaInfos.GetIterator();
1197 AreaInfo* areaInfo = it.Next();) {
1198 status_t error = fFile.WriteUserArea(areaInfo->Base(),
1199 areaInfo->Size());
1200 if (error != B_OK)
1201 return error;
1204 return fFile.Status();
1207 status_t _WriteNotes()
1209 status_t error = fFile.Seek((off_t)fNoteSegmentOffset);
1210 if (error != B_OK)
1211 return error;
1213 error = _WriteFilesNote();
1214 if (error != B_OK)
1215 return error;
1217 error = _WriteTeamNote();
1218 if (error != B_OK)
1219 return error;
1221 error = _WriteAreasNote();
1222 if (error != B_OK)
1223 return error;
1225 error = _WriteImagesNote();
1226 if (error != B_OK)
1227 return error;
1229 error = _WriteImageSymbolsNotes();
1230 if (error != B_OK)
1231 return error;
1233 error = _WriteThreadsNote();
1234 if (error != B_OK)
1235 return error;
1237 return B_OK;
1240 template<typename Writer>
1241 void _WriteTeamNote(Writer& writer)
1243 elf_note_team note;
1244 memset(&note, 0, sizeof(note));
1245 note.nt_id = fTeamInfo.team;
1246 note.nt_uid = fTeamInfo.uid;
1247 note.nt_gid = fTeamInfo.gid;
1248 writer.Write((uint32)sizeof(note));
1249 writer.Write(note);
1251 // write args
1252 const char* args = fTeamInfo.args;
1253 writer.Write(args, strlen(args) + 1);
1256 status_t _WriteTeamNote()
1258 // determine needed size for the note's data
1259 DummyWriter dummyWriter;
1260 _WriteTeamNote(dummyWriter);
1261 size_t dataSize = dummyWriter.BytesWritten();
1263 // write the note header
1264 _WriteNoteHeader(kHaikuNote, NT_TEAM, dataSize);
1266 // write the note data
1267 _WriteTeamNote(fFile);
1269 // padding
1270 _WriteNotePadding(dataSize);
1272 return fFile.Status();
1275 template<typename Writer>
1276 void _WriteFilesNote(Writer& writer)
1278 // file count and table size
1279 writer.Write(fMappedFilesCount);
1280 writer.Write((size_t)B_PAGE_SIZE);
1282 // write table
1283 for (AreaInfoList::Iterator it = fAreaInfos.GetIterator();
1284 AreaInfo* areaInfo = it.Next();) {
1285 if (areaInfo->GetImageInfo() == NULL)
1286 continue;
1288 // start address, end address, and file offset in pages
1289 writer.Write(areaInfo->Base());
1290 writer.Write(areaInfo->Base() + areaInfo->Size());
1291 writer.Write(size_t(areaInfo->CacheOffset() / B_PAGE_SIZE));
1294 // write strings
1295 for (AreaInfoList::Iterator it = fAreaInfos.GetIterator();
1296 AreaInfo* areaInfo = it.Next();) {
1297 ImageInfo* imageInfo = areaInfo->GetImageInfo();
1298 if (imageInfo == NULL)
1299 continue;
1301 const char* name = imageInfo->Name();
1302 writer.Write(name, strlen(name) + 1);
1306 status_t _WriteFilesNote()
1308 // determine needed size for the note's data
1309 DummyWriter dummyWriter;
1310 _WriteFilesNote(dummyWriter);
1311 size_t dataSize = dummyWriter.BytesWritten();
1313 // write the note header
1314 _WriteNoteHeader(kCoreNote, NT_FILE, dataSize);
1316 // write the note data
1317 _WriteFilesNote(fFile);
1319 // padding
1320 _WriteNotePadding(dataSize);
1322 return fFile.Status();
1325 template<typename Writer>
1326 void _WriteAreasNote(Writer& writer)
1328 // area count
1329 writer.Write((uint32)fAreaCount);
1330 writer.Write((uint32)sizeof(elf_note_area_entry));
1332 // write table
1333 for (AreaInfoList::Iterator it = fAreaInfos.GetIterator();
1334 AreaInfo* areaInfo = it.Next();) {
1335 elf_note_area_entry entry;
1336 memset(&entry, 0, sizeof(entry));
1337 entry.na_id = areaInfo->Id();
1338 entry.na_lock = areaInfo->Lock();
1339 entry.na_protection = areaInfo->Protection();
1340 entry.na_base = areaInfo->Base();
1341 entry.na_size = areaInfo->Size();
1342 entry.na_ram_size = areaInfo->RamSize();
1343 writer.Write(entry);
1346 // write strings
1347 for (AreaInfoList::Iterator it = fAreaInfos.GetIterator();
1348 AreaInfo* areaInfo = it.Next();) {
1349 const char* name = areaInfo->Name();
1350 writer.Write(name, strlen(name) + 1);
1354 status_t _WriteAreasNote()
1356 // determine needed size for the note's data
1357 DummyWriter dummyWriter;
1358 _WriteAreasNote(dummyWriter);
1359 size_t dataSize = dummyWriter.BytesWritten();
1361 // write the note header
1362 _WriteNoteHeader(kHaikuNote, NT_AREAS, dataSize);
1364 // write the note data
1365 _WriteAreasNote(fFile);
1367 // padding
1368 _WriteNotePadding(dataSize);
1370 return fFile.Status();
1373 template<typename Writer>
1374 void _WriteImagesNote(Writer& writer)
1376 // image count
1377 writer.Write((uint32)fImageCount);
1378 writer.Write((uint32)sizeof(elf_note_image_entry));
1380 // write table
1381 for (ImageInfoList::Iterator it = fImageInfos.GetIterator();
1382 ImageInfo* imageInfo = it.Next();) {
1383 elf_note_image_entry entry;
1384 memset(&entry, 0, sizeof(entry));
1385 entry.ni_id = imageInfo->Id();
1386 entry.ni_type = imageInfo->Type();
1387 entry.ni_init_routine = imageInfo->InitRoutine();
1388 entry.ni_term_routine = imageInfo->TermRoutine();
1389 entry.ni_device = imageInfo->DeviceId();
1390 entry.ni_node = imageInfo->NodeId();
1391 entry.ni_text_base = imageInfo->TextBase();
1392 entry.ni_text_size = imageInfo->TextSize();
1393 entry.ni_data_base = imageInfo->DataBase();
1394 entry.ni_data_size = imageInfo->DataSize();
1395 entry.ni_text_delta = imageInfo->TextDelta();
1396 entry.ni_symbol_table = imageInfo->SymbolTable();
1397 entry.ni_symbol_hash = imageInfo->SymbolHash();
1398 entry.ni_string_table = imageInfo->StringTable();
1399 writer.Write(entry);
1402 // write strings
1403 for (ImageInfoList::Iterator it = fImageInfos.GetIterator();
1404 ImageInfo* imageInfo = it.Next();) {
1405 const char* name = imageInfo->Name();
1406 writer.Write(name, strlen(name) + 1);
1410 status_t _WriteImagesNote()
1412 // determine needed size for the note's data
1413 DummyWriter dummyWriter;
1414 _WriteImagesNote(dummyWriter);
1415 size_t dataSize = dummyWriter.BytesWritten();
1417 // write the note header
1418 _WriteNoteHeader(kHaikuNote, NT_IMAGES, dataSize);
1420 // write the note data
1421 _WriteImagesNote(fFile);
1423 // padding
1424 _WriteNotePadding(dataSize);
1426 return fFile.Status();
1429 status_t _WriteImageSymbolsNotes()
1431 // write table
1432 for (ImageInfoList::Iterator it = fImageInfos.GetIterator();
1433 ImageInfo* imageInfo = it.Next();) {
1434 if (imageInfo->SymbolTableData() == NULL
1435 || imageInfo->StringTableData() == NULL) {
1436 continue;
1439 status_t error = _WriteImageSymbolsNote(imageInfo);
1440 if (error != B_OK)
1441 return error;
1444 return B_OK;
1447 template<typename Writer>
1448 void _WriteImageSymbolsNote(const ImageInfo* imageInfo, Writer& writer)
1450 uint32 symbolCount = imageInfo->SymbolCount();
1451 uint32 symbolEntrySize = (uint32)sizeof(elf_sym);
1453 writer.Write((int32)imageInfo->Id());
1454 writer.Write(symbolCount);
1455 writer.Write(symbolEntrySize);
1456 writer.Write(imageInfo->SymbolTableData(),
1457 symbolCount * symbolEntrySize);
1458 writer.Write(imageInfo->StringTableData(),
1459 imageInfo->StringTableSize());
1462 status_t _WriteImageSymbolsNote(const ImageInfo* imageInfo)
1464 // determine needed size for the note's data
1465 DummyWriter dummyWriter;
1466 _WriteImageSymbolsNote(imageInfo, dummyWriter);
1467 size_t dataSize = dummyWriter.BytesWritten();
1469 // write the note header
1470 _WriteNoteHeader(kHaikuNote, NT_SYMBOLS, dataSize);
1472 // write the note data
1473 _WriteImageSymbolsNote(imageInfo, fFile);
1475 // padding
1476 _WriteNotePadding(dataSize);
1478 return fFile.Status();
1481 template<typename Writer>
1482 void _WriteThreadsNote(Writer& writer)
1484 // thread count and size of CPU state
1485 writer.Write((uint32)fThreadCount);
1486 writer.Write((uint32)sizeof(elf_note_thread_entry));
1487 writer.Write((uint32)sizeof(debug_cpu_state));
1489 // write table
1490 for (ThreadStateList::Iterator it = fThreadStates.GetIterator();
1491 ThreadState* state = it.Next();) {
1492 elf_note_thread_entry entry;
1493 memset(&entry, 0, sizeof(entry));
1494 entry.nth_id = state->GetThread()->id;
1495 entry.nth_state = state->State();
1496 entry.nth_priority = state->Priority();
1497 entry.nth_stack_base = state->StackBase();
1498 entry.nth_stack_end = state->StackEnd();
1499 writer.Write(&entry, sizeof(entry));
1500 writer.Write(state->CpuState(), sizeof(debug_cpu_state));
1503 // write strings
1504 for (ThreadStateList::Iterator it = fThreadStates.GetIterator();
1505 ThreadState* state = it.Next();) {
1506 const char* name = state->Name();
1507 writer.Write(name, strlen(name) + 1);
1511 status_t _WriteThreadsNote()
1513 // determine needed size for the note's data
1514 DummyWriter dummyWriter;
1515 _WriteThreadsNote(dummyWriter);
1516 size_t dataSize = dummyWriter.BytesWritten();
1518 // write the note header
1519 _WriteNoteHeader(kHaikuNote, NT_THREADS, dataSize);
1521 // write the note data
1522 _WriteThreadsNote(fFile);
1524 // padding
1525 _WriteNotePadding(dataSize);
1527 return fFile.Status();
1530 status_t _WriteNoteHeader(const char* name, uint32 type, uint32 dataSize)
1532 // prepare and write the header
1533 Elf32_Nhdr noteHeader;
1534 memset(&noteHeader, 0, sizeof(noteHeader));
1535 size_t nameSize = strlen(name) + 1;
1536 noteHeader.n_namesz = nameSize;
1537 noteHeader.n_descsz = dataSize;
1538 noteHeader.n_type = type;
1539 fFile.Write(noteHeader);
1541 // write the name
1542 fFile.Write(name, nameSize);
1543 // pad the name to 4 byte alignment
1544 _WriteNotePadding(nameSize);
1545 return fFile.Status();
1548 status_t _WriteNotePadding(size_t sizeToPad)
1550 if (sizeToPad % 4 != 0) {
1551 uint8 pad[3] = {};
1552 fFile.Write(&pad, 4 - sizeToPad % 4);
1554 return fFile.Status();
1557 private:
1558 Thread* fCurrentThread;
1559 Team* fTeam;
1560 BufferedFile fFile;
1561 TeamInfo fTeamInfo;
1562 size_t fThreadCount;
1563 ThreadStateList fThreadStates;
1564 ThreadStateList fPreAllocatedThreadStates;
1565 Allocator fAreaInfoAllocator;
1566 AreaInfoList fAreaInfos;
1567 ImageInfoList fImageInfos;
1568 ConditionVariable fThreadBlockCondition;
1569 size_t fSegmentCount;
1570 size_t fProgramHeadersOffset;
1571 size_t fNoteSegmentOffset;
1572 size_t fNoteSegmentSize;
1573 size_t fFirstAreaSegmentOffset;
1574 size_t fAreaCount;
1575 size_t fImageCount;
1576 size_t fMappedFilesCount;
1580 } // unnamed namespace
1583 status_t
1584 core_dump_write_core_file(const char* path, bool killTeam)
1586 TRACE("core_dump_write_core_file(\"%s\", %d): team: %" B_PRId32 "\n", path,
1587 killTeam, team_get_current_team_id());
1589 CoreDumper* coreDumper = new(std::nothrow) CoreDumper();
1590 if (coreDumper == NULL)
1591 return B_NO_MEMORY;
1592 ObjectDeleter<CoreDumper> coreDumperDeleter(coreDumper);
1593 return coreDumper->Dump(path, killTeam);
1597 void
1598 core_dump_trap_thread()
1600 Thread* thread = thread_get_current_thread();
1601 ConditionVariableEntry conditionVariableEntry;
1602 TeamLocker teamLocker(thread->team);
1604 while ((atomic_get(&thread->flags) & THREAD_FLAGS_TRAP_FOR_CORE_DUMP)
1605 != 0) {
1606 thread->team->CoreDumpCondition()->Add(&conditionVariableEntry);
1607 teamLocker.Unlock();
1608 conditionVariableEntry.Wait();
1609 teamLocker.Lock();