xref: /xnu-10002.61.3/tools/lldbmacros/ntstat.py (revision 0f4c859e951fba394238ab619495c4e1d54d0f34)
1""" Please make sure you read the README COMPLETELY BEFORE reading anything below.
2    It is very critical that you read coding guidelines in Section E in README file.
3"""
4from __future__ import absolute_import, print_function
5
6from builtins import hex
7from xnu import *
8from utils import *
9from string import *
10from socket import *
11from enum import IntEnum
12
13import xnudefines
14from netdefines import *
15from routedefines import *
16
17######################################
18# Globals
19######################################
20""" Refer to in bsd/net/ntstat.c
21"""
22NSTAT_PROCDETAILS_MAGIC = 0xfeedc001
23NSTAT_GENERIC_SHADOW_MAGIC = 0xfadef00d
24TU_SHADOW_MAGIC = 0xfeedf00d
25""" Refer to nstat_provider_type_t in bsd/net/ntstat.h
26"""
27class NSTAT_PROVIDER(IntEnum):
28    NONE = 0
29    ROUTE = 1
30    TCP_KERNEL = 2
31    TCP_USERLAND = 3
32    UDP_KERNEL = 4
33    UDP_USERLAND = 5
34    IFNET = 6
35    SYSINFO = 7
36    QUIC_USERLAND = 8
37    CONN_USERLAND = 9
38    UDP_SUBFLOW = 10
39
40######################################
41# Helper functions
42######################################
43def ReverseIterateTAILQ_AnonymousHEAD(headval, field_name, element_type):
44    """ reverse iterate over a TAILQ_HEAD in kernel. refer to bsd/sys/queue.h
45    params:
46        headval         - value : value object representing the head of the list
47        field_name      - str   : string name of the field which holds the list links.
48        element_type    - str   : type of elements to be linked in the list
49    returns:
50        A generator does not return. It is used for iterating.
51        value : an object that is of type as headval->tqh_last. Always a pointer object
52    example usage:
53        list_head = kern.GetGlobalVariable('ctl_head')
54        for entry in ReverseIterateTAILQ_AnonymousHEAD(list_head, 'next', 'struct kctl *'):
55            print(entry)
56    """
57    head_first = headval.__getattr__('tqh_first')
58    head_first_addr = addressof(head_first)
59    iter_val = headval.__getattr__('tqh_last')
60    while (unsigned(iter_val) != unsigned(head_first_addr)) and (unsigned(iter_val) != 0) :
61        yield iter_val
62        element = Cast(iter_val, element_type)
63        iter_val = element.__getattr__(field_name).__getattr__('tqe_prev')
64    #end of yield loop
65
66def ShowNstatTUShadow(inshadow):
67    """ Display summary for an nstat_tu_shadow struct
68        params:
69            inshadow : cvalue object which points to 'struct nstat_tu_shadow *'
70    """
71    shad = Cast(inshadow, 'struct nstat_tu_shadow *')
72    procdetails = shad.shad_procdetails
73    out_string = ""
74    if shad :
75        format_string = "nstat_tu_shadow {0: <#0x}: next={1: <#020x} prev={2: <#020x} context (necp_client *)={3: <#020x} live={4: <d}"
76        out_string += format_string.format(shad, shad.shad_link.tqe_next, shad.shad_link.tqe_prev, shad.shad_provider_context, shad.shad_live)
77
78        magic = unsigned(shad.shad_magic)
79        if (magic != TU_SHADOW_MAGIC) :
80            format_string = " INVALID shad magic {0: <#0x}"
81            out_string += format_string.format(magic)
82
83        if (procdetails) :
84            format_string = "  --> procdetails {0: <#0x}: pid={1: <d} name={2: <s} refcnt={3: <d}"
85            out_string += format_string.format(procdetails, procdetails.pdet_pid, procdetails.pdet_procname, procdetails.pdet_refcnt)
86
87            procmagic = unsigned(procdetails.pdet_magic)
88            if (procmagic != NSTAT_PROCDETAILS_MAGIC) :
89                format_string = " INVALID proc magic {0: <#0x}"
90                out_string += format_string.format(procmagic)
91
92    print(out_string)
93
94def ShowNstatGShadow(inshadow):
95    """ Display summary for an nstat_generic_shadow
96        params:
97            inshadow : cvalue object which points to 'struct nstat_generic_shadow *'
98    """
99    gshad = Cast(inshadow, 'struct nstat_generic_shadow *')
100    procdetails = gshad.gshad_procdetails
101    out_string = ""
102    if gshad :
103        prov_string = GetNstatProviderString(gshad.gshad_provider)
104        format_string = "nstat_generic_shadow {0: <#0x}: prov={1: <8s} next={2: <#020x} prev={3: <#020x} refcnt={4: <d} "
105        out_string += format_string.format(gshad, prov_string, gshad.gshad_link.tqe_next, gshad.gshad_link.tqe_prev, gshad.gshad_refcnt)
106
107        ## context
108        if (gshad.gshad_provider == NSTAT_PROVIDER.CONN_USERLAND) :
109            out_string += "context (necp_client *)={0: <#020x} ".format(gshad.gshad_provider_context)
110        elif (gshad.gshad_provider == NSTAT_PROVIDER.UDP_SUBFLOW) :
111            out_string += "context (soflow_hash_entry *)={0: <#020x} ".format(gshad.gshad_provider_context)
112
113        magic = unsigned(gshad.gshad_magic)
114        if (magic != NSTAT_GENERIC_SHADOW_MAGIC) :
115            format_string = " INVALID gshad magic {0: <#0x}"
116            out_string += format_string.format(magic)
117
118        if (procdetails) :
119            format_string = " --> procdetails {0: <#0x}: pid={1: <d} name={2: <s} refcnt={3: <d}"
120            out_string += format_string.format(procdetails, procdetails.pdet_pid, procdetails.pdet_procname, procdetails.pdet_refcnt)
121
122            procmagic = unsigned(procdetails.pdet_magic)
123            if (procmagic != NSTAT_PROCDETAILS_MAGIC) :
124                format_string = " INVALID proc magic {0: <#0x}"
125                out_string += format_string.format(procmagic)
126
127    print(out_string)
128
129def GetNstatProcdetailsBrief(procdetails):
130    """ Display a brief summary for an nstat_procdetails struct
131        params:
132            procdetails : cvalue object which points to 'struct nstat_procdetails *'
133        returns:
134            str : A string describing various information for the nstat_procdetails structure
135    """
136    procdetails = Cast(procdetails, 'struct nstat_procdetails *')
137    out_string = ""
138    if (procdetails) :
139        format_string = " --> pid={0: <d} name={1: <s} refcnt={2: <d}"
140        out_string += format_string.format(procdetails.pdet_pid, procdetails.pdet_procname, procdetails.pdet_refcnt)
141
142        procmagic = unsigned(procdetails.pdet_magic)
143        if (procmagic != NSTAT_PROCDETAILS_MAGIC) :
144            format_string = " INVALID proc magic {0: <#0x}"
145            out_string += format_string.format(procmagic)
146
147    return out_string
148
149def ShowNstatProcdetails(procdetails):
150    """ Display a summary for an nstat_procdetails struct
151        params:
152            procdetails : cvalue object which points to 'struct nstat_procdetails *'
153    """
154    procdetails = Cast(procdetails, 'struct nstat_procdetails *')
155    out_string = ""
156    if (procdetails) :
157        format_string = "nstat_procdetails: {0: <#020x} next={1: <#020x} prev={2: <#020x} "
158        out_string += format_string.format(procdetails, procdetails.pdet_link.tqe_next, procdetails.pdet_link.tqe_prev)
159        out_string += GetNstatProcdetailsBrief(procdetails)
160
161    print(out_string)
162
163def GetNstatTUShadowBrief(shadow):
164    """ Display a summary for an nstat_tu_shadow struct
165        params:
166            shadow : cvalue object which points to 'struct nstat_tu_shadow *'
167        returns:
168            str : A string describing various information for the nstat_tu_shadow structure
169    """
170    out_string = ""
171    shad = Cast(shadow, 'struct nstat_tu_shadow *')
172    procdetails = shad.shad_procdetails
173    procdetails = Cast(procdetails, 'struct nstat_procdetails *')
174    out_string = ""
175    if shad :
176        format_string = " shadow {0: <#0x}: necp_client={1: <#020x} live={2: <d}"
177        out_string += format_string.format(shad, shad.shad_provider_context, shad.shad_live)
178        magic = unsigned(shad.shad_magic)
179        if (magic != TU_SHADOW_MAGIC) :
180            format_string = " INVALID shad magic {0: <#0x}"
181            out_string += format_string.format(magic)
182        elif (procdetails) :
183            out_string += GetNstatProcdetailsBrief(procdetails)
184
185    return out_string
186
187def GetNstatGenericShadowBrief(shadow):
188    """ Display a summary for an nstat_generic_shadow struct
189        params:
190            shadow : cvalue object which points to 'struct nstat_generic_shadow *'
191        returns:
192            str : A string describing various information for the nstat_tu_shadow structure
193    """
194    gshad = Cast(shadow, 'struct nstat_generic_shadow *')
195    procdetails = gshad.gshad_procdetails
196    procdetails = Cast(procdetails, 'struct nstat_procdetails *')
197    out_string = ""
198    if gshad :
199        format_string = " gshadow {0: <#0x}:"
200        out_string += format_string.format(gshad)
201        if (gshad.gshad_provider == NSTAT_PROVIDER.CONN_USERLAND) :
202            out_string += "necp_client={0: <#020x} ".format(gshad.gshad_provider_context)
203        elif (gshad.gshad_provider == NSTAT_PROVIDER.UDP_SUBFLOW) :
204            out_string += "soflow_hash_entry={0: <#020x} ".format(gshad.gshad_provider_context)
205        else :
206            out_string += "context {0: <#020x} ".format(gshad.gshad_provider_context)
207        out_string += " refcnt={0: <d} ".format(gshad.gshad_refcnt)
208
209        magic = unsigned(gshad.gshad_magic)
210        if (magic != NSTAT_GENERIC_SHADOW_MAGIC) :
211            format_string = " INVALID gshad magic {0: <#0x}"
212            out_string += format_string.format(magic)
213        elif (procdetails) :
214            out_string += GetNstatProcdetailsBrief(procdetails)
215
216    return out_string
217
218def GetNstatTUCookieBrief(cookie):
219    """ Display a summary for an nstat_tucookie struct
220        params:
221            shadow : cvalue object which points to 'struct nstat_tucookie *'
222        returns:
223            str : A string describing various information for the nstat_tucookie structure
224    """
225    out_string = ""
226    tucookie = Cast(cookie, 'struct nstat_tucookie *')
227    inp = tucookie.inp
228    pname = tucookie.pname
229    inpcb = Cast(inp, 'struct inpcb *')
230    inp_socket = inpcb.inp_socket
231    sock = Cast(inp_socket, 'struct socket *')
232    format_string = " inpcb={0: <#0x}: socket={1: <#020x} process={2: <s}"
233    out_string += format_string.format(inpcb, sock, pname)
234    return out_string
235
236def GetNstatProviderString(provider):
237    providers = {
238        NSTAT_PROVIDER.NONE: "none",
239        NSTAT_PROVIDER.ROUTE: "route",
240        NSTAT_PROVIDER.TCP_KERNEL: "TCP k",
241        NSTAT_PROVIDER.TCP_USERLAND: "TCP u",
242        NSTAT_PROVIDER.UDP_KERNEL: "UDP k",
243        NSTAT_PROVIDER.UDP_USERLAND: "UDP u",
244        NSTAT_PROVIDER.IFNET: "ifnet",
245        NSTAT_PROVIDER.SYSINFO: "sysinfo",
246        NSTAT_PROVIDER.QUIC_USERLAND: "quic u",
247        NSTAT_PROVIDER.CONN_USERLAND: "conn u",
248        NSTAT_PROVIDER.UDP_SUBFLOW: "subflow",
249    }
250    return providers.get(unsigned(provider), "unknown")
251
252def ShowNstatSrc(insrc):
253    """ Display summary for an nstat_src struct
254        params:
255            insrc : cvalue object which points to 'struct nstat_src *'
256    """
257    src = Cast(insrc, 'nstat_src *')
258    prov = src.provider
259    prov = Cast(prov, 'nstat_provider *')
260    prov_string = GetNstatProviderString(prov.nstat_provider_id)
261    out_string = ""
262    if src :
263        format_string = "  nstat_src {0: <#0x}: prov={1: <8s} next={2: <#020x} prev={3: <#020x} srcref={4: <d}"
264        out_string += format_string.format(src, prov_string, src.ns_control_link.tqe_next, src.ns_control_link.tqe_prev, src.srcref)
265
266        if ((prov.nstat_provider_id == NSTAT_PROVIDER.TCP_USERLAND) or
267            (prov.nstat_provider_id == NSTAT_PROVIDER.UDP_USERLAND) or
268            (prov.nstat_provider_id == NSTAT_PROVIDER.QUIC_USERLAND)) :
269            out_string += GetNstatTUShadowBrief(src.cookie);
270        elif ((prov.nstat_provider_id == NSTAT_PROVIDER.CONN_USERLAND) or
271            (prov.nstat_provider_id == NSTAT_PROVIDER.UDP_SUBFLOW)) :
272            out_string += GetNstatGenericShadowBrief(src.cookie);
273        elif ((prov.nstat_provider_id == NSTAT_PROVIDER.TCP_KERNEL) or
274            (prov.nstat_provider_id == NSTAT_PROVIDER.UDP_KERNEL)) :
275            out_string += GetNstatTUCookieBrief(src.cookie);
276
277    print(out_string)
278
279def ShowNstatCtrl(inctrl):
280    """ Display an nstat_control_state struct
281        params:
282            ctrl : value object representing an nstat_control_state in the kernel
283    """
284    ctrl = Cast(inctrl, 'nstat_control_state *')
285    out_string = ""
286    if ctrl :
287        format_string = "nstat_control_state {0: <#0x}: next={1: <#020x} src-head={2: <#020x} tail={3: <#020x}"
288        out_string += format_string.format(ctrl, ctrl.ncs_next, ctrl.ncs_src_queue.tqh_first, ctrl.ncs_src_queue.tqh_last)
289        procdetails = ctrl.ncs_procdetails
290        if (procdetails) :
291            format_string = "  --> procdetails {0: <#0x}: pid={1: <d} name={2: <s} refcnt={3: <d}"
292            out_string += format_string.format(procdetails, procdetails.pdet_pid, procdetails.pdet_procname, procdetails.pdet_refcnt)
293
294    print(out_string)
295
296    for src in IterateTAILQ_HEAD(ctrl.ncs_src_queue, 'ns_control_link'):
297        ShowNstatSrc(src)
298
299######################################
300# Print functions
301######################################
302def PrintNstatControlList():
303    print("nstat_controls list:\n")
304    ctrl = kern.globals.nstat_controls
305    ctrl = cast(ctrl, 'nstat_control_state *')
306    while ctrl != 0:
307        ShowNstatCtrl(ctrl)
308        ctrl = cast(ctrl.ncs_next, 'nstat_control_state *')
309
310def PrintNstatProcdetailList(reverse):
311    procdetails_head = kern.globals.nstat_procdetails_head
312    if reverse:
313        print("\nreverse nstat_procdetails list:\n")
314        iterator = ReverseIterateTAILQ_AnonymousHEAD(procdetails_head, 'pdet_link', 'struct nstat_procdetails *')
315    else:
316        print("\nnstat_procdetails list:\n")
317        iterator = IterateTAILQ_HEAD(procdetails_head, 'pdet_link')
318    for procdetails in iterator:
319        ShowNstatProcdetails(procdetails)
320
321def PrintNstatGenericShadowList(reverse):
322    gshadows = kern.globals.nstat_gshad_head
323    if reverse:
324        print("\nreverse nstat_ghsad list:\n")
325        iterator = ReverseIterateTAILQ_AnonymousHEAD(gshadows, 'gshad_link', 'struct nstat_generic_shadow *')
326    else:
327        print("\nnstat_ghsad list:\n")
328        iterator = IterateTAILQ_HEAD(gshadows, 'gshad_link')
329    for gshad in iterator:
330        ShowNstatGShadow(gshad)
331
332def PrintNstatTUShadowList(reverse):
333    shadows = kern.globals.nstat_userprot_shad_head
334    if reverse:
335        print("\nreverse nstat_userprot_shad list:\n")
336        iterator = ReverseIterateTAILQ_AnonymousHEAD(shadows, 'shad_link', 'struct nstat_tu_shadow *')
337    else:
338        print("\nnstat_userprot_shad list:\n")
339        iterator = IterateTAILQ_HEAD(shadows, 'shad_link')
340    for shad in iterator:
341        ShowNstatTUShadow(shad)
342
343######################################
344# LLDB commands
345######################################
346# Macro: showallntstat
347
348@lldb_command('showallntstat', 'R')
349def ShowAllNtstat(cmd_args=None, cmd_options={}) :
350    """ Show the contents of various ntstat (network statistics) data structures
351
352        usage: showallntstat [-R]
353            -R  : print ntstat list in reverse
354    """
355    reverse = '-R' in cmd_options
356
357    PrintNstatControlList()
358    PrintNstatTUShadowList(reverse)
359    PrintNstatGenericShadowList(reverse)
360    PrintNstatProcdetailList(reverse)
361
362# EndMacro: showallntstat
363