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 429:e581b90c3fb3
prev415:5e57f29bfd4d
next435:7a5d71e8560b
author nkeynes
date Mon Oct 08 12:09:06 2007 +0000 (16 years ago)
permissions -rw-r--r--
last change Fix compilation warnings
file annotate diff log raw
nkeynes@10
     1
/**
nkeynes@429
     2
 * $Id: debug_win.c,v 1.22 2007-10-08 11:48:56 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@392
    22
#include "sh4/sh4dasm.h"
nkeynes@43
    23
#include "gui/gui.h"
nkeynes@2
    24
#include "mem.h"
nkeynes@30
    25
#include "cpu.h"
nkeynes@144
    26
#include "display.h"
nkeynes@429
    27
#include "pvr2/pvr2.h"
nkeynes@2
    28
nkeynes@2
    29
GdkColor *msg_colors[] = { &clrError, &clrError, &clrWarn, &clrNormal,
nkeynes@2
    30
                           &clrDebug, &clrTrace };
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@45
    34
void init_register_list( debug_info_t data );
nkeynes@45
    35
nkeynes@9
    36
struct debug_info_struct {
nkeynes@9
    37
    int disasm_from;
nkeynes@9
    38
    int disasm_to;
nkeynes@9
    39
    int disasm_pc;
nkeynes@429
    40
    const struct cpu_desc_struct *cpu;
nkeynes@392
    41
    const cpu_desc_t *cpu_list;
nkeynes@9
    42
    GtkCList *msgs_list;
nkeynes@9
    43
    GtkCList *regs_list;
nkeynes@9
    44
    GtkCList *disasm_list;
nkeynes@9
    45
    GtkEntry *page_field;
nkeynes@28
    46
    GtkWidget *win;
nkeynes@9
    47
    GtkProgressBar *icounter;
nkeynes@9
    48
    char icounter_text[16];
nkeynes@9
    49
    char saved_regs[0];
nkeynes@8
    50
};
nkeynes@8
    51
nkeynes@30
    52
debug_info_t init_debug_win(GtkWidget *win, const cpu_desc_t *cpu_list )
nkeynes@2
    53
{
nkeynes@2
    54
    GnomeAppBar *appbar;
nkeynes@9
    55
    
nkeynes@11
    56
    debug_info_t data = g_malloc0( sizeof(struct debug_info_struct) + cpu_list[0]->regs_size );
nkeynes@9
    57
    data->disasm_from = -1;
nkeynes@9
    58
    data->disasm_to = -1;
nkeynes@9
    59
    data->disasm_pc = -1;
nkeynes@11
    60
    data->cpu = cpu_list[0];
nkeynes@11
    61
    data->cpu_list = cpu_list;
nkeynes@9
    62
    
nkeynes@9
    63
    data->regs_list= gtk_object_get_data(GTK_OBJECT(win), "reg_list");
nkeynes@28
    64
    data->win = win;
nkeynes@9
    65
    gtk_widget_modify_font( GTK_WIDGET(data->regs_list), fixed_list_font );
nkeynes@11
    66
    init_register_list( data );
nkeynes@9
    67
    data->msgs_list = gtk_object_get_data(GTK_OBJECT(win), "output_list");
nkeynes@9
    68
    data->disasm_list = gtk_object_get_data(GTK_OBJECT(win), "disasm_list");
nkeynes@9
    69
    gtk_clist_set_column_width( data->disasm_list, 1, 16 );
nkeynes@9
    70
    data->page_field = gtk_object_get_data(GTK_OBJECT(win), "page_field");
nkeynes@2
    71
nkeynes@2
    72
    appbar = gtk_object_get_data(GTK_OBJECT(win), "debug_appbar");
nkeynes@9
    73
    data->icounter = gnome_appbar_get_progress( appbar );
nkeynes@9
    74
    gtk_progress_bar_set_text(data->icounter, "1");
nkeynes@10
    75
    
nkeynes@9
    76
    gtk_object_set_data( GTK_OBJECT(win), "debug_data", data );
nkeynes@29
    77
    set_disassembly_pc( data, *data->cpu->pc, FALSE );
nkeynes@28
    78
    debug_win_set_running( data, FALSE );
nkeynes@9
    79
    return data;
nkeynes@2
    80
}
nkeynes@2
    81
nkeynes@11
    82
void init_register_list( debug_info_t data ) 
nkeynes@11
    83
{
nkeynes@11
    84
    int i;
nkeynes@11
    85
    char buf[20];
nkeynes@11
    86
    char *arr[2];
nkeynes@11
    87
nkeynes@11
    88
    gtk_clist_clear( data->regs_list );
nkeynes@11
    89
    arr[1] = buf;
nkeynes@11
    90
    for( i=0; data->cpu->regs_info[i].name != NULL; i++ ) {
nkeynes@11
    91
        arr[0] = data->cpu->regs_info[i].name;
nkeynes@11
    92
        if( data->cpu->regs_info->type == REG_INT )
nkeynes@11
    93
            sprintf( buf, "%08X", *((uint32_t *)data->cpu->regs_info[i].value) );
nkeynes@11
    94
        else
nkeynes@11
    95
            sprintf( buf, "%f", *((float *)data->cpu->regs_info[i].value) );
nkeynes@11
    96
        gtk_clist_append( data->regs_list, arr );
nkeynes@11
    97
    }
nkeynes@11
    98
}
nkeynes@11
    99
nkeynes@2
   100
/*
nkeynes@2
   101
 * Check for changed registers and update the display
nkeynes@2
   102
 */
nkeynes@9
   103
void update_registers( debug_info_t data )
nkeynes@2
   104
{
nkeynes@2
   105
    int i;
nkeynes@9
   106
    for( i=0; data->cpu->regs_info[i].name != NULL; i++ ) {
nkeynes@9
   107
        if( data->cpu->regs_info[i].type == REG_INT ) {
nkeynes@2
   108
            /* Yes this _is_ probably fairly evil */
nkeynes@9
   109
            if( *((uint32_t *)data->cpu->regs_info[i].value) !=
nkeynes@9
   110
                *((uint32_t *)((char *)data->saved_regs + ((char *)data->cpu->regs_info[i].value - (char *)data->cpu->regs))) ) {
nkeynes@2
   111
                char buf[20];
nkeynes@9
   112
                sprintf( buf, "%08X", *((uint32_t *)data->cpu->regs_info[i].value) );
nkeynes@9
   113
                gtk_clist_set_text( data->regs_list, i, 1, buf );
nkeynes@9
   114
                gtk_clist_set_foreground( data->regs_list, i, &clrChanged );
nkeynes@2
   115
            } else {
nkeynes@9
   116
                gtk_clist_set_foreground( data->regs_list, i, &clrNormal );
nkeynes@2
   117
            }
nkeynes@2
   118
        } else {
nkeynes@9
   119
            if( *((float *)data->cpu->regs_info[i].value) !=
nkeynes@9
   120
                *((float *)((char *)data->saved_regs + ((char *)data->cpu->regs_info[i].value - (char *)data->cpu->regs))) ) {
nkeynes@2
   121
                char buf[20];
nkeynes@9
   122
                sprintf( buf, "%f", *((float *)data->cpu->regs_info[i].value) );
nkeynes@9
   123
                gtk_clist_set_text( data->regs_list, i, 1, buf );
nkeynes@9
   124
                gtk_clist_set_foreground( data->regs_list, i, &clrChanged );
nkeynes@2
   125
            } else {
nkeynes@9
   126
                gtk_clist_set_foreground( data->regs_list, i, &clrNormal );
nkeynes@2
   127
            }
nkeynes@2
   128
        }
nkeynes@2
   129
    }
nkeynes@9
   130
nkeynes@9
   131
    set_disassembly_pc( data, *data->cpu->pc, FALSE );
nkeynes@9
   132
    memcpy( data->saved_regs, data->cpu->regs, data->cpu->regs_size );
nkeynes@2
   133
}
nkeynes@2
   134
nkeynes@9
   135
void update_icount( debug_info_t data )
nkeynes@2
   136
{
nkeynes@392
   137
    if( data != NULL ) {
nkeynes@392
   138
	//    sprintf( data->icounter_text, "%d", *data->cpu->icount );
nkeynes@392
   139
	sprintf( data->icounter_text, "%d", pvr2_get_frame_count() );
nkeynes@392
   140
	gtk_progress_bar_set_text( data->icounter, data->icounter_text );
nkeynes@392
   141
    }
nkeynes@2
   142
}
nkeynes@2
   143
nkeynes@9
   144
void set_disassembly_region( debug_info_t data, unsigned int page )
nkeynes@2
   145
{
nkeynes@11
   146
    uint32_t i, posn, next;
nkeynes@2
   147
    char buf[80];
nkeynes@2
   148
    char addr[10];
nkeynes@11
   149
    char opcode[16] = "";
nkeynes@2
   150
    char *arr[4] = { addr, " ", opcode, buf };
nkeynes@2
   151
    unsigned int from = page & 0xFFFFF000;
nkeynes@2
   152
    unsigned int to = from + 4096;
nkeynes@2
   153
    
nkeynes@9
   154
    gtk_clist_clear(data->disasm_list);
nkeynes@2
   155
nkeynes@2
   156
    sprintf( addr, "%08X", from );
nkeynes@9
   157
    gtk_entry_set_text( data->page_field, addr );
nkeynes@2
   158
nkeynes@14
   159
    if( !data->cpu->is_valid_page_func( from ) ) {
nkeynes@2
   160
        arr[3] = "This page is currently unmapped";
nkeynes@9
   161
        gtk_clist_append( data->disasm_list, arr );
nkeynes@9
   162
        gtk_clist_set_foreground( data->disasm_list, 0, &clrError );
nkeynes@2
   163
    } else {
nkeynes@11
   164
        for( i=from; i<to; i = next ) {
nkeynes@11
   165
	    next = data->cpu->disasm_func( i, buf, sizeof(buf), opcode );
nkeynes@2
   166
            sprintf( addr, "%08X", i );
nkeynes@9
   167
            posn = gtk_clist_append( data->disasm_list, arr );
nkeynes@2
   168
            if( buf[0] == '?' )
nkeynes@9
   169
                gtk_clist_set_foreground( data->disasm_list, posn, &clrWarn );
nkeynes@43
   170
	    if( data->cpu->get_breakpoint != NULL ) {
nkeynes@43
   171
		int type = data->cpu->get_breakpoint( i );
nkeynes@43
   172
		switch(type) {
nkeynes@43
   173
		case BREAK_ONESHOT:
nkeynes@43
   174
		    gtk_clist_set_background( data->disasm_list, posn, &clrTempBreak );
nkeynes@43
   175
		    break;
nkeynes@43
   176
		case BREAK_KEEP:
nkeynes@43
   177
		    gtk_clist_set_background( data->disasm_list, posn, &clrBreak );
nkeynes@43
   178
		    break;
nkeynes@43
   179
		}
nkeynes@43
   180
	    }
nkeynes@2
   181
        }
nkeynes@9
   182
        if( data->disasm_pc != -1 && data->disasm_pc >= from && data->disasm_pc < to )
nkeynes@9
   183
            gtk_clist_set_foreground( data->disasm_list, address_to_row(data, data->disasm_pc),
nkeynes@2
   184
                                      &clrPC );
nkeynes@2
   185
    }
nkeynes@2
   186
nkeynes@2
   187
    if( page != from ) { /* not a page boundary */
nkeynes@9
   188
        gtk_clist_moveto( data->disasm_list, (page-from)>>1, 0, 0.5, 0.0 );
nkeynes@2
   189
    }
nkeynes@9
   190
    data->disasm_from = from;
nkeynes@9
   191
    data->disasm_to = to;
nkeynes@2
   192
}
nkeynes@2
   193
nkeynes@9
   194
void jump_to_disassembly( debug_info_t data, unsigned int addr, gboolean select )
nkeynes@2
   195
{
nkeynes@2
   196
    int row;
nkeynes@2
   197
    
nkeynes@9
   198
    if( addr < data->disasm_from || addr >= data->disasm_to )
nkeynes@9
   199
        set_disassembly_region(data,addr);
nkeynes@2
   200
nkeynes@9
   201
    row = address_to_row( data, addr );
nkeynes@2
   202
    if(select) {
nkeynes@9
   203
        gtk_clist_select_row( data->disasm_list, row, 0 );
nkeynes@2
   204
    }
nkeynes@9
   205
    if( gtk_clist_row_is_visible( data->disasm_list, row ) != GTK_VISIBILITY_FULL ){
nkeynes@9
   206
        gtk_clist_moveto( data->disasm_list, row, 0, 0.5, 0.0 );
nkeynes@2
   207
    }
nkeynes@2
   208
}
nkeynes@2
   209
nkeynes@9
   210
void jump_to_pc( debug_info_t data, gboolean select )
nkeynes@9
   211
{
nkeynes@9
   212
    jump_to_disassembly( data, *data->cpu->pc, select );
nkeynes@9
   213
}
nkeynes@9
   214
nkeynes@9
   215
void set_disassembly_pc( debug_info_t data, unsigned int pc, gboolean select )
nkeynes@2
   216
{
nkeynes@2
   217
    int row;
nkeynes@2
   218
    
nkeynes@9
   219
    jump_to_disassembly( data, pc, select );
nkeynes@9
   220
    if( data->disasm_pc != -1 && data->disasm_pc >= data->disasm_from && 
nkeynes@9
   221
	data->disasm_pc < data->disasm_to )
nkeynes@9
   222
        gtk_clist_set_foreground( data->disasm_list, 
nkeynes@9
   223
				  (data->disasm_pc - data->disasm_from) / data->cpu->instr_size,
nkeynes@2
   224
                                  &clrNormal );
nkeynes@9
   225
    row = address_to_row( data, pc );
nkeynes@9
   226
    gtk_clist_set_foreground( data->disasm_list, row, &clrPC );
nkeynes@9
   227
    data->disasm_pc = pc;
nkeynes@2
   228
}
nkeynes@2
   229
nkeynes@26
   230
void set_disassembly_cpu( debug_info_t data, const gchar *cpu )
nkeynes@10
   231
{
nkeynes@11
   232
    int i;
nkeynes@11
   233
    for( i=0; data->cpu_list[i] != NULL; i++ ) {
nkeynes@11
   234
	if( strcmp( data->cpu_list[i]->name, cpu ) == 0 ) {
nkeynes@11
   235
	    if( data->cpu != data->cpu_list[i] ) {
nkeynes@11
   236
		data->cpu = data->cpu_list[i];
nkeynes@69
   237
		data->disasm_from = data->disasm_to = -1; /* Force reload */
nkeynes@30
   238
		set_disassembly_pc( data, *data->cpu->pc, FALSE );
nkeynes@11
   239
		init_register_list( data );
nkeynes@33
   240
		update_icount( data );
nkeynes@11
   241
	    }
nkeynes@11
   242
	    return;
nkeynes@11
   243
	}
nkeynes@11
   244
    }
nkeynes@10
   245
}
nkeynes@10
   246
nkeynes@45
   247
void debug_win_toggle_breakpoint( debug_info_t data, int row )
nkeynes@43
   248
{
nkeynes@43
   249
    uint32_t pc = row_to_address( data, row );
nkeynes@43
   250
    int oldType = data->cpu->get_breakpoint( pc );
nkeynes@43
   251
    if( oldType != BREAK_NONE ) {
nkeynes@43
   252
	data->cpu->clear_breakpoint( pc, oldType );
nkeynes@45
   253
	gtk_clist_set_background( data->disasm_list, row, &clrWhite );
nkeynes@43
   254
    } else {
nkeynes@45
   255
	data->cpu->set_breakpoint( pc, BREAK_KEEP );
nkeynes@45
   256
	gtk_clist_set_background( data->disasm_list, row, &clrBreak );
nkeynes@43
   257
    }
nkeynes@45
   258
}
nkeynes@45
   259
nkeynes@45
   260
void debug_win_set_oneshot_breakpoint( debug_info_t data, int row )
nkeynes@45
   261
{
nkeynes@45
   262
    uint32_t pc = row_to_address( data, row );
nkeynes@45
   263
    data->cpu->clear_breakpoint( pc, BREAK_ONESHOT );
nkeynes@45
   264
    data->cpu->set_breakpoint( pc, BREAK_ONESHOT );
nkeynes@45
   265
    gtk_clist_set_background( data->disasm_list, row, &clrTempBreak );
nkeynes@43
   266
}
nkeynes@43
   267
nkeynes@30
   268
/**
nkeynes@30
   269
 * Execute a single instruction using the current CPU mode.
nkeynes@30
   270
 */
nkeynes@30
   271
void debug_win_single_step( debug_info_t data )
nkeynes@30
   272
{
nkeynes@30
   273
    data->cpu->step_func();
nkeynes@30
   274
    gtk_gui_update();
nkeynes@30
   275
}
nkeynes@30
   276
nkeynes@9
   277
uint32_t row_to_address( debug_info_t data, int row ) {
nkeynes@9
   278
    return data->cpu->instr_size * row + data->disasm_from;
nkeynes@9
   279
}
nkeynes@2
   280
nkeynes@9
   281
int address_to_row( debug_info_t data, uint32_t address ) {
nkeynes@9
   282
    if( data->disasm_from > address || data->disasm_to <= address )
nkeynes@9
   283
	return -1;
nkeynes@9
   284
    return (address - data->disasm_from) / data->cpu->instr_size;
nkeynes@9
   285
}
nkeynes@9
   286
nkeynes@10
   287
nkeynes@35
   288
void emit( void *ptr, int level, const gchar *source, const char *msg, ... )
nkeynes@2
   289
{
nkeynes@2
   290
    char buf[20], addr[10] = "", *p;
nkeynes@429
   291
    const gchar *arr[4] = {buf, source, addr};
nkeynes@2
   292
    int posn;
nkeynes@2
   293
    time_t tm = time(NULL);
nkeynes@2
   294
    va_list ap;
nkeynes@9
   295
    debug_info_t data;
nkeynes@9
   296
    if( ptr == NULL )
nkeynes@9
   297
	data = main_debug;
nkeynes@9
   298
    else data = (debug_info_t)ptr;
nkeynes@415
   299
nkeynes@415
   300
    if( level > global_msg_level ) {
nkeynes@415
   301
	return; // ignored
nkeynes@415
   302
    }
nkeynes@69
   303
    va_start(ap, msg);
nkeynes@2
   304
nkeynes@392
   305
    strftime( buf, sizeof(buf), "%H:%M:%S", localtime(&tm) );
nkeynes@392
   306
nkeynes@69
   307
    if( data == NULL ) {
nkeynes@392
   308
	fprintf( stderr, "%s %08X %-5s ", buf, *sh4_cpu_desc.pc, msg_levels[level] );
nkeynes@69
   309
	vfprintf( stderr, msg, ap );
nkeynes@97
   310
	fprintf( stderr, "\n" );
nkeynes@69
   311
	va_end(ap);
nkeynes@69
   312
	return;
nkeynes@69
   313
    }
nkeynes@69
   314
nkeynes@2
   315
    p = g_strdup_vprintf( msg, ap );
nkeynes@35
   316
    sprintf( addr, "%08X", *data->cpu->pc );
nkeynes@35
   317
    arr[3] = p;
nkeynes@429
   318
    posn = gtk_clist_append(data->msgs_list, (gchar **)arr);
nkeynes@2
   319
    free(p);
nkeynes@2
   320
    va_end(ap);
nkeynes@2
   321
nkeynes@9
   322
    gtk_clist_set_foreground( data->msgs_list, posn, msg_colors[level] );
nkeynes@9
   323
    gtk_clist_moveto( data->msgs_list, posn, 0, 1.0, 0.0 );
nkeynes@2
   324
nkeynes@2
   325
    /* emit _really_ slows down the emu, to the point where the gui can be
nkeynes@2
   326
     * completely unresponsive if I don't include this:
nkeynes@2
   327
     */
nkeynes@2
   328
    while( gtk_events_pending() )
nkeynes@2
   329
        gtk_main_iteration();
nkeynes@2
   330
}
nkeynes@9
   331
nkeynes@9
   332
debug_info_t get_debug_info( GtkWidget *widget ) {
nkeynes@9
   333
    
nkeynes@9
   334
    GtkWidget *win = gtk_widget_get_toplevel(widget);
nkeynes@9
   335
    debug_info_t data = (debug_info_t)gtk_object_get_data( GTK_OBJECT(win), "debug_data" );
nkeynes@9
   336
    return data;
nkeynes@9
   337
}
nkeynes@9
   338
nkeynes@28
   339
void debug_win_enable_widget( debug_info_t data, const char *name, 
nkeynes@28
   340
			      gboolean enabled )
nkeynes@28
   341
{
nkeynes@28
   342
    GtkWidget *widget = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(data->win), name));
nkeynes@28
   343
    gtk_widget_set_sensitive( widget, enabled );
nkeynes@28
   344
}    
nkeynes@28
   345
nkeynes@28
   346
void debug_win_set_running( debug_info_t data, gboolean isRunning ) 
nkeynes@28
   347
{
nkeynes@392
   348
    if( data != NULL ) {
nkeynes@392
   349
	debug_win_enable_widget( data, "stop_btn", isRunning );
nkeynes@392
   350
	debug_win_enable_widget( data, "step_btn", !isRunning );
nkeynes@392
   351
	debug_win_enable_widget( data, "run_btn", !isRunning );
nkeynes@392
   352
	debug_win_enable_widget( data, "runto_btn", !isRunning );
nkeynes@392
   353
    }
nkeynes@28
   354
}
.