diff mbox series

[v2,28/39] gdbproxy: implement get_thread / set_thread commands

Message ID 20220420065013.222816-29-npiggin@gmail.com
State New
Headers show
Series gdbserver multi-threaded debugging and POWER9/10 support | expand

Commit Message

Nicholas Piggin April 20, 2022, 6:50 a.m. UTC
Using the PIR for a thread identifier, implement get_thread
and set_thread gdb commands.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
 src/gdb_parser.rl           |   8 +-
 src/gdb_parser_precompile.c | 301 +++++++++++++++++++-----------------
 src/pdbgproxy.c             |  36 ++++-
 src/pdbgproxy.h             |   2 +-
 4 files changed, 199 insertions(+), 148 deletions(-)

Comments

Joel Stanley May 3, 2022, 7:29 a.m. UTC | #1
On Wed, 20 Apr 2022 at 06:51, Nicholas Piggin <npiggin@gmail.com> wrote:
>
> Using the PIR for a thread identifier, implement get_thread
> and set_thread gdb commands.
>
> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>

Reviewed-by: Joel Stanley <joel@jms.id.au>

> ---
>  src/gdb_parser.rl           |   8 +-
>  src/gdb_parser_precompile.c | 301 +++++++++++++++++++-----------------
>  src/pdbgproxy.c             |  36 ++++-
>  src/pdbgproxy.h             |   2 +-
>  4 files changed, 199 insertions(+), 148 deletions(-)
>
> diff --git a/src/gdb_parser.rl b/src/gdb_parser.rl
> index e49d56d3..dc1275c3 100644
> --- a/src/gdb_parser.rl
> +++ b/src/gdb_parser.rl
> @@ -106,8 +106,6 @@
>
>         stop_reason = ('?' @{cmd = STOP_REASON;});
>
> -       set_thread = ('H' any* @{cmd = SET_THREAD;});
> -
>         detach = ('D' @{cmd = DETACH;}
>                      xdigit+ $hex_digit %push);
>
> @@ -118,6 +116,10 @@
>         qf_threadinfo = ('qfThreadInfo' @{rsp = "m1l";});
>         q_start_noack = ('QStartNoAckMode' @{rsp = "OK"; send_ack(priv); ack_mode = false;});
>
> +       # thread info
> +       get_thread = ('qC' @{cmd = GET_THREAD;});
> +       set_thread = ('Hg' ('p' xdigit+ '.')+ xdigit+ $hex_digit %push @{cmd = SET_THREAD;});
> +
>         # vCont packet parsing
>         v_contq = ('vCont?' @{rsp = "vCont;c;C;s;S";});
>         v_contc = ('vCont;c' any* @{cmd = V_CONTC;});
> @@ -126,7 +128,7 @@
>
>         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 |
> +       commands = (get_mem | get_gprs | get_spr | stop_reason | get_thread | set_thread |
>                     q_attached | q_C | q_supported | qf_threadinfo | q_C |
>                     q_start_noack | v_contq | v_contc | v_conts | put_mem |
>                     detach | unknown );
> diff --git a/src/gdb_parser_precompile.c b/src/gdb_parser_precompile.c
> index db982092..567f1dd6 100644
> --- a/src/gdb_parser_precompile.c
> +++ b/src/gdb_parser_precompile.c
> @@ -11,7 +11,7 @@
>  #include "debug.h"
>
>
> -#line 143 "src/gdb_parser.rl"
> +#line 145 "src/gdb_parser.rl"
>
>
>  static enum gdb_command cmd = NONE;
> @@ -31,29 +31,30 @@ static bool ack_mode = true;
>  #line 32 "src/gdb_parser_precompile.c"
>  static const char _gdb_actions[] = {
>         0, 1, 0, 1, 1, 1, 2, 1,
> -       3, 1, 16, 1, 22, 1, 23, 1,
> -       24, 1, 25, 2, 0, 1, 2, 2,
> +       3, 1, 15, 1, 23, 1, 24, 1,
> +       25, 1, 26, 2, 0, 1, 2, 2,
>         1, 2, 3, 1, 2, 3, 5, 2,
> -       4, 1, 2, 12, 1, 2, 14, 1,
> -       2, 15, 1, 2, 16, 1, 2, 17,
> -       1, 2, 18, 1, 2, 19, 1, 2,
> -       20, 1, 2, 21, 1, 3, 0, 6,
> -       1, 3, 0, 7, 1, 3, 0, 9,
> -       1, 3, 0, 10, 1, 3, 0, 11,
> -       1, 3, 0, 13, 1, 3, 2, 8,
> -       1
> +       4, 1, 2, 13, 1, 2, 15, 1,
> +       2, 16, 1, 2, 17, 1, 2, 20,
> +       1, 2, 21, 1, 2, 22, 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, 19, 1, 3,
> +       18, 14, 1
>  };
>
>  static const unsigned char _gdb_key_offsets[] = {
>         0, 0, 11, 12, 18, 24, 31, 38,
> -       39, 46, 54, 61, 69, 76, 78, 80,
> -       82, 84, 86, 88, 90, 92, 94, 96,
> -       98, 100, 102, 104, 111, 119, 124, 126,
> -       128, 130, 132, 134, 136, 138, 140, 147,
> -       149, 151, 153, 155, 157, 159, 161, 163,
> -       165, 166, 168, 170, 172, 174, 176, 178,
> -       180, 182, 184, 186, 188, 190, 192, 194,
> -       197, 200, 201, 202
> +       40, 42, 49, 57, 65, 72, 79, 87,
> +       94, 102, 109, 111, 113, 115, 117, 119,
> +       121, 123, 125, 127, 129, 131, 133, 135,
> +       137, 144, 152, 157, 159, 161, 163, 165,
> +       167, 169, 171, 173, 180, 182, 184, 186,
> +       188, 190, 192, 194, 196, 198, 199, 201,
> +       203, 205, 207, 209, 211, 213, 215, 217,
> +       219, 221, 223, 225, 227, 230, 233, 234,
> +       235
>  };
>
>  static const char _gdb_trans_keys[] = {
> @@ -61,64 +62,71 @@ static const char _gdb_trans_keys[] = {
>         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, 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,
> +       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, 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,
> -       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
> +       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, 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, 43, 45, 0
>  };
>
>  static const char _gdb_single_lengths[] = {
> -       0, 11, 1, 0, 0, 1, 1, 1,
> -       1, 2, 1, 2, 1, 2, 2, 2,
> +       0, 11, 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, 2, 2, 1, 2, 5, 2, 2,
> -       2, 2, 2, 2, 2, 2, 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,
> -       1, 2, 2, 2, 2, 2, 2, 2,
> -       2, 2, 2, 2, 2, 2, 2, 3,
> -       3, 1, 1, 4
> +       2, 2, 2, 2, 3, 3, 1, 1,
> +       4
>  };
>
>  static const char _gdb_range_lengths[] = {
>         0, 0, 0, 3, 3, 3, 3, 0,
> -       3, 3, 3, 3, 3, 0, 0, 0,
> +       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, 0, 0, 3, 3, 0, 0, 0,
> -       0, 0, 0, 0, 0, 0, 3, 0,
> +       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, 12, 14, 18, 22, 27, 32,
> -       34, 39, 45, 50, 56, 61, 64, 67,
> -       70, 73, 76, 79, 82, 85, 88, 91,
> -       94, 97, 100, 103, 108, 114, 120, 123,
> -       126, 129, 132, 135, 138, 141, 144, 149,
> -       152, 155, 158, 161, 164, 167, 170, 173,
> -       176, 178, 181, 184, 187, 190, 193, 196,
> -       199, 202, 205, 208, 211, 214, 217, 220,
> -       224, 228, 230, 232
> +       35, 38, 43, 49, 55, 60, 65, 71,
> +       76, 82, 87, 90, 93, 96, 99, 102,
> +       105, 108, 111, 114, 117, 120, 123, 126,
> +       129, 134, 140, 146, 149, 152, 155, 158,
> +       161, 164, 167, 170, 175, 178, 181, 184,
> +       187, 190, 193, 196, 199, 202, 204, 207,
> +       210, 213, 216, 219, 222, 225, 228, 231,
> +       234, 237, 240, 243, 246, 250, 254, 256,
> +       258
>  };
>
>  static const char _gdb_indicies[] = {
> @@ -126,82 +134,85 @@ static const char _gdb_indicies[] = {
>         9, 10, 11, 0, 13, 12, 14, 14,
>         14, 15, 16, 16, 16, 15, 13, 17,
>         17, 17, 12, 18, 17, 17, 17, 12,
> -       13, 19, 13, 20, 20, 20, 12, 13,
> -       21, 20, 20, 20, 12, 13, 22, 22,
> -       22, 12, 13, 23, 22, 22, 22, 12,
> -       13, 24, 24, 24, 12, 13, 25, 12,
> -       13, 26, 12, 13, 27, 12, 13, 28,
> -       12, 13, 29, 12, 13, 30, 12, 13,
> -       31, 12, 13, 32, 12, 13, 33, 12,
> -       13, 34, 12, 13, 35, 12, 13, 36,
> -       12, 13, 37, 12, 13, 38, 12, 13,
> -       39, 39, 39, 12, 13, 40, 39, 39,
> -       39, 12, 13, 41, 42, 43, 44, 12,
> -       13, 45, 12, 13, 46, 12, 13, 47,
> -       12, 13, 48, 12, 13, 49, 12, 13,
> -       50, 12, 13, 51, 12, 13, 52, 12,
> -       13, 53, 53, 53, 12, 13, 54, 12,
> -       13, 55, 12, 13, 56, 12, 13, 57,
> -       12, 13, 58, 12, 13, 59, 12, 13,
> -       60, 12, 13, 61, 12, 13, 62, 12,
> -       64, 63, 13, 65, 12, 13, 66, 12,
> -       13, 67, 12, 13, 68, 12, 13, 69,
> -       12, 13, 70, 12, 13, 71, 12, 13,
> -       72, 12, 13, 73, 12, 13, 74, 12,
> -       13, 75, 12, 13, 76, 12, 13, 77,
> -       12, 13, 78, 12, 13, 79, 80, 12,
> -       13, 81, 82, 12, 13, 83, 13, 84,
> -       85, 86, 87, 88, 15, 0
> +       13, 19, 12, 13, 20, 12, 13, 21,
> +       21, 21, 12, 13, 22, 21, 21, 21,
> +       12, 13, 20, 23, 23, 23, 12, 18,
> +       23, 23, 23, 12, 13, 24, 24, 24,
> +       12, 13, 25, 24, 24, 24, 12, 13,
> +       26, 26, 26, 12, 13, 27, 26, 26,
> +       26, 12, 13, 28, 28, 28, 12, 13,
> +       29, 12, 13, 30, 12, 13, 31, 12,
> +       13, 32, 12, 13, 33, 12, 13, 34,
> +       12, 13, 35, 12, 13, 36, 12, 13,
> +       37, 12, 13, 38, 12, 13, 39, 12,
> +       13, 40, 12, 13, 41, 12, 13, 42,
> +       12, 13, 43, 43, 43, 12, 13, 44,
> +       43, 43, 43, 12, 13, 45, 46, 47,
> +       48, 12, 13, 49, 12, 13, 50, 12,
> +       13, 51, 12, 13, 52, 12, 13, 53,
> +       12, 13, 54, 12, 13, 55, 12, 13,
> +       56, 12, 13, 57, 57, 57, 12, 13,
> +       58, 12, 13, 59, 12, 13, 60, 12,
> +       13, 61, 12, 13, 62, 12, 13, 63,
> +       12, 13, 64, 12, 13, 65, 12, 13,
> +       66, 12, 68, 67, 13, 69, 12, 13,
> +       70, 12, 13, 71, 12, 13, 72, 12,
> +       13, 73, 12, 13, 74, 12, 13, 75,
> +       12, 13, 76, 12, 13, 77, 12, 13,
> +       78, 12, 13, 79, 12, 13, 80, 12,
> +       13, 81, 12, 13, 82, 12, 13, 83,
> +       84, 12, 13, 85, 86, 12, 13, 87,
> +       13, 88, 89, 90, 91, 92, 15, 0
>  };
>
>  static const char _gdb_trans_targs[] = {
> -       2, 3, 2, 5, 7, 8, 13, 2,
> -       27, 5, 29, 59, 2, 3, 4, 0,
> -       67, 6, 3, 7, 9, 10, 11, 12,
> -       12, 14, 15, 16, 17, 18, 19, 20,
> -       21, 22, 23, 24, 25, 26, 2, 28,
> -       5, 30, 2, 39, 49, 31, 32, 33,
> -       34, 35, 36, 37, 38, 38, 40, 41,
> -       42, 43, 44, 45, 46, 47, 48, 2,
> -       3, 50, 51, 52, 53, 54, 55, 56,
> -       57, 58, 2, 60, 61, 62, 63, 64,
> -       2, 65, 66, 65, 66, 67, 1, 67,
> -       67
> +       2, 3, 2, 5, 7, 13, 18, 2,
> +       32, 5, 34, 64, 2, 3, 4, 0,
> +       72, 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, 5, 35, 2, 44,
> +       54, 36, 37, 38, 39, 40, 41, 42,
> +       43, 43, 45, 46, 47, 48, 49, 50,
> +       51, 52, 53, 2, 3, 55, 56, 57,
> +       58, 59, 60, 61, 62, 63, 2, 65,
> +       66, 67, 68, 69, 2, 70, 71, 70,
> +       71, 72, 1, 72, 72
>  };
>
>  static const char _gdb_trans_actions[] = {
> -       19, 1, 77, 81, 19, 65, 19, 69,
> -       61, 73, 19, 19, 3, 0, 7, 0,
> -       28, 25, 5, 34, 25, 22, 25, 85,
> -       31, 3, 3, 3, 3, 3, 3, 3,
> -       3, 3, 3, 3, 3, 3, 49, 25,
> -       22, 3, 40, 3, 3, 3, 3, 3,
> -       3, 3, 3, 3, 3, 37, 3, 3,
> -       3, 3, 3, 3, 3, 3, 3, 43,
> -       9, 3, 3, 3, 3, 3, 3, 3,
> -       3, 3, 46, 3, 3, 3, 3, 3,
> -       52, 3, 3, 55, 58, 11, 13, 15,
> -       17
> +       19, 1, 71, 75, 19, 59, 19, 63,
> +       55, 67, 19, 19, 3, 0, 7, 0,
> +       28, 25, 5, 3, 3, 3, 3, 83,
> +       25, 22, 25, 79, 31, 3, 3, 3,
> +       3, 3, 3, 3, 3, 3, 3, 3,
> +       3, 3, 43, 25, 22, 3, 87, 3,
> +       3, 3, 3, 3, 3, 3, 3, 3,
> +       3, 34, 3, 3, 3, 3, 3, 3,
> +       3, 3, 3, 37, 9, 3, 3, 3,
> +       3, 3, 3, 3, 3, 3, 40, 3,
> +       3, 3, 3, 3, 46, 3, 3, 49,
> +       52, 11, 13, 15, 17
>  };
>
> -static const int gdb_start = 67;
> -static const int gdb_first_final = 67;
> +static const int gdb_start = 72;
> +static const int gdb_first_final = 72;
>  static const int gdb_error = 0;
>
> -static const int gdb_en_main = 67;
> +static const int gdb_en_main = 72;
>
>
> -#line 159 "src/gdb_parser.rl"
> +#line 161 "src/gdb_parser.rl"
>
>  void parser_init(command_cb *callbacks)
>  {
>
> -#line 200 "src/gdb_parser_precompile.c"
> +#line 211 "src/gdb_parser_precompile.c"
>         {
>         cs = gdb_start;
>         }
>
> -#line 163 "src/gdb_parser.rl"
> +#line 165 "src/gdb_parser.rl"
>
>         command_callbacks = callbacks;
>  }
> @@ -212,7 +223,7 @@ int parse_buffer(char *buf, size_t len, void *priv)
>         char *pe = p + len;
>
>
> -#line 216 "src/gdb_parser_precompile.c"
> +#line 227 "src/gdb_parser_precompile.c"
>         {
>         int _klen;
>         unsigned int _trans;
> @@ -399,61 +410,65 @@ _match:
>         break;
>         case 12:
>  #line 109 "src/gdb_parser.rl"
> -       {cmd = SET_THREAD;}
> +       {cmd = DETACH;}
>         break;
>         case 13:
> -#line 111 "src/gdb_parser.rl"
> -       {cmd = DETACH;}
> +#line 113 "src/gdb_parser.rl"
> +       {rsp = "1";}
>         break;
>         case 14:
> -#line 115 "src/gdb_parser.rl"
> -       {rsp = "1";}
> +#line 114 "src/gdb_parser.rl"
> +       {rsp = "QC1";}
>         break;
>         case 15:
> -#line 116 "src/gdb_parser.rl"
> -       {rsp = "QC1";}
> +#line 115 "src/gdb_parser.rl"
> +       {rsp = "multiprocess+;vContSupported+;QStartNoAckMode+"; ack_mode = true;}
>         break;
>         case 16:
> -#line 117 "src/gdb_parser.rl"
> -       {rsp = "multiprocess+;vContSupported+;QStartNoAckMode+"; ack_mode = true;}
> +#line 116 "src/gdb_parser.rl"
> +       {rsp = "m1l";}
>         break;
>         case 17:
> -#line 118 "src/gdb_parser.rl"
> -       {rsp = "m1l";}
> +#line 117 "src/gdb_parser.rl"
> +       {rsp = "OK"; send_ack(priv); ack_mode = false;}
>         break;
>         case 18:
> -#line 119 "src/gdb_parser.rl"
> -       {rsp = "OK"; send_ack(priv); ack_mode = false;}
> +#line 120 "src/gdb_parser.rl"
> +       {cmd = GET_THREAD;}
>         break;
>         case 19:
> -#line 122 "src/gdb_parser.rl"
> -       {rsp = "vCont;c;C;s;S";}
> +#line 121 "src/gdb_parser.rl"
> +       {cmd = SET_THREAD;}
>         break;
>         case 20:
> -#line 123 "src/gdb_parser.rl"
> -       {cmd = V_CONTC;}
> +#line 124 "src/gdb_parser.rl"
> +       {rsp = "vCont;c;C;s;S";}
>         break;
>         case 21:
> -#line 124 "src/gdb_parser.rl"
> -       {cmd = V_CONTS;}
> +#line 125 "src/gdb_parser.rl"
> +       {cmd = V_CONTC;}
>         break;
>         case 22:
> -#line 127 "src/gdb_parser.rl"
> -       { if (command_callbacks) command_callbacks[INTERRUPT](stack, priv); PR_INFO("RAGEL:interrupt\n");}
> +#line 126 "src/gdb_parser.rl"
> +       {cmd = V_CONTS;}
>         break;
>         case 23:
> -#line 135 "src/gdb_parser.rl"
> -       {PR_INFO("RAGEL:cmd\n");}
> +#line 129 "src/gdb_parser.rl"
> +       { if (command_callbacks) command_callbacks[INTERRUPT](stack, priv); PR_INFO("RAGEL:interrupt\n");}
>         break;
>         case 24:
> -#line 138 "src/gdb_parser.rl"
> -       {PR_INFO("RAGEL:ack\n");}
> +#line 137 "src/gdb_parser.rl"
> +       {PR_INFO("RAGEL:cmd\n");}
>         break;
>         case 25:
> -#line 139 "src/gdb_parser.rl"
> +#line 140 "src/gdb_parser.rl"
> +       {PR_INFO("RAGEL:ack\n");}
> +       break;
> +       case 26:
> +#line 141 "src/gdb_parser.rl"
>         {PR_INFO("RAGEL:nack\n");}
>         break;
> -#line 457 "src/gdb_parser_precompile.c"
> +#line 472 "src/gdb_parser_precompile.c"
>                 }
>         }
>
> @@ -466,7 +481,7 @@ _again:
>         _out: {}
>         }
>
> -#line 173 "src/gdb_parser.rl"
> +#line 175 "src/gdb_parser.rl"
>
>         if (cs == gdb_error) {
>                 printf("parse error\n");
> diff --git a/src/pdbgproxy.c b/src/pdbgproxy.c
> index d0da1f37..4f30ede2 100644
> --- a/src/pdbgproxy.c
> +++ b/src/pdbgproxy.c
> @@ -93,9 +93,42 @@ void send_ack(void *priv)
>         send(fd, ACK, 1, 0);
>  }
>
> +static void get_thread(uint64_t *stack, void *priv)
> +{
> +       struct thread *thread = target_to_thread(thread_target);
> +       struct gdb_thread *gdb_thread = thread->gdbserver_priv;
> +       char data[3+4+2+1]; /* 'QCp' + 4 hex digits + '.0' + NUL */
> +
> +       snprintf(data, sizeof(data), "QC%04" PRIx64, gdb_thread->pir);
> +
> +       PR_INFO("get_thread pir=%"PRIx64"\n", gdb_thread->pir);
> +
> +       send_response(fd, data);
> +}
> +
>  static void set_thread(uint64_t *stack, void *priv)
>  {
> -       send_response(fd, OK);
> +       struct pdbg_target *target;
> +       uint64_t pir = stack[0];
> +
> +       PR_INFO("set_thread pir=%"PRIx64"\n", pir);
> +
> +       for_each_path_target_class("thread", target) {
> +               struct thread *thread = target_to_thread(target);
> +               struct gdb_thread *gdb_thread;
> +
> +               if (pdbg_target_status(target) != PDBG_TARGET_ENABLED)
> +                       continue;
> +
> +               gdb_thread = thread->gdbserver_priv;
> +
> +               if (gdb_thread->pir == pir) {
> +                       thread_target = target;
> +                       send_response(fd, OK);
> +                       return;
> +               }
> +       }
> +       send_response(fd, ERROR(EEXIST));
>  }
>
>  static void stop_reason(uint64_t *stack, void *priv)
> @@ -684,6 +717,7 @@ static command_cb callbacks[LAST_CMD + 1] = {
>         get_spr,
>         get_mem,
>         stop_reason,
> +       get_thread,
>         set_thread,
>         v_contc,
>         v_conts,
> diff --git a/src/pdbgproxy.h b/src/pdbgproxy.h
> index 1910fdba..2005083d 100644
> --- a/src/pdbgproxy.h
> +++ b/src/pdbgproxy.h
> @@ -2,7 +2,7 @@
>  #define __PDBGPROXY_H
>
>  enum gdb_command {NONE, GET_GPRS, GET_SPR, GET_MEM,
> -                 STOP_REASON, SET_THREAD, V_CONTC, V_CONTS,
> +                 STOP_REASON, GET_THREAD, SET_THREAD, V_CONTC, V_CONTS,
>                   PUT_MEM, INTERRUPT, DETACH, LAST_CMD};
>  typedef void (*command_cb)(uint64_t *stack, void *priv);
>
> --
> 2.35.1
>
> --
> Pdbg mailing list
> Pdbg@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/pdbg
diff mbox series

Patch

diff --git a/src/gdb_parser.rl b/src/gdb_parser.rl
index e49d56d3..dc1275c3 100644
--- a/src/gdb_parser.rl
+++ b/src/gdb_parser.rl
@@ -106,8 +106,6 @@ 
 
 	stop_reason = ('?' @{cmd = STOP_REASON;});
 
-	set_thread = ('H' any* @{cmd = SET_THREAD;});
-
 	detach = ('D' @{cmd = DETACH;}
 		     xdigit+ $hex_digit %push);
 
@@ -118,6 +116,10 @@ 
 	qf_threadinfo = ('qfThreadInfo' @{rsp = "m1l";});
 	q_start_noack = ('QStartNoAckMode' @{rsp = "OK"; send_ack(priv); ack_mode = false;});
 
+	# thread info
+	get_thread = ('qC' @{cmd = GET_THREAD;});
+	set_thread = ('Hg' ('p' xdigit+ '.')+ xdigit+ $hex_digit %push @{cmd = SET_THREAD;});
+
 	# vCont packet parsing
 	v_contq = ('vCont?' @{rsp = "vCont;c;C;s;S";});
 	v_contc = ('vCont;c' any* @{cmd = V_CONTC;});
@@ -126,7 +128,7 @@ 
 
 	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 |
+	commands = (get_mem | get_gprs | get_spr | stop_reason | get_thread | set_thread |
 		    q_attached | q_C | q_supported | qf_threadinfo | q_C |
 		    q_start_noack | v_contq | v_contc | v_conts | put_mem |
 		    detach | unknown );
diff --git a/src/gdb_parser_precompile.c b/src/gdb_parser_precompile.c
index db982092..567f1dd6 100644
--- a/src/gdb_parser_precompile.c
+++ b/src/gdb_parser_precompile.c
@@ -11,7 +11,7 @@ 
 #include "debug.h"
 
 
-#line 143 "src/gdb_parser.rl"
+#line 145 "src/gdb_parser.rl"
 
 
 static enum gdb_command cmd = NONE;
@@ -31,29 +31,30 @@  static bool ack_mode = true;
 #line 32 "src/gdb_parser_precompile.c"
 static const char _gdb_actions[] = {
 	0, 1, 0, 1, 1, 1, 2, 1, 
-	3, 1, 16, 1, 22, 1, 23, 1, 
-	24, 1, 25, 2, 0, 1, 2, 2, 
+	3, 1, 15, 1, 23, 1, 24, 1, 
+	25, 1, 26, 2, 0, 1, 2, 2, 
 	1, 2, 3, 1, 2, 3, 5, 2, 
-	4, 1, 2, 12, 1, 2, 14, 1, 
-	2, 15, 1, 2, 16, 1, 2, 17, 
-	1, 2, 18, 1, 2, 19, 1, 2, 
-	20, 1, 2, 21, 1, 3, 0, 6, 
-	1, 3, 0, 7, 1, 3, 0, 9, 
-	1, 3, 0, 10, 1, 3, 0, 11, 
-	1, 3, 0, 13, 1, 3, 2, 8, 
-	1
+	4, 1, 2, 13, 1, 2, 15, 1, 
+	2, 16, 1, 2, 17, 1, 2, 20, 
+	1, 2, 21, 1, 2, 22, 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, 19, 1, 3, 
+	18, 14, 1
 };
 
 static const unsigned char _gdb_key_offsets[] = {
 	0, 0, 11, 12, 18, 24, 31, 38, 
-	39, 46, 54, 61, 69, 76, 78, 80, 
-	82, 84, 86, 88, 90, 92, 94, 96, 
-	98, 100, 102, 104, 111, 119, 124, 126, 
-	128, 130, 132, 134, 136, 138, 140, 147, 
-	149, 151, 153, 155, 157, 159, 161, 163, 
-	165, 166, 168, 170, 172, 174, 176, 178, 
-	180, 182, 184, 186, 188, 190, 192, 194, 
-	197, 200, 201, 202
+	40, 42, 49, 57, 65, 72, 79, 87, 
+	94, 102, 109, 111, 113, 115, 117, 119, 
+	121, 123, 125, 127, 129, 131, 133, 135, 
+	137, 144, 152, 157, 159, 161, 163, 165, 
+	167, 169, 171, 173, 180, 182, 184, 186, 
+	188, 190, 192, 194, 196, 198, 199, 201, 
+	203, 205, 207, 209, 211, 213, 215, 217, 
+	219, 221, 223, 225, 227, 230, 233, 234, 
+	235
 };
 
 static const char _gdb_trans_keys[] = {
@@ -61,64 +62,71 @@  static const char _gdb_trans_keys[] = {
 	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, 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, 
+	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, 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, 
-	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
+	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, 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, 43, 45, 0
 };
 
 static const char _gdb_single_lengths[] = {
-	0, 11, 1, 0, 0, 1, 1, 1, 
-	1, 2, 1, 2, 1, 2, 2, 2, 
+	0, 11, 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, 2, 2, 1, 2, 5, 2, 2, 
-	2, 2, 2, 2, 2, 2, 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, 
-	1, 2, 2, 2, 2, 2, 2, 2, 
-	2, 2, 2, 2, 2, 2, 2, 3, 
-	3, 1, 1, 4
+	2, 2, 2, 2, 3, 3, 1, 1, 
+	4
 };
 
 static const char _gdb_range_lengths[] = {
 	0, 0, 0, 3, 3, 3, 3, 0, 
-	3, 3, 3, 3, 3, 0, 0, 0, 
+	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, 0, 0, 3, 3, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 3, 0, 
+	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, 12, 14, 18, 22, 27, 32, 
-	34, 39, 45, 50, 56, 61, 64, 67, 
-	70, 73, 76, 79, 82, 85, 88, 91, 
-	94, 97, 100, 103, 108, 114, 120, 123, 
-	126, 129, 132, 135, 138, 141, 144, 149, 
-	152, 155, 158, 161, 164, 167, 170, 173, 
-	176, 178, 181, 184, 187, 190, 193, 196, 
-	199, 202, 205, 208, 211, 214, 217, 220, 
-	224, 228, 230, 232
+	35, 38, 43, 49, 55, 60, 65, 71, 
+	76, 82, 87, 90, 93, 96, 99, 102, 
+	105, 108, 111, 114, 117, 120, 123, 126, 
+	129, 134, 140, 146, 149, 152, 155, 158, 
+	161, 164, 167, 170, 175, 178, 181, 184, 
+	187, 190, 193, 196, 199, 202, 204, 207, 
+	210, 213, 216, 219, 222, 225, 228, 231, 
+	234, 237, 240, 243, 246, 250, 254, 256, 
+	258
 };
 
 static const char _gdb_indicies[] = {
@@ -126,82 +134,85 @@  static const char _gdb_indicies[] = {
 	9, 10, 11, 0, 13, 12, 14, 14, 
 	14, 15, 16, 16, 16, 15, 13, 17, 
 	17, 17, 12, 18, 17, 17, 17, 12, 
-	13, 19, 13, 20, 20, 20, 12, 13, 
-	21, 20, 20, 20, 12, 13, 22, 22, 
-	22, 12, 13, 23, 22, 22, 22, 12, 
-	13, 24, 24, 24, 12, 13, 25, 12, 
-	13, 26, 12, 13, 27, 12, 13, 28, 
-	12, 13, 29, 12, 13, 30, 12, 13, 
-	31, 12, 13, 32, 12, 13, 33, 12, 
-	13, 34, 12, 13, 35, 12, 13, 36, 
-	12, 13, 37, 12, 13, 38, 12, 13, 
-	39, 39, 39, 12, 13, 40, 39, 39, 
-	39, 12, 13, 41, 42, 43, 44, 12, 
-	13, 45, 12, 13, 46, 12, 13, 47, 
-	12, 13, 48, 12, 13, 49, 12, 13, 
-	50, 12, 13, 51, 12, 13, 52, 12, 
-	13, 53, 53, 53, 12, 13, 54, 12, 
-	13, 55, 12, 13, 56, 12, 13, 57, 
-	12, 13, 58, 12, 13, 59, 12, 13, 
-	60, 12, 13, 61, 12, 13, 62, 12, 
-	64, 63, 13, 65, 12, 13, 66, 12, 
-	13, 67, 12, 13, 68, 12, 13, 69, 
-	12, 13, 70, 12, 13, 71, 12, 13, 
-	72, 12, 13, 73, 12, 13, 74, 12, 
-	13, 75, 12, 13, 76, 12, 13, 77, 
-	12, 13, 78, 12, 13, 79, 80, 12, 
-	13, 81, 82, 12, 13, 83, 13, 84, 
-	85, 86, 87, 88, 15, 0
+	13, 19, 12, 13, 20, 12, 13, 21, 
+	21, 21, 12, 13, 22, 21, 21, 21, 
+	12, 13, 20, 23, 23, 23, 12, 18, 
+	23, 23, 23, 12, 13, 24, 24, 24, 
+	12, 13, 25, 24, 24, 24, 12, 13, 
+	26, 26, 26, 12, 13, 27, 26, 26, 
+	26, 12, 13, 28, 28, 28, 12, 13, 
+	29, 12, 13, 30, 12, 13, 31, 12, 
+	13, 32, 12, 13, 33, 12, 13, 34, 
+	12, 13, 35, 12, 13, 36, 12, 13, 
+	37, 12, 13, 38, 12, 13, 39, 12, 
+	13, 40, 12, 13, 41, 12, 13, 42, 
+	12, 13, 43, 43, 43, 12, 13, 44, 
+	43, 43, 43, 12, 13, 45, 46, 47, 
+	48, 12, 13, 49, 12, 13, 50, 12, 
+	13, 51, 12, 13, 52, 12, 13, 53, 
+	12, 13, 54, 12, 13, 55, 12, 13, 
+	56, 12, 13, 57, 57, 57, 12, 13, 
+	58, 12, 13, 59, 12, 13, 60, 12, 
+	13, 61, 12, 13, 62, 12, 13, 63, 
+	12, 13, 64, 12, 13, 65, 12, 13, 
+	66, 12, 68, 67, 13, 69, 12, 13, 
+	70, 12, 13, 71, 12, 13, 72, 12, 
+	13, 73, 12, 13, 74, 12, 13, 75, 
+	12, 13, 76, 12, 13, 77, 12, 13, 
+	78, 12, 13, 79, 12, 13, 80, 12, 
+	13, 81, 12, 13, 82, 12, 13, 83, 
+	84, 12, 13, 85, 86, 12, 13, 87, 
+	13, 88, 89, 90, 91, 92, 15, 0
 };
 
 static const char _gdb_trans_targs[] = {
-	2, 3, 2, 5, 7, 8, 13, 2, 
-	27, 5, 29, 59, 2, 3, 4, 0, 
-	67, 6, 3, 7, 9, 10, 11, 12, 
-	12, 14, 15, 16, 17, 18, 19, 20, 
-	21, 22, 23, 24, 25, 26, 2, 28, 
-	5, 30, 2, 39, 49, 31, 32, 33, 
-	34, 35, 36, 37, 38, 38, 40, 41, 
-	42, 43, 44, 45, 46, 47, 48, 2, 
-	3, 50, 51, 52, 53, 54, 55, 56, 
-	57, 58, 2, 60, 61, 62, 63, 64, 
-	2, 65, 66, 65, 66, 67, 1, 67, 
-	67
+	2, 3, 2, 5, 7, 13, 18, 2, 
+	32, 5, 34, 64, 2, 3, 4, 0, 
+	72, 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, 5, 35, 2, 44, 
+	54, 36, 37, 38, 39, 40, 41, 42, 
+	43, 43, 45, 46, 47, 48, 49, 50, 
+	51, 52, 53, 2, 3, 55, 56, 57, 
+	58, 59, 60, 61, 62, 63, 2, 65, 
+	66, 67, 68, 69, 2, 70, 71, 70, 
+	71, 72, 1, 72, 72
 };
 
 static const char _gdb_trans_actions[] = {
-	19, 1, 77, 81, 19, 65, 19, 69, 
-	61, 73, 19, 19, 3, 0, 7, 0, 
-	28, 25, 5, 34, 25, 22, 25, 85, 
-	31, 3, 3, 3, 3, 3, 3, 3, 
-	3, 3, 3, 3, 3, 3, 49, 25, 
-	22, 3, 40, 3, 3, 3, 3, 3, 
-	3, 3, 3, 3, 3, 37, 3, 3, 
-	3, 3, 3, 3, 3, 3, 3, 43, 
-	9, 3, 3, 3, 3, 3, 3, 3, 
-	3, 3, 46, 3, 3, 3, 3, 3, 
-	52, 3, 3, 55, 58, 11, 13, 15, 
-	17
+	19, 1, 71, 75, 19, 59, 19, 63, 
+	55, 67, 19, 19, 3, 0, 7, 0, 
+	28, 25, 5, 3, 3, 3, 3, 83, 
+	25, 22, 25, 79, 31, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 43, 25, 22, 3, 87, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 34, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 37, 9, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 40, 3, 
+	3, 3, 3, 3, 46, 3, 3, 49, 
+	52, 11, 13, 15, 17
 };
 
-static const int gdb_start = 67;
-static const int gdb_first_final = 67;
+static const int gdb_start = 72;
+static const int gdb_first_final = 72;
 static const int gdb_error = 0;
 
-static const int gdb_en_main = 67;
+static const int gdb_en_main = 72;
 
 
-#line 159 "src/gdb_parser.rl"
+#line 161 "src/gdb_parser.rl"
 
 void parser_init(command_cb *callbacks)
 {
 	
-#line 200 "src/gdb_parser_precompile.c"
+#line 211 "src/gdb_parser_precompile.c"
 	{
 	cs = gdb_start;
 	}
 
-#line 163 "src/gdb_parser.rl"
+#line 165 "src/gdb_parser.rl"
 
 	command_callbacks = callbacks;
 }
@@ -212,7 +223,7 @@  int parse_buffer(char *buf, size_t len, void *priv)
 	char *pe = p + len;
 
 	
-#line 216 "src/gdb_parser_precompile.c"
+#line 227 "src/gdb_parser_precompile.c"
 	{
 	int _klen;
 	unsigned int _trans;
@@ -399,61 +410,65 @@  _match:
 	break;
 	case 12:
 #line 109 "src/gdb_parser.rl"
-	{cmd = SET_THREAD;}
+	{cmd = DETACH;}
 	break;
 	case 13:
-#line 111 "src/gdb_parser.rl"
-	{cmd = DETACH;}
+#line 113 "src/gdb_parser.rl"
+	{rsp = "1";}
 	break;
 	case 14:
-#line 115 "src/gdb_parser.rl"
-	{rsp = "1";}
+#line 114 "src/gdb_parser.rl"
+	{rsp = "QC1";}
 	break;
 	case 15:
-#line 116 "src/gdb_parser.rl"
-	{rsp = "QC1";}
+#line 115 "src/gdb_parser.rl"
+	{rsp = "multiprocess+;vContSupported+;QStartNoAckMode+"; ack_mode = true;}
 	break;
 	case 16:
-#line 117 "src/gdb_parser.rl"
-	{rsp = "multiprocess+;vContSupported+;QStartNoAckMode+"; ack_mode = true;}
+#line 116 "src/gdb_parser.rl"
+	{rsp = "m1l";}
 	break;
 	case 17:
-#line 118 "src/gdb_parser.rl"
-	{rsp = "m1l";}
+#line 117 "src/gdb_parser.rl"
+	{rsp = "OK"; send_ack(priv); ack_mode = false;}
 	break;
 	case 18:
-#line 119 "src/gdb_parser.rl"
-	{rsp = "OK"; send_ack(priv); ack_mode = false;}
+#line 120 "src/gdb_parser.rl"
+	{cmd = GET_THREAD;}
 	break;
 	case 19:
-#line 122 "src/gdb_parser.rl"
-	{rsp = "vCont;c;C;s;S";}
+#line 121 "src/gdb_parser.rl"
+	{cmd = SET_THREAD;}
 	break;
 	case 20:
-#line 123 "src/gdb_parser.rl"
-	{cmd = V_CONTC;}
+#line 124 "src/gdb_parser.rl"
+	{rsp = "vCont;c;C;s;S";}
 	break;
 	case 21:
-#line 124 "src/gdb_parser.rl"
-	{cmd = V_CONTS;}
+#line 125 "src/gdb_parser.rl"
+	{cmd = V_CONTC;}
 	break;
 	case 22:
-#line 127 "src/gdb_parser.rl"
-	{ if (command_callbacks) command_callbacks[INTERRUPT](stack, priv); PR_INFO("RAGEL:interrupt\n");}
+#line 126 "src/gdb_parser.rl"
+	{cmd = V_CONTS;}
 	break;
 	case 23:
-#line 135 "src/gdb_parser.rl"
-	{PR_INFO("RAGEL:cmd\n");}
+#line 129 "src/gdb_parser.rl"
+	{ if (command_callbacks) command_callbacks[INTERRUPT](stack, priv); PR_INFO("RAGEL:interrupt\n");}
 	break;
 	case 24:
-#line 138 "src/gdb_parser.rl"
-	{PR_INFO("RAGEL:ack\n");}
+#line 137 "src/gdb_parser.rl"
+	{PR_INFO("RAGEL:cmd\n");}
 	break;
 	case 25:
-#line 139 "src/gdb_parser.rl"
+#line 140 "src/gdb_parser.rl"
+	{PR_INFO("RAGEL:ack\n");}
+	break;
+	case 26:
+#line 141 "src/gdb_parser.rl"
 	{PR_INFO("RAGEL:nack\n");}
 	break;
-#line 457 "src/gdb_parser_precompile.c"
+#line 472 "src/gdb_parser_precompile.c"
 		}
 	}
 
@@ -466,7 +481,7 @@  _again:
 	_out: {}
 	}
 
-#line 173 "src/gdb_parser.rl"
+#line 175 "src/gdb_parser.rl"
 
 	if (cs == gdb_error) {
 		printf("parse error\n");
diff --git a/src/pdbgproxy.c b/src/pdbgproxy.c
index d0da1f37..4f30ede2 100644
--- a/src/pdbgproxy.c
+++ b/src/pdbgproxy.c
@@ -93,9 +93,42 @@  void send_ack(void *priv)
 	send(fd, ACK, 1, 0);
 }
 
+static void get_thread(uint64_t *stack, void *priv)
+{
+	struct thread *thread = target_to_thread(thread_target);
+	struct gdb_thread *gdb_thread = thread->gdbserver_priv;
+	char data[3+4+2+1]; /* 'QCp' + 4 hex digits + '.0' + NUL */
+
+	snprintf(data, sizeof(data), "QC%04" PRIx64, gdb_thread->pir);
+
+	PR_INFO("get_thread pir=%"PRIx64"\n", gdb_thread->pir);
+
+	send_response(fd, data);
+}
+
 static void set_thread(uint64_t *stack, void *priv)
 {
-	send_response(fd, OK);
+	struct pdbg_target *target;
+	uint64_t pir = stack[0];
+
+	PR_INFO("set_thread pir=%"PRIx64"\n", pir);
+
+	for_each_path_target_class("thread", target) {
+		struct thread *thread = target_to_thread(target);
+		struct gdb_thread *gdb_thread;
+
+		if (pdbg_target_status(target) != PDBG_TARGET_ENABLED)
+			continue;
+
+		gdb_thread = thread->gdbserver_priv;
+
+		if (gdb_thread->pir == pir) {
+			thread_target = target;
+			send_response(fd, OK);
+			return;
+		}
+	}
+	send_response(fd, ERROR(EEXIST));
 }
 
 static void stop_reason(uint64_t *stack, void *priv)
@@ -684,6 +717,7 @@  static command_cb callbacks[LAST_CMD + 1] = {
 	get_spr,
 	get_mem,
 	stop_reason,
+	get_thread,
 	set_thread,
 	v_contc,
 	v_conts,
diff --git a/src/pdbgproxy.h b/src/pdbgproxy.h
index 1910fdba..2005083d 100644
--- a/src/pdbgproxy.h
+++ b/src/pdbgproxy.h
@@ -2,7 +2,7 @@ 
 #define __PDBGPROXY_H
 
 enum gdb_command {NONE, GET_GPRS, GET_SPR, GET_MEM,
-                 STOP_REASON, SET_THREAD, V_CONTC, V_CONTS,
+                 STOP_REASON, GET_THREAD, SET_THREAD, V_CONTC, V_CONTS,
                  PUT_MEM, INTERRUPT, DETACH, LAST_CMD};
 typedef void (*command_cb)(uint64_t *stack, void *priv);