16583 Want ability to use libtermcap to filter over libcurses(3xcurses)
[illumos-gate.git] / usr / src / lib / libdisasm / common / libdisasm.c
blob7e5f545cc82948cf2abab3dd7470a6edb16a0927
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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 * Copyright 2018, Joyent, Inc.
30 #include <libdisasm.h>
31 #include <stdlib.h>
32 #ifdef DIS_STANDALONE
33 #include <mdb/mdb_modapi.h>
34 #define _MDB
35 #include <mdb/mdb_io.h>
36 #else
37 #include <stdio.h>
38 #endif
40 #include "libdisasm_impl.h"
42 static int _dis_errno;
45 * If we're building the standalone library, then we only want to
46 * include support for disassembly of the native architecture.
47 * The regular shared library should include support for all
48 * architectures.
50 #if !defined(DIS_STANDALONE) || defined(__i386) || defined(__amd64)
51 extern dis_arch_t dis_arch_i386;
52 #endif
53 #if !defined(DIS_STANDALONE) || defined(__sparc)
54 extern dis_arch_t dis_arch_sparc;
55 #endif
56 #if !defined(DIS_STANDALONE) || defined(__s390) || defined(__s390x)
57 extern dis_arch_t dis_arch_s390;
58 #endif
59 #if !defined(DIS_STANDALONE) || defined(__riscv)
60 extern dis_arch_t dis_arch_riscv;
61 #endif
63 static dis_arch_t *dis_archs[] = {
64 #if !defined(DIS_STANDALONE) || defined(__i386) || defined(__amd64)
65 &dis_arch_i386,
66 #endif
67 #if !defined(DIS_STANDALONE) || defined(__sparc)
68 &dis_arch_sparc,
69 #endif
70 #if !defined(DIS_STANDALONE) || defined(__s390) || defined(__s390x)
71 &dis_arch_s390,
72 #endif
73 #if !defined(DIS_STANDALONE) || defined(__riscv)
74 &dis_arch_riscv,
75 #endif
76 NULL
80 * For the standalone library, we need to link against mdb's malloc/free.
81 * Otherwise, use the standard malloc/free.
83 #ifdef DIS_STANDALONE
84 void *
85 dis_zalloc(size_t bytes)
87 return (mdb_zalloc(bytes, UM_SLEEP));
90 void
91 dis_free(void *ptr, size_t bytes)
93 mdb_free(ptr, bytes);
95 #else
96 void *
97 dis_zalloc(size_t bytes)
99 return (calloc(1, bytes));
102 /*ARGSUSED*/
103 void
104 dis_free(void *ptr, size_t bytes)
106 free(ptr);
108 #endif
111 dis_seterrno(int error)
113 _dis_errno = error;
114 return (-1);
118 dis_errno(void)
120 return (_dis_errno);
123 const char *
124 dis_strerror(int error)
126 switch (error) {
127 case E_DIS_NOMEM:
128 return ("out of memory");
129 case E_DIS_INVALFLAG:
130 return ("invalid flags for this architecture");
131 case E_DIS_UNSUPARCH:
132 return ("unsupported machine architecture");
133 default:
134 return ("unknown error");
138 void
139 dis_set_data(dis_handle_t *dhp, void *data)
141 dhp->dh_data = data;
144 void
145 dis_flags_set(dis_handle_t *dhp, int f)
147 dhp->dh_flags |= f;
150 void
151 dis_flags_clear(dis_handle_t *dhp, int f)
153 dhp->dh_flags &= ~f;
156 void
157 dis_handle_destroy(dis_handle_t *dhp)
159 if (dhp->dh_arch->da_handle_detach != NULL)
160 dhp->dh_arch->da_handle_detach(dhp);
162 dis_free(dhp, sizeof (dis_handle_t));
165 dis_handle_t *
166 dis_handle_create(int flags, void *data, dis_lookup_f lookup_func,
167 dis_read_f read_func)
169 dis_handle_t *dhp;
170 dis_arch_t *arch = NULL;
171 int i;
173 /* Select an architecture based on flags */
174 for (i = 0; dis_archs[i] != NULL; i++) {
175 if (dis_archs[i]->da_supports_flags(flags)) {
176 arch = dis_archs[i];
177 break;
180 if (arch == NULL) {
181 (void) dis_seterrno(E_DIS_UNSUPARCH);
182 return (NULL);
185 if ((dhp = dis_zalloc(sizeof (dis_handle_t))) == NULL) {
186 (void) dis_seterrno(E_DIS_NOMEM);
187 return (NULL);
189 dhp->dh_arch = arch;
190 dhp->dh_lookup = lookup_func;
191 dhp->dh_read = read_func;
192 dhp->dh_flags = flags;
193 dhp->dh_data = data;
196 * Allow the architecture-specific code to allocate
197 * its private data.
199 if (arch->da_handle_attach != NULL &&
200 arch->da_handle_attach(dhp) != 0) {
201 dis_free(dhp, sizeof (dis_handle_t));
202 /* dis errno already set */
203 return (NULL);
206 return (dhp);
210 dis_disassemble(dis_handle_t *dhp, uint64_t addr, char *buf, size_t buflen)
212 return (dhp->dh_arch->da_disassemble(dhp, addr, buf, buflen));
216 * On some instruction sets (e.g., x86), we have no choice except to
217 * disassemble everything from the start of the symbol, and stop when we
218 * have reached our instruction address. If we're not in the middle of a
219 * known symbol, then we return the same address to indicate failure.
221 static uint64_t
222 dis_generic_previnstr(dis_handle_t *dhp, uint64_t pc, int n)
224 uint64_t *hist, addr, start;
225 int cur, nseen;
226 uint64_t res = pc;
228 if (n <= 0)
229 return (pc);
231 if (dhp->dh_lookup(dhp->dh_data, pc, NULL, 0, &start, NULL) != 0 ||
232 start == pc)
233 return (res);
235 hist = dis_zalloc(sizeof (uint64_t) * n);
237 for (cur = 0, nseen = 0, addr = start; addr < pc; addr = dhp->dh_addr) {
238 hist[cur] = addr;
239 cur = (cur + 1) % n;
240 nseen++;
242 /* if we cannot make forward progress, give up */
243 if (dis_disassemble(dhp, addr, NULL, 0) != 0)
244 goto done;
247 if (addr != pc) {
249 * We scanned past %pc, but didn't find an instruction that
250 * started at %pc. This means that either the caller specified
251 * an invalid address, or we ran into something other than code
252 * during our scan. Virtually any combination of bytes can be
253 * construed as a valid Intel instruction, so any non-code bytes
254 * we encounter will have thrown off the scan.
256 goto done;
259 res = hist[(cur + n - MIN(n, nseen)) % n];
261 done:
262 dis_free(hist, sizeof (uint64_t) * n);
263 return (res);
267 * Return the nth previous instruction's address. Return the same address
268 * to indicate failure.
270 uint64_t
271 dis_previnstr(dis_handle_t *dhp, uint64_t pc, int n)
273 if (dhp->dh_arch->da_previnstr == NULL)
274 return (dis_generic_previnstr(dhp, pc, n));
276 return (dhp->dh_arch->da_previnstr(dhp, pc, n));
280 dis_min_instrlen(dis_handle_t *dhp)
282 return (dhp->dh_arch->da_min_instrlen(dhp));
286 dis_max_instrlen(dis_handle_t *dhp)
288 return (dhp->dh_arch->da_max_instrlen(dhp));
291 static int
292 dis_generic_instrlen(dis_handle_t *dhp, uint64_t pc)
294 if (dis_disassemble(dhp, pc, NULL, 0) != 0)
295 return (-1);
297 return (dhp->dh_addr - pc);
301 dis_instrlen(dis_handle_t *dhp, uint64_t pc)
303 if (dhp->dh_arch->da_instrlen == NULL)
304 return (dis_generic_instrlen(dhp, pc));
306 return (dhp->dh_arch->da_instrlen(dhp, pc));
310 dis_vsnprintf(char *restrict s, size_t n, const char *restrict format,
311 va_list args)
313 #ifdef DIS_STANDALONE
314 return (mdb_iob_vsnprintf(s, n, format, args));
315 #else
316 return (vsnprintf(s, n, format, args));
317 #endif
321 dis_snprintf(char *restrict s, size_t n, const char *restrict format, ...)
323 va_list args;
325 va_start(args, format);
326 n = dis_vsnprintf(s, n, format, args);
327 va_end(args);
329 return (n);