- 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
- 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._dlopen()
- self._sym = self._dlfunc('void* (*)(void*, const char*)'
- 'dlsym',
- '(%s, "fishdescriptor_donate")' % self._open)
-
- def donate(self, path, fds):
- 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)
+ return parse_eval(expr)
+
+ def _must_func(di, functype, funcname, realargs):
+ retval = di._func(functype, funcname, realargs)
+ if retval < 0:
+ errnoval = di._parse_eval_errno('%s')
+ raise RuntimeError("%s gave errno=%d `%s'" %
+ (funcname, errnoval, os.strerror(errnoval)))
+ return retval
+
+ # wrappers for the syscalls that do what we want
+
+ def _sendmsg(di, carrier, control_msg):
+ iov_base = _lit_array('char', [1])
+ iov = di._make('struct iovec', {
+ 'iov_base': iov_base,
+ 'iov_len' : 1,
+ })
+
+ msg = di._make('struct msghdr', {
+ 'msg_iov' : _lit_addressof(iov),
+ 'msg_iovlen' : 1,
+ 'msg_control' : _lit_array('char', control_msg),
+ 'msg_controllen': len(control_msg),
+ })
+
+ di._must_func(
+ 'ssize_t (*)(int, const struct msghdr*, int)',
+ 'sendmsg',
+ '(%s, %s, 0)' % (carrier, _lit_addressof(msg))
+ )
+
+ def _socket(di):
+ return di._must_func(
+ 'int (*)(int, int, int)',
+ 'socket',
+ '(%d, %d, 0)' % (socket.AF_UNIX, socket.SOCK_STREAM)
+ )
+
+ def _connect(di, fd, path):
+ addr = di._make('struct sockaddr_un', {
+ 'sun_family' : _lit_integer(socket.AF_UNIX),
+ 'sun_path' : _lit_string_uncasted(path),
+ })
+
+ di._must_func(
+ 'int (*)(int, const struct sockaddr*, socklen_t)',
+ 'connect',
+ '(%d, (const struct sockaddr*)%s, sizeof(struct sockaddr_un))'
+ % (fd, _lit_addressof(addr))
+ )
+
+ def _close(di, fd):
+ di._must_func('int (*)(int)', 'close', '(%d)' % fd)
+
+ def _mkdir(di, path, mode):
+ r = di._func(
+ 'int (*)(const char*, mode_t)',
+ 'mkdir',
+ '("%s", %d)' % (_string_escape_for_c(path), mode)
+ )
+ if r < 0:
+ errnoval = di._parse_eval_errno('%s')
+ if errnoval != os.errno.EEXIST:
+ raise RuntimeError("mkdir %s failed: `%s'" %
+ (repr(path), os.strerror(errnoval)))
+ return 0
+ return 1
+
+ def _errno_save(di):
+ di._saved_errno = di._parse_eval_errno('%s')
+
+ def _errno_restore(di):
+ to_restore = di._saved_errno
+ di._saved_errno = None
+ if to_restore is not None:
+ di._parse_eval_errno('%%s = %d' % to_restore)
+
+ def _result(di, output):
+ sys.stderr.write("#> %s" % output)
+ di._result_stream.write(output)
+ di._result_stream.flush()
+
+ # main entrypoints
+
+ def donate(di, path, control_msg):
+ # control_msg is an array of integers being the ancillary data
+ # array ("control") for sendmsg, and hence specifies which fds
+ # to pass
+
+ carrier = None
+ try:
+ di._errno_save()
+ carrier = di._socket()
+ di._connect(carrier, path)
+ di._sendmsg(carrier, control_msg)
+ di._close(carrier)
+ carrier = None
+ finally:
+ if carrier is not None:
+ try: di._close(carrier)
+ except Exception: pass
+ di._errno_restore()
+
+ di._result('1\n')
+
+ def geteuid(di):
+ try:
+ di._errno_save()
+ val = di._must_func('uid_t (*)(void)', 'geteuid', '()')
+ finally:
+ di._errno_restore()
+
+ di._result('%d\n' % val)
+
+ def mkdir(di, path):
+ try:
+ di._errno_save()
+ val = di._mkdir(path, int('0700', 8))
+ finally:
+ di._errno_restore()
+
+ di._result('%d\n' % val)
+
+ def _protocol_read(di):
+ input = sys.stdin.readline()
+ if input == '': return None
+ input = input.rstrip('\n')
+ sys.stderr.write("#< %s\n" % input)
+ return input
+
+ def eval_loop(di):
+ if not gdb.selected_inferior().was_attached:
+ print('gdb inferior not attached', file=sys.stderr)
+ sys.exit(0)
+ while True:
+ di._result('!\n')
+ cmd = di._protocol_read()
+ if cmd is None: break
+ eval(cmd)