blob: 9a755556de68aa12d829192f60c6645a7a38b138 [file] [log] [blame]
Saleem Abdulrasool675df582015-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 Abdulrasool675df582015-04-24 19:39:17 +000021#include "libunwind.h"
22#include "dwarf2.h"
23
24#include "AddressSpace.hpp"
25
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +000026extern "C" bool logDWARF();
27
28#define _LIBUNWIND_TRACE_DWARF(...) \
29 do { \
30 if (logDWARF()) \
31 fprintf(stderr, __VA_ARGS__); \
32 } while (0)
33
Saleem Abdulrasool675df582015-04-24 19:39:17 +000034namespace libunwind {
35
36/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
Ed Maste63469ff2016-07-19 17:15:50 +000037/// See DWARF Spec for details:
Saleem Abdulrasool675df582015-04-24 19:39:17 +000038/// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
39///
40template <typename A>
41class CFI_Parser {
42public:
43 typedef typename A::pint_t pint_t;
44
45 /// Information encoded in a CIE (Common Information Entry)
46 struct CIE_Info {
47 pint_t cieStart;
48 pint_t cieLength;
49 pint_t cieInstructions;
50 uint8_t pointerEncoding;
51 uint8_t lsdaEncoding;
52 uint8_t personalityEncoding;
53 uint8_t personalityOffsetInCIE;
54 pint_t personality;
55 uint32_t codeAlignFactor;
56 int dataAlignFactor;
57 bool isSignalFrame;
58 bool fdesHaveAugmentationData;
59 uint8_t returnAddressRegister;
60 };
61
62 /// Information about an FDE (Frame Description Entry)
63 struct FDE_Info {
64 pint_t fdeStart;
65 pint_t fdeLength;
66 pint_t fdeInstructions;
67 pint_t pcStart;
68 pint_t pcEnd;
69 pint_t lsda;
70 };
71
72 enum {
Ed Mastef9f79282016-07-20 15:19:09 +000073 kMaxRegisterNumber = _LIBUNWIND_HIGHEST_DWARF_REGISTER
Saleem Abdulrasool675df582015-04-24 19:39:17 +000074 };
75 enum RegisterSavedWhere {
76 kRegisterUnused,
77 kRegisterInCFA,
78 kRegisterOffsetFromCFA,
79 kRegisterInRegister,
80 kRegisterAtExpression,
81 kRegisterIsExpression
82 };
83 struct RegisterLocation {
84 RegisterSavedWhere location;
85 int64_t value;
86 };
87 /// Information about a frame layout and registers saved determined
Ed Maste63469ff2016-07-19 17:15:50 +000088 /// by "running" the DWARF FDE "instructions"
Saleem Abdulrasool675df582015-04-24 19:39:17 +000089 struct PrologInfo {
90 uint32_t cfaRegister;
91 int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
92 int64_t cfaExpression; // CFA = expression
93 uint32_t spExtraArgSize;
94 uint32_t codeOffsetAtStackDecrement;
95 bool registersInOtherRegisters;
96 bool sameValueUsed;
97 RegisterLocation savedRegisters[kMaxRegisterNumber];
98 };
99
100 struct PrologInfoStackEntry {
101 PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i)
102 : next(n), info(i) {}
103 PrologInfoStackEntry *next;
104 PrologInfo info;
105 };
106
107 static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
108 uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
109 CIE_Info *cieInfo);
110 static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
111 FDE_Info *fdeInfo, CIE_Info *cieInfo);
112 static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,
113 const CIE_Info &cieInfo, pint_t upToPC,
114 PrologInfo *results);
115
116 static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
117
118private:
119 static bool parseInstructions(A &addressSpace, pint_t instructions,
120 pint_t instructionsEnd, const CIE_Info &cieInfo,
121 pint_t pcoffset,
122 PrologInfoStackEntry *&rememberStack,
123 PrologInfo *results);
124};
125
126/// Parse a FDE into a CIE_Info and an FDE_Info
127template <typename A>
128const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
129 FDE_Info *fdeInfo, CIE_Info *cieInfo) {
130 pint_t p = fdeStart;
131 pint_t cfiLength = (pint_t)addressSpace.get32(p);
132 p += 4;
133 if (cfiLength == 0xffffffff) {
134 // 0xffffffff means length is really next 8 bytes
135 cfiLength = (pint_t)addressSpace.get64(p);
136 p += 8;
137 }
138 if (cfiLength == 0)
139 return "FDE has zero length"; // end marker
140 uint32_t ciePointer = addressSpace.get32(p);
141 if (ciePointer == 0)
142 return "FDE is really a CIE"; // this is a CIE not an FDE
143 pint_t nextCFI = p + cfiLength;
144 pint_t cieStart = p - ciePointer;
145 const char *err = parseCIE(addressSpace, cieStart, cieInfo);
146 if (err != NULL)
147 return err;
148 p += 4;
Ed Maste9de42aa2016-07-19 17:28:38 +0000149 // Parse pc begin and range.
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000150 pint_t pcStart =
151 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
152 pint_t pcRange =
153 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
Ed Maste9de42aa2016-07-19 17:28:38 +0000154 // Parse rest of info.
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000155 fdeInfo->lsda = 0;
Ed Maste9de42aa2016-07-19 17:28:38 +0000156 // Check for augmentation length.
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000157 if (cieInfo->fdesHaveAugmentationData) {
158 pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
159 pint_t endOfAug = p + augLen;
160 if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
Ed Maste9de42aa2016-07-19 17:28:38 +0000161 // Peek at value (without indirection). Zero means no LSDA.
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000162 pint_t lsdaStart = p;
163 if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) !=
164 0) {
Ed Maste9de42aa2016-07-19 17:28:38 +0000165 // Reset pointer and re-parse LSDA address.
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000166 p = lsdaStart;
167 fdeInfo->lsda =
168 addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
169 }
170 }
171 p = endOfAug;
172 }
173 fdeInfo->fdeStart = fdeStart;
174 fdeInfo->fdeLength = nextCFI - fdeStart;
175 fdeInfo->fdeInstructions = p;
176 fdeInfo->pcStart = pcStart;
177 fdeInfo->pcEnd = pcStart + pcRange;
178 return NULL; // success
179}
180
181/// Scan an eh_frame section to find an FDE for a pc
182template <typename A>
183bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
184 uint32_t sectionLength, pint_t fdeHint,
185 FDE_Info *fdeInfo, CIE_Info *cieInfo) {
186 //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
187 pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
188 const pint_t ehSectionEnd = p + sectionLength;
189 while (p < ehSectionEnd) {
190 pint_t currentCFI = p;
191 //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
192 pint_t cfiLength = addressSpace.get32(p);
193 p += 4;
194 if (cfiLength == 0xffffffff) {
195 // 0xffffffff means length is really next 8 bytes
196 cfiLength = (pint_t)addressSpace.get64(p);
197 p += 8;
198 }
199 if (cfiLength == 0)
200 return false; // end marker
201 uint32_t id = addressSpace.get32(p);
202 if (id == 0) {
Ed Maste9de42aa2016-07-19 17:28:38 +0000203 // Skip over CIEs.
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000204 p += cfiLength;
205 } else {
Ed Maste9de42aa2016-07-19 17:28:38 +0000206 // Process FDE to see if it covers pc.
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000207 pint_t nextCFI = p + cfiLength;
208 uint32_t ciePointer = addressSpace.get32(p);
209 pint_t cieStart = p - ciePointer;
Ed Maste9de42aa2016-07-19 17:28:38 +0000210 // Validate pointer to CIE is within section.
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000211 if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) {
212 if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) {
213 p += 4;
Ed Maste9de42aa2016-07-19 17:28:38 +0000214 // Parse pc begin and range.
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000215 pint_t pcStart =
216 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
217 pint_t pcRange = addressSpace.getEncodedP(
218 p, nextCFI, cieInfo->pointerEncoding & 0x0F);
Ed Maste9de42aa2016-07-19 17:28:38 +0000219 // Test if pc is within the function this FDE covers.
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000220 if ((pcStart < pc) && (pc <= pcStart + pcRange)) {
221 // parse rest of info
222 fdeInfo->lsda = 0;
223 // check for augmentation length
224 if (cieInfo->fdesHaveAugmentationData) {
225 pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
226 pint_t endOfAug = p + augLen;
227 if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
Ed Maste9de42aa2016-07-19 17:28:38 +0000228 // Peek at value (without indirection). Zero means no LSDA.
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000229 pint_t lsdaStart = p;
230 if (addressSpace.getEncodedP(
231 p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) {
Ed Maste9de42aa2016-07-19 17:28:38 +0000232 // Reset pointer and re-parse LSDA address.
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000233 p = lsdaStart;
234 fdeInfo->lsda = addressSpace
235 .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
236 }
237 }
238 p = endOfAug;
239 }
240 fdeInfo->fdeStart = currentCFI;
241 fdeInfo->fdeLength = nextCFI - currentCFI;
242 fdeInfo->fdeInstructions = p;
243 fdeInfo->pcStart = pcStart;
244 fdeInfo->pcEnd = pcStart + pcRange;
245 return true;
246 } else {
247 // pc is not in begin/range, skip this FDE
248 }
249 } else {
Ed Maste9de42aa2016-07-19 17:28:38 +0000250 // Malformed CIE, now augmentation describing pc range encoding.
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000251 }
252 } else {
253 // malformed FDE. CIE is bad
254 }
255 p = nextCFI;
256 }
257 }
258 return false;
259}
260
261/// Extract info from a CIE
262template <typename A>
263const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
264 CIE_Info *cieInfo) {
265 cieInfo->pointerEncoding = 0;
266 cieInfo->lsdaEncoding = DW_EH_PE_omit;
267 cieInfo->personalityEncoding = 0;
268 cieInfo->personalityOffsetInCIE = 0;
269 cieInfo->personality = 0;
270 cieInfo->codeAlignFactor = 0;
271 cieInfo->dataAlignFactor = 0;
272 cieInfo->isSignalFrame = false;
273 cieInfo->fdesHaveAugmentationData = false;
274 cieInfo->cieStart = cie;
275 pint_t p = cie;
276 pint_t cieLength = (pint_t)addressSpace.get32(p);
277 p += 4;
278 pint_t cieContentEnd = p + cieLength;
279 if (cieLength == 0xffffffff) {
280 // 0xffffffff means length is really next 8 bytes
281 cieLength = (pint_t)addressSpace.get64(p);
282 p += 8;
283 cieContentEnd = p + cieLength;
284 }
285 if (cieLength == 0)
286 return NULL;
287 // CIE ID is always 0
288 if (addressSpace.get32(p) != 0)
289 return "CIE ID is not zero";
290 p += 4;
291 // Version is always 1 or 3
292 uint8_t version = addressSpace.get8(p);
293 if ((version != 1) && (version != 3))
294 return "CIE version is not 1 or 3";
295 ++p;
296 // save start of augmentation string and find end
297 pint_t strStart = p;
298 while (addressSpace.get8(p) != 0)
299 ++p;
300 ++p;
301 // parse code aligment factor
302 cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd);
303 // parse data alignment factor
304 cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd);
305 // parse return address register
306 uint64_t raReg = addressSpace.getULEB128(p, cieContentEnd);
307 assert(raReg < 255 && "return address register too large");
308 cieInfo->returnAddressRegister = (uint8_t)raReg;
309 // parse augmentation data based on augmentation string
310 const char *result = NULL;
311 if (addressSpace.get8(strStart) == 'z') {
312 // parse augmentation data length
313 addressSpace.getULEB128(p, cieContentEnd);
314 for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) {
315 switch (addressSpace.get8(s)) {
316 case 'z':
317 cieInfo->fdesHaveAugmentationData = true;
318 break;
319 case 'P':
320 cieInfo->personalityEncoding = addressSpace.get8(p);
321 ++p;
322 cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie);
323 cieInfo->personality = addressSpace
324 .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
325 break;
326 case 'L':
327 cieInfo->lsdaEncoding = addressSpace.get8(p);
328 ++p;
329 break;
330 case 'R':
331 cieInfo->pointerEncoding = addressSpace.get8(p);
332 ++p;
333 break;
334 case 'S':
335 cieInfo->isSignalFrame = true;
336 break;
337 default:
338 // ignore unknown letters
339 break;
340 }
341 }
342 }
343 cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
344 cieInfo->cieInstructions = p;
345 return result;
346}
347
348
Ed Maste63469ff2016-07-19 17:15:50 +0000349/// "run" the DWARF instructions and create the abstact PrologInfo for an FDE
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000350template <typename A>
351bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
352 const FDE_Info &fdeInfo,
353 const CIE_Info &cieInfo, pint_t upToPC,
354 PrologInfo *results) {
355 // clear results
356 memset(results, '\0', sizeof(PrologInfo));
357 PrologInfoStackEntry *rememberStack = NULL;
358
359 // parse CIE then FDE instructions
360 return parseInstructions(addressSpace, cieInfo.cieInstructions,
361 cieInfo.cieStart + cieInfo.cieLength, cieInfo,
362 (pint_t)(-1), rememberStack, results) &&
363 parseInstructions(addressSpace, fdeInfo.fdeInstructions,
364 fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo,
365 upToPC - fdeInfo.pcStart, rememberStack, results);
366}
367
Ed Maste63469ff2016-07-19 17:15:50 +0000368/// "run" the DWARF instructions
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000369template <typename A>
370bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
371 pint_t instructionsEnd,
372 const CIE_Info &cieInfo, pint_t pcoffset,
373 PrologInfoStackEntry *&rememberStack,
374 PrologInfo *results) {
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000375 pint_t p = instructions;
376 pint_t codeOffset = 0;
377 PrologInfo initialState = *results;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000378
379 _LIBUNWIND_TRACE_DWARF("parseInstructions(instructions=0x%0" PRIx64 ")\n",
380 static_cast<uint64_t>(instructionsEnd));
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000381
Ed Maste63469ff2016-07-19 17:15:50 +0000382 // see DWARF Spec, section 6.4.2 for details on unwind opcodes
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000383 while ((p < instructionsEnd) && (codeOffset < pcoffset)) {
384 uint64_t reg;
385 uint64_t reg2;
386 int64_t offset;
387 uint64_t length;
388 uint8_t opcode = addressSpace.get8(p);
389 uint8_t operand;
Peter Zotov543f8482015-11-09 06:57:29 +0000390#if !defined(_LIBUNWIND_NO_HEAP)
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000391 PrologInfoStackEntry *entry;
Peter Zotov543f8482015-11-09 06:57:29 +0000392#endif
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000393 ++p;
394 switch (opcode) {
395 case DW_CFA_nop:
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000396 _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000397 break;
398 case DW_CFA_set_loc:
399 codeOffset =
400 addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000401 _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000402 break;
403 case DW_CFA_advance_loc1:
404 codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
405 p += 1;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000406 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",
407 static_cast<uint64_t>(codeOffset));
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000408 break;
409 case DW_CFA_advance_loc2:
410 codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
411 p += 2;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000412 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",
413 static_cast<uint64_t>(codeOffset));
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000414 break;
415 case DW_CFA_advance_loc4:
416 codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
417 p += 4;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000418 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",
419 static_cast<uint64_t>(codeOffset));
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000420 break;
421 case DW_CFA_offset_extended:
422 reg = addressSpace.getULEB128(p, instructionsEnd);
423 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
424 * cieInfo.dataAlignFactor;
425 if (reg > kMaxRegisterNumber) {
Saleem Abdulrasoold8c14f52017-01-21 16:22:55 +0000426 _LIBUNWIND_LOG("malformed DWARF DW_CFA_offset_extended, reg too big");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000427 return false;
428 }
429 results->savedRegisters[reg].location = kRegisterInCFA;
430 results->savedRegisters[reg].value = offset;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000431 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", "
432 "offset=%" PRId64 ")\n",
433 reg, offset);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000434 break;
435 case DW_CFA_restore_extended:
436 reg = addressSpace.getULEB128(p, instructionsEnd);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000437 if (reg > kMaxRegisterNumber) {
Saleem Abdulrasoold8c14f52017-01-21 16:22:55 +0000438 _LIBUNWIND_LOG("malformed DWARF DW_CFA_restore_extended, reg too big");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000439 return false;
440 }
441 results->savedRegisters[reg] = initialState.savedRegisters[reg];
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000442 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000443 break;
444 case DW_CFA_undefined:
445 reg = addressSpace.getULEB128(p, instructionsEnd);
446 if (reg > kMaxRegisterNumber) {
Saleem Abdulrasoold8c14f52017-01-21 16:22:55 +0000447 _LIBUNWIND_LOG("malformed DWARF DW_CFA_undefined, reg too big");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000448 return false;
449 }
450 results->savedRegisters[reg].location = kRegisterUnused;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000451 _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000452 break;
453 case DW_CFA_same_value:
454 reg = addressSpace.getULEB128(p, instructionsEnd);
455 if (reg > kMaxRegisterNumber) {
Saleem Abdulrasoold8c14f52017-01-21 16:22:55 +0000456 _LIBUNWIND_LOG("malformed DWARF DW_CFA_same_value, reg too big");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000457 return false;
458 }
459 // <rdar://problem/8456377> DW_CFA_same_value unsupported
460 // "same value" means register was stored in frame, but its current
461 // value has not changed, so no need to restore from frame.
462 // We model this as if the register was never saved.
463 results->savedRegisters[reg].location = kRegisterUnused;
464 // set flag to disable conversion to compact unwind
465 results->sameValueUsed = true;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000466 _LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000467 break;
468 case DW_CFA_register:
469 reg = addressSpace.getULEB128(p, instructionsEnd);
470 reg2 = addressSpace.getULEB128(p, instructionsEnd);
471 if (reg > kMaxRegisterNumber) {
Saleem Abdulrasoold8c14f52017-01-21 16:22:55 +0000472 _LIBUNWIND_LOG("malformed DWARF DW_CFA_register, reg too big");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000473 return false;
474 }
475 if (reg2 > kMaxRegisterNumber) {
Saleem Abdulrasoold8c14f52017-01-21 16:22:55 +0000476 _LIBUNWIND_LOG("malformed DWARF DW_CFA_register, reg2 too big");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000477 return false;
478 }
479 results->savedRegisters[reg].location = kRegisterInRegister;
480 results->savedRegisters[reg].value = (int64_t)reg2;
481 // set flag to disable conversion to compact unwind
482 results->registersInOtherRegisters = true;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000483 _LIBUNWIND_TRACE_DWARF(
484 "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000485 break;
Peter Zotov543f8482015-11-09 06:57:29 +0000486#if !defined(_LIBUNWIND_NO_HEAP)
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000487 case DW_CFA_remember_state:
488 // avoid operator new, because that would be an upward dependency
489 entry = (PrologInfoStackEntry *)malloc(sizeof(PrologInfoStackEntry));
490 if (entry != NULL) {
491 entry->next = rememberStack;
492 entry->info = *results;
493 rememberStack = entry;
494 } else {
495 return false;
496 }
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000497 _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000498 break;
499 case DW_CFA_restore_state:
500 if (rememberStack != NULL) {
501 PrologInfoStackEntry *top = rememberStack;
502 *results = top->info;
503 rememberStack = top->next;
504 free((char *)top);
505 } else {
506 return false;
507 }
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000508 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000509 break;
Peter Zotov543f8482015-11-09 06:57:29 +0000510#endif
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000511 case DW_CFA_def_cfa:
512 reg = addressSpace.getULEB128(p, instructionsEnd);
513 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);
514 if (reg > kMaxRegisterNumber) {
Saleem Abdulrasoold8c14f52017-01-21 16:22:55 +0000515 _LIBUNWIND_LOG("malformed DWARF DW_CFA_def_cfa, reg too big");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000516 return false;
517 }
518 results->cfaRegister = (uint32_t)reg;
519 results->cfaRegisterOffset = (int32_t)offset;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000520 _LIBUNWIND_TRACE_DWARF(
521 "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n", reg, offset);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000522 break;
523 case DW_CFA_def_cfa_register:
524 reg = addressSpace.getULEB128(p, instructionsEnd);
525 if (reg > kMaxRegisterNumber) {
Saleem Abdulrasoold8c14f52017-01-21 16:22:55 +0000526 _LIBUNWIND_LOG("malformed DWARF DW_CFA_def_cfa_register, reg too big");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000527 return false;
528 }
529 results->cfaRegister = (uint32_t)reg;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000530 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000531 break;
532 case DW_CFA_def_cfa_offset:
533 results->cfaRegisterOffset = (int32_t)
534 addressSpace.getULEB128(p, instructionsEnd);
535 results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000536 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n",
537 results->cfaRegisterOffset);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000538 break;
539 case DW_CFA_def_cfa_expression:
540 results->cfaRegister = 0;
541 results->cfaExpression = (int64_t)p;
542 length = addressSpace.getULEB128(p, instructionsEnd);
543 p += length;
Saleem Abdulrasoole1d4b2e2017-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 Abdulrasool675df582015-04-24 19:39:17 +0000547 break;
548 case DW_CFA_expression:
549 reg = addressSpace.getULEB128(p, instructionsEnd);
550 if (reg > kMaxRegisterNumber) {
Saleem Abdulrasoold8c14f52017-01-21 16:22:55 +0000551 _LIBUNWIND_LOG("malformed DWARF DW_CFA_expression, reg too big");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000552 return false;
553 }
554 results->savedRegisters[reg].location = kRegisterAtExpression;
555 results->savedRegisters[reg].value = (int64_t)p;
556 length = addressSpace.getULEB128(p, instructionsEnd);
557 p += length;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000558 _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", "
559 "expression=0x%" PRIx64 ", "
560 "length=%" PRIu64 ")\n",
561 reg, results->savedRegisters[reg].value, length);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000562 break;
563 case DW_CFA_offset_extended_sf:
564 reg = addressSpace.getULEB128(p, instructionsEnd);
565 if (reg > kMaxRegisterNumber) {
Saleem Abdulrasoold8c14f52017-01-21 16:22:55 +0000566 _LIBUNWIND_LOG(
567 "malformed DWARF DW_CFA_offset_extended_sf, reg too big");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000568 return false;
569 }
570 offset =
571 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
572 results->savedRegisters[reg].location = kRegisterInCFA;
573 results->savedRegisters[reg].value = offset;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000574 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", "
575 "offset=%" PRId64 ")\n",
576 reg, offset);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000577 break;
578 case DW_CFA_def_cfa_sf:
579 reg = addressSpace.getULEB128(p, instructionsEnd);
580 offset =
581 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
582 if (reg > kMaxRegisterNumber) {
Saleem Abdulrasoold8c14f52017-01-21 16:22:55 +0000583 _LIBUNWIND_LOG("malformed DWARF DW_CFA_def_cfa_sf, reg too big");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000584 return false;
585 }
586 results->cfaRegister = (uint32_t)reg;
587 results->cfaRegisterOffset = (int32_t)offset;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000588 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", "
589 "offset=%" PRId64 ")\n",
590 reg, offset);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000591 break;
592 case DW_CFA_def_cfa_offset_sf:
593 results->cfaRegisterOffset = (int32_t)
594 (addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor);
595 results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000596 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n",
597 results->cfaRegisterOffset);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000598 break;
599 case DW_CFA_val_offset:
600 reg = addressSpace.getULEB128(p, instructionsEnd);
601 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
602 * cieInfo.dataAlignFactor;
603 results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
604 results->savedRegisters[reg].value = offset;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000605 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", "
606 "offset=%" PRId64 "\n",
607 reg, offset);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000608 break;
609 case DW_CFA_val_offset_sf:
610 reg = addressSpace.getULEB128(p, instructionsEnd);
611 if (reg > kMaxRegisterNumber) {
Saleem Abdulrasoold8c14f52017-01-21 16:22:55 +0000612 _LIBUNWIND_LOG("malformed DWARF DW_CFA_val_offset_sf, reg too big");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000613 return false;
614 }
615 offset =
616 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
617 results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
618 results->savedRegisters[reg].value = offset;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000619 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", "
620 "offset=%" PRId64 "\n",
621 reg, offset);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000622 break;
623 case DW_CFA_val_expression:
624 reg = addressSpace.getULEB128(p, instructionsEnd);
625 if (reg > kMaxRegisterNumber) {
Saleem Abdulrasoold8c14f52017-01-21 16:22:55 +0000626 _LIBUNWIND_LOG("malformed DWARF DW_CFA_val_expression, reg too big");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000627 return false;
628 }
629 results->savedRegisters[reg].location = kRegisterIsExpression;
630 results->savedRegisters[reg].value = (int64_t)p;
631 length = addressSpace.getULEB128(p, instructionsEnd);
632 p += length;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000633 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", "
634 "expression=0x%" PRIx64 ", length=%" PRIu64 ")\n",
635 reg, results->savedRegisters[reg].value, length);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000636 break;
637 case DW_CFA_GNU_args_size:
638 length = addressSpace.getULEB128(p, instructionsEnd);
639 results->spExtraArgSize = (uint32_t)length;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000640 _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000641 break;
642 case DW_CFA_GNU_negative_offset_extended:
643 reg = addressSpace.getULEB128(p, instructionsEnd);
644 if (reg > kMaxRegisterNumber) {
Saleem Abdulrasoold8c14f52017-01-21 16:22:55 +0000645 _LIBUNWIND_LOG(
646 "malformed DWARF DW_CFA_GNU_negative_offset_extended, reg too big");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000647 return false;
648 }
649 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
650 * cieInfo.dataAlignFactor;
651 results->savedRegisters[reg].location = kRegisterInCFA;
652 results->savedRegisters[reg].value = -offset;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000653 _LIBUNWIND_TRACE_DWARF(
654 "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000655 break;
656 default:
657 operand = opcode & 0x3F;
658 switch (opcode & 0xC0) {
659 case DW_CFA_offset:
660 reg = operand;
661 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
662 * cieInfo.dataAlignFactor;
663 results->savedRegisters[reg].location = kRegisterInCFA;
664 results->savedRegisters[reg].value = offset;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000665 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
666 operand, offset);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000667 break;
668 case DW_CFA_advance_loc:
669 codeOffset += operand * cieInfo.codeAlignFactor;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000670 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
671 static_cast<uint64_t>(codeOffset));
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000672 break;
673 case DW_CFA_restore:
674 reg = operand;
675 results->savedRegisters[reg] = initialState.savedRegisters[reg];
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000676 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",
677 static_cast<long>(operand));
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000678 break;
679 default:
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000680 _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000681 return false;
682 }
683 }
684 }
685
686 return true;
687}
688
689} // namespace libunwind
690
691#endif // __DWARF_PARSER_HPP__