Annotation of src/usr.bin/ctfconv/dw.c, Revision 1.6
1.6 ! claudio 1: /* $OpenBSD: dw.c,v 1.5 2021/10/25 19:54:29 kn 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>
1.6 ! claudio 24: #include <stdio.h>
1.1 mpi 25: #include <stdlib.h>
26: #include <string.h>
27:
28: #include "dw.h"
29: #include "dwarf.h"
30: #include "pool.h"
31:
32: #ifndef NOPOOL
33: struct pool dcu_pool, die_pool, dav_pool, dab_pool, dat_pool;
34: #endif /* NOPOOL */
35:
36: #ifndef nitems
37: #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
38: #endif
39:
40: static int dw_read_u8(struct dwbuf *, uint8_t *);
41: static int dw_read_u16(struct dwbuf *, uint16_t *);
42: static int dw_read_u32(struct dwbuf *, uint32_t *);
43: static int dw_read_u64(struct dwbuf *, uint64_t *);
44:
45: static int dw_read_sleb128(struct dwbuf *, int64_t *);
46: static int dw_read_uleb128(struct dwbuf *, uint64_t *);
47:
48: static int dw_read_bytes(struct dwbuf *, void *, size_t);
49: static int dw_read_string(struct dwbuf *, const char **);
50: static int dw_read_buf(struct dwbuf *, struct dwbuf *, size_t);
51:
52: static int dw_skip_bytes(struct dwbuf *, size_t);
53:
54: static int dw_attr_parse(struct dwbuf *, struct dwattr *, uint8_t,
55: struct dwaval_queue *);
56: static void dw_attr_purge(struct dwaval_queue *);
57: static int dw_die_parse(struct dwbuf *, size_t, uint8_t,
58: struct dwabbrev_queue *, struct dwdie_queue *);
59: static void dw_die_purge(struct dwdie_queue *);
60:
61: static int
62: dw_read_bytes(struct dwbuf *d, void *v, size_t n)
63: {
64: if (d->len < n)
65: return -1;
66: memcpy(v, d->buf, n);
67: d->buf += n;
68: d->len -= n;
69: return 0;
70: }
71:
72: static int
73: dw_read_u8(struct dwbuf *d, uint8_t *v)
74: {
75: return dw_read_bytes(d, v, sizeof(*v));
76: }
77:
78: static int
79: dw_read_u16(struct dwbuf *d, uint16_t *v)
80: {
81: return dw_read_bytes(d, v, sizeof(*v));
82: }
83:
84: static int
85: dw_read_u32(struct dwbuf *d, uint32_t *v)
86: {
87: return dw_read_bytes(d, v, sizeof(*v));
88: }
89:
90: static int
91: dw_read_u64(struct dwbuf *d, uint64_t *v)
92: {
93: return dw_read_bytes(d, v, sizeof(*v));
94: }
95:
96: /* Read a DWARF LEB128 (little-endian base-128) value. */
97: static inline int
98: dw_read_leb128(struct dwbuf *d, uint64_t *v, int signextend)
99: {
100: unsigned int shift = 0;
101: uint64_t res = 0;
102: uint8_t x;
103:
104: while (shift < 64 && !dw_read_u8(d, &x)) {
105: res |= (uint64_t)(x & 0x7f) << shift;
106: shift += 7;
107: if ((x & 0x80) == 0) {
108: if (signextend && shift < 64 && (x & 0x40) != 0)
109: res |= ~(uint64_t)0 << shift;
110: *v = res;
111: return 0;
112: }
113: }
114: return -1;
115: }
116:
117: static int
118: dw_read_sleb128(struct dwbuf *d, int64_t *v)
119: {
120: return dw_read_leb128(d, (uint64_t *)v, 1);
121: }
122:
123: static int
124: dw_read_uleb128(struct dwbuf *d, uint64_t *v)
125: {
126: return dw_read_leb128(d, v, 0);
127: }
128:
129: /* Read a NUL terminated string. */
130: static int
131: dw_read_string(struct dwbuf *d, const char **s)
132: {
133: const char *end = memchr(d->buf, '\0', d->len);
134: size_t n;
135:
136: if (end == NULL)
137: return -1;
138:
139: n = end - d->buf + 1;
140: *s = d->buf;
141: d->buf += n;
142: d->len -= n;
143: return 0;
144: }
145:
146: static int
147: dw_read_buf(struct dwbuf *d, struct dwbuf *v, size_t n)
148: {
149: if (d->len < n)
150: return -1;
151: v->buf = d->buf;
152: v->len = n;
153: d->buf += n;
154: d->len -= n;
155: return 0;
156: }
157:
158: static int
159: dw_skip_bytes(struct dwbuf *d, size_t n)
160: {
161: if (d->len < n)
162: return -1;
163: d->buf += n;
164: d->len -= n;
165: return 0;
166: }
167:
168: const char *
169: dw_tag2name(uint64_t tag)
170: {
171: static const char *dw_tags[] = { DW_TAG_NAMES };
172:
173: if (tag <= nitems(dw_tags))
174: return dw_tags[tag - 1];
175:
176: if (tag == DW_TAG_lo_user)
177: return "DW_TAG_lo_user";
178: if (tag == DW_TAG_hi_user)
179: return "DW_TAG_hi_user";
180:
181: return NULL;
182: }
183:
184: const char *
185: dw_at2name(uint64_t at)
186: {
187: static const char *dw_attrs[] = { DW_AT_NAMES };
1.6 ! claudio 188: static char buf[64];
1.1 mpi 189:
190: if (at <= nitems(dw_attrs))
191: return dw_attrs[at - 1];
192:
193: if (at == DW_AT_lo_user)
194: return "DW_AT_lo_user";
195: if (at == DW_AT_hi_user)
196: return "DW_AT_hi_user";
197:
1.6 ! claudio 198: snprintf(buf, sizeof(buf), "#%llu", at);
! 199: return buf;
1.1 mpi 200: }
201:
202: const char *
203: dw_form2name(uint64_t form)
204: {
205: static const char *dw_forms[] = { DW_FORM_NAMES };
206:
207: if (form <= nitems(dw_forms))
208: return dw_forms[form - 1];
209:
210: if (form == DW_FORM_GNU_ref_alt)
211: return "DW_FORM_GNU_ref_alt";
212: if (form == DW_FORM_GNU_strp_alt)
213: return "DW_FORM_GNU_strp_alt";
214:
215: return NULL;
216: }
217:
218: const char *
219: dw_op2name(uint8_t op)
220: {
221: static const char *dw_ops[] = { DW_OP_NAMES };
222:
223: if (op <= nitems(dw_ops))
224: return dw_ops[op - 1];
225:
226: if (op == DW_OP_lo_user)
227: return "DW_OP_lo_user";
228: if (op == DW_OP_hi_user)
229: return "DW_OP_hi_user";
230:
231: return NULL;
232: }
233:
234: static int
235: dw_attr_parse(struct dwbuf *dwbuf, struct dwattr *dat, uint8_t psz,
236: struct dwaval_queue *davq)
237: {
238: struct dwaval *dav;
239: uint64_t form = dat->dat_form;
240: int error = 0, i = 0;
241:
242: while (form == DW_FORM_indirect) {
243: /* XXX loop prevention not strict enough? */
244: if (dw_read_uleb128(dwbuf, &form) || (++i > 3))
245: return ELOOP;
246: }
247:
248: dav = pzalloc(&dav_pool, sizeof(*dav));
249: if (dav == NULL)
250: return ENOMEM;
251:
252: dav->dav_dat = dat;
253:
254: switch (form) {
255: case DW_FORM_addr:
256: case DW_FORM_ref_addr:
257: if (psz == sizeof(uint32_t))
258: error = dw_read_u32(dwbuf, &dav->dav_u32);
259: else
260: error = dw_read_u64(dwbuf, &dav->dav_u64);
261: break;
262: case DW_FORM_block1:
263: error = dw_read_u8(dwbuf, &dav->dav_u8);
264: if (error == 0)
265: error = dw_read_buf(dwbuf, &dav->dav_buf, dav->dav_u8);
266: break;
267: case DW_FORM_block2:
268: error = dw_read_u16(dwbuf, &dav->dav_u16);
269: if (error == 0)
270: error = dw_read_buf(dwbuf, &dav->dav_buf, dav->dav_u16);
271: break;
272: case DW_FORM_block4:
273: error = dw_read_u32(dwbuf, &dav->dav_u32);
274: if (error == 0)
275: error = dw_read_buf(dwbuf, &dav->dav_buf, dav->dav_u32);
276: break;
277: case DW_FORM_block:
278: error = dw_read_uleb128(dwbuf, &dav->dav_u64);
279: if (error == 0)
280: error = dw_read_buf(dwbuf, &dav->dav_buf, dav->dav_u64);
281: break;
282: case DW_FORM_data1:
283: case DW_FORM_flag:
284: case DW_FORM_ref1:
285: error = dw_read_u8(dwbuf, &dav->dav_u8);
286: break;
287: case DW_FORM_data2:
288: case DW_FORM_ref2:
289: error = dw_read_u16(dwbuf, &dav->dav_u16);
290: break;
291: case DW_FORM_data4:
292: case DW_FORM_ref4:
293: error = dw_read_u32(dwbuf, &dav->dav_u32);
294: break;
295: case DW_FORM_data8:
296: case DW_FORM_ref8:
297: error = dw_read_u64(dwbuf, &dav->dav_u64);
298: break;
299: case DW_FORM_ref_udata:
300: case DW_FORM_udata:
301: error = dw_read_uleb128(dwbuf, &dav->dav_u64);
302: break;
303: case DW_FORM_sdata:
304: error = dw_read_sleb128(dwbuf, &dav->dav_s64);
305: break;
306: case DW_FORM_string:
307: error = dw_read_string(dwbuf, &dav->dav_str);
308: break;
309: case DW_FORM_strp:
310: error = dw_read_u32(dwbuf, &dav->dav_u32);
311: break;
312: case DW_FORM_flag_present:
313: dav->dav_u8 = 1;
314: break;
315: default:
316: error = ENOENT;
317: break;
318: }
319:
320: if (error) {
321: pfree(&dav_pool, dav);
322: return error;
323: }
324:
325: SIMPLEQ_INSERT_TAIL(davq, dav, dav_next);
326: return 0;
327: }
328:
329: static void
330: dw_attr_purge(struct dwaval_queue *davq)
331: {
332: struct dwaval *dav;
333:
334: while ((dav = SIMPLEQ_FIRST(davq)) != NULL) {
335: SIMPLEQ_REMOVE_HEAD(davq, dav_next);
336: pfree(&dav_pool, dav);
337: }
338:
339: SIMPLEQ_INIT(davq);
340: }
341:
342: static int
343: dw_die_parse(struct dwbuf *dwbuf, size_t nextoff, uint8_t psz,
344: struct dwabbrev_queue *dabq, struct dwdie_queue *dieq)
345: {
346: struct dwdie *die;
347: struct dwabbrev *dab;
348: struct dwattr *dat;
349: uint64_t code;
350: size_t doff;
351: uint8_t lvl = 0;
352: int error;
353:
354:
355: while (dwbuf->len > 0) {
356: doff = nextoff - dwbuf->len;
357: if (dw_read_uleb128(dwbuf, &code))
358: return -1;
359:
360: if (code == 0) {
361: lvl--;
362: continue;
363: }
364:
365: SIMPLEQ_FOREACH(dab, dabq, dab_next) {
366: if (dab->dab_code == code)
367: break;
368: }
369: if (dab == NULL)
370: return ESRCH;
371:
372: die = pmalloc(&die_pool, sizeof(*die));
373: if (die == NULL)
374: return ENOMEM;
375:
376: die->die_lvl = lvl;
377: die->die_dab = dab;
378: die->die_offset = doff;
379: SIMPLEQ_INIT(&die->die_avals);
380:
381: SIMPLEQ_FOREACH(dat, &dab->dab_attrs, dat_next) {
382: error = dw_attr_parse(dwbuf, dat, psz, &die->die_avals);
383: if (error != 0) {
384: dw_attr_purge(&die->die_avals);
385: return error;
386: }
387: }
388:
389: if (dab->dab_children == DW_CHILDREN_yes)
390: lvl++;
391:
392: SIMPLEQ_INSERT_TAIL(dieq, die, die_next);
393: }
394:
395: return 0;
396: }
397:
398: static void
399: dw_die_purge(struct dwdie_queue *dieq)
400: {
401: struct dwdie *die;
402:
403: while ((die = SIMPLEQ_FIRST(dieq)) != NULL) {
404: SIMPLEQ_REMOVE_HEAD(dieq, die_next);
405: dw_attr_purge(&die->die_avals);
406: pfree(&die_pool, die);
407: }
408:
409: SIMPLEQ_INIT(dieq);
410: }
411:
412: int
413: dw_ab_parse(struct dwbuf *abseg, struct dwabbrev_queue *dabq)
414: {
415: struct dwabbrev *dab;
416: uint64_t code, tag;
417: uint8_t children;
418:
419: if (abseg->len == 0)
420: return EINVAL;
421:
422: for (;;) {
423: if (dw_read_uleb128(abseg, &code) || (code == 0))
424: break;
425:
426: if (dw_read_uleb128(abseg, &tag) ||
427: dw_read_u8(abseg, &children))
428: return -1;
429:
430: dab = pmalloc(&dab_pool, sizeof(*dab));
431: if (dab == NULL)
432: return ENOMEM;
433:
434: dab->dab_code = code;
435: dab->dab_tag = tag;
436: dab->dab_children = children;
437: SIMPLEQ_INIT(&dab->dab_attrs);
438:
439: SIMPLEQ_INSERT_TAIL(dabq, dab, dab_next);
440:
441: for (;;) {
442: struct dwattr *dat;
443: uint64_t attr = 0, form = 0;
444:
445: if (dw_read_uleb128(abseg, &attr) ||
446: dw_read_uleb128(abseg, &form))
447: return -1;
448:
449: if ((attr == 0) && (form == 0))
450: break;
451:
452: dat = pmalloc(&dat_pool, sizeof(*dat));
453: if (dat == NULL)
454: return ENOMEM;
455:
456: dat->dat_attr = attr;
457: dat->dat_form = form;
458:
459: SIMPLEQ_INSERT_TAIL(&dab->dab_attrs, dat, dat_next);
460: }
461: }
462:
463: return 0;
464: }
465:
466: void
467: dw_dabq_purge(struct dwabbrev_queue *dabq)
468: {
469: struct dwabbrev *dab;
470:
471: while ((dab = SIMPLEQ_FIRST(dabq)) != NULL) {
472: struct dwattr *dat;
473:
474: SIMPLEQ_REMOVE_HEAD(dabq, dab_next);
475: while ((dat = SIMPLEQ_FIRST(&dab->dab_attrs)) != NULL) {
476: SIMPLEQ_REMOVE_HEAD(&dab->dab_attrs, dat_next);
477: pfree(&dat_pool, dat);
478: }
479:
480: pfree(&dab_pool, dab);
481: }
482:
483: SIMPLEQ_INIT(dabq);
484: }
485:
486: int
487: dw_cu_parse(struct dwbuf *info, struct dwbuf *abbrev, size_t seglen,
488: struct dwcu **dcup)
489: {
490: struct dwbuf abseg = *abbrev;
491: struct dwbuf dwbuf;
492: size_t segoff, nextoff, addrsize;
493: struct dwcu *dcu = NULL;
494: uint32_t length = 0, abbroff = 0;
495: uint16_t version;
496: uint8_t psz;
497: int error;
498: #ifndef NOPOOL
499: static int dw_pool_inited = 0;
500:
501: if (!dw_pool_inited) {
502: pool_init(&dcu_pool, "dcu", 1, sizeof(struct dwcu));
503: pool_init(&dab_pool, "dab", 32, sizeof(struct dwabbrev));
504: pool_init(&dat_pool, "dat", 32, sizeof(struct dwattr));
505: pool_init(&die_pool, "die", 512, sizeof(struct dwdie));
506: pool_init(&dav_pool, "dav", 1024, sizeof(struct dwaval));
507: dw_pool_inited = 1;
508: }
509: #endif /* NOPOOL */
510:
511: if (info->len == 0 || abbrev->len == 0)
512: return EINVAL;
513:
514: /* Offset in the segment of the current Compile Unit. */
515: segoff = seglen - info->len;
516:
517: if (dw_read_u32(info, &length))
518: return -1;
519:
520: if (length >= 0xfffffff0 || length > info->len)
521: return EOVERFLOW;
522:
1.3 anton 523: /* Offset of the next Compile Unit. */
1.1 mpi 524: nextoff = segoff + length + sizeof(uint32_t);
525:
526: if (dw_read_buf(info, &dwbuf, length))
527: return -1;
528:
529: addrsize = 4; /* XXX */
530:
531: if (dw_read_u16(&dwbuf, &version) ||
532: dw_read_bytes(&dwbuf, &abbroff, addrsize) ||
533: dw_read_u8(&dwbuf, &psz))
534: return -1;
535:
536: if (dw_skip_bytes(&abseg, abbroff))
537: return -1;
538:
539: /* Only DWARF2 until extended. */
540: if (version != 2)
541: return ENOTSUP;
542:
543: dcu = pmalloc(&dcu_pool, sizeof(*dcu));
544: if (dcu == NULL)
545: return ENOMEM;
546:
547: dcu->dcu_offset = segoff;
548: dcu->dcu_length = length;
549: dcu->dcu_version = version;
550: dcu->dcu_abbroff = abbroff;
551: dcu->dcu_psize = psz;
552: SIMPLEQ_INIT(&dcu->dcu_abbrevs);
553: SIMPLEQ_INIT(&dcu->dcu_dies);
554:
555: error = dw_ab_parse(&abseg, &dcu->dcu_abbrevs);
556: if (error != 0) {
557: dw_dcu_free(dcu);
558: return error;
559: }
560:
561: error = dw_die_parse(&dwbuf, nextoff, psz, &dcu->dcu_abbrevs,
562: &dcu->dcu_dies);
563: if (error != 0) {
564: dw_dcu_free(dcu);
565: return error;
566: }
567:
568: if (dcup != NULL)
569: *dcup = dcu;
570: else
571: dw_dcu_free(dcu);
572:
573: return 0;
574: }
575:
576: void
577: dw_dcu_free(struct dwcu *dcu)
578: {
579: if (dcu == NULL)
580: return;
581:
582: dw_die_purge(&dcu->dcu_dies);
583: dw_dabq_purge(&dcu->dcu_abbrevs);
584: pfree(&dcu_pool, dcu);
585: }
586:
587: int
588: dw_loc_parse(struct dwbuf *dwbuf, uint8_t *pop, uint64_t *poper1,
589: uint64_t *poper2)
590: {
591: uint64_t oper1 = 0, oper2 = 0;
592: uint8_t op;
593:
594: if (dw_read_u8(dwbuf, &op))
595: return -1;
596:
597: if (pop != NULL)
598: *pop = op;
599:
600: switch (op) {
1.4 mpi 601: case DW_OP_constu:
1.1 mpi 602: case DW_OP_plus_uconst:
1.4 mpi 603: case DW_OP_regx:
604: case DW_OP_piece:
1.1 mpi 605: dw_read_uleb128(dwbuf, &oper1);
1.4 mpi 606: break;
607:
608: case DW_OP_consts:
609: case DW_OP_breg0 ... DW_OP_breg31:
610: case DW_OP_fbreg:
611: dw_read_sleb128(dwbuf, &oper1);
1.1 mpi 612: break;
613: default:
614: return ENOTSUP;
615: }
616:
617: if (poper1 != NULL)
618: *poper1 = oper1;
619: if (poper2 != NULL)
620: *poper2 = oper2;
621:
622: return 0;
623: }