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  */
  27 
  28 #include <libdisasm.h>
  29 #include <stdlib.h>
  30 #ifdef DIS_STANDALONE
  31 #include <mdb/mdb_modapi.h>
  32 #endif
  33 
  34 #include "libdisasm_impl.h"
  35 
  36 static int _dis_errno;
  37 
  38 /*
  39  * If we're building the standalone library, then we only want to
  40  * include support for disassembly of the native architecture.
  41  * The regular shared library should include support for all
  42  * architectures.
  43  */
  44 #if !defined(DIS_STANDALONE) || defined(__i386) || defined(__amd64)
  45 extern dis_arch_t dis_arch_i386;
  46 #endif
  47 #if !defined(DIS_STANDALONE) || defined(__sparc)
  48 extern dis_arch_t dis_arch_sparc;
  49 #endif
  50 
  51 static dis_arch_t *dis_archs[] = {
  52 #if !defined(DIS_STANDALONE) || defined(__i386) || defined(__amd64)
  53         &dis_arch_i386,
  54 #endif
  55 #if !defined(DIS_STANDALONE) || defined(__sparc)
  56         &dis_arch_sparc,
  57 #endif
  58         NULL
  59 };
  60 
  61 /*
  62  * For the standalone library, we need to link against mdb's malloc/free.
  63  * Otherwise, use the standard malloc/free.
  64  */
  65 #ifdef DIS_STANDALONE
  66 void *
  67 dis_zalloc(size_t bytes)
  68 {
  69         return (mdb_zalloc(bytes, UM_SLEEP));
  70 }
  71 
  72 void
  73 dis_free(void *ptr, size_t bytes)
  74 {
  75         mdb_free(ptr, bytes);
  76 }
  77 #else
  78 void *
  79 dis_zalloc(size_t bytes)
  80 {
  81         return (calloc(1, bytes));
  82 }
  83 
  84 /*ARGSUSED*/
  85 void
  86 dis_free(void *ptr, size_t bytes)
  87 {
  88         free(ptr);
  89 }
  90 #endif
  91 
  92 int
  93 dis_seterrno(int error)
  94 {
  95         _dis_errno = error;
  96         return (-1);
  97 }
  98 
  99 int
 100 dis_errno(void)
 101 {
 102         return (_dis_errno);
 103 }
 104 
 105 const char *
 106 dis_strerror(int error)
 107 {
 108         switch (error) {
 109         case E_DIS_NOMEM:
 110                 return ("out of memory");
 111         case E_DIS_INVALFLAG:
 112                 return ("invalid flags for this architecture");
 113         case E_DIS_UNSUPARCH:
 114                 return ("unsupported machine architecture");
 115         default:
 116                 return ("unknown error");
 117         }
 118 }
 119 
 120 void
 121 dis_set_data(dis_handle_t *dhp, void *data)
 122 {
 123         dhp->dh_data = data;
 124 }
 125 
 126 void
 127 dis_flags_set(dis_handle_t *dhp, int f)
 128 {
 129         dhp->dh_flags |= f;
 130 }
 131 
 132 void
 133 dis_flags_clear(dis_handle_t *dhp, int f)
 134 {
 135         dhp->dh_flags &= ~f;
 136 }
 137 
 138 void
 139 dis_handle_destroy(dis_handle_t *dhp)
 140 {
 141         dhp->dh_arch->da_handle_detach(dhp);
 142         dis_free(dhp, sizeof (dis_handle_t));
 143 }
 144 
 145 dis_handle_t *
 146 dis_handle_create(int flags, void *data, dis_lookup_f lookup_func,
 147     dis_read_f read_func)
 148 {
 149         dis_handle_t *dhp;
 150         dis_arch_t *arch = NULL;
 151         int i;
 152 
 153         /* Select an architecture based on flags */
 154         for (i = 0; dis_archs[i] != NULL; i++) {
 155                 if (dis_archs[i]->da_supports_flags(flags)) {
 156                         arch = dis_archs[i];
 157                         break;
 158                 }
 159         }
 160         if (arch == NULL) {
 161                 (void) dis_seterrno(E_DIS_UNSUPARCH);
 162                 return (NULL);
 163         }
 164 
 165         if ((dhp = dis_zalloc(sizeof (dis_handle_t))) == NULL) {
 166                 (void) dis_seterrno(E_DIS_NOMEM);
 167                 return (NULL);
 168         }
 169         dhp->dh_arch = arch;
 170         dhp->dh_lookup = lookup_func;
 171         dhp->dh_read = read_func;
 172         dhp->dh_flags = flags;
 173         dhp->dh_data = data;
 174 
 175         /*
 176          * Allow the architecture-specific code to allocate
 177          * its private data.
 178          */
 179         if (arch->da_handle_attach(dhp) != 0) {
 180                 dis_free(dhp, sizeof (dis_handle_t));
 181                 /* dis errno already set */
 182                 return (NULL);
 183         }
 184 
 185         return (dhp);
 186 }
 187 
 188 int
 189 dis_disassemble(dis_handle_t *dhp, uint64_t addr, char *buf, size_t buflen)
 190 {
 191         return (dhp->dh_arch->da_disassemble(dhp, addr, buf, buflen));
 192 }
 193 
 194 uint64_t
 195 dis_previnstr(dis_handle_t *dhp, uint64_t pc, int n)
 196 {
 197         return (dhp->dh_arch->da_previnstr(dhp, pc, n));
 198 }
 199 
 200 int
 201 dis_min_instrlen(dis_handle_t *dhp)
 202 {
 203         return (dhp->dh_arch->da_min_instrlen(dhp));
 204 }
 205 
 206 int
 207 dis_max_instrlen(dis_handle_t *dhp)
 208 {
 209         return (dhp->dh_arch->da_max_instrlen(dhp));
 210 }