Path: blob/main/contrib/llvm-project/lld/MachO/EhFrame.cpp
34878 views
//===- EhFrame.cpp --------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "EhFrame.h"9#include "InputFiles.h"1011#include "lld/Common/ErrorHandler.h"12#include "llvm/BinaryFormat/Dwarf.h"13#include "llvm/Support/Endian.h"1415using namespace llvm;16using namespace lld;17using namespace lld::macho;18using namespace llvm::support::endian;1920uint64_t EhReader::readLength(size_t *off) const {21const size_t errOff = *off;22if (*off + 4 > data.size())23failOn(errOff, "CIE/FDE too small");24uint64_t len = read32le(data.data() + *off);25*off += 4;26if (len == dwarf::DW_LENGTH_DWARF64) {27// FIXME: test this DWARF64 code path28if (*off + 8 > data.size())29failOn(errOff, "CIE/FDE too small");30len = read64le(data.data() + *off);31*off += 8;32}33if (*off + len > data.size())34failOn(errOff, "CIE/FDE extends past the end of the section");35return len;36}3738void EhReader::skipValidLength(size_t *off) const {39uint32_t len = read32le(data.data() + *off);40*off += 4;41if (len == dwarf::DW_LENGTH_DWARF64)42*off += 8;43}4445// Read a byte and advance off by one byte.46uint8_t EhReader::readByte(size_t *off) const {47if (*off + 1 > data.size())48failOn(*off, "unexpected end of CIE/FDE");49return data[(*off)++];50}5152uint32_t EhReader::readU32(size_t *off) const {53if (*off + 4 > data.size())54failOn(*off, "unexpected end of CIE/FDE");55uint32_t v = read32le(data.data() + *off);56*off += 4;57return v;58}5960uint64_t EhReader::readPointer(size_t *off, uint8_t size) const {61if (*off + size > data.size())62failOn(*off, "unexpected end of CIE/FDE");63uint64_t v;64if (size == 8)65v = read64le(data.data() + *off);66else {67assert(size == 4);68v = read32le(data.data() + *off);69}70*off += size;71return v;72}7374// Read a null-terminated string.75StringRef EhReader::readString(size_t *off) const {76if (*off > data.size())77failOn(*off, "corrupted CIE (failed to read string)");78const size_t maxlen = data.size() - *off;79auto *c = reinterpret_cast<const char *>(data.data() + *off);80size_t len = strnlen(c, maxlen);81if (len == maxlen) // we failed to find the null terminator82failOn(*off, "corrupted CIE (failed to read string)");83*off += len + 1; // skip the null byte too84return StringRef(c, len);85}8687void EhReader::skipLeb128(size_t *off) const {88const size_t errOff = *off;89while (*off < data.size()) {90uint8_t val = data[(*off)++];91if ((val & 0x80) == 0)92return;93}94failOn(errOff, "corrupted CIE (failed to read LEB128)");95}9697void EhReader::failOn(size_t errOff, const Twine &msg) const {98fatal(toString(file) + ":(__eh_frame+0x" +99Twine::utohexstr(dataOff + errOff) + "): " + msg);100}101102/*103* Create a pair of relocs to write the value of:104* `b - (offset + a)` if Invert == false105* `(a + offset) - b` if Invert == true106*/107template <bool Invert = false>108static void createSubtraction(PointerUnion<Symbol *, InputSection *> a,109PointerUnion<Symbol *, InputSection *> b,110uint64_t off, uint8_t length,111SmallVectorImpl<Reloc> *newRelocs) {112auto subtrahend = a;113auto minuend = b;114if (Invert)115std::swap(subtrahend, minuend);116assert(subtrahend.is<Symbol *>());117Reloc subtrahendReloc(target->subtractorRelocType, /*pcrel=*/false, length,118off, /*addend=*/0, subtrahend);119Reloc minuendReloc(target->unsignedRelocType, /*pcrel=*/false, length, off,120(Invert ? 1 : -1) * off, minuend);121newRelocs->push_back(subtrahendReloc);122newRelocs->push_back(minuendReloc);123}124125void EhRelocator::makePcRel(uint64_t off,126PointerUnion<Symbol *, InputSection *> target,127uint8_t length) {128createSubtraction(isec->symbols[0], target, off, length, &newRelocs);129}130131void EhRelocator::makeNegativePcRel(132uint64_t off, PointerUnion<Symbol *, InputSection *> target,133uint8_t length) {134createSubtraction</*Invert=*/true>(isec, target, off, length, &newRelocs);135}136137void EhRelocator::commit() {138isec->relocs.insert(isec->relocs.end(), newRelocs.begin(), newRelocs.end());139}140141142