creport: Read exception info properly (except for crashed thread info)

This commit is contained in:
Michael Scire 2018-06-25 02:18:26 -06:00
parent 4e7fcc1a50
commit 7cd44e8980
3 changed files with 62 additions and 19 deletions

View file

@ -43,23 +43,11 @@ void CrashReport::HandleAttachProcess(DebugEventInfo &d) {
this->process_info = d.info.attach_process; this->process_info = d.info.attach_process;
if (kernelAbove500() && IsApplication()) { if (kernelAbove500() && IsApplication()) {
/* Parse out user data. */ /* Parse out user data. */
MemoryInfo mi;
u32 pi;
u64 address = this->process_info.user_exception_context_address; u64 address = this->process_info.user_exception_context_address;
u64 userdata_address = 0; u64 userdata_address = 0;
u64 userdata_size = 0; u64 userdata_size = 0;
if (R_FAILED(svcQueryDebugProcessMemory(&mi, &pi, this->debug_handle, address))) { if (!IsAddressReadable(address, sizeof(userdata_address) + sizeof(userdata_size))) {
return;
}
/* Must be read or read-write */
if ((mi.perm | Perm_W) != Perm_Rw) {
return;
}
/* Must have space for both userdata address and userdata size. */
if (address < mi.addr || mi.addr + mi.size < address + 2 * sizeof(u64)) {
return; return;
} }
@ -90,20 +78,65 @@ void CrashReport::HandleAttachProcess(DebugEventInfo &d) {
} }
void CrashReport::HandleException(DebugEventInfo &d) { void CrashReport::HandleException(DebugEventInfo &d) {
this->exception_info = d.info.exception;
switch (d.info.exception.type) { switch (d.info.exception.type) {
case DebugExceptionType::UndefinedInstruction: case DebugExceptionType::UndefinedInstruction:
this->result = (Result)CrashReportResult::UndefinedInstruction;
break;
case DebugExceptionType::InstructionAbort: case DebugExceptionType::InstructionAbort:
this->result = (Result)CrashReportResult::InstructionAbort;
this->exception_info.specific.raw = 0;
break;
case DebugExceptionType::DataAbort: case DebugExceptionType::DataAbort:
this->result = (Result)CrashReportResult::DataAbort;
break;
case DebugExceptionType::AlignmentFault: case DebugExceptionType::AlignmentFault:
this->result = (Result)CrashReportResult::AlignmentFault;
break;
case DebugExceptionType::UserBreak: 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));
}
break;
case DebugExceptionType::BadSvc: case DebugExceptionType::BadSvc:
this->result = (Result)CrashReportResult::BadSvc;
break;
case DebugExceptionType::UnknownNine: case DebugExceptionType::UnknownNine:
/* TODO: Handle these exceptions...creport seems to discard all but the latest exception? */ this->result = (Result)CrashReportResult::UnknownNine;
this->exception_info.specific.raw = 0;
break; break;
case DebugExceptionType::DebuggerAttached: case DebugExceptionType::DebuggerAttached:
case DebugExceptionType::BreakPoint: case DebugExceptionType::BreakPoint:
case DebugExceptionType::DebuggerBreak: case DebugExceptionType::DebuggerBreak:
default: default:
break; return;
} }
/* TODO: Parse crashing thread info. */
}
bool CrashReport::IsAddressReadable(u64 address, u64 size, MemoryInfo *o_mi) {
MemoryInfo mi;
u32 pi;
if (o_mi == NULL) {
o_mi = &mi;
}
if (R_FAILED(svcQueryDebugProcessMemory(o_mi, &pi, this->debug_handle, address))) {
return false;
}
/* Must be read or read-write */
if ((o_mi->perm | Perm_W) != Perm_Rw) {
return false;
}
/* Must have space for both userdata address and userdata size. */
if (address < o_mi->addr || o_mi->addr + o_mi->size < address + size) {
return false;
}
return true;
} }

View file

@ -29,13 +29,18 @@ class CrashReport {
u64 userdata_5x_address; u64 userdata_5x_address;
u64 userdata_5x_size; u64 userdata_5x_size;
/* Exception Info. */
ExceptionInfo exception_info;
public: public:
CrashReport() : debug_handle(INVALID_HANDLE), result((Result)CrashReportResult::IncompleteReport), process_info({0}) { } CrashReport() : debug_handle(INVALID_HANDLE), result((Result)CrashReportResult::IncompleteReport), process_info({}), exception_info({}) { }
void BuildReport(u64 pid, bool has_extra_info); void BuildReport(u64 pid, bool has_extra_info);
void SaveReport(); void SaveReport();
void ProcessExceptions(); void ProcessExceptions();
bool IsAddressReadable(u64 address, u64 size, MemoryInfo *mi = NULL);
Result GetResult() { Result GetResult() {
return this->result; return this->result;
} }
@ -68,7 +73,7 @@ class CrashReport {
} }
bool IsUserBreak() { bool IsUserBreak() {
return this->result == (Result)CrashReportResult::UserBreak; return this->exception_info.type == DebugExceptionType::UserBreak;
} }
private: private:
void HandleAttachProcess(DebugEventInfo &d); void HandleAttachProcess(DebugEventInfo &d);

View file

@ -43,6 +43,12 @@ struct AlignmentFaultInfo {
u64 address; u64 address;
}; };
struct UserBreakInfo {
u64 info_0;
u64 address;
u64 size;
};
struct BadSvcInfo { struct BadSvcInfo {
u32 id; u32 id;
}; };
@ -51,12 +57,11 @@ union SpecificExceptionInfo {
UndefinedInstructionInfo undefined_instruction; UndefinedInstructionInfo undefined_instruction;
DataAbortInfo data_abort; DataAbortInfo data_abort;
AlignmentFaultInfo alignment_fault; AlignmentFaultInfo alignment_fault;
UserBreakInfo user_break;
BadSvcInfo bad_svc; BadSvcInfo bad_svc;
u64 raw; u64 raw;
}; };
static_assert(sizeof(SpecificExceptionInfo) == sizeof(u64), "Bad SpecificExceptionInfo definition!");
struct ExceptionInfo { struct ExceptionInfo {
DebugExceptionType type; DebugExceptionType type;
u64 address; u64 address;