1 /* debugger.c: the GTK+ debugger
2 Copyright (c) 2002-2012 Philip Kendall
3
4 $Id: debugger.c 4908 2013-03-10 22:13:57Z sbaldovi $
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20 Author contact information:
21
22 E-mail: philip-fuse@shadowmagic.org.uk
23
24 */
25
26 #include <config.h>
27
28 #include <stdio.h>
29 #include <string.h>
30
31 #include <gdk/gdkkeysyms.h>
32 #include <gtk/gtk.h>
33
34 #include <libspectrum.h>
35
36 #include "debugger/debugger.h"
37 #include "event.h"
38 #include "fuse.h"
39 #include "gtkcompat.h"
40 #include "gtkinternals.h"
41 #include "machine.h"
42 #include "memory.h"
43 #include "peripherals/ide/zxcf.h"
44 #include "peripherals/scld.h"
45 #include "peripherals/ula.h"
46 #include "settings.h"
47 #include "ui/ui.h"
48 #include "z80/z80.h"
49 #include "z80/z80_macros.h"
50
51 /* The various debugger panes */
52 typedef enum debugger_pane {
53
54 DEBUGGER_PANE_BEGIN = 1, /* Start marker */
55
56 DEBUGGER_PANE_REGISTERS = DEBUGGER_PANE_BEGIN,
57 DEBUGGER_PANE_MEMORYMAP,
58 DEBUGGER_PANE_BREAKPOINTS,
59 DEBUGGER_PANE_DISASSEMBLY,
60 DEBUGGER_PANE_STACK,
61 DEBUGGER_PANE_EVENTS,
62
63 DEBUGGER_PANE_END /* End marker */
64
65 } debugger_pane;
66
67 /* The columns used in the breakpoints pane */
68
69 enum {
70 BREAKPOINTS_COLUMN_ID,
71 BREAKPOINTS_COLUMN_TYPE,
72 BREAKPOINTS_COLUMN_VALUE,
73 BREAKPOINTS_COLUMN_IGNORE,
74 BREAKPOINTS_COLUMN_LIFE,
75 BREAKPOINTS_COLUMN_CONDITION,
76
77 BREAKPOINTS_COLUMN_COUNT
78 };
79
80 /* The columns used in the disassembly pane */
81
82 enum {
83 DISASSEMBLY_COLUMN_ADDRESS,
84 DISASSEMBLY_COLUMN_INSTRUCTION,
85
86 DISASSEMBLY_COLUMN_COUNT
87 };
88
89 /* The columns used in the stack pane */
90
91 enum {
92 STACK_COLUMN_ADDRESS,
93 STACK_COLUMN_VALUE_TEXT,
94 STACK_COLUMN_VALUE_INT,
95
96 STACK_COLUMN_COUNT
97 };
98
99 /* The columns used in the events pane */
100
101 enum {
102 EVENTS_COLUMN_TIME,
103 EVENTS_COLUMN_TYPE,
104
105 EVENTS_COLUMN_COUNT
106 };
107
108 static int create_dialog( void );
109 static int hide_hidden_panes( void );
110 static GtkCheckMenuItem* get_pane_menu_item( debugger_pane pane );
111 static GtkWidget* get_pane( debugger_pane pane );
112 static int create_menu_bar( GtkBox *parent, GtkAccelGroup **accel_group );
113 static void toggle_display( GtkToggleAction* action, debugger_pane pane );
114 static void toggle_display_registers( GtkToggleAction* action, gpointer data );
115 static void toggle_display_memory_map( GtkToggleAction* action, gpointer data );
116 static void toggle_display_breakpoints( GtkToggleAction* action,
117 gpointer data );
118 static void toggle_display_disassembly( GtkToggleAction* action,
119 gpointer data );
120 static void toggle_display_stack( GtkToggleAction* action, gpointer data );
121 static void toggle_display_events( GtkToggleAction* action, gpointer data );
122 static int create_register_display( GtkBox *parent, gtkui_font font );
123 static int create_memory_map( GtkBox *parent );
124 static void create_breakpoints( GtkBox *parent );
125 static void create_disassembly( GtkBox *parent, gtkui_font font );
126 static void create_stack_display( GtkBox *parent, gtkui_font font );
127 static void stack_activate( GtkTreeView *tree_view, GtkTreePath *path,
128 GtkTreeViewColumn *column, gpointer user_data );
129 static void create_events( GtkBox *parent );
130 static void events_activate( GtkTreeView *tree_view, GtkTreePath *path,
131 GtkTreeViewColumn *column, gpointer user_data );
132 static int create_command_entry( GtkBox *parent, GtkAccelGroup *accel_group );
133 static int create_buttons( GtkDialog *parent, GtkAccelGroup *accel_group );
134
135 static int activate_debugger( void );
136 static void update_memory_map( void );
137 static void update_breakpoints( void );
138 static void update_disassembly( void );
139 static void update_events( void );
140 static void add_event( gpointer data, gpointer user_data );
141 static int deactivate_debugger( void );
142
143 static void move_disassembly( GtkAdjustment *adjustment, gpointer user_data );
144
145 static void evaluate_command( GtkWidget *widget, gpointer user_data );
146 static void gtkui_debugger_done_step( GtkWidget *widget, gpointer user_data );
147 static void gtkui_debugger_done_continue( GtkWidget *widget,
148 gpointer user_data );
149 static void gtkui_debugger_break( GtkWidget *widget, gpointer user_data );
150 static gboolean delete_dialog( GtkWidget *widget, GdkEvent *event,
151 gpointer user_data );
152 static void gtkui_debugger_done_close( GtkWidget *widget, gpointer user_data );
153
154 static GtkWidget *dialog, /* The debugger dialog box */
155 *continue_button, *break_button, /* Two of its buttons */
156 *register_display, /* The register display */
157 *registers[18], /* Individual registers */
158 *memory_map, /* The memory map display */
159 *memory_map_table, /* The table for the memory map */
160 *map_label[MEMORY_PAGES_IN_64K][4], /* Labels in the memory map */
161 *breakpoints, /* The breakpoint display */
162 *disassembly_box, /* A box to hold the disassembly */
163 *disassembly, /* The actual disassembly widget */
164 *stack, /* The stack display */
165 *events; /* The events display */
166
167 static GtkListStore *breakpoints_model, *disassembly_model, *stack_model,
168 *events_model;
169
170 static GtkAdjustment *disassembly_scrollbar_adjustment;
171
172 /* The top line of the current disassembly */
173 static libspectrum_word disassembly_top;
174
175 /* Have we created the above yet? */
176 static int dialog_created = 0;
177
178 /* Is the debugger window active (as opposed to the debugger itself)? */
179 static int debugger_active;
180
181 /* The UIManager used to create the menu bar */
182 static GtkUIManager *ui_manager_debugger = NULL;
183
184 /* The debugger's menu bar */
185 const gchar debugger_menu[] =
186 "<menubar name='DebuggerMenu'>"
187 " <menu name='View' action='VIEW'>"
188 " <menuitem name='Registers' action='VIEW_REGISTERS'/>"
189 " <menuitem name='Memory Map' action='VIEW_MEMORY_MAP'/>"
190 " <menuitem name='Breakpoints' action='VIEW_BREAKPOINTS'/>"
191 " <menuitem name='Disassembly' action='VIEW_DISASSEMBLY'/>"
192 " <menuitem name='Stack' action='VIEW_STACK'/>"
193 " <menuitem name='Events' action='VIEW_EVENTS'/>"
194 " </menu>"
195 "</menubar>";
196
197 /* The debugger's menu actions */
198 static GtkActionEntry menu_data[] = {
199
200 { "VIEW", NULL, "_View", NULL, NULL, NULL },
201
202 };
203
204 static guint menu_data_count = G_N_ELEMENTS( menu_data );
205
206 static GtkToggleActionEntry menu_toggles[] = {
207
208 { "VIEW_REGISTERS", NULL, "_Registers", NULL, NULL, G_CALLBACK( toggle_display_registers ), TRUE },
209 { "VIEW_MEMORY_MAP", NULL, "_Memory Map", NULL, NULL, G_CALLBACK( toggle_display_memory_map ), TRUE },
210 { "VIEW_BREAKPOINTS", NULL, "_Breakpoints", NULL, NULL, G_CALLBACK( toggle_display_breakpoints ), TRUE },
211 { "VIEW_DISASSEMBLY", NULL, "_Disassembly", NULL, NULL, G_CALLBACK( toggle_display_disassembly ), TRUE },
212 { "VIEW_STACK", NULL, "_Stack", NULL, NULL, G_CALLBACK( toggle_display_stack ), TRUE },
213 { "VIEW_EVENTS", NULL, "_Events", NULL, NULL, G_CALLBACK( toggle_display_events ), TRUE },
214
215 };
216
217 static guint menu_toggles_count = G_N_ELEMENTS( menu_toggles );
218
219 static const char*
format_8_bit(void)220 format_8_bit( void )
221 {
222 return debugger_output_base == 10 ? "%3d" : "0x%02X";
223 }
224
225 static const char*
format_16_bit(void)226 format_16_bit( void )
227 {
228 return debugger_output_base == 10 ? "%5d" : "0x%04X";
229 }
230
231 int
ui_debugger_activate(void)232 ui_debugger_activate( void )
233 {
234 int error;
235
236 fuse_emulation_pause();
237
238 /* Create the dialog box if it doesn't already exist */
239 if( !dialog_created ) if( create_dialog() ) return 1;
240
241 gtk_widget_show_all( dialog );
242 error = hide_hidden_panes(); if( error ) return error;
243
244 gtk_widget_set_sensitive( continue_button, 1 );
245 gtk_widget_set_sensitive( break_button, 0 );
246 if( !debugger_active ) activate_debugger();
247
248 return 0;
249 }
250
251 static int
hide_hidden_panes(void)252 hide_hidden_panes( void )
253 {
254 debugger_pane i;
255 GtkCheckMenuItem *checkitem; GtkWidget *pane;
256
257 for( i = DEBUGGER_PANE_BEGIN; i < DEBUGGER_PANE_END; i++ ) {
258
259 checkitem = get_pane_menu_item( i ); if( !checkitem ) return 1;
260
261 if( gtk_check_menu_item_get_active( checkitem ) ) continue;
262
263 pane = get_pane( i ); if( !pane ) return 1;
264
265 gtk_widget_hide( pane );
266 }
267
268 return 0;
269 }
270
271 static GtkCheckMenuItem*
get_pane_menu_item(debugger_pane pane)272 get_pane_menu_item( debugger_pane pane )
273 {
274 const gchar *path;
275 GtkWidget *menu_item;
276
277 path = NULL;
278
279 switch( pane ) {
280 case DEBUGGER_PANE_REGISTERS: path = "/View/Registers"; break;
281 case DEBUGGER_PANE_MEMORYMAP: path = "/View/Memory Map"; break;
282 case DEBUGGER_PANE_BREAKPOINTS: path = "/View/Breakpoints"; break;
283 case DEBUGGER_PANE_DISASSEMBLY: path = "/View/Disassembly"; break;
284 case DEBUGGER_PANE_STACK: path = "/View/Stack"; break;
285 case DEBUGGER_PANE_EVENTS: path = "/View/Events"; break;
286
287 case DEBUGGER_PANE_END: break;
288 }
289
290 if( !path ) {
291 ui_error( UI_ERROR_ERROR, "unknown debugger pane %u", pane );
292 return NULL;
293 }
294
295 gchar *full_path = g_strdup_printf( "/DebuggerMenu%s", path );
296 menu_item = gtk_ui_manager_get_widget( ui_manager_debugger, full_path );
297 g_free( full_path );
298
299 if( !menu_item ) {
300 ui_error( UI_ERROR_ERROR, "couldn't get menu item '%s'",
301 path );
302 return NULL;
303 }
304
305 return GTK_CHECK_MENU_ITEM( menu_item );
306 }
307
308 static GtkWidget*
get_pane(debugger_pane pane)309 get_pane( debugger_pane pane )
310 {
311 switch( pane ) {
312 case DEBUGGER_PANE_REGISTERS: return register_display;
313 case DEBUGGER_PANE_MEMORYMAP: return memory_map;
314 case DEBUGGER_PANE_BREAKPOINTS: return breakpoints;
315 case DEBUGGER_PANE_DISASSEMBLY: return disassembly_box;
316 case DEBUGGER_PANE_STACK: return stack;
317 case DEBUGGER_PANE_EVENTS: return events;
318
319 case DEBUGGER_PANE_END: break;
320 }
321
322 ui_error( UI_ERROR_ERROR, "unknown debugger pane %u", pane );
323 return NULL;
324 }
325
326 int
ui_debugger_deactivate(int interruptable)327 ui_debugger_deactivate( int interruptable )
328 {
329 if( debugger_active ) deactivate_debugger();
330
331 if( dialog_created ) {
332 gtk_widget_set_sensitive( continue_button, !interruptable );
333 gtk_widget_set_sensitive( break_button, interruptable );
334 }
335
336 return 0;
337 }
338
339 static int
create_dialog(void)340 create_dialog( void )
341 {
342 int error;
343 GtkWidget *hbox, *vbox, *hbox2, *content_area;
344 GtkAccelGroup *accel_group;
345
346 gtkui_font font;
347
348 error = gtkui_get_monospaced_font( &font ); if( error ) return error;
349
350 dialog = gtkstock_dialog_new( "Fuse - Debugger",
351 G_CALLBACK( delete_dialog ) );
352 content_area = gtk_dialog_get_content_area( GTK_DIALOG( dialog ) );
353
354 /* The menu bar */
355 error = create_menu_bar( GTK_BOX( content_area ), &accel_group );
356 if( error ) return error;
357
358 /* Keyboard shortcuts */
359 gtk_window_add_accel_group( GTK_WINDOW( dialog ), accel_group );
360
361 /* Some boxes to contain the things we want to display */
362 hbox = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, 0 );
363 gtk_box_pack_start( GTK_BOX( content_area ), hbox, TRUE, TRUE, 5 );
364
365 vbox = gtk_box_new( GTK_ORIENTATION_VERTICAL, 5 );
366 gtk_box_pack_start( GTK_BOX( hbox ), vbox, TRUE, TRUE, 5 );
367
368 hbox2 = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, 5 );
369 gtk_box_pack_start( GTK_BOX( vbox ), hbox2, TRUE, TRUE, 0 );
370
371 /* The main display areas */
372 error = create_register_display( GTK_BOX( hbox2 ), font );
373 if( error ) return error;
374
375 error = create_memory_map( GTK_BOX( hbox2 ) ); if( error ) return error;
376
377 create_breakpoints( GTK_BOX( vbox ) );
378 create_disassembly( GTK_BOX( hbox ), font );
379 create_stack_display( GTK_BOX( hbox ), font );
380 create_events( GTK_BOX( hbox ) );
381
382 error = create_command_entry( GTK_BOX( content_area ), accel_group );
383 if( error ) return error;
384
385 /* The action buttons */
386
387 error = create_buttons( GTK_DIALOG( dialog ), accel_group );
388 if( error ) return error;
389
390 gtkui_free_font( font );
391
392 dialog_created = 1;
393
394 return 0;
395 }
396
397 static int
create_menu_bar(GtkBox * parent,GtkAccelGroup ** accel_group)398 create_menu_bar( GtkBox *parent, GtkAccelGroup **accel_group )
399 {
400 GError *error = NULL;
401 GtkActionGroup *menu_action_group;
402 GtkWidget *menu_bar;
403 guint ui_menu_id;
404
405 /* FIXME: we should unref this at some point */
406 ui_manager_debugger = gtk_ui_manager_new();
407
408 /* Load actions */
409 menu_action_group = gtk_action_group_new( "DebuggerActionGroup" );
410 gtk_action_group_add_actions( menu_action_group, menu_data, menu_data_count,
411 NULL );
412 gtk_action_group_add_toggle_actions( menu_action_group, menu_toggles,
413 menu_toggles_count, NULL );
414 gtk_ui_manager_insert_action_group( ui_manager_debugger, menu_action_group,
415 0 );
416 g_object_unref( menu_action_group );
417
418 /* Load the menu */
419 ui_menu_id = gtk_ui_manager_add_ui_from_string( ui_manager_debugger,
420 debugger_menu,
421 sizeof( debugger_menu ),
422 &error );
423 if( error ) {
424 g_error_free( error );
425 return 1;
426 }
427 else if( !ui_menu_id ) return 1;
428
429 *accel_group = gtk_ui_manager_get_accel_group( ui_manager_debugger );
430
431 menu_bar = gtk_ui_manager_get_widget( ui_manager_debugger, "/DebuggerMenu" );
432
433 gtk_box_pack_start( parent, menu_bar, FALSE, FALSE, 0 );
434
435 return 0;
436 }
437
438 static void
toggle_display(GtkToggleAction * action,debugger_pane pane_id)439 toggle_display( GtkToggleAction* action, debugger_pane pane_id )
440 {
441 GtkWidget *pane;
442
443 pane = get_pane( pane_id ); if( !pane ) return;
444
445 if( gtk_toggle_action_get_active( action ) ) {
446 gtk_widget_show_all( pane );
447 } else {
448 gtk_widget_hide( pane );
449 }
450 }
451
452 static void
toggle_display_registers(GtkToggleAction * action,gpointer data GCC_UNUSED)453 toggle_display_registers( GtkToggleAction* action, gpointer data GCC_UNUSED )
454 {
455 toggle_display( action, DEBUGGER_PANE_REGISTERS );
456 }
457
458 static void
toggle_display_memory_map(GtkToggleAction * action,gpointer data GCC_UNUSED)459 toggle_display_memory_map( GtkToggleAction* action, gpointer data GCC_UNUSED )
460 {
461 toggle_display( action, DEBUGGER_PANE_MEMORYMAP );
462 }
463
464 static void
toggle_display_breakpoints(GtkToggleAction * action,gpointer data GCC_UNUSED)465 toggle_display_breakpoints( GtkToggleAction* action, gpointer data GCC_UNUSED )
466 {
467 toggle_display( action, DEBUGGER_PANE_BREAKPOINTS );
468 }
469
470 static void
toggle_display_disassembly(GtkToggleAction * action,gpointer data GCC_UNUSED)471 toggle_display_disassembly( GtkToggleAction* action, gpointer data GCC_UNUSED )
472 {
473 toggle_display( action, DEBUGGER_PANE_DISASSEMBLY );
474 }
475
476 static void
toggle_display_stack(GtkToggleAction * action,gpointer data GCC_UNUSED)477 toggle_display_stack( GtkToggleAction* action, gpointer data GCC_UNUSED )
478 {
479 toggle_display( action, DEBUGGER_PANE_STACK );
480 }
481
482 static void
toggle_display_events(GtkToggleAction * action,gpointer data GCC_UNUSED)483 toggle_display_events( GtkToggleAction* action, gpointer data GCC_UNUSED )
484 {
485 toggle_display( action, DEBUGGER_PANE_EVENTS );
486 }
487
488 static int
create_register_display(GtkBox * parent,gtkui_font font)489 create_register_display( GtkBox *parent, gtkui_font font )
490 {
491 size_t i;
492
493 #if GTK_CHECK_VERSION( 3, 0, 0 )
494
495 register_display = gtk_grid_new();
496 gtk_grid_set_row_spacing( GTK_GRID( register_display ), 4 );
497 gtk_container_set_border_width( GTK_CONTAINER( register_display ), 6 );
498
499 #else /* #if GTK_CHECK_VERSION( 3, 0, 0 ) */
500
501 register_display = gtk_table_new( 9, 2, FALSE );
502
503 #endif
504
505 gtk_box_pack_start( parent, register_display, FALSE, FALSE, 0 );
506
507 for( i = 0; i < 18; i++ ) {
508 registers[i] = gtk_label_new( "" );
509 gtkui_set_font( registers[i], font );
510
511 #if GTK_CHECK_VERSION( 3, 0, 0 )
512 gtk_grid_attach( GTK_GRID( register_display ), registers[i],
513 i%2, i/2, 1, 1 );
514 #else
515 gtk_table_attach( GTK_TABLE( register_display ), registers[i],
516 i%2, i%2+1, i/2, i/2+1, 0, 0, 2, 2 );
517 #endif
518
519 }
520
521 return 0;
522 }
523
524 static int
create_memory_map(GtkBox * parent)525 create_memory_map( GtkBox *parent )
526 {
527 GtkWidget *label_address, *label_source, *label_writable, *label_contended;
528
529 label_address = gtk_label_new( "Address" );
530 label_source = gtk_label_new( "Source" );
531 label_writable = gtk_label_new( "W?" );
532 label_contended = gtk_label_new( "C?" );
533
534 memory_map = gtk_frame_new( "Memory Map" );
535 gtk_box_pack_start( parent, memory_map, FALSE, FALSE, 0 );
536
537 #if GTK_CHECK_VERSION( 3, 0, 0 )
538
539 memory_map_table = gtk_grid_new();
540 gtk_grid_set_row_spacing( GTK_GRID( memory_map_table ), 4 );
541 gtk_grid_set_column_spacing( GTK_GRID( memory_map_table ), 6 );
542 gtk_container_set_border_width( GTK_CONTAINER( memory_map_table ), 6 );
543 gtk_container_add( GTK_CONTAINER( memory_map ), memory_map_table );
544
545 gtk_grid_attach( GTK_GRID( memory_map_table ), label_address, 0, 0, 1, 1 );
546 gtk_grid_attach( GTK_GRID( memory_map_table ), label_source, 1, 0, 1, 1 );
547 gtk_grid_attach( GTK_GRID( memory_map_table ), label_writable, 2, 0, 1, 1 );
548 gtk_grid_attach( GTK_GRID( memory_map_table ), label_contended, 3, 0, 1, 1 );
549
550 #else /* #if GTK_CHECK_VERSION( 3, 0, 0 ) */
551
552 memory_map_table = gtk_table_new( 1 + MEMORY_PAGES_IN_64K, 4, FALSE );
553 gtk_container_add( GTK_CONTAINER( memory_map ), memory_map_table );
554
555 gtk_table_attach( GTK_TABLE( memory_map_table ), label_address,
556 0, 1, 0, 1, 0, 0, 2, 2 );
557 gtk_table_attach( GTK_TABLE( memory_map_table ), label_source,
558 1, 2, 0, 1, 0, 0, 2, 2 );
559 gtk_table_attach( GTK_TABLE( memory_map_table ), label_writable,
560 2, 3, 0, 1, 0, 0, 2, 2 );
561 gtk_table_attach( GTK_TABLE( memory_map_table ), label_contended,
562 3, 4, 0, 1, 0, 0, 2, 2 );
563
564 #endif
565
566 return 0;
567 }
568
569 static void
create_breakpoints(GtkBox * parent)570 create_breakpoints( GtkBox *parent )
571 {
572 size_t i;
573
574 gchar *titles[] = { "ID", "Type", "Value", "Ignore", "Life",
575 "Condition" };
576
577 breakpoints_model = gtk_list_store_new( BREAKPOINTS_COLUMN_COUNT, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING );
578
579 breakpoints = gtk_tree_view_new_with_model( GTK_TREE_MODEL( breakpoints_model ) );
580 for( i = 0; i < BREAKPOINTS_COLUMN_COUNT; i++ ) {
581 GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
582 GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes( titles[i], renderer, "text", i, NULL );
583 gtk_tree_view_append_column( GTK_TREE_VIEW( breakpoints ), column );
584 }
585
586 gtk_box_pack_start( parent, breakpoints, TRUE, TRUE, 0 );
587 }
588
589 static void
create_disassembly(GtkBox * parent,gtkui_font font)590 create_disassembly( GtkBox *parent, gtkui_font font )
591 {
592 size_t i;
593
594 GtkWidget *scrollbar;
595 const gchar *titles[] = { "Address", "Instruction" };
596
597 /* A box to hold the disassembly listing and the scrollbar */
598 disassembly_box = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, 0 );
599 gtk_box_pack_start( parent, disassembly_box, TRUE, TRUE, 0 );
600
601 /* The disassembly itself */
602 disassembly_model =
603 gtk_list_store_new( DISASSEMBLY_COLUMN_COUNT, G_TYPE_STRING, G_TYPE_STRING );
604
605 disassembly = gtk_tree_view_new_with_model( GTK_TREE_MODEL( disassembly_model ) );
606 for( i = 0; i < DISASSEMBLY_COLUMN_COUNT; i++ ) {
607 GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
608 GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes( titles[i], renderer, "text", i, NULL );
609 g_object_set( G_OBJECT( renderer ), "font-desc", font, "height", 18, NULL );
610 gtk_tree_view_append_column( GTK_TREE_VIEW( disassembly ), column );
611 }
612
613 gtk_box_pack_start( GTK_BOX( disassembly_box ), disassembly, TRUE, TRUE, 0 );
614
615 /* The disassembly scrollbar */
616 disassembly_scrollbar_adjustment = GTK_ADJUSTMENT(
617 gtk_adjustment_new( 0, 0x0000, 0xffff, 0.5, 20, 20 ) );
618 g_signal_connect( G_OBJECT( disassembly_scrollbar_adjustment ),
619 "value-changed", G_CALLBACK( move_disassembly ),
620 NULL );
621 scrollbar = gtk_scrollbar_new( GTK_ORIENTATION_VERTICAL,
622 disassembly_scrollbar_adjustment );
623 gtk_box_pack_start( GTK_BOX( disassembly_box ), scrollbar, FALSE, FALSE, 0 );
624 /*
625 gtkui_scroll_connect( GTK_CLIST( disassembly ),
626 disassembly_scrollbar_adjustment );
627 */
628 }
629
630 static void
create_stack_display(GtkBox * parent,gtkui_font font)631 create_stack_display( GtkBox *parent, gtkui_font font )
632 {
633 size_t i;
634 const gchar *titles[] = { "Address", "Instruction" };
635
636 stack_model =
637 gtk_list_store_new( STACK_COLUMN_COUNT, G_TYPE_STRING, G_TYPE_STRING,
638 G_TYPE_INT );
639
640 stack = gtk_tree_view_new_with_model( GTK_TREE_MODEL( stack_model ) );
641
642 for( i = 0; i < 2; i++ ) {
643 GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
644 GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes( titles[i], renderer, "text", i, NULL );
645 g_object_set( G_OBJECT( renderer ), "font-desc", font, "height", 18, NULL );
646 gtk_tree_view_append_column( GTK_TREE_VIEW( stack ), column );
647 }
648
649 gtk_box_pack_start( parent, stack, TRUE, TRUE, 5 );
650
651 g_signal_connect( G_OBJECT( stack ), "row-activated", G_CALLBACK( stack_activate ), NULL );
652 }
653
654 static void
stack_activate(GtkTreeView * tree_view,GtkTreePath * path,GtkTreeViewColumn * column GCC_UNUSED,gpointer user_data GCC_UNUSED)655 stack_activate( GtkTreeView *tree_view, GtkTreePath *path,
656 GtkTreeViewColumn *column GCC_UNUSED,
657 gpointer user_data GCC_UNUSED )
658 {
659 GtkTreeIter it;
660 GtkTreeModel *model = gtk_tree_view_get_model( tree_view );
661
662 if( model && gtk_tree_model_get_iter( model, &it, path ) ) {
663 gint address;
664 int error;
665
666 gtk_tree_model_get( model, &it, STACK_COLUMN_VALUE_INT, &address, -1 );
667
668 error = debugger_breakpoint_add_address(
669 DEBUGGER_BREAKPOINT_TYPE_EXECUTE, memory_source_any, 0, address, 0,
670 DEBUGGER_BREAKPOINT_LIFE_ONESHOT, NULL
671 );
672 if( error ) return;
673
674 debugger_run();
675 }
676 }
677
678 static void
create_events(GtkBox * parent)679 create_events( GtkBox *parent )
680 {
681 const gchar *titles[] = { "Time", "Type" };
682 size_t i;
683
684 events_model =
685 gtk_list_store_new( EVENTS_COLUMN_COUNT, G_TYPE_INT, G_TYPE_STRING );
686
687 events = gtk_tree_view_new_with_model( GTK_TREE_MODEL( events_model ) );
688
689 for( i = 0; i < EVENTS_COLUMN_COUNT; i++ ) {
690 GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
691 GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes( titles[i], renderer, "text", i, NULL );
692 gtk_tree_view_append_column( GTK_TREE_VIEW( events ), column );
693 }
694
695 gtk_box_pack_start( parent, events, TRUE, TRUE, 5 );
696
697 g_signal_connect( G_OBJECT( events ), "row-activated", G_CALLBACK( events_activate ), NULL );
698 }
699
700 static void
events_activate(GtkTreeView * tree_view,GtkTreePath * path,GtkTreeViewColumn * column GCC_UNUSED,gpointer user_data GCC_UNUSED)701 events_activate( GtkTreeView *tree_view, GtkTreePath *path,
702 GtkTreeViewColumn *column GCC_UNUSED,
703 gpointer user_data GCC_UNUSED )
704 {
705 GtkTreeIter it;
706 GtkTreeModel *model = gtk_tree_view_get_model( tree_view );
707
708 if( model && gtk_tree_model_get_iter( model, &it, path ) ) {
709 libspectrum_dword event_tstates;
710 int error;
711
712 gtk_tree_model_get( model, &it, EVENTS_COLUMN_TIME, &event_tstates, -1 );
713
714 error = debugger_breakpoint_add_time(
715 DEBUGGER_BREAKPOINT_TYPE_TIME, event_tstates, 0,
716 DEBUGGER_BREAKPOINT_LIFE_ONESHOT, NULL
717 );
718 if( error ) return;
719
720 debugger_run();
721 }
722 }
723
724 static int
create_command_entry(GtkBox * parent,GtkAccelGroup * accel_group)725 create_command_entry( GtkBox *parent, GtkAccelGroup *accel_group )
726 {
727 GtkWidget *hbox, *entry, *eval_button;
728
729 /* An hbox to hold the command entry widget and the 'evaluate' button */
730 hbox = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, 5 );
731 gtk_box_pack_start( parent, hbox, FALSE, FALSE, 0 );
732
733 /* The command entry widget */
734 entry = gtk_entry_new();
735 g_signal_connect( G_OBJECT( entry ), "activate",
736 G_CALLBACK( evaluate_command ), NULL );
737 gtk_box_pack_start( GTK_BOX( hbox ), entry, TRUE, TRUE, 0 );
738
739 /* The 'command evaluate' button */
740 eval_button = gtk_button_new_with_label( "Evaluate" );
741 g_signal_connect_swapped( G_OBJECT( eval_button ), "clicked",
742 G_CALLBACK( evaluate_command ),
743 G_OBJECT( entry ) );
744 gtk_box_pack_start( GTK_BOX( hbox ), eval_button, FALSE, FALSE, 0 );
745
746 /* Return is equivalent to clicking on 'evaluate' */
747 gtk_widget_add_accelerator( eval_button, "clicked", accel_group,
748 GDK_KEY_Return, 0, 0 );
749
750 return 0;
751 }
752
753 static int
create_buttons(GtkDialog * parent,GtkAccelGroup * accel_group)754 create_buttons( GtkDialog *parent, GtkAccelGroup *accel_group )
755 {
756 static const gtkstock_button
757 step = { "Single step", G_CALLBACK( gtkui_debugger_done_step ), NULL, NULL, 0, 0, 0, 0 },
758 cont = { "Continue", G_CALLBACK( gtkui_debugger_done_continue ), NULL, NULL, 0, 0, 0, 0 },
759 brk = { "Break", G_CALLBACK( gtkui_debugger_break ), NULL, NULL, 0, 0, 0, 0 };
760
761 /* Create the action buttons for the dialog box */
762 gtkstock_create_button( GTK_WIDGET( parent ), accel_group, &step );
763 continue_button = gtkstock_create_button( GTK_WIDGET( parent ), accel_group,
764 &cont );
765 break_button = gtkstock_create_button( GTK_WIDGET( parent ), accel_group,
766 &brk );
767 gtkstock_create_close( GTK_WIDGET( parent ), accel_group,
768 G_CALLBACK( gtkui_debugger_done_close ), TRUE );
769
770 return 0;
771 }
772
773 static int
activate_debugger(void)774 activate_debugger( void )
775 {
776 debugger_active = 1;
777
778 ui_debugger_disassemble( PC );
779 ui_debugger_update();
780
781 gtk_main();
782 return 0;
783 }
784
785 /* Update the debugger's display */
786 int
ui_debugger_update(void)787 ui_debugger_update( void )
788 {
789 size_t i;
790 char buffer[1024], format_string[1024];
791 gchar buffer1[80], buffer2[80];
792 libspectrum_word address;
793 int capabilities; size_t length;
794
795 const char *register_name[] = { "PC", "SP",
796 "AF", "AF'",
797 "BC", "BC'",
798 "DE", "DE'",
799 "HL", "HL'",
800 "IX", "IY",
801 };
802
803 libspectrum_word *value_ptr[] = { &PC, &SP, &AF, &AF_,
804 &BC, &BC_, &DE, &DE_,
805 &HL, &HL_, &IX, &IY,
806 };
807
808 if( !dialog_created ) return 0;
809
810 for( i = 0; i < 12; i++ ) {
811 snprintf( buffer, 5, "%3s ", register_name[i] );
812 snprintf( &buffer[4], 76, format_16_bit(), *value_ptr[i] );
813 gtk_label_set_text( GTK_LABEL( registers[i] ), buffer );
814 }
815
816 strcpy( buffer, " I " ); snprintf( &buffer[6], 76, format_8_bit(), I );
817 gtk_label_set_text( GTK_LABEL( registers[12] ), buffer );
818 strcpy( buffer, " R " );
819 snprintf( &buffer[6], 80, format_8_bit(), ( R & 0x7f ) | ( R7 & 0x80 ) );
820 gtk_label_set_text( GTK_LABEL( registers[13] ), buffer );
821
822 snprintf( buffer, 80, "T-states %5d", tstates );
823 gtk_label_set_text( GTK_LABEL( registers[14] ), buffer );
824 snprintf( buffer, 80, " IM %d\nIFF1 %d\nIFF2 %d", IM, IFF1, IFF2 );
825 gtk_label_set_text( GTK_LABEL( registers[15] ), buffer );
826
827 strcpy( buffer, "SZ5H3PNC\n" );
828 for( i = 0; i < 8; i++ ) buffer[i+9] = ( F & ( 0x80 >> i ) ) ? '1' : '0';
829 buffer[17] = '\0';
830 gtk_label_set_text( GTK_LABEL( registers[16] ), buffer );
831
832 capabilities = libspectrum_machine_capabilities( machine_current->machine );
833
834 sprintf( format_string, " ULA %s", format_8_bit() );
835 snprintf( buffer, 1024, format_string, ula_last_byte() );
836
837 if( capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_AY ) {
838 sprintf( format_string, "\n AY %s", format_8_bit() );
839 length = strlen( buffer );
840 snprintf( &buffer[length], 1024-length, format_string,
841 machine_current->ay.current_register );
842 }
843
844 if( capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_128_MEMORY ) {
845 sprintf( format_string, "\n128Mem %s", format_8_bit() );
846 length = strlen( buffer );
847 snprintf( &buffer[length], 1024-length, format_string,
848 machine_current->ram.last_byte );
849 }
850
851 if( capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_PLUS3_MEMORY ) {
852 sprintf( format_string, "\n+3 Mem %s", format_8_bit() );
853 length = strlen( buffer );
854 snprintf( &buffer[length], 1024-length, format_string,
855 machine_current->ram.last_byte2 );
856 }
857
858 if( capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_TIMEX_VIDEO ||
859 capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_TIMEX_MEMORY ||
860 capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_SE_MEMORY ) {
861 sprintf( format_string, "\nTmxDec %s", format_8_bit() );
862 length = strlen( buffer );
863 snprintf( &buffer[length], 1024-length, format_string,
864 scld_last_dec.byte );
865 }
866
867 if( capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_TIMEX_MEMORY ||
868 capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_SE_MEMORY ) {
869 sprintf( format_string, "\nTmxHsr %s", format_8_bit() );
870 length = strlen( buffer );
871 snprintf( &buffer[length], 1024-length, format_string, scld_last_hsr );
872 }
873
874 if( settings_current.zxcf_active ) {
875 sprintf( format_string, "\n ZXCF %s", format_8_bit() );
876 length = strlen( buffer );
877 snprintf( &buffer[length], 1024-length, format_string,
878 zxcf_last_memctl() );
879 }
880
881 gtk_label_set_text( GTK_LABEL( registers[17] ), buffer );
882
883 update_memory_map();
884 update_breakpoints();
885 update_disassembly();
886
887 /* And the stack display */
888 gtk_list_store_clear( stack_model );
889
890 for( i = 0, address = SP + 38; i < 20; i++, address -= 2 ) {
891
892 GtkTreeIter it;
893
894 libspectrum_word contents = readbyte_internal( address ) +
895 0x100 * readbyte_internal( address + 1 );
896
897 snprintf( buffer1, sizeof( buffer1 ), format_16_bit(), address );
898 snprintf( buffer2, sizeof( buffer2 ), format_16_bit(), contents );
899
900 gtk_list_store_append( stack_model, &it );
901 gtk_list_store_set( stack_model, &it, STACK_COLUMN_ADDRESS, buffer1, STACK_COLUMN_VALUE_TEXT, buffer2, STACK_COLUMN_VALUE_INT, (gint)contents, -1 );
902 }
903
904 /* And the events display */
905 update_events();
906
907 return 0;
908 }
909
910 static void
update_memory_map(void)911 update_memory_map( void )
912 {
913 int source, page_num, writable, contended;
914 libspectrum_word offset;
915 size_t i, j, block, row;
916
917 for( i = 0; i < MEMORY_PAGES_IN_64K; i++ ) {
918 if( map_label[i][0] ) {
919 for( j = 0; j < 4; j++ ) {
920 gtk_container_remove( GTK_CONTAINER( memory_map_table ), map_label[i][j] );
921 map_label[i][j] = NULL;
922 }
923 }
924 }
925
926 source = page_num = writable = contended = -1;
927 offset = 0;
928 row = 0;
929
930 for( block = 0; block < MEMORY_PAGES_IN_64K; block++ ) {
931 memory_page *page = &memory_map_read[block];
932
933 if( page->source != source ||
934 page->page_num != page_num ||
935 page->offset != offset ||
936 page->writable != writable ||
937 page->contended != contended ) {
938
939 char buffer[40];
940 GtkWidget **row_labels = map_label[row];
941
942 snprintf( buffer, 40, format_16_bit(),
943 (unsigned)block * MEMORY_PAGE_SIZE );
944 row_labels[0] = gtk_label_new( buffer );
945
946 snprintf( buffer, 40, "%s %d",
947 memory_source_description( page->source ), page->page_num );
948 row_labels[1] = gtk_label_new( buffer );
949
950 row_labels[2] = gtk_label_new( page->writable ? "Y" : "N" );
951 row_labels[3] = gtk_label_new( page->contended ? "Y" : "N" );
952
953 for( i = 0; i < 4; i++ ) {
954
955 #if GTK_CHECK_VERSION( 3, 0, 0 )
956 gtk_grid_attach( GTK_GRID( memory_map_table ), row_labels[i],
957 i, row + 1, 1, 1 );
958 #else
959 gtk_table_attach( GTK_TABLE( memory_map_table ), row_labels[i],
960 i, i + 1, row + 1, row + 2, 0, 0, 2, 2 );
961 #endif
962
963 }
964
965 row++;
966
967 source = page->source;
968 page_num = page->page_num;
969 writable = page->writable;
970 contended = page->contended;
971 offset = page->offset;
972 }
973
974 /* We expect the next page to have an increased offset */
975 offset += MEMORY_PAGE_SIZE;
976 }
977
978 gtk_widget_show_all( GTK_WIDGET( memory_map_table ) );
979 }
980
981 static void
update_breakpoints(void)982 update_breakpoints( void )
983 {
984 GSList *ptr;
985
986 gtk_list_store_clear( breakpoints_model );
987
988 for( ptr = debugger_breakpoints; ptr; ptr = ptr->next ) {
989
990 debugger_breakpoint *bp = ptr->data;
991 GtkTreeIter it;
992 gchar buffer[40], format_string[40];
993
994 switch( bp->type ) {
995
996 case DEBUGGER_BREAKPOINT_TYPE_EXECUTE:
997 case DEBUGGER_BREAKPOINT_TYPE_READ:
998 case DEBUGGER_BREAKPOINT_TYPE_WRITE:
999 if( bp->value.address.source == memory_source_any ) {
1000 snprintf( buffer, sizeof( buffer ), format_16_bit(),
1001 bp->value.address.offset );
1002 } else {
1003 snprintf( format_string, sizeof( format_string ), "%%s:%s:%s",
1004 format_16_bit(), format_16_bit() );
1005 snprintf( buffer, sizeof( buffer ), format_string,
1006 memory_source_description( bp->value.address.source ),
1007 bp->value.address.page, bp->value.address.offset );
1008 }
1009 break;
1010
1011 case DEBUGGER_BREAKPOINT_TYPE_PORT_READ:
1012 case DEBUGGER_BREAKPOINT_TYPE_PORT_WRITE:
1013 snprintf( format_string, sizeof( format_string ), "%s:%s",
1014 format_16_bit(), format_16_bit() );
1015 snprintf( buffer, sizeof( buffer ), format_string, bp->value.port.mask,
1016 bp->value.port.port );
1017 break;
1018
1019 case DEBUGGER_BREAKPOINT_TYPE_TIME:
1020 snprintf( buffer, sizeof( buffer ), "%5d", bp->value.time.tstates );
1021 break;
1022
1023 case DEBUGGER_BREAKPOINT_TYPE_EVENT:
1024 snprintf( buffer, sizeof( buffer ), "%s:%s", bp->value.event.type,
1025 bp->value.event.detail );
1026 break;
1027
1028 }
1029
1030 gtk_list_store_append( breakpoints_model, &it );
1031 gtk_list_store_set(
1032 breakpoints_model, &it,
1033 BREAKPOINTS_COLUMN_ID, bp->id,
1034 BREAKPOINTS_COLUMN_TYPE, debugger_breakpoint_type_text[ bp->type ],
1035 BREAKPOINTS_COLUMN_VALUE, buffer,
1036 BREAKPOINTS_COLUMN_IGNORE, bp->ignore,
1037 BREAKPOINTS_COLUMN_LIFE, debugger_breakpoint_life_text[ bp->life ],
1038 -1
1039 );
1040
1041 if( bp->condition ) {
1042 gchar buffer2[80];
1043 debugger_expression_deparse( buffer2, sizeof( buffer2 ), bp->condition );
1044 gtk_list_store_set( breakpoints_model, &it, BREAKPOINTS_COLUMN_CONDITION, buffer2, -1 );
1045 }
1046
1047 }
1048 }
1049
1050 static void
update_disassembly(void)1051 update_disassembly( void )
1052 {
1053 size_t i; libspectrum_word address;
1054 GtkTreeIter it;
1055
1056 gtk_list_store_clear( disassembly_model );
1057
1058 for( i = 0, address = disassembly_top; i < 20; i++ ) {
1059 size_t l, length;
1060 char buffer1[40], buffer2[40];
1061
1062 snprintf( buffer1, sizeof( buffer1 ), format_16_bit(), address );
1063 debugger_disassemble( buffer2, sizeof( buffer2 ), &length, address );
1064
1065 /* pad to 16 characters (long instruction) to avoid varying width */
1066 l = strlen( buffer2 );
1067 while( l < 16 ) buffer2[l++] = ' ';
1068 buffer2[l] = 0;
1069
1070 gtk_list_store_append( disassembly_model, &it );
1071 gtk_list_store_set( disassembly_model, &it, DISASSEMBLY_COLUMN_ADDRESS, buffer1, DISASSEMBLY_COLUMN_INSTRUCTION, buffer2, -1 );
1072
1073 address += length;
1074 }
1075 }
1076
1077 static void
update_events(void)1078 update_events( void )
1079 {
1080 gtk_list_store_clear( events_model );
1081 event_foreach( add_event, NULL );
1082 }
1083
1084 static void
add_event(gpointer data,gpointer user_data GCC_UNUSED)1085 add_event( gpointer data, gpointer user_data GCC_UNUSED )
1086 {
1087 event_t *ptr = data;
1088 GtkTreeIter it;
1089
1090 if( ptr->type != event_type_null ) {
1091 gtk_list_store_append( events_model, &it );
1092 gtk_list_store_set( events_model, &it, EVENTS_COLUMN_TIME, ptr->tstates, EVENTS_COLUMN_TYPE, event_name( ptr->type ), -1 );
1093 }
1094 }
1095
1096 static int
deactivate_debugger(void)1097 deactivate_debugger( void )
1098 {
1099 gtk_main_quit();
1100 debugger_active = 0;
1101 fuse_emulation_unpause();
1102 return 0;
1103 }
1104
1105 /* Set the disassembly to start at 'address' */
1106 int
ui_debugger_disassemble(libspectrum_word address)1107 ui_debugger_disassemble( libspectrum_word address )
1108 {
1109 disassembly_top = address;
1110 gtk_adjustment_set_value( disassembly_scrollbar_adjustment, address );
1111 return 0;
1112 }
1113
1114 /* Called when the disassembly scrollbar is moved */
1115 static void
move_disassembly(GtkAdjustment * adjustment,gpointer user_data GCC_UNUSED)1116 move_disassembly( GtkAdjustment *adjustment, gpointer user_data GCC_UNUSED )
1117 {
1118 gdouble value;
1119 size_t length;
1120
1121 value = gtk_adjustment_get_value( adjustment );
1122
1123 /* disassembly_top < value < disassembly_top + 1 => 'down' button pressed
1124 Move the disassembly on by one instruction */
1125 if( value > disassembly_top && value - disassembly_top < 1 ) {
1126
1127 debugger_disassemble( NULL, 0, &length, disassembly_top );
1128 ui_debugger_disassemble( disassembly_top + length );
1129
1130 /* disassembly_top - 1 < value < disassembly_top => 'up' button pressed
1131
1132 The desired state after this is for the current top instruction
1133 to be the second instruction shown in the disassembly.
1134
1135 Unfortunately, it's not trivial to determine where disassembly
1136 should now start, as we have variable length instructions of
1137 unbounded length (multiple DD and FD prefixes on one instruction
1138 are possible).
1139
1140 In general, we want the _longest_ opcode which produces the
1141 current top in second place (consider something like LD A,nn:
1142 we're not interested if nn happens to represent a one-byte
1143 opcode), so look back a reasonable length (say, 8 bytes) and see
1144 what we find.
1145
1146 In some cases (eg if we're currently pointing to a data byte of a
1147 multi-byte opcode), it will be impossible to get the current top
1148 second. In this case, just move back a byte.
1149
1150 */
1151 } else if( value < disassembly_top && disassembly_top - value < 1 ) {
1152
1153 size_t i, longest = 1;
1154
1155 for( i = 1; i <= 8; i++ ) {
1156
1157 debugger_disassemble( NULL, 0, &length, disassembly_top - i );
1158 if( length == i ) longest = i;
1159
1160 }
1161
1162 ui_debugger_disassemble( disassembly_top - longest );
1163
1164 /* Anything else, just set disassembly_top to that value */
1165 } else {
1166
1167 ui_debugger_disassemble( value );
1168
1169 }
1170
1171 /* And update the disassembly if the debugger is active */
1172 if( debugger_active ) update_disassembly();
1173 }
1174
1175 /* Evaluate the command currently in the entry box */
1176 static void
evaluate_command(GtkWidget * widget,gpointer user_data GCC_UNUSED)1177 evaluate_command( GtkWidget *widget, gpointer user_data GCC_UNUSED )
1178 {
1179 debugger_command_evaluate( gtk_entry_get_text( GTK_ENTRY( widget ) ) );
1180 }
1181
1182 static void
gtkui_debugger_done_step(GtkWidget * widget GCC_UNUSED,gpointer user_data GCC_UNUSED)1183 gtkui_debugger_done_step( GtkWidget *widget GCC_UNUSED,
1184 gpointer user_data GCC_UNUSED )
1185 {
1186 debugger_step();
1187 }
1188
1189 static void
gtkui_debugger_done_continue(GtkWidget * widget GCC_UNUSED,gpointer user_data GCC_UNUSED)1190 gtkui_debugger_done_continue( GtkWidget *widget GCC_UNUSED,
1191 gpointer user_data GCC_UNUSED )
1192 {
1193 debugger_run();
1194 }
1195
1196 static void
gtkui_debugger_break(GtkWidget * widget GCC_UNUSED,gpointer user_data GCC_UNUSED)1197 gtkui_debugger_break( GtkWidget *widget GCC_UNUSED,
1198 gpointer user_data GCC_UNUSED )
1199 {
1200 debugger_mode = DEBUGGER_MODE_HALTED;
1201 gtk_widget_set_sensitive( continue_button, 1 );
1202 gtk_widget_set_sensitive( break_button, 0 );
1203 }
1204
1205 static gboolean
delete_dialog(GtkWidget * widget,GdkEvent * event GCC_UNUSED,gpointer user_data)1206 delete_dialog( GtkWidget *widget, GdkEvent *event GCC_UNUSED,
1207 gpointer user_data )
1208 {
1209 gtkui_debugger_done_close( widget, user_data );
1210 return TRUE;
1211 }
1212
1213 static void
gtkui_debugger_done_close(GtkWidget * widget,gpointer user_data GCC_UNUSED)1214 gtkui_debugger_done_close( GtkWidget *widget, gpointer user_data GCC_UNUSED )
1215 {
1216 gtk_widget_hide( widget );
1217 gtkui_debugger_done_continue( NULL, NULL );
1218 }
1219