blob: 86c0522afd3ff2f15c4957ca4d460080af71983c [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,
Ryan Prichard0cff8572020-09-16 01:22:55 -0700139 uintptr_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000140 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)
Ryan Prichard0cff8572020-09-16 01:22:55 -0700170 return "FDE has zero length"; // zero terminator
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000171 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,
Ryan Prichard0cff8572020-09-16 01:22:55 -0700215 uintptr_t sectionLength, pint_t fdeHint,
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000216 FDE_Info *fdeInfo, CIE_Info *cieInfo) {
217 //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
218 pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
Ryan Prichard0cff8572020-09-16 01:22:55 -0700219 const pint_t ehSectionEnd = (sectionLength == UINTPTR_MAX)
220 ? static_cast<pint_t>(-1)
221 : (ehSectionStart + sectionLength);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000222 while (p < ehSectionEnd) {
223 pint_t currentCFI = p;
224 //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
225 pint_t cfiLength = addressSpace.get32(p);
226 p += 4;
227 if (cfiLength == 0xffffffff) {
228 // 0xffffffff means length is really next 8 bytes
229 cfiLength = (pint_t)addressSpace.get64(p);
230 p += 8;
231 }
232 if (cfiLength == 0)
Ryan Prichard0cff8572020-09-16 01:22:55 -0700233 return false; // zero terminator
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000234 uint32_t id = addressSpace.get32(p);
235 if (id == 0) {
Ed Maste1b651132016-07-19 17:28:38 +0000236 // Skip over CIEs.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000237 p += cfiLength;
238 } else {
Ed Maste1b651132016-07-19 17:28:38 +0000239 // Process FDE to see if it covers pc.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000240 pint_t nextCFI = p + cfiLength;
241 uint32_t ciePointer = addressSpace.get32(p);
242 pint_t cieStart = p - ciePointer;
Ed Maste1b651132016-07-19 17:28:38 +0000243 // Validate pointer to CIE is within section.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000244 if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) {
245 if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) {
246 p += 4;
Ed Maste1b651132016-07-19 17:28:38 +0000247 // Parse pc begin and range.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000248 pint_t pcStart =
249 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
250 pint_t pcRange = addressSpace.getEncodedP(
251 p, nextCFI, cieInfo->pointerEncoding & 0x0F);
Ed Maste1b651132016-07-19 17:28:38 +0000252 // Test if pc is within the function this FDE covers.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000253 if ((pcStart < pc) && (pc <= pcStart + pcRange)) {
254 // parse rest of info
255 fdeInfo->lsda = 0;
256 // check for augmentation length
257 if (cieInfo->fdesHaveAugmentationData) {
258 pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
259 pint_t endOfAug = p + augLen;
260 if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
Ed Maste1b651132016-07-19 17:28:38 +0000261 // Peek at value (without indirection). Zero means no LSDA.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000262 pint_t lsdaStart = p;
263 if (addressSpace.getEncodedP(
264 p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) {
Ed Maste1b651132016-07-19 17:28:38 +0000265 // Reset pointer and re-parse LSDA address.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000266 p = lsdaStart;
267 fdeInfo->lsda = addressSpace
268 .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
269 }
270 }
271 p = endOfAug;
272 }
273 fdeInfo->fdeStart = currentCFI;
274 fdeInfo->fdeLength = nextCFI - currentCFI;
275 fdeInfo->fdeInstructions = p;
276 fdeInfo->pcStart = pcStart;
277 fdeInfo->pcEnd = pcStart + pcRange;
278 return true;
279 } else {
280 // pc is not in begin/range, skip this FDE
281 }
282 } else {
Ed Maste1b651132016-07-19 17:28:38 +0000283 // Malformed CIE, now augmentation describing pc range encoding.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000284 }
285 } else {
286 // malformed FDE. CIE is bad
287 }
288 p = nextCFI;
289 }
290 }
291 return false;
292}
293
294/// Extract info from a CIE
295template <typename A>
296const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
297 CIE_Info *cieInfo) {
298 cieInfo->pointerEncoding = 0;
299 cieInfo->lsdaEncoding = DW_EH_PE_omit;
300 cieInfo->personalityEncoding = 0;
301 cieInfo->personalityOffsetInCIE = 0;
302 cieInfo->personality = 0;
303 cieInfo->codeAlignFactor = 0;
304 cieInfo->dataAlignFactor = 0;
305 cieInfo->isSignalFrame = false;
306 cieInfo->fdesHaveAugmentationData = false;
Luke Cheesemancba83c32018-12-17 11:43:24 +0000307#if defined(_LIBUNWIND_TARGET_AARCH64)
308 cieInfo->addressesSignedWithBKey = false;
309#endif
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000310 cieInfo->cieStart = cie;
311 pint_t p = cie;
312 pint_t cieLength = (pint_t)addressSpace.get32(p);
313 p += 4;
314 pint_t cieContentEnd = p + cieLength;
315 if (cieLength == 0xffffffff) {
316 // 0xffffffff means length is really next 8 bytes
317 cieLength = (pint_t)addressSpace.get64(p);
318 p += 8;
319 cieContentEnd = p + cieLength;
320 }
321 if (cieLength == 0)
322 return NULL;
323 // CIE ID is always 0
324 if (addressSpace.get32(p) != 0)
325 return "CIE ID is not zero";
326 p += 4;
327 // Version is always 1 or 3
328 uint8_t version = addressSpace.get8(p);
329 if ((version != 1) && (version != 3))
330 return "CIE version is not 1 or 3";
331 ++p;
332 // save start of augmentation string and find end
333 pint_t strStart = p;
334 while (addressSpace.get8(p) != 0)
335 ++p;
336 ++p;
337 // parse code aligment factor
338 cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd);
339 // parse data alignment factor
340 cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd);
341 // parse return address register
Ryan Prichard58b19e62020-07-13 22:06:22 -0700342 uint64_t raReg = (version == 1) ? addressSpace.get8(p++)
343 : addressSpace.getULEB128(p, cieContentEnd);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000344 assert(raReg < 255 && "return address register too large");
345 cieInfo->returnAddressRegister = (uint8_t)raReg;
346 // parse augmentation data based on augmentation string
347 const char *result = NULL;
348 if (addressSpace.get8(strStart) == 'z') {
349 // parse augmentation data length
350 addressSpace.getULEB128(p, cieContentEnd);
351 for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) {
352 switch (addressSpace.get8(s)) {
353 case 'z':
354 cieInfo->fdesHaveAugmentationData = true;
355 break;
356 case 'P':
357 cieInfo->personalityEncoding = addressSpace.get8(p);
358 ++p;
359 cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie);
360 cieInfo->personality = addressSpace
361 .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
362 break;
363 case 'L':
364 cieInfo->lsdaEncoding = addressSpace.get8(p);
365 ++p;
366 break;
367 case 'R':
368 cieInfo->pointerEncoding = addressSpace.get8(p);
369 ++p;
370 break;
371 case 'S':
372 cieInfo->isSignalFrame = true;
373 break;
Luke Cheesemancba83c32018-12-17 11:43:24 +0000374#if defined(_LIBUNWIND_TARGET_AARCH64)
375 case 'B':
376 cieInfo->addressesSignedWithBKey = true;
377 break;
378#endif
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000379 default:
380 // ignore unknown letters
381 break;
382 }
383 }
384 }
385 cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
386 cieInfo->cieInstructions = p;
387 return result;
388}
389
390
Ed Maste4c43c3d2016-07-19 17:15:50 +0000391/// "run" the DWARF instructions and create the abstact PrologInfo for an FDE
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000392template <typename A>
393bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
394 const FDE_Info &fdeInfo,
395 const CIE_Info &cieInfo, pint_t upToPC,
Daniel Cederman9f2f07a2019-01-14 10:15:20 +0000396 int arch, PrologInfo *results) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000397 PrologInfoStackEntry *rememberStack = NULL;
398
399 // parse CIE then FDE instructions
Jorge Gorbe Moyafd8399e2020-02-18 11:48:02 -0800400 bool returnValue =
401 parseInstructions(addressSpace, cieInfo.cieInstructions,
402 cieInfo.cieStart + cieInfo.cieLength, cieInfo,
403 (pint_t)(-1), rememberStack, arch, results) &&
404 parseInstructions(addressSpace, fdeInfo.fdeInstructions,
405 fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo,
406 upToPC - fdeInfo.pcStart, rememberStack, arch, results);
407
Saleem Abdulrasool1ffb31a2020-05-15 14:43:19 -0700408#if !defined(_LIBUNWIND_NO_HEAP)
Jorge Gorbe Moyafd8399e2020-02-18 11:48:02 -0800409 // Clean up rememberStack. Even in the case where every DW_CFA_remember_state
410 // is paired with a DW_CFA_restore_state, parseInstructions can skip restore
411 // opcodes if it reaches the target PC and stops interpreting, so we have to
412 // make sure we don't leak memory.
413 while (rememberStack) {
414 PrologInfoStackEntry *next = rememberStack->next;
415 free(rememberStack);
416 rememberStack = next;
417 }
Saleem Abdulrasool1ffb31a2020-05-15 14:43:19 -0700418#endif
Jorge Gorbe Moyafd8399e2020-02-18 11:48:02 -0800419
420 return returnValue;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000421}
422
Ed Maste4c43c3d2016-07-19 17:15:50 +0000423/// "run" the DWARF instructions
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000424template <typename A>
425bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
426 pint_t instructionsEnd,
427 const CIE_Info &cieInfo, pint_t pcoffset,
428 PrologInfoStackEntry *&rememberStack,
Daniel Cederman9f2f07a2019-01-14 10:15:20 +0000429 int arch, PrologInfo *results) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000430 pint_t p = instructions;
431 pint_t codeOffset = 0;
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800432 // initialState initialized as registers in results are modified. Use
433 // PrologInfo accessor functions to avoid reading uninitialized data.
434 PrologInfo initialState(PrologInfo::InitializeTime::kLazy);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000435
436 _LIBUNWIND_TRACE_DWARF("parseInstructions(instructions=0x%0" PRIx64 ")\n",
437 static_cast<uint64_t>(instructionsEnd));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000438
Ed Maste4c43c3d2016-07-19 17:15:50 +0000439 // see DWARF Spec, section 6.4.2 for details on unwind opcodes
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000440 while ((p < instructionsEnd) && (codeOffset < pcoffset)) {
441 uint64_t reg;
442 uint64_t reg2;
443 int64_t offset;
444 uint64_t length;
445 uint8_t opcode = addressSpace.get8(p);
446 uint8_t operand;
Peter Zotov0717a2e2015-11-09 06:57:29 +0000447#if !defined(_LIBUNWIND_NO_HEAP)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000448 PrologInfoStackEntry *entry;
Peter Zotov0717a2e2015-11-09 06:57:29 +0000449#endif
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000450 ++p;
451 switch (opcode) {
452 case DW_CFA_nop:
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000453 _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000454 break;
455 case DW_CFA_set_loc:
456 codeOffset =
457 addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000458 _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000459 break;
460 case DW_CFA_advance_loc1:
461 codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
462 p += 1;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000463 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",
464 static_cast<uint64_t>(codeOffset));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000465 break;
466 case DW_CFA_advance_loc2:
467 codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
468 p += 2;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000469 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",
470 static_cast<uint64_t>(codeOffset));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000471 break;
472 case DW_CFA_advance_loc4:
473 codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
474 p += 4;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000475 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",
476 static_cast<uint64_t>(codeOffset));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000477 break;
478 case DW_CFA_offset_extended:
479 reg = addressSpace.getULEB128(p, instructionsEnd);
480 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
481 * cieInfo.dataAlignFactor;
482 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000483 _LIBUNWIND_LOG0(
484 "malformed DW_CFA_offset_extended DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000485 return false;
486 }
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800487 results->setRegister(reg, kRegisterInCFA, offset, initialState);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000488 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", "
489 "offset=%" PRId64 ")\n",
490 reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000491 break;
492 case DW_CFA_restore_extended:
493 reg = addressSpace.getULEB128(p, instructionsEnd);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000494 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000495 _LIBUNWIND_LOG0(
496 "malformed DW_CFA_restore_extended DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000497 return false;
498 }
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800499 results->restoreRegisterToInitialState(reg, initialState);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000500 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000501 break;
502 case DW_CFA_undefined:
503 reg = addressSpace.getULEB128(p, instructionsEnd);
504 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000505 _LIBUNWIND_LOG0(
506 "malformed DW_CFA_undefined DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000507 return false;
508 }
Daniel Kissd6c1e482020-09-16 23:03:19 +0200509 results->setRegisterLocation(reg, kRegisterUndefined, initialState);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000510 _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000511 break;
512 case DW_CFA_same_value:
513 reg = addressSpace.getULEB128(p, instructionsEnd);
514 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000515 _LIBUNWIND_LOG0(
516 "malformed DW_CFA_same_value DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000517 return false;
518 }
519 // <rdar://problem/8456377> DW_CFA_same_value unsupported
520 // "same value" means register was stored in frame, but its current
521 // value has not changed, so no need to restore from frame.
522 // We model this as if the register was never saved.
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800523 results->setRegisterLocation(reg, kRegisterUnused, initialState);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000524 // set flag to disable conversion to compact unwind
525 results->sameValueUsed = true;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000526 _LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000527 break;
528 case DW_CFA_register:
529 reg = addressSpace.getULEB128(p, instructionsEnd);
530 reg2 = addressSpace.getULEB128(p, instructionsEnd);
531 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000532 _LIBUNWIND_LOG0(
533 "malformed DW_CFA_register DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000534 return false;
535 }
536 if (reg2 > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000537 _LIBUNWIND_LOG0(
538 "malformed DW_CFA_register DWARF unwind, reg2 too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000539 return false;
540 }
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800541 results->setRegister(reg, kRegisterInRegister, (int64_t)reg2,
542 initialState);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000543 // set flag to disable conversion to compact unwind
544 results->registersInOtherRegisters = true;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000545 _LIBUNWIND_TRACE_DWARF(
546 "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000547 break;
Peter Zotov0717a2e2015-11-09 06:57:29 +0000548#if !defined(_LIBUNWIND_NO_HEAP)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000549 case DW_CFA_remember_state:
550 // avoid operator new, because that would be an upward dependency
551 entry = (PrologInfoStackEntry *)malloc(sizeof(PrologInfoStackEntry));
552 if (entry != NULL) {
553 entry->next = rememberStack;
554 entry->info = *results;
555 rememberStack = entry;
556 } else {
557 return false;
558 }
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000559 _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000560 break;
561 case DW_CFA_restore_state:
562 if (rememberStack != NULL) {
563 PrologInfoStackEntry *top = rememberStack;
564 *results = top->info;
565 rememberStack = top->next;
566 free((char *)top);
567 } else {
568 return false;
569 }
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000570 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000571 break;
Peter Zotov0717a2e2015-11-09 06:57:29 +0000572#endif
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000573 case DW_CFA_def_cfa:
574 reg = addressSpace.getULEB128(p, instructionsEnd);
575 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);
576 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000577 _LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000578 return false;
579 }
580 results->cfaRegister = (uint32_t)reg;
581 results->cfaRegisterOffset = (int32_t)offset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000582 _LIBUNWIND_TRACE_DWARF(
583 "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n", reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000584 break;
585 case DW_CFA_def_cfa_register:
586 reg = addressSpace.getULEB128(p, instructionsEnd);
587 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000588 _LIBUNWIND_LOG0(
589 "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000590 return false;
591 }
592 results->cfaRegister = (uint32_t)reg;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000593 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000594 break;
595 case DW_CFA_def_cfa_offset:
596 results->cfaRegisterOffset = (int32_t)
597 addressSpace.getULEB128(p, instructionsEnd);
598 results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000599 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n",
600 results->cfaRegisterOffset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000601 break;
602 case DW_CFA_def_cfa_expression:
603 results->cfaRegister = 0;
604 results->cfaExpression = (int64_t)p;
605 length = addressSpace.getULEB128(p, instructionsEnd);
whitequark443f65c2017-12-25 21:08:41 +0000606 assert(length < static_cast<pint_t>(~0) && "pointer overflow");
Saleem Abdulrasool92acbf12017-03-08 16:03:27 +0000607 p += static_cast<pint_t>(length);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000608 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64
609 ", length=%" PRIu64 ")\n",
610 results->cfaExpression, length);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000611 break;
612 case DW_CFA_expression:
613 reg = addressSpace.getULEB128(p, instructionsEnd);
614 if (reg > kMaxRegisterNumber) {
whitequarka3b115c2017-12-25 13:42:41 +0000615 _LIBUNWIND_LOG0(
whitequarkb718c5f2017-12-25 13:27:56 +0000616 "malformed DW_CFA_expression DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000617 return false;
618 }
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800619 results->setRegister(reg, kRegisterAtExpression, (int64_t)p,
620 initialState);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000621 length = addressSpace.getULEB128(p, instructionsEnd);
whitequark443f65c2017-12-25 21:08:41 +0000622 assert(length < static_cast<pint_t>(~0) && "pointer overflow");
Saleem Abdulrasool92acbf12017-03-08 16:03:27 +0000623 p += static_cast<pint_t>(length);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000624 _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", "
625 "expression=0x%" PRIx64 ", "
626 "length=%" PRIu64 ")\n",
627 reg, results->savedRegisters[reg].value, length);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000628 break;
629 case DW_CFA_offset_extended_sf:
630 reg = addressSpace.getULEB128(p, instructionsEnd);
631 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000632 _LIBUNWIND_LOG0(
633 "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000634 return false;
635 }
636 offset =
637 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800638 results->setRegister(reg, kRegisterInCFA, offset, initialState);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000639 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", "
640 "offset=%" PRId64 ")\n",
641 reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000642 break;
643 case DW_CFA_def_cfa_sf:
644 reg = addressSpace.getULEB128(p, instructionsEnd);
645 offset =
646 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
647 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000648 _LIBUNWIND_LOG0(
649 "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000650 return false;
651 }
652 results->cfaRegister = (uint32_t)reg;
653 results->cfaRegisterOffset = (int32_t)offset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000654 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", "
655 "offset=%" PRId64 ")\n",
656 reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000657 break;
658 case DW_CFA_def_cfa_offset_sf:
659 results->cfaRegisterOffset = (int32_t)
660 (addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor);
661 results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000662 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n",
663 results->cfaRegisterOffset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000664 break;
665 case DW_CFA_val_offset:
666 reg = addressSpace.getULEB128(p, instructionsEnd);
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000667 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000668 _LIBUNWIND_LOG(
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000669 "malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64
670 ") out of range\n",
671 reg);
672 return false;
673 }
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000674 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
675 * cieInfo.dataAlignFactor;
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800676 results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000677 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", "
678 "offset=%" PRId64 "\n",
679 reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000680 break;
681 case DW_CFA_val_offset_sf:
682 reg = addressSpace.getULEB128(p, instructionsEnd);
683 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000684 _LIBUNWIND_LOG0(
685 "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000686 return false;
687 }
688 offset =
689 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800690 results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000691 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", "
692 "offset=%" PRId64 "\n",
693 reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000694 break;
695 case DW_CFA_val_expression:
696 reg = addressSpace.getULEB128(p, instructionsEnd);
697 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000698 _LIBUNWIND_LOG0(
699 "malformed DW_CFA_val_expression DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000700 return false;
701 }
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800702 results->setRegister(reg, kRegisterIsExpression, (int64_t)p,
703 initialState);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000704 length = addressSpace.getULEB128(p, instructionsEnd);
whitequark443f65c2017-12-25 21:08:41 +0000705 assert(length < static_cast<pint_t>(~0) && "pointer overflow");
Saleem Abdulrasool92acbf12017-03-08 16:03:27 +0000706 p += static_cast<pint_t>(length);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000707 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", "
708 "expression=0x%" PRIx64 ", length=%" PRIu64 ")\n",
709 reg, results->savedRegisters[reg].value, length);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000710 break;
711 case DW_CFA_GNU_args_size:
712 length = addressSpace.getULEB128(p, instructionsEnd);
713 results->spExtraArgSize = (uint32_t)length;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000714 _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000715 break;
716 case DW_CFA_GNU_negative_offset_extended:
717 reg = addressSpace.getULEB128(p, instructionsEnd);
718 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000719 _LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF "
720 "unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000721 return false;
722 }
723 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
724 * cieInfo.dataAlignFactor;
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800725 results->setRegister(reg, kRegisterInCFA, -offset, initialState);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000726 _LIBUNWIND_TRACE_DWARF(
727 "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000728 break;
Luke Cheeseman4d8e4312018-12-14 11:30:12 +0000729
Daniel Cederman9f2f07a2019-01-14 10:15:20 +0000730#if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC)
731 // The same constant is used to represent different instructions on
732 // AArch64 (negate_ra_state) and SPARC (window_save).
733 static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save,
734 "uses the same constant");
Luke Cheeseman4d8e4312018-12-14 11:30:12 +0000735 case DW_CFA_AARCH64_negate_ra_state:
Daniel Cederman9f2f07a2019-01-14 10:15:20 +0000736 switch (arch) {
737#if defined(_LIBUNWIND_TARGET_AARCH64)
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800738 case REGISTERS_ARM64: {
739 int64_t value =
740 results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^ 0x1;
741 results->setRegisterValue(UNW_ARM64_RA_SIGN_STATE, value, initialState);
742 _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n");
743 } break;
Daniel Cederman9f2f07a2019-01-14 10:15:20 +0000744#endif
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800745
Daniel Cederman9f2f07a2019-01-14 10:15:20 +0000746#if defined(_LIBUNWIND_TARGET_SPARC)
747 // case DW_CFA_GNU_window_save:
748 case REGISTERS_SPARC:
749 _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n");
750 for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) {
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800751 results->setRegister(reg, kRegisterInRegister,
752 ((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0,
753 initialState);
Daniel Cederman9f2f07a2019-01-14 10:15:20 +0000754 }
755
756 for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800757 results->setRegister(reg, kRegisterInCFA,
758 ((int64_t)reg - UNW_SPARC_L0) * 4, initialState);
Daniel Cederman9f2f07a2019-01-14 10:15:20 +0000759 }
760 break;
761#endif
762 }
Luke Cheeseman4d8e4312018-12-14 11:30:12 +0000763 break;
Daniel Cederman9f2f07a2019-01-14 10:15:20 +0000764#else
765 (void)arch;
Luke Cheeseman4d8e4312018-12-14 11:30:12 +0000766#endif
767
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000768 default:
769 operand = opcode & 0x3F;
770 switch (opcode & 0xC0) {
771 case DW_CFA_offset:
772 reg = operand;
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000773 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000774 _LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64
775 ") out of range",
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000776 reg);
777 return false;
778 }
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000779 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
780 * cieInfo.dataAlignFactor;
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800781 results->setRegister(reg, kRegisterInCFA, offset, initialState);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000782 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
783 operand, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000784 break;
785 case DW_CFA_advance_loc:
786 codeOffset += operand * cieInfo.codeAlignFactor;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000787 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
788 static_cast<uint64_t>(codeOffset));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000789 break;
790 case DW_CFA_restore:
791 reg = operand;
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000792 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000793 _LIBUNWIND_LOG("malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64
794 ") out of range",
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000795 reg);
796 return false;
797 }
Sterling Augustinec0ef0db2020-03-04 16:29:58 -0800798 results->restoreRegisterToInitialState(reg, initialState);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000799 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",
Saleem Abdulrasoolc73a3c32017-01-21 21:27:29 +0000800 static_cast<uint64_t>(operand));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000801 break;
802 default:
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000803 _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000804 return false;
805 }
806 }
807 }
808
809 return true;
810}
811
812} // namespace libunwind
813
814#endif // __DWARF_PARSER_HPP__