141 lines · cpp
1//===- EhFrame.cpp --------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "EhFrame.h"10#include "InputFiles.h"11 12#include "lld/Common/ErrorHandler.h"13#include "llvm/BinaryFormat/Dwarf.h"14#include "llvm/Support/Endian.h"15 16using namespace llvm;17using namespace lld;18using namespace lld::macho;19using namespace llvm::support::endian;20 21uint64_t EhReader::readLength(size_t *off) const {22 const size_t errOff = *off;23 if (*off + 4 > data.size())24 failOn(errOff, "CIE/FDE too small");25 uint64_t len = read32le(data.data() + *off);26 *off += 4;27 if (len == dwarf::DW_LENGTH_DWARF64) {28 // FIXME: test this DWARF64 code path29 if (*off + 8 > data.size())30 failOn(errOff, "CIE/FDE too small");31 len = read64le(data.data() + *off);32 *off += 8;33 }34 if (*off + len > data.size())35 failOn(errOff, "CIE/FDE extends past the end of the section");36 return len;37}38 39void EhReader::skipValidLength(size_t *off) const {40 uint32_t len = read32le(data.data() + *off);41 *off += 4;42 if (len == dwarf::DW_LENGTH_DWARF64)43 *off += 8;44}45 46// Read a byte and advance off by one byte.47uint8_t EhReader::readByte(size_t *off) const {48 if (*off + 1 > data.size())49 failOn(*off, "unexpected end of CIE/FDE");50 return data[(*off)++];51}52 53uint32_t EhReader::readU32(size_t *off) const {54 if (*off + 4 > data.size())55 failOn(*off, "unexpected end of CIE/FDE");56 uint32_t v = read32le(data.data() + *off);57 *off += 4;58 return v;59}60 61uint64_t EhReader::readPointer(size_t *off, uint8_t size) const {62 if (*off + size > data.size())63 failOn(*off, "unexpected end of CIE/FDE");64 uint64_t v;65 if (size == 8)66 v = read64le(data.data() + *off);67 else {68 assert(size == 4);69 v = read32le(data.data() + *off);70 }71 *off += size;72 return v;73}74 75// Read a null-terminated string.76StringRef EhReader::readString(size_t *off) const {77 if (*off > data.size())78 failOn(*off, "corrupted CIE (failed to read string)");79 const size_t maxlen = data.size() - *off;80 auto *c = reinterpret_cast<const char *>(data.data() + *off);81 size_t len = strnlen(c, maxlen);82 if (len == maxlen) // we failed to find the null terminator83 failOn(*off, "corrupted CIE (failed to read string)");84 *off += len + 1; // skip the null byte too85 return StringRef(c, len);86}87 88void EhReader::skipLeb128(size_t *off) const {89 const size_t errOff = *off;90 while (*off < data.size()) {91 uint8_t val = data[(*off)++];92 if ((val & 0x80) == 0)93 return;94 }95 failOn(errOff, "corrupted CIE (failed to read LEB128)");96}97 98void EhReader::failOn(size_t errOff, const Twine &msg) const {99 fatal(toString(file) + ":(__eh_frame+0x" +100 Twine::utohexstr(dataOff + errOff) + "): " + msg);101}102 103/*104 * Create a pair of relocs to write the value of:105 * `b - (offset + a)` if Invert == false106 * `(a + offset) - b` if Invert == true107 */108template <bool Invert = false>109static void createSubtraction(PointerUnion<Symbol *, InputSection *> a,110 PointerUnion<Symbol *, InputSection *> b,111 uint64_t off, uint8_t length,112 SmallVectorImpl<Reloc> *newRelocs) {113 auto subtrahend = a;114 auto minuend = b;115 if (Invert)116 std::swap(subtrahend, minuend);117 assert(isa<Symbol *>(subtrahend));118 Reloc subtrahendReloc(target->subtractorRelocType, /*pcrel=*/false, length,119 off, /*addend=*/0, subtrahend);120 Reloc minuendReloc(target->unsignedRelocType, /*pcrel=*/false, length, off,121 (Invert ? 1 : -1) * off, minuend);122 newRelocs->push_back(subtrahendReloc);123 newRelocs->push_back(minuendReloc);124}125 126void EhRelocator::makePcRel(uint64_t off,127 PointerUnion<Symbol *, InputSection *> target,128 uint8_t length) {129 createSubtraction(isec->symbols[0], target, off, length, &newRelocs);130}131 132void EhRelocator::makeNegativePcRel(133 uint64_t off, PointerUnion<Symbol *, InputSection *> target,134 uint8_t length) {135 createSubtraction</*Invert=*/true>(isec, target, off, length, &newRelocs);136}137 138void EhRelocator::commit() {139 isec->relocs.insert(isec->relocs.end(), newRelocs.begin(), newRelocs.end());140}141