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