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