1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
4 Copyright (C) 2000 Kh. Naba Kumar Singh
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.
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.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "registers.h"
33 #include <libanjuta/resources.h>
34 #include <libanjuta/anjuta-debug.h>
36 #include "utilities.h"
40 *---------------------------------------------------------------------------*/
42 #define REGISTER_UNMODIFIED_COLOR "black"
43 #define REGISTER_MODIFIED_COLOR "red"
44 #define REGISTER_UNKNOWN_VALUE "??"
47 *---------------------------------------------------------------------------*/
49 typedef struct _DmaThreadRegisterList
54 } DmaThreadRegisterList
;
58 DmaDebuggerQueue
*debugger
;
60 DmaThreadRegisterList
* current
;
62 GtkTreeView
*treeview
;
69 REGISTER_MODIFIED
= 1 << 0,
82 *---------------------------------------------------------------------------*/
84 /* Handle list of registers for each thread
85 *---------------------------------------------------------------------------*/
88 on_copy_register_name (GtkTreeModel
*model
,
93 GtkListStore
*list
= (GtkListStore
*)user_data
;
98 gtk_tree_model_get(model
, iter
,
103 gtk_list_store_append (list
, &dest
);
104 gtk_list_store_set(list
, &dest
,
107 VALUE_COLUMN
, REGISTER_UNKNOWN_VALUE
,
116 on_cpu_registers_updated (const GList
*registers
, gpointer user_data
, GError
*error
)
118 CpuRegisters
*self
= (CpuRegisters
*)user_data
;
127 /* Command canceled */
132 if (self
->current
== NULL
)
134 /* Program has exited */
138 /* Get first item in list view */
139 valid
= gtk_tree_model_get_iter_first (self
->current
->model
, &iter
);
140 list
= GTK_LIST_STORE (self
->current
->model
);
142 self
->current
->last_update
= self
->current_update
;
144 for(node
= registers
;node
!= NULL
; node
= g_list_next (node
))
146 IAnjutaDebuggerRegisterData
*reg
= (IAnjutaDebuggerRegisterData
*)node
->data
;
150 /* Look for corresponding item in list view */
151 for (;valid
; valid
= gtk_tree_model_iter_next (self
->current
->model
, &iter
))
153 gtk_tree_model_get (self
->current
->model
, &iter
, NUMBER_COLUMN
, &id
, -1);
154 if (id
>= reg
->num
) break;
159 /* Append new item in list view */
160 gtk_list_store_append (list
, &iter
);
161 gtk_list_store_set(list
, &iter
,
162 NUMBER_COLUMN
, reg
->num
,
163 NAME_COLUMN
, reg
->name
,
164 VALUE_COLUMN
, reg
->value
== NULL
? REGISTER_UNKNOWN_VALUE
: reg
->value
,
168 else if (id
!= reg
->num
)
170 /* Insert new item in list view */
171 gtk_list_store_insert_before (list
, &iter
, &iter
);
172 gtk_list_store_set(list
, &iter
,
173 NUMBER_COLUMN
, reg
->num
,
174 NAME_COLUMN
, reg
->name
,
175 VALUE_COLUMN
, reg
->value
== NULL
? REGISTER_UNKNOWN_VALUE
: reg
->value
,
182 if (reg
->name
!= NULL
)
184 gtk_list_store_set (list
, &iter
, NAME_COLUMN
, reg
->name
, -1);
187 if (reg
->value
!= NULL
)
189 gtk_tree_model_get (self
->current
->model
, &iter
, VALUE_COLUMN
, &value
, -1);
190 if ((value
!= NULL
) && (strcmp (value
, reg
->value
) == 0))
193 gtk_list_store_set (list
, &iter
, FLAG_COLUMN
, 0, -1);
198 gtk_list_store_set (list
, &iter
, VALUE_COLUMN
, reg
->value
,
199 FLAG_COLUMN
, REGISTER_MODIFIED
,
202 if (value
!= NULL
) g_free (value
);
209 cpu_registers_update (CpuRegisters
*self
)
211 if (GTK_WIDGET_MAPPED (self
->window
))
213 dma_queue_update_register (
215 (IAnjutaDebuggerCallback
)on_cpu_registers_updated
,
220 static DmaThreadRegisterList
*
221 dma_thread_create_new_register_list (CpuRegisters
*self
, gint thread
)
223 DmaThreadRegisterList
*regs
;
226 if ((self
->list
!= NULL
)
227 && (((DmaThreadRegisterList
*)g_list_first (self
->list
)->data
)->thread
== 0))
229 /* List as been created but not associated to a thread */
231 regs
= ((DmaThreadRegisterList
*)g_list_first (self
->list
)->data
);
233 regs
->thread
= thread
;
238 /* Create new list store */
239 store
= gtk_list_store_new (COLUMNS_NB
,
245 regs
= g_new (DmaThreadRegisterList
, 1);
246 regs
->thread
= thread
;
247 regs
->model
= GTK_TREE_MODEL (store
);
248 regs
->last_update
= 0;
250 if (self
->list
== NULL
)
254 self
->current
= regs
;
256 /* List is empty, ask debugger to get all register name */
257 dma_queue_list_register (
259 (IAnjutaDebuggerCallback
)on_cpu_registers_updated
,
264 if (err
->code
== IANJUTA_DEBUGGER_NOT_IMPLEMENTED
)
266 g_object_unref (G_OBJECT (regs
->model
));
268 self
->current
= NULL
;
278 /* One register list already exist, copy register name and ID */
280 gtk_tree_model_foreach (((DmaThreadRegisterList
*)g_list_first (self
->list
)->data
)->model
,
281 on_copy_register_name
, store
);
283 self
->list
= g_list_append (self
->list
, regs
);
289 on_clear_register_list (gpointer data
, gpointer user_data
)
291 DmaThreadRegisterList
*regs
= (DmaThreadRegisterList
*) data
;
293 g_object_unref (G_OBJECT (regs
->model
));
298 dma_thread_clear_all_register_list (CpuRegisters
*self
)
300 self
->current
= NULL
;
302 /* Clear all GtkListStore */
303 g_list_foreach (self
->list
, (GFunc
)on_clear_register_list
, NULL
);
304 g_list_free (self
->list
);
310 on_find_register_list (gconstpointer a
, gconstpointer b
)
312 const DmaThreadRegisterList
*regs
= (const DmaThreadRegisterList
*)a
;
313 guint thread
= (gint
)b
;
315 return regs
->thread
!= thread
;
319 dma_thread_set_register_list (CpuRegisters
*self
, gint thread
)
322 DmaThreadRegisterList
*regs
;
324 if (self
->current
== NULL
) return; /* No register list */
326 if (self
->current
->thread
!= thread
)
328 list
= g_list_find_custom (self
->list
, (gconstpointer
) thread
, on_find_register_list
);
332 /* Create new find */
333 regs
= dma_thread_create_new_register_list(self
, thread
);
337 regs
= (DmaThreadRegisterList
*)list
->data
;
339 self
->current
= regs
;
340 gtk_tree_view_set_model (self
->treeview
, regs
->model
);
343 if (self
->current_update
!= self
->current
->last_update
)
345 cpu_registers_update (self
);
350 on_cpu_registers_changed (GtkCellRendererText
*cell
,
355 CpuRegisters
*self
= (CpuRegisters
*)user_data
;
358 if (gtk_tree_model_get_iter_from_string (self
->current
->model
, &iter
, path_string
))
360 IAnjutaDebuggerRegisterData reg
;
363 gtk_tree_model_get (self
->current
->model
, &iter
, NUMBER_COLUMN
, ®
.num
, NAME_COLUMN
, &name
, -1);
367 dma_queue_write_register (self
->debugger
, ®
);
368 dma_queue_update_register (
370 (IAnjutaDebuggerCallback
)on_cpu_registers_updated
,
377 on_program_moved (CpuRegisters
*self
, guint pid
, gint thread
)
379 self
->current_update
++;
380 dma_thread_set_register_list (self
, thread
);
384 on_frame_changed (CpuRegisters
*self
, guint frame
, gint thread
)
386 dma_thread_set_register_list (self
, thread
);
390 destroy_cpu_registers_gui (CpuRegisters
*self
)
392 /* Destroy register window */
393 if (self
->window
!= NULL
)
395 gtk_widget_destroy (self
->window
);
399 /* Destroy register list */
400 dma_thread_clear_all_register_list (self
);
404 on_program_exited (CpuRegisters
*self
)
406 /* Disconnect signals */
407 g_signal_handlers_disconnect_by_func (self
->plugin
, on_program_exited
, self
);
408 g_signal_handlers_disconnect_by_func (self
->plugin
, on_program_moved
, self
);
409 g_signal_handlers_disconnect_by_func (self
->plugin
, on_frame_changed
, self
);
411 destroy_cpu_registers_gui (self
);
415 on_map (GtkWidget
* widget
, CpuRegisters
*self
)
417 cpu_registers_update (self
);
421 cpu_registers_value_cell_data_func (GtkTreeViewColumn
*tree_column
,
422 GtkCellRenderer
*cell
, GtkTreeModel
*tree_model
,
423 GtkTreeIter
*iter
, gpointer data
)
427 GValue gvalue
= {0, };
429 gtk_tree_model_get (tree_model
, iter
, VALUE_COLUMN
, &value
, FLAG_COLUMN
, &flag
, -1);
431 g_value_init (&gvalue
, G_TYPE_STRING
);
432 g_value_set_static_string (&gvalue
, value
);
433 g_object_set_property (G_OBJECT (cell
), "text", &gvalue
);
436 g_value_reset (&gvalue
);
437 g_value_set_static_string (&gvalue
, flag
& REGISTER_MODIFIED
? REGISTER_MODIFIED_COLOR
: REGISTER_UNMODIFIED_COLOR
);
438 g_object_set_property (G_OBJECT (cell
), "foreground", &gvalue
);
443 create_cpu_registers_gui (CpuRegisters
*self
)
445 GtkCellRenderer
*renderer
;
446 GtkTreeViewColumn
*column
;
448 g_return_val_if_fail (self
->window
== NULL
, FALSE
);
450 /* Create list store */
451 if (dma_thread_create_new_register_list (self
, 0) == NULL
)
453 /* Unable to create register list */
458 /* Create list view */
459 self
->treeview
= GTK_TREE_VIEW (gtk_tree_view_new_with_model (self
->current
->model
));
460 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (self
->treeview
),
461 GTK_SELECTION_SINGLE
);
463 renderer
= gtk_cell_renderer_text_new ();
464 column
= gtk_tree_view_column_new_with_attributes (N_("Register"),
465 renderer
, "text", NAME_COLUMN
, NULL
);
466 gtk_tree_view_column_set_sizing (column
, GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
467 gtk_tree_view_append_column (self
->treeview
, column
);
468 renderer
= gtk_cell_renderer_text_new ();
469 g_object_set(renderer
, "editable", TRUE
, NULL
);
470 g_signal_connect(renderer
, "edited", (GCallback
) on_cpu_registers_changed
, self
);
471 column
= gtk_tree_view_column_new_with_attributes (N_("Value"),
473 gtk_tree_view_column_set_cell_data_func (column
, renderer
,
474 cpu_registers_value_cell_data_func
,
476 gtk_tree_view_column_set_sizing (column
, GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
477 gtk_tree_view_append_column (self
->treeview
, column
);
479 /* Add register window */
480 self
->window
= gtk_scrolled_window_new (NULL
, NULL
);
481 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (self
->window
),
482 GTK_POLICY_AUTOMATIC
,
483 GTK_POLICY_AUTOMATIC
);
484 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (self
->window
),
486 gtk_container_add (GTK_CONTAINER (self
->window
), GTK_WIDGET (self
->treeview
));
487 g_signal_connect(self
->window
, "map", (GCallback
) on_map
, self
);
489 anjuta_shell_add_widget (self
->plugin
->shell
,
491 "AnjutaDebuggerRegisters", _("Registers"),
492 NULL
, ANJUTA_SHELL_PLACEMENT_LEFT
,
499 on_program_started (CpuRegisters
*self
)
501 if (!dma_debugger_queue_is_supported (self
->debugger
, HAS_REGISTER
)) return;
503 /* If current debugger support access to cpu hardware */
504 if (!create_cpu_registers_gui (self
)) return;
506 self
->current_update
= 0;
508 /* Connect remaining signal */
509 g_signal_connect_swapped (self
->plugin
, "program-exited", G_CALLBACK (on_program_exited
), self
);
510 g_signal_connect_swapped (self
->plugin
, "program-moved", G_CALLBACK (on_program_moved
), self
);
511 g_signal_connect_swapped (self
->plugin
, "frame-changed", G_CALLBACK (on_frame_changed
), self
);
514 /* Constructor & Destructor
515 *---------------------------------------------------------------------------*/
518 cpu_registers_new(DebugManagerPlugin
*plugin
)
522 g_return_val_if_fail (plugin
!= NULL
, NULL
);
524 self
= g_new0 (CpuRegisters
, 1);
526 self
->plugin
= ANJUTA_PLUGIN (plugin
);
527 self
->debugger
= dma_debug_manager_get_queue (plugin
);
529 g_signal_connect_swapped (self
->plugin
, "program-started", G_CALLBACK (on_program_started
), self
);
535 cpu_registers_free(CpuRegisters
* self
)
537 g_return_if_fail (self
!= NULL
);
539 g_signal_handlers_disconnect_matched (self
->plugin
, G_SIGNAL_MATCH_DATA
, 0, 0, NULL
, NULL
, self
);
541 destroy_cpu_registers_gui (self
);