]>
Commit | Line | Data |
---|---|---|
d9a64523 A |
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 * | |
cb323159 | 9 | from net import * |
d9a64523 A |
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: | |
f427ee49 | 29 | proc_fd_fglob = proc_ofiles[count].fp_glob |
d9a64523 A |
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 *']) | |
f427ee49 A |
78 | @header('{:<20s} {:<65s} {:>10s} | {:<5s} {:<5s} | {:<5s} {:<5s} | {:<5s} {:<5s}'.format( |
79 | 'kernchannelring', 'name', 'flags', 'kh', 'kt', 'rh', 'rt', 'h', 't')) | |
d9a64523 A |
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: | |
f427ee49 | 459 | proc_fd_fglob = proc_ofiles[count].fp_glob |
d9a64523 A |
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) | |
cb323159 A |
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 | ||
f427ee49 A |
610 | def GetSockAddr4(in_addr): |
611 | return inet_ntoa(struct.pack("!I", in_addr.sin_addr)) | |
cb323159 | 612 | |
f427ee49 A |
613 | def GetSockAddr6(in6_addr): |
614 | addr = in6_addr.__u6_addr.__u6_addr8 | |
cb323159 A |
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 | ||
f427ee49 A |
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) | |
cb323159 | 626 | else: |
f427ee49 A |
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)) | |
cb323159 A |
631 | |
632 | def FlowEntryStr(fe): | |
f427ee49 | 633 | return "(struct flow_entry*){} {} ".format(hex(fe), FlowKeyStr(fe.fe_key)) |
cb323159 A |
634 | |
635 | def GetFlowEntryPid(fe): | |
f427ee49 | 636 | return fe.fe_pid |
cb323159 A |
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)) |