#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"

#include "BPatch_object.h"
#include "BPatch_module.h"

#include "Type.h"

#ifdef HAVE_SELINUX
#include <selinux/selinux.h>
#endif

using namespace Dyninst;

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

int main (int argc, char *argv[])
{
    if(argc < 2) {
        cerr << "./codeCoverage inputbinary" << endl;
        return EXIT_FAILURE;
    }
    char *inputprogram = argv[1];
    pid_t pid ;
    char line[512];
    FILE * command = NULL;
    char strPID[100];    
    sprintf(strPID,"pidof -s %s",inputprogram);
    command = popen(strPID,"r");
    fgets(line,512,command);
    pid = strtoul(line,NULL,10);
    pclose(command);

    cerr << "pid of process " << pid << endl;

    BPatch_addressSpace* app2 = bpatch.processAttach (NULL, pid);
    if (app2 == NULL) {
        cerr << "Failed to attach to the process" << endl;
        return EXIT_FAILURE;
    }
    BPatch_process* appProc = dynamic_cast<BPatch_process*>(app2);   
    if (appProc == NULL ) {
        cerr << "BPatch_process is NULL" << endl;
        return EXIT_FAILURE;
    }
    BPatch_image *appImage = appProc->getImage ();
    if (appImage == NULL) {
        cerr << "Failed to get image" << endl;
        return EXIT_FAILURE;
    }

    vector < BPatch_module * >*modules = appImage->getModules ();
    vector < BPatch_module * >::iterator moduleIter;
    for (moduleIter = modules->begin (); moduleIter != modules->end ();
            ++moduleIter) {
        char moduleName[1024];
        (*moduleIter)->getName (moduleName, 1024);
        
        vector < BPatch_function * >*allFunctions =
            (*moduleIter)->getProcedures ();
        vector < BPatch_function * >::iterator funcIter;

        for (funcIter = allFunctions->begin (); funcIter != allFunctions->end ();
                ++funcIter) {
            BPatch_function *curFunc = *funcIter;
            
            char funcName[1024];
            curFunc->getName (funcName, 1024);

            if(strstr(funcName, "main.")!= NULL){
                BPatch_Vector<BPatch_localVar *> *vars =  curFunc->getVars();
                cout<<"num vars in " << funcName << " are " << vars->size() << " type " << curFunc->getReturnType()<< endl;    

                for (unsigned int i = 0; i < vars->size(); ++i) {
                    cout << "var name is " << (*vars)[i]->getName() << endl;  
                    BPatch_type *type=(*vars)[i]->getType();
                    if(type)
                        cout <<" type is "<< type->getName() << endl;
                    cout << "frame off is " << (*vars)[i]->getFrameOffset() << endl;  
                    cout << "local var " << (*vars)[i]->getSymtabVar() << endl;
                    cout << "class  " << (*vars)[i]->getStorageClass() << endl;
                }
            }
        }
    }
    cout << "end main" <<endl;
    appProc->continueExecution();
    appProc->detach(true);
    return EXIT_SUCCESS;
}
