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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "stack_trace.h"
33 #include <libanjuta/resources.h>
34 #include <libanjuta/anjuta-debug.h>
35 #include <libanjuta/interfaces/ianjuta-editor.h>
36 #include <libanjuta/interfaces/ianjuta-document-manager.h>
38 #include "utilities.h"
41 #define ANJUTA_PIXMAP_POINTER PACKAGE_PIXMAPS_DIR"/pointer.png"
43 typedef struct _DmaThreadStackTrace
48 } DmaThreadStackTrace
;
52 DebugManagerPlugin
*plugin
;
53 IAnjutaDebugger
*debugger
;
55 GtkActionGroup
*action_group
;
57 DmaThreadStackTrace
* current
;
63 GtkTreeView
*treeview
;
65 GtkWidget
*scrolledwindow
;
69 STACK_TRACE_ACTIVE_COLUMN
,
70 STACK_TRACE_FRAME_COLUMN
,
71 STACK_TRACE_FILE_COLUMN
,
72 STACK_TRACE_LINE_COLUMN
,
73 STACK_TRACE_FUNC_COLUMN
,
74 STACK_TRACE_ADDR_COLUMN
,
75 STACK_TRACE_ARGS_COLUMN
,
76 STACK_TRACE_URI_COLUMN
,
77 STACK_TRACE_COLOR_COLUMN
,
82 *---------------------------------------------------------------------------*/
85 get_current_iter (GtkTreeView
*view
, GtkTreeIter
* iter
)
87 GtkTreeSelection
*selection
;
89 selection
= gtk_tree_view_get_selection (view
);
90 return gtk_tree_selection_get_selected (selection
, NULL
, iter
);
94 * returns the current stack frame or -1 on error
97 get_current_index (StackTrace
* st
)
101 if (get_current_iter (st
->treeview
, &iter
))
106 model
= gtk_tree_view_get_model (st
->treeview
);
107 gtk_tree_model_get (model
, &iter
, STACK_TRACE_FRAME_COLUMN
, &frame_no
, -1);
118 my_gtk_tree_model_get_iter_last(GtkTreeModel
*model
, GtkTreeIter
*last
)
123 exist
= gtk_tree_model_get_iter_first(model
, &iter
);
124 if (!exist
) return FALSE
;
129 exist
= gtk_tree_model_iter_next(model
, &iter
);
137 my_gtk_tree_model_iter_prev(GtkTreeModel
*model
, GtkTreeIter
*iter
)
142 path
= gtk_tree_model_get_path (model
, iter
);
143 exist
= gtk_tree_path_prev (path
);
146 exist
= gtk_tree_model_get_iter (model
, iter
, path
);
148 gtk_tree_path_free (path
);
154 my_gtk_tree_iter_compare(GtkTreeModel
*model
, GtkTreeIter
*itera
, GtkTreeIter
*iterb
)
160 patha
= gtk_tree_model_get_path (model
, itera
);
161 pathb
= gtk_tree_model_get_path (model
, iterb
);
163 comp
= gtk_tree_path_compare (patha
, pathb
);
165 gtk_tree_path_free (patha
);
166 gtk_tree_path_free (pathb
);
172 *---------------------------------------------------------------------------*/
175 on_clear_stack_trace (gpointer data
, gpointer user_data
)
177 DmaThreadStackTrace
*trace
= (DmaThreadStackTrace
*) data
;
179 g_object_unref (G_OBJECT (trace
->model
));
184 dma_thread_clear_all_stack_trace (StackTrace
*self
)
186 /* Clear all GtkListStore */
187 g_list_foreach (self
->list
, (GFunc
)on_clear_stack_trace
, NULL
);
188 g_list_free (self
->list
);
190 self
->current
= NULL
;
195 on_stack_trace_updated (const GList
*stack
, gpointer user_data
)
197 StackTrace
*self
= (StackTrace
*)user_data
;
204 model
= GTK_LIST_STORE (self
->current
->model
);
206 pic
= gdk_pixbuf_new_from_file (ANJUTA_PIXMAP_POINTER
, NULL
);
208 exist
= my_gtk_tree_model_get_iter_last (GTK_TREE_MODEL (model
), &iter
);
210 for (node
= (const GList
*)g_list_last((GList
*)stack
); node
!= NULL
; node
= node
->prev
)
212 IAnjutaDebuggerFrame
*frame
;
217 frame
= (IAnjutaDebuggerFrame
*)node
->data
;
221 /* Check if it's the same stack frame */
228 gtk_tree_model_get (GTK_TREE_MODEL (model
), &iter
,
229 STACK_TRACE_ADDR_COLUMN
, &adr
,
230 STACK_TRACE_LINE_COLUMN
, &line
,
231 STACK_TRACE_ARGS_COLUMN
, &args
,
233 address
= adr
!= NULL
? strtoul (adr
, NULL
, 0) : 0;
234 same
= (address
== frame
->address
) && (line
== frame
->line
);
235 if ((args
== NULL
) || (frame
->args
== NULL
))
237 same
= same
&& (args
== frame
->args
);
241 same
= same
&& (strcmp (args
, frame
->args
) == 0);
248 /* Same frame, just change the color */
249 gtk_list_store_set (model
, &iter
,
250 STACK_TRACE_ACTIVE_COLUMN
, frame
->level
== self
->current_frame
? pic
: NULL
,
251 STACK_TRACE_FRAME_COLUMN
, frame
->level
,
252 STACK_TRACE_COLOR_COLUMN
, "black", -1);
254 /* Check previous frame */
255 exist
= my_gtk_tree_model_iter_prev (GTK_TREE_MODEL (model
), &iter
);
256 if (!exist
|| (node
->prev
!= NULL
))
258 /* Last frame or Upper frame still exist */
261 /* Upper frame do not exist, remove all them */
264 /* New frame, remove all previous frame */
267 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model
), &first
);
268 while (my_gtk_tree_iter_compare (GTK_TREE_MODEL (model
), &first
, &iter
) < 0)
270 gtk_list_store_remove (model
, &first
);
272 gtk_list_store_remove (model
, &first
);
284 gtk_list_store_prepend (model
, &iter
);
286 adr
= g_strdup_printf ("0x%x", frame
->address
);
289 uri
= g_strconcat ("file://", frame
->file
, NULL
);
290 file
= strrchr(uri
, '/') + 1;
295 file
= frame
->library
;
298 gtk_list_store_set(model
, &iter
,
299 STACK_TRACE_ACTIVE_COLUMN
, frame
->level
== self
->current_frame
? pic
: NULL
,
300 STACK_TRACE_FRAME_COLUMN
, frame
->level
,
301 STACK_TRACE_FILE_COLUMN
, file
,
302 STACK_TRACE_LINE_COLUMN
, frame
->line
,
303 STACK_TRACE_FUNC_COLUMN
, frame
->function
,
304 STACK_TRACE_ADDR_COLUMN
, adr
,
305 STACK_TRACE_ARGS_COLUMN
, frame
->args
,
306 STACK_TRACE_URI_COLUMN
, uri
,
307 STACK_TRACE_COLOR_COLUMN
, "red",
312 gdk_pixbuf_unref (pic
);
316 static DmaThreadStackTrace
*
317 dma_thread_create_new_stack_trace (StackTrace
*self
, guint thread
)
319 DmaThreadStackTrace
*trace
;
322 /* Create new list store */
323 store
= gtk_list_store_new (STACK_TRACE_N_COLUMNS
,
334 trace
= g_new (DmaThreadStackTrace
, 1);
335 trace
->thread
= thread
;
336 trace
->model
= GTK_TREE_MODEL (store
);
337 trace
->last_update
= self
->current_update
;
339 self
->current
= trace
;
341 /* Ask debugger to get all frame data */
342 ianjuta_debugger_list_frame (
344 (IAnjutaDebuggerCallback
)on_stack_trace_updated
,
348 self
->list
= g_list_append (self
->list
, trace
);
353 static DmaThreadStackTrace
*
354 dma_thread_update_stack_trace (StackTrace
*self
, DmaThreadStackTrace
*trace
)
358 trace
->last_update
= self
->current_update
;
360 /* Ask debugger to get all frame data */
361 ianjuta_debugger_list_frame (
363 (IAnjutaDebuggerCallback
)on_stack_trace_updated
,
371 on_find_stack_trace (gconstpointer a
, gconstpointer b
)
373 const DmaThreadStackTrace
*trace
= (const DmaThreadStackTrace
*)a
;
374 guint thread
= (guint
)b
;
376 return trace
->thread
!= thread
;
380 dma_thread_set_stack_trace (StackTrace
*self
, guint thread
)
383 DmaThreadStackTrace
*trace
;
385 if ((self
->current
== NULL
) || (self
->current
->thread
!= thread
) || (self
->current
->last_update
!= self
->current_update
))
387 self
->current_frame
= 0;
389 list
= g_list_find_custom (self
->list
, (gconstpointer
) thread
, on_find_stack_trace
);
393 /* Create new stack trace */
394 trace
= dma_thread_create_new_stack_trace(self
, thread
);
398 trace
= (DmaThreadStackTrace
*)list
->data
;
399 self
->current
= trace
;
401 if (trace
->last_update
!= self
->current_update
)
403 /* Update stack trace */
404 dma_thread_update_stack_trace (self
, trace
);
407 gtk_tree_view_set_model (self
->treeview
, trace
->model
);
411 /* Callback functions
412 *---------------------------------------------------------------------------*/
415 on_frame_changed (StackTrace
*self
, guint frame
, guint thread
)
421 dma_thread_set_stack_trace (self
, thread
);
424 self
->current_frame
= frame
;
426 model
= self
->current
->model
;
428 /* Clear old pointer */
429 if(gtk_tree_model_get_iter_first (model
, &iter
))
433 /* clear pixmap on the previous active frame */
434 gtk_list_store_set (GTK_LIST_STORE (model
), &iter
,
435 STACK_TRACE_ACTIVE_COLUMN
, NULL
, -1);
436 } while (gtk_tree_model_iter_next (model
, &iter
));
439 /* Set pointer to current frame */
440 if (gtk_tree_model_iter_nth_child (model
, &iter
, NULL
, self
->current_frame
))
442 GdkPixbuf
*pointer_pix
= gdk_pixbuf_new_from_file (ANJUTA_PIXMAP_POINTER
, NULL
);
444 /* set pointer on this frame */
445 gtk_list_store_set (GTK_LIST_STORE(model
), &iter
,
446 STACK_TRACE_ACTIVE_COLUMN
, pointer_pix
,
448 gdk_pixbuf_unref (pointer_pix
);
453 on_stack_frame_set_activate (GtkAction
*action
, gpointer user_data
)
456 guint selected_frame
;
458 st
= (StackTrace
*) user_data
;
460 selected_frame
= get_current_index (st
);
462 /* No frame selected */
463 if (selected_frame
== -1)
466 /* current frame is already active */
467 if (selected_frame
== st
->current_frame
)
470 /* issue a command to switch active frame to new location */
471 ianjuta_debugger_set_frame (st
->debugger
, selected_frame
, NULL
);
475 on_stack_view_source_activate (GtkAction
*action
, gpointer user_data
)
478 GtkTreeSelection
*selection
;
486 StackTrace
* st
= (StackTrace
*) user_data
;
489 selection
= gtk_tree_view_get_selection (view
);
490 if (!gtk_tree_selection_get_selected (selection
, &model
, &iter
))
493 /* get the frame info */
494 gtk_tree_model_get (model
, &iter
,
495 STACK_TRACE_URI_COLUMN
, &uri
,
496 STACK_TRACE_LINE_COLUMN
, &line
,
497 STACK_TRACE_ADDR_COLUMN
, &adr
,
500 address
= adr
!= NULL
? strtoul (adr
, NULL
, 0) : 0;
501 dma_debug_manager_goto_code (st
->plugin
, uri
, line
, address
);
507 on_stack_trace_row_activated (GtkTreeView
*treeview
,
509 GtkTreeViewColumn
*arg2
,
512 on_stack_frame_set_activate (NULL
, st
);
516 on_stack_trace_button_press (GtkWidget
*widget
, GdkEventButton
*bevent
, gpointer user_data
)
518 StackTrace
*st
= (StackTrace
*) user_data
;
520 if ((bevent
->type
== GDK_BUTTON_PRESS
) && (bevent
->button
== 3))
522 /* Right mouse click */
523 g_return_val_if_fail (st
->menu
!= NULL
, FALSE
);
524 gtk_menu_popup (GTK_MENU (st
->menu
), NULL
, NULL
, NULL
, NULL
,
525 bevent
->button
, bevent
->time
);
527 else if ((bevent
->type
== GDK_2BUTTON_PRESS
) && (bevent
->button
== 1))
529 /* Double left mouse click */
530 on_stack_view_source_activate (NULL
, user_data
);
537 *---------------------------------------------------------------------------*/
539 static GtkActionEntry actions_stack_trace
[] = {
541 "ActionDmaSetCurrentFrame", /* Action name */
542 NULL
, /* Stock icon, if any */
543 N_("Set current frame"), /* Display label */
544 NULL
, /* short-cut */
546 G_CALLBACK (on_stack_frame_set_activate
) /* action callback */
549 "ActionDmaJumpToFrame",
554 G_CALLBACK (on_stack_view_source_activate
)
559 create_stack_trace_gui(StackTrace
*st
)
562 GtkTreeSelection
*selection
;
563 GtkTreeViewColumn
*column
;
564 GtkCellRenderer
*renderer
;
567 g_return_if_fail (st
->scrolledwindow
== NULL
);
569 /* Create tree view */
570 model
= GTK_TREE_MODEL(gtk_list_store_new (STACK_TRACE_N_COLUMNS
,
580 st
->treeview
= GTK_TREE_VIEW (gtk_tree_view_new_with_model (model
));
581 g_object_unref (G_OBJECT (model
));
583 selection
= gtk_tree_view_get_selection (st
->treeview
);
584 gtk_tree_selection_set_mode (selection
, GTK_SELECTION_SINGLE
);
587 column
= gtk_tree_view_column_new ();
588 gtk_tree_view_column_set_sizing (column
, GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
589 gtk_tree_view_column_set_title (column
, _("Active"));
590 renderer
= gtk_cell_renderer_pixbuf_new ();
591 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
592 gtk_tree_view_column_add_attribute (column
, renderer
, "pixbuf",
593 STACK_TRACE_ACTIVE_COLUMN
);
594 gtk_tree_view_append_column (st
->treeview
, column
);
595 gtk_tree_view_set_expander_column (st
->treeview
,
598 column
= gtk_tree_view_column_new ();
599 gtk_tree_view_column_set_sizing (column
, GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
600 gtk_tree_view_column_set_title (column
, _("Frame"));
601 renderer
= gtk_cell_renderer_text_new ();
602 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
603 gtk_tree_view_column_add_attribute (column
, renderer
, "text",
604 STACK_TRACE_FRAME_COLUMN
);
605 gtk_tree_view_column_add_attribute (column
, renderer
, "foreground",
606 STACK_TRACE_COLOR_COLUMN
);
607 gtk_tree_view_column_set_sizing (column
, GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
608 gtk_tree_view_append_column (st
->treeview
, column
);
609 gtk_tree_view_set_expander_column (st
->treeview
,
612 column
= gtk_tree_view_column_new ();
613 renderer
= gtk_cell_renderer_text_new ();
614 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
615 gtk_tree_view_column_add_attribute (column
, renderer
, "text",
616 STACK_TRACE_FILE_COLUMN
);
617 gtk_tree_view_column_add_attribute (column
, renderer
, "foreground",
618 STACK_TRACE_COLOR_COLUMN
);
619 gtk_tree_view_column_set_sizing (column
, GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
620 gtk_tree_view_column_set_title (column
, _("File"));
621 gtk_tree_view_append_column (st
->treeview
, column
);
623 column
= gtk_tree_view_column_new ();
624 renderer
= gtk_cell_renderer_text_new ();
625 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
626 gtk_tree_view_column_add_attribute (column
, renderer
, "text",
627 STACK_TRACE_LINE_COLUMN
);
628 gtk_tree_view_column_add_attribute (column
, renderer
, "foreground",
629 STACK_TRACE_COLOR_COLUMN
);
630 gtk_tree_view_column_set_sizing (column
, GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
631 gtk_tree_view_column_set_title (column
, _("Line"));
632 gtk_tree_view_append_column (st
->treeview
, column
);
634 column
= gtk_tree_view_column_new ();
635 renderer
= gtk_cell_renderer_text_new ();
636 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
637 gtk_tree_view_column_add_attribute (column
, renderer
, "text",
638 STACK_TRACE_FUNC_COLUMN
);
639 gtk_tree_view_column_add_attribute (column
, renderer
, "foreground",
640 STACK_TRACE_COLOR_COLUMN
);
641 gtk_tree_view_column_set_sizing (column
, GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
642 gtk_tree_view_column_set_title (column
, _("Function"));
643 gtk_tree_view_append_column (st
->treeview
, column
);
645 column
= gtk_tree_view_column_new ();
646 renderer
= gtk_cell_renderer_text_new ();
647 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
648 gtk_tree_view_column_add_attribute (column
, renderer
, "text",
649 STACK_TRACE_ADDR_COLUMN
);
650 gtk_tree_view_column_add_attribute (column
, renderer
, "foreground",
651 STACK_TRACE_COLOR_COLUMN
);
652 gtk_tree_view_column_set_sizing (column
, GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
653 gtk_tree_view_column_set_title (column
, _("Address"));
654 gtk_tree_view_append_column (st
->treeview
, column
);
656 column
= gtk_tree_view_column_new ();
657 renderer
= gtk_cell_renderer_text_new ();
658 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
659 gtk_tree_view_column_add_attribute (column
, renderer
, "text",
660 STACK_TRACE_ARGS_COLUMN
);
661 gtk_tree_view_column_add_attribute (column
, renderer
, "foreground",
662 STACK_TRACE_COLOR_COLUMN
);
663 gtk_tree_view_column_set_sizing (column
, GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
664 gtk_tree_view_column_set_title (column
, _("Arguments"));
665 gtk_tree_view_append_column (st
->treeview
, column
);
667 /* Create popup menu */
668 ui
= anjuta_shell_get_ui (ANJUTA_PLUGIN(st
->plugin
)->shell
, NULL
);
669 st
->menu
= GTK_MENU (gtk_ui_manager_get_widget (GTK_UI_MANAGER (ui
), "/PopupStack"));
672 g_signal_connect (st
->treeview
, "button-press-event", G_CALLBACK (on_stack_trace_button_press
), st
);
673 g_signal_connect (st
->treeview
, "row-activated", G_CALLBACK (on_stack_trace_row_activated
), st
);
675 /* Add stack window */
676 st
->scrolledwindow
= gtk_scrolled_window_new (NULL
, NULL
);
677 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (st
->scrolledwindow
),
678 GTK_POLICY_AUTOMATIC
,
679 GTK_POLICY_AUTOMATIC
);
680 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (st
->scrolledwindow
),
682 gtk_container_add (GTK_CONTAINER (st
->scrolledwindow
),
683 GTK_WIDGET (st
->treeview
));
684 gtk_widget_show_all (st
->scrolledwindow
);
686 anjuta_shell_add_widget (ANJUTA_PLUGIN(st
->plugin
)->shell
,
688 "AnjutaDebuggerStack", _("Stack"),
689 "gdb-stack-icon", ANJUTA_SHELL_PLACEMENT_BOTTOM
,
695 destroy_stack_trace_gui (StackTrace
*st
)
697 if (st
->scrolledwindow
!= NULL
)
699 gtk_widget_destroy (st
->scrolledwindow
);
700 st
->scrolledwindow
= NULL
;
705 on_program_stopped (StackTrace
*self
, guint thread
)
707 self
->current_update
++;
708 dma_thread_set_stack_trace (self
, thread
);
712 on_debugger_started (StackTrace
*self
)
714 self
->current_update
= 0;
715 create_stack_trace_gui (self
);
719 on_debugger_stopped (StackTrace
*self
)
721 dma_thread_clear_all_stack_trace (self
);
722 destroy_stack_trace_gui (self
);
726 *---------------------------------------------------------------------------*/
728 /* Constructor & Destructor
729 *---------------------------------------------------------------------------*/
732 stack_trace_new (IAnjutaDebugger
*debugger
, DebugManagerPlugin
*plugin
)
737 st
= g_new0 (StackTrace
, 1);
738 if (st
== NULL
) return NULL
;
741 st
->debugger
= debugger
;
742 if (debugger
!= NULL
) g_object_ref (debugger
);
744 /* Register actions */
745 ui
= anjuta_shell_get_ui (ANJUTA_PLUGIN(st
->plugin
)->shell
, NULL
);
747 anjuta_ui_add_action_group_entries (ui
, "ActionGroupStack",
748 _("Stack frame operations"),
750 G_N_ELEMENTS (actions_stack_trace
),
751 GETTEXT_PACKAGE
, TRUE
, st
);
753 g_signal_connect_swapped (st
->debugger
, "debugger-started", G_CALLBACK (on_debugger_started
), st
);
754 g_signal_connect_swapped (st
->debugger
, "debugger-stopped", G_CALLBACK (on_debugger_stopped
), st
);
755 g_signal_connect_swapped (st
->debugger
, "program-stopped", G_CALLBACK (on_program_stopped
), st
);
756 g_signal_connect_swapped (st
->debugger
, "frame-changed", G_CALLBACK (on_frame_changed
), st
);
762 stack_trace_free (StackTrace
* st
)
766 g_return_if_fail (st
!= NULL
);
768 /* Disconnect from debugger */
769 if (st
->debugger
!= NULL
)
771 g_signal_handlers_disconnect_by_func (st
->debugger
, G_CALLBACK (on_debugger_started
), st
);
772 g_signal_handlers_disconnect_by_func (st
->debugger
, G_CALLBACK (on_debugger_stopped
), st
);
773 g_signal_handlers_disconnect_by_func (st
->debugger
, G_CALLBACK (on_program_stopped
), st
);
774 g_signal_handlers_disconnect_by_func (st
->debugger
, G_CALLBACK (on_frame_changed
), st
);
775 g_object_unref (st
->debugger
);
778 /* Remove menu actions */
779 ui
= anjuta_shell_get_ui (ANJUTA_PLUGIN (st
->plugin
)->shell
, NULL
);
780 anjuta_ui_remove_action_group (ui
, st
->action_group
);
783 destroy_stack_trace_gui (st
);