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