blob: 610a3aeb0efca7cfe1492cb654213346fe8df1c3 [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"
Saleem Abdulrasool11ea06f2017-01-25 02:27:45 +000025#include "config.h"
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +000026
Saleem Abdulrasool675df582015-04-24 19:39:17 +000027namespace libunwind {
28
29/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
Ed Maste63469ff2016-07-19 17:15:50 +000030/// See DWARF Spec for details:
Saleem Abdulrasool675df582015-04-24 19:39:17 +000031/// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
32///
33template <typename A>
34class CFI_Parser {
35public:
36 typedef typename A::pint_t pint_t;
37
38 /// Information encoded in a CIE (Common Information Entry)
39 struct CIE_Info {
40 pint_t cieStart;
41 pint_t cieLength;
42 pint_t cieInstructions;
43 uint8_t pointerEncoding;
44 uint8_t lsdaEncoding;
45 uint8_t personalityEncoding;
46 uint8_t personalityOffsetInCIE;
47 pint_t personality;
48 uint32_t codeAlignFactor;
49 int dataAlignFactor;
50 bool isSignalFrame;
51 bool fdesHaveAugmentationData;
52 uint8_t returnAddressRegister;
53 };
54
55 /// Information about an FDE (Frame Description Entry)
56 struct FDE_Info {
57 pint_t fdeStart;
58 pint_t fdeLength;
59 pint_t fdeInstructions;
60 pint_t pcStart;
61 pint_t pcEnd;
62 pint_t lsda;
63 };
64
65 enum {
Ed Mastef9f79282016-07-20 15:19:09 +000066 kMaxRegisterNumber = _LIBUNWIND_HIGHEST_DWARF_REGISTER
Saleem Abdulrasool675df582015-04-24 19:39:17 +000067 };
68 enum RegisterSavedWhere {
69 kRegisterUnused,
70 kRegisterInCFA,
71 kRegisterOffsetFromCFA,
72 kRegisterInRegister,
73 kRegisterAtExpression,
74 kRegisterIsExpression
75 };
76 struct RegisterLocation {
77 RegisterSavedWhere location;
78 int64_t value;
79 };
80 /// Information about a frame layout and registers saved determined
Ed Maste63469ff2016-07-19 17:15:50 +000081 /// by "running" the DWARF FDE "instructions"
Saleem Abdulrasool675df582015-04-24 19:39:17 +000082 struct PrologInfo {
83 uint32_t cfaRegister;
84 int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
85 int64_t cfaExpression; // CFA = expression
86 uint32_t spExtraArgSize;
87 uint32_t codeOffsetAtStackDecrement;
88 bool registersInOtherRegisters;
89 bool sameValueUsed;
90 RegisterLocation savedRegisters[kMaxRegisterNumber];
91 };
92
93 struct PrologInfoStackEntry {
94 PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i)
95 : next(n), info(i) {}
96 PrologInfoStackEntry *next;
97 PrologInfo info;
98 };
99
100 static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
101 uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
102 CIE_Info *cieInfo);
103 static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
104 FDE_Info *fdeInfo, CIE_Info *cieInfo);
105 static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,
106 const CIE_Info &cieInfo, pint_t upToPC,
107 PrologInfo *results);
108
109 static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
110
111private:
112 static bool parseInstructions(A &addressSpace, pint_t instructions,
113 pint_t instructionsEnd, const CIE_Info &cieInfo,
114 pint_t pcoffset,
115 PrologInfoStackEntry *&rememberStack,
116 PrologInfo *results);
117};
118
119/// Parse a FDE into a CIE_Info and an FDE_Info
120template <typename A>
121const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
122 FDE_Info *fdeInfo, CIE_Info *cieInfo) {
123 pint_t p = fdeStart;
124 pint_t cfiLength = (pint_t)addressSpace.get32(p);
125 p += 4;
126 if (cfiLength == 0xffffffff) {
127 // 0xffffffff means length is really next 8 bytes
128 cfiLength = (pint_t)addressSpace.get64(p);
129 p += 8;
130 }
131 if (cfiLength == 0)
132 return "FDE has zero length"; // end marker
133 uint32_t ciePointer = addressSpace.get32(p);
134 if (ciePointer == 0)
135 return "FDE is really a CIE"; // this is a CIE not an FDE
136 pint_t nextCFI = p + cfiLength;
137 pint_t cieStart = p - ciePointer;
138 const char *err = parseCIE(addressSpace, cieStart, cieInfo);
139 if (err != NULL)
140 return err;
141 p += 4;
Ed Maste9de42aa2016-07-19 17:28:38 +0000142 // Parse pc begin and range.
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000143 pint_t pcStart =
144 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
145 pint_t pcRange =
146 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
Ed Maste9de42aa2016-07-19 17:28:38 +0000147 // Parse rest of info.
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000148 fdeInfo->lsda = 0;
Ed Maste9de42aa2016-07-19 17:28:38 +0000149 // Check for augmentation length.
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000150 if (cieInfo->fdesHaveAugmentationData) {
151 pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
152 pint_t endOfAug = p + augLen;
153 if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
Ed Maste9de42aa2016-07-19 17:28:38 +0000154 // Peek at value (without indirection). Zero means no LSDA.
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000155 pint_t lsdaStart = p;
156 if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) !=
157 0) {
Ed Maste9de42aa2016-07-19 17:28:38 +0000158 // Reset pointer and re-parse LSDA address.
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000159 p = lsdaStart;
160 fdeInfo->lsda =
161 addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
162 }
163 }
164 p = endOfAug;
165 }
166 fdeInfo->fdeStart = fdeStart;
167 fdeInfo->fdeLength = nextCFI - fdeStart;
168 fdeInfo->fdeInstructions = p;
169 fdeInfo->pcStart = pcStart;
170 fdeInfo->pcEnd = pcStart + pcRange;
171 return NULL; // success
172}
173
174/// Scan an eh_frame section to find an FDE for a pc
175template <typename A>
176bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
177 uint32_t sectionLength, pint_t fdeHint,
178 FDE_Info *fdeInfo, CIE_Info *cieInfo) {
179 //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
180 pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
181 const pint_t ehSectionEnd = p + sectionLength;
182 while (p < ehSectionEnd) {
183 pint_t currentCFI = p;
184 //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
185 pint_t cfiLength = addressSpace.get32(p);
186 p += 4;
187 if (cfiLength == 0xffffffff) {
188 // 0xffffffff means length is really next 8 bytes
189 cfiLength = (pint_t)addressSpace.get64(p);
190 p += 8;
191 }
192 if (cfiLength == 0)
193 return false; // end marker
194 uint32_t id = addressSpace.get32(p);
195 if (id == 0) {
Ed Maste9de42aa2016-07-19 17:28:38 +0000196 // Skip over CIEs.
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000197 p += cfiLength;
198 } else {
Ed Maste9de42aa2016-07-19 17:28:38 +0000199 // Process FDE to see if it covers pc.
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000200 pint_t nextCFI = p + cfiLength;
201 uint32_t ciePointer = addressSpace.get32(p);
202 pint_t cieStart = p - ciePointer;
Ed Maste9de42aa2016-07-19 17:28:38 +0000203 // Validate pointer to CIE is within section.
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000204 if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) {
205 if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) {
206 p += 4;
Ed Maste9de42aa2016-07-19 17:28:38 +0000207 // Parse pc begin and range.
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000208 pint_t pcStart =
209 addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
210 pint_t pcRange = addressSpace.getEncodedP(
211 p, nextCFI, cieInfo->pointerEncoding & 0x0F);
Ed Maste9de42aa2016-07-19 17:28:38 +0000212 // Test if pc is within the function this FDE covers.
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000213 if ((pcStart < pc) && (pc <= pcStart + pcRange)) {
214 // parse rest of info
215 fdeInfo->lsda = 0;
216 // check for augmentation length
217 if (cieInfo->fdesHaveAugmentationData) {
218 pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
219 pint_t endOfAug = p + augLen;
220 if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
Ed Maste9de42aa2016-07-19 17:28:38 +0000221 // Peek at value (without indirection). Zero means no LSDA.
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000222 pint_t lsdaStart = p;
223 if (addressSpace.getEncodedP(
224 p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) {
Ed Maste9de42aa2016-07-19 17:28:38 +0000225 // Reset pointer and re-parse LSDA address.
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000226 p = lsdaStart;
227 fdeInfo->lsda = addressSpace
228 .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
229 }
230 }
231 p = endOfAug;
232 }
233 fdeInfo->fdeStart = currentCFI;
234 fdeInfo->fdeLength = nextCFI - currentCFI;
235 fdeInfo->fdeInstructions = p;
236 fdeInfo->pcStart = pcStart;
237 fdeInfo->pcEnd = pcStart + pcRange;
238 return true;
239 } else {
240 // pc is not in begin/range, skip this FDE
241 }
242 } else {
Ed Maste9de42aa2016-07-19 17:28:38 +0000243 // Malformed CIE, now augmentation describing pc range encoding.
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000244 }
245 } else {
246 // malformed FDE. CIE is bad
247 }
248 p = nextCFI;
249 }
250 }
251 return false;
252}
253
254/// Extract info from a CIE
255template <typename A>
256const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
257 CIE_Info *cieInfo) {
258 cieInfo->pointerEncoding = 0;
259 cieInfo->lsdaEncoding = DW_EH_PE_omit;
260 cieInfo->personalityEncoding = 0;
261 cieInfo->personalityOffsetInCIE = 0;
262 cieInfo->personality = 0;
263 cieInfo->codeAlignFactor = 0;
264 cieInfo->dataAlignFactor = 0;
265 cieInfo->isSignalFrame = false;
266 cieInfo->fdesHaveAugmentationData = false;
267 cieInfo->cieStart = cie;
268 pint_t p = cie;
269 pint_t cieLength = (pint_t)addressSpace.get32(p);
270 p += 4;
271 pint_t cieContentEnd = p + cieLength;
272 if (cieLength == 0xffffffff) {
273 // 0xffffffff means length is really next 8 bytes
274 cieLength = (pint_t)addressSpace.get64(p);
275 p += 8;
276 cieContentEnd = p + cieLength;
277 }
278 if (cieLength == 0)
279 return NULL;
280 // CIE ID is always 0
281 if (addressSpace.get32(p) != 0)
282 return "CIE ID is not zero";
283 p += 4;
284 // Version is always 1 or 3
285 uint8_t version = addressSpace.get8(p);
286 if ((version != 1) && (version != 3))
287 return "CIE version is not 1 or 3";
288 ++p;
289 // save start of augmentation string and find end
290 pint_t strStart = p;
291 while (addressSpace.get8(p) != 0)
292 ++p;
293 ++p;
294 // parse code aligment factor
295 cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd);
296 // parse data alignment factor
297 cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd);
298 // parse return address register
299 uint64_t raReg = addressSpace.getULEB128(p, cieContentEnd);
300 assert(raReg < 255 && "return address register too large");
301 cieInfo->returnAddressRegister = (uint8_t)raReg;
302 // parse augmentation data based on augmentation string
303 const char *result = NULL;
304 if (addressSpace.get8(strStart) == 'z') {
305 // parse augmentation data length
306 addressSpace.getULEB128(p, cieContentEnd);
307 for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) {
308 switch (addressSpace.get8(s)) {
309 case 'z':
310 cieInfo->fdesHaveAugmentationData = true;
311 break;
312 case 'P':
313 cieInfo->personalityEncoding = addressSpace.get8(p);
314 ++p;
315 cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie);
316 cieInfo->personality = addressSpace
317 .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
318 break;
319 case 'L':
320 cieInfo->lsdaEncoding = addressSpace.get8(p);
321 ++p;
322 break;
323 case 'R':
324 cieInfo->pointerEncoding = addressSpace.get8(p);
325 ++p;
326 break;
327 case 'S':
328 cieInfo->isSignalFrame = true;
329 break;
330 default:
331 // ignore unknown letters
332 break;
333 }
334 }
335 }
336 cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
337 cieInfo->cieInstructions = p;
338 return result;
339}
340
341
Ed Maste63469ff2016-07-19 17:15:50 +0000342/// "run" the DWARF instructions and create the abstact PrologInfo for an FDE
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000343template <typename A>
344bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
345 const FDE_Info &fdeInfo,
346 const CIE_Info &cieInfo, pint_t upToPC,
347 PrologInfo *results) {
348 // clear results
349 memset(results, '\0', sizeof(PrologInfo));
350 PrologInfoStackEntry *rememberStack = NULL;
351
352 // parse CIE then FDE instructions
353 return parseInstructions(addressSpace, cieInfo.cieInstructions,
354 cieInfo.cieStart + cieInfo.cieLength, cieInfo,
355 (pint_t)(-1), rememberStack, results) &&
356 parseInstructions(addressSpace, fdeInfo.fdeInstructions,
357 fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo,
358 upToPC - fdeInfo.pcStart, rememberStack, results);
359}
360
Ed Maste63469ff2016-07-19 17:15:50 +0000361/// "run" the DWARF instructions
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000362template <typename A>
363bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
364 pint_t instructionsEnd,
365 const CIE_Info &cieInfo, pint_t pcoffset,
366 PrologInfoStackEntry *&rememberStack,
367 PrologInfo *results) {
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000368 pint_t p = instructions;
369 pint_t codeOffset = 0;
370 PrologInfo initialState = *results;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000371
372 _LIBUNWIND_TRACE_DWARF("parseInstructions(instructions=0x%0" PRIx64 ")\n",
373 static_cast<uint64_t>(instructionsEnd));
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000374
Ed Maste63469ff2016-07-19 17:15:50 +0000375 // see DWARF Spec, section 6.4.2 for details on unwind opcodes
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000376 while ((p < instructionsEnd) && (codeOffset < pcoffset)) {
377 uint64_t reg;
378 uint64_t reg2;
379 int64_t offset;
380 uint64_t length;
381 uint8_t opcode = addressSpace.get8(p);
382 uint8_t operand;
Peter Zotov543f8482015-11-09 06:57:29 +0000383#if !defined(_LIBUNWIND_NO_HEAP)
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000384 PrologInfoStackEntry *entry;
Peter Zotov543f8482015-11-09 06:57:29 +0000385#endif
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000386 ++p;
387 switch (opcode) {
388 case DW_CFA_nop:
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000389 _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000390 break;
391 case DW_CFA_set_loc:
392 codeOffset =
393 addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000394 _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000395 break;
396 case DW_CFA_advance_loc1:
397 codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
398 p += 1;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000399 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",
400 static_cast<uint64_t>(codeOffset));
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000401 break;
402 case DW_CFA_advance_loc2:
403 codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
404 p += 2;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000405 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",
406 static_cast<uint64_t>(codeOffset));
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000407 break;
408 case DW_CFA_advance_loc4:
409 codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
410 p += 4;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000411 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",
412 static_cast<uint64_t>(codeOffset));
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000413 break;
414 case DW_CFA_offset_extended:
415 reg = addressSpace.getULEB128(p, instructionsEnd);
416 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
417 * cieInfo.dataAlignFactor;
418 if (reg > kMaxRegisterNumber) {
Saleem Abdulrasoold8c14f52017-01-21 16:22:55 +0000419 _LIBUNWIND_LOG("malformed DWARF DW_CFA_offset_extended, reg too big");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000420 return false;
421 }
422 results->savedRegisters[reg].location = kRegisterInCFA;
423 results->savedRegisters[reg].value = offset;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000424 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", "
425 "offset=%" PRId64 ")\n",
426 reg, offset);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000427 break;
428 case DW_CFA_restore_extended:
429 reg = addressSpace.getULEB128(p, instructionsEnd);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000430 if (reg > kMaxRegisterNumber) {
Saleem Abdulrasoold8c14f52017-01-21 16:22:55 +0000431 _LIBUNWIND_LOG("malformed DWARF DW_CFA_restore_extended, reg too big");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000432 return false;
433 }
434 results->savedRegisters[reg] = initialState.savedRegisters[reg];
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000435 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000436 break;
437 case DW_CFA_undefined:
438 reg = addressSpace.getULEB128(p, instructionsEnd);
439 if (reg > kMaxRegisterNumber) {
Saleem Abdulrasoold8c14f52017-01-21 16:22:55 +0000440 _LIBUNWIND_LOG("malformed DWARF DW_CFA_undefined, reg too big");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000441 return false;
442 }
443 results->savedRegisters[reg].location = kRegisterUnused;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000444 _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000445 break;
446 case DW_CFA_same_value:
447 reg = addressSpace.getULEB128(p, instructionsEnd);
448 if (reg > kMaxRegisterNumber) {
Saleem Abdulrasoold8c14f52017-01-21 16:22:55 +0000449 _LIBUNWIND_LOG("malformed DWARF DW_CFA_same_value, reg too big");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000450 return false;
451 }
452 // <rdar://problem/8456377> DW_CFA_same_value unsupported
453 // "same value" means register was stored in frame, but its current
454 // value has not changed, so no need to restore from frame.
455 // We model this as if the register was never saved.
456 results->savedRegisters[reg].location = kRegisterUnused;
457 // set flag to disable conversion to compact unwind
458 results->sameValueUsed = true;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000459 _LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000460 break;
461 case DW_CFA_register:
462 reg = addressSpace.getULEB128(p, instructionsEnd);
463 reg2 = addressSpace.getULEB128(p, instructionsEnd);
464 if (reg > kMaxRegisterNumber) {
Saleem Abdulrasoold8c14f52017-01-21 16:22:55 +0000465 _LIBUNWIND_LOG("malformed DWARF DW_CFA_register, reg too big");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000466 return false;
467 }
468 if (reg2 > kMaxRegisterNumber) {
Saleem Abdulrasoold8c14f52017-01-21 16:22:55 +0000469 _LIBUNWIND_LOG("malformed DWARF DW_CFA_register, reg2 too big");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000470 return false;
471 }
472 results->savedRegisters[reg].location = kRegisterInRegister;
473 results->savedRegisters[reg].value = (int64_t)reg2;
474 // set flag to disable conversion to compact unwind
475 results->registersInOtherRegisters = true;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000476 _LIBUNWIND_TRACE_DWARF(
477 "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000478 break;
Peter Zotov543f8482015-11-09 06:57:29 +0000479#if !defined(_LIBUNWIND_NO_HEAP)
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000480 case DW_CFA_remember_state:
481 // avoid operator new, because that would be an upward dependency
482 entry = (PrologInfoStackEntry *)malloc(sizeof(PrologInfoStackEntry));
483 if (entry != NULL) {
484 entry->next = rememberStack;
485 entry->info = *results;
486 rememberStack = entry;
487 } else {
488 return false;
489 }
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000490 _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000491 break;
492 case DW_CFA_restore_state:
493 if (rememberStack != NULL) {
494 PrologInfoStackEntry *top = rememberStack;
495 *results = top->info;
496 rememberStack = top->next;
497 free((char *)top);
498 } else {
499 return false;
500 }
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000501 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000502 break;
Peter Zotov543f8482015-11-09 06:57:29 +0000503#endif
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000504 case DW_CFA_def_cfa:
505 reg = addressSpace.getULEB128(p, instructionsEnd);
506 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);
507 if (reg > kMaxRegisterNumber) {
Saleem Abdulrasoold8c14f52017-01-21 16:22:55 +0000508 _LIBUNWIND_LOG("malformed DWARF DW_CFA_def_cfa, reg too big");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000509 return false;
510 }
511 results->cfaRegister = (uint32_t)reg;
512 results->cfaRegisterOffset = (int32_t)offset;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000513 _LIBUNWIND_TRACE_DWARF(
514 "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n", reg, offset);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000515 break;
516 case DW_CFA_def_cfa_register:
517 reg = addressSpace.getULEB128(p, instructionsEnd);
518 if (reg > kMaxRegisterNumber) {
Saleem Abdulrasoold8c14f52017-01-21 16:22:55 +0000519 _LIBUNWIND_LOG("malformed DWARF DW_CFA_def_cfa_register, reg too big");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000520 return false;
521 }
522 results->cfaRegister = (uint32_t)reg;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000523 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000524 break;
525 case DW_CFA_def_cfa_offset:
526 results->cfaRegisterOffset = (int32_t)
527 addressSpace.getULEB128(p, instructionsEnd);
528 results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000529 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n",
530 results->cfaRegisterOffset);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000531 break;
532 case DW_CFA_def_cfa_expression:
533 results->cfaRegister = 0;
534 results->cfaExpression = (int64_t)p;
535 length = addressSpace.getULEB128(p, instructionsEnd);
536 p += length;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000537 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64
538 ", length=%" PRIu64 ")\n",
539 results->cfaExpression, length);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000540 break;
541 case DW_CFA_expression:
542 reg = addressSpace.getULEB128(p, instructionsEnd);
543 if (reg > kMaxRegisterNumber) {
Saleem Abdulrasoold8c14f52017-01-21 16:22:55 +0000544 _LIBUNWIND_LOG("malformed DWARF DW_CFA_expression, reg too big");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000545 return false;
546 }
547 results->savedRegisters[reg].location = kRegisterAtExpression;
548 results->savedRegisters[reg].value = (int64_t)p;
549 length = addressSpace.getULEB128(p, instructionsEnd);
550 p += length;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000551 _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", "
552 "expression=0x%" PRIx64 ", "
553 "length=%" PRIu64 ")\n",
554 reg, results->savedRegisters[reg].value, length);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000555 break;
556 case DW_CFA_offset_extended_sf:
557 reg = addressSpace.getULEB128(p, instructionsEnd);
558 if (reg > kMaxRegisterNumber) {
Saleem Abdulrasoold8c14f52017-01-21 16:22:55 +0000559 _LIBUNWIND_LOG(
560 "malformed DWARF DW_CFA_offset_extended_sf, reg too big");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000561 return false;
562 }
563 offset =
564 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
565 results->savedRegisters[reg].location = kRegisterInCFA;
566 results->savedRegisters[reg].value = offset;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000567 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", "
568 "offset=%" PRId64 ")\n",
569 reg, offset);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000570 break;
571 case DW_CFA_def_cfa_sf:
572 reg = addressSpace.getULEB128(p, instructionsEnd);
573 offset =
574 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
575 if (reg > kMaxRegisterNumber) {
Saleem Abdulrasoold8c14f52017-01-21 16:22:55 +0000576 _LIBUNWIND_LOG("malformed DWARF DW_CFA_def_cfa_sf, reg too big");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000577 return false;
578 }
579 results->cfaRegister = (uint32_t)reg;
580 results->cfaRegisterOffset = (int32_t)offset;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000581 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", "
582 "offset=%" PRId64 ")\n",
583 reg, offset);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000584 break;
585 case DW_CFA_def_cfa_offset_sf:
586 results->cfaRegisterOffset = (int32_t)
587 (addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor);
588 results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000589 _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n",
590 results->cfaRegisterOffset);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000591 break;
592 case DW_CFA_val_offset:
593 reg = addressSpace.getULEB128(p, instructionsEnd);
594 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
595 * cieInfo.dataAlignFactor;
596 results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
597 results->savedRegisters[reg].value = offset;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000598 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", "
599 "offset=%" PRId64 "\n",
600 reg, offset);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000601 break;
602 case DW_CFA_val_offset_sf:
603 reg = addressSpace.getULEB128(p, instructionsEnd);
604 if (reg > kMaxRegisterNumber) {
Saleem Abdulrasoold8c14f52017-01-21 16:22:55 +0000605 _LIBUNWIND_LOG("malformed DWARF DW_CFA_val_offset_sf, reg too big");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000606 return false;
607 }
608 offset =
609 addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
610 results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
611 results->savedRegisters[reg].value = offset;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000612 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", "
613 "offset=%" PRId64 "\n",
614 reg, offset);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000615 break;
616 case DW_CFA_val_expression:
617 reg = addressSpace.getULEB128(p, instructionsEnd);
618 if (reg > kMaxRegisterNumber) {
Saleem Abdulrasoold8c14f52017-01-21 16:22:55 +0000619 _LIBUNWIND_LOG("malformed DWARF DW_CFA_val_expression, reg too big");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000620 return false;
621 }
622 results->savedRegisters[reg].location = kRegisterIsExpression;
623 results->savedRegisters[reg].value = (int64_t)p;
624 length = addressSpace.getULEB128(p, instructionsEnd);
625 p += length;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000626 _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", "
627 "expression=0x%" PRIx64 ", length=%" PRIu64 ")\n",
628 reg, results->savedRegisters[reg].value, length);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000629 break;
630 case DW_CFA_GNU_args_size:
631 length = addressSpace.getULEB128(p, instructionsEnd);
632 results->spExtraArgSize = (uint32_t)length;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000633 _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000634 break;
635 case DW_CFA_GNU_negative_offset_extended:
636 reg = addressSpace.getULEB128(p, instructionsEnd);
637 if (reg > kMaxRegisterNumber) {
Saleem Abdulrasoold8c14f52017-01-21 16:22:55 +0000638 _LIBUNWIND_LOG(
639 "malformed DWARF DW_CFA_GNU_negative_offset_extended, reg too big");
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000640 return false;
641 }
642 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
643 * cieInfo.dataAlignFactor;
644 results->savedRegisters[reg].location = kRegisterInCFA;
645 results->savedRegisters[reg].value = -offset;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000646 _LIBUNWIND_TRACE_DWARF(
647 "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000648 break;
649 default:
650 operand = opcode & 0x3F;
651 switch (opcode & 0xC0) {
652 case DW_CFA_offset:
653 reg = operand;
654 offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
655 * cieInfo.dataAlignFactor;
656 results->savedRegisters[reg].location = kRegisterInCFA;
657 results->savedRegisters[reg].value = offset;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000658 _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
659 operand, offset);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000660 break;
661 case DW_CFA_advance_loc:
662 codeOffset += operand * cieInfo.codeAlignFactor;
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000663 _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
664 static_cast<uint64_t>(codeOffset));
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000665 break;
666 case DW_CFA_restore:
667 reg = operand;
668 results->savedRegisters[reg] = initialState.savedRegisters[reg];
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000669 _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",
Saleem Abdulrasool43a1c582017-01-21 21:27:29 +0000670 static_cast<uint64_t>(operand));
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000671 break;
672 default:
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000673 _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000674 return false;
675 }
676 }
677 }
678
679 return true;
680}
681
682} // namespace libunwind
683
684#endif // __DWARF_PARSER_HPP__