[LLD] Make sure MachO FDEs read their augmentation data strings from the right

CIE, not just the most recently encountered one.

llvm-svn: 237491
This commit is contained in:
Lang Hames 2015-05-16 00:08:02 +00:00
parent e2eb3a5300
commit 3d2911f5cd
2 changed files with 152 additions and 73 deletions

View File

@ -647,13 +647,15 @@ static int64_t readSPtr(bool is64, bool isBig, const uint8_t *addr) {
/// --- Augmentation String Processing ---
struct AugmentationDataInfo {
bool _present = false;
struct CIEInfo {
bool _augmentationDataPresent = false;
bool _mayHaveLSDA = false;
};
typedef llvm::DenseMap<const MachODefinedAtom*, CIEInfo> CIEInfoMap;
static std::error_code processAugmentationString(const uint8_t *augStr,
AugmentationDataInfo &adi,
CIEInfo &cieInfo,
unsigned *len = nullptr) {
if (augStr[0] == '\0') {
@ -666,12 +668,12 @@ static std::error_code processAugmentationString(const uint8_t *augStr,
return make_dynamic_error_code("expected 'z' at start of augmentation "
"string");
adi._present = true;
cieInfo._augmentationDataPresent = true;
uint64_t idx = 1;
while (augStr[idx] != '\0') {
if (augStr[idx] == 'L') {
adi._mayHaveLSDA = true;
cieInfo._mayHaveLSDA = true;
++idx;
} else
++idx;
@ -684,10 +686,12 @@ static std::error_code processAugmentationString(const uint8_t *augStr,
static std::error_code processCIE(const NormalizedFile &normalizedFile,
MachODefinedAtom *atom,
AugmentationDataInfo &adi) {
CIEInfoMap &cieInfos) {
const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
const uint8_t *frameData = atom->rawContent().data();
CIEInfo cieInfo;
uint32_t size = read32(frameData, isBig);
uint64_t cieIDField = size == 0xffffffffU
? sizeof(uint32_t) + sizeof(uint64_t)
@ -696,9 +700,11 @@ static std::error_code processCIE(const NormalizedFile &normalizedFile,
uint64_t augmentationStringField = versionField + sizeof(uint8_t);
if (auto err = processAugmentationString(frameData + augmentationStringField,
adi))
cieInfo))
return err;
cieInfos[atom] = std::move(cieInfo);
return std::error_code();
}
@ -708,7 +714,7 @@ static std::error_code processFDE(const NormalizedFile &normalizedFile,
const Section *ehFrameSection,
MachODefinedAtom *atom,
uint64_t offset,
const AugmentationDataInfo &adi) {
const CIEInfoMap &cieInfos) {
const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
@ -730,11 +736,16 @@ static std::error_code processFDE(const NormalizedFile &normalizedFile,
cieAddress -= cieDelta;
Reference::Addend addend;
const Atom *cie =
const MachODefinedAtom *cie =
findAtomCoveringAddress(normalizedFile, file, cieAddress, &addend);
atom->addReference(cieFieldInFDE, handler.unwindRefToCIEKind(), cie,
addend, handler.kindArch());
assert(cie && cie->contentType() == DefinedAtom::typeCFI && !addend &&
"FDE's CIE field does not point at the start of a CIE.");
const CIEInfo &cieInfo = cieInfos.find(cie)->second;
// Linker needs to fixup reference from the FDE to the function it's
// describing. FIXME: there are actually different ways to do this, and the
// particular method used is specified in the CIE's augmentation fields
@ -752,7 +763,7 @@ static std::error_code processFDE(const NormalizedFile &normalizedFile,
func, addend, handler.kindArch());
// Handle the augmentation data if there is any.
if (adi._present) {
if (cieInfo._augmentationDataPresent) {
// First process the augmentation data length field.
uint64_t augmentationDataLengthFieldInFDE =
rangeFieldInFDE + 2 * (is64 ? sizeof(uint64_t) : sizeof(uint32_t));
@ -761,7 +772,7 @@ static std::error_code processFDE(const NormalizedFile &normalizedFile,
llvm::decodeULEB128(frameData + augmentationDataLengthFieldInFDE,
&lengthFieldSize);
if (adi._mayHaveLSDA && augmentationDataLength > 0) {
if (cieInfo._mayHaveLSDA && augmentationDataLength > 0) {
// Look at the augmentation data field.
uint64_t augmentationDataFieldInFDE =
@ -800,7 +811,7 @@ std::error_code addEHFrameReferences(const NormalizedFile &normalizedFile,
return std::error_code();
std::error_code ehFrameErr;
AugmentationDataInfo adi;
CIEInfoMap cieInfos;
file.eachAtomInSection(*ehFrameSection,
[&](MachODefinedAtom *atom, uint64_t offset) -> void {
@ -811,12 +822,11 @@ std::error_code addEHFrameReferences(const NormalizedFile &normalizedFile,
return;
const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
if (ArchHandler::isDwarfCIE(isBig, atom)) {
adi = AugmentationDataInfo();
ehFrameErr = processCIE(normalizedFile, atom, adi);
} else
if (ArchHandler::isDwarfCIE(isBig, atom))
ehFrameErr = processCIE(normalizedFile, atom, cieInfos);
else
ehFrameErr = processFDE(normalizedFile, file, handler, ehFrameSection,
atom, offset, adi);
atom, offset, cieInfos);
});
return ehFrameErr;

View File

@ -1,83 +1,110 @@
# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
#
# Test parsing of x86_64 __eh_frame (dwarf unwind) relocations.
#
#_catchMyException:
# pushq %rbp
# movq %rsp, %rbp
# callq _foo
# popq %rbp
# retq
# movq %rax, %rdi
# callq ___cxa_begin_catch
# popq %rbp
# jmp ___cxa_end_catch
--- !mach-o
arch: x86_64
file-type: MH_OBJECT
flags: [ ]
flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
compat-version: 0.0
current-version: 0.0
has-UUID: false
OS: unknown
sections:
- segment: __TEXT
section: __text
type: S_REGULAR
attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
alignment: 16
address: 0x0000000000000000
content: [0x55, 0x48, 0x89, 0xe5, 0xe8, 0x00, 0x00, 0x00,
0x00, 0x5d, 0xc3, 0x48, 0x89, 0xc7, 0xe8, 0x00,
0x00, 0x00, 0x00, 0x5d, 0xe9, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 ]
relocations:
- offset: 0x00000015
type: X86_64_RELOC_BRANCH
length: 2
pc-rel: true
extern: true
symbol: 2
- offset: 0x0000000f
type: X86_64_RELOC_BRANCH
length: 2
pc-rel: true
extern: true
symbol: 1
- offset: 0x00000005
type: X86_64_RELOC_BRANCH
length: 2
pc-rel: true
extern: true
symbol: 0
content: [ 0x55, 0x48, 0x89, 0xE5, 0xE8, 0x00, 0x00, 0x00,
0x00, 0x5D, 0xC3, 0x48, 0x89, 0xC7, 0xE8, 0x00,
0x00, 0x00, 0x00, 0x5D, 0xE9, 0x00, 0x00, 0x00,
0x00, 0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00,
0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3, 0x66, 0x2E,
0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
0x55, 0x48, 0x89, 0xE5, 0xE8, 0x00, 0x00, 0x00,
0x00, 0x5D, 0xC3, 0x48, 0x89, 0xC7, 0xE8, 0x00,
0x00, 0x00, 0x00, 0x5D, 0xE9, 0x00, 0x00, 0x00,
0x00 ]
- segment: __TEXT
section: __gcc_except_tab
type: S_REGULAR
attributes: [ ]
address: 0x000000000000001c
content: [ 0x00, 0x00, 0x00, 0x00 ]
alignment: 4
address: 0x000000000000004C
content: [ 0xFF, 0x9B, 0xA2, 0x80, 0x80, 0x00, 0x03, 0x1A,
0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x01, 0x09, 0x00, 0x00,
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0x9B, 0xA2, 0x80, 0x80, 0x00, 0x03, 0x1A,
0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x01, 0x09, 0x00, 0x00,
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 ]
- segment: __TEXT
section: __eh_frame
type: S_COALESCED
attributes: [ ]
address: 0x0000000000000020
content: [ 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x7a, 0x50, 0x4c, 0x52, 0x00, 0x01, 0x78,
0x10, 0x07, 0x9b, 0x04, 0x00, 0x00, 0x00, 0x10,
0x10, 0x0c, 0x07, 0x08, 0x90, 0x01, 0x00, 0x00,
0x2c, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
0xB8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
alignment: 8
address: 0x0000000000000100
content: [ 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x7A, 0x50, 0x4C, 0x52, 0x00, 0x01, 0x78,
0x10, 0x07, 0x9B, 0x04, 0x00, 0x00, 0x00, 0x10,
0x10, 0x0C, 0x07, 0x08, 0x90, 0x01, 0x00, 0x00,
0x2C, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
0xD8, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x41, 0x0e, 0x10, 0x86, 0x02, 0x43, 0x0d,
0x08, 0x13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D,
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x7A, 0x52, 0x00, 0x01, 0x78, 0x10, 0x01,
0x10, 0x0C, 0x07, 0x08, 0x90, 0x01, 0x00, 0x00,
0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
0xB0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D,
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2C, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00,
0x98, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0xCB, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D,
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
- segment: __DATA
section: __data
type: S_REGULAR
attributes: [ ]
address: 0x0000000000000068
content: [ 0x00, 0x00, 0x00, 0x00 ]
relocations:
- offset: 0x00000013
type: X86_64_RELOC_GOT
length: 2
pc-rel: true
extern: true
symbol: 8
local-symbols:
- name: _catchMyException
- name: GCC_except_table0
type: N_SECT
sect: 2
value: 0x000000000000004C
- name: GCC_except_table2
type: N_SECT
sect: 2
value: 0x0000000000000074
global-symbols:
- name: _catchMyException1
type: N_SECT
scope: [ N_EXT ]
sect: 1
value: 0x0000000000000000
- name: _catchMyException2
type: N_SECT
scope: [ N_EXT ]
sect: 1
value: 0x0000000000000030
- name: _bar
type: N_SECT
scope: [ N_EXT ]
sect: 1
value: 0x0000000000000020
undefined-symbols:
- name: _foo
type: N_UNDF
@ -91,17 +118,59 @@ undefined-symbols:
type: N_UNDF
scope: [ N_EXT ]
value: 0x0000000000000000
- name: ___gxx_personality_v0
type: N_UNDF
scope: [ N_EXT ]
value: 0x0000000000000000
page-size: 0x00000000
...
# Check that LSDA fields are fixed up correctly, even when there are multiple
# CIEs involved.
#
# (1) Check that we can relocate an LSDA at all. Requires correct interpretation
# of augmentation data strings in CIEs and augmentation data fields of FDEs.
#
# CHECK: - type: unwind-cfi
# CHECK-NOT: - type:
# CHECK: references:
# CHECK-NEXT: - kind: negDelta32
# CHECK-NEXT: offset: 4
# CHECK-NEXT: target: L000
# CHECK-NEXT: target: L002
# CHECK-NEXT: - kind: unwindFDEToFunction
# CHECK-NEXT: offset: 8
# CHECK-NEXT: target: _catchMyException
# CHECK-NEXT: target: _catchMyException1
# CHECK-NEXT: - kind: unwindFDEToFunction
# CHECK-NEXT: offset: 25
# CHECK-NEXT: target: GCC_except_table0
#
# (2) Check that we have an intervening FDE with a different CIE.
# If the test fails here then test (3) probably isn't testing what it
# should, and this test-case should be updated.
#
# CHECK: - type: unwind-cfi
# CHECK-NOT: - type:
# CHECK: references:
# CHECK-NEXT: - kind: negDelta32
# CHECK-NEXT: offset: 4
# CHECK-NEXT: target: L001
# CHECK-NEXT: - kind: unwindFDEToFunction
# CHECK-NEXT: offset: 8
# CHECK-NEXT: target: _bar
#
# (3) Check that we can relocate the LSDA on a second FDE that references the
# original CIE from (1). Requires us to match this FDE up with the correct
# CIE.
#
# CHECK-NEXT: - type: unwind-cfi
# CHECK-NOT: - type:
# CHECK: references:
# CHECK-NEXT: - kind: negDelta32
# CHECK-NEXT: offset: 4
# CHECK-NEXT: target: L002
# CHECK-NEXT: - kind: unwindFDEToFunction
# CHECK-NEXT: offset: 8
# CHECK-NEXT: target: _catchMyException2
# CHECK-NEXT: - kind: unwindFDEToFunction
# CHECK-NEXT: offset: 25
# CHECK-NEXT: target: GCC_except_table2