From 2179ad7483bde3c210bf4f638ae8801b3ba11214 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 17 May 2019 21:41:33 -0400 Subject: core: Track load offsets of NSO modules Needed for backtrace decomposition --- src/core/core.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/core/core.h') diff --git a/src/core/core.h b/src/core/core.h index a9a756a4c..10542ba21 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -8,6 +8,7 @@ #include #include +#include #include "common/common_types.h" #include "core/file_sys/vfs_types.h" #include "core/hle/kernel/object.h" @@ -285,6 +286,10 @@ public: void ClearContentProvider(FileSys::ContentProviderUnionSlot slot); + void RegisterNSOModule(std::string name, VAddr start_address); + + const std::map>& GetRegisteredNSOModules() const; + private: System(); -- cgit v1.2.3 From 2dde8f5cfe81648d05d60285ab5b17a6f61c486e Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 17 May 2019 21:45:56 -0400 Subject: core: Add Reporter class to take/save reports --- src/core/CMakeLists.txt | 4 +- src/core/core.cpp | 6 + src/core/core.h | 3 + src/core/reporter.cpp | 351 ++++++++++++++++++++++++++++++++++++++++++++++++ src/core/reporter.h | 53 ++++++++ 5 files changed, 416 insertions(+), 1 deletion(-) create mode 100644 src/core/reporter.cpp create mode 100644 src/core/reporter.h (limited to 'src/core/core.h') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 2ace866ee..3eacb11b4 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -452,6 +452,8 @@ add_library(core STATIC memory_setup.h perf_stats.cpp perf_stats.h + reporter.cpp + reporter.h settings.cpp settings.h telemetry_session.cpp @@ -464,7 +466,7 @@ add_library(core STATIC create_target_directory_groups(core) target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) -target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt mbedtls opus unicorn open_source_archives) +target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt json-headers mbedtls opus unicorn open_source_archives) if (ENABLE_WEB_SERVICE) target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE) target_link_libraries(core PRIVATE web_service) diff --git a/src/core/core.cpp b/src/core/core.cpp index 96ba6a569..db4c067df 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -34,6 +34,7 @@ #include "core/hle/service/sm/sm.h" #include "core/loader/loader.h" #include "core/perf_stats.h" +#include "core/reporter.h" #include "core/settings.h" #include "core/telemetry_session.h" #include "file_sys/cheat_engine.h" @@ -271,6 +272,7 @@ struct System::Impl { std::unique_ptr telemetry_session; std::map> modules; + Reporter reporter; ResultStatus status = ResultStatus::Success; std::string status_details = ""; @@ -519,6 +521,10 @@ const std::map>& System::GetRegisteredNSOModu return impl->modules; } +const Reporter& System::GetReporter() const { + return impl->reporter; +} + System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { return impl->Init(*this, emu_window); } diff --git a/src/core/core.h b/src/core/core.h index 10542ba21..440cdbbf0 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -69,6 +69,7 @@ class Cpu; class ExclusiveMonitor; class FrameLimiter; class PerfStats; +class Reporter; class TelemetrySession; struct PerfStatsResults; @@ -290,6 +291,8 @@ public: const std::map>& GetRegisteredNSOModules() const; + const Reporter& GetReporter() const; + private: System(); diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp new file mode 100644 index 000000000..95dcfffb5 --- /dev/null +++ b/src/core/reporter.cpp @@ -0,0 +1,351 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include "common/file_util.h" +#include "common/hex_util.h" +#include "common/scm_rev.h" +#include "core/arm/arm_interface.h" +#include "core/core.h" +#include "core/hle/kernel/hle_ipc.h" +#include "core/hle/kernel/process.h" +#include "core/reporter.h" +#include "core/settings.h" +#include "fmt/time.h" + +namespace { + +std::string GetPath(std::string_view type, u64 title_id, std::string_view timestamp) { + return fmt::format("{}{}/{:016X}_{}.json", FileUtil::GetUserPath(FileUtil::UserPath::LogDir), + type, title_id, timestamp); +} + +std::string GetTimestamp() { + const auto time = std::time(nullptr); + return fmt::format("{:%FT%H-%M-%S}", *std::localtime(&time)); +} + +using namespace nlohmann; + +void SaveToFile(const json& json, const std::string& filename) { + FileUtil::CreateFullPath(filename); + std::ofstream file( + FileUtil::SanitizePath(filename, FileUtil::DirectorySeparator::PlatformDefault)); + file << std::setw(4) << json << std::endl; + file.flush(); + file.close(); +} + +json GetYuzuVersionData() { + return { + {"scm_rev", std::string(Common::g_scm_rev)}, + {"scm_branch", std::string(Common::g_scm_branch)}, + {"scm_desc", std::string(Common::g_scm_desc)}, + {"build_name", std::string(Common::g_build_name)}, + {"build_date", std::string(Common::g_build_date)}, + {"build_fullname", std::string(Common::g_build_fullname)}, + {"build_version", std::string(Common::g_build_version)}, + {"shader_cache_version", std::string(Common::g_shader_cache_version)}, + }; +} + +json GetReportCommonData(u64 title_id, ResultCode result, const std::string& timestamp, + std::optional user_id = {}) { + auto out = json{ + {"title_id", fmt::format("{:016X}", title_id)}, + {"result_raw", fmt::format("{:08X}", result.raw)}, + {"result_module", fmt::format("{:08X}", static_cast(result.module.Value()))}, + {"result_description", fmt::format("{:08X}", result.description.Value())}, + {"timestamp", timestamp}, + }; + if (user_id.has_value()) + out["user_id"] = fmt::format("{:016X}{:016X}", (*user_id)[1], (*user_id)[0]); + return std::move(out); +} + +json GetProcessorStateData(const std::string& architecture, u64 entry_point, u64 sp, u64 pc, + u64 pstate, std::array registers, + std::optional> backtrace = {}) { + auto out = json{ + {"entry_point", fmt::format("{:016X}", entry_point)}, + {"sp", fmt::format("{:016X}", sp)}, + {"pc", fmt::format("{:016X}", pc)}, + {"pstate", fmt::format("{:016X}", pstate)}, + {"architecture", architecture}, + }; + + auto registers_out = json::object(); + for (std::size_t i = 0; i < registers.size(); ++i) { + registers_out[fmt::format("X{:02d}", i)] = fmt::format("{:016X}", registers[i]); + } + + out["registers"] = std::move(registers_out); + + if (backtrace.has_value()) { + auto backtrace_out = json::array(); + for (const auto& entry : *backtrace) { + backtrace_out.push_back(fmt::format("{:016X}", entry)); + } + out["backtrace"] = std::move(backtrace_out); + } + + return std::move(out); +} + +json GetProcessorStateDataAuto() { + const auto* process{Core::CurrentProcess()}; + const auto& vm_manager{process->VMManager()}; + auto& arm{Core::CurrentArmInterface()}; + + Core::ARM_Interface::ThreadContext context{}; + arm.SaveContext(context); + + return GetProcessorStateData(process->Is64BitProcess() ? "AArch64" : "AArch32", + vm_manager.GetCodeRegionBaseAddress(), context.sp, context.pc, + context.pstate, context.cpu_registers); +} + +json GetBacktraceData() { + auto out = json::array(); + const auto& backtrace{Core::CurrentArmInterface().GetBacktrace()}; + for (const auto& entry : backtrace) { + out.push_back({ + {"module", entry.module}, + {"address", fmt::format("{:016X}", entry.address)}, + {"original_address", fmt::format("{:016X}", entry.original_address)}, + {"offset", fmt::format("{:016X}", entry.offset)}, + {"symbol_name", entry.name}, + }); + } + + return std::move(out); +} + +json GetFullDataAuto(const std::string& timestamp, u64 title_id) { + json out; + + out["yuzu_version"] = GetYuzuVersionData(); + out["report_common"] = GetReportCommonData(title_id, RESULT_SUCCESS, timestamp); + out["processor_state"] = GetProcessorStateDataAuto(); + out["backtrace"] = GetBacktraceData(); + + return std::move(out); +} + +template +json GetHLEBufferDescriptorData(const std::vector& buffer) { + auto buffer_out = json::array(); + for (const auto& desc : buffer) { + auto entry = json{ + {"address", fmt::format("{:016X}", desc.Address())}, + {"size", fmt::format("{:016X}", desc.Size())}, + }; + + if constexpr (read_value) { + std::vector data(desc.Size()); + Memory::ReadBlock(desc.Address(), data.data(), desc.Size()); + entry["data"] = Common::HexVectorToString(data); + } + + buffer_out.push_back(std::move(entry)); + } + + return std::move(buffer_out); +} + +json GetHLERequestContextData(Kernel::HLERequestContext& ctx) { + json out; + + auto cmd_buf = json::array(); + for (std::size_t i = 0; i < IPC::COMMAND_BUFFER_LENGTH; ++i) { + cmd_buf.push_back(fmt::format("{:08X}", ctx.CommandBuffer()[i])); + } + + out["command_buffer"] = std::move(cmd_buf); + + out["buffer_descriptor_a"] = GetHLEBufferDescriptorData(ctx.BufferDescriptorA()); + out["buffer_descriptor_b"] = GetHLEBufferDescriptorData(ctx.BufferDescriptorB()); + out["buffer_descriptor_c"] = GetHLEBufferDescriptorData(ctx.BufferDescriptorC()); + out["buffer_descriptor_x"] = GetHLEBufferDescriptorData(ctx.BufferDescriptorX()); + + return std::move(out); +} + +} // Anonymous namespace + +namespace Core { + +Reporter::Reporter() = default; + +Reporter::~Reporter() = default; + +void Reporter::SaveCrashReport(u64 title_id, ResultCode result, u64 set_flags, u64 entry_point, + u64 sp, u64 pc, u64 pstate, u64 afsr0, u64 afsr1, u64 esr, u64 far, + const std::array& registers, + const std::array& backtrace, u32 backtrace_size, + const std::string& arch, u32 unk10) const { + if (!IsReportingEnabled()) + return; + + const auto timestamp{GetTimestamp()}; + json out; + + out["yuzu_version"] = GetYuzuVersionData(); + out["report_common"] = GetReportCommonData(title_id, result, timestamp); + + auto proc_out = GetProcessorStateData(arch, entry_point, sp, pc, pstate, registers, backtrace); + proc_out["set_flags"] = fmt::format("{:016X}", set_flags); + proc_out["afsr0"] = fmt::format("{:016X}", afsr0); + proc_out["afsr1"] = fmt::format("{:016X}", afsr1); + proc_out["esr"] = fmt::format("{:016X}", esr); + proc_out["far"] = fmt::format("{:016X}", far); + proc_out["backtrace_size"] = fmt::format("{:08X}", backtrace_size); + proc_out["unknown_10"] = fmt::format("{:08X}", unk10); + + out["processor_state"] = std::move(proc_out); + + SaveToFile(std::move(out), GetPath("crash_report", title_id, timestamp)); +} + +void Reporter::SaveSvcBreakReport(u32 type, bool signal_debugger, u64 info1, u64 info2, + std::optional> resolved_buffer) const { + if (!IsReportingEnabled()) + return; + + const auto timestamp{GetTimestamp()}; + const auto title_id{Core::CurrentProcess()->GetTitleID()}; + auto out = GetFullDataAuto(timestamp, title_id); + + auto break_out = json{ + {"type", fmt::format("{:08X}", type)}, + {"signal_debugger", fmt::format("{}", signal_debugger)}, + {"info1", fmt::format("{:016X}", info1)}, + {"info2", fmt::format("{:016X}", info2)}, + }; + + if (resolved_buffer.has_value()) { + break_out["debug_buffer"] = Common::HexVectorToString(*resolved_buffer); + } + + out["svc_break"] = std::move(break_out); + + SaveToFile(std::move(out), GetPath("svc_break_report", title_id, timestamp)); +} + +void Reporter::SaveUnimplementedFunctionReport(Kernel::HLERequestContext& ctx, u32 command_id, + const std::string& name, + const std::string& service_name) const { + if (!IsReportingEnabled()) + return; + + const auto timestamp{GetTimestamp()}; + const auto title_id{Core::CurrentProcess()->GetTitleID()}; + auto out = GetFullDataAuto(timestamp, title_id); + + auto function_out = GetHLERequestContextData(ctx); + function_out["command_id"] = command_id; + function_out["function_name"] = name; + function_out["service_name"] = service_name; + + out["function"] = std::move(function_out); + + SaveToFile(std::move(out), GetPath("unimpl_func_report", title_id, timestamp)); +} + +void Reporter::SaveUnimplementedAppletReport( + u32 applet_id, u32 common_args_version, u32 library_version, u32 theme_color, + bool startup_sound, u64 system_tick, std::vector> normal_channel, + std::vector> interactive_channel) const { + if (!IsReportingEnabled()) + return; + + const auto timestamp{GetTimestamp()}; + const auto title_id{Core::CurrentProcess()->GetTitleID()}; + auto out = GetFullDataAuto(timestamp, title_id); + + out["applet_common_args"] = { + {"applet_id", fmt::format("{:02X}", applet_id)}, + {"common_args_version", fmt::format("{:08X}", common_args_version)}, + {"library_version", fmt::format("{:08X}", library_version)}, + {"theme_color", fmt::format("{:08X}", theme_color)}, + {"startup_sound", fmt::format("{}", startup_sound)}, + {"system_tick", fmt::format("{:016X}", system_tick)}, + }; + + auto normal_out = json::array(); + for (const auto& data : normal_channel) { + normal_out.push_back(Common::HexVectorToString(data)); + } + + auto interactive_out = json::array(); + for (const auto& data : interactive_channel) { + interactive_out.push_back(Common::HexVectorToString(data)); + } + + out["applet_normal_data"] = std::move(normal_out); + out["applet_interactive_data"] = std::move(interactive_out); + + SaveToFile(std::move(out), GetPath("unimpl_applet_report", title_id, timestamp)); +} + +void Reporter::SavePlayReport(u64 title_id, u64 unk1, std::vector> data, + std::optional user_id) const { + if (!IsReportingEnabled()) + return; + + const auto timestamp{GetTimestamp()}; + json out; + + out["yuzu_version"] = GetYuzuVersionData(); + out["report_common"] = GetReportCommonData(title_id, RESULT_SUCCESS, timestamp, user_id); + + auto data_out = json::array(); + for (const auto& d : data) { + data_out.push_back(Common::HexVectorToString(d)); + } + + out["play_report_unk1"] = fmt::format("{:016X}", unk1); + out["play_report_data"] = std::move(data_out); + + SaveToFile(std::move(out), GetPath("play_report", title_id, timestamp)); +} + +void Reporter::SaveErrorReport(u64 title_id, ResultCode result, + std::optional custom_text_main, + std::optional custom_text_detail) const { + if (!IsReportingEnabled()) + return; + + const auto timestamp{GetTimestamp()}; + json out; + + out["yuzu_version"] = GetYuzuVersionData(); + out["report_common"] = GetReportCommonData(title_id, result, timestamp); + out["processor_state"] = GetProcessorStateDataAuto(); + out["backtrace"] = GetBacktraceData(); + + out["error_custom_text"] = { + {"main", *custom_text_main}, + {"detail", *custom_text_detail}, + }; + + SaveToFile(std::move(out), GetPath("error_report", title_id, timestamp)); +} + +void Reporter::SaveUserReport() const { + if (!IsReportingEnabled()) + return; + + const auto timestamp{GetTimestamp()}; + const auto title_id{Core::CurrentProcess()->GetTitleID()}; + + SaveToFile(GetFullDataAuto(timestamp, title_id), GetPath("user_report", title_id, timestamp)); +} + +bool Reporter::IsReportingEnabled() const { + return Settings::values.reporting_services; +} + +} // namespace Core diff --git a/src/core/reporter.h b/src/core/reporter.h new file mode 100644 index 000000000..2f798ee16 --- /dev/null +++ b/src/core/reporter.h @@ -0,0 +1,53 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include "common/common_types.h" +#include "core/hle/result.h" + +namespace Kernel { +class HLERequestContext; +} // namespace Kernel + +namespace Core { + +class Reporter { +public: + Reporter(); + ~Reporter(); + + void SaveCrashReport(u64 title_id, ResultCode result, u64 set_flags, u64 entry_point, u64 sp, + u64 pc, u64 pstate, u64 afsr0, u64 afsr1, u64 esr, u64 far, + const std::array& registers, const std::array& backtrace, + u32 backtrace_size, const std::string& arch, u32 unk10) const; + + void SaveSvcBreakReport(u32 type, bool signal_debugger, u64 info1, u64 info2, + std::optional> resolved_buffer = {}) const; + + void SaveUnimplementedFunctionReport(Kernel::HLERequestContext& ctx, u32 command_id, + const std::string& name, + const std::string& service_name) const; + + void SaveUnimplementedAppletReport(u32 applet_id, u32 common_args_version, u32 library_version, + u32 theme_color, bool startup_sound, u64 system_tick, + std::vector> normal_channel, + std::vector> interactive_channel) const; + + void SavePlayReport(u64 title_id, u64 unk1, std::vector> data, + std::optional user_id = {}) const; + + void SaveErrorReport(u64 title_id, ResultCode result, + std::optional custom_text_main = {}, + std::optional custom_text_detail = {}) const; + + void SaveUserReport() const; + +private: + bool IsReportingEnabled() const; +}; + +} // namespace Core -- cgit v1.2.3 From b77fde7c5c1f63aad9d4f01ea625805661870f3e Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sun, 26 May 2019 11:40:41 -0400 Subject: loader: Move NSO module tracking to AppLoader Also cleanup of general stuff --- src/core/arm/arm_interface.cpp | 27 ++++++--- src/core/core.cpp | 11 +--- src/core/core.h | 4 -- src/core/hle/service/am/applets/applets.cpp | 5 +- src/core/hle/service/am/applets/general_backend.h | 2 +- src/core/hle/service/prepo/prepo.cpp | 6 +- src/core/loader/deconstructed_rom_directory.cpp | 11 ++++ src/core/loader/deconstructed_rom_directory.h | 4 ++ src/core/loader/loader.h | 6 ++ src/core/loader/nax.cpp | 4 ++ src/core/loader/nax.h | 2 + src/core/loader/nca.cpp | 9 +++ src/core/loader/nca.h | 2 + src/core/loader/nso.cpp | 12 +++- src/core/loader/nso.h | 5 ++ src/core/loader/nsp.cpp | 4 ++ src/core/loader/nsp.h | 2 + src/core/loader/xci.cpp | 4 ++ src/core/loader/xci.h | 2 + src/core/reporter.cpp | 74 ++++++++++++----------- src/core/reporter.h | 9 ++- src/yuzu/configuration/config.cpp | 24 ++++---- 22 files changed, 148 insertions(+), 81 deletions(-) (limited to 'src/core/core.h') diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp index 2945fcff8..372612c9b 100644 --- a/src/core/arm/arm_interface.cpp +++ b/src/core/arm/arm_interface.cpp @@ -9,6 +9,7 @@ #include "common/logging/log.h" #include "core/arm/arm_interface.h" #include "core/core.h" +#include "core/loader/loader.h" #include "core/memory.h" namespace Core { @@ -80,15 +81,17 @@ Symbols GetSymbols(VAddr text_offset) { const auto value = Memory::Read64(dynamic_index + 0x8); dynamic_index += 0x10; - if (tag == ELF_DYNAMIC_TAG_NULL) + if (tag == ELF_DYNAMIC_TAG_NULL) { break; + } - if (tag == ELF_DYNAMIC_TAG_STRTAB) + if (tag == ELF_DYNAMIC_TAG_STRTAB) { string_table_offset = value; - else if (tag == ELF_DYNAMIC_TAG_SYMTAB) + } else if (tag == ELF_DYNAMIC_TAG_SYMTAB) { symbol_table_offset = value; - else if (tag == ELF_DYNAMIC_TAG_SYMENT) + } else if (tag == ELF_DYNAMIC_TAG_SYMENT) { symbol_entry_size = value; + } } if (string_table_offset == 0 || symbol_table_offset == 0 || symbol_entry_size == 0) { @@ -126,8 +129,10 @@ std::optional GetSymbolName(const Symbols& symbols, VAddr func_addr return func_address >= symbol.value && func_address < end_address; }); - if (iter == symbols.end()) + if (iter == symbols.end()) { return std::nullopt; + } + return iter->second; } @@ -150,7 +155,12 @@ std::vector ARM_Interface::GetBacktrace() const { fp = Memory::Read64(fp); } - const auto& modules{System::GetInstance().GetRegisteredNSOModules()}; + std::map modules; + auto& loader{System::GetInstance().GetAppLoader()}; + if (loader.ReadNSOModules(modules) != Loader::ResultStatus::Success) { + return {}; + } + std::map symbols; for (const auto& module : modules) { symbols.insert_or_assign(module.second, GetSymbols(module.first)); @@ -158,7 +168,8 @@ std::vector ARM_Interface::GetBacktrace() const { for (auto& entry : out) { VAddr base = 0; - for (const auto& module : modules) { + for (auto iter = modules.rbegin(); iter != modules.rend(); ++iter) { + const auto& module{*iter}; if (entry.original_address >= module.first) { entry.module = module.second; base = module.first; @@ -191,7 +202,7 @@ void ARM_Interface::LogBacktrace() const { LOG_ERROR(Core_ARM, "Backtrace, sp={:016X}, pc={:016X}", sp, pc); LOG_ERROR(Core_ARM, "{:20}{:20}{:20}{:20}{}", "Module Name", "Address", "Original Address", "Offset", "Symbol"); - LOG_ERROR(Core_ARM, "{}", std::string(100, '-')); + LOG_ERROR(Core_ARM, ""); const auto backtrace = GetBacktrace(); for (const auto& entry : backtrace) { diff --git a/src/core/core.cpp b/src/core/core.cpp index db4c067df..ac9eeddbb 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -83,7 +83,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, return vfs->OpenFile(path, FileSys::Mode::Read); } struct System::Impl { - explicit Impl(System& system) : kernel{system}, cpu_core_manager{system} {} + explicit Impl(System& system) : kernel{system}, cpu_core_manager{system}, reporter{system} {} Cpu& CurrentCpuCore() { return cpu_core_manager.GetCurrentCore(); @@ -271,7 +271,6 @@ struct System::Impl { /// Telemetry session for this emulation session std::unique_ptr telemetry_session; - std::map> modules; Reporter reporter; ResultStatus status = ResultStatus::Success; @@ -513,14 +512,6 @@ void System::ClearContentProvider(FileSys::ContentProviderUnionSlot slot) { impl->content_provider->ClearSlot(slot); } -void System::RegisterNSOModule(std::string name, VAddr start_address) { - impl->modules.insert_or_assign(start_address, name); -} - -const std::map>& System::GetRegisteredNSOModules() const { - return impl->modules; -} - const Reporter& System::GetReporter() const { return impl->reporter; } diff --git a/src/core/core.h b/src/core/core.h index 440cdbbf0..e033057aa 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -287,10 +287,6 @@ public: void ClearContentProvider(FileSys::ContentProviderUnionSlot slot); - void RegisterNSOModule(std::string name, VAddr start_address); - - const std::map>& GetRegisteredNSOModules() const; - const Reporter& GetReporter() const; private: diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index 2a945bc7b..d8ad0079a 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -37,17 +37,18 @@ AppletDataBroker::~AppletDataBroker() = default; AppletDataBroker::RawChannelData AppletDataBroker::PeekDataToAppletForDebug() const { std::vector> out_normal; - std::vector> out_interactive; for (const auto& storage : in_channel) { out_normal.push_back(storage->GetData()); } + std::vector> out_interactive; + for (const auto& storage : in_interactive_channel) { out_interactive.push_back(storage->GetData()); } - return {out_normal, out_interactive}; + return {std::move(out_normal), std::move(out_interactive)}; } std::unique_ptr AppletDataBroker::PopNormalDataToGame() { diff --git a/src/core/hle/service/am/applets/general_backend.h b/src/core/hle/service/am/applets/general_backend.h index bc919a8dd..fb68a2543 100644 --- a/src/core/hle/service/am/applets/general_backend.h +++ b/src/core/hle/service/am/applets/general_backend.h @@ -34,7 +34,7 @@ private: class StubApplet final : public Applet { public: - StubApplet(AppletId id); + explicit StubApplet(AppletId id); ~StubApplet() override; void Initialize() override; diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp index 961b8882d..7e134f5c1 100644 --- a/src/core/hle/service/prepo/prepo.cpp +++ b/src/core/hle/service/prepo/prepo.cpp @@ -50,7 +50,7 @@ private: void SaveReportWithUserOld(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto user_id = rp.PopRaw(); - const auto unk1 = rp.PopRaw(); + const auto process_id = rp.PopRaw(); const auto data1 = ctx.ReadBuffer(0); const auto data2 = ctx.ReadBuffer(1); @@ -58,10 +58,10 @@ private: LOG_DEBUG( Service_PREPO, "called, user_id={:016X}{:016X}, unk1={:016X}, data1_size={:016X}, data2_size={:016X}", - user_id[1], user_id[0], unk1, data1.size(), data2.size()); + user_id[1], user_id[0], process_id, data1.size(), data2.size()); const auto& reporter{Core::System::GetInstance().GetReporter()}; - reporter.SavePlayReport(Core::CurrentProcess()->GetTitleID(), unk1, {data1, data2}, + reporter.SavePlayReport(Core::CurrentProcess()->GetTitleID(), process_id, {data1, data2}, user_id); IPC::ResponseBuilder rb{ctx, 2}; diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 10b13fb1d..f9e88be2b 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -141,6 +141,7 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect const FileSys::PatchManager pm(metadata.GetTitleID()); // Load NSO modules + modules.clear(); const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); VAddr next_load_addr = base_address; for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", @@ -159,6 +160,7 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect } next_load_addr = *tentative_next_load_addr; + modules.insert_or_assign(load_addr, module); LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); // Register module with GDBStub GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false); @@ -212,4 +214,13 @@ bool AppLoader_DeconstructedRomDirectory::IsRomFSUpdatable() const { return false; } +ResultStatus AppLoader_DeconstructedRomDirectory::ReadNSOModules(Modules& modules) { + if (!is_loaded) { + return ResultStatus::ErrorNotInitialized; + } + + modules = this->modules; + return ResultStatus::Success; +} + } // namespace Loader diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h index 1a65c16a4..1c0a354a4 100644 --- a/src/core/loader/deconstructed_rom_directory.h +++ b/src/core/loader/deconstructed_rom_directory.h @@ -45,6 +45,8 @@ public: ResultStatus ReadTitle(std::string& title) override; bool IsRomFSUpdatable() const override; + ResultStatus ReadNSOModules(Modules& modules) override; + private: FileSys::ProgramMetadata metadata; FileSys::VirtualFile romfs; @@ -54,6 +56,8 @@ private: std::string name; u64 title_id{}; bool override_update; + + Modules modules; }; } // namespace Loader diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index f7846db52..d6372c559 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -278,6 +278,12 @@ public: return ResultStatus::ErrorNotImplemented; } + using Modules = std::map; + + virtual ResultStatus ReadNSOModules(Modules& modules) { + return ResultStatus::ErrorNotImplemented; + } + protected: FileSys::VirtualFile file; bool is_loaded = false; diff --git a/src/core/loader/nax.cpp b/src/core/loader/nax.cpp index 34efef09a..a152981a0 100644 --- a/src/core/loader/nax.cpp +++ b/src/core/loader/nax.cpp @@ -94,4 +94,8 @@ ResultStatus AppLoader_NAX::ReadLogo(std::vector& buffer) { return nca_loader->ReadLogo(buffer); } +ResultStatus AppLoader_NAX::ReadNSOModules(Modules& modules) { + return nca_loader->ReadNSOModules(modules); +} + } // namespace Loader diff --git a/src/core/loader/nax.h b/src/core/loader/nax.h index 00f1659c1..eaec9bf58 100644 --- a/src/core/loader/nax.h +++ b/src/core/loader/nax.h @@ -42,6 +42,8 @@ public: ResultStatus ReadBanner(std::vector& buffer) override; ResultStatus ReadLogo(std::vector& buffer) override; + ResultStatus ReadNSOModules(Modules& modules) override; + private: std::unique_ptr nax; std::unique_ptr nca_loader; diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp index b3f8f1083..0f65fb637 100644 --- a/src/core/loader/nca.cpp +++ b/src/core/loader/nca.cpp @@ -105,4 +105,13 @@ ResultStatus AppLoader_NCA::ReadLogo(std::vector& buffer) { buffer = logo->GetFile("NintendoLogo.png")->ReadAllBytes(); return ResultStatus::Success; } + +ResultStatus AppLoader_NCA::ReadNSOModules(Modules& modules) { + if (directory_loader == nullptr) { + return ResultStatus::ErrorNotInitialized; + } + + return directory_loader->ReadNSOModules(modules); +} + } // namespace Loader diff --git a/src/core/loader/nca.h b/src/core/loader/nca.h index 94f0ed677..e47dc0e47 100644 --- a/src/core/loader/nca.h +++ b/src/core/loader/nca.h @@ -42,6 +42,8 @@ public: ResultStatus ReadBanner(std::vector& buffer) override; ResultStatus ReadLogo(std::vector& buffer) override; + ResultStatus ReadNSOModules(Modules& modules) override; + private: std::unique_ptr nca; std::unique_ptr directory_loader; diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 7beeaaff3..e0d6ab473 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -164,9 +164,6 @@ std::optional AppLoader_NSO::LoadModule(Kernel::Process& process, // Register module with GDBStub GDBStub::RegisterModule(file.GetName(), load_base, load_base); - // Register module for ARMInterface with System - Core::System::GetInstance().RegisterNSOModule(file.GetName(), load_base); - return load_base + image_size; } @@ -175,11 +172,15 @@ AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::Process& process) { return {ResultStatus::ErrorAlreadyLoaded, {}}; } + modules.clear(); + // Load module const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); if (!LoadModule(process, *file, base_address, true)) { return {ResultStatus::ErrorLoadingNSO, {}}; } + + modules.insert_or_assign(base_address, file->GetName()); LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address); is_loaded = true; @@ -187,4 +188,9 @@ AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::Process& process) { LoadParameters{Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE}}; } +ResultStatus AppLoader_NSO::ReadNSOModules(Modules& modules) { + modules = this->modules; + return ResultStatus::Success; +} + } // namespace Loader diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h index fdce9191c..58cbe162d 100644 --- a/src/core/loader/nso.h +++ b/src/core/loader/nso.h @@ -85,6 +85,11 @@ public: std::optional pm = {}); LoadResult Load(Kernel::Process& process) override; + + ResultStatus ReadNSOModules(Modules& modules) override; + +private: + Modules modules; }; } // namespace Loader diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp index ad56bbb38..3a22ec2c6 100644 --- a/src/core/loader/nsp.cpp +++ b/src/core/loader/nsp.cpp @@ -183,4 +183,8 @@ ResultStatus AppLoader_NSP::ReadLogo(std::vector& buffer) { return secondary_loader->ReadLogo(buffer); } +ResultStatus AppLoader_NSP::ReadNSOModules(Modules& modules) { + return secondary_loader->ReadNSOModules(modules); +} + } // namespace Loader diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h index 85e870bdf..868b028d3 100644 --- a/src/core/loader/nsp.h +++ b/src/core/loader/nsp.h @@ -49,6 +49,8 @@ public: ResultStatus ReadBanner(std::vector& buffer) override; ResultStatus ReadLogo(std::vector& buffer) override; + ResultStatus ReadNSOModules(Modules& modules) override; + private: std::unique_ptr nsp; std::unique_ptr secondary_loader; diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index 1e285a053..a5c4d3688 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp @@ -149,4 +149,8 @@ ResultStatus AppLoader_XCI::ReadLogo(std::vector& buffer) { return nca_loader->ReadLogo(buffer); } +ResultStatus AppLoader_XCI::ReadNSOModules(Modules& modules) { + return nca_loader->ReadNSOModules(modules); +} + } // namespace Loader diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h index ae7145b14..618ae2f47 100644 --- a/src/core/loader/xci.h +++ b/src/core/loader/xci.h @@ -49,6 +49,8 @@ public: ResultStatus ReadBanner(std::vector& buffer) override; ResultStatus ReadLogo(std::vector& buffer) override; + ResultStatus ReadNSOModules(Modules& modules) override; + private: std::unique_ptr xci; std::unique_ptr nca_loader; diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp index 95dcfffb5..8fe621aa0 100644 --- a/src/core/reporter.cpp +++ b/src/core/reporter.cpp @@ -11,6 +11,7 @@ #include "core/core.h" #include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/process.h" +#include "core/hle/result.h" #include "core/reporter.h" #include "core/settings.h" #include "fmt/time.h" @@ -30,12 +31,12 @@ std::string GetTimestamp() { using namespace nlohmann; void SaveToFile(const json& json, const std::string& filename) { - FileUtil::CreateFullPath(filename); + if (!FileUtil::CreateFullPath(filename)) + LOG_ERROR(Core, "Failed to create path for '{}' to save report!", filename); + std::ofstream file( FileUtil::SanitizePath(filename, FileUtil::DirectorySeparator::PlatformDefault)); file << std::setw(4) << json << std::endl; - file.flush(); - file.close(); } json GetYuzuVersionData() { @@ -62,7 +63,7 @@ json GetReportCommonData(u64 title_id, ResultCode result, const std::string& tim }; if (user_id.has_value()) out["user_id"] = fmt::format("{:016X}{:016X}", (*user_id)[1], (*user_id)[0]); - return std::move(out); + return out; } json GetProcessorStateData(const std::string& architecture, u64 entry_point, u64 sp, u64 pc, @@ -91,13 +92,13 @@ json GetProcessorStateData(const std::string& architecture, u64 entry_point, u64 out["backtrace"] = std::move(backtrace_out); } - return std::move(out); + return out; } -json GetProcessorStateDataAuto() { - const auto* process{Core::CurrentProcess()}; +json GetProcessorStateDataAuto(Core::System& system) { + const auto* process{system.CurrentProcess()}; const auto& vm_manager{process->VMManager()}; - auto& arm{Core::CurrentArmInterface()}; + auto& arm{system.CurrentArmInterface()}; Core::ARM_Interface::ThreadContext context{}; arm.SaveContext(context); @@ -107,9 +108,9 @@ json GetProcessorStateDataAuto() { context.pstate, context.cpu_registers); } -json GetBacktraceData() { +json GetBacktraceData(Core::System& system) { auto out = json::array(); - const auto& backtrace{Core::CurrentArmInterface().GetBacktrace()}; + const auto& backtrace{system.CurrentArmInterface().GetBacktrace()}; for (const auto& entry : backtrace) { out.push_back({ {"module", entry.module}, @@ -120,18 +121,18 @@ json GetBacktraceData() { }); } - return std::move(out); + return out; } -json GetFullDataAuto(const std::string& timestamp, u64 title_id) { +json GetFullDataAuto(const std::string& timestamp, u64 title_id, Core::System& system) { json out; out["yuzu_version"] = GetYuzuVersionData(); out["report_common"] = GetReportCommonData(title_id, RESULT_SUCCESS, timestamp); - out["processor_state"] = GetProcessorStateDataAuto(); - out["backtrace"] = GetBacktraceData(); + out["processor_state"] = GetProcessorStateDataAuto(system); + out["backtrace"] = GetBacktraceData(system); - return std::move(out); + return out; } template @@ -152,7 +153,7 @@ json GetHLEBufferDescriptorData(const std::vector& buffer) { buffer_out.push_back(std::move(entry)); } - return std::move(buffer_out); + return buffer_out; } json GetHLERequestContextData(Kernel::HLERequestContext& ctx) { @@ -177,7 +178,7 @@ json GetHLERequestContextData(Kernel::HLERequestContext& ctx) { namespace Core { -Reporter::Reporter() = default; +Reporter::Reporter(Core::System& system) : system(system) {} Reporter::~Reporter() = default; @@ -189,7 +190,7 @@ void Reporter::SaveCrashReport(u64 title_id, ResultCode result, u64 set_flags, u if (!IsReportingEnabled()) return; - const auto timestamp{GetTimestamp()}; + const auto timestamp = GetTimestamp(); json out; out["yuzu_version"] = GetYuzuVersionData(); @@ -214,9 +215,9 @@ void Reporter::SaveSvcBreakReport(u32 type, bool signal_debugger, u64 info1, u64 if (!IsReportingEnabled()) return; - const auto timestamp{GetTimestamp()}; - const auto title_id{Core::CurrentProcess()->GetTitleID()}; - auto out = GetFullDataAuto(timestamp, title_id); + const auto timestamp = GetTimestamp(); + const auto title_id = system.CurrentProcess()->GetTitleID(); + auto out = GetFullDataAuto(timestamp, title_id, system); auto break_out = json{ {"type", fmt::format("{:08X}", type)}, @@ -240,9 +241,9 @@ void Reporter::SaveUnimplementedFunctionReport(Kernel::HLERequestContext& ctx, u if (!IsReportingEnabled()) return; - const auto timestamp{GetTimestamp()}; - const auto title_id{Core::CurrentProcess()->GetTitleID()}; - auto out = GetFullDataAuto(timestamp, title_id); + const auto timestamp = GetTimestamp(); + const auto title_id = system.CurrentProcess()->GetTitleID(); + auto out = GetFullDataAuto(timestamp, title_id, system); auto function_out = GetHLERequestContextData(ctx); function_out["command_id"] = command_id; @@ -261,9 +262,9 @@ void Reporter::SaveUnimplementedAppletReport( if (!IsReportingEnabled()) return; - const auto timestamp{GetTimestamp()}; - const auto title_id{Core::CurrentProcess()->GetTitleID()}; - auto out = GetFullDataAuto(timestamp, title_id); + const auto timestamp = GetTimestamp(); + const auto title_id = system.CurrentProcess()->GetTitleID(); + auto out = GetFullDataAuto(timestamp, title_id, system); out["applet_common_args"] = { {"applet_id", fmt::format("{:02X}", applet_id)}, @@ -290,12 +291,12 @@ void Reporter::SaveUnimplementedAppletReport( SaveToFile(std::move(out), GetPath("unimpl_applet_report", title_id, timestamp)); } -void Reporter::SavePlayReport(u64 title_id, u64 unk1, std::vector> data, +void Reporter::SavePlayReport(u64 title_id, u64 process_id, std::vector> data, std::optional user_id) const { if (!IsReportingEnabled()) return; - const auto timestamp{GetTimestamp()}; + const auto timestamp = GetTimestamp(); json out; out["yuzu_version"] = GetYuzuVersionData(); @@ -306,7 +307,7 @@ void Reporter::SavePlayReport(u64 title_id, u64 unk1, std::vectorGetTitleID()}; + const auto timestamp = GetTimestamp(); + const auto title_id = system.CurrentProcess()->GetTitleID(); - SaveToFile(GetFullDataAuto(timestamp, title_id), GetPath("user_report", title_id, timestamp)); + SaveToFile(GetFullDataAuto(timestamp, title_id, system), + GetPath("user_report", title_id, timestamp)); } bool Reporter::IsReportingEnabled() const { diff --git a/src/core/reporter.h b/src/core/reporter.h index 2f798ee16..3de19c0f7 100644 --- a/src/core/reporter.h +++ b/src/core/reporter.h @@ -7,7 +7,8 @@ #include #include #include "common/common_types.h" -#include "core/hle/result.h" + +union ResultCode; namespace Kernel { class HLERequestContext; @@ -17,7 +18,7 @@ namespace Core { class Reporter { public: - Reporter(); + explicit Reporter(Core::System& system); ~Reporter(); void SaveCrashReport(u64 title_id, ResultCode result, u64 set_flags, u64 entry_point, u64 sp, @@ -37,7 +38,7 @@ public: std::vector> normal_channel, std::vector> interactive_channel) const; - void SavePlayReport(u64 title_id, u64 unk1, std::vector> data, + void SavePlayReport(u64 title_id, u64 process_id, std::vector> data, std::optional user_id = {}) const; void SaveErrorReport(u64 title_id, ResultCode result, @@ -48,6 +49,8 @@ public: private: bool IsReportingEnabled() const; + + Core::System& system; }; } // namespace Core diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index ed14474aa..ed0eafe4f 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -465,16 +465,18 @@ void Config::ReadDataStorageValues() { } void Config::ReadDebuggingValues() { - qt_config->beginGroup(QStringLiteral("Debugging")); - - Settings::values.use_gdbstub = ReadSetting(QStringLiteral("use_gdbstub"), false).toBool(); - Settings::values.gdbstub_port = ReadSetting(QStringLiteral("gdbstub_port"), 24689).toInt(); - Settings::values.program_args = - ReadSetting(QStringLiteral("program_args"), QStringLiteral("")).toString().toStdString(); - Settings::values.dump_exefs = ReadSetting(QStringLiteral("dump_exefs"), false).toBool(); - Settings::values.dump_nso = ReadSetting(QStringLiteral("dump_nso"), false).toBool(); - Settings::values.reporting_services = ReadSetting("reporting_services", false).toBool(); - qt_config->endGroup(); + qt_config->beginGroup(QStringLiteral("Debugging")); + + Settings::values.use_gdbstub = ReadSetting(QStringLiteral("use_gdbstub"), false).toBool(); + Settings::values.gdbstub_port = ReadSetting(QStringLiteral("gdbstub_port"), 24689).toInt(); + Settings::values.program_args = + ReadSetting(QStringLiteral("program_args"), QStringLiteral("")).toString().toStdString(); + Settings::values.dump_exefs = ReadSetting(QStringLiteral("dump_exefs"), false).toBool(); + Settings::values.dump_nso = ReadSetting(QStringLiteral("dump_nso"), false).toBool(); + Settings::values.reporting_services = + ReadSetting(QStringLiteral("reporting_services"), false).toBool(); + + qt_config->endGroup(); } void Config::ReadDisabledAddOnValues() { @@ -691,7 +693,7 @@ void Config::ReadValues() { ReadDataStorageValues(); ReadSystemValues(); ReadMiscellaneousValues(); - ReadDebugValues(); + ReadDebuggingValues(); ReadWebServiceValues(); ReadDisabledAddOnValues(); ReadUIValues(); -- cgit v1.2.3