blob: 68506a35053c9d708fc141b31caadfef6685b1ec [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;
52 };
53
54 /// Information about an FDE (Frame Description Entry)
55 struct FDE_Info {
56 pint_t fdeStart;
57 pint_t fdeLength;
58 pint_t fdeInstructions;
59 pint_t pcStart;
60 pint_t pcEnd;
61 pint_t lsda;
62 };
63
64 enum {
Ed Maste567984c2016-07-20 15:19:09 +000065 kMaxRegisterNumber = _LIBUNWIND_HIGHEST_DWARF_REGISTER
Saleem Abdulrasool17552662015-04-24 19:39:17 +000066 };
67 enum RegisterSavedWhere {
68 kRegisterUnused,
69 kRegisterInCFA,
70 kRegisterOffsetFromCFA,
71 kRegisterInRegister,
72 kRegisterAtExpression,
73 kRegisterIsExpression
74 };
75 struct RegisterLocation {
76 RegisterSavedWhere location;
77 int64_t value;
78 };
79 /// Information about a frame layout and registers saved determined
Ed Maste4c43c3d2016-07-19 17:15:50 +000080 /// by "running" the DWARF FDE "instructions"
Saleem Abdulrasool17552662015-04-24 19:39:17 +000081 struct PrologInfo {
82 uint32_t cfaRegister;
83 int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
84 int64_t cfaExpression; // CFA = expression
85 uint32_t spExtraArgSize;
86 uint32_t codeOffsetAtStackDecrement;
87 bool registersInOtherRegisters;
88 bool sameValueUsed;
Martin Storsjof10f3c92017-10-27 07:59:01 +000089 RegisterLocation savedRegisters[kMaxRegisterNumber + 1];
Saleem Abdulrasool17552662015-04-24 19:39:17 +000090 };
91
92 struct PrologInfoStackEntry {
93 PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i)
94 : next(n), info(i) {}
95 PrologInfoStackEntry *next;
96 PrologInfo info;
97 };
98
99 static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
100 uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
101 CIE_Info *cieInfo);
102 static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
103 FDE_Info *fdeInfo, CIE_Info *cieInfo);
104 static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,
105 const CIE_Info &cieInfo, pint_t upToPC,
106 PrologInfo *results);
107
108 static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
109
110private:
111 static bool parseInstructions(A &addressSpace, pint_t instructions,
112 pint_t instructionsEnd, const CIE_Info &cieInfo,
113 pint_t pcoffset,
114 PrologInfoStackEntry *&rememberStack,
115 PrologInfo *results);
116};
117
118/// Parse a FDE into a CIE_Info and an FDE_Info
119template <typename A>
120const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
121 FDE_Info *fdeInfo, CIE_Info *cieInfo) {
122 pint_t p = fdeStart;
123 pint_t cfiLength = (pint_t)addressSpace.get32(p);
124 p += 4;
125 if (cfiLength == 0xffffffff) {
126 // 0xffffffff means length is really next 8 bytes
127 cfiLength = (pint_t)addressSpace.get64(p);
128 p += 8;
129 }
130 if (cfiLength == 0)
131 return "FDE has zero length"; // end marker
132 uint32_t ciePointer = addressSpace.get32(p);
133 if (ciePointer == 0)
134 return "FDE is really a CIE"; // this is a CIE not an FDE
135 pint_t nextCFI = p + cfiLength;
136 pint_t cieStart = p - ciePointer;
137 const char *err = parseCIE(addressSpace, cieStart, cieInfo);
138 if (err != NULL)
139 return err;
140 p += 4;
Ed Maste1b651132016-07-19 17:28:38 +0000141 // Parse pc begin and range.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000142 pint_t pcStart =
143 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
144 pint_t pcRange =
145 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
Ed Maste1b651132016-07-19 17:28:38 +0000146 // Parse rest of info.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000147 fdeInfo->lsda = 0;
Ed Maste1b651132016-07-19 17:28:38 +0000148 // Check for augmentation length.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000149 if (cieInfo->fdesHaveAugmentationData) {
150 pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
151 pint_t endOfAug = p + augLen;
152 if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
Ed Maste1b651132016-07-19 17:28:38 +0000153 // Peek at value (without indirection). Zero means no LSDA.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000154 pint_t lsdaStart = p;
155 if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) !=
156 0) {
Ed Maste1b651132016-07-19 17:28:38 +0000157 // Reset pointer and re-parse LSDA address.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000158 p = lsdaStart;
159 fdeInfo->lsda =
160 addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
161 }
162 }
163 p = endOfAug;
164 }
165 fdeInfo->fdeStart = fdeStart;
166 fdeInfo->fdeLength = nextCFI - fdeStart;
167 fdeInfo->fdeInstructions = p;
168 fdeInfo->pcStart = pcStart;
169 fdeInfo->pcEnd = pcStart + pcRange;
170 return NULL; // success
171}
172
173/// Scan an eh_frame section to find an FDE for a pc
174template <typename A>
175bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
176 uint32_t sectionLength, pint_t fdeHint,
177 FDE_Info *fdeInfo, CIE_Info *cieInfo) {
178 //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
179 pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
180 const pint_t ehSectionEnd = p + sectionLength;
181 while (p < ehSectionEnd) {
182 pint_t currentCFI = p;
183 //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
184 pint_t cfiLength = addressSpace.get32(p);
185 p += 4;
186 if (cfiLength == 0xffffffff) {
187 // 0xffffffff means length is really next 8 bytes
188 cfiLength = (pint_t)addressSpace.get64(p);
189 p += 8;
190 }
191 if (cfiLength == 0)
192 return false; // end marker
193 uint32_t id = addressSpace.get32(p);
194 if (id == 0) {
Ed Maste1b651132016-07-19 17:28:38 +0000195 // Skip over CIEs.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000196 p += cfiLength;
197 } else {
Ed Maste1b651132016-07-19 17:28:38 +0000198 // Process FDE to see if it covers pc.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000199 pint_t nextCFI = p + cfiLength;
200 uint32_t ciePointer = addressSpace.get32(p);
201 pint_t cieStart = p - ciePointer;
Ed Maste1b651132016-07-19 17:28:38 +0000202 // Validate pointer to CIE is within section.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000203 if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) {
204 if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) {
205 p += 4;
Ed Maste1b651132016-07-19 17:28:38 +0000206 // Parse pc begin and range.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000207 pint_t pcStart =
208 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
209 pint_t pcRange = addressSpace.getEncodedP(
210 p, nextCFI, cieInfo->pointerEncoding & 0x0F);
Ed Maste1b651132016-07-19 17:28:38 +0000211 // Test if pc is within the function this FDE covers.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000212 if ((pcStart < pc) && (pc <= pcStart + pcRange)) {
213 // parse rest of info
214 fdeInfo->lsda = 0;
215 // check for augmentation length
216 if (cieInfo->fdesHaveAugmentationData) {
217 pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
218 pint_t endOfAug = p + augLen;
219 if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
Ed Maste1b651132016-07-19 17:28:38 +0000220 // Peek at value (without indirection). Zero means no LSDA.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000221 pint_t lsdaStart = p;
222 if (addressSpace.getEncodedP(
223 p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) {
Ed Maste1b651132016-07-19 17:28:38 +0000224 // Reset pointer and re-parse LSDA address.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000225 p = lsdaStart;
226 fdeInfo->lsda = addressSpace
227 .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
228 }
229 }
230 p = endOfAug;
231 }
232 fdeInfo->fdeStart = currentCFI;
233 fdeInfo->fdeLength = nextCFI - currentCFI;
234 fdeInfo->fdeInstructions = p;
235 fdeInfo->pcStart = pcStart;
236 fdeInfo->pcEnd = pcStart + pcRange;
237 return true;
238 } else {
239 // pc is not in begin/range, skip this FDE
240 }
241 } else {
Ed Maste1b651132016-07-19 17:28:38 +0000242 // Malformed CIE, now augmentation describing pc range encoding.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000243 }
244 } else {
245 // malformed FDE. CIE is bad
246 }
247 p = nextCFI;
248 }
249 }
250 return false;
251}
252
253/// Extract info from a CIE
254template <typename A>
255const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
256 CIE_Info *cieInfo) {
257 cieInfo->pointerEncoding = 0;
258 cieInfo->lsdaEncoding = DW_EH_PE_omit;
259 cieInfo->personalityEncoding = 0;
260 cieInfo->personalityOffsetInCIE = 0;
261 cieInfo->personality = 0;
262 cieInfo->codeAlignFactor = 0;
263 cieInfo->dataAlignFactor = 0;
264 cieInfo->isSignalFrame = false;
265 cieInfo->fdesHaveAugmentationData = false;
266 cieInfo->cieStart = cie;
267 pint_t p = cie;
268 pint_t cieLength = (pint_t)addressSpace.get32(p);
269 p += 4;
270 pint_t cieContentEnd = p + cieLength;
271 if (cieLength == 0xffffffff) {
272 // 0xffffffff means length is really next 8 bytes
273 cieLength = (pint_t)addressSpace.get64(p);
274 p += 8;
275 cieContentEnd = p + cieLength;
276 }
277 if (cieLength == 0)
278 return NULL;
279 // CIE ID is always 0
280 if (addressSpace.get32(p) != 0)
281 return "CIE ID is not zero";
282 p += 4;
283 // Version is always 1 or 3
284 uint8_t version = addressSpace.get8(p);
285 if ((version != 1) && (version != 3))
286 return "CIE version is not 1 or 3";
287 ++p;
288 // save start of augmentation string and find end
289 pint_t strStart = p;
290 while (addressSpace.get8(p) != 0)
291 ++p;
292 ++p;
293 // parse code aligment factor
294 cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd);
295 // parse data alignment factor
296 cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd);
297 // parse return address register
298 uint64_t raReg = addressSpace.getULEB128(p, cieContentEnd);
299 assert(raReg < 255 && "return address register too large");
300 cieInfo->returnAddressRegister = (uint8_t)raReg;
301 // parse augmentation data based on augmentation string
302 const char *result = NULL;
303 if (addressSpace.get8(strStart) == 'z') {
304 // parse augmentation data length
305 addressSpace.getULEB128(p, cieContentEnd);
306 for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) {
307 switch (addressSpace.get8(s)) {
308 case 'z':
309 cieInfo->fdesHaveAugmentationData = true;
310 break;
311 case 'P':
312 cieInfo->personalityEncoding = addressSpace.get8(p);
313 ++p;
314 cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie);
315 cieInfo->personality = addressSpace
316 .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
317 break;
318 case 'L':
319 cieInfo->lsdaEncoding = addressSpace.get8(p);
320 ++p;
321 break;
322 case 'R':
323 cieInfo->pointerEncoding = addressSpace.get8(p);
324 ++p;
325 break;
326 case 'S':
327 cieInfo->isSignalFrame = true;
328 break;
329 default:
330 // ignore unknown letters
331 break;
332 }
333 }
334 }
335 cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
336 cieInfo->cieInstructions = p;
337 return result;
338}
339
340
Ed Maste4c43c3d2016-07-19 17:15:50 +0000341/// "run" the DWARF instructions and create the abstact PrologInfo for an FDE
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000342template <typename A>
343bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
344 const FDE_Info &fdeInfo,
345 const CIE_Info &cieInfo, pint_t upToPC,
346 PrologInfo *results) {
347 // clear results
348 memset(results, '\0', sizeof(PrologInfo));
349 PrologInfoStackEntry *rememberStack = NULL;
350
351 // parse CIE then FDE instructions
352 return parseInstructions(addressSpace, cieInfo.cieInstructions,
353 cieInfo.cieStart + cieInfo.cieLength, cieInfo,
354 (pint_t)(-1), rememberStack, results) &&
355 parseInstructions(addressSpace, fdeInfo.fdeInstructions,
356 fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo,
357 upToPC - fdeInfo.pcStart, rememberStack, results);
358}
359
Ed Maste4c43c3d2016-07-19 17:15:50 +0000360/// "run" the DWARF instructions
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000361template <typename A>
362bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
363 pint_t instructionsEnd,
364 const CIE_Info &cieInfo, pint_t pcoffset,
365 PrologInfoStackEntry *&rememberStack,
366 PrologInfo *results) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000367 pint_t p = instructions;
368 pint_t codeOffset = 0;
369 PrologInfo initialState = *results;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000370
371 _LIBUNWIND_TRACE_DWARF("parseInstructions(instructions=0x%0" PRIx64 ")\n",
372 static_cast<uint64_t>(instructionsEnd));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000373
Ed Maste4c43c3d2016-07-19 17:15:50 +0000374 // see DWARF Spec, section 6.4.2 for details on unwind opcodes
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000375 while ((p < instructionsEnd) && (codeOffset < pcoffset)) {
376 uint64_t reg;
377 uint64_t reg2;
378 int64_t offset;
379 uint64_t length;
380 uint8_t opcode = addressSpace.get8(p);
381 uint8_t operand;
Peter Zotov0717a2e2015-11-09 06:57:29 +0000382#if !defined(_LIBUNWIND_NO_HEAP)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000383 PrologInfoStackEntry *entry;
Peter Zotov0717a2e2015-11-09 06:57:29 +0000384#endif
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000385 ++p;
386 switch (opcode) {
387 case DW_CFA_nop:
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000388 _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000389 break;
390 case DW_CFA_set_loc:
391 codeOffset =
392 addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000393 _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000394 break;
395 case DW_CFA_advance_loc1:
396 codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
397 p += 1;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000398 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",
399 static_cast<uint64_t>(codeOffset));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000400 break;
401 case DW_CFA_advance_loc2:
402 codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
403 p += 2;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000404 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",
405 static_cast<uint64_t>(codeOffset));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000406 break;
407 case DW_CFA_advance_loc4:
408 codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
409 p += 4;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000410 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",
411 static_cast<uint64_t>(codeOffset));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000412 break;
413 case DW_CFA_offset_extended:
414 reg = addressSpace.getULEB128(p, instructionsEnd);
415 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
416 * cieInfo.dataAlignFactor;
417 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000418 _LIBUNWIND_LOG0(
419 "malformed DW_CFA_offset_extended DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000420 return false;
421 }
422 results->savedRegisters[reg].location = kRegisterInCFA;
423 results->savedRegisters[reg].value = offset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000424 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", "
425 "offset=%" PRId64 ")\n",
426 reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000427 break;
428 case DW_CFA_restore_extended:
429 reg = addressSpace.getULEB128(p, instructionsEnd);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000430 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000431 _LIBUNWIND_LOG0(
432 "malformed DW_CFA_restore_extended DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000433 return false;
434 }
435 results->savedRegisters[reg] = initialState.savedRegisters[reg];
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000436 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000437 break;
438 case DW_CFA_undefined:
439 reg = addressSpace.getULEB128(p, instructionsEnd);
440 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000441 _LIBUNWIND_LOG0(
442 "malformed DW_CFA_undefined DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000443 return false;
444 }
445 results->savedRegisters[reg].location = kRegisterUnused;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000446 _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000447 break;
448 case DW_CFA_same_value:
449 reg = addressSpace.getULEB128(p, instructionsEnd);
450 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000451 _LIBUNWIND_LOG0(
452 "malformed DW_CFA_same_value DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000453 return false;
454 }
455 // <rdar://problem/8456377> DW_CFA_same_value unsupported
456 // "same value" means register was stored in frame, but its current
457 // value has not changed, so no need to restore from frame.
458 // We model this as if the register was never saved.
459 results->savedRegisters[reg].location = kRegisterUnused;
460 // set flag to disable conversion to compact unwind
461 results->sameValueUsed = true;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000462 _LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000463 break;
464 case DW_CFA_register:
465 reg = addressSpace.getULEB128(p, instructionsEnd);
466 reg2 = addressSpace.getULEB128(p, instructionsEnd);
467 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000468 _LIBUNWIND_LOG0(
469 "malformed DW_CFA_register DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000470 return false;
471 }
472 if (reg2 > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000473 _LIBUNWIND_LOG0(
474 "malformed DW_CFA_register DWARF unwind, reg2 too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000475 return false;
476 }
477 results->savedRegisters[reg].location = kRegisterInRegister;
478 results->savedRegisters[reg].value = (int64_t)reg2;
479 // set flag to disable conversion to compact unwind
480 results->registersInOtherRegisters = true;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000481 _LIBUNWIND_TRACE_DWARF(
482 "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000483 break;
Peter Zotov0717a2e2015-11-09 06:57:29 +0000484#if !defined(_LIBUNWIND_NO_HEAP)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000485 case DW_CFA_remember_state:
486 // avoid operator new, because that would be an upward dependency
487 entry = (PrologInfoStackEntry *)malloc(sizeof(PrologInfoStackEntry));
488 if (entry != NULL) {
489 entry->next = rememberStack;
490 entry->info = *results;
491 rememberStack = entry;
492 } else {
493 return false;
494 }
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000495 _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000496 break;
497 case DW_CFA_restore_state:
498 if (rememberStack != NULL) {
499 PrologInfoStackEntry *top = rememberStack;
500 *results = top->info;
501 rememberStack = top->next;
502 free((char *)top);
503 } else {
504 return false;
505 }
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000506 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000507 break;
Peter Zotov0717a2e2015-11-09 06:57:29 +0000508#endif
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000509 case DW_CFA_def_cfa:
510 reg = addressSpace.getULEB128(p, instructionsEnd);
511 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);
512 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000513 _LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000514 return false;
515 }
516 results->cfaRegister = (uint32_t)reg;
517 results->cfaRegisterOffset = (int32_t)offset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000518 _LIBUNWIND_TRACE_DWARF(
519 "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n", reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000520 break;
521 case DW_CFA_def_cfa_register:
522 reg = addressSpace.getULEB128(p, instructionsEnd);
523 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000524 _LIBUNWIND_LOG0(
525 "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000526 return false;
527 }
528 results->cfaRegister = (uint32_t)reg;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000529 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000530 break;
531 case DW_CFA_def_cfa_offset:
532 results->cfaRegisterOffset = (int32_t)
533 addressSpace.getULEB128(p, instructionsEnd);
534 results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000535 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n",
536 results->cfaRegisterOffset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000537 break;
538 case DW_CFA_def_cfa_expression:
539 results->cfaRegister = 0;
540 results->cfaExpression = (int64_t)p;
541 length = addressSpace.getULEB128(p, instructionsEnd);
whitequark443f65c2017-12-25 21:08:41 +0000542 assert(length < static_cast<pint_t>(~0) && "pointer overflow");
Saleem Abdulrasool92acbf12017-03-08 16:03:27 +0000543 p += static_cast<pint_t>(length);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000544 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64
545 ", length=%" PRIu64 ")\n",
546 results->cfaExpression, length);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000547 break;
548 case DW_CFA_expression:
549 reg = addressSpace.getULEB128(p, instructionsEnd);
550 if (reg > kMaxRegisterNumber) {
whitequarka3b115c2017-12-25 13:42:41 +0000551 _LIBUNWIND_LOG0(
whitequarkb718c5f2017-12-25 13:27:56 +0000552 "malformed DW_CFA_expression DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000553 return false;
554 }
555 results->savedRegisters[reg].location = kRegisterAtExpression;
556 results->savedRegisters[reg].value = (int64_t)p;
557 length = addressSpace.getULEB128(p, instructionsEnd);
whitequark443f65c2017-12-25 21:08:41 +0000558 assert(length < static_cast<pint_t>(~0) && "pointer overflow");
Saleem Abdulrasool92acbf12017-03-08 16:03:27 +0000559 p += static_cast<pint_t>(length);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000560 _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", "
561 "expression=0x%" PRIx64 ", "
562 "length=%" PRIu64 ")\n",
563 reg, results->savedRegisters[reg].value, length);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000564 break;
565 case DW_CFA_offset_extended_sf:
566 reg = addressSpace.getULEB128(p, instructionsEnd);
567 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000568 _LIBUNWIND_LOG0(
569 "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000570 return false;
571 }
572 offset =
573 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
574 results->savedRegisters[reg].location = kRegisterInCFA;
575 results->savedRegisters[reg].value = offset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000576 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", "
577 "offset=%" PRId64 ")\n",
578 reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000579 break;
580 case DW_CFA_def_cfa_sf:
581 reg = addressSpace.getULEB128(p, instructionsEnd);
582 offset =
583 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
584 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000585 _LIBUNWIND_LOG0(
586 "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000587 return false;
588 }
589 results->cfaRegister = (uint32_t)reg;
590 results->cfaRegisterOffset = (int32_t)offset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000591 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", "
592 "offset=%" PRId64 ")\n",
593 reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000594 break;
595 case DW_CFA_def_cfa_offset_sf:
596 results->cfaRegisterOffset = (int32_t)
597 (addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor);
598 results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000599 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n",
600 results->cfaRegisterOffset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000601 break;
602 case DW_CFA_val_offset:
603 reg = addressSpace.getULEB128(p, instructionsEnd);
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000604 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000605 _LIBUNWIND_LOG(
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000606 "malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64
607 ") out of range\n",
608 reg);
609 return false;
610 }
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000611 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
612 * cieInfo.dataAlignFactor;
613 results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
614 results->savedRegisters[reg].value = offset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000615 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", "
616 "offset=%" PRId64 "\n",
617 reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000618 break;
619 case DW_CFA_val_offset_sf:
620 reg = addressSpace.getULEB128(p, instructionsEnd);
621 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000622 _LIBUNWIND_LOG0(
623 "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000624 return false;
625 }
626 offset =
627 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
628 results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
629 results->savedRegisters[reg].value = offset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000630 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", "
631 "offset=%" PRId64 "\n",
632 reg, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000633 break;
634 case DW_CFA_val_expression:
635 reg = addressSpace.getULEB128(p, instructionsEnd);
636 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000637 _LIBUNWIND_LOG0(
638 "malformed DW_CFA_val_expression DWARF unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000639 return false;
640 }
641 results->savedRegisters[reg].location = kRegisterIsExpression;
642 results->savedRegisters[reg].value = (int64_t)p;
643 length = addressSpace.getULEB128(p, instructionsEnd);
whitequark443f65c2017-12-25 21:08:41 +0000644 assert(length < static_cast<pint_t>(~0) && "pointer overflow");
Saleem Abdulrasool92acbf12017-03-08 16:03:27 +0000645 p += static_cast<pint_t>(length);
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000646 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", "
647 "expression=0x%" PRIx64 ", length=%" PRIu64 ")\n",
648 reg, results->savedRegisters[reg].value, length);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000649 break;
650 case DW_CFA_GNU_args_size:
651 length = addressSpace.getULEB128(p, instructionsEnd);
652 results->spExtraArgSize = (uint32_t)length;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000653 _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000654 break;
655 case DW_CFA_GNU_negative_offset_extended:
656 reg = addressSpace.getULEB128(p, instructionsEnd);
657 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000658 _LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF "
659 "unwind, reg too big");
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000660 return false;
661 }
662 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
663 * cieInfo.dataAlignFactor;
664 results->savedRegisters[reg].location = kRegisterInCFA;
665 results->savedRegisters[reg].value = -offset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000666 _LIBUNWIND_TRACE_DWARF(
667 "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000668 break;
Luke Cheeseman4d8e4312018-12-14 11:30:12 +0000669
670#if defined(_LIBUNWIND_TARGET_AARCH64)
671 case DW_CFA_AARCH64_negate_ra_state:
672 results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^= 0x1;
673 _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n");
674 break;
675#endif
676
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000677 default:
678 operand = opcode & 0x3F;
679 switch (opcode & 0xC0) {
680 case DW_CFA_offset:
681 reg = operand;
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000682 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000683 _LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64
684 ") out of range",
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000685 reg);
686 return false;
687 }
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000688 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
689 * cieInfo.dataAlignFactor;
690 results->savedRegisters[reg].location = kRegisterInCFA;
691 results->savedRegisters[reg].value = offset;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000692 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
693 operand, offset);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000694 break;
695 case DW_CFA_advance_loc:
696 codeOffset += operand * cieInfo.codeAlignFactor;
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000697 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
698 static_cast<uint64_t>(codeOffset));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000699 break;
700 case DW_CFA_restore:
701 reg = operand;
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000702 if (reg > kMaxRegisterNumber) {
whitequarkb718c5f2017-12-25 13:27:56 +0000703 _LIBUNWIND_LOG("malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64
704 ") out of range",
Martin Storsjo6ae660a2017-10-24 07:16:40 +0000705 reg);
706 return false;
707 }
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000708 results->savedRegisters[reg] = initialState.savedRegisters[reg];
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000709 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",
Saleem Abdulrasoolc73a3c32017-01-21 21:27:29 +0000710 static_cast<uint64_t>(operand));
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000711 break;
712 default:
Saleem Abdulrasoold1be5b02017-01-21 16:22:57 +0000713 _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000714 return false;
715 }
716 }
717 }
718
719 return true;
720}
721
722} // namespace libunwind
723
724#endif // __DWARF_PARSER_HPP__