2 # class for use inside gdb which is debugging the donor process
12 rtld_now = dl.RTLD_NOW
14 # some installations lack dl, it seems
15 # https://bugs.launchpad.net/ubuntu/+source/python2.7/+bug/1721840
19 def _string_escape_for_c(s):
20 if not isinstance(s, bytes):
21 s = s.encode('utf-8') # sigh, python 2/3 compat
23 for c in bytearray(s): # gets us bytes in py2 and py3
24 if c == ord('\\') or c == ord('=') or c < 32 or c > 126:
30 class DonorImplementation(preloaded=False):
32 # works on the current gdb.Inferior
33 # ideally should be reused if the same process is targetd
37 self._sym = 'fishdescriptor_donate'
39 def _func(self, functype, funcname, realargs):
40 expr = '((%s) %s) %s' % (functype, funcname, realargs)
41 return gdb.parse_and_eval(expr)
43 def _dlfunc(self, functype, funcname, realargs):
44 r = self._func(functype,funcname,realargs)
46 err = self._func('char* (*)(void)', 'dlerror', '()')
48 err = 'dlerror said NULL!'
51 raise RuntimeError("%s failed: %s" % (funcname, err))
55 if self._open is not None: return
56 o = self._dlfunc('void* (*)(const char*, int)',
58 '("libfishdescriptor-donate.so.1.0", %s)' % rtld_now)
59 self._open = '((void*)%s)' % o
62 if self._sym is not None: return
64 self._sym = self._dlfunc('void* (*)(void*, const char*)'
66 '(%s, "fishdescriptor_donate")' % self._open)
68 def donate(self, path, fds):
70 r = self._func('int (*)(const char*, const int*)',
72 '("%s", (int[%d]){ %s, -1 })'
73 % (_string_escape_for_c(path),
75 ', '.join(["%d" % fd for fd in fds])))
77 err = self._func('char* (*)(int)',
81 err = 'strerror failed'
84 raise RuntimeError("donate failed: %s" % err)