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