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