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