1*699cd480SApple OSS Distributions#!/usr/local/bin/recon 2*699cd480SApple OSS Distributionslocal CoreSymbolication = require 'CoreSymbolication' 3*699cd480SApple OSS Distributionslocal argparse = require 'argparse' 4*699cd480SApple OSS Distributionslocal kperf = require 'kperf' 5*699cd480SApple OSS Distributionslocal ktrace = require 'ktrace' 6*699cd480SApple OSS Distributionslocal strict = require 'strict' 7*699cd480SApple OSS Distributions 8*699cd480SApple OSS Distributions 9*699cd480SApple OSS Distributionslocal ksancov = {} 10*699cd480SApple OSS Distributions 11*699cd480SApple OSS Distributions-- KCOV event 12*699cd480SApple OSS Distributions 13*699cd480SApple OSS Distributionsksancov.Event = {} 14*699cd480SApple OSS Distributionsksancov.Event.__index = ksancov.Event 15*699cd480SApple OSS Distributions 16*699cd480SApple OSS Distributionsfunction ksancov.Event.new() 17*699cd480SApple OSS Distributions local instance = { 18*699cd480SApple OSS Distributions pid = nil, 19*699cd480SApple OSS Distributions procname = nil, 20*699cd480SApple OSS Distributions tid = nil, 21*699cd480SApple OSS Distributions stack_size = nil, 22*699cd480SApple OSS Distributions pc = nil, 23*699cd480SApple OSS Distributions duration = nil, 24*699cd480SApple OSS Distributions ustack = nil, 25*699cd480SApple OSS Distributions kstack = nil, 26*699cd480SApple OSS Distributions } 27*699cd480SApple OSS Distributions 28*699cd480SApple OSS Distributions return setmetatable(instance, ksancov.Event) 29*699cd480SApple OSS Distributionsend 30*699cd480SApple OSS Distributions 31*699cd480SApple OSS Distributionsfunction ksancov.Event:print() 32*699cd480SApple OSS Distributions print(string.format("%s(%d)\t%d\t at %x has stack size %d.", self.procname, self.pid, self.tid, 33*699cd480SApple OSS Distributions self.pc, self.stack_size)) 34*699cd480SApple OSS Distributionsend 35*699cd480SApple OSS Distributions 36*699cd480SApple OSS Distributions-- KSANCOV tracing session 37*699cd480SApple OSS Distributions 38*699cd480SApple OSS Distributionsksancov.Session = {} 39*699cd480SApple OSS Distributionsksancov.Session.__index = ksancov.Session 40*699cd480SApple OSS Distributions 41*699cd480SApple OSS Distributionsfunction ksancov.Session.new(ktrace_session, flags) 42*699cd480SApple OSS Distributions assert(ktrace_session) 43*699cd480SApple OSS Distributions 44*699cd480SApple OSS Distributions local instance = { 45*699cd480SApple OSS Distributions ktrace_session = ktrace_session, 46*699cd480SApple OSS Distributions kperf_session = kperf.Session.new(ktrace_session), 47*699cd480SApple OSS Distributions events_by_tid = {}, 48*699cd480SApple OSS Distributions event_handlers = {}, 49*699cd480SApple OSS Distributions } 50*699cd480SApple OSS Distributions 51*699cd480SApple OSS Distributions local self = setmetatable(instance, ksancov.Session) 52*699cd480SApple OSS Distributions self:_register_kperf_callbacks(flags.ustack, flags.kstack) 53*699cd480SApple OSS Distributions self:_register_ktrace_callbacks(flags.proc) 54*699cd480SApple OSS Distributions return self 55*699cd480SApple OSS Distributionsend 56*699cd480SApple OSS Distributions 57*699cd480SApple OSS Distributionsfunction ksancov.Session:start() 58*699cd480SApple OSS Distributions return self.ktrace_session:start() 59*699cd480SApple OSS Distributionsend 60*699cd480SApple OSS Distributions 61*699cd480SApple OSS Distributionsfunction ksancov.Session:_register_kperf_callbacks(ustack, kstack) 62*699cd480SApple OSS Distributions local samplers = {} 63*699cd480SApple OSS Distributions if kstack then 64*699cd480SApple OSS Distributions table.insert(samplers, 'kstack') 65*699cd480SApple OSS Distributions end 66*699cd480SApple OSS Distributions 67*699cd480SApple OSS Distributions if ustack then 68*699cd480SApple OSS Distributions table.insert(samplers, 'ustack') 69*699cd480SApple OSS Distributions end 70*699cd480SApple OSS Distributions 71*699cd480SApple OSS Distributions -- D0x01ad0000 KCOV_THRESHOLD_ABOVE 72*699cd480SApple OSS Distributions if #samplers == 0 then 73*699cd480SApple OSS Distributions return 74*699cd480SApple OSS Distributions end 75*699cd480SApple OSS Distributions 76*699cd480SApple OSS Distributions self.kperf_session:add_kdebug_sampler({'D0x01ad0000'}, samplers) 77*699cd480SApple OSS Distributions 78*699cd480SApple OSS Distributions -- Collect userspace stacks 79*699cd480SApple OSS Distributions if ustack then 80*699cd480SApple OSS Distributions self.kperf_session:add_callback_sample({'ustack'}, function (sample) 81*699cd480SApple OSS Distributions local event = self.events_by_tid[sample.threadid] 82*699cd480SApple OSS Distributions if event then 83*699cd480SApple OSS Distributions event.ustack = sample.ustack 84*699cd480SApple OSS Distributions end 85*699cd480SApple OSS Distributions end) 86*699cd480SApple OSS Distributions end 87*699cd480SApple OSS Distributions 88*699cd480SApple OSS Distributions -- Collect kernel stacks 89*699cd480SApple OSS Distributions if kstack then 90*699cd480SApple OSS Distributions self.kperf_session:add_callback_sample({'kstack'}, function (sample) 91*699cd480SApple OSS Distributions local event = self.events_by_tid[sample.threadid] 92*699cd480SApple OSS Distributions if event then 93*699cd480SApple OSS Distributions event.kstack = sample.kstack 94*699cd480SApple OSS Distributions end 95*699cd480SApple OSS Distributions end) 96*699cd480SApple OSS Distributions end 97*699cd480SApple OSS Distributionsend 98*699cd480SApple OSS Distributions 99*699cd480SApple OSS Distributionsfunction ksancov.Session:_register_ktrace_callbacks(proc) 100*699cd480SApple OSS Distributions self.ktrace_session:add_callback('KCOV_STKSZ_THRESHOLD_ABOVE', function (trace_point) 101*699cd480SApple OSS Distributions self:_handle_threshold_above(ktrace.copy_event(trace_point)) 102*699cd480SApple OSS Distributions end) 103*699cd480SApple OSS Distributions 104*699cd480SApple OSS Distributions self.ktrace_session:add_callback('KCOV_STKSZ_THRESHOLD_BELOW', function (trace_point) 105*699cd480SApple OSS Distributions self:_handle_threshold_below(ktrace.copy_event(trace_point)) 106*699cd480SApple OSS Distributions end) 107*699cd480SApple OSS Distributions 108*699cd480SApple OSS Distributions if proc then 109*699cd480SApple OSS Distributions self.ktrace_session:filter_proc(proc) 110*699cd480SApple OSS Distributions end 111*699cd480SApple OSS Distributionsend 112*699cd480SApple OSS Distributions 113*699cd480SApple OSS Distributionsfunction ksancov.Session:_handle_threshold_above(trace_point) 114*699cd480SApple OSS Distributions local event = ksancov.Event.new() 115*699cd480SApple OSS Distributions 116*699cd480SApple OSS Distributions event.tid = trace_point["threadid"] 117*699cd480SApple OSS Distributions event.pid = self.ktrace_session:pid_for_threadid(event.tid) or "0" 118*699cd480SApple OSS Distributions event.pc = trace_point[1] 119*699cd480SApple OSS Distributions event.stack_size = trace_point[2] 120*699cd480SApple OSS Distributions event.procname = self.ktrace_session:procname_for_threadid(event.tid) 121*699cd480SApple OSS Distributions 122*699cd480SApple OSS Distributions self.events_by_tid[event.tid] = event 123*699cd480SApple OSS Distributionsend 124*699cd480SApple OSS Distributions 125*699cd480SApple OSS Distributionsfunction ksancov.Session:_handle_threshold_below(trace_point) 126*699cd480SApple OSS Distributions local event = self.events_by_tid[trace_point["threadid"]] 127*699cd480SApple OSS Distributions 128*699cd480SApple OSS Distributions -- It is possible that we redord BELOW event as first. Ignore it if we haven't seen 129*699cd480SApple OSS Distributions -- the ABOVE event first. 130*699cd480SApple OSS Distributions if event then 131*699cd480SApple OSS Distributions self.events_by_tid[event.tid] = nil 132*699cd480SApple OSS Distributions 133*699cd480SApple OSS Distributions for i, handler in pairs(self.event_handlers) do 134*699cd480SApple OSS Distributions handler(event) 135*699cd480SApple OSS Distributions end 136*699cd480SApple OSS Distributions end 137*699cd480SApple OSS Distributionsend 138*699cd480SApple OSS Distributions 139*699cd480SApple OSS Distributionsfunction ksancov.Session:add_event_handler(handler) 140*699cd480SApple OSS Distributions table.insert(self.event_handlers, handler) 141*699cd480SApple OSS Distributionsend 142*699cd480SApple OSS Distributions 143*699cd480SApple OSS Distributions-- Utility code 144*699cd480SApple OSS Distributions 145*699cd480SApple OSS Distributionslocal function parse_args() 146*699cd480SApple OSS Distributions local parser = argparse("ksancov", "Kernel stack size monitoring utility.") 147*699cd480SApple OSS Distributions 148*699cd480SApple OSS Distributions parser:option { 149*699cd480SApple OSS Distributions name = "--codes-files", 150*699cd480SApple OSS Distributions description = "Import debugid-to-string mapping files", 151*699cd480SApple OSS Distributions args = "*", 152*699cd480SApple OSS Distributions count = "?", 153*699cd480SApple OSS Distributions } 154*699cd480SApple OSS Distributions 155*699cd480SApple OSS Distributions parser:option { 156*699cd480SApple OSS Distributions name = "-f --file", 157*699cd480SApple OSS Distributions description = "artrace or ktrace file to read from", 158*699cd480SApple OSS Distributions args = 1, 159*699cd480SApple OSS Distributions count = "?", 160*699cd480SApple OSS Distributions } 161*699cd480SApple OSS Distributions 162*699cd480SApple OSS Distributions parser:option { 163*699cd480SApple OSS Distributions name = "-p --proc", 164*699cd480SApple OSS Distributions description = "pid or process name to be recorded", 165*699cd480SApple OSS Distributions args = 1, 166*699cd480SApple OSS Distributions count = "?", 167*699cd480SApple OSS Distributions } 168*699cd480SApple OSS Distributions 169*699cd480SApple OSS Distributions parser:flag { 170*699cd480SApple OSS Distributions name = "-u --ustack", 171*699cd480SApple OSS Distributions description = "sample user space stacks", 172*699cd480SApple OSS Distributions count = "?", 173*699cd480SApple OSS Distributions } 174*699cd480SApple OSS Distributions 175*699cd480SApple OSS Distributions parser:flag { 176*699cd480SApple OSS Distributions name = "-k --kstack", 177*699cd480SApple OSS Distributions description = "sample kernel space stacks", 178*699cd480SApple OSS Distributions count = "?", 179*699cd480SApple OSS Distributions } 180*699cd480SApple OSS Distributions 181*699cd480SApple OSS Distributions return parser:parse(arg) 182*699cd480SApple OSS Distributionsend 183*699cd480SApple OSS Distributions 184*699cd480SApple OSS Distributionslocal flags = parse_args() 185*699cd480SApple OSS Distributionslocal ktrace_session = ktrace.Session.new(flags.file) 186*699cd480SApple OSS Distributions 187*699cd480SApple OSS Distributionsif flags.codes_files then 188*699cd480SApple OSS Distributions for _, file in pairs(flags.codes_files) do 189*699cd480SApple OSS Distributions ktrace_session:add_codes_file(file) 190*699cd480SApple OSS Distributions end 191*699cd480SApple OSS Distributionsend 192*699cd480SApple OSS Distributions 193*699cd480SApple OSS Distributionslocal ksancov_session = ksancov.Session.new(ktrace_session, flags) 194*699cd480SApple OSS Distributions 195*699cd480SApple OSS Distributionsksancov_session:add_event_handler(function (event) 196*699cd480SApple OSS Distributions event:print() 197*699cd480SApple OSS Distributions 198*699cd480SApple OSS Distributions local function symbolicate(symbolicator, frame) 199*699cd480SApple OSS Distributions local symbol = symbolicator:symbolicate(frame) 200*699cd480SApple OSS Distributions 201*699cd480SApple OSS Distributions if symbol then 202*699cd480SApple OSS Distributions print(("\t%s (in %s)"):format(symbol.name or "???", symbol.owner_name or "???")) 203*699cd480SApple OSS Distributions else 204*699cd480SApple OSS Distributions print(("\t0x%x (in ???)").format(frame)) 205*699cd480SApple OSS Distributions end 206*699cd480SApple OSS Distributions end 207*699cd480SApple OSS Distributions 208*699cd480SApple OSS Distributions -- Symbolicate stacks 209*699cd480SApple OSS Distributions if event.ustack then 210*699cd480SApple OSS Distributions print('ustack:') 211*699cd480SApple OSS Distributions 212*699cd480SApple OSS Distributions if flags.file then 213*699cd480SApple OSS Distributions -- When reading from a file, we can't use CoreSymbolication to symbolicate the stack frames as the processes are 214*699cd480SApple OSS Distributions -- not actually running, so use our ktrace session instead. 215*699cd480SApple OSS Distributions for _, frame in ipairs(event.ustack or {}) do 216*699cd480SApple OSS Distributions print((" %s"):format(ktrace_session:symbolicate_with_pid(event.pid, frame))) 217*699cd480SApple OSS Distributions end 218*699cd480SApple OSS Distributions else 219*699cd480SApple OSS Distributions local symbolicator = CoreSymbolication.Symbolicator.new(event.pid) 220*699cd480SApple OSS Distributions if symbolicator then 221*699cd480SApple OSS Distributions for _, frame in ipairs(event.ustack or {}) do 222*699cd480SApple OSS Distributions symbolicate(symbolicator, frame) 223*699cd480SApple OSS Distributions end 224*699cd480SApple OSS Distributions end 225*699cd480SApple OSS Distributions end 226*699cd480SApple OSS Distributions end 227*699cd480SApple OSS Distributions 228*699cd480SApple OSS Distributions if event.kstack then 229*699cd480SApple OSS Distributions print('kstack:') 230*699cd480SApple OSS Distributions 231*699cd480SApple OSS Distributions if flags.file then 232*699cd480SApple OSS Distributions -- When reading from a file, we can't use CoreSymbolication to symbolicate the stack frames as the processes are 233*699cd480SApple OSS Distributions -- not actually running, so use our ktrace session instead. 234*699cd480SApple OSS Distributions for _, frame in ipairs(event.kstack or {}) do 235*699cd480SApple OSS Distributions print((" %s"):format(ktrace_session:symbolicate_with_pid(event.pid, frame))) 236*699cd480SApple OSS Distributions end 237*699cd480SApple OSS Distributions else 238*699cd480SApple OSS Distributions local symbolicator = CoreSymbolication.Symbolicator.new(0) 239*699cd480SApple OSS Distributions if symbolicator then 240*699cd480SApple OSS Distributions for _, frame in ipairs(event.kstack or {}) do 241*699cd480SApple OSS Distributions symbolicate(symbolicator, frame) 242*699cd480SApple OSS Distributions end 243*699cd480SApple OSS Distributions end 244*699cd480SApple OSS Distributions end 245*699cd480SApple OSS Distributions end 246*699cd480SApple OSS Distributionsend) 247*699cd480SApple OSS Distributions 248*699cd480SApple OSS Distributionsio.stdout:write("Started recording ...\n") 249*699cd480SApple OSS Distributionslocal ok, err = ksancov_session:start() 250*699cd480SApple OSS Distributionsif not ok then 251*699cd480SApple OSS Distributions io.stderr:write("Failed to start session: ", err, "\n") 252*699cd480SApple OSS Distributions os.exit(1) 253*699cd480SApple OSS Distributionsend 254*699cd480SApple OSS Distributions 255*699cd480SApple OSS Distributionsio.stdout:write("DONE.\n") 256*699cd480SApple OSS Distributions 257