1*0f9855f7Smpi /* $OpenBSD: ctfconv.c,v 1.20 2022/10/02 11:56:43 mpi Exp $ */
20687c322Sjasper
3192095f7Smpi /*
4192095f7Smpi * Copyright (c) 2016-2017 Martin Pieuchot
5192095f7Smpi *
6192095f7Smpi * Permission to use, copy, modify, and distribute this software for any
7192095f7Smpi * purpose with or without fee is hereby granted, provided that the above
8192095f7Smpi * copyright notice and this permission notice appear in all copies.
9192095f7Smpi *
10192095f7Smpi * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11192095f7Smpi * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12192095f7Smpi * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13192095f7Smpi * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14192095f7Smpi * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15192095f7Smpi * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16192095f7Smpi * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17192095f7Smpi */
18192095f7Smpi
19192095f7Smpi #include <sys/types.h>
20192095f7Smpi #include <sys/stat.h>
21192095f7Smpi #include <sys/mman.h>
22192095f7Smpi #include <sys/queue.h>
23192095f7Smpi #include <sys/tree.h>
24192095f7Smpi #include <sys/ctf.h>
25192095f7Smpi
26192095f7Smpi #include <assert.h>
27e4b342e5Smpi #include <elf.h>
28192095f7Smpi #include <err.h>
29192095f7Smpi #include <fcntl.h>
3008b0026dSmpi #include <limits.h>
31192095f7Smpi #include <locale.h>
32192095f7Smpi #include <stdio.h>
33192095f7Smpi #include <stdint.h>
34192095f7Smpi #include <stdlib.h>
35192095f7Smpi #include <string.h>
36192095f7Smpi #include <unistd.h>
37192095f7Smpi
38192095f7Smpi #include "itype.h"
39192095f7Smpi #include "xmalloc.h"
40192095f7Smpi
41192095f7Smpi #ifndef nitems
42192095f7Smpi #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
43192095f7Smpi #endif
44192095f7Smpi
45192095f7Smpi #define DEBUG_ABBREV ".debug_abbrev"
46192095f7Smpi #define DEBUG_INFO ".debug_info"
47192095f7Smpi #define DEBUG_STR ".debug_str"
48192095f7Smpi
49192095f7Smpi __dead void usage(void);
50192095f7Smpi int convert(const char *);
51192095f7Smpi int generate(const char *, const char *, int);
52192095f7Smpi int elf_convert(char *, size_t);
53192095f7Smpi void elf_sort(void);
5408b0026dSmpi char *guess_static_local_name(char *);
55589f0bfaSmpi struct itype *find_symb(struct itype *, size_t);
56192095f7Smpi void dump_type(struct itype *);
57192095f7Smpi void dump_func(struct itype *, int *);
58192095f7Smpi void dump_obj(struct itype *, int *);
59192095f7Smpi
60192095f7Smpi /* elf.c */
61192095f7Smpi int iself(const char *, size_t);
62192095f7Smpi int elf_getshstab(const char *, size_t, const char **, size_t *);
63be9aadfaSjsg ssize_t elf_getsymtab(const char *, size_t, const char *, size_t,
64622b7392Smpi const Elf_Sym **, size_t *, const char **, size_t *);
6559153d10Sjsg ssize_t elf_getsection(char *, size_t, const char *, const char *,
66192095f7Smpi size_t, const char **, size_t *);
67192095f7Smpi
68192095f7Smpi /* parse.c */
69192095f7Smpi void dwarf_parse(const char *, size_t, const char *, size_t);
70192095f7Smpi
71192095f7Smpi const char *ctf_enc2name(unsigned short);
72192095f7Smpi
73192095f7Smpi /* lists of parsed types and functions */
74192095f7Smpi struct itype_queue itypeq = TAILQ_HEAD_INITIALIZER(itypeq);
75192095f7Smpi struct itype_queue ifuncq = TAILQ_HEAD_INITIALIZER(ifuncq);
76192095f7Smpi struct itype_queue iobjq = TAILQ_HEAD_INITIALIZER(iobjq);
77192095f7Smpi
78192095f7Smpi __dead void
usage(void)79192095f7Smpi usage(void)
80192095f7Smpi {
81f471c1b3Sjasper fprintf(stderr, "usage: %s [-d] -l label -o outfile file\n",
82192095f7Smpi getprogname());
83192095f7Smpi exit(1);
84192095f7Smpi }
85192095f7Smpi
86192095f7Smpi int
main(int argc,char * argv[])87192095f7Smpi main(int argc, char *argv[])
88192095f7Smpi {
89192095f7Smpi const char *filename, *label = NULL, *outfile = NULL;
90192095f7Smpi int dump = 0;
91192095f7Smpi int ch, error = 0;
92192095f7Smpi struct itype *it;
93192095f7Smpi
94192095f7Smpi setlocale(LC_ALL, "");
95192095f7Smpi
96192095f7Smpi while ((ch = getopt(argc, argv, "dl:o:")) != -1) {
97192095f7Smpi switch (ch) {
98192095f7Smpi case 'd':
99d92886f7Sjasper dump = 1; /* ctfdump(1)-like SUNW_ctf sections */
100192095f7Smpi break;
101192095f7Smpi case 'l':
102192095f7Smpi if (label != NULL)
103192095f7Smpi usage();
104192095f7Smpi label = optarg;
105192095f7Smpi break;
106192095f7Smpi case 'o':
107192095f7Smpi if (outfile != NULL)
108192095f7Smpi usage();
109192095f7Smpi outfile = optarg;
110192095f7Smpi break;
111192095f7Smpi default:
112192095f7Smpi usage();
113192095f7Smpi }
114192095f7Smpi }
115192095f7Smpi
116192095f7Smpi argc -= optind;
117192095f7Smpi argv += optind;
118192095f7Smpi
119192095f7Smpi if (argc != 1)
120192095f7Smpi usage();
121192095f7Smpi
122d92886f7Sjasper /* Either dump the sections, or write it out. */
123d92886f7Sjasper if ((dump && (outfile != NULL || label != NULL)) ||
124d92886f7Sjasper (!dump && (outfile == NULL || label == NULL)))
125192095f7Smpi usage();
126192095f7Smpi
127192095f7Smpi filename = *argv;
12862a5ce36Smestre
12962a5ce36Smestre if (unveil(filename, "r") == -1)
130bc5a8259Sbeck err(1, "unveil %s", filename);
13162a5ce36Smestre
13262a5ce36Smestre if (outfile != NULL) {
13362a5ce36Smestre if (unveil(outfile, "wc") == -1)
134bc5a8259Sbeck err(1, "unveil %s", outfile);
13562a5ce36Smestre }
13662a5ce36Smestre
13762a5ce36Smestre if (pledge("stdio rpath wpath cpath", NULL) == -1)
13862a5ce36Smestre err(1, "pledge");
13962a5ce36Smestre
140192095f7Smpi error = convert(filename);
141192095f7Smpi if (error != 0)
142192095f7Smpi return error;
143192095f7Smpi
1445dd7bfaeSjasper if (outfile != NULL) {
1455dd7bfaeSjasper if (pledge("stdio wpath cpath", NULL) == -1)
1465dd7bfaeSjasper err(1, "pledge");
1475dd7bfaeSjasper
1485dd7bfaeSjasper error = generate(outfile, label, 1);
1495dd7bfaeSjasper if (error != 0)
1505dd7bfaeSjasper return error;
1515dd7bfaeSjasper }
1525dd7bfaeSjasper
153192095f7Smpi if (dump) {
1545dd7bfaeSjasper if (pledge("stdio", NULL) == -1)
1555dd7bfaeSjasper err(1, "pledge");
1565dd7bfaeSjasper
157192095f7Smpi int fidx = -1, oidx = -1;
158192095f7Smpi
159192095f7Smpi TAILQ_FOREACH(it, &iobjq, it_symb)
160192095f7Smpi dump_obj(it, &oidx);
161192095f7Smpi printf("\n");
162192095f7Smpi
163192095f7Smpi TAILQ_FOREACH(it, &ifuncq, it_symb)
164192095f7Smpi dump_func(it, &fidx);
165192095f7Smpi printf("\n");
166192095f7Smpi
167192095f7Smpi TAILQ_FOREACH(it, &itypeq, it_next) {
168192095f7Smpi if (it->it_flags & (ITF_FUNC|ITF_OBJ))
169192095f7Smpi continue;
170192095f7Smpi
171192095f7Smpi dump_type(it);
172192095f7Smpi }
173d92886f7Sjasper
174d92886f7Sjasper return 0;
175192095f7Smpi }
176192095f7Smpi
177192095f7Smpi return 0;
178192095f7Smpi }
179192095f7Smpi
180192095f7Smpi int
convert(const char * path)181192095f7Smpi convert(const char *path)
182192095f7Smpi {
183192095f7Smpi struct stat st;
184192095f7Smpi int fd, error = 1;
185192095f7Smpi char *p;
186192095f7Smpi
187192095f7Smpi fd = open(path, O_RDONLY);
188192095f7Smpi if (fd == -1) {
189192095f7Smpi warn("open %s", path);
190192095f7Smpi return 1;
191192095f7Smpi }
192192095f7Smpi if (fstat(fd, &st) == -1) {
193192095f7Smpi warn("fstat %s", path);
194c8f519c3Sjsg close(fd);
195192095f7Smpi return 1;
196192095f7Smpi }
197192095f7Smpi if ((uintmax_t)st.st_size > SIZE_MAX) {
198192095f7Smpi warnx("file too big to fit memory");
199c8f519c3Sjsg close(fd);
200192095f7Smpi return 1;
201192095f7Smpi }
202192095f7Smpi
203192095f7Smpi p = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
204192095f7Smpi if (p == MAP_FAILED)
205192095f7Smpi err(1, "mmap");
206192095f7Smpi
207192095f7Smpi if (iself(p, st.st_size))
208192095f7Smpi error = elf_convert(p, st.st_size);
209192095f7Smpi
210192095f7Smpi munmap(p, st.st_size);
211192095f7Smpi close(fd);
212192095f7Smpi
213192095f7Smpi return error;
214192095f7Smpi }
215192095f7Smpi
216192095f7Smpi const char *dstrbuf;
217192095f7Smpi size_t dstrlen;
218192095f7Smpi const char *strtab;
219192095f7Smpi const Elf_Sym *symtab;
220192095f7Smpi size_t strtabsz, nsymb;
221192095f7Smpi
222192095f7Smpi int
elf_convert(char * p,size_t filesize)223192095f7Smpi elf_convert(char *p, size_t filesize)
224192095f7Smpi {
225192095f7Smpi const char *shstab;
226192095f7Smpi const char *infobuf, *abbuf;
227192095f7Smpi size_t infolen, ablen;
228192095f7Smpi size_t shstabsz;
229192095f7Smpi
230192095f7Smpi /* Find section header string table location and size. */
231192095f7Smpi if (elf_getshstab(p, filesize, &shstab, &shstabsz))
232192095f7Smpi return 1;
233192095f7Smpi
234622b7392Smpi /* Find symbol table and associated string table. */
235622b7392Smpi if (elf_getsymtab(p, filesize, shstab, shstabsz, &symtab, &nsymb,
236622b7392Smpi &strtab, &strtabsz) == -1)
237192095f7Smpi warnx("symbol table not found");
238192095f7Smpi
239192095f7Smpi /* Find abbreviation location and size. */
24059153d10Sjsg if (elf_getsection(p, filesize, DEBUG_ABBREV, shstab, shstabsz, &abbuf,
241192095f7Smpi &ablen) == -1) {
242192095f7Smpi warnx("%s section not found", DEBUG_ABBREV);
243192095f7Smpi return 1;
244192095f7Smpi }
245192095f7Smpi
24659153d10Sjsg if (elf_getsection(p, filesize, DEBUG_INFO, shstab, shstabsz, &infobuf,
247192095f7Smpi &infolen) == -1) {
248192095f7Smpi warnx("%s section not found", DEBUG_INFO);
249192095f7Smpi return 1;
250192095f7Smpi }
251192095f7Smpi
252192095f7Smpi /* Find string table location and size. */
25359153d10Sjsg if (elf_getsection(p, filesize, DEBUG_STR, shstab, shstabsz, &dstrbuf,
254192095f7Smpi &dstrlen) == -1)
255192095f7Smpi warnx("%s section not found", DEBUG_STR);
256192095f7Smpi
257192095f7Smpi dwarf_parse(infobuf, infolen, abbuf, ablen);
258192095f7Smpi
259192095f7Smpi /* Sort functions */
260192095f7Smpi elf_sort();
261192095f7Smpi
262192095f7Smpi return 0;
263192095f7Smpi }
264192095f7Smpi
26508b0026dSmpi /*
26608b0026dSmpi * Guess which part of a local symbol name correspond to the variable
26708b0026dSmpi * name.
26808b0026dSmpi *
26908b0026dSmpi * gcc 4.2.1 emits:
27008b0026dSmpi *
27108b0026dSmpi * varname.id
27208b0026dSmpi *
27308b0026dSmpi * clang 8 emits:
27408b0026dSmpi *
27508b0026dSmpi * funcname.varname
27608b0026dSmpi *
27708b0026dSmpi */
27808b0026dSmpi char *
guess_static_local_name(char * sname)27908b0026dSmpi guess_static_local_name(char *sname)
28008b0026dSmpi {
28108b0026dSmpi const char *errstr;
28208b0026dSmpi char *first, *second;
28308b0026dSmpi
28408b0026dSmpi first = strtok(sname, ".");
28508b0026dSmpi if (first == NULL)
28608b0026dSmpi return NULL;
28708b0026dSmpi
28808b0026dSmpi /* Skip meta symbols - gcc style. */
28908b0026dSmpi if (strncmp(first, "__func__", sizeof("__func__") - 1) == 0 ||
29008b0026dSmpi strncmp(first, "__FUNCTION__", sizeof("__FUNCTION__") - 1) == 0 ||
29108b0026dSmpi strncmp(first, "__warned", sizeof("__warned") - 1) == 0)
29208b0026dSmpi return NULL;
29308b0026dSmpi
29408b0026dSmpi second = strtok(NULL, "\0");
29508b0026dSmpi if (second == NULL)
29608b0026dSmpi return first;
29708b0026dSmpi
29808b0026dSmpi /* Skip meta symbols - clang style. */
29908b0026dSmpi if (strncmp(second, "__warned", sizeof("__warned") - 1) == 0)
30008b0026dSmpi return NULL;
30108b0026dSmpi
30208b0026dSmpi /* If `second' isn't a number, assume clang-style name. */
30308b0026dSmpi if (strtonum(second, 1, INT_MAX, &errstr) == 0)
30408b0026dSmpi return second;
30508b0026dSmpi
30608b0026dSmpi return first;
30708b0026dSmpi }
30808b0026dSmpi
309589f0bfaSmpi struct itype *
find_symb(struct itype * tmp,size_t stroff)310589f0bfaSmpi find_symb(struct itype *tmp, size_t stroff)
311589f0bfaSmpi {
312589f0bfaSmpi struct itype *it;
313589f0bfaSmpi char *sname, *p;
314589f0bfaSmpi
315589f0bfaSmpi if (strtab == NULL || stroff >= strtabsz)
316589f0bfaSmpi return NULL;
317589f0bfaSmpi
318589f0bfaSmpi sname = xstrdup(strtab + stroff);
31908b0026dSmpi if ((p = guess_static_local_name(sname)) == NULL) {
320589f0bfaSmpi free(sname);
321589f0bfaSmpi return NULL;
322589f0bfaSmpi }
323589f0bfaSmpi
324589f0bfaSmpi strlcpy(tmp->it_name, p, ITNAME_MAX);
325589f0bfaSmpi free(sname);
326589f0bfaSmpi it = RB_FIND(isymb_tree, &isymbt, tmp);
327589f0bfaSmpi
328589f0bfaSmpi /* Restore original name */
329589f0bfaSmpi if (it == NULL)
330589f0bfaSmpi strlcpy(tmp->it_name, (strtab + stroff), ITNAME_MAX);
331589f0bfaSmpi
332589f0bfaSmpi return it;
333589f0bfaSmpi }
334589f0bfaSmpi
335192095f7Smpi void
elf_sort(void)336192095f7Smpi elf_sort(void)
337192095f7Smpi {
338192095f7Smpi struct itype *it, tmp;
339192095f7Smpi size_t i;
340192095f7Smpi
341192095f7Smpi memset(&tmp, 0, sizeof(tmp));
342192095f7Smpi for (i = 0; i < nsymb; i++) {
343192095f7Smpi const Elf_Sym *st = &symtab[i];
344192095f7Smpi
345192095f7Smpi if (st->st_shndx == SHN_UNDEF || st->st_shndx == SHN_COMMON)
346192095f7Smpi continue;
347192095f7Smpi
348192095f7Smpi switch (ELF_ST_TYPE(st->st_info)) {
349192095f7Smpi case STT_FUNC:
350192095f7Smpi tmp.it_flags = ITF_FUNC;
351192095f7Smpi break;
352192095f7Smpi case STT_OBJECT:
353192095f7Smpi tmp.it_flags = ITF_OBJ;
354192095f7Smpi break;
355192095f7Smpi default:
356192095f7Smpi continue;
357192095f7Smpi }
358192095f7Smpi
359589f0bfaSmpi it = find_symb(&tmp, st->st_name);
360192095f7Smpi if (it == NULL) {
361192095f7Smpi /* Insert 'unknown' entry to match symbol order. */
362192095f7Smpi it = it_dup(&tmp);
363192095f7Smpi it->it_refp = it;
364192095f7Smpi #ifdef DEBUG
365192095f7Smpi warnx("symbol not found: %s", it_name(it));
366192095f7Smpi #endif
367192095f7Smpi }
368192095f7Smpi
369192095f7Smpi if (it->it_flags & ITF_INSERTED) {
370192095f7Smpi #ifdef DEBUG
371192095f7Smpi warnx("%s: already inserted", it_name(it));
372192095f7Smpi #endif
373192095f7Smpi it = it_dup(it);
374192095f7Smpi }
375192095f7Smpi
376192095f7Smpi /* Save symbol index for dump. */
377192095f7Smpi it->it_ref = i;
378192095f7Smpi
379192095f7Smpi it->it_flags |= ITF_INSERTED;
380192095f7Smpi if (it->it_flags & ITF_FUNC)
381192095f7Smpi TAILQ_INSERT_TAIL(&ifuncq, it, it_symb);
382192095f7Smpi else
383192095f7Smpi TAILQ_INSERT_TAIL(&iobjq, it, it_symb);
384192095f7Smpi }
385192095f7Smpi }
386192095f7Smpi
387192095f7Smpi const char *
type_name(struct itype * it)388192095f7Smpi type_name(struct itype *it)
389192095f7Smpi {
390192095f7Smpi const char *name;
391192095f7Smpi
392192095f7Smpi name = it_name(it);
393192095f7Smpi if (name == NULL)
394192095f7Smpi return "(anon)";
395192095f7Smpi
396192095f7Smpi return name;
397192095f7Smpi }
398192095f7Smpi
399192095f7Smpi /* Display parsed types a la ctfdump(1) */
400192095f7Smpi void
dump_type(struct itype * it)401192095f7Smpi dump_type(struct itype *it)
402192095f7Smpi {
403192095f7Smpi struct imember *im;
404192095f7Smpi
405192095f7Smpi #ifdef DEBUG
406192095f7Smpi switch (it->it_type) {
407192095f7Smpi case CTF_K_POINTER:
408192095f7Smpi case CTF_K_TYPEDEF:
409192095f7Smpi case CTF_K_VOLATILE:
410192095f7Smpi case CTF_K_CONST:
411192095f7Smpi case CTF_K_RESTRICT:
412192095f7Smpi case CTF_K_ARRAY:
413192095f7Smpi case CTF_K_FUNCTION:
414192095f7Smpi if (it->it_refp == NULL) {
415192095f7Smpi printf("unresolved: %s type=%d\n", it_name(it),
416192095f7Smpi it->it_type);
417192095f7Smpi return;
418192095f7Smpi }
419192095f7Smpi default:
420192095f7Smpi break;
421192095f7Smpi }
422192095f7Smpi #endif
423192095f7Smpi
424192095f7Smpi switch (it->it_type) {
425192095f7Smpi case CTF_K_FLOAT:
426192095f7Smpi case CTF_K_INTEGER:
427192095f7Smpi printf(" [%u] %s %s encoding=%s offset=0 bits=%u\n",
428192095f7Smpi it->it_idx,
429192095f7Smpi (it->it_type == CTF_K_INTEGER) ? "INTEGER" : "FLOAT",
430192095f7Smpi it_name(it), ctf_enc2name(it->it_enc), it->it_size);
431192095f7Smpi break;
432192095f7Smpi case CTF_K_POINTER:
433192095f7Smpi printf(" <%u> POINTER %s refers to %u\n", it->it_idx,
434192095f7Smpi type_name(it), it->it_refp->it_idx);
435192095f7Smpi break;
436192095f7Smpi case CTF_K_TYPEDEF:
437192095f7Smpi printf(" <%u> TYPEDEF %s refers to %u\n",
438192095f7Smpi it->it_idx, it_name(it), it->it_refp->it_idx);
439192095f7Smpi break;
440192095f7Smpi case CTF_K_VOLATILE:
441192095f7Smpi printf(" <%u> VOLATILE %s refers to %u\n", it->it_idx,
442192095f7Smpi type_name(it), it->it_refp->it_idx);
443192095f7Smpi break;
444192095f7Smpi case CTF_K_CONST:
445192095f7Smpi printf(" <%u> CONST %s refers to %u\n", it->it_idx,
446192095f7Smpi type_name(it), it->it_refp->it_idx);
447192095f7Smpi break;
448192095f7Smpi case CTF_K_RESTRICT:
449192095f7Smpi printf(" <%u> RESTRICT %s refers to %u\n", it->it_idx,
450192095f7Smpi it_name(it), it->it_refp->it_idx);
451192095f7Smpi break;
452192095f7Smpi case CTF_K_ARRAY:
453192095f7Smpi printf(" [%u] ARRAY %s content: %u index: %u nelems: %u\n",
454192095f7Smpi it->it_idx, type_name(it), it->it_refp->it_idx, long_tidx,
455192095f7Smpi it->it_nelems);
456192095f7Smpi printf("\n");
457192095f7Smpi break;
458192095f7Smpi case CTF_K_STRUCT:
459192095f7Smpi case CTF_K_UNION:
460192095f7Smpi printf(" [%u] %s %s (%u bytes)\n", it->it_idx,
461192095f7Smpi (it->it_type == CTF_K_STRUCT) ? "STRUCT" : "UNION",
462192095f7Smpi type_name(it), it->it_size);
463192095f7Smpi TAILQ_FOREACH(im, &it->it_members, im_next) {
464faf74f15Smpi printf("\t%s type=%u off=%zu\n",
46572c906afSmpi (im_name(im) == NULL) ? "unknown" : im_name(im),
466d84376f1Smpi im->im_refp ? im->im_refp->it_idx : 0, im->im_off);
467192095f7Smpi }
468192095f7Smpi printf("\n");
469192095f7Smpi break;
470192095f7Smpi case CTF_K_ENUM:
471991cae8cSmpi printf(" [%u] ENUM %s\n", it->it_idx, type_name(it));
472991cae8cSmpi TAILQ_FOREACH(im, &it->it_members, im_next) {
473991cae8cSmpi printf("\t%s = %zu\n", im_name(im), im->im_ref);
474991cae8cSmpi }
475991cae8cSmpi printf("\n");
476192095f7Smpi break;
477192095f7Smpi case CTF_K_FUNCTION:
478192095f7Smpi printf(" [%u] FUNCTION (%s) returns: %u args: (",
479192095f7Smpi it->it_idx, (it_name(it) != NULL) ? it_name(it) : "anon",
480192095f7Smpi it->it_refp->it_idx);
481192095f7Smpi TAILQ_FOREACH(im, &it->it_members, im_next) {
482192095f7Smpi printf("%u%s", im->im_refp->it_idx,
483192095f7Smpi TAILQ_NEXT(im, im_next) ? ", " : "");
484192095f7Smpi }
485192095f7Smpi printf(")\n");
486192095f7Smpi break;
487192095f7Smpi default:
488192095f7Smpi assert(0 == 1);
489192095f7Smpi }
490192095f7Smpi }
491192095f7Smpi
492192095f7Smpi void
dump_func(struct itype * it,int * idx)493192095f7Smpi dump_func(struct itype *it, int *idx)
494192095f7Smpi {
495192095f7Smpi struct imember *im;
496192095f7Smpi
497192095f7Smpi (*idx)++;
498192095f7Smpi
499192095f7Smpi if (it->it_type == CTF_K_UNKNOWN && it->it_nelems == 0)
500192095f7Smpi return;
501192095f7Smpi
502192095f7Smpi printf(" [%u] FUNC (%s) returns: %u args: (", (*idx),
503192095f7Smpi (it_name(it) != NULL) ? it_name(it) : "unknown",
504192095f7Smpi it->it_refp->it_idx);
505192095f7Smpi TAILQ_FOREACH(im, &it->it_members, im_next) {
506192095f7Smpi printf("%u%s", im->im_refp->it_idx,
507192095f7Smpi TAILQ_NEXT(im, im_next) ? ", " : "");
508192095f7Smpi }
509192095f7Smpi printf(")\n");
510192095f7Smpi }
511192095f7Smpi
512192095f7Smpi void
dump_obj(struct itype * it,int * idx)513192095f7Smpi dump_obj(struct itype *it, int *idx)
514192095f7Smpi {
515192095f7Smpi int l;
516192095f7Smpi
517192095f7Smpi (*idx)++;
518192095f7Smpi
519192095f7Smpi l = printf(" [%u] %u", (*idx), it->it_refp->it_idx);
520192095f7Smpi printf("%*s %s (%llu)\n", 14 - l, "", it_name(it), it->it_ref);
521192095f7Smpi }
522192095f7Smpi
523192095f7Smpi const char *
ctf_enc2name(unsigned short enc)524192095f7Smpi ctf_enc2name(unsigned short enc)
525192095f7Smpi {
526192095f7Smpi static const char *enc_name[] = { "SIGNED", "CHAR", "SIGNED CHAR",
527192095f7Smpi "BOOL", "SIGNED BOOL" };
528192095f7Smpi static char invalid[7];
529192095f7Smpi
530192095f7Smpi if (enc == CTF_INT_VARARGS)
531192095f7Smpi return "VARARGS";
532192095f7Smpi
533192095f7Smpi if (enc > 0 && enc < nitems(enc_name))
534192095f7Smpi return enc_name[enc - 1];
535192095f7Smpi
536192095f7Smpi snprintf(invalid, sizeof(invalid), "0x%x", enc);
537192095f7Smpi return invalid;
538192095f7Smpi }
539