diff mbox series

[09/14] gdbserver: lexer fixes

Message ID 20220314041735.542867-11-npiggin@gmail.com
State New
Headers show
Series gdbserver fixes and POWER10 support | expand

Commit Message

Nicholas Piggin March 14, 2022, 4:17 a.m. UTC
The lexer is coded in a funny way that ignores all packets that don't
match a command or interrupt to start with, and then expects a command
or ack/nack following an interrupt. This results in leading ack/nack not
being matched as such which is fine because they're ignored but makes
things confusing. But it also results in command errors for the command
following an interrupt.

All this complexity and problems seems to have arisen because the
trailing NUL termination is passed in to the buffer which has made
everything more complicated.

Fix this by not passing in the trailing NUL, and rewriting the lexer
so it always matches one of a command, interrupt, ack, or nack at
the high level. Command / crc reset is done at entry to the command
state.

Some additional checks and debugging messages are added.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
 src/gdb_parser.rl           |  64 +++++---
 src/gdb_parser_precompile.c | 318 +++++++++++++++++++-----------------
 2 files changed, 216 insertions(+), 166 deletions(-)
diff mbox series

Patch

diff --git a/src/gdb_parser.rl b/src/gdb_parser.rl
index 93213e4..daa4167 100644
--- a/src/gdb_parser.rl
+++ b/src/gdb_parser.rl
@@ -1,9 +1,11 @@ 
-#include <stdio.h>
+#include <stdbool.h>
 #include <stdint.h>
+#include <stdio.h>
 #include <string.h>
 #include <assert.h>
 
 #include "src/pdbgproxy.h"
+#include "debug.h"
 
 %%{
 	machine gdb;
@@ -14,6 +16,7 @@ 
 		data = stack;
 		memset(stack, 0, sizeof(stack));
 		crc = 0;
+		PR_INFO("RAGEL: CRC reset\n");
 	}
 
 	action crc {
@@ -39,10 +42,10 @@ 
 	action end {
 		/* *data should point to the CRC */
 		if (crc != *data) {
-			printf("CRC error\n");
+			printf("CRC error cmd %d\n", cmd);
 			send_nack(priv);
 		} else {
-			printf("Cmd %d\n", cmd);
+			PR_INFO("Cmd %d\n", cmd);
 			send_ack(priv);
 
 			/* Push the response onto the stack */
@@ -51,7 +54,8 @@ 
 			else
 				*data = 0;
 
-			command_callbacks[cmd](stack, priv);
+			if (command_callbacks)
+				command_callbacks[cmd](stack, priv);
 		}
 	}
 
@@ -60,7 +64,7 @@ 
 		   ','
 		   xdigit+ $hex_digit %push);
 
-	put_mem = ('M' any* @{cmd = PUT_MEM;}
+	put_mem = ('M' (any & ^'#')* @{cmd = PUT_MEM;}
 		   xdigit+ $hex_digit %push
 		   ','
 		   xdigit+ $hex_digit %push
@@ -74,7 +78,7 @@ 
 
 	stop_reason = ('?' @{cmd = STOP_REASON;});
 
-	set_thread = ('H' any* @{cmd = SET_THREAD;});
+	set_thread = ('H' (any & ^'#')* @{cmd = SET_THREAD;});
 
 	detach = ('D' @{cmd = DETACH;}
 		     xdigit+ $hex_digit %push);
@@ -82,28 +86,29 @@ 
 	# TODO: We don't actually listen to what's supported
 	q_attached = ('qAttached:' xdigit* @{rsp = "1";});
 	q_C = ('qC' @{rsp = "QC1";});
-	q_supported = ('qSupported:' any* @{rsp = "multiprocess+;vContSupported+";});
+	q_supported = ('qSupported:' (any & ^'#')* >{rsp = "multiprocess+;vContSupported+";});
 	qf_threadinfo = ('qfThreadInfo' @{rsp = "m1l";});
 
 	# vCont packet parsing
 	v_contq = ('vCont?' @{rsp = "vCont;c;C;s;S";});
-	v_contc = ('vCont;c' any* @{cmd = V_CONTC;});
-	v_conts = ('vCont;s' any* @{cmd = V_CONTS;});
+	v_contc = ('vCont;c' (any & ^'#')* @{cmd = V_CONTC;});
+	v_conts = ('vCont;s' (any & ^'#')* @{cmd = V_CONTS;});
+	unknown = ((any & ^'#')*);
 
-	interrupt = (3 @{command_callbacks[INTERRUPT](stack, priv);});
+	interrupt = (3 @{ if (command_callbacks) command_callbacks[INTERRUPT](stack, priv); PR_INFO("RAGEL:interrupt\n");});
 
 	commands = (get_mem | get_gprs | get_spr | stop_reason | set_thread |
 		    q_attached | q_C | q_supported | qf_threadinfo | q_C |
-		    v_contq | v_contc | v_conts | put_mem | detach );
+		    v_contq | v_contc | v_conts | put_mem | detach | unknown );
 
-	cmd = ((commands & ^'#'*) | ^'#'*) $crc
-	      ('#' xdigit{2} $hex_digit @end);
+	cmd = (('$' ((commands & ^'#'*) >reset $crc)
+	      ('#' xdigit{2} $hex_digit @end)) >{PR_INFO("RAGEL:cmd\n");});
 
 	# We ignore ACK/NACK for the moment
-	ack = ('+');
-	nack = ('-');
+	ack = ('+' >{PR_INFO("RAGEL:ack\n");});
+	nack = ('-' >{PR_INFO("RAGEL:nack\n");});
 
-	main := (( ^('$' | interrupt)*('$' | interrupt) @reset) (cmd | ack | nack))*;
+	main := (cmd | interrupt | ack | nack)*;
 
 }%%
 
@@ -113,7 +118,7 @@  static char *rsp;
 static uint8_t crc;
 static int cs;
 
-command_cb *command_callbacks;
+static command_cb *command_callbacks;
 
 %%write data;
 
@@ -127,20 +132,39 @@  void parser_init(command_cb *callbacks)
 int parse_buffer(char *buf, size_t len, void *priv)
 {
 	char *p = buf;
-	char *pe = p + len + 1;
+	char *pe = p + len;
 
 	%%write exec;
 
+	if (cs == gdb_error) {
+		printf("parse error\n");
+		return -1;
+	}
+
 	return 0;
 }
 
 #if 0
+void send_nack(void *priv)
+{
+	printf("Send: -\n");
+}
+
+void send_ack(void *priv)
+{
+	printf("Send: +\n");
+}
+
 int main(int argc, char **argv)
 {
 	parser_init(NULL);
 
-	if (argc > 1)
-		parse_buffer(argv[1], strlen(argv[1]), NULL);
+	if (argc > 1) {
+		int i;
+		for (i = 1; i < argc; i++)
+			parse_buffer(argv[i], strlen(argv[i]), NULL);
+	}
+
 	return 0;
 }
 #endif
diff --git a/src/gdb_parser_precompile.c b/src/gdb_parser_precompile.c
index cee2fd0..b8cdbc1 100644
--- a/src/gdb_parser_precompile.c
+++ b/src/gdb_parser_precompile.c
@@ -1,14 +1,16 @@ 
 
 #line 1 "src/gdb_parser.rl"
-#include <stdio.h>
+#include <stdbool.h>
 #include <stdint.h>
+#include <stdio.h>
 #include <string.h>
 #include <assert.h>
 
 #include "src/pdbgproxy.h"
+#include "debug.h"
 
 
-#line 108 "src/gdb_parser.rl"
+#line 113 "src/gdb_parser.rl"
 
 
 static enum gdb_command cmd = NONE;
@@ -17,173 +19,164 @@  static char *rsp;
 static uint8_t crc;
 static int cs;
 
-command_cb *command_callbacks;
+static command_cb *command_callbacks;
 
 
-#line 24 "src/gdb_parser.c"
+#line 26 "src/gdb_parser.c"
 static const char _gdb_actions[] = {
 	0, 1, 0, 1, 1, 1, 2, 1, 
-	3, 2, 1, 0, 2, 2, 1, 2, 
-	3, 1, 2, 3, 4, 2, 5, 1, 
-	2, 6, 1, 2, 7, 1, 2, 8, 
-	1, 2, 9, 1, 2, 10, 1, 2, 
-	11, 1, 2, 12, 1, 2, 13, 1, 
-	2, 14, 1, 2, 15, 1, 2, 16, 
-	1, 2, 17, 1, 2, 18, 1, 2, 
-	19, 0, 3, 1, 19, 0, 3, 6, 
+	3, 1, 14, 1, 19, 1, 20, 1, 
+	21, 1, 22, 2, 0, 1, 2, 2, 
+	1, 2, 3, 1, 2, 3, 4, 2, 
+	6, 1, 2, 10, 1, 2, 12, 1, 
+	2, 13, 1, 2, 14, 1, 2, 15, 
+	1, 2, 16, 1, 2, 17, 1, 2, 
+	18, 1, 3, 0, 5, 1, 3, 0, 
+	7, 1, 3, 0, 8, 1, 3, 0, 
+	9, 1, 3, 0, 11, 1, 3, 6, 
 	2, 1, 3, 6, 3, 1
 };
 
 static const unsigned char _gdb_key_offsets[] = {
-	0, 0, 2, 14, 15, 21, 27, 30, 
-	38, 46, 53, 60, 61, 68, 76, 83, 
-	92, 99, 107, 114, 122, 127, 129, 131, 
-	133, 135, 137, 139, 141, 143, 150, 152, 
+	0, 0, 10, 11, 17, 23, 30, 37, 
+	38, 45, 53, 60, 69, 76, 84, 91, 
+	99, 104, 106, 108, 110, 112, 114, 116, 
+	118, 120, 127, 129, 131, 133, 135, 137, 
+	139, 141, 143, 145, 146, 148, 150, 152, 
 	154, 156, 158, 160, 162, 164, 166, 168, 
-	169, 171, 173, 175, 177, 179, 181, 183, 
-	185, 187, 189, 191, 193, 195, 197, 200, 
-	203, 204, 205, 207
+	170, 172, 174, 177, 180, 181, 182
 };
 
 static const char _gdb_trans_keys[] = {
-	3, 36, 35, 43, 45, 63, 68, 72, 
-	77, 103, 109, 112, 113, 118, 35, 48, 
-	57, 65, 70, 97, 102, 48, 57, 65, 
-	70, 97, 102, 3, 35, 36, 3, 36, 
-	48, 57, 65, 70, 97, 102, 3, 36, 
+	35, 63, 68, 72, 77, 103, 109, 112, 
+	113, 118, 35, 48, 57, 65, 70, 97, 
+	102, 48, 57, 65, 70, 97, 102, 35, 
 	48, 57, 65, 70, 97, 102, 35, 48, 
+	57, 65, 70, 97, 102, 35, 35, 48, 
+	57, 65, 70, 97, 102, 35, 44, 48, 
+	57, 65, 70, 97, 102, 35, 48, 57, 
+	65, 70, 97, 102, 35, 44, 58, 48, 
 	57, 65, 70, 97, 102, 35, 48, 57, 
-	65, 70, 97, 102, 35, 35, 48, 57, 
 	65, 70, 97, 102, 35, 44, 48, 57, 
 	65, 70, 97, 102, 35, 48, 57, 65, 
-	70, 97, 102, 35, 44, 58, 48, 57, 
-	65, 70, 97, 102, 35, 48, 57, 65, 
 	70, 97, 102, 35, 44, 48, 57, 65, 
-	70, 97, 102, 35, 48, 57, 65, 70, 
-	97, 102, 35, 44, 48, 57, 65, 70, 
-	97, 102, 35, 65, 67, 83, 102, 35, 
-	116, 35, 116, 35, 97, 35, 99, 35, 
-	104, 35, 101, 35, 100, 35, 58, 35, 
-	48, 57, 65, 70, 97, 102, 35, 117, 
-	35, 112, 35, 112, 35, 111, 35, 114, 
-	35, 116, 35, 101, 35, 100, 35, 58, 
-	35, 35, 84, 35, 104, 35, 114, 35, 
-	101, 35, 97, 35, 100, 35, 73, 35, 
-	110, 35, 102, 35, 111, 35, 67, 35, 
-	111, 35, 110, 35, 116, 35, 59, 63, 
-	35, 99, 115, 35, 35, 3, 36, 3, 
-	35, 36, 0
+	70, 97, 102, 35, 65, 67, 83, 102, 
+	35, 116, 35, 116, 35, 97, 35, 99, 
+	35, 104, 35, 101, 35, 100, 35, 58, 
+	35, 48, 57, 65, 70, 97, 102, 35, 
+	117, 35, 112, 35, 112, 35, 111, 35, 
+	114, 35, 116, 35, 101, 35, 100, 35, 
+	58, 35, 35, 84, 35, 104, 35, 114, 
+	35, 101, 35, 97, 35, 100, 35, 73, 
+	35, 110, 35, 102, 35, 111, 35, 67, 
+	35, 111, 35, 110, 35, 116, 35, 59, 
+	63, 35, 99, 115, 35, 35, 3, 36, 
+	43, 45, 0
 };
 
 static const char _gdb_single_lengths[] = {
-	0, 2, 12, 1, 0, 0, 3, 2, 
-	2, 1, 1, 1, 1, 2, 1, 3, 
-	1, 2, 1, 2, 5, 2, 2, 2, 
-	2, 2, 2, 2, 2, 1, 2, 2, 
-	2, 2, 2, 2, 2, 2, 2, 1, 
+	0, 10, 1, 0, 0, 1, 1, 1, 
+	1, 2, 1, 3, 1, 2, 1, 2, 
+	5, 2, 2, 2, 2, 2, 2, 2, 
+	2, 1, 2, 2, 2, 2, 2, 2, 
+	2, 2, 2, 1, 2, 2, 2, 2, 
 	2, 2, 2, 2, 2, 2, 2, 2, 
-	2, 2, 2, 2, 2, 2, 3, 3, 
-	1, 1, 2, 3
+	2, 2, 3, 3, 1, 1, 4
 };
 
 static const char _gdb_range_lengths[] = {
-	0, 0, 0, 0, 3, 3, 0, 3, 
-	3, 3, 3, 0, 3, 3, 3, 3, 
-	3, 3, 3, 3, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 3, 0, 0, 
+	0, 0, 0, 3, 3, 3, 3, 0, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 3, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0
+	0, 0, 0, 0, 0, 0, 0
 };
 
-static const short _gdb_index_offsets[] = {
-	0, 0, 3, 16, 18, 22, 26, 30, 
-	36, 42, 47, 52, 54, 59, 65, 70, 
-	77, 82, 88, 93, 99, 105, 108, 111, 
-	114, 117, 120, 123, 126, 129, 134, 137, 
-	140, 143, 146, 149, 152, 155, 158, 161, 
-	163, 166, 169, 172, 175, 178, 181, 184, 
-	187, 190, 193, 196, 199, 202, 205, 209, 
-	213, 215, 217, 220
+static const unsigned char _gdb_index_offsets[] = {
+	0, 0, 11, 13, 17, 21, 26, 31, 
+	33, 38, 44, 49, 56, 61, 67, 72, 
+	78, 84, 87, 90, 93, 96, 99, 102, 
+	105, 108, 113, 116, 119, 122, 125, 128, 
+	131, 134, 137, 140, 142, 145, 148, 151, 
+	154, 157, 160, 163, 166, 169, 172, 175, 
+	178, 181, 184, 188, 192, 194, 196
 };
 
 static const char _gdb_indicies[] = {
-	1, 2, 0, 4, 5, 5, 6, 7, 
-	8, 9, 10, 11, 12, 13, 14, 3, 
-	4, 3, 15, 15, 15, 16, 17, 17, 
-	17, 16, 19, 20, 21, 18, 1, 2, 
-	22, 22, 22, 0, 1, 2, 17, 17, 
-	17, 0, 4, 23, 23, 23, 3, 24, 
-	23, 23, 23, 3, 4, 25, 4, 27, 
-	27, 27, 26, 4, 28, 27, 27, 27, 
-	26, 4, 29, 29, 29, 26, 4, 28, 
-	30, 29, 29, 29, 26, 4, 31, 31, 
-	31, 26, 24, 28, 31, 31, 31, 26, 
-	4, 32, 32, 32, 3, 4, 33, 32, 
-	32, 32, 3, 4, 34, 35, 36, 37, 
-	3, 4, 38, 3, 4, 39, 3, 4, 
-	40, 3, 4, 41, 3, 4, 42, 3, 
-	4, 43, 3, 4, 44, 3, 4, 45, 
-	3, 4, 46, 46, 46, 3, 4, 47, 
-	3, 4, 48, 3, 4, 49, 3, 4, 
-	50, 3, 4, 51, 3, 4, 52, 3, 
-	4, 53, 3, 4, 54, 3, 4, 55, 
-	3, 4, 56, 4, 57, 3, 4, 58, 
-	3, 4, 59, 3, 4, 60, 3, 4, 
-	61, 3, 4, 62, 3, 4, 63, 3, 
-	4, 64, 3, 4, 65, 3, 4, 66, 
-	3, 4, 67, 3, 4, 68, 3, 4, 
-	69, 3, 4, 70, 3, 4, 71, 72, 
-	3, 4, 73, 74, 3, 4, 75, 4, 
-	76, 1, 2, 0, 19, 20, 21, 18, 
-	0
+	1, 2, 3, 4, 5, 6, 7, 8, 
+	9, 10, 0, 12, 11, 13, 13, 13, 
+	14, 15, 15, 15, 14, 12, 16, 16, 
+	16, 11, 17, 16, 16, 16, 11, 12, 
+	18, 12, 20, 20, 20, 19, 12, 21, 
+	20, 20, 20, 19, 12, 22, 22, 22, 
+	19, 12, 21, 23, 22, 22, 22, 19, 
+	12, 24, 24, 24, 19, 17, 21, 24, 
+	24, 24, 19, 12, 25, 25, 25, 11, 
+	12, 26, 25, 25, 25, 11, 12, 27, 
+	28, 29, 30, 11, 12, 31, 11, 12, 
+	32, 11, 12, 33, 11, 12, 34, 11, 
+	12, 35, 11, 12, 36, 11, 12, 37, 
+	11, 12, 38, 11, 12, 39, 39, 39, 
+	11, 12, 40, 11, 12, 41, 11, 12, 
+	42, 11, 12, 43, 11, 12, 44, 11, 
+	12, 45, 11, 12, 46, 11, 12, 47, 
+	11, 12, 48, 11, 50, 49, 12, 51, 
+	11, 12, 52, 11, 12, 53, 11, 12, 
+	54, 11, 12, 55, 11, 12, 56, 11, 
+	12, 57, 11, 12, 58, 11, 12, 59, 
+	11, 12, 60, 11, 12, 61, 11, 12, 
+	62, 11, 12, 63, 11, 12, 64, 11, 
+	12, 65, 66, 11, 12, 67, 68, 11, 
+	12, 69, 12, 70, 71, 72, 73, 74, 
+	14, 0
 };
 
 static const char _gdb_trans_targs[] = {
-	1, 2, 2, 3, 4, 59, 3, 9, 
-	11, 12, 3, 18, 9, 20, 50, 5, 
-	0, 58, 6, 2, 7, 2, 8, 10, 
-	4, 11, 12, 13, 14, 15, 16, 17, 
-	19, 9, 21, 3, 30, 40, 22, 23, 
-	24, 25, 26, 27, 28, 29, 29, 31, 
-	32, 33, 34, 35, 36, 37, 38, 39, 
-	39, 41, 42, 43, 44, 45, 46, 47, 
-	48, 49, 3, 51, 52, 53, 54, 55, 
-	3, 56, 57, 56, 57
+	2, 3, 2, 5, 7, 8, 2, 14, 
+	5, 16, 46, 2, 3, 4, 0, 54, 
+	6, 3, 7, 8, 9, 10, 11, 12, 
+	13, 15, 5, 17, 2, 26, 36, 18, 
+	19, 20, 21, 22, 23, 24, 25, 25, 
+	27, 28, 29, 30, 31, 32, 33, 34, 
+	35, 2, 3, 37, 38, 39, 40, 41, 
+	42, 43, 44, 45, 2, 47, 48, 49, 
+	50, 51, 2, 52, 53, 52, 53, 54, 
+	1, 54, 54
 };
 
 static const char _gdb_trans_actions[] = {
-	0, 63, 1, 3, 0, 3, 33, 39, 
-	3, 3, 27, 21, 30, 3, 3, 7, 
-	0, 18, 3, 66, 0, 9, 7, 15, 
-	5, 36, 24, 74, 70, 74, 70, 74, 
-	15, 12, 3, 45, 3, 3, 3, 3, 
-	3, 3, 3, 3, 3, 3, 42, 3, 
+	19, 1, 70, 74, 19, 19, 62, 58, 
+	66, 19, 19, 3, 0, 7, 0, 28, 
+	25, 5, 34, 31, 82, 78, 82, 78, 
+	82, 25, 22, 3, 40, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 37, 
 	3, 3, 3, 3, 3, 3, 3, 3, 
-	48, 3, 3, 3, 3, 3, 3, 3, 
-	3, 3, 51, 3, 3, 3, 3, 3, 
-	54, 3, 3, 57, 60
+	3, 43, 9, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 46, 3, 3, 3, 
+	3, 3, 49, 3, 3, 52, 55, 11, 
+	13, 15, 17
 };
 
-static const int gdb_start = 58;
-static const int gdb_first_final = 58;
+static const int gdb_start = 54;
+static const int gdb_first_final = 54;
 static const int gdb_error = 0;
 
-static const int gdb_en_main = 58;
+static const int gdb_en_main = 54;
 
 
-#line 119 "src/gdb_parser.rl"
+#line 124 "src/gdb_parser.rl"
 
 void parser_init(command_cb *callbacks)
 {
 	
-#line 182 "src/gdb_parser.c"
+#line 175 "src/gdb_parser.c"
 	{
 	cs = gdb_start;
 	}
 
-#line 123 "src/gdb_parser.rl"
+#line 128 "src/gdb_parser.rl"
 
 	command_callbacks = callbacks;
 }
@@ -191,10 +184,10 @@  void parser_init(command_cb *callbacks)
 int parse_buffer(char *buf, size_t len, void *priv)
 {
 	char *p = buf;
-	char *pe = p + len + 1;
+	char *pe = p + len;
 
 	
-#line 198 "src/gdb_parser.c"
+#line 191 "src/gdb_parser.c"
 	{
 	int _klen;
 	unsigned int _trans;
@@ -269,30 +262,31 @@  _match:
 		switch ( *_acts++ )
 		{
 	case 0:
-#line 11 "src/gdb_parser.rl"
+#line 13 "src/gdb_parser.rl"
 	{
 		cmd = 0;
 		rsp = NULL;
 		data = stack;
 		memset(stack, 0, sizeof(stack));
 		crc = 0;
+		PR_INFO("RAGEL: CRC reset\n");
 	}
 	break;
 	case 1:
-#line 19 "src/gdb_parser.rl"
+#line 22 "src/gdb_parser.rl"
 	{
 		crc += *p;
 	}
 	break;
 	case 2:
-#line 23 "src/gdb_parser.rl"
+#line 26 "src/gdb_parser.rl"
 	{
 		data++;
 		assert(data < &stack[10]);
 	}
 	break;
 	case 3:
-#line 28 "src/gdb_parser.rl"
+#line 31 "src/gdb_parser.rl"
 	{
 		*data *= 16;
 
@@ -305,14 +299,14 @@  _match:
 	}
 	break;
 	case 4:
-#line 39 "src/gdb_parser.rl"
+#line 42 "src/gdb_parser.rl"
 	{
 		/* *data should point to the CRC */
 		if (crc != *data) {
-			printf("CRC error\n");
+			printf("CRC error cmd %d\n", cmd);
 			send_nack(priv);
 		} else {
-			printf("Cmd %d\n", cmd);
+			PR_INFO("Cmd %d\n", cmd);
 			send_ack(priv);
 
 			/* Push the response onto the stack */
@@ -321,71 +315,84 @@  _match:
 			else
 				*data = 0;
 
-			command_callbacks[cmd](stack, priv);
+			if (command_callbacks)
+				command_callbacks[cmd](stack, priv);
 		}
 	}
 	break;
 	case 5:
-#line 58 "src/gdb_parser.rl"
+#line 62 "src/gdb_parser.rl"
 	{cmd = GET_MEM;}
 	break;
 	case 6:
-#line 63 "src/gdb_parser.rl"
+#line 67 "src/gdb_parser.rl"
 	{cmd = PUT_MEM;}
 	break;
 	case 7:
-#line 70 "src/gdb_parser.rl"
+#line 74 "src/gdb_parser.rl"
 	{cmd = GET_GPRS;}
 	break;
 	case 8:
-#line 72 "src/gdb_parser.rl"
+#line 76 "src/gdb_parser.rl"
 	{cmd = GET_SPR;}
 	break;
 	case 9:
-#line 75 "src/gdb_parser.rl"
+#line 79 "src/gdb_parser.rl"
 	{cmd = STOP_REASON;}
 	break;
 	case 10:
-#line 77 "src/gdb_parser.rl"
+#line 81 "src/gdb_parser.rl"
 	{cmd = SET_THREAD;}
 	break;
 	case 11:
-#line 79 "src/gdb_parser.rl"
+#line 83 "src/gdb_parser.rl"
 	{cmd = DETACH;}
 	break;
 	case 12:
-#line 83 "src/gdb_parser.rl"
+#line 87 "src/gdb_parser.rl"
 	{rsp = "1";}
 	break;
 	case 13:
-#line 84 "src/gdb_parser.rl"
+#line 88 "src/gdb_parser.rl"
 	{rsp = "QC1";}
 	break;
 	case 14:
-#line 85 "src/gdb_parser.rl"
+#line 89 "src/gdb_parser.rl"
 	{rsp = "multiprocess+;vContSupported+";}
 	break;
 	case 15:
-#line 86 "src/gdb_parser.rl"
+#line 90 "src/gdb_parser.rl"
 	{rsp = "m1l";}
 	break;
 	case 16:
-#line 89 "src/gdb_parser.rl"
+#line 93 "src/gdb_parser.rl"
 	{rsp = "vCont;c;C;s;S";}
 	break;
 	case 17:
-#line 90 "src/gdb_parser.rl"
+#line 94 "src/gdb_parser.rl"
 	{cmd = V_CONTC;}
 	break;
 	case 18:
-#line 91 "src/gdb_parser.rl"
+#line 95 "src/gdb_parser.rl"
 	{cmd = V_CONTS;}
 	break;
 	case 19:
-#line 93 "src/gdb_parser.rl"
-	{command_callbacks[INTERRUPT](stack, priv);}
+#line 98 "src/gdb_parser.rl"
+	{ if (command_callbacks) command_callbacks[INTERRUPT](stack, priv); PR_INFO("RAGEL:interrupt\n");}
+	break;
+	case 20:
+#line 105 "src/gdb_parser.rl"
+	{PR_INFO("RAGEL:cmd\n");}
+	break;
+	case 21:
+#line 108 "src/gdb_parser.rl"
+	{PR_INFO("RAGEL:ack\n");}
 	break;
-#line 389 "src/gdb_parser.c"
+	case 22:
+#line 109 "src/gdb_parser.rl"
+	{PR_INFO("RAGEL:nack\n");}
+	break;
+#line 396 "src/gdb_parser.c"
 		}
 	}
 
@@ -398,18 +405,37 @@  _again:
 	_out: {}
 	}
 
-#line 133 "src/gdb_parser.rl"
+#line 138 "src/gdb_parser.rl"
+
+	if (cs == gdb_error) {
+		printf("parse error\n");
+		return -1;
+	}
 
 	return 0;
 }
 
 #if 0
+void send_nack(void *priv)
+{
+	printf("Send: -\n");
+}
+
+void send_ack(void *priv)
+{
+	printf("Send: +\n");
+}
+
 int main(int argc, char **argv)
 {
 	parser_init(NULL);
 
-	if (argc > 1)
-		parse_buffer(argv[1], strlen(argv[1]), NULL);
+	if (argc > 1) {
+		int i;
+		for (i = 1; i < argc; i++)
+			parse_buffer(argv[i], strlen(argv[i]), NULL);
+	}
+
 	return 0;
 }
 #endif