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