//===- SectionSymbolSet.cpp -----------------------------------------------===//
//
//                     The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <mcld/LD/SectionSymbolSet.h>
#include <mcld/LD/LDSection.h>
#include <mcld/LD/RelocData.h>
#include <mcld/LD/SectionData.h>
#include <mcld/LD/EhFrame.h>
#include <mcld/LD/ResolveInfo.h>
#include <mcld/LD/LDSymbol.h>
#include <mcld/LD/NamePool.h>
#include <mcld/Fragment/FragmentRef.h>
#include <mcld/LD/LDFileFormat.h>


using namespace mcld;

//===----------------------------------------------------------------------===//
// SectionSymbolSet
//===----------------------------------------------------------------------===//

SectionSymbolSet::SectionSymbolSet()
{
  m_pSectionSymbolMap = new SectHashTableType(16);
}

SectionSymbolSet::~SectionSymbolSet()
{
  delete m_pSectionSymbolMap;
}

bool SectionSymbolSet::add(LDSection& pOutSect, NamePool& pNamePool)
{
  // create the resolveInfo for this section symbol
  llvm::StringRef sym_name = llvm::StringRef(pOutSect.name());
  ResolveInfo* sym_info = pNamePool.createSymbol(sym_name,
                                                 false,
                                                 ResolveInfo::Section,
                                                 ResolveInfo::Define,
                                                 ResolveInfo::Local,
                                                 0x0, // size
                                                 ResolveInfo::Default);

  // create the output section symbol and set its fragRef to the first fragment
  // of the section
  LDSymbol* sym = LDSymbol::Create(*sym_info);
  sym_info->setSymPtr(sym);

  // insert the symbol to the Section to Symbol hash map
  bool exist = false;
  SectHashTableType::entry_type* entry =
                            m_pSectionSymbolMap->insert(&pOutSect, exist);
  assert(!exist);
  entry->setValue(sym);

  return true;
}

bool SectionSymbolSet::finalize(LDSection& pOutSect,
                                SymbolTable& pSymTab, bool relocatable)
{
  if (!relocatable && pOutSect.size() == 0)
      return true;

  LDSymbol* sym = get(pOutSect);
  assert(NULL != sym);
  SectionData* data = NULL;
  switch (pOutSect.kind()) {
    case LDFileFormat::Relocation:
      // Relocation section should not have section symbol.
      return true;

    case LDFileFormat::EhFrame:
      if (EhFrame *ehframe = pOutSect.getEhFrame())
          data = ehframe->getSectionData();
      break;

    default:
      data = pOutSect.getSectionData();
      break;
  }
  FragmentRef* frag_ref;
  if (data && !data->empty())
    frag_ref = FragmentRef::Create(data->front(), 0x0);
  else
    frag_ref = FragmentRef::Null();
  sym->setFragmentRef(frag_ref);
  // push symbol into output symbol table
  pSymTab.add(*sym);

  return true;
}

LDSymbol* SectionSymbolSet::get(const LDSection& pOutSect)
{
  SectHashTableType::iterator entry = m_pSectionSymbolMap->find(&pOutSect);
  return entry.getEntry()->value();
}

const LDSymbol* SectionSymbolSet::get(const LDSection& pOutSect) const
{
  SectHashTableType::iterator entry = m_pSectionSymbolMap->find(&pOutSect);
  return entry.getEntry()->value();
}