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
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 dhp->dh_arch->da_handle_detach(dhp);
147 dis_free(dhp, sizeof (dis_handle_t));
148 }
149
150 dis_handle_t *
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
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
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
206 dis_min_instrlen(dis_handle_t *dhp)
207 {
208 return (dhp->dh_arch->da_min_instrlen(dhp));
209 }
210
211 int
212 dis_max_instrlen(dis_handle_t *dhp)
213 {
214 return (dhp->dh_arch->da_max_instrlen(dhp));
215 }
216
217 int
218 dis_instrlen(dis_handle_t *dhp, uint64_t pc)
219 {
220 return (dhp->dh_arch->da_instrlen(dhp, pc));
221 }
222
223 int
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
235 dis_snprintf(char *restrict s, size_t n, const char *restrict format, ...)
236 {
237 va_list args;
238
239 va_start(args, format);
|
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 #if !defined(DIS_STANDALONE) || defined(__s390) || defined(__s390x)
56 extern dis_arch_t dis_arch_s390;
57 #endif
58
59 static dis_arch_t *dis_archs[] = {
60 #if !defined(DIS_STANDALONE) || defined(__i386) || defined(__amd64)
61 &dis_arch_i386,
62 #endif
63 #if !defined(DIS_STANDALONE) || defined(__sparc)
64 &dis_arch_sparc,
65 #endif
66 #if !defined(DIS_STANDALONE) || defined(__s390) || defined(__s390x)
67 &dis_arch_s390,
68 #endif
69 NULL
70 };
71
72 /*
73 * For the standalone library, we need to link against mdb's malloc/free.
74 * Otherwise, use the standard malloc/free.
75 */
76 #ifdef DIS_STANDALONE
77 void *
78 dis_zalloc(size_t bytes)
79 {
80 return (mdb_zalloc(bytes, UM_SLEEP));
81 }
82
83 void
84 dis_free(void *ptr, size_t bytes)
85 {
86 mdb_free(ptr, bytes);
87 }
88 #else
132 dis_set_data(dis_handle_t *dhp, void *data)
133 {
134 dhp->dh_data = data;
135 }
136
137 void
138 dis_flags_set(dis_handle_t *dhp, int f)
139 {
140 dhp->dh_flags |= f;
141 }
142
143 void
144 dis_flags_clear(dis_handle_t *dhp, int f)
145 {
146 dhp->dh_flags &= ~f;
147 }
148
149 void
150 dis_handle_destroy(dis_handle_t *dhp)
151 {
152 if (dhp->dh_arch->da_handle_detach != NULL)
153 dhp->dh_arch->da_handle_detach(dhp);
154
155 dis_free(dhp, sizeof (dis_handle_t));
156 }
157
158 dis_handle_t *
159 dis_handle_create(int flags, void *data, dis_lookup_f lookup_func,
160 dis_read_f read_func)
161 {
162 dis_handle_t *dhp;
163 dis_arch_t *arch = NULL;
164 int i;
165
166 /* Select an architecture based on flags */
167 for (i = 0; dis_archs[i] != NULL; i++) {
168 if (dis_archs[i]->da_supports_flags(flags)) {
169 arch = dis_archs[i];
170 break;
171 }
172 }
173 if (arch == NULL) {
174 (void) dis_seterrno(E_DIS_UNSUPARCH);
175 return (NULL);
176 }
177
178 if ((dhp = dis_zalloc(sizeof (dis_handle_t))) == NULL) {
179 (void) dis_seterrno(E_DIS_NOMEM);
180 return (NULL);
181 }
182 dhp->dh_arch = arch;
183 dhp->dh_lookup = lookup_func;
184 dhp->dh_read = read_func;
185 dhp->dh_flags = flags;
186 dhp->dh_data = data;
187
188 /*
189 * Allow the architecture-specific code to allocate
190 * its private data.
191 */
192 if (arch->da_handle_attach != NULL &&
193 arch->da_handle_attach(dhp) != 0) {
194 dis_free(dhp, sizeof (dis_handle_t));
195 /* dis errno already set */
196 return (NULL);
197 }
198
199 return (dhp);
200 }
201
202 int
203 dis_disassemble(dis_handle_t *dhp, uint64_t addr, char *buf, size_t buflen)
204 {
205 return (dhp->dh_arch->da_disassemble(dhp, addr, buf, buflen));
206 }
207
208 /*
209 * On some instruction sets (e.g., x86), we have no choice except to
210 * disassemble everything from the start of the symbol, and stop when we
211 * have reached our instruction address. If we're not in the middle of a
212 * known symbol, then we return the same address to indicate failure.
213 */
214 static uint64_t
215 dis_generic_previnstr(dis_handle_t *dhp, uint64_t pc, int n)
216 {
217 uint64_t *hist, addr, start;
218 int cur, nseen;
219 uint64_t res = pc;
220
221 if (n <= 0)
222 return (pc);
223
224 if (dhp->dh_lookup(dhp->dh_data, pc, NULL, 0, &start, NULL) != 0 ||
225 start == pc)
226 return (res);
227
228 hist = dis_zalloc(sizeof (uint64_t) * n);
229
230 for (cur = 0, nseen = 0, addr = start; addr < pc; addr = dhp->dh_addr) {
231 hist[cur] = addr;
232 cur = (cur + 1) % n;
233 nseen++;
234
235 /* if we cannot make forward progress, give up */
236 if (dis_disassemble(dhp, addr, NULL, 0) != 0)
237 goto done;
238 }
239
240 if (addr != pc) {
241 /*
242 * We scanned past %pc, but didn't find an instruction that
243 * started at %pc. This means that either the caller specified
244 * an invalid address, or we ran into something other than code
245 * during our scan. Virtually any combination of bytes can be
246 * construed as a valid Intel instruction, so any non-code bytes
247 * we encounter will have thrown off the scan.
248 */
249 goto done;
250 }
251
252 res = hist[(cur + n - MIN(n, nseen)) % n];
253
254 done:
255 dis_free(hist, sizeof (uint64_t) * n);
256 return (res);
257 }
258
259 /*
260 * Return the nth previous instruction's address. Return the same address
261 * to indicate failure.
262 */
263 uint64_t
264 dis_previnstr(dis_handle_t *dhp, uint64_t pc, int n)
265 {
266 if (dhp->dh_arch->da_previnstr == NULL)
267 return (dis_generic_previnstr(dhp, pc, n));
268
269 return (dhp->dh_arch->da_previnstr(dhp, pc, n));
270 }
271
272 int
273 dis_min_instrlen(dis_handle_t *dhp)
274 {
275 return (dhp->dh_arch->da_min_instrlen(dhp));
276 }
277
278 int
279 dis_max_instrlen(dis_handle_t *dhp)
280 {
281 return (dhp->dh_arch->da_max_instrlen(dhp));
282 }
283
284 static int
285 dis_generic_instrlen(dis_handle_t *dhp, uint64_t pc)
286 {
287 if (dis_disassemble(dhp, pc, NULL, 0) != 0)
288 return (-1);
289
290 return (dhp->dh_addr - pc);
291 }
292
293 int
294 dis_instrlen(dis_handle_t *dhp, uint64_t pc)
295 {
296 if (dhp->dh_arch->da_instrlen == NULL)
297 return (dis_generic_instrlen(dhp, pc));
298
299 return (dhp->dh_arch->da_instrlen(dhp, pc));
300 }
301
302 int
303 dis_vsnprintf(char *restrict s, size_t n, const char *restrict format,
304 va_list args)
305 {
306 #ifdef DIS_STANDALONE
307 return (mdb_iob_vsnprintf(s, n, format, args));
308 #else
309 return (vsnprintf(s, n, format, args));
310 #endif
311 }
312
313 int
314 dis_snprintf(char *restrict s, size_t n, const char *restrict format, ...)
315 {
316 va_list args;
317
318 va_start(args, format);
|