[geany/geany-plugins] ca6331: debugger: Fix a few things in the GDB/MI parser
Colomban Wendling
git-noreply at xxxxx
Sun Nov 15 17:28:20 UTC 2015
Branch: refs/heads/master
Author: Colomban Wendling <ban at herbesfolles.org>
Committer: Colomban Wendling <ban at herbesfolles.org>
Date: Sat, 25 Oct 2014 21:49:44 UTC
Commit: ca63317464ddbdae68073e4a471a41363a0028bb
https://github.com/geany/geany-plugins/commit/ca63317464ddbdae68073e4a471a41363a0028bb
Log Message:
-----------
debugger: Fix a few things in the GDB/MI parser
Including:
* Fix parsing hex escapes;
* Allow short forms for hex and octal escapes;
* Remove some dead code;
* Disable debugging prints;
* Only recognize ASCII for special meanings.
Modified Paths:
--------------
debugger/src/gdb_mi.c
Modified: debugger/src/gdb_mi.c
204 lines changed, 89 insertions(+), 115 deletions(-)
===================================================================
@@ -21,27 +21,22 @@
/*
* Parses GDB/MI records
- * http://ftp.gnu.org/old-gnu/Manuals/gdb/html_node/gdb_214.html
+ * https://sourceware.org/gdb/current/onlinedocs/gdb/GDB_002fMI-Output-Syntax.html
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
#include <glib.h>
#include "gdb_mi.h"
-#define DEBUG
-#define isodigit(c) ((c) >= '0' && (c) <= '7')
+#define ascii_isodigit(c) (((guchar) (c)) >= '0' && ((guchar) (c)) <= '7')
-#if defined(DEBUG) || defined(TEST)
-static void gdb_mi_result_dump(const struct gdb_mi_result *r, gboolean next, gint indent);
-#endif
static struct gdb_mi_value *parse_value(const gchar **p);
@@ -85,46 +80,6 @@ void gdb_mi_record_free(struct gdb_mi_record *record)
g_free(record);
}
-#if defined(DEBUG) || defined(TEST)
-
-static void gdb_mi_value_dump(const struct gdb_mi_value *v, gint indent)
-{
- fprintf(stderr, "%*stype = %d\n", indent * 2, "", v->type);
- switch (v->type)
- {
- case GDB_MI_VAL_STRING:
- fprintf(stderr, "%*sstring = %s\n", indent * 2, "", v->string);
- break;
- case GDB_MI_VAL_LIST:
- fprintf(stderr, "%*slist =>\n", indent * 2, "");
- if (v->list)
- gdb_mi_result_dump(v->list, TRUE, indent + 1);
- break;
- }
-}
-
-static void gdb_mi_result_dump(const struct gdb_mi_result *r, gboolean next, gint indent)
-{
- fprintf(stderr, "%*svar = %s\n", indent * 2, "", r->var);
- fprintf(stderr, "%*sval =>\n", indent * 2, "");
- gdb_mi_value_dump(r->val, indent + 1);
- if (next && r->next)
- gdb_mi_result_dump(r->next, next, indent);
-}
-
-static void gdb_mi_record_dump(const struct gdb_mi_record *record)
-{
- fprintf(stderr, "record =>\n");
- fprintf(stderr, " type = '%c' (%d)\n", record->type ? record->type : '0', record->type);
- fprintf(stderr, " token = %s\n", record->token);
- fprintf(stderr, " class = %s\n", record->klass);
- fprintf(stderr, " results =>\n");
- if (record->first)
- gdb_mi_result_dump(record->first, TRUE, 2);
-}
-
-#endif
-
/* parses: cstring
*
* cstring is defined as:
@@ -134,7 +89,9 @@ static void gdb_mi_record_dump(const struct gdb_mi_record *record)
*
* FIXME: what exactly does "seven-bit-iso-c-string-content" mean?
* reading between the lines suggests it's US-ASCII with values >= 0x80
- * encoded as \NNN (most likely octal), but that's not really clear */
+ * encoded as \NNN (most likely octal), but that's not really clear --
+ * although it parses everything I encountered
+ * FIXME: this does NOT convert to UTF-8. should it? */
static gchar *parse_cstring(const gchar **p)
{
GString *str = g_string_new(NULL);
@@ -144,35 +101,55 @@ static gchar *parse_cstring(const gchar **p)
(*p)++;
while (**p != '"')
{
- int c = **p;
+ gchar c = **p;
/* TODO: check expansions here */
if (c == '\\')
{
(*p)++;
c = **p;
- switch (tolower(c))
+ switch (g_ascii_tolower(c))
{
case '\\':
case '"': break;
case 'a': c = '\a'; break;
case 'b': c = '\b'; break;
+ case 'f': c = '\f'; break;
case 'n': c = '\n'; break;
case 'r': c = '\r'; break;
case 't': c = '\t'; break;
case 'v': c = '\v'; break;
default:
- /* two-digit hex escape */
- if (tolower(c) == 'x' && isxdigit((*p)[1]) && isxdigit((*p)[2]))
+ /* hex escape, 1-2 digits (\xN or \xNN)
+ *
+ * FIXME: is this useful? Is this right?
+ * the original dbm_gdb.c:unescape_hex_values() used to
+ * read escapes of the form \xNNN and treat them as wide
+ * characters numbers, but this looks weird for a C-like
+ * escape.
+ * Also, note that this doesn't seem to be referenced anywhere
+ * in GDB/MI syntax. Only reference in GDB manual is about
+ * keybindings, which use the syntax implemented here */
+ if (g_ascii_tolower(**p) == 'x' && g_ascii_isxdigit((*p)[1]))
{
- c = (tolower(*++(*p)) - '0') * 16;
- c += (tolower(*++(*p)) - '0');
+ c = (gchar) g_ascii_xdigit_value(*++(*p));
+ if (g_ascii_isxdigit((*p)[1]))
+ c = (gchar) ((c * 16) + g_ascii_xdigit_value(*++(*p)));
}
- /* three-digit octal escape */
- else if (c >= '0' && c <= '3' && isodigit((*p)[1]) && isodigit((*p)[2]))
+ /* octal escape, 1-3 digits (\N, \NN or \NNN) */
+ else if (ascii_isodigit(**p))
{
- c = (* (*p) - '0') * 8 * 8;
- c += (*++(*p) - '0') * 8;
- c += (*++(*p) - '0');
+ int i, v;
+ v = g_ascii_digit_value(**p);
+ for (i = 0; ascii_isodigit((*p)[1]) && i < 2; i++)
+ v = (v * 8) + g_ascii_digit_value(*++(*p));
+ if (v <= 0xff)
+ c = (gchar) v;
+ else
+ {
+ *p = *p - 3; /* put the whole sequence back */
+ c = **p;
+ g_warning("Octal escape sequence out of range: %.4s", *p);
+ }
}
else
{
@@ -185,7 +162,7 @@ static gchar *parse_cstring(const gchar **p)
}
if (**p == '\0')
break;
- g_string_append_c(str, (gchar) c);
+ g_string_append_c(str, c);
(*p)++;
}
if (**p == '"')
@@ -195,16 +172,16 @@ static gchar *parse_cstring(const gchar **p)
}
/* parses: string
- * FIXME: what really is a string? here it uses [a-zA-Z_][a-zA-Z0-9_-.]* but
+ * FIXME: what really is a string? here it uses [a-zA-Z_-.][a-zA-Z0-9_-.]* but
* the docs aren't clear on this */
static gchar *parse_string(const gchar **p)
{
GString *str = g_string_new(NULL);
- if (isalpha(**p) || **p == '_')
+ if (g_ascii_isalpha(**p) || strchr("-_.", **p))
{
g_string_append_c(str, **p);
- for ((*p)++; isalnum(**p) || strchr("-_.", **p); (*p)++)
+ for ((*p)++; g_ascii_isalnum(**p) || strchr("-_.", **p); (*p)++)
g_string_append_c(str, **p);
}
return g_string_free(str, FALSE);
@@ -214,11 +191,11 @@ static gchar *parse_string(const gchar **p)
static gboolean parse_result(struct gdb_mi_result *result, const gchar **p)
{
result->var = parse_string(p);
- while (isspace(**p)) (*p)++;
+ while (g_ascii_isspace(**p)) (*p)++;
if (**p == '=')
{
(*p)++;
- while (isspace(**p)) (*p)++;
+ while (g_ascii_isspace(**p)) (*p)++;
result->val = parse_value(p);
}
return result->var && result->val;
@@ -243,7 +220,7 @@ static struct gdb_mi_value *parse_value(const gchar **p)
while (**p && **p != end)
{
struct gdb_mi_result *item = g_malloc0(sizeof *item);
- while (isspace(**p)) (*p)++;
+ while (g_ascii_isspace(**p)) (*p)++;
if ((item->val = parse_value(p)) ||
parse_result(item, p))
{
@@ -258,7 +235,7 @@ static struct gdb_mi_value *parse_value(const gchar **p)
gdb_mi_result_free(item, TRUE);
break;
}
- while (isspace(**p)) (*p)++;
+ while (g_ascii_isspace(**p)) (*p)++;
if (**p != ',') break;
(*p)++;
}
@@ -303,30 +280,26 @@ struct gdb_mi_record *gdb_mi_record_parse(const gchar *line)
struct gdb_mi_record *record = g_malloc0(sizeof *record);
char nl;
-#ifdef DEBUG
- fprintf(stderr, "line: %s\n", line);
-#endif
-
+ /* FIXME */
if (sscanf(line, "(gdb) %c", &nl) == 1 && (nl == '\r' || nl == '\n'))
record->type = GDB_MI_TYPE_PROMPT;
else
{
/* extract token */
const gchar *token_end = line;
- for (token_end = line; isdigit(*token_end); token_end++)
+ for (token_end = line; g_ascii_isdigit(*token_end); token_end++)
;
if (token_end > line)
{
record->token = g_strndup(line, (gsize)(token_end - line));
line = token_end;
- while (isspace(*line))
- line++;
+ while (g_ascii_isspace(*line)) line++;
}
/* extract record */
record->type = *line;
++line;
- while (isspace(*line)) line++;
+ while (g_ascii_isspace(*line)) line++;
switch (record->type)
{
case '~':
@@ -340,7 +313,7 @@ struct gdb_mi_record *gdb_mi_record_parse(const gchar *line)
* > line) or a quoted C string (which does not contain an
* > implicit newline).
*
- * This adds "raw text" to "c-string", so? */
+ * This adds "raw text" to "c-string"... so? */
record->klass = parse_cstring(&line);
break;
case '^':
@@ -352,14 +325,14 @@ struct gdb_mi_record *gdb_mi_record_parse(const gchar *line)
record->klass = parse_string(&line);
while (*line)
{
- while (isspace(*line)) line++;
+ while (g_ascii_isspace(*line)) line++;
if (*line != ',')
break;
else
{
struct gdb_mi_result *res = g_malloc0(sizeof *res);
line++;
- while (isspace(*line)) line++;
+ while (g_ascii_isspace(*line)) line++;
if (!parse_result(res, &line))
{
g_warning("failed to parse result");
@@ -381,12 +354,6 @@ struct gdb_mi_record *gdb_mi_record_parse(const gchar *line)
}
}
-#ifdef DEBUG
- if (! (gdb_mi_record_matches(record, '^', "done", NULL) &&
- gdb_mi_result_var(record->first, "files", GDB_MI_VAL_LIST)))
- gdb_mi_record_dump(record);
-#endif
-
return record;
}
@@ -422,37 +389,6 @@ const void *gdb_mi_result_var(const struct gdb_mi_result *result, const gchar *n
return NULL;
}
-/* FIXME: */
-const void *gdb_mi_result_var_path(const struct gdb_mi_result *result, const gchar *path, enum gdb_mi_value_type type)
-{
- gchar **chunks = g_strsplit(path, "/", -1);
- gchar **p;
- void *value = NULL;
-
- for (p = chunks; *p; p++)
- {
- const struct gdb_mi_value *val = gdb_mi_result_var_value(result, *p);
- if (! val)
- break;
- if (! p[1])
- {
- if (val->type == type)
- {
- if (val->type == GDB_MI_VAL_STRING)
- value = val->string;
- else if (val->type == GDB_MI_VAL_LIST)
- value = val->list;
- }
- }
- else if (val->type == GDB_MI_VAL_LIST)
- result = val->list;
- else
- break;
- }
- g_strfreev(chunks);
- return value;
-}
-
/* checks whether a record matches, possibly including some string values
* @param record a record
* @param type the expected type of the record
@@ -495,6 +431,44 @@ gboolean gdb_mi_record_matches(const struct gdb_mi_record *record, enum gdb_mi_r
#ifdef TEST
+static void gdb_mi_result_dump(const struct gdb_mi_result *r, gboolean next, gint indent);
+
+static void gdb_mi_value_dump(const struct gdb_mi_value *v, gint indent)
+{
+ fprintf(stderr, "%*stype = %d\n", indent * 2, "", v->type);
+ switch (v->type)
+ {
+ case GDB_MI_VAL_STRING:
+ fprintf(stderr, "%*sstring = %s\n", indent * 2, "", v->string);
+ break;
+ case GDB_MI_VAL_LIST:
+ fprintf(stderr, "%*slist =>\n", indent * 2, "");
+ if (v->list)
+ gdb_mi_result_dump(v->list, TRUE, indent + 1);
+ break;
+ }
+}
+
+static void gdb_mi_result_dump(const struct gdb_mi_result *r, gboolean next, gint indent)
+{
+ fprintf(stderr, "%*svar = %s\n", indent * 2, "", r->var);
+ fprintf(stderr, "%*sval =>\n", indent * 2, "");
+ gdb_mi_value_dump(r->val, indent + 1);
+ if (next && r->next)
+ gdb_mi_result_dump(r->next, next, indent);
+}
+
+static void gdb_mi_record_dump(const struct gdb_mi_record *record)
+{
+ fprintf(stderr, "record =>\n");
+ fprintf(stderr, " type = '%c' (%d)\n", record->type ? record->type : '0', record->type);
+ fprintf(stderr, " token = %s\n", record->token);
+ fprintf(stderr, " class = %s\n", record->klass);
+ fprintf(stderr, " results =>\n");
+ if (record->first)
+ gdb_mi_result_dump(record->first, TRUE, 2);
+}
+
int main(void)
{
char buf[256] = {0};
--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).
More information about the Plugins-Commits
mailing list