xref: /illumos-gate/usr/src/cmd/mdb/common/mdb/mdb_ctf.c (revision cce402975996597dc49946237271dffe2b698148)
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 	if ((ret = ctf_type_size(idp->mci_fp, idp->mci_id)) == CTF_ERR)
450 		return (set_errno(ctf_to_errno(ctf_errno(idp->mci_fp))));
451 
452 	return (ret);
453 }
454 
455 int
456 mdb_ctf_type_kind(mdb_ctf_id_t id)
457 {
458 	mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&id;
459 	int ret;
460 
461 	if ((ret = ctf_type_kind(idp->mci_fp, idp->mci_id)) == CTF_ERR)
462 		return (set_errno(ctf_to_errno(ctf_errno(idp->mci_fp))));
463 
464 	return (ret);
465 }
466 
467 int
468 mdb_ctf_type_reference(mdb_ctf_id_t mid, mdb_ctf_id_t *outp)
469 {
470 	mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&mid;
471 	ctf_id_t id;
472 
473 	if ((id = ctf_type_reference(idp->mci_fp, idp->mci_id)) == CTF_ERR) {
474 		if (outp)
475 			mdb_ctf_type_invalidate(outp);
476 		return (set_errno(ctf_to_errno(ctf_errno(idp->mci_fp))));
477 	}
478 
479 	if (outp != NULL)
480 		set_ctf_id(outp, idp->mci_fp, id);
481 
482 	return (0);
483 }
484 
485 
486 int
487 mdb_ctf_type_encoding(mdb_ctf_id_t id, ctf_encoding_t *ep)
488 {
489 	mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&id;
490 
491 	if (ctf_type_encoding(idp->mci_fp, idp->mci_id, ep) == CTF_ERR)
492 		return (set_errno(ctf_to_errno(ctf_errno(idp->mci_fp))));
493 
494 	return (0);
495 }
496 
497 /*
498  * callback proxy for mdb_ctf_type_visit
499  */
500 static int
501 type_cb(const char *name, ctf_id_t type, ulong_t off, int depth, void *arg)
502 {
503 	type_visit_t *tvp = arg;
504 	mdb_ctf_id_t id;
505 	mdb_ctf_id_t base;
506 	mdb_ctf_impl_t *basep = (mdb_ctf_impl_t *)&base;
507 
508 	int ret;
509 
510 	if (depth < tvp->tv_min_depth)
511 		return (0);
512 
513 	off += tvp->tv_base_offset;
514 	depth += tvp->tv_base_depth;
515 
516 	set_ctf_id(&id, tvp->tv_fp, type);
517 
518 	(void) mdb_ctf_type_resolve(id, &base);
519 	if ((ret = tvp->tv_cb(name, id, base, off, depth, tvp->tv_arg)) != 0)
520 		return (ret);
521 
522 	/*
523 	 * If the type resolves to a type in a different file, we must have
524 	 * followed a forward declaration.  We need to recurse into the
525 	 * new type.
526 	 */
527 	if (basep->mci_fp != tvp->tv_fp && mdb_ctf_type_valid(base)) {
528 		type_visit_t tv;
529 
530 		tv.tv_cb = tvp->tv_cb;
531 		tv.tv_arg = tvp->tv_arg;
532 		tv.tv_fp = basep->mci_fp;
533 
534 		tv.tv_base_offset = off;
535 		tv.tv_base_depth = depth;
536 		tv.tv_min_depth = 1;	/* depth = 0 has already been done */
537 
538 		ret = ctf_type_visit(basep->mci_fp, basep->mci_id,
539 		    type_cb, &tv);
540 	}
541 	return (ret);
542 }
543 
544 int
545 mdb_ctf_type_visit(mdb_ctf_id_t id, mdb_ctf_visit_f *func, void *arg)
546 {
547 	mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&id;
548 	type_visit_t tv;
549 	int ret;
550 
551 	tv.tv_cb = func;
552 	tv.tv_arg = arg;
553 	tv.tv_fp = idp->mci_fp;
554 	tv.tv_base_offset = 0;
555 	tv.tv_base_depth = 0;
556 	tv.tv_min_depth = 0;
557 
558 	ret = ctf_type_visit(idp->mci_fp, idp->mci_id, type_cb, &tv);
559 
560 	if (ret == CTF_ERR)
561 		return (set_errno(ctf_to_errno(ctf_errno(idp->mci_fp))));
562 
563 	return (ret);
564 }
565 
566 int
567 mdb_ctf_array_info(mdb_ctf_id_t id, mdb_ctf_arinfo_t *arp)
568 {
569 	mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&id;
570 	ctf_arinfo_t car;
571 
572 	if (ctf_array_info(idp->mci_fp, idp->mci_id, &car) == CTF_ERR)
573 		return (set_errno(ctf_to_errno(ctf_errno(idp->mci_fp))));
574 
575 	set_ctf_id(&arp->mta_contents, idp->mci_fp, car.ctr_contents);
576 	set_ctf_id(&arp->mta_index, idp->mci_fp, car.ctr_index);
577 
578 	arp->mta_nelems = car.ctr_nelems;
579 
580 	return (0);
581 }
582 
583 const char *
584 mdb_ctf_enum_name(mdb_ctf_id_t id, int value)
585 {
586 	mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&id;
587 	const char *ret;
588 
589 	if ((ret = ctf_enum_name(idp->mci_fp, idp->mci_id, value)) == NULL)
590 		(void) set_errno(ctf_to_errno(ctf_errno(idp->mci_fp)));
591 
592 	return (ret);
593 }
594 
595 /*
596  * callback proxy for mdb_ctf_member_iter
597  */
598 static int
599 member_iter_cb(const char *name, ctf_id_t type, ulong_t off, void *data)
600 {
601 	member_iter_t *mip = data;
602 	mdb_ctf_id_t id;
603 
604 	set_ctf_id(&id, mip->mi_fp, type);
605 
606 	return (mip->mi_cb(name, id, off, mip->mi_arg));
607 }
608 
609 int
610 mdb_ctf_member_iter(mdb_ctf_id_t id, mdb_ctf_member_f *cb, void *data)
611 {
612 	mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&id;
613 	member_iter_t mi;
614 	int ret;
615 
616 	mi.mi_cb = cb;
617 	mi.mi_arg = data;
618 	mi.mi_fp = idp->mci_fp;
619 
620 	ret = ctf_member_iter(idp->mci_fp, idp->mci_id, member_iter_cb, &mi);
621 
622 	if (ret == CTF_ERR)
623 		return (set_errno(ctf_to_errno(ctf_errno(idp->mci_fp))));
624 
625 	return (ret);
626 }
627 
628 int
629 mdb_ctf_enum_iter(mdb_ctf_id_t id, mdb_ctf_enum_f *cb, void *data)
630 {
631 	mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&id;
632 
633 	return (ctf_enum_iter(idp->mci_fp, idp->mci_id, cb, data));
634 }
635 
636 /*
637  * callback proxy for mdb_ctf_type_iter
638  */
639 static int
640 type_iter_cb(ctf_id_t type, void *data)
641 {
642 	type_iter_t *tip = data;
643 	mdb_ctf_id_t id;
644 
645 	set_ctf_id(&id, tip->ti_fp, type);
646 
647 	return (tip->ti_cb(id, tip->ti_arg));
648 }
649 
650 int
651 mdb_ctf_type_iter(const char *object, mdb_ctf_type_f *cb, void *data)
652 {
653 	ctf_file_t *fp;
654 	mdb_tgt_t *t = mdb.m_target;
655 	int ret;
656 	type_iter_t ti;
657 
658 	if ((fp = mdb_tgt_name_to_ctf(t, object)) == NULL)
659 		return (-1);
660 
661 	ti.ti_cb = cb;
662 	ti.ti_arg = data;
663 	ti.ti_fp = fp;
664 
665 	if ((ret = ctf_type_iter(fp, type_iter_cb, &ti)) == CTF_ERR)
666 		return (set_errno(ctf_to_errno(ctf_errno(fp))));
667 
668 	return (ret);
669 }
670 
671 /* utility functions */
672 
673 ctf_id_t
674 mdb_ctf_type_id(mdb_ctf_id_t id)
675 {
676 	return (((mdb_ctf_impl_t *)&id)->mci_id);
677 }
678 
679 ctf_file_t *
680 mdb_ctf_type_file(mdb_ctf_id_t id)
681 {
682 	return (((mdb_ctf_impl_t *)&id)->mci_fp);
683 }
684 
685 static int
686 member_info_cb(const char *name, mdb_ctf_id_t id, ulong_t off, void *data)
687 {
688 	mbr_info_t *mbrp = data;
689 
690 	if (strcmp(name, mbrp->mbr_member) == 0) {
691 		if (mbrp->mbr_offp != NULL)
692 			*(mbrp->mbr_offp) = off;
693 		if (mbrp->mbr_typep != NULL)
694 			*(mbrp->mbr_typep) = id;
695 
696 		return (1);
697 	}
698 
699 	return (0);
700 }
701 
702 int
703 mdb_ctf_member_info(mdb_ctf_id_t id, const char *member, ulong_t *offp,
704     mdb_ctf_id_t *typep)
705 {
706 	mbr_info_t mbr;
707 	int rc;
708 
709 	mbr.mbr_member = member;
710 	mbr.mbr_offp = offp;
711 	mbr.mbr_typep = typep;
712 
713 	rc = mdb_ctf_member_iter(id, member_info_cb, &mbr);
714 
715 	/* couldn't get member list */
716 	if (rc == -1)
717 		return (-1); /* errno is set for us */
718 
719 	/* not a member */
720 	if (rc == 0)
721 		return (set_errno(EMDB_CTFNOMEMB));
722 
723 	return (0);
724 }
725 
726 int
727 mdb_ctf_offsetof(mdb_ctf_id_t id, const char *member, ulong_t *retp)
728 {
729 	return (mdb_ctf_member_info(id, member, retp, NULL));
730 }
731 
732 /*ARGSUSED*/
733 static int
734 num_members_cb(const char *name, mdb_ctf_id_t id, ulong_t off, void *data)
735 {
736 	int *count = data;
737 	*count = *count + 1;
738 	return (0);
739 }
740 
741 int
742 mdb_ctf_num_members(mdb_ctf_id_t id)
743 {
744 	int count = 0;
745 
746 	if (mdb_ctf_member_iter(id, num_members_cb, &count) != 0)
747 		return (-1); /* errno is set for us */
748 
749 	return (count);
750 }
751 
752 typedef struct mbr_contains {
753 	char **mbc_bufp;
754 	size_t *mbc_lenp;
755 	ulong_t *mbc_offp;
756 	mdb_ctf_id_t *mbc_idp;
757 	ssize_t mbc_total;
758 } mbr_contains_t;
759 
760 static int
761 offset_to_name_cb(const char *name, mdb_ctf_id_t id, ulong_t off, void *data)
762 {
763 	mbr_contains_t *mbc = data;
764 	ulong_t size;
765 	ctf_encoding_t e;
766 	size_t n;
767 
768 	if (*mbc->mbc_offp < off)
769 		return (0);
770 
771 	if (mdb_ctf_type_encoding(id, &e) == -1)
772 		size = mdb_ctf_type_size(id) * NBBY;
773 	else
774 		size = e.cte_bits;
775 
776 	if (off + size <= *mbc->mbc_offp)
777 		return (0);
778 
779 	n = mdb_snprintf(*mbc->mbc_bufp, *mbc->mbc_lenp, "%s", name);
780 	mbc->mbc_total += n;
781 	if (n > *mbc->mbc_lenp)
782 		n = *mbc->mbc_lenp;
783 
784 	*mbc->mbc_lenp -= n;
785 	*mbc->mbc_bufp += n;
786 
787 	*mbc->mbc_offp -= off;
788 	*mbc->mbc_idp = id;
789 
790 	return (1);
791 }
792 
793 ssize_t
794 mdb_ctf_offset_to_name(mdb_ctf_id_t id, ulong_t off, char *buf, size_t len,
795     int dot, mdb_ctf_id_t *midp, ulong_t *moffp)
796 {
797 	size_t size;
798 	size_t n;
799 	mbr_contains_t mbc;
800 
801 	if (!mdb_ctf_type_valid(id))
802 		return (set_errno(EINVAL));
803 
804 	/*
805 	 * Quick sanity check to make sure the given offset is within
806 	 * this scope of this type.
807 	 */
808 	if (mdb_ctf_type_size(id) * NBBY <= off)
809 		return (set_errno(EINVAL));
810 
811 	mbc.mbc_bufp = &buf;
812 	mbc.mbc_lenp = &len;
813 	mbc.mbc_offp = &off;
814 	mbc.mbc_idp = &id;
815 	mbc.mbc_total = 0;
816 
817 	*buf = '\0';
818 
819 	for (;;) {
820 		/*
821 		 * Check for an exact match.
822 		 */
823 		if (off == 0)
824 			break;
825 
826 		(void) mdb_ctf_type_resolve(id, &id);
827 
828 		/*
829 		 * Find the member that contains this offset.
830 		 */
831 		switch (mdb_ctf_type_kind(id)) {
832 		case CTF_K_ARRAY: {
833 			mdb_ctf_arinfo_t ar;
834 			uint_t index;
835 
836 			(void) mdb_ctf_array_info(id, &ar);
837 			size = mdb_ctf_type_size(ar.mta_contents) * NBBY;
838 			index = off / size;
839 
840 			id = ar.mta_contents;
841 			off %= size;
842 
843 			n = mdb_snprintf(buf, len, "[%u]", index);
844 			mbc.mbc_total += n;
845 			if (n > len)
846 				n = len;
847 
848 			buf += n;
849 			len -= n;
850 			break;
851 		}
852 
853 		case CTF_K_STRUCT: {
854 			int ret;
855 
856 			/*
857 			 * Find the member that contains this offset
858 			 * and continue.
859 			 */
860 
861 			if (dot) {
862 				mbc.mbc_total++;
863 				if (len != 0) {
864 					*buf++ = '.';
865 					*buf = '\0';
866 					len--;
867 				}
868 			}
869 
870 			ret = mdb_ctf_member_iter(id, offset_to_name_cb, &mbc);
871 			if (ret == -1)
872 				return (-1); /* errno is set for us */
873 
874 			/*
875 			 * If we did not find a member containing this offset
876 			 * (due to holes in the structure), return EINVAL.
877 			 */
878 			if (ret == 0)
879 				return (set_errno(EINVAL));
880 
881 			break;
882 		}
883 
884 		case CTF_K_UNION:
885 			/*
886 			 * Treat unions like atomic entities since we can't
887 			 * do more than guess which member of the union
888 			 * might be the intended one.
889 			 */
890 			goto done;
891 
892 		case CTF_K_INTEGER:
893 		case CTF_K_FLOAT:
894 		case CTF_K_POINTER:
895 		case CTF_K_ENUM:
896 			goto done;
897 
898 		default:
899 			return (set_errno(EINVAL));
900 		}
901 
902 		dot = 1;
903 	}
904 done:
905 	if (midp != NULL)
906 		*midp = id;
907 	if (moffp != NULL)
908 		*moffp = off;
909 
910 	return (mbc.mbc_total);
911 }
912 
913 /*
914  * Check if two types are structurally the same rather than logically
915  * the same. That is to say that two types are equal if they have the
916  * same logical structure rather than having the same ids in CTF-land.
917  */
918 static int type_equals(mdb_ctf_id_t, mdb_ctf_id_t);
919 
920 static int
921 type_equals_cb(const char *name, mdb_ctf_id_t amem, ulong_t aoff, void *data)
922 {
923 	mdb_ctf_id_t b = *(mdb_ctf_id_t *)data;
924 	ulong_t boff;
925 	mdb_ctf_id_t bmem;
926 
927 	/*
928 	 * Look up the corresponding member in the other composite type.
929 	 */
930 	if (mdb_ctf_member_info(b, name, &boff, &bmem) != 0)
931 		return (1);
932 
933 	/*
934 	 * We don't allow members to be shuffled around.
935 	 */
936 	if (aoff != boff)
937 		return (1);
938 
939 	return (type_equals(amem, bmem) ? 0 : 1);
940 }
941 
942 static int
943 type_equals(mdb_ctf_id_t a, mdb_ctf_id_t b)
944 {
945 	size_t asz, bsz;
946 	int akind, bkind;
947 	mdb_ctf_arinfo_t aar, bar;
948 
949 	/*
950 	 * Resolve both types down to their fundamental types, and make
951 	 * sure their sizes and kinds match.
952 	 */
953 	if (mdb_ctf_type_resolve(a, &a) != 0 ||
954 	    mdb_ctf_type_resolve(b, &b) != 0 ||
955 	    (asz = mdb_ctf_type_size(a)) == -1UL ||
956 	    (bsz = mdb_ctf_type_size(b)) == -1UL ||
957 	    (akind = mdb_ctf_type_kind(a)) == -1 ||
958 	    (bkind = mdb_ctf_type_kind(b)) == -1 ||
959 	    asz != bsz || akind != bkind) {
960 		return (0);
961 	}
962 
963 	switch (akind) {
964 	case CTF_K_INTEGER:
965 	case CTF_K_FLOAT:
966 	case CTF_K_POINTER:
967 		/*
968 		 * For pointers we could be a little stricter and require
969 		 * both pointers to reference types which look vaguely
970 		 * similar (for example, we could insist that the two types
971 		 * have the same name). However, all we really care about
972 		 * here is that the structure of the two types are the same,
973 		 * and, in that regard, one pointer is as good as another.
974 		 */
975 		return (1);
976 
977 	case CTF_K_UNION:
978 	case CTF_K_STRUCT:
979 		/*
980 		 * The test for the number of members is only strictly
981 		 * necessary for unions since we'll find other problems with
982 		 * structs. However, the extra check will do no harm.
983 		 */
984 		return (mdb_ctf_num_members(a) == mdb_ctf_num_members(b) &&
985 		    mdb_ctf_member_iter(a, type_equals_cb, &b) == 0);
986 
987 	case CTF_K_ARRAY:
988 		return (mdb_ctf_array_info(a, &aar) == 0 &&
989 		    mdb_ctf_array_info(b, &bar) == 0 &&
990 		    aar.mta_nelems == bar.mta_nelems &&
991 		    type_equals(aar.mta_index, bar.mta_index) &&
992 		    type_equals(aar.mta_contents, bar.mta_contents));
993 	}
994 
995 	return (0);
996 }
997 
998 
999 typedef struct member {
1000 	char		*m_modbuf;
1001 	char		*m_tgtbuf;
1002 	mdb_ctf_id_t	m_tgtid;
1003 	uint_t		m_flags;
1004 } member_t;
1005 
1006 static int vread_helper(mdb_ctf_id_t, char *, mdb_ctf_id_t, char *, uint_t);
1007 
1008 static int
1009 member_cb(const char *name, mdb_ctf_id_t modmid, ulong_t modoff, void *data)
1010 {
1011 	member_t *mp = data;
1012 	char *modbuf = mp->m_modbuf;
1013 	mdb_ctf_id_t tgtmid;
1014 	char *tgtbuf = mp->m_tgtbuf;
1015 	ulong_t tgtoff;
1016 
1017 	if (mdb_ctf_member_info(mp->m_tgtid, name, &tgtoff, &tgtmid) != 0) {
1018 		if (mp->m_flags & MDB_CTF_VREAD_IGNORE_ABSENT)
1019 			return (0);
1020 		else
1021 			return (set_errno(EMDB_CTFNOMEMB));
1022 	}
1023 
1024 	return (vread_helper(modmid, modbuf + modoff / NBBY,
1025 	    tgtmid, tgtbuf + tgtoff / NBBY, mp->m_flags));
1026 }
1027 
1028 
1029 static int
1030 vread_helper(mdb_ctf_id_t modid, char *modbuf,
1031     mdb_ctf_id_t tgtid, char *tgtbuf, uint_t flags)
1032 {
1033 	size_t modsz, tgtsz;
1034 	int modkind, tgtkind;
1035 	member_t mbr;
1036 	int ret;
1037 	mdb_ctf_arinfo_t tar, mar;
1038 	int i;
1039 
1040 	/*
1041 	 * Resolve the types to their canonical form.
1042 	 */
1043 	(void) mdb_ctf_type_resolve(modid, &modid);
1044 	(void) mdb_ctf_type_resolve(tgtid, &tgtid);
1045 
1046 	if ((modkind = mdb_ctf_type_kind(modid)) == -1)
1047 		return (-1); /* errno is set for us */
1048 	if ((tgtkind = mdb_ctf_type_kind(tgtid)) == -1)
1049 		return (-1); /* errno is set for us */
1050 
1051 	if (tgtkind != modkind)
1052 		return (set_errno(EMDB_INCOMPAT));
1053 
1054 	switch (modkind) {
1055 	case CTF_K_INTEGER:
1056 	case CTF_K_FLOAT:
1057 	case CTF_K_POINTER:
1058 		if ((modsz = mdb_ctf_type_size(modid)) == -1UL)
1059 			return (-1); /* errno is set for us */
1060 
1061 		if ((tgtsz = mdb_ctf_type_size(tgtid)) == -1UL)
1062 			return (-1); /* errno is set for us */
1063 
1064 		/*
1065 		 * If the sizes don't match we need to be tricky to make
1066 		 * sure that the caller gets the correct data.
1067 		 */
1068 		if (modsz < tgtsz) {
1069 			if (!(flags & MDB_CTF_VREAD_IGNORE_GROW))
1070 				return (set_errno(EMDB_INCOMPAT));
1071 #ifdef _BIG_ENDIAN
1072 			bcopy(tgtbuf + tgtsz - modsz, modbuf, modsz);
1073 #else
1074 			bcopy(tgtbuf, modbuf, modsz);
1075 #endif
1076 		} else if (modsz > tgtsz) {
1077 			bzero(modbuf, modsz);
1078 #ifdef _BIG_ENDIAN
1079 			bcopy(tgtbuf, modbuf + modsz - tgtsz, tgtsz);
1080 #else
1081 			bcopy(tgtbuf, modbuf, tgtsz);
1082 #endif
1083 		} else {
1084 			bcopy(tgtbuf, modbuf, modsz);
1085 		}
1086 
1087 		return (0);
1088 
1089 	case CTF_K_STRUCT:
1090 		mbr.m_modbuf = modbuf;
1091 		mbr.m_tgtbuf = tgtbuf;
1092 		mbr.m_tgtid = tgtid;
1093 		mbr.m_flags = flags;
1094 
1095 		return (mdb_ctf_member_iter(modid, member_cb, &mbr));
1096 
1097 	case CTF_K_UNION:
1098 
1099 		/*
1100 		 * Unions are a little tricky. The only time it's truly
1101 		 * safe to read in a union is if no part of the union or
1102 		 * any of its component types have changed. We allow the
1103 		 * consumer to ignore unions. The correct use of this
1104 		 * feature is to read the containing structure, figure
1105 		 * out which component of the union is valid, compute
1106 		 * the location of that in the target and then read in
1107 		 * that part of the structure.
1108 		 */
1109 		if (flags & MDB_CTF_VREAD_IGNORE_UNIONS)
1110 			return (0);
1111 
1112 		if (!type_equals(modid, tgtid))
1113 			return (set_errno(EMDB_INCOMPAT));
1114 
1115 		modsz = mdb_ctf_type_size(modid);
1116 		tgtsz = mdb_ctf_type_size(tgtid);
1117 
1118 		ASSERT(modsz == tgtsz);
1119 
1120 		bcopy(tgtbuf, modbuf, modsz);
1121 
1122 		return (0);
1123 
1124 	case CTF_K_ARRAY:
1125 		if (mdb_ctf_array_info(tgtid, &tar) != 0)
1126 			return (-1); /* errno is set for us */
1127 		if (mdb_ctf_array_info(modid, &mar) != 0)
1128 			return (-1); /* errno is set for us */
1129 
1130 		if (tar.mta_nelems != mar.mta_nelems)
1131 			return (set_errno(EMDB_INCOMPAT));
1132 
1133 		if ((modsz = mdb_ctf_type_size(mar.mta_contents)) == -1UL)
1134 			return (-1); /* errno is set for us */
1135 
1136 		if ((tgtsz = mdb_ctf_type_size(tar.mta_contents)) == -1UL)
1137 			return (-1); /* errno is set for us */
1138 
1139 		for (i = 0; i < tar.mta_nelems; i++) {
1140 			ret = vread_helper(mar.mta_contents, modbuf + i * modsz,
1141 			    tar.mta_contents, tgtbuf + i * tgtsz, flags);
1142 
1143 			if (ret != 0)
1144 				return (ret);
1145 		}
1146 
1147 		return (0);
1148 	}
1149 
1150 	return (set_errno(EMDB_INCOMPAT));
1151 }
1152 
1153 
1154 int
1155 mdb_ctf_vread(void *modbuf, const char *typename, uintptr_t addr, uint_t flags)
1156 {
1157 	ctf_file_t *mfp;
1158 	ctf_id_t mid;
1159 	void *tgtbuf;
1160 	size_t size;
1161 	mdb_ctf_id_t tgtid;
1162 	mdb_ctf_id_t modid;
1163 	mdb_module_t *mod;
1164 
1165 	if ((mod = mdb_get_module()) == NULL || (mfp = mod->mod_ctfp) == NULL)
1166 		return (set_errno(EMDB_NOCTF));
1167 
1168 	if ((mid = ctf_lookup_by_name(mfp, typename)) == CTF_ERR) {
1169 		mdb_dprintf(MDB_DBG_CTF, "couldn't find module's ctf data\n");
1170 		return (set_errno(ctf_to_errno(ctf_errno(mfp))));
1171 	}
1172 
1173 	set_ctf_id(&modid, mfp, mid);
1174 
1175 	if (mdb_ctf_lookup_by_name(typename, &tgtid) != 0) {
1176 		mdb_dprintf(MDB_DBG_CTF, "couldn't find target's ctf data\n");
1177 		return (set_errno(EMDB_NOCTF));
1178 	}
1179 
1180 	/*
1181 	 * Read the data out of the target's address space.
1182 	 */
1183 	if ((size = mdb_ctf_type_size(tgtid)) == -1UL)
1184 		return (-1); /* errno is set for us */
1185 
1186 	tgtbuf = mdb_alloc(size, UM_SLEEP | UM_GC);
1187 
1188 	if (mdb_vread(tgtbuf, size, addr) < 0)
1189 		return (-1); /* errno is set for us */
1190 
1191 	return (vread_helper(modid, modbuf, tgtid, tgtbuf, flags));
1192 }
1193 
1194 int
1195 mdb_ctf_readsym(void *buf, const char *typename, const char *name, uint_t flags)
1196 {
1197 	GElf_Sym sym;
1198 
1199 	if (mdb_lookup_by_name(name, &sym) != 0)
1200 		return (-1); /* errno is set for us */
1201 
1202 	return (mdb_ctf_vread(buf, typename, sym.st_value, flags));
1203 }
1204 
1205 ctf_file_t *
1206 mdb_ctf_bufopen(const void *ctf_va, size_t ctf_size, const void *sym_va,
1207     Shdr *symhdr, const void *str_va, Shdr *strhdr, int *errp)
1208 {
1209 	ctf_sect_t ctdata, symtab, strtab;
1210 
1211 	ctdata.cts_name = ".SUNW_ctf";
1212 	ctdata.cts_type = SHT_PROGBITS;
1213 	ctdata.cts_flags = 0;
1214 	ctdata.cts_data = ctf_va;
1215 	ctdata.cts_size = ctf_size;
1216 	ctdata.cts_entsize = 1;
1217 	ctdata.cts_offset = 0;
1218 
1219 	symtab.cts_name = ".symtab";
1220 	symtab.cts_type = symhdr->sh_type;
1221 	symtab.cts_flags = symhdr->sh_flags;
1222 	symtab.cts_data = sym_va;
1223 	symtab.cts_size = symhdr->sh_size;
1224 	symtab.cts_entsize = symhdr->sh_entsize;
1225 	symtab.cts_offset = symhdr->sh_offset;
1226 
1227 	strtab.cts_name = ".strtab";
1228 	strtab.cts_type = strhdr->sh_type;
1229 	strtab.cts_flags = strhdr->sh_flags;
1230 	strtab.cts_data = str_va;
1231 	strtab.cts_size = strhdr->sh_size;
1232 	strtab.cts_entsize = strhdr->sh_entsize;
1233 	strtab.cts_offset = strhdr->sh_offset;
1234 
1235 	return (ctf_bufopen(&ctdata, &symtab, &strtab, errp));
1236 }
1237