]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
14 | * | |
15 | * Please obtain a copy of the License at | |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
25 | * | |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
27 | */ | |
28 | ||
29 | /* | |
30 | * Copyright (c) 1982, 1986, 1993 | |
31 | * The Regents of the University of California. All rights reserved. | |
32 | */ | |
33 | ||
34 | /* | |
35 | * Kernel Debugging Protocol UDP implementation. | |
36 | */ | |
37 | ||
38 | #include <mach_kdb.h> | |
39 | #include <mach/boolean.h> | |
40 | #include <mach/mach_types.h> | |
41 | #include <mach/exception_types.h> | |
42 | #include <kern/cpu_data.h> | |
43 | #include <kern/debug.h> | |
44 | ||
45 | #include <kdp/kdp_core.h> | |
46 | #include <kdp/kdp_internal.h> | |
47 | #include <kdp/kdp_en_debugger.h> | |
48 | #include <kdp/kdp_udp.h> | |
49 | ||
50 | #include <vm/vm_map.h> | |
51 | #include <vm/vm_protos.h> | |
52 | #include <vm/vm_kern.h> /* kernel_map */ | |
53 | ||
54 | #include <mach/memory_object_types.h> | |
55 | ||
56 | #include <string.h> | |
57 | ||
58 | #define DO_ALIGN 1 /* align all packet data accesses */ | |
59 | ||
60 | extern int kdp_getc(void); | |
61 | extern int reattach_wait; | |
62 | ||
63 | static u_short ip_id; /* ip packet ctr, for ids */ | |
64 | ||
65 | /* @(#)udp_usrreq.c 2.2 88/05/23 4.0NFSSRC SMI; from UCB 7.1 6/5/86 */ | |
66 | ||
67 | /* | |
68 | * UDP protocol implementation. | |
69 | * Per RFC 768, August, 1980. | |
70 | */ | |
71 | #define UDP_TTL 60 /* deflt time to live for UDP packets */ | |
72 | int udp_ttl = UDP_TTL; | |
73 | static unsigned char exception_seq; | |
74 | ||
75 | static struct { | |
76 | unsigned char data[KDP_MAXPACKET]; | |
77 | unsigned int off, len; | |
78 | boolean_t input; | |
79 | } pkt, saved_reply; | |
80 | ||
81 | struct { | |
82 | struct { | |
83 | struct in_addr in; | |
84 | struct ether_addr ea; | |
85 | } loc; | |
86 | struct { | |
87 | struct in_addr in; | |
88 | struct ether_addr ea; | |
89 | } rmt; | |
90 | } adr; | |
91 | ||
92 | static const char | |
93 | *exception_message[] = { | |
94 | "Unknown", | |
95 | "Memory access", /* EXC_BAD_ACCESS */ | |
96 | "Failed instruction", /* EXC_BAD_INSTRUCTION */ | |
97 | "Arithmetic", /* EXC_ARITHMETIC */ | |
98 | "Emulation", /* EXC_EMULATION */ | |
99 | "Software", /* EXC_SOFTWARE */ | |
100 | "Breakpoint" /* EXC_BREAKPOINT */ | |
101 | }; | |
102 | ||
103 | volatile int kdp_flag = 0; | |
104 | ||
105 | static kdp_send_t kdp_en_send_pkt; | |
106 | static kdp_receive_t kdp_en_recv_pkt; | |
107 | ||
108 | ||
109 | static u_long kdp_current_ip_address = 0; | |
110 | static struct ether_addr kdp_current_mac_address = {{0, 0, 0, 0, 0, 0}}; | |
111 | static void *kdp_current_ifp; | |
112 | ||
113 | static void kdp_handler( void *); | |
114 | ||
115 | static uint32_t panic_server_ip = 0; | |
116 | static uint32_t parsed_router_ip = 0; | |
117 | static uint32_t router_ip = 0; | |
118 | static uint32_t target_ip = 0; | |
119 | ||
120 | static volatile boolean_t panicd_specified = FALSE; | |
121 | static boolean_t router_specified = FALSE; | |
122 | static unsigned int panicd_port = CORE_REMOTE_PORT; | |
123 | ||
124 | static struct ether_addr etherbroadcastaddr = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}; | |
125 | ||
126 | static struct ether_addr router_mac = {{0, 0, 0 , 0, 0, 0}}; | |
127 | static struct ether_addr destination_mac = {{0, 0, 0 , 0, 0, 0}}; | |
128 | static struct ether_addr temp_mac = {{0, 0, 0 , 0, 0, 0}}; | |
129 | static struct ether_addr current_resolved_MAC = {{0, 0, 0 , 0, 0, 0}}; | |
130 | ||
131 | static boolean_t flag_panic_dump_in_progress = FALSE; | |
132 | static boolean_t flag_router_mac_initialized = FALSE; | |
133 | ||
134 | static boolean_t flag_arp_resolved = FALSE; | |
135 | ||
136 | static unsigned int panic_timeout = 100000; | |
137 | static unsigned int last_panic_port = CORE_REMOTE_PORT; | |
138 | ||
139 | unsigned int SEGSIZE = 512; | |
140 | ||
141 | __unused static unsigned int PANIC_PKTSIZE = 518; | |
142 | static char panicd_ip_str[20]; | |
143 | static char router_ip_str[20]; | |
144 | ||
145 | static unsigned int panic_block = 0; | |
146 | volatile unsigned int kdp_trigger_core_dump = 0; | |
147 | __private_extern__ volatile unsigned int flag_kdp_trigger_reboot = 0; | |
148 | ||
149 | extern unsigned int not_in_kdp; | |
150 | ||
151 | extern unsigned int disableConsoleOutput; | |
152 | ||
153 | extern int kdp_vm_read( caddr_t, caddr_t, unsigned int); | |
154 | extern void kdp_call(void); | |
155 | extern boolean_t kdp_call_kdb(void); | |
156 | extern int kern_dump(void); | |
157 | ||
158 | void * kdp_get_interface(void); | |
159 | void kdp_set_gateway_mac(void *); | |
160 | void kdp_set_ip_and_mac_addresses(struct in_addr *, struct ether_addr *); | |
161 | void kdp_set_interface(void *); | |
162 | ||
163 | void kdp_disable_arp(void); | |
164 | static void kdp_arp_reply(struct ether_arp *); | |
165 | static void kdp_process_arp_reply(struct ether_arp *); | |
166 | static boolean_t kdp_arp_resolve(uint32_t, struct ether_addr *); | |
167 | ||
168 | static volatile unsigned kdp_reentry_deadline; | |
169 | ||
170 | static boolean_t gKDPDebug = FALSE; | |
171 | #define KDP_DEBUG(...) if (gKDPDebug) printf(__VA_ARGS__); | |
172 | ||
173 | int kdp_snapshot = 0; | |
174 | static int stack_snapshot_ret = 0; | |
175 | static unsigned stack_snapshot_bytes_traced = 0; | |
176 | ||
177 | static void *stack_snapshot_buf; | |
178 | static uint32_t stack_snapshot_bufsize; | |
179 | static int stack_snapshot_pid; | |
180 | static uint32_t stack_snapshot_options; | |
181 | ||
182 | static unsigned int old_debugger; | |
183 | ||
184 | void | |
185 | kdp_snapshot_preflight(int pid, void * tracebuf, uint32_t tracebuf_size, | |
186 | uint32_t options); | |
187 | ||
188 | void | |
189 | kdp_snapshot_postflight(void); | |
190 | ||
191 | extern int | |
192 | kdp_stackshot(int pid, void *tracebuf, uint32_t tracebuf_size, | |
193 | unsigned trace_options, uint32_t *pbytesTraced); | |
194 | ||
195 | int | |
196 | kdp_stack_snapshot_geterror(void); | |
197 | ||
198 | int | |
199 | kdp_stack_snapshot_bytes_traced(void); | |
200 | ||
201 | static thread_call_t | |
202 | kdp_timer_call; | |
203 | ||
204 | static void | |
205 | kdp_ml_enter_debugger_wrapper(__unused void *param0, __unused void *param1) { | |
206 | kdp_ml_enter_debugger(); | |
207 | } | |
208 | ||
209 | static void | |
210 | kdp_timer_callout_init(void) { | |
211 | kdp_timer_call = thread_call_allocate(kdp_ml_enter_debugger_wrapper, NULL); | |
212 | } | |
213 | ||
214 | ||
215 | void | |
216 | kdp_register_send_receive( | |
217 | kdp_send_t send, | |
218 | kdp_receive_t receive) | |
219 | { | |
220 | unsigned int debug = 0; | |
221 | ||
222 | kdp_en_send_pkt = send; | |
223 | kdp_en_recv_pkt = receive; | |
224 | ||
225 | debug_log_init(); | |
226 | ||
227 | kdp_timer_callout_init(); | |
228 | ||
229 | PE_parse_boot_arg("debug", &debug); | |
230 | ||
231 | ||
232 | if (!debug) | |
233 | return; | |
234 | ||
235 | if (debug & DB_KDP_BP_DIS) | |
236 | kdp_flag |= KDP_BP_DIS; | |
237 | if (debug & DB_KDP_GETC_ENA) | |
238 | kdp_flag |= KDP_GETC_ENA; | |
239 | if (debug & DB_ARP) | |
240 | kdp_flag |= KDP_ARP; | |
241 | ||
242 | if (debug & DB_KERN_DUMP_ON_PANIC) | |
243 | kdp_flag |= KDP_PANIC_DUMP_ENABLED; | |
244 | if (debug & DB_KERN_DUMP_ON_NMI) | |
245 | kdp_flag |= PANIC_CORE_ON_NMI; | |
246 | ||
247 | if (debug & DB_DBG_POST_CORE) | |
248 | kdp_flag |= DBG_POST_CORE; | |
249 | ||
250 | if (debug & DB_PANICLOG_DUMP) | |
251 | kdp_flag |= PANIC_LOG_DUMP; | |
252 | ||
253 | if (PE_parse_boot_arg ("_panicd_ip", panicd_ip_str)) | |
254 | panicd_specified = TRUE; | |
255 | ||
256 | if (PE_parse_boot_arg ("_router_ip", router_ip_str)) | |
257 | router_specified = TRUE; | |
258 | ||
259 | if (!PE_parse_boot_arg ("panicd_port", &panicd_port)) | |
260 | panicd_port = CORE_REMOTE_PORT; | |
261 | ||
262 | kdp_flag |= KDP_READY; | |
263 | if (current_debugger == NO_CUR_DB) | |
264 | current_debugger = KDP_CUR_DB; | |
265 | if ((kdp_current_ip_address != 0) && halt_in_debugger) { | |
266 | kdp_call(); | |
267 | halt_in_debugger=0; | |
268 | } | |
269 | } | |
270 | ||
271 | void | |
272 | kdp_unregister_send_receive( | |
273 | __unused kdp_send_t send, | |
274 | __unused kdp_receive_t receive) | |
275 | { | |
276 | if (current_debugger == KDP_CUR_DB) | |
277 | current_debugger = NO_CUR_DB; | |
278 | kdp_flag &= ~KDP_READY; | |
279 | kdp_en_send_pkt = NULL; | |
280 | kdp_en_recv_pkt = NULL; | |
281 | } | |
282 | ||
283 | /* Cache stack snapshot parameters in preparation for a trace */ | |
284 | void | |
285 | kdp_snapshot_preflight(int pid, void * tracebuf, uint32_t tracebuf_size, uint32_t options) | |
286 | { | |
287 | stack_snapshot_pid = pid; | |
288 | stack_snapshot_buf = tracebuf; | |
289 | stack_snapshot_bufsize = tracebuf_size; | |
290 | stack_snapshot_options = options; | |
291 | kdp_snapshot++; | |
292 | /* Mark this debugger as active, since the polled mode driver that | |
293 | * ordinarily does this may not be enabled (yet), or since KDB may be | |
294 | * the primary debugger. | |
295 | */ | |
296 | old_debugger = current_debugger; | |
297 | if (old_debugger != KDP_CUR_DB) { | |
298 | current_debugger = KDP_CUR_DB; | |
299 | } | |
300 | } | |
301 | ||
302 | void | |
303 | kdp_snapshot_postflight(void) | |
304 | { | |
305 | kdp_snapshot--; | |
306 | if ((kdp_en_send_pkt == NULL) || (old_debugger == KDB_CUR_DB)) | |
307 | current_debugger = old_debugger; | |
308 | } | |
309 | ||
310 | int | |
311 | kdp_stack_snapshot_geterror(void) | |
312 | { | |
313 | return stack_snapshot_ret; | |
314 | } | |
315 | ||
316 | int | |
317 | kdp_stack_snapshot_bytes_traced(void) | |
318 | { | |
319 | return stack_snapshot_bytes_traced; | |
320 | } | |
321 | ||
322 | static void | |
323 | kdp_schedule_debugger_reentry(unsigned interval) { | |
324 | uint64_t deadline;; | |
325 | ||
326 | clock_interval_to_deadline(interval, 1000 * 1000, &deadline); | |
327 | thread_call_enter_delayed(kdp_timer_call, deadline); | |
328 | } | |
329 | ||
330 | static void | |
331 | enaddr_copy( | |
332 | void *src, | |
333 | void *dst | |
334 | ) | |
335 | { | |
336 | bcopy((char *)src, (char *)dst, sizeof (struct ether_addr)); | |
337 | } | |
338 | ||
339 | static unsigned short | |
340 | ip_sum( | |
341 | unsigned char *c, | |
342 | unsigned int hlen | |
343 | ) | |
344 | { | |
345 | unsigned int high, low, sum; | |
346 | ||
347 | high = low = 0; | |
348 | while (hlen-- > 0) { | |
349 | low += c[1] + c[3]; | |
350 | high += c[0] + c[2]; | |
351 | ||
352 | c += sizeof (int); | |
353 | } | |
354 | ||
355 | sum = (high << 8) + low; | |
356 | sum = (sum >> 16) + (sum & 65535); | |
357 | ||
358 | return (sum > 65535 ? sum - 65535 : sum); | |
359 | } | |
360 | ||
361 | static void | |
362 | kdp_reply( | |
363 | unsigned short reply_port | |
364 | ) | |
365 | { | |
366 | struct udpiphdr aligned_ui, *ui = &aligned_ui; | |
367 | struct ip aligned_ip, *ip = &aligned_ip; | |
368 | struct in_addr tmp_ipaddr; | |
369 | struct ether_addr tmp_enaddr; | |
370 | struct ether_header *eh = NULL; | |
371 | ||
372 | if (!pkt.input) | |
373 | kdp_panic("kdp_reply"); | |
374 | ||
375 | pkt.off -= sizeof (struct udpiphdr); | |
376 | ||
377 | #if DO_ALIGN | |
378 | bcopy((char *)&pkt.data[pkt.off], (char *)ui, sizeof(*ui)); | |
379 | #else | |
380 | ui = (struct udpiphdr *)&pkt.data[pkt.off]; | |
381 | #endif | |
382 | ui->ui_next = ui->ui_prev = NULL; | |
383 | ui->ui_x1 = 0; | |
384 | ui->ui_pr = IPPROTO_UDP; | |
385 | ui->ui_len = htons((u_short)pkt.len + sizeof (struct udphdr)); | |
386 | tmp_ipaddr = ui->ui_src; | |
387 | ui->ui_src = ui->ui_dst; | |
388 | ui->ui_dst = tmp_ipaddr; | |
389 | ui->ui_sport = htons(KDP_REMOTE_PORT); | |
390 | ui->ui_dport = reply_port; | |
391 | ui->ui_ulen = ui->ui_len; | |
392 | ui->ui_sum = 0; | |
393 | #if DO_ALIGN | |
394 | bcopy((char *)ui, (char *)&pkt.data[pkt.off], sizeof(*ui)); | |
395 | bcopy((char *)&pkt.data[pkt.off], (char *)ip, sizeof(*ip)); | |
396 | #else | |
397 | ip = (struct ip *)&pkt.data[pkt.off]; | |
398 | #endif | |
399 | ip->ip_len = htons(sizeof (struct udpiphdr) + pkt.len); | |
400 | ip->ip_v = IPVERSION; | |
401 | ip->ip_id = htons(ip_id++); | |
402 | ip->ip_hl = sizeof (struct ip) >> 2; | |
403 | ip->ip_ttl = udp_ttl; | |
404 | ip->ip_sum = 0; | |
405 | ip->ip_sum = htons(~ip_sum((unsigned char *)ip, ip->ip_hl)); | |
406 | #if DO_ALIGN | |
407 | bcopy((char *)ip, (char *)&pkt.data[pkt.off], sizeof(*ip)); | |
408 | #endif | |
409 | ||
410 | pkt.len += sizeof (struct udpiphdr); | |
411 | ||
412 | pkt.off -= sizeof (struct ether_header); | |
413 | ||
414 | eh = (struct ether_header *)&pkt.data[pkt.off]; | |
415 | enaddr_copy(eh->ether_shost, &tmp_enaddr); | |
416 | enaddr_copy(eh->ether_dhost, eh->ether_shost); | |
417 | enaddr_copy(&tmp_enaddr, eh->ether_dhost); | |
418 | eh->ether_type = htons(ETHERTYPE_IP); | |
419 | ||
420 | pkt.len += sizeof (struct ether_header); | |
421 | ||
422 | // save reply for possible retransmission | |
423 | bcopy((char *)&pkt, (char *)&saved_reply, sizeof(pkt)); | |
424 | ||
425 | (*kdp_en_send_pkt)(&pkt.data[pkt.off], pkt.len); | |
426 | ||
427 | // increment expected sequence number | |
428 | exception_seq++; | |
429 | } | |
430 | ||
431 | static void | |
432 | kdp_send( | |
433 | unsigned short remote_port | |
434 | ) | |
435 | { | |
436 | struct udpiphdr aligned_ui, *ui = &aligned_ui; | |
437 | struct ip aligned_ip, *ip = &aligned_ip; | |
438 | struct ether_header *eh; | |
439 | ||
440 | if (pkt.input) | |
441 | kdp_panic("kdp_send"); | |
442 | ||
443 | pkt.off -= sizeof (struct udpiphdr); | |
444 | ||
445 | #if DO_ALIGN | |
446 | bcopy((char *)&pkt.data[pkt.off], (char *)ui, sizeof(*ui)); | |
447 | #else | |
448 | ui = (struct udpiphdr *)&pkt.data[pkt.off]; | |
449 | #endif | |
450 | ui->ui_next = ui->ui_prev = NULL; | |
451 | ui->ui_x1 = 0; | |
452 | ui->ui_pr = IPPROTO_UDP; | |
453 | ui->ui_len = htons((u_short)pkt.len + sizeof (struct udphdr)); | |
454 | ui->ui_src = adr.loc.in; | |
455 | ui->ui_dst = adr.rmt.in; | |
456 | ui->ui_sport = htons(KDP_REMOTE_PORT); | |
457 | ui->ui_dport = remote_port; | |
458 | ui->ui_ulen = ui->ui_len; | |
459 | ui->ui_sum = 0; | |
460 | #if DO_ALIGN | |
461 | bcopy((char *)ui, (char *)&pkt.data[pkt.off], sizeof(*ui)); | |
462 | bcopy((char *)&pkt.data[pkt.off], (char *)ip, sizeof(*ip)); | |
463 | #else | |
464 | ip = (struct ip *)&pkt.data[pkt.off]; | |
465 | #endif | |
466 | ip->ip_len = htons(sizeof (struct udpiphdr) + pkt.len); | |
467 | ip->ip_v = IPVERSION; | |
468 | ip->ip_id = htons(ip_id++); | |
469 | ip->ip_hl = sizeof (struct ip) >> 2; | |
470 | ip->ip_ttl = udp_ttl; | |
471 | ip->ip_sum = 0; | |
472 | ip->ip_sum = htons(~ip_sum((unsigned char *)ip, ip->ip_hl)); | |
473 | #if DO_ALIGN | |
474 | bcopy((char *)ip, (char *)&pkt.data[pkt.off], sizeof(*ip)); | |
475 | #endif | |
476 | ||
477 | pkt.len += sizeof (struct udpiphdr); | |
478 | ||
479 | pkt.off -= sizeof (struct ether_header); | |
480 | ||
481 | eh = (struct ether_header *)&pkt.data[pkt.off]; | |
482 | enaddr_copy(&adr.loc.ea, eh->ether_shost); | |
483 | enaddr_copy(&adr.rmt.ea, eh->ether_dhost); | |
484 | eh->ether_type = htons(ETHERTYPE_IP); | |
485 | ||
486 | pkt.len += sizeof (struct ether_header); | |
487 | (*kdp_en_send_pkt)(&pkt.data[pkt.off], pkt.len); | |
488 | } | |
489 | ||
490 | /* We don't interpret this pointer, we just give it to the | |
491 | bsd stack so it can decide when to set the MAC and IP info. */ | |
492 | void | |
493 | kdp_set_interface(void *ifp) | |
494 | { | |
495 | kdp_current_ifp = ifp; | |
496 | } | |
497 | ||
498 | void * | |
499 | kdp_get_interface(void) | |
500 | { | |
501 | return kdp_current_ifp; | |
502 | } | |
503 | ||
504 | void | |
505 | kdp_set_ip_and_mac_addresses( | |
506 | struct in_addr *ipaddr, | |
507 | struct ether_addr *macaddr) | |
508 | { | |
509 | kdp_current_ip_address = ipaddr->s_addr; | |
510 | kdp_current_mac_address = *macaddr; | |
511 | if ((current_debugger == KDP_CUR_DB) && halt_in_debugger) { | |
512 | kdp_call(); | |
513 | halt_in_debugger=0; | |
514 | } | |
515 | } | |
516 | ||
517 | void | |
518 | kdp_set_gateway_mac(void *gatewaymac) | |
519 | { | |
520 | router_mac = *(struct ether_addr *)gatewaymac; | |
521 | flag_router_mac_initialized = TRUE; | |
522 | } | |
523 | ||
524 | struct ether_addr | |
525 | kdp_get_mac_addr(void) | |
526 | { | |
527 | return kdp_current_mac_address; | |
528 | } | |
529 | ||
530 | unsigned int | |
531 | kdp_get_ip_address(void) | |
532 | { | |
533 | return kdp_current_ip_address; | |
534 | } | |
535 | ||
536 | void | |
537 | kdp_disable_arp(void) | |
538 | { | |
539 | kdp_flag &= ~(DB_ARP); | |
540 | } | |
541 | ||
542 | static void | |
543 | kdp_arp_dispatch(void) | |
544 | { | |
545 | struct ether_arp aligned_ea, *ea = &aligned_ea; | |
546 | unsigned arp_header_offset; | |
547 | ||
548 | arp_header_offset = sizeof(struct ether_header) + pkt.off; | |
549 | memcpy((void *)ea, (void *)&pkt.data[arp_header_offset], sizeof(*ea)); | |
550 | ||
551 | switch(ntohs(ea->arp_op)) { | |
552 | case ARPOP_REQUEST: | |
553 | kdp_arp_reply(ea); | |
554 | break; | |
555 | case ARPOP_REPLY: | |
556 | kdp_process_arp_reply(ea); | |
557 | break; | |
558 | default: | |
559 | return; | |
560 | } | |
561 | } | |
562 | ||
563 | static void | |
564 | kdp_process_arp_reply(struct ether_arp *ea) | |
565 | { | |
566 | /* Are we interested in ARP replies? */ | |
567 | if (flag_arp_resolved == TRUE) | |
568 | return; | |
569 | ||
570 | /* Did we receive a reply from the right source? */ | |
571 | if (((struct in_addr *)(ea->arp_spa))->s_addr != target_ip) | |
572 | return; | |
573 | ||
574 | flag_arp_resolved = TRUE; | |
575 | current_resolved_MAC = *(struct ether_addr *) (ea->arp_sha); | |
576 | ||
577 | return; | |
578 | } | |
579 | ||
580 | /* ARP responses are enabled when the DB_ARP bit of the debug boot arg | |
581 | * is set. | |
582 | */ | |
583 | ||
584 | static void | |
585 | kdp_arp_reply(struct ether_arp *ea) | |
586 | { | |
587 | struct ether_header *eh; | |
588 | ||
589 | struct in_addr isaddr, itaddr, myaddr; | |
590 | struct ether_addr my_enaddr; | |
591 | ||
592 | eh = (struct ether_header *)&pkt.data[pkt.off]; | |
593 | pkt.off += sizeof(struct ether_header); | |
594 | ||
595 | if(ntohs(ea->arp_op) != ARPOP_REQUEST) | |
596 | return; | |
597 | ||
598 | myaddr.s_addr = kdp_get_ip_address(); | |
599 | my_enaddr = kdp_get_mac_addr(); | |
600 | ||
601 | if ((ntohl(myaddr.s_addr) == 0) || | |
602 | ((my_enaddr.ether_addr_octet[0] & 0xff) == 0 | |
603 | && (my_enaddr.ether_addr_octet[1] & 0xff) == 0 | |
604 | && (my_enaddr.ether_addr_octet[2] & 0xff) == 0 | |
605 | && (my_enaddr.ether_addr_octet[3] & 0xff) == 0 | |
606 | && (my_enaddr.ether_addr_octet[4] & 0xff) == 0 | |
607 | && (my_enaddr.ether_addr_octet[5] & 0xff) == 0 | |
608 | )) | |
609 | return; | |
610 | ||
611 | (void)memcpy((void *)&isaddr, (void *)ea->arp_spa, sizeof (isaddr)); | |
612 | (void)memcpy((void *)&itaddr, (void *)ea->arp_tpa, sizeof (itaddr)); | |
613 | ||
614 | if (itaddr.s_addr == myaddr.s_addr) { | |
615 | (void)memcpy((void *)ea->arp_tha, (void *)ea->arp_sha, sizeof(ea->arp_sha)); | |
616 | (void)memcpy((void *)ea->arp_sha, (void *)&my_enaddr, sizeof(ea->arp_sha)); | |
617 | ||
618 | (void)memcpy((void *)ea->arp_tpa, (void *) ea->arp_spa, sizeof(ea->arp_spa)); | |
619 | (void)memcpy((void *)ea->arp_spa, (void *) &itaddr, sizeof(ea->arp_spa)); | |
620 | ||
621 | ea->arp_op = htons(ARPOP_REPLY); | |
622 | ea->arp_pro = htons(ETHERTYPE_IP); | |
623 | (void)memcpy(eh->ether_dhost, ea->arp_tha, sizeof(eh->ether_dhost)); | |
624 | (void)memcpy(eh->ether_shost, &my_enaddr, sizeof(eh->ether_shost)); | |
625 | eh->ether_type = htons(ETHERTYPE_ARP); | |
626 | (void)memcpy(&pkt.data[pkt.off], ea, sizeof(*ea)); | |
627 | pkt.off -= sizeof (struct ether_header); | |
628 | /* pkt.len is still the length we want, ether_header+ether_arp */ | |
629 | (*kdp_en_send_pkt)(&pkt.data[pkt.off], pkt.len); | |
630 | } | |
631 | } | |
632 | ||
633 | static void | |
634 | kdp_poll(void) | |
635 | { | |
636 | struct ether_header *eh = NULL; | |
637 | struct udpiphdr aligned_ui, *ui = &aligned_ui; | |
638 | struct ip aligned_ip, *ip = &aligned_ip; | |
639 | static int msg_printed; | |
640 | ||
641 | if (pkt.input) | |
642 | kdp_panic("kdp_poll"); | |
643 | ||
644 | if (!kdp_en_recv_pkt || !kdp_en_send_pkt) { | |
645 | if( msg_printed == 0) { | |
646 | msg_printed = 1; | |
647 | printf("kdp_poll: no debugger device\n"); | |
648 | } | |
649 | return; | |
650 | } | |
651 | ||
652 | pkt.off = pkt.len = 0; | |
653 | (*kdp_en_recv_pkt)(pkt.data, &pkt.len, 3/* ms */); | |
654 | ||
655 | if (pkt.len == 0) | |
656 | return; | |
657 | ||
658 | if (pkt.len >= sizeof(struct ether_header)) | |
659 | { | |
660 | eh = (struct ether_header *)&pkt.data[pkt.off]; | |
661 | ||
662 | if (kdp_flag & KDP_ARP) | |
663 | { | |
664 | if (ntohs(eh->ether_type) == ETHERTYPE_ARP) | |
665 | { | |
666 | kdp_arp_dispatch(); | |
667 | return; | |
668 | } | |
669 | } | |
670 | } | |
671 | ||
672 | if (pkt.len < (sizeof (struct ether_header) + sizeof (struct udpiphdr))) | |
673 | return; | |
674 | ||
675 | pkt.off += sizeof (struct ether_header); | |
676 | if (ntohs(eh->ether_type) != ETHERTYPE_IP) { | |
677 | return; | |
678 | } | |
679 | ||
680 | #if DO_ALIGN | |
681 | bcopy((char *)&pkt.data[pkt.off], (char *)ui, sizeof(*ui)); | |
682 | bcopy((char *)&pkt.data[pkt.off], (char *)ip, sizeof(*ip)); | |
683 | #else | |
684 | ui = (struct udpiphdr *)&pkt.data[pkt.off]; | |
685 | ip = (struct ip *)&pkt.data[pkt.off]; | |
686 | #endif | |
687 | ||
688 | pkt.off += sizeof (struct udpiphdr); | |
689 | if (ui->ui_pr != IPPROTO_UDP) { | |
690 | return; | |
691 | } | |
692 | ||
693 | if (ip->ip_hl > (sizeof (struct ip) >> 2)) { | |
694 | return; | |
695 | } | |
696 | ||
697 | if (ntohs(ui->ui_dport) != KDP_REMOTE_PORT) { | |
698 | if (panicd_port == (ntohs(ui->ui_dport)) && | |
699 | flag_panic_dump_in_progress) { | |
700 | last_panic_port = ui->ui_sport; | |
701 | } | |
702 | else | |
703 | return; | |
704 | } | |
705 | /* If we receive a kernel debugging packet whilst a | |
706 | * core dump is in progress, abort the transfer and | |
707 | * enter the debugger. | |
708 | */ | |
709 | else | |
710 | if (flag_panic_dump_in_progress) | |
711 | { | |
712 | abort_panic_transfer(); | |
713 | return; | |
714 | } | |
715 | ||
716 | if (!kdp.is_conn && !flag_panic_dump_in_progress) { | |
717 | enaddr_copy(eh->ether_dhost, &adr.loc.ea); | |
718 | adr.loc.in = ui->ui_dst; | |
719 | ||
720 | enaddr_copy(eh->ether_shost, &adr.rmt.ea); | |
721 | adr.rmt.in = ui->ui_src; | |
722 | } | |
723 | ||
724 | /* | |
725 | * Calculate kdp packet length. | |
726 | */ | |
727 | pkt.len = ntohs((u_short)ui->ui_ulen) - sizeof (struct udphdr); | |
728 | pkt.input = TRUE; | |
729 | } | |
730 | ||
731 | /* Create and transmit an ARP resolution request for the target IP address. | |
732 | * This is modeled on ether_inet_arp()/RFC 826. | |
733 | */ | |
734 | ||
735 | static void | |
736 | transmit_ARP_request(uint32_t ip_addr) | |
737 | { | |
738 | struct ether_header *eh = (struct ether_header *) &pkt.data[0]; | |
739 | struct ether_arp *ea = (struct ether_arp *) &pkt.data[sizeof(struct ether_header)]; | |
740 | ||
741 | KDP_DEBUG("Transmitting ARP request\n"); | |
742 | /* Populate the ether_header */ | |
743 | eh->ether_type = htons(ETHERTYPE_ARP); | |
744 | enaddr_copy(&kdp_current_mac_address, eh->ether_shost); | |
745 | enaddr_copy(ðerbroadcastaddr, eh->ether_dhost); | |
746 | ||
747 | /* Populate the ARP header */ | |
748 | ea->arp_pro = htons(ETHERTYPE_IP); | |
749 | ea->arp_hln = sizeof(ea->arp_sha); | |
750 | ea->arp_pln = sizeof(ea->arp_spa); | |
751 | ea->arp_hrd = htons(ARPHRD_ETHER); | |
752 | ea->arp_op = htons(ARPOP_REQUEST); | |
753 | ||
754 | /* Target fields */ | |
755 | enaddr_copy(ðerbroadcastaddr, ea->arp_tha); | |
756 | memcpy(ea->arp_tpa, (void *) &ip_addr, sizeof(ip_addr)); | |
757 | ||
758 | /* Source fields */ | |
759 | enaddr_copy(&kdp_current_mac_address, ea->arp_sha); | |
760 | memcpy(ea->arp_spa, (void *) &kdp_current_ip_address, sizeof(kdp_current_ip_address)); | |
761 | ||
762 | pkt.off = 0; | |
763 | pkt.len = sizeof(struct ether_header) + sizeof(struct ether_arp); | |
764 | /* Transmit */ | |
765 | (*kdp_en_send_pkt)(&pkt.data[pkt.off], pkt.len); | |
766 | } | |
767 | ||
768 | static boolean_t | |
769 | kdp_arp_resolve(uint32_t arp_target_ip, struct ether_addr *resolved_MAC) | |
770 | { | |
771 | int poll_count = 256; /* ~770 ms modulo broadcast/delayed traffic? */ | |
772 | char tretries = 0; | |
773 | ||
774 | #define NUM_ARP_TX_RETRIES 5 | |
775 | ||
776 | target_ip = arp_target_ip; | |
777 | flag_arp_resolved = FALSE; | |
778 | ||
779 | TRANSMIT_RETRY: | |
780 | pkt.off = pkt.len = 0; | |
781 | ||
782 | tretries++; | |
783 | ||
784 | if (tretries >= NUM_ARP_TX_RETRIES) { | |
785 | return FALSE; | |
786 | } | |
787 | ||
788 | KDP_DEBUG("ARP TX attempt #%d \n", tretries); | |
789 | ||
790 | transmit_ARP_request(arp_target_ip); | |
791 | ||
792 | while (!pkt.input && !flag_arp_resolved && flag_panic_dump_in_progress && --poll_count) { | |
793 | kdp_poll(); | |
794 | } | |
795 | ||
796 | if (flag_arp_resolved) { | |
797 | *resolved_MAC = current_resolved_MAC; | |
798 | return TRUE; | |
799 | } | |
800 | ||
801 | if (!flag_panic_dump_in_progress || pkt.input) /* we received a debugging packet, bail*/ | |
802 | { | |
803 | printf("Received a debugger packet,transferring control to debugger\n"); | |
804 | /* Indicate that we should wait in the debugger when we return */ | |
805 | kdp_flag |= DBG_POST_CORE; | |
806 | pkt.input = FALSE; | |
807 | return FALSE; | |
808 | } | |
809 | else /* We timed out */ | |
810 | if (0 == poll_count) { | |
811 | poll_count = 256; | |
812 | goto TRANSMIT_RETRY; | |
813 | } | |
814 | return FALSE; | |
815 | } | |
816 | ||
817 | static void | |
818 | kdp_handler( | |
819 | void *saved_state | |
820 | ) | |
821 | { | |
822 | unsigned short reply_port; | |
823 | kdp_hdr_t aligned_hdr, *hdr = &aligned_hdr; | |
824 | ||
825 | kdp.saved_state = saved_state; // see comment in kdp_raise_exception | |
826 | ||
827 | do { | |
828 | while (!pkt.input) | |
829 | kdp_poll(); | |
830 | ||
831 | #if DO_ALIGN | |
832 | bcopy((char *)&pkt.data[pkt.off], (char *)hdr, sizeof(*hdr)); | |
833 | #else | |
834 | hdr = (kdp_hdr_t *)&pkt.data[pkt.off]; | |
835 | #endif | |
836 | ||
837 | // ignore replies -- we're not expecting them anyway. | |
838 | if (hdr->is_reply) { | |
839 | goto again; | |
840 | } | |
841 | ||
842 | if (hdr->request == KDP_REATTACH) | |
843 | exception_seq = hdr->seq; | |
844 | ||
845 | // check for retransmitted request | |
846 | if (hdr->seq == (exception_seq - 1)) { | |
847 | /* retransmit last reply */ | |
848 | (*kdp_en_send_pkt)(&saved_reply.data[saved_reply.off], | |
849 | saved_reply.len); | |
850 | goto again; | |
851 | } else if (hdr->seq != exception_seq) { | |
852 | printf("kdp: bad sequence %d (want %d)\n", | |
853 | hdr->seq, exception_seq); | |
854 | goto again; | |
855 | } | |
856 | ||
857 | if (kdp_packet((unsigned char*)&pkt.data[pkt.off], | |
858 | (int *)&pkt.len, | |
859 | (unsigned short *)&reply_port)) { | |
860 | kdp_reply(reply_port); | |
861 | } | |
862 | ||
863 | again: | |
864 | pkt.input = FALSE; | |
865 | } while (kdp.is_halted); | |
866 | } | |
867 | ||
868 | static void | |
869 | kdp_connection_wait(void) | |
870 | { | |
871 | unsigned short reply_port; | |
872 | struct ether_addr kdp_mac_addr = kdp_get_mac_addr(); | |
873 | unsigned int ip_addr = ntohl(kdp_get_ip_address()); | |
874 | ||
875 | /* | |
876 | * Do both a printf() and a kprintf() of the MAC and IP so that | |
877 | * they will print out on headless machines but not be added to | |
878 | * the panic.log | |
879 | */ | |
880 | ||
881 | printf( "ethernet MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", | |
882 | kdp_mac_addr.ether_addr_octet[0] & 0xff, | |
883 | kdp_mac_addr.ether_addr_octet[1] & 0xff, | |
884 | kdp_mac_addr.ether_addr_octet[2] & 0xff, | |
885 | kdp_mac_addr.ether_addr_octet[3] & 0xff, | |
886 | kdp_mac_addr.ether_addr_octet[4] & 0xff, | |
887 | kdp_mac_addr.ether_addr_octet[5] & 0xff); | |
888 | ||
889 | kprintf( "ethernet MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", | |
890 | kdp_mac_addr.ether_addr_octet[0] & 0xff, | |
891 | kdp_mac_addr.ether_addr_octet[1] & 0xff, | |
892 | kdp_mac_addr.ether_addr_octet[2] & 0xff, | |
893 | kdp_mac_addr.ether_addr_octet[3] & 0xff, | |
894 | kdp_mac_addr.ether_addr_octet[4] & 0xff, | |
895 | kdp_mac_addr.ether_addr_octet[5] & 0xff); | |
896 | ||
897 | printf( "ip address: %d.%d.%d.%d\n", | |
898 | (ip_addr & 0xff000000) >> 24, | |
899 | (ip_addr & 0xff0000) >> 16, | |
900 | (ip_addr & 0xff00) >> 8, | |
901 | (ip_addr & 0xff)); | |
902 | ||
903 | kprintf( "ip address: %d.%d.%d.%d\n", | |
904 | (ip_addr & 0xff000000) >> 24, | |
905 | (ip_addr & 0xff0000) >> 16, | |
906 | (ip_addr & 0xff00) >> 8, | |
907 | (ip_addr & 0xff)); | |
908 | ||
909 | printf("\nWaiting for remote debugger connection.\n"); | |
910 | ||
911 | ||
912 | if (reattach_wait == 0) { | |
913 | if((kdp_flag & KDP_GETC_ENA) && (0 != kdp_getc())) | |
914 | { | |
915 | printf("Options..... Type\n"); | |
916 | printf("------------ ----\n"); | |
917 | printf("continue.... 'c'\n"); | |
918 | printf("reboot...... 'r'\n"); | |
919 | #if MACH_KDB | |
920 | printf("enter kdb... 'k'\n"); | |
921 | #endif | |
922 | } | |
923 | } else | |
924 | reattach_wait = 0; | |
925 | ||
926 | exception_seq = 0; | |
927 | ||
928 | do { | |
929 | kdp_hdr_t aligned_hdr, *hdr = &aligned_hdr; | |
930 | ||
931 | while (!pkt.input) { | |
932 | if (kdp_flag & KDP_GETC_ENA) { | |
933 | switch(kdp_getc()) { | |
934 | case 'c': | |
935 | printf("Continuing...\n"); | |
936 | return; | |
937 | case 'r': | |
938 | printf("Rebooting...\n"); | |
939 | kdp_reboot(); | |
940 | break; | |
941 | #if MACH_KDB | |
942 | case 'k': | |
943 | printf("calling kdb...\n"); | |
944 | if (kdp_call_kdb()) | |
945 | return; | |
946 | else | |
947 | printf("not implemented...\n"); | |
948 | #endif | |
949 | default: | |
950 | break; | |
951 | } | |
952 | } | |
953 | kdp_poll(); | |
954 | } | |
955 | ||
956 | #if DO_ALIGN | |
957 | bcopy((char *)&pkt.data[pkt.off], (char *)hdr, sizeof(*hdr)); | |
958 | #else | |
959 | hdr = (kdp_hdr_t *)&pkt.data[pkt.off]; | |
960 | #endif | |
961 | if (hdr->request == KDP_HOSTREBOOT) { | |
962 | kdp_reboot(); | |
963 | /* should not return! */ | |
964 | } | |
965 | if (((hdr->request == KDP_CONNECT) || (hdr->request == KDP_REATTACH)) && | |
966 | !hdr->is_reply && (hdr->seq == exception_seq)) { | |
967 | if (kdp_packet((unsigned char *)&pkt.data[pkt.off], | |
968 | (int *)&pkt.len, | |
969 | (unsigned short *)&reply_port)) | |
970 | kdp_reply(reply_port); | |
971 | if (hdr->request == KDP_REATTACH) { | |
972 | reattach_wait = 0; | |
973 | hdr->request=KDP_DISCONNECT; | |
974 | exception_seq = 0; | |
975 | } | |
976 | } | |
977 | ||
978 | pkt.input = FALSE; | |
979 | } while (!kdp.is_conn); | |
980 | ||
981 | if (current_debugger == KDP_CUR_DB) | |
982 | active_debugger=1; | |
983 | printf("Connected to remote debugger.\n"); | |
984 | } | |
985 | ||
986 | static void | |
987 | kdp_send_exception( | |
988 | unsigned int exception, | |
989 | unsigned int code, | |
990 | unsigned int subcode | |
991 | ) | |
992 | { | |
993 | unsigned short remote_port; | |
994 | unsigned int timeout_count = 100; | |
995 | unsigned int poll_timeout; | |
996 | ||
997 | do { | |
998 | pkt.off = sizeof (struct ether_header) + sizeof (struct udpiphdr); | |
999 | kdp_exception((unsigned char *)&pkt.data[pkt.off], | |
1000 | (int *)&pkt.len, | |
1001 | (unsigned short *)&remote_port, | |
1002 | (unsigned int)exception, | |
1003 | (unsigned int)code, | |
1004 | (unsigned int)subcode); | |
1005 | ||
1006 | kdp_send(remote_port); | |
1007 | ||
1008 | poll_timeout = 50; | |
1009 | while(!pkt.input && poll_timeout) | |
1010 | { | |
1011 | kdp_poll(); | |
1012 | poll_timeout--; | |
1013 | } | |
1014 | ||
1015 | if (pkt.input) { | |
1016 | if (!kdp_exception_ack(&pkt.data[pkt.off], pkt.len)) { | |
1017 | pkt.input = FALSE; | |
1018 | } | |
1019 | } | |
1020 | ||
1021 | pkt.input = FALSE; | |
1022 | ||
1023 | if (kdp.exception_ack_needed) | |
1024 | kdp_us_spin(250000); | |
1025 | ||
1026 | } while (kdp.exception_ack_needed && timeout_count--); | |
1027 | ||
1028 | if (kdp.exception_ack_needed) { | |
1029 | // give up & disconnect | |
1030 | printf("kdp: exception ack timeout\n"); | |
1031 | if (current_debugger == KDP_CUR_DB) | |
1032 | active_debugger=0; | |
1033 | kdp_reset(); | |
1034 | } | |
1035 | } | |
1036 | ||
1037 | void | |
1038 | kdp_raise_exception( | |
1039 | unsigned int exception, | |
1040 | unsigned int code, | |
1041 | unsigned int subcode, | |
1042 | void *saved_state | |
1043 | ) | |
1044 | { | |
1045 | int index; | |
1046 | ||
1047 | /* Was a system trace requested ? */ | |
1048 | if (kdp_snapshot && (!panic_active()) && (panic_caller == 0)) { | |
1049 | stack_snapshot_ret = kdp_stackshot(stack_snapshot_pid, | |
1050 | stack_snapshot_buf, stack_snapshot_bufsize, | |
1051 | stack_snapshot_options, &stack_snapshot_bytes_traced); | |
1052 | return; | |
1053 | } | |
1054 | ||
1055 | disable_preemption(); | |
1056 | ||
1057 | if (saved_state == 0) | |
1058 | printf("kdp_raise_exception with NULL state\n"); | |
1059 | ||
1060 | index = exception; | |
1061 | if (exception != EXC_BREAKPOINT) { | |
1062 | if (exception > EXC_BREAKPOINT || exception < EXC_BAD_ACCESS) { | |
1063 | index = 0; | |
1064 | } | |
1065 | printf("%s exception (%x,%x,%x)\n", | |
1066 | exception_message[index], | |
1067 | exception, code, subcode); | |
1068 | } | |
1069 | ||
1070 | kdp_sync_cache(); | |
1071 | ||
1072 | /* XXX WMG it seems that sometimes it doesn't work to let kdp_handler | |
1073 | * do this. I think the client and the host can get out of sync. | |
1074 | */ | |
1075 | kdp.saved_state = saved_state; | |
1076 | kdp.kdp_cpu = cpu_number(); | |
1077 | kdp.kdp_thread = current_thread(); | |
1078 | ||
1079 | if (pkt.input) | |
1080 | kdp_panic("kdp_raise_exception"); | |
1081 | ||
1082 | ||
1083 | if (((kdp_flag & KDP_PANIC_DUMP_ENABLED) || (kdp_flag & PANIC_LOG_DUMP)) | |
1084 | && (panicstr != (char *) 0)) { | |
1085 | ||
1086 | kdp_panic_dump(); | |
1087 | } | |
1088 | else | |
1089 | if ((kdp_flag & PANIC_CORE_ON_NMI) && (panicstr == (char *) 0) && | |
1090 | !kdp.is_conn) { | |
1091 | ||
1092 | disable_debug_output = disableConsoleOutput = FALSE; | |
1093 | kdp_panic_dump(); | |
1094 | ||
1095 | if (!(kdp_flag & DBG_POST_CORE)) | |
1096 | goto exit_raise_exception; | |
1097 | } | |
1098 | ||
1099 | again: | |
1100 | if (!kdp.is_conn) | |
1101 | kdp_connection_wait(); | |
1102 | else { | |
1103 | kdp_send_exception(exception, code, subcode); | |
1104 | if (kdp.exception_ack_needed) { | |
1105 | kdp.exception_ack_needed = FALSE; | |
1106 | kdp_remove_all_breakpoints(); | |
1107 | printf("Remote debugger disconnected.\n"); | |
1108 | } | |
1109 | } | |
1110 | ||
1111 | if (kdp.is_conn) { | |
1112 | kdp.is_halted = TRUE; /* XXX */ | |
1113 | kdp_handler(saved_state); | |
1114 | if (!kdp.is_conn) | |
1115 | { | |
1116 | kdp_remove_all_breakpoints(); | |
1117 | printf("Remote debugger disconnected.\n"); | |
1118 | } | |
1119 | } | |
1120 | /* Allow triggering a panic core dump when connected to the machine | |
1121 | * Continuing after setting kdp_trigger_core_dump should do the | |
1122 | * trick. | |
1123 | */ | |
1124 | ||
1125 | if (1 == kdp_trigger_core_dump) { | |
1126 | kdp_flag &= ~PANIC_LOG_DUMP; | |
1127 | kdp_flag |= KDP_PANIC_DUMP_ENABLED; | |
1128 | kdp_panic_dump(); | |
1129 | kdp_trigger_core_dump = 0; | |
1130 | } | |
1131 | ||
1132 | /* Trigger a reboot if the user has set this flag through the | |
1133 | * debugger.Ideally, this would be done through the HOSTREBOOT packet | |
1134 | * in the protocol,but that will need gdb support,and when it's | |
1135 | * available, it should work automatically. | |
1136 | */ | |
1137 | if (1 == flag_kdp_trigger_reboot) { | |
1138 | kdp_reboot(); | |
1139 | /* If we're still around, reset the flag */ | |
1140 | flag_kdp_trigger_reboot = 0; | |
1141 | } | |
1142 | ||
1143 | if (kdp_reentry_deadline) { | |
1144 | kdp_schedule_debugger_reentry(kdp_reentry_deadline); | |
1145 | printf("Debugger re-entry scheduled in %d milliseconds\n", kdp_reentry_deadline); | |
1146 | kdp_reentry_deadline = 0; | |
1147 | } | |
1148 | ||
1149 | kdp_sync_cache(); | |
1150 | ||
1151 | if (reattach_wait == 1) | |
1152 | goto again; | |
1153 | ||
1154 | exit_raise_exception: | |
1155 | enable_preemption(); | |
1156 | } | |
1157 | ||
1158 | void | |
1159 | kdp_reset(void) | |
1160 | { | |
1161 | kdp.reply_port = kdp.exception_port = 0; | |
1162 | kdp.is_halted = kdp.is_conn = FALSE; | |
1163 | kdp.exception_seq = kdp.conn_seq = 0; | |
1164 | } | |
1165 | ||
1166 | struct corehdr * | |
1167 | create_panic_header(unsigned int request, const char *corename, | |
1168 | unsigned length, unsigned int block) | |
1169 | { | |
1170 | struct udpiphdr aligned_ui, *ui = &aligned_ui; | |
1171 | struct ip aligned_ip, *ip = &aligned_ip; | |
1172 | struct ether_header *eh; | |
1173 | struct corehdr *coreh; | |
1174 | const char *mode = "octet"; | |
1175 | char modelen = strlen(mode); | |
1176 | ||
1177 | pkt.off = sizeof (struct ether_header); | |
1178 | pkt.len = length + ((request == KDP_WRQ) ? modelen : 0) + | |
1179 | (corename ? strlen(corename): 0) + sizeof(struct corehdr); | |
1180 | ||
1181 | #if DO_ALIGN | |
1182 | bcopy((char *)&pkt.data[pkt.off], (char *)ui, sizeof(*ui)); | |
1183 | #else | |
1184 | ui = (struct udpiphdr *)&pkt.data[pkt.off]; | |
1185 | #endif | |
1186 | ui->ui_next = ui->ui_prev = NULL; | |
1187 | ui->ui_x1 = 0; | |
1188 | ui->ui_pr = IPPROTO_UDP; | |
1189 | ui->ui_len = htons((u_short)pkt.len + sizeof (struct udphdr)); | |
1190 | ui->ui_src.s_addr = kdp_current_ip_address; | |
1191 | /* Already in network byte order via inet_aton() */ | |
1192 | ui->ui_dst.s_addr = panic_server_ip; | |
1193 | ui->ui_sport = htons(panicd_port); | |
1194 | ui->ui_dport = ((request == KDP_WRQ) ? htons(panicd_port) : last_panic_port); | |
1195 | ui->ui_ulen = ui->ui_len; | |
1196 | ui->ui_sum = 0; | |
1197 | #if DO_ALIGN | |
1198 | bcopy((char *)ui, (char *)&pkt.data[pkt.off], sizeof(*ui)); | |
1199 | bcopy((char *)&pkt.data[pkt.off], (char *)ip, sizeof(*ip)); | |
1200 | #else | |
1201 | ip = (struct ip *)&pkt.data[pkt.off]; | |
1202 | #endif | |
1203 | ip->ip_len = htons(sizeof (struct udpiphdr) + pkt.len); | |
1204 | ip->ip_v = IPVERSION; | |
1205 | ip->ip_id = htons(ip_id++); | |
1206 | ip->ip_hl = sizeof (struct ip) >> 2; | |
1207 | ip->ip_ttl = udp_ttl; | |
1208 | ip->ip_sum = 0; | |
1209 | ip->ip_sum = htons(~ip_sum((unsigned char *)ip, ip->ip_hl)); | |
1210 | #if DO_ALIGN | |
1211 | bcopy((char *)ip, (char *)&pkt.data[pkt.off], sizeof(*ip)); | |
1212 | #endif | |
1213 | ||
1214 | pkt.len += sizeof (struct udpiphdr); | |
1215 | ||
1216 | pkt.off += sizeof (struct udpiphdr); | |
1217 | ||
1218 | coreh = (struct corehdr *) &pkt.data[pkt.off]; | |
1219 | coreh->th_opcode = htons((u_short)request); | |
1220 | ||
1221 | if (request == KDP_WRQ) | |
1222 | { | |
1223 | char *cp; | |
1224 | ||
1225 | cp = coreh->th_u.tu_rpl; | |
1226 | cp += strlcpy (cp, corename, KDP_MAXPACKET); | |
1227 | *cp++ = '\0'; | |
1228 | cp += strlcpy (cp, mode, KDP_MAXPACKET - strlen(corename)); | |
1229 | *cp++ = '\0'; | |
1230 | } | |
1231 | else | |
1232 | { | |
1233 | coreh->th_block = htonl((unsigned int) block); | |
1234 | } | |
1235 | ||
1236 | pkt.off -= sizeof (struct udpiphdr); | |
1237 | pkt.off -= sizeof (struct ether_header); | |
1238 | ||
1239 | eh = (struct ether_header *)&pkt.data[pkt.off]; | |
1240 | enaddr_copy(&kdp_current_mac_address, eh->ether_shost); | |
1241 | enaddr_copy(&destination_mac, eh->ether_dhost); | |
1242 | eh->ether_type = htons(ETHERTYPE_IP); | |
1243 | ||
1244 | pkt.len += sizeof (struct ether_header); | |
1245 | return coreh; | |
1246 | } | |
1247 | ||
1248 | int kdp_send_crashdump_data(unsigned int request, char *corename, | |
1249 | unsigned int length, caddr_t txstart) | |
1250 | { | |
1251 | caddr_t txend = txstart + length; | |
1252 | int panic_error = 0; | |
1253 | ||
1254 | if (length <= SEGSIZE) { | |
1255 | if ((panic_error = kdp_send_crashdump_pkt(request, corename, length, (caddr_t) txstart)) < 0) { | |
1256 | printf ("kdp_send_crashdump_pkt failed with error %d\n", panic_error); | |
1257 | return panic_error ; | |
1258 | } | |
1259 | } | |
1260 | else | |
1261 | { | |
1262 | while (txstart <= (txend - SEGSIZE)) { | |
1263 | if ((panic_error = kdp_send_crashdump_pkt(KDP_DATA, NULL, SEGSIZE, txstart)) < 0) { | |
1264 | printf ("kdp_send_crashdump_pkt failed with error %d\n", panic_error); | |
1265 | return panic_error; | |
1266 | } | |
1267 | txstart += SEGSIZE; | |
1268 | if (!(panic_block % 2000)) | |
1269 | printf("."); | |
1270 | } | |
1271 | if (txstart < txend) { | |
1272 | kdp_send_crashdump_pkt(request, corename, (txend - txstart), txstart); | |
1273 | } | |
1274 | } | |
1275 | return 0; | |
1276 | } | |
1277 | ||
1278 | int | |
1279 | kdp_send_crashdump_pkt(unsigned int request, char *corename, | |
1280 | unsigned int length, void *panic_data) | |
1281 | { | |
1282 | struct corehdr *th = NULL; | |
1283 | int poll_count = 2500; | |
1284 | ||
1285 | char rretries = 0, tretries = 0; | |
1286 | ||
1287 | pkt.off = pkt.len = 0; | |
1288 | ||
1289 | if (request == KDP_WRQ) /* longer timeout for initial request */ | |
1290 | poll_count += 1000; | |
1291 | ||
1292 | TRANSMIT_RETRY: | |
1293 | tretries++; | |
1294 | ||
1295 | if (tretries >=15) { | |
1296 | /* The crashdump server is unreachable for some reason. This could be a network | |
1297 | * issue or, if we've been especially unfortunate, we've hit Radar 2760413, | |
1298 | * which is a long standing problem with the IOKit polled mode network driver | |
1299 | * shim which can prevent transmits/receives completely. | |
1300 | */ | |
1301 | printf ("Cannot contact panic server, timing out.\n"); | |
1302 | return (-3); | |
1303 | } | |
1304 | ||
1305 | if (tretries > 2) | |
1306 | printf("TX retry #%d ", tretries ); | |
1307 | ||
1308 | th = create_panic_header(request, corename, length, panic_block); | |
1309 | ||
1310 | if (request == KDP_DATA) { | |
1311 | if (!kdp_vm_read((caddr_t) panic_data, (caddr_t) th->th_data, length)) { | |
1312 | memset ((caddr_t) th->th_data, 'X', length); | |
1313 | } | |
1314 | } | |
1315 | else if (request == KDP_SEEK) { | |
1316 | *(unsigned int *) th->th_data = htonl(*(unsigned int *) panic_data); | |
1317 | } | |
1318 | ||
1319 | (*kdp_en_send_pkt)(&pkt.data[pkt.off], pkt.len); | |
1320 | ||
1321 | /* Listen for the ACK */ | |
1322 | RECEIVE_RETRY: | |
1323 | while (!pkt.input && flag_panic_dump_in_progress && poll_count) { | |
1324 | kdp_poll(); | |
1325 | poll_count--; | |
1326 | } | |
1327 | ||
1328 | if (pkt.input) { | |
1329 | ||
1330 | pkt.input = FALSE; | |
1331 | ||
1332 | th = (struct corehdr *) &pkt.data[pkt.off]; | |
1333 | ||
1334 | if (ntohs(th->th_opcode) == KDP_ACK && ntohl(th->th_block) == panic_block) { | |
1335 | } | |
1336 | else | |
1337 | if (ntohs(th->th_opcode) == KDP_ERROR) { | |
1338 | printf("Panic server returned error %d, retrying\n", ntohl(th->th_code)); | |
1339 | poll_count = 1000; | |
1340 | goto TRANSMIT_RETRY; | |
1341 | } | |
1342 | else | |
1343 | if (ntohl(th->th_block) == (panic_block - 1)) { | |
1344 | printf("RX retry "); | |
1345 | if (++rretries > 1) | |
1346 | goto TRANSMIT_RETRY; | |
1347 | else | |
1348 | goto RECEIVE_RETRY; | |
1349 | } | |
1350 | } | |
1351 | else | |
1352 | if (!flag_panic_dump_in_progress) /* we received a debugging packet, bail*/ | |
1353 | { | |
1354 | printf("Received a debugger packet,transferring control to debugger\n"); | |
1355 | /* Configure that if not set ..*/ | |
1356 | kdp_flag |= DBG_POST_CORE; | |
1357 | return (-2); | |
1358 | } | |
1359 | else /* We timed out */ | |
1360 | if (0 == poll_count) { | |
1361 | poll_count = 1000; | |
1362 | kdp_us_spin ((tretries%4) * panic_timeout); /* capped linear backoff */ | |
1363 | goto TRANSMIT_RETRY; | |
1364 | } | |
1365 | ||
1366 | panic_block++; | |
1367 | ||
1368 | if (request == KDP_EOF) | |
1369 | printf("\nTotal number of packets transmitted: %d\n", panic_block); | |
1370 | ||
1371 | return 1; | |
1372 | } | |
1373 | ||
1374 | static int | |
1375 | isdigit (char c) | |
1376 | { | |
1377 | return ((c > 47) && (c < 58)); | |
1378 | } | |
1379 | /* From user mode Libc - this ought to be in a library */ | |
1380 | static char * | |
1381 | strnstr(char *s, const char *find, size_t slen) | |
1382 | { | |
1383 | char c, sc; | |
1384 | size_t len; | |
1385 | ||
1386 | if ((c = *find++) != '\0') { | |
1387 | len = strlen(find); | |
1388 | do { | |
1389 | do { | |
1390 | if ((sc = *s++) == '\0' || slen-- < 1) | |
1391 | return (NULL); | |
1392 | } while (sc != c); | |
1393 | if (len > slen) | |
1394 | return (NULL); | |
1395 | } while (strncmp(s, find, len) != 0); | |
1396 | s--; | |
1397 | } | |
1398 | return (s); | |
1399 | } | |
1400 | ||
1401 | extern char version[]; | |
1402 | ||
1403 | /* Horrid hack to extract xnu version if possible - a much cleaner approach | |
1404 | * would be to have the integrator run a script which would copy the | |
1405 | * xnu version into a string or an int somewhere at project submission | |
1406 | * time - makes assumptions about sizeof(version), but will not fail if | |
1407 | * it changes, but may be incorrect. | |
1408 | */ | |
1409 | /* 2006: Incorporated a change from Darwin user P. Lovell to extract | |
1410 | * the minor kernel version numbers from the version string. | |
1411 | */ | |
1412 | static int | |
1413 | kdp_get_xnu_version(char *versionbuf) | |
1414 | { | |
1415 | char *versionpos; | |
1416 | char vstr[20]; | |
1417 | int retval = -1; | |
1418 | char *vptr; | |
1419 | ||
1420 | strlcpy(vstr, "custom", 10); | |
1421 | if (strlcpy(versionbuf, version, 95) < 95) { | |
1422 | versionpos = strnstr(versionbuf, "xnu-", 90); | |
1423 | if (versionpos) { | |
1424 | strncpy(vstr, versionpos, sizeof(vstr)); | |
1425 | vstr[sizeof(vstr)-1] = '\0'; | |
1426 | vptr = vstr + 4; /* Begin after "xnu-" */ | |
1427 | while (*vptr && (isdigit(*vptr) || *vptr == '.')) | |
1428 | vptr++; | |
1429 | *vptr = '\0'; | |
1430 | /* Remove trailing period, if any */ | |
1431 | if (*(--vptr) == '.') | |
1432 | *vptr = '\0'; | |
1433 | retval = 0; | |
1434 | } | |
1435 | } | |
1436 | strlcpy(versionbuf, vstr, KDP_MAXPACKET); | |
1437 | return retval; | |
1438 | } | |
1439 | ||
1440 | extern char *inet_aton(const char *cp, struct in_addr *pin); | |
1441 | extern int snprintf(char *str, size_t size, const char *format, ...); | |
1442 | ||
1443 | /* Primary dispatch routine for the system dump */ | |
1444 | void | |
1445 | kdp_panic_dump(void) | |
1446 | { | |
1447 | char corename[50]; | |
1448 | char coreprefix[10]; | |
1449 | int panic_error; | |
1450 | ||
1451 | uint64_t abstime; | |
1452 | uint32_t current_ip = ntohl(kdp_current_ip_address); | |
1453 | ||
1454 | if (flag_panic_dump_in_progress) { | |
1455 | printf("System dump aborted.\n"); | |
1456 | goto panic_dump_exit; | |
1457 | } | |
1458 | ||
1459 | printf("Entering system dump routine\n"); | |
1460 | ||
1461 | if (!panicd_specified) { | |
1462 | printf("A dump server was not specified in the boot-args, terminating kernel core dump.\n"); | |
1463 | goto panic_dump_exit; | |
1464 | } | |
1465 | ||
1466 | flag_panic_dump_in_progress = TRUE; | |
1467 | not_in_kdp = 0; | |
1468 | ||
1469 | if (pkt.input) | |
1470 | kdp_panic("kdp_panic_dump: unexpected pending input packet"); | |
1471 | ||
1472 | kdp_get_xnu_version((char *) &pkt.data[0]); | |
1473 | ||
1474 | /* Panic log bit takes precedence over core dump bit */ | |
1475 | if ((panicstr != (char *) 0) && (kdp_flag & PANIC_LOG_DUMP)) | |
1476 | strncpy(coreprefix, "paniclog", sizeof(coreprefix)); | |
1477 | else | |
1478 | strncpy(coreprefix, "core", sizeof(coreprefix)); | |
1479 | ||
1480 | abstime = mach_absolute_time(); | |
1481 | pkt.data[20] = '\0'; | |
1482 | snprintf (corename, sizeof(corename), "%s-%s-%d.%d.%d.%d-%x", | |
1483 | coreprefix, &pkt.data[0], | |
1484 | (current_ip & 0xff000000) >> 24, | |
1485 | (current_ip & 0xff0000) >> 16, | |
1486 | (current_ip & 0xff00) >> 8, | |
1487 | (current_ip & 0xff), | |
1488 | (unsigned int) (abstime & 0xffffffff)); | |
1489 | ||
1490 | if (0 == inet_aton(panicd_ip_str, (struct in_addr *) &panic_server_ip)) { | |
1491 | printf("inet_aton() failed interpreting %s as a panic server IP\n", panicd_ip_str); | |
1492 | } | |
1493 | else | |
1494 | printf("Attempting connection to panic server configured at IP %s, port %d\n", panicd_ip_str, panicd_port); | |
1495 | ||
1496 | destination_mac = router_mac; | |
1497 | ||
1498 | if (kdp_arp_resolve(panic_server_ip, &temp_mac)) { | |
1499 | printf("Resolved %s's (or proxy's) link level address\n", panicd_ip_str); | |
1500 | destination_mac = temp_mac; | |
1501 | } | |
1502 | else { | |
1503 | if (!flag_panic_dump_in_progress) goto panic_dump_exit; | |
1504 | if (router_specified) { | |
1505 | if (0 == inet_aton(router_ip_str, (struct in_addr *) &parsed_router_ip)) | |
1506 | printf("inet_aton() failed interpreting %s as an IP\n", router_ip_str); | |
1507 | else { | |
1508 | router_ip = parsed_router_ip; | |
1509 | if (kdp_arp_resolve(router_ip, &temp_mac)) { | |
1510 | destination_mac = temp_mac; | |
1511 | printf("Routing through specified router IP %s (%d)\n", router_ip_str, router_ip); | |
1512 | } | |
1513 | } | |
1514 | } | |
1515 | } | |
1516 | ||
1517 | if (!flag_panic_dump_in_progress) goto panic_dump_exit; | |
1518 | ||
1519 | printf("Transmitting packets to link level address: %02x:%02x:%02x:%02x:%02x:%02x\n", | |
1520 | destination_mac.ether_addr_octet[0] & 0xff, | |
1521 | destination_mac.ether_addr_octet[1] & 0xff, | |
1522 | destination_mac.ether_addr_octet[2] & 0xff, | |
1523 | destination_mac.ether_addr_octet[3] & 0xff, | |
1524 | destination_mac.ether_addr_octet[4] & 0xff, | |
1525 | destination_mac.ether_addr_octet[5] & 0xff); | |
1526 | ||
1527 | printf("Kernel map size is %llu\n", (unsigned long long) get_vmmap_size(kernel_map)); | |
1528 | printf("Sending write request for %s\n", corename); | |
1529 | ||
1530 | if ((panic_error = kdp_send_crashdump_pkt(KDP_WRQ, corename, 0 , NULL)) < 0) { | |
1531 | printf ("kdp_send_crashdump_pkt failed with error %d\n", panic_error); | |
1532 | goto panic_dump_exit; | |
1533 | } | |
1534 | ||
1535 | /* Just the panic log requested */ | |
1536 | if ((panicstr != (char *) 0) && (kdp_flag & PANIC_LOG_DUMP)) { | |
1537 | printf("Transmitting panic log, please wait: "); | |
1538 | kdp_send_crashdump_data(KDP_DATA, corename, (debug_buf_ptr - debug_buf), debug_buf); | |
1539 | kdp_send_crashdump_pkt (KDP_EOF, NULL, 0, ((void *) 0)); | |
1540 | printf("Please file a bug report on this panic, if possible.\n"); | |
1541 | goto panic_dump_exit; | |
1542 | } | |
1543 | ||
1544 | /* We want a core dump if we're here */ | |
1545 | kern_dump(); | |
1546 | panic_dump_exit: | |
1547 | abort_panic_transfer(); | |
1548 | pkt.input = FALSE; | |
1549 | pkt.len = 0; | |
1550 | kdp_reset(); | |
1551 | return; | |
1552 | } | |
1553 | ||
1554 | void | |
1555 | abort_panic_transfer(void) | |
1556 | { | |
1557 | flag_panic_dump_in_progress = FALSE; | |
1558 | not_in_kdp = 1; | |
1559 | panic_block = 0; | |
1560 | } |