Patchwork gdbstub: Implement "Xfer:spaces" requests. This is a part of Codebench IDE integration.

login
register
mail settings
Submitter Alex_Rozenman@mentor.com
Date Jan. 7, 2013, 11:31 p.m.
Message ID <1357601496-31718-1-git-send-email-Alex_Rozenman@mentor.com>
Download mbox | patch
Permalink /patch/210269/
State New
Headers show

Comments

Alex_Rozenman@mentor.com - Jan. 7, 2013, 11:31 p.m.
Signed-off-by: Alex Rozenman <Alex_Rozenman@mentor.com>
---
 gdbstub.c |  113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 113 insertions(+)
Stefan Hajnoczi - Jan. 9, 2013, 8:50 a.m.
On Tue, Jan 08, 2013 at 01:31:36AM +0200, Alex Rozenman wrote:
> Signed-off-by: Alex Rozenman <Alex_Rozenman@mentor.com>
> ---
>  gdbstub.c |  113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 113 insertions(+)

Also worth CCing Jan Kiszka on gdbstub changes.

> diff --git a/gdbstub.c b/gdbstub.c
> index a8dd437..564bde1 100644
> --- a/gdbstub.c
> +++ b/gdbstub.c
> @@ -1839,6 +1839,90 @@ static const char *get_feature_xml(const char *p, const char **newp)
>      }
>      return name ? xml_builtin[i][1] : NULL;
>  }
> +
> +typedef struct XferSpaceReq {
> +    int is_write;
> +    char annex[32];
> +    uint64_t offset;
> +    unsigned length;
> +    char* data; /* Data buffer for write. */
> +} XferSpaceReq;
> +
> +static int remote_unescape_input(const char* begin, const char* end, char* out)
> +{
> +    int escaped = 0;
> +    const char *p, *out_begin = out;
> +    for (p = begin; p != end; ++p) {
> +        char b = *p;
> +        if (escaped) {
> +            *out++ = b ^ 0x20;
> +            escaped = 0;
> +	} else if (b == '}') {
> +            escaped = 1;
> +        } else {
> +            *out++ = b;
> +        }
> +    }
> +    if (escaped) {
> +        fprintf(stderr, "Unmatched escape character in target response.\n");
> +    }
> +    return out - out_begin;
> +}
> +
> +static int parse_xfer_spaces_req(const char* begin, const char* end, XferSpaceReq* req)
> +{
> +    const char *p;
> +    char *out, *limit;
> +
> +    p = begin;
> +
> +    /* Read read/write word. */
> +    if (strncmp(p, "read", 4) == 0) {
> +        req->is_write = 0;
> +        p += 4;
> +    } else if (strncmp(p, "write", 5) == 0) {
> +        req->is_write = 1;
> +        p += 5;
> +    } else {
> +        return 0; /* Malformed. */
> +    }
> +
> +    /* Consume the next colon. */
> +    if (*p != ':') return 0; /* Malformed. */
> +    p++;
> +
> +    /* Read the annex designator. */
> +    out = req->annex;
> +    limit = out + sizeof(req->annex);
> +    while (*p != ':' && out != limit) {
> +        *out++ = *p++;
> +    }
> +    if (out == limit) return 0; /* Too long. */
> +    *out = (char)0;
> +
> +    /* Consume the next colon. */
> +    if (*p != ':') return 0; /* Malformed. */
> +    p++;
> +
> +    /* Read the offset */
> +    req->offset = strtoul(p, (char **)&p, 16);
> +
> +    if (req->is_write) {
> +        if (*p != ':') return 0; /* Should be colon. */
> +        p++;
> +        req->length = remote_unescape_input(p, end, req->data);
> +    } else {
> +        if (*p != ',') return 0; /* Should be comma. */
> +        p++;
> +        /* Read the length */
> +        req->length = strtoul(p, (char **)&p, 16);
> +        if (!req->length) return 0; /* Zero length request. */
> +    }
> +
> +    return 1;
> +}
> +
> +
>  #endif
>  
>  static int gdb_read_register(CPUArchState *env, uint8_t *mem_buf, int reg)
> @@ -2467,6 +2551,35 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
>              }
>              put_packet_binary(s, buf, len + 1);
>              break;
> +        } else if (strncmp(p, "Xfer:spaces:", 12) == 0) {
> +            /* The following code is implemented according to:
> +               http://sourceware.org/gdb/onlinedocs/gdb/General-Query-Packets.html */
> +            XferSpaceReq req;
> +            req.data = (char*)mem_buf;
> +            if (!parse_xfer_spaces_req(p + 12, s->line_buf + s->line_buf_index, &req)) {
> +                fprintf(stderr, "gdbstub: Malformed Xfer '%s'\n", p);
> +                put_packet(s, "E00");
> +                break;
> +            }
> +            if (strcmp(req.annex, "memory") != 0) {
> +                /* Only annex "memory" is currently supported. */
> +                put_packet(s, "E14");
> +                break;
> +            }
> +            if (target_memory_rw_debug(s->g_cpu, req.offset, mem_buf, req.length,
> +                                       req.is_write) != 0) {
> +                put_packet(s, "E14");
> +                break;
> +            }
> +            if (req.is_write) {
> +                sprintf(buf, "%02X", req.length);
> +                put_packet(s, buf);
> +            } else {
> +                buf[0] = 'm';
> +                memtox(buf + 1, (const char*)mem_buf, req.length);
> +                put_packet_binary(s, buf, req.length + 1);
> +            }
> +            break;
>          }
>  #endif
>          /* Unrecognised 'q' command.  */
> -- 
> 1.7.9.6
> 
>
Blue Swirl - Jan. 9, 2013, 9:10 p.m.
On Mon, Jan 7, 2013 at 11:31 PM, Alex Rozenman <Alex_Rozenman@mentor.com> wrote:
> Signed-off-by: Alex Rozenman <Alex_Rozenman@mentor.com>
> ---
>  gdbstub.c |  113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 113 insertions(+)
>
> diff --git a/gdbstub.c b/gdbstub.c
> index a8dd437..564bde1 100644
> --- a/gdbstub.c
> +++ b/gdbstub.c
> @@ -1839,6 +1839,90 @@ static const char *get_feature_xml(const char *p, const char **newp)
>      }
>      return name ? xml_builtin[i][1] : NULL;
>  }
> +
> +typedef struct XferSpaceReq {
> +    int is_write;
> +    char annex[32];
> +    uint64_t offset;
> +    unsigned length;
> +    char* data; /* Data buffer for write. */
> +} XferSpaceReq;
> +
> +static int remote_unescape_input(const char* begin, const char* end, char* out)
> +{
> +    int escaped = 0;
> +    const char *p, *out_begin = out;
> +    for (p = begin; p != end; ++p) {
> +        char b = *p;
> +        if (escaped) {
> +            *out++ = b ^ 0x20;
> +            escaped = 0;
> +       } else if (b == '}') {
> +            escaped = 1;
> +        } else {
> +            *out++ = b;
> +        }
> +    }
> +    if (escaped) {
> +        fprintf(stderr, "Unmatched escape character in target response.\n");
> +    }
> +    return out - out_begin;
> +}
> +
> +static int parse_xfer_spaces_req(const char* begin, const char* end, XferSpaceReq* req)
> +{
> +    const char *p;
> +    char *out, *limit;
> +
> +    p = begin;
> +
> +    /* Read read/write word. */
> +    if (strncmp(p, "read", 4) == 0) {
> +        req->is_write = 0;
> +        p += 4;
> +    } else if (strncmp(p, "write", 5) == 0) {
> +        req->is_write = 1;
> +        p += 5;
> +    } else {
> +        return 0; /* Malformed. */
> +    }
> +
> +    /* Consume the next colon. */
> +    if (*p != ':') return 0; /* Malformed. */

The line is malformed, according to the coding style, it should be
if (*p != ':')  {
    return 0;
}

> +    p++;
> +
> +    /* Read the annex designator. */
> +    out = req->annex;
> +    limit = out + sizeof(req->annex);
> +    while (*p != ':' && out != limit) {
> +        *out++ = *p++;
> +    }
> +    if (out == limit) return 0; /* Too long. */

Also here and several other places. Please fix.

> +    *out = (char)0;
> +
> +    /* Consume the next colon. */
> +    if (*p != ':') return 0; /* Malformed. */
> +    p++;
> +
> +    /* Read the offset */
> +    req->offset = strtoul(p, (char **)&p, 16);
> +
> +    if (req->is_write) {
> +        if (*p != ':') return 0; /* Should be colon. */
> +        p++;
> +        req->length = remote_unescape_input(p, end, req->data);
> +    } else {
> +        if (*p != ',') return 0; /* Should be comma. */
> +        p++;
> +        /* Read the length */
> +        req->length = strtoul(p, (char **)&p, 16);
> +        if (!req->length) return 0; /* Zero length request. */
> +    }
> +
> +    return 1;
> +}
> +
> +
>  #endif
>
>  static int gdb_read_register(CPUArchState *env, uint8_t *mem_buf, int reg)
> @@ -2467,6 +2551,35 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
>              }
>              put_packet_binary(s, buf, len + 1);
>              break;
> +        } else if (strncmp(p, "Xfer:spaces:", 12) == 0) {
> +            /* The following code is implemented according to:
> +               http://sourceware.org/gdb/onlinedocs/gdb/General-Query-Packets.html */
> +            XferSpaceReq req;
> +            req.data = (char*)mem_buf;
> +            if (!parse_xfer_spaces_req(p + 12, s->line_buf + s->line_buf_index, &req)) {
> +                fprintf(stderr, "gdbstub: Malformed Xfer '%s'\n", p);

I'm not sure this message will be useful for the user, how about using
qemu_log(LOG_UNIMP,...)?

> +                put_packet(s, "E00");
> +                break;
> +            }
> +            if (strcmp(req.annex, "memory") != 0) {
> +                /* Only annex "memory" is currently supported. */
> +                put_packet(s, "E14");
> +                break;
> +            }
> +            if (target_memory_rw_debug(s->g_cpu, req.offset, mem_buf, req.length,
> +                                       req.is_write) != 0) {
> +                put_packet(s, "E14");
> +                break;
> +            }
> +            if (req.is_write) {
> +                sprintf(buf, "%02X", req.length);

Please use snprintf().

> +                put_packet(s, buf);
> +            } else {
> +                buf[0] = 'm';
> +                memtox(buf + 1, (const char*)mem_buf, req.length);
> +                put_packet_binary(s, buf, req.length + 1);
> +            }
> +            break;
>          }
>  #endif
>          /* Unrecognised 'q' command.  */
> --
> 1.7.9.6
>
>
Jan Kiszka - Jan. 22, 2013, 4:56 p.m.
On 2013-01-09 09:50, Stefan Hajnoczi wrote:
> On Tue, Jan 08, 2013 at 01:31:36AM +0200, Alex Rozenman wrote:
>> Signed-off-by: Alex Rozenman <Alex_Rozenman@mentor.com>
>> ---
>>  gdbstub.c |  113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 113 insertions(+)
> 
> Also worth CCing Jan Kiszka on gdbstub changes.
> 
>> diff --git a/gdbstub.c b/gdbstub.c
>> index a8dd437..564bde1 100644
>> --- a/gdbstub.c
>> +++ b/gdbstub.c
>> @@ -1839,6 +1839,90 @@ static const char *get_feature_xml(const char *p, const char **newp)
>>      }
>>      return name ? xml_builtin[i][1] : NULL;
>>  }
>> +
>> +typedef struct XferSpaceReq {
>> +    int is_write;
>> +    char annex[32];
>> +    uint64_t offset;
>> +    unsigned length;
>> +    char* data; /* Data buffer for write. */
>> +} XferSpaceReq;
>> +
>> +static int remote_unescape_input(const char* begin, const char* end, char* out)
>> +{
>> +    int escaped = 0;
>> +    const char *p, *out_begin = out;
>> +    for (p = begin; p != end; ++p) {
>> +        char b = *p;
>> +        if (escaped) {
>> +            *out++ = b ^ 0x20;
>> +            escaped = 0;
>> +	} else if (b == '}') {
>> +            escaped = 1;
>> +        } else {
>> +            *out++ = b;
>> +        }
>> +    }
>> +    if (escaped) {
>> +        fprintf(stderr, "Unmatched escape character in target response.\n");
>> +    }
>> +    return out - out_begin;
>> +}
>> +
>> +static int parse_xfer_spaces_req(const char* begin, const char* end, XferSpaceReq* req)
>> +{
>> +    const char *p;
>> +    char *out, *limit;
>> +
>> +    p = begin;
>> +
>> +    /* Read read/write word. */
>> +    if (strncmp(p, "read", 4) == 0) {
>> +        req->is_write = 0;
>> +        p += 4;
>> +    } else if (strncmp(p, "write", 5) == 0) {
>> +        req->is_write = 1;
>> +        p += 5;
>> +    } else {
>> +        return 0; /* Malformed. */
>> +    }
>> +
>> +    /* Consume the next colon. */
>> +    if (*p != ':') return 0; /* Malformed. */
>> +    p++;
>> +
>> +    /* Read the annex designator. */
>> +    out = req->annex;
>> +    limit = out + sizeof(req->annex);
>> +    while (*p != ':' && out != limit) {
>> +        *out++ = *p++;
>> +    }
>> +    if (out == limit) return 0; /* Too long. */
>> +    *out = (char)0;
>> +
>> +    /* Consume the next colon. */
>> +    if (*p != ':') return 0; /* Malformed. */
>> +    p++;
>> +
>> +    /* Read the offset */
>> +    req->offset = strtoul(p, (char **)&p, 16);
>> +
>> +    if (req->is_write) {
>> +        if (*p != ':') return 0; /* Should be colon. */
>> +        p++;
>> +        req->length = remote_unescape_input(p, end, req->data);
>> +    } else {
>> +        if (*p != ',') return 0; /* Should be comma. */
>> +        p++;
>> +        /* Read the length */
>> +        req->length = strtoul(p, (char **)&p, 16);
>> +        if (!req->length) return 0; /* Zero length request. */
>> +    }
>> +
>> +    return 1;
>> +}
>> +
>> +
>>  #endif
>>  
>>  static int gdb_read_register(CPUArchState *env, uint8_t *mem_buf, int reg)
>> @@ -2467,6 +2551,35 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
>>              }
>>              put_packet_binary(s, buf, len + 1);
>>              break;
>> +        } else if (strncmp(p, "Xfer:spaces:", 12) == 0) {
>> +            /* The following code is implemented according to:
>> +               http://sourceware.org/gdb/onlinedocs/gdb/General-Query-Packets.html */

I do not find what you implement here on that website or in gdb's git.
Is there an even more recent version? Is that protocol actually approved
already?

Jan

>> +            XferSpaceReq req;
>> +            req.data = (char*)mem_buf;
>> +            if (!parse_xfer_spaces_req(p + 12, s->line_buf + s->line_buf_index, &req)) {
>> +                fprintf(stderr, "gdbstub: Malformed Xfer '%s'\n", p);
>> +                put_packet(s, "E00");
>> +                break;
>> +            }
>> +            if (strcmp(req.annex, "memory") != 0) {
>> +                /* Only annex "memory" is currently supported. */
>> +                put_packet(s, "E14");
>> +                break;
>> +            }
>> +            if (target_memory_rw_debug(s->g_cpu, req.offset, mem_buf, req.length,
>> +                                       req.is_write) != 0) {
>> +                put_packet(s, "E14");
>> +                break;
>> +            }
>> +            if (req.is_write) {
>> +                sprintf(buf, "%02X", req.length);
>> +                put_packet(s, buf);
>> +            } else {
>> +                buf[0] = 'm';
>> +                memtox(buf + 1, (const char*)mem_buf, req.length);
>> +                put_packet_binary(s, buf, req.length + 1);
>> +            }
>> +            break;
>>          }
>>  #endif
>>          /* Unrecognised 'q' command.  */
>> -- 
>> 1.7.9.6
>>
>>

Patch

diff --git a/gdbstub.c b/gdbstub.c
index a8dd437..564bde1 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1839,6 +1839,90 @@  static const char *get_feature_xml(const char *p, const char **newp)
     }
     return name ? xml_builtin[i][1] : NULL;
 }
+
+typedef struct XferSpaceReq {
+    int is_write;
+    char annex[32];
+    uint64_t offset;
+    unsigned length;
+    char* data; /* Data buffer for write. */
+} XferSpaceReq;
+
+static int remote_unescape_input(const char* begin, const char* end, char* out)
+{
+    int escaped = 0;
+    const char *p, *out_begin = out;
+    for (p = begin; p != end; ++p) {
+        char b = *p;
+        if (escaped) {
+            *out++ = b ^ 0x20;
+            escaped = 0;
+	} else if (b == '}') {
+            escaped = 1;
+        } else {
+            *out++ = b;
+        }
+    }
+    if (escaped) {
+        fprintf(stderr, "Unmatched escape character in target response.\n");
+    }
+    return out - out_begin;
+}
+
+static int parse_xfer_spaces_req(const char* begin, const char* end, XferSpaceReq* req)
+{
+    const char *p;
+    char *out, *limit;
+
+    p = begin;
+
+    /* Read read/write word. */
+    if (strncmp(p, "read", 4) == 0) {
+        req->is_write = 0;
+        p += 4;
+    } else if (strncmp(p, "write", 5) == 0) {
+        req->is_write = 1;
+        p += 5;
+    } else {
+        return 0; /* Malformed. */
+    }
+
+    /* Consume the next colon. */
+    if (*p != ':') return 0; /* Malformed. */
+    p++;
+
+    /* Read the annex designator. */
+    out = req->annex;
+    limit = out + sizeof(req->annex);
+    while (*p != ':' && out != limit) {
+        *out++ = *p++;
+    }
+    if (out == limit) return 0; /* Too long. */
+    *out = (char)0;
+
+    /* Consume the next colon. */
+    if (*p != ':') return 0; /* Malformed. */
+    p++;
+
+    /* Read the offset */
+    req->offset = strtoul(p, (char **)&p, 16);
+
+    if (req->is_write) {
+        if (*p != ':') return 0; /* Should be colon. */
+        p++;
+        req->length = remote_unescape_input(p, end, req->data);
+    } else {
+        if (*p != ',') return 0; /* Should be comma. */
+        p++;
+        /* Read the length */
+        req->length = strtoul(p, (char **)&p, 16);
+        if (!req->length) return 0; /* Zero length request. */
+    }
+
+    return 1;
+}
+
+
 #endif
 
 static int gdb_read_register(CPUArchState *env, uint8_t *mem_buf, int reg)
@@ -2467,6 +2551,35 @@  static int gdb_handle_packet(GDBState *s, const char *line_buf)
             }
             put_packet_binary(s, buf, len + 1);
             break;
+        } else if (strncmp(p, "Xfer:spaces:", 12) == 0) {
+            /* The following code is implemented according to:
+               http://sourceware.org/gdb/onlinedocs/gdb/General-Query-Packets.html */
+            XferSpaceReq req;
+            req.data = (char*)mem_buf;
+            if (!parse_xfer_spaces_req(p + 12, s->line_buf + s->line_buf_index, &req)) {
+                fprintf(stderr, "gdbstub: Malformed Xfer '%s'\n", p);
+                put_packet(s, "E00");
+                break;
+            }
+            if (strcmp(req.annex, "memory") != 0) {
+                /* Only annex "memory" is currently supported. */
+                put_packet(s, "E14");
+                break;
+            }
+            if (target_memory_rw_debug(s->g_cpu, req.offset, mem_buf, req.length,
+                                       req.is_write) != 0) {
+                put_packet(s, "E14");
+                break;
+            }
+            if (req.is_write) {
+                sprintf(buf, "%02X", req.length);
+                put_packet(s, buf);
+            } else {
+                buf[0] = 'm';
+                memtox(buf + 1, (const char*)mem_buf, req.length);
+                put_packet_binary(s, buf, req.length + 1);
+            }
+            break;
         }
 #endif
         /* Unrecognised 'q' command.  */