<commit_before>/*
 * Copyright (c) 2002-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Steve Reinhardt
 */

#include "arch/utility.hh"
#include "base/cprintf.hh"
#include "base/inifile.hh"
#include "base/loader/symtab.hh"
#include "base/misc.hh"
#include "base/pollevent.hh"
#include "base/range.hh"
#include "base/stats/events.hh"
#include "base/trace.hh"
#include "cpu/base.hh"
#include "cpu/cpu_exec_context.hh"
#include "cpu/exec_context.hh"
#include "cpu/exetrace.hh"
#include "cpu/profile.hh"
#include "cpu/sampler/sampler.hh"
#include "cpu/simple/base.hh"
#include "cpu/smt.hh"
#include "cpu/static_inst.hh"
#include "kern/kernel_stats.hh"
#include "mem/packet_impl.hh"
#include "sim/byteswap.hh"
#include "sim/builder.hh"
#include "sim/debug.hh"
#include "sim/host.hh"
#include "sim/sim_events.hh"
#include "sim/sim_object.hh"
#include "sim/stats.hh"

#if FULL_SYSTEM
#include "base/remote_gdb.hh"
#include "sim/system.hh"
#include "arch/tlb.hh"
#include "arch/stacktrace.hh"
#include "arch/vtophys.hh"
#else // !FULL_SYSTEM
#include "mem/mem_object.hh"
#endif // FULL_SYSTEM

using namespace std;
using namespace TheISA;

BaseSimpleCPU::BaseSimpleCPU(Params *p)
    : BaseCPU(p), mem(p->mem), cpuXC(NULL)
{
#if FULL_SYSTEM
    cpuXC = new CPUExecContext(this, 0, p->system, p->itb, p->dtb);
#else
    cpuXC = new CPUExecContext(this, /* thread_num */ 0, p->process,
            /* asid */ 0, mem);
#endif // !FULL_SYSTEM

    xcProxy = cpuXC->getProxy();

    numInst = 0;
    startNumInst = 0;
    numLoad = 0;
    startNumLoad = 0;
    lastIcacheStall = 0;
    lastDcacheStall = 0;

    execContexts.push_back(xcProxy);
}

BaseSimpleCPU::~BaseSimpleCPU()
{
}

void
BaseSimpleCPU::deallocateContext(int thread_num)
{
    // for now, these are equivalent
    suspendContext(thread_num);
}

void
BaseSimpleCPU::haltContext(int thread_num)
{
    // for now, these are equivalent
    suspendContext(thread_num);
}

void
BaseSimpleCPU::regStats()
{
    using namespace Stats;

    BaseCPU::regStats();

    numInsts
        .name(name() + ".num_insts")
        .desc("Number of instructions executed")
        ;

    numMemRefs
        .name(name() + ".num_refs")
        .desc("Number of memory references")
        ;

    notIdleFraction
        .name(name() + ".not_idle_fraction")
        .desc("Percentage of non-idle cycles")
        ;

    idleFraction
        .name(name() + ".idle_fraction")
        .desc("Percentage of idle cycles")
        ;

    icacheStallCycles
        .name(name() + ".icache_stall_cycles")
        .desc("ICache total stall cycles")
        .prereq(icacheStallCycles)
        ;

    dcacheStallCycles
        .name(name() + ".dcache_stall_cycles")
        .desc("DCache total stall cycles")
        .prereq(dcacheStallCycles)
        ;

    icacheRetryCycles
        .name(name() + ".icache_retry_cycles")
        .desc("ICache total retry cycles")
        .prereq(icacheRetryCycles)
        ;

    dcacheRetryCycles
        .name(name() + ".dcache_retry_cycles")
        .desc("DCache total retry cycles")
        .prereq(dcacheRetryCycles)
        ;

    idleFraction = constant(1.0) - notIdleFraction;
}

void
BaseSimpleCPU::resetStats()
{
    startNumInst = numInst;
    // notIdleFraction = (_status != Idle);
}

void
BaseSimpleCPU::serialize(ostream &os)
{
    BaseCPU::serialize(os);
    SERIALIZE_SCALAR(inst);
    nameOut(os, csprintf("%s.xc", name()));
    cpuXC->serialize(os);
}

void
BaseSimpleCPU::unserialize(Checkpoint *cp, const string &section)
{
    BaseCPU::unserialize(cp, section);
    UNSERIALIZE_SCALAR(inst);
    cpuXC->unserialize(cp, csprintf("%s.xc", section));
}

void
change_thread_state(int thread_number, int activate, int priority)
{
}

Fault
BaseSimpleCPU::copySrcTranslate(Addr src)
{
#if 0
    static bool no_warn = true;
    int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
    // Only support block sizes of 64 atm.
    assert(blk_size == 64);
    int offset = src & (blk_size - 1);

    // Make sure block doesn't span page
    if (no_warn &&
        (src & PageMask) != ((src + blk_size) & PageMask) &&
        (src >> 40) != 0xfffffc) {
        warn("Copied block source spans pages %x.", src);
        no_warn = false;
    }

    memReq->reset(src & ~(blk_size - 1), blk_size);

    // translate to physical address
    Fault fault = cpuXC->translateDataReadReq(req);

    if (fault == NoFault) {
        cpuXC->copySrcAddr = src;
        cpuXC->copySrcPhysAddr = memReq->paddr + offset;
    } else {
        assert(!fault->isAlignmentFault());

        cpuXC->copySrcAddr = 0;
        cpuXC->copySrcPhysAddr = 0;
    }
    return fault;
#else
    return NoFault;
#endif
}

Fault
BaseSimpleCPU::copy(Addr dest)
{
#if 0
    static bool no_warn = true;
    int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
    // Only support block sizes of 64 atm.
    assert(blk_size == 64);
    uint8_t data[blk_size];
    //assert(cpuXC->copySrcAddr);
    int offset = dest & (blk_size - 1);

    // Make sure block doesn't span page
    if (no_warn &&
        (dest & PageMask) != ((dest + blk_size) & PageMask) &&
        (dest >> 40) != 0xfffffc) {
        no_warn = false;
        warn("Copied block destination spans pages %x. ", dest);
    }

    memReq->reset(dest & ~(blk_size -1), blk_size);
    // translate to physical address
    Fault fault = cpuXC->translateDataWriteReq(req);

    if (fault == NoFault) {
        Addr dest_addr = memReq->paddr + offset;
        // Need to read straight from memory since we have more than 8 bytes.
        memReq->paddr = cpuXC->copySrcPhysAddr;
        cpuXC->mem->read(memReq, data);
        memReq->paddr = dest_addr;
        cpuXC->mem->write(memReq, data);
        if (dcacheInterface) {
            memReq->cmd = Copy;
            memReq->completionEvent = NULL;
            memReq->paddr = cpuXC->copySrcPhysAddr;
            memReq->dest = dest_addr;
            memReq->size = 64;
            memReq->time = curTick;
            memReq->flags &= ~INST_READ;
            dcacheInterface->access(memReq);
        }
    }
    else
        assert(!fault->isAlignmentFault());

    return fault;
#else
    panic("copy not implemented");
    return NoFault;
#endif
}

#if FULL_SYSTEM
Addr
BaseSimpleCPU::dbg_vtophys(Addr addr)
{
    return vtophys(xcProxy, addr);
}
#endif // FULL_SYSTEM

#if FULL_SYSTEM
void
BaseSimpleCPU::post_interrupt(int int_num, int index)
{
    BaseCPU::post_interrupt(int_num, index);

    if (cpuXC->status() == ExecContext::Suspended) {
                DPRINTF(IPI,"Suspended Processor awoke\n");
        cpuXC->activate();
    }
}
#endif // FULL_SYSTEM

void
BaseSimpleCPU::checkForInterrupts()
{
#if FULL_SYSTEM
    if (checkInterrupts && check_interrupts() && !cpuXC->inPalMode()) {
        int ipl = 0;
        int summary = 0;
        checkInterrupts = false;

        if (cpuXC->readMiscReg(IPR_SIRR)) {
            for (int i = INTLEVEL_SOFTWARE_MIN;
                 i < INTLEVEL_SOFTWARE_MAX; i++) {
                if (cpuXC->readMiscReg(IPR_SIRR) & (ULL(1) << i)) {
                    // See table 4-19 of 21164 hardware reference
                    ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1;
                    summary |= (ULL(1) << i);
                }
            }
        }

        uint64_t interrupts = cpuXC->cpu->intr_status();
        for (int i = INTLEVEL_EXTERNAL_MIN;
            i < INTLEVEL_EXTERNAL_MAX; i++) {
            if (interrupts & (ULL(1) << i)) {
                // See table 4-19 of 21164 hardware reference
                ipl = i;
                summary |= (ULL(1) << i);
            }
        }

        if (cpuXC->readMiscReg(IPR_ASTRR))
            panic("asynchronous traps not implemented\n");

        if (ipl && ipl > cpuXC->readMiscReg(IPR_IPLR)) {
            cpuXC->setMiscReg(IPR_ISR, summary);
            cpuXC->setMiscReg(IPR_INTID, ipl);

            Fault(new InterruptFault)->invoke(xcProxy);

            DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
                    cpuXC->readMiscReg(IPR_IPLR), ipl, summary);
        }
    }
#endif
}

Fault
BaseSimpleCPU::setupFetchRequest(Request *req)
{
    // set up memory request for instruction fetch
    DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p NNPC:%08p\n",cpuXC->readPC(),
            cpuXC->readNextPC(),cpuXC->readNextNPC());

    req->setVirt(0, cpuXC->readPC() & ~3, sizeof(MachInst),
                 (FULL_SYSTEM && (cpuXC->readPC() & 1)) ? PHYSICAL : 0,
                 cpuXC->readPC());

    Fault fault = cpuXC->translateInstReq(req);

    return fault;
}

void
BaseSimpleCPU::preExecute()
{
    // maintain $r0 semantics
    cpuXC->setIntReg(ZeroReg, 0);
#if THE_ISA == ALPHA_ISA
    cpuXC->setFloatReg(ZeroReg, 0.0);
#endif // ALPHA_ISA

    // keep an instruction count
    numInst++;
    numInsts++;

    cpuXC->func_exe_inst++;

    // check for instruction-count-based events
    comInstEventQueue[0]->serviceEvents(numInst);

    // decode the instruction
    inst = gtoh(inst);
    curStaticInst = StaticInst::decode(makeExtMI(inst, cpuXC->readPC()));

    traceData = Trace::getInstRecord(curTick, xcProxy, this, curStaticInst,
                                     cpuXC->readPC());

    DPRINTF(Decode,"Decode: Decoded %s instruction (opcode: 0x%x): 0x%x\n",
            curStaticInst->getName(), curStaticInst->getOpcode(),
            curStaticInst->machInst);

#if FULL_SYSTEM
    cpuXC->setInst(inst);
#endif // FULL_SYSTEM
}

void
BaseSimpleCPU::postExecute()
{
#if FULL_SYSTEM
    if (system->kernelBinning->fnbin) {
        assert(kernelStats);
        system->kernelBinning->execute(xcProxy, inst);
    }

    if (cpuXC->profile) {
        bool usermode =
            (cpuXC->readMiscReg(AlphaISA::IPR_DTB_CM) & 0x18) != 0;
        cpuXC->profilePC = usermode ? 1 : cpuXC->readPC();
        ProfileNode *node = cpuXC->profile->consume(xcProxy, inst);
        if (node)
            cpuXC->profileNode = node;
    }
#endif

    if (curStaticInst->isMemRef()) {
        numMemRefs++;
    }

    if (curStaticInst->isLoad()) {
        ++numLoad;
        comLoadEventQueue[0]->serviceEvents(numLoad);
    }

    traceFunctions(cpuXC->readPC());

    if (traceData) {
        traceData->finalize();
    }
}

void
BaseSimpleCPU::advancePC(Fault fault)
{
    if (fault != NoFault) {
#if FULL_SYSTEM
        fault->invoke(xcProxy);
#else // !FULL_SYSTEM
        fatal("fault (%s) detected @ PC %08p", fault->name(), cpuXC->readPC());
#endif // FULL_SYSTEM
    }
    else {
        // go to the next instruction
        cpuXC->setPC(cpuXC->readNextPC());
#if THE_ISA == ALPHA_ISA
        cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst));
#else
        cpuXC->setNextPC(cpuXC->readNextNPC());
        cpuXC->setNextNPC(cpuXC->readNextNPC() + sizeof(MachInst));
#endif

    }

#if FULL_SYSTEM
    Addr oldpc;
    do {
        oldpc = cpuXC->readPC();
        system->pcEventQueue.service(xcProxy);
    } while (oldpc != cpuXC->readPC());
#endif
}

<commit_msg>Fix for full system compiling.<commit_after>/*
 * Copyright (c) 2002-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Steve Reinhardt
 */

#include "arch/utility.hh"
#include "base/cprintf.hh"
#include "base/inifile.hh"
#include "base/loader/symtab.hh"
#include "base/misc.hh"
#include "base/pollevent.hh"
#include "base/range.hh"
#include "base/stats/events.hh"
#include "base/trace.hh"
#include "cpu/base.hh"
#include "cpu/cpu_exec_context.hh"
#include "cpu/exec_context.hh"
#include "cpu/exetrace.hh"
#include "cpu/profile.hh"
#include "cpu/sampler/sampler.hh"
#include "cpu/simple/base.hh"
#include "cpu/smt.hh"
#include "cpu/static_inst.hh"
#include "kern/kernel_stats.hh"
#include "mem/packet_impl.hh"
#include "sim/byteswap.hh"
#include "sim/builder.hh"
#include "sim/debug.hh"
#include "sim/host.hh"
#include "sim/sim_events.hh"
#include "sim/sim_object.hh"
#include "sim/stats.hh"

#if FULL_SYSTEM
#include "base/remote_gdb.hh"
#include "sim/system.hh"
#include "arch/tlb.hh"
#include "arch/stacktrace.hh"
#include "arch/vtophys.hh"
#else // !FULL_SYSTEM
#include "mem/mem_object.hh"
#endif // FULL_SYSTEM

using namespace std;
using namespace TheISA;

BaseSimpleCPU::BaseSimpleCPU(Params *p)
    : BaseCPU(p), mem(p->mem), cpuXC(NULL)
{
#if FULL_SYSTEM
    cpuXC = new CPUExecContext(this, 0, p->system, p->itb, p->dtb);
#else
    cpuXC = new CPUExecContext(this, /* thread_num */ 0, p->process,
            /* asid */ 0, mem);
#endif // !FULL_SYSTEM

    xcProxy = cpuXC->getProxy();

    numInst = 0;
    startNumInst = 0;
    numLoad = 0;
    startNumLoad = 0;
    lastIcacheStall = 0;
    lastDcacheStall = 0;

    execContexts.push_back(xcProxy);
}

BaseSimpleCPU::~BaseSimpleCPU()
{
}

void
BaseSimpleCPU::deallocateContext(int thread_num)
{
    // for now, these are equivalent
    suspendContext(thread_num);
}

void
BaseSimpleCPU::haltContext(int thread_num)
{
    // for now, these are equivalent
    suspendContext(thread_num);
}

void
BaseSimpleCPU::regStats()
{
    using namespace Stats;

    BaseCPU::regStats();

    numInsts
        .name(name() + ".num_insts")
        .desc("Number of instructions executed")
        ;

    numMemRefs
        .name(name() + ".num_refs")
        .desc("Number of memory references")
        ;

    notIdleFraction
        .name(name() + ".not_idle_fraction")
        .desc("Percentage of non-idle cycles")
        ;

    idleFraction
        .name(name() + ".idle_fraction")
        .desc("Percentage of idle cycles")
        ;

    icacheStallCycles
        .name(name() + ".icache_stall_cycles")
        .desc("ICache total stall cycles")
        .prereq(icacheStallCycles)
        ;

    dcacheStallCycles
        .name(name() + ".dcache_stall_cycles")
        .desc("DCache total stall cycles")
        .prereq(dcacheStallCycles)
        ;

    icacheRetryCycles
        .name(name() + ".icache_retry_cycles")
        .desc("ICache total retry cycles")
        .prereq(icacheRetryCycles)
        ;

    dcacheRetryCycles
        .name(name() + ".dcache_retry_cycles")
        .desc("DCache total retry cycles")
        .prereq(dcacheRetryCycles)
        ;

    idleFraction = constant(1.0) - notIdleFraction;
}

void
BaseSimpleCPU::resetStats()
{
    startNumInst = numInst;
    // notIdleFraction = (_status != Idle);
}

void
BaseSimpleCPU::serialize(ostream &os)
{
    BaseCPU::serialize(os);
    SERIALIZE_SCALAR(inst);
    nameOut(os, csprintf("%s.xc", name()));
    cpuXC->serialize(os);
}

void
BaseSimpleCPU::unserialize(Checkpoint *cp, const string &section)
{
    BaseCPU::unserialize(cp, section);
    UNSERIALIZE_SCALAR(inst);
    cpuXC->unserialize(cp, csprintf("%s.xc", section));
}

void
change_thread_state(int thread_number, int activate, int priority)
{
}

Fault
BaseSimpleCPU::copySrcTranslate(Addr src)
{
#if 0
    static bool no_warn = true;
    int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
    // Only support block sizes of 64 atm.
    assert(blk_size == 64);
    int offset = src & (blk_size - 1);

    // Make sure block doesn't span page
    if (no_warn &&
        (src & PageMask) != ((src + blk_size) & PageMask) &&
        (src >> 40) != 0xfffffc) {
        warn("Copied block source spans pages %x.", src);
        no_warn = false;
    }

    memReq->reset(src & ~(blk_size - 1), blk_size);

    // translate to physical address
    Fault fault = cpuXC->translateDataReadReq(req);

    if (fault == NoFault) {
        cpuXC->copySrcAddr = src;
        cpuXC->copySrcPhysAddr = memReq->paddr + offset;
    } else {
        assert(!fault->isAlignmentFault());

        cpuXC->copySrcAddr = 0;
        cpuXC->copySrcPhysAddr = 0;
    }
    return fault;
#else
    return NoFault;
#endif
}

Fault
BaseSimpleCPU::copy(Addr dest)
{
#if 0
    static bool no_warn = true;
    int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
    // Only support block sizes of 64 atm.
    assert(blk_size == 64);
    uint8_t data[blk_size];
    //assert(cpuXC->copySrcAddr);
    int offset = dest & (blk_size - 1);

    // Make sure block doesn't span page
    if (no_warn &&
        (dest & PageMask) != ((dest + blk_size) & PageMask) &&
        (dest >> 40) != 0xfffffc) {
        no_warn = false;
        warn("Copied block destination spans pages %x. ", dest);
    }

    memReq->reset(dest & ~(blk_size -1), blk_size);
    // translate to physical address
    Fault fault = cpuXC->translateDataWriteReq(req);

    if (fault == NoFault) {
        Addr dest_addr = memReq->paddr + offset;
        // Need to read straight from memory since we have more than 8 bytes.
        memReq->paddr = cpuXC->copySrcPhysAddr;
        cpuXC->mem->read(memReq, data);
        memReq->paddr = dest_addr;
        cpuXC->mem->write(memReq, data);
        if (dcacheInterface) {
            memReq->cmd = Copy;
            memReq->completionEvent = NULL;
            memReq->paddr = cpuXC->copySrcPhysAddr;
            memReq->dest = dest_addr;
            memReq->size = 64;
            memReq->time = curTick;
            memReq->flags &= ~INST_READ;
            dcacheInterface->access(memReq);
        }
    }
    else
        assert(!fault->isAlignmentFault());

    return fault;
#else
    panic("copy not implemented");
    return NoFault;
#endif
}

#if FULL_SYSTEM
Addr
BaseSimpleCPU::dbg_vtophys(Addr addr)
{
    return vtophys(xcProxy, addr);
}
#endif // FULL_SYSTEM

#if FULL_SYSTEM
void
BaseSimpleCPU::post_interrupt(int int_num, int index)
{
    BaseCPU::post_interrupt(int_num, index);

    if (cpuXC->status() == ExecContext::Suspended) {
                DPRINTF(IPI,"Suspended Processor awoke\n");
        cpuXC->activate();
    }
}
#endif // FULL_SYSTEM

void
BaseSimpleCPU::checkForInterrupts()
{
#if FULL_SYSTEM
    if (checkInterrupts && check_interrupts() && !cpuXC->inPalMode()) {
        int ipl = 0;
        int summary = 0;
        checkInterrupts = false;

        if (cpuXC->readMiscReg(IPR_SIRR)) {
            for (int i = INTLEVEL_SOFTWARE_MIN;
                 i < INTLEVEL_SOFTWARE_MAX; i++) {
                if (cpuXC->readMiscReg(IPR_SIRR) & (ULL(1) << i)) {
                    // See table 4-19 of 21164 hardware reference
                    ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1;
                    summary |= (ULL(1) << i);
                }
            }
        }

        uint64_t interrupts = cpuXC->cpu->intr_status();
        for (int i = INTLEVEL_EXTERNAL_MIN;
            i < INTLEVEL_EXTERNAL_MAX; i++) {
            if (interrupts & (ULL(1) << i)) {
                // See table 4-19 of 21164 hardware reference
                ipl = i;
                summary |= (ULL(1) << i);
            }
        }

        if (cpuXC->readMiscReg(IPR_ASTRR))
            panic("asynchronous traps not implemented\n");

        if (ipl && ipl > cpuXC->readMiscReg(IPR_IPLR)) {
            cpuXC->setMiscReg(IPR_ISR, summary);
            cpuXC->setMiscReg(IPR_INTID, ipl);

            Fault(new InterruptFault)->invoke(xcProxy);

            DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
                    cpuXC->readMiscReg(IPR_IPLR), ipl, summary);
        }
    }
#endif
}

Fault
BaseSimpleCPU::setupFetchRequest(Request *req)
{
    // set up memory request for instruction fetch
    DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p NNPC:%08p\n",cpuXC->readPC(),
            cpuXC->readNextPC(),cpuXC->readNextNPC());

    req->setVirt(0, cpuXC->readPC() & ~3, sizeof(MachInst),
                 (FULL_SYSTEM && (cpuXC->readPC() & 1)) ? PHYSICAL : 0,
                 cpuXC->readPC());

    Fault fault = cpuXC->translateInstReq(req);

    return fault;
}

void
BaseSimpleCPU::preExecute()
{
    // maintain $r0 semantics
    cpuXC->setIntReg(ZeroReg, 0);
#if THE_ISA == ALPHA_ISA
    cpuXC->setFloatReg(ZeroReg, 0.0);
#endif // ALPHA_ISA

    // keep an instruction count
    numInst++;
    numInsts++;

    cpuXC->func_exe_inst++;

    // check for instruction-count-based events
    comInstEventQueue[0]->serviceEvents(numInst);

    // decode the instruction
    inst = gtoh(inst);
    curStaticInst = StaticInst::decode(makeExtMI(inst, cpuXC->readPC()));

    traceData = Trace::getInstRecord(curTick, xcProxy, this, curStaticInst,
                                     cpuXC->readPC());

    DPRINTF(Decode,"Decode: Decoded %s instruction (opcode: 0x%x): 0x%x\n",
            curStaticInst->getName(), curStaticInst->getOpcode(),
            curStaticInst->machInst);

#if FULL_SYSTEM
    cpuXC->setInst(inst);
#endif // FULL_SYSTEM
}

void
BaseSimpleCPU::postExecute()
{
#if FULL_SYSTEM
    if (system->kernelBinning->fnbin) {
        assert(cpuXC->getKernelStats());
        system->kernelBinning->execute(xcProxy, inst);
    }

    if (cpuXC->profile) {
        bool usermode =
            (cpuXC->readMiscReg(AlphaISA::IPR_DTB_CM) & 0x18) != 0;
        cpuXC->profilePC = usermode ? 1 : cpuXC->readPC();
        ProfileNode *node = cpuXC->profile->consume(xcProxy, inst);
        if (node)
            cpuXC->profileNode = node;
    }
#endif

    if (curStaticInst->isMemRef()) {
        numMemRefs++;
    }

    if (curStaticInst->isLoad()) {
        ++numLoad;
        comLoadEventQueue[0]->serviceEvents(numLoad);
    }

    traceFunctions(cpuXC->readPC());

    if (traceData) {
        traceData->finalize();
    }
}

void
BaseSimpleCPU::advancePC(Fault fault)
{
    if (fault != NoFault) {
#if FULL_SYSTEM
        fault->invoke(xcProxy);
#else // !FULL_SYSTEM
        fatal("fault (%s) detected @ PC %08p", fault->name(), cpuXC->readPC());
#endif // FULL_SYSTEM
    }
    else {
        // go to the next instruction
        cpuXC->setPC(cpuXC->readNextPC());
#if THE_ISA == ALPHA_ISA
        cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst));
#else
        cpuXC->setNextPC(cpuXC->readNextNPC());
        cpuXC->setNextNPC(cpuXC->readNextNPC() + sizeof(MachInst));
#endif

    }

#if FULL_SYSTEM
    Addr oldpc;
    do {
        oldpc = cpuXC->readPC();
        system->pcEventQueue.service(xcProxy);
    } while (oldpc != cpuXC->readPC());
#endif
}

<|endoftext|>


<commit_before>/*

Copyright (c) 2009-2014, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/bandwidth_manager.hpp"
#include "libtorrent/time.hpp"

namespace libtorrent
{

	bandwidth_manager::bandwidth_manager(int channel
#ifdef TORRENT_VERBOSE_BANDWIDTH_LIMIT
		, bool log
#endif
		)
		: m_queued_bytes(0)
		, m_channel(channel)
		, m_abort(false)
	{
#ifdef TORRENT_VERBOSE_BANDWIDTH_LIMIT
		if (log)
			m_log.open("bandwidth_limiter.log", std::ios::trunc);
		m_start = time_now();
#endif
	}

	void bandwidth_manager::close()
	{
		m_abort = true;
		m_queue.clear();
		m_queued_bytes = 0;
	}

#if TORRENT_USE_ASSERTS
	bool bandwidth_manager::is_queued(bandwidth_socket const* peer) const
	{
		for (queue_t::const_iterator i = m_queue.begin()
			, end(m_queue.end()); i != end; ++i)
		{
			if (i->peer.get() == peer) return true;
		}
		return false;
	}
#endif

	int bandwidth_manager::queue_size() const
	{
		return m_queue.size();
	}

	int bandwidth_manager::queued_bytes() const
	{
		return m_queued_bytes;
	}

	// non prioritized means that, if there's a line for bandwidth,
	// others will cut in front of the non-prioritized peers.
	// this is used by web seeds
	int bandwidth_manager::request_bandwidth(boost::intrusive_ptr<bandwidth_socket> const& peer
		, int blk, int priority
		, bandwidth_channel* chan1
		, bandwidth_channel* chan2
		, bandwidth_channel* chan3
		, bandwidth_channel* chan4
		, bandwidth_channel* chan5
		)
	{
		INVARIANT_CHECK;
		if (m_abort) return 0;

		TORRENT_ASSERT(blk > 0);
		TORRENT_ASSERT(priority > 0);
		TORRENT_ASSERT(!is_queued(peer.get()));

		bw_request bwr(peer, blk, priority);
		int i = 0;
		if (chan1 && chan1->throttle() > 0 && chan1->need_queueing(blk))
			bwr.channel[i++] = chan1;
		if (chan2 && chan2->throttle() > 0 && chan2->need_queueing(blk))
			bwr.channel[i++] = chan2;
		if (chan3 && chan3->throttle() > 0 && chan3->need_queueing(blk))
			bwr.channel[i++] = chan3;
		if (chan4 && chan4->throttle() > 0 && chan4->need_queueing(blk))
			bwr.channel[i++] = chan4;
		if (chan5 && chan5->throttle() > 0 && chan5->need_queueing(blk))
			bwr.channel[i++] = chan5;

		if (i == 0)
		{
			// the connection is not rate limited by any of its
			// bandwidth channels, or it doesn't belong to any
			// channels. There's no point in adding it to
			// the queue, just satisfy the request immediately
			return blk;
		}

		m_queued_bytes += blk;
		m_queue.push_back(bwr);
		return 0;
	}

#if TORRENT_USE_INVARIANT_CHECKS
	void bandwidth_manager::check_invariant() const
	{
		boost::int64_t queued = 0;
		for (queue_t::const_iterator i = m_queue.begin()
			, end(m_queue.end()); i != end; ++i)
		{
			queued += i->request_size - i->assigned;
		}
		TORRENT_ASSERT(queued == m_queued_bytes);
	}
#endif

	void bandwidth_manager::update_quotas(time_duration const& dt)
	{
		if (m_abort) return;
		if (m_queue.empty()) return;

		INVARIANT_CHECK;

		int dt_milliseconds = total_milliseconds(dt);
		if (dt_milliseconds > 3000) dt_milliseconds = 3000;

		// for each bandwidth channel, call update_quota(dt)

		std::vector<bandwidth_channel*> channels;

		queue_t tm;

		for (queue_t::iterator i = m_queue.begin();
			i != m_queue.end();)
		{
			if (i->peer->is_disconnecting())
			{
				m_queued_bytes -= i->request_size - i->assigned;

				// return all assigned quota to all the
				// bandwidth channels this peer belongs to
				for (int j = 0; j < bw_request::max_bandwidth_channels && i->channel[j]; ++j)
				{
					bandwidth_channel* bwc = i->channel[j];
					bwc->return_quota(i->assigned);
				}

				i->assigned = 0;
				tm.push_back(*i);
				i = m_queue.erase(i);
				continue;
			}
			for (int j = 0; j < bw_request::max_bandwidth_channels && i->channel[j]; ++j)
			{
				bandwidth_channel* bwc = i->channel[j];
				bwc->tmp = 0;
			}
			++i;
		}

		for (queue_t::iterator i = m_queue.begin()
			, end(m_queue.end()); i != end; ++i)
		{
			for (int j = 0; j < bw_request::max_bandwidth_channels && i->channel[j]; ++j)
			{
				bandwidth_channel* bwc = i->channel[j];
				if (bwc->tmp == 0) channels.push_back(bwc);
				TORRENT_ASSERT(INT_MAX - bwc->tmp > i->priority);
				bwc->tmp += i->priority;
			}
		}

		for (std::vector<bandwidth_channel*>::iterator i = channels.begin()
			, end(channels.end()); i != end; ++i)
		{
			(*i)->update_quota(dt_milliseconds);
		}

		for (queue_t::iterator i = m_queue.begin();
			i != m_queue.end();)
		{
			int a = i->assign_bandwidth();
			if (i->assigned == i->request_size
				|| (i->ttl <= 0 && i->assigned > 0))
			{
				a += i->request_size - i->assigned;
				TORRENT_ASSERT(i->assigned <= i->request_size);
				tm.push_back(*i);
				i = m_queue.erase(i);
			}
			else
			{
				++i;
			}
			m_queued_bytes -= a;
		}

		while (!tm.empty())
		{
			bw_request& bwr = tm.back();
			bwr.peer->assign_bandwidth(m_channel, bwr.assigned);
			tm.pop_back();
		}
	}
}

<commit_msg>back-port shutdown assert fix<commit_after>/*

Copyright (c) 2009-2014, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/bandwidth_manager.hpp"
#include "libtorrent/time.hpp"

namespace libtorrent
{

	bandwidth_manager::bandwidth_manager(int channel
#ifdef TORRENT_VERBOSE_BANDWIDTH_LIMIT
		, bool log
#endif
		)
		: m_queued_bytes(0)
		, m_channel(channel)
		, m_abort(false)
	{
#ifdef TORRENT_VERBOSE_BANDWIDTH_LIMIT
		if (log)
			m_log.open("bandwidth_limiter.log", std::ios::trunc);
		m_start = time_now();
#endif
	}

	void bandwidth_manager::close()
	{
		m_abort = true;

		queue_t tm;
		tm.swap(m_queue);
		m_queued_bytes = 0;

		while (!tm.empty())
		{
			bw_request& bwr = tm.back();
			bwr.peer->assign_bandwidth(m_channel, bwr.assigned);
			tm.pop_back();
		}
	}

#if TORRENT_USE_ASSERTS
	bool bandwidth_manager::is_queued(bandwidth_socket const* peer) const
	{
		for (queue_t::const_iterator i = m_queue.begin()
			, end(m_queue.end()); i != end; ++i)
		{
			if (i->peer.get() == peer) return true;
		}
		return false;
	}
#endif

	int bandwidth_manager::queue_size() const
	{
		return m_queue.size();
	}

	int bandwidth_manager::queued_bytes() const
	{
		return m_queued_bytes;
	}

	// non prioritized means that, if there's a line for bandwidth,
	// others will cut in front of the non-prioritized peers.
	// this is used by web seeds
	int bandwidth_manager::request_bandwidth(boost::intrusive_ptr<bandwidth_socket> const& peer
		, int blk, int priority
		, bandwidth_channel* chan1
		, bandwidth_channel* chan2
		, bandwidth_channel* chan3
		, bandwidth_channel* chan4
		, bandwidth_channel* chan5
		)
	{
		INVARIANT_CHECK;
		if (m_abort) return 0;

		TORRENT_ASSERT(blk > 0);
		TORRENT_ASSERT(priority > 0);
		TORRENT_ASSERT(!is_queued(peer.get()));

		bw_request bwr(peer, blk, priority);
		int i = 0;
		if (chan1 && chan1->throttle() > 0 && chan1->need_queueing(blk))
			bwr.channel[i++] = chan1;
		if (chan2 && chan2->throttle() > 0 && chan2->need_queueing(blk))
			bwr.channel[i++] = chan2;
		if (chan3 && chan3->throttle() > 0 && chan3->need_queueing(blk))
			bwr.channel[i++] = chan3;
		if (chan4 && chan4->throttle() > 0 && chan4->need_queueing(blk))
			bwr.channel[i++] = chan4;
		if (chan5 && chan5->throttle() > 0 && chan5->need_queueing(blk))
			bwr.channel[i++] = chan5;

		if (i == 0)
		{
			// the connection is not rate limited by any of its
			// bandwidth channels, or it doesn't belong to any
			// channels. There's no point in adding it to
			// the queue, just satisfy the request immediately
			return blk;
		}

		m_queued_bytes += blk;
		m_queue.push_back(bwr);
		return 0;
	}

#if TORRENT_USE_INVARIANT_CHECKS
	void bandwidth_manager::check_invariant() const
	{
		boost::int64_t queued = 0;
		for (queue_t::const_iterator i = m_queue.begin()
			, end(m_queue.end()); i != end; ++i)
		{
			queued += i->request_size - i->assigned;
		}
		TORRENT_ASSERT(queued == m_queued_bytes);
	}
#endif

	void bandwidth_manager::update_quotas(time_duration const& dt)
	{
		if (m_abort) return;
		if (m_queue.empty()) return;

		INVARIANT_CHECK;

		int dt_milliseconds = total_milliseconds(dt);
		if (dt_milliseconds > 3000) dt_milliseconds = 3000;

		// for each bandwidth channel, call update_quota(dt)

		std::vector<bandwidth_channel*> channels;

		queue_t tm;

		for (queue_t::iterator i = m_queue.begin();
			i != m_queue.end();)
		{
			if (i->peer->is_disconnecting())
			{
				m_queued_bytes -= i->request_size - i->assigned;

				// return all assigned quota to all the
				// bandwidth channels this peer belongs to
				for (int j = 0; j < bw_request::max_bandwidth_channels && i->channel[j]; ++j)
				{
					bandwidth_channel* bwc = i->channel[j];
					bwc->return_quota(i->assigned);
				}

				i->assigned = 0;
				tm.push_back(*i);
				i = m_queue.erase(i);
				continue;
			}
			for (int j = 0; j < bw_request::max_bandwidth_channels && i->channel[j]; ++j)
			{
				bandwidth_channel* bwc = i->channel[j];
				bwc->tmp = 0;
			}
			++i;
		}

		for (queue_t::iterator i = m_queue.begin()
			, end(m_queue.end()); i != end; ++i)
		{
			for (int j = 0; j < bw_request::max_bandwidth_channels && i->channel[j]; ++j)
			{
				bandwidth_channel* bwc = i->channel[j];
				if (bwc->tmp == 0) channels.push_back(bwc);
				TORRENT_ASSERT(INT_MAX - bwc->tmp > i->priority);
				bwc->tmp += i->priority;
			}
		}

		for (std::vector<bandwidth_channel*>::iterator i = channels.begin()
			, end(channels.end()); i != end; ++i)
		{
			(*i)->update_quota(dt_milliseconds);
		}

		for (queue_t::iterator i = m_queue.begin();
			i != m_queue.end();)
		{
			int a = i->assign_bandwidth();
			if (i->assigned == i->request_size
				|| (i->ttl <= 0 && i->assigned > 0))
			{
				a += i->request_size - i->assigned;
				TORRENT_ASSERT(i->assigned <= i->request_size);
				tm.push_back(*i);
				i = m_queue.erase(i);
			}
			else
			{
				++i;
			}
			m_queued_bytes -= a;
		}

		while (!tm.empty())
		{
			bw_request& bwr = tm.back();
			bwr.peer->assign_bandwidth(m_channel, bwr.assigned);
			tm.pop_back();
		}
	}
}

<|endoftext|>


<commit_before>
/***************************************************************************
                   jabberregister.cpp  -  Register dialog for Jabber
                             -------------------
    begin                : Sun Jul 11 2004
    copyright            : (C) 2004 by Till Gerken <till@tantalo.net>

		Kopete (C) 2001-2004 Kopete developers <kopete-devel@kde.org>
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "jabberregisteraccount.h"

#include <kdebug.h>
#include <klocale.h>
#include <kiconloader.h>
#include <kglobal.h>
#include <kmessagebox.h>
#include <klineedit.h>
#include <kpassdlg.h>
#include <knuminput.h>
#include <kpushbutton.h>
#include <qlabel.h>
#include <qcheckbox.h>
#include <qtimer.h>
#include <qregexp.h>

#include "qca.h"
#include "xmpp.h"
#include "xmpp_tasks.h"

#include "kopeteuiglobal.h"
#include "kopetepasswordwidget.h"
#include "jabberprotocol.h"
#include "jabberaccount.h"
#include "jabberclient.h"
#include "jabberconnector.h"
#include "jabbereditaccountwidget.h"
#include "jabberchooseserver.h"
#include "dlgjabberregisteraccount.h"

JabberRegisterAccount::JabberRegisterAccount ( JabberEditAccountWidget *parent, const char *name )
 : KDialogBase ( parent, name, true, i18n("Register New Jabber Account"),
 				 KDialogBase::Ok | KDialogBase::Cancel )
{

	mParentWidget = parent;

	// setup main dialog
	mMainWidget = new DlgJabberRegisterAccount ( this );
	setMainWidget ( mMainWidget );

	// replace "Ok" button with a "Register" button
	KGuiItem registerButton = KStdGuiItem::ok();
	registerButton.setText ( i18n ( "Register" ) );
	setButtonOK ( registerButton );

	enableButtonSeparator ( true );

	// clear variables
	jabberClient = new JabberClient ();

	connect ( jabberClient, SIGNAL ( csError ( int ) ), this, SLOT ( slotCSError ( int ) ) );
	connect ( jabberClient, SIGNAL ( tlsWarning ( int ) ), this, SLOT ( slotHandleTLSWarning ( int ) ) );
	connect ( jabberClient, SIGNAL ( connected () ), this, SLOT ( slotConnected () ) );

	jidRegExp.setPattern ( "[\\w\\d.+_-]{1,}@[\\w\\d.-]{1,}" );
	hintPixmap = KGlobal::iconLoader()->loadIcon ( "jabber_online", KIcon::Small );

	mSuccess = false;

	// get all settings from the main dialog
	mMainWidget->leServer->setText ( parent->mServer->text () );
	mMainWidget->leJID->setText ( parent->mID->text () );
	mMainWidget->lePassword->setText ( parent->mPass->password () );
	mMainWidget->lePasswordVerify->setText ( parent->mPass->password () );
	mMainWidget->sbPort->setValue ( parent->mPort->value () );
	mMainWidget->cbUseSSL->setChecked ( parent->cbUseSSL->isChecked () );

	// connect buttons to slots, ok is already connected by default
	connect ( this, SIGNAL ( cancelClicked () ), this, SLOT ( slotDeleteDialog () ) );
	connect ( mMainWidget->btnChooseServer, SIGNAL ( clicked () ), this, SLOT ( slotChooseServer () ) );
	connect ( mMainWidget->leServer, SIGNAL ( textChanged ( const QString & ) ), this, SLOT ( slotJIDInformation () ) );
	connect ( mMainWidget->leJID, SIGNAL ( textChanged ( const QString & ) ), this, SLOT ( slotJIDInformation () ) );
	connect ( mMainWidget->cbUseSSL, SIGNAL ( toggled ( bool ) ), this, SLOT ( slotSSLToggled () ) );

	connect ( mMainWidget->leServer, SIGNAL ( textChanged ( const QString & ) ), this, SLOT ( validateData () ) );
	connect ( mMainWidget->leJID, SIGNAL ( textChanged ( const QString & ) ), this, SLOT ( validateData () ) );
	connect ( mMainWidget->lePassword, SIGNAL ( textChanged ( const QString & ) ), this, SLOT ( validateData () ) );
	connect ( mMainWidget->lePasswordVerify, SIGNAL ( textChanged ( const QString & ) ), this, SLOT ( validateData () ) );

	// display JID info now
	slotJIDInformation ();

	// display validation info
	validateData ();
}

JabberRegisterAccount::~JabberRegisterAccount()
{
	delete jabberClient;
}

void JabberRegisterAccount::slotDeleteDialog ()
{

	deleteLater ();

}

void JabberRegisterAccount::validateData ()
{

	int valid = true;
	int passwordHighlight = false;

	if ( mMainWidget->leServer->text().isEmpty () )
	{
		mMainWidget->lblStatusMessage->setText ( i18n ( "Please enter a server name, or click Choose." ) );
		mMainWidget->pixServer->setPixmap ( hintPixmap );
		valid = false;
	}
	else
	{
		mMainWidget->pixServer->setText ( "" );
	}

	if ( valid && !jidRegExp.exactMatch ( mMainWidget->leJID->text() ) )
	{
		mMainWidget->lblStatusMessage->setText ( i18n ( "Please enter a valid Jabber ID." ) );
		mMainWidget->pixJID->setPixmap ( hintPixmap );
		valid = false;
	}
	else
	{
		mMainWidget->pixJID->setText ( "" );
	}

	if ( valid &&
	   ( QString::fromLatin1 ( mMainWidget->lePassword->password () ).isEmpty () ||
	     QString::fromLatin1 ( mMainWidget->lePasswordVerify->password () ).isEmpty () ) )
	{
		mMainWidget->lblStatusMessage->setText ( i18n ( "Please enter the same password twice." ) );
		valid = false;
		passwordHighlight = true;
	}

	if ( valid &&
	   ( QString::fromLatin1 ( mMainWidget->lePassword->password () ) !=
	     QString::fromLatin1 ( mMainWidget->lePasswordVerify->password () ) ) )
	{
		mMainWidget->lblStatusMessage->setText ( i18n ( "Password entries do not match." ) );
		valid = false;
		passwordHighlight = true;
	}

	if ( passwordHighlight == true )
	{
		mMainWidget->pixPassword->setPixmap ( hintPixmap );
		mMainWidget->pixPasswordVerify->setPixmap ( hintPixmap );
	}
	else {
		mMainWidget->pixPassword->setText ( "" );
		mMainWidget->pixPasswordVerify->setText ( "" );
	}

	if ( valid )
	{
		// clear status message if we have valid data
		mMainWidget->lblStatusMessage->setText ( "" );
	}

	enableButtonOK ( valid );

}

void JabberRegisterAccount::slotJIDInformation ()
{

	if ( !mMainWidget->leServer->text().isEmpty () &&
		 ( !jidRegExp.exactMatch ( mMainWidget->leJID->text () ) ||
		 ( mMainWidget->leJID->text().section ( "@", 1 ) != mMainWidget->leServer->text () ) ) )
	{
		mMainWidget->lblJIDInformation->setText ( i18n ( "Unless you know what you are doing, your JID should be of the form "
														 "\"username@server.com\".  In your case for example \"username@%1\"." ).
													arg ( mMainWidget->leServer->text () ) );
	}
	else
	{
		mMainWidget->lblJIDInformation->setText ( "" );
	}

}

void JabberRegisterAccount::slotSSLToggled ()
{

	if ( mMainWidget->cbUseSSL->isChecked () )
	{
		if ( mMainWidget->sbPort->value () == 5222 )
		{
			mMainWidget->sbPort->setValue ( 5223 );
		}
	}
	else
	{
		if ( mMainWidget->sbPort->value () == 5223 )
		{
			mMainWidget->sbPort->setValue ( 5222 );
		}
	}

}

void JabberRegisterAccount::slotChooseServer ()
{

	(new JabberChooseServer ( this ))->show ();

}

void JabberRegisterAccount::setServer ( const QString &server )
{

	mMainWidget->leServer->setText ( server );
	mMainWidget->leJID->setText ( QString ( "@%1" ).arg ( server ) );

}

void JabberRegisterAccount::slotOk ()
{

	mMainWidget->lblStatusMessage->setText ( "" );

	kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Registering a new Jabber account." << endl;

	enableButtonOK ( false );

	mMainWidget->lblStatusMessage->setText ( i18n ( "Connecting to server..." ) );

	// cancel any previous attempt
	jabberClient->disconnect ();

	// FIXME: we need to use the old protocol for now
	jabberClient->setUseXMPP09 ( true );

	jabberClient->setUseSSL ( mMainWidget->cbUseSSL->isChecked () );

	// FIXME: check this when using the new protocol
	jabberClient->setOverrideHost ( true, mMainWidget->leServer->text (), mMainWidget->sbPort->value () );

	// start connection, no authentication
	switch ( jabberClient->connect ( XMPP::Jid ( mMainWidget->leJID->text () ), QString::null, false ) )
	{
		case JabberClient::NoTLS:
			// no SSL support, at the connecting stage this means the problem is client-side
			KMessageBox::queuedMessageBox(Kopete::UI::Global::mainWidget (), KMessageBox::Error,
								i18n ("SSL support could not be initialized for account %1. This is most likely because the QCA TLS plugin is not installed on your system.").
								arg ( mMainWidget->leJID->text () ),
								i18n ("Jabber SSL Error"));
			break;

		case JabberClient::Ok:
		default:
			// everything alright!
			break;
	}

}

void JabberRegisterAccount::disconnect ()
{

	if(jabberClient)
		jabberClient->disconnect ();

	if ( !mSuccess )
		enableButtonOK ( true );

}

void JabberRegisterAccount::slotHandleTLSWarning ( int validityResult )
{
	kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Handling TLS warning..." << endl;

	if ( JabberAccount::handleTLSWarning ( jabberClient, validityResult ) )
	{
		// resume stream
		jabberClient->continueAfterTLSWarning ();
	}
	else
	{
		// disconnect stream
		disconnect ();
	}

}

void JabberRegisterAccount::slotCSError (int error)
{
	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Error in stream signalled, disconnecting." << endl;

	Kopete::Account::DisconnectReason errorClass;

	mMainWidget->lblStatusMessage->setText ( i18n ( "Protocol error." ) );

	// display message to user
	JabberAccount::handleStreamError (error, jabberClient->clientStream()->errorCondition (), jabberClient->clientConnector()->errorCode (), mMainWidget->leServer->text (), errorClass);

	disconnect ();

}

void JabberRegisterAccount::slotConnected ()
{
	kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << "Launching registration task..." << endl;

	mMainWidget->lblStatusMessage->setText ( i18n ( "Connected successfully, registering new account..." ) );

	XMPP::JT_Register * task = new XMPP::JT_Register (jabberClient->rootTask ());
	QObject::connect (task, SIGNAL (finished ()), this, SLOT (slotRegisterUserDone ()));
	task->reg (mMainWidget->leJID->text().section("@", 0, 0), mMainWidget->lePassword->password ());
	task->go (true);

}

void JabberRegisterAccount::slotRegisterUserDone ()
{
	XMPP::JT_Register * task = (XMPP::JT_Register *) sender ();

	if (task->success ())
	{
		mMainWidget->lblStatusMessage->setText ( i18n ( "Registration successful." ) );

		// save settings to parent
		mParentWidget->mServer->setText ( mMainWidget->leServer->text () );
		mParentWidget->mID->setText ( mMainWidget->leJID->text () );
		mParentWidget->mPass->setPassword ( mMainWidget->lePassword->password () );
		mParentWidget->mPort->setValue ( mMainWidget->sbPort->value () );
		mParentWidget->cbUseSSL->setChecked ( mMainWidget->cbUseSSL->isChecked () );

		// disable input widgets
		mMainWidget->btnChooseServer->setEnabled ( false );
		mMainWidget->leServer->setEnabled ( false );
		mMainWidget->leJID->setEnabled ( false );
		mMainWidget->lePassword->setEnabled ( false );
		mMainWidget->lePasswordVerify->setEnabled ( false );
		mMainWidget->sbPort->setEnabled ( false );
		mMainWidget->cbUseSSL->setEnabled ( false );

		// disable input widget labels
		mMainWidget->lblServer->setEnabled ( false );
		mMainWidget->lblJID->setEnabled ( false );
		mMainWidget->lblPassword->setEnabled ( false );
		mMainWidget->lblPasswordVerify->setEnabled ( false );
		mMainWidget->lblPort->setEnabled ( false );

		mSuccess = true;

		// rewire buttons
		enableButtonOK ( false );
		setButtonCancel ( KStdGuiItem::close () );
		connect ( this, SIGNAL ( closeClicked () ), this, SLOT ( slotDeleteDialog () ) );
	}
	else
	{
		mMainWidget->lblStatusMessage->setText ( i18n ( "Registration failed." ) );
		KMessageBox::queuedMessageBox (Kopete::UI::Global::mainWidget (), KMessageBox::Information,
								  i18n ("Unable to create account on the server. The Jabber ID is probably already in use."),
								  i18n ("Jabber Account Registration"));

	}

	// FIXME: this is required because Iris crashes if we try
	//        to disconnect here. Hopefully Justin can fix this.
	QTimer::singleShot(0, this, SLOT(disconnect ()));

}

#include "jabberregisteraccount.moc"
<commit_msg>backport fix for Bug 114631: Strange value in password field when registering a jabber account<commit_after>
/***************************************************************************
                   jabberregister.cpp  -  Register dialog for Jabber
                             -------------------
    begin                : Sun Jul 11 2004
    copyright            : (C) 2004 by Till Gerken <till@tantalo.net>

		Kopete (C) 2001-2004 Kopete developers <kopete-devel@kde.org>
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "jabberregisteraccount.h"

#include <kdebug.h>
#include <klocale.h>
#include <kiconloader.h>
#include <kglobal.h>
#include <kmessagebox.h>
#include <klineedit.h>
#include <kpassdlg.h>
#include <knuminput.h>
#include <kpushbutton.h>
#include <qlabel.h>
#include <qcheckbox.h>
#include <qtimer.h>
#include <qregexp.h>

#include "qca.h"
#include "xmpp.h"
#include "xmpp_tasks.h"

#include "kopeteuiglobal.h"
#include "kopetepasswordwidget.h"
#include "jabberprotocol.h"
#include "jabberaccount.h"
#include "jabberclient.h"
#include "jabberconnector.h"
#include "jabbereditaccountwidget.h"
#include "jabberchooseserver.h"
#include "dlgjabberregisteraccount.h"

JabberRegisterAccount::JabberRegisterAccount ( JabberEditAccountWidget *parent, const char *name )
 : KDialogBase ( parent, name, true, i18n("Register New Jabber Account"),
 				 KDialogBase::Ok | KDialogBase::Cancel )
{

	mParentWidget = parent;

	// setup main dialog
	mMainWidget = new DlgJabberRegisterAccount ( this );
	setMainWidget ( mMainWidget );

	// replace "Ok" button with a "Register" button
	KGuiItem registerButton = KStdGuiItem::ok();
	registerButton.setText ( i18n ( "Register" ) );
	setButtonOK ( registerButton );

	enableButtonSeparator ( true );

	// clear variables
	jabberClient = new JabberClient ();

	connect ( jabberClient, SIGNAL ( csError ( int ) ), this, SLOT ( slotCSError ( int ) ) );
	connect ( jabberClient, SIGNAL ( tlsWarning ( int ) ), this, SLOT ( slotHandleTLSWarning ( int ) ) );
	connect ( jabberClient, SIGNAL ( connected () ), this, SLOT ( slotConnected () ) );

	jidRegExp.setPattern ( "[\\w\\d.+_-]{1,}@[\\w\\d.-]{1,}" );
	hintPixmap = KGlobal::iconLoader()->loadIcon ( "jabber_online", KIcon::Small );

	mSuccess = false;

	// get all settings from the main dialog
	mMainWidget->leServer->setText ( parent->mServer->text () );
	mMainWidget->leJID->setText ( parent->mID->text () );
	mMainWidget->lePassword->setText ( parent->mPass->password () );
	//	mMainWidget->lePasswordVerify->setText ( parent->mPass->password () ); //BUG 14631
	mMainWidget->sbPort->setValue ( parent->mPort->value () );
	mMainWidget->cbUseSSL->setChecked ( parent->cbUseSSL->isChecked () );

	// connect buttons to slots, ok is already connected by default
	connect ( this, SIGNAL ( cancelClicked () ), this, SLOT ( slotDeleteDialog () ) );
	connect ( mMainWidget->btnChooseServer, SIGNAL ( clicked () ), this, SLOT ( slotChooseServer () ) );
	connect ( mMainWidget->leServer, SIGNAL ( textChanged ( const QString & ) ), this, SLOT ( slotJIDInformation () ) );
	connect ( mMainWidget->leJID, SIGNAL ( textChanged ( const QString & ) ), this, SLOT ( slotJIDInformation () ) );
	connect ( mMainWidget->cbUseSSL, SIGNAL ( toggled ( bool ) ), this, SLOT ( slotSSLToggled () ) );

	connect ( mMainWidget->leServer, SIGNAL ( textChanged ( const QString & ) ), this, SLOT ( validateData () ) );
	connect ( mMainWidget->leJID, SIGNAL ( textChanged ( const QString & ) ), this, SLOT ( validateData () ) );
	connect ( mMainWidget->lePassword, SIGNAL ( textChanged ( const QString & ) ), this, SLOT ( validateData () ) );
	connect ( mMainWidget->lePasswordVerify, SIGNAL ( textChanged ( const QString & ) ), this, SLOT ( validateData () ) );

	// display JID info now
	slotJIDInformation ();

	// display validation info
	validateData ();
}

JabberRegisterAccount::~JabberRegisterAccount()
{
	delete jabberClient;
}

void JabberRegisterAccount::slotDeleteDialog ()
{

	deleteLater ();

}

void JabberRegisterAccount::validateData ()
{

	int valid = true;
	int passwordHighlight = false;

	if ( mMainWidget->leServer->text().isEmpty () )
	{
		mMainWidget->lblStatusMessage->setText ( i18n ( "Please enter a server name, or click Choose." ) );
		mMainWidget->pixServer->setPixmap ( hintPixmap );
		valid = false;
	}
	else
	{
		mMainWidget->pixServer->setText ( "" );
	}

	if ( valid && !jidRegExp.exactMatch ( mMainWidget->leJID->text() ) )
	{
		mMainWidget->lblStatusMessage->setText ( i18n ( "Please enter a valid Jabber ID." ) );
		mMainWidget->pixJID->setPixmap ( hintPixmap );
		valid = false;
	}
	else
	{
		mMainWidget->pixJID->setText ( "" );
	}

	if ( valid &&
	   ( QString::fromLatin1 ( mMainWidget->lePassword->password () ).isEmpty () ||
	     QString::fromLatin1 ( mMainWidget->lePasswordVerify->password () ).isEmpty () ) )
	{
		mMainWidget->lblStatusMessage->setText ( i18n ( "Please enter the same password twice." ) );
		valid = false;
		passwordHighlight = true;
	}

	if ( valid &&
	   ( QString::fromLatin1 ( mMainWidget->lePassword->password () ) !=
	     QString::fromLatin1 ( mMainWidget->lePasswordVerify->password () ) ) )
	{
		mMainWidget->lblStatusMessage->setText ( i18n ( "Password entries do not match." ) );
		valid = false;
		passwordHighlight = true;
	}

	if ( passwordHighlight == true )
	{
		mMainWidget->pixPassword->setPixmap ( hintPixmap );
		mMainWidget->pixPasswordVerify->setPixmap ( hintPixmap );
	}
	else {
		mMainWidget->pixPassword->setText ( "" );
		mMainWidget->pixPasswordVerify->setText ( "" );
	}

	if ( valid )
	{
		// clear status message if we have valid data
		mMainWidget->lblStatusMessage->setText ( "" );
	}

	enableButtonOK ( valid );

}

void JabberRegisterAccount::slotJIDInformation ()
{

	if ( !mMainWidget->leServer->text().isEmpty () &&
		 ( !jidRegExp.exactMatch ( mMainWidget->leJID->text () ) ||
		 ( mMainWidget->leJID->text().section ( "@", 1 ) != mMainWidget->leServer->text () ) ) )
	{
		mMainWidget->lblJIDInformation->setText ( i18n ( "Unless you know what you are doing, your JID should be of the form "
														 "\"username@server.com\".  In your case for example \"username@%1\"." ).
													arg ( mMainWidget->leServer->text () ) );
	}
	else
	{
		mMainWidget->lblJIDInformation->setText ( "" );
	}

}

void JabberRegisterAccount::slotSSLToggled ()
{

	if ( mMainWidget->cbUseSSL->isChecked () )
	{
		if ( mMainWidget->sbPort->value () == 5222 )
		{
			mMainWidget->sbPort->setValue ( 5223 );
		}
	}
	else
	{
		if ( mMainWidget->sbPort->value () == 5223 )
		{
			mMainWidget->sbPort->setValue ( 5222 );
		}
	}

}

void JabberRegisterAccount::slotChooseServer ()
{

	(new JabberChooseServer ( this ))->show ();

}

void JabberRegisterAccount::setServer ( const QString &server )
{

	mMainWidget->leServer->setText ( server );
	mMainWidget->leJID->setText ( QString ( "@%1" ).arg ( server ) );

}

void JabberRegisterAccount::slotOk ()
{

	mMainWidget->lblStatusMessage->setText ( "" );

	kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Registering a new Jabber account." << endl;

	enableButtonOK ( false );

	mMainWidget->lblStatusMessage->setText ( i18n ( "Connecting to server..." ) );

	// cancel any previous attempt
	jabberClient->disconnect ();

	// FIXME: we need to use the old protocol for now
	jabberClient->setUseXMPP09 ( true );

	jabberClient->setUseSSL ( mMainWidget->cbUseSSL->isChecked () );

	// FIXME: check this when using the new protocol
	jabberClient->setOverrideHost ( true, mMainWidget->leServer->text (), mMainWidget->sbPort->value () );

	// start connection, no authentication
	switch ( jabberClient->connect ( XMPP::Jid ( mMainWidget->leJID->text () ), QString::null, false ) )
	{
		case JabberClient::NoTLS:
			// no SSL support, at the connecting stage this means the problem is client-side
			KMessageBox::queuedMessageBox(Kopete::UI::Global::mainWidget (), KMessageBox::Error,
								i18n ("SSL support could not be initialized for account %1. This is most likely because the QCA TLS plugin is not installed on your system.").
								arg ( mMainWidget->leJID->text () ),
								i18n ("Jabber SSL Error"));
			break;

		case JabberClient::Ok:
		default:
			// everything alright!
			break;
	}

}

void JabberRegisterAccount::disconnect ()
{

	if(jabberClient)
		jabberClient->disconnect ();

	if ( !mSuccess )
		enableButtonOK ( true );

}

void JabberRegisterAccount::slotHandleTLSWarning ( int validityResult )
{
	kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Handling TLS warning..." << endl;

	if ( JabberAccount::handleTLSWarning ( jabberClient, validityResult ) )
	{
		// resume stream
		jabberClient->continueAfterTLSWarning ();
	}
	else
	{
		// disconnect stream
		disconnect ();
	}

}

void JabberRegisterAccount::slotCSError (int error)
{
	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Error in stream signalled, disconnecting." << endl;

	Kopete::Account::DisconnectReason errorClass;

	mMainWidget->lblStatusMessage->setText ( i18n ( "Protocol error." ) );

	// display message to user
	JabberAccount::handleStreamError (error, jabberClient->clientStream()->errorCondition (), jabberClient->clientConnector()->errorCode (), mMainWidget->leServer->text (), errorClass);

	disconnect ();

}

void JabberRegisterAccount::slotConnected ()
{
	kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << "Launching registration task..." << endl;

	mMainWidget->lblStatusMessage->setText ( i18n ( "Connected successfully, registering new account..." ) );

	XMPP::JT_Register * task = new XMPP::JT_Register (jabberClient->rootTask ());
	QObject::connect (task, SIGNAL (finished ()), this, SLOT (slotRegisterUserDone ()));
	task->reg (mMainWidget->leJID->text().section("@", 0, 0), mMainWidget->lePassword->password ());
	task->go (true);

}

void JabberRegisterAccount::slotRegisterUserDone ()
{
	XMPP::JT_Register * task = (XMPP::JT_Register *) sender ();

	if (task->success ())
	{
		mMainWidget->lblStatusMessage->setText ( i18n ( "Registration successful." ) );

		// save settings to parent
		mParentWidget->mServer->setText ( mMainWidget->leServer->text () );
		mParentWidget->mID->setText ( mMainWidget->leJID->text () );
		mParentWidget->mPass->setPassword ( mMainWidget->lePassword->password () );
		mParentWidget->mPort->setValue ( mMainWidget->sbPort->value () );
		mParentWidget->cbUseSSL->setChecked ( mMainWidget->cbUseSSL->isChecked () );

		// disable input widgets
		mMainWidget->btnChooseServer->setEnabled ( false );
		mMainWidget->leServer->setEnabled ( false );
		mMainWidget->leJID->setEnabled ( false );
		mMainWidget->lePassword->setEnabled ( false );
		mMainWidget->lePasswordVerify->setEnabled ( false );
		mMainWidget->sbPort->setEnabled ( false );
		mMainWidget->cbUseSSL->setEnabled ( false );

		// disable input widget labels
		mMainWidget->lblServer->setEnabled ( false );
		mMainWidget->lblJID->setEnabled ( false );
		mMainWidget->lblPassword->setEnabled ( false );
		mMainWidget->lblPasswordVerify->setEnabled ( false );
		mMainWidget->lblPort->setEnabled ( false );

		mSuccess = true;

		// rewire buttons
		enableButtonOK ( false );
		setButtonCancel ( KStdGuiItem::close () );
		connect ( this, SIGNAL ( closeClicked () ), this, SLOT ( slotDeleteDialog () ) );
	}
	else
	{
		mMainWidget->lblStatusMessage->setText ( i18n ( "Registration failed." ) );
		KMessageBox::queuedMessageBox (Kopete::UI::Global::mainWidget (), KMessageBox::Information,
								  i18n ("Unable to create account on the server. The Jabber ID is probably already in use."),
								  i18n ("Jabber Account Registration"));

	}

	// FIXME: this is required because Iris crashes if we try
	//        to disconnect here. Hopefully Justin can fix this.
	QTimer::singleShot(0, this, SLOT(disconnect ()));

}

#include "jabberregisteraccount.moc"
<|endoftext|>


<commit_before>/******************************************************************************
 * This file is part of the Gluon Development Platform
 * Copyright (c) 2011 Laszlo Papp <djszapi@archlinux.us>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "qgitrepository.h"
#include "qgitcommit.h"
#include "qgitconfig.h"
#include "qgittag.h"
#include "qgittree.h"
#include "qgitblob.h"
#include "qgitsignature.h"
#include "qgitexception.h"

#include <git2/errors.h>
#include <git2/repository.h>
#include <git2/refs.h>
#include <git2/commit.h>
#include <git2/tag.h>
#include <git2/tree.h>
#include <git2/blob.h>

#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QFileInfo>
#include <QtCore/QVector>
#include <QtCore/QStringList>

#include <QtDebug>
#include <functional>

namespace {
void do_not_free(git_repository*) {}
}

namespace LibQGit2
{

QGitRepository::QGitRepository(git_repository *repository, bool own)
    : d(repository, own ? git_repository_free : do_not_free)
{
}

QGitRepository::QGitRepository( const QGitRepository& other )
    : d(other.d)
{
}

QGitRepository::~QGitRepository()
{
}

QString QGitRepository::discover(const QString& startPath, bool acrossFs, const QStringList& ceilingDirs)
{
    QByteArray repoPath(GIT_PATH_MAX, Qt::Uninitialized);
    QByteArray joinedCeilingDirs = QFile::encodeName(ceilingDirs.join(QChar(GIT_PATH_LIST_SEPARATOR)));
    qGitThrow(git_repository_discover(repoPath.data(), repoPath.length(),
                                      QFile::encodeName(startPath),
                                      acrossFs, joinedCeilingDirs));
    return QFile::decodeName(repoPath);
}

void QGitRepository::init(const QString& path, bool isBare)
{
    d.clear();
    git_repository *repo = 0;
    qGitThrow(git_repository_init(&repo, QFile::encodeName(path), isBare));
    d = ptr_type(repo, git_repository_free);
}

void QGitRepository::open(const QString& path)
{
    d.clear();
    git_repository *repo = 0;
    qGitThrow(git_repository_open(&repo, QFile::encodeName(path)));
    d = ptr_type(repo, git_repository_free);
}

void QGitRepository::discoverAndOpen(const QString &startPath,
                                     bool acrossFs,
                                     const QStringList &ceilingDirs)
{
    open(discover(startPath, acrossFs, ceilingDirs));
}

QGitRef QGitRepository::head() const
{
    git_reference *ref = 0;
    qGitThrow(git_repository_head(&ref, data()));
    return QGitRef(ref);
}

bool QGitRepository::isHeadDetached() const
{
    return qGitThrow(git_repository_head_detached(data())) == 1;
}

bool QGitRepository::isHeadOrphan() const
{
    return qGitThrow(git_repository_head_orphan(data())) == 1;
}

bool QGitRepository::isEmpty() const
{
    return qGitThrow(git_repository_is_empty(data())) == 1;
}

bool QGitRepository::isBare() const
{
    return qGitThrow(git_repository_is_bare(data())) == 1;
}

QString QGitRepository::name() const
{
    QString repoPath = QDir::cleanPath( workDirPath() );
    if (isBare())
        repoPath = QDir::cleanPath( path() );

    return QFileInfo(repoPath).fileName();
}

QString QGitRepository::path() const
{
    return QFile::decodeName(git_repository_path(data()));
}

QString QGitRepository::workDirPath() const
{
    return QFile::decodeName(git_repository_workdir(data()));
}

QGitConfig QGitRepository::configuration() const
{
    git_config *cfg;
    qGitThrow( git_repository_config(&cfg, data()) );
    return QGitConfig(cfg);
}

QGitRef QGitRepository::lookupRef(const QString& name) const
{
    git_reference *ref = 0;
    qGitThrow(git_reference_lookup(&ref, data(), QFile::encodeName(name)));
    return QGitRef(ref);
}

QGitCommit QGitRepository::lookupCommit(const QGitOId& oid) const
{
    git_commit *commit = 0;
    qGitThrow(git_commit_lookup_prefix(&commit, data(), oid.constData(), oid.length()));
    return QGitCommit(commit);
}

QGitTag QGitRepository::lookupTag(const QGitOId& oid) const
{
    git_tag *tag = 0;
    qGitThrow(git_tag_lookup_prefix(&tag, data(), oid.constData(), oid.length()));
    return QGitTag(tag);
}

QGitTree QGitRepository::lookupTree(const QGitOId& oid) const
{
    git_tree *tree = 0;
    qGitThrow(git_tree_lookup_prefix(&tree, data(), oid.constData(), oid.length()));
    return QGitTree(tree);
}

QGitBlob QGitRepository::lookupBlob(const QGitOId& oid) const
{
    git_blob *blob = 0;
    qGitThrow(git_blob_lookup_prefix(&blob, data(), oid.constData(), oid.length()));
    return QGitBlob(blob);
}

QGitObject QGitRepository::lookupAny(const QGitOId &oid) const
{
    git_object *object = 0;
    qGitThrow(git_object_lookup_prefix(&object, data(), oid.constData(), oid.length(), GIT_OBJ_ANY));
    return QGitObject(object);
}

QGitRef QGitRepository::createRef(const QString& name, const QGitOId& oid, bool overwrite)
{
    git_reference *ref = 0;
    qGitThrow(git_reference_create(&ref, data(), QFile::encodeName(name), oid.constData(), overwrite));
    return QGitRef(ref);
}

QGitRef QGitRepository::createSymbolicRef(const QString& name, const QString& target, bool overwrite)
{
    git_reference *ref = 0;
    qGitThrow(git_reference_symbolic_create(&ref, data(), QFile::encodeName(name), QFile::encodeName(target), overwrite));
    return QGitRef(ref);
}

QGitOId QGitRepository::createCommit(const QString& ref,
                                     const QGitSignature& author,
                                     const QGitSignature& committer,
                                     const QString& message,
                                     const QGitTree& tree,
                                     const QList<QGitCommit>& parents)
{
    QVector<const git_commit*> p;
    foreach (const QGitCommit& parent, parents) {
        p.append(parent.data());
    }

    QGitOId oid;
    qGitThrow(git_commit_create(oid.data(), data(), QFile::encodeName(ref), author.data(), committer.data(),
                                NULL, message.toUtf8(), tree.data(), p.size(), p.data()));
    return oid;
}

QGitOId QGitRepository::createTag(const QString& name,
                                  const QGitObject& target,
                                  bool overwrite)
{
    QGitOId oid;
    qGitThrow(git_tag_create_lightweight(oid.data(), data(), QFile::encodeName(name),
                                         target.data(), overwrite));
    return oid;
}

QGitOId QGitRepository::createTag(const QString& name,
                                  const QGitObject& target,
                                  const QGitSignature& tagger,
                                  const QString& message,
                                  bool overwrite)
{
    QGitOId oid;
    qGitThrow(git_tag_create(oid.data(), data(), QFile::encodeName(name), target.data(),
                             tagger.data(), message.toUtf8(), overwrite));
    return oid;
}

void QGitRepository::deleteTag(const QString& name)
{
    qGitThrow(git_tag_delete(data(), QFile::encodeName(name)));
}

QGitOId QGitRepository::createBlobFromFile(const QString& path)
{
    QGitOId oid;
    qGitThrow(git_blob_create_fromworkdir(oid.data(), data(), QFile::encodeName(path)));
    return oid;
}

QGitOId QGitRepository::createBlobFromBuffer(const QByteArray& buffer)
{
    QGitOId oid;
    qGitThrow(git_blob_create_frombuffer(oid.data(), data(), buffer.data(), buffer.size()));
    return oid;
}

QStringList QGitRepository::listTags(const QString& pattern) const
{
    QStringList list;
    git_strarray tags;
    qGitThrow(git_tag_list_match(&tags, qPrintable(pattern), data()));
    for (size_t i = 0; i < tags.count; ++i)
    {
        list << QString(tags.strings[i]);
    }
    git_strarray_free(&tags);
    return list;
}

QStringList QGitRepository::listReferences() const
{
    QStringList list;
    git_strarray refs;
    qGitThrow(git_reference_list( &refs, data(), GIT_REF_LISTALL));
    for (size_t i = 0; i < refs.count; ++i)
    {
        list << QString(refs.strings[i]);
    }
    git_strarray_free(&refs);
    return list;
}

void QGitRepository::branches(const char *branch_name, git_branch_t branch_type)
{
    // Do something
    repoBranches.insert(branch_name, branch_type);
}

extern "C" int branchesCallBack(const char *branch_name, git_branch_t branch_type,
                                void *payload)
{
    reinterpret_cast<QGitRepository*> (payload)->branches(branch_name, branch_type);

    // we want to continue looping so return 0
    return 0;
}

QStringList QGitRepository::showAllBranches(branchType type) const
{
    QStringList list;

    qGitThrow(git_branch_foreach(data(), type, branchesCallBack,(void*)this));

    QMap<QString, git_branch_t>::const_iterator i = repoBranches.cbegin();
    while (i != repoBranches.constEnd())
    {
        list.append(i.key());
         ++i;
    }

    return list;
}

QGitDatabase QGitRepository::database() const
{
    git_odb *odb;
    qGitThrow( git_repository_odb(&odb, data()) );
    return QGitDatabase(odb);
}

QGitIndex QGitRepository::index() const
{
    git_index *idx;
    qGitThrow(git_repository_index(&idx, data()));
    return QGitIndex(idx);
}

git_repository* QGitRepository::data() const
{
    return d.data();
}

const git_repository* QGitRepository::constData() const
{
    return d.data();
}

} // namespace LibQGit2
<commit_msg>Allow opening repository within sub directory<commit_after>/******************************************************************************
 * This file is part of the Gluon Development Platform
 * Copyright (c) 2011 Laszlo Papp <djszapi@archlinux.us>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "qgitrepository.h"
#include "qgitcommit.h"
#include "qgitconfig.h"
#include "qgittag.h"
#include "qgittree.h"
#include "qgitblob.h"
#include "qgitsignature.h"
#include "qgitexception.h"

#include <git2/errors.h>
#include <git2/repository.h>
#include <git2/refs.h>
#include <git2/commit.h>
#include <git2/tag.h>
#include <git2/tree.h>
#include <git2/blob.h>

#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QFileInfo>
#include <QtCore/QVector>
#include <QtCore/QStringList>

#include <QtDebug>
#include <functional>

namespace {
void do_not_free(git_repository*) {}
}

namespace LibQGit2
{

QGitRepository::QGitRepository(git_repository *repository, bool own)
    : d(repository, own ? git_repository_free : do_not_free)
{
}

QGitRepository::QGitRepository( const QGitRepository& other )
    : d(other.d)
{
}

QGitRepository::~QGitRepository()
{
}

QString QGitRepository::discover(const QString& startPath, bool acrossFs, const QStringList& ceilingDirs)
{
    QByteArray repoPath(GIT_PATH_MAX, Qt::Uninitialized);
    QByteArray joinedCeilingDirs = QFile::encodeName(ceilingDirs.join(QChar(GIT_PATH_LIST_SEPARATOR)));
    qGitThrow(git_repository_discover(repoPath.data(), repoPath.length(),
                                      QFile::encodeName(startPath),
                                      acrossFs, joinedCeilingDirs));
    return QFile::decodeName(repoPath);
}

void QGitRepository::init(const QString& path, bool isBare)
{
    d.clear();
    git_repository *repo = 0;
    qGitThrow(git_repository_init(&repo, QFile::encodeName(path), isBare));
    d = ptr_type(repo, git_repository_free);
}

void QGitRepository::open(const QString& path)
{
    d.clear();
    git_repository *repo = 0;
    QDir folder(path);

    do
    {
        if (folder.entryList(QDir::AllDirs | QDir::Hidden).contains(".git"))
        {
            break;
        }
    }
    while (folder.cdUp());

    qGitThrow(git_repository_open(&repo, QFile::encodeName(folder.absolutePath())));
    d = ptr_type(repo, git_repository_free);
}

void QGitRepository::discoverAndOpen(const QString &startPath,
                                     bool acrossFs,
                                     const QStringList &ceilingDirs)
{
    open(discover(startPath, acrossFs, ceilingDirs));
}

QGitRef QGitRepository::head() const
{
    git_reference *ref = 0;
    qGitThrow(git_repository_head(&ref, data()));
    return QGitRef(ref);
}

bool QGitRepository::isHeadDetached() const
{
    return qGitThrow(git_repository_head_detached(data())) == 1;
}

bool QGitRepository::isHeadOrphan() const
{
    return qGitThrow(git_repository_head_orphan(data())) == 1;
}

bool QGitRepository::isEmpty() const
{
    return qGitThrow(git_repository_is_empty(data())) == 1;
}

bool QGitRepository::isBare() const
{
    return qGitThrow(git_repository_is_bare(data())) == 1;
}

QString QGitRepository::name() const
{
    QString repoPath = QDir::cleanPath( workDirPath() );
    if (isBare())
        repoPath = QDir::cleanPath( path() );

    return QFileInfo(repoPath).fileName();
}

QString QGitRepository::path() const
{
    return QFile::decodeName(git_repository_path(data()));
}

QString QGitRepository::workDirPath() const
{
    return QFile::decodeName(git_repository_workdir(data()));
}

QGitConfig QGitRepository::configuration() const
{
    git_config *cfg;
    qGitThrow( git_repository_config(&cfg, data()) );
    return QGitConfig(cfg);
}

QGitRef QGitRepository::lookupRef(const QString& name) const
{
    git_reference *ref = 0;
    qGitThrow(git_reference_lookup(&ref, data(), QFile::encodeName(name)));
    return QGitRef(ref);
}

QGitCommit QGitRepository::lookupCommit(const QGitOId& oid) const
{
    git_commit *commit = 0;
    qGitThrow(git_commit_lookup_prefix(&commit, data(), oid.constData(), oid.length()));
    return QGitCommit(commit);
}

QGitTag QGitRepository::lookupTag(const QGitOId& oid) const
{
    git_tag *tag = 0;
    qGitThrow(git_tag_lookup_prefix(&tag, data(), oid.constData(), oid.length()));
    return QGitTag(tag);
}

QGitTree QGitRepository::lookupTree(const QGitOId& oid) const
{
    git_tree *tree = 0;
    qGitThrow(git_tree_lookup_prefix(&tree, data(), oid.constData(), oid.length()));
    return QGitTree(tree);
}

QGitBlob QGitRepository::lookupBlob(const QGitOId& oid) const
{
    git_blob *blob = 0;
    qGitThrow(git_blob_lookup_prefix(&blob, data(), oid.constData(), oid.length()));
    return QGitBlob(blob);
}

QGitObject QGitRepository::lookupAny(const QGitOId &oid) const
{
    git_object *object = 0;
    qGitThrow(git_object_lookup_prefix(&object, data(), oid.constData(), oid.length(), GIT_OBJ_ANY));
    return QGitObject(object);
}

QGitRef QGitRepository::createRef(const QString& name, const QGitOId& oid, bool overwrite)
{
    git_reference *ref = 0;
    qGitThrow(git_reference_create(&ref, data(), QFile::encodeName(name), oid.constData(), overwrite));
    return QGitRef(ref);
}

QGitRef QGitRepository::createSymbolicRef(const QString& name, const QString& target, bool overwrite)
{
    git_reference *ref = 0;
    qGitThrow(git_reference_symbolic_create(&ref, data(), QFile::encodeName(name), QFile::encodeName(target), overwrite));
    return QGitRef(ref);
}

QGitOId QGitRepository::createCommit(const QString& ref,
                                     const QGitSignature& author,
                                     const QGitSignature& committer,
                                     const QString& message,
                                     const QGitTree& tree,
                                     const QList<QGitCommit>& parents)
{
    QVector<const git_commit*> p;
    foreach (const QGitCommit& parent, parents) {
        p.append(parent.data());
    }

    QGitOId oid;
    qGitThrow(git_commit_create(oid.data(), data(), QFile::encodeName(ref), author.data(), committer.data(),
                                NULL, message.toUtf8(), tree.data(), p.size(), p.data()));
    return oid;
}

QGitOId QGitRepository::createTag(const QString& name,
                                  const QGitObject& target,
                                  bool overwrite)
{
    QGitOId oid;
    qGitThrow(git_tag_create_lightweight(oid.data(), data(), QFile::encodeName(name),
                                         target.data(), overwrite));
    return oid;
}

QGitOId QGitRepository::createTag(const QString& name,
                                  const QGitObject& target,
                                  const QGitSignature& tagger,
                                  const QString& message,
                                  bool overwrite)
{
    QGitOId oid;
    qGitThrow(git_tag_create(oid.data(), data(), QFile::encodeName(name), target.data(),
                             tagger.data(), message.toUtf8(), overwrite));
    return oid;
}

void QGitRepository::deleteTag(const QString& name)
{
    qGitThrow(git_tag_delete(data(), QFile::encodeName(name)));
}

QGitOId QGitRepository::createBlobFromFile(const QString& path)
{
    QGitOId oid;
    qGitThrow(git_blob_create_fromworkdir(oid.data(), data(), QFile::encodeName(path)));
    return oid;
}

QGitOId QGitRepository::createBlobFromBuffer(const QByteArray& buffer)
{
    QGitOId oid;
    qGitThrow(git_blob_create_frombuffer(oid.data(), data(), buffer.data(), buffer.size()));
    return oid;
}

QStringList QGitRepository::listTags(const QString& pattern) const
{
    QStringList list;
    git_strarray tags;
    qGitThrow(git_tag_list_match(&tags, qPrintable(pattern), data()));
    for (size_t i = 0; i < tags.count; ++i)
    {
        list << QString(tags.strings[i]);
    }
    git_strarray_free(&tags);
    return list;
}

QStringList QGitRepository::listReferences() const
{
    QStringList list;
    git_strarray refs;
    qGitThrow(git_reference_list( &refs, data(), GIT_REF_LISTALL));
    for (size_t i = 0; i < refs.count; ++i)
    {
        list << QString(refs.strings[i]);
    }
    git_strarray_free(&refs);
    return list;
}

void QGitRepository::branches(const char *branch_name, git_branch_t branch_type)
{
    // Do something
    repoBranches.insert(branch_name, branch_type);
}

extern "C" int branchesCallBack(const char *branch_name, git_branch_t branch_type,
                                void *payload)
{
    reinterpret_cast<QGitRepository*> (payload)->branches(branch_name, branch_type);

    // we want to continue looping so return 0
    return 0;
}

QStringList QGitRepository::showAllBranches(branchType type) const
{
    QStringList list;

    qGitThrow(git_branch_foreach(data(), type, branchesCallBack,(void*)this));

    QMap<QString, git_branch_t>::const_iterator i = repoBranches.cbegin();
    while (i != repoBranches.constEnd())
    {
        list.append(i.key());
         ++i;
    }

    return list;
}

QGitDatabase QGitRepository::database() const
{
    git_odb *odb;
    qGitThrow( git_repository_odb(&odb, data()) );
    return QGitDatabase(odb);
}

QGitIndex QGitRepository::index() const
{
    git_index *idx;
    qGitThrow(git_repository_index(&idx, data()));
    return QGitIndex(idx);
}

git_repository* QGitRepository::data() const
{
    return d.data();
}

const git_repository* QGitRepository::constData() const
{
    return d.data();
}

} // namespace LibQGit2
<|endoftext|>


<commit_before>#include <map>

#include <llvm/IR/Value.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/DataLayout.h>
#include <llvm/Support/raw_ostream.h>

#include "AnalysisGeneric.h"
#include "LLVMDependenceGraph.h"
#include "PointsTo.h"

using namespace llvm;

namespace dg {
namespace analysis {

// we assume that if the program uses inttoptr, it access this
// memory only this way - so every access to this memory is done
// via some inttoptr. Here we store the inttoptr objects
static std::map<uint64_t, LLVMNode *> intToPtrMap;

// pointer points to unknown memory location
MemoryObj UnknownMemoryObject(nullptr);
// unknown pointer value
Pointer UnknownMemoryLocation(&UnknownMemoryObject, 0);

bool Pointer::isUnknown() const
{
    return this == &UnknownMemoryLocation;
}

bool Pointer::pointsToUnknown() const
{
    assert(obj && "Pointer has not any memory object set");
    return obj->isUnknown();
}

bool Pointer::isKnown() const
{
    return !isUnknown() && !pointsToUnknown();
}

bool MemoryObj::isUnknown() const
{
    return this == &UnknownMemoryObject;
}

static LLVMNode *createNodeWithMemAlloc(const Value *val)
{
    LLVMNode *n = new LLVMNode(val);
    MemoryObj *&mo = n->getMemoryObj();
    mo = new MemoryObj(n);
    n->addPointsTo(Pointer(mo));

    return n;
}

static LLVMNode *getOrCreateNode(LLVMDependenceGraph *dg, const Value *val)
{
    LLVMNode *n = dg->getNode(val);
    if (n)
        return n;

    if (llvm::isa<llvm::Function>(val)) {
        n = createNodeWithMemAlloc(val);
    } else
        errs() << "ERR: unhandled not to create " << *val << "\n";

    return n;
}

static Pointer handleConstantBitCast(LLVMDependenceGraph *dg, const BitCastInst *BC)
{
    if (!BC->isLosslessCast()) {
        errs() << "WARN: Not a loss less cast unhandled ConstExpr"
               << *BC << "\n";
        return UnknownMemoryLocation;
    }

    const Value *llvmOp = BC->stripPointerCasts();
    LLVMNode *op = getOrCreateNode(dg, llvmOp);
    if (!op) {
        errs() << "ERR: unsupported BitCast constant operand" << *BC << "\n";
    } else {
        PointsToSetT& ptset = op->getPointsTo();
        if (ptset.size() != 1) {
            errs() << "ERR: constant BitCast with not only one pointer "
                   << *BC << "\n";
        } else
            return *ptset.begin();
    }

    return UnknownMemoryLocation;
}

static inline unsigned getPointerBitwidth(const DataLayout *DL, const Value *ptr)
{
    const Type *Ty = ptr->getType();
    return DL->getPointerSizeInBits(Ty->getPointerAddressSpace());
}

static Pointer handleConstantGep(LLVMDependenceGraph *dg,
                                 const GetElementPtrInst *GEP,
                                 const llvm::DataLayout *DL)
{
    const Value *op = GEP->getPointerOperand();
    LLVMNode *opNode = dg->getNode(op);

    // FIXME this is sound, but may be unprecise
    //  - we should use getOperand for getting opNode,
    //  becaues we can have ConstantExpr inserted in ConstantExpr
    //  (getelementptr (inttoptr ..) ...), so we can get null here
    //  as opNode
    if (!opNode) {
        errs() << "No node for Constant GEP operand: " << *GEP << "\n";
        return UnknownMemoryLocation;
    }

    PointsToSetT& S = opNode->getPointsTo();
    // since this is constant expr, there's no way how we could
    // get extra points-to binding in runtime
    assert(S.size() == 1);
    MemoryObj *mo = (*S.begin()).obj;
    if (!mo) {
        errs() << "ERR: no memory object in " << *opNode->getKey() << "\n";
        return UnknownMemoryLocation;
    }

    Pointer pointer(mo, UNKNOWN_OFFSET);
    unsigned bitwidth = getPointerBitwidth(DL, op);
    APInt offset(bitwidth, 0);

    if (GEP->accumulateConstantOffset(*DL, offset)) {
        if (offset.isIntN(bitwidth))
            pointer.offset = offset.getZExtValue();
        else
            errs() << "WARN: Offset greater than "
                   << bitwidth << "-bit" << *GEP << "\n";
    }
    // else offset is set to UNKNOWN (in constructor)

    return pointer;
}

Pointer getConstantExprPointer(const ConstantExpr *CE,
                               LLVMDependenceGraph *dg,
                               const llvm::DataLayout *DL)
{
    Pointer pointer = UnknownMemoryLocation;

    const Instruction *Inst = const_cast<ConstantExpr*>(CE)->getAsInstruction();
    if (const GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(Inst)) {
        pointer = handleConstantGep(dg, GEP, DL);
    } else if (const BitCastInst *BC = dyn_cast<BitCastInst>(Inst)) {
        pointer = handleConstantBitCast(dg, BC);
    } else {
            errs() << "ERR: Unsupported ConstantExpr " << *CE << "\n";
            errs() << "      ^^ returning unknown pointer\n";
    }

    delete Inst;
    return pointer;
}

static LLVMNode *getConstantIntToPtrNode(const ConstantExpr *CE,
                                         const llvm::DataLayout *DL)
{
    using namespace llvm;

    const Value *val = CE->getOperand(0);
    if (!isa<ConstantInt>(val)) {
        errs() << "Unhandled constant inttoptr " << *CE << "\n";
        abort();
    }

    const ConstantInt *C = cast<ConstantInt>(val);
    uint64_t value = C->getLimitedValue();

    LLVMNode *&node = intToPtrMap[value];
    if (!node) {
        node = new LLVMNode(C);
        const Value *dest = CE->getOperand(1);
        Type *Ty = dest->getType()->getContainedType(0);
        uint64_t size = 0;
        if (Ty->isSized())
            size = DL->getTypeAllocSize(Ty);

        MemoryObj *&mo = node->getMemoryObj();
        mo = new MemoryObj(node, size);
        node->addPointsTo(mo);
    }

    return node;
}

static LLVMNode *getConstantExprNode(const llvm::ConstantExpr *CE,
                                     LLVMDependenceGraph *dg,
                                     const llvm::DataLayout *DL)
{
    // we have these nodes stored
    if (isa<IntToPtrInst>(CE))
        return getConstantIntToPtrNode(CE, DL);

    // FIXME add these nodes somewhere,
    // so that we can delete them later
    LLVMNode *node = new LLVMNode(CE);

    // set points-to sets
    Pointer ptr = getConstantExprPointer(CE, dg, DL);
    node->addPointsTo(ptr);

    return node;
}

static LLVMNode *getUnknownNode(LLVMDependenceGraph *dg, const llvm::Value *val,
                                const llvm::DataLayout *DL)
{
    LLVMNode *node = nullptr;

    using namespace llvm;
    if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(val)) {
        node = getConstantExprNode(CE, dg, DL);
    } else if (isa<Function>(val)) {
        // if the function was created via function pointer during
        // points-to analysis, the operand may not be not be set.
        // What is worse, the function may not be created either,
        // so the node just may not exists at all, so we need to
        // create it
        node = getOrCreateNode(dg, val);
    } else if (isa<ConstantPointerNull>(val)) {
        // what to do with nullptr?
        node = createNodeWithMemAlloc(val);
    } else {
        errs() << "ERR: Unsupported operand: " << *val << "\n";
        abort();
    }

    assert(node && "Did not get a node");
    return node;
}

/*
 * we have DependenceGraph::getNode() which retrives existing node.
 * The operand nodes may not exists, though.
 * This function gets the existing node, or creates new one and sets
 * it as an operand.
 */
LLVMNode *getOperand(LLVMNode *node, const llvm::Value *val,
                     unsigned int idx, const llvm::DataLayout *DL)
{
    // ok, before calling this we call llvm::Value::getOperand() to get val
    // and in node->getOperand() we call it too. It is small overhead, but just
    // to know where to optimize when going to extrems

    LLVMNode *op = node->getOperand(idx);
    if (op)
        return op;

    LLVMDependenceGraph *dg = node->getDG();

    // set new operand
    op = getUnknownNode(dg, val, DL);
    assert(op && "Did not get op");

    node->setOperand(op, idx);
    return op;
}

} // namespace analysis
} // namespace dg

<commit_msg>analyses: handle recursive constant expressions<commit_after>#include <map>

#include <llvm/IR/Value.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/DataLayout.h>
#include <llvm/Support/raw_ostream.h>

#include "AnalysisGeneric.h"
#include "LLVMDependenceGraph.h"
#include "PointsTo.h"

using namespace llvm;

namespace dg {
namespace analysis {

// we assume that if the program uses inttoptr, it access this
// memory only this way - so every access to this memory is done
// via some inttoptr. Here we store the inttoptr objects
static std::map<uint64_t, LLVMNode *> intToPtrMap;

// pointer points to unknown memory location
MemoryObj UnknownMemoryObject(nullptr);
// unknown pointer value
Pointer UnknownMemoryLocation(&UnknownMemoryObject, 0);

bool Pointer::isUnknown() const
{
    return this == &UnknownMemoryLocation;
}

bool Pointer::pointsToUnknown() const
{
    assert(obj && "Pointer has not any memory object set");
    return obj->isUnknown();
}

bool Pointer::isKnown() const
{
    return !isUnknown() && !pointsToUnknown();
}

bool MemoryObj::isUnknown() const
{
    return this == &UnknownMemoryObject;
}

static LLVMNode *createNodeWithMemAlloc(const Value *val)
{
    LLVMNode *n = new LLVMNode(val);
    MemoryObj *&mo = n->getMemoryObj();
    mo = new MemoryObj(n);
    n->addPointsTo(Pointer(mo));

    return n;
}

static LLVMNode *getOrCreateNode(LLVMDependenceGraph *dg, const Value *val)
{
    LLVMNode *n = dg->getNode(val);
    if (n)
        return n;

    if (llvm::isa<llvm::Function>(val)) {
        n = createNodeWithMemAlloc(val);
    } else
        errs() << "ERR: unhandled not to create " << *val << "\n";

    return n;
}

static Pointer handleConstantBitCast(LLVMDependenceGraph *dg, const BitCastInst *BC)
{
    if (!BC->isLosslessCast()) {
        errs() << "WARN: Not a loss less cast unhandled ConstExpr"
               << *BC << "\n";
        return UnknownMemoryLocation;
    }

    const Value *llvmOp = BC->stripPointerCasts();
    LLVMNode *op = getOrCreateNode(dg, llvmOp);
    if (!op) {
        errs() << "ERR: unsupported BitCast constant operand" << *BC << "\n";
    } else {
        PointsToSetT& ptset = op->getPointsTo();
        if (ptset.size() != 1) {
            errs() << "ERR: constant BitCast with not only one pointer "
                   << *BC << "\n";
        } else
            return *ptset.begin();
    }

    return UnknownMemoryLocation;
}

static inline unsigned getPointerBitwidth(const DataLayout *DL, const Value *ptr)
{
    const Type *Ty = ptr->getType();
    return DL->getPointerSizeInBits(Ty->getPointerAddressSpace());
}

static LLVMNode *getConstantExprNode(const llvm::ConstantExpr *CE,
                                     LLVMDependenceGraph *dg,
                                     const llvm::DataLayout *DL);

static Pointer handleConstantGep(LLVMDependenceGraph *dg,
                                 const GetElementPtrInst *GEP,
                                 const llvm::DataLayout *DL)
{
    const Value *op = GEP->getPointerOperand();

    LLVMNode *opNode = dg->getNode(op);

    // FIXME this is sound, but may be unprecise
    //  - we should use getOperand for getting opNode,
    //  becaues we can have ConstantExpr inserted in ConstantExpr
    //  (getelementptr (inttoptr ..) ...), so we can get null here
    //  as opNode
    if (!opNode) {
        // is this recursively created expression?
        if (isa<ConstantExpr>(op)) {
            opNode = getConstantExprNode(cast<ConstantExpr>(op), dg, DL);
        }

        if (!opNode) {
            errs() << "No node for Constant GEP operand: " << *GEP << "\n";
            return UnknownMemoryLocation;
        }
    }

    PointsToSetT& S = opNode->getPointsTo();
    // since this is constant expr, there's no way how we could
    // get extra points-to binding in runtime
    assert(S.size() == 1);
    MemoryObj *mo = (*S.begin()).obj;
    if (!mo) {
        errs() << "ERR: no memory object in " << *opNode->getKey() << "\n";
        return UnknownMemoryLocation;
    }

    Pointer pointer(mo, UNKNOWN_OFFSET);
    unsigned bitwidth = getPointerBitwidth(DL, op);
    APInt offset(bitwidth, 0);

    if (GEP->accumulateConstantOffset(*DL, offset)) {
        if (offset.isIntN(bitwidth))
            pointer.offset = offset.getZExtValue();
        else
            errs() << "WARN: Offset greater than "
                   << bitwidth << "-bit" << *GEP << "\n";
    }
    // else offset is set to UNKNOWN (in constructor)

    return pointer;
}

Pointer getConstantExprPointer(const ConstantExpr *CE,
                               LLVMDependenceGraph *dg,
                               const llvm::DataLayout *DL)
{
    Pointer pointer = UnknownMemoryLocation;

    const Instruction *Inst = const_cast<ConstantExpr*>(CE)->getAsInstruction();
    if (const GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(Inst)) {
        pointer = handleConstantGep(dg, GEP, DL);
    } else if (const BitCastInst *BC = dyn_cast<BitCastInst>(Inst)) {
        pointer = handleConstantBitCast(dg, BC);
    } else {
            errs() << "ERR: Unsupported ConstantExpr " << *CE << "\n";
            errs() << "      ^^ returning unknown pointer\n";
    }

    delete Inst;
    return pointer;
}

static LLVMNode *getConstantIntToPtrNode(const ConstantExpr *CE,
                                         const llvm::DataLayout *DL)
{
    using namespace llvm;

    const Value *val = CE->getOperand(0);
    if (!isa<ConstantInt>(val)) {
        errs() << "Unhandled constant inttoptr " << *CE << "\n";
        abort();
    }

    const ConstantInt *C = cast<ConstantInt>(val);
    uint64_t value = C->getLimitedValue();

    LLVMNode *&node = intToPtrMap[value];
    if (!node) {
        node = new LLVMNode(C);
        const Value *dest = CE->getOperand(1);
        Type *Ty = dest->getType()->getContainedType(0);
        uint64_t size = 0;
        if (Ty->isSized())
            size = DL->getTypeAllocSize(Ty);

        MemoryObj *&mo = node->getMemoryObj();
        mo = new MemoryObj(node, size);
        node->addPointsTo(mo);
    }

    return node;
}

static LLVMNode *getConstantExprNode(const llvm::ConstantExpr *CE,
                                     LLVMDependenceGraph *dg,
                                     const llvm::DataLayout *DL)
{
    // we have these nodes stored
    if (isa<IntToPtrInst>(CE))
        return getConstantIntToPtrNode(CE, DL);

    // FIXME add these nodes somewhere,
    // so that we can delete them later
    LLVMNode *node = new LLVMNode(CE);

    // set points-to sets
    Pointer ptr = getConstantExprPointer(CE, dg, DL);
    node->addPointsTo(ptr);

    return node;
}

static LLVMNode *getUnknownNode(LLVMDependenceGraph *dg, const llvm::Value *val,
                                const llvm::DataLayout *DL)
{
    LLVMNode *node = nullptr;

    using namespace llvm;
    if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(val)) {
        node = getConstantExprNode(CE, dg, DL);
    } else if (isa<Function>(val)) {
        // if the function was created via function pointer during
        // points-to analysis, the operand may not be not be set.
        // What is worse, the function may not be created either,
        // so the node just may not exists at all, so we need to
        // create it
        node = getOrCreateNode(dg, val);
    } else if (isa<ConstantPointerNull>(val)) {
        // what to do with nullptr?
        node = createNodeWithMemAlloc(val);
    } else {
        errs() << "ERR: Unsupported operand: " << *val << "\n";
        abort();
    }

    assert(node && "Did not get a node");
    return node;
}

/*
 * we have DependenceGraph::getNode() which retrives existing node.
 * The operand nodes may not exists, though.
 * This function gets the existing node, or creates new one and sets
 * it as an operand.
 */
LLVMNode *getOperand(LLVMNode *node, const llvm::Value *val,
                     unsigned int idx, const llvm::DataLayout *DL)
{
    // ok, before calling this we call llvm::Value::getOperand() to get val
    // and in node->getOperand() we call it too. It is small overhead, but just
    // to know where to optimize when going to extrems

    LLVMNode *op = node->getOperand(idx);
    if (op)
        return op;

    LLVMDependenceGraph *dg = node->getDG();

    // set new operand
    op = getUnknownNode(dg, val, DL);
    assert(op && "Did not get op");

    node->setOperand(op, idx);
    return op;
}

} // namespace analysis
} // namespace dg

<|endoftext|>