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