xref: /openbsd/usr.bin/ctfdump/ctfdump.c (revision 09467b48)
1 /*	$OpenBSD: ctfdump.c,v 1.24 2019/09/03 10:32:15 mpi 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 *, off_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 *, off_t,
62 		     uint32_t);
63 
64 char		*decompress(const char *, size_t, off_t);
65 int		 elf_dump(uint8_t);
66 const char	*elf_idx2sym(size_t *, uint8_t);
67 
68 int
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
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 *
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
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
274 isctf(const char *p, size_t filesize)
275 {
276 	struct ctf_header	*cth = (struct ctf_header *)p;
277 	off_t 			 dlen;
278 
279 	if (filesize < sizeof(struct ctf_header)) {
280 		warnx("file too small to be CTF");
281 		return 0;
282 	}
283 
284 	if (cth->cth_magic != CTF_MAGIC || cth->cth_version != CTF_VERSION)
285 		return 0;
286 
287 	dlen = (off_t)cth->cth_stroff + cth->cth_strlen;
288 	if (dlen > (off_t)filesize && !(cth->cth_flags & CTF_F_COMPRESS)) {
289 		warnx("bogus file size");
290 		return 0;
291 	}
292 
293 	if ((cth->cth_lbloff & 3) || (cth->cth_objtoff & 1) ||
294 	    (cth->cth_funcoff & 1) || (cth->cth_typeoff & 3)) {
295 		warnx("wrongly aligned offset");
296 		return 0;
297 	}
298 
299 	if ((cth->cth_lbloff >= dlen) || (cth->cth_objtoff >= dlen) ||
300 	    (cth->cth_funcoff >= dlen) || (cth->cth_typeoff >= dlen)) {
301 		warnx("truncated file");
302 		return 0;
303 	}
304 
305 	if ((cth->cth_lbloff > cth->cth_objtoff) ||
306 	    (cth->cth_objtoff > cth->cth_funcoff) ||
307 	    (cth->cth_funcoff > cth->cth_typeoff) ||
308 	    (cth->cth_typeoff > cth->cth_stroff)) {
309 		warnx("corrupted file");
310 		return 0;
311 	}
312 
313 	return 1;
314 }
315 
316 int
317 ctf_dump(const char *p, size_t size, uint8_t flags)
318 {
319 	struct ctf_header	*cth = (struct ctf_header *)p;
320 	off_t 			 dlen;
321 	char			*data;
322 
323 	dlen = (off_t)cth->cth_stroff + cth->cth_strlen;
324 	if (cth->cth_flags & CTF_F_COMPRESS) {
325 		data = decompress(p + sizeof(*cth), size - sizeof(*cth), dlen);
326 		if (data == NULL)
327 			return 1;
328 	} else {
329 		data = (char *)p + sizeof(*cth);
330 	}
331 
332 	if (flags & DUMP_HEADER) {
333 		printf("  cth_magic    = 0x%04x\n", cth->cth_magic);
334 		printf("  cth_version  = %u\n", cth->cth_version);
335 		printf("  cth_flags    = 0x%02x\n", cth->cth_flags);
336 		printf("  cth_parlabel = %s\n",
337 		    ctf_off2name(cth, data, dlen, cth->cth_parlabel));
338 		printf("  cth_parname  = %s\n",
339 		    ctf_off2name(cth, data, dlen, cth->cth_parname));
340 		printf("  cth_lbloff   = %u\n", cth->cth_lbloff);
341 		printf("  cth_objtoff  = %u\n", cth->cth_objtoff);
342 		printf("  cth_funcoff  = %u\n", cth->cth_funcoff);
343 		printf("  cth_typeoff  = %u\n", cth->cth_typeoff);
344 		printf("  cth_stroff   = %u\n", cth->cth_stroff);
345 		printf("  cth_strlen   = %u\n", cth->cth_strlen);
346 		printf("\n");
347 	}
348 
349 	if (flags & DUMP_LABEL) {
350 		uint32_t		 lbloff = cth->cth_lbloff;
351 		struct ctf_lblent	*ctl;
352 
353 		while (lbloff < cth->cth_objtoff) {
354 			ctl = (struct ctf_lblent *)(data + lbloff);
355 
356 			printf("  %5u %s\n", ctl->ctl_typeidx,
357 			    ctf_off2name(cth, data, dlen, ctl->ctl_label));
358 
359 			lbloff += sizeof(*ctl);
360 		}
361 		printf("\n");
362 	}
363 
364 	if (flags & DUMP_OBJECT) {
365 		uint32_t		 objtoff = cth->cth_objtoff;
366 		size_t			 idx = 0, i = 0;
367 		uint16_t		*dsp;
368 		const char		*s;
369 		int			 l;
370 
371 		while (objtoff < cth->cth_funcoff) {
372 			dsp = (uint16_t *)(data + objtoff);
373 
374 			l = printf("  [%zu] %u", i++, *dsp);
375 			if ((s = elf_idx2sym(&idx, STT_OBJECT)) != NULL)
376 				printf("%*s %s (%zu)\n", (14 - l), "", s, idx);
377 			else
378 				printf("\n");
379 
380 			objtoff += sizeof(*dsp);
381 		}
382 		printf("\n");
383 	}
384 
385 	if (flags & DUMP_FUNCTION) {
386 		uint16_t		*fsp, kind, vlen;
387 		uint16_t		*fstart, *fend;
388 		size_t			 idx = 0, i = -1;
389 		const char		*s;
390 		int			 l;
391 
392 		fstart = (uint16_t *)(data + cth->cth_funcoff);
393 		fend = (uint16_t *)(data + cth->cth_typeoff);
394 
395 		fsp = fstart;
396 		while (fsp < fend) {
397 			kind = CTF_INFO_KIND(*fsp);
398 			vlen = CTF_INFO_VLEN(*fsp);
399 			s = elf_idx2sym(&idx, STT_FUNC);
400 			fsp++;
401 			i++;
402 
403 			if (kind == CTF_K_UNKNOWN && vlen == 0)
404 				continue;
405 
406 			l = printf("  [%zu] FUNC ", i);
407 			if (s != NULL)
408 				printf("(%s) ", s);
409 			printf("returns: %u args: (", *fsp++);
410 			while (vlen-- > 0 && fsp < fend)
411 				printf("%u%s", *fsp++, (vlen > 0) ? ", " : "");
412 			printf(")\n");
413 		}
414 		printf("\n");
415 	}
416 
417 	if (flags & DUMP_TYPE) {
418 		uint32_t		 idx = 1, offset = cth->cth_typeoff;
419 		uint32_t		 stroff = cth->cth_stroff;
420 
421 		while (offset < stroff) {
422 			ctf_dump_type(cth, data, dlen, stroff, &offset, idx++);
423 		}
424 		printf("\n");
425 	}
426 
427 	if (flags & DUMP_STRTAB) {
428 		uint32_t		 offset = 0;
429 		const char		*str;
430 
431 		while (offset < cth->cth_strlen) {
432 			str = ctf_off2name(cth, data, dlen, offset);
433 
434 			printf("  [%u] ", offset);
435 			if (strcmp(str, "(anon)"))
436 				offset += printf("%s\n", str);
437 			else {
438 				printf("\\0\n");
439 				offset++;
440 			}
441 		}
442 		printf("\n");
443 	}
444 
445 	if (cth->cth_flags & CTF_F_COMPRESS)
446 		free(data);
447 
448 	return 0;
449 }
450 
451 void
452 ctf_dump_type(struct ctf_header *cth, const char *data, off_t dlen,
453     uint32_t stroff, uint32_t *offset, uint32_t idx)
454 {
455 	const char		*p = data + *offset;
456 	const struct ctf_type	*ctt = (struct ctf_type *)p;
457 	const struct ctf_array	*cta;
458 	uint16_t		*argp, i, kind, vlen, root;
459 	uint32_t		 eob, toff;
460 	uint64_t		 size;
461 	const char		*name, *kname;
462 
463 	kind = CTF_INFO_KIND(ctt->ctt_info);
464 	vlen = CTF_INFO_VLEN(ctt->ctt_info);
465 	root = CTF_INFO_ISROOT(ctt->ctt_info);
466 	name = ctf_off2name(cth, data, dlen, ctt->ctt_name);
467 
468 	if (root)
469 		printf("  <%u> ", idx);
470 	else
471 		printf("  [%u] ", idx);
472 
473 	if ((kname = ctf_kind2name(kind)) != NULL)
474 		printf("%s %s", kname, name);
475 
476 	if (ctt->ctt_size <= CTF_MAX_SIZE) {
477 		size = ctt->ctt_size;
478 		toff = sizeof(struct ctf_stype);
479 	} else {
480 		size = CTF_TYPE_LSIZE(ctt);
481 		toff = sizeof(struct ctf_type);
482 	}
483 
484 	switch (kind) {
485 	case CTF_K_UNKNOWN:
486 	case CTF_K_FORWARD:
487 		break;
488 	case CTF_K_INTEGER:
489 		eob = *((uint32_t *)(p + toff));
490 		toff += sizeof(uint32_t);
491 		printf(" encoding=%s offset=%u bits=%u",
492 		    ctf_enc2name(CTF_INT_ENCODING(eob)), CTF_INT_OFFSET(eob),
493 		    CTF_INT_BITS(eob));
494 		break;
495 	case CTF_K_FLOAT:
496 		eob = *((uint32_t *)(p + toff));
497 		toff += sizeof(uint32_t);
498 		printf(" encoding=%s offset=%u bits=%u",
499 		    ctf_fpenc2name(CTF_FP_ENCODING(eob)), CTF_FP_OFFSET(eob),
500 		    CTF_FP_BITS(eob));
501 		break;
502 	case CTF_K_ARRAY:
503 		cta = (struct ctf_array *)(p + toff);
504 		printf(" content: %u index: %u nelems: %u\n", cta->cta_contents,
505 		    cta->cta_index, cta->cta_nelems);
506 		toff += sizeof(struct ctf_array);
507 		break;
508 	case CTF_K_FUNCTION:
509 		argp = (uint16_t *)(p + toff);
510 		printf(" returns: %u args: (%u", ctt->ctt_type, *argp);
511 		for (i = 1; i < vlen; i++) {
512 			argp++;
513 			if ((const char *)argp > data + dlen)
514 				errx(1, "offset exceeds CTF section");
515 
516 			printf(", %u", *argp);
517 		}
518 		printf(")");
519 		toff += (vlen + (vlen & 1)) * sizeof(uint16_t);
520 		break;
521 	case CTF_K_STRUCT:
522 	case CTF_K_UNION:
523 		printf(" (%llu bytes)\n", size);
524 
525 		if (size < CTF_LSTRUCT_THRESH) {
526 			for (i = 0; i < vlen; i++) {
527 				struct ctf_member	*ctm;
528 
529 				if (p + toff > data + dlen)
530 					errx(1, "offset exceeds CTF section");
531 
532 				if (toff > (stroff - sizeof(*ctm)))
533 					break;
534 
535 				ctm = (struct ctf_member *)(p + toff);
536 				toff += sizeof(struct ctf_member);
537 
538 				printf("\t%s type=%u off=%u\n",
539 				    ctf_off2name(cth, data, dlen,
540 					ctm->ctm_name),
541 				    ctm->ctm_type, ctm->ctm_offset);
542 			}
543 		} else {
544 			for (i = 0; i < vlen; i++) {
545 				struct ctf_lmember	*ctlm;
546 
547 				if (p + toff > data + dlen)
548 					errx(1, "offset exceeds CTF section");
549 
550 				if (toff > (stroff - sizeof(*ctlm)))
551 					break;
552 
553 				ctlm = (struct ctf_lmember *)(p + toff);
554 				toff += sizeof(struct ctf_lmember);
555 
556 				printf("\t%s type=%u off=%llu\n",
557 				    ctf_off2name(cth, data, dlen,
558 					ctlm->ctlm_name),
559 				    ctlm->ctlm_type, CTF_LMEM_OFFSET(ctlm));
560 			}
561 		}
562 		break;
563 	case CTF_K_ENUM:
564 		printf("\n");
565 		for (i = 0; i < vlen; i++) {
566 			struct ctf_enum	*cte;
567 
568 			if (p + toff > data + dlen)
569 				errx(1, "offset exceeds CTF section");
570 
571 			if (toff > (stroff - sizeof(*cte)))
572 				break;
573 
574 			cte = (struct ctf_enum *)(p + toff);
575 			toff += sizeof(struct ctf_enum);
576 
577 			printf("\t%s = %d\n",
578 			    ctf_off2name(cth, data, dlen, cte->cte_name),
579 			    cte->cte_value);
580 		}
581 		break;
582 	case CTF_K_POINTER:
583 	case CTF_K_TYPEDEF:
584 	case CTF_K_VOLATILE:
585 	case CTF_K_CONST:
586 	case CTF_K_RESTRICT:
587 		printf(" refers to %u", ctt->ctt_type);
588 		break;
589 	default:
590 		errx(1, "incorrect type %u at offset %u", kind, *offset);
591 	}
592 
593 	printf("\n");
594 
595 	*offset += toff;
596 }
597 
598 const char *
599 ctf_kind2name(uint16_t kind)
600 {
601 	static const char *kind_name[] = { NULL, "INTEGER", "FLOAT", "POINTER",
602 	   "ARRAY", "FUNCTION", "STRUCT", "UNION", "ENUM", "FORWARD",
603 	   "TYPEDEF", "VOLATILE", "CONST", "RESTRICT" };
604 
605 	if (kind >= nitems(kind_name))
606 		return NULL;
607 
608 	return kind_name[kind];
609 }
610 
611 const char *
612 ctf_enc2name(uint16_t enc)
613 {
614 	static const char *enc_name[] = { "SIGNED", "CHAR", "SIGNED CHAR",
615 	    "BOOL", "SIGNED BOOL" };
616 	static char invalid[7];
617 
618 	if (enc == CTF_INT_VARARGS)
619 		return "VARARGS";
620 
621 	if (enc > 0 && enc <= nitems(enc_name))
622 		return enc_name[enc - 1];
623 
624 	snprintf(invalid, sizeof(invalid), "0x%x", enc);
625 	return invalid;
626 }
627 
628 const char *
629 ctf_fpenc2name(uint16_t enc)
630 {
631 	static const char *enc_name[] = { "SINGLE", "DOUBLE", NULL, NULL,
632 	    NULL, "LDOUBLE" };
633 	static char invalid[7];
634 
635 	if (enc > 0 && enc <= nitems(enc_name) && enc_name[enc - 1] != NULL)
636 		return enc_name[enc - 1];
637 
638 	snprintf(invalid, sizeof(invalid), "0x%x", enc);
639 	return invalid;
640 }
641 
642 const char *
643 ctf_off2name(struct ctf_header *cth, const char *data, off_t dlen,
644     uint32_t offset)
645 {
646 	const char		*name;
647 
648 	if (CTF_NAME_STID(offset) != CTF_STRTAB_0)
649 		return "external";
650 
651 	if (CTF_NAME_OFFSET(offset) >= cth->cth_strlen)
652 		return "exceeds strlab";
653 
654 	if (cth->cth_stroff + CTF_NAME_OFFSET(offset) >= dlen)
655 		return "invalid";
656 
657 	name = data + cth->cth_stroff + CTF_NAME_OFFSET(offset);
658 	if (*name == '\0')
659 		return "(anon)";
660 
661 	return name;
662 }
663 
664 char *
665 decompress(const char *buf, size_t size, off_t len)
666 {
667 #ifdef ZLIB
668 	z_stream		 stream;
669 	char			*data;
670 	int			 error;
671 
672 	data = malloc(len);
673 	if (data == NULL) {
674 		warn(NULL);
675 		return NULL;
676 	}
677 
678 	memset(&stream, 0, sizeof(stream));
679 	stream.next_in = (void *)buf;
680 	stream.avail_in = size;
681 	stream.next_out = (uint8_t *)data;
682 	stream.avail_out = len;
683 
684 	if ((error = inflateInit(&stream)) != Z_OK) {
685 		warnx("zlib inflateInit failed: %s", zError(error));
686 		goto exit;
687 	}
688 
689 	if ((error = inflate(&stream, Z_FINISH)) != Z_STREAM_END) {
690 		warnx("zlib inflate failed: %s", zError(error));
691 		inflateEnd(&stream);
692 		goto exit;
693 	}
694 
695 	if ((error = inflateEnd(&stream)) != Z_OK) {
696 		warnx("zlib inflateEnd failed: %s", zError(error));
697 		goto exit;
698 	}
699 
700 	if (stream.total_out != len) {
701 		warnx("decompression failed: %llu != %llu",
702 		    stream.total_out, len);
703 		goto exit;
704 	}
705 
706 	return data;
707 
708 exit:
709 	free(data);
710 #endif /* ZLIB */
711 	return NULL;
712 }
713 
714 __dead void
715 usage(void)
716 {
717 	fprintf(stderr, "usage: %s [-dfhlst] file ...\n",
718 	    getprogname());
719 	exit(1);
720 }
721