[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.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: }