 * Diffie Hellman Key Exchange, Group Agnostic
 */
static int diffie_hellman_sha256(LIBSSH2_SESSION *session,
                                 _libssh2_bn *g,
                                 _libssh2_bn *p,
                                 int group_order,
                                 unsigned char packet_type_init,
                                 unsigned char packet_type_reply,
                                 unsigned char *midhash,
                                 unsigned long midhash_len,
                                 kmdhgGPshakex_state_t *exchange_state)
{
    int ret = 0;
    int rc;
    libssh2_sha256_ctx exchange_hash_ctx;

    if(exchange_state->state == libssh2_NB_state_idle) {
        /* Setup initial values */
        exchange_state->e_packet = NULL;
        exchange_state->s_packet = NULL;
        exchange_state->k_value = NULL;
        exchange_state->ctx = _libssh2_bn_ctx_new();
        libssh2_dh_init(&exchange_state->x);
        exchange_state->e = _libssh2_bn_init(); /* g^x mod p */
        exchange_state->f = _libssh2_bn_init_from_bin(); /* g^(Random from server) mod p */
        exchange_state->k = _libssh2_bn_init(); /* The shared secret: f^x mod p */

        /* Zero the whole thing out */
        memset(&exchange_state->req_state, 0, sizeof(packet_require_state_t));

        /* Generate x and e */
        rc = libssh2_dh_key_pair(&exchange_state->x, exchange_state->e, g, p,
                                 group_order, exchange_state->ctx);
        if(rc)
            goto clean_exit;

        /* Send KEX init */
        /* packet_type(1) + String Length(4) + leading 0(1) */
        exchange_state->e_packet_len =
            _libssh2_bn_bytes(exchange_state->e) + 6;
        if(_libssh2_bn_bits(exchange_state->e) % 8) {
            /* Leading 00 not needed */
            exchange_state->e_packet_len--;
        }

        exchange_state->e_packet =
            LIBSSH2_ALLOC(session, exchange_state->e_packet_len);
        if(!exchange_state->e_packet) {
            ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                                 "Out of memory error");
            goto clean_exit;
        }
        exchange_state->e_packet[0] = packet_type_init;
        _libssh2_htonu32(exchange_state->e_packet + 1,
                         exchange_state->e_packet_len - 5);
        if(_libssh2_bn_bits(exchange_state->e) % 8) {
            _libssh2_bn_to_bin(exchange_state->e,
                               exchange_state->e_packet + 5);
        }
        else {
            exchange_state->e_packet[5] = 0;
            _libssh2_bn_to_bin(exchange_state->e,
                               exchange_state->e_packet + 6);
        }

        _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sending KEX packet %d",
                       (int) packet_type_init);
        exchange_state->state = libssh2_NB_state_created;
    }

    if(exchange_state->state == libssh2_NB_state_created) {
        rc = _libssh2_transport_send(session, exchange_state->e_packet,
                                     exchange_state->e_packet_len,
                                     NULL, 0);
        if(rc == LIBSSH2_ERROR_EAGAIN) {
            return rc;
        }
        else if(rc) {
            ret = _libssh2_error(session, rc,
                                 "Unable to send KEX init message");
            goto clean_exit;
        }
        exchange_state->state = libssh2_NB_state_sent;
    }

    if(exchange_state->state == libssh2_NB_state_sent) {
        if(session->burn_optimistic_kexinit) {
            /* The first KEX packet to come along will be the guess initially
             * sent by the server.  That guess turned out to be wrong so we
             * need to silently ignore it */
            int burn_type;

            _libssh2_debug(session, LIBSSH2_TRACE_KEX,
                           "Waiting for badly guessed KEX packet (to be ignored)");
            burn_type =
                _libssh2_packet_burn(session, &exchange_state->burn_state);
            if(burn_type == LIBSSH2_ERROR_EAGAIN) {
                return burn_type;
            }
            else if(burn_type <= 0) {
                /* Failed to receive a packet */
                ret = burn_type;
                goto clean_exit;
            }
            session->burn_optimistic_kexinit = 0;

            _libssh2_debug(session, LIBSSH2_TRACE_KEX,
                           "Burnt packet of type: %02x",
                           (unsigned int) burn_type);
        }

        exchange_state->state = libssh2_NB_state_sent1;
    }

    if(exchange_state->state == libssh2_NB_state_sent1) {
        /* Wait for KEX reply */
        rc = _libssh2_packet_require(session, packet_type_reply,
                                     &exchange_state->s_packet,
                                     &exchange_state->s_packet_len, 0, NULL,
                                     0, &exchange_state->req_state);
        if(rc == LIBSSH2_ERROR_EAGAIN) {
            return rc;
        }
        if(rc) {
            ret = _libssh2_error(session, LIBSSH2_ERROR_TIMEOUT,
                                 "Timed out waiting for KEX reply");
            goto clean_exit;
        }

        /* Parse KEXDH_REPLY */
        exchange_state->s = exchange_state->s_packet + 1;

        session->server_hostkey_len = _libssh2_ntohu32(exchange_state->s);
        exchange_state->s += 4;

        if(session->server_hostkey)
            LIBSSH2_FREE(session, session->server_hostkey);

        session->server_hostkey =
            LIBSSH2_ALLOC(session, session->server_hostkey_len);
        if(!session->server_hostkey) {
            ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                                 "Unable to allocate memory for a copy "
                                 "of the host key");
            goto clean_exit;
        }
        memcpy(session->server_hostkey, exchange_state->s,
               session->server_hostkey_len);
        exchange_state->s += session->server_hostkey_len;

#if LIBSSH2_MD5
        {
            libssh2_md5_ctx fingerprint_ctx;

            if(libssh2_md5_init(&fingerprint_ctx)) {
                libssh2_md5_update(fingerprint_ctx, session->server_hostkey,
                                   session->server_hostkey_len);
                libssh2_md5_final(fingerprint_ctx,
                                  session->server_hostkey_md5);
                session->server_hostkey_md5_valid = TRUE;
            }
            else {
                session->server_hostkey_md5_valid = FALSE;
            }
        }
#ifdef LIBSSH2DEBUG
        {
            char fingerprint[50], *fprint = fingerprint;
            int i;
            for(i = 0; i < 16; i++, fprint += 3) {
                snprintf(fprint, 4, "%02x:", session->server_hostkey_md5[i]);
            }
            *(--fprint) = '\0';
            _libssh2_debug(session, LIBSSH2_TRACE_KEX,
                           "Server's MD5 Fingerprint: %s", fingerprint);
        }
#endif /* LIBSSH2DEBUG */
#endif /* ! LIBSSH2_MD5 */

        {
            libssh2_sha1_ctx fingerprint_ctx;

            if(libssh2_sha1_init(&fingerprint_ctx)) {
                libssh2_sha1_update(fingerprint_ctx, session->server_hostkey,
                                    session->server_hostkey_len);
                libssh2_sha1_final(fingerprint_ctx,
                                   session->server_hostkey_sha1);
                session->server_hostkey_sha1_valid = TRUE;
            }
            else {
                session->server_hostkey_sha1_valid = FALSE;
            }
        }
#ifdef LIBSSH2DEBUG
        {
            char fingerprint[64], *fprint = fingerprint;
            int i;

            for(i = 0; i < 20; i++, fprint += 3) {
                snprintf(fprint, 4, "%02x:", session->server_hostkey_sha1[i]);
            }
            *(--fprint) = '\0';
            _libssh2_debug(session, LIBSSH2_TRACE_KEX,
                           "Server's SHA1 Fingerprint: %s", fingerprint);
        }
#endif /* LIBSSH2DEBUG */

        {
            libssh2_sha256_ctx fingerprint_ctx;

            if(libssh2_sha256_init(&fingerprint_ctx)) {
                libssh2_sha256_update(fingerprint_ctx, session->server_hostkey,
                                      session->server_hostkey_len);
                libssh2_sha256_final(fingerprint_ctx,
                                     session->server_hostkey_sha256);
                session->server_hostkey_sha256_valid = TRUE;
            }
            else {
                session->server_hostkey_sha256_valid = FALSE;
            }
        }
#ifdef LIBSSH2DEBUG
        {
            char *base64Fingerprint = NULL;
            _libssh2_base64_encode(session, (const char *)session->server_hostkey_sha256,
                                   SHA256_DIGEST_LENGTH, &base64Fingerprint);
            if(base64Fingerprint != NULL) {
                _libssh2_debug(session, LIBSSH2_TRACE_KEX,
                               "Server's SHA256 Fingerprint: %s", base64Fingerprint);
                LIBSSH2_FREE(session, base64Fingerprint);
            }
        }
#endif /* LIBSSH2DEBUG */

        if(session->hostkey->init(session, session->server_hostkey,
                                   session->server_hostkey_len,
                                   &session->server_hostkey_abstract)) {
            ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT,
                                 "Unable to initialize hostkey importer");
            goto clean_exit;
        }

        exchange_state->f_value_len = _libssh2_ntohu32(exchange_state->s);
        exchange_state->s += 4;
        exchange_state->f_value = exchange_state->s;
        exchange_state->s += exchange_state->f_value_len;
        _libssh2_bn_from_bin(exchange_state->f, exchange_state->f_value_len,
                             exchange_state->f_value);

        exchange_state->h_sig_len = _libssh2_ntohu32(exchange_state->s);
        exchange_state->s += 4;
        exchange_state->h_sig = exchange_state->s;

        /* Compute the shared secret */
        libssh2_dh_secret(&exchange_state->x, exchange_state->k,
                          exchange_state->f, p, exchange_state->ctx);
        exchange_state->k_value_len = _libssh2_bn_bytes(exchange_state->k) + 5;
        if(_libssh2_bn_bits(exchange_state->k) % 8) {
            /* don't need leading 00 */
            exchange_state->k_value_len--;
        }
        exchange_state->k_value =
            LIBSSH2_ALLOC(session, exchange_state->k_value_len);
        if(!exchange_state->k_value) {
            ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                                 "Unable to allocate buffer for K");
            goto clean_exit;
        }
        _libssh2_htonu32(exchange_state->k_value,
                         exchange_state->k_value_len - 4);
        if(_libssh2_bn_bits(exchange_state->k) % 8) {
            _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 4);
        }
        else {
            exchange_state->k_value[4] = 0;
            _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 5);
        }

        exchange_state->exchange_hash = (void *)&exchange_hash_ctx;
        libssh2_sha256_init(&exchange_hash_ctx);

        if(session->local.banner) {
            _libssh2_htonu32(exchange_state->h_sig_comp,
                             strlen((char *) session->local.banner) - 2);
            libssh2_sha256_update(exchange_hash_ctx,
                                  exchange_state->h_sig_comp, 4);
            libssh2_sha256_update(exchange_hash_ctx,
                                  session->local.banner,
                                  strlen((char *) session->local.banner) - 2);
        }
        else {
            _libssh2_htonu32(exchange_state->h_sig_comp,
                             sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1);
            libssh2_sha256_update(exchange_hash_ctx,
                                  exchange_state->h_sig_comp, 4);
            libssh2_sha256_update(exchange_hash_ctx,
                                  (const unsigned char *)LIBSSH2_SSH_DEFAULT_BANNER,
                                  sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1);
        }

        _libssh2_htonu32(exchange_state->h_sig_comp,
                         strlen((char *) session->remote.banner));
        libssh2_sha256_update(exchange_hash_ctx,
                              exchange_state->h_sig_comp, 4);
        libssh2_sha256_update(exchange_hash_ctx,
                              session->remote.banner,
                              strlen((char *) session->remote.banner));

        _libssh2_htonu32(exchange_state->h_sig_comp,
                         session->local.kexinit_len);
        libssh2_sha256_update(exchange_hash_ctx,
                              exchange_state->h_sig_comp, 4);
        libssh2_sha256_update(exchange_hash_ctx,
                              session->local.kexinit,
                              session->local.kexinit_len);

        _libssh2_htonu32(exchange_state->h_sig_comp,
                         session->remote.kexinit_len);
        libssh2_sha256_update(exchange_hash_ctx,
                              exchange_state->h_sig_comp, 4);
        libssh2_sha256_update(exchange_hash_ctx,
                              session->remote.kexinit,
                              session->remote.kexinit_len);

        _libssh2_htonu32(exchange_state->h_sig_comp,
                         session->server_hostkey_len);
        libssh2_sha256_update(exchange_hash_ctx,
                              exchange_state->h_sig_comp, 4);
        libssh2_sha256_update(exchange_hash_ctx,
                              session->server_hostkey,
                              session->server_hostkey_len);

        if(packet_type_init == SSH_MSG_KEX_DH_GEX_INIT) {
            /* diffie-hellman-group-exchange hashes additional fields */
#ifdef LIBSSH2_DH_GEX_NEW
            _libssh2_htonu32(exchange_state->h_sig_comp,
                             LIBSSH2_DH_GEX_MINGROUP);
            _libssh2_htonu32(exchange_state->h_sig_comp + 4,
                             LIBSSH2_DH_GEX_OPTGROUP);
            _libssh2_htonu32(exchange_state->h_sig_comp + 8,
                             LIBSSH2_DH_GEX_MAXGROUP);
            libssh2_sha256_update(exchange_hash_ctx,
                                  exchange_state->h_sig_comp, 12);
#else
            _libssh2_htonu32(exchange_state->h_sig_comp,
                             LIBSSH2_DH_GEX_OPTGROUP);
            libssh2_sha256_update(exchange_hash_ctx,
                                  exchange_state->h_sig_comp, 4);
#endif
        }

        if(midhash) {
            libssh2_sha256_update(exchange_hash_ctx, midhash,
                                  midhash_len);
        }

        libssh2_sha256_update(exchange_hash_ctx,
                              exchange_state->e_packet + 1,
                              exchange_state->e_packet_len - 1);

        _libssh2_htonu32(exchange_state->h_sig_comp,
                         exchange_state->f_value_len);
        libssh2_sha256_update(exchange_hash_ctx,
                              exchange_state->h_sig_comp, 4);
        libssh2_sha256_update(exchange_hash_ctx,
                              exchange_state->f_value,
                              exchange_state->f_value_len);

        libssh2_sha256_update(exchange_hash_ctx,
                              exchange_state->k_value,
                              exchange_state->k_value_len);

        libssh2_sha256_final(exchange_hash_ctx,
                             exchange_state->h_sig_comp);

        if(session->hostkey->
            sig_verify(session, exchange_state->h_sig,
                       exchange_state->h_sig_len, exchange_state->h_sig_comp,
                       SHA256_DIGEST_LENGTH, &session->server_hostkey_abstract)) {
            ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_SIGN,
                                 "Unable to verify hostkey signature");
            goto clean_exit;
        }

        _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sending NEWKEYS message");
        exchange_state->c = SSH_MSG_NEWKEYS;

        exchange_state->state = libssh2_NB_state_sent2;
    }

    if(exchange_state->state == libssh2_NB_state_sent2) {
        rc = _libssh2_transport_send(session, &exchange_state->c, 1, NULL, 0);
        if(rc == LIBSSH2_ERROR_EAGAIN) {
            return rc;
        }
        else if(rc) {
            ret = _libssh2_error(session, rc, "Unable to send NEWKEYS message");
            goto clean_exit;
        }

        exchange_state->state = libssh2_NB_state_sent3;
    }

    if(exchange_state->state == libssh2_NB_state_sent3) {
        rc = _libssh2_packet_require(session, SSH_MSG_NEWKEYS,
                                     &exchange_state->tmp,
                                     &exchange_state->tmp_len, 0, NULL, 0,
                                     &exchange_state->req_state);
        if(rc == LIBSSH2_ERROR_EAGAIN) {
            return rc;
        }
        else if(rc) {
            ret = _libssh2_error(session, rc, "Timed out waiting for NEWKEYS");
            goto clean_exit;
        }
        /* The first key exchange has been performed,
           switch to active crypt/comp/mac mode */
        session->state |= LIBSSH2_STATE_NEWKEYS;
        _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Received NEWKEYS message");

        /* This will actually end up being just packet_type(1)
           for this packet type anyway */
        LIBSSH2_FREE(session, exchange_state->tmp);

        if(!session->session_id) {
            session->session_id = LIBSSH2_ALLOC(session, SHA256_DIGEST_LENGTH);
            if(!session->session_id) {
                ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                                     "Unable to allocate buffer for SHA digest");
                goto clean_exit;
            }
            memcpy(session->session_id, exchange_state->h_sig_comp,
                   SHA256_DIGEST_LENGTH);
            session->session_id_len = SHA256_DIGEST_LENGTH;
            _libssh2_debug(session, LIBSSH2_TRACE_KEX, "session_id calculated");
        }

        /* Cleanup any existing cipher */
        if(session->local.crypt->dtor) {
            session->local.crypt->dtor(session,
                                       &session->local.crypt_abstract);
        }

        /* Calculate IV/Secret/Key for each direction */
        if(session->local.crypt->init) {
            unsigned char *iv = NULL, *secret = NULL;
            int free_iv = 0, free_secret = 0;

            LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, iv,
                                              session->local.crypt->
                                              iv_len,
                                              (const unsigned char *)"A");
            if(!iv) {
                ret = -1;
                goto clean_exit;
            }
            LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, secret,
                                              session->local.crypt->
                                              secret_len,
                                              (const unsigned char *)"C");
            if(!secret) {
                LIBSSH2_FREE(session, iv);
                ret = LIBSSH2_ERROR_KEX_FAILURE;
                goto clean_exit;
            }
            if(session->local.crypt->
                init(session, session->local.crypt, iv, &free_iv, secret,
                     &free_secret, 1, &session->local.crypt_abstract)) {
                LIBSSH2_FREE(session, iv);
                LIBSSH2_FREE(session, secret);
                ret = LIBSSH2_ERROR_KEX_FAILURE;
                goto clean_exit;
            }

            if(free_iv) {
                _libssh2_explicit_zero(iv, session->local.crypt->iv_len);
                LIBSSH2_FREE(session, iv);
            }

            if(free_secret) {
                _libssh2_explicit_zero(secret, session->local.crypt->secret_len);
                LIBSSH2_FREE(session, secret);
            }
        }
        _libssh2_debug(session, LIBSSH2_TRACE_KEX,
                       "Client to Server IV and Key calculated");

        if(session->remote.crypt->dtor) {
            /* Cleanup any existing cipher */
            session->remote.crypt->dtor(session,
                                        &session->remote.crypt_abstract);
        }

        if(session->remote.crypt->init) {
            unsigned char *iv = NULL, *secret = NULL;
            int free_iv = 0, free_secret = 0;

            LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, iv,
                                              session->remote.crypt->
                                              iv_len,
                                              (const unsigned char *)"B");
            if(!iv) {
                ret = LIBSSH2_ERROR_KEX_FAILURE;
                goto clean_exit;
            }
            LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, secret,
                                              session->remote.crypt->
                                              secret_len,
                                              (const unsigned char *)"D");
            if(!secret) {
                LIBSSH2_FREE(session, iv);
                ret = LIBSSH2_ERROR_KEX_FAILURE;
                goto clean_exit;
            }
            if(session->remote.crypt->
                init(session, session->remote.crypt, iv, &free_iv, secret,
                     &free_secret, 0, &session->remote.crypt_abstract)) {
                LIBSSH2_FREE(session, iv);
                LIBSSH2_FREE(session, secret);
                ret = LIBSSH2_ERROR_KEX_FAILURE;
                goto clean_exit;
            }

            if(free_iv) {
                _libssh2_explicit_zero(iv, session->remote.crypt->iv_len);
                LIBSSH2_FREE(session, iv);
            }

            if(free_secret) {
                _libssh2_explicit_zero(secret, session->remote.crypt->secret_len);
                LIBSSH2_FREE(session, secret);
            }
        }
        _libssh2_debug(session, LIBSSH2_TRACE_KEX,
                       "Server to Client IV and Key calculated");

        if(session->local.mac->dtor) {
            session->local.mac->dtor(session, &session->local.mac_abstract);
        }

        if(session->local.mac->init) {
            unsigned char *key = NULL;
            int free_key = 0;

            LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, key,
                                              session->local.mac->
                                              key_len,
                                              (const unsigned char *)"E");
            if(!key) {
                ret = LIBSSH2_ERROR_KEX_FAILURE;
                goto clean_exit;
            }
            session->local.mac->init(session, key, &free_key,
                                     &session->local.mac_abstract);

            if(free_key) {
                _libssh2_explicit_zero(key, session->local.mac->key_len);
                LIBSSH2_FREE(session, key);
            }
        }
        _libssh2_debug(session, LIBSSH2_TRACE_KEX,
                       "Client to Server HMAC Key calculated");

        if(session->remote.mac->dtor) {
            session->remote.mac->dtor(session, &session->remote.mac_abstract);
        }

        if(session->remote.mac->init) {
            unsigned char *key = NULL;
            int free_key = 0;

            LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, key,
                                              session->remote.mac->
                                              key_len,
                                              (const unsigned char *)"F");
            if(!key) {
                ret = LIBSSH2_ERROR_KEX_FAILURE;
                goto clean_exit;
            }
            session->remote.mac->init(session, key, &free_key,
                                      &session->remote.mac_abstract);

            if(free_key) {
                _libssh2_explicit_zero(key, session->remote.mac->key_len);
                LIBSSH2_FREE(session, key);
            }
        }
        _libssh2_debug(session, LIBSSH2_TRACE_KEX,
                       "Server to Client HMAC Key calculated");

        /* Initialize compression for each direction */

        /* Cleanup any existing compression */
        if(session->local.comp && session->local.comp->dtor) {
            session->local.comp->dtor(session, 1,
                                      &session->local.comp_abstract);
        }

        if(session->local.comp && session->local.comp->init) {
            if(session->local.comp->init(session, 1,
                                          &session->local.comp_abstract)) {
                ret = LIBSSH2_ERROR_KEX_FAILURE;
                goto clean_exit;
            }
        }
        _libssh2_debug(session, LIBSSH2_TRACE_KEX,
                       "Client to Server compression initialized");

        if(session->remote.comp && session->remote.comp->dtor) {
            session->remote.comp->dtor(session, 0,
                                       &session->remote.comp_abstract);
        }

        if(session->remote.comp && session->remote.comp->init) {
            if(session->remote.comp->init(session, 0,
                                           &session->remote.comp_abstract)) {
                ret = LIBSSH2_ERROR_KEX_FAILURE;
                goto clean_exit;
            }
        }
        _libssh2_debug(session, LIBSSH2_TRACE_KEX,
                       "Server to Client compression initialized");

    }

  clean_exit:
    libssh2_dh_dtor(&exchange_state->x);
    _libssh2_bn_free(exchange_state->e);
    exchange_state->e = NULL;
    _libssh2_bn_free(exchange_state->f);
    exchange_state->f = NULL;
    _libssh2_bn_free(exchange_state->k);
    exchange_state->k = NULL;
    _libssh2_bn_ctx_free(exchange_state->ctx);
    exchange_state->ctx = NULL;

    if(exchange_state->e_packet) {
        LIBSSH2_FREE(session, exchange_state->e_packet);
        exchange_state->e_packet = NULL;
    }

    if(exchange_state->s_packet) {
        LIBSSH2_FREE(session, exchange_state->s_packet);
        exchange_state->s_packet = NULL;
    }

    if(exchange_state->k_value) {
        LIBSSH2_FREE(session, exchange_state->k_value);
        exchange_state->k_value = NULL;
    }

    exchange_state->state = libssh2_NB_state_idle;


_libssh2_channel_flush(LIBSSH2_CHANNEL *channel, int streamid)
{
    if(channel->flush_state == libssh2_NB_state_idle) {
        LIBSSH2_PACKET *packet =
            _libssh2_list_first(&channel->session->packets);
        channel->flush_refund_bytes = 0;
        channel->flush_flush_bytes = 0;

        while(packet) {
            LIBSSH2_PACKET *next = _libssh2_list_next(&packet->node);
            unsigned char packet_type = packet->data[0];

            if(((packet_type == SSH_MSG_CHANNEL_DATA)
                 || (packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA))
                && (_libssh2_ntohu32(packet->data + 1) == channel->local.id)) {
                /* It's our channel at least */
                long packet_stream_id =
                    (packet_type == SSH_MSG_CHANNEL_DATA) ? 0 :
                    _libssh2_ntohu32(packet->data + 5);
                if((streamid == LIBSSH2_CHANNEL_FLUSH_ALL)
                    || ((packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA)
                        && ((streamid == LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA)
                            || (streamid == packet_stream_id)))
                    || ((packet_type == SSH_MSG_CHANNEL_DATA)
                        && (streamid == 0))) {
                    int bytes_to_flush = packet->data_len - packet->data_head;

                    _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN,
                                   "Flushing %d bytes of data from stream "
                                   "%lu on channel %lu/%lu",
                                   bytes_to_flush, packet_stream_id,
                                   channel->local.id, channel->remote.id);

                    /* It's one of the streams we wanted to flush */
                    channel->flush_refund_bytes += packet->data_len - 13;
                    channel->flush_flush_bytes += bytes_to_flush;

                    LIBSSH2_FREE(channel->session, packet->data);

                    /* remove this packet from the parent's list */
                    _libssh2_list_remove(&packet->node);
                    LIBSSH2_FREE(channel->session, packet);
                }
            }
            packet = next;
        }

        channel->flush_state = libssh2_NB_state_created;
    }

    channel->read_avail -= channel->flush_flush_bytes;
    channel->remote.window_size -= channel->flush_flush_bytes;

    if(channel->flush_refund_bytes) {
        int rc;

        rc = _libssh2_channel_receive_window_adjust(channel,
                                                    channel->flush_refund_bytes,
                                                    1, NULL);
        if(rc == LIBSSH2_ERROR_EAGAIN)
            return rc;
    }

    channel->flush_state = libssh2_NB_state_idle;

    return channel->flush_flush_bytes;
}


int _libssh2_transport_read(LIBSSH2_SESSION * session)
{
    int rc;
    struct transportpacket *p = &session->packet;
    int remainbuf;
    int remainpack;
    int numbytes;
    int numdecrypt;
    unsigned char block[MAX_BLOCKSIZE];
    int blocksize;
    int encrypted = 1;
    size_t total_num;

    /* default clear the bit */
    session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_INBOUND;

    /*
     * All channels, systems, subsystems, etc eventually make it down here
     * when looking for more incoming data. If a key exchange is going on
     * (LIBSSH2_STATE_EXCHANGING_KEYS bit is set) then the remote end will
     * ONLY send key exchange related traffic. In non-blocking mode, there is
     * a chance to break out of the kex_exchange function with an EAGAIN
     * status, and never come back to it. If LIBSSH2_STATE_EXCHANGING_KEYS is
     * active, then we must redirect to the key exchange. However, if
     * kex_exchange is active (as in it is the one that calls this execution
     * of packet_read, then don't redirect, as that would be an infinite loop!
     */

    if(session->state & LIBSSH2_STATE_EXCHANGING_KEYS &&
        !(session->state & LIBSSH2_STATE_KEX_ACTIVE)) {

        /* Whoever wants a packet won't get anything until the key re-exchange
         * is done!
         */
        _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Redirecting into the"
                       " key re-exchange from _libssh2_transport_read");
        rc = _libssh2_kex_exchange(session, 1, &session->startup_key_state);
        if(rc)
            return rc;
    }

    /*
     * =============================== NOTE ===============================
     * I know this is very ugly and not a really good use of "goto", but
     * this case statement would be even uglier to do it any other way
     */
    if(session->readPack_state == libssh2_NB_state_jump1) {
        session->readPack_state = libssh2_NB_state_idle;
        encrypted = session->readPack_encrypted;
        goto libssh2_transport_read_point1;
    }

    do {
        if(session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) {
            return LIBSSH2_ERROR_NONE;
        }

        if(session->state & LIBSSH2_STATE_NEWKEYS) {
            blocksize = session->remote.crypt->blocksize;
        }
        else {
            encrypted = 0;      /* not encrypted */
            blocksize = 5;      /* not strictly true, but we can use 5 here to
                                   make the checks below work fine still */
        }

        /* read/use a whole big chunk into a temporary area stored in
           the LIBSSH2_SESSION struct. We will decrypt data from that
           buffer into the packet buffer so this temp one doesn't have
           to be able to keep a whole SSH packet, just be large enough
           so that we can read big chunks from the network layer. */

        /* how much data there is remaining in the buffer to deal with
           before we should read more from the network */
        remainbuf = p->writeidx - p->readidx;

        /* if remainbuf turns negative we have a bad internal error */
        assert(remainbuf >= 0);

        if(remainbuf < blocksize) {
            /* If we have less than a blocksize left, it is too
               little data to deal with, read more */
            ssize_t nread;

            /* move any remainder to the start of the buffer so
               that we can do a full refill */
            if(remainbuf) {
                memmove(p->buf, &p->buf[p->readidx], remainbuf);
                p->readidx = 0;
                p->writeidx = remainbuf;
            }
            else {
                /* nothing to move, just zero the indexes */
                p->readidx = p->writeidx = 0;
            }

            /* now read a big chunk from the network into the temp buffer */
            nread =
                LIBSSH2_RECV(session, &p->buf[remainbuf],
                              PACKETBUFSIZE - remainbuf,
                              LIBSSH2_SOCKET_RECV_FLAGS(session));
            if(nread <= 0) {
                /* check if this is due to EAGAIN and return the special
                   return code if so, error out normally otherwise */
                if((nread < 0) && (nread == -EAGAIN)) {
                    session->socket_block_directions |=
                        LIBSSH2_SESSION_BLOCK_INBOUND;
                    return LIBSSH2_ERROR_EAGAIN;
                }
                _libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
                               "Error recving %d bytes (got %d)",
                               PACKETBUFSIZE - remainbuf, -nread);
                return LIBSSH2_ERROR_SOCKET_RECV;
            }
            _libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
                           "Recved %d/%d bytes to %p+%d", nread,
                           PACKETBUFSIZE - remainbuf, p->buf, remainbuf);

            debugdump(session, "libssh2_transport_read() raw",
                      &p->buf[remainbuf], nread);
            /* advance write pointer */
            p->writeidx += nread;

            /* update remainbuf counter */
            remainbuf = p->writeidx - p->readidx;
        }

        /* how much data to deal with from the buffer */
        numbytes = remainbuf;

        if(!p->total_num) {
            /* No payload package area allocated yet. To know the
               size of this payload, we need to decrypt the first
               blocksize data. */

            if(numbytes < blocksize) {
                /* we can't act on anything less than blocksize, but this
                   check is only done for the initial block since once we have
                   got the start of a block we can in fact deal with fractions
                */
                session->socket_block_directions |=
                    LIBSSH2_SESSION_BLOCK_INBOUND;
                return LIBSSH2_ERROR_EAGAIN;
            }

            if(encrypted) {
                rc = decrypt(session, &p->buf[p->readidx], block, blocksize);
                if(rc != LIBSSH2_ERROR_NONE) {
                    return rc;
                }
                /* save the first 5 bytes of the decrypted package, to be
                   used in the hash calculation later down. */
                memcpy(p->init, block, 5);
            }
            else {
                /* the data is plain, just copy it verbatim to
                   the working block buffer */
                memcpy(block, &p->buf[p->readidx], blocksize);
            }

            /* advance the read pointer */
            p->readidx += blocksize;

            /* we now have the initial blocksize bytes decrypted,
             * and we can extract packet and padding length from it
             */
            p->packet_length = _libssh2_ntohu32(block);
            if(p->packet_length < 1)
                return LIBSSH2_ERROR_DECRYPT;

            p->padding_length = block[4];

            /* total_num is the number of bytes following the initial
               (5 bytes) packet length and padding length fields */
            total_num =
                p->packet_length - 1 +
                (encrypted ? session->remote.mac->mac_len : 0);

            /* RFC4253 section 6.1 Maximum Packet Length says:
             *
             * "All implementations MUST be able to process
             * packets with uncompressed payload length of 32768
             * bytes or less and total packet size of 35000 bytes
             * or less (including length, padding length, payload,
             * padding, and MAC.)."
             */
            if(total_num > LIBSSH2_PACKET_MAXPAYLOAD) {
                return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
            }

            /* Get a packet handle put data into. We get one to
               hold all data, including padding and MAC. */
            p->payload = LIBSSH2_ALLOC(session, total_num);
            if(!p->payload) {
                return LIBSSH2_ERROR_ALLOC;
            }
            p->total_num = total_num;
            /* init write pointer to start of payload buffer */
            p->wptr = p->payload;

            if(blocksize > 5) {
                /* copy the data from index 5 to the end of
                   the blocksize from the temporary buffer to
                   the start of the decrypted buffer */
                memcpy(p->wptr, &block[5], blocksize - 5);
                p->wptr += blocksize - 5;       /* advance write pointer */
            }

            /* init the data_num field to the number of bytes of
               the package read so far */
            p->data_num = p->wptr - p->payload;

            /* we already dealt with a blocksize worth of data */
            numbytes -= blocksize;
        }

        /* how much there is left to add to the current payload
           package */
        remainpack = p->total_num - p->data_num;

        if(numbytes > remainpack) {
            /* if we have more data in the buffer than what is going into this
               particular packet, we limit this round to this packet only */
            numbytes = remainpack;
        }

        if(encrypted) {
            /* At the end of the incoming stream, there is a MAC,
               and we don't want to decrypt that since we need it
               "raw". We MUST however decrypt the padding data
               since it is used for the hash later on. */
            int skip = session->remote.mac->mac_len;

            /* if what we have plus numbytes is bigger than the
               total minus the skip margin, we should lower the
               amount to decrypt even more */
            if((p->data_num + numbytes) > (p->total_num - skip)) {
                numdecrypt = (p->total_num - skip) - p->data_num;
            }
            else {
                int frac;
                numdecrypt = numbytes;
                frac = numdecrypt % blocksize;
                if(frac) {
                    /* not an aligned amount of blocks,
                       align it */
                    numdecrypt -= frac;
                    /* and make it no unencrypted data
                       after it */
                    numbytes = 0;
                }
            }
        }
        else {
            /* unencrypted data should not be decrypted at all */
            numdecrypt = 0;
        }

        /* if there are bytes to decrypt, do that */
        if(numdecrypt > 0) {
            /* now decrypt the lot */
            rc = decrypt(session, &p->buf[p->readidx], p->wptr, numdecrypt);
            if(rc != LIBSSH2_ERROR_NONE) {
                p->total_num = 0;   /* no packet buffer available */
                return rc;
            }

            /* advance the read pointer */
            p->readidx += numdecrypt;
            /* advance write pointer */
            p->wptr += numdecrypt;
            /* increase data_num */
            p->data_num += numdecrypt;

            /* bytes left to take care of without decryption */
            numbytes -= numdecrypt;
        }

        /* if there are bytes to copy that aren't decrypted, simply
           copy them as-is to the target buffer */
        if(numbytes > 0) {
            memcpy(p->wptr, &p->buf[p->readidx], numbytes);

            /* advance the read pointer */
            p->readidx += numbytes;
            /* advance write pointer */
            p->wptr += numbytes;
            /* increase data_num */
            p->data_num += numbytes;
        }

        /* now check how much data there's left to read to finish the
           current packet */
        remainpack = p->total_num - p->data_num;

        if(!remainpack) {
            /* we have a full packet */
          libssh2_transport_read_point1:
            rc = fullpacket(session, encrypted);
            if(rc == LIBSSH2_ERROR_EAGAIN) {

                if(session->packAdd_state != libssh2_NB_state_idle) {
                    /* fullpacket only returns LIBSSH2_ERROR_EAGAIN if
                     * libssh2_packet_add returns LIBSSH2_ERROR_EAGAIN. If that
                     * returns LIBSSH2_ERROR_EAGAIN but the packAdd_state is idle,
                     * then the packet has been added to the brigade, but some
                     * immediate action that was taken based on the packet
                     * type (such as key re-exchange) is not yet complete.
                     * Clear the way for a new packet to be read in.
                     */
                    session->readPack_encrypted = encrypted;
                    session->readPack_state = libssh2_NB_state_jump1;
                }

                return rc;
            }

            p->total_num = 0;   /* no packet buffer available */

            return rc;
        }
    } while(1);                /* loop */

    return LIBSSH2_ERROR_SOCKET_RECV; /* we never reach this point */
}


static void virtio_queue_host_notifier_read(EventNotifier *n) { VirtQueue *vq = container_of(n, VirtQueue, host_notifier); if (event_notifier_test_and_clear(n)) { virtio_queue_notify_vq(vq); } }


void gx_device_set_margins ( gx_device * dev , const float * margins , bool move_origin ) {
 int i ;
 for ( i = 0 ;
 i < 4 ;
 ++ i ) dev -> HWMargins [ i ] = margins [ i ] * 72.0 ;
 if ( move_origin ) {
 dev -> Margins [ 0 ] = - margins [ 0 ] * dev -> HWResolution [ 0 ] ;
 dev -> Margins [ 1 ] = - margins [ 3 ] * dev -> HWResolution [ 1 ] ;
 }
 }


void tcg_optimize(TCGContext *s) { int oi, oi_next, nb_temps, nb_globals; TCGOp *prev_mb = NULL; struct tcg_temp_info *infos; TCGTempSet temps_used; /* Array VALS has an element for each temp. If this temp holds a constant then its value is kept in VALS' element. If this temp is a copy of other ones then the other copies are available through the doubly linked circular list. */ nb_temps = s->nb_temps; nb_globals = s->nb_globals; bitmap_zero(temps_used.l, nb_temps); infos = tcg_malloc(sizeof(struct tcg_temp_info) * nb_temps); for (oi = s->gen_op_buf[0].next; oi != 0; oi = oi_next) { tcg_target_ulong mask, partmask, affected; int nb_oargs, nb_iargs, i; TCGArg tmp; TCGOp * const op = &s->gen_op_buf[oi]; TCGOpcode opc = op->opc; const TCGOpDef *def = &tcg_op_defs[opc]; oi_next = op->next; /* Count the arguments, and initialize the temps that are going to be used */ if (opc == INDEX_op_call) { nb_oargs = op->callo; nb_iargs = op->calli; for (i = 0; i < nb_oargs + nb_iargs; i++) { TCGTemp *ts = arg_temp(op->args[i]); if (ts) { init_ts_info(infos, &temps_used, ts); } } } else { nb_oargs = def->nb_oargs; nb_iargs = def->nb_iargs; for (i = 0; i < nb_oargs + nb_iargs; i++) { init_arg_info(infos, &temps_used, op->args[i]); } } /* Do copy propagation */ for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { TCGTemp *ts = arg_temp(op->args[i]); if (ts && ts_is_copy(ts)) { op->args[i] = temp_arg(find_better_copy(s, ts)); } } /* For commutative operations make constant second argument */ switch (opc) { CASE_OP_32_64(add): CASE_OP_32_64(mul): CASE_OP_32_64(and): CASE_OP_32_64(or): CASE_OP_32_64(xor): CASE_OP_32_64(eqv): CASE_OP_32_64(nand): CASE_OP_32_64(nor): CASE_OP_32_64(muluh): CASE_OP_32_64(mulsh): swap_commutative(op->args[0], &op->args[1], &op->args[2]); break; CASE_OP_32_64(brcond): if (swap_commutative(-1, &op->args[0], &op->args[1])) { op->args[2] = tcg_swap_cond(op->args[2]); } break; CASE_OP_32_64(setcond): if (swap_commutative(op->args[0], &op->args[1], &op->args[2])) { op->args[3] = tcg_swap_cond(op->args[3]); } break; CASE_OP_32_64(movcond): if (swap_commutative(-1, &op->args[1], &op->args[2])) { op->args[5] = tcg_swap_cond(op->args[5]); } /* For movcond, we canonicalize the "false" input reg to match the destination reg so that the tcg backend can implement a "move if true" operation. */ if (swap_commutative(op->args[0], &op->args[4], &op->args[3])) { op->args[5] = tcg_invert_cond(op->args[5]); } break; CASE_OP_32_64(add2): swap_commutative(op->args[0], &op->args[2], &op->args[4]); swap_commutative(op->args[1], &op->args[3], &op->args[5]); break; CASE_OP_32_64(mulu2): CASE_OP_32_64(muls2): swap_commutative(op->args[0], &op->args[2], &op->args[3]); break; case INDEX_op_brcond2_i32: if (swap_commutative2(&op->args[0], &op->args[2])) { op->args[4] = tcg_swap_cond(op->args[4]); } break; case INDEX_op_setcond2_i32: if (swap_commutative2(&op->args[1], &op->args[3])) { op->args[5] = tcg_swap_cond(op->args[5]); } break; default: break; } /* Simplify expressions for "shift/rot r, 0, a => movi r, 0", and "sub r, 0, a => neg r, a" case. */ switch (opc) { CASE_OP_32_64(shl): CASE_OP_32_64(shr): CASE_OP_32_64(sar): CASE_OP_32_64(rotl): CASE_OP_32_64(rotr): if (arg_is_const(op->args[1]) && arg_info(op->args[1])->val == 0) { tcg_opt_gen_movi(s, op, op->args[0], 0); continue; } break; CASE_OP_32_64(sub): { TCGOpcode neg_op; bool have_neg; if (arg_is_const(op->args[2])) { /* Proceed with possible constant folding. */ break; } if (opc == INDEX_op_sub_i32) { neg_op = INDEX_op_neg_i32; have_neg = TCG_TARGET_HAS_neg_i32; } else { neg_op = INDEX_op_neg_i64; have_neg = TCG_TARGET_HAS_neg_i64; } if (!have_neg) { break; } if (arg_is_const(op->args[1]) && arg_info(op->args[1])->val == 0) { op->opc = neg_op; reset_temp(op->args[0]); op->args[1] = op->args[2]; continue; } } break; CASE_OP_32_64(xor): CASE_OP_32_64(nand): if (!arg_is_const(op->args[1]) && arg_is_const(op->args[2]) && arg_info(op->args[2])->val == -1) { i = 1; goto try_not; } break; CASE_OP_32_64(nor): if (!arg_is_const(op->args[1]) && arg_is_const(op->args[2]) && arg_info(op->args[2])->val == 0) { i = 1; goto try_not; } break; CASE_OP_32_64(andc): if (!arg_is_const(op->args[2]) && arg_is_const(op->args[1]) && arg_info(op->args[1])->val == -1) { i = 2; goto try_not; } break; CASE_OP_32_64(orc): CASE_OP_32_64(eqv): if (!arg_is_const(op->args[2]) && arg_is_const(op->args[1]) && arg_info(op->args[1])->val == 0) { i = 2; goto try_not; } break; try_not: { TCGOpcode not_op; bool have_not; if (def->flags & TCG_OPF_64BIT) { not_op = INDEX_op_not_i64; have_not = TCG_TARGET_HAS_not_i64; } else { not_op = INDEX_op_not_i32; have_not = TCG_TARGET_HAS_not_i32; } if (!have_not) { break; } op->opc = not_op; reset_temp(op->args[0]); op->args[1] = op->args[i]; continue; } default: break; } /* Simplify expression for "op r, a, const => mov r, a" cases */ switch (opc) { CASE_OP_32_64(add): CASE_OP_32_64(sub): CASE_OP_32_64(shl): CASE_OP_32_64(shr): CASE_OP_32_64(sar): CASE_OP_32_64(rotl): CASE_OP_32_64(rotr): CASE_OP_32_64(or): CASE_OP_32_64(xor): CASE_OP_32_64(andc): if (!arg_is_const(op->args[1]) && arg_is_const(op->args[2]) && arg_info(op->args[2])->val == 0) { tcg_opt_gen_mov(s, op, op->args[0], op->args[1]); continue; } break; CASE_OP_32_64(and): CASE_OP_32_64(orc): CASE_OP_32_64(eqv): if (!arg_is_const(op->args[1]) && arg_is_const(op->args[2]) && arg_info(op->args[2])->val == -1) { tcg_opt_gen_mov(s, op, op->args[0], op->args[1]); continue; } break; default: break; } /* Simplify using known-zero bits. Currently only ops with a single output argument is supported. */ mask = -1; affected = -1; switch (opc) { CASE_OP_32_64(ext8s): if ((arg_info(op->args[1])->mask & 0x80) != 0) { break; } CASE_OP_32_64(ext8u): mask = 0xff; goto and_const; CASE_OP_32_64(ext16s): if ((arg_info(op->args[1])->mask & 0x8000) != 0) { break; } CASE_OP_32_64(ext16u): mask = 0xffff; goto and_const; case INDEX_op_ext32s_i64: if ((arg_info(op->args[1])->mask & 0x80000000) != 0) { break; } case INDEX_op_ext32u_i64: mask = 0xffffffffU; goto and_const; CASE_OP_32_64(and): mask = arg_info(op->args[2])->mask; if (arg_is_const(op->args[2])) { and_const: affected = arg_info(op->args[1])->mask & ~mask; } mask = arg_info(op->args[1])->mask & mask; break; case INDEX_op_ext_i32_i64: if ((arg_info(op->args[1])->mask & 0x80000000) != 0) { break; } case INDEX_op_extu_i32_i64: /* We do not compute affected as it is a size changing op. */ mask = (uint32_t)arg_info(op->args[1])->mask; break; CASE_OP_32_64(andc): /* Known-zeros does not imply known-ones. Therefore unless op->args[2] is constant, we can't infer anything from it. */ if (arg_is_const(op->args[2])) { mask = ~arg_info(op->args[2])->mask; goto and_const; } /* But we certainly know nothing outside args[1] may be set. */ mask = arg_info(op->args[1])->mask; break; case INDEX_op_sar_i32: if (arg_is_const(op->args[2])) { tmp = arg_info(op->args[2])->val & 31; mask = (int32_t)arg_info(op->args[1])->mask >> tmp; } break; case INDEX_op_sar_i64: if (arg_is_const(op->args[2])) { tmp = arg_info(op->args[2])->val & 63; mask = (int64_t)arg_info(op->args[1])->mask >> tmp; } break; case INDEX_op_shr_i32: if (arg_is_const(op->args[2])) { tmp = arg_info(op->args[2])->val & 31; mask = (uint32_t)arg_info(op->args[1])->mask >> tmp; } break; case INDEX_op_shr_i64: if (arg_is_const(op->args[2])) { tmp = arg_info(op->args[2])->val & 63; mask = (uint64_t)arg_info(op->args[1])->mask >> tmp; } break; case INDEX_op_extrl_i64_i32: mask = (uint32_t)arg_info(op->args[1])->mask; break; case INDEX_op_extrh_i64_i32: mask = (uint64_t)arg_info(op->args[1])->mask >> 32; break; CASE_OP_32_64(shl): if (arg_is_const(op->args[2])) { tmp = arg_info(op->args[2])->val & (TCG_TARGET_REG_BITS - 1); mask = arg_info(op->args[1])->mask << tmp; } break; CASE_OP_32_64(neg): /* Set to 1 all bits to the left of the rightmost. */ mask = -(arg_info(op->args[1])->mask & -arg_info(op->args[1])->mask); break; CASE_OP_32_64(deposit): mask = deposit64(arg_info(op->args[1])->mask, op->args[3], op->args[4], arg_info(op->args[2])->mask); break; CASE_OP_32_64(extract): mask = extract64(arg_info(op->args[1])->mask, op->args[2], op->args[3]); if (op->args[2] == 0) { affected = arg_info(op->args[1])->mask & ~mask; } break; CASE_OP_32_64(sextract): mask = sextract64(arg_info(op->args[1])->mask, op->args[2], op->args[3]); if (op->args[2] == 0 && (tcg_target_long)mask >= 0) { affected = arg_info(op->args[1])->mask & ~mask; } break; CASE_OP_32_64(or): CASE_OP_32_64(xor): mask = arg_info(op->args[1])->mask | arg_info(op->args[2])->mask; break; case INDEX_op_clz_i32: case INDEX_op_ctz_i32: mask = arg_info(op->args[2])->mask | 31; break; case INDEX_op_clz_i64: case INDEX_op_ctz_i64: mask = arg_info(op->args[2])->mask | 63; break; case INDEX_op_ctpop_i32: mask = 32 | 31; break; case INDEX_op_ctpop_i64: mask = 64 | 63; break; CASE_OP_32_64(setcond): case INDEX_op_setcond2_i32: mask = 1; break; CASE_OP_32_64(movcond): mask = arg_info(op->args[3])->mask | arg_info(op->args[4])->mask; break; CASE_OP_32_64(ld8u): mask = 0xff; break; CASE_OP_32_64(ld16u): mask = 0xffff; break; case INDEX_op_ld32u_i64: mask = 0xffffffffu; break; CASE_OP_32_64(qemu_ld): { TCGMemOpIdx oi = op->args[nb_oargs + nb_iargs]; TCGMemOp mop = get_memop(oi); if (!(mop & MO_SIGN)) { mask = (2ULL << ((8 << (mop & MO_SIZE)) - 1)) - 1; } } break; default: break; } /* 32-bit ops generate 32-bit results. For the result is zero test below, we can ignore high bits, but for further optimizations we need to record that the high bits contain garbage. */ partmask = mask; if (!(def->flags & TCG_OPF_64BIT)) { mask |= ~(tcg_target_ulong)0xffffffffu; partmask &= 0xffffffffu; affected &= 0xffffffffu; } if (partmask == 0) { tcg_debug_assert(nb_oargs == 1); tcg_opt_gen_movi(s, op, op->args[0], 0); continue; } if (affected == 0) { tcg_debug_assert(nb_oargs == 1); tcg_opt_gen_mov(s, op, op->args[0], op->args[1]); continue; } /* Simplify expression for "op r, a, 0 => movi r, 0" cases */ switch (opc) { CASE_OP_32_64(and): CASE_OP_32_64(mul): CASE_OP_32_64(muluh): CASE_OP_32_64(mulsh): if (arg_is_const(op->args[2]) && arg_info(op->args[2])->val == 0) { tcg_opt_gen_movi(s, op, op->args[0], 0); continue; } break; default: break; } /* Simplify expression for "op r, a, a => mov r, a" cases */ switch (opc) { CASE_OP_32_64(or): CASE_OP_32_64(and): if (args_are_copies(op->args[1], op->args[2])) { tcg_opt_gen_mov(s, op, op->args[0], op->args[1]); continue; } break; default: break; } /* Simplify expression for "op r, a, a => movi r, 0" cases */ switch (opc) { CASE_OP_32_64(andc): CASE_OP_32_64(sub): CASE_OP_32_64(xor): if (args_are_copies(op->args[1], op->args[2])) { tcg_opt_gen_movi(s, op, op->args[0], 0); continue; } break; default: break; } /* Propagate constants through copy operations and do constant folding. Constants will be substituted to arguments by register allocator where needed and possible. Also detect copies. */ switch (opc) { CASE_OP_32_64(mov): tcg_opt_gen_mov(s, op, op->args[0], op->args[1]); break; CASE_OP_32_64(movi): tcg_opt_gen_movi(s, op, op->args[0], op->args[1]); break; CASE_OP_32_64(not): CASE_OP_32_64(neg): CASE_OP_32_64(ext8s): CASE_OP_32_64(ext8u): CASE_OP_32_64(ext16s): CASE_OP_32_64(ext16u): CASE_OP_32_64(ctpop): case INDEX_op_ext32s_i64: case INDEX_op_ext32u_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: if (arg_is_const(op->args[1])) { tmp = do_constant_folding(opc, arg_info(op->args[1])->val, 0); tcg_opt_gen_movi(s, op, op->args[0], tmp); break; } goto do_default; CASE_OP_32_64(add): CASE_OP_32_64(sub): CASE_OP_32_64(mul): CASE_OP_32_64(or): CASE_OP_32_64(and): CASE_OP_32_64(xor): CASE_OP_32_64(shl): CASE_OP_32_64(shr): CASE_OP_32_64(sar): CASE_OP_32_64(rotl): CASE_OP_32_64(rotr): CASE_OP_32_64(andc): CASE_OP_32_64(orc): CASE_OP_32_64(eqv): CASE_OP_32_64(nand): CASE_OP_32_64(nor): CASE_OP_32_64(muluh): CASE_OP_32_64(mulsh): CASE_OP_32_64(div): CASE_OP_32_64(divu): CASE_OP_32_64(rem): CASE_OP_32_64(remu): if (arg_is_const(op->args[1]) && arg_is_const(op->args[2])) { tmp = do_constant_folding(opc, arg_info(op->args[1])->val, arg_info(op->args[2])->val); tcg_opt_gen_movi(s, op, op->args[0], tmp); break; } goto do_default; CASE_OP_32_64(clz): CASE_OP_32_64(ctz): if (arg_is_const(op->args[1])) { TCGArg v = arg_info(op->args[1])->val; if (v != 0) { tmp = do_constant_folding(opc, v, 0); tcg_opt_gen_movi(s, op, op->args[0], tmp); } else { tcg_opt_gen_mov(s, op, op->args[0], op->args[2]); } break; } goto do_default; CASE_OP_32_64(deposit): if (arg_is_const(op->args[1]) && arg_is_const(op->args[2])) { tmp = deposit64(arg_info(op->args[1])->val, op->args[3], op->args[4], arg_info(op->args[2])->val); tcg_opt_gen_movi(s, op, op->args[0], tmp); break; } goto do_default; CASE_OP_32_64(extract): if (arg_is_const(op->args[1])) { tmp = extract64(arg_info(op->args[1])->val, op->args[2], op->args[3]); tcg_opt_gen_movi(s, op, op->args[0], tmp); break; } goto do_default; CASE_OP_32_64(sextract): if (arg_is_const(op->args[1])) { tmp = sextract64(arg_info(op->args[1])->val, op->args[2], op->args[3]); tcg_opt_gen_movi(s, op, op->args[0], tmp); break; } goto do_default; CASE_OP_32_64(setcond): tmp = do_constant_folding_cond(opc, op->args[1], op->args[2], op->args[3]); if (tmp != 2) { tcg_opt_gen_movi(s, op, op->args[0], tmp); break; } goto do_default; CASE_OP_32_64(brcond): tmp = do_constant_folding_cond(opc, op->args[0], op->args[1], op->args[2]); if (tmp != 2) { if (tmp) { bitmap_zero(temps_used.l, nb_temps); op->opc = INDEX_op_br; op->args[0] = op->args[3]; } else { tcg_op_remove(s, op); } break; } goto do_default; CASE_OP_32_64(movcond): tmp = do_constant_folding_cond(opc, op->args[1], op->args[2], op->args[5]); if (tmp != 2) { tcg_opt_gen_mov(s, op, op->args[0], op->args[4-tmp]); break; } if (arg_is_const(op->args[3]) && arg_is_const(op->args[4])) { tcg_target_ulong tv = arg_info(op->args[3])->val; tcg_target_ulong fv = arg_info(op->args[4])->val; TCGCond cond = op->args[5]; if (fv == 1 && tv == 0) { cond = tcg_invert_cond(cond); } else if (!(tv == 1 && fv == 0)) { goto do_default; } op->args[3] = cond; op->opc = opc = (opc == INDEX_op_movcond_i32 ? INDEX_op_setcond_i32 : INDEX_op_setcond_i64); nb_iargs = 2; } goto do_default; case INDEX_op_add2_i32: case INDEX_op_sub2_i32: if (arg_is_const(op->args[2]) && arg_is_const(op->args[3]) && arg_is_const(op->args[4]) && arg_is_const(op->args[5])) { uint32_t al = arg_info(op->args[2])->val; uint32_t ah = arg_info(op->args[3])->val; uint32_t bl = arg_info(op->args[4])->val; uint32_t bh = arg_info(op->args[5])->val; uint64_t a = ((uint64_t)ah << 32) | al; uint64_t b = ((uint64_t)bh << 32) | bl; TCGArg rl, rh; TCGOp *op2 = tcg_op_insert_before(s, op, INDEX_op_movi_i32, 2); if (opc == INDEX_op_add2_i32) { a += b; } else { a -= b; } rl = op->args[0]; rh = op->args[1]; tcg_opt_gen_movi(s, op, rl, (int32_t)a); tcg_opt_gen_movi(s, op2, rh, (int32_t)(a >> 32)); /* We've done all we need to do with the movi. Skip it. */ oi_next = op2->next; break; } goto do_default; case INDEX_op_mulu2_i32: if (arg_is_const(op->args[2]) && arg_is_const(op->args[3])) { uint32_t a = arg_info(op->args[2])->val; uint32_t b = arg_info(op->args[3])->val; uint64_t r = (uint64_t)a * b; TCGArg rl, rh; TCGOp *op2 = tcg_op_insert_before(s, op, INDEX_op_movi_i32, 2); rl = op->args[0]; rh = op->args[1]; tcg_opt_gen_movi(s, op, rl, (int32_t)r); tcg_opt_gen_movi(s, op2, rh, (int32_t)(r >> 32)); /* We've done all we need to do with the movi. Skip it. */ oi_next = op2->next; break; } goto do_default; case INDEX_op_brcond2_i32: tmp = do_constant_folding_cond2(&op->args[0], &op->args[2], op->args[4]); if (tmp != 2) { if (tmp) { do_brcond_true: bitmap_zero(temps_used.l, nb_temps); op->opc = INDEX_op_br; op->args[0] = op->args[5]; } else { do_brcond_false: tcg_op_remove(s, op); } } else if ((op->args[4] == TCG_COND_LT || op->args[4] == TCG_COND_GE) && arg_is_const(op->args[2]) && arg_info(op->args[2])->val == 0 && arg_is_const(op->args[3]) && arg_info(op->args[3])->val == 0) { /* Simplify LT/GE comparisons vs zero to a single compare vs the high word of the input. */ do_brcond_high: bitmap_zero(temps_used.l, nb_temps); op->opc = INDEX_op_brcond_i32; op->args[0] = op->args[1]; op->args[1] = op->args[3]; op->args[2] = op->args[4]; op->args[3] = op->args[5]; } else if (op->args[4] == TCG_COND_EQ) { /* Simplify EQ comparisons where one of the pairs can be simplified. */ tmp = do_constant_folding_cond(INDEX_op_brcond_i32, op->args[0], op->args[2], TCG_COND_EQ); if (tmp == 0) { goto do_brcond_false; } else if (tmp == 1) { goto do_brcond_high; } tmp = do_constant_folding_cond(INDEX_op_brcond_i32, op->args[1], op->args[3], TCG_COND_EQ); if (tmp == 0) { goto do_brcond_false; } else if (tmp != 1) { goto do_default; } do_brcond_low: bitmap_zero(temps_used.l, nb_temps); op->opc = INDEX_op_brcond_i32; op->args[1] = op->args[2]; op->args[2] = op->args[4]; op->args[3] = op->args[5]; } else if (op->args[4] == TCG_COND_NE) { /* Simplify NE comparisons where one of the pairs can be simplified. */ tmp = do_constant_folding_cond(INDEX_op_brcond_i32, op->args[0], op->args[2], TCG_COND_NE); if (tmp == 0) { goto do_brcond_high; } else if (tmp == 1) { goto do_brcond_true; } tmp = do_constant_folding_cond(INDEX_op_brcond_i32, op->args[1], op->args[3], TCG_COND_NE); if (tmp == 0) { goto do_brcond_low; } else if (tmp == 1) { goto do_brcond_true; } goto do_default; } else { goto do_default; } break; case INDEX_op_setcond2_i32: tmp = do_constant_folding_cond2(&op->args[1], &op->args[3], op->args[5]); if (tmp != 2) { do_setcond_const: tcg_opt_gen_movi(s, op, op->args[0], tmp); } else if ((op->args[5] == TCG_COND_LT || op->args[5] == TCG_COND_GE) && arg_is_const(op->args[3]) && arg_info(op->args[3])->val == 0 && arg_is_const(op->args[4]) && arg_info(op->args[4])->val == 0) { /* Simplify LT/GE comparisons vs zero to a single compare vs the high word of the input. */ do_setcond_high: reset_temp(op->args[0]); arg_info(op->args[0])->mask = 1; op->opc = INDEX_op_setcond_i32; op->args[1] = op->args[2]; op->args[2] = op->args[4]; op->args[3] = op->args[5]; } else if (op->args[5] == TCG_COND_EQ) { /* Simplify EQ comparisons where one of the pairs can be simplified. */ tmp = do_constant_folding_cond(INDEX_op_setcond_i32, op->args[1], op->args[3], TCG_COND_EQ); if (tmp == 0) { goto do_setcond_const; } else if (tmp == 1) { goto do_setcond_high; } tmp = do_constant_folding_cond(INDEX_op_setcond_i32, op->args[2], op->args[4], TCG_COND_EQ); if (tmp == 0) { goto do_setcond_high; } else if (tmp != 1) { goto do_default; } do_setcond_low: reset_temp(op->args[0]); arg_info(op->args[0])->mask = 1; op->opc = INDEX_op_setcond_i32; op->args[2] = op->args[3]; op->args[3] = op->args[5]; } else if (op->args[5] == TCG_COND_NE) { /* Simplify NE comparisons where one of the pairs can be simplified. */ tmp = do_constant_folding_cond(INDEX_op_setcond_i32, op->args[1], op->args[3], TCG_COND_NE); if (tmp == 0) { goto do_setcond_high; } else if (tmp == 1) { goto do_setcond_const; } tmp = do_constant_folding_cond(INDEX_op_setcond_i32, op->args[2], op->args[4], TCG_COND_NE); if (tmp == 0) { goto do_setcond_low; } else if (tmp == 1) { goto do_setcond_const; } goto do_default; } else { goto do_default; } break; case INDEX_op_call: if (!(op->args[nb_oargs + nb_iargs + 1] & (TCG_CALL_NO_READ_GLOBALS | TCG_CALL_NO_WRITE_GLOBALS))) { for (i = 0; i < nb_globals; i++) { if (test_bit(i, temps_used.l)) { reset_ts(&s->temps[i]); } } } goto do_reset_output; default: do_default: /* Default case: we know nothing about operation (or were unable to compute the operation result) so no propagation is done. We trash everything if the operation is the end of a basic block, otherwise we only trash the output args. "mask" is the non-zero bits mask for the first output arg. */ if (def->flags & TCG_OPF_BB_END) { bitmap_zero(temps_used.l, nb_temps); } else { do_reset_output: for (i = 0; i < nb_oargs; i++) { reset_temp(op->args[i]); /* Save the corresponding known-zero bits mask for the first output argument (only one supported so far). */ if (i == 0) { arg_info(op->args[i])->mask = mask; } } } break; } /* Eliminate duplicate and redundant fence instructions. */ if (prev_mb) { switch (opc) { case INDEX_op_mb: /* Merge two barriers of the same type into one, * or a weaker barrier into a stronger one, * or two weaker barriers into a stronger one. * mb X; mb Y => mb X|Y * mb; strl => mb; st * ldaq; mb => ld; mb * ldaq; strl => ld; mb; st * Other combinations are also merged into a strong * barrier. This is stricter than specified but for * the purposes of TCG is better than not optimizing. */ prev_mb->args[0] |= op->args[0]; tcg_op_remove(s, op); break; default: /* Opcodes that end the block stop the optimization. */ if ((def->flags & TCG_OPF_BB_END) == 0) { break; } /* fallthru */ case INDEX_op_qemu_ld_i32: case INDEX_op_qemu_ld_i64: case INDEX_op_qemu_st_i32: case INDEX_op_qemu_st_i64: case INDEX_op_call: /* Opcodes that touch guest memory stop the optimization. */ prev_mb = NULL; break; } } else if (opc == INDEX_op_mb) { prev_mb = op; } } }


TocEntry * getTocEntryByDumpId ( ArchiveHandle * AH , DumpId id ) {
 if ( AH -> tocsByDumpId == NULL ) buildTocEntryArrays ( AH ) ;
 if ( id > 0 && id <= AH -> maxDumpId ) return AH -> tocsByDumpId [ id ] ;
 return NULL ;
 }


struct reloc_t* MACH0_(get_relocs)(struct MACH0_(obj_t)* bin) {
	struct reloc_t *relocs;
	int i = 0, len;
	ulebr ur = {NULL};
	int wordsize = MACH0_(get_bits)(bin) / 8;
	if (bin->dyld_info) {
		ut8 *opcodes,*end, type = 0, rel_type = 0;
		int lib_ord, seg_idx = -1, sym_ord = -1;
		size_t j, count, skip, bind_size, lazy_size;
		st64 addend = 0;
		ut64 segmentAddress = 0LL;
		ut64 addr = 0LL;
		ut8 done = 0;

#define CASE(T) case (T / 8): rel_type = R_BIN_RELOC_ ## T; break
		switch (wordsize) {
		CASE(8);
		CASE(16);
		CASE(32);
		CASE(64);
		default: return NULL;
		}
#undef CASE
		bind_size = bin->dyld_info->bind_size;
		lazy_size = bin->dyld_info->lazy_bind_size;

		if (!bind_size || !lazy_size) {
			return NULL;
		}

		if ((bind_size + lazy_size)<1) {
			return NULL;
		}
		if (bin->dyld_info->bind_off > bin->size || bin->dyld_info->bind_off + bind_size > bin->size)
			return NULL;
		if (bin->dyld_info->lazy_bind_off > bin->size || \
			bin->dyld_info->lazy_bind_off + lazy_size > bin->size)
			return NULL;
		if (bin->dyld_info->bind_off+bind_size+lazy_size > bin->size)
			return NULL;
		// NOTE(eddyb) it's a waste of memory, but we don't know the actual number of relocs.
		if (!(relocs = calloc (1, (1 + bind_size + lazy_size) * sizeof (struct reloc_t))))
			return NULL;

		opcodes = calloc (1, bind_size + lazy_size + 1);
		if (!opcodes) {
			free (relocs);
			return NULL;
		}
		len = r_buf_read_at (bin->b, bin->dyld_info->bind_off, opcodes, bind_size);
		i = r_buf_read_at (bin->b, bin->dyld_info->lazy_bind_off, opcodes + bind_size, lazy_size);
		if (len < 1 || i < 1) {
			bprintf ("Error: read (dyld_info bind) at 0x%08"PFMT64x"\n",
			(ut64)(size_t)bin->dyld_info->bind_off);
			free (opcodes);
			relocs[i].last = 1;
			return relocs;
		}
		i = 0;
		// that +2 is a minimum required for uleb128, this may be wrong,
		// the correct fix would be to make ULEB() must use rutil's
		// implementation that already checks for buffer boundaries
		for (ur.p = opcodes, end = opcodes + bind_size + lazy_size ; (ur.p+2 < end) && !done; ) {
			ut8 imm = *ur.p & BIND_IMMEDIATE_MASK, op = *ur.p & BIND_OPCODE_MASK;
			++ur.p;
			switch (op) {
#define ULEB() read_uleb128 (&ur,end)
#define SLEB() read_sleb128 (&ur,end)
			case BIND_OPCODE_DONE:
				done = 1;
				break;
			case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
				lib_ord = imm;
				break;
			case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
				lib_ord = ULEB();
				break;
			case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
				lib_ord = imm? (st8)(BIND_OPCODE_MASK | imm) : 0;
				break;
			case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: {
				char *sym_name = (char*)ur.p;
				//ut8 sym_flags = imm;
				while (*ur.p++ && ur.p<end) {
					/* empty loop */
				}
				sym_ord = -1;
				if (bin->symtab && bin->dysymtab.nundefsym < 0xffff)
				for (j = 0; j < bin->dysymtab.nundefsym; j++) {
					int stridx = 0;
					int iundefsym = bin->dysymtab.iundefsym;
					if (iundefsym>=0 && iundefsym < bin->nsymtab) {
						int sidx = iundefsym +j;
						if (sidx<0 || sidx>= bin->nsymtab)
							continue;
						stridx = bin->symtab[sidx].n_strx;
						if (stridx < 0 || stridx >= bin->symstrlen)
							continue;
					}
					if (!strcmp ((char *)bin->symstr + stridx, sym_name)) {
						sym_ord = j;
						break;
					}
				}
				break;
			}
			case BIND_OPCODE_SET_TYPE_IMM:
				type = imm;
				break;
			case BIND_OPCODE_SET_ADDEND_SLEB:
				addend = SLEB();
				break;
			case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
				seg_idx = imm;
				if (seg_idx < 0 || seg_idx >= bin->nsegs) {
					bprintf ("Error: BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB"
						" has unexistent segment %d\n", seg_idx);
					addr = 0LL;
					return 0; // early exit to avoid future mayhem
				} else {
					addr = bin->segs[seg_idx].vmaddr + ULEB();
					segmentAddress = bin->segs[seg_idx].vmaddr \
							+ bin->segs[seg_idx].vmsize;
				}
				break;
			case BIND_OPCODE_ADD_ADDR_ULEB:
				addr += ULEB();
				break;
#define DO_BIND() do {\
if (sym_ord < 0 || seg_idx < 0 ) break;\
if (i >= (bind_size + lazy_size)) break;\
relocs[i].addr = addr;\
relocs[i].offset = addr - bin->segs[seg_idx].vmaddr + bin->segs[seg_idx].fileoff;\
if (type == BIND_TYPE_TEXT_PCREL32)\
	relocs[i].addend = addend - (bin->baddr + addr);\
else relocs[i].addend = addend;\
/* library ordinal ??? */ \
relocs[i].ord = lib_ord;\
relocs[i].ord = sym_ord;\
relocs[i].type = rel_type;\
relocs[i++].last = 0;\
} while (0)
			case BIND_OPCODE_DO_BIND:
				if (addr >= segmentAddress) {
					bprintf ("Error: Malformed DO bind opcode\n");
					goto beach;
				}
				DO_BIND();
				addr += wordsize;
				break;
			case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
				if (addr >= segmentAddress) {
					bprintf ("Error: Malformed ADDR ULEB bind opcode\n");
					goto beach;
				}
				DO_BIND();
				addr += ULEB() + wordsize;
				break;
			case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
				if (addr >= segmentAddress) {
					bprintf ("Error: Malformed IMM SCALED bind opcode\n");
					goto beach;
				}
				DO_BIND();
				addr += (ut64)imm * (ut64)wordsize + wordsize;
				break;
			case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
				count = ULEB();
				skip = ULEB();
				for (j = 0; j < count; j++) {
					if (addr >= segmentAddress) {
						bprintf ("Error: Malformed ULEB TIMES bind opcode\n");
						goto beach;
					}
					DO_BIND();
					addr += skip + wordsize;
				}
				break;
#undef DO_BIND
#undef ULEB
#undef SLEB
			default:
				bprintf ("Error: unknown bind opcode 0x%02x in dyld_info\n", *ur.p);
				free (opcodes);
				relocs[i].last = 1;
				return relocs;
			}
		}
		free (opcodes);
	} else {
		int j;
		if (!bin->symtab || !bin->symstr || !bin->sects || !bin->indirectsyms)
			return NULL;
		if (!(relocs = malloc ((bin->dysymtab.nundefsym + 1) * sizeof(struct reloc_t))))
			return NULL;
		for (j = 0; j < bin->dysymtab.nundefsym; j++) {
			if (parse_import_ptr(bin, &relocs[i], bin->dysymtab.iundefsym + j)) {
				relocs[i].ord = j;
				relocs[i++].last = 0;
			}
		}
	}
beach:
	relocs[i].last = 1;

	return relocs;
}


void virtio_queue_notify(VirtIODevice *vdev, int n) { if (n < VIRTIO_PCI_QUEUE_MAX && vdev->vq[n].vring.desc) { trace_virtio_queue_notify(vdev, n, &vdev->vq[n]); vdev->vq[n].handle_output(vdev, &vdev->vq[n]); } }


void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb) { CRW *crw; uint64_t addr; int cc; hwaddr len = sizeof(*crw); CPUS390XState *env = &cpu->env; addr = decode_basedisp_s(env, ipb); if (addr & 3) { program_interrupt(env, PGM_SPECIFICATION, 2); return; } crw = s390_cpu_physical_memory_map(env, addr, &len, 1); if (!crw || len != sizeof(*crw)) { program_interrupt(env, PGM_ADDRESSING, 2); goto out; } cc = css_do_stcrw(crw); /* 0 - crw stored, 1 - zeroes stored */ setcc(cpu, cc); out: s390_cpu_physical_memory_unmap(env, crw, len, 1); }


static u_short count_var ( const struct ctl_var * k ) {
 u_int c ;
 if ( NULL == k ) return 0 ;
 c = 0 ;
 while ( ! ( EOV & ( k ++ ) -> flags ) ) c ++ ;
 ENSURE ( c <= USHRT_MAX ) ;
 return ( u_short ) c ;
 }


static void lsi_command_complete(SCSIRequest *req, uint32_t status, size_t resid) { LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent); int out; out = (s->sstat1 & PHASE_MASK) == PHASE_DO; DPRINTF("Command complete status=%d\n", (int)status); s->status = status; s->command_complete = 2; if (s->waiting && s->dbc != 0) { /* Raise phase mismatch for short transfers. */ lsi_bad_phase(s, out, PHASE_ST); } else { lsi_set_phase(s, PHASE_ST); } if (s->current && req == s->current->req) { req->hba_private = NULL; lsi_request_free(s, s->current); scsi_req_unref(req); } lsi_resume_script(s); }


find_file (const char *currpath, grub_fshelp_node_t currroot,
	   grub_fshelp_node_t *currfound,
	   struct grub_fshelp_find_file_closure *c)
{
#ifndef _MSC_VER
	char fpath[grub_strlen (currpath) + 1];
#else
	char *fpath = grub_malloc (grub_strlen (currpath) + 1);
#endif
  char *name = fpath;
  char *next;
  enum grub_fshelp_filetype type = GRUB_FSHELP_DIR;
  grub_fshelp_node_t currnode = currroot;
  grub_fshelp_node_t oldnode = currroot;

  c->currroot = currroot;

  grub_strncpy (fpath, currpath, grub_strlen (currpath) + 1);

  /* Remove all leading slashes.  */
  while (*name == '/')
    name++;

  if (! *name)
    {
      *currfound = currnode;
      return 0;
    }

  for (;;)
    {
      int found;
      struct find_file_closure cc;

      /* Extract the actual part from the pathname.  */
      next = grub_strchr (name, '/');
      if (next)
	{
	  /* Remove all leading slashes.  */
	  while (*next == '/')
	    *(next++) = '\0';
	}

      /* At this point it is expected that the current node is a
	 directory, check if this is true.  */
      if (type != GRUB_FSHELP_DIR)
	{
	  free_node (currnode, c);
	  return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
	}

      cc.name = name;
      cc.type = &type;
      cc.oldnode = &oldnode;
      cc.currnode = &currnode;
      /* Iterate over the directory.  */
      found = c->iterate_dir (currnode, iterate, &cc);
      if (! found)
	{
	  if (grub_errno)
	    return grub_errno;

	  break;
	}

      /* Read in the symlink and follow it.  */
      if (type == GRUB_FSHELP_SYMLINK)
	{
	  char *symlink;

	  /* Test if the symlink does not loop.  */
	  if (++(c->symlinknest) == 8)
	    {
	      free_node (currnode, c);
	      free_node (oldnode, c);
	      return grub_error (GRUB_ERR_SYMLINK_LOOP,
				 "too deep nesting of symlinks");
	    }

	  symlink = c->read_symlink (currnode);
	  free_node (currnode, c);

	  if (!symlink)
	    {
	      free_node (oldnode, c);
	      return grub_errno;
	    }

	  /* The symlink is an absolute path, go back to the root inode.  */
	  if (symlink[0] == '/')
	    {
	      free_node (oldnode, c);
	      oldnode = c->rootnode;
	    }

	  /* Lookup the node the symlink points to.  */
	  find_file (symlink, oldnode, &currnode, c);
	  type = c->foundtype;
	  grub_free (symlink);

	  if (grub_errno)
	    {
	      free_node (oldnode, c);
	      return grub_errno;
	    }
	}

      free_node (oldnode, c);

      /* Found the node!  */
      if (! next || *next == '\0')
	{
	  *currfound = currnode;
	  c->foundtype = type;
	  return 0;
	}

      name = next;
    }

  return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
}


static void _db_level_get(struct db_arg_chain_tree *node)
{
	struct db_arg_chain_tree *iter = node;

	while (iter->lvl_prv != NULL)
		iter = iter->lvl_prv;

	while (iter) {
		_db_tree_get(iter);
		iter = iter->lvl_nxt;
	}
}


static int _db_tree_add(struct db_arg_chain_tree **existing,
			struct db_arg_chain_tree *new,
			struct db_iter_state *state)
{
	int rc;
	struct db_arg_chain_tree *x_iter = *existing;
	struct db_arg_chain_tree *n_iter = new;

	/* TODO: when we add sub-trees to the current level (see the lt/gt
	 * branches below) we need to grab an extra reference for sub-trees at
	 * the current as the current level is visible to both the new and
	 * existing trees; at some point if would be nice if we didn't have to
	 * take this extra reference */

	do {
		if (_db_chain_eq(x_iter, n_iter)) {
			if (n_iter->act_t_flg) {
				if (!x_iter->act_t_flg) {
					/* new node has a true action */

					/* do the actions match? */
					rc = _db_tree_act_check(x_iter->nxt_t,
								n_iter->act_t);
					if (rc != 0)
						return rc;

					/* update with the new action */
					rc = _db_tree_put(&x_iter->nxt_t);
					x_iter->nxt_t = NULL;
					x_iter->act_t = n_iter->act_t;
					x_iter->act_t_flg = true;
					state->sx->node_cnt -= rc;
				} else if (n_iter->act_t != x_iter->act_t)
					return -EEXIST;
			}
			if (n_iter->act_f_flg) {
				if (!x_iter->act_f_flg) {
					/* new node has a false action */

					/* do the actions match? */
					rc = _db_tree_act_check(x_iter->nxt_f,
								n_iter->act_f);
					if (rc != 0)
						return rc;

					/* update with the new action */
					rc = _db_tree_put(&x_iter->nxt_f);
					x_iter->nxt_f = NULL;
					x_iter->act_f = n_iter->act_f;
					x_iter->act_f_flg = true;
					state->sx->node_cnt -= rc;
				} else if (n_iter->act_f != x_iter->act_f)
					return -EEXIST;
			}

			if (n_iter->nxt_t) {
				if (x_iter->nxt_t) {
					/* compare the next level */
					rc = _db_tree_add(&x_iter->nxt_t,
							  n_iter->nxt_t,
							  state);
					if (rc != 0)
						return rc;
				} else if (!x_iter->act_t_flg) {
					/* add a new sub-tree */
					x_iter->nxt_t = _db_tree_get(n_iter->nxt_t);
				} else
					/* done - existing tree is "shorter" */
					return 0;
			}
			if (n_iter->nxt_f) {
				if (x_iter->nxt_f) {
					/* compare the next level */
					rc = _db_tree_add(&x_iter->nxt_f,
							  n_iter->nxt_f,
							  state);
					if (rc != 0)
						return rc;
				} else if (!x_iter->act_f_flg) {
					/* add a new sub-tree */
					x_iter->nxt_f = _db_tree_get(n_iter->nxt_f);
				} else
					/* done - existing tree is "shorter" */
					return 0;
			}

			return 0;
		} else if (!_db_chain_lt(x_iter, n_iter)) {
			/* try to move along the current level */
			if (x_iter->lvl_nxt == NULL) {
				/* add to the end of this level */
				_db_level_get(x_iter);
				_db_tree_get(n_iter);
				n_iter->lvl_prv = x_iter;
				x_iter->lvl_nxt = n_iter;
				return 0;
			} else
				/* next */
				x_iter = x_iter->lvl_nxt;
		} else {
			/* add before the existing node on this level*/
			_db_level_get(x_iter);
			_db_tree_get(n_iter);
			if (x_iter->lvl_prv != NULL)
				x_iter->lvl_prv->lvl_nxt = n_iter;
			n_iter->lvl_prv = x_iter->lvl_prv;
			n_iter->lvl_nxt = x_iter;
			x_iter->lvl_prv = n_iter;
			if (*existing == x_iter)
				*existing = n_iter;
			return 0;
		}
	} while (x_iter);

	return 0;
}


static int selinux_inode_mkdir ( struct inode * dir , struct dentry * dentry , umode_t mask ) {
 return may_create ( dir , dentry , SECCLASS_DIR ) ;
 }


bool Curl_compareheader ( const char * headerline , const char * header , const char * content ) {
 size_t hlen = strlen ( header ) ;
 size_t clen ;
 size_t len ;
 const char * start ;
 const char * end ;
 if ( ! Curl_raw_nequal ( headerline , header , hlen ) ) return FALSE ;
 start = & headerline [ hlen ] ;
 while ( * start && ISSPACE ( * start ) ) start ++ ;
 end = strchr ( start , '\r' ) ;
 if ( ! end ) {
 end = strchr ( start , '\n' ) ;
 if ( ! end ) end = strchr ( start , '\0' ) ;
 }
 len = end - start ;
 clen = strlen ( content ) ;
 for ( ;
 len >= clen ;
 len -- , start ++ ) {
 if ( Curl_raw_nequal ( start , content , clen ) ) return TRUE ;
 }
 return FALSE ;
 }


static int sh_pci_host_init(PCIDevice *d) { pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_HITACHI); pci_config_set_device_id(d->config, PCI_DEVICE_ID_HITACHI_SH7751R); pci_set_word(d->config + PCI_COMMAND, PCI_COMMAND_WAIT); pci_set_word(d->config + PCI_STATUS, PCI_STATUS_CAP_LIST | PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM); return 0; }


static Sdb *store_versioninfo_gnu_verdef(ELFOBJ *bin, Elf_(Shdr) *shdr, int sz) {
	const char *section_name = "";
	const char *link_section_name = "";
	char *end = NULL;
	Elf_(Shdr) *link_shdr = NULL;
	ut8 dfs[sizeof (Elf_(Verdef))] = {0};
	Sdb *sdb;
	int cnt, i;
	if (shdr->sh_link > bin->ehdr.e_shnum) {
		return false;
	}
	link_shdr = &bin->shdr[shdr->sh_link];
	if (shdr->sh_size < 1) {
		return false;
	}
	Elf_(Verdef) *defs = calloc (shdr->sh_size, sizeof (char));
	if (!defs) {
		return false;
	}
	if (bin->shstrtab && shdr->sh_name < bin->shstrtab_size) {
		section_name = &bin->shstrtab[shdr->sh_name];
	}
	if (link_shdr && bin->shstrtab && link_shdr->sh_name < bin->shstrtab_size) {
		link_section_name = &bin->shstrtab[link_shdr->sh_name];
	}
	if (!defs) {
		bprintf ("Warning: Cannot allocate memory (Check Elf_(Verdef))\n");
		return NULL;
	}
	sdb = sdb_new0 ();
	end = (char *)defs + shdr->sh_size;
	sdb_set (sdb, "section_name", section_name, 0);
	sdb_num_set (sdb, "entries", shdr->sh_info, 0);
	sdb_num_set (sdb, "addr", shdr->sh_addr, 0);
	sdb_num_set (sdb, "offset", shdr->sh_offset, 0);
	sdb_num_set (sdb, "link", shdr->sh_link, 0);
	sdb_set (sdb, "link_section_name", link_section_name, 0);

	for (cnt = 0, i = 0; i >= 0 && cnt < shdr->sh_info && ((char *)defs + i < end); ++cnt) {
		Sdb *sdb_verdef = sdb_new0 ();
		char *vstart = ((char*)defs) + i;
		char key[32] = {0};
		Elf_(Verdef) *verdef = (Elf_(Verdef)*)vstart;
		Elf_(Verdaux) aux = {0};
		int j = 0;
		int isum = 0;

		r_buf_read_at (bin->b, shdr->sh_offset + i, dfs, sizeof (Elf_(Verdef)));
		verdef->vd_version = READ16 (dfs, j)
		verdef->vd_flags = READ16 (dfs, j)
		verdef->vd_ndx = READ16 (dfs, j)
		verdef->vd_cnt = READ16 (dfs, j)
		verdef->vd_hash = READ32 (dfs, j)
		verdef->vd_aux = READ32 (dfs, j)
		verdef->vd_next = READ32 (dfs, j)
		vstart += verdef->vd_aux;
		if (vstart > end || vstart + sizeof (Elf_(Verdaux)) > end) {
			sdb_free (sdb_verdef);
			goto out_error;
		}

		j = 0;
		aux.vda_name = READ32 (vstart, j)
		aux.vda_next = READ32 (vstart, j)

		isum = i + verdef->vd_aux;
		if (aux.vda_name > bin->dynstr_size) {
			sdb_free (sdb_verdef);
			goto out_error;
		}

		sdb_num_set (sdb_verdef, "idx", i, 0);
		sdb_num_set (sdb_verdef, "vd_version", verdef->vd_version, 0);
		sdb_num_set (sdb_verdef, "vd_ndx", verdef->vd_ndx, 0);
		sdb_num_set (sdb_verdef, "vd_cnt", verdef->vd_cnt, 0);
		sdb_set (sdb_verdef, "vda_name", &bin->dynstr[aux.vda_name], 0);
		sdb_set (sdb_verdef, "flags", get_ver_flags (verdef->vd_flags), 0);

		for (j = 1; j < verdef->vd_cnt; ++j) {
			int k;
			Sdb *sdb_parent = sdb_new0 ();
			isum += aux.vda_next;
			vstart += aux.vda_next;
			if (vstart > end || vstart + sizeof(Elf_(Verdaux)) > end) {
				sdb_free (sdb_verdef);
				sdb_free (sdb_parent);
				goto out_error;
			}
			k = 0;
			aux.vda_name = READ32 (vstart, k)
			aux.vda_next = READ32 (vstart, k)
			if (aux.vda_name > bin->dynstr_size) {
				sdb_free (sdb_verdef);
				sdb_free (sdb_parent);
				goto out_error;
			}
			sdb_num_set (sdb_parent, "idx", isum, 0);
			sdb_num_set (sdb_parent, "parent", j, 0);
			sdb_set (sdb_parent, "vda_name", &bin->dynstr[aux.vda_name], 0);
			snprintf (key, sizeof (key), "parent%d", j - 1);
			sdb_ns_set (sdb_verdef, key, sdb_parent);
		}

		snprintf (key, sizeof (key), "verdef%d", cnt);
		sdb_ns_set (sdb, key, sdb_verdef);
		if (!verdef->vd_next) {
			sdb_free (sdb_verdef);
			goto out_error;
		}
		if ((st32)verdef->vd_next < 1) {
			eprintf ("Warning: Invalid vd_next in the ELF version\n");
			break;
		}
		i += verdef->vd_next;
	}
	free (defs);
	return sdb;
out_error:
	free (defs);
	sdb_free (sdb);
	return NULL;
}


static inline bool cgfs_enter ( void * hdata , pid_t pid ) {
 struct cgfs_data * d = hdata ;
 struct cgroup_process_info * i ;
 int ret ;
 if ( ! d ) return false ;
 i = d -> info ;
 ret = lxc_cgroupfs_enter ( i , pid , false ) ;
 return ret == 0 ;
 }


static int read_header(FFV1Context *f) { uint8_t state[CONTEXT_SIZE]; int i, j, context_count = -1; //-1 to avoid warning RangeCoder *const c = &f->slice_context[0]->c; memset(state, 128, sizeof(state)); if (f->version < 2) { int chroma_planes, chroma_h_shift, chroma_v_shift, transparency, colorspace, bits_per_raw_sample; unsigned v= get_symbol(c, state, 0); if (v >= 2) { av_log(f->avctx, AV_LOG_ERROR, "invalid version %d in ver01 header\n", v); return AVERROR_INVALIDDATA; } f->version = v; f->ac = f->avctx->coder_type = get_symbol(c, state, 0); if (f->ac > 1) { for (i = 1; i < 256; i++) f->state_transition[i] = get_symbol(c, state, 1) + c->one_state[i]; } colorspace = get_symbol(c, state, 0); //YUV cs type bits_per_raw_sample = f->version > 0 ? get_symbol(c, state, 0) : f->avctx->bits_per_raw_sample; chroma_planes = get_rac(c, state); chroma_h_shift = get_symbol(c, state, 0); chroma_v_shift = get_symbol(c, state, 0); transparency = get_rac(c, state); if (f->plane_count) { if ( colorspace != f->colorspace || bits_per_raw_sample != f->avctx->bits_per_raw_sample || chroma_planes != f->chroma_planes || chroma_h_shift!= f->chroma_h_shift || chroma_v_shift!= f->chroma_v_shift || transparency != f->transparency) { av_log(f->avctx, AV_LOG_ERROR, "Invalid change of global parameters\n"); return AVERROR_INVALIDDATA; } } f->colorspace = colorspace; f->avctx->bits_per_raw_sample = bits_per_raw_sample; f->chroma_planes = chroma_planes; f->chroma_h_shift = chroma_h_shift; f->chroma_v_shift = chroma_v_shift; f->transparency = transparency; f->plane_count = 2 + f->transparency; } if (f->colorspace == 0) { if (!f->transparency && !f->chroma_planes) { if (f->avctx->bits_per_raw_sample <= 8) f->avctx->pix_fmt = AV_PIX_FMT_GRAY8; else f->avctx->pix_fmt = AV_PIX_FMT_GRAY16; } else if (f->avctx->bits_per_raw_sample<=8 && !f->transparency) { switch(16 * f->chroma_h_shift + f->chroma_v_shift) { case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUV444P; break; case 0x01: f->avctx->pix_fmt = AV_PIX_FMT_YUV440P; break; case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUV422P; break; case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUV420P; break; case 0x20: f->avctx->pix_fmt = AV_PIX_FMT_YUV411P; break; case 0x22: f->avctx->pix_fmt = AV_PIX_FMT_YUV410P; break; default: av_log(f->avctx, AV_LOG_ERROR, "format not supported\n"); return AVERROR(ENOSYS); } } else if (f->avctx->bits_per_raw_sample <= 8 && f->transparency) { switch(16*f->chroma_h_shift + f->chroma_v_shift) { case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUVA444P; break; case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUVA422P; break; case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUVA420P; break; default: av_log(f->avctx, AV_LOG_ERROR, "format not supported\n"); return AVERROR(ENOSYS); } } else if (f->avctx->bits_per_raw_sample == 9) { f->packed_at_lsb = 1; switch(16 * f->chroma_h_shift + f->chroma_v_shift) { case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUV444P9; break; case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUV422P9; break; case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUV420P9; break; default: av_log(f->avctx, AV_LOG_ERROR, "format not supported\n"); return AVERROR(ENOSYS); } } else if (f->avctx->bits_per_raw_sample == 10) { f->packed_at_lsb = 1; switch(16 * f->chroma_h_shift + f->chroma_v_shift) { case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUV444P10; break; case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUV422P10; break; case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUV420P10; break; default: av_log(f->avctx, AV_LOG_ERROR, "format not supported\n"); return AVERROR(ENOSYS); } } else { switch(16 * f->chroma_h_shift + f->chroma_v_shift) { case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUV444P16; break; case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUV422P16; break; case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUV420P16; break; default: av_log(f->avctx, AV_LOG_ERROR, "format not supported\n"); return AVERROR(ENOSYS); } } } else if (f->colorspace == 1) { if (f->chroma_h_shift || f->chroma_v_shift) { av_log(f->avctx, AV_LOG_ERROR, "chroma subsampling not supported in this colorspace\n"); return AVERROR(ENOSYS); } if ( f->avctx->bits_per_raw_sample == 9) f->avctx->pix_fmt = AV_PIX_FMT_GBRP9; else if (f->avctx->bits_per_raw_sample == 10) f->avctx->pix_fmt = AV_PIX_FMT_GBRP10; else if (f->avctx->bits_per_raw_sample == 12) f->avctx->pix_fmt = AV_PIX_FMT_GBRP12; else if (f->avctx->bits_per_raw_sample == 14) f->avctx->pix_fmt = AV_PIX_FMT_GBRP14; else if (f->transparency) f->avctx->pix_fmt = AV_PIX_FMT_RGB32; else f->avctx->pix_fmt = AV_PIX_FMT_0RGB32; } else { av_log(f->avctx, AV_LOG_ERROR, "colorspace not supported\n"); return AVERROR(ENOSYS); } av_dlog(f->avctx, "%d %d %d\n", f->chroma_h_shift, f->chroma_v_shift, f->avctx->pix_fmt); if (f->version < 2) { context_count = read_quant_tables(c, f->quant_table); if (context_count < 0) { av_log(f->avctx, AV_LOG_ERROR, "read_quant_table error\n"); return AVERROR_INVALIDDATA; } } else if (f->version < 3) { f->slice_count = get_symbol(c, state, 0); } else { const uint8_t *p = c->bytestream_end; for (f->slice_count = 0; f->slice_count < MAX_SLICES && 3 < p - c->bytestream_start; f->slice_count++) { int trailer = 3 + 5*!!f->ec; int size = AV_RB24(p-trailer); if (size + trailer > p - c->bytestream_start) break; p -= size + trailer; } } if (f->slice_count > (unsigned)MAX_SLICES || f->slice_count <= 0) { av_log(f->avctx, AV_LOG_ERROR, "slice count %d is invalid\n", f->slice_count); return AVERROR_INVALIDDATA; } for (j = 0; j < f->slice_count; j++) { FFV1Context *fs = f->slice_context[j]; fs->ac = f->ac; fs->packed_at_lsb = f->packed_at_lsb; fs->slice_damaged = 0; if (f->version == 2) { fs->slice_x = get_symbol(c, state, 0) * f->width ; fs->slice_y = get_symbol(c, state, 0) * f->height; fs->slice_width = (get_symbol(c, state, 0) + 1) * f->width + fs->slice_x; fs->slice_height = (get_symbol(c, state, 0) + 1) * f->height + fs->slice_y; fs->slice_x /= f->num_h_slices; fs->slice_y /= f->num_v_slices; fs->slice_width = fs->slice_width / f->num_h_slices - fs->slice_x; fs->slice_height = fs->slice_height / f->num_v_slices - fs->slice_y; if ((unsigned)fs->slice_width > f->width || (unsigned)fs->slice_height > f->height) return AVERROR_INVALIDDATA; if ( (unsigned)fs->slice_x + (uint64_t)fs->slice_width > f->width || (unsigned)fs->slice_y + (uint64_t)fs->slice_height > f->height) return AVERROR_INVALIDDATA; } for (i = 0; i < f->plane_count; i++) { PlaneContext *const p = &fs->plane[i]; if (f->version == 2) { int idx = get_symbol(c, state, 0); if (idx > (unsigned)f->quant_table_count) { av_log(f->avctx, AV_LOG_ERROR, "quant_table_index out of range\n"); return AVERROR_INVALIDDATA; } p->quant_table_index = idx; memcpy(p->quant_table, f->quant_tables[idx], sizeof(p->quant_table)); context_count = f->context_count[idx]; } else { memcpy(p->quant_table, f->quant_table, sizeof(p->quant_table)); } if (f->version <= 2) { av_assert0(context_count >= 0); if (p->context_count < context_count) { av_freep(&p->state); av_freep(&p->vlc_state); } p->context_count = context_count; } } } return 0; }


static inline void iir_filter ( int16_t * fir_coef , int16_t * iir_coef , int16_t * src , int * dest ) {
 int m , n ;
 for ( m = 0 ;
 m < SUBFRAME_LEN ;
 m ++ ) {
 int64_t filter = 0 ;
 for ( n = 1 ;
 n <= LPC_ORDER ;
 n ++ ) {
 filter -= fir_coef [ n - 1 ] * src [ m - n ] - iir_coef [ n - 1 ] * ( dest [ m - n ] >> 16 ) ;
 }
 dest [ m ] = av_clipl_int32 ( ( src [ m ] << 16 ) + ( filter << 3 ) + ( 1 << 15 ) ) ;
 }
 }


UsbHubCtrlGetSuperSpeedHubDesc (
  IN  USB_DEVICE          *HubDev,
  OUT VOID                *Buf
  )
{
  EFI_STATUS              Status;

  Status = EFI_INVALID_PARAMETER;

  Status = UsbCtrlRequest (
             HubDev,
             EfiUsbDataIn,
             USB_REQ_TYPE_CLASS,
             USB_HUB_TARGET_HUB,
             USB_HUB_REQ_GET_DESC,
             (UINT16) (USB_DESC_TYPE_HUB_SUPER_SPEED << 8),
             0,
             Buf,
             32
             );

  return Status;
}


static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len) { MpegTSContext *ts = filter->u.section_filter.opaque; MpegTSSectionFilter *tssf = &filter->u.section_filter; SectionHeader h1, *h = &h1; PESContext *pes; AVStream *st; const uint8_t *p, *p_end, *desc_list_end; int program_info_length, pcr_pid, pid, stream_type; int desc_list_len; uint32_t prog_reg_desc = 0; /* registration descriptor */ int mp4_descr_count = 0; Mp4Descr mp4_descr[MAX_MP4_DESCR_COUNT] = { { 0 } }; int i; av_log(ts->stream, AV_LOG_TRACE, "PMT: len %i\n", section_len); hex_dump_debug(ts->stream, section, section_len); p_end = section + section_len - 4; p = section; if (parse_section_header(h, &p, p_end) < 0) return; if (h->version == tssf->last_ver) return; tssf->last_ver = h->version; av_log(ts->stream, AV_LOG_TRACE, "sid=0x%x sec_num=%d/%d version=%d\n", h->id, h->sec_num, h->last_sec_num, h->version); if (h->tid != PMT_TID) return; if (!ts->scan_all_pmts && ts->skip_changes) return; if (!ts->skip_clear) clear_program(ts, h->id); pcr_pid = get16(&p, p_end); if (pcr_pid < 0) return; pcr_pid &= 0x1fff; add_pid_to_pmt(ts, h->id, pcr_pid); set_pcr_pid(ts->stream, h->id, pcr_pid); av_log(ts->stream, AV_LOG_TRACE, "pcr_pid=0x%x\n", pcr_pid); program_info_length = get16(&p, p_end); if (program_info_length < 0) return; program_info_length &= 0xfff; while (program_info_length >= 2) { uint8_t tag, len; tag = get8(&p, p_end); len = get8(&p, p_end); av_log(ts->stream, AV_LOG_TRACE, "program tag: 0x%02x len=%d\n", tag, len); if (len > program_info_length - 2) // something else is broken, exit the program_descriptors_loop break; program_info_length -= len + 2; if (tag == 0x1d) { // IOD descriptor get8(&p, p_end); // scope get8(&p, p_end); // label len -= 2; mp4_read_iods(ts->stream, p, len, mp4_descr + mp4_descr_count, &mp4_descr_count, MAX_MP4_DESCR_COUNT); } else if (tag == 0x05 && len >= 4) { // registration descriptor prog_reg_desc = bytestream_get_le32(&p); len -= 4; } p += len; } p += program_info_length; if (p >= p_end) goto out; // stop parsing after pmt, we found header if (!ts->stream->nb_streams) ts->stop_parse = 2; set_pmt_found(ts, h->id); for (;;) { st = 0; pes = NULL; stream_type = get8(&p, p_end); if (stream_type < 0) break; pid = get16(&p, p_end); if (pid < 0) goto out; pid &= 0x1fff; if (pid == ts->current_pid) goto out; /* now create stream */ if (ts->pids[pid] && ts->pids[pid]->type == MPEGTS_PES) { pes = ts->pids[pid]->u.pes_filter.opaque; if (!pes->st) { pes->st = avformat_new_stream(pes->stream, NULL); if (!pes->st) goto out; pes->st->id = pes->pid; } st = pes->st; } else if (stream_type != 0x13) { if (ts->pids[pid]) mpegts_close_filter(ts, ts->pids[pid]); // wrongly added sdt filter probably pes = add_pes_stream(ts, pid, pcr_pid); if (pes) { st = avformat_new_stream(pes->stream, NULL); if (!st) goto out; st->id = pes->pid; } } else { int idx = ff_find_stream_index(ts->stream, pid); if (idx >= 0) { st = ts->stream->streams[idx]; } else { st = avformat_new_stream(ts->stream, NULL); if (!st) goto out; st->id = pid; st->codec->codec_type = AVMEDIA_TYPE_DATA; } } if (!st) goto out; if (pes && !pes->stream_type) mpegts_set_stream_info(st, pes, stream_type, prog_reg_desc); add_pid_to_pmt(ts, h->id, pid); ff_program_add_stream_index(ts->stream, h->id, st->index); desc_list_len = get16(&p, p_end); if (desc_list_len < 0) goto out; desc_list_len &= 0xfff; desc_list_end = p + desc_list_len; if (desc_list_end > p_end) goto out; for (;;) { if (ff_parse_mpeg2_descriptor(ts->stream, st, stream_type, &p, desc_list_end, mp4_descr, mp4_descr_count, pid, ts) < 0) break; if (pes && prog_reg_desc == AV_RL32("HDMV") && stream_type == 0x83 && pes->sub_st) { ff_program_add_stream_index(ts->stream, h->id, pes->sub_st->index); pes->sub_st->codec->codec_tag = st->codec->codec_tag; } } p = desc_list_end; } if (!ts->pids[pcr_pid]) mpegts_open_pcr_filter(ts, pcr_pid); out: for (i = 0; i < mp4_descr_count; i++) av_free(mp4_descr[i].dec_config_descr); }


PeiUsbHubReadDesc (
  IN EFI_PEI_SERVICES           **PeiServices,
  IN PEI_USB_DEVICE             *PeiUsbDevice,
  IN PEI_USB_IO_PPI             *UsbIoPpi,
  OUT EFI_USB_HUB_DESCRIPTOR    *HubDescriptor
  )
{
  EFI_STATUS Status;

  if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) {
    //
    // Get the super speed hub descriptor
    //
    Status = PeiGetSuperSpeedHubDesc (PeiServices, UsbIoPpi, HubDescriptor);
  } else {

    //
    // First get the hub descriptor length
    //
    Status = PeiGetHubDescriptor (PeiServices, UsbIoPpi, 2, HubDescriptor);

    if (EFI_ERROR (Status)) {
      return Status;
    }

    //
    // Get the whole hub descriptor
    //
    Status = PeiGetHubDescriptor (PeiServices, UsbIoPpi, HubDescriptor->Length, HubDescriptor);
  }

  return Status;
}


PeiGetHubDescriptor (
  IN  EFI_PEI_SERVICES          **PeiServices,
  IN  PEI_USB_IO_PPI            *UsbIoPpi,
  IN  UINTN                     DescriptorSize,
  OUT EFI_USB_HUB_DESCRIPTOR    *HubDescriptor
  )
{
  EFI_USB_DEVICE_REQUEST      DevReq;
  ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));

  //
  // Fill Device request packet
  //
  DevReq.RequestType = USB_RT_HUB | 0x80;
  DevReq.Request     = USB_HUB_GET_DESCRIPTOR;
  DevReq.Value       = USB_DT_HUB << 8;
  DevReq.Length      = (UINT16)DescriptorSize;

  return  UsbIoPpi->UsbControlTransfer (
                      PeiServices,
                      UsbIoPpi,
                      &DevReq,
                      EfiUsbDataIn,
                      PcdGet32 (PcdUsbTransferTimeoutValue),
                      HubDescriptor,
                      (UINT16)DescriptorSize
                      );
}


void uninit_opts(void) { int i; for (i = 0; i < AVMEDIA_TYPE_NB; i++) av_freep(&avcodec_opts[i]); av_freep(&avformat_opts->key); av_freep(&avformat_opts); #if CONFIG_SWSCALE av_freep(&sws_opts); #endif for (i = 0; i < opt_name_count; i++) { //opt_values are only stored for codec-specific options in which case //both the name and value are dup'd if (opt_values[i]) { av_freep(&opt_names[i]); av_freep(&opt_values[i]); } } av_freep(&opt_names); av_freep(&opt_values); }


int idr_for_each(struct idr *idp,
		 int (*fn)(int id, void *p, void *data), void *data)
{
	int n, id, max, error = 0;
	struct idr_layer *p;
	struct idr_layer *pa[MAX_IDR_LEVEL];
	struct idr_layer **paa = &pa[0];

	n = idp->layers * IDR_BITS;
	p = rcu_dereference_raw(idp->top);
	max = 1 << n;

	id = 0;
	while (id < max) {
		while (n > 0 && p) {
			n -= IDR_BITS;
			*paa++ = p;
			p = rcu_dereference_raw(p->ary[(id >> n) & IDR_MASK]);
		}

		if (p) {
			error = fn(id, (void *)p, data);
			if (error)
				break;
		}

		id += 1 << n;
		while (n < fls(id)) {
			n += IDR_BITS;
			p = *--paa;
		}
	}

	return error;
}


int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id)
{
	struct idr_layer *pa[MAX_IDR_LEVEL];
	int rv;

	rv = idr_get_empty_slot(idp, starting_id, pa, 0, idp);
	if (rv < 0)
		return rv == -ENOMEM ? -EAGAIN : rv;

	idr_fill_slot(ptr, rv, pa);
	*id = rv;
	return 0;
}


static GstFlowReturn gst_asf_demux_process_header ( GstASFDemux * demux , guint8 * data , guint64 size ) {
 GstFlowReturn ret = GST_FLOW_OK ;
 guint32 i , num_objects ;
 guint8 unknown G_GNUC_UNUSED ;
 if ( size < ( 4 + 1 + 1 ) ) goto not_enough_data ;
 num_objects = gst_asf_demux_get_uint32 ( & data , & size ) ;
 unknown = gst_asf_demux_get_uint8 ( & data , & size ) ;
 unknown = gst_asf_demux_get_uint8 ( & data , & size ) ;
 GST_INFO_OBJECT ( demux , "object is a header with %u parts" , num_objects ) ;
 demux -> saw_file_header = FALSE ;
 for ( i = 0 ;
 i < num_objects ;
 ++ i ) {
 GST_INFO_OBJECT ( demux , "reading header part %u" , i ) ;
 ret = gst_asf_demux_process_object ( demux , & data , & size ) ;
 if ( ret != GST_FLOW_OK ) {
 GST_WARNING ( "process_object returned %s" , gst_asf_get_flow_name ( ret ) ) ;
 break ;
 }
 }
 if ( ! demux -> saw_file_header ) {
 GST_ELEMENT_ERROR ( demux , STREAM , DEMUX , ( NULL ) , ( "Header does not have mandatory FILE section" ) ) ;
 return GST_FLOW_ERROR ;
 }
 return ret ;
 not_enough_data : {
 GST_ELEMENT_ERROR ( demux , STREAM , DEMUX , ( NULL ) , ( "short read parsing HEADER object" ) ) ;
 return GST_FLOW_ERROR ;
 }
 }