mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 12:21:18 +00:00
fatal: include stack/tls in reports
This commit is contained in:
parent
2e8f06ef44
commit
846f610fff
4 changed files with 64 additions and 16 deletions
|
@ -327,7 +327,10 @@ namespace ams::fatal {
|
|||
Event erpt_event;
|
||||
Event battery_event;
|
||||
size_t stack_dump_size;
|
||||
u64 stack_dump_base;
|
||||
u8 stack_dump[0x100];
|
||||
u64 tls_address;
|
||||
u8 tls_dump[0x100];
|
||||
|
||||
void ClearState() {
|
||||
this->result = ResultSuccess();
|
||||
|
@ -339,7 +342,10 @@ namespace ams::fatal {
|
|||
std::memset(&this->erpt_event, 0, sizeof(this->erpt_event));
|
||||
std::memset(&this->battery_event, 0, sizeof(this->battery_event));
|
||||
this->stack_dump_size = 0;
|
||||
this->stack_dump_base = 0;
|
||||
std::memset(this->stack_dump, 0, sizeof(this->stack_dump));
|
||||
this->tls_address = 0;
|
||||
std::memset(this->tls_dump, 0, sizeof(this->tls_dump));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -20,55 +20,60 @@
|
|||
namespace ams::util {
|
||||
|
||||
/* Utilities for alignment to power of two. */
|
||||
template<typename T>
|
||||
constexpr ALWAYS_INLINE bool IsPowerOfTwo(T value) {
|
||||
using U = typename std::make_unsigned<T>::type;
|
||||
return (static_cast<U>(value) & static_cast<U>(value - 1)) == 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr inline T AlignUp(T value, size_t alignment) {
|
||||
constexpr ALWAYS_INLINE T AlignUp(T value, size_t alignment) {
|
||||
using U = typename std::make_unsigned<T>::type;
|
||||
const U invmask = static_cast<U>(alignment - 1);
|
||||
return static_cast<T>((value + invmask) & ~invmask);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr inline T AlignDown(T value, size_t alignment) {
|
||||
constexpr ALWAYS_INLINE T AlignDown(T value, size_t alignment) {
|
||||
using U = typename std::make_unsigned<T>::type;
|
||||
const U invmask = static_cast<U>(alignment - 1);
|
||||
return static_cast<T>(value & ~invmask);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr inline bool IsAligned(T value, size_t alignment) {
|
||||
constexpr ALWAYS_INLINE bool IsAligned(T value, size_t alignment) {
|
||||
using U = typename std::make_unsigned<T>::type;
|
||||
const U invmask = static_cast<U>(alignment - 1);
|
||||
return (value & invmask) == 0;
|
||||
}
|
||||
|
||||
template<>
|
||||
constexpr inline void *AlignUp<void *>(void *value, size_t alignment) {
|
||||
constexpr ALWAYS_INLINE void *AlignUp<void *>(void *value, size_t alignment) {
|
||||
return reinterpret_cast<void *>(AlignUp(reinterpret_cast<uintptr_t>(value), alignment));
|
||||
}
|
||||
|
||||
template<>
|
||||
constexpr inline const void *AlignUp<const void *>(const void *value, size_t alignment) {
|
||||
constexpr ALWAYS_INLINE const void *AlignUp<const void *>(const void *value, size_t alignment) {
|
||||
return reinterpret_cast<const void *>(AlignUp(reinterpret_cast<uintptr_t>(value), alignment));
|
||||
}
|
||||
|
||||
template<>
|
||||
constexpr inline void *AlignDown<void *>(void *value, size_t alignment) {
|
||||
constexpr ALWAYS_INLINE void *AlignDown<void *>(void *value, size_t alignment) {
|
||||
return reinterpret_cast<void *>(AlignDown(reinterpret_cast<uintptr_t>(value), alignment));
|
||||
}
|
||||
|
||||
template<>
|
||||
constexpr inline const void *AlignDown<const void *>(const void *value, size_t alignment) {
|
||||
constexpr ALWAYS_INLINE const void *AlignDown<const void *>(const void *value, size_t alignment) {
|
||||
return reinterpret_cast<void *>(AlignDown(reinterpret_cast<uintptr_t>(value), alignment));
|
||||
}
|
||||
|
||||
template<>
|
||||
constexpr inline bool IsAligned<void *>(void *value, size_t alignment) {
|
||||
constexpr ALWAYS_INLINE bool IsAligned<void *>(void *value, size_t alignment) {
|
||||
return IsAligned(reinterpret_cast<uintptr_t>(value), alignment);
|
||||
}
|
||||
|
||||
template<>
|
||||
constexpr inline bool IsAligned<const void *>(const void *value, size_t alignment) {
|
||||
constexpr ALWAYS_INLINE bool IsAligned<const void *>(const void *value, size_t alignment) {
|
||||
return IsAligned(reinterpret_cast<uintptr_t>(value), alignment);
|
||||
}
|
||||
|
||||
|
|
|
@ -209,6 +209,7 @@ namespace ams::fatal::srv {
|
|||
/* Welcome to hell. Here, we try to identify which thread called into fatal. */
|
||||
bool found_fatal_caller = false;
|
||||
u64 thread_id = 0;
|
||||
u64 thread_tls = 0;
|
||||
ThreadContext thread_ctx;
|
||||
{
|
||||
/* We start by trying to get a list of threads. */
|
||||
|
@ -227,6 +228,7 @@ namespace ams::fatal::srv {
|
|||
|
||||
if (IsThreadFatalCaller(ctx->result, debug_handle.Get(), cur_thread_id, thread_id_to_tls[cur_thread_id], &thread_ctx)) {
|
||||
thread_id = cur_thread_id;
|
||||
thread_tls = thread_id_to_tls[thread_id];
|
||||
found_fatal_caller = true;
|
||||
break;
|
||||
}
|
||||
|
@ -266,13 +268,23 @@ namespace ams::fatal::srv {
|
|||
}
|
||||
|
||||
/* Try to read up to 0x100 of stack. */
|
||||
ctx->stack_dump_base = 0;
|
||||
for (size_t sz = 0x100; sz > 0; sz -= 0x10) {
|
||||
if (R_SUCCEEDED(svcReadDebugProcessMemory(ctx->stack_dump, debug_handle.Get(), thread_ctx.sp, sz))) {
|
||||
ctx->stack_dump_base = thread_ctx.sp;
|
||||
ctx->stack_dump_size = sz;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to read the first 0x100 of TLS. */
|
||||
if (R_SUCCEEDED(svcReadDebugProcessMemory(ctx->tls_dump, debug_handle.Get(), thread_tls, sizeof(ctx->tls_dump)))) {
|
||||
ctx->tls_address = thread_tls;
|
||||
} else {
|
||||
ctx->tls_address = 0;
|
||||
std::memset(ctx->tls_dump, 0xCC, sizeof(ctx->tls_dump));
|
||||
}
|
||||
|
||||
/* Parse the base address. */
|
||||
ctx->cpu_ctx.aarch64_ctx.SetBaseAddress(GetBaseAddress(ctx, &thread_ctx, debug_handle.Get()));
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ namespace ams::fatal::srv {
|
|||
if (f_report != NULL) {
|
||||
ON_SCOPE_EXIT { fclose(f_report); };
|
||||
|
||||
fprintf(f_report, "Atmosphère Fatal Report (v1.0):\n");
|
||||
fprintf(f_report, "Atmosphère Fatal Report (v1.1):\n");
|
||||
fprintf(f_report, "Result: 0x%X (2%03d-%04d)\n\n", this->context->result.GetValue(), this->context->result.GetModule(), this->context->result.GetDescription());
|
||||
fprintf(f_report, "Program ID: %016lx\n", static_cast<u64>(this->context->program_id));
|
||||
if (strlen(this->context->proc_name)) {
|
||||
|
@ -114,16 +114,41 @@ namespace ams::fatal::srv {
|
|||
fprintf(f_report, " ReturnAddress[%02u]: %016lx\n", i, this->context->cpu_ctx.aarch64_ctx.stack_trace[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (this->context->stack_dump_size != 0) {
|
||||
fprintf(f_report, "Stack 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 size_t 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->context->stack_dump_base + ofs, this->context->stack_dump[ofs + 0], this->context->stack_dump[ofs + 1], this->context->stack_dump[ofs + 2], this->context->stack_dump[ofs + 3], this->context->stack_dump[ofs + 4], this->context->stack_dump[ofs + 5], this->context->stack_dump[ofs + 6], this->context->stack_dump[ofs + 7],
|
||||
this->context->stack_dump[ofs + 8], this->context->stack_dump[ofs + 9], this->context->stack_dump[ofs + 10], this->context->stack_dump[ofs + 11], this->context->stack_dump[ofs + 12], this->context->stack_dump[ofs + 13], this->context->stack_dump[ofs + 14], this->context->stack_dump[ofs + 15]);
|
||||
}
|
||||
}
|
||||
|
||||
if (this->context->tls_address != 0) {
|
||||
fprintf(f_report, "TLS Address: %016lx\n", this->context->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 size_t 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->context->tls_address + ofs, this->context->tls_dump[ofs + 0], this->context->tls_dump[ofs + 1], this->context->tls_dump[ofs + 2], this->context->tls_dump[ofs + 3], this->context->tls_dump[ofs + 4], this->context->tls_dump[ofs + 5], this->context->tls_dump[ofs + 6], this->context->tls_dump[ofs + 7],
|
||||
this->context->tls_dump[ofs + 8], this->context->tls_dump[ofs + 9], this->context->tls_dump[ofs + 10], this->context->tls_dump[ofs + 11], this->context->tls_dump[ofs + 12], this->context->tls_dump[ofs + 13], this->context->tls_dump[ofs + 14], this->context->tls_dump[ofs + 15]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this->context->stack_dump_size) {
|
||||
/* Dump data to file. */
|
||||
{
|
||||
snprintf(file_path, sizeof(file_path) - 1, "sdmc:/atmosphere/fatal_reports/dumps/%011lu_%016lx.bin", timestamp, static_cast<u64>(this->context->program_id));
|
||||
FILE *f_stackdump = fopen(file_path, "wb");
|
||||
if (f_stackdump == NULL) { return; }
|
||||
ON_SCOPE_EXIT { fclose(f_stackdump); };
|
||||
FILE *f_dump = fopen(file_path, "wb");
|
||||
if (f_dump == NULL) { return; }
|
||||
ON_SCOPE_EXIT { fclose(f_dump); };
|
||||
|
||||
fwrite(this->context->stack_dump, this->context->stack_dump_size, 1, f_stackdump);
|
||||
fflush(f_stackdump);
|
||||
fwrite(this->context->tls_dump, sizeof(this->context->tls_dump), 1, f_dump);
|
||||
if (this->context->stack_dump_size) {
|
||||
fwrite(this->context->stack_dump, this->context->stack_dump_size, 1, f_dump);
|
||||
}
|
||||
fflush(f_dump);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue