creport: Complete crash report saving.
This commit is contained in:
@@ -7,43 +7,6 @@
|
||||
#include "creport_crash_report.hpp"
|
||||
#include "creport_debug_types.hpp"
|
||||
|
||||
void CrashReport::EnsureReportDirectories() {
|
||||
char path[FS_MAX_PATH];
|
||||
strcpy(path, "sdmc:/atmosphere");
|
||||
mkdir(path, S_IRWXU);
|
||||
strcat(path, "/crash reports");
|
||||
mkdir(path, S_IRWXU);
|
||||
strcat(path, "/dumps");
|
||||
mkdir(path, S_IRWXU);
|
||||
}
|
||||
|
||||
void CrashReport::SaveReport() {
|
||||
/* TODO: Save the report to the SD card. */
|
||||
char report_path[FS_MAX_PATH];
|
||||
|
||||
/* Ensure path exists. */
|
||||
EnsureReportDirectories();
|
||||
|
||||
/* Get a timestamp. */
|
||||
u64 timestamp;
|
||||
if (!GetCurrentTime(×tamp)) {
|
||||
timestamp = svcGetSystemTick();
|
||||
}
|
||||
|
||||
/* Open report file. */
|
||||
snprintf(report_path, sizeof(report_path) - 1, "sdmc:/atmosphere/crash reports/%020lu_%016lx.log", timestamp, process_info.title_id);
|
||||
FILE *f_report = fopen(report_path, "w");
|
||||
if (f_report == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(f_report, "Atmosphere Crash Report:\n");
|
||||
|
||||
/* TODO: Actually report about the crash. */
|
||||
|
||||
fclose(f_report);
|
||||
}
|
||||
|
||||
void CrashReport::BuildReport(u64 pid, bool has_extra_info) {
|
||||
this->has_extra_info = has_extra_info;
|
||||
if (OpenProcess(pid)) {
|
||||
@@ -125,14 +88,13 @@ void CrashReport::HandleAttachProcess(DebugEventInfo &d) {
|
||||
}
|
||||
|
||||
void CrashReport::HandleException(DebugEventInfo &d) {
|
||||
this->exception_info = d.info.exception;
|
||||
switch (d.info.exception.type) {
|
||||
case DebugExceptionType::UndefinedInstruction:
|
||||
this->result = (Result)CrashReportResult::UndefinedInstruction;
|
||||
break;
|
||||
case DebugExceptionType::InstructionAbort:
|
||||
this->result = (Result)CrashReportResult::InstructionAbort;
|
||||
this->exception_info.specific.raw = 0;
|
||||
d.info.exception.specific.raw = 0;
|
||||
break;
|
||||
case DebugExceptionType::DataAbort:
|
||||
this->result = (Result)CrashReportResult::DataAbort;
|
||||
@@ -143,8 +105,8 @@ void CrashReport::HandleException(DebugEventInfo &d) {
|
||||
case DebugExceptionType::UserBreak:
|
||||
this->result = (Result)CrashReportResult::UserBreak;
|
||||
/* Try to parse out the user break result. */
|
||||
if (kernelAbove500() && IsAddressReadable(this->exception_info.specific.user_break.address, sizeof(this->result))) {
|
||||
svcReadDebugProcessMemory(&this->result, this->debug_handle, this->exception_info.specific.user_break.address, sizeof(this->result));
|
||||
if (kernelAbove500() && IsAddressReadable(d.info.exception.specific.user_break.address, sizeof(this->result))) {
|
||||
svcReadDebugProcessMemory(&this->result, this->debug_handle, d.info.exception.specific.user_break.address, sizeof(this->result));
|
||||
}
|
||||
break;
|
||||
case DebugExceptionType::BadSvc:
|
||||
@@ -152,7 +114,7 @@ void CrashReport::HandleException(DebugEventInfo &d) {
|
||||
break;
|
||||
case DebugExceptionType::UnknownNine:
|
||||
this->result = (Result)CrashReportResult::UnknownNine;
|
||||
this->exception_info.specific.raw = 0;
|
||||
d.info.exception.specific.raw = 0;
|
||||
break;
|
||||
case DebugExceptionType::DebuggerAttached:
|
||||
case DebugExceptionType::BreakPoint:
|
||||
@@ -160,6 +122,7 @@ void CrashReport::HandleException(DebugEventInfo &d) {
|
||||
default:
|
||||
return;
|
||||
}
|
||||
this->exception_info = d.info.exception;
|
||||
/* Parse crashing thread info. */
|
||||
this->crashed_thread_info.ReadFromProcess(this->debug_handle, d.thread_id, Is64Bit());
|
||||
}
|
||||
@@ -237,3 +200,121 @@ bool CrashReport::GetCurrentTime(u64 *out) {
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
void CrashReport::EnsureReportDirectories() {
|
||||
char path[FS_MAX_PATH];
|
||||
strcpy(path, "sdmc:/atmosphere");
|
||||
mkdir(path, S_IRWXU);
|
||||
strcat(path, "/crash reports");
|
||||
mkdir(path, S_IRWXU);
|
||||
strcat(path, "/dumps");
|
||||
mkdir(path, S_IRWXU);
|
||||
}
|
||||
|
||||
void CrashReport::SaveReport() {
|
||||
/* TODO: Save the report to the SD card. */
|
||||
char report_path[FS_MAX_PATH];
|
||||
|
||||
/* Ensure path exists. */
|
||||
EnsureReportDirectories();
|
||||
|
||||
/* Get a timestamp. */
|
||||
u64 timestamp;
|
||||
if (!GetCurrentTime(×tamp)) {
|
||||
timestamp = svcGetSystemTick();
|
||||
}
|
||||
|
||||
/* Open report file. */
|
||||
snprintf(report_path, sizeof(report_path) - 1, "sdmc:/atmosphere/crash reports/%011lu_%016lx.log", timestamp, process_info.title_id);
|
||||
FILE *f_report = fopen(report_path, "w");
|
||||
if (f_report == NULL) {
|
||||
return;
|
||||
}
|
||||
this->SaveToFile(f_report);
|
||||
fclose(f_report);
|
||||
|
||||
/* Dump threads. */
|
||||
snprintf(report_path, sizeof(report_path) - 1, "sdmc:/atmosphere/crash reports/dumps/%011lu_%016lx_thread_info.bin", timestamp, process_info.title_id);
|
||||
f_report = fopen(report_path, "wb");
|
||||
this->thread_list.DumpBinary(f_report, this->crashed_thread_info.GetId());
|
||||
fclose(f_report);
|
||||
}
|
||||
|
||||
void CrashReport::SaveToFile(FILE *f_report) {
|
||||
char buf[0x10] = {0};
|
||||
fprintf(f_report, "Atmosphère Crash Report (v1.0):\n");
|
||||
fprintf(f_report, "Result: 0x%X (2%03d-%04d)\n\n", this->result, R_MODULE(this->result), R_DESCRIPTION(this->result));
|
||||
|
||||
/* Process Info. */
|
||||
memcpy(buf, this->process_info.name, sizeof(this->process_info.name));
|
||||
fprintf(f_report, "Process Info:\n");
|
||||
fprintf(f_report, " Process Name: %s\n", buf);
|
||||
fprintf(f_report, " Title ID: %016lx\n", this->process_info.title_id);
|
||||
fprintf(f_report, " Process ID: %016lx\n", this->process_info.process_id);
|
||||
fprintf(f_report, " Process Flags: %08x\n", this->process_info.flags);
|
||||
if (kernelAbove500()) {
|
||||
fprintf(f_report, " User Exception Address: %016lx\n", this->process_info.user_exception_context_address);
|
||||
}
|
||||
|
||||
fprintf(f_report, "Exception Info:\n");
|
||||
fprintf(f_report, " Type: %s\n", GetDebugExceptionTypeStr(this->exception_info.type));
|
||||
fprintf(f_report, " Address: %016lx\n", this->exception_info.address);
|
||||
switch (this->exception_info.type) {
|
||||
case DebugExceptionType::UndefinedInstruction:
|
||||
fprintf(f_report, " Opcode: %08x\n", this->exception_info.specific.undefined_instruction.insn);
|
||||
break;
|
||||
case DebugExceptionType::DataAbort:
|
||||
case DebugExceptionType::AlignmentFault:
|
||||
if (this->exception_info.specific.raw != this->exception_info.address) {
|
||||
fprintf(f_report, " Fault Address: %016lx\n", this->exception_info.specific.raw);
|
||||
}
|
||||
break;
|
||||
case DebugExceptionType::BadSvc:
|
||||
fprintf(f_report, " Svc Id: 0x%02x\n", this->exception_info.specific.bad_svc.id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(f_report, "Crashed Thread Info:\n");
|
||||
this->crashed_thread_info.SaveToFile(f_report);
|
||||
|
||||
if (kernelAbove500()) {
|
||||
fprintf(f_report, "Code Region Info:\n");
|
||||
this->code_list.SaveToFile(f_report);
|
||||
fprintf(f_report, "\nThread Report:\n");
|
||||
this->thread_list.SaveToFile(f_report);
|
||||
}
|
||||
}
|
||||
|
||||
/* Lifted from hactool. */
|
||||
void CrashReport::Memdump(FILE *f, const char *prefix, const void *data, size_t size) {
|
||||
uint8_t *p = (uint8_t *)data;
|
||||
|
||||
unsigned int prefix_len = strlen(prefix);
|
||||
size_t offset = 0;
|
||||
int first = 1;
|
||||
|
||||
while (size) {
|
||||
unsigned int max = 32;
|
||||
|
||||
if (max > size) {
|
||||
max = size;
|
||||
}
|
||||
|
||||
if (first) {
|
||||
fprintf(f, "%s", prefix);
|
||||
first = 0;
|
||||
} else {
|
||||
fprintf(f, "%*s", prefix_len, "");
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < max; i++) {
|
||||
fprintf(f, "%02X", p[offset++]);
|
||||
}
|
||||
|
||||
fprintf(f, "\n");
|
||||
|
||||
size -= max;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user