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
set_ctf_id(mdb_ctf_id_t * p,ctf_file_t * fp,ctf_id_t id)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
obj_lookup(void * data,const mdb_map_t * mp,const char * name)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 *
name_to_type(mdb_tgt_t * t,const char * cname,ctf_id_t * idp)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
mdb_ctf_enabled_by_object(const char * object)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
mdb_ctf_lookup_by_name(const char * name,mdb_ctf_id_t * p)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
mdb_ctf_lookup_by_symbol(const GElf_Sym * symp,const mdb_syminfo_t * sip,mdb_ctf_id_t * p)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
mdb_ctf_lookup_by_addr(uintptr_t addr,mdb_ctf_id_t * p)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
mdb_ctf_module_lookup(const char * name,mdb_ctf_id_t * p)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
mdb_ctf_func_info(const GElf_Sym * symp,const mdb_syminfo_t * sip,mdb_ctf_funcinfo_t * mfp)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
mdb_ctf_func_args(const mdb_ctf_funcinfo_t * funcp,uint_t len,mdb_ctf_id_t * argv)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
mdb_ctf_type_invalidate(mdb_ctf_id_t * idp)373 mdb_ctf_type_invalidate(mdb_ctf_id_t *idp)
374 {
375 set_ctf_id(idp, NULL, CTF_ERR);
376 }
377
378 int
mdb_ctf_type_valid(mdb_ctf_id_t id)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
mdb_ctf_type_cmp(mdb_ctf_id_t aid,mdb_ctf_id_t bid)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
mdb_ctf_type_resolve(mdb_ctf_id_t mid,mdb_ctf_id_t * outp)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 *)∣
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 *
mdb_ctf_type_name(mdb_ctf_id_t id,char * buf,size_t len)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
mdb_ctf_type_size(mdb_ctf_id_t id)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
mdb_ctf_type_kind(mdb_ctf_id_t id)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
mdb_ctf_type_reference(mdb_ctf_id_t mid,mdb_ctf_id_t * outp)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 *)∣
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
mdb_ctf_type_encoding(mdb_ctf_id_t id,ctf_encoding_t * ep)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
type_cb(const char * name,ctf_id_t type,ulong_t off,int depth,void * arg)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
mdb_ctf_type_visit(mdb_ctf_id_t id,mdb_ctf_visit_f * func,void * arg)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
mdb_ctf_array_info(mdb_ctf_id_t id,mdb_ctf_arinfo_t * arp)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 *
mdb_ctf_enum_name(mdb_ctf_id_t id,int value)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
member_iter_cb(const char * name,ctf_id_t type,ulong_t off,void * data)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
mdb_ctf_member_iter(mdb_ctf_id_t id,mdb_ctf_member_f * cb,void * data)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
mdb_ctf_enum_iter(mdb_ctf_id_t id,mdb_ctf_enum_f * cb,void * data)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
type_iter_cb(ctf_id_t type,void * data)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
mdb_ctf_type_iter(const char * object,mdb_ctf_type_f * cb,void * data)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
mdb_ctf_type_id(mdb_ctf_id_t id)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 *
mdb_ctf_type_file(mdb_ctf_id_t id)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
member_info_cb(const char * name,mdb_ctf_id_t id,ulong_t off,void * data)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
mdb_ctf_member_info(mdb_ctf_id_t id,const char * member,ulong_t * offp,mdb_ctf_id_t * typep)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
mdb_ctf_offsetof(mdb_ctf_id_t id,const char * member,ulong_t * retp)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
num_members_cb(const char * name,mdb_ctf_id_t id,ulong_t off,void * data)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
mdb_ctf_num_members(mdb_ctf_id_t id)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
offset_to_name_cb(const char * name,mdb_ctf_id_t id,ulong_t off,void * data)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
mdb_ctf_offset_to_name(mdb_ctf_id_t id,ulong_t off,char * buf,size_t len,int dot,mdb_ctf_id_t * midp,ulong_t * moffp)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
type_equals_cb(const char * name,mdb_ctf_id_t amem,ulong_t aoff,void * data)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
type_equals(mdb_ctf_id_t a,mdb_ctf_id_t b)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
member_cb(const char * name,mdb_ctf_id_t modmid,ulong_t modoff,void * data)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
vread_helper(mdb_ctf_id_t modid,char * modbuf,mdb_ctf_id_t tgtid,char * tgtbuf,uint_t flags)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
mdb_ctf_vread(void * modbuf,const char * typename,uintptr_t addr,uint_t flags)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
mdb_ctf_readsym(void * buf,const char * typename,const char * name,uint_t flags)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 *
mdb_ctf_bufopen(const void * ctf_va,size_t ctf_size,const void * sym_va,Shdr * symhdr,const void * str_va,Shdr * strhdr,int * errp)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