The Go Programming Language

Text file src/libmach/darwin.c

     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)&regs,
   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)&regs,
   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)&regs,
   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)&regs,
   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	

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.