creport: dump tls/name on crash (closes #310)

This commit is contained in:
Michael Scire 2019-05-25 13:32:34 -07:00
parent 5f5a8567ce
commit 766097d0b7
8 changed files with 195 additions and 141 deletions

View file

@ -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. */

View file

@ -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);

View file

@ -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++;
} }
} }

View file

@ -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);