Search
lxdream.org :: lxdream/src/gtkui/debug_win.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gtkui/debug_win.c
changeset 669:ab344e42bca9
prev586:2a3ba82cf243
next736:a02d1475ccfd
author nkeynes
date Wed Jun 25 10:40:45 2008 +0000 (15 years ago)
permissions -rw-r--r--
last change Commit OSX CD-ROM driver work-in-progress
view annotate diff log raw
     1 /**
     2  * $Id$
     3  * This file is responsible for the main debugger gui frame.
     4  *
     5  * Copyright (c) 2005 Nathan Keynes.
     6  *
     7  * This program is free software; you can redistribute it and/or modify
     8  * it under the terms of the GNU General Public License as published by
     9  * the Free Software Foundation; either version 2 of the License, or
    10  * (at your option) any later version.
    11  *
    12  * This program is distributed in the hope that it will be useful,
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15  * GNU General Public License for more details.
    16  */
    17 #include <stdlib.h>
    18 #include <stdarg.h>
    19 #include <stdio.h>
    20 #include <string.h>
    21 #include <math.h>
    22 #include <glib/gi18n.h>
    23 #include <gdk/gdkkeysyms.h>
    24 #include "mem.h"
    25 #include "cpu.h"
    26 #include "dreamcast.h"
    27 #include "gtkui/gtkui.h"
    28 #include "sh4/sh4dasm.h"
    29 #include "aica/armdasm.h"
    31 GdkColor *msg_colors[] = { &gui_colour_error, &gui_colour_error, &gui_colour_warn, 
    32 			   &gui_colour_normal,&gui_colour_debug, &gui_colour_trace };
    34 const cpu_desc_t cpu_list[4] = { &sh4_cpu_desc, &arm_cpu_desc, &armt_cpu_desc, NULL };
    36 void init_register_list( debug_window_t data );
    37 uint32_t row_to_address( debug_window_t data, int row );
    38 int address_to_row( debug_window_t data, uint32_t address );
    39 void set_disassembly_pc( debug_window_t data, unsigned int pc, gboolean select );
    40 void set_disassembly_region( debug_window_t data, unsigned int page );
    41 void set_disassembly_cpu( debug_window_t data, const gchar *cpu );
    43 void on_mode_field_changed ( GtkEditable *editable, gpointer user_data);
    44 gboolean on_page_field_key_press_event( GtkWidget * widget, GdkEventKey *event,
    45                                         gpointer user_data);
    46 void on_jump_pc_btn_clicked( GtkButton *button, gpointer user_data);
    47 void on_disasm_list_select_row (GtkCList *clist, gint row, gint column,
    48 				GdkEvent *event, gpointer user_data);
    49 void on_disasm_list_unselect_row (GtkCList *clist, gint row, gint column,
    50 				  GdkEvent *event, gpointer user_data);
    51 gboolean on_debug_delete_event(GtkWidget *widget, GdkEvent event, gpointer user_data);
    53 struct debug_window_info {
    54     int disasm_from;
    55     int disasm_to;
    56     int disasm_pc;
    57     const struct cpu_desc_struct *cpu;
    58     const cpu_desc_t *cpu_list;
    59     GtkCList *regs_list;
    60     GtkCList *disasm_list;
    61     GtkEntry *page_field;
    62     GtkWidget *window;
    63     GtkWidget *statusbar;
    64     char saved_regs[0];
    65 };
    67 debug_window_t debug_window_new( const gchar *title, GtkWidget *menubar, 
    68 				 GtkWidget *toolbar, GtkAccelGroup *accel_group )
    69 {
    70     debug_window_t data = g_malloc0( sizeof(struct debug_window_info) + cpu_list[0]->regs_size );
    71         GtkWidget *vbox;
    73     data->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    74     gtk_window_set_default_size (GTK_WINDOW (data->window), 700, 480);
    75     gtk_window_set_title( GTK_WINDOW(data->window), title );
    76     gtk_window_add_accel_group (GTK_WINDOW (data->window), accel_group);
    78     gtk_toolbar_set_style( GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS );
    80     data->statusbar = gtk_statusbar_new();
    82     GtkWidget *hpaned = gtk_hpaned_new ();
    83     gtk_paned_set_position (GTK_PANED (hpaned), 500);
    85     GtkWidget *disasm_box = gtk_vbox_new(FALSE,0);
    86     gtk_paned_pack1 (GTK_PANED (hpaned), disasm_box, TRUE, TRUE);
    88     GtkWidget *hbox1 = gtk_hbox_new (FALSE, 0);
    89     gtk_box_pack_start (GTK_BOX (disasm_box), hbox1, FALSE, FALSE, 3);
    90     gtk_box_pack_start (GTK_BOX (hbox1), gtk_label_new (_("Page")), FALSE, FALSE, 4);
    92     data->page_field = GTK_ENTRY(gtk_entry_new ());
    93     gtk_box_pack_start (GTK_BOX (hbox1), GTK_WIDGET(data->page_field), FALSE, TRUE, 0);
    95     GtkWidget *jump_pc_btn = gtk_button_new_with_mnemonic (_(" Jump to PC "));
    96     gtk_box_pack_start (GTK_BOX (hbox1), jump_pc_btn, FALSE, FALSE, 4);
    98     gtk_box_pack_start (GTK_BOX (hbox1), gtk_label_new(_("Mode")), FALSE, FALSE, 5);
   100     GtkWidget *mode_box = gtk_combo_new ();
   101     gtk_box_pack_start (GTK_BOX (hbox1), mode_box, FALSE, FALSE, 0);
   102     GList *mode_box_items = NULL;
   103     mode_box_items = g_list_append (mode_box_items, (gpointer) _("SH4"));
   104     mode_box_items = g_list_append (mode_box_items, (gpointer) _("ARM7"));
   105     mode_box_items = g_list_append (mode_box_items, (gpointer) _("ARM7T"));
   106     gtk_combo_set_popdown_strings (GTK_COMBO (mode_box), mode_box_items);
   107     g_list_free (mode_box_items);
   109     GtkWidget *mode_field = GTK_COMBO (mode_box)->entry;
   110     gtk_editable_set_editable (GTK_EDITABLE (mode_field), FALSE);
   112     GtkWidget *disasm_scroll = gtk_scrolled_window_new (NULL, NULL);
   113     gtk_box_pack_start (GTK_BOX (disasm_box), disasm_scroll, TRUE, TRUE, 0);
   114     gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (disasm_scroll), GTK_SHADOW_IN);
   115     data->disasm_list = GTK_CLIST(gtk_clist_new (4));
   116     gtk_clist_set_column_width (GTK_CLIST (data->disasm_list), 0, 80);
   117     gtk_clist_set_column_width (GTK_CLIST (data->disasm_list), 2, 80);
   118     gtk_clist_set_column_width (GTK_CLIST (data->disasm_list), 3, 80);
   119     gtk_clist_set_column_width( data->disasm_list, 1, 16 );
   120     gtk_clist_column_titles_hide (GTK_CLIST (data->disasm_list));
   121     gtk_container_add (GTK_CONTAINER (disasm_scroll), GTK_WIDGET(data->disasm_list));
   123     GtkWidget *reg_scroll = gtk_scrolled_window_new (NULL, NULL);
   124     gtk_paned_pack2 (GTK_PANED (hpaned), reg_scroll, FALSE, TRUE);
   125     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (reg_scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
   126     gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (reg_scroll), GTK_SHADOW_IN);
   128     data->regs_list = GTK_CLIST(gtk_clist_new (2));
   129     gtk_container_add (GTK_CONTAINER (reg_scroll), GTK_WIDGET(data->regs_list));
   130     gtk_clist_set_column_width (GTK_CLIST (data->regs_list), 0, 80);
   131     gtk_clist_set_column_width (GTK_CLIST (data->regs_list), 1, 80);
   132     gtk_clist_column_titles_hide (GTK_CLIST (data->regs_list));
   133     gtk_widget_modify_font( GTK_WIDGET(data->regs_list), gui_fixed_font );
   135     vbox = gtk_vbox_new(FALSE, 0);
   136     gtk_container_add( GTK_CONTAINER(data->window), vbox );
   137     gtk_box_pack_start( GTK_BOX(vbox), menubar, FALSE, FALSE, 0 );
   138     gtk_box_pack_start( GTK_BOX(vbox), toolbar, FALSE, FALSE, 0 );
   139     gtk_box_pack_start( GTK_BOX(vbox), hpaned, TRUE, TRUE, 0 );
   140     gtk_box_pack_start( GTK_BOX(vbox), data->statusbar, FALSE, FALSE, 0 );
   142     g_signal_connect ((gpointer) data->page_field, "key_press_event",
   143 		      G_CALLBACK (on_page_field_key_press_event),
   144 		      data);
   145     g_signal_connect ((gpointer) jump_pc_btn, "clicked",
   146 		      G_CALLBACK (on_jump_pc_btn_clicked),
   147 		      data);
   148     g_signal_connect ((gpointer) mode_field, "changed",
   149 		      G_CALLBACK (on_mode_field_changed),
   150 		      data);
   151     g_signal_connect ((gpointer) data->disasm_list, "select_row",
   152 		      G_CALLBACK (on_disasm_list_select_row),
   153 		      data);
   154     g_signal_connect ((gpointer) data->disasm_list, "unselect_row",
   155 		      G_CALLBACK (on_disasm_list_unselect_row),
   156 		      data);
   157     g_signal_connect ((gpointer) data->window, "delete_event",
   158 		      G_CALLBACK (on_debug_delete_event),
   159 		      data);
   161     data->disasm_from = -1;
   162     data->disasm_to = -1;
   163     data->disasm_pc = -1;
   164     data->cpu = cpu_list[0];
   165     data->cpu_list = cpu_list;
   167     init_register_list( data );
   168     gtk_object_set_data( GTK_OBJECT(data->window), "debug_data", data );
   169     set_disassembly_pc( data, *data->cpu->pc, FALSE );
   170     debug_window_set_running( data, FALSE );
   172     gtk_widget_show_all( data->window );
   173     return data;
   174 }
   176 void debug_window_show( debug_window_t data, gboolean show )
   177 {
   178     if( show ) {
   179 	gtk_widget_show( data->window );
   180     } else {
   181 	gtk_widget_hide( data->window );
   182     }
   183 }
   185 int debug_window_get_selected_row( debug_window_t data )
   186 {
   187     if( data->disasm_list->selection == NULL ) {
   188 	return -1;
   189     } else {
   190 	return GPOINTER_TO_INT(data->disasm_list->selection->data);
   191     }
   192 }
   194 void init_register_list( debug_window_t data ) 
   195 {
   196     int i;
   197     char buf[20];
   198     char *arr[2];
   200     gtk_clist_clear( data->regs_list );
   201     arr[1] = buf;
   202     for( i=0; data->cpu->regs_info[i].name != NULL; i++ ) {
   203         arr[0] = data->cpu->regs_info[i].name;
   204         if( data->cpu->regs_info->type == REG_INT )
   205             sprintf( buf, "%08X", *((uint32_t *)data->cpu->regs_info[i].value) );
   206         else
   207             sprintf( buf, "%f", *((float *)data->cpu->regs_info[i].value) );
   208         gtk_clist_append( data->regs_list, arr );
   209     }
   210 }
   212 /*
   213  * Check for changed registers and update the display
   214  */
   215 void debug_window_update( debug_window_t data )
   216 {
   217     int i;
   218     for( i=0; data->cpu->regs_info[i].name != NULL; i++ ) {
   219         if( data->cpu->regs_info[i].type == REG_INT ) {
   220             /* Yes this _is_ probably fairly evil */
   221             if( *((uint32_t *)data->cpu->regs_info[i].value) !=
   222                 *((uint32_t *)((char *)data->saved_regs + ((char *)data->cpu->regs_info[i].value - (char *)data->cpu->regs))) ) {
   223                 char buf[20];
   224                 sprintf( buf, "%08X", *((uint32_t *)data->cpu->regs_info[i].value) );
   225                 gtk_clist_set_text( data->regs_list, i, 1, buf );
   226                 gtk_clist_set_foreground( data->regs_list, i, &gui_colour_changed );
   227             } else {
   228                 gtk_clist_set_foreground( data->regs_list, i, &gui_colour_normal );
   229             }
   230         } else {
   231             if( *((float *)data->cpu->regs_info[i].value) !=
   232                 *((float *)((char *)data->saved_regs + ((char *)data->cpu->regs_info[i].value - (char *)data->cpu->regs))) ) {
   233                 char buf[20];
   234                 sprintf( buf, "%f", *((float *)data->cpu->regs_info[i].value) );
   235                 gtk_clist_set_text( data->regs_list, i, 1, buf );
   236                 gtk_clist_set_foreground( data->regs_list, i, &gui_colour_changed );
   237             } else {
   238                 gtk_clist_set_foreground( data->regs_list, i, &gui_colour_normal );
   239             }
   240         }
   241     }
   243     set_disassembly_pc( data, *data->cpu->pc, TRUE );
   244     memcpy( data->saved_regs, data->cpu->regs, data->cpu->regs_size );
   245 }
   247 void set_disassembly_region( debug_window_t data, unsigned int page )
   248 {
   249     uint32_t i, posn, next;
   250     char buf[80];
   251     char addr[10];
   252     char opcode[16] = "";
   253     char *arr[4] = { addr, " ", opcode, buf };
   254     unsigned int from = page & 0xFFFFF000;
   255     unsigned int to = from + 4096;
   257     gtk_clist_clear(data->disasm_list);
   259     sprintf( addr, "%08X", from );
   260     gtk_entry_set_text( data->page_field, addr );
   262     if( !data->cpu->is_valid_page_func( from ) ) {
   263         arr[3] = _("This page is currently unmapped");
   264         gtk_clist_append( data->disasm_list, arr );
   265         gtk_clist_set_foreground( data->disasm_list, 0, &gui_colour_error );
   266     } else {
   267         for( i=from; i<to; i = next ) {
   268 	    next = data->cpu->disasm_func( i, buf, sizeof(buf), opcode );
   269             sprintf( addr, "%08X", i );
   270             posn = gtk_clist_append( data->disasm_list, arr );
   271             if( buf[0] == '?' )
   272                 gtk_clist_set_foreground( data->disasm_list, posn, &gui_colour_warn );
   273 	    if( data->cpu->get_breakpoint != NULL ) {
   274 		int type = data->cpu->get_breakpoint( i );
   275 		switch(type) {
   276 		case BREAK_ONESHOT:
   277 		    gtk_clist_set_background( data->disasm_list, posn, &gui_colour_temp_break );
   278 		    break;
   279 		case BREAK_KEEP:
   280 		    gtk_clist_set_background( data->disasm_list, posn, &gui_colour_break );
   281 		    break;
   282 		}
   283 	    }
   284         }
   285         if( data->disasm_pc != -1 && data->disasm_pc >= from && data->disasm_pc < to )
   286             gtk_clist_set_foreground( data->disasm_list, address_to_row(data, data->disasm_pc),
   287                                       &gui_colour_pc );
   288     }
   290     if( page != from ) { /* not a page boundary */
   291         gtk_clist_moveto( data->disasm_list, (page-from)>>1, 0, 0.5, 0.0 );
   292     }
   293     data->disasm_from = from;
   294     data->disasm_to = to;
   295 }
   297 void jump_to_disassembly( debug_window_t data, unsigned int addr, gboolean select )
   298 {
   299     int row;
   301     if( addr < data->disasm_from || addr >= data->disasm_to )
   302         set_disassembly_region(data,addr);
   304     row = address_to_row( data, addr );
   305     if(select) {
   306         gtk_clist_select_row( data->disasm_list, row, 0 );
   307     }
   308     if( gtk_clist_row_is_visible( data->disasm_list, row ) != GTK_VISIBILITY_FULL ){
   309         gtk_clist_moveto( data->disasm_list, row, 0, 0.5, 0.0 );
   310     }
   311 }
   313 void jump_to_pc( debug_window_t data, gboolean select )
   314 {
   315     jump_to_disassembly( data, *data->cpu->pc, select );
   316 }
   318 void set_disassembly_pc( debug_window_t data, unsigned int pc, gboolean select )
   319 {
   320     int row;
   322     jump_to_disassembly( data, pc, select );
   323     if( data->disasm_pc != -1 && data->disasm_pc >= data->disasm_from && 
   324 	data->disasm_pc < data->disasm_to )
   325         gtk_clist_set_foreground( data->disasm_list, 
   326 				  (data->disasm_pc - data->disasm_from) / data->cpu->instr_size,
   327                                   &gui_colour_normal );
   328     row = address_to_row( data, pc );
   329     gtk_clist_set_foreground( data->disasm_list, row, &gui_colour_pc );
   330     data->disasm_pc = pc;
   331 }
   333 void set_disassembly_cpu( debug_window_t data, const gchar *cpu )
   334 {
   335     int i;
   336     for( i=0; data->cpu_list[i] != NULL; i++ ) {
   337 	if( strcmp( data->cpu_list[i]->name, cpu ) == 0 ) {
   338 	    if( data->cpu != data->cpu_list[i] ) {
   339 		data->cpu = data->cpu_list[i];
   340 		data->disasm_from = data->disasm_to = -1; /* Force reload */
   341 		set_disassembly_pc( data, *data->cpu->pc, FALSE );
   342 		init_register_list( data );
   343 	    }
   344 	    return;
   345 	}
   346     }
   347 }
   349 void debug_window_toggle_breakpoint( debug_window_t data, int row )
   350 {
   351     uint32_t pc = row_to_address( data, row );
   352     int oldType = data->cpu->get_breakpoint( pc );
   353     if( oldType != BREAK_NONE ) {
   354 	data->cpu->clear_breakpoint( pc, oldType );
   355 	gtk_clist_set_background( data->disasm_list, row, &gui_colour_white );
   356     } else {
   357 	data->cpu->set_breakpoint( pc, BREAK_KEEP );
   358 	gtk_clist_set_background( data->disasm_list, row, &gui_colour_break );
   359     }
   360 }
   362 void debug_window_set_oneshot_breakpoint( debug_window_t data, int row )
   363 {
   364     uint32_t pc = row_to_address( data, row );
   365     data->cpu->clear_breakpoint( pc, BREAK_ONESHOT );
   366     data->cpu->set_breakpoint( pc, BREAK_ONESHOT );
   367     gtk_clist_set_background( data->disasm_list, row, &gui_colour_temp_break );
   368 }
   370 /**
   371  * Execute a single instruction using the current CPU mode.
   372  */
   373 void debug_window_single_step( debug_window_t data )
   374 {
   375     data->cpu->step_func();
   376     gtk_gui_update();
   377 }
   379 uint32_t row_to_address( debug_window_t data, int row ) {
   380     return data->cpu->instr_size * row + data->disasm_from;
   381 }
   383 int address_to_row( debug_window_t data, uint32_t address ) {
   384     if( data->disasm_from > address || data->disasm_to <= address )
   385 	return -1;
   386     return (address - data->disasm_from) / data->cpu->instr_size;
   387 }
   389 debug_window_t get_debug_info( GtkWidget *widget ) {
   391     GtkWidget *win = gtk_widget_get_toplevel(widget);
   392     debug_window_t data = (debug_window_t)gtk_object_get_data( GTK_OBJECT(win), "debug_data" );
   393     return data;
   394 }
   396 void debug_window_set_running( debug_window_t data, gboolean isRunning ) 
   397 {
   398     if( data != NULL ) {
   399 	gtk_gui_enable_action( "SingleStep", !isRunning );
   400 	gtk_gui_enable_action( "RunTo", !isRunning && dreamcast_can_run() );
   401     }
   402 }
   404 void on_mode_field_changed ( GtkEditable *editable, gpointer user_data)
   405 {
   406     const gchar *text = gtk_entry_get_text( GTK_ENTRY(editable) );
   407     set_disassembly_cpu( gtk_gui_get_debugger(), text );
   408 }
   411 gboolean on_page_field_key_press_event( GtkWidget * widget, GdkEventKey *event,
   412                                         gpointer user_data)
   413 {
   414     if( event->keyval == GDK_Return || event->keyval == GDK_Linefeed ) {
   415 	debug_window_t data = get_debug_info(widget);
   416         const gchar *text = gtk_entry_get_text( GTK_ENTRY(widget) );
   417         gchar *endptr;
   418         unsigned int val = strtoul( text, &endptr, 16 );
   419         if( text == endptr ) { /* invalid input */
   420             char buf[10];
   421             sprintf( buf, "%08X", row_to_address(data,0) );
   422             gtk_entry_set_text( GTK_ENTRY(widget), buf );
   423         } else {
   424             set_disassembly_region(data, val);
   425         }
   426     }
   427     return FALSE;
   428 }
   431 void on_jump_pc_btn_clicked( GtkButton *button, gpointer user_data)
   432 {
   433     debug_window_t data = get_debug_info( GTK_WIDGET(button) );
   434     jump_to_pc( data, TRUE );
   435 }
   437 void on_disasm_list_select_row (GtkCList *clist, gint row, gint column,
   438 				GdkEvent *event, gpointer user_data)
   439 {
   440     gtk_gui_enable_action( "SetBreakpoint", TRUE );
   441     gtk_gui_enable_action( "RunTo", dreamcast_can_run() );
   442 }
   444 void on_disasm_list_unselect_row (GtkCList *clist, gint row, gint column,
   445 				  GdkEvent *event, gpointer user_data)
   446 {
   447     gtk_gui_enable_action( "SetBreakpoint", FALSE );
   448     gtk_gui_enable_action( "RunTo", FALSE );
   449 }
   451 gboolean on_debug_delete_event(GtkWidget *widget, GdkEvent event, gpointer user_data)
   452 {
   453     gtk_widget_hide( widget );
   454     return TRUE;
   455 }
.