17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*8a6a72fdSaf * Common Development and Distribution License (the "License"). 6*8a6a72fdSaf * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*8a6a72fdSaf * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * Modular Debugger (MDB) 307c478bd9Sstevel@tonic-gate * 317c478bd9Sstevel@tonic-gate * Refer to the white paper "A Modular Debugger for Solaris" for information 327c478bd9Sstevel@tonic-gate * on the design, features, and goals of MDB. See /shared/sac/PSARC/1999/169 337c478bd9Sstevel@tonic-gate * for copies of the paper and related documentation. 347c478bd9Sstevel@tonic-gate * 357c478bd9Sstevel@tonic-gate * This file provides the basic construction and destruction of the debugger's 367c478bd9Sstevel@tonic-gate * global state, as well as the main execution loop, mdb_run(). MDB maintains 377c478bd9Sstevel@tonic-gate * a stack of execution frames (mdb_frame_t's) that keep track of its current 387c478bd9Sstevel@tonic-gate * state, including a stack of input and output buffers, walk and memory 397c478bd9Sstevel@tonic-gate * garbage collect lists, and a list of commands (mdb_cmd_t's). As the 407c478bd9Sstevel@tonic-gate * parser consumes input, it fills in a list of commands to execute, and then 417c478bd9Sstevel@tonic-gate * invokes mdb_call(), below. A command consists of a dcmd, telling us 427c478bd9Sstevel@tonic-gate * what function to execute, and a list of arguments and other invocation- 437c478bd9Sstevel@tonic-gate * specific data. Each frame may have more than one command, kept on a list, 447c478bd9Sstevel@tonic-gate * when multiple commands are separated by | operators. New frames may be 457c478bd9Sstevel@tonic-gate * stacked on old ones by nested calls to mdb_run: this occurs when, for 467c478bd9Sstevel@tonic-gate * example, in the middle of processing one input source (such as a file 477c478bd9Sstevel@tonic-gate * or the terminal), we invoke a dcmd that in turn calls mdb_eval(). mdb_eval 487c478bd9Sstevel@tonic-gate * will construct a new frame whose input source is the string passed to 497c478bd9Sstevel@tonic-gate * the eval function, and then execute this frame to completion. 507c478bd9Sstevel@tonic-gate */ 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate #include <sys/param.h> 537c478bd9Sstevel@tonic-gate #include <stropts.h> 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate #define _MDB_PRIVATE 567c478bd9Sstevel@tonic-gate #include <mdb/mdb.h> 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate #include <mdb/mdb_context.h> 597c478bd9Sstevel@tonic-gate #include <mdb/mdb_argvec.h> 607c478bd9Sstevel@tonic-gate #include <mdb/mdb_signal.h> 617c478bd9Sstevel@tonic-gate #include <mdb/mdb_macalias.h> 627c478bd9Sstevel@tonic-gate #include <mdb/mdb_module.h> 637c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h> 647c478bd9Sstevel@tonic-gate #include <mdb/mdb_string.h> 657c478bd9Sstevel@tonic-gate #include <mdb/mdb_callb.h> 667c478bd9Sstevel@tonic-gate #include <mdb/mdb_debug.h> 677c478bd9Sstevel@tonic-gate #include <mdb/mdb_frame.h> 687c478bd9Sstevel@tonic-gate #include <mdb/mdb_conf.h> 697c478bd9Sstevel@tonic-gate #include <mdb/mdb_err.h> 707c478bd9Sstevel@tonic-gate #include <mdb/mdb_lex.h> 717c478bd9Sstevel@tonic-gate #include <mdb/mdb_io.h> 727c478bd9Sstevel@tonic-gate #ifdef _KMDB 737c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_module.h> 747c478bd9Sstevel@tonic-gate #endif 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate /* 777c478bd9Sstevel@tonic-gate * Macro for testing if a dcmd's return status (x) indicates that we should 787c478bd9Sstevel@tonic-gate * abort the current loop or pipeline. 797c478bd9Sstevel@tonic-gate */ 807c478bd9Sstevel@tonic-gate #define DCMD_ABORTED(x) ((x) == DCMD_USAGE || (x) == DCMD_ABORT) 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate extern const mdb_dcmd_t mdb_dcmd_builtins[]; 837c478bd9Sstevel@tonic-gate extern mdb_dis_ctor_f *const mdb_dis_builtins[]; 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate /* 867c478bd9Sstevel@tonic-gate * Variable discipline for toggling MDB_FL_PSYM based on the value of the 877c478bd9Sstevel@tonic-gate * undocumented '_' variable. Once adb(1) has been removed from the system, 887c478bd9Sstevel@tonic-gate * we should just remove this functionality and always disable PSYM for macros. 897c478bd9Sstevel@tonic-gate */ 907c478bd9Sstevel@tonic-gate static uintmax_t 917c478bd9Sstevel@tonic-gate psym_disc_get(const mdb_var_t *v) 927c478bd9Sstevel@tonic-gate { 937c478bd9Sstevel@tonic-gate int i = (mdb.m_flags & MDB_FL_PSYM) ? 1 : 0; 947c478bd9Sstevel@tonic-gate int j = (MDB_NV_VALUE(v) != 0) ? 1 : 0; 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate if ((i ^ j) == 0) 977c478bd9Sstevel@tonic-gate MDB_NV_VALUE((mdb_var_t *)v) = j ^ 1; 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate return (MDB_NV_VALUE(v)); 1007c478bd9Sstevel@tonic-gate } 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate static void 1037c478bd9Sstevel@tonic-gate psym_disc_set(mdb_var_t *v, uintmax_t value) 1047c478bd9Sstevel@tonic-gate { 1057c478bd9Sstevel@tonic-gate if (value == 0) 1067c478bd9Sstevel@tonic-gate mdb.m_flags |= MDB_FL_PSYM; 1077c478bd9Sstevel@tonic-gate else 1087c478bd9Sstevel@tonic-gate mdb.m_flags &= ~MDB_FL_PSYM; 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate MDB_NV_VALUE(v) = value; 1117c478bd9Sstevel@tonic-gate } 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate /* 1147c478bd9Sstevel@tonic-gate * Variable discipline for making <1 (most recent offset) behave properly. 1157c478bd9Sstevel@tonic-gate */ 1167c478bd9Sstevel@tonic-gate static uintmax_t 1177c478bd9Sstevel@tonic-gate roff_disc_get(const mdb_var_t *v) 1187c478bd9Sstevel@tonic-gate { 1197c478bd9Sstevel@tonic-gate return (MDB_NV_VALUE(v)); 1207c478bd9Sstevel@tonic-gate } 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate static void 1237c478bd9Sstevel@tonic-gate roff_disc_set(mdb_var_t *v, uintmax_t value) 1247c478bd9Sstevel@tonic-gate { 1257c478bd9Sstevel@tonic-gate mdb_nv_set_value(mdb.m_proffset, MDB_NV_VALUE(v)); 1267c478bd9Sstevel@tonic-gate MDB_NV_VALUE(v) = value; 1277c478bd9Sstevel@tonic-gate } 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate /* 1307c478bd9Sstevel@tonic-gate * Variable discipline for exporting the representative thread. 1317c478bd9Sstevel@tonic-gate */ 1327c478bd9Sstevel@tonic-gate static uintmax_t 1337c478bd9Sstevel@tonic-gate thr_disc_get(const mdb_var_t *v) 1347c478bd9Sstevel@tonic-gate { 1357c478bd9Sstevel@tonic-gate mdb_tgt_status_t s; 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate if (mdb.m_target != NULL && mdb_tgt_status(mdb.m_target, &s) == 0) 1387c478bd9Sstevel@tonic-gate return (s.st_tid); 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate return (MDB_NV_VALUE(v)); 1417c478bd9Sstevel@tonic-gate } 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate const char ** 1447c478bd9Sstevel@tonic-gate mdb_path_alloc(const char *s, size_t *newlen) 1457c478bd9Sstevel@tonic-gate { 1467c478bd9Sstevel@tonic-gate char *format = mdb_alloc(strlen(s) * 2 + 1, UM_NOSLEEP); 1477c478bd9Sstevel@tonic-gate const char **path; 1487c478bd9Sstevel@tonic-gate char *p, *q; 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate struct utsname uts; 1517c478bd9Sstevel@tonic-gate size_t len; 1527c478bd9Sstevel@tonic-gate int i; 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate mdb_arg_t arg_i, arg_m, arg_p, arg_r, arg_t, arg_R, arg_V; 1557c478bd9Sstevel@tonic-gate mdb_argvec_t argv; 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate static const char *empty_path[] = { NULL }; 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate if (format == NULL) 1607c478bd9Sstevel@tonic-gate goto nomem; 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate while (*s == ':') 1637c478bd9Sstevel@tonic-gate s++; /* strip leading delimiters */ 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate if (*s == '\0') { 1667c478bd9Sstevel@tonic-gate *newlen = 0; 1677c478bd9Sstevel@tonic-gate return (empty_path); 1687c478bd9Sstevel@tonic-gate } 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate (void) strcpy(format, s); 1717c478bd9Sstevel@tonic-gate mdb_argvec_create(&argv); 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate /* 1747c478bd9Sstevel@tonic-gate * %i embedded in path string expands to ISA. 1757c478bd9Sstevel@tonic-gate */ 1767c478bd9Sstevel@tonic-gate arg_i.a_type = MDB_TYPE_STRING; 1777c478bd9Sstevel@tonic-gate if (mdb.m_target != NULL) 1787c478bd9Sstevel@tonic-gate arg_i.a_un.a_str = mdb_tgt_isa(mdb.m_target); 1797c478bd9Sstevel@tonic-gate else 1807c478bd9Sstevel@tonic-gate arg_i.a_un.a_str = mdb_conf_isa(); 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate /* 1837c478bd9Sstevel@tonic-gate * %p embedded in path string expands to the platform name. 1847c478bd9Sstevel@tonic-gate */ 1857c478bd9Sstevel@tonic-gate arg_p.a_type = MDB_TYPE_STRING; 1867c478bd9Sstevel@tonic-gate if (mdb.m_target != NULL) 1877c478bd9Sstevel@tonic-gate arg_p.a_un.a_str = mdb_tgt_platform(mdb.m_target); 1887c478bd9Sstevel@tonic-gate else 1897c478bd9Sstevel@tonic-gate arg_p.a_un.a_str = mdb_conf_platform(); 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate /* 1927c478bd9Sstevel@tonic-gate * %r embedded in path string expands to root directory, or 1937c478bd9Sstevel@tonic-gate * to the empty string if root is "/" (to avoid // in paths). 1947c478bd9Sstevel@tonic-gate */ 1957c478bd9Sstevel@tonic-gate arg_r.a_type = MDB_TYPE_STRING; 1967c478bd9Sstevel@tonic-gate arg_r.a_un.a_str = strcmp(mdb.m_root, "/") ? mdb.m_root : ""; 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate /* 1997c478bd9Sstevel@tonic-gate * %t embedded in path string expands to the target name. 2007c478bd9Sstevel@tonic-gate */ 2017c478bd9Sstevel@tonic-gate arg_t.a_type = MDB_TYPE_STRING; 2027c478bd9Sstevel@tonic-gate arg_t.a_un.a_str = mdb.m_target ? mdb_tgt_name(mdb.m_target) : "none"; 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate /* 2057c478bd9Sstevel@tonic-gate * %R and %V expand to uname -r (release) and uname -v (version). 2067c478bd9Sstevel@tonic-gate */ 2077c478bd9Sstevel@tonic-gate if (mdb.m_target == NULL || mdb_tgt_uname(mdb.m_target, &uts) < 0) 2087c478bd9Sstevel@tonic-gate mdb_conf_uname(&uts); 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate arg_m.a_type = MDB_TYPE_STRING; 2117c478bd9Sstevel@tonic-gate arg_m.a_un.a_str = uts.machine; 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate arg_R.a_type = MDB_TYPE_STRING; 2147c478bd9Sstevel@tonic-gate arg_R.a_un.a_str = uts.release; 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate arg_V.a_type = MDB_TYPE_STRING; 2177c478bd9Sstevel@tonic-gate if (mdb.m_flags & MDB_FL_LATEST) 2187c478bd9Sstevel@tonic-gate arg_V.a_un.a_str = "latest"; 2197c478bd9Sstevel@tonic-gate else 2207c478bd9Sstevel@tonic-gate arg_V.a_un.a_str = uts.version; 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate /* 2237c478bd9Sstevel@tonic-gate * In order to expand the buffer, we examine the format string for 2247c478bd9Sstevel@tonic-gate * our % tokens and construct an argvec, replacing each % token 2257c478bd9Sstevel@tonic-gate * with %s along the way. If we encounter an unknown token, we 2267c478bd9Sstevel@tonic-gate * shift over the remaining format buffer and stick in %%. 2277c478bd9Sstevel@tonic-gate */ 2287c478bd9Sstevel@tonic-gate for (q = format; (q = strchr(q, '%')) != NULL; q++) { 2297c478bd9Sstevel@tonic-gate switch (q[1]) { 2307c478bd9Sstevel@tonic-gate case 'i': 2317c478bd9Sstevel@tonic-gate mdb_argvec_append(&argv, &arg_i); 2327c478bd9Sstevel@tonic-gate *++q = 's'; 2337c478bd9Sstevel@tonic-gate break; 2347c478bd9Sstevel@tonic-gate case 'm': 2357c478bd9Sstevel@tonic-gate mdb_argvec_append(&argv, &arg_m); 2367c478bd9Sstevel@tonic-gate *++q = 's'; 2377c478bd9Sstevel@tonic-gate break; 2387c478bd9Sstevel@tonic-gate case 'p': 2397c478bd9Sstevel@tonic-gate mdb_argvec_append(&argv, &arg_p); 2407c478bd9Sstevel@tonic-gate *++q = 's'; 2417c478bd9Sstevel@tonic-gate break; 2427c478bd9Sstevel@tonic-gate case 'r': 2437c478bd9Sstevel@tonic-gate mdb_argvec_append(&argv, &arg_r); 2447c478bd9Sstevel@tonic-gate *++q = 's'; 2457c478bd9Sstevel@tonic-gate break; 2467c478bd9Sstevel@tonic-gate case 't': 2477c478bd9Sstevel@tonic-gate mdb_argvec_append(&argv, &arg_t); 2487c478bd9Sstevel@tonic-gate *++q = 's'; 2497c478bd9Sstevel@tonic-gate break; 2507c478bd9Sstevel@tonic-gate case 'R': 2517c478bd9Sstevel@tonic-gate mdb_argvec_append(&argv, &arg_R); 2527c478bd9Sstevel@tonic-gate *++q = 's'; 2537c478bd9Sstevel@tonic-gate break; 2547c478bd9Sstevel@tonic-gate case 'V': 2557c478bd9Sstevel@tonic-gate mdb_argvec_append(&argv, &arg_V); 2567c478bd9Sstevel@tonic-gate *++q = 's'; 2577c478bd9Sstevel@tonic-gate break; 2587c478bd9Sstevel@tonic-gate default: 2597c478bd9Sstevel@tonic-gate bcopy(q + 1, q + 2, strlen(q)); 2607c478bd9Sstevel@tonic-gate *++q = '%'; 2617c478bd9Sstevel@tonic-gate } 2627c478bd9Sstevel@tonic-gate } 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate /* 2657c478bd9Sstevel@tonic-gate * We're now ready to use our printf engine to format the final string. 2667c478bd9Sstevel@tonic-gate * Take one lap with a NULL buffer to determine how long the final 2677c478bd9Sstevel@tonic-gate * string will be, allocate it, and format it. 2687c478bd9Sstevel@tonic-gate */ 2697c478bd9Sstevel@tonic-gate len = mdb_iob_asnprintf(NULL, 0, format, argv.a_data); 2707c478bd9Sstevel@tonic-gate if ((p = mdb_alloc(len + 1, UM_NOSLEEP)) != NULL) 2717c478bd9Sstevel@tonic-gate (void) mdb_iob_asnprintf(p, len + 1, format, argv.a_data); 2727c478bd9Sstevel@tonic-gate else 2737c478bd9Sstevel@tonic-gate goto nomem; 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate mdb_argvec_zero(&argv); 2767c478bd9Sstevel@tonic-gate mdb_argvec_destroy(&argv); 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate mdb_free(format, strlen(s) * 2 + 1); 2797c478bd9Sstevel@tonic-gate format = NULL; 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate /* 2827c478bd9Sstevel@tonic-gate * Compress the string to exclude any leading delimiters. 2837c478bd9Sstevel@tonic-gate */ 2847c478bd9Sstevel@tonic-gate for (q = p; *q == ':'; q++) 2857c478bd9Sstevel@tonic-gate continue; 2867c478bd9Sstevel@tonic-gate if (q != p) 2877c478bd9Sstevel@tonic-gate bcopy(q, p, strlen(q) + 1); 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate /* 2907c478bd9Sstevel@tonic-gate * Count up the number of delimited elements. A sequence of 2917c478bd9Sstevel@tonic-gate * consecutive delimiters is only counted once. 2927c478bd9Sstevel@tonic-gate */ 2937c478bd9Sstevel@tonic-gate for (i = 1, q = p; (q = strchr(q, ':')) != NULL; i++) { 2947c478bd9Sstevel@tonic-gate while (*q == ':') 2957c478bd9Sstevel@tonic-gate q++; 2967c478bd9Sstevel@tonic-gate } 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate if ((path = mdb_alloc(sizeof (char *) * (i + 1), UM_NOSLEEP)) == NULL) { 2997c478bd9Sstevel@tonic-gate mdb_free(p, len + 1); 3007c478bd9Sstevel@tonic-gate goto nomem; 3017c478bd9Sstevel@tonic-gate } 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate for (i = 0, q = strtok(p, ":"); q != NULL; q = strtok(NULL, ":")) 3047c478bd9Sstevel@tonic-gate path[i++] = q; 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate path[i] = NULL; 3077c478bd9Sstevel@tonic-gate *newlen = len + 1; 3087c478bd9Sstevel@tonic-gate return (path); 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate nomem: 3117c478bd9Sstevel@tonic-gate warn("failed to allocate memory for path"); 3127c478bd9Sstevel@tonic-gate if (format != NULL) 3137c478bd9Sstevel@tonic-gate mdb_free(format, strlen(s) * 2 + 1); 3147c478bd9Sstevel@tonic-gate *newlen = 0; 3157c478bd9Sstevel@tonic-gate return (empty_path); 3167c478bd9Sstevel@tonic-gate } 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate const char ** 3197c478bd9Sstevel@tonic-gate mdb_path_dup(const char *path[], size_t pathlen, size_t *npathlenp) 3207c478bd9Sstevel@tonic-gate { 3217c478bd9Sstevel@tonic-gate char **npath; 3227c478bd9Sstevel@tonic-gate int i, j; 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate for (i = 0; path[i] != NULL; i++) 3257c478bd9Sstevel@tonic-gate continue; /* count the path elements */ 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate npath = mdb_zalloc(sizeof (char *) * (i + 1), UM_SLEEP); 3287c478bd9Sstevel@tonic-gate if (pathlen > 0) { 3297c478bd9Sstevel@tonic-gate npath[0] = mdb_alloc(pathlen, UM_SLEEP); 3307c478bd9Sstevel@tonic-gate bcopy(path[0], npath[0], pathlen); 3317c478bd9Sstevel@tonic-gate } 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate for (j = 1; j < i; j++) 3347c478bd9Sstevel@tonic-gate npath[j] = npath[0] + (path[j] - path[0]); 3357c478bd9Sstevel@tonic-gate npath[i] = NULL; 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate *npathlenp = pathlen; 3387c478bd9Sstevel@tonic-gate return ((const char **)npath); 3397c478bd9Sstevel@tonic-gate } 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate void 3427c478bd9Sstevel@tonic-gate mdb_path_free(const char *path[], size_t pathlen) 3437c478bd9Sstevel@tonic-gate { 3447c478bd9Sstevel@tonic-gate int i; 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate for (i = 0; path[i] != NULL; i++) 3477c478bd9Sstevel@tonic-gate continue; /* count the path elements */ 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate if (i > 0) { 3507c478bd9Sstevel@tonic-gate mdb_free((void *)path[0], pathlen); 3517c478bd9Sstevel@tonic-gate mdb_free(path, sizeof (char *) * (i + 1)); 3527c478bd9Sstevel@tonic-gate } 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate /* 3567c478bd9Sstevel@tonic-gate * Convert path string "s" to canonical form, expanding any %o tokens that are 3577c478bd9Sstevel@tonic-gate * found within the path. The old path string is specified by "path", a buffer 3587c478bd9Sstevel@tonic-gate * of size MAXPATHLEN which is then overwritten with the new path string. 3597c478bd9Sstevel@tonic-gate */ 3607c478bd9Sstevel@tonic-gate static const char * 3617c478bd9Sstevel@tonic-gate path_canon(char *path, const char *s) 3627c478bd9Sstevel@tonic-gate { 3637c478bd9Sstevel@tonic-gate char *p = path; 3647c478bd9Sstevel@tonic-gate char *q = p + MAXPATHLEN - 1; 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate char old[MAXPATHLEN]; 3677c478bd9Sstevel@tonic-gate char c; 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate (void) strcpy(old, p); 3707c478bd9Sstevel@tonic-gate *q = '\0'; 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate while (p < q && (c = *s++) != '\0') { 3737c478bd9Sstevel@tonic-gate if (c == '%') { 3747c478bd9Sstevel@tonic-gate if ((c = *s++) == 'o') { 3757c478bd9Sstevel@tonic-gate (void) strncpy(p, old, (size_t)(q - p)); 3767c478bd9Sstevel@tonic-gate p += strlen(p); 3777c478bd9Sstevel@tonic-gate } else { 3787c478bd9Sstevel@tonic-gate *p++ = '%'; 3797c478bd9Sstevel@tonic-gate if (p < q && c != '\0') 3807c478bd9Sstevel@tonic-gate *p++ = c; 3817c478bd9Sstevel@tonic-gate else 3827c478bd9Sstevel@tonic-gate break; 3837c478bd9Sstevel@tonic-gate } 3847c478bd9Sstevel@tonic-gate } else 3857c478bd9Sstevel@tonic-gate *p++ = c; 3867c478bd9Sstevel@tonic-gate } 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate *p = '\0'; 3897c478bd9Sstevel@tonic-gate return (path); 3907c478bd9Sstevel@tonic-gate } 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate void 3937c478bd9Sstevel@tonic-gate mdb_set_ipath(const char *path) 3947c478bd9Sstevel@tonic-gate { 3957c478bd9Sstevel@tonic-gate if (mdb.m_ipath != NULL) 3967c478bd9Sstevel@tonic-gate mdb_path_free(mdb.m_ipath, mdb.m_ipathlen); 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate path = path_canon(mdb.m_ipathstr, path); 3997c478bd9Sstevel@tonic-gate mdb.m_ipath = mdb_path_alloc(path, &mdb.m_ipathlen); 4007c478bd9Sstevel@tonic-gate } 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate void 4037c478bd9Sstevel@tonic-gate mdb_set_lpath(const char *path) 4047c478bd9Sstevel@tonic-gate { 4057c478bd9Sstevel@tonic-gate if (mdb.m_lpath != NULL) 4067c478bd9Sstevel@tonic-gate mdb_path_free(mdb.m_lpath, mdb.m_lpathlen); 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate path = path_canon(mdb.m_lpathstr, path); 4097c478bd9Sstevel@tonic-gate mdb.m_lpath = mdb_path_alloc(path, &mdb.m_lpathlen); 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate #ifdef _KMDB 4127c478bd9Sstevel@tonic-gate kmdb_module_path_set(mdb.m_lpath, mdb.m_lpathlen); 4137c478bd9Sstevel@tonic-gate #endif 4147c478bd9Sstevel@tonic-gate } 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate static void 4177c478bd9Sstevel@tonic-gate prompt_update(void) 4187c478bd9Sstevel@tonic-gate { 4197c478bd9Sstevel@tonic-gate (void) mdb_snprintf(mdb.m_prompt, sizeof (mdb.m_prompt), 4207c478bd9Sstevel@tonic-gate mdb.m_promptraw); 4217c478bd9Sstevel@tonic-gate mdb.m_promptlen = strlen(mdb.m_prompt); 4227c478bd9Sstevel@tonic-gate } 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate const char * 4257c478bd9Sstevel@tonic-gate mdb_get_prompt(void) 4267c478bd9Sstevel@tonic-gate { 4277c478bd9Sstevel@tonic-gate if (mdb.m_promptlen == 0) 4287c478bd9Sstevel@tonic-gate return (NULL); 4297c478bd9Sstevel@tonic-gate else 4307c478bd9Sstevel@tonic-gate return (mdb.m_prompt); 4317c478bd9Sstevel@tonic-gate } 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate int 4347c478bd9Sstevel@tonic-gate mdb_set_prompt(const char *p) 4357c478bd9Sstevel@tonic-gate { 4367c478bd9Sstevel@tonic-gate size_t len = strlen(p); 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate if (len > MDB_PROMPTLEN) { 4397c478bd9Sstevel@tonic-gate warn("prompt may not exceed %d characters\n", MDB_PROMPTLEN); 4407c478bd9Sstevel@tonic-gate return (0); 4417c478bd9Sstevel@tonic-gate } 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate (void) strcpy(mdb.m_promptraw, p); 4447c478bd9Sstevel@tonic-gate prompt_update(); 4457c478bd9Sstevel@tonic-gate return (1); 4467c478bd9Sstevel@tonic-gate } 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate static mdb_frame_t frame0; 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate void 4517c478bd9Sstevel@tonic-gate mdb_create(const char *execname, const char *arg0) 4527c478bd9Sstevel@tonic-gate { 4537c478bd9Sstevel@tonic-gate static const mdb_nv_disc_t psym_disc = { psym_disc_set, psym_disc_get }; 4547c478bd9Sstevel@tonic-gate static const mdb_nv_disc_t roff_disc = { roff_disc_set, roff_disc_get }; 4557c478bd9Sstevel@tonic-gate static const mdb_nv_disc_t thr_disc = { NULL, thr_disc_get }; 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate static char rootdir[MAXPATHLEN]; 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate const mdb_dcmd_t *dcp; 4607c478bd9Sstevel@tonic-gate int i; 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate bzero(&mdb, sizeof (mdb_t)); 4637c478bd9Sstevel@tonic-gate 4647c478bd9Sstevel@tonic-gate mdb.m_flags = MDB_FL_PSYM | MDB_FL_PAGER | MDB_FL_BPTNOSYMSTOP | 4657c478bd9Sstevel@tonic-gate MDB_FL_READBACK; 4667c478bd9Sstevel@tonic-gate mdb.m_radix = MDB_DEF_RADIX; 4677c478bd9Sstevel@tonic-gate mdb.m_nargs = MDB_DEF_NARGS; 4687c478bd9Sstevel@tonic-gate mdb.m_histlen = MDB_DEF_HISTLEN; 4697c478bd9Sstevel@tonic-gate mdb.m_armemlim = MDB_DEF_ARRMEM; 4707c478bd9Sstevel@tonic-gate mdb.m_arstrlim = MDB_DEF_ARRSTR; 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate mdb.m_pname = strbasename(arg0); 4737c478bd9Sstevel@tonic-gate if (strcmp(mdb.m_pname, "adb") == 0) { 4747c478bd9Sstevel@tonic-gate mdb.m_flags |= MDB_FL_NOMODS | MDB_FL_ADB | MDB_FL_REPLAST; 4757c478bd9Sstevel@tonic-gate mdb.m_flags &= ~MDB_FL_PAGER; 4767c478bd9Sstevel@tonic-gate } 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate mdb.m_ipathstr = mdb_zalloc(MAXPATHLEN, UM_SLEEP); 4797c478bd9Sstevel@tonic-gate mdb.m_lpathstr = mdb_zalloc(MAXPATHLEN, UM_SLEEP); 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate (void) strncpy(rootdir, execname, sizeof (rootdir)); 4827c478bd9Sstevel@tonic-gate rootdir[sizeof (rootdir) - 1] = '\0'; 4837c478bd9Sstevel@tonic-gate (void) strdirname(rootdir); 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate if (strcmp(strbasename(rootdir), "sparcv9") == 0 || 4867c478bd9Sstevel@tonic-gate strcmp(strbasename(rootdir), "sparcv7") == 0 || 4877c478bd9Sstevel@tonic-gate strcmp(strbasename(rootdir), "amd64") == 0 || 4887c478bd9Sstevel@tonic-gate strcmp(strbasename(rootdir), "i86") == 0) 4897c478bd9Sstevel@tonic-gate (void) strdirname(rootdir); 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate if (strcmp(strbasename(rootdir), "bin") == 0) { 4927c478bd9Sstevel@tonic-gate (void) strdirname(rootdir); 4937c478bd9Sstevel@tonic-gate if (strcmp(strbasename(rootdir), "usr") == 0) 4947c478bd9Sstevel@tonic-gate (void) strdirname(rootdir); 4957c478bd9Sstevel@tonic-gate } else 4967c478bd9Sstevel@tonic-gate (void) strcpy(rootdir, "/"); 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate mdb.m_root = rootdir; 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate mdb.m_rminfo.mi_dvers = MDB_API_VERSION; 5017c478bd9Sstevel@tonic-gate mdb.m_rminfo.mi_dcmds = mdb_dcmd_builtins; 5027c478bd9Sstevel@tonic-gate mdb.m_rminfo.mi_walkers = NULL; 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate (void) mdb_nv_create(&mdb.m_rmod.mod_walkers, UM_SLEEP); 5057c478bd9Sstevel@tonic-gate (void) mdb_nv_create(&mdb.m_rmod.mod_dcmds, UM_SLEEP); 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate mdb.m_rmod.mod_name = mdb.m_pname; 5087c478bd9Sstevel@tonic-gate mdb.m_rmod.mod_info = &mdb.m_rminfo; 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate (void) mdb_nv_create(&mdb.m_disasms, UM_SLEEP); 5117c478bd9Sstevel@tonic-gate (void) mdb_nv_create(&mdb.m_modules, UM_SLEEP); 5127c478bd9Sstevel@tonic-gate (void) mdb_nv_create(&mdb.m_dcmds, UM_SLEEP); 5137c478bd9Sstevel@tonic-gate (void) mdb_nv_create(&mdb.m_walkers, UM_SLEEP); 5147c478bd9Sstevel@tonic-gate (void) mdb_nv_create(&mdb.m_nv, UM_SLEEP); 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate mdb.m_dot = mdb_nv_insert(&mdb.m_nv, ".", NULL, 0, MDB_NV_PERSIST); 5177c478bd9Sstevel@tonic-gate mdb.m_rvalue = mdb_nv_insert(&mdb.m_nv, "0", NULL, 0, MDB_NV_PERSIST); 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate mdb.m_roffset = 5207c478bd9Sstevel@tonic-gate mdb_nv_insert(&mdb.m_nv, "1", &roff_disc, 0, MDB_NV_PERSIST); 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate mdb.m_proffset = mdb_nv_insert(&mdb.m_nv, "2", NULL, 0, MDB_NV_PERSIST); 5237c478bd9Sstevel@tonic-gate mdb.m_rcount = mdb_nv_insert(&mdb.m_nv, "9", NULL, 0, MDB_NV_PERSIST); 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate (void) mdb_nv_insert(&mdb.m_nv, "b", NULL, 0, MDB_NV_PERSIST); 5267c478bd9Sstevel@tonic-gate (void) mdb_nv_insert(&mdb.m_nv, "d", NULL, 0, MDB_NV_PERSIST); 5277c478bd9Sstevel@tonic-gate (void) mdb_nv_insert(&mdb.m_nv, "e", NULL, 0, MDB_NV_PERSIST); 5287c478bd9Sstevel@tonic-gate (void) mdb_nv_insert(&mdb.m_nv, "m", NULL, 0, MDB_NV_PERSIST); 5297c478bd9Sstevel@tonic-gate (void) mdb_nv_insert(&mdb.m_nv, "t", NULL, 0, MDB_NV_PERSIST); 5307c478bd9Sstevel@tonic-gate (void) mdb_nv_insert(&mdb.m_nv, "_", &psym_disc, 0, MDB_NV_PERSIST); 5317c478bd9Sstevel@tonic-gate (void) mdb_nv_insert(&mdb.m_nv, "hits", NULL, 0, MDB_NV_PERSIST); 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate (void) mdb_nv_insert(&mdb.m_nv, "thread", &thr_disc, 0, 5347c478bd9Sstevel@tonic-gate MDB_NV_PERSIST | MDB_NV_RDONLY); 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate mdb.m_prsym = mdb_gelf_symtab_create_mutable(); 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate (void) mdb_nv_insert(&mdb.m_modules, mdb.m_pname, NULL, 5397c478bd9Sstevel@tonic-gate (uintptr_t)&mdb.m_rmod, MDB_NV_RDONLY); 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate for (dcp = &mdb_dcmd_builtins[0]; dcp->dc_name != NULL; dcp++) 5427c478bd9Sstevel@tonic-gate (void) mdb_module_add_dcmd(&mdb.m_rmod, dcp, 0); 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate for (i = 0; mdb_dis_builtins[i] != NULL; i++) 5457c478bd9Sstevel@tonic-gate (void) mdb_dis_create(mdb_dis_builtins[i]); 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate mdb_macalias_create(); 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate mdb_create_builtin_tgts(); 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate (void) mdb_callb_add(NULL, MDB_CALLB_PROMPT, (mdb_callb_f)prompt_update, 5527c478bd9Sstevel@tonic-gate NULL); 5537c478bd9Sstevel@tonic-gate 5547c478bd9Sstevel@tonic-gate #ifdef _KMDB 5557c478bd9Sstevel@tonic-gate (void) mdb_nv_create(&mdb.m_dmodctl, UM_SLEEP); 5567c478bd9Sstevel@tonic-gate #endif 5577c478bd9Sstevel@tonic-gate mdb_lex_state_create(&frame0); 5587c478bd9Sstevel@tonic-gate 5597c478bd9Sstevel@tonic-gate mdb_list_append(&mdb.m_flist, &frame0); 5607c478bd9Sstevel@tonic-gate mdb.m_frame = &frame0; 5617c478bd9Sstevel@tonic-gate } 5627c478bd9Sstevel@tonic-gate 5637c478bd9Sstevel@tonic-gate void 5647c478bd9Sstevel@tonic-gate mdb_destroy(void) 5657c478bd9Sstevel@tonic-gate { 5667c478bd9Sstevel@tonic-gate const mdb_dcmd_t *dcp; 5677c478bd9Sstevel@tonic-gate mdb_var_t *v; 5687c478bd9Sstevel@tonic-gate int unload_mode = MDB_MOD_SILENT; 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate #ifdef _KMDB 5717c478bd9Sstevel@tonic-gate unload_mode |= MDB_MOD_DEFER; 5727c478bd9Sstevel@tonic-gate #endif 5737c478bd9Sstevel@tonic-gate 5747c478bd9Sstevel@tonic-gate mdb_intr_disable(); 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate mdb_macalias_destroy(); 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate /* 5797c478bd9Sstevel@tonic-gate * Unload modules _before_ destroying the disassemblers since a 5807c478bd9Sstevel@tonic-gate * module that installs a disassembler should try to clean up after 5817c478bd9Sstevel@tonic-gate * itself. 5827c478bd9Sstevel@tonic-gate */ 5837c478bd9Sstevel@tonic-gate mdb_module_unload_all(unload_mode); 5847c478bd9Sstevel@tonic-gate 5857c478bd9Sstevel@tonic-gate mdb_nv_rewind(&mdb.m_disasms); 5867c478bd9Sstevel@tonic-gate while ((v = mdb_nv_advance(&mdb.m_disasms)) != NULL) 5877c478bd9Sstevel@tonic-gate mdb_dis_destroy(mdb_nv_get_cookie(v)); 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate mdb_callb_remove_all(); 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate if (mdb.m_defdisasm != NULL) 5927c478bd9Sstevel@tonic-gate strfree(mdb.m_defdisasm); 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate if (mdb.m_target != NULL) 5957c478bd9Sstevel@tonic-gate (void) mdb_tgt_destroy(mdb.m_target); 5967c478bd9Sstevel@tonic-gate 5977c478bd9Sstevel@tonic-gate if (mdb.m_prsym != NULL) 5987c478bd9Sstevel@tonic-gate mdb_gelf_symtab_destroy(mdb.m_prsym); 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate for (dcp = &mdb_dcmd_builtins[0]; dcp->dc_name != NULL; dcp++) 6017c478bd9Sstevel@tonic-gate (void) mdb_module_remove_dcmd(&mdb.m_rmod, dcp->dc_name); 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate mdb_nv_destroy(&mdb.m_nv); 6047c478bd9Sstevel@tonic-gate mdb_nv_destroy(&mdb.m_walkers); 6057c478bd9Sstevel@tonic-gate mdb_nv_destroy(&mdb.m_dcmds); 6067c478bd9Sstevel@tonic-gate mdb_nv_destroy(&mdb.m_modules); 6077c478bd9Sstevel@tonic-gate mdb_nv_destroy(&mdb.m_disasms); 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate mdb_free(mdb.m_ipathstr, MAXPATHLEN); 6107c478bd9Sstevel@tonic-gate mdb_free(mdb.m_lpathstr, MAXPATHLEN); 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate if (mdb.m_ipath != NULL) 6137c478bd9Sstevel@tonic-gate mdb_path_free(mdb.m_ipath, mdb.m_ipathlen); 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate if (mdb.m_lpath != NULL) 6167c478bd9Sstevel@tonic-gate mdb_path_free(mdb.m_lpath, mdb.m_lpathlen); 6177c478bd9Sstevel@tonic-gate 6187c478bd9Sstevel@tonic-gate if (mdb.m_in != NULL) 6197c478bd9Sstevel@tonic-gate mdb_iob_destroy(mdb.m_in); 6207c478bd9Sstevel@tonic-gate 6217c478bd9Sstevel@tonic-gate mdb_iob_destroy(mdb.m_out); 6227c478bd9Sstevel@tonic-gate mdb.m_out = NULL; 6237c478bd9Sstevel@tonic-gate mdb_iob_destroy(mdb.m_err); 6247c478bd9Sstevel@tonic-gate mdb.m_err = NULL; 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate if (mdb.m_log != NULL) 6277c478bd9Sstevel@tonic-gate mdb_io_rele(mdb.m_log); 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate mdb_lex_state_destroy(&frame0); 6307c478bd9Sstevel@tonic-gate } 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate /* 6337c478bd9Sstevel@tonic-gate * The real main loop of the debugger: create a new execution frame on the 6347c478bd9Sstevel@tonic-gate * debugger stack, and while we have input available, call into the parser. 6357c478bd9Sstevel@tonic-gate */ 6367c478bd9Sstevel@tonic-gate int 6377c478bd9Sstevel@tonic-gate mdb_run(void) 6387c478bd9Sstevel@tonic-gate { 6397c478bd9Sstevel@tonic-gate volatile int err; 6407c478bd9Sstevel@tonic-gate mdb_frame_t f; 6417c478bd9Sstevel@tonic-gate 6427c478bd9Sstevel@tonic-gate mdb_intr_disable(); 6437c478bd9Sstevel@tonic-gate mdb_frame_push(&f); 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate /* 6467c478bd9Sstevel@tonic-gate * This is a fresh mdb context, so ignore any pipe command we may have 6477c478bd9Sstevel@tonic-gate * inherited from the previous frame. 6487c478bd9Sstevel@tonic-gate */ 6497c478bd9Sstevel@tonic-gate f.f_pcmd = NULL; 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate if ((err = setjmp(f.f_pcb)) != 0) { 6527c478bd9Sstevel@tonic-gate int pop = (mdb.m_in != NULL && 6537c478bd9Sstevel@tonic-gate (mdb_iob_isapipe(mdb.m_in) || mdb_iob_isastr(mdb.m_in))); 6547c478bd9Sstevel@tonic-gate int fromcmd = (f.f_cp != NULL); 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_DSTK, "frame <%u> caught event %s\n", 6577c478bd9Sstevel@tonic-gate f.f_id, mdb_err2str(err)); 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate /* 6607c478bd9Sstevel@tonic-gate * If a syntax error or other failure has occurred, pop all 6617c478bd9Sstevel@tonic-gate * input buffers pushed by commands executed in this frame. 6627c478bd9Sstevel@tonic-gate */ 6637c478bd9Sstevel@tonic-gate while (mdb_iob_stack_size(&f.f_istk) != 0) { 6647c478bd9Sstevel@tonic-gate if (mdb.m_in != NULL) 6657c478bd9Sstevel@tonic-gate mdb_iob_destroy(mdb.m_in); 6667c478bd9Sstevel@tonic-gate mdb.m_in = mdb_iob_stack_pop(&f.f_istk); 6677c478bd9Sstevel@tonic-gate yylineno = mdb_iob_lineno(mdb.m_in); 6687c478bd9Sstevel@tonic-gate } 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate /* 6717c478bd9Sstevel@tonic-gate * Reset standard output and the current frame to a known, 6727c478bd9Sstevel@tonic-gate * clean state, so we can continue execution. 6737c478bd9Sstevel@tonic-gate */ 6747c478bd9Sstevel@tonic-gate mdb_iob_margin(mdb.m_out, MDB_IOB_DEFMARGIN); 6757c478bd9Sstevel@tonic-gate mdb_iob_clrflags(mdb.m_out, MDB_IOB_INDENT); 6767c478bd9Sstevel@tonic-gate mdb_iob_discard(mdb.m_out); 6777c478bd9Sstevel@tonic-gate mdb_frame_reset(&f); 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate /* 6807c478bd9Sstevel@tonic-gate * If there was an error writing to output, display a warning 6817c478bd9Sstevel@tonic-gate * message if this is the topmost frame. 6827c478bd9Sstevel@tonic-gate */ 6837c478bd9Sstevel@tonic-gate if (err == MDB_ERR_OUTPUT && mdb.m_depth == 1 && errno != EPIPE) 6847c478bd9Sstevel@tonic-gate mdb_warn("write failed"); 6857c478bd9Sstevel@tonic-gate 6867c478bd9Sstevel@tonic-gate /* 6877c478bd9Sstevel@tonic-gate * If an interrupt or quit signal is reported, we may have been 6887c478bd9Sstevel@tonic-gate * in the middle of typing or processing the command line: 6897c478bd9Sstevel@tonic-gate * print a newline and discard everything in the parser's iob. 6907c478bd9Sstevel@tonic-gate * Note that we do this after m_out has been reset, otherwise 6917c478bd9Sstevel@tonic-gate * we could trigger a pipe context switch or cause a write 6927c478bd9Sstevel@tonic-gate * to a broken pipe (in the case of a shell command) when 6937c478bd9Sstevel@tonic-gate * writing the newline. 6947c478bd9Sstevel@tonic-gate */ 6957c478bd9Sstevel@tonic-gate if (err == MDB_ERR_SIGINT || err == MDB_ERR_QUIT) { 6967c478bd9Sstevel@tonic-gate mdb_iob_nl(mdb.m_out); 6977c478bd9Sstevel@tonic-gate yydiscard(); 6987c478bd9Sstevel@tonic-gate } 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate /* 7017c478bd9Sstevel@tonic-gate * If we quit or abort using the output pager, reset the 7027c478bd9Sstevel@tonic-gate * line count on standard output back to zero. 7037c478bd9Sstevel@tonic-gate */ 7047c478bd9Sstevel@tonic-gate if (err == MDB_ERR_PAGER || MDB_ERR_IS_FATAL(err)) 7057c478bd9Sstevel@tonic-gate mdb_iob_clearlines(mdb.m_out); 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate /* 7087c478bd9Sstevel@tonic-gate * If the user requested the debugger quit or abort back to 7097c478bd9Sstevel@tonic-gate * the top, or if standard input is a pipe or mdb_eval("..."), 7107c478bd9Sstevel@tonic-gate * then propagate the error up the debugger stack. 7117c478bd9Sstevel@tonic-gate */ 7127c478bd9Sstevel@tonic-gate if (MDB_ERR_IS_FATAL(err) || pop != 0 || 7137c478bd9Sstevel@tonic-gate (err == MDB_ERR_PAGER && mdb.m_fmark != &f) || 7147c478bd9Sstevel@tonic-gate (err == MDB_ERR_NOMEM && !fromcmd)) { 7157c478bd9Sstevel@tonic-gate mdb_frame_pop(&f, err); 7167c478bd9Sstevel@tonic-gate return (err); 7177c478bd9Sstevel@tonic-gate } 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate /* 7207c478bd9Sstevel@tonic-gate * If we've returned here from a context where signals were 7217c478bd9Sstevel@tonic-gate * blocked (e.g. a signal handler), we can now unblock them. 7227c478bd9Sstevel@tonic-gate */ 7237c478bd9Sstevel@tonic-gate if (err == MDB_ERR_SIGINT) 7247c478bd9Sstevel@tonic-gate (void) mdb_signal_unblock(SIGINT); 7257c478bd9Sstevel@tonic-gate } else 7267c478bd9Sstevel@tonic-gate mdb_intr_enable(); 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate for (;;) { 7297c478bd9Sstevel@tonic-gate while (mdb.m_in != NULL && (mdb_iob_getflags(mdb.m_in) & 7307c478bd9Sstevel@tonic-gate (MDB_IOB_ERR | MDB_IOB_EOF)) == 0) { 7317c478bd9Sstevel@tonic-gate if (mdb.m_depth == 1 && 7327c478bd9Sstevel@tonic-gate mdb_iob_stack_size(&f.f_istk) == 0) { 7337c478bd9Sstevel@tonic-gate mdb_iob_clearlines(mdb.m_out); 7347c478bd9Sstevel@tonic-gate mdb_tgt_periodic(mdb.m_target); 7357c478bd9Sstevel@tonic-gate } 7367c478bd9Sstevel@tonic-gate 7377c478bd9Sstevel@tonic-gate (void) yyparse(); 7387c478bd9Sstevel@tonic-gate } 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate if (mdb.m_in != NULL) { 7417c478bd9Sstevel@tonic-gate if (mdb_iob_err(mdb.m_in)) { 7427c478bd9Sstevel@tonic-gate warn("error reading input stream %s\n", 7437c478bd9Sstevel@tonic-gate mdb_iob_name(mdb.m_in)); 7447c478bd9Sstevel@tonic-gate } 7457c478bd9Sstevel@tonic-gate mdb_iob_destroy(mdb.m_in); 7467c478bd9Sstevel@tonic-gate mdb.m_in = NULL; 7477c478bd9Sstevel@tonic-gate } 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate if (mdb_iob_stack_size(&f.f_istk) == 0) 7507c478bd9Sstevel@tonic-gate break; /* return when we're out of input */ 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate mdb.m_in = mdb_iob_stack_pop(&f.f_istk); 7537c478bd9Sstevel@tonic-gate yylineno = mdb_iob_lineno(mdb.m_in); 7547c478bd9Sstevel@tonic-gate } 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate mdb_frame_pop(&f, 0); 7577c478bd9Sstevel@tonic-gate 7587c478bd9Sstevel@tonic-gate /* 7597c478bd9Sstevel@tonic-gate * The value of '.' is a per-frame attribute, to preserve it properly 7607c478bd9Sstevel@tonic-gate * when switching frames. But in the case of calling mdb_run() 7617c478bd9Sstevel@tonic-gate * explicitly (such as through mdb_eval), we want to propagate the value 7627c478bd9Sstevel@tonic-gate * of '.' to the parent. 7637c478bd9Sstevel@tonic-gate */ 7647c478bd9Sstevel@tonic-gate mdb_nv_set_value(mdb.m_dot, f.f_dot); 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate return (0); 7677c478bd9Sstevel@tonic-gate } 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate /* 7707c478bd9Sstevel@tonic-gate * The read-side of the pipe executes this service routine. We simply call 7717c478bd9Sstevel@tonic-gate * mdb_run to create a new frame on the execution stack and run the MDB parser, 7727c478bd9Sstevel@tonic-gate * and then propagate any error code back to the previous frame. 7737c478bd9Sstevel@tonic-gate */ 7747c478bd9Sstevel@tonic-gate static int 7757c478bd9Sstevel@tonic-gate runsvc(void) 7767c478bd9Sstevel@tonic-gate { 7777c478bd9Sstevel@tonic-gate int err = mdb_run(); 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate if (err != 0) { 7807c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_DSTK, "forwarding error %s from pipeline\n", 7817c478bd9Sstevel@tonic-gate mdb_err2str(err)); 7827c478bd9Sstevel@tonic-gate longjmp(mdb.m_frame->f_pcb, err); 7837c478bd9Sstevel@tonic-gate } 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate return (err); 7867c478bd9Sstevel@tonic-gate } 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate /* 7897c478bd9Sstevel@tonic-gate * Read-side pipe service routine: if we longjmp here, just return to the read 7907c478bd9Sstevel@tonic-gate * routine because now we have more data to consume. Otherwise: 7917c478bd9Sstevel@tonic-gate * (1) if ctx_data is non-NULL, longjmp to the write-side to produce more data; 7927c478bd9Sstevel@tonic-gate * (2) if wriob is NULL, there is no writer but this is the first read, so we 7937c478bd9Sstevel@tonic-gate * can just execute mdb_run() to completion on the current stack; 7947c478bd9Sstevel@tonic-gate * (3) if (1) and (2) are false, then there is a writer and this is the first 7957c478bd9Sstevel@tonic-gate * read, so create a co-routine context to execute mdb_run(). 7967c478bd9Sstevel@tonic-gate */ 7977c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7987c478bd9Sstevel@tonic-gate static void 7997c478bd9Sstevel@tonic-gate rdsvc(mdb_iob_t *rdiob, mdb_iob_t *wriob, mdb_iob_ctx_t *ctx) 8007c478bd9Sstevel@tonic-gate { 8017c478bd9Sstevel@tonic-gate if (setjmp(ctx->ctx_rpcb) == 0) { 8027c478bd9Sstevel@tonic-gate /* 8037c478bd9Sstevel@tonic-gate * Save the current standard input into the pipe context, and 8047c478bd9Sstevel@tonic-gate * reset m_in to point to the pipe. We will restore it on 8057c478bd9Sstevel@tonic-gate * the way back in wrsvc() below. 8067c478bd9Sstevel@tonic-gate */ 8077c478bd9Sstevel@tonic-gate ctx->ctx_iob = mdb.m_in; 8087c478bd9Sstevel@tonic-gate mdb.m_in = rdiob; 8097c478bd9Sstevel@tonic-gate 8107c478bd9Sstevel@tonic-gate ctx->ctx_rptr = mdb.m_frame; 8117c478bd9Sstevel@tonic-gate if (ctx->ctx_wptr != NULL) 8127c478bd9Sstevel@tonic-gate mdb_frame_switch(ctx->ctx_wptr); 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate if (ctx->ctx_data != NULL) 8157c478bd9Sstevel@tonic-gate longjmp(ctx->ctx_wpcb, 1); 8167c478bd9Sstevel@tonic-gate else if (wriob == NULL) 8177c478bd9Sstevel@tonic-gate (void) runsvc(); 8187c478bd9Sstevel@tonic-gate else if ((ctx->ctx_data = mdb_context_create(runsvc)) != NULL) 8197c478bd9Sstevel@tonic-gate mdb_context_switch(ctx->ctx_data); 8207c478bd9Sstevel@tonic-gate else 8217c478bd9Sstevel@tonic-gate mdb_warn("failed to create pipe context"); 8227c478bd9Sstevel@tonic-gate } 8237c478bd9Sstevel@tonic-gate } 8247c478bd9Sstevel@tonic-gate 8257c478bd9Sstevel@tonic-gate /* 8267c478bd9Sstevel@tonic-gate * Write-side pipe service routine: if we longjmp here, just return to the 8277c478bd9Sstevel@tonic-gate * write routine because now we have free space in the pipe buffer for writing; 8287c478bd9Sstevel@tonic-gate * otherwise longjmp to the read-side to consume data and create space for us. 8297c478bd9Sstevel@tonic-gate */ 8307c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8317c478bd9Sstevel@tonic-gate static void 8327c478bd9Sstevel@tonic-gate wrsvc(mdb_iob_t *rdiob, mdb_iob_t *wriob, mdb_iob_ctx_t *ctx) 8337c478bd9Sstevel@tonic-gate { 8347c478bd9Sstevel@tonic-gate if (setjmp(ctx->ctx_wpcb) == 0) { 8357c478bd9Sstevel@tonic-gate ctx->ctx_wptr = mdb.m_frame; 8367c478bd9Sstevel@tonic-gate if (ctx->ctx_rptr != NULL) 8377c478bd9Sstevel@tonic-gate mdb_frame_switch(ctx->ctx_rptr); 8387c478bd9Sstevel@tonic-gate 8397c478bd9Sstevel@tonic-gate mdb.m_in = ctx->ctx_iob; 8407c478bd9Sstevel@tonic-gate longjmp(ctx->ctx_rpcb, 1); 8417c478bd9Sstevel@tonic-gate } 8427c478bd9Sstevel@tonic-gate } 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate /* 8457c478bd9Sstevel@tonic-gate * Call the current frame's mdb command. This entry point is used by the 8467c478bd9Sstevel@tonic-gate * MDB parser to actually execute a command once it has successfully parsed 8477c478bd9Sstevel@tonic-gate * a line of input. The command is waiting for us in the current frame. 8487c478bd9Sstevel@tonic-gate * We loop through each command on the list, executing its dcmd with the 8497c478bd9Sstevel@tonic-gate * appropriate argument. If the command has a successor, we know it had 8507c478bd9Sstevel@tonic-gate * a | operator after it, and so we need to create a pipe and replace 8517c478bd9Sstevel@tonic-gate * stdout with the pipe's output buffer. 8527c478bd9Sstevel@tonic-gate */ 8537c478bd9Sstevel@tonic-gate int 8547c478bd9Sstevel@tonic-gate mdb_call(uintmax_t addr, uintmax_t count, uint_t flags) 8557c478bd9Sstevel@tonic-gate { 8567c478bd9Sstevel@tonic-gate mdb_frame_t *fp = mdb.m_frame; 8577c478bd9Sstevel@tonic-gate mdb_cmd_t *cp, *ncp; 8587c478bd9Sstevel@tonic-gate mdb_iob_t *iobs[2]; 8597c478bd9Sstevel@tonic-gate int status, err = 0; 8607c478bd9Sstevel@tonic-gate jmp_buf pcb; 8617c478bd9Sstevel@tonic-gate 8627c478bd9Sstevel@tonic-gate if (mdb_iob_isapipe(mdb.m_in)) 8637c478bd9Sstevel@tonic-gate yyerror("syntax error"); 8647c478bd9Sstevel@tonic-gate 8657c478bd9Sstevel@tonic-gate mdb_intr_disable(); 8667c478bd9Sstevel@tonic-gate fp->f_cp = mdb_list_next(&fp->f_cmds); 8677c478bd9Sstevel@tonic-gate 8687c478bd9Sstevel@tonic-gate if (flags & DCMD_LOOP) 8697c478bd9Sstevel@tonic-gate flags |= DCMD_LOOPFIRST; /* set LOOPFIRST if this is a loop */ 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate for (cp = mdb_list_next(&fp->f_cmds); cp; cp = mdb_list_next(cp)) { 8727c478bd9Sstevel@tonic-gate if (mdb_list_next(cp) != NULL) { 8737c478bd9Sstevel@tonic-gate mdb_iob_pipe(iobs, rdsvc, wrsvc); 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate mdb_iob_stack_push(&fp->f_istk, mdb.m_in, yylineno); 8767c478bd9Sstevel@tonic-gate mdb.m_in = iobs[MDB_IOB_RDIOB]; 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate mdb_iob_stack_push(&fp->f_ostk, mdb.m_out, 0); 8797c478bd9Sstevel@tonic-gate mdb.m_out = iobs[MDB_IOB_WRIOB]; 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate ncp = mdb_list_next(cp); 8827c478bd9Sstevel@tonic-gate mdb_vcb_inherit(cp, ncp); 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate bcopy(fp->f_pcb, pcb, sizeof (jmp_buf)); 8857c478bd9Sstevel@tonic-gate ASSERT(fp->f_pcmd == NULL); 8867c478bd9Sstevel@tonic-gate fp->f_pcmd = ncp; 8877c478bd9Sstevel@tonic-gate 888*8a6a72fdSaf mdb_frame_set_pipe(fp); 889*8a6a72fdSaf 8907c478bd9Sstevel@tonic-gate if ((err = setjmp(fp->f_pcb)) == 0) { 8917c478bd9Sstevel@tonic-gate status = mdb_call_idcmd(cp->c_dcmd, addr, count, 8927c478bd9Sstevel@tonic-gate flags | DCMD_PIPE_OUT, &cp->c_argv, 8937c478bd9Sstevel@tonic-gate &cp->c_addrv, cp->c_vcbs); 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate ASSERT(mdb.m_in == iobs[MDB_IOB_RDIOB]); 8967c478bd9Sstevel@tonic-gate ASSERT(mdb.m_out == iobs[MDB_IOB_WRIOB]); 8977c478bd9Sstevel@tonic-gate } else { 8987c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_DSTK, "frame <%u> caught " 8997c478bd9Sstevel@tonic-gate "error %s from pipeline\n", fp->f_id, 9007c478bd9Sstevel@tonic-gate mdb_err2str(err)); 9017c478bd9Sstevel@tonic-gate } 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate if (err != 0 || DCMD_ABORTED(status)) { 9047c478bd9Sstevel@tonic-gate mdb_iob_setflags(mdb.m_in, MDB_IOB_ERR); 9057c478bd9Sstevel@tonic-gate mdb_iob_setflags(mdb.m_out, MDB_IOB_ERR); 9067c478bd9Sstevel@tonic-gate } else { 9077c478bd9Sstevel@tonic-gate mdb_iob_flush(mdb.m_out); 9087c478bd9Sstevel@tonic-gate (void) mdb_iob_ctl(mdb.m_out, I_FLUSH, 9097c478bd9Sstevel@tonic-gate (void *)FLUSHW); 9107c478bd9Sstevel@tonic-gate } 9117c478bd9Sstevel@tonic-gate 912*8a6a72fdSaf mdb_frame_clear_pipe(fp); 913*8a6a72fdSaf 9147c478bd9Sstevel@tonic-gate mdb_iob_destroy(mdb.m_out); 9157c478bd9Sstevel@tonic-gate mdb.m_out = mdb_iob_stack_pop(&fp->f_ostk); 9167c478bd9Sstevel@tonic-gate 9177c478bd9Sstevel@tonic-gate if (mdb.m_in != NULL) 9187c478bd9Sstevel@tonic-gate mdb_iob_destroy(mdb.m_in); 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate mdb.m_in = mdb_iob_stack_pop(&fp->f_istk); 9217c478bd9Sstevel@tonic-gate yylineno = mdb_iob_lineno(mdb.m_in); 9227c478bd9Sstevel@tonic-gate 9237c478bd9Sstevel@tonic-gate fp->f_pcmd = NULL; 9247c478bd9Sstevel@tonic-gate bcopy(pcb, fp->f_pcb, sizeof (jmp_buf)); 9257c478bd9Sstevel@tonic-gate 9267c478bd9Sstevel@tonic-gate if (MDB_ERR_IS_FATAL(err)) 9277c478bd9Sstevel@tonic-gate longjmp(fp->f_pcb, err); 9287c478bd9Sstevel@tonic-gate 9297c478bd9Sstevel@tonic-gate if (err != 0 || DCMD_ABORTED(status) || 9307c478bd9Sstevel@tonic-gate mdb_addrvec_length(&ncp->c_addrv) == 0) 9317c478bd9Sstevel@tonic-gate break; 9327c478bd9Sstevel@tonic-gate 9337c478bd9Sstevel@tonic-gate addr = mdb_nv_get_value(mdb.m_dot); 9347c478bd9Sstevel@tonic-gate count = 1; 9357c478bd9Sstevel@tonic-gate flags = 0; 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate } else { 9387c478bd9Sstevel@tonic-gate mdb_intr_enable(); 9397c478bd9Sstevel@tonic-gate (void) mdb_call_idcmd(cp->c_dcmd, addr, count, flags, 9407c478bd9Sstevel@tonic-gate &cp->c_argv, &cp->c_addrv, cp->c_vcbs); 9417c478bd9Sstevel@tonic-gate mdb_intr_disable(); 9427c478bd9Sstevel@tonic-gate } 9437c478bd9Sstevel@tonic-gate 9447c478bd9Sstevel@tonic-gate fp->f_cp = mdb_list_next(cp); 9457c478bd9Sstevel@tonic-gate mdb_cmd_reset(cp); 9467c478bd9Sstevel@tonic-gate } 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate /* 9497c478bd9Sstevel@tonic-gate * If our last-command list is non-empty, destroy it. Then copy the 9507c478bd9Sstevel@tonic-gate * current frame's cmd list to the m_lastc list and reset the frame. 9517c478bd9Sstevel@tonic-gate */ 9527c478bd9Sstevel@tonic-gate while ((cp = mdb_list_next(&mdb.m_lastc)) != NULL) { 9537c478bd9Sstevel@tonic-gate mdb_list_delete(&mdb.m_lastc, cp); 9547c478bd9Sstevel@tonic-gate mdb_cmd_destroy(cp); 9557c478bd9Sstevel@tonic-gate } 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate mdb_list_move(&fp->f_cmds, &mdb.m_lastc); 9587c478bd9Sstevel@tonic-gate mdb_frame_reset(fp); 9597c478bd9Sstevel@tonic-gate mdb_intr_enable(); 9607c478bd9Sstevel@tonic-gate return (err == 0); 9617c478bd9Sstevel@tonic-gate } 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate uintmax_t 9647c478bd9Sstevel@tonic-gate mdb_dot_incr(const char *op) 9657c478bd9Sstevel@tonic-gate { 9667c478bd9Sstevel@tonic-gate uintmax_t odot, ndot; 9677c478bd9Sstevel@tonic-gate 9687c478bd9Sstevel@tonic-gate odot = mdb_nv_get_value(mdb.m_dot); 9697c478bd9Sstevel@tonic-gate ndot = odot + mdb.m_incr; 9707c478bd9Sstevel@tonic-gate 9717c478bd9Sstevel@tonic-gate if ((odot ^ ndot) & 0x8000000000000000ull) 9727c478bd9Sstevel@tonic-gate yyerror("'%s' would cause '.' to overflow\n", op); 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate return (ndot); 9757c478bd9Sstevel@tonic-gate } 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate uintmax_t 9787c478bd9Sstevel@tonic-gate mdb_dot_decr(const char *op) 9797c478bd9Sstevel@tonic-gate { 9807c478bd9Sstevel@tonic-gate uintmax_t odot, ndot; 9817c478bd9Sstevel@tonic-gate 9827c478bd9Sstevel@tonic-gate odot = mdb_nv_get_value(mdb.m_dot); 9837c478bd9Sstevel@tonic-gate ndot = odot - mdb.m_incr; 9847c478bd9Sstevel@tonic-gate 9857c478bd9Sstevel@tonic-gate if (ndot > odot) 9867c478bd9Sstevel@tonic-gate yyerror("'%s' would cause '.' to underflow\n", op); 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate return (ndot); 9897c478bd9Sstevel@tonic-gate } 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate mdb_iwalker_t * 9927c478bd9Sstevel@tonic-gate mdb_walker_lookup(const char *s) 9937c478bd9Sstevel@tonic-gate { 9947c478bd9Sstevel@tonic-gate const char *p = strchr(s, '`'); 9957c478bd9Sstevel@tonic-gate mdb_var_t *v; 9967c478bd9Sstevel@tonic-gate 9977c478bd9Sstevel@tonic-gate if (p != NULL) { 9987c478bd9Sstevel@tonic-gate size_t nbytes = MIN((size_t)(p - s), MDB_NV_NAMELEN - 1); 9997c478bd9Sstevel@tonic-gate char mname[MDB_NV_NAMELEN]; 10007c478bd9Sstevel@tonic-gate mdb_module_t *mod; 10017c478bd9Sstevel@tonic-gate 10027c478bd9Sstevel@tonic-gate (void) strncpy(mname, s, nbytes); 10037c478bd9Sstevel@tonic-gate mname[nbytes] = '\0'; 10047c478bd9Sstevel@tonic-gate 10057c478bd9Sstevel@tonic-gate if ((v = mdb_nv_lookup(&mdb.m_modules, mname)) == NULL) { 10067c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NOMOD); 10077c478bd9Sstevel@tonic-gate return (NULL); 10087c478bd9Sstevel@tonic-gate } 10097c478bd9Sstevel@tonic-gate 10107c478bd9Sstevel@tonic-gate mod = mdb_nv_get_cookie(v); 10117c478bd9Sstevel@tonic-gate 10127c478bd9Sstevel@tonic-gate if ((v = mdb_nv_lookup(&mod->mod_walkers, ++p)) != NULL) 10137c478bd9Sstevel@tonic-gate return (mdb_nv_get_cookie(v)); 10147c478bd9Sstevel@tonic-gate 10157c478bd9Sstevel@tonic-gate } else if ((v = mdb_nv_lookup(&mdb.m_walkers, s)) != NULL) 10167c478bd9Sstevel@tonic-gate return (mdb_nv_get_cookie(mdb_nv_get_cookie(v))); 10177c478bd9Sstevel@tonic-gate 10187c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NOWALK); 10197c478bd9Sstevel@tonic-gate return (NULL); 10207c478bd9Sstevel@tonic-gate } 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate mdb_idcmd_t * 10237c478bd9Sstevel@tonic-gate mdb_dcmd_lookup(const char *s) 10247c478bd9Sstevel@tonic-gate { 10257c478bd9Sstevel@tonic-gate const char *p = strchr(s, '`'); 10267c478bd9Sstevel@tonic-gate mdb_var_t *v; 10277c478bd9Sstevel@tonic-gate 10287c478bd9Sstevel@tonic-gate if (p != NULL) { 10297c478bd9Sstevel@tonic-gate size_t nbytes = MIN((size_t)(p - s), MDB_NV_NAMELEN - 1); 10307c478bd9Sstevel@tonic-gate char mname[MDB_NV_NAMELEN]; 10317c478bd9Sstevel@tonic-gate mdb_module_t *mod; 10327c478bd9Sstevel@tonic-gate 10337c478bd9Sstevel@tonic-gate (void) strncpy(mname, s, nbytes); 10347c478bd9Sstevel@tonic-gate mname[nbytes] = '\0'; 10357c478bd9Sstevel@tonic-gate 10367c478bd9Sstevel@tonic-gate if ((v = mdb_nv_lookup(&mdb.m_modules, mname)) == NULL) { 10377c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NOMOD); 10387c478bd9Sstevel@tonic-gate return (NULL); 10397c478bd9Sstevel@tonic-gate } 10407c478bd9Sstevel@tonic-gate 10417c478bd9Sstevel@tonic-gate mod = mdb_nv_get_cookie(v); 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate if ((v = mdb_nv_lookup(&mod->mod_dcmds, ++p)) != NULL) 10447c478bd9Sstevel@tonic-gate return (mdb_nv_get_cookie(v)); 10457c478bd9Sstevel@tonic-gate 10467c478bd9Sstevel@tonic-gate } else if ((v = mdb_nv_lookup(&mdb.m_dcmds, s)) != NULL) 10477c478bd9Sstevel@tonic-gate return (mdb_nv_get_cookie(mdb_nv_get_cookie(v))); 10487c478bd9Sstevel@tonic-gate 10497c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NODCMD); 10507c478bd9Sstevel@tonic-gate return (NULL); 10517c478bd9Sstevel@tonic-gate } 10527c478bd9Sstevel@tonic-gate 10537c478bd9Sstevel@tonic-gate void 10547c478bd9Sstevel@tonic-gate mdb_dcmd_usage(const mdb_idcmd_t *idcp, mdb_iob_t *iob) 10557c478bd9Sstevel@tonic-gate { 10567c478bd9Sstevel@tonic-gate const char *prefix = "", *usage = ""; 10577c478bd9Sstevel@tonic-gate char name0 = idcp->idc_name[0]; 10587c478bd9Sstevel@tonic-gate 10597c478bd9Sstevel@tonic-gate if (idcp->idc_usage != NULL) { 10607c478bd9Sstevel@tonic-gate if (idcp->idc_usage[0] == ':') { 10617c478bd9Sstevel@tonic-gate if (name0 != ':' && name0 != '$') 10627c478bd9Sstevel@tonic-gate prefix = "address::"; 10637c478bd9Sstevel@tonic-gate else 10647c478bd9Sstevel@tonic-gate prefix = "address"; 10657c478bd9Sstevel@tonic-gate usage = &idcp->idc_usage[1]; 10667c478bd9Sstevel@tonic-gate 10677c478bd9Sstevel@tonic-gate } else if (idcp->idc_usage[0] == '?') { 10687c478bd9Sstevel@tonic-gate if (name0 != ':' && name0 != '$') 10697c478bd9Sstevel@tonic-gate prefix = "[address]::"; 10707c478bd9Sstevel@tonic-gate else 10717c478bd9Sstevel@tonic-gate prefix = "[address]"; 10727c478bd9Sstevel@tonic-gate usage = &idcp->idc_usage[1]; 10737c478bd9Sstevel@tonic-gate 10747c478bd9Sstevel@tonic-gate } else 10757c478bd9Sstevel@tonic-gate usage = idcp->idc_usage; 10767c478bd9Sstevel@tonic-gate } 10777c478bd9Sstevel@tonic-gate 10787c478bd9Sstevel@tonic-gate mdb_iob_printf(iob, "Usage: %s%s %s\n", prefix, idcp->idc_name, usage); 10797c478bd9Sstevel@tonic-gate 10807c478bd9Sstevel@tonic-gate if (idcp->idc_help != NULL) { 10817c478bd9Sstevel@tonic-gate mdb_iob_printf(iob, "%s: try '::help %s' for more " 10827c478bd9Sstevel@tonic-gate "information\n", mdb.m_pname, idcp->idc_name); 10837c478bd9Sstevel@tonic-gate } 10847c478bd9Sstevel@tonic-gate } 10857c478bd9Sstevel@tonic-gate 10867c478bd9Sstevel@tonic-gate static mdb_idcmd_t * 10877c478bd9Sstevel@tonic-gate dcmd_ndef(const mdb_idcmd_t *idcp) 10887c478bd9Sstevel@tonic-gate { 10897c478bd9Sstevel@tonic-gate mdb_var_t *v = mdb_nv_get_ndef(idcp->idc_var); 10907c478bd9Sstevel@tonic-gate 10917c478bd9Sstevel@tonic-gate if (v != NULL) 10927c478bd9Sstevel@tonic-gate return (mdb_nv_get_cookie(mdb_nv_get_cookie(v))); 10937c478bd9Sstevel@tonic-gate 10947c478bd9Sstevel@tonic-gate return (NULL); 10957c478bd9Sstevel@tonic-gate } 10967c478bd9Sstevel@tonic-gate 10977c478bd9Sstevel@tonic-gate static int 10987c478bd9Sstevel@tonic-gate dcmd_invoke(mdb_idcmd_t *idcp, uintptr_t addr, uint_t flags, 10997c478bd9Sstevel@tonic-gate int argc, const mdb_arg_t *argv, const mdb_vcb_t *vcbs) 11007c478bd9Sstevel@tonic-gate { 11017c478bd9Sstevel@tonic-gate int status; 11027c478bd9Sstevel@tonic-gate 11037c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_DCMD, "dcmd %s`%s dot = %lr incr = %llr\n", 11047c478bd9Sstevel@tonic-gate idcp->idc_modp->mod_name, idcp->idc_name, addr, mdb.m_incr); 11057c478bd9Sstevel@tonic-gate 11067c478bd9Sstevel@tonic-gate if ((status = idcp->idc_funcp(addr, flags, argc, argv)) == DCMD_USAGE) { 11077c478bd9Sstevel@tonic-gate mdb_dcmd_usage(idcp, mdb.m_err); 11087c478bd9Sstevel@tonic-gate goto done; 11097c478bd9Sstevel@tonic-gate } 11107c478bd9Sstevel@tonic-gate 11117c478bd9Sstevel@tonic-gate while (status == DCMD_NEXT && (idcp = dcmd_ndef(idcp)) != NULL) 11127c478bd9Sstevel@tonic-gate status = idcp->idc_funcp(addr, flags, argc, argv); 11137c478bd9Sstevel@tonic-gate 11147c478bd9Sstevel@tonic-gate if (status == DCMD_USAGE) 11157c478bd9Sstevel@tonic-gate mdb_dcmd_usage(idcp, mdb.m_err); 11167c478bd9Sstevel@tonic-gate 11177c478bd9Sstevel@tonic-gate if (status == DCMD_NEXT) 11187c478bd9Sstevel@tonic-gate status = DCMD_OK; 11197c478bd9Sstevel@tonic-gate done: 11207c478bd9Sstevel@tonic-gate /* 11217c478bd9Sstevel@tonic-gate * If standard output is a pipe and there are vcbs active, we need to 11227c478bd9Sstevel@tonic-gate * flush standard out and the write-side of the pipe. The reasons for 11237c478bd9Sstevel@tonic-gate * this are explained in more detail in mdb_vcb.c. 11247c478bd9Sstevel@tonic-gate */ 11257c478bd9Sstevel@tonic-gate if ((flags & DCMD_PIPE_OUT) && (vcbs != NULL)) { 11267c478bd9Sstevel@tonic-gate mdb_iob_flush(mdb.m_out); 11277c478bd9Sstevel@tonic-gate (void) mdb_iob_ctl(mdb.m_out, I_FLUSH, (void *)FLUSHW); 11287c478bd9Sstevel@tonic-gate } 11297c478bd9Sstevel@tonic-gate 11307c478bd9Sstevel@tonic-gate return (status); 11317c478bd9Sstevel@tonic-gate } 11327c478bd9Sstevel@tonic-gate 11337c478bd9Sstevel@tonic-gate /* 11347c478bd9Sstevel@tonic-gate * Call an internal dcmd directly: this code is used by module API functions 11357c478bd9Sstevel@tonic-gate * that need to execute dcmds, and by mdb_call() above. 11367c478bd9Sstevel@tonic-gate */ 11377c478bd9Sstevel@tonic-gate int 11387c478bd9Sstevel@tonic-gate mdb_call_idcmd(mdb_idcmd_t *idcp, uintmax_t addr, uintmax_t count, 11397c478bd9Sstevel@tonic-gate uint_t flags, mdb_argvec_t *avp, mdb_addrvec_t *adp, mdb_vcb_t *vcbs) 11407c478bd9Sstevel@tonic-gate { 11417c478bd9Sstevel@tonic-gate int is_exec = (strcmp(idcp->idc_name, "$<") == 0); 11427c478bd9Sstevel@tonic-gate mdb_arg_t *argv; 11437c478bd9Sstevel@tonic-gate int argc; 11447c478bd9Sstevel@tonic-gate uintmax_t i; 11457c478bd9Sstevel@tonic-gate int status; 11467c478bd9Sstevel@tonic-gate 11477c478bd9Sstevel@tonic-gate /* 11487c478bd9Sstevel@tonic-gate * Update the values of dot and the most recent address and count 11497c478bd9Sstevel@tonic-gate * to the values of our input parameters. 11507c478bd9Sstevel@tonic-gate */ 11517c478bd9Sstevel@tonic-gate mdb_nv_set_value(mdb.m_dot, addr); 11527c478bd9Sstevel@tonic-gate mdb.m_raddr = addr; 11537c478bd9Sstevel@tonic-gate mdb.m_dcount = count; 11547c478bd9Sstevel@tonic-gate 11557c478bd9Sstevel@tonic-gate /* 11567c478bd9Sstevel@tonic-gate * Here the adb(1) man page lies: '9' is only set to count 11577c478bd9Sstevel@tonic-gate * when the command is $<, not when it's $<<. 11587c478bd9Sstevel@tonic-gate */ 11597c478bd9Sstevel@tonic-gate if (is_exec) 11607c478bd9Sstevel@tonic-gate mdb_nv_set_value(mdb.m_rcount, count); 11617c478bd9Sstevel@tonic-gate 11627c478bd9Sstevel@tonic-gate /* 11637c478bd9Sstevel@tonic-gate * We can now return if the repeat count is zero. 11647c478bd9Sstevel@tonic-gate */ 11657c478bd9Sstevel@tonic-gate if (count == 0) 11667c478bd9Sstevel@tonic-gate return (DCMD_OK); 11677c478bd9Sstevel@tonic-gate 11687c478bd9Sstevel@tonic-gate /* 11697c478bd9Sstevel@tonic-gate * To guard against bad dcmds, we avoid passing the actual argv that 11707c478bd9Sstevel@tonic-gate * we will use to free argument strings directly to the dcmd. Instead, 11717c478bd9Sstevel@tonic-gate * we pass a copy that will be garbage collected automatically. 11727c478bd9Sstevel@tonic-gate */ 11737c478bd9Sstevel@tonic-gate argc = avp->a_nelems; 11747c478bd9Sstevel@tonic-gate argv = mdb_alloc(sizeof (mdb_arg_t) * argc, UM_SLEEP | UM_GC); 11757c478bd9Sstevel@tonic-gate bcopy(avp->a_data, argv, sizeof (mdb_arg_t) * argc); 11767c478bd9Sstevel@tonic-gate 11777c478bd9Sstevel@tonic-gate if (mdb_addrvec_length(adp) != 0) { 11787c478bd9Sstevel@tonic-gate flags |= DCMD_PIPE | DCMD_LOOP | DCMD_LOOPFIRST | DCMD_ADDRSPEC; 11797c478bd9Sstevel@tonic-gate addr = mdb_addrvec_shift(adp); 11807c478bd9Sstevel@tonic-gate mdb_nv_set_value(mdb.m_dot, addr); 11817c478bd9Sstevel@tonic-gate mdb_vcb_propagate(vcbs); 11827c478bd9Sstevel@tonic-gate count = 1; 11837c478bd9Sstevel@tonic-gate } 11847c478bd9Sstevel@tonic-gate 11857c478bd9Sstevel@tonic-gate status = dcmd_invoke(idcp, addr, flags, argc, argv, vcbs); 11867c478bd9Sstevel@tonic-gate if (DCMD_ABORTED(status)) 11877c478bd9Sstevel@tonic-gate goto done; 11887c478bd9Sstevel@tonic-gate 11897c478bd9Sstevel@tonic-gate /* 11907c478bd9Sstevel@tonic-gate * If the command is $< and we're not receiving input from a pipe, we 11917c478bd9Sstevel@tonic-gate * ignore the repeat count and just return since the macro file is now 11927c478bd9Sstevel@tonic-gate * pushed on to the input stack. 11937c478bd9Sstevel@tonic-gate */ 11947c478bd9Sstevel@tonic-gate if (is_exec && mdb_addrvec_length(adp) == 0) 11957c478bd9Sstevel@tonic-gate goto done; 11967c478bd9Sstevel@tonic-gate 11977c478bd9Sstevel@tonic-gate /* 11987c478bd9Sstevel@tonic-gate * If we're going to loop, we've already executed the dcmd once, 11997c478bd9Sstevel@tonic-gate * so clear the LOOPFIRST flag before proceeding. 12007c478bd9Sstevel@tonic-gate */ 12017c478bd9Sstevel@tonic-gate if (flags & DCMD_LOOP) 12027c478bd9Sstevel@tonic-gate flags &= ~DCMD_LOOPFIRST; 12037c478bd9Sstevel@tonic-gate 12047c478bd9Sstevel@tonic-gate for (i = 1; i < count; i++) { 12057c478bd9Sstevel@tonic-gate addr = mdb_dot_incr(","); 12067c478bd9Sstevel@tonic-gate mdb_nv_set_value(mdb.m_dot, addr); 12077c478bd9Sstevel@tonic-gate status = dcmd_invoke(idcp, addr, flags, argc, argv, vcbs); 12087c478bd9Sstevel@tonic-gate if (DCMD_ABORTED(status)) 12097c478bd9Sstevel@tonic-gate goto done; 12107c478bd9Sstevel@tonic-gate } 12117c478bd9Sstevel@tonic-gate 12127c478bd9Sstevel@tonic-gate while (mdb_addrvec_length(adp) != 0) { 12137c478bd9Sstevel@tonic-gate addr = mdb_addrvec_shift(adp); 12147c478bd9Sstevel@tonic-gate mdb_nv_set_value(mdb.m_dot, addr); 12157c478bd9Sstevel@tonic-gate mdb_vcb_propagate(vcbs); 12167c478bd9Sstevel@tonic-gate status = dcmd_invoke(idcp, addr, flags, argc, argv, vcbs); 12177c478bd9Sstevel@tonic-gate if (DCMD_ABORTED(status)) 12187c478bd9Sstevel@tonic-gate goto done; 12197c478bd9Sstevel@tonic-gate } 12207c478bd9Sstevel@tonic-gate done: 12217c478bd9Sstevel@tonic-gate mdb_iob_nlflush(mdb.m_out); 12227c478bd9Sstevel@tonic-gate return (status); 12237c478bd9Sstevel@tonic-gate } 12247c478bd9Sstevel@tonic-gate 12257c478bd9Sstevel@tonic-gate void 12267c478bd9Sstevel@tonic-gate mdb_intr_enable(void) 12277c478bd9Sstevel@tonic-gate { 12287c478bd9Sstevel@tonic-gate ASSERT(mdb.m_intr >= 1); 12297c478bd9Sstevel@tonic-gate if (mdb.m_intr == 1 && mdb.m_pend != 0) { 12307c478bd9Sstevel@tonic-gate (void) mdb_signal_block(SIGINT); 12317c478bd9Sstevel@tonic-gate mdb.m_intr = mdb.m_pend = 0; 12327c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_DSTK, "delivering pending INT\n"); 12337c478bd9Sstevel@tonic-gate longjmp(mdb.m_frame->f_pcb, MDB_ERR_SIGINT); 12347c478bd9Sstevel@tonic-gate } else 12357c478bd9Sstevel@tonic-gate mdb.m_intr--; 12367c478bd9Sstevel@tonic-gate } 12377c478bd9Sstevel@tonic-gate 12387c478bd9Sstevel@tonic-gate void 12397c478bd9Sstevel@tonic-gate mdb_intr_disable(void) 12407c478bd9Sstevel@tonic-gate { 12417c478bd9Sstevel@tonic-gate mdb.m_intr++; 12427c478bd9Sstevel@tonic-gate ASSERT(mdb.m_intr >= 1); 12437c478bd9Sstevel@tonic-gate } 12447c478bd9Sstevel@tonic-gate 12457c478bd9Sstevel@tonic-gate /* 12467c478bd9Sstevel@tonic-gate * Create an encoded string representing the internal user-modifiable 12477c478bd9Sstevel@tonic-gate * configuration of the debugger and return a pointer to it. The string can be 12487c478bd9Sstevel@tonic-gate * used to initialize another instance of the debugger with the same 12497c478bd9Sstevel@tonic-gate * configuration as this one. 12507c478bd9Sstevel@tonic-gate */ 12517c478bd9Sstevel@tonic-gate char * 12527c478bd9Sstevel@tonic-gate mdb_get_config(void) 12537c478bd9Sstevel@tonic-gate { 12547c478bd9Sstevel@tonic-gate size_t r, n = 0; 12557c478bd9Sstevel@tonic-gate char *s = NULL; 12567c478bd9Sstevel@tonic-gate 12577c478bd9Sstevel@tonic-gate while ((r = mdb_snprintf(s, n, 12587c478bd9Sstevel@tonic-gate "%x;%x;%x;%x;%x;%x;%lx;%x;%x;%s;%s;%s;%s;%s", 12597c478bd9Sstevel@tonic-gate mdb.m_tgtflags, mdb.m_flags, mdb.m_debug, mdb.m_radix, mdb.m_nargs, 12607c478bd9Sstevel@tonic-gate mdb.m_histlen, (ulong_t)mdb.m_symdist, mdb.m_execmode, 12617c478bd9Sstevel@tonic-gate mdb.m_forkmode, mdb.m_root, mdb.m_termtype, mdb.m_ipathstr, 12627c478bd9Sstevel@tonic-gate mdb.m_lpathstr, mdb.m_prompt)) > n) { 12637c478bd9Sstevel@tonic-gate 12647c478bd9Sstevel@tonic-gate mdb_free(s, n); 12657c478bd9Sstevel@tonic-gate n = r + 1; 12667c478bd9Sstevel@tonic-gate s = mdb_alloc(r + 1, UM_SLEEP); 12677c478bd9Sstevel@tonic-gate } 12687c478bd9Sstevel@tonic-gate 12697c478bd9Sstevel@tonic-gate return (s); 12707c478bd9Sstevel@tonic-gate } 12717c478bd9Sstevel@tonic-gate 12727c478bd9Sstevel@tonic-gate /* 12737c478bd9Sstevel@tonic-gate * Decode a configuration string created with mdb_get_config() and reset the 12747c478bd9Sstevel@tonic-gate * appropriate parts of the global mdb_t accordingly. 12757c478bd9Sstevel@tonic-gate */ 12767c478bd9Sstevel@tonic-gate void 12777c478bd9Sstevel@tonic-gate mdb_set_config(const char *s) 12787c478bd9Sstevel@tonic-gate { 12797c478bd9Sstevel@tonic-gate const char *p; 12807c478bd9Sstevel@tonic-gate size_t len; 12817c478bd9Sstevel@tonic-gate 12827c478bd9Sstevel@tonic-gate if ((p = strchr(s, ';')) != NULL) { 12837c478bd9Sstevel@tonic-gate mdb.m_tgtflags = strntoul(s, (size_t)(p - s), 16); 12847c478bd9Sstevel@tonic-gate s = p + 1; 12857c478bd9Sstevel@tonic-gate } 12867c478bd9Sstevel@tonic-gate 12877c478bd9Sstevel@tonic-gate if ((p = strchr(s, ';')) != NULL) { 12887c478bd9Sstevel@tonic-gate mdb.m_flags = strntoul(s, (size_t)(p - s), 16); 12897c478bd9Sstevel@tonic-gate mdb.m_flags &= ~(MDB_FL_LOG | MDB_FL_LATEST); 12907c478bd9Sstevel@tonic-gate s = p + 1; 12917c478bd9Sstevel@tonic-gate } 12927c478bd9Sstevel@tonic-gate 12937c478bd9Sstevel@tonic-gate if ((p = strchr(s, ';')) != NULL) { 12947c478bd9Sstevel@tonic-gate mdb.m_debug = strntoul(s, (size_t)(p - s), 16); 12957c478bd9Sstevel@tonic-gate s = p + 1; 12967c478bd9Sstevel@tonic-gate } 12977c478bd9Sstevel@tonic-gate 12987c478bd9Sstevel@tonic-gate if ((p = strchr(s, ';')) != NULL) { 12997c478bd9Sstevel@tonic-gate mdb.m_radix = (int)strntoul(s, (size_t)(p - s), 16); 13007c478bd9Sstevel@tonic-gate if (mdb.m_radix < 2 || mdb.m_radix > 16) 13017c478bd9Sstevel@tonic-gate mdb.m_radix = MDB_DEF_RADIX; 13027c478bd9Sstevel@tonic-gate s = p + 1; 13037c478bd9Sstevel@tonic-gate } 13047c478bd9Sstevel@tonic-gate 13057c478bd9Sstevel@tonic-gate if ((p = strchr(s, ';')) != NULL) { 13067c478bd9Sstevel@tonic-gate mdb.m_nargs = (int)strntoul(s, (size_t)(p - s), 16); 13077c478bd9Sstevel@tonic-gate mdb.m_nargs = MAX(mdb.m_nargs, 0); 13087c478bd9Sstevel@tonic-gate s = p + 1; 13097c478bd9Sstevel@tonic-gate } 13107c478bd9Sstevel@tonic-gate 13117c478bd9Sstevel@tonic-gate if ((p = strchr(s, ';')) != NULL) { 13127c478bd9Sstevel@tonic-gate mdb.m_histlen = (int)strntoul(s, (size_t)(p - s), 16); 13137c478bd9Sstevel@tonic-gate mdb.m_histlen = MAX(mdb.m_histlen, 1); 13147c478bd9Sstevel@tonic-gate s = p + 1; 13157c478bd9Sstevel@tonic-gate } 13167c478bd9Sstevel@tonic-gate 13177c478bd9Sstevel@tonic-gate if ((p = strchr(s, ';')) != NULL) { 13187c478bd9Sstevel@tonic-gate mdb.m_symdist = strntoul(s, (size_t)(p - s), 16); 13197c478bd9Sstevel@tonic-gate s = p + 1; 13207c478bd9Sstevel@tonic-gate } 13217c478bd9Sstevel@tonic-gate 13227c478bd9Sstevel@tonic-gate if ((p = strchr(s, ';')) != NULL) { 13237c478bd9Sstevel@tonic-gate mdb.m_execmode = (uchar_t)strntoul(s, (size_t)(p - s), 16); 13247c478bd9Sstevel@tonic-gate if (mdb.m_execmode > MDB_EM_FOLLOW) 13257c478bd9Sstevel@tonic-gate mdb.m_execmode = MDB_EM_ASK; 13267c478bd9Sstevel@tonic-gate s = p + 1; 13277c478bd9Sstevel@tonic-gate } 13287c478bd9Sstevel@tonic-gate 13297c478bd9Sstevel@tonic-gate if ((p = strchr(s, ';')) != NULL) { 13307c478bd9Sstevel@tonic-gate mdb.m_forkmode = (uchar_t)strntoul(s, (size_t)(p - s), 16); 13317c478bd9Sstevel@tonic-gate if (mdb.m_forkmode > MDB_FM_CHILD) 13327c478bd9Sstevel@tonic-gate mdb.m_forkmode = MDB_FM_ASK; 13337c478bd9Sstevel@tonic-gate s = p + 1; 13347c478bd9Sstevel@tonic-gate } 13357c478bd9Sstevel@tonic-gate 13367c478bd9Sstevel@tonic-gate if ((p = strchr(s, ';')) != NULL) { 13377c478bd9Sstevel@tonic-gate mdb.m_root = strndup(s, (size_t)(p - s)); 13387c478bd9Sstevel@tonic-gate s = p + 1; 13397c478bd9Sstevel@tonic-gate } 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate if ((p = strchr(s, ';')) != NULL) { 13427c478bd9Sstevel@tonic-gate mdb.m_termtype = strndup(s, (size_t)(p - s)); 13437c478bd9Sstevel@tonic-gate s = p + 1; 13447c478bd9Sstevel@tonic-gate } 13457c478bd9Sstevel@tonic-gate 13467c478bd9Sstevel@tonic-gate if ((p = strchr(s, ';')) != NULL) { 13477c478bd9Sstevel@tonic-gate size_t len = MIN(sizeof (mdb.m_ipathstr) - 1, p - s); 13487c478bd9Sstevel@tonic-gate strncpy(mdb.m_ipathstr, s, len); 13497c478bd9Sstevel@tonic-gate mdb.m_ipathstr[len] = '\0'; 13507c478bd9Sstevel@tonic-gate s = p + 1; 13517c478bd9Sstevel@tonic-gate } 13527c478bd9Sstevel@tonic-gate 13537c478bd9Sstevel@tonic-gate if ((p = strchr(s, ';')) != NULL) { 13547c478bd9Sstevel@tonic-gate size_t len = MIN(sizeof (mdb.m_lpathstr) - 1, p - s); 13557c478bd9Sstevel@tonic-gate strncpy(mdb.m_lpathstr, s, len); 13567c478bd9Sstevel@tonic-gate mdb.m_lpathstr[len] = '\0'; 13577c478bd9Sstevel@tonic-gate s = p + 1; 13587c478bd9Sstevel@tonic-gate } 13597c478bd9Sstevel@tonic-gate 13607c478bd9Sstevel@tonic-gate p = s + strlen(s); 13617c478bd9Sstevel@tonic-gate len = MIN(MDB_PROMPTLEN, (size_t)(p - s)); 13627c478bd9Sstevel@tonic-gate (void) strncpy(mdb.m_prompt, s, len); 13637c478bd9Sstevel@tonic-gate mdb.m_prompt[len] = '\0'; 13647c478bd9Sstevel@tonic-gate mdb.m_promptlen = len; 13657c478bd9Sstevel@tonic-gate } 13667c478bd9Sstevel@tonic-gate 13677c478bd9Sstevel@tonic-gate mdb_module_t * 13687c478bd9Sstevel@tonic-gate mdb_get_module(void) 13697c478bd9Sstevel@tonic-gate { 13707c478bd9Sstevel@tonic-gate if (mdb.m_lmod) 13717c478bd9Sstevel@tonic-gate return (mdb.m_lmod); 13727c478bd9Sstevel@tonic-gate 13737c478bd9Sstevel@tonic-gate if (mdb.m_frame && mdb.m_frame->f_cp && mdb.m_frame->f_cp->c_dcmd) 13747c478bd9Sstevel@tonic-gate return (mdb.m_frame->f_cp->c_dcmd->idc_modp); 13757c478bd9Sstevel@tonic-gate 13767c478bd9Sstevel@tonic-gate return (NULL); 13777c478bd9Sstevel@tonic-gate } 1378