]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kdp/kdp.c
58f74392218180b82bdfeef7ad56635c25f620cd
[apple/xnu.git] / osfmk / kdp / kdp.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
5 *
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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30
31 #include <mach/mach_types.h>
32 #include <kern/debug.h>
33
34 #include <kdp/kdp_internal.h>
35 #include <kdp/kdp_private.h>
36
37 #include <libsa/types.h>
38
39 #include <string.h> /* bcopy */
40
41 #include <kern/processor.h>
42 #include <kern/thread.h>
43 #include <vm/vm_map.h>
44 #include <vm/vm_kern.h>
45
46 int kdp_vm_read( caddr_t, caddr_t, unsigned int);
47 int kdp_vm_write( caddr_t, caddr_t, unsigned int);
48
49 #define DO_ALIGN 1 /* align all packet data accesses */
50
51 #define KDP_TEST_HARNESS 0
52 #if KDP_TEST_HARNESS
53 #define dprintf(x) kprintf x
54 #else
55 #define dprintf(x)
56 #endif
57
58 static kdp_dispatch_t
59 dispatch_table[KDP_HOSTREBOOT - KDP_CONNECT +1] =
60 {
61 /* 0 */ kdp_connect,
62 /* 1 */ kdp_disconnect,
63 /* 2 */ kdp_hostinfo,
64 /* 3 */ kdp_version,
65 /* 4 */ kdp_maxbytes,
66 /* 5 */ kdp_readmem,
67 /* 6 */ kdp_writemem,
68 /* 7 */ kdp_readregs,
69 /* 8 */ kdp_writeregs,
70 /* 9 */ kdp_unknown,
71 /* A */ kdp_unknown,
72 /* B */ kdp_suspend,
73 /* C */ kdp_resumecpus,
74 /* D */ kdp_unknown,
75 /* E */ kdp_unknown,
76 /* F */ kdp_breakpoint_set,
77 /*10 */ kdp_breakpoint_remove,
78 /*11 */ kdp_regions,
79 /*12 */ kdp_reattach,
80 /*13 */ kdp_reboot
81 };
82
83 kdp_glob_t kdp;
84
85
86 #define MAX_BREAKPOINTS 100
87 #define KDP_MAX_BREAKPOINTS 100
88
89 #define BREAKPOINT_NOT_FOUND 101
90 #define BREAKPOINT_ALREADY_SET 102
91
92 #define KDP_VERSION 10
93
94 typedef struct{
95 unsigned int address;
96 unsigned int old_instruction;
97 } kdp_breakpoint_record_t;
98
99 static kdp_breakpoint_record_t breakpoint_list[MAX_BREAKPOINTS];
100 static unsigned int breakpoints_initialized = 0;
101
102 int reattach_wait = 0;
103 int noresume_on_disconnect = 0;
104
105 #define MAXCOMLEN 16
106
107 struct thread_snapshot {
108 uint32_t snapshot_magic;
109 thread_t thread_id;
110 int32_t state;
111 wait_queue_t wait_queue;
112 event64_t wait_event;
113 vm_offset_t kernel_stack;
114 vm_offset_t reserved_stack;
115 thread_continue_t continuation;
116 uint32_t nkern_frames;
117 char user64_p;
118 uint32_t nuser_frames;
119 int32_t pid;
120 char p_comm[MAXCOMLEN + 1];
121 };
122
123 typedef struct thread_snapshot *thread_snapshot_t;
124
125 extern int
126 machine_trace_thread(thread_t thread, uint32_t tracepos, uint32_t tracebound, int nframes, boolean_t user_p);
127 extern int
128 machine_trace_thread64(thread_t thread, uint32_t tracepos, uint32_t tracebound, int nframes, boolean_t user_p);
129 extern int
130 proc_pid(void *p);
131 extern void
132 proc_name(int pid, char *buf, int size);
133 extern void
134 kdp_snapshot_postflight(void);
135
136 static int
137 pid_from_task(task_t task);
138
139 int
140 kdp_stackshot(int pid, uint32_t tracebuf, uint32_t tracebuf_size, unsigned trace_options, uint32_t *pbytesTraced);
141
142 extern char version[];
143
144 boolean_t
145 kdp_packet(
146 unsigned char *pkt,
147 int *len,
148 unsigned short *reply_port
149 )
150 {
151 static unsigned aligned_pkt[1538/sizeof(unsigned)+1]; // max ether pkt
152 kdp_pkt_t *rd = (kdp_pkt_t *)&aligned_pkt;
153 int plen = *len;
154 unsigned int req;
155 boolean_t ret;
156
157 #if DO_ALIGN
158 bcopy((char *)pkt, (char *)rd, sizeof(aligned_pkt));
159 #else
160 rd = (kdp_pkt_t *)pkt;
161 #endif
162 if (plen < sizeof (rd->hdr) || rd->hdr.len != plen) {
163 printf("kdp_packet bad len pkt %d hdr %d\n", plen, rd->hdr.len);
164
165 return (FALSE);
166 }
167
168 if (rd->hdr.is_reply) {
169 printf("kdp_packet reply recvd req %x seq %x\n",
170 rd->hdr.request, rd->hdr.seq);
171
172 return (FALSE);
173 }
174
175 req = rd->hdr.request;
176 if ((req < KDP_CONNECT) || (req > KDP_HOSTREBOOT)) {
177 printf("kdp_packet bad request %x len %d seq %x key %x\n",
178 rd->hdr.request, rd->hdr.len, rd->hdr.seq, rd->hdr.key);
179
180 return (FALSE);
181 }
182
183 ret = ((*dispatch_table[req - KDP_CONNECT])(rd, len, reply_port));
184 #if DO_ALIGN
185 bcopy((char *)rd, (char *) pkt, *len);
186 #endif
187 return ret;
188 }
189
190 static boolean_t
191 kdp_unknown(
192 kdp_pkt_t *pkt,
193 int *len,
194 unsigned short *reply_port
195 )
196 {
197 kdp_pkt_t *rd = (kdp_pkt_t *)pkt;
198
199 printf("kdp_unknown request %x len %d seq %x key %x\n",
200 rd->hdr.request, rd->hdr.len, rd->hdr.seq, rd->hdr.key);
201
202 return (FALSE);
203 }
204
205 static boolean_t
206 kdp_connect(
207 kdp_pkt_t *pkt,
208 int *len,
209 unsigned short *reply_port
210 )
211 {
212 kdp_connect_req_t *rq = &pkt->connect_req;
213 int plen = *len;
214 kdp_connect_reply_t *rp = &pkt->connect_reply;
215
216 if (plen < sizeof (*rq))
217 return (FALSE);
218
219 dprintf(("kdp_connect seq %x greeting %s\n", rq->hdr.seq, rq->greeting));
220
221 if (kdp.is_conn) {
222 if (rq->hdr.seq == kdp.conn_seq) /* duplicate request */
223 rp->error = KDPERR_NO_ERROR;
224 else
225 rp->error = KDPERR_ALREADY_CONNECTED;
226 }
227 else {
228 kdp.reply_port = rq->req_reply_port;
229 kdp.exception_port = rq->exc_note_port;
230 kdp.is_conn = TRUE;
231 kdp.conn_seq = rq->hdr.seq;
232
233 rp->error = KDPERR_NO_ERROR;
234 }
235
236 rp->hdr.is_reply = 1;
237 rp->hdr.len = sizeof (*rp);
238
239 *reply_port = kdp.reply_port;
240 *len = rp->hdr.len;
241
242 if (current_debugger == KDP_CUR_DB)
243 active_debugger=1;
244
245 return (TRUE);
246 }
247
248 static boolean_t
249 kdp_disconnect(
250 kdp_pkt_t *pkt,
251 int *len,
252 unsigned short *reply_port
253 )
254 {
255 kdp_disconnect_req_t *rq = &pkt->disconnect_req;
256 int plen = *len;
257 kdp_disconnect_reply_t *rp = &pkt->disconnect_reply;
258
259 if (plen < sizeof (*rq))
260 return (FALSE);
261
262 if (!kdp.is_conn)
263 return (FALSE);
264
265 dprintf(("kdp_disconnect\n"));
266
267 *reply_port = kdp.reply_port;
268
269 kdp.reply_port = kdp.exception_port = 0;
270 kdp.is_halted = kdp.is_conn = FALSE;
271 kdp.exception_seq = kdp.conn_seq = 0;
272
273 if (noresume_on_disconnect == 1) {
274 reattach_wait = 1;
275 noresume_on_disconnect = 0;
276 }
277
278 rp->hdr.is_reply = 1;
279 rp->hdr.len = sizeof (*rp);
280
281 *len = rp->hdr.len;
282
283 if (current_debugger == KDP_CUR_DB)
284 active_debugger=0;
285
286 return (TRUE);
287 }
288
289 static boolean_t
290 kdp_reattach(
291 kdp_pkt_t *pkt,
292 int *len,
293 unsigned short *reply_port
294 )
295 {
296 kdp_reattach_req_t *rq = &pkt->reattach_req;
297 kdp_disconnect_reply_t *rp = &pkt->disconnect_reply;
298
299 kdp.is_conn = TRUE;
300 kdp_disconnect(pkt, len, reply_port);
301 *reply_port = rq->req_reply_port;
302 reattach_wait = 1;
303 return (TRUE);
304 }
305
306 static boolean_t
307 kdp_hostinfo(
308 kdp_pkt_t *pkt,
309 int *len,
310 unsigned short *reply_port
311 )
312 {
313 kdp_hostinfo_req_t *rq = &pkt->hostinfo_req;
314 int plen = *len;
315 kdp_hostinfo_reply_t *rp = &pkt->hostinfo_reply;
316
317 if (plen < sizeof (*rq))
318 return (FALSE);
319
320 rp->hdr.is_reply = 1;
321 rp->hdr.len = sizeof (*rp);
322
323 kdp_machine_hostinfo(&rp->hostinfo);
324
325 *reply_port = kdp.reply_port;
326 *len = rp->hdr.len;
327
328 return (TRUE);
329 }
330
331 static boolean_t
332 kdp_suspend(
333 kdp_pkt_t *pkt,
334 int *len,
335 unsigned short *reply_port
336 )
337 {
338 kdp_suspend_req_t *rq = &pkt->suspend_req;
339 int plen = *len;
340 kdp_suspend_reply_t *rp = &pkt->suspend_reply;
341
342 if (plen < sizeof (*rq))
343 return (FALSE);
344
345 rp->hdr.is_reply = 1;
346 rp->hdr.len = sizeof (*rp);
347
348 dprintf(("kdp_suspend\n"));
349
350 kdp.is_halted = TRUE;
351
352 *reply_port = kdp.reply_port;
353 *len = rp->hdr.len;
354
355 return (TRUE);
356 }
357
358 static boolean_t
359 kdp_resumecpus(
360 kdp_pkt_t *pkt,
361 int *len,
362 unsigned short *reply_port
363 )
364 {
365 kdp_resumecpus_req_t *rq = &pkt->resumecpus_req;
366 int plen = *len;
367 kdp_resumecpus_reply_t *rp = &pkt->resumecpus_reply;
368
369 if (plen < sizeof (*rq))
370 return (FALSE);
371
372 rp->hdr.is_reply = 1;
373 rp->hdr.len = sizeof (*rp);
374
375 dprintf(("kdp_resumecpus %x\n", rq->cpu_mask));
376
377 kdp.is_halted = FALSE;
378
379 *reply_port = kdp.reply_port;
380 *len = rp->hdr.len;
381
382 return (TRUE);
383 }
384
385 static boolean_t
386 kdp_writemem(
387 kdp_pkt_t *pkt,
388 int *len,
389 unsigned short *reply_port
390 )
391 {
392 kdp_writemem_req_t *rq = &pkt->writemem_req;
393 int plen = *len;
394 kdp_writemem_reply_t *rp = &pkt->writemem_reply;
395 int cnt;
396
397 if (plen < sizeof (*rq))
398 return (FALSE);
399
400 if (rq->nbytes > MAX_KDP_DATA_SIZE)
401 rp->error = KDPERR_BAD_NBYTES;
402 else {
403 dprintf(("kdp_writemem addr %x size %d\n", rq->address, rq->nbytes));
404
405 cnt = kdp_vm_write((caddr_t)rq->data, (caddr_t)rq->address, rq->nbytes);
406 rp->error = KDPERR_NO_ERROR;
407 }
408
409 rp->hdr.is_reply = 1;
410 rp->hdr.len = sizeof (*rp);
411
412 *reply_port = kdp.reply_port;
413 *len = rp->hdr.len;
414
415 return (TRUE);
416 }
417
418 static boolean_t
419 kdp_readmem(
420 kdp_pkt_t *pkt,
421 int *len,
422 unsigned short *reply_port
423 )
424 {
425 kdp_readmem_req_t *rq = &pkt->readmem_req;
426 int plen = *len;
427 kdp_readmem_reply_t *rp = &pkt->readmem_reply;
428 int cnt;
429 #if __i386__
430 void *pversion = &version;
431 #endif
432 if (plen < sizeof (*rq))
433 return (FALSE);
434
435 rp->hdr.is_reply = 1;
436 rp->hdr.len = sizeof (*rp);
437
438 if (rq->nbytes > MAX_KDP_DATA_SIZE)
439 rp->error = KDPERR_BAD_NBYTES;
440 else {
441 unsigned int n = rq->nbytes;
442
443 dprintf(("kdp_readmem addr %x size %d\n", rq->address, rq->nbytes));
444 #if __i386__
445 /* XXX This is a hack to facilitate the "showversion" macro
446 * on i386, which is used to obtain the kernel version without
447 * symbols - a pointer to the version string should eventually
448 * be pinned at a fixed address when an equivalent of the
449 * VECTORS segment (loaded at a fixed load address, and contains
450 * a table) is implemented on x86, as with PPC.
451 */
452 if (rq->address == (void *)0x501C)
453 rq->address = &pversion;
454 #endif
455 cnt = kdp_vm_read((caddr_t)rq->address, (caddr_t)rp->data, rq->nbytes);
456 rp->error = KDPERR_NO_ERROR;
457
458 rp->hdr.len += cnt;
459 }
460
461 *reply_port = kdp.reply_port;
462 *len = rp->hdr.len;
463
464 return (TRUE);
465 }
466
467 static boolean_t
468 kdp_maxbytes(
469 kdp_pkt_t *pkt,
470 int *len,
471 unsigned short *reply_port
472 )
473 {
474 kdp_maxbytes_req_t *rq = &pkt->maxbytes_req;
475 int plen = *len;
476 kdp_maxbytes_reply_t *rp = &pkt->maxbytes_reply;
477
478 if (plen < sizeof (*rq))
479 return (FALSE);
480
481 rp->hdr.is_reply = 1;
482 rp->hdr.len = sizeof (*rp);
483
484 dprintf(("kdp_maxbytes\n"));
485
486 rp->max_bytes = MAX_KDP_DATA_SIZE;
487
488 *reply_port = kdp.reply_port;
489 *len = rp->hdr.len;
490
491 return (TRUE);
492 }
493
494 static boolean_t
495 kdp_version(
496 kdp_pkt_t *pkt,
497 int *len,
498 unsigned short *reply_port
499 )
500 {
501 kdp_version_req_t *rq = &pkt->version_req;
502 int plen = *len;
503 kdp_version_reply_t *rp = &pkt->version_reply;
504 kdp_region_t *r;
505
506 if (plen < sizeof (*rq))
507 return (FALSE);
508
509 rp->hdr.is_reply = 1;
510 rp->hdr.len = sizeof (*rp);
511
512 dprintf(("kdp_version\n"));
513
514 rp->version = KDP_VERSION;
515 #ifdef __ppc__
516 if (!(kdp_flag & KDP_BP_DIS))
517 rp->feature = KDP_FEATURE_BP;
518 else
519 rp->feature = 0;
520 #else
521 rp->feature = 0;
522 #endif
523
524 *reply_port = kdp.reply_port;
525 *len = rp->hdr.len;
526
527 return (TRUE);
528 }
529
530 static boolean_t
531 kdp_regions(
532 kdp_pkt_t *pkt,
533 int *len,
534 unsigned short *reply_port
535 )
536 {
537 kdp_regions_req_t *rq = &pkt->regions_req;
538 int plen = *len;
539 kdp_regions_reply_t *rp = &pkt->regions_reply;
540 kdp_region_t *r;
541
542 if (plen < sizeof (*rq))
543 return (FALSE);
544
545 rp->hdr.is_reply = 1;
546 rp->hdr.len = sizeof (*rp);
547
548 dprintf(("kdp_regions\n"));
549
550 r = rp->regions;
551 rp->nregions = 0;
552
553 (vm_offset_t)r->address = 0;
554 r->nbytes = 0xffffffff;
555
556 r->protection = VM_PROT_ALL; r++; rp->nregions++;
557
558 rp->hdr.len += rp->nregions * sizeof (kdp_region_t);
559
560 *reply_port = kdp.reply_port;
561 *len = rp->hdr.len;
562
563 return (TRUE);
564 }
565
566 static boolean_t
567 kdp_writeregs(
568 kdp_pkt_t *pkt,
569 int *len,
570 unsigned short *reply_port
571 )
572 {
573 kdp_writeregs_req_t *rq = &pkt->writeregs_req;
574 int plen = *len;
575 int size;
576 kdp_writeregs_reply_t *rp = &pkt->writeregs_reply;
577
578 if (plen < sizeof (*rq))
579 return (FALSE);
580
581 size = rq->hdr.len - sizeof(kdp_hdr_t) - sizeof(unsigned int);
582 rp->error = kdp_machine_write_regs(rq->cpu, rq->flavor, rq->data, &size);
583
584 rp->hdr.is_reply = 1;
585 rp->hdr.len = sizeof (*rp);
586
587 *reply_port = kdp.reply_port;
588 *len = rp->hdr.len;
589
590 return (TRUE);
591 }
592
593 static boolean_t
594 kdp_readregs(
595 kdp_pkt_t *pkt,
596 int *len,
597 unsigned short *reply_port
598 )
599 {
600 kdp_readregs_req_t *rq = &pkt->readregs_req;
601 int plen = *len;
602 kdp_readregs_reply_t *rp = &pkt->readregs_reply;
603 int size;
604
605 if (plen < sizeof (*rq))
606 return (FALSE);
607
608 rp->hdr.is_reply = 1;
609 rp->hdr.len = sizeof (*rp);
610
611 rp->error = kdp_machine_read_regs(rq->cpu, rq->flavor, rp->data, &size);
612 rp->hdr.len += size;
613
614 *reply_port = kdp.reply_port;
615 *len = rp->hdr.len;
616
617 return (TRUE);
618 }
619
620 static boolean_t
621 kdp_breakpoint_set(
622 kdp_pkt_t *pkt,
623 int *len,
624 unsigned short *reply_port
625 )
626 {
627 kdp_breakpoint_req_t *rq = &pkt->breakpoint_req;
628 kdp_breakpoint_reply_t *rp = &pkt->breakpoint_reply;
629 int plen = *len;
630 int cnt, i;
631 unsigned int old_instruction = 0;
632 unsigned int breakinstr = kdp_ml_get_breakinsn();
633
634 if(breakpoints_initialized == 0)
635 {
636 for(i=0;(i < MAX_BREAKPOINTS); breakpoint_list[i].address=0, i++);
637 breakpoints_initialized++;
638 }
639 if (plen < sizeof (*rq))
640 return (FALSE);
641 cnt = kdp_vm_read((caddr_t)rq->address, (caddr_t)(&old_instruction), sizeof(int));
642
643 if (old_instruction==breakinstr)
644 {
645 printf("A trap was already set at that address, not setting new breakpoint\n");
646 rp->error = BREAKPOINT_ALREADY_SET;
647
648 rp->hdr.is_reply = 1;
649 rp->hdr.len = sizeof (*rp);
650 *reply_port = kdp.reply_port;
651 *len = rp->hdr.len;
652
653 return (TRUE);
654 }
655
656 for(i=0;(i < MAX_BREAKPOINTS) && (breakpoint_list[i].address != 0); i++);
657
658 if (i == MAX_BREAKPOINTS)
659 {
660 rp->error = KDP_MAX_BREAKPOINTS;
661
662 rp->hdr.is_reply = 1;
663 rp->hdr.len = sizeof (*rp);
664 *reply_port = kdp.reply_port;
665 *len = rp->hdr.len;
666
667 return (TRUE);
668 }
669 breakpoint_list[i].address = rq->address;
670 breakpoint_list[i].old_instruction = old_instruction;
671
672 cnt = kdp_vm_write((caddr_t)&breakinstr, (caddr_t)rq->address, sizeof(&breakinstr));
673
674 rp->error = KDPERR_NO_ERROR;
675 rp->hdr.is_reply = 1;
676 rp->hdr.len = sizeof (*rp);
677 *reply_port = kdp.reply_port;
678 *len = rp->hdr.len;
679
680 return (TRUE);
681 }
682
683 static boolean_t
684 kdp_breakpoint_remove(
685 kdp_pkt_t *pkt,
686 int *len,
687 unsigned short *reply_port
688 )
689 {
690 kdp_breakpoint_req_t *rq = &pkt->breakpoint_req;
691 kdp_breakpoint_reply_t *rp = &pkt->breakpoint_reply;
692 int plen = *len;
693 int cnt,i;
694
695 if (plen < sizeof (*rq))
696 return (FALSE);
697
698 for(i=0;(i < MAX_BREAKPOINTS) && (breakpoint_list[i].address != rq->address); i++);
699 if (i == MAX_BREAKPOINTS)
700 {
701 rp->error = BREAKPOINT_NOT_FOUND;
702 rp->hdr.is_reply = 1;
703 rp->hdr.len = sizeof (*rp);
704 *reply_port = kdp.reply_port;
705 *len = rp->hdr.len;
706
707 return (TRUE); /* Check if it needs to be FALSE in case of error */
708 }
709
710 breakpoint_list[i].address = 0;
711 cnt = kdp_vm_write((caddr_t)&(breakpoint_list[i].old_instruction), (caddr_t)rq->address, sizeof(int));
712 rp->error = KDPERR_NO_ERROR;
713 rp->hdr.is_reply = 1;
714 rp->hdr.len = sizeof (*rp);
715 *reply_port = kdp.reply_port;
716 *len = rp->hdr.len;
717
718 return (TRUE);
719 }
720
721 boolean_t
722 kdp_remove_all_breakpoints()
723 {
724 int i;
725 boolean_t breakpoint_found = FALSE;
726
727 if (breakpoints_initialized)
728 {
729 for(i=0;i < MAX_BREAKPOINTS; i++)
730 {
731 if (breakpoint_list[i].address)
732 {
733 kdp_vm_write((caddr_t)&(breakpoint_list[i].old_instruction), (caddr_t)breakpoint_list[i].address, sizeof(int));
734 breakpoint_found = TRUE;
735 breakpoint_list[i].address = 0;
736 }
737 }
738 if (breakpoint_found)
739 printf("kdp_remove_all_breakpoints: found extant breakpoints, removing them.\n");
740 }
741 return breakpoint_found;
742 }
743
744
745 #define MAX_FRAMES 1000
746
747 static int pid_from_task(task_t task)
748 {
749 int pid = -1;
750
751 if (task->bsd_info)
752 pid = proc_pid(task->bsd_info);
753
754 return pid;
755 }
756
757 int
758 kdp_stackshot(int pid, uint32_t tracebuf, uint32_t tracebuf_size, unsigned trace_options, uint32_t *pbytesTraced)
759 {
760 uint32_t tracepos = (uint32_t) tracebuf;
761 uint32_t tracebound = tracepos + tracebuf_size;
762 uint32_t tracebytes = 0;
763 int error = 0;
764
765 processor_set_t pset = &default_pset;
766 task_t task = TASK_NULL;
767 thread_t thread = THREAD_NULL;
768 int nframes = trace_options;
769 thread_snapshot_t tsnap = NULL;
770 unsigned framesize = 2 * sizeof(vm_offset_t);
771
772 if ((nframes <= 0) || nframes > MAX_FRAMES)
773 nframes = MAX_FRAMES;
774
775 queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
776 /* Trace everything, unless a process was specified */
777 if ((pid == -1) || (pid == pid_from_task(task)))
778 queue_iterate(&task->threads, thread, thread_t, task_threads){
779 if ((tracepos + 4 * sizeof(struct thread_snapshot)) > tracebound) {
780 error = -1;
781 goto error_exit;
782 }
783 /* Populate the thread snapshot header */
784 tsnap = (thread_snapshot_t) tracepos;
785 tsnap->thread_id = thread;
786 tsnap->state = thread->state;
787 tsnap->wait_queue = thread->wait_queue;
788 tsnap->wait_event = thread->wait_event;
789 tsnap->kernel_stack = thread->kernel_stack;
790 tsnap->reserved_stack = thread->reserved_stack;
791 tsnap->continuation = thread->continuation;
792 /* Add the BSD process identifiers */
793 if ((tsnap->pid = pid_from_task(task)) != -1)
794 proc_name(tsnap->pid, tsnap->p_comm, MAXCOMLEN + 1);
795 else
796 tsnap->p_comm[0] = '\0';
797
798 tsnap->snapshot_magic = 0xfeedface;
799 tracepos += sizeof(struct thread_snapshot);
800
801 /* Call through to the machine specific trace routines
802 * Frames are added past the snapshot header.
803 */
804 if (tsnap->kernel_stack != 0)
805 tracebytes = machine_trace_thread(thread, tracepos, tracebound, nframes, FALSE);
806 tsnap->nkern_frames = tracebytes/(2 * sizeof(vm_offset_t));
807 tracepos += tracebytes;
808 tracebytes = 0;
809 tsnap->user64_p = 0;
810 /* Trace user stack, if any */
811 if (thread->task->map != kernel_map) {
812 /* 64-bit task? */
813 if (task_has_64BitAddr(thread->task)) {
814 tracebytes = machine_trace_thread64(thread, tracepos, tracebound, nframes, TRUE);
815 tsnap->user64_p = 1;
816 framesize = 2 * sizeof(addr64_t);
817 }
818 else {
819 tracebytes = machine_trace_thread(thread, tracepos, tracebound, nframes, TRUE);
820 framesize = 2 * sizeof(vm_offset_t);
821 }
822 }
823 tsnap->nuser_frames = tracebytes/framesize;
824 tracepos += tracebytes;
825 tracebytes = 0;
826 }
827 }
828
829 error_exit:
830 /* Release stack snapshot wait indicator */
831 kdp_snapshot_postflight();
832
833 *pbytesTraced = tracepos - tracebuf;
834
835 return error;
836 }