Initialize offset correctly when dumping types.
[ctfdump/.git] / ctfdump.c
CommitLineData
f8621c6a
MP
1/*
2 * Copyright (c) 2016 Martin Pieuchot <mpi@openbsd.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <sys/param.h>
18#include <sys/types.h>
19#include <sys/stat.h>
20#include <sys/exec_elf.h>
21#include <sys/mman.h>
37e1dc0c 22#include <sys/ctf.h>
f8621c6a
MP
23
24#include <err.h>
25#include <fcntl.h>
26#include <locale.h>
27#include <stdio.h>
28#include <stdint.h>
29#include <stdlib.h>
30#include <string.h>
31#include <unistd.h>
32
33#ifdef ZLIB
34#include <zlib.h>
35#endif /* ZLIB */
36
74b86e22
MP
37#ifndef nitems
38#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
39#endif
40
f8621c6a
MP
41#define DUMP_OBJECT (1 << 0)
42#define DUMP_FUNCTION (1 << 1)
43#define DUMP_HEADER (1 << 2)
751fc09a 44#define DUMP_LABEL (1 << 3)
80c28199 45#define DUMP_STRTAB (1 << 4)
74b86e22
MP
46#define DUMP_STATISTIC (1 << 5)
47#define DUMP_TYPE (1 << 6)
f8621c6a 48
c1bd258a 49int dump(const char *, uint8_t);
f8621c6a
MP
50int isctf(const char *, size_t);
51__dead void usage(void);
52
c1bd258a 53int ctf_dump(const char *, size_t, uint8_t);
74b86e22
MP
54unsigned int ctf_dump_type(struct ctf_header *, const char *, off_t,
55 unsigned int, unsigned int);
56const char *ctf_kind2name(unsigned short);
f8621c6a
MP
57const char *ctf_off2name(struct ctf_header *, const char *, off_t,
58 unsigned int);
59
c1bd258a 60int elf_dump(const char *, size_t, uint8_t);
c36bfc0c
MP
61const char *elf_idx2sym(size_t *, unsigned char);
62
63/* elf.c */
64int iself(const char *, size_t);
f8621c6a
MP
65int elf_getshstrtab(const char *, size_t, const char **, size_t *);
66int elf_getsymtab(const char *, const char *, size_t,
67 const Elf_Sym **, size_t *);
2ef38d60
MP
68int elf_getsection(const char *, const char *, const char *,
69 size_t, const char **, size_t *);
f8621c6a
MP
70
71#ifdef ZLIB
72char *decompress(const char *, size_t, off_t);
73#endif /* ZLIB */
74
75int
76main(int argc, char *argv[])
77{
78 const char *filename;
c1bd258a 79 uint8_t flags = 0;
f8621c6a
MP
80 int ch, error = 0;
81
82 setlocale(LC_ALL, "");
83
53477564 84 while ((ch = getopt(argc, argv, "dfhlst")) != -1) {
f8621c6a 85 switch (ch) {
9fe3b2c8
MP
86 case 'd':
87 flags |= DUMP_OBJECT;
88 break;
acada86d
MP
89 case 'f':
90 flags |= DUMP_FUNCTION;
91 break;
f8621c6a
MP
92 case 'h':
93 flags |= DUMP_HEADER;
94 break;
751fc09a
MP
95 case 'l':
96 flags |= DUMP_LABEL;
97 break;
80c28199
MP
98 case 's':
99 flags |= DUMP_STRTAB;
100 break;
74b86e22
MP
101 case 't':
102 flags |= DUMP_TYPE;
103 break;
f8621c6a
MP
104 default:
105 usage();
106 }
107 }
108
109 argc -= optind;
110 argv += optind;
111
c1bd258a
MP
112 /* Dump everything by default */
113 if (flags == 0)
114 flags = 0xff;
115
f8621c6a
MP
116 while ((filename = *argv++) != NULL)
117 error |= dump(filename, flags);
118
119 return error;
120}
121
122int
c1bd258a 123dump(const char *path, uint8_t flags)
f8621c6a
MP
124{
125 struct stat st;
126 int fd, error = 1;
127 char *p;
128
129 fd = open(path, O_RDONLY);
130 if (fd == -1) {
131 warn("open");
132 return 1;
133 }
134 if (fstat(fd, &st) == -1) {
135 warn("fstat");
136 return 1;
137 }
138 if (st.st_size < (off_t)sizeof(struct ctf_header)) {
139 warnx("file too small to be CTF");
140 return 1;
141 }
142 if ((uintmax_t)st.st_size > SIZE_MAX) {
143 warnx("file too big to fit memory");
144 return 1;
145 }
146
147 p = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
148 if (p == MAP_FAILED)
149 err(1, "mmap");
150
151 if (iself(p, st.st_size)) {
152 error = elf_dump(p, st.st_size, flags);
153 } else if (isctf(p, st.st_size)) {
154 error = ctf_dump(p, st.st_size, flags);
155 }
156
157 munmap(p, st.st_size);
158 close(fd);
159
160 return error;
161}
162
f8621c6a
MP
163const char *strtab;
164const Elf_Sym *symtab;
165size_t strtabsize, nsymb;
166
9fe3b2c8
MP
167const char *
168elf_idx2sym(size_t *idx, unsigned char type)
169{
170 const Elf_Sym *st;
171 size_t i;
172
173 for (i = *idx + 1; i < nsymb; i++) {
174 st = &symtab[i];
175
176 if (ELF_ST_TYPE(st->st_info) != type)
177 continue;
178
179 *idx = i;
180 return strtab + st->st_name;
181 }
182
183 return NULL;
184}
185
f8621c6a 186int
c1bd258a 187elf_dump(const char *p, size_t filesize, uint8_t flags)
f8621c6a
MP
188{
189 Elf_Ehdr *eh = (Elf_Ehdr *)p;
190 Elf_Shdr *sh;
191 const char *shstrtab;
192 size_t i, shstrtabsize;
193
194 /* Find section header string table location and size. */
195 if (elf_getshstrtab(p, filesize, &shstrtab, &shstrtabsize))
196 return 1;
197
198 /* Find symbol table location and number of symbols. */
199 if (elf_getsymtab(p, shstrtab, shstrtabsize, &symtab, &nsymb))
200 warnx("symbol table not found");
201
202 /* Find string table location and size. */
2ef38d60 203 if (elf_getsection(p, ELF_STRTAB, shstrtab, shstrtabsize, &strtab, &strtabsize))
f8621c6a
MP
204 warnx("string table not found");
205
206 /* Find CTF section and dump it. */
207 for (i = 0; i < eh->e_shnum; i++) {
208 sh = (Elf_Shdr *)(p + eh->e_shoff + i * eh->e_shentsize);
209
210 if ((sh->sh_link >= eh->e_shnum) ||
211 (sh->sh_name >= shstrtabsize))
212 continue;
213
6d70f1d9 214 if (strncmp(shstrtab + sh->sh_name, ELF_CTF, strlen(ELF_CTF)))
f8621c6a
MP
215 continue;
216
217 if (!isctf(p + sh->sh_offset, sh->sh_size))
218 break;
219
220 return ctf_dump(p + sh->sh_offset, sh->sh_size, flags);
221 }
222
6d70f1d9 223 warnx("%s section not found", ELF_CTF);
f8621c6a
MP
224 return 1;
225}
226
227int
228isctf(const char *p, size_t filesize)
229{
230 struct ctf_header *cth = (struct ctf_header *)p;
231 off_t dlen = cth->cth_stroff + cth->cth_strlen;
232
233 if (cth->cth_magic != CTF_MAGIC || cth->cth_version != CTF_VERSION)
234 return 0;
235
236 if (dlen > filesize && !(cth->cth_flags & CTF_F_COMPRESS)) {
237 warnx("bogus file size");
238 return 0;
239 }
240
241 if ((cth->cth_lbloff & 3) || (cth->cth_objtoff & 1) ||
242 (cth->cth_funcoff & 1) || (cth->cth_typeoff & 3)) {
243 warnx("wrongly aligned offset");
244 return 0;
245 }
246
247 if ((cth->cth_lbloff >= dlen) || (cth->cth_objtoff >= dlen) ||
248 (cth->cth_funcoff >= dlen) || (cth->cth_typeoff >= dlen)) {
249 warnx("truncated file");
250 return 0;
251 }
252
253 if ((cth->cth_lbloff > cth->cth_objtoff) ||
254 (cth->cth_objtoff > cth->cth_funcoff) ||
255 (cth->cth_funcoff > cth->cth_typeoff) ||
256 (cth->cth_typeoff > cth->cth_stroff)) {
257 warnx("corrupted file");
258 return 0;
259 }
260
261 return 1;
262}
263
264int
c1bd258a 265ctf_dump(const char *p, size_t size, uint8_t flags)
f8621c6a
MP
266{
267 struct ctf_header *cth = (struct ctf_header *)p;
f8621c6a 268 off_t dlen = cth->cth_stroff + cth->cth_strlen;
b51bd0d8 269 char *data;
f8621c6a
MP
270
271 if (cth->cth_flags & CTF_F_COMPRESS) {
272 data = decompress(p + sizeof(*cth), size - sizeof(*cth), dlen);
273 if (data == NULL)
274 return 1;
b51bd0d8
MP
275 } else {
276 data = (char *)p + sizeof(*cth);
f8621c6a
MP
277 }
278
279 if (flags & DUMP_HEADER) {
6befd992
MP
280 printf(" cth_magic = 0x%04x\n", cth->cth_magic);
281 printf(" cth_version = %d\n", cth->cth_version);
282 printf(" cth_flags = 0x%02x\n", cth->cth_flags);
283 printf(" cth_parlabel = %s\n",
f8621c6a 284 ctf_off2name(cth, data, dlen, cth->cth_parname));
6befd992 285 printf(" cth_parname = %s\n",
f8621c6a 286 ctf_off2name(cth, data, dlen, cth->cth_parname));
6befd992
MP
287 printf(" cth_lbloff = %d\n", cth->cth_lbloff);
288 printf(" cth_objtoff = %d\n", cth->cth_objtoff);
289 printf(" cth_funcoff = %d\n", cth->cth_funcoff);
290 printf(" cth_typeoff = %d\n", cth->cth_typeoff);
291 printf(" cth_stroff = %d\n", cth->cth_stroff);
292 printf(" cth_strlen = %d\n", cth->cth_strlen);
293 printf("\n");
f8621c6a
MP
294 }
295
751fc09a
MP
296 if (flags & DUMP_LABEL) {
297 unsigned int lbloff = cth->cth_lbloff;
298 struct ctf_lblent *ctl;
299
300 while (lbloff < cth->cth_objtoff) {
301 ctl = (struct ctf_lblent *)(data + lbloff);
302
6befd992 303 printf(" %5u %s\n", ctl->ctl_typeidx,
751fc09a
MP
304 ctf_off2name(cth, data, dlen, ctl->ctl_label));
305
306 lbloff += sizeof(*ctl);
307 }
6befd992 308 printf("\n");
751fc09a
MP
309 }
310
9fe3b2c8
MP
311 if (flags & DUMP_OBJECT) {
312 unsigned int objtoff = cth->cth_objtoff;
313 size_t idx = 0, i = 0;
314 unsigned short *dsp;
315 const char *s;
316 int l;
317
318 while (objtoff < cth->cth_funcoff) {
319 dsp = (unsigned short *)(data + objtoff);
320
6befd992 321 l = printf(" [%zu] %u", i++, *dsp);
9fe3b2c8 322 if ((s = elf_idx2sym(&idx, STT_OBJECT)) != NULL)
86e1759d 323 printf("%*s %s (%zu)\n", (14 - l), "", s, idx);
9fe3b2c8
MP
324 else
325 printf("\n");
326
327 objtoff += sizeof(*dsp);
328 }
ac25938b 329 printf("\n");
9fe3b2c8
MP
330 }
331
acada86d
MP
332 if (flags & DUMP_FUNCTION) {
333 unsigned short *fsp, kind, vlen;
ae3b8a21 334 size_t idx = 0, i = -1;
acada86d
MP
335 const char *s;
336 int l;
337
338 fsp = (unsigned short *)(data + cth->cth_funcoff);
339 while (fsp < (unsigned short *)(data + cth->cth_typeoff)) {
340 kind = CTF_INFO_KIND(*fsp);
341 vlen = CTF_INFO_VLEN(*fsp);
ae3b8a21 342 s = elf_idx2sym(&idx, STT_FUNC);
acada86d 343 fsp++;
ae3b8a21 344 i++;
acada86d
MP
345
346 if (kind == CTF_K_UNKNOWN && vlen == 0)
347 continue;
348
ae3b8a21
MP
349 l = printf(" [%zu] FUNC ", i);
350 if (s != NULL)
86e1759d 351 printf("(%s)", s);
acada86d
MP
352 printf(" returns: %u args: (", *fsp++);
353 while (vlen-- > 0)
354 printf("%u%s", *fsp++, (vlen > 0) ? ", " : "");
355 printf(")\n");
356 }
6befd992 357 printf("\n");
acada86d
MP
358 }
359
80c28199
MP
360 if (flags & DUMP_STRTAB) {
361 unsigned int offset = 0;
362 const char *str;
363
364 while (offset < cth->cth_strlen) {
3093320c 365 str = ctf_off2name(cth, data, dlen, offset);
80c28199 366
6befd992 367 printf(" [%u] ", offset);
3093320c 368 if (strcmp(str, "(anon)"))
80c28199
MP
369 offset += printf("%s\n", str);
370 else {
371 printf("\\0\n");
372 offset++;
373 }
374 }
6befd992 375 printf("\n");
80c28199
MP
376 }
377
74b86e22 378 if (flags & DUMP_TYPE) {
5cae2a5e 379 unsigned int idx = 1, offset = cth->cth_typeoff;
74b86e22 380
6befd992 381 while (offset < cth->cth_stroff) {
74b86e22 382 offset += ctf_dump_type(cth, data, dlen, offset, idx++);
6befd992
MP
383 }
384 printf("\n");
74b86e22
MP
385 }
386
f8621c6a
MP
387 if (cth->cth_flags & CTF_F_COMPRESS)
388 free(data);
389
390 return 0;
391}
392
74b86e22
MP
393unsigned int
394ctf_dump_type(struct ctf_header *cth, const char *data, off_t dlen,
395 unsigned int offset, unsigned int idx)
396{
5cae2a5e 397 const char *p = data + offset;
23543ec6
MP
398 const struct ctf_type *ctt = (struct ctf_type *)p;
399 unsigned short i, kind, vlen, root;
400 unsigned int eob, toff;
74b86e22
MP
401 uint64_t size;
402 const char *name, *kname;
403
74b86e22
MP
404 kind = CTF_INFO_KIND(ctt->ctt_info);
405 vlen = CTF_INFO_VLEN(ctt->ctt_info);
406 root = CTF_INFO_ISROOT(ctt->ctt_info);
407 name = ctf_off2name(cth, data, dlen, ctt->ctt_name);
408
409 if (root)
6befd992 410 printf(" <%u> ", idx);
74b86e22 411 else
6befd992 412 printf(" [%u] ", idx);
74b86e22
MP
413
414 if ((kname = ctf_kind2name(kind)) != NULL)
415 printf("%s %s", kname, name);
416
417 if (ctt->ctt_size <= CTF_MAX_SIZE) {
418 size = ctt->ctt_size;
419 toff = sizeof(struct ctf_stype);
420 } else {
421 size = CTF_TYPE_LSIZE(ctt);
422 toff = sizeof(struct ctf_type);
423 }
424
425 switch (kind) {
426 case CTF_K_UNKNOWN:
427 case CTF_K_FORWARD:
428 break;
429 case CTF_K_INTEGER:
23543ec6
MP
430 eob = *((unsigned int *)((char *)ctt + toff));
431 toff += sizeof(unsigned int);
432 printf(" encoding=0x%x offset=%u bits=%u",
433 CTF_INT_ENCODING(eob), CTF_INT_OFFSET(eob),
434 CTF_INT_BITS(eob));
74b86e22
MP
435 break;
436 case CTF_K_FLOAT:
23543ec6
MP
437 eob = *((unsigned int *)((char *)ctt + toff));
438 toff += sizeof(unsigned int);
439 printf(" encoding=0x%x offset=%u bits=%u",
440 CTF_FP_ENCODING(eob), CTF_FP_OFFSET(eob), CTF_FP_BITS(eob));
74b86e22
MP
441 break;
442 case CTF_K_ARRAY:
23543ec6 443 toff += sizeof(struct ctf_array);
74b86e22
MP
444 break;
445 case CTF_K_FUNCTION:
23543ec6 446 toff += (vlen + (vlen & 1)) * sizeof(unsigned short);
74b86e22
MP
447 break;
448 case CTF_K_STRUCT:
449 case CTF_K_UNION:
23543ec6
MP
450 printf(" (%llu bytes)\n", size);
451
452 if (size < CTF_LSTRUCT_THRESH) {
453 for (i = 0; i < vlen; i++) {
454 struct ctf_member *ctm;
455
456 ctm = (struct ctf_member *)(p + toff);
457 toff += sizeof(struct ctf_member);
458
459 printf("\t%s type=%u off=%u\n",
460 ctf_off2name(cth, data, dlen,
461 ctm->ctm_name),
462 ctm->ctm_type, ctm->ctm_offset);
463 }
464 } else {
465 for (i = 0; i < vlen; i++) {
466 struct ctf_lmember *ctlm;
467
468 ctlm = (struct ctf_lmember *)(p + toff);
469 toff += sizeof(struct ctf_lmember);
470
471 printf("\t%s type=%u off=%llu\n",
472 ctf_off2name(cth, data, dlen,
473 ctlm->ctlm_name),
474 ctlm->ctlm_type, CTF_LMEM_OFFSET(ctlm));
475 }
476 }
74b86e22
MP
477 break;
478 case CTF_K_ENUM:
23543ec6
MP
479 printf("\n");
480 for (i = 0; i < vlen; i++) {
481 struct ctf_enum *cte;
482
483 cte = (struct ctf_enum *)(p + toff);
484 toff += sizeof(struct ctf_enum);
485
486 printf("\t%s = %u\n",
487 ctf_off2name(cth, data, dlen, cte->cte_name),
488 cte->cte_value);
489 }
74b86e22
MP
490 break;
491 case CTF_K_POINTER:
74b86e22
MP
492 case CTF_K_TYPEDEF:
493 case CTF_K_VOLATILE:
494 case CTF_K_CONST:
495 case CTF_K_RESTRICT:
496 printf(" refers to %u", ctt->ctt_type);
497 break;
498 default:
499 errx(1, "incorrect type %u at offset %u", kind, offset);
500 }
501
502 printf("\n");
503
23543ec6 504 return toff;
74b86e22
MP
505}
506
507const char *
508ctf_kind2name(unsigned short kind)
509{
510 static const char *kind_name[] = { NULL, "INTEGER", "FLOAT", "POINTER",
511 "ARRAYS", "FUNCTION", "STRUCT", "UNION", "ENUM", "FORWARD",
512 "TYPEDEF", "VOLATILE", "CONST", "RESTRICT" };
513
514 if (kind >= nitems(kind_name))
515 return NULL;
516
517 return kind_name[kind];
518}
519
f8621c6a
MP
520const char *
521ctf_off2name(struct ctf_header *cth, const char *data, off_t dlen,
522 unsigned int offset)
523{
524 const char *name;
525
526 if (CTF_NAME_STID(offset) != CTF_STRTAB_0)
527 return "external";
528
529 if (CTF_NAME_OFFSET(offset) >= cth->cth_strlen)
530 return "exceeds strlab";
531
532 if (cth->cth_stroff + CTF_NAME_OFFSET(offset) >= dlen)
533 return "invalid";
534
535 name = data + cth->cth_stroff + CTF_NAME_OFFSET(offset);
536 if (*name == '\0')
537 return "(anon)";
538
539 return name;
540}
541
542char *
543decompress(const char *buf, size_t size, off_t len)
544{
545#ifdef ZLIB
546 z_stream stream;
547 char *data;
548 int error;
549
550 data = malloc(len);
551 if (data == NULL) {
552 warn(NULL);
553 return NULL;
554 }
555
556 memset(&stream, 0, sizeof(stream));
557 stream.next_in = (void *)buf;
558 stream.avail_in = size;
559 stream.next_out = data;
560 stream.avail_out = len;
561
562 if ((error = inflateInit(&stream)) != Z_OK) {
563 warnx("zlib inflateInit failed: %s", zError(error));
564 goto exit;
565 }
566
567 if ((error = inflate(&stream, Z_FINISH)) != Z_STREAM_END) {
568 warnx("zlib inflate failed: %s", zError(error));
8aa77ab4 569 inflateEnd(&stream);
f8621c6a
MP
570 goto exit;
571 }
572
573 if ((error = inflateEnd(&stream)) != Z_OK) {
574 warnx("zlib inflateEnd failed: %s", zError(error));
575 goto exit;
576 }
577
578 if (stream.total_out != len) {
579 warnx("decompression failed: %llu != %llu",
580 stream.total_out, len);
581 goto exit;
582 }
583
584 return data;
585
586exit:
587 free(data);
588#endif /* ZLIB */
589 return NULL;
590}
591
592__dead void
593usage(void)
594{
595 extern char *__progname;
596
53477564 597 fprintf(stderr, "usage: %s [-dfhlst] [file ...]\n",
f8621c6a
MP
598 __progname);
599 exit(1);
600}
601