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.c 2017-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.<nonexistant_pid>, 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; @@ -1305,4 +1316,9 @@ startup_child(char **argv) struct tcb *tcp; + if (gdbserver) { + gdb_startup_child(argv); + return; + } + filename = argv[0]; filename_len = strlen(filename); @@ -1486,4 +1502,8 @@ test_ptrace_seize(void) int pid; + if (gdbserver) { + return; /* gdbserver provides syscall info */ + } + /* Need fork for test. NOMMU has no forks */ if (NOMMU_SYSTEM) { @@ -1612,4 +1632,5 @@ init(int argc, char *argv[]) #endif "D" + "G:" "a:e:o:O:p:s:S:u:E:P:I:")) != EOF) { switch (c) { @@ -1644,4 +1665,7 @@ init(int argc, char *argv[]) followfork++; break; + case 'G': + gdbserver = strdup(optarg); + break; case 'h': usage(); @@ -1742,5 +1766,6 @@ init(int argc, char *argv[]) acolumn_spaces[acolumn] = '\0'; - if (!argv[0] && !nprocs) { + /* under gdbserver, we can reasonably allow having neither to use existing targets. */ + if (!argv[0] && !nprocs && !gdbserver) { error_msg_and_help("must have PROG [ARGS] or -p PID"); } @@ -1753,4 +1778,19 @@ init(int argc, char *argv[]) followfork = optF; + if (gdbserver) { + if (username) { + error_msg_and_die("-u and -G are mutually exclusive"); + } + + if (daemonized_tracer) { + error_msg_and_die("-D and -G are mutually exclusive"); + } + + if (!followfork) { + error_msg("-G is always multithreaded, implies -f"); + followfork = 1; + } + } + if (followfork >= 2 && cflag) { error_msg_and_help("(-c or -C) and -ff are mutually exclusive"); @@ -1784,4 +1824,9 @@ init(int argc, char *argv[]) } + if (gdbserver) { + if (gdb_init() < 0) + error_msg_and_die("-G is not supported on this target."); + } + #ifdef USE_LIBUNWIND if (stack_trace_enabled) { @@ -1918,4 +1963,7 @@ init(int argc, char *argv[]) startup_attach(); + if (gdbserver) + gdb_finalize_init(); + /* Do we want pids printed in our -o OUTFILE? * -ff: no (every pid has its own file); or @@ -1926,5 +1974,5 @@ init(int argc, char *argv[]) } -static struct tcb * +struct tcb * pid2tcb(int pid) { @@ -1969,4 +2017,6 @@ cleanup(void) if (cflag) call_summary(shared_log); + + gdb_cleanup(); } @@ -2107,5 +2157,5 @@ maybe_switch_tcbs(struct tcb *tcp, const } -static void +void print_signalled(struct tcb *tcp, const int pid, int status) { @@ -2130,5 +2180,5 @@ print_signalled(struct tcb *tcp, const i } -static void +void print_exited(struct tcb *tcp, const int pid, int status) { @@ -2146,5 +2196,5 @@ print_exited(struct tcb *tcp, const int } -static void +void print_stopped(struct tcb *tcp, const siginfo_t *si, const unsigned int sig) { @@ -2237,4 +2287,7 @@ trace(void) return false; + if (gdbserver) + return gdb_trace(); + /* * Used to exit simply when nprocs hits zero, but in this testcase: diff a/syscall.c b/syscall.c --- ../src/syscall.c 2017-02-02 12:40:50.970534610 -0500 +++ syscall.c 2017-02-01 22:22:53.021936753 -0500 @@ -45,4 +45,5 @@ #include "regs.h" #include "ptrace.h" +#include "gdbserver.h" #if defined(SPARC64) @@ -318,5 +319,5 @@ set_personality(int personality) } -static void +void update_personality(struct tcb *tcp, unsigned int personality) { @@ -1150,4 +1151,7 @@ void get_regs(pid_t pid) { + if (gdbserver) +# include "gdb_get_regs.c" + #undef USE_GET_SYSCALL_RESULT_REGS #ifdef ptrace_getregset_or_getregs @@ -1219,8 +1223,13 @@ int get_scno(struct tcb *tcp) { + int rc; + if (get_regs_error) return -1; - int rc = arch_get_scno(tcp); + if (gdbserver) /* syscall number is already filled in */ + rc = 1; + else + rc = arch_get_scno(tcp); if (rc != 1) return rc; diff a/upeek.c b/upeek.c --- ../src/upeek.c 2017-01-25 10:43:07.620827253 -0500 +++ upeek.c 2017-02-01 22:22:53.019936745 -0500 @@ -34,4 +34,5 @@ #include "defs.h" #include "ptrace.h" +#include "gdbserver.h" int @@ -40,4 +41,7 @@ upeek(int pid, unsigned long off, kernel long val; + if (gdbserver) + return gdb_read_mem(pid, off, current_wordsize, false, (char*)res); + errno = 0; val = ptrace(PTRACE_PEEKUSER, (pid_t) pid, (void *) off, 0); diff a/util.c b/util.c --- ../src/util.c 2017-01-25 10:43:07.620827253 -0500 +++ util.c 2017-02-02 10:18:05.222878260 -0500 @@ -45,4 +45,5 @@ #include "regs.h" #include "ptrace.h" +#include "gdbserver.h" int @@ -1125,4 +1126,7 @@ umoven(struct tcb *const tcp, kernel_ulo } u; + if (gdbserver) + return gdb_read_mem(pid, addr, len, false, laddr); + #if ANY_WORDSIZE_LESS_THAN_KERNEL_LONG if (current_wordsize < sizeof(addr) @@ -1273,4 +1277,7 @@ umovestr(struct tcb *const tcp, kernel_u } u; + if (gdbserver) + return gdb_read_mem(pid, addr, len, true, laddr); + #if ANY_WORDSIZE_LESS_THAN_KERNEL_LONG if (current_wordsize < sizeof(addr) diff a/pathtrace.c b/pathtrace.c --- ../src/pathtrace.c 2017-01-25 10:43:07.602827131 -0500 +++ pathtrace.c 2017-02-01 22:22:53.025936769 -0500 @@ -31,4 +31,5 @@ #include <poll.h> +#include "gdbserver.h" #include "syscall.h" @@ -102,4 +103,7 @@ getfdpath(struct tcb *tcp, int fd, char ssize_t n; + if (gdbserver) + return gdb_getfdpath(tcp->pid, fd, buf, bufsize); + if (fd < 0) return -1; ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, SlashDot.org! http://sdm.link/slashdot _______________________________________________ Strace-devel mailing list Strace-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/strace-devel