xref: /illumos-gate/usr/src/cmd/mdb/common/mdb/mdb_disasm.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <mdb/mdb_disasm_impl.h>
30 #include <mdb/mdb_modapi.h>
31 #include <mdb/mdb_string.h>
32 #include <mdb/mdb_debug.h>
33 #include <mdb/mdb_err.h>
34 #include <mdb/mdb_nv.h>
35 #include <mdb/mdb.h>
36 
37 int
38 mdb_dis_select(const char *name)
39 {
40 	mdb_var_t *v = mdb_nv_lookup(&mdb.m_disasms, name);
41 
42 	if (v != NULL) {
43 		mdb.m_disasm = mdb_nv_get_cookie(v);
44 		return (0);
45 	}
46 
47 	if (mdb.m_target == NULL) {
48 		if (mdb.m_defdisasm != NULL)
49 			strfree(mdb.m_defdisasm);
50 		mdb.m_defdisasm = strdup(name);
51 		return (0);
52 	}
53 
54 	return (set_errno(EMDB_NODIS));
55 }
56 
57 mdb_disasm_t *
58 mdb_dis_create(mdb_dis_ctor_f *ctor)
59 {
60 	mdb_disasm_t *dp = mdb_zalloc(sizeof (mdb_disasm_t), UM_SLEEP);
61 
62 	if ((dp->dis_module = mdb.m_lmod) == NULL)
63 		dp->dis_module = &mdb.m_rmod;
64 
65 	if (ctor(dp) == 0) {
66 		mdb_var_t *v = mdb_nv_lookup(&mdb.m_disasms, dp->dis_name);
67 
68 		if (v != NULL) {
69 			dp->dis_ops->dis_destroy(dp);
70 			mdb_free(dp, sizeof (mdb_disasm_t));
71 			(void) set_errno(EMDB_DISEXISTS);
72 			return (NULL);
73 		}
74 
75 		(void) mdb_nv_insert(&mdb.m_disasms, dp->dis_name, NULL,
76 		    (uintptr_t)dp, MDB_NV_RDONLY | MDB_NV_SILENT);
77 
78 		if (mdb.m_disasm == NULL) {
79 			mdb.m_disasm = dp;
80 		} else if (mdb.m_defdisasm != NULL &&
81 		    strcmp(mdb.m_defdisasm, dp->dis_name) == 0) {
82 			mdb.m_disasm = dp;
83 			strfree(mdb.m_defdisasm);
84 			mdb.m_defdisasm = NULL;
85 		}
86 
87 		return (dp);
88 	}
89 
90 	mdb_free(dp, sizeof (mdb_disasm_t));
91 	return (NULL);
92 }
93 
94 void
95 mdb_dis_destroy(mdb_disasm_t *dp)
96 {
97 	mdb_var_t *v = mdb_nv_lookup(&mdb.m_disasms, dp->dis_name);
98 
99 	ASSERT(v != NULL);
100 	mdb_nv_remove(&mdb.m_disasms, v);
101 	dp->dis_ops->dis_destroy(dp);
102 	mdb_free(dp, sizeof (mdb_disasm_t));
103 
104 	if (mdb.m_disasm == dp)
105 		(void) mdb_dis_select("default");
106 }
107 
108 mdb_tgt_addr_t
109 mdb_dis_ins2str(mdb_disasm_t *dp, mdb_tgt_t *t, mdb_tgt_as_t as,
110     char *buf, size_t len, mdb_tgt_addr_t addr)
111 {
112 	return (dp->dis_ops->dis_ins2str(dp, t, as, buf, len, addr));
113 }
114 
115 mdb_tgt_addr_t
116 mdb_dis_previns(mdb_disasm_t *dp, mdb_tgt_t *t, mdb_tgt_as_t as,
117     mdb_tgt_addr_t addr, uint_t n)
118 {
119 	return (dp->dis_ops->dis_previns(dp, t, as, addr, n));
120 }
121 
122 mdb_tgt_addr_t
123 mdb_dis_nextins(mdb_disasm_t *dp, mdb_tgt_t *t, mdb_tgt_as_t as,
124     mdb_tgt_addr_t addr)
125 {
126 	return (dp->dis_ops->dis_nextins(dp, t, as, addr));
127 }
128 
129 /*ARGSUSED*/
130 int
131 cmd_dismode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
132 {
133 	if ((flags & DCMD_ADDRSPEC) || argc > 1)
134 		return (DCMD_USAGE);
135 
136 	if (argc != 0) {
137 		const char *name;
138 
139 		if (argv->a_type == MDB_TYPE_STRING)
140 			name = argv->a_un.a_str;
141 		else
142 			name = numtostr(argv->a_un.a_val, 10, NTOS_UNSIGNED);
143 
144 		if (mdb_dis_select(name) == -1) {
145 			warn("failed to set disassembly mode");
146 			return (DCMD_ERR);
147 		}
148 	}
149 
150 	mdb_printf("disassembly mode is %s (%s)\n",
151 	    mdb.m_disasm->dis_name, mdb.m_disasm->dis_desc);
152 
153 	return (DCMD_OK);
154 }
155 
156 /*ARGSUSED*/
157 static int
158 print_dis(mdb_var_t *v, void *ignore)
159 {
160 	mdb_disasm_t *dp = mdb_nv_get_cookie(v);
161 
162 	mdb_printf("%-24s - %s\n", dp->dis_name, dp->dis_desc);
163 	return (0);
164 }
165 
166 /*ARGSUSED*/
167 int
168 cmd_disasms(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
169 {
170 	if ((flags & DCMD_ADDRSPEC) || argc != 0)
171 		return (DCMD_USAGE);
172 
173 	mdb_nv_sort_iter(&mdb.m_disasms, print_dis, NULL, UM_SLEEP | UM_GC);
174 	return (DCMD_OK);
175 }
176 
177 /*ARGSUSED*/
178 static void
179 defdis_destroy(mdb_disasm_t *dp)
180 {
181 	/* Nothing to do here */
182 }
183 
184 /*ARGSUSED*/
185 static mdb_tgt_addr_t
186 defdis_ins2str(mdb_disasm_t *dp, mdb_tgt_t *t, mdb_tgt_as_t as,
187     char *buf, size_t len, mdb_tgt_addr_t addr)
188 {
189 	return (addr);
190 }
191 
192 /*ARGSUSED*/
193 static mdb_tgt_addr_t
194 defdis_previns(mdb_disasm_t *dp, mdb_tgt_t *t, mdb_tgt_as_t as,
195     mdb_tgt_addr_t addr, uint_t n)
196 {
197 	return (addr);
198 }
199 
200 /*ARGSUSED*/
201 static mdb_tgt_addr_t
202 defdis_nextins(mdb_disasm_t *dp, mdb_tgt_t *t, mdb_tgt_as_t as,
203     mdb_tgt_addr_t addr)
204 {
205 	return (addr);
206 }
207 
208 static const mdb_dis_ops_t defdis_ops = {
209 	defdis_destroy,
210 	defdis_ins2str,
211 	defdis_previns,
212 	defdis_nextins
213 };
214 
215 static int
216 defdis_create(mdb_disasm_t *dp)
217 {
218 	dp->dis_name = "default";
219 	dp->dis_desc = "default no-op disassembler";
220 	dp->dis_ops = &defdis_ops;
221 
222 	return (0);
223 }
224 
225 mdb_dis_ctor_f *const mdb_dis_builtins[] = {
226 #if defined(__amd64)
227 	ia32_create,
228 	amd64_create,
229 #elif defined(__i386)
230 	ia32_create,
231 #endif
232 	defdis_create,
233 	NULL
234 };
235