ImDebugger: Add basic filesystem browser. Add partial support for "save file dialogs" to System.

This commit is contained in:
Henrik Rydgård
2024-11-25 23:03:15 +01:00
parent 20c4649963
commit 47d8e292eb
13 changed files with 165 additions and 43 deletions
+6
View File
@@ -13,6 +13,7 @@ typedef std::function<void(const char *responseString, int responseValue)> Reque
typedef std::function<void()> RequestFailedCallback;
typedef int RequesterToken;
#define NO_REQUESTER_TOKEN -1
#define NON_EPHEMERAL_TOKEN -2
@@ -101,6 +102,7 @@ enum class BrowseFileType {
DB,
SOUND_EFFECT,
ZIP,
SYMBOL_MAP,
ANY,
};
@@ -108,6 +110,10 @@ inline void System_BrowseForFile(RequesterToken token, std::string_view title, B
g_requestManager.MakeSystemRequest(SystemRequestType::BROWSE_FOR_FILE, token, callback, failedCallback, title, "", (int)type);
}
inline void System_BrowseForFileSave(RequesterToken token, std::string_view title, std::string_view defaultFilename, BrowseFileType type, RequestCallback callback, RequestFailedCallback failedCallback = nullptr) {
g_requestManager.MakeSystemRequest(SystemRequestType::BROWSE_FOR_FILE_SAVE, token, callback, failedCallback, title, defaultFilename, (int)type);
}
void System_BrowseForFolder(RequesterToken token, std::string_view title, const Path &initialPath, RequestCallback callback, RequestFailedCallback failedCallback = nullptr);
// The returned string is username + '\n' + password.
+2
View File
@@ -70,6 +70,8 @@ enum class SystemRequestType {
BROWSE_FOR_FILE,
BROWSE_FOR_FOLDER,
BROWSE_FOR_FILE_SAVE,
EXIT_APP,
RESTART_APP, // For graphics backend changes
RECREATE_ACTIVITY, // Android
+1 -1
View File
@@ -964,7 +964,7 @@ VFSFileSystem::~VFSFileSystem() {
entries.clear();
}
std::string VFSFileSystem::GetLocalPath(const std::string &localPath) {
std::string VFSFileSystem::GetLocalPath(const std::string &localPath) const {
return basePath + localPath;
}
+1 -1
View File
@@ -145,5 +145,5 @@ private:
std::string basePath;
IHandleAllocator *hAlloc;
std::string GetLocalPath(const std::string &localpath);
std::string GetLocalPath(const std::string &localpath) const;
};
+5
View File
@@ -65,6 +65,11 @@ public:
void UnmountAll();
void Unmount(const std::string &prefix);
// Would like to make this const, but...
std::vector<MountPoint> &GetMounts() {
return fileSystems;
}
// The pointer returned from these are for temporary usage only. Do not store.
IFileSystem *GetSystem(const std::string &prefix);
IFileSystem *GetSystemFromFilename(const std::string &filename);
+5 -9
View File
@@ -243,7 +243,7 @@ void VirtualDiscFileSystem::DoState(PointerWrap &p)
// We don't savestate handlers (loaded on fs load), but if they change, it may not load properly.
}
Path VirtualDiscFileSystem::GetLocalPath(std::string localpath) {
Path VirtualDiscFileSystem::GetLocalPath(std::string localpath) const {
if (localpath.empty())
return basePath;
@@ -303,18 +303,14 @@ int VirtualDiscFileSystem::getFileListIndex(std::string &fileName)
return (int)fileList.size()-1;
}
int VirtualDiscFileSystem::getFileListIndex(u32 accessBlock, u32 accessSize, bool blockMode)
{
for (size_t i = 0; i < fileList.size(); i++)
{
if (fileList[i].firstBlock <= accessBlock)
{
int VirtualDiscFileSystem::getFileListIndex(u32 accessBlock, u32 accessSize, bool blockMode) const {
for (size_t i = 0; i < fileList.size(); i++) {
if (fileList[i].firstBlock <= accessBlock) {
u32 sectorOffset = (accessBlock-fileList[i].firstBlock)*2048;
u32 totalFileSize = blockMode ? (fileList[i].totalSize+2047) & ~2047 : fileList[i].totalSize;
u32 endOffset = sectorOffset+accessSize;
if (endOffset <= totalFileSize)
{
if (endOffset <= totalFileSize) {
return (int)i;
}
}
+2 -2
View File
@@ -60,8 +60,8 @@ private:
void LoadFileListIndex();
// Warning: modifies input string.
int getFileListIndex(std::string &fileName);
int getFileListIndex(u32 accessBlock, u32 accessSize, bool blockMode = false);
Path GetLocalPath(std::string localpath);
int getFileListIndex(u32 accessBlock, u32 accessSize, bool blockMode = false) const;
Path GetLocalPath(std::string localpath) const;
typedef void *HandlerLibrary;
typedef int HandlerHandle;
+99 -1
View File
@@ -5,6 +5,7 @@
#include "Common/StringUtils.h"
#include "Core/Config.h"
#include "Core/System.h"
#include "Core/RetroAchievements.h"
#include "Core/Core.h"
#include "Core/Debugger/DebugInterface.h"
@@ -12,6 +13,7 @@
#include "Core/Debugger/Breakpoints.h"
#include "Core/MIPS/MIPSDebugInterface.h"
#include "Core/MIPS/MIPSTables.h"
#include "Core/FileSystems/MetaFileSystem.h"
#include "Core/Debugger/SymbolMap.h"
#include "Core/MemMap.h"
#include "Core/HLE/HLE.h"
@@ -32,6 +34,8 @@
#include "UI/ImDebugger/ImDebugger.h"
#include "UI/ImDebugger/ImGe.h"
extern bool g_TakeScreenshot;
void DrawRegisterView(MIPSDebugInterface *mipsDebug, bool *open) {
if (!ImGui::Begin("Registers", open)) {
ImGui::End();
@@ -170,6 +174,40 @@ void DrawThreadView(ImConfig &cfg) {
ImGui::End();
}
// TODO: Add popup menu, export file, export dir, etc...
static void RecurseFileSystem(IFileSystem *fs, std::string path) {
std::vector<PSPFileInfo> fileInfo = fs->GetDirListing(path);
for (auto &file : fileInfo) {
if (file.type == FileType::FILETYPE_DIRECTORY) {
if (file.name != "." && file.name != ".." && ImGui::TreeNode(file.name.c_str())) {
std::string fpath = path + "/" + file.name;
RecurseFileSystem(fs, fpath);
ImGui::TreePop();
}
} else {
ImGui::TextUnformatted(file.name.c_str());
}
}
}
static void DrawFilesystemBrowser(ImConfig &cfg) {
if (!ImGui::Begin("File System", &cfg.filesystemBrowserOpen)) {
ImGui::End();
return;
}
for (auto &fs : pspFileSystem.GetMounts()) {
std::string path;
if (ImGui::TreeNode(fs.prefix.c_str())) {
auto system = fs.system;
RecurseFileSystem(system.get(), path);
ImGui::TreePop();
}
}
ImGui::End();
}
static const char *MemCheckConditionToString(MemCheckCondition cond) {
switch (cond) {
case MEMCHECK_READ: return "Read";
@@ -496,6 +534,10 @@ void DrawHLEModules(ImConfig &config) {
ImGui::End();
}
ImDebugger::ImDebugger() {
reqToken_ = g_requestManager.GenerateRequesterToken();
}
void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebug) {
// Snapshot the coreState to avoid inconsistency.
const CoreState coreState = ::coreState;
@@ -520,6 +562,47 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu
Core_Break("Menu:Break");
}
}
ImGui::Separator();
ImGui::MenuItem("Ignore bad memory accesses", nullptr, &g_Config.bIgnoreBadMemAccess);
ImGui::Separator();
/*
// Symbol stuff. Move to separate menu?
// Doesn't quite seem to work yet.
if (ImGui::MenuItem("Load symbol map...")) {
System_BrowseForFile(reqToken_, "Load symbol map", BrowseFileType::SYMBOL_MAP, [&](const char *responseString, int) {
Path path(responseString);
if (!g_symbolMap->LoadSymbolMap(path)) {
ERROR_LOG(Log::Common, "Failed to load symbol map");
}
disasm_.DirtySymbolMap();
});
}
if (ImGui::MenuItem("Save symbol map...")) {
System_BrowseForFileSave(reqToken_, "Save symbol map", "symbols.map", BrowseFileType::SYMBOL_MAP, [](const char *responseString, int) {
Path path(responseString);
if (!g_symbolMap->SaveSymbolMap(path)) {
ERROR_LOG(Log::Common, "Failed to save symbol map");
}
});
}
*/
if (ImGui::MenuItem("Reset symbol map")) {
g_symbolMap->Clear();
disasm_.DirtySymbolMap();
// NotifyDebuggerMapLoaded();
}
ImGui::Separator();
if (ImGui::MenuItem("Take screenshot")) {
g_TakeScreenshot = true;
}
if (ImGui::MenuItem("Restart graphics")) {
System_PostUIMessage(UIMessage::RESTART_GRAPHICS);
}
if (System_GetPropertyBool(SYSPROP_HAS_TEXT_CLIPBOARD)) {
if (ImGui::MenuItem("Copy memory base to clipboard")) {
System_CopyStringToClipboard(StringFromFormat("%016llx", (uint64_t)(uintptr_t)Memory::base));
}
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("CPU")) {
@@ -530,6 +613,7 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu
ImGui::EndMenu();
}
if (ImGui::BeginMenu("OS HLE")) {
ImGui::MenuItem("File System Browser", nullptr, &cfg_.filesystemBrowserOpen);
ImGui::MenuItem("HLE Threads", nullptr, &cfg_.threadsOpen);
ImGui::MenuItem("HLE Modules",nullptr, &cfg_.modulesOpen);
ImGui::MenuItem("sceAtrac", nullptr, &cfg_.atracOpen);
@@ -575,6 +659,10 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu
DrawBreakpointsView(mipsDebug, cfg_);
}
if (cfg_.filesystemBrowserOpen) {
DrawFilesystemBrowser(cfg_);
}
if (cfg_.threadsOpen) {
DrawThreadView(cfg_);
}
@@ -664,6 +752,9 @@ void ImDisasmWindow::Draw(MIPSDebugInterface *mipsDebug, bool *open, CoreState c
}
if (ImGui::BeginPopup("disSearch")) {
if (ImGui::IsWindowAppearing()) {
ImGui::SetKeyboardFocusHere();
}
if (ImGui::InputText("Search", searchTerm_, sizeof(searchTerm_), ImGuiInputTextFlags_EnterReturnsTrue)) {
disasmView_.Search(searchTerm_);
ImGui::CloseCurrentPopup();
@@ -684,7 +775,14 @@ void ImDisasmWindow::Draw(MIPSDebugInterface *mipsDebug, bool *open, CoreState c
}
ImGui::SameLine();
ImGui::Checkbox("Follow PC", &disasmView_.followPC_);
if (ImGui::SmallButton("Settings")) {
ImGui::OpenPopup("disSettings");
}
if (ImGui::BeginPopup("disSettings")) {
ImGui::Checkbox("Follow PC", &disasmView_.followPC_);
ImGui::EndPopup();
}
ImGui::SetNextItemWidth(100);
if (ImGui::InputScalar("Go to addr: ", ImGuiDataType_U32, &gotoAddr_, NULL, NULL, "%08X", ImGuiInputTextFlags_EnterReturnsTrue)) {
+9
View File
@@ -8,6 +8,8 @@
#include "Common/CommonTypes.h"
#include "Common/Log.h"
#include "Common/System/Request.h"
#include "Core/Core.h"
#include "Core/Debugger/DisassemblyManager.h"
@@ -32,6 +34,9 @@ public:
ImDisasmView &View() {
return disasmView_;
}
void DirtySymbolMap() {
symsDirty_ = true;
}
private:
// We just keep the state directly in the window. Can refactor later.
@@ -69,6 +74,7 @@ struct ImConfig {
bool structViewerOpen = false;
bool framebuffersOpen = false;
bool styleEditorOpen = false;
bool filesystemBrowserOpen = false;
// HLE explorer settings
// bool filterByUsed = true;
@@ -90,8 +96,11 @@ struct ImUiCommand {
};
struct ImDebugger {
ImDebugger();
void Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebug);
RequesterToken reqToken_;
ImDisasmWindow disasm_;
ImLuaConsole luaConsole_;
ImStructViewer structViewer_;
-1
View File
@@ -23,7 +23,6 @@ public:
// Public variables bounds to imgui checkboxes
bool followPC_ = true;
void Draw(ImDrawList *drawList);
void PopupMenu();
+3
View File
@@ -514,6 +514,9 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string
case BrowseFileType::ZIP:
supportedExtensions = { ".zip" };
break;
case BrowseFileType::SYMBOL_MAP:
supportedExtensions = { ".map" };
break;
case BrowseFileType::DB:
supportedExtensions = { ".db" };
break;
+1 -2
View File
@@ -813,7 +813,7 @@ namespace MainWindow {
case ID_DEBUG_MEMORYBASE:
{
W32Util::CopyTextToClipboard(hWnd, ConvertUTF8ToWString(StringFromFormat("%016llx", (uint64_t)(uintptr_t)Memory::base)));
System_CopyStringToClipboard(StringFromFormat("%016llx", (uint64_t)(uintptr_t)Memory::base));
break;
}
@@ -823,7 +823,6 @@ namespace MainWindow {
if (!InputBox_GetString(hInst, hWnd, L"Disc filename", filename, filename)) {
break;
}
const char *lastSlash = strrchr(filename.c_str(), '/');
if (lastSlash) {
fn = lastSlash + 1;
+31 -26
View File
@@ -489,7 +489,7 @@ void System_Notify(SystemNotification notification) {
}
}
static std::wstring MakeFilter(std::wstring filter) {
static std::wstring FinalizeFilter(std::wstring filter) {
for (size_t i = 0; i < filter.length(); i++) {
if (filter[i] == '|')
filter[i] = '\0';
@@ -497,6 +497,27 @@ static std::wstring MakeFilter(std::wstring filter) {
return filter;
}
static std::wstring MakeWindowsFilter(BrowseFileType type) {
switch (type) {
case BrowseFileType::BOOTABLE:
return FinalizeFilter(L"All supported file types (*.iso *.cso *.chd *.pbp *.elf *.prx *.zip *.ppdmp)|*.pbp;*.elf;*.iso;*.cso;*.chd;*.prx;*.zip;*.ppdmp|PSP ROMs (*.iso *.cso *.chd *.pbp *.elf *.prx)|*.pbp;*.elf;*.iso;*.cso;*.chd;*.prx|Homebrew/Demos installers (*.zip)|*.zip|All files (*.*)|*.*||");
case BrowseFileType::INI:
return FinalizeFilter(L"Ini files (*.ini)|*.ini|All files (*.*)|*.*||");
case BrowseFileType::ZIP:
return FinalizeFilter(L"ZIP files (*.zip)|*.zip|All files (*.*)|*.*||");
case BrowseFileType::DB:
return FinalizeFilter(L"Cheat db files (*.db)|*.db|All files (*.*)|*.*||");
case BrowseFileType::SOUND_EFFECT:
return FinalizeFilter(L"Sound effect files (*.wav *.mp3)|*.wav;*.mp3|All files (*.*)|*.*||");
case BrowseFileType::SYMBOL_MAP:
return FinalizeFilter(L"Symbol map files (*.ppmap)|*.ppmap|All files (*.*)|*.*||");
case BrowseFileType::ANY:
return FinalizeFilter(L"All files (*.*)|*.*||");
default:
return std::wstring();
}
}
bool System_MakeRequest(SystemRequestType type, int requestId, const std::string &param1, const std::string &param2, int64_t param3, int64_t param4) {
switch (type) {
case SystemRequestType::EXIT_APP:
@@ -574,7 +595,7 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string
std::thread([=] {
std::string out;
if (W32Util::BrowseForFileName(true, MainWindow::GetHWND(), ConvertUTF8ToWString(param1).c_str(), nullptr,
MakeFilter(L"All supported images (*.jpg *.jpeg *.png)|*.jpg;*.jpeg;*.png|All files (*.*)|*.*||").c_str(), L"jpg", out)) {
FinalizeFilter(L"All supported images (*.jpg *.jpeg *.png)|*.jpg;*.jpeg;*.png|All files (*.*)|*.*||").c_str(), L"jpg", out)) {
g_requestManager.PostSystemSuccess(requestId, out.c_str());
} else {
g_requestManager.PostSystemFailure(requestId);
@@ -582,35 +603,19 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string
}).detach();
return true;
case SystemRequestType::BROWSE_FOR_FILE:
case SystemRequestType::BROWSE_FOR_FILE_SAVE:
{
BrowseFileType type = (BrowseFileType)param3;
std::wstring filter;
switch (type) {
case BrowseFileType::BOOTABLE:
filter = MakeFilter(L"All supported file types (*.iso *.cso *.chd *.pbp *.elf *.prx *.zip *.ppdmp)|*.pbp;*.elf;*.iso;*.cso;*.chd;*.prx;*.zip;*.ppdmp|PSP ROMs (*.iso *.cso *.chd *.pbp *.elf *.prx)|*.pbp;*.elf;*.iso;*.cso;*.chd;*.prx|Homebrew/Demos installers (*.zip)|*.zip|All files (*.*)|*.*||");
break;
case BrowseFileType::INI:
filter = MakeFilter(L"Ini files (*.ini)|*.ini|All files (*.*)|*.*||");
break;
case BrowseFileType::ZIP:
filter = MakeFilter(L"ZIP files (*.zip)|*.zip|All files (*.*)|*.*||");
break;
case BrowseFileType::DB:
filter = MakeFilter(L"Cheat db files (*.db)|*.db|All files (*.*)|*.*||");
break;
case BrowseFileType::SOUND_EFFECT:
filter = MakeFilter(L"Sound effect files (*.wav *.mp3)|*.wav;*.mp3|All files (*.*)|*.*||");
break;
case BrowseFileType::ANY:
filter = MakeFilter(L"All files (*.*)|*.*||");
break;
default:
const BrowseFileType browseType = (BrowseFileType)param3;
std::wstring filter = MakeWindowsFilter(browseType);
std::wstring initialFilename = ConvertUTF8ToWString(param2); // TODO: Plumb through
if (filter.empty()) {
// Unsupported.
return false;
}
bool load = type == SystemRequestType::BROWSE_FOR_FILE;
std::thread([=] {
std::string out;
if (W32Util::BrowseForFileName(true, MainWindow::GetHWND(), ConvertUTF8ToWString(param1).c_str(), nullptr, filter.c_str(), L"", out)) {
if (W32Util::BrowseForFileName(load, MainWindow::GetHWND(), ConvertUTF8ToWString(param1).c_str(), nullptr, filter.c_str(), L"", out)) {
g_requestManager.PostSystemSuccess(requestId, out.c_str());
} else {
g_requestManager.PostSystemFailure(requestId);