From 0732786ddc8837bd50b6d27b7ec83d7d5806ee37 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sun, 14 Oct 2018 20:24:15 -0400 Subject: [PATCH 1/3] nro: Make LoadNro take a VfsFile by const reference This function doesn't need to care about ownership semantics, so we can just pass it a reference to the file itself, rather than a std::shared_ptr alias. --- src/core/loader/nro.cpp | 10 +++++----- src/core/loader/nro.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 576fe692a9..243b499f2c 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -127,10 +127,10 @@ static constexpr u32 PageAlignSize(u32 size) { return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; } -bool AppLoader_NRO::LoadNro(FileSys::VirtualFile file, VAddr load_base) { +bool AppLoader_NRO::LoadNro(const FileSys::VfsFile& file, VAddr load_base) { // Read NSO header NroHeader nro_header{}; - if (sizeof(NroHeader) != file->ReadObject(&nro_header)) { + if (sizeof(NroHeader) != file.ReadObject(&nro_header)) { return {}; } if (nro_header.magic != Common::MakeMagic('N', 'R', 'O', '0')) { @@ -138,7 +138,7 @@ bool AppLoader_NRO::LoadNro(FileSys::VirtualFile file, VAddr load_base) { } // Build program image - std::vector program_image = file->ReadBytes(PageAlignSize(nro_header.file_size)); + std::vector program_image = file.ReadBytes(PageAlignSize(nro_header.file_size)); if (program_image.size() != PageAlignSize(nro_header.file_size)) { return {}; } @@ -182,7 +182,7 @@ bool AppLoader_NRO::LoadNro(FileSys::VirtualFile file, VAddr load_base) { Core::CurrentProcess()->LoadModule(std::move(codeset), load_base); // Register module with GDBStub - GDBStub::RegisterModule(file->GetName(), load_base, load_base); + GDBStub::RegisterModule(file.GetName(), load_base, load_base); return true; } @@ -195,7 +195,7 @@ ResultStatus AppLoader_NRO::Load(Kernel::Process& process) { // Load NRO const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); - if (!LoadNro(file, base_address)) { + if (!LoadNro(*file, base_address)) { return ResultStatus::ErrorLoadingNRO; } diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h index 04b46119ad..50ee5a78a8 100644 --- a/src/core/loader/nro.h +++ b/src/core/loader/nro.h @@ -41,7 +41,7 @@ public: bool IsRomFSUpdatable() const override; private: - bool LoadNro(FileSys::VirtualFile file, VAddr load_base); + bool LoadNro(const FileSys::VfsFile& file, VAddr load_base); std::vector icon_data; std::unique_ptr nacp; From bb9cf8a127baf83aa3ebdef5b17d9bdd69869b4a Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sun, 14 Oct 2018 20:36:57 -0400 Subject: [PATCH 2/3] nso: Make LoadModule take a VfsFile by const reference --- src/core/loader/deconstructed_rom_directory.cpp | 2 +- src/core/loader/nso.cpp | 15 ++++++--------- src/core/loader/nso.h | 3 ++- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 951fd8257c..5a8bb4675b 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -141,7 +141,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process) const FileSys::VirtualFile module_file = dir->GetFile(module); if (module_file != nullptr) { const VAddr load_addr = next_load_addr; - next_load_addr = AppLoader_NSO::LoadModule(module_file, load_addr, + next_load_addr = AppLoader_NSO::LoadModule(*module_file, load_addr, std::strcmp(module, "rtld") == 0, pm); LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); // Register module with GDBStub diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index ba57db9bf6..d26fa482c7 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -93,17 +93,14 @@ static constexpr u32 PageAlignSize(u32 size) { return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; } -VAddr AppLoader_NSO::LoadModule(FileSys::VirtualFile file, VAddr load_base, +VAddr AppLoader_NSO::LoadModule(const FileSys::VfsFile& file, VAddr load_base, bool should_pass_arguments, boost::optional pm) { - if (file == nullptr) - return {}; - - if (file->GetSize() < sizeof(NsoHeader)) + if (file.GetSize() < sizeof(NsoHeader)) return {}; NsoHeader nso_header{}; - if (sizeof(NsoHeader) != file->ReadObject(&nso_header)) + if (sizeof(NsoHeader) != file.ReadObject(&nso_header)) return {}; if (nso_header.magic != Common::MakeMagic('N', 'S', 'O', '0')) @@ -114,7 +111,7 @@ VAddr AppLoader_NSO::LoadModule(FileSys::VirtualFile file, VAddr load_base, std::vector program_image; for (std::size_t i = 0; i < nso_header.segments.size(); ++i) { std::vector data = - file->ReadBytes(nso_header.segments_compressed_size[i], nso_header.segments[i].offset); + file.ReadBytes(nso_header.segments_compressed_size[i], nso_header.segments[i].offset); if (nso_header.IsSegmentCompressed(i)) { data = DecompressSegment(data, nso_header.segments[i]); } @@ -172,7 +169,7 @@ VAddr AppLoader_NSO::LoadModule(FileSys::VirtualFile file, VAddr load_base, Core::CurrentProcess()->LoadModule(std::move(codeset), load_base); // Register module with GDBStub - GDBStub::RegisterModule(file->GetName(), load_base, load_base); + GDBStub::RegisterModule(file.GetName(), load_base, load_base); return load_base + image_size; } @@ -184,7 +181,7 @@ ResultStatus AppLoader_NSO::Load(Kernel::Process& process) { // Load module const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); - LoadModule(file, base_address, true); + LoadModule(*file, base_address, true); LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address); process.Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h index 70ab3b718b..d928971306 100644 --- a/src/core/loader/nso.h +++ b/src/core/loader/nso.h @@ -36,7 +36,8 @@ public: return IdentifyType(file); } - static VAddr LoadModule(FileSys::VirtualFile file, VAddr load_base, bool should_pass_arguments, + static VAddr LoadModule(const FileSys::VfsFile& file, VAddr load_base, + bool should_pass_arguments, boost::optional pm = boost::none); ResultStatus Load(Kernel::Process& process) override; From bed872ed38e19d34c6c2e3d1a3d35a9f72e46970 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sun, 14 Oct 2018 21:41:58 -0400 Subject: [PATCH 3/3] nso: Return an optional address from LoadModule If a malformed NSO is attempted to be loaded, we shouldn't continue onwards. We should be reporting an error and bailing out. --- .../loader/deconstructed_rom_directory.cpp | 22 +++++++++++++------ src/core/loader/loader.cpp | 3 ++- src/core/loader/loader.h | 1 + src/core/loader/nso.cpp | 12 +++++----- src/core/loader/nso.h | 7 +++--- 5 files changed, 29 insertions(+), 16 deletions(-) diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 5a8bb4675b..8518dddcbb 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -139,14 +139,22 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process) for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) { const FileSys::VirtualFile module_file = dir->GetFile(module); - if (module_file != nullptr) { - const VAddr load_addr = next_load_addr; - next_load_addr = AppLoader_NSO::LoadModule(*module_file, load_addr, - std::strcmp(module, "rtld") == 0, pm); - LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); - // Register module with GDBStub - GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false); + if (module_file == nullptr) { + continue; } + + const VAddr load_addr = next_load_addr; + const bool should_pass_arguments = std::strcmp(module, "rtld") == 0; + const auto tentative_next_load_addr = + AppLoader_NSO::LoadModule(*module_file, load_addr, should_pass_arguments, pm); + if (!tentative_next_load_addr) { + return ResultStatus::ErrorLoadingNSO; + } + + next_load_addr = *tentative_next_load_addr; + LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); + // Register module with GDBStub + GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false); } process.Run(base_address, metadata.GetMainThreadPriority(), metadata.GetMainThreadStackSize()); diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 91659ec176..9cd0b0ccd0 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -93,7 +93,7 @@ std::string GetFileTypeString(FileType type) { return "unknown"; } -constexpr std::array RESULT_MESSAGES{ +constexpr std::array RESULT_MESSAGES{ "The operation completed successfully.", "The loader requested to load is already loaded.", "The operation is not implemented.", @@ -128,6 +128,7 @@ constexpr std::array RESULT_MESSAGES{ "The RomFS could not be found.", "The ELF file has incorrect size as determined by the header.", "There was a general error loading the NRO into emulated memory.", + "There was a general error loading the NSO into emulated memory.", "There is no icon available.", "There is no control data available.", "The NAX file has a bad header.", diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index 0e0333db56..e562b3a045 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -90,6 +90,7 @@ enum class ResultStatus : u16 { ErrorNoRomFS, ErrorIncorrectELFFileSize, ErrorLoadingNRO, + ErrorLoadingNSO, ErrorNoIcon, ErrorNoControl, ErrorBadNAXHeader, diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index d26fa482c7..68efca5c0d 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -93,9 +93,9 @@ static constexpr u32 PageAlignSize(u32 size) { return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; } -VAddr AppLoader_NSO::LoadModule(const FileSys::VfsFile& file, VAddr load_base, - bool should_pass_arguments, - boost::optional pm) { +std::optional AppLoader_NSO::LoadModule(const FileSys::VfsFile& file, VAddr load_base, + bool should_pass_arguments, + std::optional pm) { if (file.GetSize() < sizeof(NsoHeader)) return {}; @@ -154,7 +154,7 @@ VAddr AppLoader_NSO::LoadModule(const FileSys::VfsFile& file, VAddr load_base, program_image.resize(image_size); // Apply patches if necessary - if (pm != boost::none && pm->HasNSOPatch(nso_header.build_id)) { + if (pm && pm->HasNSOPatch(nso_header.build_id)) { std::vector pi_header(program_image.size() + 0x100); std::memcpy(pi_header.data(), &nso_header, sizeof(NsoHeader)); std::memcpy(pi_header.data() + 0x100, program_image.data(), program_image.size()); @@ -181,7 +181,9 @@ ResultStatus AppLoader_NSO::Load(Kernel::Process& process) { // Load module const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); - LoadModule(*file, base_address, true); + if (!LoadModule(*file, base_address, true)) { + return ResultStatus::ErrorLoadingNSO; + } LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address); process.Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h index d928971306..4333061390 100644 --- a/src/core/loader/nso.h +++ b/src/core/loader/nso.h @@ -4,6 +4,7 @@ #pragma once +#include #include "common/common_types.h" #include "core/file_sys/patch_manager.h" #include "core/loader/linker.h" @@ -36,9 +37,9 @@ public: return IdentifyType(file); } - static VAddr LoadModule(const FileSys::VfsFile& file, VAddr load_base, - bool should_pass_arguments, - boost::optional pm = boost::none); + static std::optional LoadModule(const FileSys::VfsFile& file, VAddr load_base, + bool should_pass_arguments, + std::optional pm = {}); ResultStatus Load(Kernel::Process& process) override; };