1 // Copyright © 2009 The Go Authors. All rights reserved.
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to deal
5 // in the Software without restriction, including without limitation the rights
6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 // copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
9 //
10 // The above copyright notice and this permission notice shall be included in
11 // all copies or substantial portions of the Software.
12 //
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 // THE SOFTWARE.
20
21 #define __DARWIN_UNIX03 0
22
23 #include <u.h>
24 #include <sys/ptrace.h>
25 #include <sys/signal.h>
26 #include <mach/mach.h>
27 #include <mach/mach_traps.h>
28 #include <errno.h>
29 #include <libc.h>
30 #include <bio.h>
31 #include <mach.h>
32 #define Ureg Ureg32
33 #include <ureg_x86.h>
34 #undef Ureg
35 #define Ureg Ureg64
36 #include <ureg_amd64.h>
37 #undef Ureg
38 #undef waitpid /* want Unix waitpid, not Plan 9 */
39
40 typedef struct Ureg32 Ureg32;
41 typedef struct Ureg64 Ureg64;
42
43 extern mach_port_t mach_reply_port(void); // should be in system headers, is not
44
45 // Mach-error wrapper.
46 // Takes a mach return code and converts it into 0 / -1,
47 // setting errstr when it returns -1.
48
49 static struct {
50 int code;
51 char *name;
52 } macherr[] = {
53 KERN_INVALID_ADDRESS, "invalid address",
54 KERN_PROTECTION_FAILURE, "protection failure",
55 KERN_NO_SPACE, "no space",
56 KERN_INVALID_ARGUMENT, "invalid argument",
57 KERN_FAILURE, "failure",
58 KERN_RESOURCE_SHORTAGE, "resource shortage",
59 KERN_NOT_RECEIVER, "not receiver",
60 KERN_NO_ACCESS, "no access",
61 KERN_MEMORY_FAILURE, "memory failure",
62 KERN_MEMORY_ERROR, "memory error",
63 KERN_ALREADY_IN_SET, "already in set",
64 KERN_NOT_IN_SET, "not in set",
65 KERN_NAME_EXISTS, "name exists",
66 KERN_ABORTED, "aborted",
67 KERN_INVALID_NAME, "invalid name",
68 KERN_INVALID_TASK, "invalid task",
69 KERN_INVALID_RIGHT, "invalid right",
70 KERN_INVALID_VALUE, "invalid value",
71 KERN_UREFS_OVERFLOW, "urefs overflow",
72 KERN_INVALID_CAPABILITY, "invalid capability",
73 KERN_RIGHT_EXISTS, "right exists",
74 KERN_INVALID_HOST, "invalid host",
75 KERN_MEMORY_PRESENT, "memory present",
76 KERN_MEMORY_DATA_MOVED, "memory data moved",
77 KERN_MEMORY_RESTART_COPY, "memory restart copy",
78 KERN_INVALID_PROCESSOR_SET, "invalid processor set",
79 KERN_POLICY_LIMIT, "policy limit",
80 KERN_INVALID_POLICY, "invalid policy",
81 KERN_INVALID_OBJECT, "invalid object",
82 KERN_ALREADY_WAITING, "already waiting",
83 KERN_DEFAULT_SET, "default set",
84 KERN_EXCEPTION_PROTECTED, "exception protected",
85 KERN_INVALID_LEDGER, "invalid ledger",
86 KERN_INVALID_MEMORY_CONTROL, "invalid memory control",
87 KERN_INVALID_SECURITY, "invalid security",
88 KERN_NOT_DEPRESSED, "not depressed",
89 KERN_TERMINATED, "terminated",
90 KERN_LOCK_SET_DESTROYED, "lock set destroyed",
91 KERN_LOCK_UNSTABLE, "lock unstable",
92 KERN_LOCK_OWNED, "lock owned",
93 KERN_LOCK_OWNED_SELF, "lock owned self",
94 KERN_SEMAPHORE_DESTROYED, "semaphore destroyed",
95 KERN_RPC_SERVER_TERMINATED, "rpc server terminated",
96 KERN_RPC_TERMINATE_ORPHAN, "rpc terminate orphan",
97 KERN_RPC_CONTINUE_ORPHAN, "rpc continue orphan",
98 KERN_NOT_SUPPORTED, "not supported",
99 KERN_NODE_DOWN, "node down",
100 KERN_NOT_WAITING, "not waiting",
101 KERN_OPERATION_TIMED_OUT, "operation timed out",
102 KERN_RETURN_MAX, "return max",
103
104 MACH_SEND_IN_PROGRESS, "send in progress",
105 MACH_SEND_INVALID_DATA, "send invalid data",
106 MACH_SEND_INVALID_DEST, "send invalid dest",
107 MACH_SEND_TIMED_OUT, "send timed out",
108 MACH_SEND_INTERRUPTED, "send interrupted",
109 MACH_SEND_MSG_TOO_SMALL, "send msg too small",
110 MACH_SEND_INVALID_REPLY, "send invalid reply",
111 MACH_SEND_INVALID_RIGHT, "send invalid right",
112 MACH_SEND_INVALID_NOTIFY, "send invalid notify",
113 MACH_SEND_INVALID_MEMORY, "send invalid memory",
114 MACH_SEND_NO_BUFFER, "send no buffer",
115 MACH_SEND_TOO_LARGE, "send too large",
116 MACH_SEND_INVALID_TYPE, "send invalid type",
117 MACH_SEND_INVALID_HEADER, "send invalid header",
118 MACH_SEND_INVALID_TRAILER, "send invalid trailer",
119 MACH_SEND_INVALID_RT_OOL_SIZE, "send invalid rt ool size",
120 MACH_RCV_IN_PROGRESS, "rcv in progress",
121 MACH_RCV_INVALID_NAME, "rcv invalid name",
122 MACH_RCV_TIMED_OUT, "rcv timed out",
123 MACH_RCV_TOO_LARGE, "rcv too large",
124 MACH_RCV_INTERRUPTED, "rcv interrupted",
125 MACH_RCV_PORT_CHANGED, "rcv port changed",
126 MACH_RCV_INVALID_NOTIFY, "rcv invalid notify",
127 MACH_RCV_INVALID_DATA, "rcv invalid data",
128 MACH_RCV_PORT_DIED, "rcv port died",
129 MACH_RCV_IN_SET, "rcv in set",
130 MACH_RCV_HEADER_ERROR, "rcv header error",
131 MACH_RCV_BODY_ERROR, "rcv body error",
132 MACH_RCV_INVALID_TYPE, "rcv invalid type",
133 MACH_RCV_SCATTER_SMALL, "rcv scatter small",
134 MACH_RCV_INVALID_TRAILER, "rcv invalid trailer",
135 MACH_RCV_IN_PROGRESS_TIMED, "rcv in progress timed",
136
137 MIG_TYPE_ERROR, "mig type error",
138 MIG_REPLY_MISMATCH, "mig reply mismatch",
139 MIG_REMOTE_ERROR, "mig remote error",
140 MIG_BAD_ID, "mig bad id",
141 MIG_BAD_ARGUMENTS, "mig bad arguments",
142 MIG_NO_REPLY, "mig no reply",
143 MIG_EXCEPTION, "mig exception",
144 MIG_ARRAY_TOO_LARGE, "mig array too large",
145 MIG_SERVER_DIED, "server died",
146 MIG_TRAILER_ERROR, "trailer has an unknown format",
147 };
148
149 static int
150 me(kern_return_t r)
151 {
152 int i;
153
154 if(r == 0)
155 return 0;
156
157 for(i=0; i<nelem(macherr); i++){
158 if(r == macherr[i].code){
159 werrstr("mach: %s", macherr[i].name);
160 return -1;
161 }
162 }
163 werrstr("mach error %#x", r);
164 return -1;
165 }
166
167 // Plan 9 and Linux do not distinguish between
168 // process ids and thread ids, so the interface here doesn't either.
169 // Unfortunately, Mach has three kinds of identifiers: process ids,
170 // handles to tasks (processes), and handles to threads within a
171 // process. All of them are small integers.
172 //
173 // To accommodate Mach, we employ a clumsy hack: in this interface,
174 // if you pass in a positive number, that's a process id.
175 // If you pass in a negative number, that identifies a thread that
176 // has been previously returned by procthreadpids (it indexes
177 // into the Thread table below).
178
179 // Table of threads we have handles for.
180 typedef struct Thread Thread;
181 struct Thread
182 {
183 int pid;
184 mach_port_t task;
185 mach_port_t thread;
186 int stopped;
187 int exc;
188 int code[10];
189 Map *map;
190 };
191 static Thread thr[1000];
192 static int nthr;
193 static pthread_mutex_t mu;
194 static pthread_cond_t cond;
195 static void* excthread(void*);
196 static void* waitthread(void*);
197 static mach_port_t excport;
198
199 enum {
200 ExcMask = EXC_MASK_BAD_ACCESS |
201 EXC_MASK_BAD_INSTRUCTION |
202 EXC_MASK_ARITHMETIC |
203 EXC_MASK_BREAKPOINT |
204 EXC_MASK_SOFTWARE
205 };
206
207 // Add process pid to the thread table.
208 // If it's already there, don't re-add it (unless force != 0).
209 static Thread*
210 addpid(int pid, int force)
211 {
212 int i, j;
213 mach_port_t task;
214 mach_port_t *thread;
215 uint nthread;
216 Thread *ret;
217 static int first = 1;
218
219 if(first){
220 // Allocate a port for exception messages and
221 // send all thread exceptions to that port.
222 // The excthread reads that port and signals
223 // us if we are waiting on that thread.
224 pthread_t p;
225 int err;
226
227 excport = mach_reply_port();
228 pthread_mutex_init(&mu, nil);
229 pthread_cond_init(&cond, nil);
230 err = pthread_create(&p, nil, excthread, nil);
231 if (err != 0) {
232 fprint(2, "pthread_create failed: %s\n", strerror(err));
233 abort();
234 }
235 err = pthread_create(&p, nil, waitthread, (void*)(uintptr)pid);
236 if (err != 0) {
237 fprint(2, "pthread_create failed: %s\n", strerror(err));
238 abort();
239 }
240 first = 0;
241 }
242
243 if(!force){
244 for(i=0; i<nthr; i++)
245 if(thr[i].pid == pid)
246 return &thr[i];
247 }
248 if(me(task_for_pid(mach_task_self(), pid, &task)) < 0)
249 return nil;
250 if(me(task_threads(task, &thread, &nthread)) < 0)
251 return nil;
252 mach_port_insert_right(mach_task_self(), excport, excport, MACH_MSG_TYPE_MAKE_SEND);
253 if(me(task_set_exception_ports(task, ExcMask,
254 excport, EXCEPTION_DEFAULT, MACHINE_THREAD_STATE)) < 0){
255 fprint(2, "warning: cannot set excport: %r\n");
256 }
257 ret = nil;
258 for(j=0; j<nthread; j++){
259 if(force){
260 // If we're forcing a refresh, don't re-add existing threads.
261 for(i=0; i<nthr; i++)
262 if(thr[i].pid == pid && thr[i].thread == thread[j]){
263 if(ret == nil)
264 ret = &thr[i];
265 goto skip;
266 }
267 }
268 if(nthr >= nelem(thr))
269 return nil;
270 // TODO: We probably should save the old thread exception
271 // ports for each bit and then put them back when we exit.
272 // Probably the BSD signal handlers have put stuff there.
273 mach_port_insert_right(mach_task_self(), excport, excport, MACH_MSG_TYPE_MAKE_SEND);
274 if(me(thread_set_exception_ports(thread[j], ExcMask,
275 excport, EXCEPTION_DEFAULT, MACHINE_THREAD_STATE)) < 0){
276 fprint(2, "warning: cannot set excport: %r\n");
277 }
278 thr[nthr].pid = pid;
279 thr[nthr].task = task;
280 thr[nthr].thread = thread[j];
281 if(ret == nil)
282 ret = &thr[nthr];
283 nthr++;
284 skip:;
285 }
286 return ret;
287 }
288
289 static Thread*
290 idtotable(int id)
291 {
292 if(id >= 0)
293 return addpid(id, 1);
294
295 id = -(id+1);
296 if(id >= nthr)
297 return nil;
298 return &thr[id];
299 }
300
301 /*
302 static int
303 idtopid(int id)
304 {
305 Thread *t;
306
307 if((t = idtotable(id)) == nil)
308 return -1;
309 return t->pid;
310 }
311 */
312
313 static mach_port_t
314 idtotask(int id)
315 {
316 Thread *t;
317
318 if((t = idtotable(id)) == nil)
319 return -1;
320 return t->task;
321 }
322
323 static mach_port_t
324 idtothread(int id)
325 {
326 Thread *t;
327
328 if((t = idtotable(id)) == nil)
329 return -1;
330 return t->thread;
331 }
332
333 static int machsegrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr);
334 static int machregrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr);
335
336 Map*
337 attachproc(int id, Fhdr *fp)
338 {
339 Thread *t;
340 Map *map;
341
342 if((t = idtotable(id)) == nil)
343 return nil;
344 if(t->map)
345 return t->map;
346 map = newmap(0, 4);
347 if(!map)
348 return nil;
349 map->pid = -((t-thr) + 1);
350 if(mach->regsize)
351 setmap(map, -1, 0, mach->regsize, 0, "regs", machregrw);
352 setmap(map, -1, fp->txtaddr, fp->txtaddr+fp->txtsz, fp->txtaddr, "*text", machsegrw);
353 setmap(map, -1, fp->dataddr, mach->utop, fp->dataddr, "*data", machsegrw);
354 t->map = map;
355 return map;
356 }
357
358 // Return list of ids for threads in id.
359 int
360 procthreadpids(int id, int *out, int nout)
361 {
362 Thread *t;
363 int i, n, pid;
364
365 t = idtotable(id);
366 if(t == nil)
367 return -1;
368 pid = t->pid;
369 addpid(pid, 1); // force refresh of thread list
370 n = 0;
371 for(i=0; i<nthr; i++) {
372 if(thr[i].pid == pid) {
373 if(n < nout)
374 out[n] = -(i+1);
375 n++;
376 }
377 }
378 return n;
379 }
380
381 // Detach from proc.
382 // TODO(rsc): Perhaps should unsuspend any threads and clean-up the table.
383 void
384 detachproc(Map *m)
385 {
386 free(m);
387 }
388
389 // Should return array of pending signals (notes)
390 // but don't know how to do that on OS X.
391 int
392 procnotes(int pid, char ***pnotes)
393 {
394 *pnotes = 0;
395 return 0;
396 }
397
398 // There must be a way to do this. Gdb can do it.
399 // But I don't see, in the Apple gdb sources, how.
400 char*
401 proctextfile(int pid)
402 {
403 return nil;
404 }
405
406 // Read/write from a Mach data segment.
407 static int
408 machsegrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr)
409 {
410 mach_port_t task;
411 int r;
412
413 task = idtotask(map->pid);
414 if(task == -1)
415 return -1;
416
417 if(isr){
418 vm_size_t nn;
419 nn = n;
420 if(me(vm_read_overwrite(task, addr, n, (uintptr)v, &nn)) < 0) {
421 fprint(2, "vm_read_overwrite %#llux %d to %p: %r\n", addr, n, v);
422 return -1;
423 }
424 return nn;
425 }else{
426 r = vm_write(task, addr, (uintptr)v, n);
427 if(r == KERN_INVALID_ADDRESS){
428 // Happens when writing to text segment.
429 // Change protections.
430 if(me(vm_protect(task, addr, n, 0, VM_PROT_WRITE|VM_PROT_READ|VM_PROT_EXECUTE)) < 0){
431 fprint(2, "vm_protect: %s\n", r);
432 return -1;
433 }
434 r = vm_write(task, addr, (uintptr)v, n);
435 }
436 if(r != 0){
437 me(r);
438 return -1;
439 }
440 return n;
441 }
442 }
443
444 // Convert Ureg offset to x86_thread_state32_t offset.
445 static int
446 go2darwin32(uvlong addr)
447 {
448 switch(addr){
449 case offsetof(Ureg32, ax):
450 return offsetof(x86_thread_state32_t, eax);
451 case offsetof(Ureg32, bx):
452 return offsetof(x86_thread_state32_t, ebx);
453 case offsetof(Ureg32, cx):
454 return offsetof(x86_thread_state32_t, ecx);
455 case offsetof(Ureg32, dx):
456 return offsetof(x86_thread_state32_t, edx);
457 case offsetof(Ureg32, si):
458 return offsetof(x86_thread_state32_t, esi);
459 case offsetof(Ureg32, di):
460 return offsetof(x86_thread_state32_t, edi);
461 case offsetof(Ureg32, bp):
462 return offsetof(x86_thread_state32_t, ebp);
463 case offsetof(Ureg32, fs):
464 return offsetof(x86_thread_state32_t, fs);
465 case offsetof(Ureg32, gs):
466 return offsetof(x86_thread_state32_t, gs);
467 case offsetof(Ureg32, pc):
468 return offsetof(x86_thread_state32_t, eip);
469 case offsetof(Ureg32, cs):
470 return offsetof(x86_thread_state32_t, cs);
471 case offsetof(Ureg32, flags):
472 return offsetof(x86_thread_state32_t, eflags);
473 case offsetof(Ureg32, sp):
474 return offsetof(x86_thread_state32_t, esp);
475 }
476 return -1;
477 }
478
479 // Convert Ureg offset to x86_thread_state64_t offset.
480 static int
481 go2darwin64(uvlong addr)
482 {
483 switch(addr){
484 case offsetof(Ureg64, ax):
485 return offsetof(x86_thread_state64_t, rax);
486 case offsetof(Ureg64, bx):
487 return offsetof(x86_thread_state64_t, rbx);
488 case offsetof(Ureg64, cx):
489 return offsetof(x86_thread_state64_t, rcx);
490 case offsetof(Ureg64, dx):
491 return offsetof(x86_thread_state64_t, rdx);
492 case offsetof(Ureg64, si):
493 return offsetof(x86_thread_state64_t, rsi);
494 case offsetof(Ureg64, di):
495 return offsetof(x86_thread_state64_t, rdi);
496 case offsetof(Ureg64, bp):
497 return offsetof(x86_thread_state64_t, rbp);
498 case offsetof(Ureg64, r8):
499 return offsetof(x86_thread_state64_t, r8);
500 case offsetof(Ureg64, r9):
501 return offsetof(x86_thread_state64_t, r9);
502 case offsetof(Ureg64, r10):
503 return offsetof(x86_thread_state64_t, r10);
504 case offsetof(Ureg64, r11):
505 return offsetof(x86_thread_state64_t, r11);
506 case offsetof(Ureg64, r12):
507 return offsetof(x86_thread_state64_t, r12);
508 case offsetof(Ureg64, r13):
509 return offsetof(x86_thread_state64_t, r13);
510 case offsetof(Ureg64, r14):
511 return offsetof(x86_thread_state64_t, r14);
512 case offsetof(Ureg64, r15):
513 return offsetof(x86_thread_state64_t, r15);
514 case offsetof(Ureg64, fs):
515 return offsetof(x86_thread_state64_t, fs);
516 case offsetof(Ureg64, gs):
517 return offsetof(x86_thread_state64_t, gs);
518 case offsetof(Ureg64, ip):
519 return offsetof(x86_thread_state64_t, rip);
520 case offsetof(Ureg64, cs):
521 return offsetof(x86_thread_state64_t, cs);
522 case offsetof(Ureg64, flags):
523 return offsetof(x86_thread_state64_t, rflags);
524 case offsetof(Ureg64, sp):
525 return offsetof(x86_thread_state64_t, rsp);
526 }
527 return -1;
528 }
529
530 extern Mach mi386;
531
532 // Read/write from fake register segment.
533 static int
534 machregrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr)
535 {
536 uint nn, count, state;
537 mach_port_t thread;
538 int reg;
539 char buf[100];
540 union {
541 x86_thread_state64_t reg64;
542 x86_thread_state32_t reg32;
543 uchar p[1];
544 } u;
545 uchar *p;
546
547 if(n > 8){
548 werrstr("asked for %d-byte register", n);
549 return -1;
550 }
551
552 thread = idtothread(map->pid);
553 if(thread == -1){
554 werrstr("no such id");
555 return -1;
556 }
557
558 if(mach == &mi386) {
559 count = x86_THREAD_STATE32_COUNT;
560 state = x86_THREAD_STATE32;
561 if((reg = go2darwin32(addr)) < 0 || reg+n > sizeof u){
562 if(isr){
563 memset(v, 0, n);
564 return 0;
565 }
566 werrstr("register %llud not available", addr);
567 return -1;
568 }
569 } else {
570 count = x86_THREAD_STATE64_COUNT;
571 state = x86_THREAD_STATE64;
572 if((reg = go2darwin64(addr)) < 0 || reg+n > sizeof u){
573 if(isr){
574 memset(v, 0, n);
575 return 0;
576 }
577 werrstr("register %llud not available", addr);
578 return -1;
579 }
580 }
581
582 if(!isr && me(thread_suspend(thread)) < 0){
583 werrstr("thread suspend %#x: %r", thread);
584 return -1;
585 }
586 nn = count;
587 if(me(thread_get_state(thread, state, (void*)u.p, &nn)) < 0){
588 if(!isr)
589 thread_resume(thread);
590 rerrstr(buf, sizeof buf);
591 if(strstr(buf, "send invalid dest") != nil)
592 werrstr("process exited");
593 else
594 werrstr("thread_get_state: %r");
595 return -1;
596 }
597
598 p = u.p+reg;
599 if(isr)
600 memmove(v, p, n);
601 else{
602 memmove(p, v, n);
603 nn = count;
604 if(me(thread_set_state(thread, state, (void*)u.p, nn)) < 0){
605 thread_resume(thread);
606 werrstr("thread_set_state: %r");
607 return -1;
608 }
609
610 if(me(thread_resume(thread)) < 0){
611 werrstr("thread_resume: %r");
612 return -1;
613 }
614 }
615 return 0;
616 }
617
618 enum
619 {
620 FLAGS_TF = 0x100 // x86 single-step processor flag
621 };
622
623 // Is thread t suspended?
624 static int
625 threadstopped(Thread *t)
626 {
627 struct thread_basic_info info;
628 uint size;
629
630 size = sizeof info;
631 if(me(thread_info(t->thread, THREAD_BASIC_INFO, (thread_info_t)&info, &size)) < 0){
632 fprint(2, "threadstopped thread_info %#x: %r\n");
633 return 1;
634 }
635 return info.suspend_count > 0;
636 }
637
638 // If thread t is suspended, start it up again.
639 // If singlestep is set, only let it execute one instruction.
640 static int
641 threadstart(Thread *t, int singlestep)
642 {
643 int i;
644 uint n;
645 struct thread_basic_info info;
646
647 if(!threadstopped(t))
648 return 0;
649
650 // Set or clear the processor single-step flag, as appropriate.
651 if(mach == &mi386) {
652 x86_thread_state32_t regs;
653 n = x86_THREAD_STATE32_COUNT;
654 if(me(thread_get_state(t->thread, x86_THREAD_STATE32,
655 (thread_state_t)®s,
656 &n)) < 0)
657 return -1;
658 if(singlestep)
659 regs.eflags |= FLAGS_TF;
660 else
661 regs.eflags &= ~FLAGS_TF;
662 if(me(thread_set_state(t->thread, x86_THREAD_STATE32,
663 (thread_state_t)®s,
664 x86_THREAD_STATE32_COUNT)) < 0)
665 return -1;
666 } else {
667 x86_thread_state64_t regs;
668 n = x86_THREAD_STATE64_COUNT;
669 if(me(thread_get_state(t->thread, x86_THREAD_STATE64,
670 (thread_state_t)®s,
671 &n)) < 0)
672 return -1;
673 if(singlestep)
674 regs.rflags |= FLAGS_TF;
675 else
676 regs.rflags &= ~FLAGS_TF;
677 if(me(thread_set_state(t->thread, x86_THREAD_STATE64,
678 (thread_state_t)®s,
679 x86_THREAD_STATE64_COUNT)) < 0)
680 return -1;
681 }
682
683 // Run.
684 n = sizeof info;
685 if(me(thread_info(t->thread, THREAD_BASIC_INFO, (thread_info_t)&info, &n)) < 0)
686 return -1;
687 for(i=0; i<info.suspend_count; i++)
688 if(me(thread_resume(t->thread)) < 0)
689 return -1;
690 return 0;
691 }
692
693 // Stop thread t.
694 static int
695 threadstop(Thread *t)
696 {
697 if(threadstopped(t))
698 return 0;
699 if(me(thread_suspend(t->thread)) < 0)
700 return -1;
701 return 0;
702 }
703
704 // Callback for exc_server below. Called when a thread we are
705 // watching has an exception like hitting a breakpoint.
706 kern_return_t
707 catch_exception_raise(mach_port_t eport, mach_port_t thread,
708 mach_port_t task, exception_type_t exception,
709 exception_data_t code, mach_msg_type_number_t ncode)
710 {
711 Thread *t;
712 int i;
713
714 t = nil;
715 for(i=0; i<nthr; i++){
716 if(thr[i].thread == thread){
717 t = &thr[i];
718 goto havet;
719 }
720 }
721 if(nthr > 0)
722 addpid(thr[0].pid, 1);
723 for(i=0; i<nthr; i++){
724 if(thr[i].thread == thread){
725 t = &thr[i];
726 goto havet;
727 }
728 }
729 fprint(2, "did not find thread in catch_exception_raise\n");
730 return KERN_SUCCESS; // let thread continue
731
732 havet:
733 t->exc = exception;
734 if(ncode > nelem(t->code))
735 ncode = nelem(t->code);
736 memmove(t->code, code, ncode*sizeof t->code[0]);
737
738 // Suspend thread, so that we can look at it & restart it later.
739 if(me(thread_suspend(thread)) < 0)
740 fprint(2, "catch_exception_raise thread_suspend: %r\n");
741
742 // Synchronize with waitstop below.
743 pthread_mutex_lock(&mu);
744 pthread_cond_broadcast(&cond);
745 pthread_mutex_unlock(&mu);
746
747 return KERN_SUCCESS;
748 }
749
750 // Exception watching thread, started in addpid above.
751 static void*
752 excthread(void *v)
753 {
754 extern boolean_t exc_server();
755 mach_msg_server(exc_server, 2048, excport, 0);
756 return 0;
757 }
758
759 // Wait for pid to exit.
760 static int exited;
761 static void*
762 waitthread(void *v)
763 {
764 int pid, status;
765
766 pid = (int)(uintptr)v;
767 waitpid(pid, &status, 0);
768 exited = 1;
769 // Synchronize with waitstop below.
770 pthread_mutex_lock(&mu);
771 pthread_cond_broadcast(&cond);
772 pthread_mutex_unlock(&mu);
773 return nil;
774 }
775
776 // Wait for thread t to stop.
777 static int
778 waitstop(Thread *t)
779 {
780 pthread_mutex_lock(&mu);
781 while(!exited && !threadstopped(t))
782 pthread_cond_wait(&cond, &mu);
783 pthread_mutex_unlock(&mu);
784 return 0;
785 }
786
787 int
788 ctlproc(int id, char *msg)
789 {
790 Thread *t;
791 int status;
792
793 // Hang/attached dance is for debugging newly exec'ed programs.
794 // After fork, the child does ctlproc("hang") before exec,
795 // and the parent does ctlproc("attached") and then waitstop.
796 // Using these requires the BSD ptrace interface, unlike everything
797 // else we do, which uses only the Mach interface. Our goal here
798 // is to do as little as possible using ptrace and then flip over to Mach.
799
800 if(strcmp(msg, "hang") == 0)
801 return ptrace(PT_TRACE_ME, 0, 0, 0);
802
803 if(strcmp(msg, "attached") == 0){
804 // The pid "id" has done a ctlproc "hang" and then
805 // exec, so we should find it stoppped just before exec
806 // of the new program.
807 #undef waitpid
808 if(waitpid(id, &status, WUNTRACED) < 0){
809 fprint(2, "ctlproc attached waitpid: %r\n");
810 return -1;
811 }
812 if(WIFEXITED(status) || !WIFSTOPPED(status)){
813 fprint(2, "ctlproc attached: bad process state\n");
814 return -1;
815 }
816
817 // Find Mach thread for pid and suspend it.
818 t = addpid(id, 1);
819 if(t == nil) {
820 fprint(2, "ctlproc attached: addpid: %r\n");
821 return -1;
822 }
823 if(me(thread_suspend(t->thread)) < 0){
824 fprint(2, "ctlproc attached: thread_suspend: %r\n");
825 return -1;
826 }
827
828 // Let ptrace tell the process to keep going:
829 // then ptrace is out of the way and we're back in Mach land.
830 if(ptrace(PT_CONTINUE, id, (caddr_t)1, 0) < 0) {
831 fprint(2, "ctlproc attached: ptrace continue: %r\n");
832 return -1;
833 }
834
835 return 0;
836 }
837
838 // All the other control messages require a Thread structure.
839 if((t = idtotable(id)) == nil){
840 werrstr("no such thread");
841 return -1;
842 }
843
844 if(strcmp(msg, "kill") == 0)
845 return ptrace(PT_KILL, t->pid, 0, 0);
846
847 if(strcmp(msg, "start") == 0)
848 return threadstart(t, 0);
849
850 if(strcmp(msg, "stop") == 0)
851 return threadstop(t);
852
853 if(strcmp(msg, "startstop") == 0){
854 if(threadstart(t, 0) < 0)
855 return -1;
856 return waitstop(t);
857 }
858
859 if(strcmp(msg, "step") == 0){
860 if(threadstart(t, 1) < 0)
861 return -1;
862 return waitstop(t);
863 }
864
865 if(strcmp(msg, "waitstop") == 0)
866 return waitstop(t);
867
868 // sysstop not available on OS X
869
870 werrstr("unknown control message");
871 return -1;
872 }
873
874 char*
875 procstatus(int id)
876 {
877 Thread *t;
878
879 if((t = idtotable(id)) == nil)
880 return "gone!";
881
882 if(threadstopped(t))
883 return "Stopped";
884
885 return "Running";
886 }
887