]> git.saurik.com Git - apple/ld64.git/blame - src/ld/parsers/libunwind/DwarfParser.hpp
ld64-127.2.tar.gz
[apple/ld64.git] / src / ld / parsers / libunwind / DwarfParser.hpp
CommitLineData
afe874b1
A
1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2008 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25//
26// processor specific parsing of dwarf unwind instructions
27//
28
29#ifndef __DWARF_PARSER_HPP__
30#define __DWARF_PARSER_HPP__
31
32#include <stdint.h>
33#include <stdio.h>
34#include <stdlib.h>
35
36#include <vector>
37
38#include "libunwind.h"
39#include "dwarf2.h"
40
41#include "AddressSpace.hpp"
42
43
44namespace libunwind {
45
46
47///
48/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
49/// See Dwarf Spec for details:
50/// http://www.linux-foundation.org/spec/booksets/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
51///
52template <typename A>
53class CFI_Parser
54{
55public:
56 typedef typename A::pint_t pint_t;
57
58 ///
59 /// Information encoded in a CIE (Common Information Entry)
60 ///
61 struct CIE_Info {
62 pint_t cieStart;
63 pint_t cieLength;
64 pint_t cieInstructions;
65 uint8_t pointerEncoding;
66 uint8_t lsdaEncoding;
67 uint8_t personalityEncoding;
68 uint8_t personalityOffsetInCIE;
69 pint_t personality;
70 int codeAlignFactor;
71 int dataAlignFactor;
72 bool isSignalFrame;
73 bool fdesHaveAugmentationData;
74 };
75
76 ///
77 /// Information about an FDE (Frame Description Entry)
78 ///
79 struct FDE_Info {
80 pint_t fdeStart;
81 pint_t fdeLength;
82 pint_t fdeInstructions;
83 pint_t pcStart;
84 pint_t pcEnd;
85 pint_t lsda;
86 };
87
88 ///
89 /// Used by linker when parsing __eh_frame section
90 ///
91 struct FDE_Reference {
92 pint_t address;
93 uint32_t offsetInFDE;
94 uint8_t encodingOfAddress;
95 };
96 struct FDE_Atom_Info {
97 pint_t fdeAddress;
98 FDE_Reference function;
99 FDE_Reference cie;
100 FDE_Reference lsda;
101 };
102 struct CIE_Atom_Info {
103 pint_t cieAddress;
104 FDE_Reference personality;
105 };
106
107
108 ///
109 /// Information about a frame layout and registers saved determined
110 /// by "running" the dwarf FDE "instructions"
111 ///
112 enum { kMaxRegisterNumber = 120 };
113 enum RegisterSavedWhere { kRegisterUnused, kRegisterInCFA, kRegisterOffsetFromCFA,
114 kRegisterInRegister, kRegisterAtExpression, kRegisterIsExpression } ;
115 struct RegisterLocation {
116 RegisterSavedWhere location;
117 int64_t value;
118 };
119 struct PrologInfo {
120 uint32_t cfaRegister;
121 int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
122 int64_t cfaExpression; // CFA = expression
123 uint32_t spExtraArgSize;
124 uint32_t codeOffsetAtStackDecrement;
125 uint8_t registerSavedTwiceInCIE;
126 bool registersInOtherRegisters;
127 bool registerSavedMoreThanOnce;
128 bool cfaOffsetWasNegative;
129 bool sameValueUsed;
130 RegisterLocation savedRegisters[kMaxRegisterNumber]; // from where to restore registers
131 };
132
133 struct PrologInfoStackEntry {
134 PrologInfoStackEntry(PrologInfoStackEntry* n, const PrologInfo& i)
135 : next(n), info(i) {}
136 PrologInfoStackEntry* next;
137 PrologInfo info;
138 };
139
140 static bool findFDE(A& addressSpace, pint_t pc, pint_t ehSectionStart, uint32_t sectionLength, pint_t fdeHint, FDE_Info* fdeInfo, CIE_Info* cieInfo);
141 static const char* decodeFDE(A& addressSpace, pint_t fdeStart, FDE_Info* fdeInfo, CIE_Info* cieInfo);
142 static bool parseFDEInstructions(A& addressSpace, const FDE_Info& fdeInfo, const CIE_Info& cieInfo, pint_t upToPC, PrologInfo* results);
143 static const char* getCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength,
144 std::vector<FDE_Atom_Info>& fdes, std::vector<CIE_Atom_Info>& cies);
145 static uint32_t getCFICount(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength);
146
147 static const char* parseCIE(A& addressSpace, pint_t cie, CIE_Info* cieInfo);
148
149private:
150 static bool parseInstructions(A& addressSpace, pint_t instructions, pint_t instructionsEnd, const CIE_Info& cieInfo,
151 pint_t pcoffset, PrologInfoStackEntry*& rememberStack, PrologInfo* results);
152};
153
154
155///
156/// Parse a FDE into a CIE_Info and an FDE_Info
157///
158template <typename A>
159const char* CFI_Parser<A>::decodeFDE(A& addressSpace, pint_t fdeStart, FDE_Info* fdeInfo, CIE_Info* cieInfo)
160{
161 pint_t p = fdeStart;
162 uint64_t cfiLength = addressSpace.get32(p);
163 p += 4;
164 if ( cfiLength == 0xffffffff ) {
165 // 0xffffffff means length is really next 8 bytes
166 cfiLength = addressSpace.get64(p);
167 p += 8;
168 }
169 if ( cfiLength == 0 )
170 return "FDE has zero length"; // end marker
171 uint32_t ciePointer = addressSpace.get32(p);
172 if ( ciePointer == 0 )
173 return "FDE is really a CIE"; // this is a CIE not an FDE
174 pint_t nextCFI = p + cfiLength;
175 pint_t cieStart = p-ciePointer;
176 const char* err = parseCIE(addressSpace, cieStart, cieInfo);
177 if (err != NULL)
178 return err;
179 p += 4;
180 // parse pc begin and range
181 pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
182 pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
183 // parse rest of info
184 fdeInfo->lsda = 0;
185 // check for augmentation length
186 if ( cieInfo->fdesHaveAugmentationData ) {
187 uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
188 pint_t endOfAug = p + augLen;
189 if ( cieInfo->lsdaEncoding != 0 ) {
190 // peek at value (without indirection). Zero means no lsda
191 pint_t lsdaStart = p;
192 if ( addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0 ) {
193 // reset pointer and re-parse lsda address
194 p = lsdaStart;
195 fdeInfo->lsda = addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
196 }
197 }
198 p = endOfAug;
199 }
200 fdeInfo->fdeStart = fdeStart;
201 fdeInfo->fdeLength = nextCFI - fdeStart;
202 fdeInfo->fdeInstructions = p;
203 fdeInfo->pcStart = pcStart;
204 fdeInfo->pcEnd = pcStart+pcRange;
205 return NULL; // success
206}
207
208
209///
210/// Scan an eh_frame section to find an FDE for a pc
211///
212template <typename A>
213bool CFI_Parser<A>::findFDE(A& addressSpace, pint_t pc, pint_t ehSectionStart, uint32_t sectionLength, pint_t fdeHint, FDE_Info* fdeInfo, CIE_Info* cieInfo)
214{
215 //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
216 pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
217 const pint_t ehSectionEnd = p + sectionLength;
218 while ( p < ehSectionEnd ) {
219 pint_t currentCFI = p;
220 //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
221 uint64_t cfiLength = addressSpace.get32(p);
222 p += 4;
223 if ( cfiLength == 0xffffffff ) {
224 // 0xffffffff means length is really next 8 bytes
225 cfiLength = addressSpace.get64(p);
226 p += 8;
227 }
228 if ( cfiLength == 0 )
229 return false; // end marker
230 uint32_t id = addressSpace.get32(p);
231 if ( id == 0 ) {
232 // skip over CIEs
233 p += cfiLength;
234 }
235 else {
236 // process FDE to see if it covers pc
237 pint_t nextCFI = p + cfiLength;
238 uint32_t ciePointer = addressSpace.get32(p);
239 pint_t cieStart = p-ciePointer;
240 // validate pointer to CIE is within section
241 if ( (ehSectionStart <= cieStart) && (cieStart < ehSectionEnd) ) {
242 if ( parseCIE(addressSpace, cieStart, cieInfo) == NULL ) {
243 p += 4;
244 // parse pc begin and range
245 pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
246 pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
247 //fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
248 // test if pc is within the function this FDE covers
249 if ( (pcStart < pc) && (pc <= pcStart+pcRange) ) {
250 // parse rest of info
251 fdeInfo->lsda = 0;
252 // check for augmentation length
253 if ( cieInfo->fdesHaveAugmentationData ) {
254 uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
255 pint_t endOfAug = p + augLen;
256 if ( cieInfo->lsdaEncoding != 0 ) {
257 // peek at value (without indirection). Zero means no lsda
258 pint_t lsdaStart = p;
259 if ( addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0 ) {
260 // reset pointer and re-parse lsda address
261 p = lsdaStart;
262 fdeInfo->lsda = addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
263 }
264 }
265 p = endOfAug;
266 }
267 fdeInfo->fdeStart = currentCFI;
268 fdeInfo->fdeLength = nextCFI - currentCFI;
269 fdeInfo->fdeInstructions = p;
270 fdeInfo->pcStart = pcStart;
271 fdeInfo->pcEnd = pcStart+pcRange;
272 //fprintf(stderr, "findFDE(pc=0x%llX) found with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pc, (uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
273 return true;
274 }
275 else {
276 //fprintf(stderr, "findFDE(pc=0x%llX) not found with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pc, (uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
277 // pc is not in begin/range, skip this FDE
278 }
279 }
280 else {
281 // malformed CIE, now augmentation describing pc range encoding
282 //fprintf(stderr, "malformed CIE\n");
283 }
284 }
285 else {
286 // malformed FDE. CIE is bad
287 //fprintf(stderr, "malformed FDE, cieStart=0x%llX, ehSectionStart=0x%llX, ehSectionEnd=0x%llX\n",
288 // (uint64_t)cieStart, (uint64_t)ehSectionStart, (uint64_t)ehSectionEnd);
289 }
290 p = nextCFI;
291 }
292 }
293 //fprintf(stderr, "findFDE(pc=0x%llX) not found\n",(uint64_t)pc);
294 return false;
295}
296
297
298
299///
300/// Extract info from a CIE
301///
302template <typename A>
303const char* CFI_Parser<A>::parseCIE(A& addressSpace, pint_t cie, CIE_Info* cieInfo)
304{
305 //fprintf(stderr, "parseCIE(0x%llX)\n", (long long)cie);
306 cieInfo->pointerEncoding = 0;
307 cieInfo->lsdaEncoding = 0;
308 cieInfo->personalityEncoding = 0;
309 cieInfo->personalityOffsetInCIE = 0;
310 cieInfo->personality = 0;
311 cieInfo->codeAlignFactor = 0;
312 cieInfo->dataAlignFactor = 0;
313 cieInfo->isSignalFrame = false;
314 cieInfo->fdesHaveAugmentationData = false;
315 cieInfo->cieStart = cie;
316 pint_t p = cie;
317 uint64_t cieLength = addressSpace.get32(p);
318 p += 4;
319 pint_t cieContentEnd = p + cieLength;
320 if ( cieLength == 0xffffffff ) {
321 // 0xffffffff means length is really next 8 bytes
322 cieLength = addressSpace.get64(p);
323 p += 8;
324 cieContentEnd = p + cieLength;
325 }
326 if ( cieLength == 0 )
327 return NULL;
328 // CIE ID is always 0
329 if ( addressSpace.get32(p) != 0 )
330 return "CIE ID is not zero";
331 p += 4;
332 // Version is always 1 or 3
333 uint8_t version = addressSpace.get8(p);
334 if ( (version != 1) && (version != 3) )
335 return "CIE version is not 1 or 3";
336 ++p;
337 // save start of augmentation string and find end
338 pint_t strStart = p;
339 while ( addressSpace.get8(p) != 0 )
340 ++p;
341 ++p;
342 // parse code aligment factor
343 cieInfo->codeAlignFactor = addressSpace.getULEB128(p, cieContentEnd);
344 // parse data alignment factor
345 cieInfo->dataAlignFactor = addressSpace.getSLEB128(p, cieContentEnd);
346 // parse return address register
347 addressSpace.getULEB128(p, cieContentEnd);
348 // parse augmentation data based on augmentation string
349 const char* result = NULL;
350 if ( addressSpace.get8(strStart) == 'z' ) {
351 // parse augmentation data length
352 addressSpace.getULEB128(p, cieContentEnd);
353 for (pint_t s=strStart; addressSpace.get8(s) != '\0'; ++s) {
354 switch ( addressSpace.get8(s) ) {
355 case 'z':
356 cieInfo->fdesHaveAugmentationData = true;
357 break;
358 case 'P':
359 cieInfo->personalityEncoding = addressSpace.get8(p);
360 ++p;
361 cieInfo->personalityOffsetInCIE = p-cie;
362 cieInfo->personality = addressSpace.getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
363 break;
364 case 'L':
365 cieInfo->lsdaEncoding = addressSpace.get8(p);
366 ++p;
367 break;
368 case 'R':
369 cieInfo->pointerEncoding = addressSpace.get8(p);
370 ++p;
371 break;
372 case 'S':
373 cieInfo->isSignalFrame = true;
374 break;
375 default:
376 // ignore unknown letters
377 break;
378 }
379 }
380 }
381 cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
382 cieInfo->cieInstructions = p;
383 return result;
384}
385
386
387template <typename A>
388uint32_t CFI_Parser<A>::getCFICount(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength)
389{
390 uint32_t count = 0;
391 const pint_t ehSectionEnd = ehSectionStart + sectionLength;
392 for (pint_t p=ehSectionStart; p < ehSectionEnd; ) {
393 uint64_t cfiLength = addressSpace.get32(p);
394 p += 4;
395 if ( cfiLength == 0xffffffff ) {
396 // 0xffffffff means length is really next 8 bytes
397 cfiLength = addressSpace.get64(p);
398 p += 8;
399 }
400 if ( cfiLength == 0 )
401 return count; // end marker
402 ++count;
403 p += cfiLength;
404 }
405 return count;
406}
407
408
409
410template <typename A>
411const char* CFI_Parser<A>::getCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength,
412 std::vector<FDE_Atom_Info>& fdes, std::vector<CIE_Atom_Info>& cies)
413{
414 const pint_t ehSectionEnd = ehSectionStart + sectionLength;
415 for (pint_t p=ehSectionStart; p < ehSectionEnd; ) {
416 pint_t currentCFI = p;
417 uint64_t cfiLength = addressSpace.get32(p);
418 p += 4;
419 if ( cfiLength == 0xffffffff ) {
420 // 0xffffffff means length is really next 8 bytes
421 cfiLength = addressSpace.get64(p);
422 p += 8;
423 }
424 if ( cfiLength == 0 )
425 return NULL; // end marker
426 uint32_t id = addressSpace.get32(p);
427 if ( id == 0 ) {
428 // is CIE
429 CIE_Info cieInfo;
430 const char* err = parseCIE(addressSpace, currentCFI, &cieInfo);
431 if ( err != NULL )
432 return err;
433 CIE_Atom_Info entry;
434 entry.cieAddress = currentCFI;
435 entry.personality.address = cieInfo.personality;
436 entry.personality.offsetInFDE = cieInfo.personalityOffsetInCIE;
437 entry.personality.encodingOfAddress = cieInfo.personalityEncoding;
438 cies.push_back(entry);
439 p += cfiLength;
440 }
441 else {
442 // is FDE
443 FDE_Atom_Info entry;
444 entry.fdeAddress = currentCFI;
445 entry.function.address = 0;
446 entry.cie.address = 0;
447 entry.lsda.address = 0;
448 pint_t nextCFI = p + cfiLength;
449 uint32_t ciePointer = addressSpace.get32(p);
450 pint_t cieStart = p-ciePointer;
451 // validate pointer to CIE is within section
452 if ( (cieStart < ehSectionStart) || (cieStart > ehSectionEnd) )
453 return "FDE points to CIE outside __eh_frame section";
454 CIE_Info cieInfo;
455 const char* err = parseCIE(addressSpace, cieStart, &cieInfo);
456 if ( err != NULL )
457 return err;
458 entry.cie.address = cieStart;
459 entry.cie.offsetInFDE = p-currentCFI;
460 entry.cie.encodingOfAddress = DW_EH_PE_sdata4 | DW_EH_PE_pcrel;
461 p += 4;
462 // parse pc begin and range
463 pint_t offsetOfFunctionAddress = p-currentCFI;
464 pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding);
465 pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding & 0x0F);
466 //fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
467 // test if pc is within the function this FDE covers
468 entry.function.address = pcStart;
469 entry.function.offsetInFDE = offsetOfFunctionAddress;
470 entry.function.encodingOfAddress = cieInfo.pointerEncoding;
471 // skip over augmentation length
472 if ( cieInfo.fdesHaveAugmentationData ) {
473 uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
474 pint_t endOfAug = p + augLen;
475 if ( (cieInfo.lsdaEncoding != 0) && (addressSpace.getP(p) != 0) ) {
476 pint_t offsetOfLSDAAddress = p-currentCFI;
477 entry.lsda.address = addressSpace.getEncodedP(p, nextCFI, cieInfo.lsdaEncoding);
478 entry.lsda.offsetInFDE = offsetOfLSDAAddress;
479 entry.lsda.encodingOfAddress = cieInfo.lsdaEncoding;
480 }
481 p = endOfAug;
482 }
483 fdes.push_back(entry);
484 p = nextCFI;
485 }
486 }
487 return NULL; // success
488}
489
490
491
492///
493/// "run" the dwarf instructions and create the abstact PrologInfo for an FDE
494///
495template <typename A>
496bool CFI_Parser<A>::parseFDEInstructions(A& addressSpace, const FDE_Info& fdeInfo, const CIE_Info& cieInfo, pint_t upToPC, PrologInfo* results)
497{
498 // clear results
499 bzero(results, sizeof(PrologInfo));
500 PrologInfoStackEntry* rememberStack = NULL;
501
502 // parse CIE then FDE instructions
503 return parseInstructions(addressSpace, cieInfo.cieInstructions, cieInfo.cieStart+cieInfo.cieLength,
504 cieInfo, (pint_t)(-1), rememberStack, results)
505 && parseInstructions(addressSpace, fdeInfo.fdeInstructions, fdeInfo.fdeStart+fdeInfo.fdeLength,
506 cieInfo, upToPC-fdeInfo.pcStart, rememberStack, results);
507}
508
509
510///
511/// "run" the dwarf instructions
512///
513template <typename A>
514bool CFI_Parser<A>::parseInstructions(A& addressSpace, pint_t instructions, pint_t instructionsEnd, const CIE_Info& cieInfo,
515 pint_t pcoffset, PrologInfoStackEntry*& rememberStack, PrologInfo* results)
516{
517 const bool logDwarf = false;
518 pint_t p = instructions;
519 uint32_t codeOffset = 0;
520 PrologInfo initialState = *results;
521 if ( logDwarf ) fprintf(stderr, "parseInstructions(instructions=0x%0llX)\n", (uint64_t)instructionsEnd);
522
523 // see Dwarf Spec, section 6.4.2 for details on unwind opcodes
524 while ( (p < instructionsEnd) && (codeOffset < pcoffset) ) {
525 uint64_t reg;
526 uint64_t reg2;
527 int64_t offset;
528 uint64_t length;
529 uint8_t opcode = addressSpace.get8(p);
530 uint8_t operand;
531 PrologInfoStackEntry* entry;
532 ++p;
533 switch (opcode) {
534 case DW_CFA_nop:
535 if ( logDwarf ) fprintf(stderr, "DW_CFA_nop\n");
536 break;
537 case DW_CFA_set_loc:
538 codeOffset = addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
539 if ( logDwarf ) fprintf(stderr, "DW_CFA_set_loc\n");
540 break;
541 case DW_CFA_advance_loc1:
542 codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
543 p += 1;
544 if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc1: new offset=%u\n", codeOffset);
545 break;
546 case DW_CFA_advance_loc2:
547 codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
548 p += 2;
549 if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc2: new offset=%u\n", codeOffset);
550 break;
551 case DW_CFA_advance_loc4:
552 codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
553 p += 4;
554 if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc4: new offset=%u\n", codeOffset);
555 break;
556 case DW_CFA_offset_extended:
557 reg = addressSpace.getULEB128(p, instructionsEnd);
558 offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
559 if ( reg > kMaxRegisterNumber ) {
560 fprintf(stderr, "malformed DW_CFA_offset_extended dwarf unwind, reg too big\n");
561 return false;
562 }
563 if ( results->savedRegisters[reg].location != kRegisterUnused )
564 results->registerSavedMoreThanOnce = true;
565 results->savedRegisters[reg].location = kRegisterInCFA;
566 results->savedRegisters[reg].value = offset;
567 if ( logDwarf ) fprintf(stderr, "DW_CFA_offset_extended(reg=%lld, offset=%lld)\n", reg, offset);
568 break;
569 case DW_CFA_restore_extended:
570 reg = addressSpace.getULEB128(p, instructionsEnd);;
571 if ( reg > kMaxRegisterNumber ) {
572 fprintf(stderr, "malformed DW_CFA_restore_extended dwarf unwind, reg too big\n");
573 return false;
574 }
575 results->savedRegisters[reg] = initialState.savedRegisters[reg];
576 if ( logDwarf ) fprintf(stderr, "DW_CFA_restore_extended(reg=%lld)\n", reg);
577 break;
578 case DW_CFA_undefined:
579 reg = addressSpace.getULEB128(p, instructionsEnd);
580 if ( reg > kMaxRegisterNumber ) {
581 fprintf(stderr, "malformed DW_CFA_undefined dwarf unwind, reg too big\n");
582 return false;
583 }
584 results->savedRegisters[reg].location = kRegisterUnused;
585 if ( logDwarf ) fprintf(stderr, "DW_CFA_undefined(reg=%lld)\n", reg);
586 break;
587 case DW_CFA_same_value:
588 reg = addressSpace.getULEB128(p, instructionsEnd);
589 if ( reg > kMaxRegisterNumber ) {
590 fprintf(stderr, "malformed DW_CFA_same_value dwarf unwind, reg too big\n");
591 return false;
592 }
593 // <rdar://problem/8456377> DW_CFA_same_value unsupported
594 // "same value" means register was stored in frame, but its current
595 // value has not changed, so no need to restore from frame.
596 // We model this as if the register was never saved.
597 results->savedRegisters[reg].location = kRegisterUnused;
598 // set flag to disable conversion to compact unwind
599 results->sameValueUsed = true;
600 if ( logDwarf ) fprintf(stderr, "DW_CFA_same_value(reg=%lld)\n", reg);
601 break;
602 case DW_CFA_register:
603 reg = addressSpace.getULEB128(p, instructionsEnd);
604 reg2 = addressSpace.getULEB128(p, instructionsEnd);
605 if ( reg > kMaxRegisterNumber ) {
606 fprintf(stderr, "malformed DW_CFA_register dwarf unwind, reg too big\n");
607 return false;
608 }
609 if ( reg2 > kMaxRegisterNumber ) {
610 fprintf(stderr, "malformed DW_CFA_register dwarf unwind, reg2 too big\n");
611 return false;
612 }
613 results->savedRegisters[reg].location = kRegisterInRegister;
614 results->savedRegisters[reg].value = reg2;
615 // set flag to disable conversion to compact unwind
616 results->registersInOtherRegisters = true;
617 if ( logDwarf ) fprintf(stderr, "DW_CFA_register(reg=%lld, reg2=%lld)\n", reg, reg2);
618 break;
619 case DW_CFA_remember_state:
620 // avoid operator new, because that would be an upward dependency
621 entry = (PrologInfoStackEntry*)malloc(sizeof(PrologInfoStackEntry));
622 if ( entry != NULL ) {
623 entry->next = rememberStack;
624 entry->info = *results;
625 rememberStack = entry;
626 }
627 else {
628 return false;
629 }
630 if ( logDwarf ) fprintf(stderr, "DW_CFA_remember_state\n");
631 break;
632 case DW_CFA_restore_state:
633 if ( rememberStack != NULL ) {
634 PrologInfoStackEntry* top = rememberStack;
635 *results = top->info;
636 rememberStack = top->next;
637 free((char*)top);
638 }
639 else {
640 return false;
641 }
642 if ( logDwarf ) fprintf(stderr, "DW_CFA_restore_state\n");
643 break;
644 case DW_CFA_def_cfa:
645 reg = addressSpace.getULEB128(p, instructionsEnd);
646 offset = addressSpace.getULEB128(p, instructionsEnd);
647 if ( reg > kMaxRegisterNumber ) {
648 fprintf(stderr, "malformed DW_CFA_def_cfa dwarf unwind, reg too big\n");
649 return false;
650 }
651 results->cfaRegister = reg;
652 results->cfaRegisterOffset = offset;
653 if ( offset > 0x80000000 )
654 results->cfaOffsetWasNegative = true;
655 if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa(reg=%lld, offset=%lld)\n", reg, offset);
656 break;
657 case DW_CFA_def_cfa_register:
658 reg = addressSpace.getULEB128(p, instructionsEnd);
659 if ( reg > kMaxRegisterNumber ) {
660 fprintf(stderr, "malformed DW_CFA_def_cfa_register dwarf unwind, reg too big\n");
661 return false;
662 }
663 results->cfaRegister = reg;
664 if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_register(%lld)\n", reg);
665 break;
666 case DW_CFA_def_cfa_offset:
667 results->cfaRegisterOffset = addressSpace.getULEB128(p, instructionsEnd);
668 results->codeOffsetAtStackDecrement = codeOffset;
669 if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_offset(%d)\n", results->cfaRegisterOffset);
670 break;
671 case DW_CFA_def_cfa_expression:
672 results->cfaRegister = 0;
673 results->cfaExpression = p;
674 length = addressSpace.getULEB128(p, instructionsEnd);
675 p += length;
676 if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_expression(expression=0x%llX, length=%llu)\n",
677 results->cfaExpression, length);
678 break;
679 case DW_CFA_expression:
680 reg = addressSpace.getULEB128(p, instructionsEnd);
681 if ( reg > kMaxRegisterNumber ) {
682 fprintf(stderr, "malformed DW_CFA_expression dwarf unwind, reg too big\n");
683 return false;
684 }
685 results->savedRegisters[reg].location = kRegisterAtExpression;
686 results->savedRegisters[reg].value = p;
687 length = addressSpace.getULEB128(p, instructionsEnd);
688 p += length;
689 if ( logDwarf ) fprintf(stderr, "DW_CFA_expression(reg=%lld, expression=0x%llX, length=%llu)\n",
690 reg, results->savedRegisters[reg].value, length);
691 break;
692 case DW_CFA_offset_extended_sf:
693 reg = addressSpace.getULEB128(p, instructionsEnd);
694 if ( reg > kMaxRegisterNumber ) {
695 fprintf(stderr, "malformed DW_CFA_offset_extended_sf dwarf unwind, reg too big\n");
696 return false;
697 }
698 offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
699 if ( results->savedRegisters[reg].location != kRegisterUnused )
700 results->registerSavedMoreThanOnce = true;
701 results->savedRegisters[reg].location = kRegisterInCFA;
702 results->savedRegisters[reg].value = offset;
703 if ( logDwarf ) fprintf(stderr, "DW_CFA_offset_extended_sf(reg=%lld, offset=%lld)\n", reg, offset);
704 break;
705 case DW_CFA_def_cfa_sf:
706 reg = addressSpace.getULEB128(p, instructionsEnd);
707 offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
708 if ( reg > kMaxRegisterNumber ) {
709 fprintf(stderr, "malformed DW_CFA_def_cfa_sf dwarf unwind, reg too big\n");
710 return false;
711 }
712 results->cfaRegister = reg;
713 results->cfaRegisterOffset = offset;
714 if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_sf(reg=%lld, offset=%lld)\n", reg, offset);
715 break;
716 case DW_CFA_def_cfa_offset_sf:
717 results->cfaRegisterOffset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
718 results->codeOffsetAtStackDecrement = codeOffset;
719 if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_offset_sf(%d)\n", results->cfaRegisterOffset);
720 break;
721 case DW_CFA_val_offset:
722 reg = addressSpace.getULEB128(p, instructionsEnd);
723 offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
724 results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
725 results->savedRegisters[reg].value = offset;
726 if ( logDwarf ) fprintf(stderr, "DW_CFA_val_offset(reg=%lld, offset=%lld\n", reg, offset);
727 break;
728 case DW_CFA_val_offset_sf:
729 reg = addressSpace.getULEB128(p, instructionsEnd);
730 if ( reg > kMaxRegisterNumber ) {
731 fprintf(stderr, "malformed DW_CFA_val_offset_sf dwarf unwind, reg too big\n");
732 return false;
733 }
734 offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
735 results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
736 results->savedRegisters[reg].value = offset;
737 if ( logDwarf ) fprintf(stderr, "DW_CFA_val_offset_sf(reg=%lld, offset=%lld\n", reg, offset);
738 break;
739 case DW_CFA_val_expression:
740 reg = addressSpace.getULEB128(p, instructionsEnd);
741 if ( reg > kMaxRegisterNumber ) {
742 fprintf(stderr, "malformed DW_CFA_val_expression dwarf unwind, reg too big\n");
743 return false;
744 }
745 results->savedRegisters[reg].location = kRegisterIsExpression;
746 results->savedRegisters[reg].value = p;
747 length = addressSpace.getULEB128(p, instructionsEnd);
748 p += length;
749 if ( logDwarf ) fprintf(stderr, "DW_CFA_val_expression(reg=%lld, expression=0x%llX, length=%lld)\n",
750 reg, results->savedRegisters[reg].value, length);
751 break;
752 case DW_CFA_GNU_args_size:
753 offset = addressSpace.getULEB128(p, instructionsEnd);
754 results->spExtraArgSize = offset;
755 if ( logDwarf ) fprintf(stderr, "DW_CFA_GNU_args_size(%lld)\n", offset);
756 break;
757 case DW_CFA_GNU_negative_offset_extended:
758 reg = addressSpace.getULEB128(p, instructionsEnd);
759 if ( reg > kMaxRegisterNumber ) {
760 fprintf(stderr, "malformed DW_CFA_GNU_negative_offset_extended dwarf unwind, reg too big\n");
761 return false;
762 }
763 offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
764 if ( results->savedRegisters[reg].location != kRegisterUnused )
765 results->registerSavedMoreThanOnce = true;
766 results->savedRegisters[reg].location = kRegisterInCFA;
767 results->savedRegisters[reg].value = -offset;
768 if ( logDwarf ) fprintf(stderr, "DW_CFA_GNU_negative_offset_extended(%lld)\n", offset);
769 break;
770 default:
771 operand = opcode & 0x3F;
772 switch ( opcode & 0xC0 ) {
773 case DW_CFA_offset:
774 reg = operand;
775 offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
776 if ( results->savedRegisters[reg].location != kRegisterUnused ) {
777 // look for idiom of PC saved twice in CIE to mean disable compact unwind encoding
778 if ( (pcoffset == (pint_t)(-1))
779 && (results->savedRegisters[reg].location == kRegisterInCFA)
780 && (results->savedRegisters[reg].value == offset) )
781 results->registerSavedTwiceInCIE = reg;
782 else
783 results->registerSavedMoreThanOnce = true;
784 }
785 results->savedRegisters[reg].location = kRegisterInCFA;
786 results->savedRegisters[reg].value = offset;
787 if ( logDwarf ) fprintf(stderr, "DW_CFA_offset(reg=%d, offset=%lld)\n", operand, offset);
788 break;
789 case DW_CFA_advance_loc:
790 codeOffset += operand * cieInfo.codeAlignFactor;
791 if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc: new offset=%u\n", codeOffset);
792 break;
793 case DW_CFA_restore:
794 // <rdar://problem/7503075> Python crashes when handling an exception thrown by an obj-c object
795 // libffi uses DW_CFA_restore in the middle of some custom dwarf, so it is not a good epilog flag
796 //return true; // gcc-4.5 starts the epilog with this
797 reg = operand;
798 results->savedRegisters[reg] = initialState.savedRegisters[reg];
799 if ( logDwarf ) fprintf(stderr, "DW_CFA_restore(reg=%lld)\n", reg);
800 break;
801 default:
802 if ( logDwarf ) fprintf(stderr, "unknown CFA opcode 0x%02X\n", opcode);
803 return false;
804 }
805 }
806 }
807
808 return true;
809}
810
811
812} // namespace libunwind
813
814
815#endif // __DWARF_PARSER_HPP__
816
817
818
819