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