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