brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.4 KiB · aade929 Raw
206 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// .eh_frame section contains information on how to unwind the stack when10// an exception is thrown. The section consists of sequence of CIE and FDE11// records. The linker needs to merge CIEs and associate FDEs to CIEs.12// That means the linker has to understand the format of the section.13//14// This file contains a few utility functions to read .eh_frame contents.15//16//===----------------------------------------------------------------------===//17 18#include "EhFrame.h"19#include "Config.h"20#include "InputFiles.h"21#include "InputSection.h"22#include "Relocations.h"23#include "Target.h"24#include "llvm/BinaryFormat/Dwarf.h"25 26using namespace llvm;27using namespace llvm::ELF;28using namespace llvm::dwarf;29using namespace llvm::object;30using namespace lld;31using namespace lld::elf;32 33namespace {34class EhReader {35public:36  EhReader(InputSectionBase *s, ArrayRef<uint8_t> d) : isec(s), d(d) {}37  uint8_t getFdeEncoding();38  bool hasLSDA();39 40private:41  template <class P> void errOn(const P *loc, const Twine &msg) {42    Ctx &ctx = isec->file->ctx;43    Err(ctx) << "corrupted .eh_frame: " << msg << "\n>>> defined in "44             << isec->getObjMsg((const uint8_t *)loc - isec->content().data());45  }46 47  uint8_t readByte();48  void skipBytes(size_t count);49  StringRef readString();50  void skipLeb128();51  void skipAugP();52  StringRef getAugmentation();53 54  InputSectionBase *isec;55  ArrayRef<uint8_t> d;56};57}58 59// Read a byte and advance D by one byte.60uint8_t EhReader::readByte() {61  if (d.empty()) {62    errOn(d.data(), "unexpected end of CIE");63    return 0;64  }65  uint8_t b = d.front();66  d = d.slice(1);67  return b;68}69 70void EhReader::skipBytes(size_t count) {71  if (d.size() < count)72    errOn(d.data(), "CIE is too small");73  else74    d = d.slice(count);75}76 77// Read a null-terminated string.78StringRef EhReader::readString() {79  const uint8_t *end = llvm::find(d, '\0');80  if (end == d.end()) {81    errOn(d.data(), "corrupted CIE (failed to read string)");82    return {};83  }84  StringRef s = toStringRef(d.slice(0, end - d.begin()));85  d = d.slice(s.size() + 1);86  return s;87}88 89// Skip an integer encoded in the LEB128 format.90// Actual number is not of interest because only the runtime needs it.91// But we need to be at least able to skip it so that we can read92// the field that follows a LEB128 number.93void EhReader::skipLeb128() {94  const uint8_t *errPos = d.data();95  while (!d.empty()) {96    uint8_t val = d.front();97    d = d.slice(1);98    if ((val & 0x80) == 0)99      return;100  }101  errOn(errPos, "corrupted CIE (failed to read LEB128)");102}103 104static size_t getAugPSize(Ctx &ctx, unsigned enc) {105  switch (enc & 0x0f) {106  case DW_EH_PE_absptr:107  case DW_EH_PE_signed:108    return ctx.arg.wordsize;109  case DW_EH_PE_udata2:110  case DW_EH_PE_sdata2:111    return 2;112  case DW_EH_PE_udata4:113  case DW_EH_PE_sdata4:114    return 4;115  case DW_EH_PE_udata8:116  case DW_EH_PE_sdata8:117    return 8;118  }119  return 0;120}121 122void EhReader::skipAugP() {123  uint8_t enc = readByte();124  if ((enc & 0xf0) == DW_EH_PE_aligned)125    return errOn(d.data() - 1, "DW_EH_PE_aligned encoding is not supported");126  size_t size = getAugPSize(isec->getCtx(), enc);127  if (size == 0)128    return errOn(d.data() - 1, "unknown FDE encoding");129  if (size >= d.size())130    return errOn(d.data() - 1, "corrupted CIE");131  d = d.slice(size);132}133 134uint8_t elf::getFdeEncoding(EhSectionPiece *p) {135  return EhReader(p->sec, p->data()).getFdeEncoding();136}137 138bool elf::hasLSDA(const EhSectionPiece &p) {139  return EhReader(p.sec, p.data()).hasLSDA();140}141 142StringRef EhReader::getAugmentation() {143  skipBytes(8);144  int version = readByte();145  if (version != 1 && version != 3) {146    errOn(d.data() - 1,147          "FDE version 1 or 3 expected, but got " + Twine(version));148    return {};149  }150 151  StringRef aug = readString();152 153  // Skip code and data alignment factors.154  skipLeb128();155  skipLeb128();156 157  // Skip the return address register. In CIE version 1 this is a single158  // byte. In CIE version 3 this is an unsigned LEB128.159  if (version == 1)160    readByte();161  else162    skipLeb128();163  return aug;164}165 166uint8_t EhReader::getFdeEncoding() {167  // We only care about an 'R' value, but other records may precede an 'R'168  // record. Unfortunately records are not in TLV (type-length-value) format,169  // so we need to teach the linker how to skip records for each type.170  StringRef aug = getAugmentation();171  for (char c : aug) {172    if (c == 'R')173      return readByte();174    if (c == 'z')175      skipLeb128();176    else if (c == 'L')177      readByte();178    else if (c == 'P')179      skipAugP();180    else if (c != 'B' && c != 'S' && c != 'G') {181      errOn(aug.data(), "unknown .eh_frame augmentation string: " + aug);182      break;183    }184  }185  return DW_EH_PE_absptr;186}187 188bool EhReader::hasLSDA() {189  StringRef aug = getAugmentation();190  for (char c : aug) {191    if (c == 'L')192      return true;193    if (c == 'z')194      skipLeb128();195    else if (c == 'P')196      skipAugP();197    else if (c == 'R')198      readByte();199    else if (c != 'B' && c != 'S' && c != 'G') {200      errOn(aug.data(), "unknown .eh_frame augmentation string: " + aug);201      break;202    }203  }204  return false;205}206