Annotation of src/usr.bin/ctfconv/dw.c, Revision 1.3
1.3 ! anton 1: /* $OpenBSD: dw.c,v 1.2 2017/08/11 14:58:56 jasper Exp $ */
1.2 jasper 2:
1.1 mpi 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:
1.3 ! anton 573: /* Offset of the next Compile Unit. */
1.1 mpi 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_plus_uconst:
652: dw_read_uleb128(dwbuf, &oper1);
653: break;
654: default:
655: return ENOTSUP;
656: }
657:
658: if (poper1 != NULL)
659: *poper1 = oper1;
660: if (poper2 != NULL)
661: *poper2 = oper2;
662:
663: return 0;
664: }