xref: /openbsd/usr.bin/ctfdump/ctfdump.c (revision 4e6a2d21)
1 /*	$OpenBSD: ctfdump.c,v 1.28 2024/02/22 13:21:03 claudio Exp $ */
2 
3 /*
4  * Copyright (c) 2016 Martin Pieuchot <mpi@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <sys/mman.h>
22 #include <sys/ctf.h>
23 
24 #include <err.h>
25 #include <fcntl.h>
26 #include <gelf.h>
27 #include <libelf.h>
28 #include <locale.h>
29 #include <stdio.h>
30 #include <stdint.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 
35 #ifdef ZLIB
36 #include <zlib.h>
37 #endif /* ZLIB */
38 
39 #ifndef nitems
40 #define nitems(_a)	(sizeof((_a)) / sizeof((_a)[0]))
41 #endif
42 
43 #define DUMP_OBJECT	(1 << 0)
44 #define DUMP_FUNCTION	(1 << 1)
45 #define DUMP_HEADER	(1 << 2)
46 #define DUMP_LABEL	(1 << 3)
47 #define DUMP_STRTAB	(1 << 4)
48 #define DUMP_STATISTIC	(1 << 5)
49 #define DUMP_TYPE	(1 << 6)
50 
51 int		 dump(const char *, uint8_t);
52 int		 isctf(const char *, size_t);
53 __dead void	 usage(void);
54 
55 int		 ctf_dump(const char *, size_t, uint8_t);
56 void		 ctf_dump_type(struct ctf_header *, const char *, size_t,
57 		     uint32_t, uint32_t *, uint32_t);
58 const char	*ctf_kind2name(uint16_t);
59 const char	*ctf_enc2name(uint16_t);
60 const char	*ctf_fpenc2name(uint16_t);
61 const char	*ctf_off2name(struct ctf_header *, const char *, size_t,
62 		     uint32_t);
63 
64 char		*decompress(const char *, size_t, size_t);
65 int		 elf_dump(uint8_t);
66 const char	*elf_idx2sym(size_t *, uint8_t);
67 
68 int
main(int argc,char * argv[])69 main(int argc, char *argv[])
70 {
71 	const char *filename;
72 	uint8_t flags = 0;
73 	int ch, error = 0;
74 
75 	setlocale(LC_ALL, "");
76 
77 	if (pledge("stdio rpath", NULL) == -1)
78 		err(1, "pledge");
79 
80 	while ((ch = getopt(argc, argv, "dfhlst")) != -1) {
81 		switch (ch) {
82 		case 'd':
83 			flags |= DUMP_OBJECT;
84 			break;
85 		case 'f':
86 			flags |= DUMP_FUNCTION;
87 			break;
88 		case 'h':
89 			flags |= DUMP_HEADER;
90 			break;
91 		case 'l':
92 			flags |= DUMP_LABEL;
93 			break;
94 		case 's':
95 			flags |= DUMP_STRTAB;
96 			break;
97 		case 't':
98 			flags |= DUMP_TYPE;
99 			break;
100 		default:
101 			usage();
102 		}
103 	}
104 
105 	argc -= optind;
106 	argv += optind;
107 
108 	if (argc <= 0)
109 		usage();
110 
111 	/* Dump everything by default */
112 	if (flags == 0)
113 		flags = 0xff;
114 
115 	if (elf_version(EV_CURRENT) == EV_NONE)
116 		errx(1, "elf_version: %s", elf_errmsg(-1));
117 
118 	while ((filename = *argv++) != NULL)
119 		error |= dump(filename, flags);
120 
121 	return error;
122 }
123 
124 Elf	*e;
125 Elf_Scn	*scnsymtab;
126 size_t	 strtabndx, strtabsz, nsymb;
127 
128 int
dump(const char * path,uint8_t flags)129 dump(const char *path, uint8_t flags)
130 {
131 	struct stat	 st;
132 	char		*p;
133 	int		 fd, error = 1;
134 
135 	fd = open(path, O_RDONLY);
136 	if (fd == -1) {
137 		warn("open");
138 		return 1;
139 	}
140 
141 	if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
142 		warnx("elf_begin: %s", elf_errmsg(-1));
143 		goto done;
144 	}
145 
146 	if (elf_kind(e) == ELF_K_ELF) {
147 		error = elf_dump(flags);
148 		elf_end(e);
149 		goto done;
150 	}
151 	elf_end(e);
152 
153 	if (fstat(fd, &st) == -1) {
154 		warn("fstat");
155 		goto done;
156 	}
157 	if ((uintmax_t)st.st_size > SIZE_MAX) {
158 		warnx("file too big to fit memory");
159 		goto done;
160 	}
161 
162 	p = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
163 	if (p == MAP_FAILED)
164 		err(1, "mmap");
165 
166 	if (isctf(p, st.st_size))
167 		error = ctf_dump(p, st.st_size, flags);
168 
169 	munmap(p, st.st_size);
170 
171  done:
172 	close(fd);
173 	return error;
174 }
175 
176 const char *
elf_idx2sym(size_t * idx,uint8_t type)177 elf_idx2sym(size_t *idx, uint8_t type)
178 {
179 	GElf_Sym	 sym;
180 	Elf_Data	*data;
181 	char		*name;
182 	size_t		 i;
183 
184 	if (scnsymtab == NULL || strtabndx == 0)
185 		return NULL;
186 
187 	data = NULL;
188 	while ((data = elf_rawdata(scnsymtab, data)) != NULL) {
189 		for (i = *idx + 1; i < nsymb; i++) {
190 			if (gelf_getsym(data, i, &sym) != &sym)
191 				continue;
192 			if (GELF_ST_TYPE(sym.st_info) != type)
193 				continue;
194 			if (sym.st_name >= strtabsz)
195 				break;
196 			if ((name = elf_strptr(e, strtabndx,
197 			    sym.st_name)) == NULL)
198 				continue;
199 
200 			*idx = i;
201 			return name;
202 		}
203 	}
204 
205 	return NULL;
206 }
207 
208 int
elf_dump(uint8_t flags)209 elf_dump(uint8_t flags)
210 {
211 	GElf_Shdr	 shdr;
212 	Elf_Scn		*scn, *scnctf;
213 	Elf_Data	*data;
214 	char		*name;
215 	size_t		 shstrndx;
216 	int		 error = 0;
217 
218 	if (elf_getshdrstrndx(e, &shstrndx) != 0) {
219 		warnx("elf_getshdrstrndx: %s", elf_errmsg(-1));
220 		return 1;
221 	}
222 
223 	scn = scnctf = NULL;
224 	while ((scn = elf_nextscn(e, scn)) != NULL) {
225 		if (gelf_getshdr(scn, &shdr) != &shdr) {
226 			warnx("elf_getshdr: %s", elf_errmsg(-1));
227 			return 1;
228 		}
229 
230 		if ((name = elf_strptr(e, shstrndx, shdr.sh_name)) == NULL) {
231 			warnx("elf_strptr: %s", elf_errmsg(-1));
232 			return 1;
233 		}
234 
235 		if (strcmp(name, ELF_CTF) == 0)
236 			scnctf = scn;
237 
238 		if (strcmp(name, ELF_SYMTAB) == 0 &&
239 		    shdr.sh_type == SHT_SYMTAB && shdr.sh_entsize != 0) {
240 			scnsymtab = scn;
241 			nsymb = shdr.sh_size / shdr.sh_entsize;
242 		}
243 
244 		if (strcmp(name, ELF_STRTAB) == 0 &&
245 		    shdr.sh_type == SHT_STRTAB) {
246 			strtabndx = elf_ndxscn(scn);
247 			strtabsz = shdr.sh_size;
248 		}
249 	}
250 
251 	if (scnctf == NULL) {
252 		warnx("%s section not found", ELF_CTF);
253 		return 1;
254 	}
255 
256 	if (scnsymtab == NULL)
257 		warnx("symbol table not found");
258 
259 	data = NULL;
260 	while ((data = elf_rawdata(scnctf, data)) != NULL) {
261 		if (data->d_buf == NULL) {
262 			warnx("%s section size is zero", ELF_CTF);
263 			return 1;
264 		}
265 
266 		if (isctf(data->d_buf, data->d_size))
267 			error |= ctf_dump(data->d_buf, data->d_size, flags);
268 	}
269 
270 	return error;
271 }
272 
273 int
isctf(const char * p,size_t filesize)274 isctf(const char *p, size_t filesize)
275 {
276 	struct ctf_header	 cth;
277 	size_t			 dlen;
278 
279 	if (filesize < sizeof(struct ctf_header)) {
280 		warnx("file too small to be CTF");
281 		return 0;
282 	}
283 
284 	memcpy(&cth, p, sizeof(struct ctf_header));
285 	if (cth.cth_magic != CTF_MAGIC || cth.cth_version != CTF_VERSION)
286 		return 0;
287 
288 	dlen = cth.cth_stroff + cth.cth_strlen;
289 	if (dlen > filesize && !(cth.cth_flags & CTF_F_COMPRESS)) {
290 		warnx("bogus file size");
291 		return 0;
292 	}
293 
294 	if ((cth.cth_lbloff & 3) || (cth.cth_objtoff & 1) ||
295 	    (cth.cth_funcoff & 1) || (cth.cth_typeoff & 3)) {
296 		warnx("wrongly aligned offset");
297 		return 0;
298 	}
299 
300 	if ((cth.cth_lbloff >= dlen) || (cth.cth_objtoff >= dlen) ||
301 	    (cth.cth_funcoff >= dlen) || (cth.cth_typeoff >= dlen)) {
302 		warnx("truncated file");
303 		return 0;
304 	}
305 
306 	if ((cth.cth_lbloff > cth.cth_objtoff) ||
307 	    (cth.cth_objtoff > cth.cth_funcoff) ||
308 	    (cth.cth_funcoff > cth.cth_typeoff) ||
309 	    (cth.cth_typeoff > cth.cth_stroff)) {
310 		warnx("corrupted file");
311 		return 0;
312 	}
313 
314 	return 1;
315 }
316 
317 int
ctf_dump(const char * p,size_t size,uint8_t flags)318 ctf_dump(const char *p, size_t size, uint8_t flags)
319 {
320 	struct ctf_header	 cth;
321 	size_t			 dlen;
322 	char			*data;
323 
324 	memcpy(&cth, p, sizeof(struct ctf_header));
325 	dlen = cth.cth_stroff + cth.cth_strlen;
326 	if (cth.cth_flags & CTF_F_COMPRESS) {
327 		data = decompress(p + sizeof(cth), size - sizeof(cth), dlen);
328 		if (data == NULL)
329 			return 1;
330 	} else {
331 		data = (char *)p + sizeof(cth);
332 	}
333 
334 	if (flags & DUMP_HEADER) {
335 		printf("  cth_magic    = 0x%04x\n", cth.cth_magic);
336 		printf("  cth_version  = %u\n", cth.cth_version);
337 		printf("  cth_flags    = 0x%02x\n", cth.cth_flags);
338 		printf("  cth_parlabel = %s\n",
339 		    ctf_off2name(&cth, data, dlen, cth.cth_parlabel));
340 		printf("  cth_parname  = %s\n",
341 		    ctf_off2name(&cth, data, dlen, cth.cth_parname));
342 		printf("  cth_lbloff   = %u\n", cth.cth_lbloff);
343 		printf("  cth_objtoff  = %u\n", cth.cth_objtoff);
344 		printf("  cth_funcoff  = %u\n", cth.cth_funcoff);
345 		printf("  cth_typeoff  = %u\n", cth.cth_typeoff);
346 		printf("  cth_stroff   = %u\n", cth.cth_stroff);
347 		printf("  cth_strlen   = %u\n", cth.cth_strlen);
348 		printf("\n");
349 	}
350 
351 	if (flags & DUMP_LABEL) {
352 		uint32_t		 lbloff = cth.cth_lbloff;
353 		struct ctf_lblent	*ctl;
354 
355 		while (lbloff < cth.cth_objtoff) {
356 			ctl = (struct ctf_lblent *)(data + lbloff);
357 
358 			printf("  %5u %s\n", ctl->ctl_typeidx,
359 			    ctf_off2name(&cth, data, dlen, ctl->ctl_label));
360 
361 			lbloff += sizeof(*ctl);
362 		}
363 		printf("\n");
364 	}
365 
366 	if (flags & DUMP_OBJECT) {
367 		uint32_t		 objtoff = cth.cth_objtoff;
368 		size_t			 idx = 0, i = 0;
369 		uint16_t		*dsp;
370 		const char		*s;
371 		int			 l;
372 
373 		while (objtoff < cth.cth_funcoff) {
374 			dsp = (uint16_t *)(data + objtoff);
375 
376 			l = printf("  [%zu] %u", i++, *dsp);
377 			if ((s = elf_idx2sym(&idx, STT_OBJECT)) != NULL)
378 				printf("%*s %s (%zu)\n", (14 - l), "", s, idx);
379 			else
380 				printf("\n");
381 
382 			objtoff += sizeof(*dsp);
383 		}
384 		printf("\n");
385 	}
386 
387 	if (flags & DUMP_FUNCTION) {
388 		uint16_t		*fsp, kind, vlen;
389 		uint16_t		*fstart, *fend;
390 		size_t			 idx = 0, i = -1;
391 		const char		*s;
392 		int			 l;
393 
394 		fstart = (uint16_t *)(data + cth.cth_funcoff);
395 		fend = (uint16_t *)(data + cth.cth_typeoff);
396 
397 		fsp = fstart;
398 		while (fsp < fend) {
399 			kind = CTF_INFO_KIND(*fsp);
400 			vlen = CTF_INFO_VLEN(*fsp);
401 			s = elf_idx2sym(&idx, STT_FUNC);
402 			fsp++;
403 			i++;
404 
405 			if (kind == CTF_K_UNKNOWN && vlen == 0)
406 				continue;
407 
408 			l = printf("  [%zu] FUNC ", i);
409 			if (s != NULL)
410 				printf("(%s) ", s);
411 			printf("returns: %u args: (", *fsp++);
412 			while (vlen-- > 0 && fsp < fend)
413 				printf("%u%s", *fsp++, (vlen > 0) ? ", " : "");
414 			printf(")\n");
415 		}
416 		printf("\n");
417 	}
418 
419 	if (flags & DUMP_TYPE) {
420 		uint32_t		 idx = 1, offset = cth.cth_typeoff;
421 		uint32_t		 stroff = cth.cth_stroff;
422 
423 		while (offset < stroff) {
424 			ctf_dump_type(&cth, data, dlen, stroff, &offset, idx++);
425 		}
426 		printf("\n");
427 	}
428 
429 	if (flags & DUMP_STRTAB) {
430 		uint32_t		 offset = 0;
431 		const char		*str;
432 
433 		while (offset < cth.cth_strlen) {
434 			str = ctf_off2name(&cth, data, dlen, offset);
435 
436 			printf("  [%u] ", offset);
437 			if (strcmp(str, "(anon)"))
438 				offset += printf("%s\n", str);
439 			else {
440 				printf("\\0\n");
441 				offset++;
442 			}
443 		}
444 		printf("\n");
445 	}
446 
447 	if (cth.cth_flags & CTF_F_COMPRESS)
448 		free(data);
449 
450 	return 0;
451 }
452 
453 void
ctf_dump_type(struct ctf_header * cth,const char * data,size_t dlen,uint32_t stroff,uint32_t * offset,uint32_t idx)454 ctf_dump_type(struct ctf_header *cth, const char *data, size_t dlen,
455     uint32_t stroff, uint32_t *offset, uint32_t idx)
456 {
457 	const char		*p = data + *offset;
458 	const struct ctf_type	*ctt = (struct ctf_type *)p;
459 	const struct ctf_array	*cta;
460 	uint16_t		*argp, i, kind, vlen, root;
461 	uint32_t		 eob, toff;
462 	uint64_t		 size;
463 	const char		*name, *kname;
464 
465 	kind = CTF_INFO_KIND(ctt->ctt_info);
466 	vlen = CTF_INFO_VLEN(ctt->ctt_info);
467 	root = CTF_INFO_ISROOT(ctt->ctt_info);
468 	name = ctf_off2name(cth, data, dlen, ctt->ctt_name);
469 
470 	if (root)
471 		printf("  <%u> ", idx);
472 	else
473 		printf("  [%u] ", idx);
474 
475 	if ((kname = ctf_kind2name(kind)) != NULL)
476 		printf("%s %s", kname, name);
477 
478 	if (ctt->ctt_size <= CTF_MAX_SIZE) {
479 		size = ctt->ctt_size;
480 		toff = sizeof(struct ctf_stype);
481 	} else {
482 		size = CTF_TYPE_LSIZE(ctt);
483 		toff = sizeof(struct ctf_type);
484 	}
485 
486 	switch (kind) {
487 	case CTF_K_UNKNOWN:
488 	case CTF_K_FORWARD:
489 		break;
490 	case CTF_K_INTEGER:
491 		eob = *((uint32_t *)(p + toff));
492 		toff += sizeof(uint32_t);
493 		printf(" encoding=%s offset=%u bits=%u (%llu bytes)",
494 		    ctf_enc2name(CTF_INT_ENCODING(eob)), CTF_INT_OFFSET(eob),
495 		    CTF_INT_BITS(eob), size);
496 		break;
497 	case CTF_K_FLOAT:
498 		eob = *((uint32_t *)(p + toff));
499 		toff += sizeof(uint32_t);
500 		printf(" encoding=%s offset=%u bits=%u (%llu bytes)",
501 		    ctf_fpenc2name(CTF_FP_ENCODING(eob)), CTF_FP_OFFSET(eob),
502 		    CTF_FP_BITS(eob), size);
503 		break;
504 	case CTF_K_ARRAY:
505 		cta = (struct ctf_array *)(p + toff);
506 		printf(" content: %u index: %u nelems: %u\n", cta->cta_contents,
507 		    cta->cta_index, cta->cta_nelems);
508 		toff += sizeof(struct ctf_array);
509 		break;
510 	case CTF_K_FUNCTION:
511 		argp = (uint16_t *)(p + toff);
512 		printf(" returns: %u args: (%u", ctt->ctt_type, *argp);
513 		for (i = 1; i < vlen; i++) {
514 			argp++;
515 			if ((const char *)argp > data + dlen)
516 				errx(1, "offset exceeds CTF section");
517 
518 			printf(", %u", *argp);
519 		}
520 		printf(")");
521 		toff += (vlen + (vlen & 1)) * sizeof(uint16_t);
522 		break;
523 	case CTF_K_STRUCT:
524 	case CTF_K_UNION:
525 		printf(" (%llu bytes)\n", size);
526 
527 		if (size < CTF_LSTRUCT_THRESH) {
528 			for (i = 0; i < vlen; i++) {
529 				struct ctf_member	*ctm;
530 
531 				if (p + toff > data + dlen)
532 					errx(1, "offset exceeds CTF section");
533 
534 				if (toff > (stroff - sizeof(*ctm)))
535 					break;
536 
537 				ctm = (struct ctf_member *)(p + toff);
538 				toff += sizeof(struct ctf_member);
539 
540 				printf("\t%s type=%u off=%u\n",
541 				    ctf_off2name(cth, data, dlen,
542 					ctm->ctm_name),
543 				    ctm->ctm_type, ctm->ctm_offset);
544 			}
545 		} else {
546 			for (i = 0; i < vlen; i++) {
547 				struct ctf_lmember	*ctlm;
548 
549 				if (p + toff > data + dlen)
550 					errx(1, "offset exceeds CTF section");
551 
552 				if (toff > (stroff - sizeof(*ctlm)))
553 					break;
554 
555 				ctlm = (struct ctf_lmember *)(p + toff);
556 				toff += sizeof(struct ctf_lmember);
557 
558 				printf("\t%s type=%u off=%llu\n",
559 				    ctf_off2name(cth, data, dlen,
560 					ctlm->ctlm_name),
561 				    ctlm->ctlm_type, CTF_LMEM_OFFSET(ctlm));
562 			}
563 		}
564 		break;
565 	case CTF_K_ENUM:
566 		printf(" (%llu bytes)\n", size);
567 
568 		for (i = 0; i < vlen; i++) {
569 			struct ctf_enum	*cte;
570 
571 			if (p + toff > data + dlen)
572 				errx(1, "offset exceeds CTF section");
573 
574 			if (toff > (stroff - sizeof(*cte)))
575 				break;
576 
577 			cte = (struct ctf_enum *)(p + toff);
578 			toff += sizeof(struct ctf_enum);
579 
580 			printf("\t%s = %d\n",
581 			    ctf_off2name(cth, data, dlen, cte->cte_name),
582 			    cte->cte_value);
583 		}
584 		break;
585 	case CTF_K_POINTER:
586 	case CTF_K_TYPEDEF:
587 	case CTF_K_VOLATILE:
588 	case CTF_K_CONST:
589 	case CTF_K_RESTRICT:
590 		printf(" refers to %u", ctt->ctt_type);
591 		break;
592 	default:
593 		errx(1, "incorrect type %u at offset %u", kind, *offset);
594 	}
595 
596 	printf("\n");
597 
598 	*offset += toff;
599 }
600 
601 const char *
ctf_kind2name(uint16_t kind)602 ctf_kind2name(uint16_t kind)
603 {
604 	static const char *kind_name[] = { NULL, "INTEGER", "FLOAT", "POINTER",
605 	   "ARRAY", "FUNCTION", "STRUCT", "UNION", "ENUM", "FORWARD",
606 	   "TYPEDEF", "VOLATILE", "CONST", "RESTRICT" };
607 
608 	if (kind >= nitems(kind_name))
609 		return NULL;
610 
611 	return kind_name[kind];
612 }
613 
614 const char *
ctf_enc2name(uint16_t enc)615 ctf_enc2name(uint16_t enc)
616 {
617 	static const char *enc_name[] = { "SIGNED", "CHAR", "SIGNED CHAR",
618 	    "BOOL", "SIGNED BOOL" };
619 	static char invalid[7];
620 
621 	if (enc == CTF_INT_VARARGS)
622 		return "VARARGS";
623 
624 	if (enc > 0 && enc <= nitems(enc_name))
625 		return enc_name[enc - 1];
626 
627 	snprintf(invalid, sizeof(invalid), "0x%x", enc);
628 	return invalid;
629 }
630 
631 const char *
ctf_fpenc2name(uint16_t enc)632 ctf_fpenc2name(uint16_t enc)
633 {
634 	static const char *enc_name[] = { "SINGLE", "DOUBLE", NULL, NULL,
635 	    NULL, "LDOUBLE" };
636 	static char invalid[7];
637 
638 	if (enc > 0 && enc <= nitems(enc_name) && enc_name[enc - 1] != NULL)
639 		return enc_name[enc - 1];
640 
641 	snprintf(invalid, sizeof(invalid), "0x%x", enc);
642 	return invalid;
643 }
644 
645 const char *
ctf_off2name(struct ctf_header * cth,const char * data,size_t dlen,uint32_t offset)646 ctf_off2name(struct ctf_header *cth, const char *data, size_t dlen,
647     uint32_t offset)
648 {
649 	const char		*name;
650 
651 	if (CTF_NAME_STID(offset) != CTF_STRTAB_0)
652 		return "external";
653 
654 	if (CTF_NAME_OFFSET(offset) >= cth->cth_strlen)
655 		return "exceeds strlab";
656 
657 	if (cth->cth_stroff + CTF_NAME_OFFSET(offset) >= dlen)
658 		return "invalid";
659 
660 	name = data + cth->cth_stroff + CTF_NAME_OFFSET(offset);
661 	if (*name == '\0')
662 		return "(anon)";
663 
664 	return name;
665 }
666 
667 char *
decompress(const char * buf,size_t size,size_t len)668 decompress(const char *buf, size_t size, size_t len)
669 {
670 #ifdef ZLIB
671 	z_stream		 stream;
672 	char			*data;
673 	int			 error;
674 
675 	data = malloc(len);
676 	if (data == NULL) {
677 		warn(NULL);
678 		return NULL;
679 	}
680 
681 	memset(&stream, 0, sizeof(stream));
682 	stream.next_in = (void *)buf;
683 	stream.avail_in = size;
684 	stream.next_out = (uint8_t *)data;
685 	stream.avail_out = len;
686 
687 	if ((error = inflateInit(&stream)) != Z_OK) {
688 		warnx("zlib inflateInit failed: %s", zError(error));
689 		goto exit;
690 	}
691 
692 	if ((error = inflate(&stream, Z_FINISH)) != Z_STREAM_END) {
693 		warnx("zlib inflate failed: %s", zError(error));
694 		inflateEnd(&stream);
695 		goto exit;
696 	}
697 
698 	if ((error = inflateEnd(&stream)) != Z_OK) {
699 		warnx("zlib inflateEnd failed: %s", zError(error));
700 		goto exit;
701 	}
702 
703 	if (stream.total_out != len) {
704 		warnx("decompression failed: %lu != %zu",
705 		    stream.total_out, len);
706 		goto exit;
707 	}
708 
709 	return data;
710 
711 exit:
712 	free(data);
713 #endif /* ZLIB */
714 	return NULL;
715 }
716 
717 __dead void
usage(void)718 usage(void)
719 {
720 	fprintf(stderr, "usage: %s [-dfhlst] file ...\n",
721 	    getprogname());
722 	exit(1);
723 }
724