creport: Implement process open, stub exception parsing.

This commit is contained in:
Michael Scire 2018-06-25 01:45:25 -06:00
parent 6ffc9bd8e0
commit 851d21a276
3 changed files with 207 additions and 3 deletions

View file

@ -1,10 +1,105 @@
#include <switch.h>
#include "creport_crash_report.hpp"
#include "creport_debug_types.hpp"
void CrashReport::BuildReport(u64 pid, bool has_extra_info) {
this->has_extra_info = has_extra_info;
if (OpenProcess(pid)) {
/* TODO: Actually generate report... */
ProcessExceptions();
/* TODO: More stuff here (sub_7100002260)... */
Close();
}
}
void CrashReport::ProcessExceptions() {
if (!IsOpen()) {
return;
}
DebugEventInfo d;
while (R_SUCCEEDED(svcGetDebugEvent((u8 *)&d, this->debug_handle))) {
switch (d.type) {
case DebugEventType::AttachProcess:
HandleAttachProcess(d);
break;
case DebugEventType::Exception:
HandleException(d);
break;
case DebugEventType::AttachThread:
case DebugEventType::ExitProcess:
case DebugEventType::ExitThread:
default:
break;
}
}
}
void CrashReport::HandleAttachProcess(DebugEventInfo &d) {
this->process_info = d.info.attach_process;
if (kernelAbove500() && IsApplication()) {
/* Parse out user data. */
MemoryInfo mi;
u32 pi;
u64 address = this->process_info.user_exception_context_address;
u64 userdata_address = 0;
u64 userdata_size = 0;
if (R_FAILED(svcQueryDebugProcessMemory(&mi, &pi, this->debug_handle, address))) {
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;
}
/* Read userdata address. */
if (R_FAILED(svcReadDebugProcessMemory(&userdata_address, this->debug_handle, address, sizeof(userdata_address)))) {
return;
}
/* Validate userdata address. */
if (userdata_address == 0 || userdata_address & 0xFFF) {
return;
}
/* Read userdata size. */
if (R_FAILED(svcReadDebugProcessMemory(&userdata_size, this->debug_handle, address + sizeof(userdata_address), sizeof(userdata_size)))) {
return;
}
/* Cap userdata size. */
if (userdata_size > 0x1000) {
userdata_size = 0x1000;
}
/* Assign. */
this->userdata_5x_address = userdata_address;
this->userdata_5x_size = userdata_size;
}
}
void CrashReport::HandleException(DebugEventInfo &d) {
switch (d.info.exception.type) {
case DebugExceptionType::UndefinedInstruction:
case DebugExceptionType::InstructionAbort:
case DebugExceptionType::DataAbort:
case DebugExceptionType::AlignmentFault:
case DebugExceptionType::UserBreak:
case DebugExceptionType::BadSvc:
case DebugExceptionType::UnknownNine:
/* TODO: Handle these exceptions...creport seems to discard all but the latest exception? */
break;
case DebugExceptionType::DebuggerAttached:
case DebugExceptionType::BreakPoint:
case DebugExceptionType::DebuggerBreak:
default:
break;
}
}

View file

@ -2,16 +2,24 @@
#include <switch.h>
#include "creport_debug_types.hpp"
class CrashReport {
private:
Handle debug_handle;
bool has_extra_info;
Result result;
/* Attach Process Info. */
AttachProcessInfo process_info;
u64 userdata_5x_address;
u64 userdata_5x_size;
public:
CrashReport() : debug_handle(INVALID_HANDLE), result(0x4A2) { }
CrashReport() : debug_handle(INVALID_HANDLE), result(0xC6A8), process_info({0}) { }
void BuildReport(u64 pid, bool has_extra_info);
void ProcessExceptions();
Result GetResult() {
return this->result;
@ -21,10 +29,25 @@ class CrashReport {
return R_SUCCEEDED(svcDebugActiveProcess(&debug_handle, pid));
}
bool IsOpen() {
return this->debug_handle != INVALID_HANDLE;
}
void Close() {
if (debug_handle != INVALID_HANDLE) {
if (IsOpen()) {
svcCloseHandle(debug_handle);
debug_handle = INVALID_HANDLE;
}
}
bool IsApplication() {
return (process_info.flags & 0x40) != 0;
}
bool Is64Bit() {
return (process_info.flags & 0x01) != 0;
}
private:
void HandleAttachProcess(DebugEventInfo &d);
void HandleException(DebugEventInfo &d);
};

View file

@ -0,0 +1,86 @@
#pragma once
#include <switch.h>
struct AttachProcessInfo {
u64 title_id;
u64 process_id;
char name[0xC];
u32 flags;
u64 user_exception_context_address; /* 5.0.0+ */
};
struct AttachThreadInfo {
u64 thread_id;
u64 tls_address;
u64 entrypoint;
};
/* TODO: ExitProcessInfo */
/* TODO: ExitThreadInfo */
enum class DebugExceptionType : u32 {
UndefinedInstruction = 0,
InstructionAbort = 1,
DataAbort = 2,
AlignmentFault = 3,
DebuggerAttached = 4,
BreakPoint = 5,
UserBreak = 6,
DebuggerBreak = 7,
BadSvc = 8,
UnknownNine = 9,
};
struct UndefinedInstructionInfo {
u32 insn;
};
struct DataAbortInfo {
u64 address;
};
struct AlignmentFaultInfo {
u64 address;
};
struct BadSvcInfo {
u32 id;
};
union SpecificExceptionInfo {
UndefinedInstructionInfo undefined_instruction;
DataAbortInfo data_abort;
AlignmentFaultInfo alignment_fault;
BadSvcInfo bad_svc;
u64 raw;
};
static_assert(sizeof(SpecificExceptionInfo) == sizeof(u64), "Bad SpecificExceptionInfo definition!");
struct ExceptionInfo {
DebugExceptionType type;
u64 address;
SpecificExceptionInfo specific;
};
enum class DebugEventType : u32 {
AttachProcess = 0,
AttachThread = 1,
ExitProcess = 2,
ExitThread = 3,
Exception = 4
};
union DebugInfo {
AttachProcessInfo attach_process;
AttachThreadInfo attach_thread;
ExceptionInfo exception;
};
struct DebugEventInfo {
DebugEventType type;
u32 flags;
u64 thread_id;
DebugInfo info;
};