Commit 55d75ca8 authored by Vicent Marti's avatar Vicent Marti

lua: Use the new native Symbol resolver

The static `BPF.SymbolCache` now uses a native symbol resolver instead
of the Lua/binutils implementation. Likewise for the kernel symbol
resolver, and the `check_path_symbol` API to find a probe's hook
address.
parent 664249b7
......@@ -139,12 +139,12 @@ return function(BPF, utils)
bpf:attach_kprobe{event="kfree", fn_name="free_enter"}
end
local syms = args.pid and utils.sym.ProcSymbols:new(args.pid) or utils.sym.KSymbols:new()
local syms = BPF.SymbolCache(args.pid)
local allocs = bpf:get_table("allocs")
local stack_traces = bpf:get_table("stack_traces")
local function resolve(addr)
local sym = syms:lookup(addr)
local sym = syms:resolve(addr)
if args.pid == nil then
sym = sym .. " [kernel]"
end
......
......@@ -79,7 +79,7 @@ return function(BPF, utils)
parser:option("-d --duration", "duration to trace for", 9999999):convert(tonumber)
local args = parser:parse()
local ksym = utils.sym.KSymbols:new()
local ksym = BPF.SymbolCache()
local filter = "1"
local MAXDEPTH = 20
......@@ -107,7 +107,7 @@ return function(BPF, utils)
for k, v in counts:items() do
for addr in stack_traces:walk(tonumber(k.stack_id)) do
print(" %-16p %s" % {addr, ksym:lookup(addr)})
print(" %-16p %s" % {addr, ksym:resolve(addr)})
end
print(" %-16s %s" % {"-", ffi.string(k.name)})
print(" %d\n" % tonumber(v))
......
......@@ -18,13 +18,12 @@ local libbcc = require("bcc.libbcc")
local TracerPipe = require("bcc.tracerpipe")
local Table = require("bcc.table")
local LD = require("bcc.ld")
local Sym = require("bcc.sym")
local Bpf = class("BPF")
Bpf.static.open_kprobes = {}
Bpf.static.open_uprobes = {}
Bpf.static.process_symbols = {}
Bpf.static.KPROBE_LIMIT = 1000
Bpf.static.tracer_pipe = nil
Bpf.static.DEFAULT_CFLAGS = {
......@@ -63,6 +62,10 @@ function Bpf.static.cleanup_probes()
end
end
function Bpf.static.SymbolCache(pid)
return Sym.create_cache(pid)
end
function Bpf.static.num_open_uprobes()
return table.count(Bpf.static.open_uprobes)
end
......@@ -71,19 +74,6 @@ function Bpf.static.num_open_kprobes()
return table.count(Bpf.static.open_kprobes)
end
function Bpf.static.usymaddr(pid, addr, refresh)
local proc_sym = Bpf.static.process_symbols[pid]
if proc_sym == nil then
proc_sym = ProcSymbols(pid)
Bpf.static.process_symbols[pid] = proc_sym
elseif refresh then
proc_sym.refresh()
end
return proc_sym.decode_addr(addr)
end
Bpf.static.SCRIPT_ROOT = "./"
function Bpf.static.script_root(root)
local dir, file = root:match'(.*/)(.*)'
......@@ -185,7 +175,7 @@ end
function Bpf:attach_uprobe(args)
Bpf.check_probe_quota(1)
local path, addr = LD.check_path_symbol(args.name, args.sym, args.addr)
local path, addr = Sym.check_path_symbol(args.name, args.sym, args.addr)
local fn = self:load_func(args.fn_name, 'BPF_PROG_TYPE_KPROBE')
local ptype = args.retprobe and "r" or "p"
local ev_name = string.format("%s_%s_0x%p", ptype, path:gsub("[^%a%d]", "_"), addr)
......
......@@ -13,166 +13,34 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
]]
local posix = require("bcc.vendor.posix")
local ProcSymbols = class("ProcSymbols")
function ProcSymbols:initialize(pid)
self.pid = pid
self:refresh()
end
function ProcSymbols:_get_exe()
return os.spawn("readlink -f /proc/%d/exe", self.pid)
end
function ProcSymbols:_get_start_time()
return tonumber(os.spawn("cut -d' ' -f 22 /proc/%d/stat", self.pid))
end
function ProcSymbols:_get_code_ranges()
local function is_binary_segment(parts)
if #parts ~= 6 then return false end
if parts[6]:starts("[") then return false end
if parts[2]:find("x") == nil then return false end
return true
end
local ranges = {}
local cmd = string.format("/proc/%d/maps", self.pid)
for line in io.lines(cmd) do
local parts = line:split()
if is_binary_segment(parts) then
local binary = parts[6]
local range = parts[1]:split("-", true)
assert(#range == 2)
ranges[binary] = {posix.tonumber64(range[1], 16), posix.tonumber64(range[2], 16)}
end
end
return ranges
end
function ProcSymbols:refresh()
self.code_ranges = self:_get_code_ranges()
self.ranges_cache = {}
self.exe = self:_get_exe()
self.start_time = self:_get_start_time()
end
function ProcSymbols:_check_pid_wrap()
local new_exe = self:_get_exe()
local new_time = self:_get_start_time()
if self.exe ~= new_exe or self.start_time ~= new_time then
self:refresh()
end
end
function ProcSymbols:_get_sym_ranges(binary)
if self.ranges_cache[binary] ~= nil then
return self.ranges_cache[binary]
end
local function is_function_sym(parts)
return #parts == 6 and parts[4] == ".text" and parts[3] == "F"
end
local sym_ranges = {}
local proc = assert(io.popen("objdump -t "..binary))
for line in proc:lines() do
local parts = line:split()
if is_function_sym(parts) then
local sym_start = posix.tonumber64(parts[1], 16)
local sym_len = posix.tonumber64(parts[5], 16)
local sym_name = parts[6]
sym_ranges[sym_name] = {sym_start, sym_len}
end
end
proc:close()
self.ranges_cache[binary] = sym_ranges
return sym_ranges
end
function ProcSymbols:_decode_sym(binary, offset)
local sym_ranges = self:_get_sym_ranges(binary)
for name, range in pairs(sym_ranges) do
local start = range[1]
local length = range[2]
if offset >= start and offset <= (start + length) then
return string.format("%s+0x%p", name, offset - start)
local ffi = require("ffi")
local libbcc = require("bcc.libbcc")
local SYM = ffi.typeof("struct bcc_symbol[1]")
local function create_cache(pid)
return {
_CACHE = libbcc.bcc_symcache_new(pid or -1),
resolve = function(self, addr)
local sym = SYM()
if libbcc.bcc_symcache_resolve(self._CACHE, addr, sym) < 0 then
return "[unknown]", 0x0
end
return ffi.string(sym[0].name), sym[0].offset
end
end
return string.format("%p", offset)
}
end
function ProcSymbols:lookup(addr)
self:_check_pid_wrap()
for binary, range in pairs(self.code_ranges) do
local start = range[1]
local tend = range[2]
if addr >= start and addr <= tend then
local offset = binary:ends(".so") and (addr - start) or addr
return string.format("%s [%s]", self:_decode_sym(binary, offset), binary)
local function check_path_symbol(module, symname, addr)
local sym = SYM()
if libbcc.bcc_resolve_symname(module, symname, addr or 0x0, sym) < 0 then
if sym[0].module == nil then
error("could not find library '%s' in the library path" % module)
else
error("failed to resolve symbol '%s' in '%s'" % {
symname, ffi.string(sym[0].module)})
end
end
return string.format("%p", addr)
end
local KSymbols = class("KSymbols")
KSymbols.static.KALLSYMS = "/proc/kallsyms"
function KSymbols:initialize()
self.ksyms = {}
self.ksym_names = {}
self.loaded = false
end
function KSymbols:_load()
if self.loaded then return end
local first_line = true
for line in io.lines(KSymbols.KALLSYMS) do
if not first_line then
local cols = line:split()
local name = cols[3]
local addr = posix.tonumber64(cols[1], 16)
table.insert(self.ksyms, {name, addr})
self.ksym_names[name] = #self.ksyms
end
first_line = false
end
self.loaded = true
end
function KSymbols:_addr2index(addr)
self:_load()
return table.bsearch(self.ksyms, addr, function(v) return v[2] end)
end
function KSymbols:lookup(addr, with_offset)
local idx = self:_addr2index(addr)
if idx == nil then
return "[unknown]"
end
if with_offset then
local offset = addr - self.ksyms[idx][2]
return "%s %p" % {self.ksyms[idx][1], offset}
else
return self.ksyms[idx][1]
end
end
function KSymbols:refresh()
-- NOOP
return ffi.string(sym[0].module), sym[0].offset
end
return { ProcSymbols=ProcSymbols, KSymbols=KSymbols }
return { create_cache=create_cache, check_path_symbol=check_path_symbol }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment