[2/6] Introduce throw_ptrace_error

Message ID 1425671886-7798-3-git-send-email-palves@redhat.com
State New, archived
Headers

Commit Message

Pedro Alves March 6, 2015, 7:58 p.m. UTC
  This adds a new function that is meant to be called instead of
perror_with_name whenever we get an error out of ptrace.  The
idea is to convert some errno errors to different GDB exceptions in
a following patch.

gdb/
2015-03-06  Pedro Alves  <palves@redhat.com>

	* Makefile.in (HFILES_NO_SRCDIR): Add nat/ptrace-utils.h.
	(ptrace-utils.o): New rule.
	* aarch64-linux-nat.c: Include nat/ptrace-utils.h and use
	throw_ptrace error intead of perror_with_name.
	* alphabsd-nat.c, amd64-linux-nat.c, amd64bsd-nat.c,
	arm-linux-nat.c, hppabsd-nat.c, hppanbsd-nat.c, i386-linux-nat.c,
	i386bsd-nat.c, i386fbsd-nat.c, inf-ptrace.c, linux-nat.c,
	m32r-linux-nat.c, m68kbsd-nat.c, m68klinux-nat.c, m88kbsd-nat.c,
	mips-linux-nat.c, mips64obsd-nat.c, mipsnbsd-nat.c, obsd-nat.c,
	ppc-linux-nat.c, ppcfbsd-nat.c, ppcnbsd-nat.c, ppcobsd-nat.c,
	rs6000-nat.c, shnbsd-nat.c, sparc-nat.c, spu-linux-nat.c,
	tilegx-linux-nat.c, vaxbsd-nat.c, x86-linux-nat.c,
	xtensa-linux-nat.c.
	* nat/ptrace-utils.c: New file.
	* nat/ptrace-utils.h: New file.
	* config/aarch64/linux.mh, config/alpha/alpha-linux.mh,
	config/alpha/fbsd.mh, config/alpha/nbsd.mh, config/arm/linux.mh,
	config/i386/fbsd.mh, config/i386/fbsd64.mh, config/i386/linux.mh,
	config/i386/linux64.mh, config/i386/nbsdelf.mh,
	config/i386/obsd.mh, config/i386/obsd64.mh, config/ia64/linux.mh,
	config/m32r/linux.mh, config/m68k/linux.mh,
	config/m68k/nbsdelf.mh, config/m68k/obsd.mh, config/m88k/obsd.mh,
	config/mips/linux.mh, config/mips/nbsd.mh, config/mips/obsd64.mh,
	config/pa/hpux.mh, config/pa/linux.mh, config/pa/nbsd.mh,
	config/pa/obsd.mh, config/powerpc/fbsd.mh,
	config/powerpc/linux.mh, config/powerpc/nbsd.mh,
	config/powerpc/obsd.mh, config/powerpc/ppc64-linux.mh,
	config/powerpc/spu-linux.mh, config/s390/linux.mh,
	config/sh/nbsd.mh, config/sparc/fbsd.mh, config/sparc/linux.mh,
	config/sparc/linux64.mh, config/sparc/nbsd64.mh,
	config/sparc/nbsdelf.mh, config/sparc/obsd64.mh,
	config/tilegx/linux.mh, config/vax/nbsdelf.mh, config/vax/obsd.mh,
	config/xtensa/linux.mh: Add ptrace-utils.o.

gdb/gdbserver/ChangeLog:
2015-03-06  Pedro Alves  <palves@redhat.com>

	* Makefile.in (SFILES): Add nat/ptrace-utils.c.
	(ptrace-utils.o): New rule.
	* configure.srv (srv_linux_obj): Add ptrace-utils.o.
---
 gdb/Makefile.in                   |  6 +++-
 gdb/aarch64-linux-nat.c           | 13 ++++----
 gdb/alphabsd-nat.c                | 13 ++++----
 gdb/amd64-linux-nat.c             | 19 ++++++------
 gdb/amd64bsd-nat.c                | 19 ++++++------
 gdb/arm-linux-nat.c               |  9 +++---
 gdb/config/aarch64/linux.mh       |  2 +-
 gdb/config/alpha/alpha-linux.mh   |  2 +-
 gdb/config/alpha/fbsd.mh          |  2 +-
 gdb/config/alpha/nbsd.mh          |  2 +-
 gdb/config/arm/linux.mh           |  2 +-
 gdb/config/arm/nbsdelf.mh         |  2 +-
 gdb/config/i386/fbsd.mh           |  2 +-
 gdb/config/i386/fbsd64.mh         |  2 +-
 gdb/config/i386/linux.mh          |  2 +-
 gdb/config/i386/linux64.mh        |  2 +-
 gdb/config/i386/nbsd64.mh         |  2 +-
 gdb/config/i386/nbsdelf.mh        |  2 +-
 gdb/config/i386/obsd.mh           |  2 +-
 gdb/config/i386/obsd64.mh         |  2 +-
 gdb/config/ia64/linux.mh          |  2 +-
 gdb/config/m32r/linux.mh          |  2 +-
 gdb/config/m68k/linux.mh          |  2 +-
 gdb/config/m68k/nbsdelf.mh        |  2 +-
 gdb/config/m68k/obsd.mh           |  2 +-
 gdb/config/m88k/obsd.mh           |  2 +-
 gdb/config/mips/linux.mh          |  2 +-
 gdb/config/mips/nbsd.mh           |  2 +-
 gdb/config/mips/obsd64.mh         |  2 +-
 gdb/config/pa/hpux.mh             |  2 +-
 gdb/config/pa/linux.mh            |  2 +-
 gdb/config/pa/nbsd.mh             |  2 +-
 gdb/config/pa/obsd.mh             |  2 +-
 gdb/config/powerpc/aix.mh         |  2 +-
 gdb/config/powerpc/fbsd.mh        |  2 +-
 gdb/config/powerpc/linux.mh       |  2 +-
 gdb/config/powerpc/nbsd.mh        |  2 +-
 gdb/config/powerpc/obsd.mh        |  2 +-
 gdb/config/powerpc/ppc64-linux.mh |  2 +-
 gdb/config/powerpc/spu-linux.mh   |  2 +-
 gdb/config/s390/linux.mh          |  2 +-
 gdb/config/sh/nbsd.mh             |  2 +-
 gdb/config/sparc/fbsd.mh          |  2 +-
 gdb/config/sparc/linux.mh         |  2 +-
 gdb/config/sparc/linux64.mh       |  2 +-
 gdb/config/sparc/nbsd64.mh        |  2 +-
 gdb/config/sparc/nbsdelf.mh       |  2 +-
 gdb/config/sparc/obsd64.mh        |  2 +-
 gdb/config/tilegx/linux.mh        |  2 +-
 gdb/config/vax/nbsdelf.mh         |  2 +-
 gdb/config/vax/obsd.mh            |  2 +-
 gdb/config/xtensa/linux.mh        |  2 +-
 gdb/gdbserver/Makefile.in         |  6 +++-
 gdb/gdbserver/configure.srv       |  2 +-
 gdb/hppanbsd-nat.c                | 13 ++++----
 gdb/hppaobsd-nat.c                | 13 ++++----
 gdb/i386-linux-nat.c              | 27 +++++++++--------
 gdb/i386bsd-nat.c                 | 23 +++++++-------
 gdb/i386fbsd-nat.c                |  3 +-
 gdb/inf-ptrace.c                  | 19 ++++++------
 gdb/linux-nat.c                   |  3 +-
 gdb/m32r-linux-nat.c              |  7 +++--
 gdb/m68kbsd-nat.c                 | 13 ++++----
 gdb/m68klinux-nat.c               | 12 ++++----
 gdb/m88kbsd-nat.c                 |  7 +++--
 gdb/mips-linux-nat.c              | 19 ++++++------
 gdb/mips64obsd-nat.c              |  7 +++--
 gdb/mipsnbsd-nat.c                | 13 ++++----
 gdb/nat/ptrace-utils.c            | 29 ++++++++++++++++++
 gdb/nat/ptrace-utils.h            | 28 +++++++++++++++++
 gdb/obsd-nat.c                    |  9 +++---
 gdb/ppc-linux-nat.c               | 63 ++++++++++++++++++++-------------------
 gdb/ppcfbsd-nat.c                 | 13 ++++----
 gdb/ppcnbsd-nat.c                 | 13 ++++----
 gdb/ppcobsd-nat.c                 | 13 ++++----
 gdb/rs6000-nat.c                  |  3 +-
 gdb/s390-linux-nat.c              | 26 ++++++++--------
 gdb/shnbsd-nat.c                  |  7 +++--
 gdb/sparc-nat.c                   | 15 +++++-----
 gdb/spu-linux-nat.c               |  3 +-
 gdb/tilegx-linux-nat.c            |  6 ++--
 gdb/vaxbsd-nat.c                  |  7 +++--
 gdb/x86-linux-nat.c               |  9 +++---
 gdb/xtensa-linux-nat.c            | 12 ++++----
 84 files changed, 354 insertions(+), 260 deletions(-)
 create mode 100644 gdb/nat/ptrace-utils.c
 create mode 100644 gdb/nat/ptrace-utils.h
  

Comments

Mark Kettenis March 6, 2015, 9:03 p.m. UTC | #1
> From: Pedro Alves <palves@redhat.com>
> Date: Fri,  6 Mar 2015 19:58:02 +0000
> 
> This adds a new function that is meant to be called instead of
> perror_with_name whenever we get an error out of ptrace.  The
> idea is to convert some errno errors to different GDB exceptions in
> a following patch.

What is ptrace-specific about throwing an error?  This really feels
like the wrong direction to me.
  
Pedro Alves March 6, 2015, 9:40 p.m. UTC | #2
On 03/06/2015 09:03 PM, Mark Kettenis wrote:
>> From: Pedro Alves <palves@redhat.com>
>> Date: Fri,  6 Mar 2015 19:58:02 +0000
>>
>> This adds a new function that is meant to be called instead of
>> perror_with_name whenever we get an error out of ptrace.  The
>> idea is to convert some errno errors to different GDB exceptions in
>> a following patch.
> 
> What is ptrace-specific about throwing an error?  This really feels
> like the wrong direction to me.

Not exactly sure what you mean.  Throwing an error is
of course not ptrace-specific.  What is ptrace-specific is the
interpretation of errno.  The end result of the series is that
an ESRCH as a result of a ptrace error ends up throwing
a THREAD_NOT_FOUND_ERROR error instead of a GENERIC_ERROR.  Then
callers up the chain can actually distinguish the errors.

Please take a look at patch 3.  It should make things clearer.

Thanks,
Pedro Alves
  
Mark Kettenis March 8, 2015, 8:29 p.m. UTC | #3
> Date: Fri, 06 Mar 2015 21:40:03 +0000
> From: Pedro Alves <palves@redhat.com>
> 
> On 03/06/2015 09:03 PM, Mark Kettenis wrote:
> >> From: Pedro Alves <palves@redhat.com>
> >> Date: Fri,  6 Mar 2015 19:58:02 +0000
> >>
> >> This adds a new function that is meant to be called instead of
> >> perror_with_name whenever we get an error out of ptrace.  The
> >> idea is to convert some errno errors to different GDB exceptions in
> >> a following patch.
> > 
> > What is ptrace-specific about throwing an error?  This really feels
> > like the wrong direction to me.
> 
> Not exactly sure what you mean.  Throwing an error is
> of course not ptrace-specific.  What is ptrace-specific is the
> interpretation of errno.  The end result of the series is that
> an ESRCH as a result of a ptrace error ends up throwing
> a THREAD_NOT_FOUND_ERROR error instead of a GENERIC_ERROR.  Then
> callers up the chain can actually distinguish the errors.
> 
> Please take a look at patch 3.  It should make things clearer.

I think your interpretation of ESRCH is too Linux-centric.  You're
once again duct-taping around the Linux kernel's whoefully
insufficient threads debugging capabilities.  It really should not be
possible for a thread to just disappear without the debugger being
notified.  Do I sound like a broken record?

I think at this point the right approach is to make
linux_resume_one_lwp() call ptrace() directly instead of calling down
into the inf_ptrace_resume().  That way you can simply check errno in
the place where it matters.
  
Pedro Alves March 8, 2015, 9:48 p.m. UTC | #4
On 03/08/2015 08:29 PM, Mark Kettenis wrote:

> I think your interpretation of ESRCH is too Linux-centric.  You're
> once again duct-taping around the Linux kernel's whoefully
> insufficient threads debugging capabilities.

Nice.

> It really should not be
> possible for a thread to just disappear without the debugger being
> notified.  Do I sound like a broken record?

Sorry, but yes, you do.  ;-)

The debugger is notified.  It's just a fact that a process can
die (and become zombie) even while it was _stopped_ under
ptrace control.  That's a race you can't prevent, only cope with.

I found NetBSD 5.1 in the GCC compile farm, and I see ESRCH
there too:

-bash-4.2$ uname -a
NetBSD gcc70.fsffrance.org 5.1 NetBSD 5.1 (GENERIC) #0: Sat Nov  6 13:19:33 UTC 2010  builds@b6.netbsd.org:/home/builds/ab/netbsd-5-1-RELEASE/amd64/201011061943Z-obj/home/builds/ab/netbsd-5-1-RELEASE/src/sys/arch/amd64/compile/GENERIC amd64

-bash-4.2$ gdb ./foo
GNU gdb 6.5
...
(gdb) start
Breakpoint 1 at 0x400894: file foo.c, line 5.
Starting program: /home/palves/foo
main () at foo.c:5
5         return 0;
(gdb) p getpid ()
$1 = 24557
(gdb) shell kill -9 24557
(gdb) c
Continuing.
ptrace: No such process.
(gdb)

But even if some ptrace-based OS uses a different errno
for that (which I doubt), we can just tweak throw_ptrace_error
(a centralized place, yay!) to look for a different
errno value.  So what does OpenBSD's ptrace return
in the test above?

> I think at this point the right approach is to make
> linux_resume_one_lwp() call ptrace() directly instead of calling down
> into the inf_ptrace_resume().  That way you can simply check errno in
> the place where it matters.

No, your "simply" is not simple as you imply.  There can be any number
of ptrace calls that fail before the PT_CONTINUE in inf_ptrace_resume
is reached.  And whether to ignore the error should be left to some
caller higher up on the call chain.  That was the _whole point_ of this
fuller fix, as I explained throughout the series.
E.g., the ptrace call that fails can be the one that tries to write
debug registers to the inferior, normal registers, reading the auxv,
any memory read/write, whatever.  Any ptrace error that throws ends up
in the generic perror_with_name today, after the series, they'll
end up in throw_ptrace_error instead, a single place we can add
more context info to the error thrown.  How is that a bad thing?

Thanks,
Pedro Alves
  
Mark Kettenis March 10, 2015, 2:53 p.m. UTC | #5
> Date: Sun, 08 Mar 2015 21:48:12 +0000
> From: Pedro Alves <palves@redhat.com>
> 
> On 03/08/2015 08:29 PM, Mark Kettenis wrote:
> 
> > I think your interpretation of ESRCH is too Linux-centric.  You're
> > once again duct-taping around the Linux kernel's whoefully
> > insufficient threads debugging capabilities.
> 
> Nice.
> 
> > It really should not be
> > possible for a thread to just disappear without the debugger being
> > notified.  Do I sound like a broken record?
> 
> Sorry, but yes, you do.  ;-)
> 
> The debugger is notified.  It's just a fact that a process can
> die (and become zombie) even while it was _stopped_ under
> ptrace control.  That's a race you can't prevent, only cope with.

A process yes, but a thread no.

> I found NetBSD 5.1 in the GCC compile farm, and I see ESRCH
> there too:
> 
> -bash-4.2$ uname -a
> NetBSD gcc70.fsffrance.org 5.1 NetBSD 5.1 (GENERIC) #0: Sat Nov  6 13:19:33 UTC 2010  builds@b6.netbsd.org:/home/builds/ab/netbsd-5-1-RELEASE/amd64/201011061943Z-obj/home/builds/ab/netbsd-5-1-RELEASE/src/sys/arch/amd64/compile/GENERIC amd64
> 
> -bash-4.2$ gdb ./foo
> GNU gdb 6.5
> ...
> (gdb) start
> Breakpoint 1 at 0x400894: file foo.c, line 5.
> Starting program: /home/palves/foo
> main () at foo.c:5
> 5         return 0;
> (gdb) p getpid ()
> $1 = 24557
> (gdb) shell kill -9 24557
> (gdb) c
> Continuing.
> ptrace: No such process.
> (gdb)

That's an ancient GDB though.

> But even if some ptrace-based OS uses a different errno
> for that (which I doubt), we can just tweak throw_ptrace_error
> (a centralized place, yay!) to look for a different
> errno value.  So what does OpenBSD's ptrace return
> in the test above?

(gdb) p getpid()
$1 = 24737
(gdb) shell kill -9 24747
ksh: kill: 24747: No such process
(gdb) shell kill -9 24737
(gdb) c
Continuing.

Program received signal SIGKILL, Killed.
main () at ../../../../src/binutils-gdb/gdb/testsuite/gdb.base/wchar.c:29
29        wchar_t narrow = 97;
(gdb) 

Which strikes me as the proper behaviour in this case.  Not sure if
the NetBSD behaviour you're seeing is the result of different GDB
code, or really different kernel behaviour.

OpenBSD's ptrace(2) will set errno to ESRCH if you pass it a
non-existant process ID or thread ID.  As can be seen when using the
"attach" command:

(gdb) attach 666
Attaching to program: /home/kettenis/obj/binutils-gdb/gdb/testsuite/gdb.base/wchar, process 666
ptrace: No such process

Perhaps the error message here could be improved, but that doesn't
require us to add a throw with more details here.

In the end the meaning of ESRCH is dependent on the context.  You
can't just interpret it as a missing thread.

> > I think at this point the right approach is to make
> > linux_resume_one_lwp() call ptrace() directly instead of calling down
> > into the inf_ptrace_resume().  That way you can simply check errno in
> > the place where it matters.
> 
> No, your "simply" is not simple as you imply.  There can be any number
> of ptrace calls that fail before the PT_CONTINUE in inf_ptrace_resume
> is reached.  And whether to ignore the error should be left to some
> caller higher up on the call chain.  That was the _whole point_ of this
> fuller fix, as I explained throughout the series.
> E.g., the ptrace call that fails can be the one that tries to write
> debug registers to the inferior, normal registers, reading the auxv,
> any memory read/write, whatever.  Any ptrace error that throws ends up
> in the generic perror_with_name today, after the series, they'll
> end up in throw_ptrace_error instead, a single place we can add
> more context info to the error thrown.  How is that a bad thing?

The problem is that you'll always end up losing some context by using
a throw/catch model.  I think that should be avoided whenever
possible, and I got the impression that in the specific race you were
trying to fix here it could be avoided.

It also strikes me as undesitable having to add a new an dfairly
generic file to the list in config/*.mh.
  

Patch

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 8c2a4de..b1bf620 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -966,7 +966,7 @@  common/print-utils.h common/rsp-low.h nat/x86-dregs.h x86-linux-nat.h \
 i386-linux-nat.h common/common-defs.h common/errors.h common/common-types.h \
 common/common-debug.h common/cleanups.h common/gdb_setjmp.h \
 common/common-exceptions.h target/target.h common/symbol.h \
-common/common-regcache.h fbsd-tdep.h nat/linux-personality.h
+common/common-regcache.h fbsd-tdep.h nat/linux-personality.h nat/ptrace-utils.h
 
 # Header files that already have srcdir in them, or which are in objdir.
 
@@ -2295,6 +2295,10 @@  linux-personality.o: ${srcdir}/nat/linux-personality.c
 	$(COMPILE) $(srcdir)/nat/linux-personality.c
 	$(POSTCOMPILE)
 
+ptrace-utils.o: $(srcdir)/nat/ptrace-utils.c
+	$(COMPILE) $(srcdir)/nat/ptrace-utils.c
+	$(POSTCOMPILE)
+
 #
 # gdb/tui/ dependencies
 #
diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
index aae4853..523f5b8 100644
--- a/gdb/aarch64-linux-nat.c
+++ b/gdb/aarch64-linux-nat.c
@@ -24,6 +24,7 @@ 
 #include "gdbcore.h"
 #include "regcache.h"
 #include "linux-nat.h"
+#include "nat/ptrace-utils.h"
 #include "target-descriptions.h"
 #include "auxv.h"
 #include "gdbcmd.h"
@@ -469,7 +470,7 @@  fetch_gregs_from_thread (struct regcache *regcache)
 
   ret = ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, &iovec);
   if (ret < 0)
-    perror_with_name (_("Unable to fetch general registers."));
+    throw_ptrace_error (_("Unable to fetch general registers."));
 
   for (regno = AARCH64_X0_REGNUM; regno <= AARCH64_CPSR_REGNUM; regno++)
     regcache_raw_supply (regcache, regno,
@@ -493,7 +494,7 @@  store_gregs_to_thread (const struct regcache *regcache)
 
   ret = ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, &iovec);
   if (ret < 0)
-    perror_with_name (_("Unable to fetch general registers."));
+    throw_ptrace_error (_("Unable to fetch general registers."));
 
   for (regno = AARCH64_X0_REGNUM; regno <= AARCH64_CPSR_REGNUM; regno++)
     if (REG_VALID == regcache_register_status (regcache, regno))
@@ -502,7 +503,7 @@  store_gregs_to_thread (const struct regcache *regcache)
 
   ret = ptrace (PTRACE_SETREGSET, tid, NT_PRSTATUS, &iovec);
   if (ret < 0)
-    perror_with_name (_("Unable to store general registers."));
+    throw_ptrace_error (_("Unable to store general registers."));
 }
 
 /* Fill GDB's register array with the fp/simd register values
@@ -522,7 +523,7 @@  fetch_fpregs_from_thread (struct regcache *regcache)
 
   ret = ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET, &iovec);
   if (ret < 0)
-    perror_with_name (_("Unable to fetch FP/SIMD registers."));
+    throw_ptrace_error (_("Unable to fetch FP/SIMD registers."));
 
   for (regno = AARCH64_V0_REGNUM; regno <= AARCH64_V31_REGNUM; regno++)
     regcache_raw_supply (regcache, regno,
@@ -549,7 +550,7 @@  store_fpregs_to_thread (const struct regcache *regcache)
 
   ret = ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET, &iovec);
   if (ret < 0)
-    perror_with_name (_("Unable to fetch FP/SIMD registers."));
+    throw_ptrace_error (_("Unable to fetch FP/SIMD registers."));
 
   for (regno = AARCH64_V0_REGNUM; regno <= AARCH64_V31_REGNUM; regno++)
     if (REG_VALID == regcache_register_status (regcache, regno))
@@ -563,7 +564,7 @@  store_fpregs_to_thread (const struct regcache *regcache)
 
   ret = ptrace (PTRACE_SETREGSET, tid, NT_FPREGSET, &iovec);
   if (ret < 0)
-    perror_with_name (_("Unable to store FP/SIMD registers."));
+    throw_ptrace_error (_("Unable to store FP/SIMD registers."));
 }
 
 /* Implement the "to_fetch_register" target_ops method.  */
diff --git a/gdb/alphabsd-nat.c b/gdb/alphabsd-nat.c
index 37a5c8d..74757ab 100644
--- a/gdb/alphabsd-nat.c
+++ b/gdb/alphabsd-nat.c
@@ -24,6 +24,7 @@ 
 #include "alpha-tdep.h"
 #include "alphabsd-tdep.h"
 #include "inf-ptrace.h"
+#include "nat/ptrace-utils.h"
 
 #include <sys/types.h>
 #include <sys/ptrace.h>
@@ -93,7 +94,7 @@  alphabsd_fetch_inferior_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &gregs, 0) == -1)
-	perror_with_name (_("Couldn't get registers"));
+	throw_ptrace_error (_("Couldn't get registers"));
 
       alphabsd_supply_reg (regcache, (char *) &gregs, regno);
       if (regno != -1)
@@ -107,7 +108,7 @@  alphabsd_fetch_inferior_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't get floating point status"));
+	throw_ptrace_error (_("Couldn't get floating point status"));
 
       alphabsd_supply_fpreg (regcache, (char *) &fpregs, regno);
     }
@@ -125,13 +126,13 @@  alphabsd_store_inferior_registers (struct target_ops *ops,
       struct reg gregs;
       if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
                   (PTRACE_TYPE_ARG3) &gregs, 0) == -1)
-        perror_with_name (_("Couldn't get registers"));
+        throw_ptrace_error (_("Couldn't get registers"));
 
       alphabsd_fill_reg (regcache, (char *) &gregs, regno);
 
       if (ptrace (PT_SETREGS, ptid_get_pid (inferior_ptid),
                   (PTRACE_TYPE_ARG3) &gregs, 0) == -1)
-        perror_with_name (_("Couldn't write registers"));
+        throw_ptrace_error (_("Couldn't write registers"));
 
       if (regno != -1)
 	return;
@@ -144,13 +145,13 @@  alphabsd_store_inferior_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't get floating point status"));
+	throw_ptrace_error (_("Couldn't get floating point status"));
 
       alphabsd_fill_fpreg (regcache, (char *) &fpregs, regno);
 
       if (ptrace (PT_SETFPREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't write floating point status"));
+	throw_ptrace_error (_("Couldn't write floating point status"));
     }
 }
 
diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c
index 22a1359..e35a52e 100644
--- a/gdb/amd64-linux-nat.c
+++ b/gdb/amd64-linux-nat.c
@@ -31,6 +31,7 @@ 
 
 #include "amd64-nat.h"
 #include "linux-nat.h"
+#include "nat/ptrace-utils.h"
 #include "amd64-tdep.h"
 #include "amd64-linux-tdep.h"
 #include "i386-linux-tdep.h"
@@ -138,7 +139,7 @@  amd64_linux_fetch_inferior_registers (struct target_ops *ops,
       elf_gregset_t regs;
 
       if (ptrace (PTRACE_GETREGS, tid, 0, (long) &regs) < 0)
-	perror_with_name (_("Couldn't get registers"));
+	throw_ptrace_error (_("Couldn't get registers"));
 
       amd64_supply_native_gregset (regcache, &regs, -1);
       if (regnum != -1)
@@ -158,14 +159,14 @@  amd64_linux_fetch_inferior_registers (struct target_ops *ops,
 	  iov.iov_len = sizeof (xstateregs);
 	  if (ptrace (PTRACE_GETREGSET, tid,
 		      (unsigned int) NT_X86_XSTATE, (long) &iov) < 0)
-	    perror_with_name (_("Couldn't get extended state status"));
+	    throw_ptrace_error (_("Couldn't get extended state status"));
 
 	  amd64_supply_xsave (regcache, -1, xstateregs);
 	}
       else
 	{
 	  if (ptrace (PTRACE_GETFPREGS, tid, 0, (long) &fpregs) < 0)
-	    perror_with_name (_("Couldn't get floating point status"));
+	    throw_ptrace_error (_("Couldn't get floating point status"));
 
 	  amd64_supply_fxsave (regcache, -1, &fpregs);
 	}
@@ -193,12 +194,12 @@  amd64_linux_store_inferior_registers (struct target_ops *ops,
       elf_gregset_t regs;
 
       if (ptrace (PTRACE_GETREGS, tid, 0, (long) &regs) < 0)
-	perror_with_name (_("Couldn't get registers"));
+	throw_ptrace_error (_("Couldn't get registers"));
 
       amd64_collect_native_gregset (regcache, &regs, regnum);
 
       if (ptrace (PTRACE_SETREGS, tid, 0, (long) &regs) < 0)
-	perror_with_name (_("Couldn't write registers"));
+	throw_ptrace_error (_("Couldn't write registers"));
 
       if (regnum != -1)
 	return;
@@ -217,23 +218,23 @@  amd64_linux_store_inferior_registers (struct target_ops *ops,
 	  iov.iov_len = sizeof (xstateregs);
 	  if (ptrace (PTRACE_GETREGSET, tid,
 		      (unsigned int) NT_X86_XSTATE, (long) &iov) < 0)
-	    perror_with_name (_("Couldn't get extended state status"));
+	    throw_ptrace_error (_("Couldn't get extended state status"));
 
 	  amd64_collect_xsave (regcache, regnum, xstateregs, 0);
 
 	  if (ptrace (PTRACE_SETREGSET, tid,
 		      (unsigned int) NT_X86_XSTATE, (long) &iov) < 0)
-	    perror_with_name (_("Couldn't write extended state status"));
+	    throw_ptrace_error (_("Couldn't write extended state status"));
 	}
       else
 	{
 	  if (ptrace (PTRACE_GETFPREGS, tid, 0, (long) &fpregs) < 0)
-	    perror_with_name (_("Couldn't get floating point status"));
+	    throw_ptrace_error (_("Couldn't get floating point status"));
 
 	  amd64_collect_fxsave (regcache, regnum, &fpregs);
 
 	  if (ptrace (PTRACE_SETFPREGS, tid, 0, (long) &fpregs) < 0)
-	    perror_with_name (_("Couldn't write floating point status"));
+	    throw_ptrace_error (_("Couldn't write floating point status"));
 	}
     }
 }
diff --git a/gdb/amd64bsd-nat.c b/gdb/amd64bsd-nat.c
index 31060a123..e28715c 100644
--- a/gdb/amd64bsd-nat.c
+++ b/gdb/amd64bsd-nat.c
@@ -33,6 +33,7 @@ 
 #include "amd64-nat.h"
 #include "amd64bsd-nat.h"
 #include "inf-ptrace.h"
+#include "nat/ptrace-utils.h"
 
 
 /* Fetch register REGNUM from the inferior.  If REGNUM is -1, do this
@@ -50,7 +51,7 @@  amd64bsd_fetch_inferior_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-	perror_with_name (_("Couldn't get registers"));
+	throw_ptrace_error (_("Couldn't get registers"));
 
       amd64_supply_native_gregset (regcache, &regs, -1);
       if (regnum != -1)
@@ -63,7 +64,7 @@  amd64bsd_fetch_inferior_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't get floating point status"));
+	throw_ptrace_error (_("Couldn't get floating point status"));
 
       amd64_supply_fxsave (regcache, -1, &fpregs);
     }
@@ -84,13 +85,13 @@  amd64bsd_store_inferior_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
                   (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-        perror_with_name (_("Couldn't get registers"));
+        throw_ptrace_error (_("Couldn't get registers"));
 
       amd64_collect_native_gregset (regcache, &regs, regnum);
 
       if (ptrace (PT_SETREGS, ptid_get_pid (inferior_ptid),
 	          (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-        perror_with_name (_("Couldn't write registers"));
+        throw_ptrace_error (_("Couldn't write registers"));
 
       if (regnum != -1)
 	return;
@@ -102,13 +103,13 @@  amd64bsd_store_inferior_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't get floating point status"));
+	throw_ptrace_error (_("Couldn't get floating point status"));
 
       amd64_collect_fxsave (regcache, regnum, &fpregs);
 
       if (ptrace (PT_SETFPREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't write floating point status"));
+	throw_ptrace_error (_("Couldn't write floating point status"));
     }
 }
 
@@ -138,7 +139,7 @@  amd64bsd_dr_get (ptid_t ptid, int regnum)
 
   if (ptrace (PT_GETDBREGS, ptid_get_pid (inferior_ptid),
 	      (PTRACE_TYPE_ARG3) &dbregs, 0) == -1)
-    perror_with_name (_("Couldn't read debug registers"));
+    throw_ptrace_error (_("Couldn't read debug registers"));
 
   return DBREG_DRX ((&dbregs), regnum);
 }
@@ -150,7 +151,7 @@  amd64bsd_dr_set (int regnum, unsigned long value)
 
   if (ptrace (PT_GETDBREGS, ptid_get_pid (inferior_ptid),
               (PTRACE_TYPE_ARG3) &dbregs, 0) == -1)
-    perror_with_name (_("Couldn't get debug registers"));
+    throw_ptrace_error (_("Couldn't get debug registers"));
 
   /* For some mysterious reason, some of the reserved bits in the
      debug control register get set.  Mask these off, otherwise the
@@ -161,7 +162,7 @@  amd64bsd_dr_set (int regnum, unsigned long value)
 
   if (ptrace (PT_SETDBREGS, ptid_get_pid (inferior_ptid),
               (PTRACE_TYPE_ARG3) &dbregs, 0) == -1)
-    perror_with_name (_("Couldn't write debug registers"));
+    throw_ptrace_error (_("Couldn't write debug registers"));
 }
 
 void
diff --git a/gdb/arm-linux-nat.c b/gdb/arm-linux-nat.c
index bb8358c..34bc2db 100644
--- a/gdb/arm-linux-nat.c
+++ b/gdb/arm-linux-nat.c
@@ -22,6 +22,7 @@ 
 #include "regcache.h"
 #include "target.h"
 #include "linux-nat.h"
+#include "nat/ptrace-utils.h"
 #include "target-descriptions.h"
 #include "auxv.h"
 #include "observer.h"
@@ -1347,12 +1348,12 @@  arm_linux_prepare_to_resume (struct lwp_info *lwp)
         if (arm_hwbp_control_is_enabled (bpts[i].control))
           if (ptrace (PTRACE_SETHBPREGS, pid,
               (PTRACE_TYPE_ARG3) ((i << 1) + 1), &bpts[i].address) < 0)
-            perror_with_name (_("Unexpected error setting breakpoint"));
+            throw_ptrace_error (_("Unexpected error setting breakpoint"));
 
         if (bpts[i].control != 0)
           if (ptrace (PTRACE_SETHBPREGS, pid,
               (PTRACE_TYPE_ARG3) ((i << 1) + 2), &bpts[i].control) < 0)
-            perror_with_name (_("Unexpected error setting breakpoint"));
+            throw_ptrace_error (_("Unexpected error setting breakpoint"));
 
         arm_lwp_info->bpts_changed[i] = 0;
       }
@@ -1364,12 +1365,12 @@  arm_linux_prepare_to_resume (struct lwp_info *lwp)
         if (arm_hwbp_control_is_enabled (wpts[i].control))
           if (ptrace (PTRACE_SETHBPREGS, pid,
               (PTRACE_TYPE_ARG3) -((i << 1) + 1), &wpts[i].address) < 0)
-            perror_with_name (_("Unexpected error setting watchpoint"));
+            throw_ptrace_error (_("Unexpected error setting watchpoint"));
 
         if (wpts[i].control != 0)
           if (ptrace (PTRACE_SETHBPREGS, pid,
               (PTRACE_TYPE_ARG3) -((i << 1) + 2), &wpts[i].control) < 0)
-            perror_with_name (_("Unexpected error setting watchpoint"));
+            throw_ptrace_error (_("Unexpected error setting watchpoint"));
 
         arm_lwp_info->wpts_changed[i] = 0;
       }
diff --git a/gdb/config/aarch64/linux.mh b/gdb/config/aarch64/linux.mh
index 7f96e4d..3b47df2 100644
--- a/gdb/config/aarch64/linux.mh
+++ b/gdb/config/aarch64/linux.mh
@@ -19,7 +19,7 @@ 
 #  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 NAT_FILE= config/nm-linux.h
-NATDEPFILES= inf-ptrace.o fork-child.o aarch64-linux-nat.o \
+NATDEPFILES= inf-ptrace.o ptrace-utils.o fork-child.o aarch64-linux-nat.o \
 	proc-service.o linux-thread-db.o linux-nat.o linux-fork.o \
 	linux-procfs.o linux-ptrace.o linux-osdata.o linux-waitpid.o \
 	linux-personality.o
diff --git a/gdb/config/alpha/alpha-linux.mh b/gdb/config/alpha/alpha-linux.mh
index 2ea02a1..b2ac9b5 100644
--- a/gdb/config/alpha/alpha-linux.mh
+++ b/gdb/config/alpha/alpha-linux.mh
@@ -1,6 +1,6 @@ 
 # Host: Little-endian Alpha running Linux
 NAT_FILE= config/nm-linux.h
-NATDEPFILES= inf-ptrace.o alpha-linux-nat.o \
+NATDEPFILES= inf-ptrace.o ptrace-utils.o alpha-linux-nat.o \
 	fork-child.o proc-service.o linux-thread-db.o \
 	linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \
 	linux-waitpid.o linux-personality.o
diff --git a/gdb/config/alpha/fbsd.mh b/gdb/config/alpha/fbsd.mh
index 6d1fe29..3867ca6 100644
--- a/gdb/config/alpha/fbsd.mh
+++ b/gdb/config/alpha/fbsd.mh
@@ -1,5 +1,5 @@ 
 # Host: FreeBSD/alpha
-NATDEPFILES= fork-child.o inf-ptrace.o \
+NATDEPFILES= fork-child.o inf-ptrace.o ptrace-utils.o \
 	fbsd-nat.o alphabsd-nat.o bsd-kvm.o \
 	core-regset.o
 
diff --git a/gdb/config/alpha/nbsd.mh b/gdb/config/alpha/nbsd.mh
index b4185a7..b4b160f 100644
--- a/gdb/config/alpha/nbsd.mh
+++ b/gdb/config/alpha/nbsd.mh
@@ -1,4 +1,4 @@ 
 # Host: NetBSD/alpha
-NATDEPFILES= fork-child.o inf-ptrace.o alphabsd-nat.o bsd-kvm.o
+NATDEPFILES= fork-child.o inf-ptrace.o ptrace-utils.o alphabsd-nat.o bsd-kvm.o
 
 LOADLIBES= -lkvm
diff --git a/gdb/config/arm/linux.mh b/gdb/config/arm/linux.mh
index 549bf42..9304e5d 100644
--- a/gdb/config/arm/linux.mh
+++ b/gdb/config/arm/linux.mh
@@ -1,7 +1,7 @@ 
 # Host: ARM based machine running GNU/Linux
 
 NAT_FILE= config/nm-linux.h
-NATDEPFILES= inf-ptrace.o fork-child.o arm-linux-nat.o \
+NATDEPFILES= inf-ptrace.o ptrace-utils.o fork-child.o arm-linux-nat.o \
 	proc-service.o linux-thread-db.o \
 	linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \
 	linux-waitpid.o linux-personality.o
diff --git a/gdb/config/arm/nbsdelf.mh b/gdb/config/arm/nbsdelf.mh
index 4efb8a3..c1f122a 100644
--- a/gdb/config/arm/nbsdelf.mh
+++ b/gdb/config/arm/nbsdelf.mh
@@ -1,2 +1,2 @@ 
 # Host: NetBSD/arm
-NATDEPFILES= fork-child.o inf-ptrace.o armnbsd-nat.o
+NATDEPFILES= fork-child.o inf-ptrace.o ptrace-utils.o armnbsd-nat.o
diff --git a/gdb/config/i386/fbsd.mh b/gdb/config/i386/fbsd.mh
index e5bff3a..37e19cb 100644
--- a/gdb/config/i386/fbsd.mh
+++ b/gdb/config/i386/fbsd.mh
@@ -1,5 +1,5 @@ 
 # Host: FreeBSD/i386
-NATDEPFILES= fork-child.o inf-ptrace.o \
+NATDEPFILES= fork-child.o inf-ptrace.o ptrace-utils.o \
 	fbsd-nat.o x86-nat.o x86-dregs.o i386bsd-nat.o i386fbsd-nat.o \
 	bsd-kvm.o
 NAT_FILE= nm-fbsd.h
diff --git a/gdb/config/i386/fbsd64.mh b/gdb/config/i386/fbsd64.mh
index 329c526..3b82c7f 100644
--- a/gdb/config/i386/fbsd64.mh
+++ b/gdb/config/i386/fbsd64.mh
@@ -1,5 +1,5 @@ 
 # Host: FreeBSD/amd64
-NATDEPFILES= fork-child.o inf-ptrace.o \
+NATDEPFILES= fork-child.o inf-ptrace.o ptrace-utils.o \
 	fbsd-nat.o amd64-nat.o amd64bsd-nat.o amd64fbsd-nat.o \
 	bsd-kvm.o x86-nat.o x86-dregs.o
 HAVE_NATIVE_GCORE_HOST = 1
diff --git a/gdb/config/i386/linux.mh b/gdb/config/i386/linux.mh
index 33fb281..c941245 100644
--- a/gdb/config/i386/linux.mh
+++ b/gdb/config/i386/linux.mh
@@ -1,7 +1,7 @@ 
 # Host: Intel 386 running GNU/Linux.
 
 NAT_FILE= config/nm-linux.h
-NATDEPFILES= inf-ptrace.o fork-child.o \
+NATDEPFILES= inf-ptrace.o ptrace-utils.o fork-child.o \
 	x86-nat.o x86-dregs.o i386-linux-nat.o x86-linux-nat.o \
 	proc-service.o linux-thread-db.o \
 	linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \
diff --git a/gdb/config/i386/linux64.mh b/gdb/config/i386/linux64.mh
index d52eb52..d5b45d0 100644
--- a/gdb/config/i386/linux64.mh
+++ b/gdb/config/i386/linux64.mh
@@ -1,5 +1,5 @@ 
 # Host: GNU/Linux x86-64
-NATDEPFILES= inf-ptrace.o fork-child.o \
+NATDEPFILES= inf-ptrace.o ptrace-utils.o fork-child.o \
 	x86-nat.o x86-dregs.o amd64-nat.o amd64-linux-nat.o \
 	x86-linux-nat.o \
 	linux-nat.o linux-osdata.o \
diff --git a/gdb/config/i386/nbsd64.mh b/gdb/config/i386/nbsd64.mh
index 5de8cf5..369a32d 100644
--- a/gdb/config/i386/nbsd64.mh
+++ b/gdb/config/i386/nbsd64.mh
@@ -1,3 +1,3 @@ 
 # Host: NetBSD/amd64
-NATDEPFILES= fork-child.o inf-ptrace.o \
+NATDEPFILES= fork-child.o inf-ptrace.o ptrace-utils.o \
 	nbsd-nat.o amd64-nat.o amd64bsd-nat.o amd64nbsd-nat.o
diff --git a/gdb/config/i386/nbsdelf.mh b/gdb/config/i386/nbsdelf.mh
index d27c842..087696d 100644
--- a/gdb/config/i386/nbsdelf.mh
+++ b/gdb/config/i386/nbsdelf.mh
@@ -1,5 +1,5 @@ 
 # Host: NetBSD/i386 ELF
-NATDEPFILES= fork-child.o inf-ptrace.o \
+NATDEPFILES= fork-child.o inf-ptrace.o ptrace-utils.o \
 	nbsd-nat.o i386bsd-nat.o i386nbsd-nat.o bsd-kvm.o
 
 LOADLIBES= -lkvm
diff --git a/gdb/config/i386/obsd.mh b/gdb/config/i386/obsd.mh
index a9041f4..15383f1 100644
--- a/gdb/config/i386/obsd.mh
+++ b/gdb/config/i386/obsd.mh
@@ -1,5 +1,5 @@ 
 # Host: OpenBSD/i386 ELF
-NATDEPFILES= fork-child.o inf-ptrace.o obsd-nat.o \
+NATDEPFILES= fork-child.o inf-ptrace.o ptrace-utils.o obsd-nat.o \
 	i386bsd-nat.o i386obsd-nat.o bsd-kvm.o
 
 LOADLIBES= -lkvm
diff --git a/gdb/config/i386/obsd64.mh b/gdb/config/i386/obsd64.mh
index 386a582..abd06b9 100644
--- a/gdb/config/i386/obsd64.mh
+++ b/gdb/config/i386/obsd64.mh
@@ -1,5 +1,5 @@ 
 # Host: OpenBSD/amd64
-NATDEPFILES= fork-child.o inf-ptrace.o obsd-nat.o \
+NATDEPFILES= fork-child.o inf-ptrace.o ptrace-utils.o obsd-nat.o \
 	amd64-nat.o amd64bsd-nat.o amd64obsd-nat.o bsd-kvm.o
 
 LOADLIBES= -lkvm
diff --git a/gdb/config/ia64/linux.mh b/gdb/config/ia64/linux.mh
index 9dce22b..c502340 100644
--- a/gdb/config/ia64/linux.mh
+++ b/gdb/config/ia64/linux.mh
@@ -1,7 +1,7 @@ 
 # Host: Intel IA-64 running GNU/Linux
 
 NAT_FILE= config/nm-linux.h
-NATDEPFILES= inf-ptrace.o fork-child.o \
+NATDEPFILES= inf-ptrace.o ptrace-utils.o fork-child.o \
 	ia64-linux-nat.o \
 	proc-service.o linux-thread-db.o \
 	linux-nat.o linux-osdata.o linux-fork.o \
diff --git a/gdb/config/m32r/linux.mh b/gdb/config/m32r/linux.mh
index 6b810e6..6a9456f 100644
--- a/gdb/config/m32r/linux.mh
+++ b/gdb/config/m32r/linux.mh
@@ -1,7 +1,7 @@ 
 # Host: M32R based machine running GNU/Linux
 
 NAT_FILE= config/nm-linux.h
-NATDEPFILES= inf-ptrace.o fork-child.o				\
+NATDEPFILES= inf-ptrace.o ptrace-utils.o fork-child.o				\
 	m32r-linux-nat.o proc-service.o linux-thread-db.o	\
 	linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \
 	linux-waitpid.o linux-personality.o
diff --git a/gdb/config/m68k/linux.mh b/gdb/config/m68k/linux.mh
index f3b3baa..8317666 100644
--- a/gdb/config/m68k/linux.mh
+++ b/gdb/config/m68k/linux.mh
@@ -1,7 +1,7 @@ 
 # Host: Motorola m68k running GNU/Linux.
 
 NAT_FILE= config/nm-linux.h
-NATDEPFILES= inf-ptrace.o fork-child.o \
+NATDEPFILES= inf-ptrace.o ptrace-utils.o fork-child.o \
 	m68klinux-nat.o \
 	proc-service.o linux-thread-db.o \
 	linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \
diff --git a/gdb/config/m68k/nbsdelf.mh b/gdb/config/m68k/nbsdelf.mh
index f2d97a1..7d458a7 100644
--- a/gdb/config/m68k/nbsdelf.mh
+++ b/gdb/config/m68k/nbsdelf.mh
@@ -1,4 +1,4 @@ 
 # Host: NetBSD/m68k ELF
-NATDEPFILES= m68kbsd-nat.o bsd-kvm.o fork-child.o inf-ptrace.o
+NATDEPFILES= m68kbsd-nat.o bsd-kvm.o fork-child.o inf-ptrace.o ptrace-utils.o
 
 LOADLIBES= -lkvm
diff --git a/gdb/config/m68k/obsd.mh b/gdb/config/m68k/obsd.mh
index 7930e3b..92c00d7 100644
--- a/gdb/config/m68k/obsd.mh
+++ b/gdb/config/m68k/obsd.mh
@@ -1,4 +1,4 @@ 
 # Host: OpenBSD/m68k
-NATDEPFILES= m68kbsd-nat.o bsd-kvm.o fork-child.o inf-ptrace.o
+NATDEPFILES= m68kbsd-nat.o bsd-kvm.o fork-child.o inf-ptrace.o ptrace-utils.o
 
 LOADLIBES= -lkvm
diff --git a/gdb/config/m88k/obsd.mh b/gdb/config/m88k/obsd.mh
index 2978edf..a9c9365 100644
--- a/gdb/config/m88k/obsd.mh
+++ b/gdb/config/m88k/obsd.mh
@@ -1,2 +1,2 @@ 
 # Host: OpenBSD/m88k
-NATDEPFILES= fork-child.o inf-ptrace.o m88kbsd-nat.o
+NATDEPFILES= fork-child.o inf-ptrace.o ptrace-utils.o m88kbsd-nat.o
diff --git a/gdb/config/mips/linux.mh b/gdb/config/mips/linux.mh
index d6a802f..eabc470 100644
--- a/gdb/config/mips/linux.mh
+++ b/gdb/config/mips/linux.mh
@@ -1,6 +1,6 @@ 
 # Host: Linux/MIPS
 NAT_FILE= config/nm-linux.h
-NATDEPFILES= inf-ptrace.o fork-child.o mips-linux-nat.o \
+NATDEPFILES= inf-ptrace.o ptrace-utils.o fork-child.o mips-linux-nat.o \
 	linux-thread-db.o proc-service.o \
 	linux-nat.o linux-osdata.o linux-fork.o \
 	linux-procfs.o linux-ptrace.o linux-waitpid.o \
diff --git a/gdb/config/mips/nbsd.mh b/gdb/config/mips/nbsd.mh
index b76df13..fe437dd 100644
--- a/gdb/config/mips/nbsd.mh
+++ b/gdb/config/mips/nbsd.mh
@@ -1,2 +1,2 @@ 
 # Host: NetBSD/mips
-NATDEPFILES= fork-child.o inf-ptrace.o mipsnbsd-nat.o
+NATDEPFILES= fork-child.o inf-ptrace.o ptrace-utils.o mipsnbsd-nat.o
diff --git a/gdb/config/mips/obsd64.mh b/gdb/config/mips/obsd64.mh
index ed04f9e..e9b7a7f 100644
--- a/gdb/config/mips/obsd64.mh
+++ b/gdb/config/mips/obsd64.mh
@@ -1,2 +1,2 @@ 
 # Host: OpenBSD/mips64
-NATDEPFILES= fork-child.o inf-ptrace.o obsd-nat.o mips64obsd-nat.o
+NATDEPFILES= fork-child.o inf-ptrace.o ptrace-utils.o obsd-nat.o mips64obsd-nat.o
diff --git a/gdb/config/pa/hpux.mh b/gdb/config/pa/hpux.mh
index 3151120..ec61058 100644
--- a/gdb/config/pa/hpux.mh
+++ b/gdb/config/pa/hpux.mh
@@ -1,3 +1,3 @@ 
 # Host: PA-RISC HP-UX
-NATDEPFILES= fork-child.o inf-ptrace.o inf-ttrace.o \
+NATDEPFILES= fork-child.o inf-ptrace.o ptrace-utils.o inf-ttrace.o \
 	hppa-hpux-nat.o
diff --git a/gdb/config/pa/linux.mh b/gdb/config/pa/linux.mh
index 9539b64..15c3752 100644
--- a/gdb/config/pa/linux.mh
+++ b/gdb/config/pa/linux.mh
@@ -1,6 +1,6 @@ 
 # Host: Hewlett-Packard PA-RISC machine, running Linux
 NAT_FILE= config/nm-linux.h
-NATDEPFILES= inf-ptrace.o fork-child.o \
+NATDEPFILES= inf-ptrace.o ptrace-utils.o fork-child.o \
 	hppa-linux-nat.o proc-service.o linux-thread-db.o \
 	linux-nat.o linux-osdata.o linux-fork.o \
 	linux-procfs.o linux-ptrace.o linux-waitpid.o \
diff --git a/gdb/config/pa/nbsd.mh b/gdb/config/pa/nbsd.mh
index 5cff698..ff34c78 100644
--- a/gdb/config/pa/nbsd.mh
+++ b/gdb/config/pa/nbsd.mh
@@ -1,2 +1,2 @@ 
 # Host: NetBSD/hppa
-NATDEPFILES= fork-child.o inf-ptrace.o nbsd-nat.o hppanbsd-nat.o
+NATDEPFILES= fork-child.o inf-ptrace.o ptrace-utils.o nbsd-nat.o hppanbsd-nat.o
diff --git a/gdb/config/pa/obsd.mh b/gdb/config/pa/obsd.mh
index 50a1192..8e025b8 100644
--- a/gdb/config/pa/obsd.mh
+++ b/gdb/config/pa/obsd.mh
@@ -1,2 +1,2 @@ 
 # Host: OpenBSD/hppa
-NATDEPFILES= fork-child.o inf-ptrace.o obsd-nat.o hppaobsd-nat.o
+NATDEPFILES= fork-child.o inf-ptrace.o ptrace-utils.o obsd-nat.o hppaobsd-nat.o
diff --git a/gdb/config/powerpc/aix.mh b/gdb/config/powerpc/aix.mh
index 141501d..52930df 100644
--- a/gdb/config/powerpc/aix.mh
+++ b/gdb/config/powerpc/aix.mh
@@ -1,7 +1,7 @@ 
 # Host: IBM PowerPC running AIX
 
 # aix-thread.o is not listed in NATDEPFILES as it is pulled in by configure.
-NATDEPFILES= fork-child.o inf-ptrace.o rs6000-nat.o
+NATDEPFILES= fork-child.o inf-ptrace.o ptrace-utils.o rs6000-nat.o
 
 # When compiled with cc, for debugging, this argument should be passed.
 # We have no idea who our current compiler is though, so we skip it.
diff --git a/gdb/config/powerpc/fbsd.mh b/gdb/config/powerpc/fbsd.mh
index e4e7b47..1ed4f49 100644
--- a/gdb/config/powerpc/fbsd.mh
+++ b/gdb/config/powerpc/fbsd.mh
@@ -17,7 +17,7 @@ 
 #  You should have received a copy of the GNU General Public License
 #  along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-NATDEPFILES= fbsd-nat.o fork-child.o inf-ptrace.o ppcfbsd-nat.o bsd-kvm.o
+NATDEPFILES= fbsd-nat.o fork-child.o inf-ptrace.o ptrace-utils.o ppcfbsd-nat.o bsd-kvm.o
 HAVE_NATIVE_GCORE_HOST = 1
 
 LOADLIBES= -lkvm
diff --git a/gdb/config/powerpc/linux.mh b/gdb/config/powerpc/linux.mh
index 76e62c0..44f4a91 100644
--- a/gdb/config/powerpc/linux.mh
+++ b/gdb/config/powerpc/linux.mh
@@ -3,7 +3,7 @@ 
 XM_CLIBS=
 
 NAT_FILE= config/nm-linux.h
-NATDEPFILES= inf-ptrace.o fork-child.o \
+NATDEPFILES= inf-ptrace.o ptrace-utils.o fork-child.o \
 	ppc-linux-nat.o proc-service.o linux-thread-db.o \
 	linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \
 	linux-waitpid.o linux-personality.o
diff --git a/gdb/config/powerpc/nbsd.mh b/gdb/config/powerpc/nbsd.mh
index db0390c..edea9dd 100644
--- a/gdb/config/powerpc/nbsd.mh
+++ b/gdb/config/powerpc/nbsd.mh
@@ -1,4 +1,4 @@ 
 # Host: NetBSD/powerpc
-NATDEPFILES= fork-child.o inf-ptrace.o ppcnbsd-nat.o bsd-kvm.o
+NATDEPFILES= fork-child.o inf-ptrace.o ptrace-utils.o ppcnbsd-nat.o bsd-kvm.o
 
 LOADLIBES= -lkvm
diff --git a/gdb/config/powerpc/obsd.mh b/gdb/config/powerpc/obsd.mh
index 2af667a..f8892ba 100644
--- a/gdb/config/powerpc/obsd.mh
+++ b/gdb/config/powerpc/obsd.mh
@@ -1,4 +1,4 @@ 
 # Host: OpenBSD/powerpc
-NATDEPFILES= fork-child.o inf-ptrace.o obsd-nat.o ppcobsd-nat.o bsd-kvm.o
+NATDEPFILES= fork-child.o inf-ptrace.o ptrace-utils.o obsd-nat.o ppcobsd-nat.o bsd-kvm.o
 
 LOADLIBES= -lkvm
diff --git a/gdb/config/powerpc/ppc64-linux.mh b/gdb/config/powerpc/ppc64-linux.mh
index 7eb6507..80c80fd 100644
--- a/gdb/config/powerpc/ppc64-linux.mh
+++ b/gdb/config/powerpc/ppc64-linux.mh
@@ -3,7 +3,7 @@ 
 XM_CLIBS=
 
 NAT_FILE= config/nm-linux.h
-NATDEPFILES= inf-ptrace.o fork-child.o \
+NATDEPFILES= inf-ptrace.o ptrace-utils.o fork-child.o \
 	ppc-linux-nat.o proc-service.o linux-thread-db.o \
 	linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \
 	linux-waitpid.o ppc-linux.o linux-personality.o
diff --git a/gdb/config/powerpc/spu-linux.mh b/gdb/config/powerpc/spu-linux.mh
index d44aeeb..38f1588 100644
--- a/gdb/config/powerpc/spu-linux.mh
+++ b/gdb/config/powerpc/spu-linux.mh
@@ -3,6 +3,6 @@ 
 # This implements a 'pseudo-native' GDB running on the
 # PPU side of the Cell BE and debugging the SPU side.
 
-NATDEPFILES = spu-linux-nat.o fork-child.o inf-ptrace.o \
+NATDEPFILES = spu-linux-nat.o fork-child.o inf-ptrace.o ptrace-utils.o \
 	      linux-procfs.o linux-ptrace.o linux-waitpid.o linux-personality.o
 
diff --git a/gdb/config/s390/linux.mh b/gdb/config/s390/linux.mh
index e1ad899..11fd721 100644
--- a/gdb/config/s390/linux.mh
+++ b/gdb/config/s390/linux.mh
@@ -1,6 +1,6 @@ 
 # Host: S390, running Linux
 NAT_FILE= config/nm-linux.h
-NATDEPFILES= inf-ptrace.o fork-child.o s390-linux-nat.o \
+NATDEPFILES= inf-ptrace.o ptrace-utils.o fork-child.o s390-linux-nat.o \
 	linux-thread-db.o proc-service.o \
 	linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \
 	linux-personality.o \
diff --git a/gdb/config/sh/nbsd.mh b/gdb/config/sh/nbsd.mh
index d5e67cb..d97e699 100644
--- a/gdb/config/sh/nbsd.mh
+++ b/gdb/config/sh/nbsd.mh
@@ -1,2 +1,2 @@ 
 # Host: NetBSD/sh
-NATDEPFILES= fork-child.o inf-ptrace.o shnbsd-nat.o
+NATDEPFILES= fork-child.o inf-ptrace.o ptrace-utils.o shnbsd-nat.o
diff --git a/gdb/config/sparc/fbsd.mh b/gdb/config/sparc/fbsd.mh
index 2774efb..45579b4 100644
--- a/gdb/config/sparc/fbsd.mh
+++ b/gdb/config/sparc/fbsd.mh
@@ -1,5 +1,5 @@ 
 # Host: FreeBSD/sparc64
-NATDEPFILES= fork-child.o inf-ptrace.o \
+NATDEPFILES= fork-child.o inf-ptrace.o ptrace-utils.o \
 	fbsd-nat.o sparc-nat.o sparc64-nat.o sparc64fbsd-nat.o \
 	bsd-kvm.o
 HAVE_NATIVE_GCORE_HOST = 1
diff --git a/gdb/config/sparc/linux.mh b/gdb/config/sparc/linux.mh
index bd7fc86..3b43eab 100644
--- a/gdb/config/sparc/linux.mh
+++ b/gdb/config/sparc/linux.mh
@@ -1,7 +1,7 @@ 
 # Host: GNU/Linux SPARC
 NAT_FILE= config/nm-linux.h
 NATDEPFILES= sparc-nat.o sparc-linux-nat.o \
-	fork-child.o inf-ptrace.o \
+	fork-child.o inf-ptrace.o ptrace-utils.o \
 	proc-service.o linux-thread-db.o \
 	linux-nat.o linux-osdata.o linux-fork.o \
 	linux-procfs.o linux-ptrace.o linux-waitpid.o \
diff --git a/gdb/config/sparc/linux64.mh b/gdb/config/sparc/linux64.mh
index 86f984f..2f4d163 100644
--- a/gdb/config/sparc/linux64.mh
+++ b/gdb/config/sparc/linux64.mh
@@ -1,7 +1,7 @@ 
 # Host: GNU/Linux UltraSPARC
 NAT_FILE= config/nm-linux.h
 NATDEPFILES= sparc-nat.o sparc64-nat.o sparc64-linux-nat.o \
-	fork-child.o inf-ptrace.o \
+	fork-child.o inf-ptrace.o ptrace-utils.o \
 	proc-service.o linux-thread-db.o \
 	linux-nat.o linux-osdata.o linux-fork.o \
 	linux-procfs.o linux-ptrace.o linux-waitpid.o \
diff --git a/gdb/config/sparc/nbsd64.mh b/gdb/config/sparc/nbsd64.mh
index 056b74d..5a9ea07 100644
--- a/gdb/config/sparc/nbsd64.mh
+++ b/gdb/config/sparc/nbsd64.mh
@@ -1,5 +1,5 @@ 
 # Host: NetBSD/sparc64
-NATDEPFILES= fork-child.o inf-ptrace.o \
+NATDEPFILES= fork-child.o inf-ptrace.o ptrace-utils.o \
 	sparc64nbsd-nat.o sparc-nat.o bsd-kvm.o
 
 LOADLIBES= -lkvm
diff --git a/gdb/config/sparc/nbsdelf.mh b/gdb/config/sparc/nbsdelf.mh
index 6bf898f..6ae92bf 100644
--- a/gdb/config/sparc/nbsdelf.mh
+++ b/gdb/config/sparc/nbsdelf.mh
@@ -1,5 +1,5 @@ 
 # Host: NetBSD/sparc ELF
-NATDEPFILES= fork-child.o inf-ptrace.o \
+NATDEPFILES= fork-child.o inf-ptrace.o ptrace-utils.o \
 	sparc-nat.o sparcnbsd-nat.o bsd-kvm.o
 
 LOADLIBES= -lkvm
diff --git a/gdb/config/sparc/obsd64.mh b/gdb/config/sparc/obsd64.mh
index d15e34d..d82386c 100644
--- a/gdb/config/sparc/obsd64.mh
+++ b/gdb/config/sparc/obsd64.mh
@@ -1,5 +1,5 @@ 
 # Host: OpenBSD/sparc64
-NATDEPFILES= fork-child.o inf-ptrace.o obsd-nat.o \
+NATDEPFILES= fork-child.o inf-ptrace.o ptrace-utils.o obsd-nat.o \
 	sparc64obsd-nat.o sparc-nat.o bsd-kvm.o
 
 LOADLIBES= -lkvm
diff --git a/gdb/config/tilegx/linux.mh b/gdb/config/tilegx/linux.mh
index b5edcd4..cdc96b9 100644
--- a/gdb/config/tilegx/linux.mh
+++ b/gdb/config/tilegx/linux.mh
@@ -1,7 +1,7 @@ 
 # Host: Tilera TILE-Gx running GNU/Linux.
 
 NAT_FILE= config/nm-linux.h
-NATDEPFILES= inf-ptrace.o fork-child.o \
+NATDEPFILES= inf-ptrace.o ptrace-utils.o fork-child.o \
 	tilegx-linux-nat.o \
 	proc-service.o linux-thread-db.o \
 	linux-nat.o linux-osdata.o linux-fork.o \
diff --git a/gdb/config/vax/nbsdelf.mh b/gdb/config/vax/nbsdelf.mh
index dd9441b..28f0276 100644
--- a/gdb/config/vax/nbsdelf.mh
+++ b/gdb/config/vax/nbsdelf.mh
@@ -1,5 +1,5 @@ 
 # Host: NetBSD/vax ELF
-NATDEPFILES= fork-child.o inf-ptrace.o \
+NATDEPFILES= fork-child.o inf-ptrace.o ptrace-utils.o \
 	vaxbsd-nat.o bsd-kvm.o
 
 LOADLIBES= -lkvm
diff --git a/gdb/config/vax/obsd.mh b/gdb/config/vax/obsd.mh
index d4d444f..57e729e 100644
--- a/gdb/config/vax/obsd.mh
+++ b/gdb/config/vax/obsd.mh
@@ -1,5 +1,5 @@ 
 # Host: OpenBSD/vax
-NATDEPFILES= fork-child.o inf-ptrace.o \
+NATDEPFILES= fork-child.o inf-ptrace.o ptrace-utils.o \
 	vaxbsd-nat.o bsd-kvm.o
 
 LOADLIBES= -lkvm
diff --git a/gdb/config/xtensa/linux.mh b/gdb/config/xtensa/linux.mh
index b4e59b3..50779d8 100644
--- a/gdb/config/xtensa/linux.mh
+++ b/gdb/config/xtensa/linux.mh
@@ -2,7 +2,7 @@ 
 
 NAT_FILE= config/nm-linux.h
 
-NATDEPFILES= inf-ptrace.o fork-child.o xtensa-linux-nat.o \
+NATDEPFILES= inf-ptrace.o ptrace-utils.o fork-child.o xtensa-linux-nat.o \
 	linux-thread-db.o proc-service.o \
 	linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \
 	linux-waitpid.o linux-personality.o
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 6dddf26..f3ef383 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -179,7 +179,8 @@  SFILES=	$(srcdir)/gdbreplay.c $(srcdir)/inferiors.c $(srcdir)/dll.c \
 	$(srcdir)/common/rsp-low.c $(srcdir)/common/errors.c \
 	$(srcdir)/common/common-debug.c $(srcdir)/common/cleanups.c \
 	$(srcdir)/common/common-exceptions.c $(srcdir)/symbol.c \
-	$(srcdir)/common/btrace-common.c
+	$(srcdir)/common/btrace-common.c \
+	$(srcdir)/nat/ptrace-utils.c
 
 DEPFILES = @GDBSERVER_DEPFILES@
 
@@ -605,6 +606,9 @@  linux-personality.o: ../nat/linux-personality.c
 btrace-common.o: ../common/btrace-common.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
+ptrace-utils.o: ../nat/ptrace-utils.c
+	$(COMPILE) $<
+	$(POSTCOMPILE)
 
 aarch64.c : $(srcdir)/../regformats/aarch64.dat $(regdat_sh)
 	$(SHELL) $(regdat_sh) $(srcdir)/../regformats/aarch64.dat aarch64.c
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index 98dd0d9..69fe157 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -42,7 +42,7 @@  srv_amd64_linux_xmlfiles="i386/amd64-linux.xml i386/amd64-avx-linux.xml i386/amd
 
 # Linux object files.  This is so we don't have to repeat
 # these files over and over again.
-srv_linux_obj="linux-low.o linux-osdata.o linux-procfs.o linux-ptrace.o linux-waitpid.o linux-personality.o"
+srv_linux_obj="linux-low.o linux-osdata.o linux-procfs.o linux-ptrace.o linux-waitpid.o linux-personality.o ptrace-utils.o"
 
 # Input is taken from the "${target}" variable.
 
diff --git a/gdb/hppanbsd-nat.c b/gdb/hppanbsd-nat.c
index 0c96b49..568de05 100644
--- a/gdb/hppanbsd-nat.c
+++ b/gdb/hppanbsd-nat.c
@@ -27,6 +27,7 @@ 
 
 #include "hppa-tdep.h"
 #include "inf-ptrace.h"
+#include "nat/ptrace-utils.h"
 
 #include "nbsd-nat.h"
 
@@ -169,7 +170,7 @@  hppanbsd_fetch_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-	perror_with_name (_("Couldn't get registers"));
+	throw_ptrace_error (_("Couldn't get registers"));
 
       hppanbsd_supply_gregset (regcache, &regs);
     }
@@ -180,7 +181,7 @@  hppanbsd_fetch_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't get floating point status"));
+	throw_ptrace_error (_("Couldn't get floating point status"));
 
       hppanbsd_supply_fpregset (regcache, &fpregs);
     }
@@ -199,13 +200,13 @@  hppanbsd_store_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
                   (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-        perror_with_name (_("Couldn't get registers"));
+        throw_ptrace_error (_("Couldn't get registers"));
 
       hppanbsd_collect_gregset (regcache, &regs, regnum);
 
       if (ptrace (PT_SETREGS, ptid_get_pid (inferior_ptid),
 	          (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-        perror_with_name (_("Couldn't write registers"));
+        throw_ptrace_error (_("Couldn't write registers"));
     }
 
   if (regnum == -1 || hppanbsd_fpregset_supplies_p (regnum))
@@ -214,13 +215,13 @@  hppanbsd_store_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't get floating point status"));
+	throw_ptrace_error (_("Couldn't get floating point status"));
 
       hppanbsd_collect_fpregset (regcache, &fpregs, regnum);
 
       if (ptrace (PT_SETFPREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't write floating point status"));
+	throw_ptrace_error (_("Couldn't write floating point status"));
     }
 }
 
diff --git a/gdb/hppaobsd-nat.c b/gdb/hppaobsd-nat.c
index fe49b99..5728b6c 100644
--- a/gdb/hppaobsd-nat.c
+++ b/gdb/hppaobsd-nat.c
@@ -28,6 +28,7 @@ 
 
 #include "hppa-tdep.h"
 #include "inf-ptrace.h"
+#include "nat/ptrace-utils.h"
 
 #include "obsd-nat.h"
 
@@ -195,7 +196,7 @@  hppaobsd_fetch_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-	perror_with_name (_("Couldn't get registers"));
+	throw_ptrace_error (_("Couldn't get registers"));
 
       hppaobsd_supply_gregset (regcache, &regs);
     }
@@ -206,7 +207,7 @@  hppaobsd_fetch_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't get floating point status"));
+	throw_ptrace_error (_("Couldn't get floating point status"));
 
       hppaobsd_supply_fpregset (regcache, &fpregs);
     }
@@ -225,13 +226,13 @@  hppaobsd_store_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
                   (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-        perror_with_name (_("Couldn't get registers"));
+        throw_ptrace_error (_("Couldn't get registers"));
 
       hppaobsd_collect_gregset (regcache, &regs, regnum);
 
       if (ptrace (PT_SETREGS, ptid_get_pid (inferior_ptid),
 	          (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-        perror_with_name (_("Couldn't write registers"));
+        throw_ptrace_error (_("Couldn't write registers"));
     }
 
   if (regnum == -1 || hppaobsd_fpregset_supplies_p (regnum))
@@ -240,13 +241,13 @@  hppaobsd_store_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't get floating point status"));
+	throw_ptrace_error (_("Couldn't get floating point status"));
 
       hppaobsd_collect_fpregset (regcache, &fpregs, regnum);
 
       if (ptrace (PT_SETFPREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't write floating point status"));
+	throw_ptrace_error (_("Couldn't write floating point status"));
     }
 }
 
diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c
index 8cb8c66..1a0dfc0 100644
--- a/gdb/i386-linux-nat.c
+++ b/gdb/i386-linux-nat.c
@@ -34,6 +34,7 @@ 
 #include "x86-xstate.h"
 
 #include "x86-linux-nat.h"
+#include "nat/ptrace-utils.h"
 
 /* The register sets used in GNU/Linux ELF core-dumps are identical to
    the register sets in `struct user' that is used for a.out
@@ -212,7 +213,7 @@  fetch_regs (struct regcache *regcache, int tid)
 	  return;
 	}
 
-      perror_with_name (_("Couldn't get registers"));
+      throw_ptrace_error (_("Couldn't get registers"));
     }
 
   supply_gregset (regcache, (const elf_gregset_t *) regs_p);
@@ -227,12 +228,12 @@  store_regs (const struct regcache *regcache, int tid, int regno)
   elf_gregset_t regs;
 
   if (ptrace (PTRACE_GETREGS, tid, 0, (int) &regs) < 0)
-    perror_with_name (_("Couldn't get registers"));
+    throw_ptrace_error (_("Couldn't get registers"));
 
   fill_gregset (regcache, &regs, regno);
   
   if (ptrace (PTRACE_SETREGS, tid, 0, (int) &regs) < 0)
-    perror_with_name (_("Couldn't write registers"));
+    throw_ptrace_error (_("Couldn't write registers"));
 }
 
 #else
@@ -276,7 +277,7 @@  fetch_fpregs (struct regcache *regcache, int tid)
   elf_fpregset_t fpregs;
 
   if (ptrace (PTRACE_GETFPREGS, tid, 0, (int) &fpregs) < 0)
-    perror_with_name (_("Couldn't get floating point status"));
+    throw_ptrace_error (_("Couldn't get floating point status"));
 
   supply_fpregset (regcache, (const elf_fpregset_t *) &fpregs);
 }
@@ -290,12 +291,12 @@  store_fpregs (const struct regcache *regcache, int tid, int regno)
   elf_fpregset_t fpregs;
 
   if (ptrace (PTRACE_GETFPREGS, tid, 0, (int) &fpregs) < 0)
-    perror_with_name (_("Couldn't get floating point status"));
+    throw_ptrace_error (_("Couldn't get floating point status"));
 
   fill_fpregset (regcache, &fpregs, regno);
 
   if (ptrace (PTRACE_SETFPREGS, tid, 0, (int) &fpregs) < 0)
-    perror_with_name (_("Couldn't write floating point status"));
+    throw_ptrace_error (_("Couldn't write floating point status"));
 }
 
 #else
@@ -332,7 +333,7 @@  fetch_xstateregs (struct regcache *regcache, int tid)
   iov.iov_len = sizeof(xstateregs);
   if (ptrace (PTRACE_GETREGSET, tid, (unsigned int) NT_X86_XSTATE,
 	      &iov) < 0)
-    perror_with_name (_("Couldn't read extended state status"));
+    throw_ptrace_error (_("Couldn't read extended state status"));
 
   i387_supply_xsave (regcache, -1, xstateregs);
   return 1;
@@ -355,13 +356,13 @@  store_xstateregs (const struct regcache *regcache, int tid, int regno)
   iov.iov_len = sizeof(xstateregs);
   if (ptrace (PTRACE_GETREGSET, tid, (unsigned int) NT_X86_XSTATE,
 	      &iov) < 0)
-    perror_with_name (_("Couldn't read extended state status"));
+    throw_ptrace_error (_("Couldn't read extended state status"));
 
   i387_collect_xsave (regcache, regno, xstateregs, 0);
 
   if (ptrace (PTRACE_SETREGSET, tid, (unsigned int) NT_X86_XSTATE,
 	      (int) &iov) < 0)
-    perror_with_name (_("Couldn't write extended state status"));
+    throw_ptrace_error (_("Couldn't write extended state status"));
 
   return 1;
 }
@@ -388,7 +389,7 @@  fetch_fpxregs (struct regcache *regcache, int tid)
 	  return 0;
 	}
 
-      perror_with_name (_("Couldn't read floating-point and SSE registers"));
+      throw_ptrace_error (_("Couldn't read floating-point and SSE registers"));
     }
 
   i387_supply_fxsave (regcache, -1, (const elf_fpxregset_t *) &fpxregs);
@@ -415,13 +416,13 @@  store_fpxregs (const struct regcache *regcache, int tid, int regno)
 	  return 0;
 	}
 
-      perror_with_name (_("Couldn't read floating-point and SSE registers"));
+      throw_ptrace_error (_("Couldn't read floating-point and SSE registers"));
     }
 
   i387_collect_fxsave (regcache, regno, &fpxregs);
 
   if (ptrace (PTRACE_SETFPXREGS, tid, 0, &fpxregs) == -1)
-    perror_with_name (_("Couldn't write floating-point and SSE registers"));
+    throw_ptrace_error (_("Couldn't write floating-point and SSE registers"));
 
   return 1;
 }
@@ -709,7 +710,7 @@  i386_linux_resume (struct target_ops *ops,
     }
 
   if (ptrace (request, pid, 0, gdb_signal_to_host (signal)) == -1)
-    perror_with_name (("ptrace"));
+    throw_ptrace_error (("ptrace"));
 }
 
 
diff --git a/gdb/i386bsd-nat.c b/gdb/i386bsd-nat.c
index 16e0707..44b24b0 100644
--- a/gdb/i386bsd-nat.c
+++ b/gdb/i386bsd-nat.c
@@ -31,6 +31,7 @@ 
 #include "i387-tdep.h"
 #include "i386bsd-nat.h"
 #include "inf-ptrace.h"
+#include "nat/ptrace-utils.h"
 
 
 /* In older BSD versions we cannot get at some of the segment
@@ -136,7 +137,7 @@  i386bsd_fetch_inferior_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-	perror_with_name (_("Couldn't get registers"));
+	throw_ptrace_error (_("Couldn't get registers"));
 
       i386bsd_supply_gregset (regcache, &regs);
       if (regnum != -1)
@@ -160,14 +161,14 @@  i386bsd_fetch_inferior_registers (struct target_ops *ops,
 	{
           if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
 		      (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	    perror_with_name (_("Couldn't get floating point status"));
+	    throw_ptrace_error (_("Couldn't get floating point status"));
 
 	  i387_supply_fsave (regcache, -1, &fpregs);
 	}
 #else
       if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't get floating point status"));
+	throw_ptrace_error (_("Couldn't get floating point status"));
 
       i387_supply_fsave (regcache, -1, &fpregs);
 #endif
@@ -187,13 +188,13 @@  i386bsd_store_inferior_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
                   (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-        perror_with_name (_("Couldn't get registers"));
+        throw_ptrace_error (_("Couldn't get registers"));
 
       i386bsd_collect_gregset (regcache, &regs, regnum);
 
       if (ptrace (PT_SETREGS, ptid_get_pid (inferior_ptid),
 	          (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-        perror_with_name (_("Couldn't write registers"));
+        throw_ptrace_error (_("Couldn't write registers"));
 
       if (regnum != -1)
 	return;
@@ -215,7 +216,7 @@  i386bsd_store_inferior_registers (struct target_ops *ops,
 
 	  if (ptrace (PT_SETXMMREGS, ptid_get_pid (inferior_ptid),
 		      (PTRACE_TYPE_ARG3) xmmregs, 0) == -1)
-            perror_with_name (_("Couldn't write XMM registers"));
+            throw_ptrace_error (_("Couldn't write XMM registers"));
 	}
       else
 	{
@@ -223,13 +224,13 @@  i386bsd_store_inferior_registers (struct target_ops *ops,
 #endif
           if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
 		      (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	    perror_with_name (_("Couldn't get floating point status"));
+	    throw_ptrace_error (_("Couldn't get floating point status"));
 
           i387_collect_fsave (regcache, regnum, &fpregs);
 
           if (ptrace (PT_SETFPREGS, ptid_get_pid (inferior_ptid),
 		      (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	    perror_with_name (_("Couldn't write floating point status"));
+	    throw_ptrace_error (_("Couldn't write floating point status"));
 #ifdef HAVE_PT_GETXMMREGS
         }
 #endif
@@ -268,7 +269,7 @@  i386bsd_dr_get (ptid_t ptid, int regnum)
 
   if (ptrace (PT_GETDBREGS, ptid_get_pid (inferior_ptid),
 	      (PTRACE_TYPE_ARG3) &dbregs, 0) == -1)
-    perror_with_name (_("Couldn't read debug registers"));
+    throw_ptrace_error (_("Couldn't read debug registers"));
 
   return DBREG_DRX ((&dbregs), regnum);
 }
@@ -280,7 +281,7 @@  i386bsd_dr_set (int regnum, unsigned int value)
 
   if (ptrace (PT_GETDBREGS, ptid_get_pid (inferior_ptid),
               (PTRACE_TYPE_ARG3) &dbregs, 0) == -1)
-    perror_with_name (_("Couldn't get debug registers"));
+    throw_ptrace_error (_("Couldn't get debug registers"));
 
   /* For some mysterious reason, some of the reserved bits in the
      debug control register get set.  Mask these off, otherwise the
@@ -291,7 +292,7 @@  i386bsd_dr_set (int regnum, unsigned int value)
 
   if (ptrace (PT_SETDBREGS, ptid_get_pid (inferior_ptid),
               (PTRACE_TYPE_ARG3) &dbregs, 0) == -1)
-    perror_with_name (_("Couldn't write debug registers"));
+    throw_ptrace_error (_("Couldn't write debug registers"));
 }
 
 void
diff --git a/gdb/i386fbsd-nat.c b/gdb/i386fbsd-nat.c
index ad439e3..ad37c13 100644
--- a/gdb/i386fbsd-nat.c
+++ b/gdb/i386fbsd-nat.c
@@ -31,6 +31,7 @@ 
 #include "i386-tdep.h"
 #include "x86-nat.h"
 #include "i386bsd-nat.h"
+#include "nat/ptrace-utils.h"
 
 /* Resume execution of the inferior process.  If STEP is nonzero,
    single-step it.  If SIGNAL is nonzero, give it that signal.  */
@@ -77,7 +78,7 @@  i386fbsd_resume (struct target_ops *ops,
      written a new PC value to the child.)  */
   if (ptrace (request, pid, (caddr_t) 1,
 	      gdb_signal_to_host (signal)) == -1)
-    perror_with_name (("ptrace"));
+    throw_ptrace_error (("ptrace"));
 }
 
 
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index cd58dfb..06382d5 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -29,6 +29,7 @@ 
 #include <signal.h>
 
 #include "inf-ptrace.h"
+#include "nat/ptrace-utils.h"
 #include "inf-child.h"
 #include "gdbthread.h"
 
@@ -52,7 +53,7 @@  inf_ptrace_follow_fork (struct target_ops *ops, int follow_child,
 	 infrun.c.  */
 
       if (ptrace (PT_DETACH, child_pid, (PTRACE_TYPE_ARG3)1, 0) == -1)
-	perror_with_name (("ptrace"));
+	throw_ptrace_error (("ptrace"));
     }
 
   return 0;
@@ -130,7 +131,7 @@  inf_ptrace_post_startup_inferior (struct target_ops *self, ptid_t pid)
   pe.pe_set_event |= PTRACE_FORK;
   if (ptrace (PT_SET_EVENT_MASK, ptid_get_pid (pid),
 	      (PTRACE_TYPE_ARG3)&pe, sizeof pe) == -1)
-    perror_with_name (("ptrace"));
+    throw_ptrace_error (("ptrace"));
 }
 
 #endif
@@ -197,7 +198,7 @@  inf_ptrace_attach (struct target_ops *ops, const char *args, int from_tty)
   errno = 0;
   ptrace (PT_ATTACH, pid, (PTRACE_TYPE_ARG3)0, 0);
   if (errno != 0)
-    perror_with_name (("ptrace"));
+    throw_ptrace_error (("ptrace"));
 #else
   error (_("This system does not support attaching to a process"));
 #endif
@@ -226,7 +227,7 @@  inf_ptrace_post_attach (struct target_ops *self, int pid)
   pe.pe_set_event |= PTRACE_FORK;
   if (ptrace (PT_SET_EVENT_MASK, pid,
 	      (PTRACE_TYPE_ARG3)&pe, sizeof pe) == -1)
-    perror_with_name (("ptrace"));
+    throw_ptrace_error (("ptrace"));
 }
 
 #endif
@@ -260,7 +261,7 @@  inf_ptrace_detach (struct target_ops *ops, const char *args, int from_tty)
   errno = 0;
   ptrace (PT_DETACH, pid, (PTRACE_TYPE_ARG3)1, sig);
   if (errno != 0)
-    perror_with_name (("ptrace"));
+    throw_ptrace_error (("ptrace"));
 #else
   error (_("This system does not support detaching from a process"));
 #endif
@@ -356,7 +357,7 @@  inf_ptrace_resume (struct target_ops *ops,
   errno = 0;
   ptrace (request, pid, (PTRACE_TYPE_ARG3)1, gdb_signal_to_host (signal));
   if (errno != 0)
-    perror_with_name (("ptrace"));
+    throw_ptrace_error (("ptrace"));
 }
 
 /* Wait for the child specified by PTID to do something.  Return the
@@ -409,7 +410,7 @@  inf_ptrace_wait (struct target_ops *ops,
 
       if (ptrace (PT_GET_PROCESS_STATE, pid,
 		  (PTRACE_TYPE_ARG3)&pe, sizeof pe) == -1)
-	perror_with_name (("ptrace"));
+	throw_ptrace_error (("ptrace"));
 
       switch (pe.pe_report_event)
 	{
@@ -420,11 +421,11 @@  inf_ptrace_wait (struct target_ops *ops,
 	  /* Make sure the other end of the fork is stopped too.  */
 	  fpid = waitpid (pe.pe_other_pid, &status, 0);
 	  if (fpid == -1)
-	    perror_with_name (("waitpid"));
+	    throw_ptrace_error (("waitpid"));
 
 	  if (ptrace (PT_GET_PROCESS_STATE, fpid,
 		      (PTRACE_TYPE_ARG3)&pe, sizeof pe) == -1)
-	    perror_with_name (("ptrace"));
+	    throw_ptrace_error (("ptrace"));
 
 	  gdb_assert (pe.pe_report_event == PTRACE_FORK);
 	  gdb_assert (pe.pe_other_pid == pid);
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 627280e..20fe533 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -40,6 +40,7 @@ 
 #include "regset.h"
 #include "inf-child.h"
 #include "inf-ptrace.h"
+#include "nat/ptrace-utils.h"
 #include "auxv.h"
 #include <sys/procfs.h>		/* for elf_gregset etc.  */
 #include "elf-bfd.h"		/* for elfcore_write_* */
@@ -425,7 +426,7 @@  linux_child_follow_fork (struct target_ops *ops, int follow_child,
 	    {
 	      linux_disable_event_reporting (child_pid);
 	      if (ptrace (PTRACE_SINGLESTEP, child_pid, 0, 0) < 0)
-		perror_with_name (_("Couldn't do single step"));
+		throw_ptrace_error (_("Couldn't do single step"));
 	      if (my_waitpid (child_pid, &status, 0) < 0)
 		perror_with_name (_("Couldn't wait vfork process"));
 	    }
diff --git a/gdb/m32r-linux-nat.c b/gdb/m32r-linux-nat.c
index e5e867b..3ece241 100644
--- a/gdb/m32r-linux-nat.c
+++ b/gdb/m32r-linux-nat.c
@@ -22,6 +22,7 @@ 
 #include "gdbcore.h"
 #include "regcache.h"
 #include "linux-nat.h"
+#include "nat/ptrace-utils.h"
 #include "target.h"
 #include <sys/ptrace.h>
 #include <sys/user.h>
@@ -109,7 +110,7 @@  fetch_regs (struct regcache *regcache, int tid)
   elf_gregset_t regs;
 
   if (ptrace (PTRACE_GETREGS, tid, 0, (int) &regs) < 0)
-    perror_with_name (_("Couldn't get registers"));
+    throw_ptrace_error (_("Couldn't get registers"));
 
   supply_gregset (regcache, (const elf_gregset_t *) &regs);
 }
@@ -158,12 +159,12 @@  store_regs (const struct regcache *regcache, int tid, int regno)
   elf_gregset_t regs;
 
   if (ptrace (PTRACE_GETREGS, tid, 0, (int) &regs) < 0)
-    perror_with_name (_("Couldn't get registers"));
+    throw_ptrace_error (_("Couldn't get registers"));
 
   fill_gregset (regcache, &regs, regno);
 
   if (ptrace (PTRACE_SETREGS, tid, 0, (int) &regs) < 0)
-    perror_with_name (_("Couldn't write registers"));
+    throw_ptrace_error (_("Couldn't write registers"));
 }
 
 
diff --git a/gdb/m68kbsd-nat.c b/gdb/m68kbsd-nat.c
index 0b7ea21..2126dfd 100644
--- a/gdb/m68kbsd-nat.c
+++ b/gdb/m68kbsd-nat.c
@@ -28,6 +28,7 @@ 
 
 #include "m68k-tdep.h"
 #include "inf-ptrace.h"
+#include "nat/ptrace-utils.h"
 
 static int
 m68kbsd_gregset_supplies_p (int regnum)
@@ -117,7 +118,7 @@  m68kbsd_fetch_inferior_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-	perror_with_name (_("Couldn't get registers"));
+	throw_ptrace_error (_("Couldn't get registers"));
 
       m68kbsd_supply_gregset (regcache, &regs);
     }
@@ -128,7 +129,7 @@  m68kbsd_fetch_inferior_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't get floating point status"));
+	throw_ptrace_error (_("Couldn't get floating point status"));
 
       m68kbsd_supply_fpregset (regcache, &fpregs);
     }
@@ -147,13 +148,13 @@  m68kbsd_store_inferior_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
                   (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-        perror_with_name (_("Couldn't get registers"));
+        throw_ptrace_error (_("Couldn't get registers"));
 
       m68kbsd_collect_gregset (regcache, &regs, regnum);
 
       if (ptrace (PT_SETREGS, ptid_get_pid (inferior_ptid),
 	          (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-        perror_with_name (_("Couldn't write registers"));
+        throw_ptrace_error (_("Couldn't write registers"));
     }
 
   if (regnum == -1 || m68kbsd_fpregset_supplies_p (regnum))
@@ -162,13 +163,13 @@  m68kbsd_store_inferior_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't get floating point status"));
+	throw_ptrace_error (_("Couldn't get floating point status"));
 
       m68kbsd_collect_fpregset (regcache, &fpregs, regnum);
 
       if (ptrace (PT_SETFPREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't write floating point status"));
+	throw_ptrace_error (_("Couldn't write floating point status"));
     }
 }
 
diff --git a/gdb/m68klinux-nat.c b/gdb/m68klinux-nat.c
index 8f89d7b..ee95ffd 100644
--- a/gdb/m68klinux-nat.c
+++ b/gdb/m68klinux-nat.c
@@ -265,7 +265,7 @@  fetch_regs (struct regcache *regcache, int tid)
 	  return;
 	}
 
-      perror_with_name (_("Couldn't get registers"));
+      throw_ptrace_error (_("Couldn't get registers"));
     }
 
   supply_gregset (regcache, (const elf_gregset_t *) &regs);
@@ -280,12 +280,12 @@  store_regs (const struct regcache *regcache, int tid, int regno)
   elf_gregset_t regs;
 
   if (ptrace (PTRACE_GETREGS, tid, 0, (int) &regs) < 0)
-    perror_with_name (_("Couldn't get registers"));
+    throw_ptrace_error (_("Couldn't get registers"));
 
   fill_gregset (regcache, &regs, regno);
 
   if (ptrace (PTRACE_SETREGS, tid, 0, (int) &regs) < 0)
-    perror_with_name (_("Couldn't write registers"));
+    throw_ptrace_error (_("Couldn't write registers"));
 }
 
 #else
@@ -362,7 +362,7 @@  fetch_fpregs (struct regcache *regcache, int tid)
   elf_fpregset_t fpregs;
 
   if (ptrace (PTRACE_GETFPREGS, tid, 0, (int) &fpregs) < 0)
-    perror_with_name (_("Couldn't get floating point status"));
+    throw_ptrace_error (_("Couldn't get floating point status"));
 
   supply_fpregset (regcache, (const elf_fpregset_t *) &fpregs);
 }
@@ -376,12 +376,12 @@  store_fpregs (const struct regcache *regcache, int tid, int regno)
   elf_fpregset_t fpregs;
 
   if (ptrace (PTRACE_GETFPREGS, tid, 0, (int) &fpregs) < 0)
-    perror_with_name (_("Couldn't get floating point status"));
+    throw_ptrace_error (_("Couldn't get floating point status"));
 
   fill_fpregset (regcache, &fpregs, regno);
 
   if (ptrace (PTRACE_SETFPREGS, tid, 0, (int) &fpregs) < 0)
-    perror_with_name (_("Couldn't write floating point status"));
+    throw_ptrace_error (_("Couldn't write floating point status"));
 }
 
 #else
diff --git a/gdb/m88kbsd-nat.c b/gdb/m88kbsd-nat.c
index 22c2a77..85ce83c 100644
--- a/gdb/m88kbsd-nat.c
+++ b/gdb/m88kbsd-nat.c
@@ -28,6 +28,7 @@ 
 
 #include "m88k-tdep.h"
 #include "inf-ptrace.h"
+#include "nat/ptrace-utils.h"
 
 /* Supply the general-purpose registers stored in GREGS to REGCACHE.  */
 
@@ -70,7 +71,7 @@  m88kbsd_fetch_inferior_registers (struct target_ops *ops,
 
   if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
 	      (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-    perror_with_name (_("Couldn't get registers"));
+    throw_ptrace_error (_("Couldn't get registers"));
 
   m88kbsd_supply_gregset (regcache, &regs);
 }
@@ -86,13 +87,13 @@  m88kbsd_store_inferior_registers (struct target_ops *ops,
 
   if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
 	      (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-    perror_with_name (_("Couldn't get registers"));
+    throw_ptrace_error (_("Couldn't get registers"));
 
   m88kbsd_collect_gregset (regcache, &regs, regnum);
 
   if (ptrace (PT_SETREGS, ptid_get_pid (inferior_ptid),
 	      (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-    perror_with_name (_("Couldn't write registers"));
+    throw_ptrace_error (_("Couldn't write registers"));
 }
 
 
diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c
index a36bb63..74b2f98 100644
--- a/gdb/mips-linux-nat.c
+++ b/gdb/mips-linux-nat.c
@@ -36,6 +36,7 @@ 
 #include <asm/ptrace.h>
 
 #include "nat/mips-linux-watch.h"
+#include "nat/ptrace-utils.h"
 
 #include "features/mips-linux.c"
 #include "features/mips-dsp-linux.c"
@@ -259,7 +260,7 @@  mips64_linux_regsets_fetch_registers (struct target_ops *ops,
 	      have_ptrace_regsets = 0;
 	      return;
 	    }
-	  perror_with_name (_("Couldn't get registers"));
+	  throw_ptrace_error (_("Couldn't get registers"));
 	}
 
       mips64_supply_gregset (regcache,
@@ -278,7 +279,7 @@  mips64_linux_regsets_fetch_registers (struct target_ops *ops,
 	      have_ptrace_regsets = 0;
 	      return;
 	    }
-	  perror_with_name (_("Couldn't get FP registers"));
+	  throw_ptrace_error (_("Couldn't get FP registers"));
 	}
 
       mips64_supply_fpregset (regcache,
@@ -341,12 +342,12 @@  mips64_linux_regsets_store_registers (struct target_ops *ops,
       mips64_elf_gregset_t regs;
 
       if (ptrace (PTRACE_GETREGS, tid, 0L, (PTRACE_TYPE_ARG3) &regs) == -1)
-	perror_with_name (_("Couldn't get registers"));
+	throw_ptrace_error (_("Couldn't get registers"));
 
       mips64_fill_gregset (regcache, &regs, regno);
 
       if (ptrace (PTRACE_SETREGS, tid, 0L, (PTRACE_TYPE_ARG3) &regs) == -1)
-	perror_with_name (_("Couldn't set registers"));
+	throw_ptrace_error (_("Couldn't set registers"));
     }
 
   if (regno == -1 || is_fp)
@@ -355,13 +356,13 @@  mips64_linux_regsets_store_registers (struct target_ops *ops,
 
       if (ptrace (PTRACE_GETFPREGS, tid, 0L,
 		  (PTRACE_TYPE_ARG3) &fp_regs) == -1)
-	perror_with_name (_("Couldn't get FP registers"));
+	throw_ptrace_error (_("Couldn't get FP registers"));
 
       mips64_fill_fpregset (regcache, &fp_regs, regno);
 
       if (ptrace (PTRACE_SETFPREGS, tid, 0L,
 		  (PTRACE_TYPE_ARG3) &fp_regs) == -1)
-	perror_with_name (_("Couldn't set FP registers"));
+	throw_ptrace_error (_("Couldn't set FP registers"));
     }
 
   if (is_dsp)
@@ -446,7 +447,7 @@  mips_linux_read_description (struct target_ops *ops)
 	  have_dsp = 0;
 	  break;
 	default:
-	  perror_with_name (_("Couldn't check DSP support"));
+	  throw_ptrace_error (_("Couldn't check DSP support"));
 	  break;
 	}
     }
@@ -615,7 +616,7 @@  write_watchpoint_regs (void)
     {
       tid = ptid_get_lwp (lp->ptid);
       if (ptrace (PTRACE_SET_WATCH_REGS, tid, &watch_mirror) == -1)
-	perror_with_name (_("Couldn't write debug register"));
+	throw_ptrace_error (_("Couldn't write debug register"));
     }
   return 0;
 }
@@ -635,7 +636,7 @@  mips_linux_new_thread (struct lwp_info *lp)
 
   tid = ptid_get_lwp (lp->ptid);
   if (ptrace (PTRACE_SET_WATCH_REGS, tid, &watch_mirror) == -1)
-    perror_with_name (_("Couldn't write debug register"));
+    throw_ptrace_error (_("Couldn't write debug register"));
 }
 
 /* Target to_insert_watchpoint implementation.  Try to insert a new
diff --git a/gdb/mips64obsd-nat.c b/gdb/mips64obsd-nat.c
index 56d4fa9..e268edc 100644
--- a/gdb/mips64obsd-nat.c
+++ b/gdb/mips64obsd-nat.c
@@ -28,6 +28,7 @@ 
 
 #include "mips-tdep.h"
 #include "inf-ptrace.h"
+#include "nat/ptrace-utils.h"
 #include "obsd-nat.h"
 
 /* Shorthand for some register numbers used below.  */
@@ -85,7 +86,7 @@  mips64obsd_fetch_inferior_registers (struct target_ops *ops,
 
   if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
 	      (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-    perror_with_name (_("Couldn't get registers"));
+    throw_ptrace_error (_("Couldn't get registers"));
 
   mips64obsd_supply_gregset (regcache, &regs);
 }
@@ -101,13 +102,13 @@  mips64obsd_store_inferior_registers (struct target_ops *ops,
 
   if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
 	      (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-    perror_with_name (_("Couldn't get registers"));
+    throw_ptrace_error (_("Couldn't get registers"));
 
   mips64obsd_collect_gregset (regcache, &regs, regnum);
 
   if (ptrace (PT_SETREGS, ptid_get_pid (inferior_ptid),
 	      (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-    perror_with_name (_("Couldn't write registers"));
+    throw_ptrace_error (_("Couldn't write registers"));
 }
 
 
diff --git a/gdb/mipsnbsd-nat.c b/gdb/mipsnbsd-nat.c
index 34dcd87..3ff1e96 100644
--- a/gdb/mipsnbsd-nat.c
+++ b/gdb/mipsnbsd-nat.c
@@ -29,6 +29,7 @@ 
 #include "mips-tdep.h"
 #include "mipsnbsd-tdep.h"
 #include "inf-ptrace.h"
+#include "nat/ptrace-utils.h"
 
 /* Determine if PT_GETREGS fetches this register.  */
 static int
@@ -49,7 +50,7 @@  mipsnbsd_fetch_inferior_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-	perror_with_name (_("Couldn't get registers"));
+	throw_ptrace_error (_("Couldn't get registers"));
       
       mipsnbsd_supply_reg (regcache, (char *) &regs, regno);
       if (regno != -1)
@@ -63,7 +64,7 @@  mipsnbsd_fetch_inferior_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't get floating point status"));
+	throw_ptrace_error (_("Couldn't get floating point status"));
 
       mipsnbsd_supply_fpreg (regcache, (char *) &fpregs, regno);
     }
@@ -80,13 +81,13 @@  mipsnbsd_store_inferior_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-	perror_with_name (_("Couldn't get registers"));
+	throw_ptrace_error (_("Couldn't get registers"));
 
       mipsnbsd_fill_reg (regcache, (char *) &regs, regno);
 
       if (ptrace (PT_SETREGS, ptid_get_pid (inferior_ptid), 
 		  (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-	perror_with_name (_("Couldn't write registers"));
+	throw_ptrace_error (_("Couldn't write registers"));
 
       if (regno != -1)
 	return;
@@ -99,13 +100,13 @@  mipsnbsd_store_inferior_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't get floating point status"));
+	throw_ptrace_error (_("Couldn't get floating point status"));
 
       mipsnbsd_fill_fpreg (regcache, (char *) &fpregs, regno);
 
       if (ptrace (PT_SETFPREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't write floating point status"));
+	throw_ptrace_error (_("Couldn't write floating point status"));
     }
 }
 
diff --git a/gdb/nat/ptrace-utils.c b/gdb/nat/ptrace-utils.c
new file mode 100644
index 0000000..a3dc9b5
--- /dev/null
+++ b/gdb/nat/ptrace-utils.c
@@ -0,0 +1,29 @@ 
+/* Misc ptrace utils.
+
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "common-defs.h"
+#include "ptrace-utils.h"
+
+/* See ptrace-utils.h.  */
+
+void
+throw_ptrace_error (const char *string)
+{
+  perror_with_name (string);
+}
diff --git a/gdb/nat/ptrace-utils.h b/gdb/nat/ptrace-utils.h
new file mode 100644
index 0000000..886d156
--- /dev/null
+++ b/gdb/nat/ptrace-utils.h
@@ -0,0 +1,28 @@ 
+/* ptrace utilities.
+
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef PTRACE_UTILS_H
+#define PTRACE_UTILS_H
+
+/* Translates an error out of a ptrace call to a GDB exception.  */
+
+extern void throw_ptrace_error (const char *string)
+  ATTRIBUTE_NORETURN;
+
+#endif
diff --git a/gdb/obsd-nat.c b/gdb/obsd-nat.c
index 72ed10c..2208d3b 100644
--- a/gdb/obsd-nat.c
+++ b/gdb/obsd-nat.c
@@ -28,6 +28,7 @@ 
 
 #include "inf-child.h"
 #include "obsd-nat.h"
+#include "nat/ptrace-utils.h"
 
 /* OpenBSD 5.2 and later include rthreads which uses a thread model
    that maps userland threads directly onto kernel threads in a 1:1
@@ -58,7 +59,7 @@  obsd_update_thread_list (struct target_ops *ops)
   prune_threads ();
 
   if (ptrace (PT_GET_THREAD_FIRST, pid, (caddr_t)&pts, sizeof pts) == -1)
-    perror_with_name (("ptrace"));
+    throw_ptrace_error (("ptrace"));
 
   while (pts.pts_tid != -1)
     {
@@ -73,7 +74,7 @@  obsd_update_thread_list (struct target_ops *ops)
 	}
 
       if (ptrace (PT_GET_THREAD_NEXT, pid, (caddr_t)&pts, sizeof pts) == -1)
-	perror_with_name (("ptrace"));
+	throw_ptrace_error (("ptrace"));
     }
 }
 
@@ -123,7 +124,7 @@  obsd_wait (struct target_ops *ops,
       pid_t fpid;
 
       if (ptrace (PT_GET_PROCESS_STATE, pid, (caddr_t)&pe, sizeof pe) == -1)
-	perror_with_name (("ptrace"));
+	throw_ptrace_error (("ptrace"));
 
       switch (pe.pe_report_event)
 	{
@@ -138,7 +139,7 @@  obsd_wait (struct target_ops *ops,
 
 	  if (ptrace (PT_GET_PROCESS_STATE, fpid,
 		      (caddr_t)&pe, sizeof pe) == -1)
-	    perror_with_name (("ptrace"));
+	    throw_ptrace_error (("ptrace"));
 
 	  gdb_assert (pe.pe_report_event == PTRACE_FORK);
 	  gdb_assert (pe.pe_other_pid == pid);
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 88ca49e..779a84a 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -47,6 +47,7 @@ 
 #include "auxv.h"
 
 #include "nat/ppc-linux.h"
+#include "nat/ptrace-utils.h"
 
 /* Similarly for the hardware watchpoint support.  These requests are used
    when the PowerPC HWDEBUG ptrace interface is not available.  */
@@ -372,7 +373,7 @@  fetch_vsx_register (struct regcache *regcache, int tid, int regno)
 	  have_ptrace_getsetvsxregs = 0;
 	  return;
 	}
-      perror_with_name (_("Unable to fetch VSX register"));
+      throw_ptrace_error (_("Unable to fetch VSX register"));
     }
 
   regcache_raw_supply (regcache, regno,
@@ -401,7 +402,7 @@  fetch_altivec_register (struct regcache *regcache, int tid, int regno)
           have_ptrace_getvrregs = 0;
           return;
         }
-      perror_with_name (_("Unable to fetch AltiVec register"));
+      throw_ptrace_error (_("Unable to fetch AltiVec register"));
     }
  
   /* VSCR is fetched as a 16 bytes quantity, but it is really 4 bytes
@@ -439,7 +440,7 @@  get_spe_registers (int tid, struct gdb_evrregset_t *evrregset)
             have_ptrace_getsetevrregs = 0;
           else
             /* Anything else needs to be reported.  */
-            perror_with_name (_("Unable to fetch SPE registers"));
+            throw_ptrace_error (_("Unable to fetch SPE registers"));
         }
     }
 
@@ -553,7 +554,7 @@  fetch_register (struct regcache *regcache, int tid, int regno)
           char message[128];
 	  xsnprintf (message, sizeof (message), "reading register %s (#%d)",
 		     gdbarch_register_name (gdbarch, regno), regno);
-	  perror_with_name (message);
+	  throw_ptrace_error (message);
 	}
       memcpy (&buf[bytes_transferred], &l, sizeof (l));
     }
@@ -634,7 +635,7 @@  fetch_vsx_registers (struct regcache *regcache, int tid)
 	  have_ptrace_getsetvsxregs = 0;
 	  return;
 	}
-      perror_with_name (_("Unable to fetch VSX registers"));
+      throw_ptrace_error (_("Unable to fetch VSX registers"));
     }
   supply_vsxregset (regcache, &regs);
 }
@@ -653,7 +654,7 @@  fetch_altivec_registers (struct regcache *regcache, int tid)
           have_ptrace_getvrregs = 0;
 	  return;
 	}
-      perror_with_name (_("Unable to fetch AltiVec registers"));
+      throw_ptrace_error (_("Unable to fetch AltiVec registers"));
     }
   supply_vrregset (regcache, &regs);
 }
@@ -664,7 +665,7 @@  fetch_altivec_registers (struct regcache *regcache, int tid)
    
    If the ptrace request does not exist, this function returns 0
    and properly sets the have_ptrace_* flag.  If the request fails,
-   this function calls perror_with_name.  Otherwise, if the request
+   this function calls throw_ptrace_error.  Otherwise, if the request
    succeeds, then the regcache gets filled and 1 is returned.  */
 static int
 fetch_all_gp_regs (struct regcache *regcache, int tid)
@@ -680,7 +681,7 @@  fetch_all_gp_regs (struct regcache *regcache, int tid)
           have_ptrace_getsetregs = 0;
           return 0;
         }
-      perror_with_name (_("Couldn't get general-purpose registers."));
+      throw_ptrace_error (_("Couldn't get general-purpose registers."));
     }
 
   supply_gregset (regcache, (const gdb_gregset_t *) &gregset);
@@ -718,7 +719,7 @@  fetch_gp_regs (struct regcache *regcache, int tid)
    
    If the ptrace request does not exist, this function returns 0
    and properly sets the have_ptrace_* flag.  If the request fails,
-   this function calls perror_with_name.  Otherwise, if the request
+   this function calls throw_ptrace_error.  Otherwise, if the request
    succeeds, then the regcache gets filled and 1 is returned.  */
 static int
 fetch_all_fp_regs (struct regcache *regcache, int tid)
@@ -732,7 +733,7 @@  fetch_all_fp_regs (struct regcache *regcache, int tid)
           have_ptrace_getsetfpregs = 0;
           return 0;
         }
-      perror_with_name (_("Couldn't get floating-point registers."));
+      throw_ptrace_error (_("Couldn't get floating-point registers."));
     }
 
   supply_fpregset (regcache, (const gdb_fpregset_t *) &fpregs);
@@ -842,7 +843,7 @@  store_vsx_register (const struct regcache *regcache, int tid, int regno)
 	  have_ptrace_getsetvsxregs = 0;
 	  return;
 	}
-      perror_with_name (_("Unable to fetch VSX register"));
+      throw_ptrace_error (_("Unable to fetch VSX register"));
     }
 
   regcache_raw_collect (regcache, regno, regs +
@@ -850,7 +851,7 @@  store_vsx_register (const struct regcache *regcache, int tid, int regno)
 
   ret = ptrace (PTRACE_SETVSXREGS, tid, 0, &regs);
   if (ret < 0)
-    perror_with_name (_("Unable to store VSX register"));
+    throw_ptrace_error (_("Unable to store VSX register"));
 }
 
 /* Store one register.  */
@@ -872,7 +873,7 @@  store_altivec_register (const struct regcache *regcache, int tid, int regno)
           have_ptrace_getvrregs = 0;
           return;
         }
-      perror_with_name (_("Unable to fetch AltiVec register"));
+      throw_ptrace_error (_("Unable to fetch AltiVec register"));
     }
 
   /* VSCR is fetched as a 16 bytes quantity, but it is really 4 bytes
@@ -886,7 +887,7 @@  store_altivec_register (const struct regcache *regcache, int tid, int regno)
 
   ret = ptrace (PTRACE_SETVRREGS, tid, 0, &regs);
   if (ret < 0)
-    perror_with_name (_("Unable to store AltiVec register"));
+    throw_ptrace_error (_("Unable to store AltiVec register"));
 }
 
 /* Assuming TID referrs to an SPE process, set the top halves of TID's
@@ -913,7 +914,7 @@  set_spe_registers (int tid, struct gdb_evrregset_t *evrregset)
             have_ptrace_getsetevrregs = 0;
           else
             /* Anything else needs to be reported.  */
-            perror_with_name (_("Unable to set SPE registers"));
+            throw_ptrace_error (_("Unable to set SPE registers"));
         }
     }
 }
@@ -1047,7 +1048,7 @@  store_register (const struct regcache *regcache, int tid, int regno)
           char message[128];
 	  xsnprintf (message, sizeof (message), "writing register %s (#%d)",
 		     gdbarch_register_name (gdbarch, regno), regno);
-	  perror_with_name (message);
+	  throw_ptrace_error (message);
 	}
     }
 }
@@ -1102,13 +1103,13 @@  store_vsx_registers (const struct regcache *regcache, int tid)
 	  have_ptrace_getsetvsxregs = 0;
 	  return;
 	}
-      perror_with_name (_("Couldn't get VSX registers"));
+      throw_ptrace_error (_("Couldn't get VSX registers"));
     }
 
   fill_vsxregset (regcache, &regs);
 
   if (ptrace (PTRACE_SETVSXREGS, tid, 0, &regs) < 0)
-    perror_with_name (_("Couldn't write VSX registers"));
+    throw_ptrace_error (_("Couldn't write VSX registers"));
 }
 
 static void
@@ -1125,13 +1126,13 @@  store_altivec_registers (const struct regcache *regcache, int tid)
           have_ptrace_getvrregs = 0;
           return;
         }
-      perror_with_name (_("Couldn't get AltiVec registers"));
+      throw_ptrace_error (_("Couldn't get AltiVec registers"));
     }
 
   fill_vrregset (regcache, &regs);
   
   if (ptrace (PTRACE_SETVRREGS, tid, 0, &regs) < 0)
-    perror_with_name (_("Couldn't write AltiVec registers"));
+    throw_ptrace_error (_("Couldn't write AltiVec registers"));
 }
 
 /* This function actually issues the request to ptrace, telling
@@ -1140,7 +1141,7 @@  store_altivec_registers (const struct regcache *regcache, int tid)
    
    If the ptrace request does not exist, this function returns 0
    and properly sets the have_ptrace_* flag.  If the request fails,
-   this function calls perror_with_name.  Otherwise, if the request
+   this function calls throw_ptrace_error.  Otherwise, if the request
    succeeds, then the regcache is stored and 1 is returned.  */
 static int
 store_all_gp_regs (const struct regcache *regcache, int tid, int regno)
@@ -1156,7 +1157,7 @@  store_all_gp_regs (const struct regcache *regcache, int tid, int regno)
           have_ptrace_getsetregs = 0;
           return 0;
         }
-      perror_with_name (_("Couldn't get general-purpose registers."));
+      throw_ptrace_error (_("Couldn't get general-purpose registers."));
     }
 
   fill_gregset (regcache, &gregset, regno);
@@ -1168,7 +1169,7 @@  store_all_gp_regs (const struct regcache *regcache, int tid, int regno)
           have_ptrace_getsetregs = 0;
           return 0;
         }
-      perror_with_name (_("Couldn't set general-purpose registers."));
+      throw_ptrace_error (_("Couldn't set general-purpose registers."));
     }
 
   return 1;
@@ -1204,7 +1205,7 @@  store_gp_regs (const struct regcache *regcache, int tid, int regno)
    
    If the ptrace request does not exist, this function returns 0
    and properly sets the have_ptrace_* flag.  If the request fails,
-   this function calls perror_with_name.  Otherwise, if the request
+   this function calls throw_ptrace_error.  Otherwise, if the request
    succeeds, then the regcache is stored and 1 is returned.  */
 static int
 store_all_fp_regs (const struct regcache *regcache, int tid, int regno)
@@ -1218,7 +1219,7 @@  store_all_fp_regs (const struct regcache *regcache, int tid, int regno)
           have_ptrace_getsetfpregs = 0;
           return 0;
         }
-      perror_with_name (_("Couldn't get floating-point registers."));
+      throw_ptrace_error (_("Couldn't get floating-point registers."));
     }
 
   fill_fpregset (regcache, &fpregs, regno);
@@ -1230,7 +1231,7 @@  store_all_fp_regs (const struct regcache *regcache, int tid, int regno)
           have_ptrace_getsetfpregs = 0;
           return 0;
         }
-      perror_with_name (_("Couldn't set floating-point registers."));
+      throw_ptrace_error (_("Couldn't set floating-point registers."));
     }
 
   return 1;
@@ -1559,7 +1560,7 @@  hwdebug_insert_point (struct ppc_hw_breakpoint *b, int tid)
   errno = 0;
   slot = ptrace (PPC_PTRACE_SETHWDEBUG, tid, 0, p);
   if (slot < 0)
-    perror_with_name (_("Unexpected error setting breakpoint or watchpoint"));
+    throw_ptrace_error (_("Unexpected error setting breakpoint or watchpoint"));
 
   /* Everything went fine, so we have to register this *point.  */
   t = hwdebug_find_thread_points_by_tid (tid, 1);
@@ -1606,7 +1607,7 @@  hwdebug_remove_point (struct ppc_hw_breakpoint *b, int tid)
   errno = 0;
   if (ptrace (PPC_PTRACE_DELHWDEBUG, tid, 0, hw_breaks[i].slot) < 0)
     if (errno != ENOENT)
-      perror_with_name (_("Unexpected error deleting "
+      throw_ptrace_error (_("Unexpected error deleting "
 			  "breakpoint or watchpoint"));
 
   xfree (hw_breaks[i].hw_break);
@@ -2419,7 +2420,7 @@  ppc_linux_read_description (struct target_ops *ops)
       /* EIO means that the PTRACE_GETEVRREGS request isn't supported.
 	 Anything else needs to be reported.  */
       else if (errno != EIO)
-	perror_with_name (_("Unable to fetch SPE registers"));
+	throw_ptrace_error (_("Unable to fetch SPE registers"));
     }
 
   if (have_ptrace_getsetvsxregs)
@@ -2432,7 +2433,7 @@  ppc_linux_read_description (struct target_ops *ops)
       /* EIO means that the PTRACE_GETVSXREGS request isn't supported.
 	 Anything else needs to be reported.  */
       else if (errno != EIO)
-	perror_with_name (_("Unable to fetch VSX registers"));
+	throw_ptrace_error (_("Unable to fetch VSX registers"));
     }
 
   if (have_ptrace_getvrregs)
@@ -2445,7 +2446,7 @@  ppc_linux_read_description (struct target_ops *ops)
       /* EIO means that the PTRACE_GETVRREGS request isn't supported.
 	 Anything else needs to be reported.  */
       else if (errno != EIO)
-	perror_with_name (_("Unable to fetch AltiVec registers"));
+	throw_ptrace_error (_("Unable to fetch AltiVec registers"));
     }
 
   /* Power ISA 2.05 (implemented by Power 6 and newer processors) increases
diff --git a/gdb/ppcfbsd-nat.c b/gdb/ppcfbsd-nat.c
index 778b4bb..544fe7a 100644
--- a/gdb/ppcfbsd-nat.c
+++ b/gdb/ppcfbsd-nat.c
@@ -35,6 +35,7 @@ 
 #include "ppc-tdep.h"
 #include "ppcfbsd-tdep.h"
 #include "inf-ptrace.h"
+#include "nat/ptrace-utils.h"
 #include "bsd-kvm.h"
 
 /* Fill GDB's register array with the general-purpose register values
@@ -123,7 +124,7 @@  ppcfbsd_fetch_inferior_registers (struct target_ops *ops,
 
   if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
 	      (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-    perror_with_name (_("Couldn't get registers"));
+    throw_ptrace_error (_("Couldn't get registers"));
 
   supply_gregset (regcache, &regs);
 
@@ -134,7 +135,7 @@  ppcfbsd_fetch_inferior_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't get FP registers"));
+	throw_ptrace_error (_("Couldn't get FP registers"));
 
       ppc_supply_fpregset (fpregset, regcache, regno, &fpregs, sizeof fpregs);
     }
@@ -151,13 +152,13 @@  ppcfbsd_store_inferior_registers (struct target_ops *ops,
 
   if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
 	      (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-    perror_with_name (_("Couldn't get registers"));
+    throw_ptrace_error (_("Couldn't get registers"));
 
   fill_gregset (regcache, &regs, regno);
 
   if (ptrace (PT_SETREGS, ptid_get_pid (inferior_ptid),
 	      (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-    perror_with_name (_("Couldn't write registers"));
+    throw_ptrace_error (_("Couldn't write registers"));
 
   if (regno == -1 || getfpregs_supplies (get_regcache_arch (regcache), regno))
     {
@@ -165,13 +166,13 @@  ppcfbsd_store_inferior_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't get FP registers"));
+	throw_ptrace_error (_("Couldn't get FP registers"));
 
       fill_fpregset (regcache, &fpregs, regno);
 
       if (ptrace (PT_SETFPREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't set FP registers"));
+	throw_ptrace_error (_("Couldn't set FP registers"));
     }
 }
 
diff --git a/gdb/ppcnbsd-nat.c b/gdb/ppcnbsd-nat.c
index 59195c0..bc7e852 100644
--- a/gdb/ppcnbsd-nat.c
+++ b/gdb/ppcnbsd-nat.c
@@ -35,6 +35,7 @@ 
 #include "ppcnbsd-tdep.h"
 #include "bsd-kvm.h"
 #include "inf-ptrace.h"
+#include "nat/ptrace-utils.h"
 
 /* Returns true if PT_GETREGS fetches this register.  */
 
@@ -88,7 +89,7 @@  ppcnbsd_fetch_inferior_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-        perror_with_name (_("Couldn't get registers"));
+        throw_ptrace_error (_("Couldn't get registers"));
 
       ppc_supply_gregset (&ppcnbsd_gregset, regcache,
 			  regnum, &regs, sizeof regs);
@@ -100,7 +101,7 @@  ppcnbsd_fetch_inferior_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't get FP registers"));
+	throw_ptrace_error (_("Couldn't get FP registers"));
 
       ppc_supply_fpregset (&ppcnbsd_fpregset, regcache,
 			   regnum, &fpregs, sizeof fpregs);
@@ -119,14 +120,14 @@  ppcnbsd_store_inferior_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-	perror_with_name (_("Couldn't get registers"));
+	throw_ptrace_error (_("Couldn't get registers"));
 
       ppc_collect_gregset (&ppcnbsd_gregset, regcache,
 			   regnum, &regs, sizeof regs);
 
       if (ptrace (PT_SETREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-	perror_with_name (_("Couldn't write registers"));
+	throw_ptrace_error (_("Couldn't write registers"));
     }
 
   if (regnum == -1 || getfpregs_supplies (gdbarch, regnum))
@@ -135,14 +136,14 @@  ppcnbsd_store_inferior_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't get FP registers"));
+	throw_ptrace_error (_("Couldn't get FP registers"));
 
       ppc_collect_fpregset (&ppcnbsd_fpregset, regcache,
 			    regnum, &fpregs, sizeof fpregs);
 
       if (ptrace (PT_SETFPREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't set FP registers"));
+	throw_ptrace_error (_("Couldn't set FP registers"));
     }
 }
 
diff --git a/gdb/ppcobsd-nat.c b/gdb/ppcobsd-nat.c
index eef7305..b1f3654 100644
--- a/gdb/ppcobsd-nat.c
+++ b/gdb/ppcobsd-nat.c
@@ -32,6 +32,7 @@ 
 #include "ppc-tdep.h"
 #include "ppcobsd-tdep.h"
 #include "inf-ptrace.h"
+#include "nat/ptrace-utils.h"
 #include "obsd-nat.h"
 #include "bsd-kvm.h"
 
@@ -78,7 +79,7 @@  ppcobsd_fetch_registers (struct target_ops *ops,
 
   if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
 	      (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-    perror_with_name (_("Couldn't get registers"));
+    throw_ptrace_error (_("Couldn't get registers"));
 
   ppc_supply_gregset (&ppcobsd_gregset, regcache, -1,
 		      &regs, sizeof regs);
@@ -95,7 +96,7 @@  ppcobsd_fetch_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't get floating point status"));
+	throw_ptrace_error (_("Couldn't get floating point status"));
 
       ppc_supply_fpregset (&ppcobsd_fpregset, regcache, -1,
 			   &fpregs, sizeof fpregs);
@@ -114,7 +115,7 @@  ppcobsd_store_registers (struct target_ops *ops,
 
   if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
 	      (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-    perror_with_name (_("Couldn't get registers"));
+    throw_ptrace_error (_("Couldn't get registers"));
 
   ppc_collect_gregset (&ppcobsd_gregset, regcache,
 		       regnum, &regs, sizeof regs);
@@ -125,7 +126,7 @@  ppcobsd_store_registers (struct target_ops *ops,
 
   if (ptrace (PT_SETREGS, ptid_get_pid (inferior_ptid),
 	      (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-    perror_with_name (_("Couldn't write registers"));
+    throw_ptrace_error (_("Couldn't write registers"));
 
 #ifdef PT_GETFPREGS
   if (regnum == -1
@@ -135,14 +136,14 @@  ppcobsd_store_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't get floating point status"));
+	throw_ptrace_error (_("Couldn't get floating point status"));
 
       ppc_collect_fpregset (&ppcobsd_fpregset, regcache,
 			    regnum, &fpregs, sizeof fpregs);
 
       if (ptrace (PT_SETFPREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't write floating point status"));
+	throw_ptrace_error (_("Couldn't write floating point status"));
     }
 #endif
 }
diff --git a/gdb/rs6000-nat.c b/gdb/rs6000-nat.c
index 8cdd86f..3c48a73 100644
--- a/gdb/rs6000-nat.c
+++ b/gdb/rs6000-nat.c
@@ -30,6 +30,7 @@ 
 #include "arch-utils.h"
 #include "inf-child.h"
 #include "inf-ptrace.h"
+#include "nat/ptrace-utils.h"
 #include "ppc-tdep.h"
 #include "rs6000-tdep.h"
 #include "rs6000-aix-tdep.h"
@@ -608,7 +609,7 @@  rs6000_ptrace_ldinfo (ptid_t ptid)
 	break; /* Success, we got the entire ld_info data.  */
 
       if (errno != ENOMEM)
-	perror_with_name (_("ptrace ldinfo"));
+	throw_ptrace_error (_("ptrace ldinfo"));
 
       /* ldi is not big enough.  Double it and try again.  */
       ldi_size *= 2;
diff --git a/gdb/s390-linux-nat.c b/gdb/s390-linux-nat.c
index 367b610..4837738 100644
--- a/gdb/s390-linux-nat.c
+++ b/gdb/s390-linux-nat.c
@@ -213,7 +213,7 @@  fetch_regs (struct regcache *regcache, int tid)
   parea.process_addr = (addr_t) &regs;
   parea.kernel_addr = offsetof (struct user_regs_struct, psw);
   if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
-    perror_with_name (_("Couldn't get registers"));
+    throw_ptrace_error (_("Couldn't get registers"));
 
   supply_gregset (regcache, (const gregset_t *) &regs);
 }
@@ -230,12 +230,12 @@  store_regs (const struct regcache *regcache, int tid, int regnum)
   parea.process_addr = (addr_t) &regs;
   parea.kernel_addr = offsetof (struct user_regs_struct, psw);
   if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
-    perror_with_name (_("Couldn't get registers"));
+    throw_ptrace_error (_("Couldn't get registers"));
 
   fill_gregset (regcache, &regs, regnum);
 
   if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0)
-    perror_with_name (_("Couldn't write registers"));
+    throw_ptrace_error (_("Couldn't write registers"));
 }
 
 /* Fetch all floating-point registers from process/thread TID and store
@@ -250,7 +250,7 @@  fetch_fpregs (struct regcache *regcache, int tid)
   parea.process_addr = (addr_t) &fpregs;
   parea.kernel_addr = offsetof (struct user_regs_struct, fp_regs);
   if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
-    perror_with_name (_("Couldn't get floating point status"));
+    throw_ptrace_error (_("Couldn't get floating point status"));
 
   supply_fpregset (regcache, (const fpregset_t *) &fpregs);
 }
@@ -267,12 +267,12 @@  store_fpregs (const struct regcache *regcache, int tid, int regnum)
   parea.process_addr = (addr_t) &fpregs;
   parea.kernel_addr = offsetof (struct user_regs_struct, fp_regs);
   if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
-    perror_with_name (_("Couldn't get floating point status"));
+    throw_ptrace_error (_("Couldn't get floating point status"));
 
   fill_fpregset (regcache, &fpregs, regnum);
 
   if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0)
-    perror_with_name (_("Couldn't write floating point status"));
+    throw_ptrace_error (_("Couldn't write floating point status"));
 }
 
 /* Fetch all registers in the kernel's register set whose number is
@@ -294,7 +294,7 @@  fetch_regset (struct regcache *regcache, int tid,
       if (errno == ENODATA)
 	regcache_supply_regset (regset, regcache, -1, NULL, regsize);
       else
-	perror_with_name (_("Couldn't get register set"));
+	throw_ptrace_error (_("Couldn't get register set"));
     }
   else
     regcache_supply_regset (regset, regcache, -1, buf, regsize);
@@ -314,12 +314,12 @@  store_regset (struct regcache *regcache, int tid,
   iov.iov_len = regsize;
 
   if (ptrace (PTRACE_GETREGSET, tid, (long) regset_id, (long) &iov) < 0)
-    perror_with_name (_("Couldn't get register set"));
+    throw_ptrace_error (_("Couldn't get register set"));
 
   regcache_collect_regset (regset, regcache, -1, buf, regsize);
 
   if (ptrace (PTRACE_SETREGSET, tid, (long) regset_id, (long) &iov) < 0)
-    perror_with_name (_("Couldn't set register set"));
+    throw_ptrace_error (_("Couldn't set register set"));
 }
 
 /* Check whether the kernel provides a register set with number REGSET
@@ -449,7 +449,7 @@  s390_stopped_by_watchpoint (struct target_ops *ops)
   parea.process_addr = (addr_t) & per_lowcore;
   parea.kernel_addr = offsetof (struct user_regs_struct, per_info.lowcore);
   if (ptrace (PTRACE_PEEKUSR_AREA, s390_inferior_tid (), &parea) < 0)
-    perror_with_name (_("Couldn't retrieve watchpoint status"));
+    throw_ptrace_error (_("Couldn't retrieve watchpoint status"));
 
   result = (per_lowcore.perc_storage_alteration == 1
 	    && per_lowcore.perc_store_real_address == 0);
@@ -459,7 +459,7 @@  s390_stopped_by_watchpoint (struct target_ops *ops)
       /* Do not report this watchpoint again.  */
       memset (&per_lowcore, 0, sizeof (per_lowcore));
       if (ptrace (PTRACE_POKEUSR_AREA, s390_inferior_tid (), &parea) < 0)
-	perror_with_name (_("Couldn't clear watchpoint status"));
+	throw_ptrace_error (_("Couldn't clear watchpoint status"));
     }
 
   return result;
@@ -490,7 +490,7 @@  s390_fix_watch_points (struct lwp_info *lp)
   parea.process_addr = (addr_t) & per_info;
   parea.kernel_addr = offsetof (struct user_regs_struct, per_info);
   if (ptrace (PTRACE_PEEKUSR_AREA, tid, &parea) < 0)
-    perror_with_name (_("Couldn't retrieve watchpoint status"));
+    throw_ptrace_error (_("Couldn't retrieve watchpoint status"));
 
   if (watch_base)
     {
@@ -506,7 +506,7 @@  s390_fix_watch_points (struct lwp_info *lp)
   per_info.ending_addr = watch_hi_addr;
 
   if (ptrace (PTRACE_POKEUSR_AREA, tid, &parea) < 0)
-    perror_with_name (_("Couldn't modify watchpoint status"));
+    throw_ptrace_error (_("Couldn't modify watchpoint status"));
 }
 
 static int
diff --git a/gdb/shnbsd-nat.c b/gdb/shnbsd-nat.c
index e0ed5e6..56e5943 100644
--- a/gdb/shnbsd-nat.c
+++ b/gdb/shnbsd-nat.c
@@ -28,6 +28,7 @@ 
 
 #include "sh-tdep.h"
 #include "inf-ptrace.h"
+#include "nat/ptrace-utils.h"
 #include "regcache.h"
 
 
@@ -51,7 +52,7 @@  shnbsd_fetch_inferior_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &inferior_registers, 0) == -1)
-	perror_with_name (_("Couldn't get registers"));
+	throw_ptrace_error (_("Couldn't get registers"));
 
       sh_corefile_supply_regset (&sh_corefile_gregset, regcache, regno,
 				 (char *) &inferior_registers,
@@ -72,7 +73,7 @@  shnbsd_store_inferior_registers (struct target_ops *ops,
 
       if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &inferior_registers, 0) == -1)
-	perror_with_name (_("Couldn't get registers"));
+	throw_ptrace_error (_("Couldn't get registers"));
 
       sh_corefile_collect_regset (&sh_corefile_gregset, regcache, regno,
 				  (char *) &inferior_registers,
@@ -80,7 +81,7 @@  shnbsd_store_inferior_registers (struct target_ops *ops,
 
       if (ptrace (PT_SETREGS, ptid_get_pid (inferior_ptid),
 		  (PTRACE_TYPE_ARG3) &inferior_registers, 0) == -1)
-	perror_with_name (_("Couldn't set registers"));
+	throw_ptrace_error (_("Couldn't set registers"));
 
       if (regno != -1)
 	return;
diff --git a/gdb/sparc-nat.c b/gdb/sparc-nat.c
index f1d82e5..152f6bb 100644
--- a/gdb/sparc-nat.c
+++ b/gdb/sparc-nat.c
@@ -32,6 +32,7 @@ 
 #include "sparc-tdep.h"
 #include "sparc-nat.h"
 #include "inf-ptrace.h"
+#include "nat/ptrace-utils.h"
 
 /* With some trickery we can use the code in this file for most (if
    not all) ptrace(2) based SPARC systems, which includes SunOS 4,
@@ -170,7 +171,7 @@  sparc_fetch_inferior_registers (struct target_ops *ops,
       gregset_t regs;
 
       if (ptrace (PTRACE_GETREGS, pid, (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-	perror_with_name (_("Couldn't get registers"));
+	throw_ptrace_error (_("Couldn't get registers"));
 
       sparc_supply_gregset (sparc_gregmap, regcache, -1, &regs);
       if (regnum != -1)
@@ -182,7 +183,7 @@  sparc_fetch_inferior_registers (struct target_ops *ops,
       fpregset_t fpregs;
 
       if (ptrace (PTRACE_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't get floating point status"));
+	throw_ptrace_error (_("Couldn't get floating point status"));
 
       sparc_supply_fpregset (sparc_fpregmap, regcache, -1, &fpregs);
     }
@@ -206,12 +207,12 @@  sparc_store_inferior_registers (struct target_ops *ops,
       gregset_t regs;
 
       if (ptrace (PTRACE_GETREGS, pid, (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-	perror_with_name (_("Couldn't get registers"));
+	throw_ptrace_error (_("Couldn't get registers"));
 
       sparc_collect_gregset (sparc_gregmap, regcache, regnum, &regs);
 
       if (ptrace (PTRACE_SETREGS, pid, (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-	perror_with_name (_("Couldn't write registers"));
+	throw_ptrace_error (_("Couldn't write registers"));
 
       /* Deal with the stack regs.  */
       if (regnum == -1 || regnum == SPARC_SP_REGNUM
@@ -232,7 +233,7 @@  sparc_store_inferior_registers (struct target_ops *ops,
       fpregset_t fpregs, saved_fpregs;
 
       if (ptrace (PTRACE_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	perror_with_name (_("Couldn't get floating-point registers"));
+	throw_ptrace_error (_("Couldn't get floating-point registers"));
 
       memcpy (&saved_fpregs, &fpregs, sizeof (fpregs));
       sparc_collect_fpregset (sparc_fpregmap, regcache, regnum, &fpregs);
@@ -245,7 +246,7 @@  sparc_store_inferior_registers (struct target_ops *ops,
 	{
 	  if (ptrace (PTRACE_SETFPREGS, pid,
 		      (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-	    perror_with_name (_("Couldn't write floating-point registers"));
+	    throw_ptrace_error (_("Couldn't write floating-point registers"));
 	}
 
       if (regnum != -1)
@@ -291,7 +292,7 @@  sparc_xfer_wcookie (struct target_ops *ops, enum target_object object,
     if (ptrace (PT_WCOOKIE, pid, (PTRACE_TYPE_ARG3) &wcookie, 0) == -1)
       {
 	if (errno != EINVAL)
-	  perror_with_name (_("Couldn't get StackGhost cookie"));
+	  throw_ptrace_error (_("Couldn't get StackGhost cookie"));
 
 	/* Although PT_WCOOKIE is defined on OpenBSD 3.1 and later,
 	   the request wasn't implemented until after OpenBSD 3.4.  If
diff --git a/gdb/spu-linux-nat.c b/gdb/spu-linux-nat.c
index b0942a9..cf0f4df 100644
--- a/gdb/spu-linux-nat.c
+++ b/gdb/spu-linux-nat.c
@@ -24,6 +24,7 @@ 
 #include "inferior.h"
 #include "inf-child.h"
 #include "inf-ptrace.h"
+#include "nat/ptrace-utils.h"
 #include "regcache.h"
 #include "symfile.h"
 #include "gdb_wait.h"
@@ -77,7 +78,7 @@  fetch_ppc_register (int regno)
     {
       char mess[128];
       xsnprintf (mess, sizeof mess, "reading PPC register #%d", regno);
-      perror_with_name (_(mess));
+      throw_ptrace_error (_(mess));
     }
 
   return (ULONGEST) (unsigned long) res;
diff --git a/gdb/tilegx-linux-nat.c b/gdb/tilegx-linux-nat.c
index b8f0c76..68c2391 100644
--- a/gdb/tilegx-linux-nat.c
+++ b/gdb/tilegx-linux-nat.c
@@ -133,7 +133,7 @@  fetch_inferior_registers (struct target_ops *ops,
     tid = ptid_get_pid (inferior_ptid);
 
   if (ptrace (PTRACE_GETREGS, tid, 0, (PTRACE_TYPE_ARG3) &regs) < 0)
-    perror_with_name (_("Couldn't get registers"));
+    throw_ptrace_error (_("Couldn't get registers"));
 
   supply_gregset (regcache, (const elf_gregset_t *)&regs);
 }
@@ -153,12 +153,12 @@  store_inferior_registers (struct target_ops *ops,
     tid = ptid_get_pid (inferior_ptid);
 
   if (ptrace (PTRACE_GETREGS, tid, 0, (PTRACE_TYPE_ARG3) &regs) < 0)
-    perror_with_name (_("Couldn't get registers"));
+    throw_ptrace_error (_("Couldn't get registers"));
 
   fill_gregset (regcache, &regs, regnum);
 
   if (ptrace (PTRACE_SETREGS, tid, 0, (PTRACE_TYPE_ARG3) &regs) < 0)
-    perror_with_name (_("Couldn't write registers"));
+    throw_ptrace_error (_("Couldn't write registers"));
 }
 
 
diff --git a/gdb/vaxbsd-nat.c b/gdb/vaxbsd-nat.c
index 866b958..7caae30 100644
--- a/gdb/vaxbsd-nat.c
+++ b/gdb/vaxbsd-nat.c
@@ -28,6 +28,7 @@ 
 
 #include "vax-tdep.h"
 #include "inf-ptrace.h"
+#include "nat/ptrace-utils.h"
 
 /* Supply the general-purpose registers stored in GREGS to REGCACHE.  */
 
@@ -70,7 +71,7 @@  vaxbsd_fetch_inferior_registers (struct target_ops *ops,
 
   if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
 	      (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-    perror_with_name (_("Couldn't get registers"));
+    throw_ptrace_error (_("Couldn't get registers"));
 
   vaxbsd_supply_gregset (regcache, &regs);
 }
@@ -86,13 +87,13 @@  vaxbsd_store_inferior_registers (struct target_ops *ops,
 
   if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
 	      (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-    perror_with_name (_("Couldn't get registers"));
+    throw_ptrace_error (_("Couldn't get registers"));
 
   vaxbsd_collect_gregset (regcache, &regs, regnum);
 
   if (ptrace (PT_SETREGS, ptid_get_pid (inferior_ptid),
 	      (PTRACE_TYPE_ARG3) &regs, 0) == -1)
-    perror_with_name (_("Couldn't write registers"));
+    throw_ptrace_error (_("Couldn't write registers"));
 }
 
 
diff --git a/gdb/x86-linux-nat.c b/gdb/x86-linux-nat.c
index 26ae0b8..d184e41 100644
--- a/gdb/x86-linux-nat.c
+++ b/gdb/x86-linux-nat.c
@@ -28,6 +28,7 @@ 
 
 #include "x86-nat.h"
 #include "linux-nat.h"
+#include "nat/ptrace-utils.h"
 #ifndef __x86_64__
 #include "i386-linux-nat.h"
 #endif
@@ -78,7 +79,7 @@  x86_linux_dr_get (ptid_t ptid, int regnum)
   value = ptrace (PTRACE_PEEKUSER, tid, u_debugreg_offset (regnum), 0);
 
   if (errno != 0)
-    perror_with_name (_("Couldn't read debug register"));
+    throw_ptrace_error (_("Couldn't read debug register"));
 
   return value;
 }
@@ -96,7 +97,7 @@  x86_linux_dr_set (ptid_t ptid, int regnum, unsigned long value)
   errno = 0;
   ptrace (PTRACE_POKEUSER, tid, u_debugreg_offset (regnum), value);
   if (errno != 0)
-    perror_with_name (_("Couldn't write debug register"));
+    throw_ptrace_error (_("Couldn't write debug register"));
 }
 
 /* Return the inferior's debug register REGNUM.  */
@@ -323,7 +324,7 @@  x86_linux_read_description (struct target_ops *ops)
     cs = ptrace (PTRACE_PEEKUSER, tid,
 		 offsetof (struct user_regs_struct, cs), 0);
     if (errno != 0)
-      perror_with_name (_("Couldn't get CS register"));
+      throw_ptrace_error (_("Couldn't get CS register"));
 
     is_64bit = cs == AMD64_LINUX_USER64_CS;
 
@@ -332,7 +333,7 @@  x86_linux_read_description (struct target_ops *ops)
     ds = ptrace (PTRACE_PEEKUSER, tid,
 		 offsetof (struct user_regs_struct, ds), 0);
     if (errno != 0)
-      perror_with_name (_("Couldn't get DS register"));
+      throw_ptrace_error (_("Couldn't get DS register"));
 
     is_x32 = ds == AMD64_LINUX_X32_DS;
 
diff --git a/gdb/xtensa-linux-nat.c b/gdb/xtensa-linux-nat.c
index 921bc99..428fe37 100644
--- a/gdb/xtensa-linux-nat.c
+++ b/gdb/xtensa-linux-nat.c
@@ -189,7 +189,7 @@  fetch_gregs (struct regcache *regcache, int regnum)
   
   if (ptrace (PTRACE_GETREGS, tid, 0, (long) &regs) < 0)
     {
-      perror_with_name (_("Couldn't get registers"));
+      throw_ptrace_error (_("Couldn't get registers"));
       return;
     }
  
@@ -208,7 +208,7 @@  store_gregs (struct regcache *regcache, int regnum)
 
   if (ptrace (PTRACE_GETREGS, tid, 0, (long) &regs) < 0)
     {
-      perror_with_name (_("Couldn't get registers"));
+      throw_ptrace_error (_("Couldn't get registers"));
       return;
     }
 
@@ -216,7 +216,7 @@  store_gregs (struct regcache *regcache, int regnum)
 
   if (ptrace (PTRACE_SETREGS, tid, 0, (long) &regs) < 0)
     {
-      perror_with_name (_("Couldn't write registers"));
+      throw_ptrace_error (_("Couldn't write registers"));
       return;
     }
 }
@@ -235,7 +235,7 @@  fetch_xtregs (struct regcache *regcache, int regnum)
   char xtregs [XTENSA_ELF_XTREG_SIZE];
 
   if (ptrace (PTRACE_GETXTREGS, tid, 0, (long)&xtregs) < 0)
-    perror_with_name (_("Couldn't get extended registers"));
+    throw_ptrace_error (_("Couldn't get extended registers"));
 
   for (ptr = xtensa_regmap_table; ptr->name; ptr++)
     if (regnum == ptr->gdb_regnum || regnum == -1)
@@ -251,7 +251,7 @@  store_xtregs (struct regcache *regcache, int regnum)
   char xtregs [XTENSA_ELF_XTREG_SIZE];
 
   if (ptrace (PTRACE_GETXTREGS, tid, 0, (long)&xtregs) < 0)
-    perror_with_name (_("Couldn't get extended registers"));
+    throw_ptrace_error (_("Couldn't get extended registers"));
 
   for (ptr = xtensa_regmap_table; ptr->name; ptr++)
     if (regnum == ptr->gdb_regnum || regnum == -1)
@@ -259,7 +259,7 @@  store_xtregs (struct regcache *regcache, int regnum)
 			    xtregs + ptr->ptrace_offset);
 
   if (ptrace (PTRACE_SETXTREGS, tid, 0, (long)&xtregs) < 0)
-    perror_with_name (_("Couldn't write extended registers"));
+    throw_ptrace_error (_("Couldn't write extended registers"));
 }
 
 void