1from __future__ import absolute_import, print_function 2 3from xnu import * 4from utils import * 5import sys 6 7current_KDP_mode = "swhosted" 8 9def GetKDPPacketHeaderInt(request=0, is_reply=False, seq=0, length=0, key=0): 10 """ create a 64 bit number that could be saved as pkt_hdr_t 11 params: 12 request:int - 7 bit kdp_req_t request type 13 is_reply:bool - False => request, True => reply 14 seq: int - 8 sequence number within session 15 length: int - 16 bit length of entire pkt including hdr 16 key: int - session key 17 returns: 18 int - 64 bit number to be saved in memory 19 """ 20 retval = request 21 if is_reply: 22 retval = 1<<7 |retval 23 retval = (seq << 8) | retval 24 retval = (length << 16) | retval 25 #retval = (retval << 32) | key 26 retval = (key << 32) | retval 27 return retval 28 29 30def KDPDumpInfo(subcmd, file_name="", dest_ip="", router_ip="", port=0): 31 """ Setup the state for DUMP INFO commands for sending coredump etc 32 """ 33 if "kdp" != GetConnectionProtocol(): 34 print("Target is not connected over kdp. Nothing to do here.") 35 return False 36 input_address = unsigned(addressof(kern.globals.manual_pkt.input)) 37 len_address = unsigned(addressof(kern.globals.manual_pkt.len)) 38 data_address = unsigned(addressof(kern.globals.manual_pkt.data)) 39 if not WriteInt32ToMemoryAddress(0, input_address): 40 return False 41 42 kdp_pkt_size = GetType('kdp_dumpinfo_req_t').GetByteSize() 43 if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address): 44 return False 45 46 data_addr = int(addressof(kern.globals.manual_pkt)) 47 pkt = kern.GetValueFromAddress(data_addr, 'kdp_dumpinfo_req_t *') 48 if len(file_name) > 49: 49 file_name = file_name[:49] 50 if len(dest_ip) > 15: 51 dest_ip = dest_ip[:15] 52 if len(router_ip) > 15: 53 router_ip = router_ip[:15] 54 55 header_value =GetKDPPacketHeaderInt(request=GetEnumValue('kdp_req_t::KDP_DUMPINFO'), length=kdp_pkt_size) 56 # 0x1f is same as KDP_DUMPINFO 57 if ( WriteInt64ToMemoryAddress((header_value), int(addressof(pkt.hdr))) and 58 WriteInt32ToMemoryAddress(subcmd, int(addressof(pkt.type))) and 59 WriteStringToMemoryAddress(file_name, int(addressof(pkt.name))) and 60 WriteStringToMemoryAddress(dest_ip, int(addressof(pkt.destip))) and 61 WriteStringToMemoryAddress(router_ip, int(addressof(pkt.routerip))) 62 ): 63 #We have saved important data successfully 64 if port > 0: 65 if not WriteInt32ToMemoryAddress(port, int(addressof(pkt.port))): 66 return False 67 if WriteInt32ToMemoryAddress(1, input_address): 68 return True 69 return False 70 71@lldb_command('sendcore') 72def KDPSendCore(cmd_args=None): 73 """ Configure kernel to send a coredump to the specified IP 74 Syntax: sendcore <IP address> [filename] 75 Configure the kernel to transmit a kernel coredump to a server (kdumpd) 76 at the specified IP address. This is useful when the remote target has 77 not been previously configured to transmit coredumps, and you wish to 78 preserve kernel state for later examination. NOTE: You must issue a "continue" 79 command after using this macro to trigger the kernel coredump. The kernel 80 will resume waiting in the debugger after completion of the coredump. You 81 may disable coredumps by executing the "disablecore" macro. You can 82 optionally specify the filename to be used for the generated core file. 83 84 """ 85 if cmd_args == None or len(cmd_args) < 1: 86 print(KDPSendCore.__doc__) 87 return False 88 ip_address = cmd_args[0] 89 filename="" 90 if len(cmd_args) >=2: 91 filename = cmd_args[1].strip() 92 retval = KDPDumpInfo(GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_CORE'), file_name=filename, dest_ip=ip_address) 93 if retval: 94 print("Remote system has been setup for coredump. Please detach/continue the system. ") 95 return True 96 else: 97 print("Something went wrong. Failed to setup the coredump on the target.") 98 return False 99 100 101@lldb_command('sendsyslog') 102def KDPSendSyslog(cmd_args=None): 103 """ Configure kernel to send a system log to the specified IP 104 Syntax: sendsyslog <IP address> [filename] 105 Configure the kernel to transmit a kernel system log to a server (kdumpd) 106 at the specified IP address. NOTE: You must issue a "continue" 107 command after using this macro to trigger the kernel system log. The kernel 108 will resume waiting in the debugger after completion. You can optionally 109 specify the name to be used for the generated system log. 110 """ 111 if cmd_args == None or len(cmd_args) < 1: 112 print(KDPSendSyslog.__doc__) 113 return False 114 ip_address = cmd_args[0] 115 filename ="" 116 if len(cmd_args) >=2: 117 filename = cmd_args[1].strip() 118 retval = KDPDumpInfo(GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_SYSTEMLOG'), file_name = filename, dest_ip = ip_address) 119 if retval: 120 print("Remote system has been setup to send system log. please detach/continue the system.") 121 return True 122 else: 123 print("Something went wrong. Failed to setup the systemlog on the target.") 124 return False 125 126@lldb_command('sendpaniclog') 127def KDPSendPaniclog(cmd_args=None): 128 """ Configure kernel to send a panic log to the specified IP 129 Syntax: sendpaniclog <IP address> [filename] 130 Configure the kernel to transmit a kernel paniclog to a server (kdumpd) 131 at the specified IP address. NOTE: You must issue a "continue" 132 command after using this macro to trigger the kernel panic log. The kernel 133 will resume waiting in the debugger after completion. You can optionally 134 specify the name to be used for the generated panic log. 135 """ 136 if cmd_args == None or len(cmd_args) < 1: 137 print(KDPSendPaniclog.__doc__) 138 return False 139 ip_address = cmd_args[0] 140 filename ="" 141 if len(cmd_args) >=2: 142 filename = cmd_args[1].strip() 143 retval = KDPDumpInfo(GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_PANICLOG'), file_name = filename, dest_ip = ip_address) 144 if retval: 145 print("Remote system has been setup to send panic log. please detach/continue the system.") 146 return True 147 else: 148 print("Something went wrong. Failed to setup the paniclog on the target.") 149 return False 150 151 152@lldb_command('disablecore') 153def KDPDisableCore(cmd_args=None): 154 """ Configure the kernel to disable coredump transmission 155 Reconfigures the kernel so that it no longer transmits kernel coredumps. This 156 complements the "sendcore" macro, but it may be used if the kernel has been 157 configured to transmit coredumps through boot-args as well. 158 159 """ 160 retval = KDPDumpInfo(GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_DISABLE')) 161 if retval : 162 print("Disabled coredump functionality on remote system.") 163 else: 164 print("Failed to disable coredump functionality.") 165 return retval 166 167@lldb_command('resume_on') 168def KDPResumeON(cmd_args=None): 169 """ The target system will resume when detaching or exiting from lldb. 170 This is the default behavior. 171 """ 172 subcmd = GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_SETINFO') | GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_RESUME') 173 retval = KDPDumpInfo(subcmd) 174 if retval : 175 print("Target system will resume on detaching from lldb.") 176 else: 177 print("Failed to enable resume functionality.") 178 return retval 179 180@lldb_command('resume_off') 181def KDPResumeOFF(cmd_args=None): 182 """ The target system will not resume when detaching or exiting from lldb. 183 """ 184 subcmd = GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_SETINFO') | GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_NORESUME') 185 retval = KDPDumpInfo(subcmd) 186 if retval : 187 print("Target system will not resume on detaching from lldb.") 188 else: 189 print("Failed to disable resume functionality.") 190 return retval 191 192 193 194@lldb_command('getdumpinfo') 195def KDPGetDumpInfo(cmd_args=None): 196 """ Retrieve the current remote dump settings. 197 """ 198 if not KDPDumpInfo(GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_GETINFO')): 199 print("Failed to get dump settings.") 200 return False 201 dumpinfo = Cast(addressof(kern.globals.manual_pkt.data), 'kdp_dumpinfo_reply_t *') 202 target_dump_type = int(dumpinfo.type) 203 if target_dump_type & GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_REBOOT'): 204 print("System will reboot after kernel info gets dumped.") 205 else: 206 print("System will not reboot after kernel info gets dumped.") 207 if target_dump_type & GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_RESUME'): 208 print("System will allow a re-attach after KDP disconnect.") 209 else: 210 print("System will not allow a re-attach after KDP disconnect.") 211 target_dump_type = target_dump_type & GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_MASK') 212 if target_dump_type == GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_DISABLE'): 213 print("Kernel not setup for remote dumps.") 214 else: 215 kern_dump_type = '' 216 if target_dump_type == GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_CORE'): 217 kern_dump_type = "Core File" 218 elif target_dump_type == GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_PANICLOG'): 219 kern_dump_type = "Panic Log" 220 elif target_dump_type == GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_SYSTEMLOG'): 221 kern_dump_type = "System Log" 222 print("Kernel dump type:" + kern_dump_type) 223 fname = "(autogenerated)" 224 if int(dumpinfo.name[0]) != 0: 225 fname = str(dumpinfo.name) 226 print("Filename: " + fname) 227 print("Network Info: {:s} [{:d}] , Router: {:s}".format(dumpinfo.destip, dumpinfo.port, dumpinfo.routerip)) 228 # end of get dump info 229 230 231@lldb_command('kdp-reenter') 232def KDPReenter(cmd_args=None): 233 """ Schedules reentry into the debugger 234 after <seconds> seconds, and resumes the target. 235 usage: kdp-reenter <seconds> 236 """ 237 if len(cmd_args) < 1: 238 print("Please provide valid time in seconds") 239 print(KDPReenter.__doc__) 240 return False 241 242 if "kdp" != GetConnectionProtocol(): 243 print("Target is not connected over kdp. Nothing to do here.") 244 return False 245 246 num_seconds = ArgumentStringToInt(cmd_args[0]) 247 milliseconds_to_sleep = num_seconds * 1000 248 if WriteInt32ToMemoryAddress(milliseconds_to_sleep, addressof(kern.globals.kdp_reentry_deadline)): 249 lldb.debugger.HandleCommand('process continue') 250 return True 251 print("Failed to setup kdp-reentry.") 252 return False 253 254@lldb_command('kdp-reboot') 255def KDPReboot(cmd_args=None): 256 """ Restart the remote target 257 """ 258 if "kdp" != GetConnectionProtocol(): 259 print("Target is not connected over kdp. Nothing to do here.") 260 return False 261 262 print("Rebooting the remote machine.") 263 lldb.debugger.HandleCommand('process plugin packet send --command 0x13') 264 lldb.debugger.HandleCommand('detach') 265 return True 266 267@lldb_command('setdumpinfo') 268def KDPSetDumpInfo(cmd_args=None): 269 """ Configure the current remote dump settings. 270 Specify "" if you want to use the defaults (filename) or previously configured 271 settings (ip/router). Specify 0 for the port if you wish to 272 use the previously configured/default setting for that. 273 Syntax: setdumpinfo <filename> <ip> <router> <port> 274 """ 275 if not cmd_args: 276 print(KDPSetDumpInfo.__doc__) 277 return False 278 if len(cmd_args) < 4: 279 print("Not enough arguments.") 280 print(KDPSetDumpInfo.__doc__) 281 return False 282 portnum = ArgumentStringToInt(cmd_args[3]) 283 retval = KDPDumpInfo(GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_SETINFO'), cmd_args[0], cmd_args[1], cmd_args[2], portnum) 284 if retval: 285 print("Successfully saved the dumpinfo.") 286 else: 287 print("Failed to save the dumpinfo.") 288 return retval 289 290@lldb_command('kdpmode') 291def KDPMode(cmd_args=None): 292 """ 293 Change KDP mode between software hosted and hardware probe. 294 When lldb is connected to a KDP server backed by a hardware debug tool 295 setting this to 'hwprobe' enables physical memory access. 296 297 swhosted: LLDB is connected to the target using a serial or socket connection. 298 hwprobe: LLDB is connected to the target using a hardware probe. 299 300 usage: kdpmode <mode> 301 mode: 'swhosted' or 'hwprobe' 302 """ 303 global current_KDP_mode 304 305 if cmd_args == None or len(cmd_args) == 0: 306 return current_KDP_mode 307 if len(cmd_args) > 1 or cmd_args[0] not in {'swhosted', 'hwprobe'}: 308 print("Invalid Arguments", KDPMode.__doc__) 309 else: 310 current_KDP_mode = cmd_args[0] 311 return 312 313