compact_unwind.cpp [plain text]
#include <stdint.h>
#include <math.h>
#include <unistd.h>
#include <dlfcn.h>
#include <mach/machine.h>
#include <mach-o/compact_unwind_encoding.h>
#include <vector>
#include <map>
#include "ld.hpp"
#include "compact_unwind.h"
#include "Architectures.hpp"
#include "MachOFileAbstraction.hpp"
namespace ld {
namespace passes {
namespace compact_unwind {
struct UnwindEntry {
UnwindEntry(const ld::Atom* f, uint64_t a, uint32_t o, const ld::Atom* d,
const ld::Atom* l, const ld::Atom* p, uint32_t en)
: func(f), fde(d), lsda(l), personalityPointer(p), funcTentAddress(a),
functionOffset(o), encoding(en) { }
const ld::Atom* func;
const ld::Atom* fde;
const ld::Atom* lsda;
const ld::Atom* personalityPointer;
uint64_t funcTentAddress;
uint32_t functionOffset;
compact_unwind_encoding_t encoding;
};
struct LSDAEntry {
const ld::Atom* func;
const ld::Atom* lsda;
};
template <typename A>
class UnwindInfoAtom : public ld::Atom {
public:
UnwindInfoAtom(const std::vector<UnwindEntry>& entries,uint64_t ehFrameSize);
~UnwindInfoAtom();
virtual const ld::File* file() const { return NULL; }
virtual const char* name() const { return "compact unwind info"; }
virtual uint64_t size() const { return _headerSize+_pagesSize; }
virtual uint64_t objectAddress() const { return 0; }
virtual void copyRawContent(uint8_t buffer[]) const;
virtual void setScope(Scope) { }
virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixups[0]; }
virtual ld::Fixup::iterator fixupsEnd() const { return (ld::Fixup*)&_fixups[_fixups.size()]; }
private:
typedef typename A::P P;
typedef typename A::P::E E;
typedef typename A::P::uint_t pint_t;
typedef macho_unwind_info_compressed_second_level_page_header<P> CSLP;
bool encodingMeansUseDwarf(compact_unwind_encoding_t enc);
void compressDuplicates(const std::vector<UnwindEntry>& entries,
std::vector<UnwindEntry>& uniqueEntries);
void makePersonalityIndexes(std::vector<UnwindEntry>& entries,
std::map<const ld::Atom*, uint32_t>& personalityIndexMap);
void findCommonEncoding(const std::vector<UnwindEntry>& entries,
std::map<compact_unwind_encoding_t, unsigned int>& commonEncodings);
void makeLsdaIndex(const std::vector<UnwindEntry>& entries, std::vector<LSDAEntry>& lsdaIndex,
std::map<const ld::Atom*, uint32_t>& lsdaIndexOffsetMap);
unsigned int makeCompressedSecondLevelPage(const std::vector<UnwindEntry>& uniqueInfos,
const std::map<compact_unwind_encoding_t,unsigned int> commonEncodings,
uint32_t pageSize, unsigned int endIndex, uint8_t*& pageEnd);
unsigned int makeRegularSecondLevelPage(const std::vector<UnwindEntry>& uniqueInfos, uint32_t pageSize,
unsigned int endIndex, uint8_t*& pageEnd);
void addCompressedAddressOffsetFixup(uint32_t offset, const ld::Atom* func, const ld::Atom* fromFunc);
void addCompressedEncodingFixup(uint32_t offset, const ld::Atom* fde);
void addRegularAddressFixup(uint32_t offset, const ld::Atom* func);
void addRegularFDEOffsetFixup(uint32_t offset, const ld::Atom* fde);
void addImageOffsetFixup(uint32_t offset, const ld::Atom* targ);
void addImageOffsetFixupPlusAddend(uint32_t offset, const ld::Atom* targ, uint32_t addend);
uint8_t* _pagesForDelete;
uint8_t* _pageAlignedPages;
uint8_t* _pages;
uint64_t _pagesSize;
uint8_t* _header;
uint64_t _headerSize;
std::vector<ld::Fixup> _fixups;
static bool _s_log;
static ld::Section _s_section;
};
template <typename A>
bool UnwindInfoAtom<A>::_s_log = false;
template <typename A>
ld::Section UnwindInfoAtom<A>::_s_section("__TEXT", "__unwind_info", ld::Section::typeUnwindInfo);
template <typename A>
UnwindInfoAtom<A>::UnwindInfoAtom(const std::vector<UnwindEntry>& entries, uint64_t ehFrameSize)
: ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified,
symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
_pagesForDelete(NULL), _pageAlignedPages(NULL), _pages(NULL), _pagesSize(0), _header(NULL), _headerSize(0)
{
std::vector<UnwindEntry> uniqueEntries;
compressDuplicates(entries, uniqueEntries);
_fixups.reserve(uniqueEntries.size()*3);
std::map<const ld::Atom*, uint32_t> personalityIndexMap;
makePersonalityIndexes(uniqueEntries, personalityIndexMap);
if ( personalityIndexMap.size() > 3 ) {
throw "too many personality routines for compact unwind to encode";
}
std::map<compact_unwind_encoding_t, unsigned int> commonEncodings;
findCommonEncoding(uniqueEntries, commonEncodings);
std::map<const ld::Atom*, uint32_t> lsdaIndexOffsetMap;
std::vector<LSDAEntry> lsdaIndex;
makeLsdaIndex(uniqueEntries, lsdaIndex, lsdaIndexOffsetMap);
const unsigned int entriesPerRegularPage = (4096-sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
assert(uniqueEntries.size() > 0);
const unsigned int pageCount = ((uniqueEntries.size() - 1)/entriesPerRegularPage) + 2;
_pagesForDelete = (uint8_t*)calloc(pageCount+1,4096);
if ( _pagesForDelete == NULL ) {
warning("could not allocate space for compact unwind info");
return;
}
_pageAlignedPages = (uint8_t*)((((uintptr_t)_pagesForDelete) + 4095) & -4096);
uint32_t maxLastPageSize = 4096 - (ehFrameSize % 4096);
uint32_t tailPad = 0;
if ( maxLastPageSize < 128 ) {
tailPad = maxLastPageSize;
maxLastPageSize = 4096;
}
const ld::Atom* secondLevelFirstFuncs[pageCount*3];
uint8_t* secondLevelPagesStarts[pageCount*3];
unsigned int endIndex = uniqueEntries.size();
unsigned int secondLevelPageCount = 0;
uint8_t* pageEnd = &_pageAlignedPages[pageCount*4096];
uint32_t pageSize = maxLastPageSize;
while ( endIndex > 0 ) {
endIndex = makeCompressedSecondLevelPage(uniqueEntries, commonEncodings, pageSize, endIndex, pageEnd);
secondLevelPagesStarts[secondLevelPageCount] = pageEnd;
secondLevelFirstFuncs[secondLevelPageCount] = uniqueEntries[endIndex].func;
++secondLevelPageCount;
if ( (pageSize != 4096) && (endIndex > 0) ) {
pageEnd = (uint8_t*)((uintptr_t)(pageEnd) & -4096);
pageSize = 4096; }
}
_pages = pageEnd;
_pagesSize = &_pageAlignedPages[pageCount*4096] - pageEnd;
const uint32_t commonEncodingsArraySectionOffset = sizeof(macho_unwind_info_section_header<P>);
const uint32_t commonEncodingsArrayCount = commonEncodings.size();
const uint32_t commonEncodingsArraySize = commonEncodingsArrayCount * sizeof(compact_unwind_encoding_t);
const uint32_t personalityArraySectionOffset = commonEncodingsArraySectionOffset + commonEncodingsArraySize;
const uint32_t personalityArrayCount = personalityIndexMap.size();
const uint32_t personalityArraySize = personalityArrayCount * sizeof(uint32_t);
const uint32_t indexSectionOffset = personalityArraySectionOffset + personalityArraySize;
const uint32_t indexCount = secondLevelPageCount+1;
const uint32_t indexSize = indexCount * sizeof(macho_unwind_info_section_header_index_entry<P>);
const uint32_t lsdaIndexArraySectionOffset = indexSectionOffset + indexSize;
const uint32_t lsdaIndexArrayCount = lsdaIndex.size();
const uint32_t lsdaIndexArraySize = lsdaIndexArrayCount * sizeof(macho_unwind_info_section_header_lsda_index_entry<P>);
const uint32_t headerEndSectionOffset = lsdaIndexArraySectionOffset + lsdaIndexArraySize;
const int32_t fixupSlide = headerEndSectionOffset + (_pageAlignedPages - _pages);
for(std::vector<ld::Fixup>::iterator it = _fixups.begin(); it != _fixups.end(); ++it) {
it->offsetInAtom += fixupSlide;
}
_headerSize = headerEndSectionOffset;
_header = new uint8_t[_headerSize];
bzero(_header, _headerSize);
macho_unwind_info_section_header<P>* sectionHeader = (macho_unwind_info_section_header<P>*)_header;
sectionHeader->set_version(UNWIND_SECTION_VERSION);
sectionHeader->set_commonEncodingsArraySectionOffset(commonEncodingsArraySectionOffset);
sectionHeader->set_commonEncodingsArrayCount(commonEncodingsArrayCount);
sectionHeader->set_personalityArraySectionOffset(personalityArraySectionOffset);
sectionHeader->set_personalityArrayCount(personalityArrayCount);
sectionHeader->set_indexSectionOffset(indexSectionOffset);
sectionHeader->set_indexCount(indexCount);
uint32_t* commonEncodingsTable = (uint32_t*)&_header[commonEncodingsArraySectionOffset];
for (std::map<uint32_t, unsigned int>::iterator it=commonEncodings.begin(); it != commonEncodings.end(); ++it)
E::set32(commonEncodingsTable[it->second], it->first);
uint32_t* personalityArray = (uint32_t*)&_header[sectionHeader->personalityArraySectionOffset()];
for (std::map<const ld::Atom*, unsigned int>::iterator it=personalityIndexMap.begin(); it != personalityIndexMap.end(); ++it) {
uint32_t offset = (uint8_t*)&personalityArray[it->second-1] - _header;
this->addImageOffsetFixup(offset, it->first);
}
macho_unwind_info_section_header_index_entry<P>* indexTable = (macho_unwind_info_section_header_index_entry<P>*)&_header[indexSectionOffset];
uint32_t refOffset;
for (unsigned int i=0; i < secondLevelPageCount; ++i) {
unsigned int reverseIndex = secondLevelPageCount - 1 - i;
indexTable[i].set_functionOffset(0);
indexTable[i].set_secondLevelPagesSectionOffset(secondLevelPagesStarts[reverseIndex]-_pages+headerEndSectionOffset);
indexTable[i].set_lsdaIndexArraySectionOffset(lsdaIndexOffsetMap[secondLevelFirstFuncs[reverseIndex]]+lsdaIndexArraySectionOffset);
refOffset = (uint8_t*)&indexTable[i] - _header;
this->addImageOffsetFixup(refOffset, secondLevelFirstFuncs[reverseIndex]);
}
indexTable[secondLevelPageCount].set_functionOffset(0);
indexTable[secondLevelPageCount].set_secondLevelPagesSectionOffset(0);
indexTable[secondLevelPageCount].set_lsdaIndexArraySectionOffset(lsdaIndexArraySectionOffset+lsdaIndexArraySize);
refOffset = (uint8_t*)&indexTable[secondLevelPageCount] - _header;
this->addImageOffsetFixupPlusAddend(refOffset, entries.back().func, entries.back().func->size()+1);
uint32_t lsdaEntrySectionOffset = lsdaIndexArraySectionOffset;
for (std::vector<LSDAEntry>::iterator it = lsdaIndex.begin(); it != lsdaIndex.end(); ++it) {
this->addImageOffsetFixup(lsdaEntrySectionOffset, it->func);
this->addImageOffsetFixup(lsdaEntrySectionOffset+4, it->lsda);
lsdaEntrySectionOffset += sizeof(unwind_info_section_header_lsda_index_entry);
}
}
template <typename A>
UnwindInfoAtom<A>::~UnwindInfoAtom()
{
free(_pagesForDelete);
free(_header);
}
template <typename A>
void UnwindInfoAtom<A>::copyRawContent(uint8_t buffer[]) const
{
memcpy(buffer, _header, _headerSize);
memcpy(&buffer[_headerSize], _pages, _pagesSize);
}
template <>
bool UnwindInfoAtom<x86>::encodingMeansUseDwarf(compact_unwind_encoding_t enc)
{
return ((enc & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF);
}
template <>
bool UnwindInfoAtom<x86_64>::encodingMeansUseDwarf(compact_unwind_encoding_t enc)
{
return ((enc & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF);
}
template <>
bool UnwindInfoAtom<arm64>::encodingMeansUseDwarf(compact_unwind_encoding_t enc)
{
return ((enc & UNWIND_ARM64_MODE_MASK) == UNWIND_ARM64_MODE_DWARF);
}
template <>
bool UnwindInfoAtom<arm>::encodingMeansUseDwarf(compact_unwind_encoding_t enc)
{
return ((enc & UNWIND_ARM_MODE_MASK) == UNWIND_ARM_MODE_DWARF);
}
template <typename A>
void UnwindInfoAtom<A>::compressDuplicates(const std::vector<UnwindEntry>& entries, std::vector<UnwindEntry>& uniqueEntries)
{
uniqueEntries.reserve(entries.size());
UnwindEntry last(NULL, 0, 0, NULL, NULL, NULL, 0xFFFFFFFF);
for(std::vector<UnwindEntry>::const_iterator it=entries.begin(); it != entries.end(); ++it) {
const UnwindEntry& next = *it;
bool newNeedsDwarf = encodingMeansUseDwarf(next.encoding);
if ( newNeedsDwarf || (next.encoding != last.encoding) || (next.personalityPointer != last.personalityPointer)
|| (next.lsda != NULL) || (last.lsda != NULL) ) {
uniqueEntries.push_back(next);
}
last = next;
}
if (_s_log) fprintf(stderr, "compressDuplicates() entries.size()=%lu, uniqueEntries.size()=%lu\n",
entries.size(), uniqueEntries.size());
}
template <typename A>
void UnwindInfoAtom<A>::makePersonalityIndexes(std::vector<UnwindEntry>& entries, std::map<const ld::Atom*, uint32_t>& personalityIndexMap)
{
for(std::vector<UnwindEntry>::iterator it=entries.begin(); it != entries.end(); ++it) {
if ( it->personalityPointer != NULL ) {
std::map<const ld::Atom*, uint32_t>::iterator pos = personalityIndexMap.find(it->personalityPointer);
if ( pos == personalityIndexMap.end() ) {
const uint32_t nextIndex = personalityIndexMap.size() + 1;
personalityIndexMap[it->personalityPointer] = nextIndex;
}
uint32_t personalityIndex = personalityIndexMap[it->personalityPointer];
it->encoding |= (personalityIndex << (__builtin_ctz(UNWIND_PERSONALITY_MASK)) );
}
}
if (_s_log) fprintf(stderr, "makePersonalityIndexes() %lu personality routines used\n", personalityIndexMap.size());
}
template <typename A>
void UnwindInfoAtom<A>::findCommonEncoding(const std::vector<UnwindEntry>& entries,
std::map<compact_unwind_encoding_t, unsigned int>& commonEncodings)
{
std::map<compact_unwind_encoding_t, unsigned int> encodingsUsed;
unsigned int mostCommonEncodingUsageCount = 0;
for(std::vector<UnwindEntry>::const_iterator it=entries.begin(); it != entries.end(); ++it) {
if ( encodingMeansUseDwarf(it->encoding) )
continue;
std::map<compact_unwind_encoding_t, unsigned int>::iterator pos = encodingsUsed.find(it->encoding);
if ( pos == encodingsUsed.end() ) {
encodingsUsed[it->encoding] = 1;
}
else {
encodingsUsed[it->encoding] += 1;
if ( mostCommonEncodingUsageCount < encodingsUsed[it->encoding] )
mostCommonEncodingUsageCount = encodingsUsed[it->encoding];
}
}
for(unsigned int usages=mostCommonEncodingUsageCount; usages > 1; --usages) {
for (std::map<compact_unwind_encoding_t, unsigned int>::iterator euit=encodingsUsed.begin(); euit != encodingsUsed.end(); ++euit) {
if ( euit->second == usages ) {
unsigned int sz = commonEncodings.size();
if ( sz < 127 ) {
commonEncodings[euit->first] = sz;
}
}
}
}
if (_s_log) fprintf(stderr, "findCommonEncoding() %lu common encodings found\n", commonEncodings.size());
}
template <typename A>
void UnwindInfoAtom<A>::makeLsdaIndex(const std::vector<UnwindEntry>& entries, std::vector<LSDAEntry>& lsdaIndex, std::map<const ld::Atom*, uint32_t>& lsdaIndexOffsetMap)
{
for(std::vector<UnwindEntry>::const_iterator it=entries.begin(); it != entries.end(); ++it) {
lsdaIndexOffsetMap[it->func] = lsdaIndex.size() * sizeof(unwind_info_section_header_lsda_index_entry);
if ( it->lsda != NULL ) {
LSDAEntry entry;
entry.func = it->func;
entry.lsda = it->lsda;
lsdaIndex.push_back(entry);
}
}
if (_s_log) fprintf(stderr, "makeLsdaIndex() %lu LSDAs found\n", lsdaIndex.size());
}
template <>
void UnwindInfoAtom<x86>::addCompressedAddressOffsetFixup(uint32_t offset, const ld::Atom* func, const ld::Atom* fromFunc)
{
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, func));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindSubtractTargetAddress, fromFunc));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndianLow24of32));
}
template <>
void UnwindInfoAtom<x86_64>::addCompressedAddressOffsetFixup(uint32_t offset, const ld::Atom* func, const ld::Atom* fromFunc)
{
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, func));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindSubtractTargetAddress, fromFunc));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndianLow24of32));
}
template <>
void UnwindInfoAtom<arm64>::addCompressedAddressOffsetFixup(uint32_t offset, const ld::Atom* func, const ld::Atom* fromFunc)
{
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, func));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindSubtractTargetAddress, fromFunc));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndianLow24of32));
}
template <>
void UnwindInfoAtom<arm>::addCompressedAddressOffsetFixup(uint32_t offset, const ld::Atom* func, const ld::Atom* fromFunc)
{
if ( fromFunc->isThumb() ) {
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, func));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, fromFunc));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 1));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndianLow24of32));
}
else {
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, func));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindSubtractTargetAddress, fromFunc));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndianLow24of32));
}
}
template <>
void UnwindInfoAtom<x86>::addCompressedEncodingFixup(uint32_t offset, const ld::Atom* fde)
{
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
}
template <>
void UnwindInfoAtom<x86_64>::addCompressedEncodingFixup(uint32_t offset, const ld::Atom* fde)
{
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
}
template <>
void UnwindInfoAtom<arm64>::addCompressedEncodingFixup(uint32_t offset, const ld::Atom* fde)
{
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
}
template <>
void UnwindInfoAtom<arm>::addCompressedEncodingFixup(uint32_t offset, const ld::Atom* fde)
{
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
}
template <>
void UnwindInfoAtom<x86>::addRegularAddressFixup(uint32_t offset, const ld::Atom* func)
{
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, func));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
}
template <>
void UnwindInfoAtom<x86_64>::addRegularAddressFixup(uint32_t offset, const ld::Atom* func)
{
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, func));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
}
template <>
void UnwindInfoAtom<arm64>::addRegularAddressFixup(uint32_t offset, const ld::Atom* func)
{
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, func));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
}
template <>
void UnwindInfoAtom<arm>::addRegularAddressFixup(uint32_t offset, const ld::Atom* func)
{
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, func));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
}
template <>
void UnwindInfoAtom<x86>::addRegularFDEOffsetFixup(uint32_t offset, const ld::Atom* fde)
{
_fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
_fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
}
template <>
void UnwindInfoAtom<x86_64>::addRegularFDEOffsetFixup(uint32_t offset, const ld::Atom* fde)
{
_fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
_fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
}
template <>
void UnwindInfoAtom<arm64>::addRegularFDEOffsetFixup(uint32_t offset, const ld::Atom* fde)
{
_fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
_fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
}
template <>
void UnwindInfoAtom<arm>::addRegularFDEOffsetFixup(uint32_t offset, const ld::Atom* fde)
{
_fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
_fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
}
template <>
void UnwindInfoAtom<x86>::addImageOffsetFixup(uint32_t offset, const ld::Atom* targ)
{
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, targ));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
}
template <>
void UnwindInfoAtom<x86_64>::addImageOffsetFixup(uint32_t offset, const ld::Atom* targ)
{
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, targ));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
}
template <>
void UnwindInfoAtom<arm64>::addImageOffsetFixup(uint32_t offset, const ld::Atom* targ)
{
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, targ));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
}
template <>
void UnwindInfoAtom<arm>::addImageOffsetFixup(uint32_t offset, const ld::Atom* targ)
{
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, targ));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
}
template <>
void UnwindInfoAtom<x86>::addImageOffsetFixupPlusAddend(uint32_t offset, const ld::Atom* targ, uint32_t addend)
{
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetImageOffset, targ));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, addend));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndian32));
}
template <>
void UnwindInfoAtom<x86_64>::addImageOffsetFixupPlusAddend(uint32_t offset, const ld::Atom* targ, uint32_t addend)
{
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetImageOffset, targ));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, addend));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndian32));
}
template <>
void UnwindInfoAtom<arm64>::addImageOffsetFixupPlusAddend(uint32_t offset, const ld::Atom* targ, uint32_t addend)
{
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetImageOffset, targ));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, addend));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndian32));
}
template <>
void UnwindInfoAtom<arm>::addImageOffsetFixupPlusAddend(uint32_t offset, const ld::Atom* targ, uint32_t addend)
{
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetImageOffset, targ));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, addend));
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndian32));
}
template <typename A>
unsigned int UnwindInfoAtom<A>::makeRegularSecondLevelPage(const std::vector<UnwindEntry>& uniqueInfos, uint32_t pageSize,
unsigned int endIndex, uint8_t*& pageEnd)
{
const unsigned int maxEntriesPerPage = (pageSize - sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
const unsigned int entriesToAdd = ((endIndex > maxEntriesPerPage) ? maxEntriesPerPage : endIndex);
uint8_t* pageStart = pageEnd
- entriesToAdd*sizeof(unwind_info_regular_second_level_entry)
- sizeof(unwind_info_regular_second_level_page_header);
macho_unwind_info_regular_second_level_page_header<P>* page = (macho_unwind_info_regular_second_level_page_header<P>*)pageStart;
page->set_kind(UNWIND_SECOND_LEVEL_REGULAR);
page->set_entryPageOffset(sizeof(macho_unwind_info_regular_second_level_page_header<P>));
page->set_entryCount(entriesToAdd);
macho_unwind_info_regular_second_level_entry<P>* entryTable = (macho_unwind_info_regular_second_level_entry<P>*)(pageStart + page->entryPageOffset());
for (unsigned int i=0; i < entriesToAdd; ++i) {
const UnwindEntry& info = uniqueInfos[endIndex-entriesToAdd+i];
entryTable[i].set_functionOffset(0);
entryTable[i].set_encoding(info.encoding);
uint32_t offset = (uint8_t*)(&entryTable[i]) - _pageAlignedPages;
this->addRegularAddressFixup(offset, info.func);
if ( encodingMeansUseDwarf(info.encoding) ) {
uint32_t encOffset = (uint8_t*)(&entryTable[i]) - _pageAlignedPages;
this->addRegularFDEOffsetFixup(encOffset, info.fde);
}
}
if (_s_log) fprintf(stderr, "regular page with %u entries\n", entriesToAdd);
pageEnd = pageStart;
return endIndex - entriesToAdd;
}
template <typename A>
unsigned int UnwindInfoAtom<A>::makeCompressedSecondLevelPage(const std::vector<UnwindEntry>& uniqueInfos,
const std::map<compact_unwind_encoding_t,unsigned int> commonEncodings,
uint32_t pageSize, unsigned int endIndex, uint8_t*& pageEnd)
{
if (_s_log) fprintf(stderr, "makeCompressedSecondLevelPage(pageSize=%u, endIndex=%u)\n", pageSize, endIndex);
std::map<compact_unwind_encoding_t, unsigned int> pageSpecificEncodings;
uint32_t space4 = (pageSize - sizeof(unwind_info_compressed_second_level_page_header))/sizeof(uint32_t);
int index = endIndex-1;
int entryCount = 0;
uint64_t lastEntryAddress = uniqueInfos[index].funcTentAddress;
bool canDo = true;
while ( canDo && (index >= 0) ) {
const UnwindEntry& info = uniqueInfos[index--];
unsigned int encodingIndex;
std::map<compact_unwind_encoding_t, unsigned int>::const_iterator pos = commonEncodings.find(info.encoding);
if ( pos != commonEncodings.end() ) {
encodingIndex = pos->second;
if (_s_log) fprintf(stderr, "makeCompressedSecondLevelPage(): funcIndex=%d, re-use commonEncodings[%d]=0x%08X\n", index, encodingIndex, info.encoding);
}
else {
uint32_t encoding = info.encoding;
if ( encodingMeansUseDwarf(encoding) ) {
encoding += (index+1);
}
std::map<compact_unwind_encoding_t, unsigned int>::iterator ppos = pageSpecificEncodings.find(encoding);
if ( ppos != pageSpecificEncodings.end() ) {
encodingIndex = pos->second;
if (_s_log) fprintf(stderr, "makeCompressedSecondLevelPage(): funcIndex=%d, re-use pageSpecificEncodings[%d]=0x%08X\n", index, encodingIndex, encoding);
}
else {
encodingIndex = commonEncodings.size() + pageSpecificEncodings.size();
if ( encodingIndex <= 255 ) {
pageSpecificEncodings[encoding] = encodingIndex;
if (_s_log) fprintf(stderr, "makeCompressedSecondLevelPage(): funcIndex=%d, pageSpecificEncodings[%d]=0x%08X\n", index, encodingIndex, encoding);
}
else {
canDo = false; if (_s_log) fprintf(stderr, "end of compressed page with %u entries, %lu custom encodings because too many custom encodings\n",
entryCount, pageSpecificEncodings.size());
}
}
}
uint32_t funcOffsetWithInPage = lastEntryAddress - info.funcTentAddress;
if ( funcOffsetWithInPage > 0x00FFFF00 ) {
canDo = false; if (_s_log) fprintf(stderr, "can't use compressed page with %u entries because function offset too big\n", entryCount);
}
if ( (pageSpecificEncodings.size()+entryCount) > space4 ) {
canDo = false; --entryCount;
if (_s_log) fprintf(stderr, "end of compressed page with %u entries because full\n", entryCount);
}
if ( canDo ) {
++entryCount;
}
}
const unsigned int compressPageUsed = sizeof(unwind_info_compressed_second_level_page_header)
+ pageSpecificEncodings.size()*sizeof(uint32_t)
+ entryCount*sizeof(uint32_t);
if ( (compressPageUsed < (pageSize-4) && (index >= 0) ) ) {
const int regularEntriesPerPage = (pageSize - sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
if ( entryCount < regularEntriesPerPage ) {
return makeRegularSecondLevelPage(uniqueInfos, pageSize, endIndex, pageEnd);
}
}
uint32_t pad = 0;
if ( compressPageUsed == (pageSize-4) )
pad = 4;
uint8_t* pageStart = pageEnd - compressPageUsed - pad;
CSLP* page = (CSLP*)pageStart;
page->set_kind(UNWIND_SECOND_LEVEL_COMPRESSED);
page->set_entryPageOffset(sizeof(CSLP));
page->set_entryCount(entryCount);
page->set_encodingsPageOffset(page->entryPageOffset()+entryCount*sizeof(uint32_t));
page->set_encodingsCount(pageSpecificEncodings.size());
uint32_t* const encodingsArray = (uint32_t*)&pageStart[page->encodingsPageOffset()];
uint32_t* const entiresArray = (uint32_t*)&pageStart[page->entryPageOffset()];
const ld::Atom* firstFunc = uniqueInfos[endIndex-entryCount].func;
for(unsigned int i=endIndex-entryCount; i < endIndex; ++i) {
const UnwindEntry& info = uniqueInfos[i];
uint8_t encodingIndex;
if ( encodingMeansUseDwarf(info.encoding) ) {
assert(pageSpecificEncodings.find(info.encoding+i) != pageSpecificEncodings.end());
encodingIndex = pageSpecificEncodings[info.encoding+i];
}
else {
std::map<uint32_t, unsigned int>::const_iterator pos = commonEncodings.find(info.encoding);
if ( pos != commonEncodings.end() )
encodingIndex = pos->second;
else
encodingIndex = pageSpecificEncodings[info.encoding];
}
uint32_t entryIndex = i - endIndex + entryCount;
E::set32(entiresArray[entryIndex], encodingIndex << 24);
uint32_t offset = (uint8_t*)(&entiresArray[entryIndex]) - _pageAlignedPages;
this->addCompressedAddressOffsetFixup(offset, info.func, firstFunc);
if ( encodingMeansUseDwarf(info.encoding) ) {
uint32_t encOffset = (uint8_t*)(&encodingsArray[encodingIndex-commonEncodings.size()]) - _pageAlignedPages;
this->addCompressedEncodingFixup(encOffset, info.fde);
}
}
for(std::map<uint32_t, unsigned int>::const_iterator it = pageSpecificEncodings.begin(); it != pageSpecificEncodings.end(); ++it) {
E::set32(encodingsArray[it->second-commonEncodings.size()], it->first);
}
if (_s_log) fprintf(stderr, "compressed page with %u entries, %lu custom encodings\n", entryCount, pageSpecificEncodings.size());
pageEnd = pageStart;
return endIndex-entryCount; }
static uint64_t calculateEHFrameSize(ld::Internal& state)
{
bool allCIEs = true;
uint64_t size = 0;
for (ld::Internal::FinalSection* sect : state.sections) {
if ( sect->type() == ld::Section::typeCFI ) {
for (const ld::Atom* atom : sect->atoms) {
size += atom->size();
if ( strcmp(atom->name(), "CIE") != 0 )
allCIEs = false;
}
if ( allCIEs ) {
sect->atoms.clear();
state.sections.erase(std::remove(state.sections.begin(), state.sections.end(), sect), state.sections.end());
return 0;
}
}
}
return size;
}
static void getAllUnwindInfos(const ld::Internal& state, std::vector<UnwindEntry>& entries)
{
uint64_t address = 0;
for (std::vector<ld::Internal::FinalSection*>::const_iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
ld::Internal::FinalSection* sect = *sit;
for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
const ld::Atom* atom = *ait;
uint64_t alignment = 1 << atom->alignment().powerOf2;
uint64_t currentModulus = (address % alignment);
uint64_t requiredModulus = atom->alignment().modulus;
if ( currentModulus != requiredModulus ) {
if ( requiredModulus > currentModulus )
address += requiredModulus-currentModulus;
else
address += requiredModulus+alignment-currentModulus;
}
if ( atom->beginUnwind() == atom->endUnwind() ) {
if ( (atom->section().type() == ld::Section::typeCode) && (atom->size() !=0) ) {
entries.push_back(UnwindEntry(atom, address, 0, NULL, NULL, NULL, 0));
}
}
else {
const ld::Atom* fde = NULL;
const ld::Atom* lsda = NULL;
const ld::Atom* personalityPointer = NULL;
for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
switch ( fit->kind ) {
case ld::Fixup::kindNoneGroupSubordinateFDE:
assert(fit->binding == ld::Fixup::bindingDirectlyBound);
fde = fit->u.target;
break;
case ld::Fixup::kindNoneGroupSubordinateLSDA:
assert(fit->binding == ld::Fixup::bindingDirectlyBound);
lsda = fit->u.target;
break;
case ld::Fixup::kindNoneGroupSubordinatePersonality:
assert(fit->binding == ld::Fixup::bindingDirectlyBound);
personalityPointer = fit->u.target;
assert(personalityPointer->section().type() == ld::Section::typeNonLazyPointer);
break;
default:
break;
}
}
if ( fde != NULL ) {
const ld::Atom* cie = NULL;
for (ld::Fixup::iterator fit = fde->fixupsBegin(), end=fde->fixupsEnd(); fit != end; ++fit) {
if ( fit->kind != ld::Fixup::kindSubtractTargetAddress )
continue;
if ( fit->binding != ld::Fixup::bindingDirectlyBound )
continue;
cie = fit->u.target;
assert(cie->section().type() == ld::Section::typeCFI);
break;
}
if ( cie != NULL ) {
for (ld::Fixup::iterator fit = cie->fixupsBegin(), end=cie->fixupsEnd(); fit != end; ++fit) {
if ( fit->kind == ld::Fixup::kindSetTargetAddress ) {
switch ( fit->binding ) {
case ld::Fixup::bindingsIndirectlyBound:
personalityPointer = state.indirectBindingTable[fit->u.bindingIndex];
assert(personalityPointer->section().type() == ld::Section::typeNonLazyPointer);
break;
case ld::Fixup::bindingDirectlyBound:
personalityPointer = fit->u.target;
assert(personalityPointer->section().type() == ld::Section::typeNonLazyPointer);
break;
default:
break;
}
}
}
}
}
for ( ld::Atom::UnwindInfo::iterator uit = atom->beginUnwind(); uit != atom->endUnwind(); ++uit ) {
entries.push_back(UnwindEntry(atom, address, uit->startOffset, fde, lsda, personalityPointer, uit->unwindInfo));
}
}
address += atom->size();
}
}
}
static void makeFinalLinkedImageCompactUnwindSection(const Options& opts, ld::Internal& state)
{
std::vector<UnwindEntry> entries;
entries.reserve(64);
getAllUnwindInfos(state, entries);
if ( entries.size() == 0 )
return;
uint64_t ehFrameSize = calculateEHFrameSize(state);
switch ( opts.architecture() ) {
#if SUPPORT_ARCH_x86_64
case CPU_TYPE_X86_64:
state.addAtom(*new UnwindInfoAtom<x86_64>(entries, ehFrameSize));
break;
#endif
#if SUPPORT_ARCH_i386
case CPU_TYPE_I386:
state.addAtom(*new UnwindInfoAtom<x86>(entries, ehFrameSize));
break;
#endif
#if SUPPORT_ARCH_arm64
case CPU_TYPE_ARM64:
state.addAtom(*new UnwindInfoAtom<arm64>(entries, ehFrameSize));
break;
#endif
#if SUPPORT_ARCH_arm_any
case CPU_TYPE_ARM:
if ( opts.armUsesZeroCostExceptions() )
state.addAtom(*new UnwindInfoAtom<arm>(entries, ehFrameSize));
break;
#endif
default:
assert(0 && "no compact unwind for arch");
}
}
template <typename A>
class CompactUnwindAtom : public ld::Atom {
public:
CompactUnwindAtom(ld::Internal& state,const ld::Atom* funcAtom,
uint32_t startOffset, uint32_t len, uint32_t cui);
~CompactUnwindAtom() {}
virtual const ld::File* file() const { return NULL; }
virtual const char* name() const { return "compact unwind info"; }
virtual uint64_t size() const { return sizeof(macho_compact_unwind_entry<P>); }
virtual uint64_t objectAddress() const { return 0; }
virtual void copyRawContent(uint8_t buffer[]) const;
virtual void setScope(Scope) { }
virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixups[0]; }
virtual ld::Fixup::iterator fixupsEnd() const { return (ld::Fixup*)&_fixups[_fixups.size()]; }
private:
typedef typename A::P P;
typedef typename A::P::E E;
typedef typename A::P::uint_t pint_t;
const ld::Atom* _atom;
const uint32_t _startOffset;
const uint32_t _len;
const uint32_t _compactUnwindInfo;
std::vector<ld::Fixup> _fixups;
static ld::Fixup::Kind _s_pointerKind;
static ld::Fixup::Kind _s_pointerStoreKind;
static ld::Section _s_section;
};
template <typename A>
ld::Section CompactUnwindAtom<A>::_s_section("__LD", "__compact_unwind", ld::Section::typeDebug);
template <> ld::Fixup::Kind CompactUnwindAtom<x86>::_s_pointerKind = ld::Fixup::kindStoreLittleEndian32;
template <> ld::Fixup::Kind CompactUnwindAtom<x86>::_s_pointerStoreKind = ld::Fixup::kindStoreTargetAddressLittleEndian32;
template <> ld::Fixup::Kind CompactUnwindAtom<x86_64>::_s_pointerKind = ld::Fixup::kindStoreLittleEndian64;
template <> ld::Fixup::Kind CompactUnwindAtom<x86_64>::_s_pointerStoreKind = ld::Fixup::kindStoreTargetAddressLittleEndian64;
#if SUPPORT_ARCH_arm64
template <> ld::Fixup::Kind CompactUnwindAtom<arm64>::_s_pointerKind = ld::Fixup::kindStoreLittleEndian64;
template <> ld::Fixup::Kind CompactUnwindAtom<arm64>::_s_pointerStoreKind = ld::Fixup::kindStoreTargetAddressLittleEndian64;
#endif
template <> ld::Fixup::Kind CompactUnwindAtom<arm>::_s_pointerKind = ld::Fixup::kindStoreLittleEndian32;
template <> ld::Fixup::Kind CompactUnwindAtom<arm>::_s_pointerStoreKind = ld::Fixup::kindStoreTargetAddressLittleEndian32;
template <typename A>
CompactUnwindAtom<A>::CompactUnwindAtom(ld::Internal& state,const ld::Atom* funcAtom, uint32_t startOffset,
uint32_t len, uint32_t cui)
: ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
ld::Atom::scopeTranslationUnit, ld::Atom::typeUnclassified,
symbolTableNotIn, false, false, false, ld::Atom::Alignment(log2(sizeof(pint_t)))),
_atom(funcAtom), _startOffset(startOffset), _len(len), _compactUnwindInfo(cui)
{
_fixups.push_back(ld::Fixup(macho_compact_unwind_entry<P>::codeStartFieldOffset(), ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, funcAtom));
_fixups.push_back(ld::Fixup(macho_compact_unwind_entry<P>::codeStartFieldOffset(), ld::Fixup::k2of3, ld::Fixup::kindAddAddend, _startOffset));
_fixups.push_back(ld::Fixup(macho_compact_unwind_entry<P>::codeStartFieldOffset(), ld::Fixup::k3of3, _s_pointerKind));
for (ld::Fixup::iterator fit = funcAtom->fixupsBegin(), end=funcAtom->fixupsEnd(); fit != end; ++fit) {
switch ( fit->kind ) {
case ld::Fixup::kindNoneGroupSubordinatePersonality:
assert(fit->binding == ld::Fixup::bindingsIndirectlyBound);
_fixups.push_back(ld::Fixup(macho_compact_unwind_entry<P>::personalityFieldOffset(), ld::Fixup::k1of1, _s_pointerStoreKind, state.indirectBindingTable[fit->u.bindingIndex]));
break;
case ld::Fixup::kindNoneGroupSubordinateLSDA:
assert(fit->binding == ld::Fixup::bindingDirectlyBound);
_fixups.push_back(ld::Fixup(macho_compact_unwind_entry<P>::lsdaFieldOffset(), ld::Fixup::k1of1, _s_pointerStoreKind, fit->u.target));
break;
default:
break;
}
}
}
template <typename A>
void CompactUnwindAtom<A>::copyRawContent(uint8_t buffer[]) const
{
macho_compact_unwind_entry<P>* buf = (macho_compact_unwind_entry<P>*)buffer;
buf->set_codeStart(0);
buf->set_codeLen(_len);
buf->set_compactUnwindInfo(_compactUnwindInfo);
buf->set_personality(0);
buf->set_lsda(0);
}
static void makeCompactUnwindAtom(const Options& opts, ld::Internal& state, const ld::Atom* atom,
uint32_t startOffset, uint32_t endOffset, uint32_t cui)
{
switch ( opts.architecture() ) {
#if SUPPORT_ARCH_x86_64
case CPU_TYPE_X86_64:
state.addAtom(*new CompactUnwindAtom<x86_64>(state, atom, startOffset, endOffset-startOffset, cui));
break;
#endif
#if SUPPORT_ARCH_i386
case CPU_TYPE_I386:
state.addAtom(*new CompactUnwindAtom<x86>(state, atom, startOffset, endOffset-startOffset, cui));
break;
#endif
#if SUPPORT_ARCH_arm64
case CPU_TYPE_ARM64:
state.addAtom(*new CompactUnwindAtom<arm64>(state, atom, startOffset, endOffset-startOffset, cui));
break;
#endif
case CPU_TYPE_ARM:
state.addAtom(*new CompactUnwindAtom<arm>(state, atom, startOffset, endOffset-startOffset, cui));
break;
}
}
static void makeRelocateableCompactUnwindSection(const Options& opts, ld::Internal& state)
{
std::vector<const ld::Atom*> atomsWithUnwind;
for (std::vector<ld::Internal::FinalSection*>::const_iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
ld::Internal::FinalSection* sect = *sit;
for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
const ld::Atom* atom = *ait;
if ( atom->beginUnwind() != atom->endUnwind() )
atomsWithUnwind.push_back(atom);
}
}
for (std::vector<const ld::Atom*>::iterator it = atomsWithUnwind.begin(); it != atomsWithUnwind.end(); ++it) {
const ld::Atom* atom = *it;
uint32_t lastOffset = 0;
uint32_t lastCUE = 0;
bool first = true;
for (ld::Atom::UnwindInfo::iterator uit=atom->beginUnwind(); uit != atom->endUnwind(); ++uit) {
if ( !first ) {
makeCompactUnwindAtom(opts, state, atom, lastOffset, uit->startOffset, lastCUE);
}
lastOffset = uit->startOffset;
lastCUE = uit->unwindInfo;
first = false;
}
makeCompactUnwindAtom(opts, state, atom, lastOffset, (uint32_t)atom->size(), lastCUE);
}
}
void doPass(const Options& opts, ld::Internal& state)
{
if ( opts.outputKind() == Options::kObjectFile )
makeRelocateableCompactUnwindSection(opts, state);
else if ( opts.needsUnwindInfoSection() )
makeFinalLinkedImageCompactUnwindSection(opts, state);
}
} } }