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 *
dis_zalloc(size_t bytes)72 dis_zalloc(size_t bytes)
73 {
74 return (mdb_zalloc(bytes, UM_SLEEP));
75 }
76
77 void
dis_free(void * ptr,size_t bytes)78 dis_free(void *ptr, size_t bytes)
79 {
80 mdb_free(ptr, bytes);
81 }
82 #else
83 void *
dis_zalloc(size_t bytes)84 dis_zalloc(size_t bytes)
85 {
86 return (calloc(1, bytes));
87 }
88
89 /*ARGSUSED*/
90 void
dis_free(void * ptr,size_t bytes)91 dis_free(void *ptr, size_t bytes)
92 {
93 free(ptr);
94 }
95 #endif
96
97 int
dis_seterrno(int error)98 dis_seterrno(int error)
99 {
100 _dis_errno = error;
101 return (-1);
102 }
103
104 int
dis_errno(void)105 dis_errno(void)
106 {
107 return (_dis_errno);
108 }
109
110 const char *
dis_strerror(int error)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
dis_set_data(dis_handle_t * dhp,void * data)126 dis_set_data(dis_handle_t *dhp, void *data)
127 {
128 dhp->dh_data = data;
129 }
130
131 void
dis_flags_set(dis_handle_t * dhp,int f)132 dis_flags_set(dis_handle_t *dhp, int f)
133 {
134 dhp->dh_flags |= f;
135 }
136
137 void
dis_flags_clear(dis_handle_t * dhp,int f)138 dis_flags_clear(dis_handle_t *dhp, int f)
139 {
140 dhp->dh_flags &= ~f;
141 }
142
143 void
dis_handle_destroy(dis_handle_t * dhp)144 dis_handle_destroy(dis_handle_t *dhp)
145 {
146 dhp->dh_arch->da_handle_detach(dhp);
147 dis_free(dhp, sizeof (dis_handle_t));
148 }
149
150 dis_handle_t *
dis_handle_create(int flags,void * data,dis_lookup_f lookup_func,dis_read_f read_func)151 dis_handle_create(int flags, void *data, dis_lookup_f lookup_func,
152 dis_read_f read_func)
153 {
154 dis_handle_t *dhp;
155 dis_arch_t *arch = NULL;
156 int i;
157
158 /* Select an architecture based on flags */
159 for (i = 0; dis_archs[i] != NULL; i++) {
160 if (dis_archs[i]->da_supports_flags(flags)) {
161 arch = dis_archs[i];
162 break;
163 }
164 }
165 if (arch == NULL) {
166 (void) dis_seterrno(E_DIS_UNSUPARCH);
167 return (NULL);
168 }
169
170 if ((dhp = dis_zalloc(sizeof (dis_handle_t))) == NULL) {
171 (void) dis_seterrno(E_DIS_NOMEM);
172 return (NULL);
173 }
174 dhp->dh_arch = arch;
175 dhp->dh_lookup = lookup_func;
176 dhp->dh_read = read_func;
177 dhp->dh_flags = flags;
178 dhp->dh_data = data;
179
180 /*
181 * Allow the architecture-specific code to allocate
182 * its private data.
183 */
184 if (arch->da_handle_attach(dhp) != 0) {
185 dis_free(dhp, sizeof (dis_handle_t));
186 /* dis errno already set */
187 return (NULL);
188 }
189
190 return (dhp);
191 }
192
193 int
dis_disassemble(dis_handle_t * dhp,uint64_t addr,char * buf,size_t buflen)194 dis_disassemble(dis_handle_t *dhp, uint64_t addr, char *buf, size_t buflen)
195 {
196 return (dhp->dh_arch->da_disassemble(dhp, addr, buf, buflen));
197 }
198
199 uint64_t
dis_previnstr(dis_handle_t * dhp,uint64_t pc,int n)200 dis_previnstr(dis_handle_t *dhp, uint64_t pc, int n)
201 {
202 return (dhp->dh_arch->da_previnstr(dhp, pc, n));
203 }
204
205 int
dis_min_instrlen(dis_handle_t * dhp)206 dis_min_instrlen(dis_handle_t *dhp)
207 {
208 return (dhp->dh_arch->da_min_instrlen(dhp));
209 }
210
211 int
dis_max_instrlen(dis_handle_t * dhp)212 dis_max_instrlen(dis_handle_t *dhp)
213 {
214 return (dhp->dh_arch->da_max_instrlen(dhp));
215 }
216
217 int
dis_instrlen(dis_handle_t * dhp,uint64_t pc)218 dis_instrlen(dis_handle_t *dhp, uint64_t pc)
219 {
220 return (dhp->dh_arch->da_instrlen(dhp, pc));
221 }
222
223 int
dis_vsnprintf(char * restrict s,size_t n,const char * restrict format,va_list args)224 dis_vsnprintf(char *restrict s, size_t n, const char *restrict format,
225 va_list args)
226 {
227 #ifdef DIS_STANDALONE
228 return (mdb_iob_vsnprintf(s, n, format, args));
229 #else
230 return (vsnprintf(s, n, format, args));
231 #endif
232 }
233
234 int
dis_snprintf(char * restrict s,size_t n,const char * restrict format,...)235 dis_snprintf(char *restrict s, size_t n, const char *restrict format, ...)
236 {
237 va_list args;
238
239 va_start(args, format);
240 n = dis_vsnprintf(s, n, format, args);
241 va_end(args);
242
243 return (n);
244 }
245