xref: /illumos-gate/usr/src/cmd/mdb/common/mdb/mdb_ctf.c (revision 56f33205c9ed776c3c909e07d52e94610a675740)
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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <mdb/mdb_ctf.h>
27 #include <mdb/mdb_ctf_impl.h>
28 #include <mdb/mdb_err.h>
29 #include <mdb/mdb_modapi.h>
30 #include <mdb/mdb_string.h>
31 #include <mdb/mdb.h>
32 #include <mdb/mdb_debug.h>
33 
34 #include <libctf.h>
35 #include <string.h>
36 
37 typedef struct tnarg {
38 	mdb_tgt_t *tn_tgt;		/* target to use for lookup */
39 	const char *tn_name;		/* query string to lookup */
40 	ctf_file_t *tn_fp;		/* CTF container from match */
41 	ctf_id_t tn_id;			/* CTF type ID from match */
42 } tnarg_t;
43 
44 typedef struct type_iter {
45 	mdb_ctf_type_f *ti_cb;
46 	void *ti_arg;
47 	ctf_file_t *ti_fp;
48 } type_iter_t;
49 
50 typedef struct member_iter {
51 	mdb_ctf_member_f *mi_cb;
52 	void *mi_arg;
53 	ctf_file_t *mi_fp;
54 } member_iter_t;
55 
56 typedef struct type_visit {
57 	mdb_ctf_visit_f	*tv_cb;
58 	void		*tv_arg;
59 	ctf_file_t	*tv_fp;
60 	ulong_t		tv_base_offset;	/* used when recursing from type_cb() */
61 	int		tv_base_depth;	/* used when recursing from type_cb() */
62 	int		tv_min_depth;
63 } type_visit_t;
64 
65 typedef struct mbr_info {
66 	const char *mbr_member;
67 	ulong_t *mbr_offp;
68 	mdb_ctf_id_t *mbr_typep;
69 } mbr_info_t;
70 
71 static void
72 set_ctf_id(mdb_ctf_id_t *p, ctf_file_t *fp, ctf_id_t id)
73 {
74 	mdb_ctf_impl_t *mcip = (mdb_ctf_impl_t *)p;
75 
76 	mcip->mci_fp = fp;
77 	mcip->mci_id = id;
78 }
79 
80 /*
81  * Callback function for mdb_tgt_object_iter used from name_to_type, below,
82  * to search the CTF namespace of each object file for a particular name.
83  */
84 /*ARGSUSED*/
85 static int
86 obj_lookup(void *data, const mdb_map_t *mp, const char *name)
87 {
88 	tnarg_t *tnp = data;
89 	ctf_file_t *fp;
90 	ctf_id_t id;
91 
92 	if ((fp = mdb_tgt_name_to_ctf(tnp->tn_tgt, name)) != NULL &&
93 	    (id = ctf_lookup_by_name(fp, tnp->tn_name)) != CTF_ERR) {
94 		tnp->tn_fp = fp;
95 		tnp->tn_id = id;
96 
97 		/*
98 		 * We may have found a forward declaration.  If we did, we'll
99 		 * note the ID and file pointer, but we'll keep searching in
100 		 * an attempt to find the real thing.  If we found something
101 		 * real (i.e. not a forward), we stop the iteration.
102 		 */
103 		return (ctf_type_kind(fp, id) == CTF_K_FORWARD ? 0 : -1);
104 	}
105 
106 	return (0);
107 }
108 
109 /*
110  * Convert a string type name with an optional leading object specifier into
111  * the corresponding CTF file container and type ID.  If an error occurs, we
112  * print an appropriate message and return NULL.
113  */
114 static ctf_file_t *
115 name_to_type(mdb_tgt_t *t, const char *cname, ctf_id_t *idp)
116 {
117 	const char *object = MDB_TGT_OBJ_EXEC;
118 	ctf_file_t *fp = NULL;
119 	ctf_id_t id;
120 	tnarg_t arg;
121 	char *p, *s;
122 	char buf[MDB_SYM_NAMLEN];
123 	char *name = &buf[0];
124 
125 	(void) mdb_snprintf(buf, sizeof (buf), "%s", cname);
126 
127 	if ((p = strrsplit(name, '`')) != NULL) {
128 		/*
129 		 * We need to shuffle things around a little to support
130 		 * type names of the form "struct module`name".
131 		 */
132 		if ((s = strsplit(name, ' ')) != NULL) {
133 			bcopy(cname + (s - name), name, (p - s) - 1);
134 			name[(p - s) - 1] = '\0';
135 			bcopy(cname, name + (p - s), s - name);
136 			p = name + (p - s);
137 		}
138 		if (*name != '\0')
139 			object = name;
140 		name = p;
141 	}
142 
143 	/*
144 	 * Attempt to look up the name in the primary object file.  If this
145 	 * fails and the name was unscoped, search all remaining object files.
146 	 */
147 	if (((fp = mdb_tgt_name_to_ctf(t, object)) == NULL ||
148 	    (id = ctf_lookup_by_name(fp, name)) == CTF_ERR ||
149 	    ctf_type_kind(fp, id) == CTF_K_FORWARD) &&
150 	    object == MDB_TGT_OBJ_EXEC) {
151 
152 		arg.tn_tgt = t;
153 		arg.tn_name = name;
154 		arg.tn_fp = NULL;
155 		arg.tn_id = CTF_ERR;
156 
157 		(void) mdb_tgt_object_iter(t, obj_lookup, &arg);
158 
159 		if (arg.tn_id != CTF_ERR) {
160 			fp = arg.tn_fp;
161 			id = arg.tn_id;
162 		}
163 	}
164 
165 	if (fp == NULL)
166 		return (NULL); /* errno is set for us */
167 
168 	if (id == CTF_ERR) {
169 		(void) set_errno(ctf_to_errno(ctf_errno(fp)));
170 		return (NULL);
171 	}
172 
173 	*idp = id;
174 	return (fp);
175 }
176 
177 /*
178  * Check to see if there is ctf data in the given object. This is useful
179  * so that we don't enter some loop where every call to lookup fails.
180  */
181 int
182 mdb_ctf_enabled_by_object(const char *object)
183 {
184 	mdb_tgt_t *t = mdb.m_target;
185 
186 	return (mdb_tgt_name_to_ctf(t, object) != NULL);
187 }
188 
189 int
190 mdb_ctf_lookup_by_name(const char *name, mdb_ctf_id_t *p)
191 {
192 	ctf_file_t *fp = NULL;
193 	mdb_ctf_impl_t *mcip = (mdb_ctf_impl_t *)p;
194 	mdb_tgt_t *t = mdb.m_target;
195 
196 	if (mcip == NULL)
197 		return (set_errno(EINVAL));
198 
199 	if ((fp = name_to_type(t, name, &mcip->mci_id)) == NULL) {
200 		mdb_ctf_type_invalidate(p);
201 		return (-1); /* errno is set for us */
202 	}
203 
204 	mcip->mci_fp = fp;
205 
206 	return (0);
207 }
208 
209 int
210 mdb_ctf_lookup_by_symbol(const GElf_Sym *symp, const mdb_syminfo_t *sip,
211     mdb_ctf_id_t *p)
212 {
213 	ctf_file_t *fp = NULL;
214 	mdb_ctf_impl_t *mcip = (mdb_ctf_impl_t *)p;
215 	mdb_tgt_t *t = mdb.m_target;
216 
217 	if (mcip == NULL)
218 		return (set_errno(EINVAL));
219 
220 	if (symp == NULL || sip == NULL) {
221 		mdb_ctf_type_invalidate(p);
222 		return (set_errno(EINVAL));
223 	}
224 
225 	if ((fp = mdb_tgt_addr_to_ctf(t, symp->st_value)) == NULL) {
226 		mdb_ctf_type_invalidate(p);
227 		return (-1); /* errno is set for us */
228 	}
229 
230 	if ((mcip->mci_id = ctf_lookup_by_symbol(fp, sip->sym_id)) == CTF_ERR) {
231 		mdb_ctf_type_invalidate(p);
232 		return (set_errno(ctf_to_errno(ctf_errno(fp))));
233 	}
234 
235 	mcip->mci_fp = fp;
236 
237 	return (0);
238 }
239 
240 int
241 mdb_ctf_lookup_by_addr(uintptr_t addr, mdb_ctf_id_t *p)
242 {
243 	GElf_Sym sym;
244 	mdb_syminfo_t si;
245 	char name[MDB_SYM_NAMLEN];
246 	const mdb_map_t *mp;
247 	mdb_tgt_t *t = mdb.m_target;
248 	const char *obj, *c;
249 
250 	if (p == NULL)
251 		return (set_errno(EINVAL));
252 
253 	if (mdb_tgt_lookup_by_addr(t, addr, MDB_TGT_SYM_EXACT, name,
254 	    sizeof (name), NULL, NULL) == -1) {
255 		mdb_ctf_type_invalidate(p);
256 		return (-1); /* errno is set for us */
257 	}
258 
259 	if ((c = strrsplit(name, '`')) != NULL) {
260 		obj = name;
261 	} else {
262 		if ((mp = mdb_tgt_addr_to_map(t, addr)) == NULL) {
263 			mdb_ctf_type_invalidate(p);
264 			return (-1); /* errno is set for us */
265 		}
266 
267 		obj = mp->map_name;
268 		c = name;
269 	}
270 
271 	if (mdb_tgt_lookup_by_name(t, obj, c, &sym, &si) == -1) {
272 		mdb_ctf_type_invalidate(p);
273 		return (-1); /* errno is set for us */
274 	}
275 
276 	return (mdb_ctf_lookup_by_symbol(&sym, &si, p));
277 }
278 
279 int
280 mdb_ctf_module_lookup(const char *name, mdb_ctf_id_t *p)
281 {
282 	ctf_file_t *fp;
283 	ctf_id_t id;
284 	mdb_module_t *mod;
285 
286 	if ((mod = mdb_get_module()) == NULL)
287 		return (set_errno(EMDB_CTX));
288 
289 	if ((fp = mod->mod_ctfp) == NULL)
290 		return (set_errno(EMDB_NOCTF));
291 
292 	if ((id = ctf_lookup_by_name(fp, name)) == CTF_ERR)
293 		return (set_errno(ctf_to_errno(ctf_errno(fp))));
294 
295 	set_ctf_id(p, fp, id);
296 
297 	return (0);
298 }
299 
300 /*ARGSUSED*/
301 int
302 mdb_ctf_func_info(const GElf_Sym *symp, const mdb_syminfo_t *sip,
303     mdb_ctf_funcinfo_t *mfp)
304 {
305 	ctf_file_t *fp = NULL;
306 	ctf_funcinfo_t f;
307 	mdb_tgt_t *t = mdb.m_target;
308 	char name[MDB_SYM_NAMLEN];
309 	const mdb_map_t *mp;
310 	mdb_syminfo_t si;
311 	int err;
312 
313 	if (symp == NULL || mfp == NULL)
314 		return (set_errno(EINVAL));
315 
316 	/*
317 	 * In case the input symbol came from a merged or private symbol table,
318 	 * re-lookup the address as a symbol, and then perform a fully scoped
319 	 * lookup of that symbol name to get the mdb_syminfo_t for its CTF.
320 	 */
321 	if ((fp = mdb_tgt_addr_to_ctf(t, symp->st_value)) == NULL ||
322 	    (mp = mdb_tgt_addr_to_map(t, symp->st_value)) == NULL ||
323 	    mdb_tgt_lookup_by_addr(t, symp->st_value, MDB_TGT_SYM_FUZZY,
324 	    name, sizeof (name), NULL, NULL) != 0)
325 		return (-1); /* errno is set for us */
326 
327 	if (strchr(name, '`') != NULL)
328 		err = mdb_tgt_lookup_by_scope(t, name, NULL, &si);
329 	else
330 		err = mdb_tgt_lookup_by_name(t, mp->map_name, name, NULL, &si);
331 
332 	if (err != 0)
333 		return (-1); /* errno is set for us */
334 
335 	if (ctf_func_info(fp, si.sym_id, &f) == CTF_ERR)
336 		return (set_errno(ctf_to_errno(ctf_errno(fp))));
337 
338 	set_ctf_id(&mfp->mtf_return, fp, f.ctc_return);
339 	mfp->mtf_argc = f.ctc_argc;
340 	mfp->mtf_flags = f.ctc_flags;
341 	mfp->mtf_symidx = si.sym_id;
342 
343 	return (0);
344 }
345 
346 int
347 mdb_ctf_func_args(const mdb_ctf_funcinfo_t *funcp, uint_t len,
348     mdb_ctf_id_t *argv)
349 {
350 	ctf_file_t *fp;
351 	ctf_id_t cargv[32];
352 	int i;
353 
354 	if (len > (sizeof (cargv) / sizeof (cargv[0])))
355 		return (set_errno(EINVAL));
356 
357 	if (funcp == NULL || argv == NULL)
358 		return (set_errno(EINVAL));
359 
360 	fp = mdb_ctf_type_file(funcp->mtf_return);
361 
362 	if (ctf_func_args(fp, funcp->mtf_symidx, len, cargv) == CTF_ERR)
363 		return (set_errno(ctf_to_errno(ctf_errno(fp))));
364 
365 	for (i = MIN(len, funcp->mtf_argc) - 1; i >= 0; i--) {
366 		set_ctf_id(&argv[i], fp, cargv[i]);
367 	}
368 
369 	return (0);
370 }
371 
372 void
373 mdb_ctf_type_invalidate(mdb_ctf_id_t *idp)
374 {
375 	set_ctf_id(idp, NULL, CTF_ERR);
376 }
377 
378 int
379 mdb_ctf_type_valid(mdb_ctf_id_t id)
380 {
381 	return (((mdb_ctf_impl_t *)&id)->mci_id != CTF_ERR);
382 }
383 
384 int
385 mdb_ctf_type_cmp(mdb_ctf_id_t aid, mdb_ctf_id_t bid)
386 {
387 	mdb_ctf_impl_t *aidp = (mdb_ctf_impl_t *)&aid;
388 	mdb_ctf_impl_t *bidp = (mdb_ctf_impl_t *)&bid;
389 
390 	return (ctf_type_cmp(aidp->mci_fp, aidp->mci_id,
391 	    bidp->mci_fp, bidp->mci_id));
392 }
393 
394 int
395 mdb_ctf_type_resolve(mdb_ctf_id_t mid, mdb_ctf_id_t *outp)
396 {
397 	ctf_id_t id;
398 	mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&mid;
399 
400 	if ((id = ctf_type_resolve(idp->mci_fp, idp->mci_id)) == CTF_ERR) {
401 		if (outp)
402 			mdb_ctf_type_invalidate(outp);
403 		return (set_errno(ctf_to_errno(ctf_errno(idp->mci_fp))));
404 	}
405 
406 	if (ctf_type_kind(idp->mci_fp, id) == CTF_K_FORWARD) {
407 		char name[MDB_SYM_NAMLEN];
408 		mdb_ctf_id_t lookup_id;
409 
410 		if (ctf_type_name(idp->mci_fp, id, name, sizeof (name)) !=
411 		    NULL &&
412 		    mdb_ctf_lookup_by_name(name, &lookup_id) == 0 &&
413 		    outp != NULL) {
414 			*outp = lookup_id;
415 			return (0);
416 		}
417 	}
418 
419 	if (outp != NULL)
420 		set_ctf_id(outp, idp->mci_fp, id);
421 
422 	return (0);
423 }
424 
425 char *
426 mdb_ctf_type_name(mdb_ctf_id_t id, char *buf, size_t len)
427 {
428 	mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&id;
429 	char *ret;
430 
431 	if (!mdb_ctf_type_valid(id)) {
432 		(void) set_errno(EINVAL);
433 		return (NULL);
434 	}
435 
436 	ret = ctf_type_name(idp->mci_fp, idp->mci_id, buf, len);
437 	if (ret == NULL)
438 		(void) set_errno(ctf_to_errno(ctf_errno(idp->mci_fp)));
439 
440 	return (ret);
441 }
442 
443 ssize_t
444 mdb_ctf_type_size(mdb_ctf_id_t id)
445 {
446 	mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&id;
447 	ssize_t ret;
448 
449 	/* resolve the type in case there's a forward declaration */
450 	if ((ret = mdb_ctf_type_resolve(id, &id)) != 0)
451 		return (ret);
452 
453 	if ((ret = ctf_type_size(idp->mci_fp, idp->mci_id)) == CTF_ERR)
454 		return (set_errno(ctf_to_errno(ctf_errno(idp->mci_fp))));
455 
456 	return (ret);
457 }
458 
459 int
460 mdb_ctf_type_kind(mdb_ctf_id_t id)
461 {
462 	mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&id;
463 	int ret;
464 
465 	if ((ret = ctf_type_kind(idp->mci_fp, idp->mci_id)) == CTF_ERR)
466 		return (set_errno(ctf_to_errno(ctf_errno(idp->mci_fp))));
467 
468 	return (ret);
469 }
470 
471 int
472 mdb_ctf_type_reference(mdb_ctf_id_t mid, mdb_ctf_id_t *outp)
473 {
474 	mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&mid;
475 	ctf_id_t id;
476 
477 	if ((id = ctf_type_reference(idp->mci_fp, idp->mci_id)) == CTF_ERR) {
478 		if (outp)
479 			mdb_ctf_type_invalidate(outp);
480 		return (set_errno(ctf_to_errno(ctf_errno(idp->mci_fp))));
481 	}
482 
483 	if (outp != NULL)
484 		set_ctf_id(outp, idp->mci_fp, id);
485 
486 	return (0);
487 }
488 
489 
490 int
491 mdb_ctf_type_encoding(mdb_ctf_id_t id, ctf_encoding_t *ep)
492 {
493 	mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&id;
494 
495 	if (ctf_type_encoding(idp->mci_fp, idp->mci_id, ep) == CTF_ERR)
496 		return (set_errno(ctf_to_errno(ctf_errno(idp->mci_fp))));
497 
498 	return (0);
499 }
500 
501 /*
502  * callback proxy for mdb_ctf_type_visit
503  */
504 static int
505 type_cb(const char *name, ctf_id_t type, ulong_t off, int depth, void *arg)
506 {
507 	type_visit_t *tvp = arg;
508 	mdb_ctf_id_t id;
509 	mdb_ctf_id_t base;
510 	mdb_ctf_impl_t *basep = (mdb_ctf_impl_t *)&base;
511 
512 	int ret;
513 
514 	if (depth < tvp->tv_min_depth)
515 		return (0);
516 
517 	off += tvp->tv_base_offset;
518 	depth += tvp->tv_base_depth;
519 
520 	set_ctf_id(&id, tvp->tv_fp, type);
521 
522 	(void) mdb_ctf_type_resolve(id, &base);
523 	if ((ret = tvp->tv_cb(name, id, base, off, depth, tvp->tv_arg)) != 0)
524 		return (ret);
525 
526 	/*
527 	 * If the type resolves to a type in a different file, we must have
528 	 * followed a forward declaration.  We need to recurse into the
529 	 * new type.
530 	 */
531 	if (basep->mci_fp != tvp->tv_fp && mdb_ctf_type_valid(base)) {
532 		type_visit_t tv;
533 
534 		tv.tv_cb = tvp->tv_cb;
535 		tv.tv_arg = tvp->tv_arg;
536 		tv.tv_fp = basep->mci_fp;
537 
538 		tv.tv_base_offset = off;
539 		tv.tv_base_depth = depth;
540 		tv.tv_min_depth = 1;	/* depth = 0 has already been done */
541 
542 		ret = ctf_type_visit(basep->mci_fp, basep->mci_id,
543 		    type_cb, &tv);
544 	}
545 	return (ret);
546 }
547 
548 int
549 mdb_ctf_type_visit(mdb_ctf_id_t id, mdb_ctf_visit_f *func, void *arg)
550 {
551 	mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&id;
552 	type_visit_t tv;
553 	int ret;
554 
555 	tv.tv_cb = func;
556 	tv.tv_arg = arg;
557 	tv.tv_fp = idp->mci_fp;
558 	tv.tv_base_offset = 0;
559 	tv.tv_base_depth = 0;
560 	tv.tv_min_depth = 0;
561 
562 	ret = ctf_type_visit(idp->mci_fp, idp->mci_id, type_cb, &tv);
563 
564 	if (ret == CTF_ERR)
565 		return (set_errno(ctf_to_errno(ctf_errno(idp->mci_fp))));
566 
567 	return (ret);
568 }
569 
570 int
571 mdb_ctf_array_info(mdb_ctf_id_t id, mdb_ctf_arinfo_t *arp)
572 {
573 	mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&id;
574 	ctf_arinfo_t car;
575 
576 	if (ctf_array_info(idp->mci_fp, idp->mci_id, &car) == CTF_ERR)
577 		return (set_errno(ctf_to_errno(ctf_errno(idp->mci_fp))));
578 
579 	set_ctf_id(&arp->mta_contents, idp->mci_fp, car.ctr_contents);
580 	set_ctf_id(&arp->mta_index, idp->mci_fp, car.ctr_index);
581 
582 	arp->mta_nelems = car.ctr_nelems;
583 
584 	return (0);
585 }
586 
587 const char *
588 mdb_ctf_enum_name(mdb_ctf_id_t id, int value)
589 {
590 	mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&id;
591 	const char *ret;
592 
593 	/* resolve the type in case there's a forward declaration */
594 	if (mdb_ctf_type_resolve(id, &id) != 0)
595 		return (NULL);
596 
597 	if ((ret = ctf_enum_name(idp->mci_fp, idp->mci_id, value)) == NULL)
598 		(void) set_errno(ctf_to_errno(ctf_errno(idp->mci_fp)));
599 
600 	return (ret);
601 }
602 
603 /*
604  * callback proxy for mdb_ctf_member_iter
605  */
606 static int
607 member_iter_cb(const char *name, ctf_id_t type, ulong_t off, void *data)
608 {
609 	member_iter_t *mip = data;
610 	mdb_ctf_id_t id;
611 
612 	set_ctf_id(&id, mip->mi_fp, type);
613 
614 	return (mip->mi_cb(name, id, off, mip->mi_arg));
615 }
616 
617 int
618 mdb_ctf_member_iter(mdb_ctf_id_t id, mdb_ctf_member_f *cb, void *data)
619 {
620 	mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&id;
621 	member_iter_t mi;
622 	int ret;
623 
624 	/* resolve the type in case there's a forward declaration */
625 	if ((ret = mdb_ctf_type_resolve(id, &id)) != 0)
626 		return (ret);
627 
628 	mi.mi_cb = cb;
629 	mi.mi_arg = data;
630 	mi.mi_fp = idp->mci_fp;
631 
632 	ret = ctf_member_iter(idp->mci_fp, idp->mci_id, member_iter_cb, &mi);
633 
634 	if (ret == CTF_ERR)
635 		return (set_errno(ctf_to_errno(ctf_errno(idp->mci_fp))));
636 
637 	return (ret);
638 }
639 
640 int
641 mdb_ctf_enum_iter(mdb_ctf_id_t id, mdb_ctf_enum_f *cb, void *data)
642 {
643 	mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&id;
644 	int ret;
645 
646 	/* resolve the type in case there's a forward declaration */
647 	if ((ret = mdb_ctf_type_resolve(id, &id)) != 0)
648 		return (ret);
649 
650 	return (ctf_enum_iter(idp->mci_fp, idp->mci_id, cb, data));
651 }
652 
653 /*
654  * callback proxy for mdb_ctf_type_iter
655  */
656 static int
657 type_iter_cb(ctf_id_t type, void *data)
658 {
659 	type_iter_t *tip = data;
660 	mdb_ctf_id_t id;
661 
662 	set_ctf_id(&id, tip->ti_fp, type);
663 
664 	return (tip->ti_cb(id, tip->ti_arg));
665 }
666 
667 int
668 mdb_ctf_type_iter(const char *object, mdb_ctf_type_f *cb, void *data)
669 {
670 	ctf_file_t *fp;
671 	mdb_tgt_t *t = mdb.m_target;
672 	int ret;
673 	type_iter_t ti;
674 
675 	if ((fp = mdb_tgt_name_to_ctf(t, object)) == NULL)
676 		return (-1);
677 
678 	ti.ti_cb = cb;
679 	ti.ti_arg = data;
680 	ti.ti_fp = fp;
681 
682 	if ((ret = ctf_type_iter(fp, type_iter_cb, &ti)) == CTF_ERR)
683 		return (set_errno(ctf_to_errno(ctf_errno(fp))));
684 
685 	return (ret);
686 }
687 
688 /* utility functions */
689 
690 ctf_id_t
691 mdb_ctf_type_id(mdb_ctf_id_t id)
692 {
693 	return (((mdb_ctf_impl_t *)&id)->mci_id);
694 }
695 
696 ctf_file_t *
697 mdb_ctf_type_file(mdb_ctf_id_t id)
698 {
699 	return (((mdb_ctf_impl_t *)&id)->mci_fp);
700 }
701 
702 static int
703 member_info_cb(const char *name, mdb_ctf_id_t id, ulong_t off, void *data)
704 {
705 	mbr_info_t *mbrp = data;
706 
707 	if (strcmp(name, mbrp->mbr_member) == 0) {
708 		if (mbrp->mbr_offp != NULL)
709 			*(mbrp->mbr_offp) = off;
710 		if (mbrp->mbr_typep != NULL)
711 			*(mbrp->mbr_typep) = id;
712 
713 		return (1);
714 	}
715 
716 	return (0);
717 }
718 
719 int
720 mdb_ctf_member_info(mdb_ctf_id_t id, const char *member, ulong_t *offp,
721     mdb_ctf_id_t *typep)
722 {
723 	mbr_info_t mbr;
724 	int rc;
725 
726 	mbr.mbr_member = member;
727 	mbr.mbr_offp = offp;
728 	mbr.mbr_typep = typep;
729 
730 	rc = mdb_ctf_member_iter(id, member_info_cb, &mbr);
731 
732 	/* couldn't get member list */
733 	if (rc == -1)
734 		return (-1); /* errno is set for us */
735 
736 	/* not a member */
737 	if (rc == 0)
738 		return (set_errno(EMDB_CTFNOMEMB));
739 
740 	return (0);
741 }
742 
743 int
744 mdb_ctf_offsetof(mdb_ctf_id_t id, const char *member, ulong_t *retp)
745 {
746 	return (mdb_ctf_member_info(id, member, retp, NULL));
747 }
748 
749 /*ARGSUSED*/
750 static int
751 num_members_cb(const char *name, mdb_ctf_id_t id, ulong_t off, void *data)
752 {
753 	int *count = data;
754 	*count = *count + 1;
755 	return (0);
756 }
757 
758 int
759 mdb_ctf_num_members(mdb_ctf_id_t id)
760 {
761 	int count = 0;
762 
763 	if (mdb_ctf_member_iter(id, num_members_cb, &count) != 0)
764 		return (-1); /* errno is set for us */
765 
766 	return (count);
767 }
768 
769 typedef struct mbr_contains {
770 	char **mbc_bufp;
771 	size_t *mbc_lenp;
772 	ulong_t *mbc_offp;
773 	mdb_ctf_id_t *mbc_idp;
774 	ssize_t mbc_total;
775 } mbr_contains_t;
776 
777 static int
778 offset_to_name_cb(const char *name, mdb_ctf_id_t id, ulong_t off, void *data)
779 {
780 	mbr_contains_t *mbc = data;
781 	ulong_t size;
782 	ctf_encoding_t e;
783 	size_t n;
784 
785 	if (*mbc->mbc_offp < off)
786 		return (0);
787 
788 	if (mdb_ctf_type_encoding(id, &e) == -1)
789 		size = mdb_ctf_type_size(id) * NBBY;
790 	else
791 		size = e.cte_bits;
792 
793 	if (off + size <= *mbc->mbc_offp)
794 		return (0);
795 
796 	n = mdb_snprintf(*mbc->mbc_bufp, *mbc->mbc_lenp, "%s", name);
797 	mbc->mbc_total += n;
798 	if (n > *mbc->mbc_lenp)
799 		n = *mbc->mbc_lenp;
800 
801 	*mbc->mbc_lenp -= n;
802 	*mbc->mbc_bufp += n;
803 
804 	*mbc->mbc_offp -= off;
805 	*mbc->mbc_idp = id;
806 
807 	return (1);
808 }
809 
810 ssize_t
811 mdb_ctf_offset_to_name(mdb_ctf_id_t id, ulong_t off, char *buf, size_t len,
812     int dot, mdb_ctf_id_t *midp, ulong_t *moffp)
813 {
814 	size_t size;
815 	size_t n;
816 	mbr_contains_t mbc;
817 
818 	if (!mdb_ctf_type_valid(id))
819 		return (set_errno(EINVAL));
820 
821 	/*
822 	 * Quick sanity check to make sure the given offset is within
823 	 * this scope of this type.
824 	 */
825 	if (mdb_ctf_type_size(id) * NBBY <= off)
826 		return (set_errno(EINVAL));
827 
828 	mbc.mbc_bufp = &buf;
829 	mbc.mbc_lenp = &len;
830 	mbc.mbc_offp = &off;
831 	mbc.mbc_idp = &id;
832 	mbc.mbc_total = 0;
833 
834 	*buf = '\0';
835 
836 	for (;;) {
837 		/*
838 		 * Check for an exact match.
839 		 */
840 		if (off == 0)
841 			break;
842 
843 		(void) mdb_ctf_type_resolve(id, &id);
844 
845 		/*
846 		 * Find the member that contains this offset.
847 		 */
848 		switch (mdb_ctf_type_kind(id)) {
849 		case CTF_K_ARRAY: {
850 			mdb_ctf_arinfo_t ar;
851 			uint_t index;
852 
853 			(void) mdb_ctf_array_info(id, &ar);
854 			size = mdb_ctf_type_size(ar.mta_contents) * NBBY;
855 			index = off / size;
856 
857 			id = ar.mta_contents;
858 			off %= size;
859 
860 			n = mdb_snprintf(buf, len, "[%u]", index);
861 			mbc.mbc_total += n;
862 			if (n > len)
863 				n = len;
864 
865 			buf += n;
866 			len -= n;
867 			break;
868 		}
869 
870 		case CTF_K_STRUCT: {
871 			int ret;
872 
873 			/*
874 			 * Find the member that contains this offset
875 			 * and continue.
876 			 */
877 
878 			if (dot) {
879 				mbc.mbc_total++;
880 				if (len != 0) {
881 					*buf++ = '.';
882 					*buf = '\0';
883 					len--;
884 				}
885 			}
886 
887 			ret = mdb_ctf_member_iter(id, offset_to_name_cb, &mbc);
888 			if (ret == -1)
889 				return (-1); /* errno is set for us */
890 
891 			/*
892 			 * If we did not find a member containing this offset
893 			 * (due to holes in the structure), return EINVAL.
894 			 */
895 			if (ret == 0)
896 				return (set_errno(EINVAL));
897 
898 			break;
899 		}
900 
901 		case CTF_K_UNION:
902 			/*
903 			 * Treat unions like atomic entities since we can't
904 			 * do more than guess which member of the union
905 			 * might be the intended one.
906 			 */
907 			goto done;
908 
909 		case CTF_K_INTEGER:
910 		case CTF_K_FLOAT:
911 		case CTF_K_POINTER:
912 		case CTF_K_ENUM:
913 			goto done;
914 
915 		default:
916 			return (set_errno(EINVAL));
917 		}
918 
919 		dot = 1;
920 	}
921 done:
922 	if (midp != NULL)
923 		*midp = id;
924 	if (moffp != NULL)
925 		*moffp = off;
926 
927 	return (mbc.mbc_total);
928 }
929 
930 /*
931  * Check if two types are structurally the same rather than logically
932  * the same. That is to say that two types are equal if they have the
933  * same logical structure rather than having the same ids in CTF-land.
934  */
935 static int type_equals(mdb_ctf_id_t, mdb_ctf_id_t);
936 
937 static int
938 type_equals_cb(const char *name, mdb_ctf_id_t amem, ulong_t aoff, void *data)
939 {
940 	mdb_ctf_id_t b = *(mdb_ctf_id_t *)data;
941 	ulong_t boff;
942 	mdb_ctf_id_t bmem;
943 
944 	/*
945 	 * Look up the corresponding member in the other composite type.
946 	 */
947 	if (mdb_ctf_member_info(b, name, &boff, &bmem) != 0)
948 		return (1);
949 
950 	/*
951 	 * We don't allow members to be shuffled around.
952 	 */
953 	if (aoff != boff)
954 		return (1);
955 
956 	return (type_equals(amem, bmem) ? 0 : 1);
957 }
958 
959 static int
960 type_equals(mdb_ctf_id_t a, mdb_ctf_id_t b)
961 {
962 	size_t asz, bsz;
963 	int akind, bkind;
964 	mdb_ctf_arinfo_t aar, bar;
965 
966 	/*
967 	 * Resolve both types down to their fundamental types, and make
968 	 * sure their sizes and kinds match.
969 	 */
970 	if (mdb_ctf_type_resolve(a, &a) != 0 ||
971 	    mdb_ctf_type_resolve(b, &b) != 0 ||
972 	    (asz = mdb_ctf_type_size(a)) == -1UL ||
973 	    (bsz = mdb_ctf_type_size(b)) == -1UL ||
974 	    (akind = mdb_ctf_type_kind(a)) == -1 ||
975 	    (bkind = mdb_ctf_type_kind(b)) == -1 ||
976 	    asz != bsz || akind != bkind) {
977 		return (0);
978 	}
979 
980 	switch (akind) {
981 	case CTF_K_INTEGER:
982 	case CTF_K_FLOAT:
983 	case CTF_K_POINTER:
984 		/*
985 		 * For pointers we could be a little stricter and require
986 		 * both pointers to reference types which look vaguely
987 		 * similar (for example, we could insist that the two types
988 		 * have the same name). However, all we really care about
989 		 * here is that the structure of the two types are the same,
990 		 * and, in that regard, one pointer is as good as another.
991 		 */
992 		return (1);
993 
994 	case CTF_K_UNION:
995 	case CTF_K_STRUCT:
996 		/*
997 		 * The test for the number of members is only strictly
998 		 * necessary for unions since we'll find other problems with
999 		 * structs. However, the extra check will do no harm.
1000 		 */
1001 		return (mdb_ctf_num_members(a) == mdb_ctf_num_members(b) &&
1002 		    mdb_ctf_member_iter(a, type_equals_cb, &b) == 0);
1003 
1004 	case CTF_K_ARRAY:
1005 		return (mdb_ctf_array_info(a, &aar) == 0 &&
1006 		    mdb_ctf_array_info(b, &bar) == 0 &&
1007 		    aar.mta_nelems == bar.mta_nelems &&
1008 		    type_equals(aar.mta_index, bar.mta_index) &&
1009 		    type_equals(aar.mta_contents, bar.mta_contents));
1010 	}
1011 
1012 	return (0);
1013 }
1014 
1015 
1016 typedef struct member {
1017 	char		*m_modbuf;
1018 	char		*m_tgtbuf;
1019 	mdb_ctf_id_t	m_tgtid;
1020 	uint_t		m_flags;
1021 } member_t;
1022 
1023 static int vread_helper(mdb_ctf_id_t, char *, mdb_ctf_id_t, char *, uint_t);
1024 
1025 static int
1026 member_cb(const char *name, mdb_ctf_id_t modmid, ulong_t modoff, void *data)
1027 {
1028 	member_t *mp = data;
1029 	char *modbuf = mp->m_modbuf;
1030 	mdb_ctf_id_t tgtmid;
1031 	char *tgtbuf = mp->m_tgtbuf;
1032 	ulong_t tgtoff;
1033 
1034 	if (mdb_ctf_member_info(mp->m_tgtid, name, &tgtoff, &tgtmid) != 0) {
1035 		if (mp->m_flags & MDB_CTF_VREAD_IGNORE_ABSENT)
1036 			return (0);
1037 		else
1038 			return (set_errno(EMDB_CTFNOMEMB));
1039 	}
1040 
1041 	return (vread_helper(modmid, modbuf + modoff / NBBY,
1042 	    tgtmid, tgtbuf + tgtoff / NBBY, mp->m_flags));
1043 }
1044 
1045 
1046 static int
1047 vread_helper(mdb_ctf_id_t modid, char *modbuf,
1048     mdb_ctf_id_t tgtid, char *tgtbuf, uint_t flags)
1049 {
1050 	size_t modsz, tgtsz;
1051 	int modkind, tgtkind;
1052 	member_t mbr;
1053 	int ret;
1054 	mdb_ctf_arinfo_t tar, mar;
1055 	int i;
1056 
1057 	/*
1058 	 * Resolve the types to their canonical form.
1059 	 */
1060 	(void) mdb_ctf_type_resolve(modid, &modid);
1061 	(void) mdb_ctf_type_resolve(tgtid, &tgtid);
1062 
1063 	if ((modkind = mdb_ctf_type_kind(modid)) == -1)
1064 		return (-1); /* errno is set for us */
1065 	if ((tgtkind = mdb_ctf_type_kind(tgtid)) == -1)
1066 		return (-1); /* errno is set for us */
1067 
1068 	if (tgtkind != modkind)
1069 		return (set_errno(EMDB_INCOMPAT));
1070 
1071 	switch (modkind) {
1072 	case CTF_K_INTEGER:
1073 	case CTF_K_FLOAT:
1074 	case CTF_K_POINTER:
1075 		if ((modsz = mdb_ctf_type_size(modid)) == -1UL)
1076 			return (-1); /* errno is set for us */
1077 
1078 		if ((tgtsz = mdb_ctf_type_size(tgtid)) == -1UL)
1079 			return (-1); /* errno is set for us */
1080 
1081 		/*
1082 		 * If the sizes don't match we need to be tricky to make
1083 		 * sure that the caller gets the correct data.
1084 		 */
1085 		if (modsz < tgtsz) {
1086 			if (!(flags & MDB_CTF_VREAD_IGNORE_GROW))
1087 				return (set_errno(EMDB_INCOMPAT));
1088 #ifdef _BIG_ENDIAN
1089 			bcopy(tgtbuf + tgtsz - modsz, modbuf, modsz);
1090 #else
1091 			bcopy(tgtbuf, modbuf, modsz);
1092 #endif
1093 		} else if (modsz > tgtsz) {
1094 			bzero(modbuf, modsz);
1095 #ifdef _BIG_ENDIAN
1096 			bcopy(tgtbuf, modbuf + modsz - tgtsz, tgtsz);
1097 #else
1098 			bcopy(tgtbuf, modbuf, tgtsz);
1099 #endif
1100 		} else {
1101 			bcopy(tgtbuf, modbuf, modsz);
1102 		}
1103 
1104 		return (0);
1105 
1106 	case CTF_K_STRUCT:
1107 		mbr.m_modbuf = modbuf;
1108 		mbr.m_tgtbuf = tgtbuf;
1109 		mbr.m_tgtid = tgtid;
1110 		mbr.m_flags = flags;
1111 
1112 		return (mdb_ctf_member_iter(modid, member_cb, &mbr));
1113 
1114 	case CTF_K_UNION:
1115 
1116 		/*
1117 		 * Unions are a little tricky. The only time it's truly
1118 		 * safe to read in a union is if no part of the union or
1119 		 * any of its component types have changed. We allow the
1120 		 * consumer to ignore unions. The correct use of this
1121 		 * feature is to read the containing structure, figure
1122 		 * out which component of the union is valid, compute
1123 		 * the location of that in the target and then read in
1124 		 * that part of the structure.
1125 		 */
1126 		if (flags & MDB_CTF_VREAD_IGNORE_UNIONS)
1127 			return (0);
1128 
1129 		if (!type_equals(modid, tgtid))
1130 			return (set_errno(EMDB_INCOMPAT));
1131 
1132 		modsz = mdb_ctf_type_size(modid);
1133 		tgtsz = mdb_ctf_type_size(tgtid);
1134 
1135 		ASSERT(modsz == tgtsz);
1136 
1137 		bcopy(tgtbuf, modbuf, modsz);
1138 
1139 		return (0);
1140 
1141 	case CTF_K_ARRAY:
1142 		if (mdb_ctf_array_info(tgtid, &tar) != 0)
1143 			return (-1); /* errno is set for us */
1144 		if (mdb_ctf_array_info(modid, &mar) != 0)
1145 			return (-1); /* errno is set for us */
1146 
1147 		if (tar.mta_nelems != mar.mta_nelems)
1148 			return (set_errno(EMDB_INCOMPAT));
1149 
1150 		if ((modsz = mdb_ctf_type_size(mar.mta_contents)) == -1UL)
1151 			return (-1); /* errno is set for us */
1152 
1153 		if ((tgtsz = mdb_ctf_type_size(tar.mta_contents)) == -1UL)
1154 			return (-1); /* errno is set for us */
1155 
1156 		for (i = 0; i < tar.mta_nelems; i++) {
1157 			ret = vread_helper(mar.mta_contents, modbuf + i * modsz,
1158 			    tar.mta_contents, tgtbuf + i * tgtsz, flags);
1159 
1160 			if (ret != 0)
1161 				return (ret);
1162 		}
1163 
1164 		return (0);
1165 	}
1166 
1167 	return (set_errno(EMDB_INCOMPAT));
1168 }
1169 
1170 
1171 int
1172 mdb_ctf_vread(void *modbuf, const char *typename, uintptr_t addr, uint_t flags)
1173 {
1174 	ctf_file_t *mfp;
1175 	ctf_id_t mid;
1176 	void *tgtbuf;
1177 	size_t size;
1178 	mdb_ctf_id_t tgtid;
1179 	mdb_ctf_id_t modid;
1180 	mdb_module_t *mod;
1181 
1182 	if ((mod = mdb_get_module()) == NULL || (mfp = mod->mod_ctfp) == NULL)
1183 		return (set_errno(EMDB_NOCTF));
1184 
1185 	if ((mid = ctf_lookup_by_name(mfp, typename)) == CTF_ERR) {
1186 		mdb_dprintf(MDB_DBG_CTF, "couldn't find module's ctf data\n");
1187 		return (set_errno(ctf_to_errno(ctf_errno(mfp))));
1188 	}
1189 
1190 	set_ctf_id(&modid, mfp, mid);
1191 
1192 	if (mdb_ctf_lookup_by_name(typename, &tgtid) != 0) {
1193 		mdb_dprintf(MDB_DBG_CTF, "couldn't find target's ctf data\n");
1194 		return (set_errno(EMDB_NOCTF));
1195 	}
1196 
1197 	/*
1198 	 * Read the data out of the target's address space.
1199 	 */
1200 	if ((size = mdb_ctf_type_size(tgtid)) == -1UL)
1201 		return (-1); /* errno is set for us */
1202 
1203 	tgtbuf = mdb_alloc(size, UM_SLEEP | UM_GC);
1204 
1205 	if (mdb_vread(tgtbuf, size, addr) < 0)
1206 		return (-1); /* errno is set for us */
1207 
1208 	return (vread_helper(modid, modbuf, tgtid, tgtbuf, flags));
1209 }
1210 
1211 int
1212 mdb_ctf_readsym(void *buf, const char *typename, const char *name, uint_t flags)
1213 {
1214 	GElf_Sym sym;
1215 
1216 	if (mdb_lookup_by_name(name, &sym) != 0)
1217 		return (-1); /* errno is set for us */
1218 
1219 	return (mdb_ctf_vread(buf, typename, sym.st_value, flags));
1220 }
1221 
1222 ctf_file_t *
1223 mdb_ctf_bufopen(const void *ctf_va, size_t ctf_size, const void *sym_va,
1224     Shdr *symhdr, const void *str_va, Shdr *strhdr, int *errp)
1225 {
1226 	ctf_sect_t ctdata, symtab, strtab;
1227 
1228 	ctdata.cts_name = ".SUNW_ctf";
1229 	ctdata.cts_type = SHT_PROGBITS;
1230 	ctdata.cts_flags = 0;
1231 	ctdata.cts_data = ctf_va;
1232 	ctdata.cts_size = ctf_size;
1233 	ctdata.cts_entsize = 1;
1234 	ctdata.cts_offset = 0;
1235 
1236 	symtab.cts_name = ".symtab";
1237 	symtab.cts_type = symhdr->sh_type;
1238 	symtab.cts_flags = symhdr->sh_flags;
1239 	symtab.cts_data = sym_va;
1240 	symtab.cts_size = symhdr->sh_size;
1241 	symtab.cts_entsize = symhdr->sh_entsize;
1242 	symtab.cts_offset = symhdr->sh_offset;
1243 
1244 	strtab.cts_name = ".strtab";
1245 	strtab.cts_type = strhdr->sh_type;
1246 	strtab.cts_flags = strhdr->sh_flags;
1247 	strtab.cts_data = str_va;
1248 	strtab.cts_size = strhdr->sh_size;
1249 	strtab.cts_entsize = strhdr->sh_entsize;
1250 	strtab.cts_offset = strhdr->sh_offset;
1251 
1252 	return (ctf_bufopen(&ctdata, &symtab, &strtab, errp));
1253 }
1254