[RFC,v3] Consolidate gdbserver global variables

Message ID 9e844707-a2f8-c969-4d09-7ee2fa3bd1ed@redhat.com
State New, archived
Headers

Commit Message

Stan Cox May 8, 2018, 8:58 p.m. UTC
  (Addressed formatting and ChangeLog issues)

> As mentioned, I'm skeptical of all client_state references
> in the backends.
> 
> How will this work with multiple clients?   What if one client
> wants exec events, and the other one doesn't?  This seems to
> suggest that the backends need to enable exec events if _any_
> client wants them (or unconditionally), and then filter out exec
> events at a higher level, before reporting the event to
> each client?

Perhaps filtering that is roughly analogous to the way
gdb_catch_this_syscall_p filters for particular syscalls.

> This "= 0" is a spurious change.  Remove it.

Removed (it eliminated a compiler warning with gcc 7.3.1)

> Give the global different name to avoid conflict with
> the type name.  Maybe "g_client_state" or "the_client_state".

Used g_client_state and also made it static instead of allocating it
with new.

> What's the plan for last_status/last_ptid?
> Shouldn't those be per-client too?

Added those.

> Should these two be per client?  I'd think so off hand,
> since they correspond to the Hc/Hg threads?

Added cont_thread and general_thread

> I suspect that it'd be better to make the server_waiting
> global be per-process instead

Returned to server_waiting being a global for now.


Thanks Pedro!


Tested on linux with native-gdbserver.

Add client_state struct.

Collect per client specific global data items into struct client_state,
which is similar in purpose to remote.c::remote_state.

     * server.h (struct client_state): New.
     * server.c (cont_thread, general_thread, multi_process)
     (report_fork_events, report_vfork_events, report_exec_events)
     (report_thread_events, swbreak_feature, hwbreak_feature)
     (vCont_supported, disable_randomization, pass_signals)
     (program_signals, program_signals_p, last_status, last_ptid, own_buf):
     Moved to client_state.
     * remote-utils.c (remote_debug, noack_mode)
     (transport_is_reliable): Moved to client_state.
     * tracepoint.c (current_traceframe): Moved to client_state.

     Update all callers.
     * server.c, remote-utils.c, tracepoint.c, fork-child.c,
     gdbthread.h, hostio.c, linux-arm-low.c, linux-low.c, notif.c,
     remote-utils.h, spu-low.c, target.c, win32-low.c: Use
     client_state.


  gdb/gdbserver/fork-child.c   |   8 +-
  gdb/gdbserver/hostio.c       |   2 -
  gdb/gdbserver/linux-low.c    |  31 +++---
  gdb/gdbserver/notif.c        |   6 +-
  gdb/gdbserver/remote-utils.c | 146 ++++++++++++++-------------
  gdb/gdbserver/remote-utils.h |   4 -
  gdb/gdbserver/server.c       | 523 
+++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------
  gdb/gdbserver/server.h       | 104 +++++++++++++------
  gdb/gdbserver/target.c       |  15 ++-
  gdb/gdbserver/tracepoint.c   |  25 ++---
  10 files changed, 461 insertions(+), 403 deletions(-)


    if (!tframe)
@@ -2343,6 +2340,7 @@ find_next_traceframe_by_tracepoint (int num, int 
*tfnump)
  static void
  cmd_qtinit (char *packet)
  {
+  client_state &cs = get_client_state ();
    struct trace_state_variable *tsv, *prev, *next;

    /* Can't do this command without a pid attached.  */
@@ -2353,7 +2351,7 @@ cmd_qtinit (char *packet)
      }

    /* Make sure we don't try to read from a trace frame.  */
-  current_traceframe = -1;
+  cs.current_traceframe = -1;

    stop_tracing ();

@@ -2813,6 +2811,7 @@ cmd_qtenable_disable (char *own_buf, int enable)
  static void
  cmd_qtv (char *own_buf)
  {
+  client_state &cs = get_client_state ();
    ULONGEST num;
    LONGEST val = 0;
    int err;
@@ -2821,7 +2820,7 @@ cmd_qtv (char *own_buf)
    packet += strlen ("qTV:");
    unpack_varlen_hex (packet, &num);

-  if (current_traceframe >= 0)
+  if (cs.current_traceframe >= 0)
      {
        err = traceframe_read_tsv ((int) num, &val);
        if (err)
@@ -3552,6 +3551,7 @@ cmd_qtdisconnected (char *own_buf)
  static void
  cmd_qtframe (char *own_buf)
  {
+  client_state &cs = get_client_state ();
    ULONGEST frame, pc, lo, hi, num;
    int tfnum, tpnum;
    struct traceframe *tframe;
@@ -3602,7 +3602,7 @@ cmd_qtframe (char *own_buf)
        if (tfnum == -1)
  	{
  	  trace_debug ("Want to stop looking at traceframes");
-	  current_traceframe = -1;
+	  cs.current_traceframe = -1;
  	  write_ok (own_buf);
  	  return;
  	}
@@ -3612,7 +3612,7 @@ cmd_qtframe (char *own_buf)

    if (tframe)
      {
-      current_traceframe = tfnum;
+      cs.current_traceframe = tfnum;
        sprintf (own_buf, "F%xT%x", tfnum, tframe->tpnum);
      }
    else
@@ -5297,6 +5297,7 @@ traceframe_read_mem (int tfnum, CORE_ADDR addr,
  static int
  traceframe_read_tsv (int tsvnum, LONGEST *val)
  {
+  client_state &cs = get_client_state ();
    int tfnum;
    struct traceframe *tframe;
    unsigned char *database, *dataptr;
@@ -5306,7 +5307,7 @@ traceframe_read_tsv (int tsvnum, LONGEST *val)

    trace_debug ("traceframe_read_tsv");

-  tfnum = current_traceframe;
+  tfnum = cs.current_traceframe;

    if (tfnum < 0)
      {
  

Comments

Pedro Alves May 25, 2018, 2:31 p.m. UTC | #1
On 05/08/2018 09:58 PM, Stan Cox wrote:
> (Addressed formatting and ChangeLog issues)

Thanks.  This is looking great now.  Some comments below,
but no need for another round of review.

> 
>> As mentioned, I'm skeptical of all client_state references
>> in the backends.
>>
>> How will this work with multiple clients?   What if one client
>> wants exec events, and the other one doesn't?  This seems to
>> suggest that the backends need to enable exec events if _any_
>> client wants them (or unconditionally), and then filter out exec
>> events at a higher level, before reporting the event to
>> each client?
> 
> Perhaps filtering that is roughly analogous to the way
> gdb_catch_this_syscall_p filters for particular syscalls.
> 

>> This "= 0" is a spurious change.  Remove it.
> 
> Removed (it eliminated a compiler warning with gcc 7.3.1)

You mean, without the change, we trigger a warning?  What
does it look like?  If we do, then we'll need to address it
somehow, of course, given -Werror.  But I'd like to see
it first.

> Tested on linux with native-gdbserver.
> 
> Add client_state struct.
> 
> Collect per client specific global data items into struct client_state,
> which is similar in purpose to remote.c::remote_state.
> @@ -1835,6 +1820,7 @@ handle_qxfer_btrace (const char *annex,
>               gdb_byte *readbuf, const gdb_byte *writebuf,
>               ULONGEST offset, LONGEST len)
>  {
> +  client_state &cs = get_client_state ();
>    static struct buffer cache;

This "static" here made me notice that there is more global
state stored as function local static variables that should
be moved to client_state.  E.g.,:

$ nm -A server.o | c++filt  | grep " b " | grep "::"
server.o:0000000000000700 b guard variable for handle_query(char*, int, int*)::thread_iter
server.o:00000000000006f8 b handle_query(char*, int, int*)::thread_iter
server.o:00000000000006c0 b handle_qxfer_btrace(char const*, unsigned char*, unsigned char const*, unsigned long long, long long)::cache
server.o:00000000000006a0 b handle_qxfer_threads(char const*, unsigned char*, unsigned char const*, unsigned long long, long long)::result_length
server.o:0000000000000698 b handle_qxfer_threads(char const*, unsigned char*, unsigned char const*, unsigned long long, long long)::result
server.o:00000000000006e0 b handle_qxfer_btrace_conf(char const*, unsigned char*, unsigned char const*, unsigned long long, long long)::cache
server.o:00000000000006b0 b handle_qxfer_traceframe_info(char const*, unsigned char*, unsigned char const*, unsigned long long, long long)::result_length
server.o:00000000000006a8 b handle_qxfer_traceframe_info(char const*, unsigned char*, unsigned char const*, unsigned long long, long long)::result

That can be done as follow up.

> @@ -3643,7 +3642,7 @@ captured_main (int argc, char *argv[])
>          }
>      }
>        else if (strcmp (*next_arg, "--remote-debug") == 0)
> -    remote_debug = 1;
> +    cs.remote_debug = 1;

remote_debug controls whether to print debug output to gdbserver'
own terminal, so I'm thinking that it should probably remain
a global.

Otherwise it looks good to me.  If we don't need to handle
a warning, then feel free to push this in with the
remote_debug issue above addressed.

Thanks,
Pedro Alves
  
Stan Cox May 29, 2018, 7:52 p.m. UTC | #2
On 05/25/2018 10:31 AM, Pedro Alves wrote:

> You mean, without the change, we trigger a warning?  What
> does it look like?  If we do, then we'll need to address it
> somehow, of course, given -Werror.

This is vanilla upstream gdb, no patches, with gcc 7.3.1 on F27

../../../src/gdb/gdbserver/server.c: In function ‘int 
handle_qxfer_btrace_conf(const char*, gdb_byte*, const gdb_byte*, 
ULONGEST, LONGEST)’:
../../../src/gdb/gdbserver/server.c:1966:7: warning: ‘result’ may be 
used uninitialized in this function [-Wmaybe-uninitialized]
        if (result != 0)
        ^~
../../../src/gdb/gdbserver/server.c: In function ‘int 
handle_qxfer_btrace(const char*, gdb_byte*, const gdb_byte*, ULONGEST, 
LONGEST)’:
../../../src/gdb/gdbserver/server.c:1895:7: warning: ‘result’ may be 
used uninitialized in this function [-Wmaybe-uninitialized]
        if (result != 0)
        ^~
The source is an assignment in a TRY/CATCH
       TRY
         {
           result = target_read_btrace_conf (thread->btrace, &cache);
           if (result != 0)
             memcpy (own_buf, cache.buffer, cache.used_size);
         }
       CATCH (exception, RETURN_MASK_ERROR)
         {
           sprintf (own_buf, "E.%s", exception.message);
           result = -1;
         }
       END_CATCH

       if (result != 0)
         return -3;

> This "static" here made me notice that there is more global
> state stored as function local static variables that should
> be moved to client_state.  E.g.,:
> That can be done as follow up.

Will do

> remote_debug controls whether to print debug output to gdbserver'
> own terminal, so I'm thinking that it should probably remain
> a global.

Ah yes; I'll do that.
  
Pedro Alves May 30, 2018, 2:01 p.m. UTC | #3
On 05/29/2018 08:52 PM, Stan Cox wrote:
> 
> 
> On 05/25/2018 10:31 AM, Pedro Alves wrote:
> 
>> You mean, without the change, we trigger a warning?  What
>> does it look like?  If we do, then we'll need to address it
>> somehow, of course, given -Werror.
> 
> This is vanilla upstream gdb, no patches, 

Ah, alright, since this happens on pristine master, it's unrelated
to your patch.  Please leave it out.  And ...

> with gcc 7.3.1 on F27
> 
> ../../../src/gdb/gdbserver/server.c: In function ‘int handle_qxfer_btrace_conf(const char*, gdb_byte*, const gdb_byte*, ULONGEST, LONGEST)’:
> ../../../src/gdb/gdbserver/server.c:1966:7: warning: ‘result’ may be used uninitialized in this function [-Wmaybe-uninitialized]
>        if (result != 0)
>        ^~
> ../../../src/gdb/gdbserver/server.c: In function ‘int handle_qxfer_btrace(const char*, gdb_byte*, const gdb_byte*, ULONGEST, LONGEST)’:
> ../../../src/gdb/gdbserver/server.c:1895:7: warning: ‘result’ may be used uninitialized in this function [-Wmaybe-uninitialized]
>        if (result != 0)
>        ^~

I've looked into this and pushed a fix, here:

 https://sourceware.org/ml/gdb-patches/2018-05/msg00783.html

Thanks,
Pedro Alves
  
Tom Tromey June 8, 2018, 4:11 p.m. UTC | #4
>>>>> "Stan" == Stan Cox <scox@redhat.com> writes:

Stan>     * server.h (struct client_state): New.
Stan>     * server.c (cont_thread, general_thread, multi_process)
Stan>     (report_fork_events, report_vfork_events, report_exec_events)
Stan>     (report_thread_events, swbreak_feature, hwbreak_feature)
Stan>     (vCont_supported, disable_randomization, pass_signals)
Stan>     (program_signals, program_signals_p, last_status, last_ptid, own_buf):
Stan>     Moved to client_state.
Stan>     * remote-utils.c (remote_debug, noack_mode)
Stan>     (transport_is_reliable): Moved to client_state.
Stan>     * tracepoint.c (current_traceframe): Moved to client_state.

I think this broke the mingw build.

I configured with:

../binutils-gdb/configure --disable-{binutils,gas,gold,gprof,ld,sim} \
  --host i686-w64-mingw32 --target i686-w64-mingw32

Then building:

../../../binutils-gdb/gdb/gdbserver/win32-low.c: In function 'int win32_create_inferior(const char*, const std::vector<char*>&)':
../../../binutils-gdb/gdb/gdbserver/win32-low.c:709:3: error: 'last_ptid' was not declared in this scope
   last_ptid = win32_wait (pid_to_ptid (current_process_id), &last_status, 0);
   ^~~~~~~~~
../../../binutils-gdb/gdb/gdbserver/win32-low.c:709:3: note: suggested alternative: 'last_sig'
   last_ptid = win32_wait (pid_to_ptid (current_process_id), &last_status, 0);
   ^~~~~~~~~
   last_sig
../../../binutils-gdb/gdb/gdbserver/win32-low.c:709:62: error: 'last_status' was not declared in this scope
   last_ptid = win32_wait (pid_to_ptid (current_process_id), &last_status, 0);
                                                              ^~~~~~~~~~~
../../../binutils-gdb/gdb/gdbserver/win32-low.c:709:62: note: suggested alternative: 'cached_status'
   last_ptid = win32_wait (pid_to_ptid (current_process_id), &last_status, 0);
                                                              ^~~~~~~~~~~
                                                              cached_status

thanks,
Tom
  
Stan Cox June 8, 2018, 4:45 p.m. UTC | #5
> I think this broke the mingw build.
I have an old laptop with mingw on it; I'll take a look.
  
Tom Tromey June 8, 2018, 4:52 p.m. UTC | #6
>>>>> "Stan" == Stan Cox <scox@redhat.com> writes:

>> I think this broke the mingw build.
Stan> I have an old laptop with mingw on it; I'll take a look.

FWIW I just installed the mingw cross compilers on Fedora.  It's super
easy, just "dnf install" a few things and you're ready to build.

Tom
  
Sergio Durigan Junior July 10, 2018, 1:14 a.m. UTC | #7
On Tuesday, May 08 2018, Stan Cox wrote:

> (Addressed formatting and ChangeLog issues)
>
>> As mentioned, I'm skeptical of all client_state references
>> in the backends.
>>
>> How will this work with multiple clients?   What if one client
>> wants exec events, and the other one doesn't?  This seems to
>> suggest that the backends need to enable exec events if _any_
>> client wants them (or unconditionally), and then filter out exec
>> events at a higher level, before reporting the event to
>> each client?
>
> Perhaps filtering that is roughly analogous to the way
> gdb_catch_this_syscall_p filters for particular syscalls.
>
>> This "= 0" is a spurious change.  Remove it.
>
> Removed (it eliminated a compiler warning with gcc 7.3.1)
>
>> Give the global different name to avoid conflict with
>> the type name.  Maybe "g_client_state" or "the_client_state".
>
> Used g_client_state and also made it static instead of allocating it
> with new.
>
>> What's the plan for last_status/last_ptid?
>> Shouldn't those be per-client too?
>
> Added those.
>
>> Should these two be per client?  I'd think so off hand,
>> since they correspond to the Hc/Hg threads?
>
> Added cont_thread and general_thread
>
>> I suspect that it'd be better to make the server_waiting
>> global be per-process instead
>
> Returned to server_waiting being a global for now.
>
>
> Thanks Pedro!
>
>
> Tested on linux with native-gdbserver.

Hi Stan,

This patch introduced a regression on GDB when testing with
--target_board=native-gdbserver.  The failure is described here:

  https://sourceware.org/bugzilla/show_bug.cgi?id=23378

I've been trying to narrow down the cause, but so far have not been very
successful.  It seems that everything was covered by your patch, so I'm
guessing there must be some hidden spot where we're forgetting to update
some internal state and the failure ends up happening.

For the sake of comparison, here's the output that should have been
printed:

  Expecting: ^(-var-update L[
  ]+)?(\^done,changelist=\[{name="L",in_scope="true",type_changed="false",has_more="0"}\][
  ]+[(]gdb[)] 
  [ ]*)
  -var-update L
  ^done,changelist=[{name="L",in_scope="true",type_changed="false",has_more="0"}]
  (gdb) 
  PASS: gdb.mi/mi-var-cmd.exp: in-and-out-of-scope: in scope now

And this is what the failure looks like:

  Expecting: ^(-var-update L[
  ]+)?(\^done,changelist=\[{name="L",in_scope="true",type_changed="false",has_more="0"}\][
  ]+[(]gdb[)] 
  [ ]*)
  -var-update L
  ^done,changelist=[]
  (gdb) 
  FAIL: gdb.mi/mi-var-cmd.exp: in-and-out-of-scope: in scope now (unexpected output)

Something to take into consideration is that gdbserver is restarted
many times during the testcase.  I think this may have something to do
with it, because the test doesn't fail on native-extended-gdbserver.

Thanks,
  

Patch

diff --git a/gdb/gdbserver/fork-child.c b/gdb/gdbserver/fork-child.c
index 831e7e1310..0dfd69d626 100644
--- a/gdb/gdbserver/fork-child.c
+++ b/gdb/gdbserver/fork-child.c
@@ -44,6 +44,7 @@  restore_old_foreground_pgrp (void)
  void
  prefork_hook (const char *args)
  {
+  client_state &cs = get_client_state ();
    if (debug_threads)
      {
        debug_printf ("args: %s\n", args);
@@ -57,7 +58,7 @@  prefork_hook (const char *args)

    /* Clear this so the backend doesn't get confused, thinking
       CONT_THREAD died, and it needs to resume all threads.  */
-  cont_thread = null_ptid;
+  cs.cont_thread = null_ptid;
  }

  /* See nat/fork-inferior.h.  */
@@ -96,6 +97,7 @@  gdb_flush_out_err ()
  void
  post_fork_inferior (int pid, const char *program)
  {
+  client_state &cs = get_client_state ();
  #ifdef SIGTTOU
    signal (SIGTTOU, SIG_IGN);
    signal (SIGTTIN, SIG_IGN);
@@ -106,9 +108,9 @@  post_fork_inferior (int pid, const char *program)
  #endif

    startup_inferior (pid, START_INFERIOR_TRAPS_EXPECTED,
-		    &last_status, &last_ptid);
+		    &cs.last_status, &cs.last_ptid);
    current_thread->last_resume_kind = resume_stop;
-  current_thread->last_status = last_status;
+  current_thread->last_status = cs.last_status;
    signal_pid = pid;
    target_post_create_inferior ();
    fprintf (stderr, "Process %s created; pid = %d\n", program, pid);
diff --git a/gdb/gdbserver/hostio.c b/gdb/gdbserver/hostio.c
index d2b5a71bad..4e388a85dc 100644
--- a/gdb/gdbserver/hostio.c
+++ b/gdb/gdbserver/hostio.c
@@ -29,8 +29,6 @@ 
  #include <sys/stat.h>
  #include "fileio.h"

-extern int remote_debug;
-
  struct fd_list
  {
    int fd;
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index e64949504d..f8507b7968 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -475,6 +475,7 @@  linux_arch_setup_thread (struct thread_info *thread)
  static int
  handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat)
  {
+  client_state &cs = get_client_state ();
    struct lwp_info *event_lwp = *orig_event_lwp;
    int event = linux_ptrace_get_extended_event (wstat);
    struct thread_info *event_thr = get_lwp_thread (event_lwp);
@@ -655,7 +656,7 @@  handle_extended_wait (struct lwp_info 
**orig_event_lwp, int wstat)
  	  new_lwp->status_pending_p = 1;
  	  new_lwp->status_pending = status;
  	}
-      else if (report_thread_events)
+      else if (cs.report_thread_events)
  	{
  	  new_lwp->waitstatus.kind = TARGET_WAITKIND_THREAD_CREATED;
  	  new_lwp->status_pending_p = 1;
@@ -683,7 +684,7 @@  handle_extended_wait (struct lwp_info 
**orig_event_lwp, int wstat)
        /* Report the event.  */
        return 0;
      }
-  else if (event == PTRACE_EVENT_EXEC && report_exec_events)
+  else if (event == PTRACE_EVENT_EXEC && cs.report_exec_events)
      {
        struct process_info *proc;
        std::vector<int> syscalls_to_catch;
@@ -998,13 +999,14 @@  static int
  linux_create_inferior (const char *program,
  		       const std::vector<char *> &program_args)
  {
+  client_state &cs = get_client_state ();
    struct lwp_info *new_lwp;
    int pid;
    ptid_t ptid;

    {
      maybe_disable_address_space_randomization restore_personality
-      (disable_randomization);
+      (cs.disable_randomization);
      std::string str_program_args = stringify_argv (program_args);

      pid = fork_inferior (program,
@@ -1429,6 +1431,7 @@  linux_kill (int pid)
  static int
  get_detach_signal (struct thread_info *thread)
  {
+  client_state &cs = get_client_state ();
    enum gdb_signal signo = GDB_SIGNAL_0;
    int status;
    struct lwp_info *lp = get_thread_lwp (thread);
@@ -1469,7 +1472,7 @@  get_detach_signal (struct thread_info *thread)

    signo = gdb_signal_from_host (WSTOPSIG (status));

-  if (program_signals_p && !program_signals[signo])
+  if (cs.program_signals_p && !cs.program_signals[signo])
      {
        if (debug_threads)
  	debug_printf ("GPS: lwp %s had signal %s, but it is in nopass state\n",
@@ -1477,7 +1480,7 @@  get_detach_signal (struct thread_info *thread)
  		      gdb_signal_to_string (signo));
        return 0;
      }
-  else if (!program_signals_p
+  else if (!cs.program_signals_p
  	   /* If we have no way to know which signals GDB does not
  	      want to have passed to the program, assume
  	      SIGTRAP/SIGINT, which is GDB's default.  */
@@ -2328,18 +2331,19 @@  check_stopped_by_watchpoint (struct lwp_info *child)
  static int
  linux_low_ptrace_options (int attached)
  {
+  client_state &cs = get_client_state ();
    int options = 0;

    if (!attached)
      options |= PTRACE_O_EXITKILL;

-  if (report_fork_events)
+  if (cs.report_fork_events)
      options |= PTRACE_O_TRACEFORK;

-  if (report_vfork_events)
+  if (cs.report_vfork_events)
      options |= (PTRACE_O_TRACEVFORK | PTRACE_O_TRACEVFORKDONE);

-  if (report_exec_events)
+  if (cs.report_exec_events)
      options |= PTRACE_O_TRACEEXEC;

    options |= PTRACE_O_TRACESYSGOOD;
@@ -2354,6 +2358,7 @@  linux_low_ptrace_options (int attached)
  static struct lwp_info *
  linux_low_filter_event (int lwpid, int wstat)
  {
+  client_state &cs = get_client_state ();
    struct lwp_info *child;
    struct thread_info *thread;
    int have_stop_pc = 0;
@@ -2425,7 +2430,7 @@  linux_low_filter_event (int lwpid, int wstat)
        /* If there is at least one more LWP, then the exit signal was
  	 not the end of the debugged application and should be
  	 ignored, unless GDB wants to hear about thread exits.  */
-      if (report_thread_events
+      if (cs.report_thread_events
  	  || last_thread_of_process_p (pid_of (thread)))
  	{
  	  /* Since events are serialized to GDB core, and we can't
@@ -3049,12 +3054,13 @@  static ptid_t
  filter_exit_event (struct lwp_info *event_child,
  		   struct target_waitstatus *ourstatus)
  {
+  client_state &cs = get_client_state ();
    struct thread_info *thread = get_lwp_thread (event_child);
    ptid_t ptid = ptid_of (thread);

    if (!last_thread_of_process_p (pid_of (thread)))
      {
-      if (report_thread_events)
+      if (cs.report_thread_events)
  	ourstatus->kind = TARGET_WAITKIND_THREAD_EXITED;
        else
  	ourstatus->kind = TARGET_WAITKIND_IGNORE;
@@ -3106,6 +3112,7 @@  static ptid_t
  linux_wait_1 (ptid_t ptid,
  	      struct target_waitstatus *ourstatus, int target_options)
  {
+  client_state &cs = get_client_state ();
    int w;
    struct lwp_info *event_child;
    int options;
@@ -3475,7 +3482,7 @@  linux_wait_1 (ptid_t ptid,
  	       || WSTOPSIG (w) == __SIGRTMIN + 1))
  	  ||
  #endif
-	  (pass_signals[gdb_signal_from_host (WSTOPSIG (w))]
+	  (cs.pass_signals[gdb_signal_from_host (WSTOPSIG (w))]
  	   && !(WSTOPSIG (w) == SIGSTOP
  		&& current_thread->last_resume_kind == resume_stop)
  	   && !linux_wstatus_maybe_breakpoint (w))))
@@ -3782,7 +3789,7 @@  linux_wait_1 (ptid_t ptid,
       it was a software breakpoint, and the client doesn't know we can
       adjust the breakpoint ourselves.  */
    if (event_child->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT
-      && !swbreak_feature)
+      && !cs.swbreak_feature)
      {
        int decr_pc = the_low_target.decr_pc_after_break;

diff --git a/gdb/gdbserver/notif.c b/gdb/gdbserver/notif.c
index 5ff7079123..6480c3abc9 100644
--- a/gdb/gdbserver/notif.c
+++ b/gdb/gdbserver/notif.c
@@ -79,6 +79,7 @@  notif_write_event (struct notif_server *notif, char 
*own_buf)
  int
  handle_notif_ack (char *own_buf, int packet_len)
  {
+  client_state &cs = get_client_state ();
    size_t i;
    struct notif_server *np;

@@ -103,7 +104,7 @@  handle_notif_ack (char *own_buf, int packet_len)
        struct notif_event *head
  	= QUEUE_deque (notif_event_p, np->queue);

-      if (remote_debug)
+      if (cs.remote_debug)
  	debug_printf ("%s: acking %d\n", np->ack_name,
  		      QUEUE_length (notif_event_p, np->queue));

@@ -121,9 +122,10 @@  void
  notif_event_enque (struct notif_server *notif,
  		   struct notif_event *event)
  {
+  client_state &cs = get_client_state ();
    QUEUE_enque (notif_event_p, notif->queue, event);

-  if (remote_debug)
+  if (cs.remote_debug)
      debug_printf ("pending events: %s %d\n", notif->notif_name,
  		  QUEUE_length (notif_event_p, notif->queue));

diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c
index 3b5a459ae4..22c8187464 100644
--- a/gdb/gdbserver/remote-utils.c
+++ b/gdb/gdbserver/remote-utils.c
@@ -103,7 +103,6 @@  struct sym_cache
    struct sym_cache *next;
  };

-int remote_debug = 0;
  struct ui_file *gdb_stdlog;

  static int remote_is_stdio = 0;
@@ -115,11 +114,6 @@  static gdb_fildes_t listen_desc = INVALID_DESCRIPTOR;
  extern int using_threads;
  extern int debug_threads;

-/* If true, then GDB has requested noack mode.  */
-int noack_mode = 0;
-/* If true, then we tell GDB to use noack mode by default.  */
-int transport_is_reliable = 0;
-
  #ifdef USE_WIN32API
  # define read(fd, buf, len) recv (fd, (char *) buf, len, 0)
  # define write(fd, buf, len) send (fd, (char *) buf, len, 0)
@@ -222,6 +216,7 @@  handle_accept_event (int err, gdb_client_data 
client_data)
  void
  remote_prepare (const char *name)
  {
+  client_state &cs = get_client_state ();
    const char *port_str;
  #ifdef USE_WIN32API
    static int winsock_initialized;
@@ -238,14 +233,14 @@  remote_prepare (const char *name)
  	 call to remote_open so start_inferior knows the connection is
  	 via stdio.  */
        remote_is_stdio = 1;
-      transport_is_reliable = 1;
+      cs.transport_is_reliable = 1;
        return;
      }

    port_str = strchr (name, ':');
    if (port_str == NULL)
      {
-      transport_is_reliable = 0;
+      cs.transport_is_reliable = 0;
        return;
      }

@@ -280,7 +275,7 @@  remote_prepare (const char *name)
        || listen (listen_desc, 1))
      perror_with_name ("Can't bind address");

-  transport_is_reliable = 1;
+  cs.transport_is_reliable = 1;
  }

  /* Open a connection to a remote debugger.
@@ -485,9 +480,10 @@  try_rle (char *buf, int remaining, unsigned char 
*csum, char **p)
  char *
  write_ptid (char *buf, ptid_t ptid)
  {
+  client_state &cs = get_client_state ();
    int pid, tid;

-  if (multi_process)
+  if (cs.multi_process)
      {
        pid = ptid_get_pid (ptid);
        if (pid < 0)
@@ -594,6 +590,7 @@  read_prim (void *buf, int count)
  static int
  putpkt_binary_1 (char *buf, int cnt, int is_notif)
  {
+  client_state &cs = get_client_state ();
    int i;
    unsigned char csum = 0;
    char *buf2;
@@ -631,10 +628,10 @@  putpkt_binary_1 (char *buf, int cnt, int is_notif)
  	  return -1;
  	}

-      if (noack_mode || is_notif)
+      if (cs.noack_mode || is_notif)
  	{
  	  /* Don't expect an ack then.  */
-	  if (remote_debug)
+	  if (cs.remote_debug)
  	    {
  	      if (is_notif)
  		debug_printf ("putpkt (\"%s\"); [notif]\n", buf2);
@@ -645,7 +642,7 @@  putpkt_binary_1 (char *buf, int cnt, int is_notif)
  	  break;
  	}

-      if (remote_debug)
+      if (cs.remote_debug)
  	{
  	  debug_printf ("putpkt (\"%s\"); [looking for ack]\n", buf2);
  	  debug_flush ();
@@ -659,7 +656,7 @@  putpkt_binary_1 (char *buf, int cnt, int is_notif)
  	  return -1;
  	}

-      if (remote_debug)
+      if (cs.remote_debug)
  	{
  	  debug_printf ("[received '%c' (0x%x)]\n", cc, cc);
  	  debug_flush ();
@@ -851,6 +848,7 @@  static unsigned char *readchar_bufp;
  static int
  readchar (void)
  {
+  client_state &cs = get_client_state ();
    int ch;

    if (readchar_bufcnt == 0)
@@ -861,7 +859,7 @@  readchar (void)
  	{
  	  if (readchar_bufcnt == 0)
  	    {
-	      if (remote_debug)
+	      if (cs.remote_debug)
  		debug_printf ("readchar: Got EOF\n");
  	    }
  	  else
@@ -926,6 +924,7 @@  reschedule (void)
  int
  getpkt (char *buf)
  {
+  client_state &cs = get_client_state ();
    char *bp;
    unsigned char csum, c1, c2;
    int c;
@@ -948,7 +947,7 @@  getpkt (char *buf)

  	  if (c == '$')
  	    break;
-	  if (remote_debug)
+	  if (cs.remote_debug)
  	    {
  	      debug_printf ("[getpkt: discarding char '%c']\n", c);
  	      debug_flush ();
@@ -977,7 +976,7 @@  getpkt (char *buf)
        if (csum == (c1 << 4) + c2)
  	break;

-      if (noack_mode)
+      if (cs.noack_mode)
  	{
  	  fprintf (stderr,
  		   "Bad checksum, sentsum=0x%x, csum=0x%x, "
@@ -993,9 +992,9 @@  getpkt (char *buf)
  	return -1;
      }

-  if (!noack_mode)
+  if (!cs.noack_mode)
      {
-      if (remote_debug)
+      if (cs.remote_debug)
  	{
  	  debug_printf ("getpkt (\"%s\");  [sending ack] \n", buf);
  	  debug_flush ();
@@ -1004,7 +1003,7 @@  getpkt (char *buf)
        if (write_prim ("+", 1) != 1)
  	return -1;

-      if (remote_debug)
+      if (cs.remote_debug)
  	{
  	  debug_printf ("[sent ack]\n");
  	  debug_flush ();
@@ -1012,7 +1011,7 @@  getpkt (char *buf)
      }
    else
      {
-      if (remote_debug)
+      if (cs.remote_debug)
  	{
  	  debug_printf ("getpkt (\"%s\");  [no ack sent] \n", buf);
  	  debug_flush ();
@@ -1081,6 +1080,7 @@  void
  prepare_resume_reply (char *buf, ptid_t ptid,
  		      struct target_waitstatus *status)
  {
+  client_state &cs = get_client_state ();
    if (debug_threads)
      debug_printf ("Writing resume reply for %s:%d\n",
  		  target_pid_to_str (ptid), status->kind);
@@ -1100,8 +1100,9 @@  prepare_resume_reply (char *buf, ptid_t ptid,
  	const char **regp;
  	struct regcache *regcache;

-	if ((status->kind == TARGET_WAITKIND_FORKED && report_fork_events)
-	    || (status->kind == TARGET_WAITKIND_VFORKED && report_vfork_events))
+	if ((status->kind == TARGET_WAITKIND_FORKED && cs.report_fork_events)
+	    || (status->kind == TARGET_WAITKIND_VFORKED
+		&& cs.report_vfork_events))
  	  {
  	    enum gdb_signal signal = GDB_SIGNAL_TRAP;
  	    const char *event = (status->kind == TARGET_WAITKIND_FORKED
@@ -1112,13 +1113,14 @@  prepare_resume_reply (char *buf, ptid_t ptid,
  	    buf = write_ptid (buf, status->value.related_pid);
  	    strcat (buf, ";");
  	  }
-	else if (status->kind == TARGET_WAITKIND_VFORK_DONE && 
report_vfork_events)
+	else if (status->kind == TARGET_WAITKIND_VFORK_DONE
+		 && cs.report_vfork_events)
  	  {
  	    enum gdb_signal signal = GDB_SIGNAL_TRAP;

  	    sprintf (buf, "T%02xvforkdone:;", signal);
  	  }
-	else if (status->kind == TARGET_WAITKIND_EXECD && report_exec_events)
+	else if (status->kind == TARGET_WAITKIND_EXECD && cs.report_exec_events)
  	  {
  	    enum gdb_signal signal = GDB_SIGNAL_TRAP;
  	    const char *event = "exec";
@@ -1138,7 +1140,7 @@  prepare_resume_reply (char *buf, ptid_t ptid,
  	    buf += strlen (buf);
  	  }
  	else if (status->kind == TARGET_WAITKIND_THREAD_CREATED
-		 && report_thread_events)
+		 && cs.report_thread_events)
  	  {
  	    enum gdb_signal signal = GDB_SIGNAL_TRAP;

@@ -1186,12 +1188,12 @@  prepare_resume_reply (char *buf, ptid_t ptid,
  	      *buf++ = tohex ((addr >> (i - 1) * 4) & 0xf);
  	    *buf++ = ';';
  	  }
-	else if (swbreak_feature && target_stopped_by_sw_breakpoint ())
+	else if (cs.swbreak_feature && target_stopped_by_sw_breakpoint ())
  	  {
  	    sprintf (buf, "swbreak:;");
  	    buf += strlen (buf);
  	  }
-	else if (hwbreak_feature && target_stopped_by_hw_breakpoint ())
+	else if (cs.hwbreak_feature && target_stopped_by_hw_breakpoint ())
  	  {
  	    sprintf (buf, "hwbreak:;");
  	    buf += strlen (buf);
@@ -1219,13 +1221,13 @@  prepare_resume_reply (char *buf, ptid_t ptid,
  	       in GDB will claim this event belongs to inferior_ptid
  	       if we do not specify a thread, and there's no way for
  	       gdbserver to know what inferior_ptid is.  */
-	    if (1 || !ptid_equal (general_thread, ptid))
+	    if (1 || !ptid_equal (cs.general_thread, ptid))
  	      {
  		int core = -1;
  		/* In non-stop, don't change the general thread behind
  		   GDB's back.  */
  		if (!non_stop)
-		  general_thread = ptid;
+		  cs.general_thread = ptid;
  		sprintf (buf, "thread:");
  		buf += strlen (buf);
  		buf = write_ptid (buf, ptid);
@@ -1256,14 +1258,14 @@  prepare_resume_reply (char *buf, ptid_t ptid,
        }
        break;
      case TARGET_WAITKIND_EXITED:
-      if (multi_process)
+      if (cs.multi_process)
  	sprintf (buf, "W%x;process:%x",
  		 status->value.integer, ptid_get_pid (ptid));
        else
  	sprintf (buf, "W%02x", status->value.integer);
        break;
      case TARGET_WAITKIND_SIGNALLED:
-      if (multi_process)
+      if (cs.multi_process)
  	sprintf (buf, "X%x;process:%x",
  		 status->value.sig, ptid_get_pid (ptid));
        else
@@ -1435,6 +1437,7 @@  clear_symbol_cache (struct sym_cache **symcache_p)
  int
  look_up_one_symbol (const char *name, CORE_ADDR *addrp, int may_ask_gdb)
  {
+  client_state &cs = get_client_state ();
    char *p, *q;
    int len;
    struct sym_cache *sym;
@@ -1456,14 +1459,14 @@  look_up_one_symbol (const char *name, CORE_ADDR 
*addrp, int may_ask_gdb)
      return 0;

    /* Send the request.  */
-  strcpy (own_buf, "qSymbol:");
-  bin2hex ((const gdb_byte *) name, own_buf + strlen ("qSymbol:"),
+  strcpy (cs.own_buf, "qSymbol:");
+  bin2hex ((const gdb_byte *) name, cs.own_buf + strlen ("qSymbol:"),
  	  strlen (name));
-  if (putpkt (own_buf) < 0)
+  if (putpkt (cs.own_buf) < 0)
      return -1;

    /* FIXME:  Eventually add buffer overflow checking (to getpkt?)  */
-  len = getpkt (own_buf);
+  len = getpkt (cs.own_buf);
    if (len < 0)
      return -1;

@@ -1474,45 +1477,45 @@  look_up_one_symbol (const char *name, CORE_ADDR 
*addrp, int may_ask_gdb)
       while it figures out the address of the symbol.  */
    while (1)
      {
-      if (own_buf[0] == 'm')
+      if (cs.own_buf[0] == 'm')
  	{
  	  CORE_ADDR mem_addr;
  	  unsigned char *mem_buf;
  	  unsigned int mem_len;

-	  decode_m_packet (&own_buf[1], &mem_addr, &mem_len);
+	  decode_m_packet (&cs.own_buf[1], &mem_addr, &mem_len);
  	  mem_buf = (unsigned char *) xmalloc (mem_len);
  	  if (read_inferior_memory (mem_addr, mem_buf, mem_len) == 0)
-	    bin2hex (mem_buf, own_buf, mem_len);
+	    bin2hex (mem_buf, cs.own_buf, mem_len);
  	  else
-	    write_enn (own_buf);
+	    write_enn (cs.own_buf);
  	  free (mem_buf);
-	  if (putpkt (own_buf) < 0)
+	  if (putpkt (cs.own_buf) < 0)
  	    return -1;
  	}
-      else if (own_buf[0] == 'v')
+      else if (cs.own_buf[0] == 'v')
  	{
  	  int new_len = -1;
-	  handle_v_requests (own_buf, len, &new_len);
+	  handle_v_requests (cs.own_buf, len, &new_len);
  	  if (new_len != -1)
-	    putpkt_binary (own_buf, new_len);
+	    putpkt_binary (cs.own_buf, new_len);
  	  else
-	    putpkt (own_buf);
+	    putpkt (cs.own_buf);
  	}
        else
  	break;
-      len = getpkt (own_buf);
+      len = getpkt (cs.own_buf);
        if (len < 0)
  	return -1;
      }

-  if (!startswith (own_buf, "qSymbol:"))
+  if (!startswith (cs.own_buf, "qSymbol:"))
      {
-      warning ("Malformed response to qSymbol, ignoring: %s\n", own_buf);
+      warning ("Malformed response to qSymbol, ignoring: %s\n", 
cs.own_buf);
        return -1;
      }

-  p = own_buf + strlen ("qSymbol:");
+  p = cs.own_buf + strlen ("qSymbol:");
    q = p;
    while (*q && *q != ':')
      q++;
@@ -1548,17 +1551,18 @@  look_up_one_symbol (const char *name, CORE_ADDR 
*addrp, int may_ask_gdb)
  int
  relocate_instruction (CORE_ADDR *to, CORE_ADDR oldloc)
  {
+  client_state &cs = get_client_state ();
    int len;
    ULONGEST written = 0;

    /* Send the request.  */
-  sprintf (own_buf, "qRelocInsn:%s;%s", paddress (oldloc),
+  sprintf (cs.own_buf, "qRelocInsn:%s;%s", paddress (oldloc),
  	   paddress (*to));
-  if (putpkt (own_buf) < 0)
+  if (putpkt (cs.own_buf) < 0)
      return -1;

    /* FIXME:  Eventually add buffer overflow checking (to getpkt?)  */
-  len = getpkt (own_buf);
+  len = getpkt (cs.own_buf);
    if (len < 0)
      return -1;

@@ -1566,61 +1570,61 @@  relocate_instruction (CORE_ADDR *to, CORE_ADDR 
oldloc)
       wait for the qRelocInsn "response".  That requires re-entering
       the main loop.  For now, this is an adequate approximation; allow
       GDB to access memory.  */
-  while (own_buf[0] == 'm' || own_buf[0] == 'M' || own_buf[0] == 'X')
+  while (cs.own_buf[0] == 'm' || cs.own_buf[0] == 'M' || cs.own_buf[0] 
== 'X')
      {
        CORE_ADDR mem_addr;
        unsigned char *mem_buf = NULL;
        unsigned int mem_len;

-      if (own_buf[0] == 'm')
+      if (cs.own_buf[0] == 'm')
  	{
-	  decode_m_packet (&own_buf[1], &mem_addr, &mem_len);
+	  decode_m_packet (&cs.own_buf[1], &mem_addr, &mem_len);
  	  mem_buf = (unsigned char *) xmalloc (mem_len);
  	  if (read_inferior_memory (mem_addr, mem_buf, mem_len) == 0)
-	    bin2hex (mem_buf, own_buf, mem_len);
+	    bin2hex (mem_buf, cs.own_buf, mem_len);
  	  else
-	    write_enn (own_buf);
+	    write_enn (cs.own_buf);
  	}
-      else if (own_buf[0] == 'X')
+      else if (cs.own_buf[0] == 'X')
  	{
-	  if (decode_X_packet (&own_buf[1], len - 1, &mem_addr,
+	  if (decode_X_packet (&cs.own_buf[1], len - 1, &mem_addr,
  			       &mem_len, &mem_buf) < 0
  	      || write_inferior_memory (mem_addr, mem_buf, mem_len) != 0)
-	    write_enn (own_buf);
+	    write_enn (cs.own_buf);
  	  else
-	    write_ok (own_buf);
+	    write_ok (cs.own_buf);
  	}
        else
  	{
-	  decode_M_packet (&own_buf[1], &mem_addr, &mem_len, &mem_buf);
+	  decode_M_packet (&cs.own_buf[1], &mem_addr, &mem_len, &mem_buf);
  	  if (write_inferior_memory (mem_addr, mem_buf, mem_len) == 0)
-	    write_ok (own_buf);
+	    write_ok (cs.own_buf);
  	  else
-	    write_enn (own_buf);
+	    write_enn (cs.own_buf);
  	}
        free (mem_buf);
-      if (putpkt (own_buf) < 0)
+      if (putpkt (cs.own_buf) < 0)
  	return -1;
-      len = getpkt (own_buf);
+      len = getpkt (cs.own_buf);
        if (len < 0)
  	return -1;
      }

-  if (own_buf[0] == 'E')
+  if (cs.own_buf[0] == 'E')
      {
        warning ("An error occurred while relocating an instruction: %s\n",
-	       own_buf);
+	       cs.own_buf);
        return -1;
      }

-  if (!startswith (own_buf, "qRelocInsn:"))
+  if (!startswith (cs.own_buf, "qRelocInsn:"))
      {
        warning ("Malformed response to qRelocInsn, ignoring: %s\n",
-	       own_buf);
+	       cs.own_buf);
        return -1;
      }

-  unpack_varlen_hex (own_buf + strlen ("qRelocInsn:"), &written);
+  unpack_varlen_hex (cs.own_buf + strlen ("qRelocInsn:"), &written);

    *to += written;
    return 0;
diff --git a/gdb/gdbserver/remote-utils.h b/gdb/gdbserver/remote-utils.h
index c64807f406..a28c5ae035 100644
--- a/gdb/gdbserver/remote-utils.h
+++ b/gdb/gdbserver/remote-utils.h
@@ -19,10 +19,6 @@ 
  #ifndef REMOTE_UTILS_H
  #define REMOTE_UTILS_H

-extern int remote_debug;
-extern int noack_mode;
-extern int transport_is_reliable;
-
  int gdb_connected (void);

  #define STDIO_CONNECTION_NAME "stdio"
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 5027df5e10..fcdd7725f5 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -72,17 +72,6 @@  static gdb_environ our_environ;

  int startup_with_shell = 1;

-/* The thread set with an `Hc' packet.  `Hc' is deprecated in favor of
-   `vCont'.  Note the multi-process extensions made `vCont' a
-   requirement, so `Hc pPID.TID' is pretty much undefined.  So
-   CONT_THREAD can be null_ptid for no `Hc' thread, minus_one_ptid for
-   resuming all threads of the process (again, `Hc' isn't used for
-   multi-process), or a specific thread ptid_t.  */
-ptid_t cont_thread;
-
-/* The thread set with an `Hg' packet.  */
-ptid_t general_thread;
-
  int server_waiting;

  static int extended_protocol;
@@ -92,27 +81,10 @@  static int exit_requested;
  /* --once: Exit after the first connection has closed.  */
  int run_once;

-int multi_process;
-int report_fork_events;
-int report_vfork_events;
-int report_exec_events;
-int report_thread_events;
-
  /* Whether to report TARGET_WAITKING_NO_RESUMED events.  */
  static int report_no_resumed;

  int non_stop;
-int swbreak_feature;
-int hwbreak_feature;
-
-/* True if the "vContSupported" feature is active.  In that case, GDB
-   wants us to report whether single step is supported in the reply to
-   "vCont?" packet.  */
-static int vCont_supported;
-
-/* Whether we should attempt to disable the operating system's address
-   space randomization feature before starting an inferior.  */
-int disable_randomization = 1;

  static struct {
    /* Set the PROGRAM_PATH.  Here we adjust the path of the provided
@@ -146,10 +118,6 @@  private:
  static std::vector<char *> program_args;
  static std::string wrapper_argv;

-int pass_signals[GDB_SIGNAL_LAST];
-int program_signals[GDB_SIGNAL_LAST];
-int program_signals_p;
-
  /* The PID of the originally created or attached inferior.  Used to
     send signals to the process when GDB sends us an asynchronous interrupt
     (user hitting Control-C in the client), and to wait for the child 
to exit
@@ -165,11 +133,6 @@  int disable_packet_Tthread;
  int disable_packet_qC;
  int disable_packet_qfThreadInfo;

-/* Last status reported to GDB.  */
-struct target_waitstatus last_status;
-ptid_t last_ptid;
-
-char *own_buf;
  static unsigned char *mem_buf;

  /* A sub-class of 'struct notif_event' for stop, holding information
@@ -193,6 +156,18 @@  static struct btrace_config current_btrace_conf;

  DEFINE_QUEUE_P (notif_event_p);

+/* The client remote protocol state. */
+
+static client_state g_client_state;
+
+client_state &
+get_client_state ()
+{
+  client_state &cs = g_client_state;
+  return cs;
+}
+
+
  /* Put a stop reply to the stop reply queue.  */

  static void
@@ -316,6 +291,7 @@  get_environ ()
  static int
  attach_inferior (int pid)
  {
+  client_state &cs = get_client_state ();
    /* myattach should return -1 if attaching is unsupported,
       0 if it succeeded, and call error() otherwise.  */

@@ -332,23 +308,22 @@  attach_inferior (int pid)

    if (!non_stop)
      {
-      last_ptid = mywait (pid_to_ptid (pid), &last_status, 0, 0);
+      cs.last_ptid = mywait (pid_to_ptid (pid), &cs.last_status, 0, 0);

        /* GDB knows to ignore the first SIGSTOP after attaching to a 
running
  	 process using the "attach" command, but this is different; it's
  	 just using "target remote".  Pretend it's just starting up.  */
-      if (last_status.kind == TARGET_WAITKIND_STOPPED
-	  && last_status.value.sig == GDB_SIGNAL_STOP)
-	last_status.value.sig = GDB_SIGNAL_TRAP;
+      if (cs.last_status.kind == TARGET_WAITKIND_STOPPED
+	  && cs.last_status.value.sig == GDB_SIGNAL_STOP)
+	cs.last_status.value.sig = GDB_SIGNAL_TRAP;

        current_thread->last_resume_kind = resume_stop;
-      current_thread->last_status = last_status;
+      current_thread->last_status = cs.last_status;
      }

    return 0;
  }

-extern int remote_debug;

  /* Decode a qXfer read request.  Return 0 if everything looks OK,
     or -1 otherwise.  */
@@ -456,6 +431,7 @@  handle_btrace_disable (struct thread_info *thread)
  static int
  handle_btrace_general_set (char *own_buf)
  {
+  client_state &cs = get_client_state ();
    struct thread_info *thread;
    char *op;

@@ -464,14 +440,14 @@  handle_btrace_general_set (char *own_buf)

    op = own_buf + strlen ("Qbtrace:");

-  if (ptid_equal (general_thread, null_ptid)
-      || ptid_equal (general_thread, minus_one_ptid))
+  if (ptid_equal (cs.general_thread, null_ptid)
+      || ptid_equal (cs.general_thread, minus_one_ptid))
      {
        strcpy (own_buf, "E.Must select a single thread.");
        return -1;
      }

-  thread = find_thread_ptid (general_thread);
+  thread = find_thread_ptid (cs.general_thread);
    if (thread == NULL)
      {
        strcpy (own_buf, "E.No such thread.");
@@ -505,6 +481,7 @@  handle_btrace_general_set (char *own_buf)
  static int
  handle_btrace_conf_general_set (char *own_buf)
  {
+  client_state &cs = get_client_state ();
    struct thread_info *thread;
    char *op;

@@ -513,14 +490,14 @@  handle_btrace_conf_general_set (char *own_buf)

    op = own_buf + strlen ("Qbtrace-conf:");

-  if (ptid_equal (general_thread, null_ptid)
-      || ptid_equal (general_thread, minus_one_ptid))
+  if (ptid_equal (cs.general_thread, null_ptid)
+      || ptid_equal (cs.general_thread, minus_one_ptid))
      {
        strcpy (own_buf, "E.Must select a single thread.");
        return -1;
      }

-  thread = find_thread_ptid (general_thread);
+  thread = find_thread_ptid (cs.general_thread);
    if (thread == NULL)
      {
        strcpy (own_buf, "E.No such thread.");
@@ -572,6 +549,7 @@  handle_btrace_conf_general_set (char *own_buf)
  static void
  handle_general_set (char *own_buf)
  {
+  client_state &cs = get_client_state ();
    if (startswith (own_buf, "QPassSignals:"))
      {
        int numsigs = (int) GDB_SIGNAL_LAST, i;
@@ -583,7 +561,7 @@  handle_general_set (char *own_buf)
  	{
  	  if (i == cursig)
  	    {
-	      pass_signals[i] = 1;
+	      cs.pass_signals[i] = 1;
  	      if (*p == '\0')
  		/* Keep looping, to clear the remaining signals.  */
  		cursig = -1;
@@ -591,7 +569,7 @@  handle_general_set (char *own_buf)
  		p = decode_address_to_semicolon (&cursig, p);
  	    }
  	  else
-	    pass_signals[i] = 0;
+	    cs.pass_signals[i] = 0;
  	}
        strcpy (own_buf, "OK");
        return;
@@ -603,14 +581,14 @@  handle_general_set (char *own_buf)
        const char *p = own_buf + strlen ("QProgramSignals:");
        CORE_ADDR cursig;

-      program_signals_p = 1;
+      cs.program_signals_p = 1;

        p = decode_address_to_semicolon (&cursig, p);
        for (i = 0; i < numsigs; i++)
  	{
  	  if (i == cursig)
  	    {
-	      program_signals[i] = 1;
+	      cs.program_signals[i] = 1;
  	      if (*p == '\0')
  		/* Keep looping, to clear the remaining signals.  */
  		cursig = -1;
@@ -618,7 +596,7 @@  handle_general_set (char *own_buf)
  		p = decode_address_to_semicolon (&cursig, p);
  	    }
  	  else
-	    program_signals[i] = 0;
+	    cs.program_signals[i] = 0;
  	}
        strcpy (own_buf, "OK");
        return;
@@ -688,7 +666,7 @@  handle_general_set (char *own_buf)
        std::string final_var = hex2str (p);
        std::string var_name, var_value;

-      if (remote_debug)
+      if (cs.remote_debug)
  	{
  	  debug_printf (_("[QEnvironmentHexEncoded received '%s']\n"), p);
  	  debug_printf (_("[Environment variable to be set: '%s']\n"),
@@ -719,7 +697,7 @@  handle_general_set (char *own_buf)
        const char *p = own_buf + sizeof ("QEnvironmentUnset:") - 1;
        std::string varname = hex2str (p);

-      if (remote_debug)
+      if (cs.remote_debug)
  	{
  	  debug_printf (_("[QEnvironmentUnset received '%s']\n"), p);
  	  debug_printf (_("[Environment variable to be unset: '%s']\n"),
@@ -735,13 +713,13 @@  handle_general_set (char *own_buf)

    if (strcmp (own_buf, "QStartNoAckMode") == 0)
      {
-      if (remote_debug)
+      if (cs.remote_debug)
  	{
  	  debug_printf ("[noack mode enabled]\n");
  	  debug_flush ();
  	}

-      noack_mode = 1;
+      cs.noack_mode = 1;
        write_ok (own_buf);
        return;
      }
@@ -776,7 +754,7 @@  handle_general_set (char *own_buf)

        non_stop = req;

-      if (remote_debug)
+      if (cs.remote_debug)
  	debug_printf ("[%s mode enabled]\n", req_str);

        write_ok (own_buf);
@@ -789,11 +767,11 @@  handle_general_set (char *own_buf)
        ULONGEST setting;

        unpack_varlen_hex (packet, &setting);
-      disable_randomization = setting;
+      cs.disable_randomization = setting;

-      if (remote_debug)
+      if (cs.remote_debug)
  	{
-	  debug_printf (disable_randomization
+	  debug_printf (cs.disable_randomization
  			? "[address space randomization disabled]\n"
  			: "[address space randomization enabled]\n");
  	}
@@ -824,7 +802,7 @@  handle_general_set (char *own_buf)

        /* Update the flag.  */
        use_agent = req;
-      if (remote_debug)
+      if (cs.remote_debug)
  	debug_printf ("[%s agent]\n", req ? "Enable" : "Disable");
        write_ok (own_buf);
        return;
@@ -853,11 +831,11 @@  handle_general_set (char *own_buf)
  	  return;
  	}

-      report_thread_events = (req == TRIBOOL_TRUE);
+      cs.report_thread_events = (req == TRIBOOL_TRUE);

-      if (remote_debug)
+      if (cs.remote_debug)
  	{
-	  const char *req_str = report_thread_events ? "enabled" : "disabled";
+	  const char *req_str = cs.report_thread_events ? "enabled" : "disabled";

  	  debug_printf ("[thread events are now %s]\n", req_str);
  	}
@@ -883,7 +861,7 @@  handle_general_set (char *own_buf)
  	  return;
  	}

-      if (remote_debug)
+      if (cs.remote_debug)
  	debug_printf (_("[Inferior will %s started with shell]"),
  		      startup_with_shell ? "be" : "not be");

@@ -901,7 +879,7 @@  handle_general_set (char *own_buf)

  	  set_inferior_cwd (path.c_str ());

-	  if (remote_debug)
+	  if (cs.remote_debug)
  	    debug_printf (_("[Set the inferior's current directory to %s]\n"),
  			  path.c_str ());
  	}
@@ -911,7 +889,7 @@  handle_general_set (char *own_buf)
  	     previously set cwd for the inferior.  */
  	  set_inferior_cwd (NULL);

-	  if (remote_debug)
+	  if (cs.remote_debug)
  	    debug_printf (_("\
  [Unset the inferior's current directory; will use gdbserver's cwd]\n"));
  	}
@@ -998,14 +976,15 @@  monitor_show_help (void)
  static int
  gdb_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
  {
+  client_state &cs = get_client_state ();
    int res;

-  if (current_traceframe >= 0)
+  if (cs.current_traceframe >= 0)
      {
        ULONGEST nbytes;
        ULONGEST length = len;

-      if (traceframe_read_mem (current_traceframe,
+      if (traceframe_read_mem (cs.current_traceframe,
  			       memaddr, myaddr, len, &nbytes))
  	return -1;
        /* Data read from trace buffer, we're done.  */
@@ -1038,7 +1017,8 @@  gdb_read_memory (CORE_ADDR memaddr, unsigned char 
*myaddr, int len)
  static int
  gdb_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
  {
-  if (current_traceframe >= 0)
+  client_state &cs = get_client_state ();
+  if (cs.current_traceframe >= 0)
      return EIO;
    else
      {
@@ -1213,11 +1193,12 @@  handle_search_memory (char *own_buf, int packet_len)
  static void
  handle_detach (char *own_buf)
  {
+  client_state &cs = get_client_state ();
    require_running_or_return (own_buf);

    int pid;

-  if (multi_process)
+  if (cs.multi_process)
      {
        /* skip 'D;' */
        pid = strtol (&own_buf[2], NULL, 16);
@@ -1282,9 +1263,9 @@  handle_detach (char *own_buf)
  	  /* There is still at least one inferior remaining or
  	     we are in extended mode, so don't terminate gdbserver,
  	     and instead treat this like a normal program exit.  */
-	  last_status.kind = TARGET_WAITKIND_EXITED;
-	  last_status.value.integer = 0;
-	  last_ptid = pid_to_ptid (pid);
+	  cs.last_status.kind = TARGET_WAITKIND_EXITED;
+	  cs.last_status.value.integer = 0;
+	  cs.last_ptid = pid_to_ptid (pid);

  	  current_thread = NULL;
  	}
@@ -1370,6 +1351,7 @@  parse_debug_format_options (const char *arg, int 
is_monitor)
  static void
  handle_monitor_command (char *mon, char *own_buf)
  {
+  client_state &cs = get_client_state ();
    if (strcmp (mon, "set debug 1") == 0)
      {
        debug_threads = 1;
@@ -1392,12 +1374,12 @@  handle_monitor_command (char *mon, char *own_buf)
      }
    else if (strcmp (mon, "set remote-debug 1") == 0)
      {
-      remote_debug = 1;
+      cs.remote_debug = 1;
        monitor_output ("Protocol debug output enabled.\n");
      }
    else if (strcmp (mon, "set remote-debug 0") == 0)
      {
-      remote_debug = 0;
+      cs.remote_debug = 0;
        monitor_output ("Protocol debug output disabled.\n");
      }
    else if (startswith (mon, "set debug-format "))
@@ -1646,15 +1628,17 @@  handle_qxfer_statictrace (const char *annex,
  			  gdb_byte *readbuf, const gdb_byte *writebuf,
  			  ULONGEST offset, LONGEST len)
  {
+  client_state &cs = get_client_state ();
    ULONGEST nbytes;

    if (writebuf != NULL)
      return -2;

-  if (annex[0] != '\0' || current_thread == NULL || current_traceframe 
== -1)
+  if (annex[0] != '\0' || current_thread == NULL
+      || cs.current_traceframe == -1)
      return -1;

-  if (traceframe_read_sdata (current_traceframe, offset,
+  if (traceframe_read_sdata (cs.current_traceframe, offset,
  			     readbuf, len, &nbytes))
      return -1;
    return nbytes;
@@ -1770,13 +1754,14 @@  handle_qxfer_traceframe_info (const char *annex,
  			      gdb_byte *readbuf, const gdb_byte *writebuf,
  			      ULONGEST offset, LONGEST len)
  {
+  client_state &cs = get_client_state ();
    static char *result = 0;
    static unsigned int result_length = 0;

    if (writebuf != NULL)
      return -2;

-  if (!target_running () || annex[0] != '\0' || current_traceframe == -1)
+  if (!target_running () || annex[0] != '\0' || cs.current_traceframe 
== -1)
      return -1;

    if (offset == 0)
@@ -1790,7 +1775,7 @@  handle_qxfer_traceframe_info (const char *annex,

        buffer_init (&buffer);

-      traceframe_read_info (current_traceframe, &buffer);
+      traceframe_read_info (cs.current_traceframe, &buffer);

        result = buffer_finish (&buffer);
        result_length = strlen (result);
@@ -1835,6 +1820,7 @@  handle_qxfer_btrace (const char *annex,
  		     gdb_byte *readbuf, const gdb_byte *writebuf,
  		     ULONGEST offset, LONGEST len)
  {
+  client_state &cs = get_client_state ();
    static struct buffer cache;
    struct thread_info *thread;
    enum btrace_read_type type;
@@ -1843,23 +1829,23 @@  handle_qxfer_btrace (const char *annex,
    if (writebuf != NULL)
      return -2;

-  if (ptid_equal (general_thread, null_ptid)
-      || ptid_equal (general_thread, minus_one_ptid))
+  if (ptid_equal (cs.general_thread, null_ptid)
+      || ptid_equal (cs.general_thread, minus_one_ptid))
      {
-      strcpy (own_buf, "E.Must select a single thread.");
+      strcpy (cs.own_buf, "E.Must select a single thread.");
        return -3;
      }

-  thread = find_thread_ptid (general_thread);
+  thread = find_thread_ptid (cs.general_thread);
    if (thread == NULL)
      {
-      strcpy (own_buf, "E.No such thread.");
+      strcpy (cs.own_buf, "E.No such thread.");
        return -3;
      }

    if (thread->btrace == NULL)
      {
-      strcpy (own_buf, "E.Btrace not enabled.");
+      strcpy (cs.own_buf, "E.Btrace not enabled.");
        return -3;
      }

@@ -1871,7 +1857,7 @@  handle_qxfer_btrace (const char *annex,
      type = BTRACE_READ_DELTA;
    else
      {
-      strcpy (own_buf, "E.Bad annex.");
+      strcpy (cs.own_buf, "E.Bad annex.");
        return -3;
      }

@@ -1883,11 +1869,11 @@  handle_qxfer_btrace (const char *annex,
  	{
  	  result = target_read_btrace (thread->btrace, &cache, type);
  	  if (result != 0)
-	    memcpy (own_buf, cache.buffer, cache.used_size);
+	    memcpy (cs.own_buf, cache.buffer, cache.used_size);
  	}
        CATCH (exception, RETURN_MASK_ERROR)
  	{
-	  sprintf (own_buf, "E.%s", exception.message);
+	  sprintf (cs.own_buf, "E.%s", exception.message);
  	  result = -1;
  	}
        END_CATCH
@@ -1916,6 +1902,7 @@  handle_qxfer_btrace_conf (const char *annex,
  			  gdb_byte *readbuf, const gdb_byte *writebuf,
  			  ULONGEST offset, LONGEST len)
  {
+  client_state &cs = get_client_state ();
    static struct buffer cache;
    struct thread_info *thread;
    int result;
@@ -1926,23 +1913,23 @@  handle_qxfer_btrace_conf (const char *annex,
    if (annex[0] != '\0')
      return -1;

-  if (ptid_equal (general_thread, null_ptid)
-      || ptid_equal (general_thread, minus_one_ptid))
+  if (ptid_equal (cs.general_thread, null_ptid)
+      || ptid_equal (cs.general_thread, minus_one_ptid))
      {
-      strcpy (own_buf, "E.Must select a single thread.");
+      strcpy (cs.own_buf, "E.Must select a single thread.");
        return -3;
      }

-  thread = find_thread_ptid (general_thread);
+  thread = find_thread_ptid (cs.general_thread);
    if (thread == NULL)
      {
-      strcpy (own_buf, "E.No such thread.");
+      strcpy (cs.own_buf, "E.No such thread.");
        return -3;
      }

    if (thread->btrace == NULL)
      {
-      strcpy (own_buf, "E.Btrace not enabled.");
+      strcpy (cs.own_buf, "E.Btrace not enabled.");
        return -3;
      }

@@ -1954,11 +1941,11 @@  handle_qxfer_btrace_conf (const char *annex,
  	{
  	  result = target_read_btrace_conf (thread->btrace, &cache);
  	  if (result != 0)
-	    memcpy (own_buf, cache.buffer, cache.used_size);
+	    memcpy (cs.own_buf, cache.buffer, cache.used_size);
  	}
        CATCH (exception, RETURN_MASK_ERROR)
  	{
-	  sprintf (own_buf, "E.%s", exception.message);
+	  sprintf (cs.own_buf, "E.%s", exception.message);
  	  result = -1;
  	}
        END_CATCH
@@ -2158,6 +2145,7 @@  supported_btrace_packets (char *buf)
  static void
  handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
  {
+  client_state &cs = get_client_state ();
    static std::list<thread_info *>::const_iterator thread_iter;

    /* Reply the current thread id.  */
@@ -2166,8 +2154,8 @@  handle_query (char *own_buf, int packet_len, int 
*new_packet_len_p)
        ptid_t ptid;
        require_running_or_return (own_buf);

-      if (general_thread != null_ptid && general_thread != minus_one_ptid)
-	ptid = general_thread;
+      if (cs.general_thread != null_ptid && cs.general_thread != 
minus_one_ptid)
+	ptid = cs.general_thread;
        else
  	{
  	  thread_iter = all_threads.begin ();
@@ -2192,7 +2180,7 @@  handle_query (char *own_buf, int packet_len, int 
*new_packet_len_p)
        if (current_thread == NULL)
  	{
  	  current_thread
-	    = find_any_thread_of_pid (ptid_get_pid (general_thread));
+	    = find_any_thread_of_pid (ptid_get_pid (cs.general_thread));

  	  /* Just in case, if we didn't find a thread, then bail out
  	     instead of crashing.  */
@@ -2312,7 +2300,7 @@  handle_query (char *own_buf, int packet_len, int 
*new_packet_len_p)
  		  /* GDB supports and wants multi-process support if
  		     possible.  */
  		  if (target_supports_multi_process ())
-		    multi_process = 1;
+		    cs.multi_process = 1;
  		}
  	      else if (strcmp (p, "qRelocInsn+") == 0)
  		{
@@ -2325,35 +2313,35 @@  handle_query (char *own_buf, int packet_len, int 
*new_packet_len_p)
  		     by a software breakpoint and for us to handle PC
  		     adjustment if necessary on this target.  */
  		  if (target_supports_stopped_by_sw_breakpoint ())
-		    swbreak_feature = 1;
+		    cs.swbreak_feature = 1;
  		}
  	      else if (strcmp (p, "hwbreak+") == 0)
  		{
  		  /* GDB wants us to report whether a trap is caused
  		     by a hardware breakpoint.  */
  		  if (target_supports_stopped_by_hw_breakpoint ())
-		    hwbreak_feature = 1;
+		    cs.hwbreak_feature = 1;
  		}
  	      else if (strcmp (p, "fork-events+") == 0)
  		{
  		  /* GDB supports and wants fork events if possible.  */
  		  if (target_supports_fork_events ())
-		    report_fork_events = 1;
+		    cs.report_fork_events = 1;
  		}
  	      else if (strcmp (p, "vfork-events+") == 0)
  		{
  		  /* GDB supports and wants vfork events if possible.  */
  		  if (target_supports_vfork_events ())
-		    report_vfork_events = 1;
+		    cs.report_vfork_events = 1;
  		}
  	      else if (strcmp (p, "exec-events+") == 0)
  		{
  		  /* GDB supports and wants exec events if possible.  */
  		  if (target_supports_exec_events ())
-		    report_exec_events = 1;
+		    cs.report_exec_events = 1;
  		}
  	      else if (strcmp (p, "vContSupported+") == 0)
-		vCont_supported = 1;
+		cs.vCont_supported = 1;
  	      else if (strcmp (p, "QThreadEvents+") == 0)
  		;
  	      else if (strcmp (p, "no-resumed+") == 0)
@@ -2418,7 +2406,7 @@  handle_query (char *own_buf, int packet_len, int 
*new_packet_len_p)
  	 qXfer:feature:read at all, we will never be re-queried.  */
        strcat (own_buf, ";qXfer:features:read+");

-      if (transport_is_reliable)
+      if (cs.transport_is_reliable)
  	strcat (own_buf, ";QStartNoAckMode+");

        if (the_target->qxfer_osdata != NULL)
@@ -2729,13 +2717,14 @@  static int
  handle_pending_status (const struct thread_resume *resumption,
  		       struct thread_info *thread)
  {
+  client_state &cs = get_client_state ();
    if (thread->status_pending_p)
      {
        thread->status_pending_p = 0;

-      last_status = thread->last_status;
-      last_ptid = thread->id;
-      prepare_resume_reply (own_buf, last_ptid, &last_status);
+      cs.last_status = thread->last_status;
+      cs.last_ptid = thread->id;
+      prepare_resume_reply (cs.own_buf, cs.last_ptid, &cs.last_status);
        return 1;
      }
    return 0;
@@ -2855,6 +2844,7 @@  err:
  static void
  resume (struct thread_resume *actions, size_t num_actions)
  {
+  client_state &cs = get_client_state ();
    if (!non_stop)
      {
        /* Check if among the threads that GDB wants actioned, there's
@@ -2877,37 +2867,37 @@  resume (struct thread_resume *actions, size_t 
num_actions)
    (*the_target->resume) (actions, num_actions);

    if (non_stop)
-    write_ok (own_buf);
+    write_ok (cs.own_buf);
    else
      {
-      last_ptid = mywait (minus_one_ptid, &last_status, 0, 1);
+      cs.last_ptid = mywait (minus_one_ptid, &cs.last_status, 0, 1);

-      if (last_status.kind == TARGET_WAITKIND_NO_RESUMED
+      if (cs.last_status.kind == TARGET_WAITKIND_NO_RESUMED
  	  && !report_no_resumed)
  	{
  	  /* The client does not support this stop reply.  At least
  	     return error.  */
-	  sprintf (own_buf, "E.No unwaited-for children left.");
+	  sprintf (cs.own_buf, "E.No unwaited-for children left.");
  	  disable_async_io ();
  	  return;
  	}

-      if (last_status.kind != TARGET_WAITKIND_EXITED
-          && last_status.kind != TARGET_WAITKIND_SIGNALLED
-	  && last_status.kind != TARGET_WAITKIND_NO_RESUMED)
-	current_thread->last_status = last_status;
+      if (cs.last_status.kind != TARGET_WAITKIND_EXITED
+          && cs.last_status.kind != TARGET_WAITKIND_SIGNALLED
+	  && cs.last_status.kind != TARGET_WAITKIND_NO_RESUMED)
+	current_thread->last_status = cs.last_status;

        /* From the client's perspective, all-stop mode always stops all
  	 threads implicitly (and the target backend has already done
  	 so by now).  Tag all threads as "want-stopped", so we don't
  	 resume them implicitly without the client telling us to.  */
        gdb_wants_all_threads_stopped ();
-      prepare_resume_reply (own_buf, last_ptid, &last_status);
+      prepare_resume_reply (cs.own_buf, cs.last_ptid, &cs.last_status);
        disable_async_io ();

-      if (last_status.kind == TARGET_WAITKIND_EXITED
-          || last_status.kind == TARGET_WAITKIND_SIGNALLED)
-        target_mourn_inferior (last_ptid);
+      if (cs.last_status.kind == TARGET_WAITKIND_EXITED
+          || cs.last_status.kind == TARGET_WAITKIND_SIGNALLED)
+        target_mourn_inferior (cs.last_ptid);
      }
  }

@@ -2915,6 +2905,7 @@  resume (struct thread_resume *actions, size_t 
num_actions)
  static int
  handle_v_attach (char *own_buf)
  {
+  client_state &cs = get_client_state ();
    int pid;

    pid = strtol (own_buf + 8, NULL, 16);
@@ -2934,7 +2925,7 @@  handle_v_attach (char *own_buf)
  	  write_ok (own_buf);
  	}
        else
-	prepare_resume_reply (own_buf, last_ptid, &last_status);
+	prepare_resume_reply (own_buf, cs.last_ptid, &cs.last_status);

        return 1;
      }
@@ -2949,6 +2940,7 @@  handle_v_attach (char *own_buf)
  static int
  handle_v_run (char *own_buf)
  {
+  client_state &cs = get_client_state ();
    char *p, *next_p;
    std::vector<char *> new_argv;
    char *new_program_name = NULL;
@@ -3055,15 +3047,15 @@  handle_v_run (char *own_buf)

    create_inferior (program_path.get (), program_args);

-  if (last_status.kind == TARGET_WAITKIND_STOPPED)
+  if (cs.last_status.kind == TARGET_WAITKIND_STOPPED)
      {
-      prepare_resume_reply (own_buf, last_ptid, &last_status);
+      prepare_resume_reply (own_buf, cs.last_ptid, &cs.last_status);

        /* In non-stop, sending a resume reply doesn't set the general
  	 thread, but GDB assumes a vRun sets it (this is so GDB can
  	 query which is the main thread of the new inferior.  */
        if (non_stop)
-	general_thread = last_ptid;
+	cs.general_thread = cs.last_ptid;

        return 1;
      }
@@ -3078,18 +3070,19 @@  handle_v_run (char *own_buf)
  static int
  handle_v_kill (char *own_buf)
  {
+  client_state &cs = get_client_state ();
    int pid;
    char *p = &own_buf[6];
-  if (multi_process)
+  if (cs.multi_process)
      pid = strtol (p, NULL, 16);
    else
      pid = signal_pid;
    if (pid != 0 && kill_inferior (pid) == 0)
      {
-      last_status.kind = TARGET_WAITKIND_SIGNALLED;
-      last_status.value.sig = GDB_SIGNAL_KILL;
-      last_ptid = pid_to_ptid (pid);
-      discard_queued_stop_replies (last_ptid);
+      cs.last_status.kind = TARGET_WAITKIND_SIGNALLED;
+      cs.last_status.value.sig = GDB_SIGNAL_KILL;
+      cs.last_ptid = pid_to_ptid (pid);
+      discard_queued_stop_replies (cs.last_ptid);
        write_ok (own_buf);
        return 1;
      }
@@ -3104,6 +3097,7 @@  handle_v_kill (char *own_buf)
  void
  handle_v_requests (char *own_buf, int packet_len, int *new_packet_len)
  {
+  client_state &cs = get_client_state ();
    if (!disable_packet_vCont)
      {
        if (strcmp (own_buf, "vCtrlC") == 0)
@@ -3125,7 +3119,7 @@  handle_v_requests (char *own_buf, int packet_len, 
int *new_packet_len)

  	  if (target_supports_hardware_single_step ()
  	      || target_supports_software_single_step ()
-	      || !vCont_supported)
+	      || !cs.vCont_supported)
  	    {
  	      /* If target supports single step either by hardware or by
  		 software, add actions s and S to the list of supported
@@ -3151,7 +3145,7 @@  handle_v_requests (char *own_buf, int packet_len, 
int *new_packet_len)

    if (startswith (own_buf, "vAttach;"))
      {
-      if ((!extended_protocol || !multi_process) && target_running ())
+      if ((!extended_protocol || !cs.multi_process) && target_running ())
  	{
  	  fprintf (stderr, "Already debugging a process\n");
  	  write_enn (own_buf);
@@ -3163,7 +3157,7 @@  handle_v_requests (char *own_buf, int packet_len, 
int *new_packet_len)

    if (startswith (own_buf, "vRun;"))
      {
-      if ((!extended_protocol || !multi_process) && target_running ())
+      if ((!extended_protocol || !cs.multi_process) && target_running ())
  	{
  	  fprintf (stderr, "Already debugging a process\n");
  	  write_enn (own_buf);
@@ -3200,12 +3194,13 @@  handle_v_requests (char *own_buf, int 
packet_len, int *new_packet_len)
  static void
  myresume (char *own_buf, int step, int sig)
  {
+  client_state &cs = get_client_state ();
    struct thread_resume resume_info[2];
    int n = 0;
    int valid_cont_thread;

-  valid_cont_thread = (!ptid_equal (cont_thread, null_ptid)
-			 && !ptid_equal (cont_thread, minus_one_ptid));
+  valid_cont_thread = (!ptid_equal (cs.cont_thread, null_ptid)
+			 && !ptid_equal (cs.cont_thread, minus_one_ptid));

    if (step || sig || valid_cont_thread)
      {
@@ -3320,6 +3315,8 @@  set_pending_status_callback (thread_info *thread)
  static void
  handle_status (char *own_buf)
  {
+  client_state &cs = get_client_state ();
+
    /* GDB is connected, don't forward events to the target anymore.  */
    for_each_process ([] (process_info *process) {
      process->gdb_detached = 0;
@@ -3336,7 +3333,7 @@  handle_status (char *own_buf)
        /* The first is sent immediatly.  OK is sent if there is no
  	 stopped thread, which is the same handling of the vStopped
  	 packet (by design).  */
-      notif_write_event (&notif_stop, own_buf);
+      notif_write_event (&notif_stop, cs.own_buf);
      }
    else
      {
@@ -3356,10 +3353,10 @@  handle_status (char *own_buf)

        /* Prefer the last thread that reported an event to GDB (even if
  	 that was a GDB_SIGNAL_TRAP).  */
-      if (last_status.kind != TARGET_WAITKIND_IGNORE
-	  && last_status.kind != TARGET_WAITKIND_EXITED
-	  && last_status.kind != TARGET_WAITKIND_SIGNALLED)
-	thread = find_thread_ptid (last_ptid);
+      if (cs.last_status.kind != TARGET_WAITKIND_IGNORE
+	  && cs.last_status.kind != TARGET_WAITKIND_EXITED
+	  && cs.last_status.kind != TARGET_WAITKIND_SIGNALLED)
+	thread = find_thread_ptid (cs.last_ptid);

        /* If the last event thread is not found for some reason, look
  	 for some other thread that might have an event to report.  */
@@ -3384,7 +3381,7 @@  handle_status (char *own_buf)

  	  /* GDB assumes the current thread is the thread we're
  	     reporting the status for.  */
-	  general_thread = thread->id;
+	  cs.general_thread = thread->id;
  	  set_desired_thread ();

  	  gdb_assert (tp->last_status.kind != TARGET_WAITKIND_IGNORE);
@@ -3577,6 +3574,8 @@  captured_main (int argc, char *argv[])
  #endif

    current_directory = getcwd (NULL, 0);
+  client_state &cs = get_client_state ();
+
    if (current_directory == NULL)
      {
        error (_("Could not find current working directory: %s"),
@@ -3643,7 +3642,7 @@  captured_main (int argc, char *argv[])
  	    }
  	}
        else if (strcmp (*next_arg, "--remote-debug") == 0)
-	remote_debug = 1;
+	cs.remote_debug = 1;
        else if (strcmp (*next_arg, "--disable-packet") == 0)
  	{
  	  gdbserver_show_disableable (stdout);
@@ -3691,9 +3690,9 @@  captured_main (int argc, char *argv[])
  	  break;
  	}
        else if (strcmp (*next_arg, "--disable-randomization") == 0)
-	disable_randomization = 1;
+	cs.disable_randomization = 1;
        else if (strcmp (*next_arg, "--no-disable-randomization") == 0)
-	disable_randomization = 0;
+	cs.disable_randomization = 0;
        else if (strcmp (*next_arg, "--startup-with-shell") == 0)
  	startup_with_shell = true;
        else if (strcmp (*next_arg, "--no-startup-with-shell") == 0)
@@ -3780,7 +3779,6 @@  captured_main (int argc, char *argv[])
      initialize_tracepoint ();
    initialize_notif ();

-  own_buf = (char *) xmalloc (PBUFSIZ + 1);
    mem_buf = (unsigned char *) xmalloc (PBUFSIZ);

    if (selftest)
@@ -3819,9 +3817,9 @@  captured_main (int argc, char *argv[])
      }
    else
      {
-      last_status.kind = TARGET_WAITKIND_EXITED;
-      last_status.value.integer = 0;
-      last_ptid = minus_one_ptid;
+      cs.last_status.kind = TARGET_WAITKIND_EXITED;
+      cs.last_status.value.integer = 0;
+      cs.last_ptid = minus_one_ptid;
      }
    make_cleanup (detach_or_kill_for_exit_cleanup, NULL);

@@ -3830,8 +3828,8 @@  captured_main (int argc, char *argv[])
       shared library event" notice on gdb side.  */
    dlls_changed = 0;

-  if (last_status.kind == TARGET_WAITKIND_EXITED
-      || last_status.kind == TARGET_WAITKIND_SIGNALLED)
+  if (cs.last_status.kind == TARGET_WAITKIND_EXITED
+      || cs.last_status.kind == TARGET_WAITKIND_SIGNALLED)
      was_running = 0;
    else
      was_running = 1;
@@ -3841,18 +3839,17 @@  captured_main (int argc, char *argv[])

    while (1)
      {
-
-      noack_mode = 0;
-      multi_process = 0;
-      report_fork_events = 0;
-      report_vfork_events = 0;
-      report_exec_events = 0;
+      cs.noack_mode = 0;
+      cs.multi_process = 0;
+      cs.report_fork_events = 0;
+      cs.report_vfork_events = 0;
+      cs.report_exec_events = 0;
        /* Be sure we're out of tfind mode.  */
-      current_traceframe = -1;
-      cont_thread = null_ptid;
-      swbreak_feature = 0;
-      hwbreak_feature = 0;
-      vCont_supported = 0;
+      cs.current_traceframe = -1;
+      cs.cont_thread = null_ptid;
+      cs.swbreak_feature = 0;
+      cs.hwbreak_feature = 0;
+      cs.vCont_supported = 0;

        remote_open (port);

@@ -3928,8 +3925,8 @@  captured_main (int argc, char *argv[])

  	  if (response_needed)
  	    {
-	      write_enn (own_buf);
-	      putpkt (own_buf);
+	      write_enn (cs.own_buf);
+	      putpkt (cs.own_buf);
  	    }

  	  if (run_once)
@@ -4024,6 +4021,7 @@  process_point_options (struct gdb_breakpoint *bp, 
const char **packet)
  static int
  process_serial_event (void)
  {
+  client_state &cs = get_client_state ();
    int signal;
    unsigned int len;
    int res;
@@ -4035,7 +4033,7 @@  process_serial_event (void)
    disable_async_io ();

    response_needed = 0;
-  packet_len = getpkt (own_buf);
+  packet_len = getpkt (cs.own_buf);
    if (packet_len <= 0)
      {
        remote_close ();
@@ -4044,31 +4042,31 @@  process_serial_event (void)
      }
    response_needed = 1;

-  char ch = own_buf[0];
+  char ch = cs.own_buf[0];
    switch (ch)
      {
      case 'q':
-      handle_query (own_buf, packet_len, &new_packet_len);
+      handle_query (cs.own_buf, packet_len, &new_packet_len);
        break;
      case 'Q':
-      handle_general_set (own_buf);
+      handle_general_set (cs.own_buf);
        break;
      case 'D':
-      handle_detach (own_buf);
+      handle_detach (cs.own_buf);
        break;
      case '!':
        extended_protocol = 1;
-      write_ok (own_buf);
+      write_ok (cs.own_buf);
        break;
      case '?':
-      handle_status (own_buf);
+      handle_status (cs.own_buf);
        break;
      case 'H':
-      if (own_buf[1] == 'c' || own_buf[1] == 'g' || own_buf[1] == 's')
+      if (cs.own_buf[1] == 'c' || cs.own_buf[1] == 'g' || cs.own_buf[1] 
== 's')
  	{
-	  require_running_or_break (own_buf);
+	  require_running_or_break (cs.own_buf);

-	  ptid_t thread_id = read_ptid (&own_buf[2], NULL);
+	  ptid_t thread_id = read_ptid (&cs.own_buf[2], NULL);

  	  if (thread_id == null_ptid || thread_id == minus_one_ptid)
  	    thread_id = null_ptid;
@@ -4079,7 +4077,7 @@  process_serial_event (void)

  	      if (thread == NULL)
  		{
-		  write_enn (own_buf);
+		  write_enn (cs.own_buf);
  		  break;
  		}

@@ -4090,52 +4088,52 @@  process_serial_event (void)
  	      /* The ptid represents a lwp/tid.  */
  	      if (find_thread_ptid (thread_id) == NULL)
  		{
-		  write_enn (own_buf);
+		  write_enn (cs.own_buf);
  		  break;
  		}
  	    }

-	  if (own_buf[1] == 'g')
+	  if (cs.own_buf[1] == 'g')
  	    {
  	      if (ptid_equal (thread_id, null_ptid))
  		{
  		  /* GDB is telling us to choose any thread.  Check if
  		     the currently selected thread is still valid. If
  		     it is not, select the first available.  */
-		  thread_info *thread = find_thread_ptid (general_thread);
+		  thread_info *thread = find_thread_ptid (cs.general_thread);
  		  if (thread == NULL)
  		    thread = get_first_thread ();
  		  thread_id = thread->id;
  		}

-	      general_thread = thread_id;
+	      cs.general_thread = thread_id;
  	      set_desired_thread ();
  	      gdb_assert (current_thread != NULL);
  	    }
-	  else if (own_buf[1] == 'c')
-	    cont_thread = thread_id;
+	  else if (cs.own_buf[1] == 'c')
+	    cs.cont_thread = thread_id;

-	  write_ok (own_buf);
+	  write_ok (cs.own_buf);
  	}
        else
  	{
  	  /* Silently ignore it so that gdb can extend the protocol
  	     without compatibility headaches.  */
-	  own_buf[0] = '\0';
+	  cs.own_buf[0] = '\0';
  	}
        break;
      case 'g':
-      require_running_or_break (own_buf);
-      if (current_traceframe >= 0)
+      require_running_or_break (cs.own_buf);
+      if (cs.current_traceframe >= 0)
  	{
  	  struct regcache *regcache
  	    = new_register_cache (current_target_desc ());

-	  if (fetch_traceframe_registers (current_traceframe,
+	  if (fetch_traceframe_registers (cs.current_traceframe,
  					  regcache, -1) == 0)
-	    registers_to_string (regcache, own_buf);
+	    registers_to_string (regcache, cs.own_buf);
  	  else
-	    write_enn (own_buf);
+	    write_enn (cs.own_buf);
  	  free_register_cache (regcache);
  	}
        else
@@ -4143,85 +4141,85 @@  process_serial_event (void)
  	  struct regcache *regcache;

  	  if (!set_desired_thread ())
-	    write_enn (own_buf);
+	    write_enn (cs.own_buf);
  	  else
  	    {
  	      regcache = get_thread_regcache (current_thread, 1);
-	      registers_to_string (regcache, own_buf);
+	      registers_to_string (regcache, cs.own_buf);
  	    }
  	}
        break;
      case 'G':
-      require_running_or_break (own_buf);
-      if (current_traceframe >= 0)
-	write_enn (own_buf);
+      require_running_or_break (cs.own_buf);
+      if (cs.current_traceframe >= 0)
+	write_enn (cs.own_buf);
        else
  	{
  	  struct regcache *regcache;

  	  if (!set_desired_thread ())
-	    write_enn (own_buf);
+	    write_enn (cs.own_buf);
  	  else
  	    {
  	      regcache = get_thread_regcache (current_thread, 1);
-	      registers_from_string (regcache, &own_buf[1]);
-	      write_ok (own_buf);
+	      registers_from_string (regcache, &cs.own_buf[1]);
+	      write_ok (cs.own_buf);
  	    }
  	}
        break;
      case 'm':
-      require_running_or_break (own_buf);
-      decode_m_packet (&own_buf[1], &mem_addr, &len);
+      require_running_or_break (cs.own_buf);
+      decode_m_packet (&cs.own_buf[1], &mem_addr, &len);
        res = gdb_read_memory (mem_addr, mem_buf, len);
        if (res < 0)
-	write_enn (own_buf);
+	write_enn (cs.own_buf);
        else
-	bin2hex (mem_buf, own_buf, res);
+	bin2hex (mem_buf, cs.own_buf, res);
        break;
      case 'M':
-      require_running_or_break (own_buf);
-      decode_M_packet (&own_buf[1], &mem_addr, &len, &mem_buf);
+      require_running_or_break (cs.own_buf);
+      decode_M_packet (&cs.own_buf[1], &mem_addr, &len, &mem_buf);
        if (gdb_write_memory (mem_addr, mem_buf, len) == 0)
-	write_ok (own_buf);
+	write_ok (cs.own_buf);
        else
-	write_enn (own_buf);
+	write_enn (cs.own_buf);
        break;
      case 'X':
-      require_running_or_break (own_buf);
-      if (decode_X_packet (&own_buf[1], packet_len - 1,
+      require_running_or_break (cs.own_buf);
+      if (decode_X_packet (&cs.own_buf[1], packet_len - 1,
  			   &mem_addr, &len, &mem_buf) < 0
  	  || gdb_write_memory (mem_addr, mem_buf, len) != 0)
-	write_enn (own_buf);
+	write_enn (cs.own_buf);
        else
-	write_ok (own_buf);
+	write_ok (cs.own_buf);
        break;
      case 'C':
-      require_running_or_break (own_buf);
-      hex2bin (own_buf + 1, &sig, 1);
+      require_running_or_break (cs.own_buf);
+      hex2bin (cs.own_buf + 1, &sig, 1);
        if (gdb_signal_to_host_p ((enum gdb_signal) sig))
  	signal = gdb_signal_to_host ((enum gdb_signal) sig);
        else
  	signal = 0;
-      myresume (own_buf, 0, signal);
+      myresume (cs.own_buf, 0, signal);
        break;
      case 'S':
-      require_running_or_break (own_buf);
-      hex2bin (own_buf + 1, &sig, 1);
+      require_running_or_break (cs.own_buf);
+      hex2bin (cs.own_buf + 1, &sig, 1);
        if (gdb_signal_to_host_p ((enum gdb_signal) sig))
  	signal = gdb_signal_to_host ((enum gdb_signal) sig);
        else
  	signal = 0;
-      myresume (own_buf, 1, signal);
+      myresume (cs.own_buf, 1, signal);
        break;
      case 'c':
-      require_running_or_break (own_buf);
+      require_running_or_break (cs.own_buf);
        signal = 0;
-      myresume (own_buf, 0, signal);
+      myresume (cs.own_buf, 0, signal);
        break;
      case 's':
-      require_running_or_break (own_buf);
+      require_running_or_break (cs.own_buf);
        signal = 0;
-      myresume (own_buf, 1, signal);
+      myresume (cs.own_buf, 1, signal);
        break;
      case 'Z':  /* insert_ ... */
        /* Fallthrough.  */
@@ -4230,10 +4228,10 @@  process_serial_event (void)
  	char *dataptr;
  	ULONGEST addr;
  	int kind;
-	char type = own_buf[1];
+	char type = cs.own_buf[1];
  	int res;
  	const int insert = ch == 'Z';
-	const char *p = &own_buf[3];
+	const char *p = &cs.own_buf[3];

  	p = unpack_varlen_hex (p, &addr);
  	kind = strtol (p + 1, &dataptr, 16);
@@ -4261,12 +4259,12 @@  process_serial_event (void)
  	  res = delete_gdb_breakpoint (type, addr, kind);

  	if (res == 0)
-	  write_ok (own_buf);
+	  write_ok (cs.own_buf);
  	else if (res == 1)
  	  /* Unsupported.  */
-	  own_buf[0] = '\0';
+	  cs.own_buf[0] = '\0';
  	else
-	  write_enn (own_buf);
+	  write_enn (cs.own_buf);
  	break;
        }
      case 'k':
@@ -4284,8 +4282,8 @@  process_serial_event (void)
  	 running.  The traditional protocol will exit instead.  */
        if (extended_protocol)
  	{
-	  last_status.kind = TARGET_WAITKIND_EXITED;
-	  last_status.value.sig = GDB_SIGNAL_KILL;
+	  cs.last_status.kind = TARGET_WAITKIND_EXITED;
+	  cs.last_status.value.sig = GDB_SIGNAL_KILL;
  	  return 0;
  	}
        else
@@ -4293,19 +4291,19 @@  process_serial_event (void)

      case 'T':
        {
-	require_running_or_break (own_buf);
+	require_running_or_break (cs.own_buf);

-	ptid_t thread_id = read_ptid (&own_buf[1], NULL);
+	ptid_t thread_id = read_ptid (&cs.own_buf[1], NULL);
  	if (find_thread_ptid (thread_id) == NULL)
  	  {
-	    write_enn (own_buf);
+	    write_enn (cs.own_buf);
  	    break;
  	  }

  	if (mythread_alive (thread_id))
-	  write_ok (own_buf);
+	  write_ok (cs.own_buf);
  	else
-	  write_enn (own_buf);
+	  write_enn (cs.own_buf);
        }
        break;
      case 'R':
@@ -4325,22 +4323,22 @@  process_serial_event (void)
  	    {
  	      create_inferior (program_path.get (), program_args);

-	      if (last_status.kind == TARGET_WAITKIND_STOPPED)
+	      if (cs.last_status.kind == TARGET_WAITKIND_STOPPED)
  		{
  		  /* Stopped at the first instruction of the target
  		     process.  */
-		  general_thread = last_ptid;
+		  cs.general_thread = cs.last_ptid;
  		}
  	      else
  		{
  		  /* Something went wrong.  */
-		  general_thread = null_ptid;
+		  cs.general_thread = null_ptid;
  		}
  	    }
  	  else
  	    {
-	      last_status.kind = TARGET_WAITKIND_EXITED;
-	      last_status.value.sig = GDB_SIGNAL_KILL;
+	      cs.last_status.kind = TARGET_WAITKIND_EXITED;
+	      cs.last_status.value.sig = GDB_SIGNAL_KILL;
  	    }
  	  return 0;
  	}
@@ -4349,26 +4347,26 @@  process_serial_event (void)
  	  /* It is a request we don't understand.  Respond with an
  	     empty packet so that gdb knows that we don't support this
  	     request.  */
-	  own_buf[0] = '\0';
+	  cs.own_buf[0] = '\0';
  	  break;
  	}
      case 'v':
        /* Extended (long) request.  */
-      handle_v_requests (own_buf, packet_len, &new_packet_len);
+      handle_v_requests (cs.own_buf, packet_len, &new_packet_len);
        break;

      default:
        /* It is a request we don't understand.  Respond with an empty
  	 packet so that gdb knows that we don't support this
  	 request.  */
-      own_buf[0] = '\0';
+      cs.own_buf[0] = '\0';
        break;
      }

    if (new_packet_len != -1)
-    putpkt_binary (own_buf, new_packet_len);
+    putpkt_binary (cs.own_buf, new_packet_len);
    else
-    putpkt (own_buf);
+    putpkt (cs.own_buf);

    response_needed = 0;

@@ -4415,30 +4413,31 @@  push_stop_notification (ptid_t ptid, struct 
target_waitstatus *status)
  int
  handle_target_event (int err, gdb_client_data client_data)
  {
+  client_state &cs = get_client_state ();
    if (debug_threads)
      debug_printf ("handling possible target event\n");

-  last_ptid = mywait (minus_one_ptid, &last_status,
+  cs.last_ptid = mywait (minus_one_ptid, &cs.last_status,
  		      TARGET_WNOHANG, 1);

-  if (last_status.kind == TARGET_WAITKIND_NO_RESUMED)
+  if (cs.last_status.kind == TARGET_WAITKIND_NO_RESUMED)
      {
        if (gdb_connected () && report_no_resumed)
-	push_stop_notification (null_ptid, &last_status);
+	push_stop_notification (null_ptid, &cs.last_status);
      }
-  else if (last_status.kind != TARGET_WAITKIND_IGNORE)
+  else if (cs.last_status.kind != TARGET_WAITKIND_IGNORE)
      {
-      int pid = ptid_get_pid (last_ptid);
+      int pid = ptid_get_pid (cs.last_ptid);
        struct process_info *process = find_process_pid (pid);
        int forward_event = !gdb_connected () || process->gdb_detached;

-      if (last_status.kind == TARGET_WAITKIND_EXITED
-	  || last_status.kind == TARGET_WAITKIND_SIGNALLED)
+      if (cs.last_status.kind == TARGET_WAITKIND_EXITED
+	  || cs.last_status.kind == TARGET_WAITKIND_SIGNALLED)
  	{
  	  mark_breakpoints_out (process);
-	  target_mourn_inferior (last_ptid);
+	  target_mourn_inferior (cs.last_ptid);
  	}
-      else if (last_status.kind == TARGET_WAITKIND_THREAD_EXITED)
+      else if (cs.last_status.kind == TARGET_WAITKIND_THREAD_EXITED)
  	;
        else
  	{
@@ -4446,7 +4445,7 @@  handle_target_event (int err, gdb_client_data 
client_data)
  	     "want-stopped" state to what the client wants, until it
  	     gets a new resume action.  */
  	  current_thread->last_resume_kind = resume_stop;
-	  current_thread->last_status = last_status;
+	  current_thread->last_status = cs.last_status;
  	}

        if (forward_event)
@@ -4457,9 +4456,9 @@  handle_target_event (int err, gdb_client_data 
client_data)
  	      exit (0);
  	    }

-	  if (last_status.kind == TARGET_WAITKIND_EXITED
-	      || last_status.kind == TARGET_WAITKIND_SIGNALLED
-	      || last_status.kind == TARGET_WAITKIND_THREAD_EXITED)
+	  if (cs.last_status.kind == TARGET_WAITKIND_EXITED
+	      || cs.last_status.kind == TARGET_WAITKIND_SIGNALLED
+	      || cs.last_status.kind == TARGET_WAITKIND_THREAD_EXITED)
  	    ;
  	  else
  	    {
@@ -4471,18 +4470,18 @@  handle_target_event (int err, gdb_client_data 
client_data)
  	      if (debug_threads)
  		debug_printf ("GDB not connected; forwarding event %d for"
  			      " [%s]\n",
-			      (int) last_status.kind,
-			      target_pid_to_str (last_ptid));
+			      (int) cs.last_status.kind,
+			      target_pid_to_str (cs.last_ptid));

-	      if (last_status.kind == TARGET_WAITKIND_STOPPED)
-		signal = last_status.value.sig;
+	      if (cs.last_status.kind == TARGET_WAITKIND_STOPPED)
+		signal = cs.last_status.value.sig;
  	      else
  		signal = GDB_SIGNAL_0;
-	      target_continue (last_ptid, signal);
+	      target_continue (cs.last_ptid, signal);
  	    }
  	}
        else
-	push_stop_notification (last_ptid, &last_status);
+	push_stop_notification (cs.last_ptid, &cs.last_status);
      }

    /* Be sure to not change the selected thread behind GDB's back.
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index 5970431d8e..fea007c6b6 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -60,8 +60,6 @@  int vsnprintf(char *str, size_t size, const char 
*format, va_list ap);
  #include "gdb_signals.h"
  #include "target.h"
  #include "mem-break.h"
-#include "gdbthread.h"
-#include "inferiors.h"
  #include "environ.h"

  /* Target-specific functions */
@@ -70,42 +68,16 @@  void initialize_low ();

  /* Public variables in server.c */

-extern ptid_t cont_thread;
-extern ptid_t general_thread;
-
  extern int server_waiting;
-extern int pass_signals[];
-extern int program_signals[];
-extern int program_signals_p;

  extern int disable_packet_vCont;
  extern int disable_packet_Tthread;
  extern int disable_packet_qC;
  extern int disable_packet_qfThreadInfo;

-extern char *own_buf;
-
  extern int run_once;
-extern int multi_process;
-extern int report_fork_events;
-extern int report_vfork_events;
-extern int report_exec_events;
-extern int report_thread_events;
  extern int non_stop;

-/* True if the "swbreak+" feature is active.  In that case, GDB wants
-   us to report whether a trap is explained by a software breakpoint
-   and for the server to handle PC adjustment if necessary on this
-   target.  Only enabled if the target supports it.  */
-extern int swbreak_feature;
-
-/* True if the "hwbreak+" feature is active.  In that case, GDB wants
-   us to report whether a trap is explained by a hardware breakpoint.
-   Only enabled if the target supports it.  */
-extern int hwbreak_feature;
-
-extern int disable_randomization;
-
  #if USE_WIN32API
  #include <winsock2.h>
  typedef SOCKET gdb_fildes_t;
@@ -158,8 +130,80 @@  extern void post_fork_inferior (int pid, const char 
*program);
  /* Get the gdb_environ being used in the current session.  */
  extern gdb_environ *get_environ ();

-extern target_waitstatus last_status;
-extern ptid_t last_ptid;
  extern unsigned long signal_pid;

+
+/* Description of the client remote protocol state for the currently
+   connected client.  */
+
+struct client_state
+{
+  client_state ():
+    own_buf ((char *) xmalloc (PBUFSIZ + 1))
+  {}
+
+  /* The thread set with an `Hc' packet.  `Hc' is deprecated in favor of
+     `vCont'.  Note the multi-process extensions made `vCont' a
+     requirement, so `Hc pPID.TID' is pretty much undefined.  So
+     CONT_THREAD can be null_ptid for no `Hc' thread, minus_one_ptid for
+     resuming all threads of the process (again, `Hc' isn't used for
+     multi-process), or a specific thread ptid_t.  */
+  ptid_t cont_thread;
+
+  /* The thread set with an `Hg' packet.  */
+  ptid_t general_thread;
+
+  int multi_process = 0;
+  int report_fork_events = 0;
+  int report_vfork_events = 0;
+  int report_exec_events = 0;
+  int report_thread_events = 0;
+
+  /* True if the "swbreak+" feature is active.  In that case, GDB wants
+     us to report whether a trap is explained by a software breakpoint
+     and for the server to handle PC adjustment if necessary on this
+     target.  Only enabled if the target supports it.  */
+  int swbreak_feature = 0;
+  /* True if the "hwbreak+" feature is active.  In that case, GDB wants
+     us to report whether a trap is explained by a hardware breakpoint.
+     Only enabled if the target supports it.  */
+  int hwbreak_feature = 0;
+
+  /* True if the "vContSupported" feature is active.  In that case, GDB
+     wants us to report whether single step is supported in the reply to
+     "vCont?" packet.  */
+  int vCont_supported = 0;
+
+  /* Whether we should attempt to disable the operating system's address
+     space randomization feature before starting an inferior.  */
+  int disable_randomization = 0;
+
+  int pass_signals[GDB_SIGNAL_LAST];
+  int program_signals[GDB_SIGNAL_LAST];
+  int program_signals_p = 0;
+
+  /* Last status reported to GDB.  */
+  struct target_waitstatus last_status;
+  ptid_t last_ptid;
+
+  char *own_buf;
+
+  int remote_debug = 0;
+  /* If true, then GDB has requested noack mode.  */
+  int noack_mode = 0;
+  /* If true, then we tell GDB to use noack mode by default.  */
+  int transport_is_reliable = 0;
+
+  /* The traceframe to be used as the source of data to send back to
+     GDB.  A value of -1 means to get data from the live program.  */
+
+  int current_traceframe = -1;
+
+};
+
+client_state &get_client_state ();
+
+#include "gdbthread.h"
+#include "inferiors.h"
+
  #endif /* SERVER_H */
diff --git a/gdb/gdbserver/target.c b/gdb/gdbserver/target.c
index fe40b94db7..c2763294af 100644
--- a/gdb/gdbserver/target.c
+++ b/gdb/gdbserver/target.c
@@ -26,7 +26,8 @@  struct target_ops *the_target;
  int
  set_desired_thread ()
  {
-  thread_info *found = find_thread_ptid (general_thread);
+  client_state &cs = get_client_state ();
+  thread_info *found = find_thread_ptid (cs.general_thread);

    current_thread = found;
    return (current_thread != NULL);
@@ -42,6 +43,8 @@  static ptid_t prev_general_thread;
  int
  prepare_to_access_memory (void)
  {
+  client_state &cs = get_client_state ();
+
    /* The first thread found.  */
    struct thread_info *first = NULL;
    /* The first stopped thread found.  */
@@ -51,7 +54,7 @@  prepare_to_access_memory (void)

    /* Save the general thread value, since prepare_to_access_memory 
could change
       it.  */
-  prev_general_thread = general_thread;
+  prev_general_thread = cs.general_thread;

    if (the_target->prepare_to_access_memory != NULL)
      {
@@ -98,7 +101,7 @@  prepare_to_access_memory (void)
      }

    current_thread = thread;
-  general_thread = ptid_of (thread);
+  cs.general_thread = ptid_of (thread);

    return 0;
  }
@@ -108,12 +111,14 @@  prepare_to_access_memory (void)
  void
  done_accessing_memory (void)
  {
+  client_state &cs = get_client_state ();
+
    if (the_target->done_accessing_memory != NULL)
      the_target->done_accessing_memory ();

    /* Restore the previous selected thread.  */
-  general_thread = prev_general_thread;
-  switch_to_thread (general_thread);
+  cs.general_thread = prev_general_thread;
+  switch_to_thread (cs.general_thread);
  }

  int
diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c
index 4172756192..c203080dff 100644
--- a/gdb/gdbserver/tracepoint.c
+++ b/gdb/gdbserver/tracepoint.c
@@ -973,11 +973,6 @@  struct traceframe
     fields (and no data) marks the end of trace data.  */
  #define TRACEFRAME_EOB_MARKER_SIZE offsetof (struct traceframe, data)

-/* The traceframe to be used as the source of data to send back to
-   GDB.  A value of -1 means to get data from the live program.  */
-
-int current_traceframe = -1;
-
  /* This flag is true if the trace buffer is circular, meaning that
     when it fills, the oldest trace frames are discarded in order to
     make room.  */
@@ -2279,10 +2274,11 @@  static struct traceframe *
  find_next_traceframe_in_range (CORE_ADDR lo, CORE_ADDR hi, int inside_p,
  			       int *tfnump)
  {
+  client_state &cs = get_client_state ();
    struct traceframe *tframe;
    CORE_ADDR tfaddr;

-  *tfnump = current_traceframe + 1;
+  *tfnump = cs.current_traceframe + 1;
    tframe = find_traceframe (*tfnump);
    /* The search is not supposed to wrap around.  */
    if (!tframe)
@@ -2312,9 +2308,10 @@  find_next_traceframe_in_range (CORE_ADDR lo, 
CORE_ADDR hi, int inside_p,
  static struct traceframe *
  find_next_traceframe_by_tracepoint (int num, int *tfnump)
  {
+  client_state &cs = get_client_state ();
    struct traceframe *tframe;

-  *tfnump = current_traceframe + 1;
+  *tfnump = cs.current_traceframe + 1;
    tframe = find_traceframe (*tfnump);
    /* The search is not supposed to wrap around.  */