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