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
Notes:
sideshowbarker
2024-07-18 23:57:45 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/2f3b901f7fe
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 {};
|
||||
|
||||
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() };
|
||||
{
|
||||
// Check if we've got it cached already.
|
||||
auto mapped_file = m_mapped_files.get(path);
|
||||
if (mapped_file.has_value())
|
||||
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
Reference in a new issue