diff --git a/Core/HLE/AtracCtx.h b/Core/HLE/AtracCtx.h index 8f2bf38fda..0212aa0884 100644 --- a/Core/HLE/AtracCtx.h +++ b/Core/HLE/AtracCtx.h @@ -291,6 +291,7 @@ public: } u8 *BufferStart(); + void DoState(PointerWrap &p) override; void WriteContextToPSPMem() override; diff --git a/Core/HLE/HLE.cpp b/Core/HLE/HLE.cpp index 6fbe816b45..cdc8a8d7ba 100644 --- a/Core/HLE/HLE.cpp +++ b/Core/HLE/HLE.cpp @@ -162,14 +162,20 @@ void HLEShutdown() { mipsCallActions.clear(); } -void RegisterModule(const char *name, int numFunctions, const HLEFunction *funcTable) -{ +int GetNumRegisteredModules() { + return (int)moduleDB.size(); +} + +void RegisterModule(const char *name, int numFunctions, const HLEFunction *funcTable) { HLEModule module = {name, numFunctions, funcTable}; moduleDB.push_back(module); } -int GetModuleIndex(const char *moduleName) -{ +const HLEModule *GetModuleByIndex(int index) { + return &moduleDB[index]; +} + +int GetModuleIndex(const char *moduleName) { for (size_t i = 0; i < moduleDB.size(); i++) if (strcmp(moduleName, moduleDB[i].name) == 0) return (int)i; diff --git a/Core/HLE/HLE.h b/Core/HLE/HLE.h index ba96ef4570..12a0590351 100644 --- a/Core/HLE/HLE.h +++ b/Core/HLE/HLE.h @@ -44,8 +44,7 @@ enum { HLE_KERNEL_SYSCALL = 1 << 11, }; -struct HLEFunction -{ +struct HLEFunction { // This is the id, or nid, of the function (which is how it's linked.) // Generally, the truncated least significant 32 bits of a SHA-1 hash. u32 ID; @@ -72,8 +71,7 @@ struct HLEFunction u32 stackBytesToClear; }; -struct HLEModule -{ +struct HLEModule { const char *name; int numFunctions; const HLEFunction *funcTable; @@ -81,8 +79,7 @@ struct HLEModule typedef char SyscallModuleName[32]; -struct Syscall -{ +struct Syscall { SyscallModuleName moduleName; u32 symAddr; u32 nid; @@ -102,6 +99,8 @@ int GetFuncIndex(int moduleIndex, u32 nib); int GetModuleIndex(const char *modulename); void RegisterModule(const char *name, int numFunctions, const HLEFunction *funcTable); +int GetNumRegisteredModules(); +const HLEModule *GetModuleByIndex(int index); // Run the current thread's callbacks after the syscall finishes. void hleCheckCurrentCallbacks(); diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index 9f74b329a9..f4d99f6313 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -75,13 +75,20 @@ static const int atracDecodeDelay = 2300; -const int PSP_NUM_ATRAC_IDS = 6; static bool atracInited = true; static AtracBase *atracContexts[PSP_NUM_ATRAC_IDS]; static u32 atracContextTypes[PSP_NUM_ATRAC_IDS]; static int atracLibVersion = 0; static u32 atracLibCrc = 0; +// For debugger only. +const AtracBase *__AtracGetCtx(int i, u32 *type) { + if (type) { + *type = atracContextTypes[i]; + } + return atracContexts[i]; +} + void __AtracInit() { _assert_(sizeof(SceAtracContext) == 256); diff --git a/Core/HLE/sceAtrac.h b/Core/HLE/sceAtrac.h index f29c59f798..e0bf3ec86c 100644 --- a/Core/HLE/sceAtrac.h +++ b/Core/HLE/sceAtrac.h @@ -85,6 +85,12 @@ struct SceAtracContext { SceAtracIdInfo info; }; +const int PSP_NUM_ATRAC_IDS = 6; + +class AtracBase; + +const AtracBase *__AtracGetCtx(int i, u32 *type); + // External interface used by sceSas. u32 AtracSasAddStreamData(int atracID, u32 bufPtr, u32 bytesToAdd); u32 AtracSasDecodeData(int atracID, u8* outbuf, u32 outbufPtr, u32 *SamplesNum, u32* finish, int *remains); diff --git a/Core/MIPS/MIPSStackWalk.cpp b/Core/MIPS/MIPSStackWalk.cpp index 60e38a0658..446c31d6c9 100644 --- a/Core/MIPS/MIPSStackWalk.cpp +++ b/Core/MIPS/MIPSStackWalk.cpp @@ -15,6 +15,7 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include "Common/Log.h" #include "Core/MemMap.h" #include "Core/Debugger/SymbolMap.h" #include "Core/MIPS/MIPSCodeUtils.h" @@ -112,6 +113,7 @@ namespace MIPSStackWalk { stop = start - LONGEST_FUNCTION; } for (u32 pc = start; Memory::IsValidAddress(pc) && pc >= stop; pc -= 4) { + _dbg_assert_(Memory::IsValidAddress(pc)); MIPSOpcode op = Memory::Read_Instruction(pc, true); // Here's where they store the ra address. @@ -161,7 +163,7 @@ namespace MIPSStackWalk { } } - std::vector Walk(u32 pc, u32 ra, u32 sp, u32 threadEntry, u32 threadStackTop) { + std::vector Walk(const u32 pc, u32 ra, u32 sp, const u32 threadEntry, u32 threadStackTop) { std::vector frames; if (!Memory::IsValidAddress(pc) || !Memory::IsValidAddress(sp) || !Memory::IsValidAddress(ra)) { @@ -175,7 +177,11 @@ namespace MIPSStackWalk { current.stackSize = -1; u32 prevEntry = INVALIDTARGET; - while (pc != threadEntry) { + while (current.pc != threadEntry) { + if (!Memory::IsValidAddress(current.pc)) { + break; + } + u32 possibleEntry = GuessEntry(current.pc); if (DetermineFrameInfo(current, possibleEntry, threadEntry, ra)) { frames.push_back(current); diff --git a/Core/MemMap.cpp b/Core/MemMap.cpp index 67bbe6f9f3..26182005f5 100644 --- a/Core/MemMap.cpp +++ b/Core/MemMap.cpp @@ -158,8 +158,8 @@ static bool Memory_TryBase(u32 flags) { *view.out_ptr = (u8*)g_arena.CreateView( position, view.size, base + view.virtual_address); if (!*view.out_ptr) { + ERROR_LOG(Log::MemMap, "Failed at view %d", i); goto bail; - DEBUG_LOG(Log::MemMap, "Failed at view %d", i); } #else if (CanIgnoreView(view)) { @@ -169,7 +169,7 @@ static bool Memory_TryBase(u32 flags) { *view.out_ptr = (u8*)g_arena.CreateView( position, view.size, base + (view.virtual_address & MEMVIEW32_MASK)); if (!*view.out_ptr) { - DEBUG_LOG(Log::MemMap, "Failed at view %d", i); + ERROR_LOG(Log::MemMap, "Failed at view %d", i); goto bail; } } @@ -185,11 +185,11 @@ bail: if (views[i].size == 0) continue; SKIP(flags, views[i].flags); - if (*views[j].out_ptr) { + if (views[j].out_ptr && *views[j].out_ptr) { if (!CanIgnoreView(views[j])) { g_arena.ReleaseView(0, *views[j].out_ptr, views[j].size); } - *views[j].out_ptr = NULL; + *views[j].out_ptr = nullptr; } } return false; diff --git a/UI/ImDebugger/ImDebugger.cpp b/UI/ImDebugger/ImDebugger.cpp index b9a3273499..aa15f8fec6 100644 --- a/UI/ImDebugger/ImDebugger.cpp +++ b/UI/ImDebugger/ImDebugger.cpp @@ -1,3 +1,5 @@ +#include + #include "ext/imgui/imgui_internal.h" @@ -11,8 +13,12 @@ #include "Core/MIPS/MIPSTables.h" #include "Core/Debugger/SymbolMap.h" #include "Core/MemMap.h" +#include "Core/HLE/HLE.h" #include "Common/System/Request.h" +#include "Core/HLE/sceAtrac.h" +#include "Core/HLE/AtracCtx.h" + // Threads window #include "Core/HLE/sceKernelThread.h" @@ -104,8 +110,8 @@ static const char *ThreadStatusToString(u32 status) { return "(unk)"; } -void DrawThreadView(bool *open) { - if (!ImGui::Begin("Threads", open)) { +void DrawThreadView(ImConfig &cfg) { + if (!ImGui::Begin("Threads", &cfg.threadsOpen)) { ImGui::End(); return; } @@ -119,22 +125,78 @@ void DrawThreadView(bool *open) { ImGui::TableSetupColumn("State", ImGuiTableColumnFlags_WidthStretch); ImGui::TableHeadersRow(); - ImGui::TableNextRow(); - // TODO: Add context menu - for (auto &thread : info) { - ImGui::TableSetColumnIndex(0); - ImGui::Text("%s", thread.name); - ImGui::TableSetColumnIndex(1); - ImGui::Text("%08x", thread.curPC); - ImGui::TableSetColumnIndex(2); - ImGui::Text("%08x", thread.entrypoint); - ImGui::TableSetColumnIndex(3); - ImGui::Text("%d", thread.priority); - ImGui::TableSetColumnIndex(4); - ImGui::Text("%s", ThreadStatusToString(thread.status)); + for (int i = 0; i < (int)info.size(); i++) { + const auto &thread = info[i]; ImGui::TableNextRow(); - // TODO: More fields? + ImGui::TableNextColumn(); + ImGui::PushID(i); + if (ImGui::Selectable(thread.name, cfg.selectedThread == i, ImGuiSelectableFlags_AllowDoubleClick | ImGuiSelectableFlags_SpanAllColumns)) { + cfg.selectedThread = i; + } + if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { + cfg.selectedThread = i; + ImGui::OpenPopup("threadPopup"); + } + ImGui::TableNextColumn(); + ImGui::Text("%08x", thread.curPC); + ImGui::TableNextColumn(); + ImGui::Text("%08x", thread.entrypoint); + ImGui::TableNextColumn(); + ImGui::Text("%d", thread.priority); + ImGui::TableNextColumn(); + ImGui::Text("%s", ThreadStatusToString(thread.status)); + if (ImGui::BeginPopup("threadPopup")) { + DebugThreadInfo &thread = info[i]; + ImGui::Text("Thread: %s", thread.name); + if (ImGui::MenuItem("Kill thread")) { + sceKernelTerminateThread(thread.id); + } + if (ImGui::MenuItem("Force run")) { + __KernelResumeThreadFromWait(thread.id, 0); + } + ImGui::EndPopup(); + } + ImGui::PopID(); + } + + ImGui::EndTable(); + } + ImGui::End(); +} + +void DrawAtracView(ImConfig &cfg) { + if (!ImGui::Begin("sceAtrac contexts", &cfg.atracOpen)) { + ImGui::End(); + return; + } + + if (ImGui::BeginTable("atracs", 5, ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersH)) { + ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("OutChans", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("CurrentSample", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("RemainingFrames", ImGuiTableColumnFlags_WidthFixed); + + ImGui::TableHeadersRow(); + + for (int i = 0; i < PSP_NUM_ATRAC_IDS; i++) { + u32 type = 0; + const AtracBase *atracBase = __AtracGetCtx(i, &type); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + if (!atracBase) { + ImGui::Text("-", type); + continue; + } + + ImGui::Text("%d", type); + ImGui::TableNextColumn(); + ImGui::Text("%d", atracBase->GetOutputChannels()); + ImGui::TableNextColumn(); + ImGui::Text("%d", atracBase->CurrentSample()); + ImGui::TableNextColumn(); + ImGui::Text("%d", atracBase->RemainingFrames()); } ImGui::EndTable(); @@ -198,14 +260,13 @@ void DrawCallStacks(MIPSDebugInterface *debug, bool *open) { ImGui::End(); } -void DrawModules(MIPSDebugInterface *debug, bool *open) { - if (!ImGui::Begin("Modules", open) || !g_symbolMap) { +void DrawModules(MIPSDebugInterface *debug, ImConfig &cfg) { + if (!ImGui::Begin("Modules", &cfg.modulesOpen) || !g_symbolMap) { ImGui::End(); return; } std::vector modules = g_symbolMap->getAllModules(); - if (ImGui::BeginTable("modules", 4, ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersH)) { ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("Address", ImGuiTableColumnFlags_WidthFixed); @@ -213,23 +274,60 @@ void DrawModules(MIPSDebugInterface *debug, bool *open) { ImGui::TableSetupColumn("Active", ImGuiTableColumnFlags_WidthFixed); ImGui::TableHeadersRow(); - ImGui::TableNextRow(); // TODO: Add context menu and clickability - for (auto &module : modules) { - ImGui::TableSetColumnIndex(0); - ImGui::Text("%s", module.name.c_str()); - ImGui::TableSetColumnIndex(1); - ImGui::Text("%08x", module.address); - ImGui::TableSetColumnIndex(2); - ImGui::Text("%08x", module.size); - ImGui::TableSetColumnIndex(3); - ImGui::Text("%s", module.active ? "yes" : "no"); + for (int i = 0; i < (int)modules.size(); i++) { + auto &module = modules[i]; ImGui::TableNextRow(); + ImGui::TableNextColumn(); + if (ImGui::Selectable(module.name.c_str(), cfg.selectedModule == i, ImGuiSelectableFlags_SpanAllColumns)) { + cfg.selectedModule = i; + } + ImGui::TableNextColumn(); + ImGui::Text("%08x", module.address); + ImGui::TableNextColumn(); + ImGui::Text("%08x", module.size); + ImGui::TableNextColumn(); + ImGui::Text("%s", module.active ? "yes" : "no"); } ImGui::EndTable(); } + + if (cfg.selectedModule >= 0 && cfg.selectedModule < (int)modules.size()) { + auto &module = modules[cfg.selectedModule]; + // TODO: Show details + } + ImGui::End(); +} + +void DrawHLEModules(ImConfig &config) { + if (!ImGui::Begin("HLE Modules", &config.hleModulesOpen)) { + ImGui::End(); + return; + } + + const int moduleCount = GetNumRegisteredModules(); + std::vector modules; + modules.reserve(moduleCount); + for (int i = 0; i < moduleCount; i++) { + modules.push_back(GetModuleByIndex(i)); + } + + std::sort(modules.begin(), modules.end(), [](const HLEModule* a, const HLEModule* b) { + return std::strcmp(a->name, b->name) < 0; + }); + + for (auto mod : modules) { + if (ImGui::TreeNode(mod->name)) { + for (int j = 0; j < mod->numFunctions; j++) { + auto &func = mod->funcTable[j]; + ImGui::Text("%s(%s)", func.name, func.argmask); + } + ImGui::TreePop(); + } + } + ImGui::End(); } @@ -272,40 +370,47 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug) { ImGui::EndMenu(); } if (ImGui::BeginMenu("Window")) { - ImGui::Checkbox("Dear ImGUI Demo", &demoOpen_); - ImGui::Checkbox("CPU debugger", &disasmOpen_); - ImGui::Checkbox("Registers", ®sOpen_); - ImGui::Checkbox("Callstacks", &callstackOpen_); - ImGui::Checkbox("HLE Modules", &modulesOpen_); - ImGui::Checkbox("HLE Threads", &threadsOpen_); + ImGui::Checkbox("Dear ImGUI Demo", &cfg_.demoOpen); + ImGui::Checkbox("CPU debugger", &cfg_.disasmOpen); + ImGui::Checkbox("Registers", &cfg_.regsOpen); + ImGui::Checkbox("Callstacks", &cfg_.callstackOpen); + ImGui::Checkbox("HLE Modules", &cfg_.modulesOpen); + ImGui::Checkbox("HLE Threads", &cfg_.threadsOpen); + ImGui::Checkbox("sceAtrac", &cfg_.atracOpen); ImGui::EndMenu(); } ImGui::EndMainMenuBar(); } - if (demoOpen_) { - ImGui::ShowDemoWindow(&demoOpen_); + if (cfg_.demoOpen) { + ImGui::ShowDemoWindow(&cfg_.demoOpen); } - if (disasmOpen_) { - disasm_.Draw(mipsDebug, &disasmOpen_, coreState); + if (cfg_.disasmOpen) { + disasm_.Draw(mipsDebug, &cfg_.disasmOpen, coreState); } - if (regsOpen_) { - DrawRegisterView(mipsDebug, ®sOpen_); + if (cfg_.regsOpen) { + DrawRegisterView(mipsDebug, &cfg_.regsOpen); } - if (threadsOpen_) { - DrawThreadView(&threadsOpen_); + if (cfg_.threadsOpen) { + DrawThreadView(cfg_); } - if (callstackOpen_) { - DrawCallStacks(mipsDebug, &callstackOpen_); + if (cfg_.callstackOpen) { + DrawCallStacks(mipsDebug, &cfg_.callstackOpen); } - if (modulesOpen_) { - DrawModules(mipsDebug, &modulesOpen_); + if (cfg_.modulesOpen) { + DrawModules(mipsDebug, cfg_); } + + if (cfg_.atracOpen) { + DrawAtracView(cfg_); + } + + DrawHLEModules(cfg_); } void ImDisasmWindow::Draw(MIPSDebugInterface *mipsDebug, bool *open, CoreState coreState) { diff --git a/UI/ImDebugger/ImDebugger.h b/UI/ImDebugger/ImDebugger.h index 1eba71030c..389088deb6 100644 --- a/UI/ImDebugger/ImDebugger.h +++ b/UI/ImDebugger/ImDebugger.h @@ -48,6 +48,24 @@ public: // Stub }; +struct ImConfig { + bool disasmOpen = true; + bool demoOpen = false; + bool regsOpen = true; + bool threadsOpen = true; + bool callstackOpen = true; + bool modulesOpen = true; + bool hleModulesOpen = false; + bool atracOpen = true; + + // HLE explorer settings + // bool filterByUsed = true; + + // Various selections + int selectedModule = 0; + int selectedThread = 0; +}; + struct ImDebugger { void Frame(MIPSDebugInterface *mipsDebug); @@ -55,10 +73,5 @@ struct ImDebugger { ImLuaConsole luaConsole_; // Open variables. - bool disasmOpen_ = true; - bool demoOpen_ = false; - bool regsOpen_ = true; - bool threadsOpen_ = true; - bool callstackOpen_ = true; - bool modulesOpen_ = true; + ImConfig cfg_; };