//===- bolt/Core/Exceptions.cpp - Helpers for C++ exceptions --------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file implements functions for handling C++ exception meta data. // // Some of the code is taken from examples/ExceptionDemo // //===----------------------------------------------------------------------===// #include "bolt/Core/Exceptions.h" #include "bolt/Core/BinaryFunction.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Errc.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include <map> #undef DEBUG_TYPE #define DEBUG_TYPE … usingnamespacellvm::dwarf; namespace opts { extern llvm::cl::OptionCategory BoltCategory; extern llvm::cl::opt<unsigned> Verbosity; static llvm::cl::opt<bool> PrintExceptions("print-exceptions", llvm::cl::desc("print exception handling data"), llvm::cl::Hidden, llvm::cl::cat(BoltCategory)); } // namespace opts namespace llvm { namespace bolt { // Read and dump the .gcc_exception_table section entry. // // .gcc_except_table section contains a set of Language-Specific Data Areas - // a fancy name for exception handling tables. There's one LSDA entry per // function. However, we can't actually tell which function LSDA refers to // unless we parse .eh_frame entry that refers to the LSDA. // Then inside LSDA most addresses are encoded relative to the function start, // so we need the function context in order to get to real addresses. // // The best visual representation of the tables comprising LSDA and // relationships between them is illustrated at: // https://github.com/itanium-cxx-abi/cxx-abi/blob/master/exceptions.pdf // Keep in mind that GCC implementation deviates slightly from that document. // // To summarize, there are 4 tables in LSDA: call site table, actions table, // types table, and types index table (for indirection). The main table contains // call site entries. Each call site includes a PC range that can throw an // exception, a handler (landing pad), and a reference to an entry in the action // table. The handler and/or action could be 0. The action entry is a head // of a list of actions associated with a call site. The action table contains // all such lists (it could be optimized to share list tails). Each action could // be either to catch an exception of a given type, to perform a cleanup, or to // propagate the exception after filtering it out (e.g. to make sure function // exception specification is not violated). Catch action contains a reference // to an entry in the type table, and filter action refers to an entry in the // type index table to encode a set of types to filter. // // Call site table follows LSDA header. Action table immediately follows the // call site table. // // Both types table and type index table start at the same location, but they // grow in opposite directions (types go up, indices go down). The beginning of // these tables is encoded in LSDA header. Sizes for both of the tables are not // included anywhere. // // We have to parse all of the tables to determine their sizes. Then we have // to parse the call site table and associate discovered information with // actual call instructions and landing pad blocks. // // For the purpose of rewriting exception handling tables, we can reuse action, // and type index tables in their original binary format. // // Type table could be encoded using position-independent references, and thus // may require relocation. // // Ideally we should be able to re-write LSDA in-place, without the need to // allocate a new space for it. Sadly there's no guarantee that the new call // site table will be the same size as GCC uses uleb encodings for PC offsets. // // Note: some functions have LSDA entries with 0 call site entries. Error BinaryFunction::parseLSDA(ArrayRef<uint8_t> LSDASectionData, uint64_t LSDASectionAddress) { … } void BinaryFunction::updateEHRanges() { … } const uint8_t DWARF_CFI_PRIMARY_OPCODE_MASK = …; CFIReaderWriter::CFIReaderWriter(BinaryContext &BC, const DWARFDebugFrame &EHFrame) : … { … } bool CFIReaderWriter::fillCFIInfoFor(BinaryFunction &Function) const { … } std::vector<char> CFIReaderWriter::generateEHFrameHeader( const DWARFDebugFrame &OldEHFrame, const DWARFDebugFrame &NewEHFrame, uint64_t EHFrameHeaderAddress, std::vector<uint64_t> &FailedAddresses) const { … } Error EHFrameParser::parseCIE(uint64_t StartOffset) { … } Error EHFrameParser::parseFDE(uint64_t CIEPointer, uint64_t StartStructureOffset) { … } Error EHFrameParser::parse() { … } Error EHFrameParser::parse(DWARFDataExtractor Data, uint64_t EHFrameAddress, PatcherCallbackTy PatcherCallback) { … } } // namespace bolt } // namespace llvm