rose_addr_t
DwarfLineMapper::src2first_addr(const SrcInfo &srcinfo) const
{
    ExtentMap ex = src2addr(srcinfo);
    return ex.empty() ? 0 : ex.min();
}
Example #2
0
Partitioner::RegionStats *
Partitioner::region_statistics(const ExtentMap &addresses)
{
    RegionStats *stats = new_region_stats();
    assert(stats!=NULL);
    size_t nbytes = addresses.size();
    if (0==nbytes)
        return stats;
    stats->add_sample(RegionStats::RA_NBYTES, nbytes);
    ExtentMap not_addresses = addresses.invert<ExtentMap>();

    Disassembler::AddressSet worklist;          // addresses waiting to be disassembled recursively
    InstructionMap insns_found;                 // all the instructions we found herein
    ExtentMap insns_extent;                     // memory used by the instructions we've found
    ExtentMap pending = addresses;              // addresses we haven't looked at yet

    /* Undirected local control flow graph used to count connected components */
    typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS> CFG;
    typedef boost::graph_traits<CFG>::vertex_descriptor CFGVertex;
    typedef std::map<rose_addr_t, CFGVertex> Addr2Vertex;
    CFG cfg;
    Addr2Vertex va2id;

    /* Statistics */
    size_t nstarts=0;                           // number of times the recursive disassembler was started
    size_t nfails=0;                            // number of disassembler failures
    size_t noverlaps=0;                         // instructions overlapping with a previously found instruction
    size_t nincomplete=0;                       // number of instructions with unknown successors
    size_t nfallthrough=0;                      // number of branches to fall-through address within our "addresses"
    size_t ncalls=0;                            // number of function calls outside our "addresses"
    size_t nnoncalls=0;                         // number of branches to non-functions outside our "addresses"
    size_t ninternal=0;                         // number of non-fallthrough internal branches

    while (!pending.empty()) {
        rose_addr_t start_va = pending.min();
        worklist.insert(start_va);
        ++nstarts;

        while (!worklist.empty()) {
            rose_addr_t va = *worklist.begin();
            worklist.erase(worklist.begin());

            /* Obtain (disassemble) the instruction and make sure it falls entirely within the "addresses" */
            Instruction *insn = find_instruction(va);
            if (!insn) {
                ++nfails;
                pending.erase(Extent(va));
                continue;
            }
            Extent ie(va, insn->get_size());
            if (not_addresses.overlaps(ie)) {
                ++nfails;
                pending.erase(Extent(va));
                continue;
            }

            /* The disassembler can also return an "unknown" instruction when failing, depending on how it is invoked. */
            if (insn->node->is_unknown()) {
                ++nfails;
                pending.erase(Extent(va, insn->get_size()));
                continue;
            }

            insns_found.insert(std::make_pair(va, insn));
            rose_addr_t fall_through_va = va + insn->get_size();

            /* Does this instruction overlap with any we've already found? */
            if (insns_extent.overlaps(ie))
                ++noverlaps;
            pending.erase(Extent(va, insn->get_size()));
            insns_extent.insert(ie);

            /* Find instruction successors by looking only at the instruction itself.  This is simpler, but less rigorous
             * method than finding successors a basic block at a time.  For instance, we'll find both sides of a branch
             * instruction even if the more rigorous method determined that one side or the other is always taken.  But this is
             * probably what we want here anyway for determining whether something looks like code. */
            bool complete;
            Disassembler::AddressSet succs = insn->get_successors(&complete);
            if (!complete)
                ++nincomplete;

            /* Add instruction as vertex to CFG */
            std::pair<Addr2Vertex::iterator, bool> inserted = va2id.insert(std::make_pair(va, va2id.size()));
            if (inserted.second) {
                CFGVertex vertex __attribute__((unused)) = add_vertex(cfg);
                assert(vertex==inserted.first->second);
            }

            /* Classify the various successors. */
            for (Disassembler::AddressSet::const_iterator si=succs.begin(); si!=succs.end(); ++si) {
                rose_addr_t succ_va = *si;


                if (succ_va==fall_through_va) {
                    ++nfallthrough;
                    if (pending.find(succ_va)!=pending.end())
                        worklist.insert(succ_va);
                    /* Add edge to CFG graph */
                    va2id.insert(std::make_pair(succ_va, va2id.size()));
                    add_edge(va2id[va], va2id[succ_va], cfg);
                } else if (addresses.find(succ_va)==addresses.end()) {
                    /* A non-fallthrough branch to something outside this memory region */
                    if (functions.find(succ_va)!=functions.end()) {
                        /* A branch to a function entry point we've previously discovered. */
                        ++ncalls;
                    } else {
                        ++nnoncalls;
                    }
                } else {
                    /* A non-fallthrough branch to something in our address range. */
                    ++ninternal;
                    if (pending.find(succ_va)!=pending.end())
                        worklist.insert(succ_va);

                    /* Add edge to CFG graph */
                    va2id.insert(std::make_pair(succ_va, va2id.size()));
                    add_edge(va2id[va], va2id[succ_va], cfg);
                }
            }
        }
    }

    /* Statistics */
    stats->add_sample(RegionStats::RA_NFAILS, nfails);
    stats->add_sample(RegionStats::RA_NINSNS, insns_found.size());
    stats->add_sample(RegionStats::RA_NOVERLAPS, noverlaps);
    stats->add_sample(RegionStats::RA_NSTARTS, nstarts);
    stats->add_sample(RegionStats::RA_NCOVERAGE, insns_extent.size());
    stats->add_sample(RegionStats::RA_NINCOMPLETE, nincomplete);
    stats->add_sample(RegionStats::RA_NBRANCHES, ncalls+nnoncalls+ninternal);
    stats->add_sample(RegionStats::RA_NCALLS, ncalls);
    stats->add_sample(RegionStats::RA_NNONCALLS, nnoncalls);
    stats->add_sample(RegionStats::RA_NINTERNAL, ninternal);
    stats->add_sample(RegionStats::RA_NICFGEDGES, ninternal + nfallthrough);
    stats->add_sample(RegionStats::RA_NIUNIQUE, count_kinds(insns_found));
    stats->add_sample(RegionStats::RA_NPRIV, count_privileged(insns_found));
    stats->add_sample(RegionStats::RA_NFLOAT, count_floating_point(insns_found));
    double regsz, regvar;
    stats->add_sample(RegionStats::RA_NREGREFS, count_registers(insns_found, &regsz, &regvar));
    stats->add_sample(RegionStats::RA_REGSZ, regsz);
    stats->add_sample(RegionStats::RA_REGVAR, regvar);

    /* Count the number of connected components in the undirected CFG */
    if (!va2id.empty()) {
        std::vector<int> component(num_vertices(cfg));
        stats->add_sample(RegionStats::RA_NCOMPS, connected_components(cfg, &component[0]));
    }

    stats->compute_ratios();
    return stats;
}