/*
 * Copyright (c) 1996-2011 Barton P. Miller
 * 
 * We provide the Paradyn Parallel Performance 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 <assert.h>
#include <string.h>
#include <algorithm>

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

#include "Serialization.h"
#include "Symtab.h"
#include "Module.h"
#include "Collections.h"
#include "Function.h"
#include "Variable.h"

#include "annotations.h"

#include "debug.h"

#include "symtabAPI/src/Object.h"

#if !defined(os_windows)
#include <dlfcn.h>
#else
#include <windows.h>
#endif

#include <iomanip>
#include <stdarg.h>

using namespace Dyninst;
using namespace Dyninst::SymtabAPI;
using namespace std;

static std::string errMsg;
extern bool parseCompilerType(Object *);

static const int Symtab_major_version = 7;
static const int Symtab_minor_version = 0;
static const int Symtab_maintenance_version = 0;

void Symtab::version(int& major, int& minor, int& maintenance)
{
    major = Symtab_major_version;
    minor = Symtab_minor_version;
    maintenance = Symtab_maintenance_version;
}


void symtab_log_perror(const char *msg)
{
   errMsg = std::string(msg);
};


SymtabError serr;

std::vector<Symtab *> Symtab::allSymtabs;
builtInTypeCollection *Symtab::builtInTypes = NULL;
typeCollection *Symtab::stdTypes = NULL;
 
SymtabError Symtab::getLastSymtabError()
{
    return serr;
}

void setSymtabError(SymtabError new_err)
{
   serr = new_err;
}

std::string Symtab::printError(SymtabError serr)
{
    switch (serr)
    {
       case Obj_Parsing:
           return "Failed to parse the Object"+errMsg;
       case Syms_To_Functions:
           return "Failed to convert Symbols to Functions";
       case No_Such_Function:
           return "Function does not exist";
       case No_Such_Variable:
           return "Variable does not exist";
       case No_Such_Module:
          return "Module does not exist";
       case No_Such_Region:
           return "Region does not exist";
       case No_Such_Symbol:
           return "Symbol does not exist";
       case Not_A_File:
           return "Not a File. Call openArchive()";
       case Not_An_Archive:
           return "Not an Archive. Call openFile()";
       case Export_Error:
           return "Error Constructing XML"+errMsg;
       case Emit_Error:
           return "Error rewriting binary: " + errMsg;
       case Invalid_Flags:
          return "Flags passed are invalid.";
       case No_Error:
          return "No previous Error.";
       default:
          return "Unknown Error";
    }		
}

Type *Symtab::type_Error = NULL;
Type *Symtab::type_Untyped = NULL;

void Symtab::setupTypes()
{
    /*
     * Create the "error" and "untyped" types.
     */
    std::string name = "<error>";
    if (NULL == type_Error) type_Error  = new Type(name, 0, dataUnknownType);
    name = std::string("<no type>");
    if (NULL == type_Untyped) type_Untyped = new Type(name, 0, dataUnknownType);
    setupStdTypes();
}    

void Symtab::setupStdTypes() 
{
   if (builtInTypes)
    	return;

   builtInTypes = new builtInTypeCollection;
   typeScalar *newType;

   // NOTE: integral type  mean twos-complement
   // -1  int, 32 bit signed integral type
   // in stab document, size specified in bits, system size is in bytes
   builtInTypes->addBuiltInType(newType = new typeScalar(-1, 4, "int", true));
   newType->decrRefCount();
   // -2  char, 8 bit type holding a character. GDB & dbx(AIX) treat as signed
   builtInTypes->addBuiltInType(newType = new typeScalar(-2, 1, "char", true));
   newType->decrRefCount();
   // -3  short, 16 bit signed integral type
   builtInTypes->addBuiltInType(newType = new typeScalar(-3, 2, "short", true));
   newType->decrRefCount();
   // -4  long, 32/64 bit signed integral type
   builtInTypes->addBuiltInType(newType = new typeScalar(-4, sizeof(long), "long", true));
   newType->decrRefCount();
   // -5  unsigned char, 8 bit unsigned integral type
   builtInTypes->addBuiltInType(newType = new typeScalar(-5, 1, "unsigned char"));
   newType->decrRefCount();
   // -6  signed char, 8 bit signed integral type
   builtInTypes->addBuiltInType(newType = new typeScalar(-6, 1, "signed char", true));
   newType->decrRefCount();
   // -7  unsigned short, 16 bit unsigned integral type
   builtInTypes->addBuiltInType(newType = new typeScalar(-7, 2, "unsigned short"));
   newType->decrRefCount();
   // -8  unsigned int, 32 bit unsigned integral type
   builtInTypes->addBuiltInType(newType = new typeScalar(-8, 4, "unsigned int"));
   newType->decrRefCount();
   // -9  unsigned, 32 bit unsigned integral type
   builtInTypes->addBuiltInType(newType = new typeScalar(-9, 4, "unsigned"));
   newType->decrRefCount();
   // -10 unsigned long, 32 bit unsigned integral type
   builtInTypes->addBuiltInType(newType = new typeScalar(-10, sizeof(unsigned long), "unsigned long"));
   newType->decrRefCount();
   // -11 void, type indicating the lack of a value
   //  XXX-size may not be correct jdd 4/22/99
   builtInTypes->addBuiltInType(newType = new typeScalar(-11, 0, "void", false));
   newType->decrRefCount();
   // -12 float, IEEE single precision
   builtInTypes->addBuiltInType(newType = new typeScalar(-12, sizeof(float), "float", true));
   newType->decrRefCount();
   // -13 double, IEEE double precision
   builtInTypes->addBuiltInType(newType = new typeScalar(-13, sizeof(double), "double", true));
   newType->decrRefCount();
   // -14 long double, IEEE double precision, size may increase in future
   builtInTypes->addBuiltInType(newType = new typeScalar(-14, sizeof(long double), "long double", true));
   newType->decrRefCount();
   // -15 integer, 32 bit signed integral type
   builtInTypes->addBuiltInType(newType = new typeScalar(-15, 4, "integer", true));
   newType->decrRefCount();
   // -16 boolean, 32 bit type. GDB/GCC 0=False, 1=True, all other values
   //  have unspecified meaning
   builtInTypes->addBuiltInType(newType = new typeScalar(-16, sizeof(bool), "boolean"));
   newType->decrRefCount();
   // -17 short real, IEEE single precision
   //  XXX-size may not be correct jdd 4/22/99
   builtInTypes->addBuiltInType(newType = new typeScalar(-17, sizeof(float), "short real", true));
   newType->decrRefCount();
   // -18 real, IEEE double precision XXX-size may not be correct jdd 4/22/99
   builtInTypes->addBuiltInType(newType = new typeScalar(-18, sizeof(double), "real", true));
   newType->decrRefCount();
   // -19 stringptr XXX- size of void * -- jdd 4/22/99
   builtInTypes->addBuiltInType(newType = new typeScalar(-19, sizeof(void *), "stringptr"));
   newType->decrRefCount();
   // -20 character, 8 bit unsigned character type
   builtInTypes->addBuiltInType(newType = new typeScalar(-20, 1, "character"));
   newType->decrRefCount();
   // -21 logical*1, 8 bit type (Fortran, used for boolean or unsigned int)
   builtInTypes->addBuiltInType(newType = new typeScalar(-21, 1, "logical*1"));
   newType->decrRefCount();
   // -22 logical*2, 16 bit type (Fortran, some for boolean or unsigned int)
   builtInTypes->addBuiltInType(newType = new typeScalar(-22, 2, "logical*2"));
   newType->decrRefCount();
   // -23 logical*4, 32 bit type (Fortran, some for boolean or unsigned int)
   builtInTypes->addBuiltInType(newType = new typeScalar(-23, 4, "logical*4"));
   newType->decrRefCount();
   // -24 logical, 32 bit type (Fortran, some for boolean or unsigned int)
   builtInTypes->addBuiltInType(newType = new typeScalar(-24, 4, "logical"));
   newType->decrRefCount();
   // -25 complex, consists of 2 IEEE single-precision floating point values
   builtInTypes->addBuiltInType(newType = new typeScalar(-25, sizeof(float)*2, "complex", true));
   newType->decrRefCount();
   // -26 complex, consists of 2 IEEE double-precision floating point values
   builtInTypes->addBuiltInType(newType = new typeScalar(-26, sizeof(double)*2, "complex*16", true));
   newType->decrRefCount();
   // -27 integer*1, 8 bit signed integral type
   builtInTypes->addBuiltInType(newType = new typeScalar(-27, 1, "integer*1", true));
   newType->decrRefCount();
   // -28 integer*2, 16 bit signed integral type
   builtInTypes->addBuiltInType(newType = new typeScalar(-28, 2, "integer*2", true));
   newType->decrRefCount();

   /* Quick hack to make integer*4 compatible with int for Fortran
      jnb 6/20/01 */
   // This seems questionable - let's try removing that hack - jmo 05/21/04
   /*
     builtInTypes->addBuiltInType(newType = new type("int",-29,
     built_inType, 4));
     newType->decrRefCount();
   */
   // -29 integer*4, 32 bit signed integral type
   builtInTypes->addBuiltInType(newType = new typeScalar(-29, 4, "integer*4", true));
   newType->decrRefCount();
   // -30 wchar, Wide character, 16 bits wide, unsigned (unknown format)
   builtInTypes->addBuiltInType(newType = new typeScalar(-30, 2, "wchar"));
   newType->decrRefCount();
#if defined(os_windows)
   // -31 long long, 64 bit signed integral type
   builtInTypes->addBuiltInType(newType = new typeScalar(-31, sizeof(LONGLONG), "long long", true));
   newType->decrRefCount();
   // -32 unsigned long long, 64 bit unsigned integral type
   builtInTypes->addBuiltInType(newType = new typeScalar(-32, sizeof(ULONGLONG), "unsigned long long"));
   newType->decrRefCount();
#else
   // -31 long long, 64 bit signed integral type
   builtInTypes->addBuiltInType(newType = new typeScalar(-31, sizeof(long long), "long long", true));
   newType->decrRefCount();
   // -32 unsigned long long, 64 bit unsigned integral type
   builtInTypes->addBuiltInType(newType = new typeScalar(-32, sizeof(unsigned long long), "unsigned long long"));
   newType->decrRefCount();
#endif
   // -33 logical*8, 64 bit unsigned integral type
   builtInTypes->addBuiltInType(newType = new typeScalar(-33, 8, "logical*8"));
   newType->decrRefCount();
   // -34 integer*8, 64 bit signed integral type
   builtInTypes->addBuiltInType(newType = new typeScalar(-34, 8, "integer*8", true));
   newType->decrRefCount();

	/*
    * Initialize hash table of standard types.
    */
	if (stdTypes)
    	return;

   stdTypes = new typeCollection();
   stdTypes->addType(newType = new typeScalar(-1, sizeof(int), "int"));
   newType->decrRefCount();

   Type *charType = new typeScalar(-2, sizeof(char), "char");
   stdTypes->addType(charType);

	std::string tName = "char *";
	typePointer *newPtrType;
   stdTypes->addType(newPtrType = new typePointer(-3, charType, tName));
   charType->decrRefCount();
   newPtrType->decrRefCount();

   Type *voidType = new typeScalar(-11, 0, "void", false);
   stdTypes->addType(voidType);

	tName = "void *";
   stdTypes->addType(newPtrType = new typePointer(-4, voidType, tName));
   voidType->decrRefCount();
   newPtrType->decrRefCount();

   stdTypes->addType(newType = new typeScalar(-12, sizeof(float), "float"));
   newType->decrRefCount();

#if defined(i386_unknown_nt4_0)
   stdTypes->addType(newType = new typeScalar(-31, sizeof(LONGLONG), "long long"));    
#else
   stdTypes->addType(newType = new typeScalar(-31, sizeof(long long), "long long"));
#endif

	newType->decrRefCount();

   return;
}

SYMTAB_EXPORT unsigned Symtab::getAddressWidth() const 
{
   return address_width_;
}
 
SYMTAB_EXPORT bool Symtab::isNativeCompiler() const 
{
    return nativeCompiler; 
}

SYMTAB_EXPORT Symtab::Symtab(MappedFile *mf_) :
   AnnotatableSparse(),
   mf(mf_), 
   mfForDebugInfo(mf_),
   imageOffset_(0),   
   address_width_(sizeof(int)),
   object_type_(obj_Unknown),
   defaultNamespacePrefix(""),
   no_of_sections(0),
   newSectionInsertPoint(0),
   no_of_symbols(0),
   obj_private(NULL),
   _ref_cnt(1)
{
    init_debug_symtabAPI();

#if defined(os_vxworks)
    // This is how we initialize objects from WTX information alone.
    // Basically replaces extractInfo().
    object_type_ = obj_RelocatableFile;
    mfForDebugInfo = NULL;
    imageOffset_ = 0;
    dataOffset_ = 0;
    imageLen_ = 0;
    dataLen_ = 0;
    isStaticBinary_ = false;
    hasRel_ = false;
    hasRela_ = false;
    hasReldyn_ = false;
    hasReladyn_ = false;
    hasRelplt_ = false;
    hasRelaplt_ = false;
    is_a_out = false;
    code_ptr_ = NULL;
    data_ptr_ = NULL;
    entry_address_ = 0;
    base_address_ = 0;
    load_address_ = 0;
    toc_offset_ = 0;
    is_eel_ = false;
#endif

    createDefaultModule();
}

SYMTAB_EXPORT Symtab::Symtab() :
   imageOffset_(0),
   address_width_(sizeof(int)),
   object_type_(obj_Unknown),
   defaultNamespacePrefix(""),
   no_of_sections(0),
   newSectionInsertPoint(0),
   no_of_symbols(0),
   obj_private(NULL),
   _ref_cnt(1)
{
    init_debug_symtabAPI();
    create_printf("%s[%d]: Created symtab via default constructor\n", FILE__, __LINE__);
    createDefaultModule();
}

SYMTAB_EXPORT bool Symtab::isExec() const 
{
    return is_a_out; 
}

SYMTAB_EXPORT bool Symtab::isStripped() 
{
#if defined(os_linux) || defined(os_freebsd) || defined(os_solaris)
    Region *sec;
    return !findRegion(sec,".symtab");
#else
    return (no_of_symbols==0);
#endif
}

SYMTAB_EXPORT Offset Symtab::imageOffset() const 
{
    return imageOffset_;
}

SYMTAB_EXPORT Offset Symtab::dataOffset() const 
{ 
    return dataOffset_;
}

SYMTAB_EXPORT Offset Symtab::dataLength() const 
{
    return dataLen_;
} 

SYMTAB_EXPORT Offset Symtab::imageLength() const 
{
    return imageLen_;
}

SYMTAB_EXPORT void Symtab::fixup_code_and_data(Offset newImageOffset,
                                               Offset newImageLength,
                                               Offset newDataOffset,
                                               Offset newDataLength)
{
    imageOffset_ = newImageOffset;
    imageLen_ = newImageLength;
    dataOffset_ = newDataOffset;
    dataLen_ = newDataLength;

    // Should we update the underlying Object?
}

/*
SYMTAB_EXPORT char* Symtab::image_ptr ()  const 
{
   return code_ptr_;
}

SYMTAB_EXPORT char* Symtab::data_ptr ()  const 
{ 
   return data_ptr_;
}
*/
SYMTAB_EXPORT const char*  Symtab::getInterpreterName() const 
{
   if (interpreter_name_.length())
      return interpreter_name_.c_str();
   return NULL;
}
 
SYMTAB_EXPORT Offset Symtab::getEntryOffset() const 
{ 
   return entry_address_;
}

SYMTAB_EXPORT Offset Symtab::getBaseOffset() const 
{
   return base_address_;
}

SYMTAB_EXPORT Offset Symtab::getLoadOffset() const 
{ 
   return load_address_;
}

SYMTAB_EXPORT Offset Symtab::getTOCoffset() const 
{
   return toc_offset_;
}

SYMTAB_EXPORT string Symtab::getDefaultNamespacePrefix() const
{
    return defaultNamespacePrefix;
}
	
	
// TODO -- is this g++ specific
bool Symtab::buildDemangledName( const std::string &mangled, 
      std::string &pretty,
      std::string &typed,
      bool nativeCompiler, 
      supportedLanguages lang )
{
   /* The C++ demangling function demangles MPI__Allgather (and other MPI__
    * functions with start with A) into the MPI constructor.  In order to
    * prevent this a hack needed to be made, and this seemed the cleanest
    * approach.
    */

   if ((mangled.length()>5) && (mangled.substr(0,5)==std::string("MPI__"))) 
   {
      return false;
   }	  

   /* If it's Fortran, eliminate the trailing underscores, if any. */
   if (lang == lang_Fortran 
         || lang == lang_CMFortran 
         || lang == lang_Fortran_with_pretty_debug )
   {
      if ( mangled[ mangled.length() - 1 ] == '_' ) 
      {
         char * demangled = P_strdup( mangled.c_str() );
         demangled[ mangled.length() - 1 ] = '\0';
         pretty = std::string( demangled );

         free ( demangled );
         return true;
      }
      else 
      {
         /* No trailing underscores, do nothing */
         return false;
      }
   } /* end if it's Fortran. */

   //  Check to see if we have a gnu versioned symbol on our hands.
   //  These are of the form <symbol>@<version> or <symbol>@@<version>
   //
   //  If we do, we want to create a "demangled" name for the one that
   //  is of the form <symbol>@@<version> since this is, by definition,
   //  the default.  The "demangled" name will just be <symbol>

   //  NOTE:  this is just a 0th order approach to dealing with versioned
   //         symbols.  We may need to do something more sophisticated
   //         in the future.  JAW 10/03

#if !defined(os_windows)

   const char *atat;

   if (NULL != (atat = strstr(mangled.c_str(), "@@"))) 
   {
        pretty = mangled.substr(0 /*start pos*/, 
                        (int)(atat - mangled.c_str())/*len*/);
        //char msg[256];
        //sprintf(msg, "%s[%d]: 'demangling' versioned symbol: %s, to %s",
        //          __FILE__, __LINE__, mangled.c_str(), pretty.c_str());

        //cerr << msg << endl;
        //logLine(msg);
      
        return true;
    }

#endif

    bool retval = false;
  
    /* Try demangling it. */
    char * demangled = P_cplus_demangle( mangled.c_str(), nativeCompiler, false);
    if (demangled) 
    {
        pretty = std::string( demangled );
        retval = true;
    }
  
    char *t_demangled = P_cplus_demangle(mangled.c_str(), nativeCompiler, true);
    if (t_demangled && (strcmp(t_demangled, demangled) != 0)) 
    {
        typed = std::string(t_demangled);
        retval = true;
    }

    if (demangled)
        free(demangled);
    if (t_demangled)
        free(t_demangled);

    return retval;
} /* end buildDemangledName() */


/*
 * extractSymbolsFromFile
 *
 * Create a Symtab-level list of symbols by pulling out data
 * from the low-level parse (linkedFile).
 * Technically this causes a duplication of symbols; however,
 * we will be rewriting these symbols and so we need our own
 * copy. 
 *
 * TODO: delete the linkedFile once we're done?
 */

bool Symtab::extractSymbolsFromFile(Object *linkedFile, std::vector<Symbol *> &raw_syms) 
{
    for (SymbolIter symIter(*linkedFile); symIter; symIter++) 
	{
        Symbol *sym = symIter.currval();
		if (!sym) 
		{
			fprintf(stderr, "%s[%d]:  range error, stopping now\n", FILE__, __LINE__);
			return true;
		}

        // If a symbol starts with "." we want to skip it. These indicate labels in the
        // code. 
        
        // removed 1/09: this should be done in Dyninst, not Symtab

        // check for undefined dynamic symbols. Used when rewriting relocation section.
        // relocation entries have references to these undefined dynamic symbols.
        // We also have undefined symbols for the static binary case.
        
#if !defined(os_vxworks)
        if (sym->getSec() == NULL && !sym->isAbsolute() && !sym->isCommonStorage()) {
            undefDynSyms[sym->getMangledName()].push_back(sym);
            continue;
        }
#endif

        // Check whether this symbol has a valid offset. If they do not we have a
        // consistency issue. This should be a null check.

        // Symbols can have an offset of 0 if they don't refer to things within a file.

        raw_syms.push_back(sym);
    }

    return true;
}

/*
 * fixSymModules
 * 
 * Add Module information to all symbols. 
 */

bool Symtab::fixSymModules(std::vector<Symbol *> &raw_syms) 
{
    for (unsigned i = 0; i < raw_syms.size(); i++) {
        fixSymModule(raw_syms[i]);
    }
	Object *obj = getObject();
	if (!obj)
	{
#if !defined(os_vxworks)
		fprintf(stderr, "%s[%d]:  getObject failed here\n", FILE__, __LINE__);
#endif
		return false;
	}
    const std::vector<std::pair<std::string, Offset> > &mods = obj->modules_;
    for (unsigned i=0; i< mods.size(); i++) {
       getOrCreateModule(mods[i].first, mods[i].second);
    }
       
    return true;
}

/*
 * demangleSymbols
 *
 * Perform name demangling on all symbols.
 */

bool Symtab::demangleSymbols(std::vector<Symbol *> &raw_syms) 
{
    for (unsigned i = 0; i < raw_syms.size(); i++) {
        demangleSymbol(raw_syms[i]);
    }
    return true;
}

/*
 * createIndices
 *
 * We index symbols by various attributes for quick lookup. Build those
 * indices here. 
 */

bool Symtab::createIndices(std::vector<Symbol *> &raw_syms) {
    for (unsigned i = 0; i < raw_syms.size(); i++) {
        addSymbolToIndices(raw_syms[i]);
    }
    return true;
}

/*
 * createAggregates
 *
 * Frequently there will be multiple Symbols that refer to a single 
 * code object (e.g., function or variable). We use separate objects
 * to refer to these aggregates, and build those objects here. 
 */

bool Symtab::createAggregates() 
{
#if !defined(os_vxworks)
    // In VxWorks, symbol offsets are not complete until object is loaded.

    for (unsigned i = 0; i < everyDefinedSymbol.size(); i++) 
      {
	if (!doNotAggregate(everyDefinedSymbol[i])) {
	  addSymbolToAggregates(everyDefinedSymbol[i]);
	}
      }
#endif

    return true;
}
 
bool Symtab::fixSymModule(Symbol *&sym) 
{
    //////////
    //////////
    //////////
    //
    // It has been decided that all libraries shall have only one
    // module named after the library. The a.out has one module
    // per (reported) source file, plus DEFAULT_MODULE for everything
    // else. This is enforced here, although the Object-* files might
    // do it as well.
    Module *mod = NULL;
    if (getObjectType() == obj_SharedLib) {
        mod = getDefaultModule();
    }
    else {
		Object *obj = getObject();
		if (!obj)
		{
#if !defined(os_vxworks)
			fprintf(stderr, "%s[%d]:  getObject failed here\n", FILE__, __LINE__);
#endif
			return false;
		}
        std::string modName = obj->findModuleForSym(sym);
        if (modName.length() == 0) {
            mod = getDefaultModule();
        }
        else {
            mod = getOrCreateModule(modName, sym->getOffset());
        }
    }
    if (!mod)
        return false;

    sym->setModule(mod);
    return true;
}

bool Symtab::demangleSymbol(Symbol *&sym) {
    switch (sym->getType()) {
    case Symbol::ST_FUNCTION: {
        Module *rawmod = sym->getModule();
        assert(rawmod);
        
        // At this point we need to generate the following information:
        // A symtab name.
        // A pretty (demangled) name.
        // The symtab name goes in the global list as well as the module list.
        // Same for the pretty name.
        // Finally, check addresses to find aliases.
        
        std::string mangled_name = sym->getMangledName();
        std::string working_name = mangled_name;
        
#if !defined(os_windows)        
        //Remove extra stabs information
        const char *p = strchr(working_name.c_str(), ':');
        if( p ) {
            unsigned nchars = p - mangled_name.c_str();
            working_name = std::string(mangled_name.c_str(), nchars);
        }
#endif        
        
        std::string pretty_name = working_name;
        std::string typed_name = working_name;
        
        if (!buildDemangledName(working_name, pretty_name, typed_name,
                                nativeCompiler, rawmod->language())) {
            pretty_name = working_name;
        }

        sym->prettyName_ = pretty_name;
        sym->typedName_ = typed_name;
        
        break;
    }
    default: {
        // All cases where there really shouldn't be a mangled
        // name, since mangling is for functions.
        
        char *prettyName = P_cplus_demangle(sym->getMangledName().c_str(), nativeCompiler, false);
        if (prettyName) {
            sym->prettyName_ = prettyName;
        }
        break;
    }
    }
    return true;
}

bool Symtab::addSymbolToIndices(Symbol *&sym) 
{
	assert(sym);
//	sym->index_ = everyDefinedSymbol.size();

    everyDefinedSymbol.push_back(sym);

#if !defined(os_vxworks)    
    // VxWorks doesn't know symbol addresses until object is loaded.
    symsByOffset[sym->getAddr()].push_back(sym);
#endif

    symsByMangledName[sym->getMangledName()].push_back(sym);

    symsByPrettyName[sym->getPrettyName()].push_back(sym);

    symsByTypedName[sym->getTypedName()].push_back(sym);

    return true;
}

bool Symtab::addSymbolToAggregates(Symbol *&sym) 
{

    switch(sym->getType()) {
    case Symbol::ST_FUNCTION: {
        // We want to do the following:
        // If no function exists, create and add. 
        // Combine this information
        //   Add this symbol's names to the function.
        //   Keep module information 

        Function *func = NULL;
        findFuncByEntryOffset(func, sym->getAddr());
        if (!func) {
            // Create a new function
            // Also, update the symbol to point to this function.

            func = new Function(sym);

            everyFunction.push_back(func);
            sorted_everyFunction = false;
            funcsByOffset[sym->getAddr()] = func;
        }
        else {
            /* XXX 
             * For relocatable files, the offset of a symbol is relative to the
             * beginning of a Region. Therefore, a symbol in a relocatable file
             * is not uniquely identifiable by its offset, but it is uniquely
             * identifiable by its Region and its offset.
             *
             * For now, do not add these functions to funcsByOffset collection.
             */

            if( func->getRegion() != sym->getRegion() ) {
                func = new Function(sym);
                everyFunction.push_back(func);
                sorted_everyFunction = false;
            }
            func->addSymbol(sym);
        } 
        sym->setFunction(func);

        break;
    }
    case Symbol::ST_TLS:
    case Symbol::ST_OBJECT: {
        // The same as the above, but with variables.
        Variable *var = NULL;
        findVariableByOffset(var, sym->getAddr());
        if (!var) {
            // Create a new function
            // Also, update the symbol to point to this function.
            var = new Variable(sym);
            
            everyVariable.push_back(var);
            varsByOffset[sym->getAddr()] = var;
        }
        else {
            /* XXX
             * For relocatable files, the offset is not a unique identifier for
             * a Symbol. With functions, the Region and offset could be used to
             * identify the symbol. With variables, the Region and offset may 
             * not uniquely identify the symbol. The only case were this occurs
             * is with COMMON symbols -- their offset is their memory alignment
             * and their Region is undefined. In this case, always create a 
             * new variable.
             */
            if( obj_RelocatableFile == getObjectType() &&
                ( var->getRegion() != sym->getRegion() ||
                  NULL == sym->getRegion() ) )
            {
                var = new Variable(sym);
                everyVariable.push_back(var);
            }else{
                var->addSymbol(sym);
            }
        }
        sym->setVariable(var);
        break;
    }
    default: {
        break;
    }
    }
    return true;
}

// A hacky override for specially treating symbols that appear
// to be functions or variables but aren't.
//
// Example: IA-32/AMD-64 libc (and others compiled with libc headers)
// uses outlined locking primitives. These are named _L_lock_<num>
// and _L_unlock_<num> and labelled as functions. We explicitly do
// not include them in function scope.
bool Symtab::doNotAggregate(Symbol *&sym) {
  if (sym->getMangledName().compare(0, strlen("_L_lock_"), "_L_lock_") == 0) {
    return true;
  }
  if (sym->getMangledName().compare(0, strlen("_L_unlock_"), "_L_unlock_") == 0) {
    return true;
  }

  // PPC64 Linux symbols in the .opd section appear to be functions,
  // but are not.
  if (sym->getRegion() && sym->getRegion()->getRegionName() == ".opd") {
      return true;
  }

  return false;
}

/* Add the new name to the appropriate symbol index */

bool Symtab::updateIndices(Symbol *sym, std::string newName, NameType nameType) {
    if (nameType & mangledName) {
        // Add this symbol under the given name (as mangled)
        symsByMangledName[newName].push_back(sym);
    }
    if (nameType & prettyName) {
        // Add this symbol under the given name (as pretty)
        symsByPrettyName[newName].push_back(sym);
    }
    if (nameType & typedName) {
        // Add this symbol under the given name (as typed)
        symsByTypedName[newName].push_back(sym);
    }
    return true;
}

#if 0
/* checkPPC64DescriptorSymbols() is no longer needed.  3-word descriptor
 * symbols are properly taken care of during symbol parsing.  See
 * parse_symbols() in Object-elf.C for details.
 */

#if defined(ppc64_linux)
/* Special case for ppc64 ELF binaries. Sometimes a function has a 3-byte descriptor symbol
 * along with it in the symbol table and "." preceding its original pretty name for the correct
 * function symbol. This checks to see if we have a corresponding 3-byte descriptor symbol existing
 * and if it does we remove the preceding "." from the name of the symbol
 */

void Symtab::checkPPC64DescriptorSymbols(Object *linkedFile)
{
   // find the real functions -- those with the correct type in the symbol table
   for(SymbolIter symIter(*linkedFile); symIter;symIter++)
   {
      Symbol *lookUp = symIter.currval();
      const char *np = lookUp->getMangledName().c_str();
      if(!np)
         continue;

      if(np[0] == '.' && (lookUp->getType() == Symbol::ST_FUNCTION))
      {
         std::vector<Symbol *>syms;
         std::string newName = np+1;
         if(linkedFile->get_symbols(newName, syms) && (syms[0]->getSize() == 24 || syms[0]->getSize() == 0))
         {
            //Remove the "." from the name
            lookUp->mangledNames[0] = newName;

            //Change the type of the descriptor symbol
            syms[0]->type_ = Symbol::ST_NOTYPE;
         }
      }
   }

}

#endif
#endif

//  setModuleLanguages is only called after modules have been defined.
//  it attempts to set each module's language, information which is needed
//  before names can be demangled.
void Symtab::setModuleLanguages(dyn_hash_map<std::string, supportedLanguages> *mod_langs)
{
   if (!mod_langs->size())
      return;  // cannot do anything here
   //  this case will arise on non-stabs platforms until language parsing can be introduced at this level
   std::vector<Module *> *modlist;
   Module *currmod = NULL;
   modlist = &_mods;
   //int dump = 0;

   for (unsigned int i = 0;  i < modlist->size(); ++i)
   {
      currmod = (*modlist)[i];
      supportedLanguages currLang;
      if (currmod->isShared()) {
         continue;  // need to find some way to get shared object languages?
      }

      const std::string fn = currmod->fileName();
      if (mod_langs->find(currmod->fileName()) != mod_langs->end())
      {
         currLang = (*mod_langs)[fn];
      }
      else if (fn.rfind(".s") != std::string::npos ||
            fn.rfind(".asm") != std::string::npos)
      {
         currLang = lang_Assembly;
      }
      else if (fn.rfind(".c") != std::string::npos)
      {
         currLang = lang_C;
      }
      else if (fn.rfind(".cpp") != std::string::npos ||
            fn.rfind(".cc") != std::string::npos ||
            fn.rfind(".C") != std::string::npos)
      {
         currLang = lang_CPlusPlus;
      }
      else
      {
         continue;
      }
      currmod->setLanguage(currLang);
   }
}

void Symtab::createDefaultModule() {
    Module *mod = NULL;
    if (getObjectType() == obj_SharedLib) {
        mod = new Module(lang_Unknown, 
                         imageOffset_,
                         name(),
                         this);
    }
    else {
        mod = new Module(lang_Unknown, 
                         imageOffset_,
#if defined(os_vxworks)
                         // VxWorks' kernel objects should
                         // have their own module.
                         name(),
#else
                         "DEFAULT_MODULE",
#endif
                         this);
    }
    modsByFileName[mod->fileName()] = mod;
    modsByFullName[mod->fullName()] = mod;
    _mods.push_back(mod);
}



Module *Symtab::getOrCreateModule(const std::string &modName, 
                                  const Offset modAddr)
{
   std::string nameToUse;
   if (modName.length() > 0)
      nameToUse = modName;
   else
      nameToUse = "DEFAULT_MODULE";

   Module *fm = NULL;
   if (findModuleByName(fm, nameToUse)) 
   {
      return fm;
   }

    const char *str = nameToUse.c_str();
    int len = nameToUse.length();
    assert(len>0);

    // TODO ignore directory definitions for now
    if (str[len-1] == '/') 
        return NULL;

    return (newModule(nameToUse, modAddr, lang_Unknown));
}
 
Module *Symtab::newModule(const std::string &name, const Offset addr, supportedLanguages lang)
{
    Module *ret = NULL;
    // modules can be defined several times in C++ due to templates and
    //   in-line member functions.

    if (findModuleByName(ret, name)) 
    {
        return(ret);
    }

    //parsing_printf("=== image, creating new pdmodule %s, addr 0x%x\n",
    //				name.c_str(), addr);
    
    std::string fileNm, fullNm;
    fullNm = name;
    fileNm = extract_pathname_tail(name);

    // /* DEBUG */ fprintf( stderr, "%s[%d]: In %p: Creating new pdmodule '%s'/'%s'\n", FILE__, __LINE__, this, fileNm.c_str(), fullNm.c_str() );
    create_printf("%s[%d]: In %p: Creating new module '%s'/'%s'\n", FILE__, __LINE__, this, fileNm.c_str(), fullNm.c_str());

    ret = new Module(lang, addr, fullNm, this);
    assert(ret);

    /*
     * FIXME
     *
     * There are cases where the fileName can be the same, but the full name is
     * different and the modules are actually different. This is an inherent
     * problem with how modules are processed.
     */
    if (modsByFileName.end() != modsByFileName.find(ret->fileName()))
    {
       create_printf("%s[%d]:  WARN:  LEAK?  already have module with name %s\n", 
             FILE__, __LINE__, ret->fileName().c_str());
    }

    if (modsByFullName.end() != modsByFullName.find(ret->fullName()))
    {
       create_printf("%s[%d]:  WARN:  LEAK?  already have module with name %s\n", 
                     FILE__, __LINE__, ret->fullName().c_str());
    }

    modsByFileName[ret->fileName()] = ret;
    modsByFullName[ret->fullName()] = ret;
    _mods.push_back(ret);
    
    return (ret);
}

Symtab::Symtab(std::string filename,bool &err) :
   member_offset_(0),
   is_a_out(false), 
   main_call_addr_(0),
   nativeCompiler(false), 
   isLineInfoValid_(false), 
   isTypeInfoValid_(false),
   obj_private(NULL),
   _ref_cnt(1)
{
    init_debug_symtabAPI();
   // Initialize error parameter
   err = false;
   
   create_printf("%s[%d]: created symtab for %s\n", FILE__, __LINE__, filename.c_str());

#if defined (os_windows)
   extern void fixup_filename(std::string &);
   fixup_filename(filename);
#endif

   //  createMappedFile handles reference counting
   mf = MappedFile::createMappedFile(filename);
   if (!mf) {
      create_printf("%s[%d]: WARNING: creating symtab for %s, " 
                    "createMappedFile() failed\n", FILE__, __LINE__, 
                    filename.c_str());
      err = true;
      return;
   }

   obj_private = new Object(mf, mfForDebugInfo, symtab_log_perror, true);
   if (obj_private->hasError()) {
     err = true;
     return;
   }

   if (!extractInfo(obj_private))
   {
      create_printf("%s[%d]: WARNING: creating symtab for %s, extractInfo() " 
                    "failed\n", FILE__, __LINE__, filename.c_str());
      err = true;
   }

   member_name_ = mf->filename();

   defaultNamespacePrefix = "";
}

Symtab::Symtab(char *mem_image, size_t image_size, bool &err) :
   member_offset_(0),
   is_a_out(false), 
   main_call_addr_(0),
   nativeCompiler(false),
   isLineInfoValid_(false),
   isTypeInfoValid_(false),
   obj_private(NULL),
   _ref_cnt(1)
{
   // Initialize error parameter
   err = false;
  
   create_printf("%s[%d]: created symtab for memory image at addr %u\n", 
                 FILE__, __LINE__, mem_image);

   //  createMappedFile handles reference counting
   mf = MappedFile::createMappedFile(mem_image, image_size);
   if (!mf) {
      create_printf("%s[%d]: WARNING: creating symtab for memory image at " 
                    "addr %u, createMappedFile() failed\n", FILE__, __LINE__, 
                    mem_image);
      err = true;
      return;
   }

   obj_private = new Object(mf, mfForDebugInfo, symtab_log_perror, true);
   if (obj_private->hasError()) {
     err = true;
     return;
   }

   if (!extractInfo(obj_private))
   {
      create_printf("%s[%d]: WARNING: creating symtab for memory image at addr" 
                    "%u, extractInfo() failed\n", FILE__, __LINE__, mem_image);
      err = true;
   }

   member_name_ = mf->filename();

   defaultNamespacePrefix = "";
}

// Symtab constructor for archive members
#if defined(os_aix)
Symtab::Symtab(std::string filename, std::string member_name, Offset offset, 
               bool &err, void *base) :
   member_name_(member_name), 
   member_offset_(offset),
   is_a_out(false),
   main_call_addr_(0), 
   nativeCompiler(false), 
   isLineInfoValid_(false),
   isTypeInfoValid_(false), 
   obj_private(NULL),
   _ref_cnt(1)
{
   mf = MappedFile::createMappedFile(filename);
   assert(mf);
   obj_private = new Object(mf, mfForDebugInfo, member_name, offset, symtab_log_perror, base);
   if (obj_private->hasError()) {
     err = true;
     return;
   }
   err = !extractInfo(obj_private);
   defaultNamespacePrefix = "";

   create_printf("%s[%d]: created symtab for %s(%s)\n", FILE__, __LINE__, filename.c_str(),
           member_name.c_str());
}
#else
Symtab::Symtab(std::string, std::string, Offset, bool &, void *)
{
    assert(0);
}
#endif

#if defined(os_aix)
Symtab::Symtab(char *mem_image, size_t image_size, std::string member_name,
                       Offset offset, bool &err, void *base) :
   member_name_(member_name), 
   member_offset_(offset),
   is_a_out(false), 
   main_call_addr_(0),
   nativeCompiler(false), 
   isLineInfoValid_(false), 
   isTypeInfoValid_(false),
   _ref_cnt(1)
{
   mf = MappedFile::createMappedFile(mem_image, image_size);
   assert(mf);
   obj_private = new Object(mf, mf, member_name, offset, symtab_log_perror, base);
   if (obj_private->hasError()) {
     err = true;
     return;
   }
   err = !extractInfo(obj_private);
   defaultNamespacePrefix = "";
}
#else 
Symtab::Symtab(char *, size_t, std::string , Offset, bool &, void *)
{
    assert(0);
}
#endif

bool sort_reg_by_addr(const Region* a, const Region* b)
{
  if (a->getRegionAddr() == b->getRegionAddr())
    return a->getMemSize() < b->getMemSize();
  return a->getRegionAddr() < b->getRegionAddr();
}

extern void print_symbols( std::vector< Symbol *>& allsymbols );
extern void print_symbol_map( dyn_hash_map< std::string, std::vector< Symbol *> > *symbols);

bool Symtab::extractInfo(Object *linkedFile)
{
#if defined(TIMED_PARSE)
    struct timeval starttime;
    gettimeofday(&starttime, NULL);
#endif
    mfForDebugInfo = linkedFile->getMappedFileForDebugInfo();

    /* FIXME 
     *
     * Some ELF .o's don't have contiguous code and data Regions so these data
     * members are imprecise. These members should probably be deprecated in
     * favor of the getCodeRegions and getDataRegions functions.
     */

    bool err = true;
    imageOffset_ = linkedFile->code_off();
    dataOffset_ = linkedFile->data_off();

    imageLen_ = linkedFile->code_len();
    dataLen_ = linkedFile->data_len();
    
    if (0 == imageLen_ || 0 == linkedFile->code_ptr()) 
    {
        // for AIX, code_ptr()==NULL is normal behavior
#if !defined(os_aix)
       if (0 == linkedFile->code_ptr()) {
          //fprintf(stderr, "[%s][%d]WARNING: null code pointer in Symtab for"
          //" file %s, possibly due to a missing .text section.\n",
          //__FILE__,__LINE__, file().c_str());
          linkedFile->code_ptr_ = (char *) linkedFile->code_off();
       }
       else 
#endif
       {
           if( object_type_ != obj_RelocatableFile ||
               linkedFile->code_ptr() == 0)
           {
                serr = Obj_Parsing;
                return false;
           }
       }
   }
	
  //  if (!imageLen_ || !linkedFile->code_ptr()) {
  //      serr = Obj_Parsing; 
  //      return false; 
   // }

    no_of_sections = linkedFile->no_of_sections();
    newSectionInsertPoint = no_of_sections;
    no_of_symbols = linkedFile->no_of_symbols();
    
    isStaticBinary_ = linkedFile->isStaticBinary();

    hasRel_ = false;
    hasRela_ = false;
    hasReldyn_ = false;
    hasReladyn_ = false;
    hasRelplt_ = false;
    hasRelaplt_ = false;
    regions_ = linkedFile->getAllRegions();

    for (unsigned index=0;index<regions_.size();index++)
    {
        if ( regions_[index]->isLoadable() ) 
        {
           if (     (regions_[index]->getRegionPermissions() == Region::RP_RX) 
                 || (regions_[index]->getRegionPermissions() == Region::RP_RWX)) 
           {
              codeRegions_.push_back(regions_[index]);
           }
           else 
           {
              dataRegions_.push_back(regions_[index]);
           }
        }

        regionsByEntryAddr[regions_[index]->getRegionAddr()] = regions_[index];

        if (regions_[index]->getRegionType() == Region::RT_REL) 
        {
            hasRel_ = true;
        }

        if (regions_[index]->getRegionType() == Region::RT_RELA) 
        {
            hasRela_ = true;
        }

#if defined(os_linux) || defined(os_solaris) || defined(os_freebsd)
        hasReldyn_ = linkedFile->hasReldyn();
	hasReladyn_ = linkedFile->hasReladyn();
        hasRelplt_ = linkedFile->hasRelplt();
        hasRelaplt_ = linkedFile->hasRelaplt();
#endif	

    }
    // sort regions_ & codeRegions_ vectors

    std::sort(codeRegions_.begin(), codeRegions_.end(), sort_reg_by_addr);
    std::sort(dataRegions_.begin(), dataRegions_.end(), sort_reg_by_addr);
    std::sort(regions_.begin(), regions_.end(), sort_reg_by_addr);

    /* insert error check here. check if parsed */
    address_width_ = linkedFile->getAddressWidth();
    is_a_out = linkedFile->is_aout();
    code_ptr_ = linkedFile->code_ptr();
    data_ptr_ = linkedFile->data_ptr();

    if (linkedFile->interpreter_name())
       interpreter_name_ = std::string(linkedFile->interpreter_name());

    entry_address_ = linkedFile->getEntryAddress();
    base_address_ = linkedFile->getBaseAddress();
    load_address_ = linkedFile->getLoadAddress();
    toc_offset_ = linkedFile->getTOCoffset();
    object_type_  = linkedFile->objType();
    is_eel_ = linkedFile->isEEL();
    linkedFile->getSegments(segments_);

#if !defined(os_aix) && !defined(os_windows)
    linkedFile->getDependencies(deps_);
#endif

#if defined (os_aix)
    //  These should go away
    linkedFile->get_stab_info(stabstr_, nstabs_, stabs_, stringpool_);
    linkedFile->get_line_info(nlines_, lines_, fdptr_);
#endif

#if defined(os_solaris) || defined(os_aix) || defined(os_linux) || defined(os_freebsd)
    // make sure we're using the right demangler
    
    nativeCompiler = parseCompilerType(linkedFile);
    //parsing_printf("isNativeCompiler: %d\n", nativeCompiler);
#endif
    
    // define all of the functions
    //statusLine("winnowing functions");

    // a vector to hold all created symbols until they are properly classified
    std::vector<Symbol *> raw_syms;

#ifdef BINEDIT_DEBUG
    printf("== from linkedFile...\n");
    print_symbol_map(linkedFile->getAllSymbols());
#endif

    if (!extractSymbolsFromFile(linkedFile, raw_syms)) 
    {
        err = false;
        serr = Syms_To_Functions;
        return false;
    }

#ifdef BINEDIT_DEBUG
    printf("== in Symtab now...\n");
    //print_symbols(raw_syms);
    std::vector<Symbol *> undefsyms;
    std::map<std::string, std::vector<Symbol *> >::iterator iter;
    std::vector<Symbol *>::iterator siter;
    for (iter = undefDynSyms.begin(); iter != undefDynSyms.end(); iter++)
        for (siter = iter->second.begin(); siter != iter->second.end(); siter++)
            undefsyms.push_back(*siter);
    //print_symbols(undefsyms);
    printf("%d total symbol(s)\n", raw_syms.size() + undefsyms.size());
#endif

    // don't sort the symbols--preserve the original ordering
    //sort(raw_syms.begin(),raw_syms.end(),symbol_compare);

    createDefaultModule();

    if (!fixSymModules(raw_syms)) 
    {
        err = false;
        serr = Syms_To_Functions;
        return false;
    }
	Object *obj = getObject();
	if (!obj)
	{
#if !defined(os_vxworks)
		fprintf(stderr, "%s[%d]:  getObject failed here\n", FILE__, __LINE__);
#endif
		return false;
	}
    obj->clearSymsToMods();

    // wait until all modules are defined before applying languages to
    // them we want to do it this way so that module information comes
    // from the function symbols, first and foremost, to avoid any
    // internal module-function mismatching.
            
    // get Information on the language each modules is written in
    // (prior to making modules)

    dyn_hash_map<std::string, supportedLanguages> mod_langs;
    linkedFile->getModuleLanguageInfo(&mod_langs);
    setModuleLanguages(&mod_langs);
	
    // Be sure that module languages are set before demangling, or
    // we won't get very far.

    if (!demangleSymbols(raw_syms)) 
    {
        err = false;
        serr = Syms_To_Functions;
        return false;
    }

    if (!createIndices(raw_syms)) 
    {
        err = false;
        serr = Syms_To_Functions;
        return false;
    }

    if (!createAggregates()) 
    {
        err = false;
        serr = Syms_To_Functions;
        return false;
    }
	
    // Once languages are assigned, we can build demangled names (in
    // the wider sense of demangling which includes stripping _'s from
    // fortran names -- this is why language information must be
    // determined before this step).
    
    // Also identifies aliases (multiple names with equal addresses)
    
    //addSymtabVariables();
    linkedFile->getAllExceptions(excpBlocks);

    vector<relocationEntry >fbt;
    linkedFile->get_func_binding_table(fbt);
    for(unsigned i=0; i<fbt.size();i++)
        relocation_table_.push_back(fbt[i]);
    return true;
}

Symtab::Symtab(const Symtab& obj) :
   LookupInterface(),
   Serializable(),
   AnnotatableSparse(),
   _ref_cnt(1)
{
    create_printf("%s[%d]: Creating symtab 0x%p from symtab 0x%p\n", FILE__, __LINE__, this, &obj);
  
    member_name_ = obj.member_name_;
    member_offset_ = obj.member_offset_;
    imageOffset_ = obj.imageOffset_;
    imageLen_ = obj.imageLen_;
    dataOffset_ = obj.dataOffset_;
    dataLen_ = obj.dataLen_;

   isLineInfoValid_ = obj.isLineInfoValid_;
   isTypeInfoValid_ = obj.isTypeInfoValid_;

   is_a_out = obj.is_a_out;
   main_call_addr_ = obj.main_call_addr_; // address of call to main()

   nativeCompiler = obj.nativeCompiler;
   defaultNamespacePrefix = obj.defaultNamespacePrefix;

   //sections
   no_of_sections = obj.no_of_sections;
   unsigned i;

   for (i=0;i<obj.regions_.size();i++)
      regions_.push_back(new Region(*(obj.regions_[i])));

   for (i=0;i<regions_.size();i++)
      regionsByEntryAddr[regions_[i]->getRegionAddr()] = regions_[i];

   // TODO FIXME: copying symbols/Functions/Variables

   for (i=0;i<obj._mods.size();i++)
   {
      Module *m = new Module(*(obj._mods[i]));
      _mods.push_back(m);
      modsByFileName[m->fileName()] = m;
      modsByFullName[m->fullName()] = m;
      fprintf(stderr, "%s[%d]:  copy ctor creating new module %s\n", 
            FILE__, __LINE__, m->fileName().c_str());
   }

   for (i=0; i<relocation_table_.size();i++) 
   {
      relocation_table_.push_back(relocationEntry(obj.relocation_table_[i]));
      //undefDynSyms[obj.relocation_table_[i].name()] = relocation_table_[i].getDynSym();
      undefDynSyms[obj.relocation_table_[i].name()].push_back(relocation_table_[i].getDynSym());

   }

   for (i=0;i<excpBlocks.size();i++)
   {
      excpBlocks.push_back(new ExceptionBlock(*(obj.excpBlocks[i])));
   }

   deps_ = obj.deps_;
   setupTypes();
}

// Address must be in code or data range since some code may end up
// in the data segment
bool Symtab::isValidOffset(const Offset where) const
{
   return isCode(where) || isData(where);
}

/* Performs a binary search on the codeRegions_ vector, which must
 * be kept in sorted order
 */
bool Symtab::isCode(const Offset where)  const
{
#if defined(os_vxworks)
    // All memory is valid in the kernel.  Kinda.
    //return true;
#endif

   if (!codeRegions_.size()) 
   {
      fprintf(stderr, "%s[%d] No code regions in %s \n",
            __FILE__, __LINE__, mf->filename().c_str());
      return false;
   }

   // search for "where" in codeRegions_ (code regions must not overlap)
   int first = 0; 
   int last = codeRegions_.size() - 1;

   while (last >= first) 
   {
      Region *curreg = codeRegions_[(first + last) / 2];
      if (where >= curreg->getRegionAddr()
            && where < (curreg->getRegionAddr()
               + curreg->getDiskSize())) 
      {
         if (curreg->getRegionType() == Region::RT_BSS)
            return false;
         return true;
      }
      else if (where < curreg->getRegionAddr()) 
      {
         last = ((first + last) / 2) - 1;
      }
      else if (where >= (curreg->getRegionAddr() + curreg->getMemSize()))
      {
         first = ((first + last) / 2) + 1;
      }
      else 
      {  // "where" is in the range: 
         // [memOffset + diskSize , memOffset + memSize)
         // meaning that it's in an uninitialized data region 
         return false;
      }
   }

   return false;
}

/* Performs a binary search on the dataRegions_ vector, which must
 * be kept in sorted order */
bool Symtab::isData(const Offset where)  const
{
   if (!dataRegions_.size()) 
   {
      fprintf(stderr, "%s[%d] No data regions in %s \n",
            __FILE__,__LINE__,mf->filename().c_str());
      return false;
   }

   int first = 0; 
   int last = dataRegions_.size() - 1;

   while (last >= first) 
   {
      Region *curreg = dataRegions_[(first + last) / 2];

      if (     (where >= curreg->getRegionAddr())
            && (where < (curreg->getRegionAddr() + curreg->getRegionSize())))
      {
         return true;
      }
      else if (where < curreg->getRegionAddr()) 
      {
         last = ((first + last) / 2) - 1;
      }
      else 
      {
         first = ((first + last) / 2) + 1;
      }
   }

   return false;
}

SYMTAB_EXPORT bool Symtab::getFuncBindingTable(std::vector<relocationEntry> &fbt) const
{
   fbt = relocation_table_;
   return true;
}

SYMTAB_EXPORT bool Symtab::updateFuncBindingTable(Offset stub_addr, Offset plt_addr)
{
    int stub_idx = -1, plt_idx = -1;

    for (unsigned i = 0; i < relocation_table_.size(); ++i) {
        if (stub_addr == relocation_table_[i].target_addr())
            stub_idx = i;
        if (plt_addr  == relocation_table_[i].target_addr())
            plt_idx = i;
        if (stub_idx >= 0 && plt_idx >= 0)
            break;
    }
    if (stub_idx >= 0 && plt_idx >= 0) {
        relocation_table_[stub_idx] = relocation_table_[plt_idx];
        relocation_table_[stub_idx].setTargetAddr(stub_addr);
        return true;
    }
    return false;
}

SYMTAB_EXPORT std::vector<std::string> &Symtab::getDependencies(){
    return deps_;
}

SYMTAB_EXPORT Archive *Symtab::getParentArchive() const {
    return parentArchive_;
}

Symtab::~Symtab()
{
   // Doesn't do anything yet, moved here so we don't mess with symtab.h
   // Only called if we fail to create a process.
   // Or delete the a.out...

#if 1 

   for (unsigned i = 0; i < regions_.size(); i++) 
   {
      delete regions_[i];
   }

   regions_.clear();
   codeRegions_.clear();
   dataRegions_.clear();
   regionsByEntryAddr.clear();

   std::vector<Region *> *user_regions = NULL;
   getAnnotation(user_regions, UserRegionsAnno);

   if (user_regions)
   {
      for (unsigned i = 0; i < user_regions->size(); ++i) 
         delete (*user_regions)[i];
      user_regions->clear();
   }

   // Symbols are copied from linkedFile, and NOT deleted
   everyDefinedSymbol.clear();
   undefDynSyms.clear();

   // TODO make annotation
   userAddedSymbols.clear();
   symsByOffset.clear();
   symsByMangledName.clear();
   symsByPrettyName.clear();
   symsByTypedName.clear();

   for (unsigned i = 0; i < everyFunction.size(); i++) 
   {
      delete everyFunction[i];
   }

   everyFunction.clear();
   funcsByOffset.clear();

   for (unsigned i = 0; i < everyVariable.size(); i++) 
   {
      delete everyVariable[i];
   }

   everyVariable.clear();
   varsByOffset.clear();

   for (unsigned i = 0; i < _mods.size(); i++) 
   {
      delete _mods[i];
   }
   _mods.clear();
   modsByFileName.clear();
   modsByFullName.clear();

   for (unsigned i=0;i<excpBlocks.size();i++)
      delete excpBlocks[i];

   create_printf("%s[%d]: Symtab::~Symtab removing %p from allSymtabs\n", 
         FILE__, __LINE__, this);

   deps_.clear();

   for (unsigned i = 0; i < allSymtabs.size(); i++) 
   {
      if (allSymtabs[i] == this)
         allSymtabs.erase(allSymtabs.begin()+i);
   }

   // Make sure to free the underlying Object as it doesn't have a factory
   // open method
   if( obj_private ) delete obj_private;

   //fprintf(stderr, "%s[%d]:  symtab DTOR, mf = %p: %s\n", FILE__, __LINE__, mf, mf->filename().c_str());
   if (mf) MappedFile::closeMappedFile(mf);
   //if (mfForDebugInfo) MappedFile::closeMappedFile(mfForDebugInfo);
#endif
}	

bool Symtab::exportXML(string file)
{
#if defined (cap_serialization)
   try 
   {
	   SerContext<Symtab> *scs = new SerContext<Symtab>(this, file);
	   serialize(file, scs, ser_xml);
#if 0
	   SerContext<Symtab> *scs = new SerContext<Symtab>(this);
	   SerializerXML *ser = new SerializerXML(scs, "XMLTranslator", file, sd_serialize, true);
	   serialize(ser, "Symtab");
#endif
#if 0
      SerializerXML sb("XMLTranslator", file, sd_serialize, true);
      serialize(&sb, "Symtab");
#endif
   } 
   catch (const SerializerError &err) 
   {
      fprintf(stderr, "%s[%d]: error serializing xml: %s\n", FILE__, __LINE__, err.what());
      return false;
   }

   return false;
#else
   fprintf(stderr, "%s[%d]:  WARNING:  cannot produce %s, serialization not available\n", FILE__, __LINE__, file.c_str());
   return false;
#endif
}

#if defined (cap_serialization)
bool Symtab::exportBin(string file)
{
   try
   {
	   SerContext<Symtab> *scs = new SerContext<Symtab>(this, file);
	   serialize(file, scs, ser_bin);
	   //fprintf(stderr, "%s[%d]:  did serialize\n", FILE__, __LINE__);
	   return true;
   }

   catch (const SerializerError &err)
   {
      if (err.code() == SerializerError::ser_err_disabled) 
      {
         fprintf(stderr, "%s[%d]:  WARN:  serialization is disabled for file %s\n",
               FILE__, __LINE__, file.c_str());
         return false;
      }

      fprintf(stderr, "%s[%d]: %s\n\tfrom: %s[%d]\n", FILE__, __LINE__,
            err.what(), err.file().c_str(), err.line());
   }

   fprintf(stderr, "%s[%d]:  error doing binary serialization\n", __FILE__, __LINE__);
   return false;
}
#else
bool Symtab::exportBin(string) 
{
   fprintf(stderr, "%s[%d]:  WARNING:  serialization not available\n", FILE__, __LINE__);
   return false;
}
#endif

Symtab *Symtab::importBin(std::string file)
{
#if defined (cap_serialization)
   MappedFile *mf= MappedFile::createMappedFile(file);
   if (!mf) 
   {
      fprintf(stderr, "%s[%d]:  failed to map file %s\n", FILE__, __LINE__, file.c_str());
      return NULL;
   }

   Symtab *st = new Symtab(mf);

   try
   {
	   SerContext<Symtab> *scs = new SerContext<Symtab>(st, file);
	   if (!st->deserialize(file, scs))
	   {
		   delete st;
		   return NULL;
	   }

	   return st;
   }

   catch (const SerializerError &err)
   {
      if (err.code() == SerializerError::ser_err_disabled) 
      {
         serialize_printf("%s[%d]:  WARN:  serialization is disabled for file %s\n",
               FILE__, __LINE__, file.c_str());
         fprintf(stderr, "%s[%d]:  WARN:  serialization is disabled for file %s\n",
               FILE__, __LINE__, file.c_str());
         return NULL;
      }

      serialize_printf("%s[%d]: %s\n\tfrom: %s[%d]\n", FILE__, __LINE__,
            err.what(), err.file().c_str(), err.line());
      fprintf(stderr, "%s[%d]: %s\n\tfrom: %s[%d]\n", FILE__, __LINE__,
            err.what(), err.file().c_str(), err.line());
   }


   serialize_printf("%s[%d]:  error doing binary deserialization\n", __FILE__, __LINE__);
   delete st;
   return NULL;
#else
   serialize_printf("%s[%d]:  WARNING:  cannot produce %s, serialization not available\n", FILE__, __LINE__, file.c_str());
   return NULL;
#endif
}


bool Symtab::openFile(Symtab *&obj, char *mem_image, size_t size)
{
   bool err = false;
#if defined(TIMED_PARSE)
   struct timeval starttime;
   gettimeofday(&starttime, NULL);
#endif

   obj = new Symtab(mem_image, size, err);

#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__ <<": openFile "<< filename<< " took "<<dursecs <<" msecs" << endl;
#endif
    if(!err)
    {
       allSymtabs.push_back(obj);
       obj->setupTypes();	
    }
    else
    {
        delete obj;
       obj = NULL;
    }
    // returns true on success (not an error)
    return !err;
}

bool Symtab::closeSymtab(Symtab *st)
{
	bool found = false;
	if (!st) return false;

    --(st->_ref_cnt);

	std::vector<Symtab *>::reverse_iterator iter;
	for (iter = allSymtabs.rbegin(); iter != allSymtabs.rend() ; iter++)
	{
		if (*iter == st)
		{
            if(0 == st->_ref_cnt)
			    allSymtabs.erase(iter.base() -1);
			found = true;
		}
	}
    if(0 == st->_ref_cnt)
	    delete(st);
	return found;
}

Symtab *Symtab::findOpenSymtab(std::string filename)
{
   unsigned numSymtabs = allSymtabs.size();
	for (unsigned u=0; u<numSymtabs; u++) 
	{
		assert(allSymtabs[u]);
		if (filename == allSymtabs[u]->file() && 
          allSymtabs[u]->mf->canBeShared()) 
		{
            allSymtabs[u]->_ref_cnt++;
			// return it
			return allSymtabs[u];
		}
	}   
	return NULL;
}

bool Symtab::openFile(Symtab *&obj, std::string filename)
{
   bool err = false;
#if defined(TIMED_PARSE)
   struct timeval starttime;
   gettimeofday(&starttime, NULL);
#endif

   // AIX: it's possible that we're reparsing a file with better information
   // about it. If so, yank the old one out of the allSymtabs std::vector -- replace
   // it, basically.
   if ( filename.find("/proc") == std::string::npos)
   {
	   obj = findOpenSymtab(filename);
	   if (obj)
	   {
		   //fprintf(stderr, "%s[%d]:  have existing symtab obj for %s\n", FILE__, __LINE__, filename.c_str());
		   return true;
   }
   }


#if defined (cap_serialization)
#if 0
   obj = importBin(filename);

   if (NULL == obj) 
   {
	   if (deserializeEnforced<Symtab>(filename))
	  {
			  serialize_printf("%s[%d]: aborting new symtab, expected deserialize failed\n",
					  FILE__, __LINE__);
			  fprintf(stderr, "%s[%d]: aborting new symtab, expected deserialize failed\n",
					  FILE__, __LINE__);
			  return false;
	  }
	   //fprintf(stderr, "%s[%d]:  deserialize failed, but not enforced for %s\n", FILE__, __LINE__, filename.c_str());
   }
   else 
   {
	  //fprintf(stderr, "%s[%d]:  deserialize success\n", FILE__, __LINE__);
      return true;
   }
#endif
#endif

   obj = new Symtab(filename, err);

#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__ <<": openFile "<< filename<< " took "<<dursecs <<" msecs" << endl;
#endif

   if (!err)
   {
      if (filename.find("/proc") == std::string::npos)
         allSymtabs.push_back(obj);

      obj->setupTypes();	

#if defined (cap_serialization)
#if 0
      serialize_printf("%s[%d]:  doing bin-serialize for %s\n", 
            FILE__, __LINE__, filename.c_str());

      if (!obj->exportBin(filename))
      {
         serialize_printf("%s[%d]:  failed to export symtab\n", FILE__, __LINE__);
      }
      else
         serialize_printf("%s[%d]:  did bin-serialize for %s\n", 
                          FILE__, __LINE__, filename.c_str());
#endif
#endif

    }
    else
    {
       create_printf("%s[%d]: WARNING: failed to open symtab for %s\n", 
             FILE__, __LINE__, filename.c_str());
       delete obj;
       obj = NULL;
    }

   // returns true on success (not an error)
   return !err;
}

bool Symtab::addRegion(Offset vaddr, void *data, unsigned int dataSize, std::string name, 
        Region::RegionType rType_, bool loadable, unsigned long memAlign, bool tls)
{
   Region *sec;
   unsigned i;
   if (loadable)
   {
      sec = new Region(newSectionInsertPoint, name, vaddr, dataSize, vaddr, 
            dataSize, (char *)data, Region::RP_R, rType_, true, tls, memAlign);

      regions_.insert(regions_.begin()+newSectionInsertPoint, sec);

      for (i = newSectionInsertPoint+1; i < regions_.size(); i++)
      {
         regions_[i]->setRegionNumber(regions_[i]->getRegionNumber() + 1);
      }

      if (    (sec->getRegionType() == Region::RT_TEXT) 
            || (sec->getRegionType() == Region::RT_TEXTDATA))
      {
         codeRegions_.push_back(sec);
         std::sort(codeRegions_.begin(), codeRegions_.end(), sort_reg_by_addr);
      }

      if (    (sec->getRegionType() == Region::RT_DATA) 
            || (sec->getRegionType() == Region::RT_TEXTDATA))
      {
         dataRegions_.push_back(sec);
         std::sort(dataRegions_.begin(), dataRegions_.end(), sort_reg_by_addr);
      }
   }
   else
   {
      sec = new Region(regions_.size()+1, name, vaddr, dataSize, 0, 0, 
            (char *)data, Region::RP_R, rType_, loadable, tls, memAlign);
      regions_.push_back(sec);
   }

   addUserRegion(sec);
   std::sort(regions_.begin(), regions_.end(), sort_reg_by_addr);
   return true;
}

bool Symtab::addUserRegion(Region *reg)
{
   std::vector<Region *> *user_regions = NULL;

   if (!getAnnotation(user_regions, UserRegionsAnno))
   {
      user_regions = new std::vector<Region *>();
      if (!addAnnotation(user_regions, UserRegionsAnno))
      {
         fprintf(stderr, "%s[%d]:  failed to addAnnotation here\n", FILE__, __LINE__);
         return false;
      }
   }

   if (!user_regions)
   {
      fprintf(stderr, "%s[%d]:  failed to addAnnotation here\n", FILE__, __LINE__);
      return false;
   }

   user_regions->push_back(reg);

   return true;
}

bool Symtab::addUserType(Type *t)
{
   std::vector<Type *> *user_types = NULL;

   //  need to change this to something based on AnnotationContainer
   //  for it to work with serialization
   if (!getAnnotation(user_types, UserTypesAnno))
   {
      user_types = new std::vector<Type *>();
      if (!addAnnotation(user_types, UserTypesAnno))
      {
         fprintf(stderr, "%s[%d]:  failed to addAnnotation here\n", FILE__, __LINE__);
         return false;
      }
   }
   if (!user_types)
   {
      fprintf(stderr, "%s[%d]:  failed to addAnnotation here\n", FILE__, __LINE__);
      return false;
   }

   user_types->push_back(t);

   return true;
}

bool Symtab::addRegion(Region *sec)
{
   regions_.push_back(sec);
   std::sort(regions_.begin(), regions_.end(), sort_reg_by_addr);
   addUserRegion(sec);
   return true;
}

void Symtab::parseLineInformation()
{
   dyn_hash_map<std::string, LineInformation> *lineInfo = new dyn_hash_map <std::string, LineInformation>;


   Object *linkedFile = getObject();
	if (!linkedFile)
	{
#if !defined(os_vxworks)
		fprintf(stderr, "%s[%d]:  getObject failed here\n", FILE__, __LINE__);
#endif
		return;
	}
   linkedFile->parseFileLineInfo(this, *lineInfo);

   isLineInfoValid_ = true;	
   dyn_hash_map <std::string, LineInformation>::iterator iter;

   for (iter = lineInfo->begin(); iter!=lineInfo->end(); iter++)
   {
      Module *mod = NULL;
      bool result = findModuleByName(mod, iter->first);
      if (!result) {
         mod = getDefaultModule();
      }

         LineInformation *lineInformation = mod->getLineInformation();
         if (!lineInformation) 
         {
            mod->setLineInfo(&(iter->second));
         } 
         else 
         {
            lineInformation->addLineInfo(&(iter->second));
            mod->setLineInfo(lineInformation);
         }
      }
}

SYMTAB_EXPORT bool Symtab::getAddressRanges(std::vector<pair<Offset, Offset> >&ranges,
      std::string lineSource, unsigned int lineNo)
{
   unsigned int originalSize = ranges.size();

   /* Iteratate over the modules, looking for ranges in each. */

   for ( unsigned int i = 0; i < _mods.size(); i++ ) 
   {
      LineInformation *lineInformation = _mods[i]->getLineInformation();

      if (lineInformation)
         lineInformation->getAddressRanges( lineSource.c_str(), lineNo, ranges );

   } /* end iteration over modules */

   if ( ranges.size() != originalSize )
      return true;

   fprintf(stderr, "%s[%d]:  failing to getAdressRanges for %s[%d]\n", FILE__, __LINE__, lineSource.c_str(), lineNo);
   return false;
}

SYMTAB_EXPORT bool Symtab::getSourceLines(std::vector<Statement *> &lines, Offset addressInRange)
{
   unsigned int originalSize = lines.size();

   /* Iteratate over the modules, looking for ranges in each. */
   for ( unsigned int i = 0; i < _mods.size(); i++ ) 
   {
      LineInformation *lineInformation = _mods[i]->getLineInformation();

      if (lineInformation)
         lineInformation->getSourceLines( addressInRange, lines );

   } /* end iteration over modules */

   if ( lines.size() != originalSize )
      return true;

   return false;

}

SYMTAB_EXPORT bool Symtab::getSourceLines(std::vector<LineNoTuple> &lines, Offset addressInRange)
{
   unsigned int originalSize = lines.size();
   
   /* Iteratate over the modules, looking for ranges in each. */
   for ( unsigned int i = 0; i < _mods.size(); i++ ) 
   {
      LineInformation *lineInformation = _mods[i]->getLineInformation();
      
      if (lineInformation)
         lineInformation->getSourceLines( addressInRange, lines );
      
   } /* end iteration over modules */
   
   if ( lines.size() != originalSize )
      return true;
   
   return false;
}

SYMTAB_EXPORT bool Symtab::addLine(std::string lineSource, unsigned int lineNo,
      unsigned int lineOffset, Offset lowInclAddr,
      Offset highExclAddr)
{
   Module *mod;

   if (!findModuleByName(mod, lineSource))
   {
      std::string fileNm = extract_pathname_tail(lineSource);

      if (!findModuleByName(mod, fileNm))
      {
         if (!findModuleByName(mod, mf->pathname()))
            return false;
      }    
   }

   LineInformation *lineInfo = mod->getLineInformation();

   if (!lineInfo)
      return false;

   return (lineInfo->addLine(lineSource.c_str(), lineNo, lineOffset, 
            lowInclAddr, highExclAddr));
}

SYMTAB_EXPORT bool Symtab::addAddressRange( Offset lowInclusiveAddr, Offset highExclusiveAddr,
      std::string lineSource, unsigned int lineNo,
      unsigned int lineOffset)
{
   Module *mod;

   if (!findModuleByName(mod, lineSource))
   {
      std::string fileNm = extract_pathname_tail(lineSource);

      if (!findModuleByName(mod, fileNm))
         return false;
   }

   LineInformation *lineInfo = mod->getLineInformation();

   if (!lineInfo)
      return false;

   return (lineInfo->addAddressRange(lowInclusiveAddr, highExclusiveAddr, 
            lineSource.c_str(), lineNo, lineOffset));
}

void Symtab::setTruncateLinePaths(bool value)
{
   getObject()->setTruncateLinePaths(value);
}

bool Symtab::getTruncateLinePaths()
{
   return getObject()->getTruncateLinePaths();
}

void Symtab::parseTypes()
{
   Object *linkedFile = getObject();
	if (!linkedFile)
	{
#if !defined(os_vxworks)
		fprintf(stderr, "%s[%d]:  getObject failed here\n", FILE__, __LINE__);
#endif
		return;
	}
   linkedFile->parseTypeInfo(this);
   isTypeInfoValid_ = true;

   for (unsigned int i = 0; i < _mods.size(); ++i)
   {
	   typeCollection *tc = typeCollection::getModTypeCollection(_mods[i]);

	   if (!_mods[i]->addAnnotation(tc, ModuleTypeInfoAnno))
	   {
		   fprintf(stderr, "%s[%d]:  failed to addAnnotation here\n", FILE__, __LINE__);
	   }
   }

   //  optionally we might want to clear the static data struct in typeCollection
   //  here....  the parsing is over, and we have added all typeCollections as
   //  annotations proper.

   typeCollection::fileToTypesMap.clear();

}

bool Symtab::addType(Type *type)
{
  bool result = addUserType(type);
  if (!result)
    return false;

  return true;
}

SYMTAB_EXPORT vector<Type *> *Symtab::getAllstdTypes()
{
   setupStdTypes();
   return stdTypes->getAllTypes(); 	
}

SYMTAB_EXPORT vector<Type *> *Symtab::getAllbuiltInTypes()
{
   setupStdTypes();
   return builtInTypes->getAllBuiltInTypes();
}

SYMTAB_EXPORT bool Symtab::findType(Type *&type, std::string name)
{
   parseTypesNow();

   if (!_mods.size())
      return false;

   for (unsigned int i = 0; i < _mods.size(); ++i)
   {
	   typeCollection *tc = _mods[i]->getModuleTypes();
	   if (!tc) continue;
	   type = tc->findType(name);
	   if (type) return true;
   }

   if (type == NULL)
      return false;

   return true;	
}

SYMTAB_EXPORT Type *Symtab::findType(unsigned type_id)
{
	Type *t = NULL;
   parseTypesNow();

   if (!_mods.size())
   {
	   //fprintf(stderr, "%s[%d]:  findType failing due to lack of modules\n", FILE__, __LINE__);
      return NULL;
   }

   for (unsigned int i = 0; i < _mods.size(); ++i)
   {
	   typeCollection *tc = _mods[i]->getModuleTypes();
	   if (!tc) continue;
	   t = tc->findType(type_id);
	   if (t)  break;
   }

   if (t == NULL)
   {
	   if (builtInTypes)
	   {
		   t = builtInTypes->findBuiltInType(type_id);
		   if (t) return t;
	   }
	   else
	   {
		   //fprintf(stderr, "%s[%d]:  no built in types!\n", FILE__, __LINE__);
	   }

	   if (stdTypes)
	   {
		   t = stdTypes->findType(type_id);
		   if (t) return t;
	   }
	   else
	   {
		   //fprintf(stderr, "%s[%d]:  no std types!\n", FILE__, __LINE__);
	   }

	   return NULL;
   }

   return t;	
}

SYMTAB_EXPORT bool Symtab::findVariableType(Type *&type, std::string name)
{
   parseTypesNow();

   if (!_mods.size())
      return false;


   for (unsigned int i = 0; i < _mods.size(); ++i)
   {
	   typeCollection *tc = _mods[i]->getModuleTypes();
	   if (!tc) continue;
	   type = tc->findVariableType(name);
	   if (type) break;
   }

   if (type == NULL)
      return false;

   return true;	
}

SYMTAB_EXPORT bool Symtab::findLocalVariable(std::vector<localVar *>&vars, std::string name)
{
   parseTypesNow();
   unsigned origSize = vars.size();

   for (unsigned i = 0; i < everyFunction.size(); i++)
   {
      everyFunction[i]->findLocalVariable(vars, name);
   }

   if (vars.size()>origSize)
      return true;

   return false;	
}

SYMTAB_EXPORT bool Symtab::hasRel() const
{
   return hasRel_;
}

SYMTAB_EXPORT bool Symtab::hasRela() const
{
   return hasRela_;
}

SYMTAB_EXPORT bool Symtab::hasReldyn() const
{
   return hasReldyn_;
}

SYMTAB_EXPORT bool Symtab::hasReladyn() const
{
   return hasReladyn_;
}

SYMTAB_EXPORT bool Symtab::hasRelplt() const
{
   return hasRelplt_;
}

SYMTAB_EXPORT bool Symtab::hasRelaplt() const
{
   return hasRelaplt_;
}

SYMTAB_EXPORT bool Symtab::isStaticBinary() const
{
   return isStaticBinary_;
}

bool Symtab::setDefaultNamespacePrefix(string &str)
{
   defaultNamespacePrefix = str;
   return true;
}

SYMTAB_EXPORT bool Symtab::emitSymbols(Object *linkedFile,std::string filename, unsigned flag)
{
    // Start with all the defined symbols
    std::vector<Symbol *> allSyms;
    for (unsigned i = 0; i < everyDefinedSymbol.size(); i++) {
        allSyms.push_back(everyDefinedSymbol[i]);
    }

    // Add the undefined dynamic symbols
    map<string, std::vector<Symbol *> >::iterator iter;
    std::vector<Symbol *>::iterator siter;

    for (iter = undefDynSyms.begin(); iter != undefDynSyms.end(); iter++)
        for (siter=iter->second.begin(); siter != iter->second.end(); siter++)
            allSyms.push_back(*siter);

    // Write the new file
    return linkedFile->emitDriver(this, filename, allSyms, flag);
}

SYMTAB_EXPORT bool Symtab::emit(std::string filename, unsigned flag)
{
	Object *obj = getObject();
	if (!obj)
	{
#if !defined(os_vxworks)
		fprintf(stderr, "%s[%d]:  getObject failed here\n", FILE__, __LINE__);
#endif
		return false;
	}
   obj->mf->setSharing(false);
   return emitSymbols(obj, filename, flag);
}

SYMTAB_EXPORT void Symtab::addDynLibSubstitution(std::string oldName, std::string newName)
{
   dynLibSubs[oldName] = newName;
}

SYMTAB_EXPORT std::string Symtab::getDynLibSubstitution(std::string name)
{
#ifdef BINEDIT_DEBUG
   map<std::string, std::string>::iterator iter = dynLibSubs.begin();

   printf ("substitutions for %s:\n", mf->filename().c_str());

   while (iter != dynLibSubs.end()) 
   {
      printf("  \"%s\" => \"%s\"\n", iter->first.c_str(), iter->second.c_str());
      iter++;
   }
#endif

   map<std::string, std::string>::iterator loc = dynLibSubs.find(name);

   if (loc == dynLibSubs.end())
      return name;
   else
      return loc->second;
}

SYMTAB_EXPORT bool Symtab::getSegments(vector<Segment> &segs) const
{
   segs = segments_;

   if (!segments_.size()) 
      return false;

   return true;
}

SYMTAB_EXPORT bool Symtab::getMappedRegions(std::vector<Region *> &mappedRegs) const
{
   unsigned origSize = mappedRegs.size();

   for (unsigned i = 0; i < regions_.size(); i++)
   {
      if (regions_[i]->isLoadable())
         mappedRegs.push_back(regions_[i]);
   }

   if (mappedRegs.size() > origSize)
      return true;

   return false;
}

SYMTAB_EXPORT bool Symtab::fixup_RegionAddr(const char* name, Offset memOffset, long memSize)
{
    Region *sec;

    if (!findRegion(sec, name)) {
        return false;
    }

    vector<relocationEntry> relocs;
    Object *obj = getObject();

    // Fix relocation table with correct memory address
    if (obj) {
        obj->get_func_binding_table(relocs);
        /* DEBUG
        fprintf(stderr, "There are %d relocs in this symtab.\n",
                relocs.size()); // */

        for (unsigned i=0; i < relocs.size(); i++) {
            Offset value = relocs[i].rel_addr();
            relocs[i].setRelAddr(memOffset + value);
            /* DEBUG
            fprintf(stderr, "Fixing reloc from 0x%x to 0x%x\n",
                    value, memOffset + value); // */
        }
    }
    relocation_table_ = relocs;

    vector<relocationEntry> &relref = sec->getRelocations();
    for (unsigned i=0; i < relref.size(); i++) {
        Offset value = relref[i].rel_addr();
        relref[i].setRelAddr(memOffset + value);
        /* DEBUG
        fprintf(stderr, "Fixing region reloc from 0x%x to 0x%x\n",
                value, memOffset + value); // */
    }

#if defined(_MSC_VER)
    regionsByEntryAddr.erase(sec->getRegionAddr());
#endif

    /* DEBUG
    fprintf(stderr, "Fixing region %s from 0x%x [0x%x] to 0x%x [0x%x]\n",
            name, sec->getRegionAddr(), sec->getRegionSize(), memOffset,
            memSize); // */
    sec->setMemOffset(memOffset);
    sec->setMemSize(memSize);

#if defined(_MSC_VER)
    regionsByEntryAddr[sec->getRegionAddr()] = sec;
#endif

    std::sort(codeRegions_.begin(), codeRegions_.end(), sort_reg_by_addr);
    std::sort(dataRegions_.begin(), dataRegions_.end(), sort_reg_by_addr);
    std::sort(regions_.begin(), regions_.end(), sort_reg_by_addr);
    return true;
}

SYMTAB_EXPORT bool Symtab::fixup_SymbolAddr(const char* name, Offset newOffset)
{
    // Find the symbol.
    if (symsByMangledName.count(name) == 0) return false;
    // /* DEBUG
    if (symsByMangledName[name].size() != 1)
        fprintf(stderr, "*** Found %d symbols with name %s.  Expecting 1.\n",
                symsByMangledName[name].size(), name); // */
    Symbol *sym = symsByMangledName[name][0];

    // Update symbol.
    Offset oldOffset = sym->getOffset();
    sym->setOffset(newOffset);

    /* DEBUG
    fprintf(stderr, "Fixing symbol %s from 0x%x to 0x%x\n",
            name, oldOffset, newOffset); // */

    // Update hashes.
    if (symsByOffset.count(oldOffset)) {
        std::vector<Symbol *>::iterator iter = symsByOffset[oldOffset].begin();
        while (iter != symsByOffset[oldOffset].end()) {
            if (*iter == sym) {
                symsByOffset[oldOffset].erase(iter);
                iter = symsByOffset[oldOffset].begin();

            } else iter++;
        }
    }
    if (!findSymbolByOffset(newOffset))
        symsByOffset[newOffset].push_back(sym);

    // Update aggregates.
    if (!doNotAggregate(sym)) {
      addSymbolToAggregates(sym);
    }

    return true;
}

SYMTAB_EXPORT bool Symtab::updateRegion(const char* name, void *buffer, unsigned size)
{
   Region *sec;

   if (!findRegion(sec, name))
      return false;

   sec->setPtrToRawData(buffer, size);

   return true;
}

SYMTAB_EXPORT bool Symtab::updateCode(void *buffer, unsigned size)
{
  return updateRegion(".text", buffer, size);
}

SYMTAB_EXPORT bool Symtab::updateData(void *buffer, unsigned size)
{
  return updateRegion(".data", buffer, size);
}

SYMTAB_EXPORT Offset Symtab::getFreeOffset(unsigned size) 
{
   // Look through sections until we find a gap with
   // sufficient space.
   Offset highWaterMark = 0;
   Offset secoffset = 0;
   Offset prevSecoffset = 0;
   Object *linkedFile = getObject();
	if (!linkedFile)
	{
#if !defined(os_vxworks)
		fprintf(stderr, "%s[%d]:  getObject failed here\n", FILE__, __LINE__);
#endif
		return 0;
	}

   for (unsigned i = 0; i < regions_.size(); i++) 
   {
      //Offset end = regions_[i]->getRegionAddr() + regions_[i]->getDiskSize();
      Offset end = regions_[i]->getRegionAddr() + regions_[i]->getRegionSize();
      if (regions_[i]->getRegionAddr() == 0) 
         continue;

      prevSecoffset = secoffset;

      unsigned region_offset = (unsigned)((char *)(regions_[i]->getPtrToRawData())
                                          - linkedFile->mem_image());

      if (region_offset < (unsigned)prevSecoffset)
      {
         //secoffset += regions_[i]->getDiskSize();
         secoffset += regions_[i]->getRegionSize();
      }
      else 
      {
         secoffset = (char *)(regions_[i]->getPtrToRawData()) - linkedFile->mem_image();
         //secoffset += regions_[i]->getDiskSize();
         secoffset += regions_[i]->getRegionSize();
      }

      /*fprintf(stderr, "%d: secAddr 0x%lx, size %d, end 0x%lx, looking for %d\n",
        i, regions_[i]->getSecAddr(), regions_[i]->getSecSize(),
        end,size);*/

      if (end > highWaterMark) 
      {
         //fprintf(stderr, "Increasing highWaterMark...\n");
         newSectionInsertPoint = i+1;
         highWaterMark = end;
      }

      if (     (i < (regions_.size()-2)) 
               && ((end + size) < regions_[i+1]->getRegionAddr())) 
      {
         /*      fprintf(stderr, "Found a hole between sections %d and %d\n",
                 i, i+1);
                 fprintf(stderr, "End at 0x%lx, next one at 0x%lx\n",
                 end, regions_[i+1]->getSecAddr());
         */   
         newSectionInsertPoint = i+1;
         highWaterMark = end;
         break;
      }
   }

   //   return highWaterMark;
#if defined (os_windows)
	Object *obj = getObject();
	if (!obj)
	{
		fprintf(stderr, "%s[%d]:  getObject failed here\n", FILE__, __LINE__);
		return 0;
	}
	unsigned pgSize = obj->getSecAlign();
	//printf("pgSize:0x%x\n", pgSize);
	Offset newaddr = highWaterMark  - (highWaterMark & (pgSize-1));
	while(newaddr < highWaterMark)
      newaddr += pgSize;
	//printf("getfreeoffset:%lu\n", newaddr);
	return newaddr;

#else
	unsigned pgSize = P_getpagesize();

#if defined(os_linux)
        // Bluegene compute nodes have a 1MB alignment restructions on PT_LOAD section
	Object *obj = getObject();
	if (!obj)
	{
		fprintf(stderr, "%s[%d]:  getObject failed here\n", FILE__, __LINE__);
		return 0;
	}
	bool isBlueGene = obj->isBlueGene();
	bool hasNoteSection = obj->hasNoteSection();
	if (isBlueGene && hasNoteSection)
		pgSize = 0x100000; 
#endif	
	Offset newaddr = highWaterMark  - (highWaterMark & (pgSize-1));
	if(newaddr < highWaterMark)
		newaddr += pgSize;

   return newaddr;
#endif	
}

SYMTAB_EXPORT ObjectType Symtab::getObjectType() const 
{
   return object_type_;
}

SYMTAB_EXPORT Dyninst::Architecture Symtab::getArchitecture()
{
   return getObject()->getArch();
}

SYMTAB_EXPORT char *Symtab::mem_image() const 
{
   return (char *)mf->base_addr();
}

SYMTAB_EXPORT std::string Symtab::file() const 
{
   assert(mf);
   return mf->pathname();
}

SYMTAB_EXPORT std::string Symtab::name() const 
{
   return mf->filename();
}

SYMTAB_EXPORT std::string Symtab::memberName() const 
{
    return member_name_;
}

SYMTAB_EXPORT unsigned Symtab::getNumberofRegions() const 
{
   return no_of_sections; 
}

SYMTAB_EXPORT unsigned Symtab::getNumberofSymbols() const 
{
   return no_of_symbols; 
}

bool Symtab::setup_module_up_ptrs(SerializerBase *, Symtab *st)
{
   std::vector<Module *> &mods = st->_mods;

   for (unsigned int i = 0; i < mods.size(); ++i) 
   {
      Module *m = mods[i];
      m->exec_ = st;
   }

   return true;
}

bool Symtab::fixup_relocation_symbols(SerializerBase *, Symtab *st)
{
   std::vector<Module *> &mods = st->_mods;

   for (unsigned int i = 0; i < mods.size(); ++i) 
   {
      Module *m = mods[i];
      m->exec_ = st;
   }

   return true;
}

void Symtab::rebuild_symbol_hashes(SerializerBase *sb)
{
	if (!is_input(sb))
		return;

	for (unsigned long i = 0; i < everyDefinedSymbol.size(); ++i)
	{
		Symbol *s = everyDefinedSymbol[i];
		assert(s);
		const std::string &pn = s->getPrettyName();
		const std::string &mn = s->getMangledName();
		const std::string tn = s->getTypedName();

		symsByPrettyName[pn].push_back(s);
		symsByMangledName[mn].push_back(s);
		symsByTypedName[tn].push_back(s);
		symsByOffset[s->getOffset()].push_back(s);
	}
}

void Symtab::rebuild_funcvar_hashes(SerializerBase *sb)
{
	if (!is_input(sb))
		return;
	for (unsigned int i = 0; i < everyFunction.size(); ++i)
	{
		Function *f = everyFunction[i];
		funcsByOffset[f->getOffset()] = f;
	}
	for (unsigned int i = 0; i < everyVariable.size(); ++i)
	{
		Variable *v = everyVariable[i];
		varsByOffset[v->getOffset()] = v;
	}
}
void Symtab::rebuild_module_hashes(SerializerBase *sb)
{
	if (!is_input(sb))
		return;
	for (unsigned int i = 0; i < _mods.size(); ++i)
	{
		Module *m = _mods[i];
		modsByFileName[m->fileName()] = m;
		modsByFullName[m->fullName()] = m;
	}
}
void Symtab::rebuild_region_indexes(SerializerBase *sb) THROW_SPEC (SerializerError)
{
	if (!is_input(sb))
		return;

	for (unsigned int i = 0; i < regions_.size(); ++i)
	{
		Region *r = regions_[i];

		if (!r) SER_ERR("FIXME:  NULL REGION");

		if ( r->isLoadable() )
		{
			if ((r->getRegionPermissions() == Region::RP_RX)
					|| (r->getRegionPermissions() == Region::RP_RWX))
				codeRegions_.push_back(r);
			else
				dataRegions_.push_back(r);
		}

		//  entry addr might require some special attn on windows, since it
		//  is not the disk offset but the actual mem addr, which is going to be
		//  different after deserialize.  Probably have to look it up again.
		regionsByEntryAddr[r->getRegionAddr()] = r;
	}

	std::sort(codeRegions_.begin(), codeRegions_.end(), sort_reg_by_addr);
	std::sort(dataRegions_.begin(), dataRegions_.end(), sort_reg_by_addr);


}

Serializable *Symtab::serialize_impl(SerializerBase *sb, 
		const char *tag) THROW_SPEC (SerializerError)
{
	serialize_printf("%s[%d]:  welcome to Symtab::serialize_impl\n", 
			FILE__, __LINE__);
	if (is_input(sb))
	{
		//  don't bother with serializing standard and builtin types.
		setupTypes();
	}

	ifxml_start_element(sb, tag);
	gtranslate(sb, imageOffset_, "imageOffset");
	gtranslate(sb, imageLen_, "imageLen");
	gtranslate(sb, dataOffset_, "dataOff");
	gtranslate(sb, dataLen_, "dataLen");
	gtranslate(sb, is_a_out, "isExec");
	gtranslate(sb, _mods, "Modules", "Module");
	rebuild_module_hashes(sb);
	if (is_input(sb))
	{
		//  problem:  if isTypeInfoValid_ is not true, we can trigger type parsing
		//  for an object class that does not exist.  Need to introduce logic to 
		//  recreate the object in this case
		isTypeInfoValid_ = true;
		isLineInfoValid_ = true; //  NOTE:  set this to true after deserializing at least one lineInformaton object
	}
	gtranslate(sb, regions_, "Regions", "Region");
	rebuild_region_indexes(sb);
	gtranslate(sb, everyDefinedSymbol, "EveryDefinedSymbol", "Symbol");
	rebuild_symbol_hashes(sb);
	gtranslate(sb, relocation_table_, "RelocationTable", "RelocationTableEntry");
	gtranslate(sb, everyFunction, "EveryFunction", "Function");
	gtranslate(sb, everyVariable, "EveryVariable", "Variable");
	rebuild_funcvar_hashes(sb);

	//gtranslate(sb, everyUniqueVariable, "EveryUniqueVariable", "UniqueVariable");
	//gtranslate(sb, modSyms, "ModuleSymbols", "ModuleSymbol");

	gtranslate(sb, excpBlocks, "ExceptionBlocks", "ExceptionBlock");
	ifxml_end_element(sb, tag);

	sb->magic_check(FILE__, __LINE__);
#if 0
	ifinput(Symtab::setup_module_up_ptrs, sb, this);
	ifinput(fixup_relocation_symbols, sb, this);
#endif

	if (is_input(sb))
	{
		dyn_hash_map<Address, Symbol *> *map_p = NULL;
		if (getAnnotation(map_p, IdToSymAnno) && (NULL != map_p))
		{
			if (!removeAnnotation(IdToSymAnno))
			{
				fprintf(stderr, "%s[%d]:  failed to remove id-to-sym map\n", 
						FILE__, __LINE__);
			}
			delete map_p;
		}
	}
	serialize_printf("%s[%d]:  leaving Symtab::serialize_impl\n", FILE__, __LINE__);
	return NULL;
}

SYMTAB_EXPORT LookupInterface::LookupInterface() 
{
}

SYMTAB_EXPORT LookupInterface::~LookupInterface()
{
}


SYMTAB_EXPORT ExceptionBlock::ExceptionBlock(Offset tStart, 
      unsigned tSize, 
      Offset cStart) 
: tryStart_(tStart), trySize_(tSize), catchStart_(cStart), hasTry_(true) 
{
}

   SYMTAB_EXPORT ExceptionBlock::ExceptionBlock(Offset cStart) 
: tryStart_(0), trySize_(0), catchStart_(cStart), hasTry_(false) 
{
}

SYMTAB_EXPORT ExceptionBlock::ExceptionBlock(const ExceptionBlock &eb) :
   Serializable(),
   tryStart_(eb.tryStart_), trySize_(eb.trySize_), 
   catchStart_(eb.catchStart_), hasTry_(eb.hasTry_) 
{
}
SYMTAB_EXPORT bool ExceptionBlock::hasTry() const
{ 
   return hasTry_; 
}

SYMTAB_EXPORT Offset ExceptionBlock::tryStart() const
{ 
   return tryStart_; 
}

SYMTAB_EXPORT Offset ExceptionBlock::tryEnd() const
{ 
   return tryStart_ + trySize_; 
}

SYMTAB_EXPORT Offset ExceptionBlock::trySize() const
{
   return trySize_; 
}

SYMTAB_EXPORT bool ExceptionBlock::contains(Offset a) const
{ 
   return (a >= tryStart_ && a < tryStart_ + trySize_); 
}

Serializable * ExceptionBlock::serialize_impl(SerializerBase *sb, const char *tag) THROW_SPEC (SerializerError)
{
	ifxml_start_element(sb, tag);
	gtranslate(sb, tryStart_, "tryStart");
	gtranslate(sb, trySize_, "trySize");
	gtranslate(sb, catchStart_, "catchStart");
	gtranslate(sb, hasTry_, "hasTry");
	ifxml_end_element(sb, tag);
	return NULL;
}


SYMTAB_EXPORT relocationEntry::relocationEntry() :
   target_addr_(0), 
   rel_addr_(0), 
   addend_(0), 
   rtype_(Region::RT_REL), 
   name_(""), 
   dynref_(NULL), 
   relType_(0)
{
}   

SYMTAB_EXPORT relocationEntry::relocationEntry(Offset ta, Offset ra, std::string n, 
      Symbol *dynref, unsigned long relType) :
   target_addr_(ta), 
   rel_addr_(ra), 
   addend_(0), 
   rtype_(Region::RT_REL), 
   name_(n), 
   dynref_(dynref), 
   relType_(relType)
{
}   

SYMTAB_EXPORT relocationEntry::relocationEntry(Offset ta, Offset ra, Offset add, 
      std::string n, Symbol *dynref, unsigned long relType) :
   target_addr_(ta), 
   rel_addr_(ra), 
   addend_(add), 
   rtype_(Region::RT_REL), 
   name_(n), 
   dynref_(dynref), 
   relType_(relType)
{
}

SYMTAB_EXPORT relocationEntry::relocationEntry(Offset ra, std::string n, 
      Symbol *dynref, unsigned long relType, Region::RegionType rtype) :
   target_addr_(0), 
   rel_addr_(ra), 
   addend_(0), 
   rtype_(rtype), 
   name_(n), 
   dynref_(dynref), 
   relType_(relType)
{
}

SYMTAB_EXPORT relocationEntry::relocationEntry(Offset ta, Offset ra, Offset add,
        std::string n, Symbol *dynref, unsigned long relType,
        Region::RegionType rtype) :
    target_addr_(ta),
    rel_addr_(ra),
    addend_(add),
    rtype_(rtype),
    name_(n),
    dynref_(dynref),
    relType_(relType)
{}

SYMTAB_EXPORT const relocationEntry& relocationEntry::operator=(const relocationEntry &ra) 
{
   target_addr_ = ra.target_addr_;
   rel_addr_ = ra.rel_addr_;
   addend_ = ra.addend_;
   rtype_ = ra.rtype_;
   name_ = ra.name_; 
   dynref_ = ra.dynref_;
   relType_ = ra.relType_;
   return *this;
}

SYMTAB_EXPORT Offset relocationEntry::target_addr() const 
{
    return target_addr_;
}

SYMTAB_EXPORT void relocationEntry::setTargetAddr(const Offset off)
{
    target_addr_ = off;
}

SYMTAB_EXPORT Offset relocationEntry::rel_addr() const 
{
    return rel_addr_;
}

SYMTAB_EXPORT void relocationEntry::setRelAddr(const Offset value)
{
    rel_addr_ = value;
}

SYMTAB_EXPORT const string &relocationEntry::name() const 
{
    return name_;
}

SYMTAB_EXPORT Symbol *relocationEntry::getDynSym() const 
{
    return dynref_;
}

SYMTAB_EXPORT bool relocationEntry::addDynSym(Symbol *dynref) 
{
    dynref_ = dynref;
    return true;
}

SYMTAB_EXPORT Region::RegionType relocationEntry::regionType() const
{
	return rtype_;
}

SYMTAB_EXPORT unsigned long relocationEntry::getRelType() const 
{
    return relType_;
}

SYMTAB_EXPORT Offset relocationEntry::addend() const
{
        return addend_;
}

SYMTAB_EXPORT void relocationEntry::setAddend(const Offset value)
{
        addend_ = value;
}

SYMTAB_EXPORT void relocationEntry::setRegionType(const Region::RegionType value)
{
        rtype_ = value;
}

SYMTAB_EXPORT void relocationEntry::setName(const std::string &newName) {
    name_ = newName;
}

bool relocationEntry::operator==(const relocationEntry &r) const
{
	if (target_addr_ != r.target_addr_) return false;
	if (rel_addr_ != r.rel_addr_) return false;
	if (addend_ != r.addend_) return false;
	if (rtype_ != r.rtype_) return false;
	if (name_ != r.name_) return false;
	if (relType_ != r.relType_) return false;
	if (dynref_ && !r.dynref_) return false;
	if (!dynref_ && r.dynref_) return false;
	if (dynref_)
	{
		if (dynref_->getName() != r.dynref_->getName()) return false;
		if (dynref_->getOffset() != r.dynref_->getOffset()) return false;
	}

	return true;
}

Serializable *relocationEntry::serialize_impl(SerializerBase *sb, const char *tag) THROW_SPEC (SerializerError)
{
	//  on deserialize need to rebuild symtab::undefDynSyms before deserializing relocations

	std::string symname = dynref_ ? dynref_->getName() : std::string("");
	Offset symoff = dynref_ ? dynref_->getOffset() : (Offset) -1;

      ifxml_start_element(sb, tag);
      gtranslate(sb, target_addr_, "targetAddress");
      gtranslate(sb, rel_addr_, "relocationAddress");
      gtranslate(sb, addend_, "Addend");
      gtranslate(sb, name_, "relocationName");
      gtranslate(sb,  rtype_, Region::regionType2Str, "regionType");
      gtranslate(sb, relType_, "relocationType");
      gtranslate(sb, symname, "SymbolName");
      gtranslate(sb, symoff, "SymbolOffset");
      ifxml_end_element(sb, tag);

	  if (sb->isInput())
	  {
		  dynref_ = NULL;
		  if (symname != std::string(""))
		  {
			  //  if we have a name for this symbol, the offset should not be -1;
			  if (symoff == (Offset) -1)
			  {
				  fprintf(stderr, "%s[%d]:  inconsistent symname and offset combo!\n", 
						  FILE__, __LINE__);
			  }

			  SerContextBase *scb = sb->getContext();
			  if (!scb)
			  {
				  fprintf(stderr, "%s[%d]:  SERIOUS:  FIXME\n", FILE__, __LINE__);
				  SER_ERR("FIXME");
			  }

			  SerContext<Symtab> *scs = dynamic_cast<SerContext<Symtab> *>(scb);

			  if (!scs)
			  {
				  fprintf(stderr, "%s[%d]:  SERIOUS:  FIXME\n", FILE__, __LINE__);
				  SER_ERR("FIXME");
			  }

			  Symtab *st = scs->getScope();

			  if (!st)
			  {
				  fprintf(stderr, "%s[%d]:  SERIOUS:  FIXME\n", FILE__, __LINE__);
				  SER_ERR("FIXME");
			  }

			  std::vector<Symbol *> *syms = st->findSymbolByOffset(symoff);
			  if (!syms || !syms->size())
			  {
				  serialize_printf("%s[%d]:  cannot find symbol by offset %p\n", 
						  FILE__, __LINE__, (void *)symoff);
				  return NULL;
			  }

			  //  Might want to try to select the "best" symbol here if there is
			  //  more than one.  Or Maybe just returning the first is sufficient.

			  dynref_ = (*syms)[0];
		  }
	  }
	  return NULL;
}

ostream & Dyninst::SymtabAPI::operator<< (ostream &os, const relocationEntry &r) 
{
    if( r.getDynSym() != NULL ) {
        os << "Name: " << setw(20) << ( "'" + r.getDynSym()->getName() + "'" );
    }else{
        os << "Name: " << setw(20) << r.name();
    }
    os << " Offset: " << std::hex << std::setfill('0') << setw(8) << r.rel_addr() 
       << std::dec << std::setfill(' ')
       << " Offset: " << std::hex << std::setfill('0') << setw(8) << r.target_addr() 
       << std::dec << std::setfill(' ')
       << " Addend: " << r.addend()
       << " Region: " << Region::regionType2Str(r.regionType())
       << " Type: " << setw(15) << relocationEntry::relType2Str(r.getRelType())
       << "(" << r.getRelType() << ")";
    if( r.getDynSym() != NULL ) {
        os << " Symbol Offset: " << std::hex << std::setfill('0') << setw(8) << r.getDynSym()->getOffset();
        os << std::setfill(' ');
        if( r.getDynSym()->isCommonStorage() ) {
            os << " COM";
        }else if( r.getDynSym()->getRegion() == NULL ) {
            os << " UND";
        }
    }
    return os;
}

const char *Symbol::symbolType2Str(SymbolType t) 
{
   switch (t) 
   {
      CASE_RETURN_STR(ST_UNKNOWN);
      CASE_RETURN_STR(ST_FUNCTION);
      CASE_RETURN_STR(ST_OBJECT);
      CASE_RETURN_STR(ST_MODULE);
      CASE_RETURN_STR(ST_SECTION);
      CASE_RETURN_STR(ST_TLS);
      CASE_RETURN_STR(ST_DELETED);
      CASE_RETURN_STR(ST_NOTYPE);
   };

   return "invalid symbol type";
}

const char *Symbol::symbolLinkage2Str(SymbolLinkage t) 
{
   switch (t) 
   {
      CASE_RETURN_STR(SL_UNKNOWN);
      CASE_RETURN_STR(SL_GLOBAL);
      CASE_RETURN_STR(SL_LOCAL);
      CASE_RETURN_STR(SL_WEAK);
   };

   return "invalid symbol linkage";
}

const char *Symbol::symbolTag2Str(SymbolTag t) 
{
   switch (t) 
   {
      CASE_RETURN_STR(TAG_UNKNOWN);
      CASE_RETURN_STR(TAG_USER);
      CASE_RETURN_STR(TAG_LIBRARY);
      CASE_RETURN_STR(TAG_INTERNAL);
   };

   return "invalid symbol tag";
}

const char *Symbol::symbolVisibility2Str(SymbolVisibility t) 
{
   switch(t) {
      CASE_RETURN_STR(SV_UNKNOWN);
      CASE_RETURN_STR(SV_DEFAULT);
      CASE_RETURN_STR(SV_INTERNAL);
      CASE_RETURN_STR(SV_HIDDEN);
      CASE_RETURN_STR(SV_PROTECTED);
   }
   return "invalid symbol visibility";
}

bool Symtab::hasStackwalkDebugInfo()
{

	Object *obj = getObject();
	if (!obj)
	{
		fprintf(stderr, "%s[%d]:  getObject failed here\n", FILE__, __LINE__);
		return false;
	}
   return obj->hasFrameDebugInfo();
}

bool Symtab::getRegValueAtFrame(Address pc, 
                                Dyninst::MachRegister reg, 
                                Dyninst::MachRegisterVal &reg_result,
                                MemRegReader *reader)
{
	Object *obj = getObject();
	if (!obj)
	{
		fprintf(stderr, "%s[%d]:  getObject failed here\n", FILE__, __LINE__);
		return false;
	}
   return obj->getRegValueAtFrame(pc, reg, reg_result, reader);
}

Object *Symtab::getObject()
{
   if (obj_private)
      return obj_private;

   //TODO: This likely triggered because we serialized in an object
   // from cache, but now the user is requesting more information from
   // the on disk object.  We should create a new 'Object' from data
   // (likely a file path) serialized in.
   
   fprintf(stderr, "%s[%d]:  FIXME:  request for object that does not exist!\n", FILE__, __LINE__);
   return NULL;
   //obj_private = new Object();
   //return obj_private;
}

void Symtab::parseTypesNow()
{
   if (isTypeInfoValid_)
      return;

   parseTypes();
}

#if defined (cap_serialization)
//  Not sure this is strictly necessary, problems only seem to exist with Module 
// annotations when the file was split off, so there's probably something else that
//  can be done to instantiate the relevant functions.

bool dummy_for_ser_instance(std::string file, SerializerBase *sb)
{
   if (file == std::string("no_such_file")) 
   {
      if (!sb) 
      {
         fprintf(stderr, "%s[%d]:  really should not happen\n", FILE__, __LINE__);
         return false;
      }
      fprintf(stderr, "%s[%d]:  WARN:  disabled serializer init here\n", FILE__, __LINE__);
   }
   return true;
}

#endif

namespace Dyninst {
	namespace SymtabAPI {


#if 1
SYMTAB_EXPORT SerializerBase *nonpublic_make_bin_symtab_serializer(Symtab *t, std::string file)
{
	SerializerBin *ser;
	SerContext<Symtab> *scs = new SerContext<Symtab>(t, file);
	ser = new SerializerBin(scs, "SerializerBin", file, sd_serialize, false);
	return ser;
}

SYMTAB_EXPORT SerializerBase *nonpublic_make_bin_symtab_deserializer(Symtab *t, std::string file)
{
	SerializerBin *ser;
	SerContext<Symtab> *scs = new SerContext<Symtab>(t, file);
	ser = new SerializerBin(scs, "DeserializerBin", file, sd_deserialize, false);
	return ser;
}

SYMTAB_EXPORT void nonpublic_free_bin_symtab_serializer(SerializerBase *sb)
{
	SerializerBin *sbin = dynamic_cast<SerializerBin *>(sb);
	if (sbin)
	{
		delete(sbin);
	}
	else
		fprintf(stderr, "%s[%d]:  FIXME\n", FILE__, __LINE__);

}
#endif

SYMTAB_EXPORT Offset Symtab::getElfDynamicOffset()
{
#if defined(os_linux) || defined(os_freebsd)
	Object *obj = getObject();
	if (!obj)
	{
		fprintf(stderr, "%s[%d]:  getObject failed here\n", FILE__, __LINE__);
		return 0;
	}
   return obj->getDynamicAddr();
#else
   return 0;
#endif
}

SYMTAB_EXPORT bool Symtab::addLibraryPrereq(std::string name)
{
#if defined(os_linux) || defined(os_freebsd)
	Object *obj = getObject();
	if (!obj)
	{
		fprintf(stderr, "%s[%d]:  getObject failed here\n", FILE__, __LINE__);
		return false;
	}
   size_t size = name.find_last_of("/");
   string filename = name.substr(size+1);
   obj->insertPrereqLibrary(filename);
   return true;
#else
   return false;
#endif
}

SYMTAB_EXPORT bool Symtab::addSysVDynamic(long name, long value)
{
#if defined(os_linux) || defined(os_freebsd)
	Object *obj = getObject();
	if (!obj)
	{
		fprintf(stderr, "%s[%d]:  getObject failed here\n", FILE__, __LINE__);
		return false;
	}
  obj->insertDynamicEntry(name, value);
   return true;
#else
   return false;
#endif
}

SYMTAB_EXPORT bool Symtab::addExternalSymbolReference(Symbol *externalSym, Region *localRegion,
        relocationEntry localRel)
{
    // Adjust this to the correct value
    localRel.setRegionType(getObject()->getRelType());

    // Create placeholder Symbol for external Symbol reference
    // Bernat, 7SEP2010 - according to Matt, these symbols should have
    // type "undefined", which means a region of NULL. Changing
    // from "localRegion" to NULL. 
    Symbol *symRef = new Symbol(externalSym->getName(),
                                externalSym->getType(),
                                Symbol::SL_GLOBAL,
                                Symbol::SV_DEFAULT,
                                (Address)0,
                                getDefaultModule(),
                                NULL, // localRegion,
                                externalSym->getSize(),
                                true,
                                false);

   if( !addSymbol(symRef, externalSym) ) return false;

   localRegion->addRelocationEntry(localRel);

   // Make sure the Symtab holding the external symbol gets linked
   // with this Symtab
   explicitSymtabRefs_.insert(externalSym->getSymtab());

   return true;
}

bool Symtab::getExplicitSymtabRefs(std::set<Symtab *> &refs) {
    refs = explicitSymtabRefs_;
    return (refs.size() != 0);
}

SYMTAB_EXPORT bool Symtab::addLinkingResource(Archive *library) {
    linkingResources_.push_back(library);

    return true;
}

SYMTAB_EXPORT bool Symtab::getLinkingResources(std::vector<Archive *> &libs) {
    libs = linkingResources_;
    return (linkingResources_.size() != 0);
}

SYMTAB_EXPORT Address Symtab::getLoadAddress()
{
#if defined(os_linux) || defined(os_freebsd) || defined(os_aix)
   return getObject()->getLoadAddress();
#else
   return 0x0;
#endif
}

SYMTAB_EXPORT bool Symtab::canBeShared()
{
   return mf->canBeShared();
}

SYMTAB_EXPORT Offset Symtab::getInitOffset()
{
#if defined(os_linux) || defined(os_freebsd) || defined(os_solaris)
   return getObject()->getInitAddr();
#else
   return 0x0;
#endif

}

SYMTAB_EXPORT Offset Symtab::getFiniOffset()
{
#if defined(os_linux) || defined(os_freebsd) || defined(os_solaris)
   return getObject()->getFiniAddr();
#else
   return 0x0;
#endif

}

} // namespace SymtabAPI
} // namespace Dyninst

