Annotation of src/usr.bin/ctfconv/ctfconv.c, Revision 1.15
1.15 ! mpi 1: /* $OpenBSD: ctfconv.c,v 1.14 2017/11/03 12:54:50 mpi Exp $ */
1.2 jasper 2:
1.1 mpi 3: /*
4: * Copyright (c) 2016-2017 Martin Pieuchot
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/queue.h>
23: #include <sys/tree.h>
24: #include <sys/ctf.h>
25:
26: #include <assert.h>
1.13 mpi 27: #include <elf.h>
1.1 mpi 28: #include <err.h>
29: #include <fcntl.h>
30: #include <locale.h>
31: #include <stdio.h>
32: #include <stdint.h>
33: #include <stdlib.h>
34: #include <string.h>
35: #include <unistd.h>
36:
37: #include "itype.h"
38: #include "xmalloc.h"
39:
40: #ifndef nitems
41: #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
42: #endif
43:
44: #define DEBUG_ABBREV ".debug_abbrev"
45: #define DEBUG_INFO ".debug_info"
46: #define DEBUG_LINE ".debug_line"
47: #define DEBUG_STR ".debug_str"
48:
49: __dead void usage(void);
50: int convert(const char *);
51: int generate(const char *, const char *, int);
52: int elf_convert(char *, size_t);
53: void elf_sort(void);
1.11 mpi 54: struct itype *find_symb(struct itype *, size_t);
1.1 mpi 55: void dump_type(struct itype *);
56: void dump_func(struct itype *, int *);
57: void dump_obj(struct itype *, int *);
58:
59: /* elf.c */
60: int iself(const char *, size_t);
61: int elf_getshstab(const char *, size_t, const char **, size_t *);
1.12 jsg 62: ssize_t elf_getsymtab(const char *, size_t, const char *, size_t,
1.1 mpi 63: const Elf_Sym **, size_t *);
1.10 jsg 64: ssize_t elf_getsection(char *, size_t, const char *, const char *,
1.1 mpi 65: size_t, const char **, size_t *);
66:
67: /* parse.c */
68: void dwarf_parse(const char *, size_t, const char *, size_t);
69:
70: const char *ctf_enc2name(unsigned short);
71:
72: /* lists of parsed types and functions */
73: struct itype_queue itypeq = TAILQ_HEAD_INITIALIZER(itypeq);
74: struct itype_queue ifuncq = TAILQ_HEAD_INITIALIZER(ifuncq);
75: struct itype_queue iobjq = TAILQ_HEAD_INITIALIZER(iobjq);
76:
77: __dead void
78: usage(void)
79: {
1.7 jasper 80: fprintf(stderr, "usage: %s [-d] -l label -o outfile file\n",
1.1 mpi 81: getprogname());
82: exit(1);
83: }
84:
85: int
86: main(int argc, char *argv[])
87: {
88: const char *filename, *label = NULL, *outfile = NULL;
89: int dump = 0;
90: int ch, error = 0;
91: struct itype *it;
92:
93: setlocale(LC_ALL, "");
94:
1.6 jasper 95: if (pledge("stdio rpath wpath cpath", NULL) == -1)
96: err(1, "pledge");
97:
1.1 mpi 98: while ((ch = getopt(argc, argv, "dl:o:")) != -1) {
99: switch (ch) {
100: case 'd':
1.5 jasper 101: dump = 1; /* ctfdump(1)-like SUNW_ctf sections */
1.1 mpi 102: break;
103: case 'l':
104: if (label != NULL)
105: usage();
106: label = optarg;
107: break;
108: case 'o':
109: if (outfile != NULL)
110: usage();
111: outfile = optarg;
112: break;
113: default:
114: usage();
115: }
116: }
117:
118: argc -= optind;
119: argv += optind;
120:
121: if (argc != 1)
122: usage();
123:
1.5 jasper 124: /* Either dump the sections, or write it out. */
125: if ((dump && (outfile != NULL || label != NULL)) ||
126: (!dump && (outfile == NULL || label == NULL)))
1.1 mpi 127: usage();
128:
129: filename = *argv;
130: error = convert(filename);
131: if (error != 0)
132: return error;
133:
1.6 jasper 134: if (outfile != NULL) {
135: if (pledge("stdio wpath cpath", NULL) == -1)
136: err(1, "pledge");
137:
138: error = generate(outfile, label, 1);
139: if (error != 0)
140: return error;
141: }
142:
1.1 mpi 143: if (dump) {
1.6 jasper 144: if (pledge("stdio", NULL) == -1)
145: err(1, "pledge");
146:
1.1 mpi 147: int fidx = -1, oidx = -1;
148:
149: TAILQ_FOREACH(it, &iobjq, it_symb)
150: dump_obj(it, &oidx);
151: printf("\n");
152:
153: TAILQ_FOREACH(it, &ifuncq, it_symb)
154: dump_func(it, &fidx);
155: printf("\n");
156:
157: TAILQ_FOREACH(it, &itypeq, it_next) {
158: if (it->it_flags & (ITF_FUNC|ITF_OBJ))
159: continue;
160:
161: dump_type(it);
162: }
1.5 jasper 163:
164: return 0;
1.1 mpi 165: }
166:
167: return 0;
168: }
169:
170: int
171: convert(const char *path)
172: {
173: struct stat st;
174: int fd, error = 1;
175: char *p;
176:
177: fd = open(path, O_RDONLY);
178: if (fd == -1) {
179: warn("open %s", path);
180: return 1;
181: }
182: if (fstat(fd, &st) == -1) {
183: warn("fstat %s", path);
1.9 jsg 184: close(fd);
1.1 mpi 185: return 1;
186: }
187: if ((uintmax_t)st.st_size > SIZE_MAX) {
188: warnx("file too big to fit memory");
1.9 jsg 189: close(fd);
1.1 mpi 190: return 1;
191: }
192:
193: p = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
194: if (p == MAP_FAILED)
195: err(1, "mmap");
196:
197: if (iself(p, st.st_size))
198: error = elf_convert(p, st.st_size);
199:
200: munmap(p, st.st_size);
201: close(fd);
202:
203: return error;
204: }
205:
206: const char *dstrbuf;
207: size_t dstrlen;
208: const char *strtab;
209: const Elf_Sym *symtab;
210: size_t strtabsz, nsymb;
211:
212: int
213: elf_convert(char *p, size_t filesize)
214: {
215: const char *shstab;
216: const char *infobuf, *abbuf;
217: size_t infolen, ablen;
218: size_t shstabsz;
219:
220: /* Find section header string table location and size. */
221: if (elf_getshstab(p, filesize, &shstab, &shstabsz))
222: return 1;
223:
224: /* Find symbol table location and number of symbols. */
1.12 jsg 225: if (elf_getsymtab(p, filesize, shstab, shstabsz, &symtab, &nsymb) == -1)
1.1 mpi 226: warnx("symbol table not found");
227:
228: /* Find string table location and size. */
1.10 jsg 229: if (elf_getsection(p, filesize, ELF_STRTAB, shstab, shstabsz, &strtab,
1.1 mpi 230: &strtabsz) == -1)
231: warnx("string table not found");
232:
233: /* Find abbreviation location and size. */
1.10 jsg 234: if (elf_getsection(p, filesize, DEBUG_ABBREV, shstab, shstabsz, &abbuf,
1.1 mpi 235: &ablen) == -1) {
236: warnx("%s section not found", DEBUG_ABBREV);
237: return 1;
238: }
239:
1.10 jsg 240: if (elf_getsection(p, filesize, DEBUG_INFO, shstab, shstabsz, &infobuf,
1.1 mpi 241: &infolen) == -1) {
242: warnx("%s section not found", DEBUG_INFO);
243: return 1;
244: }
245:
246: /* Find string table location and size. */
1.10 jsg 247: if (elf_getsection(p, filesize, DEBUG_STR, shstab, shstabsz, &dstrbuf,
1.1 mpi 248: &dstrlen) == -1)
249: warnx("%s section not found", DEBUG_STR);
250:
251: dwarf_parse(infobuf, infolen, abbuf, ablen);
252:
253: /* Sort functions */
254: elf_sort();
255:
256: return 0;
257: }
258:
1.11 mpi 259: struct itype *
260: find_symb(struct itype *tmp, size_t stroff)
261: {
262: struct itype *it;
263: char *sname, *p;
264:
265: if (strtab == NULL || stroff >= strtabsz)
266: return NULL;
267:
268: /*
269: * Skip local suffix
270: *
271: * FIXME: only skip local copies.
272: */
273: sname = xstrdup(strtab + stroff);
274: if ((p = strtok(sname, ".")) == NULL) {
275: free(sname);
276: return NULL;
277: }
278:
279: strlcpy(tmp->it_name, p, ITNAME_MAX);
280: free(sname);
281: it = RB_FIND(isymb_tree, &isymbt, tmp);
282:
283: /* Restore original name */
284: if (it == NULL)
285: strlcpy(tmp->it_name, (strtab + stroff), ITNAME_MAX);
286:
287: return it;
288: }
289:
1.1 mpi 290: void
291: elf_sort(void)
292: {
293: struct itype *it, tmp;
294: size_t i;
295:
296: memset(&tmp, 0, sizeof(tmp));
297: for (i = 0; i < nsymb; i++) {
298: const Elf_Sym *st = &symtab[i];
299:
300: if (st->st_shndx == SHN_UNDEF || st->st_shndx == SHN_COMMON)
301: continue;
302:
303: switch (ELF_ST_TYPE(st->st_info)) {
304: case STT_FUNC:
305: tmp.it_flags = ITF_FUNC;
306: break;
307: case STT_OBJECT:
308: tmp.it_flags = ITF_OBJ;
309: break;
310: default:
311: continue;
312: }
313:
1.11 mpi 314: it = find_symb(&tmp, st->st_name);
1.1 mpi 315: if (it == NULL) {
316: /* Insert 'unknown' entry to match symbol order. */
317: it = it_dup(&tmp);
318: it->it_refp = it;
319: #ifdef DEBUG
320: warnx("symbol not found: %s", it_name(it));
321: #endif
322: }
323:
324: if (it->it_flags & ITF_INSERTED) {
325: #ifdef DEBUG
326: warnx("%s: already inserted", it_name(it));
327: #endif
328: it = it_dup(it);
329: }
330:
331: /* Save symbol index for dump. */
332: it->it_ref = i;
333:
334: it->it_flags |= ITF_INSERTED;
335: if (it->it_flags & ITF_FUNC)
336: TAILQ_INSERT_TAIL(&ifuncq, it, it_symb);
337: else
338: TAILQ_INSERT_TAIL(&iobjq, it, it_symb);
339: }
340: }
341:
342: const char *
343: type_name(struct itype *it)
344: {
345: const char *name;
346:
347: name = it_name(it);
348: if (name == NULL)
349: return "(anon)";
350:
351: return name;
352: }
353:
354: /* Display parsed types a la ctfdump(1) */
355: void
356: dump_type(struct itype *it)
357: {
358: struct imember *im;
359:
360: #ifdef DEBUG
361: switch (it->it_type) {
362: case CTF_K_POINTER:
363: case CTF_K_TYPEDEF:
364: case CTF_K_VOLATILE:
365: case CTF_K_CONST:
366: case CTF_K_RESTRICT:
367: case CTF_K_ARRAY:
368: case CTF_K_FUNCTION:
369: if (it->it_refp == NULL) {
370: printf("unresolved: %s type=%d\n", it_name(it),
371: it->it_type);
372: return;
373: }
374: default:
375: break;
376: }
377: #endif
378:
379: switch (it->it_type) {
380: case CTF_K_FLOAT:
381: case CTF_K_INTEGER:
382: printf(" [%u] %s %s encoding=%s offset=0 bits=%u\n",
383: it->it_idx,
384: (it->it_type == CTF_K_INTEGER) ? "INTEGER" : "FLOAT",
385: it_name(it), ctf_enc2name(it->it_enc), it->it_size);
386: break;
387: case CTF_K_POINTER:
388: printf(" <%u> POINTER %s refers to %u\n", it->it_idx,
389: type_name(it), it->it_refp->it_idx);
390: break;
391: case CTF_K_TYPEDEF:
392: printf(" <%u> TYPEDEF %s refers to %u\n",
393: it->it_idx, it_name(it), it->it_refp->it_idx);
394: break;
395: case CTF_K_VOLATILE:
396: printf(" <%u> VOLATILE %s refers to %u\n", it->it_idx,
397: type_name(it), it->it_refp->it_idx);
398: break;
399: case CTF_K_CONST:
400: printf(" <%u> CONST %s refers to %u\n", it->it_idx,
401: type_name(it), it->it_refp->it_idx);
402: break;
403: case CTF_K_RESTRICT:
404: printf(" <%u> RESTRICT %s refers to %u\n", it->it_idx,
405: it_name(it), it->it_refp->it_idx);
406: break;
407: case CTF_K_ARRAY:
408: printf(" [%u] ARRAY %s content: %u index: %u nelems: %u\n",
409: it->it_idx, type_name(it), it->it_refp->it_idx, long_tidx,
410: it->it_nelems);
411: printf("\n");
412: break;
413: case CTF_K_STRUCT:
414: case CTF_K_UNION:
415: printf(" [%u] %s %s (%u bytes)\n", it->it_idx,
416: (it->it_type == CTF_K_STRUCT) ? "STRUCT" : "UNION",
417: type_name(it), it->it_size);
418: TAILQ_FOREACH(im, &it->it_members, im_next) {
1.14 mpi 419: printf("\t%s type=%u off=%zu\n",
1.3 mpi 420: (im_name(im) == NULL) ? "unknown" : im_name(im),
1.4 mpi 421: im->im_refp ? im->im_refp->it_idx : 0, im->im_off);
1.1 mpi 422: }
423: printf("\n");
424: break;
425: case CTF_K_ENUM:
1.15 ! mpi 426: printf(" [%u] ENUM %s\n", it->it_idx, type_name(it));
! 427: TAILQ_FOREACH(im, &it->it_members, im_next) {
! 428: printf("\t%s = %zu\n", im_name(im), im->im_ref);
! 429: }
! 430: printf("\n");
1.1 mpi 431: break;
432: case CTF_K_FUNCTION:
433: printf(" [%u] FUNCTION (%s) returns: %u args: (",
434: it->it_idx, (it_name(it) != NULL) ? it_name(it) : "anon",
435: it->it_refp->it_idx);
436: TAILQ_FOREACH(im, &it->it_members, im_next) {
437: printf("%u%s", im->im_refp->it_idx,
438: TAILQ_NEXT(im, im_next) ? ", " : "");
439: }
440: printf(")\n");
441: break;
442: default:
443: assert(0 == 1);
444: }
445: }
446:
447: void
448: dump_func(struct itype *it, int *idx)
449: {
450: struct imember *im;
451:
452: (*idx)++;
453:
454: if (it->it_type == CTF_K_UNKNOWN && it->it_nelems == 0)
455: return;
456:
457: printf(" [%u] FUNC (%s) returns: %u args: (", (*idx),
458: (it_name(it) != NULL) ? it_name(it) : "unknown",
459: it->it_refp->it_idx);
460: TAILQ_FOREACH(im, &it->it_members, im_next) {
461: printf("%u%s", im->im_refp->it_idx,
462: TAILQ_NEXT(im, im_next) ? ", " : "");
463: }
464: printf(")\n");
465: }
466:
467: void
468: dump_obj(struct itype *it, int *idx)
469: {
470: int l;
471:
472: (*idx)++;
473:
474: l = printf(" [%u] %u", (*idx), it->it_refp->it_idx);
475: printf("%*s %s (%llu)\n", 14 - l, "", it_name(it), it->it_ref);
476: }
477:
478: const char *
479: ctf_enc2name(unsigned short enc)
480: {
481: static const char *enc_name[] = { "SIGNED", "CHAR", "SIGNED CHAR",
482: "BOOL", "SIGNED BOOL" };
483: static char invalid[7];
484:
485: if (enc == CTF_INT_VARARGS)
486: return "VARARGS";
487:
488: if (enc > 0 && enc < nitems(enc_name))
489: return enc_name[enc - 1];
490:
491: snprintf(invalid, sizeof(invalid), "0x%x", enc);
492: return invalid;
493: }