mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 04:02:44 +00:00 
			
		
		
		
	AK: Make MappedFile heap-allocated and ref-counted
Let's adapt this class a bit better to how it's actually being used. Instead of having valid/invalid states and storing an error in case it's invalid, a MappedFile is now always valid, and the factory function that creates it will return an OSError if mapping fails.
This commit is contained in:
		
							parent
							
								
									70fce5c4c7
								
							
						
					
					
						commit
						2f3b901f7f
					
				
					 36 changed files with 184 additions and 199 deletions
				
			
		|  | @ -1,5 +1,5 @@ | |||
| /*
 | ||||
|  * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> | ||||
|  * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org> | ||||
|  * All rights reserved. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  | @ -25,6 +25,7 @@ | |||
|  */ | ||||
| 
 | ||||
| #include <AK/MappedFile.h> | ||||
| #include <AK/ScopeGuard.h> | ||||
| #include <AK/String.h> | ||||
| #include <fcntl.h> | ||||
| #include <stdio.h> | ||||
|  | @ -32,68 +33,43 @@ | |||
| #include <sys/stat.h> | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| //#define DEBUG_MAPPED_FILE
 | ||||
| 
 | ||||
| namespace AK { | ||||
| 
 | ||||
| MappedFile::MappedFile(const StringView& file_name) | ||||
| Result<NonnullRefPtr<MappedFile>, OSError> MappedFile::map(const StringView& path) | ||||
| { | ||||
|     int fd = open_with_path_length(file_name.characters_without_null_termination(), file_name.length(), O_RDONLY | O_CLOEXEC, 0); | ||||
|     int fd = open_with_path_length(path.characters_without_null_termination(), path.length(), O_RDONLY | O_CLOEXEC, 0); | ||||
|     if (fd < 0) | ||||
|         return OSError(errno); | ||||
| 
 | ||||
|     if (fd == -1) { | ||||
|         m_errno = errno; | ||||
|         perror("open"); | ||||
|         return; | ||||
|     } | ||||
|     ScopeGuard fd_close_guard = [fd] { | ||||
|         close(fd); | ||||
|     }; | ||||
| 
 | ||||
|     struct stat st; | ||||
|     fstat(fd, &st); | ||||
|     m_size = st.st_size; | ||||
|     m_map = mmap(nullptr, m_size, PROT_READ, MAP_SHARED, fd, 0); | ||||
| 
 | ||||
|     if (m_map == MAP_FAILED) { | ||||
|         m_errno = errno; | ||||
|         perror("mmap"); | ||||
|     if (fstat(fd, &st) < 0) { | ||||
|         auto saved_errno = errno; | ||||
|         return OSError(saved_errno); | ||||
|     } | ||||
| 
 | ||||
| #ifdef DEBUG_MAPPED_FILE | ||||
|     dbgln("MappedFile(\"{}\") := ( fd={}, m_size={}, m_map={} )", file_name, fd, m_size, m_map); | ||||
| #endif | ||||
|     auto size = st.st_size; | ||||
|     auto* ptr = mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0); | ||||
| 
 | ||||
|     close(fd); | ||||
|     if (ptr == MAP_FAILED) | ||||
|         return OSError(errno); | ||||
| 
 | ||||
|     return adopt(*new MappedFile(ptr, size)); | ||||
| } | ||||
| 
 | ||||
| MappedFile::MappedFile(void* ptr, size_t size) | ||||
|     : m_data(ptr) | ||||
|     , m_size(size) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| MappedFile::~MappedFile() | ||||
| { | ||||
|     unmap(); | ||||
| } | ||||
| 
 | ||||
| void MappedFile::unmap() | ||||
| { | ||||
|     if (!is_valid()) | ||||
|         return; | ||||
|     int rc = munmap(m_map, m_size); | ||||
|     auto rc = munmap(m_data, m_size); | ||||
|     ASSERT(rc == 0); | ||||
|     m_size = 0; | ||||
|     m_map = (void*)-1; | ||||
| } | ||||
| 
 | ||||
| MappedFile::MappedFile(MappedFile&& other) | ||||
|     : m_size(other.m_size) | ||||
|     , m_map(other.m_map) | ||||
| { | ||||
|     other.m_size = 0; | ||||
|     other.m_map = (void*)-1; | ||||
| } | ||||
| 
 | ||||
| MappedFile& MappedFile::operator=(MappedFile&& other) | ||||
| { | ||||
|     if (this == &other) | ||||
|         return *this; | ||||
|     unmap(); | ||||
|     swap(m_size, other.m_size); | ||||
|     swap(m_map, other.m_map); | ||||
|     return *this; | ||||
| } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -27,37 +27,33 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <AK/Noncopyable.h> | ||||
| #include <AK/StringView.h> | ||||
| #include <AK/NonnullRefPtr.h> | ||||
| #include <AK/OSError.h> | ||||
| #include <AK/RefCounted.h> | ||||
| #include <AK/Result.h> | ||||
| 
 | ||||
| namespace AK { | ||||
| 
 | ||||
| class MappedFile { | ||||
| class MappedFile : public RefCounted<MappedFile> { | ||||
|     AK_MAKE_NONCOPYABLE(MappedFile); | ||||
|     AK_MAKE_NONMOVABLE(MappedFile); | ||||
| 
 | ||||
| public: | ||||
|     MappedFile() { } | ||||
|     explicit MappedFile(const StringView& file_name); | ||||
|     MappedFile(MappedFile&&); | ||||
|     static Result<NonnullRefPtr<MappedFile>, OSError> map(const StringView& path); | ||||
|     ~MappedFile(); | ||||
| 
 | ||||
|     MappedFile& operator=(MappedFile&&); | ||||
|     void* data() { return m_data; } | ||||
|     const void* data() const { return m_data; } | ||||
| 
 | ||||
|     bool is_valid() const { return m_map != (void*)-1; } | ||||
|     int errno_if_invalid() const | ||||
|     { | ||||
|         ASSERT(!is_valid()); | ||||
|         return m_errno; | ||||
|     } | ||||
|     void unmap(); | ||||
| 
 | ||||
|     void* data() { return m_map; } | ||||
|     const void* data() const { return m_map; } | ||||
|     size_t size() const { return m_size; } | ||||
| 
 | ||||
|     ReadonlyBytes bytes() const { return { m_data, m_size }; } | ||||
| 
 | ||||
| private: | ||||
|     explicit MappedFile(void*, size_t); | ||||
| 
 | ||||
|     void* m_data { nullptr }; | ||||
|     size_t m_size { 0 }; | ||||
|     void* m_map { (void*)-1 }; | ||||
|     int m_errno { 0 }; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -79,22 +79,24 @@ String ManualModel::page_path(const GUI::ModelIndex& index) const | |||
|     return page->path(); | ||||
| } | ||||
| 
 | ||||
| Result<StringView, int> ManualModel::page_view(const String& path) const | ||||
| Result<StringView, OSError> ManualModel::page_view(const String& path) const | ||||
| { | ||||
|     if (path.is_empty()) | ||||
|         return StringView {}; | ||||
| 
 | ||||
|     { | ||||
|         // Check if we've got it cached already.
 | ||||
|         auto mapped_file = m_mapped_files.get(path); | ||||
|         if (mapped_file.has_value()) | ||||
|         return StringView { (const char*)mapped_file.value()->data(), mapped_file.value()->size() }; | ||||
|             return StringView { mapped_file.value()->bytes() }; | ||||
|     } | ||||
| 
 | ||||
|     auto map = make<MappedFile>(path); | ||||
|     if (!map->is_valid()) | ||||
|         return map->errno_if_invalid(); | ||||
| 
 | ||||
|     StringView view { (const char*)map->data(), map->size() }; | ||||
|     m_mapped_files.set(path, move(map)); | ||||
|     auto file_or_error = MappedFile::map(path); | ||||
|     if (file_or_error.is_error()) | ||||
|         return file_or_error.error(); | ||||
| 
 | ||||
|     StringView view { file_or_error.value()->bytes() }; | ||||
|     m_mapped_files.set(path, file_or_error.release_value()); | ||||
|     return view; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -45,7 +45,7 @@ public: | |||
| 
 | ||||
|     String page_path(const GUI::ModelIndex&) const; | ||||
|     String page_and_section(const GUI::ModelIndex&) const; | ||||
|     Result<StringView, int> page_view(const String& path) const; | ||||
|     Result<StringView, OSError> page_view(const String& path) const; | ||||
| 
 | ||||
|     void update_section_node_on_toggle(const GUI::ModelIndex&, const bool); | ||||
|     virtual int row_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override; | ||||
|  | @ -62,5 +62,5 @@ private: | |||
|     GUI::Icon m_section_open_icon; | ||||
|     GUI::Icon m_section_icon; | ||||
|     GUI::Icon m_page_icon; | ||||
|     mutable HashMap<String, OwnPtr<MappedFile>> m_mapped_files; | ||||
|     mutable HashMap<String, NonnullRefPtr<MappedFile>> m_mapped_files; | ||||
| }; | ||||
|  |  | |||
|  | @ -159,7 +159,7 @@ int main(int argc, char* argv[]) | |||
| 
 | ||||
|         auto source_result = model->page_view(path); | ||||
|         if (source_result.is_error()) { | ||||
|             GUI::MessageBox::show(window, strerror(source_result.error()), "Failed to open man page", GUI::MessageBox::Type::Error); | ||||
|             GUI::MessageBox::show(window, source_result.error().string(), "Failed to open man page", GUI::MessageBox::Type::Error); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -51,10 +51,10 @@ DisassemblyModel::DisassemblyModel(const Debug::DebugSession& debug_session, con | |||
|     const ELF::Image* elf = nullptr; | ||||
| 
 | ||||
|     if (containing_function.value().address_low >= 0xc0000000) { | ||||
|         auto kernel_file = make<MappedFile>("/boot/Kernel"); | ||||
|         if (!kernel_file->is_valid()) | ||||
|         auto file_or_error = MappedFile::map("/boot/Kernel"); | ||||
|         if (file_or_error.is_error()) | ||||
|             return; | ||||
|         kernel_elf = make<ELF::Image>((const u8*)kernel_file->data(), kernel_file->size()); | ||||
|         kernel_elf = make<ELF::Image>(file_or_error.value()->bytes()); | ||||
|         elf = kernel_elf.ptr(); | ||||
|     } else { | ||||
|         elf = &lib->debug_info->elf(); | ||||
|  |  | |||
|  | @ -60,9 +60,10 @@ DisassemblyModel::DisassemblyModel(Profile& profile, ProfileNode& node) | |||
|     FlatPtr base_address = 0; | ||||
|     if (m_node.address() >= 0xc0000000) { | ||||
|         if (!m_kernel_file) { | ||||
|             m_kernel_file = new MappedFile("/boot/Kernel"); | ||||
|             if (!m_kernel_file->is_valid()) | ||||
|             auto file_or_error = MappedFile::map("/boot/Kernel"); | ||||
|             if (file_or_error.is_error()) | ||||
|                 return; | ||||
|             m_kernel_file = file_or_error.release_value(); | ||||
|         } | ||||
|         kernel_elf = make<ELF::Image>((const u8*)m_kernel_file->data(), m_kernel_file->size()); | ||||
|         elf = kernel_elf.ptr(); | ||||
|  |  | |||
|  | @ -69,7 +69,7 @@ private: | |||
| 
 | ||||
|     Profile& m_profile; | ||||
|     ProfileNode& m_node; | ||||
|     OwnPtr<MappedFile> m_kernel_file; | ||||
|     RefPtr<MappedFile> m_kernel_file; | ||||
| 
 | ||||
|     Vector<InstructionData> m_instructions; | ||||
| }; | ||||
|  |  | |||
|  | @ -230,10 +230,10 @@ Result<NonnullOwnPtr<Profile>, String> Profile::load_from_perfcore_file(const St | |||
|     if (!coredump) | ||||
|         return String { "Could not open coredump" }; | ||||
| 
 | ||||
|     MappedFile kernel_elf_file("/boot/Kernel"); | ||||
|     auto file_or_error = MappedFile::map("/boot/Kernel"); | ||||
|     OwnPtr<ELF::Image> kernel_elf; | ||||
|     if (kernel_elf_file.is_valid()) | ||||
|         kernel_elf = make<ELF::Image>(static_cast<const u8*>(kernel_elf_file.data()), kernel_elf_file.size()); | ||||
|     if (!file_or_error.is_error()) | ||||
|         kernel_elf = make<ELF::Image>(file_or_error.value()->bytes()); | ||||
| 
 | ||||
|     auto events_value = object.get("events"); | ||||
|     if (!events_value.is_array()) | ||||
|  |  | |||
|  | @ -167,13 +167,14 @@ void Emulator::setup_stack(Vector<ELF::AuxiliaryValue> aux_vector) | |||
| 
 | ||||
| bool Emulator::load_elf() | ||||
| { | ||||
|     MappedFile mapped_executable(m_executable_path); | ||||
|     if (!mapped_executable.is_valid()) { | ||||
|         reportln("Unable to map {}", m_executable_path); | ||||
|     auto file_or_error = MappedFile::map(m_executable_path); | ||||
|     if (file_or_error.is_error()) { | ||||
|         reportln("Unable to map {}: {}", m_executable_path, file_or_error.error()); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     ELF::Image executable_elf((const u8*)mapped_executable.data(), mapped_executable.size()); | ||||
|     auto elf_image_data = file_or_error.value()->bytes(); | ||||
|     ELF::Image executable_elf(elf_image_data); | ||||
| 
 | ||||
|     if (!executable_elf.is_dynamic()) { | ||||
|         // FIXME: Support static objects
 | ||||
|  | @ -181,7 +182,7 @@ bool Emulator::load_elf() | |||
|     } | ||||
| 
 | ||||
|     String interpreter_path; | ||||
|     if (!ELF::validate_program_headers(*(Elf32_Ehdr*)mapped_executable.data(), mapped_executable.size(), (u8*)mapped_executable.data(), mapped_executable.size(), &interpreter_path)) { | ||||
|     if (!ELF::validate_program_headers(*(const Elf32_Ehdr*)elf_image_data.data(), elf_image_data.size(), (const u8*)elf_image_data.data(), elf_image_data.size(), &interpreter_path)) { | ||||
|         reportln("failed to validate ELF file"); | ||||
|         return false; | ||||
|     } | ||||
|  | @ -189,9 +190,10 @@ bool Emulator::load_elf() | |||
|     ASSERT(!interpreter_path.is_null()); | ||||
|     dbgln("interpreter: {}", interpreter_path); | ||||
| 
 | ||||
|     auto interpreter_file = make<MappedFile>(interpreter_path); | ||||
|     ASSERT(interpreter_file->is_valid()); | ||||
|     ELF::Image interpreter_image((const u8*)interpreter_file->data(), interpreter_file->size()); | ||||
|     auto interpreter_file_or_error = MappedFile::map(interpreter_path); | ||||
|     ASSERT(!interpreter_file_or_error.is_error()); | ||||
|     auto interpreter_image_data = interpreter_file_or_error.value()->bytes(); | ||||
|     ELF::Image interpreter_image(interpreter_image_data); | ||||
| 
 | ||||
|     constexpr FlatPtr interpreter_load_offset = 0x08000000; | ||||
|     interpreter_image.for_each_program_header([&](const ELF::Image::ProgramHeader& program_header) { | ||||
|  | @ -308,12 +310,12 @@ String Emulator::create_backtrace_line(FlatPtr address) | |||
|         lib_path = String::formatted("/usr/lib/{}", lib_path); | ||||
| 
 | ||||
|     if (!m_dynamic_library_cache.contains(lib_path)) { | ||||
|         MappedFile mapped_file { lib_path }; | ||||
|         if (!mapped_file.is_valid()) | ||||
|         auto file_or_error = MappedFile::map(lib_path); | ||||
|         if (file_or_error.is_error()) | ||||
|             return minimal; | ||||
| 
 | ||||
|         auto debug_info = make<Debug::DebugInfo>(make<ELF::Image>((const u8*)mapped_file.data(), mapped_file.size())); | ||||
|         m_dynamic_library_cache.set(lib_path, CachedELF { move(mapped_file), move(debug_info) }); | ||||
|         auto debug_info = make<Debug::DebugInfo>(make<ELF::Image>(file_or_error.value()->bytes())); | ||||
|         m_dynamic_library_cache.set(lib_path, CachedELF { file_or_error.release_value(), move(debug_info) }); | ||||
|     } | ||||
| 
 | ||||
|     auto it = m_dynamic_library_cache.find(lib_path); | ||||
|  | @ -1765,11 +1767,11 @@ int Emulator::virt$beep() | |||
| 
 | ||||
| bool Emulator::find_malloc_symbols(const MmapRegion& libc_text) | ||||
| { | ||||
|     auto mapped_file = make<MappedFile>("/usr/lib/libc.so"); | ||||
|     if (!mapped_file->is_valid()) | ||||
|         return {}; | ||||
|     auto file_or_error = MappedFile::map("/usr/lib/libc.so"); | ||||
|     if (file_or_error.is_error()) | ||||
|         return false; | ||||
| 
 | ||||
|     ELF::Image image((const u8*)mapped_file->data(), mapped_file->size()); | ||||
|     ELF::Image image(file_or_error.value()->bytes()); | ||||
|     auto malloc_symbol = image.find_demangled_function("malloc"); | ||||
|     auto free_symbol = image.find_demangled_function("free"); | ||||
|     auto realloc_symbol = image.find_demangled_function("realloc"); | ||||
|  |  | |||
|  | @ -207,7 +207,7 @@ private: | |||
|     Optional<size_t> m_loader_text_size; | ||||
| 
 | ||||
|     struct CachedELF { | ||||
|         MappedFile mapped_file; | ||||
|         NonnullRefPtr<MappedFile> mapped_file; | ||||
|         NonnullOwnPtr<Debug::DebugInfo> debug_info; | ||||
|     }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -57,11 +57,12 @@ static const ELFObjectInfo* object_info_for_region(const ELF::Core::MemoryRegion | |||
|     if (!Core::File::exists(path.characters())) | ||||
|         return nullptr; | ||||
| 
 | ||||
|     MappedFile object_file(path); | ||||
|     if (!object_file.is_valid()) | ||||
|     auto file_or_error = MappedFile::map(path); | ||||
|     if (file_or_error.is_error()) | ||||
|         return nullptr; | ||||
| 
 | ||||
|     auto info = make<ELFObjectInfo>(move(object_file), Debug::DebugInfo { make<ELF::Image>((const u8*)object_file.data(), object_file.size()) }); | ||||
|     auto image = make<ELF::Image>(file_or_error.value()->bytes()); | ||||
|     auto info = make<ELFObjectInfo>(file_or_error.release_value(), Debug::DebugInfo { move(image) }); | ||||
|     auto* info_ptr = info.ptr(); | ||||
|     s_debug_info_cache.set(path, move(info)); | ||||
|     return info_ptr; | ||||
|  |  | |||
|  | @ -33,13 +33,13 @@ | |||
| namespace CoreDump { | ||||
| 
 | ||||
| struct ELFObjectInfo { | ||||
|     ELFObjectInfo(MappedFile&& file, Debug::DebugInfo&& debug_info) | ||||
|     ELFObjectInfo(NonnullRefPtr<MappedFile> file, Debug::DebugInfo&& debug_info) | ||||
|         : file(move(file)) | ||||
|         , debug_info(move(debug_info)) | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
|     MappedFile file; | ||||
|     NonnullRefPtr<MappedFile> file; | ||||
|     Debug::DebugInfo debug_info; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -35,15 +35,15 @@ namespace CoreDump { | |||
| 
 | ||||
| OwnPtr<Reader> Reader::create(const String& path) | ||||
| { | ||||
|     auto mapped_file = make<MappedFile>(path); | ||||
|     if (!mapped_file->is_valid()) | ||||
|     auto file_or_error = MappedFile::map(path); | ||||
|     if (file_or_error.is_error()) | ||||
|         return nullptr; | ||||
|     return make<Reader>(move(mapped_file)); | ||||
|     return adopt_own(*new Reader(file_or_error.release_value())); | ||||
| } | ||||
| 
 | ||||
| Reader::Reader(OwnPtr<MappedFile>&& coredump_file) | ||||
| Reader::Reader(NonnullRefPtr<MappedFile> coredump_file) | ||||
|     : m_coredump_file(move(coredump_file)) | ||||
|     , m_coredump_image((u8*)m_coredump_file->data(), m_coredump_file->size()) | ||||
|     , m_coredump_image(m_coredump_file->bytes()) | ||||
| { | ||||
|     size_t index = 0; | ||||
|     m_coredump_image.for_each_program_header([this, &index](auto pheader) { | ||||
|  | @ -201,11 +201,11 @@ const Reader::LibraryData* Reader::library_containing(FlatPtr address) const | |||
|     } | ||||
| 
 | ||||
|     if (!cached_libs.contains(path)) { | ||||
|         auto lib_file = make<MappedFile>(path); | ||||
|         if (!lib_file->is_valid()) | ||||
|         auto file_or_error = MappedFile::map(path); | ||||
|         if (file_or_error.is_error()) | ||||
|             return {}; | ||||
|         auto image = ELF::Image((const u8*)lib_file->data(), lib_file->size()); | ||||
|         cached_libs.set(path, make<LibraryData>(name, region->region_start, move(lib_file), move(image))); | ||||
|         auto image = ELF::Image(file_or_error.value()->bytes()); | ||||
|         cached_libs.set(path, make<LibraryData>(name, region->region_start, file_or_error.release_value(), move(image))); | ||||
|     } | ||||
| 
 | ||||
|     auto lib_data = cached_libs.get(path).value(); | ||||
|  |  | |||
|  | @ -38,13 +38,12 @@ namespace CoreDump { | |||
| 
 | ||||
| class Reader { | ||||
|     AK_MAKE_NONCOPYABLE(Reader); | ||||
|     AK_MAKE_NONMOVABLE(Reader); | ||||
| 
 | ||||
| public: | ||||
|     static OwnPtr<Reader> create(const String&); | ||||
|     ~Reader(); | ||||
| 
 | ||||
|     Reader(OwnPtr<MappedFile>&&); | ||||
| 
 | ||||
|     const ELF::Core::ProcessInfo& process_info() const; | ||||
| 
 | ||||
|     template<typename Func> | ||||
|  | @ -61,7 +60,7 @@ public: | |||
|     struct LibraryData { | ||||
|         String name; | ||||
|         FlatPtr base_address { 0 }; | ||||
|         OwnPtr<MappedFile> file; | ||||
|         NonnullRefPtr<MappedFile> file; | ||||
|         ELF::Image lib_elf; | ||||
|     }; | ||||
|     const LibraryData* library_containing(FlatPtr address) const; | ||||
|  | @ -70,6 +69,8 @@ public: | |||
|     const HashMap<String, String> metadata() const; | ||||
| 
 | ||||
| private: | ||||
|     Reader(NonnullRefPtr<MappedFile>); | ||||
| 
 | ||||
|     class NotesEntryIterator { | ||||
|     public: | ||||
|         NotesEntryIterator(const u8* notes_data); | ||||
|  | @ -85,7 +86,7 @@ private: | |||
|         const u8* start { nullptr }; | ||||
|     }; | ||||
| 
 | ||||
|     OwnPtr<MappedFile> m_coredump_file; | ||||
|     NonnullRefPtr<MappedFile> m_coredump_file; | ||||
|     ELF::Image m_coredump_image; | ||||
|     ssize_t m_notes_segment_index { -1 }; | ||||
| }; | ||||
|  |  | |||
|  | @ -42,13 +42,6 @@ DebugSession::DebugSession(pid_t pid, String source_root) | |||
| { | ||||
| } | ||||
| 
 | ||||
| MappedFile DebugSession::map_executable_for_process(pid_t pid) | ||||
| { | ||||
|     MappedFile executable(String::formatted("/proc/{}/exe", pid)); | ||||
|     ASSERT(executable.is_valid()); | ||||
|     return executable; | ||||
| } | ||||
| 
 | ||||
| DebugSession::~DebugSession() | ||||
| { | ||||
|     if (m_is_debuggee_dead) | ||||
|  | @ -373,13 +366,13 @@ void DebugSession::update_loaded_libs() | |||
|         if (m_loaded_libraries.contains(lib_name)) | ||||
|             return IterationDecision::Continue; | ||||
| 
 | ||||
|         MappedFile lib_file(object_path.value()); | ||||
|         if (!lib_file.is_valid()) | ||||
|         auto file_or_error = MappedFile ::map(object_path.value()); | ||||
|         if (file_or_error.is_error()) | ||||
|             return IterationDecision::Continue; | ||||
| 
 | ||||
|         FlatPtr base_address = entry.as_object().get("address").as_u32(); | ||||
|         auto debug_info = make<DebugInfo>(make<ELF::Image>(reinterpret_cast<const u8*>(lib_file.data()), lib_file.size()), m_source_root, base_address); | ||||
|         auto lib = make<LoadedLibrary>(lib_name, move(lib_file), move(debug_info), base_address); | ||||
|         auto debug_info = make<DebugInfo>(make<ELF::Image>(file_or_error.value()->bytes()), m_source_root, base_address); | ||||
|         auto lib = make<LoadedLibrary>(lib_name, file_or_error.release_value(), move(debug_info), base_address); | ||||
|         m_loaded_libraries.set(lib_name, move(lib)); | ||||
| 
 | ||||
|         return IterationDecision::Continue; | ||||
|  |  | |||
|  | @ -134,11 +134,11 @@ public: | |||
| 
 | ||||
|     struct LoadedLibrary { | ||||
|         String name; | ||||
|         MappedFile file; | ||||
|         NonnullRefPtr<MappedFile> file; | ||||
|         NonnullOwnPtr<DebugInfo> debug_info; | ||||
|         FlatPtr base_address; | ||||
| 
 | ||||
|         LoadedLibrary(const String& name, MappedFile&& file, NonnullOwnPtr<DebugInfo>&& debug_info, FlatPtr base_address) | ||||
|         LoadedLibrary(const String& name, NonnullRefPtr<MappedFile> file, NonnullOwnPtr<DebugInfo>&& debug_info, FlatPtr base_address) | ||||
|             : name(name) | ||||
|             , file(move(file)) | ||||
|             , debug_info(move(debug_info)) | ||||
|  | @ -175,8 +175,6 @@ private: | |||
|     // x86 breakpoint instruction "int3"
 | ||||
|     static constexpr u8 BREAKPOINT_INSTRUCTION = 0xcc; | ||||
| 
 | ||||
|     static MappedFile map_executable_for_process(pid_t); | ||||
| 
 | ||||
|     void update_loaded_libs(); | ||||
| 
 | ||||
|     int m_debuggee_pid { -1 }; | ||||
|  |  | |||
|  | @ -36,14 +36,19 @@ | |||
| 
 | ||||
| namespace ELF { | ||||
| 
 | ||||
| Image::Image(const u8* buffer, size_t size, bool verbose_logging) | ||||
|     : m_buffer(buffer) | ||||
|     , m_size(size) | ||||
| Image::Image(ReadonlyBytes bytes, bool verbose_logging) | ||||
|     : m_buffer(bytes.data()) | ||||
|     , m_size(bytes.size()) | ||||
|     , m_verbose_logging(verbose_logging) | ||||
| { | ||||
|     parse(); | ||||
| } | ||||
| 
 | ||||
| Image::Image(const u8* buffer, size_t size, bool verbose_logging) | ||||
|     : Image(ReadonlyBytes { buffer, size }, verbose_logging) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| Image::~Image() | ||||
| { | ||||
| } | ||||
|  |  | |||
|  | @ -37,7 +37,9 @@ namespace ELF { | |||
| 
 | ||||
| class Image { | ||||
| public: | ||||
|     explicit Image(ReadonlyBytes, bool verbose_logging = true); | ||||
|     explicit Image(const u8*, size_t, bool verbose_logging = true); | ||||
| 
 | ||||
|     ~Image(); | ||||
|     void dump() const; | ||||
|     bool is_valid() const { return m_valid; } | ||||
|  |  | |||
|  | @ -150,12 +150,14 @@ Icon FileIconProvider::icon_for_executable(const String& path) | |||
|     // If the icon for an app isn't in the cache we attempt to load the file as an ELF image and extract
 | ||||
|     // the serenity_app_icon_* sections which should contain the icons as raw PNG data. In the future it would
 | ||||
|     // be better if the binary signalled the image format being used or we deduced it, e.g. using magic bytes.
 | ||||
|     auto mapped_file = make<MappedFile>(path); | ||||
|     if (!mapped_file->is_valid()) { | ||||
|     auto file_or_error = MappedFile::map(path); | ||||
|     if (file_or_error.is_error()) { | ||||
|         app_icon_cache.set(path, s_executable_icon); | ||||
|         return s_executable_icon; | ||||
|     } | ||||
| 
 | ||||
|     auto& mapped_file = file_or_error.value(); | ||||
| 
 | ||||
|     if (mapped_file->size() < SELFMAG) { | ||||
|         app_icon_cache.set(path, s_executable_icon); | ||||
|         return s_executable_icon; | ||||
|  |  | |||
|  | @ -92,10 +92,11 @@ void ImageWidget::animate() | |||
| 
 | ||||
| void ImageWidget::load_from_file(const StringView& path) | ||||
| { | ||||
|     MappedFile mapped_file(path); | ||||
|     if (!mapped_file.is_valid()) | ||||
|     auto file_or_error = MappedFile::map(path); | ||||
|     if (file_or_error.is_error()) | ||||
|         return; | ||||
| 
 | ||||
|     auto& mapped_file = *file_or_error.value(); | ||||
|     m_image_decoder = Gfx::ImageDecoder::create((const u8*)mapped_file.data(), mapped_file.size()); | ||||
|     auto bitmap = m_image_decoder->bitmap(); | ||||
|     ASSERT(bitmap); | ||||
|  |  | |||
|  | @ -179,10 +179,10 @@ static RefPtr<Bitmap> load_bmp_impl(const u8*, size_t); | |||
| 
 | ||||
| RefPtr<Gfx::Bitmap> load_bmp(const StringView& path) | ||||
| { | ||||
|     MappedFile mapped_file(path); | ||||
|     if (!mapped_file.is_valid()) | ||||
|     auto file_or_error = MappedFile::map(path); | ||||
|     if (file_or_error.is_error()) | ||||
|         return nullptr; | ||||
|     auto bitmap = load_bmp_impl((const u8*)mapped_file.data(), mapped_file.size()); | ||||
|     auto bitmap = load_bmp_impl((const u8*)file_or_error.value()->data(), file_or_error.value()->size()); | ||||
|     if (bitmap) | ||||
|         bitmap->set_mmap_name(String::formatted("Gfx::Bitmap [{}] - Decoded BMP: {}", bitmap->size(), LexicalPath::canonicalized_path(path))); | ||||
|     return bitmap; | ||||
|  |  | |||
|  | @ -27,7 +27,6 @@ | |||
| #include "BitmapFont.h" | ||||
| #include "Bitmap.h" | ||||
| #include "Emoji.h" | ||||
| #include <AK/MappedFile.h> | ||||
| #include <AK/StdLibExtras.h> | ||||
| #include <AK/StringBuilder.h> | ||||
| #include <AK/Utf32View.h> | ||||
|  | @ -174,15 +173,15 @@ size_t BitmapFont::glyph_count_by_type(FontTypes type) | |||
| 
 | ||||
| RefPtr<BitmapFont> BitmapFont::load_from_file(const StringView& path) | ||||
| { | ||||
|     MappedFile mapped_file(path); | ||||
|     if (!mapped_file.is_valid()) | ||||
|     auto file_or_error = MappedFile::map(path); | ||||
|     if (file_or_error.is_error()) | ||||
|         return nullptr; | ||||
| 
 | ||||
|     auto font = load_from_memory((const u8*)mapped_file.data()); | ||||
|     auto font = load_from_memory((const u8*)file_or_error.value()->data()); | ||||
|     if (!font) | ||||
|         return nullptr; | ||||
| 
 | ||||
|     font->m_mapped_file = move(mapped_file); | ||||
|     font->m_mapped_file = file_or_error.release_value(); | ||||
|     return font; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -128,7 +128,7 @@ private: | |||
| 
 | ||||
|     unsigned* m_rows { nullptr }; | ||||
|     u8* m_glyph_widths { nullptr }; | ||||
|     MappedFile m_mapped_file; | ||||
|     RefPtr<MappedFile> m_mapped_file; | ||||
| 
 | ||||
|     u8 m_glyph_width { 0 }; | ||||
|     u8 m_glyph_height { 0 }; | ||||
|  |  | |||
|  | @ -107,10 +107,10 @@ struct GIFLoadingContext { | |||
| 
 | ||||
| RefPtr<Gfx::Bitmap> load_gif(const StringView& path) | ||||
| { | ||||
|     MappedFile mapped_file(path); | ||||
|     if (!mapped_file.is_valid()) | ||||
|     auto file_or_error = MappedFile::map(path); | ||||
|     if (file_or_error.is_error()) | ||||
|         return nullptr; | ||||
|     GIFImageDecoderPlugin gif_decoder((const u8*)mapped_file.data(), mapped_file.size()); | ||||
|     GIFImageDecoderPlugin gif_decoder((const u8*)file_or_error.value()->data(), file_or_error.value()->size()); | ||||
|     auto bitmap = gif_decoder.bitmap(); | ||||
|     if (bitmap) | ||||
|         bitmap->set_mmap_name(String::formatted("Gfx::Bitmap [{}] - Decoded GIF: {}", bitmap->size(), LexicalPath::canonicalized_path(path))); | ||||
|  |  | |||
|  | @ -116,10 +116,10 @@ struct ICOLoadingContext { | |||
| 
 | ||||
| RefPtr<Gfx::Bitmap> load_ico(const StringView& path) | ||||
| { | ||||
|     MappedFile mapped_file(path); | ||||
|     if (!mapped_file.is_valid()) | ||||
|     auto file_or_error = MappedFile::map(path); | ||||
|     if (file_or_error.is_error()) | ||||
|         return nullptr; | ||||
|     ICOImageDecoderPlugin decoder((const u8*)mapped_file.data(), mapped_file.size()); | ||||
|     ICOImageDecoderPlugin decoder((const u8*)file_or_error.value()->data(), file_or_error.value()->size()); | ||||
|     auto bitmap = decoder.bitmap(); | ||||
|     if (bitmap) | ||||
|         bitmap->set_mmap_name(String::formatted("Gfx::Bitmap [{}] - Decoded ICO: {}", bitmap->size(), LexicalPath::canonicalized_path(path))); | ||||
|  |  | |||
|  | @ -1320,12 +1320,10 @@ static RefPtr<Gfx::Bitmap> load_jpg_impl(const u8* data, size_t data_size) | |||
| 
 | ||||
| RefPtr<Gfx::Bitmap> load_jpg(const StringView& path) | ||||
| { | ||||
|     MappedFile mapped_file(path); | ||||
|     if (!mapped_file.is_valid()) { | ||||
|     auto file_or_error = MappedFile::map(path); | ||||
|     if (file_or_error.is_error()) | ||||
|         return nullptr; | ||||
|     } | ||||
| 
 | ||||
|     auto bitmap = load_jpg_impl((const u8*)mapped_file.data(), mapped_file.size()); | ||||
|     auto bitmap = load_jpg_impl((const u8*)file_or_error.value()->data(), file_or_error.value()->size()); | ||||
|     if (bitmap) | ||||
|         bitmap->set_mmap_name(String::formatted("Gfx::Bitmap [{}] - Decoded JPG: {}", bitmap->size(), LexicalPath::canonicalized_path(path))); | ||||
|     return bitmap; | ||||
|  |  | |||
|  | @ -193,10 +193,10 @@ static bool process_chunk(Streamer&, PNGLoadingContext& context); | |||
| 
 | ||||
| RefPtr<Gfx::Bitmap> load_png(const StringView& path) | ||||
| { | ||||
|     MappedFile mapped_file(path); | ||||
|     if (!mapped_file.is_valid()) | ||||
|     auto file_or_error = MappedFile::map(path); | ||||
|     if (file_or_error.is_error()) | ||||
|         return nullptr; | ||||
|     auto bitmap = load_png_impl((const u8*)mapped_file.data(), mapped_file.size()); | ||||
|     auto bitmap = load_png_impl((const u8*)file_or_error.value()->data(), file_or_error.value()->size()); | ||||
|     if (bitmap) | ||||
|         bitmap->set_mmap_name(String::formatted("Gfx::Bitmap [{}] - Decoded PNG: {}", bitmap->size(), LexicalPath::canonicalized_path(path))); | ||||
|     return bitmap; | ||||
|  |  | |||
|  | @ -294,12 +294,10 @@ static RefPtr<Gfx::Bitmap> load_impl(const u8* data, size_t data_size) | |||
| template<typename TContext> | ||||
| static RefPtr<Gfx::Bitmap> load(const StringView& path) | ||||
| { | ||||
|     MappedFile mapped_file(path); | ||||
|     if (!mapped_file.is_valid()) { | ||||
|     auto file_or_error = MappedFile::map(path); | ||||
|     if (file_or_error.is_error()) | ||||
|         return nullptr; | ||||
|     } | ||||
| 
 | ||||
|     auto bitmap = load_impl<TContext>((const u8*)mapped_file.data(), mapped_file.size()); | ||||
|     auto bitmap = load_impl<TContext>((const u8*)file_or_error.value()->data(), file_or_error.value()->size()); | ||||
|     if (bitmap) | ||||
|         bitmap->set_mmap_name(String::formatted("Gfx::Bitmap [{}] - Decoded {}: {}", | ||||
|             bitmap->size(), | ||||
|  |  | |||
|  | @ -34,7 +34,10 @@ namespace PCIDB { | |||
| 
 | ||||
| RefPtr<Database> Database::open(const StringView& file_name) | ||||
| { | ||||
|     auto res = adopt(*new Database(file_name)); | ||||
|     auto file_or_error = MappedFile::map(file_name); | ||||
|     if (file_or_error.is_error()) | ||||
|         return nullptr; | ||||
|     auto res = adopt(*new Database(file_or_error.release_value())); | ||||
|     if (res->init() != 0) | ||||
|         return nullptr; | ||||
|     return res; | ||||
|  | @ -131,10 +134,7 @@ int Database::init() | |||
|     if (m_ready) | ||||
|         return 0; | ||||
| 
 | ||||
|     if (!m_file.is_valid()) | ||||
|         return -1; | ||||
| 
 | ||||
|     m_view = StringView((const char*)m_file.data(), m_file.size()); | ||||
|     m_view = StringView { m_file->bytes() }; | ||||
| 
 | ||||
|     ParseMode mode = ParseMode::UnknownMode; | ||||
| 
 | ||||
|  |  | |||
|  | @ -83,8 +83,10 @@ public: | |||
|     const StringView get_programming_interface(u8 class_id, u8 subclass_id, u8 programming_interface_id) const; | ||||
| 
 | ||||
| private: | ||||
|     Database(const StringView& file_name) | ||||
|         : m_file(file_name) {}; | ||||
|     explicit Database(NonnullRefPtr<MappedFile> file) | ||||
|         : m_file(move(file)) | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
|     int init(); | ||||
| 
 | ||||
|  | @ -94,7 +96,7 @@ private: | |||
|         ClassMode, | ||||
|     }; | ||||
| 
 | ||||
|     MappedFile m_file {}; | ||||
|     NonnullRefPtr<MappedFile> m_file; | ||||
|     StringView m_view {}; | ||||
|     HashMap<int, NonnullOwnPtr<Vendor>> m_vendors; | ||||
|     HashMap<int, NonnullOwnPtr<Class>> m_classes; | ||||
|  |  | |||
|  | @ -162,8 +162,9 @@ static String folder_image_data() | |||
| { | ||||
|     static String cache; | ||||
|     if (cache.is_empty()) { | ||||
|         MappedFile image("/res/icons/16x16/filetype-folder.png"); | ||||
|         cache = encode_base64({ image.data(), image.size() }); | ||||
|         auto file_or_error = MappedFile::map("/res/icons/16x16/filetype-folder.png"); | ||||
|         ASSERT(!file_or_error.is_error()); | ||||
|         cache = encode_base64(file_or_error.value()->bytes()); | ||||
|     } | ||||
|     return cache; | ||||
| } | ||||
|  | @ -172,8 +173,9 @@ static String file_image_data() | |||
| { | ||||
|     static String cache; | ||||
|     if (cache.is_empty()) { | ||||
|         MappedFile image("/res/icons/16x16/filetype-unknown.png"); | ||||
|         cache = encode_base64({ image.data(), image.size() }); | ||||
|         auto file_or_error = MappedFile::map("/res/icons/16x16/filetype-unknown.png"); | ||||
|         ASSERT(!file_or_error.is_error()); | ||||
|         cache = encode_base64(file_or_error.value()->bytes()); | ||||
|     } | ||||
|     return cache; | ||||
| } | ||||
|  |  | |||
|  | @ -48,12 +48,14 @@ int main(int argc, char** argv) | |||
|     args_parser.add_positional_argument(path, "Path to i386 binary file", "path"); | ||||
|     args_parser.parse(argc, argv); | ||||
| 
 | ||||
|     MappedFile file(path); | ||||
|     if (!file.is_valid()) { | ||||
|         // Already printed some error message.
 | ||||
|     auto file_or_error = MappedFile::map(path); | ||||
|     if (file_or_error.is_error()) { | ||||
|         warnln("Could not map file: {}", file_or_error.error().string()); | ||||
|         return 1; | ||||
|     } | ||||
| 
 | ||||
|     auto& file = *file_or_error.value(); | ||||
| 
 | ||||
|     struct Symbol { | ||||
|         size_t value; | ||||
|         size_t size; | ||||
|  |  | |||
|  | @ -90,7 +90,7 @@ static NonnullOwnPtr<HashMap<void*, X86::Instruction>> instrument_code() | |||
|             if (section.name() != ".text") | ||||
|                 return IterationDecision::Continue; | ||||
| 
 | ||||
|             X86::SimpleInstructionStream stream((const u8*)((u32)lib.file.data() + section.offset()), section.size()); | ||||
|             X86::SimpleInstructionStream stream((const u8*)((u32)lib.file->data() + section.offset()), section.size()); | ||||
|             X86::Disassembler disassembler(stream); | ||||
|             for (;;) { | ||||
|                 auto offset = stream.offset(); | ||||
|  |  | |||
|  | @ -284,14 +284,15 @@ int main(int argc, char** argv) | |||
|         display_symbol_table = true; | ||||
|     } | ||||
| 
 | ||||
|     MappedFile mapped_executable(path); | ||||
|     auto file_or_error = MappedFile::map(path); | ||||
| 
 | ||||
|     if (!mapped_executable.is_valid()) { | ||||
|         fprintf(stderr, "Unable to map file %s\n", path); | ||||
|     if (file_or_error.is_error()) { | ||||
|         warnln("Unable to map file {}: {}", path, file_or_error.error()); | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     ELF::Image executable_elf((const u8*)mapped_executable.data(), mapped_executable.size()); | ||||
|     auto elf_image_data = file_or_error.value()->bytes(); | ||||
|     ELF::Image executable_elf(elf_image_data); | ||||
| 
 | ||||
|     if (!executable_elf.is_valid()) { | ||||
|         fprintf(stderr, "File is not a valid ELF object\n"); | ||||
|  | @ -300,7 +301,7 @@ int main(int argc, char** argv) | |||
| 
 | ||||
|     String interpreter_path; | ||||
| 
 | ||||
|     if (!ELF::validate_program_headers(*(Elf32_Ehdr*)mapped_executable.data(), mapped_executable.size(), (u8*)mapped_executable.data(), mapped_executable.size(), &interpreter_path)) { | ||||
|     if (!ELF::validate_program_headers(*(const Elf32_Ehdr*)elf_image_data.data(), elf_image_data.size(), (const u8*)elf_image_data.data(), elf_image_data.size(), &interpreter_path)) { | ||||
|         fprintf(stderr, "Invalid ELF headers\n"); | ||||
|         return -1; | ||||
|     } | ||||
|  | @ -309,14 +310,14 @@ int main(int argc, char** argv) | |||
|         fprintf(stderr, "Warning: Dynamic ELF object has no interpreter path\n"); | ||||
|     } | ||||
| 
 | ||||
|     ELF::Image interpreter_image((const u8*)mapped_executable.data(), mapped_executable.size()); | ||||
|     ELF::Image interpreter_image(elf_image_data); | ||||
| 
 | ||||
|     if (!interpreter_image.is_valid()) { | ||||
|         fprintf(stderr, "ELF image is invalid\n"); | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     auto header = *reinterpret_cast<const Elf32_Ehdr*>(mapped_executable.data()); | ||||
|     auto& header = *reinterpret_cast<const Elf32_Ehdr*>(elf_image_data.data()); | ||||
| 
 | ||||
|     if (display_elf_header) { | ||||
|         printf("ELF header:\n"); | ||||
|  |  | |||
|  | @ -181,9 +181,12 @@ int main(int argc, char** argv) | |||
|         return 1; | ||||
|     } | ||||
| 
 | ||||
|     MappedFile mapped_file { zip_file_path }; | ||||
|     if (!mapped_file.is_valid()) | ||||
|     auto file_or_error = MappedFile ::map(zip_file_path); | ||||
|     if (file_or_error.is_error()) { | ||||
|         warnln("Failed to open {}: {}", zip_file_path, file_or_error.error()); | ||||
|         return 1; | ||||
|     } | ||||
|     auto& mapped_file = *file_or_error.value(); | ||||
| 
 | ||||
|     printf("Archive: %s\n", zip_file_path.characters()); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling