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