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