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 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); 240 n = dis_vsnprintf(s, n, format, args); 241 va_end(args); 242 243 return (n); 244 } 245