diff --git a/src/gdb_parser.rl b/src/gdb_parser.rl
index abb361a..4404833 100644
--- a/src/gdb_parser.rl
+++ b/src/gdb_parser.rl
@@ -121,6 +121,10 @@
 	qf_threadinfo = ('qfThreadInfo' @{cmd = QF_THREADINFO;});
 	qs_threadinfo = ('qsThreadInfo' @{cmd = QS_THREADINFO;});
 
+	# breakpoints
+	set_break = ('Z0,' xdigit+ $hex_digit %push ',4' @{cmd = SET_BREAK;});
+	clear_break = ('z0,' xdigit+ $hex_digit %push ',4' @{cmd = CLEAR_BREAK;});
+
 	# vCont packet parsing
 	v_contq = ('vCont?' @{rsp = "vCont;c;C;s;S";});
 	v_contc = ('vCont;c' any* @{cmd = V_CONTC;});
@@ -135,6 +139,7 @@
 		    v_contq | v_contc | v_conts |
 		    qf_threadinfo | qs_threadinfo |
 		    get_mem | put_mem |
+		    set_break | clear_break |
 		    detach | unknown );
 
 	cmd = (('$' ((commands & ^'#'*) >reset $crc)
diff --git a/src/gdb_parser_precompile.c b/src/gdb_parser_precompile.c
index 97cdae2..68502ac 100644
--- a/src/gdb_parser_precompile.c
+++ b/src/gdb_parser_precompile.c
@@ -11,7 +11,7 @@
 #include "debug.h"
 
 
-#line 149 "src/gdb_parser.rl"
+#line 154 "src/gdb_parser.rl"
 
 
 static enum gdb_command cmd = NONE;
@@ -31,86 +31,96 @@ static bool ack_mode = true;
 #line 32 "src/gdb_parser.c"
 static const char _gdb_actions[] = {
 	0, 1, 0, 1, 1, 1, 2, 1, 
-	3, 1, 14, 1, 24, 1, 25, 1, 
-	26, 1, 27, 2, 0, 1, 2, 2, 
+	3, 1, 14, 1, 26, 1, 27, 1, 
+	28, 1, 29, 2, 0, 1, 2, 2, 
 	1, 2, 3, 1, 2, 3, 5, 2, 
 	4, 1, 2, 13, 1, 2, 14, 1, 
 	2, 15, 1, 2, 16, 1, 2, 17, 
 	1, 2, 19, 1, 2, 20, 1, 2, 
 	21, 1, 2, 22, 1, 2, 23, 1, 
-	3, 0, 6, 1, 3, 0, 7, 1, 
-	3, 0, 9, 1, 3, 0, 10, 1, 
-	3, 0, 11, 1, 3, 0, 12, 1, 
-	3, 2, 8, 1, 3, 3, 18, 1
-	
+	2, 24, 1, 2, 25, 1, 3, 0, 
+	6, 1, 3, 0, 7, 1, 3, 0, 
+	9, 1, 3, 0, 10, 1, 3, 0, 
+	11, 1, 3, 0, 12, 1, 3, 2, 
+	8, 1, 3, 3, 18, 1
 };
 
 static const short _gdb_key_offsets[] = {
-	0, 0, 12, 13, 19, 25, 32, 39, 
-	41, 43, 50, 58, 66, 73, 80, 88, 
-	95, 103, 110, 112, 114, 116, 118, 120, 
-	122, 124, 126, 128, 130, 132, 134, 136, 
-	138, 140, 147, 155, 163, 170, 177, 185, 
-	191, 193, 195, 197, 199, 201, 203, 205, 
-	207, 214, 216, 218, 220, 222, 224, 226, 
-	228, 230, 232, 233, 235, 237, 239, 241, 
-	243, 245, 247, 249, 251, 253, 255, 257, 
-	259, 261, 263, 265, 267, 269, 271, 273, 
-	275, 277, 279, 281, 284, 287, 288, 289
+	0, 0, 14, 15, 21, 27, 34, 41, 
+	43, 45, 52, 60, 68, 75, 82, 90, 
+	97, 105, 112, 114, 116, 118, 120, 122, 
+	124, 126, 128, 130, 132, 134, 136, 138, 
+	140, 142, 149, 157, 165, 172, 174, 176, 
+	183, 191, 193, 200, 208, 214, 216, 218, 
+	220, 222, 224, 226, 228, 230, 237, 239, 
+	241, 243, 245, 247, 249, 251, 253, 255, 
+	256, 258, 260, 262, 264, 266, 268, 270, 
+	272, 274, 276, 278, 280, 282, 284, 286, 
+	288, 290, 292, 294, 296, 298, 300, 302, 
+	304, 307, 310, 311, 312, 314, 316, 323, 
+	331, 333
 };
 
 static const char _gdb_trans_keys[] = {
-	35, 63, 68, 72, 77, 81, 84, 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, 
-	103, 35, 112, 35, 48, 57, 65, 70, 
-	97, 102, 35, 46, 48, 57, 65, 70, 
-	97, 102, 35, 112, 48, 57, 65, 70, 
+	35, 63, 68, 72, 77, 81, 84, 90, 
+	103, 109, 112, 113, 118, 122, 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, 48, 57, 65, 70, 97, 102, 
-	35, 44, 48, 57, 65, 70, 97, 102, 
-	35, 48, 57, 65, 70, 97, 102, 35, 
-	58, 48, 57, 65, 70, 97, 102, 35, 
-	48, 57, 65, 70, 97, 102, 35, 83, 
-	35, 116, 35, 97, 35, 114, 35, 116, 
-	35, 78, 35, 111, 35, 65, 35, 99, 
-	35, 107, 35, 77, 35, 111, 35, 100, 
-	35, 101, 35, 112, 35, 48, 57, 65, 
-	70, 97, 102, 35, 46, 48, 57, 65, 
-	70, 97, 102, 35, 112, 48, 57, 65, 
+	102, 35, 103, 35, 112, 35, 48, 57, 
+	65, 70, 97, 102, 35, 46, 48, 57, 
+	65, 70, 97, 102, 35, 112, 48, 57, 
+	65, 70, 97, 102, 35, 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, 115, 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, 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
+	102, 35, 58, 48, 57, 65, 70, 97, 
+	102, 35, 48, 57, 65, 70, 97, 102, 
+	35, 83, 35, 116, 35, 97, 35, 114, 
+	35, 116, 35, 78, 35, 111, 35, 65, 
+	35, 99, 35, 107, 35, 77, 35, 111, 
+	35, 100, 35, 101, 35, 112, 35, 48, 
+	57, 65, 70, 97, 102, 35, 46, 48, 
+	57, 65, 70, 97, 102, 35, 112, 48, 
+	57, 65, 70, 97, 102, 35, 48, 57, 
+	65, 70, 97, 102, 35, 48, 35, 44, 
+	35, 48, 57, 65, 70, 97, 102, 35, 
+	44, 48, 57, 65, 70, 97, 102, 35, 
+	52, 35, 48, 57, 65, 70, 97, 102, 
+	35, 44, 48, 57, 65, 70, 97, 102, 
+	35, 65, 67, 83, 102, 115, 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, 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, 
+	35, 48, 35, 44, 35, 48, 57, 65, 
+	70, 97, 102, 35, 44, 48, 57, 65, 
+	70, 97, 102, 35, 52, 3, 36, 43, 
+	45, 0
 };
 
 static const char _gdb_single_lengths[] = {
-	0, 12, 1, 0, 0, 1, 1, 2, 
+	0, 14, 1, 0, 0, 1, 1, 2, 
 	2, 1, 2, 2, 1, 1, 2, 1, 
 	2, 1, 2, 2, 2, 2, 2, 2, 
 	2, 2, 2, 2, 2, 2, 2, 2, 
-	2, 1, 2, 2, 1, 1, 2, 6, 
+	2, 1, 2, 2, 1, 2, 2, 1, 
+	2, 2, 1, 2, 6, 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, 
-	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, 2, 2, 2, 
-	2, 2, 2, 3, 3, 1, 1, 4
+	3, 3, 1, 1, 2, 2, 1, 2, 
+	2, 4
 };
 
 static const char _gdb_range_lengths[] = {
@@ -118,125 +128,138 @@ static const char _gdb_range_lengths[] = {
 	0, 3, 3, 3, 3, 3, 3, 3, 
 	3, 3, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 3, 3, 3, 3, 3, 3, 0, 
+	0, 3, 3, 3, 3, 0, 0, 3, 
+	3, 0, 3, 3, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 3, 0, 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, 0, 0, 0, 0, 0, 0
+	0, 0, 0, 0, 0, 0, 3, 3, 
+	0, 0
 };
 
 static const short _gdb_index_offsets[] = {
-	0, 0, 13, 15, 19, 23, 28, 33, 
-	36, 39, 44, 50, 56, 61, 66, 72, 
-	77, 83, 88, 91, 94, 97, 100, 103, 
-	106, 109, 112, 115, 118, 121, 124, 127, 
-	130, 133, 138, 144, 150, 155, 160, 166, 
-	173, 176, 179, 182, 185, 188, 191, 194, 
-	197, 202, 205, 208, 211, 214, 217, 220, 
-	223, 226, 229, 231, 234, 237, 240, 243, 
-	246, 249, 252, 255, 258, 261, 264, 267, 
-	270, 273, 276, 279, 282, 285, 288, 291, 
-	294, 297, 300, 303, 307, 311, 313, 315
+	0, 0, 15, 17, 21, 25, 30, 35, 
+	38, 41, 46, 52, 58, 63, 68, 74, 
+	79, 85, 90, 93, 96, 99, 102, 105, 
+	108, 111, 114, 117, 120, 123, 126, 129, 
+	132, 135, 140, 146, 152, 157, 160, 163, 
+	168, 174, 177, 182, 188, 195, 198, 201, 
+	204, 207, 210, 213, 216, 219, 224, 227, 
+	230, 233, 236, 239, 242, 245, 248, 251, 
+	253, 256, 259, 262, 265, 268, 271, 274, 
+	277, 280, 283, 286, 289, 292, 295, 298, 
+	301, 304, 307, 310, 313, 316, 319, 322, 
+	325, 329, 333, 335, 337, 340, 343, 348, 
+	354, 357
 };
 
 static const char _gdb_indicies[] = {
 	1, 2, 3, 4, 5, 6, 7, 8, 
-	9, 10, 11, 12, 0, 14, 13, 15, 
-	15, 15, 16, 17, 17, 17, 16, 14, 
-	18, 18, 18, 13, 19, 18, 18, 18, 
-	13, 14, 20, 13, 14, 21, 13, 14, 
-	22, 22, 22, 13, 14, 23, 22, 22, 
-	22, 13, 14, 21, 24, 24, 24, 13, 
-	19, 24, 24, 24, 13, 14, 25, 25, 
-	25, 13, 14, 26, 25, 25, 25, 13, 
-	14, 27, 27, 27, 13, 14, 28, 27, 
-	27, 27, 13, 14, 29, 29, 29, 13, 
-	14, 30, 13, 14, 31, 13, 14, 32, 
-	13, 14, 33, 13, 14, 34, 13, 14, 
-	35, 13, 14, 36, 13, 14, 37, 13, 
-	14, 38, 13, 14, 39, 13, 14, 40, 
-	13, 14, 41, 13, 14, 42, 13, 14, 
-	43, 13, 14, 44, 13, 14, 45, 45, 
-	45, 13, 14, 46, 45, 45, 45, 13, 
-	14, 44, 47, 47, 47, 13, 14, 47, 
-	47, 47, 13, 14, 48, 48, 48, 13, 
-	14, 49, 48, 48, 48, 13, 14, 50, 
-	51, 52, 53, 54, 13, 14, 55, 13, 
-	14, 56, 13, 14, 57, 13, 14, 58, 
-	13, 14, 59, 13, 14, 60, 13, 14, 
-	61, 13, 14, 62, 13, 14, 63, 63, 
-	63, 13, 14, 64, 13, 14, 65, 13, 
-	14, 66, 13, 14, 67, 13, 14, 68, 
-	13, 14, 69, 13, 14, 70, 13, 14, 
-	71, 13, 14, 72, 13, 74, 73, 14, 
-	75, 13, 14, 76, 13, 14, 77, 13, 
-	14, 78, 13, 14, 79, 13, 14, 80, 
-	13, 14, 81, 13, 14, 82, 13, 14, 
-	83, 13, 14, 84, 13, 14, 85, 13, 
-	14, 86, 13, 14, 87, 13, 14, 88, 
-	13, 14, 89, 13, 14, 90, 13, 14, 
-	91, 13, 14, 92, 13, 14, 93, 13, 
-	14, 94, 13, 14, 95, 13, 14, 96, 
-	13, 14, 97, 13, 14, 98, 13, 14, 
-	99, 100, 13, 14, 101, 102, 13, 14, 
-	103, 14, 104, 105, 106, 107, 108, 16, 
-	0
+	9, 10, 11, 12, 13, 14, 0, 16, 
+	15, 17, 17, 17, 18, 19, 19, 19, 
+	18, 16, 20, 20, 20, 15, 21, 20, 
+	20, 20, 15, 16, 22, 15, 16, 23, 
+	15, 16, 24, 24, 24, 15, 16, 25, 
+	24, 24, 24, 15, 16, 23, 26, 26, 
+	26, 15, 21, 26, 26, 26, 15, 16, 
+	27, 27, 27, 15, 16, 28, 27, 27, 
+	27, 15, 16, 29, 29, 29, 15, 16, 
+	30, 29, 29, 29, 15, 16, 31, 31, 
+	31, 15, 16, 32, 15, 16, 33, 15, 
+	16, 34, 15, 16, 35, 15, 16, 36, 
+	15, 16, 37, 15, 16, 38, 15, 16, 
+	39, 15, 16, 40, 15, 16, 41, 15, 
+	16, 42, 15, 16, 43, 15, 16, 44, 
+	15, 16, 45, 15, 16, 46, 15, 16, 
+	47, 47, 47, 15, 16, 48, 47, 47, 
+	47, 15, 16, 46, 49, 49, 49, 15, 
+	16, 49, 49, 49, 15, 16, 50, 15, 
+	16, 51, 15, 16, 52, 52, 52, 15, 
+	16, 53, 52, 52, 52, 15, 16, 54, 
+	15, 16, 55, 55, 55, 15, 16, 56, 
+	55, 55, 55, 15, 16, 57, 58, 59, 
+	60, 61, 15, 16, 62, 15, 16, 63, 
+	15, 16, 64, 15, 16, 65, 15, 16, 
+	66, 15, 16, 67, 15, 16, 68, 15, 
+	16, 69, 15, 16, 70, 70, 70, 15, 
+	16, 71, 15, 16, 72, 15, 16, 73, 
+	15, 16, 74, 15, 16, 75, 15, 16, 
+	76, 15, 16, 77, 15, 16, 78, 15, 
+	16, 79, 15, 81, 80, 16, 82, 15, 
+	16, 83, 15, 16, 84, 15, 16, 85, 
+	15, 16, 86, 15, 16, 87, 15, 16, 
+	88, 15, 16, 89, 15, 16, 90, 15, 
+	16, 91, 15, 16, 92, 15, 16, 93, 
+	15, 16, 94, 15, 16, 95, 15, 16, 
+	96, 15, 16, 97, 15, 16, 98, 15, 
+	16, 99, 15, 16, 100, 15, 16, 101, 
+	15, 16, 102, 15, 16, 103, 15, 16, 
+	104, 15, 16, 105, 15, 16, 106, 107, 
+	15, 16, 108, 109, 15, 16, 110, 16, 
+	111, 16, 112, 15, 16, 113, 15, 16, 
+	114, 114, 114, 15, 16, 115, 114, 114, 
+	114, 15, 16, 116, 15, 117, 118, 119, 
+	120, 18, 0
 };
 
 static const char _gdb_trans_targs[] = {
 	2, 3, 2, 5, 7, 13, 18, 32, 
-	2, 37, 5, 39, 79, 2, 3, 4, 
-	0, 87, 6, 3, 8, 9, 10, 11, 
-	12, 14, 15, 16, 17, 17, 19, 20, 
-	21, 22, 23, 24, 25, 26, 27, 28, 
-	29, 30, 31, 2, 33, 34, 35, 36, 
-	38, 5, 40, 2, 49, 59, 69, 41, 
-	42, 43, 44, 45, 46, 47, 48, 48, 
-	50, 51, 52, 53, 54, 55, 56, 57, 
-	58, 2, 3, 60, 61, 62, 63, 64, 
-	65, 66, 67, 68, 2, 70, 71, 72, 
-	73, 74, 75, 76, 77, 78, 2, 80, 
-	81, 82, 83, 84, 2, 85, 86, 85, 
-	86, 87, 1, 87, 87
+	37, 2, 42, 5, 44, 84, 92, 2, 
+	3, 4, 0, 97, 6, 3, 8, 9, 
+	10, 11, 12, 14, 15, 16, 17, 17, 
+	19, 20, 21, 22, 23, 24, 25, 26, 
+	27, 28, 29, 30, 31, 2, 33, 34, 
+	35, 36, 38, 39, 40, 41, 2, 43, 
+	5, 45, 2, 54, 64, 74, 46, 47, 
+	48, 49, 50, 51, 52, 53, 53, 55, 
+	56, 57, 58, 59, 60, 61, 62, 63, 
+	2, 3, 65, 66, 67, 68, 69, 70, 
+	71, 72, 73, 2, 75, 76, 77, 78, 
+	79, 80, 81, 82, 83, 2, 85, 86, 
+	87, 88, 89, 2, 90, 91, 90, 91, 
+	93, 94, 95, 96, 2, 97, 1, 97, 
+	97
 };
 
 static const char _gdb_trans_actions[] = {
-	19, 1, 80, 84, 19, 68, 19, 19, 
-	72, 64, 76, 19, 19, 3, 0, 7, 
-	0, 28, 25, 5, 3, 3, 3, 3, 
-	92, 25, 22, 25, 88, 31, 3, 3, 
+	19, 1, 86, 90, 19, 74, 19, 19, 
+	19, 78, 70, 82, 19, 19, 19, 3, 
+	0, 7, 0, 28, 25, 5, 3, 3, 
+	3, 3, 98, 25, 22, 25, 94, 31, 
 	3, 3, 3, 3, 3, 3, 3, 3, 
-	3, 3, 3, 40, 3, 3, 3, 43, 
-	25, 22, 3, 46, 3, 3, 3, 3, 
-	3, 3, 3, 3, 3, 3, 3, 34, 
+	3, 3, 3, 3, 3, 40, 3, 3, 
+	3, 43, 3, 3, 25, 22, 55, 25, 
+	22, 3, 46, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 34, 3, 
 	3, 3, 3, 3, 3, 3, 3, 3, 
-	3, 37, 9, 3, 3, 3, 3, 3, 
-	3, 3, 3, 3, 49, 3, 3, 3, 
-	3, 3, 3, 3, 3, 3, 52, 3, 
-	3, 3, 3, 3, 55, 3, 3, 58, 
-	61, 11, 13, 15, 17
+	37, 9, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 49, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 52, 3, 3, 
+	3, 3, 3, 61, 3, 3, 64, 67, 
+	3, 3, 25, 22, 58, 11, 13, 15, 
+	17
 };
 
-static const int gdb_start = 87;
-static const int gdb_first_final = 87;
+static const int gdb_start = 97;
+static const int gdb_first_final = 97;
 static const int gdb_error = 0;
 
-static const int gdb_en_main = 87;
+static const int gdb_en_main = 97;
 
 
-#line 165 "src/gdb_parser.rl"
+#line 170 "src/gdb_parser.rl"
 
 void parser_init(command_cb *callbacks)
 {
 	
-#line 235 "src/gdb_parser.c"
+#line 258 "src/gdb_parser.c"
 	{
 	cs = gdb_start;
 	}
 
-#line 169 "src/gdb_parser.rl"
+#line 174 "src/gdb_parser.rl"
 
 	command_callbacks = callbacks;
 }
@@ -247,7 +270,7 @@ int parse_buffer(char *buf, size_t len, void *priv)
 	char *pe = p + len;
 
 	
-#line 251 "src/gdb_parser.c"
+#line 274 "src/gdb_parser.c"
 	{
 	int _klen;
 	unsigned int _trans;
@@ -470,33 +493,41 @@ _match:
 	break;
 	case 21:
 #line 125 "src/gdb_parser.rl"
-	{rsp = "vCont;c;C;s;S";}
+	{cmd = SET_BREAK;}
 	break;
 	case 22:
 #line 126 "src/gdb_parser.rl"
-	{cmd = V_CONTC;}
+	{cmd = CLEAR_BREAK;}
 	break;
 	case 23:
-#line 127 "src/gdb_parser.rl"
-	{cmd = V_CONTS;}
+#line 129 "src/gdb_parser.rl"
+	{rsp = "vCont;c;C;s;S";}
 	break;
 	case 24:
 #line 130 "src/gdb_parser.rl"
-	{ if (command_callbacks) command_callbacks[INTERRUPT](stack, priv); PR_INFO("RAGEL:interrupt\n");}
+	{cmd = V_CONTC;}
 	break;
 	case 25:
-#line 141 "src/gdb_parser.rl"
-	{PR_INFO("RAGEL:cmd\n");}
+#line 131 "src/gdb_parser.rl"
+	{cmd = V_CONTS;}
 	break;
 	case 26:
-#line 144 "src/gdb_parser.rl"
-	{PR_INFO("RAGEL:ack\n");}
+#line 134 "src/gdb_parser.rl"
+	{ if (command_callbacks) command_callbacks[INTERRUPT](stack, priv); PR_INFO("RAGEL:interrupt\n");}
 	break;
 	case 27:
-#line 145 "src/gdb_parser.rl"
+#line 146 "src/gdb_parser.rl"
+	{PR_INFO("RAGEL:cmd\n");}
+	break;
+	case 28:
+#line 149 "src/gdb_parser.rl"
+	{PR_INFO("RAGEL:ack\n");}
+	break;
+	case 29:
+#line 150 "src/gdb_parser.rl"
 	{PR_INFO("RAGEL:nack\n");}
 	break;
-#line 500 "src/gdb_parser.c"
+#line 531 "src/gdb_parser.c"
 		}
 	}
 
@@ -509,7 +540,7 @@ _again:
 	_out: {}
 	}
 
-#line 179 "src/gdb_parser.rl"
+#line 184 "src/gdb_parser.rl"
 
 	if (cs == gdb_error) {
 		printf("parse error\n");
diff --git a/src/pdbgproxy.c b/src/pdbgproxy.c
index 687f766..c257361 100644
--- a/src/pdbgproxy.c
+++ b/src/pdbgproxy.c
@@ -664,6 +664,192 @@ out:
 		send_response(fd, OK);
 }
 
+#define MAX_BPS 64
+static uint64_t bps[MAX_BPS];
+static uint32_t saved_insn[MAX_BPS];
+static int nr_bps = 0;
+
+static int set_bp(uint64_t addr)
+{
+	int i;
+
+	if (nr_bps == MAX_BPS)
+		return -1;
+
+	if (addr == -1ULL)
+		return -1;
+
+	for (i = 0; i < MAX_BPS; i++) {
+		if (bps[i] == -1ULL) {
+			bps[i] = addr;
+			nr_bps++;
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+static int clear_bp(uint64_t addr)
+{
+	int i;
+
+	if (nr_bps == 0)
+		return -1;
+
+	if (addr == -1ULL)
+		return -1;
+
+	for (i = 0; i < MAX_BPS; i++) {
+		if (bps[i] == addr) {
+			bps[i] = -1ULL;
+			nr_bps--;
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+static int get_insn(uint64_t addr, uint32_t *insn)
+{
+	uint64_t linear_map;
+
+	linear_map = get_real_addr(addr);
+	if (linear_map != -1UL) {
+		if (read_memory(linear_map, 4, insn, 1)) {
+			PR_ERROR("Unable to read memory\n");
+			return -1;
+		}
+	} else {
+		/* Virtual address */
+		return -1;
+	}
+
+	return 0;
+}
+
+static int put_insn(uint64_t addr, uint32_t insn)
+{
+	uint64_t linear_map;
+
+	linear_map = get_real_addr(addr);
+	if (linear_map != -1UL) {
+		if (write_memory(linear_map, 4, &insn, 8)) {
+			PR_ERROR("Unable to write memory\n");
+			return -1;
+		}
+	} else {
+		/* Virtual address */
+		return -1;
+	}
+
+	return 0;
+}
+
+static void init_breakpoints(void)
+{
+	int i;
+
+	for (i = 0; i < MAX_BPS; i++)
+		bps[i] = -1ULL;
+}
+
+static bool match_breakpoint(uint64_t addr)
+{
+	int i;
+
+	if (nr_bps == 0)
+		return false;
+
+	for (i = 0; i < MAX_BPS; i++) {
+		if (bps[i] == addr)
+			return true;
+	}
+
+	return false;
+}
+
+static int install_breakpoints(void)
+{
+	uint8_t attn_opcode[] = {0x00, 0x00, 0x02, 0x00};
+	uint32_t *attn = (uint32_t *)&attn_opcode[0];
+	uint64_t msr;
+	int i;
+
+	if (!nr_bps)
+		return 0;
+
+	/* Check endianess in MSR */
+	if (thread_getmsr(thread_target, &msr)) {
+		PR_ERROR("Couldn't read the MSR to set breakpoint endian");
+		return -1;
+	}
+
+	if (msr & 1) /* currently little endian */
+		*attn = bswap_32(*attn);
+
+	for (i = 0; i < MAX_BPS; i++) {
+		if (bps[i] == -1ULL)
+			continue;
+		if (get_insn(bps[i], &saved_insn[i]))
+			continue; /* XXX: handle properly */
+		if (put_insn(bps[i], *attn))
+			continue; /* XXX: handle properly */
+	}
+
+	set_attn(true);
+
+	return 0;
+}
+
+static int uninstall_breakpoints(void)
+{
+	int i;
+
+	if (!nr_bps)
+		return 0;
+
+	for (i = 0; i < MAX_BPS; i++) {
+		if (bps[i] == -1ULL)
+			continue;
+		if (put_insn(bps[i], saved_insn[i]))
+			continue; /* XXX: handle properly */
+
+	}
+
+	set_attn(false);
+
+	return 0;
+}
+
+
+static void set_break(uint64_t *stack, void *priv)
+{
+	uint64_t addr;
+
+	/* stack[0] is the address */
+	addr = stack[0];
+
+	if (!set_bp(addr))
+		send_response(fd, OK);
+	else
+		send_response(fd, ERROR(ENOMEM));
+}
+
+static void clear_break(uint64_t *stack, void *priv)
+{
+	uint64_t addr;
+
+	/* stack[0] is the address */
+	addr = stack[0];
+
+	if (!clear_bp(addr))
+		send_response(fd, OK);
+	else
+		send_response(fd, ERROR(ENOENT));
+}
+
 static void v_conts(uint64_t *stack, void *priv)
 {
 	struct thread *thread = target_to_thread(thread_target);
@@ -709,6 +895,8 @@ static void start_all(void)
 {
 	struct pdbg_target *target;
 
+	install_breakpoints();
+
 	for_each_path_target_class("thread", target) {
 		struct thread *thread = target_to_thread(target);
 		struct gdb_thread *gdb_thread;
@@ -843,14 +1031,26 @@ static void stop_all(void)
 			gdb_thread->stop_attn = true;
 
 			if (!(status.active))
-				PR_ERROR("Error thread inactive after trap\n");
-			/* Restore NIA to before break */
+				PR_ERROR("Error thread inactive after attn\n");
+
 			if (thread_getnia(target, &nia))
 				PR_ERROR("Error during getnia\n");
-			if (thread_putnia(target, nia - 4))
-				PR_ERROR("Error during putnia\n");
+
+			/*
+			 * If we hit a non-breakpoint attn we still want to
+			 * switch to that thread, but we don't rewind the nip
+			 * so as to advance over the attn.
+			 */
+			if (match_breakpoint(nia - 4)) {
+				PR_INFO("thread pir=%llx attn is breakpoint\n", gdb_thread->pir);
+				/* Restore NIA to breakpoint address */
+				if (thread_putnia(target, nia - 4))
+					PR_ERROR("Error during putnia\n");
+			}
 		}
 	}
+
+	uninstall_breakpoints();
 }
 
 static void interrupt(uint64_t *stack, void *priv)
@@ -918,8 +1118,6 @@ static void poll(void)
 		}
 	}
 
-	set_attn(false);
-
 	state = IDLE;
 	poll_interval = VCONT_POLL_DELAY;
 
@@ -991,6 +1189,8 @@ static command_cb callbacks[LAST_CMD + 1] = {
 	qs_threadinfo,
 	get_mem,
 	put_mem,
+	set_break,
+	clear_break,
 	interrupt,
 	detach,
 	NULL};
@@ -1107,6 +1307,8 @@ static int gdbserver(uint16_t port)
 	struct pdbg_target *first_stopped_target = NULL;
 	struct pdbg_target *first_attn_target = NULL;
 
+	init_breakpoints();
+
 	for_each_path_target_class("thread", target) {
 		struct thread *thread = target_to_thread(target);
 		struct gdb_thread *gdb_thread;
diff --git a/src/pdbgproxy.h b/src/pdbgproxy.h
index cafd4cb..6a89444 100644
--- a/src/pdbgproxy.h
+++ b/src/pdbgproxy.h
@@ -6,6 +6,7 @@ enum gdb_command {NONE, GET_GPRS, GET_SPR,
                  V_CONTC, V_CONTS,
                  QF_THREADINFO, QS_THREADINFO,
                  GET_MEM, PUT_MEM,
+                 SET_BREAK, CLEAR_BREAK,
                  INTERRUPT, DETACH, LAST_CMD};
 
 typedef void (*command_cb)(uint64_t *stack, void *priv);
