]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kdp/kdp.c
xnu-344.21.74.tar.gz
[apple/xnu.git] / osfmk / kdp / kdp.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
d7e50217 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
d7e50217
A
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
d7e50217
A
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
1c79356b
A
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
1c79356b
A
25
26#include <mach/mach_types.h>
27#include <kern/debug.h>
28
29#include <kdp/kdp_internal.h>
30#include <kdp/kdp_private.h>
31
9bccf70c
A
32#include <libsa/types.h>
33
1c79356b
A
34int kdp_vm_read( caddr_t, caddr_t, unsigned int);
35int kdp_vm_write( caddr_t, caddr_t, unsigned int);
36
37#define DO_ALIGN 1 /* align all packet data accesses */
38
39#define KDP_TEST_HARNESS 0
40#if KDP_TEST_HARNESS
41#define dprintf(x) kprintf x
42#else
43#define dprintf(x)
44#endif
45
46static kdp_dispatch_t
9bccf70c 47 dispatch_table[KDP_REATTACH - KDP_CONNECT +1] =
1c79356b
A
48 {
49/* 0 */ kdp_connect,
50/* 1 */ kdp_disconnect,
51/* 2 */ kdp_hostinfo,
9bccf70c 52/* 3 */ kdp_version,
1c79356b
A
53/* 4 */ kdp_maxbytes,
54/* 5 */ kdp_readmem,
55/* 6 */ kdp_writemem,
56/* 7 */ kdp_readregs,
57/* 8 */ kdp_writeregs,
9bccf70c
A
58/* 9 */ kdp_unknown,
59/* A */ kdp_unknown,
1c79356b
A
60/* B */ kdp_suspend,
61/* C */ kdp_resumecpus,
62/* D */ kdp_unknown,
9bccf70c
A
63/* E */ kdp_unknown,
64/* F */ kdp_breakpoint_set,
65/*10 */ kdp_breakpoint_remove,
66/*11 */ kdp_regions,
67/*12 */ kdp_reattach
1c79356b
A
68 };
69
70kdp_glob_t kdp;
9bccf70c
A
71
72
73#define MAX_BREAKPOINTS 100
74#define KDP_MAX_BREAKPOINTS 100
75
76#define BREAKPOINT_NOT_FOUND 101
77#define BREAKPOINT_ALREADY_SET 102
78
79#define KDP_VERSION 10
80
81typedef struct{
82 unsigned int address;
83 unsigned int old_instruction;
84} kdp_breakpoint_record_t;
85
86static kdp_breakpoint_record_t breakpoint_list[MAX_BREAKPOINTS];
87static unsigned int breakpoints_initialized = 0;
88int reattach_wait = 0;
1c79356b
A
89
90boolean_t
91kdp_packet(
92 unsigned char *pkt,
93 int *len,
94 unsigned short *reply_port
95)
96{
97 static unsigned aligned_pkt[1538/sizeof(unsigned)+1]; // max ether pkt
98 kdp_pkt_t *rd = (kdp_pkt_t *)&aligned_pkt;
99 int plen = *len;
100 unsigned int req;
101 boolean_t ret;
102
103#if DO_ALIGN
104 bcopy((char *)pkt, (char *)rd, sizeof(aligned_pkt));
105#else
106 rd = (kdp_pkt_t *)pkt;
107#endif
108 if (plen < sizeof (rd->hdr) || rd->hdr.len != plen) {
109 printf("kdp_packet bad len pkt %d hdr %d\n", plen, rd->hdr.len);
110
111 return (FALSE);
112 }
113
114 if (rd->hdr.is_reply) {
115 printf("kdp_packet reply recvd req %x seq %x\n",
116 rd->hdr.request, rd->hdr.seq);
117
118 return (FALSE);
119 }
120
121 req = rd->hdr.request;
9bccf70c 122 if ((req < KDP_CONNECT) || (req > KDP_REATTACH)) {
1c79356b
A
123 printf("kdp_packet bad request %x len %d seq %x key %x\n",
124 rd->hdr.request, rd->hdr.len, rd->hdr.seq, rd->hdr.key);
125
126 return (FALSE);
127 }
128
129 ret = ((*dispatch_table[req - KDP_CONNECT])(rd, len, reply_port));
130#if DO_ALIGN
131 bcopy((char *)rd, (char *) pkt, *len);
132#endif
133 return ret;
134}
135
136static boolean_t
137kdp_unknown(
138 kdp_pkt_t *pkt,
139 int *len,
140 unsigned short *reply_port
141)
142{
143 kdp_pkt_t *rd = (kdp_pkt_t *)pkt;
144
145 printf("kdp_unknown request %x len %d seq %x key %x\n",
146 rd->hdr.request, rd->hdr.len, rd->hdr.seq, rd->hdr.key);
147
148 return (FALSE);
149}
150
151static boolean_t
152kdp_connect(
153 kdp_pkt_t *pkt,
154 int *len,
155 unsigned short *reply_port
156)
157{
158 kdp_connect_req_t *rq = &pkt->connect_req;
159 int plen = *len;
160 kdp_connect_reply_t *rp = &pkt->connect_reply;
161
162 if (plen < sizeof (*rq))
163 return (FALSE);
164
165 dprintf(("kdp_connect seq %x greeting %s\n", rq->hdr.seq, rq->greeting));
166
167 if (kdp.is_conn) {
168 if (rq->hdr.seq == kdp.conn_seq) /* duplicate request */
169 rp->error = KDPERR_NO_ERROR;
170 else
171 rp->error = KDPERR_ALREADY_CONNECTED;
172 }
173 else {
174 kdp.reply_port = rq->req_reply_port;
175 kdp.exception_port = rq->exc_note_port;
176 kdp.is_conn = TRUE;
177 kdp.conn_seq = rq->hdr.seq;
178
179 rp->error = KDPERR_NO_ERROR;
180 }
181
182 rp->hdr.is_reply = 1;
183 rp->hdr.len = sizeof (*rp);
184
185 *reply_port = kdp.reply_port;
186 *len = rp->hdr.len;
187
188 if (current_debugger == KDP_CUR_DB)
189 active_debugger=1;
190
191 return (TRUE);
192}
193
194static boolean_t
195kdp_disconnect(
196 kdp_pkt_t *pkt,
197 int *len,
198 unsigned short *reply_port
199)
200{
201 kdp_disconnect_req_t *rq = &pkt->disconnect_req;
202 int plen = *len;
203 kdp_disconnect_reply_t *rp = &pkt->disconnect_reply;
204
205 if (plen < sizeof (*rq))
206 return (FALSE);
207
208 if (!kdp.is_conn)
209 return (FALSE);
210
211 dprintf(("kdp_disconnect\n"));
212
213 *reply_port = kdp.reply_port;
214
215 kdp.reply_port = kdp.exception_port = 0;
216 kdp.is_halted = kdp.is_conn = FALSE;
217 kdp.exception_seq = kdp.conn_seq = 0;
218
219 rp->hdr.is_reply = 1;
220 rp->hdr.len = sizeof (*rp);
221
222 *len = rp->hdr.len;
223
224 if (current_debugger == KDP_CUR_DB)
225 active_debugger=0;
226
227 return (TRUE);
228}
229
9bccf70c
A
230static boolean_t
231kdp_reattach(
232 kdp_pkt_t *pkt,
233 int *len,
234 unsigned short *reply_port
235)
236{
237 kdp_reattach_req_t *rq = &pkt->reattach_req;
238 kdp_disconnect_reply_t *rp = &pkt->disconnect_reply;
239
240 kdp.is_conn = TRUE;
241 kdp_disconnect(pkt, len, reply_port);
242 *reply_port = rq->req_reply_port;
243 reattach_wait = 1;
244 return (TRUE);
245}
246
1c79356b
A
247static boolean_t
248kdp_hostinfo(
249 kdp_pkt_t *pkt,
250 int *len,
251 unsigned short *reply_port
252)
253{
254 kdp_hostinfo_req_t *rq = &pkt->hostinfo_req;
255 int plen = *len;
256 kdp_hostinfo_reply_t *rp = &pkt->hostinfo_reply;
257
258 if (plen < sizeof (*rq))
259 return (FALSE);
260
261 rp->hdr.is_reply = 1;
262 rp->hdr.len = sizeof (*rp);
263
264 kdp_machine_hostinfo(&rp->hostinfo);
9bccf70c 265
1c79356b
A
266 *reply_port = kdp.reply_port;
267 *len = rp->hdr.len;
268
269 return (TRUE);
270}
271
272static boolean_t
273kdp_suspend(
274 kdp_pkt_t *pkt,
275 int *len,
276 unsigned short *reply_port
277)
278{
279 kdp_suspend_req_t *rq = &pkt->suspend_req;
280 int plen = *len;
281 kdp_suspend_reply_t *rp = &pkt->suspend_reply;
282
283 if (plen < sizeof (*rq))
284 return (FALSE);
285
286 rp->hdr.is_reply = 1;
287 rp->hdr.len = sizeof (*rp);
288
289 dprintf(("kdp_suspend\n"));
290
291 kdp.is_halted = TRUE;
292
293 *reply_port = kdp.reply_port;
294 *len = rp->hdr.len;
295
296 return (TRUE);
297}
298
299static boolean_t
300kdp_resumecpus(
301 kdp_pkt_t *pkt,
302 int *len,
303 unsigned short *reply_port
304)
305{
306 kdp_resumecpus_req_t *rq = &pkt->resumecpus_req;
307 int plen = *len;
308 kdp_resumecpus_reply_t *rp = &pkt->resumecpus_reply;
309
310 if (plen < sizeof (*rq))
311 return (FALSE);
312
313 rp->hdr.is_reply = 1;
314 rp->hdr.len = sizeof (*rp);
315
316 dprintf(("kdp_resumecpus %x\n", rq->cpu_mask));
9bccf70c 317
1c79356b
A
318 kdp.is_halted = FALSE;
319
320 *reply_port = kdp.reply_port;
321 *len = rp->hdr.len;
322
323 return (TRUE);
324}
325
326static boolean_t
327kdp_writemem(
328 kdp_pkt_t *pkt,
329 int *len,
330 unsigned short *reply_port
331)
332{
333 kdp_writemem_req_t *rq = &pkt->writemem_req;
334 int plen = *len;
335 kdp_writemem_reply_t *rp = &pkt->writemem_reply;
336 int cnt;
337
338 if (plen < sizeof (*rq))
339 return (FALSE);
340
341 if (rq->nbytes > MAX_KDP_DATA_SIZE)
342 rp->error = KDPERR_BAD_NBYTES;
343 else {
344 dprintf(("kdp_writemem addr %x size %d\n", rq->address, rq->nbytes));
345
346 cnt = kdp_vm_write((caddr_t)rq->data, (caddr_t)rq->address, rq->nbytes);
347 rp->error = KDPERR_NO_ERROR;
348 }
349
350 rp->hdr.is_reply = 1;
351 rp->hdr.len = sizeof (*rp);
352
353 *reply_port = kdp.reply_port;
354 *len = rp->hdr.len;
355
356 return (TRUE);
357}
358
359static boolean_t
360kdp_readmem(
361 kdp_pkt_t *pkt,
362 int *len,
363 unsigned short *reply_port
364)
365{
366 kdp_readmem_req_t *rq = &pkt->readmem_req;
367 int plen = *len;
368 kdp_readmem_reply_t *rp = &pkt->readmem_reply;
369 int cnt;
370
371 if (plen < sizeof (*rq))
372 return (FALSE);
373
374 rp->hdr.is_reply = 1;
375 rp->hdr.len = sizeof (*rp);
376
377 if (rq->nbytes > MAX_KDP_DATA_SIZE)
378 rp->error = KDPERR_BAD_NBYTES;
379 else {
380 unsigned int n = rq->nbytes;
381
382 dprintf(("kdp_readmem addr %x size %d\n", rq->address, rq->nbytes));
383
384 cnt = kdp_vm_read((caddr_t)rq->address, (caddr_t)rp->data, rq->nbytes);
385 rp->error = KDPERR_NO_ERROR;
386
387 rp->hdr.len += cnt;
388 }
389
390 *reply_port = kdp.reply_port;
391 *len = rp->hdr.len;
392
393 return (TRUE);
394}
395
396static boolean_t
397kdp_maxbytes(
398 kdp_pkt_t *pkt,
399 int *len,
400 unsigned short *reply_port
401)
402{
403 kdp_maxbytes_req_t *rq = &pkt->maxbytes_req;
404 int plen = *len;
405 kdp_maxbytes_reply_t *rp = &pkt->maxbytes_reply;
406
407 if (plen < sizeof (*rq))
408 return (FALSE);
409
410 rp->hdr.is_reply = 1;
411 rp->hdr.len = sizeof (*rp);
412
413 dprintf(("kdp_maxbytes\n"));
414
415 rp->max_bytes = MAX_KDP_DATA_SIZE;
416
417 *reply_port = kdp.reply_port;
418 *len = rp->hdr.len;
419
420 return (TRUE);
421}
422
9bccf70c
A
423static boolean_t
424kdp_version(
425 kdp_pkt_t *pkt,
426 int *len,
427 unsigned short *reply_port
428)
429{
430 kdp_version_req_t *rq = &pkt->version_req;
431 int plen = *len;
432 kdp_version_reply_t *rp = &pkt->version_reply;
433 kdp_region_t *r;
434
435 if (plen < sizeof (*rq))
436 return (FALSE);
437
438 rp->hdr.is_reply = 1;
439 rp->hdr.len = sizeof (*rp);
440
441 dprintf(("kdp_version\n"));
442
443 rp->version = KDP_VERSION;
444#ifdef __ppc__
445 if (!(kdp_flag & KDP_BP_DIS))
446 rp->feature = KDP_FEATURE_BP;
447 else
448 rp->feature = 0;
449#else
450 rp->feature = 0;
451#endif
452
453 *reply_port = kdp.reply_port;
454 *len = rp->hdr.len;
455
456 return (TRUE);
457}
458
1c79356b
A
459static boolean_t
460kdp_regions(
461 kdp_pkt_t *pkt,
462 int *len,
463 unsigned short *reply_port
464)
465{
466 kdp_regions_req_t *rq = &pkt->regions_req;
467 int plen = *len;
468 kdp_regions_reply_t *rp = &pkt->regions_reply;
469 kdp_region_t *r;
470
471 if (plen < sizeof (*rq))
472 return (FALSE);
473
474 rp->hdr.is_reply = 1;
475 rp->hdr.len = sizeof (*rp);
476
477 dprintf(("kdp_regions\n"));
478
479 r = rp->regions;
480 rp->nregions = 0;
481
482 (vm_offset_t)r->address = 0;
483 r->nbytes = 0xffffffff;
484
485 r->protection = VM_PROT_ALL; r++; rp->nregions++;
486
487 rp->hdr.len += rp->nregions * sizeof (kdp_region_t);
488
489 *reply_port = kdp.reply_port;
490 *len = rp->hdr.len;
491
492 return (TRUE);
493}
494
495static boolean_t
496kdp_writeregs(
497 kdp_pkt_t *pkt,
498 int *len,
499 unsigned short *reply_port
500)
501{
502 kdp_writeregs_req_t *rq = &pkt->writeregs_req;
503 int plen = *len;
504 int size;
505 kdp_writeregs_reply_t *rp = &pkt->writeregs_reply;
506
507 if (plen < sizeof (*rq))
508 return (FALSE);
509
510 size = rq->hdr.len - sizeof(kdp_hdr_t) - sizeof(unsigned int);
511 rp->error = kdp_machine_write_regs(rq->cpu, rq->flavor, rq->data, &size);
512
513 rp->hdr.is_reply = 1;
514 rp->hdr.len = sizeof (*rp);
515
516 *reply_port = kdp.reply_port;
517 *len = rp->hdr.len;
518
519 return (TRUE);
520}
521
522static boolean_t
523kdp_readregs(
524 kdp_pkt_t *pkt,
525 int *len,
526 unsigned short *reply_port
527)
528{
529 kdp_readregs_req_t *rq = &pkt->readregs_req;
530 int plen = *len;
531 kdp_readregs_reply_t *rp = &pkt->readregs_reply;
532 int size;
533
534 if (plen < sizeof (*rq))
535 return (FALSE);
536
537 rp->hdr.is_reply = 1;
538 rp->hdr.len = sizeof (*rp);
539
540 rp->error = kdp_machine_read_regs(rq->cpu, rq->flavor, rp->data, &size);
541 rp->hdr.len += size;
542
543 *reply_port = kdp.reply_port;
544 *len = rp->hdr.len;
545
546 return (TRUE);
547}
9bccf70c
A
548
549static boolean_t
550kdp_breakpoint_set(
551 kdp_pkt_t *pkt,
552 int *len,
553 unsigned short *reply_port
554)
555{
556 kdp_breakpoint_req_t *rq = &pkt->breakpoint_req;
557 kdp_breakpoint_reply_t *rp = &pkt->breakpoint_reply;
558 int plen = *len;
559 int cnt, i;
560 unsigned int old_instruction = 0;
561 unsigned int breakinstr = kdp_ml_get_breakinsn();
562
563 if(breakpoints_initialized == 0)
564 {
565 for(i=0;(i < MAX_BREAKPOINTS); breakpoint_list[i].address=0, i++);
566 breakpoints_initialized++;
567 }
568 if (plen < sizeof (*rq))
569 return (FALSE);
570 cnt = kdp_vm_read((caddr_t)rq->address, (caddr_t)(&old_instruction), sizeof(int));
571
572 if (old_instruction==breakinstr)
573 {
574 printf("A trap was already set at that address, not setting new breakpoint\n");
575 rp->error = BREAKPOINT_ALREADY_SET;
576
577 rp->hdr.is_reply = 1;
578 rp->hdr.len = sizeof (*rp);
579 *reply_port = kdp.reply_port;
580 *len = rp->hdr.len;
581
582 return (TRUE);
583 }
584
585 for(i=0;(i < MAX_BREAKPOINTS) && (breakpoint_list[i].address != 0); i++);
586
587 if (i == MAX_BREAKPOINTS)
588 {
589 rp->error = KDP_MAX_BREAKPOINTS;
590
591 rp->hdr.is_reply = 1;
592 rp->hdr.len = sizeof (*rp);
593 *reply_port = kdp.reply_port;
594 *len = rp->hdr.len;
595
596 return (TRUE);
597 }
598 breakpoint_list[i].address = rq->address;
599 breakpoint_list[i].old_instruction = old_instruction;
600
601 cnt = kdp_vm_write((caddr_t)&breakinstr, (caddr_t)rq->address, sizeof(&breakinstr));
602
603 rp->error = KDPERR_NO_ERROR;
604 rp->hdr.is_reply = 1;
605 rp->hdr.len = sizeof (*rp);
606 *reply_port = kdp.reply_port;
607 *len = rp->hdr.len;
608
609 return (TRUE);
610}
611
612static boolean_t
613kdp_breakpoint_remove(
614 kdp_pkt_t *pkt,
615 int *len,
616 unsigned short *reply_port
617)
618{
619 kdp_breakpoint_req_t *rq = &pkt->breakpoint_req;
620 kdp_breakpoint_reply_t *rp = &pkt->breakpoint_reply;
621 int plen = *len;
622 int cnt,i;
623
624 if (plen < sizeof (*rq))
625 return (FALSE);
626
627 for(i=0;(i < MAX_BREAKPOINTS) && (breakpoint_list[i].address != rq->address); i++);
628 if (i == MAX_BREAKPOINTS)
629 {
630 rp->error = BREAKPOINT_NOT_FOUND;
631 rp->hdr.is_reply = 1;
632 rp->hdr.len = sizeof (*rp);
633 *reply_port = kdp.reply_port;
634 *len = rp->hdr.len;
635
636 return (TRUE); /* Check if it needs to be FALSE in case of error */
637 }
638
639 breakpoint_list[i].address = 0;
640 cnt = kdp_vm_write((caddr_t)&(breakpoint_list[i].old_instruction), (caddr_t)rq->address, sizeof(int));
641 rp->error = KDPERR_NO_ERROR;
642 rp->hdr.is_reply = 1;
643 rp->hdr.len = sizeof (*rp);
644 *reply_port = kdp.reply_port;
645 *len = rp->hdr.len;
646
647 return (TRUE);
648}
649
650boolean_t
651kdp_remove_all_breakpoints()
652{
653 int i;
654 boolean_t breakpoint_found = FALSE;
655
656 if (breakpoints_initialized)
657 {
658 for(i=0;i < MAX_BREAKPOINTS; i++)
659 {
660 if (breakpoint_list[i].address)
661 {
662 kdp_vm_write((caddr_t)&(breakpoint_list[i].old_instruction), (caddr_t)breakpoint_list[i].address, sizeof(int));
663 breakpoint_found = TRUE;
664 breakpoint_list[i].address = 0;
665 }
666 }
667 if (breakpoint_found)
668 printf("kdp_remove_all_breakpoints: found extant breakpoints, removing them.\n");
669 }
670 return breakpoint_found;
671}