]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kdp/kdp.c
xnu-1699.22.73.tar.gz
[apple/xnu.git] / osfmk / kdp / kdp.c
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 2000-2007 Apple Computer, Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
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.
8f6c56a5 14 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b 27 */
1c79356b
A
28
29#include <mach/mach_types.h>
b0d623f7 30#include <sys/appleapiopts.h>
1c79356b 31#include <kern/debug.h>
b7266188 32#include <uuid/uuid.h>
1c79356b
A
33
34#include <kdp/kdp_internal.h>
35#include <kdp/kdp_private.h>
7e4a7d39 36#include <kdp/kdp_core.h>
b7266188 37#include <kdp/kdp_dyld.h>
1c79356b 38
9bccf70c 39#include <libsa/types.h>
6d2010ae 40#include <libkern/version.h>
9bccf70c 41
91447636
A
42#include <string.h> /* bcopy */
43
0c530ab8
A
44#include <kern/processor.h>
45#include <kern/thread.h>
6d2010ae 46#include <kern/clock.h>
0c530ab8
A
47#include <vm/vm_map.h>
48#include <vm/vm_kern.h>
49
1c79356b
A
50#define DO_ALIGN 1 /* align all packet data accesses */
51
52#define KDP_TEST_HARNESS 0
53#if KDP_TEST_HARNESS
54#define dprintf(x) kprintf x
55#else
56#define dprintf(x)
57#endif
58
59static kdp_dispatch_t
b0d623f7 60 dispatch_table[KDP_INVALID_REQUEST-KDP_CONNECT] =
1c79356b
A
61 {
62/* 0 */ kdp_connect,
63/* 1 */ kdp_disconnect,
64/* 2 */ kdp_hostinfo,
9bccf70c 65/* 3 */ kdp_version,
1c79356b
A
66/* 4 */ kdp_maxbytes,
67/* 5 */ kdp_readmem,
68/* 6 */ kdp_writemem,
69/* 7 */ kdp_readregs,
70/* 8 */ kdp_writeregs,
9bccf70c
A
71/* 9 */ kdp_unknown,
72/* A */ kdp_unknown,
1c79356b
A
73/* B */ kdp_suspend,
74/* C */ kdp_resumecpus,
75/* D */ kdp_unknown,
9bccf70c
A
76/* E */ kdp_unknown,
77/* F */ kdp_breakpoint_set,
78/*10 */ kdp_breakpoint_remove,
79/*11 */ kdp_regions,
91447636 80/*12 */ kdp_reattach,
b0d623f7
A
81/*13 */ kdp_reboot,
82/*14 */ kdp_readmem64,
83/*15 */ kdp_writemem64,
84/*16 */ kdp_breakpoint64_set,
85/*17 */ kdp_breakpoint64_remove,
86/*18 */ kdp_kernelversion,
87/*19 */ kdp_readphysmem64,
7e4a7d39
A
88/*1A */ kdp_writephysmem64,
89/*1B */ kdp_readioport,
90/*1C */ kdp_writeioport,
91/*1D */ kdp_readmsr64,
92/*1E */ kdp_writemsr64,
93/*1F */ kdp_dumpinfo,
1c79356b
A
94 };
95
96kdp_glob_t kdp;
9bccf70c 97
9bccf70c 98#define MAX_BREAKPOINTS 100
9bccf70c 99
b0d623f7
A
100/*
101 * Version 11 of the KDP Protocol adds support for 64-bit wide memory
102 * addresses (read/write and breakpoints) as well as a dedicated
103 * kernelversion request. Version 12 adds read/writing of physical
7e4a7d39 104 * memory with 64-bit wide memory addresses.
b0d623f7
A
105 */
106#define KDP_VERSION 12
9bccf70c
A
107
108typedef struct{
b0d623f7
A
109 mach_vm_address_t address;
110 uint32_t bytesused;
111 uint8_t oldbytes[MAX_BREAKINSN_BYTES];
9bccf70c
A
112} kdp_breakpoint_record_t;
113
114static kdp_breakpoint_record_t breakpoint_list[MAX_BREAKPOINTS];
115static unsigned int breakpoints_initialized = 0;
55e303ae 116
9bccf70c 117int reattach_wait = 0;
55e303ae 118int noresume_on_disconnect = 0;
2d21ac55 119extern unsigned int return_on_panic;
1c79356b 120
0c530ab8 121typedef struct thread_snapshot *thread_snapshot_t;
b7266188 122typedef struct task_snapshot *task_snapshot_t;
0c530ab8
A
123
124extern int
2d21ac55 125machine_trace_thread(thread_t thread, char *tracepos, char *tracebound, int nframes, boolean_t user_p);
0c530ab8 126extern int
2d21ac55 127machine_trace_thread64(thread_t thread, char *tracepos, char *tracebound, int nframes, boolean_t user_p);
0c530ab8
A
128extern int
129proc_pid(void *p);
130extern void
2d21ac55
A
131proc_name_kdp(task_t task, char *buf, int size);
132
0c530ab8
A
133extern void
134kdp_snapshot_postflight(void);
135
136static int
137pid_from_task(task_t task);
138
b0d623f7
A
139kdp_error_t
140kdp_set_breakpoint_internal(
141 mach_vm_address_t address
142 );
143
144kdp_error_t
145kdp_remove_breakpoint_internal(
146 mach_vm_address_t address
147 );
148
149
0c530ab8 150int
b7266188 151kdp_stackshot(int pid, void *tracebuf, uint32_t tracebuf_size, uint32_t trace_flags, uint32_t dispatch_offset, uint32_t *pbytesTraced);
0c530ab8 152
b0d623f7
A
153boolean_t kdp_copyin(pmap_t, uint64_t, void *, size_t);
154extern void bcopy_phys(addr64_t, addr64_t, vm_size_t);
155
1c79356b
A
156boolean_t
157kdp_packet(
158 unsigned char *pkt,
159 int *len,
160 unsigned short *reply_port
161)
162{
163 static unsigned aligned_pkt[1538/sizeof(unsigned)+1]; // max ether pkt
164 kdp_pkt_t *rd = (kdp_pkt_t *)&aligned_pkt;
2d21ac55
A
165 size_t plen = *len;
166 kdp_req_t req;
1c79356b
A
167 boolean_t ret;
168
169#if DO_ALIGN
170 bcopy((char *)pkt, (char *)rd, sizeof(aligned_pkt));
171#else
172 rd = (kdp_pkt_t *)pkt;
173#endif
174 if (plen < sizeof (rd->hdr) || rd->hdr.len != plen) {
2d21ac55 175 printf("kdp_packet bad len pkt %lu hdr %d\n", plen, rd->hdr.len);
1c79356b
A
176
177 return (FALSE);
178 }
179
180 if (rd->hdr.is_reply) {
181 printf("kdp_packet reply recvd req %x seq %x\n",
182 rd->hdr.request, rd->hdr.seq);
183
184 return (FALSE);
185 }
186
187 req = rd->hdr.request;
b0d623f7 188 if (req >= KDP_INVALID_REQUEST) {
1c79356b
A
189 printf("kdp_packet bad request %x len %d seq %x key %x\n",
190 rd->hdr.request, rd->hdr.len, rd->hdr.seq, rd->hdr.key);
191
192 return (FALSE);
193 }
194
195 ret = ((*dispatch_table[req - KDP_CONNECT])(rd, len, reply_port));
196#if DO_ALIGN
197 bcopy((char *)rd, (char *) pkt, *len);
198#endif
199 return ret;
200}
201
202static boolean_t
203kdp_unknown(
204 kdp_pkt_t *pkt,
2d21ac55
A
205 __unused int *len,
206 __unused unsigned short *reply_port
1c79356b
A
207)
208{
209 kdp_pkt_t *rd = (kdp_pkt_t *)pkt;
210
211 printf("kdp_unknown request %x len %d seq %x key %x\n",
212 rd->hdr.request, rd->hdr.len, rd->hdr.seq, rd->hdr.key);
213
214 return (FALSE);
215}
216
217static boolean_t
218kdp_connect(
219 kdp_pkt_t *pkt,
220 int *len,
221 unsigned short *reply_port
222)
223{
224 kdp_connect_req_t *rq = &pkt->connect_req;
2d21ac55 225 size_t plen = *len;
1c79356b 226 kdp_connect_reply_t *rp = &pkt->connect_reply;
7e4a7d39
A
227 uint16_t rport, eport;
228 uint32_t key;
229 uint8_t seq;
1c79356b
A
230
231 if (plen < sizeof (*rq))
232 return (FALSE);
233
234 dprintf(("kdp_connect seq %x greeting %s\n", rq->hdr.seq, rq->greeting));
235
7e4a7d39
A
236 rport = rq->req_reply_port;
237 eport = rq->exc_note_port;
238 key = rq->hdr.key;
239 seq = rq->hdr.seq;
1c79356b 240 if (kdp.is_conn) {
7e4a7d39
A
241 if ((seq == kdp.conn_seq) && /* duplicate request */
242 (rport == kdp.reply_port) &&
243 (eport == kdp.exception_port) &&
244 (key == kdp.session_key))
1c79356b 245 rp->error = KDPERR_NO_ERROR;
7e4a7d39 246 else
1c79356b
A
247 rp->error = KDPERR_ALREADY_CONNECTED;
248 }
249 else {
6d2010ae
A
250 kdp.reply_port = rport;
251 kdp.exception_port = eport;
252 kdp.is_conn = TRUE;
253 kdp.conn_seq = seq;
7e4a7d39
A
254 kdp.session_key = key;
255
1c79356b
A
256 rp->error = KDPERR_NO_ERROR;
257 }
258
259 rp->hdr.is_reply = 1;
260 rp->hdr.len = sizeof (*rp);
261
7e4a7d39 262 *reply_port = rport;
1c79356b
A
263 *len = rp->hdr.len;
264
265 if (current_debugger == KDP_CUR_DB)
266 active_debugger=1;
267
268 return (TRUE);
269}
270
271static boolean_t
272kdp_disconnect(
273 kdp_pkt_t *pkt,
274 int *len,
275 unsigned short *reply_port
276)
277{
278 kdp_disconnect_req_t *rq = &pkt->disconnect_req;
2d21ac55 279 size_t plen = *len;
1c79356b
A
280 kdp_disconnect_reply_t *rp = &pkt->disconnect_reply;
281
282 if (plen < sizeof (*rq))
283 return (FALSE);
284
285 if (!kdp.is_conn)
286 return (FALSE);
287
288 dprintf(("kdp_disconnect\n"));
289
290 *reply_port = kdp.reply_port;
291
292 kdp.reply_port = kdp.exception_port = 0;
293 kdp.is_halted = kdp.is_conn = FALSE;
294 kdp.exception_seq = kdp.conn_seq = 0;
7e4a7d39 295 kdp.session_key = 0;
1c79356b 296
2d21ac55
A
297 if ((panicstr != NULL) && (return_on_panic == 0))
298 reattach_wait = 1;
299
55e303ae
A
300 if (noresume_on_disconnect == 1) {
301 reattach_wait = 1;
302 noresume_on_disconnect = 0;
303 }
304
1c79356b
A
305 rp->hdr.is_reply = 1;
306 rp->hdr.len = sizeof (*rp);
307
308 *len = rp->hdr.len;
309
310 if (current_debugger == KDP_CUR_DB)
311 active_debugger=0;
312
313 return (TRUE);
314}
315
9bccf70c
A
316static boolean_t
317kdp_reattach(
318 kdp_pkt_t *pkt,
319 int *len,
320 unsigned short *reply_port
321)
322{
323 kdp_reattach_req_t *rq = &pkt->reattach_req;
9bccf70c
A
324
325 kdp.is_conn = TRUE;
326 kdp_disconnect(pkt, len, reply_port);
327 *reply_port = rq->req_reply_port;
328 reattach_wait = 1;
329 return (TRUE);
330}
331
1c79356b
A
332static boolean_t
333kdp_hostinfo(
334 kdp_pkt_t *pkt,
335 int *len,
336 unsigned short *reply_port
337)
338{
339 kdp_hostinfo_req_t *rq = &pkt->hostinfo_req;
2d21ac55 340 size_t plen = *len;
1c79356b
A
341 kdp_hostinfo_reply_t *rp = &pkt->hostinfo_reply;
342
343 if (plen < sizeof (*rq))
344 return (FALSE);
345
b0d623f7
A
346 dprintf(("kdp_hostinfo\n"));
347
1c79356b
A
348 rp->hdr.is_reply = 1;
349 rp->hdr.len = sizeof (*rp);
350
351 kdp_machine_hostinfo(&rp->hostinfo);
9bccf70c 352
1c79356b
A
353 *reply_port = kdp.reply_port;
354 *len = rp->hdr.len;
355
356 return (TRUE);
357}
358
b0d623f7
A
359static boolean_t
360kdp_kernelversion(
361 kdp_pkt_t *pkt,
362 int *len,
363 unsigned short *reply_port
364)
365{
366 kdp_kernelversion_req_t *rq = &pkt->kernelversion_req;
367 size_t plen = *len;
368 kdp_kernelversion_reply_t *rp = &pkt->kernelversion_reply;
369 size_t slen;
370
371 if (plen < sizeof (*rq))
372 return (FALSE);
373
374 rp->hdr.is_reply = 1;
375 rp->hdr.len = sizeof (*rp);
376
377 dprintf(("kdp_kernelversion\n"));
6d2010ae 378 slen = strlcpy(rp->version, kdp_kernelversion_string, MAX_KDP_DATA_SIZE);
b0d623f7
A
379
380 rp->hdr.len += slen + 1; /* strlcpy returns the amount copied with NUL */
381
382 *reply_port = kdp.reply_port;
383 *len = rp->hdr.len;
384
385 return (TRUE);
386}
387
1c79356b
A
388static boolean_t
389kdp_suspend(
390 kdp_pkt_t *pkt,
391 int *len,
392 unsigned short *reply_port
393)
394{
395 kdp_suspend_req_t *rq = &pkt->suspend_req;
2d21ac55 396 size_t plen = *len;
1c79356b
A
397 kdp_suspend_reply_t *rp = &pkt->suspend_reply;
398
399 if (plen < sizeof (*rq))
400 return (FALSE);
401
402 rp->hdr.is_reply = 1;
403 rp->hdr.len = sizeof (*rp);
404
405 dprintf(("kdp_suspend\n"));
406
407 kdp.is_halted = TRUE;
408
409 *reply_port = kdp.reply_port;
410 *len = rp->hdr.len;
411
412 return (TRUE);
413}
414
415static boolean_t
416kdp_resumecpus(
417 kdp_pkt_t *pkt,
418 int *len,
419 unsigned short *reply_port
420)
421{
422 kdp_resumecpus_req_t *rq = &pkt->resumecpus_req;
2d21ac55 423 size_t plen = *len;
1c79356b
A
424 kdp_resumecpus_reply_t *rp = &pkt->resumecpus_reply;
425
426 if (plen < sizeof (*rq))
427 return (FALSE);
428
429 rp->hdr.is_reply = 1;
430 rp->hdr.len = sizeof (*rp);
431
432 dprintf(("kdp_resumecpus %x\n", rq->cpu_mask));
9bccf70c 433
1c79356b
A
434 kdp.is_halted = FALSE;
435
436 *reply_port = kdp.reply_port;
437 *len = rp->hdr.len;
438
439 return (TRUE);
440}
441
442static boolean_t
443kdp_writemem(
444 kdp_pkt_t *pkt,
445 int *len,
446 unsigned short *reply_port
447)
448{
449 kdp_writemem_req_t *rq = &pkt->writemem_req;
2d21ac55 450 size_t plen = *len;
1c79356b 451 kdp_writemem_reply_t *rp = &pkt->writemem_reply;
b0d623f7 452 mach_vm_size_t cnt;
1c79356b
A
453
454 if (plen < sizeof (*rq))
455 return (FALSE);
456
457 if (rq->nbytes > MAX_KDP_DATA_SIZE)
458 rp->error = KDPERR_BAD_NBYTES;
459 else {
460 dprintf(("kdp_writemem addr %x size %d\n", rq->address, rq->nbytes));
461
b0d623f7 462 cnt = kdp_machine_vm_write((caddr_t)rq->data, (mach_vm_address_t)rq->address, rq->nbytes);
1c79356b
A
463 rp->error = KDPERR_NO_ERROR;
464 }
465
466 rp->hdr.is_reply = 1;
467 rp->hdr.len = sizeof (*rp);
468
469 *reply_port = kdp.reply_port;
470 *len = rp->hdr.len;
471
472 return (TRUE);
473}
474
b0d623f7
A
475static boolean_t
476kdp_writemem64(
477 kdp_pkt_t *pkt,
478 int *len,
479 unsigned short *reply_port
480)
481{
482 kdp_writemem64_req_t *rq = &pkt->writemem64_req;
483 size_t plen = *len;
484 kdp_writemem64_reply_t *rp = &pkt->writemem64_reply;
485 mach_vm_size_t cnt;
486
487 if (plen < sizeof (*rq))
488 return (FALSE);
489
490 if (rq->nbytes > MAX_KDP_DATA_SIZE)
491 rp->error = KDPERR_BAD_NBYTES;
492 else {
493 dprintf(("kdp_writemem64 addr %llx size %d\n", rq->address, rq->nbytes));
494
495 cnt = kdp_machine_vm_write((caddr_t)rq->data, (mach_vm_address_t)rq->address, (mach_vm_size_t)rq->nbytes);
496 rp->error = KDPERR_NO_ERROR;
497 }
498
499 rp->hdr.is_reply = 1;
500 rp->hdr.len = sizeof (*rp);
501
502 *reply_port = kdp.reply_port;
503 *len = rp->hdr.len;
504
505 return (TRUE);
506}
507
508static boolean_t
509kdp_writephysmem64(
510 kdp_pkt_t *pkt,
511 int *len,
512 unsigned short *reply_port
513)
514{
515 kdp_writephysmem64_req_t *rq = &pkt->writephysmem64_req;
516 size_t plen = *len;
517 kdp_writephysmem64_reply_t *rp = &pkt->writephysmem64_reply;
518
519 if (plen < sizeof (*rq))
520 return (FALSE);
521
522 if (rq->nbytes > MAX_KDP_DATA_SIZE)
523 rp->error = KDPERR_BAD_NBYTES;
524 else {
525 dprintf(("kdp_writephysmem64 addr %llx size %d\n", rq->address, rq->nbytes));
526 kdp_machine_phys_write(rq, rq->data, rq->lcpu);
527 rp->error = KDPERR_NO_ERROR;
528 }
529
530 rp->hdr.is_reply = 1;
531 rp->hdr.len = sizeof (*rp);
532
533 *reply_port = kdp.reply_port;
534 *len = rp->hdr.len;
535
536 return (TRUE);
537}
538
1c79356b
A
539static boolean_t
540kdp_readmem(
541 kdp_pkt_t *pkt,
542 int *len,
543 unsigned short *reply_port
544)
545{
546 kdp_readmem_req_t *rq = &pkt->readmem_req;
2d21ac55 547 size_t plen = *len;
1c79356b 548 kdp_readmem_reply_t *rp = &pkt->readmem_reply;
b0d623f7 549 mach_vm_size_t cnt;
6d2010ae
A
550#if __i386__
551 void *pversion = &kdp_kernelversion_string;
0c530ab8 552#endif
b0d623f7 553
1c79356b
A
554 if (plen < sizeof (*rq))
555 return (FALSE);
556
557 rp->hdr.is_reply = 1;
558 rp->hdr.len = sizeof (*rp);
559
560 if (rq->nbytes > MAX_KDP_DATA_SIZE)
561 rp->error = KDPERR_BAD_NBYTES;
562 else {
563 unsigned int n = rq->nbytes;
564
2d21ac55 565 dprintf(("kdp_readmem addr %x size %d\n", rq->address, n));
6d2010ae 566#if __i386__
0c530ab8 567 /* XXX This is a hack to facilitate the "showversion" macro
6d2010ae 568 * on i386, which is used to obtain the kernel version without
0c530ab8
A
569 * symbols - a pointer to the version string should eventually
570 * be pinned at a fixed address when an equivalent of the
571 * VECTORS segment (loaded at a fixed load address, and contains
2d21ac55
A
572 * a table) is implemented on these architectures, as with PPC.
573 * N.B.: x86 now has a low global page, and the version indirection
574 * is pinned at 0x201C. We retain the 0x501C address override
b0d623f7
A
575 * for compatibility. Future architectures should instead use
576 * the KDP_KERNELVERSION request.
0c530ab8 577 */
b0d623f7
A
578 if (rq->address == 0x501C)
579 rq->address = (uintptr_t)&pversion;
0c530ab8 580#endif
b0d623f7 581 cnt = kdp_machine_vm_read((mach_vm_address_t)rq->address, (caddr_t)rp->data, n);
1c79356b
A
582 rp->error = KDPERR_NO_ERROR;
583
584 rp->hdr.len += cnt;
585 }
586
587 *reply_port = kdp.reply_port;
588 *len = rp->hdr.len;
589
590 return (TRUE);
591}
592
b0d623f7
A
593static boolean_t
594kdp_readmem64(
595 kdp_pkt_t *pkt,
596 int *len,
597 unsigned short *reply_port
598)
599{
600 kdp_readmem64_req_t *rq = &pkt->readmem64_req;
601 size_t plen = *len;
602 kdp_readmem64_reply_t *rp = &pkt->readmem64_reply;
603 mach_vm_size_t cnt;
604
605 if (plen < sizeof (*rq))
606 return (FALSE);
607
608 rp->hdr.is_reply = 1;
609 rp->hdr.len = sizeof (*rp);
610
611 if (rq->nbytes > MAX_KDP_DATA_SIZE)
612 rp->error = KDPERR_BAD_NBYTES;
613 else {
614
615 dprintf(("kdp_readmem64 addr %llx size %d\n", rq->address, rq->nbytes));
616
617 cnt = kdp_machine_vm_read((mach_vm_address_t)rq->address, (caddr_t)rp->data, rq->nbytes);
618 rp->error = KDPERR_NO_ERROR;
619
620 rp->hdr.len += cnt;
621 }
622
623 *reply_port = kdp.reply_port;
624 *len = rp->hdr.len;
625
626 return (TRUE);
627}
628
629static boolean_t
630kdp_readphysmem64(
631 kdp_pkt_t *pkt,
632 int *len,
633 unsigned short *reply_port
634)
635{
636 kdp_readphysmem64_req_t *rq = &pkt->readphysmem64_req;
637 size_t plen = *len;
638 kdp_readphysmem64_reply_t *rp = &pkt->readphysmem64_reply;
639 int cnt;
640
641 if (plen < sizeof (*rq))
642 return (FALSE);
643
644 rp->hdr.is_reply = 1;
645 rp->hdr.len = sizeof (*rp);
646
647 if (rq->nbytes > MAX_KDP_DATA_SIZE)
648 rp->error = KDPERR_BAD_NBYTES;
649 else {
650
651 dprintf(("kdp_readphysmem64 addr %llx size %d\n", rq->address, rq->nbytes));
652
653 cnt = (int)kdp_machine_phys_read(rq, rp->data, rq->lcpu);
654 rp->error = KDPERR_NO_ERROR;
655
656 rp->hdr.len += cnt;
657 }
658
659 *reply_port = kdp.reply_port;
660 *len = rp->hdr.len;
661
662 return (TRUE);
663}
664
1c79356b
A
665static boolean_t
666kdp_maxbytes(
667 kdp_pkt_t *pkt,
668 int *len,
669 unsigned short *reply_port
670)
671{
672 kdp_maxbytes_req_t *rq = &pkt->maxbytes_req;
2d21ac55 673 size_t plen = *len;
1c79356b
A
674 kdp_maxbytes_reply_t *rp = &pkt->maxbytes_reply;
675
676 if (plen < sizeof (*rq))
677 return (FALSE);
678
679 rp->hdr.is_reply = 1;
680 rp->hdr.len = sizeof (*rp);
681
682 dprintf(("kdp_maxbytes\n"));
683
684 rp->max_bytes = MAX_KDP_DATA_SIZE;
685
686 *reply_port = kdp.reply_port;
687 *len = rp->hdr.len;
688
689 return (TRUE);
690}
691
9bccf70c
A
692static boolean_t
693kdp_version(
694 kdp_pkt_t *pkt,
695 int *len,
696 unsigned short *reply_port
697)
698{
699 kdp_version_req_t *rq = &pkt->version_req;
2d21ac55 700 size_t plen = *len;
9bccf70c 701 kdp_version_reply_t *rp = &pkt->version_reply;
9bccf70c
A
702
703 if (plen < sizeof (*rq))
704 return (FALSE);
705
706 rp->hdr.is_reply = 1;
707 rp->hdr.len = sizeof (*rp);
708
709 dprintf(("kdp_version\n"));
710
711 rp->version = KDP_VERSION;
9bccf70c
A
712 if (!(kdp_flag & KDP_BP_DIS))
713 rp->feature = KDP_FEATURE_BP;
714 else
715 rp->feature = 0;
b0d623f7 716
9bccf70c
A
717 *reply_port = kdp.reply_port;
718 *len = rp->hdr.len;
719
720 return (TRUE);
721}
722
1c79356b
A
723static boolean_t
724kdp_regions(
725 kdp_pkt_t *pkt,
726 int *len,
727 unsigned short *reply_port
728)
729{
730 kdp_regions_req_t *rq = &pkt->regions_req;
2d21ac55 731 size_t plen = *len;
1c79356b
A
732 kdp_regions_reply_t *rp = &pkt->regions_reply;
733 kdp_region_t *r;
734
735 if (plen < sizeof (*rq))
736 return (FALSE);
737
738 rp->hdr.is_reply = 1;
739 rp->hdr.len = sizeof (*rp);
740
741 dprintf(("kdp_regions\n"));
742
743 r = rp->regions;
744 rp->nregions = 0;
745
b0d623f7 746 r->address = 0;
1c79356b
A
747 r->nbytes = 0xffffffff;
748
749 r->protection = VM_PROT_ALL; r++; rp->nregions++;
750
751 rp->hdr.len += rp->nregions * sizeof (kdp_region_t);
752
753 *reply_port = kdp.reply_port;
754 *len = rp->hdr.len;
755
756 return (TRUE);
757}
758
759static boolean_t
760kdp_writeregs(
761 kdp_pkt_t *pkt,
762 int *len,
763 unsigned short *reply_port
764)
765{
766 kdp_writeregs_req_t *rq = &pkt->writeregs_req;
2d21ac55 767 size_t plen = *len;
1c79356b
A
768 int size;
769 kdp_writeregs_reply_t *rp = &pkt->writeregs_reply;
770
771 if (plen < sizeof (*rq))
772 return (FALSE);
773
b0d623f7 774 size = rq->hdr.len - (unsigned)sizeof(kdp_hdr_t) - (unsigned)sizeof(unsigned int);
1c79356b
A
775 rp->error = kdp_machine_write_regs(rq->cpu, rq->flavor, rq->data, &size);
776
777 rp->hdr.is_reply = 1;
778 rp->hdr.len = sizeof (*rp);
779
780 *reply_port = kdp.reply_port;
781 *len = rp->hdr.len;
782
783 return (TRUE);
784}
785
786static boolean_t
787kdp_readregs(
788 kdp_pkt_t *pkt,
789 int *len,
790 unsigned short *reply_port
791)
792{
793 kdp_readregs_req_t *rq = &pkt->readregs_req;
2d21ac55 794 size_t plen = *len;
1c79356b
A
795 kdp_readregs_reply_t *rp = &pkt->readregs_reply;
796 int size;
797
798 if (plen < sizeof (*rq))
799 return (FALSE);
800
801 rp->hdr.is_reply = 1;
802 rp->hdr.len = sizeof (*rp);
803
804 rp->error = kdp_machine_read_regs(rq->cpu, rq->flavor, rp->data, &size);
805 rp->hdr.len += size;
806
807 *reply_port = kdp.reply_port;
808 *len = rp->hdr.len;
809
810 return (TRUE);
811}
9bccf70c 812
b0d623f7
A
813
814boolean_t
9bccf70c 815kdp_breakpoint_set(
b0d623f7
A
816 kdp_pkt_t *pkt,
817 int *len,
818 unsigned short *reply_port
9bccf70c
A
819)
820{
b0d623f7
A
821 kdp_breakpoint_req_t *rq = &pkt->breakpoint_req;
822 kdp_breakpoint_reply_t *rp = &pkt->breakpoint_reply;
823 size_t plen = *len;
824 kdp_error_t kerr;
825
826 if (plen < sizeof (*rq))
827 return (FALSE);
828
829 dprintf(("kdp_breakpoint_set %x\n", rq->address));
9bccf70c 830
b0d623f7
A
831 kerr = kdp_set_breakpoint_internal((mach_vm_address_t)rq->address);
832
833 rp->error = kerr;
834
835 rp->hdr.is_reply = 1;
836 rp->hdr.len = sizeof (*rp);
837 *reply_port = kdp.reply_port;
838 *len = rp->hdr.len;
839
840 return (TRUE);
841}
9bccf70c 842
b0d623f7
A
843boolean_t
844kdp_breakpoint64_set(
845 kdp_pkt_t *pkt,
846 int *len,
847 unsigned short *reply_port
848)
849{
850 kdp_breakpoint64_req_t *rq = &pkt->breakpoint64_req;
851 kdp_breakpoint64_reply_t *rp = &pkt->breakpoint64_reply;
852 size_t plen = *len;
853 kdp_error_t kerr;
854
855 if (plen < sizeof (*rq))
856 return (FALSE);
857
858 dprintf(("kdp_breakpoint64_set %llx\n", rq->address));
9bccf70c 859
b0d623f7
A
860 kerr = kdp_set_breakpoint_internal((mach_vm_address_t)rq->address);
861
862 rp->error = kerr;
863
864 rp->hdr.is_reply = 1;
865 rp->hdr.len = sizeof (*rp);
866 *reply_port = kdp.reply_port;
867 *len = rp->hdr.len;
868
869 return (TRUE);
870}
9bccf70c 871
b0d623f7
A
872boolean_t
873kdp_breakpoint_remove(
874 kdp_pkt_t *pkt,
875 int *len,
876 unsigned short *reply_port
877)
878{
879 kdp_breakpoint_req_t *rq = &pkt->breakpoint_req;
880 kdp_breakpoint_reply_t *rp = &pkt->breakpoint_reply;
881 size_t plen = *len;
882 kdp_error_t kerr;
883 if (plen < sizeof (*rq))
884 return (FALSE);
885
886 dprintf(("kdp_breakpoint_remove %x\n", rq->address));
9bccf70c 887
b0d623f7
A
888 kerr = kdp_remove_breakpoint_internal((mach_vm_address_t)rq->address);
889
890 rp->error = kerr;
891
892 rp->hdr.is_reply = 1;
893 rp->hdr.len = sizeof (*rp);
894 *reply_port = kdp.reply_port;
895 *len = rp->hdr.len;
896
897 return (TRUE);
9bccf70c
A
898}
899
b0d623f7
A
900boolean_t
901kdp_breakpoint64_remove(
902 kdp_pkt_t *pkt,
903 int *len,
904 unsigned short *reply_port
9bccf70c
A
905)
906{
b0d623f7
A
907 kdp_breakpoint64_req_t *rq = &pkt->breakpoint64_req;
908 kdp_breakpoint64_reply_t *rp = &pkt->breakpoint64_reply;
909 size_t plen = *len;
910 kdp_error_t kerr;
911
912 if (plen < sizeof (*rq))
913 return (FALSE);
914
915 dprintf(("kdp_breakpoint64_remove %llx\n", rq->address));
9bccf70c 916
b0d623f7
A
917 kerr = kdp_remove_breakpoint_internal((mach_vm_address_t)rq->address);
918
919 rp->error = kerr;
920
921 rp->hdr.is_reply = 1;
922 rp->hdr.len = sizeof (*rp);
923 *reply_port = kdp.reply_port;
924 *len = rp->hdr.len;
925
926 return (TRUE);
927}
9bccf70c 928
9bccf70c 929
b0d623f7
A
930kdp_error_t
931kdp_set_breakpoint_internal(
932 mach_vm_address_t address
933 )
934{
935
936 uint8_t breakinstr[MAX_BREAKINSN_BYTES], oldinstr[MAX_BREAKINSN_BYTES];
937 uint32_t breakinstrsize = sizeof(breakinstr);
938 mach_vm_size_t cnt;
939 int i;
940
941 kdp_machine_get_breakinsn(breakinstr, &breakinstrsize);
942
943 if(breakpoints_initialized == 0)
944 {
945 for(i=0;(i < MAX_BREAKPOINTS); breakpoint_list[i].address=0, i++);
946 breakpoints_initialized++;
9bccf70c 947 }
b0d623f7
A
948
949 cnt = kdp_machine_vm_read(address, (caddr_t)&oldinstr, (mach_vm_size_t)breakinstrsize);
950
951 if (0 == memcmp(oldinstr, breakinstr, breakinstrsize)) {
952 printf("A trap was already set at that address, not setting new breakpoint\n");
953
954 return KDPERR_BREAKPOINT_ALREADY_SET;
955 }
956
957 for(i=0;(i < MAX_BREAKPOINTS) && (breakpoint_list[i].address != 0); i++);
958
959 if (i == MAX_BREAKPOINTS) {
960 return KDPERR_MAX_BREAKPOINTS;
961 }
962
963 breakpoint_list[i].address = address;
964 memcpy(breakpoint_list[i].oldbytes, oldinstr, breakinstrsize);
965 breakpoint_list[i].bytesused = breakinstrsize;
966
967 cnt = kdp_machine_vm_write((caddr_t)&breakinstr, address, breakinstrsize);
968
969 return KDPERR_NO_ERROR;
970}
9bccf70c 971
b0d623f7
A
972kdp_error_t
973kdp_remove_breakpoint_internal(
974 mach_vm_address_t address
975 )
976{
977 mach_vm_size_t cnt;
978 int i;
979
980 for(i=0;(i < MAX_BREAKPOINTS) && (breakpoint_list[i].address != address); i++);
981
982 if (i == MAX_BREAKPOINTS)
983 {
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;
9bccf70c
A
991}
992
993boolean_t
2d21ac55 994kdp_remove_all_breakpoints(void)
9bccf70c 995{
b0d623f7
A
996 int i;
997 boolean_t breakpoint_found = FALSE;
998
999 if (breakpoints_initialized)
9bccf70c 1000 {
b0d623f7
A
1001 for(i=0;i < MAX_BREAKPOINTS; i++)
1002 {
1003 if (breakpoint_list[i].address)
1004 {
1005 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);
1006 breakpoint_found = TRUE;
1007 breakpoint_list[i].address = 0;
1008 }
1009 }
1010
1011 if (breakpoint_found)
1012 printf("kdp_remove_all_breakpoints: found extant breakpoints, removing them.\n");
9bccf70c 1013 }
b0d623f7 1014 return breakpoint_found;
9bccf70c 1015}
0c530ab8 1016
b0d623f7
A
1017boolean_t
1018kdp_reboot(
1019 __unused kdp_pkt_t *pkt,
1020 __unused int *len,
1021 __unused unsigned short *reply_port
1022)
1023{
1024 dprintf(("kdp_reboot\n"));
1025
1026 kdp_machine_reboot();
1027
1028 return (TRUE); // no, not really, we won't return
1029}
0c530ab8
A
1030
1031#define MAX_FRAMES 1000
1032
1033static int pid_from_task(task_t task)
1034{
1035 int pid = -1;
1036
1037 if (task->bsd_info)
1038 pid = proc_pid(task->bsd_info);
1039
1040 return pid;
1041}
1042
b0d623f7
A
1043boolean_t
1044kdp_copyin(pmap_t p, uint64_t uaddr, void *dest, size_t size) {
1045 size_t rem = size;
1046 char *kvaddr = dest;
1047
1048 while (rem) {
1049 ppnum_t upn = pmap_find_phys(p, uaddr);
060df5ea 1050 uint64_t phys_src = ptoa_64(upn) | (uaddr & PAGE_MASK);
b0d623f7
A
1051 uint64_t phys_dest = kvtophys((vm_offset_t)kvaddr);
1052 uint64_t src_rem = PAGE_SIZE - (phys_src & PAGE_MASK);
1053 uint64_t dst_rem = PAGE_SIZE - (phys_dest & PAGE_MASK);
1054 size_t cur_size = (uint32_t) MIN(src_rem, dst_rem);
1055 cur_size = MIN(cur_size, rem);
1056
1057 if (upn && pmap_valid_page(upn) && phys_dest) {
1058 bcopy_phys(phys_src, phys_dest, cur_size);
1059 }
1060 else
1061 break;
1062 uaddr += cur_size;
1063 kvaddr += cur_size;
1064 rem -= cur_size;
1065 }
1066 return (rem == 0);
1067}
1068
6d2010ae
A
1069
1070static void
1071kdp_mem_snapshot(struct mem_snapshot *mem_snap)
1072{
1073 mem_snap->snapshot_magic = STACKSHOT_MEM_SNAPSHOT_MAGIC;
1074 mem_snap->free_pages = vm_page_free_count;
1075 mem_snap->active_pages = vm_page_active_count;
1076 mem_snap->inactive_pages = vm_page_inactive_count;
1077 mem_snap->purgeable_pages = vm_page_purgeable_count;
1078 mem_snap->wired_pages = vm_page_wire_count;
1079 mem_snap->speculative_pages = vm_page_speculative_count;
1080 mem_snap->throttled_pages = vm_page_throttled_count;
1081}
1082
1083
1084/*
1085 * Method for grabbing timer values safely, in the sense that no infinite loop will occur
1086 * Certain flavors of the timer_grab function, which would seem to be the thing to use,
1087 * can loop infinitely if called while the timer is in the process of being updated.
1088 * Unfortunately, it is (rarely) possible to get inconsistent top and bottom halves of
1089 * the timer using this method. This seems insoluble, since stackshot runs in a context
1090 * where the timer might be half-updated, and has no way of yielding control just long
1091 * enough to finish the update.
1092 */
1093
1094static uint64_t safe_grab_timer_value(struct timer *t)
1095{
1096#if defined(__LP64__)
1097 return t->all_bits;
1098#else
1099 uint64_t time = t->high_bits; /* endian independent grab */
1100 time = (time << 32) | t->low_bits;
1101 return time;
1102#endif
1103}
1104
0c530ab8 1105int
b7266188 1106kdp_stackshot(int pid, void *tracebuf, uint32_t tracebuf_size, uint32_t trace_flags, uint32_t dispatch_offset, uint32_t *pbytesTraced)
0c530ab8 1107{
2d21ac55
A
1108 char *tracepos = (char *) tracebuf;
1109 char *tracebound = tracepos + tracebuf_size;
0c530ab8
A
1110 uint32_t tracebytes = 0;
1111 int error = 0;
2d21ac55 1112
0c530ab8
A
1113 task_t task = TASK_NULL;
1114 thread_t thread = THREAD_NULL;
0c530ab8
A
1115 thread_snapshot_t tsnap = NULL;
1116 unsigned framesize = 2 * sizeof(vm_offset_t);
2d21ac55
A
1117 struct task ctask;
1118 struct thread cthread;
6d2010ae
A
1119 struct _vm_map cmap;
1120 struct pmap cpmap;
1121
1122 queue_head_t *task_list = &tasks;
1123 boolean_t is_active_list = TRUE;
b7266188
A
1124
1125 boolean_t dispatch_p = ((trace_flags & STACKSHOT_GET_DQ) != 0);
1126 boolean_t save_loadinfo_p = ((trace_flags & STACKSHOT_SAVE_LOADINFO) != 0);
0c530ab8 1127
6d2010ae
A
1128 if(trace_flags & STACKSHOT_GET_GLOBAL_MEM_STATS) {
1129 if(tracepos + sizeof(struct mem_snapshot) > tracebound) {
1130 error = -1;
1131 goto error_exit;
1132 }
1133 kdp_mem_snapshot((struct mem_snapshot *)tracepos);
1134 tracepos += sizeof(struct mem_snapshot);
1135 }
1136
1137walk_list:
1138 queue_iterate(task_list, task, task_t, tasks) {
2d21ac55
A
1139 if ((task == NULL) || (ml_nofault_copy((vm_offset_t) task, (vm_offset_t) &ctask, sizeof(struct task)) != sizeof(struct task)))
1140 goto error_exit;
b7266188 1141
060df5ea
A
1142 int task_pid = pid_from_task(task);
1143 boolean_t task64 = task_has_64BitAddr(task);
1144
6d2010ae
A
1145 if (!task->active) {
1146 /*
1147 * Not interested in terminated tasks without threads, and
1148 * at the moment, stackshot can't handle a task without a name.
1149 */
1150 if (queue_empty(&task->threads) || task_pid == -1) {
1151 continue;
1152 }
1153 }
1154
0c530ab8 1155 /* Trace everything, unless a process was specified */
b7266188
A
1156 if ((pid == -1) || (pid == task_pid)) {
1157 task_snapshot_t task_snap;
6d2010ae
A
1158 uint32_t uuid_info_count = 0;
1159 mach_vm_address_t uuid_info_addr = 0;
1160 boolean_t have_map = (task->map != NULL) &&
1161 (ml_nofault_copy((vm_offset_t)(task->map), (vm_offset_t)&cmap, sizeof(struct _vm_map)) == sizeof(struct _vm_map));
1162 boolean_t have_pmap = have_map && (cmap.pmap != NULL) &&
1163 (ml_nofault_copy((vm_offset_t)(cmap.pmap), (vm_offset_t)&cpmap, sizeof(struct pmap)) == sizeof(struct pmap));
1164
1165 if (have_pmap && task->active && save_loadinfo_p && task_pid > 0) {
b7266188
A
1166 // Read the dyld_all_image_infos struct from the task memory to get UUID array count and location
1167 if (task64) {
1168 struct dyld_all_image_infos64 task_image_infos;
6d2010ae
A
1169 if (kdp_copyin(task->map->pmap, task->all_image_info_addr, &task_image_infos, sizeof(struct dyld_all_image_infos64))) {
1170 uuid_info_count = (uint32_t)task_image_infos.uuidArrayCount;
1171 uuid_info_addr = task_image_infos.uuidArray;
1172 }
b7266188
A
1173 } else {
1174 struct dyld_all_image_infos task_image_infos;
6d2010ae
A
1175 if (kdp_copyin(task->map->pmap, task->all_image_info_addr, &task_image_infos, sizeof(struct dyld_all_image_infos))) {
1176 uuid_info_count = task_image_infos.uuidArrayCount;
1177 uuid_info_addr = task_image_infos.uuidArray;
1178 }
1179 }
1180
1181 // If we get a NULL uuid_info_addr (which can happen when we catch dyld in the middle of updating
1182 // this data structure), we zero the uuid_info_count so that we won't even try to save load info
1183 // for this task.
1184 if (!uuid_info_addr) {
1185 uuid_info_count = 0;
b7266188 1186 }
b7266188
A
1187 }
1188
1189 if (tracepos + sizeof(struct task_snapshot) > tracebound) {
1190 error = -1;
1191 goto error_exit;
1192 }
1193
1194 task_snap = (task_snapshot_t) tracepos;
1195 task_snap->snapshot_magic = STACKSHOT_TASK_SNAPSHOT_MAGIC;
1196 task_snap->pid = task_pid;
1197 task_snap->nloadinfos = uuid_info_count;
1198 /* Add the BSD process identifiers */
1199 if (task_pid != -1)
1200 proc_name_kdp(task, task_snap->p_comm, sizeof(task_snap->p_comm));
1201 else
1202 task_snap->p_comm[0] = '\0';
1203 task_snap->ss_flags = 0;
1204 if (task64)
1205 task_snap->ss_flags |= kUser64_p;
6d2010ae
A
1206 if (!task->active)
1207 task_snap->ss_flags |= kTerminatedSnapshot;
1208
1209 task_snap->suspend_count = task->suspend_count;
1210 task_snap->task_size = have_pmap ? pmap_resident_count(task->map->pmap) : 0;
1211 task_snap->faults = task->faults;
1212 task_snap->pageins = task->pageins;
1213 task_snap->cow_faults = task->cow_faults;
b7266188 1214
6d2010ae
A
1215 task_snap->user_time_in_terminated_threads = task->total_user_time;
1216 task_snap->system_time_in_terminated_threads = task->total_system_time;
b7266188
A
1217 tracepos += sizeof(struct task_snapshot);
1218
1219 if (task_pid > 0 && uuid_info_count > 0) {
1220 uint32_t uuid_info_size = (uint32_t)(task64 ? sizeof(struct dyld_uuid_info64) : sizeof(struct dyld_uuid_info));
1221 uint32_t uuid_info_array_size = uuid_info_count * uuid_info_size;
1222
1223 if (tracepos + uuid_info_array_size > tracebound) {
1224 error = -1;
1225 goto error_exit;
1226 }
1227
1228 // Copy in the UUID info array
6d2010ae
A
1229 // It may be nonresident, in which case just fix up nloadinfos to 0 in the task_snap
1230 if (have_pmap && !kdp_copyin(task->map->pmap, uuid_info_addr, tracepos, uuid_info_array_size))
1231 task_snap->nloadinfos = 0;
1232 else
1233 tracepos += uuid_info_array_size;
b7266188
A
1234 }
1235
0c530ab8 1236 queue_iterate(&task->threads, thread, thread_t, task_threads){
2d21ac55
A
1237 if ((thread == NULL) || (ml_nofault_copy((vm_offset_t) thread, (vm_offset_t) &cthread, sizeof(struct thread)) != sizeof(struct thread)))
1238 goto error_exit;
b7266188 1239
2d21ac55 1240 if (((tracepos + 4 * sizeof(struct thread_snapshot)) > tracebound)) {
0c530ab8
A
1241 error = -1;
1242 goto error_exit;
1243 }
b7266188 1244 /* Populate the thread snapshot header */
0c530ab8 1245 tsnap = (thread_snapshot_t) tracepos;
d41d1dae 1246 tsnap->thread_id = thread_tid(thread);
0c530ab8 1247 tsnap->state = thread->state;
0c530ab8 1248 tsnap->wait_event = thread->wait_event;
b0d623f7 1249 tsnap->continuation = (uint64_t) (uintptr_t) thread->continuation;
6d2010ae
A
1250 tsnap->user_time = safe_grab_timer_value(&thread->user_timer);
1251 tsnap->system_time = safe_grab_timer_value(&thread->system_timer);
b7266188 1252 tsnap->snapshot_magic = STACKSHOT_THREAD_SNAPSHOT_MAGIC;
0c530ab8 1253 tracepos += sizeof(struct thread_snapshot);
b0d623f7
A
1254 tsnap->ss_flags = 0;
1255
6d2010ae 1256 if (dispatch_p && (task != kernel_task) && (task->active) && have_pmap) {
b0d623f7
A
1257 uint64_t dqkeyaddr = thread_dispatchqaddr(thread);
1258 if (dqkeyaddr != 0) {
b0d623f7
A
1259 uint64_t dqaddr = 0;
1260 if (kdp_copyin(task->map->pmap, dqkeyaddr, &dqaddr, (task64 ? 8 : 4)) && (dqaddr != 0)) {
1261 uint64_t dqserialnumaddr = dqaddr + dispatch_offset;
1262 uint64_t dqserialnum = 0;
1263 if (kdp_copyin(task->map->pmap, dqserialnumaddr, &dqserialnum, (task64 ? 8 : 4))) {
1264 tsnap->ss_flags |= kHasDispatchSerial;
1265 *(uint64_t *)tracepos = dqserialnum;
1266 tracepos += 8;
1267 }
1268 }
1269 }
1270 }
0c530ab8
A
1271/* Call through to the machine specific trace routines
1272 * Frames are added past the snapshot header.
1273 */
6d2010ae 1274 tracebytes = 0;
b0d623f7
A
1275 if (thread->kernel_stack != 0) {
1276#if defined(__LP64__)
b7266188 1277 tracebytes = machine_trace_thread64(thread, tracepos, tracebound, MAX_FRAMES, FALSE);
b0d623f7
A
1278 tsnap->ss_flags |= kKernel64_p;
1279 framesize = 16;
1280#else
b7266188 1281 tracebytes = machine_trace_thread(thread, tracepos, tracebound, MAX_FRAMES, FALSE);
b0d623f7
A
1282 framesize = 8;
1283#endif
1284 }
1285 tsnap->nkern_frames = tracebytes/framesize;
0c530ab8
A
1286 tracepos += tracebytes;
1287 tracebytes = 0;
b7266188 1288 /* Trace user stack, if any */
6d2010ae 1289 if (task->active && thread->task->map != kernel_map) {
b0d623f7 1290 /* 64-bit task? */
0c530ab8 1291 if (task_has_64BitAddr(thread->task)) {
b7266188 1292 tracebytes = machine_trace_thread64(thread, tracepos, tracebound, MAX_FRAMES, TRUE);
b0d623f7
A
1293 tsnap->ss_flags |= kUser64_p;
1294 framesize = 16;
0c530ab8
A
1295 }
1296 else {
b7266188 1297 tracebytes = machine_trace_thread(thread, tracepos, tracebound, MAX_FRAMES, TRUE);
b0d623f7 1298 framesize = 8;
0c530ab8
A
1299 }
1300 }
1301 tsnap->nuser_frames = tracebytes/framesize;
1302 tracepos += tracebytes;
1303 tracebytes = 0;
1304 }
b7266188 1305 }
0c530ab8
A
1306 }
1307
6d2010ae
A
1308 if (is_active_list) {
1309 is_active_list = FALSE;
1310 task_list = &terminated_tasks;
1311 goto walk_list;
1312 }
1313
0c530ab8
A
1314error_exit:
1315 /* Release stack snapshot wait indicator */
1316 kdp_snapshot_postflight();
1317
b0d623f7 1318 *pbytesTraced = (uint32_t)(tracepos - (char *) tracebuf);
0c530ab8
A
1319
1320 return error;
1321}
b0d623f7
A
1322
1323static boolean_t
1324kdp_readioport(kdp_pkt_t *pkt,
1325 int *len,
1326 unsigned short *reply_port
1327 )
1328{
1329 kdp_readioport_req_t *rq = &pkt->readioport_req;
1330 kdp_readioport_reply_t *rp = &pkt->readioport_reply;
1331 size_t plen = *len;
1332
1333 if (plen < sizeof (*rq))
1334 return (FALSE);
1335
1336 rp->hdr.is_reply = 1;
1337 rp->hdr.len = sizeof (*rp);
1338
1339 if (rq->nbytes > MAX_KDP_DATA_SIZE)
1340 rp->error = KDPERR_BAD_NBYTES;
1341 else {
1342#if KDP_TEST_HARNESS
1343 uint16_t addr = rq->address;
1344#endif
1345 uint16_t size = rq->nbytes;
1346 dprintf(("kdp_readioport addr %x size %d\n", addr, size));
1347
1348 rp->error = kdp_machine_ioport_read(rq, rp->data, rq->lcpu);
1349 if (rp->error == KDPERR_NO_ERROR)
1350 rp->hdr.len += size;
1351 }
1352
1353 *reply_port = kdp.reply_port;
1354 *len = rp->hdr.len;
1355
1356 return (TRUE);
1357}
1358
1359static boolean_t
1360kdp_writeioport(
1361 kdp_pkt_t *pkt,
1362 int *len,
1363 unsigned short *reply_port
1364 )
1365{
1366 kdp_writeioport_req_t *rq = &pkt->writeioport_req;
1367 kdp_writeioport_reply_t *rp = &pkt->writeioport_reply;
1368 size_t plen = *len;
1369
1370 if (plen < sizeof (*rq))
1371 return (FALSE);
1372
1373 if (rq->nbytes > MAX_KDP_DATA_SIZE)
1374 rp->error = KDPERR_BAD_NBYTES;
1375 else {
1376 dprintf(("kdp_writeioport addr %x size %d\n", rq->address,
1377 rq->nbytes));
1378
1379 rp->error = kdp_machine_ioport_write(rq, rq->data, rq->lcpu);
1380 }
1381
1382 rp->hdr.is_reply = 1;
1383 rp->hdr.len = sizeof (*rp);
1384
1385 *reply_port = kdp.reply_port;
1386 *len = rp->hdr.len;
1387
1388 return (TRUE);
1389}
1390
1391static boolean_t
1392kdp_readmsr64(kdp_pkt_t *pkt,
1393 int *len,
1394 unsigned short *reply_port
1395 )
1396{
1397 kdp_readmsr64_req_t *rq = &pkt->readmsr64_req;
1398 kdp_readmsr64_reply_t *rp = &pkt->readmsr64_reply;
1399 size_t plen = *len;
1400
1401 if (plen < sizeof (*rq))
1402 return (FALSE);
1403
1404 rp->hdr.is_reply = 1;
1405 rp->hdr.len = sizeof (*rp);
1406
1407 dprintf(("kdp_readmsr64 lcpu %x addr %x\n", rq->lcpu, rq->address));
1408 rp->error = kdp_machine_msr64_read(rq, rp->data, rq->lcpu);
1409 if (rp->error == KDPERR_NO_ERROR)
1410 rp->hdr.len += sizeof(uint64_t);
1411
1412 *reply_port = kdp.reply_port;
1413 *len = rp->hdr.len;
1414
1415 return (TRUE);
1416}
1417
1418static boolean_t
1419kdp_writemsr64(
1420 kdp_pkt_t *pkt,
1421 int *len,
1422 unsigned short *reply_port
1423 )
1424{
1425 kdp_writemsr64_req_t *rq = &pkt->writemsr64_req;
1426 kdp_writemsr64_reply_t *rp = &pkt->writemsr64_reply;
1427 size_t plen = *len;
1428
1429 if (plen < sizeof (*rq))
1430 return (FALSE);
1431
1432 dprintf(("kdp_writemsr64 lcpu %x addr %x\n", rq->lcpu, rq->address));
1433 rp->error = kdp_machine_msr64_write(rq, rq->data, rq->lcpu);
1434
1435 rp->hdr.is_reply = 1;
1436 rp->hdr.len = sizeof (*rp);
1437
1438 *reply_port = kdp.reply_port;
1439 *len = rp->hdr.len;
1440
1441 return (TRUE);
1442}
7e4a7d39
A
1443
1444static boolean_t
1445kdp_dumpinfo(
1446 kdp_pkt_t *pkt,
1447 int *len,
1448 unsigned short *reply_port
1449 )
1450{
1451 kdp_dumpinfo_req_t *rq = &pkt->dumpinfo_req;
1452 kdp_dumpinfo_reply_t *rp = &pkt->dumpinfo_reply;
1453 size_t plen = *len;
1454
1455 if (plen < sizeof (*rq))
1456 return (FALSE);
1457
1458 dprintf(("kdp_dumpinfo file=%s destip=%s routerip=%s\n", rq->name, rq->destip, rq->routerip));
1459 rp->hdr.is_reply = 1;
1460 rp->hdr.len = sizeof (*rp);
1461
1462 if ((rq->type & KDP_DUMPINFO_MASK) != KDP_DUMPINFO_GETINFO) {
1463 kdp_set_dump_info(rq->type, rq->name, rq->destip, rq->routerip,
1464 rq->port);
1465 }
1466
1467 /* gather some stats for reply */
1468 kdp_get_dump_info(&rp->type, rp->name, rp->destip, rp->routerip,
1469 &rp->port);
1470
1471 *reply_port = kdp.reply_port;
1472 *len = rp->hdr.len;
1473
1474 return (TRUE);
1475}