ELF: Simplify getFdeEncoding.

I found that the handling of 'L' character in an augmentation string is
wrong because 'L' means that the next byte is the length field. I could
have fixed that by just skipping the next byte, but I decided to take a
different approach.

Teaching the linker about all the types of CIE internal records just to
skip them is silly. And the code doing that is not actually executed now
(that's why the bug did not cause any issue.) It is because the 'R' field,
which we want to read, is always at beginning of the CIE. So I reduced
the code dramatically by assuming that that's always the case. I want to
see how it works in the wild. If it doesn't work, we can roll this back
(with a fix for 'L').

http://reviews.llvm.org/D16939

llvm-svn: 260073
This commit is contained in:
Rui Ueyama 2016-02-08 05:18:44 +00:00
parent b4fd8bb27e
commit be748c2033

View File

@ -881,34 +881,10 @@ static void skipLeb128(ArrayRef<uint8_t> &D) {
fatal("corrupted or unsupported CIE information");
}
template <class ELFT> static unsigned getSizeForEncoding(unsigned Enc) {
typedef typename ELFFile<ELFT>::uintX_t uintX_t;
switch (Enc & 0x0f) {
default:
fatal("unknown FDE encoding");
case dwarf::DW_EH_PE_absptr:
case dwarf::DW_EH_PE_signed:
return sizeof(uintX_t);
case dwarf::DW_EH_PE_udata2:
case dwarf::DW_EH_PE_sdata2:
return 2;
case dwarf::DW_EH_PE_udata4:
case dwarf::DW_EH_PE_sdata4:
return 4;
case dwarf::DW_EH_PE_udata8:
case dwarf::DW_EH_PE_sdata8:
return 8;
}
}
template <class ELFT>
uint8_t EHOutputSection<ELFT>::getFdeEncoding(ArrayRef<uint8_t> D) {
auto Check = [](bool C) {
if (!C)
fatal("corrupted or unsupported CIE information");
};
Check(D.size() >= 8);
if (D.size() < 8)
fatal("CIE too small");
D = D.slice(8);
uint8_t Version = readByte(D);
@ -916,14 +892,16 @@ uint8_t EHOutputSection<ELFT>::getFdeEncoding(ArrayRef<uint8_t> D) {
fatal("FDE version 1 or 3 expected, but got " + Twine((unsigned)Version));
auto AugEnd = std::find(D.begin() + 1, D.end(), '\0');
Check(AugEnd != D.end());
ArrayRef<uint8_t> AugString(D.begin(), AugEnd - D.begin());
D = D.slice(AugString.size() + 1);
if (AugEnd == D.end())
fatal("corrupted CIE");
StringRef Aug((char *)D.begin(), AugEnd - D.begin());
D = D.slice(Aug.size() + 1);
// Code alignment factor should always be 1 for .eh_frame.
if (readByte(D) != 1)
fatal("CIE code alignment must be 1");
// Skip data alignment factor
// Skip data alignment factor.
skipLeb128(D);
// Skip the return address register. In CIE version 1 this is a single
@ -933,34 +911,13 @@ uint8_t EHOutputSection<ELFT>::getFdeEncoding(ArrayRef<uint8_t> D) {
else
skipLeb128(D);
while (!AugString.empty()) {
switch (readByte(AugString)) {
case 'z':
skipLeb128(D);
break;
case 'R':
return readByte(D);
case 'P': {
uint8_t Enc = readByte(D);
if ((Enc & 0xf0) == dwarf::DW_EH_PE_aligned)
fatal("DW_EH_PE_aligned encoding for address of a personality routine "
"handler not supported");
unsigned EncSize = getSizeForEncoding<ELFT>(Enc);
Check(D.size() >= EncSize);
D = D.slice(EncSize);
break;
}
case 'S':
case 'L':
// L: Language Specific Data Area (LSDA) encoding
// S: This CIE represents a stack frame for the invocation of a signal
// handler
break;
default:
fatal("unknown .eh_frame augmentation string value");
}
}
return dwarf::DW_EH_PE_absptr;
// We assume that the augmentation string always starts with 'z'
// (which specifies the size of the CIE field) and 'R' (which
// specifies the FDE encoding.)
if (!Aug.startswith("zR"))
fatal("unknown .eh_frame augmentation string: " + Aug);
skipLeb128(D);
return readByte(D);
}
template <class ELFT>