xref: /openbsd-src/gnu/llvm/libunwind/src/DwarfParser.hpp (revision 202cdb0e0a5b97857d0b77e650500ce112f967da)
1*202cdb0eSrobert //===----------------------------------------------------------------------===//
2f6c50668Spatrick //
3f6c50668Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4f6c50668Spatrick // See https://llvm.org/LICENSE.txt for license information.
5f6c50668Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f6c50668Spatrick //
7f6c50668Spatrick //
8f6c50668Spatrick //  Parses DWARF CFIs (FDEs and CIEs).
9f6c50668Spatrick //
10f6c50668Spatrick //===----------------------------------------------------------------------===//
11f6c50668Spatrick 
12f6c50668Spatrick #ifndef __DWARF_PARSER_HPP__
13f6c50668Spatrick #define __DWARF_PARSER_HPP__
14f6c50668Spatrick 
15f6c50668Spatrick #include <inttypes.h>
16f6c50668Spatrick #include <stdint.h>
17f6c50668Spatrick #include <stdio.h>
18f6c50668Spatrick #include <stdlib.h>
19f6c50668Spatrick 
20f6c50668Spatrick #include "libunwind.h"
21f6c50668Spatrick #include "dwarf2.h"
22f6c50668Spatrick #include "Registers.hpp"
23f6c50668Spatrick 
24f6c50668Spatrick #include "config.h"
25f6c50668Spatrick 
26f6c50668Spatrick namespace libunwind {
27f6c50668Spatrick 
28f6c50668Spatrick /// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
29f6c50668Spatrick /// See DWARF Spec for details:
30f6c50668Spatrick ///    http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
31f6c50668Spatrick ///
32f6c50668Spatrick template <typename A>
33f6c50668Spatrick class CFI_Parser {
34f6c50668Spatrick public:
35f6c50668Spatrick   typedef typename A::pint_t pint_t;
36f6c50668Spatrick 
37f6c50668Spatrick   /// Information encoded in a CIE (Common Information Entry)
38f6c50668Spatrick   struct CIE_Info {
39f6c50668Spatrick     pint_t    cieStart;
40f6c50668Spatrick     pint_t    cieLength;
41f6c50668Spatrick     pint_t    cieInstructions;
42f6c50668Spatrick     uint8_t   pointerEncoding;
43f6c50668Spatrick     uint8_t   lsdaEncoding;
44f6c50668Spatrick     uint8_t   personalityEncoding;
45f6c50668Spatrick     uint8_t   personalityOffsetInCIE;
46f6c50668Spatrick     pint_t    personality;
47f6c50668Spatrick     uint32_t  codeAlignFactor;
48f6c50668Spatrick     int       dataAlignFactor;
49f6c50668Spatrick     bool      isSignalFrame;
50f6c50668Spatrick     bool      fdesHaveAugmentationData;
51f6c50668Spatrick     uint8_t   returnAddressRegister;
52f6c50668Spatrick #if defined(_LIBUNWIND_TARGET_AARCH64)
53f6c50668Spatrick     bool      addressesSignedWithBKey;
54*202cdb0eSrobert     bool      mteTaggedFrame;
55f6c50668Spatrick #endif
56f6c50668Spatrick   };
57f6c50668Spatrick 
58f6c50668Spatrick   /// Information about an FDE (Frame Description Entry)
59f6c50668Spatrick   struct FDE_Info {
60f6c50668Spatrick     pint_t  fdeStart;
61f6c50668Spatrick     pint_t  fdeLength;
62f6c50668Spatrick     pint_t  fdeInstructions;
63f6c50668Spatrick     pint_t  pcStart;
64f6c50668Spatrick     pint_t  pcEnd;
65f6c50668Spatrick     pint_t  lsda;
66f6c50668Spatrick   };
67f6c50668Spatrick 
68f6c50668Spatrick   enum {
69f6c50668Spatrick     kMaxRegisterNumber = _LIBUNWIND_HIGHEST_DWARF_REGISTER
70f6c50668Spatrick   };
71f6c50668Spatrick   enum RegisterSavedWhere {
72f6c50668Spatrick     kRegisterUnused,
73a0747c9fSpatrick     kRegisterUndefined,
74f6c50668Spatrick     kRegisterInCFA,
75*202cdb0eSrobert     kRegisterInCFADecrypt, // sparc64 specific
76f6c50668Spatrick     kRegisterOffsetFromCFA,
77f6c50668Spatrick     kRegisterInRegister,
78f6c50668Spatrick     kRegisterAtExpression,
79f6c50668Spatrick     kRegisterIsExpression
80f6c50668Spatrick   };
81f6c50668Spatrick   struct RegisterLocation {
82f6c50668Spatrick     RegisterSavedWhere location;
83f6c50668Spatrick     bool initialStateSaved;
84f6c50668Spatrick     int64_t value;
85f6c50668Spatrick   };
86f6c50668Spatrick   /// Information about a frame layout and registers saved determined
87f6c50668Spatrick   /// by "running" the DWARF FDE "instructions"
88f6c50668Spatrick   struct PrologInfo {
89f6c50668Spatrick     uint32_t          cfaRegister;
90f6c50668Spatrick     int32_t           cfaRegisterOffset;  // CFA = (cfaRegister)+cfaRegisterOffset
91f6c50668Spatrick     int64_t           cfaExpression;      // CFA = expression
92f6c50668Spatrick     uint32_t          spExtraArgSize;
93f6c50668Spatrick     RegisterLocation  savedRegisters[kMaxRegisterNumber + 1];
94f6c50668Spatrick     enum class InitializeTime { kLazy, kNormal };
95f6c50668Spatrick 
96f6c50668Spatrick     // When saving registers, this data structure is lazily initialized.
PrologInfolibunwind::CFI_Parser::PrologInfo97f6c50668Spatrick     PrologInfo(InitializeTime IT = InitializeTime::kNormal) {
98f6c50668Spatrick       if (IT == InitializeTime::kNormal)
99f6c50668Spatrick         memset(this, 0, sizeof(*this));
100f6c50668Spatrick     }
checkSaveRegisterlibunwind::CFI_Parser::PrologInfo101f6c50668Spatrick     void checkSaveRegister(uint64_t reg, PrologInfo &initialState) {
102f6c50668Spatrick       if (!savedRegisters[reg].initialStateSaved) {
103f6c50668Spatrick         initialState.savedRegisters[reg] = savedRegisters[reg];
104f6c50668Spatrick         savedRegisters[reg].initialStateSaved = true;
105f6c50668Spatrick       }
106f6c50668Spatrick     }
setRegisterlibunwind::CFI_Parser::PrologInfo107f6c50668Spatrick     void setRegister(uint64_t reg, RegisterSavedWhere newLocation,
108f6c50668Spatrick                      int64_t newValue, PrologInfo &initialState) {
109f6c50668Spatrick       checkSaveRegister(reg, initialState);
110f6c50668Spatrick       savedRegisters[reg].location = newLocation;
111f6c50668Spatrick       savedRegisters[reg].value = newValue;
112f6c50668Spatrick     }
setRegisterLocationlibunwind::CFI_Parser::PrologInfo113f6c50668Spatrick     void setRegisterLocation(uint64_t reg, RegisterSavedWhere newLocation,
114f6c50668Spatrick                              PrologInfo &initialState) {
115f6c50668Spatrick       checkSaveRegister(reg, initialState);
116f6c50668Spatrick       savedRegisters[reg].location = newLocation;
117f6c50668Spatrick     }
setRegisterValuelibunwind::CFI_Parser::PrologInfo118f6c50668Spatrick     void setRegisterValue(uint64_t reg, int64_t newValue,
119f6c50668Spatrick                           PrologInfo &initialState) {
120f6c50668Spatrick       checkSaveRegister(reg, initialState);
121f6c50668Spatrick       savedRegisters[reg].value = newValue;
122f6c50668Spatrick     }
restoreRegisterToInitialStatelibunwind::CFI_Parser::PrologInfo123f6c50668Spatrick     void restoreRegisterToInitialState(uint64_t reg, PrologInfo &initialState) {
124f6c50668Spatrick       if (savedRegisters[reg].initialStateSaved)
125f6c50668Spatrick         savedRegisters[reg] = initialState.savedRegisters[reg];
126f6c50668Spatrick       // else the register still holds its initial state
127f6c50668Spatrick     }
128f6c50668Spatrick   };
129f6c50668Spatrick 
130f6c50668Spatrick   struct PrologInfoStackEntry {
PrologInfoStackEntrylibunwind::CFI_Parser::PrologInfoStackEntry131f6c50668Spatrick     PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i)
132f6c50668Spatrick         : next(n), info(i) {}
133f6c50668Spatrick     PrologInfoStackEntry *next;
134f6c50668Spatrick     PrologInfo info;
135f6c50668Spatrick   };
136f6c50668Spatrick 
137a0747c9fSpatrick   struct RememberStack {
138a0747c9fSpatrick     PrologInfoStackEntry *entry;
RememberStacklibunwind::CFI_Parser::RememberStack139a0747c9fSpatrick     RememberStack() : entry(nullptr) {}
~RememberStacklibunwind::CFI_Parser::RememberStack140a0747c9fSpatrick     ~RememberStack() {
141a0747c9fSpatrick #if defined(_LIBUNWIND_REMEMBER_CLEANUP_NEEDED)
142a0747c9fSpatrick       // Clean up rememberStack. Even in the case where every
143a0747c9fSpatrick       // DW_CFA_remember_state is paired with a DW_CFA_restore_state,
144a0747c9fSpatrick       // parseInstructions can skip restore opcodes if it reaches the target PC
145a0747c9fSpatrick       // and stops interpreting, so we have to make sure we don't leak memory.
146a0747c9fSpatrick       while (entry) {
147a0747c9fSpatrick         PrologInfoStackEntry *next = entry->next;
148a0747c9fSpatrick         _LIBUNWIND_REMEMBER_FREE(entry);
149a0747c9fSpatrick         entry = next;
150a0747c9fSpatrick       }
151a0747c9fSpatrick #endif
152a0747c9fSpatrick     }
153a0747c9fSpatrick   };
154a0747c9fSpatrick 
155f6c50668Spatrick   static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
156*202cdb0eSrobert                       size_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
157f6c50668Spatrick                       CIE_Info *cieInfo);
158f6c50668Spatrick   static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
159*202cdb0eSrobert                                FDE_Info *fdeInfo, CIE_Info *cieInfo,
160*202cdb0eSrobert                                bool useCIEInfo = false);
161f6c50668Spatrick   static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,
162f6c50668Spatrick                                    const CIE_Info &cieInfo, pint_t upToPC,
163f6c50668Spatrick                                    int arch, PrologInfo *results);
164f6c50668Spatrick 
165f6c50668Spatrick   static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
166f6c50668Spatrick };
167f6c50668Spatrick 
168*202cdb0eSrobert /// Parse a FDE into a CIE_Info and an FDE_Info. If useCIEInfo is
169*202cdb0eSrobert /// true, treat cieInfo as already-parsed CIE_Info (whose start offset
170*202cdb0eSrobert /// must match the one specified by the FDE) rather than parsing the
171*202cdb0eSrobert /// one indicated within the FDE.
172f6c50668Spatrick template <typename A>
decodeFDE(A & addressSpace,pint_t fdeStart,FDE_Info * fdeInfo,CIE_Info * cieInfo,bool useCIEInfo)173f6c50668Spatrick const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
174*202cdb0eSrobert                                      FDE_Info *fdeInfo, CIE_Info *cieInfo,
175*202cdb0eSrobert                                      bool useCIEInfo) {
176f6c50668Spatrick   pint_t p = fdeStart;
177f6c50668Spatrick   pint_t cfiLength = (pint_t)addressSpace.get32(p);
178f6c50668Spatrick   p += 4;
179f6c50668Spatrick   if (cfiLength == 0xffffffff) {
180f6c50668Spatrick     // 0xffffffff means length is really next 8 bytes
181f6c50668Spatrick     cfiLength = (pint_t)addressSpace.get64(p);
182f6c50668Spatrick     p += 8;
183f6c50668Spatrick   }
184f6c50668Spatrick   if (cfiLength == 0)
185a0747c9fSpatrick     return "FDE has zero length"; // zero terminator
186f6c50668Spatrick   uint32_t ciePointer = addressSpace.get32(p);
187f6c50668Spatrick   if (ciePointer == 0)
188f6c50668Spatrick     return "FDE is really a CIE"; // this is a CIE not an FDE
189f6c50668Spatrick   pint_t nextCFI = p + cfiLength;
190f6c50668Spatrick   pint_t cieStart = p - ciePointer;
191*202cdb0eSrobert   if (useCIEInfo) {
192*202cdb0eSrobert     if (cieInfo->cieStart != cieStart)
193*202cdb0eSrobert       return "CIE start does not match";
194*202cdb0eSrobert   } else {
195f6c50668Spatrick     const char *err = parseCIE(addressSpace, cieStart, cieInfo);
196f6c50668Spatrick     if (err != NULL)
197f6c50668Spatrick       return err;
198*202cdb0eSrobert   }
199f6c50668Spatrick   p += 4;
200f6c50668Spatrick   // Parse pc begin and range.
201f6c50668Spatrick   pint_t pcStart =
202f6c50668Spatrick       addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
203f6c50668Spatrick   pint_t pcRange =
204f6c50668Spatrick       addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
205f6c50668Spatrick   // Parse rest of info.
206f6c50668Spatrick   fdeInfo->lsda = 0;
207f6c50668Spatrick   // Check for augmentation length.
208f6c50668Spatrick   if (cieInfo->fdesHaveAugmentationData) {
209f6c50668Spatrick     pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
210f6c50668Spatrick     pint_t endOfAug = p + augLen;
211f6c50668Spatrick     if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
212f6c50668Spatrick       // Peek at value (without indirection).  Zero means no LSDA.
213f6c50668Spatrick       pint_t lsdaStart = p;
214f6c50668Spatrick       if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) !=
215f6c50668Spatrick           0) {
216f6c50668Spatrick         // Reset pointer and re-parse LSDA address.
217f6c50668Spatrick         p = lsdaStart;
218f6c50668Spatrick         fdeInfo->lsda =
219f6c50668Spatrick             addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
220f6c50668Spatrick       }
221f6c50668Spatrick     }
222f6c50668Spatrick     p = endOfAug;
223f6c50668Spatrick   }
224f6c50668Spatrick   fdeInfo->fdeStart = fdeStart;
225f6c50668Spatrick   fdeInfo->fdeLength = nextCFI - fdeStart;
226f6c50668Spatrick   fdeInfo->fdeInstructions = p;
227f6c50668Spatrick   fdeInfo->pcStart = pcStart;
228f6c50668Spatrick   fdeInfo->pcEnd = pcStart + pcRange;
229f6c50668Spatrick   return NULL; // success
230f6c50668Spatrick }
231f6c50668Spatrick 
232f6c50668Spatrick /// Scan an eh_frame section to find an FDE for a pc
233f6c50668Spatrick template <typename A>
findFDE(A & addressSpace,pint_t pc,pint_t ehSectionStart,size_t sectionLength,pint_t fdeHint,FDE_Info * fdeInfo,CIE_Info * cieInfo)234f6c50668Spatrick bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
235*202cdb0eSrobert                             size_t sectionLength, pint_t fdeHint,
236f6c50668Spatrick                             FDE_Info *fdeInfo, CIE_Info *cieInfo) {
237f6c50668Spatrick   //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
238f6c50668Spatrick   pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
239*202cdb0eSrobert   const pint_t ehSectionEnd = (sectionLength == SIZE_MAX)
240a0747c9fSpatrick                                   ? static_cast<pint_t>(-1)
241a0747c9fSpatrick                                   : (ehSectionStart + sectionLength);
242f6c50668Spatrick   while (p < ehSectionEnd) {
243f6c50668Spatrick     pint_t currentCFI = p;
244f6c50668Spatrick     //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
245f6c50668Spatrick     pint_t cfiLength = addressSpace.get32(p);
246f6c50668Spatrick     p += 4;
247f6c50668Spatrick     if (cfiLength == 0xffffffff) {
248f6c50668Spatrick       // 0xffffffff means length is really next 8 bytes
249f6c50668Spatrick       cfiLength = (pint_t)addressSpace.get64(p);
250f6c50668Spatrick       p += 8;
251f6c50668Spatrick     }
252f6c50668Spatrick     if (cfiLength == 0)
253a0747c9fSpatrick       return false; // zero terminator
254f6c50668Spatrick     uint32_t id = addressSpace.get32(p);
255f6c50668Spatrick     if (id == 0) {
256f6c50668Spatrick       // Skip over CIEs.
257f6c50668Spatrick       p += cfiLength;
258f6c50668Spatrick     } else {
259f6c50668Spatrick       // Process FDE to see if it covers pc.
260f6c50668Spatrick       pint_t nextCFI = p + cfiLength;
261f6c50668Spatrick       uint32_t ciePointer = addressSpace.get32(p);
262f6c50668Spatrick       pint_t cieStart = p - ciePointer;
263f6c50668Spatrick       // Validate pointer to CIE is within section.
264f6c50668Spatrick       if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) {
265f6c50668Spatrick         if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) {
266f6c50668Spatrick           p += 4;
267f6c50668Spatrick           // Parse pc begin and range.
268f6c50668Spatrick           pint_t pcStart =
269f6c50668Spatrick               addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
270f6c50668Spatrick           pint_t pcRange = addressSpace.getEncodedP(
271f6c50668Spatrick               p, nextCFI, cieInfo->pointerEncoding & 0x0F);
272f6c50668Spatrick           // Test if pc is within the function this FDE covers.
273f6c50668Spatrick           if ((pcStart < pc) && (pc <= pcStart + pcRange)) {
274f6c50668Spatrick             // parse rest of info
275f6c50668Spatrick             fdeInfo->lsda = 0;
276f6c50668Spatrick             // check for augmentation length
277f6c50668Spatrick             if (cieInfo->fdesHaveAugmentationData) {
278f6c50668Spatrick               pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
279f6c50668Spatrick               pint_t endOfAug = p + augLen;
280f6c50668Spatrick               if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
281f6c50668Spatrick                 // Peek at value (without indirection).  Zero means no LSDA.
282f6c50668Spatrick                 pint_t lsdaStart = p;
283f6c50668Spatrick                 if (addressSpace.getEncodedP(
284f6c50668Spatrick                         p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) {
285f6c50668Spatrick                   // Reset pointer and re-parse LSDA address.
286f6c50668Spatrick                   p = lsdaStart;
287f6c50668Spatrick                   fdeInfo->lsda = addressSpace
288f6c50668Spatrick                       .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
289f6c50668Spatrick                 }
290f6c50668Spatrick               }
291f6c50668Spatrick               p = endOfAug;
292f6c50668Spatrick             }
293f6c50668Spatrick             fdeInfo->fdeStart = currentCFI;
294f6c50668Spatrick             fdeInfo->fdeLength = nextCFI - currentCFI;
295f6c50668Spatrick             fdeInfo->fdeInstructions = p;
296f6c50668Spatrick             fdeInfo->pcStart = pcStart;
297f6c50668Spatrick             fdeInfo->pcEnd = pcStart + pcRange;
298f6c50668Spatrick             return true;
299f6c50668Spatrick           } else {
300f6c50668Spatrick             // pc is not in begin/range, skip this FDE
301f6c50668Spatrick           }
302f6c50668Spatrick         } else {
303f6c50668Spatrick           // Malformed CIE, now augmentation describing pc range encoding.
304f6c50668Spatrick         }
305f6c50668Spatrick       } else {
306f6c50668Spatrick         // malformed FDE.  CIE is bad
307f6c50668Spatrick       }
308f6c50668Spatrick       p = nextCFI;
309f6c50668Spatrick     }
310f6c50668Spatrick   }
311f6c50668Spatrick   return false;
312f6c50668Spatrick }
313f6c50668Spatrick 
314f6c50668Spatrick /// Extract info from a CIE
315f6c50668Spatrick template <typename A>
parseCIE(A & addressSpace,pint_t cie,CIE_Info * cieInfo)316f6c50668Spatrick const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
317f6c50668Spatrick                                     CIE_Info *cieInfo) {
318f6c50668Spatrick   cieInfo->pointerEncoding = 0;
319f6c50668Spatrick   cieInfo->lsdaEncoding = DW_EH_PE_omit;
320f6c50668Spatrick   cieInfo->personalityEncoding = 0;
321f6c50668Spatrick   cieInfo->personalityOffsetInCIE = 0;
322f6c50668Spatrick   cieInfo->personality = 0;
323f6c50668Spatrick   cieInfo->codeAlignFactor = 0;
324f6c50668Spatrick   cieInfo->dataAlignFactor = 0;
325f6c50668Spatrick   cieInfo->isSignalFrame = false;
326f6c50668Spatrick   cieInfo->fdesHaveAugmentationData = false;
327f6c50668Spatrick #if defined(_LIBUNWIND_TARGET_AARCH64)
328f6c50668Spatrick   cieInfo->addressesSignedWithBKey = false;
329*202cdb0eSrobert   cieInfo->mteTaggedFrame = false;
330f6c50668Spatrick #endif
331f6c50668Spatrick   cieInfo->cieStart = cie;
332f6c50668Spatrick   pint_t p = cie;
333f6c50668Spatrick   pint_t cieLength = (pint_t)addressSpace.get32(p);
334f6c50668Spatrick   p += 4;
335f6c50668Spatrick   pint_t cieContentEnd = p + cieLength;
336f6c50668Spatrick   if (cieLength == 0xffffffff) {
337f6c50668Spatrick     // 0xffffffff means length is really next 8 bytes
338f6c50668Spatrick     cieLength = (pint_t)addressSpace.get64(p);
339f6c50668Spatrick     p += 8;
340f6c50668Spatrick     cieContentEnd = p + cieLength;
341f6c50668Spatrick   }
342f6c50668Spatrick   if (cieLength == 0)
343f6c50668Spatrick     return NULL;
344f6c50668Spatrick   // CIE ID is always 0
345f6c50668Spatrick   if (addressSpace.get32(p) != 0)
346f6c50668Spatrick     return "CIE ID is not zero";
347f6c50668Spatrick   p += 4;
348f6c50668Spatrick   // Version is always 1 or 3
349f6c50668Spatrick   uint8_t version = addressSpace.get8(p);
350f6c50668Spatrick   if ((version != 1) && (version != 3))
351f6c50668Spatrick     return "CIE version is not 1 or 3";
352f6c50668Spatrick   ++p;
353f6c50668Spatrick   // save start of augmentation string and find end
354f6c50668Spatrick   pint_t strStart = p;
355f6c50668Spatrick   while (addressSpace.get8(p) != 0)
356f6c50668Spatrick     ++p;
357f6c50668Spatrick   ++p;
358*202cdb0eSrobert   // parse code alignment factor
359f6c50668Spatrick   cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd);
360f6c50668Spatrick   // parse data alignment factor
361f6c50668Spatrick   cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd);
362f6c50668Spatrick   // parse return address register
363a0747c9fSpatrick   uint64_t raReg = (version == 1) ? addressSpace.get8(p++)
364a0747c9fSpatrick                                   : addressSpace.getULEB128(p, cieContentEnd);
365f6c50668Spatrick   assert(raReg < 255 && "return address register too large");
366f6c50668Spatrick   cieInfo->returnAddressRegister = (uint8_t)raReg;
367f6c50668Spatrick   // parse augmentation data based on augmentation string
368f6c50668Spatrick   const char *result = NULL;
369f6c50668Spatrick   if (addressSpace.get8(strStart) == 'z') {
370f6c50668Spatrick     // parse augmentation data length
371f6c50668Spatrick     addressSpace.getULEB128(p, cieContentEnd);
372f6c50668Spatrick     for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) {
373f6c50668Spatrick       switch (addressSpace.get8(s)) {
374f6c50668Spatrick       case 'z':
375f6c50668Spatrick         cieInfo->fdesHaveAugmentationData = true;
376f6c50668Spatrick         break;
377f6c50668Spatrick       case 'P':
378f6c50668Spatrick         cieInfo->personalityEncoding = addressSpace.get8(p);
379f6c50668Spatrick         ++p;
380f6c50668Spatrick         cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie);
381f6c50668Spatrick         cieInfo->personality = addressSpace
382f6c50668Spatrick             .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
383f6c50668Spatrick         break;
384f6c50668Spatrick       case 'L':
385f6c50668Spatrick         cieInfo->lsdaEncoding = addressSpace.get8(p);
386f6c50668Spatrick         ++p;
387f6c50668Spatrick         break;
388f6c50668Spatrick       case 'R':
389f6c50668Spatrick         cieInfo->pointerEncoding = addressSpace.get8(p);
390f6c50668Spatrick         ++p;
391f6c50668Spatrick         break;
392f6c50668Spatrick       case 'S':
393f6c50668Spatrick         cieInfo->isSignalFrame = true;
394f6c50668Spatrick         break;
395f6c50668Spatrick #if defined(_LIBUNWIND_TARGET_AARCH64)
396f6c50668Spatrick       case 'B':
397f6c50668Spatrick         cieInfo->addressesSignedWithBKey = true;
398f6c50668Spatrick         break;
399*202cdb0eSrobert       case 'G':
400*202cdb0eSrobert         cieInfo->mteTaggedFrame = true;
401*202cdb0eSrobert         break;
402f6c50668Spatrick #endif
403f6c50668Spatrick       default:
404f6c50668Spatrick         // ignore unknown letters
405f6c50668Spatrick         break;
406f6c50668Spatrick       }
407f6c50668Spatrick     }
408f6c50668Spatrick   }
409f6c50668Spatrick   cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
410f6c50668Spatrick   cieInfo->cieInstructions = p;
411f6c50668Spatrick   return result;
412f6c50668Spatrick }
413f6c50668Spatrick 
414f6c50668Spatrick 
415*202cdb0eSrobert /// "run" the DWARF instructions and create the abstract PrologInfo for an FDE
416f6c50668Spatrick template <typename A>
parseFDEInstructions(A & addressSpace,const FDE_Info & fdeInfo,const CIE_Info & cieInfo,pint_t upToPC,int arch,PrologInfo * results)417f6c50668Spatrick bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
418f6c50668Spatrick                                          const FDE_Info &fdeInfo,
419f6c50668Spatrick                                          const CIE_Info &cieInfo, pint_t upToPC,
420f6c50668Spatrick                                          int arch, PrologInfo *results) {
421a0747c9fSpatrick   // Alloca is used for the allocation of the rememberStack entries. It removes
422a0747c9fSpatrick   // the dependency on new/malloc but the below for loop can not be refactored
423a0747c9fSpatrick   // into functions. Entry could be saved during the processing of a CIE and
424a0747c9fSpatrick   // restored by an FDE.
425a0747c9fSpatrick   RememberStack rememberStack;
426f6c50668Spatrick 
427a0747c9fSpatrick   struct ParseInfo {
428a0747c9fSpatrick     pint_t instructions;
429a0747c9fSpatrick     pint_t instructionsEnd;
430a0747c9fSpatrick     pint_t pcoffset;
431a0747c9fSpatrick   };
432f6c50668Spatrick 
433a0747c9fSpatrick   ParseInfo parseInfoArray[] = {
434a0747c9fSpatrick       {cieInfo.cieInstructions, cieInfo.cieStart + cieInfo.cieLength,
435a0747c9fSpatrick        (pint_t)(-1)},
436a0747c9fSpatrick       {fdeInfo.fdeInstructions, fdeInfo.fdeStart + fdeInfo.fdeLength,
437a0747c9fSpatrick        upToPC - fdeInfo.pcStart}};
438f6c50668Spatrick 
439a0747c9fSpatrick   for (const auto &info : parseInfoArray) {
440a0747c9fSpatrick     pint_t p = info.instructions;
441a0747c9fSpatrick     pint_t instructionsEnd = info.instructionsEnd;
442a0747c9fSpatrick     pint_t pcoffset = info.pcoffset;
443f6c50668Spatrick     pint_t codeOffset = 0;
444a0747c9fSpatrick 
445f6c50668Spatrick     // initialState initialized as registers in results are modified. Use
446f6c50668Spatrick     // PrologInfo accessor functions to avoid reading uninitialized data.
447f6c50668Spatrick     PrologInfo initialState(PrologInfo::InitializeTime::kLazy);
448f6c50668Spatrick 
449a0747c9fSpatrick     _LIBUNWIND_TRACE_DWARF("parseFDEInstructions(instructions=0x%0" PRIx64
450a0747c9fSpatrick                            ")\n",
451f6c50668Spatrick                            static_cast<uint64_t>(instructionsEnd));
452f6c50668Spatrick 
453f6c50668Spatrick     // see DWARF Spec, section 6.4.2 for details on unwind opcodes
454f6c50668Spatrick     while ((p < instructionsEnd) && (codeOffset < pcoffset)) {
455f6c50668Spatrick       uint64_t reg;
456f6c50668Spatrick       uint64_t reg2;
457f6c50668Spatrick       int64_t offset;
458f6c50668Spatrick       uint64_t length;
459f6c50668Spatrick       uint8_t opcode = addressSpace.get8(p);
460f6c50668Spatrick       uint8_t operand;
461a0747c9fSpatrick 
462f6c50668Spatrick       ++p;
463f6c50668Spatrick       switch (opcode) {
464f6c50668Spatrick       case DW_CFA_nop:
465f6c50668Spatrick         _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n");
466f6c50668Spatrick         break;
467f6c50668Spatrick       case DW_CFA_set_loc:
468a0747c9fSpatrick         codeOffset = addressSpace.getEncodedP(p, instructionsEnd,
469a0747c9fSpatrick                                               cieInfo.pointerEncoding);
470f6c50668Spatrick         _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n");
471f6c50668Spatrick         break;
472f6c50668Spatrick       case DW_CFA_advance_loc1:
473f6c50668Spatrick         codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
474f6c50668Spatrick         p += 1;
475f6c50668Spatrick         _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",
476f6c50668Spatrick                                static_cast<uint64_t>(codeOffset));
477f6c50668Spatrick         break;
478f6c50668Spatrick       case DW_CFA_advance_loc2:
479f6c50668Spatrick         codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
480f6c50668Spatrick         p += 2;
481f6c50668Spatrick         _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",
482f6c50668Spatrick                                static_cast<uint64_t>(codeOffset));
483f6c50668Spatrick         break;
484f6c50668Spatrick       case DW_CFA_advance_loc4:
485f6c50668Spatrick         codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
486f6c50668Spatrick         p += 4;
487f6c50668Spatrick         _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",
488f6c50668Spatrick                                static_cast<uint64_t>(codeOffset));
489f6c50668Spatrick         break;
490f6c50668Spatrick       case DW_CFA_offset_extended:
491f6c50668Spatrick         reg = addressSpace.getULEB128(p, instructionsEnd);
492a0747c9fSpatrick         offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *
493a0747c9fSpatrick                  cieInfo.dataAlignFactor;
494f6c50668Spatrick         if (reg > kMaxRegisterNumber) {
495f6c50668Spatrick           _LIBUNWIND_LOG0(
496f6c50668Spatrick               "malformed DW_CFA_offset_extended DWARF unwind, reg too big");
497f6c50668Spatrick           return false;
498f6c50668Spatrick         }
499f6c50668Spatrick         results->setRegister(reg, kRegisterInCFA, offset, initialState);
500f6c50668Spatrick         _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", "
501f6c50668Spatrick                                "offset=%" PRId64 ")\n",
502f6c50668Spatrick                                reg, offset);
503f6c50668Spatrick         break;
504f6c50668Spatrick       case DW_CFA_restore_extended:
505f6c50668Spatrick         reg = addressSpace.getULEB128(p, instructionsEnd);
506f6c50668Spatrick         if (reg > kMaxRegisterNumber) {
507f6c50668Spatrick           _LIBUNWIND_LOG0(
508f6c50668Spatrick               "malformed DW_CFA_restore_extended DWARF unwind, reg too big");
509f6c50668Spatrick           return false;
510f6c50668Spatrick         }
511f6c50668Spatrick         results->restoreRegisterToInitialState(reg, initialState);
512a0747c9fSpatrick         _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n",
513a0747c9fSpatrick                                reg);
514f6c50668Spatrick         break;
515f6c50668Spatrick       case DW_CFA_undefined:
516f6c50668Spatrick         reg = addressSpace.getULEB128(p, instructionsEnd);
517f6c50668Spatrick         if (reg > kMaxRegisterNumber) {
518f6c50668Spatrick           _LIBUNWIND_LOG0(
519f6c50668Spatrick               "malformed DW_CFA_undefined DWARF unwind, reg too big");
520f6c50668Spatrick           return false;
521f6c50668Spatrick         }
522a0747c9fSpatrick         results->setRegisterLocation(reg, kRegisterUndefined, initialState);
523f6c50668Spatrick         _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);
524f6c50668Spatrick         break;
525f6c50668Spatrick       case DW_CFA_same_value:
526f6c50668Spatrick         reg = addressSpace.getULEB128(p, instructionsEnd);
527f6c50668Spatrick         if (reg > kMaxRegisterNumber) {
528f6c50668Spatrick           _LIBUNWIND_LOG0(
529f6c50668Spatrick               "malformed DW_CFA_same_value DWARF unwind, reg too big");
530f6c50668Spatrick           return false;
531f6c50668Spatrick         }
532f6c50668Spatrick         // <rdar://problem/8456377> DW_CFA_same_value unsupported
533f6c50668Spatrick         // "same value" means register was stored in frame, but its current
534f6c50668Spatrick         // value has not changed, so no need to restore from frame.
535f6c50668Spatrick         // We model this as if the register was never saved.
536f6c50668Spatrick         results->setRegisterLocation(reg, kRegisterUnused, initialState);
537f6c50668Spatrick         _LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);
538f6c50668Spatrick         break;
539f6c50668Spatrick       case DW_CFA_register:
540f6c50668Spatrick         reg = addressSpace.getULEB128(p, instructionsEnd);
541f6c50668Spatrick         reg2 = addressSpace.getULEB128(p, instructionsEnd);
542f6c50668Spatrick         if (reg > kMaxRegisterNumber) {
543f6c50668Spatrick           _LIBUNWIND_LOG0(
544f6c50668Spatrick               "malformed DW_CFA_register DWARF unwind, reg too big");
545f6c50668Spatrick           return false;
546f6c50668Spatrick         }
547f6c50668Spatrick         if (reg2 > kMaxRegisterNumber) {
548f6c50668Spatrick           _LIBUNWIND_LOG0(
549f6c50668Spatrick               "malformed DW_CFA_register DWARF unwind, reg2 too big");
550f6c50668Spatrick           return false;
551f6c50668Spatrick         }
552f6c50668Spatrick         results->setRegister(reg, kRegisterInRegister, (int64_t)reg2,
553f6c50668Spatrick                              initialState);
554f6c50668Spatrick         _LIBUNWIND_TRACE_DWARF(
555f6c50668Spatrick             "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2);
556f6c50668Spatrick         break;
557a0747c9fSpatrick       case DW_CFA_remember_state: {
558a0747c9fSpatrick         // Avoid operator new because that would be an upward dependency.
559a0747c9fSpatrick         // Avoid malloc because it needs heap allocation.
560a0747c9fSpatrick         PrologInfoStackEntry *entry =
561a0747c9fSpatrick             (PrologInfoStackEntry *)_LIBUNWIND_REMEMBER_ALLOC(
562a0747c9fSpatrick                 sizeof(PrologInfoStackEntry));
563f6c50668Spatrick         if (entry != NULL) {
564a0747c9fSpatrick           entry->next = rememberStack.entry;
565f6c50668Spatrick           entry->info = *results;
566a0747c9fSpatrick           rememberStack.entry = entry;
567f6c50668Spatrick         } else {
568f6c50668Spatrick           return false;
569f6c50668Spatrick         }
570f6c50668Spatrick         _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n");
571f6c50668Spatrick         break;
572a0747c9fSpatrick       }
573f6c50668Spatrick       case DW_CFA_restore_state:
574a0747c9fSpatrick         if (rememberStack.entry != NULL) {
575a0747c9fSpatrick           PrologInfoStackEntry *top = rememberStack.entry;
576f6c50668Spatrick           *results = top->info;
577a0747c9fSpatrick           rememberStack.entry = top->next;
578a0747c9fSpatrick           _LIBUNWIND_REMEMBER_FREE(top);
579f6c50668Spatrick         } else {
580f6c50668Spatrick           return false;
581f6c50668Spatrick         }
582f6c50668Spatrick         _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n");
583f6c50668Spatrick         break;
584f6c50668Spatrick       case DW_CFA_def_cfa:
585f6c50668Spatrick         reg = addressSpace.getULEB128(p, instructionsEnd);
586f6c50668Spatrick         offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);
587f6c50668Spatrick         if (reg > kMaxRegisterNumber) {
588f6c50668Spatrick           _LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big");
589f6c50668Spatrick           return false;
590f6c50668Spatrick         }
591f6c50668Spatrick         results->cfaRegister = (uint32_t)reg;
592f6c50668Spatrick         results->cfaRegisterOffset = (int32_t)offset;
593a0747c9fSpatrick         _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64
594a0747c9fSpatrick                                ")\n",
595a0747c9fSpatrick                                reg, offset);
596f6c50668Spatrick         break;
597f6c50668Spatrick       case DW_CFA_def_cfa_register:
598f6c50668Spatrick         reg = addressSpace.getULEB128(p, instructionsEnd);
599f6c50668Spatrick         if (reg > kMaxRegisterNumber) {
600f6c50668Spatrick           _LIBUNWIND_LOG0(
601f6c50668Spatrick               "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big");
602f6c50668Spatrick           return false;
603f6c50668Spatrick         }
604f6c50668Spatrick         results->cfaRegister = (uint32_t)reg;
605f6c50668Spatrick         _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);
606f6c50668Spatrick         break;
607f6c50668Spatrick       case DW_CFA_def_cfa_offset:
608a0747c9fSpatrick         results->cfaRegisterOffset =
609a0747c9fSpatrick             (int32_t)addressSpace.getULEB128(p, instructionsEnd);
610f6c50668Spatrick         _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n",
611f6c50668Spatrick                                results->cfaRegisterOffset);
612f6c50668Spatrick         break;
613f6c50668Spatrick       case DW_CFA_def_cfa_expression:
614f6c50668Spatrick         results->cfaRegister = 0;
615f6c50668Spatrick         results->cfaExpression = (int64_t)p;
616f6c50668Spatrick         length = addressSpace.getULEB128(p, instructionsEnd);
617f6c50668Spatrick         assert(length < static_cast<pint_t>(~0) && "pointer overflow");
618f6c50668Spatrick         p += static_cast<pint_t>(length);
619f6c50668Spatrick         _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64
620f6c50668Spatrick                                ", length=%" PRIu64 ")\n",
621f6c50668Spatrick                                results->cfaExpression, length);
622f6c50668Spatrick         break;
623f6c50668Spatrick       case DW_CFA_expression:
624f6c50668Spatrick         reg = addressSpace.getULEB128(p, instructionsEnd);
625f6c50668Spatrick         if (reg > kMaxRegisterNumber) {
626f6c50668Spatrick           _LIBUNWIND_LOG0(
627f6c50668Spatrick               "malformed DW_CFA_expression DWARF unwind, reg too big");
628f6c50668Spatrick           return false;
629f6c50668Spatrick         }
630f6c50668Spatrick         results->setRegister(reg, kRegisterAtExpression, (int64_t)p,
631f6c50668Spatrick                              initialState);
632f6c50668Spatrick         length = addressSpace.getULEB128(p, instructionsEnd);
633f6c50668Spatrick         assert(length < static_cast<pint_t>(~0) && "pointer overflow");
634f6c50668Spatrick         p += static_cast<pint_t>(length);
635f6c50668Spatrick         _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", "
636f6c50668Spatrick                                "expression=0x%" PRIx64 ", "
637f6c50668Spatrick                                "length=%" PRIu64 ")\n",
638f6c50668Spatrick                                reg, results->savedRegisters[reg].value, length);
639f6c50668Spatrick         break;
640f6c50668Spatrick       case DW_CFA_offset_extended_sf:
641f6c50668Spatrick         reg = addressSpace.getULEB128(p, instructionsEnd);
642f6c50668Spatrick         if (reg > kMaxRegisterNumber) {
643f6c50668Spatrick           _LIBUNWIND_LOG0(
644f6c50668Spatrick               "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big");
645f6c50668Spatrick           return false;
646f6c50668Spatrick         }
647a0747c9fSpatrick         offset = addressSpace.getSLEB128(p, instructionsEnd) *
648a0747c9fSpatrick                  cieInfo.dataAlignFactor;
649f6c50668Spatrick         results->setRegister(reg, kRegisterInCFA, offset, initialState);
650f6c50668Spatrick         _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", "
651f6c50668Spatrick                                "offset=%" PRId64 ")\n",
652f6c50668Spatrick                                reg, offset);
653f6c50668Spatrick         break;
654f6c50668Spatrick       case DW_CFA_def_cfa_sf:
655f6c50668Spatrick         reg = addressSpace.getULEB128(p, instructionsEnd);
656a0747c9fSpatrick         offset = addressSpace.getSLEB128(p, instructionsEnd) *
657a0747c9fSpatrick                  cieInfo.dataAlignFactor;
658f6c50668Spatrick         if (reg > kMaxRegisterNumber) {
659f6c50668Spatrick           _LIBUNWIND_LOG0(
660f6c50668Spatrick               "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big");
661f6c50668Spatrick           return false;
662f6c50668Spatrick         }
663f6c50668Spatrick         results->cfaRegister = (uint32_t)reg;
664f6c50668Spatrick         results->cfaRegisterOffset = (int32_t)offset;
665f6c50668Spatrick         _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", "
666f6c50668Spatrick                                "offset=%" PRId64 ")\n",
667f6c50668Spatrick                                reg, offset);
668f6c50668Spatrick         break;
669f6c50668Spatrick       case DW_CFA_def_cfa_offset_sf:
670a0747c9fSpatrick         results->cfaRegisterOffset =
671a0747c9fSpatrick             (int32_t)(addressSpace.getSLEB128(p, instructionsEnd) *
672a0747c9fSpatrick                       cieInfo.dataAlignFactor);
673f6c50668Spatrick         _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n",
674f6c50668Spatrick                                results->cfaRegisterOffset);
675f6c50668Spatrick         break;
676f6c50668Spatrick       case DW_CFA_val_offset:
677f6c50668Spatrick         reg = addressSpace.getULEB128(p, instructionsEnd);
678f6c50668Spatrick         if (reg > kMaxRegisterNumber) {
679f6c50668Spatrick           _LIBUNWIND_LOG(
680f6c50668Spatrick               "malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64
681f6c50668Spatrick               ") out of range\n",
682f6c50668Spatrick               reg);
683f6c50668Spatrick           return false;
684f6c50668Spatrick         }
685a0747c9fSpatrick         offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *
686a0747c9fSpatrick                  cieInfo.dataAlignFactor;
687f6c50668Spatrick         results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState);
688f6c50668Spatrick         _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", "
689f6c50668Spatrick                                "offset=%" PRId64 "\n",
690f6c50668Spatrick                                reg, offset);
691f6c50668Spatrick         break;
692f6c50668Spatrick       case DW_CFA_val_offset_sf:
693f6c50668Spatrick         reg = addressSpace.getULEB128(p, instructionsEnd);
694f6c50668Spatrick         if (reg > kMaxRegisterNumber) {
695f6c50668Spatrick           _LIBUNWIND_LOG0(
696f6c50668Spatrick               "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big");
697f6c50668Spatrick           return false;
698f6c50668Spatrick         }
699a0747c9fSpatrick         offset = addressSpace.getSLEB128(p, instructionsEnd) *
700a0747c9fSpatrick                  cieInfo.dataAlignFactor;
701f6c50668Spatrick         results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState);
702f6c50668Spatrick         _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", "
703f6c50668Spatrick                                "offset=%" PRId64 "\n",
704f6c50668Spatrick                                reg, offset);
705f6c50668Spatrick         break;
706f6c50668Spatrick       case DW_CFA_val_expression:
707f6c50668Spatrick         reg = addressSpace.getULEB128(p, instructionsEnd);
708f6c50668Spatrick         if (reg > kMaxRegisterNumber) {
709f6c50668Spatrick           _LIBUNWIND_LOG0(
710f6c50668Spatrick               "malformed DW_CFA_val_expression DWARF unwind, reg too big");
711f6c50668Spatrick           return false;
712f6c50668Spatrick         }
713f6c50668Spatrick         results->setRegister(reg, kRegisterIsExpression, (int64_t)p,
714f6c50668Spatrick                              initialState);
715f6c50668Spatrick         length = addressSpace.getULEB128(p, instructionsEnd);
716f6c50668Spatrick         assert(length < static_cast<pint_t>(~0) && "pointer overflow");
717f6c50668Spatrick         p += static_cast<pint_t>(length);
718f6c50668Spatrick         _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", "
719a0747c9fSpatrick                                "expression=0x%" PRIx64 ", length=%" PRIu64
720a0747c9fSpatrick                                ")\n",
721f6c50668Spatrick                                reg, results->savedRegisters[reg].value, length);
722f6c50668Spatrick         break;
723f6c50668Spatrick       case DW_CFA_GNU_args_size:
724f6c50668Spatrick         length = addressSpace.getULEB128(p, instructionsEnd);
725f6c50668Spatrick         results->spExtraArgSize = (uint32_t)length;
726f6c50668Spatrick         _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
727f6c50668Spatrick         break;
728f6c50668Spatrick       case DW_CFA_GNU_negative_offset_extended:
729f6c50668Spatrick         reg = addressSpace.getULEB128(p, instructionsEnd);
730f6c50668Spatrick         if (reg > kMaxRegisterNumber) {
731f6c50668Spatrick           _LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF "
732f6c50668Spatrick                           "unwind, reg too big");
733f6c50668Spatrick           return false;
734f6c50668Spatrick         }
735a0747c9fSpatrick         offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *
736a0747c9fSpatrick                  cieInfo.dataAlignFactor;
737f6c50668Spatrick         results->setRegister(reg, kRegisterInCFA, -offset, initialState);
738f6c50668Spatrick         _LIBUNWIND_TRACE_DWARF(
739f6c50668Spatrick             "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
740f6c50668Spatrick         break;
741f6c50668Spatrick 
742*202cdb0eSrobert #if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC) || \
743*202cdb0eSrobert     defined(_LIBUNWIND_TARGET_SPARC64)
744f6c50668Spatrick         // The same constant is used to represent different instructions on
745f6c50668Spatrick         // AArch64 (negate_ra_state) and SPARC (window_save).
746f6c50668Spatrick         static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save,
747f6c50668Spatrick                       "uses the same constant");
748f6c50668Spatrick       case DW_CFA_AARCH64_negate_ra_state:
749f6c50668Spatrick         switch (arch) {
750f6c50668Spatrick #if defined(_LIBUNWIND_TARGET_AARCH64)
751f6c50668Spatrick         case REGISTERS_ARM64: {
752f6c50668Spatrick           int64_t value =
753*202cdb0eSrobert               results->savedRegisters[UNW_AARCH64_RA_SIGN_STATE].value ^ 0x1;
754*202cdb0eSrobert           results->setRegisterValue(UNW_AARCH64_RA_SIGN_STATE, value,
755a0747c9fSpatrick                                     initialState);
756f6c50668Spatrick           _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n");
757f6c50668Spatrick         } break;
758f6c50668Spatrick #endif
759f6c50668Spatrick 
760f6c50668Spatrick #if defined(_LIBUNWIND_TARGET_SPARC)
761f6c50668Spatrick         // case DW_CFA_GNU_window_save:
762f6c50668Spatrick         case REGISTERS_SPARC:
763f6c50668Spatrick           _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n");
764f6c50668Spatrick           for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) {
765f6c50668Spatrick             results->setRegister(reg, kRegisterInRegister,
766f6c50668Spatrick                                  ((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0,
767f6c50668Spatrick                                  initialState);
768f6c50668Spatrick           }
769f6c50668Spatrick 
770f6c50668Spatrick           for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {
771f6c50668Spatrick             results->setRegister(reg, kRegisterInCFA,
772a0747c9fSpatrick                                  ((int64_t)reg - UNW_SPARC_L0) * 4,
773a0747c9fSpatrick                                  initialState);
774f6c50668Spatrick           }
775f6c50668Spatrick           break;
776f6c50668Spatrick #endif
777*202cdb0eSrobert 
778*202cdb0eSrobert #if defined(_LIBUNWIND_TARGET_SPARC64)
779*202cdb0eSrobert         // case DW_CFA_GNU_window_save:
780*202cdb0eSrobert         case REGISTERS_SPARC64:
781*202cdb0eSrobert           // Don't save %o0-%o7 on sparc64.
782*202cdb0eSrobert           // https://reviews.llvm.org/D32450#736405
783*202cdb0eSrobert 
784*202cdb0eSrobert           for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {
785*202cdb0eSrobert             if (reg == UNW_SPARC_I7)
786*202cdb0eSrobert               results->setRegister(
787*202cdb0eSrobert                   reg, kRegisterInCFADecrypt,
788*202cdb0eSrobert                   static_cast<int64_t>((reg - UNW_SPARC_L0) * sizeof(pint_t)),
789*202cdb0eSrobert                   initialState);
790*202cdb0eSrobert             else
791*202cdb0eSrobert               results->setRegister(
792*202cdb0eSrobert                   reg, kRegisterInCFA,
793*202cdb0eSrobert                   static_cast<int64_t>((reg - UNW_SPARC_L0) * sizeof(pint_t)),
794*202cdb0eSrobert                   initialState);
795*202cdb0eSrobert           }
796*202cdb0eSrobert           _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save\n");
797*202cdb0eSrobert           break;
798*202cdb0eSrobert #endif
799f6c50668Spatrick         }
800f6c50668Spatrick         break;
801*202cdb0eSrobert 
802f6c50668Spatrick #else
803f6c50668Spatrick         (void)arch;
804f6c50668Spatrick #endif
805f6c50668Spatrick 
806f6c50668Spatrick       default:
807f6c50668Spatrick         operand = opcode & 0x3F;
808f6c50668Spatrick         switch (opcode & 0xC0) {
809f6c50668Spatrick         case DW_CFA_offset:
810f6c50668Spatrick           reg = operand;
811f6c50668Spatrick           if (reg > kMaxRegisterNumber) {
812f6c50668Spatrick             _LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64
813f6c50668Spatrick                            ") out of range",
814f6c50668Spatrick                            reg);
815f6c50668Spatrick             return false;
816f6c50668Spatrick           }
817a0747c9fSpatrick           offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *
818a0747c9fSpatrick                    cieInfo.dataAlignFactor;
819f6c50668Spatrick           results->setRegister(reg, kRegisterInCFA, offset, initialState);
820f6c50668Spatrick           _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
821f6c50668Spatrick                                  operand, offset);
822f6c50668Spatrick           break;
823f6c50668Spatrick         case DW_CFA_advance_loc:
824f6c50668Spatrick           codeOffset += operand * cieInfo.codeAlignFactor;
825f6c50668Spatrick           _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
826f6c50668Spatrick                                  static_cast<uint64_t>(codeOffset));
827f6c50668Spatrick           break;
828f6c50668Spatrick         case DW_CFA_restore:
829f6c50668Spatrick           reg = operand;
830f6c50668Spatrick           if (reg > kMaxRegisterNumber) {
831a0747c9fSpatrick             _LIBUNWIND_LOG(
832a0747c9fSpatrick                 "malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64
833f6c50668Spatrick                 ") out of range",
834f6c50668Spatrick                 reg);
835f6c50668Spatrick             return false;
836f6c50668Spatrick           }
837f6c50668Spatrick           results->restoreRegisterToInitialState(reg, initialState);
838f6c50668Spatrick           _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",
839f6c50668Spatrick                                  static_cast<uint64_t>(operand));
840f6c50668Spatrick           break;
841f6c50668Spatrick         default:
842f6c50668Spatrick           _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode);
843f6c50668Spatrick           return false;
844f6c50668Spatrick         }
845f6c50668Spatrick       }
846f6c50668Spatrick     }
847a0747c9fSpatrick   }
848f6c50668Spatrick   return true;
849f6c50668Spatrick }
850f6c50668Spatrick 
851f6c50668Spatrick } // namespace libunwind
852f6c50668Spatrick 
853f6c50668Spatrick #endif // __DWARF_PARSER_HPP__
854