xref: /openbsd-src/usr.bin/ctfconv/dw.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
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 	if (d->len < n)
68 		return -1;
69 	memcpy(v, d->buf, n);
70 	d->buf += n;
71 	d->len -= n;
72 	return 0;
73 }
74 
75 static int
76 dw_read_u8(struct dwbuf *d, uint8_t *v)
77 {
78 	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 	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 	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 	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 	uint8_t x;
106 
107 	while (shift < 64 && !dw_read_u8(d, &x)) {
108 		res |= (uint64_t)(x & 0x7f) << shift;
109 		shift += 7;
110 		if ((x & 0x80) == 0) {
111 			if (signextend && shift < 64 && (x & 0x40) != 0)
112 				res |= ~(uint64_t)0 << shift;
113 			*v = res;
114 			return 0;
115 		}
116 	}
117 	return -1;
118 }
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 	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 	if (d->len < n)
153 		return -1;
154 	v->buf = d->buf;
155 	v->len = n;
156 	d->buf += n;
157 	d->len -= n;
158 	return 0;
159 }
160 
161 static int
162 dw_skip_bytes(struct dwbuf *d, size_t n)
163 {
164 	if (d->len < n)
165 		return -1;
166 	d->buf += n;
167 	d->len -= n;
168 	return 0;
169 }
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 	uint64_t	 form = dat->dat_form;
290 	int		 error = 0, i = 0;
291 
292 	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 	dav = pzalloc(&dav_pool, sizeof(*dav));
299 	if (dav == NULL)
300 		return ENOMEM;
301 
302 	dav->dav_dat = dat;
303 
304 	switch (form) {
305 	case DW_FORM_addr:
306 	case DW_FORM_ref_addr:
307 		if (psz == sizeof(uint32_t))
308 			error = dw_read_u32(dwbuf, &dav->dav_u32);
309 		else
310 			error = dw_read_u64(dwbuf, &dav->dav_u64);
311 		break;
312 	case DW_FORM_block1:
313 		error = dw_read_u8(dwbuf, &dav->dav_u8);
314 		if (error == 0)
315 			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 		error = dw_read_u8(dwbuf, &dav->dav_u8);
336 		break;
337 	case DW_FORM_data2:
338 	case DW_FORM_ref2:
339 		error = dw_read_u16(dwbuf, &dav->dav_u16);
340 		break;
341 	case DW_FORM_data4:
342 	case DW_FORM_ref4:
343 		error = dw_read_u32(dwbuf, &dav->dav_u32);
344 		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 		error = dw_read_u32(dwbuf, &dav->dav_u32);
361 		break;
362 	case DW_FORM_flag_present:
363 		dav->dav_u8 = 1;
364 		break;
365 	default:
366 		error = ENOENT;
367 		break;
368 	}
369 
370 	if (error) {
371 		pfree(&dav_pool, dav);
372 		return error;
373 	}
374 
375 	SIMPLEQ_INSERT_TAIL(davq, dav, dav_next);
376 	return 0;
377 }
378 
379 static void
380 dw_attr_purge(struct dwaval_queue *davq)
381 {
382 	struct dwaval	*dav;
383 
384 	while ((dav = SIMPLEQ_FIRST(davq)) != NULL) {
385 		SIMPLEQ_REMOVE_HEAD(davq, dav_next);
386 		pfree(&dav_pool, dav);
387 	}
388 
389 	SIMPLEQ_INIT(davq);
390 }
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 	uint64_t	 code;
400 	size_t		 doff;
401 	uint8_t		 lvl = 0;
402 	int		 error;
403 
404 
405 	while (dwbuf->len > 0) {
406 		doff = nextoff - dwbuf->len;
407 		if (dw_read_uleb128(dwbuf, &code))
408 			return -1;
409 
410 		if (code == 0) {
411 			lvl--;
412 			continue;
413 		}
414 
415 		SIMPLEQ_FOREACH(dab, dabq, dab_next) {
416 			if (dab->dab_code == code)
417 				break;
418 		}
419 		if (dab == NULL)
420 			return ESRCH;
421 
422 		die = pmalloc(&die_pool, sizeof(*die));
423 		if (die == NULL)
424 			return ENOMEM;
425 
426 		die->die_lvl = lvl;
427 		die->die_dab = dab;
428 		die->die_offset = doff;
429 		SIMPLEQ_INIT(&die->die_avals);
430 
431 		SIMPLEQ_FOREACH(dat, &dab->dab_attrs, dat_next) {
432 			error = dw_attr_parse(dwbuf, dat, psz, &die->die_avals);
433 			if (error != 0) {
434 				dw_attr_purge(&die->die_avals);
435 				return error;
436 			}
437 		}
438 
439 		if (dab->dab_children == DW_CHILDREN_yes)
440 			lvl++;
441 
442 		SIMPLEQ_INSERT_TAIL(dieq, die, die_next);
443 	}
444 
445 	return 0;
446 }
447 
448 static void
449 dw_die_purge(struct dwdie_queue *dieq)
450 {
451 	struct dwdie	*die;
452 
453 	while ((die = SIMPLEQ_FIRST(dieq)) != NULL) {
454 		SIMPLEQ_REMOVE_HEAD(dieq, die_next);
455 		dw_attr_purge(&die->die_avals);
456 		pfree(&die_pool, die);
457 	}
458 
459 	SIMPLEQ_INIT(dieq);
460 }
461 
462 int
463 dw_ab_parse(struct dwbuf *abseg, struct dwabbrev_queue *dabq)
464 {
465 	struct dwabbrev	*dab;
466 	uint64_t	 code, tag;
467 	uint8_t		 children;
468 
469 	if (abseg->len == 0)
470 		return EINVAL;
471 
472 	for (;;) {
473 		if (dw_read_uleb128(abseg, &code) || (code == 0))
474 			break;
475 
476 		if (dw_read_uleb128(abseg, &tag) ||
477 		    dw_read_u8(abseg, &children))
478 			return -1;
479 
480 		dab = pmalloc(&dab_pool, sizeof(*dab));
481 		if (dab == NULL)
482 			return ENOMEM;
483 
484 		dab->dab_code = code;
485 		dab->dab_tag = tag;
486 		dab->dab_children = children;
487 		SIMPLEQ_INIT(&dab->dab_attrs);
488 
489 		SIMPLEQ_INSERT_TAIL(dabq, dab, dab_next);
490 
491 		for (;;) {
492 			struct dwattr *dat;
493 			uint64_t attr = 0, form = 0;
494 
495 			if (dw_read_uleb128(abseg, &attr) ||
496 			    dw_read_uleb128(abseg, &form))
497 				return -1;
498 
499 			if ((attr == 0) && (form == 0))
500 				break;
501 
502 			dat = pmalloc(&dat_pool, sizeof(*dat));
503 			if (dat == NULL)
504 				return ENOMEM;
505 
506 			dat->dat_attr = attr;
507 			dat->dat_form = form;
508 
509 			SIMPLEQ_INSERT_TAIL(&dab->dab_attrs, dat, dat_next);
510 		}
511 	}
512 
513 	return 0;
514 }
515 
516 void
517 dw_dabq_purge(struct dwabbrev_queue *dabq)
518 {
519 	struct dwabbrev	*dab;
520 
521 	while ((dab = SIMPLEQ_FIRST(dabq)) != NULL) {
522 		struct dwattr *dat;
523 
524 		SIMPLEQ_REMOVE_HEAD(dabq, dab_next);
525 		while ((dat = SIMPLEQ_FIRST(&dab->dab_attrs)) != NULL) {
526 			SIMPLEQ_REMOVE_HEAD(&dab->dab_attrs, dat_next);
527 			pfree(&dat_pool, dat);
528 		}
529 
530 		pfree(&dab_pool, dab);
531 	}
532 
533 	SIMPLEQ_INIT(dabq);
534 }
535 
536 int
537 dw_cu_parse(struct dwbuf *info, struct dwbuf *abbrev, size_t seglen,
538     struct dwcu **dcup)
539 {
540 	struct dwbuf	 abseg = *abbrev;
541 	struct dwbuf	 dwbuf;
542 	size_t		 segoff, nextoff, addrsize;
543 	struct dwcu	*dcu = NULL;
544 	uint32_t	 length = 0, abbroff = 0;
545 	uint16_t	 version;
546 	uint8_t		 psz;
547 	int		 error;
548 #ifndef NOPOOL
549 	static int 	 dw_pool_inited = 0;
550 
551 	if (!dw_pool_inited) {
552 		pool_init(&dcu_pool, "dcu", 1, sizeof(struct dwcu));
553 		pool_init(&dab_pool, "dab", 32, sizeof(struct dwabbrev));
554 		pool_init(&dat_pool, "dat", 32, sizeof(struct dwattr));
555 		pool_init(&die_pool, "die", 512, sizeof(struct dwdie));
556 		pool_init(&dav_pool, "dav", 1024, sizeof(struct dwaval));
557 		dw_pool_inited = 1;
558 	}
559 #endif /* NOPOOL */
560 
561 	if (info->len == 0 || abbrev->len == 0)
562 		return EINVAL;
563 
564 	/* Offset in the segment of the current Compile Unit. */
565 	segoff = seglen - info->len;
566 
567 	if (dw_read_u32(info, &length))
568 		return -1;
569 
570 	if (length >= 0xfffffff0 || length > info->len)
571 		return EOVERFLOW;
572 
573 	/* Offset of the next Compile Unit. */
574 	nextoff = segoff + length + sizeof(uint32_t);
575 
576 	if (dw_read_buf(info, &dwbuf, length))
577 		return -1;
578 
579 	addrsize = 4; /* XXX */
580 
581 	if (dw_read_u16(&dwbuf, &version) ||
582 	    dw_read_bytes(&dwbuf, &abbroff, addrsize) ||
583 	    dw_read_u8(&dwbuf, &psz))
584 		return -1;
585 
586 	if (dw_skip_bytes(&abseg, abbroff))
587 		return -1;
588 
589 	/* Only DWARF2 until extended. */
590 	if (version != 2)
591 		return ENOTSUP;
592 
593 	dcu = pmalloc(&dcu_pool, sizeof(*dcu));
594 	if (dcu == NULL)
595 		return ENOMEM;
596 
597 	dcu->dcu_offset = segoff;
598 	dcu->dcu_length = length;
599 	dcu->dcu_version = version;
600 	dcu->dcu_abbroff = abbroff;
601 	dcu->dcu_psize = psz;
602 	SIMPLEQ_INIT(&dcu->dcu_abbrevs);
603 	SIMPLEQ_INIT(&dcu->dcu_dies);
604 
605 	error = dw_ab_parse(&abseg, &dcu->dcu_abbrevs);
606 	if (error != 0) {
607 		dw_dcu_free(dcu);
608 		return error;
609 	}
610 
611 	error = dw_die_parse(&dwbuf, nextoff, psz, &dcu->dcu_abbrevs,
612 	    &dcu->dcu_dies);
613 	if (error != 0) {
614 		dw_dcu_free(dcu);
615 		return error;
616 	}
617 
618 	if (dcup != NULL)
619 		*dcup = dcu;
620 	else
621 		dw_dcu_free(dcu);
622 
623 	return 0;
624 }
625 
626 void
627 dw_dcu_free(struct dwcu *dcu)
628 {
629 	if (dcu == NULL)
630 		return;
631 
632 	dw_die_purge(&dcu->dcu_dies);
633 	dw_dabq_purge(&dcu->dcu_abbrevs);
634 	pfree(&dcu_pool, dcu);
635 }
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 }
674