This is xnu-11215.1.10. See this file in:
#!/usr/local/bin/recon
local CoreSymbolication = require 'CoreSymbolication'
local argparse = require 'argparse'
local kperf = require 'kperf'
local ktrace = require 'ktrace'
local strict = require 'strict'


local ksancov = {}

-- KCOV event

ksancov.Event = {}
ksancov.Event.__index = ksancov.Event

function ksancov.Event.new()
	local instance = {
		pid = nil,
		procname = nil,
		tid = nil,
		stack_size = nil,
		pc = nil,
		duration = nil,
		ustack = nil,
		kstack = nil,
	}

	return setmetatable(instance, ksancov.Event)
end

function ksancov.Event:print()
	print(string.format("%s(%d)\t%d\t at %x has stack size %d.", self.procname, self.pid, self.tid,
		self.pc, self.stack_size))
end

-- KSANCOV tracing session

ksancov.Session = {}
ksancov.Session.__index = ksancov.Session

function ksancov.Session.new(ktrace_session, flags)
	assert(ktrace_session)

	local instance = {
		ktrace_session = ktrace_session,
		kperf_session = kperf.Session.new(ktrace_session),
		events_by_tid = {},
		event_handlers = {},
	}

	local self = setmetatable(instance, ksancov.Session)
	self:_register_kperf_callbacks(flags.ustack, flags.kstack)
	self:_register_ktrace_callbacks(flags.proc)
	return self
end

function ksancov.Session:start()
	return self.ktrace_session:start()
end

function ksancov.Session:_register_kperf_callbacks(ustack, kstack)
	local samplers = {}
	if kstack then
		table.insert(samplers, 'kstack')
	end

	if ustack then
		table.insert(samplers, 'ustack')
	end

	-- D0x01ad0000 KCOV_THRESHOLD_ABOVE
	if #samplers == 0 then
		return
	end

	self.kperf_session:add_kdebug_sampler({'D0x01ad0000'}, samplers)

	-- Collect userspace stacks
	if ustack then
		self.kperf_session:add_callback_sample({'ustack'}, function (sample)
			local event = self.events_by_tid[sample.threadid]
			if event then
				event.ustack = sample.ustack
			end
		end)
	end

	-- Collect kernel stacks
	if kstack then
		self.kperf_session:add_callback_sample({'kstack'}, function (sample)
			local event = self.events_by_tid[sample.threadid]
			if event then
				event.kstack = sample.kstack
			end
		end)
	end
end

function ksancov.Session:_register_ktrace_callbacks(proc)
	self.ktrace_session:add_callback('KCOV_STKSZ_THRESHOLD_ABOVE', function (trace_point)
		self:_handle_threshold_above(ktrace.copy_event(trace_point))
	end)

	self.ktrace_session:add_callback('KCOV_STKSZ_THRESHOLD_BELOW', function (trace_point)
		self:_handle_threshold_below(ktrace.copy_event(trace_point))
	end)

	if proc then
		self.ktrace_session:filter_proc(proc)
	end
end

function ksancov.Session:_handle_threshold_above(trace_point)
	local event = ksancov.Event.new()

	event.tid = trace_point["threadid"]
	event.pid = self.ktrace_session:pid_for_threadid(event.tid) or "0"
	event.pc = trace_point[1]
	event.stack_size = trace_point[2]
	event.procname = self.ktrace_session:procname_for_threadid(event.tid)

	self.events_by_tid[event.tid] = event
end

function ksancov.Session:_handle_threshold_below(trace_point)
	local event = self.events_by_tid[trace_point["threadid"]]

	-- It is possible that we redord BELOW event as first. Ignore it if we haven't seen
	-- the ABOVE event first.
	if event then
		self.events_by_tid[event.tid] = nil

		for i, handler in pairs(self.event_handlers) do
			handler(event)
		end
	end
end

function ksancov.Session:add_event_handler(handler)
	table.insert(self.event_handlers, handler)
end

-- Utility code

local function parse_args()
	local parser = argparse("ksancov", "Kernel stack size monitoring utility.")

	parser:option {
		name = "--codes-files",
		description = "Import debugid-to-string mapping files",
		args = "*",
		count = "?",
	}

	parser:option {
		name = "-f --file",
		description = "artrace or ktrace file to read from",
		args = 1,
		count = "?",
	}

	parser:option {
		name = "-p --proc",
		description = "pid or process name to be recorded",
		args = 1,
		count = "?",
	}

	parser:flag  {
		name = "-u --ustack",
		description = "sample user space stacks",
		count = "?",
	}

	parser:flag {
		name = "-k --kstack",
		description = "sample kernel space stacks",
		count = "?",
	}

	return parser:parse(arg)
end

local flags = parse_args()
local ktrace_session = ktrace.Session.new(flags.file)

if flags.codes_files then
	for _, file in pairs(flags.codes_files) do
		ktrace_session:add_codes_file(file)
	end
end

local ksancov_session = ksancov.Session.new(ktrace_session, flags)

ksancov_session:add_event_handler(function (event)
	event:print()

	local function symbolicate(symbolicator, frame)
		local symbol = symbolicator:symbolicate(frame)

		if symbol then
			print(("\t%s  (in %s)"):format(symbol.name or "???", symbol.owner_name or "???"))
		else
			print(("\t0x%x  (in ???)").format(frame))
		end
	end

	-- Symbolicate stacks
	if event.ustack then
		print('ustack:')

		if flags.file then
			-- When reading from a file, we can't use CoreSymbolication to symbolicate the stack frames as the processes are
			-- not actually running, so use our ktrace session instead.
			for _, frame in ipairs(event.ustack or {}) do
				print(("    %s"):format(ktrace_session:symbolicate_with_pid(event.pid, frame)))
			end
		else
			local symbolicator = CoreSymbolication.Symbolicator.new(event.pid)
			if symbolicator then
				for _, frame in ipairs(event.ustack or {}) do
					symbolicate(symbolicator, frame)
				end
			end
		end
	end

	if event.kstack then
		print('kstack:')

		if flags.file then
			-- When reading from a file, we can't use CoreSymbolication to symbolicate the stack frames as the processes are
			-- not actually running, so use our ktrace session instead.
			for _, frame in ipairs(event.kstack or {}) do
				print(("    %s"):format(ktrace_session:symbolicate_with_pid(event.pid, frame)))
			end
		else
			local symbolicator = CoreSymbolication.Symbolicator.new(0)
			if symbolicator then
				for _, frame in ipairs(event.kstack or {}) do
					symbolicate(symbolicator, frame)
				end
			end
		end
	end
end)

io.stdout:write("Started recording ...\n")
local ok, err = ksancov_session:start()
if not ok then
	io.stderr:write("Failed to start session: ", err, "\n")
	os.exit(1)
end

io.stdout:write("DONE.\n")