]> git.saurik.com Git - apple/xnu.git/blob - tools/lldbmacros/skywalk.py
xnu-4903.270.47.tar.gz
[apple/xnu.git] / tools / lldbmacros / skywalk.py
1
2 """ Please make sure you read the README COMPLETELY BEFORE reading anything below.
3 It is very critical that you read coding guidelines in Section E in README file.
4 """
5
6 from xnu import *
7 from utils import *
8 from string import *
9
10 import xnudefines
11
12 def IterateProcChannels(proc):
13 """ Iterate through all channels in the given process
14
15 params:
16 proc - the proc object
17 returns: nothing, this is meant to be used as a generator function
18 kc - yields each kern_channel in the process
19 """
20
21 proc_filedesc = proc.p_fd
22 proc_lastfile = unsigned(proc_filedesc.fd_lastfile)
23 proc_ofiles = proc_filedesc.fd_ofiles
24
25 count = 0
26 while count <= proc_lastfile:
27 if unsigned(proc_ofiles[count]) != 0:
28 proc_fd_fglob = proc_ofiles[count].f_fglob
29 if (unsigned(proc_fd_fglob.fg_ops.fo_type) == 10):
30 yield Cast(proc_fd_fglob.fg_data, 'kern_channel *')
31 count += 1
32
33 def IterateKernChannelRings(kc, kind):
34 """ Iterate through all rings on a given channel
35 """
36
37 NR_RX = 0
38 NR_TX = 1
39 NR_A = 2
40 NR_F = 3
41
42 if kind == NR_RX:
43 rings = kc.ch_na.na_rx_rings
44 elif kind == NR_TX :
45 rings = kc.ch_na.na_tx_rings
46 elif kind == NR_A :
47 rings = kc.ch_na.na_alloc_rings
48 else :
49 rings = kc.ch_na.na_free_rings
50
51 # note that ch_last is actually one greater than the last
52 # as per the comment in ch_connect
53 for i in xrange(kc.ch_first[kind], kc.ch_last[kind]):
54 yield addressof(rings[i])
55
56 # Note this is broken if you have type summaries enabled
57 # because we are summarizing the pointer to the structure
58 # and not the structure itself. Unfortunately, that's
59 # the pattern used elsewhere.
60 # Trying to actually use the type summary will blow up
61 # because it has a linked list pointer to itself
62 #
63 @lldb_type_summary(['kern_channel_t', 'kern_channel *'])
64 @header('{:<20s} {:<36s}'.format('kern_channel', 'uuid'))
65 def GetKernChannelSummary(kc):
66 """ Summarizes a kern_channel and related information
67
68 returns: str - summary of kern_channel
69 """
70
71 format_string = '{o: <#020x} {u: <36s}'
72 return format_string.format(
73 o=kc,
74 u=GetUUIDSummary(kc.ch_info.cinfo_ch_id))
75
76 @lldb_type_summary(['__kern_channel_ring *'])
77 @header('{:<20s} {:<65s} {:>10s} | {:<5s} {:<5s} | {:<5s} {:<5s} {:<5s} | {:<5s} {:<5s} {:<5s}'.format(
78 'kernchannelring', 'name', 'flags', 'kc', 'kt', 'rc', 'rh', 'rt', 'c', 'h', 't'))
79 def GetKernChannelRingSummary(kring):
80 """ Summarizes a __kern_channel_ring and related information
81
82 returns: str - summary of kern_channel_ring
83 """
84
85 format_string = '{o: <#020x} "{name: <63s}" {flags: >#010x} | {kh: <5d} {kt: <5d} | {rh: <5d} {rt: <5d} | {h: <5d} {t: <5d}'
86 return format_string.format(
87 o=kring,
88 name=kring.ckr_name,
89 flags=kring.ckr_flags,
90 kh=kring.ckr_khead,
91 kt=kring.ckr_ktail,
92 rh=kring.ckr_rhead,
93 rt=kring.ckr_rtail,
94 h=kring.ckr_ring.ring_head,
95 t=kring.ckr_ring.ring_tail)
96
97 @lldb_command('showprocchannels')
98 def ShowProcChannels(cmd_args=None):
99 """ Show the skywalk channels for a given process.
100
101 usage: showprocchannels <proc_t>
102 """
103
104 if not cmd_args:
105 raise ArgumentError('missing struct proc * argument')
106
107 proc = kern.GetValueFromAddress(cmd_args[0], 'proc_t')
108
109 print GetKernChannelSummary.header
110 for kc in IterateProcChannels(proc):
111 print GetKernChannelSummary(kc)
112
113 @lldb_command('showchannelrings')
114 def ShowChannelRings(cmd_args=None):
115 """ Show the skywalk rings for a given channel.
116
117 usage: showchannelrings <struct kern_channel *>
118 """
119
120 if not cmd_args:
121 raise ArgumentError('missing struct kern_channel * argument')
122
123 kc = kern.GetValueFromAddress(cmd_args[0], 'kern_channel *')
124
125 print "RX rings:"
126 print GetKernChannelRingSummary.header
127 for ring in IterateKernChannelRings(kc, 0) :
128 print GetKernChannelRingSummary(ring)
129
130 print "TX rings:"
131 print GetKernChannelRingSummary.header
132 for ring in IterateKernChannelRings(kc, 1) :
133 print GetKernChannelRingSummary(ring)
134
135 print "ALLOC rings:"
136 print GetKernChannelRingSummary.header
137 for ring in IterateKernChannelRings(kc, 2) :
138 print GetKernChannelRingSummary(ring)
139
140 print "FREE rings:"
141 print GetKernChannelRingSummary.header
142 for ring in IterateKernChannelRings(kc, 3) :
143 print GetKernChannelRingSummary(ring)
144
145 def SkmemCacheModeAsString(mode) :
146 out_string = ""
147 SKM_MODE_NOCACHE = 0x1
148 SKM_MODE_AUDIT = 0x2
149
150 if (mode & SKM_MODE_NOCACHE) :
151 out_string += "n"
152 else :
153 out_string += "-"
154 if (mode & SKM_MODE_AUDIT) :
155 out_string += "a"
156 else :
157 out_string += "-"
158
159 return out_string
160
161 @lldb_command('showskmemcache')
162 def ShowSkmemCache(cmd_args=None) :
163 """ Show the global list of skmem caches
164 """
165
166 format_string = "{:<4s} {:<18s} {:<4s} {:<4s} {:<4s} {:<4s} {:<4s} {:<4s} {:<4s} {:<4s} {:<4s} {:<s}"
167 print format_string.format("", "ADDR", "BUFI", "BUFM", "RESC", "SLCR", "SLDE", "SLAL", "SLFR", "DECO", "MODE", "NAME")
168
169 i = 1
170 skmhead = kern.globals.skmem_cache_head
171
172 for skm in IterateTAILQ_HEAD(skmhead, "skm_link") :
173 format_string = "{:>4d}: 0x{:<08x} {:<4d} {:<4d} {:<4d} {:<4d} {:<4d} {:<4d} {:<4d} {:<4d} {:<4s} \"{:<s}\""
174 print format_string.format(i, skm, skm.skm_bufinuse, skm.skm_bufmax, skm.skm_rescale, skm.skm_sl_create, skm.skm_sl_destroy, skm.skm_sl_alloc, skm.skm_sl_free, skm.skm_depot_contention, SkmemCacheModeAsString(skm.skm_mode), str(skm.skm_name))
175 i += 1
176
177 @lldb_command('showskmemslab')
178 def ShowBufCtl(cmd_args=None) :
179 """ Show slabs and bufctls of a skmem cache
180 """
181
182 if (cmd_args == None or len(cmd_args) == 0) :
183 print "Missing argument 0 (skmem_cache address)."
184 return
185
186 skm = kern.GetValueFromAddress(cmd_args[0], 'skmem_cache *')
187
188 for slab in IterateTAILQ_HEAD(skm.skm_sl_partial, "sl_link") :
189 format_string = "{:<08x} {:<4d} 0x{:<08x} 0x{:08x}"
190 print format_string.format(slab, slab.sl_refcnt, slab.sl_base, slab.sl_basem)
191
192 for slab in IterateTAILQ_HEAD(skm.skm_sl_empty, "sl_link") :
193 format_string = "{:<08x} {:<4d} 0x{:<08x} 0x{:08x}"
194 print format_string.format(slab, slab.sl_refcnt, slab.sl_base, slab.sl_basem)
195
196 def SkmemArenaTypeAsString(type) :
197 out_string = ""
198 SKMEM_ARENA_TYPE_NEXUS = 0
199 SKMEM_ARENA_TYPE_NECP = 1
200 SKMEM_ARENA_TYPE_SYSTEM = 2
201
202 if (type == SKMEM_ARENA_TYPE_NEXUS) :
203 out_string += "NEXUS"
204 elif (type == SKMEM_ARENA_TYPE_NECP) :
205 out_string += "NECP"
206 elif (type == SKMEM_ARENA_TYPE_SYSTEM) :
207 out_string += "SYSTEM"
208 else :
209 out_string += "?"
210
211 return out_string
212
213 @lldb_command('showskmemarena')
214 def ShowSkmemArena(cmd_args=None) :
215 """ Show the global list of skmem arenas
216 """
217
218 i = 1
219 arhead = kern.globals.skmem_arena_head
220
221 for ar in IterateTAILQ_HEAD(arhead, "ar_link") :
222 format_string = "{:>4d}: 0x{:<08x} {:<6s} {:>5d} KB \"{:<s}\""
223 print format_string.format(i, ar, SkmemArenaTypeAsString(ar.ar_type), ar.ar_mapsize >> 10, str(ar.ar_name))
224 i += 1
225
226 @lldb_command('showskmemregion')
227 def ShowSkmemRegion(cmd_args=None) :
228 """ Show the global list of skmem regions
229 """
230
231 i = 1
232 skrhead = kern.globals.skmem_region_head
233
234 for skr in IterateTAILQ_HEAD(skrhead, "skr_link") :
235 format_string = "{:>4d}: 0x{:<08x} \"{:<s}\""
236 print format_string.format(i, skr, str(skr.skr_name))
237 i += 1
238
239 @lldb_command('showchannelupphash')
240 def ShowChannelUppHash(cmd_args=None) :
241 """ Show channel user packet pool hash chain
242 """
243
244 if (cmd_args == None or len(cmd_args) == 0) :
245 print "Missing argument 0 (skmem_cache address)."
246 return
247
248 ch = kern.GetValueFromAddress(cmd_args[0], 'kern_channel *')
249 KERN_CHANNEL_UPP_HTBL_SIZE = 256
250
251 for i in range(KERN_CHANNEL_UPP_HTBL_SIZE) :
252 bkt = addressof(ch.ch_upp_hash_table[i])
253 format_string = "{:>4d} 0x{:<08x}"
254 print format_string.format(i, bkt)
255 for kqum in IterateListEntry(bkt.upp_head, 'struct __kern_quantum *',
256 'qum_upp_link', list_prefix='s') :
257 format_string = "0x{:<08x}"
258 print format_string.format(kqum)
259
260 @lldb_type_summary(['struct ns *'])
261 @header('{:<20s} {:<5s} {:<48s} {:<4s}'.format('ns', 'proto', 'addr', 'nreservations'))
262 def GetStructNsSummary(ns):
263 """ Summarizes a struct ns from the netns
264
265 returns: str - summary of struct ns
266 """
267
268 if (ns.ns_proto == IPPROTO_TCP):
269 proto = "tcp"
270 elif (ns.ns_proto == IPPROTO_UDP):
271 proto = "udp"
272 else:
273 proto = str(ns.ns_proto)
274
275 if (ns.ns_addr_len == sizeof('struct in_addr')):
276 addr = GetInAddrAsString(addressof(ns.ns_inaddr))
277 elif (ns.ns_addr_len == sizeof('struct in6_addr')):
278 addr = GetIn6AddrAsString(ns.ns_in6addr.__u6_addr.__u6_addr8)
279 else:
280 addr = str(ns_addr) + " bad len {:u}".format(ns.ns_addr_len)
281
282 format_string = '{o:#020x} {p:<5s} {a:<48s} {n:<4d}'
283
284 """ show ports and refs, one per line
285 """
286 ports_string = "ports & refs\n"
287 for f in IterateRBTreeEntry(ns.ns_reservations, 'struct ns_reservation *', 'nsr_link'):
288 ports_string += "\t%u" % f.nsr_port
289 ports_string += "\tlisten %d\tskywalk %d\tbsd %d\tpf %d\n" % (f.nsr_refs[0], f.nsr_refs[1], f.nsr_refs[2], f.nsr_refs[3])
290 """ show just the ports, not refs
291 offs = 0
292 ports_string = "\nports:\t"
293 for f in IterateRBTreeEntry(ns.ns_reservations, 'struct ns_reservation *', 'nsr_link'):
294 if (len(ports_string)-offs > 70):
295 ports_string += "\n\t"
296 offs = len(ports_string)
297 ports_string += " %u" % f.nsr_port
298 """
299
300 return format_string.format(
301 o=ns,
302 p=proto,
303 a=addr,
304 n=ns.ns_n_reservations) + ports_string
305
306 @lldb_command('shownetns')
307 def ShowNetNS(cmd_args=None):
308 """ Show the netns table
309 """
310 print"\nnetns_namespaces:"
311 print GetStructNsSummary.header
312
313 namespaces = kern.globals.netns_namespaces
314 for ns in IterateRBTreeEntry(namespaces, 'struct ns *', 'ns_link'):
315 print GetStructNsSummary(ns)
316
317 print "\nwild: (these should be duplicated above)"
318 print GetStructNsSummary.header
319 for i in range(0,4):
320 print GetStructNsSummary(kern.globals.netns_global_wild[i])
321
322 print "\nnon wild:"
323 print GetStructNsSummary.header
324 for i in range(0,4):
325 print GetStructNsSummary(kern.globals.netns_global_non_wild[i])
326
327
328 @lldb_type_summary(['struct ns_token *'])
329 @header('{:<20s} {:<5s} {:<48s} {:<12s} {:<8s} {:<38s} {:<38s} {:<12s}'.format('nt', 'proto', 'addr', 'port', 'owner', 'ifp', 'parent', 'flags'))
330 def GetNsTokenSummary(nt):
331 """ Summarizes a struct ns from the netns
332
333 returns: str - summary of struct ns
334 """
335
336 if (nt.nt_proto == IPPROTO_TCP):
337 proto = "tcp"
338 elif (nt.nt_proto == IPPROTO_UDP):
339 proto = "udp"
340 else:
341 proto = str(nt.nt_proto)
342
343 if (nt.nt_addr_len == sizeof('struct in_addr')):
344 addr = GetInAddrAsString(addressof(nt.nt_inaddr))
345 elif (nt.nt_addr_len == sizeof('struct in6_addr')):
346 addr = GetIn6AddrAsString(nt.nt_in6addr.__u6_addr.__u6_addr8)
347 else:
348 addr = str(nt_addr) + " bad len {:u}".format(nt.nt_addr_len)
349
350 format_string = '{o:#020x} {p:<5s} {a:<48s} {pt:<12s} {wn:<8s} {ifp:38s} {pa:38s} {f:#012x}'
351
352 ports = "%u" % nt.nt_port
353
354 ifp = "(struct ifnet *)" + hex(nt.nt_ifp)
355
356 if ((nt.nt_flags & 0x7) == 0x00):
357 owner = "LISTENER"
358 parent = "(void *)" + hex(nt.nt_parent)
359 elif ((nt.nt_flags & 0x7) == 0x01):
360 owner = "SKYWALK"
361 parent = "(struct flow_entry *)" + hex(nt.nt_parent_skywalk)
362 elif ((nt.nt_flags & 0x7) == 0x02): # XXX xnudefines?
363 owner = "BSD"
364 parent = "(struct inpcb *)" + hex(nt.nt_parent_bsd)
365 elif ((nt.nt_flags & 0x7) == 0x03): # XXX xnudefines?
366 owner = "PF"
367 parent = "(void *)" + hex(nt.nt_parent)
368
369 return format_string.format(
370 o=nt,
371 p=proto,
372 a=addr,
373 pt=ports,
374 wn=owner,
375 ifp=ifp,
376 pa=parent,
377 f=nt.nt_flags)
378
379 @lldb_command("showallnetnstokens")
380 def ShowAllNetNSTokens(cmd_args=None):
381 """ show all netns tokens
382 """
383
384 tokenhead = kern.globals.netns_all_tokens
385 print GetNsTokenSummary.header
386 for nt in IterateListEntry(tokenhead, 'struct ns_token *', 'nt_all_link', list_prefix='s'):
387 print GetNsTokenSummary(nt)
388
389 @lldb_command("shownetnstokens")
390 def ShowNetNSTokens(cmd_args=None):
391 """ show netns tokens attached to an ifp
392 with no args, shows unbound tokens
393 """
394
395 if (cmd_args == None or len(cmd_args) == 0):
396 print "No ifp argument provided, showing unbound tokens"
397 tokenhead = kern.globals.netns_unbound_tokens
398 elif len(cmd_args) > 0:
399 ifp = kern.GetValueFromAddress(cmd_args[0], 'ifnet *')
400 print "Showing tokens for ifp %r" % ifp
401 tokenhead = ifp.if_netns_tokens
402 else:
403 print "Missing ifp argument 0 in shownetnstokens"
404 print cmd_args
405 return
406
407 print GetNsTokenSummary.header
408 for nt in IterateListEntry(tokenhead, 'struct ns_token *', 'nt_ifp_link', list_prefix='s'):
409 print GetNsTokenSummary(nt)
410
411 def IterateSTAILQ_HEAD(headval, element_name):
412 iter_val = headval.stqh_first
413 while unsigned(iter_val) != 0 :
414 yield iter_val
415 iter_val = iter_val.__getattr__(element_name).stqe_next
416 #end of yield loop
417
418 @lldb_command("shownexuschannels")
419 def ShowNexusChannels(cmd_args=None):
420 """ show nexus channels
421 """
422 if (cmd_args == None or len(cmd_args) == 0):
423 print "Missing argument 0 (kern_nexus address)."
424 return
425
426 nx = kern.GetValueFromAddress(cmd_args[0], 'kern_nexus *')
427 i = 1
428
429 format_string = "{:>4s} {:<18s} {:>4s} {:<7s} {:<7s} {:<18s} {:<18s} {:<18s} {:>8s} {:6s} {:<18s} {:>4s} {:s}"
430 print format_string.format("", "addr", "refs", "txrings", "rxrings", "arena", "ioskmap", "mapaddr", "mapsize", "maprdr", "na", "fd", "process")
431
432 for ch in IterateSTAILQ_HEAD(nx.nx_ch_head, "ch_link"):
433 format_string = "{:>4d}: 0x{:<08x} {:>4d} [{:2d},{:2d}] [{:2d},{:2d}] 0x{:<08x} 0x{:<08x} 0x{:<16x} {:>8d} {:>6d} 0x{:<08x} {:>4d} {:s}({:d})"
434 print format_string.format(i, ch, ch.ch_refcnt, ch.ch_first[0], ch.ch_last[0], ch.ch_first[1], ch.ch_last[1], ch.ch_mmap.ami_arena, ch.ch_mmap.ami_mapref, ch.ch_mmap.ami_mapaddr, ch.ch_mmap.ami_mapsize, ch.ch_mmap.ami_redirect, ch.ch_na, ch.ch_fd, ch.ch_name, ch.ch_pid)
435 i += 1
436
437 for ch in IterateSTAILQ_HEAD(nx.nx_ch_nonxref_head, "ch_link"):
438 format_string = "{:>4d}: 0x{:<08x} {:>4d} [{:2d},{:2d}] [{:2d},{:2d}] 0x{:<08x} 0x{:<08x} 0x{:<16x} {:>8d} {:>6d} 0x{:<08x} {:>4d} {:s}({:d})"
439 print format_string.format(i, ch, ch.ch_refcnt, ch.ch_first[0], ch.ch_last[0], ch.ch_first[1], ch.ch_last[1], ch.ch_mmap.ami_arena, ch.ch_mmap.ami_mapref, ch.ch_mmap.ami_mapaddr, ch.ch_mmap.ami_mapsize, ch.ch_mmap.ami_redirect, ch.ch_na, ch.ch_fd, ch.ch_name, ch.ch_pid)
440 i += 1
441
442 def IterateProcNECP(proc):
443 """ Iterate through all NECP descriptors in the given process
444
445 params:
446 proc - the proc object
447 returns: nothing, this is meant to be used as a generator function
448 necp - yields each necp_fd_data in the process
449 """
450
451 proc_filedesc = proc.p_fd
452 proc_lastfile = unsigned(proc_filedesc.fd_lastfile)
453 proc_ofiles = proc_filedesc.fd_ofiles
454
455 count = 0
456 while count <= proc_lastfile:
457 if unsigned(proc_ofiles[count]) != 0:
458 proc_fd_fglob = proc_ofiles[count].f_fglob
459 if (unsigned(proc_fd_fglob.fg_ops.fo_type) == 9):
460 yield Cast(proc_fd_fglob.fg_data, 'necp_fd_data *')
461 count += 1
462
463 def GetNECPClientBitFields(necp):
464 """ Return the bit fields in necp_client as string
465
466 returns: str - string representation of necp_client bit fields
467 """
468
469 bitfields_string = ''
470 if necp.result_read != 0:
471 bitfields_string += 'r'
472 else:
473 bitfields_string += '-'
474 if necp.allow_multiple_flows != 0:
475 bitfields_string += 'm'
476 else:
477 bitfields_string += '-'
478 if necp.background != 0:
479 bitfields_string += 'b'
480 else:
481 bitfields_string += '-'
482 if necp.background_update != 0:
483 bitfields_string += 'B'
484 else:
485 bitfields_string += '-'
486 if necp.platform_binary != 0:
487 bitfields_string += 'p'
488 else:
489 bitfields_string += '-'
490
491 return bitfields_string
492
493 def GetNECPFlowBitFields(flow_registration):
494 """ Return the bit fields in necp_client_flow_registration as string
495
496 returns: str - string representation of necp_client_flow_registration bit fields
497 """
498
499 bitfields_string = ''
500 if flow_registration.flow_result_read != 0:
501 bitfields_string += 'r'
502 else:
503 bitfields_string += '-'
504 if flow_registration.defunct != 0:
505 bitfields_string += 'd'
506 else:
507 bitfields_string += '-'
508
509 return bitfields_string
510
511 @lldb_type_summary(['necp_fd_data *'])
512 @header('{:<20s} {:<8s}'.format('necp_fd_data', "flags"))
513 def GetNECPSummary(necp):
514 """ Summarizes a necp_fd_data and related information
515
516 returns: str - summary of necp_fd_data
517 """
518
519 format_string = '{o: <#020x} {u:<#08x}'
520
521 stats_arenas_string = "\n\n\t%-18s %-39s %-4s %-10s\n" % ("stats_arenas", "mmap", "refs", "flags")
522 for sa in IterateListEntry(necp.stats_arena_list, 'struct necp_arena_info *', 'nai_chain'):
523 stats_arenas_string += "\t0x%016x " % sa
524 stats_arenas_string += "[0x%016x-0x%016x) " % (sa.nai_mmap.ami_mapaddr,(sa.nai_mmap.ami_mapaddr+sa.nai_mmap.ami_mapsize))
525 stats_arenas_string += "%4u " % sa.nai_use_count
526 stats_arenas_string += "0x%08x " % sa.nai_flags
527 stats_arenas_string += "\n"
528
529 clients_string = ""
530 for c in IterateRBTreeEntry(necp.clients, 'struct necp_client *', 'link'):
531 clients_string += "\n\t%-18s %-36s %-4s %-5s\n" % ("necp_clients", "client_id", "refs", "flags")
532 clients_string += "\t0x%016x " % c
533 clients_string += "%36s " % GetUUIDSummary(c.client_id)
534 clients_string += "%4u " % c.reference_count
535 clients_string += "%5s " % GetNECPClientBitFields(c)
536 count = 0;
537 for f in IterateRBTreeEntry(c.flow_registrations, 'struct necp_client_flow_registration *', 'client_link'):
538 if count == 0:
539 clients_string += "\n\t\t%-18s %-36s %-2s %-18s %-18s %-18s\n" % ("flow_registration", "registraton_id", "flags", "stats_arena", "kstats_obj", "ustats_obj")
540 clients_string += "\t\t0x%016x " % f
541 clients_string += "%36s " % GetUUIDSummary(f.registration_id)
542 clients_string += "%2s " % GetNECPFlowBitFields(f)
543 clients_string += "0x%016x " % f.stats_arena
544 clients_string += "0x%016x " % f.kstats_kaddr
545 clients_string += "0x%016x " % f.ustats_uaddr
546 clients_string += "\n"
547
548 return format_string.format(
549 o=necp,
550 u=necp.flags) + stats_arenas_string + clients_string
551
552 @lldb_command('showprocnecp')
553 def ShowProcNECP(cmd_args=None):
554 """ Show NECP descriptors for a given process.
555
556 usage: showprocnecp <proc_t>
557 """
558
559 if not cmd_args:
560 raise ArgumentError('missing struct proc * argument')
561
562 proc = kern.GetValueFromAddress(cmd_args[0], 'proc_t')
563
564 print GetNECPSummary.header
565 for kc in IterateProcNECP(proc):
566 print GetNECPSummary(kc)