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