xref: /xnu-8019.80.24/tools/lldbmacros/kevent.py (revision a325d9c4a84054e40bbe985afedcb50ab80993ea)
1from xnu import *
2from workqueue import GetWorkqueueThreadRequestSummary
3from memory import vm_unpack_pointer
4
5def IterateProcKqueues(proc):
6    """ Iterate through all kqueues in the given process
7
8        params:
9            proc - the proc object
10        returns: nothing, this is meant to be used as a generator function
11            kq - yields each kqueue in the process
12    """
13    for kqf in IterateProcKqfiles(proc):
14        yield kern.GetValueFromAddress(int(kqf), 'struct kqueue *')
15    if int(proc.p_fd.fd_wqkqueue) != 0:
16        yield kern.GetValueFromAddress(int(proc.p_fd.fd_wqkqueue), 'struct kqueue *')
17    for kqwl in IterateProcKqworkloops(proc):
18        yield kern.GetValueFromAddress(int(kqwl), 'struct kqueue *')
19
20def IterateProcKqfiles(proc):
21    """ Iterate through all kqfiles in the given process
22
23        params:
24            proc - the proc object
25        returns: nothing, this is meant to be used as a generator function
26            kqf - yields each kqfile in the process
27    """
28    filetype_KQUEUE = 5
29
30    proc_filedesc = addressof(proc.p_fd)
31    proc_ofiles = proc_filedesc.fd_ofiles
32    queues = list()
33
34    if unsigned(proc_ofiles) == 0:
35        return
36
37    for fd in xrange(0, unsigned(proc_filedesc.fd_afterlast)):
38        if unsigned(proc_ofiles[fd]) != 0:
39            proc_fd_flags = proc_ofiles[fd].fp_flags
40            proc_fd_fglob = proc_ofiles[fd].fp_glob
41            proc_fd_ftype = unsigned(proc_fd_fglob.fg_ops.fo_type)
42            if proc_fd_ftype == xnudefines.DTYPE_KQUEUE:
43                proc_fd_fglob_fg_data = Cast(proc_fd_fglob.fg_data, 'void *')
44                yield Cast(proc_fd_fglob_fg_data, 'struct kqfile *')
45
46def IterateProcKqworkloops(proc):
47    """ Iterate through all kqworkloops in the given process
48
49        params:
50            proc - the proc object
51        returns: nothing, this is meant to be used as a generator function
52            kqwl - yields each kqworkloop in the process
53    """
54    proc_filedesc = addressof(proc.p_fd)
55    if int(proc_filedesc.fd_kqhash) == 0:
56        return
57
58    hash_mask = proc_filedesc.fd_kqhashmask
59    for i in xrange(hash_mask + 1):
60        for kqwl in IterateListEntry(proc_filedesc.fd_kqhash[i], 'struct kqworkloop *', 'kqwl_hashlink'):
61            yield kqwl
62
63def IterateAllKqueues():
64    """ Iterate through all kqueues in the system
65
66        returns: nothing, this is meant to be used as a generator function
67            kq - yields each kqueue in the system
68    """
69    for t in kern.tasks:
70        proc = unsigned(t.bsd_info)
71        if proc == 0:
72            continue
73        proc = kern.GetValueFromAddress(proc, 'proc_t')
74        for kq in IterateProcKqueues(proc):
75            yield kq
76
77def IterateProcKnotes(proc):
78    """ Iterate through all knotes in the given process
79
80        params:
81            proc - the proc object
82        returns: nothing, this is meant to be used as a generator function
83            kn - yields each knote in the process
84    """
85    proc_filedesc = addressof(proc.p_fd)
86
87    if int(proc.p_fd.fd_knlist) != 0:
88        for i in xrange(proc.p_fd.fd_knlistsize):
89            for kn in IterateListEntry(proc.p_fd.fd_knlist[i], 'struct knote *', 'kn_link', list_prefix='s'):
90                yield kn
91    if int(proc.p_fd.fd_knhash) != 0:
92        for i in xrange(proc.p_fd.fd_knhashmask + 1):
93            for kn in IterateListEntry(proc.p_fd.fd_knhash[i], 'struct knote *', 'kn_link', list_prefix='s'):
94                yield kn
95
96def GetKnoteKqueue(kn):
97    """ Get the kqueue corresponding to a given knote
98
99        params:
100            kn - the knote object
101        returns: kq - the kqueue corresponding to the knote
102    """
103
104    return vm_unpack_pointer(kn.kn_kq_packed, kern.globals.kn_kq_packing_params, 'struct kqueue *')
105
106
107@lldb_type_summary(['knote *'])
108@header('{:<20s} {:<20s} {:<10s} {:<20s} {:<20s} {:<30s} {:<10} {:<10} {:<10} {:<20s}'.format('knote', 'ident', 'kev_flags', 'kqueue', 'udata', 'filtops', 'qos_req', 'qos_use', 'qos_ovr', 'status'))
109def GetKnoteSummary(kn):
110    """ Summarizes a knote and related information
111
112        returns: str - summary of knote
113    """
114    format_string = '{o: <#020x} {o.kn_kevent.kei_ident: <#020x} {o.kn_kevent.kei_flags: <#010x} {kq_ptr: <#020x} {o.kn_kevent.kei_udata: <#020x} {ops_str: <30s} {qos_req: <10s} {qos_use: <10s} {qos_ovr: <10s} {st_str: <20s}'
115    state = unsigned(kn.kn_status)
116    fops_str = kern.Symbolicate(kern.globals.sysfilt_ops[unsigned(kn.kn_kevent.kei_filtid)])
117    qos_index = int(kn.kn_qos_index)
118    if qos_index > 6:
119        qos_req = qos_index
120    else:
121        qos_req = int((kn.kn_kevent.kei_qos & 0x003fff00) >> 8).bit_length()
122    return format_string.format(
123            o=kn,
124            qos_req=xnudefines.thread_qos_short_strings[qos_req],
125            qos_use=xnudefines.thread_qos_short_strings[qos_index],
126            qos_ovr=xnudefines.thread_qos_short_strings[int(kn.kn_qos_override)],
127            st_str=GetOptionString('kn_status_t', state, 'KN_'),
128            kq_ptr=int(GetKnoteKqueue(kn)),
129            ops_str=fops_str)
130
131@lldb_command('showknote', fancy=True)
132def ShowKnote(cmd_args=None, cmd_options={}, O=None):
133    """ Show information about a knote
134
135        usage: showknote <struct knote *>
136    """
137    if not cmd_args:
138        return O.error('missing struct knote * argument')
139
140    kn = kern.GetValueFromAddress(cmd_args[0], 'struct knote *')
141    with O.table(GetKnoteSummary.header):
142        print GetKnoteSummary(kn)
143
144def IterateKqueueKnotes(kq):
145    """ Iterate through all knotes of a given kqueue
146
147        params:
148            kq - the kqueue to iterate the knotes of
149        returns: nothing, this is meant to be used as a generator function
150            kn - yields each knote in the kqueue
151    """
152    proc = kq.kq_p
153    for kn in IterateProcKnotes(proc):
154        if unsigned(GetKnoteKqueue(kn)) != unsigned(addressof(kq)):
155            continue
156        yield kn
157
158kqueue_summary_fmt = '{ptr: <#020x} {o.kq_p: <#020x} {dyn_id: <#020x} {servicer: <#20x} {owner: <#20x} {o.kq_count: <6d} {st_str: <10s}'
159
160def GetServicer(req):
161    if req.tr_state in [3, 4]: # [ BINDING , BOUND ]
162        return int(req.tr_thread)
163    return 0
164
165@lldb_type_summary(['struct kqueue *'])
166@header('{: <20s} {: <20s} {: <20s} {: <20s} {: <20s} {: <6s} {: <10s}'.format('kqueue', 'process', 'dynamic_id', 'servicer', 'owner', '#evts', 'state'))
167def GetKqueueSummary(kq):
168    """ Summarize kqueue information
169
170        params:
171            kq - the kqueue object
172        returns: str - summary of kqueue
173    """
174    if int(kq.kq_state) & GetEnumValue('kq_state_t', 'KQ_WORKQ'):
175        return GetKqworkqSummary(kern.GetValueFromAddress(int(kq), 'struct kqworkq *'))
176    elif int(kq.kq_state) & GetEnumValue('kq_state_t', 'KQ_WORKLOOP'):
177        return GetKqworkloopSummary(kern.GetValueFromAddress(int(kq), 'struct kqworkloop *'))
178    else:
179        return GetKqfileSummary(kern.GetValueFromAddress(int(kq), 'struct kqfile *'))
180
181@lldb_type_summary(['struct kqfile *'])
182@header(GetKqueueSummary.header)
183def GetKqfileSummary(kqf):
184    kq = kern.GetValueFromAddress(int(kqf), 'struct kqueue *')
185    state = int(kq.kq_state)
186    return kqueue_summary_fmt.format(
187            o=kq,
188            ptr=int(kq),
189            dyn_id=0,
190            st_str=GetOptionString('kq_state_t', state, 'KQ_'),
191            servicer=0,
192            owner=0)
193
194@lldb_command('showkqfile', fancy=True)
195def ShowKqfile(cmd_args=None, cmd_options={}, O=None):
196    """ Display information about a kqfile object.
197
198        usage: showkqfile <struct kqfile *>
199    """
200    if len(cmd_args) < 1:
201        return O.error('missing struct kqfile * argument')
202
203    kqf = kern.GetValueFromAddress(cmd_args[0], 'kqfile *')
204
205    with O.table(GetKqfileSummary.header):
206        print GetKqfileSummary(kqf)
207    with O.table(GetKnoteSummary.header):
208        for kn in IterateKqueueKnotes(kqf.kqf_kqueue):
209            print GetKnoteSummary(kn)
210        for kn in IterateTAILQ_HEAD(kqf.kqf_suppressed, 'kn_tqe'):
211            print GetKnoteSummary(kn)
212
213@lldb_type_summary(['struct kqworkq *'])
214@header(GetKqueueSummary.header)
215def GetKqworkqSummary(kqwq):
216    """ Summarize workqueue kqueue information
217
218        params:
219            kqwq - the kqworkq object
220        returns: str - summary of workqueue kqueue
221    """
222    return GetKqfileSummary(kern.GetValueFromAddress(int(kqwq), 'struct kqfile *'))
223
224@lldb_command('showkqworkq', fancy=True)
225def ShowKqworkq(cmd_args=None, cmd_options={}, O=None):
226    """ Display summary and knote information about a kqworkq.
227
228        usage: showkqworkq <struct kqworkq *>
229    """
230    if len(cmd_args) < 1:
231        return O.error('missing struct kqworkq * argument')
232
233    kqwq = kern.GetValueFromAddress(cmd_args[0], 'struct kqworkq *')
234    kq = kqwq.kqwq_kqueue
235    with O.table(GetKqueueSummary.header):
236        print GetKqworkqSummary(kqwq)
237
238    with O.table(GetWorkqueueThreadRequestSummary.header):
239        for i in range(0, 7):
240            print GetWorkqueueThreadRequestSummary(kq.kq_p, kqwq.kqwq_request[i])
241
242    with O.table(GetKnoteSummary.header):
243        for kn in IterateKqueueKnotes(kq):
244            print GetKnoteSummary(kn)
245
246@lldb_type_summary(['struct kqworkloop *'])
247@header(GetKqueueSummary.header)
248def GetKqworkloopSummary(kqwl):
249    """ Summarize workloop kqueue information
250
251        params:
252            kqwl - the kqworkloop object
253        returns: str - summary of workloop kqueue
254    """
255    state = int(kqwl.kqwl_kqueue.kq_state)
256    return kqueue_summary_fmt.format(
257            ptr=int(kqwl),
258            o=kqwl.kqwl_kqueue,
259            dyn_id=kqwl.kqwl_dynamicid,
260            st_str=GetOptionString('kq_state_t', state, 'KQ_'),
261            servicer=GetServicer(kqwl.kqwl_request),
262            owner=int(kqwl.kqwl_owner)
263            )
264
265@lldb_command('showkqworkloop', fancy=True)
266def ShowKqworkloop(cmd_args=None, cmd_options={}, O=None):
267    """ Display information about a kqworkloop.
268
269        usage: showkqworkloop <struct kqworkloop *>
270    """
271    if len(cmd_args) < 1:
272        return O.error('missing struct kqworkloop * argument')
273
274    kqwl = kern.GetValueFromAddress(cmd_args[0], 'struct kqworkloop *')
275
276    with O.table(GetKqworkloopSummary.header):
277        print GetKqworkloopSummary(kqwl)
278
279    with O.table(GetWorkqueueThreadRequestSummary.header):
280        print GetWorkqueueThreadRequestSummary(kqwl.kqwl_kqueue.kq_p, kqwl.kqwl_request)
281
282    with O.table(GetKnoteSummary.header):
283        for kn in IterateKqueueKnotes(kqwl.kqwl_kqueue):
284            print GetKnoteSummary(kn)
285
286@lldb_command('showkqueue', fancy=True)
287def ShowKqueue(cmd_args=None, cmd_options={}, O=None):
288    """ Given a struct kqueue pointer, display the summary of the kqueue
289
290        usage: showkqueue <struct kqueue *>
291    """
292    if not cmd_args:
293        return O.error('missing struct kqueue * argument')
294
295    kq = kern.GetValueFromAddress(cmd_args[0], 'struct kqueue *')
296    if int(kq.kq_state) & GetEnumValue('kq_state_t', 'KQ_WORKQ'):
297        ShowKqworkq(cmd_args, cmd_options, O)
298    elif int(kq.kq_state) & GetEnumValue('kq_state_t', 'KQ_WORKLOOP'):
299        ShowKqworkloop(cmd_args, cmd_options, O)
300    else:
301        ShowKqfile(cmd_args, cmd_options, O)
302
303@lldb_command('showprocworkqkqueue', fancy=True)
304def ShowProcWorkqKqueue(cmd_args=None, cmd_options={}, O=None):
305    """ Show the workqueue kqueue for a given process.
306
307        usage: showprocworkqkqueue <proc_t>
308    """
309    if not cmd_args:
310        return O.error('missing struct proc * argument')
311
312    proc = kern.GetValueFromAddress(cmd_args[0], 'proc_t')
313    ShowKqworkq(cmd_args=[str(int(proc.p_fd.fd_wqkqueue))])
314
315@lldb_command('showprockqueues', fancy=True)
316def ShowProcKqueues(cmd_args=None, cmd_options={}, O=None):
317    """ Show the kqueues for a given process.
318
319        usage: showprockqueues <proc_t>
320    """
321    if not cmd_args:
322        return O.error('missing struct proc * argument')
323
324    proc = kern.GetValueFromAddress(cmd_args[0], 'proc_t')
325
326    with O.table(GetKqueueSummary.header):
327        for kq in IterateProcKqueues(proc):
328            print GetKqueueSummary(kq)
329
330@lldb_command('showprocknotes', fancy=True)
331def ShowProcKnotes(cmd_args=None, cmd_options={}, O=None):
332    """ Show the knotes for a given process.
333
334        usage: showprocknotes <proc_t>
335    """
336
337    if not cmd_args:
338        return O.error('missing struct proc * argument')
339
340    proc = kern.GetValueFromAddress(cmd_args[0], 'proc_t')
341
342    with O.table(GetKnoteSummary.header):
343        for kn in IterateProcKnotes(proc):
344            print GetKnoteSummary(kn)
345
346@lldb_command('showallkqueues', fancy=True)
347def ShowAllKqueues(cmd_args=None, cmd_options={}, O=None):
348    """ Display a summary of all the kqueues in the system
349
350        usage: showallkqueues
351    """
352    with O.table(GetKqueueSummary.header):
353        for kq in IterateAllKqueues():
354            print GetKqueueSummary(kq)
355