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