1*a1e26a70SApple OSS Distributionsfrom collections import namedtuple 2*a1e26a70SApple OSS Distributionsfrom itertools import chain 3*a1e26a70SApple OSS Distributions 4*a1e26a70SApple OSS Distributionsfrom xnu import * 5*a1e26a70SApple OSS Distributions 6*a1e26a70SApple OSS DistributionsLogBlock = namedtuple('LogBlock', ['blk_id', 'blk']) 7*a1e26a70SApple OSS DistributionsLQEntry = namedtuple('LQEntry', ['state', 'size', 'lmid', 'data']) 8*a1e26a70SApple OSS DistributionsLogStreamElem = namedtuple( 9*a1e26a70SApple OSS Distributions 'LogStreamElem', ['blk_id', 'offset', 'lsm', 'ftid']) 10*a1e26a70SApple OSS Distributions 11*a1e26a70SApple OSS Distributions 12*a1e26a70SApple OSS Distributionsclass PPrinter(object): 13*a1e26a70SApple OSS Distributions """ Naive yet helpful pretty printer. """ 14*a1e26a70SApple OSS Distributions 15*a1e26a70SApple OSS Distributions def __init__(self, O, kv_indent=17): 16*a1e26a70SApple OSS Distributions self._O = O 17*a1e26a70SApple OSS Distributions self._kv_fmt = "{:<" + str(kv_indent) + "}" 18*a1e26a70SApple OSS Distributions 19*a1e26a70SApple OSS Distributions def header(self, title, upper_case=False): 20*a1e26a70SApple OSS Distributions """ Prints out a header with a given text. """ 21*a1e26a70SApple OSS Distributions if upper_case: 22*a1e26a70SApple OSS Distributions title = title.upper() 23*a1e26a70SApple OSS Distributions print(self._O.format("{VT.Bold}{:s}{VT.EndBold}", title)) 24*a1e26a70SApple OSS Distributions 25*a1e26a70SApple OSS Distributions def table(self, args): 26*a1e26a70SApple OSS Distributions """ Switches to a table mode. """ 27*a1e26a70SApple OSS Distributions return self._O.table(args) 28*a1e26a70SApple OSS Distributions 29*a1e26a70SApple OSS Distributions @staticmethod 30*a1e26a70SApple OSS Distributions def print(*values): 31*a1e26a70SApple OSS Distributions """ A simple wrapper around `print` providing same functionality. """ 32*a1e26a70SApple OSS Distributions print(*values) 33*a1e26a70SApple OSS Distributions 34*a1e26a70SApple OSS Distributions def kvprint(self, key, fmt, *values): 35*a1e26a70SApple OSS Distributions """ Pretty prints aligned `key: values`. The `fmt` argument specifies 36*a1e26a70SApple OSS Distributions value(s) format string. 37*a1e26a70SApple OSS Distributions """ 38*a1e26a70SApple OSS Distributions print(self._kv_fmt.format(key), end=": ") 39*a1e26a70SApple OSS Distributions print(fmt.format(*values)) 40*a1e26a70SApple OSS Distributions 41*a1e26a70SApple OSS Distributions @staticmethod 42*a1e26a70SApple OSS Distributions def empty_line(): 43*a1e26a70SApple OSS Distributions """ Prints an empty line. """ 44*a1e26a70SApple OSS Distributions print(" \n") 45*a1e26a70SApple OSS Distributions 46*a1e26a70SApple OSS Distributions 47*a1e26a70SApple OSS Distributionsclass FTID(object): 48*a1e26a70SApple OSS Distributions """ Represents a firehose tracepoint identifier. Decodes the tracepoint 49*a1e26a70SApple OSS Distributions and provides details on its fields. 50*a1e26a70SApple OSS Distributions """ 51*a1e26a70SApple OSS Distributions 52*a1e26a70SApple OSS Distributions TYPE = { 53*a1e26a70SApple OSS Distributions 0x00: "default", 54*a1e26a70SApple OSS Distributions 0x01: "info", 55*a1e26a70SApple OSS Distributions 0x02: "debug", 56*a1e26a70SApple OSS Distributions 0x10: "error", 57*a1e26a70SApple OSS Distributions 0x11: "fault" 58*a1e26a70SApple OSS Distributions } 59*a1e26a70SApple OSS Distributions 60*a1e26a70SApple OSS Distributions def __init__(self, ftid): 61*a1e26a70SApple OSS Distributions self._ftid = ftid 62*a1e26a70SApple OSS Distributions 63*a1e26a70SApple OSS Distributions @property 64*a1e26a70SApple OSS Distributions def value(self): 65*a1e26a70SApple OSS Distributions """ Returns a firehose tracepoint id compound value. """ 66*a1e26a70SApple OSS Distributions return self._ftid.ftid_value 67*a1e26a70SApple OSS Distributions 68*a1e26a70SApple OSS Distributions @property 69*a1e26a70SApple OSS Distributions def namespace(self): 70*a1e26a70SApple OSS Distributions """ Returns a tuple of a namespace identifier and its name. """ 71*a1e26a70SApple OSS Distributions ns_id = int(self._ftid.ftid._namespace) 72*a1e26a70SApple OSS Distributions ns_name = GetEnumName('firehose_tracepoint_namespace_t', 73*a1e26a70SApple OSS Distributions ns_id, 'firehose_tracepoint_namespace') 74*a1e26a70SApple OSS Distributions return (ns_id, ns_name.split('_')[-1]) 75*a1e26a70SApple OSS Distributions 76*a1e26a70SApple OSS Distributions @property 77*a1e26a70SApple OSS Distributions def code(self): 78*a1e26a70SApple OSS Distributions """ Returns a tracepoint code value. """ 79*a1e26a70SApple OSS Distributions return int(self._ftid.ftid._code) 80*a1e26a70SApple OSS Distributions 81*a1e26a70SApple OSS Distributions @property 82*a1e26a70SApple OSS Distributions def flags(self): 83*a1e26a70SApple OSS Distributions """ Returns a tuple of a tracepoint flag and its name. """ 84*a1e26a70SApple OSS Distributions flag_id = unsigned(self._ftid.ftid._flags) 85*a1e26a70SApple OSS Distributions flag_name = GetEnumName('firehose_tracepoint_flags_t', 86*a1e26a70SApple OSS Distributions flag_id, '_firehose_tracepoint_flags_') 87*a1e26a70SApple OSS Distributions parts = flag_name.split('_') 88*a1e26a70SApple OSS Distributions flag_name = parts[0] + ":" + " ".join(parts[2:]) 89*a1e26a70SApple OSS Distributions return (flag_id, flag_name) 90*a1e26a70SApple OSS Distributions 91*a1e26a70SApple OSS Distributions @property 92*a1e26a70SApple OSS Distributions def type(self): 93*a1e26a70SApple OSS Distributions """ Returns a tuple of a tracepoint type and its name. """ 94*a1e26a70SApple OSS Distributions # GetEnumName cannot be used because _firehose_tracepoint_type_trace_t 95*a1e26a70SApple OSS Distributions # is defined as OS_ENUM which defines values as anonymous enum 96*a1e26a70SApple OSS Distributions # unrelated to the type name whatsoever. 97*a1e26a70SApple OSS Distributions code_id = int(self._ftid.ftid._type) 98*a1e26a70SApple OSS Distributions return (code_id, self.TYPE.get(code_id, "<unknown>")) 99*a1e26a70SApple OSS Distributions 100*a1e26a70SApple OSS Distributions 101*a1e26a70SApple OSS Distributionsclass LogBlocks(object): 102*a1e26a70SApple OSS Distributions """ A base class for objects using log blocks. """ 103*a1e26a70SApple OSS Distributions BLOCK_SIZE = 64 104*a1e26a70SApple OSS Distributions 105*a1e26a70SApple OSS Distributions def __init__(self, buf, blk, blk_count, is_ringbuffer): 106*a1e26a70SApple OSS Distributions self._buf = buf 107*a1e26a70SApple OSS Distributions self._blk = blk 108*a1e26a70SApple OSS Distributions self._blk_count = blk_count 109*a1e26a70SApple OSS Distributions self._is_ringbuffer = is_ringbuffer 110*a1e26a70SApple OSS Distributions 111*a1e26a70SApple OSS Distributions @property 112*a1e26a70SApple OSS Distributions def block_count(self): 113*a1e26a70SApple OSS Distributions """ Returns a total block count. """ 114*a1e26a70SApple OSS Distributions return self._blk_count 115*a1e26a70SApple OSS Distributions 116*a1e26a70SApple OSS Distributions def block_size(self, block_count=1): 117*a1e26a70SApple OSS Distributions """ Returns a space size occupied by a given number of blocks. """ 118*a1e26a70SApple OSS Distributions return self.BLOCK_SIZE * block_count 119*a1e26a70SApple OSS Distributions 120*a1e26a70SApple OSS Distributions def block_position(self, cursor): 121*a1e26a70SApple OSS Distributions """ Returns a block number and a buffer offset of a log at 122*a1e26a70SApple OSS Distributions a provided position (block sequence number). 123*a1e26a70SApple OSS Distributions """ 124*a1e26a70SApple OSS Distributions blk_id = cursor % self.block_count if self.block_count > 0 else 0 125*a1e26a70SApple OSS Distributions return (blk_id, self.block_size(blk_id)) 126*a1e26a70SApple OSS Distributions 127*a1e26a70SApple OSS Distributions def blocks(self, head_block=0): 128*a1e26a70SApple OSS Distributions """ Returns a generator of log blocks starting at a provided 129*a1e26a70SApple OSS Distributions block position. 130*a1e26a70SApple OSS Distributions """ 131*a1e26a70SApple OSS Distributions blocks = self._blocks_range(head_block, self.block_count) 132*a1e26a70SApple OSS Distributions if self._is_ringbuffer: 133*a1e26a70SApple OSS Distributions blocks = chain(blocks, self._blocks_range(0, head_block)) 134*a1e26a70SApple OSS Distributions return blocks 135*a1e26a70SApple OSS Distributions 136*a1e26a70SApple OSS Distributions def logs(self, head_block=0): 137*a1e26a70SApple OSS Distributions """ Returns a generator of `LogStreamMsg` elements starting at 138*a1e26a70SApple OSS Distributions a given block position. 139*a1e26a70SApple OSS Distributions """ 140*a1e26a70SApple OSS Distributions return (self._log_stream_msg(b.blk_id) for b in self.blocks(head_block) if b.blk) 141*a1e26a70SApple OSS Distributions 142*a1e26a70SApple OSS Distributions def _blocks_range(self, s, e): 143*a1e26a70SApple OSS Distributions return (LogBlock(blk_id=i, blk=self._blk[i]) for i in range(s, e)) 144*a1e26a70SApple OSS Distributions 145*a1e26a70SApple OSS Distributions def _log_stream_msg(self, blk_id): 146*a1e26a70SApple OSS Distributions lsm_offset = self.block_size(blk_id) 147*a1e26a70SApple OSS Distributions lsm = Cast(addressof(self._buf[lsm_offset]), 'log_stream_msg_t *') 148*a1e26a70SApple OSS Distributions return LogStreamElem(blk_id=blk_id, 149*a1e26a70SApple OSS Distributions offset=lsm_offset, 150*a1e26a70SApple OSS Distributions lsm=lsm, 151*a1e26a70SApple OSS Distributions ftid=FTID(addressof(lsm.lsm_ft.ft_id))) 152*a1e26a70SApple OSS Distributions 153*a1e26a70SApple OSS Distributions 154*a1e26a70SApple OSS Distributionsclass LogStream(LogBlocks): 155*a1e26a70SApple OSS Distributions """ Represents an OSLog Stream buffer. """ 156*a1e26a70SApple OSS Distributions 157*a1e26a70SApple OSS Distributions def __init__(self, log_stream): 158*a1e26a70SApple OSS Distributions super().__init__(log_stream.ls_buf, 159*a1e26a70SApple OSS Distributions log_stream.ls_blk, 160*a1e26a70SApple OSS Distributions log_stream.ls_blk_count, 161*a1e26a70SApple OSS Distributions True) 162*a1e26a70SApple OSS Distributions self._stream = log_stream 163*a1e26a70SApple OSS Distributions 164*a1e26a70SApple OSS Distributions @property 165*a1e26a70SApple OSS Distributions def address(self): 166*a1e26a70SApple OSS Distributions """ Returns a log stream address. """ 167*a1e26a70SApple OSS Distributions return int(self._stream) 168*a1e26a70SApple OSS Distributions 169*a1e26a70SApple OSS Distributions @property 170*a1e26a70SApple OSS Distributions def enabled(self): 171*a1e26a70SApple OSS Distributions """ Returns true for enabled log stream, false otherwise. """ 172*a1e26a70SApple OSS Distributions return self._stream.ls_enabled 173*a1e26a70SApple OSS Distributions 174*a1e26a70SApple OSS Distributions @property 175*a1e26a70SApple OSS Distributions def reserved(self): 176*a1e26a70SApple OSS Distributions """ Returns a total number of reserved bytes. """ 177*a1e26a70SApple OSS Distributions return self._stream.ls_reserved 178*a1e26a70SApple OSS Distributions 179*a1e26a70SApple OSS Distributions @property 180*a1e26a70SApple OSS Distributions def logged(self): 181*a1e26a70SApple OSS Distributions """ Returns a number of commited bytes and an actual number 182*a1e26a70SApple OSS Distributions of logged bytes. 183*a1e26a70SApple OSS Distributions """ 184*a1e26a70SApple OSS Distributions return (self._stream.ls_commited.v, 185*a1e26a70SApple OSS Distributions self._stream.ls_commited.v - self._stream.ls_commited_wraps) 186*a1e26a70SApple OSS Distributions 187*a1e26a70SApple OSS Distributions def sync_cursor(self, cursor): 188*a1e26a70SApple OSS Distributions """ Aligns read cursor so it points to the actual beginning 189*a1e26a70SApple OSS Distributions of a log stream. 190*a1e26a70SApple OSS Distributions """ 191*a1e26a70SApple OSS Distributions commited, logged = self.logged 192*a1e26a70SApple OSS Distributions read = cursor 193*a1e26a70SApple OSS Distributions if read + self.block_count < logged: 194*a1e26a70SApple OSS Distributions read = logged 195*a1e26a70SApple OSS Distributions if commited >= self.block_count: 196*a1e26a70SApple OSS Distributions read -= self.block_count 197*a1e26a70SApple OSS Distributions return read % self.block_count 198*a1e26a70SApple OSS Distributions 199*a1e26a70SApple OSS Distributions 200*a1e26a70SApple OSS Distributionsclass LogStreamCache(LogBlocks): 201*a1e26a70SApple OSS Distributions """ Represents an OSLog Stream Cache. 202*a1e26a70SApple OSS Distributions """ 203*a1e26a70SApple OSS Distributions 204*a1e26a70SApple OSS Distributions def __init__(self, log_cache): 205*a1e26a70SApple OSS Distributions super().__init__(log_cache.lc_buf, 206*a1e26a70SApple OSS Distributions log_cache.lc_blk, 207*a1e26a70SApple OSS Distributions log_cache.lc_blk_count, 208*a1e26a70SApple OSS Distributions False) 209*a1e26a70SApple OSS Distributions self._cache = log_cache 210*a1e26a70SApple OSS Distributions 211*a1e26a70SApple OSS Distributions @property 212*a1e26a70SApple OSS Distributions def address(self): 213*a1e26a70SApple OSS Distributions """ Returns a log stream cache address. """ 214*a1e26a70SApple OSS Distributions return addressof(self._cache) 215*a1e26a70SApple OSS Distributions 216*a1e26a70SApple OSS Distributions @property 217*a1e26a70SApple OSS Distributions def stream(self): 218*a1e26a70SApple OSS Distributions """ Returns a log stream cached by this instance. 219*a1e26a70SApple OSS Distributions """ 220*a1e26a70SApple OSS Distributions return LogStream(self._cache.lc_stream) if self._cache.lc_stream else None 221*a1e26a70SApple OSS Distributions 222*a1e26a70SApple OSS Distributions @property 223*a1e26a70SApple OSS Distributions def stream_cursor(self): 224*a1e26a70SApple OSS Distributions """ Returns a current log stream read cursor. The value is 225*a1e26a70SApple OSS Distributions a block sequence of a block to read from next. 226*a1e26a70SApple OSS Distributions """ 227*a1e26a70SApple OSS Distributions if not self.stream: 228*a1e26a70SApple OSS Distributions return 0 229*a1e26a70SApple OSS Distributions return self.stream.sync_cursor(self._cache.lc_stream_pos) 230*a1e26a70SApple OSS Distributions 231*a1e26a70SApple OSS Distributions @property 232*a1e26a70SApple OSS Distributions def cache_cursor(self): 233*a1e26a70SApple OSS Distributions """ Returns a current log cache cursor. The value is a number 234*a1e26a70SApple OSS Distributions of a block to read from next. 235*a1e26a70SApple OSS Distributions """ 236*a1e26a70SApple OSS Distributions return self._cache.lc_blk_pos 237*a1e26a70SApple OSS Distributions 238*a1e26a70SApple OSS Distributions 239*a1e26a70SApple OSS Distributionsclass MsgBuffer(object): 240*a1e26a70SApple OSS Distributions """ Provides access to msgbuf_t ring buffer which is primarily 241*a1e26a70SApple OSS Distributions a data type behind system message buffer accessible via dmesg 242*a1e26a70SApple OSS Distributions CLI command. 243*a1e26a70SApple OSS Distributions """ 244*a1e26a70SApple OSS Distributions MSG_MAGIC = 0x063061 245*a1e26a70SApple OSS Distributions 246*a1e26a70SApple OSS Distributions def __init__(self, msgbuf): 247*a1e26a70SApple OSS Distributions self._msgbuf = msgbuf 248*a1e26a70SApple OSS Distributions size = int(self._msgbuf.msg_size) 249*a1e26a70SApple OSS Distributions self._buffer = self._msgbuf.msg_bufc.GetSBValue().GetPointeeData(0, size) 250*a1e26a70SApple OSS Distributions 251*a1e26a70SApple OSS Distributions def __eq__(self, other): 252*a1e26a70SApple OSS Distributions return unsigned(self._msgbuf) == unsigned(other._msgbuf) 253*a1e26a70SApple OSS Distributions 254*a1e26a70SApple OSS Distributions def __hash__(self): 255*a1e26a70SApple OSS Distributions return hash(unsigned(self._msgbuf)) 256*a1e26a70SApple OSS Distributions 257*a1e26a70SApple OSS Distributions @dyn_cached_property 258*a1e26a70SApple OSS Distributions def values(self, target=None): 259*a1e26a70SApple OSS Distributions """ Returns a list of all log messages. """ 260*a1e26a70SApple OSS Distributions 261*a1e26a70SApple OSS Distributions return list(self._values()) 262*a1e26a70SApple OSS Distributions 263*a1e26a70SApple OSS Distributions def __len__(self): 264*a1e26a70SApple OSS Distributions """ Returns a number of log messages in the message buffer. """ 265*a1e26a70SApple OSS Distributions return len(self.values) 266*a1e26a70SApple OSS Distributions 267*a1e26a70SApple OSS Distributions def __getitem__(self, i): 268*a1e26a70SApple OSS Distributions """ Returns a log message at a given index. """ 269*a1e26a70SApple OSS Distributions return self.values[i] 270*a1e26a70SApple OSS Distributions 271*a1e26a70SApple OSS Distributions def __iter__(self): 272*a1e26a70SApple OSS Distributions """ Returns an iterator object of log messages. """ 273*a1e26a70SApple OSS Distributions return iter(self.values) 274*a1e26a70SApple OSS Distributions 275*a1e26a70SApple OSS Distributions def _values(self): 276*a1e26a70SApple OSS Distributions """ Returns a generator object of log messages. """ 277*a1e26a70SApple OSS Distributions chars = (c for c in (self._at(i) for i in self._range()) if c != 0) 278*a1e26a70SApple OSS Distributions line = bytearray() 279*a1e26a70SApple OSS Distributions for c in chars: 280*a1e26a70SApple OSS Distributions line.append(c) 281*a1e26a70SApple OSS Distributions if chr(c) == '\n': 282*a1e26a70SApple OSS Distributions yield line.decode(errors='backslashreplace') 283*a1e26a70SApple OSS Distributions line = bytearray() 284*a1e26a70SApple OSS Distributions yield line.decode(errors='backslashreplace') 285*a1e26a70SApple OSS Distributions 286*a1e26a70SApple OSS Distributions def _at(self, i): 287*a1e26a70SApple OSS Distributions """ Returns a character at a given index. """ 288*a1e26a70SApple OSS Distributions err = lldb.SBError() 289*a1e26a70SApple OSS Distributions c = self._buffer.GetUnsignedInt8(err, i) 290*a1e26a70SApple OSS Distributions if not err.Success(): 291*a1e26a70SApple OSS Distributions raise ValueError( 292*a1e26a70SApple OSS Distributions "Failed to read character at offset " + str(i) + ": " + err.GetCString()) 293*a1e26a70SApple OSS Distributions return c 294*a1e26a70SApple OSS Distributions 295*a1e26a70SApple OSS Distributions def _range(self): 296*a1e26a70SApple OSS Distributions """ Returns character indices starting at a ring buffer head. """ 297*a1e26a70SApple OSS Distributions start = int(self._msgbuf.msg_bufx) 298*a1e26a70SApple OSS Distributions size = int(self._msgbuf.msg_size) 299*a1e26a70SApple OSS Distributions return ((start + i) % size for i in range(0, size)) 300*a1e26a70SApple OSS Distributions 301*a1e26a70SApple OSS Distributions 302*a1e26a70SApple OSS Distributionsclass LogQueue(object): 303*a1e26a70SApple OSS Distributions """ Represents a kernel log queue. """ 304*a1e26a70SApple OSS Distributions 305*a1e26a70SApple OSS Distributions def __init__(self, cpu, lq): 306*a1e26a70SApple OSS Distributions self._cpu = cpu 307*a1e26a70SApple OSS Distributions self._lq = lq 308*a1e26a70SApple OSS Distributions 309*a1e26a70SApple OSS Distributions @property 310*a1e26a70SApple OSS Distributions def cpu(self): 311*a1e26a70SApple OSS Distributions """ Returns a CPU number the log queue is associated with. """ 312*a1e26a70SApple OSS Distributions return self._cpu 313*a1e26a70SApple OSS Distributions 314*a1e26a70SApple OSS Distributions @property 315*a1e26a70SApple OSS Distributions def ptr(self): 316*a1e26a70SApple OSS Distributions """ Returns a pointer to enclosed log_queue_s. """ 317*a1e26a70SApple OSS Distributions return self._lq 318*a1e26a70SApple OSS Distributions 319*a1e26a70SApple OSS Distributions @property 320*a1e26a70SApple OSS Distributions def address(self): 321*a1e26a70SApple OSS Distributions """ Returns a log queue address. """ 322*a1e26a70SApple OSS Distributions return int(self.ptr) 323*a1e26a70SApple OSS Distributions 324*a1e26a70SApple OSS Distributions @property 325*a1e26a70SApple OSS Distributions def size(self): 326*a1e26a70SApple OSS Distributions """ Returns an actual total log queue size. """ 327*a1e26a70SApple OSS Distributions slot_size = 1 << unsigned(self._lq.lq_mem_size_order) 328*a1e26a70SApple OSS Distributions return self._lq.lq_cnt_mem_active * slot_size 329*a1e26a70SApple OSS Distributions 330*a1e26a70SApple OSS Distributions @property 331*a1e26a70SApple OSS Distributions def enqueued(self): 332*a1e26a70SApple OSS Distributions """ Returns a generator of logs enqueued in the log queue. """ 333*a1e26a70SApple OSS Distributions return self._lq_entries(addressof(self._lq.lq_log_list)) 334*a1e26a70SApple OSS Distributions 335*a1e26a70SApple OSS Distributions @property 336*a1e26a70SApple OSS Distributions def dispatched(self): 337*a1e26a70SApple OSS Distributions """ Returns a generator of logs dispatched by the log queue. """ 338*a1e26a70SApple OSS Distributions return self._lq_entries(addressof(self._lq.lq_dispatch_list)) 339*a1e26a70SApple OSS Distributions 340*a1e26a70SApple OSS Distributions @staticmethod 341*a1e26a70SApple OSS Distributions def _lq_entries(lqe_list): 342*a1e26a70SApple OSS Distributions """ Returns a generator of LQEntry elements representing given single-linked list. """ 343*a1e26a70SApple OSS Distributions def lq_entry(lqe): 344*a1e26a70SApple OSS Distributions lqe_state = GetEnumName('log_queue_entry_state_t', 345*a1e26a70SApple OSS Distributions lqe.lqe_state, 'LOG_QUEUE_ENTRY_STATE_') 346*a1e26a70SApple OSS Distributions return LQEntry(state=lqe_state, size=lqe.lqe_size, lmid=lqe.lqe_lm_id, data=lqe.lqe_payload) 347*a1e26a70SApple OSS Distributions return (lq_entry(e) for e in IterateTAILQ_HEAD(lqe_list, 'lqe_link', 's') if e) 348*a1e26a70SApple OSS Distributions 349*a1e26a70SApple OSS Distributions @staticmethod 350*a1e26a70SApple OSS Distributions def collect(): 351*a1e26a70SApple OSS Distributions """ Returns a list of all per-CPU log queues. """ 352*a1e26a70SApple OSS Distributions pcpu_lqs = addressof(kern.GetGlobalVariable('percpu_slot_oslog_queue')) 353*a1e26a70SApple OSS Distributions pcpu_lqs_type = pcpu_lqs.GetSBValue().GetType().name 354*a1e26a70SApple OSS Distributions cpus = range(0, kern.globals.zpercpu_early_count) 355*a1e26a70SApple OSS Distributions 356*a1e26a70SApple OSS Distributions def PCPUSlot(i): 357*a1e26a70SApple OSS Distributions addr = unsigned(pcpu_lqs) + kern.PERCPU_BASE(i) 358*a1e26a70SApple OSS Distributions return kern.GetValueFromAddress(addr, pcpu_lqs_type) 359*a1e26a70SApple OSS Distributions 360*a1e26a70SApple OSS Distributions return [LogQueue(cpu, PCPUSlot(cpu)) for cpu in cpus] 361*a1e26a70SApple OSS Distributions 362*a1e26a70SApple OSS Distributions 363*a1e26a70SApple OSS Distributionsdef show_log_stream_logs(pp, logs): 364*a1e26a70SApple OSS Distributions """ Pretty prints logs metadata. 365*a1e26a70SApple OSS Distributions """ 366*a1e26a70SApple OSS Distributions hdr = "{0:>5s} {1:>7s} {2:>6s} {3:>12s} {4:>16s} {5:>8s} {6:>9s} {7:>7s} {8:>8s} {9:>18s}" 367*a1e26a70SApple OSS Distributions hdr_labels = ( 368*a1e26a70SApple OSS Distributions "BLOCK", "OFFSET", "LENGTH", "TIMESTAMP", "FTID", 369*a1e26a70SApple OSS Distributions "TID", "NAMESPACE", "TYPE", "CODE", "FLAGS" 370*a1e26a70SApple OSS Distributions ) 371*a1e26a70SApple OSS Distributions log_hdr = ( 372*a1e26a70SApple OSS Distributions "{log.blk_id:>5d} {log.offset:>7d} {ft.ft_length:>6d} {ts:>12d} " 373*a1e26a70SApple OSS Distributions "{ftid.value:>16x} {ft.ft_thread:>8d} {ftid.namespace[1]:>9s} " 374*a1e26a70SApple OSS Distributions "{ftid.type[1]:>7s} {ftid.code:>08x} {ftid.flags[1]:>18s}" 375*a1e26a70SApple OSS Distributions ) 376*a1e26a70SApple OSS Distributions 377*a1e26a70SApple OSS Distributions log_count = 0 378*a1e26a70SApple OSS Distributions with pp.table(hdr.format(*hdr_labels)): 379*a1e26a70SApple OSS Distributions for log in logs: 380*a1e26a70SApple OSS Distributions pp.print(log_hdr.format(log=log, ts=log.lsm.lsm_ts, 381*a1e26a70SApple OSS Distributions ft=log.lsm.lsm_ft, ftid=log.ftid)) 382*a1e26a70SApple OSS Distributions log_count += 1 383*a1e26a70SApple OSS Distributions pp.print("(Shown {:d} logs)".format(log_count)) 384*a1e26a70SApple OSS Distributions 385*a1e26a70SApple OSS Distributions 386*a1e26a70SApple OSS Distributionsdef show_log_stream_cache(pp, lsc): 387*a1e26a70SApple OSS Distributions """ Pretty prints configuration details of a given log cache. 388*a1e26a70SApple OSS Distributions """ 389*a1e26a70SApple OSS Distributions pp.header("Stream Cache") 390*a1e26a70SApple OSS Distributions 391*a1e26a70SApple OSS Distributions pp.kvprint("Address", "{:#0x}", lsc.address) 392*a1e26a70SApple OSS Distributions pp.kvprint("Size", "{:>d} bytes ({:d} blocks)", 393*a1e26a70SApple OSS Distributions lsc.block_size(lsc.block_count), lsc.block_count) 394*a1e26a70SApple OSS Distributions pp.kvprint("Next Read Block", "{:d} (Offset: {:d})", 395*a1e26a70SApple OSS Distributions *lsc.block_position(lsc.cache_cursor)) 396*a1e26a70SApple OSS Distributions 397*a1e26a70SApple OSS Distributions 398*a1e26a70SApple OSS Distributionsdef show_log_stream(pp, ls, read_pos): 399*a1e26a70SApple OSS Distributions """ Pretty prints configuration details of a given log stream. 400*a1e26a70SApple OSS Distributions """ 401*a1e26a70SApple OSS Distributions pp.header("Stream") 402*a1e26a70SApple OSS Distributions 403*a1e26a70SApple OSS Distributions if not ls: 404*a1e26a70SApple OSS Distributions pp.print("No log stream configured.") 405*a1e26a70SApple OSS Distributions return 406*a1e26a70SApple OSS Distributions 407*a1e26a70SApple OSS Distributions commited, logged_bytes = ls.logged 408*a1e26a70SApple OSS Distributions pp.kvprint("Address", "{:#0x}", ls.address) 409*a1e26a70SApple OSS Distributions pp.kvprint("State", "{:s}", "Enabled" if ls.enabled else "Disabled") 410*a1e26a70SApple OSS Distributions pp.kvprint("Size", "{:>d} bytes ({:d} blocks)", 411*a1e26a70SApple OSS Distributions ls.block_size(ls.block_count), ls.block_count) 412*a1e26a70SApple OSS Distributions pp.kvprint("Reserved", "{:d}", ls.reserved) 413*a1e26a70SApple OSS Distributions pp.kvprint("Commited", "{:d}", commited) 414*a1e26a70SApple OSS Distributions 415*a1e26a70SApple OSS Distributions block, offset = ls.block_position(commited) 416*a1e26a70SApple OSS Distributions pp.kvprint("Written", "{:d} bytes", logged_bytes) 417*a1e26a70SApple OSS Distributions pp.kvprint("Next Write Block", "{:d} (Offset: {:d})", block, offset) 418*a1e26a70SApple OSS Distributions 419*a1e26a70SApple OSS Distributions block, offset = ls.block_position(read_pos) 420*a1e26a70SApple OSS Distributions pp.kvprint("Read", "{:d} bytes", read_pos) 421*a1e26a70SApple OSS Distributions pp.kvprint("Next Read Block", "{:d} (Offset: {:d})", block, offset) 422*a1e26a70SApple OSS Distributions 423*a1e26a70SApple OSS Distributions 424*a1e26a70SApple OSS Distributionsdef show_log_stream_stats(pp): 425*a1e26a70SApple OSS Distributions """ Pretty prints values of log stream counters. """ 426*a1e26a70SApple OSS Distributions pp.header("Statistics") 427*a1e26a70SApple OSS Distributions 428*a1e26a70SApple OSS Distributions pp.kvprint("Total Count", "{:s}", 429*a1e26a70SApple OSS Distributions GetSimpleCounter(kern.globals.oslog_s_total_msgcount)) 430*a1e26a70SApple OSS Distributions pp.kvprint("Metadata Count", "{:s}", 431*a1e26a70SApple OSS Distributions GetSimpleCounter(kern.globals.oslog_s_metadata_msgcount)) 432*a1e26a70SApple OSS Distributions pp.kvprint("Streamed Logs", "{:s}", 433*a1e26a70SApple OSS Distributions GetSimpleCounter(kern.globals.oslog_s_streamed_msgcount)) 434*a1e26a70SApple OSS Distributions pp.kvprint("Dropped Logs", "{:s}", 435*a1e26a70SApple OSS Distributions GetSimpleCounter(kern.globals.oslog_s_dropped_msgcount)) 436*a1e26a70SApple OSS Distributions pp.kvprint("Invalid Logs", "{:s}", 437*a1e26a70SApple OSS Distributions GetSimpleCounter(kern.globals.oslog_s_error_count)) 438*a1e26a70SApple OSS Distributions 439*a1e26a70SApple OSS Distributions 440*a1e26a70SApple OSS Distributionsdef show_log_stream_info(show_meta, O=None): 441*a1e26a70SApple OSS Distributions """ Pretty prints configuration details of OSLog Streaming and 442*a1e26a70SApple OSS Distributions its current content. 443*a1e26a70SApple OSS Distributions """ 444*a1e26a70SApple OSS Distributions pp = PPrinter(O) 445*a1e26a70SApple OSS Distributions log_cache = LogStreamCache(kern.globals.log_stream_cache) 446*a1e26a70SApple OSS Distributions 447*a1e26a70SApple OSS Distributions pp.empty_line() 448*a1e26a70SApple OSS Distributions pp.header("Overview", True) 449*a1e26a70SApple OSS Distributions show_log_stream_stats(pp) 450*a1e26a70SApple OSS Distributions show_log_stream_cache(pp, log_cache) 451*a1e26a70SApple OSS Distributions show_log_stream(pp, log_cache.stream, log_cache.stream_cursor) 452*a1e26a70SApple OSS Distributions 453*a1e26a70SApple OSS Distributions if not show_meta: 454*a1e26a70SApple OSS Distributions return 455*a1e26a70SApple OSS Distributions 456*a1e26a70SApple OSS Distributions pp.empty_line() 457*a1e26a70SApple OSS Distributions pp.header("Cached Stream Logs", True) 458*a1e26a70SApple OSS Distributions show_log_stream_logs(pp, log_cache.logs(0)) 459*a1e26a70SApple OSS Distributions 460*a1e26a70SApple OSS Distributions if log_cache.stream: 461*a1e26a70SApple OSS Distributions pp.empty_line() 462*a1e26a70SApple OSS Distributions pp.header("Stream Logs", True) 463*a1e26a70SApple OSS Distributions show_log_stream_logs( 464*a1e26a70SApple OSS Distributions pp, log_cache.stream.logs(log_cache.stream_cursor)) 465*a1e26a70SApple OSS Distributions 466*a1e26a70SApple OSS Distributions 467*a1e26a70SApple OSS Distributionsdef show_log_queues(pp, log_queues, show_logs): 468*a1e26a70SApple OSS Distributions """ Pretty prints log queue summary and logs. """ 469*a1e26a70SApple OSS Distributions hdr = "{:>3s} {:>16s} {:>2s} {:>10s} {:>10s} {:>5s} {:>8s} {:>6s} {:>6s} {:>8s}" 470*a1e26a70SApple OSS Distributions hdr_labels = ( 471*a1e26a70SApple OSS Distributions "CPU", "ADDRESS", "ON", "STATE", "RECONF", "SLOTS", 472*a1e26a70SApple OSS Distributions "SIZE", "AVAIL", "STORED", "EN_ROUTE" 473*a1e26a70SApple OSS Distributions ) 474*a1e26a70SApple OSS Distributions hdr_lq = ( 475*a1e26a70SApple OSS Distributions "{cpu:>3s} {lq.address:>16x} {lq.ptr.lq_ready:>2d} {state:>10s} {reconf:>10s} " 476*a1e26a70SApple OSS Distributions "{lq.ptr.lq_cnt_mem_active:>5d} {size:>8d} {lq.ptr.lq_cnt_mem_avail:>6d} " 477*a1e26a70SApple OSS Distributions "{enq:>6d} {disp:>8d}" 478*a1e26a70SApple OSS Distributions ) 479*a1e26a70SApple OSS Distributions 480*a1e26a70SApple OSS Distributions def show_log_queue(lq, enqueued, dispatched): 481*a1e26a70SApple OSS Distributions state = GetEnumName( 482*a1e26a70SApple OSS Distributions 'lq_mem_state_t', lq._lq.lq_mem_state, 'LQ_MEM_STATE_') 483*a1e26a70SApple OSS Distributions reconf = GetEnumName( 484*a1e26a70SApple OSS Distributions 'lq_req_state_t', lq._lq.lq_req_state, 'LQ_REQ_STATE_') 485*a1e26a70SApple OSS Distributions cpu = "N/A" if lq.cpu is None else str(lq.cpu) 486*a1e26a70SApple OSS Distributions pp.print(hdr_lq.format(lq=lq, state=state, size=lq.size, reconf=reconf, cpu=cpu, 487*a1e26a70SApple OSS Distributions enq=len(enqueued), 488*a1e26a70SApple OSS Distributions disp=len(dispatched))) 489*a1e26a70SApple OSS Distributions 490*a1e26a70SApple OSS Distributions if show_logs: 491*a1e26a70SApple OSS Distributions for lq in log_queues: 492*a1e26a70SApple OSS Distributions lq_enqueued = list(lq.enqueued) 493*a1e26a70SApple OSS Distributions lq_dispatched = list(lq.dispatched) 494*a1e26a70SApple OSS Distributions pp.empty_line() 495*a1e26a70SApple OSS Distributions with pp.table(hdr.format(*hdr_labels)): 496*a1e26a70SApple OSS Distributions show_log_queue(lq, lq_enqueued, lq_dispatched) 497*a1e26a70SApple OSS Distributions 498*a1e26a70SApple OSS Distributions pp.empty_line() 499*a1e26a70SApple OSS Distributions pp.header("Enqueues Log Messages") 500*a1e26a70SApple OSS Distributions show_log_queue_logs(pp, lq_enqueued) 501*a1e26a70SApple OSS Distributions 502*a1e26a70SApple OSS Distributions pp.empty_line() 503*a1e26a70SApple OSS Distributions pp.header("Dispatched Log Messages") 504*a1e26a70SApple OSS Distributions show_log_queue_logs(pp, lq_dispatched) 505*a1e26a70SApple OSS Distributions 506*a1e26a70SApple OSS Distributions pp.empty_line() 507*a1e26a70SApple OSS Distributions return 508*a1e26a70SApple OSS Distributions 509*a1e26a70SApple OSS Distributions with pp.table(hdr.format(*hdr_labels)): 510*a1e26a70SApple OSS Distributions for lq in log_queues: 511*a1e26a70SApple OSS Distributions show_log_queue(lq, list(lq.enqueued), list(lq.dispatched)) 512*a1e26a70SApple OSS Distributions 513*a1e26a70SApple OSS Distributions 514*a1e26a70SApple OSS Distributionsdef show_log_queue_logs(pp, lqe_list): 515*a1e26a70SApple OSS Distributions """ Pretty prints log queue logs. """ 516*a1e26a70SApple OSS Distributions if not lqe_list: 517*a1e26a70SApple OSS Distributions pp.print("No log messages present") 518*a1e26a70SApple OSS Distributions return 519*a1e26a70SApple OSS Distributions 520*a1e26a70SApple OSS Distributions hdr = ("{:>5s} {:>7s} {:>10s} " 521*a1e26a70SApple OSS Distributions "{:>12s} {:>8s} " 522*a1e26a70SApple OSS Distributions "{:>16s} {:>9s} {:>7s} {:>8s} {:>18s}") 523*a1e26a70SApple OSS Distributions hdr_labels = ( 524*a1e26a70SApple OSS Distributions "LM_ID", "LM_SIZE", "STATE", "TIMESTAMP", "LOG_SIZE", 525*a1e26a70SApple OSS Distributions "FTID", "NAMESPACE", "TYPE", "CODE", "FLAGS" 526*a1e26a70SApple OSS Distributions ) 527*a1e26a70SApple OSS Distributions log_hdr = ( 528*a1e26a70SApple OSS Distributions "{lqe.lmid:>5x} {lqe.size:>7d} {lqe.state:>10s} " 529*a1e26a70SApple OSS Distributions "{d.lp_timestamp:>12d} {d.lp_data_size:>8d} " 530*a1e26a70SApple OSS Distributions "{ftid.value:>16x} {ftid.namespace[1]:>9s} " 531*a1e26a70SApple OSS Distributions "{ftid.type[1]:>7s} {ftid.code:>08x} {ftid.flags[1]:>18s}" 532*a1e26a70SApple OSS Distributions ) 533*a1e26a70SApple OSS Distributions with pp.table(hdr.format(*hdr_labels)): 534*a1e26a70SApple OSS Distributions for lqe in lqe_list: 535*a1e26a70SApple OSS Distributions pp.print(log_hdr.format(lqe=lqe, d=lqe.data, 536*a1e26a70SApple OSS Distributions ftid=FTID(lqe.data.lp_ftid))) 537*a1e26a70SApple OSS Distributions pp.print("(Shown {:d} logs)".format(len(lqe_list))) 538*a1e26a70SApple OSS Distributions 539*a1e26a70SApple OSS Distributions 540*a1e26a70SApple OSS Distributions@lldb_command('showlogstream', 'L', fancy=True) 541*a1e26a70SApple OSS Distributionsdef showLogStream(cmd_args=None, cmd_options=None, O=None): 542*a1e26a70SApple OSS Distributions """ Displays the contents of the log stream and the log stream cache. 543*a1e26a70SApple OSS Distributions 544*a1e26a70SApple OSS Distributions showlogstream [-L] 545*a1e26a70SApple OSS Distributions 546*a1e26a70SApple OSS Distributions Options: 547*a1e26a70SApple OSS Distributions -L: Show metadata of logs stored in the log stream and the cache 548*a1e26a70SApple OSS Distributions """ 549*a1e26a70SApple OSS Distributions 550*a1e26a70SApple OSS Distributions show_meta = "-L" in cmd_options 551*a1e26a70SApple OSS Distributions 552*a1e26a70SApple OSS Distributions show_log_stream_info(show_meta, O) 553*a1e26a70SApple OSS Distributions 554*a1e26a70SApple OSS Distributions 555*a1e26a70SApple OSS Distributions@lldb_command('showlq', 'LC:A:', fancy=True) 556*a1e26a70SApple OSS Distributionsdef showLogQueue(cmd_args=None, cmd_options=None, O=None): 557*a1e26a70SApple OSS Distributions """ Displays the contents of the log queue. 558*a1e26a70SApple OSS Distributions 559*a1e26a70SApple OSS Distributions usage: showlq [-C cpu_num][-A addr][-L] 560*a1e26a70SApple OSS Distributions 561*a1e26a70SApple OSS Distributions -C n Shows a log queue summary of a selected CPU. 562*a1e26a70SApple OSS Distributions -A a Shows a log queue summary at a given address. 563*a1e26a70SApple OSS Distributions -L Show metadata of enqueued and dispatched logs 564*a1e26a70SApple OSS Distributions 565*a1e26a70SApple OSS Distributions Options -A and -C are mutually exclusive. 566*a1e26a70SApple OSS Distributions If no options provided summaries of all per-CPU log queues are shown. 567*a1e26a70SApple OSS Distributions 568*a1e26a70SApple OSS Distributions Examples: 569*a1e26a70SApple OSS Distributions showlq 570*a1e26a70SApple OSS Distributions showlq -C 2 -L 571*a1e26a70SApple OSS Distributions showlq -A 0xfffffff123456789 -L 572*a1e26a70SApple OSS Distributions """ 573*a1e26a70SApple OSS Distributions 574*a1e26a70SApple OSS Distributions log_queues = LogQueue.collect() 575*a1e26a70SApple OSS Distributions 576*a1e26a70SApple OSS Distributions if "-C" in cmd_options and "-A" in cmd_options: 577*a1e26a70SApple OSS Distributions raise ArgumentError("Options -A and -C are mutually exclusive.") 578*a1e26a70SApple OSS Distributions 579*a1e26a70SApple OSS Distributions if "-C" in cmd_options: 580*a1e26a70SApple OSS Distributions cpu_no = ArgumentStringToInt(cmd_options['-C']) 581*a1e26a70SApple OSS Distributions if cpu_no not in range(0, len(log_queues)): 582*a1e26a70SApple OSS Distributions print("CPU number out of [0, {:d}) range".format(len(log_queues))) 583*a1e26a70SApple OSS Distributions return 584*a1e26a70SApple OSS Distributions log_queues = [lq for lq in log_queues if lq.cpu == cpu_no] 585*a1e26a70SApple OSS Distributions elif "-A" in cmd_options: 586*a1e26a70SApple OSS Distributions addr = ArgumentStringToInt(cmd_options['-A']) 587*a1e26a70SApple OSS Distributions log_queues = [lq for lq in log_queues if addr == lq.address] 588*a1e26a70SApple OSS Distributions if not log_queues: 589*a1e26a70SApple OSS Distributions lq = kern.GetValueFromAddress(addr, 'log_queue_t') 590*a1e26a70SApple OSS Distributions log_queues = [LogQueue(None, lq)] 591*a1e26a70SApple OSS Distributions 592*a1e26a70SApple OSS Distributions show_logs = "-L" in cmd_options 593*a1e26a70SApple OSS Distributions 594*a1e26a70SApple OSS Distributions show_log_queues(PPrinter(O), log_queues, show_logs) 595*a1e26a70SApple OSS Distributions 596*a1e26a70SApple OSS Distributions 597*a1e26a70SApple OSS Distributions@lldb_command('showmsgbuf', 'C:F') 598*a1e26a70SApple OSS Distributionsdef showMsgBuf(cmd_args=None, cmd_options=None): 599*a1e26a70SApple OSS Distributions """ Displays the contents of msgbuf_t type at a given address. 600*a1e26a70SApple OSS Distributions 601*a1e26a70SApple OSS Distributions usage: showmsgbuf [-C <num>][-F] addr 602*a1e26a70SApple OSS Distributions 603*a1e26a70SApple OSS Distributions -C <num> Shows first or last (if negative) specified number of logs. 604*a1e26a70SApple OSS Distributions -F Show the content even if the magic key indicates data corruption. 605*a1e26a70SApple OSS Distributions """ 606*a1e26a70SApple OSS Distributions 607*a1e26a70SApple OSS Distributions if cmd_args is None or len(cmd_args) == 0: 608*a1e26a70SApple OSS Distributions raise ArgumentError() 609*a1e26a70SApple OSS Distributions 610*a1e26a70SApple OSS Distributions addr = kern.GetValueFromAddress(cmd_args[0], 'struct msgbuf *') 611*a1e26a70SApple OSS Distributions 612*a1e26a70SApple OSS Distributions if addr.msg_magic != MsgBuffer.MSG_MAGIC: 613*a1e26a70SApple OSS Distributions print("Error: Invalid msgbuf_t magic key {:#x} (expected {:#x}). " 614*a1e26a70SApple OSS Distributions "Invalid address or the content is corrupted.".format(addr.msg_magic, MsgBuffer.MSG_MAGIC)) 615*a1e26a70SApple OSS Distributions if not "-F" in cmd_options: 616*a1e26a70SApple OSS Distributions return 617*a1e26a70SApple OSS Distributions 618*a1e26a70SApple OSS Distributions msgbuf = MsgBuffer(addr) 619*a1e26a70SApple OSS Distributions 620*a1e26a70SApple OSS Distributions if "-C" in cmd_options: 621*a1e26a70SApple OSS Distributions count = ArgumentStringToInt(cmd_options['-C']) 622*a1e26a70SApple OSS Distributions n = min(abs(count), len(msgbuf)) 623*a1e26a70SApple OSS Distributions msgbuf = msgbuf[:n] if count > 0 else msgbuf[-n:] 624*a1e26a70SApple OSS Distributions 625*a1e26a70SApple OSS Distributions for msg in msgbuf: 626*a1e26a70SApple OSS Distributions print(msg.rstrip("\n")) 627*a1e26a70SApple OSS Distributions 628*a1e26a70SApple OSS Distributions 629*a1e26a70SApple OSS Distributions@lldb_command('systemlog', 'C:F') 630*a1e26a70SApple OSS Distributionsdef systemLog(cmd_args=None, cmd_options=None): 631*a1e26a70SApple OSS Distributions """ Displays the contents of the system message buffer. 632*a1e26a70SApple OSS Distributions 633*a1e26a70SApple OSS Distributions usage: systemlog [-C <num>][-F] 634*a1e26a70SApple OSS Distributions 635*a1e26a70SApple OSS Distributions -C <num> Shows first or last (if negative) specified number of logs. 636*a1e26a70SApple OSS Distributions -F Show the content even if the magic key indicates data corruption. 637*a1e26a70SApple OSS Distributions """ 638*a1e26a70SApple OSS Distributions showMsgBuf([unsigned(kern.globals.msgbufp)], cmd_options) 639