[mach-o] Add support for parsing __eh_frame section. Generalize support for whether symbols in a section are ignored or illegal

llvm-svn: 209858
This commit is contained in:
Nick Kledzik 2014-05-29 23:07:20 +00:00
parent 3012a1b4cd
commit b367c25f28
3 changed files with 180 additions and 21 deletions

View File

@ -200,6 +200,9 @@ SectionInfo *Util::makeSection(DefinedAtom::ContentType type) {
case DefinedAtom::typeCFString:
return new (_allocator) SectionInfo("__DATA", "__cfstring",
S_REGULAR);
case DefinedAtom::typeCFI:
return new (_allocator) SectionInfo("__TEXT", "__eh_frame",
S_COALESCED);
default:
llvm_unreachable("TO DO: add support for more sections");
break;

View File

@ -21,6 +21,7 @@
/// +-------+
#include "MachONormalizedFile.h"
#include "MachONormalizedFileBinaryUtils.h"
#include "File.h"
#include "Atoms.h"
@ -35,8 +36,14 @@ namespace lld {
namespace mach_o {
namespace normalized {
enum SymbolsInSection {
symbolsOk,
symbolsIgnored,
symbolsIllegal
};
static uint64_t nextSymbolAddress(const NormalizedFile &normalizedFile,
const Symbol &symbol) {
const Symbol &symbol) {
uint64_t symbolAddr = symbol.value;
uint8_t symbolSectionIndex = symbol.sect;
const Section &section = normalizedFile.sections[symbolSectionIndex - 1];
@ -80,19 +87,38 @@ static DefinedAtom::ContentType atomTypeFromSection(const Section &section) {
return DefinedAtom::typeCode;
}
static void processSymbol(const NormalizedFile &normalizedFile, MachOFile &file,
const Symbol &sym, bool copyRefs) {
static error_code
processSymbol(const NormalizedFile &normalizedFile, MachOFile &file,
const Symbol &sym, bool copyRefs,
const SmallVector<SymbolsInSection, 32> symbolsInSect) {
if (sym.sect > normalizedFile.sections.size()) {
int sectionIndex = sym.sect;
return make_dynamic_error_code(Twine("Symbol '") + sym.name
+ "' has n_sect ("
+ Twine(sectionIndex)
+ ") which is too large");
}
const Section &section = normalizedFile.sections[sym.sect - 1];
switch (symbolsInSect[sym.sect-1]) {
case symbolsOk:
break;
case symbolsIgnored:
return error_code::success();
break;
case symbolsIllegal:
return make_dynamic_error_code(Twine("Symbol '") + sym.name
+ "' is not legal in section "
+ section.segmentName + "/"
+ section.sectionName);
break;
}
uint64_t offset = sym.value - section.address;
// Mach-O symbol table does have size in it, so need to scan ahead
// to find symbol with next highest address.
const Section &section = normalizedFile.sections[sym.sect - 1];
uint64_t offset = sym.value - section.address;
uint64_t size = nextSymbolAddress(normalizedFile, sym) - sym.value;
if (section.type == llvm::MachO::S_ZEROFILL) {
file.addZeroFillDefinedAtom(sym.name, atomScope(sym.scope), size, copyRefs);
}
else if ((section.type == llvm::MachO::S_CSTRING_LITERALS) &&
(sym.name[0] == 'L')) {
// Ignore L labels on cstrings.
} else {
ArrayRef<uint8_t> atomContent = section.content.slice(offset, size);
DefinedAtom::Merge m = DefinedAtom::mergeNo;
@ -101,6 +127,7 @@ static void processSymbol(const NormalizedFile &normalizedFile, MachOFile &file,
file.addDefinedAtom(sym.name, atomScope(sym.scope),
atomTypeFromSection(section), m, atomContent, copyRefs);
}
return error_code::success();
}
@ -168,22 +195,63 @@ static error_code processCFStringSection(MachOFile &file,const Section &section,
return error_code::success();
}
// A __TEXT/__eh_frame section contains dwarf unwind CFIs (either CIE or FDE).
// Atom boundaries are determined by looking at the length content header
// in each CFI.
static error_code processCFISection(MachOFile &file, const Section &section,
bool is64, bool swap, bool copyRefs) {
const unsigned char* buffer = section.content.data();
for (size_t offset = 0, end = section.content.size(); offset < end; ) {
size_t remaining = end - offset;
if (remaining < 16) {
return make_dynamic_error_code(Twine("Section __TEXT/__eh_frame is "
"malformed. Not enough room left for "
"a CFI starting at offset ("
+ Twine(offset)
+ ")"));
}
const uint32_t *cfi = reinterpret_cast<const uint32_t *>(&buffer[offset]);
uint32_t len = read32(swap, *cfi) + 4;
if (offset+len > end) {
return make_dynamic_error_code(Twine("Section __TEXT/__eh_frame is "
"malformed. Size of CFI starting at "
"at offset ("
+ Twine(offset)
+ ") is past end of section."));
}
ArrayRef<uint8_t> bytes = section.content.slice(offset, len);
file.addDefinedAtom(StringRef(), DefinedAtom::scopeTranslationUnit,
DefinedAtom::typeCFI, DefinedAtom::mergeNo,
bytes, copyRefs);
offset += len;
}
return error_code::success();
}
static error_code processSection(MachOFile &file, const Section &section,
bool is64, bool copyRefs) {
bool is64, bool swap, bool copyRefs,
SymbolsInSection &symbolsInSect) {
unsigned offset = 0;
const unsigned pointerSize = (is64 ? 8 : 4);
switch (section.type) {
case llvm::MachO::S_REGULAR:
if (section.segmentName.equals("__TEXT") &&
section.sectionName.equals("__ustring")) {
symbolsInSect = symbolsIgnored;
return processUTF16Section(file, section, is64, copyRefs);
}
else if (section.segmentName.equals("__DATA") &&
} else if (section.segmentName.equals("__DATA") &&
section.sectionName.equals("__cfstring")) {
symbolsInSect = symbolsIllegal;
return processCFStringSection(file, section, is64, copyRefs);
}
break;
case llvm::MachO::S_COALESCED:
if (section.segmentName.equals("__TEXT") &&
section.sectionName.equals("__eh_frame")) {
symbolsInSect = symbolsIgnored;
return processCFISection(file, section, is64, swap, copyRefs);
}
case llvm::MachO::S_ZEROFILL:
// These sections are broken into atoms based on symbols.
break;
@ -204,6 +272,7 @@ static error_code processSection(MachOFile &file, const Section &section,
bytes, copyRefs);
offset += pointerSize;
}
symbolsInSect = symbolsIllegal;
break;
case S_MOD_TERM_FUNC_POINTERS:
if ((section.content.size() % pointerSize) != 0) {
@ -222,6 +291,7 @@ static error_code processSection(MachOFile &file, const Section &section,
bytes, copyRefs);
offset += pointerSize;
}
symbolsInSect = symbolsIllegal;
break;
case S_NON_LAZY_SYMBOL_POINTERS:
if ((section.content.size() % pointerSize) != 0) {
@ -240,6 +310,7 @@ static error_code processSection(MachOFile &file, const Section &section,
bytes, copyRefs);
offset += pointerSize;
}
symbolsInSect = symbolsIllegal;
break;
case llvm::MachO::S_CSTRING_LITERALS:
for (size_t i = 0, e = section.content.size(); i != e; ++i) {
@ -259,6 +330,7 @@ static error_code processSection(MachOFile &file, const Section &section,
"last string in the section is not zero "
"terminated.");
}
symbolsInSect = symbolsIgnored;
break;
case llvm::MachO::S_4BYTE_LITERALS:
if ((section.content.size() % 4) != 0)
@ -274,6 +346,7 @@ static error_code processSection(MachOFile &file, const Section &section,
DefinedAtom::mergeByContent, byteContent, copyRefs);
offset += 4;
}
symbolsInSect = symbolsIllegal;
break;
case llvm::MachO::S_8BYTE_LITERALS:
if ((section.content.size() % 8) != 0)
@ -289,6 +362,7 @@ static error_code processSection(MachOFile &file, const Section &section,
DefinedAtom::mergeByContent, byteContent, copyRefs);
offset += 8;
}
symbolsInSect = symbolsIllegal;
break;
case llvm::MachO::S_16BYTE_LITERALS:
if ((section.content.size() % 16) != 0)
@ -304,6 +378,7 @@ static error_code processSection(MachOFile &file, const Section &section,
DefinedAtom::mergeByContent, byteContent, copyRefs);
offset += 16;
}
symbolsInSect = symbolsIllegal;
break;
default:
llvm_unreachable("mach-o section type not supported yet");
@ -317,24 +392,32 @@ normalizedObjectToAtoms(const NormalizedFile &normalizedFile, StringRef path,
bool copyRefs) {
std::unique_ptr<MachOFile> file(new MachOFile(path));
// Create atoms from sections that don't have symbols.
bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
bool swap = !MachOLinkingContext::isHostEndian(normalizedFile.arch);
SmallVector<SymbolsInSection, 32> symbolsInSect;
for (auto &sect : normalizedFile.sections) {
symbolsInSect.push_back(symbolsOk);
if (error_code ec = processSection(*file, sect, is64, swap, copyRefs,
symbolsInSect.back()))
return ec;
}
// Create atoms from global symbols.
for (const Symbol &sym : normalizedFile.globalSymbols) {
processSymbol(normalizedFile, *file, sym, copyRefs);
if (error_code ec = processSymbol(normalizedFile, *file, sym, copyRefs,
symbolsInSect))
return ec;
}
// Create atoms from local symbols.
for (const Symbol &sym : normalizedFile.localSymbols) {
processSymbol(normalizedFile, *file, sym, copyRefs);
if (error_code ec = processSymbol(normalizedFile, *file, sym, copyRefs,
symbolsInSect))
return ec;
}
// Create atoms from undefinded symbols.
// Create atoms from undefined symbols.
for (auto &sym : normalizedFile.undefinedSymbols) {
processUndefindeSymbol(*file, sym, copyRefs);
}
// Create atoms from sections that don't have symbols.
bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
for (auto &sect : normalizedFile.sections) {
if (error_code ec = processSection(*file, sect, is64, copyRefs))
return ec;
}
return std::unique_ptr<File>(std::move(file));
}

View File

@ -0,0 +1,73 @@
# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
#
# Test parsing of __eh_frame (dwarf unwind) section.
#
--- !mach-o
arch: x86_64
file-type: MH_OBJECT
flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
has-UUID: false
OS: unknown
sections:
- segment: __TEXT
section: __text
type: S_REGULAR
attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
address: 0x0000000000000000
content: [ 0x55, 0x48, 0x89, 0xE5, 0xB8, 0x09, 0x00, 0x00,
0x00, 0x5D, 0xC3, 0x55, 0x48, 0x89, 0xE5, 0xB8,
0x0A, 0x00, 0x00, 0x00, 0x5D, 0xC3 ]
- segment: __TEXT
section: __eh_frame
type: S_COALESCED
attributes: [ ]
alignment: 3
address: 0x0000000000000058
content: [ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x7A, 0x52, 0x00, 0x01, 0x78, 0x10, 0x01,
0x10, 0x0C, 0x07, 0x08, 0x90, 0x01, 0x00, 0x00,
0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
0x88, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D,
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,
0x6B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D,
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
global-symbols:
- name: __Z3barv
type: N_SECT
scope: [ N_EXT ]
sect: 1
value: 0x0000000000000000
- name: __Z3foov
type: N_SECT
scope: [ N_EXT ]
sect: 1
value: 0x000000000000000B
...
# CHECK: defined-atoms:
# CHECK: - type: unwind-cfi
# CHECK: content: [ 14, 00, 00, 00, 00, 00, 00, 00, 01, 7A, 52, 00,
# CHECK: 01, 78, 10, 01, 10, 0C, 07, 08, 90, 01, 00, 00 ]
# CHECK: - type: unwind-cfi
# CHECK: content: [ 24, 00, 00, 00, 1C, 00, 00, 00, 88, FF, FF, FF,
# CHECK: FF, FF, FF, FF, 0B, 00, 00, 00, 00, 00, 00, 00,
# CHECK: 00, 41, 0E, 10, 86, 02, 43, 0D, 06, 00, 00, 00,
# CHECK: 00, 00, 00, 00 ]
# CHECK: - type: unwind-cfi
# CHECK: content: [ 24, 00, 00, 00, 44, 00, 00, 00, 6B, FF, FF, FF,
# CHECK: FF, FF, FF, FF, 0B, 00, 00, 00, 00, 00, 00, 00,
# CHECK: 00, 41, 0E, 10, 86, 02, 43, 0D, 06, 00, 00, 00,
# CHECK: 00, 00, 00, 00 ]
# CHECK: - name: __Z3barv
# CHECK: scope: global
# CHECK: content: [ 55, 48, 89, E5, B8, 09, 00, 00, 00, 5D, C3 ]
# CHECK: - name: __Z3foov
# CHECK: scope: global
# CHECK: content: [ 55, 48, 89, E5, B8, 0A, 00, 00, 00, 5D, C3 ]