dyninst codecoverage

codeCoverage.c
/*
 *  A simple code coverage tool using DyninstAPI
 *
 *  This tool uses DyninstAPI to instrument the functions and basic blocks in
 *  an executable and its shared libraries in order to record code coverage
 *  data when the executable is run. This code coverage data is output when the
 *  rewritten executable finishes running.
 *
 *  The intent of this tool is to demonstrate some capabilities of DyninstAPI;
 *  it should serve as a good stepping stone to building a more feature-rich
 *  code coverage tool on top of Dyninst.
 */

#include <cstdlib>
#include <iostream>
#include <vector>
#include <string>
using namespace std;

// Command line parsing
#include <getopt.h>

// DyninstAPI includes
#include "BPatch.h"
#include "BPatch_binaryEdit.h"
#include "BPatch_flowGraph.h"
#include "BPatch_function.h"
#include "BPatch_point.h"

using namespace Dyninst;

static const char *USAGE = " [-bpsa] <binary> <output binary>\n                             -b: Basic block level code coverage\n                             -p: Print all functions (including functions that are never executed)\n                             -s: Instrument shared libraries also\n                             -a: Sort results alphabetically by function name\n";

static const char *OPT_STR = "bpsa";

// configuration options
char *inBinary = NULL;
char *outBinary = NULL;
bool includeSharedLib = false;
int printAll = 0;
bool bbCoverage = false;
int alphabetical = 0;

set < string > skipLibraries;

void initSkipLibraries ()
{
    /* List of shared libraries to skip instrumenting */
    /* Do not instrument the instrumentation library */
    skipLibraries.insert ("libInst.so");
    skipLibraries.insert ("libc.so.6");
    skipLibraries.insert ("libc.so.7");
    skipLibraries.insert ("ld-2.5.so");
    skipLibraries.insert ("ld-linux.so.2");
    skipLibraries.insert ("ld-lsb.so.3");
    skipLibraries.insert ("ld-linux-x86-64.so.2");
    skipLibraries.insert ("ld-lsb-x86-64.so");
    skipLibraries.insert ("ld-elf.so.1");
    skipLibraries.insert ("ld-elf32.so.1");
    skipLibraries.insert ("libstdc++.so.6");
    return;
}

bool parseArgs (int argc, char *argv[])
{
    int c;
    while ((c = getopt (argc, argv, OPT_STR)) != -1) {
        switch ((char) c) {
            case ‘b‘:
                bbCoverage = true;
                break;
            case ‘p‘:
                printAll = 1;
                break;
            case ‘s‘:
                /* if includeSharedLib is set,
                 * all libraries linked to the binary will also be instrumented */
                includeSharedLib = true;
                break;
            case ‘a‘:
                alphabetical = 1;
                break;
            default:
                cerr << "Usage: " << argv[0] << USAGE;
                return false;
        }
    }

    int endArgs = optind;

    if (endArgs >= argc) {
        cerr << "Input binary not specified." << endl
            << "Usage: " << argv[0] << USAGE;
        return false;
    }
    /* Input Binary */
    inBinary = argv[endArgs];

    endArgs++;
    if (endArgs >= argc) {
        cerr << "Output binary not specified." << endl
            << "Usage: " << argv[0] << USAGE;
        return false;
    }

    /* Rewritten Binary */
    outBinary = argv[endArgs];

    return true;
}

BPatch_function *findFuncByName (BPatch_image * appImage, char *funcName)
{
    /* fundFunctions returns a list of all functions with the name ‘funcName‘ in the binary */
    BPatch_Vector < BPatch_function * >funcs;
    if (NULL == appImage->findFunction (funcName, funcs) || !funcs.size ()
            || NULL == funcs[0]) {
        cerr << "Failed to find " << funcName <<
            " function in the instrumentation library" << endl;
        return NULL;
    }
    return funcs[0];
}

bool insertFuncEntry (BPatch_binaryEdit * appBin, BPatch_function * curFunc,
        char *funcName, BPatch_function * instIncFunc,
        int funcId)
{
    /* Find the instrumentation points */
    vector < BPatch_point * >*funcEntry = curFunc->findPoint (BPatch_entry);
    if (NULL == funcEntry) {
        cerr << "Failed to find entry for function " << funcName << endl;
        return false;
    }

    cout << "Inserting instrumention at function entry of " << funcName << endl;
    /* Create a vector of arguments to the function
     * incCoverage function takes the function name as argument */
    BPatch_Vector < BPatch_snippet * >instArgs;
    BPatch_constExpr id (funcId);
    instArgs.push_back (&id);
    BPatch_funcCallExpr instIncExpr (*instIncFunc, instArgs);

    /* Insert the snippet at function entry */
    BPatchSnippetHandle *handle =
        appBin->insertSnippet (instIncExpr, *funcEntry, BPatch_callBefore,
                BPatch_lastSnippet);
    if (!handle) {
        cerr << "Failed to insert instrumention at function entry of " << funcName
            << endl;
        return false;
    }
    return true;

}

bool insertBBEntry (BPatch_binaryEdit * appBin, BPatch_function * curFunc,
        char *funcName, const char *moduleName,
        BPatch_function * instBBIncFunc,
        BPatch_function * registerBB, int *bbIndex,
        BPatch_Vector < BPatch_snippet * >*registerCalls)
{
    BPatch_flowGraph *appCFG = curFunc->getCFG ();
    BPatch_Set < BPatch_basicBlock * >allBlocks;
    BPatch_Set < BPatch_basicBlock * >::iterator iter;
    if (!appCFG) {
        cerr << "Failed to find CFG for function " << funcName << endl;
        return EXIT_FAILURE;
    }
    if (!appCFG->getAllBasicBlocks (allBlocks)) {
        cerr << "Failed to find basic blocks for function " << funcName << endl;
        return EXIT_FAILURE;
    } else if (allBlocks.size () == 0) {
        cerr << "No basic blocks for function " << funcName << endl;
        return EXIT_FAILURE;
    }

    /* Instrument the entry of every basic block */

    for (iter = allBlocks.begin (); iter != allBlocks.end (); iter++) {
        unsigned long address = (*iter)->getStartAddress ();
        cout << "Instrumenting Basic Block 0x" << hex << address << " of " <<
            funcName << endl;
        BPatch_Vector < BPatch_snippet * >instArgs;
        BPatch_constExpr bbId (*bbIndex);
        instArgs.push_back (&bbId);
        BPatch_point *bbEntry = (*iter)->findEntryPoint ();
        if (NULL == bbEntry) {
            cerr << "Failed to find entry for basic block at 0x" << hex << address
                << endl;
            return false;
        }
        BPatch_funcCallExpr instIncExpr (*instBBIncFunc, instArgs);
        BPatchSnippetHandle *handle =
            appBin->insertSnippet (instIncExpr, *bbEntry, BPatch_callBefore,
                    BPatch_lastSnippet);
        if (!handle) {
            cerr << "Failed to insert instrumention in basic block at 0x" << hex <<
                address << endl;
            return false;
        }

        /* Create a call to the registration function for this basic block */
        BPatch_Vector < BPatch_snippet * >regArgs;
        BPatch_constExpr bbIdReg (*bbIndex);
        regArgs.push_back (&bbIdReg);
        BPatch_constExpr coverageFunc (funcName);
        regArgs.push_back (&coverageFunc);
        BPatch_constExpr coverageModule (moduleName);
        regArgs.push_back (&coverageModule);
        BPatch_constExpr addrArg (address);
        regArgs.push_back (&addrArg);

        BPatch_funcCallExpr *regCall =
            new BPatch_funcCallExpr (*registerBB, regArgs);
        registerCalls->push_back (regCall);

        (*bbIndex)++;
    }

    return true;
}

int main (int argc, char *argv[])
{
    if (!parseArgs (argc, argv))
        return EXIT_FAILURE;

    /* Initialize list of libraries that should not be instrumented - relevant only if includeSharedLib is true */
    initSkipLibraries ();

    /* Every Dyninst mutator needs to declare one instance of BPatch */
    BPatch bpatch;

    /* Open the specified binary for binary rewriting. 
     * When the second parameter is set to true, all the library dependencies 
     * as well as the binary are opened */

    BPatch_binaryEdit *appBin = bpatch.openBinary (inBinary, true);
    if (appBin == NULL) {
        cerr << "Failed to open binary" << endl;
        return EXIT_FAILURE;
    }

    /* Open the instrumentation library.
     * loadLibrary loads the instrumentation library into the binary image and
     * adds it as a new dynamic dependency in the rewritten library */
    const char *instLibrary = "./libInst.so";
    if (!appBin->loadLibrary (instLibrary)) {
        cerr << "Failed to open instrumentation library" << endl;
        return EXIT_FAILURE;
    }

    BPatch_image *appImage = appBin->getImage ();
    /* Find code coverage functions in the instrumentation library */
    BPatch_function *instInitFunc =
        findFuncByName (appImage, (char *) "initCoverage");
    BPatch_function *registerFunc =
        findFuncByName (appImage, (char *) "registerFunc");
    BPatch_function *instIncFunc =
        findFuncByName (appImage, (char *) "incFuncCoverage");
    BPatch_function *registerBB =
        findFuncByName (appImage, (char *) "registerBB");
    BPatch_function *instBBIncFunc =
        findFuncByName (appImage, (char *) "incBBCoverage");
    BPatch_function *instExitFunc =
        findFuncByName (appImage, (char *) "exitCoverage");

    if (!instInitFunc || !instIncFunc || !instExitFunc || !instBBIncFunc
            || !registerFunc || !registerBB) {
        return EXIT_FAILURE;
    }

    /* To instrument every function in the binary
     * --> iterate over all the modules in the binary 
     * --> iterate over all functions in each modules */

    vector < BPatch_module * >*modules = appImage->getModules ();
    vector < BPatch_module * >::iterator moduleIter;
    BPatch_module *defaultModule;

    BPatch_Vector < BPatch_snippet * >registerCalls;

    int bbIndex = 0;
    int funcIndex = 0;
    for (moduleIter = modules->begin (); moduleIter != modules->end ();
            ++moduleIter) {
        char moduleName[1024];
        (*moduleIter)->getName (moduleName, 1024);

        /* if includeSharedLib is not set, skip instrumenting dependent libraries */
        if ((*moduleIter)->isSharedLib ()) {
            if (!includeSharedLib
                    || skipLibraries.find (moduleName) != skipLibraries.end ()) {
                cout << "Skipping library: " << moduleName << endl;
                continue;
            }
        }

        /* Every binary has one default module.
         * code coverage initialize and finalize functions should be called only once.
         * Hence call them from the default module */
        if (string (moduleName).find ("DEFAULT_MODULE") != string::npos) {
            defaultModule = (*moduleIter);
        }

        cout << "Instrumenting module: " << moduleName << endl;
        vector < BPatch_function * >*allFunctions =
            (*moduleIter)->getProcedures ();
        vector < BPatch_function * >::iterator funcIter;

        /* Insert snippets at the entry of every function */
        for (funcIter = allFunctions->begin (); funcIter != allFunctions->end ();
                ++funcIter) {
            BPatch_function *curFunc = *funcIter;

            char funcName[1024];
            curFunc->getName (funcName, 1024);

            /*
             * Replace DEFAULT_MODULE with the name of the input binary in the output 
             */
            string passedModName (moduleName);
            if (passedModName.find ("DEFAULT_MODULE") != string::npos) {
                // Strip the directory
                passedModName = inBinary;
                passedModName =
                    passedModName.substr (passedModName.find_last_of ("\\/") + 1);
            }

            insertFuncEntry (appBin, curFunc, funcName, instIncFunc, funcIndex);

            /* Create a call to the registration function */
            BPatch_Vector < BPatch_snippet * >regArgs;
            BPatch_constExpr funcIdReg (funcIndex);
            regArgs.push_back (&funcIdReg);
            BPatch_constExpr coverageFunc (funcName);
            regArgs.push_back (&coverageFunc);
            BPatch_constExpr coverageModule (passedModName.c_str ());
            regArgs.push_back (&coverageModule);

            BPatch_funcCallExpr *regCall =
                new BPatch_funcCallExpr (*registerFunc, regArgs);
            registerCalls.push_back (regCall);

            funcIndex++;

            if (bbCoverage) {
                insertBBEntry (appBin, curFunc, funcName, passedModName.c_str (),
                        instBBIncFunc, registerBB, &bbIndex, &registerCalls);
            }
        }
    }

    /* Create argument list for initCoverage function 
     * with the number of functions the number of basic blocks */
    BPatch_Vector < BPatch_snippet * >instInitArgs;
    BPatch_constExpr numFuncs (funcIndex);
    instInitArgs.push_back (&numFuncs);
    BPatch_constExpr numBBs (bbIndex);
    instInitArgs.push_back (&numBBs);
    BPatch_funcCallExpr instInitExpr (*instInitFunc, instInitArgs);

    // Execute the function registration and basic block registration calls after
    // the call to the initialization function, i.e.,
    // initCoverage()
    // registerFunc()
    // ...
    // registerBB()
    // ...
    BPatch_sequence registerSequence (registerCalls);

    BPatch_Vector < BPatch_snippet * >initSequenceVec;
    initSequenceVec.push_back (&instInitExpr);
    initSequenceVec.push_back (&registerSequence);

    BPatch_sequence initSequence (initSequenceVec);

    /* Locate _init */
    BPatch_Vector<BPatch_function*> funcs;
    appImage->findFunction("_init", funcs);
    if (funcs.size()) {
        BPatch_Vector<BPatch_function*>::iterator fIter;
        for (fIter = funcs.begin(); fIter != funcs.end(); ++fIter) {
            BPatch_module * mod = (*fIter)->getModule();
            char modName[1024];
            mod->getName(modName, 1024);
             if (!mod->isSharedLib ()) {
                mod->insertInitCallback(initSequence);
                cerr << "insertInitCallback on " << modName << endl;
            }
        }
    }

    /* Insert initCoverage function in the init section of the default module 
     * to be executed exactly once when the module is loaded */
//    if (!defaultModule->insertInitCallback (initSequence)) {
//        cerr << "Failed to insert init function in the module" << endl;
//        return EXIT_FAILURE;
//    }

    /* Insert exitCoverage function in the fini section of the default module 
     * to be executed exactly once when the module is unloaded */
    BPatch_Vector < BPatch_snippet * >instExitArgs;
    BPatch_constExpr varPrint (printAll);
    instExitArgs.push_back (&varPrint);
    BPatch_constExpr varBBPrint (bbCoverage ? 1 : 0);
    instExitArgs.push_back (&varBBPrint);
    BPatch_constExpr varAlpha (alphabetical);
    instExitArgs.push_back (&varAlpha);
    BPatch_funcCallExpr instExitExpr (*instExitFunc, instExitArgs);
    
    /* Locate _fini */
    funcs.clear();
    appImage->findFunction("_fini", funcs);
    if (funcs.size()) {
        BPatch_Vector<BPatch_function*>::iterator fIter;
        for (fIter = funcs.begin(); fIter != funcs.end(); ++fIter) {
            BPatch_module * mod = (*fIter)->getModule();
            char modName[1024];
            mod->getName(modName, 1024);
             if (!mod->isSharedLib ()) {
                mod->insertFiniCallback(instExitExpr);
                cerr << "insertFiniCallback on " << modName << endl;
            }
        }
    }
    
//    if (!defaultModule->insertFiniCallback (instExitExpr)) {
//        cerr << "Failed to insert exit function in the module" << endl;
//        return EXIT_FAILURE;
//    }

    // Output the instrumented binary
    if (!appBin->writeFile (outBinary)) {
        cerr << "Failed to write output file: " << outBinary << endl;
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

libInst.C

/*
 * The instrumentation library for the codeCoverage tool. Provides
 * functions for initialization, registering functions and basic
 * blocks for coverage tracking, and outputting the results.
 */

#include<cstdlib>
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;

class bbRecord {
public:
  string funcName;
  string modName;
  unsigned long address;
  unsigned long count;
  bbRecord() : funcName(""), modName(""), address(0), count(0) {}
};

class funcRecord {
public:
    string funcName;
    string modName;
    unsigned long count;
    funcRecord() : funcName(""), modName(""), count(0) {}
};

// Used to records via qsort
static int compareFuncRecordByName(const void *left, const void *right) {
    funcRecord *leftRecord = (funcRecord *)left;
    funcRecord *rightRecord = (funcRecord *)right;

    return leftRecord->funcName.compare(rightRecord->funcName);
}

static int compareFuncRecordByCount(const void *left, const void *right) {
    funcRecord *leftRecord = (funcRecord *)left;
    funcRecord *rightRecord = (funcRecord *)right;

    if( leftRecord->count < rightRecord->count ) return 1;

    if( leftRecord->count > rightRecord->count ) return -1;

    return 0;
}

static int compareBBRecordByName(const void *left, const void *right) {
    bbRecord *leftRecord = (bbRecord *)left;
    bbRecord *rightRecord = (bbRecord *)right;

    return leftRecord->funcName.compare(rightRecord->funcName);
}

static int compareBBRecordByCount(const void *left, const void *right) {
    bbRecord *leftRecord = (bbRecord *)left;
    bbRecord *rightRecord = (bbRecord *)right;

    if( leftRecord->count < rightRecord->count ) return 1;

    if( leftRecord->count > rightRecord->count ) return -1;

    return 0;
}

// For efficency in instrumentation, indexed by id
static bbRecord *bbs;
static funcRecord *funcs;

int numFuncs = 0;
int numBBs = 0;
int enabled = 0;

// Allocates space for all tracked functions and basic blocks
void initCoverage(int totalFuncs, int totalBBs) {
    numFuncs = totalFuncs;
    numBBs = totalBBs;

    funcs = new funcRecord[numFuncs];
    bbs = new bbRecord[numBBs];

    enabled = 1;
}

// Populates a record for a function
void registerFunc(int id, char *name, char *modName) {
    if( !enabled ) return;

    funcs[id].funcName = name;
    funcs[id].modName = modName;
    funcs[id].count = 0;
}

// Populates a record for a basic block
void registerBB(int id, char *name, char *modName, unsigned long addr) {
    if( !enabled ) return;

    bbs[id].funcName = name;
    bbs[id].modName = modName;
    bbs[id].address = addr;
    bbs[id].count = 0;
}

// Should be called on function entry 
void incFuncCoverage(int id) {
  if( !enabled ) return;

  funcs[id].count++;
}

// Should be called on basic block entry
void incBBCoverage(int id) {
  if( !enabled ) return;

  bbs[id].count++;
}

// Prints the code coverage stats. to standard out, also disables any more tracking
void exitCoverage(int printAll, int printBasicBlocks, int sortAlphabetical) {
  if( !enabled ) return;

  printf("\n\n ************************** Code Coverage ************************* \n\n");
  int count = 0;
  if( sortAlphabetical ) qsort(funcs, numFuncs, sizeof(funcRecord), &compareFuncRecordByName);
  else qsort(funcs, numFuncs, sizeof(funcRecord), &compareFuncRecordByCount);

  for(int i = 0; i < numFuncs; ++i) {
      if( funcs[i].count > 0 ) count++;
      if( printAll || (funcs[i].count > 0) )
        printf(" %4lu : %s, %s\n", funcs[i].count, funcs[i].funcName.c_str(), funcs[i].modName.c_str()); 
  }
  printf("\n ************** Code Coverage %d out of %d functions ************** \n\n", count, numFuncs);

  if (printBasicBlocks) {
    int bbCount = 0;
    printf("\n\n ************************** Basic Block Coverage ************************* \n\n");
    if( sortAlphabetical ) qsort(bbs, numBBs, sizeof(bbRecord), &compareBBRecordByName);
    else qsort(bbs, numBBs, sizeof(bbRecord), &compareBBRecordByCount);

    string curFunc;
    string curMod;
    for(int i = 0; i < numBBs; ++i) {
        if( bbs[i].count > 0 ) bbCount++;
        else if( !printAll ) continue;

        if( curFunc != bbs[i].funcName || curMod != bbs[i].modName ) {
            curFunc = bbs[i].funcName;
            curMod = bbs[i].modName;
            printf(" (%s, %s)\n", bbs[i].funcName.c_str(), bbs[i].modName.c_str());
            printf(" \t %4lu : 0x%-8lx\n", bbs[i].count, bbs[i].address);
        }else{
            printf(" \t %4lu : 0x%-8lx\n", bbs[i].count, bbs[i].address);
        }

    }
    printf("\n ************** Basic Block Coverage %d out of %d blocks ************** \n\n", bbCount, numBBs);
  }

  enabled = 0;
}

libtestcc.c

/*
 * A toy library to demonstrate the codeCoverage tool
 */

#include "libtestcc.h"

static int otherFunctionCalled = 0;

static void otherFunction() {
    otherFunctionCalled = 1;
}

void libFooFunction(int callOtherFunction) {
    if( callOtherFunction ) otherFunction();
}

libtestcc.h

/*
 * Header for libtestcc
 */

#ifndef __LIB_TESTCC_H__
#define __LIB_TESTCC_H__

extern void libFooFunction(int callOtherFunction);

#endif

Makefile

README

This directory contains a simple code coverage tool built with DyninstAPI. The
tool uses Dyninst to instrument every function in a program binary as well as
optionally instrumenting every basic block to record code coverage data.  

The goal of this tool is to demonstrate some of the capabilities of DyninstAPI.
It does very little processing of the raw code coverage data, just some basic
sorting when outputting the data. This tool should serve as the basis for
creating a more feature-rich code coverage tool using Dyninst.

The presence of debugging information in the program binary is recommended to
acquire the most useful information about code coverage, but it is not
required. Without debugging information, source file information will not be
available in the code coverage output.

This tool makes use of an instrumentation library, libInst, to collect the code
coverage data. The tool adds this library as a dependency to the input
executable and also inserts calls into this library at function entries and
basic block entries.

The provided Makefile can be used to build the program. The DYNINST_ROOT
environment variable should be set to the directory where Dyninst was
built/installed. This directory should contain an include directory with the
Dyninst headers and a lib directory with the Dyninst libraries. Also, make sure
to set the LD_LIBRARY_PATH environment variable to include the library
directory and set the DYNINSTAPI_RT_LIB environment variable to
${DYNINST_LIBRARY_DIRECTORY}/libdyninstAPI_RT.so.1

Also included in this directory is a toy program that demonstrates a use of the
codeCoverage tool: testcc and libtestcc. They can be built with the provided
Makefile.

An example usage of the codeCoverage tool with this program follows.

It is assumed that the following binaries have been built: codeCoverage,
libtestcc, testcc. Also, this example assumes you are using csh/tcsh, but
should easily transfer to another shell.

Before starting, the testcc program will not work unless the libtestcc.so
library can be found by the dynamic linker. Among other solutions, this
command should make testcc execute successfully.

% setenv LD_LIBRARY_PATH ${LD_LIBRARY_PATH}:.

First, execute codeCoverage without any arguments to see the usage.

% ./codeCoverage
Input binary not specified.
Usage: ./codeCoverage [-bpsa] <binary> <output binary>
    -b: Basic block level code coverage
    -p: Print all functions (including functions that are never executed)
    -s: Instrument shared libraries also
    -a: Sort results alphabetically by function name

Now, pass the testcc executable as input, instrumenting basic blocks as
well as a shared library used by testcc, libtestcc.so.
% ./codeCoverage -sb ./testcc testcc.inst
[ Lots of output stating what the tool is doing ]

You may notice that the tool skips some shared libraries. The default behavior
of the tool is to not instrument standard libraries such as libc.

The last command will output a rewritten version of testcc, testcc.inst. It will
also overwrite the existing libtestcc.so file with a rewritten version. The
default Dyninst behavior when rewritting the shared libraries of an executable
is to output the shared libraries in the same directory as the rewritten 
executable.

Now, run the testcc.inst program to generate code coverage data. An abridged
version of the output follows.

% ./testcc.inst

 ************************** Code Coverage ************************* 

    1 : _init, testcc
    1 : __do_global_dtors_aux, testcc
    1 : frame_dummy, testcc
    1 : __do_global_ctors_aux, testcc
    1 : _fini, testcc
    1 : two, testcc.c
    1 : one, testcc.c
    1 : main, testcc.c

 ************** Code Coverage 8 out of 17 functions ************** 

 ************************** Basic Block Coverage ************************* 

[...snip...]
 (two, testcc.c)
 	    1 : 0x4006ab  
 (one, testcc.c)
 	    1 : 0x4006c0  
 	    1 : 0x4006d6  
 (__do_global_dtors_aux, testcc)
 	    1 : 0x40063c  
 (one, testcc.c)
 	    1 : 0x4006e4  
 (main, testcc.c)
 	    1 : 0x4006f0  
 (__do_global_dtors_aux, testcc)
 	    1 : 0x400643  
 (main, testcc.c)
 	    1 : 0x40071a
[...snip...]

 ************** Basic Block Coverage 23 out of 69 blocks ************** 

END OUTPUT

The first set of data contains counts for the number of times each function was
called. The second set of data contains counts for the number of times each
basic block was entered.

If you run the program again with a few command line arguments, you will see
that the ‘three‘ function in testcc.c was now called as well as functions in
libtestcc.so.

% ./testcc.inst 1 2

 ************************** Code Coverage ************************* 

    1 : _init, testcc
    1 : three, testcc.c
    1 : two, testcc.c
    1 : one, testcc.c
    1 : main, testcc.c
    1 : otherFunction, libtestcc.so
    1 : libFooFunction, libtestcc.so
    1 : __do_global_dtors_aux, testcc
    1 : frame_dummy, testcc
    1 : __do_global_ctors_aux, testcc
    1 : _fini, testcc

 ************** Code Coverage 11 out of 17 functions ************** 

[...snip...] basic block output not included
END OUTPUT

This output shows that more functions have been called with this new input set.
时间: 2024-11-05 11:37:09

dyninst codecoverage的相关文章

make

http://futeng.iteye.com/blog/2071867 http://zhou123.blog.51cto.com/4355617/1196415 w [email protected]52-248-ubuntu:/# wget http://download.redis.io/releases/redis-3.2.8.tar.gz --2017-04-28 21:43:43-- http://download.redis.io/releases/redis-3.2.8.tar

三种Linux性能分析工具的比较

无论是在CPU设计.服务器研发还是存储系统开发的过程中,性能总是一个绕不过去的硬指标.很多时候,我们发现系统功能完备,但就是性能不尽如意,这时候就需要找到性能瓶颈.进行优化.首先我们需要结合硬件特点.操作系统和应用程序的特点深入了解系统内部的运行机制.数据流图和关键路径,最好找出核心模块.建立起抽象模型:接着需要利用各种性能分析工具,探测相关模块的热点路径.耗时统计和占比.在这方面,Linux操作系统自带了多种灵活又具有专对性的工具,此外一些厂家也开源了不少优秀的性能分析工具.下面就结合笔者最近

awesome-php中英文资源整理(同步更新)

中文版 收集整理一些常用的PHP类库, 资源以及技巧. 以便在工作中迅速的查找所需… 这个列表中的内容有来自 awesome-php 的翻译, 有来自开发者周刊以及个人的积累等. 一个前端组件的列表 awesome-frontend 推荐 学习资源 PHP相关的有参考价值的社区,博客,网站,文章,书籍,视频等资源 PHP网站(PHP Websites) PHP The Right Way – 一个PHP实践的快速参考指导 PHP Best Practices – 一个PHP最佳实践 PHP We

单元测试之覆盖率浅谈

一.什么是代码覆盖率 代码覆盖是软件测试中的一种度量,描述程式中源代码被测试的比例和程度,所得比例称为代码覆盖率.一般我们用工具做的代码覆盖率的计算方法是: 代码覆盖率 = 被测代码行数 / 参测代码总行数 * 100% 二.度量方式 代码覆盖程度的度量方式是有很多种的,这里介绍一下最常用的几种: 1. 语句覆盖/行覆盖(StatementCoverage) 这是一种较为常用且具有代表性的指标,度量的是被测代码中所有语句是否被执行到. 2.判定覆盖(DecisionCoverage) 度量程序中

Android 自动化测试(5)&lt;robotium&gt;

关于Android的自动化测试之UI测试,之前介绍过Android 自动化测试(4)<uiautomator>, 在android原生的单元测试框架上,利用uiautomator.jar这个类库来完成Android的界面上的测试,这已经使得测试比较简单了.但还有更加简单的写测试的方式,那就是利用一些第三方的测试框架,比如robotium. Android的第三方的测试框架,有Robolectric 和 robotium,我试着用了下,觉得robotium已经非常好用了. 1.概要 Roboti

redis集群 部署操作流程

/************************操作说明************************************/ 1.本操作过程是在centOS7_64的环境下进行: 2.登录用户为root(管理员账号): 3.本流程中使用的redis.conf是自己已经配好的文件,进行细微修改即可(文件下载见:参考文献及资料下载路径): 4.使用的虚拟机为vmware 12.0.0 build-2985596 /***************************************

awesome-java

Awesome Java A curated list of awesome Java frameworks, libraries and software. Awesome Java Ancients Bean Mapping Build Bytecode Manipulation Cluster Management Code Analysis Code Coverage Compiler-compiler Configuration Constraint Satisfaction Prob

centos7.3 编译安装lamp,利用wordpress实现个人博客搭建

软件环境:centos7.3 软件包: apr-1.5.2.tar.bz2 apr-util-1.5.4.tar.bz2 httpd-2.4.27.tar.bz2 mariadb-10.2.7-linux-x86_64.tar.gz php-7.1.7.tar.bz2 wordpress-4.8-zh_CN.tar.gz xcache-3.2.0.tar.gz 准备工作: [[email protected] ~]# mkdir /app                      #创建/app

Redis【第一篇】安装

第一步:准备 1. 操作系统 CentOS-7-x86_64-Everything-1511 2. redis 版本 redis-3.2.8 3. 修改内核参数 有三种方式: 1)编辑/etc/sysctl.conf ,改vm.overcommit_memory=1,然后sysctl -p 使配置文件生效 2)sysctl vm.overcommit_memory=1 3)echo 1 > /proc/sys/vm/overcommit_memory 附:内核参数 overcommit_memo