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