diff --git a/tools/lldb/netinet.lua b/tools/lldb/netinet.lua new file mode 100644 --- /dev/null +++ b/tools/lldb/netinet.lua @@ -0,0 +1,103 @@ +-- +-- SPDX-License-Identifier: BSD-2-Clause +-- +-- Copyright (c) 2024 The FreeBSD Foundation +-- +-- This software was developed by Tom Jones under +-- sponsorship from the FreeBSD Foundation. +-- + +local netinet = {} + +-- +-- Accessing vnet members takes the form: +-- (struct inpcbinfo*)((((struct vnet *) vnet0 )->vnet_data_base) + +-- (uintptr_t )&vnet_entry_tcbinfo) +-- While we could feed this directly to EvaluateExpression (as we do with gdb), +-- but lldb offers us a better form for constructing the final value. +-- +-- We are expecting the full vnet member name, i.e. vnet_entry_tcbinfo +-- and an output type, i.e. struct pcbinfo * +-- +function netinet.vnet_get_member(self, vnet, value) + local db = vnet:GetChildMemberWithName("vnet_data_base") + local v = lldb.target:FindFirstGlobalVariable(value) + :AddressOf() + return db:GetValueAsUnsigned() + v:GetValueAsUnsigned() +end + +function netinet.vnet_get_member_and_cast(self, vnet, value, outtype) + local db = vnet:GetChildMemberWithName("vnet_data_base") + local mb = lldb.target:FindFirstGlobalVariable(value) + :AddressOf() + local addr = db:GetValueAsUnsigned() + mb:GetValueAsUnsigned() + + return lldb.frame:EvaluateExpression("(" .. outtype .. ") " .. addr) +end + +-- +-- Take a V_xxx member and look it up in curvnet, i.e. go from V_tcpinfo to +-- vnet_entry_tcbinfo then get it from the current vnet. +function netinet.vnet_get_V_value(self, value, vnet) + -- if value starts with V_ it is virtualised + local basevar = value:match("V_(.+)") + if not basevar then + print("vnet_get_V_value: Requires a value name starting with V_, given: " .. value) + return nil + end + + local vimage = lldb.target: + FindFirstGlobalVariable("sysctl___kern_features_vimage") ~= nil + + if not vimage then + return lldb.target:FindFirstGlobalVariable(value) + end + + if vnet == nil then + print("vnet_get_V_value: vnet is nil and this is a vimage kernel") + return nil + end + + value = "vnet_entry_" .. value + return netinet:vnet_get_member(vnet, value) +end + +function netinet.vnet_iter(self) + local vnet = nil + return function () + if vnet == nil then + vnet = lldb.target:FindFirstGlobalVariable("vnet0") + return vnet + else + vnet = vnet:GetChildMemberWithName("vnet_le") + :GetChildMemberWithName("le_next") + + if vnet:GetValueAsUnsigned() == 0x0 then + return nil + else + return vnet + end + end + end +end + +function netinet.inpcb_iter(self, inpcbinfo) + local inp = nil + return function () + if inp == nil then + inp = inpcbinfo:GetChildMemberWithName("ipi_listhead") + :GetChildMemberWithName("clh_first") + return inp + else + inp = inp :GetChildMemberWithName("inp_list") + :GetChildMemberWithName("cle_next") + if inp:GetValueAsUnsigned() == 0x0 then + return nil + else + return inp + end + end + end +end + +return netinet