[RFC,v2] Consolidate gdbserver global variables

Message ID 7d9764b6-d95a-96b4-b064-27ce539327cf@redhat.com
State New, archived
Headers

Commit Message

Stan Cox May 3, 2018, 3:06 p.m. UTC
  > Why do we need server_state, if the value is the same for
> all clients?

That was an effort to treat all global data similarly but I see your
point about adding complexity, so this was removed.

> The first patch would only move the globals to structures, and start
> with a single global instance of such structures.

This patch does that.  Any global data that reflects a client view of 
the state of things, those items that would be unique if there was more 
than one client, are moved to the structure client_state.  No change to 
other global data items.

> There is _always_ a client_state, right?  I.e., get_client_state()
> never returns NULL?  If so, sounds like get_client_state()
> could return a reference instead of a pointer?

Yes, good suggestion, changed throughout.

> Can we use in-class initialization?

Ah yes indeed.

> ... all this indirection for each iteration.

Removing server_state removed all of this and simplified things 
considerably.

>> int run_once
> Is this one really per client?

Kept run_once and non_stop as globals in server.c.

> On your next update, please make sure to wrap the text in the
> proposed commit log to 74-columns, so that it's easier to read
> in "git show", "git log", etc.
> 
> Please address the comments above, squash the patches together,
> rebased on current master, and repost a new self-contained
> version (including updated proposed git commit log) with
> "PATCH v2" in the subject line.  That should make it easier
> to iterate on, and see if someone else has further
> comments, too.

Tested on linux with native-gdbserver.  (Two other targets required a 
simple change.)

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, server_waiting, 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, 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    |   1 +
  gdb/gdbserver/gdbthread.h     |   3 +
  gdb/gdbserver/hostio.c        |   2 -
  gdb/gdbserver/linux-arm-low.c |   1 +
  gdb/gdbserver/linux-low.c     |  32 +++++----
  gdb/gdbserver/notif.c         |   6 +-
  gdb/gdbserver/remote-utils.c  | 143 
++++++++++++++++++++-------------------
  gdb/gdbserver/remote-utils.h  |   4 --
  gdb/gdbserver/server.c        | 344 
++++++++++++++++++++++++++++++++++++++++++++++++----------------------------------------------
  gdb/gdbserver/server.h        |  86 ++++++++++++++++--------
  gdb/gdbserver/spu-low.c       |   5 +-
  gdb/gdbserver/target.c        |   6 +-
  gdb/gdbserver/tracepoint.c    |  25 +++----
  gdb/gdbserver/win32-low.c     |   3 +-
  14 files changed, 358 insertions(+), 303 deletions(-)
  

Comments

Pedro Alves May 4, 2018, 2:13 p.m. UTC | #1
Hi Stan,

On 05/03/2018 04:06 PM, Stan Cox wrote:

> Removing server_state removed all of this and simplified things considerably.

Great.

This makes it easier to see where we're going.

Some comments more.  I still have some design reservations.
It seems to me that simply making some of the globals be
per client along won't work correctly.  Particularly, the
cases where the globals are used in the backends.

More details below.

> 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, server_waiting, 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, 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.

Remove ()s around files list after "Update all callers".

There's spurious whitespace before and after "Use" in the
last entry.

> 
> --- 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)
>  {
> +  struct client_state & cs = get_client_state ();

Just like with * for pointers, no space after &.

While at it, no need for spelling out "struct" in C++, so,
please write:

     client_state &cs = get_client_state ();

throughout.

>    if (debug_threads)
>      {
>        debug_printf ("args: %s\n", args);
> diff --git a/gdb/gdbserver/gdbthread.h b/gdb/gdbserver/gdbthread.h
> index 0edf870c56..9a8c72e780 100644
> --- a/gdb/gdbserver/gdbthread.h
> +++ b/gdb/gdbserver/gdbthread.h
> @@ -224,4 +224,7 @@ lwpid_of (const thread_info *thread)
>    return thread->id.lwp ();
>  }
> 
> +/* Create a cleanup to restore current_thread.  */
> +struct cleanup *make_cleanup_restore_current_thread (void);

Please mention this in the ChangeLog.

> +
>  #endif /* GDB_THREAD_H */
> 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;
> -

This wasn't mentioned in the ChangeLog.

>  struct fd_list
>  {
>    int fd;
> diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c
> index 6c2dcead03..3004018e5b 100644
> --- a/gdb/gdbserver/linux-arm-low.c
> +++ b/gdb/gdbserver/linux-arm-low.c
> @@ -160,6 +160,7 @@ static struct arm_get_next_pcs_ops get_next_pcs_ops = {
>    arm_linux_get_next_pcs_fixup,
>  };
> 
> +
>  static int
>  arm_cannot_store_register (int regno)
>  {

Spurious change.  Please remove it.

> diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
> index e64949504d..47dea21e5a 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)
>  {
> +  struct 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;

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?

> @@ -998,13 +999,14 @@ static int
>  linux_create_inferior (const char *program,
>                 const std::vector<char *> &program_args)
>  {
> +  struct 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);
> 

This one might be OK-ish with the assumption that it's always
going to be the current client that is requesting the
inferior creation.

>      pid = fork_inferior (program,
> @@ -1429,6 +1431,7 @@ linux_kill (int pid)
>  static int
>  get_detach_signal (struct thread_info *thread)
>  {
> +  struct 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])

Similarly, what is the plan for multiple clients for this property,
when the clients don't agree, on both support for the packet,
and, what if they don't agree on pass/nopass state?

>      {
>        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)
>  {
> +  struct 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;

Ditto.

> @@ -2354,6 +2358,7 @@ linux_low_ptrace_options (int attached)
>  static struct lwp_info *
>  linux_low_filter_event (int lwpid, int wstat)
>  {
> +  struct 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

Ditto.

> @@ -3049,12 +3054,13 @@ static ptid_t
>  filter_exit_event (struct lwp_info *event_child,
>             struct target_waitstatus *ourstatus)
>  {
> +  struct 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)
>  {
> +  struct 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;
> 
> @@ -5036,6 +5043,7 @@ linux_resume_one_thread (thread_info *thread, bool leave_all_stopped)
>  static void
>  linux_resume (struct thread_resume *resume_info, size_t n)
>  {
> +  struct client_state & cs = get_client_state ();
>    struct thread_info *need_step_over = NULL;
> 

This one looks unnecessary/unused.  'cs' is not used.

>    if (debug_threads)
> diff --git a/gdb/gdbserver/notif.c b/gdb/gdbserver/notif.c
> index 5ff7079123..2cd411f9bb 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)
>  {
> +  struct 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)
>  {
> +  struct 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..ea02631444 100644
> --- a/gdb/gdbserver/remote-utils.c
> +++ b/gdb/gdbserver/remote-utils.c
> @@ -26,6 +26,7 @@
>  #include "dll.h"
>  #include "rsp-low.h"
>  #include "gdbthread.h"
> +#include "server.h"

This should be unnecessary - "server.h" is already included above.
I could tell because "server.h" must always be the
first include in all .c files.

>  #include <ctype.h>
>  #if HAVE_SYS_IOCTL_H
>  #include <sys/ioctl.h>
> @@ -103,7 +104,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 +115,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)


> diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
> index 5027df5e10..b4b72b55f8 100644
> --- a/gdb/gdbserver/server.c
> +++ b/gdb/gdbserver/server.c
> @@ -83,36 +83,17 @@ ptid_t cont_thread;
>  /* The thread set with an `Hg' packet.  */
>  ptid_t general_thread;
> 
> -int server_waiting;
> -
>  static int extended_protocol;
>  static int response_needed;
>  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;
> +int run_once = 0;

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

> 
>  /* 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

> 
>  /* A sub-class of 'struct notif_event' for stop, holding information
> @@ -193,6 +169,18 @@ static struct btrace_config current_btrace_conf;
> 
>  DEFINE_QUEUE_P (notif_event_p);
> 
> +/* The client remote protocol state. */
> +
> +static struct client_state *client_state;

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

> +
> +struct client_state &
> +get_client_state (void)

We use (void) in many places because of C heritage, but it's
no longer needed in C++, so:

  (void) -> ()

> +{
> +  struct client_state & cs = *client_state;
> +  return cs;

Simply write:

  return *g_client_state;

Thus:

 client_state &
 get_client_state ()
 {
   return *g_client_state;
 }

> @@ -1835,10 +1830,11 @@ handle_qxfer_btrace (const char *annex,
>               gdb_byte *readbuf, const gdb_byte *writebuf,
>               ULONGEST offset, LONGEST len)
>  {
> +  struct client_state & cs = get_client_state ();
>    static struct buffer cache;
>    struct thread_info *thread;
>    enum btrace_read_type type;
> -  int result;
> +  int result = 0;

This "= 0" looks like a spurious change.

> 
>    if (writebuf != NULL)
>      return -2;
> @@ -1846,20 +1842,20 @@ handle_qxfer_btrace (const char *annex,
>    if (ptid_equal (general_thread, null_ptid)
>        || ptid_equal (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);
>    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 +1867,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 +1879,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,9 +1912,10 @@ handle_qxfer_btrace_conf (const char *annex,
>                gdb_byte *readbuf, const gdb_byte *writebuf,
>                ULONGEST offset, LONGEST len)
>  {
> +  struct client_state & cs = get_client_state ();
>    static struct buffer cache;
>    struct thread_info *thread;
> -  int result;
> +  int result = 0;

Ditto.

> 
>    if (writebuf != NULL)
>      return -2;

> @@ -2729,13 +2727,14 @@ static int
>  handle_pending_status (const struct thread_resume *resumption,
>                 struct thread_info *thread)
>  {
> +  struct 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;

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

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


> @@ -3577,6 +3581,9 @@ captured_main (int argc, char *argv[])
>  #endif
> 
>    current_directory = getcwd (NULL, 0);
> +  client_state = new (struct client_state);

Write:

  g_client_state = new client_state ();

Or better, at this point (in this patch) there's really no
need to allocate this object on the heap, so let's remove the
'new' line, and make the g_client_state global not-a-pointer:

 client_state g_client_state;

We can move it to the heap in the patch that actually 
allocates more than one such objects.

> diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
> index 5970431d8e..7518309988 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 */
> @@ -72,40 +70,14 @@ void initialize_low ();
> 
>  extern ptid_t cont_thread;
>  extern ptid_t general_thread;

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

> @@ -162,4 +134,62 @@ 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 target.  */

What is a "target" in this context?  Did you mean "connected client"
instead of "connected target"?

> +
> +struct client_state
> +{
> +  /* From server.c */

I'm thinking that this "From foo.c" comments won't make much sense
after this is merged.  (Ideally we'd add descriptions for what
the fields are instead, but we don't have one today, so this can
go without.)

> +  int server_waiting = 0;
> +  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];

Add line break between the two above, they're unrelated.

> +  int program_signals[GDB_SIGNAL_LAST];
> +  int program_signals_p = 0;
> +  char *own_buf;

Add line break between the two above, they're unrelated.

> +
> +  /* from remote-utils.c */
> +  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;
> +  /* from tracepoint.c */
> +  /* 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 ():
> +    own_buf ((char *) xmalloc (PBUFSIZ + 1)) {}

Contructors should go above the data fields.  Please make
this the first entry in the struct.  Also, formatting, please
write:

  client_state ()
    : own_buf ((char *) xmalloc (PBUFSIZ + 1)) 
  {}

> +};
> +
> +struct client_state& get_client_state (void);

Write:

 extern client_state &get_client_state ();

> diff --git a/gdb/gdbserver/spu-low.c b/gdb/gdbserver/spu-low.c
> index 5b880d2a42..d909966199 100644
> --- a/gdb/gdbserver/spu-low.c
> +++ b/gdb/gdbserver/spu-low.c
> @@ -418,6 +418,7 @@ spu_resume (struct thread_resume *resume_info, size_t n)
>  static ptid_t
>  spu_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int options)
>  {
> +  struct client_state & cs = get_client_state ();
>    int pid = ptid_get_pid (ptid);
>    int w;
>    int ret;
> @@ -439,7 +440,7 @@ spu_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int options)
> 
>    /* On the first wait, continue running the inferior until we are
>       blocked inside an spu_run system call.  */
> -  if (!server_waiting)
> +  if (!cs.server_waiting)

This is another case of what does this mean for
multiple clients?  One will be waiting, but another
one won't.  How can the backend know what to do?

I suspect that it'd be better to make the server_waiting
global be per-process instead (and likely renamed), though
I haven't studied in detail what are all the cases it is
used for.

> --- a/gdb/gdbserver/target.c
> +++ b/gdb/gdbserver/target.c
> @@ -52,7 +52,6 @@ prepare_to_access_memory (void)
>    /* Save the general thread value, since prepare_to_access_memory could change
>       it.  */
>    prev_general_thread = general_thread;
> -
>    if (the_target->prepare_to_access_memory != NULL)

Spurious change.

Thanks,
Pedro Alves
  
Frank Ch. Eigler May 7, 2018, 7:16 p.m. UTC | #2
palves wrote:

> [...]
> Some comments more.  I still have some design reservations.
> It seems to me that simply making some of the globals be
> per client along won't work correctly.  Particularly, the
> cases where the globals are used in the backends.
> [...]

I don't want to speak for Stan here, but I suspect all this is about is
the breaking up of the multi-client work along the patchset path your
requested.  Yup, indeed backends have to do the logical 'union' of the
work that all the clients request, and each client interface will have
to filter the notifications correspondingly to undo the 'union'.  

But all that is in a separate patch; this part seems to simply
reorganize the globals in preparation for that, as you asked.

- FChE
  
Pedro Alves May 25, 2018, 1:49 p.m. UTC | #3
On 05/07/2018 08:16 PM, Frank Ch. Eigler wrote:
> 
> palves wrote:
> 
>> [...]
>> Some comments more.  I still have some design reservations.
>> It seems to me that simply making some of the globals be
>> per client along won't work correctly.  Particularly, the
>> cases where the globals are used in the backends.
>> [...]
> 

> I don't want to speak for Stan here, 

;-)

> but I suspect all this is about is
> the breaking up of the multi-client work along the patchset path your
> requested.  Yup, indeed backends have to do the logical 'union' of the
> work that all the clients request, and each client interface will have
> to filter the notifications correspondingly to undo the 'union'.  

Note that in some cases it's not just even filtering.  Globals
can control modes of operation, like the cs->non_stop case I pointed
out in a previous review.

> 
> But all that is in a separate patch; this part seems to simply
> reorganize the globals in preparation for that, as you asked.

Right, but it doesn't hurt to think about the plan for the
issues I pointed out a bit, since it may avoid churn in a
direction that we may not want.  In the original version of the patch,
when macros were used, these references to client_state fields
from the backends were pretty much invisible (because of the macros),
so it would be unsurprising to me if the full multi-client prototype
that is based on the macros version does not consider these issues.

I'll go look at the updated patch.

Thanks,
Pedro Alves
  

Patch

--- 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)
  {
+  struct client_state & cs = get_client_state ();
    if (debug_threads)
      {
        debug_printf ("args: %s\n", args);
diff --git a/gdb/gdbserver/gdbthread.h b/gdb/gdbserver/gdbthread.h
index 0edf870c56..9a8c72e780 100644
--- a/gdb/gdbserver/gdbthread.h
+++ b/gdb/gdbserver/gdbthread.h
@@ -224,4 +224,7 @@  lwpid_of (const thread_info *thread)
    return thread->id.lwp ();
  }

+/* Create a cleanup to restore current_thread.  */
+struct cleanup *make_cleanup_restore_current_thread (void);
+
  #endif /* GDB_THREAD_H */
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-arm-low.c b/gdb/gdbserver/linux-arm-low.c
index 6c2dcead03..3004018e5b 100644
--- a/gdb/gdbserver/linux-arm-low.c
+++ b/gdb/gdbserver/linux-arm-low.c
@@ -160,6 +160,7 @@  static struct arm_get_next_pcs_ops get_next_pcs_ops = {
    arm_linux_get_next_pcs_fixup,
  };

+
  static int
  arm_cannot_store_register (int regno)
  {
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index e64949504d..47dea21e5a 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)
  {
+  struct 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)
  {
+  struct 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)
  {
+  struct 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)
  {
+  struct 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)
  {
+  struct 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)
  {
+  struct 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)
  {
+  struct 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;

@@ -5036,6 +5043,7 @@  linux_resume_one_thread (thread_info *thread, bool 
leave_all_stopped)
  static void
  linux_resume (struct thread_resume *resume_info, size_t n)
  {
+  struct client_state & cs = get_client_state ();
    struct thread_info *need_step_over = NULL;

    if (debug_threads)
diff --git a/gdb/gdbserver/notif.c b/gdb/gdbserver/notif.c
index 5ff7079123..2cd411f9bb 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)
  {
+  struct 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)
  {
+  struct 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..ea02631444 100644
--- a/gdb/gdbserver/remote-utils.c
+++ b/gdb/gdbserver/remote-utils.c
@@ -26,6 +26,7 @@ 
  #include "dll.h"
  #include "rsp-low.h"
  #include "gdbthread.h"
+#include "server.h"
  #include <ctype.h>
  #if HAVE_SYS_IOCTL_H
  #include <sys/ioctl.h>
@@ -103,7 +104,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 +115,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 +217,7 @@  handle_accept_event (int err, gdb_client_data 
client_data)
  void
  remote_prepare (const char *name)
  {
+  struct client_state & cs = get_client_state ();
    const char *port_str;
  #ifdef USE_WIN32API
    static int winsock_initialized;
@@ -238,14 +234,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 +276,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 +481,10 @@  try_rle (char *buf, int remaining, unsigned char 
*csum, char **p)
  char *
  write_ptid (char *buf, ptid_t ptid)
  {
+  struct 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 +591,7 @@  read_prim (void *buf, int count)
  static int
  putpkt_binary_1 (char *buf, int cnt, int is_notif)
  {
+  struct client_state & cs = get_client_state ();
    int i;
    unsigned char csum = 0;
    char *buf2;
@@ -631,10 +629,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 +643,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 +657,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 +849,7 @@  static unsigned char *readchar_bufp;
  static int
  readchar (void)
  {
+  struct client_state & cs = get_client_state ();
    int ch;

    if (readchar_bufcnt == 0)
@@ -861,7 +860,7 @@  readchar (void)
  	{
  	  if (readchar_bufcnt == 0)
  	    {
-	      if (remote_debug)
+	      if (cs.remote_debug)
  		debug_printf ("readchar: Got EOF\n");
  	    }
  	  else
@@ -926,6 +925,7 @@  reschedule (void)
  int
  getpkt (char *buf)
  {
+  struct client_state & cs = get_client_state ();
    char *bp;
    unsigned char csum, c1, c2;
    int c;
@@ -948,7 +948,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 +977,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 +993,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 +1004,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 +1012,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 +1081,7 @@  void
  prepare_resume_reply (char *buf, ptid_t ptid,
  		      struct target_waitstatus *status)
  {
+  struct 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 +1101,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 +1114,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 +1141,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 +1189,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);
@@ -1256,14 +1259,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 +1438,7 @@  clear_symbol_cache (struct sym_cache **symcache_p)
  int
  look_up_one_symbol (const char *name, CORE_ADDR *addrp, int may_ask_gdb)
  {
+  struct client_state & cs = get_client_state ();
    char *p, *q;
    int len;
    struct sym_cache *sym;
@@ -1456,14 +1460,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 +1478,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 +1552,18 @@  look_up_one_symbol (const char *name, CORE_ADDR 
*addrp, int may_ask_gdb)
  int
  relocate_instruction (CORE_ADDR *to, CORE_ADDR oldloc)
  {
+  struct 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 +1571,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..b4b72b55f8 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -83,36 +83,17 @@  ptid_t cont_thread;
  /* The thread set with an `Hg' packet.  */
  ptid_t general_thread;

-int server_waiting;
-
  static int extended_protocol;
  static int response_needed;
  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;
+int run_once = 0;

  /* 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 +127,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
@@ -169,7 +146,6 @@  int disable_packet_qfThreadInfo;
  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 +169,18 @@  static struct btrace_config current_btrace_conf;

  DEFINE_QUEUE_P (notif_event_p);

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

  static void
@@ -348,7 +336,6 @@  attach_inferior (int pid)
    return 0;
  }

-extern int remote_debug;

  /* Decode a qXfer read request.  Return 0 if everything looks OK,
     or -1 otherwise.  */
@@ -572,6 +559,7 @@  handle_btrace_conf_general_set (char *own_buf)
  static void
  handle_general_set (char *own_buf)
  {
+  struct client_state & cs = get_client_state ();
    if (startswith (own_buf, "QPassSignals:"))
      {
        int numsigs = (int) GDB_SIGNAL_LAST, i;
@@ -583,7 +571,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 +579,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 +591,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 +606,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 +676,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 +707,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 +723,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 +764,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 +777,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 +812,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 +841,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 +871,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 +889,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 +899,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 +986,15 @@  monitor_show_help (void)
  static int
  gdb_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
  {
+  struct 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 +1027,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)
+  struct client_state & cs = get_client_state ();
+  if (cs.current_traceframe >= 0)
      return EIO;
    else
      {
@@ -1213,11 +1203,12 @@  handle_search_memory (char *own_buf, int packet_len)
  static void
  handle_detach (char *own_buf)
  {
+  struct 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);
@@ -1370,6 +1361,7 @@  parse_debug_format_options (const char *arg, int 
is_monitor)
  static void
  handle_monitor_command (char *mon, char *own_buf)
  {
+  struct client_state & cs = get_client_state ();
    if (strcmp (mon, "set debug 1") == 0)
      {
        debug_threads = 1;
@@ -1392,12 +1384,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 +1638,17 @@  handle_qxfer_statictrace (const char *annex,
  			  gdb_byte *readbuf, const gdb_byte *writebuf,
  			  ULONGEST offset, LONGEST len)
  {
+  struct 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 +1764,14 @@  handle_qxfer_traceframe_info (const char *annex,
  			      gdb_byte *readbuf, const gdb_byte *writebuf,
  			      ULONGEST offset, LONGEST len)
  {
+  struct 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 +1785,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,10 +1830,11 @@  handle_qxfer_btrace (const char *annex,
  		     gdb_byte *readbuf, const gdb_byte *writebuf,
  		     ULONGEST offset, LONGEST len)
  {
+  struct client_state & cs = get_client_state ();
    static struct buffer cache;
    struct thread_info *thread;
    enum btrace_read_type type;
-  int result;
+  int result = 0;

    if (writebuf != NULL)
      return -2;
@@ -1846,20 +1842,20 @@  handle_qxfer_btrace (const char *annex,
    if (ptid_equal (general_thread, null_ptid)
        || ptid_equal (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);
    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 +1867,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 +1879,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,9 +1912,10 @@  handle_qxfer_btrace_conf (const char *annex,
  			  gdb_byte *readbuf, const gdb_byte *writebuf,
  			  ULONGEST offset, LONGEST len)
  {
+  struct client_state & cs = get_client_state ();
    static struct buffer cache;
    struct thread_info *thread;
-  int result;
+  int result = 0;

    if (writebuf != NULL)
      return -2;
@@ -1929,20 +1926,20 @@  handle_qxfer_btrace_conf (const char *annex,
    if (ptid_equal (general_thread, null_ptid)
        || ptid_equal (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);
    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 +1951,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 +2155,7 @@  supported_btrace_packets (char *buf)
  static void
  handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
  {
+  struct client_state & cs = get_client_state ();
    static std::list<thread_info *>::const_iterator thread_iter;

    /* Reply the current thread id.  */
@@ -2312,7 +2310,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 +2323,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 +2416,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 +2727,14 @@  static int
  handle_pending_status (const struct thread_resume *resumption,
  		       struct thread_info *thread)
  {
+  struct 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);
+      prepare_resume_reply (cs.own_buf, last_ptid, &last_status);
        return 1;
      }
    return 0;
@@ -2855,6 +2854,7 @@  err:
  static void
  resume (struct thread_resume *actions, size_t num_actions)
  {
+  struct client_state & cs = get_client_state ();
    if (!non_stop)
      {
        /* Check if among the threads that GDB wants actioned, there's
@@ -2877,7 +2877,7 @@  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);
@@ -2887,7 +2887,7 @@  resume (struct thread_resume *actions, size_t 
num_actions)
  	{
  	  /* 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;
  	}
@@ -2902,7 +2902,7 @@  resume (struct thread_resume *actions, size_t 
num_actions)
  	 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, last_ptid, &last_status);
        disable_async_io ();

        if (last_status.kind == TARGET_WAITKIND_EXITED
@@ -3078,9 +3078,10 @@  handle_v_run (char *own_buf)
  static int
  handle_v_kill (char *own_buf)
  {
+  struct 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;
@@ -3104,6 +3105,7 @@  handle_v_kill (char *own_buf)
  void
  handle_v_requests (char *own_buf, int packet_len, int *new_packet_len)
  {
+  struct client_state & cs = get_client_state ();
    if (!disable_packet_vCont)
      {
        if (strcmp (own_buf, "vCtrlC") == 0)
@@ -3125,7 +3127,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 +3153,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 +3165,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);
@@ -3320,6 +3322,8 @@  set_pending_status_callback (thread_info *thread)
  static void
  handle_status (char *own_buf)
  {
+  struct 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 +3340,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
      {
@@ -3577,6 +3581,9 @@  captured_main (int argc, char *argv[])
  #endif

    current_directory = getcwd (NULL, 0);
+  client_state = new (struct client_state);
+  struct client_state & cs = *client_state;
+
    if (current_directory == NULL)
      {
        error (_("Could not find current working directory: %s"),
@@ -3643,7 +3650,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 +3698,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 +3787,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)
@@ -3841,18 +3847,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;
+      cs.current_traceframe = -1;
        cont_thread = null_ptid;
-      swbreak_feature = 0;
-      hwbreak_feature = 0;
-      vCont_supported = 0;
+      cs.swbreak_feature = 0;
+      cs.hwbreak_feature = 0;
+      cs.vCont_supported = 0;

        remote_open (port);

@@ -3928,8 +3933,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 +4029,7 @@  process_point_options (struct gdb_breakpoint *bp, 
const char **packet)
  static int
  process_serial_event (void)
  {
+  struct client_state & cs = get_client_state ();
    int signal;
    unsigned int len;
    int res;
@@ -4035,7 +4041,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 +4050,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 +4085,7 @@  process_serial_event (void)

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

@@ -4090,12 +4096,12 @@  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))
  		{
@@ -4112,30 +4118,30 @@  process_serial_event (void)
  	      set_desired_thread ();
  	      gdb_assert (current_thread != NULL);
  	    }
-	  else if (own_buf[1] == 'c')
+	  else if (cs.own_buf[1] == 'c')
  	    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 +4149,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 +4236,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 +4267,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':
@@ -4293,19 +4299,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':
@@ -4349,26 +4355,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;

diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index 5970431d8e..7518309988 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 */
@@ -72,40 +70,14 @@  void initialize_low ();

  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;
@@ -162,4 +134,62 @@  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 target.  */
+
+struct client_state
+{
+  /* From server.c */
+  int server_waiting = 0;
+  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;
+  char *own_buf;
+
+  /* from remote-utils.c */
+  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;
+  /* from tracepoint.c */
+  /* 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 ():
+    own_buf ((char *) xmalloc (PBUFSIZ + 1)) {}
+};
+
+struct client_state& get_client_state (void);
+
+#include "gdbthread.h"
+#include "inferiors.h"
+
  #endif /* SERVER_H */
diff --git a/gdb/gdbserver/spu-low.c b/gdb/gdbserver/spu-low.c
index 5b880d2a42..d909966199 100644
--- a/gdb/gdbserver/spu-low.c
+++ b/gdb/gdbserver/spu-low.c
@@ -418,6 +418,7 @@  spu_resume (struct thread_resume *resume_info, size_t n)
  static ptid_t
  spu_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int options)
  {
+  struct client_state & cs = get_client_state ();
    int pid = ptid_get_pid (ptid);
    int w;
    int ret;
@@ -439,7 +440,7 @@  spu_wait (ptid_t ptid, struct target_waitstatus 
*ourstatus, int options)

    /* On the first wait, continue running the inferior until we are
       blocked inside an spu_run system call.  */
-  if (!server_waiting)
+  if (!cs.server_waiting)
      {
        int fd;
        CORE_ADDR addr;
@@ -470,7 +471,7 @@  spu_wait (ptid_t ptid, struct target_waitstatus 
*ourstatus, int options)

    /* After attach, we may have received a SIGSTOP.  Do not return this
       as signal to GDB, or else it will try to continue with SIGSTOP 
...  */
-  if (!server_waiting)
+  if (!cs.server_waiting)
      {
        ourstatus->kind = TARGET_WAITKIND_STOPPED;
        ourstatus->value.sig = GDB_SIGNAL_0;
diff --git a/gdb/gdbserver/target.c b/gdb/gdbserver/target.c
index fe40b94db7..7ba1b96223 100644
--- a/gdb/gdbserver/target.c
+++ b/gdb/gdbserver/target.c
@@ -52,7 +52,6 @@  prepare_to_access_memory (void)
    /* Save the general thread value, since prepare_to_access_memory 
could change
       it.  */
    prev_general_thread = general_thread;
-
    if (the_target->prepare_to_access_memory != NULL)
      {
        int res;
@@ -176,10 +175,11 @@  ptid_t
  mywait (ptid_t ptid, struct target_waitstatus *ourstatus, int options,
  	int connected_wait)
  {
+  struct client_state & cs = get_client_state ();
    ptid_t ret;

    if (connected_wait)
-    server_waiting = 1;
+    cs.server_waiting = 1;

    ret = target_wait (ptid, ourstatus, options);

@@ -206,7 +206,7 @@  mywait (ptid_t ptid, struct target_waitstatus 
*ourstatus, int options,
      }

    if (connected_wait)
-    server_waiting = 0;
+    cs.server_waiting = 0;

    return ret;
  }
diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c
index 4172756192..61a01b218d 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)
  {
+  struct 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)
  {
+  struct 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.  */
    if (!tframe)
@@ -2343,6 +2340,7 @@  find_next_traceframe_by_tracepoint (int num, int 
*tfnump)
  static void
  cmd_qtinit (char *packet)
  {
+  struct 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)
  {
+  struct 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)
  {
+  struct 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)
  {
+  struct 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)
      {
diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
index 9f0c4e46c1..bbb4a04345 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -747,6 +747,7 @@  static void
  handle_output_debug_string (void)
  {
  #define READ_BUFFER_LEN 1024
+  struct client_state & cs = get_client_state ();
    CORE_ADDR addr;
    char s[READ_BUFFER_LEN + 1] = { 0 };
    DWORD nbytes = current_event.u.DebugString.nDebugStringLength;
@@ -776,7 +777,7 @@  handle_output_debug_string (void)

    if (!startswith (s, "cYg"))
      {
-      if (!server_waiting)
+      if (!cs.server_waiting)
  	{
  	  OUTMSG2(("%s", s));
  	  return;