Path: blob/main/contrib/llvm-project/lld/ELF/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//===----------------------------------------------------------------------===//7//8// .eh_frame section contains information on how to unwind the stack when9// an exception is thrown. The section consists of sequence of CIE and FDE10// records. The linker needs to merge CIEs and associate FDEs to CIEs.11// That means the linker has to understand the format of the section.12//13// This file contains a few utility functions to read .eh_frame contents.14//15//===----------------------------------------------------------------------===//1617#include "EhFrame.h"18#include "Config.h"19#include "InputSection.h"20#include "Relocations.h"21#include "Target.h"22#include "lld/Common/ErrorHandler.h"23#include "lld/Common/Strings.h"24#include "llvm/BinaryFormat/Dwarf.h"25#include "llvm/Object/ELF.h"2627using namespace llvm;28using namespace llvm::ELF;29using namespace llvm::dwarf;30using namespace llvm::object;31using namespace lld;32using namespace lld::elf;3334namespace {35class EhReader {36public:37EhReader(InputSectionBase *s, ArrayRef<uint8_t> d) : isec(s), d(d) {}38uint8_t getFdeEncoding();39bool hasLSDA();4041private:42template <class P> void failOn(const P *loc, const Twine &msg) {43fatal("corrupted .eh_frame: " + msg + "\n>>> defined in " +44isec->getObjMsg((const uint8_t *)loc - isec->content().data()));45}4647uint8_t readByte();48void skipBytes(size_t count);49StringRef readString();50void skipLeb128();51void skipAugP();52StringRef getAugmentation();5354InputSectionBase *isec;55ArrayRef<uint8_t> d;56};57}5859// Read a byte and advance D by one byte.60uint8_t EhReader::readByte() {61if (d.empty())62failOn(d.data(), "unexpected end of CIE");63uint8_t b = d.front();64d = d.slice(1);65return b;66}6768void EhReader::skipBytes(size_t count) {69if (d.size() < count)70failOn(d.data(), "CIE is too small");71d = d.slice(count);72}7374// Read a null-terminated string.75StringRef EhReader::readString() {76const uint8_t *end = llvm::find(d, '\0');77if (end == d.end())78failOn(d.data(), "corrupted CIE (failed to read string)");79StringRef s = toStringRef(d.slice(0, end - d.begin()));80d = d.slice(s.size() + 1);81return s;82}8384// Skip an integer encoded in the LEB128 format.85// Actual number is not of interest because only the runtime needs it.86// But we need to be at least able to skip it so that we can read87// the field that follows a LEB128 number.88void EhReader::skipLeb128() {89const uint8_t *errPos = d.data();90while (!d.empty()) {91uint8_t val = d.front();92d = d.slice(1);93if ((val & 0x80) == 0)94return;95}96failOn(errPos, "corrupted CIE (failed to read LEB128)");97}9899static size_t getAugPSize(unsigned enc) {100switch (enc & 0x0f) {101case DW_EH_PE_absptr:102case DW_EH_PE_signed:103return config->wordsize;104case DW_EH_PE_udata2:105case DW_EH_PE_sdata2:106return 2;107case DW_EH_PE_udata4:108case DW_EH_PE_sdata4:109return 4;110case DW_EH_PE_udata8:111case DW_EH_PE_sdata8:112return 8;113}114return 0;115}116117void EhReader::skipAugP() {118uint8_t enc = readByte();119if ((enc & 0xf0) == DW_EH_PE_aligned)120failOn(d.data() - 1, "DW_EH_PE_aligned encoding is not supported");121size_t size = getAugPSize(enc);122if (size == 0)123failOn(d.data() - 1, "unknown FDE encoding");124if (size >= d.size())125failOn(d.data() - 1, "corrupted CIE");126d = d.slice(size);127}128129uint8_t elf::getFdeEncoding(EhSectionPiece *p) {130return EhReader(p->sec, p->data()).getFdeEncoding();131}132133bool elf::hasLSDA(const EhSectionPiece &p) {134return EhReader(p.sec, p.data()).hasLSDA();135}136137StringRef EhReader::getAugmentation() {138skipBytes(8);139int version = readByte();140if (version != 1 && version != 3)141failOn(d.data() - 1,142"FDE version 1 or 3 expected, but got " + Twine(version));143144StringRef aug = readString();145146// Skip code and data alignment factors.147skipLeb128();148skipLeb128();149150// Skip the return address register. In CIE version 1 this is a single151// byte. In CIE version 3 this is an unsigned LEB128.152if (version == 1)153readByte();154else155skipLeb128();156return aug;157}158159uint8_t EhReader::getFdeEncoding() {160// We only care about an 'R' value, but other records may precede an 'R'161// record. Unfortunately records are not in TLV (type-length-value) format,162// so we need to teach the linker how to skip records for each type.163StringRef aug = getAugmentation();164for (char c : aug) {165if (c == 'R')166return readByte();167if (c == 'z')168skipLeb128();169else if (c == 'L')170readByte();171else if (c == 'P')172skipAugP();173else if (c != 'B' && c != 'S' && c != 'G')174failOn(aug.data(), "unknown .eh_frame augmentation string: " + aug);175}176return DW_EH_PE_absptr;177}178179bool EhReader::hasLSDA() {180StringRef aug = getAugmentation();181for (char c : aug) {182if (c == 'L')183return true;184if (c == 'z')185skipLeb128();186else if (c == 'P')187skipAugP();188else if (c == 'R')189readByte();190else if (c != 'B' && c != 'S' && c != 'G')191failOn(aug.data(), "unknown .eh_frame augmentation string: " + aug);192}193return false;194}195196197