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 /*
287c478bd9Sstevel@tonic-gate  * Routines for manipulating the kmdb-specific aspects of dmods.
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <sys/param.h>
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include <mdb/mdb_target_impl.h>
347c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_module.h>
357c478bd9Sstevel@tonic-gate #include <mdb/mdb_debug.h>
367c478bd9Sstevel@tonic-gate #include <mdb/mdb_err.h>
377c478bd9Sstevel@tonic-gate #include <mdb/mdb.h>
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate typedef struct kmod_symarg {
407c478bd9Sstevel@tonic-gate 	mdb_tgt_sym_f *sym_cb;		/* Caller's callback function */
417c478bd9Sstevel@tonic-gate 	void *sym_data;			/* Callback function argument */
427c478bd9Sstevel@tonic-gate 	uint_t sym_type;		/* Symbol type/binding filter */
437c478bd9Sstevel@tonic-gate 	mdb_syminfo_t sym_info;		/* Symbol id and table id */
447c478bd9Sstevel@tonic-gate 	const char *sym_obj;		/* Containing object */
457c478bd9Sstevel@tonic-gate } kmod_symarg_t;
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate void
kmdb_module_path_set(const char ** path,size_t pathlen)487c478bd9Sstevel@tonic-gate kmdb_module_path_set(const char **path, size_t pathlen)
497c478bd9Sstevel@tonic-gate {
507c478bd9Sstevel@tonic-gate 	kmdb_wr_path_t *wr;
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate 	wr = mdb_zalloc(sizeof (kmdb_wr_path_t), UM_SLEEP);
537c478bd9Sstevel@tonic-gate 	wr->dpth_node.wn_task = WNTASK_DMOD_PATH_CHANGE;
547c478bd9Sstevel@tonic-gate 	wr->dpth_path = mdb_path_dup(path, pathlen, &wr->dpth_pathlen);
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate 	kmdb_wr_driver_notify(wr);
577c478bd9Sstevel@tonic-gate }
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate void
kmdb_module_path_ack(kmdb_wr_path_t * dpth)607c478bd9Sstevel@tonic-gate kmdb_module_path_ack(kmdb_wr_path_t *dpth)
617c478bd9Sstevel@tonic-gate {
627c478bd9Sstevel@tonic-gate 	if (dpth->dpth_path != NULL)
637c478bd9Sstevel@tonic-gate 		mdb_path_free(dpth->dpth_path, dpth->dpth_pathlen);
647c478bd9Sstevel@tonic-gate 	mdb_free(dpth, sizeof (kmdb_wr_path_t));
657c478bd9Sstevel@tonic-gate }
667c478bd9Sstevel@tonic-gate 
67*5ae68c69Sjohnlev static kmdb_modctl_t *
kmdb_module_lookup_loaded(const char * name)68*5ae68c69Sjohnlev kmdb_module_lookup_loaded(const char *name)
69*5ae68c69Sjohnlev {
70*5ae68c69Sjohnlev 	kmdb_modctl_t *kmc;
71*5ae68c69Sjohnlev 	mdb_var_t *v;
72*5ae68c69Sjohnlev 
73*5ae68c69Sjohnlev 	if ((v = mdb_nv_lookup(&mdb.m_dmodctl, name)) == NULL)
74*5ae68c69Sjohnlev 		return (NULL);
75*5ae68c69Sjohnlev 
76*5ae68c69Sjohnlev 	kmc = MDB_NV_COOKIE(v);
77*5ae68c69Sjohnlev 	if (kmc->kmc_state != KMDB_MC_STATE_LOADED)
78*5ae68c69Sjohnlev 		return (NULL);
79*5ae68c69Sjohnlev 
80*5ae68c69Sjohnlev 	return (kmc);
81*5ae68c69Sjohnlev }
82*5ae68c69Sjohnlev 
837c478bd9Sstevel@tonic-gate /*
847c478bd9Sstevel@tonic-gate  * Given an address, try to match it up with a dmod symbol.
857c478bd9Sstevel@tonic-gate  */
867c478bd9Sstevel@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)877c478bd9Sstevel@tonic-gate kmdb_module_lookup_by_addr(uintptr_t addr, uint_t flags, char *buf,
887c478bd9Sstevel@tonic-gate     size_t nbytes, GElf_Sym *symp, mdb_syminfo_t *sip)
897c478bd9Sstevel@tonic-gate {
907c478bd9Sstevel@tonic-gate 	kmdb_modctl_t *sym_kmc = NULL;
917c478bd9Sstevel@tonic-gate 	GElf_Sym sym;
927c478bd9Sstevel@tonic-gate 	uint_t symid;
937c478bd9Sstevel@tonic-gate 	mdb_var_t *v;
947c478bd9Sstevel@tonic-gate 	const char *name;
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 	mdb_nv_rewind(&mdb.m_dmodctl);
977c478bd9Sstevel@tonic-gate 	while ((v = mdb_nv_advance(&mdb.m_dmodctl)) != NULL) {
987c478bd9Sstevel@tonic-gate 		kmdb_modctl_t *kmc = MDB_NV_COOKIE(v);
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 		if (kmc->kmc_state != KMDB_MC_STATE_LOADED)
1017c478bd9Sstevel@tonic-gate 			continue;
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 		if (mdb_gelf_symtab_lookup_by_addr(kmc->kmc_symtab, addr, flags,
1047c478bd9Sstevel@tonic-gate 		    buf, nbytes, symp, &sip->sym_id) != 0 ||
1057c478bd9Sstevel@tonic-gate 		    symp->st_value == 0)
1067c478bd9Sstevel@tonic-gate 			continue;
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 		if (flags & MDB_TGT_SYM_EXACT) {
1097c478bd9Sstevel@tonic-gate 			sym_kmc = kmc;
1107c478bd9Sstevel@tonic-gate 			goto found;
1117c478bd9Sstevel@tonic-gate 		}
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 		/*
1147c478bd9Sstevel@tonic-gate 		 * If this is the first match we've found, or if this symbol is
1157c478bd9Sstevel@tonic-gate 		 * closer to the specified address than the last one we found,
1167c478bd9Sstevel@tonic-gate 		 * use it.
1177c478bd9Sstevel@tonic-gate 		 */
1187c478bd9Sstevel@tonic-gate 		if (sym_kmc == NULL || mdb_gelf_sym_closer(symp, &sym, addr)) {
1197c478bd9Sstevel@tonic-gate 			sym_kmc = kmc;
1207c478bd9Sstevel@tonic-gate 			sym = *symp;
1217c478bd9Sstevel@tonic-gate 			symid = sip->sym_id;
1227c478bd9Sstevel@tonic-gate 		}
1237c478bd9Sstevel@tonic-gate 	}
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 	if (sym_kmc == NULL)
1267c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_NOSYMADDR));
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	*symp = sym;
1297c478bd9Sstevel@tonic-gate 	sip->sym_id = symid;
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate found:
1327c478bd9Sstevel@tonic-gate 	/*
1337c478bd9Sstevel@tonic-gate 	 * Once we've found something, copy the final name into the caller's
1347c478bd9Sstevel@tonic-gate 	 * buffer, prefixed with a marker identifying this as a dmod symbol.
1357c478bd9Sstevel@tonic-gate 	 */
1367c478bd9Sstevel@tonic-gate 	if (buf != NULL) {
1377c478bd9Sstevel@tonic-gate 		name = mdb_gelf_sym_name(sym_kmc->kmc_symtab, symp);
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 		(void) mdb_snprintf(buf, nbytes, "DMOD`%s`%s",
1407c478bd9Sstevel@tonic-gate 		    sym_kmc->kmc_modname, name);
1417c478bd9Sstevel@tonic-gate 	}
1427c478bd9Sstevel@tonic-gate 	sip->sym_table = MDB_TGT_SYMTAB;
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 	return (0);
1457c478bd9Sstevel@tonic-gate }
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate /*
1487c478bd9Sstevel@tonic-gate  * Locate a given dmod symbol
1497c478bd9Sstevel@tonic-gate  */
1507c478bd9Sstevel@tonic-gate int
kmdb_module_lookup_by_name(const char * obj,const char * name,GElf_Sym * symp,mdb_syminfo_t * sip)1517c478bd9Sstevel@tonic-gate kmdb_module_lookup_by_name(const char *obj, const char *name, GElf_Sym *symp,
1527c478bd9Sstevel@tonic-gate     mdb_syminfo_t *sip)
1537c478bd9Sstevel@tonic-gate {
1547c478bd9Sstevel@tonic-gate 	kmdb_modctl_t *kmc;
1557c478bd9Sstevel@tonic-gate 
156*5ae68c69Sjohnlev 	if ((kmc = kmdb_module_lookup_loaded(obj)) == NULL)
1577c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_NOSYMADDR));
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	if (mdb_gelf_symtab_lookup_by_name(kmc->kmc_symtab, name,
1607c478bd9Sstevel@tonic-gate 	    symp, &sip->sym_id) == 0) {
1617c478bd9Sstevel@tonic-gate 		sip->sym_table = MDB_TGT_SYMTAB;
1627c478bd9Sstevel@tonic-gate 		return (0);
1637c478bd9Sstevel@tonic-gate 	}
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	return (set_errno(EMDB_NOSYM));
1667c478bd9Sstevel@tonic-gate }
1677c478bd9Sstevel@tonic-gate 
168*5ae68c69Sjohnlev ctf_file_t *
kmdb_module_addr_to_ctf(uintptr_t addr)169*5ae68c69Sjohnlev kmdb_module_addr_to_ctf(uintptr_t addr)
170*5ae68c69Sjohnlev {
171*5ae68c69Sjohnlev 	mdb_var_t *v;
172*5ae68c69Sjohnlev 
173*5ae68c69Sjohnlev 	mdb_nv_rewind(&mdb.m_dmodctl);
174*5ae68c69Sjohnlev 	while ((v = mdb_nv_advance(&mdb.m_dmodctl)) != NULL) {
175*5ae68c69Sjohnlev 		kmdb_modctl_t *kmc = MDB_NV_COOKIE(v);
176*5ae68c69Sjohnlev 		struct module *mp;
177*5ae68c69Sjohnlev 
178*5ae68c69Sjohnlev 		if (kmc->kmc_state != KMDB_MC_STATE_LOADED)
179*5ae68c69Sjohnlev 			continue;
180*5ae68c69Sjohnlev 
181*5ae68c69Sjohnlev 		mp = kmc->kmc_modctl->mod_mp;
182*5ae68c69Sjohnlev 		if (addr - (uintptr_t)mp->text < mp->text_size ||
183*5ae68c69Sjohnlev 		    addr - (uintptr_t)mp->data < mp->data_size ||
184*5ae68c69Sjohnlev 		    addr - mp->bss < mp->bss_size) {
185*5ae68c69Sjohnlev 			ctf_file_t *ctfp = kmc->kmc_mod->mod_ctfp;
186*5ae68c69Sjohnlev 
187*5ae68c69Sjohnlev 			if (ctfp == NULL) {
188*5ae68c69Sjohnlev 				(void) set_errno(EMDB_NOCTF);
189*5ae68c69Sjohnlev 				return (NULL);
190*5ae68c69Sjohnlev 			}
191*5ae68c69Sjohnlev 
192*5ae68c69Sjohnlev 			return (ctfp);
193*5ae68c69Sjohnlev 		}
194*5ae68c69Sjohnlev 	}
195*5ae68c69Sjohnlev 
196*5ae68c69Sjohnlev 	(void) set_errno(EMDB_NOMAP);
197*5ae68c69Sjohnlev 	return (NULL);
198*5ae68c69Sjohnlev }
199*5ae68c69Sjohnlev 
200*5ae68c69Sjohnlev ctf_file_t *
kmdb_module_name_to_ctf(const char * obj)201*5ae68c69Sjohnlev kmdb_module_name_to_ctf(const char *obj)
202*5ae68c69Sjohnlev {
203*5ae68c69Sjohnlev 	kmdb_modctl_t *kmc;
204*5ae68c69Sjohnlev 	ctf_file_t *ctfp;
205*5ae68c69Sjohnlev 
206*5ae68c69Sjohnlev 	if ((kmc = kmdb_module_lookup_loaded(obj)) == NULL) {
207*5ae68c69Sjohnlev 		(void) set_errno(EMDB_NOOBJ);
208*5ae68c69Sjohnlev 		return (NULL);
209*5ae68c69Sjohnlev 	}
210*5ae68c69Sjohnlev 
211*5ae68c69Sjohnlev 	if ((ctfp = kmc->kmc_mod->mod_ctfp) == NULL) {
212*5ae68c69Sjohnlev 		(void) set_errno(EMDB_NOCTF);
213*5ae68c69Sjohnlev 		return (NULL);
214*5ae68c69Sjohnlev 	}
215*5ae68c69Sjohnlev 
216*5ae68c69Sjohnlev 	return (ctfp);
217*5ae68c69Sjohnlev }
218*5ae68c69Sjohnlev 
2197c478bd9Sstevel@tonic-gate static int
kmdb_module_symtab_func(void * data,const GElf_Sym * sym,const char * name,uint_t id)2207c478bd9Sstevel@tonic-gate kmdb_module_symtab_func(void *data, const GElf_Sym *sym, const char *name,
2217c478bd9Sstevel@tonic-gate     uint_t id)
2227c478bd9Sstevel@tonic-gate {
2237c478bd9Sstevel@tonic-gate 	kmod_symarg_t *arg = data;
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	if (mdb_tgt_sym_match(sym, arg->sym_type)) {
2267c478bd9Sstevel@tonic-gate 		arg->sym_info.sym_id = id;
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 		return (arg->sym_cb(arg->sym_data, sym, name, &arg->sym_info,
2297c478bd9Sstevel@tonic-gate 		    arg->sym_obj));
2307c478bd9Sstevel@tonic-gate 	}
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 	return (0);
2337c478bd9Sstevel@tonic-gate }
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate int
kmdb_module_symbol_iter(const char * obj,uint_t type,mdb_tgt_sym_f * cb,void * p)2367c478bd9Sstevel@tonic-gate kmdb_module_symbol_iter(const char *obj, uint_t type, mdb_tgt_sym_f *cb,
2377c478bd9Sstevel@tonic-gate     void *p)
2387c478bd9Sstevel@tonic-gate {
2397c478bd9Sstevel@tonic-gate 	kmdb_modctl_t *kmc;
2407c478bd9Sstevel@tonic-gate 	kmod_symarg_t arg;
2417c478bd9Sstevel@tonic-gate 	mdb_var_t *v;
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	if ((v = mdb_nv_lookup(&mdb.m_dmodctl, obj)) == NULL)
2447c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_NOMOD));
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 	kmc = MDB_NV_COOKIE(v);
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 	if (kmc->kmc_state != KMDB_MC_STATE_LOADED)
2497c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_NOMOD));
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	arg.sym_cb = cb;
2527c478bd9Sstevel@tonic-gate 	arg.sym_data = p;
2537c478bd9Sstevel@tonic-gate 	arg.sym_type = type;
2547c478bd9Sstevel@tonic-gate 	arg.sym_info.sym_table = kmc->kmc_symtab->gst_tabid;
2557c478bd9Sstevel@tonic-gate 	arg.sym_obj = obj;
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	mdb_gelf_symtab_iter(kmc->kmc_symtab, kmdb_module_symtab_func, &arg);
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 	return (0);
2607c478bd9Sstevel@tonic-gate }
261