예제 #1
0
static int
stacks_has_caller(stacks_entry_t *sep, uintptr_t addr)
{
	uintptr_t laddr = addr;
	uintptr_t haddr = addr + 1;
	int idx;
	char c[MDB_SYM_NAMLEN];
	GElf_Sym sym;

	if (mdb_lookup_by_addr(addr, MDB_SYM_FUZZY,
	    c, sizeof (c), &sym) != -1 &&
	    addr == (uintptr_t)sym.st_value) {
		laddr = (uintptr_t)sym.st_value;
		haddr = (uintptr_t)sym.st_value + sym.st_size;
	}

	for (idx = 0; idx < sep->se_depth; idx++)
		if (sep->se_stack[idx] >= laddr && sep->se_stack[idx] < haddr)
			return (1);

	return (0);
}
예제 #2
0
static int
fmd_timer(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
	char name[32], func[MDB_SYM_NAMLEN];
	fmd_timer_t t;

	if (!(flags & DCMD_ADDRSPEC)) {
		if (mdb_walk_dcmd("fmd_timerq", "fmd_timer", argc, argv) != 0) {
			mdb_warn("failed to walk fmd_timerq");
			return (DCMD_ERR);
		}
		return (DCMD_OK);
	}

	if (mdb_vread(&t, sizeof (t), addr) != sizeof (t)) {
		mdb_warn("failed to read fmd_timer at %p", addr);
		return (DCMD_ERR);
	}

	if (DCMD_HDRSPEC(flags)) {
		mdb_printf("%<u>%-8s %-20s %-4s %-18s %-8s %s%</u>\n",
		    "ADDR", "MODULE", "ID", "HRTIME", "ARG", "FUNC");
	}

	if (mdb_readstr(name, sizeof (name), (uintptr_t)
	    t.tmr_ids + OFFSETOF(fmd_idspace_t, ids_name)) <= 0)
		(void) mdb_snprintf(name, sizeof (name), "<%p>", t.tmr_ids);

	if (mdb_lookup_by_addr((uintptr_t)t.tmr_func, MDB_SYM_FUZZY,
	    func, sizeof (func), NULL) != 0)
		(void) mdb_snprintf(func, sizeof (func), "<%p>", t.tmr_func);

	mdb_printf("%-8p %-20s %4d 0x%-16llx %-8p %s\n",
	    addr, name, t.tmr_id, t.tmr_hrt, t.tmr_arg, func);
	return (DCMD_OK);
}
예제 #3
0
/*
 * This is used to both compare stacks for equality and to sort the final
 * list of unique stacks.  forsort specifies the latter behavior, which
 * additionally:
 *	compares se_count, and
 *	sorts the stacks by text function name.
 *
 * The equality test is independent of se_count, and doesn't care about
 * relative ordering, so we don't do the extra work of looking up symbols
 * for the stack addresses.
 */
int
stacks_entry_comp_impl(stacks_entry_t *l, stacks_entry_t *r,
    uint_t forsort)
{
	int idx;

	int depth = MIN(l->se_depth, r->se_depth);

	/* no matter what, panic stacks come last. */
	if (l->se_panic > r->se_panic)
		return (1);
	if (l->se_panic < r->se_panic)
		return (-1);

	if (forsort) {
		/* put large counts earlier */
		if (l->se_count > r->se_count)
			return (-1);
		if (l->se_count < r->se_count)
			return (1);
	}

	if (l->se_tstate > r->se_tstate)
		return (1);
	if (l->se_tstate < r->se_tstate)
		return (-1);

	if (l->se_failed > r->se_failed)
		return (1);
	if (l->se_failed < r->se_failed)
		return (-1);

	for (idx = 0; idx < depth; idx++) {
		char lbuf[MDB_SYM_NAMLEN];
		char rbuf[MDB_SYM_NAMLEN];

		int rval;
		uintptr_t laddr = l->se_stack[idx];
		uintptr_t raddr = r->se_stack[idx];

		if (laddr == raddr)
			continue;

		if (forsort &&
		    mdb_lookup_by_addr(laddr, MDB_SYM_FUZZY,
		    lbuf, sizeof (lbuf), NULL) != -1 &&
		    mdb_lookup_by_addr(raddr, MDB_SYM_FUZZY,
		    rbuf, sizeof (rbuf), NULL) != -1 &&
		    (rval = strcmp(lbuf, rbuf)) != 0)
			return (rval);

		if (laddr > raddr)
			return (1);
		return (-1);
	}

	if (l->se_overflow > r->se_overflow)
		return (-1);
	if (l->se_overflow < r->se_overflow)
		return (1);

	if (l->se_depth > r->se_depth)
		return (1);
	if (l->se_depth < r->se_depth)
		return (-1);

	if (l->se_sobj_ops > r->se_sobj_ops)
		return (1);
	if (l->se_sobj_ops < r->se_sobj_ops)
		return (-1);

	return (0);
}
예제 #4
0
파일: vfs.c 프로젝트: andreiw/polaris
/*
 * Utility routine to read in a filesystem name given a vfs pointer.  If
 * no vfssw entry for the vfs is available (as is the case with some pseudo-
 * filesystems), we check against some known problem fs's: doorfs and
 * portfs.  If that fails, we try to guess the filesystem name using
 * symbol names.  fsname should be a buffer of size _ST_FSTYPSZ.
 */
static int
read_fsname(uintptr_t vfsp, char *fsname)
{
	vfs_t vfs;
	struct vfssw vfssw_entry;
	GElf_Sym vfssw_sym, test_sym;
	char testname[MDB_SYM_NAMLEN];

	if (mdb_vread(&vfs, sizeof (vfs), vfsp) == -1) {
		mdb_warn("failed to read vfs %p", vfsp);
		return (-1);
	}

	if (mdb_lookup_by_name("vfssw", &vfssw_sym) == -1) {
		mdb_warn("failed to find vfssw");
		return (-1);
	}

	/*
	 * vfssw is an array; we need vfssw[vfs.vfs_fstype].
	 */
	if (mdb_vread(&vfssw_entry, sizeof (vfssw_entry),
	    vfssw_sym.st_value + (sizeof (struct vfssw) * vfs.vfs_fstype))
	    == -1) {
		mdb_warn("failed to read vfssw index %d", vfs.vfs_fstype);
		return (-1);
	}

	if (vfs.vfs_fstype != 0) {
		if (mdb_readstr(fsname, _ST_FSTYPSZ,
		    (uintptr_t)vfssw_entry.vsw_name) == -1) {
			mdb_warn("failed to find fs name %p",
			    vfssw_entry.vsw_name);
			return (-1);
		}
		return (0);
	}

	/*
	 * Do precise detection for certain filesystem types that we
	 * know do not appear in vfssw[], and that we depend upon in other
	 * parts of the code: doorfs and portfs.
	 */
	if (mdb_lookup_by_name("door_vfs", &test_sym) != -1) {
		if (test_sym.st_value == vfsp) {
			strcpy(fsname, "doorfs");
			return (0);
		}
	}
	if (mdb_lookup_by_name("port_vfs", &test_sym) != -1) {
		if (test_sym.st_value == vfsp) {
			strcpy(fsname, "portfs");
			return (0);
		}
	}

	/*
	 * Heuristic detection for other filesystems that don't have a
	 * vfssw[] entry.  These tend to be named <fsname>_vfs, so we do a
	 * lookup_by_addr and see if we find a symbol of that name.
	 */
	if (mdb_lookup_by_addr(vfsp, MDB_SYM_EXACT, testname, sizeof (testname),
	    &test_sym) != -1) {
		if ((strlen(testname) > 4) &&
		    (strcmp(testname + strlen(testname) - 4, "_vfs") == 0)) {
			testname[strlen(testname) - 4] = '\0';
			strncpy(fsname, testname, _ST_FSTYPSZ);
			return (0);
		}
	}

	mdb_warn("unknown filesystem type for vfs %p", vfsp);
	return (-1);
}
예제 #5
0
/*
 * Display selected fields of the flow_entry_t structure
 */
static int
mac_flow_dcmd_output(uintptr_t addr, uint_t flags, uint_t args)
{
	static const mdb_bitmask_t flow_type_bits[] = {
		{"P", FLOW_PRIMARY_MAC, FLOW_PRIMARY_MAC},
		{"V", FLOW_VNIC_MAC, FLOW_VNIC_MAC},
		{"M", FLOW_MCAST, FLOW_MCAST},
		{"O", FLOW_OTHER, FLOW_OTHER},
		{"U", FLOW_USER, FLOW_USER},
		{"V", FLOW_VNIC, FLOW_VNIC},
		{"NS", FLOW_NO_STATS, FLOW_NO_STATS},
		{ NULL, 0, 0 }
	};
#define	FLOW_MAX_TYPE	(sizeof (flow_type_bits) / sizeof (mdb_bitmask_t))

	static const mdb_bitmask_t flow_flag_bits[] = {
		{"Q", FE_QUIESCE, FE_QUIESCE},
		{"W", FE_WAITER, FE_WAITER},
		{"T", FE_FLOW_TAB, FE_FLOW_TAB},
		{"G", FE_G_FLOW_HASH, FE_G_FLOW_HASH},
		{"I", FE_INCIPIENT, FE_INCIPIENT},
		{"C", FE_CONDEMNED, FE_CONDEMNED},
		{"NU", FE_UF_NO_DATAPATH, FE_UF_NO_DATAPATH},
		{"NC", FE_MC_NO_DATAPATH, FE_MC_NO_DATAPATH},
		{ NULL, 0, 0 }
	};
#define	FLOW_MAX_FLAGS	(sizeof (flow_flag_bits) / sizeof (mdb_bitmask_t))
	flow_entry_t		fe;
	mac_client_impl_t	mcip;
	mac_impl_t		mip;

	if (mdb_vread(&fe, sizeof (fe), addr) == -1) {
		mdb_warn("failed to read struct flow_entry_s at %p", addr);
		return (DCMD_ERR);
	}
	if (args & MAC_FLOW_USER) {
		args &= ~MAC_FLOW_USER;
		if (fe.fe_type & FLOW_MCAST) {
			if (DCMD_HDRSPEC(flags))
				mac_flow_print_header(args);
			return (DCMD_OK);
		}
	}
	if (DCMD_HDRSPEC(flags))
		mac_flow_print_header(args);
	bzero(&mcip, sizeof (mcip));
	bzero(&mip, sizeof (mip));
	if (fe.fe_mcip != NULL && mdb_vread(&mcip, sizeof (mcip),
	    (uintptr_t)fe.fe_mcip) == sizeof (mcip)) {
		(void) mdb_vread(&mip, sizeof (mip), (uintptr_t)mcip.mci_mip);
	}
	switch (args) {
	case MAC_FLOW_NONE: {
		mdb_printf("%?p %-20s %4d %?p "
		    "%?p %-16s\n",
		    addr, fe.fe_flow_name, fe.fe_link_id, fe.fe_mcip,
		    mcip.mci_mip, mip.mi_name);
		break;
	}
	case MAC_FLOW_ATTR: {
		struct	in_addr	in4;
		uintptr_t	desc_addr;
		flow_desc_t	fdesc;

		desc_addr = addr + OFFSETOF(flow_entry_t, fe_flow_desc);
		if (mdb_vread(&fdesc, sizeof (fdesc), desc_addr) == -1) {
			mdb_warn("failed to read struct flow_description at %p",
			    desc_addr);
			return (DCMD_ERR);
		}
		mdb_printf("%?p %-32s "
		    "%-7s %6d "
		    "%4d:%-4d ",
		    addr, fe.fe_flow_name,
		    mac_flow_proto2str(fdesc.fd_protocol), fdesc.fd_local_port,
		    fdesc.fd_dsfield, fdesc.fd_dsfield_mask);
		if (fdesc.fd_ipversion == IPV4_VERSION) {
			IN6_V4MAPPED_TO_INADDR(&fdesc.fd_local_addr, &in4);
			mdb_printf("%I", in4.s_addr);
		} else if (fdesc.fd_ipversion == IPV6_VERSION) {
			mdb_printf("%N", &fdesc.fd_local_addr);
		} else {
			mdb_printf("%s", "--");
		}
		mdb_printf("\n");
		break;
	}
	case MAC_FLOW_PROP: {
		uintptr_t	prop_addr;
		char		bwstr[STRSIZE];
		mac_resource_props_t	fprop;

		prop_addr = addr + OFFSETOF(flow_entry_t, fe_resource_props);
		if (mdb_vread(&fprop, sizeof (fprop), prop_addr) == -1) {
			mdb_warn("failed to read struct mac_resoource_props "
			    "at %p", prop_addr);
			return (DCMD_ERR);
		}
		mdb_printf("%?p %-32s "
		    "%8s %9s\n",
		    addr, fe.fe_flow_name,
		    mac_flow_bw2str(fprop.mrp_maxbw, bwstr, STRSIZE),
		    mac_flow_priority2str(fprop.mrp_priority));
		break;
	}
	case MAC_FLOW_MISC: {
		char		flow_flags[2 * FLOW_MAX_FLAGS];
		char		flow_type[2 * FLOW_MAX_TYPE];
		GElf_Sym	sym;
		char		func_name[MDB_SYM_NAMLEN] = "";
		uintptr_t	func, match_addr;

		match_addr = addr + OFFSETOF(flow_entry_t, fe_match);
		(void) mdb_vread(&func, sizeof (func), match_addr);
		(void) mdb_lookup_by_addr(func, MDB_SYM_EXACT, func_name,
		    MDB_SYM_NAMLEN, &sym);
		mdb_snprintf(flow_flags, 2 * FLOW_MAX_FLAGS, "%hb",
		    fe.fe_flags, flow_flag_bits);
		mdb_snprintf(flow_type, 2 * FLOW_MAX_TYPE, "%hb",
		    fe.fe_type, flow_type_bits);
		mdb_printf("%?p %-24s %10s %10s %20s\n",
		    addr, fe.fe_flow_name, flow_type, flow_flags, func_name);
		break;
	}
	case MAC_FLOW_RX: {
		uintptr_t	rxaddr, rx_srs[MAX_RINGS_PER_GROUP] = {0};
		int		i;

		rxaddr = addr + OFFSETOF(flow_entry_t, fe_rx_srs);
		(void) mdb_vread(rx_srs, MAC_RX_SRS_SIZE, rxaddr);
		mdb_printf("%?p %-24s %3d ",
		    addr, fe.fe_flow_name, fe.fe_rx_srs_cnt);
		for (i = 0; i < MAX_RINGS_PER_GROUP; i++) {
			if (rx_srs[i] == 0)
				continue;
			mdb_printf("%p ", rx_srs[i]);
		}
		mdb_printf("\n");
		break;
	}
	case MAC_FLOW_TX: {
		uintptr_t	tx_srs = 0, txaddr;

		txaddr = addr + OFFSETOF(flow_entry_t, fe_tx_srs);
		(void) mdb_vread(&tx_srs, sizeof (uintptr_t), txaddr);
		mdb_printf("%?p %-32s %?p\n",
		    addr, fe.fe_flow_name, fe.fe_tx_srs);
		break;
	}
	case MAC_FLOW_STATS: {
		uint64_t		totibytes = 0;
		uint64_t		totobytes = 0;
		mac_soft_ring_set_t	*mac_srs;
		mac_rx_stats_t		mac_rx_stat;
		mac_tx_stats_t		mac_tx_stat;
		int			i;

		/*
		 * Sum bytes for all Rx SRS.
		 */
		for (i = 0; i < fe.fe_rx_srs_cnt; i++) {
			mac_srs = (mac_soft_ring_set_t *)(fe.fe_rx_srs[i]);
			if (mdb_vread(&mac_rx_stat, sizeof (mac_rx_stats_t),
			    (uintptr_t)&mac_srs->srs_rx.sr_stat) == -1) {
				mdb_warn("failed to read mac_rx_stats_t at %p",
				    &mac_srs->srs_rx.sr_stat);
				return (DCMD_ERR);
			}

			totibytes += mac_rx_stat.mrs_intrbytes +
			    mac_rx_stat.mrs_pollbytes +
			    mac_rx_stat.mrs_lclbytes;
		}

		/*
		 * Sum bytes for Tx SRS.
		 */
		mac_srs = (mac_soft_ring_set_t *)(fe.fe_tx_srs);
		if (mac_srs != NULL) {
			if (mdb_vread(&mac_tx_stat, sizeof (mac_tx_stats_t),
			    (uintptr_t)&mac_srs->srs_tx.st_stat) == -1) {
				mdb_warn("failed to read max_tx_stats_t at %p",
				    &mac_srs->srs_tx.st_stat);
				return (DCMD_ERR);
			}

			totobytes = mac_tx_stat.mts_obytes;
		}

		mdb_printf("%?p %-32s %16llu %16llu\n",
		    addr, fe.fe_flow_name, totibytes, totobytes);

		break;
	}
	}
	return (DCMD_OK);
}
예제 #6
0
int print_type_info(struct type_info *tinfo, long long offset, char *data)
{
	int btype;
	int ret;
	GElf_Sym sym;

	switch(tinfo->type) {
		case BASIC_TYPE :
			if (tinfo->info.btype.sign) {
				switch (tinfo->info.btype.size) {
					case 1 : my_printf("0x%x", (char)*data); return 1;
					case 2 : my_printf("0x%hx", *((short*)data)); return 2;
					case 4 : my_printf("0x%lx",*((int*)data)); return 4;
					case 8 : my_printf("0x%llx", *((long*)data)); return 8;
				}
			} else {
					switch (tinfo->info.btype.size) {
					case 1 : my_printf("0x%x", (unsigned char)*data); return 1;
					case 2 : my_printf("0x%hx", *((unsigned short*)data)); return 2;
					case 4 : my_printf("0x%lx",*((unsigned int*)data)); return 4;
					case 8 : my_printf("0x%llx", *((unsigned long*)data)); return 8;
				}
			}
		break;
		
	case FLOAT_TYPE :
		switch(tinfo->info.ftype.size) {
		case 4 : my_printf(" float "); return 4;
		case 8 : my_printf(" double "); return 8;
		}
		break;
		
	case EQUAL :
		return print_id(tinfo->id, offset, data);
		
	case POINTER :
		/* print strings for char data type else print %p */
		if (sizeof(void*) == 8) 
			my_printf("0x%llx", *((long*)data)); 
		else 
			my_printf("0x%x", *((long*)data)); 

		btype = base_type(tinfo->id); 
		if (btype == CHAR || btype == UCHAR) {
			if (*(long*)data == 0) return 8;
			memset(str, 0, MAX_STR_LEN);
			ret = mdb_readstr(str, MAX_STR_LEN, *((long*)data));
			if (ret <= 0) return 8;
			my_printf(" \"%s\"", str);
		}
		if (btype == TYPE_FUNCTION_PTR) 
		{
			memset(str, 0, MAX_STR_LEN);
			ret= mdb_lookup_by_addr(*(long*)data, MDB_SYM_EXACT, str,
				MAX_STR_LEN, &sym);
			if (ret != -1) my_printf("  \"%s\" ", str);
		}
		return 8;

		
	case ARRAY :
		return print_array(tinfo, offset, data);
		
	case FORWARD_REF :
		return print_id(tinfo->id, offset, data);
		
	default :
		my_printf("error");
	}
}
예제 #7
0
파일: ipp.c 프로젝트: andreiw/polaris
/*ARGSUSED*/
static int
ippops(
	uintptr_t	addr,
	uint_t		flags,
	int		argc,
	const mdb_arg_t	*argv)
{
	ipp_ops_t	*ippo;
	GElf_Sym	sym;
	char		buf[MDB_SYM_NAMLEN];

	if ((flags & DCMD_ADDRSPEC) == 0)
		return (DCMD_ERR);

	ippo = mdb_alloc(sizeof (ipp_ops_t), UM_SLEEP);
	if (mdb_vread(ippo, sizeof (ipp_ops_t), addr) == -1) {
		mdb_warn("failed to read ipp_ops_t at %p", addr);
		mdb_free(ippo, sizeof (ipp_ops_t));
		return (DCMD_ERR);
	}

	mdb_printf("%?p: %20s = %d\n", addr, "rev", ippo->ippo_rev);

	if (mdb_lookup_by_addr((uintptr_t)ippo->ippo_action_create,
	    MDB_SYM_EXACT, buf, MDB_SYM_NAMLEN, &sym) == 0)
		mdb_printf("%?s  %20s = %s\n", "", "action_create", buf);
	else
		mdb_printf("%?s  %20s = 0x%p\n", "", "action_create",
		    ippo->ippo_action_create);

	if (mdb_lookup_by_addr((uintptr_t)ippo->ippo_action_modify,
	    MDB_SYM_EXACT, buf, MDB_SYM_NAMLEN, &sym) == 0)
		mdb_printf("%?s  %20s = %s\n", "", "action_modify", buf);
	else
		mdb_printf("%?s  %20s = 0x%p\n", "", "action_modify",
		    ippo->ippo_action_modify);

	if (mdb_lookup_by_addr((uintptr_t)ippo->ippo_action_destroy,
	    MDB_SYM_EXACT, buf, MDB_SYM_NAMLEN, &sym) == 0)
		mdb_printf("%?s  %20s = %s\n", "", "action_destroy", buf);
	else
		mdb_printf("%?s  %20s = 0x%p\n", "", "action_destroy",
		    ippo->ippo_action_destroy);

	if (mdb_lookup_by_addr((uintptr_t)ippo->ippo_action_info,
	    MDB_SYM_EXACT, buf, MDB_SYM_NAMLEN, &sym) == 0)
		mdb_printf("%?s  %20s = %s\n", "", "action_info", buf);
	else
		mdb_printf("%?s  %20s = 0x%p\n", "", "action_info",
		    ippo->ippo_action_info);

	if (mdb_lookup_by_addr((uintptr_t)ippo->ippo_action_invoke,
	    MDB_SYM_EXACT, buf, MDB_SYM_NAMLEN, &sym) == 0)
		mdb_printf("%?s  %20s = %s\n", "", "action_invoke", buf);
	else
		mdb_printf("%?s  %20s = 0x%p\n", "", "action_invoke",
		    ippo->ippo_action_invoke);

	mdb_printf("\n");

	mdb_free(ippo, sizeof (ipp_ops_t));
	return (DCMD_OK);
}
예제 #8
0
파일: mdb_evset.c 프로젝트: andreiw/polaris
/*ARGSUSED*/
int
cmd_wp(uintptr_t x, uint_t flags, int argc, const mdb_arg_t *argv)
{
	mdb_tgt_addr_t addr = mdb_get_dot();
	char *opt_c = NULL;
	uint_t opt_i = FALSE;
	uint_t opt_l = FALSE;
	uint64_t opt_L = 0;
	uintptr_t opt_n = 0;
	uint_t opt_o = FALSE;
	uint_t opt_p = FALSE;
	uint_t opt_rwx = 0;
	int id;
	char buf[MDB_SYM_NAMLEN];
	GElf_Sym gsym;
	int size;

	if ((argv = ev_getopts(addr, flags, argc, argv, &flags, &opt_c, &opt_i,
	    &opt_l, &opt_L, &opt_n, &opt_o, &opt_p, &opt_rwx)) == NULL ||
	    opt_o || (opt_p && opt_i))
		return (DCMD_USAGE);

#ifndef _KMDB
	if (opt_i)
		return (DCMD_USAGE);
#endif

	if (argv->a_type != MDB_TYPE_IMMEDIATE)
		return (DCMD_USAGE);

	if (opt_rwx == 0) {
		mdb_warn("at least one of -r, -w, or -x must be specified\n");
		return (DCMD_USAGE);
	}

	if ((opt_l) + (opt_L > 0) + (mdb.m_dcount != 1) > 1) {
		mdb_warn("only one of -l, -L, or command count can be "
		    "specified\n");
		return (DCMD_ABORT);
	}

	if (opt_l) {
		if (mdb_lookup_by_addr(addr, MDB_SYM_EXACT, buf,
		    sizeof (buf), &gsym) == -1) {
			mdb_warn("failed to lookup symbol at %p", addr);
			return (DCMD_ERR);
		}

		if (gsym.st_size == 0) {
			mdb_warn("cannot set watchpoint: symbol '%s' has zero "
			    "size\n", buf);
			return (DCMD_ERR);
		}
		size = gsym.st_size;
	} else if (opt_L != 0) {
		size = opt_L;
	} else
		size = mdb.m_dcount;

	if (opt_p) {
		id = mdb_tgt_add_pwapt(mdb.m_target, addr, size, opt_rwx,
		    flags, cmd_event, NULL);
	} else if (opt_i) {
		id = mdb_tgt_add_iowapt(mdb.m_target, addr, size, opt_rwx,
		    flags, cmd_event, NULL);
	} else {
		id = mdb_tgt_add_vwapt(mdb.m_target, addr, size, opt_rwx,
		    flags, cmd_event, NULL);
	}

	if (id == 0) {
		mdb_warn("failed to set watchpoint at %p", addr);
		return ((opt_l || opt_L) ? DCMD_ERR : DCMD_ABORT);
	}

	if (opt_c || opt_n)
		ev_setopts(mdb.m_target, id, opt_c, opt_n);

	/*
	 * We use m_dcount as an argument; don't loop. We ignore this
	 * restriction with the -l and -L options, since we read the size from
	 * the symbol and don't rely on the count.
	 */
	return ((opt_l || opt_L) ? DCMD_OK : DCMD_ABORT);
}