Commit | Line | Data |
---|---|---|
ef79bbde P |
1 | /* Memory Viewer/Dumper for PCSX-Reloaded |
2 | * Copyright (C) 2010, Wei Mingzhi <whistler_wmz@users.sf.net>. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; either version 2 of the License, or | |
7 | * (at your option) any later version. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License | |
15 | * along with this program; if not, write to the Free Software | |
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA | |
17 | */ | |
18 | ||
19 | #include "Linux.h" | |
20 | #include "../libpcsxcore/psxmem.h" | |
21 | #include <glade/glade.h> | |
22 | ||
23 | #define MEMVIEW_MAX_LINES 256 | |
24 | ||
25 | static GtkWidget *MemViewDlg = NULL; | |
26 | static u32 MemViewAddress = 0; | |
27 | ||
28 | static void UpdateMemViewDlg() { | |
29 | s32 start, end; | |
30 | int i; | |
31 | char bufaddr[9], bufdata[16][3], buftext[17]; | |
32 | ||
33 | GtkListStore *store = gtk_list_store_new(18, G_TYPE_STRING, G_TYPE_STRING, | |
34 | G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, | |
35 | G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, | |
36 | G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, | |
37 | G_TYPE_STRING); | |
38 | ||
39 | GtkTreeIter iter; | |
40 | GtkWidget *widget; | |
41 | GladeXML *xml; | |
42 | ||
43 | xml = glade_get_widget_tree(MemViewDlg); | |
44 | ||
45 | MemViewAddress &= 0x1fffff; | |
46 | ||
47 | sprintf(buftext, "%.8X", MemViewAddress | 0x80000000); | |
48 | widget = glade_xml_get_widget(xml, "entry_address"); | |
49 | gtk_entry_set_text(GTK_ENTRY(widget), buftext); | |
50 | ||
51 | start = MemViewAddress & 0x1ffff0; | |
52 | end = start + MEMVIEW_MAX_LINES * 16; | |
53 | ||
54 | if (end > 0x1fffff) end = 0x1fffff; | |
55 | ||
56 | widget = glade_xml_get_widget(xml, "GtkCList_MemView"); | |
57 | ||
58 | buftext[16] = '\0'; | |
59 | ||
60 | while (start < end) { | |
61 | sprintf(bufaddr, "%.8X", start | 0x80000000); | |
62 | ||
63 | for (i = 0; i < 16; i++) { | |
64 | buftext[i] = psxMs8(start + i); | |
65 | sprintf(bufdata[i], "%.2X", (u8)buftext[i]); | |
66 | if ((u8)buftext[i] < 32 || (u8)buftext[i] >= 127) | |
67 | buftext[i] = '.'; | |
68 | } | |
69 | ||
70 | gtk_list_store_append(store, &iter); | |
71 | gtk_list_store_set(store, &iter, 0, bufaddr, 1, bufdata[0], | |
72 | 2, bufdata[1], 3, bufdata[2], 4, bufdata[3], 5, bufdata[4], | |
73 | 6, bufdata[5], 7, bufdata[6], 8, bufdata[7], 9, bufdata[8], | |
74 | 10, bufdata[9], 11, bufdata[10], 12, bufdata[11], 13, bufdata[12], | |
75 | 14, bufdata[13], 15, bufdata[14], 16, bufdata[15], 17, buftext, -1); | |
76 | ||
77 | start += 16; | |
78 | } | |
79 | ||
80 | gtk_tree_view_set_model(GTK_TREE_VIEW(widget), GTK_TREE_MODEL(store)); | |
81 | g_object_unref(G_OBJECT(store)); | |
82 | gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(widget), TRUE); | |
83 | gtk_widget_show(widget); | |
84 | } | |
85 | ||
86 | static void MemView_Go() { | |
87 | GtkWidget *widget; | |
88 | GladeXML *xml; | |
89 | ||
90 | xml = glade_get_widget_tree(MemViewDlg); | |
91 | widget = glade_xml_get_widget(xml, "entry_address"); | |
92 | ||
93 | sscanf(gtk_entry_get_text(GTK_ENTRY(widget)), "%x", &MemViewAddress); | |
94 | ||
95 | UpdateMemViewDlg(); | |
96 | } | |
97 | ||
98 | static void MemView_Dump() { | |
99 | GtkWidget *dlg; | |
100 | GtkWidget *box, *table, *label, *start_edit, *length_edit; | |
101 | char buf[10]; | |
102 | ||
103 | dlg = gtk_dialog_new_with_buttons(_("Memory Dump"), GTK_WINDOW(MemViewDlg), | |
104 | GTK_DIALOG_MODAL, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, | |
105 | GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); | |
106 | ||
107 | box = GTK_WIDGET(GTK_DIALOG(dlg)->vbox); | |
108 | ||
109 | table = gtk_table_new(2, 2, FALSE); | |
110 | ||
111 | label = gtk_label_new(_("Start Address (Hexadecimal):")); | |
112 | gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, 0, 0, 5, 5); | |
113 | gtk_widget_show(label); | |
114 | ||
115 | start_edit = gtk_entry_new_with_max_length(8); | |
116 | sprintf(buf, "%.8X", MemViewAddress | 0x80000000); | |
117 | gtk_entry_set_text(GTK_ENTRY(start_edit), buf); | |
118 | gtk_table_attach(GTK_TABLE(table), start_edit, 1, 2, 0, 1, 0, 0, 5, 5); | |
119 | gtk_widget_show(start_edit); | |
120 | ||
121 | label = gtk_label_new(_("Length (Decimal):")); | |
122 | gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, 0, 0, 5, 5); | |
123 | gtk_widget_show(label); | |
124 | ||
125 | length_edit = gtk_entry_new(); | |
126 | gtk_table_attach(GTK_TABLE(table), length_edit, 1, 2, 1, 2, 0, 0, 5, 5); | |
127 | gtk_widget_show(length_edit); | |
128 | ||
129 | gtk_box_pack_start(GTK_BOX(box), table, FALSE, FALSE, 5); | |
130 | ||
131 | gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER); | |
132 | gtk_widget_show_all(dlg); | |
133 | ||
134 | if (gtk_dialog_run(GTK_DIALOG(dlg)) == GTK_RESPONSE_ACCEPT) { | |
135 | s32 start = 0, length = 0; | |
136 | ||
137 | sscanf(gtk_entry_get_text(GTK_ENTRY(start_edit)), "%x", &start); | |
138 | sscanf(gtk_entry_get_text(GTK_ENTRY(length_edit)), "%d", &length); | |
139 | ||
140 | start &= 0x1fffff; | |
141 | ||
142 | if (start + length > 0x1fffff) { | |
143 | length = 0x1fffff - start; | |
144 | } | |
145 | ||
146 | if (length > 0) { | |
147 | GtkWidget *file_chooser = gtk_file_chooser_dialog_new(_("Dump to File"), | |
148 | NULL, GTK_FILE_CHOOSER_ACTION_SAVE, | |
149 | GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, | |
150 | GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); | |
151 | ||
152 | gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_chooser), getenv("HOME")); | |
153 | ||
154 | if (gtk_dialog_run(GTK_DIALOG(file_chooser)) == GTK_RESPONSE_ACCEPT) { | |
155 | gchar *file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_chooser)); | |
156 | FILE *fp = fopen(file, "wb"); | |
157 | ||
158 | if (fp != NULL) { | |
159 | fwrite(&psxM[start], 1, length, fp); | |
160 | fclose(fp); | |
161 | } else { | |
162 | SysMessage(_("Error writing to %s!"), file); | |
163 | } | |
164 | ||
165 | g_free(file); | |
166 | } | |
167 | ||
168 | gtk_widget_destroy(file_chooser); | |
169 | } | |
170 | } | |
171 | ||
172 | gtk_widget_destroy(dlg); | |
173 | } | |
174 | ||
175 | static void MemView_Patch() { | |
176 | GtkWidget *dlg; | |
177 | GtkWidget *box, *table, *label, *addr_edit, *val_edit; | |
178 | char buf[10]; | |
179 | ||
180 | dlg = gtk_dialog_new_with_buttons(_("Memory Patch"), GTK_WINDOW(MemViewDlg), | |
181 | GTK_DIALOG_MODAL, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, | |
182 | GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); | |
183 | ||
184 | box = GTK_WIDGET(GTK_DIALOG(dlg)->vbox); | |
185 | ||
186 | table = gtk_table_new(2, 2, FALSE); | |
187 | ||
188 | label = gtk_label_new(_("Address (Hexadecimal):")); | |
189 | gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, 0, 0, 5, 5); | |
190 | gtk_widget_show(label); | |
191 | ||
192 | addr_edit = gtk_entry_new_with_max_length(8); | |
193 | sprintf(buf, "%.8X", MemViewAddress | 0x80000000); | |
194 | gtk_entry_set_text(GTK_ENTRY(addr_edit), buf); | |
195 | gtk_table_attach(GTK_TABLE(table), addr_edit, 1, 2, 0, 1, 0, 0, 5, 5); | |
196 | gtk_widget_show(addr_edit); | |
197 | ||
198 | label = gtk_label_new(_("Value (Hexa string):")); | |
199 | gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, 0, 0, 5, 5); | |
200 | gtk_widget_show(label); | |
201 | ||
202 | val_edit = gtk_entry_new(); | |
203 | gtk_table_attach(GTK_TABLE(table), val_edit, 1, 2, 1, 2, 0, 0, 5, 5); | |
204 | gtk_widget_show(val_edit); | |
205 | ||
206 | gtk_box_pack_start(GTK_BOX(box), table, FALSE, FALSE, 5); | |
207 | ||
208 | gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER); | |
209 | gtk_widget_show_all(dlg); | |
210 | ||
211 | if (gtk_dialog_run(GTK_DIALOG(dlg)) == GTK_RESPONSE_ACCEPT) { | |
212 | u32 addr = 0xffffffff, val = 0; | |
213 | const char *p = gtk_entry_get_text(GTK_ENTRY(val_edit)); | |
214 | int r = strlen(p); | |
215 | ||
216 | sscanf(gtk_entry_get_text(GTK_ENTRY(addr_edit)), "%x", &addr); | |
217 | ||
218 | if (r > 0 && addr != 0xffffffff) { | |
219 | addr &= 0x1fffff; | |
220 | MemViewAddress = addr; | |
221 | ||
222 | while (r > 0 && addr <= 0x1fffff) { | |
223 | sscanf(p, "%2x", &val); | |
224 | p += 2; | |
225 | r -= 2; | |
226 | ||
227 | while (r > 0 && (*p == '\t' || *p == ' ')) { | |
228 | p++; | |
229 | r--; | |
230 | } | |
231 | ||
232 | psxMemWrite8(addr, (u8)val); | |
233 | addr++; | |
234 | } | |
235 | ||
236 | UpdateMemViewDlg(); | |
237 | } | |
238 | } | |
239 | ||
240 | gtk_widget_destroy(dlg); | |
241 | } | |
242 | ||
243 | // close the memory viewer window | |
244 | static void MemView_Close(GtkWidget *widget, gpointer user_data) { | |
245 | gtk_widget_destroy(MemViewDlg); | |
246 | MemViewDlg = NULL; | |
247 | } | |
248 | ||
249 | void RunDebugMemoryDialog() { | |
250 | GladeXML *xml; | |
251 | GtkWidget *widget; | |
252 | GtkCellRenderer *renderer; | |
253 | GtkTreeViewColumn *column; | |
254 | PangoFontDescription *pfd; | |
255 | int i; | |
256 | ||
257 | xml = glade_xml_new(PACKAGE_DATA_DIR "pcsx.glade2", "MemViewDlg", NULL); | |
258 | if (!xml) { | |
259 | g_warning(_("Error: Glade interface could not be loaded!")); | |
260 | return; | |
261 | } | |
262 | ||
263 | MemViewDlg = glade_xml_get_widget(xml, "MemViewDlg"); | |
264 | gtk_window_set_title(GTK_WINDOW(MemViewDlg), _("Memory Viewer")); | |
265 | ||
266 | widget = glade_xml_get_widget(xml, "GtkCList_MemView"); | |
267 | ||
268 | renderer = gtk_cell_renderer_text_new(); | |
269 | column = gtk_tree_view_column_new_with_attributes(_("Address"), | |
270 | renderer, "text", 0, NULL); | |
271 | gtk_tree_view_append_column(GTK_TREE_VIEW(widget), column); | |
272 | ||
273 | for (i = 0; i < 16; i++) { | |
274 | const char *p = "0123456789ABCDEF"; | |
275 | char buf[2]; | |
276 | ||
277 | buf[0] = p[i]; | |
278 | buf[1] = '\0'; | |
279 | ||
280 | renderer = gtk_cell_renderer_text_new(); | |
281 | column = gtk_tree_view_column_new_with_attributes(buf, | |
282 | renderer, "text", i + 1, NULL); | |
283 | gtk_tree_view_append_column(GTK_TREE_VIEW(widget), column); | |
284 | } | |
285 | ||
286 | renderer = gtk_cell_renderer_text_new(); | |
287 | column = gtk_tree_view_column_new_with_attributes(_("Text"), | |
288 | renderer, "text", 17, NULL); | |
289 | gtk_tree_view_append_column(GTK_TREE_VIEW(widget), column); | |
290 | ||
291 | pfd = pango_font_description_from_string("Bitstream Vera Sans Mono, " | |
292 | "DejaVu Sans Mono, Liberation Mono, FreeMono, Sans Mono 9"); | |
293 | gtk_widget_modify_font(widget, pfd); | |
294 | pango_font_description_free(pfd); | |
295 | ||
296 | UpdateMemViewDlg(); | |
297 | ||
298 | widget = glade_xml_get_widget(xml, "btn_dump"); | |
299 | g_signal_connect_data(GTK_OBJECT(widget), "clicked", | |
300 | GTK_SIGNAL_FUNC(MemView_Dump), xml, NULL, G_CONNECT_AFTER); | |
301 | ||
302 | widget = glade_xml_get_widget(xml, "btn_patch"); | |
303 | g_signal_connect_data(GTK_OBJECT(widget), "clicked", | |
304 | GTK_SIGNAL_FUNC(MemView_Patch), xml, NULL, G_CONNECT_AFTER); | |
305 | ||
306 | widget = glade_xml_get_widget(xml, "btn_go"); | |
307 | g_signal_connect_data(GTK_OBJECT(widget), "clicked", | |
308 | GTK_SIGNAL_FUNC(MemView_Go), xml, NULL, G_CONNECT_AFTER); | |
309 | ||
310 | g_signal_connect_data(GTK_OBJECT(MemViewDlg), "response", | |
311 | GTK_SIGNAL_FUNC(MemView_Close), xml, (GClosureNotify)g_object_unref, G_CONNECT_AFTER); | |
312 | } |