#!/usr/bin/env bcc-lua --[[ Copyright 2016 Marek Vavrusa Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 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. ]] -- Trace operations on keys matching given pattern in KyotoTycoon daemon. -- This can show you if certain keys were modified or read during the lifetime -- even if KT doesn't support this. It also shows how to attach to C++ mangled symbols. local ffi = require('ffi') local bpf = require('bpf') local S = require('syscall') local function help(err) print(string.format('%s [get|set] [key]', arg[0])) if err then print('error: '..err) end os.exit(1) end -- Accept the same format as ktremotemgr for clarity: local writeable, watch_key, klen = 'any', arg[2] or '*', 80 if arg[1] == 'get' then writeable = 0 elseif arg[1] == 'set' then writeable = 1 elseif arg[1] == '-h' or arg[1] == '--help' then help() elseif arg[1] and arg[1] ~= 'any' then help(string.format('bad cmd: "%s"', arg[1])) end if watch_key ~= '*' then klen = #watch_key end -- Find a good entrypoint that has both key and differentiates read/write in KT -- That is going to serve as an attachment point for BPF program -- ABI: bool accept(void *this, const char* kbuf, size_t ksiz, Visitor* visitor, bool writable) local key_type = string.format('char [%d]', klen) local probe = bpf.uprobe('/usr/local/bin/ktserver:kyotocabinet::StashDB::accept', function (ptregs) -- Watch either get/set or both if writeable ~= 'any' then if ptregs.parm5 ~= writeable then return end end local line = ffi.new(key_type) ffi.copy(line, ffi.cast('char *', ptregs.parm2)) -- Check if we're looking for specific key if watch_key ~= '*' then if ptregs.parm3 ~= klen then return false end if line ~= watch_key then return false end end print('%s write:%d\n', line, ptregs.parm5) end, false, -1, 0) -- User-space part of the program local ok, err = pcall(function() local log = bpf.tracelog() print(' TASK-PID CPU# TIMESTAMP FUNCTION') print(' | | | | |') while true do print(log:read()) end end)