xref: /titanic_50/usr/src/lib/libdisasm/common/libdisasm.c (revision 0c923cf7b6cda6dcbc5df1a5974bed6386c49807)
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 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  * Copyright 2012 Joshua M. Clulow <josh@sysmgr.org>
26  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
27  */
28 
29 #include <libdisasm.h>
30 #include <stdlib.h>
31 #ifdef DIS_STANDALONE
32 #include <mdb/mdb_modapi.h>
33 #define	_MDB
34 #include <mdb/mdb_io.h>
35 #else
36 #include <stdio.h>
37 #endif
38 
39 #include "libdisasm_impl.h"
40 
41 static int _dis_errno;
42 
43 /*
44  * If we're building the standalone library, then we only want to
45  * include support for disassembly of the native architecture.
46  * The regular shared library should include support for all
47  * architectures.
48  */
49 #if !defined(DIS_STANDALONE) || defined(__i386) || defined(__amd64)
50 extern dis_arch_t dis_arch_i386;
51 #endif
52 #if !defined(DIS_STANDALONE) || defined(__sparc)
53 extern dis_arch_t dis_arch_sparc;
54 #endif
55 
56 static dis_arch_t *dis_archs[] = {
57 #if !defined(DIS_STANDALONE) || defined(__i386) || defined(__amd64)
58 	&dis_arch_i386,
59 #endif
60 #if !defined(DIS_STANDALONE) || defined(__sparc)
61 	&dis_arch_sparc,
62 #endif
63 	NULL
64 };
65 
66 /*
67  * For the standalone library, we need to link against mdb's malloc/free.
68  * Otherwise, use the standard malloc/free.
69  */
70 #ifdef DIS_STANDALONE
71 void *
72 dis_zalloc(size_t bytes)
73 {
74 	return (mdb_zalloc(bytes, UM_SLEEP));
75 }
76 
77 void
78 dis_free(void *ptr, size_t bytes)
79 {
80 	mdb_free(ptr, bytes);
81 }
82 #else
83 void *
84 dis_zalloc(size_t bytes)
85 {
86 	return (calloc(1, bytes));
87 }
88 
89 /*ARGSUSED*/
90 void
91 dis_free(void *ptr, size_t bytes)
92 {
93 	free(ptr);
94 }
95 #endif
96 
97 int
98 dis_seterrno(int error)
99 {
100 	_dis_errno = error;
101 	return (-1);
102 }
103 
104 int
105 dis_errno(void)
106 {
107 	return (_dis_errno);
108 }
109 
110 const char *
111 dis_strerror(int error)
112 {
113 	switch (error) {
114 	case E_DIS_NOMEM:
115 		return ("out of memory");
116 	case E_DIS_INVALFLAG:
117 		return ("invalid flags for this architecture");
118 	case E_DIS_UNSUPARCH:
119 		return ("unsupported machine architecture");
120 	default:
121 		return ("unknown error");
122 	}
123 }
124 
125 void
126 dis_set_data(dis_handle_t *dhp, void *data)
127 {
128 	dhp->dh_data = data;
129 }
130 
131 void
132 dis_flags_set(dis_handle_t *dhp, int f)
133 {
134 	dhp->dh_flags |= f;
135 }
136 
137 void
138 dis_flags_clear(dis_handle_t *dhp, int f)
139 {
140 	dhp->dh_flags &= ~f;
141 }
142 
143 void
144 dis_handle_destroy(dis_handle_t *dhp)
145 {
146 	if (dhp->dh_arch->da_handle_detach != NULL)
147 		dhp->dh_arch->da_handle_detach(dhp);
148 
149 	dis_free(dhp, sizeof (dis_handle_t));
150 }
151 
152 dis_handle_t *
153 dis_handle_create(int flags, void *data, dis_lookup_f lookup_func,
154     dis_read_f read_func)
155 {
156 	dis_handle_t *dhp;
157 	dis_arch_t *arch = NULL;
158 	int i;
159 
160 	/* Select an architecture based on flags */
161 	for (i = 0; dis_archs[i] != NULL; i++) {
162 		if (dis_archs[i]->da_supports_flags(flags)) {
163 			arch = dis_archs[i];
164 			break;
165 		}
166 	}
167 	if (arch == NULL) {
168 		(void) dis_seterrno(E_DIS_UNSUPARCH);
169 		return (NULL);
170 	}
171 
172 	if ((dhp = dis_zalloc(sizeof (dis_handle_t))) == NULL) {
173 		(void) dis_seterrno(E_DIS_NOMEM);
174 		return (NULL);
175 	}
176 	dhp->dh_arch = arch;
177 	dhp->dh_lookup = lookup_func;
178 	dhp->dh_read = read_func;
179 	dhp->dh_flags = flags;
180 	dhp->dh_data = data;
181 
182 	/*
183 	 * Allow the architecture-specific code to allocate
184 	 * its private data.
185 	 */
186 	if (arch->da_handle_attach != NULL &&
187 	    arch->da_handle_attach(dhp) != 0) {
188 		dis_free(dhp, sizeof (dis_handle_t));
189 		/* dis errno already set */
190 		return (NULL);
191 	}
192 
193 	return (dhp);
194 }
195 
196 int
197 dis_disassemble(dis_handle_t *dhp, uint64_t addr, char *buf, size_t buflen)
198 {
199 	return (dhp->dh_arch->da_disassemble(dhp, addr, buf, buflen));
200 }
201 
202 /*
203  * On some instruction sets (e.g., x86), we have no choice except to
204  * disassemble everything from the start of the symbol, and stop when we
205  * have reached our instruction address.  If we're not in the middle of a
206  * known symbol, then we return the same address to indicate failure.
207  */
208 static uint64_t
209 dis_generic_previnstr(dis_handle_t *dhp, uint64_t pc, int n)
210 {
211 	uint64_t *hist, addr, start;
212 	int cur, nseen;
213 	uint64_t res = pc;
214 
215 	if (n <= 0)
216 		return (pc);
217 
218 	if (dhp->dh_lookup(dhp->dh_data, pc, NULL, 0, &start, NULL) != 0 ||
219 	    start == pc)
220 		return (res);
221 
222 	hist = dis_zalloc(sizeof (uint64_t) * n);
223 
224 	for (cur = 0, nseen = 0, addr = start; addr < pc; addr = dhp->dh_addr) {
225 		hist[cur] = addr;
226 		cur = (cur + 1) % n;
227 		nseen++;
228 
229 		/* if we cannot make forward progress, give up */
230 		if (dis_disassemble(dhp, addr, NULL, 0) != 0)
231 			goto done;
232 	}
233 
234 	if (addr != pc) {
235 		/*
236 		 * We scanned past %pc, but didn't find an instruction that
237 		 * started at %pc.  This means that either the caller specified
238 		 * an invalid address, or we ran into something other than code
239 		 * during our scan.  Virtually any combination of bytes can be
240 		 * construed as a valid Intel instruction, so any non-code bytes
241 		 * we encounter will have thrown off the scan.
242 		 */
243 		goto done;
244 	}
245 
246 	res = hist[(cur + n - MIN(n, nseen)) % n];
247 
248 done:
249 	dis_free(hist, sizeof (uint64_t) * n);
250 	return (res);
251 }
252 
253 /*
254  * Return the nth previous instruction's address.  Return the same address
255  * to indicate failure.
256  */
257 uint64_t
258 dis_previnstr(dis_handle_t *dhp, uint64_t pc, int n)
259 {
260 	if (dhp->dh_arch->da_previnstr == NULL)
261 		return (dis_generic_previnstr(dhp, pc, n));
262 
263 	return (dhp->dh_arch->da_previnstr(dhp, pc, n));
264 }
265 
266 int
267 dis_min_instrlen(dis_handle_t *dhp)
268 {
269 	return (dhp->dh_arch->da_min_instrlen(dhp));
270 }
271 
272 int
273 dis_max_instrlen(dis_handle_t *dhp)
274 {
275 	return (dhp->dh_arch->da_max_instrlen(dhp));
276 }
277 
278 static int
279 dis_generic_instrlen(dis_handle_t *dhp, uint64_t pc)
280 {
281 	if (dis_disassemble(dhp, pc, NULL, 0) != 0)
282 		return (-1);
283 
284 	return (dhp->dh_addr - pc);
285 }
286 
287 int
288 dis_instrlen(dis_handle_t *dhp, uint64_t pc)
289 {
290 	if (dhp->dh_arch->da_instrlen == NULL)
291 		return (dis_generic_instrlen(dhp, pc));
292 
293 	return (dhp->dh_arch->da_instrlen(dhp, pc));
294 }
295 
296 int
297 dis_vsnprintf(char *restrict s, size_t n, const char *restrict format,
298     va_list args)
299 {
300 #ifdef DIS_STANDALONE
301 	return (mdb_iob_vsnprintf(s, n, format, args));
302 #else
303 	return (vsnprintf(s, n, format, args));
304 #endif
305 }
306 
307 int
308 dis_snprintf(char *restrict s, size_t n, const char *restrict format, ...)
309 {
310 	va_list args;
311 
312 	va_start(args, format);
313 	n = dis_vsnprintf(s, n, format, args);
314 	va_end(args);
315 
316 	return (n);
317 }
318