void SymbolTable::print(){
    char tmpstr[__MAX_STRING_SIZE];
    PRINT_INFOR("SymbolTable : %d aka sect %d with %d symbols",index,getSectionIndex(),symbols.size());
    PRINT_INFOR("\tdyn? : %s", isDynamic() ? "yes" : "no");
    for (uint32_t i = 0; i < symbols.size(); i++){
        symbols[i]->print();
    }
}
void DataReference::print(){
    uint16_t sidx = 0;
    if (rawSection){
        sidx = rawSection->getSectionIndex();
    }
    PRINT_INFOR("DATAREF %#llx: Offset %#llx in section %d -- %#llx", getBaseAddress(), sectionOffset, sidx, data);
}
void DataSection::setBytesAtOffset(uint64_t offset, uint32_t size, char* content){
    if (offset + size > getSizeInBytes()){
        PRINT_INFOR("offset %ld size %d GetSize %ld", offset, size, getSizeInBytes());
    }
    ASSERT(offset + size <= getSizeInBytes());
    ASSERT(rawBytes);

    memcpy(rawBytes + offset, content, size);
}
void DataSection::printBytes(uint64_t offset, uint32_t bytesPerWord, uint32_t bytesPerLine){
    fprintf(stdout, "\n");
    PRINT_INFOR("Raw bytes for DATA section %d:", sectionIndex);

    uint32_t printMax = getSectionHeader()->GET(sh_size);
    if (0x400 < printMax){
        printMax = 0x400;
    }
    printBufferPretty(charStream() + offset, printMax, getSectionHeader()->GET(sh_addr) + offset, bytesPerWord, bytesPerLine);
}
void RelocationTable::print(){
    PRINT_INFOR("RelocTable : %d aka sect %d with %d relocations",index,getSectionIndex(),relocations.size());
    PRINT_INFOR("\tadd? : %s", type == ElfRelType_rela ? "yes" : "no");
    PRINT_INFOR("\tsect : %d", elfFile->getSectionHeader(getSectionIndex())->GET(sh_info));
    PRINT_INFOR("\tstbs : %d", elfFile->getSectionHeader(getSectionIndex())->GET(sh_link));

    ASSERT(elfFile->getSectionHeader(getSectionIndex()) && "Section header doesn't exist");

    for (uint32_t i = 0; i < relocations.size(); i++){
        char* namestr = NULL;
        Symbol* foundsymbols[3];
        for (uint32_t j = 0; j < 3; j++){
            foundsymbols[j] = NULL;
        }
        symbolTable->findSymbol4Addr(relocations[i]->GET(r_offset),foundsymbols,3,&namestr);
        relocations[i]->print(namestr);
        for (uint32_t j = 0; j < 3; j++){
            if (foundsymbols[j]){
                foundsymbols[j]->print();
            }
        }
        delete[] namestr;
    }
}
CallReplace::CallReplace(ElfFile* elf, char* traceFile, char* libList)
    : InstrumentationTool(elf)
{
    programEntry = NULL;
    programExit = NULL;

    functionList = new Vector<char*>();
    initializeFileList(traceFile, functionList);

    // replace any ':' character with a '\0'
    for (uint32_t i = 0; i < (*functionList).size(); i++){
        char* both = (*functionList)[i];
        uint32_t numrepl = 0;
        for (uint32_t j = 0; j < strlen(both); j++){
            if (both[j] == ':'){
                both[j] = '\0';
                numrepl++;
            }
        }
        if (numrepl != 1){
            PRINT_ERROR("input file %s line %d should contain a ':'", traceFile, i+1);
        }
    }

    Vector<uint32_t> libIdx;
    libIdx.append(0);
    uint32_t listSize = strlen(libList);
    for (uint32_t i = 0; i < listSize; i++){
        if (libList[i] == ','){
            libList[i] = '\0';
            libIdx.append(i+1);
        }
    }
    for (uint32_t i = 0; i < libIdx.size(); i++){
        if (libIdx[i] < listSize){
            libraries.append(libList + libIdx[i]);
        } else {
            PRINT_ERROR("improperly formatted library list given to call replacement tool");
            __SHOULD_NOT_ARRIVE;
        }
    }

    for (uint32_t i = 0; i < libraries.size(); i++){
        PRINT_INFOR("library -- %s", libraries[i]);
    }

}
void ProgramHeader::print() { 

    PRINT_INFOR("PHeader : %d",index);
    if(GET(p_type) <= PT_PHDR){
        PRINT_INFOR("\tPtyp : %s",PTypeNames[GET(p_type)]);
    } else {
        char* ptr = "UNK";
        switch(GET(p_type)){
            case PT_LOOS         : ptr = "LOOS"; break;
            case PT_GNU_EH_FRAME : ptr = "GNU_EH_FRAME"; break;
            case PT_GNU_STACK    : ptr = "GNU_STACK"; break;
            case PT_LOSUNW       : ptr = "LOSUNW"; break;
            case PT_SUNWSTACK    : ptr = "SUNWSTACK"; break;
            case PT_HIOS         : ptr = "HIOS"; break;
            case PT_LOPROC       : ptr = "LOPROC"; break;
            case PT_HIPROC       : ptr = "HIPROC"; break;
            default              : ptr = "UNK"; break;
        }
        PRINT_INFOR("\tPtyp : %s (%#x)",ptr,GET(p_type));
    }

    PRINT_INFOR("\tPoff : @%llx for %lluB",GET(p_offset),GET(p_filesz));
    PRINT_INFOR("\tPvad : %#llx for %lluB",GET(p_vaddr),GET(p_memsz));
    PRINT_INFOR("\tPpad : %#llx",GET(p_paddr));
    uint32_t alignment = GET(p_align);
    for(uint32_t i=0;i<32;i++){
        if((alignment >> i) & 0x1){
            alignment = i;
        }
    }
    PRINT_INFOR("\talig : 2**%u",alignment);

    uint32_t flags  = GET(p_flags);
    PRINT_INFOR("\tflgs : %c%c%c%c%c",ISPF_R(flags) ? 'r' : '-',
                                      ISPF_W(flags) ? 'w' : '-',
                                      ISPF_X(flags) ? 'x' : '-',
                                      flags == PF_MASKOS ? 'o' : '-',
                                      flags == PF_MASKPROC ? 'p' : '-');
}
void Symbol::print(){

    char* bindstr = "UNK";
    switch(ELF32_ST_BIND(GET(st_info))){
        case STB_LOCAL: bindstr="LOC";break;
        case STB_GLOBAL:bindstr="GLB";break;
        case STB_WEAK:  bindstr="WEA";break;
        case STB_NUM:   bindstr="NUM";break;
        case STB_LOOS:  bindstr="LOS";break;
        case STB_HIOS:  bindstr="HIS";break;
        case STB_LOPROC:bindstr="LOP";break;
        case STB_HIPROC:bindstr="HIP";break;
        default: break;  
    }

    char* typestr = "UNK";
    switch(ELF32_ST_TYPE(GET(st_info))){
        case STT_NOTYPE: typestr="NOTY";break;
        case STT_OBJECT: typestr="OBJT";break;
        case STT_FUNC:   typestr="FUNC";break;
        case STT_SECTION:typestr="SECT";break;
        case STT_FILE:   typestr="FILE";break;
        case STT_COMMON: typestr="COMM";break;
        case STT_TLS:    typestr="TLS ";break;
        case STT_NUM:    typestr="NUM ";break;
        case STT_LOOS:   typestr="LOOS";break;
        case STT_HIOS:   typestr="HIOS";break;
        case STT_LOPROC: typestr="LOPR";break;
        case STT_HIPROC: typestr="HIPR";break;
        default:break;
    }

    char* symbolName = table->getSymbolName(index);

    PRINT_INFOR("\tsym%5d -- sx:%5d sz:%8lld bxt: %3s.%4s vl:%#12llx ot:%3d nx:%8u\t%s",index,
            GET(st_shndx),GET(st_size),bindstr,typestr,GET(st_value),GET(st_other),
            GET(st_name),symbolName ? symbolName : "");
}
int main(int argc,char* argv[]){
    int overflow = 0xbeefbeef;

    char*    inptName   = NULL;
    char*    extension  = "";
    char*    libPath    = NULL;
    int32_t  phaseNo    = 0;
    uint32_t instType   = unknown_inst_type;
    uint32_t argApp     = 0;
    uint32_t argTyp     = 0;
    uint32_t argExt     = 0;
    uint32_t argPhs     = 0;
    uint32_t argInp     = 0;
    bool     loopIncl   = false;
    bool     extdPrnt   = false;
    bool     verbose    = false;
    bool     dryRun     = false;
    uint32_t printCodes = 0x00000000;
    char* rawPrintCodes = NULL;
    char* inputFuncList = NULL;
    char* inputTrackList = NULL;
    char* libList       = NULL;
    bool deleteInpList  = false;
    char*    execName   = NULL;

    TIMER(double t = timer());
    for (int32_t i = 1; i < argc; i++){
        if (!strcmp(argv[i],"--app")){
            if (argApp++){
                fprintf(stderr,"\nError : Duplicate %s option\n",argv[i]);
                printUsage();
            }
            execName = argv[++i];
        } else if (!strcmp(argv[i],"--typ")){
            if (argTyp++){
                fprintf(stderr,"\nError : Duplicate %s option\n",argv[i]);
                printUsage();
            }
            ++i;
            if (!strcmp(argv[i],"ide")){
                instType = identical_inst_type;
                extension = "ideinst";
            } else if (!strcmp(argv[i],"fnc")){
                instType = function_counter_type;
                extension = "fncinst";
            } else if (!strcmp(argv[i],"jbb")){
                instType = frequency_inst_type;
                extension = "jbbinst";
            } else if (!strcmp(argv[i],"sim")){
                instType = simulation_inst_type;
                extension = "siminst";
            } else if (!strcmp(argv[i],"csc")){
                instType = simucntr_inst_type;
                extension = "cscinst";
            } else if (!strcmp(argv[i],"ftm")){
                instType = func_timer_type;
                extension = "ftminst";
            } else if (!strcmp(argv[i],"crp")){
                instType = call_wrapper_type;
                extension = "crpinst";
            }
        } else if (!strcmp(argv[i],"--help")){
            printUsage(true, true);
        }
    }

    if (!execName){
        fprintf(stderr,"\nError : No executable is specified\n\n");
        printUsage();
    }

    if ((instType <= unknown_inst_type) || 
       (instType >= Total_InstrumentationType)){
        fprintf(stderr,"\nError : Unknown instrumentation type\n");
        printUsage();
    }

    for (int32_t i = 1; i < argc; i++){
        if (!strcmp(argv[i],"--app") || !strcmp(argv[i],"--typ")){
            ++i;
        } else if (!strcmp(argv[i],"--ext")){
            if (argExt++){
                fprintf(stderr,"\nError : Duplicate %s option\n",argv[i]);
                printUsage();
            }
            extension = argv[++i];
        } else if(!strcmp(argv[i],"--phs")){
            if (argPhs++){
                fprintf(stderr,"\nError : Duplicate %s option\n",argv[i]);
                printUsage();
            }
            if ((instType != simulation_inst_type) && (instType != simucntr_inst_type)){
                fprintf(stderr,"\nError : Option %s is not valid other than simulation\n",argv[i]);
                printUsage();
            }

            ++i;
            char* endptr = NULL;
            phaseNo = strtol(argv[i],&endptr,10);
            if ((endptr == argv[i]) || !phaseNo){
                fprintf(stderr,"\nError : Given phase number is not correct, requires > 0\n\n");
                printUsage();
            }

        } else if (!strcmp(argv[i],"--inp")){
            if (argInp++){
                fprintf(stderr,"\nError : Duplicate %s option\n",argv[i]);
                printUsage();
            }
            if ((instType != simulation_inst_type) && (instType != simucntr_inst_type)){
                fprintf(stderr,"\nError : Option %s is not valid other than simulation\n",argv[i]);
                printUsage();
            }

            inptName = argv[++i];
        } else if (!strcmp(argv[i],"--lpi")){
            loopIncl = true;
            if ((instType != simulation_inst_type) && (instType != simucntr_inst_type)){
                fprintf(stderr,"\nError : Option %s is not valid other than simulation\n",argv[i++]);
                printUsage();
            }
        } else if (!strcmp(argv[i],"--ver")){
            verbose = true;
            rawPrintCodes = argv[++i];
        } else if (!strcmp(argv[i],"--dtl")){
            extdPrnt = true;
        } else if (!strcmp(argv[i],"--lib")){
            libPath = argv[++i];
        } else if (!strcmp(argv[i],"--dry")){
            dryRun = true;
        } else if (!strcmp(argv[i],"--fbl")){
            if (inputFuncList){
                printUsage();
            }
            inputFuncList = argv[++i];
        } else if (!strcmp(argv[i],"--trk")){
            if (inputTrackList){
                printUsage();
            }
            inputTrackList = argv[++i];
        } else if (!strcmp(argv[i],"--lnc")){
            if (libList){
                printUsage();
            }
            libList = argv[++i];
        } else {
            fprintf(stderr,"\nError : Unknown switch at %s\n\n",argv[i]);
            printUsage();
        }
    }

    if (((instType == simulation_inst_type) || 
         (instType == simucntr_inst_type)) && !inptName){
        fprintf(stderr,"\nError : Input is required for cache simulation instrumentation\n\n");
        printUsage();
    }

    ASSERT((instType == simulation_inst_type) || (instType == simucntr_inst_type) || (phaseNo == 0));

    if (verbose){
        if (!rawPrintCodes){
            fprintf(stderr,"\tError: verbose option used without argument");
            printUsage();
        }
        printCodes = processPrintCodes(rawPrintCodes);
    }

    if(!libPath){
        libPath = getenv("PEBIL_LIB");
        if (!libPath){
            PRINT_ERROR("Use the -lib option or define the PEBIL_LIB variable"); 
        }
    }
    PRINT_INFOR("The instrumentation libraries will be used from %s",libPath);

    if (!inputFuncList){
        deleteInpList = true;
        char* pebilRoot = getenv("PEBIL_ROOT");
        if (!pebilRoot){
            PRINT_ERROR("Set the PEBIL_ROOT variable"); 
        }
        inputFuncList = new char[__MAX_STRING_SIZE];
        sprintf(inputFuncList, "%s/%s", pebilRoot, DEFAULT_FUNC_BLACKLIST);
    }
    PRINT_INFOR("The function blacklist is taken from %s", inputFuncList);

    if (dryRun){
        PRINT_INFOR("--dry option was used, exiting...");
        exit(0);
    }

    uint32_t stepNumber = 0;
    TIMER(double t1 = timer(), t2);

    PRINT_INFOR("******** Instrumentation Beginning ********");
    ElfFile elfFile(execName);

    elfFile.parse();
    TIMER(t2 = timer();PRINT_INFOR("___timer: Step %d Parse   : %.2f seconds",++stepNumber,t2-t1);t1=t2);

    elfFile.initSectionFilePointers();
    TIMER(t2 = timer();PRINT_INFOR("___timer: Step %d Disasm  : %.2f seconds",++stepNumber,t2-t1);t1=t2);

    elfFile.generateCFGs();
    TIMER(t2 = timer();PRINT_INFOR("___timer: Step %d GenCFG  : %.2f seconds",++stepNumber,t2-t1);t1=t2);    

    if (extdPrnt){
        elfFile.findLoops();
        TIMER(t2 = timer();PRINT_INFOR("___timer: Step %d Loop    : %.2f seconds",++stepNumber,t2-t1);t1=t2);
    }

    PRINT_MEMTRACK_STATS(__LINE__, __FILE__, __FUNCTION__);

    if (verbose){
        elfFile.print(printCodes);
        TIMER(t2 = timer();PRINT_INFOR("___timer: Step %d Print   : %.2f seconds",++stepNumber,t2-t1);t1=t2);
    }

    elfFile.verify();
    TIMER(t2 = timer();PRINT_INFOR("___timer: Step %d Verify  : %.2f seconds",++stepNumber,t2-t1);t1=t2);

    ElfFileInst* elfInst = NULL;

    if (instType == identical_inst_type){
        elfFile.dump(extension);
        return 0;
    } else if (instType == function_counter_type){
        elfInst = new FunctionCounter(&elfFile);
    } else if (instType == frequency_inst_type){
        elfInst = new BasicBlockCounter(&elfFile);
    } else if (instType == simulation_inst_type){
        elfInst = new CacheSimulation(&elfFile, inptName);
    } else if (instType == func_timer_type){
        elfInst = new FunctionTimer(&elfFile);
    } else if (instType == call_wrapper_type){
        if (!inputTrackList){
            fprintf(stderr, "\nError: option --trk needs to be given with call wrapper inst\n");
            printUsage();
        }
        ASSERT(inputTrackList);
        if (!libList){
            fprintf(stderr, "\nError: option --lnc needs to be given with call wrapper inst\n");
        }
        ASSERT(libList);
        elfInst = new CallReplace(&elfFile, inputTrackList, libList);
    }
    else {
        PRINT_ERROR("Error : invalid instrumentation type");
    }

    PRINT_MEMTRACK_STATS(__LINE__, __FILE__, __FUNCTION__);
    ASSERT(elfInst);
    ASSERT(libPath);
    ASSERT(extension);

    elfInst->setPathToInstLib(libPath);
    elfInst->setInstExtension(extension);
    if (inputFuncList){
        elfInst->setInputFunctions(inputFuncList);
    }
    
    elfInst->phasedInstrumentation();
    PRINT_MEMTRACK_STATS(__LINE__, __FILE__, __FUNCTION__);
    elfInst->print(Print_Code_Instrumentation);
    TIMER(t2 = timer();PRINT_INFOR("___timer: Instrumentation Step %d Instr   : %.2f seconds",++stepNumber,t2-t1);t1=t2);
    
    if (verbose){
        elfInst->print(printCodes);
        TIMER(t2 = timer();PRINT_INFOR("___timer: Instrumentation Step %d Print   : %.2f seconds",++stepNumber,t2-t1);t1=t2);
    }
    
    elfInst->dump();
    TIMER(t2 = timer();PRINT_INFOR("___timer: Instrumentation Step %d Dump    : %.2f seconds",++stepNumber,t2-t1);t1=t2);
    if (verbose){
        elfInst->print(printCodes);
        TIMER(t2 = timer();PRINT_INFOR("___timer: Instrumentation Step %d Print   : %.2f seconds",++stepNumber,t2-t1);t1=t2);
    }

    // arrrrrg. i can't figure out why just deleting elfInst doesn't
    // call the CallReplace destructor in this case without the cast
    if (instType == call_wrapper_type){
        delete (CallReplace*)elfInst;
        //        delete (CallReplace*)elfInst;
    } else if (instType == simulation_inst_type){
        delete (CacheSimulation*)elfInst;
    } else {
        delete elfInst;
    }

    if (deleteInpList){
        delete[] inputFuncList;
    }
    PRINT_INFOR("******** Instrumentation Successfull ********");

    TIMER(t = timer()-t;PRINT_INFOR("___timer: Total Execution Time          : %.2f seconds",t););
void CallReplace::instrument(){
    uint32_t temp32;
    uint64_t temp64;

    LineInfoFinder* lineInfoFinder = NULL;
    if (hasLineInformation()){
        lineInfoFinder = getLineInfoFinder();
    }

    InstrumentationPoint* p = addInstrumentationPoint(getProgramEntryBlock(), programEntry, InstrumentationMode_tramp, FlagsProtectionMethod_full, InstLocation_prior);
    ASSERT(p);
    if (!p->getInstBaseAddress()){
        PRINT_ERROR("Cannot find an instrumentation point at the exit function");
    }

    p = addInstrumentationPoint(getProgramExitBlock(), programExit, InstrumentationMode_tramp, FlagsProtectionMethod_full, InstLocation_prior);
    ASSERT(p);
    if (!p->getInstBaseAddress()){
        PRINT_ERROR("Cannot find an instrumentation point at the exit function");
    }

    uint64_t siteIndex = reserveDataOffset(sizeof(uint32_t));
    programEntry->addArgument(siteIndex);

    Vector<X86Instruction*> myInstPoints;
    Vector<uint32_t> myInstList;
    Vector<LineInfo*> myLineInfos;
    for (uint32_t i = 0; i < getNumberOfExposedInstructions(); i++){
        X86Instruction* instruction = getExposedInstruction(i);
        ASSERT(instruction->getContainer()->isFunction());
        Function* function = (Function*)instruction->getContainer();
        
        if (instruction->isFunctionCall()){
            Symbol* functionSymbol = getElfFile()->lookupFunctionSymbol(instruction->getTargetAddress());

            if (functionSymbol){
                //PRINT_INFOR("looking for function %s", functionSymbol->getSymbolName());
                uint32_t funcIdx = searchFileList(functionList, functionSymbol->getSymbolName());
                if (funcIdx < (*functionList).size()){
                    BasicBlock* bb = function->getBasicBlockAtAddress(instruction->getBaseAddress());
                    ASSERT(bb->containsCallToRange(0,-1));
                    ASSERT(instruction->getSizeInBytes() == Size__uncond_jump);

                    myInstPoints.append(instruction);
                    myInstList.append(funcIdx);
                    LineInfo* li = NULL;
                    if (lineInfoFinder){
                        li = lineInfoFinder->lookupLineInfo(bb);
                    }
                    myLineInfos.append(li);
                }
            }
        } 
    }
    ASSERT(myInstPoints.size() == myInstList.size());
    ASSERT(myLineInfos.size() == myInstList.size());

    uint64_t fileNames = reserveDataOffset(sizeof(char*) * myInstList.size());
    uint64_t lineNumbers = reserveDataOffset(sizeof(uint32_t) * myInstList.size());
    for (uint32_t i = 0; i < myInstList.size(); i++){
        uint32_t line = 0;
        char* fname = NOSTRING;
        if (myLineInfos[i]){
            line = myLineInfos[i]->GET(lr_line);
            fname = myLineInfos[i]->getFileName();
        }
        uint64_t filenameaddr = getInstDataAddress() + reserveDataOffset(strlen(fname) + 1);
        initializeReservedData(getInstDataAddress() + fileNames + i*sizeof(char*), sizeof(char*), &filenameaddr);
        initializeReservedData(filenameaddr, strlen(fname), fname);
        initializeReservedData(getInstDataAddress() + lineNumbers + i*sizeof(uint32_t), sizeof(uint32_t), &line);
    }
    programEntry->addArgument(fileNames);
    programEntry->addArgument(lineNumbers);

    for (uint32_t i = 0; i < myInstPoints.size(); i++){
        PRINT_INFOR("(site %d) %#llx: replacing call %s -> %s in function %s", i, myInstPoints[i]->getBaseAddress(), getFunctionName(myInstList[i]), getWrapperName(myInstList[i]), myInstPoints[i]->getContainer()->getName());
        InstrumentationPoint* pt = addInstrumentationPoint(myInstPoints[i], functionWrappers[myInstList[i]], InstrumentationMode_tramp, FlagsProtectionMethod_none, InstLocation_replace);
        if (getElfFile()->is64Bit()){
            pt->addPrecursorInstruction(X86InstructionFactory64::emitMoveRegToMem(X86_REG_CX, getInstDataAddress() + getRegStorageOffset()));
            pt->addPrecursorInstruction(X86InstructionFactory64::emitMoveImmToReg(i, X86_REG_CX));
            pt->addPrecursorInstruction(X86InstructionFactory64::emitMoveRegToMem(X86_REG_CX, getInstDataAddress() + siteIndex));
            pt->addPrecursorInstruction(X86InstructionFactory64::emitMoveMemToReg(getInstDataAddress() + getRegStorageOffset(), X86_REG_CX, true));
        } else {
            pt->addPrecursorInstruction(X86InstructionFactory32::emitMoveRegToMem(X86_REG_CX, getInstDataAddress() + getRegStorageOffset()));
            pt->addPrecursorInstruction(X86InstructionFactory32::emitMoveImmToReg(i, X86_REG_CX));
            pt->addPrecursorInstruction(X86InstructionFactory32::emitMoveRegToMem(X86_REG_CX, getInstDataAddress() + siteIndex));
            pt->addPrecursorInstruction(X86InstructionFactory32::emitMoveMemToReg(getInstDataAddress() + getRegStorageOffset(), X86_REG_CX));            
        }
    }
}
void RawSection::printBytes(uint64_t offset, uint32_t bytesPerWord, uint32_t bytesPerLine){
    fprintf(stdout, "\n");
    PRINT_INFOR("Raw bytes for RAW section %d:", sectionIndex);
    printBufferPretty(charStream() + offset, getSizeInBytes(), getSectionHeader()->GET(sh_offset) + offset, bytesPerWord, bytesPerLine);
}
void TauFunctionTrace::instrument(){
    //InstrumentationTool::instrument();

    LineInfoFinder* lineInfoFinder = NULL;
    if (hasLineInformation()){
        lineInfoFinder = getLineInfoFinder();
    }

    InstrumentationPoint* p;

    uint64_t nameAddr = reserveDataOffset(sizeof(uint64_t));
    uint64_t fileAddr = reserveDataOffset(sizeof(uint64_t));
    uint64_t lineAddr = reserveDataOffset(sizeof(uint32_t));
    uint64_t siteIndexAddr = reserveDataOffset(sizeof(uint32_t));

    uint32_t site = functionEntry->addConstantArgument();
    ASSERT(site == functionExit->addConstantArgument());

    std::pebil_map_type<uint64_t, ControlInfo> functions;
    std::vector<uint64_t> orderedfuncs;

    uint32_t sequenceId = 0;
    if (doIntro){
        // go over all functions and intrument entries/exits
        for (uint32_t i = 0; i < getNumberOfExposedFunctions(); i++){
            Function* function = getExposedFunction(i);
            uint64_t addr = function->getBaseAddress();
            if (instrumentList && !instrumentList->functionMatches(function->getName())){
                continue;
            }
            if (!strcmp(function->getName(), "_fini")){
                continue;
            }

            BasicBlock* entryBlock = function->getFlowGraph()->getEntryBlock();
            Vector<BasicBlock*>* exitPoints = function->getFlowGraph()->getExitBlocks();

            std::string c;
            c.append(function->getName());
            if (c == "_start"){
                exitPoints->append(getProgramExitBlock());
                PRINT_INFOR("Special case: inserting exit for _start inside _fini since control generally doesn't reach its exit");
            }

            ASSERT(functions.count(addr) == 0 && "Multiple functions have the same base address?");

            PRINT_INFOR("[FUNCTION index=%d] internal instrumentation: %s", sequenceId, function->getName());

            ControlInfo f = ControlInfo();
            f.name = c;
            f.file = "";
            f.line = 0;
            f.index = sequenceId++;
            f.baseaddr = addr;
            f.type = ControlType_Function;

            LineInfo* li = NULL;
            if (lineInfoFinder){
                li = lineInfoFinder->lookupLineInfo(addr);
            }

            if (li){
                f.file.append(li->getFileName());
                f.line = li->GET(lr_line);
            }

            functions[addr] = f;
            orderedfuncs.push_back(addr);

            InstrumentationPoint* prior = addInstrumentationPoint(entryBlock->getLeader(), functionEntry, InstrumentationMode_tramp, InstLocation_prior);
            prior->setPriority(InstPriority_custom3);
            assignStoragePrior(prior, f.index, site);

            for (uint32_t j = 0; j < exitPoints->size(); j++){
                InstrumentationPoint* after = addInstrumentationPoint((*exitPoints)[j]->getExitInstruction(), functionExit, InstrumentationMode_tramp, InstLocation_prior);
                after->setPriority(InstPriority_custom5);

                if (c == "_start" && j == exitPoints->size() - 1){
                    after->setPriority(InstPriority_custom6);
                }
                assignStoragePrior(after, f.index, site);
            }

            delete exitPoints;
        }

    } else {
        // go over all instructions. when we find a call, instrument it
        for (uint32_t i = 0; i < getNumberOfExposedInstructions(); i++){
            X86Instruction* x = getExposedInstruction(i);
            ASSERT(x->getContainer()->isFunction());
            Function* function = (Function*)x->getContainer();

            if (x->isFunctionCall()){
                uint64_t addr = x->getTargetAddress();
                Symbol* functionSymbol = getElfFile()->lookupFunctionSymbol(addr);
            
                if (functionSymbol){

                    if (instrumentList && !instrumentList->functionMatches(functionSymbol->getSymbolName())){
                        continue;
                    }
                    ASSERT(x->getSizeInBytes() == Size__uncond_jump);
                
                    std::string c;
                    c.append(functionSymbol->getSymbolName());
                    if (functions.count(addr) == 0){
                        PRINT_INFOR("[FUNCTION index=%d] call site instrumentation: %#lx(%s) -> %s", sequenceId, addr, function->getName(), functionSymbol->getSymbolName());

                        ControlInfo f = ControlInfo();
                        f.name = c;
                        f.file = "";
                        f.line = 0;
                        f.index = sequenceId++;
                        f.baseaddr = addr;
                        f.type = ControlType_Function;

                        LineInfo* li = NULL;
                        if (lineInfoFinder){
                            li = lineInfoFinder->lookupLineInfo(addr);
                        }

                        if (li){
                            f.file.append(li->getFileName());
                            f.line = li->GET(lr_line);
                        }

                        functions[addr] = f;
                        orderedfuncs.push_back(addr);
                    }
                    uint32_t idx = functions[addr].index;

                    Base* exitpoint = (Base*)x;
                    if (c == "__libc_start_main"){
                        PRINT_INFOR("Special case: inserting exit for __libc_start_main inside _fini since this call generally doesn't return");
                        exitpoint = (Base*)getProgramExitBlock();
                    }

                    InstrumentationPoint* prior = addInstrumentationPoint(x, functionEntry, InstrumentationMode_tramp, InstLocation_prior);
                    InstrumentationPoint* after = addInstrumentationPoint(exitpoint, functionExit, InstrumentationMode_tramp, InstLocation_after);

                    assignStoragePrior(prior, idx, site);
                    assignStoragePrior(after, idx, site);
                }
            }
        }
    }


    // set up argument passing for function registration
    functionRegister->addArgument(nameAddr);
    functionRegister->addArgument(fileAddr);
    functionRegister->addArgument(lineAddr);
    uint32_t siteReg = functionRegister->addConstantArgument();


    // go over every function that was found, insert a registration call at program start
    for (std::vector<uint64_t>::iterator it = orderedfuncs.begin(); it != orderedfuncs.end(); it++){
        uint64_t addr = *it;
        ControlInfo f = functions[addr];
       
        ASSERT(f.baseaddr == addr);

        InstrumentationPoint* p = addInstrumentationPoint(getProgramEntryBlock(), functionRegister, InstrumentationMode_tramp);
        p->setPriority(InstPriority_custom1);

        const char* cstring = f.name.c_str();
        uint64_t storage = reserveDataOffset(strlen(cstring) + 1);
        initializeReservedData(getInstDataAddress() + storage, strlen(cstring), (void*)cstring);
        assignStoragePrior(p, getInstDataAddress() + storage, getInstDataAddress() + nameAddr, X86_REG_CX, getInstDataAddress() + getRegStorageOffset());

        const char* cstring2 = f.file.c_str();
        if (f.file == ""){
            assignStoragePrior(p, NULL, getInstDataAddress() + fileAddr, X86_REG_CX, getInstDataAddress() + getRegStorageOffset());            
        } else {
            storage = reserveDataOffset(strlen(cstring2) + 1);
            initializeReservedData(getInstDataAddress() + storage, strlen(cstring2), (void*)cstring2);
            assignStoragePrior(p, getInstDataAddress() + storage, getInstDataAddress() + fileAddr, X86_REG_CX, getInstDataAddress() + getRegStorageOffset());
        }

        assignStoragePrior(p, f.line, getInstDataAddress() + lineAddr, X86_REG_CX, getInstDataAddress() + getRegStorageOffset());
        assignStoragePrior(p, f.index, siteReg);
    }


    if (!instrumentList){
        return;
    }

    // instrument loops
    std::pebil_map_type<uint64_t, ControlInfo> loops;
    std::vector<uint64_t> orderedloops;

    loopRegister->addArgument(nameAddr);
    loopRegister->addArgument(fileAddr);
    loopRegister->addArgument(lineAddr);
    ASSERT(siteReg == loopRegister->addConstantArgument());

    for (uint32_t i = 0; i < getNumberOfExposedFunctions(); i++){
        Function* function = getExposedFunction(i);
        FlowGraph* flowgraph = function->getFlowGraph();

        if (!instrumentList->loopMatches(function->getName())){
            continue;
        }

        for (uint32_t j = 0; j < flowgraph->getNumberOfLoops(); j++){
            Loop* loop = flowgraph->getLoop(j);
            uint32_t depth = flowgraph->getLoopDepth(loop);
            BasicBlock* head = loop->getHead();
            uint64_t addr = head->getBaseAddress();

            // only want outer-most (depth == 1) loops
            if (depth != 1){
                continue;
            }

            BasicBlock** allLoopBlocks = new BasicBlock*[loop->getNumberOfBlocks()];
            loop->getAllBlocks(allLoopBlocks);

            // reject any loop that contains an indirect branch since it is difficult to guarantee that we will find all exits
            bool badLoop = false;
            for (uint32_t k = 0; k < loop->getNumberOfBlocks() && !badLoop; k++){
                BasicBlock* bb = allLoopBlocks[k];
                if (bb->getExitInstruction()->isIndirectBranch()){
                    badLoop = true;
                }
            }

            if (badLoop){
                PRINT_WARN(20, "Loop at %#lx in %s contains an indirect branch so we can't guarantee that all exits will be found. skipping!", addr, function->getName());
                delete[] allLoopBlocks;
                continue;
            }

            std::string c;
            c.append(function->getName());

            uint32_t entryc = 0;

            Vector<LoopPoint*>* points = NULL;

            // if addr already exists, it means that two loops share a head and we are going to merge them logically here
            if (loops.count(addr) == 0){

                ControlInfo f = ControlInfo();
                f.name = c;
                f.file = "";
                f.line = 0;
                f.index = sequenceId++;
                f.baseaddr = addr;
                f.type = ControlType_Loop;

                points = new Vector<LoopPoint*>();
                f.info = points;

                LineInfo* li = NULL;
                if (lineInfoFinder){
                    li = lineInfoFinder->lookupLineInfo(addr);
                }
                if (li){
                    f.file.append(li->getFileName());
                    f.line = li->GET(lr_line);
                }

                loops[addr] = f;
                orderedloops.push_back(addr);

                // find entries into this loop
                for (uint32_t k = 0; k < head->getNumberOfSources(); k++){
                    BasicBlock* source = head->getSourceBlock(k);

                    if (!loop->isBlockIn(source->getIndex())){
                        LoopPoint* lp = new LoopPoint();
                        points->append(lp);

                        lp->flowgraph = flowgraph;
                        lp->source = source;
                        lp->target = NULL;
                        lp->entry = true;
                        lp->interpose = false;

                        if (source->getBaseAddress() + source->getNumberOfBytes() != head->getBaseAddress()){
                            lp->interpose = true;
                            lp->target = head;
                        }
                        entryc++;
                    }
                }
            }

            ControlInfo f = loops[addr];
            points = f.info;

            // find exits from this loop
            uint32_t exitc = 0;
            for (uint32_t k = 0; k < loop->getNumberOfBlocks(); k++){
                BasicBlock* bb = allLoopBlocks[k];
                if (bb->endsWithReturn()){
                    LoopPoint* lp = new LoopPoint();
                    points->append(lp);

                    lp->flowgraph = flowgraph;
                    lp->source = bb;
                    lp->target = NULL;
                    lp->entry = false;
                    lp->interpose = false;
                    exitc++;
                }

                for (uint32_t m = 0; m < bb->getNumberOfTargets(); m++){
                    BasicBlock* target = bb->getTargetBlock(m);
                    if (!loop->isBlockIn(target->getIndex())){
                        LoopPoint* lp = new LoopPoint();
                        points->append(lp);

                        lp->flowgraph = flowgraph;
                        lp->source = bb;
                        lp->target = NULL;
                        lp->entry = false;
                        lp->interpose = false;

                        if (target->getBaseAddress() != bb->getBaseAddress() + bb->getNumberOfBytes()){
                            lp->interpose = true;
                            lp->target = target;
                        }
                        exitc++;
                    }
                }
            }

            PRINT_INFOR("[LOOP index=%d] loop instrumentation %#lx(%s) has %d entries and %d exits", sequenceId-1, addr, function->getName(), entryc, exitc);

            delete[] allLoopBlocks;
        }
    }

    // go over every loop that was found, insert a registration call at program start
    // [source_addr -> [target_addr -> interposed]]
    std::pebil_map_type<uint64_t, std::pebil_map_type<uint64_t, BasicBlock*> > idone;
    for (std::vector<uint64_t>::iterator it = orderedloops.begin(); it != orderedloops.end(); it++){
        uint64_t addr = *it;
        ControlInfo f = loops[addr];
       
        ASSERT(f.baseaddr == addr);

        InstrumentationPoint* p = addInstrumentationPoint(getProgramEntryBlock(), loopRegister, InstrumentationMode_tramp);
        p->setPriority(InstPriority_custom2);

        const char* cstring = f.name.c_str();
        uint64_t storage = reserveDataOffset(strlen(cstring) + 1);
        initializeReservedData(getInstDataAddress() + storage, strlen(cstring), (void*)cstring);
        assignStoragePrior(p, getInstDataAddress() + storage, getInstDataAddress() + nameAddr, X86_REG_CX, getInstDataAddress() + getRegStorageOffset());

        const char* cstring2 = f.file.c_str();
        if (f.file == ""){
            assignStoragePrior(p, NULL, getInstDataAddress() + fileAddr, X86_REG_CX, getInstDataAddress() + getRegStorageOffset());            
        } else {
            storage = reserveDataOffset(strlen(cstring2) + 1);
            initializeReservedData(getInstDataAddress() + storage, strlen(cstring2), (void*)cstring2);
            assignStoragePrior(p, getInstDataAddress() + storage, getInstDataAddress() + fileAddr, X86_REG_CX, getInstDataAddress() + getRegStorageOffset());
        }

        assignStoragePrior(p, f.line, getInstDataAddress() + lineAddr, X86_REG_CX, getInstDataAddress() + getRegStorageOffset());
        assignStoragePrior(p, f.index, siteReg);

        // now add instrumentation for each loop entry/exit
        Vector<LoopPoint*>* v = (Vector<LoopPoint*>*)f.info;
        for (uint32_t i = 0; i < v->size(); i++){
            LoopPoint* lp = (*v)[i];
            ASSERT(lp->flowgraph && lp->source);

            BasicBlock* bb = lp->source;
            if (lp->interpose){
                ASSERT(lp->target);
                if (idone.count(lp->source->getBaseAddress()) == 0){
                    idone[lp->source->getBaseAddress()] = std::pebil_map_type<uint64_t, BasicBlock*>();
                }
                if (idone[lp->source->getBaseAddress()].count(lp->target->getBaseAddress()) == 0){
                    idone[lp->source->getBaseAddress()][lp->target->getBaseAddress()] = initInterposeBlock(lp->flowgraph, lp->source->getIndex(), lp->target->getIndex());
                }

                bb = idone[lp->source->getBaseAddress()][lp->target->getBaseAddress()];

            } else {
                ASSERT(lp->target == NULL);
            }

            Base* pt = (Base*)bb;
            InstLocations loc = InstLocation_prior;

            // if exit block falls through, we must place the instrumentation point at the very end of the block
            if (!lp->entry && !lp->interpose){
                pt = (Base*)bb->getExitInstruction();
                if (!bb->getExitInstruction()->isReturn()){
                    loc = InstLocation_after;
                }
            }

            InstrumentationFunction* inf = functionExit;
            if (lp->entry){
                inf = functionEntry;
            }

            InstrumentationPoint* p = addInstrumentationPoint(pt, inf, InstrumentationMode_tramp, loc);
            p->setPriority(InstPriority_custom4);
            assignStoragePrior(p, f.index, site);

            delete lp;
        }
        delete v;
    }

}
void BasicBlockCounter::instrument() 
{
    InstrumentationTool::instrument();
    ASSERT(currentPhase == ElfInstPhase_user_reserve && "Instrumentation phase order must be observed"); 
    uint32_t temp32;

    LineInfoFinder* lineInfoFinder = NULL;
    if (hasLineInformation()){
        lineInfoFinder = getLineInfoFinder();
    }

    uint64_t lineArray = reserveDataOffset(getNumberOfExposedBasicBlocks() * sizeof(uint32_t));
    uint64_t fileNameArray = reserveDataOffset(getNumberOfExposedBasicBlocks() * sizeof(char*));
    uint64_t funcNameArray = reserveDataOffset(getNumberOfExposedBasicBlocks() * sizeof(char*));
    uint64_t hashCodeArray = reserveDataOffset(getNumberOfExposedBasicBlocks() * sizeof(uint64_t));
    uint64_t appName = reserveDataOffset((strlen(getApplicationName()) + 1) * sizeof(char));
    initializeReservedData(getInstDataAddress() + appName, strlen(getApplicationName()) + 1, getApplicationName());
    uint64_t instExt = reserveDataOffset((strlen(getInstSuffix()) + 1) * sizeof(char));
    initializeReservedData(getInstDataAddress() + instExt, strlen(getInstSuffix()) + 1, getInstSuffix());

    // the number blocks in the code
    uint64_t counterArrayEntries = reserveDataOffset(sizeof(uint32_t));

    // an array of counters. note that everything is passed by reference
    uint64_t counterArray = reserveDataOffset(getNumberOfExposedBasicBlocks() * sizeof(uint32_t));

    exitFunc->addArgument(counterArray);
    exitFunc->addArgument(appName);
    exitFunc->addArgument(instExt);

    InstrumentationPoint* p = addInstrumentationPoint(getProgramExitBlock(), exitFunc, InstrumentationMode_tramp);
    if (!p->getInstBaseAddress()){
        PRINT_ERROR("Cannot find an instrumentation point at the exit function");
    }

    temp32 = 0;
    for (uint32_t i = 0; i < getNumberOfExposedBasicBlocks(); i++){
        initializeReservedData(getInstDataAddress() + counterArray + i*sizeof(uint32_t), sizeof(uint32_t), &temp32);
    }

    // the number of inst points
    entryFunc->addArgument(counterArrayEntries);
    temp32 = getNumberOfExposedBasicBlocks();
    initializeReservedData(getInstDataAddress() + counterArrayEntries, sizeof(uint32_t), &temp32);

    // an array for line numbers
    entryFunc->addArgument(lineArray);
    // an array for file name pointers
    entryFunc->addArgument(fileNameArray);
    // an array for function name pointers
    entryFunc->addArgument(funcNameArray);
    // an array for hashcodes
    entryFunc->addArgument(hashCodeArray);

    p = addInstrumentationPoint(getProgramEntryBlock(), entryFunc, InstrumentationMode_tramp, FlagsProtectionMethod_full, InstLocation_prior);
    p->setPriority(InstPriority_userinit);
    if (!p->getInstBaseAddress()){
        PRINT_ERROR("Cannot find an instrumentation point at the entry block");
    }

    uint64_t noDataAddr = getInstDataAddress() + reserveDataOffset(strlen(NOSTRING) + 1);
    char* nostring = new char[strlen(NOSTRING) + 1];
    sprintf(nostring, "%s\0", NOSTRING);
    initializeReservedData(noDataAddr, strlen(NOSTRING) + 1, nostring);

    PRINT_DEBUG_MEMTRACK("There are %d instrumentation points", getNumberOfExposedBasicBlocks());
    Vector<BasicBlock*>* allBlocks = new Vector<BasicBlock*>();
    Vector<LineInfo*>* allLineInfos = new Vector<LineInfo*>();

    uint32_t noProtPoints = 0;
    uint32_t complexSelection = 0;
    for (uint32_t i = 0; i < getNumberOfExposedBasicBlocks(); i++){

        BasicBlock* bb = getExposedBasicBlock(i);
        LineInfo* li = NULL;
        if (lineInfoFinder){
            li = lineInfoFinder->lookupLineInfo(bb);
        }
        Function* f = bb->getFunction();

        (*allBlocks).append(bb);
        (*allLineInfos).append(li);

        if (i % 1000 == 0){
            PRINT_DEBUG_MEMTRACK("inst point %d", i);
            PRINT_MEMTRACK_STATS(__LINE__, __FILE__, __FUNCTION__);            
        }

        if (li){
            uint32_t line = li->GET(lr_line);
            initializeReservedData(getInstDataAddress() + lineArray + sizeof(uint32_t)*i, sizeof(uint32_t), &line);

            uint64_t filename = reserveDataOffset(strlen(li->getFileName()) + 1);
            uint64_t filenameAddr = getInstDataAddress() + filename;
            initializeReservedData(getInstDataAddress() + fileNameArray + i*sizeof(char*), sizeof(char*), &filenameAddr);
            initializeReservedData(getInstDataAddress() + filename, strlen(li->getFileName()) + 1, (void*)li->getFileName());

        } else {
            temp32 = 0;
            initializeReservedData(getInstDataAddress() + lineArray + sizeof(uint32_t)*i, sizeof(uint32_t), &temp32);
            initializeReservedData(getInstDataAddress() + fileNameArray + i*sizeof(char*), sizeof(char*), &noDataAddr);
        }
        uint64_t funcname = reserveDataOffset(strlen(f->getName()) + 1);
        uint64_t funcnameAddr = getInstDataAddress() + funcname;
        initializeReservedData(getInstDataAddress() + funcNameArray + i*sizeof(char*), sizeof(char*), &funcnameAddr);
        initializeReservedData(getInstDataAddress() + funcname, strlen(f->getName()) + 1, (void*)f->getName());

        uint64_t hashValue = bb->getHashCode().getValue();
        initializeReservedData(getInstDataAddress() + hashCodeArray + i*sizeof(uint64_t), sizeof(uint64_t), &hashValue);
        
        InstrumentationSnippet* snip = new InstrumentationSnippet();
        uint64_t counterOffset = counterArray + (i * sizeof(uint32_t));

        // snippet contents, in this case just increment a counter
        if (is64Bit()){
            snip->addSnippetInstruction(X86InstructionFactory64::emitAddImmByteToMem(1, getInstDataAddress() + counterOffset));
        } else {
            snip->addSnippetInstruction(X86InstructionFactory32::emitAddImmByteToMem(1, getInstDataAddress() + counterOffset));
        }

        // do not generate control instructions to get back to the application, this is done for
        // the snippet automatically during code generation
            
        // register the snippet we just created
        addInstrumentationSnippet(snip);            
            
        // register an instrumentation point at the function that uses this snippet
        FlagsProtectionMethods prot = FlagsProtectionMethod_light;
#ifndef NO_REG_ANALYSIS
        if (bb->getLeader()->allFlagsDeadIn()){
            prot = FlagsProtectionMethod_none;
            noProtPoints++;
        }
        for (uint32_t j = 0; j < bb->getNumberOfInstructions(); j++){
            if (bb->getInstruction(j)->allFlagsDeadIn() || bb->getInstruction(j)->allFlagsDeadOut()){
                complexSelection++;
                break;
            }
        }
#endif
        InstrumentationPoint* p = addInstrumentationPoint(bb, snip, InstrumentationMode_inline, prot);
    }
    PRINT_MEMTRACK_STATS(__LINE__, __FILE__, __FUNCTION__);
#ifdef NO_REG_ANALYSIS
    PRINT_WARN(10, "Warning: register analysis disabled");
#endif
    PRINT_INFOR("Excluding flags protection for %d/%d instrumentation points", noProtPoints, getNumberOfExposedBasicBlocks());
    //PRINT_INFOR("complex inst point selection: %d/%d instrumentation points", complexSelection, getNumberOfExposedBasicBlocks());

    printStaticFile(allBlocks, allLineInfos);

    delete[] nostring;
    delete allBlocks;
    delete allLineInfos;

    ASSERT(currentPhase == ElfInstPhase_user_reserve && "Instrumentation phase order must be observed"); 
}
void SectionHeader::print() { 

    char tmpstr[__MAX_STRING_SIZE];
    PRINT_INFOR("SHeader : %d",index);
    PRINT_INFOR("\tSnam : %s",getSectionNamePtr() ? getSectionNamePtr() : "<none>");
    if(GET(sh_type) <= SHT_DYNSYM){
        PRINT_INFOR("\tStyp : %s",STypeNames[GET(sh_type)]);
    } else {
        char* ptr = "UNK";
        switch(GET(sh_type)){
            case SHT_INIT_ARRAY: ptr="INIT_ARRAY"; break;
            case SHT_FINI_ARRAY: ptr="FINI_ARRAY"; break;
            case SHT_PREINIT_ARRAY: ptr="PREINIT_ARRAY"; break;
            case SHT_GROUP: ptr="GROUP"; break;
            case SHT_SYMTAB_SHNDX: ptr="SYMTAB_SHNDX"; break;
            case SHT_NUM: ptr="NUM"; break;
            case SHT_LOOS: ptr="LOOS"; break;
            case SHT_GNU_HASH: ptr="GNU_HASH"; break;
            case SHT_GNU_LIBLIST: ptr="GNU_LIBLIST"; break;
            case SHT_CHECKSUM: ptr="CHECKSUM"; break;
            case SHT_LOSUNW: ptr="LOSUNW"; break;
            case SHT_SUNW_COMDAT: ptr="SUNW_COMDAT"; break;
            case SHT_SUNW_syminfo: ptr="SUNW_syminfo"; break;
            case SHT_GNU_verdef: ptr="GNU_verdef"; break;
            case SHT_GNU_verneed: ptr="GNU_verneed"; break;
            case SHT_GNU_versym: ptr="GNU_versym"; break;
            case SHT_LOPROC: ptr="LOPROC"; break;
            case SHT_HIPROC: ptr="HIPROC"; break;
            case SHT_LOUSER: ptr="LOUSER"; break;
            case SHT_HIUSER: ptr="HIUSER"; break;
            default: break;
        }
        PRINT_INFOR("\tStyp : %s",ptr);
    }
    sprintf(tmpstr,"READ");
    for(uint32_t i=0;i<=10;i++){
        if(GET(sh_flags) & (0x1 << i)){
            strcat(tmpstr," + ");
            strcat(tmpstr,SFlagNames[i]);
        }
    }
    PRINT_INFOR("\tSflg : %s",tmpstr);
    PRINT_INFOR("\tSoff : @%llx with %lluB",GET(sh_offset),GET(sh_size));
    if(GET(sh_addr)){
        PRINT_INFOR("\tSvad : %#llx",GET(sh_addr));
    } else {
        PRINT_INFOR("\tSvad : <no virtual address>");
    }
    if(GET(sh_entsize)){
        PRINT_INFOR("\tSent : %lldB each",GET(sh_entsize));
    } else {
        PRINT_INFOR("\tSent : <no fixed-size entries>",GET(sh_addr));
    }
    uint64_t alignment = GET(sh_addralign);
    for(uint32_t i=0;i<64;i++){
        if((alignment >> i) & 0x1){
            alignment = i;
        }
    }
    PRINT_INFOR("\talig : 2**%llu",alignment);

    uint32_t linkValue = GET(sh_link);
    uint32_t infoValue = GET(sh_info);
    PRINT_INFOR("\tlink: %d", linkValue);
    PRINT_INFOR("\tinfo: %d", infoValue);
    switch(GET(sh_type)){
        case SHT_DYNAMIC:
        {
            sprintf(tmpstr,"string table at sect %d",linkValue);
            ASSERT(!infoValue);
            break;
        }
        case SHT_HASH:
        {
            sprintf(tmpstr,"symbol table at sect %d",linkValue);
            ASSERT(!infoValue);
            break;
        }
        case SHT_REL:
        case SHT_RELA:
            sprintf(tmpstr,"symbol table at sect %d and relocation applies to sect %d",linkValue,infoValue);
            break;
        case SHT_SYMTAB:
        case SHT_DYNSYM:
            sprintf(tmpstr,"string table at sect %d and symbol table index of last local sym %d",linkValue,infoValue-1);
            break;
        default: {
            if((linkValue != SHN_UNDEF) || infoValue){
                sprintf(tmpstr,"unknown link %d and %d",linkValue,infoValue-1);
            } else {
                sprintf(tmpstr,"<no extra info>");
                ASSERT(linkValue == SHN_UNDEF);
                ASSERT(!infoValue);
            }
        }
    }
    PRINT_INFOR("\tinfo : %s",tmpstr);
}
void RelocationAddend64::print(char* str){
    if(!str) str = "";
    PRINT_INFOR("\trel%5d -- off:%#12llx stx:%5lld ad:%12lld %25s -- %s",index,GET(r_offset),ELF64_R_SYM(GET(r_info)),
                GET(r_addend),
                ELF64_R_TYPE(GET(r_info)) <= R_386_NUM ? RTypeNames[ELF64_R_TYPE(GET(r_info))] : "UNK",str);
}