1 /*
2 * debug.c
3 *
4 * Copyright 2010 Alexander Petukhov <devel(at)apetukhov.ru>
5 *
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.
10 *
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.
15 *
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,
19 * MA 02110-1301, USA.
20 */
21
22 /*
23 * Debug activities handlers (Run, Stop, etc)
24 * Manages GUI that is debug-state dependent.
25 * Finaly, after checking current debug state - passes
26 * command to the active debug module.
27 * Also creates debug-related GUI (local, debug terminal pages)
28 * and handles run-time watches and breakpoints changes.
29 * Contains callbacks from debugger module to handle debug state changes.
30 */
31
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35
36 #include <stdio.h>
37
38 #include <stdlib.h>
39 int unlockpt(int fildes);
40 int grantpt(int fd);
41
42 #include <string.h>
43 #include <unistd.h>
44 #if defined(HAVE_UTIL_H)
45 #include <util.h>
46 #elif defined(HAVE_LIBUTIL_H)
47 #include <libutil.h>
48 #elif defined(HAVE_PTY_H)
49 #include <pty.h>
50 #endif
51 #include <gtk/gtk.h>
52 #include <gdk/gdkkeysyms.h>
53 #include <vte/vte.h>
54
55 #ifdef HAVE_CONFIG_H
56 #include "config.h"
57 #endif
58 #include <geanyplugin.h>
59 #include <gp_vtecompat.h>
60 extern GeanyData *geany_data;
61
62 #include "tpage.h"
63 #include "breakpoints.h"
64 #include "debug.h"
65 #include "utils.h"
66 #include "stree.h"
67 #include "watch_model.h"
68 #include "wtree.h"
69 #include "atree.h"
70 #include "tpage.h"
71 #include "calltip.h"
72 #include "bptree.h"
73 #include "btnpanel.h"
74 #include "dconfig.h"
75 #include "tabs.h"
76
77 /*
78 * calltip size
79 */
80 #define CALLTIP_HEIGHT 20
81 #define CALLTIP_WIDTH 200
82
83 /* module description structure (name/module pointer) */
84 typedef struct _module_description {
85 const gchar *title;
86 dbg_module *module;
87 } module_description;
88
89 /* holds current debug state */
90 enum dbs debug_state = DBS_IDLE;
91
92 /* debug modules declarations */
93 extern dbg_module dbg_module_gdb;
94 /* extern dbg_module dbg_module_bash; */
95
96 /* active debug module */
97 dbg_module *active_module = NULL;
98
99 /* Interrupt relateed data
100 * Interrtion is requested when breakpoint is set/added/removed
101 * asyncronously. Then debug_request_interrupt is called,
102 * supplied with interrupt reason (interrupt_flags),
103 * breakpoint pointer (interrupt_data) and callback to call
104 * after interruption
105 */
106 bs_callback interrupt_cb = NULL;
107 gpointer interrupt_data = NULL;
108
109 /* flag to set when debug stop is requested while debugger is running.
110 * Then this flag is set to TRUE, and debug_request_interrupt function is called
111 */
112 gboolean exit_pending = FALSE;
113
114 /* debug terminal PTY master/slave file descriptors */
115 int pty_master, pty_slave;
116
117 /* debug terminal widget */
118 GtkWidget *terminal = NULL;
119
120 /* GtkTextView to put debugger messages */
121 static GtkWidget *debugger_messages_textview = NULL;
122
123 /*
124 * Adjustments of a scroll view containing debugger messages
125 * text view. Values are changed during new text adding.
126 */
127 static GtkAdjustment *hadj = NULL;
128 static GtkAdjustment *vadj = NULL;
129
130 /* stack trace/watch/autos CtkTreeView widgets */
131 static GtkWidget *stree = NULL;
132 static GtkWidget *wtree = NULL;
133 static GtkWidget *atree = NULL;
134
135 /* watch tree view model and store */
136 GtkTreeStore *wstore = NULL;
137 GtkTreeModel *wmodel = NULL;
138
139 /* array of widgets, ti enable/disable regard of a debug state */
140 static GtkWidget **sensitive_widget[] = {&stree, &wtree, &atree, NULL};
141
142 /*
143 * current stack for holding
144 * position of ffreames markers
145 */
146 static GList* stack = NULL;
147
148 /*
149 * pages which are loaded in debugger and therefore, are set readonly
150 */
151 static GList *read_only_pages = NULL;
152
153 /* available modules */
154 static module_description modules[] =
155 {
156 { "GDB", &dbg_module_gdb },
157 { NULL, NULL }
158 };
159
160 /* calltips cache */
161 static GHashTable *calltips = NULL;
162
163 /*
164 * remove stack margin markers
165 */
remove_stack_markers(void)166 static void remove_stack_markers(void)
167 {
168 int active_frame_index = active_module->get_active_frame();
169
170 GList *iter;
171 int frame_index;
172 for (iter = stack, frame_index = 0; iter; iter = iter->next, frame_index++)
173 {
174 if (iter)
175 {
176 frame *f = (frame*)iter->data;
177 if (f->have_source)
178 {
179 if (active_frame_index == frame_index)
180 {
181 markers_remove_current_instruction(f->file, f->line);
182 }
183 else
184 {
185 markers_remove_frame(f->file, f->line);
186 }
187 }
188 }
189 }
190 }
191
192 /*
193 * add stack margin markers
194 */
add_stack_markers(void)195 static void add_stack_markers(void)
196 {
197 int active_frame_index = active_module->get_active_frame();
198
199 GList *iter;
200 int frame_index;
201 for (iter = stack, frame_index = 0; iter; iter = iter->next, frame_index++)
202 {
203 if (iter)
204 {
205 frame *f = (frame*)iter->data;
206 if (f->have_source)
207 {
208 if (active_frame_index == frame_index)
209 {
210 markers_add_current_instruction(f->file, f->line);
211 }
212 else
213 {
214 markers_add_frame(f->file, f->line);
215 }
216 }
217 }
218 }
219 }
220
221 /*
222 * Handlers for GUI maked changes in watches
223 */
224
225 /*
226 * watch expression has been changed
227 */
on_watch_changed(GtkCellRendererText * renderer,gchar * path,gchar * new_text,gpointer user_data)228 static void on_watch_changed(GtkCellRendererText *renderer, gchar *path, gchar *new_text, gpointer user_data)
229 {
230 /* get iterator to the changed row */
231 GtkTreeIter iter;
232 gchar *oldvalue;
233 gchar *internal = NULL;
234 GtkTreePath *empty_path;
235 GtkTreePath *tree_path = gtk_tree_path_new_from_string (path);
236 gboolean is_empty_row;
237 gchar *striped;
238
239 gtk_tree_model_get_iter (
240 gtk_tree_view_get_model(GTK_TREE_VIEW(wtree)),
241 &iter,
242 tree_path);
243
244 /* get oldvalue */
245 gtk_tree_model_get (
246 wmodel,
247 &iter,
248 W_NAME, &oldvalue,
249 -1);
250 gtk_tree_model_get (
251 wmodel,
252 &iter,
253 W_INTERNAL, &internal,
254 -1);
255
256 /* check if it is empty row */
257 empty_path = wtree_empty_path();
258 is_empty_row = !gtk_tree_path_compare (tree_path, empty_path);
259 gtk_tree_path_free(empty_path);
260
261 striped = g_strstrip(g_strdup(new_text));
262 if (!strlen(striped) &&
263 !is_empty_row &&
264 dialogs_show_question(_("Delete variable?")))
265 {
266 /* if new value is empty string on non-empty row
267 * offer to delete watch */
268 gtk_tree_store_remove(wstore, &iter);
269 if (DBS_STOPPED == debug_state)
270 active_module->remove_watch(internal);
271
272 config_set_debug_changed();
273 }
274 else if (strcmp(oldvalue, striped))
275 {
276 /* new value is non empty */
277
278 /* insert new row if changing was the last empty row */
279 GtkTreeIter newiter;
280 if (is_empty_row)
281 gtk_tree_store_insert_before(wstore, &newiter, NULL, &iter);
282
283 /* set expression */
284 variable_set_name_only(wstore, is_empty_row ? &newiter : &iter, striped);
285
286 /* if debug is active - remove old watch and add new one */
287 if (DBS_STOPPED == debug_state)
288 {
289 variable *newvar;
290
291 active_module->remove_watch(internal);
292 newvar = active_module->add_watch(striped);
293 change_watch(GTK_TREE_VIEW(wtree), is_empty_row ? &newiter : &iter, newvar);
294 }
295
296 /* if new watch has been added - set selection to the new created row */
297 if (is_empty_row)
298 {
299 GtkTreePath *_path = gtk_tree_model_get_path(wmodel, &newiter);
300 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(wtree));
301 gtk_tree_selection_unselect_all(selection);
302 gtk_tree_selection_select_path(selection, _path);
303 gtk_tree_path_free(_path);
304 }
305
306 config_set_debug_changed();
307 }
308
309 /* free resources */
310 gtk_tree_path_free(tree_path);
311 g_free(oldvalue);
312 g_free(internal);
313 g_free(striped);
314 }
315
316 /*
317 * text has been dragged into the watch tree view
318 */
on_watch_dragged_callback(GtkWidget * wgt,GdkDragContext * context,int x,int y,GtkSelectionData * seldata,guint info,guint _time,gpointer userdata)319 static void on_watch_dragged_callback(GtkWidget *wgt, GdkDragContext *context, int x, int y,
320 GtkSelectionData *seldata, guint info, guint _time,
321 gpointer userdata)
322 {
323 /* string that is dragged */
324 gchar *expression = (gchar*)gtk_selection_data_get_data(seldata);
325 GtkTreePath *path = NULL;
326 GtkTreeViewDropPosition pos;
327 GtkTreePath *empty_path;
328 GtkTreeIter newvar;
329
330 /* lookup for where the text has been dropped */
331 gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(wtree), x, y, &path, &pos);
332
333 /* if dropped into last row - insert before it */
334 empty_path = wtree_empty_path();
335 if (!gtk_tree_path_compare(empty_path, path))
336 pos = GTK_TREE_VIEW_DROP_BEFORE;
337 gtk_tree_path_free(empty_path);
338
339 /* if dropped into children area - insert before parent */
340 if (gtk_tree_path_get_depth(path) > 1)
341 {
342 while (gtk_tree_path_get_depth(path) > 1)
343 gtk_tree_path_up(path);
344 pos = GTK_TREE_VIEW_DROP_BEFORE;
345 }
346
347 /* insert new row */
348 if (path)
349 {
350 GtkTreeIter sibling;
351 gtk_tree_model_get_iter(wmodel, &sibling, path);
352
353 if (GTK_TREE_VIEW_DROP_BEFORE == pos || GTK_TREE_VIEW_DROP_INTO_OR_BEFORE == pos)
354 gtk_tree_store_insert_before(wstore, &newvar, NULL, &sibling);
355 else
356 gtk_tree_store_insert_after(wstore, &newvar, NULL, &sibling);
357 }
358 else
359 {
360 GtkTreeIter empty;
361
362 wtree_empty_row(&empty);
363 gtk_tree_store_insert_before(wstore, &newvar, NULL, &empty);
364 }
365
366 /* if debugger is active (in stopped condition) - add to run-time watch list
367 * if not - just set new expession in the tree view */
368 if (DBS_STOPPED == debug_state)
369 {
370 variable *var = active_module->add_watch(expression);
371 change_watch(GTK_TREE_VIEW(wtree), &newvar, var);
372 }
373 else
374 variable_set_name_only(wstore, &newvar, expression);
375
376 config_set_debug_changed();
377 }
378
379 /*
380 * key has been pressed while being in watch tree view
381 */
on_watch_key_pressed_callback(GtkWidget * widget,GdkEvent * event,gpointer user_data)382 static gboolean on_watch_key_pressed_callback(GtkWidget *widget, GdkEvent *event, gpointer user_data)
383 {
384 GtkTreeSelection *selection;
385 GList *rows;
386 GtkTreePath *empty_path;
387
388 /* handling only Delete button pressing
389 * that means "delete selected rows" */
390 if (((GdkEventKey*)event)->keyval != GDK_Delete)
391 return FALSE;
392
393 /* get selected rows */
394 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(wtree));
395 rows = gtk_tree_selection_get_selected_rows(selection, &wmodel);
396
397 /* empty row path */
398 empty_path = wtree_empty_path();
399
400 /* check whether only empty row was selected */
401 if (1 != gtk_tree_selection_count_selected_rows(selection) ||
402 (rows && gtk_tree_path_compare((GtkTreePath*)rows->data, empty_path)))
403 {
404 /* path reference to select after deleteing finishes */
405 GtkTreeRowReference *reference_to_select = NULL;
406 GtkTreePath *path_to_select;
407
408 /* get references to the rows */
409 GList *references = NULL;
410 GList *iter = rows;
411 while (iter)
412 {
413 GtkTreePath *path = (GtkTreePath*)iter->data;
414
415 /* move up paths to the root elements */
416 while (gtk_tree_path_get_depth(path) > 1)
417 gtk_tree_path_up(path);
418
419 /* add path reference if it's not an empty row*/
420 if (gtk_tree_path_compare(path, empty_path))
421 references = g_list_prepend(references, gtk_tree_row_reference_new(wmodel, path));
422
423 iter = iter->next;
424 }
425
426 /* iterate through references and remove */
427 iter = g_list_reverse(references);
428 while (iter)
429 {
430 GtkTreeRowReference *reference = (GtkTreeRowReference*)iter->data;
431 /* check for valid reference because two or more equal
432 refernces could be put in the list if several child items
433 of the same node were selected and the path for the
434 current reference was already deleted */
435 if (gtk_tree_row_reference_valid(reference))
436 {
437 GtkTreeIter titer;
438 GtkTreePath *path = gtk_tree_row_reference_get_path(reference);
439
440 if (!reference_to_select)
441 {
442 /* select upper sibling of the upper
443 selected row that has unselected upper sibling */
444 GtkTreePath *sibling = gtk_tree_path_copy(path);
445 if(gtk_tree_path_prev(sibling))
446 {
447 if (!gtk_tree_selection_path_is_selected(selection, sibling))
448 reference_to_select = gtk_tree_row_reference_new(gtk_tree_view_get_model(GTK_TREE_VIEW(wtree)), sibling);
449 }
450 else if (gtk_tree_path_next(sibling), gtk_tree_path_compare(path, sibling))
451 reference_to_select = gtk_tree_row_reference_new(gtk_tree_view_get_model(GTK_TREE_VIEW(wtree)), sibling);
452 }
453
454 /* get iterator */
455 gtk_tree_model_get_iter(wmodel, &titer, path);
456
457 /* remove from the debug session, if it's active */
458 if (DBS_STOPPED == debug_state)
459 {
460
461 gchar *internal = NULL;
462 gtk_tree_model_get (
463 wmodel,
464 &titer,
465 W_INTERNAL, &internal,
466 -1);
467
468 active_module->remove_watch(internal);
469
470 g_free(internal);
471 }
472
473
474 gtk_tree_store_remove(wstore, &titer);
475
476 gtk_tree_path_free(path);
477 }
478
479 iter = iter->next;
480 }
481
482 /* if all (with or without empty row) was selected - set empty row
483 as a path to be selected after deleting */
484 if (!reference_to_select)
485 {
486 GtkTreePath *path = wtree_empty_path();
487 reference_to_select = gtk_tree_row_reference_new (gtk_tree_view_get_model(GTK_TREE_VIEW(wtree)), path);
488 gtk_tree_path_free(path);
489 }
490
491 /* set selection */
492 gtk_tree_selection_unselect_all(selection);
493 path_to_select = gtk_tree_row_reference_get_path(reference_to_select);
494 gtk_tree_selection_select_path(selection, path_to_select);
495 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(widget), path_to_select, NULL, TRUE, 0.5, 0.5);
496 gtk_tree_path_free(path_to_select);
497
498 /* free references list */
499 g_list_foreach (references, (GFunc)gtk_tree_row_reference_free, NULL);
500 g_list_free (references);
501
502 config_set_debug_changed();
503 }
504
505 gtk_tree_path_free(empty_path);
506
507 /* free rows list */
508 g_list_foreach (rows, (GFunc)gtk_tree_path_free, NULL);
509 g_list_free (rows);
510
511 return FALSE;
512 }
513
514 /*
515 * mouse button has been pressed while being in watch(autos) tree view
516 */
on_watch_button_pressed_callback(GtkWidget * treeview,GdkEventButton * event,gpointer userdata)517 static gboolean on_watch_button_pressed_callback(GtkWidget *treeview, GdkEventButton *event, gpointer userdata)
518 {
519 if (event->type == GDK_2BUTTON_PRESS && event->button == 1)
520 {
521 GtkTreePath *path = NULL;
522 if (gtk_tree_view_get_path_at_pos(
523 GTK_TREE_VIEW(treeview),
524 (int)event->x, (int)event->y, &path, NULL, NULL, NULL))
525 {
526 gchar *expression = NULL;
527 GtkTreeIter iter;
528 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
529 gtk_tree_model_get_iter (model, &iter, path);
530
531 gtk_tree_model_get(model, &iter,
532 W_EXPRESSION, &expression,
533 -1);
534
535 if (strlen(expression))
536 {
537 GtkTreeIter newvar, empty;
538
539 wtree_empty_row(&empty);
540 gtk_tree_store_insert_before(wstore, &newvar, NULL, &empty);
541
542 /* if debugger is active (in stopped condition) - add to run-time watch list
543 * if not - just set new expession in the tree view */
544 if (DBS_STOPPED == debug_state)
545 {
546 variable *var = active_module->add_watch(expression);
547 change_watch(GTK_TREE_VIEW(wtree), &newvar, var);
548 }
549 else
550 variable_set_name_only(wstore, &newvar, expression);
551
552 config_set_debug_changed();
553 }
554
555 g_free(expression);
556 }
557 }
558
559 return FALSE;
560 }
561
562
563 /*
564 * watch that has children has been expanded
565 */
on_watch_expanded_callback(GtkTreeView * tree,GtkTreeIter * iter,GtkTreePath * path,gpointer user_data)566 static void on_watch_expanded_callback(GtkTreeView *tree, GtkTreeIter *iter, GtkTreePath *path, gpointer user_data)
567 {
568 /* get tree view model and store as it can be watch or autos tree */
569 GtkTreeModel *model = gtk_tree_view_get_model(tree);
570 GtkTreeStore *store = GTK_TREE_STORE(model);
571
572 /* get a flag indicating that item has only stub andd need to
573 * evaluate its children */
574 gboolean only_stub = FALSE;
575 gtk_tree_model_get (
576 model,
577 iter,
578 W_STUB, &only_stub,
579 -1);
580
581 if (only_stub)
582 {
583 GList *children;
584 gchar *internal;
585
586 /* if item has not been expanded before */
587 gtk_tree_model_get (
588 model,
589 iter,
590 W_INTERNAL, &internal,
591 -1);
592
593 /* get children list */
594 children = active_module->get_children(internal);
595
596 /* remove stub and add children */
597 expand_stub(tree, iter, children);
598
599 /* free children list */
600 free_variables_list(children);
601
602 /* unset W_STUB flag */
603 gtk_tree_store_set (store, iter,
604 W_STUB, FALSE,
605 -1);
606
607 g_free(internal);
608 }
609 }
610
611 /*
612 * GUI functions
613 */
614
615 /*
616 * enable/disable sensitive widgets
617 * arguments:
618 * enable - enable or disable widgets
619 */
enable_sensitive_widgets(gboolean enable)620 static void enable_sensitive_widgets(gboolean enable)
621 {
622 int i;
623 for(i = 0; sensitive_widget[i]; i++)
624 gtk_widget_set_sensitive(*sensitive_widget[i], enable);
625 }
626
627 /*
628 * Debug state changed hanflers
629 */
630
631 /*
632 * called from debug module when debugger is being run
633 */
on_debugger_run(void)634 static void on_debugger_run (void)
635 {
636 /* update debug state */
637 debug_state = DBS_RUNNING;
638
639 /* if curren instruction marker was set previously - remove it */
640 if (stack)
641 {
642 remove_stack_markers();
643 g_list_foreach(stack, (GFunc)frame_unref, NULL);
644 g_list_free(stack);
645 stack = NULL;
646
647 stree_remove_frames();
648 }
649
650 /* disable widgets */
651 enable_sensitive_widgets(FALSE);
652
653 /* update buttons panel state */
654 btnpanel_set_debug_state(debug_state);
655 }
656
657
658 /*
659 * called from debug module when debugger is being stopped
660 */
on_debugger_stopped(int thread_id)661 static void on_debugger_stopped (int thread_id)
662 {
663 GList *iter, *files, *autos, *watches;
664
665 /* update debug state */
666 debug_state = DBS_STOPPED;
667
668 /* update buttons panel state */
669 if (!interrupt_data)
670 {
671 btnpanel_set_debug_state(debug_state);
672 }
673
674 /* clear calltips cache */
675 if (calltips)
676 g_hash_table_remove_all(calltips);
677
678 /* if a stop was requested for asyncronous exiting -
679 * stop debug module and exit */
680 if (exit_pending)
681 {
682 active_module->stop();
683 exit_pending = FALSE;
684 return;
685 }
686
687 /* check for async activities pending */
688 if (interrupt_data)
689 {
690 interrupt_cb(interrupt_data);
691 interrupt_data = NULL;
692
693 active_module->resume();
694
695 return;
696 }
697
698 /* clear stack tree view */
699 stree_set_active_thread_id(thread_id);
700
701 /* get current stack trace and put in the tree view */
702 stack = active_module->get_stack();
703 stree_add (stack);
704 stree_select_first_frame(TRUE);
705
706 /* files */
707 files = active_module->get_files();
708 /* remove from list and make writable those files,
709 that are not in the current list */
710 iter = read_only_pages;
711 while (iter)
712 {
713 if (!g_list_find_custom(files, iter->data, (GCompareFunc)g_strcmp0))
714 {
715 GList *next;
716
717 /* set document writable */
718 GeanyDocument *doc = document_find_by_real_path((const gchar*)iter->data);
719 if (doc)
720 scintilla_send_message(doc->editor->sci, SCI_SETREADONLY, 0, 0);
721
722 /* free file name */
723 g_free(iter->data);
724 /* save next item pointer */
725 next = iter->next;
726 /* remove current item */
727 read_only_pages = g_list_delete_link(read_only_pages, iter);
728
729 /* set next item and continue */
730 iter = next;
731 continue;
732 }
733
734 iter = iter->next;
735 }
736 /* add to the list and make readonly those files
737 from the current list that are new */
738 iter = files;
739 while (iter)
740 {
741 if (!g_list_find_custom(read_only_pages, iter->data, (GCompareFunc)g_strcmp0))
742 {
743 /* set document readonly */
744 GeanyDocument *doc = document_find_by_real_path((const gchar*)iter->data);
745 if (doc)
746 scintilla_send_message(doc->editor->sci, SCI_SETREADONLY, 1, 0);
747
748 /* add new file to the list */
749 read_only_pages = g_list_append(read_only_pages, g_strdup((gchar*)iter->data));
750 }
751 iter = iter->next;
752 }
753 g_list_free(files);
754
755 /* autos */
756 autos = active_module->get_autos();
757 update_variables(GTK_TREE_VIEW(atree), NULL, autos);
758
759 /* watches */
760 watches = active_module->get_watches();
761 update_variables(GTK_TREE_VIEW(wtree), NULL, watches);
762
763 if (stack)
764 {
765 frame *current = (frame*)stack->data;
766
767 if (current->have_source)
768 {
769 /* open current instruction position */
770 editor_open_position(current->file, current->line);
771 }
772
773 /* add current instruction marker */
774 add_stack_markers();
775 }
776
777 /* enable widgets */
778 enable_sensitive_widgets(TRUE);
779
780 /* remove breaks readonly if current module doesn't support run-time breaks operation */
781 if (!(active_module->features & MF_ASYNC_BREAKS))
782 bptree_set_readonly(FALSE);
783 }
784
785 /*
786 * called when debugger exits
787 */
on_debugger_exited(int code)788 static void on_debugger_exited (int code)
789 {
790 GtkTextIter start, end;
791 GtkTextBuffer *buffer;
792 GList *iter;
793
794 /* remove marker for current instruction if was set */
795 if (stack)
796 {
797 remove_stack_markers();
798 g_list_foreach(stack, (GFunc)frame_unref, NULL);
799 g_list_free(stack);
800 stack = NULL;
801 }
802
803 /* clear watch page */
804 clear_watch_values(GTK_TREE_VIEW(wtree));
805
806 /* clear autos page */
807 gtk_tree_store_clear(GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(atree))));
808
809 /* clear stack trace tree */
810 stree_clear();
811
812 /* clear debug terminal */
813 vte_terminal_reset(VTE_TERMINAL(terminal), TRUE, TRUE);
814
815 /* clear debug messages window */
816 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(debugger_messages_textview));
817 gtk_text_buffer_get_bounds(buffer, &start, &end);
818 gtk_text_buffer_delete(buffer, &start, &end);
819
820 /* enable target page */
821 tpage_set_readonly(FALSE);
822
823 /* remove breaks readonly if current module doesn't support run-time breaks operation */
824 if (!(active_module->features & MF_ASYNC_BREAKS))
825 bptree_set_readonly(FALSE);
826
827 /* set files that was readonly during debug writable */
828 for (iter = read_only_pages; iter; iter = iter->next)
829 {
830 GeanyDocument *doc = document_find_by_real_path((const gchar*)iter->data);
831 if (doc)
832 scintilla_send_message(doc->editor->sci, SCI_SETREADONLY, 0, 0);
833
834 /* free file name */
835 g_free(iter->data);
836 }
837 g_list_free(read_only_pages);
838 read_only_pages = NULL;
839
840 /* clear and destroy calltips cache */
841 if (calltips)
842 {
843 g_hash_table_destroy(calltips);
844 calltips = NULL;
845 }
846
847 /* enable widgets */
848 enable_sensitive_widgets(TRUE);
849
850 /* update buttons panel state */
851 btnpanel_set_debug_state(DBS_IDLE);
852
853 /* update debug state */
854 debug_state = DBS_IDLE;
855 }
856
857 /*
858 * called from debugger module to show a message in debugger messages pane
859 */
on_debugger_message(const gchar * message,const gchar * color)860 static void on_debugger_message (const gchar* message, const gchar *color)
861 {
862 gchar *msg = g_strdup_printf("%s\n", message);
863
864 GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(debugger_messages_textview));
865
866 GtkTextIter iter;
867 gtk_text_buffer_get_end_iter(buffer, &iter);
868 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, msg, -1, color, NULL);
869
870 g_free(msg);
871
872 gtk_adjustment_set_value(vadj, gtk_adjustment_get_upper(vadj));
873 }
874
875 /*
876 * called from debugger module to clear messages tab
877 */
on_debugger_messages_clear(void)878 static void on_debugger_messages_clear (void)
879 {
880 /* clear debug messages window */
881 GtkTextIter start, end;
882 GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(debugger_messages_textview));
883 gtk_text_buffer_get_bounds(buffer, &start, &end);
884 gtk_text_buffer_delete(buffer, &start, &end);
885 }
886
887 /*
888 * called from debugger module to show an error message box
889 */
on_debugger_error(const gchar * message)890 static void on_debugger_error (const gchar* message)
891 {
892 dialogs_show_msgbox(GTK_MESSAGE_ERROR, "%s", message);
893 }
894
895 /*
896 * called from debugger module when a thead has been removed
897 */
on_thread_removed(int thread_id)898 static void on_thread_removed(int thread_id)
899 {
900 stree_remove_thread(thread_id);
901 }
902
903 /*
904 * called from debugger module when a new thead has been added
905 */
on_thread_added(int thread_id)906 static void on_thread_added (int thread_id)
907 {
908 stree_add_thread(thread_id);
909 }
910
911 /* callbacks structure to pass to debugger module */
912 dbg_callbacks callbacks = {
913 on_debugger_run,
914 on_debugger_stopped,
915 on_debugger_exited,
916 on_debugger_message,
917 on_debugger_messages_clear,
918 on_debugger_error,
919 on_thread_added,
920 on_thread_removed,
921 };
922
923 /*
924 * Interface functions
925 */
926
927 /*
928 * called when a frame in the stack tree has been selected
929 */
on_select_frame(int frame_number)930 static void on_select_frame(int frame_number)
931 {
932 GList *autos, *watches;
933 frame *f = (frame*)g_list_nth_data(stack, active_module->get_active_frame());
934 if (f)
935 {
936 markers_remove_current_instruction(f->file, f->line);
937 markers_add_frame(f->file, f->line);
938 }
939
940 active_module->set_active_frame(frame_number);
941
942 /* clear calltips cache */
943 if (calltips)
944 g_hash_table_remove_all(calltips);
945
946 /* autos */
947 autos = active_module->get_autos();
948 update_variables(GTK_TREE_VIEW(atree), NULL, autos);
949
950 /* watches */
951 watches = active_module->get_watches();
952 update_variables(GTK_TREE_VIEW(wtree), NULL, watches);
953
954 f = (frame*)g_list_nth_data(stack, frame_number);
955 if (f)
956 {
957 markers_remove_frame(f->file, f->line);
958 markers_add_current_instruction(f->file, f->line);
959 }
960 }
961
962 /*
963 * called when a thread should been selected
964 */
on_select_thread(int thread_id)965 static void on_select_thread(int thread_id)
966 {
967 gboolean success;
968
969 if (stack)
970 remove_stack_markers();
971
972 if ((success = active_module->set_active_thread(thread_id)))
973 {
974 g_list_free_full(stack, (GDestroyNotify)frame_unref);
975 stack = active_module->get_stack();
976
977 /* update the stack tree */
978 stree_remove_frames();
979 stree_set_active_thread_id(thread_id);
980 stree_add(stack);
981 stree_select_first_frame(TRUE);
982 }
983
984 if (stack)
985 add_stack_markers();
986
987 if (success)
988 on_select_frame(0);
989 }
990
991 /*
992 * init debug related GUI (watch tree view)
993 * arguments:
994 */
debug_init(void)995 void debug_init(void)
996 {
997 GtkWidget *scrollbar;
998 GtkWidget *hbox;
999 GKeyFile *config;
1000 gchar *configfile;
1001 gchar *font;
1002 GtkTextBuffer *buffer;
1003
1004 #if GTK_CHECK_VERSION(3, 0, 0)
1005 VtePty *pty;
1006 #endif
1007
1008 /* create watch page */
1009 wtree = wtree_init(on_watch_expanded_callback,
1010 on_watch_dragged_callback,
1011 on_watch_key_pressed_callback,
1012 on_watch_changed,
1013 on_watch_button_pressed_callback);
1014 wmodel = gtk_tree_view_get_model(GTK_TREE_VIEW(wtree));
1015 wstore = GTK_TREE_STORE(wmodel);
1016
1017 tab_watch = gtk_scrolled_window_new(NULL, NULL);
1018 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(tab_watch),
1019 GTK_POLICY_AUTOMATIC,
1020 GTK_POLICY_AUTOMATIC);
1021 gtk_container_add(GTK_CONTAINER(tab_watch), wtree);
1022
1023 /* create autos page */
1024 atree = atree_init(on_watch_expanded_callback, on_watch_button_pressed_callback);
1025 tab_autos = gtk_scrolled_window_new(NULL, NULL);
1026 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(tab_autos),
1027 GTK_POLICY_AUTOMATIC,
1028 GTK_POLICY_AUTOMATIC);
1029 gtk_container_add(GTK_CONTAINER(tab_autos), atree);
1030
1031 /* create stack trace page */
1032 stree = stree_init(editor_open_position, on_select_thread, on_select_frame);
1033 tab_call_stack = gtk_scrolled_window_new(NULL, NULL);
1034 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(tab_call_stack),
1035 GTK_POLICY_AUTOMATIC,
1036 GTK_POLICY_AUTOMATIC);
1037 gtk_container_add(GTK_CONTAINER(tab_call_stack), stree);
1038
1039 /* create debug terminal page */
1040 terminal = vte_terminal_new();
1041 /* create PTY */
1042 openpty(&pty_master, &pty_slave, NULL,
1043 NULL,
1044 NULL);
1045 grantpt(pty_master);
1046 unlockpt(pty_master);
1047 #if GTK_CHECK_VERSION(3, 0, 0)
1048 pty = vte_pty_new_foreign_sync(pty_master, NULL, NULL);
1049 vte_terminal_set_pty(VTE_TERMINAL(terminal), pty);
1050 g_object_unref(pty);
1051 scrollbar = gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL, gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(terminal)));
1052 #else
1053 vte_terminal_set_pty(VTE_TERMINAL(terminal), pty_master);
1054 scrollbar = gtk_vscrollbar_new(GTK_ADJUSTMENT(VTE_TERMINAL(terminal)->adjustment));
1055 #endif
1056 gtk_widget_set_can_focus(GTK_WIDGET(scrollbar), FALSE);
1057 tab_terminal = gtk_frame_new(NULL);
1058 gtk_frame_set_shadow_type (GTK_FRAME(tab_terminal), GTK_SHADOW_NONE);
1059 #if GTK_CHECK_VERSION(3, 0, 0)
1060 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
1061 #else
1062 hbox = gtk_hbox_new(FALSE, 0);
1063 #endif
1064 gtk_container_add(GTK_CONTAINER(tab_terminal), hbox);
1065 gtk_box_pack_start(GTK_BOX(hbox), terminal, TRUE, TRUE, 0);
1066 gtk_box_pack_start(GTK_BOX(hbox), scrollbar, FALSE, FALSE, 0);
1067 /* set the default widget size first to prevent VTE expanding too much,
1068 * sometimes causing the hscrollbar to be too big or out of view. */
1069 gtk_widget_set_size_request(GTK_WIDGET(terminal), 10, 10);
1070 vte_terminal_set_size(VTE_TERMINAL(terminal), 30, 1);
1071 /* set terminal font. */
1072 config = g_key_file_new();
1073 configfile = g_strconcat(geany_data->app->configdir, G_DIR_SEPARATOR_S, "geany.conf", NULL);
1074 g_key_file_load_from_file(config, configfile, G_KEY_FILE_NONE, NULL);
1075 font = utils_get_setting_string(config, "VTE", "font", "Monospace 10");
1076 vte_terminal_set_font_from_string (VTE_TERMINAL(terminal), font);
1077
1078 /* debug messages page */
1079 tab_messages = gtk_scrolled_window_new(NULL, NULL);
1080 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(tab_messages),
1081 GTK_POLICY_AUTOMATIC,
1082 GTK_POLICY_AUTOMATIC);
1083 hadj = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(tab_messages));
1084 vadj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(tab_messages));
1085
1086 debugger_messages_textview = gtk_text_view_new();
1087 gtk_text_view_set_editable (GTK_TEXT_VIEW (debugger_messages_textview), FALSE);
1088 #if GTK_CHECK_VERSION(3, 0, 0)
1089 gtk_container_add(GTK_CONTAINER(tab_messages), debugger_messages_textview);
1090 #else
1091 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(tab_messages), debugger_messages_textview);
1092 #endif
1093
1094 /* create tex tags */
1095 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(debugger_messages_textview));
1096 gtk_text_buffer_create_tag(buffer, "black", "foreground", "#000000", NULL);
1097 gtk_text_buffer_create_tag(buffer, "grey", "foreground", "#AAAAAA", NULL);
1098 gtk_text_buffer_create_tag(buffer, "red", "foreground", "#FF0000", NULL);
1099 gtk_text_buffer_create_tag(buffer, "green", "foreground", "#00FF00", NULL);
1100 gtk_text_buffer_create_tag(buffer, "blue", "foreground", "#0000FF", NULL);
1101 gtk_text_buffer_create_tag(buffer, "yellow", "foreground", "#FFFF00", NULL);
1102 gtk_text_buffer_create_tag(buffer, "brown", "foreground", "#BB8915", NULL);
1103 gtk_text_buffer_create_tag(buffer, "rose", "foreground", "#BA92B7", NULL);
1104 }
1105
1106 /*
1107 * called when plugin is being unloaded to remove current instruction marker
1108 */
debug_destroy(void)1109 void debug_destroy(void)
1110 {
1111 /* close PTY file descriptors */
1112 close(pty_master);
1113 close(pty_slave);
1114
1115 /* remove stack markers if present */
1116 if (stack)
1117 {
1118 remove_stack_markers();
1119 g_list_foreach(stack, (GFunc)frame_unref, NULL);
1120 g_list_free(stack);
1121 stack = NULL;
1122 }
1123
1124 stree_destroy();
1125 }
1126
1127 /*
1128 * gets current debug state
1129 */
debug_get_state(void)1130 enum dbs debug_get_state(void)
1131 {
1132 return debug_state;
1133 }
1134
1135 /*
1136 * gets current stack frames lisy
1137 */
debug_get_stack(void)1138 GList* debug_get_stack(void)
1139 {
1140 return stack;
1141 }
1142
1143 /*
1144 * gets debug module index from name
1145 * arguments:
1146 * modulename - debug module name
1147 */
debug_get_module_index(const gchar * modulename)1148 int debug_get_module_index(const gchar *modulename)
1149 {
1150 int _index = 0;
1151 while (modules[_index].title)
1152 {
1153 if (!strcmp(modules[_index].title, modulename))
1154 return _index;
1155 _index++;
1156 }
1157
1158 return -1;
1159 }
1160
1161 /*
1162 * gets GList with all debug modules pointers
1163 */
debug_get_modules(void)1164 GList* debug_get_modules(void)
1165 {
1166 GList *mods = NULL;
1167 module_description *desc = modules;
1168 while (desc->title)
1169 {
1170 mods = g_list_prepend(mods, (gpointer)desc->title);
1171 desc++;
1172 }
1173
1174 return g_list_reverse(mods);
1175 }
1176
1177 /*
1178 * checks whether currently active debug module supports asyncronous breaks
1179 */
debug_supports_async_breaks(void)1180 gboolean debug_supports_async_breaks(void)
1181 {
1182 return active_module->features & MF_ASYNC_BREAKS;
1183 }
1184
1185 /*
1186 * starts or continues debug process
1187 */
debug_run(void)1188 void debug_run(void)
1189 {
1190 if (DBS_IDLE == debug_state)
1191 {
1192 gchar *target, *commandline;
1193 GList *env, *watches, *breaks;
1194
1195 target = g_strstrip(tpage_get_target());
1196 if (!strlen(target))
1197 {
1198 g_free(target);
1199 return;
1200 }
1201 commandline = tpage_get_commandline();
1202 env = tpage_get_environment();
1203 watches = get_root_items(GTK_TREE_VIEW(wtree));
1204 breaks = breaks_get_all();
1205
1206 /* init selected debugger module */
1207 active_module = modules[tpage_get_debug_module_index()].module;
1208 if(active_module->run(target, commandline, env, watches, breaks, ttyname(pty_slave), &callbacks))
1209 {
1210 /* set target page - readonly */
1211 tpage_set_readonly(TRUE);
1212
1213 /* update debuf state */
1214 debug_state = DBS_RUN_REQUESTED;
1215 }
1216
1217 /* free stuff */
1218 g_free(target);
1219 g_free(commandline);
1220
1221 g_list_foreach(env, (GFunc)g_free, NULL);
1222 g_list_free(env);
1223
1224 g_list_foreach(watches, (GFunc)g_free, NULL);
1225 g_list_free(watches);
1226
1227 g_list_free(breaks);
1228 }
1229 else if (DBS_STOPPED == debug_state)
1230 {
1231 /* resume */
1232 active_module->resume();
1233 debug_state = DBS_RUN_REQUESTED;
1234 }
1235
1236 /* set breaks readonly if current module doesn't support run-time breaks operation */
1237 if (!(active_module->features & MF_ASYNC_BREAKS))
1238 bptree_set_readonly(TRUE);
1239 }
1240
1241 /*
1242 * restarts debug process
1243 */
debug_restart(void)1244 void debug_restart(void)
1245 {
1246 if (DBS_STOPPED == debug_state)
1247 {
1248 /* stop instantly if not running */
1249 vte_terminal_reset(VTE_TERMINAL(terminal), TRUE, TRUE);
1250 active_module->restart();
1251 debug_state = DBS_RUN_REQUESTED;
1252 }
1253 }
1254
1255 /*
1256 * stops debug process
1257 */
debug_stop(void)1258 void debug_stop(void)
1259 {
1260 if (DBS_STOPPED == debug_state)
1261 {
1262 /* stop instantly if not running */
1263 active_module->stop();
1264 debug_state = DBS_STOP_REQUESTED;
1265 }
1266 else if (DBS_IDLE != debug_state)
1267 {
1268 /* if running - request interrupt */
1269 exit_pending = TRUE;
1270 active_module->request_interrupt();
1271 }
1272 }
1273
1274 /*
1275 * step over
1276 */
debug_step_over(void)1277 void debug_step_over(void)
1278 {
1279 if (DBS_STOPPED == debug_state)
1280 active_module->step_over();
1281 }
1282
1283 /*
1284 * step into
1285 */
debug_step_into(void)1286 void debug_step_into(void)
1287 {
1288 if (DBS_STOPPED == debug_state)
1289 active_module->step_into();
1290 }
1291
1292 /*
1293 * step out
1294 */
debug_step_out(void)1295 void debug_step_out(void)
1296 {
1297 if (DBS_STOPPED == debug_state)
1298 active_module->step_out();
1299 }
1300
1301 /*
1302 * step to position
1303 */
debug_execute_until(const gchar * file,int line)1304 void debug_execute_until(const gchar *file, int line)
1305 {
1306 if (DBS_STOPPED == debug_state)
1307 active_module->execute_until(file, line);
1308 }
1309
1310 /*
1311 * sets a break
1312 * arguments:
1313 * bp - breakpoitn to set
1314 * bsa - what to do with breakpoint (add/remove/change)
1315 */
debug_set_break(breakpoint * bp,break_set_activity bsa)1316 gboolean debug_set_break(breakpoint* bp, break_set_activity bsa)
1317 {
1318 if (DBS_STOPPED == debug_state)
1319 {
1320 return active_module->set_break(bp, bsa);
1321 }
1322 return FALSE;
1323 }
1324
1325 /*
1326 * removes a break
1327 * arguments:
1328 * bp - breakpoitn to set
1329 */
debug_remove_break(breakpoint * bp)1330 gboolean debug_remove_break(breakpoint* bp)
1331 {
1332 if (DBS_STOPPED == debug_state)
1333 {
1334 return active_module->remove_break(bp);
1335 }
1336 return FALSE;
1337 }
1338
1339 /*
1340 * requests active debug module to interrupt fo further
1341 * breakpoint modifications
1342 * arguments:
1343 * cb - callback to call on interruption happents
1344 * bp - breakpoint to deal with
1345 * flags - whar to do with breakpoint
1346 */
debug_request_interrupt(bs_callback cb,gpointer data)1347 void debug_request_interrupt(bs_callback cb, gpointer data)
1348 {
1349 interrupt_cb = cb;
1350 interrupt_data = data;
1351
1352 active_module->request_interrupt();
1353 }
1354
1355 /*
1356 * gets debug modules error message
1357 */
debug_error_message(void)1358 gchar* debug_error_message(void)
1359 {
1360 return active_module->error_message();
1361 }
1362
1363 /*
1364 * evaluates expression in runtime and returns its value or NULL if unevaluatable
1365 */
debug_evaluate_expression(gchar * expression)1366 gchar* debug_evaluate_expression(gchar *expression)
1367 {
1368 return active_module->evaluate_expression(expression);
1369 }
1370
1371 /*
1372 * return list of strings for the calltip
1373 * first line is a header, others should be shifted right with tab
1374 */
debug_get_calltip_for_expression(gchar * expression)1375 gchar* debug_get_calltip_for_expression(gchar* expression)
1376 {
1377 gchar *calltip = NULL;
1378 if (!calltips || !(calltip = g_hash_table_lookup(calltips, expression)))
1379 {
1380 GString *calltip_str = NULL;
1381 variable *var = active_module->add_watch(expression);
1382 if (var)
1383 {
1384 calltip_str = get_calltip_line(var, TRUE);
1385 if (calltip_str)
1386 {
1387 if (var->has_children)
1388 {
1389 int lines_left = MAX_CALLTIP_HEIGHT - 1;
1390 GList* children = active_module->get_children(var->internal->str);
1391 GList* child = children;
1392 while(child && lines_left)
1393 {
1394 variable *varchild = (variable*)child->data;
1395 GString *child_string = get_calltip_line(varchild, FALSE);
1396 g_string_append_printf(calltip_str, "\n%s", child_string->str);
1397 g_string_free(child_string, TRUE);
1398
1399 child = child->next;
1400 lines_left--;
1401 }
1402 if (!lines_left && child)
1403 {
1404 g_string_append(calltip_str, "\n\t\t........");
1405 }
1406 g_list_foreach(children, (GFunc)variable_free, NULL);
1407 g_list_free(children);
1408 }
1409 calltip = g_string_free(calltip_str, FALSE);
1410 }
1411
1412 active_module->remove_watch(var->internal->str);
1413
1414 if (!calltips)
1415 {
1416 calltips = g_hash_table_new_full(g_str_hash, g_str_equal, (GDestroyNotify)g_free, (GDestroyNotify)g_free);
1417 }
1418 g_hash_table_insert(calltips, g_strdup(expression), calltip);
1419 }
1420 }
1421
1422 return calltip;
1423 }
1424
1425 /*
1426 * check whether source for the current instruction
1427 * is avaiable
1428 */
debug_current_instruction_have_sources(void)1429 gboolean debug_current_instruction_have_sources(void)
1430 {
1431 frame *current = (frame*)stack->data;
1432 return current->have_source ? strlen(current->file) : 0;
1433 }
1434
1435 /*
1436 * opens position according to the current instruction
1437 */
debug_jump_to_current_instruction(void)1438 void debug_jump_to_current_instruction(void)
1439 {
1440 frame *current = (frame*)stack->data;
1441 editor_open_position(current->file, current->line);
1442 }
1443
1444 /*
1445 * called from the document open callback to set file
1446 * readonly if debug is active and file is a debugging source file
1447 */
debug_on_file_open(GeanyDocument * doc)1448 void debug_on_file_open(GeanyDocument *doc)
1449 {
1450 const gchar *file = DOC_FILENAME(doc);
1451 if (g_list_find_custom(read_only_pages, (gpointer)file, (GCompareFunc)g_strcmp0))
1452 scintilla_send_message(doc->editor->sci, SCI_SETREADONLY, 1, 0);
1453 }
1454
1455 /*
1456 * get active frame index
1457 */
debug_get_active_frame(void)1458 int debug_get_active_frame(void)
1459 {
1460 return active_module->get_active_frame();
1461 }
1462