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
58a6a72fdSaf  * Common Development and Distribution License (the "License").
68a6a72fdSaf  * 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  */
21c9a6ea2eSBryan Cantrill 
227c478bd9Sstevel@tonic-gate /*
23c9a6ea2eSBryan Cantrill  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
2422ce0148SMatthew Ahrens  * Copyright (c) 2013 by Delphix. All rights reserved.
25ab2e2ee8SGordon Ross  * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
260eb3364fSJohn Levon  * Copyright 2019 Joyent, Inc.
27*a48fdbefSBryan Cantrill  * Copyright 2024 Oxide Computer Company
2861f797f5SJason King  * Copyright 2023 RackTop Systems, Inc.
2965bed588SAndy Fiddaman  * Copyright 2023 OmniOS Community Edition (OmniOSce) Association.
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
337c478bd9Sstevel@tonic-gate #include <mdb/mdb_module.h>
347c478bd9Sstevel@tonic-gate #include <mdb/mdb_string.h>
357c478bd9Sstevel@tonic-gate #include <mdb/mdb_debug.h>
367c478bd9Sstevel@tonic-gate #include <mdb/mdb_callb.h>
377c478bd9Sstevel@tonic-gate #include <mdb/mdb_dump.h>
387c478bd9Sstevel@tonic-gate #include <mdb/mdb_err.h>
397c478bd9Sstevel@tonic-gate #include <mdb/mdb_io.h>
407c478bd9Sstevel@tonic-gate #include <mdb/mdb_lex.h>
417c478bd9Sstevel@tonic-gate #include <mdb/mdb_frame.h>
427c478bd9Sstevel@tonic-gate #include <mdb/mdb.h>
4346f52c84SRobert Mustacchi #include <inttypes.h>
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate /*
467c478bd9Sstevel@tonic-gate  * Private callback structure for implementing mdb_walk_dcmd, below.
477c478bd9Sstevel@tonic-gate  */
487c478bd9Sstevel@tonic-gate typedef struct {
497c478bd9Sstevel@tonic-gate 	mdb_idcmd_t *dw_dcmd;
507c478bd9Sstevel@tonic-gate 	mdb_argvec_t dw_argv;
517c478bd9Sstevel@tonic-gate 	uint_t dw_flags;
527c478bd9Sstevel@tonic-gate } dcmd_walk_arg_t;
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate /*
557c478bd9Sstevel@tonic-gate  * Global properties which modules are allowed to look at.  These are
567c478bd9Sstevel@tonic-gate  * re-initialized by the target activation callbacks.
577c478bd9Sstevel@tonic-gate  */
587c478bd9Sstevel@tonic-gate int mdb_prop_postmortem = FALSE;	/* Are we examining a dump? */
597c478bd9Sstevel@tonic-gate int mdb_prop_kernel = FALSE;		/* Are we examining a kernel? */
607c478bd9Sstevel@tonic-gate int mdb_prop_datamodel = 0;		/* Data model (see mdb_target_impl.h) */
617c478bd9Sstevel@tonic-gate 
62ab2e2ee8SGordon Ross static int
63ab2e2ee8SGordon Ross call_idcmd(mdb_idcmd_t *idcp, uintmax_t addr, uintmax_t count,
64ab2e2ee8SGordon Ross     uint_t flags, mdb_argvec_t *argv);
65ab2e2ee8SGordon Ross 
66d70f65dfSToomas Soome int
mdb_snprintfrac(char * buf,int len,uint64_t numerator,uint64_t denom,int frac_digits)67d70f65dfSToomas Soome mdb_snprintfrac(char *buf, int len,
68d70f65dfSToomas Soome     uint64_t numerator, uint64_t denom, int frac_digits)
69d70f65dfSToomas Soome {
70d70f65dfSToomas Soome 	int mul = 1;
71d70f65dfSToomas Soome 	int whole, frac, i;
72d70f65dfSToomas Soome 
73d70f65dfSToomas Soome 	for (i = frac_digits; i; i--)
74d70f65dfSToomas Soome 		mul *= 10;
75d70f65dfSToomas Soome 	whole = numerator / denom;
76d70f65dfSToomas Soome 	frac = mul * numerator / denom - mul * whole;
77d70f65dfSToomas Soome 	return (mdb_snprintf(buf, len, "%u.%0*u", whole, frac_digits, frac));
78d70f65dfSToomas Soome }
79d70f65dfSToomas Soome 
80d70f65dfSToomas Soome void
mdb_nicenum(uint64_t num,char * buf)81d70f65dfSToomas Soome mdb_nicenum(uint64_t num, char *buf)
82d70f65dfSToomas Soome {
83d70f65dfSToomas Soome 	uint64_t n = num;
84d70f65dfSToomas Soome 	int index = 0;
85d70f65dfSToomas Soome 	char *u;
86d70f65dfSToomas Soome 
87d70f65dfSToomas Soome 	while (n >= 1024) {
88d70f65dfSToomas Soome 		n = (n + (1024 / 2)) / 1024; /* Round up or down */
89d70f65dfSToomas Soome 		index++;
90d70f65dfSToomas Soome 	}
91d70f65dfSToomas Soome 
92d70f65dfSToomas Soome 	u = &" \0K\0M\0G\0T\0P\0E\0"[index*2];
93d70f65dfSToomas Soome 
94d70f65dfSToomas Soome 	if (index == 0) {
95d70f65dfSToomas Soome 		(void) mdb_snprintf(buf, MDB_NICENUM_BUFLEN, "%llu",
96d70f65dfSToomas Soome 		    (u_longlong_t)n);
97d70f65dfSToomas Soome 	} else if (n < 10 && (num & (num - 1)) != 0) {
98d70f65dfSToomas Soome 		(void) mdb_snprintfrac(buf, MDB_NICENUM_BUFLEN,
99d70f65dfSToomas Soome 		    num, 1ULL << 10 * index, 2);
1000eb3364fSJohn Levon 		(void) strcat(buf, u);
101d70f65dfSToomas Soome 	} else if (n < 100 && (num & (num - 1)) != 0) {
102d70f65dfSToomas Soome 		(void) mdb_snprintfrac(buf, MDB_NICENUM_BUFLEN,
103d70f65dfSToomas Soome 		    num, 1ULL << 10 * index, 1);
1040eb3364fSJohn Levon 		(void) strcat(buf, u);
105d70f65dfSToomas Soome 	} else {
106d70f65dfSToomas Soome 		(void) mdb_snprintf(buf, MDB_NICENUM_BUFLEN, "%llu%s",
107d70f65dfSToomas Soome 		    (u_longlong_t)n, u);
108d70f65dfSToomas Soome 	}
109d70f65dfSToomas Soome }
110d70f65dfSToomas Soome 
11161f797f5SJason King void
mdb_nicetime(int64_t delta,char * buf,size_t buflen)11261f797f5SJason King mdb_nicetime(int64_t delta, char *buf, size_t buflen)
11361f797f5SJason King {
11461f797f5SJason King 	const char	*sign = (delta < 0) ? "-" : "+";
11561f797f5SJason King 	char		daybuf[32] = { 0 };
11661f797f5SJason King 	char		fracbuf[32] = { 0 };
11761f797f5SJason King 
11861f797f5SJason King 	if (delta < 0)
11961f797f5SJason King 		delta = -delta;
12061f797f5SJason King 
12161f797f5SJason King 	if (delta == 0) {
12261f797f5SJason King 		(void) mdb_snprintf(buf, buflen, "0ns");
12361f797f5SJason King 		return;
12461f797f5SJason King 	}
12561f797f5SJason King 
12661f797f5SJason King 	/* Handle values < 1s */
12761f797f5SJason King 	if (delta < NANOSEC) {
12861f797f5SJason King 		static const char f_units[] = "num";
12961f797f5SJason King 
13061f797f5SJason King 		uint_t idx = 0;
13161f797f5SJason King 		while (delta >= 1000) {
13261f797f5SJason King 			delta /= 1000;
13361f797f5SJason King 			idx++;
13461f797f5SJason King 		}
13561f797f5SJason King 
13661f797f5SJason King 		(void) mdb_snprintf(buf, buflen, "t%s%lld%cs",
13761f797f5SJason King 		    sign, delta, f_units[idx]);
13861f797f5SJason King 		return;
13961f797f5SJason King 	}
14061f797f5SJason King 
14161f797f5SJason King 	uint64_t days, hours, mins, secs, frac;
14261f797f5SJason King 
14361f797f5SJason King 	frac = delta % NANOSEC;
14461f797f5SJason King 	delta /= NANOSEC;
14561f797f5SJason King 
14661f797f5SJason King 	secs = delta % 60;
14761f797f5SJason King 	delta /= 60;
14861f797f5SJason King 
14961f797f5SJason King 	mins = delta % 60;
15061f797f5SJason King 	delta /= 60;
15161f797f5SJason King 
15261f797f5SJason King 	hours = delta % 24;
15361f797f5SJason King 	delta /= 24;
15461f797f5SJason King 
15561f797f5SJason King 	days = delta;
15661f797f5SJason King 
15761f797f5SJason King 	if (days > 0)
15861f797f5SJason King 		(void) mdb_snprintf(daybuf, sizeof (daybuf), "%llud ", days);
15961f797f5SJason King 
16061f797f5SJason King 	if (frac > 0)
16161f797f5SJason King 		(void) mdb_snprintf(fracbuf, sizeof (fracbuf), ".%llu", frac);
16261f797f5SJason King 
16361f797f5SJason King 	(void) mdb_snprintf(buf, buflen, "t%s%s%02llu:%02llu:%02llu%s",
16461f797f5SJason King 	    sign, daybuf, hours, mins, secs, fracbuf);
16561f797f5SJason King }
16661f797f5SJason King 
1677c478bd9Sstevel@tonic-gate ssize_t
mdb_vread(void * buf,size_t nbytes,uintptr_t addr)1687c478bd9Sstevel@tonic-gate mdb_vread(void *buf, size_t nbytes, uintptr_t addr)
1697c478bd9Sstevel@tonic-gate {
1707c478bd9Sstevel@tonic-gate 	ssize_t rbytes = mdb_tgt_vread(mdb.m_target, buf, nbytes, addr);
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	if (rbytes > 0 && rbytes < nbytes)
1737c478bd9Sstevel@tonic-gate 		return (set_errbytes(rbytes, nbytes));
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	return (rbytes);
1767c478bd9Sstevel@tonic-gate }
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate ssize_t
mdb_vwrite(const void * buf,size_t nbytes,uintptr_t addr)1797c478bd9Sstevel@tonic-gate mdb_vwrite(const void *buf, size_t nbytes, uintptr_t addr)
1807c478bd9Sstevel@tonic-gate {
1817c478bd9Sstevel@tonic-gate 	return (mdb_tgt_vwrite(mdb.m_target, buf, nbytes, addr));
1827c478bd9Sstevel@tonic-gate }
1837c478bd9Sstevel@tonic-gate 
1842a12f85aSJeremy Jones ssize_t
mdb_aread(void * buf,size_t nbytes,uintptr_t addr,void * as)1852a12f85aSJeremy Jones mdb_aread(void *buf, size_t nbytes, uintptr_t addr, void *as)
1862a12f85aSJeremy Jones {
1872a12f85aSJeremy Jones 	ssize_t rbytes = mdb_tgt_aread(mdb.m_target, as, buf, nbytes, addr);
1882a12f85aSJeremy Jones 
1892a12f85aSJeremy Jones 	if (rbytes > 0 && rbytes < nbytes)
1902a12f85aSJeremy Jones 		return (set_errbytes(rbytes, nbytes));
1912a12f85aSJeremy Jones 
1922a12f85aSJeremy Jones 	return (rbytes);
1932a12f85aSJeremy Jones }
1942a12f85aSJeremy Jones 
1952a12f85aSJeremy Jones ssize_t
mdb_awrite(const void * buf,size_t nbytes,uintptr_t addr,void * as)1962a12f85aSJeremy Jones mdb_awrite(const void *buf, size_t nbytes, uintptr_t addr, void *as)
1972a12f85aSJeremy Jones {
1982a12f85aSJeremy Jones 	return (mdb_tgt_awrite(mdb.m_target, as, buf, nbytes, addr));
1992a12f85aSJeremy Jones }
2002a12f85aSJeremy Jones 
2017c478bd9Sstevel@tonic-gate ssize_t
mdb_fread(void * buf,size_t nbytes,uintptr_t addr)2027c478bd9Sstevel@tonic-gate mdb_fread(void *buf, size_t nbytes, uintptr_t addr)
2037c478bd9Sstevel@tonic-gate {
2047c478bd9Sstevel@tonic-gate 	ssize_t rbytes = mdb_tgt_fread(mdb.m_target, buf, nbytes, addr);
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	if (rbytes > 0 && rbytes < nbytes)
2077c478bd9Sstevel@tonic-gate 		return (set_errbytes(rbytes, nbytes));
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	return (rbytes);
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate ssize_t
mdb_fwrite(const void * buf,size_t nbytes,uintptr_t addr)2137c478bd9Sstevel@tonic-gate mdb_fwrite(const void *buf, size_t nbytes, uintptr_t addr)
2147c478bd9Sstevel@tonic-gate {
2157c478bd9Sstevel@tonic-gate 	return (mdb_tgt_fwrite(mdb.m_target, buf, nbytes, addr));
2167c478bd9Sstevel@tonic-gate }
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate ssize_t
mdb_pread(void * buf,size_t nbytes,physaddr_t addr)2197c478bd9Sstevel@tonic-gate mdb_pread(void *buf, size_t nbytes, physaddr_t addr)
2207c478bd9Sstevel@tonic-gate {
2217c478bd9Sstevel@tonic-gate 	ssize_t rbytes = mdb_tgt_pread(mdb.m_target, buf, nbytes, addr);
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 	if (rbytes > 0 && rbytes < nbytes)
2247c478bd9Sstevel@tonic-gate 		return (set_errbytes(rbytes, nbytes));
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	return (rbytes);
2277c478bd9Sstevel@tonic-gate }
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate ssize_t
mdb_pwrite(const void * buf,size_t nbytes,physaddr_t addr)2307c478bd9Sstevel@tonic-gate mdb_pwrite(const void *buf, size_t nbytes, physaddr_t addr)
2317c478bd9Sstevel@tonic-gate {
2327c478bd9Sstevel@tonic-gate 	return (mdb_tgt_pwrite(mdb.m_target, buf, nbytes, addr));
2337c478bd9Sstevel@tonic-gate }
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate ssize_t
mdb_readstr(char * buf,size_t nbytes,uintptr_t addr)2367c478bd9Sstevel@tonic-gate mdb_readstr(char *buf, size_t nbytes, uintptr_t addr)
2377c478bd9Sstevel@tonic-gate {
2387c478bd9Sstevel@tonic-gate 	return (mdb_tgt_readstr(mdb.m_target, MDB_TGT_AS_VIRT,
2397c478bd9Sstevel@tonic-gate 	    buf, nbytes, addr));
2407c478bd9Sstevel@tonic-gate }
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate ssize_t
mdb_writestr(const char * buf,uintptr_t addr)2437c478bd9Sstevel@tonic-gate mdb_writestr(const char *buf, uintptr_t addr)
2447c478bd9Sstevel@tonic-gate {
2457c478bd9Sstevel@tonic-gate 	return (mdb_tgt_writestr(mdb.m_target, MDB_TGT_AS_VIRT, buf, addr));
2467c478bd9Sstevel@tonic-gate }
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate ssize_t
mdb_readsym(void * buf,size_t nbytes,const char * name)2497c478bd9Sstevel@tonic-gate mdb_readsym(void *buf, size_t nbytes, const char *name)
2507c478bd9Sstevel@tonic-gate {
2517c478bd9Sstevel@tonic-gate 	ssize_t rbytes = mdb_tgt_readsym(mdb.m_target, MDB_TGT_AS_VIRT,
25222ce0148SMatthew Ahrens 	    buf, nbytes, MDB_TGT_OBJ_EVERY, name);
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	if (rbytes > 0 && rbytes < nbytes)
2557c478bd9Sstevel@tonic-gate 		return (set_errbytes(rbytes, nbytes));
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	return (rbytes);
2587c478bd9Sstevel@tonic-gate }
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate ssize_t
mdb_writesym(const void * buf,size_t nbytes,const char * name)2617c478bd9Sstevel@tonic-gate mdb_writesym(const void *buf, size_t nbytes, const char *name)
2627c478bd9Sstevel@tonic-gate {
2637c478bd9Sstevel@tonic-gate 	return (mdb_tgt_writesym(mdb.m_target, MDB_TGT_AS_VIRT,
26422ce0148SMatthew Ahrens 	    buf, nbytes, MDB_TGT_OBJ_EVERY, name));
2657c478bd9Sstevel@tonic-gate }
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate ssize_t
mdb_readvar(void * buf,const char * name)2687c478bd9Sstevel@tonic-gate mdb_readvar(void *buf, const char *name)
2697c478bd9Sstevel@tonic-gate {
2707c478bd9Sstevel@tonic-gate 	GElf_Sym sym;
2717c478bd9Sstevel@tonic-gate 
27222ce0148SMatthew Ahrens 	if (mdb_tgt_lookup_by_name(mdb.m_target, MDB_TGT_OBJ_EVERY,
2737c478bd9Sstevel@tonic-gate 	    name, &sym, NULL))
2747c478bd9Sstevel@tonic-gate 		return (-1);
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 	if (mdb_tgt_vread(mdb.m_target, buf, sym.st_size,
2777c478bd9Sstevel@tonic-gate 	    (uintptr_t)sym.st_value) == sym.st_size)
2787c478bd9Sstevel@tonic-gate 		return ((ssize_t)sym.st_size);
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	return (-1);
2817c478bd9Sstevel@tonic-gate }
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate ssize_t
mdb_writevar(const void * buf,const char * name)2847c478bd9Sstevel@tonic-gate mdb_writevar(const void *buf, const char *name)
2857c478bd9Sstevel@tonic-gate {
2867c478bd9Sstevel@tonic-gate 	GElf_Sym sym;
2877c478bd9Sstevel@tonic-gate 
28822ce0148SMatthew Ahrens 	if (mdb_tgt_lookup_by_name(mdb.m_target, MDB_TGT_OBJ_EVERY,
2897c478bd9Sstevel@tonic-gate 	    name, &sym, NULL))
2907c478bd9Sstevel@tonic-gate 		return (-1);
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	if (mdb_tgt_vwrite(mdb.m_target, buf, sym.st_size,
2937c478bd9Sstevel@tonic-gate 	    (uintptr_t)sym.st_value) == sym.st_size)
2947c478bd9Sstevel@tonic-gate 		return ((ssize_t)sym.st_size);
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	return (-1);
2977c478bd9Sstevel@tonic-gate }
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate int
mdb_lookup_by_name(const char * name,GElf_Sym * sym)3007c478bd9Sstevel@tonic-gate mdb_lookup_by_name(const char *name, GElf_Sym *sym)
3017c478bd9Sstevel@tonic-gate {
30222ce0148SMatthew Ahrens 	return (mdb_lookup_by_obj(MDB_TGT_OBJ_EVERY, name, sym));
3037c478bd9Sstevel@tonic-gate }
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate int
mdb_lookup_by_obj(const char * obj,const char * name,GElf_Sym * sym)3067c478bd9Sstevel@tonic-gate mdb_lookup_by_obj(const char *obj, const char *name, GElf_Sym *sym)
3077c478bd9Sstevel@tonic-gate {
3087c478bd9Sstevel@tonic-gate 	return (mdb_tgt_lookup_by_name(mdb.m_target, obj, name, sym, NULL));
3097c478bd9Sstevel@tonic-gate }
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate int
mdb_lookup_by_addr(uintptr_t addr,uint_t flags,char * buf,size_t nbytes,GElf_Sym * sym)3127c478bd9Sstevel@tonic-gate mdb_lookup_by_addr(uintptr_t addr, uint_t flags, char *buf,
3134585130bSYuri Pankov     size_t nbytes, GElf_Sym *sym)
3147c478bd9Sstevel@tonic-gate {
3157c478bd9Sstevel@tonic-gate 	return (mdb_tgt_lookup_by_addr(mdb.m_target, addr, flags,
3167c478bd9Sstevel@tonic-gate 	    buf, nbytes, sym, NULL));
3177c478bd9Sstevel@tonic-gate }
3187c478bd9Sstevel@tonic-gate 
319c9a6ea2eSBryan Cantrill int
mdb_getareg(mdb_tid_t tid,const char * rname,mdb_reg_t * rp)320c9a6ea2eSBryan Cantrill mdb_getareg(mdb_tid_t tid, const char *rname, mdb_reg_t *rp)
321c9a6ea2eSBryan Cantrill {
322c9a6ea2eSBryan Cantrill 	return (mdb_tgt_getareg(mdb.m_target, tid, rname, rp));
323c9a6ea2eSBryan Cantrill }
324c9a6ea2eSBryan Cantrill 
325*a48fdbefSBryan Cantrill int
mdb_thread_name(mdb_tid_t tid,char * buf,size_t bufsize)326*a48fdbefSBryan Cantrill mdb_thread_name(mdb_tid_t tid, char *buf, size_t bufsize)
327*a48fdbefSBryan Cantrill {
328*a48fdbefSBryan Cantrill 	return (mdb_tgt_thread_name(mdb.m_target, tid, buf, bufsize));
329*a48fdbefSBryan Cantrill }
330*a48fdbefSBryan Cantrill 
33146f52c84SRobert Mustacchi static u_longlong_t
mdb_strtoull_int(const char * s,int radix)33246f52c84SRobert Mustacchi mdb_strtoull_int(const char *s, int radix)
3337c478bd9Sstevel@tonic-gate {
3347c478bd9Sstevel@tonic-gate 	if (s[0] == '0') {
3357c478bd9Sstevel@tonic-gate 		switch (s[1]) {
3367c478bd9Sstevel@tonic-gate 		case 'I':
3377c478bd9Sstevel@tonic-gate 		case 'i':
3387c478bd9Sstevel@tonic-gate 			radix = 2;
3397c478bd9Sstevel@tonic-gate 			s += 2;
3407c478bd9Sstevel@tonic-gate 			break;
3417c478bd9Sstevel@tonic-gate 		case 'O':
3427c478bd9Sstevel@tonic-gate 		case 'o':
3437c478bd9Sstevel@tonic-gate 			radix = 8;
3447c478bd9Sstevel@tonic-gate 			s += 2;
3457c478bd9Sstevel@tonic-gate 			break;
3467c478bd9Sstevel@tonic-gate 		case 'T':
3477c478bd9Sstevel@tonic-gate 		case 't':
3487c478bd9Sstevel@tonic-gate 			radix = 10;
3497c478bd9Sstevel@tonic-gate 			s += 2;
3507c478bd9Sstevel@tonic-gate 			break;
3517c478bd9Sstevel@tonic-gate 		case 'X':
3527c478bd9Sstevel@tonic-gate 		case 'x':
3537c478bd9Sstevel@tonic-gate 			radix = 16;
3547c478bd9Sstevel@tonic-gate 			s += 2;
3557c478bd9Sstevel@tonic-gate 			break;
3567c478bd9Sstevel@tonic-gate 		}
3577c478bd9Sstevel@tonic-gate 	}
3587c478bd9Sstevel@tonic-gate 
3594585130bSYuri Pankov 	return (mdb_strtonum(s, radix));
3607c478bd9Sstevel@tonic-gate }
3617c478bd9Sstevel@tonic-gate 
36246f52c84SRobert Mustacchi u_longlong_t
mdb_strtoullx(const char * s,mdb_strtoull_flags_t flags)36346f52c84SRobert Mustacchi mdb_strtoullx(const char *s, mdb_strtoull_flags_t flags)
36446f52c84SRobert Mustacchi {
36546f52c84SRobert Mustacchi 	int radix;
36646f52c84SRobert Mustacchi 
36746f52c84SRobert Mustacchi 	if ((flags & ~MDB_STRTOULL_F_BASE_C) != 0) {
36846f52c84SRobert Mustacchi 		mdb_warn("invalid options specified: 0x%lx" PRIx64 "\n",
36946f52c84SRobert Mustacchi 		    (uint64_t)flags);
37046f52c84SRobert Mustacchi 		return ((uintmax_t)ULLONG_MAX);
37146f52c84SRobert Mustacchi 	}
37246f52c84SRobert Mustacchi 
37346f52c84SRobert Mustacchi 	if ((flags & MDB_STRTOULL_F_BASE_C) != 0) {
37446f52c84SRobert Mustacchi 		radix = 10;
37546f52c84SRobert Mustacchi 	} else {
37646f52c84SRobert Mustacchi 		radix = mdb.m_radix;
37746f52c84SRobert Mustacchi 	}
37846f52c84SRobert Mustacchi 
37946f52c84SRobert Mustacchi 	return (mdb_strtoull_int(s, radix));
38046f52c84SRobert Mustacchi }
38146f52c84SRobert Mustacchi 
38246f52c84SRobert Mustacchi u_longlong_t
mdb_strtoull(const char * s)38346f52c84SRobert Mustacchi mdb_strtoull(const char *s)
38446f52c84SRobert Mustacchi {
38546f52c84SRobert Mustacchi 	return (mdb_strtoull_int(s, mdb.m_radix));
38646f52c84SRobert Mustacchi }
38746f52c84SRobert Mustacchi 
3887c478bd9Sstevel@tonic-gate size_t
mdb_snprintf(char * buf,size_t nbytes,const char * format,...)3897c478bd9Sstevel@tonic-gate mdb_snprintf(char *buf, size_t nbytes, const char *format, ...)
3907c478bd9Sstevel@tonic-gate {
3917c478bd9Sstevel@tonic-gate 	va_list alist;
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 	va_start(alist, format);
3947c478bd9Sstevel@tonic-gate 	nbytes = mdb_iob_vsnprintf(buf, nbytes, format, alist);
3957c478bd9Sstevel@tonic-gate 	va_end(alist);
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	return (nbytes);
3987c478bd9Sstevel@tonic-gate }
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate void
mdb_printf(const char * format,...)4017c478bd9Sstevel@tonic-gate mdb_printf(const char *format, ...)
4027c478bd9Sstevel@tonic-gate {
4037c478bd9Sstevel@tonic-gate 	va_list alist;
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	va_start(alist, format);
4067c478bd9Sstevel@tonic-gate 	mdb_iob_vprintf(mdb.m_out, format, alist);
4077c478bd9Sstevel@tonic-gate 	va_end(alist);
4087c478bd9Sstevel@tonic-gate }
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate void
mdb_warn(const char * format,...)4117c478bd9Sstevel@tonic-gate mdb_warn(const char *format, ...)
4127c478bd9Sstevel@tonic-gate {
4137c478bd9Sstevel@tonic-gate 	va_list alist;
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	va_start(alist, format);
4167c478bd9Sstevel@tonic-gate 	vwarn(format, alist);
4177c478bd9Sstevel@tonic-gate 	va_end(alist);
4187c478bd9Sstevel@tonic-gate }
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate void
mdb_flush(void)4217c478bd9Sstevel@tonic-gate mdb_flush(void)
4227c478bd9Sstevel@tonic-gate {
4237c478bd9Sstevel@tonic-gate 	mdb_iob_flush(mdb.m_out);
4247c478bd9Sstevel@tonic-gate }
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate /*
4277c478bd9Sstevel@tonic-gate  * Convert an object of len bytes pointed to by srcraw between
4287c478bd9Sstevel@tonic-gate  * network-order and host-order and store in dstraw.  The length len must
4297c478bd9Sstevel@tonic-gate  * be the actual length of the objects pointed to by srcraw and dstraw (or
4307c478bd9Sstevel@tonic-gate  * zero) or the results are undefined.  srcraw and dstraw may be the same,
4317c478bd9Sstevel@tonic-gate  * in which case the object is converted in-place.  Note that this routine
4327c478bd9Sstevel@tonic-gate  * will convert from host-order to network-order or network-order to
4337c478bd9Sstevel@tonic-gate  * host-order, since the conversion is the same in either case.
4347c478bd9Sstevel@tonic-gate  */
4357c478bd9Sstevel@tonic-gate /* ARGSUSED */
4367c478bd9Sstevel@tonic-gate void
mdb_nhconvert(void * dstraw,const void * srcraw,size_t len)4377c478bd9Sstevel@tonic-gate mdb_nhconvert(void *dstraw, const void *srcraw, size_t len)
4387c478bd9Sstevel@tonic-gate {
4397c478bd9Sstevel@tonic-gate #ifdef	_LITTLE_ENDIAN
4407c478bd9Sstevel@tonic-gate 	uint8_t	b1, b2;
4417c478bd9Sstevel@tonic-gate 	uint8_t *dst, *src;
4427c478bd9Sstevel@tonic-gate 	size_t i;
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 	dst = (uint8_t *)dstraw;
4457c478bd9Sstevel@tonic-gate 	src = (uint8_t *)srcraw;
4467c478bd9Sstevel@tonic-gate 	for (i = 0; i < len / 2; i++) {
4477c478bd9Sstevel@tonic-gate 		b1 = src[i];
4487c478bd9Sstevel@tonic-gate 		b2 = src[len - i - 1];
4497c478bd9Sstevel@tonic-gate 		dst[i] = b2;
4507c478bd9Sstevel@tonic-gate 		dst[len - i - 1] = b1;
4517c478bd9Sstevel@tonic-gate 	}
4527c478bd9Sstevel@tonic-gate #else
4537c478bd9Sstevel@tonic-gate 	if (dstraw != srcraw)
4547c478bd9Sstevel@tonic-gate 		bcopy(srcraw, dstraw, len);
4557c478bd9Sstevel@tonic-gate #endif
4567c478bd9Sstevel@tonic-gate }
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate /*
4607c478bd9Sstevel@tonic-gate  * Bit formatting functions: Note the interesting use of UM_GC here to
4617c478bd9Sstevel@tonic-gate  * allocate a buffer for the caller which will be automatically freed
4627c478bd9Sstevel@tonic-gate  * when the dcmd completes or is forcibly aborted.
4637c478bd9Sstevel@tonic-gate  */
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate #define	NBNB			(NBBY / 2)	/* number of bits per nibble */
4667c478bd9Sstevel@tonic-gate #define	SETBIT(buf, j, c) { \
4677c478bd9Sstevel@tonic-gate 	if (((j) + 1) % (NBNB + 1) == 0) \
4687c478bd9Sstevel@tonic-gate 		(buf)[(j)++] = ' '; \
4697c478bd9Sstevel@tonic-gate 	(buf)[(j)++] = (c); \
4707c478bd9Sstevel@tonic-gate }
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate const char *
mdb_one_bit(int width,int bit,int on)4737c478bd9Sstevel@tonic-gate mdb_one_bit(int width, int bit, int on)
4747c478bd9Sstevel@tonic-gate {
4757c478bd9Sstevel@tonic-gate 	int i, j = 0;
4767c478bd9Sstevel@tonic-gate 	char *buf;
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	buf = mdb_zalloc(width + (width / NBNB) + 2, UM_GC | UM_SLEEP);
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 	for (i = --width; i > bit; i--)
4817c478bd9Sstevel@tonic-gate 		SETBIT(buf, j, '.');
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 	SETBIT(buf, j, on ? '1' : '0');
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	for (i = bit - 1; i >= 0; i--)
4867c478bd9Sstevel@tonic-gate 		SETBIT(buf, j, '.');
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 	return (buf);
4897c478bd9Sstevel@tonic-gate }
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate const char *
mdb_inval_bits(int width,int start,int stop)4927c478bd9Sstevel@tonic-gate mdb_inval_bits(int width, int start, int stop)
4937c478bd9Sstevel@tonic-gate {
4947c478bd9Sstevel@tonic-gate 	int i, j = 0;
4957c478bd9Sstevel@tonic-gate 	char *buf;
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	buf = mdb_zalloc(width + (width / NBNB) + 2, UM_GC | UM_SLEEP);
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 	for (i = --width; i > stop; i--)
5007c478bd9Sstevel@tonic-gate 		SETBIT(buf, j, '.');
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 	for (i = stop; i >= start; i--)
5037c478bd9Sstevel@tonic-gate 		SETBIT(buf, j, 'x');
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	for (; i >= 0; i--)
5067c478bd9Sstevel@tonic-gate 		SETBIT(buf, j, '.');
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 	return (buf);
5097c478bd9Sstevel@tonic-gate }
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate ulong_t
mdb_inc_indent(ulong_t i)5127c478bd9Sstevel@tonic-gate mdb_inc_indent(ulong_t i)
5137c478bd9Sstevel@tonic-gate {
5147c478bd9Sstevel@tonic-gate 	if (mdb_iob_getflags(mdb.m_out) & MDB_IOB_INDENT) {
5157c478bd9Sstevel@tonic-gate 		ulong_t margin = mdb_iob_getmargin(mdb.m_out);
5167c478bd9Sstevel@tonic-gate 		mdb_iob_margin(mdb.m_out, margin + i);
5177c478bd9Sstevel@tonic-gate 		return (margin);
5187c478bd9Sstevel@tonic-gate 	}
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	mdb_iob_margin(mdb.m_out, i);
5217c478bd9Sstevel@tonic-gate 	mdb_iob_setflags(mdb.m_out, MDB_IOB_INDENT);
5227c478bd9Sstevel@tonic-gate 	return (0);
5237c478bd9Sstevel@tonic-gate }
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate ulong_t
mdb_dec_indent(ulong_t i)5267c478bd9Sstevel@tonic-gate mdb_dec_indent(ulong_t i)
5277c478bd9Sstevel@tonic-gate {
5287c478bd9Sstevel@tonic-gate 	if (mdb_iob_getflags(mdb.m_out) & MDB_IOB_INDENT) {
5297c478bd9Sstevel@tonic-gate 		ulong_t margin = mdb_iob_getmargin(mdb.m_out);
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 		if (margin < i || margin - i == 0) {
5327c478bd9Sstevel@tonic-gate 			mdb_iob_clrflags(mdb.m_out, MDB_IOB_INDENT);
5337c478bd9Sstevel@tonic-gate 			mdb_iob_margin(mdb.m_out, MDB_IOB_DEFMARGIN);
5347c478bd9Sstevel@tonic-gate 		} else
5357c478bd9Sstevel@tonic-gate 			mdb_iob_margin(mdb.m_out, margin - i);
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 		return (margin);
5387c478bd9Sstevel@tonic-gate 	}
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	return (0);
5417c478bd9Sstevel@tonic-gate }
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate int
mdb_eval(const char * s)5447c478bd9Sstevel@tonic-gate mdb_eval(const char *s)
5457c478bd9Sstevel@tonic-gate {
5467c478bd9Sstevel@tonic-gate 	mdb_frame_t *ofp = mdb.m_fmark;
5477c478bd9Sstevel@tonic-gate 	mdb_frame_t *fp = mdb.m_frame;
5487c478bd9Sstevel@tonic-gate 	int err;
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 	if (s == NULL)
5517c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 	/*
5547c478bd9Sstevel@tonic-gate 	 * Push m_in down onto the input stack, then set m_in to point to the
5557c478bd9Sstevel@tonic-gate 	 * i/o buffer for our command string, and reset the frame marker.
5567c478bd9Sstevel@tonic-gate 	 * The mdb_run() function returns when the new m_in iob reaches EOF.
5577c478bd9Sstevel@tonic-gate 	 */
5587c478bd9Sstevel@tonic-gate 	mdb_iob_stack_push(&fp->f_istk, mdb.m_in, yylineno);
5597c478bd9Sstevel@tonic-gate 	mdb.m_in = mdb_iob_create(mdb_strio_create(s), MDB_IOB_RDONLY);
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 	mdb.m_fmark = NULL;
5627c478bd9Sstevel@tonic-gate 	err = mdb_run();
5637c478bd9Sstevel@tonic-gate 	mdb.m_fmark = ofp;
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 	/*
5667c478bd9Sstevel@tonic-gate 	 * Now pop the old standard input stream and restore mdb.m_in and
5677c478bd9Sstevel@tonic-gate 	 * the parser's saved current line number.
5687c478bd9Sstevel@tonic-gate 	 */
5697c478bd9Sstevel@tonic-gate 	mdb.m_in = mdb_iob_stack_pop(&fp->f_istk);
5707c478bd9Sstevel@tonic-gate 	yylineno = mdb_iob_lineno(mdb.m_in);
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 	/*
5737c478bd9Sstevel@tonic-gate 	 * If mdb_run() returned an error, propagate this backward
5747c478bd9Sstevel@tonic-gate 	 * up the stack of debugger environment frames.
5757c478bd9Sstevel@tonic-gate 	 */
5767c478bd9Sstevel@tonic-gate 	if (MDB_ERR_IS_FATAL(err))
5777c478bd9Sstevel@tonic-gate 		longjmp(fp->f_pcb, err);
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 	if (err == MDB_ERR_PAGER || err == MDB_ERR_SIGINT)
5807c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_CANCEL));
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 	if (err != 0)
5837c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_EVAL));
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 	return (0);
5867c478bd9Sstevel@tonic-gate }
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate void
mdb_set_dot(uintmax_t addr)5897c478bd9Sstevel@tonic-gate mdb_set_dot(uintmax_t addr)
5907c478bd9Sstevel@tonic-gate {
5917c478bd9Sstevel@tonic-gate 	mdb_nv_set_value(mdb.m_dot, addr);
5927c478bd9Sstevel@tonic-gate 	mdb.m_incr = 0;
5937c478bd9Sstevel@tonic-gate }
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate uintmax_t
mdb_get_dot(void)5967c478bd9Sstevel@tonic-gate mdb_get_dot(void)
5977c478bd9Sstevel@tonic-gate {
5987c478bd9Sstevel@tonic-gate 	return (mdb_nv_get_value(mdb.m_dot));
5997c478bd9Sstevel@tonic-gate }
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate static int
walk_step(mdb_wcb_t * wcb)6027c478bd9Sstevel@tonic-gate walk_step(mdb_wcb_t *wcb)
6037c478bd9Sstevel@tonic-gate {
6047c478bd9Sstevel@tonic-gate 	mdb_wcb_t *nwcb = wcb->w_lyr_head;
6057c478bd9Sstevel@tonic-gate 	int status;
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	/*
6087c478bd9Sstevel@tonic-gate 	 * If the control block has no layers, we just invoke the walker's
6097c478bd9Sstevel@tonic-gate 	 * step function and return status indicating whether to continue
6107c478bd9Sstevel@tonic-gate 	 * or stop.  If the control block has layers, we need to invoke
6117c478bd9Sstevel@tonic-gate 	 * ourself recursively for the next layer, until eventually we
6127c478bd9Sstevel@tonic-gate 	 * percolate down to an unlayered walk.
6137c478bd9Sstevel@tonic-gate 	 */
6147c478bd9Sstevel@tonic-gate 	if (nwcb == NULL)
6157c478bd9Sstevel@tonic-gate 		return (wcb->w_walker->iwlk_step(&wcb->w_state));
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate 	if ((status = walk_step(nwcb)) != WALK_NEXT) {
6187c478bd9Sstevel@tonic-gate 		wcb->w_lyr_head = nwcb->w_lyr_link;
6197c478bd9Sstevel@tonic-gate 		nwcb->w_lyr_link = NULL;
6207c478bd9Sstevel@tonic-gate 		mdb_wcb_destroy(nwcb);
6217c478bd9Sstevel@tonic-gate 	}
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 	if (status == WALK_DONE && wcb->w_lyr_head != NULL)
6247c478bd9Sstevel@tonic-gate 		return (WALK_NEXT);
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 	return (status);
6277c478bd9Sstevel@tonic-gate }
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate static int
walk_common(mdb_wcb_t * wcb)6307c478bd9Sstevel@tonic-gate walk_common(mdb_wcb_t *wcb)
6317c478bd9Sstevel@tonic-gate {
6327c478bd9Sstevel@tonic-gate 	int status, rval = 0;
6337c478bd9Sstevel@tonic-gate 	mdb_frame_t *pfp;
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 	/*
6367c478bd9Sstevel@tonic-gate 	 * Enter the control block in the active list so that mdb can clean
6377c478bd9Sstevel@tonic-gate 	 * up after it in case we abort out of the current command.
6387c478bd9Sstevel@tonic-gate 	 */
6397c478bd9Sstevel@tonic-gate 	if ((pfp = mdb_list_prev(mdb.m_frame)) != NULL && pfp->f_pcmd != NULL)
6407c478bd9Sstevel@tonic-gate 		mdb_wcb_insert(wcb, pfp);
6417c478bd9Sstevel@tonic-gate 	else
6427c478bd9Sstevel@tonic-gate 		mdb_wcb_insert(wcb, mdb.m_frame);
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 	/*
6457c478bd9Sstevel@tonic-gate 	 * The per-walk constructor performs private buffer initialization
6467c478bd9Sstevel@tonic-gate 	 * and locates whatever symbols are necessary.
6477c478bd9Sstevel@tonic-gate 	 */
6487c478bd9Sstevel@tonic-gate 	if ((status = wcb->w_walker->iwlk_init(&wcb->w_state)) != WALK_NEXT) {
6497c478bd9Sstevel@tonic-gate 		if (status != WALK_DONE)
6507c478bd9Sstevel@tonic-gate 			rval = set_errno(EMDB_WALKINIT);
6517c478bd9Sstevel@tonic-gate 		goto done;
6527c478bd9Sstevel@tonic-gate 	}
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 	/*
6557c478bd9Sstevel@tonic-gate 	 * Mark wcb to indicate that walk_init has been called (which means
6567c478bd9Sstevel@tonic-gate 	 * we can call walk_fini if the walk is aborted at this point).
6577c478bd9Sstevel@tonic-gate 	 */
6587c478bd9Sstevel@tonic-gate 	wcb->w_inited = TRUE;
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 	while (walk_step(wcb) == WALK_NEXT)
6617c478bd9Sstevel@tonic-gate 		continue;
6627c478bd9Sstevel@tonic-gate done:
6637c478bd9Sstevel@tonic-gate 	if ((pfp = mdb_list_prev(mdb.m_frame)) != NULL && pfp->f_pcmd != NULL)
6647c478bd9Sstevel@tonic-gate 		mdb_wcb_delete(wcb, pfp);
6657c478bd9Sstevel@tonic-gate 	else
6667c478bd9Sstevel@tonic-gate 		mdb_wcb_delete(wcb, mdb.m_frame);
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 	mdb_wcb_destroy(wcb);
6697c478bd9Sstevel@tonic-gate 	return (rval);
6707c478bd9Sstevel@tonic-gate }
6717c478bd9Sstevel@tonic-gate 
67228e4da25SMatthew Ahrens typedef struct pwalk_step {
67328e4da25SMatthew Ahrens 	mdb_walk_cb_t ps_cb;
67428e4da25SMatthew Ahrens 	void *ps_private;
67528e4da25SMatthew Ahrens } pwalk_step_t;
67628e4da25SMatthew Ahrens 
67728e4da25SMatthew Ahrens static int
pwalk_step(uintptr_t addr,const void * data,void * private)67828e4da25SMatthew Ahrens pwalk_step(uintptr_t addr, const void *data, void *private)
67928e4da25SMatthew Ahrens {
68028e4da25SMatthew Ahrens 	pwalk_step_t *psp = private;
68128e4da25SMatthew Ahrens 	int ret;
68228e4da25SMatthew Ahrens 
68328e4da25SMatthew Ahrens 	mdb.m_frame->f_cbactive = B_TRUE;
68428e4da25SMatthew Ahrens 	ret = psp->ps_cb(addr, data, psp->ps_private);
68528e4da25SMatthew Ahrens 	mdb.m_frame->f_cbactive = B_FALSE;
68628e4da25SMatthew Ahrens 
68728e4da25SMatthew Ahrens 	return (ret);
68828e4da25SMatthew Ahrens }
68928e4da25SMatthew Ahrens 
6907c478bd9Sstevel@tonic-gate int
mdb_pwalk(const char * name,mdb_walk_cb_t func,void * private,uintptr_t addr)69128e4da25SMatthew Ahrens mdb_pwalk(const char *name, mdb_walk_cb_t func, void *private, uintptr_t addr)
6927c478bd9Sstevel@tonic-gate {
6937c478bd9Sstevel@tonic-gate 	mdb_iwalker_t *iwp = mdb_walker_lookup(name);
69428e4da25SMatthew Ahrens 	pwalk_step_t p;
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 	if (func == NULL)
6977c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
6987c478bd9Sstevel@tonic-gate 
69928e4da25SMatthew Ahrens 	p.ps_cb = func;
70028e4da25SMatthew Ahrens 	p.ps_private = private;
70128e4da25SMatthew Ahrens 
70228e4da25SMatthew Ahrens 	if (iwp != NULL) {
70328e4da25SMatthew Ahrens 		int ret;
70428e4da25SMatthew Ahrens 		int cbactive = mdb.m_frame->f_cbactive;
70528e4da25SMatthew Ahrens 		mdb.m_frame->f_cbactive = B_FALSE;
70628e4da25SMatthew Ahrens 		ret = walk_common(mdb_wcb_create(iwp, pwalk_step, &p, addr));
70728e4da25SMatthew Ahrens 		mdb.m_frame->f_cbactive = cbactive;
70828e4da25SMatthew Ahrens 		return (ret);
70928e4da25SMatthew Ahrens 	}
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 	return (-1); /* errno is set for us */
7127c478bd9Sstevel@tonic-gate }
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate int
mdb_walk(const char * name,mdb_walk_cb_t func,void * data)7157c478bd9Sstevel@tonic-gate mdb_walk(const char *name, mdb_walk_cb_t func, void *data)
7167c478bd9Sstevel@tonic-gate {
717892ad162SToomas Soome 	return (mdb_pwalk(name, func, data, 0));
7187c478bd9Sstevel@tonic-gate }
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7217c478bd9Sstevel@tonic-gate static int
walk_dcmd(uintptr_t addr,const void * ignored,dcmd_walk_arg_t * dwp)7227c478bd9Sstevel@tonic-gate walk_dcmd(uintptr_t addr, const void *ignored, dcmd_walk_arg_t *dwp)
7237c478bd9Sstevel@tonic-gate {
724315fecc4SGordon Ross 	int status;
725315fecc4SGordon Ross 
726315fecc4SGordon Ross 	mdb.m_frame->f_cbactive = B_TRUE;
727ab2e2ee8SGordon Ross 	status = call_idcmd(dwp->dw_dcmd, addr, 1, dwp->dw_flags,
728ab2e2ee8SGordon Ross 	    &dwp->dw_argv);
729315fecc4SGordon Ross 	mdb.m_frame->f_cbactive = B_FALSE;
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 	if (status == DCMD_USAGE || status == DCMD_ABORT)
7327c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 	dwp->dw_flags &= ~DCMD_LOOPFIRST;
7357c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
7367c478bd9Sstevel@tonic-gate }
7377c478bd9Sstevel@tonic-gate 
73865bed588SAndy Fiddaman static int
i_mdb_pwalk_dcmd(const char * wname,const char * dcname,int argc,const mdb_arg_t * argv,uintptr_t addr,uint_t flags)73965bed588SAndy Fiddaman i_mdb_pwalk_dcmd(const char *wname, const char *dcname,
74065bed588SAndy Fiddaman     int argc, const mdb_arg_t *argv, uintptr_t addr, uint_t flags)
7417c478bd9Sstevel@tonic-gate {
7427c478bd9Sstevel@tonic-gate 	mdb_argvec_t args;
7437c478bd9Sstevel@tonic-gate 	dcmd_walk_arg_t dw;
7447c478bd9Sstevel@tonic-gate 	mdb_iwalker_t *iwp;
7457c478bd9Sstevel@tonic-gate 	mdb_wcb_t *wcb;
7467c478bd9Sstevel@tonic-gate 	int status;
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 	if (wname == NULL || dcname == NULL)
7497c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 	if ((dw.dw_dcmd = mdb_dcmd_lookup(dcname)) == NULL)
7527c478bd9Sstevel@tonic-gate 		return (-1); /* errno is set for us */
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 	if ((iwp = mdb_walker_lookup(wname)) == NULL)
7557c478bd9Sstevel@tonic-gate 		return (-1); /* errno is set for us */
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 	args.a_data = (mdb_arg_t *)argv;
7587c478bd9Sstevel@tonic-gate 	args.a_nelems = args.a_size = argc;
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 	mdb_argvec_create(&dw.dw_argv);
7617c478bd9Sstevel@tonic-gate 	mdb_argvec_copy(&dw.dw_argv, &args);
76265bed588SAndy Fiddaman 	dw.dw_flags = flags | DCMD_LOOP | DCMD_LOOPFIRST | DCMD_ADDRSPEC;
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 	wcb = mdb_wcb_create(iwp, (mdb_walk_cb_t)walk_dcmd, &dw, addr);
7657c478bd9Sstevel@tonic-gate 	status = walk_common(wcb);
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate 	mdb_argvec_zero(&dw.dw_argv);
7687c478bd9Sstevel@tonic-gate 	mdb_argvec_destroy(&dw.dw_argv);
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 	return (status);
7717c478bd9Sstevel@tonic-gate }
7727c478bd9Sstevel@tonic-gate 
77365bed588SAndy Fiddaman int
mdb_pwalk_dcmd(const char * wname,const char * dcname,int argc,const mdb_arg_t * argv,uintptr_t addr)77465bed588SAndy Fiddaman mdb_pwalk_dcmd(const char *wname, const char *dcname,
77565bed588SAndy Fiddaman     int argc, const mdb_arg_t *argv, uintptr_t addr)
77665bed588SAndy Fiddaman {
77765bed588SAndy Fiddaman 	return (i_mdb_pwalk_dcmd(wname, dcname, argc, argv, addr, 0));
77865bed588SAndy Fiddaman }
77965bed588SAndy Fiddaman 
78065bed588SAndy Fiddaman int
mdb_fpwalk_dcmd(const char * wname,const char * dcname,int argc,const mdb_arg_t * argv,uintptr_t addr,uint_t flags)78165bed588SAndy Fiddaman mdb_fpwalk_dcmd(const char *wname, const char *dcname,
78265bed588SAndy Fiddaman     int argc, const mdb_arg_t *argv, uintptr_t addr, uint_t flags)
78365bed588SAndy Fiddaman {
78465bed588SAndy Fiddaman 	return (i_mdb_pwalk_dcmd(wname, dcname, argc, argv, addr, flags));
78565bed588SAndy Fiddaman }
78665bed588SAndy Fiddaman 
78765bed588SAndy Fiddaman 
7887c478bd9Sstevel@tonic-gate int
mdb_walk_dcmd(const char * wname,const char * dcname,int argc,const mdb_arg_t * argv)7897c478bd9Sstevel@tonic-gate mdb_walk_dcmd(const char *wname, const char *dcname,
7907c478bd9Sstevel@tonic-gate     int argc, const mdb_arg_t *argv)
7917c478bd9Sstevel@tonic-gate {
79265bed588SAndy Fiddaman 	return (i_mdb_pwalk_dcmd(wname, dcname, argc, argv, 0, 0));
7937c478bd9Sstevel@tonic-gate }
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7967c478bd9Sstevel@tonic-gate static int
layered_walk_step(uintptr_t addr,const void * data,mdb_wcb_t * wcb)7977c478bd9Sstevel@tonic-gate layered_walk_step(uintptr_t addr, const void *data, mdb_wcb_t *wcb)
7987c478bd9Sstevel@tonic-gate {
7997c478bd9Sstevel@tonic-gate 	/*
8007c478bd9Sstevel@tonic-gate 	 * Prior to calling the top-level walker's step function, reset its
8017c478bd9Sstevel@tonic-gate 	 * mdb_walk_state_t walk_addr and walk_layer members to refer to the
8027c478bd9Sstevel@tonic-gate 	 * target virtual address and data buffer of the underlying object.
8037c478bd9Sstevel@tonic-gate 	 */
8047c478bd9Sstevel@tonic-gate 	wcb->w_state.walk_addr = addr;
8057c478bd9Sstevel@tonic-gate 	wcb->w_state.walk_layer = data;
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate 	return (wcb->w_walker->iwlk_step(&wcb->w_state));
8087c478bd9Sstevel@tonic-gate }
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate int
mdb_layered_walk(const char * wname,mdb_walk_state_t * wsp)8117c478bd9Sstevel@tonic-gate mdb_layered_walk(const char *wname, mdb_walk_state_t *wsp)
8127c478bd9Sstevel@tonic-gate {
8137c478bd9Sstevel@tonic-gate 	mdb_wcb_t *cwcb, *wcb;
8147c478bd9Sstevel@tonic-gate 	mdb_iwalker_t *iwp;
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate 	if (wname == NULL || wsp == NULL)
8177c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 	if ((iwp = mdb_walker_lookup(wname)) == NULL)
8207c478bd9Sstevel@tonic-gate 		return (-1); /* errno is set for us */
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate 	if ((cwcb = mdb_wcb_from_state(wsp)) == NULL)
8237c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_BADWCB));
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate 	if (cwcb->w_walker == iwp)
8267c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_WALKLOOP));
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 	wcb = mdb_wcb_create(iwp, (mdb_walk_cb_t)layered_walk_step,
8297c478bd9Sstevel@tonic-gate 	    cwcb, wsp->walk_addr);
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 	if (iwp->iwlk_init(&wcb->w_state) != WALK_NEXT) {
8327c478bd9Sstevel@tonic-gate 		mdb_wcb_destroy(wcb);
8337c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_WALKINIT));
8347c478bd9Sstevel@tonic-gate 	}
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 	wcb->w_inited = TRUE;
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 	mdb_dprintf(MDB_DBG_WALK, "added %s`%s as %s`%s layer\n",
8397c478bd9Sstevel@tonic-gate 	    iwp->iwlk_modp->mod_name, iwp->iwlk_name,
8407c478bd9Sstevel@tonic-gate 	    cwcb->w_walker->iwlk_modp->mod_name, cwcb->w_walker->iwlk_name);
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 	if (cwcb->w_lyr_head != NULL) {
8437c478bd9Sstevel@tonic-gate 		for (cwcb = cwcb->w_lyr_head; cwcb->w_lyr_link != NULL; )
8447c478bd9Sstevel@tonic-gate 			cwcb = cwcb->w_lyr_link;
8457c478bd9Sstevel@tonic-gate 		cwcb->w_lyr_link = wcb;
8467c478bd9Sstevel@tonic-gate 	} else
8477c478bd9Sstevel@tonic-gate 		cwcb->w_lyr_head = wcb;
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 	return (0);
8507c478bd9Sstevel@tonic-gate }
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate int
mdb_call_dcmd(const char * name,uintptr_t dot,uint_t flags,int argc,const mdb_arg_t * argv)8537c478bd9Sstevel@tonic-gate mdb_call_dcmd(const char *name, uintptr_t dot, uint_t flags,
8547c478bd9Sstevel@tonic-gate     int argc, const mdb_arg_t *argv)
8557c478bd9Sstevel@tonic-gate {
8567c478bd9Sstevel@tonic-gate 	mdb_idcmd_t *idcp;
8577c478bd9Sstevel@tonic-gate 	mdb_argvec_t args;
8587c478bd9Sstevel@tonic-gate 	int status;
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 	if (name == NULL || argc < 0)
8617c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate 	if ((idcp = mdb_dcmd_lookup(name)) == NULL)
8647c478bd9Sstevel@tonic-gate 		return (-1); /* errno is set for us */
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate 	args.a_data = (mdb_arg_t *)argv;
8677c478bd9Sstevel@tonic-gate 	args.a_nelems = args.a_size = argc;
868ab2e2ee8SGordon Ross 	status = call_idcmd(idcp, dot, 1, flags, &args);
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 	if (status == DCMD_ERR || status == DCMD_ABORT)
8717c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_DCFAIL));
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 	if (status == DCMD_USAGE)
8747c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_DCUSAGE));
8757c478bd9Sstevel@tonic-gate 
8767c478bd9Sstevel@tonic-gate 	return (0);
8777c478bd9Sstevel@tonic-gate }
8787c478bd9Sstevel@tonic-gate 
879ab2e2ee8SGordon Ross /*
880ab2e2ee8SGordon Ross  * When dcmds or walkers call a dcmd that might be in another module,
881ab2e2ee8SGordon Ross  * we need to set mdb.m_frame->f_cp to an mdb_cmd that represents the
882ab2e2ee8SGordon Ross  * dcmd we're currently executing, otherwise mdb_get_module gets the
883ab2e2ee8SGordon Ross  * module of the caller instead of the module for the current dcmd.
884ab2e2ee8SGordon Ross  */
885ab2e2ee8SGordon Ross static int
call_idcmd(mdb_idcmd_t * idcp,uintmax_t addr,uintmax_t count,uint_t flags,mdb_argvec_t * argv)886ab2e2ee8SGordon Ross call_idcmd(mdb_idcmd_t *idcp, uintmax_t addr, uintmax_t count,
887ab2e2ee8SGordon Ross     uint_t flags, mdb_argvec_t *argv)
888ab2e2ee8SGordon Ross {
889ab2e2ee8SGordon Ross 	mdb_cmd_t *save_cp;
890ab2e2ee8SGordon Ross 	mdb_cmd_t cmd;
891ab2e2ee8SGordon Ross 	int ret;
892ab2e2ee8SGordon Ross 
893ab2e2ee8SGordon Ross 	bzero(&cmd, sizeof (cmd));
894ab2e2ee8SGordon Ross 	cmd.c_dcmd = idcp;
895ab2e2ee8SGordon Ross 	cmd.c_argv = *argv;
896ab2e2ee8SGordon Ross 
897ab2e2ee8SGordon Ross 	save_cp = mdb.m_frame->f_cp;
898ab2e2ee8SGordon Ross 	mdb.m_frame->f_cp = &cmd;
899ab2e2ee8SGordon Ross 
900ab2e2ee8SGordon Ross 	ret = mdb_call_idcmd(cmd.c_dcmd, addr, count, flags,
901ab2e2ee8SGordon Ross 	    &cmd.c_argv, NULL, NULL);
902ab2e2ee8SGordon Ross 
903ab2e2ee8SGordon Ross 	mdb.m_frame->f_cp = save_cp;
904ab2e2ee8SGordon Ross 
905ab2e2ee8SGordon Ross 	return (ret);
906ab2e2ee8SGordon Ross }
907ab2e2ee8SGordon Ross 
9087c478bd9Sstevel@tonic-gate int
mdb_add_walker(const mdb_walker_t * wp)9097c478bd9Sstevel@tonic-gate mdb_add_walker(const mdb_walker_t *wp)
9107c478bd9Sstevel@tonic-gate {
9117c478bd9Sstevel@tonic-gate 	mdb_module_t *mp;
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate 	if (mdb.m_lmod == NULL) {
9147c478bd9Sstevel@tonic-gate 		mdb_cmd_t *cp = mdb.m_frame->f_cp;
9157c478bd9Sstevel@tonic-gate 		mp = cp->c_dcmd->idc_modp;
9167c478bd9Sstevel@tonic-gate 	} else
9177c478bd9Sstevel@tonic-gate 		mp = mdb.m_lmod;
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate 	return (mdb_module_add_walker(mp, wp, 0));
9207c478bd9Sstevel@tonic-gate }
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate int
mdb_remove_walker(const char * name)9237c478bd9Sstevel@tonic-gate mdb_remove_walker(const char *name)
9247c478bd9Sstevel@tonic-gate {
9257c478bd9Sstevel@tonic-gate 	mdb_module_t *mp;
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 	if (mdb.m_lmod == NULL) {
9287c478bd9Sstevel@tonic-gate 		mdb_cmd_t *cp = mdb.m_frame->f_cp;
9297c478bd9Sstevel@tonic-gate 		mp = cp->c_dcmd->idc_modp;
9307c478bd9Sstevel@tonic-gate 	} else
9317c478bd9Sstevel@tonic-gate 		mp = mdb.m_lmod;
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	return (mdb_module_remove_walker(mp, name));
9347c478bd9Sstevel@tonic-gate }
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate void
mdb_get_pipe(mdb_pipe_t * p)9377c478bd9Sstevel@tonic-gate mdb_get_pipe(mdb_pipe_t *p)
9387c478bd9Sstevel@tonic-gate {
9397c478bd9Sstevel@tonic-gate 	mdb_cmd_t *cp = mdb.m_frame->f_cp;
9407c478bd9Sstevel@tonic-gate 	mdb_addrvec_t *adp = &cp->c_addrv;
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 	if (p == NULL) {
9437c478bd9Sstevel@tonic-gate 		warn("dcmd failure: mdb_get_pipe invoked with NULL pointer\n");
9447c478bd9Sstevel@tonic-gate 		longjmp(mdb.m_frame->f_pcb, MDB_ERR_API);
9457c478bd9Sstevel@tonic-gate 	}
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate 	if (adp->ad_nelems != 0) {
9487c478bd9Sstevel@tonic-gate 		ASSERT(adp->ad_ndx != 0);
9497c478bd9Sstevel@tonic-gate 		p->pipe_data = &adp->ad_data[adp->ad_ndx - 1];
9507c478bd9Sstevel@tonic-gate 		p->pipe_len = adp->ad_nelems - adp->ad_ndx + 1;
9517c478bd9Sstevel@tonic-gate 		adp->ad_ndx = adp->ad_nelems;
9527c478bd9Sstevel@tonic-gate 	} else {
9537c478bd9Sstevel@tonic-gate 		p->pipe_data = NULL;
9547c478bd9Sstevel@tonic-gate 		p->pipe_len = 0;
9557c478bd9Sstevel@tonic-gate 	}
9567c478bd9Sstevel@tonic-gate }
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate void
mdb_set_pipe(const mdb_pipe_t * p)9597c478bd9Sstevel@tonic-gate mdb_set_pipe(const mdb_pipe_t *p)
9607c478bd9Sstevel@tonic-gate {
9617c478bd9Sstevel@tonic-gate 	mdb_cmd_t *cp = mdb.m_frame->f_pcmd;
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate 	if (p == NULL) {
9647c478bd9Sstevel@tonic-gate 		warn("dcmd failure: mdb_set_pipe invoked with NULL pointer\n");
9657c478bd9Sstevel@tonic-gate 		longjmp(mdb.m_frame->f_pcb, MDB_ERR_API);
9667c478bd9Sstevel@tonic-gate 	}
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 	if (cp != NULL) {
9697c478bd9Sstevel@tonic-gate 		size_t nbytes = sizeof (uintptr_t) * p->pipe_len;
9707c478bd9Sstevel@tonic-gate 
9718a6a72fdSaf 		mdb_cmd_reset(cp);
9727c478bd9Sstevel@tonic-gate 		cp->c_addrv.ad_data = mdb_alloc(nbytes, UM_SLEEP);
9737c478bd9Sstevel@tonic-gate 		bcopy(p->pipe_data, cp->c_addrv.ad_data, nbytes);
9747c478bd9Sstevel@tonic-gate 		cp->c_addrv.ad_nelems = p->pipe_len;
9757c478bd9Sstevel@tonic-gate 		cp->c_addrv.ad_size = p->pipe_len;
9767c478bd9Sstevel@tonic-gate 	}
9777c478bd9Sstevel@tonic-gate }
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate ssize_t
mdb_get_xdata(const char * name,void * buf,size_t nbytes)9807c478bd9Sstevel@tonic-gate mdb_get_xdata(const char *name, void *buf, size_t nbytes)
9817c478bd9Sstevel@tonic-gate {
9827c478bd9Sstevel@tonic-gate 	return (mdb_tgt_getxdata(mdb.m_target, name, buf, nbytes));
9837c478bd9Sstevel@tonic-gate }
9847c478bd9Sstevel@tonic-gate 
985c9a6ea2eSBryan Cantrill /*
986c9a6ea2eSBryan Cantrill  * Private callback structure for implementing mdb_object_iter, below.
987c9a6ea2eSBryan Cantrill  */
988c9a6ea2eSBryan Cantrill typedef struct {
989c9a6ea2eSBryan Cantrill 	mdb_object_cb_t oi_cb;
990c9a6ea2eSBryan Cantrill 	void *oi_arg;
991c9a6ea2eSBryan Cantrill 	int oi_rval;
992c9a6ea2eSBryan Cantrill } object_iter_arg_t;
993c9a6ea2eSBryan Cantrill 
994c9a6ea2eSBryan Cantrill /*ARGSUSED*/
995c9a6ea2eSBryan Cantrill static int
mdb_object_cb(void * data,const mdb_map_t * map,const char * fullname)996c9a6ea2eSBryan Cantrill mdb_object_cb(void *data, const mdb_map_t *map, const char *fullname)
997c9a6ea2eSBryan Cantrill {
998c9a6ea2eSBryan Cantrill 	object_iter_arg_t *arg = data;
999c9a6ea2eSBryan Cantrill 	mdb_object_t obj;
1000c9a6ea2eSBryan Cantrill 
1001c9a6ea2eSBryan Cantrill 	if (arg->oi_rval != 0)
1002c9a6ea2eSBryan Cantrill 		return (0);
1003c9a6ea2eSBryan Cantrill 
1004c9a6ea2eSBryan Cantrill 	bzero(&obj, sizeof (obj));
1005c9a6ea2eSBryan Cantrill 	obj.obj_base = map->map_base;
1006c9a6ea2eSBryan Cantrill 	obj.obj_name = strbasename(map->map_name);
1007c9a6ea2eSBryan Cantrill 	obj.obj_size = map->map_size;
1008c9a6ea2eSBryan Cantrill 	obj.obj_fullname = fullname;
1009c9a6ea2eSBryan Cantrill 
1010c9a6ea2eSBryan Cantrill 	arg->oi_rval = arg->oi_cb(&obj, arg->oi_arg);
1011c9a6ea2eSBryan Cantrill 
1012c9a6ea2eSBryan Cantrill 	return (0);
1013c9a6ea2eSBryan Cantrill }
1014c9a6ea2eSBryan Cantrill 
1015c9a6ea2eSBryan Cantrill int
mdb_object_iter(mdb_object_cb_t cb,void * data)1016c9a6ea2eSBryan Cantrill mdb_object_iter(mdb_object_cb_t cb, void *data)
1017c9a6ea2eSBryan Cantrill {
1018c9a6ea2eSBryan Cantrill 	object_iter_arg_t arg;
1019c9a6ea2eSBryan Cantrill 
1020c9a6ea2eSBryan Cantrill 	arg.oi_cb = cb;
1021c9a6ea2eSBryan Cantrill 	arg.oi_arg = data;
1022c9a6ea2eSBryan Cantrill 	arg.oi_rval = 0;
1023c9a6ea2eSBryan Cantrill 
1024c9a6ea2eSBryan Cantrill 	if (mdb_tgt_object_iter(mdb.m_target, mdb_object_cb, &arg) != 0)
1025c9a6ea2eSBryan Cantrill 		return (-1);
1026c9a6ea2eSBryan Cantrill 
1027c9a6ea2eSBryan Cantrill 	return (arg.oi_rval);
1028c9a6ea2eSBryan Cantrill }
1029c9a6ea2eSBryan Cantrill 
1030ac58c5dbSDave Pacheco /*
1031ac58c5dbSDave Pacheco  * Private callback structure for implementing mdb_symbol_iter, below.
1032ac58c5dbSDave Pacheco  */
1033ac58c5dbSDave Pacheco typedef struct {
1034ac58c5dbSDave Pacheco 	mdb_symbol_cb_t si_cb;
1035ac58c5dbSDave Pacheco 	void *si_arg;
1036ac58c5dbSDave Pacheco 	int si_rval;
1037ac58c5dbSDave Pacheco } symbol_iter_arg_t;
1038ac58c5dbSDave Pacheco 
1039ac58c5dbSDave Pacheco /*ARGSUSED*/
1040ac58c5dbSDave Pacheco static int
mdb_symbol_cb(void * data,const GElf_Sym * gsym,const char * name,const mdb_syminfo_t * sip,const char * obj)1041ac58c5dbSDave Pacheco mdb_symbol_cb(void *data, const GElf_Sym *gsym, const char *name,
1042ac58c5dbSDave Pacheco     const mdb_syminfo_t *sip, const char *obj)
1043ac58c5dbSDave Pacheco {
1044ac58c5dbSDave Pacheco 	symbol_iter_arg_t *arg = data;
1045ac58c5dbSDave Pacheco 	mdb_symbol_t sym;
1046ac58c5dbSDave Pacheco 
1047ac58c5dbSDave Pacheco 	if (arg->si_rval != 0)
1048ac58c5dbSDave Pacheco 		return (0);
1049ac58c5dbSDave Pacheco 
1050ac58c5dbSDave Pacheco 	bzero(&sym, sizeof (sym));
1051ac58c5dbSDave Pacheco 	sym.sym_name = name;
1052ac58c5dbSDave Pacheco 	sym.sym_object = obj;
1053ac58c5dbSDave Pacheco 	sym.sym_sym = gsym;
1054ac58c5dbSDave Pacheco 	sym.sym_table = sip->sym_table;
1055ac58c5dbSDave Pacheco 	sym.sym_id = sip->sym_id;
1056ac58c5dbSDave Pacheco 
1057ac58c5dbSDave Pacheco 	arg->si_rval = arg->si_cb(&sym, arg->si_arg);
1058ac58c5dbSDave Pacheco 
1059ac58c5dbSDave Pacheco 	return (0);
1060ac58c5dbSDave Pacheco }
1061ac58c5dbSDave Pacheco 
1062ac58c5dbSDave Pacheco int
mdb_symbol_iter(const char * obj,uint_t which,uint_t type,mdb_symbol_cb_t cb,void * data)1063ac58c5dbSDave Pacheco mdb_symbol_iter(const char *obj, uint_t which, uint_t type,
1064ac58c5dbSDave Pacheco     mdb_symbol_cb_t cb, void *data)
1065ac58c5dbSDave Pacheco {
1066ac58c5dbSDave Pacheco 	symbol_iter_arg_t arg;
1067ac58c5dbSDave Pacheco 
1068ac58c5dbSDave Pacheco 	arg.si_cb = cb;
1069ac58c5dbSDave Pacheco 	arg.si_arg = data;
1070ac58c5dbSDave Pacheco 	arg.si_rval = 0;
1071ac58c5dbSDave Pacheco 
1072ac58c5dbSDave Pacheco 	if (mdb_tgt_symbol_iter(mdb.m_target, obj, which, type,
1073ac58c5dbSDave Pacheco 	    mdb_symbol_cb, &arg) != 0)
1074ac58c5dbSDave Pacheco 		return (-1);
1075ac58c5dbSDave Pacheco 
1076ac58c5dbSDave Pacheco 	return (arg.si_rval);
1077ac58c5dbSDave Pacheco }
1078ac58c5dbSDave Pacheco 
10797c478bd9Sstevel@tonic-gate /*
10807c478bd9Sstevel@tonic-gate  * Private structure and function for implementing mdb_dumpptr on top
10817c478bd9Sstevel@tonic-gate  * of mdb_dump_internal
10827c478bd9Sstevel@tonic-gate  */
10837c478bd9Sstevel@tonic-gate typedef struct dptrdat {
10847c478bd9Sstevel@tonic-gate 	mdb_dumpptr_cb_t func;
10857c478bd9Sstevel@tonic-gate 	void *arg;
10867c478bd9Sstevel@tonic-gate } dptrdat_t;
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate static ssize_t
mdb_dump_aux_ptr(void * buf,size_t nbyte,uint64_t offset,void * arg)10897c478bd9Sstevel@tonic-gate mdb_dump_aux_ptr(void *buf, size_t nbyte, uint64_t offset, void *arg)
10907c478bd9Sstevel@tonic-gate {
10917c478bd9Sstevel@tonic-gate 	dptrdat_t *dat = arg;
10927c478bd9Sstevel@tonic-gate 
10937c478bd9Sstevel@tonic-gate 	return (dat->func(buf, nbyte, offset, dat->arg));
10947c478bd9Sstevel@tonic-gate }
10957c478bd9Sstevel@tonic-gate 
10967c478bd9Sstevel@tonic-gate /*
10977c478bd9Sstevel@tonic-gate  * Private structure and function for handling callbacks which return
10987c478bd9Sstevel@tonic-gate  * EMDB_PARTIAL
10997c478bd9Sstevel@tonic-gate  */
11007c478bd9Sstevel@tonic-gate typedef struct d64dat {
11017c478bd9Sstevel@tonic-gate 	mdb_dump64_cb_t func;
11027c478bd9Sstevel@tonic-gate 	void *arg;
11037c478bd9Sstevel@tonic-gate } d64dat_t;
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate static ssize_t
mdb_dump_aux_partial(void * buf,size_t nbyte,uint64_t offset,void * arg)11067c478bd9Sstevel@tonic-gate mdb_dump_aux_partial(void *buf, size_t nbyte, uint64_t offset, void *arg)
11077c478bd9Sstevel@tonic-gate {
11087c478bd9Sstevel@tonic-gate 	d64dat_t *dat = arg;
11097c478bd9Sstevel@tonic-gate 	int result;
11107c478bd9Sstevel@tonic-gate 	int count;
11117c478bd9Sstevel@tonic-gate 
11127c478bd9Sstevel@tonic-gate 	result = dat->func(buf, nbyte, offset, dat->arg);
11137c478bd9Sstevel@tonic-gate 	if (result == -1 && errno == EMDB_PARTIAL) {
11147c478bd9Sstevel@tonic-gate 		count = 0;
11157c478bd9Sstevel@tonic-gate 		do {
11167c478bd9Sstevel@tonic-gate 			result = dat->func((char *)buf + count, 1,
11177c478bd9Sstevel@tonic-gate 			    offset + count, dat->arg);
11187c478bd9Sstevel@tonic-gate 			if (result == 1)
11197c478bd9Sstevel@tonic-gate 				count++;
11207c478bd9Sstevel@tonic-gate 		} while (count < nbyte && result == 1);
11217c478bd9Sstevel@tonic-gate 		if (count)
11227c478bd9Sstevel@tonic-gate 			result = count;
11237c478bd9Sstevel@tonic-gate 	}
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate 	return (result);
11267c478bd9Sstevel@tonic-gate }
11277c478bd9Sstevel@tonic-gate 
1128cf01ae8aSToomas Soome /* Default callback for mdb_dumpptr() is calling mdb_vread(). */
1129cf01ae8aSToomas Soome static ssize_t
mdb_dumpptr_cb(void * buf,size_t nbytes,uintptr_t addr,void * arg __unused)1130cf01ae8aSToomas Soome mdb_dumpptr_cb(void *buf, size_t nbytes, uintptr_t addr, void *arg __unused)
1131cf01ae8aSToomas Soome {
1132cf01ae8aSToomas Soome 	return (mdb_vread(buf, nbytes, addr));
1133cf01ae8aSToomas Soome }
1134cf01ae8aSToomas Soome 
11357c478bd9Sstevel@tonic-gate int
mdb_dumpptr(uintptr_t addr,size_t len,uint_t flags,mdb_dumpptr_cb_t fp,void * arg)11367c478bd9Sstevel@tonic-gate mdb_dumpptr(uintptr_t addr, size_t len, uint_t flags, mdb_dumpptr_cb_t fp,
11377c478bd9Sstevel@tonic-gate     void *arg)
11387c478bd9Sstevel@tonic-gate {
11397c478bd9Sstevel@tonic-gate 	dptrdat_t dat;
11407c478bd9Sstevel@tonic-gate 	d64dat_t dat64;
11417c478bd9Sstevel@tonic-gate 
1142cf01ae8aSToomas Soome 	if (fp == NULL)
1143cf01ae8aSToomas Soome 		dat.func = mdb_dumpptr_cb;
1144cf01ae8aSToomas Soome 	else
1145cf01ae8aSToomas Soome 		dat.func = fp;
11467c478bd9Sstevel@tonic-gate 	dat.arg = arg;
11477c478bd9Sstevel@tonic-gate 	dat64.func = mdb_dump_aux_ptr;
11487c478bd9Sstevel@tonic-gate 	dat64.arg = &dat;
11497c478bd9Sstevel@tonic-gate 	return (mdb_dump_internal(addr, len, flags, mdb_dump_aux_partial,
11507c478bd9Sstevel@tonic-gate 	    &dat64, sizeof (uintptr_t)));
11517c478bd9Sstevel@tonic-gate }
11527c478bd9Sstevel@tonic-gate 
11537c478bd9Sstevel@tonic-gate int
mdb_dump64(uint64_t addr,uint64_t len,uint_t flags,mdb_dump64_cb_t fp,void * arg)11547c478bd9Sstevel@tonic-gate mdb_dump64(uint64_t addr, uint64_t len, uint_t flags, mdb_dump64_cb_t fp,
11557c478bd9Sstevel@tonic-gate     void *arg)
11567c478bd9Sstevel@tonic-gate {
11577c478bd9Sstevel@tonic-gate 	d64dat_t dat64;
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate 	dat64.func = fp;
11607c478bd9Sstevel@tonic-gate 	dat64.arg = arg;
11617c478bd9Sstevel@tonic-gate 	return (mdb_dump_internal(addr, len, flags, mdb_dump_aux_partial,
11627c478bd9Sstevel@tonic-gate 	    &dat64, sizeof (uint64_t)));
11637c478bd9Sstevel@tonic-gate }
11647c478bd9Sstevel@tonic-gate 
11657c478bd9Sstevel@tonic-gate int
mdb_get_state(void)11667c478bd9Sstevel@tonic-gate mdb_get_state(void)
11677c478bd9Sstevel@tonic-gate {
11687c478bd9Sstevel@tonic-gate 	mdb_tgt_status_t ts;
11697c478bd9Sstevel@tonic-gate 
11707c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_status(mdb.m_target, &ts);
11717c478bd9Sstevel@tonic-gate 
11727c478bd9Sstevel@tonic-gate 	return (ts.st_state);
11737c478bd9Sstevel@tonic-gate }
11747c478bd9Sstevel@tonic-gate 
11757c478bd9Sstevel@tonic-gate void *
mdb_callback_add(int class,mdb_callback_f fp,void * arg)11767c478bd9Sstevel@tonic-gate mdb_callback_add(int class, mdb_callback_f fp, void *arg)
11777c478bd9Sstevel@tonic-gate {
11787c478bd9Sstevel@tonic-gate 	mdb_module_t *m;
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate 	if (class != MDB_CALLBACK_STCHG && class != MDB_CALLBACK_PROMPT) {
11817c478bd9Sstevel@tonic-gate 		(void) set_errno(EINVAL);
11827c478bd9Sstevel@tonic-gate 		return (NULL);
11837c478bd9Sstevel@tonic-gate 	}
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate 	if (mdb.m_lmod != NULL)
11867c478bd9Sstevel@tonic-gate 		m = mdb.m_lmod;
11877c478bd9Sstevel@tonic-gate 	else
11887c478bd9Sstevel@tonic-gate 		m = mdb.m_frame->f_cp->c_dcmd->idc_modp;
11897c478bd9Sstevel@tonic-gate 
11907c478bd9Sstevel@tonic-gate 	return (mdb_callb_add(m, class, fp, arg));
11917c478bd9Sstevel@tonic-gate }
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate void
mdb_callback_remove(void * hdl)11947c478bd9Sstevel@tonic-gate mdb_callback_remove(void *hdl)
11957c478bd9Sstevel@tonic-gate {
11967c478bd9Sstevel@tonic-gate 	mdb_callb_remove(hdl);
11977c478bd9Sstevel@tonic-gate }
1198