diff --git a/Core/Core.cpp b/Core/Core.cpp index fc604bf243..ae73aff5da 100644 --- a/Core/Core.cpp +++ b/Core/Core.cpp @@ -39,6 +39,7 @@ #include "Core/MIPS/MIPS.h" #include "Core/MIPS/MIPSAnalyst.h" #include "Core/HLE/sceNetAdhoc.h" +#include "Core/HLE/sceKernelModule.h" #include "Core/MIPS/MIPSTracer.h" #include "GPU/Debugger/Stepping.h" @@ -557,16 +558,27 @@ static ExceptionAction ResolveExceptionAction(ExceptionAction action) { return action; } +// Looks up which loaded module (and section) an address falls in, formatted for appending +// straight after an address in a log line, e.g. " [EBOOT.BIN.text+1234]". Empty if no match. +static std::string ModuleAddressSuffix(u32 address) { + std::string desc = KernelModuleAddressDescription(address); + if (desc.empty()) + return std::string(); + return " [" + desc + "]"; +} + void Core_MemoryException(u32 address, u32 accessSize, u32 pc, MemoryExceptionType type, std::string_view additionalInfo, bool forceReport) { const char *desc = MemoryExceptionTypeAsString(type); // In jit, we only flush PC when bIgnoreBadMemAccess is off. - char pcDetails[64]; + char pcDetails[128]; pcDetails[0] = 0; if ((CPUCore)g_Config.iCpuCore == CPUCore::INTERPRETER) { - snprintf(pcDetails, sizeof(pcDetails), " PC %08x LR %08x", currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]); + snprintf(pcDetails, sizeof(pcDetails), " PC %08x%s LR %08x%s", currentMIPS->pc, ModuleAddressSuffix(currentMIPS->pc).c_str(), currentMIPS->r[MIPS_REG_RA], ModuleAddressSuffix(currentMIPS->r[MIPS_REG_RA]).c_str()); } + const std::string addressSuffix = ModuleAddressSuffix(address); + ExceptionAction action; switch (type) { case MemoryExceptionType::WRITE_WORD: @@ -582,13 +594,13 @@ void Core_MemoryException(u32 address, u32 accessSize, u32 pc, MemoryExceptionTy if (action == ExceptionAction::Ignore) { // Simplest logging and continue. - WARN_LOG(Log::MemMap, "%s: Invalid access at %08x (size %08x) %s%.*s", desc, address, accessSize, pcDetails, (int)additionalInfo.length(), additionalInfo.data()); + WARN_LOG(Log::MemMap, "%s: Invalid access at %08x%s (size %08x) %s%.*s", desc, address, addressSuffix.c_str(), accessSize, pcDetails, (int)additionalInfo.length(), additionalInfo.data()); return; } const std::string stackTrace = FormatStackTrace(WalkCurrentStack(-1)); // Do the most detailed logging we can. - ERROR_LOG(Log::MemMap, "%s: Invalid access at %08x (size %08x) %s%.*s\n%s", desc, address, accessSize, pcDetails, (int)additionalInfo.length(), additionalInfo.data(), stackTrace.c_str()); + ERROR_LOG(Log::MemMap, "%s: Invalid access at %08x%s (size %08x) %s%.*s\n%s", desc, address, addressSuffix.c_str(), accessSize, pcDetails, (int)additionalInfo.length(), additionalInfo.data(), stackTrace.c_str()); if (action == ExceptionAction::Break) { MIPSExceptionInfo &e = g_exceptionInfo; e = {}; @@ -606,7 +618,7 @@ void Core_MemoryException(u32 address, u32 accessSize, u32 pc, MemoryExceptionTy // Can't be ignored, must break. Not sure we can get a meaningful stack trace here (since the PC is invalid). void Core_ExecException(u32 address, u32 pc, ExecExceptionType type) { const char *desc = ExecExceptionTypeAsString(type); - WARN_LOG(Log::MemMap, "%s: Invalid exec address %08x pc=%08x ra=%08x", desc, address, pc, currentMIPS->r[MIPS_REG_RA]); + WARN_LOG(Log::MemMap, "%s: Invalid exec address %08x%s pc=%08x%s ra=%08x%s", desc, address, ModuleAddressSuffix(address).c_str(), pc, ModuleAddressSuffix(pc).c_str(), currentMIPS->r[MIPS_REG_RA], ModuleAddressSuffix(currentMIPS->r[MIPS_REG_RA]).c_str()); MIPSExceptionInfo &e = g_exceptionInfo; e = {}; @@ -628,15 +640,17 @@ void Core_BreakException(u32 pc) { e.info.clear(); e.pc = pc; + const std::string pcSuffix = ModuleAddressSuffix(pc); + const ExceptionAction action = ResolveExceptionAction((ExceptionAction)g_Config.iExceptionActionBreak); if (action == ExceptionAction::Ignore) { // Simplest logging and continue. - WARN_LOG(Log::CPU, "CPU exception: break instruction hit at %08x. Ignoring (use --break=log for more details or --break=break to break)", pc); + WARN_LOG(Log::CPU, "CPU exception: break instruction hit at %08x%s. Ignoring (use --break=log for more details or --break=break to break)", pc, pcSuffix.c_str()); return; } const std::string stackTrace = FormatStackTrace(WalkCurrentStack(-1)); - ERROR_LOG(Log::CPU, "CPU exception: break instruction hit at %08x (ra=%08x)\n%s", pc, currentMIPS->r[MIPS_REG_RA], stackTrace.c_str()); + ERROR_LOG(Log::CPU, "CPU exception: break instruction hit at %08x%s (ra=%08x%s)\n%s", pc, pcSuffix.c_str(), currentMIPS->r[MIPS_REG_RA], ModuleAddressSuffix(currentMIPS->r[MIPS_REG_RA]).c_str(), stackTrace.c_str()); if (action == ExceptionAction::Break) { Core_Break(BreakReason::BreakInstruction, currentMIPS->pc); } diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 66fe2fd94c..cb8e640628 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -2647,6 +2647,31 @@ static u32 sceKernelGetModuleIdList(u32 resultBuffer, u32 resultBufferSize, u32 return hleNoLog(0); } +std::string KernelModuleAddressDescription(u32 address) { + u32 error; + for (SceUID moduleId : loadedModules) { + PSPModule *module = kernelObjects.Get(moduleId, error); + if (!module) + continue; + + const NativeModule &nm = module->nm; + u32 dataAddr = module->GetDataAddr(); + u32 bssAddr = module->GetBSSAddr(); + + if (nm.text_size != 0 && address >= nm.text_addr && address < nm.text_addr + nm.text_size) + return StringFromFormat("%s.text+%x", nm.name, address - nm.text_addr); + if (nm.data_size != 0 && address >= dataAddr && address < dataAddr + nm.data_size) + return StringFromFormat("%s.data+%x", nm.name, address - dataAddr); + if (nm.bss_size != 0 && address >= bssAddr && address < bssAddr + nm.bss_size) + return StringFromFormat("%s.bss+%x", nm.name, address - bssAddr); + for (int i = 0; i < (int)nm.nsegment && i < 4; i++) { + if (nm.segmentsize[i] != 0 && address >= nm.segmentaddr[i] && address < nm.segmentaddr[i] + nm.segmentsize[i]) + return StringFromFormat("%s.seg%d+%x", nm.name, i, address - nm.segmentaddr[i]); + } + } + return std::string(); +} + //fix for tiger x dragon static u32 sceKernelLoadModuleForLoadExecVSHDisc(const char *name, u32 flags, u32 optionAddr) { return sceKernelLoadModule(name, flags, optionAddr); diff --git a/Core/HLE/sceKernelModule.h b/Core/HLE/sceKernelModule.h index 461c7d4c99..4212a04868 100644 --- a/Core/HLE/sceKernelModule.h +++ b/Core/HLE/sceKernelModule.h @@ -236,6 +236,9 @@ bool KernelModuleIsKernelMode(SceUID module); bool __KernelLoadGEDump(std::string_view base_filename, std::string *error_string); bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_string); bool KernelFindImportByStubAddr(u32 stubAddr, std::string *importModuleName, u32 *nid, std::string *importingModuleName); +// Describes which loaded module (and section within it) an address falls in, e.g. "EBOOT.BIN.text+1234". +// Returns an empty string if the address isn't inside any currently loaded module. +std::string KernelModuleAddressDescription(u32 address); int __KernelGPUReplay(); void __KernelReturnFromModuleFunc(); SceUID KernelLoadModule(const std::string &filename, std::string *error_string); diff --git a/Core/MemFault.cpp b/Core/MemFault.cpp index 514a4879eb..31029d1a3c 100644 --- a/Core/MemFault.cpp +++ b/Core/MemFault.cpp @@ -48,6 +48,7 @@ #include "Core/MIPS/MIPSStackWalk.h" #include "Core/MIPS/MIPSDebugInterface.h" #include "Core/HLE/sceKernelThread.h" +#include "Core/HLE/sceKernelModule.h" namespace Memory { @@ -373,7 +374,12 @@ std::string FormatStackTrace(const std::vector &frame std::stringstream str; for (const auto &frame : frames) { std::string desc = g_symbolMap->GetDescription(frame.entry); - str << StringFromFormat("%s (%08x+%03x, pc: %08x sp: %08x)\n", desc.c_str(), frame.entry, frame.pc - frame.entry, frame.pc, frame.sp); + std::string moduleDesc = KernelModuleAddressDescription(frame.pc); + if (!moduleDesc.empty()) { + str << StringFromFormat("%s [%s] (%08x+%03x, pc: %08x sp: %08x)\n", desc.c_str(), moduleDesc.c_str(), frame.entry, frame.pc - frame.entry, frame.pc, frame.sp); + } else { + str << StringFromFormat("%s (%08x+%03x, pc: %08x sp: %08x)\n", desc.c_str(), frame.entry, frame.pc - frame.entry, frame.pc, frame.sp); + } } return str.str(); }