]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
e5568f75 A |
6 | * The contents of this file constitute Original Code as defined in and |
7 | * are subject to the Apple Public Source License Version 1.1 (the | |
8 | * "License"). You may not use this file except in compliance with the | |
9 | * License. Please obtain a copy of the License at | |
10 | * http://www.apple.com/publicsource and read it before using this file. | |
1c79356b | 11 | * |
e5568f75 A |
12 | * This Original Code and all software distributed under the License are |
13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
1c79356b A |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
e5568f75 A |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the |
17 | * License for the specific language governing rights and limitations | |
18 | * under the License. | |
1c79356b A |
19 | * |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | /* | |
9bccf70c A |
23 | * Copyright (c) 1982, 1986, 1993 |
24 | * The Regents of the University of California. All rights reserved. | |
25 | */ | |
26 | ||
27 | /* | |
28 | * Kernel Debugging Protocol UDP implementation. | |
1c79356b A |
29 | */ |
30 | ||
31 | #include <mach_kdb.h> | |
32 | #include <mach/boolean.h> | |
de355530 | 33 | #include <mach/mach_types.h> |
55e303ae | 34 | #include <mach/exception_types.h> |
9bccf70c | 35 | #include <kern/cpu_data.h> |
1c79356b A |
36 | #include <kern/debug.h> |
37 | ||
38 | #include <kdp/kdp_internal.h> | |
39 | #include <kdp/kdp_en_debugger.h> | |
40 | #include <kdp/kdp_udp.h> | |
41 | ||
55e303ae A |
42 | #include <kdp/kdp_core.h> |
43 | ||
44 | #include <vm/vm_map.h> | |
45 | #include <mach/memory_object_types.h> | |
46 | ||
47 | #include <string.h> | |
48 | ||
1c79356b A |
49 | #define DO_ALIGN 1 /* align all packet data accesses */ |
50 | ||
51 | extern int kdp_getc(void); | |
9bccf70c | 52 | extern int reattach_wait; |
1c79356b | 53 | |
9bccf70c | 54 | static u_short ip_id; /* ip packet ctr, for ids */ |
1c79356b A |
55 | |
56 | /* @(#)udp_usrreq.c 2.2 88/05/23 4.0NFSSRC SMI; from UCB 7.1 6/5/86 */ | |
57 | ||
58 | /* | |
59 | * UDP protocol implementation. | |
60 | * Per RFC 768, August, 1980. | |
61 | */ | |
62 | #define UDP_TTL 60 /* deflt time to live for UDP packets */ | |
55e303ae | 63 | int udp_ttl = UDP_TTL; |
1c79356b A |
64 | static unsigned char exception_seq; |
65 | ||
66 | static struct { | |
67 | unsigned char data[KDP_MAXPACKET]; | |
68 | unsigned int off, len; | |
69 | boolean_t input; | |
70 | } pkt, saved_reply; | |
71 | ||
72 | struct { | |
73 | struct { | |
74 | struct in_addr in; | |
75 | struct ether_addr ea; | |
76 | } loc; | |
77 | struct { | |
78 | struct in_addr in; | |
79 | struct ether_addr ea; | |
80 | } rmt; | |
81 | } adr; | |
82 | ||
83 | static char | |
84 | *exception_message[] = { | |
85 | "Unknown", | |
86 | "Memory access", /* EXC_BAD_ACCESS */ | |
87 | "Failed instruction", /* EXC_BAD_INSTRUCTION */ | |
88 | "Arithmetic", /* EXC_ARITHMETIC */ | |
89 | "Emulation", /* EXC_EMULATION */ | |
90 | "Software", /* EXC_SOFTWARE */ | |
91 | "Breakpoint" /* EXC_BREAKPOINT */ | |
92 | }; | |
93 | ||
9bccf70c A |
94 | int kdp_flag = 0; |
95 | ||
1c79356b A |
96 | static kdp_send_t kdp_en_send_pkt = 0; |
97 | static kdp_receive_t kdp_en_recv_pkt = 0; | |
98 | ||
9bccf70c | 99 | |
55e303ae | 100 | static u_long kdp_current_ip_address = 0; |
9bccf70c | 101 | static struct ether_addr kdp_current_mac_address = {{0, 0, 0, 0, 0, 0}}; |
4a249263 | 102 | static void *kdp_current_ifp = 0; |
9bccf70c | 103 | |
55e303ae A |
104 | static void kdp_handler( void *); |
105 | ||
106 | static unsigned int panic_server_ip = 0; | |
107 | static unsigned int parsed_router_ip = 0; | |
108 | static unsigned int router_ip = 0; | |
109 | static unsigned int panicd_specified = 0; | |
110 | static unsigned int router_specified = 0; | |
111 | ||
112 | static struct ether_addr router_mac = {{0, 0, 0 , 0, 0, 0}}; | |
113 | ||
114 | static u_char flag_panic_dump_in_progress = 0; | |
115 | static u_char flag_router_mac_initialized = 0; | |
116 | ||
117 | static unsigned int panic_timeout = 100000; | |
118 | static unsigned int last_panic_port = CORE_REMOTE_PORT; | |
119 | ||
120 | unsigned int SEGSIZE = 512; | |
121 | ||
122 | static unsigned int PANIC_PKTSIZE = 518; | |
123 | static char panicd_ip_str[20]; | |
124 | static char router_ip_str[20]; | |
125 | ||
126 | static unsigned int panic_block = 0; | |
127 | static volatile unsigned int kdp_trigger_core_dump = 0; | |
128 | ||
129 | extern unsigned int not_in_kdp; | |
1c79356b A |
130 | |
131 | void | |
9bccf70c | 132 | kdp_register_send_receive( |
55e303ae | 133 | kdp_send_t send, |
9bccf70c | 134 | kdp_receive_t receive) |
1c79356b | 135 | { |
9bccf70c | 136 | unsigned int debug; |
1c79356b A |
137 | |
138 | kdp_en_send_pkt = send; | |
139 | kdp_en_recv_pkt = receive; | |
55e303ae | 140 | |
9bccf70c | 141 | debug_log_init(); |
55e303ae | 142 | |
9bccf70c | 143 | PE_parse_boot_arg("debug", &debug); |
55e303ae | 144 | |
9bccf70c A |
145 | if (debug & DB_KDP_BP_DIS) |
146 | kdp_flag |= KDP_BP_DIS; | |
55e303ae A |
147 | if (debug & DB_KDP_GETC_ENA) |
148 | kdp_flag |= KDP_GETC_ENA; | |
149 | if (debug & DB_ARP) | |
150 | kdp_flag |= KDP_ARP; | |
151 | ||
152 | if (debug & DB_KERN_DUMP_ON_PANIC) | |
153 | kdp_flag |= KDP_PANIC_DUMP_ENABLED; | |
154 | if (debug & DB_KERN_DUMP_ON_NMI) | |
155 | kdp_flag |= PANIC_CORE_ON_NMI; | |
156 | ||
157 | if (debug & DB_DBG_POST_CORE) | |
158 | kdp_flag |= DBG_POST_CORE; | |
159 | ||
160 | if (debug & DB_PANICLOG_DUMP) | |
161 | kdp_flag |= PANIC_LOG_DUMP; | |
162 | ||
163 | if (PE_parse_boot_arg ("_panicd_ip", panicd_ip_str)) | |
164 | panicd_specified = 1; | |
165 | /* For the future, currently non-functional */ | |
166 | if (PE_parse_boot_arg ("_router_ip", router_ip_str)) | |
167 | router_specified = 1; | |
9bccf70c | 168 | |
1c79356b A |
169 | kdp_flag |= KDP_READY; |
170 | if (current_debugger == NO_CUR_DB) | |
171 | current_debugger = KDP_CUR_DB; | |
172 | if (halt_in_debugger) { | |
173 | kdp_call(); | |
174 | halt_in_debugger=0; | |
175 | } | |
176 | } | |
177 | ||
1c79356b | 178 | void |
9bccf70c A |
179 | kdp_unregister_send_receive( |
180 | kdp_send_t send, | |
181 | kdp_receive_t receive) | |
182 | { | |
183 | if (current_debugger == KDP_CUR_DB) | |
184 | current_debugger = NO_CUR_DB; | |
185 | kdp_flag &= ~KDP_READY; | |
186 | kdp_en_send_pkt = NULL; | |
187 | kdp_en_recv_pkt = NULL; | |
188 | } | |
189 | ||
190 | static void | |
1c79356b | 191 | enaddr_copy( |
9bccf70c A |
192 | void *src, |
193 | void *dst | |
1c79356b A |
194 | ) |
195 | { | |
9bccf70c | 196 | bcopy((char *)src, (char *)dst, sizeof (struct ether_addr)); |
1c79356b A |
197 | } |
198 | ||
9bccf70c | 199 | static unsigned short |
1c79356b | 200 | ip_sum( |
9bccf70c A |
201 | unsigned char *c, |
202 | unsigned int hlen | |
1c79356b A |
203 | ) |
204 | { | |
205 | unsigned int high, low, sum; | |
206 | ||
207 | high = low = 0; | |
208 | while (hlen-- > 0) { | |
209 | low += c[1] + c[3]; | |
210 | high += c[0] + c[2]; | |
211 | ||
212 | c += sizeof (int); | |
213 | } | |
214 | ||
215 | sum = (high << 8) + low; | |
216 | sum = (sum >> 16) + (sum & 65535); | |
217 | ||
218 | return (sum > 65535 ? sum - 65535 : sum); | |
219 | } | |
220 | ||
9bccf70c | 221 | static void |
1c79356b | 222 | kdp_reply( |
9bccf70c | 223 | unsigned short reply_port |
1c79356b A |
224 | ) |
225 | { | |
226 | struct udpiphdr aligned_ui, *ui = &aligned_ui; | |
227 | struct ip aligned_ip, *ip = &aligned_ip; | |
228 | struct in_addr tmp_ipaddr; | |
229 | struct ether_addr tmp_enaddr; | |
230 | struct ether_header *eh; | |
231 | ||
232 | if (!pkt.input) | |
233 | kdp_panic("kdp_reply"); | |
234 | ||
235 | pkt.off -= sizeof (struct udpiphdr); | |
236 | ||
237 | #if DO_ALIGN | |
238 | bcopy((char *)&pkt.data[pkt.off], (char *)ui, sizeof(*ui)); | |
239 | #else | |
240 | ui = (struct udpiphdr *)&pkt.data[pkt.off]; | |
241 | #endif | |
242 | ui->ui_next = ui->ui_prev = 0; | |
243 | ui->ui_x1 = 0; | |
244 | ui->ui_pr = IPPROTO_UDP; | |
245 | ui->ui_len = htons((u_short)pkt.len + sizeof (struct udphdr)); | |
246 | tmp_ipaddr = ui->ui_src; | |
247 | ui->ui_src = ui->ui_dst; | |
248 | ui->ui_dst = tmp_ipaddr; | |
249 | ui->ui_sport = htons(KDP_REMOTE_PORT); | |
250 | ui->ui_dport = reply_port; | |
251 | ui->ui_ulen = ui->ui_len; | |
252 | ui->ui_sum = 0; | |
253 | #if DO_ALIGN | |
254 | bcopy((char *)ui, (char *)&pkt.data[pkt.off], sizeof(*ui)); | |
1c79356b A |
255 | bcopy((char *)&pkt.data[pkt.off], (char *)ip, sizeof(*ip)); |
256 | #else | |
257 | ip = (struct ip *)&pkt.data[pkt.off]; | |
258 | #endif | |
259 | ip->ip_len = htons(sizeof (struct udpiphdr) + pkt.len); | |
260 | ip->ip_v = IPVERSION; | |
261 | ip->ip_id = htons(ip_id++); | |
262 | ip->ip_hl = sizeof (struct ip) >> 2; | |
263 | ip->ip_ttl = udp_ttl; | |
264 | ip->ip_sum = 0; | |
265 | ip->ip_sum = htons(~ip_sum((unsigned char *)ip, ip->ip_hl)); | |
266 | #if DO_ALIGN | |
267 | bcopy((char *)ip, (char *)&pkt.data[pkt.off], sizeof(*ip)); | |
268 | #endif | |
269 | ||
270 | pkt.len += sizeof (struct udpiphdr); | |
271 | ||
272 | pkt.off -= sizeof (struct ether_header); | |
273 | ||
274 | eh = (struct ether_header *)&pkt.data[pkt.off]; | |
275 | enaddr_copy(eh->ether_shost, &tmp_enaddr); | |
276 | enaddr_copy(eh->ether_dhost, eh->ether_shost); | |
277 | enaddr_copy(&tmp_enaddr, eh->ether_dhost); | |
278 | eh->ether_type = htons(ETHERTYPE_IP); | |
279 | ||
280 | pkt.len += sizeof (struct ether_header); | |
281 | ||
282 | // save reply for possible retransmission | |
283 | bcopy((char *)&pkt, (char *)&saved_reply, sizeof(pkt)); | |
284 | ||
285 | (*kdp_en_send_pkt)(&pkt.data[pkt.off], pkt.len); | |
286 | ||
287 | // increment expected sequence number | |
288 | exception_seq++; | |
289 | } | |
290 | ||
9bccf70c | 291 | static void |
1c79356b A |
292 | kdp_send( |
293 | unsigned short remote_port | |
294 | ) | |
295 | { | |
296 | struct udpiphdr aligned_ui, *ui = &aligned_ui; | |
297 | struct ip aligned_ip, *ip = &aligned_ip; | |
298 | struct ether_header *eh; | |
299 | ||
300 | if (pkt.input) | |
301 | kdp_panic("kdp_send"); | |
302 | ||
303 | pkt.off -= sizeof (struct udpiphdr); | |
304 | ||
305 | #if DO_ALIGN | |
306 | bcopy((char *)&pkt.data[pkt.off], (char *)ui, sizeof(*ui)); | |
307 | #else | |
308 | ui = (struct udpiphdr *)&pkt.data[pkt.off]; | |
309 | #endif | |
310 | ui->ui_next = ui->ui_prev = 0; | |
311 | ui->ui_x1 = 0; | |
312 | ui->ui_pr = IPPROTO_UDP; | |
313 | ui->ui_len = htons((u_short)pkt.len + sizeof (struct udphdr)); | |
314 | ui->ui_src = adr.loc.in; | |
315 | ui->ui_dst = adr.rmt.in; | |
316 | ui->ui_sport = htons(KDP_REMOTE_PORT); | |
317 | ui->ui_dport = remote_port; | |
318 | ui->ui_ulen = ui->ui_len; | |
319 | ui->ui_sum = 0; | |
320 | #if DO_ALIGN | |
321 | bcopy((char *)ui, (char *)&pkt.data[pkt.off], sizeof(*ui)); | |
322 | bcopy((char *)&pkt.data[pkt.off], (char *)ip, sizeof(*ip)); | |
323 | #else | |
324 | ip = (struct ip *)&pkt.data[pkt.off]; | |
325 | #endif | |
326 | ip->ip_len = htons(sizeof (struct udpiphdr) + pkt.len); | |
327 | ip->ip_v = IPVERSION; | |
328 | ip->ip_id = htons(ip_id++); | |
329 | ip->ip_hl = sizeof (struct ip) >> 2; | |
330 | ip->ip_ttl = udp_ttl; | |
331 | ip->ip_sum = 0; | |
332 | ip->ip_sum = htons(~ip_sum((unsigned char *)ip, ip->ip_hl)); | |
333 | #if DO_ALIGN | |
334 | bcopy((char *)ip, (char *)&pkt.data[pkt.off], sizeof(*ip)); | |
335 | #endif | |
336 | ||
337 | pkt.len += sizeof (struct udpiphdr); | |
338 | ||
339 | pkt.off -= sizeof (struct ether_header); | |
340 | ||
341 | eh = (struct ether_header *)&pkt.data[pkt.off]; | |
342 | enaddr_copy(&adr.loc.ea, eh->ether_shost); | |
343 | enaddr_copy(&adr.rmt.ea, eh->ether_dhost); | |
344 | eh->ether_type = htons(ETHERTYPE_IP); | |
345 | ||
346 | pkt.len += sizeof (struct ether_header); | |
1c79356b A |
347 | (*kdp_en_send_pkt)(&pkt.data[pkt.off], pkt.len); |
348 | } | |
349 | ||
4a249263 A |
350 | /* We don't interpret this pointer, we just give it to the |
351 | bsd stack so it can decide when to set the MAC and IP info. */ | |
352 | void | |
353 | kdp_set_interface(void *ifp) | |
354 | { | |
355 | kdp_current_ifp = ifp; | |
356 | } | |
357 | ||
358 | void * | |
359 | kdp_get_interface() | |
360 | { | |
361 | return kdp_current_ifp; | |
362 | } | |
9bccf70c A |
363 | |
364 | void | |
365 | kdp_set_ip_and_mac_addresses( | |
366 | struct in_addr *ipaddr, | |
367 | struct ether_addr *macaddr) | |
1c79356b | 368 | { |
9bccf70c A |
369 | unsigned int debug = 0; |
370 | ||
371 | kdp_current_ip_address = ipaddr->s_addr; | |
372 | kdp_current_mac_address = *macaddr; | |
9bccf70c A |
373 | } |
374 | ||
55e303ae A |
375 | void |
376 | kdp_set_gateway_mac(void *gatewaymac) | |
377 | { | |
378 | router_mac = *(struct ether_addr *)gatewaymac; | |
379 | } | |
380 | ||
9bccf70c A |
381 | struct ether_addr |
382 | kdp_get_mac_addr(void) | |
383 | { | |
384 | return kdp_current_mac_address; | |
385 | } | |
386 | ||
387 | unsigned int | |
388 | kdp_get_ip_address(void) | |
389 | { | |
390 | return kdp_current_ip_address; | |
391 | } | |
392 | ||
393 | /* ARP responses are enabled when the DB_ARP bit of the debug boot arg | |
394 | is set. A workaround if you don't want to reboot is to set | |
395 | kdpDEBUGFlag &= DB_ARP when connected (but that certainly isn't a published | |
396 | interface!) | |
397 | */ | |
9bccf70c A |
398 | static void |
399 | kdp_arp_reply(void) | |
400 | { | |
401 | struct ether_header *eh; | |
55e303ae | 402 | struct ether_arp aligned_ea, *ea = &aligned_ea; |
9bccf70c A |
403 | |
404 | struct in_addr isaddr, itaddr, myaddr; | |
55e303ae | 405 | struct ether_addr my_enaddr; |
9bccf70c A |
406 | |
407 | eh = (struct ether_header *)&pkt.data[pkt.off]; | |
408 | pkt.off += sizeof(struct ether_header); | |
409 | ||
55e303ae | 410 | memcpy((void *)ea, (void *)&pkt.data[pkt.off],sizeof(*ea)); |
9bccf70c | 411 | |
55e303ae A |
412 | if(ntohs(ea->arp_op) != ARPOP_REQUEST) |
413 | return; | |
9bccf70c A |
414 | |
415 | myaddr.s_addr = kdp_get_ip_address(); | |
416 | my_enaddr = kdp_get_mac_addr(); | |
417 | ||
418 | if (!(myaddr.s_addr) || !(my_enaddr.ether_addr_octet[1])) | |
419 | return; | |
420 | ||
421 | (void)memcpy((void *)&isaddr, (void *)ea->arp_spa, sizeof (isaddr)); | |
422 | (void)memcpy((void *)&itaddr, (void *)ea->arp_tpa, sizeof (itaddr)); | |
423 | ||
424 | if (itaddr.s_addr == myaddr.s_addr) { | |
425 | (void)memcpy((void *)ea->arp_tha, (void *)ea->arp_sha, sizeof(ea->arp_sha)); | |
426 | (void)memcpy((void *)ea->arp_sha, (void *)&my_enaddr, sizeof(ea->arp_sha)); | |
427 | ||
428 | (void)memcpy((void *)ea->arp_tpa, (void *) ea->arp_spa, sizeof(ea->arp_spa)); | |
429 | (void)memcpy((void *)ea->arp_spa, (void *) &itaddr, sizeof(ea->arp_spa)); | |
430 | ||
431 | ea->arp_op = htons(ARPOP_REPLY); | |
432 | ea->arp_pro = htons(ETHERTYPE_IP); | |
433 | (void)memcpy(eh->ether_dhost, ea->arp_tha, sizeof(eh->ether_dhost)); | |
434 | (void)memcpy(eh->ether_shost, &my_enaddr, sizeof(eh->ether_shost)); | |
435 | eh->ether_type = htons(ETHERTYPE_ARP); | |
436 | (void)memcpy(&pkt.data[pkt.off], ea, sizeof(*ea)); | |
437 | pkt.off -= sizeof (struct ether_header); | |
438 | /* pkt.len is still the length we want, ether_header+ether_arp */ | |
439 | (*kdp_en_send_pkt)(&pkt.data[pkt.off], pkt.len); | |
440 | } | |
441 | } | |
442 | ||
443 | static void | |
444 | kdp_poll(void) | |
445 | { | |
446 | struct ether_header *eh; | |
55e303ae A |
447 | struct udpiphdr aligned_ui, *ui = &aligned_ui; |
448 | struct ip aligned_ip, *ip = &aligned_ip; | |
449 | static int msg_printed; | |
9bccf70c | 450 | |
1c79356b A |
451 | |
452 | if (pkt.input) | |
453 | kdp_panic("kdp_poll"); | |
454 | ||
455 | if (!kdp_en_recv_pkt || !kdp_en_send_pkt) { | |
456 | if( msg_printed == 0) { | |
457 | msg_printed = 1; | |
458 | printf("kdp_poll: no debugger device\n"); | |
459 | } | |
460 | return; | |
461 | } | |
462 | ||
9bccf70c | 463 | pkt.off = pkt.len = 0; |
1c79356b | 464 | (*kdp_en_recv_pkt)(pkt.data, &pkt.len, 3/* ms */); |
9bccf70c | 465 | |
1c79356b A |
466 | if (pkt.len == 0) |
467 | return; | |
9bccf70c A |
468 | |
469 | if (pkt.len >= sizeof(struct ether_header)) | |
470 | { | |
471 | eh = (struct ether_header *)&pkt.data[pkt.off]; | |
472 | ||
473 | if (kdp_flag & KDP_ARP) | |
474 | { | |
475 | if (ntohs(eh->ether_type) == ETHERTYPE_ARP) | |
476 | { | |
477 | kdp_arp_reply(); | |
478 | return; | |
479 | } | |
480 | } | |
481 | } | |
482 | ||
1c79356b A |
483 | if (pkt.len < (sizeof (struct ether_header) + sizeof (struct udpiphdr))) |
484 | return; | |
9bccf70c | 485 | |
1c79356b A |
486 | pkt.off += sizeof (struct ether_header); |
487 | if (ntohs(eh->ether_type) != ETHERTYPE_IP) { | |
488 | return; | |
489 | } | |
490 | ||
491 | #if DO_ALIGN | |
492 | bcopy((char *)&pkt.data[pkt.off], (char *)ui, sizeof(*ui)); | |
493 | bcopy((char *)&pkt.data[pkt.off], (char *)ip, sizeof(*ip)); | |
494 | #else | |
495 | ui = (struct udpiphdr *)&pkt.data[pkt.off]; | |
496 | ip = (struct ip *)&pkt.data[pkt.off]; | |
497 | #endif | |
498 | ||
499 | pkt.off += sizeof (struct udpiphdr); | |
500 | if (ui->ui_pr != IPPROTO_UDP) { | |
501 | return; | |
502 | } | |
503 | ||
504 | if (ip->ip_hl > (sizeof (struct ip) >> 2)) { | |
505 | return; | |
506 | } | |
507 | ||
508 | if (ntohs(ui->ui_dport) != KDP_REMOTE_PORT) { | |
55e303ae A |
509 | if (CORE_REMOTE_PORT == (ntohs(ui->ui_dport)) && |
510 | flag_panic_dump_in_progress) { | |
511 | last_panic_port = ui->ui_sport; | |
512 | } | |
513 | else | |
1c79356b A |
514 | return; |
515 | } | |
55e303ae A |
516 | /* If we receive a kernel debugging packet whilst a |
517 | * core dump is in progress, abort the transfer and | |
518 | * enter the debugger. | |
519 | */ | |
520 | else | |
521 | if (flag_panic_dump_in_progress) | |
522 | { | |
523 | abort_panic_transfer(); | |
524 | return; | |
525 | } | |
526 | ||
527 | if (!kdp.is_conn && !flag_panic_dump_in_progress) { | |
1c79356b A |
528 | enaddr_copy(eh->ether_dhost, &adr.loc.ea); |
529 | adr.loc.in = ui->ui_dst; | |
530 | ||
531 | enaddr_copy(eh->ether_shost, &adr.rmt.ea); | |
532 | adr.rmt.in = ui->ui_src; | |
533 | } | |
534 | ||
535 | /* | |
536 | * Calculate kdp packet length. | |
537 | */ | |
538 | pkt.len = ntohs((u_short)ui->ui_ulen) - sizeof (struct udphdr); | |
539 | pkt.input = TRUE; | |
1c79356b A |
540 | } |
541 | ||
9bccf70c | 542 | static void |
1c79356b | 543 | kdp_handler( |
9bccf70c | 544 | void *saved_state |
1c79356b A |
545 | ) |
546 | { | |
547 | unsigned short reply_port; | |
548 | kdp_hdr_t aligned_hdr, *hdr = &aligned_hdr; | |
549 | ||
550 | ||
551 | kdp.saved_state = saved_state; // see comment in kdp_raise_exception | |
552 | ||
553 | do { | |
554 | while (!pkt.input) | |
555 | kdp_poll(); | |
556 | ||
557 | #if DO_ALIGN | |
558 | bcopy((char *)&pkt.data[pkt.off], (char *)hdr, sizeof(*hdr)); | |
559 | #else | |
560 | hdr = (kdp_hdr_t *)&pkt.data[pkt.off]; | |
561 | #endif | |
562 | ||
563 | // ignore replies -- we're not expecting them anyway. | |
564 | if (hdr->is_reply) { | |
565 | goto again; | |
566 | } | |
567 | ||
9bccf70c A |
568 | if (hdr->request == KDP_REATTACH) |
569 | exception_seq = hdr->seq; | |
570 | ||
1c79356b A |
571 | // check for retransmitted request |
572 | if (hdr->seq == (exception_seq - 1)) { | |
573 | /* retransmit last reply */ | |
574 | (*kdp_en_send_pkt)(&saved_reply.data[saved_reply.off], | |
575 | saved_reply.len); | |
576 | goto again; | |
577 | } else if (hdr->seq != exception_seq) { | |
578 | printf("kdp: bad sequence %d (want %d)\n", | |
579 | hdr->seq, exception_seq); | |
580 | goto again; | |
581 | } | |
582 | ||
583 | if (kdp_packet((unsigned char*)&pkt.data[pkt.off], | |
584 | (int *)&pkt.len, | |
585 | (unsigned short *)&reply_port)) { | |
586 | kdp_reply(reply_port); | |
587 | } | |
588 | ||
589 | again: | |
590 | pkt.input = FALSE; | |
591 | } while (kdp.is_halted); | |
592 | } | |
593 | ||
9bccf70c A |
594 | static void |
595 | kdp_connection_wait(void) | |
1c79356b | 596 | { |
55e303ae A |
597 | unsigned short reply_port; |
598 | boolean_t kdp_call_kdb(); | |
599 | struct ether_addr kdp_mac_addr = kdp_get_mac_addr(); | |
600 | unsigned int ip_addr = ntohl(kdp_get_ip_address()); | |
9bccf70c A |
601 | |
602 | printf( "ethernet MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", | |
603 | kdp_mac_addr.ether_addr_octet[0] & 0xff, | |
604 | kdp_mac_addr.ether_addr_octet[1] & 0xff, | |
605 | kdp_mac_addr.ether_addr_octet[2] & 0xff, | |
606 | kdp_mac_addr.ether_addr_octet[3] & 0xff, | |
607 | kdp_mac_addr.ether_addr_octet[4] & 0xff, | |
608 | kdp_mac_addr.ether_addr_octet[5] & 0xff); | |
609 | ||
610 | printf( "ip address: %d.%d.%d.%d\n", | |
611 | (ip_addr & 0xff000000) >> 24, | |
612 | (ip_addr & 0xff0000) >> 16, | |
613 | (ip_addr & 0xff00) >> 8, | |
614 | (ip_addr & 0xff)); | |
615 | ||
55e303ae A |
616 | printf("\nWaiting for remote debugger connection.\n"); |
617 | ||
618 | if (reattach_wait == 0) { | |
619 | if((kdp_flag & KDP_GETC_ENA) && (0 != kdp_getc())) | |
620 | { | |
621 | printf("Options..... Type\n"); | |
622 | printf("------------ ----\n"); | |
623 | printf("continue.... 'c'\n"); | |
624 | printf("reboot...... 'r'\n"); | |
1c79356b | 625 | #if MACH_KDB |
55e303ae | 626 | printf("enter kdb... 'k'\n"); |
1c79356b | 627 | #endif |
55e303ae A |
628 | } |
629 | } else | |
630 | reattach_wait = 0; | |
9bccf70c | 631 | |
55e303ae A |
632 | exception_seq = 0; |
633 | ||
634 | do { | |
635 | kdp_hdr_t aligned_hdr, *hdr = &aligned_hdr; | |
1c79356b | 636 | |
55e303ae A |
637 | while (!pkt.input) { |
638 | if (kdp_flag & KDP_GETC_ENA) { | |
639 | switch(kdp_getc()) { | |
640 | case 'c': | |
641 | printf("Continuing...\n"); | |
642 | return; | |
643 | case 'r': | |
644 | printf("Rebooting...\n"); | |
645 | kdp_reboot(); | |
646 | break; | |
1c79356b | 647 | #if MACH_KDB |
55e303ae A |
648 | case 'k': |
649 | printf("calling kdb...\n"); | |
650 | if (kdp_call_kdb()) | |
651 | return; | |
652 | else | |
653 | printf("not implemented...\n"); | |
1c79356b | 654 | #endif |
55e303ae A |
655 | default: |
656 | break; | |
657 | } | |
658 | } | |
659 | kdp_poll(); | |
660 | } | |
1c79356b | 661 | |
1c79356b | 662 | #if DO_ALIGN |
55e303ae | 663 | bcopy((char *)&pkt.data[pkt.off], (char *)hdr, sizeof(*hdr)); |
1c79356b | 664 | #else |
55e303ae | 665 | hdr = (kdp_hdr_t *)&pkt.data[pkt.off]; |
1c79356b | 666 | #endif |
55e303ae A |
667 | if (hdr->request == KDP_HOSTREBOOT) { |
668 | kdp_reboot(); | |
669 | /* should not return! */ | |
670 | } | |
671 | if (((hdr->request == KDP_CONNECT) || (hdr->request == KDP_REATTACH)) && | |
672 | !hdr->is_reply && (hdr->seq == exception_seq)) { | |
673 | if (kdp_packet((unsigned char *)&pkt.data[pkt.off], | |
674 | (int *)&pkt.len, | |
675 | (unsigned short *)&reply_port)) | |
676 | kdp_reply(reply_port); | |
677 | if (hdr->request == KDP_REATTACH) { | |
678 | reattach_wait = 0; | |
679 | hdr->request=KDP_DISCONNECT; | |
680 | exception_seq = 0; | |
681 | } | |
682 | } | |
683 | ||
684 | pkt.input = FALSE; | |
685 | } while (!kdp.is_conn); | |
1c79356b | 686 | |
55e303ae A |
687 | if (current_debugger == KDP_CUR_DB) |
688 | active_debugger=1; | |
689 | printf("Connected to remote debugger.\n"); | |
1c79356b A |
690 | } |
691 | ||
9bccf70c | 692 | static void |
1c79356b A |
693 | kdp_send_exception( |
694 | unsigned int exception, | |
695 | unsigned int code, | |
696 | unsigned int subcode | |
697 | ) | |
698 | { | |
699 | unsigned short remote_port; | |
9bccf70c A |
700 | unsigned int timeout_count = 100; |
701 | unsigned int poll_timeout; | |
1c79356b | 702 | |
1c79356b A |
703 | do { |
704 | pkt.off = sizeof (struct ether_header) + sizeof (struct udpiphdr); | |
705 | kdp_exception((unsigned char *)&pkt.data[pkt.off], | |
706 | (int *)&pkt.len, | |
707 | (unsigned short *)&remote_port, | |
708 | (unsigned int)exception, | |
709 | (unsigned int)code, | |
710 | (unsigned int)subcode); | |
9bccf70c | 711 | |
1c79356b A |
712 | kdp_send(remote_port); |
713 | ||
9bccf70c A |
714 | poll_timeout = 50; |
715 | while(!pkt.input && poll_timeout) | |
716 | { | |
717 | kdp_poll(); | |
718 | poll_timeout--; | |
719 | } | |
720 | ||
1c79356b A |
721 | if (pkt.input) { |
722 | if (!kdp_exception_ack(&pkt.data[pkt.off], pkt.len)) { | |
723 | pkt.input = FALSE; | |
1c79356b | 724 | } |
1c79356b | 725 | } |
9bccf70c | 726 | |
1c79356b | 727 | pkt.input = FALSE; |
9bccf70c | 728 | |
1c79356b | 729 | if (kdp.exception_ack_needed) |
9bccf70c | 730 | kdp_us_spin(250000); |
1c79356b A |
731 | |
732 | } while (kdp.exception_ack_needed && timeout_count--); | |
733 | ||
734 | if (kdp.exception_ack_needed) { | |
735 | // give up & disconnect | |
736 | printf("kdp: exception ack timeout\n"); | |
9bccf70c A |
737 | if (current_debugger == KDP_CUR_DB) |
738 | active_debugger=0; | |
1c79356b A |
739 | kdp_reset(); |
740 | } | |
741 | } | |
742 | ||
743 | void | |
744 | kdp_raise_exception( | |
745 | unsigned int exception, | |
746 | unsigned int code, | |
747 | unsigned int subcode, | |
748 | void *saved_state | |
749 | ) | |
750 | { | |
1c79356b A |
751 | int index; |
752 | ||
55e303ae A |
753 | extern unsigned int disableDebugOuput; |
754 | extern unsigned int disableConsoleOutput; | |
755 | ||
9bccf70c A |
756 | disable_preemption(); |
757 | ||
1c79356b A |
758 | if (saved_state == 0) |
759 | printf("kdp_raise_exception with NULL state\n"); | |
760 | ||
761 | index = exception; | |
762 | if (exception != EXC_BREAKPOINT) { | |
763 | if (exception > EXC_BREAKPOINT || exception < EXC_BAD_ACCESS) { | |
764 | index = 0; | |
765 | } | |
766 | printf("%s exception (%x,%x,%x)\n", | |
767 | exception_message[index], | |
768 | exception, code, subcode); | |
769 | } | |
770 | ||
771 | kdp_sync_cache(); | |
772 | ||
773 | /* XXX WMG it seems that sometimes it doesn't work to let kdp_handler | |
774 | * do this. I think the client and the host can get out of sync. | |
775 | */ | |
776 | kdp.saved_state = saved_state; | |
55e303ae | 777 | |
1c79356b A |
778 | if (pkt.input) |
779 | kdp_panic("kdp_raise_exception"); | |
55e303ae A |
780 | |
781 | if (((kdp_flag & KDP_PANIC_DUMP_ENABLED) || (kdp_flag & PANIC_LOG_DUMP)) | |
782 | && (panicstr != (char *) 0)) { | |
783 | ||
784 | kdp_panic_dump(); | |
785 | ||
786 | } | |
787 | else | |
788 | if ((kdp_flag & PANIC_CORE_ON_NMI) && (panicstr == (char *) 0) && | |
789 | !kdp.is_conn) { | |
790 | ||
791 | disableDebugOuput = disableConsoleOutput = FALSE; | |
792 | kdp_panic_dump(); | |
793 | ||
794 | if (!(kdp_flag & DBG_POST_CORE)) | |
795 | goto exit_raise_exception; | |
796 | } | |
797 | ||
9bccf70c | 798 | again: |
1c79356b A |
799 | if (!kdp.is_conn) |
800 | kdp_connection_wait(); | |
55e303ae | 801 | else { |
1c79356b | 802 | kdp_send_exception(exception, code, subcode); |
55e303ae | 803 | if (kdp.exception_ack_needed) { |
9bccf70c A |
804 | kdp.exception_ack_needed = FALSE; |
805 | kdp_remove_all_breakpoints(); | |
806 | printf("Remote debugger disconnected.\n"); | |
807 | } | |
808 | } | |
1c79356b A |
809 | |
810 | if (kdp.is_conn) { | |
811 | kdp.is_halted = TRUE; /* XXX */ | |
812 | kdp_handler(saved_state); | |
813 | if (!kdp.is_conn) | |
9bccf70c A |
814 | { |
815 | kdp_remove_all_breakpoints(); | |
1c79356b | 816 | printf("Remote debugger disconnected.\n"); |
9bccf70c | 817 | } |
1c79356b | 818 | } |
55e303ae A |
819 | /* Allow triggering a panic core dump when connected to the machine |
820 | * Continuing after setting kdp_trigger_core_dump should do the | |
821 | * trick. | |
822 | */ | |
823 | if (1 == kdp_trigger_core_dump) { | |
824 | kdp_flag &= ~PANIC_LOG_DUMP; | |
825 | kdp_flag |= KDP_PANIC_DUMP_ENABLED; | |
826 | kdp_panic_dump(); | |
827 | } | |
1c79356b A |
828 | |
829 | kdp_sync_cache(); | |
9bccf70c A |
830 | |
831 | if (reattach_wait == 1) | |
832 | goto again; | |
55e303ae | 833 | exit_raise_exception: |
9bccf70c | 834 | enable_preemption(); |
1c79356b A |
835 | } |
836 | ||
837 | void | |
838 | kdp_reset(void) | |
839 | { | |
9bccf70c A |
840 | kdp.reply_port = kdp.exception_port = 0; |
841 | kdp.is_halted = kdp.is_conn = FALSE; | |
842 | kdp.exception_seq = kdp.conn_seq = 0; | |
1c79356b A |
843 | } |
844 | ||
55e303ae A |
845 | struct corehdr * |
846 | create_panic_header(unsigned int request, const char *corename, | |
847 | unsigned length, unsigned int block) | |
848 | { | |
849 | struct udpiphdr aligned_ui, *ui = &aligned_ui; | |
850 | struct ip aligned_ip, *ip = &aligned_ip; | |
851 | struct ether_header *eh; | |
852 | struct corehdr *coreh; | |
853 | const char *mode = "octet"; | |
854 | char modelen = strlen(mode); | |
855 | ||
856 | pkt.off = sizeof (struct ether_header); | |
857 | pkt.len = length + ((request == KDP_WRQ) ? modelen : 0) + | |
858 | (corename ? strlen(corename): 0) + sizeof(struct corehdr); | |
859 | ||
860 | #if DO_ALIGN | |
861 | bcopy((char *)&pkt.data[pkt.off], (char *)ui, sizeof(*ui)); | |
862 | #else | |
863 | ui = (struct udpiphdr *)&pkt.data[pkt.off]; | |
864 | #endif | |
865 | ui->ui_next = ui->ui_prev = 0; | |
866 | ui->ui_x1 = 0; | |
867 | ui->ui_pr = IPPROTO_UDP; | |
868 | ui->ui_len = htons((u_short)pkt.len + sizeof (struct udphdr)); | |
869 | ui->ui_src.s_addr = htonl(kdp_current_ip_address); | |
870 | ui->ui_dst.s_addr = panic_server_ip; | |
871 | ui->ui_sport = htons(CORE_REMOTE_PORT); | |
872 | ui->ui_dport = ((request == KDP_WRQ) ? htons(CORE_REMOTE_PORT) : last_panic_port); | |
873 | ui->ui_ulen = ui->ui_len; | |
874 | ui->ui_sum = 0; | |
875 | #if DO_ALIGN | |
876 | bcopy((char *)ui, (char *)&pkt.data[pkt.off], sizeof(*ui)); | |
877 | bcopy((char *)&pkt.data[pkt.off], (char *)ip, sizeof(*ip)); | |
878 | #else | |
879 | ip = (struct ip *)&pkt.data[pkt.off]; | |
880 | #endif | |
881 | ip->ip_len = htons(sizeof (struct udpiphdr) + pkt.len); | |
882 | ip->ip_v = IPVERSION; | |
883 | ip->ip_id = htons(ip_id++); | |
884 | ip->ip_hl = sizeof (struct ip) >> 2; | |
885 | ip->ip_ttl = udp_ttl; | |
886 | ip->ip_sum = 0; | |
887 | ip->ip_sum = htons(~ip_sum((unsigned char *)ip, ip->ip_hl)); | |
888 | #if DO_ALIGN | |
889 | bcopy((char *)ip, (char *)&pkt.data[pkt.off], sizeof(*ip)); | |
890 | #endif | |
891 | ||
892 | pkt.len += sizeof (struct udpiphdr); | |
893 | ||
894 | pkt.off += sizeof (struct udpiphdr); | |
895 | ||
896 | coreh = (struct corehdr *) &pkt.data[pkt.off]; | |
897 | coreh->th_opcode = htons((u_short)request); | |
898 | ||
899 | if (request == KDP_WRQ) | |
900 | { | |
901 | register char *cp; | |
902 | ||
903 | cp = coreh->th_u.tu_rpl; | |
904 | strcpy (cp, corename); | |
905 | cp += strlen(corename); | |
906 | *cp++ = '\0'; | |
907 | strcpy (cp, mode); | |
908 | cp+= modelen; | |
909 | *cp++ = '\0'; | |
910 | } | |
911 | else | |
912 | { | |
913 | coreh->th_block = htonl((unsigned int) block); | |
914 | } | |
915 | ||
916 | pkt.off -= sizeof (struct udpiphdr); | |
917 | pkt.off -= sizeof (struct ether_header); | |
918 | ||
919 | eh = (struct ether_header *)&pkt.data[pkt.off]; | |
920 | enaddr_copy(&kdp_current_mac_address, eh->ether_shost); | |
921 | enaddr_copy(&router_mac, eh->ether_dhost); | |
922 | eh->ether_type = htons(ETHERTYPE_IP); | |
923 | ||
924 | pkt.len += sizeof (struct ether_header); | |
925 | return coreh; | |
926 | } | |
927 | ||
928 | int kdp_send_panic_packets (unsigned int request, char *corename, | |
929 | unsigned int length, unsigned int txstart) | |
930 | { | |
931 | unsigned int txend = txstart + length; | |
932 | int panic_error = 0; | |
933 | ||
934 | if (length <= SEGSIZE) { | |
935 | if ((panic_error = kdp_send_panic_pkt (request, corename, length, (caddr_t) txstart)) < 0) { | |
936 | printf ("kdp_send_panic_pkt failed with error %d\n", panic_error); | |
937 | return panic_error ; | |
938 | } | |
939 | } | |
940 | else | |
941 | { | |
942 | while (txstart <= (txend - SEGSIZE)) { | |
943 | if ((panic_error = kdp_send_panic_pkt (KDP_DATA, NULL, SEGSIZE, (caddr_t) txstart)) < 0) { | |
944 | printf ("kdp_send_panic_pkt failed with error %d\n", panic_error); | |
945 | return panic_error; | |
946 | } | |
947 | txstart += SEGSIZE; | |
948 | if (!(panic_block % 2000)) | |
949 | printf("."); | |
950 | } | |
951 | if (txstart < txend) { | |
952 | kdp_send_panic_pkt(request, corename, (txend - txstart), (caddr_t) txstart); | |
953 | } | |
954 | } | |
955 | } | |
956 | ||
957 | int | |
958 | kdp_send_panic_pkt (unsigned int request, char *corename, | |
959 | unsigned int length, void *panic_data) | |
960 | { | |
961 | struct corehdr *th = NULL; | |
962 | int poll_count = 2500; | |
963 | ||
964 | char rretries = 0, tretries = 0; | |
965 | /* | |
966 | extern signed long gIODebuggerSemaphore; | |
967 | */ | |
968 | pkt.off = pkt.len = 0; | |
969 | ||
970 | if (request == KDP_WRQ) /* longer timeout for initial request */ | |
971 | poll_count += 1000; | |
972 | ||
973 | TRANSMIT_RETRY: | |
974 | tretries++; | |
975 | ||
976 | if (tretries > 2) | |
977 | printf("TX retry #%d ", tretries ); | |
978 | ||
979 | if (tretries >=15) { | |
980 | /* This iokit layer issue can potentially | |
981 | *cause a hang, uncomment to check if it's happening. | |
982 | */ | |
983 | /* | |
984 | if (gIODebuggerSemaphore) | |
985 | printf("The gIODebuggerSemaphore is raised, preventing packet transmission (2760413)\n"); | |
986 | */ | |
987 | ||
988 | printf ("Cannot contact panic server, timing out.\n"); | |
989 | return (-3); | |
990 | } | |
991 | ||
992 | th = create_panic_header(request, corename, length, panic_block); | |
993 | ||
994 | if (request == KDP_DATA || request == KDP_SEEK) { | |
995 | if (!kdp_vm_read ((caddr_t) panic_data, (caddr_t) th->th_data, length)) { | |
996 | memset ((caddr_t) th->th_data, 'X', length); | |
997 | } | |
998 | } | |
999 | ||
1000 | (*kdp_en_send_pkt)(&pkt.data[pkt.off], pkt.len); | |
1001 | ||
1002 | /* Now we have to listen for the ACK */ | |
1003 | RECEIVE_RETRY: | |
1004 | ||
1005 | while (!pkt.input && flag_panic_dump_in_progress && poll_count) { | |
1006 | kdp_poll(); | |
1007 | poll_count--; | |
1008 | } | |
1009 | ||
1010 | if (pkt.input) { | |
1011 | ||
1012 | pkt.input = FALSE; | |
1013 | ||
1014 | th = (struct corehdr *) &pkt.data[pkt.off]; | |
1015 | /* These will eventually have to be ntoh[ls]'ed as appropriate */ | |
1016 | ||
1017 | if (th->th_opcode == KDP_ACK && th->th_block == panic_block) { | |
1018 | } | |
1019 | else | |
1020 | if (th->th_opcode == KDP_ERROR) { | |
1021 | printf("Panic server returned error %d, retrying\n", th->th_code); | |
1022 | poll_count = 1000; | |
1023 | goto TRANSMIT_RETRY; | |
1024 | } | |
1025 | else | |
1026 | if (th->th_block == (panic_block -1)) { | |
1027 | printf("RX retry "); | |
1028 | if (++rretries > 1) | |
1029 | goto TRANSMIT_RETRY; | |
1030 | else | |
1031 | goto RECEIVE_RETRY; | |
1032 | } | |
1033 | } | |
1034 | else | |
1035 | if (!flag_panic_dump_in_progress) /* we received a debugging packet, bail*/ | |
1036 | { | |
1037 | printf("Received a debugger packet,transferring control to debugger\n"); | |
1038 | /* Configure that if not set ..*/ | |
1039 | kdp_flag |= DBG_POST_CORE; | |
1040 | return (-2); | |
1041 | } | |
1042 | else /* We timed out */ | |
1043 | if (0 == poll_count) { | |
1044 | poll_count = 1000; | |
1045 | kdp_us_spin ((tretries%4) * panic_timeout); /* capped linear backoff */ | |
1046 | goto TRANSMIT_RETRY; | |
1047 | } | |
1048 | ||
1049 | panic_block++; | |
1050 | ||
1051 | if (request == KDP_EOF) | |
1052 | printf ("\nTotal number of packets transmitted: %d\n", panic_block); | |
1053 | ||
1054 | return 1; | |
1055 | } | |
1056 | ||
1057 | /* Since we don't seem to have an isdigit() .. */ | |
1058 | static int | |
1059 | isdigit (char c) | |
1060 | { | |
1061 | return ((c > 47) && (c < 58)); | |
1062 | } | |
1063 | /* From user mode Libc - this ought to be in a library */ | |
1064 | static char * | |
1065 | strnstr(s, find, slen) | |
1066 | const char *s; | |
1067 | const char *find; | |
1068 | size_t slen; | |
1069 | { | |
1070 | char c, sc; | |
1071 | size_t len; | |
1072 | ||
1073 | if ((c = *find++) != '\0') { | |
1074 | len = strlen(find); | |
1075 | do { | |
1076 | do { | |
1077 | if ((sc = *s++) == '\0' || slen-- < 1) | |
1078 | return (NULL); | |
1079 | } while (sc != c); | |
1080 | if (len > slen) | |
1081 | return (NULL); | |
1082 | } while (strncmp(s, find, len) != 0); | |
1083 | s--; | |
1084 | } | |
1085 | return ((char *)s); | |
1086 | } | |
1087 | ||
1088 | /* Horrid hack to extract xnu version if possible - a much cleaner approach | |
1089 | * would be to have the integrator run a script which would copy the | |
1090 | * xnu version into a string or an int somewhere at project submission | |
1091 | * time - makes assumptions about sizeof(version), but will not fail if | |
1092 | * it changes, but may be incorrect. | |
1093 | */ | |
1094 | ||
1095 | static int | |
1096 | kdp_get_xnu_version(char *versionbuf) | |
1097 | { | |
1098 | extern const char version[]; | |
1099 | char *versionpos; | |
1100 | char vstr[10]; | |
1101 | int retval = -1; | |
1102 | ||
1103 | strcpy(vstr, "custom"); | |
1104 | if (version) { | |
1105 | if (kdp_vm_read(version, versionbuf, 90)) { | |
1106 | ||
1107 | versionbuf[89] = '\0'; | |
1108 | ||
1109 | versionpos = strnstr(versionbuf, "xnu-", 80); | |
1110 | ||
1111 | if (versionpos) { | |
1112 | strncpy (vstr, versionpos, (isdigit (versionpos[7]) ? 8 : 7)); | |
1113 | vstr[(isdigit (versionpos[7]) ? 8 : 7)] = '\0'; | |
1114 | retval = 0; | |
1115 | } | |
1116 | } | |
1117 | } | |
1118 | strcpy(versionbuf, vstr); | |
1119 | return retval; | |
1120 | } | |
1121 | /* Primary dispatch routine for the system dump */ | |
1122 | void | |
1123 | kdp_panic_dump() | |
1124 | { | |
1125 | char corename[50]; | |
1126 | char coreprefix[10]; | |
1127 | int panic_error; | |
1128 | extern char *debug_buf; | |
1129 | extern vm_map_t kernel_map; | |
1130 | ||
1131 | extern char *inet_aton(const char *cp, struct in_addr *pin); | |
1132 | ||
1133 | extern char *debug_buf; | |
1134 | extern char *debug_buf_ptr; | |
1135 | uint64_t abstime; | |
1136 | ||
1137 | printf ("Entering system dump routine\n"); | |
1138 | ||
1139 | if (!panicd_specified) { | |
1140 | printf ("A panic server was not specified in the boot-args, terminating kernel core dump.\n"); | |
1141 | goto panic_dump_exit; | |
1142 | } | |
1143 | ||
1144 | flag_panic_dump_in_progress = 1; | |
1145 | not_in_kdp = 0; | |
1146 | ||
1147 | if (pkt.input) | |
1148 | kdp_panic("kdp_panic_dump"); | |
1149 | ||
1150 | kdp_get_xnu_version((char *) &pkt.data[0]); | |
1151 | ||
1152 | /* Panic log bit takes precedence over core dump bit */ | |
1153 | if ((panicstr != (char *) 0) && (kdp_flag & PANIC_LOG_DUMP)) | |
1154 | strncpy(coreprefix, "paniclog", sizeof(coreprefix)); | |
1155 | else | |
1156 | strncpy(coreprefix, "core", sizeof(coreprefix)); | |
1157 | ||
1158 | abstime = mach_absolute_time(); | |
1159 | pkt.data[10] = '\0'; | |
1160 | snprintf (corename, sizeof(corename), "%s-%s-%d.%d.%d.%d-%x", | |
1161 | coreprefix, &pkt.data[0], | |
1162 | (kdp_current_ip_address & 0xff000000) >> 24, | |
1163 | (kdp_current_ip_address & 0xff0000) >> 16, | |
1164 | (kdp_current_ip_address & 0xff00) >> 8, | |
1165 | (kdp_current_ip_address & 0xff), | |
1166 | (unsigned int) (abstime & 0xffffffff)); | |
1167 | ||
1168 | if (0 == inet_aton(panicd_ip_str, (struct in_addr *) &panic_server_ip)) { | |
1169 | printf("inet_aton() failed interpreting %s as a panic server IP\n", | |
1170 | panicd_ip_str); | |
1171 | } | |
1172 | else | |
1173 | printf("Attempting connection to panic server configured at IP %s\n", | |
1174 | panicd_ip_str); | |
1175 | ||
1176 | if (router_specified) { | |
1177 | if (0 == inet_aton(router_ip_str, (struct in_addr *) &parsed_router_ip)){ | |
1178 | printf("inet_aton() failed interpreting %s as an IP\n", router_ip); | |
1179 | } | |
1180 | else { | |
1181 | router_ip = parsed_router_ip; | |
1182 | printf("Routing through specified router IP %s (%d)\n", router_ip_str, router_ip); | |
1183 | /* We will eventually need to resolve the router's MAC ourselves, | |
1184 | * if one is specified,rather than being set through the BSD callback | |
1185 | * but the _router_ip option does not function currently | |
1186 | */ | |
1187 | } | |
1188 | } | |
1189 | /* These & 0xffs aren't necessary,but cut&paste is ever so convenient */ | |
1190 | printf("Routing via router MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", | |
1191 | router_mac.ether_addr_octet[0] & 0xff, | |
1192 | router_mac.ether_addr_octet[1] & 0xff, | |
1193 | router_mac.ether_addr_octet[2] & 0xff, | |
1194 | router_mac.ether_addr_octet[3] & 0xff, | |
1195 | router_mac.ether_addr_octet[4] & 0xff, | |
1196 | router_mac.ether_addr_octet[5] & 0xff); | |
1197 | ||
1198 | printf("Kernel map size is %d\n", get_vmmap_size(kernel_map)); | |
1199 | printf ("Sending write request for %s\n", corename); | |
1200 | ||
1201 | if ((panic_error = kdp_send_panic_pkt (KDP_WRQ, corename, 0 , NULL) < 0)) { | |
1202 | printf ("kdp_send_panic_pkt failed with error %d\n", panic_error); | |
1203 | goto panic_dump_exit; | |
1204 | } | |
1205 | ||
1206 | /* Just the panic log requested */ | |
1207 | if ((panicstr != (char *) 0) && (kdp_flag & PANIC_LOG_DUMP)) { | |
1208 | printf("Transmitting panic log, please wait: "); | |
1209 | kdp_send_panic_packets (KDP_DATA, corename, (debug_buf_ptr - debug_buf), (unsigned int) debug_buf); | |
1210 | kdp_send_panic_pkt (KDP_EOF, NULL, 0, ((void *) 0)); | |
1211 | printf("Please file a bug report on this panic, if possible.\n"); | |
1212 | goto panic_dump_exit; | |
1213 | } | |
1214 | ||
1215 | /* We want a core dump if we're here */ | |
1216 | kern_dump(); | |
1217 | panic_dump_exit: | |
1218 | not_in_kdp = 1; | |
1219 | flag_panic_dump_in_progress = 0; | |
1220 | panic_block = 0; | |
1221 | pkt.input = FALSE; | |
1222 | pkt.len = 0; | |
1223 | kdp_reset(); | |
1224 | return; | |
1225 | } | |
1226 | ||
1227 | void | |
1228 | abort_panic_transfer() | |
1229 | { | |
1230 | flag_panic_dump_in_progress = 0; | |
1231 | not_in_kdp = 1; | |
1232 | panic_block = 0; | |
1233 | } |