]>
Commit | Line | Data |
---|---|---|
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 |