xref: /netbsd-src/sys/lib/libunwind/DwarfParser.hpp (revision 6a493d6bc668897c91594964a732d38505b70cbb)
1 //===--------------------------- DwarfParser.hpp --------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
7 //
8 //
9 //  Parses DWARF CFIs (FDEs and CIEs).
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef __DWARF_PARSER_HPP__
14 #define __DWARF_PARSER_HPP__
15 
16 #include <cstdint>
17 #include <cstdlib>
18 
19 #include "dwarf2.h"
20 #include "AddressSpace.hpp"
21 
22 namespace _Unwind {
23 
24 /// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
25 /// See Dwarf Spec for details:
26 ///    http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
27 ///
28 template <typename A, typename R> class CFI_Parser {
29 public:
30   typedef typename A::pint_t pint_t;
31 
32   /// Information encoded in a CIE (Common Information Entry)
33   struct CIE_Info {
34     pint_t cieStart;
35     pint_t cieLength;
36     pint_t cieInstructions;
37     pint_t personality;
38     uint32_t codeAlignFactor;
39     int dataAlignFactor;
40     uint8_t pointerEncoding;
41     uint8_t lsdaEncoding;
42     uint8_t personalityEncoding;
43     uint8_t personalityOffsetInCIE;
44     bool isSignalFrame;
45     bool fdesHaveAugmentationData;
46   };
47 
48   /// Information about an FDE (Frame Description Entry)
49   struct FDE_Info {
50     pint_t fdeStart;
51     pint_t fdeLength;
52     pint_t fdeInstructions;
53     pint_t pcStart;
54     pint_t pcEnd;
55     pint_t lsda;
56   };
57 
58   /// Information about a frame layout and registers saved determined
59   /// by "running" the DWARF FDE "instructions"
60   enum {
61     kMaxRegisterNumber = R::LAST_REGISTER + 1
62   };
63   enum RegisterSavedWhere {
64     kRegisterUnused,
65     kRegisterInCFA,
66     kRegisterOffsetFromCFA,
67     kRegisterInRegister,
68     kRegisterAtExpression,
69     kRegisterIsExpression,
70   };
71   struct RegisterLocation {
72     RegisterSavedWhere location;
73     int64_t value;
74   };
75   struct PrologInfo {
76     uint32_t cfaRegister;
77     int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
78     int64_t cfaExpression;     // CFA = expression
79     uint32_t spExtraArgSize;
80     uint32_t codeOffsetAtStackDecrement;
81     RegisterLocation savedRegisters[kMaxRegisterNumber];
82   };
83 
84   struct PrologInfoStackEntry {
85     PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i)
86         : next(n), info(i) {}
87     PrologInfoStackEntry *next;
88     PrologInfo info;
89   };
90 
91   static void findPCRange(A &, pint_t, pint_t &, pint_t &);
92 
93   static bool decodeFDE(A &, pint_t, FDE_Info *, CIE_Info *,
94                         unw_proc_info_t *ctx);
95   static bool parseFDEInstructions(A &, const FDE_Info &, const CIE_Info &,
96                                    pint_t, PrologInfo *, unw_proc_info_t *ctx);
97 
98   static bool parseCIE(A &, pint_t, CIE_Info *);
99 
100 private:
101   static bool parseInstructions(A &, pint_t, pint_t, const CIE_Info &, pint_t,
102                                 PrologInfoStackEntry *&, PrologInfo *,
103                                 unw_proc_info_t *ctx);
104 };
105 
106 ///
107 /// Parse a FDE and return the last PC it covers.
108 ///
109 template <typename A, typename R>
110 void CFI_Parser<A, R>::findPCRange(A &addressSpace, pint_t fde, pint_t &pcStart,
111                                    pint_t &pcEnd) {
112   pcStart = 0;
113   pcEnd = 0;
114   pint_t p = fde;
115   uint64_t cfiLength = addressSpace.get32(p);
116   p += 4;
117   if (cfiLength == 0xffffffff) {
118     // 0xffffffff means length is really the next 8 Bytes.
119     cfiLength = addressSpace.get64(p);
120     p += 8;
121   }
122   if (cfiLength == 0)
123     return;
124   uint32_t ciePointer = addressSpace.get32(p);
125   if (ciePointer == 0)
126     return;
127   pint_t nextCFI = p + cfiLength;
128   pint_t cieStart = p - ciePointer;
129   typename CFI_Parser<A, R>::CIE_Info cieInfo;
130   if (!parseCIE(addressSpace, cieStart, &cieInfo))
131     return;
132   p += 4;
133   // Parse pc begin and range.
134   pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding, NULL);
135   pcEnd = pcStart + addressSpace.getEncodedP(
136                         p, nextCFI, cieInfo.pointerEncoding & 0x0F, NULL);
137 }
138 
139 ///
140 /// Parse a FDE into a CIE_Info and an FDE_Info
141 ///
142 template <typename A, typename R>
143 bool CFI_Parser<A, R>::decodeFDE(A &addressSpace, pint_t fdeStart,
144                                  FDE_Info *fdeInfo, CIE_Info *cieInfo,
145                                  unw_proc_info_t *ctx) {
146   pint_t p = fdeStart;
147   uint64_t cfiLength = addressSpace.get32(p);
148   p += 4;
149   if (cfiLength == 0xffffffff) {
150     // 0xffffffff means length is really the next 8 Bytes.
151     cfiLength = addressSpace.get64(p);
152     p += 8;
153   }
154   if (cfiLength == 0)
155     return false;
156   uint32_t ciePointer = addressSpace.get32(p);
157   if (ciePointer == 0)
158     return false;
159   pint_t nextCFI = p + cfiLength;
160   pint_t cieStart = p - ciePointer;
161   if (!parseCIE(addressSpace, cieStart, cieInfo))
162     return false;
163   p += 4;
164   // Parse pc begin and range.
165   pint_t pcStart =
166       addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding, ctx);
167   pint_t pcRange = addressSpace.getEncodedP(
168       p, nextCFI, cieInfo->pointerEncoding & 0x0F, ctx);
169   // Parse rest of info.
170   fdeInfo->lsda = 0;
171   // Check for augmentation length
172   if (cieInfo->fdesHaveAugmentationData) {
173     uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
174     pint_t endOfAug = p + augLen;
175     if (cieInfo->lsdaEncoding != 0) {
176       // Peek at value (without indirection).  Zero means no LSDA.
177       pint_t lsdaStart = p;
178       if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F,
179                                    ctx) != 0) {
180         // Reset pointer and re-parse LSDA address.
181         p = lsdaStart;
182         fdeInfo->lsda =
183             addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding, ctx);
184       }
185     }
186     p = endOfAug;
187   }
188   fdeInfo->fdeStart = fdeStart;
189   fdeInfo->fdeLength = nextCFI - fdeStart;
190   fdeInfo->fdeInstructions = p;
191   fdeInfo->pcStart = pcStart;
192   fdeInfo->pcEnd = pcStart + pcRange;
193   return true;
194 }
195 
196 /// Extract info from a CIE
197 template <typename A, typename R>
198 bool CFI_Parser<A, R>::parseCIE(A &addressSpace, pint_t cie,
199                                 CIE_Info *cieInfo) {
200   cieInfo->pointerEncoding = 0;
201   cieInfo->lsdaEncoding = 0;
202   cieInfo->personalityEncoding = 0;
203   cieInfo->personalityOffsetInCIE = 0;
204   cieInfo->personality = 0;
205   cieInfo->codeAlignFactor = 0;
206   cieInfo->dataAlignFactor = 0;
207   cieInfo->isSignalFrame = false;
208   cieInfo->fdesHaveAugmentationData = false;
209   cieInfo->cieStart = cie;
210   pint_t p = cie;
211   uint64_t cieLength = addressSpace.get32(p);
212   p += 4;
213   pint_t cieContentEnd = p + cieLength;
214   if (cieLength == 0xffffffff) {
215     // 0xffffffff means length is really the next 8 Bytes.
216     cieLength = addressSpace.get64(p);
217     p += 8;
218     cieContentEnd = p + cieLength;
219   }
220   if (cieLength == 0)
221     return true;
222   // CIE ID is always 0
223   if (addressSpace.get32(p) != 0)
224     return false;
225   p += 4;
226   // Version is always 1 or 3
227   uint8_t version = addressSpace.get8(p);
228   if (version != 1 && version != 3)
229     return false;
230   ++p;
231   // Save start of augmentation string and find end.
232   pint_t strStart = p;
233   while (addressSpace.get8(p) != 0)
234     ++p;
235   ++p;
236   // Parse code aligment factor
237   cieInfo->codeAlignFactor = addressSpace.getULEB128(p, cieContentEnd);
238   // Parse data alignment factor
239   cieInfo->dataAlignFactor = addressSpace.getSLEB128(p, cieContentEnd);
240   // Parse return address register
241   addressSpace.getULEB128(p, cieContentEnd);
242   // Parse augmentation data based on augmentation string.
243   if (addressSpace.get8(strStart) == 'z') {
244     // parse augmentation data length
245     addressSpace.getULEB128(p, cieContentEnd);
246     for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) {
247       switch (addressSpace.get8(s)) {
248       case 'z':
249         cieInfo->fdesHaveAugmentationData = true;
250         break;
251       case 'P':
252         cieInfo->personalityEncoding = addressSpace.get8(p);
253         ++p;
254         cieInfo->personalityOffsetInCIE = p - cie;
255         cieInfo->personality = addressSpace.getEncodedP(
256             p, cieContentEnd, cieInfo->personalityEncoding, NULL);
257         break;
258       case 'L':
259         cieInfo->lsdaEncoding = addressSpace.get8(p);
260         ++p;
261         break;
262       case 'R':
263         cieInfo->pointerEncoding = addressSpace.get8(p);
264         ++p;
265         break;
266       case 'S':
267         cieInfo->isSignalFrame = true;
268         break;
269       default:
270         // ignore unknown letters
271         break;
272       }
273     }
274   }
275   cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
276   cieInfo->cieInstructions = p;
277   return true;
278 }
279 
280 /// "Run" the dwarf instructions and create the abstact PrologInfo for an FDE.
281 template <typename A, typename R>
282 bool CFI_Parser<A, R>::parseFDEInstructions(A &addressSpace,
283                                             const FDE_Info &fdeInfo,
284                                             const CIE_Info &cieInfo,
285                                             pint_t upToPC, PrologInfo *results,
286                                             unw_proc_info_t *ctx) {
287   // Clear results.
288   memset(results, 0, sizeof(*results));
289   PrologInfoStackEntry *rememberStack = NULL;
290 
291   // First parse the CIE then FDE instructions.
292   if (!parseInstructions(addressSpace, cieInfo.cieInstructions,
293                          cieInfo.cieStart + cieInfo.cieLength, cieInfo,
294                          (pint_t)(-1), rememberStack, results, ctx))
295     return false;
296   return parseInstructions(addressSpace, fdeInfo.fdeInstructions,
297                            fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo,
298                            upToPC - fdeInfo.pcStart, rememberStack, results,
299                            ctx);
300 }
301 
302 /// "Run" the DWARF instructions.
303 template <typename A, typename R>
304 bool
305 CFI_Parser<A, R>::parseInstructions(A &addressSpace, pint_t instructions,
306                                     pint_t instructionsEnd,
307                                     const CIE_Info &cieInfo, pint_t pcoffset,
308                                     PrologInfoStackEntry *&rememberStack,
309                                     PrologInfo *results, unw_proc_info_t *ctx) {
310   pint_t p = instructions;
311   uint32_t codeOffset = 0;
312   PrologInfo initialState = *results;
313 
314   // See Dwarf Spec, section 6.4.2 for details on unwind opcodes.
315   while (p < instructionsEnd && codeOffset < pcoffset) {
316     uint64_t reg;
317     uint64_t reg2;
318     int64_t offset;
319     uint64_t length;
320     uint8_t opcode = addressSpace.get8(p);
321     uint8_t operand;
322     PrologInfoStackEntry *entry;
323     ++p;
324     switch (opcode) {
325     case DW_CFA_nop:
326       break;
327     case DW_CFA_set_loc:
328       codeOffset = addressSpace.getEncodedP(p, instructionsEnd,
329                                             cieInfo.pointerEncoding, ctx);
330       break;
331     case DW_CFA_advance_loc1:
332       codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
333       p += 1;
334       break;
335     case DW_CFA_advance_loc2:
336       codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
337       p += 2;
338       break;
339     case DW_CFA_advance_loc4:
340       codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
341       p += 4;
342       break;
343     case DW_CFA_offset_extended:
344       reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
345       offset =
346           addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
347       if (reg > kMaxRegisterNumber)
348         return false;
349       results->savedRegisters[reg].location = kRegisterInCFA;
350       results->savedRegisters[reg].value = offset;
351       break;
352     case DW_CFA_restore_extended:
353       reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
354       if (reg > kMaxRegisterNumber)
355         return false;
356       results->savedRegisters[reg] = initialState.savedRegisters[reg];
357       break;
358     case DW_CFA_undefined:
359       reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
360       if (reg > kMaxRegisterNumber)
361         return false;
362       results->savedRegisters[reg].location = kRegisterUnused;
363       break;
364     case DW_CFA_same_value:
365       reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
366       if (reg > kMaxRegisterNumber)
367         return false;
368       // "same value" means register was stored in frame, but its current
369       // value has not changed, so no need to restore from frame.
370       // We model this as if the register was never saved.
371       results->savedRegisters[reg].location = kRegisterUnused;
372       break;
373     case DW_CFA_register:
374       reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
375       reg2 = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
376       if (reg > kMaxRegisterNumber)
377         return false;
378       if (reg2 > kMaxRegisterNumber)
379         return false;
380       results->savedRegisters[reg].location = kRegisterInRegister;
381       results->savedRegisters[reg].value = reg2;
382       break;
383     case DW_CFA_remember_state:
384       // avoid operator new, because that would be an upward dependency
385       entry = (PrologInfoStackEntry *)malloc(sizeof(PrologInfoStackEntry));
386       if (entry == NULL)
387         return false;
388 
389       entry->next = rememberStack;
390       entry->info = *results;
391       rememberStack = entry;
392       break;
393     case DW_CFA_restore_state:
394       if (rememberStack == NULL)
395         return false;
396       {
397         PrologInfoStackEntry *top = rememberStack;
398         *results = top->info;
399         rememberStack = top->next;
400         free((char *)top);
401       }
402       break;
403     case DW_CFA_def_cfa:
404       reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
405       offset = addressSpace.getULEB128(p, instructionsEnd);
406       if (reg > kMaxRegisterNumber)
407         return false;
408       results->cfaRegister = reg;
409       results->cfaRegisterOffset = offset;
410       break;
411     case DW_CFA_def_cfa_register:
412       reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
413       if (reg > kMaxRegisterNumber)
414         return false;
415       results->cfaRegister = reg;
416       break;
417     case DW_CFA_def_cfa_offset:
418       results->cfaRegisterOffset = addressSpace.getULEB128(p, instructionsEnd);
419       results->codeOffsetAtStackDecrement = codeOffset;
420       break;
421     case DW_CFA_def_cfa_expression:
422       results->cfaRegister = 0;
423       results->cfaExpression = p;
424       length = addressSpace.getULEB128(p, instructionsEnd);
425       p += length;
426       break;
427     case DW_CFA_expression:
428       reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
429       if (reg > kMaxRegisterNumber)
430         return false;
431       results->savedRegisters[reg].location = kRegisterAtExpression;
432       results->savedRegisters[reg].value = p;
433       length = addressSpace.getULEB128(p, instructionsEnd);
434       p += length;
435       break;
436     case DW_CFA_offset_extended_sf:
437       reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
438       if (reg > kMaxRegisterNumber)
439         return false;
440       offset =
441           addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
442       results->savedRegisters[reg].location = kRegisterInCFA;
443       results->savedRegisters[reg].value = offset;
444       break;
445     case DW_CFA_def_cfa_sf:
446       reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
447       offset =
448           addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
449       if (reg > kMaxRegisterNumber)
450         return false;
451       results->cfaRegister = reg;
452       results->cfaRegisterOffset = offset;
453       break;
454     case DW_CFA_def_cfa_offset_sf:
455       results->cfaRegisterOffset =
456           addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
457       results->codeOffsetAtStackDecrement = codeOffset;
458       break;
459     case DW_CFA_val_offset:
460       reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
461       offset =
462           addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
463       results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
464       results->savedRegisters[reg].value = offset;
465       break;
466     case DW_CFA_val_offset_sf:
467       reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
468       if (reg > kMaxRegisterNumber)
469         return false;
470       offset =
471           addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
472       results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
473       results->savedRegisters[reg].value = offset;
474       break;
475     case DW_CFA_val_expression:
476       reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
477       if (reg > kMaxRegisterNumber)
478         return false;
479       results->savedRegisters[reg].location = kRegisterIsExpression;
480       results->savedRegisters[reg].value = p;
481       length = addressSpace.getULEB128(p, instructionsEnd);
482       p += length;
483       break;
484     case DW_CFA_GNU_args_size:
485       offset = addressSpace.getULEB128(p, instructionsEnd);
486       results->spExtraArgSize = offset;
487       break;
488     case DW_CFA_GNU_negative_offset_extended:
489       reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
490       if (reg > kMaxRegisterNumber)
491         return false;
492       offset =
493           addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
494       results->savedRegisters[reg].location = kRegisterInCFA;
495       results->savedRegisters[reg].value = -offset;
496       break;
497     default:
498       operand = opcode & 0x3F;
499       switch (opcode & 0xC0) {
500       case DW_CFA_offset:
501         reg = R::dwarf2regno(operand);
502         if (reg > kMaxRegisterNumber)
503           return false;
504         offset = addressSpace.getULEB128(p, instructionsEnd) *
505                  cieInfo.dataAlignFactor;
506         results->savedRegisters[reg].location = kRegisterInCFA;
507         results->savedRegisters[reg].value = offset;
508         break;
509       case DW_CFA_advance_loc:
510         codeOffset += operand * cieInfo.codeAlignFactor;
511         break;
512       case DW_CFA_restore:
513         reg = R::dwarf2regno(operand);
514         if (reg > kMaxRegisterNumber)
515           return false;
516         results->savedRegisters[reg] = initialState.savedRegisters[reg];
517         break;
518       default:
519         return false;
520       }
521     }
522   }
523 
524   return true;
525 }
526 
527 } // namespace _Unwind
528 
529 #endif // __DWARF_PARSER_HPP__
530