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