blob: 1ce2cf2943a2f505d6f6729f47c88756dd9f43bc [file] [log] [blame]
Saleem Abdulrasool17552662015-04-24 19:39:17 +00001//===--------------------------- DwarfParser.hpp --------------------------===//
2//
Chandler Carruth61860a52019-01-19 10:56:40 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Saleem Abdulrasool17552662015-04-24 19:39:17 +00006//
7//
8// Parses DWARF CFIs (FDEs and CIEs).
9//
10//===----------------------------------------------------------------------===//
11
12#ifndef __DWARF_PARSER_HPP__
13#define __DWARF_PARSER_HPP__
14
15#include <inttypes.h>
16#include <stdint.h>
17#include <stdio.h>
18#include <stdlib.h>
19
Saleem Abdulrasool17552662015-04-24 19:39:17 +000020#include "libunwind.h"
21#include "dwarf2.h"
Daniel Cederman9f2f07a2019-01-14 10:15:20 +000022#include "Registers.hpp"
Saleem Abdulrasool17552662015-04-24 19:39:17 +000023
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,
Daniel Kissd6c1e482020-09-16 23:03:19 +020072 kRegisterUndefined,
Saleem Abdulrasool17552662015-04-24 19:39:17 +000073 kRegisterInCFA,
74 kRegisterOffsetFromCFA,
75 kRegisterInRegister,
76 kRegisterAtExpression,
77 kRegisterIsExpression
78 };
79 struct RegisterLocation {
80 RegisterSavedWhere location;
Sterling Augustinec0ef0db2020-03-04 16:29:58 -080081 bool initialStateSaved;
Saleem Abdulrasool17552662015-04-24 19:39:17 +000082 int64_t value;
83 };
84 /// Information about a frame layout and registers saved determined
Ed Maste4c43c3d2016-07-19 17:15:50 +000085 /// by "running" the DWARF FDE "instructions"
Saleem Abdulrasool17552662015-04-24 19:39:17 +000086 struct PrologInfo {
87 uint32_t cfaRegister;
88 int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
89 int64_t cfaExpression; // CFA = expression
90 uint32_t spExtraArgSize;
91 uint32_t codeOffsetAtStackDecrement;
92 bool registersInOtherRegisters;
93 bool sameValueUsed;
Martin Storsjof10f3c92017-10-27 07:59:01 +000094 RegisterLocation savedRegisters[kMaxRegisterNumber + 1];
Sterling Augustinec0ef0db2020-03-04 16:29:58 -080095 enum class InitializeTime { kLazy, kNormal };
96
97 // When saving registers, this data structure is lazily initialized.
98 PrologInfo(InitializeTime IT = InitializeTime::kNormal) {
99 if (IT == InitializeTime::kNormal)
100 memset(this, 0, sizeof(*this));
101 }
102 void checkSaveRegister(uint64_t reg, PrologInfo &initialState) {
103 if (!savedRegisters[reg].initialStateSaved) {
104 initialState.savedRegisters[reg] = savedRegisters[reg];
105 savedRegisters[reg].initialStateSaved = true;
106 }
107 }
108 void setRegister(uint64_t reg, RegisterSavedWhere newLocation,
109 int64_t newValue, PrologInfo &initialState) {
110 checkSaveRegister(reg, initialState);
111 savedRegisters[reg].location = newLocation;
112 savedRegisters[reg].value = newValue;
113 }
114 void setRegisterLocation(uint64_t reg, RegisterSavedWhere newLocation,
115 PrologInfo &initialState) {
116 checkSaveRegister(reg, initialState);
117 savedRegisters[reg].location = newLocation;
118 }
119 void setRegisterValue(uint64_t reg, int64_t newValue,
120 PrologInfo &initialState) {
121 checkSaveRegister(reg, initialState);
122 savedRegisters[reg].value = newValue;
123 }
124 void restoreRegisterToInitialState(uint64_t reg, PrologInfo &initialState) {
125 if (savedRegisters[reg].initialStateSaved)
126 savedRegisters[reg] = initialState.savedRegisters[reg];
127 // else the register still holds its initial state
128 }
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000129 };
130
131 struct PrologInfoStackEntry {
132 PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i)
133 : next(n), info(i) {}
134 PrologInfoStackEntry *next;
135 PrologInfo info;
136 };
137
138 static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
139 uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
140 CIE_Info *cieInfo);
141 static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
142 FDE_Info *fdeInfo, CIE_Info *cieInfo);
143 static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,
144 const CIE_Info &cieInfo, pint_t upToPC,
Daniel Cederman9f2f07a2019-01-14 10:15:20 +0000145 int arch, PrologInfo *results);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000146
147 static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
148
149private:
150 static bool parseInstructions(A &addressSpace, pint_t instructions,
151 pint_t instructionsEnd, const CIE_Info &cieInfo,
152 pint_t pcoffset,
Daniel Cederman9f2f07a2019-01-14 10:15:20 +0000153 PrologInfoStackEntry *&rememberStack, int arch,
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000154 PrologInfo *results);
155};
156
157/// Parse a FDE into a CIE_Info and an FDE_Info
158template <typename A>
159const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
160 FDE_Info *fdeInfo, CIE_Info *cieInfo) {
161 pint_t p = fdeStart;
162 pint_t cfiLength = (pint_t)addressSpace.get32(p);
163 p += 4;
164 if (cfiLength == 0xffffffff) {
165 // 0xffffffff means length is really next 8 bytes
166 cfiLength = (pint_t)addressSpace.get64(p);
167 p += 8;
168 }
169 if (cfiLength == 0)
170 return "FDE has zero length"; // end marker
171 uint32_t ciePointer = addressSpace.get32(p);
172 if (ciePointer == 0)
173 return "FDE is really a CIE"; // this is a CIE not an FDE
174 pint_t nextCFI = p + cfiLength;
175 pint_t cieStart = p - ciePointer;
176 const char *err = parseCIE(addressSpace, cieStart, cieInfo);
177 if (err != NULL)
178 return err;
179 p += 4;
Ed Maste1b651132016-07-19 17:28:38 +0000180 // Parse pc begin and range.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000181 pint_t pcStart =
182 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
183 pint_t pcRange =
184 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
Ed Maste1b651132016-07-19 17:28:38 +0000185 // Parse rest of info.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000186 fdeInfo->lsda = 0;
Ed Maste1b651132016-07-19 17:28:38 +0000187 // Check for augmentation length.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000188 if (cieInfo->fdesHaveAugmentationData) {
189 pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
190 pint_t endOfAug = p + augLen;
191 if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
Ed Maste1b651132016-07-19 17:28:38 +0000192 // Peek at value (without indirection). Zero means no LSDA.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000193 pint_t lsdaStart = p;
194 if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) !=
195 0) {
Ed Maste1b651132016-07-19 17:28:38 +0000196 // Reset pointer and re-parse LSDA address.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000197 p = lsdaStart;
198 fdeInfo->lsda =
199 addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
200 }
201 }
202 p = endOfAug;
203 }
204 fdeInfo->fdeStart = fdeStart;
205 fdeInfo->fdeLength = nextCFI - fdeStart;
206 fdeInfo->fdeInstructions = p;
207 fdeInfo->pcStart = pcStart;
208 fdeInfo->pcEnd = pcStart + pcRange;
209 return NULL; // success
210}
211
212/// Scan an eh_frame section to find an FDE for a pc
213template <typename A>
214bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
215 uint32_t sectionLength, pint_t fdeHint,
216 FDE_Info *fdeInfo, CIE_Info *cieInfo) {
217 //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
218 pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
219 const pint_t ehSectionEnd = p + sectionLength;
220 while (p < ehSectionEnd) {
221 pint_t currentCFI = p;
222 //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
223 pint_t cfiLength = addressSpace.get32(p);
224 p += 4;
225 if (cfiLength == 0xffffffff) {
226 // 0xffffffff means length is really next 8 bytes
227 cfiLength = (pint_t)addressSpace.get64(p);
228 p += 8;
229 }
230 if (cfiLength == 0)
231 return false; // end marker
232 uint32_t id = addressSpace.get32(p);
233 if (id == 0) {
Ed Maste1b651132016-07-19 17:28:38 +0000234 // Skip over CIEs.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000235 p += cfiLength;
236 } else {
Ed Maste1b651132016-07-19 17:28:38 +0000237 // Process FDE to see if it covers pc.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000238 pint_t nextCFI = p + cfiLength;
239 uint32_t ciePointer = addressSpace.get32(p);
240 pint_t cieStart = p - ciePointer;
Ed Maste1b651132016-07-19 17:28:38 +0000241 // Validate pointer to CIE is within section.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000242 if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) {
243 if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) {
244 p += 4;
Ed Maste1b651132016-07-19 17:28:38 +0000245 // Parse pc begin and range.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000246 pint_t pcStart =
247 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
248 pint_t pcRange = addressSpace.getEncodedP(
249 p, nextCFI, cieInfo->pointerEncoding & 0x0F);
Ed Maste1b651132016-07-19 17:28:38 +0000250 // Test if pc is within the function this FDE covers.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000251 if ((pcStart < pc) && (pc <= pcStart + pcRange)) {
252 // parse rest of info
253 fdeInfo->lsda = 0;
254 // check for augmentation length
255 if (cieInfo->fdesHaveAugmentationData) {
256 pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
257 pint_t endOfAug = p + augLen;
258 if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
Ed Maste1b651132016-07-19 17:28:38 +0000259 // Peek at value (without indirection). Zero means no LSDA.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000260 pint_t lsdaStart = p;
261 if (addressSpace.getEncodedP(
262 p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) {
Ed Maste1b651132016-07-19 17:28:38 +0000263 // Reset pointer and re-parse LSDA address.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000264 p = lsdaStart;
265 fdeInfo->lsda = addressSpace
266 .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
267 }
268 }
269 p = endOfAug;
270 }
271 fdeInfo->fdeStart = currentCFI;
272 fdeInfo->fdeLength = nextCFI - currentCFI;
273 fdeInfo->fdeInstructions = p;
274 fdeInfo->pcStart = pcStart;
275 fdeInfo->pcEnd = pcStart + pcRange;
276 return true;
277 } else {
278 // pc is not in begin/range, skip this FDE
279 }
280 } else {
Ed Maste1b651132016-07-19 17:28:38 +0000281 // Malformed CIE, now augmentation describing pc range encoding.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000282 }
283 } else {
284 // malformed FDE. CIE is bad
285 }
286 p = nextCFI;
287 }
288 }
289 return false;
290}
291
292/// Extract info from a CIE
293template <typename A>
294const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
295 CIE_Info *cieInfo) {
296 cieInfo->pointerEncoding = 0;
297 cieInfo->lsdaEncoding = DW_EH_PE_omit;
298 cieInfo->personalityEncoding = 0;
299 cieInfo->personalityOffsetInCIE = 0;
300 cieInfo->personality = 0;
301 cieInfo->codeAlignFactor = 0;
302 cieInfo->dataAlignFactor = 0;
303 cieInfo->isSignalFrame = false;
304 cieInfo->fdesHaveAugmentationData = false;
Luke Cheesemancba83c32018-12-17 11:43:24 +0000305#if defined(_LIBUNWIND_TARGET_AARCH64)
306 cieInfo->addressesSignedWithBKey = false;
307#endif
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000308 cieInfo->cieStart = cie;
309 pint_t p = cie;
310 pint_t cieLength = (pint_t)addressSpace.get32(p);
311 p += 4;
312 pint_t cieContentEnd = p + cieLength;
313 if (cieLength == 0xffffffff) {
314 // 0xffffffff means length is really next 8 bytes
315 cieLength = (pint_t)addressSpace.get64(p);
316 p += 8;
317 cieContentEnd = p + cieLength;
318 }
319 if (cieLength == 0)
320 return NULL;
321 // CIE ID is always 0
322 if (addressSpace.get32(p) != 0)
323 return "CIE ID is not zero";
324 p += 4;
325 // Version is always 1 or 3
326 uint8_t version = addressSpace.get8(p);
327 if ((version != 1) && (version != 3))
328 return "CIE version is not 1 or 3";
329 ++p;
330 // save start of augmentation string and find end
331 pint_t strStart = p;
332 while (addressSpace.get8(p) != 0)
333 ++p;
334 ++p;
335 // parse code aligment factor
336 cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd);
337 // parse data alignment factor
338 cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd);
339 // parse return address register
Ryan Prichard58b19e62020-07-13 22:06:22 -0700340 uint64_t raReg = (version == 1) ? addressSpace.get8(p++)
341 : addressSpace.getULEB128(p, cieContentEnd);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000342 assert(raReg < 255 && "return address register too large");
343 cieInfo->returnAddressRegister = (uint8_t)raReg;
344 // parse augmentation data based on augmentation string
345 const char *result = NULL;
346 if (addressSpace.get8(strStart) == 'z') {
347 // parse augmentation data length
348 addressSpace.getULEB128(p, cieContentEnd);
349 for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) {
350 switch (addressSpace.get8(s)) {
351 case 'z':
352 cieInfo->fdesHaveAugmentationData = true;
353 break;
354 case 'P':
355 cieInfo->personalityEncoding = addressSpace.get8(p);
356 ++p;
357 cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie);
358 cieInfo->personality = addressSpace
359 .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
360 break;
361 case 'L':
362 cieInfo->lsdaEncoding = addressSpace.get8(p);
363 ++p;
364 break;
365 case 'R':
366 cieInfo->pointerEncoding = addressSpace.get8(p);
367 ++p;
368 break;
369 case 'S':
370 cieInfo->isSignalFrame = true;
371 break;
Luke Cheesemancba83c32018-12-17 11:43:24 +0000372#if defined(_LIBUNWIND_TARGET_AARCH64)
373 case 'B':
374 cieInfo->addressesSignedWithBKey = true;
375 break;
376#endif
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000377 default:
378 // ignore unknown letters
379 break;
380 }
381 }
382 }
383 cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
384 cieInfo->cieInstructions = p;
385 return result;
386}
387
388
Ed Maste4c43c3d2016-07-19 17:15:50 +0000389/// "run" the DWARF instructions and create the abstact PrologInfo for an FDE
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000390template <typename A>
391bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
392 const FDE_Info &fdeInfo,
393 const CIE_Info &cieInfo, pint_t upToPC,
Daniel Cederman9f2f07a2019-01-14 10:15:20 +0000394 int arch, PrologInfo *results) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000395 PrologInfoStackEntry *rememberStack = NULL;
396
397 // parse CIE then FDE instructions
Jorge Gorbe Moyafd8399e2020-02-18 11:48:02 -0800398 bool returnValue =
399 parseInstructions(addressSpace, cieInfo.cieInstructions,
400 cieInfo.cieStart + cieInfo.cieLength, cieInfo,
401 (pint_t)(-1), rememberStack, arch, results) &&
402 parseInstructions(addressSpace, fdeInfo.fdeInstructions,
403 fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo,
404 upToPC - fdeInfo.pcStart, rememberStack, arch, results);
405
Saleem Abdulrasool1ffb31a2020-05-15 14:43:19 -0700406#if !defined(_LIBUNWIND_NO_HEAP)
Jorge Gorbe Moyafd8399e2020-02-18 11:48:02 -0800407 // Clean up rememberStack. Even in the case where every DW_CFA_remember_state
408 // is paired with a DW_CFA_restore_state, parseInstructions can skip restore
409 // opcodes if it reaches the target PC and stops interpreting, so we have to
410 // make sure we don't leak memory.
411 while (rememberStack) {
412 PrologInfoStackEntry *next = rememberStack->next;
413 free(rememberStack);
414 rememberStack = next;
415 }
Saleem Abdulrasool1ffb31a2020-05-15 14:43:19 -0700416#endif
Jorge Gorbe Moyafd8399e2020-02-18 11:48:02 -0800417
418 return returnValue;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000419}
420
Ed Maste4c43c3d2016-07-19 17:15:50 +0000421/// "run" the DWARF instructions
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000422template <typename A>
423bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
424 pint_t instructionsEnd,
425 const CIE_Info &cieInfo, pint_t pcoffset,
426 PrologInfoStackEntry *&rememberStack,
Daniel Cederman9f2f07a2019-01-14 10:15:20 +0000427 int arch, PrologInfo *results) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000428 pint_t p = instructions;
429 pint_t codeOffset = 0;
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800430 // initialState initialized as registers in results are modified. Use
431 // PrologInfo accessor functions to avoid reading uninitialized data.
432 PrologInfo initialState(PrologInfo::InitializeTime::kLazy);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000433
434 _LIBUNWIND_TRACE_DWARF("parseInstructions(instructions=0x%0" PRIx64 ")\n",
435 static_cast<uint64_t>(instructionsEnd));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000436
Ed Maste4c43c3d2016-07-19 17:15:50 +0000437 // see DWARF Spec, section 6.4.2 for details on unwind opcodes
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000438 while ((p < instructionsEnd) && (codeOffset < pcoffset)) {
439 uint64_t reg;
440 uint64_t reg2;
441 int64_t offset;
442 uint64_t length;
443 uint8_t opcode = addressSpace.get8(p);
444 uint8_t operand;
Peter Zotov0717a2e2015-11-09 06:57:29 +0000445#if !defined(_LIBUNWIND_NO_HEAP)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000446 PrologInfoStackEntry *entry;
Peter Zotov0717a2e2015-11-09 06:57:29 +0000447#endif
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000448 ++p;
449 switch (opcode) {
450 case DW_CFA_nop:
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000451 _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000452 break;
453 case DW_CFA_set_loc:
454 codeOffset =
455 addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000456 _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000457 break;
458 case DW_CFA_advance_loc1:
459 codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
460 p += 1;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000461 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",
462 static_cast<uint64_t>(codeOffset));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000463 break;
464 case DW_CFA_advance_loc2:
465 codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
466 p += 2;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000467 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",
468 static_cast<uint64_t>(codeOffset));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000469 break;
470 case DW_CFA_advance_loc4:
471 codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
472 p += 4;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000473 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",
474 static_cast<uint64_t>(codeOffset));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000475 break;
476 case DW_CFA_offset_extended:
477 reg = addressSpace.getULEB128(p, instructionsEnd);
478 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
479 * cieInfo.dataAlignFactor;
480 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000481 _LIBUNWIND_LOG0(
482 "malformed DW_CFA_offset_extended DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000483 return false;
484 }
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800485 results->setRegister(reg, kRegisterInCFA, offset, initialState);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000486 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", "
487 "offset=%" PRId64 ")\n",
488 reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000489 break;
490 case DW_CFA_restore_extended:
491 reg = addressSpace.getULEB128(p, instructionsEnd);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000492 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000493 _LIBUNWIND_LOG0(
494 "malformed DW_CFA_restore_extended DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000495 return false;
496 }
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800497 results->restoreRegisterToInitialState(reg, initialState);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000498 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000499 break;
500 case DW_CFA_undefined:
501 reg = addressSpace.getULEB128(p, instructionsEnd);
502 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000503 _LIBUNWIND_LOG0(
504 "malformed DW_CFA_undefined DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000505 return false;
506 }
Daniel Kissd6c1e482020-09-16 23:03:19 +0200507 results->setRegisterLocation(reg, kRegisterUndefined, initialState);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000508 _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000509 break;
510 case DW_CFA_same_value:
511 reg = addressSpace.getULEB128(p, instructionsEnd);
512 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000513 _LIBUNWIND_LOG0(
514 "malformed DW_CFA_same_value DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000515 return false;
516 }
517 // <rdar://problem/8456377> DW_CFA_same_value unsupported
518 // "same value" means register was stored in frame, but its current
519 // value has not changed, so no need to restore from frame.
520 // We model this as if the register was never saved.
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800521 results->setRegisterLocation(reg, kRegisterUnused, initialState);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000522 // set flag to disable conversion to compact unwind
523 results->sameValueUsed = true;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000524 _LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000525 break;
526 case DW_CFA_register:
527 reg = addressSpace.getULEB128(p, instructionsEnd);
528 reg2 = addressSpace.getULEB128(p, instructionsEnd);
529 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000530 _LIBUNWIND_LOG0(
531 "malformed DW_CFA_register DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000532 return false;
533 }
534 if (reg2 > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000535 _LIBUNWIND_LOG0(
536 "malformed DW_CFA_register DWARF unwind, reg2 too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000537 return false;
538 }
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800539 results->setRegister(reg, kRegisterInRegister, (int64_t)reg2,
540 initialState);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000541 // set flag to disable conversion to compact unwind
542 results->registersInOtherRegisters = true;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000543 _LIBUNWIND_TRACE_DWARF(
544 "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000545 break;
Peter Zotov0717a2e2015-11-09 06:57:29 +0000546#if !defined(_LIBUNWIND_NO_HEAP)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000547 case DW_CFA_remember_state:
548 // avoid operator new, because that would be an upward dependency
549 entry = (PrologInfoStackEntry *)malloc(sizeof(PrologInfoStackEntry));
550 if (entry != NULL) {
551 entry->next = rememberStack;
552 entry->info = *results;
553 rememberStack = entry;
554 } else {
555 return false;
556 }
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000557 _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000558 break;
559 case DW_CFA_restore_state:
560 if (rememberStack != NULL) {
561 PrologInfoStackEntry *top = rememberStack;
562 *results = top->info;
563 rememberStack = top->next;
564 free((char *)top);
565 } else {
566 return false;
567 }
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000568 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000569 break;
Peter Zotov0717a2e2015-11-09 06:57:29 +0000570#endif
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000571 case DW_CFA_def_cfa:
572 reg = addressSpace.getULEB128(p, instructionsEnd);
573 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);
574 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000575 _LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000576 return false;
577 }
578 results->cfaRegister = (uint32_t)reg;
579 results->cfaRegisterOffset = (int32_t)offset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000580 _LIBUNWIND_TRACE_DWARF(
581 "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n", reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000582 break;
583 case DW_CFA_def_cfa_register:
584 reg = addressSpace.getULEB128(p, instructionsEnd);
585 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000586 _LIBUNWIND_LOG0(
587 "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000588 return false;
589 }
590 results->cfaRegister = (uint32_t)reg;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000591 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000592 break;
593 case DW_CFA_def_cfa_offset:
594 results->cfaRegisterOffset = (int32_t)
595 addressSpace.getULEB128(p, instructionsEnd);
596 results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000597 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n",
598 results->cfaRegisterOffset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000599 break;
600 case DW_CFA_def_cfa_expression:
601 results->cfaRegister = 0;
602 results->cfaExpression = (int64_t)p;
603 length = addressSpace.getULEB128(p, instructionsEnd);
whitequark443f65c2017-12-25 21:08:41 +0000604 assert(length < static_cast<pint_t>(~0) && "pointer overflow");
Saleem Abdulrasool92acbf12017-03-08 16:03:27 +0000605 p += static_cast<pint_t>(length);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000606 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64
607 ", length=%" PRIu64 ")\n",
608 results->cfaExpression, length);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000609 break;
610 case DW_CFA_expression:
611 reg = addressSpace.getULEB128(p, instructionsEnd);
612 if (reg > kMaxRegisterNumber) {
whitequarka3b115c2017-12-25 13:42:41 +0000613 _LIBUNWIND_LOG0(
whitequarkb718c5f2017-12-25 13:27:56 +0000614 "malformed DW_CFA_expression DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000615 return false;
616 }
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800617 results->setRegister(reg, kRegisterAtExpression, (int64_t)p,
618 initialState);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000619 length = addressSpace.getULEB128(p, instructionsEnd);
whitequark443f65c2017-12-25 21:08:41 +0000620 assert(length < static_cast<pint_t>(~0) && "pointer overflow");
Saleem Abdulrasool92acbf12017-03-08 16:03:27 +0000621 p += static_cast<pint_t>(length);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000622 _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", "
623 "expression=0x%" PRIx64 ", "
624 "length=%" PRIu64 ")\n",
625 reg, results->savedRegisters[reg].value, length);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000626 break;
627 case DW_CFA_offset_extended_sf:
628 reg = addressSpace.getULEB128(p, instructionsEnd);
629 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000630 _LIBUNWIND_LOG0(
631 "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000632 return false;
633 }
634 offset =
635 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800636 results->setRegister(reg, kRegisterInCFA, offset, initialState);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000637 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", "
638 "offset=%" PRId64 ")\n",
639 reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000640 break;
641 case DW_CFA_def_cfa_sf:
642 reg = addressSpace.getULEB128(p, instructionsEnd);
643 offset =
644 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
645 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000646 _LIBUNWIND_LOG0(
647 "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000648 return false;
649 }
650 results->cfaRegister = (uint32_t)reg;
651 results->cfaRegisterOffset = (int32_t)offset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000652 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", "
653 "offset=%" PRId64 ")\n",
654 reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000655 break;
656 case DW_CFA_def_cfa_offset_sf:
657 results->cfaRegisterOffset = (int32_t)
658 (addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor);
659 results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000660 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n",
661 results->cfaRegisterOffset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000662 break;
663 case DW_CFA_val_offset:
664 reg = addressSpace.getULEB128(p, instructionsEnd);
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000665 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000666 _LIBUNWIND_LOG(
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000667 "malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64
668 ") out of range\n",
669 reg);
670 return false;
671 }
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000672 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
673 * cieInfo.dataAlignFactor;
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800674 results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000675 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", "
676 "offset=%" PRId64 "\n",
677 reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000678 break;
679 case DW_CFA_val_offset_sf:
680 reg = addressSpace.getULEB128(p, instructionsEnd);
681 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000682 _LIBUNWIND_LOG0(
683 "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000684 return false;
685 }
686 offset =
687 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800688 results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000689 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", "
690 "offset=%" PRId64 "\n",
691 reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000692 break;
693 case DW_CFA_val_expression:
694 reg = addressSpace.getULEB128(p, instructionsEnd);
695 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000696 _LIBUNWIND_LOG0(
697 "malformed DW_CFA_val_expression DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000698 return false;
699 }
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800700 results->setRegister(reg, kRegisterIsExpression, (int64_t)p,
701 initialState);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000702 length = addressSpace.getULEB128(p, instructionsEnd);
whitequark443f65c2017-12-25 21:08:41 +0000703 assert(length < static_cast<pint_t>(~0) && "pointer overflow");
Saleem Abdulrasool92acbf12017-03-08 16:03:27 +0000704 p += static_cast<pint_t>(length);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000705 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", "
706 "expression=0x%" PRIx64 ", length=%" PRIu64 ")\n",
707 reg, results->savedRegisters[reg].value, length);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000708 break;
709 case DW_CFA_GNU_args_size:
710 length = addressSpace.getULEB128(p, instructionsEnd);
711 results->spExtraArgSize = (uint32_t)length;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000712 _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000713 break;
714 case DW_CFA_GNU_negative_offset_extended:
715 reg = addressSpace.getULEB128(p, instructionsEnd);
716 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000717 _LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF "
718 "unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000719 return false;
720 }
721 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
722 * cieInfo.dataAlignFactor;
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800723 results->setRegister(reg, kRegisterInCFA, -offset, initialState);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000724 _LIBUNWIND_TRACE_DWARF(
725 "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000726 break;
Luke Cheeseman4d8e4312018-12-14 11:30:12 +0000727
Daniel Cederman9f2f07a2019-01-14 10:15:20 +0000728#if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC)
729 // The same constant is used to represent different instructions on
730 // AArch64 (negate_ra_state) and SPARC (window_save).
731 static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save,
732 "uses the same constant");
Luke Cheeseman4d8e4312018-12-14 11:30:12 +0000733 case DW_CFA_AARCH64_negate_ra_state:
Daniel Cederman9f2f07a2019-01-14 10:15:20 +0000734 switch (arch) {
735#if defined(_LIBUNWIND_TARGET_AARCH64)
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800736 case REGISTERS_ARM64: {
737 int64_t value =
738 results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^ 0x1;
739 results->setRegisterValue(UNW_ARM64_RA_SIGN_STATE, value, initialState);
740 _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n");
741 } break;
Daniel Cederman9f2f07a2019-01-14 10:15:20 +0000742#endif
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800743
Daniel Cederman9f2f07a2019-01-14 10:15:20 +0000744#if defined(_LIBUNWIND_TARGET_SPARC)
745 // case DW_CFA_GNU_window_save:
746 case REGISTERS_SPARC:
747 _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n");
748 for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) {
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800749 results->setRegister(reg, kRegisterInRegister,
750 ((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0,
751 initialState);
Daniel Cederman9f2f07a2019-01-14 10:15:20 +0000752 }
753
754 for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800755 results->setRegister(reg, kRegisterInCFA,
756 ((int64_t)reg - UNW_SPARC_L0) * 4, initialState);
Daniel Cederman9f2f07a2019-01-14 10:15:20 +0000757 }
758 break;
759#endif
760 }
Luke Cheeseman4d8e4312018-12-14 11:30:12 +0000761 break;
Daniel Cederman9f2f07a2019-01-14 10:15:20 +0000762#else
763 (void)arch;
Luke Cheeseman4d8e4312018-12-14 11:30:12 +0000764#endif
765
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000766 default:
767 operand = opcode & 0x3F;
768 switch (opcode & 0xC0) {
769 case DW_CFA_offset:
770 reg = operand;
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000771 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000772 _LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64
773 ") out of range",
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000774 reg);
775 return false;
776 }
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000777 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
778 * cieInfo.dataAlignFactor;
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800779 results->setRegister(reg, kRegisterInCFA, offset, initialState);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000780 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
781 operand, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000782 break;
783 case DW_CFA_advance_loc:
784 codeOffset += operand * cieInfo.codeAlignFactor;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000785 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
786 static_cast<uint64_t>(codeOffset));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000787 break;
788 case DW_CFA_restore:
789 reg = operand;
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000790 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000791 _LIBUNWIND_LOG("malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64
792 ") out of range",
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000793 reg);
794 return false;
795 }
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800796 results->restoreRegisterToInitialState(reg, initialState);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000797 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",
Saleem Abdulrasoolc73a3c32017-01-21 21:27:29 +0000798 static_cast<uint64_t>(operand));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000799 break;
800 default:
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000801 _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000802 return false;
803 }
804 }
805 }
806
807 return true;
808}
809
810} // namespace libunwind
811
812#endif // __DWARF_PARSER_HPP__