diff --git a/libraries/libstratosphere/include/stratosphere/ldr.hpp b/libraries/libstratosphere/include/stratosphere/ldr.hpp index c3474f63e..c278de699 100644 --- a/libraries/libstratosphere/include/stratosphere/ldr.hpp +++ b/libraries/libstratosphere/include/stratosphere/ldr.hpp @@ -16,5 +16,6 @@ #pragma once -#include "ldr/ldr_types.hpp" -#include "ldr/ldr_pm_api.hpp" +#include +#include +#include diff --git a/libraries/libstratosphere/include/stratosphere/ldr/ldr_shell_api.hpp b/libraries/libstratosphere/include/stratosphere/ldr/ldr_shell_api.hpp new file mode 100644 index 000000000..24a33e9c9 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/ldr/ldr_shell_api.hpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include +#include + +namespace ams::ldr { + + /* Shell API. */ + Result InitializeForShell(); + Result FinalizeForShell(); + + Result SetProgramArgument(ncm::ProgramId program_id, const void *arg, size_t size); + Result FlushArguments(); + +} diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_system_content_meta_id.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_system_content_meta_id.hpp index 42d2531a0..7154243cb 100644 --- a/libraries/libstratosphere/include/stratosphere/ncm/ncm_system_content_meta_id.hpp +++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_system_content_meta_id.hpp @@ -402,6 +402,34 @@ namespace ams::ncm { return true; } + struct SystemDebugAppletId { + u64 value; + + constexpr operator ProgramId() const { + return { this->value }; + } + + static const SystemDebugAppletId Start; + + static const SystemDebugAppletId SnapShotDumper; + + static const SystemDebugAppletId End; + }; + + inline constexpr const SystemDebugAppletId SystemDebugAppletId::Start = { 0x0100000000002000ul }; + + inline constexpr const SystemDebugAppletId SystemDebugAppletId::SnapShotDumper = { 0x0100000000002071ul }; + + inline constexpr const SystemDebugAppletId SystemDebugAppletId::End = { 0x0100000000002FFFul }; + + inline constexpr bool IsSystemDebugAppletId(const ProgramId &program_id) { + return SystemDebugAppletId::Start <= program_id && program_id <= SystemDebugAppletId::End; + } + + inline constexpr bool IsSystemDebugAppletId(const SystemDebugAppletId &program_id) { + return true; + } + struct LibraryAppletId { u64 value; diff --git a/libraries/libstratosphere/source/ldr/ldr_shell_api.cpp b/libraries/libstratosphere/source/ldr/ldr_shell_api.cpp new file mode 100644 index 000000000..b5391a14b --- /dev/null +++ b/libraries/libstratosphere/source/ldr/ldr_shell_api.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +namespace ams::ldr { + + Result InitializeForShell() { + return ::ldrShellInitialize(); + } + + Result FinalizeForShell() { + ::ldrShellExit(); + return ResultSuccess(); + } + + Result SetProgramArgument(ncm::ProgramId program_id, const void *arg, size_t size) { + return ::ldrShellSetProgramArguments(static_cast(program_id), arg, size); + } + + Result FlushArguments() { + return ::ldrShellFlushArguments(); + } + +} diff --git a/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.cpp b/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.cpp index d7aa4c48c..a9653911d 100644 --- a/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.cpp +++ b/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.cpp @@ -82,6 +82,55 @@ namespace ams::pgl::srv { } } + s32 ConvertDumpTypeToArgument(SnapShotDumpType dump_type) { + switch (dump_type) { + case SnapShotDumpType::None: return -1; + case SnapShotDumpType::Auto: return 0; + case SnapShotDumpType::Full: return 1; + AMS_UNREACHABLE_DEFAULT_CASE(); + } + } + + bool GetSnapShotDumpOutputAllLog(os::ProcessId process_id) { + /* Check if we have an option set for the process. */ + { + std::scoped_lock lk(g_process_data_mutex); + if (ProcessData *data = FindProcessData(process_id); data != nullptr) { + if ((data->flags & ProcessDataFlag_HasLogOption) != 0) { + return ((data->flags & ProcessDataFlag_OutputAllLog) != 0); + } + } + } + + /* If we don't have an option for the process, fall back to settings. */ + u8 log_option; + const size_t option_size = settings::fwdbg::GetSettingsItemValue(std::addressof(log_option), sizeof(log_option), "snap_shot_dump", "output_all_log"); + return (option_size == sizeof(log_option) && log_option != 0); + } + + size_t CreateSnapShotDumpArguments(char *dst, size_t dst_size, os::ProcessId process_id, SnapShotDumpType dump_type, const char *str_arg) { + const s32 dump_arg = ConvertDumpTypeToArgument(dump_type); + const s32 log_arg = GetSnapShotDumpOutputAllLog(process_id) ? 1 : 0; + if (str_arg != nullptr) { + return std::snprintf(dst, dst_size, "D %010llu \"%s\" -log %d -dump %d", static_cast(static_cast(process_id)), str_arg, log_arg, dump_arg); + } else { + return std::snprintf(dst, dst_size, "D %010llu -log %d -dump %d", static_cast(static_cast(process_id)), log_arg, dump_arg); + } + } + + Result TriggerSnapShotDumper(os::ProcessId process_id, SnapShotDumpType dump_type, const char *arg) { + /* Create the arguments. */ + char process_arguments[800]; + const size_t arg_len = CreateSnapShotDumpArguments(process_arguments, sizeof(process_arguments), process_id, dump_type, arg); + + /* Set the arguments. */ + R_TRY(ldr::SetProgramArgument(ncm::SystemDebugAppletId::SnapShotDumper, process_arguments, arg_len + 1)); + + /* Launch the process. */ + os::ProcessId dummy_process_id; + return pm::shell::LaunchProgram(std::addressof(dummy_process_id), ncm::ProgramLocation::Make(ncm::SystemDebugAppletId::SnapShotDumper, ncm::StorageId::BuiltInSystem), pm::LaunchFlags_None); + } + } void InitializeProcessControlTask() { @@ -205,7 +254,12 @@ namespace ams::pgl::srv { } Result TriggerApplicationSnapShotDumper(SnapShotDumpType dump_type, const char *arg) { - /* TODO */ + /* Try to get the application process id. */ + os::ProcessId process_id; + R_TRY(pm::shell::GetApplicationProcessIdForShell(std::addressof(process_id))); + + /* Launch the snapshot dumper. */ + return TriggerSnapShotDumper(process_id, dump_type, arg); } }