GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/ctfconv/ctfconv.c Lines: 0 197 0.0 %
Date: 2017-11-13 Branches: 0 126 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: ctfconv.c,v 1.16 2017/11/06 14:59:27 mpi Exp $ */
2
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>
27
#include <elf.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
struct itype	*find_symb(struct itype *, size_t);
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 *, size_t, const char *, size_t,
63
		     const Elf_Sym **, size_t *, const char **, size_t *);
64
ssize_t		 elf_getsection(char *, size_t, 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
	if (pledge("stdio rpath wpath cpath flock", NULL) == -1)
96
		err(1, "pledge");
97
98
	while ((ch = getopt(argc, argv, "dl:o:")) != -1) {
99
		switch (ch) {
100
		case 'd':
101
			dump = 1;	/* ctfdump(1)-like SUNW_ctf sections */
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
124
	/* Either dump the sections, or write it out. */
125
	if ((dump && (outfile != NULL || label != NULL)) ||
126
	    (!dump && (outfile == NULL || label == NULL)))
127
		usage();
128
129
	filename = *argv;
130
	error = convert(filename);
131
	if (error != 0)
132
		return error;
133
134
	if (outfile != NULL) {
135
		if (pledge("stdio wpath cpath flock rpath", NULL) == -1)
136
			err(1, "pledge");
137
138
		error = generate(outfile, label, 1);
139
		if (error != 0)
140
			return error;
141
	}
142
143
	if (dump) {
144
		if (pledge("stdio flock rpath cpath wpath", NULL) == -1)
145
			err(1, "pledge");
146
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
		}
163
164
		return 0;
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);
184
		close(fd);
185
		return 1;
186
	}
187
	if ((uintmax_t)st.st_size > SIZE_MAX) {
188
		warnx("file too big to fit memory");
189
		close(fd);
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 and associated string table. */
225
	if (elf_getsymtab(p, filesize, shstab, shstabsz, &symtab, &nsymb,
226
	    &strtab, &strtabsz) == -1)
227
		warnx("symbol table not found");
228
229
	/* Find abbreviation location and size. */
230
	if (elf_getsection(p, filesize, DEBUG_ABBREV, shstab, shstabsz, &abbuf,
231
	    &ablen) == -1) {
232
		warnx("%s section not found", DEBUG_ABBREV);
233
		return 1;
234
	}
235
236
	if (elf_getsection(p, filesize, DEBUG_INFO, shstab, shstabsz, &infobuf,
237
	    &infolen) == -1) {
238
		warnx("%s section not found", DEBUG_INFO);
239
		return 1;
240
	}
241
242
	/* Find string table location and size. */
243
	if (elf_getsection(p, filesize, DEBUG_STR, shstab, shstabsz, &dstrbuf,
244
	    &dstrlen) == -1)
245
		warnx("%s section not found", DEBUG_STR);
246
247
	dwarf_parse(infobuf, infolen, abbuf, ablen);
248
249
	/* Sort functions */
250
	elf_sort();
251
252
	return 0;
253
}
254
255
struct itype *
256
find_symb(struct itype *tmp, size_t stroff)
257
{
258
	struct itype		*it;
259
	char 			*sname, *p;
260
261
	if (strtab == NULL || stroff >= strtabsz)
262
		return NULL;
263
264
	/*
265
	 * Skip local suffix
266
	 *
267
	 * FIXME: only skip local copies.
268
	 */
269
	sname = xstrdup(strtab + stroff);
270
	if ((p = strtok(sname, ".")) == NULL) {
271
		free(sname);
272
		return NULL;
273
	}
274
275
	strlcpy(tmp->it_name, p, ITNAME_MAX);
276
	free(sname);
277
	it = RB_FIND(isymb_tree, &isymbt, tmp);
278
279
	/* Restore original name */
280
	if (it == NULL)
281
		strlcpy(tmp->it_name, (strtab + stroff), ITNAME_MAX);
282
283
	return it;
284
}
285
286
void
287
elf_sort(void)
288
{
289
	struct itype		*it, tmp;
290
	size_t			 i;
291
292
	memset(&tmp, 0, sizeof(tmp));
293
	for (i = 0; i < nsymb; i++) {
294
		const Elf_Sym	*st = &symtab[i];
295
296
		if (st->st_shndx == SHN_UNDEF || st->st_shndx == SHN_COMMON)
297
			continue;
298
299
		switch (ELF_ST_TYPE(st->st_info)) {
300
		case STT_FUNC:
301
			tmp.it_flags = ITF_FUNC;
302
			break;
303
		case STT_OBJECT:
304
			tmp.it_flags = ITF_OBJ;
305
			break;
306
		default:
307
			continue;
308
		}
309
310
		it = find_symb(&tmp, st->st_name);
311
		if (it == NULL) {
312
			/* Insert 'unknown' entry to match symbol order. */
313
			it = it_dup(&tmp);
314
			it->it_refp = it;
315
#ifdef DEBUG
316
			warnx("symbol not found: %s", it_name(it));
317
#endif
318
		}
319
320
		if (it->it_flags & ITF_INSERTED) {
321
#ifdef DEBUG
322
			warnx("%s: already inserted", it_name(it));
323
#endif
324
			it = it_dup(it);
325
		}
326
327
		/* Save symbol index for dump. */
328
		it->it_ref = i;
329
330
		it->it_flags |= ITF_INSERTED;
331
		if (it->it_flags & ITF_FUNC)
332
			TAILQ_INSERT_TAIL(&ifuncq, it, it_symb);
333
		else
334
			TAILQ_INSERT_TAIL(&iobjq, it, it_symb);
335
	}
336
}
337
338
const char *
339
type_name(struct itype *it)
340
{
341
	const char *name;
342
343
	name = it_name(it);
344
	if (name == NULL)
345
		return "(anon)";
346
347
	return name;
348
}
349
350
/* Display parsed types a la ctfdump(1) */
351
void
352
dump_type(struct itype *it)
353
{
354
	struct imember *im;
355
356
#ifdef DEBUG
357
	switch (it->it_type) {
358
	case CTF_K_POINTER:
359
	case CTF_K_TYPEDEF:
360
	case CTF_K_VOLATILE:
361
	case CTF_K_CONST:
362
	case CTF_K_RESTRICT:
363
	case CTF_K_ARRAY:
364
	case CTF_K_FUNCTION:
365
		if (it->it_refp == NULL) {
366
			printf("unresolved: %s type=%d\n", it_name(it),
367
			    it->it_type);
368
			return;
369
		}
370
	default:
371
		break;
372
	}
373
#endif
374
375
	switch (it->it_type) {
376
	case CTF_K_FLOAT:
377
	case CTF_K_INTEGER:
378
		printf("  [%u] %s %s encoding=%s offset=0 bits=%u\n",
379
		    it->it_idx,
380
		    (it->it_type == CTF_K_INTEGER) ? "INTEGER" : "FLOAT",
381
		    it_name(it), ctf_enc2name(it->it_enc), it->it_size);
382
		break;
383
	case CTF_K_POINTER:
384
		printf("  <%u> POINTER %s refers to %u\n", it->it_idx,
385
		    type_name(it), it->it_refp->it_idx);
386
		break;
387
	case CTF_K_TYPEDEF:
388
		printf("  <%u> TYPEDEF %s refers to %u\n",
389
		    it->it_idx, it_name(it), it->it_refp->it_idx);
390
		break;
391
	case CTF_K_VOLATILE:
392
		printf("  <%u> VOLATILE %s refers to %u\n", it->it_idx,
393
		    type_name(it), it->it_refp->it_idx);
394
		break;
395
	case CTF_K_CONST:
396
		printf("  <%u> CONST %s refers to %u\n", it->it_idx,
397
		    type_name(it), it->it_refp->it_idx);
398
		break;
399
	case CTF_K_RESTRICT:
400
		printf("  <%u> RESTRICT %s refers to %u\n", it->it_idx,
401
		    it_name(it), it->it_refp->it_idx);
402
		break;
403
	case CTF_K_ARRAY:
404
		printf("  [%u] ARRAY %s content: %u index: %u nelems: %u\n",
405
		    it->it_idx, type_name(it), it->it_refp->it_idx, long_tidx,
406
		    it->it_nelems);
407
		printf("\n");
408
		break;
409
	case CTF_K_STRUCT:
410
	case CTF_K_UNION:
411
		printf("  [%u] %s %s (%u bytes)\n", it->it_idx,
412
		    (it->it_type == CTF_K_STRUCT) ? "STRUCT" : "UNION",
413
		    type_name(it), it->it_size);
414
		TAILQ_FOREACH(im, &it->it_members, im_next) {
415
			printf("\t%s type=%u off=%zu\n",
416
			    (im_name(im) == NULL) ? "unknown" : im_name(im),
417
			    im->im_refp ? im->im_refp->it_idx : 0, im->im_off);
418
		}
419
		printf("\n");
420
		break;
421
	case CTF_K_ENUM:
422
		printf("  [%u] ENUM %s\n", it->it_idx, type_name(it));
423
		TAILQ_FOREACH(im, &it->it_members, im_next) {
424
			printf("\t%s = %zu\n", im_name(im), im->im_ref);
425
		}
426
		printf("\n");
427
		break;
428
	case CTF_K_FUNCTION:
429
		printf("  [%u] FUNCTION (%s) returns: %u args: (",
430
		    it->it_idx, (it_name(it) != NULL) ? it_name(it) : "anon",
431
		    it->it_refp->it_idx);
432
		TAILQ_FOREACH(im, &it->it_members, im_next) {
433
			printf("%u%s", im->im_refp->it_idx,
434
			    TAILQ_NEXT(im, im_next) ? ", " : "");
435
		}
436
		printf(")\n");
437
		break;
438
	default:
439
		assert(0 == 1);
440
	}
441
}
442
443
void
444
dump_func(struct itype *it, int *idx)
445
{
446
	struct imember *im;
447
448
	(*idx)++;
449
450
	if (it->it_type == CTF_K_UNKNOWN && it->it_nelems == 0)
451
		return;
452
453
	printf("  [%u] FUNC (%s) returns: %u args: (", (*idx),
454
	    (it_name(it) != NULL) ? it_name(it) : "unknown",
455
	    it->it_refp->it_idx);
456
	TAILQ_FOREACH(im, &it->it_members, im_next) {
457
		printf("%u%s", im->im_refp->it_idx,
458
		    TAILQ_NEXT(im, im_next) ? ", " : "");
459
	}
460
	printf(")\n");
461
}
462
463
void
464
dump_obj(struct itype *it, int *idx)
465
{
466
	int l;
467
468
	(*idx)++;
469
470
	l = printf("  [%u] %u", (*idx), it->it_refp->it_idx);
471
	printf("%*s %s (%llu)\n", 14 - l, "", it_name(it), it->it_ref);
472
}
473
474
const char *
475
ctf_enc2name(unsigned short enc)
476
{
477
	static const char *enc_name[] = { "SIGNED", "CHAR", "SIGNED CHAR",
478
	    "BOOL", "SIGNED BOOL" };
479
	static char invalid[7];
480
481
	if (enc == CTF_INT_VARARGS)
482
		return "VARARGS";
483
484
	if (enc > 0 && enc < nitems(enc_name))
485
		return enc_name[enc - 1];
486
487
	snprintf(invalid, sizeof(invalid), "0x%x", enc);
488
	return invalid;
489
}