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