//===- DebugString.cpp ----------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "mcld/LD/DebugString.h"
#include "mcld/LD/LDSection.h"
#include "mcld/LD/LDSymbol.h"
#include "mcld/LD/RelocData.h"
#include "mcld/LD/ResolveInfo.h"
#include "mcld/LD/SectionData.h"
#include "mcld/Fragment/Fragment.h"
#include "mcld/Fragment/RegionFragment.h"
#include "mcld/Fragment/Relocation.h"
#include "mcld/Target/TargetLDBackend.h"
#include "mcld/LD/Relocator.h"
#include <llvm/Support/Casting.h>
#include <llvm/Support/ManagedStatic.h>
namespace mcld {
// DebugString represents the output .debug_str section, which is at most on
// in each linking
static llvm::ManagedStatic<DebugString> g_DebugString;
static inline size_t string_length(const char* pStr) {
const char* p = pStr;
size_t len = 0;
for (; *p != 0; ++p)
++len;
return len;
}
//==========================
// DebugString
void DebugString::merge(LDSection& pSection) {
// get the fragment contents
llvm::StringRef strings;
SectionData::iterator it, end = pSection.getSectionData()->end();
for (it = pSection.getSectionData()->begin(); it != end; ++it) {
if ((*it).getKind() == Fragment::Region) {
RegionFragment* frag = llvm::cast<RegionFragment>(&(*it));
strings = frag->getRegion().data();
}
}
// get the debug strings and add them into merged string table
const char* str = strings.data();
const char* str_end = str + pSection.size();
while (str < str_end) {
size_t len = string_length(str);
m_StringTable.insertString(llvm::StringRef(str, len));
str = str + len + 1;
}
}
size_t DebugString::computeOffsetSize() {
size_t size = m_StringTable.finalizeOffset();
m_pSection->setSize(size);
return size;
}
void DebugString::applyOffset(Relocation& pReloc, TargetLDBackend& pBackend) {
// get the refered string
ResolveInfo* info = pReloc.symInfo();
// the symbol should point to the first region fragment in the debug
// string section, get the input .debut_str region
llvm::StringRef d_str;
if (info->outSymbol()->fragRef()->frag()->getKind() == Fragment::Region) {
RegionFragment* frag =
llvm::cast<RegionFragment>(info->outSymbol()->fragRef()->frag());
d_str = frag->getRegion();
}
uint32_t offset = pBackend.getRelocator()->getDebugStringOffset(pReloc);
const char* str = d_str.data() + offset;
// apply the relocation
pBackend.getRelocator()->applyDebugStringOffset(pReloc,
m_StringTable.getOutputOffset(llvm::StringRef(str, string_length(str))));
}
void DebugString::emit(MemoryRegion& pRegion) {
return m_StringTable.emit(pRegion);
}
DebugString* DebugString::Create(LDSection& pSection) {
g_DebugString->setOutputSection(pSection);
return &(*g_DebugString);
}
} // namespace mcld