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