xref: /illumos-gate/usr/src/cmd/mdb/common/mdb/mdb_pservice.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Proc Service API Interposition Layer
31  *
32  * In order to allow multiple MDB targets to make use of librtld_db, we
33  * provide an interposition layer for functions in the proc_service.h API
34  * that are used by librtld_db.  Each of the functions used by librtld_db
35  * can be conveniently expressed in terms of the MDB target API, so this
36  * layer simply selects the appropriate target, invokes the corresponding
37  * target API function, and then translates the error codes appropriately.
38  * We expect that each proc_service entry point will be invoked with a
39  * cookie (struct ps_prochandle *) which matches either a known MDB target,
40  * or the value of a target's t->t_pshandle.  This allows us to re-vector
41  * calls to the proc service API around libproc (which also contains an
42  * implementation of the proc_service API) like this:
43  *
44  * Linker map:
45  * +---------+   +---------+   +------------+      Legend:
46  * |   MDB   | ->| libproc | ->| librtld_db |      <1> function in this file
47  * +---------+   +---------+   +------------+      <2> function in libproc
48  * ps_pread<1>   ps_pread<2>   call ps_pread() --+
49  *                                               |
50  * +---------------------------------------------+
51  * |
52  * +-> ps_pread<1>(P, ...)
53  *       t = mdb_tgt_from_pshandle(P);
54  *       mdb_tgt_vread(t, ...);
55  *
56  * If we are debugging a user process, we then make these calls (which form
57  * the equivalent of libproc's proc_service implementation):
58  *
59  * mdb_tgt_vread() -> proc target t->t_vread() -> libproc.so`Pread()
60  *
61  * If we are debugging a user process through a kernel crash dump (kproc
62  * target), we make these calls:
63  *
64  * mdb_tgt_vread() -> kproc target t->t_vread() -> mdb_tgt_aread(kvm target) ->
65  * 	kvm target t->t_aread() -> libkvm.so`kvm_aread()
66  *
67  * This design allows us to support both kproc's use of librtld_db, as well
68  * as libproc's use of librtld_db, but it does lead to one unfortunate problem
69  * in the creation of a proc target: when the proc target invokes libproc to
70  * construct a ps_prochandle, and libproc in turn invokes librtld_db, MDB does
71  * not yet know what ps_prochandle has been allocated inside of libproc since
72  * this call has not yet returned.  We also can't translate this ps_prochandle
73  * to the target itself, since that target isn't ready to handle requests yet;
74  * we actually need to pass the call back through to libproc.  In order to
75  * do that, we use libdl to lookup the address of libproc's definition of the
76  * various functions (RTLD_NEXT on the link map chain) and store these in the
77  * ps_ops structure below.  If we ever fail to translate a ps_prochandle to
78  * an MDB target, we simply pass the call through to libproc.
79  */
80 
81 #include <proc_service.h>
82 #include <dlfcn.h>
83 
84 #include <mdb/mdb_target_impl.h>
85 #include <mdb/mdb_debug.h>
86 #include <mdb/mdb.h>
87 
88 static struct {
89 	ps_err_e (*ps_pread)(struct ps_prochandle *,
90 	    psaddr_t, void *, size_t);
91 	ps_err_e (*ps_pwrite)(struct ps_prochandle *,
92 	    psaddr_t, const void *, size_t);
93 	ps_err_e (*ps_pglobal_lookup)(struct ps_prochandle *,
94 	    const char *, const char *, psaddr_t *);
95 	ps_err_e (*ps_pglobal_sym)(struct ps_prochandle *P,
96 	    const char *, const char *, ps_sym_t *);
97 	ps_err_e (*ps_pauxv)(struct ps_prochandle *,
98 	    const auxv_t **);
99 	ps_err_e (*ps_pbrandname)(struct ps_prochandle *,
100 	    char *, size_t);
101 	ps_err_e (*ps_pdmodel)(struct ps_prochandle *,
102 	    int *);
103 } ps_ops;
104 
105 static mdb_tgt_t *
106 mdb_tgt_from_pshandle(void *P)
107 {
108 	mdb_tgt_t *t;
109 
110 	for (t = mdb_list_next(&mdb.m_tgtlist); t; t = mdb_list_next(t)) {
111 		if (t == P || t->t_pshandle == P)
112 			return (t);
113 	}
114 
115 	return (NULL);
116 }
117 
118 /*
119  * Read from the specified target virtual address.
120  */
121 ps_err_e
122 ps_pread(struct ps_prochandle *P, psaddr_t addr, void *buf, size_t size)
123 {
124 	mdb_tgt_t *t = mdb_tgt_from_pshandle(P);
125 
126 	if (t == NULL)
127 		return (ps_ops.ps_pread(P, addr, buf, size));
128 
129 	if (mdb_tgt_vread(t, buf, size, addr) != size)
130 		return (PS_BADADDR);
131 
132 	return (PS_OK);
133 }
134 
135 /*
136  * Write to the specified target virtual address.
137  */
138 ps_err_e
139 ps_pwrite(struct ps_prochandle *P, psaddr_t addr, const void *buf, size_t size)
140 {
141 	mdb_tgt_t *t = mdb_tgt_from_pshandle(P);
142 
143 	if (t == NULL)
144 		return (ps_ops.ps_pwrite(P, addr, buf, size));
145 
146 	if (mdb_tgt_vwrite(t, buf, size, addr) != size)
147 		return (PS_BADADDR);
148 
149 	return (PS_OK);
150 }
151 
152 /*
153  * Search for a symbol by name and return the corresponding address.
154  */
155 ps_err_e
156 ps_pglobal_lookup(struct ps_prochandle *P, const char *object,
157     const char *name, psaddr_t *symp)
158 {
159 	mdb_tgt_t *t = mdb_tgt_from_pshandle(P);
160 	GElf_Sym sym;
161 
162 	if (t == NULL)
163 		return (ps_ops.ps_pglobal_lookup(P, object, name, symp));
164 
165 	if (mdb_tgt_lookup_by_name(t, object, name, &sym, NULL) == 0) {
166 		*symp = (psaddr_t)sym.st_value;
167 		return (PS_OK);
168 	}
169 
170 	return (PS_NOSYM);
171 }
172 
173 /*
174  * Search for a symbol by name and return the corresponding symbol data.
175  * If we're compiled _LP64, we just call mdb_tgt_lookup_by_name and return
176  * because ps_sym_t is defined to be an Elf64_Sym, which is the same as a
177  * GElf_Sym.  In the _ILP32 case, we have to convert mdb_tgt_lookup_by_name's
178  * result back to a ps_sym_t (which is an Elf32_Sym).
179  */
180 ps_err_e
181 ps_pglobal_sym(struct ps_prochandle *P, const char *object,
182     const char *name, ps_sym_t *symp)
183 {
184 	mdb_tgt_t *t = mdb_tgt_from_pshandle(P);
185 #if defined(_ILP32)
186 	GElf_Sym sym;
187 
188 	if (t == NULL)
189 		return (ps_ops.ps_pglobal_sym(P, object, name, symp));
190 
191 	if (mdb_tgt_lookup_by_name(t, object, name, &sym, NULL) == 0) {
192 		symp->st_name = (Elf32_Word)sym.st_name;
193 		symp->st_value = (Elf32_Addr)sym.st_value;
194 		symp->st_size = (Elf32_Word)sym.st_size;
195 		symp->st_info = ELF32_ST_INFO(
196 		    GELF_ST_BIND(sym.st_info), GELF_ST_TYPE(sym.st_info));
197 		symp->st_other = sym.st_other;
198 		symp->st_shndx = sym.st_shndx;
199 		return (PS_OK);
200 	}
201 
202 #elif defined(_LP64)
203 	if (t == NULL)
204 		return (ps_ops.ps_pglobal_sym(P, object, name, symp));
205 
206 	if (mdb_tgt_lookup_by_name(t, object, name, symp, NULL) == 0)
207 		return (PS_OK);
208 #endif
209 
210 	return (PS_NOSYM);
211 }
212 
213 /*
214  * Report a debug message.  We allow proc_service API clients to report
215  * messages via our debug stream if the MDB_DBG_PSVC token is enabled.
216  */
217 void
218 ps_plog(const char *format, ...)
219 {
220 	va_list alist;
221 
222 	va_start(alist, format);
223 	mdb_dvprintf(MDB_DBG_PSVC, format, alist);
224 	va_end(alist);
225 }
226 
227 /*
228  * Return the auxv structure from the process being examined.
229  */
230 ps_err_e
231 ps_pauxv(struct ps_prochandle *P, const auxv_t **auxvp)
232 {
233 	mdb_tgt_t *t = mdb_tgt_from_pshandle(P);
234 
235 	if (t == NULL)
236 		return (ps_ops.ps_pauxv(P, auxvp));
237 
238 	if (mdb_tgt_auxv(t, auxvp) != 0)
239 		return (PS_ERR);
240 
241 	return (PS_OK);
242 }
243 
244 ps_err_e
245 ps_pbrandname(struct ps_prochandle *P, char *buf, size_t len)
246 {
247 	mdb_tgt_t *t = mdb_tgt_from_pshandle(P);
248 	const auxv_t *auxv;
249 
250 	if (t == NULL)
251 		return (ps_ops.ps_pbrandname(P, buf, len));
252 
253 	if (mdb_tgt_auxv(t, &auxv) != 0)
254 		return (PS_ERR);
255 
256 	while (auxv->a_type != AT_NULL) {
257 		if (auxv->a_type == AT_SUN_BRANDNAME)
258 			break;
259 		auxv++;
260 	}
261 	if (auxv->a_type == AT_NULL)
262 		return (PS_ERR);
263 
264 	if (mdb_tgt_readstr(t, MDB_TGT_AS_VIRT,
265 	    buf, len, auxv->a_un.a_val) <= 0)
266 		return (PS_ERR);
267 
268 	return (PS_OK);
269 }
270 
271 /*
272  * Return the data model of the target.
273  */
274 ps_err_e
275 ps_pdmodel(struct ps_prochandle *P, int *dm)
276 {
277 	mdb_tgt_t *t = mdb_tgt_from_pshandle(P);
278 
279 	if (t == NULL)
280 		return (ps_ops.ps_pdmodel(P, dm));
281 
282 	switch (mdb_tgt_dmodel(t)) {
283 	case MDB_TGT_MODEL_LP64:
284 		*dm = PR_MODEL_LP64;
285 		return (PS_OK);
286 	case MDB_TGT_MODEL_ILP32:
287 		*dm = PR_MODEL_ILP32;
288 		return (PS_OK);
289 	}
290 
291 	return (PS_ERR);
292 }
293 
294 /*
295  * Stub function in case we cannot find the necessary symbols from libproc.
296  */
297 static ps_err_e
298 ps_fail(struct ps_prochandle *P)
299 {
300 	mdb_dprintf(MDB_DBG_PSVC, "failing call to pshandle %p\n", (void *)P);
301 	return (PS_BADPID);
302 }
303 
304 /*
305  * Initialization function for the proc service interposition layer: we use
306  * libdl to look up the next definition of each function in the link map.
307  */
308 void
309 mdb_pservice_init(void)
310 {
311 	if ((ps_ops.ps_pread = (ps_err_e (*)())
312 	    dlsym(RTLD_NEXT, "ps_pread")) == NULL)
313 		ps_ops.ps_pread = (ps_err_e (*)())ps_fail;
314 
315 	if ((ps_ops.ps_pwrite = (ps_err_e (*)())
316 	    dlsym(RTLD_NEXT, "ps_pwrite")) == NULL)
317 		ps_ops.ps_pwrite = (ps_err_e (*)())ps_fail;
318 
319 	if ((ps_ops.ps_pglobal_lookup = (ps_err_e (*)())
320 	    dlsym(RTLD_NEXT, "ps_pglobal_lookup")) == NULL)
321 		ps_ops.ps_pglobal_lookup = (ps_err_e (*)())ps_fail;
322 
323 	if ((ps_ops.ps_pglobal_sym = (ps_err_e (*)())
324 	    dlsym(RTLD_NEXT, "ps_pglobal_sym")) == NULL)
325 		ps_ops.ps_pglobal_sym = (ps_err_e (*)())ps_fail;
326 
327 	if ((ps_ops.ps_pauxv = (ps_err_e (*)())
328 	    dlsym(RTLD_NEXT, "ps_pauxv")) == NULL)
329 		ps_ops.ps_pauxv = (ps_err_e (*)())ps_fail;
330 
331 	if ((ps_ops.ps_pbrandname = (ps_err_e (*)())
332 	    dlsym(RTLD_NEXT, "ps_pbrandname")) == NULL)
333 		ps_ops.ps_pbrandname = (ps_err_e (*)())ps_fail;
334 
335 	if ((ps_ops.ps_pdmodel = (ps_err_e (*)())
336 	    dlsym(RTLD_NEXT, "ps_pdmodel")) == NULL)
337 		ps_ops.ps_pdmodel = (ps_err_e (*)())ps_fail;
338 }
339