blob: 9de2898c075a72d1ecf8206211977602c76d1af5 [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
28/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
Ed Maste4c43c3d2016-07-19 17:15:50 +000029/// See DWARF Spec for details:
Saleem Abdulrasool17552662015-04-24 19:39:17 +000030/// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
31///
32template <typename A>
33class CFI_Parser {
34public:
35 typedef typename A::pint_t pint_t;
36
37 /// Information encoded in a CIE (Common Information Entry)
38 struct CIE_Info {
39 pint_t cieStart;
40 pint_t cieLength;
41 pint_t cieInstructions;
42 uint8_t pointerEncoding;
43 uint8_t lsdaEncoding;
44 uint8_t personalityEncoding;
45 uint8_t personalityOffsetInCIE;
46 pint_t personality;
47 uint32_t codeAlignFactor;
48 int dataAlignFactor;
49 bool isSignalFrame;
50 bool fdesHaveAugmentationData;
51 uint8_t returnAddressRegister;
Luke Cheesemancba83c32018-12-17 11:43:24 +000052#if defined(_LIBUNWIND_TARGET_AARCH64)
53 bool addressesSignedWithBKey;
54#endif
Saleem Abdulrasool17552662015-04-24 19:39:17 +000055 };
56
57 /// Information about an FDE (Frame Description Entry)
58 struct FDE_Info {
59 pint_t fdeStart;
60 pint_t fdeLength;
61 pint_t fdeInstructions;
62 pint_t pcStart;
63 pint_t pcEnd;
64 pint_t lsda;
65 };
66
67 enum {
Ed Maste567984c2016-07-20 15:19:09 +000068 kMaxRegisterNumber = _LIBUNWIND_HIGHEST_DWARF_REGISTER
Saleem Abdulrasool17552662015-04-24 19:39:17 +000069 };
70 enum RegisterSavedWhere {
71 kRegisterUnused,
72 kRegisterInCFA,
73 kRegisterOffsetFromCFA,
74 kRegisterInRegister,
75 kRegisterAtExpression,
76 kRegisterIsExpression
77 };
78 struct RegisterLocation {
79 RegisterSavedWhere location;
80 int64_t value;
81 };
82 /// Information about a frame layout and registers saved determined
Ed Maste4c43c3d2016-07-19 17:15:50 +000083 /// by "running" the DWARF FDE "instructions"
Saleem Abdulrasool17552662015-04-24 19:39:17 +000084 struct PrologInfo {
85 uint32_t cfaRegister;
86 int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
87 int64_t cfaExpression; // CFA = expression
88 uint32_t spExtraArgSize;
89 uint32_t codeOffsetAtStackDecrement;
90 bool registersInOtherRegisters;
91 bool sameValueUsed;
Martin Storsjof10f3c92017-10-27 07:59:01 +000092 RegisterLocation savedRegisters[kMaxRegisterNumber + 1];
Saleem Abdulrasool17552662015-04-24 19:39:17 +000093 };
94
95 struct PrologInfoStackEntry {
96 PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i)
97 : next(n), info(i) {}
98 PrologInfoStackEntry *next;
99 PrologInfo info;
100 };
101
102 static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
103 uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
104 CIE_Info *cieInfo);
105 static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
106 FDE_Info *fdeInfo, CIE_Info *cieInfo);
107 static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,
108 const CIE_Info &cieInfo, pint_t upToPC,
109 PrologInfo *results);
110
111 static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
112
113private:
114 static bool parseInstructions(A &addressSpace, pint_t instructions,
115 pint_t instructionsEnd, const CIE_Info &cieInfo,
116 pint_t pcoffset,
117 PrologInfoStackEntry *&rememberStack,
118 PrologInfo *results);
119};
120
121/// Parse a FDE into a CIE_Info and an FDE_Info
122template <typename A>
123const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
124 FDE_Info *fdeInfo, CIE_Info *cieInfo) {
125 pint_t p = fdeStart;
126 pint_t cfiLength = (pint_t)addressSpace.get32(p);
127 p += 4;
128 if (cfiLength == 0xffffffff) {
129 // 0xffffffff means length is really next 8 bytes
130 cfiLength = (pint_t)addressSpace.get64(p);
131 p += 8;
132 }
133 if (cfiLength == 0)
134 return "FDE has zero length"; // end marker
135 uint32_t ciePointer = addressSpace.get32(p);
136 if (ciePointer == 0)
137 return "FDE is really a CIE"; // this is a CIE not an FDE
138 pint_t nextCFI = p + cfiLength;
139 pint_t cieStart = p - ciePointer;
140 const char *err = parseCIE(addressSpace, cieStart, cieInfo);
141 if (err != NULL)
142 return err;
143 p += 4;
Ed Maste1b651132016-07-19 17:28:38 +0000144 // Parse pc begin and range.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000145 pint_t pcStart =
146 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
147 pint_t pcRange =
148 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
Ed Maste1b651132016-07-19 17:28:38 +0000149 // Parse rest of info.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000150 fdeInfo->lsda = 0;
Ed Maste1b651132016-07-19 17:28:38 +0000151 // Check for augmentation length.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000152 if (cieInfo->fdesHaveAugmentationData) {
153 pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
154 pint_t endOfAug = p + augLen;
155 if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
Ed Maste1b651132016-07-19 17:28:38 +0000156 // Peek at value (without indirection). Zero means no LSDA.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000157 pint_t lsdaStart = p;
158 if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) !=
159 0) {
Ed Maste1b651132016-07-19 17:28:38 +0000160 // Reset pointer and re-parse LSDA address.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000161 p = lsdaStart;
162 fdeInfo->lsda =
163 addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
164 }
165 }
166 p = endOfAug;
167 }
168 fdeInfo->fdeStart = fdeStart;
169 fdeInfo->fdeLength = nextCFI - fdeStart;
170 fdeInfo->fdeInstructions = p;
171 fdeInfo->pcStart = pcStart;
172 fdeInfo->pcEnd = pcStart + pcRange;
173 return NULL; // success
174}
175
176/// Scan an eh_frame section to find an FDE for a pc
177template <typename A>
178bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
179 uint32_t sectionLength, pint_t fdeHint,
180 FDE_Info *fdeInfo, CIE_Info *cieInfo) {
181 //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
182 pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
183 const pint_t ehSectionEnd = p + sectionLength;
184 while (p < ehSectionEnd) {
185 pint_t currentCFI = p;
186 //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
187 pint_t cfiLength = addressSpace.get32(p);
188 p += 4;
189 if (cfiLength == 0xffffffff) {
190 // 0xffffffff means length is really next 8 bytes
191 cfiLength = (pint_t)addressSpace.get64(p);
192 p += 8;
193 }
194 if (cfiLength == 0)
195 return false; // end marker
196 uint32_t id = addressSpace.get32(p);
197 if (id == 0) {
Ed Maste1b651132016-07-19 17:28:38 +0000198 // Skip over CIEs.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000199 p += cfiLength;
200 } else {
Ed Maste1b651132016-07-19 17:28:38 +0000201 // Process FDE to see if it covers pc.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000202 pint_t nextCFI = p + cfiLength;
203 uint32_t ciePointer = addressSpace.get32(p);
204 pint_t cieStart = p - ciePointer;
Ed Maste1b651132016-07-19 17:28:38 +0000205 // Validate pointer to CIE is within section.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000206 if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) {
207 if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) {
208 p += 4;
Ed Maste1b651132016-07-19 17:28:38 +0000209 // Parse pc begin and range.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000210 pint_t pcStart =
211 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
212 pint_t pcRange = addressSpace.getEncodedP(
213 p, nextCFI, cieInfo->pointerEncoding & 0x0F);
Ed Maste1b651132016-07-19 17:28:38 +0000214 // Test if pc is within the function this FDE covers.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000215 if ((pcStart < pc) && (pc <= pcStart + pcRange)) {
216 // parse rest of info
217 fdeInfo->lsda = 0;
218 // check for augmentation length
219 if (cieInfo->fdesHaveAugmentationData) {
220 pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
221 pint_t endOfAug = p + augLen;
222 if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
Ed Maste1b651132016-07-19 17:28:38 +0000223 // Peek at value (without indirection). Zero means no LSDA.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000224 pint_t lsdaStart = p;
225 if (addressSpace.getEncodedP(
226 p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) {
Ed Maste1b651132016-07-19 17:28:38 +0000227 // Reset pointer and re-parse LSDA address.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000228 p = lsdaStart;
229 fdeInfo->lsda = addressSpace
230 .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
231 }
232 }
233 p = endOfAug;
234 }
235 fdeInfo->fdeStart = currentCFI;
236 fdeInfo->fdeLength = nextCFI - currentCFI;
237 fdeInfo->fdeInstructions = p;
238 fdeInfo->pcStart = pcStart;
239 fdeInfo->pcEnd = pcStart + pcRange;
240 return true;
241 } else {
242 // pc is not in begin/range, skip this FDE
243 }
244 } else {
Ed Maste1b651132016-07-19 17:28:38 +0000245 // Malformed CIE, now augmentation describing pc range encoding.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000246 }
247 } else {
248 // malformed FDE. CIE is bad
249 }
250 p = nextCFI;
251 }
252 }
253 return false;
254}
255
256/// Extract info from a CIE
257template <typename A>
258const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
259 CIE_Info *cieInfo) {
260 cieInfo->pointerEncoding = 0;
261 cieInfo->lsdaEncoding = DW_EH_PE_omit;
262 cieInfo->personalityEncoding = 0;
263 cieInfo->personalityOffsetInCIE = 0;
264 cieInfo->personality = 0;
265 cieInfo->codeAlignFactor = 0;
266 cieInfo->dataAlignFactor = 0;
267 cieInfo->isSignalFrame = false;
268 cieInfo->fdesHaveAugmentationData = false;
Luke Cheesemancba83c32018-12-17 11:43:24 +0000269#if defined(_LIBUNWIND_TARGET_AARCH64)
270 cieInfo->addressesSignedWithBKey = false;
271#endif
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000272 cieInfo->cieStart = cie;
273 pint_t p = cie;
274 pint_t cieLength = (pint_t)addressSpace.get32(p);
275 p += 4;
276 pint_t cieContentEnd = p + cieLength;
277 if (cieLength == 0xffffffff) {
278 // 0xffffffff means length is really next 8 bytes
279 cieLength = (pint_t)addressSpace.get64(p);
280 p += 8;
281 cieContentEnd = p + cieLength;
282 }
283 if (cieLength == 0)
284 return NULL;
285 // CIE ID is always 0
286 if (addressSpace.get32(p) != 0)
287 return "CIE ID is not zero";
288 p += 4;
289 // Version is always 1 or 3
290 uint8_t version = addressSpace.get8(p);
291 if ((version != 1) && (version != 3))
292 return "CIE version is not 1 or 3";
293 ++p;
294 // save start of augmentation string and find end
295 pint_t strStart = p;
296 while (addressSpace.get8(p) != 0)
297 ++p;
298 ++p;
299 // parse code aligment factor
300 cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd);
301 // parse data alignment factor
302 cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd);
303 // parse return address register
304 uint64_t raReg = addressSpace.getULEB128(p, cieContentEnd);
305 assert(raReg < 255 && "return address register too large");
306 cieInfo->returnAddressRegister = (uint8_t)raReg;
307 // parse augmentation data based on augmentation string
308 const char *result = NULL;
309 if (addressSpace.get8(strStart) == 'z') {
310 // parse augmentation data length
311 addressSpace.getULEB128(p, cieContentEnd);
312 for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) {
313 switch (addressSpace.get8(s)) {
314 case 'z':
315 cieInfo->fdesHaveAugmentationData = true;
316 break;
317 case 'P':
318 cieInfo->personalityEncoding = addressSpace.get8(p);
319 ++p;
320 cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie);
321 cieInfo->personality = addressSpace
322 .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
323 break;
324 case 'L':
325 cieInfo->lsdaEncoding = addressSpace.get8(p);
326 ++p;
327 break;
328 case 'R':
329 cieInfo->pointerEncoding = addressSpace.get8(p);
330 ++p;
331 break;
332 case 'S':
333 cieInfo->isSignalFrame = true;
334 break;
Luke Cheesemancba83c32018-12-17 11:43:24 +0000335#if defined(_LIBUNWIND_TARGET_AARCH64)
336 case 'B':
337 cieInfo->addressesSignedWithBKey = true;
338 break;
339#endif
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000340 default:
341 // ignore unknown letters
342 break;
343 }
344 }
345 }
346 cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
347 cieInfo->cieInstructions = p;
348 return result;
349}
350
351
Ed Maste4c43c3d2016-07-19 17:15:50 +0000352/// "run" the DWARF instructions and create the abstact PrologInfo for an FDE
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000353template <typename A>
354bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
355 const FDE_Info &fdeInfo,
356 const CIE_Info &cieInfo, pint_t upToPC,
357 PrologInfo *results) {
358 // clear results
359 memset(results, '\0', sizeof(PrologInfo));
360 PrologInfoStackEntry *rememberStack = NULL;
361
362 // parse CIE then FDE instructions
363 return parseInstructions(addressSpace, cieInfo.cieInstructions,
364 cieInfo.cieStart + cieInfo.cieLength, cieInfo,
365 (pint_t)(-1), rememberStack, results) &&
366 parseInstructions(addressSpace, fdeInfo.fdeInstructions,
367 fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo,
368 upToPC - fdeInfo.pcStart, rememberStack, results);
369}
370
Ed Maste4c43c3d2016-07-19 17:15:50 +0000371/// "run" the DWARF instructions
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000372template <typename A>
373bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
374 pint_t instructionsEnd,
375 const CIE_Info &cieInfo, pint_t pcoffset,
376 PrologInfoStackEntry *&rememberStack,
377 PrologInfo *results) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000378 pint_t p = instructions;
379 pint_t codeOffset = 0;
380 PrologInfo initialState = *results;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000381
382 _LIBUNWIND_TRACE_DWARF("parseInstructions(instructions=0x%0" PRIx64 ")\n",
383 static_cast<uint64_t>(instructionsEnd));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000384
Ed Maste4c43c3d2016-07-19 17:15:50 +0000385 // see DWARF Spec, section 6.4.2 for details on unwind opcodes
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000386 while ((p < instructionsEnd) && (codeOffset < pcoffset)) {
387 uint64_t reg;
388 uint64_t reg2;
389 int64_t offset;
390 uint64_t length;
391 uint8_t opcode = addressSpace.get8(p);
392 uint8_t operand;
Peter Zotov0717a2e2015-11-09 06:57:29 +0000393#if !defined(_LIBUNWIND_NO_HEAP)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000394 PrologInfoStackEntry *entry;
Peter Zotov0717a2e2015-11-09 06:57:29 +0000395#endif
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000396 ++p;
397 switch (opcode) {
398 case DW_CFA_nop:
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000399 _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000400 break;
401 case DW_CFA_set_loc:
402 codeOffset =
403 addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000404 _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000405 break;
406 case DW_CFA_advance_loc1:
407 codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
408 p += 1;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000409 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",
410 static_cast<uint64_t>(codeOffset));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000411 break;
412 case DW_CFA_advance_loc2:
413 codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
414 p += 2;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000415 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",
416 static_cast<uint64_t>(codeOffset));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000417 break;
418 case DW_CFA_advance_loc4:
419 codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
420 p += 4;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000421 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",
422 static_cast<uint64_t>(codeOffset));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000423 break;
424 case DW_CFA_offset_extended:
425 reg = addressSpace.getULEB128(p, instructionsEnd);
426 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
427 * cieInfo.dataAlignFactor;
428 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000429 _LIBUNWIND_LOG0(
430 "malformed DW_CFA_offset_extended DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000431 return false;
432 }
433 results->savedRegisters[reg].location = kRegisterInCFA;
434 results->savedRegisters[reg].value = offset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000435 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", "
436 "offset=%" PRId64 ")\n",
437 reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000438 break;
439 case DW_CFA_restore_extended:
440 reg = addressSpace.getULEB128(p, instructionsEnd);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000441 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000442 _LIBUNWIND_LOG0(
443 "malformed DW_CFA_restore_extended DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000444 return false;
445 }
446 results->savedRegisters[reg] = initialState.savedRegisters[reg];
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000447 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000448 break;
449 case DW_CFA_undefined:
450 reg = addressSpace.getULEB128(p, instructionsEnd);
451 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000452 _LIBUNWIND_LOG0(
453 "malformed DW_CFA_undefined DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000454 return false;
455 }
456 results->savedRegisters[reg].location = kRegisterUnused;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000457 _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000458 break;
459 case DW_CFA_same_value:
460 reg = addressSpace.getULEB128(p, instructionsEnd);
461 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000462 _LIBUNWIND_LOG0(
463 "malformed DW_CFA_same_value DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000464 return false;
465 }
466 // <rdar://problem/8456377> DW_CFA_same_value unsupported
467 // "same value" means register was stored in frame, but its current
468 // value has not changed, so no need to restore from frame.
469 // We model this as if the register was never saved.
470 results->savedRegisters[reg].location = kRegisterUnused;
471 // set flag to disable conversion to compact unwind
472 results->sameValueUsed = true;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000473 _LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000474 break;
475 case DW_CFA_register:
476 reg = addressSpace.getULEB128(p, instructionsEnd);
477 reg2 = addressSpace.getULEB128(p, instructionsEnd);
478 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000479 _LIBUNWIND_LOG0(
480 "malformed DW_CFA_register DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000481 return false;
482 }
483 if (reg2 > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000484 _LIBUNWIND_LOG0(
485 "malformed DW_CFA_register DWARF unwind, reg2 too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000486 return false;
487 }
488 results->savedRegisters[reg].location = kRegisterInRegister;
489 results->savedRegisters[reg].value = (int64_t)reg2;
490 // set flag to disable conversion to compact unwind
491 results->registersInOtherRegisters = true;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000492 _LIBUNWIND_TRACE_DWARF(
493 "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000494 break;
Peter Zotov0717a2e2015-11-09 06:57:29 +0000495#if !defined(_LIBUNWIND_NO_HEAP)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000496 case DW_CFA_remember_state:
497 // avoid operator new, because that would be an upward dependency
498 entry = (PrologInfoStackEntry *)malloc(sizeof(PrologInfoStackEntry));
499 if (entry != NULL) {
500 entry->next = rememberStack;
501 entry->info = *results;
502 rememberStack = entry;
503 } else {
504 return false;
505 }
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000506 _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000507 break;
508 case DW_CFA_restore_state:
509 if (rememberStack != NULL) {
510 PrologInfoStackEntry *top = rememberStack;
511 *results = top->info;
512 rememberStack = top->next;
513 free((char *)top);
514 } else {
515 return false;
516 }
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000517 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000518 break;
Peter Zotov0717a2e2015-11-09 06:57:29 +0000519#endif
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000520 case DW_CFA_def_cfa:
521 reg = addressSpace.getULEB128(p, instructionsEnd);
522 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);
523 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000524 _LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000525 return false;
526 }
527 results->cfaRegister = (uint32_t)reg;
528 results->cfaRegisterOffset = (int32_t)offset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000529 _LIBUNWIND_TRACE_DWARF(
530 "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n", reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000531 break;
532 case DW_CFA_def_cfa_register:
533 reg = addressSpace.getULEB128(p, instructionsEnd);
534 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000535 _LIBUNWIND_LOG0(
536 "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000537 return false;
538 }
539 results->cfaRegister = (uint32_t)reg;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000540 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000541 break;
542 case DW_CFA_def_cfa_offset:
543 results->cfaRegisterOffset = (int32_t)
544 addressSpace.getULEB128(p, instructionsEnd);
545 results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000546 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n",
547 results->cfaRegisterOffset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000548 break;
549 case DW_CFA_def_cfa_expression:
550 results->cfaRegister = 0;
551 results->cfaExpression = (int64_t)p;
552 length = addressSpace.getULEB128(p, instructionsEnd);
whitequark443f65c2017-12-25 21:08:41 +0000553 assert(length < static_cast<pint_t>(~0) && "pointer overflow");
Saleem Abdulrasool92acbf12017-03-08 16:03:27 +0000554 p += static_cast<pint_t>(length);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000555 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64
556 ", length=%" PRIu64 ")\n",
557 results->cfaExpression, length);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000558 break;
559 case DW_CFA_expression:
560 reg = addressSpace.getULEB128(p, instructionsEnd);
561 if (reg > kMaxRegisterNumber) {
whitequarka3b115c2017-12-25 13:42:41 +0000562 _LIBUNWIND_LOG0(
whitequarkb718c5f2017-12-25 13:27:56 +0000563 "malformed DW_CFA_expression DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000564 return false;
565 }
566 results->savedRegisters[reg].location = kRegisterAtExpression;
567 results->savedRegisters[reg].value = (int64_t)p;
568 length = addressSpace.getULEB128(p, instructionsEnd);
whitequark443f65c2017-12-25 21:08:41 +0000569 assert(length < static_cast<pint_t>(~0) && "pointer overflow");
Saleem Abdulrasool92acbf12017-03-08 16:03:27 +0000570 p += static_cast<pint_t>(length);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000571 _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", "
572 "expression=0x%" PRIx64 ", "
573 "length=%" PRIu64 ")\n",
574 reg, results->savedRegisters[reg].value, length);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000575 break;
576 case DW_CFA_offset_extended_sf:
577 reg = addressSpace.getULEB128(p, instructionsEnd);
578 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000579 _LIBUNWIND_LOG0(
580 "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000581 return false;
582 }
583 offset =
584 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
585 results->savedRegisters[reg].location = kRegisterInCFA;
586 results->savedRegisters[reg].value = offset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000587 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", "
588 "offset=%" PRId64 ")\n",
589 reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000590 break;
591 case DW_CFA_def_cfa_sf:
592 reg = addressSpace.getULEB128(p, instructionsEnd);
593 offset =
594 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
595 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000596 _LIBUNWIND_LOG0(
597 "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000598 return false;
599 }
600 results->cfaRegister = (uint32_t)reg;
601 results->cfaRegisterOffset = (int32_t)offset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000602 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", "
603 "offset=%" PRId64 ")\n",
604 reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000605 break;
606 case DW_CFA_def_cfa_offset_sf:
607 results->cfaRegisterOffset = (int32_t)
608 (addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor);
609 results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000610 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n",
611 results->cfaRegisterOffset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000612 break;
613 case DW_CFA_val_offset:
614 reg = addressSpace.getULEB128(p, instructionsEnd);
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000615 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000616 _LIBUNWIND_LOG(
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000617 "malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64
618 ") out of range\n",
619 reg);
620 return false;
621 }
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000622 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
623 * cieInfo.dataAlignFactor;
624 results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
625 results->savedRegisters[reg].value = offset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000626 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", "
627 "offset=%" PRId64 "\n",
628 reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000629 break;
630 case DW_CFA_val_offset_sf:
631 reg = addressSpace.getULEB128(p, instructionsEnd);
632 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000633 _LIBUNWIND_LOG0(
634 "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000635 return false;
636 }
637 offset =
638 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
639 results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
640 results->savedRegisters[reg].value = offset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000641 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", "
642 "offset=%" PRId64 "\n",
643 reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000644 break;
645 case DW_CFA_val_expression:
646 reg = addressSpace.getULEB128(p, instructionsEnd);
647 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000648 _LIBUNWIND_LOG0(
649 "malformed DW_CFA_val_expression DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000650 return false;
651 }
652 results->savedRegisters[reg].location = kRegisterIsExpression;
653 results->savedRegisters[reg].value = (int64_t)p;
654 length = addressSpace.getULEB128(p, instructionsEnd);
whitequark443f65c2017-12-25 21:08:41 +0000655 assert(length < static_cast<pint_t>(~0) && "pointer overflow");
Saleem Abdulrasool92acbf12017-03-08 16:03:27 +0000656 p += static_cast<pint_t>(length);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000657 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", "
658 "expression=0x%" PRIx64 ", length=%" PRIu64 ")\n",
659 reg, results->savedRegisters[reg].value, length);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000660 break;
661 case DW_CFA_GNU_args_size:
662 length = addressSpace.getULEB128(p, instructionsEnd);
663 results->spExtraArgSize = (uint32_t)length;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000664 _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000665 break;
666 case DW_CFA_GNU_negative_offset_extended:
667 reg = addressSpace.getULEB128(p, instructionsEnd);
668 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000669 _LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF "
670 "unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000671 return false;
672 }
673 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
674 * cieInfo.dataAlignFactor;
675 results->savedRegisters[reg].location = kRegisterInCFA;
676 results->savedRegisters[reg].value = -offset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000677 _LIBUNWIND_TRACE_DWARF(
678 "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000679 break;
Luke Cheeseman4d8e4312018-12-14 11:30:12 +0000680
681#if defined(_LIBUNWIND_TARGET_AARCH64)
682 case DW_CFA_AARCH64_negate_ra_state:
683 results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^= 0x1;
684 _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n");
685 break;
686#endif
687
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000688 default:
689 operand = opcode & 0x3F;
690 switch (opcode & 0xC0) {
691 case DW_CFA_offset:
692 reg = operand;
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000693 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000694 _LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64
695 ") out of range",
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000696 reg);
697 return false;
698 }
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000699 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
700 * cieInfo.dataAlignFactor;
701 results->savedRegisters[reg].location = kRegisterInCFA;
702 results->savedRegisters[reg].value = offset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000703 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
704 operand, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000705 break;
706 case DW_CFA_advance_loc:
707 codeOffset += operand * cieInfo.codeAlignFactor;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000708 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
709 static_cast<uint64_t>(codeOffset));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000710 break;
711 case DW_CFA_restore:
712 reg = operand;
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000713 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000714 _LIBUNWIND_LOG("malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64
715 ") out of range",
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000716 reg);
717 return false;
718 }
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000719 results->savedRegisters[reg] = initialState.savedRegisters[reg];
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000720 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",
Saleem Abdulrasoolc73a3c32017-01-21 21:27:29 +0000721 static_cast<uint64_t>(operand));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000722 break;
723 default:
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000724 _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000725 return false;
726 }
727 }
728 }
729
730 return true;
731}
732
733} // namespace libunwind
734
735#endif // __DWARF_PARSER_HPP__