xref: /openbsd-src/usr.bin/ctfconv/ctfconv.c (revision be9aadfacfc45dac92e962c697836a1ffb5455e0)
1*be9aadfaSjsg /*	$OpenBSD: ctfconv.c,v 1.12 2017/09/29 16:05:53 jsg 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/exec_elf.h>
22192095f7Smpi #include <sys/mman.h>
23192095f7Smpi #include <sys/queue.h>
24192095f7Smpi #include <sys/tree.h>
25192095f7Smpi #include <sys/ctf.h>
26192095f7Smpi 
27192095f7Smpi #include <assert.h>
28192095f7Smpi #include <err.h>
29192095f7Smpi #include <fcntl.h>
30192095f7Smpi #include <locale.h>
31192095f7Smpi #include <stdio.h>
32192095f7Smpi #include <stdint.h>
33192095f7Smpi #include <stdlib.h>
34192095f7Smpi #include <string.h>
35192095f7Smpi #include <unistd.h>
36192095f7Smpi 
37192095f7Smpi #include "itype.h"
38192095f7Smpi #include "xmalloc.h"
39192095f7Smpi 
40192095f7Smpi #ifndef nitems
41192095f7Smpi #define nitems(_a)	(sizeof((_a)) / sizeof((_a)[0]))
42192095f7Smpi #endif
43192095f7Smpi 
44192095f7Smpi #define DEBUG_ABBREV	".debug_abbrev"
45192095f7Smpi #define DEBUG_INFO	".debug_info"
46192095f7Smpi #define DEBUG_LINE	".debug_line"
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);
54589f0bfaSmpi struct itype	*find_symb(struct itype *, size_t);
55192095f7Smpi void		 dump_type(struct itype *);
56192095f7Smpi void		 dump_func(struct itype *, int *);
57192095f7Smpi void		 dump_obj(struct itype *, int *);
58192095f7Smpi 
59192095f7Smpi /* elf.c */
60192095f7Smpi int		 iself(const char *, size_t);
61192095f7Smpi int		 elf_getshstab(const char *, size_t, const char **, size_t *);
62*be9aadfaSjsg ssize_t		 elf_getsymtab(const char *, size_t, const char *, size_t,
63192095f7Smpi 		     const Elf_Sym **, size_t *);
6459153d10Sjsg ssize_t		 elf_getsection(char *, size_t, const char *, const char *,
65192095f7Smpi 		     size_t, const char **, size_t *);
66192095f7Smpi 
67192095f7Smpi /* parse.c */
68192095f7Smpi void		 dwarf_parse(const char *, size_t, const char *, size_t);
69192095f7Smpi 
70192095f7Smpi const char	*ctf_enc2name(unsigned short);
71192095f7Smpi 
72192095f7Smpi /* lists of parsed types and functions */
73192095f7Smpi struct itype_queue itypeq = TAILQ_HEAD_INITIALIZER(itypeq);
74192095f7Smpi struct itype_queue ifuncq = TAILQ_HEAD_INITIALIZER(ifuncq);
75192095f7Smpi struct itype_queue iobjq = TAILQ_HEAD_INITIALIZER(iobjq);
76192095f7Smpi 
77192095f7Smpi __dead void
78192095f7Smpi usage(void)
79192095f7Smpi {
80f471c1b3Sjasper 	fprintf(stderr, "usage: %s [-d] -l label -o outfile file\n",
81192095f7Smpi 	    getprogname());
82192095f7Smpi 	exit(1);
83192095f7Smpi }
84192095f7Smpi 
85192095f7Smpi int
86192095f7Smpi main(int argc, char *argv[])
87192095f7Smpi {
88192095f7Smpi 	const char *filename, *label = NULL, *outfile = NULL;
89192095f7Smpi 	int dump = 0;
90192095f7Smpi 	int ch, error = 0;
91192095f7Smpi 	struct itype *it;
92192095f7Smpi 
93192095f7Smpi 	setlocale(LC_ALL, "");
94192095f7Smpi 
955dd7bfaeSjasper 	if (pledge("stdio rpath wpath cpath", NULL) == -1)
965dd7bfaeSjasper 		err(1, "pledge");
975dd7bfaeSjasper 
98192095f7Smpi 	while ((ch = getopt(argc, argv, "dl:o:")) != -1) {
99192095f7Smpi 		switch (ch) {
100192095f7Smpi 		case 'd':
101d92886f7Sjasper 			dump = 1;	/* ctfdump(1)-like SUNW_ctf sections */
102192095f7Smpi 			break;
103192095f7Smpi 		case 'l':
104192095f7Smpi 			if (label != NULL)
105192095f7Smpi 				usage();
106192095f7Smpi 			label = optarg;
107192095f7Smpi 			break;
108192095f7Smpi 		case 'o':
109192095f7Smpi 			if (outfile != NULL)
110192095f7Smpi 				usage();
111192095f7Smpi 			outfile = optarg;
112192095f7Smpi 			break;
113192095f7Smpi 		default:
114192095f7Smpi 			usage();
115192095f7Smpi 		}
116192095f7Smpi 	}
117192095f7Smpi 
118192095f7Smpi 	argc -= optind;
119192095f7Smpi 	argv += optind;
120192095f7Smpi 
121192095f7Smpi 	if (argc != 1)
122192095f7Smpi 		usage();
123192095f7Smpi 
124d92886f7Sjasper 	/* Either dump the sections, or write it out. */
125d92886f7Sjasper 	if ((dump && (outfile != NULL || label != NULL)) ||
126d92886f7Sjasper 	    (!dump && (outfile == NULL || label == NULL)))
127192095f7Smpi 		usage();
128192095f7Smpi 
129192095f7Smpi 	filename = *argv;
130192095f7Smpi 	error = convert(filename);
131192095f7Smpi 	if (error != 0)
132192095f7Smpi 		return error;
133192095f7Smpi 
1345dd7bfaeSjasper 	if (outfile != NULL) {
1355dd7bfaeSjasper 		if (pledge("stdio wpath cpath", NULL) == -1)
1365dd7bfaeSjasper 			err(1, "pledge");
1375dd7bfaeSjasper 
1385dd7bfaeSjasper 		error = generate(outfile, label, 1);
1395dd7bfaeSjasper 		if (error != 0)
1405dd7bfaeSjasper 			return error;
1415dd7bfaeSjasper 	}
1425dd7bfaeSjasper 
143192095f7Smpi 	if (dump) {
1445dd7bfaeSjasper 		if (pledge("stdio", NULL) == -1)
1455dd7bfaeSjasper 			err(1, "pledge");
1465dd7bfaeSjasper 
147192095f7Smpi 		int fidx = -1, oidx = -1;
148192095f7Smpi 
149192095f7Smpi 		TAILQ_FOREACH(it, &iobjq, it_symb)
150192095f7Smpi 			dump_obj(it, &oidx);
151192095f7Smpi 		printf("\n");
152192095f7Smpi 
153192095f7Smpi 		TAILQ_FOREACH(it, &ifuncq, it_symb)
154192095f7Smpi 			dump_func(it, &fidx);
155192095f7Smpi 		printf("\n");
156192095f7Smpi 
157192095f7Smpi 		TAILQ_FOREACH(it, &itypeq, it_next) {
158192095f7Smpi 			if (it->it_flags & (ITF_FUNC|ITF_OBJ))
159192095f7Smpi 				continue;
160192095f7Smpi 
161192095f7Smpi 			dump_type(it);
162192095f7Smpi 		}
163d92886f7Sjasper 
164d92886f7Sjasper 		return 0;
165192095f7Smpi 	}
166192095f7Smpi 
167192095f7Smpi 	return 0;
168192095f7Smpi }
169192095f7Smpi 
170192095f7Smpi int
171192095f7Smpi convert(const char *path)
172192095f7Smpi {
173192095f7Smpi 	struct stat		 st;
174192095f7Smpi 	int			 fd, error = 1;
175192095f7Smpi 	char			*p;
176192095f7Smpi 
177192095f7Smpi 	fd = open(path, O_RDONLY);
178192095f7Smpi 	if (fd == -1) {
179192095f7Smpi 		warn("open %s", path);
180192095f7Smpi 		return 1;
181192095f7Smpi 	}
182192095f7Smpi 	if (fstat(fd, &st) == -1) {
183192095f7Smpi 		warn("fstat %s", path);
184c8f519c3Sjsg 		close(fd);
185192095f7Smpi 		return 1;
186192095f7Smpi 	}
187192095f7Smpi 	if ((uintmax_t)st.st_size > SIZE_MAX) {
188192095f7Smpi 		warnx("file too big to fit memory");
189c8f519c3Sjsg 		close(fd);
190192095f7Smpi 		return 1;
191192095f7Smpi 	}
192192095f7Smpi 
193192095f7Smpi 	p = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
194192095f7Smpi 	if (p == MAP_FAILED)
195192095f7Smpi 		err(1, "mmap");
196192095f7Smpi 
197192095f7Smpi 	if (iself(p, st.st_size))
198192095f7Smpi 		error = elf_convert(p, st.st_size);
199192095f7Smpi 
200192095f7Smpi 	munmap(p, st.st_size);
201192095f7Smpi 	close(fd);
202192095f7Smpi 
203192095f7Smpi 	return error;
204192095f7Smpi }
205192095f7Smpi 
206192095f7Smpi const char		*dstrbuf;
207192095f7Smpi size_t			 dstrlen;
208192095f7Smpi const char		*strtab;
209192095f7Smpi const Elf_Sym		*symtab;
210192095f7Smpi size_t			 strtabsz, nsymb;
211192095f7Smpi 
212192095f7Smpi int
213192095f7Smpi elf_convert(char *p, size_t filesize)
214192095f7Smpi {
215192095f7Smpi 	const char		*shstab;
216192095f7Smpi 	const char		*infobuf, *abbuf;
217192095f7Smpi 	size_t			 infolen, ablen;
218192095f7Smpi 	size_t			 shstabsz;
219192095f7Smpi 
220192095f7Smpi 	/* Find section header string table location and size. */
221192095f7Smpi 	if (elf_getshstab(p, filesize, &shstab, &shstabsz))
222192095f7Smpi 		return 1;
223192095f7Smpi 
224192095f7Smpi 	/* Find symbol table location and number of symbols. */
225*be9aadfaSjsg 	if (elf_getsymtab(p, filesize, shstab, shstabsz, &symtab, &nsymb) == -1)
226192095f7Smpi 		warnx("symbol table not found");
227192095f7Smpi 
228192095f7Smpi 	/* Find string table location and size. */
22959153d10Sjsg 	if (elf_getsection(p, filesize, ELF_STRTAB, shstab, shstabsz, &strtab,
230192095f7Smpi 	    &strtabsz) == -1)
231192095f7Smpi 		warnx("string table not found");
232192095f7Smpi 
233192095f7Smpi 	/* Find abbreviation location and size. */
23459153d10Sjsg 	if (elf_getsection(p, filesize, DEBUG_ABBREV, shstab, shstabsz, &abbuf,
235192095f7Smpi 	    &ablen) == -1) {
236192095f7Smpi 		warnx("%s section not found", DEBUG_ABBREV);
237192095f7Smpi 		return 1;
238192095f7Smpi 	}
239192095f7Smpi 
24059153d10Sjsg 	if (elf_getsection(p, filesize, DEBUG_INFO, shstab, shstabsz, &infobuf,
241192095f7Smpi 	    &infolen) == -1) {
242192095f7Smpi 		warnx("%s section not found", DEBUG_INFO);
243192095f7Smpi 		return 1;
244192095f7Smpi 	}
245192095f7Smpi 
246192095f7Smpi 	/* Find string table location and size. */
24759153d10Sjsg 	if (elf_getsection(p, filesize, DEBUG_STR, shstab, shstabsz, &dstrbuf,
248192095f7Smpi 	    &dstrlen) == -1)
249192095f7Smpi 		warnx("%s section not found", DEBUG_STR);
250192095f7Smpi 
251192095f7Smpi 	dwarf_parse(infobuf, infolen, abbuf, ablen);
252192095f7Smpi 
253192095f7Smpi 	/* Sort functions */
254192095f7Smpi 	elf_sort();
255192095f7Smpi 
256192095f7Smpi 	return 0;
257192095f7Smpi }
258192095f7Smpi 
259589f0bfaSmpi struct itype *
260589f0bfaSmpi find_symb(struct itype *tmp, size_t stroff)
261589f0bfaSmpi {
262589f0bfaSmpi 	struct itype		*it;
263589f0bfaSmpi 	char 			*sname, *p;
264589f0bfaSmpi 
265589f0bfaSmpi 	if (strtab == NULL || stroff >= strtabsz)
266589f0bfaSmpi 		return NULL;
267589f0bfaSmpi 
268589f0bfaSmpi 	/*
269589f0bfaSmpi 	 * Skip local suffix
270589f0bfaSmpi 	 *
271589f0bfaSmpi 	 * FIXME: only skip local copies.
272589f0bfaSmpi 	 */
273589f0bfaSmpi 	sname = xstrdup(strtab + stroff);
274589f0bfaSmpi 	if ((p = strtok(sname, ".")) == NULL) {
275589f0bfaSmpi 		free(sname);
276589f0bfaSmpi 		return NULL;
277589f0bfaSmpi 	}
278589f0bfaSmpi 
279589f0bfaSmpi 	strlcpy(tmp->it_name, p, ITNAME_MAX);
280589f0bfaSmpi 	free(sname);
281589f0bfaSmpi 	it = RB_FIND(isymb_tree, &isymbt, tmp);
282589f0bfaSmpi 
283589f0bfaSmpi 	/* Restore original name */
284589f0bfaSmpi 	if (it == NULL)
285589f0bfaSmpi 		strlcpy(tmp->it_name, (strtab + stroff), ITNAME_MAX);
286589f0bfaSmpi 
287589f0bfaSmpi 	return it;
288589f0bfaSmpi }
289589f0bfaSmpi 
290192095f7Smpi void
291192095f7Smpi elf_sort(void)
292192095f7Smpi {
293192095f7Smpi 	struct itype		*it, tmp;
294192095f7Smpi 	size_t			 i;
295192095f7Smpi 
296192095f7Smpi 	memset(&tmp, 0, sizeof(tmp));
297192095f7Smpi 	for (i = 0; i < nsymb; i++) {
298192095f7Smpi 		const Elf_Sym	*st = &symtab[i];
299192095f7Smpi 
300192095f7Smpi 		if (st->st_shndx == SHN_UNDEF || st->st_shndx == SHN_COMMON)
301192095f7Smpi 			continue;
302192095f7Smpi 
303192095f7Smpi 		switch (ELF_ST_TYPE(st->st_info)) {
304192095f7Smpi 		case STT_FUNC:
305192095f7Smpi 			tmp.it_flags = ITF_FUNC;
306192095f7Smpi 			break;
307192095f7Smpi 		case STT_OBJECT:
308192095f7Smpi 			tmp.it_flags = ITF_OBJ;
309192095f7Smpi 			break;
310192095f7Smpi 		default:
311192095f7Smpi 			continue;
312192095f7Smpi 		}
313192095f7Smpi 
314589f0bfaSmpi 		it = find_symb(&tmp, st->st_name);
315192095f7Smpi 		if (it == NULL) {
316192095f7Smpi 			/* Insert 'unknown' entry to match symbol order. */
317192095f7Smpi 			it = it_dup(&tmp);
318192095f7Smpi 			it->it_refp = it;
319192095f7Smpi #ifdef DEBUG
320192095f7Smpi 			warnx("symbol not found: %s", it_name(it));
321192095f7Smpi #endif
322192095f7Smpi 		}
323192095f7Smpi 
324192095f7Smpi 		if (it->it_flags & ITF_INSERTED) {
325192095f7Smpi #ifdef DEBUG
326192095f7Smpi 			warnx("%s: already inserted", it_name(it));
327192095f7Smpi #endif
328192095f7Smpi 			it = it_dup(it);
329192095f7Smpi 		}
330192095f7Smpi 
331192095f7Smpi 		/* Save symbol index for dump. */
332192095f7Smpi 		it->it_ref = i;
333192095f7Smpi 
334192095f7Smpi 		it->it_flags |= ITF_INSERTED;
335192095f7Smpi 		if (it->it_flags & ITF_FUNC)
336192095f7Smpi 			TAILQ_INSERT_TAIL(&ifuncq, it, it_symb);
337192095f7Smpi 		else
338192095f7Smpi 			TAILQ_INSERT_TAIL(&iobjq, it, it_symb);
339192095f7Smpi 	}
340192095f7Smpi }
341192095f7Smpi 
342192095f7Smpi const char *
343192095f7Smpi type_name(struct itype *it)
344192095f7Smpi {
345192095f7Smpi 	const char *name;
346192095f7Smpi 
347192095f7Smpi 	name = it_name(it);
348192095f7Smpi 	if (name == NULL)
349192095f7Smpi 		return "(anon)";
350192095f7Smpi 
351192095f7Smpi 	return name;
352192095f7Smpi }
353192095f7Smpi 
354192095f7Smpi /* Display parsed types a la ctfdump(1) */
355192095f7Smpi void
356192095f7Smpi dump_type(struct itype *it)
357192095f7Smpi {
358192095f7Smpi 	struct imember *im;
359192095f7Smpi 
360192095f7Smpi #ifdef DEBUG
361192095f7Smpi 	switch (it->it_type) {
362192095f7Smpi 	case CTF_K_POINTER:
363192095f7Smpi 	case CTF_K_TYPEDEF:
364192095f7Smpi 	case CTF_K_VOLATILE:
365192095f7Smpi 	case CTF_K_CONST:
366192095f7Smpi 	case CTF_K_RESTRICT:
367192095f7Smpi 	case CTF_K_ARRAY:
368192095f7Smpi 	case CTF_K_FUNCTION:
369192095f7Smpi 		if (it->it_refp == NULL) {
370192095f7Smpi 			printf("unresolved: %s type=%d\n", it_name(it),
371192095f7Smpi 			    it->it_type);
372192095f7Smpi 			return;
373192095f7Smpi 		}
374192095f7Smpi 	default:
375192095f7Smpi 		break;
376192095f7Smpi 	}
377192095f7Smpi #endif
378192095f7Smpi 
379192095f7Smpi 	switch (it->it_type) {
380192095f7Smpi 	case CTF_K_FLOAT:
381192095f7Smpi 	case CTF_K_INTEGER:
382192095f7Smpi 		printf("  [%u] %s %s encoding=%s offset=0 bits=%u\n",
383192095f7Smpi 		    it->it_idx,
384192095f7Smpi 		    (it->it_type == CTF_K_INTEGER) ? "INTEGER" : "FLOAT",
385192095f7Smpi 		    it_name(it), ctf_enc2name(it->it_enc), it->it_size);
386192095f7Smpi 		break;
387192095f7Smpi 	case CTF_K_POINTER:
388192095f7Smpi 		printf("  <%u> POINTER %s refers to %u\n", it->it_idx,
389192095f7Smpi 		    type_name(it), it->it_refp->it_idx);
390192095f7Smpi 		break;
391192095f7Smpi 	case CTF_K_TYPEDEF:
392192095f7Smpi 		printf("  <%u> TYPEDEF %s refers to %u\n",
393192095f7Smpi 		    it->it_idx, it_name(it), it->it_refp->it_idx);
394192095f7Smpi 		break;
395192095f7Smpi 	case CTF_K_VOLATILE:
396192095f7Smpi 		printf("  <%u> VOLATILE %s refers to %u\n", it->it_idx,
397192095f7Smpi 		    type_name(it), it->it_refp->it_idx);
398192095f7Smpi 		break;
399192095f7Smpi 	case CTF_K_CONST:
400192095f7Smpi 		printf("  <%u> CONST %s refers to %u\n", it->it_idx,
401192095f7Smpi 		    type_name(it), it->it_refp->it_idx);
402192095f7Smpi 		break;
403192095f7Smpi 	case CTF_K_RESTRICT:
404192095f7Smpi 		printf("  <%u> RESTRICT %s refers to %u\n", it->it_idx,
405192095f7Smpi 		    it_name(it), it->it_refp->it_idx);
406192095f7Smpi 		break;
407192095f7Smpi 	case CTF_K_ARRAY:
408192095f7Smpi 		printf("  [%u] ARRAY %s content: %u index: %u nelems: %u\n",
409192095f7Smpi 		    it->it_idx, type_name(it), it->it_refp->it_idx, long_tidx,
410192095f7Smpi 		    it->it_nelems);
411192095f7Smpi 		printf("\n");
412192095f7Smpi 		break;
413192095f7Smpi 	case CTF_K_STRUCT:
414192095f7Smpi 	case CTF_K_UNION:
415192095f7Smpi 		printf("  [%u] %s %s (%u bytes)\n", it->it_idx,
416192095f7Smpi 		    (it->it_type == CTF_K_STRUCT) ? "STRUCT" : "UNION",
417192095f7Smpi 		    type_name(it), it->it_size);
418192095f7Smpi 		TAILQ_FOREACH(im, &it->it_members, im_next) {
419192095f7Smpi 			printf("\t%s type=%u off=%zd\n",
42072c906afSmpi 			    (im_name(im) == NULL) ? "unknown" : im_name(im),
421d84376f1Smpi 			    im->im_refp ? im->im_refp->it_idx : 0, im->im_off);
422192095f7Smpi 		}
423192095f7Smpi 		printf("\n");
424192095f7Smpi 		break;
425192095f7Smpi 	case CTF_K_ENUM:
426192095f7Smpi 		printf("  [%u] ENUM %s\n\n", it->it_idx, type_name(it));
427192095f7Smpi 		break;
428192095f7Smpi 	case CTF_K_FUNCTION:
429192095f7Smpi 		printf("  [%u] FUNCTION (%s) returns: %u args: (",
430192095f7Smpi 		    it->it_idx, (it_name(it) != NULL) ? it_name(it) : "anon",
431192095f7Smpi 		    it->it_refp->it_idx);
432192095f7Smpi 		TAILQ_FOREACH(im, &it->it_members, im_next) {
433192095f7Smpi 			printf("%u%s", im->im_refp->it_idx,
434192095f7Smpi 			    TAILQ_NEXT(im, im_next) ? ", " : "");
435192095f7Smpi 		}
436192095f7Smpi 		printf(")\n");
437192095f7Smpi 		break;
438192095f7Smpi 	default:
439192095f7Smpi 		assert(0 == 1);
440192095f7Smpi 	}
441192095f7Smpi }
442192095f7Smpi 
443192095f7Smpi void
444192095f7Smpi dump_func(struct itype *it, int *idx)
445192095f7Smpi {
446192095f7Smpi 	struct imember *im;
447192095f7Smpi 
448192095f7Smpi 	(*idx)++;
449192095f7Smpi 
450192095f7Smpi 	if (it->it_type == CTF_K_UNKNOWN && it->it_nelems == 0)
451192095f7Smpi 		return;
452192095f7Smpi 
453192095f7Smpi 	printf("  [%u] FUNC (%s) returns: %u args: (", (*idx),
454192095f7Smpi 	    (it_name(it) != NULL) ? it_name(it) : "unknown",
455192095f7Smpi 	    it->it_refp->it_idx);
456192095f7Smpi 	TAILQ_FOREACH(im, &it->it_members, im_next) {
457192095f7Smpi 		printf("%u%s", im->im_refp->it_idx,
458192095f7Smpi 		    TAILQ_NEXT(im, im_next) ? ", " : "");
459192095f7Smpi 	}
460192095f7Smpi 	printf(")\n");
461192095f7Smpi }
462192095f7Smpi 
463192095f7Smpi void
464192095f7Smpi dump_obj(struct itype *it, int *idx)
465192095f7Smpi {
466192095f7Smpi 	int l;
467192095f7Smpi 
468192095f7Smpi 	(*idx)++;
469192095f7Smpi 
470192095f7Smpi 	l = printf("  [%u] %u", (*idx), it->it_refp->it_idx);
471192095f7Smpi 	printf("%*s %s (%llu)\n", 14 - l, "", it_name(it), it->it_ref);
472192095f7Smpi }
473192095f7Smpi 
474192095f7Smpi const char *
475192095f7Smpi ctf_enc2name(unsigned short enc)
476192095f7Smpi {
477192095f7Smpi 	static const char *enc_name[] = { "SIGNED", "CHAR", "SIGNED CHAR",
478192095f7Smpi 	    "BOOL", "SIGNED BOOL" };
479192095f7Smpi 	static char invalid[7];
480192095f7Smpi 
481192095f7Smpi 	if (enc == CTF_INT_VARARGS)
482192095f7Smpi 		return "VARARGS";
483192095f7Smpi 
484192095f7Smpi 	if (enc > 0 && enc < nitems(enc_name))
485192095f7Smpi 		return enc_name[enc - 1];
486192095f7Smpi 
487192095f7Smpi 	snprintf(invalid, sizeof(invalid), "0x%x", enc);
488192095f7Smpi 	return invalid;
489192095f7Smpi }
490