patch proposal for backend dispatch table

Stan Cox scox at redhat.com
Mon Apr 24 03:48:34 UTC 2017


This is a proposal  to facilitate more cleanly integrating a new 
backend, e.g. the previously proposed gdbserver backend

  https://sourceforge.net/p/strace/mailman/message/35672632/

This is a proposed patch to add a dispatch table for a new backend.  The 
idea is to add a dispatch table, a table of function pointers to those 
routines that a new backend needs to override. Changes fall into three 
categories

0. Add new dispatch table, "backend" to defs.h

1. The new backend will replace the default routine.  The default case 
simply uses the existing routine.  e.g. detach.  All uses replaced by 
backend.foo

2. The new backend needs additional functionality.  The default case 
will not use the entry.  e.g. start_init,  All uses guarded by null 
entry pointer check

3. The new backend will replace the default routine.  The default case 
simply uses the existing routine but to account for having many callers 
a preprocessor macro is defined which uses the same name.  e.g. umoven   
(Could alternately be replaced by #1)


Any comments on using this approach to allow new backends to have a 
cleaner way to integrate with the existing frontend?


Current patch


diff --git a/defs.h b/defs.h
index 5b81647..ec890ae 100644
--- a/defs.h
+++ b/defs.h
@@ -289,6 +289,28 @@ struct tcb {
  #define filtered(tcp)    ((tcp)->flags & TCB_FILTERED)
  #define hide_log(tcp)    ((tcp)->flags & TCB_HIDE_LOG)

+/* BackendControl Block */
+struct backend {
+    bool (*trace) (void);
+    void (*detach) (struct tcb *tcp);
+    void (*startup_child) (char **argv);
+    void (*test_ptrace_seize) (void);
+    bool (*start_init) (void);
+    bool (*end_init) (void);
+    void (*startup_attach) (struct tcb *tcp);
+    void (*get_regs) (pid_t pid);
+    int (*get_scno) (struct tcb *tcp);
+    int (*getfdpath) (struct tcb *tcp, int fd, char *buf, unsigned 
bufsize);
+    int (*umoven_) (struct tcb *const tcp, kernel_ulong_t addr, 
unsigned int len,
+           void *const our_addr);
+    int (*umovestr) (struct tcb *const tcp, kernel_ulong_t addr, 
unsigned int len, char *laddr);
+    int (*upeek_) (int pid, unsigned long off, kernel_ulong_t *res);
+    int (*upoke_) (int pid, unsigned long off, kernel_ulong_t val);
+} backend;
+
+#define umoven(tcp,addr,len,our_addr) 
backend.umoven_(tcp,addr,len,our_addr)
+#define upeek(pid,off,res) backend.upeek_(int pid, unsigned long off, 
kernel_ulong_t *res)
+
  #include "xlat.h"

  extern const struct xlat addrfams[];
@@ -445,8 +467,8 @@ static inline int set_tcb_priv_ulong(struct tcb 
*tcp, unsigned long val)
      return set_tcb_priv_data(tcp, (void *) val, 0);
  }

-extern int
-umoven(struct tcb *tcp, kernel_ulong_t addr, unsigned int len, void 
*laddr);
+// extern int
+// umoven(struct tcb *tcp, kernel_ulong_t addr, unsigned int len, void 
*laddr);
  #define umove(pid, addr, objp)    \
      umoven((pid), (addr), sizeof(*(objp)), (void *) (objp))

@@ -463,9 +485,17 @@ umoven_or_printaddr_ignore_syserror(struct tcb 
*tcp, kernel_ulong_t addr,
  extern int
  umovestr(struct tcb *tcp, kernel_ulong_t addr, unsigned int len, char 
*laddr);

+#pragma push_macro("upeek")
+#pragma push_macro("upoke")
+#undef upeek
+#undef upoke
+
  extern int upeek(int pid, unsigned long, kernel_ulong_t *);
  extern int upoke(int pid, unsigned long, kernel_ulong_t);

+#pragma pop_macro("upeek")
+#pragma pop_macro("upoke")
+
  extern bool
  print_array(struct tcb *tcp,
          kernel_ulong_t start_addr,
diff --git a/pathtrace.c b/pathtrace.c
index 90974f4..2d17d6e 100644
--- a/pathtrace.c
+++ b/pathtrace.c
@@ -58,7 +58,7 @@ upathmatch(struct tcb *const tcp, const kernel_ulong_t 
upath)
  {
      char path[PATH_MAX + 1];

-    return umovestr(tcp, upath, sizeof path, path) > 0 &&
+    return backend.umovestr(tcp, upath, sizeof path, path) > 0 &&
          pathmatch(path);
  }

@@ -69,7 +69,7 @@ static int
  fdmatch(struct tcb *tcp, int fd)
  {
      char path[PATH_MAX + 1];
-    int n = getfdpath(tcp, fd, path, sizeof(path));
+    int n = backend.getfdpath(tcp, fd, path, sizeof(path));

      return n >= 0 && pathmatch(path);
  }
diff --git a/strace.c b/strace.c
index 4ee2d5d..1dd912f 100644
--- a/strace.c
+++ b/strace.c
@@ -157,7 +157,14 @@ unsigned os_release; /* generated from uname()'s 
u.release */
  static void detach(struct tcb *tcp);
  static void cleanup(void);
  static void interrupt(int sig);
+static bool trace (void);
  static sigset_t empty_set, blocked_set;
+#pragma push_macro("umoven")
+#undef umoven
+int    umoven(struct tcb *const tcp, kernel_ulong_t addr, unsigned int len,
+        void *const our_addr);
+#pragma pop_macro("umoven")
+

  #ifdef HAVE_SIG_ATOMIC_T
  static volatile sig_atomic_t interrupted;
@@ -1132,6 +1139,11 @@ startup_attach(void)
          if (tcp->flags & TCB_ATTACHED)
              continue; /* no, we already attached it */

+        if (backend.startup_attach) {
+            backend.startup_attach(tcp);
+            continue;
+        }
+
          if (tcp->pid == parent_pid || tcp->pid == strace_tracer_pid) {
              errno = EPERM;
              perror_msg("attach: pid %d", tcp->pid);
@@ -1567,6 +1579,7 @@ get_os_release(void)
      return rel;
  }

+
  /*
   * Initialization part of main() was eating much stack (~0.5k),
   * which was unused after init.
@@ -1783,6 +1796,9 @@ init(int argc, char *argv[])
          tflag = 1;
      }

+    if (backend.start_init && backend.start_init() < 0)
+            error_msg_and_die("Cannot initialize backend on this target.");
+
  #ifdef USE_LIBUNWIND
      if (stack_trace_enabled) {
          unsigned int tcbi;
@@ -1817,9 +1833,23 @@ init(int argc, char *argv[])
          ptrace_setoptions |= PTRACE_O_TRACECLONE |
                       PTRACE_O_TRACEFORK |
                       PTRACE_O_TRACEVFORK;
+    backend.trace = trace;
+    backend.detach = detach;
+    backend.startup_child = startup_child;
+    backend.test_ptrace_seize = test_ptrace_seize;
+    backend.start_init = NULL;
+    backend.startup_attach = NULL;
+    backend.get_regs = NULL;
+    backend.get_scno = NULL;
+    backend.getfdpath = getfdpath;
+    backend.umoven_ = umoven;
+    backend.umovestr = umovestr;
+    backend.upeek_ = upeek;
+    backend.upoke_ = upoke;
+
      if (debug_flag)
          error_msg("ptrace_setoptions = %#x", ptrace_setoptions);
-    test_ptrace_seize();
+    backend.test_ptrace_seize();

      /*
       * Is something weird with our stdin and/or stdout -
@@ -1882,7 +1912,7 @@ init(int argc, char *argv[])
       * in the startup_child() mode we kill the spawned process anyway.
       */
      if (argv[0]) {
-        startup_child(argv);
+        backend.startup_child(argv);
      }

      sa.sa_handler = SIG_IGN;
@@ -1917,6 +1947,9 @@ init(int argc, char *argv[])
      if (nprocs != 0 || daemonized_tracer)
          startup_attach();

+    if (backend.end_init)
+        backend.end_init();
+
      /* Do we want pids printed in our -o OUTFILE?
       * -ff: no (every pid has its own file); or
       * -f: yes (there can be more pids in the future); or
@@ -1964,7 +1997,7 @@ cleanup(void)
              kill(tcp->pid, SIGCONT);
              kill(tcp->pid, fatal_sig);
          }
-        detach(tcp);
+        backend.detach(tcp);
      }
      if (cflag)
          call_summary(shared_log);
@@ -2325,7 +2358,7 @@ trace(void)
              if (tcp->flags & TCB_SKIP_DETACH_ON_FIRST_EXEC) {
                  tcp->flags &= ~TCB_SKIP_DETACH_ON_FIRST_EXEC;
              } else {
-                detach(tcp); /* do "-b execve" thingy */
+                backend.detach(tcp); /* do "-b execve" thingy */
                  return true;
              }
          }
@@ -2483,6 +2516,7 @@ restart_tracee:
      return true;
  }

+
  int
  main(int argc, char *argv[])
  {
@@ -2490,7 +2524,7 @@ main(int argc, char *argv[])

      exit_code = !nprocs;

-    while (trace())
+    while (backend.trace())
          ;

      cleanup();
diff --git a/syscall.c b/syscall.c
index 3e91880..bb50659 100644
--- a/syscall.c
+++ b/syscall.c
@@ -1153,6 +1153,9 @@ ptrace_setregs(pid_t pid)
  static void
  get_regs(pid_t pid)
  {
+    if (backend.get_regs)
+        return backend.get_regs (pid);
+
  #undef USE_GET_SYSCALL_RESULT_REGS
  #ifdef ptrace_getregset_or_getregs

@@ -1230,7 +1233,11 @@ get_scno(struct tcb *tcp)
      if (get_regs_error)
          return -1;

-    int rc = arch_get_scno(tcp);
+    int rc;
+    if (backend.get_scno)
+        rc = backend.get_scno(tcp);
+    else
+        rc= arch_get_scno(tcp);
      if (rc != 1)
          return rc;

diff --git a/upeek.c b/upeek.c
index 01a12d3..8f191c7 100644
--- a/upeek.c
+++ b/upeek.c
@@ -34,6 +34,8 @@
  #include "defs.h"
  #include "ptrace.h"

+#undef upeek
+
  int
  upeek(int pid, unsigned long off, kernel_ulong_t *res)
  {
diff --git a/upoke.c b/upoke.c
index dda0b8d..be4cea6 100644
--- a/upoke.c
+++ b/upoke.c
@@ -28,6 +28,8 @@
  #include "defs.h"
  #include "ptrace.h"

+#undef upoke
+
  int
  upoke(int pid, unsigned long off, kernel_ulong_t val)
  {
diff --git a/util.c b/util.c
index 9144efb..0474c92 100644
--- a/util.c
+++ b/util.c
@@ -597,7 +597,7 @@ void
  printfd(struct tcb *tcp, int fd)
  {
      char path[PATH_MAX + 1];
-    if (show_fd_path && getfdpath(tcp, fd, path, sizeof(path)) >= 0) {
+    if (show_fd_path && backend.getfdpath(tcp, fd, path, sizeof(path)) 
 >= 0) {
          static const char socket_prefix[] = "socket:[";
          const size_t socket_prefix_len = sizeof(socket_prefix) - 1;
          const size_t path_len = strlen(path);
@@ -855,7 +855,7 @@ printpathn(struct tcb *const tcp, const 
kernel_ulong_t addr, unsigned int n)
          n = sizeof path - 1;

      /* Fetch one byte more to find out whether path length > n. */
-    nul_seen = umovestr(tcp, addr, n + 1, path);
+    nul_seen = backend.umovestr(tcp, addr, n + 1, path);
      if (nul_seen < 0)
          printaddr(addr);
      else {
@@ -912,7 +912,7 @@ printstr_ex(struct tcb *const tcp, const 
kernel_ulong_t addr,
      if (size > len)
          size = len;
      if (style & QUOTE_0_TERMINATED)
-        rc = umovestr(tcp, addr, size, str);
+        rc = backend.umovestr(tcp, addr, size, str);
      else
          rc = umoven(tcp, addr, size, str);

@@ -1111,6 +1111,9 @@ vm_read_mem(const pid_t pid, void *const laddr,
   * move `len' bytes of data from process `pid'
   * at address `addr' to our space at `our_addr'
   */
+#pragma push_macro("umoven")
+#undef umoven
+
  int
  umoven(struct tcb *const tcp, kernel_ulong_t addr, unsigned int len,
         void *const our_addr)
@@ -1221,6 +1224,8 @@ umoven(struct tcb *const tcp, kernel_ulong_t addr, 
unsigned int len,
      return 0;
  }

+#pragma pop_macro("umoven")
+
  int
  umoven_or_printaddr(struct tcb *const tcp, const kernel_ulong_t addr,
              const unsigned int len, void *const our_addr)






More information about the Strace-devel mailing list