mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
creport: Try to take screenshot of application crashes on 9.x+
This commit is contained in:
parent
93e0c9194d
commit
6ac1ff6f24
9 changed files with 201 additions and 23 deletions
|
@ -19,3 +19,4 @@
|
||||||
#include <stratosphere/capsrv/capsrv_screen_shot_decode_option.hpp>
|
#include <stratosphere/capsrv/capsrv_screen_shot_decode_option.hpp>
|
||||||
#include <stratosphere/capsrv/server/capsrv_server_config.hpp>
|
#include <stratosphere/capsrv/server/capsrv_server_config.hpp>
|
||||||
#include <stratosphere/capsrv/server/capsrv_server_decoder_api.hpp>
|
#include <stratosphere/capsrv/server/capsrv_server_decoder_api.hpp>
|
||||||
|
#include <stratosphere/capsrv/capsrv_screen_shot_control_api.hpp>
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/vi/vi_layer_stack.hpp>
|
||||||
|
|
||||||
|
namespace ams::capsrv {
|
||||||
|
|
||||||
|
constexpr inline s32 DefaultCaptureTimeoutMilliSeconds = 100;
|
||||||
|
|
||||||
|
Result InitializeScreenShotControl();
|
||||||
|
void FinalizeScreenShotControl();
|
||||||
|
|
||||||
|
Result CaptureJpegScreenshot(u64 *out_size, void *dst, size_t dst_size, vi::LayerStack layer_stack, TimeSpan timeout);
|
||||||
|
|
||||||
|
}
|
19
libraries/libstratosphere/include/stratosphere/vi.hpp
Normal file
19
libraries/libstratosphere/include/stratosphere/vi.hpp
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stratosphere/vi/vi_layer_stack.hpp>
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
|
||||||
|
namespace ams::vi {
|
||||||
|
|
||||||
|
enum LayerStack {
|
||||||
|
LayerStack_Default = 0,
|
||||||
|
LayerStack_Lcd = 1,
|
||||||
|
LayerStack_Screenshot = 2,
|
||||||
|
LayerStack_Recording = 3,
|
||||||
|
LayerStack_LastFrame = 4,
|
||||||
|
LayerStack_Arbitrary = 5,
|
||||||
|
LayerStack_ApplicationForDebug = 6,
|
||||||
|
LayerStack_Null = 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::capsrv {
|
||||||
|
|
||||||
|
Result InitializeScreenShotControl() {
|
||||||
|
return ::capsscInitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FinalizeScreenShotControl() {
|
||||||
|
return ::capsscExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result CaptureJpegScreenshot(u64 *out_size, void *dst, size_t dst_size, vi::LayerStack layer_stack, TimeSpan timeout) {
|
||||||
|
return ::capsscCaptureJpegScreenShot(out_size, dst, dst_size, static_cast<::ViLayerStack>(layer_stack), timeout.GetNanoSeconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -20,6 +20,7 @@
|
||||||
"service_access": [
|
"service_access": [
|
||||||
"csrng",
|
"csrng",
|
||||||
"spl:",
|
"spl:",
|
||||||
|
"caps:sc",
|
||||||
"erpt:c",
|
"erpt:c",
|
||||||
"fatal:u",
|
"fatal:u",
|
||||||
"ns:dev",
|
"ns:dev",
|
||||||
|
|
|
@ -81,6 +81,19 @@ namespace ams::creport {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CrashReport::Initialize() {
|
||||||
|
/* Initialize the heap. */
|
||||||
|
this->heap_handle = lmem::CreateExpHeap(this->heap_storage, sizeof(this->heap_storage), lmem::CreateOption_None);
|
||||||
|
|
||||||
|
/* Allocate members. */
|
||||||
|
this->module_list = new (lmem::AllocateFromExpHeap(this->heap_handle, sizeof(ModuleList))) ModuleList;
|
||||||
|
this->thread_list = new (lmem::AllocateFromExpHeap(this->heap_handle, sizeof(ThreadList))) ThreadList;
|
||||||
|
this->dying_message = static_cast<u8 *>(lmem::AllocateFromExpHeap(this->heap_handle, DyingMessageSizeMax));
|
||||||
|
if (this->dying_message != nullptr) {
|
||||||
|
std::memset(this->dying_message, 0, DyingMessageSizeMax);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CrashReport::BuildReport(os::ProcessId process_id, bool has_extra_info) {
|
void CrashReport::BuildReport(os::ProcessId process_id, bool has_extra_info) {
|
||||||
this->has_extra_info = has_extra_info;
|
this->has_extra_info = has_extra_info;
|
||||||
|
|
||||||
|
@ -89,12 +102,12 @@ namespace ams::creport {
|
||||||
|
|
||||||
/* Parse info from the crashed process. */
|
/* Parse info from the crashed process. */
|
||||||
this->ProcessExceptions();
|
this->ProcessExceptions();
|
||||||
this->module_list.FindModulesFromThreadInfo(this->debug_handle, this->crashed_thread);
|
this->module_list->FindModulesFromThreadInfo(this->debug_handle, this->crashed_thread);
|
||||||
this->thread_list.ReadFromProcess(this->debug_handle, this->thread_tls_map, this->Is64Bit());
|
this->thread_list->ReadFromProcess(this->debug_handle, this->thread_tls_map, this->Is64Bit());
|
||||||
|
|
||||||
/* Associate module list to threads. */
|
/* Associate module list to threads. */
|
||||||
this->crashed_thread.SetModuleList(&this->module_list);
|
this->crashed_thread.SetModuleList(this->module_list);
|
||||||
this->thread_list.SetModuleList(&this->module_list);
|
this->thread_list->SetModuleList(this->module_list);
|
||||||
|
|
||||||
/* Process dying message for applications. */
|
/* Process dying message for applications. */
|
||||||
if (this->IsApplication()) {
|
if (this->IsApplication()) {
|
||||||
|
@ -103,8 +116,13 @@ namespace ams::creport {
|
||||||
|
|
||||||
/* Nintendo's creport finds extra modules by looking at all threads if application, */
|
/* Nintendo's creport finds extra modules by looking at all threads if application, */
|
||||||
/* but there's no reason for us not to always go looking. */
|
/* but there's no reason for us not to always go looking. */
|
||||||
for (size_t i = 0; i < this->thread_list.GetThreadCount(); i++) {
|
for (size_t i = 0; i < this->thread_list->GetThreadCount(); i++) {
|
||||||
this->module_list.FindModulesFromThreadInfo(this->debug_handle, this->thread_list.GetThreadInfo(i));
|
this->module_list->FindModulesFromThreadInfo(this->debug_handle, this->thread_list->GetThreadInfo(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cache the module base address to send to fatal. */
|
||||||
|
if (this->module_list->GetModuleCount()) {
|
||||||
|
this->module_base_address = this->module_list->GetModuleStartAddress(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Nintendo's creport saves the report to erpt here, but we'll save to SD card later. */
|
/* Nintendo's creport saves the report to erpt here, but we'll save to SD card later. */
|
||||||
|
@ -133,8 +151,8 @@ namespace ams::creport {
|
||||||
out->aarch64_ctx.stack_trace[i] = this->crashed_thread.GetStackTrace(i);
|
out->aarch64_ctx.stack_trace[i] = this->crashed_thread.GetStackTrace(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->module_list.GetModuleCount()) {
|
if (this->module_base_address != 0) {
|
||||||
out->aarch64_ctx.SetBaseAddress(this->module_list.GetModuleStartAddress(0));
|
out->aarch64_ctx.SetBaseAddress(this->module_base_address);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For ams fatal, which doesn't use afsr0, pass program_id instead. */
|
/* For ams fatal, which doesn't use afsr0, pass program_id instead. */
|
||||||
|
@ -194,7 +212,7 @@ namespace ams::creport {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Cap userdata size. */
|
/* Cap userdata size. */
|
||||||
userdata_size = std::min(size_t(userdata_size), sizeof(this->dying_message));
|
userdata_size = std::min(size_t(userdata_size), DyingMessageSizeMax);
|
||||||
|
|
||||||
this->dying_message_address = userdata_address;
|
this->dying_message_address = userdata_address;
|
||||||
this->dying_message_size = userdata_size;
|
this->dying_message_size = userdata_size;
|
||||||
|
@ -253,7 +271,7 @@ namespace ams::creport {
|
||||||
if (this->dying_message_address == 0 || this->dying_message_address & 0xFFF) {
|
if (this->dying_message_address == 0 || this->dying_message_address & 0xFFF) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this->dying_message_size > sizeof(this->dying_message)) {
|
if (this->dying_message_size > DyingMessageSizeMax) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,6 +280,11 @@ namespace ams::creport {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Verify that we have a dying message buffer. */
|
||||||
|
if (this->dying_message == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Read the dying message. */
|
/* Read the dying message. */
|
||||||
svcReadDebugProcessMemory(this->dying_message, this->debug_handle, this->dying_message_address, this->dying_message_size);
|
svcReadDebugProcessMemory(this->dying_message, this->debug_handle, this->dying_message_address, this->dying_message_size);
|
||||||
}
|
}
|
||||||
|
@ -294,7 +317,34 @@ namespace ams::creport {
|
||||||
{
|
{
|
||||||
ScopedFile file(file_path);
|
ScopedFile file(file_path);
|
||||||
if (file.IsOpen()) {
|
if (file.IsOpen()) {
|
||||||
this->thread_list.DumpBinary(file, this->crashed_thread.GetThreadId());
|
this->thread_list->DumpBinary(file, this->crashed_thread.GetThreadId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finalize our heap. */
|
||||||
|
this->module_list->~ModuleList();
|
||||||
|
this->thread_list->~ThreadList();
|
||||||
|
lmem::FreeToExpHeap(this->heap_handle, this->module_list);
|
||||||
|
lmem::FreeToExpHeap(this->heap_handle, this->thread_list);
|
||||||
|
if (this->dying_message != nullptr) {
|
||||||
|
lmem::FreeToExpHeap(this->heap_handle, this->dying_message);
|
||||||
|
}
|
||||||
|
this->module_list = nullptr;
|
||||||
|
this->thread_list = nullptr;
|
||||||
|
this->dying_message = nullptr;
|
||||||
|
|
||||||
|
/* Try to take a screenshot. */
|
||||||
|
if (hos::GetVersion() >= hos::Version_9_0_0 && this->IsApplication()) {
|
||||||
|
sm::ScopedServiceHolder<capsrv::InitializeScreenShotControl, capsrv::FinalizeScreenShotControl> capssc_holder;
|
||||||
|
if (capssc_holder) {
|
||||||
|
u64 jpeg_size;
|
||||||
|
if (R_SUCCEEDED(capsrv::CaptureJpegScreenshot(std::addressof(jpeg_size), this->heap_storage, sizeof(this->heap_storage), vi::LayerStack_ApplicationForDebug, TimeSpan::FromSeconds(10)))) {
|
||||||
|
std::snprintf(file_path, sizeof(file_path), "sdmc:/atmosphere/crash_reports/%011lu_%016lx.jpg", timestamp, this->process_info.program_id);
|
||||||
|
ScopedFile file(file_path);
|
||||||
|
if (file.IsOpen()) {
|
||||||
|
file.Write(this->heap_storage, jpeg_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -314,13 +364,13 @@ namespace ams::creport {
|
||||||
file.WriteFormat(" Process ID: %016lx\n", this->process_info.process_id);
|
file.WriteFormat(" Process ID: %016lx\n", this->process_info.process_id);
|
||||||
file.WriteFormat(" Process Flags: %08x\n", this->process_info.flags);
|
file.WriteFormat(" Process Flags: %08x\n", this->process_info.flags);
|
||||||
if (hos::GetVersion() >= hos::Version_5_0_0) {
|
if (hos::GetVersion() >= hos::Version_5_0_0) {
|
||||||
file.WriteFormat(" User Exception Address: %s\n", this->module_list.GetFormattedAddressString(this->process_info.user_exception_context_address));
|
file.WriteFormat(" User Exception Address: %s\n", this->module_list->GetFormattedAddressString(this->process_info.user_exception_context_address));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Exception Info. */
|
/* Exception Info. */
|
||||||
file.WriteFormat("Exception Info:\n");
|
file.WriteFormat("Exception Info:\n");
|
||||||
file.WriteFormat(" Type: %s\n", GetDebugExceptionString(this->exception_info.type));
|
file.WriteFormat(" Type: %s\n", GetDebugExceptionString(this->exception_info.type));
|
||||||
file.WriteFormat(" Address: %s\n", this->module_list.GetFormattedAddressString(this->exception_info.address));
|
file.WriteFormat(" Address: %s\n", this->module_list->GetFormattedAddressString(this->exception_info.address));
|
||||||
switch (this->exception_info.type) {
|
switch (this->exception_info.type) {
|
||||||
case svc::DebugException_UndefinedInstruction:
|
case svc::DebugException_UndefinedInstruction:
|
||||||
file.WriteFormat(" Opcode: %08x\n", this->exception_info.specific.undefined_instruction.insn);
|
file.WriteFormat(" Opcode: %08x\n", this->exception_info.specific.undefined_instruction.insn);
|
||||||
|
@ -328,7 +378,7 @@ namespace ams::creport {
|
||||||
case svc::DebugException_DataAbort:
|
case svc::DebugException_DataAbort:
|
||||||
case svc::DebugException_AlignmentFault:
|
case svc::DebugException_AlignmentFault:
|
||||||
if (this->exception_info.specific.raw != this->exception_info.address) {
|
if (this->exception_info.specific.raw != this->exception_info.address) {
|
||||||
file.WriteFormat(" Fault Address: %s\n", this->module_list.GetFormattedAddressString(this->exception_info.specific.raw));
|
file.WriteFormat(" Fault Address: %s\n", this->module_list->GetFormattedAddressString(this->exception_info.specific.raw));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case svc::DebugException_UndefinedSystemCall:
|
case svc::DebugException_UndefinedSystemCall:
|
||||||
|
@ -336,7 +386,7 @@ namespace ams::creport {
|
||||||
break;
|
break;
|
||||||
case svc::DebugException_UserBreak:
|
case svc::DebugException_UserBreak:
|
||||||
file.WriteFormat(" Break Reason: 0x%x\n", this->exception_info.specific.user_break.break_reason);
|
file.WriteFormat(" Break Reason: 0x%x\n", this->exception_info.specific.user_break.break_reason);
|
||||||
file.WriteFormat(" Break Address: %s\n", this->module_list.GetFormattedAddressString(this->exception_info.specific.user_break.address));
|
file.WriteFormat(" Break Address: %s\n", this->module_list->GetFormattedAddressString(this->exception_info.specific.user_break.address));
|
||||||
file.WriteFormat(" Break Size: 0x%lx\n", this->exception_info.specific.user_break.size);
|
file.WriteFormat(" Break Size: 0x%lx\n", this->exception_info.specific.user_break.size);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -350,18 +400,18 @@ namespace ams::creport {
|
||||||
/* Dying Message. */
|
/* Dying Message. */
|
||||||
if (hos::GetVersion() >= hos::Version_5_0_0 && this->dying_message_size != 0) {
|
if (hos::GetVersion() >= hos::Version_5_0_0 && this->dying_message_size != 0) {
|
||||||
file.WriteFormat("Dying Message Info:\n");
|
file.WriteFormat("Dying Message Info:\n");
|
||||||
file.WriteFormat(" Address: 0x%s\n", this->module_list.GetFormattedAddressString(this->dying_message_address));
|
file.WriteFormat(" Address: 0x%s\n", this->module_list->GetFormattedAddressString(this->dying_message_address));
|
||||||
file.WriteFormat(" Size: 0x%016lx\n", this->dying_message_size);
|
file.WriteFormat(" Size: 0x%016lx\n", this->dying_message_size);
|
||||||
file.DumpMemory( " Dying Message: ", this->dying_message, this->dying_message_size);
|
file.DumpMemory( " Dying Message: ", this->dying_message, this->dying_message_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Module Info. */
|
/* Module Info. */
|
||||||
file.WriteFormat("Module Info:\n");
|
file.WriteFormat("Module Info:\n");
|
||||||
this->module_list.SaveToFile(file);
|
this->module_list->SaveToFile(file);
|
||||||
|
|
||||||
/* Thread Info. */
|
/* Thread Info. */
|
||||||
file.WriteFormat("Thread Report:\n");
|
file.WriteFormat("Thread Report:\n");
|
||||||
this->thread_list.SaveToFile(file);
|
this->thread_list->SaveToFile(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,28 +22,35 @@ namespace ams::creport {
|
||||||
class CrashReport {
|
class CrashReport {
|
||||||
private:
|
private:
|
||||||
static constexpr size_t DyingMessageSizeMax = os::MemoryPageSize;
|
static constexpr size_t DyingMessageSizeMax = os::MemoryPageSize;
|
||||||
|
static constexpr size_t MemoryHeapSize = 512_KB;
|
||||||
|
static_assert(MemoryHeapSize >= DyingMessageSizeMax + sizeof(ModuleList) + sizeof(ThreadList) + os::MemoryPageSize);
|
||||||
private:
|
private:
|
||||||
Handle debug_handle = INVALID_HANDLE;
|
Handle debug_handle = INVALID_HANDLE;
|
||||||
bool has_extra_info = true;
|
bool has_extra_info = true;
|
||||||
Result result = ResultIncompleteReport();
|
Result result = ResultIncompleteReport();
|
||||||
|
|
||||||
|
/* Meta, used for building module/thread list. */
|
||||||
|
std::map<u64, u64> thread_tls_map;
|
||||||
|
|
||||||
/* Attach process info. */
|
/* Attach process info. */
|
||||||
svc::DebugInfoAttachProcess process_info = {};
|
svc::DebugInfoAttachProcess process_info = {};
|
||||||
u64 dying_message_address = 0;
|
u64 dying_message_address = 0;
|
||||||
u64 dying_message_size = 0;
|
u64 dying_message_size = 0;
|
||||||
u8 dying_message[DyingMessageSizeMax] = {};
|
u8 *dying_message = nullptr;
|
||||||
|
|
||||||
/* Exception info. */
|
/* Exception info. */
|
||||||
svc::DebugInfoException exception_info = {};
|
svc::DebugInfoException exception_info = {};
|
||||||
|
u64 module_base_address = 0;
|
||||||
u64 crashed_thread_id = 0;
|
u64 crashed_thread_id = 0;
|
||||||
ThreadInfo crashed_thread;
|
ThreadInfo crashed_thread;
|
||||||
|
|
||||||
/* Lists. */
|
/* Lists. */
|
||||||
ModuleList module_list;
|
ModuleList *module_list = nullptr;
|
||||||
ThreadList thread_list;
|
ThreadList *thread_list = nullptr;
|
||||||
|
|
||||||
/* Meta, used for building module/thread list. */
|
/* Memory heap. */
|
||||||
std::map<u64, u64> thread_tls_map;
|
lmem::HeapHandle heap_handle;
|
||||||
|
u8 heap_storage[MemoryHeapSize];
|
||||||
public:
|
public:
|
||||||
Result GetResult() const {
|
Result GetResult() const {
|
||||||
return this->result;
|
return this->result;
|
||||||
|
@ -80,6 +87,8 @@ namespace ams::creport {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Initialize();
|
||||||
|
|
||||||
void BuildReport(os::ProcessId process_id, bool has_extra_info);
|
void BuildReport(os::ProcessId process_id, bool has_extra_info);
|
||||||
void GetFatalContext(::FatalCpuContext *out) const;
|
void GetFatalContext(::FatalCpuContext *out) const;
|
||||||
void SaveReport();
|
void SaveReport();
|
||||||
|
|
|
@ -102,6 +102,9 @@ int main(int argc, char **argv) {
|
||||||
/* Parse crashed PID. */
|
/* Parse crashed PID. */
|
||||||
os::ProcessId crashed_pid = creport::ParseProcessIdArgument(argv[0]);
|
os::ProcessId crashed_pid = creport::ParseProcessIdArgument(argv[0]);
|
||||||
|
|
||||||
|
/* Initialize the crash report. */
|
||||||
|
g_crash_report.Initialize();
|
||||||
|
|
||||||
/* Try to debug the crashed process. */
|
/* Try to debug the crashed process. */
|
||||||
g_crash_report.BuildReport(crashed_pid, argv[1][0] == '1');
|
g_crash_report.BuildReport(crashed_pid, argv[1][0] == '1');
|
||||||
if (!g_crash_report.IsComplete()) {
|
if (!g_crash_report.IsComplete()) {
|
||||||
|
|
Loading…
Reference in a new issue