1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2008-2010 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
820