/*
 * See the dyninst/COPYRIGHT file for copyright information.
 * 
 * We provide the Paradyn Tools (below described as "Paradyn")
 * on an AS IS basis, and do not warrant its validity or performance.
 * We reserve the right to update, modify, or discontinue this
 * software at any time.  We shall have no obligation to supply such
 * updates or modifications or any other form of support to you.
 * 
 * By your use of Paradyn, you understand and agree that we (or any
 * other person or entity with proprietary rights in Paradyn) are
 * under no obligation to provide either maintenance services,
 * update services, notices of latent defects, or correction of
 * defects for Paradyn.
 * 
 * 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <string>
#include <fstream>

#include "image.h"
#include "common/h/arch.h"
#include "parRegion.h"
#include "util.h"
#include "inst.h"
#include "debug.h"
#include "function.h"
#include "Parsing.h"

#include "common/h/Timer.h"
#include "common/h/debugOstream.h"
#include "common/h/pathName.h"
#include "common/h/MappedFile.h"

#include "dyninstAPI/h/BPatch_flowGraph.h"
#include "dynutil/h/util.h"

#include "symtabAPI/h/Function.h"

#include "parseAPI/h/InstructionSource.h"
#include "parseAPI/h/CodeObject.h"
#include "parseAPI/h/CFG.h"

#if defined(TIMED_PARSE)
#include <sys/time.h>
#endif

#if defined( USES_DWARF_DEBUG )
#include "dwarf.h"
#include "libdwarf.h"
#endif

#if defined(i386_unknown_nt4_0)
#include <dbghelp.h>
//#include <cvconst.h>
#endif

#if defined(os_vxworks)
#include "dyninstAPI/src/vxworks.h"
#endif

// For callbacks
#include "dyninstAPI/src/mapped_object.h" 

AnnotationClass<image_variable> ImageVariableUpPtrAnno("ImageVariableUpPtrAnno");
AnnotationClass<parse_func> ImageFuncUpPtrAnno("ImageFuncUpPtrAnno");
pdvector<image*> allImages;

using namespace std;
using namespace Dyninst;
using namespace Dyninst::ParseAPI;

using Dyninst::SymtabAPI::Symtab;
using Dyninst::SymtabAPI::Symbol;
using Dyninst::SymtabAPI::Region;
using Dyninst::SymtabAPI::Variable;
using Dyninst::SymtabAPI::Module;

char main_function_names[NUMBER_OF_MAIN_POSSIBILITIES][20] = {
    "main",
    "DYNINST_pltMain",
    "_main",
    "WinMain",
    "_WinMain",
    "wWinMain",
    "_wWinMain",
    "tls_cb_0"};

string fileDescriptor::emptyString(string(""));
fileDescriptor::fileDescriptor() {
    // This shouldn't be called... must be public for pdvector, though
}

bool fileDescriptor::IsEqual(const fileDescriptor &fd) const {
    // Don't test isShared, only file name and addresses
    bool file_match_ = false;

    // Annoying... we often get "foo vs ./foo" or such. So consider it a match
    // if either file name is prefixed by the other; we don't get trailing crud.
    string::size_type len1 = file_.length();
    string::size_type len2 = fd.file_.length();
  
    if(((len1>=len2) && (file_.substr(len1-len2,len2) == fd.file_))
       || ((len2>len1) && (fd.file_.substr(len2-len1,len1) == file_)))
        file_match_ = true;   
#if defined(os_linux)
    struct stat buf1;
    struct stat buf2;
    if (!stat(file_.c_str(),&buf1)
        && !stat(fd.file_.c_str(),&buf2)
        && buf1.st_ino == buf2.st_ino) {
        file_match_ = true;
    }
#endif  

#if defined(os_windows)
    if(extract_pathname_tail(file_) == extract_pathname_tail(fd.file_)) file_match_ = true;
#endif
#if 0
    cerr << hex << "Addr comparison: " << code_ << " ? " << fd.code_
         << ", " << data_ << " ? " << fd.data_ 
         << ", " << dynamic_ << " ? " << fd.dynamic_ << dec << endl;
#endif
    bool addr_match = ((code_ == fd.code_ && data_ == fd.data_) ||
                       (dynamic_ && dynamic_ == fd.dynamic_));
#if 0
    cerr << "file " << file_match_ 
         << ", addr " << addr_match
         << ", member_ " << (member_ == fd.member_)
         << ", pid_ " << (pid_ == fd.pid_) << endl;
#endif
    if (file_match_ &&
        (addr_match) &&
        (member_ == fd.member_) &&
        (pid_ == fd.pid_))
        return true;
    else
        return false;
}

// only for non-files
void* fileDescriptor::rawPtr()
{
#if defined(os_windows)

    return rawPtr_;

#else

    return NULL;

#endif
}


// All debug_ostream vrbles are defined in process.C (for no particular reason)
extern unsigned enable_pd_sharedobj_debug;

int codeBytesSeen = 0;

#if defined(ppc32_linux) || defined(ppc32_bgp) || defined(ppc64_linux) || defined(ppc64_bgq)

#include <dataflowAPI/h/slicing.h>
#include <dataflowAPI/h/SymEval.h>
#include <dataflowAPI/h/AbslocInterface.h>
#include <dataflowAPI/h/Absloc.h>
#include <dynutil/h/DynAST.h>

namespace {
    /* On PPC GLIBC (32 & 64 bit) the address of main is in a structure
       located in either .data or .rodata, depending on whether the 
       binary is PIC. The structure has the following format:

        struct 
        {
            void * // "small data area base"
            main   // pointer to main
            init   // pointer to init
            fini   // pointer to fini
        }

        This structure is passed in GR8 as an argument to libc_start_main.

        Annoyingly, the value in GR8 is computed in several different ways,
        depending on how GLIBC was compiled.

        This code follows the i386 linux version closely otherwise.
    */

    class Default_Predicates : public Slicer::Predicates {};

    /* This visitor is capable of simplifying constant value computations
       that involve additions and concatenations (lis instruction). This
       is sufficient to handle the startup struct address calculation in
       GLIBC that we have seen; if additional variants are introduced
       (refer to start.S in glibc or equivalently to the compiled library)
       this visitor should be expanded to handle any new operations */
        
    class SimpleArithVisitor : public ASTVisitor {

        using ASTVisitor::visit;

        virtual ASTPtr visit(AST * a) {return a->ptr();};
        virtual ASTPtr visit(DataflowAPI::BottomAST *a) {return a->ptr(); };
        virtual ASTPtr visit(DataflowAPI::ConstantAST *c) {return c->ptr();};
        virtual ASTPtr visit(DataflowAPI::VariableAST *v) {return v->ptr();};

        virtual AST::Ptr visit(DataflowAPI::RoseAST * r) {
            using namespace DataflowAPI;

            AST::Children newKids;
            for(unsigned i=0;i<r->numChildren();++i) {
                newKids.push_back(r->child(i)->accept(this));
            }

            switch(r->val().op) {
                case ROSEOperation::addOp:
                    assert(newKids.size() == 2);
                    if(newKids[0]->getID() == AST::V_ConstantAST &&
                       newKids[1]->getID() == AST::V_ConstantAST)
                    {
                        ConstantAST::Ptr c1 = ConstantAST::convert(newKids[0]);
                        ConstantAST::Ptr c2 = ConstantAST::convert(newKids[1]);
                        return ConstantAST::create(
                            Constant(c1->val().val+c2->val().val));
                    }
                    break;
                case ROSEOperation::concatOp:
                    assert(newKids.size() == 2);
                    if(newKids[0]->getID() == AST::V_ConstantAST &&
                       newKids[1]->getID() == AST::V_ConstantAST)
                    {
                        ConstantAST::Ptr c1 = ConstantAST::convert(newKids[0]);
                        ConstantAST::Ptr c2 = ConstantAST::convert(newKids[1]);
                        unsigned long result = c1->val().val;
                        result |= (c2->val().val << c2->val().size);
                        return ConstantAST::create(result);
                    }
                    break;
                default:
                    startup_printf("%s[%d] unhandled operation in simplification\n",FILE__,__LINE__);
            }
        
            return RoseAST::create(r->val(), newKids);
        }
    };

    struct libc_startup_info {
        void * sda;
        void * main_addr;
        void * init_addr;
        void * fini_addr;
    };

    /*
     * b ends with a call to libc_start_main. We are looking for the
     * value in GR8, which is the address of a structure that contains
     * the address to main
     */
    Address evaluate_main_address(Symtab * linkedFile, Function * f, Block *b)
    {
        using namespace DataflowAPI;
        using namespace InstructionAPI;
        // looking for the *last* instruction in the block
        // that defines GR8
    
        Instruction::Ptr r8_def;
        Address r8_def_addr;
    
        InstructionDecoder dec(
            b->region()->getPtrToInstruction(b->start()),
            b->end()-b->start(),
            b->region()->getArch());

        RegisterAST::Ptr r8( new RegisterAST(ppc32::r8) );

        Address cur_addr = b->start();
        while(Instruction::Ptr cur = dec.decode()) {
            if(cur->isWritten(r8)) {
                r8_def = cur;
                r8_def_addr = cur_addr;  
            }
            cur_addr += cur->size();
        }
        if(!r8_def)
            return 0;

        // Get all of the assignments that happen in this instruction
        AssignmentConverter conv(true);
        vector<Assignment::Ptr> assigns;
        conv.convert(r8_def,r8_def_addr,f,b,assigns);

        // find the one we care about (r8)
        vector<Assignment::Ptr>::iterator ait = assigns.begin();
        for( ; ait != assigns.end(); ++ait) {
            AbsRegion & outReg = (*ait)->out();
            Absloc const& loc = outReg.absloc();
            if(loc.reg() == r8->getID())
                break;
        }
        if(ait == assigns.end()) {
            return 0;
        }

        // Slice back to the definition of R8, and, if possible, simplify
        // to a constant
        Slicer slc(*ait,b,f);
        Default_Predicates preds;
        Graph::Ptr slg = slc.backwardSlice(preds);
        DataflowAPI::Result_t sl_res;
        DataflowAPI::SymEval::expand(slg,sl_res);
        AST::Ptr calculation = sl_res[*ait];
        SimpleArithVisitor visit; 
        AST::Ptr simplified = calculation->accept(&visit);
        //printf("after simplification:\n%s\n",simplified->format().c_str());
        if(simplified->getID() == AST::V_ConstantAST) { 
            ConstantAST::Ptr cp = ConstantAST::convert(simplified);
            Address ss_addr = cp->val().val;

            // need a pointer to the image data
            SymtabAPI::Region * dreg = linkedFile->findEnclosingRegion(ss_addr);
        
            if(dreg) {
                struct libc_startup_info * si =
                    (struct libc_startup_info *)(
                        ((Address)dreg->getPtrToRawData()) + 
                        ss_addr - (Address)dreg->getMemOffset());
                return (Address)si->main_addr;
            }
        }

        return 0;
    }
}
#endif

/* 
 * Search for the Main Symbols in the list of symbols, Only in case
 * if the file is a shared object. If not present add them to the
 * list
 */
void image::findMain()
{
#if defined(ppc32_linux) || defined(ppc32_bgp)
    using namespace Dyninst::InstructionAPI;

    if(!desc_.isSharedObject())
    {
    	bool foundMain = false;
    	bool foundStart = false;
    	bool foundFini = false;
    	//check if 'main' is in allsymbols
        vector <SymtabAPI::Function *> funcs;
        if (linkedFile->findFunctionsByName(funcs, "main") ||
            linkedFile->findFunctionsByName(funcs, "_main"))
            foundMain = true;
        else if (linkedFile->findFunctionsByName(funcs, "_start"))
            foundStart = true;
        else if (linkedFile->findFunctionsByName(funcs, "_fini"))
            foundFini = true;
    
    	Region *eReg = NULL;
    	bool foundText = linkedFile->findRegion(eReg, ".text");
        if (foundText == false) {
            return;
        }
	
    	if( !foundMain )
    	{
            logLine("No main symbol found: attempting to create symbol for main\n");
            const unsigned char* p;
            p = (( const unsigned char * ) eReg->getPtrToRawData());

            Address mainAddress = 0;

	        bool parseInAllLoadableRegions = (BPatch_normalMode != mode_);
	        SymtabCodeSource scs(linkedFile, filt, parseInAllLoadableRegions);
            CodeObject tco(&scs,NULL,NULL,false);

            tco.parse(eReg->getMemOffset(),false);
            set<CodeRegion *> regions;
            scs.findRegions(eReg->getMemOffset(),regions);
            if(regions.empty()) {
                // express puzzlement
                return;
            }
            SymtabCodeRegion * reg = 
                static_cast<SymtabCodeRegion*>(*regions.begin());
            Function * func = 
                tco.findFuncByEntry(reg,eReg->getMemOffset());
            if(!func) {
                // again, puzzlement
                return;
            }

            const Function::edgelist & calls = func->callEdges();
            if(calls.size() != 1) {
                startup_printf("%s[%d] _start has unexpected number (%d) of"
                               " call edges, bailing on findMain()\n",
                    FILE__,__LINE__,calls.size());
                return; 
            }
            Function::edgelist::iterator cit = calls.begin();
            Block * b = (*cit)->src();

            mainAddress = evaluate_main_address(linkedFile,func,b);
            if(0 == mainAddress || !scs.isValidAddress(mainAddress)) {
                startup_printf("%s[%d] failed to find main\n",FILE__,__LINE__);
                return;
            } else {
                startup_printf("%s[%d] found main at %lx\n",
                    FILE__,__LINE__,mainAddress);
            }
           	Symbol *newSym= new Symbol( "main", 
                                            Symbol::ST_FUNCTION,
                                            Symbol::SL_GLOBAL, 
                                            Symbol::SV_DEFAULT, 
                                            mainAddress,
                                            linkedFile->getDefaultModule(),
                                            eReg, 
                                            0 );
	        linkedFile->addSymbol(newSym);		
        }
    }
#elif defined(i386_unknown_linux2_0) \
|| defined(x86_64_unknown_linux2_4) /* Blind duplication - Ray */ \
|| defined(i386_unknown_solaris2_5) \
|| (defined(os_freebsd) \
    && (defined(arch_x86) || defined(arch_x86_64)))
    if(!desc_.isSharedObject())
    {
    	bool foundMain = false;
    	bool foundStart = false;
    	bool foundFini = false;

    	//check if 'main' is in allsymbols
        vector <SymtabAPI::Function *> funcs;
        if (linkedFile->findFunctionsByName(funcs, "main") ||
            linkedFile->findFunctionsByName(funcs, "_main")) {
           foundMain = true;
        }

        if (linkedFile->findFunctionsByName(funcs, "_start")) {
            foundStart = true;
        }

        if (linkedFile->findFunctionsByName(funcs, "_fini")) {
            foundFini = true;
        }

        Address eAddr = linkedFile->getEntryOffset();
        Region *eReg = linkedFile->findEnclosingRegion(eAddr);
        if (!eReg) {
           return;
        }
        Address eStart = eReg->getMemOffset();

    	if( !foundMain )
    	{
            logLine( "No main symbol found: creating symbol for main\n" );

    	    //find and add main to allsymbols
            const unsigned char* p;
		                   
            p = (( const unsigned char * ) eReg->getPtrToRawData());

            if (eAddr > eStart) {
               p += (eAddr - eStart);
            }

            switch(linkedFile->getAddressWidth()) {
       	    	case 4:
            	    // 32-bit...
                    startup_printf("%s[%u]:  setting 32-bit mode\n",
                        FILE__,__LINE__);
            	    ia32_set_mode_64(false);
                    break;
         	case 8:
                    startup_printf("%s[%u]:  setting 64-bit mode\n",
                        FILE__,__LINE__);
            	    ia32_set_mode_64(true);
            	    break;
        	default:
            	    assert(0 && "Illegal address width");
            	    break;
            }

            instruction insn;
            insn.setInstruction( p );
            Address mainAddress = 0;

	    // Create a temporary SymtabCodeSource that we can use for parsing. 
	    // We're going to throw it away when we're done so that we can re-sync
	    // with the new symbols we're going to add shortly. 
	    bool parseInAllLoadableRegions = (BPatch_normalMode != mode_);
	    SymtabCodeSource scs(linkedFile, filt, parseInAllLoadableRegions);

#if !defined(os_freebsd)
            const unsigned char *lastP = 0;
            while( !insn.isCall() )
            {
            	lastP = p;
            	p += insn.size();
            	insn.setInstruction( p );
            }

            // We _really_ can't handle a call with nothing before it....
            assert(lastP);

            // FIXME: this assumes that the instruction immediately before the call sets
            // the main address - this may not be true.
            instruction preCall;
            preCall.setInstruction(lastP);

            mainAddress = get_immediate_operand(&preCall);
#else
            // Heuristic: main is the target of the 4th call in the text section
            using namespace Dyninst::InstructionAPI;

            unsigned bytesSeen = 0, numCalls = 0;
            InstructionDecoder decoder(p, eReg->getMemSize(), scs.getArch());

            Instruction::Ptr curInsn = decoder.decode();
            while( numCalls < 4 && curInsn && curInsn->isValid() &&
                   bytesSeen < eReg->getMemSize())
            {
                InsnCategory category = curInsn->getCategory();
                if( category == c_CallInsn ) {
                    numCalls++;
                }

                if( numCalls < 4 ) {
                    bytesSeen += curInsn->size();
                    curInsn = decoder.decode();
                }
            }

            if( numCalls != 4 ) {
                logLine("heuristic for finding global constructor function failed\n");
            }else{
                Address callAddress = eReg->getMemOffset() + bytesSeen;
                RegisterAST thePC = RegisterAST(Dyninst::MachRegister::getPC(scs.getArch()));

                Expression::Ptr callTarget = curInsn->getControlFlowTarget();

                if( callTarget.get() ) {
                    callTarget->bind(&thePC, Result(s64, callAddress));
                    Result actualTarget = callTarget->eval();
                    if( actualTarget.defined ) {
                        mainAddress = actualTarget.convert<Address>();
                    }
                }
            }
#endif

            if(!mainAddress || !scs.isValidAddress(mainAddress)) {
                startup_printf("%s[%u]:  invalid main address 0x%lx\n",
                    FILE__, __LINE__, mainAddress);   
            } else {
                startup_printf("%s[%u]:  set main address to 0x%lx\n",
                    FILE__,__LINE__,mainAddress);
            }

            /* Note: creating a symbol for main at the invalid address 
               anyway, because there is guard code for this later in the
               process and otherwise we end up in a weird "this is not an
               a.out" path.

               findMain, like all important utility functions, should have
               a way of gracefully indicating that it has failed. It should
               not return void. NR
            */

    	    Region *pltsec;
            if((linkedFile->findRegion(pltsec, ".plt")) && pltsec->isOffsetInRegion(mainAddress))
            {
            	//logLine( "No static symbol for function main\n" );
                Symbol *newSym = new Symbol("DYNINST_pltMain", 
                                            Symbol::ST_FUNCTION, 
                                            Symbol::SL_GLOBAL,
                                            Symbol::SV_DEFAULT,
                                            mainAddress,
                                            linkedFile->getDefaultModule(),
                                            eReg, 
                                            0 );
                linkedFile->addSymbol( newSym );
           }
           else
           {
           	Symbol *newSym= new Symbol( "main", 
                                            Symbol::ST_FUNCTION,
                                            Symbol::SL_GLOBAL, 
                                            Symbol::SV_DEFAULT, 
                                            mainAddress,
                                            linkedFile->getDefaultModule(),
                                            eReg, 
                                            0 );
	        linkedFile->addSymbol(newSym);		
            }
        }
    	if( !foundStart )
    	{
            Symbol *startSym = new Symbol( "_start",
                                           Symbol::ST_FUNCTION,
                                           Symbol::SL_GLOBAL,
                                           Symbol::SV_DEFAULT, 
                                           eReg->getMemOffset(),
                                           linkedFile->getDefaultModule(),
                                           eReg,
                                           0 );
            //cout << "sim for start!" << endl;
        
	    linkedFile->addSymbol(startSym);		
    	}
    	if( !foundFini )
    	{
	  Region *finisec = NULL;
	  if (linkedFile->findRegion(finisec,".fini")) {
	    Symbol *finiSym = new Symbol( "_fini",
					  Symbol::ST_FUNCTION,
					  Symbol::SL_GLOBAL, 
					  Symbol::SV_DEFAULT, 
					  finisec->getMemOffset(),
					  linkedFile->getDefaultModule(),
					  finisec, 
					  0 );
	    linkedFile->addSymbol(finiSym);	
	  }	
    	}
    }

    Region *dynamicsec;
    vector < Symbol *>syms;
    if(linkedFile->findRegion(dynamicsec, ".dynamic")==true)
    {
        if(linkedFile->findSymbol(syms,
                                  "_DYNAMIC",
                                  Symbol::ST_UNKNOWN,
                                  SymtabAPI::mangledName)==false)
        {
	    Symbol *newSym = new Symbol( "_DYNAMIC", 
					Symbol::ST_OBJECT, 
                                         Symbol::SL_GLOBAL, 
                                         Symbol::SV_DEFAULT,
                                         dynamicsec->getMemOffset(), 
                                         linkedFile->getDefaultModule(),
                                         dynamicsec, 
                                         0 );
	    linkedFile->addSymbol(newSym);
	}
    }
    
#elif defined(rs6000_ibm_aix4_1) || defined(rs6000_ibm_aix5_1)
   
   bool foundMain = false;
   vector <SymtabAPI::Function *> funcs;
   if (linkedFile->findFunctionsByName(funcs, "main") ||
       linkedFile->findFunctionsByName(funcs, "usla_main"))
       foundMain = true;

   Region *sec = NULL;
   bool found = linkedFile->findRegion(sec, ".text"); 	

   if( !foundMain && linkedFile->isExec() && found )
   {
       //we havent found a symbol for main therefore we have to parse _start
       //to find the address of main

       //last two calls in _start are to main and exit
       //find the end of _start then back up to find the target addresses
       //for exit and main
      
       int c;
       int calls = 0;
       Word *code_ptr_ = (Word *) sec->getPtrToRawData();
       
       for( c = 0; code_ptr_[ c ] != 0; c++ );

       instruction i;
       while( c > 0 )
       {
           i.setInstruction((codeBuf_t*)(&code_ptr_[ c ]));

           if(IFORM_LK(i) && 
              ((IFORM_OP(i) == Bop) || (BFORM_OP(i) == BCop) ||
               ((XLFORM_OP(i) == BCLRop) && 
                ((XLFORM_XO(i) == 16) || (XLFORM_XO(i) == 528)))))
           {
               calls++;
               if( calls == 2 )
                   break;
           }
           c--;
       }
       
       Offset currAddr = sec->getMemOffset() + c * instruction::size();
       Offset mainAddr = 0;
       
       if( ( IFORM_OP(i) == Bop ) || ( BFORM_OP(i) == BCop ) )
       {
           int disp = 0;
           if(IFORM_OP(i) == Bop)
           {
               disp = IFORM_LI(i);
           }
           else if(BFORM_OP(i) == BCop)
           {
               disp = BFORM_BD(i);
           }

           disp <<= 2;

           if(IFORM_AA(i))
           {
               mainAddr = (Offset)disp;
           }
           else
               mainAddr = (Offset)( currAddr + disp );      
       }  
       
       Symbol *sym = new Symbol( "main", 
                                 Symbol::ST_FUNCTION,
                                 Symbol::SL_GLOBAL,
                                 Symbol::SV_DEFAULT, 
                                 mainAddr,
                                 linkedFile->getDefaultModule(),
                                 sec);
       linkedFile->addSymbol(sym);
      
   
       //since we are here make up a sym for _start as well

       Symbol *sym1 = new Symbol( "__start", 
                                  Symbol::ST_FUNCTION,
                                  Symbol::SL_GLOBAL, 
                                  Symbol::SV_DEFAULT, 
                                  sec->getMemOffset(), 
                                  linkedFile->getDefaultModule(),
                                  sec);
       linkedFile->addSymbol(sym1);
   }

#elif defined(i386_unknown_nt4_0)

   if(linkedFile->isExec()) {
       vector <Symbol *>syms;
       vector<SymtabAPI::Function *> funcs;
       Address eAddr = linkedFile->getEntryOffset();
       Region *eReg = linkedFile->findEnclosingRegion(eAddr);
       
       bool found_main = false;
       for (unsigned i=0; i<NUMBER_OF_MAIN_POSSIBILITIES; i++) {
           if(linkedFile->findFunctionsByName(funcs, main_function_names[i])) {
               found_main = true;
               break;
           }
       }
       if (found_main) {
           if(!linkedFile->findSymbol(syms,"start",Symbol::ST_UNKNOWN, SymtabAPI::mangledName)) {
               //use 'start' for mainCRTStartup.
               Symbol *startSym = new Symbol( "start", 
                                              Symbol::ST_FUNCTION,
                                              Symbol::SL_GLOBAL, 
                                              Symbol::SV_DEFAULT, 
                                              eAddr ,
                                              linkedFile->getDefaultModule(),
                                              eReg,
                                              UINT_MAX );
               linkedFile->addSymbol(startSym);
           }
           syms.clear();
       } 
       else {
           // add entry point as main given that nothing else was found
           startup_printf("[%s:%u] - findmain could not find symbol "
                          "for main, using binary entry point %x\n",
                          __FILE__, __LINE__, eAddr);
           linkedFile->addSymbol(new Symbol("main",
                                            Symbol::ST_FUNCTION, 
                                            Symbol::SL_GLOBAL, 
                                            Symbol::SV_DEFAULT,
                                            eAddr,
                                            linkedFile->getDefaultModule(),
                                            eReg));
       }
   }
#endif
}

/*
 * We do a search for a "main" symbol (a couple of variants), and
 * if found we flag this image as the executable (a.out). 
 */
bool image::determineImageType()
{
#if defined(TIMED_PARSE)
  struct timeval starttime;
  gettimeofday(&starttime, NULL);
#endif

  //Checking "main" function names in same order as in the inst-*.C files
  vector <SymtabAPI::Function *>funcs;
  if (linkedFile->findFunctionsByName(funcs,"main")       ||
      linkedFile->findFunctionsByName(funcs,"_main")     
#if defined(os_windows)
      || linkedFile->findFunctionsByName(funcs,"WinMain")   ||
      linkedFile->findFunctionsByName(funcs,"_WinMain")  ||
      linkedFile->findFunctionsByName(funcs,"wWinMain")  ||
      linkedFile->findFunctionsByName(funcs,"_wWinMain") 
#endif
      ) {
      is_a_out = true;
  }
  else
      is_a_out = false;
  
  // Checking for libdyninstRT (DYNINSTinit())
  if (linkedFile->findFunctionsByName(funcs, "DYNINSTinit") ||
      linkedFile->findFunctionsByName(funcs, "_DYNINSTinit"))
      is_libdyninstRT = true;
  else
      is_libdyninstRT = false;
   
#if defined(TIMED_PARSE)
  struct timeval endtime;
  gettimeofday(&endtime, NULL);
  unsigned long lstarttime = starttime.tv_sec * 1000 * 1000 + starttime.tv_usec;
  unsigned long lendtime = endtime.tv_sec * 1000 * 1000 + endtime.tv_usec;
  unsigned long difftime = lendtime - lstarttime;
  double dursecs = difftime/(1000 );
  cout << __FILE__ << ":" << __LINE__ <<": determineImageType took "<<dursecs <<" msecs" << endl;
#endif
  return true;
}

bool image::getInferiorHeaps(vector<pair<string,Address> > &codeHeaps,
                             vector<pair<string,Address> > &dataHeaps) {
    if ((codeHeaps_.size() == 0) &&
        (dataHeaps_.size() == 0)) return false;

    for (unsigned i = 0; i < codeHeaps_.size(); i++) {
        codeHeaps.push_back(codeHeaps_[i]);
    }

    for (unsigned i = 0; i < dataHeaps_.size(); i++) {
        dataHeaps.push_back(dataHeaps_[i]);
    }
    return true;
}

bool image::addSymtabVariables()
{
   /* Eventually we'll have to do this on all platforms (because we'll retrieve
    * the type information here).
    */
   
#if defined(TIMED_PARSE)
   struct timeval starttime;
   gettimeofday(&starttime, NULL);
#endif

   std::string mangledName; 

   vector<Variable *> allVars;

   linkedFile->getAllVariables(allVars); 

   for (vector<Variable *>::iterator varIter = allVars.begin();
        varIter != allVars.end(); 
        varIter++) {
       Variable *symVar = *varIter;

       parsing_printf("New variable, mangled %s, module %s...\n",
                      symVar->getAllMangledNames()[0].c_str(),
                      symVar->getFirstSymbol()->getModule()->fileName().c_str());
       pdmodule *use = getOrCreateModule(symVar->getModule());

       assert(use);
       image_variable *var = new image_variable(symVar, use);
       if (!var->svar()->addAnnotation(var, ImageVariableUpPtrAnno)) {
           fprintf(stderr, "%s[%d]: failed to add annotation here\n", FILE__, __LINE__);
           return false;
       }

       // If this is a Dyninst dynamic heap placeholder, add it to the
       // list of inferior heaps...
       string compString = "DYNINSTstaticHeap";
       if (!var->symTabName().compare(0, compString.size(), compString)) {
           dataHeaps_.push_back(pair<string,Address>(var->symTabName(), var->getOffset()));
       }

       exportedVariables.push_back(var);
       everyUniqueVariable.push_back(var);
       varsByAddr[var->getOffset()] = var;
   }

#if defined(TIMED_PARSE)
   struct timeval endtime;
   gettimeofday(&endtime, NULL);
   unsigned long lstarttime = starttime.tv_sec * 1000 * 1000 + starttime.tv_usec;
   unsigned long lendtime = endtime.tv_sec * 1000 * 1000 + endtime.tv_usec;
   unsigned long difftime = lendtime - lstarttime;
   double dursecs = difftime/(1000 );
   cout << __FILE__ << ":" << __LINE__ <<": addSymtabVariables took "<<dursecs <<" msecs" << endl;
#endif

   return true;
}

pdmodule *image::findModule(const string &name, bool wildcard)
{
   pdmodule *found = NULL;
   //cerr << "image::findModule " << name << " , " << find_if_excluded
   //     << " called" << endl;

   if (!wildcard) {
      if (modsByFileName.find(name) != modsByFileName.end()) {
         //cerr << " (image::findModule) found module in modsByFileName" << endl;
         found = modsByFileName[name];
      }
      else if (modsByFullName.find(name) != modsByFullName.end()) {
         //cerr << " (image::findModule) found module in modsByFullName" << endl;
         found = modsByFullName[name];
      }
   }
   else {
      //  if we want a substring, have to iterate over all module names
      //  this is ok b/c there are not usually more than a handful or so
      //
      dyn_hash_map <string, pdmodule *>::iterator mi;
      string str; pdmodule *mod;
      std::string pds = name.c_str();

      for(mi = modsByFileName.begin(); mi != modsByFileName.end() ; mi++)
      {
         str = mi->first;
         mod = mi->second;
         if (wildcardEquiv(pds, mod->fileName()) ||
               wildcardEquiv(pds, mod->fullName())) {
            found = mod; 
            break;
         }
      }
   }

   //cerr << " (image::findModule) did not find module, returning NULL" << endl;
   if (found) {
      // Just-in-time...
      //if (parseState_ == symtab)
      //analyzeImage();
      return found;
   }

   return NULL;
}

const CodeObject::funclist &
image::getAllFunctions()
{
    analyzeIfNeeded();
    return codeObject()->funcs();
}

const pdvector<image_variable*> &image::getAllVariables()
{
    analyzeIfNeeded();
    return everyUniqueVariable;
}

const pdvector<image_variable*> &image::getExportedVariables() const { return exportedVariables; }

const pdvector<image_variable*> &image::getCreatedVariables()
{
  analyzeIfNeeded();
  return createdVariables;
}

bool image::getModules(vector<pdmodule *> &mods) 
{
    bool ret = false;
   pdvector<pdmodule *> toReturn;
    for (map<Module *, pdmodule *>::const_iterator iter = mods_.begin();
         iter != mods_.end(); iter++) {
        ret = true;
        mods.push_back(iter->second);
    }
    return ret;
}

// identify module name from symbol address (binary search)
// based on module tags found in file format (ELF/COFF)
void image::findModByAddr (const Symbol *lookUp, vector<Symbol *> &mods,
			   string &modName, Address &modAddr, 
			   const string &defName)
{
  if (mods.size() == 0) {
    modAddr = 0;
    modName = defName;
    return;
  }

  Address symAddr = lookUp->getOffset();
  int index;
  int start = 0;
  int end = mods.size() - 1;
  int last = end;
  bool found = false;
  while ((start <= end) && !found) {
    index = (start+end)/2;
    if ((index == last) ||
	((mods[index]->getOffset() <= symAddr) && 
	 (mods[index+1]->getOffset() > symAddr))) {
      modName = mods[index]->getMangledName().c_str();
      modAddr = mods[index]->getOffset();      
      found = true;
    } else if (symAddr < mods[index]->getOffset()) {
      end = index - 1;
    } else {
      start = index + 1;
    }
  }
  if (!found) { 
    // must be (start > end)
    modAddr = 0;
    modName = defName;
  }
}

unsigned int int_addrHash(const Address& addr) {
  return (unsigned int)addr;
}

/*
 * load an executable:
 *   1.) parse symbol table and identify rotuines.
 *   2.) scan executable to identify inst points.
 *
 *  offset is normally zero except on CM-5 where we have two images in one
 *    file.  The offset passed to parseImage is the logical offset (0/1), not
 *    the physical point in the file.  This makes it faster to "parse" multiple
 *    copies of the same image since we don't have to stat and read to find the
 *    physical offset. 
 */

image *image::parseImage(fileDescriptor &desc, 
                         BPatch_hybridMode mode, 
                         bool parseGaps)
{
  /*
   * Check to see if we have parsed this image before. We will
   * consider it a match if the filename matches (Our code is now able
   * to cache the parsing results even if a library is loaded at a
   * different address for the second time).
   */
  unsigned numImages = allImages.size();
  
  // AIX: it's possible that we're reparsing a file with better information
  // about it. If so, yank the old one out of the images vector -- replace
  // it, basically.
  for (unsigned u=0; u<numImages; u++) {
      if (desc.isSameFile(allImages[u]->desc())) {
         if (allImages[u]->getObject()->canBeShared()) {
            // We reference count...
            startup_printf("%s[%d]: returning pre-parsed image\n", FILE__, __LINE__);
            return allImages[u]->clone();
         }
      }
  }

  stats_parse.startTimer(PARSE_SYMTAB_TIMER);

  /*
   * load the symbol table. (This is the a.out format specific routine).
   */
  
  bool err=false;

#if defined(TIMED_PARSE)
  struct timeval starttime;
  gettimeofday(&starttime, NULL);
#endif

  startup_printf("%s[%d]:  about to create image\n", FILE__, __LINE__);
  image *ret = new image(desc, err, mode, parseGaps); 
  startup_printf("%s[%d]:  created image\n", FILE__, __LINE__);

  if(desc.isSharedObject()) 
      startup_printf("%s[%d]: processing shared object\n", FILE__, __LINE__);
  else  
      startup_printf("%s[%d]: processing executable object\n", FILE__, __LINE__);
      

#if defined(TIMED_PARSE)
  struct timeval endtime;
  gettimeofday(&endtime, NULL);
  unsigned long lstarttime = starttime.tv_sec * 1000 * 1000 + starttime.tv_usec;
  unsigned long lendtime = endtime.tv_sec * 1000 * 1000 + endtime.tv_usec;
  unsigned long difftime = lendtime - lstarttime;
  double dursecs = difftime/(1000 );
  cout << __FILE__ << ":" << __LINE__ <<": parsing image "<< desc.file().c_str() <<" took "<<dursecs <<" msecs" << endl;
#endif

  if (err || !ret) {
     if (ret) {
         startup_printf("%s[%d]: error in processing, deleting image and returning\n",
                        FILE__, __LINE__);
         delete ret;
     }
     else {
        fprintf(stderr, "Failed to allocate memory for parsing %s!\n", 
                desc.file().c_str());
     }
     stats_parse.stopTimer(PARSE_SYMTAB_TIMER);
     return NULL;
  }

  allImages.push_back(ret);

  // start tracking new blocks after initial parse
  if ( BPatch_exploratoryMode == mode ||
       BPatch_defensiveMode == mode ) 
  {
      ret->trackNewBlocks_ = true;
  }

  // define all modules.

  statusLine("ready"); // this shouldn't be here, right? (cuz we're not done, right?)
  stats_parse.stopTimer(PARSE_SYMTAB_TIMER);

  return ret;
}

/*
 * Remove a parsed executable from the global list. Used if the old handle
 * is no longer valid.
 */
void image::removeImage(image *img)
{

  // Here's a question... do we want to actually delete images?
  // Pro: free up memory. Con: we'd just have to parse them again...
  // I guess the question is "how often do we serially open files".
  /* int refCount = */ img->destroy();
  

  /*
    // We're not deleting when the refcount hits 0, so we may as well
    // keep the vector. It's a time/memory problem. 
  if (refCount == 0) {
    pdvector<image*> newImages;
    // It's gone... remove from image vector
    for (unsigned i = 0; i < allImages.size(); i++) {
      if (allImages[i] != img)
	newImages.push_back(allImages[i]);
    }
    allImages = newImages;
  }
  */
}

int image::destroy() {
    refCount--;
    if (refCount == 0) {
        if (!desc().isSharedObject()) {
            // a.out... destroy it
            //delete this;
            return 0;
        }
    }
    if (refCount < 0)
        assert(0 && "NEGATIVE REFERENCE COUNT FOR IMAGE!");
    return refCount; 
}

void image::analyzeIfNeeded() {
  if (parseState_ == symtab) {
      parsing_printf("ANALYZING IMAGE %s\n",
              file().c_str());
      analyzeImage();
	  // For defensive mode: we only care about incremental splitting and block
	  // creation, not ones noted during parsing (as we haven't created the int
	  // layer yet, so no harm no foul)
	  clearNewBlocks();
  }
}

void image::analyzeImage() {
#if defined(TIMED_PARSE)
    struct timeval starttime;
    gettimeofday(&starttime, NULL);
#endif
    stats_parse.startTimer(PARSE_ANALYZE_TIMER);

// FIXME necessary?
#if defined(arch_x86_64)
    ia32_set_mode_64(getObject()->getAddressWidth() == 8);
#endif

    assert(parseState_ < analyzed);
    if(parseState_ < symtab){
        fprintf(stderr, "Error: attempt to analyze incomplete image\n");
        goto done;
    }
    parseState_ = analyzing;

    obj_->parse();

#if defined(os_aix)
  {
  image_parRegion *parReg;
  int currentSectionNum = 0;

  // Most of the time there will be no parallel regions in an image, so nothing will happen.
  // If there is a parallel region we examine it individually 
  for (unsigned i = 0; i < parallelRegions.size(); i++)
    {
      parReg = parallelRegions[i];
      if (parReg == NULL)
    continue;
      else
    {
      // Every parallel region has the parse_func that contains the
      //   region associated with it 
            parse_func * imf = const_cast<parse_func*>(parReg->getAssociatedFunc());
      
      // Returns pointers to all potential parse_funcs that correspond
      //   to what could be the parent OpenMP function for the region 
      const pdvector<parse_func *> *prettyNames =
        findFuncVectorByPretty(imf->calcParentFunc(imf, parallelRegions));
      
      //There may be more than one (or none) functions with that name, we take the first 
      // This function gives us all the information about the parallel region by getting
      // information for the parallel region parent function  
      if (prettyNames->size() > 0)
        imf->parseOMP(parReg, (*prettyNames)[0], currentSectionNum);
      else
        continue;
    }
    }
  }
  /**************************/
  /* END OpenMP Parsing Code */
  /**************************/

#endif

#if defined(cap_stripped_binaries)
   {
       vector<CodeRegion *>::const_iterator rit = cs_->regions().begin();
       for( ; rit != cs_->regions().end(); ++rit)
       {
        SymtabCodeRegion * scr = static_cast<SymtabCodeRegion*>(*rit);
        if(parseGaps_ && scr->symRegion()->isText()) {
            obj_->parseGaps(scr);
        }
       } 
   }
#endif // cap_stripped_binaries
    
    parseState_ = analyzed;
  done:
    stats_parse.stopTimer(PARSE_ANALYZE_TIMER); 

#if defined(TIMED_PARSE)
    struct timeval endtime;
    gettimeofday(&endtime, NULL);
    unsigned long lstarttime = starttime.tv_sec * 1000*1000+starttime.tv_usec;
    unsigned long lendtime = endtime.tv_sec * 1000*1000+endtime.tv_usec;
    unsigned long difftime = lendtime - lstarttime;
    double dursecs = difftime/(1000 );
    cout << __FILE__ << ":" << __LINE__ <<": analyzeImage of " << name_ << " took "<<dursecs <<" msecs" << endl;
#endif
}

// Constructor for the image object. The fileDescriptor simply
// wraps (in the normal case) the object name and a relocation
// address (0 for a.out file). On the following platforms, we
// are handling a special case:
//   AIX: objects can possibly have a name like /lib/libc.so:shr.o
//          since libraries are archives
//        Both text and data sections have a relocation address


image::image(fileDescriptor &desc, 
             bool &err, 
             BPatch_hybridMode mode, 
             bool parseGaps) :
   desc_(desc),
   activelyParsing(addrHash4),
   is_libdyninstRT(false),
   is_a_out(false),
   main_call_addr_(0),
   nativeCompiler(false),    
   obj_(NULL),
   cs_(NULL),
   filt(NULL),
   img_fact_(NULL),
   parse_cb_(NULL),
   nextBlockID_(0),
   pltFuncs(NULL),
   varsByAddr(addrHash4),
   trackNewBlocks_(false),
   refCount(1),
   parseState_(unparsed),
   parseGaps_(parseGaps),
   mode_(mode),
   arch(Dyninst::Arch_none)
{
#if defined(os_aix)
   archive = NULL;
   string file = desc_.file().c_str();
   SymtabAPI::SymtabError serr = SymtabAPI::Not_An_Archive;

   startup_printf("%s[%d]:  opening file %s (or archive)\n", FILE__, __LINE__, file.c_str());
   if (!SymtabAPI::Archive::openArchive(archive, file))
   {
      err = true;
      if (archive->getLastError() != serr) {
         startup_printf("%s[%d]:  opened archive\n", FILE__, __LINE__);
         return;
      }
      else
      {
         startup_printf("%s[%d]:  opening file (not archive)\n", FILE__, __LINE__);
         if (!SymtabAPI::Symtab::openFile(linkedFile, file, BPatch_defensiveMode == mode)) 
         {
            startup_printf("%s[%d]:  opening file (not archive) failed\n", FILE__, __LINE__);
            err = true;
            return;
         }
         startup_printf("%s[%d]:  opened file\n", FILE__, __LINE__);
      }
   }
   else
   {
      assert (archive);
      startup_printf("%s[%d]:  getting member\n", FILE__, __LINE__);
      string member = std::string(desc_.member());
      if (member == fileDescriptor::emptyString) {
         fprintf(stderr, "%s[%d]:  WARNING:  not asking for unnamed member\n", FILE__, __LINE__);
      }
      else {
         if (!archive->getMember(linkedFile, member))
         {
            startup_printf("%s[%d]:  getting member failed\n", FILE__, __LINE__);
            err = true;
            return;
         }
         startup_printf("%s[%d]:  got member\n", FILE__, __LINE__);
      }
   }
   startup_printf("%s[%d]:  opened file %s (or archive)\n", FILE__, __LINE__, file.c_str());
#elif defined(os_linux) || defined(os_freebsd)
   string file = desc_.file().c_str();
   if( desc_.member().empty() ) {
       startup_printf("%s[%d]:  opening file %s\n", FILE__, __LINE__, file.c_str());
       if( !SymtabAPI::Symtab::openFile(linkedFile, file, (BPatch_defensiveMode == mode ? Symtab::Defensive : Symtab::NotDefensive)) ) {
           err = true;
           return;
       }
   }else{
       startup_printf("%s[%d]: opening archive member: %s(%s)\n", FILE__, __LINE__, file.c_str(),
               desc_.member().c_str());

       if( SymtabAPI::Archive::openArchive(archive, file) ) {
           if( !archive->getMember(linkedFile, const_cast<std::string&>(desc_.member())) ) {
               err = true;
               return;
           }
       }else{
           err = true;
           return;
       }
   }
#elif defined(os_vxworks)
   string file = desc_.file();
   startup_printf("%s[%d]: opening file %s\n", FILE__, __LINE__, file.c_str());
   if( !Symtab::openFile(linkedFile, file) ) {
       startup_printf("%s[%d]: %s unavailable. Building info from target.\n",
                      FILE__, __LINE__, file.c_str());
       MappedFile *mf = MappedFile::createMappedFile(file);
       linkedFile = new Symtab::Symtab(mf);
   }

   // Fill in remaining unknown information from remote target.
   fixup_offsets(file, linkedFile);

#else
	std::string file = desc_.file();
   startup_printf("%s[%d]: opening file %s\n", FILE__, __LINE__, file.c_str());
   Symtab::def_t symMode = (BPatch_defensiveMode == mode) ? 
       Symtab::Defensive : Symtab::NotDefensive;
   if(desc.rawPtr()) {
       linkedFile = new Symtab((unsigned char*)desc.rawPtr(), 
                                          desc.length(), 
                                          desc.file(), 
                                          symMode,
                                          err);
   } 
   else if(!Symtab::openFile(linkedFile, file, symMode)) 
   {
      err = true;
      return;
   }
#endif

   err = false;

   // fix isSharedObject flag in file descriptor
   desc.setIsShared(!linkedFile->isExec());
   desc_.setIsShared(!linkedFile->isExec());

   name_ = extract_pathname_tail(string(desc.file().c_str()));

   //   fprintf(stderr,"img name %s\n",name_.c_str());
   pathname_ = desc.file().c_str();

   // initialize (data members) codeOffset_, dataOffset_,
   //  codeLen_, dataLen_.

   imageOffset_ = linkedFile->imageOffset();
   dataOffset_ = linkedFile->dataOffset();

   imageLen_ = linkedFile->imageLength();
   dataLen_ = linkedFile->dataLength();

   /*
    * When working with ELF .o's, it is a possibility that the region
    * which is referred to by imageOffset(), imageLength() could have a zero
    * length. This is okay for .o's
    */

   // if unable to parse object file (somehow??), try to
   //  notify user/calling process + return....    
   if (!imageLen_ && 
       linkedFile->getObjectType() != SymtabAPI::obj_RelocatableFile)
    {
      string msg = string("Parsing problem with executable file: ") + desc.file();
      statusLine(msg.c_str());
      msg += "\n";
      logLine(msg.c_str());
      err = true;
      return;
   }

   //Now add Main and Dynamic Symbols if they are not present
   startup_printf("%s[%d]:  before findMain\n", FILE__, __LINE__);
   findMain();

   // Initialize ParseAPI 
   filt = NULL;

   /** Optionally eliminate some hints in which Dyninst is not
       interested **/
   struct filt_heap : SymtabCodeSource::hint_filt {
        bool operator()(SymtabAPI::Function * f) {
            return f->getModule()->fullName() == "DYNINSTheap";
        }
    } nuke_heap;
    filt = &nuke_heap;

   bool parseInAllLoadableRegions = (BPatch_normalMode != mode_);
   cs_ = new SymtabCodeSource(linkedFile,filt,parseInAllLoadableRegions);

   // Continue ParseAPI init
   img_fact_ = new DynCFGFactory(this);
   parse_cb_ = new DynParseCallback(this);
   obj_ = new CodeObject(cs_,img_fact_,parse_cb_,BPatch_defensiveMode == mode);

   string msg;
   // give user some feedback....
   msg = string("Parsing object file: ") + desc.file();

   statusLine(msg.c_str());


   // look for `main' or something similar to recognize a.outs
   startup_printf("%s[%d]:  before determineImageType\n", FILE__, __LINE__);
   determineImageType();
   if (isDyninstRTLib()) { // don't parse gaps in the runtime library
       parseGaps_ = false;
   }
            
   // And symtab variables
   addSymtabVariables();

   parseState_ = symtab;
}

image::~image() 
{
    unsigned i;

    for (map<Module *, pdmodule *>::iterator iter = mods_.begin();
         iter != mods_.end(); iter++) {
        delete (iter->second);
    }

    for (i = 0; i < everyUniqueVariable.size(); i++) {
        delete everyUniqueVariable[i];
    }
    everyUniqueVariable.clear();
    createdVariables.clear();
    exportedVariables.clear();

   
    for (i = 0; i < parallelRegions.size(); i++)
      delete parallelRegions[i];
    parallelRegions.clear();

    // Finally, remove us from the image list.
    for (i = 0; i < allImages.size(); i++) {
        if (allImages[i] == this)
            VECTOR_ERASE(allImages,i,i);
    }

    if (pltFuncs) {
       delete pltFuncs;
       pltFuncs = NULL;
    }

    if(obj_) delete obj_;
    if(cs_) delete cs_;
    if(img_fact_) delete img_fact_;
    if(parse_cb_) delete parse_cb_;

    if (linkedFile) { SymtabAPI::Symtab::closeSymtab(linkedFile); }
#if defined (os_aix)
    //fprintf(stderr, "%s[%d]:  IMAGE DTOR:  archive = %p\n", FILE__, __LINE__, archive);
    if (archive) delete archive;
#endif
}

bool pdmodule::findFunction( const std::string &name, pdvector<parse_func *> &found ) {
    if (findFunctionByMangled(name, found))
        return true;
    return findFunctionByPretty(name, found);
}

bool pdmodule::findFunctionByMangled( const std::string &name,
                                      pdvector<parse_func *> &found)
{
    // For efficiency sake, we grab the image vector and strip out the
    // functions we want.
    // We could also keep them all in modules and ditch the image-wide search; 
    // the problem is that BPatch goes by module and internal goes by image. 
    unsigned orig_size = found.size();
    
    const pdvector<parse_func *> *obj_funcs = imExec()->findFuncVectorByMangled(name.c_str());
    if (!obj_funcs) {
        return false;
    }
    for (unsigned i = 0; i < obj_funcs->size(); i++) {
        if ((*obj_funcs)[i]->pdmod() == this)
            found.push_back((*obj_funcs)[i]);
    }
    if (found.size() > orig_size) {
        //exec()->analyzeIfNeeded();
        return true;
    }
    
    return false;
}


bool pdmodule::findFunctionByPretty( const std::string &name,
                                     pdvector<parse_func *> &found)
{
    // For efficiency sake, we grab the image vector and strip out the
    // functions we want.
    // We could also keep them all in modules and ditch the image-wide search; 
    // the problem is that BPatch goes by module and internal goes by image. 
    unsigned orig_size = found.size();
    
    const pdvector<parse_func *> *obj_funcs = imExec()->findFuncVectorByPretty(name);
    if (!obj_funcs) {
        return false;
    }
    for (unsigned i = 0; i < obj_funcs->size(); i++) {
        if ((*obj_funcs)[i]->pdmod() == this)
            found.push_back((*obj_funcs)[i]);
    }
    if (found.size() > orig_size) {
        //exec()->analyzeIfNeeded();
        return true;
    }
    
    return false;
}

void pdmodule::dumpMangled(std::string &prefix) const
{
  cerr << fileName() << "::dumpMangled("<< prefix << "): " << endl;

  const CodeObject::funclist & allFuncs = imExec()->getAllFunctions();
  CodeObject::funclist::const_iterator fit = allFuncs.begin();
  for( ; fit != allFuncs.end(); ++fit) {
      parse_func * pdf = (parse_func*)*fit;
      if (pdf->pdmod() != this) continue;

      if( ! strncmp( pdf->symTabName().c_str(), prefix.c_str(), strlen( prefix.c_str() ) ) ) {
          cerr << pdf->symTabName() << " ";
      }
      else {
          // bperr( "%s is not a prefix of %s\n", prefix, pdf->symTabName().c_str() );
      }
  }
  cerr << endl;
}

parse_func *image::addFunction(Address functionEntryAddr, const char *fName)
 {
     set<CodeRegion *> regions;
     CodeRegion * region;
     codeObject()->cs()->findRegions(functionEntryAddr,regions);
     if(regions.empty()) {
        parsing_printf("[%s:%d] refusing to create function in nonexistent "
                       "region at %lx\n",
            FILE__,__LINE__,functionEntryAddr);
        return NULL;
     }
     region = *(regions.begin()); // XXX pick one, throwing up hands. 

     pdmodule *mod = getOrCreateModule(linkedFile->getDefaultModule());

     // copy or create function name
     char funcName[32];
     if (fName) {
         snprintf( funcName, 32, "%s", fName);
     } else {
         snprintf( funcName, 32, "entry_%lx", functionEntryAddr);	
     }
     Symbol *funcSym = new Symbol(funcName,
                                  Symbol::ST_FUNCTION,
                                  Symbol::SL_GLOBAL, 
                                  Symbol::SV_DEFAULT,
                                  functionEntryAddr, 
                                  mod->mod(),
                                  NULL,
                                  UINT_MAX);
     // create function stub, update datastructures
     if (!linkedFile->addSymbol( funcSym )) {
         return NULL;
     }
     
     // Adding the symbol finds or creates a Function object...
     assert(funcSym->getFunction());

     // Parse, but not recursively
     codeObject()->parse(functionEntryAddr, false); 

     parse_func * func = static_cast<parse_func*>(
            codeObject()->findFuncByEntry(region,functionEntryAddr));

     if(NULL == func) {
        parsing_printf("[%s:%d] failed to create function at %lx\n",
            FILE__,__LINE__,functionEntryAddr);
        return NULL;
     }

     if (!func->getSymtabFunction()->addAnnotation(func, ImageFuncUpPtrAnno))
     {
        fprintf(stderr, "%s[%d]: failed to add annotation here\n", FILE__, __LINE__);
        return NULL;
     }

     // If this is a Dyninst dynamic heap placeholder, add it to the
     // list of inferior heaps...
     string compString = "DYNINSTstaticHeap";
     if (!func->symTabName().compare(0, compString.size(), compString)) {
         codeHeaps_.push_back(pair<string, Address>(func->symTabName(), func->getOffset()));
     }

     func->addSymTabName( funcName ); 
     func->addPrettyName( funcName );
     // funcsByEntryAddr[func->getOffset()] = func;
     //createdFunctions.push_back(func);

     return func;
}

const string &pdmodule::fileName() const
{
    return mod_->fileName();
}

const string &pdmodule::fullName() const
{
    return mod_->fullName();
}

SymtabAPI::supportedLanguages 
pdmodule::language() const
{
    return mod_->language();
}

Address pdmodule::addr() const
{
    return mod_->addr();
}

bool pdmodule::isShared() const
{
    return mod_->isShared();
}

Module *pdmodule::mod()
{
    return mod_;
}

pdmodule *image::getOrCreateModule(Module *mod) {
    if (mods_.find(mod) != mods_.end())
        return mods_[mod];

    pdmodule *pdmod = new pdmodule(mod, this);

    mods_[mod] = pdmod;
    modsByFileName[pdmod->fileName()] = pdmod;
    modsByFullName[pdmod->fullName()] = pdmod;
    
    return pdmod;
}

namespace {
    /* 
     * See ParseAPI::SymtabCodeSource::lookup_region for 
     * details about this
     */  
    CodeRegion * aix_region_hack(set<CodeRegion *> regs,Address addr)
    {
        set<CodeRegion*>::iterator rit = regs.begin();
        for( ; rit != regs.end(); ++rit) {
            CodeRegion * tmp = *rit;
            if(tmp->isCode(addr))
                return tmp;
        }
        return *regs.begin();
    }
};


/*********************************************************************/
/**** Function lookup (by name or address) routines               ****/
/****                                                             ****/
/**** Overlapping region objects MUST NOT use these routines(+)   ****/
/*********************************************************************/
/*
 * (+) that is, except on AIX which is just /different/
 */

int
image::findFuncs(const Address offset, set<Function *> & funcs) {
    analyzeIfNeeded();

    set<CodeRegion *> match;
    int cnt = cs_->findRegions(offset,match);
    if(cnt == 0)
        return 0;
    else if(cnt == 1)
        return obj_->findFuncs(*match.begin(),offset,funcs);

#if !defined(os_aix)
        fprintf(stderr,"[%s:%d] image::findFuncs(offset) called on "
                       "overlapping-region object\n",
            FILE__,__LINE__);
        assert(0);
        return 0;
#else
    CodeRegion * single = aix_region_hack(match,offset);
    return obj_->findFuncs(single,offset,funcs);
#endif 
}

parse_func *image::findFuncByEntry(const Address &entry) {
    analyzeIfNeeded();

    set<CodeRegion *> match;
    int cnt = cs_->findRegions(entry,match);
    if(cnt == 0)
        return 0;
    else if(cnt == 1)
        return (parse_func*)obj_->findFuncByEntry(*match.begin(),entry);

#if !defined(os_aix)
    fprintf(stderr,"[%s:%d] image::findFuncByEntry(entry) called on "
                   "overlapping-region object\n",
        FILE__,__LINE__);
    assert(0);
    return 0;
#else
    CodeRegion * single = aix_region_hack(match,entry);
    return (parse_func*)obj_->findFuncByEntry(single,entry);
#endif 
}

int 
image::findBlocksByAddr(const Address addr, set<ParseAPI::Block *> & blocks ) 
{
    analyzeIfNeeded();

    set<CodeRegion *> match;
    int cnt = cs_->findRegions(addr,match);
    if(cnt == 0)
        return 0;
    else if(cnt == 1)
        return obj_->findBlocks(*match.begin(),addr,blocks);

#if !defined(os_aix)
        fprintf(stderr,"[%s:%d] image::findBlocks(offset) called on "
                       "overlapping-region object\n",
            FILE__,__LINE__);
        assert(0);
        return 0;
#else
    CodeRegion * single = aix_region_hack(match,addr);
    return obj_->findBlocks(single,addr,blocks);
#endif
}

// Return the vector of functions associated with a pretty (demangled) name
// Very well might be more than one!

const pdvector<parse_func *> *image::findFuncVectorByPretty(const std::string &name) {
    //Have to change here
    pdvector<parse_func *>* res = new pdvector<parse_func *>;
    vector<SymtabAPI::Function *> funcs;
    linkedFile->findFunctionsByName(funcs, name.c_str(), SymtabAPI::prettyName);

    for(unsigned index=0; index < funcs.size(); index++)
    {
        SymtabAPI::Function *symFunc = funcs[index];
        parse_func *imf = NULL;
        
        if (!symFunc->getAnnotation(imf, ImageFuncUpPtrAnno)) {
	  // TODO: just create the function here...

           return NULL;
        }
        
        if (imf) {
            res->push_back(imf);
        }


    }		
    if(res->size())	
	return res;	    
    else {
        delete res;
    	return NULL;
    }
}

// Return the vector of functions associated with a mangled name
// Very well might be more than one! -- multiple static functions in different .o files

const pdvector <parse_func *> *image::findFuncVectorByMangled(const std::string &name)
{
    pdvector<parse_func *>* res = new pdvector<parse_func *>;

    vector<SymtabAPI::Function *> funcs;
    linkedFile->findFunctionsByName(funcs, name.c_str(), SymtabAPI::mangledName);

    for(unsigned index=0; index < funcs.size(); index++) {
        SymtabAPI::Function *symFunc = funcs[index];
        parse_func *imf = NULL;
        
        if (!symFunc->getAnnotation(imf, ImageFuncUpPtrAnno)) {
            return NULL;
        }
        
        if (imf) {
            res->push_back(imf);
        }

    }	    
    if(res->size()) 
	return res;	    
    else {
        delete res;
    	return NULL;
    }   
}

const pdvector <image_variable *> *image::findVarVectorByPretty(const std::string &name)
{
    pdvector<image_variable *>* res = new pdvector<image_variable *>;

    vector<Variable *> vars;
    linkedFile->findVariablesByName(vars, name.c_str(), SymtabAPI::prettyName);
    
    for (unsigned index=0; index < vars.size(); index++) {
        Variable *symVar = vars[index];
        image_variable *imv = NULL;
        
        if (!symVar->getAnnotation(imv, ImageVariableUpPtrAnno)) {
            fprintf(stderr, "%s[%d]:  failed to getAnnotations here\n", FILE__, __LINE__);
            return NULL;
        }

       if (imv) {
           res->push_back(imv);
       }
    }	    
    if(res->size())	
	return res;	    
    else {
        delete res;
    	return NULL;
    }
}

const pdvector <image_variable *> *image::findVarVectorByMangled(const std::string &name)
{
    //    fprintf(stderr,"findVariableVectorByPretty %s\n",name.c_str());
#ifdef IBM_BPATCH_COMPAT_STAB_DEBUG
    bperr( "%s[%d]:  inside findVariableVectorByPretty\n", FILE__, __LINE__);
#endif
    pdvector<image_variable *>* res = new pdvector<image_variable *>;

    vector<Variable *> vars;
    linkedFile->findVariablesByName(vars, name.c_str(), SymtabAPI::mangledName);
    
    for (unsigned index=0; index < vars.size(); index++) {
        Variable *symVar = vars[index];
        image_variable *imv = NULL;
        
        if (!symVar->getAnnotation(imv, ImageVariableUpPtrAnno)) {
            fprintf(stderr, "%s[%d]:  failed to getAnnotations here\n", FILE__, __LINE__);
            return NULL;
        }

        if (imv) {
            res->push_back(imv);
        }
    }	    
    if(res->size())	
	return res;	    
    else {
        delete res;
    	return NULL;
    }
  /*
  if (varsByMangled.defines(name)) {
      //analyzeIfNeeded();
      return varsByMangled[name];
  }
  return NULL;*/
}

bool pdmodule::getFunctions(pdvector<parse_func *> &funcs)  {
    unsigned curFuncSize = funcs.size();
    const CodeObject::funclist & allFuncs = imExec()->getAllFunctions();
    
    CodeObject::funclist::const_iterator fit = allFuncs.begin();
    for( ; fit != allFuncs.end(); ++fit) {
        parse_func *f = (parse_func*)*fit;
        if (f->pdmod() == this) 
	{
            funcs.push_back(f);
	}
    }
  
    return (funcs.size() > curFuncSize);
} /* end getFunctions() */

/* Instrumentable-only, by the last version's source. */
bool pdmodule::getVariables(pdvector<image_variable *> &vars)  {
    pdvector<image_variable *> allVars = imExec()->getAllVariables();
    unsigned curVarSize = vars.size();

    for (unsigned i = 0; i < allVars.size(); i++) {
        if (allVars[i]->pdmod() == this)
            vars.push_back(allVars[i]);
    }
  
    return (vars.size() > curVarSize);
} /* end getFunctions() */

/*
void *image::getPtrToDataInText( Address offset ) const {
    if( isData(offset) ) { return NULL; }
    if( ! isCode(offset) ) { return NULL; }
	
    Region *reg = linkedFile->findEnclosingRegion(offset);
    if(reg != NULL) {
        return (void*) ((Address)reg->getPtrToRawData() + offset 
                        - reg->getMemOffset());
    }
    return NULL;
} *//* end getPtrToDataInText() */
    
bool image::getExecCodeRanges(std::vector<std::pair<Address, Address> > &ranges)
{
   std::vector<Region *> regions;
   bool result = linkedFile->getCodeRegions(regions);
   if (!result)
      return false;
   Address cur_start = 0, cur_end = (Address)(-1);
   bool found_something = false;
   fprintf(stderr, "\n");
   for (std::vector<Region *>::iterator i = regions.begin(); i != regions.end(); i++)
   {
      Region *r = *i;
      if (!r->isStandardCode() && !codeObject()->defensiveMode())
         continue;
      if (!found_something) {
         cur_start = r->getDiskOffset();
         cur_end = cur_start + r->getDiskSize();
         found_something = true;
         continue;
      }

      if (r->getDiskOffset() <= cur_end) {
         cur_end = r->getDiskOffset() + r->getDiskSize();
      }
      else {
         ranges.push_back(std::pair<Address, Address>(cur_start, cur_end));
         cur_start = r->getDiskOffset();
         cur_end = cur_start + r->getDiskSize();
      }
   }
   if (!found_something) {
      return false;
   }
   ranges.push_back(std::pair<Address, Address>(cur_start, cur_end));
   return true;
}

Symbol *image::symbol_info(const std::string& symbol_name) {
   vector< Symbol *> symbols;
   if(!(linkedFile->findSymbol(symbols,symbol_name.c_str(),Symbol::ST_UNKNOWN, SymtabAPI::anyName))) 
       return false;

   return symbols[0];
}

bool image::findSymByPrefix(const std::string &prefix, pdvector<Symbol *> &ret) {
    unsigned start;
    vector <Symbol *>found;	
    std::string reg = prefix+std::string("*");
    if(!linkedFile->findSymbol(found, reg.c_str(), Symbol::ST_UNKNOWN, SymtabAPI::anyName, true))
    	return false;
    for(start=0;start< found.size();start++)
		ret.push_back(found[start]);
	return true;	
}

dictionary_hash<Address, std::string> *image::getPltFuncs()
{
   bool result;
   if (pltFuncs)
      return pltFuncs;


   vector<SymtabAPI::relocationEntry> fbt;
   result = getObject()->getFuncBindingTable(fbt);
   if (!result)
      return NULL;

   pltFuncs = new dictionary_hash<Address, std::string>(addrHash);
   assert(pltFuncs);
   for(unsigned k = 0; k < fbt.size(); k++) {
#if defined(os_vxworks)
       if (fbt[k].target_addr() == 0) {
           (*pltFuncs)[fbt[k].rel_addr()] = fbt[k].name().c_str();
       }
#else
      (*pltFuncs)[fbt[k].target_addr()] = fbt[k].name().c_str();
#endif
   }
   return pltFuncs;
}

void image::getPltFuncs(std::map<Address, std::string> &out)
{
   out.clear();
   vector<SymtabAPI::relocationEntry> fbt;
   bool result = getObject()->getFuncBindingTable(fbt);
   if (!result)
      return;

   for(unsigned k = 0; k < fbt.size(); k++) {
      out[fbt[k].target_addr()] = fbt[k].name();
   }
}

image_variable* image::createImageVariable(Offset offset, std::string name, int size, pdmodule *mod)
{
    // What to do here?
    if (varsByAddr.defines(offset))
        return varsByAddr[offset];

    Variable *sVar = getObject()->createVariable(name, offset, size, mod->mod());

    image_variable *ret = new image_variable(sVar, mod);

    extern AnnotationClass<image_variable> ImageVariableUpPtrAnno;
    if (!sVar->addAnnotation(ret, ImageVariableUpPtrAnno)) {
        fprintf(stderr, "%s[%d]:  failed to add annotation here\n", FILE__, __LINE__);
    }

    createdVariables.push_back(ret);
    everyUniqueVariable.push_back(ret);
    varsByAddr[offset] = ret;
    return ret;
}


const vector<parse_block*> & image::getNewBlocks() const
{
    return newBlocks_;
}
void image::clearNewBlocks()
{
    newBlocks_.clear();
}

void image::setImageLength(Address newlen)
{
    imageLen_ = newlen; 
}

void image::destroy(ParseAPI::Block *) {}
void image::destroy(ParseAPI::Edge *) {}
void image::destroy(ParseAPI::Function *) {}
