mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-10 10:01:42 +00:00
[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:
parent
e2eb3a5300
commit
3d2911f5cd
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user