add: if (c == '\0' && intuple) break;
context: dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,    uintptr_t arg2, uintptr_t arg3, uintptr_t arg4){	processorid_t cpuid;	dtrace_icookie_t cookie;	dtrace_probe_t *probe;	dtrace_mstate_t mstate;	dtrace_ecb_t *ecb;	dtrace_action_t *act;	intptr_t offs;	size_t size;	int vtime, onintr;	volatile uint16_t *flags;	hrtime_t now;	/*	 * Kick out immediately if this CPU is still being born (in which case	 * curthread will be set to -1)	 */	if ((uintptr_t)curthread & 1)		return;	cookie = dtrace_interrupt_disable();	probe = dtrace_probes[id - 1];	cpuid = CPU->cpu_id;	onintr = CPU_ON_INTR(CPU);	if (!onintr && probe->dtpr_predcache != DTRACE_CACHEIDNONE &&	    probe->dtpr_predcache == curthread->t_predcache) {		/*		 * We have hit in the predicate cache; we know that		 * this predicate would evaluate to be false.		 */		dtrace_interrupt_enable(cookie);		return;	}	if (panic_quiesce) {		/*		 * We don't trace anything if we're panicking.		 */		dtrace_interrupt_enable(cookie);		return;	}	now = dtrace_gethrtime();	vtime = dtrace_vtime_references != 0;	if (vtime && curthread->t_dtrace_start)		curthread->t_dtrace_vtime += now - curthread->t_dtrace_start;	mstate.dtms_probe = probe;	mstate.dtms_arg[0] = arg0;	mstate.dtms_arg[1] = arg1;	mstate.dtms_arg[2] = arg2;	mstate.dtms_arg[3] = arg3;	mstate.dtms_arg[4] = arg4;	flags = (volatile uint16_t *)&cpu_core[cpuid].cpuc_dtrace_flags;	for (ecb = probe->dtpr_ecb; ecb != NULL; ecb = ecb->dte_next) {		dtrace_predicate_t *pred = ecb->dte_predicate;		dtrace_state_t *state = ecb->dte_state;		dtrace_buffer_t *buf = &state->dts_buffer[cpuid];		dtrace_buffer_t *aggbuf = &state->dts_aggbuffer[cpuid];		dtrace_vstate_t *vstate = &state->dts_vstate;		dtrace_provider_t *prov = probe->dtpr_provider;		int committed = 0;		caddr_t tomax;		/*		 * A little subtlety with the following (seemingly innocuous)		 * declaration of the automatic 'val':  by looking at the		 * code, you might think that it could be declared in the		 * action processing loop, below.  (That is, it's only used in		 * the action processing loop.)  However, it must be declared		 * out of that scope because in the case of DIF expression		 * arguments to aggregating actions, one iteration of the		 * action loop will use the last iteration's value.		 */#ifdef lint		uint64_t val = 0;#else		uint64_t val;#endif		mstate.dtms_present = DTRACE_MSTATE_ARGS | DTRACE_MSTATE_PROBE;		*flags &= ~CPU_DTRACE_ERROR;		if (prov == dtrace_provider) {			/*			 * If dtrace itself is the provider of this probe,			 * we're only going to continue processing the ECB if			 * arg0 (the dtrace_state_t) is equal to the ECB's			 * creating state.  (This prevents disjoint consumers			 * from seeing one another's metaprobes.)			 */			if (arg0 != (uint64_t)(uintptr_t)state)				continue;		}		if (state->dts_activity != DTRACE_ACTIVITY_ACTIVE) {			/*			 * We're not currently active.  If our provider isn't			 * the dtrace pseudo provider, we're not interested.			 */			if (prov != dtrace_provider)				continue;			/*			 * Now we must further check if we are in the BEGIN			 * probe.  If we are, we will only continue processing			 * if we're still in WARMUP -- if one BEGIN enabling			 * has invoked the exit() action, we don't want to			 * evaluate subsequent BEGIN enablings.			 */			if (probe->dtpr_id == dtrace_probeid_begin &&			    state->dts_activity != DTRACE_ACTIVITY_WARMUP) {				ASSERT(state->dts_activity ==				    DTRACE_ACTIVITY_DRAINING);				continue;			}		}		if (ecb->dte_cond) {			/*			 * If the dte_cond bits indicate that this			 * consumer is only allowed to see user-mode firings			 * of this probe, call the provider's dtps_usermode()			 * entry point to check that the probe was fired			 * while in a user context. Skip this ECB if that's			 * not the case.			 */			if ((ecb->dte_cond & DTRACE_COND_USERMODE) &&			    prov->dtpv_pops.dtps_usermode(prov->dtpv_arg,			    probe->dtpr_id, probe->dtpr_arg) == 0)				continue;			/*			 * This is more subtle than it looks. We have to be			 * absolutely certain that CRED() isn't going to			 * change out from under us so it's only legit to			 * examine that structure if we're in constrained			 * situations. Currently, the only times we'll this			 * check is if a non-super-user has enabled the			 * profile or syscall providers -- providers that			 * allow visibility of all processes. For the			 * profile case, the check above will ensure that			 * we're examining a user context.			 */			if (ecb->dte_cond & DTRACE_COND_OWNER) {				uid_t uid = ecb->dte_state->dts_cred.dcr_uid;				gid_t gid = ecb->dte_state->dts_cred.dcr_gid;				cred_t *cr;				proc_t *proc;				if ((cr = CRED()) == NULL ||				    uid != cr->cr_uid ||				    uid != cr->cr_ruid ||				    uid != cr->cr_suid ||				    gid != cr->cr_gid ||				    gid != cr->cr_rgid ||				    gid != cr->cr_sgid ||				    (proc = ttoproc(curthread)) == NULL ||				    (proc->p_flag & SNOCD))					continue;			}		}		if (now - state->dts_alive > dtrace_deadman_timeout) {			/*			 * We seem to be dead.  Unless we (a) have kernel			 * destructive permissions (b) have expicitly enabled			 * destructive actions and (c) destructive actions have			 * not been disabled, we're going to transition into			 * the KILLED state, from which no further processing			 * on this state will be performed.			 */			if (!dtrace_priv_kernel_destructive(state) ||			    !state->dts_cred.dcr_destructive ||			    dtrace_destructive_disallow) {				void *activity = &state->dts_activity;				dtrace_activity_t current;				do {					current = state->dts_activity;				} while (dtrace_cas32(activity, current,				    DTRACE_ACTIVITY_KILLED) != current);				continue;			}		}		if ((offs = dtrace_buffer_reserve(buf, ecb->dte_needed,		    ecb->dte_alignment, state, &mstate)) < 0)			continue;		tomax = buf->dtb_tomax;		ASSERT(tomax != NULL);		if (ecb->dte_size != 0)			DTRACE_STORE(uint32_t, tomax, offs, ecb->dte_epid);		mstate.dtms_epid = ecb->dte_epid;		mstate.dtms_present |= DTRACE_MSTATE_EPID;		if (pred != NULL) {			dtrace_difo_t *dp = pred->dtp_difo;			int rval;			rval = dtrace_dif_emulate(dp, &mstate, vstate, state);			if (!(*flags & CPU_DTRACE_ERROR) && !rval) {				dtrace_cacheid_t cid = probe->dtpr_predcache;				if (cid != DTRACE_CACHEIDNONE && !onintr) {					/*					 * Update the predicate cache...					 */					ASSERT(cid == pred->dtp_cacheid);					curthread->t_predcache = cid;				}				continue;			}		}		for (act = ecb->dte_action; !(*flags & CPU_DTRACE_ERROR) &&		    act != NULL; act = act->dta_next) {			size_t valoffs;			dtrace_difo_t *dp;			dtrace_recdesc_t *rec = &act->dta_rec;			size = rec->dtrd_size;			valoffs = offs + rec->dtrd_offset;			if (DTRACEACT_ISAGG(act->dta_kind)) {				uint64_t v = 0xbad;				dtrace_aggregation_t *agg;				agg = (dtrace_aggregation_t *)act;				if ((dp = act->dta_difo) != NULL)					v = dtrace_dif_emulate(dp,					    &mstate, vstate, state);				if (*flags & CPU_DTRACE_ERROR)					continue;				/*				 * Note that we always pass the expression				 * value from the previous iteration of the				 * action loop.  This value will only be used				 * if there is an expression argument to the				 * aggregating action, denoted by the				 * dtag_hasarg field.				 */				dtrace_aggregate(agg, buf,				    offs, aggbuf, v, val);				continue;			}			switch (act->dta_kind) {			case DTRACEACT_STOP:				if (dtrace_priv_proc_destructive(state))					dtrace_action_stop();				continue;			case DTRACEACT_BREAKPOINT:				if (dtrace_priv_kernel_destructive(state))					dtrace_action_breakpoint(ecb);				continue;			case DTRACEACT_PANIC:				if (dtrace_priv_kernel_destructive(state))					dtrace_action_panic(ecb);				continue;			case DTRACEACT_STACK:				if (!dtrace_priv_kernel(state))					continue;				dtrace_getpcstack((pc_t *)(tomax + valoffs),				    size / sizeof (pc_t), probe->dtpr_aframes,				    DTRACE_ANCHORED(probe) ? NULL :				    (uint32_t *)arg0);				continue;			case DTRACEACT_JSTACK:			case DTRACEACT_USTACK:				if (!dtrace_priv_proc(state))					continue;				/*				 * See comment in DIF_VAR_PID.				 */				if (DTRACE_ANCHORED(mstate.dtms_probe) &&				    CPU_ON_INTR(CPU)) {					int depth = DTRACE_USTACK_NFRAMES(					    rec->dtrd_arg) + 1;					dtrace_bzero((void *)(tomax + valoffs),					    DTRACE_USTACK_STRSIZE(rec->dtrd_arg)					    + depth * sizeof (uint64_t));					continue;				}				if (DTRACE_USTACK_STRSIZE(rec->dtrd_arg) != 0 &&				    curproc->p_dtrace_helpers != NULL) {					/*					 * This is the slow path -- we have					 * allocated string space, and we're					 * getting the stack of a process that					 * has helpers.  Call into a separate					 * routine to perform this processing.					 */					dtrace_action_ustack(&mstate, state,					    (uint64_t *)(tomax + valoffs),					    rec->dtrd_arg);					continue;				}				DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);				dtrace_getupcstack((uint64_t *)				    (tomax + valoffs),				    DTRACE_USTACK_NFRAMES(rec->dtrd_arg) + 1);				DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);				continue;			default:				break;			}			dp = act->dta_difo;			ASSERT(dp != NULL);			val = dtrace_dif_emulate(dp, &mstate, vstate, state);			if (*flags & CPU_DTRACE_ERROR)				continue;			switch (act->dta_kind) {			case DTRACEACT_SPECULATE:				ASSERT(buf == &state->dts_buffer[cpuid]);				buf = dtrace_speculation_buffer(state,				    cpuid, val);				if (buf == NULL) {					*flags |= CPU_DTRACE_DROP;					continue;				}				offs = dtrace_buffer_reserve(buf,				    ecb->dte_needed, ecb->dte_alignment,				    state, NULL);				if (offs < 0) {					*flags |= CPU_DTRACE_DROP;					continue;				}				tomax = buf->dtb_tomax;				ASSERT(tomax != NULL);				if (ecb->dte_size != 0)					DTRACE_STORE(uint32_t, tomax, offs,					    ecb->dte_epid);				continue;			case DTRACEACT_CHILL:				if (dtrace_priv_kernel_destructive(state))					dtrace_action_chill(&mstate, val);				continue;			case DTRACEACT_RAISE:				if (dtrace_priv_proc_destructive(state))					dtrace_action_raise(val);				continue;			case DTRACEACT_COMMIT:				ASSERT(!committed);				/*				 * We need to commit our buffer state.				 */				if (ecb->dte_size)					buf->dtb_offset = offs + ecb->dte_size;				buf = &state->dts_buffer[cpuid];				dtrace_speculation_commit(state, cpuid, val);				committed = 1;				continue;			case DTRACEACT_DISCARD:				dtrace_speculation_discard(state, cpuid, val);				continue;			case DTRACEACT_DIFEXPR:			case DTRACEACT_LIBACT:			case DTRACEACT_PRINTF:			case DTRACEACT_PRINTA:			case DTRACEACT_SYSTEM:			case DTRACEACT_FREOPEN:				break;			case DTRACEACT_SYM:			case DTRACEACT_MOD:				if (!dtrace_priv_kernel(state))					continue;				break;			case DTRACEACT_USYM:			case DTRACEACT_UMOD:			case DTRACEACT_UADDR: {				struct pid *pid = curthread->t_procp->p_pidp;				if (!dtrace_priv_proc(state))					continue;				DTRACE_STORE(uint64_t, tomax,				    valoffs, (uint64_t)pid->pid_id);				DTRACE_STORE(uint64_t, tomax,				    valoffs + sizeof (uint64_t), val);				continue;			}			case DTRACEACT_EXIT: {				/*				 * For the exit action, we are going to attempt				 * to atomically set our activity to be				 * draining.  If this fails (either because				 * another CPU has beat us to the exit action,				 * or because our current activity is something				 * other than ACTIVE or WARMUP), we will				 * continue.  This assures that the exit action				 * can be successfully recorded at most once				 * when we're in the ACTIVE state.  If we're				 * encountering the exit() action while in				 * COOLDOWN, however, we want to honor the new				 * status code.  (We know that we're the only				 * thread in COOLDOWN, so there is no race.)				 */				void *activity = &state->dts_activity;				dtrace_activity_t current = state->dts_activity;				if (current == DTRACE_ACTIVITY_COOLDOWN)					break;				if (current != DTRACE_ACTIVITY_WARMUP)					current = DTRACE_ACTIVITY_ACTIVE;				if (dtrace_cas32(activity, current,				    DTRACE_ACTIVITY_DRAINING) != current) {					*flags |= CPU_DTRACE_DROP;					continue;				}				break;			}			default:				ASSERT(0);			}			if (dp->dtdo_rtype.dtdt_flags & DIF_TF_BYREF) {				uintptr_t end = valoffs + size;				/*				 * If this is a string, we're going to only				 * load until we find the zero byte -- after				 * which we'll store zero bytes.				 */				if (dp->dtdo_rtype.dtdt_kind ==				    DIF_TYPE_STRING) {					char c = '\0' + 1;					size_t s;					for (s = 0; s < size; s++) {						if (c != '\0')							c = dtrace_load8(val++);						DTRACE_STORE(uint8_t, tomax,						    valoffs++, c);					}					continue;				}				while (valoffs < end) {					DTRACE_STORE(uint8_t, tomax, valoffs++,					    dtrace_load8(val++));				}				continue;			}			switch (size) {			case 0:				break;			case sizeof (uint8_t):				DTRACE_STORE(uint8_t, tomax, valoffs, val);				break;			case sizeof (uint16_t):				DTRACE_STORE(uint16_t, tomax, valoffs, val);				break;			case sizeof (uint32_t):				DTRACE_STORE(uint32_t, tomax, valoffs, val);				break;			case sizeof (uint64_t):				DTRACE_STORE(uint64_t, tomax, valoffs, val);				break;			default:				/*				 * Any other size should have been returned by				 * reference, not by value.				 */				ASSERT(0);				break;			}		}		if (*flags & CPU_DTRACE_DROP)			continue;		if (*flags & CPU_DTRACE_FAULT) {			int ndx;			dtrace_action_t *err;			buf->dtb_errors++;			if (probe->dtpr_id == dtrace_probeid_error) {				/*				 * There's nothing we can do -- we had an				 * error on the error probe.  We bump an				 * error counter to at least indicate that				 * this condition happened.				 */				dtrace_error(&state->dts_dblerrors);				continue;			}			if (vtime) {				/*				 * Before recursing on dtrace_probe(), we				 * need to explicitly clear out our start				 * time to prevent it from being accumulated				 * into t_dtrace_vtime.				 */				curthread->t_dtrace_start = 0;			}			/*			 * Iterate over the actions to figure out which action			 * we were processing when we experienced the error.			 * Note that act points _past_ the faulting action; if			 * act is ecb->dte_action, the fault was in the			 * predicate, if it's ecb->dte_action->dta_next it's			 * in action #1, and so on.			 */			for (err = ecb->dte_action, ndx = 0;			    err != act; err = err->dta_next, ndx++)				continue;			dtrace_probe_error(state, ecb->dte_epid, ndx,			    (mstate.dtms_present & DTRACE_MSTATE_FLTOFFS) ?			    mstate.dtms_fltoffs : -1, DTRACE_FLAGS2FLT(*flags),			    cpu_core[cpuid].cpuc_dtrace_illval);			continue;		}		if (!committed)			buf->dtb_offset = offs + ecb->dte_size;	}	if (vtime)		curthread->t_dtrace_start = dtrace_gethrtime();	dtrace_interrupt_enable(cookie);}