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