diff --git a/libraries/libstratosphere/include/stratosphere/pm/pm_shell_api.hpp b/libraries/libstratosphere/include/stratosphere/pm/pm_shell_api.hpp
index 4dd79409c..c38452710 100644
--- a/libraries/libstratosphere/include/stratosphere/pm/pm_shell_api.hpp
+++ b/libraries/libstratosphere/include/stratosphere/pm/pm_shell_api.hpp
@@ -25,6 +25,8 @@ namespace ams::pm::shell {
/* Shell API. */
Result LaunchProgram(os::ProcessId *out, const ncm::ProgramLocation &loc, u32 launch_flags);
Result TerminateProcess(os::ProcessId process_id);
+ Result GetProcessEventEvent(os::SystemEvent *out);
+ Result GetProcessEventInfo(ProcessEventInfo *out);
Result GetApplicationProcessIdForShell(os::ProcessId *out);
Result BoostSystemMemoryResourceLimit(u64 size);
Result EnableApplicationExtraThread();
diff --git a/libraries/libstratosphere/include/stratosphere/pm/pm_types.hpp b/libraries/libstratosphere/include/stratosphere/pm/pm_types.hpp
index fbd4931fe..f433bddb4 100644
--- a/libraries/libstratosphere/include/stratosphere/pm/pm_types.hpp
+++ b/libraries/libstratosphere/include/stratosphere/pm/pm_types.hpp
@@ -54,7 +54,7 @@ namespace ams::pm {
constexpr inline u32 LaunchFlagsMask = (1 << 6) - 1;
- enum class ProcessEvent {
+ enum class ProcessEvent : u32 {
None = 0,
Exited = 1,
Started = 2,
@@ -63,7 +63,7 @@ namespace ams::pm {
DebugBreak = 5,
};
- enum class ProcessEventDeprecated {
+ enum class ProcessEventDeprecated : u32 {
None = 0,
Exception = 1,
Exited = 2,
diff --git a/libraries/libstratosphere/include/stratosphere/settings.hpp b/libraries/libstratosphere/include/stratosphere/settings.hpp
index 8c95dc127..a509fe93a 100644
--- a/libraries/libstratosphere/include/stratosphere/settings.hpp
+++ b/libraries/libstratosphere/include/stratosphere/settings.hpp
@@ -19,6 +19,7 @@
#include "settings/settings_types.hpp"
#include "settings/settings_fwdbg_types.hpp"
#include "settings/settings_fwdbg_api.hpp"
+#include "settings/system/settings_error_report.hpp"
#include "settings/system/settings_firmware_version.hpp"
#include "settings/system/settings_product_model.hpp"
#include "settings/system/settings_region.hpp"
diff --git a/libraries/libstratosphere/include/stratosphere/settings/system/settings_error_report.hpp b/libraries/libstratosphere/include/stratosphere/settings/system/settings_error_report.hpp
new file mode 100644
index 000000000..c0c67d5b8
--- /dev/null
+++ b/libraries/libstratosphere/include/stratosphere/settings/system/settings_error_report.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
+
+namespace ams::settings::system {
+
+ enum ErrorReportSharePermission {
+ ErrorReportSharePermission_NotConfirmed = 0,
+ ErrorReportSharePermission_Granted = 1,
+ ErrorReportSharePermission_Denied = 2,
+ };
+
+ ErrorReportSharePermission GetErrorReportSharePermission();
+
+}
diff --git a/libraries/libstratosphere/source/lr/lr_remote_location_resolver_impl.hpp b/libraries/libstratosphere/source/lr/lr_remote_location_resolver_impl.hpp
index 5ac2b47e4..59093e7d8 100644
--- a/libraries/libstratosphere/source/lr/lr_remote_location_resolver_impl.hpp
+++ b/libraries/libstratosphere/source/lr/lr_remote_location_resolver_impl.hpp
@@ -28,19 +28,19 @@ namespace ams::lr {
public:
/* Actual commands. */
virtual Result ResolveProgramPath(sf::Out out, ncm::ProgramId id) override {
- return lrLrResolveProgramPath(std::addressof(this->srv), static_cast(id), out->str);
+ return lrLrResolveProgramPath(std::addressof(this->srv), id.value, out->str);
}
virtual Result RedirectProgramPath(const Path &path, ncm::ProgramId id) override {
- return lrLrRedirectProgramPath(std::addressof(this->srv), static_cast(id), path.str);
+ return lrLrRedirectProgramPath(std::addressof(this->srv), id.value, path.str);
}
virtual Result ResolveApplicationControlPath(sf::Out out, ncm::ProgramId id) override {
- return lrLrResolveApplicationControlPath(std::addressof(this->srv), static_cast(id), out->str);
+ return lrLrResolveApplicationControlPath(std::addressof(this->srv), id.value, out->str);
}
virtual Result ResolveApplicationHtmlDocumentPath(sf::Out out, ncm::ProgramId id) override {
- return lrLrResolveApplicationHtmlDocumentPath(std::addressof(this->srv), static_cast(id), out->str);
+ return lrLrResolveApplicationHtmlDocumentPath(std::addressof(this->srv), id.value, out->str);
}
virtual Result ResolveDataPath(sf::Out out, ncm::DataId id) override {
@@ -48,31 +48,31 @@ namespace ams::lr {
}
virtual Result RedirectApplicationControlPathDeprecated(const Path &path, ncm::ProgramId id) override {
- return lrLrRedirectApplicationControlPath(std::addressof(this->srv), static_cast(id), 0, path.str);
+ return lrLrRedirectApplicationControlPath(std::addressof(this->srv), id.value, 0, path.str);
}
virtual Result RedirectApplicationControlPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) override {
- return lrLrRedirectApplicationControlPath(std::addressof(this->srv), static_cast(id), static_cast(owner_id), path.str);
+ return lrLrRedirectApplicationControlPath(std::addressof(this->srv), id.value, owner_id.value, path.str);
}
virtual Result RedirectApplicationHtmlDocumentPathDeprecated(const Path &path, ncm::ProgramId id) override {
- return lrLrRedirectApplicationHtmlDocumentPath(std::addressof(this->srv), static_cast(id), 0, path.str);
+ return lrLrRedirectApplicationHtmlDocumentPath(std::addressof(this->srv), id.value, 0, path.str);
}
virtual Result RedirectApplicationHtmlDocumentPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) override {
- return lrLrRedirectApplicationHtmlDocumentPath(std::addressof(this->srv), static_cast(id), static_cast(owner_id), path.str);
+ return lrLrRedirectApplicationHtmlDocumentPath(std::addressof(this->srv), id.value, owner_id.value, path.str);
}
virtual Result ResolveApplicationLegalInformationPath(sf::Out out, ncm::ProgramId id) override {
- return lrLrResolveApplicationLegalInformationPath(std::addressof(this->srv), static_cast(id), out->str);
+ return lrLrResolveApplicationLegalInformationPath(std::addressof(this->srv), id.value, out->str);
}
virtual Result RedirectApplicationLegalInformationPathDeprecated(const Path &path, ncm::ProgramId id) override {
- return lrLrRedirectApplicationLegalInformationPath(std::addressof(this->srv), static_cast(id), 0, path.str);
+ return lrLrRedirectApplicationLegalInformationPath(std::addressof(this->srv), id.value, 0, path.str);
}
virtual Result RedirectApplicationLegalInformationPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) override {
- return lrLrRedirectApplicationLegalInformationPath(std::addressof(this->srv), static_cast(id), static_cast(owner_id), path.str);
+ return lrLrRedirectApplicationLegalInformationPath(std::addressof(this->srv), id.value, owner_id.value, path.str);
}
virtual Result Refresh() override {
@@ -100,8 +100,7 @@ namespace ams::lr {
}
virtual Result EraseProgramRedirection(ncm::ProgramId id) override {
- /* TODO: libnx bindings */
- AMS_ABORT();
+ return lrLrEraseProgramRedirection(std::addressof(this->srv), id.value);
}
virtual Result EraseApplicationControlRedirection(ncm::ProgramId id) override {
diff --git a/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.cpp b/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.cpp
index 5ae538539..37537bd4b 100644
--- a/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.cpp
+++ b/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.cpp
@@ -140,8 +140,182 @@ namespace ams::pgl::srv {
return pm::shell::LaunchProgram(std::addressof(dummy_process_id), ncm::ProgramLocation::Make(ncm::SystemDebugAppletId::SnapShotDumper, ncm::StorageId::BuiltInSystem), pm::LaunchFlags_None);
}
+ bool ShouldSnapShotAutoDump() {
+ bool dump;
+ const size_t sz = settings::fwdbg::GetSettingsItemValue(std::addressof(dump), sizeof(dump), "snap_shot_dump", "auto_dump");
+ return sz == sizeof(dump) && dump;
+ }
+
+ bool ShouldSnapShotFullDump() {
+ bool dump;
+ const size_t sz = settings::fwdbg::GetSettingsItemValue(std::addressof(dump), sizeof(dump), "snap_shot_dump", "full_dump");
+ return sz == sizeof(dump) && dump;
+ }
+
+ SnapShotDumpType GetSnapShotDumpType() {
+ if (ShouldSnapShotAutoDump()) {
+ if (ShouldSnapShotFullDump()) {
+ return SnapShotDumpType::Full;
+ } else {
+ return SnapShotDumpType::Auto;
+ }
+ } else {
+ return SnapShotDumpType::None;
+ }
+ }
+
+ void TriggerSnapShotDumper(os::ProcessId process_id) {
+ TriggerSnapShotDumper(process_id, GetSnapShotDumpType(), nullptr);
+ }
+
+ s32 GetCrashReportDetailedArgument(u32 data_flags) {
+ if (((data_flags & ProcessDataFlag_DetailedCrashReportAllowed) != 0) && ((data_flags & ProcessDataFlag_DetailedCrashReportEnabled) != 0)) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ s32 GetCrashReportScreenShotArgument(u32 data_flags) {
+ if (settings::system::GetErrorReportSharePermission() == settings::system::ErrorReportSharePermission_Granted) {
+ return ((data_flags & ProcessDataFlag_EnableCrashReportScreenShot) != 0) ? 1 : 0;
+ } else {
+ return 0;
+ }
+ }
+
+ void TriggerCrashReport(os::ProcessId process_id) {
+ static os::ProcessId s_crashed_process_id = os::InvalidProcessId;
+ static os::ProcessId s_creport_process_id = os::InvalidProcessId;
+
+ /* If the program that crashed is creport, we should just terminate both processes and return. */
+ if (process_id == s_creport_process_id) {
+ TerminateProcess(s_crashed_process_id);
+ TerminateProcess(s_creport_process_id);
+ s_crashed_process_id = os::InvalidProcessId;
+ s_creport_process_id = os::InvalidProcessId;
+ return;
+ }
+
+ /* Get the data flags for the process. */
+ u32 data_flags;
+ {
+ std::scoped_lock lk(g_process_data_mutex);
+ if (auto *data = FindProcessData(process_id); data != nullptr) {
+ data_flags = data->flags;
+ } else {
+ data_flags = ProcessDataFlag_None;
+ }
+ }
+
+ /* Generate arguments. */
+ char arguments[0x40];
+ const size_t len = std::snprintf(arguments, sizeof(arguments), "%ld %d %d", static_cast(static_cast(process_id)), GetCrashReportDetailedArgument(data_flags), GetCrashReportScreenShotArgument(data_flags));
+ if (R_FAILED(ldr::SetProgramArgument(ncm::SystemProgramId::Creport, arguments, len + 1))) {
+ return;
+ }
+
+ /* Launch creport. */
+ os::ProcessId creport_process_id;
+ if (R_FAILED(pm::shell::LaunchProgram(std::addressof(creport_process_id), ncm::ProgramLocation::Make(ncm::SystemProgramId::Creport, ncm::StorageId::BuiltInSystem), pm::LaunchFlags_None))) {
+ return;
+ }
+
+ /* Set the globals. */
+ s_crashed_process_id = process_id;
+ s_creport_process_id = creport_process_id;
+ }
+
+ void HandleException(os::ProcessId process_id) {
+ if (g_enable_jit_debug) {
+ /* If jit debug is enabled, we want to try to launch snap shot dumper. */
+ ProcessData *data = nullptr;
+ {
+ std::scoped_lock lk(g_process_data_mutex);
+ data = FindProcessData(process_id);
+ }
+
+ /* If we're tracking the process, we can launch dumper. Otherwise we should just terminate. */
+ if (data != nullptr) {
+ TriggerSnapShotDumper(process_id);
+ } else {
+ TerminateProcess(process_id);
+ }
+ } else {
+ /* Otherwise, we want to launch creport. */
+ TriggerCrashReport(process_id);
+ }
+ }
+
+ void HandleExit(os::ProcessId process_id) {
+ std::scoped_lock lk(g_process_data_mutex);
+ if (auto *data = FindProcessData(process_id); data != nullptr) {
+ data->process_id = os::InvalidProcessId;
+ }
+ }
+
+ void OnProcessEvent(const pm::ProcessEventInfo &event_info) {
+ /* Determine if we're tracking the process. */
+ ProcessData *data = nullptr;
+ {
+ std::scoped_lock lk(g_process_data_mutex);
+ data = FindProcessData(event_info.process_id);
+ }
+
+ /* If we are, we're going to want to notify our listeners. */
+ if (data != nullptr) {
+ /* If we closed the process, note that. */
+ if (static_cast(event_info.event) == pm::ProcessEvent::Exited) {
+ HandleExit(event_info.process_id);
+ }
+
+ /* Notify all observers. */
+ std::scoped_lock lk(g_observer_list_mutex);
+ for (auto &observer : g_observer_list) {
+ observer.Notify(event_info);
+ }
+ }
+
+ /* If the process crashed, handle that. */
+ if (static_cast(event_info.event) == pm::ProcessEvent::Exception) {
+ HandleException(event_info.process_id);
+ }
+ }
+
void ProcessControlTask(void *) {
- /* TODO */
+ /* Get the process event event from pm. */
+ os::SystemEvent process_event;
+ R_ABORT_UNLESS(pm::shell::GetProcessEventEvent(std::addressof(process_event)));
+
+ while (true) {
+ /* Wait for an event to come in, and clear our signal. */
+ process_event.Wait();
+ process_event.Signal();
+
+ bool continue_getting_event = true;
+ while (continue_getting_event) {
+ /* Try to get an event info. */
+ pm::ProcessEventInfo event_info;
+ if (R_FAILED(pm::shell::GetProcessEventInfo(std::addressof(event_info)))) {
+ break;
+ }
+
+ /* Process the event. */
+ switch (static_cast(event_info.event)) {
+ case pm::ProcessEvent::None:
+ continue_getting_event = false;
+ break;
+ case pm::ProcessEvent::Exited:
+ case pm::ProcessEvent::Started:
+ case pm::ProcessEvent::Exception:
+ case pm::ProcessEvent::DebugRunning:
+ case pm::ProcessEvent::DebugBreak:
+ OnProcessEvent(event_info);
+ break;
+ AMS_UNREACHABLE_DEFAULT_CASE();
+ }
+ }
+ }
}
}
diff --git a/libraries/libstratosphere/source/pm/pm_shell_api.cpp b/libraries/libstratosphere/source/pm/pm_shell_api.cpp
index cee379611..dd3155edd 100644
--- a/libraries/libstratosphere/source/pm/pm_shell_api.cpp
+++ b/libraries/libstratosphere/source/pm/pm_shell_api.cpp
@@ -28,6 +28,18 @@ namespace ams::pm::shell {
return ::pmshellTerminateProcess(static_cast(process_id));
}
+ Result GetProcessEventEvent(os::SystemEvent *out) {
+ ::Event evt;
+ R_TRY(::pmshellGetProcessEventHandle(std::addressof(evt)));
+ out->Attach(evt.revent, true, svc::InvalidHandle, false, os::EventClearMode_ManualClear);
+ return ResultSuccess();
+ }
+
+ Result GetProcessEventInfo(ProcessEventInfo *out) {
+ static_assert(sizeof(*out) == sizeof(::PmProcessEventInfo));
+ return ::pmshellGetProcessEventInfo(reinterpret_cast<::PmProcessEventInfo *>(out));
+ }
+
Result GetApplicationProcessIdForShell(os::ProcessId *out) {
static_assert(sizeof(*out) == sizeof(u64));
return ::pmshellGetApplicationProcessIdForShell(reinterpret_cast(out));
diff --git a/libraries/libstratosphere/source/settings/impl/settings_error_report.cpp b/libraries/libstratosphere/source/settings/impl/settings_error_report.cpp
new file mode 100644
index 000000000..26e8ce588
--- /dev/null
+++ b/libraries/libstratosphere/source/settings/impl/settings_error_report.cpp
@@ -0,0 +1,26 @@
+/*
+ * 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
+#include "settings_error_report_impl.hpp"
+
+namespace ams::settings::impl {
+
+ Result GetErrorReportSharePermission(s32 *out) {
+ static_assert(sizeof(*out) == sizeof(::SetSysErrorReportSharePermission));
+ return ::setsysGetErrorReportSharePermission(reinterpret_cast<::SetSysErrorReportSharePermission *>(out));
+ }
+
+}
diff --git a/libraries/libstratosphere/source/settings/impl/settings_error_report_impl.hpp b/libraries/libstratosphere/source/settings/impl/settings_error_report_impl.hpp
new file mode 100644
index 000000000..6f791b17d
--- /dev/null
+++ b/libraries/libstratosphere/source/settings/impl/settings_error_report_impl.hpp
@@ -0,0 +1,23 @@
+/*
+ * 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
+
+namespace ams::settings::impl {
+
+ Result GetErrorReportSharePermission(s32 *out);
+
+}
diff --git a/libraries/libstratosphere/source/settings/settings_error_report.cpp b/libraries/libstratosphere/source/settings/settings_error_report.cpp
new file mode 100644
index 000000000..f1b8ff528
--- /dev/null
+++ b/libraries/libstratosphere/source/settings/settings_error_report.cpp
@@ -0,0 +1,27 @@
+/*
+ * 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
+#include "impl/settings_error_report_impl.hpp"
+
+namespace ams::settings::system {
+
+ ErrorReportSharePermission GetErrorReportSharePermission() {
+ s32 perm = 0;
+ R_ABORT_UNLESS(settings::impl::GetErrorReportSharePermission(std::addressof(perm)));
+ return static_cast(model);
+ }
+
+}