1 /*
2 * dbm_gdm.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 * Implementation of struct _dbg_module for GDB
24 */
25
26 #include <string.h>
27 #include <stdlib.h>
28 #include <ctype.h>
29 #include <wctype.h>
30 #include <unistd.h>
31
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35 #include <geanyplugin.h>
36 extern GeanyData *geany_data;
37
38 #include "breakpoint.h"
39 #include "debug_module.h"
40 #include "gdb_mi.h"
41
42 /* module features */
43 #define MODULE_FEATURES MF_ASYNC_BREAKS
44
45 /* GDB spawn flags */
46 #define GDB_SPAWN_FLAGS \
47 G_SPAWN_SEARCH_PATH | \
48 G_SPAWN_DO_NOT_REAP_CHILD
49
50 /* GDB prompt */
51 #define GDB_PROMPT "(gdb) \n"
52
53 /* enumeration for GDB command execution status */
54 typedef enum _result_class {
55 RC_DONE,
56 RC_EXIT,
57 RC_ERROR
58 } result_class;
59
60 /* structure to keep async command data (command line, messages) */
61 typedef struct _queue_item {
62 gchar *message;
63 gchar *command;
64 gchar *error_message;
65 gboolean format_error_message;
66 } queue_item;
67
68 /* enumeration for stop reason */
69 enum sr {
70 SR_BREAKPOINT_HIT,
71 SR_END_STEPPING_RANGE,
72 SR_EXITED_NORMALLY,
73 SR_SIGNAL_RECIEVED,
74 SR_EXITED_SIGNALLED,
75 SR_EXITED_WITH_CODE,
76 } stop_reason;
77
78 /* callbacks to use for messaging, error reporting and state change alerting */
79 static dbg_callbacks* dbg_cbs;
80
81 /* GDB command line arguments*/
82 static const gchar *gdb_args[] = { "gdb", "-i=mi", NULL };
83
84 /* GDB pid*/
85 static GPid gdb_pid = 0;
86
87 /* target pid*/
88 static GPid target_pid = 0;
89
90 /* GSource to watch GDB exit */
91 static guint gdb_src_id;
92
93 /* channels for GDB input/output */
94 static gint gdb_in;
95 static gint gdb_out;
96 static GIOChannel *gdb_ch_in;
97 static GIOChannel *gdb_ch_out;
98
99 /* GDB output event source id */
100 static guint gdb_id_out;
101
102 /* buffer for the error message */
103 char err_message[1000];
104
105 /* flag, showing that on debugger stop we have to call a callback */
106 gboolean requested_interrupt = FALSE;
107
108 /* autos list */
109 static GList *autos = NULL;
110
111 /* watches list */
112 static GList *watches = NULL;
113
114 /* loaded files list */
115 static GList *files = NULL;
116
117 /* set to true if library was loaded/unloaded
118 and it's nessesary to refresh files list */
119 static gboolean file_refresh_needed = FALSE;
120
121 /* current frame number */
122 static int active_frame = 0;
123
124 /* forward declarations */
125 static void stop(void);
126 static variable* add_watch(gchar* expression);
127 static void update_watches(void);
128 static void update_autos(void);
129 static void update_files(void);
130
131 /*
132 * print message using color, based on message type
133 */
colorize_message(gchar * message)134 static void colorize_message(gchar *message)
135 {
136 const gchar *color;
137 if ('=' == *message)
138 color = "rose";
139 else if ('^' == *message)
140 color = "brown";
141 else if ('*' == *message)
142 color = "blue";
143 else if ('~' == *message)
144 color = "grey";
145 else
146 color = "red";
147
148 dbg_cbs->send_message(message, color);
149 }
150
151 /*
152 * shutdown GIOChannel
153 */
shutdown_channel(GIOChannel ** ch)154 static void shutdown_channel(GIOChannel ** ch)
155 {
156 if (*ch)
157 {
158 gint fd = g_io_channel_unix_get_fd(*ch);
159 g_io_channel_shutdown(*ch, TRUE, NULL);
160 g_io_channel_unref(*ch);
161 *ch = NULL;
162 if (fd >= 0)
163 {
164 close(fd);
165 }
166 }
167 }
168
169 /*
170 * called on GDB exit
171 */
on_gdb_exit(GPid pid,gint status,gpointer data)172 static void on_gdb_exit(GPid pid, gint status, gpointer data)
173 {
174 gdb_pid = target_pid = 0;
175 g_spawn_close_pid(pid);
176 shutdown_channel(&gdb_ch_in);
177 shutdown_channel(&gdb_ch_out);
178
179 /* delete autos */
180 g_list_foreach(autos, (GFunc)g_free, NULL);
181 g_list_free(autos);
182 autos = NULL;
183
184 /* delete watches */
185 g_list_foreach(watches, (GFunc)g_free, NULL);
186 g_list_free(watches);
187 watches = NULL;
188
189 /* delete files */
190 g_list_foreach(files, (GFunc)g_free, NULL);
191 g_list_free(files);
192 files = NULL;
193
194 g_source_remove(gdb_src_id);
195 gdb_src_id = 0;
196
197 dbg_cbs->set_exited(0);
198 }
199
200 /*
201 * reads gdb_out until "(gdb)" prompt met
202 */
read_until_prompt(void)203 static GList* read_until_prompt(void)
204 {
205 GList *lines = NULL;
206
207 gchar *line = NULL;
208 gsize terminator;
209 while (G_IO_STATUS_NORMAL == g_io_channel_read_line(gdb_ch_out, &line, NULL, &terminator, NULL))
210 {
211 if (!strcmp(GDB_PROMPT, line))
212 break;
213
214 line[terminator] = '\0';
215 lines = g_list_prepend (lines, line);
216 }
217
218 return g_list_reverse(lines);
219 }
220
221 /*
222 * write a command to a gdb channel and flush with a newlinw character
223 */
gdb_input_write_line(const gchar * line)224 static void gdb_input_write_line(const gchar *line)
225 {
226 GIOStatus st;
227 GError *err = NULL;
228 gsize count;
229 const char *p;
230 char command[1000];
231 g_snprintf(command, sizeof command, "%s\n", line);
232
233 for (p = command; *p; p += count)
234 {
235 st = g_io_channel_write_chars(gdb_ch_in, p, strlen(p), &count, &err);
236 if (err || (st == G_IO_STATUS_ERROR) || (st == G_IO_STATUS_EOF))
237 {
238 if (err)
239 {
240 #ifdef DEBUG_OUTPUT
241 dbg_cbs->send_message(err->message, "red");
242 #endif
243 g_clear_error(&err);
244 }
245 break;
246 }
247 }
248
249 st = g_io_channel_flush(gdb_ch_in, &err);
250 if (err || (st == G_IO_STATUS_ERROR) || (st == G_IO_STATUS_EOF))
251 {
252 if (err)
253 {
254 #ifdef DEBUG_OUTPUT
255 dbg_cbs->send_message(err->message, "red");
256 #endif
257 g_clear_error(&err);
258 }
259 }
260 }
261
262 /*
263 * free memory occupied by a queue item
264 */
free_queue_item(queue_item * item)265 static void free_queue_item(queue_item *item)
266 {
267 g_free(item->message);
268 g_free(item->command);
269 g_free(item->error_message);
270 g_free(item);
271 }
272
273 /*
274 * free a list of "queue_item" structures
275 */
free_commands_queue(GList * queue)276 static void free_commands_queue(GList *queue)
277 {
278 /* all commands completed */
279 queue = g_list_first(queue);
280 g_list_foreach(queue, (GFunc)free_queue_item, NULL);
281 g_list_free(queue);
282 }
283
284 /*
285 * add a new command ("queue_item" structure) to a list
286 */
add_to_queue(GList * queue,const gchar * message,const gchar * command,const gchar * error_message,gboolean format_error_message)287 static GList* add_to_queue(GList* queue, const gchar *message, const gchar *command, const gchar *error_message, gboolean format_error_message)
288 {
289 queue_item *item = (queue_item*)g_malloc(sizeof(queue_item));
290
291 memset((void*)item, 0, sizeof(queue_item));
292
293 item->message = g_strdup(message);
294 item->command = g_strdup(command);
295 item->error_message = g_strdup(error_message);
296 item->format_error_message = format_error_message;
297
298 return g_list_append(queue, (gpointer)item);
299 }
300
301 /*
302 * asyncronous output reader
303 * reads from startup async commands.
304 * looks for a command completion (normal or abnormal), if noraml - executes next command
305 */
306 static void exec_async_command(const gchar* command);
on_read_async_output(GIOChannel * src,GIOCondition cond,gpointer data)307 static gboolean on_read_async_output(GIOChannel * src, GIOCondition cond, gpointer data)
308 {
309 gchar *line;
310 gsize length;
311 struct gdb_mi_record *record;
312
313 if (G_IO_STATUS_NORMAL != g_io_channel_read_line(src, &line, NULL, &length, NULL))
314 return TRUE;
315
316 record = gdb_mi_record_parse(line);
317
318 if (record && record->type == '^')
319 {
320 /* got some result */
321
322 GList *lines;
323 GList *commands = (GList*)data;
324
325 if (gdb_id_out)
326 {
327 g_source_remove(gdb_id_out);
328 gdb_id_out = 0;
329 }
330
331 lines = read_until_prompt();
332 g_list_foreach(lines, (GFunc)g_free, NULL);
333 g_list_free (lines);
334
335 if (!strcmp(record->klass, "done"))
336 {
337 /* command completed succesfully - run next command if exists */
338 if (commands->next)
339 {
340 /* if there are commads left */
341 queue_item *item;
342
343 commands = commands->next;
344 item = (queue_item*)commands->data;
345
346 /* send message to debugger messages window */
347 if (item->message)
348 {
349 dbg_cbs->send_message(item->message, "grey");
350 }
351
352 gdb_input_write_line(item->command);
353
354 gdb_id_out = g_io_add_watch(gdb_ch_out, G_IO_IN, on_read_async_output, commands);
355 }
356 else
357 {
358 /* all commands completed */
359 free_commands_queue(commands);
360
361 /* removing read callback */
362 if (gdb_id_out)
363 {
364 g_source_remove(gdb_id_out);
365 gdb_id_out = 0;
366 }
367
368 /* update source files list */
369 update_files();
370
371 /* -exec-run */
372 exec_async_command("-exec-run");
373 }
374 }
375 else
376 {
377 queue_item *item = (queue_item*)commands->data;
378 if(item->error_message)
379 {
380 if (item->format_error_message)
381 {
382 const gchar* gdb_msg = gdb_mi_result_var(record->first, "msg", GDB_MI_VAL_STRING);
383 gchar *msg = g_strdup_printf(item->error_message, gdb_msg);
384
385 dbg_cbs->report_error(msg);
386 g_free(msg);
387 }
388 else
389 {
390 dbg_cbs->report_error(item->error_message);
391 }
392 }
393
394 /* free commands queue */
395 free_commands_queue(commands);
396
397 stop();
398 }
399 }
400
401 gdb_mi_record_free(record);
402 g_free(line);
403
404 return TRUE;
405 }
406
407 /*
408 * asyncronous gdb output reader
409 * looks for a stopped event, then notifies "debug" module and removes async handler
410 */
411 enum dbs debug_get_state(void);
on_read_from_gdb(GIOChannel * src,GIOCondition cond,gpointer data)412 static gboolean on_read_from_gdb(GIOChannel * src, GIOCondition cond, gpointer data)
413 {
414 gchar *line;
415 gsize length;
416 const gchar *id;
417 struct gdb_mi_record *record;
418
419 if (G_IO_STATUS_NORMAL != g_io_channel_read_line(src, &line, NULL, &length, NULL))
420 return TRUE;
421
422 record = gdb_mi_record_parse(line);
423
424 if (! record || record->type != GDB_MI_TYPE_PROMPT)
425 {
426 line[length] = '\0';
427 if ((record && '~' == record->type) || '~' == line[0])
428 {
429 colorize_message(line);
430 }
431 else
432 {
433 gchar *compressed = g_strcompress(line);
434 colorize_message(compressed);
435 g_free(compressed);
436 }
437 }
438
439 if (! record)
440 {
441 g_free(line);
442 return TRUE;
443 }
444
445 if (!target_pid &&
446 /* FIXME: =thread-group-created doesn't seem to exist, at least not in latest GDB docs */
447 (gdb_mi_record_matches(record, '=', "thread-group-created", "id", &id, NULL) ||
448 gdb_mi_record_matches(record, '=', "thread-group-started", "pid", &id, NULL)))
449 {
450 target_pid = atoi(id);
451 }
452 else if (gdb_mi_record_matches(record, '=', "thread-created", "id", &id, NULL))
453 {
454 dbg_cbs->add_thread(atoi(id));
455 }
456 else if (gdb_mi_record_matches(record, '=', "thread-exited", "id", &id, NULL))
457 {
458 dbg_cbs->remove_thread(atoi(id));
459 }
460 else if (gdb_mi_record_matches(record, '=', "library-loaded", NULL) ||
461 gdb_mi_record_matches(record, '=', "library-unloaded", NULL))
462 {
463 file_refresh_needed = TRUE;
464 }
465 else if (gdb_mi_record_matches(record, '*', "running", NULL))
466 dbg_cbs->set_run();
467 else if (gdb_mi_record_matches(record, '*', "stopped", NULL))
468 {
469 const gchar *reason;
470
471 /* removing read callback (will pulling all output left manually) */
472 if (gdb_id_out)
473 {
474 g_source_remove(gdb_id_out);
475 gdb_id_out = 0;
476 }
477
478 /* looking for a reason to stop */
479 if ((reason = gdb_mi_result_var(record->first, "reason", GDB_MI_VAL_STRING)) != NULL)
480 {
481 if (!strcmp(reason, "breakpoint-hit"))
482 stop_reason = SR_BREAKPOINT_HIT;
483 else if (!strcmp(reason, "end-stepping-range"))
484 stop_reason = SR_END_STEPPING_RANGE;
485 else if (!strcmp(reason, "signal-received"))
486 stop_reason = SR_SIGNAL_RECIEVED;
487 else if (!strcmp(reason, "exited-normally"))
488 stop_reason = SR_EXITED_NORMALLY;
489 else if (!strcmp(reason, "exited-signalled"))
490 stop_reason = SR_EXITED_SIGNALLED;
491 else if (!strcmp(reason, "exited"))
492 stop_reason = SR_EXITED_WITH_CODE;
493 /* FIXME: handle "location-reached" */
494 }
495 else
496 {
497 /* somehow, sometimes there can be no stop reason */
498 stop_reason = SR_EXITED_NORMALLY;
499 }
500
501 if (SR_BREAKPOINT_HIT == stop_reason || SR_END_STEPPING_RANGE == stop_reason || SR_SIGNAL_RECIEVED == stop_reason)
502 {
503 const gchar *thread_id = gdb_mi_result_var(record->first, "thread-id", GDB_MI_VAL_STRING);
504
505 active_frame = 0;
506
507 if (SR_BREAKPOINT_HIT == stop_reason || SR_END_STEPPING_RANGE == stop_reason)
508 {
509 /* update autos */
510 update_autos();
511
512 /* update watches */
513 update_watches();
514
515 /* update files */
516 if (file_refresh_needed)
517 {
518 update_files();
519 file_refresh_needed = FALSE;
520 }
521 }
522 else
523 {
524 if (!requested_interrupt)
525 {
526 gchar *msg = g_strdup_printf(_("Program received signal %s (%s)"),
527 (gchar *) gdb_mi_result_var(record->first, "signal-name", GDB_MI_VAL_STRING),
528 (gchar *) gdb_mi_result_var(record->first, "signal-meaning", GDB_MI_VAL_STRING));
529
530 dbg_cbs->report_error(msg);
531 g_free(msg);
532 }
533 else
534 requested_interrupt = FALSE;
535 }
536
537 dbg_cbs->set_stopped(thread_id ? atoi(thread_id) : 0);
538 }
539 else if (stop_reason == SR_EXITED_NORMALLY || stop_reason == SR_EXITED_SIGNALLED || stop_reason == SR_EXITED_WITH_CODE)
540 {
541 if (stop_reason == SR_EXITED_WITH_CODE)
542 {
543 const gchar *exit_code = gdb_mi_result_var(record->first, "exit-code", GDB_MI_VAL_STRING);
544 long int code = exit_code ? strtol(exit_code, NULL, 8) : 0;
545 gchar *message;
546
547 message = g_strdup_printf(_("Program exited with code \"%i\""), (int)(char)code);
548 dbg_cbs->report_error(message);
549
550 g_free(message);
551 }
552
553 stop();
554 }
555 }
556 else if (gdb_mi_record_matches(record, '^', "error", NULL))
557 {
558 GList *lines, *iter;
559 const gchar *msg = gdb_mi_result_var(record->first, "msg", GDB_MI_VAL_STRING);
560
561 /* removing read callback (will pulling all output left manually) */
562 if (gdb_id_out)
563 {
564 g_source_remove(gdb_id_out);
565 gdb_id_out = 0;
566 }
567
568 /* set debugger stopped if is running */
569 if (DBS_STOPPED != debug_get_state())
570 {
571 /* FIXME: does GDB/MI ever return a thread-id with an error?? */
572 const gchar *thread_id = gdb_mi_result_var(record->first, "thread-id", GDB_MI_VAL_STRING);
573
574 dbg_cbs->set_stopped(thread_id ? atoi(thread_id) : 0);
575 }
576
577 /* reading until prompt */
578 lines = read_until_prompt();
579 for (iter = lines; iter; iter = iter->next)
580 {
581 gchar *l = (gchar*)iter->data;
582 if (strcmp(l, GDB_PROMPT))
583 colorize_message(l);
584 g_free(l);
585 }
586 g_list_free (lines);
587
588 /* send error message */
589 dbg_cbs->report_error(msg);
590 }
591
592 g_free(line);
593 gdb_mi_record_free(record);
594
595 return TRUE;
596 }
597
598 /*
599 * execute "command" asyncronously
600 * after writing command to an input channel
601 * connects reader to output channel and exits
602 * after execution
603 */
exec_async_command(const gchar * command)604 static void exec_async_command(const gchar* command)
605 {
606 #ifdef DEBUG_OUTPUT
607 dbg_cbs->send_message(command, "red");
608 #endif
609
610 gdb_input_write_line(command);
611
612 /* connect read callback to the output chanel */
613 gdb_id_out = g_io_add_watch(gdb_ch_out, G_IO_IN, on_read_from_gdb, NULL);
614 }
615
616 /*
617 * execute "command" syncronously
618 * i.e. reading output right
619 * after execution
620 */
exec_sync_command(const gchar * command,gboolean wait4prompt,struct gdb_mi_record ** command_record)621 static result_class exec_sync_command(const gchar* command, gboolean wait4prompt, struct gdb_mi_record ** command_record)
622 {
623 GList *lines, *iter;
624 result_class rc;
625
626 #ifdef DEBUG_OUTPUT
627 dbg_cbs->send_message(command, "red");
628 #endif
629
630 /* write command to gdb input channel */
631 gdb_input_write_line(command);
632
633 if (!wait4prompt)
634 return RC_DONE;
635
636 if (command_record)
637 *command_record = NULL;
638
639 lines = read_until_prompt();
640
641 #ifdef DEBUG_OUTPUT
642 for (iter = lines; iter; iter = iter->next)
643 {
644 dbg_cbs->send_message((gchar*)iter->data, "red");
645 }
646 #endif
647
648 rc = RC_ERROR;
649
650 for (iter = lines; iter; iter = iter->next)
651 {
652 gchar *line = (gchar*)iter->data;
653 struct gdb_mi_record *record = gdb_mi_record_parse(line);
654
655 if (record && '^' == record->type)
656 {
657 if (gdb_mi_record_matches(record, '^', "done", NULL))
658 rc = RC_DONE;
659 else if (gdb_mi_record_matches(record, '^', "error", NULL))
660 {
661 /* save error message */
662 const gchar *msg = gdb_mi_result_var(record->first, "msg", GDB_MI_VAL_STRING);
663 strncpy(err_message, msg ? msg : "", G_N_ELEMENTS(err_message) - 1);
664
665 rc = RC_ERROR;
666 }
667 else if (gdb_mi_record_matches(record, '^', "exit", NULL))
668 rc = RC_EXIT;
669
670 if (command_record)
671 {
672 *command_record = record;
673 record = NULL;
674 }
675 }
676 else if (! record || '&' != record->type)
677 {
678 colorize_message (line);
679 }
680 gdb_mi_record_free(record);
681 }
682
683 g_list_foreach(lines, (GFunc)g_free, NULL);
684 g_list_free(lines);
685
686 return rc;
687 }
688
689
690 /* escapes @str so it is valid to put it inside a quoted argument
691 * escapes '\' and '"'
692 * unlike g_strescape(), it doesn't escape non-ASCII characters so keeps
693 * all of UTF-8 */
escape_string(const gchar * str)694 static gchar *escape_string(const gchar *str)
695 {
696 gchar *new = g_malloc(strlen(str) * 2 + 1);
697 gchar *p;
698
699 for (p = new; *str; str++) {
700 switch (*str) {
701 /* FIXME: what to do with '\n'? can't seem to find a way to escape it */
702 case '\\':
703 case '"':
704 *p++ = '\\';
705 /* fallthrough */
706 default:
707 *p++ = *str;
708 }
709 }
710 *p = 0;
711
712 return new;
713 }
714
715 /*
716 * starts gdb, collects commands and start the first one
717 */
run(const gchar * file,const gchar * commandline,GList * env,GList * witer,GList * biter,const gchar * terminal_device,dbg_callbacks * callbacks)718 static gboolean run(const gchar* file, const gchar* commandline, GList* env, GList *witer, GList *biter, const gchar* terminal_device, dbg_callbacks* callbacks)
719 {
720 const gchar *exclude[] = { "LANG", NULL };
721 gchar **gdb_env = utils_copy_environment(exclude, "LANG", "C", NULL);
722 gchar *working_directory = g_path_get_dirname(file);
723 GList *lines, *iter;
724 GList *commands = NULL;
725 gchar *command;
726 gchar *escaped;
727 int bp_index;
728 queue_item *item;
729
730 dbg_cbs = callbacks;
731
732 /* spawn GDB */
733 if (!g_spawn_async_with_pipes(working_directory, (gchar**)gdb_args, gdb_env,
734 GDB_SPAWN_FLAGS, NULL,
735 NULL, &gdb_pid, &gdb_in, &gdb_out, NULL, NULL))
736 {
737 dbg_cbs->report_error(_("Failed to spawn gdb process"));
738 g_free(working_directory);
739 g_strfreev(gdb_env);
740 return FALSE;
741 }
742 g_free(working_directory);
743 g_strfreev(gdb_env);
744
745 /* move gdb to it's own process group */
746 setpgid(gdb_pid, 0);
747
748 /* set handler for gdb process exit event */
749 gdb_src_id = g_child_watch_add(gdb_pid, on_gdb_exit, NULL);
750
751 /* create GDB GIO chanels */
752 gdb_ch_in = g_io_channel_unix_new(gdb_in);
753 gdb_ch_out = g_io_channel_unix_new(gdb_out);
754
755 /* reading starting gdb messages */
756 lines = read_until_prompt();
757 for (iter = lines; iter; iter = iter->next)
758 {
759 gchar *unescaped = g_strcompress((gchar*)iter->data);
760 if (strlen(unescaped))
761 {
762 colorize_message((gchar*)iter->data);
763 }
764 }
765 g_list_foreach(lines, (GFunc)g_free, NULL);
766 g_list_free(lines);
767
768 /* add initial watches to the list */
769 while (witer)
770 {
771 gchar *name = (gchar*)witer->data;
772
773 variable *var = variable_new(name, VT_WATCH);
774 watches = g_list_append(watches, var);
775
776 witer = witer->next;
777 }
778
779 /* collect commands */
780
781 /* loading file */
782 escaped = escape_string(file);
783 command = g_strdup_printf("-file-exec-and-symbols \"%s\"", escaped);
784 commands = add_to_queue(commands, _("~\"Loading target file.\\n\""), command, _("Error loading file"), FALSE);
785 g_free(command);
786 g_free(escaped);
787
788 /* setting asyncronous mode */
789 commands = add_to_queue(commands, NULL, "-gdb-set target-async 1", _("Error configuring GDB"), FALSE);
790
791 /* setting null-stop array printing */
792 commands = add_to_queue(commands, NULL, "-interpreter-exec console \"set print null-stop\"", _("Error configuring GDB"), FALSE);
793
794 /* enable pretty printing */
795 commands = add_to_queue(commands, NULL, "-enable-pretty-printing", _("Error configuring GDB"), FALSE);
796
797 /* set locale */
798 command = g_strdup_printf("-gdb-set environment LANG=%s", g_getenv("LANG"));
799 commands = add_to_queue(commands, NULL, command, NULL, FALSE);
800 g_free(command);
801
802 /* set arguments */
803 command = g_strdup_printf("-exec-arguments %s", commandline);
804 commands = add_to_queue(commands, NULL, command, NULL, FALSE);
805 g_free(command);
806
807 /* set passed evironment */
808 iter = env;
809 while (iter)
810 {
811 gchar *name, *value;
812
813 name = (gchar*)iter->data;
814 iter = iter->next;
815 value = (gchar*)iter->data;
816
817 command = g_strdup_printf("-gdb-set environment %s=%s", name, value);
818 commands = add_to_queue(commands, NULL, command, NULL, FALSE);
819 g_free(command);
820
821 iter = iter->next;
822 }
823
824 /* set breaks */
825 bp_index = 1;
826 while (biter)
827 {
828 breakpoint *bp = (breakpoint*)biter->data;
829 gchar *error_message;
830
831 escaped = escape_string(bp->file);
832 command = g_strdup_printf("-break-insert -f \"\\\"%s\\\":%i\"", escaped, bp->line);
833 g_free(escaped);
834
835 error_message = g_strdup_printf(_("Breakpoint at %s:%i cannot be set\nDebugger message: %s"), bp->file, bp->line, "%s");
836
837 commands = add_to_queue(commands, NULL, command, error_message, TRUE);
838
839 g_free(command);
840
841 if (bp->hitscount)
842 {
843 command = g_strdup_printf("-break-after %i %i", bp_index, bp->hitscount);
844 commands = add_to_queue(commands, NULL, command, error_message, TRUE);
845 g_free(command);
846 }
847 if (strlen(bp->condition))
848 {
849 command = g_strdup_printf ("-break-condition %i %s", bp_index, bp->condition);
850 commands = add_to_queue(commands, NULL, command, error_message, TRUE);
851 g_free(command);
852 }
853 if (!bp->enabled)
854 {
855 command = g_strdup_printf ("-break-disable %i", bp_index);
856 commands = add_to_queue(commands, NULL, command, error_message, TRUE);
857 g_free(command);
858 }
859
860 g_free(error_message);
861
862 bp_index++;
863 biter = biter->next;
864 }
865
866 /* set debugging terminal */
867 command = g_strconcat("-inferior-tty-set ", terminal_device, NULL);
868 commands = add_to_queue(commands, NULL, command, NULL, FALSE);
869 g_free(command);
870
871 /* connect read callback to the output chanel */
872 gdb_id_out = g_io_add_watch(gdb_ch_out, G_IO_IN, on_read_async_output, commands);
873
874 item = (queue_item*)commands->data;
875
876 /* send message to debugger messages window */
877 if (item->message)
878 {
879 dbg_cbs->send_message(item->message, "grey");
880 }
881
882 /* send first command */
883 gdb_input_write_line(item->command);
884
885 return TRUE;
886 }
887
888 /*
889 * starts debugging
890 */
restart(void)891 static void restart(void)
892 {
893 dbg_cbs->clear_messages();
894 exec_async_command("-exec-run");
895 }
896
897 /*
898 * stops GDB
899 */
stop(void)900 static void stop(void)
901 {
902 exec_sync_command("-gdb-exit", FALSE, NULL);
903 }
904
905 /*
906 * resumes GDB
907 */
resume(void)908 static void resume(void)
909 {
910 exec_async_command("-exec-continue");
911 }
912
913 /*
914 * step over
915 */
step_over(void)916 static void step_over(void)
917 {
918 exec_async_command("-exec-next");
919 }
920
921 /*
922 * step into
923 */
step_into(void)924 static void step_into(void)
925 {
926 exec_async_command("-exec-step");
927 }
928
929 /*
930 * step out
931 */
step_out(void)932 static void step_out(void)
933 {
934 exec_async_command("-exec-finish");
935 }
936
937 /*
938 * execute until
939 */
execute_until(const gchar * file,int line)940 static void execute_until(const gchar *file, int line)
941 {
942 gchar command[1000];
943 g_snprintf(command, sizeof command, "-exec-until %s:%i", file, line);
944 exec_async_command(command);
945 }
946
947 /*
948 * gets breakpoint number by file and line
949 */
get_break_number(char * file,int line)950 static int get_break_number(char* file, int line)
951 {
952 struct gdb_mi_record *record;
953 const struct gdb_mi_result *table, *body, *bkpt;
954 int break_number = -1;
955
956 exec_sync_command("-break-list", TRUE, &record);
957 if (! record)
958 return -1;
959
960 table = gdb_mi_result_var(record->first, "BreakpointTable", GDB_MI_VAL_LIST);
961 body = gdb_mi_result_var(table, "body", GDB_MI_VAL_LIST);
962 gdb_mi_result_foreach_matched (bkpt, body, "bkpt", GDB_MI_VAL_LIST)
963 {
964 const gchar *number = gdb_mi_result_var(bkpt->val->v.list, "number", GDB_MI_VAL_STRING);
965 const gchar *location = gdb_mi_result_var(bkpt->val->v.list, "original-location", GDB_MI_VAL_STRING);
966 const gchar *colon;
967 gboolean break_found = FALSE;
968
969 if (! number || ! location)
970 continue;
971
972 colon = strrchr(location, ':');
973 if (colon && atoi(colon + 1) == line)
974 {
975 gchar *fname;
976
977 /* quotes around filename (location not found or something?) */
978 if (*location == '"' && colon - location > 2)
979 fname = g_strndup(location + 1, colon - location - 2);
980 else
981 fname = g_strndup(location, colon - location);
982 break_found = strcmp(fname, file) == 0;
983 g_free(fname);
984 }
985 if (break_found)
986 {
987 break_number = atoi(number);
988 break;
989 }
990 }
991
992 gdb_mi_record_free(record);
993
994 return break_number;
995 }
996
997 /*
998 * set breakpoint
999 */
set_break(breakpoint * bp,break_set_activity bsa)1000 static gboolean set_break(breakpoint* bp, break_set_activity bsa)
1001 {
1002 char command[1000];
1003 if (BSA_NEW_BREAK == bsa)
1004 {
1005 /* new breakpoint */
1006 struct gdb_mi_record *record;
1007 const struct gdb_mi_result *bkpt;
1008 const gchar *number;
1009 gchar *escaped;
1010 int num = 0;
1011
1012 /* 1. insert breakpoint */
1013 escaped = escape_string(bp->file);
1014 g_snprintf(command, sizeof command, "-break-insert \"\\\"%s\\\":%i\"", escaped, bp->line);
1015 if (RC_DONE != exec_sync_command(command, TRUE, &record) || !record)
1016 {
1017 gdb_mi_record_free(record);
1018 record = NULL;
1019 g_snprintf(command, sizeof command, "-break-insert -f \"\\\"%s\\\":%i\"", escaped, bp->line);
1020 if (RC_DONE != exec_sync_command(command, TRUE, &record) || !record)
1021 {
1022 gdb_mi_record_free(record);
1023 g_free(escaped);
1024 return FALSE;
1025 }
1026 }
1027 /* lookup break-number */
1028 bkpt = gdb_mi_result_var(record->first, "bkpt", GDB_MI_VAL_LIST);
1029 if ((number = gdb_mi_result_var(bkpt, "number", GDB_MI_VAL_STRING)))
1030 num = atoi(number);
1031 gdb_mi_record_free(record);
1032 g_free(escaped);
1033 /* 2. set hits count if differs from 0 */
1034 if (bp->hitscount)
1035 {
1036 g_snprintf(command, sizeof command, "-break-after %i %i", num, bp->hitscount);
1037 exec_sync_command(command, TRUE, NULL);
1038 }
1039 /* 3. set condition if exists */
1040 if (strlen(bp->condition))
1041 {
1042 g_snprintf(command, sizeof command, "-break-condition %i %s", num, bp->condition);
1043 if (RC_DONE != exec_sync_command(command, TRUE, NULL))
1044 return FALSE;
1045 }
1046 /* 4. disable if disabled */
1047 if (!bp->enabled)
1048 {
1049 g_snprintf(command, sizeof command, "-break-disable %i", num);
1050 exec_sync_command(command, TRUE, NULL);
1051 }
1052
1053 return TRUE;
1054 }
1055 else
1056 {
1057 /* modify existing breakpoint */
1058 int bnumber = get_break_number(bp->file, bp->line);
1059 if (-1 == bnumber)
1060 return FALSE;
1061
1062 if (BSA_UPDATE_ENABLE == bsa)
1063 g_snprintf(command, sizeof command, bp->enabled ? "-break-enable %i" : "-break-disable %i", bnumber);
1064 else if (BSA_UPDATE_HITS_COUNT == bsa)
1065 g_snprintf(command, sizeof command, "-break-after %i %i", bnumber, bp->hitscount);
1066 else if (BSA_UPDATE_CONDITION == bsa)
1067 g_snprintf(command, sizeof command, "-break-condition %i %s", bnumber, bp->condition);
1068
1069 return RC_DONE == exec_sync_command(command, TRUE, NULL);
1070 }
1071
1072 return FALSE;
1073 }
1074
1075 /*
1076 * removes breakpoint
1077 */
remove_break(breakpoint * bp)1078 static gboolean remove_break(breakpoint* bp)
1079 {
1080 /* find break number */
1081 int number = get_break_number(bp->file, bp->line);
1082 if (-1 != number)
1083 {
1084 result_class rc;
1085 gchar command[100];
1086
1087 g_snprintf(command, sizeof command, "-break-delete %i", number);
1088 rc = exec_sync_command(command, TRUE, NULL);
1089
1090 return RC_DONE == rc;
1091 }
1092 return FALSE;
1093 }
1094
1095 /*
1096 * get active frame
1097 */
get_active_frame(void)1098 static int get_active_frame(void)
1099 {
1100 return active_frame;
1101 }
1102
1103 /*
1104 * select frame
1105 */
set_active_frame(int frame_number)1106 static void set_active_frame(int frame_number)
1107 {
1108 gchar *command = g_strdup_printf("-stack-select-frame %i", frame_number);
1109 if (RC_DONE == exec_sync_command(command, TRUE, NULL))
1110 {
1111 active_frame = frame_number;
1112 update_autos();
1113 update_watches();
1114 }
1115 g_free(command);
1116 }
1117
get_active_thread(void)1118 static int get_active_thread(void)
1119 {
1120 struct gdb_mi_record *record = NULL;
1121 int current_thread = 0;
1122
1123 if (RC_DONE == exec_sync_command("-thread-info", TRUE, &record))
1124 {
1125 const gchar *id = gdb_mi_result_var(record->first, "current-thread-id", GDB_MI_VAL_STRING);
1126 current_thread = id ? atoi(id) : 0;
1127 }
1128 gdb_mi_record_free(record);
1129
1130 return current_thread;
1131 }
1132
set_active_thread(int thread_id)1133 static gboolean set_active_thread(int thread_id)
1134 {
1135 gchar *command = g_strdup_printf("-thread-select %i", thread_id);
1136 gboolean success = (RC_DONE == exec_sync_command(command, TRUE, NULL));
1137
1138 if (success)
1139 set_active_frame(0);
1140
1141 g_free(command);
1142
1143 return success;
1144 }
1145
1146 /*
1147 * gets stack
1148 */
get_stack(void)1149 static GList* get_stack(void)
1150 {
1151 struct gdb_mi_record *record = NULL;
1152 const struct gdb_mi_result *stack_node, *frame_node;
1153 GList *stack = NULL;
1154
1155 if (RC_DONE != exec_sync_command("-stack-list-frames", TRUE, &record) || ! record)
1156 {
1157 gdb_mi_record_free(record);
1158 return NULL;
1159 }
1160
1161 stack_node = gdb_mi_result_var(record->first, "stack", GDB_MI_VAL_LIST);
1162 gdb_mi_result_foreach_matched (frame_node, stack_node, "frame", GDB_MI_VAL_LIST)
1163 {
1164 const gchar *addr = gdb_mi_result_var(frame_node->val->v.list, "addr", GDB_MI_VAL_STRING);
1165 const gchar *func = gdb_mi_result_var(frame_node->val->v.list, "func", GDB_MI_VAL_STRING);
1166 const gchar *line = gdb_mi_result_var(frame_node->val->v.list, "line", GDB_MI_VAL_STRING);
1167 const gchar *file, *fullname;
1168 frame *f = frame_new();
1169
1170 f->address = g_strdup(addr);
1171 f->function = g_strdup(func);
1172
1173 /* file: fullname | file | from */
1174 if ((fullname = file = gdb_mi_result_var(frame_node->val->v.list, "fullname", GDB_MI_VAL_STRING)) ||
1175 (file = gdb_mi_result_var(frame_node->val->v.list, "file", GDB_MI_VAL_STRING)) ||
1176 (file = gdb_mi_result_var(frame_node->val->v.list, "from", GDB_MI_VAL_STRING)))
1177 {
1178 f->file = g_strdup(file);
1179 }
1180 else
1181 {
1182 f->file = g_strdup("");
1183 }
1184
1185 /* whether source is available */
1186 f->have_source = fullname ? TRUE : FALSE;
1187
1188 /* line */
1189 f->line = line ? atoi(line) : 0;
1190
1191 stack = g_list_prepend(stack, f);
1192 }
1193 gdb_mi_record_free(record);
1194
1195 return g_list_reverse(stack);
1196 }
1197
1198 /*
1199 * updates variables from vars list
1200 */
get_variables(GList * vars)1201 static void get_variables (GList *vars)
1202 {
1203 while (vars)
1204 {
1205 gchar command[1000];
1206
1207 variable *var = (variable*)vars->data;
1208
1209 gchar *varname = var->internal->str;
1210 struct gdb_mi_record *record = NULL;
1211 const gchar *expression = NULL;
1212 const gchar *numchild = NULL;
1213 const gchar *value = NULL;
1214 const gchar *type = NULL;
1215
1216 /* path expression */
1217 g_snprintf(command, sizeof command, "-var-info-path-expression \"%s\"", varname);
1218 exec_sync_command(command, TRUE, &record);
1219 if (record)
1220 expression = gdb_mi_result_var(record->first, "path_expr", GDB_MI_VAL_STRING);
1221 g_string_assign(var->expression, expression ? expression : "");
1222 gdb_mi_record_free(record);
1223
1224 /* children number */
1225 g_snprintf(command, sizeof command, "-var-info-num-children \"%s\"", varname);
1226 exec_sync_command(command, TRUE, &record);
1227 if (record)
1228 numchild = gdb_mi_result_var(record->first, "numchild", GDB_MI_VAL_STRING);
1229 var->has_children = numchild && atoi(numchild) > 0;
1230 gdb_mi_record_free(record);
1231
1232 /* value */
1233 g_snprintf(command, sizeof command, "-data-evaluate-expression \"%s\"", var->expression->str);
1234 exec_sync_command(command, TRUE, &record);
1235 if (record)
1236 value = gdb_mi_result_var(record->first, "value", GDB_MI_VAL_STRING);
1237 if (!value)
1238 {
1239 gdb_mi_record_free(record);
1240 g_snprintf(command, sizeof command, "-var-evaluate-expression \"%s\"", varname);
1241 exec_sync_command(command, TRUE, &record);
1242 if (record)
1243 value = gdb_mi_result_var(record->first, "value", GDB_MI_VAL_STRING);
1244 }
1245 g_string_assign(var->value, value ? value : "");
1246 gdb_mi_record_free(record);
1247
1248 /* type */
1249 g_snprintf(command, sizeof command, "-var-info-type \"%s\"", varname);
1250 exec_sync_command(command, TRUE, &record);
1251 if (record)
1252 type = gdb_mi_result_var(record->first, "type", GDB_MI_VAL_STRING);
1253 g_string_assign(var->type, type ? type : "");
1254 gdb_mi_record_free(record);
1255
1256 vars = vars->next;
1257 }
1258 }
1259
1260 /*
1261 * updates files list
1262 */
update_files(void)1263 static void update_files(void)
1264 {
1265 GHashTable *ht;
1266 struct gdb_mi_record *record = NULL;
1267 const struct gdb_mi_result *files_node;
1268
1269 if (files)
1270 {
1271 /* free previous list */
1272 g_list_foreach(files, (GFunc)g_free, NULL);
1273 g_list_free(files);
1274 files = NULL;
1275 }
1276
1277 exec_sync_command("-file-list-exec-source-files", TRUE, &record);
1278 if (! record)
1279 return;
1280
1281 ht = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
1282
1283 files_node = gdb_mi_result_var(record->first, "files", GDB_MI_VAL_LIST);
1284 gdb_mi_result_foreach_matched (files_node, files_node, NULL, GDB_MI_VAL_LIST)
1285 {
1286 const gchar *fullname = gdb_mi_result_var(files_node->val->v.list, "fullname", GDB_MI_VAL_STRING);
1287
1288 if (fullname && !g_hash_table_lookup(ht, fullname))
1289 {
1290 g_hash_table_insert(ht, (gpointer)fullname, (gpointer)1);
1291 files = g_list_append(files, g_strdup(fullname));
1292 }
1293 }
1294
1295 g_hash_table_destroy(ht);
1296 gdb_mi_record_free(record);
1297 }
1298
1299 /*
1300 * updates watches list
1301 */
update_watches(void)1302 static void update_watches(void)
1303 {
1304 gchar command[1000];
1305 GList *updating = NULL;
1306 GList *iter;
1307
1308 /* delete all GDB variables */
1309 for (iter = watches; iter; iter = iter->next)
1310 {
1311 variable *var = (variable*)iter->data;
1312
1313 if (var->internal->len)
1314 {
1315 g_snprintf(command, sizeof command, "-var-delete %s", var->internal->str);
1316 exec_sync_command(command, TRUE, NULL);
1317 }
1318
1319 /* reset all variables fields */
1320 variable_reset(var);
1321 }
1322
1323 /* create GDB variables, adding successfully created
1324 variables to the list then passed for updatind */
1325 for (iter = watches; iter; iter = iter->next)
1326 {
1327 variable *var = (variable*)iter->data;
1328 struct gdb_mi_record *record = NULL;
1329 const gchar *name;
1330 gchar *escaped;
1331
1332 /* try to create variable */
1333 escaped = escape_string(var->name->str);
1334 g_snprintf(command, sizeof command, "-var-create - * \"%s\"", escaped);
1335 g_free(escaped);
1336
1337 if (RC_DONE != exec_sync_command(command, TRUE, &record) || !record)
1338 {
1339 /* do not include to updating list, move to next watch */
1340 var->evaluated = FALSE;
1341 g_string_assign(var->internal, "");
1342 gdb_mi_record_free(record);
1343
1344 continue;
1345 }
1346
1347 /* find and assign internal name */
1348 name = gdb_mi_result_var(record->first, "name", GDB_MI_VAL_STRING);
1349 g_string_assign(var->internal, name ? name : "");
1350 gdb_mi_record_free(record);
1351
1352 var->evaluated = name != NULL;
1353
1354 /* add to updating list */
1355 updating = g_list_prepend(updating, var);
1356 }
1357 updating = g_list_reverse(updating);
1358
1359 /* update watches */
1360 get_variables(updating);
1361
1362 /* free updating list */
1363 g_list_free(updating);
1364 }
1365
1366 /*
1367 * updates autos list
1368 */
update_autos(void)1369 static void update_autos(void)
1370 {
1371 gchar command[1000];
1372 GList *unevaluated = NULL, *vars = NULL, *iter;
1373
1374 /* remove all previous GDB variables for autos */
1375 for (iter = autos; iter; iter = iter->next)
1376 {
1377 variable *var = (variable*)iter->data;
1378
1379 g_snprintf(command, sizeof command, "-var-delete %s", var->internal->str);
1380 exec_sync_command(command, TRUE, NULL);
1381 }
1382
1383 g_list_foreach(autos, (GFunc)variable_free, NULL);
1384 g_list_free(autos);
1385 autos = NULL;
1386
1387 /* add current autos to the list */
1388
1389 struct gdb_mi_record *record = NULL;
1390
1391 g_snprintf(command, sizeof command, "-stack-list-arguments 0 %i %i", active_frame, active_frame);
1392 if (RC_DONE == exec_sync_command(command, TRUE, &record) && record)
1393 {
1394 const struct gdb_mi_result *stack_args = gdb_mi_result_var(record->first, "stack-args", GDB_MI_VAL_LIST);
1395
1396 gdb_mi_result_foreach_matched (stack_args, stack_args, "frame", GDB_MI_VAL_LIST)
1397 {
1398 const struct gdb_mi_result *args = gdb_mi_result_var(stack_args->val->v.list, "args", GDB_MI_VAL_LIST);
1399
1400 gdb_mi_result_foreach_matched (args, args, "name", GDB_MI_VAL_STRING)
1401 {
1402 variable *var = variable_new(args->val->v.string, VT_ARGUMENT);
1403 vars = g_list_append(vars, var);
1404 }
1405 }
1406 }
1407 gdb_mi_record_free(record);
1408
1409 if (RC_DONE == exec_sync_command("-stack-list-locals 0", TRUE, &record) && record)
1410 {
1411 const struct gdb_mi_result *locals = gdb_mi_result_var(record->first, "locals", GDB_MI_VAL_LIST);
1412
1413 gdb_mi_result_foreach_matched (locals, locals, "name", GDB_MI_VAL_STRING)
1414 {
1415 variable *var = variable_new(locals->val->v.string, VT_LOCAL);
1416 vars = g_list_append(vars, var);
1417 }
1418 }
1419 gdb_mi_record_free(record);
1420
1421 for (iter = vars; iter; iter = iter->next)
1422 {
1423 variable *var = iter->data;
1424 struct gdb_mi_record *create_record = NULL;
1425 gchar *escaped;
1426 const gchar *intname;
1427
1428 /* create new gdb variable */
1429 escaped = escape_string(var->name->str);
1430 g_snprintf(command, sizeof command, "-var-create - * \"%s\"", escaped);
1431 g_free(escaped);
1432
1433 /* form new variable */
1434 if (RC_DONE == exec_sync_command(command, TRUE, &create_record) && create_record &&
1435 (intname = gdb_mi_result_var(create_record->first, "name", GDB_MI_VAL_STRING)))
1436 {
1437 var->evaluated = TRUE;
1438 g_string_assign(var->internal, intname);
1439 autos = g_list_append(autos, var);
1440 }
1441 else
1442 {
1443 var->evaluated = FALSE;
1444 g_string_assign(var->internal, "");
1445 unevaluated = g_list_append(unevaluated, var);
1446 }
1447 gdb_mi_record_free(create_record);
1448 }
1449 g_list_free(vars);
1450
1451 /* get values for the autos (without incorrect variables) */
1452 get_variables(autos);
1453
1454 /* add incorrect variables */
1455 autos = g_list_concat(autos, unevaluated);
1456 }
1457
1458 /*
1459 * get autos list
1460 */
get_autos(void)1461 static GList* get_autos (void)
1462 {
1463 return g_list_copy(autos);
1464 }
1465
1466 /*
1467 * get watches list
1468 */
get_watches(void)1469 static GList* get_watches (void)
1470 {
1471 return g_list_copy(watches);
1472 }
1473
1474 /*
1475 * get files list
1476 */
get_files(void)1477 static GList* get_files (void)
1478 {
1479 return g_list_copy(files);
1480 }
1481
1482 /*
1483 * get list of children
1484 */
get_children(gchar * path)1485 static GList* get_children (gchar* path)
1486 {
1487 GList *children = NULL;
1488
1489 gchar command[1000];
1490 result_class rc;
1491 struct gdb_mi_record *record = NULL;
1492 const gchar *numchild;
1493 int n;
1494
1495 /* children number */
1496 g_snprintf(command, sizeof command, "-var-info-num-children \"%s\"", path);
1497 rc = exec_sync_command(command, TRUE, &record);
1498 if (RC_DONE != rc || ! record)
1499 {
1500 gdb_mi_record_free(record);
1501 return NULL;
1502 }
1503 numchild = gdb_mi_result_var(record->first, "numchild", GDB_MI_VAL_STRING);
1504 n = numchild ? atoi(numchild) : 0;
1505 gdb_mi_record_free(record);
1506 if (!n)
1507 return NULL;
1508
1509 /* recursive get children and put into list */
1510 g_snprintf(command, sizeof command, "-var-list-children \"%s\"", path);
1511 rc = exec_sync_command(command, TRUE, &record);
1512 if (RC_DONE == rc && record)
1513 {
1514 const struct gdb_mi_result *child_node = gdb_mi_result_var(record->first, "children", GDB_MI_VAL_LIST);
1515
1516 gdb_mi_result_foreach_matched (child_node, child_node, "child", GDB_MI_VAL_LIST)
1517 {
1518 const gchar *internal = gdb_mi_result_var(child_node->val->v.list, "name", GDB_MI_VAL_STRING);
1519 const gchar *name = gdb_mi_result_var(child_node->val->v.list, "exp", GDB_MI_VAL_STRING);
1520 variable *var;
1521
1522 if (! name || ! internal)
1523 continue;
1524
1525 var = variable_new2(name, internal, VT_CHILD);
1526 var->evaluated = TRUE;
1527
1528 children = g_list_prepend(children, var);
1529 }
1530 }
1531 gdb_mi_record_free(record);
1532
1533 children = g_list_reverse(children);
1534 get_variables(children);
1535
1536 return children;
1537 }
1538
1539 /*
1540 * add new watch
1541 */
add_watch(gchar * expression)1542 static variable* add_watch(gchar* expression)
1543 {
1544 gchar command[1000];
1545 gchar *escaped;
1546 struct gdb_mi_record *record = NULL;
1547 const gchar *name;
1548 GList *vars = NULL;
1549 variable *var = variable_new(expression, VT_WATCH);
1550
1551 watches = g_list_append(watches, var);
1552
1553 /* try to create a variable */
1554 escaped = escape_string(var->name->str);
1555 g_snprintf(command, sizeof command, "-var-create - * \"%s\"", escaped);
1556 g_free(escaped);
1557
1558 if (RC_DONE != exec_sync_command(command, TRUE, &record) || !record)
1559 {
1560 gdb_mi_record_free(record);
1561 return var;
1562 }
1563
1564 name = gdb_mi_result_var(record->first, "name", GDB_MI_VAL_STRING);
1565 g_string_assign(var->internal, name ? name : "");
1566 var->evaluated = name != NULL;
1567
1568 vars = g_list_append(NULL, var);
1569 get_variables(vars);
1570
1571 gdb_mi_record_free(record);
1572 g_list_free(vars);
1573
1574 return var;
1575 }
1576
1577 /*
1578 * remove watch
1579 */
remove_watch(gchar * internal)1580 static void remove_watch(gchar* internal)
1581 {
1582 GList *iter = watches;
1583 while (iter)
1584 {
1585 variable *var = (variable*)iter->data;
1586 if (!strcmp(var->internal->str, internal))
1587 {
1588 gchar command[1000];
1589 g_snprintf(command, sizeof command, "-var-delete %s", internal);
1590 exec_sync_command(command, TRUE, NULL);
1591 variable_free(var);
1592 watches = g_list_delete_link(watches, iter);
1593 }
1594 iter = iter->next;
1595 }
1596 }
1597
1598 /*
1599 * evaluates given expression and returns the result
1600 */
evaluate_expression(gchar * expression)1601 static gchar *evaluate_expression(gchar *expression)
1602 {
1603 struct gdb_mi_record *record = NULL;
1604 gchar *value;
1605 char command[1000];
1606
1607 g_snprintf(command, sizeof command, "-data-evaluate-expression \"%s\"", expression);
1608 if (RC_DONE != exec_sync_command(command, TRUE, &record) || ! record)
1609 {
1610 gdb_mi_record_free(record);
1611 return NULL;
1612 }
1613
1614 value = g_strdup(gdb_mi_result_var(record->first, "value", GDB_MI_VAL_STRING));
1615 gdb_mi_record_free(record);
1616
1617 return value;
1618 }
1619
1620 /*
1621 * request GDB interrupt
1622 */
request_interrupt(void)1623 static gboolean request_interrupt(void)
1624 {
1625 #ifdef DEBUG_OUTPUT
1626 char msg[1000];
1627 g_snprintf(msg, sizeof msg, "interrupting pid=%i", target_pid);
1628 dbg_cbs->send_message(msg, "red");
1629 #endif
1630
1631 requested_interrupt = TRUE;
1632 kill(target_pid, SIGINT);
1633
1634 return TRUE;
1635 }
1636
1637 /*
1638 * get GDB error messages
1639 */
error_message(void)1640 static gchar* error_message(void)
1641 {
1642 return err_message;
1643 }
1644
1645 /*
1646 * define GDB debug module
1647 */
1648 DBG_MODULE_DEFINE(gdb);
1649
1650
1651