Home | History | Annotate | Download | only in mdb
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*
     27  * MDB Target Layer
     28  *
     29  * The *target* is the program being inspected by the debugger.  The MDB target
     30  * layer provides a set of functions that insulate common debugger code,
     31  * including the MDB Module API, from the implementation details of how the
     32  * debugger accesses information from a given target.  Each target exports a
     33  * standard set of properties, including one or more address  spaces, one or
     34  * more symbol tables, a set of load objects, and a set of threads that can be
     35  * examined using the interfaces in <mdb/mdb_target.h>.  This technique has
     36  * been employed successfully in other debuggers, including [1], primarily
     37  * to improve portability, although the term "target" often refers to the
     38  * encapsulation of architectural or operating system-specific details.  The
     39  * target abstraction is useful for MDB because it allows us to easily extend
     40  * the debugger to examine a variety of different program forms.  Primarily,
     41  * the target functions validate input arguments and then call an appropriate
     42  * function in the target ops vector, defined in <mdb/mdb_target_impl.h>.
     43  * However, this interface layer provides a very high level of flexibility for
     44  * separating the debugger interface from instrumentation details.  Experience
     45  * has shown this kind of design can facilitate separating out debugger
     46  * instrumentation into an external agent [2] and enable the development of
     47  * advanced instrumentation frameworks [3].  We want MDB to be an ideal
     48  * extensible framework for the development of such applications.
     49  *
     50  * Aside from a set of wrapper functions, the target layer also provides event
     51  * management for targets that represent live executing programs.  Our model of
     52  * events is also extensible, and is based upon work in [3] and [4].  We define
     53  * a *software event* as a state transition in the target program (for example,
     54  * the transition of the program counter to a location of interest) that is
     55  * observed by the debugger or its agent.  A *software event specifier* is a
     56  * description of a class of software events that is used by the debugger to
     57  * instrument the target so that the corresponding software events can be
     58  * observed.  In MDB, software event specifiers are represented by the
     59  * mdb_sespec_t structure, defined in <mdb/mdb_target_impl.h>.  As the user,
     60  * the internal debugger code, and MDB modules may all wish to observe software
     61  * events and receive appropriate notification and callbacks, we do not expose
     62  * software event specifiers directly as part of the user interface.  Instead,
     63  * clients of the target layer request that events be observed by creating
     64  * new *virtual event specifiers*.  Each virtual specifier is named by a unique
     65  * non-zero integer (the VID), and is represented by a mdb_vespec_t structure.
     66  * One or more virtual specifiers are then associated with each underlying
     67  * software event specifier.  This design enforces the constraint that the
     68  * target must only insert one set of instrumentation, regardless of how many
     69  * times the target layer was asked to trace a given event.  For example, if
     70  * multiple clients request a breakpoint at a particular address, the virtual
     71  * specifiers will map to the same sespec, ensuring that only one breakpoint
     72  * trap instruction is actually planted at the given target address.  When no
     73  * virtual specifiers refer to an sespec, it is no longer needed and can be
     74  * removed, along with the corresponding instrumentation.
     75  *
     76  * The following state transition diagram illustrates the life cycle of a
     77  * software event specifier and example transitions:
     78  *
     79  *                                         cont/
     80  *     +--------+   delete   +--------+    stop    +-------+
     81  *    (|( DEAD )|) <------- (  ACTIVE  ) <------> (  ARMED  )
     82  *     +--------+            +--------+            +-------+
     83  *          ^   load/unload  ^        ^   failure/     |
     84  *   delete |        object /          \  reset        | failure
     85  *          |              v            v              |
     86  *          |      +--------+          +-------+       |
     87  *          +---- (   IDLE   )        (   ERR   ) <----+
     88  *          |      +--------+          +-------+
     89  *          |                              |
     90  *          +------------------------------+
     91  *
     92  * The MDB execution control model is based upon the synchronous debugging
     93  * model exported by Solaris proc(4).  A target program is set running or the
     94  * debugger is attached to a running target.  On ISTOP (stop on event of
     95  * interest), one target thread is selected as the representative.  The
     96  * algorithm for selecting the representative is target-specific, but we assume
     97  * that if an observed software event has occurred, the target will select the
     98  * thread that triggered the state transition of interest.  The other threads
     99  * are stopped in sympathy with the representative as soon as possible.  Prior
    100  * to continuing the target, we plant our instrumentation, transitioning event
    101  * specifiers from the ACTIVE to the ARMED state, and then back again when the
    102  * target stops.  We then query each active event specifier to learn which ones
    103  * are matched, and then invoke the callbacks associated with their vespecs.
    104  * If an OS error occurs while attempting to arm or disarm a specifier, the
    105  * specifier is transitioned to the ERROR state; we will attempt to arm it
    106  * again at the next continue.  If no target process is under our control or
    107  * if an event is not currently applicable (e.g. a deferred breakpoint on an
    108  * object that is not yet loaded), it remains in the IDLE state.  The target
    109  * implementation should intercept object load events and then transition the
    110  * specifier to the ACTIVE state when the corresponding object is loaded.
    111  *
    112  * To simplify the debugger implementation and allow targets to easily provide
    113  * new types of observable events, most of the event specifier management is
    114  * done by the target layer.  Each software event specifier provides an ops
    115  * vector of subroutines that the target layer can call to perform the
    116  * various state transitions described above.  The target maintains two lists
    117  * of mdb_sespec_t's: the t_idle list (IDLE state) and the t_active list
    118  * (ACTIVE, ARMED, and ERROR states).  Each mdb_sespec_t maintains a list of
    119  * associated mdb_vespec_t's.  If an sespec is IDLE or ERROR, its se_errno
    120  * field will have an errno value specifying the reason for its inactivity.
    121  * The vespec stores the client's callback function and private data, and the
    122  * arguments used to construct the sespec.  All objects are reference counted
    123  * so we can destroy an object when it is no longer needed.  The mdb_sespec_t
    124  * invariants for the respective states are as follows:
    125  *
    126  *   IDLE: on t_idle list, se_data == NULL, se_errno != 0, se_ctor not called
    127  * ACTIVE: on t_active list, se_data valid, se_errno == 0, se_ctor called
    128  *  ARMED: on t_active list, se_data valid, se_errno == 0, se_ctor called
    129  *  ERROR: on t_active list, se_data valid, se_errno != 0, se_ctor called
    130  *
    131  * Additional commentary on specific state transitions and issues involving
    132  * event management can be found below near the target layer functions.
    133  *
    134  * References
    135  *
    136  * [1] John Gilmore, "Working in GDB", Technical Report, Cygnus Support,
    137  *     1.84 edition, 1994.
    138  *
    139  * [2] David R. Hanson and Mukund Raghavachari, "A Machine-Independent
    140  *     Debugger", Software--Practice and Experience, 26(11), 1277-1299(1996).
    141  *
    142  * [3] Michael W. Shapiro, "RDB: A System for Incremental Replay Debugging",
    143  *     Technical Report CS-97-12, Department of Computer Science,
    144  *     Brown University.
    145  *
    146  * [4] Daniel B. Price, "New Techniques for Replay Debugging", Technical
    147  *     Report CS-98-05, Department of Computer Science, Brown University.
    148  */
    149 
    150 #include <mdb/mdb_target_impl.h>
    151 #include <mdb/mdb_debug.h>
    152 #include <mdb/mdb_modapi.h>
    153 #include <mdb/mdb_err.h>
    154 #include <mdb/mdb_callb.h>
    155 #include <mdb/mdb_gelf.h>
    156 #include <mdb/mdb_io_impl.h>
    157 #include <mdb/mdb_string.h>
    158 #include <mdb/mdb_signal.h>
    159 #include <mdb/mdb_frame.h>
    160 #include <mdb/mdb.h>
    161 
    162 #include <sys/stat.h>
    163 #include <sys/param.h>
    164 #include <sys/signal.h>
    165 #include <strings.h>
    166 #include <stdlib.h>
    167 #include <errno.h>
    168 
    169 /*
    170  * Define convenience macros for referencing the set of vespec flag bits that
    171  * are preserved by the target implementation, and the set of bits that
    172  * determine automatic ve_hits == ve_limit behavior.
    173  */
    174 #define	T_IMPL_BITS	\
    175 	(MDB_TGT_SPEC_INTERNAL | MDB_TGT_SPEC_SILENT | MDB_TGT_SPEC_MATCHED | \
    176 	MDB_TGT_SPEC_DELETED)
    177 
    178 #define	T_AUTO_BITS	\
    179 	(MDB_TGT_SPEC_AUTOSTOP | MDB_TGT_SPEC_AUTODEL | MDB_TGT_SPEC_AUTODIS)
    180 
    181 /*
    182  * Define convenience macro for referencing target flag pending continue bits.
    183  */
    184 #define	T_CONT_BITS	\
    185 	(MDB_TGT_F_STEP | MDB_TGT_F_STEP_OUT | MDB_TGT_F_STEP_BRANCH | \
    186 	MDB_TGT_F_NEXT | MDB_TGT_F_CONT)
    187 
    188 mdb_tgt_t *
    189 mdb_tgt_create(mdb_tgt_ctor_f *ctor, int flags, int argc, const char *argv[])
    190 {
    191 	mdb_module_t *mp;
    192 	mdb_tgt_t *t;
    193 
    194 	if (flags & ~MDB_TGT_F_ALL) {
    195 		(void) set_errno(EINVAL);
    196 		return (NULL);
    197 	}
    198 
    199 	t = mdb_zalloc(sizeof (mdb_tgt_t), UM_SLEEP);
    200 	mdb_list_append(&mdb.m_tgtlist, t);
    201 
    202 	t->t_module = &mdb.m_rmod;
    203 	t->t_matched = T_SE_END;
    204 	t->t_flags = flags;
    205 	t->t_vepos = 1;
    206 	t->t_veneg = 1;
    207 
    208 	for (mp = mdb.m_mhead; mp != NULL; mp = mp->mod_next) {
    209 		if (ctor == mp->mod_tgt_ctor) {
    210 			t->t_module = mp;
    211 			break;
    212 		}
    213 	}
    214 
    215 	if (ctor(t, argc, argv) != 0) {
    216 		mdb_list_delete(&mdb.m_tgtlist, t);
    217 		mdb_free(t, sizeof (mdb_tgt_t));
    218 		return (NULL);
    219 	}
    220 
    221 	mdb_dprintf(MDB_DBG_TGT, "t_create %s (%p)\n",
    222 	    t->t_module->mod_name, (void *)t);
    223 
    224 	(void) t->t_ops->t_status(t, &t->t_status);
    225 	return (t);
    226 }
    227 
    228 int
    229 mdb_tgt_getflags(mdb_tgt_t *t)
    230 {
    231 	return (t->t_flags);
    232 }
    233 
    234 int
    235 mdb_tgt_setflags(mdb_tgt_t *t, int flags)
    236 {
    237 	if (flags & ~MDB_TGT_F_ALL)
    238 		return (set_errno(EINVAL));
    239 
    240 	return (t->t_ops->t_setflags(t, flags));
    241 }
    242 
    243 int
    244 mdb_tgt_setcontext(mdb_tgt_t *t, void *context)
    245 {
    246 	return (t->t_ops->t_setcontext(t, context));
    247 }
    248 
    249 /*ARGSUSED*/
    250 static int
    251 tgt_delete_vespec(mdb_tgt_t *t, void *private, int vid, void *data)
    252 {
    253 	(void) mdb_tgt_vespec_delete(t, vid);
    254 	return (0);
    255 }
    256 
    257 void
    258 mdb_tgt_destroy(mdb_tgt_t *t)
    259 {
    260 	mdb_xdata_t *xdp, *nxdp;
    261 
    262 	if (mdb.m_target == t) {
    263 		mdb_dprintf(MDB_DBG_TGT, "t_deactivate %s (%p)\n",
    264 		    t->t_module->mod_name, (void *)t);
    265 		t->t_ops->t_deactivate(t);
    266 		mdb.m_target = NULL;
    267 	}
    268 
    269 	mdb_dprintf(MDB_DBG_TGT, "t_destroy %s (%p)\n",
    270 	    t->t_module->mod_name, (void *)t);
    271 
    272 	for (xdp = mdb_list_next(&t->t_xdlist); xdp != NULL; xdp = nxdp) {
    273 		nxdp = mdb_list_next(xdp);
    274 		mdb_list_delete(&t->t_xdlist, xdp);
    275 		mdb_free(xdp, sizeof (mdb_xdata_t));
    276 	}
    277 
    278 	mdb_tgt_sespec_idle_all(t, EBUSY, TRUE);
    279 	(void) mdb_tgt_vespec_iter(t, tgt_delete_vespec, NULL);
    280 	t->t_ops->t_destroy(t);
    281 
    282 	mdb_list_delete(&mdb.m_tgtlist, t);
    283 	mdb_free(t, sizeof (mdb_tgt_t));
    284 
    285 	if (mdb.m_target == NULL)
    286 		mdb_tgt_activate(mdb_list_prev(&mdb.m_tgtlist));
    287 }
    288 
    289 void
    290 mdb_tgt_activate(mdb_tgt_t *t)
    291 {
    292 	mdb_tgt_t *otgt = mdb.m_target;
    293 
    294 	if (mdb.m_target != NULL) {
    295 		mdb_dprintf(MDB_DBG_TGT, "t_deactivate %s (%p)\n",
    296 		    mdb.m_target->t_module->mod_name, (void *)mdb.m_target);
    297 		mdb.m_target->t_ops->t_deactivate(mdb.m_target);
    298 	}
    299 
    300 	if ((mdb.m_target = t) != NULL) {
    301 		const char *v = strstr(mdb.m_root, "%V");
    302 
    303 		mdb_dprintf(MDB_DBG_TGT, "t_activate %s (%p)\n",
    304 		    t->t_module->mod_name, (void *)t);
    305 
    306 		/*
    307 		 * If the root was explicitly set with -R and contains %V,
    308 		 * expand it like a path.  If the resulting directory is
    309 		 * not present, then replace %V with "latest" and re-evaluate.
    310 		 */
    311 		if (v != NULL) {
    312 			char old_root[MAXPATHLEN];
    313 			const char **p;
    314 #ifndef _KMDB
    315 			struct stat s;
    316 #endif
    317 			size_t len;
    318 
    319 			p = mdb_path_alloc(mdb.m_root, &len);
    320 			(void) strcpy(old_root, mdb.m_root);
    321 			(void) strncpy(mdb.m_root, p[0], MAXPATHLEN);
    322 			mdb.m_root[MAXPATHLEN - 1] = '\0';
    323 			mdb_path_free(p, len);
    324 
    325 #ifndef _KMDB
    326 			if (stat(mdb.m_root, &s) == -1 && errno == ENOENT) {
    327 				mdb.m_flags |= MDB_FL_LATEST;
    328 				p = mdb_path_alloc(old_root, &len);
    329 				(void) strncpy(mdb.m_root, p[0], MAXPATHLEN);
    330 				mdb.m_root[MAXPATHLEN - 1] = '\0';
    331 				mdb_path_free(p, len);
    332 			}
    333 #endif
    334 		}
    335 
    336 		/*
    337 		 * Re-evaluate the macro and dmod paths now that we have the
    338 		 * new target set and m_root figured out.
    339 		 */
    340 		if (otgt == NULL) {
    341 			mdb_set_ipath(mdb.m_ipathstr);
    342 			mdb_set_lpath(mdb.m_lpathstr);
    343 		}
    344 
    345 		t->t_ops->t_activate(t);
    346 	}
    347 }
    348 
    349 void
    350 mdb_tgt_periodic(mdb_tgt_t *t)
    351 {
    352 	t->t_ops->t_periodic(t);
    353 }
    354 
    355 const char *
    356 mdb_tgt_name(mdb_tgt_t *t)
    357 {
    358 	return (t->t_ops->t_name(t));
    359 }
    360 
    361 const char *
    362 mdb_tgt_isa(mdb_tgt_t *t)
    363 {
    364 	return (t->t_ops->t_isa(t));
    365 }
    366 
    367 const char *
    368 mdb_tgt_platform(mdb_tgt_t *t)
    369 {
    370 	return (t->t_ops->t_platform(t));
    371 }
    372 
    373 int
    374 mdb_tgt_uname(mdb_tgt_t *t, struct utsname *utsp)
    375 {
    376 	return (t->t_ops->t_uname(t, utsp));
    377 }
    378 
    379 int
    380 mdb_tgt_dmodel(mdb_tgt_t *t)
    381 {
    382 	return (t->t_ops->t_dmodel(t));
    383 }
    384 
    385 int
    386 mdb_tgt_auxv(mdb_tgt_t *t, const auxv_t **auxvp)
    387 {
    388 	return (t->t_ops->t_auxv(t, auxvp));
    389 }
    390 
    391 ssize_t
    392 mdb_tgt_aread(mdb_tgt_t *t, mdb_tgt_as_t as,
    393 	void *buf, size_t n, mdb_tgt_addr_t addr)
    394 {
    395 	if (t->t_flags & MDB_TGT_F_ASIO)
    396 		return (t->t_ops->t_aread(t, as, buf, n, addr));
    397 
    398 	switch ((uintptr_t)as) {
    399 	case (uintptr_t)MDB_TGT_AS_VIRT:
    400 		return (t->t_ops->t_vread(t, buf, n, addr));
    401 	case (uintptr_t)MDB_TGT_AS_PHYS:
    402 		return (t->t_ops->t_pread(t, buf, n, addr));
    403 	case (uintptr_t)MDB_TGT_AS_FILE:
    404 		return (t->t_ops->t_fread(t, buf, n, addr));
    405 	case (uintptr_t)MDB_TGT_AS_IO:
    406 		return (t->t_ops->t_ioread(t, buf, n, addr));
    407 	}
    408 	return (t->t_ops->t_aread(t, as, buf, n, addr));
    409 }
    410 
    411 ssize_t
    412 mdb_tgt_awrite(mdb_tgt_t *t, mdb_tgt_as_t as,
    413 	const void *buf, size_t n, mdb_tgt_addr_t addr)
    414 {
    415 	if (!(t->t_flags & MDB_TGT_F_RDWR))
    416 		return (set_errno(EMDB_TGTRDONLY));
    417 
    418 	if (t->t_flags & MDB_TGT_F_ASIO)
    419 		return (t->t_ops->t_awrite(t, as, buf, n, addr));
    420 
    421 	switch ((uintptr_t)as) {
    422 	case (uintptr_t)MDB_TGT_AS_VIRT:
    423 		return (t->t_ops->t_vwrite(t, buf, n, addr));
    424 	case (uintptr_t)MDB_TGT_AS_PHYS:
    425 		return (t->t_ops->t_pwrite(t, buf, n, addr));
    426 	case (uintptr_t)MDB_TGT_AS_FILE:
    427 		return (t->t_ops->t_fwrite(t, buf, n, addr));
    428 	case (uintptr_t)MDB_TGT_AS_IO:
    429 		return (t->t_ops->t_iowrite(t, buf, n, addr));
    430 	}
    431 	return (t->t_ops->t_awrite(t, as, buf, n, addr));
    432 }
    433 
    434 ssize_t
    435 mdb_tgt_vread(mdb_tgt_t *t, void *buf, size_t n, uintptr_t addr)
    436 {
    437 	return (t->t_ops->t_vread(t, buf, n, addr));
    438 }
    439 
    440 ssize_t
    441 mdb_tgt_vwrite(mdb_tgt_t *t, const void *buf, size_t n, uintptr_t addr)
    442 {
    443 	if (t->t_flags & MDB_TGT_F_RDWR)
    444 		return (t->t_ops->t_vwrite(t, buf, n, addr));
    445 
    446 	return (set_errno(EMDB_TGTRDONLY));
    447 }
    448 
    449 ssize_t
    450 mdb_tgt_pread(mdb_tgt_t *t, void *buf, size_t n, physaddr_t addr)
    451 {
    452 	return (t->t_ops->t_pread(t, buf, n, addr));
    453 }
    454 
    455 ssize_t
    456 mdb_tgt_pwrite(mdb_tgt_t *t, const void *buf, size_t n, physaddr_t addr)
    457 {
    458 	if (t->t_flags & MDB_TGT_F_RDWR)
    459 		return (t->t_ops->t_pwrite(t, buf, n, addr));
    460 
    461 	return (set_errno(EMDB_TGTRDONLY));
    462 }
    463 
    464 ssize_t
    465 mdb_tgt_fread(mdb_tgt_t *t, void *buf, size_t n, uintptr_t addr)
    466 {
    467 	return (t->t_ops->t_fread(t, buf, n, addr));
    468 }
    469 
    470 ssize_t
    471 mdb_tgt_fwrite(mdb_tgt_t *t, const void *buf, size_t n, uintptr_t addr)
    472 {
    473 	if (t->t_flags & MDB_TGT_F_RDWR)
    474 		return (t->t_ops->t_fwrite(t, buf, n, addr));
    475 
    476 	return (set_errno(EMDB_TGTRDONLY));
    477 }
    478 
    479 ssize_t
    480 mdb_tgt_ioread(mdb_tgt_t *t, void *buf, size_t n, uintptr_t addr)
    481 {
    482 	return (t->t_ops->t_ioread(t, buf, n, addr));
    483 }
    484 
    485 ssize_t
    486 mdb_tgt_iowrite(mdb_tgt_t *t, const void *buf, size_t n, uintptr_t addr)
    487 {
    488 	if (t->t_flags & MDB_TGT_F_RDWR)
    489 		return (t->t_ops->t_iowrite(t, buf, n, addr));
    490 
    491 	return (set_errno(EMDB_TGTRDONLY));
    492 }
    493 
    494 int
    495 mdb_tgt_vtop(mdb_tgt_t *t, mdb_tgt_as_t as, uintptr_t va, physaddr_t *pap)
    496 {
    497 	return (t->t_ops->t_vtop(t, as, va, pap));
    498 }
    499 
    500 ssize_t
    501 mdb_tgt_readstr(mdb_tgt_t *t, mdb_tgt_as_t as, char *buf,
    502 	size_t nbytes, mdb_tgt_addr_t addr)
    503 {
    504 	ssize_t n, nread = mdb_tgt_aread(t, as, buf, nbytes, addr);
    505 	char *p;
    506 
    507 	if (nread >= 0) {
    508 		if ((p = memchr(buf, '\0', nread)) != NULL)
    509 			nread = (size_t)(p - buf);
    510 		goto done;
    511 	}
    512 
    513 	nread = 0;
    514 	p = &buf[0];
    515 
    516 	while (nread < nbytes && (n = mdb_tgt_aread(t, as, p, 1, addr)) == 1) {
    517 		if (*p == '\0')
    518 			return (nread);
    519 		nread++;
    520 		addr++;
    521 		p++;
    522 	}
    523 
    524 	if (nread == 0 && n == -1)
    525 		return (-1); /* If we can't even read a byte, return -1 */
    526 
    527 done:
    528 	if (nbytes != 0)
    529 		buf[MIN(nread, nbytes - 1)] = '\0';
    530 
    531 	return (nread);
    532 }
    533 
    534 ssize_t
    535 mdb_tgt_writestr(mdb_tgt_t *t, mdb_tgt_as_t as,
    536 	const char *buf, mdb_tgt_addr_t addr)
    537 {
    538 	ssize_t nwritten = mdb_tgt_awrite(t, as, buf, strlen(buf) + 1, addr);
    539 	return (nwritten > 0 ? nwritten - 1 : nwritten);
    540 }
    541 
    542 int
    543 mdb_tgt_lookup_by_name(mdb_tgt_t *t, const char *obj,
    544 	const char *name, GElf_Sym *symp, mdb_syminfo_t *sip)
    545 {
    546 	mdb_syminfo_t info;
    547 	GElf_Sym sym;
    548 	uint_t id;
    549 
    550 	if (name == NULL || t == NULL)
    551 		return (set_errno(EINVAL));
    552 
    553 	if (obj == MDB_TGT_OBJ_EVERY &&
    554 	    mdb_gelf_symtab_lookup_by_name(mdb.m_prsym, name, &sym, &id) == 0) {
    555 		info.sym_table = MDB_TGT_PRVSYM;
    556 		info.sym_id = id;
    557 		goto found;
    558 	}
    559 
    560 	if (t->t_ops->t_lookup_by_name(t, obj, name, &sym, &info) == 0)
    561 		goto found;
    562 
    563 	return (-1);
    564 
    565 found:
    566 	if (symp != NULL)
    567 		*symp = sym;
    568 	if (sip != NULL)
    569 		*sip = info;
    570 	return (0);
    571 }
    572 
    573 int
    574 mdb_tgt_lookup_by_addr(mdb_tgt_t *t, uintptr_t addr, uint_t flags,
    575 	char *buf, size_t len, GElf_Sym *symp, mdb_syminfo_t *sip)
    576 {
    577 	mdb_syminfo_t info;
    578 	GElf_Sym sym;
    579 
    580 	if (t == NULL)
    581 		return (set_errno(EINVAL));
    582 
    583 	if (t->t_ops->t_lookup_by_addr(t, addr, flags,
    584 	    buf, len, &sym, &info) == 0) {
    585 		if (symp != NULL)
    586 			*symp = sym;
    587 		if (sip != NULL)
    588 			*sip = info;
    589 		return (0);
    590 	}
    591 
    592 	return (-1);
    593 }
    594 
    595 /*
    596  * The mdb_tgt_lookup_by_scope function is a convenience routine for code that
    597  * wants to look up a scoped symbol name such as "object`symbol".  It is
    598  * implemented as a simple wrapper around mdb_tgt_lookup_by_name.  Note that
    599  * we split on the *last* occurrence of "`", so the object name itself may
    600  * contain additional scopes whose evaluation is left to the target.  This
    601  * allows targets to implement additional scopes, such as source files,
    602  * function names, link map identifiers, etc.
    603  */
    604 int
    605 mdb_tgt_lookup_by_scope(mdb_tgt_t *t, const char *s, GElf_Sym *symp,
    606 	mdb_syminfo_t *sip)
    607 {
    608 	const char *object = MDB_TGT_OBJ_EVERY;
    609 	const char *name = s;
    610 	char buf[MDB_TGT_SYM_NAMLEN];
    611 
    612 	if (t == NULL)
    613 		return (set_errno(EINVAL));
    614 
    615 	if (strchr(name, '`') != NULL) {
    616 
    617 		(void) strncpy(buf, s, sizeof (buf));
    618 		buf[sizeof (buf) - 1] = '\0';
    619 		name = buf;
    620 
    621 		if ((s = strrsplit(buf, '`')) != NULL) {
    622 			object = buf;
    623 			name = s;
    624 			if (*object == '\0')
    625 				return (set_errno(EMDB_NOOBJ));
    626 			if (*name == '\0')
    627 				return (set_errno(EMDB_NOSYM));
    628 		}
    629 	}
    630 
    631 	return (mdb_tgt_lookup_by_name(t, object, name, symp, sip));
    632 }
    633 
    634 int
    635 mdb_tgt_symbol_iter(mdb_tgt_t *t, const char *obj, uint_t which,
    636 	uint_t type, mdb_tgt_sym_f *cb, void *p)
    637 {
    638 	if ((which != MDB_TGT_SYMTAB && which != MDB_TGT_DYNSYM) ||
    639 	    (type & ~(MDB_TGT_BIND_ANY | MDB_TGT_TYPE_ANY)) != 0)
    640 		return (set_errno(EINVAL));
    641 
    642 	return (t->t_ops->t_symbol_iter(t, obj, which, type, cb, p));
    643 }
    644 
    645 ssize_t
    646 mdb_tgt_readsym(mdb_tgt_t *t, mdb_tgt_as_t as, void *buf, size_t nbytes,
    647 	const char *obj, const char *name)
    648 {
    649 	GElf_Sym sym;
    650 
    651 	if (mdb_tgt_lookup_by_name(t, obj, name, &sym, NULL) == 0)
    652 		return (mdb_tgt_aread(t, as, buf, nbytes, sym.st_value));
    653 
    654 	return (-1);
    655 }
    656 
    657 ssize_t
    658 mdb_tgt_writesym(mdb_tgt_t *t, mdb_tgt_as_t as, const void *buf,
    659 	size_t nbytes, const char *obj, const char *name)
    660 {
    661 	GElf_Sym sym;
    662 
    663 	if (mdb_tgt_lookup_by_name(t, obj, name, &sym, NULL) == 0)
    664 		return (mdb_tgt_awrite(t, as, buf, nbytes, sym.st_value));
    665 
    666 	return (-1);
    667 }
    668 
    669 int
    670 mdb_tgt_mapping_iter(mdb_tgt_t *t, mdb_tgt_map_f *cb, void *p)
    671 {
    672 	return (t->t_ops->t_mapping_iter(t, cb, p));
    673 }
    674 
    675 int
    676 mdb_tgt_object_iter(mdb_tgt_t *t, mdb_tgt_map_f *cb, void *p)
    677 {
    678 	return (t->t_ops->t_object_iter(t, cb, p));
    679 }
    680 
    681 const mdb_map_t *
    682 mdb_tgt_addr_to_map(mdb_tgt_t *t, uintptr_t addr)
    683 {
    684 	return (t->t_ops->t_addr_to_map(t, addr));
    685 }
    686 
    687 const mdb_map_t *
    688 mdb_tgt_name_to_map(mdb_tgt_t *t, const char *name)
    689 {
    690 	return (t->t_ops->t_name_to_map(t, name));
    691 }
    692 
    693 struct ctf_file *
    694 mdb_tgt_addr_to_ctf(mdb_tgt_t *t, uintptr_t addr)
    695 {
    696 	return (t->t_ops->t_addr_to_ctf(t, addr));
    697 }
    698 
    699 struct ctf_file *
    700 mdb_tgt_name_to_ctf(mdb_tgt_t *t, const char *name)
    701 {
    702 	return (t->t_ops->t_name_to_ctf(t, name));
    703 }
    704 
    705 /*
    706  * Return the latest target status.  We just copy out our cached copy.  The
    707  * status only needs to change when the target is run, stepped, or continued.
    708  */
    709 int
    710 mdb_tgt_status(mdb_tgt_t *t, mdb_tgt_status_t *tsp)
    711 {
    712 	uint_t dstop = (t->t_status.st_flags & MDB_TGT_DSTOP);
    713 	uint_t istop = (t->t_status.st_flags & MDB_TGT_ISTOP);
    714 	uint_t state = t->t_status.st_state;
    715 
    716 	if (tsp == NULL)
    717 		return (set_errno(EINVAL));
    718 
    719 	/*
    720 	 * If we're called with the address of the target's internal status,
    721 	 * then call down to update it; otherwise copy out the saved status.
    722 	 */
    723 	if (tsp == &t->t_status && t->t_ops->t_status(t, &t->t_status) != 0)
    724 		return (-1); /* errno is set for us */
    725 
    726 	/*
    727 	 * Assert that our state is valid before returning it.  The state must
    728 	 * be valid, and DSTOP and ISTOP cannot be set simultaneously.  ISTOP
    729 	 * is only valid when stopped.  DSTOP is only valid when running or
    730 	 * stopped.  If any test fails, abort the debugger.
    731 	 */
    732 	if (state > MDB_TGT_LOST)
    733 		fail("invalid target state (%u)\n", state);
    734 	if (state != MDB_TGT_STOPPED && istop)
    735 		fail("target state is (%u) and ISTOP is set\n", state);
    736 	if (state != MDB_TGT_STOPPED && state != MDB_TGT_RUNNING && dstop)
    737 		fail("target state is (%u) and DSTOP is set\n", state);
    738 	if (istop && dstop)
    739 		fail("target has ISTOP and DSTOP set simultaneously\n");
    740 
    741 	if (tsp != &t->t_status)
    742 		bcopy(&t->t_status, tsp, sizeof (mdb_tgt_status_t));
    743 
    744 	return (0);
    745 }
    746 
    747 /*
    748  * For the given sespec, scan its list of vespecs for ones that are marked
    749  * temporary and delete them.  We use the same method as vespec_delete below.
    750  */
    751 /*ARGSUSED*/
    752 void
    753 mdb_tgt_sespec_prune_one(mdb_tgt_t *t, mdb_sespec_t *sep)
    754 {
    755 	mdb_vespec_t *vep, *nvep;
    756 
    757 	for (vep = mdb_list_next(&sep->se_velist); vep; vep = nvep) {
    758 		nvep = mdb_list_next(vep);
    759 
    760 		if ((vep->ve_flags & (MDB_TGT_SPEC_DELETED |
    761 		    MDB_TGT_SPEC_TEMPORARY)) == MDB_TGT_SPEC_TEMPORARY) {
    762 			vep->ve_flags |= MDB_TGT_SPEC_DELETED;
    763 			mdb_tgt_vespec_rele(t, vep);
    764 		}
    765 	}
    766 }
    767 
    768 /*
    769  * Prune each sespec on the active list of temporary vespecs.  This function
    770  * is called, for example, after the target finishes a continue operation.
    771  */
    772 void
    773 mdb_tgt_sespec_prune_all(mdb_tgt_t *t)
    774 {
    775 	mdb_sespec_t *sep, *nsep;
    776 
    777 	for (sep = mdb_list_next(&t->t_active); sep != NULL; sep = nsep) {
    778 		nsep = mdb_list_next(sep);
    779 		mdb_tgt_sespec_prune_one(t, sep);
    780 	}
    781 }
    782 
    783 /*
    784  * Transition the given sespec to the IDLE state.  We invoke the destructor,
    785  * and then move the sespec from the active list to the idle list.
    786  */
    787 void
    788 mdb_tgt_sespec_idle_one(mdb_tgt_t *t, mdb_sespec_t *sep, int reason)
    789 {
    790 	ASSERT(sep->se_state != MDB_TGT_SPEC_IDLE);
    791 
    792 	if (sep->se_state == MDB_TGT_SPEC_ARMED)
    793 		(void) sep->se_ops->se_disarm(t, sep);
    794 
    795 	sep->se_ops->se_dtor(t, sep);
    796 	sep->se_data = NULL;
    797 
    798 	sep->se_state = MDB_TGT_SPEC_IDLE;
    799 	sep->se_errno = reason;
    800 
    801 	mdb_list_delete(&t->t_active, sep);
    802 	mdb_list_append(&t->t_idle, sep);
    803 
    804 	mdb_tgt_sespec_prune_one(t, sep);
    805 }
    806 
    807 /*
    808  * Transition each sespec on the active list to the IDLE state.  This function
    809  * is called, for example, after the target terminates execution.
    810  */
    811 void
    812 mdb_tgt_sespec_idle_all(mdb_tgt_t *t, int reason, int clear_matched)
    813 {
    814 	mdb_sespec_t *sep, *nsep;
    815 	mdb_vespec_t *vep;
    816 
    817 	while ((sep = t->t_matched) != T_SE_END && clear_matched) {
    818 		for (vep = mdb_list_next(&sep->se_velist); vep != NULL; ) {
    819 			vep->ve_flags &= ~MDB_TGT_SPEC_MATCHED;
    820 			vep = mdb_list_next(vep);
    821 		}
    822 
    823 		t->t_matched = sep->se_matched;
    824 		sep->se_matched = NULL;
    825 		mdb_tgt_sespec_rele(t, sep);
    826 	}
    827 
    828 	for (sep = mdb_list_next(&t->t_active); sep != NULL; sep = nsep) {
    829 		nsep = mdb_list_next(sep);
    830 		mdb_tgt_sespec_idle_one(t, sep, reason);
    831 	}
    832 }
    833 
    834 /*
    835  * Attempt to transition the given sespec from the IDLE to ACTIVE state.  We
    836  * do this by invoking se_ctor -- if this fails, we save the reason in se_errno
    837  * and return -1 with errno set.  One strange case we need to deal with here is
    838  * the possibility that a given vespec is sitting on the idle list with its
    839  * corresponding sespec, but it is actually a duplicate of another sespec on the
    840  * active list.  This can happen if the sespec is associated with a
    841  * MDB_TGT_SPEC_DISABLED vespec that was just enabled, and is now ready to be
    842  * activated.  A more interesting reason this situation might arise is the case
    843  * where a virtual address breakpoint is set at an address just mmap'ed by
    844  * dlmopen.  Since no symbol table information is available for this mapping
    845  * yet, a pre-existing deferred symbolic breakpoint may already exist for this
    846  * address, but it is on the idle list.  When the symbol table is ready and the
    847  * DLACTIVITY event occurs, we now discover that the virtual address obtained by
    848  * evaluating the symbolic breakpoint matches the explicit virtual address of
    849  * the active virtual breakpoint.  To resolve this conflict in either case, we
    850  * destroy the idle sespec, and attach its list of vespecs to the existing
    851  * active sespec.
    852  */
    853 int
    854 mdb_tgt_sespec_activate_one(mdb_tgt_t *t, mdb_sespec_t *sep)
    855 {
    856 	mdb_vespec_t *vep = mdb_list_next(&sep->se_velist);
    857 
    858 	mdb_vespec_t *nvep;
    859 	mdb_sespec_t *dup;
    860 
    861 	ASSERT(sep->se_state == MDB_TGT_SPEC_IDLE);
    862 	ASSERT(vep != NULL);
    863 
    864 	if (vep->ve_flags & MDB_TGT_SPEC_DISABLED)
    865 		return (0); /* cannot be activated while disabled bit set */
    866 
    867 	/*
    868 	 * First search the active list for an existing, duplicate sespec to
    869 	 * handle the special case described above.
    870 	 */
    871 	for (dup = mdb_list_next(&t->t_active); dup; dup = mdb_list_next(dup)) {
    872 		if (dup->se_ops == sep->se_ops &&
    873 		    dup->se_ops->se_secmp(t, dup, vep->ve_args)) {
    874 			ASSERT(dup != sep);
    875 			break;
    876 		}
    877 	}
    878 
    879 	/*
    880 	 * If a duplicate is found, destroy the existing, idle sespec, and
    881 	 * attach all of its vespecs to the duplicate sespec.
    882 	 */
    883 	if (dup != NULL) {
    884 		for (vep = mdb_list_next(&sep->se_velist); vep; vep = nvep) {
    885 			mdb_dprintf(MDB_DBG_TGT, "merge [ %d ] to sespec %p\n",
    886 			    vep->ve_id, (void *)dup);
    887 
    888 			if (dup->se_matched != NULL)
    889 				vep->ve_flags |= MDB_TGT_SPEC_MATCHED;
    890 
    891 			nvep = mdb_list_next(vep);
    892 			vep->ve_hits = 0;
    893 
    894 			mdb_list_delete(&sep->se_velist, vep);
    895 			mdb_tgt_sespec_rele(t, sep);
    896 
    897 			mdb_list_append(&dup->se_velist, vep);
    898 			mdb_tgt_sespec_hold(t, dup);
    899 			vep->ve_se = dup;
    900 		}
    901 
    902 		mdb_dprintf(MDB_DBG_TGT, "merged idle sespec %p with %p\n",
    903 		    (void *)sep, (void *)dup);
    904 		return (0);
    905 	}
    906 
    907 	/*
    908 	 * If no duplicate is found, call the sespec's constructor.  If this
    909 	 * is successful, move the sespec to the active list.
    910 	 */
    911 	if (sep->se_ops->se_ctor(t, sep, vep->ve_args) < 0) {
    912 		sep->se_errno = errno;
    913 		sep->se_data = NULL;
    914 
    915 		return (-1);
    916 	}
    917 
    918 	for (vep = mdb_list_next(&sep->se_velist); vep; vep = nvep) {
    919 		nvep = mdb_list_next(vep);
    920 		vep->ve_hits = 0;
    921 	}
    922 	mdb_list_delete(&t->t_idle, sep);
    923 	mdb_list_append(&t->t_active, sep);
    924 	sep->se_state = MDB_TGT_SPEC_ACTIVE;
    925 	sep->se_errno = 0;
    926 
    927 	return (0);
    928 }
    929 
    930 /*
    931  * Transition each sespec on the idle list to the ACTIVE state.  This function
    932  * is called, for example, after the target's t_run() function returns.  If
    933  * the se_ctor() function fails, the specifier is not yet applicable; it will
    934  * remain on the idle list and can be activated later.
    935  *
    936  * Returns 1 if there weren't any unexpected activation failures; 0 if there
    937  * were.
    938  */
    939 int
    940 mdb_tgt_sespec_activate_all(mdb_tgt_t *t)
    941 {
    942 	mdb_sespec_t *sep, *nsep;
    943 	int rc = 1;
    944 
    945 	for (sep = mdb_list_next(&t->t_idle); sep != NULL; sep = nsep) {
    946 		nsep = mdb_list_next(sep);
    947 
    948 		if (mdb_tgt_sespec_activate_one(t, sep) < 0 &&
    949 		    sep->se_errno != EMDB_NOOBJ)
    950 			rc = 0;
    951 	}
    952 
    953 	return (rc);
    954 }
    955 
    956 /*
    957  * Transition the given sespec to the ARMED state.  Note that we attempt to
    958  * re-arm sespecs previously in the ERROR state.  If se_arm() fails the sespec
    959  * transitions to the ERROR state but stays on the active list.
    960  */
    961 void
    962 mdb_tgt_sespec_arm_one(mdb_tgt_t *t, mdb_sespec_t *sep)
    963 {
    964 	ASSERT(sep->se_state != MDB_TGT_SPEC_IDLE);
    965 
    966 	if (sep->se_state == MDB_TGT_SPEC_ARMED)
    967 		return; /* do not arm sespecs more than once */
    968 
    969 	if (sep->se_ops->se_arm(t, sep) == -1) {
    970 		sep->se_state = MDB_TGT_SPEC_ERROR;
    971 		sep->se_errno = errno;
    972 	} else {
    973 		sep->se_state = MDB_TGT_SPEC_ARMED;
    974 		sep->se_errno = 0;
    975 	}
    976 }
    977 
    978 /*
    979  * Transition each sespec on the active list (except matched specs) to the
    980  * ARMED state.  This function is called prior to continuing the target.
    981  */
    982 void
    983 mdb_tgt_sespec_arm_all(mdb_tgt_t *t)
    984 {
    985 	mdb_sespec_t *sep, *nsep;
    986 
    987 	for (sep = mdb_list_next(&t->t_active); sep != NULL; sep = nsep) {
    988 		nsep = mdb_list_next(sep);
    989 		if (sep->se_matched == NULL)
    990 			mdb_tgt_sespec_arm_one(t, sep);
    991 	}
    992 }
    993 
    994 /*
    995  * Transition each sespec on the active list that is in the ARMED state to
    996  * the ACTIVE state.  If se_disarm() fails, the sespec is transitioned to
    997  * the ERROR state instead, but left on the active list.
    998  */
    999 static void
   1000 tgt_disarm_sespecs(mdb_tgt_t *t)
   1001 {
   1002 	mdb_sespec_t *sep;
   1003 
   1004 	for (sep = mdb_list_next(&t->t_active); sep; sep = mdb_list_next(sep)) {
   1005 		if (sep->se_state != MDB_TGT_SPEC_ARMED)
   1006 			continue; /* do not disarm if in ERROR state */
   1007 
   1008 		if (sep->se_ops->se_disarm(t, sep) == -1) {
   1009 			sep->se_state = MDB_TGT_SPEC_ERROR;
   1010 			sep->se_errno = errno;
   1011 		} else {
   1012 			sep->se_state = MDB_TGT_SPEC_ACTIVE;
   1013 			sep->se_errno = 0;
   1014 		}
   1015 	}
   1016 }
   1017 
   1018 /*
   1019  * Determine if the software event that triggered the most recent stop matches
   1020  * any of the active event specifiers.  If 'all' is TRUE, we consider all
   1021  * sespecs in our search.   If 'all' is FALSE, we only consider ARMED sespecs.
   1022  * If we successfully match an event, we add it to the t_matched list and
   1023  * place an additional hold on it.
   1024  */
   1025 static mdb_sespec_t *
   1026 tgt_match_sespecs(mdb_tgt_t *t, int all)
   1027 {
   1028 	mdb_sespec_t *sep;
   1029 
   1030 	for (sep = mdb_list_next(&t->t_active); sep; sep = mdb_list_next(sep)) {
   1031 		if (all == FALSE && sep->se_state != MDB_TGT_SPEC_ARMED)
   1032 			continue; /* restrict search to ARMED sespecs */
   1033 
   1034 		if (sep->se_state != MDB_TGT_SPEC_ERROR &&
   1035 		    sep->se_ops->se_match(t, sep, &t->t_status)) {
   1036 			mdb_dprintf(MDB_DBG_TGT, "match se %p\n", (void *)sep);
   1037 			mdb_tgt_sespec_hold(t, sep);
   1038 			sep->se_matched = t->t_matched;
   1039 			t->t_matched = sep;
   1040 		}
   1041 	}
   1042 
   1043 	return (t->t_matched);
   1044 }
   1045 
   1046 /*
   1047  * This function provides the low-level target continue algorithm.  We proceed
   1048  * in three phases: (1) we arm the active sespecs, except the specs matched at
   1049  * the time we last stopped, (2) we call se_cont() on any matched sespecs to
   1050  * step over these event transitions, and then arm the corresponding sespecs,
   1051  * and (3) we call the appropriate low-level continue routine.  Once the
   1052  * target stops again, we determine which sespecs were matched, and invoke the
   1053  * appropriate vespec callbacks and perform other vespec maintenance.
   1054  */
   1055 static int
   1056 tgt_continue(mdb_tgt_t *t, mdb_tgt_status_t *tsp,
   1057     int (*t_cont)(mdb_tgt_t *, mdb_tgt_status_t *))
   1058 {
   1059 	mdb_var_t *hitv = mdb_nv_lookup(&mdb.m_nv, "hits");
   1060 	uintptr_t pc = t->t_status.st_pc;
   1061 	int error = 0;
   1062 
   1063 	mdb_sespec_t *sep, *nsep, *matched;
   1064 	mdb_vespec_t *vep, *nvep;
   1065 	uintptr_t addr;
   1066 
   1067 	uint_t cbits = 0;	/* union of pending continue bits */
   1068 	uint_t ncont = 0;	/* # of callbacks that requested cont */
   1069 	uint_t n = 0;		/* # of callbacks */
   1070 
   1071 	/*
   1072 	 * If the target is undead, dead, or lost, we no longer allow continue.
   1073 	 * This effectively forces the user to use ::kill or ::run after death.
   1074 	 */
   1075 	if (t->t_status.st_state == MDB_TGT_UNDEAD)
   1076 		return (set_errno(EMDB_TGTZOMB));
   1077 	if (t->t_status.st_state == MDB_TGT_DEAD)
   1078 		return (set_errno(EMDB_TGTCORE));
   1079 	if (t->t_status.st_state == MDB_TGT_LOST)
   1080 		return (set_errno(EMDB_TGTLOST));
   1081 
   1082 	/*
   1083 	 * If any of single-step, step-over, or step-out is pending, it takes
   1084 	 * precedence over an explicit or pending continue, because these are
   1085 	 * all different specialized forms of continue.
   1086 	 */
   1087 	if (t->t_flags & MDB_TGT_F_STEP)
   1088 		t_cont = t->t_ops->t_step;
   1089 	else if (t->t_flags & MDB_TGT_F_NEXT)
   1090 		t_cont = t->t_ops->t_step;
   1091 	else if (t->t_flags & MDB_TGT_F_STEP_BRANCH)
   1092 		t_cont = t->t_ops->t_cont;
   1093 	else if (t->t_flags & MDB_TGT_F_STEP_OUT)
   1094 		t_cont = t->t_ops->t_cont;
   1095 
   1096 	/*
   1097 	 * To handle step-over, we ask the target to find the address past the
   1098 	 * next control transfer instruction.  If an address is found, we plant
   1099 	 * a temporary breakpoint there and continue; otherwise just step.
   1100 	 */
   1101 	if ((t->t_flags & MDB_TGT_F_NEXT) && !(t->t_flags & MDB_TGT_F_STEP)) {
   1102 		if (t->t_ops->t_next(t, &addr) == -1 || mdb_tgt_add_vbrkpt(t,
   1103 		    addr, MDB_TGT_SPEC_HIDDEN | MDB_TGT_SPEC_TEMPORARY,
   1104 		    no_se_f, NULL) == 0) {
   1105 			mdb_dprintf(MDB_DBG_TGT, "next falling back to step: "
   1106 			    "%s\n", mdb_strerror(errno));
   1107 		} else
   1108 			t_cont = t->t_ops->t_cont;
   1109 	}
   1110 
   1111 	/*
   1112 	 * To handle step-out, we ask the target to find the return address of
   1113 	 * the current frame, plant a temporary breakpoint there, and continue.
   1114 	 */
   1115 	if (t->t_flags & MDB_TGT_F_STEP_OUT) {
   1116 		if (t->t_ops->t_step_out(t, &addr) == -1)
   1117 			return (-1); /* errno is set for us */
   1118 
   1119 		if (mdb_tgt_add_vbrkpt(t, addr, MDB_TGT_SPEC_HIDDEN |
   1120 		    MDB_TGT_SPEC_TEMPORARY, no_se_f, NULL) == 0)
   1121 			return (-1); /* errno is set for us */
   1122 	}
   1123 
   1124 	/*
   1125 	 * To handle step-branch, we ask the target to enable it for the coming
   1126 	 * continue.  Step-branch is incompatible with step, so don't enable it
   1127 	 * if we're going to be stepping.
   1128 	 */
   1129 	if (t->t_flags & MDB_TGT_F_STEP_BRANCH && t_cont == t->t_ops->t_cont) {
   1130 		if (t->t_ops->t_step_branch(t) == -1)
   1131 			return (-1); /* errno is set for us */
   1132 	}
   1133 
   1134 	(void) mdb_signal_block(SIGHUP);
   1135 	(void) mdb_signal_block(SIGTERM);
   1136 	mdb_intr_disable();
   1137 
   1138 	t->t_flags &= ~T_CONT_BITS;
   1139 	t->t_flags |= MDB_TGT_F_BUSY;
   1140 	mdb_tgt_sespec_arm_all(t);
   1141 
   1142 	ASSERT(t->t_matched != NULL);
   1143 	matched = t->t_matched;
   1144 	t->t_matched = T_SE_END;
   1145 
   1146 	if (mdb.m_term != NULL)
   1147 		IOP_SUSPEND(mdb.m_term);
   1148 
   1149 	/*
   1150 	 * Iterate over the matched sespec list, performing autostop processing
   1151 	 * and clearing the matched bit for each associated vespec.  We then
   1152 	 * invoke each sespec's se_cont callback in order to continue past
   1153 	 * the corresponding event.  If the matched list has more than one
   1154 	 * sespec, we assume that the se_cont callbacks are non-interfering.
   1155 	 */
   1156 	for (sep = matched; sep != T_SE_END; sep = sep->se_matched) {
   1157 		for (vep = mdb_list_next(&sep->se_velist); vep != NULL; ) {
   1158 			if ((vep->ve_flags & MDB_TGT_SPEC_AUTOSTOP) &&
   1159 			    (vep->ve_limit && vep->ve_hits == vep->ve_limit))
   1160 				vep->ve_hits = 0;
   1161 
   1162 			vep->ve_flags &= ~MDB_TGT_SPEC_MATCHED;
   1163 			vep = mdb_list_next(vep);
   1164 		}
   1165 
   1166 		if (sep->se_ops->se_cont(t, sep, &t->t_status) == -1) {
   1167 			error = errno ? errno : -1;
   1168 			tgt_disarm_sespecs(t);
   1169 			break;
   1170 		}
   1171 
   1172 		if (!(t->t_status.st_flags & MDB_TGT_ISTOP)) {
   1173 			tgt_disarm_sespecs(t);
   1174 			if (t->t_status.st_state == MDB_TGT_UNDEAD)
   1175 				mdb_tgt_sespec_idle_all(t, EMDB_TGTZOMB, TRUE);
   1176 			else if (t->t_status.st_state == MDB_TGT_LOST)
   1177 				mdb_tgt_sespec_idle_all(t, EMDB_TGTLOST, TRUE);
   1178 			break;
   1179 		}
   1180 	}
   1181 
   1182 	/*
   1183 	 * Clear the se_matched field for each matched sespec, and drop the
   1184 	 * reference count since the sespec is no longer on the matched list.
   1185 	 */
   1186 	for (sep = matched; sep != T_SE_END; sep = nsep) {
   1187 		nsep = sep->se_matched;
   1188 		sep->se_matched = NULL;
   1189 		mdb_tgt_sespec_rele(t, sep);
   1190 	}
   1191 
   1192 	/*
   1193 	 * If the matched list was non-empty, see if we hit another event while
   1194 	 * performing se_cont() processing.  If so, don't bother continuing any
   1195 	 * further.  If not, arm the sespecs on the old matched list by calling
   1196 	 * mdb_tgt_sespec_arm_all() again and then continue by calling t_cont.
   1197 	 */
   1198 	if (matched != T_SE_END) {
   1199 		if (error != 0 || !(t->t_status.st_flags & MDB_TGT_ISTOP))
   1200 			goto out; /* abort now if se_cont() failed */
   1201 
   1202 		if ((t->t_matched = tgt_match_sespecs(t, FALSE)) != T_SE_END) {
   1203 			tgt_disarm_sespecs(t);
   1204 			goto out;
   1205 		}
   1206 
   1207 		mdb_tgt_sespec_arm_all(t);
   1208 	}
   1209 
   1210 	if (t_cont != t->t_ops->t_step || pc == t->t_status.st_pc) {
   1211 		if (t_cont(t, &t->t_status) != 0)
   1212 			error = errno ? errno : -1;
   1213 	}
   1214 
   1215 	tgt_disarm_sespecs(t);
   1216 
   1217 	if (t->t_flags & MDB_TGT_F_UNLOAD)
   1218 		longjmp(mdb.m_frame->f_pcb, MDB_ERR_QUIT);
   1219 
   1220 	if (t->t_status.st_state == MDB_TGT_UNDEAD)
   1221 		mdb_tgt_sespec_idle_all(t, EMDB_TGTZOMB, TRUE);
   1222 	else if (t->t_status.st_state == MDB_TGT_LOST)
   1223 		mdb_tgt_sespec_idle_all(t, EMDB_TGTLOST, TRUE);
   1224 	else if (t->t_status.st_flags & MDB_TGT_ISTOP)
   1225 		t->t_matched = tgt_match_sespecs(t, TRUE);
   1226 out:
   1227 	if (mdb.m_term != NULL)
   1228 		IOP_RESUME(mdb.m_term);
   1229 
   1230 	(void) mdb_signal_unblock(SIGTERM);
   1231 	(void) mdb_signal_unblock(SIGHUP);
   1232 	mdb_intr_enable();
   1233 
   1234 	for (sep = t->t_matched; sep != T_SE_END; sep = sep->se_matched) {
   1235 		/*
   1236 		 * When we invoke a ve_callback, it may in turn request that the
   1237 		 * target continue immediately after callback processing is
   1238 		 * complete.  We only allow this to occur if *all* callbacks
   1239 		 * agree to continue.  To implement this behavior, we keep a
   1240 		 * count (ncont) of such requests, and only apply the cumulative
   1241 		 * continue bits (cbits) to the target if ncont is equal to the
   1242 		 * total number of callbacks that are invoked (n).
   1243 		 */
   1244 		for (vep = mdb_list_next(&sep->se_velist);
   1245 		    vep != NULL; vep = nvep, n++) {
   1246 			/*
   1247 			 * Place an extra hold on the current vespec and pick
   1248 			 * up the next pointer before invoking the callback: we
   1249 			 * must be prepared for the vespec to be deleted or
   1250 			 * moved to a different list by the callback.
   1251 			 */
   1252 			mdb_tgt_vespec_hold(t, vep);
   1253 			nvep = mdb_list_next(vep);
   1254 
   1255 			vep->ve_flags |= MDB_TGT_SPEC_MATCHED;
   1256 			vep->ve_hits++;
   1257 
   1258 			mdb_nv_set_value(mdb.m_dot, t->t_status.st_pc);
   1259 			mdb_nv_set_value(hitv, vep->ve_hits);
   1260 
   1261 			ASSERT((t->t_flags & T_CONT_BITS) == 0);
   1262 			vep->ve_callback(t, vep->ve_id, vep->ve_data);
   1263 
   1264 			ncont += (t->t_flags & T_CONT_BITS) != 0;
   1265 			cbits |= (t->t_flags & T_CONT_BITS);
   1266 			t->t_flags &= ~T_CONT_BITS;
   1267 
   1268 			if (vep->ve_limit && vep->ve_hits == vep->ve_limit) {
   1269 				if (vep->ve_flags & MDB_TGT_SPEC_AUTODEL)
   1270 					(void) mdb_tgt_vespec_delete(t,
   1271 					    vep->ve_id);
   1272 				else if (vep->ve_flags & MDB_TGT_SPEC_AUTODIS)
   1273 					(void) mdb_tgt_vespec_disable(t,
   1274 					    vep->ve_id);
   1275 			}
   1276 
   1277 			if (vep->ve_limit && vep->ve_hits < vep->ve_limit) {
   1278 				if (vep->ve_flags & MDB_TGT_SPEC_AUTOSTOP)
   1279 					(void) mdb_tgt_continue(t, NULL);
   1280 			}
   1281 
   1282 			mdb_tgt_vespec_rele(t, vep);
   1283 		}
   1284 	}
   1285 
   1286 	if (t->t_matched != T_SE_END && ncont == n)
   1287 		t->t_flags |= cbits; /* apply continues (see above) */
   1288 
   1289 	mdb_tgt_sespec_prune_all(t);
   1290 
   1291 	t->t_status.st_flags &= ~MDB_TGT_BUSY;
   1292 	t->t_flags &= ~MDB_TGT_F_BUSY;
   1293 
   1294 	if (tsp != NULL)
   1295 		bcopy(&t->t_status, tsp, sizeof (mdb_tgt_status_t));
   1296 
   1297 	if (error != 0)
   1298 		return (set_errno(error));
   1299 
   1300 	return (0);
   1301 }
   1302 
   1303 /*
   1304  * This function is the common glue that connects the high-level target layer
   1305  * continue functions (e.g. step and cont below) with the low-level
   1306  * tgt_continue() function above.  Since vespec callbacks may perform any
   1307  * actions, including attempting to continue the target itself, we must be
   1308  * prepared to be called while the target is still marked F_BUSY.  In this
   1309  * case, we just set a pending bit and return.  When we return from the call
   1310  * to tgt_continue() that made us busy into the tgt_request_continue() call
   1311  * that is still on the stack, we will loop around and call tgt_continue()
   1312  * again.  This allows vespecs to continue the target without recursion.
   1313  */
   1314 static int
   1315 tgt_request_continue(mdb_tgt_t *t, mdb_tgt_status_t *tsp, uint_t tflag,
   1316     int (*t_cont)(mdb_tgt_t *, mdb_tgt_status_t *))
   1317 {
   1318 	mdb_tgt_spec_desc_t desc;
   1319 	mdb_sespec_t *sep;
   1320 	char buf[BUFSIZ];
   1321 	int status;
   1322 
   1323 	if (t->t_flags & MDB_TGT_F_BUSY) {
   1324 		t->t_flags |= tflag;
   1325 		return (0);
   1326 	}
   1327 
   1328 	do {
   1329 		status = tgt_continue(t, tsp, t_cont);
   1330 	} while (status == 0 && (t->t_flags & T_CONT_BITS));
   1331 
   1332 	if (status == 0) {
   1333 		for (sep = t->t_matched; sep != T_SE_END;
   1334 		    sep = sep->se_matched) {
   1335 			mdb_vespec_t *vep;
   1336 
   1337 			for (vep = mdb_list_next(&sep->se_velist); vep;
   1338 			    vep = mdb_list_next(vep)) {
   1339 				if (vep->ve_flags & MDB_TGT_SPEC_SILENT)
   1340 					continue;
   1341 				warn("%s\n", sep->se_ops->se_info(t, sep,
   1342 				    vep, &desc, buf, sizeof (buf)));
   1343 			}
   1344 		}
   1345 
   1346 		mdb_callb_fire(MDB_CALLB_STCHG);
   1347 	}
   1348 
   1349 	t->t_flags &= ~T_CONT_BITS;
   1350 	return (status);
   1351 }
   1352 
   1353 /*
   1354  * Restart target execution: we rely upon the underlying target implementation
   1355  * to do most of the work for us.  In particular, we assume it will properly
   1356  * preserve the state of our event lists if the run fails for some reason,
   1357  * and that it will reset all events to the IDLE state if the run succeeds.
   1358  * If it is successful, we attempt to activate all of the idle sespecs.  The
   1359  * t_run() operation is defined to leave the target stopped at the earliest
   1360  * possible point in execution, and then return control to the debugger,
   1361  * awaiting a step or continue operation to set it running again.
   1362  */
   1363 int
   1364 mdb_tgt_run(mdb_tgt_t *t, int argc, const mdb_arg_t *argv)
   1365 {
   1366 	int i;
   1367 
   1368 	for (i = 0; i < argc; i++) {
   1369 		if (argv->a_type != MDB_TYPE_STRING)
   1370 			return (set_errno(EINVAL));
   1371 	}
   1372 
   1373 	if (t->t_ops->t_run(t, argc, argv) == -1)
   1374 		return (-1); /* errno is set for us */
   1375 
   1376 	t->t_flags &= ~T_CONT_BITS;
   1377 	(void) mdb_tgt_sespec_activate_all(t);
   1378 
   1379 	if (mdb.m_term != NULL)
   1380 		IOP_CTL(mdb.m_term, MDB_IOC_CTTY, NULL);
   1381 
   1382 	return (0);
   1383 }
   1384 
   1385 int
   1386 mdb_tgt_step(mdb_tgt_t *t, mdb_tgt_status_t *tsp)
   1387 {
   1388 	return (tgt_request_continue(t, tsp, MDB_TGT_F_STEP, t->t_ops->t_step));
   1389 }
   1390 
   1391 int
   1392 mdb_tgt_step_out(mdb_tgt_t *t, mdb_tgt_status_t *tsp)
   1393 {
   1394 	t->t_flags |= MDB_TGT_F_STEP_OUT; /* set flag even if tgt not busy */
   1395 	return (tgt_request_continue(t, tsp, 0, t->t_ops->t_cont));
   1396 }
   1397 
   1398 int
   1399 mdb_tgt_step_branch(mdb_tgt_t *t, mdb_tgt_status_t *tsp)
   1400 {
   1401 	t->t_flags |= MDB_TGT_F_STEP_BRANCH; /* set flag even if tgt not busy */
   1402 	return (tgt_request_continue(t, tsp, 0, t->t_ops->t_cont));
   1403 }
   1404 
   1405 int
   1406 mdb_tgt_next(mdb_tgt_t *t, mdb_tgt_status_t *tsp)
   1407 {
   1408 	t->t_flags |= MDB_TGT_F_NEXT; /* set flag even if tgt not busy */
   1409 	return (tgt_request_continue(t, tsp, 0, t->t_ops->t_step));
   1410 }
   1411 
   1412 int
   1413 mdb_tgt_continue(mdb_tgt_t *t, mdb_tgt_status_t *tsp)
   1414 {
   1415 	return (tgt_request_continue(t, tsp, MDB_TGT_F_CONT, t->t_ops->t_cont));
   1416 }
   1417 
   1418 int
   1419 mdb_tgt_signal(mdb_tgt_t *t, int sig)
   1420 {
   1421 	return (t->t_ops->t_signal(t, sig));
   1422 }
   1423 
   1424 void *
   1425 mdb_tgt_vespec_data(mdb_tgt_t *t, int vid)
   1426 {
   1427 	mdb_vespec_t *vep = mdb_tgt_vespec_lookup(t, vid);
   1428 
   1429 	if (vep == NULL) {
   1430 		(void) set_errno(EMDB_NOSESPEC);
   1431 		return (NULL);
   1432 	}
   1433 
   1434 	return (vep->ve_data);
   1435 }
   1436 
   1437 /*
   1438  * Return a structured description and comment string for the given vespec.
   1439  * We fill in the common information from the vespec, and then call down to
   1440  * the underlying sespec to provide the comment string and modify any
   1441  * event type-specific information.
   1442  */
   1443 char *
   1444 mdb_tgt_vespec_info(mdb_tgt_t *t, int vid, mdb_tgt_spec_desc_t *sp,
   1445     char *buf, size_t nbytes)
   1446 {
   1447 	mdb_vespec_t *vep = mdb_tgt_vespec_lookup(t, vid);
   1448 
   1449 	mdb_tgt_spec_desc_t desc;
   1450 	mdb_sespec_t *sep;
   1451 
   1452 	if (vep == NULL) {
   1453 		if (sp != NULL)
   1454 			bzero(sp, sizeof (mdb_tgt_spec_desc_t));
   1455 		(void) set_errno(EMDB_NOSESPEC);
   1456 		return (NULL);
   1457 	}
   1458 
   1459 	if (sp == NULL)
   1460 		sp = &desc;
   1461 
   1462 	sep = vep->ve_se;
   1463 
   1464 	sp->spec_id = vep->ve_id;
   1465 	sp->spec_flags = vep->ve_flags;
   1466 	sp->spec_hits = vep->ve_hits;
   1467 	sp->spec_limit = vep->ve_limit;
   1468 	sp->spec_state = sep->se_state;
   1469 	sp->spec_errno = sep->se_errno;
   1470 	sp->spec_base = NULL;
   1471 	sp->spec_size = 0;
   1472 	sp->spec_data = vep->ve_data;
   1473 
   1474 	return (sep->se_ops->se_info(t, sep, vep, sp, buf, nbytes));
   1475 }
   1476 
   1477 /*
   1478  * Qsort callback for sorting vespecs by VID, used below.
   1479  */
   1480 static int
   1481 tgt_vespec_compare(const mdb_vespec_t **lp, const mdb_vespec_t **rp)
   1482 {
   1483 	return ((*lp)->ve_id - (*rp)->ve_id);
   1484 }
   1485 
   1486 /*
   1487  * Iterate over all vespecs and call the specified callback function with the
   1488  * corresponding VID and caller data pointer.  We want the callback function
   1489  * to see a consistent, sorted snapshot of the vespecs, and allow the callback
   1490  * to take actions such as deleting the vespec itself, so we cannot simply
   1491  * iterate over the lists.  Instead, we pre-allocate an array of vespec
   1492  * pointers, fill it in and place an additional hold on each vespec, and then
   1493  * sort it.  After the callback has been executed on each vespec in the
   1494  * sorted array, we remove our hold and free the temporary array.
   1495  */
   1496 int
   1497 mdb_tgt_vespec_iter(mdb_tgt_t *t, mdb_tgt_vespec_f *func, void *p)
   1498 {
   1499 	mdb_vespec_t **veps, **vepp, **vend;
   1500 	mdb_vespec_t *vep, *nvep;
   1501 	mdb_sespec_t *sep;
   1502 
   1503 	uint_t vecnt = t->t_vecnt;
   1504 
   1505 	veps = mdb_alloc(sizeof (mdb_vespec_t *) * vecnt, UM_SLEEP);
   1506 	vend = veps + vecnt;
   1507 	vepp = veps;
   1508 
   1509 	for (sep = mdb_list_next(&t->t_active); sep; sep = mdb_list_next(sep)) {
   1510 		for (vep = mdb_list_next(&sep->se_velist); vep; vep = nvep) {
   1511 			mdb_tgt_vespec_hold(t, vep);
   1512 			nvep = mdb_list_next(vep);
   1513 			*vepp++ = vep;
   1514 		}
   1515 	}
   1516 
   1517 	for (sep = mdb_list_next(&t->t_idle); sep; sep = mdb_list_next(sep)) {
   1518 		for (vep = mdb_list_next(&sep->se_velist); vep; vep = nvep) {
   1519 			mdb_tgt_vespec_hold(t, vep);
   1520 			nvep = mdb_list_next(vep);
   1521 			*vepp++ = vep;
   1522 		}
   1523 	}
   1524 
   1525 	if (vepp != vend) {
   1526 		fail("target has %u vespecs on list but vecnt shows %u\n",
   1527 		    (uint_t)(vepp - veps), vecnt);
   1528 	}
   1529 
   1530 	qsort(veps, vecnt, sizeof (mdb_vespec_t *),
   1531 	    (int (*)(const void *, const void *))tgt_vespec_compare);
   1532 
   1533 	for (vepp = veps; vepp < vend; vepp++) {
   1534 		if (func(t, p, (*vepp)->ve_id, (*vepp)->ve_data) != 0)
   1535 			break;
   1536 	}
   1537 
   1538 	for (vepp = veps; vepp < vend; vepp++)
   1539 		mdb_tgt_vespec_rele(t, *vepp);
   1540 
   1541 	mdb_free(veps, sizeof (mdb_vespec_t *) * vecnt);
   1542 	return (0);
   1543 }
   1544 
   1545 /*
   1546  * Reset the vespec flags, match limit, and callback data to the specified
   1547  * values.  We silently correct invalid parameters, except for the VID.
   1548  * The caller is required to query the existing properties and pass back
   1549  * the existing values for any properties that should not be modified.
   1550  * If the callback data is modified, the caller is responsible for cleaning
   1551  * up any state associated with the previous value.
   1552  */
   1553 int
   1554 mdb_tgt_vespec_modify(mdb_tgt_t *t, int id, uint_t flags,
   1555     uint_t limit, void *data)
   1556 {
   1557 	mdb_vespec_t *vep = mdb_tgt_vespec_lookup(t, id);
   1558 
   1559 	if (vep == NULL)
   1560 		return (set_errno(EMDB_NOSESPEC));
   1561 
   1562 	/*
   1563 	 * If the value of the MDB_TGT_SPEC_DISABLED bit is changing, call the
   1564 	 * appropriate vespec function to do the enable/disable work.
   1565 	 */
   1566 	if ((flags & MDB_TGT_SPEC_DISABLED) !=
   1567 	    (vep->ve_flags & MDB_TGT_SPEC_DISABLED)) {
   1568 		if (flags & MDB_TGT_SPEC_DISABLED)
   1569 			(void) mdb_tgt_vespec_disable(t, id);
   1570 		else
   1571 			(void) mdb_tgt_vespec_enable(t, id);
   1572 	}
   1573 
   1574 	/*
   1575 	 * Make that only one MDB_TGT_SPEC_AUTO* bit is set in the new flags
   1576 	 * value: extra bits are cleared according to order of precedence.
   1577 	 */
   1578 	if (flags & MDB_TGT_SPEC_AUTOSTOP)
   1579 		flags &= ~(MDB_TGT_SPEC_AUTODEL | MDB_TGT_SPEC_AUTODIS);
   1580 	else if (flags & MDB_TGT_SPEC_AUTODEL)
   1581 		flags &= ~MDB_TGT_SPEC_AUTODIS;
   1582 
   1583 	/*
   1584 	 * The TEMPORARY property always takes precedence over STICKY.
   1585 	 */
   1586 	if (flags & MDB_TGT_SPEC_TEMPORARY)
   1587 		flags &= ~MDB_TGT_SPEC_STICKY;
   1588 
   1589 	/*
   1590 	 * If any MDB_TGT_SPEC_AUTO* bits are changing, reset the hit count
   1591 	 * back to zero and clear all of the old auto bits.
   1592 	 */
   1593 	if ((flags & T_AUTO_BITS) != (vep->ve_flags & T_AUTO_BITS)) {
   1594 		vep->ve_flags &= ~T_AUTO_BITS;
   1595 		vep->ve_hits = 0;
   1596 	}
   1597 
   1598 	vep->ve_flags = (vep->ve_flags & T_IMPL_BITS) | (flags & ~T_IMPL_BITS);
   1599 	vep->ve_data = data;
   1600 
   1601 	/*
   1602 	 * If any MDB_TGT_SPEC_AUTO* flags are set, make sure the limit is at
   1603 	 * least one.  If none are set, reset it back to zero.
   1604 	 */
   1605 	if (vep->ve_flags & T_AUTO_BITS)
   1606 		vep->ve_limit = MAX(limit, 1);
   1607 	else
   1608 		vep->ve_limit = 0;
   1609 
   1610 	/*
   1611 	 * As a convenience, we allow the caller to specify SPEC_DELETED in
   1612 	 * the flags field as indication that the event should be deleted.
   1613 	 */
   1614 	if (flags & MDB_TGT_SPEC_DELETED)
   1615 		(void) mdb_tgt_vespec_delete(t, id);
   1616 
   1617 	return (0);
   1618 }
   1619 
   1620 /*
   1621  * Remove the user disabled bit from the specified vespec, and attempt to
   1622  * activate the underlying sespec and move it to the active list if possible.
   1623  */
   1624 int
   1625 mdb_tgt_vespec_enable(mdb_tgt_t *t, int id)
   1626 {
   1627 	mdb_vespec_t *vep = mdb_tgt_vespec_lookup(t, id);
   1628 
   1629 	if (vep == NULL)
   1630 		return (set_errno(EMDB_NOSESPEC));
   1631 
   1632 	if (vep->ve_flags & MDB_TGT_SPEC_DISABLED) {
   1633 		ASSERT(mdb_list_next(vep) == NULL);
   1634 		vep->ve_flags &= ~MDB_TGT_SPEC_DISABLED;
   1635 		if (mdb_tgt_sespec_activate_one(t, vep->ve_se) < 0)
   1636 			return (-1); /* errno is set for us */
   1637 	}
   1638 
   1639 	return (0);
   1640 }
   1641 
   1642 /*
   1643  * Set the user disabled bit on the specified vespec, and move it to the idle
   1644  * list.  If the vespec is not alone with its sespec or if it is a currently
   1645  * matched event, we must always create a new idle sespec and move the vespec
   1646  * there.  If the vespec was alone and active, we can simply idle the sespec.
   1647  */
   1648 int
   1649 mdb_tgt_vespec_disable(mdb_tgt_t *t, int id)
   1650 {
   1651 	mdb_vespec_t *vep = mdb_tgt_vespec_lookup(t, id);
   1652 	mdb_sespec_t *sep;
   1653 
   1654 	if (vep == NULL)
   1655 		return (set_errno(EMDB_NOSESPEC));
   1656 
   1657 	if (vep->ve_flags & MDB_TGT_SPEC_DISABLED)
   1658 		return (0); /* already disabled */
   1659 
   1660 	if (mdb_list_prev(vep) != NULL || mdb_list_next(vep) != NULL ||
   1661 	    vep->ve_se->se_matched != NULL) {
   1662 
   1663 		sep = mdb_tgt_sespec_insert(t, vep->ve_se->se_ops, &t->t_idle);
   1664 
   1665 		mdb_list_delete(&vep->ve_se->se_velist, vep);
   1666 		mdb_tgt_sespec_rele(t, vep->ve_se);
   1667 
   1668 		mdb_list_append(&sep->se_velist, vep);
   1669 		mdb_tgt_sespec_hold(t, sep);
   1670 
   1671 		vep->ve_flags &= ~MDB_TGT_SPEC_MATCHED;
   1672 		vep->ve_se = sep;
   1673 
   1674 	} else if (vep->ve_se->se_state != MDB_TGT_SPEC_IDLE)
   1675 		mdb_tgt_sespec_idle_one(t, vep->ve_se, EMDB_SPECDIS);
   1676 
   1677 	vep->ve_flags |= MDB_TGT_SPEC_DISABLED;
   1678 	return (0);
   1679 }
   1680 
   1681 /*
   1682  * Delete the given vespec.  We use the MDB_TGT_SPEC_DELETED flag to ensure that
   1683  * multiple calls to mdb_tgt_vespec_delete to not attempt to decrement the
   1684  * reference count on the vespec more than once.  This is because the vespec
   1685  * may remain referenced if it is currently held by another routine (e.g.
   1686  * vespec_iter), and so the user could attempt to delete it more than once
   1687  * since it reference count will be >= 2 prior to the first delete call.
   1688  */
   1689 int
   1690 mdb_tgt_vespec_delete(mdb_tgt_t *t, int id)
   1691 {
   1692 	mdb_vespec_t *vep = mdb_tgt_vespec_lookup(t, id);
   1693 
   1694 	if (vep == NULL)
   1695 		return (set_errno(EMDB_NOSESPEC));
   1696 
   1697 	if (vep->ve_flags & MDB_TGT_SPEC_DELETED)
   1698 		return (set_errno(EBUSY));
   1699 
   1700 	vep->ve_flags |= MDB_TGT_SPEC_DELETED;
   1701 	mdb_tgt_vespec_rele(t, vep);
   1702 	return (0);
   1703 }
   1704 
   1705 int
   1706 mdb_tgt_add_vbrkpt(mdb_tgt_t *t, uintptr_t addr,
   1707     int spec_flags, mdb_tgt_se_f *func, void *p)
   1708 {
   1709 	return (t->t_ops->t_add_vbrkpt(t, addr, spec_flags, func, p));
   1710 }
   1711 
   1712 int
   1713 mdb_tgt_add_sbrkpt(mdb_tgt_t *t, const char *symbol,
   1714     int spec_flags, mdb_tgt_se_f *func, void *p)
   1715 {
   1716 	return (t->t_ops->t_add_sbrkpt(t, symbol, spec_flags, func, p));
   1717 }
   1718 
   1719 int
   1720 mdb_tgt_add_pwapt(mdb_tgt_t *t, physaddr_t pa, size_t n, uint_t flags,
   1721     int spec_flags, mdb_tgt_se_f *func, void *p)
   1722 {
   1723 	if ((flags & ~MDB_TGT_WA_RWX) || flags == 0) {
   1724 		(void) set_errno(EINVAL);
   1725 		return (0);
   1726 	}
   1727 
   1728 	if (pa + n < pa) {
   1729 		(void) set_errno(EMDB_WPRANGE);
   1730 		return (0);
   1731 	}
   1732 
   1733 	return (t->t_ops->t_add_pwapt(t, pa, n, flags, spec_flags, func, p));
   1734 }
   1735 
   1736 int
   1737 mdb_tgt_add_vwapt(mdb_tgt_t *t, uintptr_t va, size_t n, uint_t flags,
   1738     int spec_flags, mdb_tgt_se_f *func, void *p)
   1739 {
   1740 	if ((flags & ~MDB_TGT_WA_RWX) || flags == 0) {
   1741 		(void) set_errno(EINVAL);
   1742 		return (0);
   1743 	}
   1744 
   1745 	if (va + n < va) {
   1746 		(void) set_errno(EMDB_WPRANGE);
   1747 		return (0);
   1748 	}
   1749 
   1750 	return (t->t_ops->t_add_vwapt(t, va, n, flags, spec_flags, func, p));
   1751 }
   1752 
   1753 int
   1754 mdb_tgt_add_iowapt(mdb_tgt_t *t, uintptr_t addr, size_t n, uint_t flags,
   1755     int spec_flags, mdb_tgt_se_f *func, void *p)
   1756 {
   1757 	if ((flags & ~MDB_TGT_WA_RWX) || flags == 0) {
   1758 		(void) set_errno(EINVAL);
   1759 		return (0);
   1760 	}
   1761 
   1762 	if (addr + n < addr) {
   1763 		(void) set_errno(EMDB_WPRANGE);
   1764 		return (0);
   1765 	}
   1766 
   1767 	return (t->t_ops->t_add_iowapt(t, addr, n, flags, spec_flags, func, p));
   1768 }
   1769 
   1770 int
   1771 mdb_tgt_add_sysenter(mdb_tgt_t *t, int sysnum,
   1772     int spec_flags, mdb_tgt_se_f *func, void *p)
   1773 {
   1774 	return (t->t_ops->t_add_sysenter(t, sysnum, spec_flags, func, p));
   1775 }
   1776 
   1777 int
   1778 mdb_tgt_add_sysexit(mdb_tgt_t *t, int sysnum,
   1779     int spec_flags, mdb_tgt_se_f *func, void *p)
   1780 {
   1781 	return (t->t_ops->t_add_sysexit(t, sysnum, spec_flags, func, p));
   1782 }
   1783 
   1784 int
   1785 mdb_tgt_add_signal(mdb_tgt_t *t, int sig,
   1786     int spec_flags, mdb_tgt_se_f *func, void *p)
   1787 {
   1788 	return (t->t_ops->t_add_signal(t, sig, spec_flags, func, p));
   1789 }
   1790 
   1791 int
   1792 mdb_tgt_add_fault(mdb_tgt_t *t, int flt,
   1793     int spec_flags, mdb_tgt_se_f *func, void *p)
   1794 {
   1795 	return (t->t_ops->t_add_fault(t, flt, spec_flags, func, p));
   1796 }
   1797 
   1798 int
   1799 mdb_tgt_getareg(mdb_tgt_t *t, mdb_tgt_tid_t tid,
   1800     const char *rname, mdb_tgt_reg_t *rp)
   1801 {
   1802 	return (t->t_ops->t_getareg(t, tid, rname, rp));
   1803 }
   1804 
   1805 int
   1806 mdb_tgt_putareg(mdb_tgt_t *t, mdb_tgt_tid_t tid,
   1807     const char *rname, mdb_tgt_reg_t r)
   1808 {
   1809 	return (t->t_ops->t_putareg(t, tid, rname, r));
   1810 }
   1811 
   1812 int
   1813 mdb_tgt_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gregs,
   1814     mdb_tgt_stack_f *cb, void *p)
   1815 {
   1816 	return (t->t_ops->t_stack_iter(t, gregs, cb, p));
   1817 }
   1818 
   1819 int
   1820 mdb_tgt_xdata_iter(mdb_tgt_t *t, mdb_tgt_xdata_f *func, void *private)
   1821 {
   1822 	mdb_xdata_t *xdp;
   1823 
   1824 	for (xdp = mdb_list_next(&t->t_xdlist); xdp; xdp = mdb_list_next(xdp)) {
   1825 		if (func(private, xdp->xd_name, xdp->xd_desc,
   1826 		    xdp->xd_copy(t, NULL, 0)) != 0)
   1827 			break;
   1828 	}
   1829 
   1830 	return (0);
   1831 }
   1832 
   1833 ssize_t
   1834 mdb_tgt_getxdata(mdb_tgt_t *t, const char *name, void *buf, size_t nbytes)
   1835 {
   1836 	mdb_xdata_t *xdp;
   1837 
   1838 	for (xdp = mdb_list_next(&t->t_xdlist); xdp; xdp = mdb_list_next(xdp)) {
   1839 		if (strcmp(xdp->xd_name, name) == 0)
   1840 			return (xdp->xd_copy(t, buf, nbytes));
   1841 	}
   1842 
   1843 	return (set_errno(ENODATA));
   1844 }
   1845 
   1846 long
   1847 mdb_tgt_notsup()
   1848 {
   1849 	return (set_errno(EMDB_TGTNOTSUP));
   1850 }
   1851 
   1852 void *
   1853 mdb_tgt_null()
   1854 {
   1855 	(void) set_errno(EMDB_TGTNOTSUP);
   1856 	return (NULL);
   1857 }
   1858 
   1859 long
   1860 mdb_tgt_nop()
   1861 {
   1862 	return (0L);
   1863 }
   1864 
   1865 int
   1866 mdb_tgt_xdata_insert(mdb_tgt_t *t, const char *name, const char *desc,
   1867 	ssize_t (*copy)(mdb_tgt_t *, void *, size_t))
   1868 {
   1869 	mdb_xdata_t *xdp;
   1870 
   1871 	for (xdp = mdb_list_next(&t->t_xdlist); xdp; xdp = mdb_list_next(xdp)) {
   1872 		if (strcmp(xdp->xd_name, name) == 0)
   1873 			return (set_errno(EMDB_XDEXISTS));
   1874 	}
   1875 
   1876 	xdp = mdb_alloc(sizeof (mdb_xdata_t), UM_SLEEP);
   1877 	mdb_list_append(&t->t_xdlist, xdp);
   1878 
   1879 	xdp->xd_name = name;
   1880 	xdp->xd_desc = desc;
   1881 	xdp->xd_copy = copy;
   1882 
   1883 	return (0);
   1884 }
   1885 
   1886 int
   1887 mdb_tgt_xdata_delete(mdb_tgt_t *t, const char *name)
   1888 {
   1889 	mdb_xdata_t *xdp;
   1890 
   1891 	for (xdp = mdb_list_next(&t->t_xdlist); xdp; xdp = mdb_list_next(xdp)) {
   1892 		if (strcmp(xdp->xd_name, name) == 0) {
   1893 			mdb_list_delete(&t->t_xdlist, xdp);
   1894 			mdb_free(xdp, sizeof (mdb_xdata_t));
   1895 			return (0);
   1896 		}
   1897 	}
   1898 
   1899 	return (set_errno(EMDB_NOXD));
   1900 }
   1901 
   1902 int
   1903 mdb_tgt_sym_match(const GElf_Sym *sym, uint_t mask)
   1904 {
   1905 #if STT_NUM != (STT_TLS + 1)
   1906 #error "STT_NUM has grown. update mdb_tgt_sym_match()"
   1907 #endif
   1908 
   1909 	uchar_t s_bind = GELF_ST_BIND(sym->st_info);
   1910 	uchar_t s_type = GELF_ST_TYPE(sym->st_info);
   1911 
   1912 	/*
   1913 	 * In case you haven't already guessed, this relies on the bitmask
   1914 	 * used by <mdb/mdb_target.h> and <libproc.h> for encoding symbol
   1915 	 * type and binding matching the order of STB and STT constants
   1916 	 * in <sys/elf.h>.  Changes to ELF must maintain binary
   1917 	 * compatibility, so I think this is reasonably fair game.
   1918 	 */
   1919 	if (s_bind < STB_NUM && s_type < STT_NUM) {
   1920 		uint_t type = (1 << (s_type + 8)) | (1 << s_bind);
   1921 		return ((type & ~mask) == 0);
   1922 	}
   1923 
   1924 	return (0); /* Unknown binding or type; fail to match */
   1925 }
   1926 
   1927 void
   1928 mdb_tgt_elf_export(mdb_gelf_file_t *gf)
   1929 {
   1930 	GElf_Xword d = 0, t = 0;
   1931 	GElf_Addr b = 0, e = 0;
   1932 	uint32_t m = 0;
   1933 	mdb_var_t *v;
   1934 
   1935 	/*
   1936 	 * Reset legacy adb variables based on the specified ELF object file
   1937 	 * provided by the target.  We define these variables:
   1938 	 *
   1939 	 * b - the address of the data segment (first writeable Phdr)
   1940 	 * d - the size of the data segment
   1941 	 * e - the address of the entry point
   1942 	 * m - the magic number identifying the file
   1943 	 * t - the address of the text segment (first executable Phdr)
   1944 	 */
   1945 	if (gf != NULL) {
   1946 		const GElf_Phdr *text = NULL, *data = NULL;
   1947 		size_t i;
   1948 
   1949 		e = gf->gf_ehdr.e_entry;
   1950 		bcopy(&gf->gf_ehdr.e_ident[EI_MAG0], &m, sizeof (m));
   1951 
   1952 		for (i = 0; i < gf->gf_npload; i++) {
   1953 			if (text == NULL && (gf->gf_phdrs[i].p_flags & PF_X))
   1954 				text = &gf->gf_phdrs[i];
   1955 			if (data == NULL && (gf->gf_phdrs[i].p_flags & PF_W))
   1956 				data = &gf->gf_phdrs[i];
   1957 		}
   1958 
   1959 		if (text != NULL)
   1960 			t = text->p_memsz;
   1961 		if (data != NULL) {
   1962 			b = data->p_vaddr;
   1963 			d = data->p_memsz;
   1964 		}
   1965 	}
   1966 
   1967 	if ((v = mdb_nv_lookup(&mdb.m_nv, "b")) != NULL)
   1968 		mdb_nv_set_value(v, b);
   1969 	if ((v = mdb_nv_lookup(&mdb.m_nv, "d")) != NULL)
   1970 		mdb_nv_set_value(v, d);
   1971 	if ((v = mdb_nv_lookup(&mdb.m_nv, "e")) != NULL)
   1972 		mdb_nv_set_value(v, e);
   1973 	if ((v = mdb_nv_lookup(&mdb.m_nv, "m")) != NULL)
   1974 		mdb_nv_set_value(v, m);
   1975 	if ((v = mdb_nv_lookup(&mdb.m_nv, "t")) != NULL)
   1976 		mdb_nv_set_value(v, t);
   1977 }
   1978 
   1979 /*ARGSUSED*/
   1980 void
   1981 mdb_tgt_sespec_hold(mdb_tgt_t *t, mdb_sespec_t *sep)
   1982 {
   1983 	sep->se_refs++;
   1984 	ASSERT(sep->se_refs != 0);
   1985 }
   1986 
   1987 void
   1988 mdb_tgt_sespec_rele(mdb_tgt_t *t, mdb_sespec_t *sep)
   1989 {
   1990 	ASSERT(sep->se_refs != 0);
   1991 
   1992 	if (--sep->se_refs == 0) {
   1993 		mdb_dprintf(MDB_DBG_TGT, "destroying sespec %p\n", (void *)sep);
   1994 		ASSERT(mdb_list_next(&sep->se_velist) == NULL);
   1995 
   1996 		if (sep->se_state != MDB_TGT_SPEC_IDLE) {
   1997 			sep->se_ops->se_dtor(t, sep);
   1998 			mdb_list_delete(&t->t_active, sep);
   1999 		} else
   2000 			mdb_list_delete(&t->t_idle, sep);
   2001 
   2002 		mdb_free(sep, sizeof (mdb_sespec_t));
   2003 	}
   2004 }
   2005 
   2006 mdb_sespec_t *
   2007 mdb_tgt_sespec_insert(mdb_tgt_t *t, const mdb_se_ops_t *ops, mdb_list_t *list)
   2008 {
   2009 	mdb_sespec_t *sep = mdb_zalloc(sizeof (mdb_sespec_t), UM_SLEEP);
   2010 
   2011 	if (list == &t->t_active)
   2012 		sep->se_state = MDB_TGT_SPEC_ACTIVE;
   2013 	else
   2014 		sep->se_state = MDB_TGT_SPEC_IDLE;
   2015 
   2016 	mdb_list_append(list, sep);
   2017 	sep->se_ops = ops;
   2018 	return (sep);
   2019 }
   2020 
   2021 mdb_sespec_t *
   2022 mdb_tgt_sespec_lookup_active(mdb_tgt_t *t, const mdb_se_ops_t *ops, void *args)
   2023 {
   2024 	mdb_sespec_t *sep;
   2025 
   2026 	for (sep = mdb_list_next(&t->t_active); sep; sep = mdb_list_next(sep)) {
   2027 		if (sep->se_ops == ops && sep->se_ops->se_secmp(t, sep, args))
   2028 			break;
   2029 	}
   2030 
   2031 	return (sep);
   2032 }
   2033 
   2034 mdb_sespec_t *
   2035 mdb_tgt_sespec_lookup_idle(mdb_tgt_t *t, const mdb_se_ops_t *ops, void *args)
   2036 {
   2037 	mdb_sespec_t *sep;
   2038 
   2039 	for (sep = mdb_list_next(&t->t_idle); sep; sep = mdb_list_next(sep)) {
   2040 		if (sep->se_ops == ops && sep->se_ops->se_vecmp(t,
   2041 		    mdb_list_next(&sep->se_velist), args))
   2042 			break;
   2043 	}
   2044 
   2045 	return (sep);
   2046 }
   2047 
   2048 /*ARGSUSED*/
   2049 void
   2050 mdb_tgt_vespec_hold(mdb_tgt_t *t, mdb_vespec_t *vep)
   2051 {
   2052 	vep->ve_refs++;
   2053 	ASSERT(vep->ve_refs != 0);
   2054 }
   2055 
   2056 void
   2057 mdb_tgt_vespec_rele(mdb_tgt_t *t, mdb_vespec_t *vep)
   2058 {
   2059 	ASSERT(vep->ve_refs != 0);
   2060 
   2061 	if (--vep->ve_refs == 0) {
   2062 		/*
   2063 		 * Remove this vespec from the sespec's velist and decrement
   2064 		 * the reference count on the sespec.
   2065 		 */
   2066 		mdb_list_delete(&vep->ve_se->se_velist, vep);
   2067 		mdb_tgt_sespec_rele(t, vep->ve_se);
   2068 
   2069 		/*
   2070 		 * If we are deleting the most recently assigned VID, reset
   2071 		 * t_vepos or t_veneg as appropriate to re-use that number.
   2072 		 * This could be enhanced to re-use any free number by
   2073 		 * maintaining a bitmap or hash of the allocated IDs.
   2074 		 */
   2075 		if (vep->ve_id > 0 && t->t_vepos == vep->ve_id + 1)
   2076 			t->t_vepos = vep->ve_id;
   2077 		else if (vep->ve_id < 0 && t->t_veneg == -vep->ve_id + 1)
   2078 			t->t_veneg = -vep->ve_id;
   2079 
   2080 		/*
   2081 		 * Call the destructor to clean up ve_args, and then free
   2082 		 * the actual vespec structure.
   2083 		 */
   2084 		vep->ve_dtor(vep);
   2085 		mdb_free(vep, sizeof (mdb_vespec_t));
   2086 
   2087 		ASSERT(t->t_vecnt != 0);
   2088 		t->t_vecnt--;
   2089 	}
   2090 }
   2091 
   2092 int
   2093 mdb_tgt_vespec_insert(mdb_tgt_t *t, const mdb_se_ops_t *ops, int flags,
   2094     mdb_tgt_se_f *func, void *data, void *args, void (*dtor)(mdb_vespec_t *))
   2095 {
   2096 	mdb_vespec_t *vep = mdb_zalloc(sizeof (mdb_vespec_t), UM_SLEEP);
   2097 
   2098 	int id, mult, *seqp;
   2099 	mdb_sespec_t *sep;
   2100 
   2101 	/*
   2102 	 * Make that only one MDB_TGT_SPEC_AUTO* bit is set in the new flags
   2103 	 * value: extra bits are cleared according to order of precedence.
   2104 	 */
   2105 	if (flags & MDB_TGT_SPEC_AUTOSTOP)
   2106 		flags &= ~(MDB_TGT_SPEC_AUTODEL | MDB_TGT_SPEC_AUTODIS);
   2107 	else if (flags & MDB_TGT_SPEC_AUTODEL)
   2108 		flags &= ~MDB_TGT_SPEC_AUTODIS;
   2109 
   2110 	/*
   2111 	 * The TEMPORARY property always takes precedence over STICKY.
   2112 	 */
   2113 	if (flags & MDB_TGT_SPEC_TEMPORARY)
   2114 		flags &= ~MDB_TGT_SPEC_STICKY;
   2115 
   2116 	/*
   2117 	 * Find a matching sespec or create a new one on the appropriate list.
   2118 	 * We always create a new sespec if the vespec is created disabled.
   2119 	 */
   2120 	if (flags & MDB_TGT_SPEC_DISABLED)
   2121 		sep = mdb_tgt_sespec_insert(t, ops, &t->t_idle);
   2122 	else if ((sep = mdb_tgt_sespec_lookup_active(t, ops, args)) == NULL &&
   2123 	    (sep = mdb_tgt_sespec_lookup_idle(t, ops, args)) == NULL)
   2124 		sep = mdb_tgt_sespec_insert(t, ops, &t->t_active);
   2125 
   2126 	/*
   2127 	 * Generate a new ID for the vespec.  Increasing positive integers are
   2128 	 * assigned to visible vespecs; decreasing negative integers are
   2129 	 * assigned to hidden vespecs.  The target saves our most recent choice.
   2130 	 */
   2131 	if (flags & MDB_TGT_SPEC_INTERNAL) {
   2132 		seqp = &t->t_veneg;
   2133 		mult = -1;
   2134 	} else {
   2135 		seqp = &t->t_vepos;
   2136 		mult = 1;
   2137 	}
   2138 
   2139 	id = *seqp;
   2140 
   2141 	while (mdb_tgt_vespec_lookup(t, id * mult) != NULL)
   2142 		id = MAX(id + 1, 1);
   2143 
   2144 	*seqp = MAX(id + 1, 1);
   2145 
   2146 	vep->ve_id = id * mult;
   2147 	vep->ve_flags = flags & ~(MDB_TGT_SPEC_MATCHED | MDB_TGT_SPEC_DELETED);
   2148 	vep->ve_se = sep;
   2149 	vep->ve_callback = func;
   2150 	vep->ve_data = data;
   2151 	vep->ve_args = args;
   2152 	vep->ve_dtor = dtor;
   2153 
   2154 	mdb_list_append(&sep->se_velist, vep);
   2155 	mdb_tgt_sespec_hold(t, sep);
   2156 
   2157 	mdb_tgt_vespec_hold(t, vep);
   2158 	t->t_vecnt++;
   2159 
   2160 	/*
   2161 	 * If this vespec is the first reference to the sespec and it's active,
   2162 	 * then it is newly created and we should attempt to initialize it.
   2163 	 * If se_ctor fails, then move the sespec back to the idle list.
   2164 	 */
   2165 	if (sep->se_refs == 1 && sep->se_state == MDB_TGT_SPEC_ACTIVE &&
   2166 	    sep->se_ops->se_ctor(t, sep, vep->ve_args) == -1) {
   2167 
   2168 		mdb_list_delete(&t->t_active, sep);
   2169 		mdb_list_append(&t->t_idle, sep);
   2170 
   2171 		sep->se_state = MDB_TGT_SPEC_IDLE;
   2172 		sep->se_errno = errno;
   2173 		sep->se_data = NULL;
   2174 	}
   2175 
   2176 	/*
   2177 	 * If the sespec is active and the target is currently running (because
   2178 	 * we grabbed it using PGRAB_NOSTOP), then go ahead and attempt to arm
   2179 	 * the sespec so it will take effect immediately.
   2180 	 */
   2181 	if (sep->se_state == MDB_TGT_SPEC_ACTIVE &&
   2182 	    t->t_status.st_state == MDB_TGT_RUNNING)
   2183 		mdb_tgt_sespec_arm_one(t, sep);
   2184 
   2185 	mdb_dprintf(MDB_DBG_TGT, "inserted [ %d ] sep=%p refs=%u state=%d\n",
   2186 	    vep->ve_id, (void *)sep, sep->se_refs, sep->se_state);
   2187 
   2188 	return (vep->ve_id);
   2189 }
   2190 
   2191 /*
   2192  * Search the target's active, idle, and disabled lists for the vespec matching
   2193  * the specified VID, and return a pointer to it, or NULL if no match is found.
   2194  */
   2195 mdb_vespec_t *
   2196 mdb_tgt_vespec_lookup(mdb_tgt_t *t, int vid)
   2197 {
   2198 	mdb_sespec_t *sep;
   2199 	mdb_vespec_t *vep;
   2200 
   2201 	if (vid == 0)
   2202 		return (NULL); /* 0 is never a valid VID */
   2203 
   2204 	for (sep = mdb_list_next(&t->t_active); sep; sep = mdb_list_next(sep)) {
   2205 		for (vep = mdb_list_next(&sep->se_velist); vep;
   2206 		    vep = mdb_list_next(vep)) {
   2207 			if (vep->ve_id == vid)
   2208 				return (vep);
   2209 		}
   2210 	}
   2211 
   2212 	for (sep = mdb_list_next(&t->t_idle); sep; sep = mdb_list_next(sep)) {
   2213 		for (vep = mdb_list_next(&sep->se_velist); vep;
   2214 		    vep = mdb_list_next(vep)) {
   2215 			if (vep->ve_id == vid)
   2216 				return (vep);
   2217 		}
   2218 	}
   2219 
   2220 	return (NULL);
   2221 }
   2222 
   2223 /*ARGSUSED*/
   2224 void
   2225 no_ve_dtor(mdb_vespec_t *vep)
   2226 {
   2227 	/* default destructor does nothing */
   2228 }
   2229 
   2230 /*ARGSUSED*/
   2231 void
   2232 no_se_f(mdb_tgt_t *t, int vid, void *data)
   2233 {
   2234 	/* default callback does nothing */
   2235 }
   2236 
   2237 /*ARGSUSED*/
   2238 void
   2239 no_se_dtor(mdb_tgt_t *t, mdb_sespec_t *sep)
   2240 {
   2241 	/* default destructor does nothing */
   2242 }
   2243 
   2244 /*ARGSUSED*/
   2245 int
   2246 no_se_secmp(mdb_tgt_t *t, mdb_sespec_t *sep, void *args)
   2247 {
   2248 	return (sep->se_data == args);
   2249 }
   2250 
   2251 /*ARGSUSED*/
   2252 int
   2253 no_se_vecmp(mdb_tgt_t *t, mdb_vespec_t *vep, void *args)
   2254 {
   2255 	return (vep->ve_args == args);
   2256 }
   2257 
   2258 /*ARGSUSED*/
   2259 int
   2260 no_se_arm(mdb_tgt_t *t, mdb_sespec_t *sep)
   2261 {
   2262 	return (0); /* return success */
   2263 }
   2264 
   2265 /*ARGSUSED*/
   2266 int
   2267 no_se_disarm(mdb_tgt_t *t, mdb_sespec_t *sep)
   2268 {
   2269 	return (0); /* return success */
   2270 }
   2271 
   2272 /*ARGSUSED*/
   2273 int
   2274 no_se_cont(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_tgt_status_t *tsp)
   2275 {
   2276 	if (tsp != &t->t_status)
   2277 		bcopy(&t->t_status, tsp, sizeof (mdb_tgt_status_t));
   2278 
   2279 	return (0); /* return success */
   2280 }
   2281 
   2282 int
   2283 mdb_tgt_register_dcmds(mdb_tgt_t *t, const mdb_dcmd_t *dcp, int flags)
   2284 {
   2285 	int fail = 0;
   2286 
   2287 	for (; dcp->dc_name != NULL; dcp++) {
   2288 		if (mdb_module_add_dcmd(t->t_module, dcp, flags) == -1) {
   2289 			warn("failed to add dcmd %s", dcp->dc_name);
   2290 			fail++;
   2291 		}
   2292 	}
   2293 
   2294 	return (fail > 0 ? -1 : 0);
   2295 }
   2296 
   2297 int
   2298 mdb_tgt_register_walkers(mdb_tgt_t *t, const mdb_walker_t *wp, int flags)
   2299 {
   2300 	int fail = 0;
   2301 
   2302 	for (; wp->walk_name != NULL; wp++) {
   2303 		if (mdb_module_add_walker(t->t_module, wp, flags) == -1) {
   2304 			warn("failed to add walk %s", wp->walk_name);
   2305 			fail++;
   2306 		}
   2307 	}
   2308 
   2309 	return (fail > 0 ? -1 : 0);
   2310 }
   2311 
   2312 void
   2313 mdb_tgt_register_regvars(mdb_tgt_t *t, const mdb_tgt_regdesc_t *rdp,
   2314     const mdb_nv_disc_t *disc, int flags)
   2315 {
   2316 	for (; rdp->rd_name != NULL; rdp++) {
   2317 		if (!(rdp->rd_flags & MDB_TGT_R_EXPORT))
   2318 			continue; /* Don't export register as a variable */
   2319 
   2320 		if (rdp->rd_flags & MDB_TGT_R_RDONLY)
   2321 			flags |= MDB_NV_RDONLY;
   2322 
   2323 		(void) mdb_nv_insert(&mdb.m_nv, rdp->rd_name, disc,
   2324 		    (uintptr_t)t, MDB_NV_PERSIST | flags);
   2325 	}
   2326 }
   2327