Search
lxdream.org :: lxdream/src/gui/debug_win.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gui/debug_win.c
changeset 437:2c259474b474
prev435:7a5d71e8560b
next455:3080881d00d4
author nkeynes
date Wed Oct 17 11:26:45 2007 +0000 (16 years ago)
permissions -rw-r--r--
last change Split config management out to config.[ch]
Manage config filename
Check home dir + sysconfdir for conf file
Initial work on a path settings dialog
view annotate diff log raw
     1 /**
     2  * $Id: debug_win.c,v 1.24 2007-10-11 08:22:03 nkeynes Exp $
     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 <gnome.h>
    21 #include <math.h>
    22 #include "mem.h"
    23 #include "cpu.h"
    24 #include "debugif.h"
    25 #include "gui/gtkui.h"
    26 #include "sh4/sh4dasm.h"
    27 #include "aica/armdasm.h"
    29 GdkColor *msg_colors[] = { &gui_colour_error, &gui_colour_error, &gui_colour_warn, 
    30 			   &gui_colour_normal,&gui_colour_debug, &gui_colour_trace };
    32 const cpu_desc_t cpu_list[4] = { &sh4_cpu_desc, &arm_cpu_desc, &armt_cpu_desc, NULL };
    34 void init_register_list( debug_window_t data );
    35 uint32_t row_to_address( debug_window_t data, int row );
    36 void set_disassembly_pc( debug_window_t data, unsigned int pc, gboolean select );
    37 void set_disassembly_region( debug_window_t data, unsigned int page );
    38 void set_disassembly_cpu( debug_window_t data, const gchar *cpu );
    40 struct debug_window_info {
    41     int disasm_from;
    42     int disasm_to;
    43     int disasm_pc;
    44     const struct cpu_desc_struct *cpu;
    45     const cpu_desc_t *cpu_list;
    46     GtkCList *msgs_list;
    47     GtkCList *regs_list;
    48     GtkCList *disasm_list;
    49     GtkEntry *page_field;
    50     GtkWidget *win;
    51     GtkProgressBar *icounter;
    52     char icounter_text[16];
    53     char saved_regs[0];
    54 };
    56 debug_window_t debug_window_new( )
    57 {
    58     GtkWidget *win = create_debug_win();
    59     GnomeAppBar *appbar;
    61     debug_window_t data = g_malloc0( sizeof(struct debug_window_info) + cpu_list[0]->regs_size );
    62     data->disasm_from = -1;
    63     data->disasm_to = -1;
    64     data->disasm_pc = -1;
    65     data->cpu = cpu_list[0];
    66     data->cpu_list = cpu_list;
    68     data->regs_list= gtk_object_get_data(GTK_OBJECT(win), "reg_list");
    69     data->win = win;
    70     gtk_widget_modify_font( GTK_WIDGET(data->regs_list), gui_fixed_font );
    71     init_register_list( data );
    72     data->msgs_list = gtk_object_get_data(GTK_OBJECT(win), "output_list");
    73     data->disasm_list = gtk_object_get_data(GTK_OBJECT(win), "disasm_list");
    74     gtk_clist_set_column_width( data->disasm_list, 1, 16 );
    75     data->page_field = gtk_object_get_data(GTK_OBJECT(win), "page_field");
    77     appbar = gtk_object_get_data(GTK_OBJECT(win), "debug_appbar");
    78     data->icounter = gnome_appbar_get_progress( appbar );
    79     gtk_progress_bar_set_text(data->icounter, "1");
    81     gtk_object_set_data( GTK_OBJECT(win), "debug_data", data );
    82     set_disassembly_pc( data, *data->cpu->pc, FALSE );
    83     debug_window_set_running( data, FALSE );
    85     gtk_widget_show( win );
    86     return data;
    87 }
    89 void debug_window_show( debug_window_t data, gboolean show )
    90 {
    91     if( show ) {
    92 	gtk_widget_show( data->win );
    93     } else {
    94 	gtk_widget_hide( data->win );
    95     }
    96 }
    98 void init_register_list( debug_window_t data ) 
    99 {
   100     int i;
   101     char buf[20];
   102     char *arr[2];
   104     gtk_clist_clear( data->regs_list );
   105     arr[1] = buf;
   106     for( i=0; data->cpu->regs_info[i].name != NULL; i++ ) {
   107         arr[0] = data->cpu->regs_info[i].name;
   108         if( data->cpu->regs_info->type == REG_INT )
   109             sprintf( buf, "%08X", *((uint32_t *)data->cpu->regs_info[i].value) );
   110         else
   111             sprintf( buf, "%f", *((float *)data->cpu->regs_info[i].value) );
   112         gtk_clist_append( data->regs_list, arr );
   113     }
   114 }
   116 /*
   117  * Check for changed registers and update the display
   118  */
   119 void debug_window_update( debug_window_t data )
   120 {
   121     int i;
   122     for( i=0; data->cpu->regs_info[i].name != NULL; i++ ) {
   123         if( data->cpu->regs_info[i].type == REG_INT ) {
   124             /* Yes this _is_ probably fairly evil */
   125             if( *((uint32_t *)data->cpu->regs_info[i].value) !=
   126                 *((uint32_t *)((char *)data->saved_regs + ((char *)data->cpu->regs_info[i].value - (char *)data->cpu->regs))) ) {
   127                 char buf[20];
   128                 sprintf( buf, "%08X", *((uint32_t *)data->cpu->regs_info[i].value) );
   129                 gtk_clist_set_text( data->regs_list, i, 1, buf );
   130                 gtk_clist_set_foreground( data->regs_list, i, &gui_colour_changed );
   131             } else {
   132                 gtk_clist_set_foreground( data->regs_list, i, &gui_colour_normal );
   133             }
   134         } else {
   135             if( *((float *)data->cpu->regs_info[i].value) !=
   136                 *((float *)((char *)data->saved_regs + ((char *)data->cpu->regs_info[i].value - (char *)data->cpu->regs))) ) {
   137                 char buf[20];
   138                 sprintf( buf, "%f", *((float *)data->cpu->regs_info[i].value) );
   139                 gtk_clist_set_text( data->regs_list, i, 1, buf );
   140                 gtk_clist_set_foreground( data->regs_list, i, &gui_colour_changed );
   141             } else {
   142                 gtk_clist_set_foreground( data->regs_list, i, &gui_colour_normal );
   143             }
   144         }
   145     }
   147     set_disassembly_pc( data, *data->cpu->pc, FALSE );
   148     memcpy( data->saved_regs, data->cpu->regs, data->cpu->regs_size );
   149 }
   151 void set_disassembly_region( debug_window_t data, unsigned int page )
   152 {
   153     uint32_t i, posn, next;
   154     char buf[80];
   155     char addr[10];
   156     char opcode[16] = "";
   157     char *arr[4] = { addr, " ", opcode, buf };
   158     unsigned int from = page & 0xFFFFF000;
   159     unsigned int to = from + 4096;
   161     gtk_clist_clear(data->disasm_list);
   163     sprintf( addr, "%08X", from );
   164     gtk_entry_set_text( data->page_field, addr );
   166     if( !data->cpu->is_valid_page_func( from ) ) {
   167         arr[3] = "This page is currently unmapped";
   168         gtk_clist_append( data->disasm_list, arr );
   169         gtk_clist_set_foreground( data->disasm_list, 0, &gui_colour_error );
   170     } else {
   171         for( i=from; i<to; i = next ) {
   172 	    next = data->cpu->disasm_func( i, buf, sizeof(buf), opcode );
   173             sprintf( addr, "%08X", i );
   174             posn = gtk_clist_append( data->disasm_list, arr );
   175             if( buf[0] == '?' )
   176                 gtk_clist_set_foreground( data->disasm_list, posn, &gui_colour_warn );
   177 	    if( data->cpu->get_breakpoint != NULL ) {
   178 		int type = data->cpu->get_breakpoint( i );
   179 		switch(type) {
   180 		case BREAK_ONESHOT:
   181 		    gtk_clist_set_background( data->disasm_list, posn, &gui_colour_temp_break );
   182 		    break;
   183 		case BREAK_KEEP:
   184 		    gtk_clist_set_background( data->disasm_list, posn, &gui_colour_break );
   185 		    break;
   186 		}
   187 	    }
   188         }
   189         if( data->disasm_pc != -1 && data->disasm_pc >= from && data->disasm_pc < to )
   190             gtk_clist_set_foreground( data->disasm_list, address_to_row(data, data->disasm_pc),
   191                                       &gui_colour_pc );
   192     }
   194     if( page != from ) { /* not a page boundary */
   195         gtk_clist_moveto( data->disasm_list, (page-from)>>1, 0, 0.5, 0.0 );
   196     }
   197     data->disasm_from = from;
   198     data->disasm_to = to;
   199 }
   201 void jump_to_disassembly( debug_window_t data, unsigned int addr, gboolean select )
   202 {
   203     int row;
   205     if( addr < data->disasm_from || addr >= data->disasm_to )
   206         set_disassembly_region(data,addr);
   208     row = address_to_row( data, addr );
   209     if(select) {
   210         gtk_clist_select_row( data->disasm_list, row, 0 );
   211     }
   212     if( gtk_clist_row_is_visible( data->disasm_list, row ) != GTK_VISIBILITY_FULL ){
   213         gtk_clist_moveto( data->disasm_list, row, 0, 0.5, 0.0 );
   214     }
   215 }
   217 void jump_to_pc( debug_window_t data, gboolean select )
   218 {
   219     jump_to_disassembly( data, *data->cpu->pc, select );
   220 }
   222 void set_disassembly_pc( debug_window_t data, unsigned int pc, gboolean select )
   223 {
   224     int row;
   226     jump_to_disassembly( data, pc, select );
   227     if( data->disasm_pc != -1 && data->disasm_pc >= data->disasm_from && 
   228 	data->disasm_pc < data->disasm_to )
   229         gtk_clist_set_foreground( data->disasm_list, 
   230 				  (data->disasm_pc - data->disasm_from) / data->cpu->instr_size,
   231                                   &gui_colour_normal );
   232     row = address_to_row( data, pc );
   233     gtk_clist_set_foreground( data->disasm_list, row, &gui_colour_pc );
   234     data->disasm_pc = pc;
   235 }
   237 void set_disassembly_cpu( debug_window_t data, const gchar *cpu )
   238 {
   239     int i;
   240     for( i=0; data->cpu_list[i] != NULL; i++ ) {
   241 	if( strcmp( data->cpu_list[i]->name, cpu ) == 0 ) {
   242 	    if( data->cpu != data->cpu_list[i] ) {
   243 		data->cpu = data->cpu_list[i];
   244 		data->disasm_from = data->disasm_to = -1; /* Force reload */
   245 		set_disassembly_pc( data, *data->cpu->pc, FALSE );
   246 		init_register_list( data );
   247 	    }
   248 	    return;
   249 	}
   250     }
   251 }
   253 void debug_win_toggle_breakpoint( debug_window_t data, int row )
   254 {
   255     uint32_t pc = row_to_address( data, row );
   256     int oldType = data->cpu->get_breakpoint( pc );
   257     if( oldType != BREAK_NONE ) {
   258 	data->cpu->clear_breakpoint( pc, oldType );
   259 	gtk_clist_set_background( data->disasm_list, row, &gui_colour_white );
   260     } else {
   261 	data->cpu->set_breakpoint( pc, BREAK_KEEP );
   262 	gtk_clist_set_background( data->disasm_list, row, &gui_colour_break );
   263     }
   264 }
   266 void debug_win_set_oneshot_breakpoint( debug_window_t data, int row )
   267 {
   268     uint32_t pc = row_to_address( data, row );
   269     data->cpu->clear_breakpoint( pc, BREAK_ONESHOT );
   270     data->cpu->set_breakpoint( pc, BREAK_ONESHOT );
   271     gtk_clist_set_background( data->disasm_list, row, &gui_colour_temp_break );
   272 }
   274 /**
   275  * Execute a single instruction using the current CPU mode.
   276  */
   277 void debug_win_single_step( debug_window_t data )
   278 {
   279     data->cpu->step_func();
   280     gtk_gui_update();
   281 }
   283 uint32_t row_to_address( debug_window_t data, int row ) {
   284     return data->cpu->instr_size * row + data->disasm_from;
   285 }
   287 int address_to_row( debug_window_t data, uint32_t address ) {
   288     if( data->disasm_from > address || data->disasm_to <= address )
   289 	return -1;
   290     return (address - data->disasm_from) / data->cpu->instr_size;
   291 }
   293 #if 0
   294 void emit( void *ptr, int level, const gchar *source, const char *msg, ... )
   295 {
   296     char buf[20], addr[10] = "", *p;
   297     const gchar *arr[4] = {buf, source, addr};
   298     int posn;
   299     time_t tm = time(NULL);
   300     va_list ap;
   301     debug_window_t data = NULL;
   302     /*
   303     if( ptr == NULL )
   304 	data = debug_win;
   305     else data = (debug_window_t)ptr;
   306     */
   307     if( level > global_msg_level ) {
   308 	return; // ignored
   309     }
   310     va_start(ap, msg);
   312     strftime( buf, sizeof(buf), "%H:%M:%S", localtime(&tm) );
   314     if( data == NULL ) {
   315 	fprintf( stderr, "%s %08X %-5s ", buf, *sh4_cpu_desc.pc, msg_levels[level] );
   316 	vfprintf( stderr, msg, ap );
   317 	fprintf( stderr, "\n" );
   318 	va_end(ap);
   319 	return;
   320     }
   322     p = g_strdup_vprintf( msg, ap );
   323     sprintf( addr, "%08X", *data->cpu->pc );
   324     arr[3] = p;
   325     posn = gtk_clist_append(data->msgs_list, (gchar **)arr);
   326     free(p);
   327     va_end(ap);
   329     gtk_clist_set_foreground( data->msgs_list, posn, msg_colors[level] );
   330     gtk_clist_moveto( data->msgs_list, posn, 0, 1.0, 0.0 );
   332     /* emit _really_ slows down the emu, to the point where the gui can be
   333      * completely unresponsive if I don't include this:
   334      */
   335     while( gtk_events_pending() )
   336         gtk_main_iteration();
   337 }
   338 #endif
   339 debug_window_t get_debug_info( GtkWidget *widget ) {
   341     GtkWidget *win = gtk_widget_get_toplevel(widget);
   342     debug_window_t data = (debug_window_t)gtk_object_get_data( GTK_OBJECT(win), "debug_data" );
   343     return data;
   344 }
   346 void debug_win_enable_widget( debug_window_t data, const char *name, 
   347 			      gboolean enabled )
   348 {
   349     GtkWidget *widget = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(data->win), name));
   350     gtk_widget_set_sensitive( widget, enabled );
   351 }    
   353 void debug_window_set_running( debug_window_t data, gboolean isRunning ) 
   354 {
   355     if( data != NULL ) {
   356 	debug_win_enable_widget( data, "stop_btn", isRunning );
   357 	debug_win_enable_widget( data, "step_btn", !isRunning );
   358 	debug_win_enable_widget( data, "run_btn", !isRunning );
   359 	debug_win_enable_widget( data, "runto_btn", !isRunning );
   360     }
   361 }
.