]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kdp/kdp.c
35e5b610574df6920d82c151b8a2ea18967d33e1
[apple/xnu.git] / osfmk / kdp / kdp.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
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
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
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
32 #include <libsa/types.h>
33
34 int kdp_vm_read( caddr_t, caddr_t, unsigned int);
35 int 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
46 static kdp_dispatch_t
47 dispatch_table[KDP_REATTACH - KDP_CONNECT +1] =
48 {
49 /* 0 */ kdp_connect,
50 /* 1 */ kdp_disconnect,
51 /* 2 */ kdp_hostinfo,
52 /* 3 */ kdp_version,
53 /* 4 */ kdp_maxbytes,
54 /* 5 */ kdp_readmem,
55 /* 6 */ kdp_writemem,
56 /* 7 */ kdp_readregs,
57 /* 8 */ kdp_writeregs,
58 /* 9 */ kdp_unknown,
59 /* A */ kdp_unknown,
60 /* B */ kdp_suspend,
61 /* C */ kdp_resumecpus,
62 /* D */ kdp_unknown,
63 /* E */ kdp_unknown,
64 /* F */ kdp_breakpoint_set,
65 /*10 */ kdp_breakpoint_remove,
66 /*11 */ kdp_regions,
67 /*12 */ kdp_reattach
68 };
69
70 kdp_glob_t kdp;
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
81 typedef struct{
82 unsigned int address;
83 unsigned int old_instruction;
84 } kdp_breakpoint_record_t;
85
86 static kdp_breakpoint_record_t breakpoint_list[MAX_BREAKPOINTS];
87 static unsigned int breakpoints_initialized = 0;
88 int reattach_wait = 0;
89
90 boolean_t
91 kdp_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;
122 if ((req < KDP_CONNECT) || (req > KDP_REATTACH)) {
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
136 static boolean_t
137 kdp_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
151 static boolean_t
152 kdp_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
194 static boolean_t
195 kdp_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
230 static boolean_t
231 kdp_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
247 static boolean_t
248 kdp_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);
265
266 *reply_port = kdp.reply_port;
267 *len = rp->hdr.len;
268
269 return (TRUE);
270 }
271
272 static boolean_t
273 kdp_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
299 static boolean_t
300 kdp_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));
317
318 kdp.is_halted = FALSE;
319
320 *reply_port = kdp.reply_port;
321 *len = rp->hdr.len;
322
323 return (TRUE);
324 }
325
326 static boolean_t
327 kdp_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
359 static boolean_t
360 kdp_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
396 static boolean_t
397 kdp_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
423 static boolean_t
424 kdp_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
459 static boolean_t
460 kdp_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
495 static boolean_t
496 kdp_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
522 static boolean_t
523 kdp_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 }
548
549 static boolean_t
550 kdp_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
612 static boolean_t
613 kdp_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
650 boolean_t
651 kdp_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 }