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 2006 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 /* 30 * Routines for manipulating the kmdb-specific aspects of dmods. 31 */ 32 33 #include <sys/param.h> 34 35 #include <mdb/mdb_target_impl.h> 36 #include <kmdb/kmdb_module.h> 37 #include <mdb/mdb_debug.h> 38 #include <mdb/mdb_err.h> 39 #include <mdb/mdb.h> 40 41 typedef struct kmod_symarg { 42 mdb_tgt_sym_f *sym_cb; /* Caller's callback function */ 43 void *sym_data; /* Callback function argument */ 44 uint_t sym_type; /* Symbol type/binding filter */ 45 mdb_syminfo_t sym_info; /* Symbol id and table id */ 46 const char *sym_obj; /* Containing object */ 47 } kmod_symarg_t; 48 49 void 50 kmdb_module_path_set(const char **path, size_t pathlen) 51 { 52 kmdb_wr_path_t *wr; 53 54 wr = mdb_zalloc(sizeof (kmdb_wr_path_t), UM_SLEEP); 55 wr->dpth_node.wn_task = WNTASK_DMOD_PATH_CHANGE; 56 wr->dpth_path = mdb_path_dup(path, pathlen, &wr->dpth_pathlen); 57 58 kmdb_wr_driver_notify(wr); 59 } 60 61 void 62 kmdb_module_path_ack(kmdb_wr_path_t *dpth) 63 { 64 if (dpth->dpth_path != NULL) 65 mdb_path_free(dpth->dpth_path, dpth->dpth_pathlen); 66 mdb_free(dpth, sizeof (kmdb_wr_path_t)); 67 } 68 69 static kmdb_modctl_t * 70 kmdb_module_lookup_loaded(const char *name) 71 { 72 kmdb_modctl_t *kmc; 73 mdb_var_t *v; 74 75 if ((v = mdb_nv_lookup(&mdb.m_dmodctl, name)) == NULL) 76 return (NULL); 77 78 kmc = MDB_NV_COOKIE(v); 79 if (kmc->kmc_state != KMDB_MC_STATE_LOADED) 80 return (NULL); 81 82 return (kmc); 83 } 84 85 /* 86 * Given an address, try to match it up with a dmod symbol. 87 */ 88 int 89 kmdb_module_lookup_by_addr(uintptr_t addr, uint_t flags, char *buf, 90 size_t nbytes, GElf_Sym *symp, mdb_syminfo_t *sip) 91 { 92 kmdb_modctl_t *sym_kmc = NULL; 93 GElf_Sym sym; 94 uint_t symid; 95 mdb_var_t *v; 96 const char *name; 97 98 mdb_nv_rewind(&mdb.m_dmodctl); 99 while ((v = mdb_nv_advance(&mdb.m_dmodctl)) != NULL) { 100 kmdb_modctl_t *kmc = MDB_NV_COOKIE(v); 101 102 if (kmc->kmc_state != KMDB_MC_STATE_LOADED) 103 continue; 104 105 if (mdb_gelf_symtab_lookup_by_addr(kmc->kmc_symtab, addr, flags, 106 buf, nbytes, symp, &sip->sym_id) != 0 || 107 symp->st_value == 0) 108 continue; 109 110 if (flags & MDB_TGT_SYM_EXACT) { 111 sym_kmc = kmc; 112 goto found; 113 } 114 115 /* 116 * If this is the first match we've found, or if this symbol is 117 * closer to the specified address than the last one we found, 118 * use it. 119 */ 120 if (sym_kmc == NULL || mdb_gelf_sym_closer(symp, &sym, addr)) { 121 sym_kmc = kmc; 122 sym = *symp; 123 symid = sip->sym_id; 124 } 125 } 126 127 if (sym_kmc == NULL) 128 return (set_errno(EMDB_NOSYMADDR)); 129 130 *symp = sym; 131 sip->sym_id = symid; 132 133 found: 134 /* 135 * Once we've found something, copy the final name into the caller's 136 * buffer, prefixed with a marker identifying this as a dmod symbol. 137 */ 138 if (buf != NULL) { 139 name = mdb_gelf_sym_name(sym_kmc->kmc_symtab, symp); 140 141 (void) mdb_snprintf(buf, nbytes, "DMOD`%s`%s", 142 sym_kmc->kmc_modname, name); 143 } 144 sip->sym_table = MDB_TGT_SYMTAB; 145 146 return (0); 147 } 148 149 /* 150 * Locate a given dmod symbol 151 */ 152 int 153 kmdb_module_lookup_by_name(const char *obj, const char *name, GElf_Sym *symp, 154 mdb_syminfo_t *sip) 155 { 156 kmdb_modctl_t *kmc; 157 158 if ((kmc = kmdb_module_lookup_loaded(obj)) == NULL) 159 return (set_errno(EMDB_NOSYMADDR)); 160 161 if (mdb_gelf_symtab_lookup_by_name(kmc->kmc_symtab, name, 162 symp, &sip->sym_id) == 0) { 163 sip->sym_table = MDB_TGT_SYMTAB; 164 return (0); 165 } 166 167 return (set_errno(EMDB_NOSYM)); 168 } 169 170 ctf_file_t * 171 kmdb_module_addr_to_ctf(uintptr_t addr) 172 { 173 mdb_var_t *v; 174 175 mdb_nv_rewind(&mdb.m_dmodctl); 176 while ((v = mdb_nv_advance(&mdb.m_dmodctl)) != NULL) { 177 kmdb_modctl_t *kmc = MDB_NV_COOKIE(v); 178 struct module *mp; 179 180 if (kmc->kmc_state != KMDB_MC_STATE_LOADED) 181 continue; 182 183 mp = kmc->kmc_modctl->mod_mp; 184 if (addr - (uintptr_t)mp->text < mp->text_size || 185 addr - (uintptr_t)mp->data < mp->data_size || 186 addr - mp->bss < mp->bss_size) { 187 ctf_file_t *ctfp = kmc->kmc_mod->mod_ctfp; 188 189 if (ctfp == NULL) { 190 (void) set_errno(EMDB_NOCTF); 191 return (NULL); 192 } 193 194 return (ctfp); 195 } 196 } 197 198 (void) set_errno(EMDB_NOMAP); 199 return (NULL); 200 } 201 202 ctf_file_t * 203 kmdb_module_name_to_ctf(const char *obj) 204 { 205 kmdb_modctl_t *kmc; 206 ctf_file_t *ctfp; 207 208 if ((kmc = kmdb_module_lookup_loaded(obj)) == NULL) { 209 (void) set_errno(EMDB_NOOBJ); 210 return (NULL); 211 } 212 213 if ((ctfp = kmc->kmc_mod->mod_ctfp) == NULL) { 214 (void) set_errno(EMDB_NOCTF); 215 return (NULL); 216 } 217 218 return (ctfp); 219 } 220 221 static int 222 kmdb_module_symtab_func(void *data, const GElf_Sym *sym, const char *name, 223 uint_t id) 224 { 225 kmod_symarg_t *arg = data; 226 227 if (mdb_tgt_sym_match(sym, arg->sym_type)) { 228 arg->sym_info.sym_id = id; 229 230 return (arg->sym_cb(arg->sym_data, sym, name, &arg->sym_info, 231 arg->sym_obj)); 232 } 233 234 return (0); 235 } 236 237 int 238 kmdb_module_symbol_iter(const char *obj, uint_t type, mdb_tgt_sym_f *cb, 239 void *p) 240 { 241 kmdb_modctl_t *kmc; 242 kmod_symarg_t arg; 243 mdb_var_t *v; 244 245 if ((v = mdb_nv_lookup(&mdb.m_dmodctl, obj)) == NULL) 246 return (set_errno(EMDB_NOMOD)); 247 248 kmc = MDB_NV_COOKIE(v); 249 250 if (kmc->kmc_state != KMDB_MC_STATE_LOADED) 251 return (set_errno(EMDB_NOMOD)); 252 253 arg.sym_cb = cb; 254 arg.sym_data = p; 255 arg.sym_type = type; 256 arg.sym_info.sym_table = kmc->kmc_symtab->gst_tabid; 257 arg.sym_obj = obj; 258 259 mdb_gelf_symtab_iter(kmc->kmc_symtab, kmdb_module_symtab_func, &arg); 260 261 return (0); 262 } 263