]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kdp/kdp.c
xnu-344.23.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 *
de355530
A
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.
1c79356b 11 *
de355530
A
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
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
de355530
A
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.
1c79356b
A
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
1c79356b
A
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
9bccf70c
A
29#include <libsa/types.h>
30
1c79356b
A
31int kdp_vm_read( caddr_t, caddr_t, unsigned int);
32int 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
43static kdp_dispatch_t
9bccf70c 44 dispatch_table[KDP_REATTACH - KDP_CONNECT +1] =
1c79356b
A
45 {
46/* 0 */ kdp_connect,
47/* 1 */ kdp_disconnect,
48/* 2 */ kdp_hostinfo,
9bccf70c 49/* 3 */ kdp_version,
1c79356b
A
50/* 4 */ kdp_maxbytes,
51/* 5 */ kdp_readmem,
52/* 6 */ kdp_writemem,
53/* 7 */ kdp_readregs,
54/* 8 */ kdp_writeregs,
9bccf70c
A
55/* 9 */ kdp_unknown,
56/* A */ kdp_unknown,
1c79356b
A
57/* B */ kdp_suspend,
58/* C */ kdp_resumecpus,
59/* D */ kdp_unknown,
9bccf70c
A
60/* E */ kdp_unknown,
61/* F */ kdp_breakpoint_set,
62/*10 */ kdp_breakpoint_remove,
63/*11 */ kdp_regions,
64/*12 */ kdp_reattach
1c79356b
A
65 };
66
67kdp_glob_t kdp;
9bccf70c
A
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
78typedef struct{
79 unsigned int address;
80 unsigned int old_instruction;
81} kdp_breakpoint_record_t;
82
83static kdp_breakpoint_record_t breakpoint_list[MAX_BREAKPOINTS];
84static unsigned int breakpoints_initialized = 0;
85int reattach_wait = 0;
1c79356b
A
86
87boolean_t
88kdp_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;
9bccf70c 119 if ((req < KDP_CONNECT) || (req > KDP_REATTACH)) {
1c79356b
A
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
133static boolean_t
134kdp_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
148static boolean_t
149kdp_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
191static boolean_t
192kdp_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
9bccf70c
A
227static boolean_t
228kdp_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
1c79356b
A
244static boolean_t
245kdp_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);
9bccf70c 262
1c79356b
A
263 *reply_port = kdp.reply_port;
264 *len = rp->hdr.len;
265
266 return (TRUE);
267}
268
269static boolean_t
270kdp_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
296static boolean_t
297kdp_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));
9bccf70c 314
1c79356b
A
315 kdp.is_halted = FALSE;
316
317 *reply_port = kdp.reply_port;
318 *len = rp->hdr.len;
319
320 return (TRUE);
321}
322
323static boolean_t
324kdp_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
356static boolean_t
357kdp_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
393static boolean_t
394kdp_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
9bccf70c
A
420static boolean_t
421kdp_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
1c79356b
A
456static boolean_t
457kdp_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
492static boolean_t
493kdp_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
519static boolean_t
520kdp_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}
9bccf70c
A
545
546static boolean_t
547kdp_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
609static boolean_t
610kdp_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
647boolean_t
648kdp_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}