#include "ansidecl.h"
#include "mi_gdb.h"
+#define fatal(fmt...) fatal_func (__FILE__, __LINE__, __PRETTY_FUNCTION__, fmt)
#define gdb_assert assert
+#define gdb_assert_not_reached(msg) fatal ("%s", (msg))
+#define _(x) x
static ATTRIBUTE_NORETURN void
-fatal (const char *fmt, ...)
+fatal_func (const char *file, int line, const char *func, const char *fmt, ...)
{
va_list ap;
+ fprintf (stderr, "%s:%d:%s:", file, line, func);
va_start (ap, fmt);
vfprintf (stderr, fmt, ap);
va_end (ap);
+ fputc ('\n', stderr);
raise (SIGABRT);
exit (EXIT_FAILURE);
}
return retval;
}
+static void *
+xmalloc (size_t size)
+{
+ void *p;
+
+ gdb_assert (size != 0);
+ p = malloc (size);
+ gdb_assert (p != NULL);
+ return p;
+}
+
+static void *
+xrealloc (void *p, size_t size)
+{
+ if (p == NULL)
+ return xmalloc (size);
+ gdb_assert (size != 0);
+ p = realloc (p, size);
+ gdb_assert (p != NULL);
+ return p;
+}
+
static void
xfree (void *p)
{
count--;
break;
case MI_CL_ERROR:
+ count--;
gdb_assert (rec->c->type == t_const);
puts (rec->c->v.cstr);
break;
return retval;
}
+static mi_h *completion_entry_function_h;
+
+static char **completion_entry_function_data;
+static size_t completion_entry_function_data_used;
+static size_t completion_entry_function_data_allocated;
+
+static void
+completion_entry_function_console_cb (const char *str, void *data)
+{
+ int line_start = (intptr_t) data;
+ const char *cs;
+ char *s;
+
+ if (completion_entry_function_data_used
+ == completion_entry_function_data_allocated)
+ {
+ if (completion_entry_function_data_allocated > 0)
+ completion_entry_function_data_allocated *= 2;
+ else
+ completion_entry_function_data_allocated = 0x100;
+ completion_entry_function_data = xrealloc (completion_entry_function_data,
+ (sizeof (*completion_entry_function_data)
+ * completion_entry_function_data_allocated));
+ }
+
+ cs = strchr (str, '\n');
+ if (cs == NULL || cs[1] != '\0')
+ fatal ("Invalid GDB data: %s", str);
+
+ if (strncmp (rl_line_buffer, str, rl_point) != 0)
+ fatal ("Completion GDB data do not match, have \"%.*s\", got \"%.*s\".",
+ (int) rl_point, rl_line_buffer, (int) (cs - str), str);
+
+ s = xmalloc (cs - str - line_start + 1);
+ memcpy (s, &str[line_start], cs - str - line_start);
+ s[cs - str - line_start] = '\0';
+ completion_entry_function_data[completion_entry_function_data_used++] = s;
+}
+
+static char *
+completion_entry_function (const char *text, int matches)
+{
+ mi_h *h = completion_entry_function_h;
+
+ gdb_assert (matches >= 0);
+ if (matches == 0)
+ {
+ mi_output *res;
+ int line_start;
+
+ while (completion_entry_function_data_used)
+ xfree (completion_entry_function_data
+ [--completion_entry_function_data_used]);
+ xfree (completion_entry_function_data);
+ completion_entry_function_data = NULL;
+ completion_entry_function_data_used = 0;
+ completion_entry_function_data_allocated = 0;
+
+ gdb_assert (rl_point >= 0);
+ gdb_assert (strlen (rl_line_buffer) >= rl_point);
+ gdb_assert (strlen (text) <= rl_point);
+ line_start = rl_point - strlen (text);
+ gdb_assert (strncmp (text, &rl_line_buffer[line_start],
+ strlen (text)) == 0);
+ mi_send (h, "-interpreter-exec console \"complete %.*s\"\n",
+ (int) rl_point, rl_line_buffer);
+
+ mi_set_console_cb (h, completion_entry_function_console_cb,
+ (void *) (intptr_t) line_start);
+ res = mi_get_response_blk (h);
+ gdb_assert (res != NULL && res->next == NULL && res->tclass == MI_CL_DONE
+ && res->c == NULL);
+ mi_free_output (res);
+ mi_set_console_cb (h, console_cb, NULL);
+ }
+
+ if (matches < completion_entry_function_data_used)
+ return xstrdup (completion_entry_function_data[matches]);
+ else if (matches == completion_entry_function_data_used)
+ return NULL;
+ else
+ gdb_assert_not_reached ("too many matches");
+}
+
+extern char **mi_gdb_argv;
+extern void (*mi_gdb_start_hook) (mi_h *h);
+
+static void
+start_hook (mi_h *h)
+{
+ on_exit (h_disconnect, h);
+ mi_set_console_cb (h, console_cb, NULL);
+// mi_set_to_gdb_cb (h, to_gdb_cb, NULL);
+// mi_set_from_gdb_cb (h, from_gdb_cb, NULL);
+}
+
int
main (int argc, char **argv)
{
mi_h *h;
- char *cmd;
- const char *ex[argc];
- unsigned ex_count = 0, ex_used = 0;
+ mi_output *res;
setbuf (stdout, NULL);
- while (*++argv != NULL)
- {
- if (strcmp (*argv, "-ex") == 0 && argv[1] != NULL)
- ex[ex_count++] = *++argv;
- else
- fatal ("Unknown parameter: %s", *argv);
- }
+ mi_gdb_argv = xmalloc ((argc + 2) * sizeof (*mi_gdb_argv));
+ memcpy (&mi_gdb_argv[2], &argv[1], argc * sizeof (*mi_gdb_argv));
+ mi_gdb_argv[0] = "gdb";
+ mi_gdb_argv[1] = "--interpreter=mi";
- mi_set_workaround (MI_PSYM_SEARCH, 0);
+ mi_gdb_start_hook = start_hook;
h = mi_connect_local ();
if (h == NULL)
fatal ("Cannot connect to GDB");
- on_exit (h_disconnect, h);
+ /* First eat the prompt. Then run empty command so that additional results
+ from -ex or -x during mi_connect_local are flushed. */
+ res = mi_get_response_blk (h);
+ gdb_assert (res == NULL);
+ default_command (h, "echo");
- mi_set_console_cb (h, console_cb, NULL);
-// mi_set_to_gdb_cb (h, to_gdb_cb, NULL);
-// mi_set_from_gdb_cb (h, from_gdb_cb, NULL);
+ completion_entry_function_h = h;
+ rl_completion_entry_function = completion_entry_function;
+ rl_readline_name = "gdb";
if (gdb_show_bool (h, "history save"))
{
for (;;)
{
- if (ex_used < ex_count)
- {
- cmd = xstrdup (ex[ex_used++]);
- printf ("(gdb) %s\n", cmd);
- }
+ char *prompt, *cmd;
+
+ prompt = gdb_show_string (h, "prompt");
+ cmd = readline (prompt);
+ xfree (prompt);
+
+ if (cmd == NULL)
+ cmd = xstrdup ("quit");
else
- {
- cmd = readline ("(gdb) ");
- if (cmd == NULL)
- cmd = xstrdup ("quit");
- else
- add_history (cmd);
- }
+ add_history (cmd);
+
executecommand (h, cmd);
xfree (cmd);
}