17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate * with the License.
87c478bd9Sstevel@tonic-gate *
97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate * and limitations under the License.
137c478bd9Sstevel@tonic-gate *
147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate *
207c478bd9Sstevel@tonic-gate * CDDL HEADER END
217c478bd9Sstevel@tonic-gate */
227c478bd9Sstevel@tonic-gate /*
23*5ae68c69Sjohnlev * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate * Routines for manipulating the kmdb-specific aspects of dmods.
317c478bd9Sstevel@tonic-gate */
327c478bd9Sstevel@tonic-gate
337c478bd9Sstevel@tonic-gate #include <sys/param.h>
347c478bd9Sstevel@tonic-gate
357c478bd9Sstevel@tonic-gate #include <mdb/mdb_target_impl.h>
367c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_module.h>
377c478bd9Sstevel@tonic-gate #include <mdb/mdb_debug.h>
387c478bd9Sstevel@tonic-gate #include <mdb/mdb_err.h>
397c478bd9Sstevel@tonic-gate #include <mdb/mdb.h>
407c478bd9Sstevel@tonic-gate
417c478bd9Sstevel@tonic-gate typedef struct kmod_symarg {
427c478bd9Sstevel@tonic-gate mdb_tgt_sym_f *sym_cb; /* Caller's callback function */
437c478bd9Sstevel@tonic-gate void *sym_data; /* Callback function argument */
447c478bd9Sstevel@tonic-gate uint_t sym_type; /* Symbol type/binding filter */
457c478bd9Sstevel@tonic-gate mdb_syminfo_t sym_info; /* Symbol id and table id */
467c478bd9Sstevel@tonic-gate const char *sym_obj; /* Containing object */
477c478bd9Sstevel@tonic-gate } kmod_symarg_t;
487c478bd9Sstevel@tonic-gate
497c478bd9Sstevel@tonic-gate void
kmdb_module_path_set(const char ** path,size_t pathlen)507c478bd9Sstevel@tonic-gate kmdb_module_path_set(const char **path, size_t pathlen)
517c478bd9Sstevel@tonic-gate {
527c478bd9Sstevel@tonic-gate kmdb_wr_path_t *wr;
537c478bd9Sstevel@tonic-gate
547c478bd9Sstevel@tonic-gate wr = mdb_zalloc(sizeof (kmdb_wr_path_t), UM_SLEEP);
557c478bd9Sstevel@tonic-gate wr->dpth_node.wn_task = WNTASK_DMOD_PATH_CHANGE;
567c478bd9Sstevel@tonic-gate wr->dpth_path = mdb_path_dup(path, pathlen, &wr->dpth_pathlen);
577c478bd9Sstevel@tonic-gate
587c478bd9Sstevel@tonic-gate kmdb_wr_driver_notify(wr);
597c478bd9Sstevel@tonic-gate }
607c478bd9Sstevel@tonic-gate
617c478bd9Sstevel@tonic-gate void
kmdb_module_path_ack(kmdb_wr_path_t * dpth)627c478bd9Sstevel@tonic-gate kmdb_module_path_ack(kmdb_wr_path_t *dpth)
637c478bd9Sstevel@tonic-gate {
647c478bd9Sstevel@tonic-gate if (dpth->dpth_path != NULL)
657c478bd9Sstevel@tonic-gate mdb_path_free(dpth->dpth_path, dpth->dpth_pathlen);
667c478bd9Sstevel@tonic-gate mdb_free(dpth, sizeof (kmdb_wr_path_t));
677c478bd9Sstevel@tonic-gate }
687c478bd9Sstevel@tonic-gate
69*5ae68c69Sjohnlev static kmdb_modctl_t *
kmdb_module_lookup_loaded(const char * name)70*5ae68c69Sjohnlev kmdb_module_lookup_loaded(const char *name)
71*5ae68c69Sjohnlev {
72*5ae68c69Sjohnlev kmdb_modctl_t *kmc;
73*5ae68c69Sjohnlev mdb_var_t *v;
74*5ae68c69Sjohnlev
75*5ae68c69Sjohnlev if ((v = mdb_nv_lookup(&mdb.m_dmodctl, name)) == NULL)
76*5ae68c69Sjohnlev return (NULL);
77*5ae68c69Sjohnlev
78*5ae68c69Sjohnlev kmc = MDB_NV_COOKIE(v);
79*5ae68c69Sjohnlev if (kmc->kmc_state != KMDB_MC_STATE_LOADED)
80*5ae68c69Sjohnlev return (NULL);
81*5ae68c69Sjohnlev
82*5ae68c69Sjohnlev return (kmc);
83*5ae68c69Sjohnlev }
84*5ae68c69Sjohnlev
857c478bd9Sstevel@tonic-gate /*
867c478bd9Sstevel@tonic-gate * Given an address, try to match it up with a dmod symbol.
877c478bd9Sstevel@tonic-gate */
887c478bd9Sstevel@tonic-gate int
kmdb_module_lookup_by_addr(uintptr_t addr,uint_t flags,char * buf,size_t nbytes,GElf_Sym * symp,mdb_syminfo_t * sip)897c478bd9Sstevel@tonic-gate kmdb_module_lookup_by_addr(uintptr_t addr, uint_t flags, char *buf,
907c478bd9Sstevel@tonic-gate size_t nbytes, GElf_Sym *symp, mdb_syminfo_t *sip)
917c478bd9Sstevel@tonic-gate {
927c478bd9Sstevel@tonic-gate kmdb_modctl_t *sym_kmc = NULL;
937c478bd9Sstevel@tonic-gate GElf_Sym sym;
947c478bd9Sstevel@tonic-gate uint_t symid;
957c478bd9Sstevel@tonic-gate mdb_var_t *v;
967c478bd9Sstevel@tonic-gate const char *name;
977c478bd9Sstevel@tonic-gate
987c478bd9Sstevel@tonic-gate mdb_nv_rewind(&mdb.m_dmodctl);
997c478bd9Sstevel@tonic-gate while ((v = mdb_nv_advance(&mdb.m_dmodctl)) != NULL) {
1007c478bd9Sstevel@tonic-gate kmdb_modctl_t *kmc = MDB_NV_COOKIE(v);
1017c478bd9Sstevel@tonic-gate
1027c478bd9Sstevel@tonic-gate if (kmc->kmc_state != KMDB_MC_STATE_LOADED)
1037c478bd9Sstevel@tonic-gate continue;
1047c478bd9Sstevel@tonic-gate
1057c478bd9Sstevel@tonic-gate if (mdb_gelf_symtab_lookup_by_addr(kmc->kmc_symtab, addr, flags,
1067c478bd9Sstevel@tonic-gate buf, nbytes, symp, &sip->sym_id) != 0 ||
1077c478bd9Sstevel@tonic-gate symp->st_value == 0)
1087c478bd9Sstevel@tonic-gate continue;
1097c478bd9Sstevel@tonic-gate
1107c478bd9Sstevel@tonic-gate if (flags & MDB_TGT_SYM_EXACT) {
1117c478bd9Sstevel@tonic-gate sym_kmc = kmc;
1127c478bd9Sstevel@tonic-gate goto found;
1137c478bd9Sstevel@tonic-gate }
1147c478bd9Sstevel@tonic-gate
1157c478bd9Sstevel@tonic-gate /*
1167c478bd9Sstevel@tonic-gate * If this is the first match we've found, or if this symbol is
1177c478bd9Sstevel@tonic-gate * closer to the specified address than the last one we found,
1187c478bd9Sstevel@tonic-gate * use it.
1197c478bd9Sstevel@tonic-gate */
1207c478bd9Sstevel@tonic-gate if (sym_kmc == NULL || mdb_gelf_sym_closer(symp, &sym, addr)) {
1217c478bd9Sstevel@tonic-gate sym_kmc = kmc;
1227c478bd9Sstevel@tonic-gate sym = *symp;
1237c478bd9Sstevel@tonic-gate symid = sip->sym_id;
1247c478bd9Sstevel@tonic-gate }
1257c478bd9Sstevel@tonic-gate }
1267c478bd9Sstevel@tonic-gate
1277c478bd9Sstevel@tonic-gate if (sym_kmc == NULL)
1287c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOSYMADDR));
1297c478bd9Sstevel@tonic-gate
1307c478bd9Sstevel@tonic-gate *symp = sym;
1317c478bd9Sstevel@tonic-gate sip->sym_id = symid;
1327c478bd9Sstevel@tonic-gate
1337c478bd9Sstevel@tonic-gate found:
1347c478bd9Sstevel@tonic-gate /*
1357c478bd9Sstevel@tonic-gate * Once we've found something, copy the final name into the caller's
1367c478bd9Sstevel@tonic-gate * buffer, prefixed with a marker identifying this as a dmod symbol.
1377c478bd9Sstevel@tonic-gate */
1387c478bd9Sstevel@tonic-gate if (buf != NULL) {
1397c478bd9Sstevel@tonic-gate name = mdb_gelf_sym_name(sym_kmc->kmc_symtab, symp);
1407c478bd9Sstevel@tonic-gate
1417c478bd9Sstevel@tonic-gate (void) mdb_snprintf(buf, nbytes, "DMOD`%s`%s",
1427c478bd9Sstevel@tonic-gate sym_kmc->kmc_modname, name);
1437c478bd9Sstevel@tonic-gate }
1447c478bd9Sstevel@tonic-gate sip->sym_table = MDB_TGT_SYMTAB;
1457c478bd9Sstevel@tonic-gate
1467c478bd9Sstevel@tonic-gate return (0);
1477c478bd9Sstevel@tonic-gate }
1487c478bd9Sstevel@tonic-gate
1497c478bd9Sstevel@tonic-gate /*
1507c478bd9Sstevel@tonic-gate * Locate a given dmod symbol
1517c478bd9Sstevel@tonic-gate */
1527c478bd9Sstevel@tonic-gate int
kmdb_module_lookup_by_name(const char * obj,const char * name,GElf_Sym * symp,mdb_syminfo_t * sip)1537c478bd9Sstevel@tonic-gate kmdb_module_lookup_by_name(const char *obj, const char *name, GElf_Sym *symp,
1547c478bd9Sstevel@tonic-gate mdb_syminfo_t *sip)
1557c478bd9Sstevel@tonic-gate {
1567c478bd9Sstevel@tonic-gate kmdb_modctl_t *kmc;
1577c478bd9Sstevel@tonic-gate
158*5ae68c69Sjohnlev if ((kmc = kmdb_module_lookup_loaded(obj)) == NULL)
1597c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOSYMADDR));
1607c478bd9Sstevel@tonic-gate
1617c478bd9Sstevel@tonic-gate if (mdb_gelf_symtab_lookup_by_name(kmc->kmc_symtab, name,
1627c478bd9Sstevel@tonic-gate symp, &sip->sym_id) == 0) {
1637c478bd9Sstevel@tonic-gate sip->sym_table = MDB_TGT_SYMTAB;
1647c478bd9Sstevel@tonic-gate return (0);
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOSYM));
1687c478bd9Sstevel@tonic-gate }
1697c478bd9Sstevel@tonic-gate
170*5ae68c69Sjohnlev ctf_file_t *
kmdb_module_addr_to_ctf(uintptr_t addr)171*5ae68c69Sjohnlev kmdb_module_addr_to_ctf(uintptr_t addr)
172*5ae68c69Sjohnlev {
173*5ae68c69Sjohnlev mdb_var_t *v;
174*5ae68c69Sjohnlev
175*5ae68c69Sjohnlev mdb_nv_rewind(&mdb.m_dmodctl);
176*5ae68c69Sjohnlev while ((v = mdb_nv_advance(&mdb.m_dmodctl)) != NULL) {
177*5ae68c69Sjohnlev kmdb_modctl_t *kmc = MDB_NV_COOKIE(v);
178*5ae68c69Sjohnlev struct module *mp;
179*5ae68c69Sjohnlev
180*5ae68c69Sjohnlev if (kmc->kmc_state != KMDB_MC_STATE_LOADED)
181*5ae68c69Sjohnlev continue;
182*5ae68c69Sjohnlev
183*5ae68c69Sjohnlev mp = kmc->kmc_modctl->mod_mp;
184*5ae68c69Sjohnlev if (addr - (uintptr_t)mp->text < mp->text_size ||
185*5ae68c69Sjohnlev addr - (uintptr_t)mp->data < mp->data_size ||
186*5ae68c69Sjohnlev addr - mp->bss < mp->bss_size) {
187*5ae68c69Sjohnlev ctf_file_t *ctfp = kmc->kmc_mod->mod_ctfp;
188*5ae68c69Sjohnlev
189*5ae68c69Sjohnlev if (ctfp == NULL) {
190*5ae68c69Sjohnlev (void) set_errno(EMDB_NOCTF);
191*5ae68c69Sjohnlev return (NULL);
192*5ae68c69Sjohnlev }
193*5ae68c69Sjohnlev
194*5ae68c69Sjohnlev return (ctfp);
195*5ae68c69Sjohnlev }
196*5ae68c69Sjohnlev }
197*5ae68c69Sjohnlev
198*5ae68c69Sjohnlev (void) set_errno(EMDB_NOMAP);
199*5ae68c69Sjohnlev return (NULL);
200*5ae68c69Sjohnlev }
201*5ae68c69Sjohnlev
202*5ae68c69Sjohnlev ctf_file_t *
kmdb_module_name_to_ctf(const char * obj)203*5ae68c69Sjohnlev kmdb_module_name_to_ctf(const char *obj)
204*5ae68c69Sjohnlev {
205*5ae68c69Sjohnlev kmdb_modctl_t *kmc;
206*5ae68c69Sjohnlev ctf_file_t *ctfp;
207*5ae68c69Sjohnlev
208*5ae68c69Sjohnlev if ((kmc = kmdb_module_lookup_loaded(obj)) == NULL) {
209*5ae68c69Sjohnlev (void) set_errno(EMDB_NOOBJ);
210*5ae68c69Sjohnlev return (NULL);
211*5ae68c69Sjohnlev }
212*5ae68c69Sjohnlev
213*5ae68c69Sjohnlev if ((ctfp = kmc->kmc_mod->mod_ctfp) == NULL) {
214*5ae68c69Sjohnlev (void) set_errno(EMDB_NOCTF);
215*5ae68c69Sjohnlev return (NULL);
216*5ae68c69Sjohnlev }
217*5ae68c69Sjohnlev
218*5ae68c69Sjohnlev return (ctfp);
219*5ae68c69Sjohnlev }
220*5ae68c69Sjohnlev
2217c478bd9Sstevel@tonic-gate static int
kmdb_module_symtab_func(void * data,const GElf_Sym * sym,const char * name,uint_t id)2227c478bd9Sstevel@tonic-gate kmdb_module_symtab_func(void *data, const GElf_Sym *sym, const char *name,
2237c478bd9Sstevel@tonic-gate uint_t id)
2247c478bd9Sstevel@tonic-gate {
2257c478bd9Sstevel@tonic-gate kmod_symarg_t *arg = data;
2267c478bd9Sstevel@tonic-gate
2277c478bd9Sstevel@tonic-gate if (mdb_tgt_sym_match(sym, arg->sym_type)) {
2287c478bd9Sstevel@tonic-gate arg->sym_info.sym_id = id;
2297c478bd9Sstevel@tonic-gate
2307c478bd9Sstevel@tonic-gate return (arg->sym_cb(arg->sym_data, sym, name, &arg->sym_info,
2317c478bd9Sstevel@tonic-gate arg->sym_obj));
2327c478bd9Sstevel@tonic-gate }
2337c478bd9Sstevel@tonic-gate
2347c478bd9Sstevel@tonic-gate return (0);
2357c478bd9Sstevel@tonic-gate }
2367c478bd9Sstevel@tonic-gate
2377c478bd9Sstevel@tonic-gate int
kmdb_module_symbol_iter(const char * obj,uint_t type,mdb_tgt_sym_f * cb,void * p)2387c478bd9Sstevel@tonic-gate kmdb_module_symbol_iter(const char *obj, uint_t type, mdb_tgt_sym_f *cb,
2397c478bd9Sstevel@tonic-gate void *p)
2407c478bd9Sstevel@tonic-gate {
2417c478bd9Sstevel@tonic-gate kmdb_modctl_t *kmc;
2427c478bd9Sstevel@tonic-gate kmod_symarg_t arg;
2437c478bd9Sstevel@tonic-gate mdb_var_t *v;
2447c478bd9Sstevel@tonic-gate
2457c478bd9Sstevel@tonic-gate if ((v = mdb_nv_lookup(&mdb.m_dmodctl, obj)) == NULL)
2467c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOMOD));
2477c478bd9Sstevel@tonic-gate
2487c478bd9Sstevel@tonic-gate kmc = MDB_NV_COOKIE(v);
2497c478bd9Sstevel@tonic-gate
2507c478bd9Sstevel@tonic-gate if (kmc->kmc_state != KMDB_MC_STATE_LOADED)
2517c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOMOD));
2527c478bd9Sstevel@tonic-gate
2537c478bd9Sstevel@tonic-gate arg.sym_cb = cb;
2547c478bd9Sstevel@tonic-gate arg.sym_data = p;
2557c478bd9Sstevel@tonic-gate arg.sym_type = type;
2567c478bd9Sstevel@tonic-gate arg.sym_info.sym_table = kmc->kmc_symtab->gst_tabid;
2577c478bd9Sstevel@tonic-gate arg.sym_obj = obj;
2587c478bd9Sstevel@tonic-gate
2597c478bd9Sstevel@tonic-gate mdb_gelf_symtab_iter(kmc->kmc_symtab, kmdb_module_symtab_func, &arg);
2607c478bd9Sstevel@tonic-gate
2617c478bd9Sstevel@tonic-gate return (0);
2627c478bd9Sstevel@tonic-gate }
263