xref: /xnu-8020.140.41/osfmk/kdp/kdp.c (revision 27b03b360a988dfd3dfdf34262bb0042026747cc)
1 /*
2  * Copyright (c) 2000-2012 Apple 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 #include <mach/mach_types.h>
30 #include <mach/vm_param.h>
31 #include <sys/appleapiopts.h>
32 #include <kern/debug.h>
33 #include <uuid/uuid.h>
34 
35 #include <kdp/kdp_internal.h>
36 #include <kdp/kdp_private.h>
37 #include <kdp/kdp_core.h>
38 
39 #include <libsa/types.h>
40 #include <libkern/section_keywords.h>
41 #include <libkern/version.h>
42 
43 #include <string.h> /* bcopy */
44 
45 #include <kern/processor.h>
46 #include <kern/thread.h>
47 #include <kern/clock.h>
48 #include <vm/vm_map.h>
49 #include <vm/vm_kern.h>
50 #include <vm/vm_pageout.h>
51 #include <vm/vm_shared_region.h>
52 #include <libkern/OSKextLibPrivate.h>
53 
54 #define DO_ALIGN        1       /* align all packet data accesses */
55 
56 #define KDP_TEST_HARNESS 0
57 #if KDP_TEST_HARNESS
58 #define dprintf(x) kprintf x
59 #else
60 #define dprintf(x)
61 #endif
62 
63 SECURITY_READ_ONLY_EARLY(static kdp_dispatch_t)
64 dispatch_table[KDP_INVALID_REQUEST - KDP_CONNECT] =
65 {
66 /* 0 */ kdp_connect,
67 /* 1 */ kdp_disconnect,
68 /* 2 */ kdp_hostinfo,
69 /* 3 */ kdp_version,
70 /* 4 */ kdp_maxbytes,
71 /* 5 */ kdp_readmem,
72 /* 6 */ kdp_writemem,
73 /* 7 */ kdp_readregs,
74 /* 8 */ kdp_writeregs,
75 /* 9 */ kdp_unknown,
76 /* A */ kdp_unknown,
77 /* B */ kdp_suspend,
78 /* C */ kdp_resumecpus,
79 /* D */ kdp_unknown,
80 /* E */ kdp_unknown,
81 /* F */ kdp_breakpoint_set,
82 /*10 */ kdp_breakpoint_remove,
83 /*11 */ kdp_regions,
84 /*12 */ kdp_reattach,
85 /*13 */ kdp_reboot,
86 /*14 */ kdp_readmem64,
87 /*15 */ kdp_writemem64,
88 /*16 */ kdp_breakpoint64_set,
89 /*17 */ kdp_breakpoint64_remove,
90 /*18 */ kdp_kernelversion,
91 /*19 */ kdp_readphysmem64,
92 /*1A */ kdp_writephysmem64,
93 /*1B */ kdp_readioport,
94 /*1C */ kdp_writeioport,
95 /*1D */ kdp_readmsr64,
96 /*1E */ kdp_writemsr64,
97 /*1F */ kdp_dumpinfo,
98 };
99 
100 kdp_glob_t      kdp;
101 
102 #define MAX_BREAKPOINTS 100
103 
104 /*
105  * Version 11 of the KDP Protocol adds support for 64-bit wide memory
106  * addresses (read/write and breakpoints) as well as a dedicated
107  * kernelversion request. Version 12 adds read/writing of physical
108  * memory with 64-bit wide memory addresses.
109  */
110 #define KDP_VERSION 12
111 
112 typedef struct{
113 	mach_vm_address_t       address;
114 	uint32_t        bytesused;
115 	uint8_t         oldbytes[MAX_BREAKINSN_BYTES];
116 } kdp_breakpoint_record_t;
117 
118 static kdp_breakpoint_record_t breakpoint_list[MAX_BREAKPOINTS];
119 static unsigned int breakpoints_initialized = 0;
120 
121 int reattach_wait = 0;
122 int noresume_on_disconnect = 0;
123 
124 kdp_error_t
125 kdp_set_breakpoint_internal(
126 	mach_vm_address_t    address
127 	);
128 
129 kdp_error_t
130 kdp_remove_breakpoint_internal(
131 	mach_vm_address_t    address
132 	);
133 
134 boolean_t
kdp_packet(unsigned char * pkt,int * len,unsigned short * reply_port)135 kdp_packet(
136 	unsigned char       *pkt,
137 	int                 *len,
138 	unsigned short      *reply_port
139 	)
140 {
141 	static unsigned     aligned_pkt[1538 / sizeof(unsigned) + 1];// max ether pkt
142 	kdp_pkt_t           *rd = (kdp_pkt_t *)&aligned_pkt;
143 	size_t              plen = *len;
144 	kdp_req_t           req;
145 	boolean_t           ret;
146 
147 #if DO_ALIGN
148 	if (plen > sizeof(aligned_pkt)) {
149 		printf("kdp_packet bad len %lu\n", plen);
150 		return FALSE;
151 	}
152 	bcopy((char *)pkt, (char *)rd, plen);
153 #else
154 	rd = (kdp_pkt_t *)pkt;
155 #endif
156 	if (plen < sizeof(rd->hdr) || rd->hdr.len != plen) {
157 		printf("kdp_packet bad len pkt %lu hdr %d\n", plen, rd->hdr.len);
158 
159 		return FALSE;
160 	}
161 
162 	if (rd->hdr.is_reply) {
163 		printf("kdp_packet reply recvd req %x seq %x\n",
164 		    rd->hdr.request, rd->hdr.seq);
165 
166 		return FALSE;
167 	}
168 
169 	req = rd->hdr.request;
170 	if (req >= KDP_INVALID_REQUEST) {
171 		printf("kdp_packet bad request %x len %d seq %x key %x\n",
172 		    rd->hdr.request, rd->hdr.len, rd->hdr.seq, rd->hdr.key);
173 
174 		return FALSE;
175 	}
176 
177 	ret = ((*dispatch_table[req - KDP_CONNECT])(rd, len, reply_port));
178 #if DO_ALIGN
179 	bcopy((char *)rd, (char *) pkt, *len);
180 #endif
181 	return ret;
182 }
183 
184 static boolean_t
kdp_unknown(kdp_pkt_t * pkt,__unused int * len,__unused unsigned short * reply_port)185 kdp_unknown(
186 	kdp_pkt_t           *pkt,
187 	__unused int        *len,
188 	__unused unsigned short     *reply_port
189 	)
190 {
191 	kdp_pkt_t           *rd = (kdp_pkt_t *)pkt;
192 
193 	printf("kdp_unknown request %x len %d seq %x key %x\n",
194 	    rd->hdr.request, rd->hdr.len, rd->hdr.seq, rd->hdr.key);
195 
196 	return FALSE;
197 }
198 
199 static boolean_t
kdp_connect(kdp_pkt_t * pkt,int * len,unsigned short * reply_port)200 kdp_connect(
201 	kdp_pkt_t           *pkt,
202 	int                 *len,
203 	unsigned short      *reply_port
204 	)
205 {
206 	kdp_connect_req_t   *rq = &pkt->connect_req;
207 	size_t              plen = *len;
208 	kdp_connect_reply_t *rp = &pkt->connect_reply;
209 	uint16_t            rport, eport;
210 	uint32_t            key;
211 	uint8_t             seq;
212 
213 	if (plen < sizeof(*rq)) {
214 		return FALSE;
215 	}
216 
217 	dprintf(("kdp_connect seq %x greeting %s\n", rq->hdr.seq, rq->greeting));
218 
219 	rport = rq->req_reply_port;
220 	eport = rq->exc_note_port;
221 	key   = rq->hdr.key;
222 	seq   = rq->hdr.seq;
223 	if (kdp.is_conn) {
224 		if ((seq == kdp.conn_seq) && /* duplicate request */
225 		    (rport == kdp.reply_port) &&
226 		    (eport == kdp.exception_port) &&
227 		    (key == kdp.session_key)) {
228 			rp->error = KDPERR_NO_ERROR;
229 		} else {
230 			rp->error = KDPERR_ALREADY_CONNECTED;
231 		}
232 	} else {
233 		kdp.reply_port     = rport;
234 		kdp.exception_port = eport;
235 		kdp.is_conn        = TRUE;
236 		kdp.conn_seq       = seq;
237 		kdp.session_key    = key;
238 
239 		rp->error = KDPERR_NO_ERROR;
240 	}
241 
242 	rp->hdr.is_reply = 1;
243 	rp->hdr.len = sizeof(*rp);
244 
245 	*reply_port = rport;
246 	*len = rp->hdr.len;
247 
248 	if (current_debugger == KDP_CUR_DB) {
249 		active_debugger = 1;
250 	}
251 
252 	return TRUE;
253 }
254 
255 static boolean_t
kdp_disconnect(kdp_pkt_t * pkt,int * len,unsigned short * reply_port)256 kdp_disconnect(
257 	kdp_pkt_t           *pkt,
258 	int                 *len,
259 	unsigned short      *reply_port
260 	)
261 {
262 	kdp_disconnect_req_t        *rq = &pkt->disconnect_req;
263 	size_t                      plen = *len;
264 	kdp_disconnect_reply_t      *rp = &pkt->disconnect_reply;
265 
266 	if (plen < sizeof(*rq)) {
267 		return FALSE;
268 	}
269 
270 	if (!kdp.is_conn) {
271 		return FALSE;
272 	}
273 
274 	dprintf(("kdp_disconnect\n"));
275 
276 	*reply_port = kdp.reply_port;
277 
278 	kdp.reply_port = kdp.exception_port = 0;
279 	kdp.is_halted = kdp.is_conn = FALSE;
280 	kdp.exception_seq = kdp.conn_seq = 0;
281 	kdp.session_key = 0;
282 
283 	if (debugger_panic_str != NULL) {
284 		reattach_wait = 1;
285 	}
286 
287 	if (noresume_on_disconnect == 1) {
288 		reattach_wait = 1;
289 		noresume_on_disconnect = 0;
290 	}
291 
292 	rp->hdr.is_reply = 1;
293 	rp->hdr.len = sizeof(*rp);
294 
295 	*len = rp->hdr.len;
296 
297 	if (current_debugger == KDP_CUR_DB) {
298 		active_debugger = 0;
299 	}
300 
301 	return TRUE;
302 }
303 
304 static boolean_t
kdp_reattach(kdp_pkt_t * pkt,int * len,unsigned short * reply_port)305 kdp_reattach(
306 	kdp_pkt_t           *pkt,
307 	int                 *len,
308 	unsigned short      *reply_port
309 	)
310 {
311 	kdp_reattach_req_t            *rq = &pkt->reattach_req;
312 
313 	kdp.is_conn = TRUE;
314 	kdp_disconnect(pkt, len, reply_port);
315 	*reply_port = rq->req_reply_port;
316 	reattach_wait = 1;
317 	return TRUE;
318 }
319 
320 static boolean_t
kdp_hostinfo(kdp_pkt_t * pkt,int * len,unsigned short * reply_port)321 kdp_hostinfo(
322 	kdp_pkt_t           *pkt,
323 	int                 *len,
324 	unsigned short      *reply_port
325 	)
326 {
327 	kdp_hostinfo_req_t  *rq = &pkt->hostinfo_req;
328 	size_t              plen = *len;
329 	kdp_hostinfo_reply_t *rp = &pkt->hostinfo_reply;
330 
331 	if (plen < sizeof(*rq)) {
332 		return FALSE;
333 	}
334 
335 	dprintf(("kdp_hostinfo\n"));
336 
337 	rp->hdr.is_reply = 1;
338 	rp->hdr.len = sizeof(*rp);
339 
340 	kdp_machine_hostinfo(&rp->hostinfo);
341 
342 	*reply_port = kdp.reply_port;
343 	*len = rp->hdr.len;
344 
345 	return TRUE;
346 }
347 
348 static boolean_t
kdp_kernelversion(kdp_pkt_t * pkt,int * len,unsigned short * reply_port)349 kdp_kernelversion(
350 	kdp_pkt_t           *pkt,
351 	int                 *len,
352 	unsigned short      *reply_port
353 	)
354 {
355 	kdp_kernelversion_req_t     *rq = &pkt->kernelversion_req;
356 	size_t              plen = *len;
357 	kdp_kernelversion_reply_t *rp = &pkt->kernelversion_reply;
358 	size_t          slen;
359 
360 	if (plen < sizeof(*rq)) {
361 		return FALSE;
362 	}
363 
364 	rp->hdr.is_reply = 1;
365 	rp->hdr.len = sizeof(*rp);
366 
367 	dprintf(("kdp_kernelversion\n"));
368 	slen = strlcpy(rp->version, kdp_kernelversion_string, MAX_KDP_DATA_SIZE);
369 
370 	rp->hdr.len += slen + 1; /* strlcpy returns the amount copied with NUL */
371 
372 	*reply_port = kdp.reply_port;
373 	*len = rp->hdr.len;
374 
375 	return TRUE;
376 }
377 
378 static boolean_t
kdp_suspend(kdp_pkt_t * pkt,int * len,unsigned short * reply_port)379 kdp_suspend(
380 	kdp_pkt_t           *pkt,
381 	int                 *len,
382 	unsigned short      *reply_port
383 	)
384 {
385 	kdp_suspend_req_t   *rq = &pkt->suspend_req;
386 	size_t              plen = *len;
387 	kdp_suspend_reply_t *rp = &pkt->suspend_reply;
388 
389 	if (plen < sizeof(*rq)) {
390 		return FALSE;
391 	}
392 
393 	rp->hdr.is_reply = 1;
394 	rp->hdr.len = sizeof(*rp);
395 
396 	dprintf(("kdp_suspend\n"));
397 
398 	kdp.is_halted = TRUE;
399 
400 	*reply_port = kdp.reply_port;
401 	*len = rp->hdr.len;
402 
403 	return TRUE;
404 }
405 
406 static boolean_t
kdp_resumecpus(kdp_pkt_t * pkt,int * len,unsigned short * reply_port)407 kdp_resumecpus(
408 	kdp_pkt_t           *pkt,
409 	int                 *len,
410 	unsigned short      *reply_port
411 	)
412 {
413 	kdp_resumecpus_req_t        *rq = &pkt->resumecpus_req;
414 	size_t                      plen = *len;
415 	kdp_resumecpus_reply_t      *rp = &pkt->resumecpus_reply;
416 
417 	if (plen < sizeof(*rq)) {
418 		return FALSE;
419 	}
420 
421 	rp->hdr.is_reply = 1;
422 	rp->hdr.len = sizeof(*rp);
423 
424 	dprintf(("kdp_resumecpus %x\n", rq->cpu_mask));
425 
426 	kdp.is_halted = FALSE;
427 
428 	*reply_port = kdp.reply_port;
429 	*len = rp->hdr.len;
430 
431 	return TRUE;
432 }
433 
434 static boolean_t
kdp_writemem(kdp_pkt_t * pkt,int * len,unsigned short * reply_port)435 kdp_writemem(
436 	kdp_pkt_t           *pkt,
437 	int                 *len,
438 	unsigned short      *reply_port
439 	)
440 {
441 	kdp_writemem_req_t  *rq = &pkt->writemem_req;
442 	size_t              plen = *len;
443 	kdp_writemem_reply_t *rp = &pkt->writemem_reply;
444 	mach_vm_size_t      cnt;
445 
446 	if (plen < sizeof(*rq)) {
447 		return FALSE;
448 	}
449 
450 	if (rq->nbytes > MAX_KDP_DATA_SIZE) {
451 		rp->error = KDPERR_BAD_NBYTES;
452 	} else {
453 		dprintf(("kdp_writemem addr %x size %d\n", rq->address, rq->nbytes));
454 		cnt = kdp_machine_vm_write((caddr_t)rq->data, (mach_vm_address_t)rq->address, rq->nbytes);
455 		rp->error = KDPERR_ACCESS(rq->nbytes, cnt);
456 		dprintf(("  cnt %lld error %d\n", cnt, rp->error));
457 	}
458 
459 	rp->hdr.is_reply = 1;
460 	rp->hdr.len = sizeof(*rp);
461 
462 	*reply_port = kdp.reply_port;
463 	*len = rp->hdr.len;
464 
465 	return TRUE;
466 }
467 
468 static boolean_t
kdp_writemem64(kdp_pkt_t * pkt,int * len,unsigned short * reply_port)469 kdp_writemem64(
470 	kdp_pkt_t           *pkt,
471 	int                 *len,
472 	unsigned short      *reply_port
473 	)
474 {
475 	kdp_writemem64_req_t        *rq = &pkt->writemem64_req;
476 	size_t              plen = *len;
477 	kdp_writemem64_reply_t *rp = &pkt->writemem64_reply;
478 	mach_vm_size_t              cnt;
479 
480 	if (plen < sizeof(*rq)) {
481 		return FALSE;
482 	}
483 
484 	if (rq->nbytes > MAX_KDP_DATA_SIZE) {
485 		rp->error = KDPERR_BAD_NBYTES;
486 	} else {
487 		dprintf(("kdp_writemem64 addr %llx size %d\n", rq->address, rq->nbytes));
488 		cnt = kdp_machine_vm_write((caddr_t)rq->data, (mach_vm_address_t)rq->address, (mach_vm_size_t)rq->nbytes);
489 		rp->error = KDPERR_ACCESS(rq->nbytes, cnt);
490 		dprintf(("  cnt %lld error %d\n", cnt, rp->error));
491 	}
492 
493 	rp->hdr.is_reply = 1;
494 	rp->hdr.len = sizeof(*rp);
495 
496 	*reply_port = kdp.reply_port;
497 	*len = rp->hdr.len;
498 
499 	return TRUE;
500 }
501 
502 static boolean_t
kdp_writephysmem64(kdp_pkt_t * pkt,int * len,unsigned short * reply_port)503 kdp_writephysmem64(
504 	kdp_pkt_t           *pkt,
505 	int                 *len,
506 	unsigned short      *reply_port
507 	)
508 {
509 	kdp_writephysmem64_req_t    *rq = &pkt->writephysmem64_req;
510 	size_t              plen = *len;
511 	kdp_writephysmem64_reply_t *rp = &pkt->writephysmem64_reply;
512 	mach_vm_size_t              cnt;
513 	unsigned int                size;
514 
515 	if (plen < sizeof(*rq)) {
516 		return FALSE;
517 	}
518 
519 	size = rq->nbytes;
520 	if (size > MAX_KDP_DATA_SIZE) {
521 		rp->error = KDPERR_BAD_NBYTES;
522 	} else {
523 		dprintf(("kdp_writephysmem64 addr %llx size %d\n", rq->address, size));
524 		cnt = kdp_machine_phys_write(rq, rq->data, rq->lcpu);
525 		rp->error = KDPERR_ACCESS(size, cnt);
526 		dprintf(("  cnt %lld error %d\n", cnt, rp->error));
527 	}
528 
529 	rp->hdr.is_reply = 1;
530 	rp->hdr.len = sizeof(*rp);
531 
532 	*reply_port = kdp.reply_port;
533 	*len = rp->hdr.len;
534 
535 	return TRUE;
536 }
537 
538 static boolean_t
kdp_readmem(kdp_pkt_t * pkt,int * len,unsigned short * reply_port)539 kdp_readmem(
540 	kdp_pkt_t           *pkt,
541 	int                 *len,
542 	unsigned short      *reply_port
543 	)
544 {
545 	kdp_readmem_req_t   *rq = &pkt->readmem_req;
546 	size_t              plen = *len;
547 	kdp_readmem_reply_t *rp = &pkt->readmem_reply;
548 	mach_vm_size_t      cnt;
549 	unsigned int        size;
550 
551 	if (plen < sizeof(*rq)) {
552 		return FALSE;
553 	}
554 
555 	rp->hdr.is_reply = 1;
556 	rp->hdr.len = sizeof(*rp);
557 
558 	size = rq->nbytes;
559 	if (size > MAX_KDP_DATA_SIZE) {
560 		rp->error = KDPERR_BAD_NBYTES;
561 	} else {
562 		dprintf(("kdp_readmem addr %x size %d\n", rq->address, size));
563 		cnt = kdp_machine_vm_read((mach_vm_address_t)rq->address, (caddr_t)rp->data, rq->nbytes);
564 		rp->error = KDPERR_ACCESS(size, cnt);
565 		dprintf(("  cnt %lld error %d\n", cnt, rp->error));
566 
567 		rp->hdr.len += cnt;
568 	}
569 
570 	*reply_port = kdp.reply_port;
571 	*len = rp->hdr.len;
572 
573 	return TRUE;
574 }
575 
576 static boolean_t
kdp_readmem64(kdp_pkt_t * pkt,int * len,unsigned short * reply_port)577 kdp_readmem64(
578 	kdp_pkt_t           *pkt,
579 	int                 *len,
580 	unsigned short      *reply_port
581 	)
582 {
583 	kdp_readmem64_req_t *rq = &pkt->readmem64_req;
584 	size_t              plen = *len;
585 	kdp_readmem64_reply_t *rp = &pkt->readmem64_reply;
586 	mach_vm_size_t      cnt;
587 	unsigned int        size;
588 
589 	if (plen < sizeof(*rq)) {
590 		return FALSE;
591 	}
592 
593 	rp->hdr.is_reply = 1;
594 	rp->hdr.len = sizeof(*rp);
595 
596 	size = rq->nbytes;
597 	if (size > MAX_KDP_DATA_SIZE) {
598 		rp->error = KDPERR_BAD_NBYTES;
599 	} else {
600 		dprintf(("kdp_readmem64 addr %llx size %d\n", rq->address, size));
601 		cnt = kdp_machine_vm_read((mach_vm_address_t)rq->address, (caddr_t)rp->data, rq->nbytes);
602 		rp->error = KDPERR_ACCESS(size, cnt);
603 		dprintf(("  cnt %lld error %d\n", cnt, rp->error));
604 
605 		rp->hdr.len += cnt;
606 	}
607 
608 	*reply_port = kdp.reply_port;
609 	*len = rp->hdr.len;
610 
611 	return TRUE;
612 }
613 
614 static boolean_t
kdp_readphysmem64(kdp_pkt_t * pkt,int * len,unsigned short * reply_port)615 kdp_readphysmem64(
616 	kdp_pkt_t           *pkt,
617 	int                 *len,
618 	unsigned short      *reply_port
619 	)
620 {
621 	kdp_readphysmem64_req_t     *rq = &pkt->readphysmem64_req;
622 	size_t              plen = *len;
623 	kdp_readphysmem64_reply_t *rp = &pkt->readphysmem64_reply;
624 	mach_vm_size_t      cnt;
625 	unsigned int        size;
626 
627 	if (plen < sizeof(*rq)) {
628 		return FALSE;
629 	}
630 
631 	rp->hdr.is_reply = 1;
632 	rp->hdr.len = sizeof(*rp);
633 
634 	size = rq->nbytes;
635 	if (size > MAX_KDP_DATA_SIZE) {
636 		rp->error = KDPERR_BAD_NBYTES;
637 	} else {
638 		dprintf(("kdp_readphysmem64 addr %llx size %d\n", rq->address, size));
639 		cnt = kdp_machine_phys_read(rq, rp->data, rq->lcpu);
640 		rp->error = KDPERR_ACCESS(size, cnt);
641 		dprintf(("  cnt %lld error %d\n", cnt, rp->error));
642 
643 		rp->hdr.len += cnt;
644 	}
645 
646 	*reply_port = kdp.reply_port;
647 	*len = rp->hdr.len;
648 
649 	return TRUE;
650 }
651 
652 static boolean_t
kdp_maxbytes(kdp_pkt_t * pkt,int * len,unsigned short * reply_port)653 kdp_maxbytes(
654 	kdp_pkt_t           *pkt,
655 	int                 *len,
656 	unsigned short      *reply_port
657 	)
658 {
659 	kdp_maxbytes_req_t  *rq = &pkt->maxbytes_req;
660 	size_t              plen = *len;
661 	kdp_maxbytes_reply_t *rp = &pkt->maxbytes_reply;
662 
663 	if (plen < sizeof(*rq)) {
664 		return FALSE;
665 	}
666 
667 	rp->hdr.is_reply = 1;
668 	rp->hdr.len = sizeof(*rp);
669 
670 	dprintf(("kdp_maxbytes\n"));
671 
672 	rp->max_bytes = MAX_KDP_DATA_SIZE;
673 
674 	*reply_port = kdp.reply_port;
675 	*len = rp->hdr.len;
676 
677 	return TRUE;
678 }
679 
680 static boolean_t
kdp_version(kdp_pkt_t * pkt,int * len,unsigned short * reply_port)681 kdp_version(
682 	kdp_pkt_t           *pkt,
683 	int                 *len,
684 	unsigned short      *reply_port
685 	)
686 {
687 	kdp_version_req_t   *rq = &pkt->version_req;
688 	size_t              plen = *len;
689 	kdp_version_reply_t *rp = &pkt->version_reply;
690 
691 	if (plen < sizeof(*rq)) {
692 		return FALSE;
693 	}
694 
695 	rp->hdr.is_reply = 1;
696 	rp->hdr.len = sizeof(*rp);
697 
698 	dprintf(("kdp_version\n"));
699 
700 	rp->version = KDP_VERSION;
701 	if (!(kdp_flag & KDP_BP_DIS)) {
702 		rp->feature = KDP_FEATURE_BP;
703 	} else {
704 		rp->feature = 0;
705 	}
706 
707 	*reply_port = kdp.reply_port;
708 	*len = rp->hdr.len;
709 
710 	return TRUE;
711 }
712 
713 static boolean_t
kdp_regions(kdp_pkt_t * pkt,int * len,unsigned short * reply_port)714 kdp_regions(
715 	kdp_pkt_t           *pkt,
716 	int                 *len,
717 	unsigned short      *reply_port
718 	)
719 {
720 	kdp_regions_req_t   *rq = &pkt->regions_req;
721 	size_t              plen = *len;
722 	kdp_regions_reply_t *rp = &pkt->regions_reply;
723 	kdp_region_t        *r;
724 
725 	if (plen < sizeof(*rq)) {
726 		return FALSE;
727 	}
728 
729 	rp->hdr.is_reply = 1;
730 	rp->hdr.len = sizeof(*rp);
731 
732 	dprintf(("kdp_regions\n"));
733 
734 	r = rp->regions;
735 	rp->nregions = 0;
736 
737 	r->address = 0;
738 	r->nbytes = 0xffffffff;
739 
740 	r->protection = VM_PROT_ALL; r++; rp->nregions++;
741 
742 	rp->hdr.len += rp->nregions * sizeof(kdp_region_t);
743 
744 	*reply_port = kdp.reply_port;
745 	*len = rp->hdr.len;
746 
747 	return TRUE;
748 }
749 
750 static boolean_t
kdp_writeregs(kdp_pkt_t * pkt,int * len,unsigned short * reply_port)751 kdp_writeregs(
752 	kdp_pkt_t           *pkt,
753 	int                 *len,
754 	unsigned short      *reply_port
755 	)
756 {
757 	kdp_writeregs_req_t *rq = &pkt->writeregs_req;
758 	size_t              plen = *len;
759 	int                 size;
760 	kdp_writeregs_reply_t *rp = &pkt->writeregs_reply;
761 
762 	if (plen < sizeof(*rq)) {
763 		return FALSE;
764 	}
765 
766 	size = rq->hdr.len - (unsigned)sizeof(kdp_hdr_t) - (unsigned)sizeof(unsigned int);
767 	rp->error = kdp_machine_write_regs(rq->cpu, rq->flavor, rq->data, &size);
768 
769 	rp->hdr.is_reply = 1;
770 	rp->hdr.len = sizeof(*rp);
771 
772 	*reply_port = kdp.reply_port;
773 	*len = rp->hdr.len;
774 
775 	return TRUE;
776 }
777 
778 static boolean_t
kdp_readregs(kdp_pkt_t * pkt,int * len,unsigned short * reply_port)779 kdp_readregs(
780 	kdp_pkt_t           *pkt,
781 	int                 *len,
782 	unsigned short      *reply_port
783 	)
784 {
785 	kdp_readregs_req_t  *rq = &pkt->readregs_req;
786 	size_t              plen = *len;
787 	kdp_readregs_reply_t *rp = &pkt->readregs_reply;
788 	int                 size;
789 
790 	if (plen < sizeof(*rq)) {
791 		return FALSE;
792 	}
793 
794 	rp->hdr.is_reply = 1;
795 	rp->hdr.len = sizeof(*rp);
796 
797 	rp->error = kdp_machine_read_regs(rq->cpu, rq->flavor, rp->data, &size);
798 	rp->hdr.len += size;
799 
800 	*reply_port = kdp.reply_port;
801 	*len = rp->hdr.len;
802 
803 	return TRUE;
804 }
805 
806 
807 boolean_t
kdp_breakpoint_set(kdp_pkt_t * pkt,int * len,unsigned short * reply_port)808 kdp_breakpoint_set(
809 	kdp_pkt_t           *pkt,
810 	int                 *len,
811 	unsigned short      *reply_port
812 	)
813 {
814 	kdp_breakpoint_req_t    *rq = &pkt->breakpoint_req;
815 	kdp_breakpoint_reply_t *rp = &pkt->breakpoint_reply;
816 	size_t          plen = *len;
817 	kdp_error_t     kerr;
818 
819 	if (plen < sizeof(*rq)) {
820 		return FALSE;
821 	}
822 
823 	dprintf(("kdp_breakpoint_set %x\n", rq->address));
824 
825 	kerr = kdp_set_breakpoint_internal((mach_vm_address_t)rq->address);
826 
827 	rp->error = kerr;
828 
829 	rp->hdr.is_reply = 1;
830 	rp->hdr.len = sizeof(*rp);
831 	*reply_port = kdp.reply_port;
832 	*len = rp->hdr.len;
833 
834 	return TRUE;
835 }
836 
837 boolean_t
kdp_breakpoint64_set(kdp_pkt_t * pkt,int * len,unsigned short * reply_port)838 kdp_breakpoint64_set(
839 	kdp_pkt_t           *pkt,
840 	int                 *len,
841 	unsigned short      *reply_port
842 	)
843 {
844 	kdp_breakpoint64_req_t  *rq = &pkt->breakpoint64_req;
845 	kdp_breakpoint64_reply_t *rp = &pkt->breakpoint64_reply;
846 	size_t          plen = *len;
847 	kdp_error_t     kerr;
848 
849 	if (plen < sizeof(*rq)) {
850 		return FALSE;
851 	}
852 
853 	dprintf(("kdp_breakpoint64_set %llx\n", rq->address));
854 
855 	kerr = kdp_set_breakpoint_internal((mach_vm_address_t)rq->address);
856 
857 	rp->error = kerr;
858 
859 	rp->hdr.is_reply = 1;
860 	rp->hdr.len = sizeof(*rp);
861 	*reply_port = kdp.reply_port;
862 	*len = rp->hdr.len;
863 
864 	return TRUE;
865 }
866 
867 boolean_t
kdp_breakpoint_remove(kdp_pkt_t * pkt,int * len,unsigned short * reply_port)868 kdp_breakpoint_remove(
869 	kdp_pkt_t           *pkt,
870 	int                 *len,
871 	unsigned short      *reply_port
872 	)
873 {
874 	kdp_breakpoint_req_t    *rq = &pkt->breakpoint_req;
875 	kdp_breakpoint_reply_t *rp = &pkt->breakpoint_reply;
876 	size_t          plen = *len;
877 	kdp_error_t     kerr;
878 	if (plen < sizeof(*rq)) {
879 		return FALSE;
880 	}
881 
882 	dprintf(("kdp_breakpoint_remove %x\n", rq->address));
883 
884 	kerr = kdp_remove_breakpoint_internal((mach_vm_address_t)rq->address);
885 
886 	rp->error = kerr;
887 
888 	rp->hdr.is_reply = 1;
889 	rp->hdr.len = sizeof(*rp);
890 	*reply_port = kdp.reply_port;
891 	*len = rp->hdr.len;
892 
893 	return TRUE;
894 }
895 
896 boolean_t
kdp_breakpoint64_remove(kdp_pkt_t * pkt,int * len,unsigned short * reply_port)897 kdp_breakpoint64_remove(
898 	kdp_pkt_t           *pkt,
899 	int                 *len,
900 	unsigned short      *reply_port
901 	)
902 {
903 	kdp_breakpoint64_req_t  *rq = &pkt->breakpoint64_req;
904 	kdp_breakpoint64_reply_t *rp = &pkt->breakpoint64_reply;
905 	size_t          plen = *len;
906 	kdp_error_t     kerr;
907 
908 	if (plen < sizeof(*rq)) {
909 		return FALSE;
910 	}
911 
912 	dprintf(("kdp_breakpoint64_remove %llx\n", rq->address));
913 
914 	kerr = kdp_remove_breakpoint_internal((mach_vm_address_t)rq->address);
915 
916 	rp->error = kerr;
917 
918 	rp->hdr.is_reply = 1;
919 	rp->hdr.len = sizeof(*rp);
920 	*reply_port = kdp.reply_port;
921 	*len = rp->hdr.len;
922 
923 	return TRUE;
924 }
925 
926 
927 kdp_error_t
kdp_set_breakpoint_internal(mach_vm_address_t address)928 kdp_set_breakpoint_internal(
929 	mach_vm_address_t   address
930 	)
931 {
932 	uint8_t         breakinstr[MAX_BREAKINSN_BYTES], oldinstr[MAX_BREAKINSN_BYTES];
933 	uint32_t        breakinstrsize = sizeof(breakinstr);
934 	mach_vm_size_t  cnt;
935 	int                     i;
936 
937 	kdp_machine_get_breakinsn(breakinstr, &breakinstrsize);
938 
939 	if (breakpoints_initialized == 0) {
940 		for (i = 0; (i < MAX_BREAKPOINTS); breakpoint_list[i].address = 0, i++) {
941 			;
942 		}
943 		breakpoints_initialized++;
944 	}
945 
946 	cnt = kdp_machine_vm_read(address, (caddr_t)&oldinstr, (mach_vm_size_t)breakinstrsize);
947 
948 	if (0 == memcmp(oldinstr, breakinstr, breakinstrsize)) {
949 		printf("A trap was already set at that address, not setting new breakpoint\n");
950 
951 		return KDPERR_BREAKPOINT_ALREADY_SET;
952 	}
953 
954 	for (i = 0; (i < MAX_BREAKPOINTS) && (breakpoint_list[i].address != 0); i++) {
955 		;
956 	}
957 
958 	if (i == MAX_BREAKPOINTS) {
959 		return KDPERR_MAX_BREAKPOINTS;
960 	}
961 
962 	breakpoint_list[i].address =  address;
963 	memcpy(breakpoint_list[i].oldbytes, oldinstr, breakinstrsize);
964 	breakpoint_list[i].bytesused =  breakinstrsize;
965 
966 	cnt = kdp_machine_vm_write((caddr_t)&breakinstr, address, breakinstrsize);
967 
968 	return KDPERR_NO_ERROR;
969 }
970 
971 kdp_error_t
kdp_remove_breakpoint_internal(mach_vm_address_t address)972 kdp_remove_breakpoint_internal(
973 	mach_vm_address_t   address
974 	)
975 {
976 	mach_vm_size_t  cnt;
977 	int             i;
978 
979 	for (i = 0; (i < MAX_BREAKPOINTS) && (breakpoint_list[i].address != address); i++) {
980 		;
981 	}
982 
983 	if (i == MAX_BREAKPOINTS) {
984 		return KDPERR_BREAKPOINT_NOT_FOUND;
985 	}
986 
987 	breakpoint_list[i].address = 0;
988 	cnt = kdp_machine_vm_write((caddr_t)&breakpoint_list[i].oldbytes, address, breakpoint_list[i].bytesused);
989 
990 	return KDPERR_NO_ERROR;
991 }
992 
993 boolean_t
kdp_remove_all_breakpoints(void)994 kdp_remove_all_breakpoints(void)
995 {
996 	int i;
997 	boolean_t breakpoint_found = FALSE;
998 
999 	if (breakpoints_initialized) {
1000 		for (i = 0; i < MAX_BREAKPOINTS; i++) {
1001 			if (breakpoint_list[i].address) {
1002 				kdp_machine_vm_write((caddr_t)&(breakpoint_list[i].oldbytes), (mach_vm_address_t)breakpoint_list[i].address, (mach_vm_size_t)breakpoint_list[i].bytesused);
1003 				breakpoint_found = TRUE;
1004 				breakpoint_list[i].address = 0;
1005 			}
1006 		}
1007 
1008 		if (breakpoint_found) {
1009 			printf("kdp_remove_all_breakpoints: found extant breakpoints, removing them.\n");
1010 		}
1011 	}
1012 	return breakpoint_found;
1013 }
1014 
1015 boolean_t
kdp_reboot(__unused kdp_pkt_t * pkt,__unused int * len,__unused unsigned short * reply_port)1016 kdp_reboot(
1017 	__unused kdp_pkt_t *pkt,
1018 	__unused int    *len,
1019 	__unused unsigned short *reply_port
1020 	)
1021 {
1022 	dprintf(("kdp_reboot\n"));
1023 
1024 	kdp_machine_reboot();
1025 
1026 	return TRUE; // no, not really, we won't return
1027 }
1028 
1029 static boolean_t
kdp_readioport(kdp_pkt_t * pkt,int * len,unsigned short * reply_port)1030 kdp_readioport(
1031 	kdp_pkt_t           *pkt,
1032 	int                 *len,
1033 	unsigned short      *reply_port
1034 	)
1035 {
1036 	kdp_readioport_req_t   *rq = &pkt->readioport_req;
1037 	kdp_readioport_reply_t *rp = &pkt->readioport_reply;
1038 	size_t plen = *len;
1039 
1040 	if (plen < sizeof(*rq)) {
1041 		return FALSE;
1042 	}
1043 
1044 	rp->hdr.is_reply = 1;
1045 	rp->hdr.len = sizeof(*rp);
1046 
1047 	if (rq->nbytes > MAX_KDP_DATA_SIZE) {
1048 		rp->error = KDPERR_BAD_NBYTES;
1049 	} else {
1050 #if KDP_TEST_HARNESS
1051 		uint16_t addr = rq->address;
1052 #endif
1053 		uint16_t size = rq->nbytes;
1054 		dprintf(("kdp_readioport addr %x size %d\n", addr, size));
1055 
1056 		rp->error = kdp_machine_ioport_read(rq, rp->data, rq->lcpu);
1057 		if (rp->error == KDPERR_NO_ERROR) {
1058 			rp->hdr.len += size;
1059 		}
1060 	}
1061 
1062 	*reply_port = kdp.reply_port;
1063 	*len = rp->hdr.len;
1064 
1065 	return TRUE;
1066 }
1067 
1068 static boolean_t
kdp_writeioport(kdp_pkt_t * pkt,int * len,unsigned short * reply_port)1069 kdp_writeioport(
1070 	kdp_pkt_t       *pkt,
1071 	int             *len,
1072 	unsigned short  *reply_port
1073 	)
1074 {
1075 	kdp_writeioport_req_t   *rq = &pkt->writeioport_req;
1076 	kdp_writeioport_reply_t *rp = &pkt->writeioport_reply;
1077 	size_t  plen = *len;
1078 
1079 	if (plen < sizeof(*rq)) {
1080 		return FALSE;
1081 	}
1082 
1083 	if (rq->nbytes > MAX_KDP_DATA_SIZE) {
1084 		rp->error = KDPERR_BAD_NBYTES;
1085 	} else {
1086 		dprintf(("kdp_writeioport addr %x size %d\n", rq->address,
1087 		    rq->nbytes));
1088 
1089 		rp->error = kdp_machine_ioport_write(rq, rq->data, rq->lcpu);
1090 	}
1091 
1092 	rp->hdr.is_reply = 1;
1093 	rp->hdr.len = sizeof(*rp);
1094 
1095 	*reply_port = kdp.reply_port;
1096 	*len = rp->hdr.len;
1097 
1098 	return TRUE;
1099 }
1100 
1101 static boolean_t
kdp_readmsr64(kdp_pkt_t * pkt,int * len,unsigned short * reply_port)1102 kdp_readmsr64(
1103 	kdp_pkt_t               *pkt,
1104 	int                     *len,
1105 	unsigned short  *reply_port
1106 	)
1107 {
1108 	kdp_readmsr64_req_t   *rq = &pkt->readmsr64_req;
1109 	kdp_readmsr64_reply_t *rp = &pkt->readmsr64_reply;
1110 	size_t plen = *len;
1111 
1112 	if (plen < sizeof(*rq)) {
1113 		return FALSE;
1114 	}
1115 
1116 	rp->hdr.is_reply = 1;
1117 	rp->hdr.len = sizeof(*rp);
1118 
1119 	dprintf(("kdp_readmsr64 lcpu %x addr %x\n", rq->lcpu, rq->address));
1120 	rp->error = kdp_machine_msr64_read(rq, rp->data, rq->lcpu);
1121 	if (rp->error == KDPERR_NO_ERROR) {
1122 		rp->hdr.len += sizeof(uint64_t);
1123 	}
1124 
1125 	*reply_port = kdp.reply_port;
1126 	*len = rp->hdr.len;
1127 
1128 	return TRUE;
1129 }
1130 
1131 static boolean_t
kdp_writemsr64(kdp_pkt_t * pkt,int * len,unsigned short * reply_port)1132 kdp_writemsr64(
1133 	kdp_pkt_t       *pkt,
1134 	int             *len,
1135 	unsigned short  *reply_port
1136 	)
1137 {
1138 	kdp_writemsr64_req_t   *rq = &pkt->writemsr64_req;
1139 	kdp_writemsr64_reply_t *rp = &pkt->writemsr64_reply;
1140 	size_t  plen = *len;
1141 
1142 	if (plen < sizeof(*rq)) {
1143 		return FALSE;
1144 	}
1145 
1146 	dprintf(("kdp_writemsr64 lcpu %x addr %x\n", rq->lcpu, rq->address));
1147 	rp->error = kdp_machine_msr64_write(rq, rq->data, rq->lcpu);
1148 
1149 	rp->hdr.is_reply = 1;
1150 	rp->hdr.len = sizeof(*rp);
1151 
1152 	*reply_port = kdp.reply_port;
1153 	*len = rp->hdr.len;
1154 
1155 	return TRUE;
1156 }
1157 
1158 static boolean_t
kdp_dumpinfo(kdp_pkt_t * pkt,int * len,unsigned short * reply_port)1159 kdp_dumpinfo(
1160 	kdp_pkt_t       *pkt,
1161 	int             *len,
1162 	unsigned short  *reply_port
1163 	)
1164 {
1165 	kdp_dumpinfo_req_t   *rq = &pkt->dumpinfo_req;
1166 	kdp_dumpinfo_reply_t *rp = &pkt->dumpinfo_reply;
1167 	size_t  plen = *len;
1168 
1169 	if (plen < sizeof(*rq)) {
1170 		return FALSE;
1171 	}
1172 
1173 	dprintf(("kdp_dumpinfo file=%s destip=%s routerip=%s\n", rq->name, rq->destip, rq->routerip));
1174 	rp->hdr.is_reply = 1;
1175 	rp->hdr.len = sizeof(*rp);
1176 
1177 	if ((rq->type & KDP_DUMPINFO_MASK) != KDP_DUMPINFO_GETINFO) {
1178 		kdp_set_dump_info(rq->type, rq->name, rq->destip, rq->routerip,
1179 		    rq->port);
1180 	}
1181 
1182 	/* gather some stats for reply */
1183 	kdp_get_dump_info(rp);
1184 
1185 	*reply_port = kdp.reply_port;
1186 	*len = rp->hdr.len;
1187 
1188 	return TRUE;
1189 }
1190