[BACK]Return to dw.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ctfconv

Annotation of src/usr.bin/ctfconv/dw.c, Revision 1.4

1.4     ! mpi         1: /*     $OpenBSD: dw.c,v 1.3 2017/09/04 12:56:01 anton 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) {
1.4     ! mpi       651:        case DW_OP_constu:
1.1       mpi       652:        case DW_OP_plus_uconst:
1.4     ! mpi       653:        case DW_OP_regx:
        !           654:        case DW_OP_piece:
1.1       mpi       655:                dw_read_uleb128(dwbuf, &oper1);
1.4     ! mpi       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);
1.1       mpi       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: }