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 435:7a5d71e8560b
prev429:e581b90c3fb3
next437:2c259474b474
author nkeynes
date Wed Oct 10 11:02:04 2007 +0000 (14 years ago)
permissions -rw-r--r--
last change First cut of new GUI
file annotate diff log raw
nkeynes@10
     1
/**
nkeynes@435
     2
 * $Id: debug_win.c,v 1.23 2007-10-10 11:02:04 nkeynes Exp $
nkeynes@10
     3
 * This file is responsible for the main debugger gui frame.
nkeynes@10
     4
 *
nkeynes@10
     5
 * Copyright (c) 2005 Nathan Keynes.
nkeynes@10
     6
 *
nkeynes@10
     7
 * This program is free software; you can redistribute it and/or modify
nkeynes@10
     8
 * it under the terms of the GNU General Public License as published by
nkeynes@10
     9
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@10
    10
 * (at your option) any later version.
nkeynes@10
    11
 *
nkeynes@10
    12
 * This program is distributed in the hope that it will be useful,
nkeynes@10
    13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@10
    14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@10
    15
 * GNU General Public License for more details.
nkeynes@10
    16
 */
nkeynes@2
    17
#include <stdlib.h>
nkeynes@2
    18
#include <stdarg.h>
nkeynes@69
    19
#include <stdio.h>
nkeynes@2
    20
#include <gnome.h>
nkeynes@2
    21
#include <math.h>
nkeynes@2
    22
#include "mem.h"
nkeynes@30
    23
#include "cpu.h"
nkeynes@435
    24
#include "debugif.h"
nkeynes@435
    25
#include "gui/gtkui.h"
nkeynes@435
    26
#include "sh4/sh4dasm.h"
nkeynes@435
    27
#include "aica/armdasm.h"
nkeynes@2
    28
nkeynes@435
    29
GdkColor *msg_colors[] = { &gui_colour_error, &gui_colour_error, &gui_colour_warn, 
nkeynes@435
    30
			   &gui_colour_normal,&gui_colour_debug, &gui_colour_trace };
nkeynes@392
    31
char *msg_levels[] = { "FATAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE" };
nkeynes@415
    32
int global_msg_level = EMIT_WARN;
nkeynes@2
    33
nkeynes@435
    34
const cpu_desc_t cpu_list[4] = { &sh4_cpu_desc, &arm_cpu_desc, &armt_cpu_desc, NULL };
nkeynes@45
    35
nkeynes@435
    36
void init_register_list( debug_window_t data );
nkeynes@435
    37
uint32_t row_to_address( debug_window_t data, int row );
nkeynes@435
    38
void set_disassembly_pc( debug_window_t data, unsigned int pc, gboolean select );
nkeynes@435
    39
void set_disassembly_region( debug_window_t data, unsigned int page );
nkeynes@435
    40
void set_disassembly_cpu( debug_window_t data, const gchar *cpu );
nkeynes@435
    41
nkeynes@435
    42
struct debug_window_info {
nkeynes@9
    43
    int disasm_from;
nkeynes@9
    44
    int disasm_to;
nkeynes@9
    45
    int disasm_pc;
nkeynes@429
    46
    const struct cpu_desc_struct *cpu;
nkeynes@392
    47
    const cpu_desc_t *cpu_list;
nkeynes@9
    48
    GtkCList *msgs_list;
nkeynes@9
    49
    GtkCList *regs_list;
nkeynes@9
    50
    GtkCList *disasm_list;
nkeynes@9
    51
    GtkEntry *page_field;
nkeynes@28
    52
    GtkWidget *win;
nkeynes@9
    53
    GtkProgressBar *icounter;
nkeynes@9
    54
    char icounter_text[16];
nkeynes@9
    55
    char saved_regs[0];
nkeynes@8
    56
};
nkeynes@8
    57
nkeynes@435
    58
debug_window_t debug_window_new( )
nkeynes@2
    59
{
nkeynes@435
    60
    GtkWidget *win = create_debug_win();
nkeynes@2
    61
    GnomeAppBar *appbar;
nkeynes@9
    62
    
nkeynes@435
    63
    debug_window_t data = g_malloc0( sizeof(struct debug_window_info) + cpu_list[0]->regs_size );
nkeynes@9
    64
    data->disasm_from = -1;
nkeynes@9
    65
    data->disasm_to = -1;
nkeynes@9
    66
    data->disasm_pc = -1;
nkeynes@11
    67
    data->cpu = cpu_list[0];
nkeynes@11
    68
    data->cpu_list = cpu_list;
nkeynes@9
    69
    
nkeynes@9
    70
    data->regs_list= gtk_object_get_data(GTK_OBJECT(win), "reg_list");
nkeynes@28
    71
    data->win = win;
nkeynes@435
    72
    gtk_widget_modify_font( GTK_WIDGET(data->regs_list), gui_fixed_font );
nkeynes@11
    73
    init_register_list( data );
nkeynes@9
    74
    data->msgs_list = gtk_object_get_data(GTK_OBJECT(win), "output_list");
nkeynes@9
    75
    data->disasm_list = gtk_object_get_data(GTK_OBJECT(win), "disasm_list");
nkeynes@9
    76
    gtk_clist_set_column_width( data->disasm_list, 1, 16 );
nkeynes@9
    77
    data->page_field = gtk_object_get_data(GTK_OBJECT(win), "page_field");
nkeynes@2
    78
nkeynes@2
    79
    appbar = gtk_object_get_data(GTK_OBJECT(win), "debug_appbar");
nkeynes@9
    80
    data->icounter = gnome_appbar_get_progress( appbar );
nkeynes@9
    81
    gtk_progress_bar_set_text(data->icounter, "1");
nkeynes@10
    82
    
nkeynes@9
    83
    gtk_object_set_data( GTK_OBJECT(win), "debug_data", data );
nkeynes@29
    84
    set_disassembly_pc( data, *data->cpu->pc, FALSE );
nkeynes@435
    85
    debug_window_set_running( data, FALSE );
nkeynes@435
    86
nkeynes@435
    87
    gtk_widget_show( win );
nkeynes@9
    88
    return data;
nkeynes@2
    89
}
nkeynes@2
    90
nkeynes@435
    91
void debug_window_show( debug_window_t data, gboolean show )
nkeynes@435
    92
{
nkeynes@435
    93
    if( show ) {
nkeynes@435
    94
	gtk_widget_show( data->win );
nkeynes@435
    95
    } else {
nkeynes@435
    96
	gtk_widget_hide( data->win );
nkeynes@435
    97
    }
nkeynes@435
    98
}
nkeynes@435
    99
nkeynes@435
   100
void init_register_list( debug_window_t data ) 
nkeynes@11
   101
{
nkeynes@11
   102
    int i;
nkeynes@11
   103
    char buf[20];
nkeynes@11
   104
    char *arr[2];
nkeynes@11
   105
nkeynes@11
   106
    gtk_clist_clear( data->regs_list );
nkeynes@11
   107
    arr[1] = buf;
nkeynes@11
   108
    for( i=0; data->cpu->regs_info[i].name != NULL; i++ ) {
nkeynes@11
   109
        arr[0] = data->cpu->regs_info[i].name;
nkeynes@11
   110
        if( data->cpu->regs_info->type == REG_INT )
nkeynes@11
   111
            sprintf( buf, "%08X", *((uint32_t *)data->cpu->regs_info[i].value) );
nkeynes@11
   112
        else
nkeynes@11
   113
            sprintf( buf, "%f", *((float *)data->cpu->regs_info[i].value) );
nkeynes@11
   114
        gtk_clist_append( data->regs_list, arr );
nkeynes@11
   115
    }
nkeynes@11
   116
}
nkeynes@11
   117
nkeynes@2
   118
/*
nkeynes@2
   119
 * Check for changed registers and update the display
nkeynes@2
   120
 */
nkeynes@435
   121
void debug_window_update( debug_window_t data )
nkeynes@2
   122
{
nkeynes@2
   123
    int i;
nkeynes@9
   124
    for( i=0; data->cpu->regs_info[i].name != NULL; i++ ) {
nkeynes@9
   125
        if( data->cpu->regs_info[i].type == REG_INT ) {
nkeynes@2
   126
            /* Yes this _is_ probably fairly evil */
nkeynes@9
   127
            if( *((uint32_t *)data->cpu->regs_info[i].value) !=
nkeynes@9
   128
                *((uint32_t *)((char *)data->saved_regs + ((char *)data->cpu->regs_info[i].value - (char *)data->cpu->regs))) ) {
nkeynes@2
   129
                char buf[20];
nkeynes@9
   130
                sprintf( buf, "%08X", *((uint32_t *)data->cpu->regs_info[i].value) );
nkeynes@9
   131
                gtk_clist_set_text( data->regs_list, i, 1, buf );
nkeynes@435
   132
                gtk_clist_set_foreground( data->regs_list, i, &gui_colour_changed );
nkeynes@2
   133
            } else {
nkeynes@435
   134
                gtk_clist_set_foreground( data->regs_list, i, &gui_colour_normal );
nkeynes@2
   135
            }
nkeynes@2
   136
        } else {
nkeynes@9
   137
            if( *((float *)data->cpu->regs_info[i].value) !=
nkeynes@9
   138
                *((float *)((char *)data->saved_regs + ((char *)data->cpu->regs_info[i].value - (char *)data->cpu->regs))) ) {
nkeynes@2
   139
                char buf[20];
nkeynes@9
   140
                sprintf( buf, "%f", *((float *)data->cpu->regs_info[i].value) );
nkeynes@9
   141
                gtk_clist_set_text( data->regs_list, i, 1, buf );
nkeynes@435
   142
                gtk_clist_set_foreground( data->regs_list, i, &gui_colour_changed );
nkeynes@2
   143
            } else {
nkeynes@435
   144
                gtk_clist_set_foreground( data->regs_list, i, &gui_colour_normal );
nkeynes@2
   145
            }
nkeynes@2
   146
        }
nkeynes@2
   147
    }
nkeynes@9
   148
nkeynes@9
   149
    set_disassembly_pc( data, *data->cpu->pc, FALSE );
nkeynes@9
   150
    memcpy( data->saved_regs, data->cpu->regs, data->cpu->regs_size );
nkeynes@2
   151
}
nkeynes@2
   152
nkeynes@435
   153
void set_disassembly_region( debug_window_t data, unsigned int page )
nkeynes@2
   154
{
nkeynes@11
   155
    uint32_t i, posn, next;
nkeynes@2
   156
    char buf[80];
nkeynes@2
   157
    char addr[10];
nkeynes@11
   158
    char opcode[16] = "";
nkeynes@2
   159
    char *arr[4] = { addr, " ", opcode, buf };
nkeynes@2
   160
    unsigned int from = page & 0xFFFFF000;
nkeynes@2
   161
    unsigned int to = from + 4096;
nkeynes@2
   162
    
nkeynes@9
   163
    gtk_clist_clear(data->disasm_list);
nkeynes@2
   164
nkeynes@2
   165
    sprintf( addr, "%08X", from );
nkeynes@9
   166
    gtk_entry_set_text( data->page_field, addr );
nkeynes@2
   167
nkeynes@14
   168
    if( !data->cpu->is_valid_page_func( from ) ) {
nkeynes@2
   169
        arr[3] = "This page is currently unmapped";
nkeynes@9
   170
        gtk_clist_append( data->disasm_list, arr );
nkeynes@435
   171
        gtk_clist_set_foreground( data->disasm_list, 0, &gui_colour_error );
nkeynes@2
   172
    } else {
nkeynes@11
   173
        for( i=from; i<to; i = next ) {
nkeynes@11
   174
	    next = data->cpu->disasm_func( i, buf, sizeof(buf), opcode );
nkeynes@2
   175
            sprintf( addr, "%08X", i );
nkeynes@9
   176
            posn = gtk_clist_append( data->disasm_list, arr );
nkeynes@2
   177
            if( buf[0] == '?' )
nkeynes@435
   178
                gtk_clist_set_foreground( data->disasm_list, posn, &gui_colour_warn );
nkeynes@43
   179
	    if( data->cpu->get_breakpoint != NULL ) {
nkeynes@43
   180
		int type = data->cpu->get_breakpoint( i );
nkeynes@43
   181
		switch(type) {
nkeynes@43
   182
		case BREAK_ONESHOT:
nkeynes@435
   183
		    gtk_clist_set_background( data->disasm_list, posn, &gui_colour_temp_break );
nkeynes@43
   184
		    break;
nkeynes@43
   185
		case BREAK_KEEP:
nkeynes@435
   186
		    gtk_clist_set_background( data->disasm_list, posn, &gui_colour_break );
nkeynes@43
   187
		    break;
nkeynes@43
   188
		}
nkeynes@43
   189
	    }
nkeynes@2
   190
        }
nkeynes@9
   191
        if( data->disasm_pc != -1 && data->disasm_pc >= from && data->disasm_pc < to )
nkeynes@9
   192
            gtk_clist_set_foreground( data->disasm_list, address_to_row(data, data->disasm_pc),
nkeynes@435
   193
                                      &gui_colour_pc );
nkeynes@2
   194
    }
nkeynes@2
   195
nkeynes@2
   196
    if( page != from ) { /* not a page boundary */
nkeynes@9
   197
        gtk_clist_moveto( data->disasm_list, (page-from)>>1, 0, 0.5, 0.0 );
nkeynes@2
   198
    }
nkeynes@9
   199
    data->disasm_from = from;
nkeynes@9
   200
    data->disasm_to = to;
nkeynes@2
   201
}
nkeynes@2
   202
nkeynes@435
   203
void jump_to_disassembly( debug_window_t data, unsigned int addr, gboolean select )
nkeynes@2
   204
{
nkeynes@2
   205
    int row;
nkeynes@2
   206
    
nkeynes@9
   207
    if( addr < data->disasm_from || addr >= data->disasm_to )
nkeynes@9
   208
        set_disassembly_region(data,addr);
nkeynes@2
   209
nkeynes@9
   210
    row = address_to_row( data, addr );
nkeynes@2
   211
    if(select) {
nkeynes@9
   212
        gtk_clist_select_row( data->disasm_list, row, 0 );
nkeynes@2
   213
    }
nkeynes@9
   214
    if( gtk_clist_row_is_visible( data->disasm_list, row ) != GTK_VISIBILITY_FULL ){
nkeynes@9
   215
        gtk_clist_moveto( data->disasm_list, row, 0, 0.5, 0.0 );
nkeynes@2
   216
    }
nkeynes@2
   217
}
nkeynes@2
   218
nkeynes@435
   219
void jump_to_pc( debug_window_t data, gboolean select )
nkeynes@9
   220
{
nkeynes@9
   221
    jump_to_disassembly( data, *data->cpu->pc, select );
nkeynes@9
   222
}
nkeynes@9
   223
nkeynes@435
   224
void set_disassembly_pc( debug_window_t data, unsigned int pc, gboolean select )
nkeynes@2
   225
{
nkeynes@2
   226
    int row;
nkeynes@2
   227
    
nkeynes@9
   228
    jump_to_disassembly( data, pc, select );
nkeynes@9
   229
    if( data->disasm_pc != -1 && data->disasm_pc >= data->disasm_from && 
nkeynes@9
   230
	data->disasm_pc < data->disasm_to )
nkeynes@9
   231
        gtk_clist_set_foreground( data->disasm_list, 
nkeynes@9
   232
				  (data->disasm_pc - data->disasm_from) / data->cpu->instr_size,
nkeynes@435
   233
                                  &gui_colour_normal );
nkeynes@9
   234
    row = address_to_row( data, pc );
nkeynes@435
   235
    gtk_clist_set_foreground( data->disasm_list, row, &gui_colour_pc );
nkeynes@9
   236
    data->disasm_pc = pc;
nkeynes@2
   237
}
nkeynes@2
   238
nkeynes@435
   239
void set_disassembly_cpu( debug_window_t data, const gchar *cpu )
nkeynes@10
   240
{
nkeynes@11
   241
    int i;
nkeynes@11
   242
    for( i=0; data->cpu_list[i] != NULL; i++ ) {
nkeynes@11
   243
	if( strcmp( data->cpu_list[i]->name, cpu ) == 0 ) {
nkeynes@11
   244
	    if( data->cpu != data->cpu_list[i] ) {
nkeynes@11
   245
		data->cpu = data->cpu_list[i];
nkeynes@69
   246
		data->disasm_from = data->disasm_to = -1; /* Force reload */
nkeynes@30
   247
		set_disassembly_pc( data, *data->cpu->pc, FALSE );
nkeynes@11
   248
		init_register_list( data );
nkeynes@11
   249
	    }
nkeynes@11
   250
	    return;
nkeynes@11
   251
	}
nkeynes@11
   252
    }
nkeynes@10
   253
}
nkeynes@10
   254
nkeynes@435
   255
void debug_win_toggle_breakpoint( debug_window_t data, int row )
nkeynes@43
   256
{
nkeynes@43
   257
    uint32_t pc = row_to_address( data, row );
nkeynes@43
   258
    int oldType = data->cpu->get_breakpoint( pc );
nkeynes@43
   259
    if( oldType != BREAK_NONE ) {
nkeynes@43
   260
	data->cpu->clear_breakpoint( pc, oldType );
nkeynes@435
   261
	gtk_clist_set_background( data->disasm_list, row, &gui_colour_white );
nkeynes@43
   262
    } else {
nkeynes@45
   263
	data->cpu->set_breakpoint( pc, BREAK_KEEP );
nkeynes@435
   264
	gtk_clist_set_background( data->disasm_list, row, &gui_colour_break );
nkeynes@43
   265
    }
nkeynes@45
   266
}
nkeynes@45
   267
nkeynes@435
   268
void debug_win_set_oneshot_breakpoint( debug_window_t data, int row )
nkeynes@45
   269
{
nkeynes@45
   270
    uint32_t pc = row_to_address( data, row );
nkeynes@45
   271
    data->cpu->clear_breakpoint( pc, BREAK_ONESHOT );
nkeynes@45
   272
    data->cpu->set_breakpoint( pc, BREAK_ONESHOT );
nkeynes@435
   273
    gtk_clist_set_background( data->disasm_list, row, &gui_colour_temp_break );
nkeynes@43
   274
}
nkeynes@43
   275
nkeynes@30
   276
/**
nkeynes@30
   277
 * Execute a single instruction using the current CPU mode.
nkeynes@30
   278
 */
nkeynes@435
   279
void debug_win_single_step( debug_window_t data )
nkeynes@30
   280
{
nkeynes@30
   281
    data->cpu->step_func();
nkeynes@30
   282
    gtk_gui_update();
nkeynes@30
   283
}
nkeynes@30
   284
nkeynes@435
   285
uint32_t row_to_address( debug_window_t data, int row ) {
nkeynes@9
   286
    return data->cpu->instr_size * row + data->disasm_from;
nkeynes@9
   287
}
nkeynes@2
   288
nkeynes@435
   289
int address_to_row( debug_window_t data, uint32_t address ) {
nkeynes@9
   290
    if( data->disasm_from > address || data->disasm_to <= address )
nkeynes@9
   291
	return -1;
nkeynes@9
   292
    return (address - data->disasm_from) / data->cpu->instr_size;
nkeynes@9
   293
}
nkeynes@9
   294
nkeynes@10
   295
nkeynes@35
   296
void emit( void *ptr, int level, const gchar *source, const char *msg, ... )
nkeynes@2
   297
{
nkeynes@2
   298
    char buf[20], addr[10] = "", *p;
nkeynes@429
   299
    const gchar *arr[4] = {buf, source, addr};
nkeynes@2
   300
    int posn;
nkeynes@2
   301
    time_t tm = time(NULL);
nkeynes@2
   302
    va_list ap;
nkeynes@435
   303
    debug_window_t data = NULL;
nkeynes@435
   304
    /*
nkeynes@9
   305
    if( ptr == NULL )
nkeynes@435
   306
	data = debug_win;
nkeynes@435
   307
    else data = (debug_window_t)ptr;
nkeynes@435
   308
    */
nkeynes@415
   309
    if( level > global_msg_level ) {
nkeynes@415
   310
	return; // ignored
nkeynes@415
   311
    }
nkeynes@69
   312
    va_start(ap, msg);
nkeynes@2
   313
nkeynes@392
   314
    strftime( buf, sizeof(buf), "%H:%M:%S", localtime(&tm) );
nkeynes@392
   315
nkeynes@69
   316
    if( data == NULL ) {
nkeynes@392
   317
	fprintf( stderr, "%s %08X %-5s ", buf, *sh4_cpu_desc.pc, msg_levels[level] );
nkeynes@69
   318
	vfprintf( stderr, msg, ap );
nkeynes@97
   319
	fprintf( stderr, "\n" );
nkeynes@69
   320
	va_end(ap);
nkeynes@69
   321
	return;
nkeynes@69
   322
    }
nkeynes@69
   323
nkeynes@2
   324
    p = g_strdup_vprintf( msg, ap );
nkeynes@35
   325
    sprintf( addr, "%08X", *data->cpu->pc );
nkeynes@35
   326
    arr[3] = p;
nkeynes@429
   327
    posn = gtk_clist_append(data->msgs_list, (gchar **)arr);
nkeynes@2
   328
    free(p);
nkeynes@2
   329
    va_end(ap);
nkeynes@2
   330
nkeynes@9
   331
    gtk_clist_set_foreground( data->msgs_list, posn, msg_colors[level] );
nkeynes@9
   332
    gtk_clist_moveto( data->msgs_list, posn, 0, 1.0, 0.0 );
nkeynes@2
   333
nkeynes@2
   334
    /* emit _really_ slows down the emu, to the point where the gui can be
nkeynes@2
   335
     * completely unresponsive if I don't include this:
nkeynes@2
   336
     */
nkeynes@2
   337
    while( gtk_events_pending() )
nkeynes@2
   338
        gtk_main_iteration();
nkeynes@2
   339
}
nkeynes@9
   340
nkeynes@435
   341
debug_window_t get_debug_info( GtkWidget *widget ) {
nkeynes@9
   342
    
nkeynes@9
   343
    GtkWidget *win = gtk_widget_get_toplevel(widget);
nkeynes@435
   344
    debug_window_t data = (debug_window_t)gtk_object_get_data( GTK_OBJECT(win), "debug_data" );
nkeynes@9
   345
    return data;
nkeynes@9
   346
}
nkeynes@9
   347
nkeynes@435
   348
void debug_win_enable_widget( debug_window_t data, const char *name, 
nkeynes@28
   349
			      gboolean enabled )
nkeynes@28
   350
{
nkeynes@28
   351
    GtkWidget *widget = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(data->win), name));
nkeynes@28
   352
    gtk_widget_set_sensitive( widget, enabled );
nkeynes@28
   353
}    
nkeynes@28
   354
nkeynes@435
   355
void debug_window_set_running( debug_window_t data, gboolean isRunning ) 
nkeynes@28
   356
{
nkeynes@392
   357
    if( data != NULL ) {
nkeynes@392
   358
	debug_win_enable_widget( data, "stop_btn", isRunning );
nkeynes@392
   359
	debug_win_enable_widget( data, "step_btn", !isRunning );
nkeynes@392
   360
	debug_win_enable_widget( data, "run_btn", !isRunning );
nkeynes@392
   361
	debug_win_enable_widget( data, "runto_btn", !isRunning );
nkeynes@392
   362
    }
nkeynes@28
   363
}
.