1""" Some of the functionality here is a copy of existing macros from memory.py 2 with the VM specific stuff removed so the macros work with any btlog. 3 Eventually the zstack macros should be refactored to reuse the generic btlog 4 support added here. 5""" 6 7from xnu import * 8 9@lldb_type_summary(['btlog_t *']) 10@header("{0: <20s} {1: <9s} {2: <6s} {3: >9s}".format("btlog", "capacity", "depth", "count")) 11def GetBTLogSummary(btlog): 12 """ Summarizes btlog structure. 13 params: btlog: value - value object representing a btlog in kernel 14 returns: str - summary of the btlog 15 """ 16 17 index = btlog.head 18 records = btlog.btrecords 19 record_size = btlog.btrecord_size 20 count = 0 21 22 while index != 0xffffff: 23 addr = records + (index * record_size) 24 record = kern.GetValueFromAddress(addr, 'btlog_record_t *') 25 index = record.next 26 count += 1 27 28 capacity = (btlog.btlog_buffersize - sizeof('btlog_t')) / btlog.btrecord_size 29 30 format_string = "{0: <#20x} {1: <9d} {2: <6d} {3: >9d}" 31 32 return format_string.format(btlog, capacity, btlog.btrecord_btdepth, count) 33 34def GetBTLogEntryBacktrace(depth, record): 35 """ Helper routine for getting a btlog record backtrace stack. 36 params: 37 depth:int - The depth of the stack record 38 record:btlog_record_t * - A btlog record 39 returns: 40 str - string with backtrace in it. 41 """ 42 out_str = '' 43 frame = 0 44 if not record: 45 return "no record!" 46 47 depth_val = unsigned(depth) 48 while frame < depth_val: 49 frame_pc = record.bt[frame] 50 if not frame_pc or int(frame_pc) == 0: 51 break 52 symbol_arr = kern.SymbolicateFromAddress(frame_pc) 53 if symbol_arr: 54 symbol_str = str(symbol_arr[0].addr) 55 else: 56 symbol_str = '' 57 out_str += "{0: <#0x} <{1: <s}>\n".format(frame_pc, symbol_str) 58 frame += 1 59 return out_str 60 61def ShowBTLogRecord(record, index, depth, count): 62 """ Helper routine for printing a single btlog record 63 params: 64 record:btlog_record_t * - A BTLog record 65 index:int - Index for the record in the BTLog table 66 depth:int - Depth of stack 67 count:int - Active count 68 returns: 69 None 70 """ 71 72 out_str = ('-' * 8) 73 out_str += " OP {0: <d} Stack Index {1: <d} with active refs {2: <d} of {3: <d} {4: <s}\n".format(record.operation, index, record.ref_count, count, ('-' * 8)) 74 print out_str 75 print GetBTLogEntryBacktrace(depth, record) 76 print " \n" 77 78# Macro: showbtlog 79@lldb_command('showbtlog') 80def ShowBTLogHelper(cmd_args=None): 81 """ Display a summary of the specified btlog 82 Usage: showbtlog <btlog address> 83 """ 84 85 btlog = kern.GetValueFromAddress(cmd_args[0], 'btlog_t *') 86 if not btlog: 87 raise ("Unknown arguments: %r" % cmd_args) 88 89 print GetBTLogSummary.header 90 print GetBTLogSummary(btlog) 91 92# EndMacro: showbtlog 93 94 95# Macro: showbtlogrecords 96 97@lldb_command('showbtlogrecords', 'E:') 98def ShowBTLog(cmd_args=None, cmd_options={}): 99 """ Print all records in the btlog from head to tail. 100 Usage: showbtlogrecords <btlog addr> 101 """ 102 if not cmd_args: 103 print "Print contents of btlog. \nUsage: showbtlogrecords <btlog addr>" 104 return 105 106 if "-E" in cmd_options: 107 108 element = kern.GetValueFromAddress(cmd_options["-E"], 'void *') 109 else: 110 element = None 111 112 btlog = kern.GetValueFromAddress(cmd_args[0], 'btlog_t *') 113 if not btlog: 114 raise ("Unknown arguments: %r" % cmd_args) 115 116 records = btlog.btrecords 117 record_size = btlog.btrecord_size 118 depth = btlog.btrecord_btdepth 119 count = btlog.active_element_count; 120 121 if not element: 122 123 index = btlog.head 124 while index != 0xffffff: 125 addr = records + (index * record_size) 126 record = kern.GetValueFromAddress(addr, 'btlog_record_t *') 127 ShowBTLogRecord(record, index, depth, count) 128 index = record.next 129 130 else: 131 132 if btlog.caller_will_remove_entries_for_element == 1: 133 print "'-E' not supported with this type of btlog" 134 return 135 136 if (element >> 32) != 0: 137 element = element ^ 0xFFFFFFFFFFFFFFFF 138 else: 139 element = element ^ 0xFFFFFFFF 140 141 scan_items = 0 142 hashelem = cast(btlog.elem_linkage_un.element_hash_queue.tqh_first, 143 'btlog_element_t *') 144 while hashelem != 0: 145 146 if unsigned(hashelem.elem) == element: 147 recindex = hashelem.recindex 148 recoffset = recindex * record_size 149 record = kern.GetValueFromAddress(records + recoffset, 150 'btlog_record_t *') 151 ShowBTLogRecord(record, recindex, depth, count) 152 scan_items = 0 153 154 hashelem = cast(hashelem.element_hash_link.tqe_next, 'btlog_element_t *') 155 scan_items += 1 156 if scan_items % 100 == 0: 157 print "Scanning is ongoing. {0: <d} items scanned since last check." \ 158 .format(scan_items) 159 160# EndMacro : showbtlogrecords 161