xref: /illumos-gate/usr/src/cmd/mdb/common/kmdb/kmdb_module.c (revision 3ce5372277f4657ad0e52d36c979527c4ca22de2)
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