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