xref: /illumos-gate/usr/src/cmd/mdb/common/mdb/mdb_evset.c (revision 4585130b)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <mdb/mdb_target.h>
28 #include <mdb/mdb_modapi.h>
29 #include <mdb/mdb_string.h>
30 #include <mdb/mdb.h>
31 
32 #include <libproc.h>
33 #include <string.h>
34 
35 /*ARGSUSED*/
36 void
cmd_event(mdb_tgt_t * t,int vid,void * s)37 cmd_event(mdb_tgt_t *t, int vid, void *s)
38 {
39 	if (s != NULL && mdb_eval(s) == -1)
40 		mdb_warn("failed to eval [ %d ] command \"%s\"", vid, s);
41 }
42 
43 int
cmd_evset(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)44 cmd_evset(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
45 {
46 	uint_t setb = 0, clrb = 0;
47 	const char *opt_c = NULL;
48 	uint_t opt_F = FALSE;
49 	uintptr_t opt_n = 0;
50 
51 	int *idv = mdb_zalloc(sizeof (int) * (argc + 1), UM_SLEEP | UM_GC);
52 	int idc = 0;
53 
54 	int status = DCMD_OK;
55 	const char *p;
56 	void *data;
57 	int argi;
58 
59 	if (flags & DCMD_ADDRSPEC)
60 		idv[idc++] = (int)(intptr_t)addr;
61 
62 	/*
63 	 * Perform an initial pass through argv: we accumulate integer ids into
64 	 * idv, and compute a group of bits to set and a group to clear.
65 	 */
66 	while (argc != 0 && (argi = mdb_getopts(argc, argv,
67 	    'c', MDB_OPT_STR, &opt_c,
68 	    'd', MDB_OPT_SETBITS, MDB_TGT_SPEC_AUTODIS, &setb,
69 	    'D', MDB_OPT_SETBITS, MDB_TGT_SPEC_AUTODEL, &setb,
70 	    'e', MDB_OPT_SETBITS, MDB_TGT_SPEC_DISABLED, &clrb,
71 	    'F', MDB_OPT_SETBITS, TRUE, &opt_F,
72 	    'n', MDB_OPT_UINTPTR, &opt_n,
73 	    's', MDB_OPT_SETBITS, MDB_TGT_SPEC_AUTOSTOP, &setb,
74 	    't', MDB_OPT_SETBITS, MDB_TGT_SPEC_TEMPORARY, &setb,
75 	    'T', MDB_OPT_SETBITS, MDB_TGT_SPEC_STICKY, &setb,
76 	    NULL)) != argc) {
77 
78 		argv += argi; /* advance past elements processed by getopts */
79 		argc -= argi; /* decrement argc by number of args processed */
80 
81 		if (argv->a_type == MDB_TYPE_STRING) {
82 			if (argv->a_un.a_str[0] == '+') {
83 				for (p = argv->a_un.a_str + 1; *p != '\0'; ) {
84 					switch (*p++) {
85 					case 'd':
86 						clrb |= MDB_TGT_SPEC_AUTODIS;
87 						break;
88 					case 'D':
89 						clrb |= MDB_TGT_SPEC_AUTODEL;
90 						break;
91 					case 'e':
92 						setb |= MDB_TGT_SPEC_DISABLED;
93 						break;
94 					case 's':
95 						clrb |= MDB_TGT_SPEC_AUTOSTOP;
96 						break;
97 					case 't':
98 						clrb |= MDB_TGT_SPEC_TEMPORARY;
99 						break;
100 					case 'T':
101 						clrb |= MDB_TGT_SPEC_STICKY;
102 						break;
103 					default:
104 						mdb_warn("illegal option -- "
105 						    "+%c\n", p[-1]);
106 						return (DCMD_USAGE);
107 					}
108 				}
109 			} else if (argv->a_un.a_str[0] != '-') {
110 				idv[idc++] = (int)(intmax_t)
111 				    mdb_strtonum(argv->a_un.a_str, 10);
112 			} else
113 				return (DCMD_USAGE);
114 		} else
115 			idv[idc++] = (int)(intmax_t)argv->a_un.a_val;
116 
117 		argc--;
118 		argv++;
119 	}
120 
121 	if (idc == 0) {
122 		mdb_warn("expected one or more event IDs to be specified\n");
123 		return (DCMD_USAGE);
124 	}
125 
126 	/*
127 	 * If -n was not specified, then -d means "disable now" instead of
128 	 * meaning "set auto-disable after n hits".
129 	 */
130 	if (opt_n == 0 && (setb & MDB_TGT_SPEC_AUTODIS))
131 		setb = (setb & ~MDB_TGT_SPEC_AUTODIS) | MDB_TGT_SPEC_DISABLED;
132 
133 	while (idc-- != 0) {
134 		mdb_tgt_spec_desc_t sp;
135 		int id = *idv++;
136 
137 		bzero(&sp, sizeof (mdb_tgt_spec_desc_t));
138 		(void) mdb_tgt_vespec_info(mdb.m_target, id, &sp, NULL, 0);
139 		data = sp.spec_data;
140 
141 		if (opt_F == FALSE && (sp.spec_flags & MDB_TGT_SPEC_HIDDEN)) {
142 			mdb_warn("cannot modify event %d: internal "
143 			    "debugger event\n", id);
144 			status = DCMD_ERR;
145 			continue;
146 		}
147 
148 		sp.spec_flags |= setb;
149 		sp.spec_flags &= ~clrb;
150 
151 		if (opt_c && !(sp.spec_flags & MDB_TGT_SPEC_HIDDEN)) {
152 			if (opt_c[0] != '\0')
153 				sp.spec_data = strdup(opt_c);
154 			else
155 				sp.spec_data = NULL;
156 		}
157 
158 		if (opt_n)
159 			sp.spec_limit = opt_n;
160 
161 		if (mdb_tgt_vespec_modify(mdb.m_target, id, sp.spec_flags,
162 		    sp.spec_limit, sp.spec_data) == -1) {
163 			mdb_warn("failed to modify event %d", id);
164 			data = sp.spec_data;
165 			status = DCMD_ERR;
166 		}
167 
168 		if (opt_c && data && !(sp.spec_flags & MDB_TGT_SPEC_HIDDEN))
169 			strfree(data);
170 	}
171 
172 	return (status);
173 }
174 
175 /*
176  * Utility routine for performing the stock argument processing that is common
177  * among the dcmds that create event specifiers.  We parse out the standard set
178  * of event property options from the command-line, and return a copy of the
179  * argument list to the caller that consists solely of the remaining non-option
180  * arguments.  If a parsing error occurs, NULL is returned.
181  */
182 static const mdb_arg_t *
ev_getopts(uintmax_t addr,uint_t flags,int argc,const mdb_arg_t * argv,uint_t * evflags,char ** opt_c,uint_t * opt_i,uint_t * opt_l,uint64_t * opt_L,uintptr_t * opt_n,uint_t * opt_o,uint_t * opt_p,uint_t * rwx)183 ev_getopts(uintmax_t addr, uint_t flags, int argc, const mdb_arg_t *argv,
184     uint_t *evflags, char **opt_c, uint_t *opt_i, uint_t *opt_l,
185     uint64_t *opt_L, uintptr_t *opt_n, uint_t *opt_o, uint_t *opt_p,
186     uint_t *rwx)
187 {
188 	uint_t setb = 0, clrb = 0;
189 	const char *p;
190 	int argi;
191 
192 	mdb_arg_t *av;
193 	int ac = 0;
194 
195 	/* keep lint happy */
196 	*opt_p = FALSE;
197 
198 	av = mdb_alloc(sizeof (mdb_arg_t) * (argc + 2), UM_SLEEP | UM_GC);
199 
200 	/*
201 	 * If an address was specified, take it as an additional immediate
202 	 * value argument by adding it to the argument list.
203 	 */
204 	if (flags & DCMD_ADDRSPEC) {
205 		av[ac].a_type = MDB_TYPE_IMMEDIATE;
206 		av[ac++].a_un.a_val = addr;
207 	}
208 
209 	/*
210 	 * Now call mdb_getopts repeatedly to parse the argument list.  We need
211 	 * to handle '+[a-z]' processing manually, and we also manually copy
212 	 * each non-option argument into the av[] array as we encounter them.
213 	 */
214 	while (argc != 0 && (argi = mdb_getopts(argc, argv,
215 	    'c', MDB_OPT_STR, opt_c,
216 	    'd', MDB_OPT_SETBITS, MDB_TGT_SPEC_AUTODIS, &setb,
217 	    'D', MDB_OPT_SETBITS, MDB_TGT_SPEC_AUTODEL, &setb,
218 	    'e', MDB_OPT_SETBITS, MDB_TGT_SPEC_DISABLED, &clrb,
219 	    'i', MDB_OPT_SETBITS, TRUE, opt_i,
220 	    'n', MDB_OPT_UINTPTR, opt_n,
221 	    'o', MDB_OPT_SETBITS, TRUE, opt_o,
222 #ifdef _KMDB
223 	    'p', MDB_OPT_SETBITS, TRUE, opt_p,
224 #endif
225 	    'r', MDB_OPT_SETBITS, MDB_TGT_WA_R, rwx,
226 	    's', MDB_OPT_SETBITS, MDB_TGT_SPEC_AUTOSTOP, &setb,
227 	    'l', MDB_OPT_SETBITS, TRUE, opt_l,
228 	    'L', MDB_OPT_UINT64, opt_L,
229 	    't', MDB_OPT_SETBITS, MDB_TGT_SPEC_TEMPORARY, &setb,
230 	    'T', MDB_OPT_SETBITS, MDB_TGT_SPEC_STICKY, &setb,
231 	    'w', MDB_OPT_SETBITS, MDB_TGT_WA_W, rwx,
232 	    'x', MDB_OPT_SETBITS, MDB_TGT_WA_X, rwx, NULL)) != argc) {
233 
234 		argv += argi; /* advance past elements processed by getopts */
235 		argc -= argi; /* decrement argc by number of args processed */
236 
237 		if (argv->a_type == MDB_TYPE_STRING) {
238 			if (argv->a_un.a_str[0] == '+') {
239 				for (p = argv->a_un.a_str + 1; *p != '\0'; ) {
240 					switch (*p++) {
241 					case 'd':
242 						clrb |= MDB_TGT_SPEC_AUTODIS;
243 						break;
244 					case 'D':
245 						clrb |= MDB_TGT_SPEC_AUTODEL;
246 						break;
247 					case 'e':
248 						setb |= MDB_TGT_SPEC_DISABLED;
249 						break;
250 					case 's':
251 						clrb |= MDB_TGT_SPEC_AUTOSTOP;
252 						break;
253 					case 't':
254 						clrb |= MDB_TGT_SPEC_TEMPORARY;
255 						break;
256 					case 'T':
257 						clrb |= MDB_TGT_SPEC_STICKY;
258 						break;
259 					default:
260 						mdb_warn("illegal option -- "
261 						    "+%c\n", p[-1]);
262 						return (NULL);
263 					}
264 				}
265 			} else if (argv->a_un.a_str[0] != '-') {
266 				av[ac++] = *argv;
267 			} else
268 				return (NULL);
269 		} else
270 			av[ac++] = *argv;
271 
272 		argc--;
273 		argv++;
274 	}
275 
276 	/*
277 	 * If no arguments were found on the command-line, return NULL to
278 	 * indicate that the caller should return DCMD_USAGE.
279 	 */
280 	if (ac == 0)
281 		return (NULL);
282 
283 	/*
284 	 * If -n was not specified, then -d means "disable now" instead of
285 	 * meaning "set auto-disable after n hits".
286 	 */
287 	if (opt_n == 0 && (setb & MDB_TGT_SPEC_AUTODIS))
288 		setb = (setb & ~MDB_TGT_SPEC_AUTODIS) | MDB_TGT_SPEC_DISABLED;
289 
290 	/*
291 	 * Return the final set of flags, and terminate the argument array
292 	 * with a NULL string argument.
293 	 */
294 	*evflags = setb & ~clrb;
295 
296 	av[ac].a_type = MDB_TYPE_STRING;
297 	av[ac].a_un.a_str = NULL;
298 
299 	return (av);
300 }
301 
302 /*
303  * Utility function for modifying the spec_data and spec_limit properties of an
304  * event specifier.  We use this for handling the -c and -n options below.
305  */
306 static void
ev_setopts(mdb_tgt_t * t,int id,const char * opt_c,uintptr_t opt_n)307 ev_setopts(mdb_tgt_t *t, int id, const char *opt_c, uintptr_t opt_n)
308 {
309 	mdb_tgt_spec_desc_t sp;
310 
311 	(void) mdb_tgt_vespec_info(t, id, &sp, NULL, 0);
312 
313 	if (opt_c != NULL)
314 		sp.spec_data = strdup(opt_c);
315 	if (opt_n != 0)
316 		sp.spec_limit = opt_n;
317 
318 	if (mdb_tgt_vespec_modify(t, id, sp.spec_flags,
319 	    sp.spec_limit, sp.spec_data) == -1) {
320 		mdb_warn("failed to modify event %d", id);
321 		if (opt_c != NULL)
322 			strfree(sp.spec_data);
323 	}
324 }
325 
326 int
cmd_bp(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)327 cmd_bp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
328 {
329 	char *opt_c = NULL;
330 	uint_t opt_i = FALSE;
331 	uint_t opt_l = FALSE;
332 	uint64_t opt_L = 0;
333 	uintptr_t opt_n = 0;
334 	uint_t opt_o = FALSE;
335 	uint_t opt_p = FALSE;
336 	uint_t opt_rwx = 0;
337 	int status = DCMD_OK;
338 	int id;
339 
340 	if ((argv = ev_getopts(addr, flags, argc, argv, &flags, &opt_c, &opt_i,
341 	    &opt_l, &opt_L, &opt_n, &opt_o, &opt_p, &opt_rwx)) == NULL ||
342 	    opt_i || opt_o || opt_rwx != 0 || opt_l || opt_L != 0 || opt_p)
343 		return (DCMD_USAGE);
344 
345 	while (argv->a_type != MDB_TYPE_STRING || argv->a_un.a_str != NULL) {
346 		if (argv->a_type == MDB_TYPE_STRING) {
347 			id = mdb_tgt_add_sbrkpt(mdb.m_target, argv->a_un.a_str,
348 			    flags, cmd_event, NULL);
349 		} else {
350 			id = mdb_tgt_add_vbrkpt(mdb.m_target, argv->a_un.a_val,
351 			    flags, cmd_event, NULL);
352 		}
353 
354 		if (id == 0) {
355 			mdb_warn("failed to add breakpoint at %s",
356 			    argv->a_type == MDB_TYPE_STRING ? argv->a_un.a_str :
357 			    numtostr(argv->a_un.a_val, mdb.m_radix,
358 			    NTOS_UNSIGNED | NTOS_SHOWBASE));
359 			status = DCMD_ERR;
360 
361 		} else if (opt_c || opt_n)
362 			ev_setopts(mdb.m_target, id, opt_c, opt_n);
363 
364 		argv++;
365 	}
366 
367 	return (status);
368 }
369 
370 
371 int
cmd_sigbp(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)372 cmd_sigbp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
373 {
374 	char *opt_c = NULL;
375 	uint_t opt_i = FALSE;
376 	uint_t opt_l = FALSE;
377 	uint64_t opt_L = 0;
378 	uintptr_t opt_n = 0;
379 	uint_t opt_o = FALSE;
380 	uint_t opt_p = FALSE;
381 	uint_t opt_rwx = 0;
382 	int status = DCMD_OK;
383 	int id, sig;
384 
385 	if ((argv = ev_getopts(addr, flags, argc, argv, &flags, &opt_c, &opt_i,
386 	    &opt_l, &opt_L, &opt_n, &opt_o, &opt_p, &opt_rwx)) == NULL ||
387 	    opt_i || opt_l || opt_L != 0 || opt_o || opt_p || opt_rwx != 0)
388 		return (DCMD_USAGE);
389 
390 	while (argv->a_type != MDB_TYPE_STRING || argv->a_un.a_str != NULL) {
391 		if (argv->a_type == MDB_TYPE_STRING) {
392 			if (proc_str2sig(argv->a_un.a_str, &sig) == -1) {
393 				mdb_warn("invalid signal name -- %s\n",
394 				    argv->a_un.a_str);
395 				status = DCMD_ERR;
396 				argv++;
397 				continue;
398 			}
399 		} else
400 			sig = (int)(intmax_t)argv->a_un.a_val;
401 
402 		if ((id = mdb_tgt_add_signal(mdb.m_target, sig, flags,
403 		    cmd_event, NULL)) == 0) {
404 			mdb_warn("failed to trace signal %d", sig);
405 			status = DCMD_ERR;
406 		} else if (opt_c || opt_n)
407 			ev_setopts(mdb.m_target, id, opt_c, opt_n);
408 
409 		argv++;
410 	}
411 
412 	return (status);
413 }
414 
415 int
cmd_sysbp(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)416 cmd_sysbp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
417 {
418 	char *opt_c = NULL;
419 	uint_t opt_i = FALSE;
420 	uint_t opt_l = FALSE;
421 	uint64_t opt_L = 0;
422 	uintptr_t opt_n = 0;
423 	uint_t opt_o = FALSE;
424 	uint_t opt_p = FALSE;
425 	uint_t opt_rwx = 0;
426 	int status = DCMD_OK;
427 	int id, sysnum;
428 
429 	if ((argv = ev_getopts(addr, flags, argc, argv, &flags, &opt_c, &opt_i,
430 	    &opt_l, &opt_L, &opt_n, &opt_o, &opt_p, &opt_rwx)) == NULL ||
431 	    (opt_i && opt_o) || opt_l || opt_L != 0 || opt_p || opt_rwx != 0)
432 		return (DCMD_USAGE);
433 
434 	while (argv->a_type != MDB_TYPE_STRING || argv->a_un.a_str != NULL) {
435 		if (argv->a_type == MDB_TYPE_STRING) {
436 			if (proc_str2sys(argv->a_un.a_str, &sysnum) == -1) {
437 				mdb_warn("invalid system call name -- %s\n",
438 				    argv->a_un.a_str);
439 				status = DCMD_ERR;
440 				argv++;
441 				continue;
442 			}
443 		} else
444 			sysnum = (int)(intmax_t)argv->a_un.a_val;
445 
446 		if (opt_o) {
447 			id = mdb_tgt_add_sysexit(mdb.m_target, sysnum,
448 			    flags, cmd_event, NULL);
449 		} else {
450 			id = mdb_tgt_add_sysenter(mdb.m_target, sysnum,
451 			    flags, cmd_event, NULL);
452 		}
453 
454 		if (id == 0) {
455 			mdb_warn("failed to trace system call %d", sysnum);
456 			status = DCMD_ERR;
457 		} else if (opt_c || opt_n)
458 			ev_setopts(mdb.m_target, id, opt_c, opt_n);
459 
460 		argv++;
461 	}
462 
463 	return (status);
464 }
465 
466 int
cmd_fltbp(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)467 cmd_fltbp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
468 {
469 	char *opt_c = NULL;
470 	uint_t opt_i = FALSE;
471 	uint_t opt_l = FALSE;
472 	uint64_t opt_L = 0;
473 	uintptr_t opt_n = 0;
474 	uint_t opt_o = FALSE;
475 	uint_t opt_p = FALSE;
476 	uint_t opt_rwx = 0;
477 	int status = DCMD_OK;
478 	int id, fltnum;
479 
480 	if ((argv = ev_getopts(addr, flags, argc, argv, &flags, &opt_c,
481 	    &opt_i, &opt_l, &opt_L, &opt_n, &opt_o, &opt_p,
482 	    &opt_rwx)) == NULL || opt_i || opt_l || opt_L != 0 || opt_o ||
483 	    opt_p || opt_rwx != 0)
484 		return (DCMD_USAGE);
485 
486 	while (argv->a_type != MDB_TYPE_STRING || argv->a_un.a_str != NULL) {
487 		if (argv->a_type == MDB_TYPE_STRING) {
488 			if (proc_str2flt(argv->a_un.a_str, &fltnum) == -1) {
489 				mdb_warn("invalid fault name -- %s\n",
490 				    argv->a_un.a_str);
491 				status = DCMD_ERR;
492 				argv++;
493 				continue;
494 			}
495 		} else
496 			fltnum = (int)(intmax_t)argv->a_un.a_val;
497 
498 		id = mdb_tgt_add_fault(mdb.m_target, fltnum,
499 		    flags, cmd_event, NULL);
500 
501 		if (id == 0) {
502 			mdb_warn("failed to trace fault %d", fltnum);
503 			status = DCMD_ERR;
504 		} else if (opt_c || opt_n)
505 			ev_setopts(mdb.m_target, id, opt_c, opt_n);
506 
507 		argv++;
508 	}
509 
510 	return (status);
511 }
512 
513 /*ARGSUSED*/
514 int
cmd_wp(uintptr_t x,uint_t flags,int argc,const mdb_arg_t * argv)515 cmd_wp(uintptr_t x, uint_t flags, int argc, const mdb_arg_t *argv)
516 {
517 	mdb_tgt_addr_t addr = mdb_get_dot();
518 	char *opt_c = NULL;
519 	uint_t opt_i = FALSE;
520 	uint_t opt_l = FALSE;
521 	uint64_t opt_L = 0;
522 	uintptr_t opt_n = 0;
523 	uint_t opt_o = FALSE;
524 	uint_t opt_p = FALSE;
525 	uint_t opt_rwx = 0;
526 	int id;
527 	char buf[MDB_SYM_NAMLEN];
528 	GElf_Sym gsym;
529 	int size;
530 
531 	if ((argv = ev_getopts(addr, flags, argc, argv, &flags, &opt_c, &opt_i,
532 	    &opt_l, &opt_L, &opt_n, &opt_o, &opt_p, &opt_rwx)) == NULL ||
533 	    opt_o || (opt_p && opt_i))
534 		return (DCMD_USAGE);
535 
536 #ifndef _KMDB
537 	if (opt_i)
538 		return (DCMD_USAGE);
539 #endif
540 
541 	if (argv->a_type != MDB_TYPE_IMMEDIATE)
542 		return (DCMD_USAGE);
543 
544 	if (opt_rwx == 0) {
545 		mdb_warn("at least one of -r, -w, or -x must be specified\n");
546 		return (DCMD_USAGE);
547 	}
548 
549 	if ((opt_l) + (opt_L > 0) + (mdb.m_dcount != 1) > 1) {
550 		mdb_warn("only one of -l, -L, or command count can be "
551 		    "specified\n");
552 		return (DCMD_ABORT);
553 	}
554 
555 	if (opt_l) {
556 		if (mdb_lookup_by_addr(addr, MDB_SYM_EXACT, buf,
557 		    sizeof (buf), &gsym) == -1) {
558 			mdb_warn("failed to lookup symbol at %p", addr);
559 			return (DCMD_ERR);
560 		}
561 
562 		if (gsym.st_size == 0) {
563 			mdb_warn("cannot set watchpoint: symbol '%s' has zero "
564 			    "size\n", buf);
565 			return (DCMD_ERR);
566 		}
567 		size = gsym.st_size;
568 	} else if (opt_L != 0) {
569 		size = opt_L;
570 	} else
571 		size = mdb.m_dcount;
572 
573 	if (opt_p) {
574 		id = mdb_tgt_add_pwapt(mdb.m_target, addr, size, opt_rwx,
575 		    flags, cmd_event, NULL);
576 	} else if (opt_i) {
577 		id = mdb_tgt_add_iowapt(mdb.m_target, addr, size, opt_rwx,
578 		    flags, cmd_event, NULL);
579 	} else {
580 		id = mdb_tgt_add_vwapt(mdb.m_target, addr, size, opt_rwx,
581 		    flags, cmd_event, NULL);
582 	}
583 
584 	if (id == 0) {
585 		mdb_warn("failed to set watchpoint at %p", addr);
586 		return ((opt_l || opt_L) ? DCMD_ERR : DCMD_ABORT);
587 	}
588 
589 	if (opt_c || opt_n)
590 		ev_setopts(mdb.m_target, id, opt_c, opt_n);
591 
592 	/*
593 	 * We use m_dcount as an argument; don't loop. We ignore this
594 	 * restriction with the -l and -L options, since we read the size from
595 	 * the symbol and don't rely on the count.
596 	 */
597 	return ((opt_l || opt_L) ? DCMD_OK : DCMD_ABORT);
598 }
599 
600 /*ARGSUSED*/
601 int
cmd_oldbp(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)602 cmd_oldbp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
603 {
604 	char *s = mdb_argv_to_str(argc, argv);
605 
606 	if (mdb_tgt_add_vbrkpt(mdb.m_target, addr, 0, cmd_event, s) == 0) {
607 		mdb_warn("failed to add breakpoint");
608 		if (s != NULL)
609 			strfree(s);
610 		return (DCMD_ERR);
611 	}
612 
613 	return (DCMD_OK);
614 }
615 
616 /*ARGSUSED*/
617 static int
oldwp(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv,uint_t rwx)618 oldwp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv, uint_t rwx)
619 {
620 	char *s = mdb_argv_to_str(argc, argv);
621 
622 	if (mdb_tgt_add_vwapt(mdb.m_target, addr, mdb.m_dcount, rwx, 0,
623 	    cmd_event, s) == 0) {
624 		mdb_warn("failed to add watchpoint");
625 		if (s != NULL)
626 			strfree(s);
627 		return (DCMD_ABORT);
628 	}
629 
630 	return (DCMD_ABORT); /* we use m_dcount as an argument; don't loop */
631 }
632 
633 int
cmd_oldwpr(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)634 cmd_oldwpr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
635 {
636 	return (oldwp(addr, flags, argc, argv, MDB_TGT_WA_R));
637 }
638 
639 int
cmd_oldwpw(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)640 cmd_oldwpw(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
641 {
642 	return (oldwp(addr, flags, argc, argv, MDB_TGT_WA_W));
643 }
644 
645 int
cmd_oldwpx(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)646 cmd_oldwpx(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
647 {
648 	return (oldwp(addr, flags, argc, argv, MDB_TGT_WA_X));
649 }
650 
651 static const char _evset_help[] =
652 "+/-d     disable specifier when hit count reaches limit (+d to unset);\n"
653 "         if -n is not present with -d, specifier is disabled immediately\n\n"
654 "+/-D     delete specifier when hit count reaches limit (+D to unset);\n"
655 "+/-e     enable specifier (+e or -d to disable)\n"
656 "+/-s     stop target when hit count reaches limit (+s to unset)\n"
657 "+/-t     delete specifier the next time the target stops (+t to unset)\n"
658 "+/-T     sticky bit: ::delete all will not remove specifier (+T to unset)\n\n"
659 "-c cmd   execute \"cmd\" each time the corresponding event occurs\n"
660 "-n count set limit for -D, -d, or -s to \"count\" (default 1)\n\n";
661 
662 void
bp_help(void)663 bp_help(void)
664 {
665 	mdb_printf(_evset_help);
666 	mdb_printf("addr     set breakpoint at specified virtual address\n");
667 	mdb_printf("sym      set deferred breakpoint at specified symbol\n");
668 }
669 
670 void
evset_help(void)671 evset_help(void)
672 {
673 	mdb_printf(_evset_help);
674 	mdb_printf("addr/id  set properties of specified event ids\n");
675 }
676 
677 void
fltbp_help(void)678 fltbp_help(void)
679 {
680 	mdb_printf(_evset_help);
681 	mdb_printf("flt      fault name (see <sys/fault.h>) or number\n");
682 }
683 
684 void
sigbp_help(void)685 sigbp_help(void)
686 {
687 	mdb_printf(_evset_help);
688 	mdb_printf("SIG      signal name (see signal(3HEAD)) or number\n");
689 }
690 
691 void
sysbp_help(void)692 sysbp_help(void)
693 {
694 	mdb_printf(_evset_help);
695 	mdb_printf("-i       trace system call on entry into kernel (default)\n"
696 	    "-o       trace system call on exit from kernel\n\n"
697 	    "syscall  system call name (see <sys/syscall.h>) or number\n");
698 }
699 
700 void
wp_help(void)701 wp_help(void)
702 {
703 	mdb_printf(_evset_help);
704 	mdb_printf(
705 #ifdef _KMDB
706 	    "-p       treat addr as a physical address\n"
707 	    "-i       treat addr as an I/O port address\n"
708 #endif
709 	    "-l       use size of addr's type for watched region\n"
710 	    "-L size  set size of watched region (default 1)\n"
711 	    "-r       trace read access to watched region\n"
712 	    "-w       trace write access to watched region\n"
713 	    "-x       trace execute access to watched region\n\n"
714 	    "addr     address for base of watched region\n"
715 	    "repeat   size of watched region (equivalent to -L)\n");
716 }
717