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 #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 89 void * 90 dis_zalloc(size_t bytes) 91 { 92 return (calloc(1, bytes)); 93 } 94 95 /*ARGSUSED*/ 96 void 97 dis_free(void *ptr, size_t bytes) 98 { 99 free(ptr); 100 } 101 #endif 102 103 int 104 dis_seterrno(int error) 105 { 106 _dis_errno = error; 107 return (-1); 108 } 109 110 int 111 dis_errno(void) 112 { 113 return (_dis_errno); 114 } 115 116 const char * 117 dis_strerror(int error) 118 { 119 switch (error) { 120 case E_DIS_NOMEM: 121 return ("out of memory"); 122 case E_DIS_INVALFLAG: 123 return ("invalid flags for this architecture"); 124 case E_DIS_UNSUPARCH: 125 return ("unsupported machine architecture"); 126 default: 127 return ("unknown error"); 128 } 129 } 130 131 void 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); 319 n = dis_vsnprintf(s, n, format, args); 320 va_end(args); 321 322 return (n); 323 } 324