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 * 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 83 void * 84 dis_zalloc(size_t bytes) 85 { 86 return (calloc(1, bytes)); 87 } 88 89 /*ARGSUSED*/ 90 void 91 dis_free(void *ptr, size_t bytes) 92 { 93 free(ptr); 94 } 95 #endif 96 97 int 98 dis_seterrno(int error) 99 { 100 _dis_errno = error; 101 return (-1); 102 } 103 104 int 105 dis_errno(void) 106 { 107 return (_dis_errno); 108 } 109 110 const char * 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 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 /* 200 * On some instruction sets (e.g., x86), we have no choice except to 201 * disassemble everything from the start of the symbol, and stop when we 202 * have reached our instruction address. If we're not in the middle of a 203 * known symbol, then we return the same address to indicate failure. 204 */ 205 static uint64_t 206 dis_generic_previnstr(dis_handle_t *dhp, uint64_t pc, int n) 207 { 208 uint64_t *hist, addr, start; 209 int cur, nseen; 210 uint64_t res = pc; 211 212 if (n <= 0) 213 return (pc); 214 215 if (dhp->dh_lookup(dhp->dh_data, pc, NULL, 0, &start, NULL) != 0 || 216 start == pc) 217 return (res); 218 219 hist = dis_zalloc(sizeof (uint64_t) * n); 220 221 for (cur = 0, nseen = 0, addr = start; addr < pc; addr = dhp->dh_addr) { 222 hist[cur] = addr; 223 cur = (cur + 1) % n; 224 nseen++; 225 226 /* if we cannot make forward progress, give up */ 227 if (dis_disassemble(dhp, addr, NULL, 0) != 0) 228 goto done; 229 } 230 231 if (addr != pc) { 232 /* 233 * We scanned past %pc, but didn't find an instruction that 234 * started at %pc. This means that either the caller specified 235 * an invalid address, or we ran into something other than code 236 * during our scan. Virtually any combination of bytes can be 237 * construed as a valid Intel instruction, so any non-code bytes 238 * we encounter will have thrown off the scan. 239 */ 240 goto done; 241 } 242 243 res = hist[(cur + n - MIN(n, nseen)) % n]; 244 245 done: 246 dis_free(hist, sizeof (uint64_t) * n); 247 return (res); 248 } 249 250 /* 251 * Return the nth previous instruction's address. Return the same address 252 * to indicate failure. 253 */ 254 uint64_t 255 dis_previnstr(dis_handle_t *dhp, uint64_t pc, int n) 256 { 257 if (dhp->dh_arch->da_previnstr == NULL) 258 return (dis_generic_previnstr(dhp, pc, n)); 259 260 return (dhp->dh_arch->da_previnstr(dhp, pc, n)); 261 } 262 263 int 264 dis_min_instrlen(dis_handle_t *dhp) 265 { 266 return (dhp->dh_arch->da_min_instrlen(dhp)); 267 } 268 269 int 270 dis_max_instrlen(dis_handle_t *dhp) 271 { 272 return (dhp->dh_arch->da_max_instrlen(dhp)); 273 } 274 275 int 276 dis_instrlen(dis_handle_t *dhp, uint64_t pc) 277 { 278 return (dhp->dh_arch->da_instrlen(dhp, pc)); 279 } 280 281 int 282 dis_vsnprintf(char *restrict s, size_t n, const char *restrict format, 283 va_list args) 284 { 285 #ifdef DIS_STANDALONE 286 return (mdb_iob_vsnprintf(s, n, format, args)); 287 #else 288 return (vsnprintf(s, n, format, args)); 289 #endif 290 } 291 292 int 293 dis_snprintf(char *restrict s, size_t n, const char *restrict format, ...) 294 { 295 va_list args; 296 297 va_start(args, format); 298 n = dis_vsnprintf(s, n, format, args); 299 va_end(args); 300 301 return (n); 302 }