GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/ctfconv/dw.c Lines: 172 279 61.6 %
Date: 2017-11-07 Branches: 82 222 36.9 %

Line Branch Exec Source
1
/*	$OpenBSD: dw.c,v 1.4 2017/09/27 08:59:38 mpi Exp $ */
2
3
/*
4
 * Copyright (c) 2016 Martin Pieuchot
5
 * Copyright (c) 2014 Matthew Dempsky <matthew@dempsky.org>
6
 *
7
 * Permission to use, copy, modify, and distribute this software for any
8
 * purpose with or without fee is hereby granted, provided that the above
9
 * copyright notice and this permission notice appear in all copies.
10
 *
11
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
 */
19
20
#include <sys/queue.h>
21
22
#include <errno.h>
23
#include <stdint.h>
24
#include <stdlib.h>
25
#include <string.h>
26
27
#include "dw.h"
28
#include "dwarf.h"
29
#include "pool.h"
30
31
#ifndef NOPOOL
32
struct pool dcu_pool, die_pool, dav_pool, dab_pool, dat_pool;
33
#endif /* NOPOOL */
34
35
#ifndef nitems
36
#define nitems(_a)	(sizeof((_a)) / sizeof((_a)[0]))
37
#endif
38
39
static int	 dw_read_u8(struct dwbuf *, uint8_t *);
40
static int	 dw_read_u16(struct dwbuf *, uint16_t *);
41
static int	 dw_read_u32(struct dwbuf *, uint32_t *);
42
static int	 dw_read_u64(struct dwbuf *, uint64_t *);
43
44
static int	 dw_read_sleb128(struct dwbuf *, int64_t *);
45
static int	 dw_read_uleb128(struct dwbuf *, uint64_t *);
46
47
static int	 dw_read_bytes(struct dwbuf *, void *, size_t);
48
static int	 dw_read_string(struct dwbuf *, const char **);
49
static int	 dw_read_buf(struct dwbuf *, struct dwbuf *, size_t);
50
51
static int	 dw_skip_bytes(struct dwbuf *, size_t);
52
53
static int	 dw_read_filename(struct dwbuf *, const char **, const char **,
54
		     uint8_t, uint64_t);
55
56
57
static int	 dw_attr_parse(struct dwbuf *, struct dwattr *, uint8_t,
58
		     struct dwaval_queue *);
59
static void	 dw_attr_purge(struct dwaval_queue *);
60
static int	 dw_die_parse(struct dwbuf *, size_t, uint8_t,
61
		     struct dwabbrev_queue *, struct dwdie_queue *);
62
static void	 dw_die_purge(struct dwdie_queue *);
63
64
static int
65
dw_read_bytes(struct dwbuf *d, void *v, size_t n)
66
{
67
812
	if (d->len < n)
68
		return -1;
69
406
	memcpy(v, d->buf, n);
70
406
	d->buf += n;
71
406
	d->len -= n;
72
406
	return 0;
73
406
}
74
75
static int
76
dw_read_u8(struct dwbuf *d, uint8_t *v)
77
{
78
648
	return dw_read_bytes(d, v, sizeof(*v));
79
}
80
81
static int
82
dw_read_u16(struct dwbuf *d, uint16_t *v)
83
{
84
8
	return dw_read_bytes(d, v, sizeof(*v));
85
}
86
87
static int
88
dw_read_u32(struct dwbuf *d, uint32_t *v)
89
{
90
136
	return dw_read_bytes(d, v, sizeof(*v));
91
}
92
93
static int
94
dw_read_u64(struct dwbuf *d, uint64_t *v)
95
{
96
16
	return dw_read_bytes(d, v, sizeof(*v));
97
}
98
99
/* Read a DWARF LEB128 (little-endian base-128) value. */
100
static inline int
101
dw_read_leb128(struct dwbuf *d, uint64_t *v, int signextend)
102
{
103
	unsigned int shift = 0;
104
	uint64_t res = 0;
105
432
	uint8_t x;
106
107

648
	while (shift < 64 && !dw_read_u8(d, &x)) {
108
216
		res |= (uint64_t)(x & 0x7f) << shift;
109
216
		shift += 7;
110
216
		if ((x & 0x80) == 0) {
111

216
			if (signextend && shift < 64 && (x & 0x40) != 0)
112
				res |= ~(uint64_t)0 << shift;
113
216
			*v = res;
114
216
			return 0;
115
		}
116
	}
117
	return -1;
118
216
}
119
120
static int
121
dw_read_sleb128(struct dwbuf *d, int64_t *v)
122
{
123
	return dw_read_leb128(d, (uint64_t *)v, 1);
124
}
125
126
static int
127
dw_read_uleb128(struct dwbuf *d, uint64_t *v)
128
{
129
432
	return dw_read_leb128(d, v, 0);
130
}
131
132
/* Read a NUL terminated string. */
133
static int
134
dw_read_string(struct dwbuf *d, const char **s)
135
{
136
	const char *end = memchr(d->buf, '\0', d->len);
137
	size_t n;
138
139
	if (end == NULL)
140
		return -1;
141
142
	n = end - d->buf + 1;
143
	*s = d->buf;
144
	d->buf += n;
145
	d->len -= n;
146
	return 0;
147
}
148
149
static int
150
dw_read_buf(struct dwbuf *d, struct dwbuf *v, size_t n)
151
{
152
32
	if (d->len < n)
153
		return -1;
154
16
	v->buf = d->buf;
155
16
	v->len = n;
156
16
	d->buf += n;
157
16
	d->len -= n;
158
16
	return 0;
159
16
}
160
161
static int
162
dw_skip_bytes(struct dwbuf *d, size_t n)
163
{
164
4
	if (d->len < n)
165
		return -1;
166
2
	d->buf += n;
167
2
	d->len -= n;
168
2
	return 0;
169
2
}
170
171
static int
172
dw_read_filename(struct dwbuf *names, const char **outdirname,
173
    const char **outbasename, uint8_t opcode_base, uint64_t file)
174
{
175
	struct dwbuf dirnames;
176
	const char *basename = NULL, *dirname = NULL;
177
	uint64_t mtime, size, dummy, dir = 0;
178
	const char *name;
179
	size_t i;
180
181
	if (file == 0)
182
		return -1;
183
184
	/* Skip over opcode table. */
185
	for (i = 1; i < opcode_base; i++) {
186
		if (dw_read_uleb128(names, &dummy))
187
			return -1;
188
	}
189
190
	/* Skip over directory name table for now. */
191
	dirnames = *names;
192
	for (;;) {
193
		if (dw_read_string(names, &name))
194
			return -1;
195
		if (*name == '\0')
196
			break;
197
	}
198
199
	/* Locate file entry. */
200
	for (i = 0; i < file; i++) {
201
		if (dw_read_string(names, &basename) || *basename == '\0' ||
202
		    dw_read_uleb128(names, &dir) ||
203
		    dw_read_uleb128(names, &mtime) ||
204
		    dw_read_uleb128(names, &size))
205
			return -1;
206
	}
207
208
	for (i = 0; i < dir; i++) {
209
		if (!dw_read_string(&dirnames, &dirname) || *dirname == '\0')
210
			return -1;
211
	}
212
213
	*outdirname = dirname;
214
	*outbasename = basename;
215
216
	return 0;
217
}
218
219
220
const char *
221
dw_tag2name(uint64_t tag)
222
{
223
	static const char *dw_tags[] = { DW_TAG_NAMES };
224
225
	if (tag <= nitems(dw_tags))
226
		return dw_tags[tag - 1];
227
228
	if (tag == DW_TAG_lo_user)
229
		return "DW_TAG_lo_user";
230
	if (tag == DW_TAG_hi_user)
231
		return "DW_TAG_hi_user";
232
233
	return NULL;
234
}
235
236
const char *
237
dw_at2name(uint64_t at)
238
{
239
	static const char *dw_attrs[] = { DW_AT_NAMES };
240
241
	if (at <= nitems(dw_attrs))
242
		return dw_attrs[at - 1];
243
244
	if (at == DW_AT_lo_user)
245
		return "DW_AT_lo_user";
246
	if (at == DW_AT_hi_user)
247
		return "DW_AT_hi_user";
248
249
	return NULL;
250
}
251
252
const char *
253
dw_form2name(uint64_t form)
254
{
255
	static const char *dw_forms[] = { DW_FORM_NAMES };
256
257
	if (form <= nitems(dw_forms))
258
		return dw_forms[form - 1];
259
260
	if (form == DW_FORM_GNU_ref_alt)
261
		return "DW_FORM_GNU_ref_alt";
262
	if (form == DW_FORM_GNU_strp_alt)
263
		return "DW_FORM_GNU_strp_alt";
264
265
	return NULL;
266
}
267
268
const char *
269
dw_op2name(uint8_t op)
270
{
271
	static const char *dw_ops[] = { DW_OP_NAMES };
272
273
	if (op <= nitems(dw_ops))
274
		return dw_ops[op - 1];
275
276
	if (op == DW_OP_lo_user)
277
		return "DW_OP_lo_user";
278
	if (op == DW_OP_hi_user)
279
		return "DW_OP_hi_user";
280
281
	return NULL;
282
}
283
284
static int
285
dw_attr_parse(struct dwbuf *dwbuf, struct dwattr *dat, uint8_t psz,
286
    struct dwaval_queue *davq)
287
{
288
	struct dwaval	*dav;
289
340
	uint64_t	 form = dat->dat_form;
290
	int		 error = 0, i = 0;
291
292
340
	while (form == DW_FORM_indirect) {
293
		/* XXX loop prevention not strict enough? */
294
		if (dw_read_uleb128(dwbuf, &form) || (++i > 3))
295
			return ELOOP;
296
	}
297
298
170
	dav = pzalloc(&dav_pool, sizeof(*dav));
299
170
	if (dav == NULL)
300
		return ENOMEM;
301
302
170
	dav->dav_dat = dat;
303
304





170
	switch (form) {
305
	case DW_FORM_addr:
306
	case DW_FORM_ref_addr:
307
8
		if (psz == sizeof(uint32_t))
308
			error = dw_read_u32(dwbuf, &dav->dav_u32);
309
		else
310
8
			error = dw_read_u64(dwbuf, &dav->dav_u64);
311
		break;
312
	case DW_FORM_block1:
313
14
		error = dw_read_u8(dwbuf, &dav->dav_u8);
314
14
		if (error == 0)
315
14
			error = dw_read_buf(dwbuf, &dav->dav_buf, dav->dav_u8);
316
		break;
317
	case DW_FORM_block2:
318
		error = dw_read_u16(dwbuf, &dav->dav_u16);
319
		if (error == 0)
320
			error = dw_read_buf(dwbuf, &dav->dav_buf, dav->dav_u16);
321
		break;
322
	case DW_FORM_block4:
323
		error = dw_read_u32(dwbuf, &dav->dav_u32);
324
		if (error == 0)
325
			error = dw_read_buf(dwbuf, &dav->dav_buf, dav->dav_u32);
326
		break;
327
	case DW_FORM_block:
328
		error = dw_read_uleb128(dwbuf, &dav->dav_u64);
329
		if (error == 0)
330
			error = dw_read_buf(dwbuf, &dav->dav_buf, dav->dav_u64);
331
		break;
332
	case DW_FORM_data1:
333
	case DW_FORM_flag:
334
	case DW_FORM_ref1:
335
80
		error = dw_read_u8(dwbuf, &dav->dav_u8);
336
80
		break;
337
	case DW_FORM_data2:
338
	case DW_FORM_ref2:
339
2
		error = dw_read_u16(dwbuf, &dav->dav_u16);
340
2
		break;
341
	case DW_FORM_data4:
342
	case DW_FORM_ref4:
343
28
		error = dw_read_u32(dwbuf, &dav->dav_u32);
344
28
		break;
345
	case DW_FORM_data8:
346
	case DW_FORM_ref8:
347
		error = dw_read_u64(dwbuf, &dav->dav_u64);
348
		break;
349
	case DW_FORM_ref_udata:
350
	case DW_FORM_udata:
351
		error = dw_read_uleb128(dwbuf, &dav->dav_u64);
352
		break;
353
	case DW_FORM_sdata:
354
		error = dw_read_sleb128(dwbuf, &dav->dav_s64);
355
		break;
356
	case DW_FORM_string:
357
		error = dw_read_string(dwbuf, &dav->dav_str);
358
		break;
359
	case DW_FORM_strp:
360
38
		error = dw_read_u32(dwbuf, &dav->dav_u32);
361
38
		break;
362
	case DW_FORM_flag_present:
363
		dav->dav_u8 = 1;
364
		break;
365
	default:
366
		error = ENOENT;
367
		break;
368
	}
369
370
170
	if (error) {
371
		pfree(&dav_pool, dav);
372
		return error;
373
	}
374
375
170
	SIMPLEQ_INSERT_TAIL(davq, dav, dav_next);
376
170
	return 0;
377
170
}
378
379
static void
380
dw_attr_purge(struct dwaval_queue *davq)
381
{
382
	struct dwaval	*dav;
383
384
454
	while ((dav = SIMPLEQ_FIRST(davq)) != NULL) {
385
208
		SIMPLEQ_REMOVE_HEAD(davq, dav_next);
386
170
		pfree(&dav_pool, dav);
387
	}
388
389
38
	SIMPLEQ_INIT(davq);
390
38
}
391
392
static int
393
dw_die_parse(struct dwbuf *dwbuf, size_t nextoff, uint8_t psz,
394
    struct dwabbrev_queue *dabq, struct dwdie_queue *dieq)
395
{
396
	struct dwdie	*die;
397
	struct dwabbrev	*dab;
398
	struct dwattr	*dat;
399
4
	uint64_t	 code;
400
	size_t		 doff;
401
	uint8_t		 lvl = 0;
402
	int		 error;
403
404
405
84
	while (dwbuf->len > 0) {
406
42
		doff = nextoff - dwbuf->len;
407
42
		if (dw_read_uleb128(dwbuf, &code))
408
			return -1;
409
410
42
		if (code == 0) {
411
4
			lvl--;
412
4
			continue;
413
		}
414
415
240
		SIMPLEQ_FOREACH(dab, dabq, dab_next) {
416
120
			if (dab->dab_code == code)
417
				break;
418
		}
419
38
		if (dab == NULL)
420
			return ESRCH;
421
422
38
		die = pmalloc(&die_pool, sizeof(*die));
423
38
		if (die == NULL)
424
			return ENOMEM;
425
426
38
		die->die_lvl = lvl;
427
38
		die->die_dab = dab;
428
38
		die->die_offset = doff;
429
38
		SIMPLEQ_INIT(&die->die_avals);
430
431
416
		SIMPLEQ_FOREACH(dat, &dab->dab_attrs, dat_next) {
432
170
			error = dw_attr_parse(dwbuf, dat, psz, &die->die_avals);
433
170
			if (error != 0) {
434
				dw_attr_purge(&die->die_avals);
435
				return error;
436
			}
437
		}
438
439
38
		if (dab->dab_children == DW_CHILDREN_yes)
440
4
			lvl++;
441
442
38
		SIMPLEQ_INSERT_TAIL(dieq, die, die_next);
443
	}
444
445
2
	return 0;
446
2
}
447
448
static void
449
dw_die_purge(struct dwdie_queue *dieq)
450
{
451
	struct dwdie	*die;
452
453
82
	while ((die = SIMPLEQ_FIRST(dieq)) != NULL) {
454
40
		SIMPLEQ_REMOVE_HEAD(dieq, die_next);
455
38
		dw_attr_purge(&die->die_avals);
456
38
		pfree(&die_pool, die);
457
	}
458
459
2
	SIMPLEQ_INIT(dieq);
460
2
}
461
462
int
463
dw_ab_parse(struct dwbuf *abseg, struct dwabbrev_queue *dabq)
464
{
465
	struct dwabbrev	*dab;
466
4
	uint64_t	 code, tag;
467
2
	uint8_t		 children;
468
469
2
	if (abseg->len == 0)
470
		return EINVAL;
471
472
	for (;;) {
473
14
		if (dw_read_uleb128(abseg, &code) || (code == 0))
474
			break;
475
476

24
		if (dw_read_uleb128(abseg, &tag) ||
477
12
		    dw_read_u8(abseg, &children))
478
			return -1;
479
480
12
		dab = pmalloc(&dab_pool, sizeof(*dab));
481
12
		if (dab == NULL)
482
			return ENOMEM;
483
484
12
		dab->dab_code = code;
485
12
		dab->dab_tag = tag;
486
12
		dab->dab_children = children;
487
12
		SIMPLEQ_INIT(&dab->dab_attrs);
488
489
12
		SIMPLEQ_INSERT_TAIL(dabq, dab, dab_next);
490
491
12
		for (;;) {
492
			struct dwattr *dat;
493
74
			uint64_t attr = 0, form = 0;
494
495

148
			if (dw_read_uleb128(abseg, &attr) ||
496
74
			    dw_read_uleb128(abseg, &form))
497
				return -1;
498
499
74
			if ((attr == 0) && (form == 0))
500
12
				break;
501
502
62
			dat = pmalloc(&dat_pool, sizeof(*dat));
503
62
			if (dat == NULL)
504
				return ENOMEM;
505
506
62
			dat->dat_attr = attr;
507
62
			dat->dat_form = form;
508
509
62
			SIMPLEQ_INSERT_TAIL(&dab->dab_attrs, dat, dat_next);
510
148
		}
511
	}
512
513
2
	return 0;
514
2
}
515
516
void
517
dw_dabq_purge(struct dwabbrev_queue *dabq)
518
{
519
	struct dwabbrev	*dab;
520
521
30
	while ((dab = SIMPLEQ_FIRST(dabq)) != NULL) {
522
		struct dwattr *dat;
523
524
14
		SIMPLEQ_REMOVE_HEAD(dabq, dab_next);
525
136
		while ((dat = SIMPLEQ_FIRST(&dab->dab_attrs)) != NULL) {
526
74
			SIMPLEQ_REMOVE_HEAD(&dab->dab_attrs, dat_next);
527
62
			pfree(&dat_pool, dat);
528
		}
529
530
12
		pfree(&dab_pool, dab);
531
	}
532
533
2
	SIMPLEQ_INIT(dabq);
534
2
}
535
536
int
537
dw_cu_parse(struct dwbuf *info, struct dwbuf *abbrev, size_t seglen,
538
    struct dwcu **dcup)
539
{
540
8
	struct dwbuf	 abseg = *abbrev;
541
4
	struct dwbuf	 dwbuf;
542
	size_t		 segoff, nextoff, addrsize;
543
	struct dwcu	*dcu = NULL;
544
4
	uint32_t	 length = 0, abbroff = 0;
545
4
	uint16_t	 version;
546
4
	uint8_t		 psz;
547
	int		 error;
548
#ifndef NOPOOL
549
	static int 	 dw_pool_inited = 0;
550
551
4
	if (!dw_pool_inited) {
552
2
		pool_init(&dcu_pool, "dcu", 1, sizeof(struct dwcu));
553
2
		pool_init(&dab_pool, "dab", 32, sizeof(struct dwabbrev));
554
2
		pool_init(&dat_pool, "dat", 32, sizeof(struct dwattr));
555
2
		pool_init(&die_pool, "die", 512, sizeof(struct dwdie));
556
2
		pool_init(&dav_pool, "dav", 1024, sizeof(struct dwaval));
557
2
		dw_pool_inited = 1;
558
2
	}
559
#endif /* NOPOOL */
560
561

6
	if (info->len == 0 || abbrev->len == 0)
562
2
		return EINVAL;
563
564
	/* Offset in the segment of the current Compile Unit. */
565
2
	segoff = seglen - info->len;
566
567
2
	if (dw_read_u32(info, &length))
568
		return -1;
569
570

4
	if (length >= 0xfffffff0 || length > info->len)
571
		return EOVERFLOW;
572
573
	/* Offset of the next Compile Unit. */
574
2
	nextoff = segoff + length + sizeof(uint32_t);
575
576
2
	if (dw_read_buf(info, &dwbuf, length))
577
		return -1;
578
579
	addrsize = 4; /* XXX */
580
581

4
	if (dw_read_u16(&dwbuf, &version) ||
582
2
	    dw_read_bytes(&dwbuf, &abbroff, addrsize) ||
583
2
	    dw_read_u8(&dwbuf, &psz))
584
		return -1;
585
586
2
	if (dw_skip_bytes(&abseg, abbroff))
587
		return -1;
588
589
	/* Only DWARF2 until extended. */
590
2
	if (version != 2)
591
		return ENOTSUP;
592
593
2
	dcu = pmalloc(&dcu_pool, sizeof(*dcu));
594
2
	if (dcu == NULL)
595
		return ENOMEM;
596
597
2
	dcu->dcu_offset = segoff;
598
2
	dcu->dcu_length = length;
599
2
	dcu->dcu_version = version;
600
2
	dcu->dcu_abbroff = abbroff;
601
2
	dcu->dcu_psize = psz;
602
2
	SIMPLEQ_INIT(&dcu->dcu_abbrevs);
603
2
	SIMPLEQ_INIT(&dcu->dcu_dies);
604
605
2
	error = dw_ab_parse(&abseg, &dcu->dcu_abbrevs);
606
2
	if (error != 0) {
607
		dw_dcu_free(dcu);
608
		return error;
609
	}
610
611
2
	error = dw_die_parse(&dwbuf, nextoff, psz, &dcu->dcu_abbrevs,
612
	    &dcu->dcu_dies);
613
2
	if (error != 0) {
614
		dw_dcu_free(dcu);
615
		return error;
616
	}
617
618
2
	if (dcup != NULL)
619
2
		*dcup = dcu;
620
	else
621
		dw_dcu_free(dcu);
622
623
2
	return 0;
624
4
}
625
626
void
627
dw_dcu_free(struct dwcu *dcu)
628
{
629
4
	if (dcu == NULL)
630
		return;
631
632
2
	dw_die_purge(&dcu->dcu_dies);
633
2
	dw_dabq_purge(&dcu->dcu_abbrevs);
634
2
	pfree(&dcu_pool, dcu);
635
4
}
636
637
int
638
dw_loc_parse(struct dwbuf *dwbuf, uint8_t *pop, uint64_t *poper1,
639
    uint64_t *poper2)
640
{
641
	uint64_t oper1 = 0, oper2 = 0;
642
	uint8_t op;
643
644
	if (dw_read_u8(dwbuf, &op))
645
		return -1;
646
647
	if (pop != NULL)
648
		*pop = op;
649
650
	switch (op) {
651
	case DW_OP_constu:
652
	case DW_OP_plus_uconst:
653
	case DW_OP_regx:
654
	case DW_OP_piece:
655
		dw_read_uleb128(dwbuf, &oper1);
656
		break;
657
658
	case DW_OP_consts:
659
	case DW_OP_breg0 ... DW_OP_breg31:
660
	case DW_OP_fbreg:
661
		dw_read_sleb128(dwbuf, &oper1);
662
		break;
663
	default:
664
		return ENOTSUP;
665
	}
666
667
	if (poper1 != NULL)
668
		*poper1 = oper1;
669
	if (poper2 != NULL)
670
		*poper2 = oper2;
671
672
	return 0;
673
}