CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Windows/Debugger/DumpMemoryWindow.cpp
Views: 1401
1
#include <algorithm>
2
#include <cstdio>
3
#include <mutex>
4
#include "Common/Data/Encoding/Utf8.h"
5
#include "Core/Core.h"
6
#include "Core/HLE/ReplaceTables.h"
7
#include "Core/MemMap.h"
8
#include "Core/MIPS/JitCommon/JitBlockCache.h"
9
#include "Windows/Debugger/DumpMemoryWindow.h"
10
#include "Windows/resource.h"
11
#include "Windows/W32Util/ShellUtil.h"
12
13
DumpMemoryWindow* DumpMemoryWindow::bp;
14
15
void DumpMemoryWindow::HandleBrowseClick(HWND hwnd) {
16
std::wstring buffer;
17
HWND filenameWnd = GetDlgItem(hwnd, IDC_DUMP_FILENAME);
18
buffer.resize(GetWindowTextLengthW(filenameWnd) + 1);
19
GetWindowTextW(filenameWnd, &buffer[0], (int)buffer.size());
20
std::string fn = ConvertWStringToUTF8(buffer);
21
22
bool result = W32Util::BrowseForFileName(false, hwnd, L"Select filename", NULL, NULL, NULL, fn);
23
if (result) {
24
filenameChosen_ = true;
25
buffer = ConvertUTF8ToWString(fn);
26
SetWindowTextW(filenameWnd, buffer.c_str());
27
}
28
}
29
30
INT_PTR CALLBACK DumpMemoryWindow::dlgFunc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
31
{
32
switch (iMsg)
33
{
34
case WM_INITDIALOG:
35
bp->changeMode(hwnd,bp->selectedMode);
36
return TRUE;
37
case WM_COMMAND:
38
switch (LOWORD(wParam))
39
{
40
case IDC_DUMP_USERMEMORY:
41
switch (HIWORD(wParam))
42
{
43
case BN_CLICKED:
44
bp->changeMode(hwnd,MODE_RAM);
45
break;
46
}
47
break;
48
case IDC_DUMP_VRAM:
49
switch (HIWORD(wParam))
50
{
51
case BN_CLICKED:
52
bp->changeMode(hwnd,MODE_VRAM);
53
break;
54
}
55
break;
56
case IDC_DUMP_SCRATCHPAD:
57
switch (HIWORD(wParam))
58
{
59
case BN_CLICKED:
60
bp->changeMode(hwnd,MODE_SCRATCHPAD);
61
break;
62
}
63
break;
64
case IDC_DUMP_CUSTOMRANGE:
65
switch (HIWORD(wParam))
66
{
67
case BN_CLICKED:
68
bp->changeMode(hwnd,MODE_CUSTOM);
69
break;
70
}
71
break;
72
case IDC_DUMP_BROWSEFILENAME:
73
switch (HIWORD(wParam))
74
{
75
case BN_CLICKED:
76
bp->HandleBrowseClick(hwnd);
77
break;
78
}
79
break;
80
case IDOK:
81
if (bp->fetchDialogData(hwnd)) {
82
bool priorDumpWasStepping = Core_IsStepping();
83
if (!priorDumpWasStepping && PSP_IsInited()) {
84
// If emulator isn't paused force paused state, but wait before locking.
85
Core_EnableStepping(true, "memory.access", bp->start);
86
Core_WaitInactive();
87
}
88
89
auto memLock = Memory::Lock();
90
if (!PSP_IsInited())
91
break;
92
93
FILE *output = _wfopen(bp->fileName_.c_str(), L"wb");
94
if (output == nullptr) {
95
char errorMessage[2048];
96
snprintf(errorMessage, sizeof(errorMessage), "Could not open file \"%S\".", bp->fileName_.c_str());
97
MessageBoxA(hwnd, errorMessage, "Error", MB_OK);
98
break;
99
}
100
101
bool includeReplacements = SendMessage(GetDlgItem(hwnd, IDC_DUMP_INCLUDEHACKS), BM_GETCHECK, 0, 0) != 0;
102
if (includeReplacements) {
103
fwrite(Memory::GetPointer(bp->start), 1, bp->size, output);
104
} else {
105
auto savedReplacements = SaveAndClearReplacements();
106
std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);
107
if (MIPSComp::jit) {
108
auto savedBlocks = MIPSComp::jit->SaveAndClearEmuHackOps();
109
fwrite(Memory::GetPointer(bp->start), 1, bp->size, output);
110
MIPSComp::jit->RestoreSavedEmuHackOps(savedBlocks);
111
} else {
112
fwrite(Memory::GetPointer(bp->start), 1, bp->size, output);
113
}
114
RestoreSavedReplacements(savedReplacements);
115
}
116
117
fclose(output);
118
if (!priorDumpWasStepping) {
119
// If emulator wasn't paused before memory dump resume emulation automatically.
120
Core_EnableStepping(false);
121
}
122
123
MessageBoxA(hwnd, "Done.", "Information", MB_OK);
124
EndDialog(hwnd, true);
125
}
126
break;
127
case IDCANCEL:
128
EndDialog(hwnd,false);
129
break;
130
}
131
132
case WM_KEYDOWN:
133
134
break;
135
}
136
137
return FALSE;
138
}
139
140
static bool isInInterval(u32 start, u32 end, u32 value)
141
{
142
return start <= value && value < end;
143
}
144
145
bool DumpMemoryWindow::fetchDialogData(HWND hwnd)
146
{
147
char str[256],errorMessage[256];
148
PostfixExpression exp;
149
150
// parse start address
151
GetWindowTextA(GetDlgItem(hwnd,IDC_DUMP_STARTADDRESS),str,256);
152
if (cpu->initExpression(str,exp) == false
153
|| cpu->parseExpression(exp,start) == false)
154
{
155
snprintf(errorMessage, sizeof(errorMessage), "Invalid address expression \"%s\".",str);
156
MessageBoxA(hwnd,errorMessage,"Error",MB_OK);
157
return false;
158
}
159
160
// parse size
161
GetWindowTextA(GetDlgItem(hwnd,IDC_DUMP_SIZE),str,256);
162
if (cpu->initExpression(str,exp) == false
163
|| cpu->parseExpression(exp,size) == false)
164
{
165
snprintf(errorMessage, sizeof(errorMessage), "Invalid size expression \"%s\".",str);
166
MessageBoxA(hwnd,errorMessage,"Error",MB_OK);
167
return false;
168
}
169
170
if (size == 0)
171
{
172
MessageBoxA(hwnd,"Invalid size 0.","Error",MB_OK);
173
return false;
174
}
175
176
// get filename
177
fileName_.resize(GetWindowTextLengthW(GetDlgItem(hwnd, IDC_DUMP_FILENAME)) + 1);
178
GetWindowTextW(GetDlgItem(hwnd, IDC_DUMP_FILENAME), &fileName_[0], (int)fileName_.size());
179
if (fileName_.size() == 0)
180
return false;
181
182
// now check if data makes sense...
183
bool invalidSize = false;
184
bool invalidAddress = false;
185
if (isInInterval(PSP_GetScratchpadMemoryBase(),PSP_GetScratchpadMemoryEnd(),start))
186
{
187
invalidSize = !isInInterval(PSP_GetScratchpadMemoryBase(),PSP_GetScratchpadMemoryEnd(),start+size-1);
188
} else if (isInInterval(PSP_GetVidMemBase(),PSP_GetVidMemEnd(),start))
189
{
190
invalidSize = !isInInterval(PSP_GetVidMemBase(),PSP_GetVidMemEnd(),start+size-1);
191
} else if (isInInterval(PSP_GetKernelMemoryBase(),PSP_GetUserMemoryEnd(),start))
192
{
193
invalidSize = !isInInterval(PSP_GetKernelMemoryBase(),PSP_GetUserMemoryEnd(),start+size-1);
194
} else
195
{
196
invalidAddress = true;
197
}
198
199
if (invalidAddress)
200
{
201
snprintf(errorMessage, sizeof(errorMessage), "Invalid address 0x%08X.",start);
202
MessageBoxA(hwnd,errorMessage,"Error",MB_OK);
203
return false;
204
} else if (invalidSize)
205
{
206
snprintf(errorMessage, sizeof(errorMessage), "Invalid end address 0x%08X.",start+size);
207
MessageBoxA(hwnd,errorMessage,"Error",MB_OK);
208
return false;
209
}
210
211
return true;
212
}
213
214
void DumpMemoryWindow::changeMode(HWND hwnd, Mode newMode)
215
{
216
char buffer[128];
217
selectedMode = newMode;
218
219
SendMessage(GetDlgItem(hwnd,IDC_DUMP_USERMEMORY),BM_SETCHECK,selectedMode == MODE_RAM ? BST_CHECKED : BST_UNCHECKED,0);
220
SendMessage(GetDlgItem(hwnd,IDC_DUMP_VRAM),BM_SETCHECK,selectedMode == MODE_VRAM ? BST_CHECKED : BST_UNCHECKED,0);
221
SendMessage(GetDlgItem(hwnd,IDC_DUMP_SCRATCHPAD),BM_SETCHECK,selectedMode == MODE_SCRATCHPAD ? BST_CHECKED : BST_UNCHECKED,0);
222
SendMessage(GetDlgItem(hwnd,IDC_DUMP_CUSTOMRANGE),BM_SETCHECK,selectedMode == MODE_CUSTOM ? BST_CHECKED : BST_UNCHECKED,0);
223
224
if (selectedMode == MODE_CUSTOM)
225
{
226
EnableWindow(GetDlgItem(hwnd,IDC_DUMP_STARTADDRESS),TRUE);
227
EnableWindow(GetDlgItem(hwnd,IDC_DUMP_SIZE),TRUE);
228
229
if (filenameChosen_ == false)
230
SetWindowTextA(GetDlgItem(hwnd,IDC_DUMP_FILENAME),"Custom.dump");
231
} else {
232
u32 start = 0, size = 0;
233
const char *defaultFileName = "";
234
235
switch (selectedMode) {
236
case MODE_RAM:
237
start = PSP_GetUserMemoryBase();
238
size = PSP_GetUserMemoryEnd()-start;
239
defaultFileName = "RAM.dump";
240
break;
241
case MODE_VRAM:
242
start = PSP_GetVidMemBase();
243
size = PSP_GetVidMemEnd()-start;
244
defaultFileName = "VRAM.dump";
245
break;
246
case MODE_SCRATCHPAD:
247
start = PSP_GetScratchpadMemoryBase();
248
size = PSP_GetScratchpadMemoryEnd()-start;
249
defaultFileName = "Scratchpad.dump";
250
break;
251
}
252
253
snprintf(buffer, sizeof(buffer), "0x%08X", start);
254
SetWindowTextA(GetDlgItem(hwnd,IDC_DUMP_STARTADDRESS),buffer);
255
EnableWindow(GetDlgItem(hwnd,IDC_DUMP_STARTADDRESS),FALSE);
256
257
snprintf(buffer, sizeof(buffer), "0x%08X", size);
258
SetWindowTextA(GetDlgItem(hwnd,IDC_DUMP_SIZE),buffer);
259
EnableWindow(GetDlgItem(hwnd,IDC_DUMP_SIZE),FALSE);
260
261
if (filenameChosen_ == false)
262
SetWindowTextA(GetDlgItem(hwnd,IDC_DUMP_FILENAME),defaultFileName);
263
}
264
}
265
266
bool DumpMemoryWindow::exec()
267
{
268
bp = this;
269
bool result = DialogBoxParam(GetModuleHandle(0),MAKEINTRESOURCE(IDD_DUMPMEMORY),parentHwnd,dlgFunc,(LPARAM)this) != 0;
270
return result;
271
}
272
273