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,134 @@ +-- +-- SPDX-License-Identifier: BSD-2-Clause +-- +-- Copyright (c) 2024 Tom Jones +-- All rights reserved. +-- +-- Redistribution and use in source and binary forms, with or without +-- modification, are permitted provided that the following conditions +-- are met: +-- 1. Redistributions of source code must retain the above copyright +-- notice, this list of conditions and the following disclaimer. +-- 2. Redistributions in binary form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +-- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +-- SUCH DAMAGE. +-- + +local netinet = {} + +-- Module exports +-- Commonly appearing constants +-- + +-- +-- 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) + db = vnet:GetChildMemberWithName("vnet_data_base") + v = lldb.target:FindFirstGlobalVariable(value) + :AddressOf() + return db:GetValueAsUnsigned() + v:GetValueAsUnsigned() +end + +function netinet.vnet_get_member_and_cast(self, vnet, value, outtype) + db = vnet:GetChildMemberWithName("vnet_data_base") + mb = lldb.target:FindFirstGlobalVariable(value) + :AddressOf() + 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 + if value:sub(1, 2, "V_") == "V_" + then + value = value:sub(3, -1, "V_") + else + print("vnet_get_V_value: Requires a value name starting with V_, given: " .. value) + return nil + end + + 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