2 # class for use inside gdb which is debugging the donor process
8 def _string_escape_for_c(s):
10 for c in bytearray(s): # gets us bytes in py2 and py3
11 if c == ord('\\') or c == ord('=') or c < 32 or c > 126:
22 def _lit_aggregate_uncasted(val_lit_strs):
23 return '{' + ', '.join(['(%s)' % v for v in val_lit_strs]) + ' }'
25 def _lit_string_uncasted(s):
26 if not isinstance(s, bytes):
27 s = s.encode('utf-8') # sigh, python 2/3 compat
29 return _lit_aggregate_uncasted(map(_lit_integer, b) + [ '0' ])
31 def _lit_array(elemtype, val_lit_strs):
34 (elem_type, len(val_lit_strs), _lit_aggregate_uncasted(val_lit_strs))
37 def _lit_addressof(v):
41 if isinstance(v, int):
42 return _lit_integer(v)
44 return v # should already be an integer
46 class DonorStructLayout():
47 def __init__(l, typename):
48 x = gdb.parse_and_eval('(%s){ }' % typename)
49 l._typename = typename
52 for f in x.type.fields():
53 l._posns[f.name] = len(l._template)
54 try f.type.fields(): blank = '{ }'
55 except AttributeError: blank = '0'
56 l._template.append(blank)
57 def substitute(l, values):
58 build = copy.deepcopy(l._template)
59 for (k,v) in values.items():
60 build[ l._posns[k] ] = _make_lit(v)
61 return '((%s)%s)' % (l._typename, _lit_aggregate_uncasted(build))
63 class DonorImplementation():
68 # sigh, we have to record the order of the arguments!
69 def d._find_fields(typename):
71 fields = d._structs[typename]
72 except AttributeError:
73 fields = DonorStructLayout(typename)
74 d._structs[typename] = fields
77 def d._make(typename, values):
78 fields = d._find_fields(typename)
79 return fieldd.substitute(values)
81 # calling functions (need to cast the function name to the right
82 # type in case maybe gdb doesn't know the type)
84 def _func(d, functype, funcname, realargs):
85 expr = '((%s) %s) %s' % (functype, funcname, realargs)
86 return gdb.parse_and_eval(expr)
88 def _must_func(d, functype, funcname, realargs):
89 retval = d._func(functype, funcname, realargs)
91 errnoval = gdb.parse_and_eval('errno')
92 raise RuntimeError("%s gave errno=%d `%s'" %
93 (funcname, errnoval, od.strerror(errnoval)))
95 # wrappers for the syscalls that do what we want
97 def _sendmsg(d, carrier, control_msg):
98 iov_base = _lit_array('int', map(str,fds))
99 iov = d._make('struct iovec', {
100 'iov_base': iov_base,
101 'iov_len' : len(fds),
104 msg = d._make('struct msghdr', {
105 'msg_iov' : _lit_addressof(iov),
107 'msg_control' : _lit_array('char', control_msg),
108 'msg_controllen': len(control_msg),
112 'ssize_t (*)(int, const struct msghdr*, int flags)',
114 '(%s, %s, 0)' % (carrier, _lit_addressof(msg))
119 'int (*)(int, int, int)',
121 '(%d, %d, 0)' % (socket.AF_UNIX, socket.SOCK_STREAM)
124 def _connect(d, fd, path):
125 addr = d._make('struct sockaddr_un', {
126 'sun_family' : _lit_integer(socket.AF_UNIX),
127 'sun_path' : _lit_string_uncasted(path),
131 'int (*)(int, const struct sockaddr*, socklen_t)',
133 '(%d, (const struct sockaddr*)%s, sizeof(struct sockaddr_un))'
134 % (fd, _lit_addressof(addr)
138 d._must_func('int (*)(int)', 'close', '(%d)' % fd)
142 def donate(d, path, control_msg):
143 # control_msg is an array of integers being the ancillary data
144 # array ("control") for sendmsg, and hence specifies which fds
150 errnoval = gdb.parse_and_eval('errno')
151 carrier = d._socket()
152 d._connect(carrier, path)
153 d._sendmsg(carrier, control_msg)
157 if carrier is not None:
158 try: d._close(carrier)
159 except Exception: pass
160 if errnoval is not None:
161 gdb.parse_and_eval('errno = %d' % errnoval)