mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-06-23 19:52:39 +02:00
creport: Add better 32-bit support
This commit is contained in:
parent
4e99a5e08d
commit
157eb0ec6c
@ -105,7 +105,7 @@ namespace ams::creport {
|
|||||||
if (this->OpenProcess(process_id)) {
|
if (this->OpenProcess(process_id)) {
|
||||||
/* Parse info from the crashed process. */
|
/* Parse info from the crashed process. */
|
||||||
this->ProcessExceptions();
|
this->ProcessExceptions();
|
||||||
m_module_list->FindModulesFromThreadInfo(m_debug_handle, m_crashed_thread, this->Is64Bit());
|
m_module_list->FindModulesFromThreadInfo(m_debug_handle, m_crashed_thread);
|
||||||
m_thread_list->ReadFromProcess(m_debug_handle, m_thread_tls_map, this->Is64Bit());
|
m_thread_list->ReadFromProcess(m_debug_handle, m_thread_tls_map, this->Is64Bit());
|
||||||
|
|
||||||
/* Associate module list to threads. */
|
/* Associate module list to threads. */
|
||||||
@ -120,7 +120,7 @@ namespace ams::creport {
|
|||||||
/* Nintendo's creport finds extra modules by looking at all threads if application, */
|
/* Nintendo's creport finds extra modules by looking at all threads if application, */
|
||||||
/* but there's no reason for us not to always go looking. */
|
/* but there's no reason for us not to always go looking. */
|
||||||
for (size_t i = 0; i < m_thread_list->GetThreadCount(); i++) {
|
for (size_t i = 0; i < m_thread_list->GetThreadCount(); i++) {
|
||||||
m_module_list->FindModulesFromThreadInfo(m_debug_handle, m_thread_list->GetThreadInfo(i), this->Is64Bit());
|
m_module_list->FindModulesFromThreadInfo(m_debug_handle, m_thread_list->GetThreadInfo(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Cache the module base address to send to fatal. */
|
/* Cache the module base address to send to fatal. */
|
||||||
@ -188,6 +188,7 @@ namespace ams::creport {
|
|||||||
|
|
||||||
void CrashReport::HandleDebugEventInfoCreateProcess(const svc::DebugEventInfo &d) {
|
void CrashReport::HandleDebugEventInfoCreateProcess(const svc::DebugEventInfo &d) {
|
||||||
m_process_info = d.info.create_process;
|
m_process_info = d.info.create_process;
|
||||||
|
m_module_list->SetIs64Bit(Is64Bit());
|
||||||
|
|
||||||
/* On 5.0.0+, we want to parse out a dying message from application crashes. */
|
/* On 5.0.0+, we want to parse out a dying message from application crashes. */
|
||||||
if (hos::GetVersion() < hos::Version_5_0_0 || !IsApplication()) {
|
if (hos::GetVersion() < hos::Version_5_0_0 || !IsApplication()) {
|
||||||
|
@ -58,26 +58,26 @@ namespace ams::creport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModuleList::FindModulesFromThreadInfo(os::NativeHandle debug_handle, const ThreadInfo &thread, bool is_64_bit) {
|
void ModuleList::FindModulesFromThreadInfo(os::NativeHandle debug_handle, const ThreadInfo &thread) {
|
||||||
/* Set the debug handle, for access in other member functions. */
|
/* Set the debug handle, for access in other member functions. */
|
||||||
m_debug_handle = debug_handle;
|
m_debug_handle = debug_handle;
|
||||||
|
|
||||||
/* Try to add the thread's PC. */
|
/* Try to add the thread's PC. */
|
||||||
this->TryAddModule(thread.GetPC(), is_64_bit);
|
this->TryAddModule(thread.GetPC());
|
||||||
|
|
||||||
/* Try to add the thread's LR. */
|
/* Try to add the thread's LR. */
|
||||||
this->TryAddModule(thread.GetLR(), is_64_bit);
|
this->TryAddModule(thread.GetLR());
|
||||||
|
|
||||||
/* Try to add all the addresses in the thread's stacktrace. */
|
/* Try to add all the addresses in the thread's stacktrace. */
|
||||||
for (size_t i = 0; i < thread.GetStackTraceSize(); i++) {
|
for (size_t i = 0; i < thread.GetStackTraceSize(); i++) {
|
||||||
this->TryAddModule(thread.GetStackTrace(i), is_64_bit);
|
this->TryAddModule(thread.GetStackTrace(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModuleList::TryAddModule(uintptr_t guess, bool is_64_bit) {
|
void ModuleList::TryAddModule(uintptr_t guess) {
|
||||||
/* Try to locate module from guess. */
|
/* Try to locate module from guess. */
|
||||||
uintptr_t base_address = 0;
|
uintptr_t base_address = 0;
|
||||||
if (!this->TryFindModule(std::addressof(base_address), guess, is_64_bit)) {
|
if (!this->TryFindModule(std::addressof(base_address), guess)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,11 +114,9 @@ namespace ams::creport {
|
|||||||
util::SNPrintf(module.name, sizeof(module.name), "[%02x%02x%02x%02x]", module.module_id[0], module.module_id[1], module.module_id[2], module.module_id[3]);
|
util::SNPrintf(module.name, sizeof(module.name), "[%02x%02x%02x%02x]", module.module_id[0], module.module_id[1], module.module_id[2], module.module_id[3]);
|
||||||
} else {
|
} else {
|
||||||
/* The module has a name, and so might have a symbol table. Try to add it, if it does. */
|
/* The module has a name, and so might have a symbol table. Try to add it, if it does. */
|
||||||
if (is_64_bit) {
|
|
||||||
DetectModuleSymbolTable(module);
|
DetectModuleSymbolTable(module);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* If we're out of readable memory, we're done reading code. */
|
/* If we're out of readable memory, we're done reading code. */
|
||||||
if (mi.state == svc::MemoryState_Free || mi.state == svc::MemoryState_Inaccessible) {
|
if (mi.state == svc::MemoryState_Free || mi.state == svc::MemoryState_Inaccessible) {
|
||||||
@ -134,9 +132,7 @@ namespace ams::creport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModuleList::TryFindModule(uintptr_t *out_address, uintptr_t guess, bool is_64_bit) {
|
bool ModuleList::TryFindModule(uintptr_t *out_address, uintptr_t guess) {
|
||||||
AMS_UNUSED(is_64_bit);
|
|
||||||
|
|
||||||
/* Query the memory region our guess falls in. */
|
/* Query the memory region our guess falls in. */
|
||||||
svc::MemoryInfo mi;
|
svc::MemoryInfo mi;
|
||||||
svc::PageInfo pi;
|
svc::PageInfo pi;
|
||||||
@ -265,7 +261,6 @@ namespace ams::creport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Declare temporaries. */
|
/* Declare temporaries. */
|
||||||
u64 temp_64;
|
|
||||||
u32 temp_32;
|
u32 temp_32;
|
||||||
|
|
||||||
/* Get module state. */
|
/* Get module state. */
|
||||||
@ -316,43 +311,54 @@ namespace ams::creport {
|
|||||||
dyn_address = module.start_address + mod_offset + temp_32;
|
dyn_address = module.start_address + mod_offset + temp_32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
struct Elf64_Dyn {
|
||||||
|
u64 d_tag;
|
||||||
|
u64 d_val;
|
||||||
|
} dyn;
|
||||||
|
|
||||||
|
struct Elf32_Dyn {
|
||||||
|
u32 d_tag;
|
||||||
|
u32 d_val;
|
||||||
|
} dyn_32;
|
||||||
|
|
||||||
|
size_t dyn_size = m_is_64_bit ? sizeof(Elf64_Dyn) : sizeof(Elf32_Dyn);
|
||||||
|
uintptr_t dyn_read_address = m_is_64_bit ? reinterpret_cast<uintptr_t>(std::addressof(dyn)) : reinterpret_cast<uintptr_t>(std::addressof(dyn_32));
|
||||||
|
|
||||||
/* Locate tables inside .dyn. */
|
/* Locate tables inside .dyn. */
|
||||||
for (size_t ofs = 0; /* ... */; ofs += 0x10) {
|
for (size_t ofs = 0; /* ... */; ofs += dyn_size) {
|
||||||
/* Read the DynamicTag. */
|
/* Read the dynamic entry. */
|
||||||
if (R_FAILED(svc::ReadDebugProcessMemory(reinterpret_cast<uintptr_t>(std::addressof(temp_64)), m_debug_handle, dyn_address + ofs, sizeof(u64)))) {
|
if (R_FAILED(svc::ReadDebugProcessMemory(dyn_read_address, m_debug_handle, dyn_address + ofs, dyn_size))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (temp_64 == 0) {
|
/* Copy entry if necessary. */
|
||||||
|
if (!m_is_64_bit) {
|
||||||
|
dyn.d_tag = dyn_32.d_tag;
|
||||||
|
dyn.d_val = dyn_32.d_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dyn.d_tag == 0) {
|
||||||
/* We're done parsing .dyn. */
|
/* We're done parsing .dyn. */
|
||||||
break;
|
break;
|
||||||
} else if (temp_64 == 4) {
|
} else if (dyn.d_tag == 4) {
|
||||||
/* We found DT_HASH */
|
/* We found DT_HASH */
|
||||||
if (R_FAILED(svc::ReadDebugProcessMemory(reinterpret_cast<uintptr_t>(std::addressof(temp_64)), m_debug_handle, dyn_address + ofs + sizeof(u64), sizeof(u64)))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read nchain, to get the number of symbols. */
|
/* Read nchain, to get the number of symbols. */
|
||||||
if (R_FAILED(svc::ReadDebugProcessMemory(reinterpret_cast<uintptr_t>(std::addressof(temp_32)), m_debug_handle, module.start_address + temp_64 + sizeof(u32), sizeof(u32)))) {
|
if (R_FAILED(svc::ReadDebugProcessMemory(reinterpret_cast<uintptr_t>(std::addressof(temp_32)), m_debug_handle, module.start_address + dyn.d_val + sizeof(u32), sizeof(u32)))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
num_sym = temp_32;
|
num_sym = temp_32;
|
||||||
} else if (temp_64 == 5) {
|
} else if (dyn.d_tag == 5) {
|
||||||
/* We found DT_STRTAB */
|
/* We found DT_STRTAB */
|
||||||
if (R_FAILED(svc::ReadDebugProcessMemory(reinterpret_cast<uintptr_t>(std::addressof(temp_64)), m_debug_handle, dyn_address + ofs + sizeof(u64), sizeof(u64)))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
str_tab = module.start_address + temp_64;
|
str_tab = module.start_address + dyn.d_val;
|
||||||
} else if (temp_64 == 6) {
|
} else if (dyn.d_tag == 6) {
|
||||||
/* We found DT_SYMTAB */
|
/* We found DT_SYMTAB */
|
||||||
if (R_FAILED(svc::ReadDebugProcessMemory(reinterpret_cast<uintptr_t>(std::addressof(temp_64)), m_debug_handle, dyn_address + ofs + sizeof(u64), sizeof(u64)))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sym_tab = module.start_address + temp_64;
|
sym_tab = module.start_address + dyn.d_val;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,7 +385,7 @@ namespace ams::creport {
|
|||||||
/* Try to locate an appropriate symbol. */
|
/* Try to locate an appropriate symbol. */
|
||||||
for (size_t j = 0; j < module.num_sym; ++j) {
|
for (size_t j = 0; j < module.num_sym; ++j) {
|
||||||
/* Read symbol from the module's symbol table. */
|
/* Read symbol from the module's symbol table. */
|
||||||
struct {
|
struct Elf64_Sym {
|
||||||
u32 st_name;
|
u32 st_name;
|
||||||
u8 st_info;
|
u8 st_info;
|
||||||
u8 st_other;
|
u8 st_other;
|
||||||
@ -387,7 +393,33 @@ namespace ams::creport {
|
|||||||
u64 st_value;
|
u64 st_value;
|
||||||
u64 st_size;
|
u64 st_size;
|
||||||
} sym;
|
} sym;
|
||||||
if (R_FAILED(svc::ReadDebugProcessMemory(reinterpret_cast<uintptr_t>(std::addressof(sym)), m_debug_handle, module.sym_tab + j * sizeof(sym), sizeof(sym)))) {
|
|
||||||
|
/* Elf32_Sym is different from Elf64_Sym. */
|
||||||
|
if (!m_is_64_bit)
|
||||||
|
{
|
||||||
|
struct Elf32_Sym {
|
||||||
|
u32 st_name;
|
||||||
|
u32 st_value;
|
||||||
|
u32 st_size;
|
||||||
|
u8 st_info;
|
||||||
|
u8 st_other;
|
||||||
|
u16 st_shndx;
|
||||||
|
} sym_32;
|
||||||
|
|
||||||
|
/* Read 32-bit symbol. */
|
||||||
|
if (R_FAILED(svc::ReadDebugProcessMemory(reinterpret_cast<uintptr_t>(std::addressof(sym_32)), m_debug_handle, module.sym_tab + j * sizeof(sym_32), sizeof(sym_32)))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sym.st_name = sym_32.st_name;
|
||||||
|
sym.st_info = sym_32.st_info;
|
||||||
|
sym.st_other = sym_32.st_other;
|
||||||
|
sym.st_shndx = sym_32.st_shndx;
|
||||||
|
sym.st_value = sym_32.st_value;
|
||||||
|
sym.st_size = sym_32.st_size;
|
||||||
|
}
|
||||||
|
/* Read 64-bit symbol. */
|
||||||
|
else if (R_FAILED(svc::ReadDebugProcessMemory(reinterpret_cast<uintptr_t>(std::addressof(sym)), m_debug_handle, module.sym_tab + j * sizeof(sym), sizeof(sym)))) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,13 +37,14 @@ namespace ams::creport {
|
|||||||
};
|
};
|
||||||
private:
|
private:
|
||||||
os::NativeHandle m_debug_handle;
|
os::NativeHandle m_debug_handle;
|
||||||
|
bool m_is_64_bit;
|
||||||
size_t m_num_modules;
|
size_t m_num_modules;
|
||||||
ModuleInfo m_modules[ModuleCountMax];
|
ModuleInfo m_modules[ModuleCountMax];
|
||||||
|
|
||||||
/* For pretty-printing. */
|
/* For pretty-printing. */
|
||||||
char m_address_str_buf[1_KB];
|
char m_address_str_buf[1_KB];
|
||||||
public:
|
public:
|
||||||
ModuleList() : m_debug_handle(os::InvalidNativeHandle), m_num_modules(0) {
|
ModuleList() : m_debug_handle(os::InvalidNativeHandle), m_is_64_bit(true), m_num_modules(0) {
|
||||||
std::memset(m_modules, 0, sizeof(m_modules));
|
std::memset(m_modules, 0, sizeof(m_modules));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,12 +56,16 @@ namespace ams::creport {
|
|||||||
return m_modules[i].start_address;
|
return m_modules[i].start_address;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FindModulesFromThreadInfo(os::NativeHandle debug_handle, const ThreadInfo &thread, bool is_64_bit);
|
void SetIs64Bit(bool is_64_bit) {
|
||||||
|
m_is_64_bit = is_64_bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FindModulesFromThreadInfo(os::NativeHandle debug_handle, const ThreadInfo &thread);
|
||||||
const char *GetFormattedAddressString(uintptr_t address);
|
const char *GetFormattedAddressString(uintptr_t address);
|
||||||
void SaveToFile(ScopedFile &file);
|
void SaveToFile(ScopedFile &file);
|
||||||
private:
|
private:
|
||||||
bool TryFindModule(uintptr_t *out_address, uintptr_t guess, bool is_64_bit);
|
bool TryFindModule(uintptr_t *out_address, uintptr_t guess);
|
||||||
void TryAddModule(uintptr_t guess, bool is_64_bit);
|
void TryAddModule(uintptr_t guess);
|
||||||
void GetModuleName(char *out_name, uintptr_t text_start, uintptr_t ro_start);
|
void GetModuleName(char *out_name, uintptr_t text_start, uintptr_t ro_start);
|
||||||
void GetModuleId(u8 *out, uintptr_t ro_start);
|
void GetModuleId(u8 *out, uintptr_t ro_start);
|
||||||
void DetectModuleSymbolTable(ModuleInfo &module);
|
void DetectModuleSymbolTable(ModuleInfo &module);
|
||||||
|
Loading…
Reference in New Issue
Block a user