Re: strace cant parse struct msghdr RHEL

2017-02-10 Thread Eugene Syromyatnikov
On Fri, Feb 10, 2017 at 9:20 PM, Al Gambardella  wrote:
> I attached strace to a running process and I am trying to understand
> what strace is telling me regarding the select system call. Here are
> two lines of the strace output below:
>
>  _newselect(17, NULL, NULL, [16], {0, 0}) = 0 (Timeout)
>  _newselect(9, [8], NULL, NULL, {0, 0}) = 1 (in [8], left {0, 0})
>
> I know you can pass a timeval struct of all zeros indicating don't
> block at all just check the descriptors and return immediately.
>
> Treating each line above as a separate case:
> Is it possible to determine if the caller passed a timeval struct with
> an actual > 0 timeout value versus an all zero timeval struct?
The last argument of _newselect call is struct timeval, and strace
decodes it. Note that since 4.15, strace prints field values for this
type (it was decided that consistency and readability are more
important than brevity of the output in this case).

> I am assuming that strace is showing the timeval struct after the
> kernel updates it
> and is not showing the timeval struct value the caller passed into
> select. Is this correct?
Yes, auxstr contains information regarding result of select syscall,
namedly fds in in/out/except state and the updated value of the fourth
argument.

> Thanks for any help
>
> On Tue, Oct 4, 2016 at 9:00 AM, Al Gambardella  wrote:
>> I downloaded strace version 4.13 and was able to build the source code
>> and produce the strace executable. I need to see the all of the
>> payload in the recvmsg and sendmsg calls. including the iov style
>> arrays
>>
>> My system is RHEL Server 5.8 Tikanga. Kernel version 2.6.18-348.el5
>>
>> When I run strace with the following command line:
>> ./strace -p  -e 'trace=recvmsg,sendmsg' -e write=8 -e read=8
>>
>> I am getting the following output (which contains errors). Can someone
>> explain why and if this can be fixed?
>>
>> sendmsg(8, {msg_name=NULL, msg_namelen=-7630976, msg_iov=NULL,
>> msg_iovlen=92, msg_control=[{cmsg_len=2048, cmsg_level=SOL_IP,
>> cmsg_type=0x8f80 /* IP_??? */}, {cmsg_len=2565867895,
>> cmsg_level=0xc26cff8b /* SOL_??? */, cmsg_type=0x8cacff8b}, ...],
>> msg_controllen=38647074816,
>> msg_flags=MSG_DONTROUTE|MSG_CTRUNC|MSG_DONTWAIT|MSG_WAITALL|MSG_FIN|MSG_SYN|MSG_CONFIRM|MSG_MORE|0xff8b0010},
>> 0) = 12
>> sendmsg(8, {msg_name=NULL, msg_namelen=-7623584, msg_iov=NULL,
>> msg_iovlen=33655230453052149, msg_control=./strace: umoven: short read
>> (13250 < 20480) @0xff8bac3e: Input/output error
>> 0x2ff8bac3e, msg_controllen=38647082208,
>> msg_flags=MSG_DONTROUTE|MSG_CTRUNC|MSG_TRUNC|MSG_SYN|MSG_CONFIRM|MSG_ERRQUEUE|MSG_MORE|0xff8b0010},
>> 0) = 12
>> ./strace: Out of memory
>> recvmsg(8, {msg_name=NULL, msg_namelen=-7623488, msg_iov=NULL,
>> msg_iovlen=0, msg_control=NULL, msg_controllen=17869443930177667072,
>> msg_flags=MSG_CTRUNC|MSG_TRUNC|MSG_WAITALL|MSG_CONFIRM|0xbe00010},
>> MSG_WAITALL) = 4188
>> sendmsg(8, {msg_name=NULL, msg_namelen=-7623584, msg_iov=NULL,
>> msg_iovlen=33655230453052149, msg_control=./strace: umoven: short read
>> (13250 < 20480) @0xff8bac3e: Input/output error
>> 0x2ff8bac3e, msg_controllen=38647082208,
>> msg_flags=MSG_DONTROUTE|MSG_CTRUNC|MSG_TRUNC|MSG_SYN|MSG_CONFIRM|MSG_ERRQUEUE|MSG_MORE|0xff8b0010},
>> 0) = 12
>> ./strace: Out of memory
>> recvmsg(8, {msg_name=NULL, msg_namelen=-7623488, msg_iov=NULL,
>> msg_iovlen=0, msg_control=NULL, msg_controllen=17869443930177667072,
>> msg_flags=MSG_CTRUNC|MSG_TRUNC|MSG_WAITALL|MSG_CONFIRM|0xbe00010},
>> MSG_WAITALL) = 12
>> recvmsg(8, {msg_name=NULL, msg_namelen=-7623488, msg_iov=NULL,
>> msg_iovlen=0, msg_control=NULL, msg_controllen=17869443930177667072,
>> msg_flags=MSG_CTRUNC|MSG_TRUNC|MSG_WAITALL|MSG_CONFIRM|0xbe00010},
>> MSG_WAITALL) = 12
>> recvmsg(8, {msg_name=NULL, msg_namelen=-7623488, msg_iov=NULL,
>> msg_iovlen=0, msg_control=NULL, msg_controllen=17869443930177667072,
>> msg_flags=MSG_CTRUNC|MSG_TRUNC|MSG_WAITALL|MSG_CONFIRM|0xbe00010},
>> MSG_WAITALL) = 4188
>> sendmsg(8, {msg_name=NULL, msg_namelen=-7623584, msg_iov=NULL,
>> msg_iovlen=33655230453052149, msg_control=./strace: umoven: short read
>> (13250 < 20480) @0xff8bac3e: Input/output error
>> 0x2ff8bac3e, msg_controllen=38647082208,
>> msg_flags=MSG_DONTROUTE|MSG_CTRUNC|MSG_TRUNC|MSG_SYN|MSG_CONFIRM|MSG_ERRQUEUE|MSG_MORE|0xff8b0010},
>> 0) = 12
>> ./strace: Out of memory
>> recvmsg(8, {msg_name=NULL, msg_namelen=-7623488, msg_iov=NULL,
>> msg_iovlen=0, msg_control=NULL, msg_controllen=17869443930177667072,
>> msg_flags=MSG_CTRUNC|MSG_TRUNC|MSG_WAITALL|MSG_CONFIRM|0xbe00010},
>> MSG_WAITALL) = 4188
>> sendmsg(8, {msg_name=NULL, msg_namelen=-7623584, msg_iov=NULL,
>> msg_iovlen=33655230453052149, msg_control=./strace: umoven: short read
>> (13250 < 20480) @0xff8bac3e: Input/output error
>> 0x2ff8bac3e, msg_controllen=38647082208,
>> msg_flags=MSG_DONTROUTE|MSG_CTRUNC|MSG_TRUNC|MSG_SYN|MSG_CONFIRM|MSG_ERRQUEUE|MSG_MORE|0xff8b0010},
>> 0) = 12
>> ./strace: 

Re: strace cant parse struct msghdr RHEL

2017-02-10 Thread Al Gambardella
I attached strace to a running process and I am trying to understand
what strace is telling me regarding the select system call. Here are
two lines of the strace output below:

 _newselect(17, NULL, NULL, [16], {0, 0}) = 0 (Timeout)
 _newselect(9, [8], NULL, NULL, {0, 0}) = 1 (in [8], left {0, 0})

I know you can pass a timeval struct of all zeros indicating don't
block at all just check the descriptors and return immediately.

Treating each line above as a separate case:
Is it possible to determine if the caller passed a timeval struct with
an actual > 0 timeout value versus an all zero timeval struct?

I am assuming that strace is showing the timeval struct after the
kernel updates it
and is not showing the timeval struct value the caller passed into
select. Is this correct?

Thanks for any help

On Tue, Oct 4, 2016 at 9:00 AM, Al Gambardella  wrote:
> I downloaded strace version 4.13 and was able to build the source code
> and produce the strace executable. I need to see the all of the
> payload in the recvmsg and sendmsg calls. including the iov style
> arrays
>
> My system is RHEL Server 5.8 Tikanga. Kernel version 2.6.18-348.el5
>
> When I run strace with the following command line:
> ./strace -p  -e 'trace=recvmsg,sendmsg' -e write=8 -e read=8
>
> I am getting the following output (which contains errors). Can someone
> explain why and if this can be fixed?
>
> sendmsg(8, {msg_name=NULL, msg_namelen=-7630976, msg_iov=NULL,
> msg_iovlen=92, msg_control=[{cmsg_len=2048, cmsg_level=SOL_IP,
> cmsg_type=0x8f80 /* IP_??? */}, {cmsg_len=2565867895,
> cmsg_level=0xc26cff8b /* SOL_??? */, cmsg_type=0x8cacff8b}, ...],
> msg_controllen=38647074816,
> msg_flags=MSG_DONTROUTE|MSG_CTRUNC|MSG_DONTWAIT|MSG_WAITALL|MSG_FIN|MSG_SYN|MSG_CONFIRM|MSG_MORE|0xff8b0010},
> 0) = 12
> sendmsg(8, {msg_name=NULL, msg_namelen=-7623584, msg_iov=NULL,
> msg_iovlen=33655230453052149, msg_control=./strace: umoven: short read
> (13250 < 20480) @0xff8bac3e: Input/output error
> 0x2ff8bac3e, msg_controllen=38647082208,
> msg_flags=MSG_DONTROUTE|MSG_CTRUNC|MSG_TRUNC|MSG_SYN|MSG_CONFIRM|MSG_ERRQUEUE|MSG_MORE|0xff8b0010},
> 0) = 12
> ./strace: Out of memory
> recvmsg(8, {msg_name=NULL, msg_namelen=-7623488, msg_iov=NULL,
> msg_iovlen=0, msg_control=NULL, msg_controllen=17869443930177667072,
> msg_flags=MSG_CTRUNC|MSG_TRUNC|MSG_WAITALL|MSG_CONFIRM|0xbe00010},
> MSG_WAITALL) = 4188
> sendmsg(8, {msg_name=NULL, msg_namelen=-7623584, msg_iov=NULL,
> msg_iovlen=33655230453052149, msg_control=./strace: umoven: short read
> (13250 < 20480) @0xff8bac3e: Input/output error
> 0x2ff8bac3e, msg_controllen=38647082208,
> msg_flags=MSG_DONTROUTE|MSG_CTRUNC|MSG_TRUNC|MSG_SYN|MSG_CONFIRM|MSG_ERRQUEUE|MSG_MORE|0xff8b0010},
> 0) = 12
> ./strace: Out of memory
> recvmsg(8, {msg_name=NULL, msg_namelen=-7623488, msg_iov=NULL,
> msg_iovlen=0, msg_control=NULL, msg_controllen=17869443930177667072,
> msg_flags=MSG_CTRUNC|MSG_TRUNC|MSG_WAITALL|MSG_CONFIRM|0xbe00010},
> MSG_WAITALL) = 12
> recvmsg(8, {msg_name=NULL, msg_namelen=-7623488, msg_iov=NULL,
> msg_iovlen=0, msg_control=NULL, msg_controllen=17869443930177667072,
> msg_flags=MSG_CTRUNC|MSG_TRUNC|MSG_WAITALL|MSG_CONFIRM|0xbe00010},
> MSG_WAITALL) = 12
> recvmsg(8, {msg_name=NULL, msg_namelen=-7623488, msg_iov=NULL,
> msg_iovlen=0, msg_control=NULL, msg_controllen=17869443930177667072,
> msg_flags=MSG_CTRUNC|MSG_TRUNC|MSG_WAITALL|MSG_CONFIRM|0xbe00010},
> MSG_WAITALL) = 4188
> sendmsg(8, {msg_name=NULL, msg_namelen=-7623584, msg_iov=NULL,
> msg_iovlen=33655230453052149, msg_control=./strace: umoven: short read
> (13250 < 20480) @0xff8bac3e: Input/output error
> 0x2ff8bac3e, msg_controllen=38647082208,
> msg_flags=MSG_DONTROUTE|MSG_CTRUNC|MSG_TRUNC|MSG_SYN|MSG_CONFIRM|MSG_ERRQUEUE|MSG_MORE|0xff8b0010},
> 0) = 12
> ./strace: Out of memory
> recvmsg(8, {msg_name=NULL, msg_namelen=-7623488, msg_iov=NULL,
> msg_iovlen=0, msg_control=NULL, msg_controllen=17869443930177667072,
> msg_flags=MSG_CTRUNC|MSG_TRUNC|MSG_WAITALL|MSG_CONFIRM|0xbe00010},
> MSG_WAITALL) = 4188
> sendmsg(8, {msg_name=NULL, msg_namelen=-7623584, msg_iov=NULL,
> msg_iovlen=33655230453052149, msg_control=./strace: umoven: short read
> (13250 < 20480) @0xff8bac3e: Input/output error
> 0x2ff8bac3e, msg_controllen=38647082208,
> msg_flags=MSG_DONTROUTE|MSG_CTRUNC|MSG_TRUNC|MSG_SYN|MSG_CONFIRM|MSG_ERRQUEUE|MSG_MORE|0xff8b0010},
> 0) = 12
> ./strace: Out of memory
> recvmsg(8, {msg_name=NULL, msg_namelen=-7623488, msg_iov=NULL,
> msg_iovlen=0, msg_control=NULL, msg_controllen=17869443930177667072,
> msg_flags=MSG_CTRUNC|MSG_TRUNC|MSG_WAITALL|MSG_CONFIRM|0xbe00010},
> MSG_WAITALL) = 12
> recvmsg(8, {msg_name=NULL, msg_namelen=-7623488, msg_iov=NULL,
> msg_iovlen=0, msg_control=NULL, msg_controllen=17869443930177667072,
> msg_flags=MSG_CTRUNC|MSG_TRUNC|MSG_WAITALL|MSG_CONFIRM|0xbe00010},
> MSG_WAITALL) = 4188
> sendmsg(8, {msg_name=NULL, msg_namelen=-7623584, msg_iov=NULL,
> msg_iovlen=33655230453052149, msg_control=./strace: 

[PATCH 2/3] Add gdb remote protocol handling to strace

2017-02-10 Thread Stan Cox
The gdbserver directory contains the gdbserver backend, which 
communicates with gdbserver via the gdb remote protocol, e.g.
  strace sends packet: $vCont;c  (continue)
  strace receives packet: 
T05syscall_entry:16;06:b0e2ff7f;07:68e2ff7f;10:27a9b0f7ff7f;thread:p2162.2162;core:5;
  strace sends packet: $g (get registers)
  strace receives packet: daff...

The backend supports both x86_64 and i386.  This patch is large (sorry 
about that)  as all of these files are new.

Brief summary of changes:

gdbserver/x86_64/gdb_get_regs.c: handles the register fetching and is 
included in get_regs.

gdbserver/signals.{c,def}:  handles the signal conversion between strace 
and the gdb remote protocol.

gdbserver/gdbserver.c:  gdb_recv_exit, gdb_recv_stop, gdb_ok:  handle
parsing the remote packets.
gdb_init, gdb_init_syscalls, gdb_finalize_init:  Initialize the
gdbserver backend.
gdb_cleanup, gdb_detach:  Cleanup.
gdb_startup_child:  starts a child.
gdb_startup_attach:  attaches to an existing process.
gdb_trace: Primary tracing loop:  Get the packet,  call trace_syscall for
syscall_entry and syscall_return packets, send continue to
gdbserver.
gdb_get_regs:  handle 'g' packet.
gdb_read_mem:  Read memory from gdbserver.

gdbserver/protocol.c:  The knowledge of how to encode, send and
receive remote packets is localized here.  This is described in
"info gdb 'Remote Protocol' 'Overview'"
gdb_encode_hex, gdb_encode_hex_string, hex_nibble, gdb_decode_hex,
gdb_decode_hex_string:  handle the remote protocol encoding scheme.
gdb_begin_command, gdb_begin_tcp, gdb_begin_path:  Setup the
protocol.
gdb_send, send_packet:  Send a packet.
push_notification, pop_notification:  Handle the remote protocol
non-stop notifications.
gdb_recv, gdb_recv_packet:  Receive and parse a packet.



diff --git a/gdbserver/gdbserver.c b/gdbserver/gdbserver.c
new file mode 100644
index 000..ba2634e
--- /dev/null
+++ b/gdbserver/gdbserver.c
@@ -0,0 +1,950 @@
+/* Implementation of strace features over the GDB remote protocol.
+ *
+ * Copyright (c) 2015, 2016 Red Hat Inc.
+ * Copyright (c) 2015 Josh Stone 
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *notice, this list of conditions and the following disclaimer in the
+ *documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 
USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define _GNU_SOURCE 1
+#include 
+#include 
+
+#include "defs.h"
+#include "gdbserver.h"
+#include "protocol.h"
+#include "signals.h"
+
+/* FIXME jistone: export hacks */
+struct tcb *pid2tcb(int pid);
+struct tcb *alloctcb(int pid);
+void droptcb(struct tcb *tcp);
+void newoutf(struct tcb *tcp);
+void print_signalled(struct tcb *tcp, const int pid, int status);
+void print_exited(struct tcb *tcp, const int pid, int status);
+void print_stopped(struct tcb *tcp, const siginfo_t *si, const unsigned 
int sig);
+struct tcb *current_tcp;
+int strace_child;
+
+char* gdbserver = NULL;
+static struct gdb_conn* gdb = NULL;
+static bool gdb_extended = false;
+static bool gdb_multiprocess = false;
+static bool gdb_vcont = false;
+static bool gdb_nonstop = false;
+
+static const char * const gdb_signal_names[] = {
+#define SET(symbol, constant, name, string) \
+[constant] = name,
+#include "signals.def"
+#undef SET
+};
+
+static int gdb_signal_map[SUPPORTED_PERSONALITIES][GDB_SIGNAL_LAST];
+
+enum gdb_stop {
+gdb_stop_unknown, // O or F or anything else
+gdb_stop_error, // E
+gdb_stop_signal, // S or T
+gdb_stop_exited, // W
+gdb_stop_terminated, // X
+
+// specific variants of gdb_stop_signal 05
+gdb_stop_trap, // missing or unrecognized stop reason
+gdb_stop_syscall_entry,
+

[PATCH 1/3] Add gdb remote protocol handling to strace

2017-02-10 Thread Stan Cox
Requesting comments on this patch, which adds support for the gdb
remote serial protocol, which is described further in "info gdb
'Remote Protocol' 'Packets'" This protocol connects to gdbserver,
which catches the syscalls and returns information about them, as well
as register and memory info, via the protocol.  The strace -d option
will display the packets going over the protocol.  Most of the
implementation is in the gdbserver backend.  The strace level support
is primarily of two types: option handling and gdb remote protocol
interception.

This is currently located at github.com:stanfordcox/strace.git on the
gdbserver0 branch.

Brief summary of changes:

Makefile.am:  Also consider gdbserver when searching for header
files. Build gdbserver.c and protocol.c

defs.h:  Add TCB_GDB_CONT_PID_TID which determines what type of
continue packet to use..  Make pid2tcb available for use by the
gdbserver backend.

strace.c:  droptcb:  gdb_detach a connection.
starup_attach: gdb_starup_attach a connection.
startup_child:  gdb_startup_child a child.
test_ptrace_seize:  gdbserver handles this itself.
init:  Add -G option.  The connection syntax is further described in "info
gdb 'Remote Debugging' 'Connecting'"  Initialize via gdb_init and
gdb_finalize_init.
cleanup:  gdb_cleanup to cleanup.
trace: gdb_trace handles gdb remote protocol tracing

syscall.c:  update_personality called by gdbserver backend.
get_regs: gdbserver returns the register values.
get_scno:  gdbserver returns the syscall number.

upeek.c:  upeek:  gdbserver reads memory.

util.c:  umoven/umovestr:  gdbserver reads memory.

pathtrace.c:  getfdpath:  gdbserver gets the path.




diff a/Makefile.am b/Makefile.am
--- ../src/Makefile.am  2017-01-25 10:43:07.586827022 -0500
+++ Makefile.am 2017-02-02 10:30:27.834558340 -0500
@@ -47,5 +47,5 @@ ARCH  = @arch@
  ACLOCAL_AMFLAGS = -I m4
  AM_CFLAGS = $(WARN_CFLAGS)
-AM_CPPFLAGS = -I$(builddir)/$(OS)/$(ARCH) \
+OS_CPPFLAGS = -I$(builddir)/$(OS)/$(ARCH) \
  -I$(srcdir)/$(OS)/$(ARCH) \
  -I$(builddir)/$(OS) \
@@ -54,4 +54,9 @@ AM_CPPFLAGS = -I$(builddir)/$(OS)/$(ARCH
  -I$(srcdir)

+AM_CPPFLAGS = -I$(builddir)/gdbserver/$(ARCH) \
+ -I$(srcdir)/gdbserver/$(ARCH) \
+ -I$(builddir)/gdbserver \
+ -I$(srcdir)/gdbserver $(OS_CPPFLAGS)
+
  AM_CFLAGS_FOR_BUILD = $(WARN_CFLAGS_FOR_BUILD)
  AM_CPPFLAGS_FOR_BUILD = $(AM_CPPFLAGS)
@@ -262,4 +267,9 @@ strace_SOURCES =\
# end of strace_SOURCES

+# jistone
+strace_SOURCES +=  \
+   gdbserver/gdbserver.c   \
+   gdbserver/protocol.c
+
  if USE_LIBUNWIND
  strace_SOURCES += unwind.c

diff a/defs.h b/defs.h
--- ../src/defs.h   2017-02-02 12:40:50.967534599 -0500
+++ defs.h  2017-02-09 10:53:49.474373376 -0500
@@ -269,4 +269,5 @@ struct tcb {
  #define TCB_HIDE_LOG  0x80/* We should hide everything (until execve) */
  #define TCB_SKIP_DETACH_ON_FIRST_EXEC 0x100   /* -b execve should skip 
detach on first execve */
+#define TCB_GDB_CONT_PID_TID 0x200 /* Use vCont;c:pPID.TID for for gdb 
backend */

  /* qualifier flags */
@@ -431,4 +432,5 @@ extern int set_tcb_priv_data(struct tcb
 void (*free_priv_data)(void *));
  extern void free_tcb_priv_data(struct tcb *);
+extern struct tcb *pid2tcb(int pid);

  static inline unsigned long get_tcb_priv_ulong(const struct tcb *tcp)

diff a/strace.c b/strace.c
--- ../src/strace.c 2017-01-25 10:43:07.605827151 -0500
+++ strace.c2017-02-02 10:15:09.396248528 -0500
@@ -50,4 +50,6 @@
  #include "printsiginfo.h"

+#include "gdbserver.h"
+
  /* In some libc, these aren't declared. Do it ourself: */
  extern char **environ;
@@ -131,5 +133,5 @@ static bool detach_on_execve = 0;

  static int exit_code;
-static int strace_child = 0;
+int strace_child = 0;
  static int strace_tracer_pid = 0;

@@ -147,5 +149,5 @@ static FILE *shared_log;

  struct tcb *printing_tcp = NULL;
-static struct tcb *current_tcp;
+struct tcb *current_tcp;

  static struct tcb **tcbtab;
@@ -692,5 +694,5 @@ tabto(void)
   * may create bogus empty FILE., and then die.
   */
-static void
+void
  newoutf(struct tcb *tcp)
  {
@@ -727,5 +729,5 @@ expand_tcbtab(void)
  }

-static struct tcb *
+struct tcb *
  alloctcb(int pid)
  {
@@ -791,5 +793,5 @@ free_tcb_priv_data(struct tcb *tcp)
  }

-static void
+void
  droptcb(struct tcb *tcp)
  {
@@ -845,4 +847,9 @@ detach(struct tcb *tcp)
int status;

+   if (gdbserver) {
+   gdb_detach(tcp);
+   goto drop;
+   }
+
/*
 * Linux wrongly insists the child be stopped
@@ -1133,4 +1140,8 @@ startup_attach(void)
continue; /* no, we already attached it */

+   if (gdbserver) {
+   gdb_startup_attach(tcp);
+   continue;
+   }
if (tcp->pid == parent_pid || tcp->pid == strace_tracer_pid) {
errno = EPERM;
@@