brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.4 KiB · 2446b49 Raw
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