blob: 645ac217a3d547ce52a0f0c82113019a49a4db81 [file] [log] [blame]
Saleem Abdulrasool17552662015-04-24 19:39:17 +00001//===--------------------------- 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 <inttypes.h>
17#include <stdint.h>
18#include <stdio.h>
19#include <stdlib.h>
20
Saleem Abdulrasool17552662015-04-24 19:39:17 +000021#include "libunwind.h"
22#include "dwarf2.h"
23
Saleem Abdulrasool286a9162017-01-25 02:27:45 +000024#include "config.h"
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +000025
Saleem Abdulrasool17552662015-04-24 19:39:17 +000026namespace libunwind {
27
whitequark1ab4b9d2017-12-25 20:04:47 +000028// Avoid relying on C++ headers.
29template <class T>
30static constexpr T pint_max_value() { return ~0; }
31
Saleem Abdulrasool17552662015-04-24 19:39:17 +000032/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
Ed Maste4c43c3d2016-07-19 17:15:50 +000033/// See DWARF Spec for details:
Saleem Abdulrasool17552662015-04-24 19:39:17 +000034/// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
35///
36template <typename A>
37class CFI_Parser {
38public:
39 typedef typename A::pint_t pint_t;
40
41 /// Information encoded in a CIE (Common Information Entry)
42 struct CIE_Info {
43 pint_t cieStart;
44 pint_t cieLength;
45 pint_t cieInstructions;
46 uint8_t pointerEncoding;
47 uint8_t lsdaEncoding;
48 uint8_t personalityEncoding;
49 uint8_t personalityOffsetInCIE;
50 pint_t personality;
51 uint32_t codeAlignFactor;
52 int dataAlignFactor;
53 bool isSignalFrame;
54 bool fdesHaveAugmentationData;
55 uint8_t returnAddressRegister;
56 };
57
58 /// Information about an FDE (Frame Description Entry)
59 struct FDE_Info {
60 pint_t fdeStart;
61 pint_t fdeLength;
62 pint_t fdeInstructions;
63 pint_t pcStart;
64 pint_t pcEnd;
65 pint_t lsda;
66 };
67
68 enum {
Ed Maste567984c2016-07-20 15:19:09 +000069 kMaxRegisterNumber = _LIBUNWIND_HIGHEST_DWARF_REGISTER
Saleem Abdulrasool17552662015-04-24 19:39:17 +000070 };
71 enum RegisterSavedWhere {
72 kRegisterUnused,
73 kRegisterInCFA,
74 kRegisterOffsetFromCFA,
75 kRegisterInRegister,
76 kRegisterAtExpression,
77 kRegisterIsExpression
78 };
79 struct RegisterLocation {
80 RegisterSavedWhere location;
81 int64_t value;
82 };
83 /// Information about a frame layout and registers saved determined
Ed Maste4c43c3d2016-07-19 17:15:50 +000084 /// by "running" the DWARF FDE "instructions"
Saleem Abdulrasool17552662015-04-24 19:39:17 +000085 struct PrologInfo {
86 uint32_t cfaRegister;
87 int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
88 int64_t cfaExpression; // CFA = expression
89 uint32_t spExtraArgSize;
90 uint32_t codeOffsetAtStackDecrement;
91 bool registersInOtherRegisters;
92 bool sameValueUsed;
Martin Storsjof10f3c92017-10-27 07:59:01 +000093 RegisterLocation savedRegisters[kMaxRegisterNumber + 1];
Saleem Abdulrasool17552662015-04-24 19:39:17 +000094 };
95
96 struct PrologInfoStackEntry {
97 PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i)
98 : next(n), info(i) {}
99 PrologInfoStackEntry *next;
100 PrologInfo info;
101 };
102
103 static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
104 uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
105 CIE_Info *cieInfo);
106 static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
107 FDE_Info *fdeInfo, CIE_Info *cieInfo);
108 static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,
109 const CIE_Info &cieInfo, pint_t upToPC,
110 PrologInfo *results);
111
112 static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
113
114private:
115 static bool parseInstructions(A &addressSpace, pint_t instructions,
116 pint_t instructionsEnd, const CIE_Info &cieInfo,
117 pint_t pcoffset,
118 PrologInfoStackEntry *&rememberStack,
119 PrologInfo *results);
120};
121
122/// Parse a FDE into a CIE_Info and an FDE_Info
123template <typename A>
124const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
125 FDE_Info *fdeInfo, CIE_Info *cieInfo) {
126 pint_t p = fdeStart;
127 pint_t cfiLength = (pint_t)addressSpace.get32(p);
128 p += 4;
129 if (cfiLength == 0xffffffff) {
130 // 0xffffffff means length is really next 8 bytes
131 cfiLength = (pint_t)addressSpace.get64(p);
132 p += 8;
133 }
134 if (cfiLength == 0)
135 return "FDE has zero length"; // end marker
136 uint32_t ciePointer = addressSpace.get32(p);
137 if (ciePointer == 0)
138 return "FDE is really a CIE"; // this is a CIE not an FDE
139 pint_t nextCFI = p + cfiLength;
140 pint_t cieStart = p - ciePointer;
141 const char *err = parseCIE(addressSpace, cieStart, cieInfo);
142 if (err != NULL)
143 return err;
144 p += 4;
Ed Maste1b651132016-07-19 17:28:38 +0000145 // Parse pc begin and range.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000146 pint_t pcStart =
147 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
148 pint_t pcRange =
149 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
Ed Maste1b651132016-07-19 17:28:38 +0000150 // Parse rest of info.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000151 fdeInfo->lsda = 0;
Ed Maste1b651132016-07-19 17:28:38 +0000152 // Check for augmentation length.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000153 if (cieInfo->fdesHaveAugmentationData) {
154 pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
155 pint_t endOfAug = p + augLen;
156 if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
Ed Maste1b651132016-07-19 17:28:38 +0000157 // Peek at value (without indirection). Zero means no LSDA.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000158 pint_t lsdaStart = p;
159 if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) !=
160 0) {
Ed Maste1b651132016-07-19 17:28:38 +0000161 // Reset pointer and re-parse LSDA address.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000162 p = lsdaStart;
163 fdeInfo->lsda =
164 addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
165 }
166 }
167 p = endOfAug;
168 }
169 fdeInfo->fdeStart = fdeStart;
170 fdeInfo->fdeLength = nextCFI - fdeStart;
171 fdeInfo->fdeInstructions = p;
172 fdeInfo->pcStart = pcStart;
173 fdeInfo->pcEnd = pcStart + pcRange;
174 return NULL; // success
175}
176
177/// Scan an eh_frame section to find an FDE for a pc
178template <typename A>
179bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
180 uint32_t sectionLength, pint_t fdeHint,
181 FDE_Info *fdeInfo, CIE_Info *cieInfo) {
182 //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
183 pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
184 const pint_t ehSectionEnd = p + sectionLength;
185 while (p < ehSectionEnd) {
186 pint_t currentCFI = p;
187 //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
188 pint_t cfiLength = addressSpace.get32(p);
189 p += 4;
190 if (cfiLength == 0xffffffff) {
191 // 0xffffffff means length is really next 8 bytes
192 cfiLength = (pint_t)addressSpace.get64(p);
193 p += 8;
194 }
195 if (cfiLength == 0)
196 return false; // end marker
197 uint32_t id = addressSpace.get32(p);
198 if (id == 0) {
Ed Maste1b651132016-07-19 17:28:38 +0000199 // Skip over CIEs.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000200 p += cfiLength;
201 } else {
Ed Maste1b651132016-07-19 17:28:38 +0000202 // Process FDE to see if it covers pc.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000203 pint_t nextCFI = p + cfiLength;
204 uint32_t ciePointer = addressSpace.get32(p);
205 pint_t cieStart = p - ciePointer;
Ed Maste1b651132016-07-19 17:28:38 +0000206 // Validate pointer to CIE is within section.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000207 if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) {
208 if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) {
209 p += 4;
Ed Maste1b651132016-07-19 17:28:38 +0000210 // Parse pc begin and range.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000211 pint_t pcStart =
212 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
213 pint_t pcRange = addressSpace.getEncodedP(
214 p, nextCFI, cieInfo->pointerEncoding & 0x0F);
Ed Maste1b651132016-07-19 17:28:38 +0000215 // Test if pc is within the function this FDE covers.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000216 if ((pcStart < pc) && (pc <= pcStart + pcRange)) {
217 // parse rest of info
218 fdeInfo->lsda = 0;
219 // check for augmentation length
220 if (cieInfo->fdesHaveAugmentationData) {
221 pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
222 pint_t endOfAug = p + augLen;
223 if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
Ed Maste1b651132016-07-19 17:28:38 +0000224 // Peek at value (without indirection). Zero means no LSDA.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000225 pint_t lsdaStart = p;
226 if (addressSpace.getEncodedP(
227 p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) {
Ed Maste1b651132016-07-19 17:28:38 +0000228 // Reset pointer and re-parse LSDA address.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000229 p = lsdaStart;
230 fdeInfo->lsda = addressSpace
231 .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
232 }
233 }
234 p = endOfAug;
235 }
236 fdeInfo->fdeStart = currentCFI;
237 fdeInfo->fdeLength = nextCFI - currentCFI;
238 fdeInfo->fdeInstructions = p;
239 fdeInfo->pcStart = pcStart;
240 fdeInfo->pcEnd = pcStart + pcRange;
241 return true;
242 } else {
243 // pc is not in begin/range, skip this FDE
244 }
245 } else {
Ed Maste1b651132016-07-19 17:28:38 +0000246 // Malformed CIE, now augmentation describing pc range encoding.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000247 }
248 } else {
249 // malformed FDE. CIE is bad
250 }
251 p = nextCFI;
252 }
253 }
254 return false;
255}
256
257/// Extract info from a CIE
258template <typename A>
259const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
260 CIE_Info *cieInfo) {
261 cieInfo->pointerEncoding = 0;
262 cieInfo->lsdaEncoding = DW_EH_PE_omit;
263 cieInfo->personalityEncoding = 0;
264 cieInfo->personalityOffsetInCIE = 0;
265 cieInfo->personality = 0;
266 cieInfo->codeAlignFactor = 0;
267 cieInfo->dataAlignFactor = 0;
268 cieInfo->isSignalFrame = false;
269 cieInfo->fdesHaveAugmentationData = false;
270 cieInfo->cieStart = cie;
271 pint_t p = cie;
272 pint_t cieLength = (pint_t)addressSpace.get32(p);
273 p += 4;
274 pint_t cieContentEnd = p + cieLength;
275 if (cieLength == 0xffffffff) {
276 // 0xffffffff means length is really next 8 bytes
277 cieLength = (pint_t)addressSpace.get64(p);
278 p += 8;
279 cieContentEnd = p + cieLength;
280 }
281 if (cieLength == 0)
282 return NULL;
283 // CIE ID is always 0
284 if (addressSpace.get32(p) != 0)
285 return "CIE ID is not zero";
286 p += 4;
287 // Version is always 1 or 3
288 uint8_t version = addressSpace.get8(p);
289 if ((version != 1) && (version != 3))
290 return "CIE version is not 1 or 3";
291 ++p;
292 // save start of augmentation string and find end
293 pint_t strStart = p;
294 while (addressSpace.get8(p) != 0)
295 ++p;
296 ++p;
297 // parse code aligment factor
298 cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd);
299 // parse data alignment factor
300 cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd);
301 // parse return address register
302 uint64_t raReg = addressSpace.getULEB128(p, cieContentEnd);
303 assert(raReg < 255 && "return address register too large");
304 cieInfo->returnAddressRegister = (uint8_t)raReg;
305 // parse augmentation data based on augmentation string
306 const char *result = NULL;
307 if (addressSpace.get8(strStart) == 'z') {
308 // parse augmentation data length
309 addressSpace.getULEB128(p, cieContentEnd);
310 for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) {
311 switch (addressSpace.get8(s)) {
312 case 'z':
313 cieInfo->fdesHaveAugmentationData = true;
314 break;
315 case 'P':
316 cieInfo->personalityEncoding = addressSpace.get8(p);
317 ++p;
318 cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie);
319 cieInfo->personality = addressSpace
320 .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
321 break;
322 case 'L':
323 cieInfo->lsdaEncoding = addressSpace.get8(p);
324 ++p;
325 break;
326 case 'R':
327 cieInfo->pointerEncoding = addressSpace.get8(p);
328 ++p;
329 break;
330 case 'S':
331 cieInfo->isSignalFrame = true;
332 break;
333 default:
334 // ignore unknown letters
335 break;
336 }
337 }
338 }
339 cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
340 cieInfo->cieInstructions = p;
341 return result;
342}
343
344
Ed Maste4c43c3d2016-07-19 17:15:50 +0000345/// "run" the DWARF instructions and create the abstact PrologInfo for an FDE
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000346template <typename A>
347bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
348 const FDE_Info &fdeInfo,
349 const CIE_Info &cieInfo, pint_t upToPC,
350 PrologInfo *results) {
351 // clear results
352 memset(results, '\0', sizeof(PrologInfo));
353 PrologInfoStackEntry *rememberStack = NULL;
354
355 // parse CIE then FDE instructions
356 return parseInstructions(addressSpace, cieInfo.cieInstructions,
357 cieInfo.cieStart + cieInfo.cieLength, cieInfo,
358 (pint_t)(-1), rememberStack, results) &&
359 parseInstructions(addressSpace, fdeInfo.fdeInstructions,
360 fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo,
361 upToPC - fdeInfo.pcStart, rememberStack, results);
362}
363
Ed Maste4c43c3d2016-07-19 17:15:50 +0000364/// "run" the DWARF instructions
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000365template <typename A>
366bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
367 pint_t instructionsEnd,
368 const CIE_Info &cieInfo, pint_t pcoffset,
369 PrologInfoStackEntry *&rememberStack,
370 PrologInfo *results) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000371 pint_t p = instructions;
372 pint_t codeOffset = 0;
373 PrologInfo initialState = *results;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000374
375 _LIBUNWIND_TRACE_DWARF("parseInstructions(instructions=0x%0" PRIx64 ")\n",
376 static_cast<uint64_t>(instructionsEnd));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000377
Ed Maste4c43c3d2016-07-19 17:15:50 +0000378 // see DWARF Spec, section 6.4.2 for details on unwind opcodes
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000379 while ((p < instructionsEnd) && (codeOffset < pcoffset)) {
380 uint64_t reg;
381 uint64_t reg2;
382 int64_t offset;
383 uint64_t length;
384 uint8_t opcode = addressSpace.get8(p);
385 uint8_t operand;
Peter Zotov0717a2e2015-11-09 06:57:29 +0000386#if !defined(_LIBUNWIND_NO_HEAP)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000387 PrologInfoStackEntry *entry;
Peter Zotov0717a2e2015-11-09 06:57:29 +0000388#endif
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000389 ++p;
390 switch (opcode) {
391 case DW_CFA_nop:
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000392 _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000393 break;
394 case DW_CFA_set_loc:
395 codeOffset =
396 addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000397 _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000398 break;
399 case DW_CFA_advance_loc1:
400 codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
401 p += 1;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000402 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",
403 static_cast<uint64_t>(codeOffset));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000404 break;
405 case DW_CFA_advance_loc2:
406 codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
407 p += 2;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000408 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",
409 static_cast<uint64_t>(codeOffset));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000410 break;
411 case DW_CFA_advance_loc4:
412 codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
413 p += 4;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000414 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",
415 static_cast<uint64_t>(codeOffset));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000416 break;
417 case DW_CFA_offset_extended:
418 reg = addressSpace.getULEB128(p, instructionsEnd);
419 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
420 * cieInfo.dataAlignFactor;
421 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000422 _LIBUNWIND_LOG0(
423 "malformed DW_CFA_offset_extended DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000424 return false;
425 }
426 results->savedRegisters[reg].location = kRegisterInCFA;
427 results->savedRegisters[reg].value = offset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000428 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", "
429 "offset=%" PRId64 ")\n",
430 reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000431 break;
432 case DW_CFA_restore_extended:
433 reg = addressSpace.getULEB128(p, instructionsEnd);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000434 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000435 _LIBUNWIND_LOG0(
436 "malformed DW_CFA_restore_extended DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000437 return false;
438 }
439 results->savedRegisters[reg] = initialState.savedRegisters[reg];
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000440 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000441 break;
442 case DW_CFA_undefined:
443 reg = addressSpace.getULEB128(p, instructionsEnd);
444 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000445 _LIBUNWIND_LOG0(
446 "malformed DW_CFA_undefined DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000447 return false;
448 }
449 results->savedRegisters[reg].location = kRegisterUnused;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000450 _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000451 break;
452 case DW_CFA_same_value:
453 reg = addressSpace.getULEB128(p, instructionsEnd);
454 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000455 _LIBUNWIND_LOG0(
456 "malformed DW_CFA_same_value DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000457 return false;
458 }
459 // <rdar://problem/8456377> DW_CFA_same_value unsupported
460 // "same value" means register was stored in frame, but its current
461 // value has not changed, so no need to restore from frame.
462 // We model this as if the register was never saved.
463 results->savedRegisters[reg].location = kRegisterUnused;
464 // set flag to disable conversion to compact unwind
465 results->sameValueUsed = true;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000466 _LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000467 break;
468 case DW_CFA_register:
469 reg = addressSpace.getULEB128(p, instructionsEnd);
470 reg2 = addressSpace.getULEB128(p, instructionsEnd);
471 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000472 _LIBUNWIND_LOG0(
473 "malformed DW_CFA_register DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000474 return false;
475 }
476 if (reg2 > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000477 _LIBUNWIND_LOG0(
478 "malformed DW_CFA_register DWARF unwind, reg2 too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000479 return false;
480 }
481 results->savedRegisters[reg].location = kRegisterInRegister;
482 results->savedRegisters[reg].value = (int64_t)reg2;
483 // set flag to disable conversion to compact unwind
484 results->registersInOtherRegisters = true;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000485 _LIBUNWIND_TRACE_DWARF(
486 "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000487 break;
Peter Zotov0717a2e2015-11-09 06:57:29 +0000488#if !defined(_LIBUNWIND_NO_HEAP)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000489 case DW_CFA_remember_state:
490 // avoid operator new, because that would be an upward dependency
491 entry = (PrologInfoStackEntry *)malloc(sizeof(PrologInfoStackEntry));
492 if (entry != NULL) {
493 entry->next = rememberStack;
494 entry->info = *results;
495 rememberStack = entry;
496 } else {
497 return false;
498 }
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000499 _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000500 break;
501 case DW_CFA_restore_state:
502 if (rememberStack != NULL) {
503 PrologInfoStackEntry *top = rememberStack;
504 *results = top->info;
505 rememberStack = top->next;
506 free((char *)top);
507 } else {
508 return false;
509 }
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000510 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000511 break;
Peter Zotov0717a2e2015-11-09 06:57:29 +0000512#endif
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000513 case DW_CFA_def_cfa:
514 reg = addressSpace.getULEB128(p, instructionsEnd);
515 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);
516 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000517 _LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000518 return false;
519 }
520 results->cfaRegister = (uint32_t)reg;
521 results->cfaRegisterOffset = (int32_t)offset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000522 _LIBUNWIND_TRACE_DWARF(
523 "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n", reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000524 break;
525 case DW_CFA_def_cfa_register:
526 reg = addressSpace.getULEB128(p, instructionsEnd);
527 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000528 _LIBUNWIND_LOG0(
529 "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000530 return false;
531 }
532 results->cfaRegister = (uint32_t)reg;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000533 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000534 break;
535 case DW_CFA_def_cfa_offset:
536 results->cfaRegisterOffset = (int32_t)
537 addressSpace.getULEB128(p, instructionsEnd);
538 results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000539 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n",
540 results->cfaRegisterOffset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000541 break;
542 case DW_CFA_def_cfa_expression:
543 results->cfaRegister = 0;
544 results->cfaExpression = (int64_t)p;
545 length = addressSpace.getULEB128(p, instructionsEnd);
whitequark1ab4b9d2017-12-25 20:04:47 +0000546 assert(length < pint_max_value<pint_t>() && "pointer overflow");
Saleem Abdulrasool92acbf12017-03-08 16:03:27 +0000547 p += static_cast<pint_t>(length);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000548 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64
549 ", length=%" PRIu64 ")\n",
550 results->cfaExpression, length);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000551 break;
552 case DW_CFA_expression:
553 reg = addressSpace.getULEB128(p, instructionsEnd);
554 if (reg > kMaxRegisterNumber) {
whitequarka3b115c2017-12-25 13:42:41 +0000555 _LIBUNWIND_LOG0(
whitequarkb718c5f2017-12-25 13:27:56 +0000556 "malformed DW_CFA_expression DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000557 return false;
558 }
559 results->savedRegisters[reg].location = kRegisterAtExpression;
560 results->savedRegisters[reg].value = (int64_t)p;
561 length = addressSpace.getULEB128(p, instructionsEnd);
whitequark1ab4b9d2017-12-25 20:04:47 +0000562 assert(length < pint_max_value<pint_t>() && "pointer overflow");
Saleem Abdulrasool92acbf12017-03-08 16:03:27 +0000563 p += static_cast<pint_t>(length);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000564 _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", "
565 "expression=0x%" PRIx64 ", "
566 "length=%" PRIu64 ")\n",
567 reg, results->savedRegisters[reg].value, length);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000568 break;
569 case DW_CFA_offset_extended_sf:
570 reg = addressSpace.getULEB128(p, instructionsEnd);
571 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000572 _LIBUNWIND_LOG0(
573 "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000574 return false;
575 }
576 offset =
577 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
578 results->savedRegisters[reg].location = kRegisterInCFA;
579 results->savedRegisters[reg].value = offset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000580 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", "
581 "offset=%" PRId64 ")\n",
582 reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000583 break;
584 case DW_CFA_def_cfa_sf:
585 reg = addressSpace.getULEB128(p, instructionsEnd);
586 offset =
587 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
588 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000589 _LIBUNWIND_LOG0(
590 "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000591 return false;
592 }
593 results->cfaRegister = (uint32_t)reg;
594 results->cfaRegisterOffset = (int32_t)offset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000595 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", "
596 "offset=%" PRId64 ")\n",
597 reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000598 break;
599 case DW_CFA_def_cfa_offset_sf:
600 results->cfaRegisterOffset = (int32_t)
601 (addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor);
602 results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000603 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n",
604 results->cfaRegisterOffset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000605 break;
606 case DW_CFA_val_offset:
607 reg = addressSpace.getULEB128(p, instructionsEnd);
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000608 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000609 _LIBUNWIND_LOG(
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000610 "malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64
611 ") out of range\n",
612 reg);
613 return false;
614 }
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000615 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
616 * cieInfo.dataAlignFactor;
617 results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
618 results->savedRegisters[reg].value = offset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000619 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", "
620 "offset=%" PRId64 "\n",
621 reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000622 break;
623 case DW_CFA_val_offset_sf:
624 reg = addressSpace.getULEB128(p, instructionsEnd);
625 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000626 _LIBUNWIND_LOG0(
627 "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000628 return false;
629 }
630 offset =
631 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
632 results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
633 results->savedRegisters[reg].value = offset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000634 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", "
635 "offset=%" PRId64 "\n",
636 reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000637 break;
638 case DW_CFA_val_expression:
639 reg = addressSpace.getULEB128(p, instructionsEnd);
640 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000641 _LIBUNWIND_LOG0(
642 "malformed DW_CFA_val_expression DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000643 return false;
644 }
645 results->savedRegisters[reg].location = kRegisterIsExpression;
646 results->savedRegisters[reg].value = (int64_t)p;
647 length = addressSpace.getULEB128(p, instructionsEnd);
whitequark1ab4b9d2017-12-25 20:04:47 +0000648 assert(length < pint_max_value<pint_t>() && "pointer overflow");
Saleem Abdulrasool92acbf12017-03-08 16:03:27 +0000649 p += static_cast<pint_t>(length);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000650 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", "
651 "expression=0x%" PRIx64 ", length=%" PRIu64 ")\n",
652 reg, results->savedRegisters[reg].value, length);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000653 break;
654 case DW_CFA_GNU_args_size:
655 length = addressSpace.getULEB128(p, instructionsEnd);
656 results->spExtraArgSize = (uint32_t)length;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000657 _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000658 break;
659 case DW_CFA_GNU_negative_offset_extended:
660 reg = addressSpace.getULEB128(p, instructionsEnd);
661 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000662 _LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF "
663 "unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000664 return false;
665 }
666 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
667 * cieInfo.dataAlignFactor;
668 results->savedRegisters[reg].location = kRegisterInCFA;
669 results->savedRegisters[reg].value = -offset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000670 _LIBUNWIND_TRACE_DWARF(
671 "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000672 break;
673 default:
674 operand = opcode & 0x3F;
675 switch (opcode & 0xC0) {
676 case DW_CFA_offset:
677 reg = operand;
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000678 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000679 _LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64
680 ") out of range",
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000681 reg);
682 return false;
683 }
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000684 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
685 * cieInfo.dataAlignFactor;
686 results->savedRegisters[reg].location = kRegisterInCFA;
687 results->savedRegisters[reg].value = offset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000688 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
689 operand, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000690 break;
691 case DW_CFA_advance_loc:
692 codeOffset += operand * cieInfo.codeAlignFactor;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000693 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
694 static_cast<uint64_t>(codeOffset));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000695 break;
696 case DW_CFA_restore:
697 reg = operand;
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000698 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000699 _LIBUNWIND_LOG("malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64
700 ") out of range",
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000701 reg);
702 return false;
703 }
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000704 results->savedRegisters[reg] = initialState.savedRegisters[reg];
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000705 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",
Saleem Abdulrasoolc73a3c32017-01-21 21:27:29 +0000706 static_cast<uint64_t>(operand));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000707 break;
708 default:
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000709 _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000710 return false;
711 }
712 }
713 }
714
715 return true;
716}
717
718} // namespace libunwind
719
720#endif // __DWARF_PARSER_HPP__