]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kdp/kdp_udp.c
xnu-123.5.tar.gz
[apple/xnu.git] / osfmk / kdp / kdp_udp.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * Copyright (c) 1993 NeXT Computer, Inc. All rights reserved.
24 *
25 * kdp_udp.c -- Kernel Debugging Protocol UDP implementation.
26 *
27 */
28
29 #include <mach_kdb.h>
30 #include <mach/boolean.h>
31 #include <mach/exception_types.h>
32 #include <mach/mach_types.h>
33 #include <kern/debug.h>
34
35 #include <kdp/kdp_internal.h>
36 #include <kdp/kdp_en_debugger.h>
37 #include <kdp/kdp_udp.h>
38
39 #define DO_ALIGN 1 /* align all packet data accesses */
40
41 extern int kdp_getc(void);
42
43 static
44 u_short ip_id; /* ip packet ctr, for ids */
45
46 /* @(#)udp_usrreq.c 2.2 88/05/23 4.0NFSSRC SMI; from UCB 7.1 6/5/86 */
47
48 /*
49 * UDP protocol implementation.
50 * Per RFC 768, August, 1980.
51 */
52 #define UDP_TTL 60 /* deflt time to live for UDP packets */
53 int udp_ttl=UDP_TTL;
54 static unsigned char exception_seq;
55
56 static struct {
57 unsigned char data[KDP_MAXPACKET];
58 unsigned int off, len;
59 boolean_t input;
60 } pkt, saved_reply;
61
62 struct {
63 struct {
64 struct in_addr in;
65 struct ether_addr ea;
66 } loc;
67 struct {
68 struct in_addr in;
69 struct ether_addr ea;
70 } rmt;
71 } adr;
72
73 static char
74 *exception_message[] = {
75 "Unknown",
76 "Memory access", /* EXC_BAD_ACCESS */
77 "Failed instruction", /* EXC_BAD_INSTRUCTION */
78 "Arithmetic", /* EXC_ARITHMETIC */
79 "Emulation", /* EXC_EMULATION */
80 "Software", /* EXC_SOFTWARE */
81 "Breakpoint" /* EXC_BREAKPOINT */
82 };
83
84 static kdp_send_t kdp_en_send_pkt = 0;
85 static kdp_receive_t kdp_en_recv_pkt = 0;
86
87 static void kdp_handler( void *);
88
89 void
90 kdp_register_send_receive(kdp_send_t send, kdp_receive_t receive)
91 {
92 #define KDP_READY 0x1
93
94 kdp_en_send_pkt = send;
95 kdp_en_recv_pkt = receive;
96 kdp_flag |= KDP_READY;
97 if (current_debugger == NO_CUR_DB)
98 current_debugger = KDP_CUR_DB;
99 if (halt_in_debugger) {
100 kdp_call();
101 halt_in_debugger=0;
102 }
103 }
104
105 static
106 void
107 enaddr_copy(
108 void *src,
109 void *dst
110 )
111 {
112 bcopy((char *)src, (char *)dst, sizeof (struct ether_addr));
113 }
114
115 static
116 unsigned short
117 ip_sum(
118 unsigned char *c,
119 unsigned int hlen
120 )
121 {
122 unsigned int high, low, sum;
123
124 high = low = 0;
125 while (hlen-- > 0) {
126 low += c[1] + c[3];
127 high += c[0] + c[2];
128
129 c += sizeof (int);
130 }
131
132 sum = (high << 8) + low;
133 sum = (sum >> 16) + (sum & 65535);
134
135 return (sum > 65535 ? sum - 65535 : sum);
136 }
137
138 static
139 void
140 kdp_reply(
141 unsigned short reply_port
142 )
143 {
144 struct udpiphdr aligned_ui, *ui = &aligned_ui;
145 struct ip aligned_ip, *ip = &aligned_ip;
146 struct in_addr tmp_ipaddr;
147 struct ether_addr tmp_enaddr;
148 struct ether_header *eh;
149
150 if (!pkt.input)
151 kdp_panic("kdp_reply");
152
153 pkt.off -= sizeof (struct udpiphdr);
154
155 #if DO_ALIGN
156 bcopy((char *)&pkt.data[pkt.off], (char *)ui, sizeof(*ui));
157 #else
158 ui = (struct udpiphdr *)&pkt.data[pkt.off];
159 #endif
160 ui->ui_next = ui->ui_prev = 0;
161 ui->ui_x1 = 0;
162 ui->ui_pr = IPPROTO_UDP;
163 ui->ui_len = htons((u_short)pkt.len + sizeof (struct udphdr));
164 tmp_ipaddr = ui->ui_src;
165 ui->ui_src = ui->ui_dst;
166 ui->ui_dst = tmp_ipaddr;
167 ui->ui_sport = htons(KDP_REMOTE_PORT);
168 ui->ui_dport = reply_port;
169 ui->ui_ulen = ui->ui_len;
170 ui->ui_sum = 0;
171 #if DO_ALIGN
172 bcopy((char *)ui, (char *)&pkt.data[pkt.off], sizeof(*ui));
173
174 bcopy((char *)&pkt.data[pkt.off], (char *)ip, sizeof(*ip));
175 #else
176 ip = (struct ip *)&pkt.data[pkt.off];
177 #endif
178 ip->ip_len = htons(sizeof (struct udpiphdr) + pkt.len);
179 ip->ip_v = IPVERSION;
180 ip->ip_id = htons(ip_id++);
181 ip->ip_hl = sizeof (struct ip) >> 2;
182 ip->ip_ttl = udp_ttl;
183 ip->ip_sum = 0;
184 ip->ip_sum = htons(~ip_sum((unsigned char *)ip, ip->ip_hl));
185 #if DO_ALIGN
186 bcopy((char *)ip, (char *)&pkt.data[pkt.off], sizeof(*ip));
187 #endif
188
189 pkt.len += sizeof (struct udpiphdr);
190
191 pkt.off -= sizeof (struct ether_header);
192
193 eh = (struct ether_header *)&pkt.data[pkt.off];
194 enaddr_copy(eh->ether_shost, &tmp_enaddr);
195 enaddr_copy(eh->ether_dhost, eh->ether_shost);
196 enaddr_copy(&tmp_enaddr, eh->ether_dhost);
197 eh->ether_type = htons(ETHERTYPE_IP);
198
199 pkt.len += sizeof (struct ether_header);
200
201 // save reply for possible retransmission
202 bcopy((char *)&pkt, (char *)&saved_reply, sizeof(pkt));
203
204 (*kdp_en_send_pkt)(&pkt.data[pkt.off], pkt.len);
205
206 // increment expected sequence number
207 exception_seq++;
208 }
209
210 static
211 void
212 kdp_send(
213 unsigned short remote_port
214 )
215 {
216 struct udpiphdr aligned_ui, *ui = &aligned_ui;
217 struct ip aligned_ip, *ip = &aligned_ip;
218 struct ether_header *eh;
219
220 if (pkt.input)
221 kdp_panic("kdp_send");
222
223 pkt.off -= sizeof (struct udpiphdr);
224
225 #if DO_ALIGN
226 bcopy((char *)&pkt.data[pkt.off], (char *)ui, sizeof(*ui));
227 #else
228 ui = (struct udpiphdr *)&pkt.data[pkt.off];
229 #endif
230 ui->ui_next = ui->ui_prev = 0;
231 ui->ui_x1 = 0;
232 ui->ui_pr = IPPROTO_UDP;
233 ui->ui_len = htons((u_short)pkt.len + sizeof (struct udphdr));
234 ui->ui_src = adr.loc.in;
235 ui->ui_dst = adr.rmt.in;
236 ui->ui_sport = htons(KDP_REMOTE_PORT);
237 ui->ui_dport = remote_port;
238 ui->ui_ulen = ui->ui_len;
239 ui->ui_sum = 0;
240 #if DO_ALIGN
241 bcopy((char *)ui, (char *)&pkt.data[pkt.off], sizeof(*ui));
242 bcopy((char *)&pkt.data[pkt.off], (char *)ip, sizeof(*ip));
243 #else
244 ip = (struct ip *)&pkt.data[pkt.off];
245 #endif
246 ip->ip_len = htons(sizeof (struct udpiphdr) + pkt.len);
247 ip->ip_v = IPVERSION;
248 ip->ip_id = htons(ip_id++);
249 ip->ip_hl = sizeof (struct ip) >> 2;
250 ip->ip_ttl = udp_ttl;
251 ip->ip_sum = 0;
252 ip->ip_sum = htons(~ip_sum((unsigned char *)ip, ip->ip_hl));
253 #if DO_ALIGN
254 bcopy((char *)ip, (char *)&pkt.data[pkt.off], sizeof(*ip));
255 #endif
256
257 pkt.len += sizeof (struct udpiphdr);
258
259 pkt.off -= sizeof (struct ether_header);
260
261 eh = (struct ether_header *)&pkt.data[pkt.off];
262 enaddr_copy(&adr.loc.ea, eh->ether_shost);
263 enaddr_copy(&adr.rmt.ea, eh->ether_dhost);
264 eh->ether_type = htons(ETHERTYPE_IP);
265
266 pkt.len += sizeof (struct ether_header);
267
268 (*kdp_en_send_pkt)(&pkt.data[pkt.off], pkt.len);
269 }
270
271 static
272 void
273 kdp_poll(
274 void
275 )
276 {
277 struct ether_header *eh;
278 struct udpiphdr aligned_ui, *ui = &aligned_ui;
279 struct ip aligned_ip, *ip = &aligned_ip;
280 static int msg_printed;
281
282 if (pkt.input)
283 kdp_panic("kdp_poll");
284
285 if (!kdp_en_recv_pkt || !kdp_en_send_pkt) {
286 if( msg_printed == 0) {
287 msg_printed = 1;
288 printf("kdp_poll: no debugger device\n");
289 }
290 return;
291 }
292
293 pkt.off = 0;
294 (*kdp_en_recv_pkt)(pkt.data, &pkt.len, 3/* ms */);
295
296 if (pkt.len == 0)
297 return;
298
299 if (pkt.len < (sizeof (struct ether_header) + sizeof (struct udpiphdr)))
300 return;
301
302 eh = (struct ether_header *)&pkt.data[pkt.off];
303 pkt.off += sizeof (struct ether_header);
304 if (ntohs(eh->ether_type) != ETHERTYPE_IP) {
305 return;
306 }
307
308 #if DO_ALIGN
309 bcopy((char *)&pkt.data[pkt.off], (char *)ui, sizeof(*ui));
310 bcopy((char *)&pkt.data[pkt.off], (char *)ip, sizeof(*ip));
311 #else
312 ui = (struct udpiphdr *)&pkt.data[pkt.off];
313 ip = (struct ip *)&pkt.data[pkt.off];
314 #endif
315
316 pkt.off += sizeof (struct udpiphdr);
317 if (ui->ui_pr != IPPROTO_UDP) {
318 return;
319 }
320
321 if (ip->ip_hl > (sizeof (struct ip) >> 2)) {
322 return;
323 }
324
325 if (ntohs(ui->ui_dport) != KDP_REMOTE_PORT) {
326 return;
327 }
328
329 if (!kdp.is_conn) {
330 enaddr_copy(eh->ether_dhost, &adr.loc.ea);
331 adr.loc.in = ui->ui_dst;
332
333 enaddr_copy(eh->ether_shost, &adr.rmt.ea);
334 adr.rmt.in = ui->ui_src;
335 }
336
337 /*
338 * Calculate kdp packet length.
339 */
340 pkt.len = ntohs((u_short)ui->ui_ulen) - sizeof (struct udphdr);
341 pkt.input = TRUE;
342
343 }
344
345 static
346 void
347 kdp_handler(
348 void *saved_state
349 )
350 {
351 unsigned short reply_port;
352 kdp_hdr_t aligned_hdr, *hdr = &aligned_hdr;
353
354
355 kdp.saved_state = saved_state; // see comment in kdp_raise_exception
356
357 do {
358 while (!pkt.input)
359 kdp_poll();
360
361 #if DO_ALIGN
362 bcopy((char *)&pkt.data[pkt.off], (char *)hdr, sizeof(*hdr));
363 #else
364 hdr = (kdp_hdr_t *)&pkt.data[pkt.off];
365 #endif
366
367 // ignore replies -- we're not expecting them anyway.
368 if (hdr->is_reply) {
369 goto again;
370 }
371
372 // check for retransmitted request
373 if (hdr->seq == (exception_seq - 1)) {
374 /* retransmit last reply */
375 (*kdp_en_send_pkt)(&saved_reply.data[saved_reply.off],
376 saved_reply.len);
377 goto again;
378 } else if (hdr->seq != exception_seq) {
379 printf("kdp: bad sequence %d (want %d)\n",
380 hdr->seq, exception_seq);
381 goto again;
382 }
383
384 if (kdp_packet((unsigned char*)&pkt.data[pkt.off],
385 (int *)&pkt.len,
386 (unsigned short *)&reply_port)) {
387 kdp_reply(reply_port);
388 }
389
390 again:
391 pkt.input = FALSE;
392 } while (kdp.is_halted);
393 }
394
395 static
396 void
397 kdp_connection_wait(
398 void
399 )
400 {
401 unsigned short reply_port;
402 boolean_t kdp_call_kdb();
403
404 printf("\nWaiting for remote debugger connection.\n");
405 #ifdef MACH_PE
406 if( 0 != kdp_getc())
407 #endif
408 {
409 printf("Options..... Type\n");
410 printf("------------ ----\n");
411 printf("continue.... 'c'\n");
412 printf("reboot...... 'r'\n");
413 #if MACH_KDB
414 printf("enter kdb... 'k'\n");
415 #endif
416 }
417
418 exception_seq = 0;
419 do {
420 kdp_hdr_t aligned_hdr, *hdr = &aligned_hdr;
421
422 while (!pkt.input) {
423 int c;
424 c = kdp_getc();
425 switch(c) {
426 case 'c':
427 printf("Continuing...\n");
428 return;
429 case 'r':
430 printf("Rebooting...\n");
431 kdp_reboot();
432 break;
433 #if MACH_KDB
434 case 'k':
435 printf("calling kdb...\n");
436 if (kdp_call_kdb())
437 return;
438 else
439 printf("not implemented...\n");
440 #endif
441 default:
442 break;
443 }
444 kdp_poll();
445 }
446
447 // check for sequence number of 0
448 #if DO_ALIGN
449 bcopy((char *)&pkt.data[pkt.off], (char *)hdr, sizeof(*hdr));
450 #else
451 hdr = (kdp_hdr_t *)&pkt.data[pkt.off];
452 #endif
453 if (hdr->request == KDP_HOSTREBOOT) {
454 kdp_reboot();
455 /* should not return! */
456 }
457 if ((hdr->request == KDP_CONNECT) &&
458 !hdr->is_reply && (hdr->seq == exception_seq)) {
459 if (kdp_packet((unsigned char *)&pkt.data[pkt.off],
460 (int *)&pkt.len,
461 (unsigned short *)&reply_port))
462 kdp_reply(reply_port);
463 }
464
465 pkt.input = FALSE;
466 } while (!kdp.is_conn);
467
468 if (current_debugger == KDP_CUR_DB)
469 active_debugger=1;
470 printf("Connected to remote debugger.\n");
471 }
472
473 static
474 void
475 kdp_send_exception(
476 unsigned int exception,
477 unsigned int code,
478 unsigned int subcode
479 )
480 {
481 unsigned short remote_port;
482 unsigned int timeout_count;
483
484 timeout_count = 300; // should be about 30 seconds
485 do {
486 pkt.off = sizeof (struct ether_header) + sizeof (struct udpiphdr);
487 kdp_exception((unsigned char *)&pkt.data[pkt.off],
488 (int *)&pkt.len,
489 (unsigned short *)&remote_port,
490 (unsigned int)exception,
491 (unsigned int)code,
492 (unsigned int)subcode);
493
494 kdp_send(remote_port);
495
496 again:
497 kdp_poll();
498
499 if (pkt.input) {
500 if (!kdp_exception_ack(&pkt.data[pkt.off], pkt.len)) {
501 pkt.input = FALSE;
502 goto again;
503 }
504 } else {
505 pkt.input = FALSE;
506 goto again;
507 }
508 pkt.input = FALSE;
509 if (kdp.exception_ack_needed)
510 kdp_us_spin(100000); // 1/10 sec
511
512 } while (kdp.exception_ack_needed && timeout_count--);
513
514 if (kdp.exception_ack_needed) {
515 // give up & disconnect
516 printf("kdp: exception ack timeout\n");
517 kdp_reset();
518 }
519 }
520
521 void
522 kdp_raise_exception(
523 unsigned int exception,
524 unsigned int code,
525 unsigned int subcode,
526 void *saved_state
527 )
528 {
529 int s;
530 int index;
531
532 if (saved_state == 0)
533 printf("kdp_raise_exception with NULL state\n");
534
535 index = exception;
536 if (exception != EXC_BREAKPOINT) {
537 if (exception > EXC_BREAKPOINT || exception < EXC_BAD_ACCESS) {
538 index = 0;
539 }
540 printf("%s exception (%x,%x,%x)\n",
541 exception_message[index],
542 exception, code, subcode);
543 }
544
545 kdp_sync_cache();
546
547 /* XXX WMG it seems that sometimes it doesn't work to let kdp_handler
548 * do this. I think the client and the host can get out of sync.
549 */
550 kdp.saved_state = saved_state;
551
552 if (pkt.input)
553 kdp_panic("kdp_raise_exception");
554
555 if (!kdp.is_conn)
556 kdp_connection_wait();
557 else
558 kdp_send_exception(exception, code, subcode);
559
560 if (kdp.is_conn) {
561 kdp.is_halted = TRUE; /* XXX */
562 kdp_handler(saved_state);
563 if (!kdp.is_conn)
564 printf("Remote debugger disconnected.\n");
565 }
566
567 kdp_sync_cache();
568 }
569
570 void
571 kdp_reset(void)
572 {
573 kdp.reply_port = kdp.exception_port = 0;
574 kdp.is_halted = kdp.is_conn = FALSE;
575 kdp.exception_seq = kdp.conn_seq = 0;
576 }
577