mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-10 07:06:34 +00:00
creport: dump tls/name on crash (closes #310)
This commit is contained in:
parent
5f5a8567ce
commit
766097d0b7
8 changed files with 195 additions and 141 deletions
|
@ -28,7 +28,7 @@ void CrashReport::BuildReport(u64 pid, bool has_extra_info) {
|
||||||
if (OpenProcess(pid)) {
|
if (OpenProcess(pid)) {
|
||||||
ProcessExceptions();
|
ProcessExceptions();
|
||||||
this->code_list.ReadCodeRegionsFromThreadInfo(this->debug_handle, &this->crashed_thread_info);
|
this->code_list.ReadCodeRegionsFromThreadInfo(this->debug_handle, &this->crashed_thread_info);
|
||||||
this->thread_list.ReadThreadsFromProcess(this->debug_handle, Is64Bit());
|
this->thread_list.ReadThreadsFromProcess(this->thread_tls_map, this->debug_handle, Is64Bit());
|
||||||
this->crashed_thread_info.SetCodeList(&this->code_list);
|
this->crashed_thread_info.SetCodeList(&this->code_list);
|
||||||
this->thread_list.SetCodeList(&this->code_list);
|
this->thread_list.SetCodeList(&this->code_list);
|
||||||
|
|
||||||
|
@ -91,12 +91,16 @@ void CrashReport::ProcessExceptions() {
|
||||||
HandleException(d);
|
HandleException(d);
|
||||||
break;
|
break;
|
||||||
case DebugEventType::AttachThread:
|
case DebugEventType::AttachThread:
|
||||||
|
HandleAttachThread(d);
|
||||||
case DebugEventType::ExitProcess:
|
case DebugEventType::ExitProcess:
|
||||||
case DebugEventType::ExitThread:
|
case DebugEventType::ExitThread:
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parse crashing thread info. */
|
||||||
|
this->crashed_thread_info.ReadFromProcess(this->thread_tls_map, this->debug_handle, this->crashed_thread_id, Is64Bit());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CrashReport::HandleAttachProcess(DebugEventInfo &d) {
|
void CrashReport::HandleAttachProcess(DebugEventInfo &d) {
|
||||||
|
@ -180,8 +184,11 @@ void CrashReport::HandleException(DebugEventInfo &d) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this->exception_info = d.info.exception;
|
this->exception_info = d.info.exception;
|
||||||
/* Parse crashing thread info. */
|
this->crashed_thread_id = d.thread_id;
|
||||||
this->crashed_thread_info.ReadFromProcess(this->debug_handle, d.thread_id, Is64Bit());
|
}
|
||||||
|
|
||||||
|
void CrashReport::HandleAttachThread(DebugEventInfo &d) {
|
||||||
|
this->thread_tls_map[d.info.attach_thread.thread_id] = d.info.attach_thread.tls_address;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CrashReport::ProcessDyingMessage() {
|
void CrashReport::ProcessDyingMessage() {
|
||||||
|
@ -308,7 +315,7 @@ void CrashReport::SaveReport() {
|
||||||
|
|
||||||
void CrashReport::SaveToFile(FILE *f_report) {
|
void CrashReport::SaveToFile(FILE *f_report) {
|
||||||
char buf[0x10] = {0};
|
char buf[0x10] = {0};
|
||||||
fprintf(f_report, "Atmosphère Crash Report (v1.2):\n");
|
fprintf(f_report, "Atmosphère Crash Report (v1.3):\n");
|
||||||
fprintf(f_report, "Result: 0x%X (2%03d-%04d)\n\n", this->result, R_MODULE(this->result), R_DESCRIPTION(this->result));
|
fprintf(f_report, "Result: 0x%X (2%03d-%04d)\n\n", this->result, R_MODULE(this->result), R_DESCRIPTION(this->result));
|
||||||
|
|
||||||
/* Process Info. */
|
/* Process Info. */
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include "creport_debug_types.hpp"
|
#include "creport_debug_types.hpp"
|
||||||
#include "creport_thread_info.hpp"
|
#include "creport_thread_info.hpp"
|
||||||
|
@ -40,12 +41,16 @@ class CrashReport {
|
||||||
|
|
||||||
/* Exception Info. */
|
/* Exception Info. */
|
||||||
ExceptionInfo exception_info{};
|
ExceptionInfo exception_info{};
|
||||||
|
u64 crashed_thread_id = 0;
|
||||||
ThreadInfo crashed_thread_info;
|
ThreadInfo crashed_thread_info;
|
||||||
|
|
||||||
/* Extra Info. */
|
/* Extra Info. */
|
||||||
CodeList code_list;
|
CodeList code_list;
|
||||||
ThreadList thread_list;
|
ThreadList thread_list;
|
||||||
|
|
||||||
|
/* Meta, used for building list. */
|
||||||
|
std::map<u64, u64> thread_tls_map;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void BuildReport(u64 pid, bool has_extra_info);
|
void BuildReport(u64 pid, bool has_extra_info);
|
||||||
FatalContext *GetFatalContext();
|
FatalContext *GetFatalContext();
|
||||||
|
@ -94,6 +99,7 @@ class CrashReport {
|
||||||
void ProcessDyingMessage();
|
void ProcessDyingMessage();
|
||||||
void HandleAttachProcess(DebugEventInfo &d);
|
void HandleAttachProcess(DebugEventInfo &d);
|
||||||
void HandleException(DebugEventInfo &d);
|
void HandleException(DebugEventInfo &d);
|
||||||
|
void HandleAttachThread(DebugEventInfo &d);
|
||||||
|
|
||||||
void SaveToFile(FILE *f);
|
void SaveToFile(FILE *f);
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,9 @@
|
||||||
|
|
||||||
void ThreadInfo::SaveToFile(FILE *f_report) {
|
void ThreadInfo::SaveToFile(FILE *f_report) {
|
||||||
fprintf(f_report, " Thread ID: %016lx\n", this->thread_id);
|
fprintf(f_report, " Thread ID: %016lx\n", this->thread_id);
|
||||||
|
if (strcmp(name, "") != 0) {
|
||||||
|
fprintf(f_report, " Thread Name: %s\n", this->name);
|
||||||
|
}
|
||||||
if (stack_top) {
|
if (stack_top) {
|
||||||
fprintf(f_report, " Stack: %016lx-%016lx\n", this->stack_bottom, this->stack_top);
|
fprintf(f_report, " Stack: %016lx-%016lx\n", this->stack_bottom, this->stack_top);
|
||||||
}
|
}
|
||||||
|
@ -39,9 +42,19 @@ void ThreadInfo::SaveToFile(FILE *f_report) {
|
||||||
for (unsigned int i = 0; i < this->stack_trace_size; i++) {
|
for (unsigned int i = 0; i < this->stack_trace_size; i++) {
|
||||||
fprintf(f_report, " ReturnAddress[%02u]: %s\n", i, this->code_list->GetFormattedAddressString(this->stack_trace[i]));
|
fprintf(f_report, " ReturnAddress[%02u]: %s\n", i, this->code_list->GetFormattedAddressString(this->stack_trace[i]));
|
||||||
}
|
}
|
||||||
|
if (this->tls_address != 0) {
|
||||||
|
fprintf(f_report, " TLS Address: %016lx\n", this->tls_address);
|
||||||
|
fprintf(f_report, " TLS Dump: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
|
||||||
|
for (size_t i = 0; i < 0x10; i++) {
|
||||||
|
const u32 ofs = i * 0x10;
|
||||||
|
fprintf(f_report, " %012lx %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||||
|
this->tls_address + ofs, this->tls[ofs + 0], this->tls[ofs + 1], this->tls[ofs + 2], this->tls[ofs + 3], this->tls[ofs + 4], this->tls[ofs + 5], this->tls[ofs + 6], this->tls[ofs + 7],
|
||||||
|
this->tls[ofs + 8], this->tls[ofs + 9], this->tls[ofs + 10], this->tls[ofs + 11], this->tls[ofs + 12], this->tls[ofs + 13], this->tls[ofs + 14], this->tls[ofs + 15]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ThreadInfo::ReadFromProcess(Handle debug_handle, u64 thread_id, bool is_64_bit) {
|
bool ThreadInfo::ReadFromProcess(std::map<u64, u64> &tls_map, Handle debug_handle, u64 thread_id, bool is_64_bit) {
|
||||||
this->thread_id = thread_id;
|
this->thread_id = thread_id;
|
||||||
|
|
||||||
/* Verify that the thread is running or waiting. */
|
/* Verify that the thread is running or waiting. */
|
||||||
|
@ -67,6 +80,26 @@ bool ThreadInfo::ReadFromProcess(Handle debug_handle, u64 thread_id, bool is_64_
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parse information from TLS if present. */
|
||||||
|
if (tls_map.find(thread_id) != tls_map.end()) {
|
||||||
|
this->tls_address = tls_map[thread_id];
|
||||||
|
u8 thread_tls[0x200];
|
||||||
|
if (R_SUCCEEDED(svcReadDebugProcessMemory(thread_tls, debug_handle, this->tls_address, sizeof(thread_tls)))) {
|
||||||
|
std::memcpy(this->tls, thread_tls, sizeof(this->tls));
|
||||||
|
/* Try to detect libnx threads, and skip name parsing then. */
|
||||||
|
if (*(reinterpret_cast<u32 *>(&thread_tls[0x1E0])) != 0x21545624) {
|
||||||
|
u8 thread_type[0x1D0];
|
||||||
|
const u64 thread_type_addr = *(reinterpret_cast<u64 *>(&thread_tls[0x1F8]));
|
||||||
|
if (R_SUCCEEDED(svcReadDebugProcessMemory(thread_type, debug_handle, thread_type_addr, sizeof(thread_type)))) {
|
||||||
|
/* Check thread name is actually at thread name. */
|
||||||
|
if (*(reinterpret_cast<u64 *>(&thread_type[0x1A8])) == thread_type_addr + 0x188) {
|
||||||
|
std::memcpy(this->name, thread_type + 0x188, 0x20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Try to locate stack top/bottom. */
|
/* Try to locate stack top/bottom. */
|
||||||
TryGetStackInfo(debug_handle);
|
TryGetStackInfo(debug_handle);
|
||||||
|
|
||||||
|
@ -120,6 +153,10 @@ void ThreadInfo::DumpBinary(FILE *f_bin) {
|
||||||
fwrite(&this->thread_id, sizeof(this->thread_id), 1, f_bin);
|
fwrite(&this->thread_id, sizeof(this->thread_id), 1, f_bin);
|
||||||
fwrite(&this->context, sizeof(this->context), 1, f_bin);
|
fwrite(&this->context, sizeof(this->context), 1, f_bin);
|
||||||
|
|
||||||
|
fwrite(&this->tls_address, sizeof(this->tls_address), 1, f_bin);
|
||||||
|
fwrite(&this->tls, sizeof(this->tls), 1, f_bin);
|
||||||
|
fwrite(&this->name, sizeof(this->name), 1, f_bin);
|
||||||
|
|
||||||
u64 sts = this->stack_trace_size;
|
u64 sts = this->stack_trace_size;
|
||||||
fwrite(&sts, sizeof(sts), 1, f_bin);
|
fwrite(&sts, sizeof(sts), 1, f_bin);
|
||||||
fwrite(this->stack_trace, sizeof(u64), this->stack_trace_size, f_bin);
|
fwrite(this->stack_trace, sizeof(u64), this->stack_trace_size, f_bin);
|
||||||
|
@ -128,7 +165,7 @@ void ThreadInfo::DumpBinary(FILE *f_bin) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadList::DumpBinary(FILE *f_bin, u64 crashed_id) {
|
void ThreadList::DumpBinary(FILE *f_bin, u64 crashed_id) {
|
||||||
u32 magic = 0x30495444; /* 'DTI0' */
|
u32 magic = 0x31495444; /* 'DTI1' */
|
||||||
fwrite(&magic, sizeof(magic), 1, f_bin);
|
fwrite(&magic, sizeof(magic), 1, f_bin);
|
||||||
fwrite(&this->thread_count, sizeof(u32), 1, f_bin);
|
fwrite(&this->thread_count, sizeof(u32), 1, f_bin);
|
||||||
fwrite(&crashed_id, sizeof(crashed_id), 1, f_bin);
|
fwrite(&crashed_id, sizeof(crashed_id), 1, f_bin);
|
||||||
|
@ -145,7 +182,7 @@ void ThreadList::SaveToFile(FILE *f_report) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadList::ReadThreadsFromProcess(Handle debug_handle, bool is_64_bit) {
|
void ThreadList::ReadThreadsFromProcess(std::map<u64, u64> &tls_map, Handle debug_handle, bool is_64_bit) {
|
||||||
u32 thread_count;
|
u32 thread_count;
|
||||||
u64 thread_ids[max_thread_count];
|
u64 thread_ids[max_thread_count];
|
||||||
|
|
||||||
|
@ -159,7 +196,7 @@ void ThreadList::ReadThreadsFromProcess(Handle debug_handle, bool is_64_bit) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < thread_count; i++) {
|
for (unsigned int i = 0; i < thread_count; i++) {
|
||||||
if (this->thread_infos[this->thread_count].ReadFromProcess(debug_handle, thread_ids[this->thread_count], is_64_bit)) {
|
if (this->thread_infos[this->thread_count].ReadFromProcess(tls_map, debug_handle, thread_ids[this->thread_count], is_64_bit)) {
|
||||||
this->thread_count++;
|
this->thread_count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include "creport_debug_types.hpp"
|
#include "creport_debug_types.hpp"
|
||||||
|
|
||||||
|
@ -30,6 +31,9 @@ class ThreadInfo {
|
||||||
u64 stack_bottom = 0;
|
u64 stack_bottom = 0;
|
||||||
u64 stack_trace[0x20]{};
|
u64 stack_trace[0x20]{};
|
||||||
u32 stack_trace_size = 0;
|
u32 stack_trace_size = 0;
|
||||||
|
u64 tls_address = 0;
|
||||||
|
u8 tls[0x100]{};
|
||||||
|
char name[0x40]{};
|
||||||
CodeList *code_list;
|
CodeList *code_list;
|
||||||
public:
|
public:
|
||||||
u64 GetPC() const { return context.pc.x; }
|
u64 GetPC() const { return context.pc.x; }
|
||||||
|
@ -38,7 +42,7 @@ class ThreadInfo {
|
||||||
u32 GetStackTraceSize() const { return stack_trace_size; }
|
u32 GetStackTraceSize() const { return stack_trace_size; }
|
||||||
u64 GetStackTrace(u32 i) const { return stack_trace[i]; }
|
u64 GetStackTrace(u32 i) const { return stack_trace[i]; }
|
||||||
|
|
||||||
bool ReadFromProcess(Handle debug_handle, u64 thread_id, bool is_64_bit);
|
bool ReadFromProcess(std::map<u64, u64> &tls_map, Handle debug_handle, u64 thread_id, bool is_64_bit);
|
||||||
void SaveToFile(FILE *f_report);
|
void SaveToFile(FILE *f_report);
|
||||||
void DumpBinary(FILE *f_bin);
|
void DumpBinary(FILE *f_bin);
|
||||||
void SetCodeList(CodeList *cl) { this->code_list = cl; }
|
void SetCodeList(CodeList *cl) { this->code_list = cl; }
|
||||||
|
@ -57,7 +61,7 @@ class ThreadList {
|
||||||
|
|
||||||
void SaveToFile(FILE *f_report);
|
void SaveToFile(FILE *f_report);
|
||||||
void DumpBinary(FILE *f_bin, u64 crashed_id);
|
void DumpBinary(FILE *f_bin, u64 crashed_id);
|
||||||
void ReadThreadsFromProcess(Handle debug_handle, bool is_64_bit);
|
void ReadThreadsFromProcess(std::map<u64, u64> &tls_map, Handle debug_handle, bool is_64_bit);
|
||||||
void SetCodeList(CodeList *cl) {
|
void SetCodeList(CodeList *cl) {
|
||||||
for (u32 i = 0; i < thread_count; i++) {
|
for (u32 i = 0; i < thread_count; i++) {
|
||||||
thread_infos[i].SetCodeList(cl);
|
thread_infos[i].SetCodeList(cl);
|
||||||
|
|
Loading…
Reference in a new issue