]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/projects/libunwind/src/EHHeaderParser.hpp
stand: Improve some debugging experience
[FreeBSD/FreeBSD.git] / contrib / llvm / projects / libunwind / src / EHHeaderParser.hpp
1 //===------------------------- EHHeaderParser.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 ELF .eh_frame_hdr sections.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #ifndef __EHHEADERPARSER_HPP__
14 #define __EHHEADERPARSER_HPP__
15
16 #include "libunwind.h"
17
18 #include "DwarfParser.hpp"
19
20 namespace libunwind {
21
22 /// \brief EHHeaderParser does basic parsing of an ELF .eh_frame_hdr section.
23 ///
24 /// See DWARF spec for details:
25 ///    http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
26 ///
27 template <typename A> class EHHeaderParser {
28 public:
29   typedef typename A::pint_t pint_t;
30
31   /// Information encoded in the EH frame header.
32   struct EHHeaderInfo {
33     pint_t eh_frame_ptr;
34     size_t fde_count;
35     pint_t table;
36     uint8_t table_enc;
37   };
38
39   static bool decodeEHHdr(A &addressSpace, pint_t ehHdrStart, pint_t ehHdrEnd,
40                           EHHeaderInfo &ehHdrInfo);
41   static bool findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart,
42                       uint32_t sectionLength,
43                       typename CFI_Parser<A>::FDE_Info *fdeInfo,
44                       typename CFI_Parser<A>::CIE_Info *cieInfo);
45
46 private:
47   static bool decodeTableEntry(A &addressSpace, pint_t &tableEntry,
48                                pint_t ehHdrStart, pint_t ehHdrEnd,
49                                uint8_t tableEnc,
50                                typename CFI_Parser<A>::FDE_Info *fdeInfo,
51                                typename CFI_Parser<A>::CIE_Info *cieInfo);
52   static size_t getTableEntrySize(uint8_t tableEnc);
53 };
54
55 template <typename A>
56 bool EHHeaderParser<A>::decodeEHHdr(A &addressSpace, pint_t ehHdrStart,
57                                     pint_t ehHdrEnd, EHHeaderInfo &ehHdrInfo) {
58   pint_t p = ehHdrStart;
59   uint8_t version = addressSpace.get8(p++);
60   if (version != 1) {
61     _LIBUNWIND_LOG0("Unsupported .eh_frame_hdr version");
62     return false;
63   }
64
65   uint8_t eh_frame_ptr_enc = addressSpace.get8(p++);
66   uint8_t fde_count_enc = addressSpace.get8(p++);
67   ehHdrInfo.table_enc = addressSpace.get8(p++);
68
69   ehHdrInfo.eh_frame_ptr =
70       addressSpace.getEncodedP(p, ehHdrEnd, eh_frame_ptr_enc, ehHdrStart);
71   ehHdrInfo.fde_count =
72       fde_count_enc == DW_EH_PE_omit
73           ? 0
74           : addressSpace.getEncodedP(p, ehHdrEnd, fde_count_enc, ehHdrStart);
75   ehHdrInfo.table = p;
76
77   return true;
78 }
79
80 template <typename A>
81 bool EHHeaderParser<A>::decodeTableEntry(
82     A &addressSpace, pint_t &tableEntry, pint_t ehHdrStart, pint_t ehHdrEnd,
83     uint8_t tableEnc, typename CFI_Parser<A>::FDE_Info *fdeInfo,
84     typename CFI_Parser<A>::CIE_Info *cieInfo) {
85   // Have to decode the whole FDE for the PC range anyway, so just throw away
86   // the PC start.
87   addressSpace.getEncodedP(tableEntry, ehHdrEnd, tableEnc, ehHdrStart);
88   pint_t fde =
89       addressSpace.getEncodedP(tableEntry, ehHdrEnd, tableEnc, ehHdrStart);
90   const char *message =
91       CFI_Parser<A>::decodeFDE(addressSpace, fde, fdeInfo, cieInfo);
92   if (message != NULL) {
93     _LIBUNWIND_DEBUG_LOG("EHHeaderParser::decodeTableEntry: bad fde: %s",
94                          message);
95     return false;
96   }
97
98   return true;
99 }
100
101 template <typename A>
102 bool EHHeaderParser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart,
103                                 uint32_t sectionLength,
104                                 typename CFI_Parser<A>::FDE_Info *fdeInfo,
105                                 typename CFI_Parser<A>::CIE_Info *cieInfo) {
106   pint_t ehHdrEnd = ehHdrStart + sectionLength;
107
108   EHHeaderParser<A>::EHHeaderInfo hdrInfo;
109   if (!EHHeaderParser<A>::decodeEHHdr(addressSpace, ehHdrStart, ehHdrEnd,
110                                       hdrInfo))
111     return false;
112
113   size_t tableEntrySize = getTableEntrySize(hdrInfo.table_enc);
114   pint_t tableEntry;
115
116   size_t low = 0;
117   for (size_t len = hdrInfo.fde_count; len > 1;) {
118     size_t mid = low + (len / 2);
119     tableEntry = hdrInfo.table + mid * tableEntrySize;
120     pint_t start = addressSpace.getEncodedP(tableEntry, ehHdrEnd,
121                                             hdrInfo.table_enc, ehHdrStart);
122
123     if (start == pc) {
124       low = mid;
125       break;
126     } else if (start < pc) {
127       low = mid;
128       len -= (len / 2);
129     } else {
130       len /= 2;
131     }
132   }
133
134   tableEntry = hdrInfo.table + low * tableEntrySize;
135   if (decodeTableEntry(addressSpace, tableEntry, ehHdrStart, ehHdrEnd,
136                        hdrInfo.table_enc, fdeInfo, cieInfo)) {
137     if (pc >= fdeInfo->pcStart && pc < fdeInfo->pcEnd)
138       return true;
139   }
140
141   return false;
142 }
143
144 template <typename A>
145 size_t EHHeaderParser<A>::getTableEntrySize(uint8_t tableEnc) {
146   switch (tableEnc & 0x0f) {
147   case DW_EH_PE_sdata2:
148   case DW_EH_PE_udata2:
149     return 4;
150   case DW_EH_PE_sdata4:
151   case DW_EH_PE_udata4:
152     return 8;
153   case DW_EH_PE_sdata8:
154   case DW_EH_PE_udata8:
155     return 16;
156   case DW_EH_PE_sleb128:
157   case DW_EH_PE_uleb128:
158     _LIBUNWIND_ABORT("Can't binary search on variable length encoded data.");
159   case DW_EH_PE_omit:
160     return 0;
161   default:
162     _LIBUNWIND_ABORT("Unknown DWARF encoding for search table.");
163   }
164 }
165
166 }
167
168 #endif