xref: /onnv-gate/usr/src/cmd/mdb/common/kmdb/kmdb_module.c (revision 1348:11df8410c452)
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