Skip to content

Commit 6884fbc

Browse files
committed
[JITLink] Enable exception handling for ELF.
Adds the EHFrameSplitter and EHFrameEdgeFixer passes to the default JITLink pass pipeline for ELF/x86-64, and teaches EHFrameEdgeFixer to handle some new pointer encodings. Together these changes enable exception handling (at least for the basic cases that I've tested so far) for ELF/x86-64 objects loaded via JITLink.
1 parent ffc3e80 commit 6884fbc

File tree

6 files changed

+305
-65
lines changed

6 files changed

+305
-65
lines changed

llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp

Lines changed: 142 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,10 @@ Error EHFrameSplitter::processBlock(LinkGraph &G, Block &B,
119119
}
120120

121121
EHFrameEdgeFixer::EHFrameEdgeFixer(StringRef EHFrameSectionName,
122-
Edge::Kind Delta64, Edge::Kind NegDelta32)
123-
: EHFrameSectionName(EHFrameSectionName), Delta64(Delta64),
124-
NegDelta32(NegDelta32) {}
122+
unsigned PointerSize, Edge::Kind Delta64,
123+
Edge::Kind Delta32, Edge::Kind NegDelta32)
124+
: EHFrameSectionName(EHFrameSectionName), PointerSize(PointerSize),
125+
Delta64(Delta64), Delta32(Delta32), NegDelta32(NegDelta32) {}
125126

126127
Error EHFrameEdgeFixer::operator()(LinkGraph &G) {
127128
auto *EHFrame = G.findSectionByName(EHFrameSectionName);
@@ -134,6 +135,11 @@ Error EHFrameEdgeFixer::operator()(LinkGraph &G) {
134135
return Error::success();
135136
}
136137

138+
// Check that we support the graph's pointer size.
139+
if (G.getPointerSize() != 4 && G.getPointerSize() != 8)
140+
return make_error<JITLinkError>(
141+
"EHFrameEdgeFixer only supports 32 and 64 bit targets");
142+
137143
LLVM_DEBUG({
138144
dbgs() << "EHFrameEdgeFixer: Processing " << EHFrameSectionName << "...\n";
139145
});
@@ -258,7 +264,6 @@ Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {
258264
Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B,
259265
size_t RecordOffset, size_t RecordLength,
260266
size_t CIEDeltaFieldOffset) {
261-
using namespace dwarf;
262267

263268
LLVM_DEBUG(dbgs() << " Record is CIE\n");
264269

@@ -329,19 +334,21 @@ Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B,
329334
uint8_t LSDAPointerEncoding;
330335
if (auto Err = RecordReader.readInteger(LSDAPointerEncoding))
331336
return Err;
332-
if (LSDAPointerEncoding != (DW_EH_PE_pcrel | DW_EH_PE_absptr))
337+
if (!isSupportedPointerEncoding(LSDAPointerEncoding))
333338
return make_error<JITLinkError>(
334339
"Unsupported LSDA pointer encoding " +
335340
formatv("{0:x2}", LSDAPointerEncoding) + " in CIE at " +
336341
formatv("{0:x16}", CIESymbol.getAddress()));
342+
CIEInfo.LSDAPointerEncoding = LSDAPointerEncoding;
337343
break;
338344
}
339345
case 'P': {
340346
uint8_t PersonalityPointerEncoding = 0;
341347
if (auto Err = RecordReader.readInteger(PersonalityPointerEncoding))
342348
return Err;
343349
if (PersonalityPointerEncoding !=
344-
(DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4))
350+
(dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
351+
dwarf::DW_EH_PE_sdata4))
345352
return make_error<JITLinkError>(
346353
"Unspported personality pointer "
347354
"encoding " +
@@ -356,12 +363,12 @@ Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B,
356363
uint8_t FDEPointerEncoding;
357364
if (auto Err = RecordReader.readInteger(FDEPointerEncoding))
358365
return Err;
359-
if (FDEPointerEncoding != (DW_EH_PE_pcrel | DW_EH_PE_absptr))
366+
if (!isSupportedPointerEncoding(FDEPointerEncoding))
360367
return make_error<JITLinkError>(
361-
"Unsupported FDE address pointer "
362-
"encoding " +
368+
"Unsupported FDE pointer encoding " +
363369
formatv("{0:x2}", FDEPointerEncoding) + " in CIE at " +
364370
formatv("{0:x16}", CIESymbol.getAddress()));
371+
CIEInfo.FDEPointerEncoding = FDEPointerEncoding;
365372
break;
366373
}
367374
default:
@@ -445,11 +452,13 @@ Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
445452
JITTargetAddress PCBeginFieldOffset = RecordReader.getOffset();
446453
auto PCEdgeItr = BlockEdges.find(RecordOffset + PCBeginFieldOffset);
447454
if (PCEdgeItr == BlockEdges.end()) {
448-
auto PCBeginDelta = readAbsolutePointer(PC.G, RecordReader);
449-
if (!PCBeginDelta)
450-
return PCBeginDelta.takeError();
451-
JITTargetAddress PCBegin =
452-
RecordAddress + PCBeginFieldOffset + *PCBeginDelta;
455+
auto PCBeginPtrInfo =
456+
readEncodedPointer(CIEInfo->FDEPointerEncoding,
457+
RecordAddress + PCBeginFieldOffset, RecordReader);
458+
if (!PCBeginPtrInfo)
459+
return PCBeginPtrInfo.takeError();
460+
JITTargetAddress PCBegin = PCBeginPtrInfo->first;
461+
Edge::Kind PCBeginEdgeKind = PCBeginPtrInfo->second;
453462
LLVM_DEBUG({
454463
dbgs() << " Adding edge at "
455464
<< formatv("{0:x16}", RecordAddress + PCBeginFieldOffset)
@@ -458,7 +467,8 @@ Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
458467
auto PCBeginSym = getOrCreateSymbol(PC, PCBegin);
459468
if (!PCBeginSym)
460469
return PCBeginSym.takeError();
461-
B.addEdge(Delta64, RecordOffset + PCBeginFieldOffset, *PCBeginSym, 0);
470+
B.addEdge(PCBeginEdgeKind, RecordOffset + PCBeginFieldOffset, *PCBeginSym,
471+
0);
462472
PCBeginBlock = &PCBeginSym->getBlock();
463473
} else {
464474
auto &EI = PCEdgeItr->second;
@@ -479,38 +489,42 @@ Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
479489
" points at external block");
480490
}
481491
PCBeginBlock = &EI.Target->getBlock();
482-
if (auto Err = RecordReader.skip(PC.G.getPointerSize()))
492+
if (auto Err = RecordReader.skip(
493+
getPointerEncodingDataSize(CIEInfo->FDEPointerEncoding)))
483494
return Err;
484495
}
485496

486497
// Add a keep-alive edge from the FDE target to the FDE to ensure that the
487498
// FDE is kept alive if its target is.
488499
assert(PCBeginBlock && "PC-begin block not recorded");
500+
LLVM_DEBUG({
501+
dbgs() << " Adding keep-alive edge from target at "
502+
<< formatv("{0:x16}", PCBeginBlock->getAddress()) << " to FDE at "
503+
<< formatv("{0:x16}", RecordAddress) << "\n";
504+
});
489505
PCBeginBlock->addEdge(Edge::KeepAlive, 0, FDESymbol, 0);
490506
}
491507

492508
// Skip over the PC range size field.
493-
if (auto Err = RecordReader.skip(PC.G.getPointerSize()))
509+
if (auto Err = RecordReader.skip(
510+
getPointerEncodingDataSize(CIEInfo->FDEPointerEncoding)))
494511
return Err;
495512

496513
if (CIEInfo->FDEsHaveLSDAField) {
497514
uint64_t AugmentationDataSize;
498515
if (auto Err = RecordReader.readULEB128(AugmentationDataSize))
499516
return Err;
500-
if (AugmentationDataSize != PC.G.getPointerSize())
501-
return make_error<JITLinkError>(
502-
"Unexpected FDE augmentation data size (expected " +
503-
Twine(PC.G.getPointerSize()) + ", got " +
504-
Twine(AugmentationDataSize) + ") for FDE at " +
505-
formatv("{0:x16}", RecordAddress));
506517

507518
JITTargetAddress LSDAFieldOffset = RecordReader.getOffset();
508519
auto LSDAEdgeItr = BlockEdges.find(RecordOffset + LSDAFieldOffset);
509520
if (LSDAEdgeItr == BlockEdges.end()) {
510-
auto LSDADelta = readAbsolutePointer(PC.G, RecordReader);
511-
if (!LSDADelta)
512-
return LSDADelta.takeError();
513-
JITTargetAddress LSDA = RecordAddress + LSDAFieldOffset + *LSDADelta;
521+
auto LSDAPointerInfo =
522+
readEncodedPointer(CIEInfo->LSDAPointerEncoding,
523+
RecordAddress + LSDAFieldOffset, RecordReader);
524+
if (!LSDAPointerInfo)
525+
return LSDAPointerInfo.takeError();
526+
JITTargetAddress LSDA = LSDAPointerInfo->first;
527+
Edge::Kind LSDAEdgeKind = LSDAPointerInfo->second;
514528
auto LSDASym = getOrCreateSymbol(PC, LSDA);
515529
if (!LSDASym)
516530
return LSDASym.takeError();
@@ -519,7 +533,7 @@ Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
519533
<< formatv("{0:x16}", RecordAddress + LSDAFieldOffset)
520534
<< " to LSDA at " << formatv("{0:x16}", LSDA) << "\n";
521535
});
522-
B.addEdge(Delta64, RecordOffset + LSDAFieldOffset, *LSDASym, 0);
536+
B.addEdge(LSDAEdgeKind, RecordOffset + LSDAFieldOffset, *LSDASym, 0);
523537
} else {
524538
LLVM_DEBUG({
525539
auto &EI = LSDAEdgeItr->second;
@@ -530,7 +544,7 @@ Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
530544
dbgs() << " + " << formatv("{0:x16}", EI.Addend);
531545
dbgs() << "\n";
532546
});
533-
if (auto Err = RecordReader.skip(PC.G.getPointerSize()))
547+
if (auto Err = RecordReader.skip(AugmentationDataSize))
534548
return Err;
535549
}
536550
} else {
@@ -581,23 +595,110 @@ EHFrameEdgeFixer::parseAugmentationString(BinaryStreamReader &RecordReader) {
581595
return std::move(AugInfo);
582596
}
583597

584-
Expected<JITTargetAddress>
585-
EHFrameEdgeFixer::readAbsolutePointer(LinkGraph &G,
586-
BinaryStreamReader &RecordReader) {
598+
bool EHFrameEdgeFixer::isSupportedPointerEncoding(uint8_t PointerEncoding) {
599+
using namespace dwarf;
600+
601+
// We only support PC-rel for now.
602+
if ((PointerEncoding & 0x70) != DW_EH_PE_pcrel)
603+
return false;
604+
605+
// readEncodedPointer does not handle indirect.
606+
if (PointerEncoding & DW_EH_PE_indirect)
607+
return false;
608+
609+
// Supported datatypes.
610+
switch (PointerEncoding & 0xf) {
611+
case DW_EH_PE_absptr:
612+
case DW_EH_PE_udata4:
613+
case DW_EH_PE_udata8:
614+
case DW_EH_PE_sdata4:
615+
case DW_EH_PE_sdata8:
616+
return true;
617+
}
618+
619+
return false;
620+
}
621+
622+
unsigned EHFrameEdgeFixer::getPointerEncodingDataSize(uint8_t PointerEncoding) {
623+
using namespace dwarf;
624+
625+
assert(isSupportedPointerEncoding(PointerEncoding) &&
626+
"Unsupported pointer encoding");
627+
switch (PointerEncoding & 0xf) {
628+
case DW_EH_PE_absptr:
629+
return PointerSize;
630+
case DW_EH_PE_udata4:
631+
case DW_EH_PE_sdata4:
632+
return 4;
633+
case DW_EH_PE_udata8:
634+
case DW_EH_PE_sdata8:
635+
return 8;
636+
default:
637+
llvm_unreachable("Unsupported encoding");
638+
}
639+
}
640+
641+
Expected<std::pair<JITTargetAddress, Edge::Kind>>
642+
EHFrameEdgeFixer::readEncodedPointer(uint8_t PointerEncoding,
643+
JITTargetAddress PointerFieldAddress,
644+
BinaryStreamReader &RecordReader) {
587645
static_assert(sizeof(JITTargetAddress) == sizeof(uint64_t),
588646
"Result must be able to hold a uint64_t");
647+
assert(isSupportedPointerEncoding(PointerEncoding) &&
648+
"Unsupported pointer encoding");
649+
650+
using namespace dwarf;
651+
652+
// Isolate data type, remap absptr to udata4 or udata8. This relies on us
653+
// having verified that the graph uses 32-bit or 64-bit pointers only at the
654+
// start of this pass.
655+
uint8_t EffectiveType = PointerEncoding & 0xf;
656+
if (EffectiveType == DW_EH_PE_absptr)
657+
EffectiveType = (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4;
658+
589659
JITTargetAddress Addr;
590-
if (G.getPointerSize() == 8) {
591-
if (auto Err = RecordReader.readInteger(Addr))
660+
Edge::Kind PointerEdgeKind;
661+
switch (EffectiveType) {
662+
case DW_EH_PE_udata4: {
663+
uint32_t Val;
664+
if (auto Err = RecordReader.readInteger(Val))
592665
return std::move(Err);
593-
} else if (G.getPointerSize() == 4) {
594-
uint32_t Addr32;
595-
if (auto Err = RecordReader.readInteger(Addr32))
666+
Addr = PointerFieldAddress + Val;
667+
PointerEdgeKind = Delta32;
668+
break;
669+
}
670+
case DW_EH_PE_udata8: {
671+
uint64_t Val;
672+
if (auto Err = RecordReader.readInteger(Val))
596673
return std::move(Err);
597-
Addr = Addr32;
598-
} else
599-
llvm_unreachable("Pointer size is not 32-bit or 64-bit");
600-
return Addr;
674+
Addr = PointerFieldAddress + Val;
675+
PointerEdgeKind = Delta64;
676+
break;
677+
}
678+
case DW_EH_PE_sdata4: {
679+
int32_t Val;
680+
if (auto Err = RecordReader.readInteger(Val))
681+
return std::move(Err);
682+
Addr = PointerFieldAddress + Val;
683+
PointerEdgeKind = Delta32;
684+
break;
685+
}
686+
case DW_EH_PE_sdata8: {
687+
int64_t Val;
688+
if (auto Err = RecordReader.readInteger(Val))
689+
return std::move(Err);
690+
Addr = PointerFieldAddress + Val;
691+
PointerEdgeKind = Delta64;
692+
break;
693+
}
694+
}
695+
696+
if (PointerEdgeKind == Edge::Invalid)
697+
return make_error<JITLinkError>(
698+
"Unspported edge kind for encoded pointer at " +
699+
formatv("{0:x}", PointerFieldAddress));
700+
701+
return std::make_pair(Addr, Delta64);
601702
}
602703

603704
Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC,

llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ class EHFrameSplitter {
4040
/// edges.
4141
class EHFrameEdgeFixer {
4242
public:
43-
EHFrameEdgeFixer(StringRef EHFrameSectionName, Edge::Kind Delta64,
43+
EHFrameEdgeFixer(StringRef EHFrameSectionName, unsigned PointerSize,
44+
Edge::Kind Delta64, Edge::Kind Delta32,
4445
Edge::Kind NegDelta32);
4546
Error operator()(LinkGraph &G);
4647

@@ -57,6 +58,8 @@ class EHFrameEdgeFixer {
5758
CIEInformation(Symbol &CIESymbol) : CIESymbol(&CIESymbol) {}
5859
Symbol *CIESymbol = nullptr;
5960
bool FDEsHaveLSDAField = false;
61+
uint8_t FDEPointerEncoding = 0;
62+
uint8_t LSDAPointerEncoding = 0;
6063
};
6164

6265
struct EdgeTarget {
@@ -96,12 +99,20 @@ class EHFrameEdgeFixer {
9699

97100
Expected<AugmentationInfo>
98101
parseAugmentationString(BinaryStreamReader &RecordReader);
99-
Expected<JITTargetAddress>
100-
readAbsolutePointer(LinkGraph &G, BinaryStreamReader &RecordReader);
102+
103+
static bool isSupportedPointerEncoding(uint8_t PointerEncoding);
104+
unsigned getPointerEncodingDataSize(uint8_t PointerEncoding);
105+
Expected<std::pair<JITTargetAddress, Edge::Kind>>
106+
readEncodedPointer(uint8_t PointerEncoding,
107+
JITTargetAddress PointerFieldAddress,
108+
BinaryStreamReader &RecordReader);
109+
101110
Expected<Symbol &> getOrCreateSymbol(ParseContext &PC, JITTargetAddress Addr);
102111

103112
StringRef EHFrameSectionName;
113+
unsigned PointerSize;
104114
Edge::Kind Delta64;
115+
Edge::Kind Delta32;
105116
Edge::Kind NegDelta32;
106117
};
107118

0 commit comments

Comments
 (0)