]> git.saurik.com Git - apple/xnu.git/blob - tools/lldbmacros/skywalk.py
xnu-7195.50.7.100.1.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 from net import *
10
11 import xnudefines
12
13 def IterateProcChannels(proc):
14 """ Iterate through all channels in the given process
15
16 params:
17 proc - the proc object
18 returns: nothing, this is meant to be used as a generator function
19 kc - yields each kern_channel in the process
20 """
21
22 proc_filedesc = proc.p_fd
23 proc_lastfile = unsigned(proc_filedesc.fd_lastfile)
24 proc_ofiles = proc_filedesc.fd_ofiles
25
26 count = 0
27 while count <= proc_lastfile:
28 if unsigned(proc_ofiles[count]) != 0:
29 proc_fd_fglob = proc_ofiles[count].fp_glob
30 if (unsigned(proc_fd_fglob.fg_ops.fo_type) == 10):
31 yield Cast(proc_fd_fglob.fg_data, 'kern_channel *')
32 count += 1
33
34 def IterateKernChannelRings(kc, kind):
35 """ Iterate through all rings on a given channel
36 """
37
38 NR_RX = 0
39 NR_TX = 1
40 NR_A = 2
41 NR_F = 3
42
43 if kind == NR_RX:
44 rings = kc.ch_na.na_rx_rings
45 elif kind == NR_TX :
46 rings = kc.ch_na.na_tx_rings
47 elif kind == NR_A :
48 rings = kc.ch_na.na_alloc_rings
49 else :
50 rings = kc.ch_na.na_free_rings
51
52 # note that ch_last is actually one greater than the last
53 # as per the comment in ch_connect
54 for i in xrange(kc.ch_first[kind], kc.ch_last[kind]):
55 yield addressof(rings[i])
56
57 # Note this is broken if you have type summaries enabled
58 # because we are summarizing the pointer to the structure
59 # and not the structure itself. Unfortunately, that's
60 # the pattern used elsewhere.
61 # Trying to actually use the type summary will blow up
62 # because it has a linked list pointer to itself
63 #
64 @lldb_type_summary(['kern_channel_t', 'kern_channel *'])
65 @header('{:<20s} {:<36s}'.format('kern_channel', 'uuid'))
66 def GetKernChannelSummary(kc):
67 """ Summarizes a kern_channel and related information
68
69 returns: str - summary of kern_channel
70 """
71
72 format_string = '{o: <#020x} {u: <36s}'
73 return format_string.format(
74 o=kc,
75 u=GetUUIDSummary(kc.ch_info.cinfo_ch_id))
76
77 @lldb_type_summary(['__kern_channel_ring *'])
78 @header('{:<20s} {:<65s} {:>10s} | {:<5s} {:<5s} | {:<5s} {:<5s} | {:<5s} {:<5s}'.format(
79 'kernchannelring', 'name', 'flags', 'kh', 'kt', 'rh', 'rt', 'h', 't'))
80 def GetKernChannelRingSummary(kring):
81 """ Summarizes a __kern_channel_ring and related information
82
83 returns: str - summary of kern_channel_ring
84 """
85
86 format_string = '{o: <#020x} "{name: <63s}" {flags: >#010x} | {kh: <5d} {kt: <5d} | {rh: <5d} {rt: <5d} | {h: <5d} {t: <5d}'
87 return format_string.format(
88 o=kring,
89 name=kring.ckr_name,
90 flags=kring.ckr_flags,
91 kh=kring.ckr_khead,
92 kt=kring.ckr_ktail,
93 rh=kring.ckr_rhead,
94 rt=kring.ckr_rtail,
95 h=kring.ckr_ring.ring_head,
96 t=kring.ckr_ring.ring_tail)
97
98 @lldb_command('showprocchannels')
99 def ShowProcChannels(cmd_args=None):
100 """ Show the skywalk channels for a given process.
101
102 usage: showprocchannels <proc_t>
103 """
104
105 if not cmd_args:
106 raise ArgumentError('missing struct proc * argument')
107
108 proc = kern.GetValueFromAddress(cmd_args[0], 'proc_t')
109
110 print GetKernChannelSummary.header
111 for kc in IterateProcChannels(proc):
112 print GetKernChannelSummary(kc)
113
114 @lldb_command('showchannelrings')
115 def ShowChannelRings(cmd_args=None):
116 """ Show the skywalk rings for a given channel.
117
118 usage: showchannelrings <struct kern_channel *>
119 """
120
121 if not cmd_args:
122 raise ArgumentError('missing struct kern_channel * argument')
123
124 kc = kern.GetValueFromAddress(cmd_args[0], 'kern_channel *')
125
126 print "RX rings:"
127 print GetKernChannelRingSummary.header
128 for ring in IterateKernChannelRings(kc, 0) :
129 print GetKernChannelRingSummary(ring)
130
131 print "TX rings:"
132 print GetKernChannelRingSummary.header
133 for ring in IterateKernChannelRings(kc, 1) :
134 print GetKernChannelRingSummary(ring)
135
136 print "ALLOC rings:"
137 print GetKernChannelRingSummary.header
138 for ring in IterateKernChannelRings(kc, 2) :
139 print GetKernChannelRingSummary(ring)
140
141 print "FREE rings:"
142 print GetKernChannelRingSummary.header
143 for ring in IterateKernChannelRings(kc, 3) :
144 print GetKernChannelRingSummary(ring)
145
146 def SkmemCacheModeAsString(mode) :
147 out_string = ""
148 SKM_MODE_NOCACHE = 0x1
149 SKM_MODE_AUDIT = 0x2
150
151 if (mode & SKM_MODE_NOCACHE) :
152 out_string += "n"
153 else :
154 out_string += "-"
155 if (mode & SKM_MODE_AUDIT) :
156 out_string += "a"
157 else :
158 out_string += "-"
159
160 return out_string
161
162 @lldb_command('showskmemcache')
163 def ShowSkmemCache(cmd_args=None) :
164 """ Show the global list of skmem caches
165 """
166
167 format_string = "{:<4s} {:<18s} {:<4s} {:<4s} {:<4s} {:<4s} {:<4s} {:<4s} {:<4s} {:<4s} {:<4s} {:<s}"
168 print format_string.format("", "ADDR", "BUFI", "BUFM", "RESC", "SLCR", "SLDE", "SLAL", "SLFR", "DECO", "MODE", "NAME")
169
170 i = 1
171 skmhead = kern.globals.skmem_cache_head
172
173 for skm in IterateTAILQ_HEAD(skmhead, "skm_link") :
174 format_string = "{:>4d}: 0x{:<08x} {:<4d} {:<4d} {:<4d} {:<4d} {:<4d} {:<4d} {:<4d} {:<4d} {:<4s} \"{:<s}\""
175 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))
176 i += 1
177
178 @lldb_command('showskmemslab')
179 def ShowBufCtl(cmd_args=None) :
180 """ Show slabs and bufctls of a skmem cache
181 """
182
183 if (cmd_args == None or len(cmd_args) == 0) :
184 print "Missing argument 0 (skmem_cache address)."
185 return
186
187 skm = kern.GetValueFromAddress(cmd_args[0], 'skmem_cache *')
188
189 for slab in IterateTAILQ_HEAD(skm.skm_sl_partial, "sl_link") :
190 format_string = "{:<08x} {:<4d} 0x{:<08x} 0x{:08x}"
191 print format_string.format(slab, slab.sl_refcnt, slab.sl_base, slab.sl_basem)
192
193 for slab in IterateTAILQ_HEAD(skm.skm_sl_empty, "sl_link") :
194 format_string = "{:<08x} {:<4d} 0x{:<08x} 0x{:08x}"
195 print format_string.format(slab, slab.sl_refcnt, slab.sl_base, slab.sl_basem)
196
197 def SkmemArenaTypeAsString(type) :
198 out_string = ""
199 SKMEM_ARENA_TYPE_NEXUS = 0
200 SKMEM_ARENA_TYPE_NECP = 1
201 SKMEM_ARENA_TYPE_SYSTEM = 2
202
203 if (type == SKMEM_ARENA_TYPE_NEXUS) :
204 out_string += "NEXUS"
205 elif (type == SKMEM_ARENA_TYPE_NECP) :
206 out_string += "NECP"
207 elif (type == SKMEM_ARENA_TYPE_SYSTEM) :
208 out_string += "SYSTEM"
209 else :
210 out_string += "?"
211
212 return out_string
213
214 @lldb_command('showskmemarena')
215 def ShowSkmemArena(cmd_args=None) :
216 """ Show the global list of skmem arenas
217 """
218
219 i = 1
220 arhead = kern.globals.skmem_arena_head
221
222 for ar in IterateTAILQ_HEAD(arhead, "ar_link") :
223 format_string = "{:>4d}: 0x{:<08x} {:<6s} {:>5d} KB \"{:<s}\""
224 print format_string.format(i, ar, SkmemArenaTypeAsString(ar.ar_type), ar.ar_mapsize >> 10, str(ar.ar_name))
225 i += 1
226
227 @lldb_command('showskmemregion')
228 def ShowSkmemRegion(cmd_args=None) :
229 """ Show the global list of skmem regions
230 """
231
232 i = 1
233 skrhead = kern.globals.skmem_region_head
234
235 for skr in IterateTAILQ_HEAD(skrhead, "skr_link") :
236 format_string = "{:>4d}: 0x{:<08x} \"{:<s}\""
237 print format_string.format(i, skr, str(skr.skr_name))
238 i += 1
239
240 @lldb_command('showchannelupphash')
241 def ShowChannelUppHash(cmd_args=None) :
242 """ Show channel user packet pool hash chain
243 """
244
245 if (cmd_args == None or len(cmd_args) == 0) :
246 print "Missing argument 0 (skmem_cache address)."
247 return
248
249 ch = kern.GetValueFromAddress(cmd_args[0], 'kern_channel *')
250 KERN_CHANNEL_UPP_HTBL_SIZE = 256
251
252 for i in range(KERN_CHANNEL_UPP_HTBL_SIZE) :
253 bkt = addressof(ch.ch_upp_hash_table[i])
254 format_string = "{:>4d} 0x{:<08x}"
255 print format_string.format(i, bkt)
256 for kqum in IterateListEntry(bkt.upp_head, 'struct __kern_quantum *',
257 'qum_upp_link', list_prefix='s') :
258 format_string = "0x{:<08x}"
259 print format_string.format(kqum)
260
261 @lldb_type_summary(['struct ns *'])
262 @header('{:<20s} {:<5s} {:<48s} {:<4s}'.format('ns', 'proto', 'addr', 'nreservations'))
263 def GetStructNsSummary(ns):
264 """ Summarizes a struct ns from the netns
265
266 returns: str - summary of struct ns
267 """
268
269 if (ns.ns_proto == IPPROTO_TCP):
270 proto = "tcp"
271 elif (ns.ns_proto == IPPROTO_UDP):
272 proto = "udp"
273 else:
274 proto = str(ns.ns_proto)
275
276 if (ns.ns_addr_len == sizeof('struct in_addr')):
277 addr = GetInAddrAsString(addressof(ns.ns_inaddr))
278 elif (ns.ns_addr_len == sizeof('struct in6_addr')):
279 addr = GetIn6AddrAsString(ns.ns_in6addr.__u6_addr.__u6_addr8)
280 else:
281 addr = str(ns_addr) + " bad len {:u}".format(ns.ns_addr_len)
282
283 format_string = '{o:#020x} {p:<5s} {a:<48s} {n:<4d}'
284
285 """ show ports and refs, one per line
286 """
287 ports_string = "ports & refs\n"
288 for f in IterateRBTreeEntry(ns.ns_reservations, 'struct ns_reservation *', 'nsr_link'):
289 ports_string += "\t%u" % f.nsr_port
290 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])
291 """ show just the ports, not refs
292 offs = 0
293 ports_string = "\nports:\t"
294 for f in IterateRBTreeEntry(ns.ns_reservations, 'struct ns_reservation *', 'nsr_link'):
295 if (len(ports_string)-offs > 70):
296 ports_string += "\n\t"
297 offs = len(ports_string)
298 ports_string += " %u" % f.nsr_port
299 """
300
301 return format_string.format(
302 o=ns,
303 p=proto,
304 a=addr,
305 n=ns.ns_n_reservations) + ports_string
306
307 @lldb_command('shownetns')
308 def ShowNetNS(cmd_args=None):
309 """ Show the netns table
310 """
311 print"\nnetns_namespaces:"
312 print GetStructNsSummary.header
313
314 namespaces = kern.globals.netns_namespaces
315 for ns in IterateRBTreeEntry(namespaces, 'struct ns *', 'ns_link'):
316 print GetStructNsSummary(ns)
317
318 print "\nwild: (these should be duplicated above)"
319 print GetStructNsSummary.header
320 for i in range(0,4):
321 print GetStructNsSummary(kern.globals.netns_global_wild[i])
322
323 print "\nnon wild:"
324 print GetStructNsSummary.header
325 for i in range(0,4):
326 print GetStructNsSummary(kern.globals.netns_global_non_wild[i])
327
328
329 @lldb_type_summary(['struct ns_token *'])
330 @header('{:<20s} {:<5s} {:<48s} {:<12s} {:<8s} {:<38s} {:<38s} {:<12s}'.format('nt', 'proto', 'addr', 'port', 'owner', 'ifp', 'parent', 'flags'))
331 def GetNsTokenSummary(nt):
332 """ Summarizes a struct ns from the netns
333
334 returns: str - summary of struct ns
335 """
336
337 if (nt.nt_proto == IPPROTO_TCP):
338 proto = "tcp"
339 elif (nt.nt_proto == IPPROTO_UDP):
340 proto = "udp"
341 else:
342 proto = str(nt.nt_proto)
343
344 if (nt.nt_addr_len == sizeof('struct in_addr')):
345 addr = GetInAddrAsString(addressof(nt.nt_inaddr))
346 elif (nt.nt_addr_len == sizeof('struct in6_addr')):
347 addr = GetIn6AddrAsString(nt.nt_in6addr.__u6_addr.__u6_addr8)
348 else:
349 addr = str(nt_addr) + " bad len {:u}".format(nt.nt_addr_len)
350
351 format_string = '{o:#020x} {p:<5s} {a:<48s} {pt:<12s} {wn:<8s} {ifp:38s} {pa:38s} {f:#012x}'
352
353 ports = "%u" % nt.nt_port
354
355 ifp = "(struct ifnet *)" + hex(nt.nt_ifp)
356
357 if ((nt.nt_flags & 0x7) == 0x00):
358 owner = "LISTENER"
359 parent = "(void *)" + hex(nt.nt_parent)
360 elif ((nt.nt_flags & 0x7) == 0x01):
361 owner = "SKYWALK"
362 parent = "(struct flow_entry *)" + hex(nt.nt_parent_skywalk)
363 elif ((nt.nt_flags & 0x7) == 0x02): # XXX xnudefines?
364 owner = "BSD"
365 parent = "(struct inpcb *)" + hex(nt.nt_parent_bsd)
366 elif ((nt.nt_flags & 0x7) == 0x03): # XXX xnudefines?
367 owner = "PF"
368 parent = "(void *)" + hex(nt.nt_parent)
369
370 return format_string.format(
371 o=nt,
372 p=proto,
373 a=addr,
374 pt=ports,
375 wn=owner,
376 ifp=ifp,
377 pa=parent,
378 f=nt.nt_flags)
379
380 @lldb_command("showallnetnstokens")
381 def ShowAllNetNSTokens(cmd_args=None):
382 """ show all netns tokens
383 """
384
385 tokenhead = kern.globals.netns_all_tokens
386 print GetNsTokenSummary.header
387 for nt in IterateListEntry(tokenhead, 'struct ns_token *', 'nt_all_link', list_prefix='s'):
388 print GetNsTokenSummary(nt)
389
390 @lldb_command("shownetnstokens")
391 def ShowNetNSTokens(cmd_args=None):
392 """ show netns tokens attached to an ifp
393 with no args, shows unbound tokens
394 """
395
396 if (cmd_args == None or len(cmd_args) == 0):
397 print "No ifp argument provided, showing unbound tokens"
398 tokenhead = kern.globals.netns_unbound_tokens
399 elif len(cmd_args) > 0:
400 ifp = kern.GetValueFromAddress(cmd_args[0], 'ifnet *')
401 print "Showing tokens for ifp %r" % ifp
402 tokenhead = ifp.if_netns_tokens
403 else:
404 print "Missing ifp argument 0 in shownetnstokens"
405 print cmd_args
406 return
407
408 print GetNsTokenSummary.header
409 for nt in IterateListEntry(tokenhead, 'struct ns_token *', 'nt_ifp_link', list_prefix='s'):
410 print GetNsTokenSummary(nt)
411
412 def IterateSTAILQ_HEAD(headval, element_name):
413 iter_val = headval.stqh_first
414 while unsigned(iter_val) != 0 :
415 yield iter_val
416 iter_val = iter_val.__getattr__(element_name).stqe_next
417 #end of yield loop
418
419 @lldb_command("shownexuschannels")
420 def ShowNexusChannels(cmd_args=None):
421 """ show nexus channels
422 """
423 if (cmd_args == None or len(cmd_args) == 0):
424 print "Missing argument 0 (kern_nexus address)."
425 return
426
427 nx = kern.GetValueFromAddress(cmd_args[0], 'kern_nexus *')
428 i = 1
429
430 format_string = "{:>4s} {:<18s} {:>4s} {:<7s} {:<7s} {:<18s} {:<18s} {:<18s} {:>8s} {:6s} {:<18s} {:>4s} {:s}"
431 print format_string.format("", "addr", "refs", "txrings", "rxrings", "arena", "ioskmap", "mapaddr", "mapsize", "maprdr", "na", "fd", "process")
432
433 for ch in IterateSTAILQ_HEAD(nx.nx_ch_head, "ch_link"):
434 format_string = "{:>4d}: 0x{:<08x} {:>4d} [{:2d},{:2d}] [{:2d},{:2d}] 0x{:<08x} 0x{:<08x} 0x{:<16x} {:>8d} {:>6d} 0x{:<08x} {:>4d} {:s}({:d})"
435 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)
436 i += 1
437
438 for ch in IterateSTAILQ_HEAD(nx.nx_ch_nonxref_head, "ch_link"):
439 format_string = "{:>4d}: 0x{:<08x} {:>4d} [{:2d},{:2d}] [{:2d},{:2d}] 0x{:<08x} 0x{:<08x} 0x{:<16x} {:>8d} {:>6d} 0x{:<08x} {:>4d} {:s}({:d})"
440 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)
441 i += 1
442
443 def IterateProcNECP(proc):
444 """ Iterate through all NECP descriptors in the given process
445
446 params:
447 proc - the proc object
448 returns: nothing, this is meant to be used as a generator function
449 necp - yields each necp_fd_data in the process
450 """
451
452 proc_filedesc = proc.p_fd
453 proc_lastfile = unsigned(proc_filedesc.fd_lastfile)
454 proc_ofiles = proc_filedesc.fd_ofiles
455
456 count = 0
457 while count <= proc_lastfile:
458 if unsigned(proc_ofiles[count]) != 0:
459 proc_fd_fglob = proc_ofiles[count].fp_glob
460 if (unsigned(proc_fd_fglob.fg_ops.fo_type) == 9):
461 yield Cast(proc_fd_fglob.fg_data, 'necp_fd_data *')
462 count += 1
463
464 def GetNECPClientBitFields(necp):
465 """ Return the bit fields in necp_client as string
466
467 returns: str - string representation of necp_client bit fields
468 """
469
470 bitfields_string = ''
471 if necp.result_read != 0:
472 bitfields_string += 'r'
473 else:
474 bitfields_string += '-'
475 if necp.allow_multiple_flows != 0:
476 bitfields_string += 'm'
477 else:
478 bitfields_string += '-'
479 if necp.background != 0:
480 bitfields_string += 'b'
481 else:
482 bitfields_string += '-'
483 if necp.background_update != 0:
484 bitfields_string += 'B'
485 else:
486 bitfields_string += '-'
487 if necp.platform_binary != 0:
488 bitfields_string += 'p'
489 else:
490 bitfields_string += '-'
491
492 return bitfields_string
493
494 def GetNECPFlowBitFields(flow_registration):
495 """ Return the bit fields in necp_client_flow_registration as string
496
497 returns: str - string representation of necp_client_flow_registration bit fields
498 """
499
500 bitfields_string = ''
501 if flow_registration.flow_result_read != 0:
502 bitfields_string += 'r'
503 else:
504 bitfields_string += '-'
505 if flow_registration.defunct != 0:
506 bitfields_string += 'd'
507 else:
508 bitfields_string += '-'
509
510 return bitfields_string
511
512 @lldb_type_summary(['necp_fd_data *'])
513 @header('{:<20s} {:<8s}'.format('necp_fd_data', "flags"))
514 def GetNECPSummary(necp):
515 """ Summarizes a necp_fd_data and related information
516
517 returns: str - summary of necp_fd_data
518 """
519
520 format_string = '{o: <#020x} {u:<#08x}'
521
522 stats_arenas_string = "\n\n\t%-18s %-39s %-4s %-10s\n" % ("stats_arenas", "mmap", "refs", "flags")
523 for sa in IterateListEntry(necp.stats_arena_list, 'struct necp_arena_info *', 'nai_chain'):
524 stats_arenas_string += "\t0x%016x " % sa
525 stats_arenas_string += "[0x%016x-0x%016x) " % (sa.nai_mmap.ami_mapaddr,(sa.nai_mmap.ami_mapaddr+sa.nai_mmap.ami_mapsize))
526 stats_arenas_string += "%4u " % sa.nai_use_count
527 stats_arenas_string += "0x%08x " % sa.nai_flags
528 stats_arenas_string += "\n"
529
530 clients_string = ""
531 for c in IterateRBTreeEntry(necp.clients, 'struct necp_client *', 'link'):
532 clients_string += "\n\t%-18s %-36s %-4s %-5s\n" % ("necp_clients", "client_id", "refs", "flags")
533 clients_string += "\t0x%016x " % c
534 clients_string += "%36s " % GetUUIDSummary(c.client_id)
535 clients_string += "%4u " % c.reference_count
536 clients_string += "%5s " % GetNECPClientBitFields(c)
537 count = 0;
538 for f in IterateRBTreeEntry(c.flow_registrations, 'struct necp_client_flow_registration *', 'client_link'):
539 if count == 0:
540 clients_string += "\n\t\t%-18s %-36s %-2s %-18s %-18s %-18s\n" % ("flow_registration", "registraton_id", "flags", "stats_arena", "kstats_obj", "ustats_obj")
541 clients_string += "\t\t0x%016x " % f
542 clients_string += "%36s " % GetUUIDSummary(f.registration_id)
543 clients_string += "%2s " % GetNECPFlowBitFields(f)
544 clients_string += "0x%016x " % f.stats_arena
545 clients_string += "0x%016x " % f.kstats_kaddr
546 clients_string += "0x%016x " % f.ustats_uaddr
547 clients_string += "\n"
548
549 return format_string.format(
550 o=necp,
551 u=necp.flags) + stats_arenas_string + clients_string
552
553 @lldb_command('showprocnecp')
554 def ShowProcNECP(cmd_args=None):
555 """ Show NECP descriptors for a given process.
556
557 usage: showprocnecp <proc_t>
558 """
559
560 if not cmd_args:
561 raise ArgumentError('missing struct proc * argument')
562
563 proc = kern.GetValueFromAddress(cmd_args[0], 'proc_t')
564
565 print GetNECPSummary.header
566 for kc in IterateProcNECP(proc):
567 print GetNECPSummary(kc)
568
569 def NexusTypePtr(nx):
570 if nx.nx_prov.nxprov_params.nxp_type == GetEnumValue("nexus_type_t::NEXUS_TYPE_FLOW_SWITCH"):
571 return "(struct nx_flowswitch *){:18s}".format(hex(nx.nx_arg))
572 elif nx.nx_prov.nxprov_params.nxp_type == GetEnumValue("nexus_type_t::NEXUS_TYPE_NET_IF"):
573 return " (struct nx_netif *){:18s}".format(hex(nx.nx_arg))
574 elif nx.nx_prov.nxprov_params.nxp_type == GetEnumValue("nexus_type_t::NEXUS_TYPE_USER_PIPE"):
575 return " (struct nx_upipe *){:18s}".format(hex(nx.nx_arg))
576 elif nx.nx_prov.nxprov_params.nxp_type == GetEnumValue("nexus_type_t::NEXUS_TYPE_KERNEL_PIPE"):
577 return " (struct kern_nexus *){:18s}".format(hex(nx))
578 else:
579 return "unknown"
580
581 def GetStructNexusSummary(nx):
582 nexus_summary_string = ""
583 nexus_summary_string += "{0:s} ".format(NexusTypePtr(nx))
584 nexus_summary_string += "{0:30s} ".format(str(Cast(addressof(nx.nx_prov.nxprov_params.nxp_name), 'char *')))
585 nexus_summary_string += "rings: tx {:2d} rx {:2d} slots: {:4d} rx {:4d} bufsize {:5d} metasize {:5d} mhints {:2d} ".format(
586 nx.nx_prov.nxprov_params.nxp_tx_rings,
587 nx.nx_prov.nxprov_params.nxp_rx_rings,
588 nx.nx_prov.nxprov_params.nxp_rx_slots,
589 nx.nx_prov.nxprov_params.nxp_tx_slots,
590 nx.nx_prov.nxprov_params.nxp_buf_size,
591 nx.nx_prov.nxprov_params.nxp_meta_size,
592 nx.nx_prov.nxprov_params.nxp_mhints)
593
594 return nexus_summary_string
595
596 @lldb_command('shownexuses')
597 def ShowNexuses(cmd_args=None):
598 """ Show Nexus.
599
600 usage: shownexues
601 """
602 nexus_summaries = []
603 nexuses = kern.globals.nx_head
604 for nx in IterateRBTreeEntry(nexuses, 'struct kern_nexus*', 'nx_link'):
605 nexus_summaries.append(GetStructNexusSummary(nx))
606 nexus_summaries.sort()
607 for nx_str in nexus_summaries:
608 print "{0:s}".format(nx_str)
609
610 def GetSockAddr4(in_addr):
611 return inet_ntoa(struct.pack("!I", in_addr.sin_addr))
612
613 def GetSockAddr6(in6_addr):
614 addr = in6_addr.__u6_addr.__u6_addr8
615 addr_raw_string = ":".join(["{0:02x}{0:02x}".format(unsigned(addr[i]),
616 unsigned(addr[i+1])) for i in range(0, 16, 2)])
617 return inet_ntop(AF_INET6, inet_pton(AF_INET6, addr_raw_string))
618
619 def FlowKeyStr(fk):
620 if fk.fk_ipver == 0x4:
621 src_str = GetSockAddr4(fk.fk_src._v4)
622 dst_str = GetSockAddr4(fk.fk_dst._v4)
623 elif fk.fk_ipver == 0x60:
624 src_str = GetSockAddr6(fk.fk_src._v6)
625 dst_str = GetSockAddr6(fk.fk_dst._v6)
626 else:
627 return "unkown ipver"
628
629 return "src={},dst={},proto={},sport={},dport={}".format(src_str, dst_str,
630 unsigned(fk.fk_proto), ntohs(fk.fk_sport), ntohs(fk.fk_dport))
631
632 def FlowEntryStr(fe):
633 return "(struct flow_entry*){} {} ".format(hex(fe), FlowKeyStr(fe.fe_key))
634
635 def GetFlowEntryPid(fe):
636 return fe.fe_pid
637
638 def GetFlowswitchFlowEntries(fsw):
639 fm = kern.GetValueFromAddress(unsigned(fsw.fsw_flow_mgr), 'struct flow_mgr *')
640 cht = kern.GetValueFromAddress(unsigned(fm.fm_flow_table), 'struct cuckoo_hashtable *')
641
642 flows = []
643 def GetCuckooNodeAsFLowEntry(node, hashValue):
644 fe = containerof(node, 'struct flow_entry', 'fe_cnode')
645 flows.append(fe)
646
647 CuckooHashtableForeach(cht, GetCuckooNodeAsFLowEntry)
648 return flows
649
650 def IsNexusAFlowswitch(nx):
651 return nx.nx_prov.nxprov_params.nxp_type == GetEnumValue('nexus_type_t::NEXUS_TYPE_FLOW_SWITCH')
652
653 def GetNexusAsFlowswitch(nx):
654 return kern.GetValueFromAddress(unsigned(nx.nx_arg), 'struct nx_flowswitch *')
655
656 def FlowswitchStr(fsw):
657 return "{}:\n(struct nx_flowswitch *){}".format(str(fsw.fsw_ifp.if_xname), hex(fsw))
658
659 @lldb_command('showflowswitches')
660 def ShowFlowswitches(cmd_args=None):
661 """ Show flow switches
662
663 usage: showflowswitches [ifname]
664 """
665 ifname = ""
666 if len(cmd_args) == 1:
667 ifname = cmd_args[0]
668
669 nexuses = kern.globals.nx_head
670 for nx in IterateRBTreeEntry(nexuses, 'struct kern_nexus*', 'nx_link'):
671 if not IsNexusAFlowswitch(nx):
672 continue
673 fsw = GetNexusAsFlowswitch(nx)
674 if ifname not in str(fsw.fsw_ifp.if_xname):
675 continue
676 print "{}".format(FlowswitchStr(fsw))
677 flows = GetFlowswitchFlowEntries(fsw)
678 flows.sort(key=GetFlowEntryPid)
679 for fe in flows:
680 print " {}".format(FlowEntryStr(fe))
681
682 def CuckooHashtableForeachSlot(cht, slotHandler):
683 for i in range(0, cht._n_buckets):
684 b = cht._buckets[i]
685 if unsigned(b._inuse) == 0:
686 continue
687 for j in range(0, kern.globals._CHT_BUCKET_SLOTS):
688 s = b._slots[j]
689 if unsigned(s._node) != 0:
690 slotHandler(s)
691
692 def CuckooHashtableForeach(cht, handler):
693 def CuckooHashtableSlotHandler(s):
694 if unsigned(s._node) == 0:
695 return
696 node = s._node
697 while unsigned(node) != 0:
698 handler(node, s._hash)
699 node = node.next
700 CuckooHashtableForeachSlot(cht, CuckooHashtableSlotHandler)
701
702 @lldb_command('showcuckoohashtable')
703 def ShowCuckooHashtable(cmd_args=None):
704 """ Show Cuckoo Hashtable.
705
706 usage: showcuckoohashtable <struct cuckoo_hashtable *>
707 """
708 if not cmd_args:
709 raise ArgumentError('missing struct cuckoo_hashtable * argument')
710
711 cht = kern.GetValueFromAddress(cmd_args[0], 'struct cuckoo_hashtable *')
712
713 print "(struct cuckoo_hashtable *){:18s} capacity {:d} entries {:d}".format(hex(cht), cht._capacity, cht._n_entries)
714 def CuckooHashtablePrintNode(node, hashValue):
715 print " node {} hash 0x{:08x}".format(hex(node), int(hashValue))
716
717 CuckooHashtableForeach(cht, CuckooHashtablePrintNode)
718
719 @lldb_command('showprotons')
720 def ShowProtoNS(cmd_args=None):
721 """ Show the protons table
722 """
723
724 protons_tokens = kern.globals.protons_tokens
725 for pt in IterateRBTreeEntry(protons_tokens, 'struct protons_token *', 'pt_link'):
726 print "(struct protons_token *){} protocol {:3} pid {:5} epid {:5} ref {:2} flags {}".format(
727 hex(pt), int(pt.pt_protocol), int(pt.pt_pid), int(pt.pt_epid),
728 int(pt.pt_refcnt.ref_count), hex(pt.pt_flags))