xref: /minix3/sys/lib/libunwind/DwarfParser.hpp (revision b029fb598aff7d169ad9d60ec6eafa774faef921)
1472758f3SLionel Sambuc //===--------------------------- DwarfParser.hpp --------------------------===//
2472758f3SLionel Sambuc //
3472758f3SLionel Sambuc //                     The LLVM Compiler Infrastructure
4472758f3SLionel Sambuc //
5472758f3SLionel Sambuc // This file is dual licensed under the MIT and the University of Illinois Open
6472758f3SLionel Sambuc // Source Licenses. See LICENSE.TXT for details.
7472758f3SLionel Sambuc //
8472758f3SLionel Sambuc //
9472758f3SLionel Sambuc //  Parses DWARF CFIs (FDEs and CIEs).
10472758f3SLionel Sambuc //
11472758f3SLionel Sambuc //===----------------------------------------------------------------------===//
12472758f3SLionel Sambuc 
13472758f3SLionel Sambuc #ifndef __DWARF_PARSER_HPP__
14472758f3SLionel Sambuc #define __DWARF_PARSER_HPP__
15472758f3SLionel Sambuc 
16472758f3SLionel Sambuc #include <cstdint>
17472758f3SLionel Sambuc #include <cstdlib>
18472758f3SLionel Sambuc 
19472758f3SLionel Sambuc #include "dwarf2.h"
20472758f3SLionel Sambuc #include "AddressSpace.hpp"
21472758f3SLionel Sambuc 
22472758f3SLionel Sambuc namespace _Unwind {
23472758f3SLionel Sambuc 
24472758f3SLionel Sambuc /// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
25472758f3SLionel Sambuc /// See Dwarf Spec for details:
26472758f3SLionel Sambuc ///    http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
27472758f3SLionel Sambuc ///
28472758f3SLionel Sambuc template <typename A, typename R> class CFI_Parser {
29472758f3SLionel Sambuc public:
30472758f3SLionel Sambuc   typedef typename A::pint_t pint_t;
31472758f3SLionel Sambuc 
32472758f3SLionel Sambuc   /// Information encoded in a CIE (Common Information Entry)
33472758f3SLionel Sambuc   struct CIE_Info {
34472758f3SLionel Sambuc     pint_t cieStart;
35472758f3SLionel Sambuc     pint_t cieLength;
36472758f3SLionel Sambuc     pint_t cieInstructions;
37472758f3SLionel Sambuc     pint_t personality;
38472758f3SLionel Sambuc     uint32_t codeAlignFactor;
39472758f3SLionel Sambuc     int dataAlignFactor;
40472758f3SLionel Sambuc     uint8_t pointerEncoding;
41472758f3SLionel Sambuc     uint8_t lsdaEncoding;
42472758f3SLionel Sambuc     uint8_t personalityEncoding;
43472758f3SLionel Sambuc     uint8_t personalityOffsetInCIE;
44472758f3SLionel Sambuc     bool isSignalFrame;
45472758f3SLionel Sambuc     bool fdesHaveAugmentationData;
46*b029fb59SBen Gras     uint8_t returnAddressRegister;
47472758f3SLionel Sambuc   };
48472758f3SLionel Sambuc 
49472758f3SLionel Sambuc   /// Information about an FDE (Frame Description Entry)
50472758f3SLionel Sambuc   struct FDE_Info {
51472758f3SLionel Sambuc     pint_t fdeStart;
52472758f3SLionel Sambuc     pint_t fdeLength;
53472758f3SLionel Sambuc     pint_t fdeInstructions;
54472758f3SLionel Sambuc     pint_t pcStart;
55472758f3SLionel Sambuc     pint_t pcEnd;
56472758f3SLionel Sambuc     pint_t lsda;
57472758f3SLionel Sambuc   };
58472758f3SLionel Sambuc 
59472758f3SLionel Sambuc   /// Information about a frame layout and registers saved determined
60472758f3SLionel Sambuc   /// by "running" the DWARF FDE "instructions"
61472758f3SLionel Sambuc   enum {
62472758f3SLionel Sambuc     kMaxRegisterNumber = R::LAST_REGISTER + 1
63472758f3SLionel Sambuc   };
64472758f3SLionel Sambuc   enum RegisterSavedWhere {
65472758f3SLionel Sambuc     kRegisterUnused,
66472758f3SLionel Sambuc     kRegisterInCFA,
67472758f3SLionel Sambuc     kRegisterOffsetFromCFA,
68472758f3SLionel Sambuc     kRegisterInRegister,
69472758f3SLionel Sambuc     kRegisterAtExpression,
70472758f3SLionel Sambuc     kRegisterIsExpression,
71472758f3SLionel Sambuc   };
72472758f3SLionel Sambuc   struct RegisterLocation {
73472758f3SLionel Sambuc     RegisterSavedWhere location;
74472758f3SLionel Sambuc     int64_t value;
75472758f3SLionel Sambuc   };
76472758f3SLionel Sambuc   struct PrologInfo {
77472758f3SLionel Sambuc     uint32_t cfaRegister;
78472758f3SLionel Sambuc     int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
79472758f3SLionel Sambuc     int64_t cfaExpression;     // CFA = expression
80472758f3SLionel Sambuc     uint32_t spExtraArgSize;
81472758f3SLionel Sambuc     uint32_t codeOffsetAtStackDecrement;
82472758f3SLionel Sambuc     RegisterLocation savedRegisters[kMaxRegisterNumber];
83472758f3SLionel Sambuc   };
84472758f3SLionel Sambuc 
85472758f3SLionel Sambuc   struct PrologInfoStackEntry {
PrologInfoStackEntry_Unwind::CFI_Parser::PrologInfoStackEntry86472758f3SLionel Sambuc     PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i)
87472758f3SLionel Sambuc         : next(n), info(i) {}
88472758f3SLionel Sambuc     PrologInfoStackEntry *next;
89472758f3SLionel Sambuc     PrologInfo info;
90472758f3SLionel Sambuc   };
91472758f3SLionel Sambuc 
92472758f3SLionel Sambuc   static void findPCRange(A &, pint_t, pint_t &, pint_t &);
93472758f3SLionel Sambuc 
94472758f3SLionel Sambuc   static bool decodeFDE(A &, pint_t, FDE_Info *, CIE_Info *,
95472758f3SLionel Sambuc                         unw_proc_info_t *ctx);
96472758f3SLionel Sambuc   static bool parseFDEInstructions(A &, const FDE_Info &, const CIE_Info &,
97472758f3SLionel Sambuc                                    pint_t, PrologInfo *, unw_proc_info_t *ctx);
98472758f3SLionel Sambuc 
99472758f3SLionel Sambuc   static bool parseCIE(A &, pint_t, CIE_Info *);
100472758f3SLionel Sambuc 
101472758f3SLionel Sambuc private:
102472758f3SLionel Sambuc   static bool parseInstructions(A &, pint_t, pint_t, const CIE_Info &, pint_t,
103472758f3SLionel Sambuc                                 PrologInfoStackEntry *&, PrologInfo *,
104472758f3SLionel Sambuc                                 unw_proc_info_t *ctx);
105472758f3SLionel Sambuc };
106472758f3SLionel Sambuc 
107472758f3SLionel Sambuc ///
108472758f3SLionel Sambuc /// Parse a FDE and return the last PC it covers.
109472758f3SLionel Sambuc ///
110472758f3SLionel Sambuc template <typename A, typename R>
findPCRange(A & addressSpace,pint_t fde,pint_t & pcStart,pint_t & pcEnd)111472758f3SLionel Sambuc void CFI_Parser<A, R>::findPCRange(A &addressSpace, pint_t fde, pint_t &pcStart,
112472758f3SLionel Sambuc                                    pint_t &pcEnd) {
113472758f3SLionel Sambuc   pcStart = 0;
114472758f3SLionel Sambuc   pcEnd = 0;
115472758f3SLionel Sambuc   pint_t p = fde;
116472758f3SLionel Sambuc   uint64_t cfiLength = addressSpace.get32(p);
117472758f3SLionel Sambuc   p += 4;
118472758f3SLionel Sambuc   if (cfiLength == 0xffffffff) {
119472758f3SLionel Sambuc     // 0xffffffff means length is really the next 8 Bytes.
120472758f3SLionel Sambuc     cfiLength = addressSpace.get64(p);
121472758f3SLionel Sambuc     p += 8;
122472758f3SLionel Sambuc   }
123472758f3SLionel Sambuc   if (cfiLength == 0)
124472758f3SLionel Sambuc     return;
125472758f3SLionel Sambuc   uint32_t ciePointer = addressSpace.get32(p);
126472758f3SLionel Sambuc   if (ciePointer == 0)
127472758f3SLionel Sambuc     return;
128472758f3SLionel Sambuc   pint_t nextCFI = p + cfiLength;
129472758f3SLionel Sambuc   pint_t cieStart = p - ciePointer;
130472758f3SLionel Sambuc   typename CFI_Parser<A, R>::CIE_Info cieInfo;
131472758f3SLionel Sambuc   if (!parseCIE(addressSpace, cieStart, &cieInfo))
132472758f3SLionel Sambuc     return;
133472758f3SLionel Sambuc   p += 4;
134472758f3SLionel Sambuc   // Parse pc begin and range.
135472758f3SLionel Sambuc   pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding, NULL);
136472758f3SLionel Sambuc   pcEnd = pcStart + addressSpace.getEncodedP(
137472758f3SLionel Sambuc                         p, nextCFI, cieInfo.pointerEncoding & 0x0F, NULL);
138472758f3SLionel Sambuc }
139472758f3SLionel Sambuc 
140472758f3SLionel Sambuc ///
141472758f3SLionel Sambuc /// Parse a FDE into a CIE_Info and an FDE_Info
142472758f3SLionel Sambuc ///
143472758f3SLionel Sambuc template <typename A, typename R>
decodeFDE(A & addressSpace,pint_t fdeStart,FDE_Info * fdeInfo,CIE_Info * cieInfo,unw_proc_info_t * ctx)144472758f3SLionel Sambuc bool CFI_Parser<A, R>::decodeFDE(A &addressSpace, pint_t fdeStart,
145472758f3SLionel Sambuc                                  FDE_Info *fdeInfo, CIE_Info *cieInfo,
146472758f3SLionel Sambuc                                  unw_proc_info_t *ctx) {
147472758f3SLionel Sambuc   pint_t p = fdeStart;
148472758f3SLionel Sambuc   uint64_t cfiLength = addressSpace.get32(p);
149472758f3SLionel Sambuc   p += 4;
150472758f3SLionel Sambuc   if (cfiLength == 0xffffffff) {
151472758f3SLionel Sambuc     // 0xffffffff means length is really the next 8 Bytes.
152472758f3SLionel Sambuc     cfiLength = addressSpace.get64(p);
153472758f3SLionel Sambuc     p += 8;
154472758f3SLionel Sambuc   }
155472758f3SLionel Sambuc   if (cfiLength == 0)
156472758f3SLionel Sambuc     return false;
157472758f3SLionel Sambuc   uint32_t ciePointer = addressSpace.get32(p);
158472758f3SLionel Sambuc   if (ciePointer == 0)
159472758f3SLionel Sambuc     return false;
160472758f3SLionel Sambuc   pint_t nextCFI = p + cfiLength;
161472758f3SLionel Sambuc   pint_t cieStart = p - ciePointer;
162472758f3SLionel Sambuc   if (!parseCIE(addressSpace, cieStart, cieInfo))
163472758f3SLionel Sambuc     return false;
164472758f3SLionel Sambuc   p += 4;
165472758f3SLionel Sambuc   // Parse pc begin and range.
166472758f3SLionel Sambuc   pint_t pcStart =
167472758f3SLionel Sambuc       addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding, ctx);
168472758f3SLionel Sambuc   pint_t pcRange = addressSpace.getEncodedP(
169472758f3SLionel Sambuc       p, nextCFI, cieInfo->pointerEncoding & 0x0F, ctx);
170472758f3SLionel Sambuc   // Parse rest of info.
171472758f3SLionel Sambuc   fdeInfo->lsda = 0;
172472758f3SLionel Sambuc   // Check for augmentation length
173472758f3SLionel Sambuc   if (cieInfo->fdesHaveAugmentationData) {
174472758f3SLionel Sambuc     uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
175472758f3SLionel Sambuc     pint_t endOfAug = p + augLen;
176*b029fb59SBen Gras     if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
177472758f3SLionel Sambuc       // Peek at value (without indirection).  Zero means no LSDA.
178472758f3SLionel Sambuc       pint_t lsdaStart = p;
179472758f3SLionel Sambuc       if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F,
180472758f3SLionel Sambuc                                    ctx) != 0) {
181472758f3SLionel Sambuc         // Reset pointer and re-parse LSDA address.
182472758f3SLionel Sambuc         p = lsdaStart;
183472758f3SLionel Sambuc         fdeInfo->lsda =
184472758f3SLionel Sambuc             addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding, ctx);
185472758f3SLionel Sambuc       }
186472758f3SLionel Sambuc     }
187472758f3SLionel Sambuc     p = endOfAug;
188472758f3SLionel Sambuc   }
189472758f3SLionel Sambuc   fdeInfo->fdeStart = fdeStart;
190472758f3SLionel Sambuc   fdeInfo->fdeLength = nextCFI - fdeStart;
191472758f3SLionel Sambuc   fdeInfo->fdeInstructions = p;
192472758f3SLionel Sambuc   fdeInfo->pcStart = pcStart;
193472758f3SLionel Sambuc   fdeInfo->pcEnd = pcStart + pcRange;
194472758f3SLionel Sambuc   return true;
195472758f3SLionel Sambuc }
196472758f3SLionel Sambuc 
197472758f3SLionel Sambuc /// Extract info from a CIE
198472758f3SLionel Sambuc template <typename A, typename R>
parseCIE(A & addressSpace,pint_t cie,CIE_Info * cieInfo)199472758f3SLionel Sambuc bool CFI_Parser<A, R>::parseCIE(A &addressSpace, pint_t cie,
200472758f3SLionel Sambuc                                 CIE_Info *cieInfo) {
201472758f3SLionel Sambuc   cieInfo->pointerEncoding = 0;
202*b029fb59SBen Gras   cieInfo->lsdaEncoding = DW_EH_PE_omit;
203472758f3SLionel Sambuc   cieInfo->personalityEncoding = 0;
204472758f3SLionel Sambuc   cieInfo->personalityOffsetInCIE = 0;
205472758f3SLionel Sambuc   cieInfo->personality = 0;
206472758f3SLionel Sambuc   cieInfo->codeAlignFactor = 0;
207472758f3SLionel Sambuc   cieInfo->dataAlignFactor = 0;
208472758f3SLionel Sambuc   cieInfo->isSignalFrame = false;
209472758f3SLionel Sambuc   cieInfo->fdesHaveAugmentationData = false;
210472758f3SLionel Sambuc   cieInfo->cieStart = cie;
211472758f3SLionel Sambuc   pint_t p = cie;
212472758f3SLionel Sambuc   uint64_t cieLength = addressSpace.get32(p);
213472758f3SLionel Sambuc   p += 4;
214472758f3SLionel Sambuc   pint_t cieContentEnd = p + cieLength;
215472758f3SLionel Sambuc   if (cieLength == 0xffffffff) {
216472758f3SLionel Sambuc     // 0xffffffff means length is really the next 8 Bytes.
217472758f3SLionel Sambuc     cieLength = addressSpace.get64(p);
218472758f3SLionel Sambuc     p += 8;
219472758f3SLionel Sambuc     cieContentEnd = p + cieLength;
220472758f3SLionel Sambuc   }
221472758f3SLionel Sambuc   if (cieLength == 0)
222472758f3SLionel Sambuc     return true;
223472758f3SLionel Sambuc   // CIE ID is always 0
224472758f3SLionel Sambuc   if (addressSpace.get32(p) != 0)
225472758f3SLionel Sambuc     return false;
226472758f3SLionel Sambuc   p += 4;
227472758f3SLionel Sambuc   // Version is always 1 or 3
228472758f3SLionel Sambuc   uint8_t version = addressSpace.get8(p);
229472758f3SLionel Sambuc   if (version != 1 && version != 3)
230472758f3SLionel Sambuc     return false;
231472758f3SLionel Sambuc   ++p;
232472758f3SLionel Sambuc   // Save start of augmentation string and find end.
233472758f3SLionel Sambuc   pint_t strStart = p;
234472758f3SLionel Sambuc   while (addressSpace.get8(p) != 0)
235472758f3SLionel Sambuc     ++p;
236472758f3SLionel Sambuc   ++p;
237472758f3SLionel Sambuc   // Parse code aligment factor
238472758f3SLionel Sambuc   cieInfo->codeAlignFactor = addressSpace.getULEB128(p, cieContentEnd);
239472758f3SLionel Sambuc   // Parse data alignment factor
240472758f3SLionel Sambuc   cieInfo->dataAlignFactor = addressSpace.getSLEB128(p, cieContentEnd);
241472758f3SLionel Sambuc   // Parse return address register
242*b029fb59SBen Gras   cieInfo->returnAddressRegister = (uint8_t)addressSpace.getULEB128(p, cieContentEnd);
243472758f3SLionel Sambuc   // Parse augmentation data based on augmentation string.
244472758f3SLionel Sambuc   if (addressSpace.get8(strStart) == 'z') {
245472758f3SLionel Sambuc     // parse augmentation data length
246472758f3SLionel Sambuc     addressSpace.getULEB128(p, cieContentEnd);
247472758f3SLionel Sambuc     for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) {
248472758f3SLionel Sambuc       switch (addressSpace.get8(s)) {
249472758f3SLionel Sambuc       case 'z':
250472758f3SLionel Sambuc         cieInfo->fdesHaveAugmentationData = true;
251472758f3SLionel Sambuc         break;
252472758f3SLionel Sambuc       case 'P':
253472758f3SLionel Sambuc         cieInfo->personalityEncoding = addressSpace.get8(p);
254472758f3SLionel Sambuc         ++p;
255472758f3SLionel Sambuc         cieInfo->personalityOffsetInCIE = p - cie;
256472758f3SLionel Sambuc         cieInfo->personality = addressSpace.getEncodedP(
257472758f3SLionel Sambuc             p, cieContentEnd, cieInfo->personalityEncoding, NULL);
258472758f3SLionel Sambuc         break;
259472758f3SLionel Sambuc       case 'L':
260472758f3SLionel Sambuc         cieInfo->lsdaEncoding = addressSpace.get8(p);
261472758f3SLionel Sambuc         ++p;
262472758f3SLionel Sambuc         break;
263472758f3SLionel Sambuc       case 'R':
264472758f3SLionel Sambuc         cieInfo->pointerEncoding = addressSpace.get8(p);
265472758f3SLionel Sambuc         ++p;
266472758f3SLionel Sambuc         break;
267472758f3SLionel Sambuc       case 'S':
268472758f3SLionel Sambuc         cieInfo->isSignalFrame = true;
269472758f3SLionel Sambuc         break;
270472758f3SLionel Sambuc       default:
271472758f3SLionel Sambuc         // ignore unknown letters
272472758f3SLionel Sambuc         break;
273472758f3SLionel Sambuc       }
274472758f3SLionel Sambuc     }
275472758f3SLionel Sambuc   }
276472758f3SLionel Sambuc   cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
277472758f3SLionel Sambuc   cieInfo->cieInstructions = p;
278472758f3SLionel Sambuc   return true;
279472758f3SLionel Sambuc }
280472758f3SLionel Sambuc 
281472758f3SLionel Sambuc /// "Run" the dwarf instructions and create the abstact PrologInfo for an FDE.
282472758f3SLionel Sambuc template <typename A, typename R>
parseFDEInstructions(A & addressSpace,const FDE_Info & fdeInfo,const CIE_Info & cieInfo,pint_t upToPC,PrologInfo * results,unw_proc_info_t * ctx)283472758f3SLionel Sambuc bool CFI_Parser<A, R>::parseFDEInstructions(A &addressSpace,
284472758f3SLionel Sambuc                                             const FDE_Info &fdeInfo,
285472758f3SLionel Sambuc                                             const CIE_Info &cieInfo,
286472758f3SLionel Sambuc                                             pint_t upToPC, PrologInfo *results,
287472758f3SLionel Sambuc                                             unw_proc_info_t *ctx) {
288472758f3SLionel Sambuc   // Clear results.
289472758f3SLionel Sambuc   memset(results, 0, sizeof(*results));
290472758f3SLionel Sambuc   PrologInfoStackEntry *rememberStack = NULL;
291472758f3SLionel Sambuc 
292472758f3SLionel Sambuc   // First parse the CIE then FDE instructions.
293472758f3SLionel Sambuc   if (!parseInstructions(addressSpace, cieInfo.cieInstructions,
294472758f3SLionel Sambuc                          cieInfo.cieStart + cieInfo.cieLength, cieInfo,
295472758f3SLionel Sambuc                          (pint_t)(-1), rememberStack, results, ctx))
296472758f3SLionel Sambuc     return false;
297472758f3SLionel Sambuc   return parseInstructions(addressSpace, fdeInfo.fdeInstructions,
298472758f3SLionel Sambuc                            fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo,
299472758f3SLionel Sambuc                            upToPC - fdeInfo.pcStart, rememberStack, results,
300472758f3SLionel Sambuc                            ctx);
301472758f3SLionel Sambuc }
302472758f3SLionel Sambuc 
303472758f3SLionel Sambuc /// "Run" the DWARF instructions.
304472758f3SLionel Sambuc template <typename A, typename R>
305472758f3SLionel Sambuc bool
parseInstructions(A & addressSpace,pint_t instructions,pint_t instructionsEnd,const CIE_Info & cieInfo,pint_t pcoffset,PrologInfoStackEntry * & rememberStack,PrologInfo * results,unw_proc_info_t * ctx)306472758f3SLionel Sambuc CFI_Parser<A, R>::parseInstructions(A &addressSpace, pint_t instructions,
307472758f3SLionel Sambuc                                     pint_t instructionsEnd,
308472758f3SLionel Sambuc                                     const CIE_Info &cieInfo, pint_t pcoffset,
309472758f3SLionel Sambuc                                     PrologInfoStackEntry *&rememberStack,
310472758f3SLionel Sambuc                                     PrologInfo *results, unw_proc_info_t *ctx) {
311472758f3SLionel Sambuc   pint_t p = instructions;
312472758f3SLionel Sambuc   uint32_t codeOffset = 0;
313472758f3SLionel Sambuc   PrologInfo initialState = *results;
314472758f3SLionel Sambuc 
315472758f3SLionel Sambuc   // See Dwarf Spec, section 6.4.2 for details on unwind opcodes.
316472758f3SLionel Sambuc   while (p < instructionsEnd && codeOffset < pcoffset) {
317472758f3SLionel Sambuc     uint64_t reg;
318472758f3SLionel Sambuc     uint64_t reg2;
319472758f3SLionel Sambuc     int64_t offset;
320472758f3SLionel Sambuc     uint64_t length;
321472758f3SLionel Sambuc     uint8_t opcode = addressSpace.get8(p);
322472758f3SLionel Sambuc     uint8_t operand;
323472758f3SLionel Sambuc     PrologInfoStackEntry *entry;
324472758f3SLionel Sambuc     ++p;
325472758f3SLionel Sambuc     switch (opcode) {
326472758f3SLionel Sambuc     case DW_CFA_nop:
327472758f3SLionel Sambuc       break;
328472758f3SLionel Sambuc     case DW_CFA_set_loc:
329472758f3SLionel Sambuc       codeOffset = addressSpace.getEncodedP(p, instructionsEnd,
330472758f3SLionel Sambuc                                             cieInfo.pointerEncoding, ctx);
331472758f3SLionel Sambuc       break;
332472758f3SLionel Sambuc     case DW_CFA_advance_loc1:
333472758f3SLionel Sambuc       codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
334472758f3SLionel Sambuc       p += 1;
335472758f3SLionel Sambuc       break;
336472758f3SLionel Sambuc     case DW_CFA_advance_loc2:
337472758f3SLionel Sambuc       codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
338472758f3SLionel Sambuc       p += 2;
339472758f3SLionel Sambuc       break;
340472758f3SLionel Sambuc     case DW_CFA_advance_loc4:
341472758f3SLionel Sambuc       codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
342472758f3SLionel Sambuc       p += 4;
343472758f3SLionel Sambuc       break;
344472758f3SLionel Sambuc     case DW_CFA_offset_extended:
345472758f3SLionel Sambuc       reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
346472758f3SLionel Sambuc       offset =
347472758f3SLionel Sambuc           addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
348472758f3SLionel Sambuc       if (reg > kMaxRegisterNumber)
349472758f3SLionel Sambuc         return false;
350472758f3SLionel Sambuc       results->savedRegisters[reg].location = kRegisterInCFA;
351472758f3SLionel Sambuc       results->savedRegisters[reg].value = offset;
352472758f3SLionel Sambuc       break;
353472758f3SLionel Sambuc     case DW_CFA_restore_extended:
354472758f3SLionel Sambuc       reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
355472758f3SLionel Sambuc       if (reg > kMaxRegisterNumber)
356472758f3SLionel Sambuc         return false;
357472758f3SLionel Sambuc       results->savedRegisters[reg] = initialState.savedRegisters[reg];
358472758f3SLionel Sambuc       break;
359472758f3SLionel Sambuc     case DW_CFA_undefined:
360472758f3SLionel Sambuc       reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
361472758f3SLionel Sambuc       if (reg > kMaxRegisterNumber)
362472758f3SLionel Sambuc         return false;
363472758f3SLionel Sambuc       results->savedRegisters[reg].location = kRegisterUnused;
364472758f3SLionel Sambuc       break;
365472758f3SLionel Sambuc     case DW_CFA_same_value:
366472758f3SLionel Sambuc       reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
367472758f3SLionel Sambuc       if (reg > kMaxRegisterNumber)
368472758f3SLionel Sambuc         return false;
369472758f3SLionel Sambuc       // "same value" means register was stored in frame, but its current
370472758f3SLionel Sambuc       // value has not changed, so no need to restore from frame.
371472758f3SLionel Sambuc       // We model this as if the register was never saved.
372472758f3SLionel Sambuc       results->savedRegisters[reg].location = kRegisterUnused;
373472758f3SLionel Sambuc       break;
374472758f3SLionel Sambuc     case DW_CFA_register:
375472758f3SLionel Sambuc       reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
376472758f3SLionel Sambuc       reg2 = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
377472758f3SLionel Sambuc       if (reg > kMaxRegisterNumber)
378472758f3SLionel Sambuc         return false;
379472758f3SLionel Sambuc       if (reg2 > kMaxRegisterNumber)
380472758f3SLionel Sambuc         return false;
381472758f3SLionel Sambuc       results->savedRegisters[reg].location = kRegisterInRegister;
382472758f3SLionel Sambuc       results->savedRegisters[reg].value = reg2;
383472758f3SLionel Sambuc       break;
384472758f3SLionel Sambuc     case DW_CFA_remember_state:
385472758f3SLionel Sambuc       // avoid operator new, because that would be an upward dependency
386472758f3SLionel Sambuc       entry = (PrologInfoStackEntry *)malloc(sizeof(PrologInfoStackEntry));
387472758f3SLionel Sambuc       if (entry == NULL)
388472758f3SLionel Sambuc         return false;
389472758f3SLionel Sambuc 
390472758f3SLionel Sambuc       entry->next = rememberStack;
391472758f3SLionel Sambuc       entry->info = *results;
392472758f3SLionel Sambuc       rememberStack = entry;
393472758f3SLionel Sambuc       break;
394472758f3SLionel Sambuc     case DW_CFA_restore_state:
395472758f3SLionel Sambuc       if (rememberStack == NULL)
396472758f3SLionel Sambuc         return false;
397472758f3SLionel Sambuc       {
398472758f3SLionel Sambuc         PrologInfoStackEntry *top = rememberStack;
399472758f3SLionel Sambuc         *results = top->info;
400472758f3SLionel Sambuc         rememberStack = top->next;
401472758f3SLionel Sambuc         free((char *)top);
402472758f3SLionel Sambuc       }
403472758f3SLionel Sambuc       break;
404472758f3SLionel Sambuc     case DW_CFA_def_cfa:
405472758f3SLionel Sambuc       reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
406472758f3SLionel Sambuc       offset = addressSpace.getULEB128(p, instructionsEnd);
407472758f3SLionel Sambuc       if (reg > kMaxRegisterNumber)
408472758f3SLionel Sambuc         return false;
409472758f3SLionel Sambuc       results->cfaRegister = reg;
410472758f3SLionel Sambuc       results->cfaRegisterOffset = offset;
411472758f3SLionel Sambuc       break;
412472758f3SLionel Sambuc     case DW_CFA_def_cfa_register:
413472758f3SLionel Sambuc       reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
414472758f3SLionel Sambuc       if (reg > kMaxRegisterNumber)
415472758f3SLionel Sambuc         return false;
416472758f3SLionel Sambuc       results->cfaRegister = reg;
417472758f3SLionel Sambuc       break;
418472758f3SLionel Sambuc     case DW_CFA_def_cfa_offset:
419472758f3SLionel Sambuc       results->cfaRegisterOffset = addressSpace.getULEB128(p, instructionsEnd);
420472758f3SLionel Sambuc       results->codeOffsetAtStackDecrement = codeOffset;
421472758f3SLionel Sambuc       break;
422472758f3SLionel Sambuc     case DW_CFA_def_cfa_expression:
423472758f3SLionel Sambuc       results->cfaRegister = 0;
424472758f3SLionel Sambuc       results->cfaExpression = p;
425472758f3SLionel Sambuc       length = addressSpace.getULEB128(p, instructionsEnd);
426472758f3SLionel Sambuc       p += length;
427472758f3SLionel Sambuc       break;
428472758f3SLionel Sambuc     case DW_CFA_expression:
429472758f3SLionel Sambuc       reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
430472758f3SLionel Sambuc       if (reg > kMaxRegisterNumber)
431472758f3SLionel Sambuc         return false;
432472758f3SLionel Sambuc       results->savedRegisters[reg].location = kRegisterAtExpression;
433472758f3SLionel Sambuc       results->savedRegisters[reg].value = p;
434472758f3SLionel Sambuc       length = addressSpace.getULEB128(p, instructionsEnd);
435472758f3SLionel Sambuc       p += length;
436472758f3SLionel Sambuc       break;
437472758f3SLionel Sambuc     case DW_CFA_offset_extended_sf:
438472758f3SLionel Sambuc       reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
439472758f3SLionel Sambuc       if (reg > kMaxRegisterNumber)
440472758f3SLionel Sambuc         return false;
441472758f3SLionel Sambuc       offset =
442472758f3SLionel Sambuc           addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
443472758f3SLionel Sambuc       results->savedRegisters[reg].location = kRegisterInCFA;
444472758f3SLionel Sambuc       results->savedRegisters[reg].value = offset;
445472758f3SLionel Sambuc       break;
446472758f3SLionel Sambuc     case DW_CFA_def_cfa_sf:
447472758f3SLionel Sambuc       reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
448472758f3SLionel Sambuc       offset =
449472758f3SLionel Sambuc           addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
450472758f3SLionel Sambuc       if (reg > kMaxRegisterNumber)
451472758f3SLionel Sambuc         return false;
452472758f3SLionel Sambuc       results->cfaRegister = reg;
453472758f3SLionel Sambuc       results->cfaRegisterOffset = offset;
454472758f3SLionel Sambuc       break;
455472758f3SLionel Sambuc     case DW_CFA_def_cfa_offset_sf:
456472758f3SLionel Sambuc       results->cfaRegisterOffset =
457472758f3SLionel Sambuc           addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
458472758f3SLionel Sambuc       results->codeOffsetAtStackDecrement = codeOffset;
459472758f3SLionel Sambuc       break;
460472758f3SLionel Sambuc     case DW_CFA_val_offset:
461472758f3SLionel Sambuc       reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
462472758f3SLionel Sambuc       offset =
463472758f3SLionel Sambuc           addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
464*b029fb59SBen Gras       if (reg > kMaxRegisterNumber)
465*b029fb59SBen Gras         return false;
466472758f3SLionel Sambuc       results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
467472758f3SLionel Sambuc       results->savedRegisters[reg].value = offset;
468472758f3SLionel Sambuc       break;
469472758f3SLionel Sambuc     case DW_CFA_val_offset_sf:
470472758f3SLionel Sambuc       reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
471472758f3SLionel Sambuc       if (reg > kMaxRegisterNumber)
472472758f3SLionel Sambuc         return false;
473472758f3SLionel Sambuc       offset =
474472758f3SLionel Sambuc           addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
475472758f3SLionel Sambuc       results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
476472758f3SLionel Sambuc       results->savedRegisters[reg].value = offset;
477472758f3SLionel Sambuc       break;
478472758f3SLionel Sambuc     case DW_CFA_val_expression:
479472758f3SLionel Sambuc       reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
480472758f3SLionel Sambuc       if (reg > kMaxRegisterNumber)
481472758f3SLionel Sambuc         return false;
482472758f3SLionel Sambuc       results->savedRegisters[reg].location = kRegisterIsExpression;
483472758f3SLionel Sambuc       results->savedRegisters[reg].value = p;
484472758f3SLionel Sambuc       length = addressSpace.getULEB128(p, instructionsEnd);
485472758f3SLionel Sambuc       p += length;
486472758f3SLionel Sambuc       break;
487*b029fb59SBen Gras     case DW_CFA_GNU_window_save:
488*b029fb59SBen Gras #if defined(__sparc__)
489*b029fb59SBen Gras       for (reg = 8; reg < 16; ++reg) {
490*b029fb59SBen Gras         results->savedRegisters[reg].location = kRegisterInRegister;
491*b029fb59SBen Gras         results->savedRegisters[reg].value = reg + 16;
492*b029fb59SBen Gras       }
493*b029fb59SBen Gras       for (reg = 16; reg < 32; ++reg) {
494*b029fb59SBen Gras         results->savedRegisters[reg].location = kRegisterInCFA;
495*b029fb59SBen Gras         results->savedRegisters[reg].value = (reg - 16) * sizeof(typename R::reg_t);
496*b029fb59SBen Gras       }
497*b029fb59SBen Gras       break;
498*b029fb59SBen Gras #else
499*b029fb59SBen Gras       return false;
500*b029fb59SBen Gras #endif
501472758f3SLionel Sambuc     case DW_CFA_GNU_args_size:
502472758f3SLionel Sambuc       offset = addressSpace.getULEB128(p, instructionsEnd);
503472758f3SLionel Sambuc       results->spExtraArgSize = offset;
504472758f3SLionel Sambuc       break;
505472758f3SLionel Sambuc     case DW_CFA_GNU_negative_offset_extended:
506472758f3SLionel Sambuc       reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
507472758f3SLionel Sambuc       if (reg > kMaxRegisterNumber)
508472758f3SLionel Sambuc         return false;
509472758f3SLionel Sambuc       offset =
510472758f3SLionel Sambuc           addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
511472758f3SLionel Sambuc       results->savedRegisters[reg].location = kRegisterInCFA;
512472758f3SLionel Sambuc       results->savedRegisters[reg].value = -offset;
513472758f3SLionel Sambuc       break;
514472758f3SLionel Sambuc     default:
515472758f3SLionel Sambuc       operand = opcode & 0x3F;
516472758f3SLionel Sambuc       switch (opcode & 0xC0) {
517472758f3SLionel Sambuc       case DW_CFA_offset:
518472758f3SLionel Sambuc         reg = R::dwarf2regno(operand);
519472758f3SLionel Sambuc         if (reg > kMaxRegisterNumber)
520472758f3SLionel Sambuc           return false;
521472758f3SLionel Sambuc         offset = addressSpace.getULEB128(p, instructionsEnd) *
522472758f3SLionel Sambuc                  cieInfo.dataAlignFactor;
523472758f3SLionel Sambuc         results->savedRegisters[reg].location = kRegisterInCFA;
524472758f3SLionel Sambuc         results->savedRegisters[reg].value = offset;
525472758f3SLionel Sambuc         break;
526472758f3SLionel Sambuc       case DW_CFA_advance_loc:
527472758f3SLionel Sambuc         codeOffset += operand * cieInfo.codeAlignFactor;
528472758f3SLionel Sambuc         break;
529472758f3SLionel Sambuc       case DW_CFA_restore:
530472758f3SLionel Sambuc         reg = R::dwarf2regno(operand);
531472758f3SLionel Sambuc         if (reg > kMaxRegisterNumber)
532472758f3SLionel Sambuc           return false;
533472758f3SLionel Sambuc         results->savedRegisters[reg] = initialState.savedRegisters[reg];
534472758f3SLionel Sambuc         break;
535472758f3SLionel Sambuc       default:
536472758f3SLionel Sambuc         return false;
537472758f3SLionel Sambuc       }
538472758f3SLionel Sambuc     }
539472758f3SLionel Sambuc   }
540472758f3SLionel Sambuc 
541472758f3SLionel Sambuc   return true;
542472758f3SLionel Sambuc }
543472758f3SLionel Sambuc 
544472758f3SLionel Sambuc } // namespace _Unwind
545472758f3SLionel Sambuc 
546472758f3SLionel Sambuc #endif // __DWARF_PARSER_HPP__
547