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