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