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