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.
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.
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]
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.
29 #include <libdisasm.h>
32 #include <mdb/mdb_modapi.h>
34 #include <mdb/mdb_io.h>
39 #include "libdisasm_impl.h"
41 static int _dis_errno
;
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
49 #if !defined(DIS_STANDALONE) || defined(__i386) || defined(__amd64)
50 extern dis_arch_t dis_arch_i386
;
52 #if !defined(DIS_STANDALONE) || defined(__sparc)
53 extern dis_arch_t dis_arch_sparc
;
56 static dis_arch_t
*dis_archs
[] = {
57 #if !defined(DIS_STANDALONE) || defined(__i386) || defined(__amd64)
60 #if !defined(DIS_STANDALONE) || defined(__sparc)
67 * For the standalone library, we need to link against mdb's malloc/free.
68 * Otherwise, use the standard malloc/free.
72 dis_zalloc(size_t bytes
)
74 return (mdb_zalloc(bytes
, UM_SLEEP
));
78 dis_free(void *ptr
, size_t bytes
)
84 dis_zalloc(size_t bytes
)
86 return (calloc(1, bytes
));
91 dis_free(void *ptr
, size_t bytes
)
98 dis_seterrno(int error
)
111 dis_strerror(int error
)
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");
121 return ("unknown error");
126 dis_set_data(dis_handle_t
*dhp
, void *data
)
132 dis_flags_set(dis_handle_t
*dhp
, int f
)
138 dis_flags_clear(dis_handle_t
*dhp
, int f
)
144 dis_handle_destroy(dis_handle_t
*dhp
)
146 if (dhp
->dh_arch
->da_handle_detach
!= NULL
)
147 dhp
->dh_arch
->da_handle_detach(dhp
);
149 dis_free(dhp
, sizeof (dis_handle_t
));
153 dis_handle_create(int flags
, void *data
, dis_lookup_f lookup_func
,
154 dis_read_f read_func
)
157 dis_arch_t
*arch
= NULL
;
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
)) {
168 (void) dis_seterrno(E_DIS_UNSUPARCH
);
172 if ((dhp
= dis_zalloc(sizeof (dis_handle_t
))) == NULL
) {
173 (void) dis_seterrno(E_DIS_NOMEM
);
177 dhp
->dh_lookup
= lookup_func
;
178 dhp
->dh_read
= read_func
;
179 dhp
->dh_flags
= flags
;
183 * Allow the architecture-specific code to allocate
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 */
197 dis_disassemble(dis_handle_t
*dhp
, uint64_t addr
, char *buf
, size_t buflen
)
199 return (dhp
->dh_arch
->da_disassemble(dhp
, addr
, buf
, buflen
));
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.
209 dis_generic_previnstr(dis_handle_t
*dhp
, uint64_t pc
, int n
)
211 uint64_t *hist
, addr
, start
;
218 if (dhp
->dh_lookup(dhp
->dh_data
, pc
, NULL
, 0, &start
, NULL
) != 0 ||
222 hist
= dis_zalloc(sizeof (uint64_t) * n
);
224 for (cur
= 0, nseen
= 0, addr
= start
; addr
< pc
; addr
= dhp
->dh_addr
) {
229 /* if we cannot make forward progress, give up */
230 if (dis_disassemble(dhp
, addr
, NULL
, 0) != 0)
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.
246 res
= hist
[(cur
+ n
- MIN(n
, nseen
)) % n
];
249 dis_free(hist
, sizeof (uint64_t) * n
);
254 * Return the nth previous instruction's address. Return the same address
255 * to indicate failure.
258 dis_previnstr(dis_handle_t
*dhp
, uint64_t pc
, int n
)
260 if (dhp
->dh_arch
->da_previnstr
== NULL
)
261 return (dis_generic_previnstr(dhp
, pc
, n
));
263 return (dhp
->dh_arch
->da_previnstr(dhp
, pc
, n
));
267 dis_min_instrlen(dis_handle_t
*dhp
)
269 return (dhp
->dh_arch
->da_min_instrlen(dhp
));
273 dis_max_instrlen(dis_handle_t
*dhp
)
275 return (dhp
->dh_arch
->da_max_instrlen(dhp
));
279 dis_generic_instrlen(dis_handle_t
*dhp
, uint64_t pc
)
281 if (dis_disassemble(dhp
, pc
, NULL
, 0) != 0)
284 return (dhp
->dh_addr
- pc
);
288 dis_instrlen(dis_handle_t
*dhp
, uint64_t pc
)
290 if (dhp
->dh_arch
->da_instrlen
== NULL
)
291 return (dis_generic_instrlen(dhp
, pc
));
293 return (dhp
->dh_arch
->da_instrlen(dhp
, pc
));
297 dis_vsnprintf(char *restrict s
, size_t n
, const char *restrict format
,
300 #ifdef DIS_STANDALONE
301 return (mdb_iob_vsnprintf(s
, n
, format
, args
));
303 return (vsnprintf(s
, n
, format
, args
));
308 dis_snprintf(char *restrict s
, size_t n
, const char *restrict format
, ...)
312 va_start(args
, format
);
313 n
= dis_vsnprintf(s
, n
, format
, args
);