12f09f445SMaksim Panchenko //===- bolt/Core/Exceptions.cpp - Helpers for C++ exceptions --------------===//
2a34c753fSRafael Auler //
3a34c753fSRafael Auler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a34c753fSRafael Auler // See https://llvm.org/LICENSE.txt for license information.
5a34c753fSRafael Auler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a34c753fSRafael Auler //
7a34c753fSRafael Auler //===----------------------------------------------------------------------===//
8a34c753fSRafael Auler //
92f09f445SMaksim Panchenko // This file implements functions for handling C++ exception meta data.
102f09f445SMaksim Panchenko //
11a34c753fSRafael Auler // Some of the code is taken from examples/ExceptionDemo
12a34c753fSRafael Auler //
13a34c753fSRafael Auler //===----------------------------------------------------------------------===//
14a34c753fSRafael Auler
15a34c753fSRafael Auler #include "bolt/Core/Exceptions.h"
16a34c753fSRafael Auler #include "bolt/Core/BinaryFunction.h"
17a34c753fSRafael Auler #include "llvm/ADT/ArrayRef.h"
18a34c753fSRafael Auler #include "llvm/ADT/Twine.h"
19a34c753fSRafael Auler #include "llvm/BinaryFormat/Dwarf.h"
20a34c753fSRafael Auler #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
21a34c753fSRafael Auler #include "llvm/Support/Casting.h"
22a34c753fSRafael Auler #include "llvm/Support/CommandLine.h"
23a34c753fSRafael Auler #include "llvm/Support/Debug.h"
24290e4823Sserge-sans-paille #include "llvm/Support/Errc.h"
25a34c753fSRafael Auler #include "llvm/Support/LEB128.h"
26a34c753fSRafael Auler #include "llvm/Support/MathExtras.h"
27a34c753fSRafael Auler #include "llvm/Support/raw_ostream.h"
28a34c753fSRafael Auler #include <map>
29a34c753fSRafael Auler
30a34c753fSRafael Auler #undef DEBUG_TYPE
31a34c753fSRafael Auler #define DEBUG_TYPE "bolt-exceptions"
32a34c753fSRafael Auler
33a34c753fSRafael Auler using namespace llvm::dwarf;
34a34c753fSRafael Auler
35a34c753fSRafael Auler namespace opts {
36a34c753fSRafael Auler
37a34c753fSRafael Auler extern llvm::cl::OptionCategory BoltCategory;
38a34c753fSRafael Auler
39a34c753fSRafael Auler extern llvm::cl::opt<unsigned> Verbosity;
40a34c753fSRafael Auler
41a34c753fSRafael Auler static llvm::cl::opt<bool>
42a34c753fSRafael Auler PrintExceptions("print-exceptions",
43a34c753fSRafael Auler llvm::cl::desc("print exception handling data"),
44b92436efSFangrui Song llvm::cl::Hidden, llvm::cl::cat(BoltCategory));
45a34c753fSRafael Auler
46a34c753fSRafael Auler } // namespace opts
47a34c753fSRafael Auler
48a34c753fSRafael Auler namespace llvm {
49a34c753fSRafael Auler namespace bolt {
50a34c753fSRafael Auler
51a34c753fSRafael Auler // Read and dump the .gcc_exception_table section entry.
52a34c753fSRafael Auler //
53a34c753fSRafael Auler // .gcc_except_table section contains a set of Language-Specific Data Areas -
54a34c753fSRafael Auler // a fancy name for exception handling tables. There's one LSDA entry per
55a34c753fSRafael Auler // function. However, we can't actually tell which function LSDA refers to
56a34c753fSRafael Auler // unless we parse .eh_frame entry that refers to the LSDA.
57a34c753fSRafael Auler // Then inside LSDA most addresses are encoded relative to the function start,
58a34c753fSRafael Auler // so we need the function context in order to get to real addresses.
59a34c753fSRafael Auler //
60a34c753fSRafael Auler // The best visual representation of the tables comprising LSDA and
61a34c753fSRafael Auler // relationships between them is illustrated at:
62a34c753fSRafael Auler // https://github.com/itanium-cxx-abi/cxx-abi/blob/master/exceptions.pdf
63a34c753fSRafael Auler // Keep in mind that GCC implementation deviates slightly from that document.
64a34c753fSRafael Auler //
65a34c753fSRafael Auler // To summarize, there are 4 tables in LSDA: call site table, actions table,
66a34c753fSRafael Auler // types table, and types index table (for indirection). The main table contains
67a34c753fSRafael Auler // call site entries. Each call site includes a PC range that can throw an
68a34c753fSRafael Auler // exception, a handler (landing pad), and a reference to an entry in the action
69a34c753fSRafael Auler // table. The handler and/or action could be 0. The action entry is a head
70a34c753fSRafael Auler // of a list of actions associated with a call site. The action table contains
71a34c753fSRafael Auler // all such lists (it could be optimized to share list tails). Each action could
72a34c753fSRafael Auler // be either to catch an exception of a given type, to perform a cleanup, or to
73a34c753fSRafael Auler // propagate the exception after filtering it out (e.g. to make sure function
74a34c753fSRafael Auler // exception specification is not violated). Catch action contains a reference
75a34c753fSRafael Auler // to an entry in the type table, and filter action refers to an entry in the
76a34c753fSRafael Auler // type index table to encode a set of types to filter.
77a34c753fSRafael Auler //
78a34c753fSRafael Auler // Call site table follows LSDA header. Action table immediately follows the
79a34c753fSRafael Auler // call site table.
80a34c753fSRafael Auler //
81a34c753fSRafael Auler // Both types table and type index table start at the same location, but they
82a34c753fSRafael Auler // grow in opposite directions (types go up, indices go down). The beginning of
83a34c753fSRafael Auler // these tables is encoded in LSDA header. Sizes for both of the tables are not
84a34c753fSRafael Auler // included anywhere.
85a34c753fSRafael Auler //
86a34c753fSRafael Auler // We have to parse all of the tables to determine their sizes. Then we have
87a34c753fSRafael Auler // to parse the call site table and associate discovered information with
88a34c753fSRafael Auler // actual call instructions and landing pad blocks.
89a34c753fSRafael Auler //
90a34c753fSRafael Auler // For the purpose of rewriting exception handling tables, we can reuse action,
91a34c753fSRafael Auler // and type index tables in their original binary format.
92a34c753fSRafael Auler //
93a34c753fSRafael Auler // Type table could be encoded using position-independent references, and thus
94a34c753fSRafael Auler // may require relocation.
95a34c753fSRafael Auler //
96a34c753fSRafael Auler // Ideally we should be able to re-write LSDA in-place, without the need to
97a34c753fSRafael Auler // allocate a new space for it. Sadly there's no guarantee that the new call
98a34c753fSRafael Auler // site table will be the same size as GCC uses uleb encodings for PC offsets.
99a34c753fSRafael Auler //
100a34c753fSRafael Auler // Note: some functions have LSDA entries with 0 call site entries.
parseLSDA(ArrayRef<uint8_t> LSDASectionData,uint64_t LSDASectionAddress)101a34c753fSRafael Auler void BinaryFunction::parseLSDA(ArrayRef<uint8_t> LSDASectionData,
102a34c753fSRafael Auler uint64_t LSDASectionAddress) {
103a34c753fSRafael Auler assert(CurrentState == State::Disassembled && "unexpected function state");
104a34c753fSRafael Auler
105a34c753fSRafael Auler if (!getLSDAAddress())
106a34c753fSRafael Auler return;
107a34c753fSRafael Auler
108a34c753fSRafael Auler DWARFDataExtractor Data(
109a34c753fSRafael Auler StringRef(reinterpret_cast<const char *>(LSDASectionData.data()),
110a34c753fSRafael Auler LSDASectionData.size()),
111a34c753fSRafael Auler BC.DwCtx->getDWARFObj().isLittleEndian(), 8);
112a34c753fSRafael Auler uint64_t Offset = getLSDAAddress() - LSDASectionAddress;
113a34c753fSRafael Auler assert(Data.isValidOffset(Offset) && "wrong LSDA address");
114a34c753fSRafael Auler
115a34c753fSRafael Auler uint8_t LPStartEncoding = Data.getU8(&Offset);
116a34c753fSRafael Auler uint64_t LPStart = 0;
117ae563c91SHuan Nguyen // Convert to offset if LPStartEncoding is typed absptr DW_EH_PE_absptr
118a34c753fSRafael Auler if (Optional<uint64_t> MaybeLPStart = Data.getEncodedPointer(
119a34c753fSRafael Auler &Offset, LPStartEncoding, Offset + LSDASectionAddress))
120ae563c91SHuan Nguyen LPStart = (LPStartEncoding && 0xFF == 0) ? *MaybeLPStart
121ae563c91SHuan Nguyen : *MaybeLPStart - Address;
122a34c753fSRafael Auler
123a34c753fSRafael Auler const uint8_t TTypeEncoding = Data.getU8(&Offset);
124a34c753fSRafael Auler size_t TTypeEncodingSize = 0;
125a34c753fSRafael Auler uintptr_t TTypeEnd = 0;
126a34c753fSRafael Auler if (TTypeEncoding != DW_EH_PE_omit) {
127a34c753fSRafael Auler TTypeEnd = Data.getULEB128(&Offset);
128a34c753fSRafael Auler TTypeEncodingSize = BC.getDWARFEncodingSize(TTypeEncoding);
129a34c753fSRafael Auler }
130a34c753fSRafael Auler
131a34c753fSRafael Auler if (opts::PrintExceptions) {
132a34c753fSRafael Auler outs() << "[LSDA at 0x" << Twine::utohexstr(getLSDAAddress())
133a34c753fSRafael Auler << " for function " << *this << "]:\n";
13440c2e0faSMaksim Panchenko outs() << "LPStart Encoding = 0x" << Twine::utohexstr(LPStartEncoding)
13540c2e0faSMaksim Panchenko << '\n';
136a34c753fSRafael Auler outs() << "LPStart = 0x" << Twine::utohexstr(LPStart) << '\n';
137a34c753fSRafael Auler outs() << "TType Encoding = 0x" << Twine::utohexstr(TTypeEncoding) << '\n';
138a34c753fSRafael Auler outs() << "TType End = " << TTypeEnd << '\n';
139a34c753fSRafael Auler }
140a34c753fSRafael Auler
141a34c753fSRafael Auler // Table to store list of indices in type table. Entries are uleb128 values.
142a34c753fSRafael Auler const uint64_t TypeIndexTableStart = Offset + TTypeEnd;
143a34c753fSRafael Auler
144a34c753fSRafael Auler // Offset past the last decoded index.
145a34c753fSRafael Auler uint64_t MaxTypeIndexTableOffset = 0;
146a34c753fSRafael Auler
147a34c753fSRafael Auler // Max positive index used in type table.
148a34c753fSRafael Auler unsigned MaxTypeIndex = 0;
149a34c753fSRafael Auler
150a34c753fSRafael Auler // The actual type info table starts at the same location, but grows in
151a34c753fSRafael Auler // opposite direction. TTypeEncoding is used to encode stored values.
152a34c753fSRafael Auler const uint64_t TypeTableStart = Offset + TTypeEnd;
153a34c753fSRafael Auler
154a34c753fSRafael Auler uint8_t CallSiteEncoding = Data.getU8(&Offset);
155a34c753fSRafael Auler uint32_t CallSiteTableLength = Data.getULEB128(&Offset);
156a34c753fSRafael Auler uint64_t CallSiteTableStart = Offset;
157a34c753fSRafael Auler uint64_t CallSiteTableEnd = CallSiteTableStart + CallSiteTableLength;
158a34c753fSRafael Auler uint64_t CallSitePtr = CallSiteTableStart;
159a34c753fSRafael Auler uint64_t ActionTableStart = CallSiteTableEnd;
160a34c753fSRafael Auler
161a34c753fSRafael Auler if (opts::PrintExceptions) {
162a34c753fSRafael Auler outs() << "CallSite Encoding = " << (unsigned)CallSiteEncoding << '\n';
163a34c753fSRafael Auler outs() << "CallSite table length = " << CallSiteTableLength << '\n';
164a34c753fSRafael Auler outs() << '\n';
165a34c753fSRafael Auler }
166a34c753fSRafael Auler
167a34c753fSRafael Auler this->HasEHRanges = CallSitePtr < CallSiteTableEnd;
168a34c753fSRafael Auler const uint64_t RangeBase = getAddress();
169a34c753fSRafael Auler while (CallSitePtr < CallSiteTableEnd) {
170a34c753fSRafael Auler uint64_t Start = *Data.getEncodedPointer(&CallSitePtr, CallSiteEncoding,
171a34c753fSRafael Auler CallSitePtr + LSDASectionAddress);
17240c2e0faSMaksim Panchenko uint64_t Length = *Data.getEncodedPointer(&CallSitePtr, CallSiteEncoding,
17340c2e0faSMaksim Panchenko CallSitePtr + LSDASectionAddress);
174a34c753fSRafael Auler uint64_t LandingPad = *Data.getEncodedPointer(
175a34c753fSRafael Auler &CallSitePtr, CallSiteEncoding, CallSitePtr + LSDASectionAddress);
176a34c753fSRafael Auler uint64_t ActionEntry = Data.getULEB128(&CallSitePtr);
177a34c753fSRafael Auler
178ae563c91SHuan Nguyen uint64_t LPOffset = LPStart + LandingPad;
179ae563c91SHuan Nguyen uint64_t LPAddress = Address + LPOffset;
180ae563c91SHuan Nguyen
181ae563c91SHuan Nguyen // Verify if landing pad code is located outside current function
182ae563c91SHuan Nguyen // Support landing pad to builtin_unreachable
183ae563c91SHuan Nguyen if (LPAddress < Address || LPAddress > Address + getSize()) {
184ae563c91SHuan Nguyen BinaryFunction *Fragment =
185ae563c91SHuan Nguyen BC.getBinaryFunctionContainingAddress(LPAddress);
186ae563c91SHuan Nguyen assert(Fragment != nullptr &&
187ae563c91SHuan Nguyen "BOLT-ERROR: cannot find landing pad fragment");
188ae563c91SHuan Nguyen BC.addInterproceduralReference(this, Fragment->getAddress());
189ae563c91SHuan Nguyen BC.processInterproceduralReferences();
190ae563c91SHuan Nguyen auto isFragmentOf = [](BinaryFunction *Fragment,
191ae563c91SHuan Nguyen BinaryFunction *Parent) -> bool {
192ae563c91SHuan Nguyen return (Fragment->isFragment() && Fragment->isParentFragment(Parent));
193ae563c91SHuan Nguyen };
194ae563c91SHuan Nguyen assert((isFragmentOf(this, Fragment) || isFragmentOf(Fragment, this)) &&
195ae563c91SHuan Nguyen "BOLT-ERROR: cannot have landing pads in different "
196ae563c91SHuan Nguyen "functions");
197ae563c91SHuan Nguyen setHasIndirectTargetToSplitFragment(true);
198ae563c91SHuan Nguyen BC.addFragmentsToSkip(this);
199ae563c91SHuan Nguyen return;
200ae563c91SHuan Nguyen }
201ae563c91SHuan Nguyen
202a34c753fSRafael Auler if (opts::PrintExceptions) {
203a34c753fSRafael Auler outs() << "Call Site: [0x" << Twine::utohexstr(RangeBase + Start)
204a34c753fSRafael Auler << ", 0x" << Twine::utohexstr(RangeBase + Start + Length)
205ae563c91SHuan Nguyen << "); landing pad: 0x" << Twine::utohexstr(LPOffset)
206a34c753fSRafael Auler << "; action entry: 0x" << Twine::utohexstr(ActionEntry) << "\n";
207a34c753fSRafael Auler outs() << " current offset is " << (CallSitePtr - CallSiteTableStart)
208a34c753fSRafael Auler << '\n';
209a34c753fSRafael Auler }
210a34c753fSRafael Auler
211a34c753fSRafael Auler // Create a handler entry if necessary.
212a34c753fSRafael Auler MCSymbol *LPSymbol = nullptr;
213ae563c91SHuan Nguyen if (LPOffset) {
214ae563c91SHuan Nguyen if (!getInstructionAtOffset(LPOffset)) {
21569706eafSMaksim Panchenko if (opts::Verbosity >= 1)
216ae563c91SHuan Nguyen errs() << "BOLT-WARNING: landing pad " << Twine::utohexstr(LPOffset)
21769706eafSMaksim Panchenko << " not pointing to an instruction in function " << *this
21869706eafSMaksim Panchenko << " - ignoring.\n";
219a34c753fSRafael Auler } else {
220ae563c91SHuan Nguyen auto Label = Labels.find(LPOffset);
221a34c753fSRafael Auler if (Label != Labels.end()) {
222a34c753fSRafael Auler LPSymbol = Label->second;
223a34c753fSRafael Auler } else {
224a34c753fSRafael Auler LPSymbol = BC.Ctx->createNamedTempSymbol("LP");
225ae563c91SHuan Nguyen Labels[LPOffset] = LPSymbol;
226a34c753fSRafael Auler }
227a34c753fSRafael Auler }
228a34c753fSRafael Auler }
229a34c753fSRafael Auler
230a34c753fSRafael Auler // Mark all call instructions in the range.
231a34c753fSRafael Auler auto II = Instructions.find(Start);
232a34c753fSRafael Auler auto IE = Instructions.end();
233a34c753fSRafael Auler assert(II != IE && "exception range not pointing to an instruction");
234a34c753fSRafael Auler do {
235a34c753fSRafael Auler MCInst &Instruction = II->second;
236a34c753fSRafael Auler if (BC.MIB->isCall(Instruction) &&
237a34c753fSRafael Auler !BC.MIB->getConditionalTailCall(Instruction)) {
238a34c753fSRafael Auler assert(!BC.MIB->isInvoke(Instruction) &&
239a34c753fSRafael Auler "overlapping exception ranges detected");
240a34c753fSRafael Auler // Add extra operands to a call instruction making it an invoke from
241a34c753fSRafael Auler // now on.
242a34c753fSRafael Auler BC.MIB->addEHInfo(Instruction,
243a34c753fSRafael Auler MCPlus::MCLandingPad(LPSymbol, ActionEntry));
244a34c753fSRafael Auler }
245a34c753fSRafael Auler ++II;
246a34c753fSRafael Auler } while (II != IE && II->first < Start + Length);
247a34c753fSRafael Auler
248a34c753fSRafael Auler if (ActionEntry != 0) {
249a34c753fSRafael Auler auto printType = [&](int Index, raw_ostream &OS) {
250a34c753fSRafael Auler assert(Index > 0 && "only positive indices are valid");
251a34c753fSRafael Auler uint64_t TTEntry = TypeTableStart - Index * TTypeEncodingSize;
252a34c753fSRafael Auler const uint64_t TTEntryAddress = TTEntry + LSDASectionAddress;
253a34c753fSRafael Auler uint64_t TypeAddress =
254a34c753fSRafael Auler *Data.getEncodedPointer(&TTEntry, TTypeEncoding, TTEntryAddress);
2553652483cSRafael Auler if ((TTypeEncoding & DW_EH_PE_pcrel) && TypeAddress == TTEntryAddress)
256a34c753fSRafael Auler TypeAddress = 0;
257a34c753fSRafael Auler if (TypeAddress == 0) {
258a34c753fSRafael Auler OS << "<all>";
259a34c753fSRafael Auler return;
260a34c753fSRafael Auler }
261a34c753fSRafael Auler if (TTypeEncoding & DW_EH_PE_indirect) {
262a34c753fSRafael Auler ErrorOr<uint64_t> PointerOrErr = BC.getPointerAtAddress(TypeAddress);
263a34c753fSRafael Auler assert(PointerOrErr && "failed to decode indirect address");
264a34c753fSRafael Auler TypeAddress = *PointerOrErr;
265a34c753fSRafael Auler }
2663652483cSRafael Auler if (BinaryData *TypeSymBD = BC.getBinaryDataAtAddress(TypeAddress))
267a34c753fSRafael Auler OS << TypeSymBD->getName();
2683652483cSRafael Auler else
269a34c753fSRafael Auler OS << "0x" << Twine::utohexstr(TypeAddress);
270a34c753fSRafael Auler };
271a34c753fSRafael Auler if (opts::PrintExceptions)
272a34c753fSRafael Auler outs() << " actions: ";
273a34c753fSRafael Auler uint64_t ActionPtr = ActionTableStart + ActionEntry - 1;
274a34c753fSRafael Auler int64_t ActionType;
275a34c753fSRafael Auler int64_t ActionNext;
276a34c753fSRafael Auler const char *Sep = "";
277a34c753fSRafael Auler do {
278a34c753fSRafael Auler ActionType = Data.getSLEB128(&ActionPtr);
279a34c753fSRafael Auler const uint32_t Self = ActionPtr;
280a34c753fSRafael Auler ActionNext = Data.getSLEB128(&ActionPtr);
281a34c753fSRafael Auler if (opts::PrintExceptions)
282a34c753fSRafael Auler outs() << Sep << "(" << ActionType << ", " << ActionNext << ") ";
283a34c753fSRafael Auler if (ActionType == 0) {
284a34c753fSRafael Auler if (opts::PrintExceptions)
285a34c753fSRafael Auler outs() << "cleanup";
286a34c753fSRafael Auler } else if (ActionType > 0) {
287a34c753fSRafael Auler // It's an index into a type table.
28840c2e0faSMaksim Panchenko MaxTypeIndex =
28940c2e0faSMaksim Panchenko std::max(MaxTypeIndex, static_cast<unsigned>(ActionType));
290a34c753fSRafael Auler if (opts::PrintExceptions) {
291a34c753fSRafael Auler outs() << "catch type ";
292a34c753fSRafael Auler printType(ActionType, outs());
293a34c753fSRafael Auler }
294a34c753fSRafael Auler } else { // ActionType < 0
295a34c753fSRafael Auler if (opts::PrintExceptions)
296a34c753fSRafael Auler outs() << "filter exception types ";
297a34c753fSRafael Auler const char *TSep = "";
298a34c753fSRafael Auler // ActionType is a negative *byte* offset into *uleb128-encoded* table
299a34c753fSRafael Auler // of indices with base 1.
300a34c753fSRafael Auler // E.g. -1 means offset 0, -2 is offset 1, etc. The indices are
301a34c753fSRafael Auler // encoded using uleb128 thus we cannot directly dereference them.
302a34c753fSRafael Auler uint64_t TypeIndexTablePtr = TypeIndexTableStart - ActionType - 1;
303a34c753fSRafael Auler while (uint64_t Index = Data.getULEB128(&TypeIndexTablePtr)) {
304a34c753fSRafael Auler MaxTypeIndex = std::max(MaxTypeIndex, static_cast<unsigned>(Index));
305a34c753fSRafael Auler if (opts::PrintExceptions) {
306a34c753fSRafael Auler outs() << TSep;
307a34c753fSRafael Auler printType(Index, outs());
308a34c753fSRafael Auler TSep = ", ";
309a34c753fSRafael Auler }
310a34c753fSRafael Auler }
31140c2e0faSMaksim Panchenko MaxTypeIndexTableOffset = std::max(
31240c2e0faSMaksim Panchenko MaxTypeIndexTableOffset, TypeIndexTablePtr - TypeIndexTableStart);
313a34c753fSRafael Auler }
314a34c753fSRafael Auler
315a34c753fSRafael Auler Sep = "; ";
316a34c753fSRafael Auler
317a34c753fSRafael Auler ActionPtr = Self + ActionNext;
318a34c753fSRafael Auler } while (ActionNext);
319a34c753fSRafael Auler if (opts::PrintExceptions)
320a34c753fSRafael Auler outs() << '\n';
321a34c753fSRafael Auler }
322a34c753fSRafael Auler }
323a34c753fSRafael Auler if (opts::PrintExceptions)
324a34c753fSRafael Auler outs() << '\n';
325a34c753fSRafael Auler
326a34c753fSRafael Auler assert(TypeIndexTableStart + MaxTypeIndexTableOffset <=
327a34c753fSRafael Auler Data.getData().size() &&
328a34c753fSRafael Auler "LSDA entry has crossed section boundary");
329a34c753fSRafael Auler
330a34c753fSRafael Auler if (TTypeEnd) {
331a34c753fSRafael Auler LSDAActionTable = LSDASectionData.slice(
332a34c753fSRafael Auler ActionTableStart, TypeIndexTableStart -
333a34c753fSRafael Auler MaxTypeIndex * TTypeEncodingSize -
334a34c753fSRafael Auler ActionTableStart);
335a34c753fSRafael Auler for (unsigned Index = 1; Index <= MaxTypeIndex; ++Index) {
336a34c753fSRafael Auler uint64_t TTEntry = TypeTableStart - Index * TTypeEncodingSize;
337a34c753fSRafael Auler const uint64_t TTEntryAddress = TTEntry + LSDASectionAddress;
338a34c753fSRafael Auler uint64_t TypeAddress =
339a34c753fSRafael Auler *Data.getEncodedPointer(&TTEntry, TTypeEncoding, TTEntryAddress);
340a34c753fSRafael Auler if ((TTypeEncoding & DW_EH_PE_pcrel) && (TypeAddress == TTEntryAddress))
341a34c753fSRafael Auler TypeAddress = 0;
342a34c753fSRafael Auler if (TTypeEncoding & DW_EH_PE_indirect) {
343a34c753fSRafael Auler LSDATypeAddressTable.emplace_back(TypeAddress);
344a34c753fSRafael Auler if (TypeAddress) {
345a34c753fSRafael Auler ErrorOr<uint64_t> PointerOrErr = BC.getPointerAtAddress(TypeAddress);
346a34c753fSRafael Auler assert(PointerOrErr && "failed to decode indirect address");
347a34c753fSRafael Auler TypeAddress = *PointerOrErr;
348a34c753fSRafael Auler }
349a34c753fSRafael Auler }
350a34c753fSRafael Auler LSDATypeTable.emplace_back(TypeAddress);
351a34c753fSRafael Auler }
352a34c753fSRafael Auler LSDATypeIndexTable =
353a34c753fSRafael Auler LSDASectionData.slice(TypeIndexTableStart, MaxTypeIndexTableOffset);
354a34c753fSRafael Auler }
355a34c753fSRafael Auler }
356a34c753fSRafael Auler
updateEHRanges()357a34c753fSRafael Auler void BinaryFunction::updateEHRanges() {
358a34c753fSRafael Auler if (getSize() == 0)
359a34c753fSRafael Auler return;
360a34c753fSRafael Auler
361a34c753fSRafael Auler assert(CurrentState == State::CFG_Finalized && "unexpected state");
362a34c753fSRafael Auler
363a34c753fSRafael Auler // Build call sites table.
364a34c753fSRafael Auler struct EHInfo {
365a34c753fSRafael Auler const MCSymbol *LP; // landing pad
366a34c753fSRafael Auler uint64_t Action;
367a34c753fSRafael Auler };
368a34c753fSRafael Auler
369a34c753fSRafael Auler // If previous call can throw, this is its exception handler.
370a34c753fSRafael Auler EHInfo PreviousEH = {nullptr, 0};
371a34c753fSRafael Auler
372a34c753fSRafael Auler // Marker for the beginning of exceptions range.
373a34c753fSRafael Auler const MCSymbol *StartRange = nullptr;
374a34c753fSRafael Auler
375a34c753fSRafael Auler // Indicates whether the start range is located in a cold part.
376a34c753fSRafael Auler bool IsStartInCold = false;
377a34c753fSRafael Auler
378a34c753fSRafael Auler // Have we crossed hot/cold border for split functions?
379a34c753fSRafael Auler bool SeenCold = false;
380a34c753fSRafael Auler
381a34c753fSRafael Auler // Sites to update - either regular or cold.
382ebe51c4dSMaksim Panchenko CallSitesType *Sites = &CallSites;
383a34c753fSRafael Auler
384*8477bc67SFabian Parzefall for (BinaryBasicBlock *BB : getLayout().blocks()) {
385a34c753fSRafael Auler
386a34c753fSRafael Auler if (BB->isCold() && !SeenCold) {
387a34c753fSRafael Auler SeenCold = true;
388a34c753fSRafael Auler
389a34c753fSRafael Auler // Close the range (if any) and change the target call sites.
390a34c753fSRafael Auler if (StartRange) {
391a34c753fSRafael Auler Sites->emplace_back(CallSite{StartRange, getFunctionEndLabel(),
392a34c753fSRafael Auler PreviousEH.LP, PreviousEH.Action});
393a34c753fSRafael Auler }
394a34c753fSRafael Auler Sites = &ColdCallSites;
395a34c753fSRafael Auler
396a34c753fSRafael Auler // Reset the range.
397a34c753fSRafael Auler StartRange = nullptr;
398a34c753fSRafael Auler PreviousEH = {nullptr, 0};
399a34c753fSRafael Auler }
400a34c753fSRafael Auler
401a34c753fSRafael Auler for (auto II = BB->begin(); II != BB->end(); ++II) {
402a34c753fSRafael Auler if (!BC.MIB->isCall(*II))
403a34c753fSRafael Auler continue;
404a34c753fSRafael Auler
405a34c753fSRafael Auler // Instruction can throw an exception that should be handled.
406a34c753fSRafael Auler const bool Throws = BC.MIB->isInvoke(*II);
407a34c753fSRafael Auler
408a34c753fSRafael Auler // Ignore the call if it's a continuation of a no-throw gap.
409a34c753fSRafael Auler if (!Throws && !StartRange)
410a34c753fSRafael Auler continue;
411a34c753fSRafael Auler
412a34c753fSRafael Auler // Extract exception handling information from the instruction.
413a34c753fSRafael Auler const MCSymbol *LP = nullptr;
414a34c753fSRafael Auler uint64_t Action = 0;
415a34c753fSRafael Auler if (const Optional<MCPlus::MCLandingPad> EHInfo = BC.MIB->getEHInfo(*II))
416a34c753fSRafael Auler std::tie(LP, Action) = *EHInfo;
417a34c753fSRafael Auler
418a34c753fSRafael Auler // No action if the exception handler has not changed.
41940c2e0faSMaksim Panchenko if (Throws && StartRange && PreviousEH.LP == LP &&
420a34c753fSRafael Auler PreviousEH.Action == Action)
421a34c753fSRafael Auler continue;
422a34c753fSRafael Auler
423a34c753fSRafael Auler // Same symbol is used for the beginning and the end of the range.
424a34c753fSRafael Auler const MCSymbol *EHSymbol;
425a34c753fSRafael Auler MCInst EHLabel;
426a34c753fSRafael Auler {
427a34c753fSRafael Auler std::unique_lock<std::shared_timed_mutex> Lock(BC.CtxMutex);
428a34c753fSRafael Auler EHSymbol = BC.Ctx->createNamedTempSymbol("EH");
429a34c753fSRafael Auler BC.MIB->createEHLabel(EHLabel, EHSymbol, BC.Ctx.get());
430a34c753fSRafael Auler }
431a34c753fSRafael Auler
432a34c753fSRafael Auler II = std::next(BB->insertPseudoInstr(II, EHLabel));
433a34c753fSRafael Auler
434a34c753fSRafael Auler // At this point we could be in one of the following states:
435a34c753fSRafael Auler //
436a34c753fSRafael Auler // I. Exception handler has changed and we need to close previous range
437a34c753fSRafael Auler // and start a new one.
438a34c753fSRafael Auler //
439a34c753fSRafael Auler // II. Start a new exception range after the gap.
440a34c753fSRafael Auler //
441a34c753fSRafael Auler // III. Close current exception range and start a new gap.
442a34c753fSRafael Auler const MCSymbol *EndRange;
443a34c753fSRafael Auler if (StartRange) {
444a34c753fSRafael Auler // I, III:
445a34c753fSRafael Auler EndRange = EHSymbol;
446a34c753fSRafael Auler } else {
447a34c753fSRafael Auler // II:
448a34c753fSRafael Auler StartRange = EHSymbol;
449a34c753fSRafael Auler IsStartInCold = SeenCold;
450a34c753fSRafael Auler EndRange = nullptr;
451a34c753fSRafael Auler }
452a34c753fSRafael Auler
453a34c753fSRafael Auler // Close the previous range.
454a34c753fSRafael Auler if (EndRange) {
45540c2e0faSMaksim Panchenko Sites->emplace_back(
45640c2e0faSMaksim Panchenko CallSite{StartRange, EndRange, PreviousEH.LP, PreviousEH.Action});
457a34c753fSRafael Auler }
458a34c753fSRafael Auler
459a34c753fSRafael Auler if (Throws) {
460a34c753fSRafael Auler // I, II:
461a34c753fSRafael Auler StartRange = EHSymbol;
462a34c753fSRafael Auler IsStartInCold = SeenCold;
463a34c753fSRafael Auler PreviousEH = EHInfo{LP, Action};
464a34c753fSRafael Auler } else {
465a34c753fSRafael Auler StartRange = nullptr;
466a34c753fSRafael Auler }
467a34c753fSRafael Auler }
468a34c753fSRafael Auler }
469a34c753fSRafael Auler
470a34c753fSRafael Auler // Check if we need to close the range.
471a34c753fSRafael Auler if (StartRange) {
472a34c753fSRafael Auler assert((!isSplit() || Sites == &ColdCallSites) && "sites mismatch");
473a34c753fSRafael Auler const MCSymbol *EndRange =
474a34c753fSRafael Auler IsStartInCold ? getFunctionColdEndLabel() : getFunctionEndLabel();
47540c2e0faSMaksim Panchenko Sites->emplace_back(
47640c2e0faSMaksim Panchenko CallSite{StartRange, EndRange, PreviousEH.LP, PreviousEH.Action});
477a34c753fSRafael Auler }
478a34c753fSRafael Auler }
479a34c753fSRafael Auler
480a34c753fSRafael Auler const uint8_t DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0;
481a34c753fSRafael Auler
CFIReaderWriter(const DWARFDebugFrame & EHFrame)482a34c753fSRafael Auler CFIReaderWriter::CFIReaderWriter(const DWARFDebugFrame &EHFrame) {
483a34c753fSRafael Auler // Prepare FDEs for fast lookup
484a34c753fSRafael Auler for (const dwarf::FrameEntry &Entry : EHFrame.entries()) {
485a34c753fSRafael Auler const auto *CurFDE = dyn_cast<dwarf::FDE>(&Entry);
486a34c753fSRafael Auler // Skip CIEs.
487a34c753fSRafael Auler if (!CurFDE)
488a34c753fSRafael Auler continue;
489a34c753fSRafael Auler // There could me multiple FDEs with the same initial address, and perhaps
490a34c753fSRafael Auler // different sizes (address ranges). Use the first entry with non-zero size.
491a34c753fSRafael Auler auto FDEI = FDEs.lower_bound(CurFDE->getInitialLocation());
492a34c753fSRafael Auler if (FDEI != FDEs.end() && FDEI->first == CurFDE->getInitialLocation()) {
493a34c753fSRafael Auler if (CurFDE->getAddressRange()) {
494a34c753fSRafael Auler if (FDEI->second->getAddressRange() == 0) {
495a34c753fSRafael Auler FDEI->second = CurFDE;
496a34c753fSRafael Auler } else if (opts::Verbosity > 0) {
497a34c753fSRafael Auler errs() << "BOLT-WARNING: different FDEs for function at 0x"
498a34c753fSRafael Auler << Twine::utohexstr(FDEI->first)
49940c2e0faSMaksim Panchenko << " detected; sizes: " << FDEI->second->getAddressRange()
50040c2e0faSMaksim Panchenko << " and " << CurFDE->getAddressRange() << '\n';
501a34c753fSRafael Auler }
502a34c753fSRafael Auler }
503a34c753fSRafael Auler } else {
504a34c753fSRafael Auler FDEs.emplace_hint(FDEI, CurFDE->getInitialLocation(), CurFDE);
505a34c753fSRafael Auler }
506a34c753fSRafael Auler }
507a34c753fSRafael Auler }
508a34c753fSRafael Auler
fillCFIInfoFor(BinaryFunction & Function) const509a34c753fSRafael Auler bool CFIReaderWriter::fillCFIInfoFor(BinaryFunction &Function) const {
510a34c753fSRafael Auler uint64_t Address = Function.getAddress();
511a34c753fSRafael Auler auto I = FDEs.find(Address);
512a34c753fSRafael Auler // Ignore zero-length FDE ranges.
513a34c753fSRafael Auler if (I == FDEs.end() || !I->second->getAddressRange())
514a34c753fSRafael Auler return true;
515a34c753fSRafael Auler
516a34c753fSRafael Auler const FDE &CurFDE = *I->second;
517a34c753fSRafael Auler Optional<uint64_t> LSDA = CurFDE.getLSDAAddress();
518a34c753fSRafael Auler Function.setLSDAAddress(LSDA ? *LSDA : 0);
519a34c753fSRafael Auler
5200b7e8bafSDenis Revunov uint64_t Offset = Function.getFirstInstructionOffset();
521a34c753fSRafael Auler uint64_t CodeAlignment = CurFDE.getLinkedCIE()->getCodeAlignmentFactor();
522a34c753fSRafael Auler uint64_t DataAlignment = CurFDE.getLinkedCIE()->getDataAlignmentFactor();
523a34c753fSRafael Auler if (CurFDE.getLinkedCIE()->getPersonalityAddress()) {
524a34c753fSRafael Auler Function.setPersonalityFunction(
525a34c753fSRafael Auler *CurFDE.getLinkedCIE()->getPersonalityAddress());
526a34c753fSRafael Auler Function.setPersonalityEncoding(
527a34c753fSRafael Auler *CurFDE.getLinkedCIE()->getPersonalityEncoding());
528a34c753fSRafael Auler }
529a34c753fSRafael Auler
53040c2e0faSMaksim Panchenko auto decodeFrameInstruction = [&Function, &Offset, Address, CodeAlignment,
53140c2e0faSMaksim Panchenko DataAlignment](
532a34c753fSRafael Auler const CFIProgram::Instruction &Instr) {
533a34c753fSRafael Auler uint8_t Opcode = Instr.Opcode;
534a34c753fSRafael Auler if (Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK)
535a34c753fSRafael Auler Opcode &= DWARF_CFI_PRIMARY_OPCODE_MASK;
536a34c753fSRafael Auler switch (Instr.Opcode) {
537a34c753fSRafael Auler case DW_CFA_nop:
538a34c753fSRafael Auler break;
539a34c753fSRafael Auler case DW_CFA_advance_loc4:
540a34c753fSRafael Auler case DW_CFA_advance_loc2:
541a34c753fSRafael Auler case DW_CFA_advance_loc1:
542a34c753fSRafael Auler case DW_CFA_advance_loc:
543a34c753fSRafael Auler // Advance our current address
544a34c753fSRafael Auler Offset += CodeAlignment * int64_t(Instr.Ops[0]);
545a34c753fSRafael Auler break;
546a34c753fSRafael Auler case DW_CFA_offset_extended_sf:
547a34c753fSRafael Auler Function.addCFIInstruction(
54840c2e0faSMaksim Panchenko Offset,
54940c2e0faSMaksim Panchenko MCCFIInstruction::createOffset(
55040c2e0faSMaksim Panchenko nullptr, Instr.Ops[0], DataAlignment * int64_t(Instr.Ops[1])));
551a34c753fSRafael Auler break;
552a34c753fSRafael Auler case DW_CFA_offset_extended:
553a34c753fSRafael Auler case DW_CFA_offset:
554a34c753fSRafael Auler Function.addCFIInstruction(
55540c2e0faSMaksim Panchenko Offset, MCCFIInstruction::createOffset(nullptr, Instr.Ops[0],
55640c2e0faSMaksim Panchenko DataAlignment * Instr.Ops[1]));
557a34c753fSRafael Auler break;
558a34c753fSRafael Auler case DW_CFA_restore_extended:
559a34c753fSRafael Auler case DW_CFA_restore:
560a34c753fSRafael Auler Function.addCFIInstruction(
561a34c753fSRafael Auler Offset, MCCFIInstruction::createRestore(nullptr, Instr.Ops[0]));
562a34c753fSRafael Auler break;
563a34c753fSRafael Auler case DW_CFA_set_loc:
564a34c753fSRafael Auler assert(Instr.Ops[0] >= Address && "set_loc out of function bounds");
565a34c753fSRafael Auler assert(Instr.Ops[0] <= Address + Function.getSize() &&
566a34c753fSRafael Auler "set_loc out of function bounds");
567a34c753fSRafael Auler Offset = Instr.Ops[0] - Address;
568a34c753fSRafael Auler break;
569a34c753fSRafael Auler
570a34c753fSRafael Auler case DW_CFA_undefined:
571a34c753fSRafael Auler Function.addCFIInstruction(
572a34c753fSRafael Auler Offset, MCCFIInstruction::createUndefined(nullptr, Instr.Ops[0]));
573a34c753fSRafael Auler break;
574a34c753fSRafael Auler case DW_CFA_same_value:
575a34c753fSRafael Auler Function.addCFIInstruction(
576a34c753fSRafael Auler Offset, MCCFIInstruction::createSameValue(nullptr, Instr.Ops[0]));
577a34c753fSRafael Auler break;
578a34c753fSRafael Auler case DW_CFA_register:
579a34c753fSRafael Auler Function.addCFIInstruction(
580a34c753fSRafael Auler Offset, MCCFIInstruction::createRegister(nullptr, Instr.Ops[0],
581a34c753fSRafael Auler Instr.Ops[1]));
582a34c753fSRafael Auler break;
583a34c753fSRafael Auler case DW_CFA_remember_state:
584a34c753fSRafael Auler Function.addCFIInstruction(
585a34c753fSRafael Auler Offset, MCCFIInstruction::createRememberState(nullptr));
586a34c753fSRafael Auler break;
587a34c753fSRafael Auler case DW_CFA_restore_state:
58840c2e0faSMaksim Panchenko Function.addCFIInstruction(Offset,
58940c2e0faSMaksim Panchenko MCCFIInstruction::createRestoreState(nullptr));
590a34c753fSRafael Auler break;
591a34c753fSRafael Auler case DW_CFA_def_cfa:
592a34c753fSRafael Auler Function.addCFIInstruction(
59340c2e0faSMaksim Panchenko Offset,
59440c2e0faSMaksim Panchenko MCCFIInstruction::cfiDefCfa(nullptr, Instr.Ops[0], Instr.Ops[1]));
595a34c753fSRafael Auler break;
596a34c753fSRafael Auler case DW_CFA_def_cfa_sf:
597a34c753fSRafael Auler Function.addCFIInstruction(
59840c2e0faSMaksim Panchenko Offset,
59940c2e0faSMaksim Panchenko MCCFIInstruction::cfiDefCfa(nullptr, Instr.Ops[0],
600a34c753fSRafael Auler DataAlignment * int64_t(Instr.Ops[1])));
601a34c753fSRafael Auler break;
602a34c753fSRafael Auler case DW_CFA_def_cfa_register:
60340c2e0faSMaksim Panchenko Function.addCFIInstruction(Offset, MCCFIInstruction::createDefCfaRegister(
60440c2e0faSMaksim Panchenko nullptr, Instr.Ops[0]));
605a34c753fSRafael Auler break;
606a34c753fSRafael Auler case DW_CFA_def_cfa_offset:
607a34c753fSRafael Auler Function.addCFIInstruction(
60840c2e0faSMaksim Panchenko Offset, MCCFIInstruction::cfiDefCfaOffset(nullptr, Instr.Ops[0]));
609a34c753fSRafael Auler break;
610a34c753fSRafael Auler case DW_CFA_def_cfa_offset_sf:
611a34c753fSRafael Auler Function.addCFIInstruction(
612a34c753fSRafael Auler Offset, MCCFIInstruction::cfiDefCfaOffset(
613a34c753fSRafael Auler nullptr, DataAlignment * int64_t(Instr.Ops[0])));
614a34c753fSRafael Auler break;
615a34c753fSRafael Auler case DW_CFA_GNU_args_size:
616a34c753fSRafael Auler Function.addCFIInstruction(
61740c2e0faSMaksim Panchenko Offset, MCCFIInstruction::createGnuArgsSize(nullptr, Instr.Ops[0]));
618a34c753fSRafael Auler Function.setUsesGnuArgsSize();
619a34c753fSRafael Auler break;
620a34c753fSRafael Auler case DW_CFA_val_offset_sf:
621a34c753fSRafael Auler case DW_CFA_val_offset:
622a34c753fSRafael Auler if (opts::Verbosity >= 1) {
623a34c753fSRafael Auler errs() << "BOLT-WARNING: DWARF val_offset() unimplemented\n";
624a34c753fSRafael Auler }
625a34c753fSRafael Auler return false;
626a34c753fSRafael Auler case DW_CFA_def_cfa_expression:
627a34c753fSRafael Auler case DW_CFA_val_expression:
628a34c753fSRafael Auler case DW_CFA_expression: {
629a34c753fSRafael Auler StringRef ExprBytes = Instr.Expression->getData();
630a34c753fSRafael Auler std::string Str;
631a34c753fSRafael Auler raw_string_ostream OS(Str);
632a34c753fSRafael Auler // Manually encode this instruction using CFI escape
633a34c753fSRafael Auler OS << Opcode;
6343652483cSRafael Auler if (Opcode != DW_CFA_def_cfa_expression)
635a34c753fSRafael Auler encodeULEB128(Instr.Ops[0], OS);
636a34c753fSRafael Auler encodeULEB128(ExprBytes.size(), OS);
637a34c753fSRafael Auler OS << ExprBytes;
638a34c753fSRafael Auler Function.addCFIInstruction(
639a34c753fSRafael Auler Offset, MCCFIInstruction::createEscape(nullptr, OS.str()));
640a34c753fSRafael Auler break;
641a34c753fSRafael Auler }
642a34c753fSRafael Auler case DW_CFA_MIPS_advance_loc8:
6433652483cSRafael Auler if (opts::Verbosity >= 1)
644a34c753fSRafael Auler errs() << "BOLT-WARNING: DW_CFA_MIPS_advance_loc unimplemented\n";
645a34c753fSRafael Auler return false;
646a34c753fSRafael Auler case DW_CFA_GNU_window_save:
647a34c753fSRafael Auler case DW_CFA_lo_user:
648a34c753fSRafael Auler case DW_CFA_hi_user:
649a34c753fSRafael Auler if (opts::Verbosity >= 1) {
650a34c753fSRafael Auler errs() << "BOLT-WARNING: DW_CFA_GNU_* and DW_CFA_*_user "
651a34c753fSRafael Auler "unimplemented\n";
652a34c753fSRafael Auler }
653a34c753fSRafael Auler return false;
654a34c753fSRafael Auler default:
655a34c753fSRafael Auler if (opts::Verbosity >= 1) {
65640c2e0faSMaksim Panchenko errs() << "BOLT-WARNING: Unrecognized CFI instruction: " << Instr.Opcode
65740c2e0faSMaksim Panchenko << '\n';
658a34c753fSRafael Auler }
659a34c753fSRafael Auler return false;
660a34c753fSRafael Auler }
661a34c753fSRafael Auler
662a34c753fSRafael Auler return true;
663a34c753fSRafael Auler };
664a34c753fSRafael Auler
6653652483cSRafael Auler for (const CFIProgram::Instruction &Instr : CurFDE.getLinkedCIE()->cfis())
666a34c753fSRafael Auler if (!decodeFrameInstruction(Instr))
667a34c753fSRafael Auler return false;
668a34c753fSRafael Auler
6693652483cSRafael Auler for (const CFIProgram::Instruction &Instr : CurFDE.cfis())
670a34c753fSRafael Auler if (!decodeFrameInstruction(Instr))
671a34c753fSRafael Auler return false;
672a34c753fSRafael Auler
673a34c753fSRafael Auler return true;
674a34c753fSRafael Auler }
675a34c753fSRafael Auler
generateEHFrameHeader(const DWARFDebugFrame & OldEHFrame,const DWARFDebugFrame & NewEHFrame,uint64_t EHFrameHeaderAddress,std::vector<uint64_t> & FailedAddresses) const676a34c753fSRafael Auler std::vector<char> CFIReaderWriter::generateEHFrameHeader(
67740c2e0faSMaksim Panchenko const DWARFDebugFrame &OldEHFrame, const DWARFDebugFrame &NewEHFrame,
678a34c753fSRafael Auler uint64_t EHFrameHeaderAddress,
679a34c753fSRafael Auler std::vector<uint64_t> &FailedAddresses) const {
680a34c753fSRafael Auler // Common PC -> FDE map to be written into .eh_frame_hdr.
681a34c753fSRafael Auler std::map<uint64_t, uint64_t> PCToFDE;
682a34c753fSRafael Auler
683a34c753fSRafael Auler // Presort array for binary search.
684d2c87699SAmir Ayupov llvm::sort(FailedAddresses);
685a34c753fSRafael Auler
686a34c753fSRafael Auler // Initialize PCToFDE using NewEHFrame.
687a34c753fSRafael Auler for (dwarf::FrameEntry &Entry : NewEHFrame.entries()) {
688a34c753fSRafael Auler const dwarf::FDE *FDE = dyn_cast<dwarf::FDE>(&Entry);
689a34c753fSRafael Auler if (FDE == nullptr)
690a34c753fSRafael Auler continue;
691a34c753fSRafael Auler const uint64_t FuncAddress = FDE->getInitialLocation();
692a34c753fSRafael Auler const uint64_t FDEAddress =
693a34c753fSRafael Auler NewEHFrame.getEHFrameAddress() + FDE->getOffset();
694a34c753fSRafael Auler
695a34c753fSRafael Auler // Ignore unused FDEs.
696a34c753fSRafael Auler if (FuncAddress == 0)
697a34c753fSRafael Auler continue;
698a34c753fSRafael Auler
699a34c753fSRafael Auler // Add the address to the map unless we failed to write it.
700a34c753fSRafael Auler if (!std::binary_search(FailedAddresses.begin(), FailedAddresses.end(),
701a34c753fSRafael Auler FuncAddress)) {
702a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "BOLT-DEBUG: FDE for function at 0x"
703a34c753fSRafael Auler << Twine::utohexstr(FuncAddress) << " is at 0x"
704a34c753fSRafael Auler << Twine::utohexstr(FDEAddress) << '\n');
705a34c753fSRafael Auler PCToFDE[FuncAddress] = FDEAddress;
706a34c753fSRafael Auler }
707a34c753fSRafael Auler };
708a34c753fSRafael Auler
709a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "BOLT-DEBUG: new .eh_frame contains "
710d2c87699SAmir Ayupov << llvm::size(NewEHFrame.entries()) << " entries\n");
711a34c753fSRafael Auler
712a34c753fSRafael Auler // Add entries from the original .eh_frame corresponding to the functions
713a34c753fSRafael Auler // that we did not update.
714a34c753fSRafael Auler for (const dwarf::FrameEntry &Entry : OldEHFrame) {
715a34c753fSRafael Auler const dwarf::FDE *FDE = dyn_cast<dwarf::FDE>(&Entry);
716a34c753fSRafael Auler if (FDE == nullptr)
717a34c753fSRafael Auler continue;
718a34c753fSRafael Auler const uint64_t FuncAddress = FDE->getInitialLocation();
719a34c753fSRafael Auler const uint64_t FDEAddress =
720a34c753fSRafael Auler OldEHFrame.getEHFrameAddress() + FDE->getOffset();
721a34c753fSRafael Auler
722a34c753fSRafael Auler // Add the address if we failed to write it.
723a34c753fSRafael Auler if (PCToFDE.count(FuncAddress) == 0) {
724a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "BOLT-DEBUG: old FDE for function at 0x"
725a34c753fSRafael Auler << Twine::utohexstr(FuncAddress) << " is at 0x"
726a34c753fSRafael Auler << Twine::utohexstr(FDEAddress) << '\n');
727a34c753fSRafael Auler PCToFDE[FuncAddress] = FDEAddress;
728a34c753fSRafael Auler }
729a34c753fSRafael Auler };
730a34c753fSRafael Auler
731a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "BOLT-DEBUG: old .eh_frame contains "
732d2c87699SAmir Ayupov << llvm::size(OldEHFrame.entries()) << " entries\n");
733a34c753fSRafael Auler
734a34c753fSRafael Auler // Generate a new .eh_frame_hdr based on the new map.
735a34c753fSRafael Auler
736a34c753fSRafael Auler // Header plus table of entries of size 8 bytes.
737a34c753fSRafael Auler std::vector<char> EHFrameHeader(12 + PCToFDE.size() * 8);
738a34c753fSRafael Auler
739a34c753fSRafael Auler // Version is 1.
740a34c753fSRafael Auler EHFrameHeader[0] = 1;
741a34c753fSRafael Auler // Encoding of the eh_frame pointer.
742a34c753fSRafael Auler EHFrameHeader[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4;
743a34c753fSRafael Auler // Encoding of the count field to follow.
744a34c753fSRafael Auler EHFrameHeader[2] = DW_EH_PE_udata4;
745a34c753fSRafael Auler // Encoding of the table entries - 4-byte offset from the start of the header.
746a34c753fSRafael Auler EHFrameHeader[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4;
747a34c753fSRafael Auler
748a34c753fSRafael Auler // Address of eh_frame. Use the new one.
749a34c753fSRafael Auler support::ulittle32_t::ref(EHFrameHeader.data() + 4) =
750a34c753fSRafael Auler NewEHFrame.getEHFrameAddress() - (EHFrameHeaderAddress + 4);
751a34c753fSRafael Auler
752a34c753fSRafael Auler // Number of entries in the table (FDE count).
753a34c753fSRafael Auler support::ulittle32_t::ref(EHFrameHeader.data() + 8) = PCToFDE.size();
754a34c753fSRafael Auler
755a34c753fSRafael Auler // Write the table at offset 12.
756a34c753fSRafael Auler char *Ptr = EHFrameHeader.data();
757a34c753fSRafael Auler uint32_t Offset = 12;
758a34c753fSRafael Auler for (const auto &PCI : PCToFDE) {
759a34c753fSRafael Auler int64_t InitialPCOffset = PCI.first - EHFrameHeaderAddress;
760a34c753fSRafael Auler assert(isInt<32>(InitialPCOffset) && "PC offset out of bounds");
761a34c753fSRafael Auler support::ulittle32_t::ref(Ptr + Offset) = InitialPCOffset;
762a34c753fSRafael Auler Offset += 4;
763a34c753fSRafael Auler int64_t FDEOffset = PCI.second - EHFrameHeaderAddress;
764a34c753fSRafael Auler assert(isInt<32>(FDEOffset) && "FDE offset out of bounds");
765a34c753fSRafael Auler support::ulittle32_t::ref(Ptr + Offset) = FDEOffset;
766a34c753fSRafael Auler Offset += 4;
767a34c753fSRafael Auler }
768a34c753fSRafael Auler
769a34c753fSRafael Auler return EHFrameHeader;
770a34c753fSRafael Auler }
771a34c753fSRafael Auler
parseCIE(uint64_t StartOffset)772a34c753fSRafael Auler Error EHFrameParser::parseCIE(uint64_t StartOffset) {
773a34c753fSRafael Auler uint8_t Version = Data.getU8(&Offset);
774a34c753fSRafael Auler const char *Augmentation = Data.getCStr(&Offset);
775a34c753fSRafael Auler StringRef AugmentationString(Augmentation ? Augmentation : "");
776a34c753fSRafael Auler uint8_t AddressSize =
777a34c753fSRafael Auler Version < 4 ? Data.getAddressSize() : Data.getU8(&Offset);
778a34c753fSRafael Auler Data.setAddressSize(AddressSize);
779a34c753fSRafael Auler // Skip segment descriptor size
780a34c753fSRafael Auler if (Version >= 4)
781a34c753fSRafael Auler Offset += 1;
782a34c753fSRafael Auler // Skip code alignment factor
783a34c753fSRafael Auler Data.getULEB128(&Offset);
784a34c753fSRafael Auler // Skip data alignment
785a34c753fSRafael Auler Data.getSLEB128(&Offset);
786a34c753fSRafael Auler // Skip return address register
7873652483cSRafael Auler if (Version == 1)
788a34c753fSRafael Auler Offset += 1;
7893652483cSRafael Auler else
790a34c753fSRafael Auler Data.getULEB128(&Offset);
791a34c753fSRafael Auler
792a34c753fSRafael Auler uint32_t FDEPointerEncoding = DW_EH_PE_absptr;
793a34c753fSRafael Auler uint32_t LSDAPointerEncoding = DW_EH_PE_omit;
794a34c753fSRafael Auler // Walk the augmentation string to get all the augmentation data.
795a34c753fSRafael Auler for (unsigned i = 0, e = AugmentationString.size(); i != e; ++i) {
796a34c753fSRafael Auler switch (AugmentationString[i]) {
797a34c753fSRafael Auler default:
798a34c753fSRafael Auler return createStringError(
799a34c753fSRafael Auler errc::invalid_argument,
800a34c753fSRafael Auler "unknown augmentation character in entry at 0x%" PRIx64, StartOffset);
801a34c753fSRafael Auler case 'L':
802a34c753fSRafael Auler LSDAPointerEncoding = Data.getU8(&Offset);
803a34c753fSRafael Auler break;
804a34c753fSRafael Auler case 'P': {
805a34c753fSRafael Auler uint32_t PersonalityEncoding = Data.getU8(&Offset);
806a34c753fSRafael Auler Optional<uint64_t> Personality =
807a34c753fSRafael Auler Data.getEncodedPointer(&Offset, PersonalityEncoding,
808a34c753fSRafael Auler EHFrameAddress ? EHFrameAddress + Offset : 0);
809a34c753fSRafael Auler // Patch personality address
810a34c753fSRafael Auler if (Personality)
811a34c753fSRafael Auler PatcherCallback(*Personality, Offset, PersonalityEncoding);
812a34c753fSRafael Auler break;
813a34c753fSRafael Auler }
814a34c753fSRafael Auler case 'R':
815a34c753fSRafael Auler FDEPointerEncoding = Data.getU8(&Offset);
816a34c753fSRafael Auler break;
817a34c753fSRafael Auler case 'z':
818a34c753fSRafael Auler if (i)
819a34c753fSRafael Auler return createStringError(
820a34c753fSRafael Auler errc::invalid_argument,
821a34c753fSRafael Auler "'z' must be the first character at 0x%" PRIx64, StartOffset);
822a34c753fSRafael Auler // Skip augmentation length
823a34c753fSRafael Auler Data.getULEB128(&Offset);
824a34c753fSRafael Auler break;
825a34c753fSRafael Auler case 'S':
826a34c753fSRafael Auler case 'B':
827a34c753fSRafael Auler break;
828a34c753fSRafael Auler }
829a34c753fSRafael Auler }
830a34c753fSRafael Auler Entries.emplace_back(std::make_unique<CIEInfo>(
831a34c753fSRafael Auler FDEPointerEncoding, LSDAPointerEncoding, AugmentationString));
832a34c753fSRafael Auler CIEs[StartOffset] = &*Entries.back();
833a34c753fSRafael Auler return Error::success();
834a34c753fSRafael Auler }
835a34c753fSRafael Auler
parseFDE(uint64_t CIEPointer,uint64_t StartStructureOffset)836a34c753fSRafael Auler Error EHFrameParser::parseFDE(uint64_t CIEPointer,
837a34c753fSRafael Auler uint64_t StartStructureOffset) {
838a34c753fSRafael Auler Optional<uint64_t> LSDAAddress;
839a34c753fSRafael Auler CIEInfo *Cie = CIEs[StartStructureOffset - CIEPointer];
840a34c753fSRafael Auler
841a34c753fSRafael Auler // The address size is encoded in the CIE we reference.
842a34c753fSRafael Auler if (!Cie)
843a34c753fSRafael Auler return createStringError(errc::invalid_argument,
844a34c753fSRafael Auler "parsing FDE data at 0x%" PRIx64
845a34c753fSRafael Auler " failed due to missing CIE",
846a34c753fSRafael Auler StartStructureOffset);
847a34c753fSRafael Auler // Patch initial location
848a34c753fSRafael Auler if (auto Val = Data.getEncodedPointer(&Offset, Cie->FDEPtrEncoding,
849a34c753fSRafael Auler EHFrameAddress + Offset)) {
850a34c753fSRafael Auler PatcherCallback(*Val, Offset, Cie->FDEPtrEncoding);
851a34c753fSRafael Auler }
852a34c753fSRafael Auler // Skip address range
853a34c753fSRafael Auler Data.getEncodedPointer(&Offset, Cie->FDEPtrEncoding, 0);
854a34c753fSRafael Auler
855a34c753fSRafael Auler // Process augmentation data for this FDE.
856a34c753fSRafael Auler StringRef AugmentationString = Cie->AugmentationString;
857a34c753fSRafael Auler if (!AugmentationString.empty() && Cie->LSDAPtrEncoding != DW_EH_PE_omit) {
858a34c753fSRafael Auler // Skip augmentation length
859a34c753fSRafael Auler Data.getULEB128(&Offset);
860a34c753fSRafael Auler LSDAAddress =
861a34c753fSRafael Auler Data.getEncodedPointer(&Offset, Cie->LSDAPtrEncoding,
862a34c753fSRafael Auler EHFrameAddress ? Offset + EHFrameAddress : 0);
863a34c753fSRafael Auler // Patch LSDA address
864a34c753fSRafael Auler PatcherCallback(*LSDAAddress, Offset, Cie->LSDAPtrEncoding);
865a34c753fSRafael Auler }
866a34c753fSRafael Auler return Error::success();
867a34c753fSRafael Auler }
868a34c753fSRafael Auler
parse()869a34c753fSRafael Auler Error EHFrameParser::parse() {
870a34c753fSRafael Auler while (Data.isValidOffset(Offset)) {
871a34c753fSRafael Auler const uint64_t StartOffset = Offset;
872a34c753fSRafael Auler
873a34c753fSRafael Auler uint64_t Length;
874a34c753fSRafael Auler DwarfFormat Format;
875a34c753fSRafael Auler std::tie(Length, Format) = Data.getInitialLength(&Offset);
876a34c753fSRafael Auler
877a34c753fSRafael Auler // If the Length is 0, then this CIE is a terminator
878a34c753fSRafael Auler if (Length == 0)
879a34c753fSRafael Auler break;
880a34c753fSRafael Auler
881a34c753fSRafael Auler const uint64_t StartStructureOffset = Offset;
882a34c753fSRafael Auler const uint64_t EndStructureOffset = Offset + Length;
883a34c753fSRafael Auler
884a34c753fSRafael Auler Error Err = Error::success();
885a34c753fSRafael Auler const uint64_t Id = Data.getRelocatedValue(4, &Offset,
886a34c753fSRafael Auler /*SectionIndex=*/nullptr, &Err);
887a34c753fSRafael Auler if (Err)
888a34c753fSRafael Auler return Err;
889a34c753fSRafael Auler
890a34c753fSRafael Auler if (!Id) {
891a34c753fSRafael Auler if (Error Err = parseCIE(StartOffset))
892a34c753fSRafael Auler return Err;
893a34c753fSRafael Auler } else {
894a34c753fSRafael Auler if (Error Err = parseFDE(Id, StartStructureOffset))
895a34c753fSRafael Auler return Err;
896a34c753fSRafael Auler }
897a34c753fSRafael Auler Offset = EndStructureOffset;
898a34c753fSRafael Auler }
899a34c753fSRafael Auler
900a34c753fSRafael Auler return Error::success();
901a34c753fSRafael Auler }
902a34c753fSRafael Auler
parse(DWARFDataExtractor Data,uint64_t EHFrameAddress,PatcherCallbackTy PatcherCallback)903a34c753fSRafael Auler Error EHFrameParser::parse(DWARFDataExtractor Data, uint64_t EHFrameAddress,
904a34c753fSRafael Auler PatcherCallbackTy PatcherCallback) {
905a34c753fSRafael Auler EHFrameParser Parser(Data, EHFrameAddress, PatcherCallback);
906a34c753fSRafael Auler return Parser.parse();
907a34c753fSRafael Auler }
908a34c753fSRafael Auler
909a34c753fSRafael Auler } // namespace bolt
910a34c753fSRafael Auler } // namespace llvm
911