Annotation of src/usr.bin/ctfconv/ctfconv.c, Revision 1.10
1.10 ! jsg 1: /* $OpenBSD: ctfconv.c,v 1.9 2017/09/19 08:28:57 jsg 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/exec_elf.h>
22: #include <sys/mman.h>
23: #include <sys/queue.h>
24: #include <sys/tree.h>
25: #include <sys/ctf.h>
26:
27: #include <assert.h>
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);
54: void dump_type(struct itype *);
55: void dump_func(struct itype *, int *);
56: void dump_obj(struct itype *, int *);
57:
58: /* elf.c */
59: int iself(const char *, size_t);
60: int elf_getshstab(const char *, size_t, const char **, size_t *);
61: ssize_t elf_getsymtab(const char *, const char *, size_t,
62: const Elf_Sym **, size_t *);
1.10 ! jsg 63: ssize_t elf_getsection(char *, size_t, const char *, const char *,
1.1 mpi 64: size_t, const char **, size_t *);
65:
66: /* parse.c */
67: void dwarf_parse(const char *, size_t, const char *, size_t);
68:
69: const char *ctf_enc2name(unsigned short);
70:
71: /* lists of parsed types and functions */
72: struct itype_queue itypeq = TAILQ_HEAD_INITIALIZER(itypeq);
73: struct itype_queue ifuncq = TAILQ_HEAD_INITIALIZER(ifuncq);
74: struct itype_queue iobjq = TAILQ_HEAD_INITIALIZER(iobjq);
75:
76: __dead void
77: usage(void)
78: {
1.7 jasper 79: fprintf(stderr, "usage: %s [-d] -l label -o outfile file\n",
1.1 mpi 80: getprogname());
81: exit(1);
82: }
83:
84: int
85: main(int argc, char *argv[])
86: {
87: const char *filename, *label = NULL, *outfile = NULL;
88: int dump = 0;
89: int ch, error = 0;
90: struct itype *it;
91:
92: setlocale(LC_ALL, "");
93:
1.6 jasper 94: if (pledge("stdio rpath wpath cpath", NULL) == -1)
95: err(1, "pledge");
96:
1.1 mpi 97: while ((ch = getopt(argc, argv, "dl:o:")) != -1) {
98: switch (ch) {
99: case 'd':
1.5 jasper 100: dump = 1; /* ctfdump(1)-like SUNW_ctf sections */
1.1 mpi 101: break;
102: case 'l':
103: if (label != NULL)
104: usage();
105: label = optarg;
106: break;
107: case 'o':
108: if (outfile != NULL)
109: usage();
110: outfile = optarg;
111: break;
112: default:
113: usage();
114: }
115: }
116:
117: argc -= optind;
118: argv += optind;
119:
120: if (argc != 1)
121: usage();
122:
1.5 jasper 123: /* Either dump the sections, or write it out. */
124: if ((dump && (outfile != NULL || label != NULL)) ||
125: (!dump && (outfile == NULL || label == NULL)))
1.1 mpi 126: usage();
127:
128: filename = *argv;
129: error = convert(filename);
130: if (error != 0)
131: return error;
132:
1.6 jasper 133: if (outfile != NULL) {
134: if (pledge("stdio wpath cpath", NULL) == -1)
135: err(1, "pledge");
136:
137: error = generate(outfile, label, 1);
138: if (error != 0)
139: return error;
140: }
141:
1.1 mpi 142: if (dump) {
1.6 jasper 143: if (pledge("stdio", NULL) == -1)
144: err(1, "pledge");
145:
1.1 mpi 146: int fidx = -1, oidx = -1;
147:
148: TAILQ_FOREACH(it, &iobjq, it_symb)
149: dump_obj(it, &oidx);
150: printf("\n");
151:
152: TAILQ_FOREACH(it, &ifuncq, it_symb)
153: dump_func(it, &fidx);
154: printf("\n");
155:
156: TAILQ_FOREACH(it, &itypeq, it_next) {
157: if (it->it_flags & (ITF_FUNC|ITF_OBJ))
158: continue;
159:
160: dump_type(it);
161: }
1.5 jasper 162:
163: return 0;
1.1 mpi 164: }
165:
166: return 0;
167: }
168:
169: int
170: convert(const char *path)
171: {
172: struct stat st;
173: int fd, error = 1;
174: char *p;
175:
176: fd = open(path, O_RDONLY);
177: if (fd == -1) {
178: warn("open %s", path);
179: return 1;
180: }
181: if (fstat(fd, &st) == -1) {
182: warn("fstat %s", path);
1.9 jsg 183: close(fd);
1.1 mpi 184: return 1;
185: }
186: if ((uintmax_t)st.st_size > SIZE_MAX) {
187: warnx("file too big to fit memory");
1.9 jsg 188: close(fd);
1.1 mpi 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. */
1.10 ! jsg 228: if (elf_getsection(p, filesize, ELF_STRTAB, shstab, shstabsz, &strtab,
1.1 mpi 229: &strtabsz) == -1)
230: warnx("string table not found");
231:
232: /* Find abbreviation location and size. */
1.10 ! jsg 233: if (elf_getsection(p, filesize, DEBUG_ABBREV, shstab, shstabsz, &abbuf,
1.1 mpi 234: &ablen) == -1) {
235: warnx("%s section not found", DEBUG_ABBREV);
236: return 1;
237: }
238:
1.10 ! jsg 239: if (elf_getsection(p, filesize, DEBUG_INFO, shstab, shstabsz, &infobuf,
1.1 mpi 240: &infolen) == -1) {
241: warnx("%s section not found", DEBUG_INFO);
242: return 1;
243: }
244:
245: /* Find string table location and size. */
1.10 ! jsg 246: if (elf_getsection(p, filesize, DEBUG_STR, shstab, shstabsz, &dstrbuf,
1.1 mpi 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: }