[3/3] gdb, gdbserver: make target_waitstatus safe

Message ID 20211012161755.502639-3-simon.marchi@efficios.com
State New
Headers show
Series
  • [1/3] gdbserver: make thread_info non-POD
Related show

Commit Message

Stafford Horne via Gdb-patches Oct. 12, 2021, 4:17 p.m.
From: Simon Marchi <simon.marchi@polymtl.ca>


I stumbled on a bug caused by the fact that a code path read
target_waitstatus::value::sig (expecting it to contain a gdb_signal
value) while target_waitstatus::kind was TARGET_WAITKIND_FORKED.  This
meant that the active union field was in fact
target_waitstatus::value::related_pid, and contained a ptid.  The read
signal value was therefore garbage, and that caused GDB to crash soon
after.  Or, since that GDB was built with ubsan, this nice error
message:

    /home/simark/src/binutils-gdb/gdb/linux-nat.c:1271:12: runtime error: load of value 2686365, which is not a valid value for type 'gdb_signal'

Despite being a large-ish change, I think it would be nice to make
target_waitstatus safe against that kind of bug.  As already done
elsewhere (e.g. dynamic_prop), validate that the type of value read from
the union matches what is supposed to be the active field.

 - Make the kind and value of target_waitstatus private.
 - Make the kind initialized to TARGET_WAITKIND_IGNORE on
   target_waitstatus construction.  This is what most users appear to do
   explicitly.
 - Add setters, one for each kind.  Each setter takes as a parameter the
   data associated to that kind, if any.  This makes it impossible to
   forget to attach the associated data.
 - Add getters, one for each associated data type.  Each getter
   validates that the data type fetched by the user matches the wait
   status kind.
 - Change "integer" to "exit_status", "related_pid" to "child_ptid",
   just because that's more precise terminology.
 - Fix all users.

That last point is semi-mechanical.  There are a lot of obvious changes,
but some less obvious ones.  For example, it's not possible to set the
kind at some point and the associated data later, as some users did.
But in any case, the intent of the code should not change in this patch.

This was tested on x86-64 Linux (unix, native-gdbserver and
native-extended-gdbserver boards).  It was built-tested on x86-64
FreeBSD, NetBSD, MinGW and macOS.  The rest of the changes to native
files was done as a best effort.  If I forgot any place to update in
these files, it should be easy to fix (unless the change happens to
reveal an actual bug).

Change-Id: I0ae967df1ff6e28de78abbe3ac9b4b2ff4ad03b7
---
 gdb/aix-thread.c          |   4 +-
 gdb/break-catch-sig.c     |   6 +-
 gdb/break-catch-syscall.c |  14 +--
 gdb/breakpoint.c          |  22 ++--
 gdb/bsd-uthread.c         |   4 +-
 gdb/darwin-nat.c          |  58 +++++-----
 gdb/fbsd-nat.c            |  33 +++---
 gdb/gdbthread.h           |   2 +-
 gdb/gnu-nat.c             |  38 +++---
 gdb/go32-nat.c            |  16 +--
 gdb/inf-child.c           |  15 +--
 gdb/inf-ptrace.c          |   3 +-
 gdb/infcmd.c              |   3 +-
 gdb/infrun.c              | 189 +++++++++++++++---------------
 gdb/infrun.h              |   2 +-
 gdb/linux-nat.c           |  69 +++++------
 gdb/linux-nat.h           |   6 +-
 gdb/linux-thread-db.c     |   2 +-
 gdb/nat/fork-inferior.c   |  19 ++-
 gdb/nat/windows-nat.c     |  52 ++++-----
 gdb/netbsd-nat.c          |  26 ++---
 gdb/nto-procfs.c          |  37 ++----
 gdb/obsd-nat.c            |   9 +-
 gdb/procfs.c              |   9 +-
 gdb/ravenscar-thread.c    |   4 +-
 gdb/record-btrace.c       |  26 ++---
 gdb/record-full.c         |  36 +++---
 gdb/remote-sim.c          |   4 +-
 gdb/remote.c              | 142 ++++++++++-------------
 gdb/rs6000-nat.c          |   7 +-
 gdb/sol-thread.c          |   2 +-
 gdb/target.c              |   3 +-
 gdb/target/waitstatus.c   |  20 ++--
 gdb/target/waitstatus.h   | 236 +++++++++++++++++++++++++++++++++++++-
 gdb/thread.c              |   4 +-
 gdb/windows-nat.c         |  30 ++---
 gdbserver/gdbthread.h     |   4 +-
 gdbserver/linux-low.cc    | 134 +++++++++++-----------
 gdbserver/linux-low.h     |   5 -
 gdbserver/netbsd-low.cc   |  50 ++++----
 gdbserver/remote-utils.cc |  44 ++++---
 gdbserver/server.cc       |  90 +++++++--------
 gdbserver/target.cc       |  14 +--
 gdbserver/win32-low.cc    |  40 +++----
 44 files changed, 827 insertions(+), 706 deletions(-)

-- 
2.33.0

Comments

John Baldwin Oct. 12, 2021, 5:04 p.m. | #1
On 10/12/21 9:17 AM, Simon Marchi via Gdb-patches wrote:
> From: Simon Marchi <simon.marchi@polymtl.ca>

> 

> I stumbled on a bug caused by the fact that a code path read

> target_waitstatus::value::sig (expecting it to contain a gdb_signal

> value) while target_waitstatus::kind was TARGET_WAITKIND_FORKED.  This

> meant that the active union field was in fact

> target_waitstatus::value::related_pid, and contained a ptid.  The read

> signal value was therefore garbage, and that caused GDB to crash soon

> after.  Or, since that GDB was built with ubsan, this nice error

> message:

> 

>      /home/simark/src/binutils-gdb/gdb/linux-nat.c:1271:12: runtime error: load of value 2686365, which is not a valid value for type 'gdb_signal'

> 

> Despite being a large-ish change, I think it would be nice to make

> target_waitstatus safe against that kind of bug.  As already done

> elsewhere (e.g. dynamic_prop), validate that the type of value read from

> the union matches what is supposed to be the active field.

> 

>   - Make the kind and value of target_waitstatus private.

>   - Make the kind initialized to TARGET_WAITKIND_IGNORE on

>     target_waitstatus construction.  This is what most users appear to do

>     explicitly.

>   - Add setters, one for each kind.  Each setter takes as a parameter the

>     data associated to that kind, if any.  This makes it impossible to

>     forget to attach the associated data.

>   - Add getters, one for each associated data type.  Each getter

>     validates that the data type fetched by the user matches the wait

>     status kind.

>   - Change "integer" to "exit_status", "related_pid" to "child_ptid",

>     just because that's more precise terminology.

>   - Fix all users.

> 

> That last point is semi-mechanical.  There are a lot of obvious changes,

> but some less obvious ones.  For example, it's not possible to set the

> kind at some point and the associated data later, as some users did.

> But in any case, the intent of the code should not change in this patch.

> 

> This was tested on x86-64 Linux (unix, native-gdbserver and

> native-extended-gdbserver boards).  It was built-tested on x86-64

> FreeBSD, NetBSD, MinGW and macOS.  The rest of the changes to native

> files was done as a best effort.  If I forgot any place to update in

> these files, it should be easy to fix (unless the change happens to

> reveal an actual bug).


I think this is a good change.  I only read over fbsd-nat.c and I think
I like the idea.  One thing that does stick out to me is the assymetry
in that we no longer use TARGET_WAITKIND_* for setting the status, only
when comparing the result of kind().  I wonder if instead you might
consider adding type specific queries (e.g. is_ignored(), is_forked())
and removing TARGET_WAITKIND_* as a public interface entirely?

-- 
John Baldwin
Simon Marchi Oct. 12, 2021, 5:28 p.m. | #2
On 2021-10-12 1:04 p.m., John Baldwin wrote:
> I think this is a good change.  I only read over fbsd-nat.c and I think

> I like the idea.  One thing that does stick out to me is the assymetry

> in that we no longer use TARGET_WAITKIND_* for setting the status, only

> when comparing the result of kind().  I wonder if instead you might

> consider adding type specific queries (e.g. is_ignored(), is_forked())

> and removing TARGET_WAITKIND_* as a public interface entirely?


I don't mind giving it a try, but it would be as a separate patch.

Simon
Stafford Horne via Gdb-patches Oct. 13, 2021, 1:57 a.m. | #3
On 2021-10-12 13:28, Simon Marchi wrote:
> On 2021-10-12 1:04 p.m., John Baldwin wrote:

>> I think this is a good change.  I only read over fbsd-nat.c and I think

>> I like the idea.  One thing that does stick out to me is the assymetry

>> in that we no longer use TARGET_WAITKIND_* for setting the status, only

>> when comparing the result of kind().  I wonder if instead you might

>> consider adding type specific queries (e.g. is_ignored(), is_forked())

>> and removing TARGET_WAITKIND_* as a public interface entirely?

> 

> I don't mind giving it a try, but it would be as a separate patch.

> 

> Simon

> 


I gave this a try, and I don't think I will pursue it.  It would be a
lot of work for not much gain.  Also, there are spots where we call
kind() and use the result in a switch.  I don't really want to convert
them to chains of if/else if/else if, I think it would make things less
readable actually.

Simon
John Baldwin Oct. 13, 2021, 2:08 a.m. | #4
On 10/12/21 6:57 PM, Simon Marchi wrote:
> On 2021-10-12 13:28, Simon Marchi wrote:

>> On 2021-10-12 1:04 p.m., John Baldwin wrote:

>>> I think this is a good change.  I only read over fbsd-nat.c and I think

>>> I like the idea.  One thing that does stick out to me is the assymetry

>>> in that we no longer use TARGET_WAITKIND_* for setting the status, only

>>> when comparing the result of kind().  I wonder if instead you might

>>> consider adding type specific queries (e.g. is_ignored(), is_forked())

>>> and removing TARGET_WAITKIND_* as a public interface entirely?

>>

>> I don't mind giving it a try, but it would be as a separate patch.

>>

>> Simon

>>

> 

> I gave this a try, and I don't think I will pursue it.  It would be a

> lot of work for not much gain.  Also, there are spots where we call

> kind() and use the result in a switch.  I don't really want to convert

> them to chains of if/else if/else if, I think it would make things less

> readable actually.


Ok, fair enough.  Thanks for looking at it.

-- 
John Baldwin

Patch

diff --git a/gdb/aix-thread.c b/gdb/aix-thread.c
index 04649015d23..a604320d666 100644
--- a/gdb/aix-thread.c
+++ b/gdb/aix-thread.c
@@ -1092,8 +1092,8 @@  aix_thread_target::wait (ptid_t ptid, struct target_waitstatus *status,
     return ptid_t (-1);
 
   /* Check whether libpthdebug might be ready to be initialized.  */
-  if (!pd_active && status->kind == TARGET_WAITKIND_STOPPED
-      && status->value.sig == GDB_SIGNAL_TRAP)
+  if (!pd_active && status->kind () == TARGET_WAITKIND_STOPPED
+      && status->sig () == GDB_SIGNAL_TRAP)
     {
       process_stratum_target *proc_target
 	= current_inferior ()->process_target ();
diff --git a/gdb/break-catch-sig.c b/gdb/break-catch-sig.c
index 5c7d62fe1ec..9c5db901614 100644
--- a/gdb/break-catch-sig.c
+++ b/gdb/break-catch-sig.c
@@ -155,10 +155,10 @@  signal_catchpoint_breakpoint_hit (const struct bp_location *bl,
     = (const struct signal_catchpoint *) bl->owner;
   gdb_signal signal_number;
 
-  if (ws->kind != TARGET_WAITKIND_STOPPED)
+  if (ws->kind () != TARGET_WAITKIND_STOPPED)
     return 0;
 
-  signal_number = ws->value.sig;
+  signal_number = ws->sig ();
 
   /* If we are catching specific signals in this breakpoint, then we
      must guarantee that the called signal is the same signal we are
@@ -188,7 +188,7 @@  signal_catchpoint_print_it (bpstat bs)
 
   get_last_target_status (nullptr, nullptr, &last);
 
-  signal_name = signal_to_name_or_int (last.value.sig);
+  signal_name = signal_to_name_or_int (last.sig ());
 
   annotate_catchpoint (b->number);
   maybe_print_thread_hit_breakpoint (uiout);
diff --git a/gdb/break-catch-syscall.c b/gdb/break-catch-syscall.c
index 32736f024ad..6d3549d6fb1 100644
--- a/gdb/break-catch-syscall.c
+++ b/gdb/break-catch-syscall.c
@@ -152,11 +152,11 @@  breakpoint_hit_catch_syscall (const struct bp_location *bl,
   const struct syscall_catchpoint *c
     = (const struct syscall_catchpoint *) bl->owner;
 
-  if (ws->kind != TARGET_WAITKIND_SYSCALL_ENTRY
-      && ws->kind != TARGET_WAITKIND_SYSCALL_RETURN)
+  if (ws->kind () != TARGET_WAITKIND_SYSCALL_ENTRY
+      && ws->kind () != TARGET_WAITKIND_SYSCALL_RETURN)
     return 0;
 
-  syscall_number = ws->value.syscall_number;
+  syscall_number = ws->syscall_number ();
 
   /* Now, checking if the syscall is the same.  */
   if (!c->syscalls_to_be_caught.empty ())
@@ -189,7 +189,7 @@  print_it_catch_syscall (bpstat bs)
 
   get_last_target_status (nullptr, nullptr, &last);
 
-  get_syscall_by_number (gdbarch, last.value.syscall_number, &s);
+  get_syscall_by_number (gdbarch, last.syscall_number (), &s);
 
   annotate_catchpoint (b->number);
   maybe_print_thread_hit_breakpoint (uiout);
@@ -201,20 +201,20 @@  print_it_catch_syscall (bpstat bs)
   if (uiout->is_mi_like_p ())
     {
       uiout->field_string ("reason",
-			   async_reason_lookup (last.kind == TARGET_WAITKIND_SYSCALL_ENTRY
+			   async_reason_lookup (last.kind () == TARGET_WAITKIND_SYSCALL_ENTRY
 						? EXEC_ASYNC_SYSCALL_ENTRY
 						: EXEC_ASYNC_SYSCALL_RETURN));
       uiout->field_string ("disp", bpdisp_text (b->disposition));
     }
   uiout->field_signed ("bkptno", b->number);
 
-  if (last.kind == TARGET_WAITKIND_SYSCALL_ENTRY)
+  if (last.kind () == TARGET_WAITKIND_SYSCALL_ENTRY)
     uiout->text (" (call to syscall ");
   else
     uiout->text (" (returned from syscall ");
 
   if (s.name == NULL || uiout->is_mi_like_p ())
-    uiout->field_signed ("syscall-number", last.value.syscall_number);
+    uiout->field_signed ("syscall-number", last.syscall_number ());
   if (s.name != NULL)
     uiout->field_string ("syscall-name", s.name);
 
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index e742a1eccfe..359e77a20c2 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -7764,10 +7764,10 @@  breakpoint_hit_catch_fork (const struct bp_location *bl,
 {
   struct fork_catchpoint *c = (struct fork_catchpoint *) bl->owner;
 
-  if (ws->kind != TARGET_WAITKIND_FORKED)
+  if (ws->kind () != TARGET_WAITKIND_FORKED)
     return 0;
 
-  c->forked_inferior_pid = ws->value.related_pid;
+  c->forked_inferior_pid = ws->child_ptid ();
   return 1;
 }
 
@@ -7880,10 +7880,10 @@  breakpoint_hit_catch_vfork (const struct bp_location *bl,
 {
   struct fork_catchpoint *c = (struct fork_catchpoint *) bl->owner;
 
-  if (ws->kind != TARGET_WAITKIND_VFORKED)
+  if (ws->kind () != TARGET_WAITKIND_VFORKED)
     return 0;
 
-  c->forked_inferior_pid = ws->value.related_pid;
+  c->forked_inferior_pid = ws->child_ptid ();
   return 1;
 }
 
@@ -8009,7 +8009,7 @@  breakpoint_hit_catch_solib (const struct bp_location *bl,
 {
   struct solib_catchpoint *self = (struct solib_catchpoint *) bl->owner;
 
-  if (ws->kind == TARGET_WAITKIND_LOADED)
+  if (ws->kind () == TARGET_WAITKIND_LOADED)
     return 1;
 
   for (breakpoint *other : all_breakpoints ())
@@ -8289,10 +8289,10 @@  breakpoint_hit_catch_exec (const struct bp_location *bl,
 {
   struct exec_catchpoint *c = (struct exec_catchpoint *) bl->owner;
 
-  if (ws->kind != TARGET_WAITKIND_EXECD)
+  if (ws->kind () != TARGET_WAITKIND_EXECD)
     return 0;
 
-  c->exec_pathname = xstrdup (ws->value.execd_pathname);
+  c->exec_pathname = xstrdup (ws->execd_pathname ());
   return 1;
 }
 
@@ -9787,8 +9787,8 @@  breakpoint_hit_ranged_breakpoint (const struct bp_location *bl,
 				  CORE_ADDR bp_addr,
 				  const struct target_waitstatus *ws)
 {
-  if (ws->kind != TARGET_WAITKIND_STOPPED
-      || ws->value.sig != GDB_SIGNAL_TRAP)
+  if (ws->kind () != TARGET_WAITKIND_STOPPED
+      || ws->sig () != GDB_SIGNAL_TRAP)
     return 0;
 
   return breakpoint_address_match_range (bl->pspace->aspace, bl->address,
@@ -12474,8 +12474,8 @@  bkpt_breakpoint_hit (const struct bp_location *bl,
 		     const address_space *aspace, CORE_ADDR bp_addr,
 		     const struct target_waitstatus *ws)
 {
-  if (ws->kind != TARGET_WAITKIND_STOPPED
-      || ws->value.sig != GDB_SIGNAL_TRAP)
+  if (ws->kind () != TARGET_WAITKIND_STOPPED
+      || ws->sig () != GDB_SIGNAL_TRAP)
     return 0;
 
   if (!breakpoint_address_match (bl->pspace->aspace, bl->address,
diff --git a/gdb/bsd-uthread.c b/gdb/bsd-uthread.c
index 1e594983bcd..7709a81b3ce 100644
--- a/gdb/bsd-uthread.c
+++ b/gdb/bsd-uthread.c
@@ -389,8 +389,8 @@  bsd_uthread_target::wait (ptid_t ptid, struct target_waitstatus *status,
 
   /* If the process is no longer alive, there's no point in figuring
      out the thread ID.  It will fail anyway.  */
-  if (status->kind == TARGET_WAITKIND_SIGNALLED
-      || status->kind == TARGET_WAITKIND_EXITED)
+  if (status->kind () == TARGET_WAITKIND_SIGNALLED
+      || status->kind () == TARGET_WAITKIND_EXITED)
     return ptid;
 
   /* Fetch the corresponding thread ID, and augment the returned
diff --git a/gdb/darwin-nat.c b/gdb/darwin-nat.c
index 141eede11fe..e1aeb69e404 100644
--- a/gdb/darwin-nat.c
+++ b/gdb/darwin-nat.c
@@ -980,12 +980,12 @@  darwin_nat_target::decode_message (mach_msg_header_t *hdr,
 	  printf_unfiltered
 	    (_("darwin_wait: ill-formatted message (id=0x%x)\n"), hdr->msgh_id);
 	  /* FIXME: send a failure reply?  */
-	  status->kind = TARGET_WAITKIND_IGNORE;
+	  status->set_ignore ();
 	  return minus_one_ptid;
 	}
       if (inf == NULL)
 	{
-	  status->kind = TARGET_WAITKIND_IGNORE;
+	  status->set_ignore ();
 	  return minus_one_ptid;
 	}
       *pinf = inf;
@@ -995,7 +995,6 @@  darwin_nat_target::decode_message (mach_msg_header_t *hdr,
 
       priv->pending_messages++;
 
-      status->kind = TARGET_WAITKIND_STOPPED;
       thread->msg_state = DARWIN_MESSAGE;
 
       inferior_debug (4, _("darwin_wait: thread=0x%x, got %s\n"),
@@ -1005,25 +1004,25 @@  darwin_nat_target::decode_message (mach_msg_header_t *hdr,
       switch (thread->event.ex_type)
 	{
 	case EXC_BAD_ACCESS:
-	  status->value.sig = GDB_EXC_BAD_ACCESS;
+	  status->set_stopped (GDB_EXC_BAD_ACCESS);
 	  break;
 	case EXC_BAD_INSTRUCTION:
-	  status->value.sig = GDB_EXC_BAD_INSTRUCTION;
+	  status->set_stopped (GDB_EXC_BAD_INSTRUCTION);
 	  break;
 	case EXC_ARITHMETIC:
-	  status->value.sig = GDB_EXC_ARITHMETIC;
+	  status->set_stopped (GDB_EXC_ARITHMETIC);
 	  break;
 	case EXC_EMULATION:
-	  status->value.sig = GDB_EXC_EMULATION;
+	  status->set_stopped (GDB_EXC_EMULATION);
 	  break;
 	case EXC_SOFTWARE:
 	  if (thread->event.ex_data[0] == EXC_SOFT_SIGNAL)
 	    {
-	      status->value.sig =
-		gdb_signal_from_host (thread->event.ex_data[1]);
+	      status->set_stopped
+		(gdb_signal_from_host (thread->event.ex_data[1]));
 	      inferior_debug (5, _("  (signal %d: %s)\n"),
 			      thread->event.ex_data[1],
-			      gdb_signal_to_name (status->value.sig));
+			      gdb_signal_to_name (status->sig ()));
 
 	      /* If the thread is stopped because it has received a signal
 		 that gdb has just sent, continue.  */
@@ -1032,20 +1031,20 @@  darwin_nat_target::decode_message (mach_msg_header_t *hdr,
 		  thread->signaled = 0;
 		  darwin_send_reply (inf, thread);
 		  thread->msg_state = DARWIN_RUNNING;
-		  status->kind = TARGET_WAITKIND_IGNORE;
+		  status->set_ignore ();
 		}
 	    }
 	  else
-	    status->value.sig = GDB_EXC_SOFTWARE;
+	    status->set_stopped (GDB_EXC_SOFTWARE);
 	  break;
 	case EXC_BREAKPOINT:
 	  /* Many internal GDB routines expect breakpoints to be reported
 	     as GDB_SIGNAL_TRAP, and will report GDB_EXC_BREAKPOINT
 	     as a spurious signal.  */
-	  status->value.sig = GDB_SIGNAL_TRAP;
+	  status->set_stopped (GDB_SIGNAL_TRAP);
 	  break;
 	default:
-	  status->value.sig = GDB_SIGNAL_UNKNOWN;
+	  status->set_stopped (GDB_SIGNAL_UNKNOWN);
 	  break;
 	}
 
@@ -1071,7 +1070,7 @@  darwin_nat_target::decode_message (mach_msg_header_t *hdr,
 
       if (res < 0 || inf == NULL)
 	{
-	  status->kind = TARGET_WAITKIND_IGNORE;
+	  status->set_ignore ();
 	  return minus_one_ptid;
 	}
 
@@ -1089,18 +1088,15 @@  darwin_nat_target::decode_message (mach_msg_header_t *hdr,
 		{
 		  printf_unfiltered (_("wait4: res=%d: %s\n"),
 				     res_pid, safe_strerror (errno));
-		  status->kind = TARGET_WAITKIND_IGNORE;
+		  status->set_ignore ();
 		  return minus_one_ptid;
 		}
 	      if (WIFEXITED (wstatus))
-		{
-		  status->kind = TARGET_WAITKIND_EXITED;
-		  status->value.integer = WEXITSTATUS (wstatus);
-		}
+		status->set_exited (WEXITSTATUS (wstatus));
 	      else
 		{
-		  status->kind = TARGET_WAITKIND_SIGNALLED;
-		  status->value.sig = gdb_signal_from_host (WTERMSIG (wstatus));
+		  status->set_signalled
+		    (gdb_signal_from_host (WTERMSIG (wstatus)));
 		}
 
 	      inferior_debug (4, _("darwin_wait: pid=%d exit, status=0x%x\n"),
@@ -1114,8 +1110,7 @@  darwin_nat_target::decode_message (mach_msg_header_t *hdr,
 	  else
 	    {
 	      inferior_debug (4, _("darwin_wait: pid=%d\n"), inf->pid);
-	      status->kind = TARGET_WAITKIND_EXITED;
-	      status->value.integer = 0; /* Don't know.  */
+	      status->set_exited (0 /* Don't know.  */);
 	      return ptid_t (inf->pid, 0, 0);
 	    }
 	}
@@ -1123,7 +1118,7 @@  darwin_nat_target::decode_message (mach_msg_header_t *hdr,
 
   /* Unknown message.  */
   warning (_("darwin: got unknown message, id: 0x%x"), hdr->msgh_id);
-  status->kind = TARGET_WAITKIND_IGNORE;
+  status->set_ignore ();
   return minus_one_ptid;
 }
 
@@ -1182,8 +1177,7 @@  darwin_nat_target::wait_1 (ptid_t ptid, struct target_waitstatus *status)
 
       darwin_inferior *priv = get_darwin_inferior (inf);
 
-      status->kind = TARGET_WAITKIND_STOPPED;
-      status->value.sig = GDB_SIGNAL_TRAP;
+      status->set_stopped (GDB_SIGNAL_TRAP);
       thread = priv->threads[0];
       thread->msg_state = DARWIN_STOPPED;
       return ptid_t (inf->pid, 0, thread->gdb_port);
@@ -1201,14 +1195,14 @@  darwin_nat_target::wait_1 (ptid_t ptid, struct target_waitstatus *status)
 
       if (kret == MACH_RCV_INTERRUPTED)
 	{
-	  status->kind = TARGET_WAITKIND_IGNORE;
+	  status->set_ignore ();
 	  return minus_one_ptid;
 	}
 
       if (kret != MACH_MSG_SUCCESS)
 	{
 	  inferior_debug (5, _("mach_msg: ret=0x%x\n"), kret);
-	  status->kind = TARGET_WAITKIND_SPURIOUS;
+	  status->set_spurious ();
 	  return minus_one_ptid;
 	}
 
@@ -1225,7 +1219,7 @@  darwin_nat_target::wait_1 (ptid_t ptid, struct target_waitstatus *status)
       if (inf == NULL)
 	return res;
     }
-  while (status->kind == TARGET_WAITKIND_IGNORE);
+  while (status->kind () == TARGET_WAITKIND_IGNORE);
 
   /* Stop all tasks.  */
   for (inferior *inf : all_inferiors (this))
@@ -1400,8 +1394,8 @@  darwin_nat_target::stop_inferior (inferior *inf)
   while (1)
     {
       ptid = wait_1 (ptid_t (inf->pid), &wstatus);
-      if (wstatus.kind == TARGET_WAITKIND_STOPPED
-	  && wstatus.value.sig == GDB_SIGNAL_STOP)
+      if (wstatus.kind () == TARGET_WAITKIND_STOPPED
+	  && wstatus.sig () == GDB_SIGNAL_STOP)
 	break;
     }
 }
diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c
index 1323626e3d0..e90aa12e442 100644
--- a/gdb/fbsd-nat.c
+++ b/gdb/fbsd-nat.c
@@ -1181,7 +1181,7 @@  fbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 	}
 #endif
       wptid = inf_ptrace_target::wait (ptid, ourstatus, target_options);
-      if (ourstatus->kind == TARGET_WAITKIND_STOPPED)
+      if (ourstatus->kind () == TARGET_WAITKIND_STOPPED)
 	{
 	  struct ptrace_lwpinfo pl;
 	  pid_t pid;
@@ -1252,7 +1252,7 @@  fbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 					 pl.pl_lwpid);
 		  add_thread (this, wptid);
 		}
-	      ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+	      ourstatus->set_spurious ();
 	      return wptid;
 	    }
 #endif
@@ -1263,14 +1263,14 @@  fbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 #ifndef PTRACE_VFORK
 	      struct kinfo_proc kp;
 #endif
+	      bool is_vfork = false;
 	      ptid_t child_ptid;
 	      pid_t child;
 
 	      child = pl.pl_child_pid;
-	      ourstatus->kind = TARGET_WAITKIND_FORKED;
 #ifdef PTRACE_VFORK
 	      if (pl.pl_flags & PL_FLAG_VFORKED)
-		ourstatus->kind = TARGET_WAITKIND_VFORKED;
+		is_vfork = true;
 #endif
 
 	      /* Make sure the other end of the fork is stopped too.  */
@@ -1299,12 +1299,16 @@  fbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 	      if (fbsd_fetch_kinfo_proc (child, &kp))
 		{
 		  if (kp.ki_flag & P_PPWAIT)
-		    ourstatus->kind = TARGET_WAITKIND_VFORKED;
+		    is_vfork = true;
 		}
 	      else
 		warning (_("Failed to fetch process information"));
 #endif
-	      ourstatus->value.related_pid = child_ptid;
+
+	      if (is_vfork)
+		ourstatus->set_vforked (child_ptid);
+	      else
+		ourstatus->set_forked (child_ptid);
 
 	      return wptid;
 	    }
@@ -1321,7 +1325,7 @@  fbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 #ifdef PTRACE_VFORK
 	  if (pl.pl_flags & PL_FLAG_VFORK_DONE)
 	    {
-	      ourstatus->kind = TARGET_WAITKIND_VFORK_DONE;
+	      ourstatus->set_vfork_done ();
 	      return wptid;
 	    }
 #endif
@@ -1329,9 +1333,8 @@  fbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 
 	  if (pl.pl_flags & PL_FLAG_EXEC)
 	    {
-	      ourstatus->kind = TARGET_WAITKIND_EXECD;
-	      ourstatus->value.execd_pathname
-		= xstrdup (pid_to_exec_file (pid));
+	      ourstatus->set_execd
+		(make_unique_xstrdup (pid_to_exec_file (pid)));
 	      return wptid;
 	    }
 
@@ -1348,7 +1351,7 @@  fbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 	     SIGTRAP, so only treat SIGTRAP events as system call
 	     entry/exit events.  */
 	  if (pl.pl_flags & (PL_FLAG_SCE | PL_FLAG_SCX)
-	      && ourstatus->value.sig == SIGTRAP)
+	      && ourstatus->sig () == SIGTRAP)
 	    {
 #ifdef HAVE_STRUCT_PTRACE_LWPINFO_PL_SYSCALL_CODE
 	      if (catch_syscall_enabled ())
@@ -1356,10 +1359,10 @@  fbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 		  if (catching_syscall_number (pl.pl_syscall_code))
 		    {
 		      if (pl.pl_flags & PL_FLAG_SCE)
-			ourstatus->kind = TARGET_WAITKIND_SYSCALL_ENTRY;
+			ourstatus->set_syscall_entry (pl.pl_syscall_code);
 		      else
-			ourstatus->kind = TARGET_WAITKIND_SYSCALL_RETURN;
-		      ourstatus->value.syscall_number = pl.pl_syscall_code;
+			ourstatus->set_syscall_return (pl.pl_syscall_code);
+
 		      return wptid;
 		    }
 		}
@@ -1490,7 +1493,7 @@  fbsd_nat_target::follow_fork (inferior *child_inf, ptid_t child_ptid,
 	perror_with_name (("ptrace"));
 
 #ifndef PTRACE_VFORK
-      if (fork_kind == TARGET_WAITKIND_VFORKED)
+      if (fork_kind () == TARGET_WAITKIND_VFORKED)
 	{
 	  /* We can't insert breakpoints until the child process has
 	     finished with the shared memory region.  The parent
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 7beccba4272..bd8d1a2952f 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -180,7 +180,7 @@  struct thread_suspend_state
   enum target_stop_reason stop_reason = TARGET_STOPPED_BY_NO_REASON;
 
   /* The waitstatus for this thread's last event.  */
-  struct target_waitstatus waitstatus {};
+  struct target_waitstatus waitstatus;
   /* If true WAITSTATUS hasn't been handled yet.  */
   int waitstatus_pending_p = 0;
 
diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
index 67ce00e9c30..54838347f94 100644
--- a/gdb/gnu-nat.c
+++ b/gdb/gnu-nat.c
@@ -626,13 +626,13 @@  gnu_nat_target::_proc_free (struct proc *proc)
 static struct inf *
 make_inf (void)
 {
-  struct inf *inf = XNEW (struct inf);
+  struct inf *inf = new struct inf;
 
   inf->task = 0;
   inf->threads = 0;
   inf->threads_up_to_date = 0;
   inf->pid = 0;
-  inf->wait.status.kind = TARGET_WAITKIND_SPURIOUS;
+  inf->wait.status.set_spurious ();
   inf->wait.thread = 0;
   inf->wait.exc.handler = MACH_PORT_NULL;
   inf->wait.exc.reply = MACH_PORT_NULL;
@@ -661,7 +661,7 @@  void
 gnu_nat_target::inf_clear_wait (struct inf *inf)
 {
   inf_debug (inf, "clearing wait");
-  inf->wait.status.kind = TARGET_WAITKIND_SPURIOUS;
+  inf->wait.status.set_spurious ();
   inf->wait.thread = 0;
   inf->wait.suppress = 0;
   if (inf->wait.exc.handler != MACH_PORT_NULL)
@@ -1326,8 +1326,8 @@  gnu_nat_target::inf_signal (struct inf *inf, enum gdb_signal sig)
     {
       struct inf_wait *w = &inf->wait;
 
-      if (w->status.kind == TARGET_WAITKIND_STOPPED
-	  && w->status.value.sig == sig
+      if (w->status.kind () == TARGET_WAITKIND_STOPPED
+	  && w->status.sig () == sig
 	  && w->thread && !w->thread->aborted)
 	/* We're passing through the last exception we received.  This is
 	   kind of bogus, because exceptions are per-thread whereas gdb
@@ -1549,7 +1549,7 @@  gnu_nat_target::wait (ptid_t ptid, struct target_waitstatus *status,
     /* We're waiting for the inferior to finish execing.  */
     {
       struct inf_wait *w = &inf->wait;
-      enum target_waitkind kind = w->status.kind;
+      enum target_waitkind kind = w->status.kind ();
 
       if (kind == TARGET_WAITKIND_SPURIOUS)
 	/* Since gdb is actually counting the number of times the inferior
@@ -1560,7 +1560,7 @@  gnu_nat_target::wait (ptid_t ptid, struct target_waitstatus *status,
 	  inf_debug (inf, "pending_execs, ignoring minor event");
 	}
       else if (kind == TARGET_WAITKIND_STOPPED
-	       && w->status.value.sig == GDB_SIGNAL_TRAP)
+	       && w->status.sig () == GDB_SIGNAL_TRAP)
 	/* Ah hah!  A SIGTRAP from the inferior while starting up probably
 	   means we've succesfully completed an exec!  */
 	{
@@ -1585,7 +1585,7 @@  gnu_nat_target::wait (ptid_t ptid, struct target_waitstatus *status,
     }
 
   /* Pass back out our results.  */
-  memcpy (status, &inf->wait.status, sizeof (*status));
+  *status = inf->wait.status;
 
   thread = inf->wait.thread;
   if (thread)
@@ -1608,7 +1608,7 @@  gnu_nat_target::wait (ptid_t ptid, struct target_waitstatus *status,
 
   if (thread
       && ptid != minus_one_ptid
-      && status->kind != TARGET_WAITKIND_SPURIOUS
+      && status->kind () != TARGET_WAITKIND_SPURIOUS
       && inf->pause_sc == 0 && thread->pause_sc == 0)
     /* If something actually happened to THREAD, make sure we
        suspend it.  */
@@ -1658,12 +1658,10 @@  S_exception_raise_request (mach_port_t port, mach_port_t reply_port,
       /* Store away the details; this will destroy any previous info.  */
       inf->wait.thread = thread;
 
-      inf->wait.status.kind = TARGET_WAITKIND_STOPPED;
-
       if (exception == EXC_BREAKPOINT)
 	/* GDB likes to get SIGTRAP for breakpoints.  */
 	{
-	  inf->wait.status.value.sig = GDB_SIGNAL_TRAP;
+	  inf->wait.status.set_stopped (GDB_SIGNAL_TRAP);
 	  mach_port_deallocate (mach_task_self (), reply_port);
 	}
       else
@@ -1696,8 +1694,8 @@  S_exception_raise_request (mach_port_t port, mach_port_t reply_port,
 	  /* Exceptions are encoded in the signal space by putting
 	     them after _NSIG; this assumes they're positive (and not
 	     extremely large)!  */
-	  inf->wait.status.value.sig =
-	    gdb_signal_from_host (_NSIG + exception);
+	  inf->wait.status.set_stopped
+	    (gdb_signal_from_host (_NSIG + exception));
 	}
     }
   else
@@ -1718,8 +1716,7 @@  inf_task_died_status (struct inf *inf)
 {
   warning (_("Pid %d died with unknown exit status, using SIGKILL."),
 	   inf->pid);
-  inf->wait.status.kind = TARGET_WAITKIND_SIGNALLED;
-  inf->wait.status.value.sig = GDB_SIGNAL_KILL;
+  inf->wait.status.set_signalled (GDB_SIGNAL_KILL);
 }
 
 /* Notify server routines.  The only real one is dead name notification.  */
@@ -1825,7 +1822,7 @@  S_proc_wait_reply (mach_port_t reply, kern_return_t err,
   else if (pid == inf->pid)
     {
       store_waitstatus (&inf->wait.status, status);
-      if (inf->wait.status.kind == TARGET_WAITKIND_STOPPED)
+      if (inf->wait.status.kind () == TARGET_WAITKIND_STOPPED)
 	/* The process has sent us a signal, and stopped itself in a sane
 	   state pending our actions.  */
 	{
@@ -1915,10 +1912,7 @@  S_msg_sig_post_untraced_reply (mach_port_t reply, kern_return_t err)
        like the process stopped (using a signal of 0 should mean that the
        *next* time the user continues, it will pass signal 0, which the crash
        server should like).  */
-    {
-      inf->wait.status.kind = TARGET_WAITKIND_STOPPED;
-      inf->wait.status.value.sig = GDB_SIGNAL_0;
-    }
+    inf->wait.status.set_stopped (GDB_SIGNAL_0);
   else if (err)
     warning (_("Signal delivery failed: %s"), safe_strerror (err));
 
@@ -1994,7 +1988,7 @@  gnu_nat_target::resume (ptid_t ptid, int step, enum gdb_signal sig)
       proc_abort (inf->wait.thread, 1);
       warning (_("Aborting %s with unforwarded exception %s."),
 	       proc_string (inf->wait.thread),
-	       gdb_signal_to_name (inf->wait.status.value.sig));
+	       gdb_signal_to_name (inf->wait.status.sig ()));
     }
 
   if (port_msgs_queued (inf->event_port))
diff --git a/gdb/go32-nat.c b/gdb/go32-nat.c
index 093ed9e792e..528cb761c81 100644
--- a/gdb/go32-nat.c
+++ b/gdb/go32-nat.c
@@ -511,24 +511,20 @@  go32_nat_target::wait (ptid_t ptid, struct target_waitstatus *status,
     chdir (current_directory);
 
   if (a_tss.tss_irqn == 0x21)
-    {
-      status->kind = TARGET_WAITKIND_EXITED;
-      status->value.integer = a_tss.tss_eax & 0xff;
-    }
+    status->set_exited (a_tss.tss_eax & 0xff);
   else
     {
-      status->value.sig = GDB_SIGNAL_UNKNOWN;
-      status->kind = TARGET_WAITKIND_STOPPED;
+      status->set_stopped (GDB_SIGNAL_UNKNOWN);
       for (i = 0; sig_map[i].go32_sig != -1; i++)
 	{
 	  if (a_tss.tss_irqn == sig_map[i].go32_sig)
 	    {
 #if __DJGPP_MINOR__ < 3
-	      if ((status->value.sig = sig_map[i].gdb_sig) !=
-		  GDB_SIGNAL_TRAP)
-		status->kind = TARGET_WAITKIND_SIGNALLED;
+	      status->set_stopped (sig_map[i].gdb_sig);
+	      if (status->sig () != GDB_SIGNAL_TRAP)
+		status->set_signalled (status->sig ());
 #else
-	      status->value.sig = sig_map[i].gdb_sig;
+	      status->set_stopped (sig_map[i].gdb_sig);
 #endif
 	      break;
 	    }
diff --git a/gdb/inf-child.c b/gdb/inf-child.c
index 5084f448c1e..5e821f45598 100644
--- a/gdb/inf-child.c
+++ b/gdb/inf-child.c
@@ -58,20 +58,11 @@  void
 store_waitstatus (struct target_waitstatus *ourstatus, int hoststatus)
 {
   if (WIFEXITED (hoststatus))
-    {
-      ourstatus->kind = TARGET_WAITKIND_EXITED;
-      ourstatus->value.integer = WEXITSTATUS (hoststatus);
-    }
+    ourstatus->set_exited (WEXITSTATUS (hoststatus));
   else if (!WIFSTOPPED (hoststatus))
-    {
-      ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
-      ourstatus->value.sig = gdb_signal_from_host (WTERMSIG (hoststatus));
-    }
+    ourstatus->set_signalled (gdb_signal_from_host (WTERMSIG (hoststatus)));
   else
-    {
-      ourstatus->kind = TARGET_WAITKIND_STOPPED;
-      ourstatus->value.sig = gdb_signal_from_host (WSTOPSIG (hoststatus));
-    }
+    ourstatus->set_stopped (gdb_signal_from_host (WSTOPSIG (hoststatus)));
 }
 
 inf_child_target::~inf_child_target ()
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index afa38de6ef7..852636ba646 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -324,8 +324,7 @@  inf_ptrace_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 			      safe_strerror (save_errno));
 
 	  /* Claim it exited with unknown signal.  */
-	  ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
-	  ourstatus->value.sig = GDB_SIGNAL_UNKNOWN;
+	  ourstatus->set_signalled (GDB_SIGNAL_UNKNOWN);
 	  return inferior_ptid;
 	}
 
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index b55a56c020d..6d3a8b09beb 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -482,8 +482,7 @@  run_command_1 (const char *args, int from_tty, enum run_how run_how)
     {
       thread_info *thr = inferior_thread ();
       target_waitstatus ws;
-      ws.kind = TARGET_WAITKIND_STOPPED;
-      ws.value.sig = GDB_SIGNAL_0;
+      ws.set_stopped (GDB_SIGNAL_0);
       thr->set_pending_waitstatus (ws);
     }
 
diff --git a/gdb/infrun.c b/gdb/infrun.c
index af552e0090b..d97d469e112 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -404,12 +404,12 @@  show_follow_fork_mode_string (struct ui_file *file, int from_tty,
 static bool
 follow_fork_inferior (bool follow_child, bool detach_fork)
 {
-  target_waitkind fork_kind = inferior_thread ()->pending_follow.kind;
+  target_waitkind fork_kind = inferior_thread ()->pending_follow.kind ();
   gdb_assert (fork_kind == TARGET_WAITKIND_FORKED
 	      || fork_kind == TARGET_WAITKIND_VFORKED);
   bool has_vforked = fork_kind == TARGET_WAITKIND_VFORKED;
   ptid_t parent_ptid = inferior_ptid;
-  ptid_t child_ptid = inferior_thread ()->pending_follow.value.related_pid;
+  ptid_t child_ptid = inferior_thread ()->pending_follow.child_ptid ();
 
   if (has_vforked
       && !non_stop /* Non-stop always resumes both branches.  */
@@ -697,8 +697,8 @@  follow_fork ()
 
       /* If not stopped at a fork event, then there's nothing else to
 	 do.  */
-      if (wait_status.kind != TARGET_WAITKIND_FORKED
-	  && wait_status.kind != TARGET_WAITKIND_VFORKED)
+      if (wait_status.kind () != TARGET_WAITKIND_FORKED
+	  && wait_status.kind () != TARGET_WAITKIND_VFORKED)
 	return 1;
 
       /* Check if we switched over from WAIT_PTID, since the event was
@@ -721,7 +721,7 @@  follow_fork ()
 
   /* If there were any forks/vforks that were caught and are now to be
      followed, then do so now.  */
-  switch (tp->pending_follow.kind)
+  switch (tp->pending_follow.kind ())
     {
     case TARGET_WAITKIND_FORKED:
     case TARGET_WAITKIND_VFORKED:
@@ -757,7 +757,7 @@  follow_fork ()
 	  }
 
 	parent = inferior_ptid;
-	child = tp->pending_follow.value.related_pid;
+	child = tp->pending_follow.child_ptid ();
 
 	process_stratum_target *parent_targ = tp->inf->process_target ();
 	/* Set up inferior(s) as specified by the caller, and tell the
@@ -777,7 +777,7 @@  follow_fork ()
 	       to clear the pending follow request.  */
 	    tp = find_thread_ptid (parent_targ, parent);
 	    if (tp)
-	      tp->pending_follow.kind = TARGET_WAITKIND_SPURIOUS;
+	      tp->pending_follow.set_spurious ();
 
 	    /* This makes sure we don't try to apply the "Switched
 	       over from WAIT_PID" logic above.  */
@@ -829,7 +829,7 @@  follow_fork ()
     default:
       internal_error (__FILE__, __LINE__,
 		      "Unexpected pending_follow.kind %d\n",
-		      tp->pending_follow.kind);
+		      tp->pending_follow.kind ());
       break;
     }
 
@@ -1785,6 +1785,25 @@  displaced_step_finish (thread_info *event_thread, enum gdb_signal signal)
    discarded between events.  */
 struct execution_control_state
 {
+  execution_control_state ()
+  {
+    this->reset ();
+  }
+
+  void reset ()
+  {
+    this->target = nullptr;
+    this->ptid = null_ptid;
+    this->event_thread = nullptr;
+    ws = target_waitstatus ();
+    stop_func_filled_in = 0;
+    stop_func_start = 0;
+    stop_func_end = 0;
+    stop_func_name = nullptr;
+    wait_some_more = 0;
+    hit_singlestep_breakpoint = 0;
+  }
+
   process_stratum_target *target;
   ptid_t ptid;
   /* The thread that got the event, if this was a thread event; NULL
@@ -1810,7 +1829,7 @@  struct execution_control_state
 static void
 reset_ecs (struct execution_control_state *ecs, struct thread_info *tp)
 {
-  memset (ecs, 0, sizeof (*ecs));
+  ecs->reset ();
   ecs->event_thread = tp;
   ecs->ptid = tp->ptid;
 }
@@ -3367,8 +3386,7 @@  infrun_thread_stop_requested (ptid_t ptid)
       if (!tp->has_pending_waitstatus ())
 	{
 	  target_waitstatus ws;
-	  ws.kind = TARGET_WAITKIND_STOPPED;
-	  ws.value.sig = GDB_SIGNAL_0;
+	  ws.set_stopped (GDB_SIGNAL_0);
 	  tp->set_pending_waitstatus (ws);
 	}
 
@@ -3562,7 +3580,7 @@  do_target_wait_1 (inferior *inf, ptid_t ptid,
 
 	  tp->clear_pending_waitstatus ();
 	  target_waitstatus ws;
-	  ws.kind = TARGET_WAITKIND_SPURIOUS;
+	  ws.set_spurious ();
 	  tp->set_pending_waitstatus (ws);
 	  tp->set_stop_reason (TARGET_STOPPED_BY_NO_REASON);
 	}
@@ -3651,7 +3669,7 @@  do_target_wait (execution_control_state *ecs, target_wait_flags options)
 
   if (num_inferiors == 0)
     {
-      ecs->ws.kind = TARGET_WAITKIND_IGNORE;
+      ecs->ws.set_ignore ();
       return false;
     }
 
@@ -3682,7 +3700,7 @@  do_target_wait (execution_control_state *ecs, target_wait_flags options)
   {
     ecs->ptid = do_target_wait_1 (inf, minus_one_ptid, &ecs->ws, options);
     ecs->target = inf->process_target ();
-    return (ecs->ws.kind != TARGET_WAITKIND_IGNORE);
+    return (ecs->ws.kind () != TARGET_WAITKIND_IGNORE);
   };
 
   /* Needed in 'all-stop + target-non-stop' mode, because we end up
@@ -3713,7 +3731,7 @@  do_target_wait (execution_control_state *ecs, target_wait_flags options)
 	return true;
     }
 
-  ecs->ws.kind = TARGET_WAITKIND_IGNORE;
+  ecs->ws.set_ignore ();
   return false;
 }
 
@@ -3856,8 +3874,6 @@  wait_for_inferior (inferior *inf)
       struct execution_control_state ecss;
       struct execution_control_state *ecs = &ecss;
 
-      memset (ecs, 0, sizeof (*ecs));
-
       overlay_cache_invalid = 1;
 
       /* Flush target cache before starting to handle each event.
@@ -3999,8 +4015,6 @@  fetch_inferior_event ()
   struct execution_control_state *ecs = &ecss;
   int cmd_done = 0;
 
-  memset (ecs, 0, sizeof (*ecs));
-
   /* Events are always processed with the main UI as current UI.  This
      way, warnings, debug output, etc. are always consistently sent to
      the main console.  */
@@ -4055,7 +4069,7 @@  fetch_inferior_event ()
 	return;
       }
 
-    gdb_assert (ecs->ws.kind != TARGET_WAITKIND_IGNORE);
+    gdb_assert (ecs->ws.kind () != TARGET_WAITKIND_IGNORE);
 
     /* Switch to the target that generated the event, so we can do
        target calls.  */
@@ -4133,7 +4147,7 @@  fetch_inferior_event ()
 	       selected.".  */
 	    if (!non_stop
 		&& cmd_done
-		&& ecs->ws.kind != TARGET_WAITKIND_NO_RESUMED)
+		&& ecs->ws.kind () != TARGET_WAITKIND_NO_RESUMED)
 	      restore_thread.dont_restore ();
 	  }
       }
@@ -4194,7 +4208,7 @@  init_thread_stepping_state (struct thread_info *tss)
 
 void
 set_last_target_status (process_stratum_target *target, ptid_t ptid,
-			target_waitstatus status)
+			const target_waitstatus &status)
 {
   target_last_proc_target = target;
   target_last_wait_ptid = ptid;
@@ -4276,10 +4290,10 @@  adjust_pc_after_break (struct thread_info *thread,
      target with both of these set in GDB history, and it seems unlikely to be
      correct, so gdbarch_have_nonsteppable_watchpoint is not checked here.  */
 
-  if (ws->kind != TARGET_WAITKIND_STOPPED)
+  if (ws->kind () != TARGET_WAITKIND_STOPPED)
     return;
 
-  if (ws->value.sig != GDB_SIGNAL_TRAP)
+  if (ws->sig () != GDB_SIGNAL_TRAP)
     return;
 
   /* In reverse execution, when a breakpoint is hit, the instruction
@@ -4454,8 +4468,7 @@  handle_stop_requested (struct execution_control_state *ecs)
 {
   if (ecs->event_thread->stop_requested)
     {
-      ecs->ws.kind = TARGET_WAITKIND_STOPPED;
-      ecs->ws.value.sig = GDB_SIGNAL_0;
+      ecs->ws.set_stopped (GDB_SIGNAL_0);
       handle_signal_stop (ecs);
       return true;
     }
@@ -4476,7 +4489,7 @@  handle_syscall_event (struct execution_control_state *ecs)
   context_switch (ecs);
 
   regcache = get_thread_regcache (ecs->event_thread);
-  syscall_number = ecs->ws.value.syscall_number;
+  syscall_number = ecs->ws.syscall_number ();
   ecs->event_thread->set_stop_pc (regcache_read_pc (regcache));
 
   if (catch_syscall_enabled () > 0
@@ -4612,13 +4625,13 @@  wait_one ()
 	  event.target = target;
 	  event.ptid = poll_one_curr_target (&event.ws);
 
-	  if (event.ws.kind == TARGET_WAITKIND_NO_RESUMED)
+	  if (event.ws.kind () == TARGET_WAITKIND_NO_RESUMED)
 	    {
 	      /* If nothing is resumed, remove the target from the
 		 event loop.  */
 	      target_async (0);
 	    }
-	  else if (event.ws.kind != TARGET_WAITKIND_IGNORE)
+	  else if (event.ws.kind () != TARGET_WAITKIND_IGNORE)
 	    return event;
 	}
 
@@ -4646,7 +4659,9 @@  wait_one ()
       if (nfds == 0)
 	{
 	  /* No waitable targets left.  All must be stopped.  */
-	  return {NULL, minus_one_ptid, {TARGET_WAITKIND_NO_RESUMED}};
+	  target_waitstatus ws;
+	  ws.set_no_resumed ();
+	  return {NULL, minus_one_ptid, std::move (ws)};
 	}
 
       QUIT;
@@ -4674,8 +4689,8 @@  save_waitstatus (struct thread_info *tp, const target_waitstatus *ws)
   /* Record for later.  */
   tp->set_pending_waitstatus (*ws);
 
-  if (ws->kind == TARGET_WAITKIND_STOPPED
-      && ws->value.sig == GDB_SIGNAL_TRAP)
+  if (ws->kind () == TARGET_WAITKIND_STOPPED
+      && ws->sig () == GDB_SIGNAL_TRAP)
     {
       struct regcache *regcache = get_thread_regcache (tp);
       const address_space *aspace = regcache->aspace ();
@@ -4713,14 +4728,14 @@  save_waitstatus (struct thread_info *tp, const target_waitstatus *ws)
 static void
 mark_non_executing_threads (process_stratum_target *target,
 			    ptid_t event_ptid,
-			    struct target_waitstatus ws)
+			    const target_waitstatus &ws)
 {
   ptid_t mark_ptid;
 
   if (!target_is_non_stop_p ())
     mark_ptid = minus_one_ptid;
-  else if (ws.kind == TARGET_WAITKIND_SIGNALLED
-	   || ws.kind == TARGET_WAITKIND_EXITED)
+  else if (ws.kind () == TARGET_WAITKIND_SIGNALLED
+	   || ws.kind () == TARGET_WAITKIND_EXITED)
     {
       /* If we're handling a process exit in non-stop mode, even
 	 though threads haven't been deleted yet, one would think
@@ -4762,14 +4777,14 @@  handle_one (const wait_one_event &event)
     ("%s %s", target_waitstatus_to_string (&event.ws).c_str (),
      target_pid_to_str (event.ptid).c_str ());
 
-  if (event.ws.kind == TARGET_WAITKIND_NO_RESUMED)
+  if (event.ws.kind () == TARGET_WAITKIND_NO_RESUMED)
     {
       /* All resumed threads exited.  */
       return true;
     }
-  else if (event.ws.kind == TARGET_WAITKIND_THREAD_EXITED
-	   || event.ws.kind == TARGET_WAITKIND_EXITED
-	   || event.ws.kind == TARGET_WAITKIND_SIGNALLED)
+  else if (event.ws.kind () == TARGET_WAITKIND_THREAD_EXITED
+	   || event.ws.kind () == TARGET_WAITKIND_EXITED
+	   || event.ws.kind () == TARGET_WAITKIND_SIGNALLED)
     {
       /* One thread/process exited/signalled.  */
 
@@ -4804,7 +4819,7 @@  handle_one (const wait_one_event &event)
 	  /* Check if this is the first time we see this thread.
 	     Don't bother adding if it individually exited.  */
 	  if (t == nullptr
-	      && event.ws.kind != TARGET_WAITKIND_THREAD_EXITED)
+	      && event.ws.kind () != TARGET_WAITKIND_THREAD_EXITED)
 	    t = add_thread (event.target, event.ptid);
 	}
 
@@ -4839,8 +4854,8 @@  handle_one (const wait_one_event &event)
 	  setup_inferior (0);
 	}
 
-      if (event.ws.kind == TARGET_WAITKIND_STOPPED
-	  && event.ws.value.sig == GDB_SIGNAL_0)
+      if (event.ws.kind () == TARGET_WAITKIND_STOPPED
+	  && event.ws.sig () == GDB_SIGNAL_0)
 	{
 	  /* We caught the event that we intended to catch, so
 	     there's no event to save as pending.  */
@@ -4871,8 +4886,8 @@  handle_one (const wait_one_event &event)
 	  /* Record for later.  */
 	  save_waitstatus (t, &event.ws);
 
-	  sig = (event.ws.kind == TARGET_WAITKIND_STOPPED
-		 ? event.ws.value.sig : GDB_SIGNAL_0);
+	  sig = (event.ws.kind () == TARGET_WAITKIND_STOPPED
+		 ? event.ws.sig () : GDB_SIGNAL_0);
 
 	  if (displaced_step_finish (t, sig)
 	      == DISPLACED_STEP_FINISH_STATUS_NOT_EXECUTED)
@@ -5174,7 +5189,7 @@  handle_inferior_event (struct execution_control_state *ecs)
 
   infrun_debug_printf ("%s", target_waitstatus_to_string (&ecs->ws).c_str ());
 
-  if (ecs->ws.kind == TARGET_WAITKIND_IGNORE)
+  if (ecs->ws.kind () == TARGET_WAITKIND_IGNORE)
     {
       /* We had an event in the inferior, but we are not interested in
 	 handling it at this level.  The lower layers have already
@@ -5189,13 +5204,13 @@  handle_inferior_event (struct execution_control_state *ecs)
       return;
     }
 
-  if (ecs->ws.kind == TARGET_WAITKIND_THREAD_EXITED)
+  if (ecs->ws.kind () == TARGET_WAITKIND_THREAD_EXITED)
     {
       prepare_to_wait (ecs);
       return;
     }
 
-  if (ecs->ws.kind == TARGET_WAITKIND_NO_RESUMED
+  if (ecs->ws.kind () == TARGET_WAITKIND_NO_RESUMED
       && handle_no_resumed (ecs))
     return;
 
@@ -5205,7 +5220,7 @@  handle_inferior_event (struct execution_control_state *ecs)
   /* Always clear state belonging to the previous time we stopped.  */
   stop_stack_dummy = STOP_NONE;
 
-  if (ecs->ws.kind == TARGET_WAITKIND_NO_RESUMED)
+  if (ecs->ws.kind () == TARGET_WAITKIND_NO_RESUMED)
     {
       /* No unwaited-for children left.  IOW, all resumed children
 	 have exited.  */
@@ -5214,8 +5229,8 @@  handle_inferior_event (struct execution_control_state *ecs)
       return;
     }
 
-  if (ecs->ws.kind != TARGET_WAITKIND_EXITED
-      && ecs->ws.kind != TARGET_WAITKIND_SIGNALLED)
+  if (ecs->ws.kind () != TARGET_WAITKIND_EXITED
+      && ecs->ws.kind () != TARGET_WAITKIND_SIGNALLED)
     {
       ecs->event_thread = find_thread_ptid (ecs->target, ecs->ptid);
       /* If it's a new thread, add it to the thread database.  */
@@ -5245,10 +5260,10 @@  handle_inferior_event (struct execution_control_state *ecs)
      non-executable stack.  This happens for call dummy breakpoints
      for architectures like SPARC that place call dummies on the
      stack.  */
-  if (ecs->ws.kind == TARGET_WAITKIND_STOPPED
-      && (ecs->ws.value.sig == GDB_SIGNAL_ILL
-	  || ecs->ws.value.sig == GDB_SIGNAL_SEGV
-	  || ecs->ws.value.sig == GDB_SIGNAL_EMT))
+  if (ecs->ws.kind () == TARGET_WAITKIND_STOPPED
+      && (ecs->ws.sig () == GDB_SIGNAL_ILL
+	  || ecs->ws.sig () == GDB_SIGNAL_SEGV
+	  || ecs->ws.sig () == GDB_SIGNAL_EMT))
     {
       struct regcache *regcache = get_thread_regcache (ecs->event_thread);
 
@@ -5256,13 +5271,13 @@  handle_inferior_event (struct execution_control_state *ecs)
 				      regcache_read_pc (regcache)))
 	{
 	  infrun_debug_printf ("Treating signal as SIGTRAP");
-	  ecs->ws.value.sig = GDB_SIGNAL_TRAP;
+	  ecs->ws.set_stopped (GDB_SIGNAL_TRAP);
 	}
     }
 
   mark_non_executing_threads (ecs->target, ecs->ptid, ecs->ws);
 
-  switch (ecs->ws.kind)
+  switch (ecs->ws.kind ())
     {
     case TARGET_WAITKIND_LOADED:
       {
@@ -5382,21 +5397,21 @@  handle_inferior_event (struct execution_control_state *ecs)
       /* Clearing any previous state of convenience variables.  */
       clear_exit_convenience_vars ();
 
-      if (ecs->ws.kind == TARGET_WAITKIND_EXITED)
+      if (ecs->ws.kind () == TARGET_WAITKIND_EXITED)
 	{
 	  /* Record the exit code in the convenience variable $_exitcode, so
 	     that the user can inspect this again later.  */
 	  set_internalvar_integer (lookup_internalvar ("_exitcode"),
-				   (LONGEST) ecs->ws.value.integer);
+				   (LONGEST) ecs->ws.exit_status ());
 
 	  /* Also record this in the inferior itself.  */
 	  current_inferior ()->has_exit_code = 1;
-	  current_inferior ()->exit_code = (LONGEST) ecs->ws.value.integer;
+	  current_inferior ()->exit_code = (LONGEST) ecs->ws.exit_status ();
 
 	  /* Support the --return-child-result option.  */
-	  return_child_result_value = ecs->ws.value.integer;
+	  return_child_result_value = ecs->ws.exit_status ();
 
-	  gdb::observers::exited.notify (ecs->ws.value.integer);
+	  gdb::observers::exited.notify (ecs->ws.exit_status ());
 	}
       else
 	{
@@ -5408,7 +5423,7 @@  handle_inferior_event (struct execution_control_state *ecs)
 		 which holds the signal uncaught by the inferior.  */
 	      set_internalvar_integer (lookup_internalvar ("_exitsignal"),
 				       gdbarch_gdb_signal_to_target (gdbarch,
-							  ecs->ws.value.sig));
+							  ecs->ws.sig ()));
 	    }
 	  else
 	    {
@@ -5423,7 +5438,7 @@  handle_inferior_event (struct execution_control_state *ecs)
 				   "signal number.");
 	    }
 
-	  gdb::observers::signal_exited.notify (ecs->ws.value.sig);
+	  gdb::observers::signal_exited.notify (ecs->ws.sig ());
 	}
 
       gdb_flush (gdb_stdout);
@@ -5450,10 +5465,10 @@  handle_inferior_event (struct execution_control_state *ecs)
 	   gdbarch_displaced_step_restore_all_in_ptid.  This is not
 	   enforced during gdbarch validation to support architectures
 	   which support displaced stepping but not forks.  */
-	if (ecs->ws.kind == TARGET_WAITKIND_FORKED
+	if (ecs->ws.kind () == TARGET_WAITKIND_FORKED
 	    && gdbarch_supports_displaced_stepping (gdbarch))
 	  gdbarch_displaced_step_restore_all_in_ptid
-	    (gdbarch, parent_inf, ecs->ws.value.related_pid);
+	    (gdbarch, parent_inf, ecs->ws.child_ptid ());
 
 	/* If displaced stepping is supported, and thread ecs->ptid is
 	   displaced stepping.  */
@@ -5481,7 +5496,7 @@  handle_inferior_event (struct execution_control_state *ecs)
 
 	    child_regcache
 	      = get_thread_arch_aspace_regcache (parent_inf->process_target (),
-						 ecs->ws.value.related_pid,
+						 ecs->ws.child_ptid (),
 						 gdbarch,
 						 parent_inf->aspace);
 	    /* Read PC value of parent process.  */
@@ -5510,11 +5525,11 @@  handle_inferior_event (struct execution_control_state *ecs)
 	 need to unpatch at follow/detach time instead to be certain
 	 that new breakpoints added between catchpoint hit time and
 	 vfork follow are detached.  */
-      if (ecs->ws.kind != TARGET_WAITKIND_VFORKED)
+      if (ecs->ws.kind () != TARGET_WAITKIND_VFORKED)
 	{
 	  /* This won't actually modify the breakpoint list, but will
 	     physically remove the breakpoints from the child.  */
-	  detach_breakpoints (ecs->ws.value.related_pid);
+	  detach_breakpoints (ecs->ws.child_ptid ());
 	}
 
       delete_just_stopped_threads_single_step_breakpoints ();
@@ -5554,8 +5569,7 @@  handle_inferior_event (struct execution_control_state *ecs)
 	  /* Note that one of these may be an invalid pointer,
 	     depending on detach_fork.  */
 	  thread_info *parent = ecs->event_thread;
-	  thread_info *child
-	    = find_thread_ptid (targ, ecs->ws.value.related_pid);
+	  thread_info *child = find_thread_ptid (targ, ecs->ws.child_ptid ());
 
 	  /* At this point, the parent is marked running, and the
 	     child is marked stopped.  */
@@ -5629,7 +5643,7 @@  handle_inferior_event (struct execution_control_state *ecs)
       /* This causes the eventpoints and symbol table to be reset.
 	 Must do this now, before trying to determine whether to
 	 stop.  */
-      follow_exec (inferior_ptid, ecs->ws.value.execd_pathname);
+      follow_exec (inferior_ptid, ecs->ws.execd_pathname ());
 
       /* In follow_exec we may have deleted the original thread and
 	 created a new one.  Make sure that the event thread is the
@@ -5644,11 +5658,6 @@  handle_inferior_event (struct execution_control_state *ecs)
 			      ecs->event_thread->stop_pc (),
 			      ecs->event_thread, &ecs->ws);
 
-      /* Note that this may be referenced from inside
-	 bpstat_stop_status above, through inferior_has_execd.  */
-      xfree (ecs->ws.value.execd_pathname);
-      ecs->ws.value.execd_pathname = NULL;
-
       if (handle_stop_requested (ecs))
 	return;
 
@@ -5928,9 +5937,9 @@  handle_signal_stop (struct execution_control_state *ecs)
   enum stop_kind stop_soon;
   int random_signal;
 
-  gdb_assert (ecs->ws.kind == TARGET_WAITKIND_STOPPED);
+  gdb_assert (ecs->ws.kind () == TARGET_WAITKIND_STOPPED);
 
-  ecs->event_thread->set_stop_signal (ecs->ws.value.sig);
+  ecs->event_thread->set_stop_signal (ecs->ws.sig ());
 
   /* Do we need to clean up the state of a thread that has
      completed a displaced single-step?  (Doing so usually affects
@@ -8265,7 +8274,7 @@  print_stop_location (struct target_waitstatus *ws)
   int do_frame_printing = 1;
   struct thread_info *tp = inferior_thread ();
 
-  bpstat_ret = bpstat_print (tp->control.stop_bpstat, ws->kind);
+  bpstat_ret = bpstat_print (tp->control.stop_bpstat, ws->kind ());
   switch (bpstat_ret)
     {
     case PRINT_UNKNOWN:
@@ -8440,8 +8449,8 @@  normal_stop (void)
 
   if (!non_stop)
     finish_ptid = minus_one_ptid;
-  else if (last.kind == TARGET_WAITKIND_SIGNALLED
-	   || last.kind == TARGET_WAITKIND_EXITED)
+  else if (last.kind () == TARGET_WAITKIND_SIGNALLED
+	   || last.kind () == TARGET_WAITKIND_EXITED)
     {
       /* On some targets, we may still have live threads in the
 	 inferior when we get a process exit event.  E.g., for
@@ -8451,7 +8460,7 @@  normal_stop (void)
       if (inferior_ptid != null_ptid)
 	finish_ptid = ptid_t (inferior_ptid.pid ());
     }
-  else if (last.kind != TARGET_WAITKIND_NO_RESUMED)
+  else if (last.kind () != TARGET_WAITKIND_NO_RESUMED)
     finish_ptid = inferior_ptid;
 
   gdb::optional<scoped_finish_thread_state> maybe_finish_thread_state;
@@ -8471,7 +8480,7 @@  normal_stop (void)
      instead of after.  */
   update_thread_list ();
 
-  if (last.kind == TARGET_WAITKIND_STOPPED && stopped_by_random_signal)
+  if (last.kind () == TARGET_WAITKIND_STOPPED && stopped_by_random_signal)
     gdb::observers::signal_received.notify (inferior_thread ()->stop_signal ());
 
   /* As with the notification of thread events, we want to delay
@@ -8493,9 +8502,9 @@  normal_stop (void)
   if (!non_stop
       && previous_inferior_ptid != inferior_ptid
       && target_has_execution ()
-      && last.kind != TARGET_WAITKIND_SIGNALLED
-      && last.kind != TARGET_WAITKIND_EXITED
-      && last.kind != TARGET_WAITKIND_NO_RESUMED)
+      && last.kind () != TARGET_WAITKIND_SIGNALLED
+      && last.kind () != TARGET_WAITKIND_EXITED
+      && last.kind () != TARGET_WAITKIND_NO_RESUMED)
     {
       SWITCH_THRU_ALL_UIS ()
 	{
@@ -8507,7 +8516,7 @@  normal_stop (void)
       previous_inferior_ptid = inferior_ptid;
     }
 
-  if (last.kind == TARGET_WAITKIND_NO_RESUMED)
+  if (last.kind () == TARGET_WAITKIND_NO_RESUMED)
     {
       SWITCH_THRU_ALL_UIS ()
 	if (current_ui->prompt_state == PROMPT_BLOCKED)
@@ -8599,9 +8608,9 @@  normal_stop (void)
 
   if (target_has_execution ())
     {
-      if (last.kind != TARGET_WAITKIND_SIGNALLED
-	  && last.kind != TARGET_WAITKIND_EXITED
-	  && last.kind != TARGET_WAITKIND_NO_RESUMED)
+      if (last.kind () != TARGET_WAITKIND_SIGNALLED
+	  && last.kind () != TARGET_WAITKIND_EXITED
+	  && last.kind () != TARGET_WAITKIND_NO_RESUMED)
 	/* Delete the breakpoint we stopped at, if it wants to be deleted.
 	   Delete any breakpoint that is to be deleted at the next stop.  */
 	breakpoint_auto_delete (inferior_thread ()->control.stop_bpstat);
diff --git a/gdb/infrun.h b/gdb/infrun.h
index 5a577365f94..c5f98d9d305 100644
--- a/gdb/infrun.h
+++ b/gdb/infrun.h
@@ -133,7 +133,7 @@  extern void get_last_target_status (process_stratum_target **target,
 
 /* Set the cached copy of the last target/ptid/waitstatus.  */
 extern void set_last_target_status (process_stratum_target *target, ptid_t ptid,
-				    struct target_waitstatus status);
+				    const target_waitstatus &status);
 
 /* Clear the cached copy of the last ptid/waitstatus returned by
    target_wait().  */
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 6f50ea39142..cada889c534 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -575,7 +575,7 @@  linux_nat_target::follow_fork (inferior *child_inf, ptid_t child_ptid,
 		 will notice a pending event, and bypasses actually
 		 resuming the inferior.  */
 	      parent_lp->status = 0;
-	      parent_lp->waitstatus.kind = TARGET_WAITKIND_VFORK_DONE;
+	      parent_lp->waitstatus.set_vfork_done ();
 	      parent_lp->stopped = 1;
 
 	      /* If we're in async mode, need to tell the event loop
@@ -1257,7 +1257,7 @@  get_detach_signal (struct lwp_info *lp)
      signal pass state).  Normally SIGTRAP isn't set to pass state, so
      this is really a corner case.  */
 
-  if (lp->waitstatus.kind != TARGET_WAITKIND_IGNORE)
+  if (lp->waitstatus.kind () != TARGET_WAITKIND_IGNORE)
     signo = GDB_SIGNAL_0; /* a pending ptrace event, not a real signal.  */
   else if (lp->status)
     signo = gdb_signal_from_host (WSTOPSIG (lp->status));
@@ -1268,7 +1268,7 @@  get_detach_signal (struct lwp_info *lp)
       if (target_is_non_stop_p () && !tp->executing ())
 	{
 	  if (tp->has_pending_waitstatus ())
-	    signo = tp->pending_waitstatus ().value.sig;
+	    signo = tp->pending_waitstatus ().sig ();
 	  else
 	    signo = tp->stop_signal ();
 	}
@@ -1520,7 +1520,7 @@  check_ptrace_stopped_lwp_gone (struct lwp_info *lp)
     {
       lp->stop_reason = TARGET_STOPPED_BY_NO_REASON;
       lp->status = 0;
-      lp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
+      lp->waitstatus.set_ignore ();
       return 1;
     }
   return 0;
@@ -1793,8 +1793,12 @@  linux_handle_syscall_trap (struct lwp_info *lp, int stopping)
       if (catching_syscall_number (syscall_number))
 	{
 	  /* Alright, an event to report.  */
-	  ourstatus->kind = lp->syscall_state;
-	  ourstatus->value.syscall_number = syscall_number;
+	  if (lp->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY)
+	    ourstatus->set_syscall_entry (syscall_number);
+	  else if (lp->syscall_state == TARGET_WAITKIND_SYSCALL_RETURN)
+	    ourstatus->set_syscall_return (syscall_number);
+	  else
+	    gdb_assert_not_reached ("unexpected syscall state");
 
 	  linux_nat_debug_printf
 	    ("stopping for %s of syscall %d for LWP %ld",
@@ -1886,7 +1890,7 @@  linux_handle_extended_wait (struct lwp_info *lp, int status)
 			    _("wait returned unexpected status 0x%x"), status);
 	}
 
-      ourstatus->value.related_pid = ptid_t (new_pid, new_pid);
+      ptid_t child_ptid (new_pid, new_pid);
 
       if (event == PTRACE_EVENT_FORK || event == PTRACE_EVENT_VFORK)
 	{
@@ -1918,21 +1922,21 @@  linux_handle_extended_wait (struct lwp_info *lp, int status)
 	  /* Report as spurious, so that infrun doesn't want to follow
 	     this fork.  We're actually doing an infcall in
 	     linux-fork.c.  */
-	  ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+	  ourstatus->set_spurious ();
 
 	  /* Report the stop to the core.  */
 	  return 0;
 	}
 
       if (event == PTRACE_EVENT_FORK)
-	ourstatus->kind = TARGET_WAITKIND_FORKED;
+	ourstatus->set_forked (child_ptid);
       else if (event == PTRACE_EVENT_VFORK)
-	ourstatus->kind = TARGET_WAITKIND_VFORKED;
+	ourstatus->set_vforked (child_ptid);
       else if (event == PTRACE_EVENT_CLONE)
 	{
 	  struct lwp_info *new_lp;
 
-	  ourstatus->kind = TARGET_WAITKIND_IGNORE;
+	  ourstatus->set_ignore ();
 
 	  linux_nat_debug_printf
 	    ("Got clone event from LWP %d, new child is LWP %ld", pid, new_pid);
@@ -1981,7 +1985,7 @@  linux_handle_extended_wait (struct lwp_info *lp, int status)
 	    }
 	  else if (report_thread_events)
 	    {
-	      new_lp->waitstatus.kind = TARGET_WAITKIND_THREAD_CREATED;
+	      new_lp->waitstatus.set_thread_created ();
 	      new_lp->status = status;
 	    }
 
@@ -1999,9 +2003,8 @@  linux_handle_extended_wait (struct lwp_info *lp, int status)
 	 inferior.  */
       maybe_close_proc_mem_file (lp->ptid.pid ());
 
-      ourstatus->kind = TARGET_WAITKIND_EXECD;
-      ourstatus->value.execd_pathname
-	= xstrdup (linux_proc_pid_to_exec_file (pid));
+      ourstatus->set_execd
+	(make_unique_xstrdup (linux_proc_pid_to_exec_file (pid)));
 
       /* The thread that execed must have been resumed, but, when a
 	 thread execs, it changes its tid to the tgid, and the old
@@ -2018,7 +2021,7 @@  linux_handle_extended_wait (struct lwp_info *lp, int status)
 	    ("Got expected PTRACE_EVENT_VFORK_DONE from LWP %ld: stopping",
 	     lp->ptid.lwp ());
 
-	  ourstatus->kind = TARGET_WAITKIND_VFORK_DONE;
+	  ourstatus->set_vfork_done ();
 	  return 0;
 	}
 
@@ -2538,7 +2541,7 @@  lwp_status_pending_p (struct lwp_info *lp)
   /* We check for lp->waitstatus in addition to lp->status, because we
      can have pending process exits recorded in lp->status and
      W_EXITCODE(0,0) happens to be 0.  */
-  return lp->status != 0 || lp->waitstatus.kind != TARGET_WAITKIND_IGNORE;
+  return lp->status != 0 || lp->waitstatus.kind () != TARGET_WAITKIND_IGNORE;
 }
 
 /* Select the Nth LWP that has had an event.  */
@@ -3085,9 +3088,9 @@  filter_exit_event (struct lwp_info *event_child,
   if (num_lwps (ptid.pid ()) > 1)
     {
       if (report_thread_events)
-	ourstatus->kind = TARGET_WAITKIND_THREAD_EXITED;
+	ourstatus->set_thread_exited (0);
       else
-	ourstatus->kind = TARGET_WAITKIND_IGNORE;
+	ourstatus->set_ignore ();
 
       exit_lwp (event_child);
     }
@@ -3195,7 +3198,7 @@  linux_nat_wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus,
 	{
 	  linux_nat_debug_printf ("exit (no resumed LWP)");
 
-	  ourstatus->kind = TARGET_WAITKIND_NO_RESUMED;
+	  ourstatus->set_no_resumed ();
 
 	  restore_child_signals_mask (&prev_mask);
 	  return minus_one_ptid;
@@ -3207,7 +3210,7 @@  linux_nat_wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus,
 	{
 	  linux_nat_debug_printf ("exit (ignore)");
 
-	  ourstatus->kind = TARGET_WAITKIND_IGNORE;
+	  ourstatus->set_ignore ();
 	  restore_child_signals_mask (&prev_mask);
 	  return minus_one_ptid;
 	}
@@ -3283,10 +3286,10 @@  linux_nat_wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus,
 			      target_pid_to_str (lp->ptid).c_str ());
     }
 
-  if (lp->waitstatus.kind != TARGET_WAITKIND_IGNORE)
+  if (lp->waitstatus.kind () != TARGET_WAITKIND_IGNORE)
     {
       *ourstatus = lp->waitstatus;
-      lp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
+      lp->waitstatus.set_ignore ();
     }
   else
     store_waitstatus (ourstatus, status);
@@ -3296,22 +3299,22 @@  linux_nat_wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus,
   restore_child_signals_mask (&prev_mask);
 
   if (last_resume_kind == resume_stop
-      && ourstatus->kind == TARGET_WAITKIND_STOPPED
+      && ourstatus->kind () == TARGET_WAITKIND_STOPPED
       && WSTOPSIG (status) == SIGSTOP)
     {
       /* A thread that has been requested to stop by GDB with
 	 target_stop, and it stopped cleanly, so report as SIG0.  The
 	 use of SIGSTOP is an implementation detail.  */
-      ourstatus->value.sig = GDB_SIGNAL_0;
+      ourstatus->set_stopped (GDB_SIGNAL_0);
     }
 
-  if (ourstatus->kind == TARGET_WAITKIND_EXITED
-      || ourstatus->kind == TARGET_WAITKIND_SIGNALLED)
+  if (ourstatus->kind () == TARGET_WAITKIND_EXITED
+      || ourstatus->kind () == TARGET_WAITKIND_SIGNALLED)
     lp->core = -1;
   else
     lp->core = linux_common_core_of_thread (lp->ptid);
 
-  if (ourstatus->kind == TARGET_WAITKIND_EXITED)
+  if (ourstatus->kind () == TARGET_WAITKIND_EXITED)
     return filter_exit_event (lp, ourstatus);
 
   return lp->ptid;
@@ -3409,8 +3412,8 @@  linux_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
      may be more.  If we requested a specific lwp or process, also
      assume there may be more.  */
   if (target_is_async_p ()
-      && ((ourstatus->kind != TARGET_WAITKIND_IGNORE
-	   && ourstatus->kind != TARGET_WAITKIND_NO_RESUMED)
+      && ((ourstatus->kind () != TARGET_WAITKIND_IGNORE
+	   && ourstatus->kind () != TARGET_WAITKIND_NO_RESUMED)
 	  || ptid != minus_one_ptid))
     async_file_mark ();
 
@@ -3508,10 +3511,10 @@  kill_unfollowed_fork_children (struct inferior *inf)
     {
       struct target_waitstatus *ws = &thread->pending_follow;
 
-      if (ws->kind == TARGET_WAITKIND_FORKED
-	  || ws->kind == TARGET_WAITKIND_VFORKED)
+      if (ws->kind () == TARGET_WAITKIND_FORKED
+	  || ws->kind () == TARGET_WAITKIND_VFORKED)
 	{
-	  ptid_t child_ptid = ws->value.related_pid;
+	  ptid_t child_ptid = ws->child_ptid ();
 	  int child_pid = child_ptid.pid ();
 	  int child_lwp = child_ptid.lwp ();
 
diff --git a/gdb/linux-nat.h b/gdb/linux-nat.h
index 74b5eddc136..95e26b7ee46 100644
--- a/gdb/linux-nat.h
+++ b/gdb/linux-nat.h
@@ -202,9 +202,7 @@  struct lwp_info : intrusive_list_node<lwp_info>
 {
   lwp_info (ptid_t ptid)
     : ptid (ptid)
-  {
-    waitstatus.kind = TARGET_WAITKIND_IGNORE;
-  }
+  {}
 
   ~lwp_info ();
 
@@ -212,7 +210,7 @@  struct lwp_info : intrusive_list_node<lwp_info>
 
   /* The process id of the LWP.  This is a combination of the LWP id
      and overall process id.  */
-  ptid_t ptid;
+  ptid_t ptid = null_ptid;
 
   /* If this flag is set, we need to set the event request flags the
      next time we see this LWP stop.  */
diff --git a/gdb/linux-thread-db.c b/gdb/linux-thread-db.c
index 54e68ccd0d7..c2a3f54d43c 100644
--- a/gdb/linux-thread-db.c
+++ b/gdb/linux-thread-db.c
@@ -1407,7 +1407,7 @@  thread_db_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 
   ptid = beneath->wait (ptid, ourstatus, options);
 
-  switch (ourstatus->kind)
+  switch (ourstatus->kind ())
     {
     case TARGET_WAITKIND_IGNORE:
     case TARGET_WAITKIND_EXITED:
diff --git a/gdb/nat/fork-inferior.c b/gdb/nat/fork-inferior.c
index c88cf4cf716..fc19f17a4f6 100644
--- a/gdb/nat/fork-inferior.c
+++ b/gdb/nat/fork-inferior.c
@@ -479,7 +479,6 @@  startup_inferior (process_stratum_target *proc_target, pid_t pid, int ntraps,
       ptid_t event_ptid;
 
       struct target_waitstatus ws;
-      memset (&ws, 0, sizeof (ws));
       event_ptid = target_wait (resume_ptid, &ws, 0);
 
       if (last_waitstatus != NULL)
@@ -487,11 +486,11 @@  startup_inferior (process_stratum_target *proc_target, pid_t pid, int ntraps,
       if (last_ptid != NULL)
 	*last_ptid = event_ptid;
 
-      if (ws.kind == TARGET_WAITKIND_IGNORE)
+      if (ws.kind () == TARGET_WAITKIND_IGNORE)
 	/* The inferior didn't really stop, keep waiting.  */
 	continue;
 
-      switch (ws.kind)
+      switch (ws.kind ())
 	{
 	  case TARGET_WAITKIND_SPURIOUS:
 	  case TARGET_WAITKIND_LOADED:
@@ -507,32 +506,28 @@  startup_inferior (process_stratum_target *proc_target, pid_t pid, int ntraps,
 	    target_terminal::ours ();
 	    target_mourn_inferior (event_ptid);
 	    error (_("During startup program terminated with signal %s, %s."),
-		   gdb_signal_to_name (ws.value.sig),
-		   gdb_signal_to_string (ws.value.sig));
+		   gdb_signal_to_name (ws.sig ()),
+		   gdb_signal_to_string (ws.sig ()));
 	    return resume_ptid;
 
 	  case TARGET_WAITKIND_EXITED:
 	    target_terminal::ours ();
 	    target_mourn_inferior (event_ptid);
-	    if (ws.value.integer)
+	    if (ws.exit_status ())
 	      error (_("During startup program exited with code %d."),
-		     ws.value.integer);
+		     ws.exit_status ());
 	    else
 	      error (_("During startup program exited normally."));
 	    return resume_ptid;
 
 	  case TARGET_WAITKIND_EXECD:
 	    /* Handle EXEC signals as if they were SIGTRAP signals.  */
-	    /* Free the exec'ed pathname, but only if this isn't the
-	       waitstatus we are returning to the caller.  */
-	    if (pending_execs != 1)
-	      xfree (ws.value.execd_pathname);
 	    resume_signal = GDB_SIGNAL_TRAP;
 	    switch_to_thread (proc_target, event_ptid);
 	    break;
 
 	  case TARGET_WAITKIND_STOPPED:
-	    resume_signal = ws.value.sig;
+	    resume_signal = ws.sig ();
 	    switch_to_thread (proc_target, event_ptid);
 	    break;
 	}
diff --git a/gdb/nat/windows-nat.c b/gdb/nat/windows-nat.c
index 0bb87ec0674..fa0ed56175a 100644
--- a/gdb/nat/windows-nat.c
+++ b/gdb/nat/windows-nat.c
@@ -197,8 +197,6 @@  handle_exception (struct target_waitstatus *ourstatus, bool debug_exceptions)
 
   memcpy (&siginfo_er, rec, sizeof siginfo_er);
 
-  ourstatus->kind = TARGET_WAITKIND_STOPPED;
-
   /* Record the context of the current thread.  */
   thread_rec (ptid_t (current_event.dwProcessId, current_event.dwThreadId, 0),
 	      DONT_SUSPEND);
@@ -207,53 +205,53 @@  handle_exception (struct target_waitstatus *ourstatus, bool debug_exceptions)
     {
     case EXCEPTION_ACCESS_VIOLATION:
       DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ACCESS_VIOLATION");
-      ourstatus->value.sig = GDB_SIGNAL_SEGV;
+      ourstatus->set_stopped (GDB_SIGNAL_SEGV);
       if (handle_access_violation (rec))
 	return HANDLE_EXCEPTION_UNHANDLED;
       break;
     case STATUS_STACK_OVERFLOW:
       DEBUG_EXCEPTION_SIMPLE ("STATUS_STACK_OVERFLOW");
-      ourstatus->value.sig = GDB_SIGNAL_SEGV;
+      ourstatus->set_stopped (GDB_SIGNAL_SEGV);
       break;
     case STATUS_FLOAT_DENORMAL_OPERAND:
       DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_DENORMAL_OPERAND");
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
+      ourstatus->set_stopped (GDB_SIGNAL_FPE);
       break;
     case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
       DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ARRAY_BOUNDS_EXCEEDED");
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
+      ourstatus->set_stopped (GDB_SIGNAL_FPE);
       break;
     case STATUS_FLOAT_INEXACT_RESULT:
       DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_INEXACT_RESULT");
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
+      ourstatus->set_stopped (GDB_SIGNAL_FPE);
       break;
     case STATUS_FLOAT_INVALID_OPERATION:
       DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_INVALID_OPERATION");
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
+      ourstatus->set_stopped (GDB_SIGNAL_FPE);
       break;
     case STATUS_FLOAT_OVERFLOW:
       DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_OVERFLOW");
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
+      ourstatus->set_stopped (GDB_SIGNAL_FPE);
       break;
     case STATUS_FLOAT_STACK_CHECK:
       DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_STACK_CHECK");
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
+      ourstatus->set_stopped (GDB_SIGNAL_FPE);
       break;
     case STATUS_FLOAT_UNDERFLOW:
       DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_UNDERFLOW");
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
+      ourstatus->set_stopped (GDB_SIGNAL_FPE);
       break;
     case STATUS_FLOAT_DIVIDE_BY_ZERO:
       DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_DIVIDE_BY_ZERO");
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
+      ourstatus->set_stopped (GDB_SIGNAL_FPE);
       break;
     case STATUS_INTEGER_DIVIDE_BY_ZERO:
       DEBUG_EXCEPTION_SIMPLE ("STATUS_INTEGER_DIVIDE_BY_ZERO");
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
+      ourstatus->set_stopped (GDB_SIGNAL_FPE);
       break;
     case STATUS_INTEGER_OVERFLOW:
       DEBUG_EXCEPTION_SIMPLE ("STATUS_INTEGER_OVERFLOW");
-      ourstatus->value.sig = GDB_SIGNAL_FPE;
+      ourstatus->set_stopped (GDB_SIGNAL_FPE);
       break;
     case EXCEPTION_BREAKPOINT:
 #ifdef __x86_64__
@@ -263,7 +261,7 @@  handle_exception (struct target_waitstatus *ourstatus, bool debug_exceptions)
 	     on startup, first a BREAKPOINT for the 64bit ntdll.dll,
 	     then a WX86_BREAKPOINT for the 32bit ntdll.dll.
 	     Here we only care about the WX86_BREAKPOINT's.  */
-	  ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+	  ourstatus->set_spurious ();
 	  ignore_first_breakpoint = false;
 	}
       else if (wow64_process)
@@ -277,45 +275,45 @@  handle_exception (struct target_waitstatus *ourstatus, bool debug_exceptions)
 	     unconditionally.  */
 	  DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_BREAKPOINT");
 	  rec->ExceptionCode = DBG_CONTROL_C;
-	  ourstatus->value.sig = GDB_SIGNAL_INT;
+	  ourstatus->set_stopped (GDB_SIGNAL_INT);
 	  break;
 	}
 #endif
       /* FALLTHROUGH */
     case STATUS_WX86_BREAKPOINT:
       DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_BREAKPOINT");
-      ourstatus->value.sig = GDB_SIGNAL_TRAP;
+      ourstatus->set_stopped (GDB_SIGNAL_TRAP);
       break;
     case DBG_CONTROL_C:
       DEBUG_EXCEPTION_SIMPLE ("DBG_CONTROL_C");
-      ourstatus->value.sig = GDB_SIGNAL_INT;
+      ourstatus->set_stopped (GDB_SIGNAL_INT);
       break;
     case DBG_CONTROL_BREAK:
       DEBUG_EXCEPTION_SIMPLE ("DBG_CONTROL_BREAK");
-      ourstatus->value.sig = GDB_SIGNAL_INT;
+      ourstatus->set_stopped (GDB_SIGNAL_INT);
       break;
     case EXCEPTION_SINGLE_STEP:
     case STATUS_WX86_SINGLE_STEP:
       DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_SINGLE_STEP");
-      ourstatus->value.sig = GDB_SIGNAL_TRAP;
+      ourstatus->set_stopped (GDB_SIGNAL_TRAP);
       break;
     case EXCEPTION_ILLEGAL_INSTRUCTION:
       DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ILLEGAL_INSTRUCTION");
-      ourstatus->value.sig = GDB_SIGNAL_ILL;
+      ourstatus->set_stopped (GDB_SIGNAL_ILL);
       break;
     case EXCEPTION_PRIV_INSTRUCTION:
       DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_PRIV_INSTRUCTION");
-      ourstatus->value.sig = GDB_SIGNAL_ILL;
+      ourstatus->set_stopped (GDB_SIGNAL_ILL);
       break;
     case EXCEPTION_NONCONTINUABLE_EXCEPTION:
       DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_NONCONTINUABLE_EXCEPTION");
-      ourstatus->value.sig = GDB_SIGNAL_ILL;
+      ourstatus->set_stopped (GDB_SIGNAL_ILL);
       break;
     case MS_VC_EXCEPTION:
       DEBUG_EXCEPTION_SIMPLE ("MS_VC_EXCEPTION");
       if (handle_ms_vc_exception (rec))
 	{
-	  ourstatus->value.sig = GDB_SIGNAL_TRAP;
+	  ourstatus->set_stopped (GDB_SIGNAL_TRAP);
 	  result = HANDLE_EXCEPTION_IGNORED;
 	  break;
 	}
@@ -329,11 +327,13 @@  handle_exception (struct target_waitstatus *ourstatus, bool debug_exceptions)
 	(unsigned) current_event.u.Exception.ExceptionRecord.ExceptionCode,
 	host_address_to_string (
 	  current_event.u.Exception.ExceptionRecord.ExceptionAddress));
-      ourstatus->value.sig = GDB_SIGNAL_UNKNOWN;
+      ourstatus->set_stopped (GDB_SIGNAL_UNKNOWN);
       break;
     }
 
-  last_sig = ourstatus->value.sig;
+  if (ourstatus->kind () == TARGET_WAITKIND_STOPPED)
+    last_sig = ourstatus->sig ();
+
   return result;
 
 #undef DEBUG_EXCEPTION_SIMPLE
diff --git a/gdb/netbsd-nat.c b/gdb/netbsd-nat.c
index 5e17f8a6c28..e06c036fcdd 100644
--- a/gdb/netbsd-nat.c
+++ b/gdb/netbsd-nat.c
@@ -576,7 +576,7 @@  nbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
   ptid_t wptid = ptid_t (pid);
 
   /* If the child stopped, keep investigating its status.  */
-  if (ourstatus->kind != TARGET_WAITKIND_STOPPED)
+  if (ourstatus->kind () != TARGET_WAITKIND_STOPPED)
     return wptid;
 
   /* Extract the event and thread that received a signal.  */
@@ -620,12 +620,11 @@  nbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 	 Ignore exited events for an unknown LWP.  */
       thread_info *thr = find_thread_ptid (this, wptid);
       if (thr == nullptr)
-	  ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+	  ourstatus->set_spurious ();
       else
 	{
-	  ourstatus->kind = TARGET_WAITKIND_THREAD_EXITED;
 	  /* NetBSD does not store an LWP exit status.  */
-	  ourstatus->value.integer = 0;
+	  ourstatus->set_thread_exited (0);
 
 	  if (print_thread_events)
 	    printf_unfiltered (_("[%s exited]\n"),
@@ -650,19 +649,18 @@  nbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 	 not yet reported their PTRACE_LWP_CREATE event.  Ignore
 	 born events for an already-known LWP.  */
       if (in_thread_list (this, wptid))
-	  ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+	  ourstatus->set_spurious ();
       else
 	{
 	  add_thread (this, wptid);
-	  ourstatus->kind = TARGET_WAITKIND_THREAD_CREATED;
+	  ourstatus->set_thread_created ();
 	}
       return wptid;
     }
 
   if (code == TRAP_EXEC)
     {
-      ourstatus->kind = TARGET_WAITKIND_EXECD;
-      ourstatus->value.execd_pathname = xstrdup (pid_to_exec_file (pid));
+      ourstatus->set_execd (make_unique_xstrdup (pid_to_exec_file (pid)));
       return wptid;
     }
 
@@ -679,14 +677,14 @@  nbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
       if (!catch_syscall_enabled () || !catching_syscall_number (sysnum))
 	{
 	  /* If the core isn't interested in this event, ignore it.  */
-	  ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+	  ourstatus->set_spurious ();
 	  return wptid;
 	}
 
-      ourstatus->kind =
-	(code == TRAP_SCE) ? TARGET_WAITKIND_SYSCALL_ENTRY :
-	TARGET_WAITKIND_SYSCALL_RETURN;
-      ourstatus->value.syscall_number = sysnum;
+      if (code == TRAP_SCE)
+	ourstatus->set_syscall_entry (sysnum);
+      else
+	ourstatus->set_syscall_return (sysnum);
       return wptid;
     }
 
@@ -697,7 +695,7 @@  nbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
     }
 
   /* Unclassified SIGTRAP event.  */
-  ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+  ourstatus->set_spurious ();
   return wptid;
 }
 
diff --git a/gdb/nto-procfs.c b/gdb/nto-procfs.c
index 1d21153bb4c..365610360a9 100644
--- a/gdb/nto-procfs.c
+++ b/gdb/nto-procfs.c
@@ -802,12 +802,11 @@  nto_procfs_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
   procfs_status status;
   static int exit_signo = 0;	/* To track signals that cause termination.  */
 
-  ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+  ourstatus->set_spurious ();
 
   if (inferior_ptid == null_ptid)
     {
-      ourstatus->kind = TARGET_WAITKIND_STOPPED;
-      ourstatus->value.sig = GDB_SIGNAL_0;
+      ourstatus->set_stopped (GDB_SIGNAL_0);
       exit_signo = 0;
       return null_ptid;
     }
@@ -828,38 +827,29 @@  nto_procfs_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
   nto_inferior_data (NULL)->stopped_pc = status.ip;
 
   if (status.flags & _DEBUG_FLAG_SSTEP)
-    {
-      ourstatus->kind = TARGET_WAITKIND_STOPPED;
-      ourstatus->value.sig = GDB_SIGNAL_TRAP;
-    }
+    ourstatus->set_stopped (GDB_SIGNAL_TRAP);
   /* Was it a breakpoint?  */
   else if (status.flags & _DEBUG_FLAG_TRACE)
-    {
-      ourstatus->kind = TARGET_WAITKIND_STOPPED;
-      ourstatus->value.sig = GDB_SIGNAL_TRAP;
-    }
+    ourstatus->set_stopped (GDB_SIGNAL_TRAP);
   else if (status.flags & _DEBUG_FLAG_ISTOP)
     {
       switch (status.why)
 	{
 	case _DEBUG_WHY_SIGNALLED:
-	  ourstatus->kind = TARGET_WAITKIND_STOPPED;
-	  ourstatus->value.sig =
-	    gdb_signal_from_host (status.info.si_signo);
+	  ourstatus->set_stopped (gdb_signal_from_host (status.info.si_signo));
 	  exit_signo = 0;
 	  break;
 	case _DEBUG_WHY_FAULTED:
-	  ourstatus->kind = TARGET_WAITKIND_STOPPED;
 	  if (status.info.si_signo == SIGTRAP)
 	    {
-	      ourstatus->value.sig = 0;
+	      ourstatus->set_stopped (0);
 	      exit_signo = 0;
 	    }
 	  else
 	    {
-	      ourstatus->value.sig =
-		gdb_signal_from_host (status.info.si_signo);
-	      exit_signo = ourstatus->value.sig;
+	      ourstatus->set_stopped
+		(gdb_signal_from_host (status.info.si_signo));
+	      exit_signo = ourstatus->sig ();
 	    }
 	  break;
 
@@ -871,14 +861,12 @@  nto_procfs_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 	    if (exit_signo)
 	      {
 		/* Abnormal death.  */
-		ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
-		ourstatus->value.sig = exit_signo;
+		ourstatus->set_signalled (exit_signo);
 	      }
 	    else
 	      {
 		/* Normal death.  */
-		ourstatus->kind = TARGET_WAITKIND_EXITED;
-		ourstatus->value.integer = WEXITSTATUS (waitval);
+		ourstatus->set_exited (WEXITSTATUS (waitval));
 	      }
 	    exit_signo = 0;
 	    break;
@@ -886,8 +874,7 @@  nto_procfs_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 
 	case _DEBUG_WHY_REQUESTED:
 	  /* We are assuming a requested stop is due to a SIGINT.  */
-	  ourstatus->kind = TARGET_WAITKIND_STOPPED;
-	  ourstatus->value.sig = GDB_SIGNAL_INT;
+	  ourstatus->set_stopped (GDB_SIGNAL_INT);
 	  exit_signo = 0;
 	  break;
 	}
diff --git a/gdb/obsd-nat.c b/gdb/obsd-nat.c
index 890ec5ed670..c70820d60d0 100644
--- a/gdb/obsd-nat.c
+++ b/gdb/obsd-nat.c
@@ -90,7 +90,7 @@  obsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 		       target_wait_flags options)
 {
   ptid_t wptid = inf_ptrace_target::wait (ptid, ourstatus, options);
-  if (ourstatus->kind == TARGET_WAITKIND_STOPPED)
+  if (ourstatus->kind () == TARGET_WAITKIND_STOPPED)
     {
       ptrace_state_t pe;
 
@@ -103,8 +103,7 @@  obsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
       switch (pe.pe_report_event)
 	{
 	case PTRACE_FORK:
-	  ourstatus->kind = TARGET_WAITKIND_FORKED;
-	  ourstatus->value.related_pid = ptid_t (pe.pe_other_pid);
+	  ourstatus->set_forked (ptid_t (pe.pe_other_pid));
 
 	  /* Make sure the other end of the fork is stopped too.  */
 	  pid_t fpid = waitpid (pe.pe_other_pid, nullptr, 0);
@@ -119,11 +118,11 @@  obsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 	  gdb_assert (pe.pe_other_pid == pid);
 	  if (find_inferior_pid (this, fpid) != nullptr)
 	    {
-	      ourstatus->value.related_pid = ptid_t (pe.pe_other_pid);
+	      ourstatus->set_forked (ptid_t (pe.pe_other_pid));
 	      wptid = ptid_t (fpid, pe.pe_tid, 0);
 	    }
 
-	  obsd_enable_proc_events (ourstatus->value.related_pid.pid ());
+	  obsd_enable_proc_events (ourstatus->child_ptid ().pid ());
 	  break;
 	}
 
diff --git a/gdb/procfs.c b/gdb/procfs.c
index a8ee9334a3c..2c96919dceb 100644
--- a/gdb/procfs.c
+++ b/gdb/procfs.c
@@ -1311,8 +1311,8 @@  proc_set_current_signal (procinfo *pi, int signo)
   get_last_target_status (&wait_target, &wait_ptid, &wait_status);
   if (wait_target == &the_procfs_target
       && wait_ptid == inferior_ptid
-      && wait_status.kind == TARGET_WAITKIND_STOPPED
-      && wait_status.value.sig == gdb_signal_from_host (signo)
+      && wait_status.kind () == TARGET_WAITKIND_STOPPED
+      && wait_status.sig () == gdb_signal_from_host (signo)
       && proc_get_status (pi)
       && pi->prstatus.pr_lwp.pr_info.si_signo == signo
       )
@@ -2256,7 +2256,7 @@  procfs_target::wait (ptid_t ptid, struct target_waitstatus *status,
 		      printf_unfiltered (_("[%s exited]\n"),
 					 target_pid_to_str (retval).c_str ());
 		    delete_thread (find_thread_ptid (this, retval));
-		    status->kind = TARGET_WAITKIND_SPURIOUS;
+		    status->set_spurious ();
 		    return retval;
 		  }
 		else
@@ -2306,8 +2306,7 @@  procfs_target::wait (ptid_t ptid, struct target_waitstatus *status,
 		    if (!in_thread_list (this, temp_ptid))
 		      add_thread (this, temp_ptid);
 
-		    status->kind = TARGET_WAITKIND_STOPPED;
-		    status->value.sig = GDB_SIGNAL_0;
+		    status->set_stopped (GDB_SIGNAL_0);
 		    return retval;
 		  }
 #endif
diff --git a/gdb/ravenscar-thread.c b/gdb/ravenscar-thread.c
index 85f934be3af..4afe95cb96b 100644
--- a/gdb/ravenscar-thread.c
+++ b/gdb/ravenscar-thread.c
@@ -401,8 +401,8 @@  ravenscar_thread_target::wait (ptid_t ptid,
      this causes problems when debugging through the remote protocol,
      because we might try switching threads (and thus sending packets)
      after the remote has disconnected.  */
-  if (status->kind != TARGET_WAITKIND_EXITED
-      && status->kind != TARGET_WAITKIND_SIGNALLED
+  if (status->kind () != TARGET_WAITKIND_EXITED
+      && status->kind () != TARGET_WAITKIND_SIGNALLED
       && runtime_initialized ())
     {
       m_base_ptid = event_ptid;
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index e2b9866d68a..e2538ee8eda 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -2235,7 +2235,7 @@  btrace_step_no_history (void)
 {
   struct target_waitstatus status;
 
-  status.kind = TARGET_WAITKIND_NO_HISTORY;
+  status.set_no_history ();
 
   return status;
 }
@@ -2247,8 +2247,7 @@  btrace_step_stopped (void)
 {
   struct target_waitstatus status;
 
-  status.kind = TARGET_WAITKIND_STOPPED;
-  status.value.sig = GDB_SIGNAL_TRAP;
+  status.set_stopped (GDB_SIGNAL_TRAP);
 
   return status;
 }
@@ -2261,8 +2260,7 @@  btrace_step_stopped_on_request (void)
 {
   struct target_waitstatus status;
 
-  status.kind = TARGET_WAITKIND_STOPPED;
-  status.value.sig = GDB_SIGNAL_0;
+  status.set_stopped (GDB_SIGNAL_0);
 
   return status;
 }
@@ -2274,7 +2272,7 @@  btrace_step_spurious (void)
 {
   struct target_waitstatus status;
 
-  status.kind = TARGET_WAITKIND_SPURIOUS;
+  status.set_spurious ();
 
   return status;
 }
@@ -2286,7 +2284,7 @@  btrace_step_no_resumed (void)
 {
   struct target_waitstatus status;
 
-  status.kind = TARGET_WAITKIND_NO_RESUMED;
+  status.set_no_resumed ();
 
   return status;
 }
@@ -2298,7 +2296,7 @@  btrace_step_again (void)
 {
   struct target_waitstatus status;
 
-  status.kind = TARGET_WAITKIND_IGNORE;
+  status.set_ignore ();
 
   return status;
 }
@@ -2466,21 +2464,21 @@  record_btrace_step_thread (struct thread_info *tp)
 
     case BTHR_STEP:
       status = record_btrace_single_step_forward (tp);
-      if (status.kind != TARGET_WAITKIND_SPURIOUS)
+      if (status.kind () != TARGET_WAITKIND_SPURIOUS)
 	break;
 
       return btrace_step_stopped ();
 
     case BTHR_RSTEP:
       status = record_btrace_single_step_backward (tp);
-      if (status.kind != TARGET_WAITKIND_SPURIOUS)
+      if (status.kind () != TARGET_WAITKIND_SPURIOUS)
 	break;
 
       return btrace_step_stopped ();
 
     case BTHR_CONT:
       status = record_btrace_single_step_forward (tp);
-      if (status.kind != TARGET_WAITKIND_SPURIOUS)
+      if (status.kind () != TARGET_WAITKIND_SPURIOUS)
 	break;
 
       btinfo->flags |= flags;
@@ -2488,7 +2486,7 @@  record_btrace_step_thread (struct thread_info *tp)
 
     case BTHR_RCONT:
       status = record_btrace_single_step_backward (tp);
-      if (status.kind != TARGET_WAITKIND_SPURIOUS)
+      if (status.kind () != TARGET_WAITKIND_SPURIOUS)
 	break;
 
       btinfo->flags |= flags;
@@ -2497,7 +2495,7 @@  record_btrace_step_thread (struct thread_info *tp)
 
   /* We keep threads moving at the end of their execution history.  The wait
      method will stop the thread for whom the event is reported.  */
-  if (status.kind == TARGET_WAITKIND_NO_HISTORY)
+  if (status.kind () == TARGET_WAITKIND_NO_HISTORY)
     btinfo->flags |= flags;
 
   return status;
@@ -2589,7 +2587,7 @@  record_btrace_target::wait (ptid_t ptid, struct target_waitstatus *status,
 
 	  *status = record_btrace_step_thread (tp);
 
-	  switch (status->kind)
+	  switch (status->kind ())
 	    {
 	    case TARGET_WAITKIND_IGNORE:
 	      ix++;
diff --git a/gdb/record-full.c b/gdb/record-full.c
index f5c4244f0ed..bb02e766748 100644
--- a/gdb/record-full.c
+++ b/gdb/record-full.c
@@ -1155,7 +1155,7 @@  record_full_wait_1 (struct target_ops *ops,
       gdb_assert ((options & TARGET_WNOHANG) != 0);
 
       /* No interesting event.  */
-      status->kind = TARGET_WAITKIND_IGNORE;
+      status->set_ignore ();
       return minus_one_ptid;
     }
 
@@ -1182,7 +1182,7 @@  record_full_wait_1 (struct target_ops *ops,
 	  while (1)
 	    {
 	      ret = ops->beneath ()->wait (ptid, status, options);
-	      if (status->kind == TARGET_WAITKIND_IGNORE)
+	      if (status->kind () == TARGET_WAITKIND_IGNORE)
 		{
 		  if (record_debug)
 		    fprintf_unfiltered (gdb_stdlog,
@@ -1198,8 +1198,8 @@  record_full_wait_1 (struct target_ops *ops,
 		return ret;
 
 	      /* Is this a SIGTRAP?  */
-	      if (status->kind == TARGET_WAITKIND_STOPPED
-		  && status->value.sig == GDB_SIGNAL_TRAP)
+	      if (status->kind () == TARGET_WAITKIND_STOPPED
+		  && status->sig () == GDB_SIGNAL_TRAP)
 		{
 		  struct regcache *regcache;
 		  enum target_stop_reason *stop_reason_p
@@ -1237,8 +1237,7 @@  record_full_wait_1 (struct target_ops *ops,
 		      if (!record_full_message_wrapper_safe (regcache,
 							     GDB_SIGNAL_0))
 			{
-			   status->kind = TARGET_WAITKIND_STOPPED;
-			   status->value.sig = GDB_SIGNAL_0;
+			   status->set_stopped (GDB_SIGNAL_0);
 			   break;
 			}
 
@@ -1292,7 +1291,7 @@  record_full_wait_1 (struct target_ops *ops,
 	  CORE_ADDR tmp_pc;
 
 	  record_full_stop_reason = TARGET_STOPPED_BY_NO_REASON;
-	  status->kind = TARGET_WAITKIND_STOPPED;
+	  status->set_stopped (GDB_SIGNAL_0);
 
 	  /* Check breakpoint when forward execute.  */
 	  if (execution_direction == EXEC_FORWARD)
@@ -1330,14 +1329,14 @@  record_full_wait_1 (struct target_ops *ops,
 		  && record_full_list == &record_full_first)
 		{
 		  /* Hit beginning of record log in reverse.  */
-		  status->kind = TARGET_WAITKIND_NO_HISTORY;
+		  status->set_no_history ();
 		  break;
 		}
 	      if (execution_direction != EXEC_REVERSE
 		  && !record_full_list->next)
 		{
 		  /* Hit end of record log going forward.  */
-		  status->kind = TARGET_WAITKIND_NO_HISTORY;
+		  status->set_no_history ();
 		  break;
 		}
 
@@ -1422,13 +1421,16 @@  record_full_wait_1 (struct target_ops *ops,
 	  while (continue_flag);
 
 	replay_out:
-	  if (record_full_get_sig)
-	    status->value.sig = GDB_SIGNAL_INT;
-	  else if (record_full_list->u.end.sigval != GDB_SIGNAL_0)
-	    /* FIXME: better way to check */
-	    status->value.sig = record_full_list->u.end.sigval;
-	  else
-	    status->value.sig = GDB_SIGNAL_TRAP;
+	  if (status->kind () == TARGET_WAITKIND_STOPPED)
+	    {
+	      if (record_full_get_sig)
+		status->set_stopped (GDB_SIGNAL_INT);
+	      else if (record_full_list->u.end.sigval != GDB_SIGNAL_0)
+		/* FIXME: better way to check */
+		status->set_stopped (record_full_list->u.end.sigval);
+	      else
+		status->set_stopped (GDB_SIGNAL_TRAP);
+	    }
 	}
       catch (const gdb_exception &ex)
 	{
@@ -1458,7 +1460,7 @@  record_full_base_target::wait (ptid_t ptid, struct target_waitstatus *status,
   clear_async_event_handler (record_full_async_inferior_event_token);
 
   return_ptid = record_full_wait_1 (this, ptid, status, options);
-  if (status->kind != TARGET_WAITKIND_IGNORE)
+  if (status->kind () != TARGET_WAITKIND_IGNORE)
     {
       /* We're reporting a stop.  Make sure any spurious
 	 target_wait(WNOHANG) doesn't advance the target until the
diff --git a/gdb/remote-sim.c b/gdb/remote-sim.c
index 3143b4213a6..55d674fc4d3 100644
--- a/gdb/remote-sim.c
+++ b/gdb/remote-sim.c
@@ -993,13 +993,13 @@  gdbsim_target::wait (ptid_t ptid, struct target_waitstatus *status,
 	case GDB_SIGNAL_TRAP:
 	default:
 	  status->kind = TARGET_WAITKIND_STOPPED;
-	  status->value.sig = (enum gdb_signal) sigrc;
+	  status->sig () = (enum gdb_signal) sigrc;
 	  break;
 	}
       break;
     case sim_signalled:
       status->kind = TARGET_WAITKIND_SIGNALLED;
-      status->value.sig = (enum gdb_signal) sigrc;
+      status->sig () = (enum gdb_signal) sigrc;
       break;
     case sim_running:
     case sim_polling:
diff --git a/gdb/remote.c b/gdb/remote.c
index d5eb40ce578..f3b8fdd2f2c 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -4497,8 +4497,7 @@  remote_target::print_one_stopped_thread (thread_info *thread)
     }
   else
     {
-      ws.kind = TARGET_WAITKIND_STOPPED;
-      ws.value.sig = GDB_SIGNAL_0;
+      ws.set_stopped (GDB_SIGNAL_0);
     }
 
   switch_to_thread (thread);
@@ -4508,9 +4507,9 @@  remote_target::print_one_stopped_thread (thread_info *thread)
   /* For "info program".  */
   set_last_target_status (this, thread->ptid, ws);
 
-  if (ws.kind == TARGET_WAITKIND_STOPPED)
+  if (ws.kind () == TARGET_WAITKIND_STOPPED)
     {
-      enum gdb_signal sig = ws.value.sig;
+      enum gdb_signal sig = ws.sig ();
 
       if (signal_print_state (sig))
 	gdb::observers::signal_received.notify (sig);
@@ -4542,12 +4541,11 @@  remote_target::process_initial_stop_replies (int from_tty)
       struct target_waitstatus ws;
       int ignore_event = 0;
 
-      memset (&ws, 0, sizeof (ws));
       event_ptid = target_wait (waiton_ptid, &ws, TARGET_WNOHANG);
       if (remote_debug)
 	print_target_wait_results (waiton_ptid, event_ptid, &ws);
 
-      switch (ws.kind)
+      switch (ws.kind ())
 	{
 	case TARGET_WAITKIND_IGNORE:
 	case TARGET_WAITKIND_NO_RESUMED:
@@ -4558,9 +4556,6 @@  remote_target::process_initial_stop_replies (int from_tty)
 	  ignore_event = 1;
 	  break;
 
-	case TARGET_WAITKIND_EXECD:
-	  xfree (ws.value.execd_pathname);
-	  break;
 	default:
 	  break;
 	}
@@ -4570,20 +4565,20 @@  remote_target::process_initial_stop_replies (int from_tty)
 
       thread_info *evthread = find_thread_ptid (this, event_ptid);
 
-      if (ws.kind == TARGET_WAITKIND_STOPPED)
+      if (ws.kind () == TARGET_WAITKIND_STOPPED)
 	{
-	  enum gdb_signal sig = ws.value.sig;
+	  enum gdb_signal sig = ws.sig ();
 
 	  /* Stubs traditionally report SIGTRAP as initial signal,
 	     instead of signal 0.  Suppress it.  */
 	  if (sig == GDB_SIGNAL_TRAP)
 	    sig = GDB_SIGNAL_0;
 	  evthread->set_stop_signal (sig);
-	  ws.value.sig = sig;
+	  ws.set_stopped (sig);
 	}
 
-      if (ws.kind != TARGET_WAITKIND_STOPPED
-	  || ws.value.sig != GDB_SIGNAL_0)
+      if (ws.kind () != TARGET_WAITKIND_STOPPED
+	  || ws.sig () != GDB_SIGNAL_0)
 	evthread->set_pending_waitstatus (ws);
 
       set_executing (this, event_ptid, false);
@@ -5887,7 +5882,7 @@  remote_target::remote_detach_1 (inferior *inf, int from_tty)
   /* Check to see if we are detaching a fork parent.  Note that if we
      are detaching a fork child, tp == NULL.  */
   is_fork_parent = (tp != NULL
-		    && tp->pending_follow.kind == TARGET_WAITKIND_FORKED);
+		    && tp->pending_follow.kind () == TARGET_WAITKIND_FORKED);
 
   /* If doing detach-on-fork, we don't mourn, because that will delete
      breakpoints that should be available for the followed inferior.  */
@@ -6930,8 +6925,7 @@  remote_target::remote_stop_ns (ptid_t ptid)
 	    stop_reply *sr = new stop_reply ();
 	    sr->ptid = tp->ptid;
 	    sr->rs = rs;
-	    sr->ws.kind = TARGET_WAITKIND_STOPPED;
-	    sr->ws.value.sig = GDB_SIGNAL_0;
+	    sr->ws.set_stopped (GDB_SIGNAL_0);
 	    sr->arch = tp->inf->gdbarch;
 	    sr->stop_reason = TARGET_STOPPED_BY_NO_REASON;
 	    sr->watch_data_address = 0;
@@ -7183,7 +7177,7 @@  remote_notif_stop_ack (remote_target *remote,
   /* Kind can be TARGET_WAITKIND_IGNORE if we have meanwhile discarded
      the notification.  It was left in the queue because we need to
      acknowledge it and pull the rest of the notifications out.  */
-  if (stop_reply->ws.kind != TARGET_WAITKIND_IGNORE)
+  if (stop_reply->ws.kind () != TARGET_WAITKIND_IGNORE)
     remote->push_stop_reply (stop_reply);
 }
 
@@ -7234,8 +7228,8 @@  static int
 is_pending_fork_parent (const target_waitstatus *ws, int event_pid,
 			ptid_t thread_ptid)
 {
-  if (ws->kind == TARGET_WAITKIND_FORKED
-      || ws->kind == TARGET_WAITKIND_VFORKED)
+  if (ws->kind () == TARGET_WAITKIND_FORKED
+      || ws->kind () == TARGET_WAITKIND_VFORKED)
     {
       if (event_pid == -1 || event_pid == thread_ptid.pid ())
 	return 1;
@@ -7286,7 +7280,7 @@  remote_target::remove_new_fork_children (threads_listing_context *context)
       const target_waitstatus *ws = thread_pending_fork_status (thread);
 
       if (is_pending_fork_parent (ws, pid, thread->ptid))
-	context->remove_thread (ws->value.related_pid);
+	context->remove_thread (ws->child_ptid ());
     }
 
   /* Check for any pending fork events (not reported or processed yet)
@@ -7294,10 +7288,10 @@  remote_target::remove_new_fork_children (threads_listing_context *context)
      CONTEXT list as well.  */
   remote_notif_get_pending_events (notif);
   for (auto &event : get_remote_state ()->stop_reply_queue)
-    if (event->ws.kind == TARGET_WAITKIND_FORKED
-	|| event->ws.kind == TARGET_WAITKIND_VFORKED
-	|| event->ws.kind == TARGET_WAITKIND_THREAD_EXITED)
-      context->remove_thread (event->ws.value.related_pid);
+    if (event->ws.kind () == TARGET_WAITKIND_FORKED
+	|| event->ws.kind () == TARGET_WAITKIND_VFORKED
+	|| event->ws.kind () == TARGET_WAITKIND_THREAD_EXITED)
+      context->remove_thread (event->ws.child_ptid ());
 }
 
 /* Check whether any event pending in the vStopped queue would prevent a
@@ -7315,12 +7309,12 @@  remote_target::check_pending_events_prevent_wildcard_vcont
   remote_notif_get_pending_events (notif);
   for (auto &event : get_remote_state ()->stop_reply_queue)
     {
-      if (event->ws.kind == TARGET_WAITKIND_NO_RESUMED
-	  || event->ws.kind == TARGET_WAITKIND_NO_HISTORY)
+      if (event->ws.kind () == TARGET_WAITKIND_NO_RESUMED
+	  || event->ws.kind () == TARGET_WAITKIND_NO_HISTORY)
 	continue;
 
-      if (event->ws.kind == TARGET_WAITKIND_FORKED
-	  || event->ws.kind == TARGET_WAITKIND_VFORKED)
+      if (event->ws.kind () == TARGET_WAITKIND_FORKED
+	  || event->ws.kind () == TARGET_WAITKIND_VFORKED)
 	*may_global_wildcard = false;
 
       /* This may be the first time we heard about this process.
@@ -7358,7 +7352,7 @@  remote_target::discard_pending_stop_replies (struct inferior *inf)
       /* Leave the notification pending, since the server expects that
 	 we acknowledge it with vStopped.  But clear its contents, so
 	 that later on when we acknowledge it, we also discard it.  */
-      reply->ws.kind = TARGET_WAITKIND_IGNORE;
+      reply->ws.set_ignore ();
 
       if (remote_debug)
 	fprintf_unfiltered (gdb_stdlog,
@@ -7472,7 +7466,7 @@  remote_target::peek_stop_reply (ptid_t ptid)
   remote_state *rs = get_remote_state ();
   for (auto &event : rs->stop_reply_queue)
     if (ptid == event->ptid
-	&& event->ws.kind == TARGET_WAITKIND_STOPPED)
+	&& event->ws.kind () == TARGET_WAITKIND_STOPPED)
       return 1;
   return 0;
 }
@@ -7502,8 +7496,7 @@  remote_target::remote_parse_stop_reply (const char *buf, stop_reply *event)
 
   event->ptid = null_ptid;
   event->rs = get_remote_state ();
-  event->ws.kind = TARGET_WAITKIND_IGNORE;
-  event->ws.value.integer = 0;
+  event->ws.set_ignore ();
   event->stop_reason = TARGET_STOPPED_BY_NO_REASON;
   event->regcache.clear ();
   event->core = -1;
@@ -7547,17 +7540,15 @@  Packet: '%s'\n"),
 	    {
 	      ULONGEST sysno;
 
-	      event->ws.kind = TARGET_WAITKIND_SYSCALL_ENTRY;
 	      p = unpack_varlen_hex (++p1, &sysno);
-	      event->ws.value.syscall_number = (int) sysno;
+	      event->ws.set_syscall_entry ((int) sysno);
 	    }
 	  else if (strprefix (p, p1, "syscall_return"))
 	    {
 	      ULONGEST sysno;
 
-	      event->ws.kind = TARGET_WAITKIND_SYSCALL_RETURN;
 	      p = unpack_varlen_hex (++p1, &sysno);
-	      event->ws.value.syscall_number = (int) sysno;
+	      event->ws.set_syscall_return ((int) sysno);
 	    }
 	  else if (strprefix (p, p1, "watch")
 		   || strprefix (p, p1, "rwatch")
@@ -7595,12 +7586,12 @@  Packet: '%s'\n"),
 	    }
 	  else if (strprefix (p, p1, "library"))
 	    {
-	      event->ws.kind = TARGET_WAITKIND_LOADED;
+	      event->ws.set_loaded ();
 	      p = strchrnul (p1 + 1, ';');
 	    }
 	  else if (strprefix (p, p1, "replaylog"))
 	    {
-	      event->ws.kind = TARGET_WAITKIND_NO_HISTORY;
+	      event->ws.set_no_history ();
 	      /* p1 will indicate "begin" or "end", but it makes
 		 no difference for now, so ignore it.  */
 	      p = strchrnul (p1 + 1, ';');
@@ -7613,18 +7604,12 @@  Packet: '%s'\n"),
 	      event->core = c;
 	    }
 	  else if (strprefix (p, p1, "fork"))
-	    {
-	      event->ws.value.related_pid = read_ptid (++p1, &p);
-	      event->ws.kind = TARGET_WAITKIND_FORKED;
-	    }
+	    event->ws.set_forked (read_ptid (++p1, &p));
 	  else if (strprefix (p, p1, "vfork"))
-	    {
-	      event->ws.value.related_pid = read_ptid (++p1, &p);
-	      event->ws.kind = TARGET_WAITKIND_VFORKED;
-	    }
+	    event->ws.set_vforked (read_ptid (++p1, &p));
 	  else if (strprefix (p, p1, "vforkdone"))
 	    {
-	      event->ws.kind = TARGET_WAITKIND_VFORK_DONE;
+	      event->ws.set_vfork_done ();
 	      p = strchrnul (p1 + 1, ';');
 	    }
 	  else if (strprefix (p, p1, "exec"))
@@ -7638,14 +7623,13 @@  Packet: '%s'\n"),
 
 	      /* Save the pathname for event reporting and for
 		 the next run command.  */
-	      gdb::unique_xmalloc_ptr<char[]> pathname
+	      gdb::unique_xmalloc_ptr<char> pathname
 		((char *) xmalloc (pathlen + 1));
 	      hex2bin (p1, (gdb_byte *) pathname.get (), pathlen);
-	      pathname[pathlen] = '\0';
+	      pathname.get ()[pathlen] = '\0';
 
 	      /* This is freed during event handling.  */
-	      event->ws.value.execd_pathname = pathname.release ();
-	      event->ws.kind = TARGET_WAITKIND_EXECD;
+	      event->ws.set_execd (std::move (pathname));
 
 	      /* Skip the registers included in this packet, since
 		 they may be for an architecture different from the
@@ -7654,7 +7638,7 @@  Packet: '%s'\n"),
 	    }
 	  else if (strprefix (p, p1, "create"))
 	    {
-	      event->ws.kind = TARGET_WAITKIND_THREAD_CREATED;
+	      event->ws.set_thread_created ();
 	      p = strchrnul (p1 + 1, ';');
 	    }
 	  else
@@ -7753,7 +7737,7 @@  Packet: '%s'\n"),
 	  ++p;
 	}
 
-      if (event->ws.kind != TARGET_WAITKIND_IGNORE)
+      if (event->ws.kind () != TARGET_WAITKIND_IGNORE)
 	break;
 
       /* fall through */
@@ -7761,21 +7745,19 @@  Packet: '%s'\n"),
       {
 	int sig;
 
-	event->ws.kind = TARGET_WAITKIND_STOPPED;
 	sig = (fromhex (buf[1]) << 4) + fromhex (buf[2]);
 	if (GDB_SIGNAL_FIRST <= sig && sig < GDB_SIGNAL_LAST)
-	  event->ws.value.sig = (enum gdb_signal) sig;
+	  event->ws.set_stopped ((enum gdb_signal) sig);
 	else
-	  event->ws.value.sig = GDB_SIGNAL_UNKNOWN;
+	  event->ws.set_stopped (GDB_SIGNAL_UNKNOWN);
       }
       break;
     case 'w':		/* Thread exited.  */
       {
 	ULONGEST value;
 
-	event->ws.kind = TARGET_WAITKIND_THREAD_EXITED;
 	p = unpack_varlen_hex (&buf[1], &value);
-	event->ws.value.integer = value;
+	event->ws.set_thread_exited (value);
 	if (*p != ';')
 	  error (_("stop reply packet badly formatted: %s"), buf);
 	event->ptid = read_ptid (++p, NULL);
@@ -7794,17 +7776,15 @@  Packet: '%s'\n"),
 	if (buf[0] == 'W')
 	  {
 	    /* The remote process exited.  */
-	    event->ws.kind = TARGET_WAITKIND_EXITED;
-	    event->ws.value.integer = value;
+	    event->ws.set_exited (value);
 	  }
 	else
 	  {
 	    /* The remote process exited with a signal.  */
-	    event->ws.kind = TARGET_WAITKIND_SIGNALLED;
 	    if (GDB_SIGNAL_FIRST <= value && value < GDB_SIGNAL_LAST)
-	      event->ws.value.sig = (enum gdb_signal) value;
+	      event->ws.set_signalled ((enum gdb_signal) value);
 	    else
-	      event->ws.value.sig = GDB_SIGNAL_UNKNOWN;
+	      event->ws.set_signalled (GDB_SIGNAL_UNKNOWN);
 	  }
 
 	/* If no process is specified, return null_ptid, and let the
@@ -7835,7 +7815,7 @@  Packet: '%s'\n"),
       }
       break;
     case 'N':
-      event->ws.kind = TARGET_WAITKIND_NO_RESUMED;
+      event->ws.set_no_resumed ();
       event->ptid = minus_one_ptid;
       break;
     }
@@ -7968,8 +7948,8 @@  remote_target::select_thread_for_ambiguous_stop_reply
   /* Some stop events apply to all threads in an inferior, while others
      only apply to a single thread.  */
   bool process_wide_stop
-    = (status->kind == TARGET_WAITKIND_EXITED
-       || status->kind == TARGET_WAITKIND_SIGNALLED);
+    = (status->kind () == TARGET_WAITKIND_EXITED
+       || status->kind () == TARGET_WAITKIND_SIGNALLED);
 
   remote_debug_printf ("process_wide_stop = %d", process_wide_stop);
 
@@ -8054,9 +8034,9 @@  remote_target::process_stop_reply (struct stop_reply *stop_reply,
     ptid = select_thread_for_ambiguous_stop_reply (status);
   gdb_assert (ptid != null_ptid);
 
-  if (status->kind != TARGET_WAITKIND_EXITED
-      && status->kind != TARGET_WAITKIND_SIGNALLED
-      && status->kind != TARGET_WAITKIND_NO_RESUMED)
+  if (status->kind () != TARGET_WAITKIND_EXITED
+      && status->kind () != TARGET_WAITKIND_SIGNALLED
+      && status->kind () != TARGET_WAITKIND_NO_RESUMED)
     {
       /* Expedited registers.  */
       if (!stop_reply->regcache.empty ())
@@ -8146,7 +8126,7 @@  remote_target::wait_ns (ptid_t ptid, struct target_waitstatus *status,
 	 return to the event loop.  */
       if (options & TARGET_WNOHANG)
 	{
-	  status->kind = TARGET_WAITKIND_IGNORE;
+	  status->set_ignore ();
 	  return minus_one_ptid;
 	}
 
@@ -8180,8 +8160,7 @@  remote_target::wait_as (ptid_t ptid, target_waitstatus *status,
 
  again:
 
-  status->kind = TARGET_WAITKIND_IGNORE;
-  status->value.integer = 0;
+  status->set_ignore ();
 
   stop_reply = queued_stop_reply (ptid);
   if (stop_reply != NULL)
@@ -8199,7 +8178,7 @@  remote_target::wait_as (ptid_t ptid, target_waitstatus *status,
 
       if (!rs->waiting_for_stop_reply)
 	{
-	  status->kind = TARGET_WAITKIND_NO_RESUMED;
+	  status->set_no_resumed ();
 	  return minus_one_ptid;
 	}
 
@@ -8233,8 +8212,7 @@  remote_target::wait_as (ptid_t ptid, target_waitstatus *status,
       rs->waiting_for_stop_reply = 0;
 
       warning (_("Remote failure reply: %s"), buf);
-      status->kind = TARGET_WAITKIND_STOPPED;
-      status->value.sig = GDB_SIGNAL_0;
+      status->set_stopped (GDB_SIGNAL_0);
       break;
     case 'F':		/* File-I/O request.  */
       /* GDB may access the inferior memory while handling the File-I/O
@@ -8286,9 +8264,9 @@  remote_target::wait_as (ptid_t ptid, target_waitstatus *status,
       break;
     }
 
-  if (status->kind == TARGET_WAITKIND_NO_RESUMED)
+  if (status->kind () == TARGET_WAITKIND_NO_RESUMED)
     return minus_one_ptid;
-  else if (status->kind == TARGET_WAITKIND_IGNORE)
+  else if (status->kind () == TARGET_WAITKIND_IGNORE)
     {
       /* Nothing interesting happened.  If we're doing a non-blocking
 	 poll, we're done.  Otherwise, go back to waiting.  */
@@ -8297,8 +8275,8 @@  remote_target::wait_as (ptid_t ptid, target_waitstatus *status,
       else
 	goto again;
     }
-  else if (status->kind != TARGET_WAITKIND_EXITED
-	   && status->kind != TARGET_WAITKIND_SIGNALLED)
+  else if (status->kind () != TARGET_WAITKIND_EXITED
+	   && status->kind () != TARGET_WAITKIND_SIGNALLED)
     {
       if (event_ptid != null_ptid)
 	record_currthread (rs, event_ptid);
@@ -10083,7 +10061,7 @@  remote_target::kill_new_fork_children (int pid)
 
       if (is_pending_fork_parent (ws, pid, thread->ptid))
 	{
-	  int child_pid = ws->value.related_pid.pid ();
+	  int child_pid = ws->child_ptid ().pid ();
 	  int res;
 
 	  res = remote_vkill (child_pid);
@@ -10098,7 +10076,7 @@  remote_target::kill_new_fork_children (int pid)
   for (auto &event : rs->stop_reply_queue)
     if (is_pending_fork_parent (&event->ws, pid, event->ptid))
       {
-	int child_pid = event->ws.value.related_pid.pid ();
+	int child_pid = event->ws.child_ptid ().pid ();
 	int res;
 
 	res = remote_vkill (child_pid);
diff --git a/gdb/rs6000-nat.c b/gdb/rs6000-nat.c
index ee00a600343..6d5996c2011 100644
--- a/gdb/rs6000-nat.c
+++ b/gdb/rs6000-nat.c
@@ -520,8 +520,7 @@  rs6000_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 			      safe_strerror (save_errno));
 
 	  /* Claim it exited with unknown signal.  */
-	  ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
-	  ourstatus->value.sig = GDB_SIGNAL_UNKNOWN;
+	  ourstatus->set_signalled (GDB_SIGNAL_UNKNOWN);
 	  return inferior_ptid;
 	}
 
@@ -535,10 +534,10 @@  rs6000_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 
   /* stop after load" status.  */
   if (status == 0x57c)
-    ourstatus->kind = TARGET_WAITKIND_LOADED;
+    ourstatus->set_loaded ();
   /* signal 0.  I have no idea why wait(2) returns with this status word.  */
   else if (status == 0x7f)
-    ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+    ourstatus->set_spurious ();
   /* A normal waitstatus.  Let the usual macros deal with it.  */
   else
     store_waitstatus (ourstatus, status);
diff --git a/gdb/sol-thread.c b/gdb/sol-thread.c
index 513d0309bc4..47246092fc4 100644
--- a/gdb/sol-thread.c
+++ b/gdb/sol-thread.c
@@ -441,7 +441,7 @@  sol_thread_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 
   ptid_t rtnval = beneath ()->wait (ptid, ourstatus, options);
 
-  if (ourstatus->kind != TARGET_WAITKIND_EXITED)
+  if (ourstatus->kind () != TARGET_WAITKIND_EXITED)
     {
       /* Map the LWP of interest back to the appropriate thread ID.  */
       ptid_t thr_ptid = lwp_to_thread (rtnval);
diff --git a/gdb/target.c b/gdb/target.c
index 2cb587d9cee..6219393987e 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -2615,7 +2615,7 @@  default_target_wait (struct target_ops *ops,
 		     ptid_t ptid, struct target_waitstatus *status,
 		     target_wait_flags options)
 {
-  status->kind = TARGET_WAITKIND_IGNORE;
+  status->set_ignore ();
   return minus_one_ptid;
 }
 
@@ -3851,7 +3851,6 @@  target_stop_and_wait (ptid_t ptid)
   non_stop = true;
   target_stop (ptid);
 
-  memset (&status, 0, sizeof (status));
   target_wait (ptid, &status, 0);
 
   non_stop = was_non_stop;
diff --git a/gdb/target/waitstatus.c b/gdb/target/waitstatus.c
index be5e21eae78..dc3d75eef6e 100644
--- a/gdb/target/waitstatus.c
+++ b/gdb/target/waitstatus.c
@@ -27,36 +27,36 @@  target_waitstatus_to_string (const struct target_waitstatus *ws)
 {
   const char *kind_str = "status->kind = ";
 
-  switch (ws->kind)
+  switch (ws->kind ())
     {
     case TARGET_WAITKIND_EXITED:
       return string_printf ("%sexited, status = %d",
-			    kind_str, ws->value.integer);
+			    kind_str, ws->exit_status ());
 
     case TARGET_WAITKIND_STOPPED:
       return string_printf ("%sstopped, signal = %s",
 			    kind_str,
-			    gdb_signal_to_symbol_string (ws->value.sig));
+			    gdb_signal_to_symbol_string (ws->sig ()));
 
     case TARGET_WAITKIND_SIGNALLED:
       return string_printf ("%ssignalled, signal = %s",
 			    kind_str,
-			    gdb_signal_to_symbol_string (ws->value.sig));
+			    gdb_signal_to_symbol_string (ws->sig ()));
 
     case TARGET_WAITKIND_LOADED:
       return string_printf ("%sloaded", kind_str);
 
     case TARGET_WAITKIND_FORKED:
-      return string_printf ("%sforked, related_pid = %s", kind_str,
-			    ws->value.related_pid.to_string ().c_str ());
+      return string_printf ("%sforked, child_ptid = %s", kind_str,
+			    ws->child_ptid ().to_string ().c_str ());
 
     case TARGET_WAITKIND_VFORKED:
-      return string_printf ("%svforked, related_pid = %s", kind_str,
-			    ws->value.related_pid.to_string ().c_str ());
+      return string_printf ("%svforked, child_ptid = %s", kind_str,
+			    ws->child_ptid ().to_string ().c_str ());
 
     case TARGET_WAITKIND_EXECD:
       return string_printf ("%sexecd, execd_pathname = %s", kind_str,
-			    ws->value.execd_pathname);
+			    ws->execd_pathname ());
 
     case TARGET_WAITKIND_VFORK_DONE:
       return string_printf ("%svfork-done", kind_str);
@@ -84,7 +84,7 @@  target_waitstatus_to_string (const struct target_waitstatus *ws)
 
     case TARGET_WAITKIND_THREAD_EXITED:
       return string_printf ("%sthread exited, status = %d",
-			    kind_str, ws->value.integer);
+			    kind_str, ws->exit_status ());
 
     default:
       return string_printf ("%sunknown???", kind_str);
diff --git a/gdb/target/waitstatus.h b/gdb/target/waitstatus.h
index 4123f42af5f..333863e6d6e 100644
--- a/gdb/target/waitstatus.h
+++ b/gdb/target/waitstatus.h
@@ -103,22 +103,250 @@  enum target_waitkind
 
 struct target_waitstatus
 {
-  enum target_waitkind kind;
+  /* Default constructor.  */
+  target_waitstatus () = default;
+
+  /* Copy constructor.  */
+
+  target_waitstatus (const target_waitstatus &other)
+  {
+    m_kind = other.m_kind;
+    m_value = other.m_value;
+
+    if (m_kind == TARGET_WAITKIND_EXECD)
+      m_value.execd_pathname = xstrdup (m_value.execd_pathname);
+  }
+
+  /* Move constructor.  */
+
+  target_waitstatus (target_waitstatus &&other)
+  {
+    m_kind = other.m_kind;
+    m_value = other.m_value;
+
+    if (m_kind == TARGET_WAITKIND_EXECD)
+      other.m_value.execd_pathname = nullptr;
+
+    other.reset ();
+  }
+
+  /* Copy assignment operator.  */
+
+  target_waitstatus &operator= (const target_waitstatus &rhs)
+  {
+    this->reset ();
+    m_kind = rhs.m_kind;
+    m_value = rhs.m_value;
+
+    if (m_kind == TARGET_WAITKIND_EXECD)
+      m_value.execd_pathname = xstrdup (m_value.execd_pathname);
+
+    return *this;
+  }
+
+  /* Move assignment operator.  */
+
+  target_waitstatus &operator= (target_waitstatus &&rhs)
+  {
+    this->reset ();
+    m_kind = rhs.m_kind;
+    m_value = rhs.m_value;
+
+    if (m_kind == TARGET_WAITKIND_EXECD)
+      rhs.m_value.execd_pathname = nullptr;
+
+    rhs.reset ();
+
+    return *this;
+  }
+
+  /* Destructor.  */
+
+  ~target_waitstatus ()
+  {
+    this->reset ();
+  }
+
+  /* Setters: set the wait status kind plus any associated data.  */
+
+  void set_exited (int exit_status)
+  {
+    this->reset ();
+    m_kind = TARGET_WAITKIND_EXITED;
+    m_value.exit_status = exit_status;
+  }
+
+  void set_stopped (gdb_signal sig)
+  {
+    this->reset ();
+    m_kind = TARGET_WAITKIND_STOPPED;
+    m_value.sig = sig;
+  }
+
+  void set_signalled (gdb_signal sig)
+  {
+    this->reset ();
+    m_kind = TARGET_WAITKIND_SIGNALLED;
+    m_value.sig = sig;
+  }
+
+  void set_loaded ()
+  {
+    this->reset ();
+    m_kind = TARGET_WAITKIND_LOADED;
+  }
+
+  void set_forked (ptid_t child_ptid)
+  {
+    this->reset ();
+    m_kind = TARGET_WAITKIND_FORKED;
+    m_value.child_ptid = child_ptid;
+  }
+
+  void set_vforked (ptid_t child_ptid)
+  {
+    this->reset ();
+    m_kind = TARGET_WAITKIND_VFORKED;
+    m_value.child_ptid = child_ptid;
+  }
+
+  void set_execd (gdb::unique_xmalloc_ptr<char> execd_pathname)
+  {
+    this->reset ();
+    m_kind = TARGET_WAITKIND_EXECD;
+    m_value.execd_pathname = execd_pathname.release ();
+  }
+
+  void set_vfork_done ()
+  {
+    this->reset ();
+    m_kind = TARGET_WAITKIND_VFORK_DONE;
+  }
+
+  void set_syscall_entry (int syscall_number)
+  {
+    this->reset ();
+    m_kind = TARGET_WAITKIND_SYSCALL_ENTRY;
+    m_value.syscall_number = syscall_number;
+  }
+
+  void set_syscall_return (int syscall_number)
+  {
+    this->reset ();
+    m_kind = TARGET_WAITKIND_SYSCALL_RETURN;
+    m_value.syscall_number = syscall_number;
+  }
+
+  void set_spurious ()
+  {
+    this->reset ();
+    m_kind = TARGET_WAITKIND_SPURIOUS;
+  }
+
+  void set_ignore ()
+  {
+    this->reset ();
+    m_kind = TARGET_WAITKIND_IGNORE;
+  }
+
+  void set_no_history ()
+  {
+    this->reset ();
+    m_kind = TARGET_WAITKIND_NO_HISTORY;
+  }
+
+  void set_no_resumed ()
+  {
+    this->reset ();
+    m_kind = TARGET_WAITKIND_NO_RESUMED;
+  }
+
+  void set_thread_created ()
+  {
+    this->reset ();
+    m_kind = TARGET_WAITKIND_THREAD_CREATED;
+  }
+
+  void set_thread_exited (int exit_status)
+  {
+    this->reset ();
+    m_kind = TARGET_WAITKIND_THREAD_EXITED;
+    m_value.exit_status = exit_status;
+  }
+
+  /* Get the kind of this wait status.  */
+
+  target_waitkind kind () const
+  {
+    return m_kind;
+  }
+
+  /* Getters for the associated data.
+
+     Getters can only be used if the wait status is of the appropriate kind.
+     See the setters above or the assertions below to know which data is
+     associated to which kind.  */
+
+  int exit_status () const
+  {
+    gdb_assert (m_kind == TARGET_WAITKIND_EXITED
+		|| m_kind == TARGET_WAITKIND_THREAD_EXITED);
+    return m_value.exit_status;
+  }
+
+  gdb_signal sig () const
+  {
+    gdb_assert (m_kind == TARGET_WAITKIND_STOPPED
+		|| m_kind == TARGET_WAITKIND_SIGNALLED);
+    return m_value.sig;
+  }
+
+  ptid_t child_ptid () const
+  {
+    gdb_assert (m_kind == TARGET_WAITKIND_FORKED
+		|| m_kind == TARGET_WAITKIND_VFORKED);
+    return m_value.child_ptid;
+  }
+
+  const char *execd_pathname () const
+  {
+    gdb_assert (m_kind == TARGET_WAITKIND_EXECD);
+    return m_value.execd_pathname;
+  }
+
+  int syscall_number () const
+  {
+    gdb_assert (m_kind == TARGET_WAITKIND_SYSCALL_ENTRY
+		|| m_kind == TARGET_WAITKIND_SYSCALL_RETURN);
+    return m_value.syscall_number;
+  }
+
+private:
+  /* Reset the wait status to its original state.  */
+  void reset ()
+  {
+    if (m_kind == TARGET_WAITKIND_EXECD)
+      xfree (m_value.execd_pathname);
+
+    m_kind = TARGET_WAITKIND_IGNORE;
+  }
+
+  target_waitkind m_kind = TARGET_WAITKIND_IGNORE;
 
   /* Additional information about the event.  */
   union
     {
       /* Exit status */
-      int integer;
+      int exit_status;
       /* Signal number */
       enum gdb_signal sig;
       /* Forked child pid */
-      ptid_t related_pid;
+      ptid_t child_ptid;
       /* execd pathname */
       char *execd_pathname;
       /* Syscall number */
       int syscall_number;
-    } value;
+    } m_value;
 };
 
 /* Extended reasons that can explain why a target/thread stopped for a
diff --git a/gdb/thread.c b/gdb/thread.c
index 9abb51179d6..ee9f05325cd 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -297,9 +297,7 @@  thread_info::thread_info (struct inferior *inf_, ptid_t ptid_)
   this->per_inf_num = ++inf_->highest_thread_num;
 
   /* Nothing to follow yet.  */
-  memset (&this->pending_follow, 0, sizeof (this->pending_follow));
-  this->pending_follow.kind = TARGET_WAITKIND_SPURIOUS;
-  this->m_suspend.waitstatus.kind = TARGET_WAITKIND_IGNORE;
+  this->pending_follow.set_spurious ();
 }
 
 /* See gdbthread.h.  */
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index 736b794fc82..a26d6eac816 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -937,13 +937,12 @@  windows_nat::handle_output_debug_string (struct target_waitstatus *ourstatus)
       int sig = strtol (s.get () + sizeof (_CYGWIN_SIGNAL_STRING) - 1, &p, 0);
       gdb_signal gotasig = gdb_signal_from_host (sig);
 
-      ourstatus->value.sig = gotasig;
       if (gotasig)
 	{
 	  LPCVOID x;
 	  SIZE_T n;
 
-	  ourstatus->kind = TARGET_WAITKIND_STOPPED;
+	  ourstatus->set_stopped (gotasig);
 	  retval = strtoul (p, &p, 0);
 	  if (!retval)
 	    retval = current_event.dwThreadId;
@@ -1505,7 +1504,7 @@  windows_nat_target::get_windows_debug_event (int pid,
   continue_status = DBG_CONTINUE;
 
   event_code = current_event.dwDebugEventCode;
-  ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+  ourstatus->set_spurious ();
   have_saved_context = 0;
 
   switch (event_code)
@@ -1595,15 +1594,10 @@  windows_nat_target::get_windows_debug_event (int pid,
 	  int exit_signal
 	    = WIFSIGNALED (exit_status) ? WTERMSIG (exit_status) : -1;
 	  if (exit_signal == -1)
-	    {
-	      ourstatus->kind = TARGET_WAITKIND_EXITED;
-	      ourstatus->value.integer = exit_status;
-	    }
+	    ourstatus->set_exited (exit_status);
 	  else
-	    {
-	      ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
-	      ourstatus->value.sig = gdb_signal_from_host (exit_signal);
-	    }
+	    ourstatus->set_signalled (gdb_signal_from_host (exit_signal));
+
 	  thread_id = current_event.dwThreadId;
 	}
       break;
@@ -1617,8 +1611,7 @@  windows_nat_target::get_windows_debug_event (int pid,
       if (saw_create != 1 || ! windows_initialization_done)
 	break;
       catch_errors (dll_loaded_event);
-      ourstatus->kind = TARGET_WAITKIND_LOADED;
-      ourstatus->value.integer = 0;
+      ourstatus->set_loaded ();
       thread_id = current_event.dwThreadId;
       break;
 
@@ -1630,8 +1623,7 @@  windows_nat_target::get_windows_debug_event (int pid,
       if (saw_create != 1 || ! windows_initialization_done)
 	break;
       catch_errors (handle_unload_dll);
-      ourstatus->kind = TARGET_WAITKIND_LOADED;
-      ourstatus->value.integer = 0;
+      ourstatus->set_loaded ();
       thread_id = current_event.dwThreadId;
       break;
 
@@ -1762,8 +1754,8 @@  windows_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 	{
 	  ptid_t result = ptid_t (current_event.dwProcessId, retval, 0);
 
-	  if (ourstatus->kind != TARGET_WAITKIND_EXITED
-	      && ourstatus->kind !=  TARGET_WAITKIND_SIGNALLED)
+	  if (ourstatus->kind () != TARGET_WAITKIND_EXITED
+	      && ourstatus->kind () !=  TARGET_WAITKIND_SIGNALLED)
 	    {
 	      windows_thread_info *th = thread_rec (result, INVALIDATE_CONTEXT);
 
@@ -1856,8 +1848,8 @@  windows_nat_target::do_initial_windows_stuff (DWORD pid, bool attaching)
 
       /* Note windows_wait returns TARGET_WAITKIND_SPURIOUS for thread
 	 events.  */
-      if (status.kind != TARGET_WAITKIND_LOADED
-	  && status.kind != TARGET_WAITKIND_SPURIOUS)
+      if (status.kind () != TARGET_WAITKIND_LOADED
+	  && status.kind () != TARGET_WAITKIND_SPURIOUS)
 	break;
 
       this->resume (minus_one_ptid, 0, GDB_SIGNAL_0);
diff --git a/gdbserver/gdbthread.h b/gdbserver/gdbthread.h
index fc9b4d20435..7c293b1f89d 100644
--- a/gdbserver/gdbthread.h
+++ b/gdbserver/gdbthread.h
@@ -31,9 +31,7 @@  struct thread_info
 {
   thread_info (ptid_t id, void *target_data)
     : id (id), target_data (target_data)
-  {
-    this->last_status.kind = TARGET_WAITKIND_IGNORE;
-  }
+  {}
 
   ~thread_info ()
   {
diff --git a/gdbserver/linux-low.cc b/gdbserver/linux-low.cc
index 6ea517e7fbc..e6dcc81358d 100644
--- a/gdbserver/linux-low.cc
+++ b/gdbserver/linux-low.cc
@@ -450,7 +450,7 @@  linux_process_target::handle_extended_wait (lwp_info **orig_event_lwp,
   struct thread_info *event_thr = get_lwp_thread (event_lwp);
   struct lwp_info *new_lwp;
 
-  gdb_assert (event_lwp->waitstatus.kind == TARGET_WAITKIND_IGNORE);
+  gdb_assert (event_lwp->waitstatus.kind () == TARGET_WAITKIND_IGNORE);
 
   /* All extended events we currently use are mid-syscall.  Only
      PTRACE_EVENT_STOP is delivered more like a signal-stop, but
@@ -515,7 +515,7 @@  linux_process_target::handle_extended_wait (lwp_info **orig_event_lwp,
 	  child_lwp->status_pending_p = 0;
 	  child_thr = get_lwp_thread (child_lwp);
 	  child_thr->last_resume_kind = resume_stop;
-	  child_thr->last_status.kind = TARGET_WAITKIND_STOPPED;
+	  child_thr->last_status.set_stopped (GDB_SIGNAL_0);
 
 	  /* If we're suspending all threads, leave this one suspended
 	     too.  If the fork/clone parent is stepping over a breakpoint,
@@ -554,11 +554,9 @@  linux_process_target::handle_extended_wait (lwp_info **orig_event_lwp,
 
 	  /* Save fork info in the parent thread.  */
 	  if (event == PTRACE_EVENT_FORK)
-	    event_lwp->waitstatus.kind = TARGET_WAITKIND_FORKED;
+	    event_lwp->waitstatus.set_forked (ptid);
 	  else if (event == PTRACE_EVENT_VFORK)
-	    event_lwp->waitstatus.kind = TARGET_WAITKIND_VFORKED;
-
-	  event_lwp->waitstatus.value.related_pid = ptid;
+	    event_lwp->waitstatus.set_vforked (ptid);
 
 	  /* The status_pending field contains bits denoting the
 	     extended event, so when the pending event is handled,
@@ -625,7 +623,7 @@  linux_process_target::handle_extended_wait (lwp_info **orig_event_lwp,
 	}
       else if (cs.report_thread_events)
 	{
-	  new_lwp->waitstatus.kind = TARGET_WAITKIND_THREAD_CREATED;
+	  new_lwp->waitstatus.set_thread_created ();
 	  new_lwp->status_pending_p = 1;
 	  new_lwp->status_pending = status;
 	}
@@ -639,7 +637,7 @@  linux_process_target::handle_extended_wait (lwp_info **orig_event_lwp,
     }
   else if (event == PTRACE_EVENT_VFORK_DONE)
     {
-      event_lwp->waitstatus.kind = TARGET_WAITKIND_VFORK_DONE;
+      event_lwp->waitstatus.set_vfork_done ();
 
       if (event_lwp->bp_reinsert != 0 && supports_software_single_step ())
 	{
@@ -684,16 +682,16 @@  linux_process_target::handle_extended_wait (lwp_info **orig_event_lwp,
       arch_setup_thread (event_thr);
 
       /* Set the event status.  */
-      event_lwp->waitstatus.kind = TARGET_WAITKIND_EXECD;
-      event_lwp->waitstatus.value.execd_pathname
-	= xstrdup (linux_proc_pid_to_exec_file (lwpid_of (event_thr)));
+      event_lwp->waitstatus.set_execd
+	(make_unique_xstrdup
+	   (linux_proc_pid_to_exec_file (lwpid_of (event_thr))));
 
       /* Mark the exec status as pending.  */
       event_lwp->stopped = 1;
       event_lwp->status_pending_p = 1;
       event_lwp->status_pending = wstat;
       event_thr->last_resume_kind = resume_continue;
-      event_thr->last_status.kind = TARGET_WAITKIND_IGNORE;
+      event_thr->last_status.set_ignore ();
 
       /* Update syscall state in the new lwp, effectively mid-syscall too.  */
       event_lwp->syscall_state = TARGET_WAITKIND_SYSCALL_ENTRY;
@@ -1388,8 +1386,8 @@  get_detach_signal (struct thread_info *thread)
       /* If the thread had been suspended by gdbserver, and it stopped
 	 cleanly, then it'll have stopped with SIGSTOP.  But we don't
 	 want to deliver that SIGSTOP.  */
-      if (thread->last_status.kind != TARGET_WAITKIND_STOPPED
-	  || thread->last_status.value.sig == GDB_SIGNAL_0)
+      if (thread->last_status.kind () != TARGET_WAITKIND_STOPPED
+	  || thread->last_status.sig () == GDB_SIGNAL_0)
 	return 0;
 
       /* Otherwise, we may need to deliver the signal we
@@ -1712,7 +1710,7 @@  lwp_resumed (struct lwp_info *lwp)
      corresponding stop to gdb yet?  If so, the thread is still
      resumed/running from gdb's perspective.  */
   if (thread->last_resume_kind == resume_stop
-      && thread->last_status.kind == TARGET_WAITKIND_IGNORE)
+      && thread->last_status.kind () == TARGET_WAITKIND_IGNORE)
     return 1;
 
   return 0;
@@ -2464,7 +2462,7 @@  linux_process_target::resume_stopped_resumed_lwps (thread_info *thread)
   if (lp->stopped
       && !lp->suspended
       && !lp->status_pending_p
-      && thread->last_status.kind == TARGET_WAITKIND_IGNORE)
+      && thread->last_status.kind () == TARGET_WAITKIND_IGNORE)
     {
       int step = 0;
 
@@ -2710,7 +2708,7 @@  select_event_lwp (struct lwp_info **orig_lp)
 	{
 	  lwp_info *lp = get_thread_lwp (thread);
 
-	  return (thread->last_status.kind == TARGET_WAITKIND_IGNORE
+	  return (thread->last_status.kind () == TARGET_WAITKIND_IGNORE
 		  && thread->last_resume_kind == resume_step
 		  && lp->status_pending_p);
 	});
@@ -2732,7 +2730,7 @@  select_event_lwp (struct lwp_info **orig_lp)
 	  lwp_info *lp = get_thread_lwp (thread);
 
 	  /* Only resumed LWPs that have an event pending. */
-	  return (thread->last_status.kind == TARGET_WAITKIND_IGNORE
+	  return (thread->last_status.kind () == TARGET_WAITKIND_IGNORE
 		  && lp->status_pending_p);
 	});
     }
@@ -2831,17 +2829,17 @@  linux_process_target::stabilize_threads ()
 	 over internal breakpoints and such.  */
       wait_1 (minus_one_ptid, &ourstatus, 0);
 
-      if (ourstatus.kind == TARGET_WAITKIND_STOPPED)
+      if (ourstatus.kind () == TARGET_WAITKIND_STOPPED)
 	{
 	  lwp = get_thread_lwp (current_thread);
 
 	  /* Lock it.  */
 	  lwp_suspended_inc (lwp);
 
-	  if (ourstatus.value.sig != GDB_SIGNAL_0
+	  if (ourstatus.sig () != GDB_SIGNAL_0
 	      || current_thread->last_resume_kind == resume_stop)
 	    {
-	      wstat = W_STOPCODE (gdb_signal_to_host (ourstatus.value.sig));
+	      wstat = W_STOPCODE (gdb_signal_to_host (ourstatus.sig ()));
 	      enqueue_one_deferred_signal (lwp, &wstat);
 	    }
 	}
@@ -2877,7 +2875,7 @@  ignore_event (struct target_waitstatus *ourstatus)
      another target_wait call.  */
   async_file_mark ();
 
-  ourstatus->kind = TARGET_WAITKIND_IGNORE;
+  ourstatus->set_ignore ();
   return null_ptid;
 }
 
@@ -2892,9 +2890,9 @@  linux_process_target::filter_exit_event (lwp_info *event_child,
   if (!last_thread_of_process_p (pid_of (thread)))
     {
       if (cs.report_thread_events)
-	ourstatus->kind = TARGET_WAITKIND_THREAD_EXITED;
+	ourstatus->set_thread_exited (0);
       else
-	ourstatus->kind = TARGET_WAITKIND_IGNORE;
+	ourstatus->set_ignore ();
 
       delete_lwp (event_child);
     }
@@ -2965,7 +2963,7 @@  linux_process_target::wait_1 (ptid_t ptid, target_waitstatus *ourstatus,
   bp_explains_trap = 0;
   trace_event = 0;
   in_step_range = 0;
-  ourstatus->kind = TARGET_WAITKIND_IGNORE;
+  ourstatus->set_ignore ();
 
   auto status_pending_p_any = [&] (thread_info *thread)
     {
@@ -3006,7 +3004,7 @@  linux_process_target::wait_1 (ptid_t ptid, target_waitstatus *ourstatus,
 	  debug_exit ();
 	}
 
-      ourstatus->kind = TARGET_WAITKIND_IGNORE;
+      ourstatus->set_ignore ();
       return null_ptid;
     }
   else if (pid == -1)
@@ -3018,7 +3016,7 @@  linux_process_target::wait_1 (ptid_t ptid, target_waitstatus *ourstatus,
 	  debug_exit ();
 	}
 
-      ourstatus->kind = TARGET_WAITKIND_NO_RESUMED;
+      ourstatus->set_no_resumed ();
       return null_ptid;
     }
 
@@ -3030,8 +3028,7 @@  linux_process_target::wait_1 (ptid_t ptid, target_waitstatus *ourstatus,
     {
       if (WIFEXITED (w))
 	{
-	  ourstatus->kind = TARGET_WAITKIND_EXITED;
-	  ourstatus->value.integer = WEXITSTATUS (w);
+	  ourstatus->set_exited (WEXITSTATUS (w));
 
 	  if (debug_threads)
 	    {
@@ -3044,8 +3041,7 @@  linux_process_target::wait_1 (ptid_t ptid, target_waitstatus *ourstatus,
 	}
       else
 	{
-	  ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
-	  ourstatus->value.sig = gdb_signal_from_host (WTERMSIG (w));
+	  ourstatus->set_signalled (gdb_signal_from_host (WTERMSIG (w)));
 
 	  if (debug_threads)
 	    {
@@ -3057,7 +3053,7 @@  linux_process_target::wait_1 (ptid_t ptid, target_waitstatus *ourstatus,
 	    }
 	}
 
-      if (ourstatus->kind == TARGET_WAITKIND_EXITED)
+      if (ourstatus->kind () == TARGET_WAITKIND_EXITED)
 	return filter_exit_event (event_child, ourstatus);
 
       return ptid_of (current_thread);
@@ -3252,8 +3248,7 @@  linux_process_target::wait_1 (ptid_t ptid, target_waitstatus *ourstatus,
 
 	      if (stabilizing_threads)
 		{
-		  ourstatus->kind = TARGET_WAITKIND_STOPPED;
-		  ourstatus->value.sig = GDB_SIGNAL_0;
+		  ourstatus->set_stopped (GDB_SIGNAL_0);
 
 		  if (debug_threads)
 		    {
@@ -3378,7 +3373,7 @@  linux_process_target::wait_1 (ptid_t ptid, target_waitstatus *ourstatus,
 		   || (gdb_breakpoint_here (event_child->stop_pc)
 		       && gdb_condition_true_at_breakpoint (event_child->stop_pc)
 		       && gdb_no_commands_at_breakpoint (event_child->stop_pc))
-		   || event_child->waitstatus.kind != TARGET_WAITKIND_IGNORE);
+		   || event_child->waitstatus.kind () != TARGET_WAITKIND_IGNORE);
 
   run_breakpoint_commands (event_child->stop_pc);
 
@@ -3448,7 +3443,7 @@  linux_process_target::wait_1 (ptid_t ptid, target_waitstatus *ourstatus,
 
   if (debug_threads)
     {
-      if (event_child->waitstatus.kind != TARGET_WAITKIND_IGNORE)
+      if (event_child->waitstatus.kind () != TARGET_WAITKIND_IGNORE)
 	{
 	  std::string str
 	    = target_waitstatus_to_string (&event_child->waitstatus);
@@ -3589,14 +3584,14 @@  linux_process_target::wait_1 (ptid_t ptid, target_waitstatus *ourstatus,
 	unstop_all_lwps (1, event_child);
     }
 
-  if (event_child->waitstatus.kind != TARGET_WAITKIND_IGNORE)
+  if (event_child->waitstatus.kind () != TARGET_WAITKIND_IGNORE)
     {
       /* If the reported event is an exit, fork, vfork or exec, let
 	 GDB know.  */
 
       /* Break the unreported fork relationship chain.  */
-      if (event_child->waitstatus.kind == TARGET_WAITKIND_FORKED
-	  || event_child->waitstatus.kind == TARGET_WAITKIND_VFORKED)
+      if (event_child->waitstatus.kind () == TARGET_WAITKIND_FORKED
+	  || event_child->waitstatus.kind () == TARGET_WAITKIND_VFORKED)
 	{
 	  event_child->fork_relative->fork_relative = NULL;
 	  event_child->fork_relative = NULL;
@@ -3604,10 +3599,13 @@  linux_process_target::wait_1 (ptid_t ptid, target_waitstatus *ourstatus,
 
       *ourstatus = event_child->waitstatus;
       /* Clear the event lwp's waitstatus since we handled it already.  */
-      event_child->waitstatus.kind = TARGET_WAITKIND_IGNORE;
+      event_child->waitstatus.set_ignore ();
     }
   else
-    ourstatus->kind = TARGET_WAITKIND_STOPPED;
+    {
+      /* The actual stop signal is overwritten below.  */
+      ourstatus->set_stopped (GDB_SIGNAL_0);
+    }
 
   /* Now that we've selected our final event LWP, un-adjust its PC if
      it was a software breakpoint, and the client doesn't know we can
@@ -3627,9 +3625,15 @@  linux_process_target::wait_1 (ptid_t ptid, target_waitstatus *ourstatus,
 
   if (WSTOPSIG (w) == SYSCALL_SIGTRAP)
     {
-      get_syscall_trapinfo (event_child,
-			    &ourstatus->value.syscall_number);
-      ourstatus->kind = event_child->syscall_state;
+      int syscall_number;
+
+      get_syscall_trapinfo (event_child, &syscall_number);
+      if (event_child->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY)
+	ourstatus->set_syscall_entry (syscall_number);
+      else if (event_child->syscall_state == TARGET_WAITKIND_SYSCALL_RETURN)
+	ourstatus->set_syscall_return (syscall_number);
+      else
+	gdb_assert_not_reached ("unexpected syscall state");
     }
   else if (current_thread->last_resume_kind == resume_stop
 	   && WSTOPSIG (w) == SIGSTOP)
@@ -3637,31 +3641,29 @@  linux_process_target::wait_1 (ptid_t ptid, target_waitstatus *ourstatus,
       /* A thread that has been requested to stop by GDB with vCont;t,
 	 and it stopped cleanly, so report as SIG0.  The use of
 	 SIGSTOP is an implementation detail.  */
-      ourstatus->value.sig = GDB_SIGNAL_0;
+      ourstatus->set_stopped (GDB_SIGNAL_0);
     }
   else if (current_thread->last_resume_kind == resume_stop
 	   && WSTOPSIG (w) != SIGSTOP)
     {
       /* A thread that has been requested to stop by GDB with vCont;t,
 	 but, it stopped for other reasons.  */
-      ourstatus->value.sig = gdb_signal_from_host (WSTOPSIG (w));
-    }
-  else if (ourstatus->kind == TARGET_WAITKIND_STOPPED)
-    {
-      ourstatus->value.sig = gdb_signal_from_host (WSTOPSIG (w));
+      ourstatus->set_stopped (gdb_signal_from_host (WSTOPSIG (w)));
     }
+  else if (ourstatus->kind () == TARGET_WAITKIND_STOPPED)
+    ourstatus->set_stopped (gdb_signal_from_host (WSTOPSIG (w)));
 
   gdb_assert (step_over_bkpt == null_ptid);
 
   if (debug_threads)
     {
-      debug_printf ("wait_1 ret = %s, %d, %d\n",
+      debug_printf ("wait_1 ret = %s, %s\n",
 		    target_pid_to_str (ptid_of (current_thread)),
-		    ourstatus->kind, ourstatus->value.sig);
+		    target_waitstatus_to_string (ourstatus).c_str ());
       debug_exit ();
     }
 
-  if (ourstatus->kind == TARGET_WAITKIND_EXITED)
+  if (ourstatus->kind () == TARGET_WAITKIND_EXITED)
     return filter_exit_event (event_child, ourstatus);
 
   return ptid_of (current_thread);
@@ -3712,7 +3714,7 @@  linux_process_target::wait (ptid_t ptid,
     }
   while ((target_options & TARGET_WNOHANG) == 0
 	 && event_ptid == null_ptid
-	 && ourstatus->kind == TARGET_WAITKIND_IGNORE);
+	 && ourstatus->kind () == TARGET_WAITKIND_IGNORE);
 
   /* If at least one stop was reported, there may be more.  A single
      SIGCHLD can signal more than one child stop.  */
@@ -3813,15 +3815,9 @@  mark_lwp_dead (struct lwp_info *lwp, int wstat)
   /* Store in waitstatus as well, as there's nothing else to process
      for this event.  */
   if (WIFEXITED (wstat))
-    {
-      lwp->waitstatus.kind = TARGET_WAITKIND_EXITED;
-      lwp->waitstatus.value.integer = WEXITSTATUS (wstat);
-    }
+    lwp->waitstatus.set_exited (WEXITSTATUS (wstat));
   else if (WIFSIGNALED (wstat))
-    {
-      lwp->waitstatus.kind = TARGET_WAITKIND_SIGNALLED;
-      lwp->waitstatus.value.sig = gdb_signal_from_host (WTERMSIG (wstat));
-    }
+    lwp->waitstatus.set_signalled (gdb_signal_from_host (WTERMSIG (wstat)));
 
   /* Prevent trying to stop it.  */
   lwp->stopped = 1;
@@ -4087,7 +4083,7 @@  linux_process_target::resume_one_lwp_throw (lwp_info *lwp, int step,
   if (lwp->stopped == 0)
     return;
 
-  gdb_assert (lwp->waitstatus.kind == TARGET_WAITKIND_IGNORE);
+  gdb_assert (lwp->waitstatus.kind () == TARGET_WAITKIND_IGNORE);
 
   fast_tpoint_collect_result fast_tp_collecting
     = lwp->collecting_fast_tracepoint;
@@ -4351,7 +4347,7 @@  linux_set_resume_request (thread_info *thread, thread_resume *resume, size_t n)
 	    {
 	      if (debug_threads)
 		debug_printf ("already %s LWP %ld at GDB's request\n",
-			      (thread->last_status.kind
+			      (thread->last_status.kind ()
 			       == TARGET_WAITKIND_STOPPED)
 			      ? "stopped"
 			      : "stopping",
@@ -4382,8 +4378,8 @@  linux_set_resume_request (thread_info *thread, thread_resume *resume, size_t n)
 	      struct lwp_info *rel = lwp->fork_relative;
 
 	      if (rel->status_pending_p
-		  && (rel->waitstatus.kind == TARGET_WAITKIND_FORKED
-		      || rel->waitstatus.kind == TARGET_WAITKIND_VFORKED))
+		  && (rel->waitstatus.kind () == TARGET_WAITKIND_FORKED
+		      || rel->waitstatus.kind () == TARGET_WAITKIND_VFORKED))
 		{
 		  if (debug_threads)
 		    debug_printf ("not resuming LWP %ld: has queued stop reply\n",
@@ -4771,7 +4767,7 @@  linux_process_target::resume_one_thread (thread_info *thread,
 
       /* For stop requests, we're done.  */
       lwp->resume = NULL;
-      thread->last_status.kind = TARGET_WAITKIND_IGNORE;
+      thread->last_status.set_ignore ();
       return;
     }
 
@@ -4818,7 +4814,7 @@  linux_process_target::resume_one_thread (thread_info *thread,
 	debug_printf ("leaving LWP %ld stopped\n", lwpid_of (thread));
     }
 
-  thread->last_status.kind = TARGET_WAITKIND_IGNORE;
+  thread->last_status.set_ignore ();
   lwp->resume = NULL;
 }
 
@@ -4918,7 +4914,7 @@  linux_process_target::proceed_one_lwp (thread_info *thread, lwp_info *except)
     }
 
   if (thread->last_resume_kind == resume_stop
-      && thread->last_status.kind != TARGET_WAITKIND_IGNORE)
+      && thread->last_status.kind () != TARGET_WAITKIND_IGNORE)
     {
       if (debug_threads)
 	debug_printf ("   client wants LWP to remain %ld stopped\n",
diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
index c6a17a498f5..05067ffc6e6 100644
--- a/gdbserver/linux-low.h
+++ b/gdbserver/linux-low.h
@@ -721,11 +721,6 @@  struct pending_signal
 
 struct lwp_info
 {
-  lwp_info ()
-  {
-    this->waitstatus.kind = TARGET_WAITKIND_IGNORE;
-  }
-
   /* Backlink to the parent object.  */
   struct thread_info *thread = nullptr;
 
diff --git a/gdbserver/netbsd-low.cc b/gdbserver/netbsd-low.cc
index 84e34d0e065..ada92c1fd60 100644
--- a/gdbserver/netbsd-low.cc
+++ b/gdbserver/netbsd-low.cc
@@ -206,20 +206,11 @@  static void
 netbsd_store_waitstatus (struct target_waitstatus *ourstatus, int hoststatus)
 {
   if (WIFEXITED (hoststatus))
-    {
-      ourstatus->kind = TARGET_WAITKIND_EXITED;
-      ourstatus->value.integer = WEXITSTATUS (hoststatus);
-    }
+    ourstatus->set_exited (WEXITSTATUS (hoststatus));
   else if (!WIFSTOPPED (hoststatus))
-    {
-      ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
-      ourstatus->value.sig = gdb_signal_from_host (WTERMSIG (hoststatus));
-    }
+    ourstatus->set_signalled (gdb_signal_from_host (WTERMSIG (hoststatus)));
   else
-    {
-      ourstatus->kind = TARGET_WAITKIND_STOPPED;
-      ourstatus->value.sig = gdb_signal_from_host (WSTOPSIG (hoststatus));
-    }
+    ourstatus->set_stopped (gdb_signal_from_host (WSTOPSIG (hoststatus)));
 }
 
 /* Implement a safe wrapper around waitpid().  */
@@ -258,14 +249,14 @@  netbsd_wait (ptid_t ptid, struct target_waitstatus *ourstatus,
   if (pid == 0)
     {
       gdb_assert (target_options & TARGET_WNOHANG);
-      ourstatus->kind = TARGET_WAITKIND_IGNORE;
+      ourstatus->set_ignore ();
       return null_ptid;
     }
 
   gdb_assert (pid != -1);
 
   /* If the child stopped, keep investigating its status.  */
-  if (ourstatus->kind != TARGET_WAITKIND_STOPPED)
+  if (ourstatus->kind () != TARGET_WAITKIND_STOPPED)
     return wptid;
 
   /* Extract the event and thread that received a signal.  */
@@ -307,12 +298,11 @@  netbsd_wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 	 Ignore exited events for an unknown LWP.  */
       thread_info *thr = find_thread_ptid (wptid);
       if (thr == nullptr)
-	  ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+	  ourstatus->set_spurious ();
       else
 	{
-	  ourstatus->kind = TARGET_WAITKIND_THREAD_EXITED;
 	  /* NetBSD does not store an LWP exit status.  */
-	  ourstatus->value.integer = 0;
+	  ourstatus->set_thread_exited (0);
 
 	  remove_thread (thr);
 	}
@@ -329,20 +319,19 @@  netbsd_wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 	 not yet reported their PTRACE_LWP_CREATE event.  Ignore
 	 born events for an already-known LWP.  */
       if (find_thread_ptid (wptid))
-	  ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+	ourstatus->set_spurious ();
       else
 	{
 	  add_thread (wptid, NULL);
-	  ourstatus->kind = TARGET_WAITKIND_THREAD_CREATED;
+	  ourstatus->set_thread_created ();
 	}
       return wptid;
     }
 
   if (code == TRAP_EXEC)
     {
-      ourstatus->kind = TARGET_WAITKIND_EXECD;
-      ourstatus->value.execd_pathname
-	= xstrdup (netbsd_nat::pid_to_exec_file (pid));
+      ourstatus->set_execd
+	(make_unique_xstrdup (netbsd_nat::pid_to_exec_file (pid)));
       return wptid;
     }
 
@@ -356,14 +345,15 @@  netbsd_wait (ptid_t ptid, struct target_waitstatus *ourstatus,
       if (!netbsd_catch_this_syscall(sysnum))
 	{
 	  /* If the core isn't interested in this event, ignore it.  */
-	  ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+	  ourstatus->set_spurious ();
 	  return wptid;
 	}
 
-      ourstatus->kind
-	= ((code == TRAP_SCE) ? TARGET_WAITKIND_SYSCALL_ENTRY :
-	   TARGET_WAITKIND_SYSCALL_RETURN);
-      ourstatus->value.syscall_number = sysnum;
+      if (code == TRAP_SCE)
+	ourstatus->set_syscall_entry (sysnum);
+      else
+	ourstatus->set_syscall_return (sysnum);
+
       return wptid;
     }
 
@@ -381,7 +371,7 @@  netbsd_wait (ptid_t ptid, struct target_waitstatus *ourstatus,
     }
 
   /* Unclassified SIGTRAP event.  */
-  ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+  ourstatus->set_spurious ();
   return wptid;
 }
 
@@ -401,10 +391,10 @@  netbsd_process_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 	 This may also happen on attach, when an event is registered on a thread
 	 that was not fully initialized during the attach stage.  */
       if (wptid.lwp () != 0 && !find_thread_ptid (wptid)
-	  && ourstatus->kind != TARGET_WAITKIND_THREAD_EXITED)
+	  && ourstatus->kind () != TARGET_WAITKIND_THREAD_EXITED)
 	add_thread (wptid, nullptr);
 
-      switch (ourstatus->kind)
+      switch (ourstatus->kind ())
 	{
 	case TARGET_WAITKIND_EXITED:
 	case TARGET_WAITKIND_STOPPED:
diff --git a/gdbserver/remote-utils.cc b/gdbserver/remote-utils.cc
index b79c2aae498..a4cc3267996 100644
--- a/gdbserver/remote-utils.cc
+++ b/gdbserver/remote-utils.cc
@@ -1087,9 +1087,9 @@  prepare_resume_reply (char *buf, ptid_t ptid,
   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);
+		  target_pid_to_str (ptid), status->kind ());
 
-  switch (status->kind)
+  switch (status->kind ())
     {
     case TARGET_WAITKIND_STOPPED:
     case TARGET_WAITKIND_FORKED:
@@ -1104,27 +1104,27 @@  prepare_resume_reply (char *buf, ptid_t ptid,
 	const char **regp;
 	struct regcache *regcache;
 
-	if ((status->kind == TARGET_WAITKIND_FORKED && cs.report_fork_events)
-	    || (status->kind == TARGET_WAITKIND_VFORKED 
+	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
+	    const char *event = (status->kind () == TARGET_WAITKIND_FORKED
 				 ? "fork" : "vfork");
 
 	    sprintf (buf, "T%02x%s:", signal, event);
 	    buf += strlen (buf);
-	    buf = write_ptid (buf, status->value.related_pid);
+	    buf = write_ptid (buf, status->child_ptid ());
 	    strcat (buf, ";");
 	  }
-	else if (status->kind == TARGET_WAITKIND_VFORK_DONE 
+	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 && cs.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";
@@ -1134,34 +1134,32 @@  prepare_resume_reply (char *buf, ptid_t ptid,
 	    buf += strlen (buf);
 
 	    /* Encode pathname to hexified format.  */
-	    bin2hex ((const gdb_byte *) status->value.execd_pathname,
+	    bin2hex ((const gdb_byte *) status->execd_pathname (),
 		     hexified_pathname,
-		     strlen (status->value.execd_pathname));
+		     strlen (status->execd_pathname ()));
 
 	    sprintf (buf, "%s;", hexified_pathname);
-	    xfree (status->value.execd_pathname);
-	    status->value.execd_pathname = NULL;
 	    buf += strlen (buf);
 	  }
-	else if (status->kind == TARGET_WAITKIND_THREAD_CREATED
+	else if (status->kind () == TARGET_WAITKIND_THREAD_CREATED
 		 && cs.report_thread_events)
 	  {
 	    enum gdb_signal signal = GDB_SIGNAL_TRAP;
 
 	    sprintf (buf, "T%02xcreate:;", signal);
 	  }
-	else if (status->kind == TARGET_WAITKIND_SYSCALL_ENTRY
-		 || status->kind == TARGET_WAITKIND_SYSCALL_RETURN)
+	else if (status->kind () == TARGET_WAITKIND_SYSCALL_ENTRY
+		 || status->kind () == TARGET_WAITKIND_SYSCALL_RETURN)
 	  {
 	    enum gdb_signal signal = GDB_SIGNAL_TRAP;
-	    const char *event = (status->kind == TARGET_WAITKIND_SYSCALL_ENTRY
+	    const char *event = (status->kind () == TARGET_WAITKIND_SYSCALL_ENTRY
 				 ? "syscall_entry" : "syscall_return");
 
 	    sprintf (buf, "T%02x%s:%x;", signal, event,
-		     status->value.syscall_number);
+		     status->syscall_number ());
 	  }
 	else
-	  sprintf (buf, "T%02x", status->value.sig);
+	  sprintf (buf, "T%02x", status->sig ());
 
 	if (disable_packet_T)
 	  {
@@ -1283,19 +1281,19 @@  prepare_resume_reply (char *buf, ptid_t ptid,
     case TARGET_WAITKIND_EXITED:
       if (cs.multi_process)
 	sprintf (buf, "W%x;process:%x",
-		 status->value.integer, ptid.pid ());
+		 status->exit_status (), ptid.pid ());
       else
-	sprintf (buf, "W%02x", status->value.integer);
+	sprintf (buf, "W%02x", status->exit_status ());
       break;
     case TARGET_WAITKIND_SIGNALLED:
       if (cs.multi_process)
 	sprintf (buf, "X%x;process:%x",
-		 status->value.sig, ptid.pid ());
+		 status->sig (), ptid.pid ());
       else
-	sprintf (buf, "X%02x", status->value.sig);
+	sprintf (buf, "X%02x", status->sig ());
       break;
     case TARGET_WAITKIND_THREAD_EXITED:
-      sprintf (buf, "w%x;", status->value.integer);
+      sprintf (buf, "w%x;", status->exit_status ());
       buf += strlen (buf);
       buf = write_ptid (buf, ptid);
       break;
diff --git a/gdbserver/server.cc b/gdbserver/server.cc
index 193c3d9d7d1..2cb378ce9c9 100644
--- a/gdbserver/server.cc
+++ b/gdbserver/server.cc
@@ -239,9 +239,9 @@  in_queued_stop_replies_ptid (struct notif_event *event, ptid_t filter_ptid)
     return true;
 
   /* Don't resume fork children that GDB does not know about yet.  */
-  if ((vstop_event->status.kind == TARGET_WAITKIND_FORKED
-       || vstop_event->status.kind == TARGET_WAITKIND_VFORKED)
-      && vstop_event->status.value.related_pid.matches (filter_ptid))
+  if ((vstop_event->status.kind () == TARGET_WAITKIND_FORKED
+       || vstop_event->status.kind () == TARGET_WAITKIND_VFORKED)
+      && vstop_event->status.child_ptid ().matches (filter_ptid))
     return true;
 
   return false;
@@ -327,9 +327,9 @@  attach_inferior (int pid)
       /* GDB knows to ignore the first SIGSTOP after attaching to a running
 	 process using the "attach" command, but this is different; it's
 	 just using "target remote".  Pretend it's just starting up.  */
-      if (cs.last_status.kind == TARGET_WAITKIND_STOPPED
-	  && cs.last_status.value.sig == GDB_SIGNAL_STOP)
-	cs.last_status.value.sig = GDB_SIGNAL_TRAP;
+      if (cs.last_status.kind () == TARGET_WAITKIND_STOPPED
+	  && cs.last_status.sig () == GDB_SIGNAL_STOP)
+	cs.last_status.set_stopped (GDB_SIGNAL_TRAP);
 
       current_thread->last_resume_kind = resume_stop;
       current_thread->last_status = cs.last_status;
@@ -1262,8 +1262,7 @@  handle_detach (char *own_buf)
 	  /* There is still at least one inferior remaining or
 	     we are in extended mode, so don't terminate gdbserver,
 	     and instead treat this like a normal program exit.  */
-	  cs.last_status.kind = TARGET_WAITKIND_EXITED;
-	  cs.last_status.value.integer = 0;
+	  cs.last_status.set_exited (0);
 	  cs.last_ptid = ptid_t (pid);
 
 	  current_thread = NULL;
@@ -2944,7 +2943,7 @@  resume (struct thread_resume *actions, size_t num_actions)
     {
       cs.last_ptid = mywait (minus_one_ptid, &cs.last_status, 0, 1);
 
-      if (cs.last_status.kind == TARGET_WAITKIND_NO_RESUMED
+      if (cs.last_status.kind () == TARGET_WAITKIND_NO_RESUMED
 	  && !report_no_resumed)
 	{
 	  /* The client does not support this stop reply.  At least
@@ -2954,9 +2953,9 @@  resume (struct thread_resume *actions, size_t num_actions)
 	  return;
 	}
 
-      if (cs.last_status.kind != TARGET_WAITKIND_EXITED
-	  && cs.last_status.kind != TARGET_WAITKIND_SIGNALLED
-	  && cs.last_status.kind != TARGET_WAITKIND_NO_RESUMED)
+      if (cs.last_status.kind () != TARGET_WAITKIND_EXITED
+	  && cs.last_status.kind () != TARGET_WAITKIND_SIGNALLED
+	  && cs.last_status.kind () != TARGET_WAITKIND_NO_RESUMED)
 	current_thread->last_status = cs.last_status;
 
       /* From the client's perspective, all-stop mode always stops all
@@ -2967,8 +2966,8 @@  resume (struct thread_resume *actions, size_t num_actions)
       prepare_resume_reply (cs.own_buf, cs.last_ptid, &cs.last_status);
       disable_async_io ();
 
-      if (cs.last_status.kind == TARGET_WAITKIND_EXITED
-	  || cs.last_status.kind == TARGET_WAITKIND_SIGNALLED)
+      if (cs.last_status.kind () == TARGET_WAITKIND_EXITED
+	  || cs.last_status.kind () == TARGET_WAITKIND_SIGNALLED)
 	target_mourn_inferior (cs.last_ptid);
     }
 }
@@ -3113,7 +3112,7 @@  handle_v_run (char *own_buf)
 
   target_create_inferior (program_path.get (), program_args);
 
-  if (cs.last_status.kind == TARGET_WAITKIND_STOPPED)
+  if (cs.last_status.kind () == TARGET_WAITKIND_STOPPED)
     {
       prepare_resume_reply (own_buf, cs.last_ptid, &cs.last_status);
 
@@ -3143,8 +3142,7 @@  handle_v_kill (char *own_buf)
 
   if (proc != nullptr && kill_inferior (proc) == 0)
     {
-      cs.last_status.kind = TARGET_WAITKIND_SIGNALLED;
-      cs.last_status.value.sig = GDB_SIGNAL_KILL;
+      cs.last_status.set_signalled (GDB_SIGNAL_KILL);
       cs.last_ptid = ptid_t (pid);
       discard_queued_stop_replies (cs.last_ptid);
       write_ok (own_buf);
@@ -3316,7 +3314,7 @@  queue_stop_reply_callback (thread_info *thread)
 			    status_string.c_str ());
 	    }
 
-	  gdb_assert (thread->last_status.kind != TARGET_WAITKIND_IGNORE);
+	  gdb_assert (thread->last_status.kind () != TARGET_WAITKIND_IGNORE);
 
 	  /* Pass the last stop reply back to GDB, but don't notify
 	     yet.  */
@@ -3334,12 +3332,11 @@  gdb_wants_thread_stopped (thread_info *thread)
 {
   thread->last_resume_kind = resume_stop;
 
-  if (thread->last_status.kind == TARGET_WAITKIND_IGNORE)
+  if (thread->last_status.kind () == TARGET_WAITKIND_IGNORE)
     {
       /* Most threads are stopped implicitly (all-stop); tag that with
 	 signal 0.  */
-      thread->last_status.kind = TARGET_WAITKIND_STOPPED;
-      thread->last_status.value.sig = GDB_SIGNAL_0;
+      thread->last_status.set_stopped (GDB_SIGNAL_0);
     }
 }
 
@@ -3357,15 +3354,15 @@  gdb_wants_all_threads_stopped (void)
 static void
 set_pending_status_callback (thread_info *thread)
 {
-  if (thread->last_status.kind != TARGET_WAITKIND_STOPPED
-      || (thread->last_status.value.sig != GDB_SIGNAL_0
+  if (thread->last_status.kind () != TARGET_WAITKIND_STOPPED
+      || (thread->last_status.sig () != GDB_SIGNAL_0
 	  /* A breakpoint, watchpoint or finished step from a previous
 	     GDB run isn't considered interesting for a new GDB run.
 	     If we left those pending, the new GDB could consider them
 	     random SIGTRAPs.  This leaves out real async traps.  We'd
 	     have to peek into the (target-specific) siginfo to
 	     distinguish those.  */
-	  && thread->last_status.value.sig != GDB_SIGNAL_TRAP))
+	  && thread->last_status.sig () != GDB_SIGNAL_TRAP))
     thread->status_pending_p = 1;
 }
 
@@ -3412,9 +3409,9 @@  handle_status (char *own_buf)
 
       /* Prefer the last thread that reported an event to GDB (even if
 	 that was a GDB_SIGNAL_TRAP).  */
-      if (cs.last_status.kind != TARGET_WAITKIND_IGNORE
-	  && cs.last_status.kind != TARGET_WAITKIND_EXITED
-	  && cs.last_status.kind != TARGET_WAITKIND_SIGNALLED)
+      if (cs.last_status.kind () != TARGET_WAITKIND_IGNORE
+	  && cs.last_status.kind () != TARGET_WAITKIND_EXITED
+	  && cs.last_status.kind () != TARGET_WAITKIND_SIGNALLED)
 	thread = find_thread_ptid (cs.last_ptid);
 
       /* If the last event thread is not found for some reason, look
@@ -3443,7 +3440,7 @@  handle_status (char *own_buf)
 	  cs.general_thread = thread->id;
 	  set_desired_thread ();
 
-	  gdb_assert (tp->last_status.kind != TARGET_WAITKIND_IGNORE);
+	  gdb_assert (tp->last_status.kind () != TARGET_WAITKIND_IGNORE);
 	  prepare_resume_reply (own_buf, tp->id, &tp->last_status);
 	}
       else
@@ -3989,8 +3986,7 @@  captured_main (int argc, char *argv[])
     }
   else
     {
-      cs.last_status.kind = TARGET_WAITKIND_EXITED;
-      cs.last_status.value.integer = 0;
+      cs.last_status.set_exited (0);
       cs.last_ptid = minus_one_ptid;
     }
 
@@ -4002,8 +3998,8 @@  captured_main (int argc, char *argv[])
   if (current_thread != nullptr)
     current_process ()->dlls_changed = false;
 
-  if (cs.last_status.kind == TARGET_WAITKIND_EXITED
-      || cs.last_status.kind == TARGET_WAITKIND_SIGNALLED)
+  if (cs.last_status.kind () == TARGET_WAITKIND_EXITED
+      || cs.last_status.kind () == TARGET_WAITKIND_SIGNALLED)
     was_running = 0;
   else
     was_running = 1;
@@ -4456,8 +4452,7 @@  process_serial_event (void)
 	 running.  The traditional protocol will exit instead.  */
       if (extended_protocol)
 	{
-	  cs.last_status.kind = TARGET_WAITKIND_EXITED;
-	  cs.last_status.value.sig = GDB_SIGNAL_KILL;
+	  cs.last_status.set_exited (GDB_SIGNAL_KILL);
 	  return 0;
 	}
       else
@@ -4497,7 +4492,7 @@  process_serial_event (void)
 	    {
 	      target_create_inferior (program_path.get (), program_args);
 
-	      if (cs.last_status.kind == TARGET_WAITKIND_STOPPED)
+	      if (cs.last_status.kind () == TARGET_WAITKIND_STOPPED)
 		{
 		  /* Stopped at the first instruction of the target
 		     process.  */
@@ -4511,8 +4506,7 @@  process_serial_event (void)
 	    }
 	  else
 	    {
-	      cs.last_status.kind = TARGET_WAITKIND_EXITED;
-	      cs.last_status.value.sig = GDB_SIGNAL_KILL;
+	      cs.last_status.set_exited (GDB_SIGNAL_KILL);
 	    }
 	  return 0;
 	}
@@ -4595,24 +4589,24 @@  handle_target_event (int err, gdb_client_data client_data)
   cs.last_ptid = mywait (minus_one_ptid, &cs.last_status,
 		      TARGET_WNOHANG, 1);
 
-  if (cs.last_status.kind == TARGET_WAITKIND_NO_RESUMED)
+  if (cs.last_status.kind () == TARGET_WAITKIND_NO_RESUMED)
     {
       if (gdb_connected () && report_no_resumed)
 	push_stop_notification (null_ptid, &cs.last_status);
     }
-  else if (cs.last_status.kind != TARGET_WAITKIND_IGNORE)
+  else if (cs.last_status.kind () != TARGET_WAITKIND_IGNORE)
     {
       int pid = cs.last_ptid.pid ();
       struct process_info *process = find_process_pid (pid);
       int forward_event = !gdb_connected () || process->gdb_detached;
 
-      if (cs.last_status.kind == TARGET_WAITKIND_EXITED
-	  || cs.last_status.kind == TARGET_WAITKIND_SIGNALLED)
+      if (cs.last_status.kind () == TARGET_WAITKIND_EXITED
+	  || cs.last_status.kind () == TARGET_WAITKIND_SIGNALLED)
 	{
 	  mark_breakpoints_out (process);
 	  target_mourn_inferior (cs.last_ptid);
 	}
-      else if (cs.last_status.kind == TARGET_WAITKIND_THREAD_EXITED)
+      else if (cs.last_status.kind () == TARGET_WAITKIND_THREAD_EXITED)
 	;
       else
 	{
@@ -4631,9 +4625,9 @@  handle_target_event (int err, gdb_client_data client_data)
 	      exit (0);
 	    }
 
-	  if (cs.last_status.kind == TARGET_WAITKIND_EXITED
-	      || cs.last_status.kind == TARGET_WAITKIND_SIGNALLED
-	      || cs.last_status.kind == TARGET_WAITKIND_THREAD_EXITED)
+	  if (cs.last_status.kind () == TARGET_WAITKIND_EXITED
+	      || cs.last_status.kind () == TARGET_WAITKIND_SIGNALLED
+	      || cs.last_status.kind () == TARGET_WAITKIND_THREAD_EXITED)
 	    ;
 	  else
 	    {
@@ -4645,11 +4639,11 @@  handle_target_event (int err, gdb_client_data client_data)
 	      if (debug_threads)
 		debug_printf ("GDB not connected; forwarding event %d for"
 			      " [%s]\n",
-			      (int) cs.last_status.kind,
+			      (int) cs.last_status.kind (),
 			      target_pid_to_str (cs.last_ptid));
 
-	      if (cs.last_status.kind == TARGET_WAITKIND_STOPPED)
-		signal = cs.last_status.value.sig;
+	      if (cs.last_status.kind () == TARGET_WAITKIND_STOPPED)
+		signal = cs.last_status.sig ();
 	      else
 		signal = GDB_SIGNAL_0;
 	      target_continue (cs.last_ptid, signal);
diff --git a/gdbserver/target.cc b/gdbserver/target.cc
index 988c6d50c5c..b6a1cb24025 100644
--- a/gdbserver/target.cc
+++ b/gdbserver/target.cc
@@ -172,8 +172,8 @@  mywait (ptid_t ptid, struct target_waitstatus *ourstatus,
 
   /* We don't expose _LOADED events to gdbserver core.  See the
      `dlls_changed' global.  */
-  if (ourstatus->kind == TARGET_WAITKIND_LOADED)
-    ourstatus->kind = TARGET_WAITKIND_STOPPED;
+  if (ourstatus->kind () == TARGET_WAITKIND_LOADED)
+    ourstatus->set_stopped (GDB_SIGNAL_0);
 
   /* If GDB is connected through TCP/serial, then GDBserver will most
      probably be running on its own terminal/console, so it's nice to
@@ -183,13 +183,13 @@  mywait (ptid_t ptid, struct target_waitstatus *ourstatus,
      regular GDB output, in that same terminal.  */
   if (!remote_connection_is_stdio ())
     {
-      if (ourstatus->kind == TARGET_WAITKIND_EXITED)
+      if (ourstatus->kind () == TARGET_WAITKIND_EXITED)
 	fprintf (stderr,
-		 "\nChild exited with status %d\n", ourstatus->value.integer);
-      else if (ourstatus->kind == TARGET_WAITKIND_SIGNALLED)
+		 "\nChild exited with status %d\n", ourstatus->exit_status ());
+      else if (ourstatus->kind () == TARGET_WAITKIND_SIGNALLED)
 	fprintf (stderr, "\nChild terminated with signal = 0x%x (%s)\n",
-		 gdb_signal_to_host (ourstatus->value.sig),
-		 gdb_signal_to_name (ourstatus->value.sig));
+		 gdb_signal_to_host (ourstatus->sig ()),
+		 gdb_signal_to_name (ourstatus->sig ()));
     }
 
   if (connected_wait)
diff --git a/gdbserver/win32-low.cc b/gdbserver/win32-low.cc
index 1e97f91d954..cc981d3988e 100644
--- a/gdbserver/win32-low.cc
+++ b/gdbserver/win32-low.cc
@@ -374,7 +374,7 @@  do_initial_child_stuff (HANDLE proch, DWORD pid, int attached)
   if (the_low_target.initial_stuff != NULL)
     (*the_low_target.initial_stuff) ();
 
-  cached_status.kind = TARGET_WAITKIND_IGNORE;
+  cached_status.set_ignore ();
 
   /* Flush all currently pending debug events (thread and dll list) up
      to the initial breakpoint.  */
@@ -385,7 +385,7 @@  do_initial_child_stuff (HANDLE proch, DWORD pid, int attached)
       the_target->wait (minus_one_ptid, &status, 0);
 
       /* Note win32_wait doesn't return thread events.  */
-      if (status.kind != TARGET_WAITKIND_LOADED)
+      if (status.kind () != TARGET_WAITKIND_LOADED)
 	{
 	  cached_status = status;
 	  break;
@@ -1081,7 +1081,7 @@  get_child_debug_event (DWORD *continue_status,
   ptid_t ptid;
 
   last_sig = GDB_SIGNAL_0;
-  ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+  ourstatus->set_spurious ();
   *continue_status = DBG_CONTINUE;
 
   /* Check if GDB sent us an interrupt request.  */
@@ -1119,8 +1119,7 @@  get_child_debug_event (DWORD *continue_status,
 	       load the application, e.g., if the main executable
 	       tries to pull in a non-existing export from a
 	       DLL.  */
-	    ourstatus->kind = TARGET_WAITKIND_EXITED;
-	    ourstatus->value.integer = 1;
+	    ourstatus->set_exited (1);
 	    return 1;
 	  }
 
@@ -1192,15 +1191,9 @@  get_child_debug_event (DWORD *continue_status,
 	int exit_signal
 	  = WIFSIGNALED (exit_status) ? WTERMSIG (exit_status) : -1;
 	if (exit_signal == -1)
-	  {
-	    ourstatus->kind = TARGET_WAITKIND_EXITED;
-	    ourstatus->value.integer = exit_status;
-	  }
+	  ourstatus->set_exited (exit_status);
 	else
-	  {
-	    ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
-	    ourstatus->value.sig = gdb_signal_from_host (exit_signal);
-	  }
+	  ourstatus->set_signalled (gdb_signal_from_host (exit_signal));
       }
       child_continue (DBG_CONTINUE, desired_stop_thread_id);
       break;
@@ -1215,8 +1208,7 @@  get_child_debug_event (DWORD *continue_status,
 	break;
       dll_loaded_event ();
 
-      ourstatus->kind = TARGET_WAITKIND_LOADED;
-      ourstatus->value.sig = GDB_SIGNAL_TRAP;
+      ourstatus->set_loaded ();
       break;
 
     case UNLOAD_DLL_DEBUG_EVENT:
@@ -1227,8 +1219,7 @@  get_child_debug_event (DWORD *continue_status,
       if (! child_initialization_done)
 	break;
       handle_unload_dll ();
-      ourstatus->kind = TARGET_WAITKIND_LOADED;
-      ourstatus->value.sig = GDB_SIGNAL_TRAP;
+      ourstatus->set_loaded ();
       break;
 
     case EXCEPTION_DEBUG_EVENT:
@@ -1270,7 +1261,7 @@  get_child_debug_event (DWORD *continue_status,
 		ptid.lwp (), desired_stop_thread_id));
       maybe_adjust_pc ();
       pending_stops.push_back ({(DWORD) ptid.lwp (), *ourstatus, current_event});
-      ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+      ourstatus->set_spurious ();
     }
   else
     current_thread = find_thread_ptid (ptid);
@@ -1285,14 +1276,14 @@  ptid_t
 win32_process_target::wait (ptid_t ptid, target_waitstatus *ourstatus,
 			    target_wait_flags options)
 {
-  if (cached_status.kind != TARGET_WAITKIND_IGNORE)
+  if (cached_status.kind () != TARGET_WAITKIND_IGNORE)
     {
       /* The core always does a wait after creating the inferior, and
 	 do_initial_child_stuff already ran the inferior to the
 	 initial breakpoint (or an exit, if creating the process
 	 fails).  Report it now.  */
       *ourstatus = cached_status;
-      cached_status.kind = TARGET_WAITKIND_IGNORE;
+      cached_status.set_ignore ();
       return debug_event_ptid (&current_event);
     }
 
@@ -1302,11 +1293,11 @@  win32_process_target::wait (ptid_t ptid, target_waitstatus *ourstatus,
       if (!get_child_debug_event (&continue_status, ourstatus))
 	continue;
 
-      switch (ourstatus->kind)
+      switch (ourstatus->kind ())
 	{
 	case TARGET_WAITKIND_EXITED:
 	  OUTMSG2 (("Child exited with retcode = %x\n",
-		    ourstatus->value.integer));
+		    ourstatus->exit_status ()));
 	  win32_clear_inferiors ();
 	  return ptid_t (current_event.dwProcessId);
 	case TARGET_WAITKIND_STOPPED:
@@ -1314,12 +1305,13 @@  win32_process_target::wait (ptid_t ptid, target_waitstatus *ourstatus,
 	case TARGET_WAITKIND_LOADED:
 	  {
 	    OUTMSG2 (("Child Stopped with signal = %d \n",
-		      ourstatus->value.sig));
+		      ourstatus->sig ()));
 	    maybe_adjust_pc ();
 	    return debug_event_ptid (&current_event);
 	  }
 	default:
-	  OUTMSG (("Ignoring unknown internal event, %d\n", ourstatus->kind));
+	  OUTMSG (("Ignoring unknown internal event, %d\n",
+		  ourstatus->kind ()));
 	  /* fall-through */
 	case TARGET_WAITKIND_SPURIOUS:
 	  /* do nothing, just continue */