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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <mdb/mdb_disasm_impl.h> 30 #include <mdb/mdb_modapi.h> 31 #include <mdb/mdb_string.h> 32 #include <mdb/mdb_debug.h> 33 #include <mdb/mdb_err.h> 34 #include <mdb/mdb_nv.h> 35 #include <mdb/mdb.h> 36 37 int 38 mdb_dis_select(const char *name) 39 { 40 mdb_var_t *v = mdb_nv_lookup(&mdb.m_disasms, name); 41 42 if (v != NULL) { 43 mdb.m_disasm = mdb_nv_get_cookie(v); 44 return (0); 45 } 46 47 if (mdb.m_target == NULL) { 48 if (mdb.m_defdisasm != NULL) 49 strfree(mdb.m_defdisasm); 50 mdb.m_defdisasm = strdup(name); 51 return (0); 52 } 53 54 return (set_errno(EMDB_NODIS)); 55 } 56 57 mdb_disasm_t * 58 mdb_dis_create(mdb_dis_ctor_f *ctor) 59 { 60 mdb_disasm_t *dp = mdb_zalloc(sizeof (mdb_disasm_t), UM_SLEEP); 61 62 if ((dp->dis_module = mdb.m_lmod) == NULL) 63 dp->dis_module = &mdb.m_rmod; 64 65 if (ctor(dp) == 0) { 66 mdb_var_t *v = mdb_nv_lookup(&mdb.m_disasms, dp->dis_name); 67 68 if (v != NULL) { 69 dp->dis_ops->dis_destroy(dp); 70 mdb_free(dp, sizeof (mdb_disasm_t)); 71 (void) set_errno(EMDB_DISEXISTS); 72 return (NULL); 73 } 74 75 (void) mdb_nv_insert(&mdb.m_disasms, dp->dis_name, NULL, 76 (uintptr_t)dp, MDB_NV_RDONLY | MDB_NV_SILENT); 77 78 if (mdb.m_disasm == NULL) { 79 mdb.m_disasm = dp; 80 } else if (mdb.m_defdisasm != NULL && 81 strcmp(mdb.m_defdisasm, dp->dis_name) == 0) { 82 mdb.m_disasm = dp; 83 strfree(mdb.m_defdisasm); 84 mdb.m_defdisasm = NULL; 85 } 86 87 return (dp); 88 } 89 90 mdb_free(dp, sizeof (mdb_disasm_t)); 91 return (NULL); 92 } 93 94 void 95 mdb_dis_destroy(mdb_disasm_t *dp) 96 { 97 mdb_var_t *v = mdb_nv_lookup(&mdb.m_disasms, dp->dis_name); 98 99 ASSERT(v != NULL); 100 mdb_nv_remove(&mdb.m_disasms, v); 101 dp->dis_ops->dis_destroy(dp); 102 mdb_free(dp, sizeof (mdb_disasm_t)); 103 104 if (mdb.m_disasm == dp) 105 (void) mdb_dis_select("default"); 106 } 107 108 mdb_tgt_addr_t 109 mdb_dis_ins2str(mdb_disasm_t *dp, mdb_tgt_t *t, mdb_tgt_as_t as, 110 char *buf, size_t len, mdb_tgt_addr_t addr) 111 { 112 return (dp->dis_ops->dis_ins2str(dp, t, as, buf, len, addr)); 113 } 114 115 mdb_tgt_addr_t 116 mdb_dis_previns(mdb_disasm_t *dp, mdb_tgt_t *t, mdb_tgt_as_t as, 117 mdb_tgt_addr_t addr, uint_t n) 118 { 119 return (dp->dis_ops->dis_previns(dp, t, as, addr, n)); 120 } 121 122 mdb_tgt_addr_t 123 mdb_dis_nextins(mdb_disasm_t *dp, mdb_tgt_t *t, mdb_tgt_as_t as, 124 mdb_tgt_addr_t addr) 125 { 126 return (dp->dis_ops->dis_nextins(dp, t, as, addr)); 127 } 128 129 /*ARGSUSED*/ 130 int 131 cmd_dismode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 132 { 133 if ((flags & DCMD_ADDRSPEC) || argc > 1) 134 return (DCMD_USAGE); 135 136 if (argc != 0) { 137 const char *name; 138 139 if (argv->a_type == MDB_TYPE_STRING) 140 name = argv->a_un.a_str; 141 else 142 name = numtostr(argv->a_un.a_val, 10, NTOS_UNSIGNED); 143 144 if (mdb_dis_select(name) == -1) { 145 warn("failed to set disassembly mode"); 146 return (DCMD_ERR); 147 } 148 } 149 150 mdb_printf("disassembly mode is %s (%s)\n", 151 mdb.m_disasm->dis_name, mdb.m_disasm->dis_desc); 152 153 return (DCMD_OK); 154 } 155 156 /*ARGSUSED*/ 157 static int 158 print_dis(mdb_var_t *v, void *ignore) 159 { 160 mdb_disasm_t *dp = mdb_nv_get_cookie(v); 161 162 mdb_printf("%-24s - %s\n", dp->dis_name, dp->dis_desc); 163 return (0); 164 } 165 166 /*ARGSUSED*/ 167 int 168 cmd_disasms(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 169 { 170 if ((flags & DCMD_ADDRSPEC) || argc != 0) 171 return (DCMD_USAGE); 172 173 mdb_nv_sort_iter(&mdb.m_disasms, print_dis, NULL, UM_SLEEP | UM_GC); 174 return (DCMD_OK); 175 } 176 177 /*ARGSUSED*/ 178 static void 179 defdis_destroy(mdb_disasm_t *dp) 180 { 181 /* Nothing to do here */ 182 } 183 184 /*ARGSUSED*/ 185 static mdb_tgt_addr_t 186 defdis_ins2str(mdb_disasm_t *dp, mdb_tgt_t *t, mdb_tgt_as_t as, 187 char *buf, size_t len, mdb_tgt_addr_t addr) 188 { 189 return (addr); 190 } 191 192 /*ARGSUSED*/ 193 static mdb_tgt_addr_t 194 defdis_previns(mdb_disasm_t *dp, mdb_tgt_t *t, mdb_tgt_as_t as, 195 mdb_tgt_addr_t addr, uint_t n) 196 { 197 return (addr); 198 } 199 200 /*ARGSUSED*/ 201 static mdb_tgt_addr_t 202 defdis_nextins(mdb_disasm_t *dp, mdb_tgt_t *t, mdb_tgt_as_t as, 203 mdb_tgt_addr_t addr) 204 { 205 return (addr); 206 } 207 208 static const mdb_dis_ops_t defdis_ops = { 209 defdis_destroy, 210 defdis_ins2str, 211 defdis_previns, 212 defdis_nextins 213 }; 214 215 static int 216 defdis_create(mdb_disasm_t *dp) 217 { 218 dp->dis_name = "default"; 219 dp->dis_desc = "default no-op disassembler"; 220 dp->dis_ops = &defdis_ops; 221 222 return (0); 223 } 224 225 mdb_dis_ctor_f *const mdb_dis_builtins[] = { 226 #if defined(__amd64) 227 ia32_create, 228 amd64_create, 229 #elif defined(__i386) 230 ia32_create, 231 #endif 232 defdis_create, 233 NULL 234 }; 235