chiark / gitweb /
fishdescriptor: work on python code
authorIan Jackson <ian.jackson@eu.citrix.com>
Fri, 6 Oct 2017 18:03:25 +0000 (19:03 +0100)
committerIan Jackson <Ian.Jackson@eu.citrix.com>
Fri, 6 Oct 2017 18:03:25 +0000 (19:03 +0100)
Still very incomplete

Signed-off-by: Ian Jackson <Ian.Jackson@eu.citrix.com>
fishdescriptor/Makefile
fishdescriptor/greenend/fishdescriptor/__init__.py [new file with mode: 0644]
fishdescriptor/greenend/fishdescriptor/indonor.py [new file with mode: 0644]

index f9065154f58c17ba048456d7e10250567c71c78b..e6b493ac17e5e4bc13084564e2b51690f76bc0c7 100644 (file)
@@ -9,6 +9,8 @@ MINOR=0
 LIBCANON=       libfishdescriptor-donate.so.$(MAJOR)
 LIBTARGET=      $(LIBCANON).$(MINOR)
 
+all:   $(LIBTARGET)
+
 $(LIBTARGET):  donate.o
        $(CC) -shared -Wl,-soname -Wl,$(LIBCANON) -o $@ $< $(LIBS)
 
diff --git a/fishdescriptor/greenend/fishdescriptor/__init__.py b/fishdescriptor/greenend/fishdescriptor/__init__.py
new file mode 100644 (file)
index 0000000..2a80833
--- /dev/null
@@ -0,0 +1,2 @@
+
+class 
diff --git a/fishdescriptor/greenend/fishdescriptor/indonor.py b/fishdescriptor/greenend/fishdescriptor/indonor.py
new file mode 100644 (file)
index 0000000..b9e9053
--- /dev/null
@@ -0,0 +1,71 @@
+
+# class for use inside gdb which is debugging the donor process
+
+import gdb
+
+def _string_escape_for_c(s):
+    if not isinstance(s, bytes):
+        s = s.encode('utf-8') # sigh, python 2/3 compat
+    out = ''
+    for c in bytearray(s): # gets us bytes in py2 and py3
+        if c == ord('\\') or c == ord('=') or c < 32 or c > 126:
+            out += '\\x%02x' % c
+        else:
+            out += chr(c)
+    return out
+
+class DonorImplementation():
+    def __init__(self):
+        # works on the current gdb.Inferior
+        # ideally should be reused if the same process is targetd
+        self._open = None
+        self._sym = None
+
+    def _func(self, functype, funcname, realargs):
+        expr = '((%s) %s) %s' % (functype, funcname, realargs)
+        return gdb.parse_and_eval(expr)
+
+    def _dlfunc(self, functype, funcname, realargs):
+        r = self._func(functype,funcname,realargs)
+        if not r:
+            err = self._func('char* (*)(void)', 'dlerror', '()')
+            if not err:
+                err = 'dlerror said NULL!'
+            else:
+                err = err.string()
+            raise RuntimeError("%s failed: %s" % (funcname, err))
+        return r
+
+    def _dlopen(self):
+        if self._open is not None: return
+        rtld_print_cmd = ['fishdescriptor','--print-rtld-now'];
+        rtld_now = subprocess.check_output(rtld_print_cmd).rstrip('\n')
+        o = self._dlfunc('void* (*)(const char*, int)',
+                         'dlopen',
+                         '("libfishdescriptor-donate.so.1.0", %s)' % rtld_now)
+        self._open = '((void*)%s)' % o
+
+    def _dlsym(self):
+        if self._sym is not None: return
+        self._sym = self._dlfunc('void* (*)(void*, const char*)'
+                                 'dlsym',
+                                 '(%s, "fishdescriptor_donate")' % self._open)
+
+    def donate(self, path, fds):
+        self._dlopen()
+        self._dlsym()
+        r = self._func('int (*)(const char*, const int*)',
+                       self._sym,
+                       '("%s", (int[%d]){ %s, -1 })'
+                       % (_string_escape_for_c(path),
+                          len(fds) + 1,
+                          ', '.join(["%d" % fd for fd in fds])))
+        if r:
+            err = self._func('char* (*)(int)',
+                             strerror,
+                             r)
+            if not err:
+                err = 'strerror failed'
+            else:
+                err = err.string()
+            raise RuntimeError("donate failed: %s" % err)