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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25 /*
26 * Copyright (c) 2012 by Delphix. All rights reserved.
27 * Copyright 2021 Joyent, Inc.
28 */
29
30 /*
31 * Modular Debugger (MDB)
32 *
33 * Refer to the white paper "A Modular Debugger for Solaris" for information
34 * on the design, features, and goals of MDB. See /shared/sac/PSARC/1999/169
35 * for copies of the paper and related documentation.
36 *
37 * This file provides the basic construction and destruction of the debugger's
38 * global state, as well as the main execution loop, mdb_run(). MDB maintains
39 * a stack of execution frames (mdb_frame_t's) that keep track of its current
40 * state, including a stack of input and output buffers, walk and memory
41 * garbage collect lists, and a list of commands (mdb_cmd_t's). As the
42 * parser consumes input, it fills in a list of commands to execute, and then
43 * invokes mdb_call(), below. A command consists of a dcmd, telling us
44 * what function to execute, and a list of arguments and other invocation-
45 * specific data. Each frame may have more than one command, kept on a list,
46 * when multiple commands are separated by | operators. New frames may be
47 * stacked on old ones by nested calls to mdb_run: this occurs when, for
48 * example, in the middle of processing one input source (such as a file
49 * or the terminal), we invoke a dcmd that in turn calls mdb_eval(). mdb_eval
50 * will construct a new frame whose input source is the string passed to
51 * the eval function, and then execute this frame to completion.
52 */
53
54 #include <sys/param.h>
55 #include <stropts.h>
56
57 #define _MDB_PRIVATE
58 #include <mdb/mdb.h>
59
60 #include <mdb/mdb_context.h>
61 #include <mdb/mdb_argvec.h>
62 #include <mdb/mdb_signal.h>
63 #include <mdb/mdb_macalias.h>
64 #include <mdb/mdb_module.h>
65 #include <mdb/mdb_modapi.h>
66 #include <mdb/mdb_string.h>
67 #include <mdb/mdb_callb.h>
68 #include <mdb/mdb_debug.h>
69 #include <mdb/mdb_frame.h>
70 #include <mdb/mdb_conf.h>
71 #include <mdb/mdb_err.h>
72 #include <mdb/mdb_lex.h>
73 #include <mdb/mdb_io.h>
74 #include <mdb/mdb_ctf.h>
75 #ifdef _KMDB
76 #include <kmdb/kmdb_module.h>
77 #endif
78
79 /*
80 * Macro for testing if a dcmd's return status (x) indicates that we should
81 * abort the current loop or pipeline.
82 */
83 #define DCMD_ABORTED(x) ((x) == DCMD_USAGE || (x) == DCMD_ABORT)
84
85 extern const mdb_dcmd_t mdb_dcmd_builtins[];
86 extern const mdb_walker_t mdb_walker_builtins[];
87 extern mdb_dis_ctor_f *const mdb_dis_builtins[];
88
89 /*
90 * Variable discipline for toggling MDB_FL_PSYM based on the value of the
91 * undocumented '_' variable. Once adb(1) has been removed from the system,
92 * we should just remove this functionality and always disable PSYM for macros.
93 */
94 static uintmax_t
psym_disc_get(const mdb_var_t * v)95 psym_disc_get(const mdb_var_t *v)
96 {
97 int i = (mdb.m_flags & MDB_FL_PSYM) ? 1 : 0;
98 int j = (MDB_NV_VALUE(v) != 0) ? 1 : 0;
99
100 if ((i ^ j) == 0)
101 MDB_NV_VALUE((mdb_var_t *)v) = j ^ 1;
102
103 return (MDB_NV_VALUE(v));
104 }
105
106 static void
psym_disc_set(mdb_var_t * v,uintmax_t value)107 psym_disc_set(mdb_var_t *v, uintmax_t value)
108 {
109 if (value == 0)
110 mdb.m_flags |= MDB_FL_PSYM;
111 else
112 mdb.m_flags &= ~MDB_FL_PSYM;
113
114 MDB_NV_VALUE(v) = value;
115 }
116
117 /*
118 * Variable discipline for making <1 (most recent offset) behave properly.
119 */
120 static uintmax_t
roff_disc_get(const mdb_var_t * v)121 roff_disc_get(const mdb_var_t *v)
122 {
123 return (MDB_NV_VALUE(v));
124 }
125
126 static void
roff_disc_set(mdb_var_t * v,uintmax_t value)127 roff_disc_set(mdb_var_t *v, uintmax_t value)
128 {
129 mdb_nv_set_value(mdb.m_proffset, MDB_NV_VALUE(v));
130 MDB_NV_VALUE(v) = value;
131 }
132
133 /*
134 * Variable discipline for exporting the representative thread.
135 */
136 static uintmax_t
thr_disc_get(const mdb_var_t * v)137 thr_disc_get(const mdb_var_t *v)
138 {
139 mdb_tgt_status_t s;
140
141 if (mdb.m_target != NULL && mdb_tgt_status(mdb.m_target, &s) == 0)
142 return (s.st_tid);
143
144 return (MDB_NV_VALUE(v));
145 }
146
147 const char **
mdb_path_alloc(const char * s,size_t * newlen)148 mdb_path_alloc(const char *s, size_t *newlen)
149 {
150 char *format = mdb_alloc(strlen(s) * 2 + 1, UM_NOSLEEP);
151 const char **path;
152 char *p, *q;
153
154 struct utsname uts;
155 size_t len;
156 int i;
157
158 mdb_arg_t arg_i, arg_m, arg_p, arg_r, arg_t, arg_R, arg_V;
159 mdb_argvec_t argv;
160
161 static const char *empty_path[] = { NULL };
162
163 if (format == NULL)
164 goto nomem;
165
166 while (*s == ':')
167 s++; /* strip leading delimiters */
168
169 if (*s == '\0') {
170 *newlen = 0;
171 return (empty_path);
172 }
173
174 (void) strcpy(format, s);
175 mdb_argvec_create(&argv);
176
177 /*
178 * %i embedded in path string expands to ISA.
179 */
180 arg_i.a_type = MDB_TYPE_STRING;
181 if (mdb.m_target != NULL)
182 arg_i.a_un.a_str = mdb_tgt_isa(mdb.m_target);
183 else
184 arg_i.a_un.a_str = mdb_conf_isa();
185
186 /*
187 * %p embedded in path string expands to the platform name.
188 */
189 arg_p.a_type = MDB_TYPE_STRING;
190 if (mdb.m_target != NULL)
191 arg_p.a_un.a_str = mdb_tgt_platform(mdb.m_target);
192 else
193 arg_p.a_un.a_str = mdb_conf_platform();
194
195 /*
196 * %r embedded in path string expands to root directory, or
197 * to the empty string if root is "/" (to avoid // in paths).
198 */
199 arg_r.a_type = MDB_TYPE_STRING;
200 arg_r.a_un.a_str = strcmp(mdb.m_root, "/") ? mdb.m_root : "";
201
202 /*
203 * %t embedded in path string expands to the target name, defaulting to
204 * kvm; this is so we can find mdb_kb, which is used during bootstrap.
205 */
206 arg_t.a_type = MDB_TYPE_STRING;
207 arg_t.a_un.a_str = mdb.m_target ? mdb_tgt_name(mdb.m_target) : "kvm";
208
209 /*
210 * %R and %V expand to uname -r (release) and uname -v (version).
211 */
212 if (mdb.m_target == NULL || mdb_tgt_uname(mdb.m_target, &uts) < 0)
213 mdb_conf_uname(&uts);
214
215 arg_m.a_type = MDB_TYPE_STRING;
216 arg_m.a_un.a_str = uts.machine;
217
218 arg_R.a_type = MDB_TYPE_STRING;
219 arg_R.a_un.a_str = uts.release;
220
221 arg_V.a_type = MDB_TYPE_STRING;
222 if (mdb.m_flags & MDB_FL_LATEST)
223 arg_V.a_un.a_str = "latest";
224 else
225 arg_V.a_un.a_str = uts.version;
226
227 /*
228 * In order to expand the buffer, we examine the format string for
229 * our % tokens and construct an argvec, replacing each % token
230 * with %s along the way. If we encounter an unknown token, we
231 * shift over the remaining format buffer and stick in %%.
232 */
233 for (q = format; (q = strchr(q, '%')) != NULL; q++) {
234 switch (q[1]) {
235 case 'i':
236 mdb_argvec_append(&argv, &arg_i);
237 *++q = 's';
238 break;
239 case 'm':
240 mdb_argvec_append(&argv, &arg_m);
241 *++q = 's';
242 break;
243 case 'p':
244 mdb_argvec_append(&argv, &arg_p);
245 *++q = 's';
246 break;
247 case 'r':
248 mdb_argvec_append(&argv, &arg_r);
249 *++q = 's';
250 break;
251 case 't':
252 mdb_argvec_append(&argv, &arg_t);
253 *++q = 's';
254 break;
255 case 'R':
256 mdb_argvec_append(&argv, &arg_R);
257 *++q = 's';
258 break;
259 case 'V':
260 mdb_argvec_append(&argv, &arg_V);
261 *++q = 's';
262 break;
263 default:
264 bcopy(q + 1, q + 2, strlen(q));
265 *++q = '%';
266 }
267 }
268
269 /*
270 * We're now ready to use our printf engine to format the final string.
271 * Take one lap with a NULL buffer to determine how long the final
272 * string will be, allocate it, and format it.
273 */
274 len = mdb_iob_asnprintf(NULL, 0, format, argv.a_data);
275 if ((p = mdb_alloc(len + 1, UM_NOSLEEP)) != NULL)
276 (void) mdb_iob_asnprintf(p, len + 1, format, argv.a_data);
277 else
278 goto nomem;
279
280 mdb_argvec_zero(&argv);
281 mdb_argvec_destroy(&argv);
282
283 mdb_free(format, strlen(s) * 2 + 1);
284 format = NULL;
285
286 /*
287 * Compress the string to exclude any leading delimiters.
288 */
289 for (q = p; *q == ':'; q++)
290 continue;
291 if (q != p)
292 bcopy(q, p, strlen(q) + 1);
293
294 /*
295 * Count up the number of delimited elements. A sequence of
296 * consecutive delimiters is only counted once.
297 */
298 for (i = 1, q = p; (q = strchr(q, ':')) != NULL; i++) {
299 while (*q == ':')
300 q++;
301 }
302
303 if ((path = mdb_alloc(sizeof (char *) * (i + 1), UM_NOSLEEP)) == NULL) {
304 mdb_free(p, len + 1);
305 goto nomem;
306 }
307
308 for (i = 0, q = strtok(p, ":"); q != NULL; q = strtok(NULL, ":"))
309 path[i++] = q;
310
311 path[i] = NULL;
312 *newlen = len + 1;
313 return (path);
314
315 nomem:
316 warn("failed to allocate memory for path");
317 if (format != NULL)
318 mdb_free(format, strlen(s) * 2 + 1);
319 *newlen = 0;
320 return (empty_path);
321 }
322
323 const char **
mdb_path_dup(const char * path[],size_t pathlen,size_t * npathlenp)324 mdb_path_dup(const char *path[], size_t pathlen, size_t *npathlenp)
325 {
326 char **npath;
327 int i, j;
328
329 for (i = 0; path[i] != NULL; i++)
330 continue; /* count the path elements */
331
332 npath = mdb_zalloc(sizeof (char *) * (i + 1), UM_SLEEP);
333 if (pathlen > 0) {
334 npath[0] = mdb_alloc(pathlen, UM_SLEEP);
335 bcopy(path[0], npath[0], pathlen);
336 }
337
338 for (j = 1; j < i; j++)
339 npath[j] = npath[0] + (path[j] - path[0]);
340 npath[i] = NULL;
341
342 *npathlenp = pathlen;
343 return ((const char **)npath);
344 }
345
346 void
mdb_path_free(const char * path[],size_t pathlen)347 mdb_path_free(const char *path[], size_t pathlen)
348 {
349 int i;
350
351 for (i = 0; path[i] != NULL; i++)
352 continue; /* count the path elements */
353
354 if (i > 0) {
355 mdb_free((void *)path[0], pathlen);
356 mdb_free(path, sizeof (char *) * (i + 1));
357 }
358 }
359
360 /*
361 * Convert path string "s" to canonical form, expanding any %o tokens that are
362 * found within the path. The old path string is specified by "path", a buffer
363 * of size MAXPATHLEN which is then overwritten with the new path string.
364 */
365 static const char *
path_canon(char * path,const char * s)366 path_canon(char *path, const char *s)
367 {
368 char *p = path;
369 char *q = p + MAXPATHLEN - 1;
370
371 char old[MAXPATHLEN];
372 char c;
373
374 (void) strcpy(old, p);
375 *q = '\0';
376
377 while (p < q && (c = *s++) != '\0') {
378 if (c == '%') {
379 if ((c = *s++) == 'o') {
380 (void) strncpy(p, old, (size_t)(q - p));
381 p += strlen(p);
382 } else {
383 *p++ = '%';
384 if (p < q && c != '\0')
385 *p++ = c;
386 else
387 break;
388 }
389 } else
390 *p++ = c;
391 }
392
393 *p = '\0';
394 return (path);
395 }
396
397 void
mdb_set_ipath(const char * path)398 mdb_set_ipath(const char *path)
399 {
400 if (mdb.m_ipath != NULL)
401 mdb_path_free(mdb.m_ipath, mdb.m_ipathlen);
402
403 path = path_canon(mdb.m_ipathstr, path);
404 mdb.m_ipath = mdb_path_alloc(path, &mdb.m_ipathlen);
405 }
406
407 void
mdb_set_lpath(const char * path)408 mdb_set_lpath(const char *path)
409 {
410 if (mdb.m_lpath != NULL)
411 mdb_path_free(mdb.m_lpath, mdb.m_lpathlen);
412
413 path = path_canon(mdb.m_lpathstr, path);
414 mdb.m_lpath = mdb_path_alloc(path, &mdb.m_lpathlen);
415
416 #ifdef _KMDB
417 kmdb_module_path_set(mdb.m_lpath, mdb.m_lpathlen);
418 #endif
419 }
420
421 static void
prompt_update(void)422 prompt_update(void)
423 {
424 (void) mdb_snprintf(mdb.m_prompt, sizeof (mdb.m_prompt),
425 mdb.m_promptraw);
426 mdb.m_promptlen = strlen(mdb.m_prompt);
427 }
428
429 const char *
mdb_get_prompt(void)430 mdb_get_prompt(void)
431 {
432 if (mdb.m_promptlen == 0)
433 return (NULL);
434 else
435 return (mdb.m_prompt);
436 }
437
438 int
mdb_set_prompt(const char * p)439 mdb_set_prompt(const char *p)
440 {
441 size_t len = strlen(p);
442
443 if (len > MDB_PROMPTLEN) {
444 warn("prompt may not exceed %d characters\n", MDB_PROMPTLEN);
445 return (0);
446 }
447
448 (void) strcpy(mdb.m_promptraw, p);
449 prompt_update();
450 return (1);
451 }
452
453 static mdb_frame_t frame0;
454
455 void
mdb_create(const char * execname,const char * arg0)456 mdb_create(const char *execname, const char *arg0)
457 {
458 static const mdb_nv_disc_t psym_disc = {
459 .disc_set = psym_disc_set,
460 .disc_get = psym_disc_get
461 };
462 static const mdb_nv_disc_t roff_disc = {
463 .disc_set = roff_disc_set,
464 .disc_get = roff_disc_get
465 };
466 static const mdb_nv_disc_t thr_disc = { .disc_get = thr_disc_get };
467
468 static char rootdir[MAXPATHLEN];
469
470 const mdb_dcmd_t *dcp;
471 const mdb_walker_t *wcp;
472 int i;
473
474 bzero(&mdb, sizeof (mdb_t));
475
476 mdb.m_flags = MDB_FL_PSYM | MDB_FL_PAGER | MDB_FL_BPTNOSYMSTOP |
477 MDB_FL_READBACK;
478 mdb.m_radix = MDB_DEF_RADIX;
479 mdb.m_nargs = MDB_DEF_NARGS;
480 mdb.m_histlen = MDB_DEF_HISTLEN;
481 mdb.m_armemlim = MDB_DEF_ARRMEM;
482 mdb.m_arstrlim = MDB_DEF_ARRSTR;
483
484 mdb.m_pname = strbasename(arg0);
485 if (strcmp(mdb.m_pname, "adb") == 0) {
486 mdb.m_flags |= MDB_FL_NOMODS | MDB_FL_ADB | MDB_FL_REPLAST;
487 mdb.m_flags &= ~MDB_FL_PAGER;
488 }
489
490 mdb.m_ipathstr = mdb_zalloc(MAXPATHLEN, UM_SLEEP);
491 mdb.m_lpathstr = mdb_zalloc(MAXPATHLEN, UM_SLEEP);
492
493 (void) strncpy(rootdir, execname, sizeof (rootdir));
494 rootdir[sizeof (rootdir) - 1] = '\0';
495 (void) strdirname(rootdir);
496
497 if (strcmp(strbasename(rootdir), "sparcv9") == 0 ||
498 strcmp(strbasename(rootdir), "sparcv7") == 0 ||
499 strcmp(strbasename(rootdir), "amd64") == 0 ||
500 strcmp(strbasename(rootdir), "i86") == 0)
501 (void) strdirname(rootdir);
502
503 if (strcmp(strbasename(rootdir), "bin") == 0) {
504 (void) strdirname(rootdir);
505 if (strcmp(strbasename(rootdir), "usr") == 0)
506 (void) strdirname(rootdir);
507 } else
508 (void) strcpy(rootdir, "/");
509
510 mdb.m_root = rootdir;
511
512 mdb.m_rminfo.mi_dvers = MDB_API_VERSION;
513 mdb.m_rminfo.mi_dcmds = mdb_dcmd_builtins;
514 mdb.m_rminfo.mi_walkers = mdb_walker_builtins;
515
516 (void) mdb_nv_create(&mdb.m_rmod.mod_walkers, UM_SLEEP);
517 (void) mdb_nv_create(&mdb.m_rmod.mod_dcmds, UM_SLEEP);
518
519 mdb.m_rmod.mod_name = mdb.m_pname;
520 mdb.m_rmod.mod_info = &mdb.m_rminfo;
521
522 (void) mdb_nv_create(&mdb.m_disasms, UM_SLEEP);
523 (void) mdb_nv_create(&mdb.m_modules, UM_SLEEP);
524 (void) mdb_nv_create(&mdb.m_dcmds, UM_SLEEP);
525 (void) mdb_nv_create(&mdb.m_walkers, UM_SLEEP);
526 (void) mdb_nv_create(&mdb.m_nv, UM_SLEEP);
527
528 mdb.m_dot = mdb_nv_insert(&mdb.m_nv, ".", NULL, 0, MDB_NV_PERSIST);
529 mdb.m_rvalue = mdb_nv_insert(&mdb.m_nv, "0", NULL, 0, MDB_NV_PERSIST);
530
531 mdb.m_roffset =
532 mdb_nv_insert(&mdb.m_nv, "1", &roff_disc, 0, MDB_NV_PERSIST);
533
534 mdb.m_proffset = mdb_nv_insert(&mdb.m_nv, "2", NULL, 0, MDB_NV_PERSIST);
535 mdb.m_rcount = mdb_nv_insert(&mdb.m_nv, "9", NULL, 0, MDB_NV_PERSIST);
536
537 (void) mdb_nv_insert(&mdb.m_nv, "b", NULL, 0, MDB_NV_PERSIST);
538 (void) mdb_nv_insert(&mdb.m_nv, "d", NULL, 0, MDB_NV_PERSIST);
539 (void) mdb_nv_insert(&mdb.m_nv, "e", NULL, 0, MDB_NV_PERSIST);
540 (void) mdb_nv_insert(&mdb.m_nv, "m", NULL, 0, MDB_NV_PERSIST);
541 (void) mdb_nv_insert(&mdb.m_nv, "t", NULL, 0, MDB_NV_PERSIST);
542 (void) mdb_nv_insert(&mdb.m_nv, "_", &psym_disc, 0, MDB_NV_PERSIST);
543 (void) mdb_nv_insert(&mdb.m_nv, "hits", NULL, 0, MDB_NV_PERSIST);
544
545 (void) mdb_nv_insert(&mdb.m_nv, "thread", &thr_disc, 0,
546 MDB_NV_PERSIST | MDB_NV_RDONLY);
547
548 mdb.m_prsym = mdb_gelf_symtab_create_mutable();
549
550 (void) mdb_nv_insert(&mdb.m_modules, mdb.m_pname, NULL,
551 (uintptr_t)&mdb.m_rmod, MDB_NV_RDONLY);
552
553 for (dcp = &mdb_dcmd_builtins[0]; dcp->dc_name != NULL; dcp++)
554 (void) mdb_module_add_dcmd(&mdb.m_rmod, dcp, 0);
555
556 for (wcp = &mdb_walker_builtins[0]; wcp->walk_name != NULL; wcp++)
557 (void) mdb_module_add_walker(&mdb.m_rmod, wcp, 0);
558
559 for (i = 0; mdb_dis_builtins[i] != NULL; i++)
560 (void) mdb_dis_create(mdb_dis_builtins[i]);
561
562 mdb_macalias_create();
563
564 mdb_create_builtin_tgts();
565
566 (void) mdb_callb_add(NULL, MDB_CALLB_PROMPT, (mdb_callb_f)prompt_update,
567 NULL);
568
569 /*
570 * The call to ctf_create that this does can in fact fail, but that's
571 * okay. All of the ctf functions that might use the synthetic types
572 * make sure that this is safe.
573 */
574 (void) mdb_ctf_synthetics_init();
575
576 #ifdef _KMDB
577 (void) mdb_nv_create(&mdb.m_dmodctl, UM_SLEEP);
578 #endif
579 mdb_lex_state_create(&frame0);
580
581 mdb_list_append(&mdb.m_flist, &frame0);
582 mdb.m_frame = &frame0;
583 }
584
585 void
mdb_destroy(void)586 mdb_destroy(void)
587 {
588 const mdb_dcmd_t *dcp;
589 mdb_var_t *v;
590 int unload_mode = MDB_MOD_SILENT;
591
592 #ifdef _KMDB
593 unload_mode |= MDB_MOD_DEFER;
594 #endif
595
596 mdb_intr_disable();
597
598 mdb_ctf_synthetics_fini();
599
600 mdb_macalias_destroy();
601
602 /*
603 * Some targets use modules during ->t_destroy, so do it first.
604 */
605 if (mdb.m_target != NULL)
606 (void) mdb_tgt_destroy(mdb.m_target);
607
608 /*
609 * Unload modules _before_ destroying the disassemblers since a
610 * module that installs a disassembler should try to clean up after
611 * itself.
612 */
613 mdb_module_unload_all(unload_mode);
614
615 mdb_nv_rewind(&mdb.m_disasms);
616 while ((v = mdb_nv_advance(&mdb.m_disasms)) != NULL)
617 mdb_dis_destroy(mdb_nv_get_cookie(v));
618
619 mdb_callb_remove_all();
620
621 if (mdb.m_defdisasm != NULL)
622 strfree(mdb.m_defdisasm);
623
624 if (mdb.m_prsym != NULL)
625 mdb_gelf_symtab_destroy(mdb.m_prsym);
626
627 for (dcp = &mdb_dcmd_builtins[0]; dcp->dc_name != NULL; dcp++)
628 (void) mdb_module_remove_dcmd(&mdb.m_rmod, dcp->dc_name);
629
630 mdb_nv_destroy(&mdb.m_nv);
631 mdb_nv_destroy(&mdb.m_walkers);
632 mdb_nv_destroy(&mdb.m_dcmds);
633 mdb_nv_destroy(&mdb.m_modules);
634 mdb_nv_destroy(&mdb.m_disasms);
635
636 mdb_free(mdb.m_ipathstr, MAXPATHLEN);
637 mdb_free(mdb.m_lpathstr, MAXPATHLEN);
638
639 if (mdb.m_ipath != NULL)
640 mdb_path_free(mdb.m_ipath, mdb.m_ipathlen);
641
642 if (mdb.m_lpath != NULL)
643 mdb_path_free(mdb.m_lpath, mdb.m_lpathlen);
644
645 if (mdb.m_in != NULL)
646 mdb_iob_destroy(mdb.m_in);
647
648 mdb_iob_destroy(mdb.m_out);
649 mdb.m_out = NULL;
650 mdb_iob_destroy(mdb.m_err);
651 mdb.m_err = NULL;
652
653 if (mdb.m_log != NULL)
654 mdb_io_rele(mdb.m_log);
655
656 mdb_lex_state_destroy(&frame0);
657 }
658
659 /*
660 * The real main loop of the debugger: create a new execution frame on the
661 * debugger stack, and while we have input available, call into the parser.
662 */
663 int
mdb_run(void)664 mdb_run(void)
665 {
666 volatile int err;
667 mdb_frame_t f;
668
669 mdb_intr_disable();
670 mdb_frame_push(&f);
671
672 /*
673 * This is a fresh mdb context, so ignore any pipe command we may have
674 * inherited from the previous frame.
675 */
676 f.f_pcmd = NULL;
677
678 if ((err = setjmp(f.f_pcb)) != 0) {
679 int pop = (mdb.m_in != NULL &&
680 (mdb_iob_isapipe(mdb.m_in) || mdb_iob_isastr(mdb.m_in)));
681 int fromcmd = (f.f_cp != NULL);
682
683 mdb_dprintf(MDB_DBG_DSTK, "frame <%u> caught event %s\n",
684 f.f_id, mdb_err2str(err));
685
686 /*
687 * If a syntax error or other failure has occurred, pop all
688 * input buffers pushed by commands executed in this frame.
689 */
690 while (mdb_iob_stack_size(&f.f_istk) != 0) {
691 if (mdb.m_in != NULL)
692 mdb_iob_destroy(mdb.m_in);
693 mdb.m_in = mdb_iob_stack_pop(&f.f_istk);
694 yylineno = mdb_iob_lineno(mdb.m_in);
695 }
696
697 /*
698 * Reset standard output and the current frame to a known,
699 * clean state, so we can continue execution.
700 */
701 mdb_iob_margin(mdb.m_out, MDB_IOB_DEFMARGIN);
702 mdb_iob_clrflags(mdb.m_out, MDB_IOB_INDENT);
703 mdb_iob_discard(mdb.m_out);
704 mdb_frame_reset(&f);
705
706 /*
707 * If there was an error writing to output, display a warning
708 * message if this is the topmost frame.
709 */
710 if (err == MDB_ERR_OUTPUT && mdb.m_depth == 1 && errno != EPIPE)
711 mdb_warn("write failed");
712
713 /*
714 * If an interrupt or quit signal is reported, we may have been
715 * in the middle of typing or processing the command line:
716 * print a newline and discard everything in the parser's iob.
717 * Note that we do this after m_out has been reset, otherwise
718 * we could trigger a pipe context switch or cause a write
719 * to a broken pipe (in the case of a shell command) when
720 * writing the newline.
721 */
722 if (err == MDB_ERR_SIGINT || err == MDB_ERR_QUIT) {
723 mdb_iob_nl(mdb.m_out);
724 yydiscard();
725 }
726
727 /*
728 * If we quit or abort using the output pager, reset the
729 * line count on standard output back to zero.
730 */
731 if (err == MDB_ERR_PAGER || MDB_ERR_IS_FATAL(err))
732 mdb_iob_clearlines(mdb.m_out);
733
734 /*
735 * If the user requested the debugger quit or abort back to
736 * the top, or if standard input is a pipe or mdb_eval("..."),
737 * then propagate the error up the debugger stack.
738 */
739 if (MDB_ERR_IS_FATAL(err) || pop != 0 ||
740 (err == MDB_ERR_PAGER && mdb.m_fmark != &f) ||
741 (err == MDB_ERR_NOMEM && !fromcmd)) {
742 mdb_frame_pop(&f, err);
743 return (err);
744 }
745
746 /*
747 * If we've returned here from a context where signals were
748 * blocked (e.g. a signal handler), we can now unblock them.
749 */
750 if (err == MDB_ERR_SIGINT)
751 (void) mdb_signal_unblock(SIGINT);
752 } else
753 mdb_intr_enable();
754
755 for (;;) {
756 while (mdb.m_in != NULL && (mdb_iob_getflags(mdb.m_in) &
757 (MDB_IOB_ERR | MDB_IOB_EOF)) == 0) {
758 if (mdb.m_depth == 1 &&
759 mdb_iob_stack_size(&f.f_istk) == 0) {
760 mdb_iob_clearlines(mdb.m_out);
761 mdb_tgt_periodic(mdb.m_target);
762 }
763
764 (void) yyparse();
765 }
766
767 if (mdb.m_in != NULL) {
768 if (mdb_iob_err(mdb.m_in)) {
769 warn("error reading input stream %s\n",
770 mdb_iob_name(mdb.m_in));
771 }
772 mdb_iob_destroy(mdb.m_in);
773 mdb.m_in = NULL;
774 }
775
776 if (mdb_iob_stack_size(&f.f_istk) == 0)
777 break; /* return when we're out of input */
778
779 mdb.m_in = mdb_iob_stack_pop(&f.f_istk);
780 yylineno = mdb_iob_lineno(mdb.m_in);
781 }
782
783 mdb_frame_pop(&f, 0);
784
785 /*
786 * The value of '.' is a per-frame attribute, to preserve it properly
787 * when switching frames. But in the case of calling mdb_run()
788 * explicitly (such as through mdb_eval), we want to propagate the value
789 * of '.' to the parent.
790 */
791 mdb_nv_set_value(mdb.m_dot, f.f_dot);
792
793 return (0);
794 }
795
796 /*
797 * The read-side of the pipe executes this service routine. We simply call
798 * mdb_run to create a new frame on the execution stack and run the MDB parser,
799 * and then propagate any error code back to the previous frame.
800 */
801 static int
runsvc(void)802 runsvc(void)
803 {
804 int err = mdb_run();
805
806 if (err != 0) {
807 mdb_dprintf(MDB_DBG_DSTK, "forwarding error %s from pipeline\n",
808 mdb_err2str(err));
809 longjmp(mdb.m_frame->f_pcb, err);
810 }
811
812 return (err);
813 }
814
815 /*
816 * Read-side pipe service routine: if we longjmp here, just return to the read
817 * routine because now we have more data to consume. Otherwise:
818 * (1) if ctx_data is non-NULL, longjmp to the write-side to produce more data;
819 * (2) if wriob is NULL, there is no writer but this is the first read, so we
820 * can just execute mdb_run() to completion on the current stack;
821 * (3) if (1) and (2) are false, then there is a writer and this is the first
822 * read, so create a co-routine context to execute mdb_run().
823 */
824 /*ARGSUSED*/
825 static void
rdsvc(mdb_iob_t * rdiob,mdb_iob_t * wriob,mdb_iob_ctx_t * ctx)826 rdsvc(mdb_iob_t *rdiob, mdb_iob_t *wriob, mdb_iob_ctx_t *ctx)
827 {
828 if (setjmp(ctx->ctx_rpcb) == 0) {
829 /*
830 * Save the current standard input into the pipe context, and
831 * reset m_in to point to the pipe. We will restore it on
832 * the way back in wrsvc() below.
833 */
834 ctx->ctx_iob = mdb.m_in;
835 mdb.m_in = rdiob;
836
837 ctx->ctx_rptr = mdb.m_frame;
838 if (ctx->ctx_wptr != NULL)
839 mdb_frame_switch(ctx->ctx_wptr);
840
841 if (ctx->ctx_data != NULL)
842 longjmp(ctx->ctx_wpcb, 1);
843 else if (wriob == NULL)
844 (void) runsvc();
845 else if ((ctx->ctx_data = mdb_context_create(runsvc)) != NULL)
846 mdb_context_switch(ctx->ctx_data);
847 else
848 mdb_warn("failed to create pipe context");
849 }
850 }
851
852 /*
853 * Write-side pipe service routine: if we longjmp here, just return to the
854 * write routine because now we have free space in the pipe buffer for writing;
855 * otherwise longjmp to the read-side to consume data and create space for us.
856 */
857 /*ARGSUSED*/
858 static void
wrsvc(mdb_iob_t * rdiob,mdb_iob_t * wriob,mdb_iob_ctx_t * ctx)859 wrsvc(mdb_iob_t *rdiob, mdb_iob_t *wriob, mdb_iob_ctx_t *ctx)
860 {
861 if (setjmp(ctx->ctx_wpcb) == 0) {
862 ctx->ctx_wptr = mdb.m_frame;
863 if (ctx->ctx_rptr != NULL)
864 mdb_frame_switch(ctx->ctx_rptr);
865
866 mdb.m_in = ctx->ctx_iob;
867 longjmp(ctx->ctx_rpcb, 1);
868 }
869 }
870
871 /*
872 * Call the current frame's mdb command. This entry point is used by the
873 * MDB parser to actually execute a command once it has successfully parsed
874 * a line of input. The command is waiting for us in the current frame.
875 * We loop through each command on the list, executing its dcmd with the
876 * appropriate argument. If the command has a successor, we know it had
877 * a | operator after it, and so we need to create a pipe and replace
878 * stdout with the pipe's output buffer.
879 */
880 int
mdb_call(uintmax_t addr,uintmax_t count,uint_t flags)881 mdb_call(uintmax_t addr, uintmax_t count, uint_t flags)
882 {
883 mdb_frame_t *fp = mdb.m_frame;
884 mdb_cmd_t *cp, *ncp;
885 mdb_iob_t *iobs[2];
886 int status, err = 0;
887 jmp_buf pcb;
888
889 if (mdb_iob_isapipe(mdb.m_in))
890 yyerror("syntax error");
891
892 mdb_intr_disable();
893 fp->f_cp = mdb_list_next(&fp->f_cmds);
894
895 if (flags & DCMD_LOOP)
896 flags |= DCMD_LOOPFIRST; /* set LOOPFIRST if this is a loop */
897
898 for (cp = mdb_list_next(&fp->f_cmds); cp; cp = mdb_list_next(cp)) {
899 if (mdb_list_next(cp) != NULL) {
900 mdb_iob_pipe(iobs, rdsvc, wrsvc);
901
902 mdb_iob_stack_push(&fp->f_istk, mdb.m_in, yylineno);
903 mdb.m_in = iobs[MDB_IOB_RDIOB];
904
905 mdb_iob_stack_push(&fp->f_ostk, mdb.m_out, 0);
906 mdb.m_out = iobs[MDB_IOB_WRIOB];
907
908 ncp = mdb_list_next(cp);
909 mdb_vcb_inherit(cp, ncp);
910
911 bcopy(fp->f_pcb, pcb, sizeof (jmp_buf));
912 ASSERT(fp->f_pcmd == NULL);
913 fp->f_pcmd = ncp;
914
915 mdb_frame_set_pipe(fp);
916
917 if ((err = setjmp(fp->f_pcb)) == 0) {
918 status = mdb_call_idcmd(cp->c_dcmd, addr, count,
919 flags | DCMD_PIPE_OUT, &cp->c_argv,
920 &cp->c_addrv, cp->c_vcbs);
921
922 mdb.m_lastret = status;
923
924 ASSERT(mdb.m_in == iobs[MDB_IOB_RDIOB]);
925 ASSERT(mdb.m_out == iobs[MDB_IOB_WRIOB]);
926 } else {
927 mdb_dprintf(MDB_DBG_DSTK, "frame <%u> caught "
928 "error %s from pipeline\n", fp->f_id,
929 mdb_err2str(err));
930 }
931
932 if (err != 0 || DCMD_ABORTED(status)) {
933 mdb_iob_setflags(mdb.m_in, MDB_IOB_ERR);
934 mdb_iob_setflags(mdb.m_out, MDB_IOB_ERR);
935 } else {
936 mdb_iob_flush(mdb.m_out);
937 (void) mdb_iob_ctl(mdb.m_out, I_FLUSH,
938 (void *)FLUSHW);
939 }
940
941 mdb_frame_clear_pipe(fp);
942
943 mdb_iob_destroy(mdb.m_out);
944 mdb.m_out = mdb_iob_stack_pop(&fp->f_ostk);
945
946 if (mdb.m_in != NULL)
947 mdb_iob_destroy(mdb.m_in);
948
949 mdb.m_in = mdb_iob_stack_pop(&fp->f_istk);
950 yylineno = mdb_iob_lineno(mdb.m_in);
951
952 fp->f_pcmd = NULL;
953 bcopy(pcb, fp->f_pcb, sizeof (jmp_buf));
954
955 if (MDB_ERR_IS_FATAL(err))
956 longjmp(fp->f_pcb, err);
957
958 if (err != 0 || DCMD_ABORTED(status) ||
959 mdb_addrvec_length(&ncp->c_addrv) == 0)
960 break;
961
962 addr = mdb_nv_get_value(mdb.m_dot);
963 count = 1;
964 flags = 0;
965
966 } else {
967 mdb_intr_enable();
968 mdb.m_lastret = mdb_call_idcmd(cp->c_dcmd, addr, count,
969 flags, &cp->c_argv, &cp->c_addrv, cp->c_vcbs);
970 mdb_intr_disable();
971 }
972
973 fp->f_cp = mdb_list_next(cp);
974 mdb_cmd_reset(cp);
975 }
976
977 /*
978 * If our last-command list is non-empty, destroy it. Then copy the
979 * current frame's cmd list to the m_lastc list and reset the frame.
980 */
981 while ((cp = mdb_list_next(&mdb.m_lastc)) != NULL) {
982 mdb_list_delete(&mdb.m_lastc, cp);
983 mdb_cmd_destroy(cp);
984 }
985
986 mdb_list_move(&fp->f_cmds, &mdb.m_lastc);
987 mdb_frame_reset(fp);
988 mdb_intr_enable();
989 return (err == 0);
990 }
991
992 uintmax_t
mdb_dot_incr(const char * op)993 mdb_dot_incr(const char *op)
994 {
995 uintmax_t odot, ndot;
996
997 odot = mdb_nv_get_value(mdb.m_dot);
998 ndot = odot + mdb.m_incr;
999
1000 if ((odot ^ ndot) & 0x8000000000000000ull)
1001 yyerror("'%s' would cause '.' to overflow\n", op);
1002
1003 return (ndot);
1004 }
1005
1006 uintmax_t
mdb_dot_decr(const char * op)1007 mdb_dot_decr(const char *op)
1008 {
1009 uintmax_t odot, ndot;
1010
1011 odot = mdb_nv_get_value(mdb.m_dot);
1012 ndot = odot - mdb.m_incr;
1013
1014 if (ndot > odot)
1015 yyerror("'%s' would cause '.' to underflow\n", op);
1016
1017 return (ndot);
1018 }
1019
1020 mdb_iwalker_t *
mdb_walker_lookup(const char * s)1021 mdb_walker_lookup(const char *s)
1022 {
1023 const char *p = strchr(s, '`');
1024 mdb_var_t *v;
1025
1026 if (p != NULL) {
1027 size_t nbytes = MIN((size_t)(p - s), MDB_NV_NAMELEN - 1);
1028 char mname[MDB_NV_NAMELEN];
1029 mdb_module_t *mod;
1030
1031 (void) strncpy(mname, s, nbytes);
1032 mname[nbytes] = '\0';
1033
1034 if ((v = mdb_nv_lookup(&mdb.m_modules, mname)) == NULL) {
1035 (void) set_errno(EMDB_NOMOD);
1036 return (NULL);
1037 }
1038
1039 mod = mdb_nv_get_cookie(v);
1040
1041 if ((v = mdb_nv_lookup(&mod->mod_walkers, ++p)) != NULL)
1042 return (mdb_nv_get_cookie(v));
1043
1044 } else if ((v = mdb_nv_lookup(&mdb.m_walkers, s)) != NULL)
1045 return (mdb_nv_get_cookie(mdb_nv_get_cookie(v)));
1046
1047 (void) set_errno(EMDB_NOWALK);
1048 return (NULL);
1049 }
1050
1051 mdb_idcmd_t *
mdb_dcmd_lookup(const char * s)1052 mdb_dcmd_lookup(const char *s)
1053 {
1054 const char *p = strchr(s, '`');
1055 mdb_var_t *v;
1056
1057 if (p != NULL) {
1058 size_t nbytes = MIN((size_t)(p - s), MDB_NV_NAMELEN - 1);
1059 char mname[MDB_NV_NAMELEN];
1060 mdb_module_t *mod;
1061
1062 (void) strncpy(mname, s, nbytes);
1063 mname[nbytes] = '\0';
1064
1065 if ((v = mdb_nv_lookup(&mdb.m_modules, mname)) == NULL) {
1066 (void) set_errno(EMDB_NOMOD);
1067 return (NULL);
1068 }
1069
1070 mod = mdb_nv_get_cookie(v);
1071
1072 if ((v = mdb_nv_lookup(&mod->mod_dcmds, ++p)) != NULL)
1073 return (mdb_nv_get_cookie(v));
1074
1075 } else if ((v = mdb_nv_lookup(&mdb.m_dcmds, s)) != NULL)
1076 return (mdb_nv_get_cookie(mdb_nv_get_cookie(v)));
1077
1078 (void) set_errno(EMDB_NODCMD);
1079 return (NULL);
1080 }
1081
1082 void
mdb_dcmd_usage(const mdb_idcmd_t * idcp,mdb_iob_t * iob)1083 mdb_dcmd_usage(const mdb_idcmd_t *idcp, mdb_iob_t *iob)
1084 {
1085 const char *prefix = "", *usage = "";
1086 char name0 = idcp->idc_name[0];
1087
1088 if (idcp->idc_usage != NULL) {
1089 if (idcp->idc_usage[0] == ':') {
1090 if (name0 != ':' && name0 != '$')
1091 prefix = "address::";
1092 else
1093 prefix = "address";
1094 usage = &idcp->idc_usage[1];
1095
1096 } else if (idcp->idc_usage[0] == '?') {
1097 if (name0 != ':' && name0 != '$')
1098 prefix = "[address]::";
1099 else
1100 prefix = "[address]";
1101 usage = &idcp->idc_usage[1];
1102
1103 } else
1104 usage = idcp->idc_usage;
1105 }
1106
1107 mdb_iob_printf(iob, "Usage: %s%s %s\n", prefix, idcp->idc_name, usage);
1108
1109 if (idcp->idc_help != NULL) {
1110 mdb_iob_printf(iob, "%s: try '::help %s' for more "
1111 "information\n", mdb.m_pname, idcp->idc_name);
1112 }
1113 }
1114
1115 static mdb_idcmd_t *
dcmd_ndef(const mdb_idcmd_t * idcp)1116 dcmd_ndef(const mdb_idcmd_t *idcp)
1117 {
1118 mdb_var_t *v = mdb_nv_get_ndef(idcp->idc_var);
1119
1120 if (v != NULL)
1121 return (mdb_nv_get_cookie(mdb_nv_get_cookie(v)));
1122
1123 return (NULL);
1124 }
1125
1126 static int
dcmd_invoke(mdb_idcmd_t * idcp,uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv,const mdb_vcb_t * vcbs)1127 dcmd_invoke(mdb_idcmd_t *idcp, uintptr_t addr, uint_t flags,
1128 int argc, const mdb_arg_t *argv, const mdb_vcb_t *vcbs)
1129 {
1130 int status;
1131
1132 mdb_dprintf(MDB_DBG_DCMD, "dcmd %s`%s dot = %lr incr = %llr\n",
1133 idcp->idc_modp->mod_name, idcp->idc_name, addr, mdb.m_incr);
1134
1135 if ((status = idcp->idc_funcp(addr, flags, argc, argv)) == DCMD_USAGE) {
1136 mdb_dcmd_usage(idcp, mdb.m_err);
1137 goto done;
1138 }
1139
1140 while (status == DCMD_NEXT && (idcp = dcmd_ndef(idcp)) != NULL)
1141 status = idcp->idc_funcp(addr, flags, argc, argv);
1142
1143 if (status == DCMD_USAGE)
1144 mdb_dcmd_usage(idcp, mdb.m_err);
1145
1146 if (status == DCMD_NEXT)
1147 status = DCMD_OK;
1148 done:
1149 /*
1150 * If standard output is a pipe and there are vcbs active, we need to
1151 * flush standard out and the write-side of the pipe. The reasons for
1152 * this are explained in more detail in mdb_vcb.c.
1153 */
1154 if ((flags & DCMD_PIPE_OUT) && (vcbs != NULL)) {
1155 mdb_iob_flush(mdb.m_out);
1156 (void) mdb_iob_ctl(mdb.m_out, I_FLUSH, (void *)FLUSHW);
1157 }
1158
1159 return (status);
1160 }
1161
1162 void
mdb_call_tab(mdb_idcmd_t * idcp,mdb_tab_cookie_t * mcp,uint_t flags,uintmax_t argc,mdb_arg_t * argv)1163 mdb_call_tab(mdb_idcmd_t *idcp, mdb_tab_cookie_t *mcp, uint_t flags,
1164 uintmax_t argc, mdb_arg_t *argv)
1165 {
1166 if (idcp->idc_tabp == NULL)
1167 return;
1168
1169 (void) idcp->idc_tabp(mcp, flags, argc, argv);
1170 }
1171
1172 /*
1173 * Call an internal dcmd directly: this code is used by module API functions
1174 * that need to execute dcmds, and by mdb_call() above.
1175 */
1176 int
mdb_call_idcmd(mdb_idcmd_t * idcp,uintmax_t addr,uintmax_t count,uint_t flags,mdb_argvec_t * avp,mdb_addrvec_t * adp,mdb_vcb_t * vcbs)1177 mdb_call_idcmd(mdb_idcmd_t *idcp, uintmax_t addr, uintmax_t count,
1178 uint_t flags, mdb_argvec_t *avp, mdb_addrvec_t *adp, mdb_vcb_t *vcbs)
1179 {
1180 int is_exec = (strcmp(idcp->idc_name, "$<") == 0);
1181 mdb_arg_t *argv;
1182 int argc;
1183 uintmax_t i;
1184 int status;
1185
1186 /*
1187 * Update the values of dot and the most recent address and count
1188 * to the values of our input parameters.
1189 */
1190 mdb_nv_set_value(mdb.m_dot, addr);
1191 mdb.m_raddr = addr;
1192 mdb.m_dcount = count;
1193
1194 /*
1195 * Here the adb(1) man page lies: '9' is only set to count
1196 * when the command is $<, not when it's $<<.
1197 */
1198 if (is_exec)
1199 mdb_nv_set_value(mdb.m_rcount, count);
1200
1201 /*
1202 * We can now return if the repeat count is zero.
1203 */
1204 if (count == 0)
1205 return (DCMD_OK);
1206
1207 /*
1208 * To guard against bad dcmds, we avoid passing the actual argv that
1209 * we will use to free argument strings directly to the dcmd. Instead,
1210 * we pass a copy that will be garbage collected automatically.
1211 */
1212 argc = avp->a_nelems;
1213 argv = mdb_alloc(sizeof (mdb_arg_t) * argc, UM_SLEEP | UM_GC);
1214 bcopy(avp->a_data, argv, sizeof (mdb_arg_t) * argc);
1215
1216 if (mdb_addrvec_length(adp) != 0) {
1217 flags |= DCMD_PIPE | DCMD_LOOP | DCMD_LOOPFIRST | DCMD_ADDRSPEC;
1218 addr = mdb_addrvec_shift(adp);
1219 mdb_nv_set_value(mdb.m_dot, addr);
1220 mdb_vcb_propagate(vcbs);
1221 count = 1;
1222 }
1223
1224 status = dcmd_invoke(idcp, addr, flags, argc, argv, vcbs);
1225 if (DCMD_ABORTED(status))
1226 goto done;
1227
1228 /*
1229 * If the command is $< and we're not receiving input from a pipe, we
1230 * ignore the repeat count and just return since the macro file is now
1231 * pushed on to the input stack.
1232 */
1233 if (is_exec && mdb_addrvec_length(adp) == 0)
1234 goto done;
1235
1236 /*
1237 * If we're going to loop, we've already executed the dcmd once,
1238 * so clear the LOOPFIRST flag before proceeding.
1239 */
1240 if (flags & DCMD_LOOP)
1241 flags &= ~DCMD_LOOPFIRST;
1242
1243 for (i = 1; i < count; i++) {
1244 addr = mdb_dot_incr(",");
1245 mdb_nv_set_value(mdb.m_dot, addr);
1246 status = dcmd_invoke(idcp, addr, flags, argc, argv, vcbs);
1247 if (DCMD_ABORTED(status))
1248 goto done;
1249 }
1250
1251 while (mdb_addrvec_length(adp) != 0) {
1252 addr = mdb_addrvec_shift(adp);
1253 mdb_nv_set_value(mdb.m_dot, addr);
1254 mdb_vcb_propagate(vcbs);
1255 status = dcmd_invoke(idcp, addr, flags, argc, argv, vcbs);
1256 if (DCMD_ABORTED(status))
1257 goto done;
1258 }
1259 done:
1260 mdb_iob_nlflush(mdb.m_out);
1261 return (status);
1262 }
1263
1264 void
mdb_intr_enable(void)1265 mdb_intr_enable(void)
1266 {
1267 ASSERT(mdb.m_intr >= 1);
1268 if (mdb.m_intr == 1 && mdb.m_pend != 0) {
1269 (void) mdb_signal_block(SIGINT);
1270 mdb.m_intr = mdb.m_pend = 0;
1271 mdb_dprintf(MDB_DBG_DSTK, "delivering pending INT\n");
1272 longjmp(mdb.m_frame->f_pcb, MDB_ERR_SIGINT);
1273 } else
1274 mdb.m_intr--;
1275 }
1276
1277 void
mdb_intr_disable(void)1278 mdb_intr_disable(void)
1279 {
1280 mdb.m_intr++;
1281 ASSERT(mdb.m_intr >= 1);
1282 }
1283
1284 /*
1285 * Create an encoded string representing the internal user-modifiable
1286 * configuration of the debugger and return a pointer to it. The string can be
1287 * used to initialize another instance of the debugger with the same
1288 * configuration as this one.
1289 */
1290 char *
mdb_get_config(void)1291 mdb_get_config(void)
1292 {
1293 size_t r, n = 0;
1294 char *s = NULL;
1295
1296 while ((r = mdb_snprintf(s, n,
1297 "%x;%x;%x;%x;%x;%x;%lx;%x;%x;%s;%s;%s;%s;%s",
1298 mdb.m_tgtflags, mdb.m_flags, mdb.m_debug, mdb.m_radix, mdb.m_nargs,
1299 mdb.m_histlen, (ulong_t)mdb.m_symdist, mdb.m_execmode,
1300 mdb.m_forkmode, mdb.m_root, mdb.m_termtype, mdb.m_ipathstr,
1301 mdb.m_lpathstr, mdb.m_prompt)) > n) {
1302
1303 mdb_free(s, n);
1304 n = r + 1;
1305 s = mdb_alloc(r + 1, UM_SLEEP);
1306 }
1307
1308 return (s);
1309 }
1310
1311 /*
1312 * Decode a configuration string created with mdb_get_config() and reset the
1313 * appropriate parts of the global mdb_t accordingly.
1314 */
1315 void
mdb_set_config(const char * s)1316 mdb_set_config(const char *s)
1317 {
1318 const char *p;
1319 size_t len;
1320
1321 if ((p = strchr(s, ';')) != NULL) {
1322 mdb.m_tgtflags = strntoul(s, (size_t)(p - s), 16);
1323 s = p + 1;
1324 }
1325
1326 if ((p = strchr(s, ';')) != NULL) {
1327 mdb.m_flags = strntoul(s, (size_t)(p - s), 16);
1328 mdb.m_flags &= ~(MDB_FL_LOG | MDB_FL_LATEST);
1329 s = p + 1;
1330 }
1331
1332 if ((p = strchr(s, ';')) != NULL) {
1333 mdb.m_debug = strntoul(s, (size_t)(p - s), 16);
1334 s = p + 1;
1335 }
1336
1337 if ((p = strchr(s, ';')) != NULL) {
1338 mdb.m_radix = (int)strntoul(s, (size_t)(p - s), 16);
1339 if (mdb.m_radix < 2 || mdb.m_radix > 16)
1340 mdb.m_radix = MDB_DEF_RADIX;
1341 s = p + 1;
1342 }
1343
1344 if ((p = strchr(s, ';')) != NULL) {
1345 mdb.m_nargs = (int)strntoul(s, (size_t)(p - s), 16);
1346 mdb.m_nargs = MAX(mdb.m_nargs, 0);
1347 s = p + 1;
1348 }
1349
1350 if ((p = strchr(s, ';')) != NULL) {
1351 mdb.m_histlen = (int)strntoul(s, (size_t)(p - s), 16);
1352 mdb.m_histlen = MAX(mdb.m_histlen, 1);
1353 s = p + 1;
1354 }
1355
1356 if ((p = strchr(s, ';')) != NULL) {
1357 mdb.m_symdist = strntoul(s, (size_t)(p - s), 16);
1358 s = p + 1;
1359 }
1360
1361 if ((p = strchr(s, ';')) != NULL) {
1362 mdb.m_execmode = (uchar_t)strntoul(s, (size_t)(p - s), 16);
1363 if (mdb.m_execmode > MDB_EM_FOLLOW)
1364 mdb.m_execmode = MDB_EM_ASK;
1365 s = p + 1;
1366 }
1367
1368 if ((p = strchr(s, ';')) != NULL) {
1369 mdb.m_forkmode = (uchar_t)strntoul(s, (size_t)(p - s), 16);
1370 if (mdb.m_forkmode > MDB_FM_CHILD)
1371 mdb.m_forkmode = MDB_FM_ASK;
1372 s = p + 1;
1373 }
1374
1375 if ((p = strchr(s, ';')) != NULL) {
1376 mdb.m_root = strndup(s, (size_t)(p - s));
1377 s = p + 1;
1378 }
1379
1380 if ((p = strchr(s, ';')) != NULL) {
1381 mdb.m_termtype = strndup(s, (size_t)(p - s));
1382 s = p + 1;
1383 }
1384
1385 if ((p = strchr(s, ';')) != NULL) {
1386 size_t len = MIN(sizeof (mdb.m_ipathstr) - 1, p - s);
1387 (void) strncpy(mdb.m_ipathstr, s, len);
1388 mdb.m_ipathstr[len] = '\0';
1389 s = p + 1;
1390 }
1391
1392 if ((p = strchr(s, ';')) != NULL) {
1393 size_t len = MIN(sizeof (mdb.m_lpathstr) - 1, p - s);
1394 (void) strncpy(mdb.m_lpathstr, s, len);
1395 mdb.m_lpathstr[len] = '\0';
1396 s = p + 1;
1397 }
1398
1399 p = s + strlen(s);
1400 len = MIN(MDB_PROMPTLEN, (size_t)(p - s));
1401 (void) strncpy(mdb.m_prompt, s, len);
1402 mdb.m_prompt[len] = '\0';
1403 mdb.m_promptlen = len;
1404 }
1405
1406 mdb_module_t *
mdb_get_module(void)1407 mdb_get_module(void)
1408 {
1409 if (mdb.m_lmod)
1410 return (mdb.m_lmod);
1411
1412 if (mdb.m_frame == NULL)
1413 return (NULL);
1414
1415 if (mdb.m_frame->f_wcbs && mdb.m_frame->f_wcbs->w_walker &&
1416 mdb.m_frame->f_wcbs->w_walker->iwlk_modp &&
1417 !mdb.m_frame->f_cbactive)
1418 return (mdb.m_frame->f_wcbs->w_walker->iwlk_modp);
1419
1420 if (mdb.m_frame->f_cp && mdb.m_frame->f_cp->c_dcmd)
1421 return (mdb.m_frame->f_cp->c_dcmd->idc_modp);
1422
1423 return (NULL);
1424 }
1425