mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 16:42:44 +00:00 
			
		
		
		
	 6e19ab2bbc
			
		
	
	
		6e19ab2bbc
		
	
	
	
	
		
			
			We have a new, improved string type coming up in AK (OOM aware, no null state), and while it's going to use UTF-8, the name UTF8String is a mouthful - so let's free up the String name by renaming the existing class. Making the old one have an annoying name will hopefully also help with quick adoption :^)
		
			
				
	
	
		
			166 lines
		
	
	
	
		
			5.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			166 lines
		
	
	
	
		
			5.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
 | |
|  * Copyright (c) 2022, the SerenityOS developers.
 | |
|  *
 | |
|  * SPDX-License-Identifier: BSD-2-Clause
 | |
|  */
 | |
| 
 | |
| #pragma once
 | |
| 
 | |
| #include <AK/ByteReader.h>
 | |
| #include <AK/HashMap.h>
 | |
| #include <AK/Noncopyable.h>
 | |
| #include <AK/OwnPtr.h>
 | |
| #include <LibCore/MappedFile.h>
 | |
| #include <LibELF/Core.h>
 | |
| #include <LibELF/Image.h>
 | |
| 
 | |
| namespace Coredump {
 | |
| 
 | |
| struct MemoryRegionInfo {
 | |
|     ELF::Core::NotesEntryHeader header;
 | |
|     uint64_t region_start;
 | |
|     uint64_t region_end;
 | |
|     uint16_t program_header_index;
 | |
|     StringView region_name;
 | |
| 
 | |
|     StringView object_name() const
 | |
|     {
 | |
|         if (region_name.contains("Loader.so"sv))
 | |
|             return "Loader.so"sv;
 | |
|         auto maybe_colon_index = region_name.find(':');
 | |
|         if (!maybe_colon_index.has_value())
 | |
|             return {};
 | |
|         return region_name.substring_view(0, *maybe_colon_index);
 | |
|     }
 | |
| };
 | |
| 
 | |
| class Reader {
 | |
|     AK_MAKE_NONCOPYABLE(Reader);
 | |
|     AK_MAKE_NONMOVABLE(Reader);
 | |
| 
 | |
| public:
 | |
|     static OwnPtr<Reader> create(StringView);
 | |
|     ~Reader() = default;
 | |
| 
 | |
|     template<typename Func>
 | |
|     void for_each_memory_region_info(Func func) const;
 | |
| 
 | |
|     struct LibraryInfo {
 | |
|         DeprecatedString name;
 | |
|         DeprecatedString path;
 | |
|         FlatPtr base_address { 0 };
 | |
|     };
 | |
| 
 | |
|     void for_each_library(Function<void(LibraryInfo)> func) const;
 | |
| 
 | |
|     template<typename Func>
 | |
|     void for_each_thread_info(Func func) const;
 | |
| 
 | |
|     const ELF::Image& image() const { return m_coredump_image; }
 | |
| 
 | |
|     Optional<FlatPtr> peek_memory(FlatPtr address) const;
 | |
|     Optional<MemoryRegionInfo> first_region_for_object(StringView object_name) const;
 | |
|     Optional<MemoryRegionInfo> region_containing(FlatPtr address) const;
 | |
| 
 | |
|     struct LibraryData {
 | |
|         DeprecatedString name;
 | |
|         FlatPtr base_address { 0 };
 | |
|         NonnullRefPtr<Core::MappedFile> file;
 | |
|         ELF::Image lib_elf;
 | |
|     };
 | |
|     LibraryData const* library_containing(FlatPtr address) const;
 | |
| 
 | |
|     DeprecatedString resolve_object_path(StringView object_name) const;
 | |
| 
 | |
|     int process_pid() const;
 | |
|     u8 process_termination_signal() const;
 | |
|     DeprecatedString process_executable_path() const;
 | |
|     Vector<DeprecatedString> process_arguments() const;
 | |
|     Vector<DeprecatedString> process_environment() const;
 | |
|     HashMap<DeprecatedString, DeprecatedString> metadata() const;
 | |
| 
 | |
| private:
 | |
|     explicit Reader(ReadonlyBytes);
 | |
|     explicit Reader(ByteBuffer);
 | |
|     explicit Reader(NonnullRefPtr<Core::MappedFile>);
 | |
| 
 | |
|     static Optional<ByteBuffer> decompress_coredump(ReadonlyBytes);
 | |
| 
 | |
|     class NotesEntryIterator {
 | |
|     public:
 | |
|         NotesEntryIterator(u8 const* notes_data);
 | |
| 
 | |
|         ELF::Core::NotesEntryHeader::Type type() const;
 | |
|         const ELF::Core::NotesEntry* current() const;
 | |
| 
 | |
|         void next();
 | |
|         bool at_end() const;
 | |
| 
 | |
|     private:
 | |
|         const ELF::Core::NotesEntry* m_current { nullptr };
 | |
|         u8 const* start { nullptr };
 | |
|     };
 | |
| 
 | |
|     // Private as we don't need anyone poking around in this JsonObject
 | |
|     // manually - we know very well what should be included and expose that
 | |
|     // as getters with the appropriate (non-JsonValue) types.
 | |
|     const JsonObject process_info() const;
 | |
| 
 | |
|     // For uncompressed coredumps, we keep the MappedFile
 | |
|     RefPtr<Core::MappedFile> m_mapped_file;
 | |
| 
 | |
|     // For compressed coredumps, we decompress them into a ByteBuffer
 | |
|     ByteBuffer m_coredump_buffer;
 | |
| 
 | |
|     ReadonlyBytes m_coredump_bytes;
 | |
| 
 | |
|     ELF::Image m_coredump_image;
 | |
|     ssize_t m_notes_segment_index { -1 };
 | |
| };
 | |
| 
 | |
| template<typename Func>
 | |
| void Reader::for_each_memory_region_info(Func func) const
 | |
| {
 | |
|     NotesEntryIterator it(bit_cast<u8 const*>(m_coredump_image.program_header(m_notes_segment_index).raw_data()));
 | |
|     for (; !it.at_end(); it.next()) {
 | |
|         if (it.type() != ELF::Core::NotesEntryHeader::Type::MemoryRegionInfo)
 | |
|             continue;
 | |
|         ELF::Core::MemoryRegionInfo raw_memory_region_info;
 | |
|         ReadonlyBytes raw_data {
 | |
|             it.current(),
 | |
|             sizeof(raw_memory_region_info),
 | |
|         };
 | |
|         ByteReader::load(raw_data.data(), raw_memory_region_info);
 | |
| 
 | |
|         auto const* region_name_ptr = bit_cast<char const*>(raw_data.offset_pointer(raw_data.size()));
 | |
|         MemoryRegionInfo memory_region_info {
 | |
|             raw_memory_region_info.header,
 | |
|             raw_memory_region_info.region_start,
 | |
|             raw_memory_region_info.region_end,
 | |
|             raw_memory_region_info.program_header_index,
 | |
|             { region_name_ptr, strlen(region_name_ptr) },
 | |
|         };
 | |
|         IterationDecision decision = func(memory_region_info);
 | |
|         if (decision == IterationDecision::Break)
 | |
|             return;
 | |
|     }
 | |
| }
 | |
| 
 | |
| template<typename Func>
 | |
| void Reader::for_each_thread_info(Func func) const
 | |
| {
 | |
|     NotesEntryIterator it(bit_cast<u8 const*>(m_coredump_image.program_header(m_notes_segment_index).raw_data()));
 | |
|     for (; !it.at_end(); it.next()) {
 | |
|         if (it.type() != ELF::Core::NotesEntryHeader::Type::ThreadInfo)
 | |
|             continue;
 | |
|         ELF::Core::ThreadInfo thread_info;
 | |
|         ByteReader::load(bit_cast<u8 const*>(it.current()), thread_info);
 | |
| 
 | |
|         IterationDecision decision = func(thread_info);
 | |
|         if (decision == IterationDecision::Break)
 | |
|             return;
 | |
|     }
 | |
| }
 | |
| 
 | |
| }
 |