10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
70Sstevel@tonic-gate * with the License.
80Sstevel@tonic-gate *
90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate * See the License for the specific language governing permissions
120Sstevel@tonic-gate * and limitations under the License.
130Sstevel@tonic-gate *
140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate *
200Sstevel@tonic-gate * CDDL HEADER END
210Sstevel@tonic-gate */
220Sstevel@tonic-gate /*
23*1348Sjohnlev * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
280Sstevel@tonic-gate
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate * Routines for manipulating the kmdb-specific aspects of dmods.
310Sstevel@tonic-gate */
320Sstevel@tonic-gate
330Sstevel@tonic-gate #include <sys/param.h>
340Sstevel@tonic-gate
350Sstevel@tonic-gate #include <mdb/mdb_target_impl.h>
360Sstevel@tonic-gate #include <kmdb/kmdb_module.h>
370Sstevel@tonic-gate #include <mdb/mdb_debug.h>
380Sstevel@tonic-gate #include <mdb/mdb_err.h>
390Sstevel@tonic-gate #include <mdb/mdb.h>
400Sstevel@tonic-gate
410Sstevel@tonic-gate typedef struct kmod_symarg {
420Sstevel@tonic-gate mdb_tgt_sym_f *sym_cb; /* Caller's callback function */
430Sstevel@tonic-gate void *sym_data; /* Callback function argument */
440Sstevel@tonic-gate uint_t sym_type; /* Symbol type/binding filter */
450Sstevel@tonic-gate mdb_syminfo_t sym_info; /* Symbol id and table id */
460Sstevel@tonic-gate const char *sym_obj; /* Containing object */
470Sstevel@tonic-gate } kmod_symarg_t;
480Sstevel@tonic-gate
490Sstevel@tonic-gate void
kmdb_module_path_set(const char ** path,size_t pathlen)500Sstevel@tonic-gate kmdb_module_path_set(const char **path, size_t pathlen)
510Sstevel@tonic-gate {
520Sstevel@tonic-gate kmdb_wr_path_t *wr;
530Sstevel@tonic-gate
540Sstevel@tonic-gate wr = mdb_zalloc(sizeof (kmdb_wr_path_t), UM_SLEEP);
550Sstevel@tonic-gate wr->dpth_node.wn_task = WNTASK_DMOD_PATH_CHANGE;
560Sstevel@tonic-gate wr->dpth_path = mdb_path_dup(path, pathlen, &wr->dpth_pathlen);
570Sstevel@tonic-gate
580Sstevel@tonic-gate kmdb_wr_driver_notify(wr);
590Sstevel@tonic-gate }
600Sstevel@tonic-gate
610Sstevel@tonic-gate void
kmdb_module_path_ack(kmdb_wr_path_t * dpth)620Sstevel@tonic-gate kmdb_module_path_ack(kmdb_wr_path_t *dpth)
630Sstevel@tonic-gate {
640Sstevel@tonic-gate if (dpth->dpth_path != NULL)
650Sstevel@tonic-gate mdb_path_free(dpth->dpth_path, dpth->dpth_pathlen);
660Sstevel@tonic-gate mdb_free(dpth, sizeof (kmdb_wr_path_t));
670Sstevel@tonic-gate }
680Sstevel@tonic-gate
69*1348Sjohnlev static kmdb_modctl_t *
kmdb_module_lookup_loaded(const char * name)70*1348Sjohnlev kmdb_module_lookup_loaded(const char *name)
71*1348Sjohnlev {
72*1348Sjohnlev kmdb_modctl_t *kmc;
73*1348Sjohnlev mdb_var_t *v;
74*1348Sjohnlev
75*1348Sjohnlev if ((v = mdb_nv_lookup(&mdb.m_dmodctl, name)) == NULL)
76*1348Sjohnlev return (NULL);
77*1348Sjohnlev
78*1348Sjohnlev kmc = MDB_NV_COOKIE(v);
79*1348Sjohnlev if (kmc->kmc_state != KMDB_MC_STATE_LOADED)
80*1348Sjohnlev return (NULL);
81*1348Sjohnlev
82*1348Sjohnlev return (kmc);
83*1348Sjohnlev }
84*1348Sjohnlev
850Sstevel@tonic-gate /*
860Sstevel@tonic-gate * Given an address, try to match it up with a dmod symbol.
870Sstevel@tonic-gate */
880Sstevel@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)890Sstevel@tonic-gate kmdb_module_lookup_by_addr(uintptr_t addr, uint_t flags, char *buf,
900Sstevel@tonic-gate size_t nbytes, GElf_Sym *symp, mdb_syminfo_t *sip)
910Sstevel@tonic-gate {
920Sstevel@tonic-gate kmdb_modctl_t *sym_kmc = NULL;
930Sstevel@tonic-gate GElf_Sym sym;
940Sstevel@tonic-gate uint_t symid;
950Sstevel@tonic-gate mdb_var_t *v;
960Sstevel@tonic-gate const char *name;
970Sstevel@tonic-gate
980Sstevel@tonic-gate mdb_nv_rewind(&mdb.m_dmodctl);
990Sstevel@tonic-gate while ((v = mdb_nv_advance(&mdb.m_dmodctl)) != NULL) {
1000Sstevel@tonic-gate kmdb_modctl_t *kmc = MDB_NV_COOKIE(v);
1010Sstevel@tonic-gate
1020Sstevel@tonic-gate if (kmc->kmc_state != KMDB_MC_STATE_LOADED)
1030Sstevel@tonic-gate continue;
1040Sstevel@tonic-gate
1050Sstevel@tonic-gate if (mdb_gelf_symtab_lookup_by_addr(kmc->kmc_symtab, addr, flags,
1060Sstevel@tonic-gate buf, nbytes, symp, &sip->sym_id) != 0 ||
1070Sstevel@tonic-gate symp->st_value == 0)
1080Sstevel@tonic-gate continue;
1090Sstevel@tonic-gate
1100Sstevel@tonic-gate if (flags & MDB_TGT_SYM_EXACT) {
1110Sstevel@tonic-gate sym_kmc = kmc;
1120Sstevel@tonic-gate goto found;
1130Sstevel@tonic-gate }
1140Sstevel@tonic-gate
1150Sstevel@tonic-gate /*
1160Sstevel@tonic-gate * If this is the first match we've found, or if this symbol is
1170Sstevel@tonic-gate * closer to the specified address than the last one we found,
1180Sstevel@tonic-gate * use it.
1190Sstevel@tonic-gate */
1200Sstevel@tonic-gate if (sym_kmc == NULL || mdb_gelf_sym_closer(symp, &sym, addr)) {
1210Sstevel@tonic-gate sym_kmc = kmc;
1220Sstevel@tonic-gate sym = *symp;
1230Sstevel@tonic-gate symid = sip->sym_id;
1240Sstevel@tonic-gate }
1250Sstevel@tonic-gate }
1260Sstevel@tonic-gate
1270Sstevel@tonic-gate if (sym_kmc == NULL)
1280Sstevel@tonic-gate return (set_errno(EMDB_NOSYMADDR));
1290Sstevel@tonic-gate
1300Sstevel@tonic-gate *symp = sym;
1310Sstevel@tonic-gate sip->sym_id = symid;
1320Sstevel@tonic-gate
1330Sstevel@tonic-gate found:
1340Sstevel@tonic-gate /*
1350Sstevel@tonic-gate * Once we've found something, copy the final name into the caller's
1360Sstevel@tonic-gate * buffer, prefixed with a marker identifying this as a dmod symbol.
1370Sstevel@tonic-gate */
1380Sstevel@tonic-gate if (buf != NULL) {
1390Sstevel@tonic-gate name = mdb_gelf_sym_name(sym_kmc->kmc_symtab, symp);
1400Sstevel@tonic-gate
1410Sstevel@tonic-gate (void) mdb_snprintf(buf, nbytes, "DMOD`%s`%s",
1420Sstevel@tonic-gate sym_kmc->kmc_modname, name);
1430Sstevel@tonic-gate }
1440Sstevel@tonic-gate sip->sym_table = MDB_TGT_SYMTAB;
1450Sstevel@tonic-gate
1460Sstevel@tonic-gate return (0);
1470Sstevel@tonic-gate }
1480Sstevel@tonic-gate
1490Sstevel@tonic-gate /*
1500Sstevel@tonic-gate * Locate a given dmod symbol
1510Sstevel@tonic-gate */
1520Sstevel@tonic-gate int
kmdb_module_lookup_by_name(const char * obj,const char * name,GElf_Sym * symp,mdb_syminfo_t * sip)1530Sstevel@tonic-gate kmdb_module_lookup_by_name(const char *obj, const char *name, GElf_Sym *symp,
1540Sstevel@tonic-gate mdb_syminfo_t *sip)
1550Sstevel@tonic-gate {
1560Sstevel@tonic-gate kmdb_modctl_t *kmc;
1570Sstevel@tonic-gate
158*1348Sjohnlev if ((kmc = kmdb_module_lookup_loaded(obj)) == NULL)
1590Sstevel@tonic-gate return (set_errno(EMDB_NOSYMADDR));
1600Sstevel@tonic-gate
1610Sstevel@tonic-gate if (mdb_gelf_symtab_lookup_by_name(kmc->kmc_symtab, name,
1620Sstevel@tonic-gate symp, &sip->sym_id) == 0) {
1630Sstevel@tonic-gate sip->sym_table = MDB_TGT_SYMTAB;
1640Sstevel@tonic-gate return (0);
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate
1670Sstevel@tonic-gate return (set_errno(EMDB_NOSYM));
1680Sstevel@tonic-gate }
1690Sstevel@tonic-gate
170*1348Sjohnlev ctf_file_t *
kmdb_module_addr_to_ctf(uintptr_t addr)171*1348Sjohnlev kmdb_module_addr_to_ctf(uintptr_t addr)
172*1348Sjohnlev {
173*1348Sjohnlev mdb_var_t *v;
174*1348Sjohnlev
175*1348Sjohnlev mdb_nv_rewind(&mdb.m_dmodctl);
176*1348Sjohnlev while ((v = mdb_nv_advance(&mdb.m_dmodctl)) != NULL) {
177*1348Sjohnlev kmdb_modctl_t *kmc = MDB_NV_COOKIE(v);
178*1348Sjohnlev struct module *mp;
179*1348Sjohnlev
180*1348Sjohnlev if (kmc->kmc_state != KMDB_MC_STATE_LOADED)
181*1348Sjohnlev continue;
182*1348Sjohnlev
183*1348Sjohnlev mp = kmc->kmc_modctl->mod_mp;
184*1348Sjohnlev if (addr - (uintptr_t)mp->text < mp->text_size ||
185*1348Sjohnlev addr - (uintptr_t)mp->data < mp->data_size ||
186*1348Sjohnlev addr - mp->bss < mp->bss_size) {
187*1348Sjohnlev ctf_file_t *ctfp = kmc->kmc_mod->mod_ctfp;
188*1348Sjohnlev
189*1348Sjohnlev if (ctfp == NULL) {
190*1348Sjohnlev (void) set_errno(EMDB_NOCTF);
191*1348Sjohnlev return (NULL);
192*1348Sjohnlev }
193*1348Sjohnlev
194*1348Sjohnlev return (ctfp);
195*1348Sjohnlev }
196*1348Sjohnlev }
197*1348Sjohnlev
198*1348Sjohnlev (void) set_errno(EMDB_NOMAP);
199*1348Sjohnlev return (NULL);
200*1348Sjohnlev }
201*1348Sjohnlev
202*1348Sjohnlev ctf_file_t *
kmdb_module_name_to_ctf(const char * obj)203*1348Sjohnlev kmdb_module_name_to_ctf(const char *obj)
204*1348Sjohnlev {
205*1348Sjohnlev kmdb_modctl_t *kmc;
206*1348Sjohnlev ctf_file_t *ctfp;
207*1348Sjohnlev
208*1348Sjohnlev if ((kmc = kmdb_module_lookup_loaded(obj)) == NULL) {
209*1348Sjohnlev (void) set_errno(EMDB_NOOBJ);
210*1348Sjohnlev return (NULL);
211*1348Sjohnlev }
212*1348Sjohnlev
213*1348Sjohnlev if ((ctfp = kmc->kmc_mod->mod_ctfp) == NULL) {
214*1348Sjohnlev (void) set_errno(EMDB_NOCTF);
215*1348Sjohnlev return (NULL);
216*1348Sjohnlev }
217*1348Sjohnlev
218*1348Sjohnlev return (ctfp);
219*1348Sjohnlev }
220*1348Sjohnlev
2210Sstevel@tonic-gate static int
kmdb_module_symtab_func(void * data,const GElf_Sym * sym,const char * name,uint_t id)2220Sstevel@tonic-gate kmdb_module_symtab_func(void *data, const GElf_Sym *sym, const char *name,
2230Sstevel@tonic-gate uint_t id)
2240Sstevel@tonic-gate {
2250Sstevel@tonic-gate kmod_symarg_t *arg = data;
2260Sstevel@tonic-gate
2270Sstevel@tonic-gate if (mdb_tgt_sym_match(sym, arg->sym_type)) {
2280Sstevel@tonic-gate arg->sym_info.sym_id = id;
2290Sstevel@tonic-gate
2300Sstevel@tonic-gate return (arg->sym_cb(arg->sym_data, sym, name, &arg->sym_info,
2310Sstevel@tonic-gate arg->sym_obj));
2320Sstevel@tonic-gate }
2330Sstevel@tonic-gate
2340Sstevel@tonic-gate return (0);
2350Sstevel@tonic-gate }
2360Sstevel@tonic-gate
2370Sstevel@tonic-gate int
kmdb_module_symbol_iter(const char * obj,uint_t type,mdb_tgt_sym_f * cb,void * p)2380Sstevel@tonic-gate kmdb_module_symbol_iter(const char *obj, uint_t type, mdb_tgt_sym_f *cb,
2390Sstevel@tonic-gate void *p)
2400Sstevel@tonic-gate {
2410Sstevel@tonic-gate kmdb_modctl_t *kmc;
2420Sstevel@tonic-gate kmod_symarg_t arg;
2430Sstevel@tonic-gate mdb_var_t *v;
2440Sstevel@tonic-gate
2450Sstevel@tonic-gate if ((v = mdb_nv_lookup(&mdb.m_dmodctl, obj)) == NULL)
2460Sstevel@tonic-gate return (set_errno(EMDB_NOMOD));
2470Sstevel@tonic-gate
2480Sstevel@tonic-gate kmc = MDB_NV_COOKIE(v);
2490Sstevel@tonic-gate
2500Sstevel@tonic-gate if (kmc->kmc_state != KMDB_MC_STATE_LOADED)
2510Sstevel@tonic-gate return (set_errno(EMDB_NOMOD));
2520Sstevel@tonic-gate
2530Sstevel@tonic-gate arg.sym_cb = cb;
2540Sstevel@tonic-gate arg.sym_data = p;
2550Sstevel@tonic-gate arg.sym_type = type;
2560Sstevel@tonic-gate arg.sym_info.sym_table = kmc->kmc_symtab->gst_tabid;
2570Sstevel@tonic-gate arg.sym_obj = obj;
2580Sstevel@tonic-gate
2590Sstevel@tonic-gate mdb_gelf_symtab_iter(kmc->kmc_symtab, kmdb_module_symtab_func, &arg);
2600Sstevel@tonic-gate
2610Sstevel@tonic-gate return (0);
2620Sstevel@tonic-gate }
263