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