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 "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>
37 #include <libgnomevfs/gnome-vfs-utils.h>
39 #include "utilities.h"
43 #define ANJUTA_PIXMAP_POINTER PACKAGE_PIXMAPS_DIR"/pointer.png"
45 typedef struct _DmaThreadStackTrace
50 } DmaThreadStackTrace
;
54 DebugManagerPlugin
*plugin
;
55 DmaDebuggerQueue
*debugger
;
57 GtkActionGroup
*action_group
;
59 DmaThreadStackTrace
* current
;
65 GtkTreeView
*treeview
;
67 GtkWidget
*scrolledwindow
;
71 STACK_TRACE_ACTIVE_COLUMN
,
72 STACK_TRACE_FRAME_COLUMN
,
73 STACK_TRACE_FILE_COLUMN
,
74 STACK_TRACE_LINE_COLUMN
,
75 STACK_TRACE_FUNC_COLUMN
,
76 STACK_TRACE_ADDR_COLUMN
,
77 STACK_TRACE_ARGS_COLUMN
,
78 STACK_TRACE_URI_COLUMN
,
79 STACK_TRACE_COLOR_COLUMN
,
84 *---------------------------------------------------------------------------*/
87 get_current_iter (GtkTreeView
*view
, GtkTreeIter
* iter
)
89 GtkTreeSelection
*selection
;
91 selection
= gtk_tree_view_get_selection (view
);
92 return gtk_tree_selection_get_selected (selection
, NULL
, iter
);
96 * returns the current stack frame or -1 on error
99 get_current_index (StackTrace
* st
)
103 if (get_current_iter (st
->treeview
, &iter
))
108 model
= gtk_tree_view_get_model (st
->treeview
);
109 gtk_tree_model_get (model
, &iter
, STACK_TRACE_FRAME_COLUMN
, &frame_no
, -1);
120 my_gtk_tree_model_get_iter_last(GtkTreeModel
*model
, GtkTreeIter
*last
)
125 exist
= gtk_tree_model_get_iter_first(model
, &iter
);
126 if (!exist
) return FALSE
;
131 exist
= gtk_tree_model_iter_next(model
, &iter
);
139 my_gtk_tree_model_iter_prev(GtkTreeModel
*model
, GtkTreeIter
*iter
)
144 path
= gtk_tree_model_get_path (model
, iter
);
145 exist
= gtk_tree_path_prev (path
);
148 exist
= gtk_tree_model_get_iter (model
, iter
, path
);
150 gtk_tree_path_free (path
);
156 my_gtk_tree_iter_compare(GtkTreeModel
*model
, GtkTreeIter
*itera
, GtkTreeIter
*iterb
)
162 patha
= gtk_tree_model_get_path (model
, itera
);
163 pathb
= gtk_tree_model_get_path (model
, iterb
);
165 comp
= gtk_tree_path_compare (patha
, pathb
);
167 gtk_tree_path_free (patha
);
168 gtk_tree_path_free (pathb
);
174 *---------------------------------------------------------------------------*/
177 on_clear_stack_trace (gpointer data
, gpointer user_data
)
179 DmaThreadStackTrace
*trace
= (DmaThreadStackTrace
*) data
;
181 g_object_unref (G_OBJECT (trace
->model
));
186 dma_thread_clear_all_stack_trace (StackTrace
*self
)
188 /* Clear all GtkListStore */
189 g_list_foreach (self
->list
, (GFunc
)on_clear_stack_trace
, NULL
);
190 g_list_free (self
->list
);
192 self
->current
= NULL
;
197 on_stack_trace_updated (const GList
*stack
, gpointer user_data
, GError
*error
)
199 StackTrace
*self
= (StackTrace
*)user_data
;
206 if (error
!= NULL
) return;
208 model
= GTK_LIST_STORE (self
->current
->model
);
210 pic
= gdk_pixbuf_new_from_file (ANJUTA_PIXMAP_POINTER
, NULL
);
212 exist
= my_gtk_tree_model_get_iter_last (GTK_TREE_MODEL (model
), &iter
);
214 for (node
= (const GList
*)g_list_last((GList
*)stack
); node
!= NULL
; node
= node
->prev
)
216 IAnjutaDebuggerFrame
*frame
;
221 frame
= (IAnjutaDebuggerFrame
*)node
->data
;
225 /* Check if it's the same stack frame */
232 gtk_tree_model_get (GTK_TREE_MODEL (model
), &iter
,
233 STACK_TRACE_ADDR_COLUMN
, &adr
,
234 STACK_TRACE_LINE_COLUMN
, &line
,
235 STACK_TRACE_ARGS_COLUMN
, &args
,
237 address
= adr
!= NULL
? strtoul (adr
, NULL
, 0) : 0;
238 same
= (address
== frame
->address
) && (line
== frame
->line
);
239 if ((args
== NULL
) || (frame
->args
== NULL
))
241 same
= same
&& (args
== frame
->args
);
245 same
= same
&& (strcmp (args
, frame
->args
) == 0);
252 /* Same frame, just change the color */
253 gtk_list_store_set (model
, &iter
,
254 STACK_TRACE_ACTIVE_COLUMN
, frame
->level
== self
->current_frame
? pic
: NULL
,
255 STACK_TRACE_FRAME_COLUMN
, frame
->level
,
256 STACK_TRACE_COLOR_COLUMN
, "black", -1);
258 /* Check previous frame */
259 exist
= my_gtk_tree_model_iter_prev (GTK_TREE_MODEL (model
), &iter
);
260 if (!exist
|| (node
->prev
!= NULL
))
262 /* Last frame or Upper frame still exist */
265 /* Upper frame do not exist, remove all them */
268 /* New frame, remove all previous frame */
271 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model
), &first
);
272 while (my_gtk_tree_iter_compare (GTK_TREE_MODEL (model
), &first
, &iter
) < 0)
274 gtk_list_store_remove (model
, &first
);
276 gtk_list_store_remove (model
, &first
);
288 gtk_list_store_prepend (model
, &iter
);
290 adr
= g_strdup_printf ("0x%lx", frame
->address
);
293 if (g_path_is_absolute (frame
->file
))
295 uri
= gnome_vfs_get_uri_from_local_path(frame
->file
);
296 file
= strrchr(frame
->file
, G_DIR_SEPARATOR
) + 1;
307 file
= frame
->library
;
310 gtk_list_store_set(model
, &iter
,
311 STACK_TRACE_ACTIVE_COLUMN
, frame
->level
== self
->current_frame
? pic
: NULL
,
312 STACK_TRACE_FRAME_COLUMN
, frame
->level
,
313 STACK_TRACE_FILE_COLUMN
, file
,
314 STACK_TRACE_LINE_COLUMN
, frame
->line
,
315 STACK_TRACE_FUNC_COLUMN
, frame
->function
,
316 STACK_TRACE_ADDR_COLUMN
, adr
,
317 STACK_TRACE_ARGS_COLUMN
, frame
->args
,
318 STACK_TRACE_URI_COLUMN
, uri
,
319 STACK_TRACE_COLOR_COLUMN
, "red",
324 gdk_pixbuf_unref (pic
);
328 static DmaThreadStackTrace
*
329 dma_thread_create_new_stack_trace (StackTrace
*self
, gint thread
)
331 DmaThreadStackTrace
*trace
;
334 /* Create new list store */
335 store
= gtk_list_store_new (STACK_TRACE_N_COLUMNS
,
346 trace
= g_new (DmaThreadStackTrace
, 1);
347 trace
->thread
= thread
;
348 trace
->model
= GTK_TREE_MODEL (store
);
349 trace
->last_update
= self
->current_update
;
351 self
->current
= trace
;
353 /* Ask debugger to get all frame data */
354 dma_queue_list_frame (
356 (IAnjutaDebuggerCallback
)on_stack_trace_updated
,
359 self
->list
= g_list_append (self
->list
, trace
);
364 static DmaThreadStackTrace
*
365 dma_thread_update_stack_trace (StackTrace
*self
, DmaThreadStackTrace
*trace
)
367 trace
->last_update
= self
->current_update
;
369 /* Ask debugger to get all frame data */
370 dma_queue_list_frame (
372 (IAnjutaDebuggerCallback
)on_stack_trace_updated
,
379 on_find_stack_trace (gconstpointer a
, gconstpointer b
)
381 const DmaThreadStackTrace
*trace
= (const DmaThreadStackTrace
*)a
;
382 guint thread
= (gint
)b
;
384 return trace
->thread
!= thread
;
388 dma_thread_set_stack_trace (StackTrace
*self
, gint thread
)
391 DmaThreadStackTrace
*trace
;
393 if ((self
->current
== NULL
) || (self
->current
->thread
!= thread
) || (self
->current
->last_update
!= self
->current_update
))
395 self
->current_frame
= 0;
397 list
= g_list_find_custom (self
->list
, (gconstpointer
) thread
, on_find_stack_trace
);
401 /* Create new stack trace */
402 trace
= dma_thread_create_new_stack_trace(self
, thread
);
406 trace
= (DmaThreadStackTrace
*)list
->data
;
407 self
->current
= trace
;
409 if (trace
->last_update
!= self
->current_update
)
411 /* Update stack trace */
412 dma_thread_update_stack_trace (self
, trace
);
415 gtk_tree_view_set_model (self
->treeview
, trace
->model
);
419 /* Callback functions
420 *---------------------------------------------------------------------------*/
423 on_frame_changed (StackTrace
*self
, guint frame
, gint thread
)
429 dma_thread_set_stack_trace (self
, thread
);
432 self
->current_frame
= frame
;
434 model
= self
->current
->model
;
436 /* Clear old pointer */
437 if(gtk_tree_model_get_iter_first (model
, &iter
))
441 /* clear pixmap on the previous active frame */
442 gtk_list_store_set (GTK_LIST_STORE (model
), &iter
,
443 STACK_TRACE_ACTIVE_COLUMN
, NULL
, -1);
444 } while (gtk_tree_model_iter_next (model
, &iter
));
447 /* Set pointer to current frame */
448 if (gtk_tree_model_iter_nth_child (model
, &iter
, NULL
, self
->current_frame
))
450 GdkPixbuf
*pointer_pix
= gdk_pixbuf_new_from_file (ANJUTA_PIXMAP_POINTER
, NULL
);
452 /* set pointer on this frame */
453 gtk_list_store_set (GTK_LIST_STORE(model
), &iter
,
454 STACK_TRACE_ACTIVE_COLUMN
, pointer_pix
,
456 gdk_pixbuf_unref (pointer_pix
);
461 on_stack_frame_set_activate (GtkAction
*action
, gpointer user_data
)
464 guint selected_frame
;
466 st
= (StackTrace
*) user_data
;
468 selected_frame
= get_current_index (st
);
470 /* No frame selected */
471 if (selected_frame
== -1)
474 /* current frame is already active */
475 if (selected_frame
== st
->current_frame
)
478 /* issue a command to switch active frame to new location */
479 dma_queue_set_frame (st
->debugger
, selected_frame
);
483 on_stack_view_source_activate (GtkAction
*action
, gpointer user_data
)
486 GtkTreeSelection
*selection
;
494 StackTrace
* st
= (StackTrace
*) user_data
;
497 selection
= gtk_tree_view_get_selection (view
);
498 if (!gtk_tree_selection_get_selected (selection
, &model
, &iter
))
501 /* get the frame info */
502 gtk_tree_model_get (model
, &iter
,
503 STACK_TRACE_URI_COLUMN
, &uri
,
504 STACK_TRACE_LINE_COLUMN
, &line
,
505 STACK_TRACE_ADDR_COLUMN
, &adr
,
508 address
= adr
!= NULL
? strtoul (adr
, NULL
, 0) : 0;
509 g_signal_emit_by_name (st
->plugin
, "location-changed", address
, uri
, line
);
515 on_stack_trace_row_activated (GtkTreeView
*treeview
,
517 GtkTreeViewColumn
*arg2
,
520 on_stack_frame_set_activate (NULL
, st
);
524 on_stack_trace_button_press (GtkWidget
*widget
, GdkEventButton
*bevent
, gpointer user_data
)
526 StackTrace
*st
= (StackTrace
*) user_data
;
528 if ((bevent
->type
== GDK_BUTTON_PRESS
) && (bevent
->button
== 3))
530 /* Right mouse click */
531 g_return_val_if_fail (st
->menu
!= NULL
, FALSE
);
532 gtk_menu_popup (GTK_MENU (st
->menu
), NULL
, NULL
, NULL
, NULL
,
533 bevent
->button
, bevent
->time
);
535 else if ((bevent
->type
== GDK_2BUTTON_PRESS
) && (bevent
->button
== 1))
537 /* Double left mouse click */
538 on_stack_view_source_activate (NULL
, user_data
);
545 *---------------------------------------------------------------------------*/
547 static GtkActionEntry actions_stack_trace
[] = {
549 "ActionDmaSetCurrentFrame", /* Action name */
550 NULL
, /* Stock icon, if any */
551 N_("Set current frame"), /* Display label */
552 NULL
, /* short-cut */
554 G_CALLBACK (on_stack_frame_set_activate
) /* action callback */
557 "ActionDmaJumpToFrame",
562 G_CALLBACK (on_stack_view_source_activate
)
567 create_stack_trace_gui(StackTrace
*st
)
570 GtkTreeSelection
*selection
;
571 GtkTreeViewColumn
*column
;
572 GtkCellRenderer
*renderer
;
575 g_return_if_fail (st
->scrolledwindow
== NULL
);
577 /* Create tree view */
578 model
= GTK_TREE_MODEL(gtk_list_store_new (STACK_TRACE_N_COLUMNS
,
588 st
->treeview
= GTK_TREE_VIEW (gtk_tree_view_new_with_model (model
));
589 g_object_unref (G_OBJECT (model
));
591 selection
= gtk_tree_view_get_selection (st
->treeview
);
592 gtk_tree_selection_set_mode (selection
, GTK_SELECTION_SINGLE
);
595 column
= gtk_tree_view_column_new ();
596 gtk_tree_view_column_set_sizing (column
, GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
597 gtk_tree_view_column_set_title (column
, _("Active"));
598 renderer
= gtk_cell_renderer_pixbuf_new ();
599 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
600 gtk_tree_view_column_add_attribute (column
, renderer
, "pixbuf",
601 STACK_TRACE_ACTIVE_COLUMN
);
602 gtk_tree_view_append_column (st
->treeview
, column
);
603 gtk_tree_view_set_expander_column (st
->treeview
,
606 column
= gtk_tree_view_column_new ();
607 gtk_tree_view_column_set_sizing (column
, GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
608 gtk_tree_view_column_set_title (column
, _("Frame"));
609 renderer
= gtk_cell_renderer_text_new ();
610 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
611 gtk_tree_view_column_add_attribute (column
, renderer
, "text",
612 STACK_TRACE_FRAME_COLUMN
);
613 gtk_tree_view_column_add_attribute (column
, renderer
, "foreground",
614 STACK_TRACE_COLOR_COLUMN
);
615 gtk_tree_view_column_set_sizing (column
, GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
616 gtk_tree_view_append_column (st
->treeview
, column
);
617 gtk_tree_view_set_expander_column (st
->treeview
,
620 column
= gtk_tree_view_column_new ();
621 renderer
= gtk_cell_renderer_text_new ();
622 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
623 gtk_tree_view_column_add_attribute (column
, renderer
, "text",
624 STACK_TRACE_FILE_COLUMN
);
625 gtk_tree_view_column_add_attribute (column
, renderer
, "foreground",
626 STACK_TRACE_COLOR_COLUMN
);
627 gtk_tree_view_column_set_sizing (column
, GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
628 gtk_tree_view_column_set_title (column
, _("File"));
629 gtk_tree_view_append_column (st
->treeview
, column
);
631 column
= gtk_tree_view_column_new ();
632 renderer
= gtk_cell_renderer_text_new ();
633 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
634 gtk_tree_view_column_add_attribute (column
, renderer
, "text",
635 STACK_TRACE_LINE_COLUMN
);
636 gtk_tree_view_column_add_attribute (column
, renderer
, "foreground",
637 STACK_TRACE_COLOR_COLUMN
);
638 gtk_tree_view_column_set_sizing (column
, GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
639 gtk_tree_view_column_set_title (column
, _("Line"));
640 gtk_tree_view_append_column (st
->treeview
, column
);
642 column
= gtk_tree_view_column_new ();
643 renderer
= gtk_cell_renderer_text_new ();
644 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
645 gtk_tree_view_column_add_attribute (column
, renderer
, "text",
646 STACK_TRACE_FUNC_COLUMN
);
647 gtk_tree_view_column_add_attribute (column
, renderer
, "foreground",
648 STACK_TRACE_COLOR_COLUMN
);
649 gtk_tree_view_column_set_sizing (column
, GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
650 gtk_tree_view_column_set_title (column
, _("Function"));
651 gtk_tree_view_append_column (st
->treeview
, column
);
653 if (dma_debugger_queue_is_supported (st
->debugger
, HAS_MEMORY
))
655 /* Display address only if debugger has such concept */
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_ADDR_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
, _("Address"));
665 gtk_tree_view_append_column (st
->treeview
, column
);
668 column
= gtk_tree_view_column_new ();
669 renderer
= gtk_cell_renderer_text_new ();
670 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
671 gtk_tree_view_column_add_attribute (column
, renderer
, "text",
672 STACK_TRACE_ARGS_COLUMN
);
673 gtk_tree_view_column_add_attribute (column
, renderer
, "foreground",
674 STACK_TRACE_COLOR_COLUMN
);
675 gtk_tree_view_column_set_sizing (column
, GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
676 gtk_tree_view_column_set_title (column
, _("Arguments"));
677 gtk_tree_view_append_column (st
->treeview
, column
);
679 /* Create popup menu */
680 ui
= anjuta_shell_get_ui (ANJUTA_PLUGIN(st
->plugin
)->shell
, NULL
);
681 st
->menu
= GTK_MENU (gtk_ui_manager_get_widget (GTK_UI_MANAGER (ui
), "/PopupStack"));
684 g_signal_connect (st
->treeview
, "button-press-event", G_CALLBACK (on_stack_trace_button_press
), st
);
685 g_signal_connect (st
->treeview
, "row-activated", G_CALLBACK (on_stack_trace_row_activated
), st
);
687 /* Add stack window */
688 st
->scrolledwindow
= gtk_scrolled_window_new (NULL
, NULL
);
689 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (st
->scrolledwindow
),
690 GTK_POLICY_AUTOMATIC
,
691 GTK_POLICY_AUTOMATIC
);
692 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (st
->scrolledwindow
),
694 gtk_container_add (GTK_CONTAINER (st
->scrolledwindow
),
695 GTK_WIDGET (st
->treeview
));
696 gtk_widget_show_all (st
->scrolledwindow
);
698 anjuta_shell_add_widget (ANJUTA_PLUGIN(st
->plugin
)->shell
,
700 "AnjutaDebuggerStack", _("Stack"),
701 "gdb-stack-icon", ANJUTA_SHELL_PLACEMENT_BOTTOM
,
707 destroy_stack_trace_gui (StackTrace
*st
)
709 if (st
->scrolledwindow
!= NULL
)
711 gtk_widget_destroy (st
->scrolledwindow
);
712 st
->scrolledwindow
= NULL
;
717 on_program_moved (StackTrace
*self
, guint pid
, gint thread
)
719 self
->current_update
++;
720 dma_thread_set_stack_trace (self
, thread
);
724 on_program_exited (StackTrace
*self
)
726 g_signal_handlers_disconnect_by_func (self
->plugin
, G_CALLBACK (on_program_exited
), self
);
727 g_signal_handlers_disconnect_by_func (self
->plugin
, G_CALLBACK (on_program_moved
), self
);
728 g_signal_handlers_disconnect_by_func (self
->plugin
, G_CALLBACK (on_frame_changed
), self
);
730 dma_thread_clear_all_stack_trace (self
);
731 destroy_stack_trace_gui (self
);
735 on_program_started (StackTrace
*self
)
737 self
->current_update
= 0;
738 create_stack_trace_gui (self
);
740 g_signal_connect_swapped (self
->plugin
, "program-exited", G_CALLBACK (on_program_exited
), self
);
741 g_signal_connect_swapped (self
->plugin
, "program-moved", G_CALLBACK (on_program_moved
), self
);
742 g_signal_connect_swapped (self
->plugin
, "frame-changed", G_CALLBACK (on_frame_changed
), self
);
746 *---------------------------------------------------------------------------*/
748 /* Constructor & Destructor
749 *---------------------------------------------------------------------------*/
752 stack_trace_new (DebugManagerPlugin
*plugin
)
757 st
= g_new0 (StackTrace
, 1);
758 if (st
== NULL
) return NULL
;
761 st
->debugger
= dma_debug_manager_get_queue (plugin
);
763 /* Register actions */
764 ui
= anjuta_shell_get_ui (ANJUTA_PLUGIN(st
->plugin
)->shell
, NULL
);
766 anjuta_ui_add_action_group_entries (ui
, "ActionGroupStack",
767 _("Stack frame operations"),
769 G_N_ELEMENTS (actions_stack_trace
),
770 GETTEXT_PACKAGE
, TRUE
, st
);
772 g_signal_connect_swapped (st
->plugin
, "program-started", G_CALLBACK (on_program_started
), st
);
778 stack_trace_free (StackTrace
* st
)
782 g_return_if_fail (st
!= NULL
);
784 /* Disconnect from debugger */
785 g_signal_handlers_disconnect_matched (st
->plugin
, G_SIGNAL_MATCH_DATA
, 0, 0, NULL
, NULL
, st
);
787 /* Remove menu actions */
788 ui
= anjuta_shell_get_ui (ANJUTA_PLUGIN (st
->plugin
)->shell
, NULL
);
789 anjuta_ui_remove_action_group (ui
, st
->action_group
);
792 destroy_stack_trace_gui (st
);