Support "commands".
[gdbmicli.git] / main.c
1 #define _GNU_SOURCE
2 #include <stdio.h>
3 #include <stdarg.h>
4 #include <signal.h>
5 #include <readline/readline.h>
6 #include <readline/history.h>
7 #include <assert.h>
8 #include <errno.h>
9 #include "ansidecl.h"
10 #include "mi_gdb.h"
11
12 #define fatal(fmt...) fatal_func (__FILE__, __LINE__, __PRETTY_FUNCTION__, fmt)
13 #define gdb_assert assert
14 #define gdb_assert_not_reached(msg) fatal ("%s", (msg))
15 #define _(x) x
16
17 static ATTRIBUTE_NORETURN void
18 fatal_func (const char *file, int line, const char *func, const char *fmt, ...)
19 {
20   va_list ap;
21
22   fprintf (stderr, "%s:%d:%s:", file, line, func);
23   va_start (ap, fmt);
24   vfprintf (stderr, fmt, ap);
25   va_end (ap);
26   fputc ('\n', stderr);
27 raise (SIGABRT);
28   exit (EXIT_FAILURE);
29 }
30
31 static char *
32 xstrdup (const char *s)
33 {
34   char *retval;
35
36   gdb_assert (s != NULL);
37   retval = strdup (s);
38   gdb_assert (retval != NULL);
39   return retval;
40 }
41
42 static void *
43 xmalloc (size_t size)
44 {
45   void *p;
46
47   gdb_assert (size != 0);
48   p = malloc (size);
49   gdb_assert (p != NULL);
50   return p;
51 }
52
53 static void *
54 xrealloc (void *p, size_t size)
55 {
56   if (p == NULL)
57     return xmalloc (size);
58   gdb_assert (size != 0);
59   p = realloc (p, size);
60   gdb_assert (p != NULL);
61   return p;
62 }
63
64 static void
65 xfree (void *p)
66 {
67   free (p);
68 }
69
70 static char *
71 xstrprintf (const char *fmt, ...)
72 {
73   va_list ap;
74   char *retval;
75   int i;
76
77   va_start (ap, fmt);
78   i = vasprintf (&retval, fmt, ap);
79   va_end (ap);
80   gdb_assert (i > 0);
81   gdb_assert (i == strlen (retval));
82   return retval;
83 }
84
85 static void
86 console_cb (const char *str, void *data)
87 {
88   fputs (str, stdout);
89 }
90
91 static int
92 time_out_cb (void *data)
93 {
94   fatal ("GDB response has timed out");
95   /* NOTREACHED */
96   return 0;
97 }
98
99 static ATTRIBUTE_UNUSED void
100 to_gdb_cb (const char *str, void *data)
101 {
102   printf ("to_gdb: %s\n", str);
103 }
104
105 static ATTRIBUTE_UNUSED void
106 from_gdb_cb (const char *str, void *data)
107 {
108   printf ("from_gdb: %s\n", str);
109 }
110
111 static void
112 h_disconnect (int rc, void *arg)
113 {
114   mi_h *h = arg;
115
116   mi_disconnect (h);
117 }
118
119 static void
120 history_save (int rc, void *arg)
121 {
122   const char *history_filename = arg;
123
124   write_history (history_filename);
125 }
126
127 static void
128 default_command (mi_h *h, const char *cmd)
129 {
130   int count = 1;
131
132   gdb_assert (strchr (cmd, '\n') == 0);
133   mi_send (h, "-interpreter-exec console \"%s\"\n", cmd);
134
135   while (count > 0)
136     {
137       mi_output *rec, *res;
138
139       res = mi_get_response_blk (h);
140       gdb_assert (res != NULL);
141
142       for (rec = res; rec != NULL; rec = rec->next)
143         switch (rec->tclass)
144         {
145           case MI_CL_DONE:
146             count--;
147             break;
148           case MI_CL_RUNNING:
149             /* We do not get MI_CL_DONE here, wait for MI_CL_STOPPED.  */
150             break;
151           case MI_CL_STOPPED:
152             count--;
153             break;
154           case MI_CL_ERROR:
155             count--;
156             gdb_assert (rec->c->type == t_const);
157             puts (rec->c->v.cstr);
158             break;
159           default:
160             fatal ("mi_get_rrecord == MI_CL_??? (%d)", rec->tclass);
161         }
162
163       mi_free_output (res);
164     }
165 }
166
167 static void
168 quit_command (mi_h *h, const char *cmd)
169 {
170   exit (EXIT_SUCCESS);
171 }
172
173 static char *
174 mi_escape (const char *cs)
175 {
176   char *d, *retval = xmalloc (strlen (cs) * 2 + 1);
177
178   d = retval;
179   while (*cs)
180     {
181       if (*cs == '"' || *cs == '\\')
182         *d++ = '\\';
183       *d++ = *cs++;
184     }
185   *d = '\0';
186   return retval;
187 }
188
189 static void
190 gdb_done (mi_h *h, const char *command)
191 {
192   mi_output *res;
193
194   mi_send (h, "%s\n", command);
195   res = mi_get_response_blk (h);
196   gdb_assert (res != NULL && res->next == NULL && res->tclass == MI_CL_DONE
197               && res->c == NULL);
198   mi_free_output (res);
199 }
200
201 static void
202 commands_command_console_cb (const char *str, void *data)
203 {
204   char **strptr = data;
205
206   gdb_assert (*strptr == NULL);
207   *strptr = xstrdup (str);
208 }
209
210 static void
211 commands_command (mi_h *h, const char *cmd_param)
212 {
213   char *cmd = xstrdup ("");
214   size_t cmd_len = 0;
215   mi_output *res;
216   char *bpnum = NULL;
217   int nesting;
218
219   if (*cmd_param == '\0')
220     {
221       mi_set_console_cb (h, commands_command_console_cb, &bpnum);
222       gdb_done (h, "output $bpnum");
223       mi_set_console_cb (h, console_cb, NULL);
224       gdb_assert (bpnum != NULL);
225       cmd_param = bpnum;
226     }
227
228   printf (_("Type commands for breakpoint(s) %s, one per line.\n"
229             "End with a line saying just \"end\".\n"), cmd_param);
230
231   nesting = 0;
232   while (nesting >= 0)
233     {
234       char *prompt, *data, *data2, *start, *end;
235       size_t data2_len;
236       int do_nest = 0;
237
238       prompt = xstrprintf ("%*s>", (int) nesting);
239       data = readline (prompt);
240       xfree (prompt);
241       if (data == NULL)
242         data = xstrdup ("end");
243
244       for (start = data; isspace (*start); start++);
245       for (end = data + strlen (data); end > start && isspace (end[-1]); end--);
246       data2 = xmalloc (end - start + 1);
247       memcpy (data2, start, end - start);
248       data2[end - start] = '\0';
249       if (strcmp (data2, "python") == 0)
250         do_nest = 1;
251       if (strcmp (data2, "end") == 0)
252         do_nest = -1;
253       for (end = data2; *end && !isspace (*end); end++);
254       *end = '\0';
255
256       /* Here is a bug in GDB, it does not recognize command shortcuts.  */
257       if (strcmp (data2, "while") == 0 || strcmp (data2, "if") == 0
258           || strcmp (data2, "commands") == 0
259           || strcmp (data2, "while-stepping") == 0
260           || strcmp (data2, "stepping") == 0 || strcmp (data2, "ws") == 0)
261         do_nest = 1;
262       xfree (data2);
263
264       nesting += do_nest;
265       if (nesting < 0)
266         break;
267
268       data2 = mi_escape (data);
269       xfree (data);
270       data2_len = strlen (data2);
271       cmd = xrealloc (cmd, cmd_len + 2 + data2_len + 2);
272       cmd[cmd_len] = ' ';
273       cmd[cmd_len + 1] = '"';
274       memcpy (&cmd[cmd_len + 2], data2, data2_len);
275       cmd[cmd_len + 2 + data2_len] = '"';
276       cmd[cmd_len + 2 + data2_len + 1] = '\0';
277       cmd_len += 2 + data2_len + 1;
278       xfree (data2);
279     }
280
281   mi_send (h, "-break-commands %s%s\n", cmd_param, cmd);
282   xfree (cmd);
283   xfree (bpnum);
284
285   res = mi_get_response_blk (h);
286   gdb_assert (res != NULL && res->next == NULL && res->tclass == MI_CL_DONE
287               && res->c == NULL);
288   mi_free_output (res);
289 }
290
291 static const struct cmd
292 {
293   const char *name;
294   int min_shortcut;
295   void (*func) (mi_h *h, const char *cmd);
296 } cmds[] =
297 {
298   { "quit", 1, quit_command },
299   { "commands", 4, commands_command },
300 };
301
302 static void
303 executecommand (mi_h *h, const char *cmd)
304 {
305   const char *start, *end, *cs;
306   const struct cmd *cmdp;
307
308   cs = cmd;
309   while (isspace (*cs))
310     cs++;
311   start = cs;
312   while (isalnum (*cs))
313     cs++;
314   end = cs;
315   while (isspace (*cs))
316     cs++;
317
318   for (cmdp = cmds; cmdp < &cmds[LENGTH (cmds)]; cmdp++)
319     if (cmdp->min_shortcut <= end - start && end - start <= strlen (cmdp->name)
320         && strncmp (start, cmdp->name, end - start) == 0)
321       return cmdp->func (h, cs);
322
323   return default_command (h, cmd);
324 }
325
326 static void
327 gdb_set_string (mi_h *h, const char *setting, const char *value)
328 {
329   char *cmd = xstrprintf ("-gdb-set %s %s", setting, value);
330
331   gdb_done (h, cmd);
332   xfree (cmd);
333 }
334
335 static void
336 gdb_set_bool (mi_h *h, const char *setting, bool value)
337 {
338   gdb_set_string (h, setting, value ? "on" : "off");
339 }
340
341 static char *
342 gdb_show_string (mi_h *h, const char *setting)
343 {
344   mi_output *res;
345   char *retval;
346
347   mi_send (h, "-gdb-show %s\n", setting);
348   res = mi_get_response_blk (h);
349   gdb_assert (res != NULL && res->next == NULL && res->tclass == MI_CL_DONE
350               && res->c != NULL && res->c->next == NULL
351               && res->c->type == t_const && strcmp (res->c->var, "value") == 0);
352   retval = xstrdup (res->c->v.cstr);
353   mi_free_output (res);
354   return retval;
355 }
356
357 static int
358 gdb_show_int (mi_h *h, const char *setting)
359 {
360   char *string = gdb_show_string (h, setting);
361   long l;
362   int retval;
363   char *end;
364
365   errno = 0;
366   retval = l = strtol (string, &end, 10);
367   gdb_assert (errno == 0 && (end == NULL || *end == '\0') && retval == l);
368   xfree (string);
369   return retval;
370 }
371
372 static bool
373 gdb_show_bool (mi_h *h, const char *setting)
374 {
375   char *string = gdb_show_string (h, setting);
376   bool retval;
377
378   retval = strcmp (string, "on") == 0;
379   gdb_assert (retval || strcmp (string, "off") == 0);
380   xfree (string);
381   return retval;
382 }
383
384 static mi_h *completion_entry_function_h;
385
386 static char **completion_entry_function_data;
387 static size_t completion_entry_function_data_used;
388 static size_t completion_entry_function_data_allocated;
389
390 static void
391 completion_entry_function_console_cb (const char *str, void *data)
392 {
393   int line_start = (intptr_t) data;
394   const char *cs;
395   char *s;
396
397   if (completion_entry_function_data_used
398       == completion_entry_function_data_allocated)
399     {
400       if (completion_entry_function_data_allocated > 0)
401         completion_entry_function_data_allocated *= 2;
402       else
403         completion_entry_function_data_allocated = 0x100;
404       completion_entry_function_data = xrealloc (completion_entry_function_data,
405                                   (sizeof (*completion_entry_function_data)
406                                    * completion_entry_function_data_allocated));
407     }
408
409   cs = strchr (str, '\n');
410   if (cs == NULL || cs[1] != '\0')
411     fatal ("Invalid GDB data: %s", str);
412
413   if (strncmp (rl_line_buffer, str, rl_point) != 0)
414     fatal ("Completion GDB data do not match, have \"%.*s\", got \"%.*s\".",
415            (int) rl_point, rl_line_buffer, (int) (cs - str), str);
416
417   s = xmalloc (cs - str - line_start + 1);
418   memcpy (s, &str[line_start], cs - str - line_start);
419   s[cs - str - line_start] = '\0';
420   completion_entry_function_data[completion_entry_function_data_used++] = s;
421 }
422
423 static char *
424 completion_entry_function (const char *text, int matches)
425 {
426   mi_h *h = completion_entry_function_h;
427
428   gdb_assert (matches >= 0);
429   if (matches == 0)
430     {
431       mi_output *res;
432       int line_start;
433
434       while (completion_entry_function_data_used)
435         xfree (completion_entry_function_data
436                [--completion_entry_function_data_used]);
437       xfree (completion_entry_function_data);
438       completion_entry_function_data = NULL;
439       completion_entry_function_data_used = 0;
440       completion_entry_function_data_allocated = 0;
441
442       gdb_assert (rl_point >= 0);
443       gdb_assert (strlen (rl_line_buffer) >= rl_point);
444       gdb_assert (strlen (text) <= rl_point);
445       line_start = rl_point - strlen (text);
446       gdb_assert (strncmp (text, &rl_line_buffer[line_start],
447                            strlen (text)) == 0);
448       mi_send (h, "-interpreter-exec console \"complete %.*s\"\n",
449                (int) rl_point, rl_line_buffer);
450
451       mi_set_console_cb (h, completion_entry_function_console_cb,
452                          (void *) (intptr_t) line_start);
453       res = mi_get_response_blk (h);
454       gdb_assert (res != NULL && res->next == NULL && res->tclass == MI_CL_DONE
455                   && res->c == NULL);
456       mi_free_output (res);
457       mi_set_console_cb (h, console_cb, NULL);
458     }
459
460   if (matches < completion_entry_function_data_used)
461     return xstrdup (completion_entry_function_data[matches]);
462   else if (matches == completion_entry_function_data_used)
463     return NULL;
464   else
465     gdb_assert_not_reached ("too many matches");
466 }
467
468 extern char **mi_gdb_argv;
469 extern void (*mi_gdb_start_hook) (mi_h *h);
470
471 static void
472 start_hook (mi_h *h)
473 {
474   on_exit (h_disconnect, h);
475   mi_set_console_cb (h, console_cb, NULL);
476   mi_set_time_out_cb (h, time_out_cb, NULL);
477
478 //  mi_set_to_gdb_cb (h, to_gdb_cb, NULL);
479 //  mi_set_from_gdb_cb (h, from_gdb_cb, NULL);
480 }
481
482 int
483 main (int argc, char **argv)
484 {
485   mi_h *h;
486   mi_output *res;
487
488   setbuf (stdout, NULL);
489
490   mi_gdb_argv = xmalloc ((argc + 2) * sizeof (*mi_gdb_argv));
491   memcpy (&mi_gdb_argv[2], &argv[1], argc * sizeof (*mi_gdb_argv));
492   mi_gdb_argv[0] = "gdb";
493   mi_gdb_argv[1] = "--interpreter=mi";
494
495   mi_gdb_start_hook = start_hook;
496
497   h = mi_connect_local ();
498   if (h == NULL)
499     fatal ("Cannot connect to GDB");
500
501   /* First eat the prompt.  Then run empty command so that additional results
502      from -ex or -x during mi_connect_local are flushed.  */
503   res = mi_get_response_blk (h);
504   gdb_assert (res == NULL);
505   default_command (h, "echo");
506
507   completion_entry_function_h = h;
508   rl_completion_entry_function = completion_entry_function;
509   rl_readline_name = "gdb";        
510
511   if (gdb_show_bool (h, "history save"))
512     {
513       int history_size = gdb_show_int (h, "history size");
514       char *history_filename = gdb_show_string (h, "history filename");
515
516       gdb_set_bool (h, "history save", false);
517       stifle_history (history_size);
518       read_history (history_filename);
519       on_exit (history_save, history_filename);
520       /* Do not free HISTORY_FILENAME.  */
521     }
522
523   for (;;)
524     {
525       char *prompt, *cmd;
526       
527       prompt = gdb_show_string (h, "prompt");
528       cmd = readline (prompt);
529       xfree (prompt);
530
531       if (cmd == NULL)
532         cmd = xstrdup ("quit");
533       else
534         add_history (cmd);
535
536       executecommand (h, cmd);
537       xfree (cmd);
538     }
539 }