1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2007-2009 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//	C++ interface to lower levels of libuwind
27//
28
29#ifndef __UNWINDCURSOR_HPP__
30#define __UNWINDCURSOR_HPP__
31
32#include <stdint.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <pthread.h>
36#include <Availability.h>
37
38#include "libunwind.h"
39
40#include "AddressSpace.hpp"
41#include "Registers.hpp"
42#include "DwarfInstructions.hpp"
43#include "CompactUnwinder.hpp"
44#include "InternalMacros.h"
45
46#if __MAC_OS_X_VERSION_MIN_REQUIRED
47  #define KEYMGR_SUPPPORT 1
48#else
49  #define KEYMGR_SUPPPORT 0
50#endif
51
52
53#if KEYMGR_SUPPPORT
54// private keymgr stuff
55#define KEYMGR_GCC3_DW2_OBJ_LIST   302
56extern "C" {
57	extern void	 _keymgr_set_and_unlock_processwide_ptr(int key, void* ptr);
58	extern void* _keymgr_get_and_lock_processwide_ptr(int key);
59};
60
61// undocumented libgcc "struct object"
62struct libgcc_object
63{
64	void*			start;
65	void*			unused1;
66	void*			unused2;
67	void*			fde;
68	unsigned long	encoding;
69	void*			fde_end;
70	libgcc_object*	next;
71};
72
73// undocumented libgcc "struct km_object_info" referenced by KEYMGR_GCC3_DW2_OBJ_LIST
74struct libgcc_object_info {
75  struct libgcc_object*		seen_objects;
76  struct libgcc_object*		unseen_objects;
77  unsigned					spare[2];
78};
79#endif // KEYMGR_SUPPPORT
80
81
82
83namespace libunwind {
84
85#if !FOR_DYLD
86template <typename A>
87class DwarfFDECache
88{
89public:
90	typedef typename A::pint_t	pint_t;
91	static pint_t					findFDE(pint_t mh, pint_t pc);
92	static void						add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde);
93	static void						removeAllIn(pint_t mh);
94	static void						iterateCacheEntries(void (*func)(unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh));
95private:
96	static void						dyldUnloadHook(const struct mach_header* mh, intptr_t vmaddr_slide);
97
98	struct entry { pint_t mh; pint_t ip_start; pint_t ip_end; pint_t fde; };
99
100	// these fields are all static to avoid needing an initializer
101	// there is only one instance of this class per process
102	static pthread_rwlock_t			fgLock;
103	static bool						fgRegisteredForDyldUnloads;
104	// can't use std::vector<> here because this code must live in libSystem.dylib (which is below libstdc++.dylib)
105	static entry*					fgBuffer;
106	static entry*					fgBufferUsed;
107	static entry*					fgBufferEnd;
108	static entry					fgInitialBuffer[64];
109};
110
111template <typename A> typename DwarfFDECache<A>::entry* DwarfFDECache<A>::fgBuffer		= fgInitialBuffer;
112template <typename A> typename DwarfFDECache<A>::entry* DwarfFDECache<A>::fgBufferUsed	= fgInitialBuffer;
113template <typename A> typename DwarfFDECache<A>::entry* DwarfFDECache<A>::fgBufferEnd	= &fgInitialBuffer[64];
114template <typename A> typename DwarfFDECache<A>::entry  DwarfFDECache<A>::fgInitialBuffer[64];
115
116template <typename A>
117pthread_rwlock_t DwarfFDECache<A>::fgLock = PTHREAD_RWLOCK_INITIALIZER;
118
119template <typename A>
120bool DwarfFDECache<A>::fgRegisteredForDyldUnloads = false;
121
122
123template <typename A>
124typename A::pint_t DwarfFDECache<A>::findFDE(pint_t mh, pint_t pc)
125{
126	pint_t result = NULL;
127	DEBUG_LOG_NON_ZERO(::pthread_rwlock_rdlock(&fgLock));
128	for(entry* p=fgBuffer; p < fgBufferUsed; ++p) {
129		if ( (mh == p->mh) || (mh == 0) ) {
130			if ( (p->ip_start <= pc) && (pc < p->ip_end) ) {
131				result = p->fde;
132				break;
133			}
134		}
135	}
136	DEBUG_LOG_NON_ZERO(::pthread_rwlock_unlock(&fgLock));
137	//fprintf(stderr, "DwarfFDECache::findFDE(mh=0x%llX, pc=0x%llX) => 0x%llX\n", (uint64_t)mh, (uint64_t)pc, (uint64_t)result);
138	return result;
139}
140
141template <typename A>
142void DwarfFDECache<A>::add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde)
143{
144	//fprintf(stderr, "DwarfFDECache::add(mh=0x%llX, ip_start=0x%llX, ip_end=0x%llX, fde=0x%llX) pthread=%p\n",
145	//		(uint64_t)mh, (uint64_t)ip_start, (uint64_t)ip_end, (uint64_t)fde, pthread_self());
146	DEBUG_LOG_NON_ZERO(::pthread_rwlock_wrlock(&fgLock));
147	if ( fgBufferUsed >= fgBufferEnd ) {
148		int oldSize = fgBufferEnd - fgBuffer;
149		int newSize = oldSize*4;
150		entry* newBuffer = (entry*)malloc(newSize*sizeof(entry));	// can't use operator new in libSystem.dylib
151		memcpy(newBuffer, fgBuffer, oldSize*sizeof(entry));
152		//fprintf(stderr, "DwarfFDECache::add() growing buffer to %d\n",  newSize);
153		if ( fgBuffer != fgInitialBuffer )
154			free(fgBuffer);
155		fgBuffer = newBuffer;
156		fgBufferUsed = &newBuffer[oldSize];
157		fgBufferEnd = &newBuffer[newSize];
158	}
159	fgBufferUsed->mh = mh;
160	fgBufferUsed->ip_start = ip_start;
161	fgBufferUsed->ip_end = ip_end;
162	fgBufferUsed->fde = fde;
163	++fgBufferUsed;
164	if ( !fgRegisteredForDyldUnloads ) {
165		_dyld_register_func_for_remove_image(&dyldUnloadHook);
166		fgRegisteredForDyldUnloads = true;
167	}
168	DEBUG_LOG_NON_ZERO(::pthread_rwlock_unlock(&fgLock));
169}
170
171
172
173template <typename A>
174void DwarfFDECache<A>::removeAllIn(pint_t mh)
175{
176	DEBUG_LOG_NON_ZERO(::pthread_rwlock_wrlock(&fgLock));
177	entry* d=fgBuffer;
178	for(const entry* s=fgBuffer; s < fgBufferUsed; ++s) {
179		if ( s->mh != mh ) {
180			if ( d != s )
181				*d = *s;
182			++d;
183		}
184	}
185	fgBufferUsed = d;
186	DEBUG_LOG_NON_ZERO(::pthread_rwlock_unlock(&fgLock));
187}
188
189
190template <typename A>
191void DwarfFDECache<A>::dyldUnloadHook(const struct mach_header* mh, intptr_t vmaddr_slide)
192{
193	removeAllIn((pint_t)mh);
194}
195
196template <typename A>
197void DwarfFDECache<A>::iterateCacheEntries(void (*func)(unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh))
198{
199	DEBUG_LOG_NON_ZERO(::pthread_rwlock_wrlock(&fgLock));
200	for(entry* p=fgBuffer; p < fgBufferUsed; ++p) {
201		(*func)(p->ip_start, p->ip_end, p->fde, p->mh);
202	}
203	DEBUG_LOG_NON_ZERO(::pthread_rwlock_unlock(&fgLock));
204}
205#endif // !FOR_DYLD
206
207
208
209
210#define arrayoffsetof(type, index, field) ((size_t)(&((type *)0)[index].field))
211
212template <typename A>
213class UnwindSectionHeader {
214public:
215					UnwindSectionHeader(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {}
216
217	uint32_t		version() const								INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, version)); }
218	uint32_t		commonEncodingsArraySectionOffset() const	INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, commonEncodingsArraySectionOffset)); }
219	uint32_t		commonEncodingsArrayCount() const			INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, commonEncodingsArrayCount)); }
220	uint32_t		personalityArraySectionOffset() const		INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, personalityArraySectionOffset)); }
221	uint32_t		personalityArrayCount() const				INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, personalityArrayCount)); }
222	uint32_t		indexSectionOffset() const					INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, indexSectionOffset)); }
223	uint32_t		indexCount() const							INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, indexCount)); }
224private:
225	A&						fAddressSpace;
226	typename A::pint_t		fAddr;
227};
228
229template <typename A>
230class UnwindSectionIndexArray {
231public:
232					UnwindSectionIndexArray(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {}
233
234	uint32_t		functionOffset(int index) const					INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_index_entry, index, functionOffset)); }
235	uint32_t		secondLevelPagesSectionOffset(int index) const	INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_index_entry, index, secondLevelPagesSectionOffset)); }
236	uint32_t		lsdaIndexArraySectionOffset(int index) const	INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_index_entry, index, lsdaIndexArraySectionOffset)); }
237private:
238	A&						fAddressSpace;
239	typename A::pint_t		fAddr;
240};
241
242
243template <typename A>
244class UnwindSectionRegularPageHeader {
245public:
246					UnwindSectionRegularPageHeader(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {}
247
248	uint32_t		kind() const				INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_regular_second_level_page_header, kind)); }
249	uint16_t		entryPageOffset() const		INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_regular_second_level_page_header, entryPageOffset)); }
250	uint16_t		entryCount() const			INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_regular_second_level_page_header, entryCount)); }
251private:
252	A&						fAddressSpace;
253	typename A::pint_t		fAddr;
254};
255
256
257template <typename A>
258class UnwindSectionRegularArray {
259public:
260					UnwindSectionRegularArray(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {}
261
262	uint32_t		functionOffset(int index) const		INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_regular_second_level_entry, index, functionOffset)); }
263	uint32_t		encoding(int index) const			INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_regular_second_level_entry, index, encoding)); }
264private:
265	A&						fAddressSpace;
266	typename A::pint_t		fAddr;
267};
268
269
270template <typename A>
271class UnwindSectionCompressedPageHeader {
272public:
273					UnwindSectionCompressedPageHeader(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {}
274
275	uint32_t		kind() const				INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_compressed_second_level_page_header, kind)); }
276	uint16_t		entryPageOffset() const		INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_compressed_second_level_page_header, entryPageOffset)); }
277	uint16_t		entryCount() const			INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_compressed_second_level_page_header, entryCount)); }
278	uint16_t		encodingsPageOffset() const	INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_compressed_second_level_page_header, encodingsPageOffset)); }
279	uint16_t		encodingsCount() const		INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_compressed_second_level_page_header, encodingsCount)); }
280private:
281	A&						fAddressSpace;
282	typename A::pint_t		fAddr;
283};
284
285
286template <typename A>
287class UnwindSectionCompressedArray {
288public:
289					UnwindSectionCompressedArray(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {}
290
291	uint32_t		functionOffset(int index) const		INLINE { return UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET( fAddressSpace.get32(fAddr + index*sizeof(uint32_t)) ); }
292	uint16_t		encodingIndex(int index) const		INLINE { return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX( fAddressSpace.get32(fAddr + index*sizeof(uint32_t)) ); }
293private:
294	A&						fAddressSpace;
295	typename A::pint_t		fAddr;
296};
297
298
299template <typename A>
300class UnwindSectionLsdaArray {
301public:
302					UnwindSectionLsdaArray(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {}
303
304	uint32_t		functionOffset(int index) const		INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_lsda_index_entry, index, functionOffset)); }
305	int32_t			lsdaOffset(int index) const			INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_lsda_index_entry, index, lsdaOffset)); }
306private:
307	A&						fAddressSpace;
308	typename A::pint_t		fAddr;
309};
310
311
312template <typename A, typename R>
313class UnwindCursor
314{
315public:
316						UnwindCursor(unw_context_t* context, A& as);
317						UnwindCursor(A& as, thread_t thread);
318	virtual				~UnwindCursor() {}
319	virtual bool		validReg(int);
320	virtual uint64_t	getReg(int);
321	virtual void		setReg(int, uint64_t);
322	virtual bool		validFloatReg(int);
323	virtual double		getFloatReg(int);
324	virtual void		setFloatReg(int, double);
325	virtual int			step();
326	virtual void		getInfo(unw_proc_info_t*);
327	virtual void		jumpto();
328	virtual const char*	getRegisterName(int num);
329	virtual bool		isSignalFrame();
330	virtual bool		getFunctionName(char* buf, size_t bufLen, unw_word_t* offset);
331	virtual void		setInfoBasedOnIPRegister(bool isReturnAddress=false);
332
333	void				operator delete(void* p, size_t size) {}
334
335private:
336	typedef typename A::pint_t		pint_t;
337	typedef uint32_t				EncodedUnwindInfo;
338
339	bool				getInfoFromCompactEncodingSection(pint_t pc, pint_t mh, pint_t unwindSectionStart);
340	bool				getInfoFromDwarfSection(pint_t pc, pint_t mh, pint_t ehSectionStart, uint32_t sectionLength, uint32_t sectionOffsetOfFDE);
341
342	int					stepWithDwarfFDE()
343							{ return DwarfInstructions<A,R>::stepWithDwarf(fAddressSpace, this->getReg(UNW_REG_IP), fInfo.unwind_info, fRegisters); }
344
345	int					stepWithCompactEncoding() { R dummy; return stepWithCompactEncoding(dummy); }
346	int					stepWithCompactEncoding(Registers_x86_64&)
347							{ return CompactUnwinder_x86_64<A>::stepWithCompactEncoding(fInfo.format, fInfo.start_ip, fAddressSpace, fRegisters); }
348	int					stepWithCompactEncoding(Registers_x86&)
349							{ return CompactUnwinder_x86<A>::stepWithCompactEncoding(fInfo.format, fInfo.start_ip, fAddressSpace, fRegisters); }
350	int					stepWithCompactEncoding(Registers_ppc&)
351							{ return UNW_EINVAL; }
352
353#if FOR_DYLD
354  #if __ppc__
355	bool				mustUseDwarf() const { return true; }
356  #else
357	bool				mustUseDwarf() const { return false; }
358  #endif
359#else
360	bool				mustUseDwarf() const { R dummy; uint32_t offset; return dwarfWithOffset(dummy, offset); }
361#endif
362
363	bool				dwarfWithOffset(uint32_t& offset) const { R dummy; return dwarfWithOffset(dummy, offset); }
364	bool				dwarfWithOffset(Registers_x86_64&, uint32_t& offset) const {
365							if ( (fInfo.format & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF ) {
366								offset = (fInfo.format & UNWIND_X86_64_DWARF_SECTION_OFFSET);
367								return true;
368							}
369#if SUPPORT_OLD_BINARIES
370							if ( (fInfo.format & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_COMPATIBILITY ) {
371								if ( (fInfo.format & UNWIND_X86_64_CASE_MASK) == UNWIND_X86_64_UNWIND_REQUIRES_DWARF ) {
372									offset = 0;
373									return true;
374								}
375							}
376#endif
377							return false;
378						}
379	bool				dwarfWithOffset(Registers_x86&, uint32_t& offset) const {
380							if ( (fInfo.format & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF ) {
381								offset = (fInfo.format & UNWIND_X86_DWARF_SECTION_OFFSET);
382								return true;
383							}
384#if SUPPORT_OLD_BINARIES
385							if ( (fInfo.format & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_COMPATIBILITY ) {
386								if ( (fInfo.format & UNWIND_X86_CASE_MASK) == UNWIND_X86_UNWIND_REQUIRES_DWARF ) {
387									offset = 0;
388									return true;
389								}
390							}
391#endif
392							return false;
393						}
394	bool				dwarfWithOffset(Registers_ppc&, uint32_t& offset) const { return true; }
395
396
397	compact_unwind_encoding_t		dwarfEncoding() const { R dummy; return dwarfEncoding(dummy); }
398	compact_unwind_encoding_t		dwarfEncoding(Registers_x86_64&) const { return UNWIND_X86_64_MODE_DWARF; }
399	compact_unwind_encoding_t		dwarfEncoding(Registers_x86&)	const { return UNWIND_X86_MODE_DWARF; }
400	compact_unwind_encoding_t		dwarfEncoding(Registers_ppc&)	const { return 0; }
401
402	unw_proc_info_t				fInfo;
403	R							fRegisters;
404	A&							fAddressSpace;
405	bool						fUnwindInfoMissing;
406	bool						fIsSignalFrame;
407};
408
409typedef UnwindCursor<LocalAddressSpace,Registers_x86> AbstractUnwindCursor;
410
411template <typename A, typename R>
412UnwindCursor<A,R>::UnwindCursor(unw_context_t* context, A& as)
413  : fRegisters(context), fAddressSpace(as), fUnwindInfoMissing(false), fIsSignalFrame(false)
414{
415	COMPILE_TIME_ASSERT( sizeof(UnwindCursor<A,R>) < sizeof(unw_cursor_t) );
416
417	bzero(&fInfo, sizeof(fInfo));
418}
419
420template <typename A, typename R>
421UnwindCursor<A,R>::UnwindCursor(A& as, thread_t thread)
422  : fAddressSpace(as), fUnwindInfoMissing(false), fIsSignalFrame(false)
423{
424	bzero(&fInfo, sizeof(fInfo));
425	// FIXME
426	// fill in fRegisters from thread
427}
428
429template <typename A, typename R>
430bool UnwindCursor<A,R>::validReg(int regNum)
431{
432	return fRegisters.validRegister(regNum);
433}
434
435template <typename A, typename R>
436uint64_t UnwindCursor<A,R>::getReg(int regNum)
437{
438	return fRegisters.getRegister(regNum);
439}
440
441template <typename A, typename R>
442void UnwindCursor<A,R>::setReg(int regNum, uint64_t value)
443{
444	fRegisters.setRegister(regNum, value);
445}
446
447template <typename A, typename R>
448bool UnwindCursor<A,R>::validFloatReg(int regNum)
449{
450	return fRegisters.validFloatRegister(regNum);
451}
452
453template <typename A, typename R>
454double UnwindCursor<A,R>::getFloatReg(int regNum)
455{
456	return fRegisters.getFloatRegister(regNum);
457}
458
459template <typename A, typename R>
460void UnwindCursor<A,R>::setFloatReg(int regNum, double value)
461{
462	fRegisters.setFloatRegister(regNum, value);
463}
464
465template <typename A, typename R>
466void UnwindCursor<A,R>::jumpto()
467{
468	fRegisters.jumpto();
469}
470
471template <typename A, typename R>
472const char* UnwindCursor<A,R>::getRegisterName(int regNum)
473{
474	return fRegisters.getRegisterName(regNum);
475}
476
477template <typename A, typename R>
478bool UnwindCursor<A,R>::isSignalFrame()
479{
480	 return fIsSignalFrame;
481}
482
483
484template <typename A, typename R>
485bool UnwindCursor<A,R>::getInfoFromDwarfSection(pint_t pc, pint_t mh, pint_t ehSectionStart, uint32_t sectionLength, uint32_t sectionOffsetOfFDE)
486{
487	typename CFI_Parser<A>::FDE_Info fdeInfo;
488	typename CFI_Parser<A>::CIE_Info cieInfo;
489	bool foundFDE = false;
490	bool foundInCache = false;
491	// if compact encoding table gave offset into dwarf section, go directly there
492	if ( sectionOffsetOfFDE != 0 ) {
493		foundFDE = CFI_Parser<A>::findFDE(fAddressSpace, pc, ehSectionStart, sectionLength, ehSectionStart+sectionOffsetOfFDE, &fdeInfo, &cieInfo);
494	}
495#if !FOR_DYLD
496	if ( !foundFDE ) {
497		// otherwise, search cache of previously found FDEs
498		pint_t cachedFDE = DwarfFDECache<A>::findFDE(mh, pc);
499		//fprintf(stderr, "getInfoFromDwarfSection(pc=0x%llX) cachedFDE=0x%llX\n", (uint64_t)pc, (uint64_t)cachedFDE);
500		if ( cachedFDE != 0 ) {
501			foundFDE = CFI_Parser<A>::findFDE(fAddressSpace, pc, ehSectionStart, sectionLength, cachedFDE, &fdeInfo, &cieInfo);
502			foundInCache = foundFDE;
503			//fprintf(stderr, "cachedFDE=0x%llX, foundInCache=%d\n", (uint64_t)cachedFDE, foundInCache);
504		}
505	}
506#endif
507	if ( !foundFDE ) {
508		// still not found, do full scan of __eh_frame section
509		foundFDE = CFI_Parser<A>::findFDE(fAddressSpace, pc, ehSectionStart, sectionLength, 0, &fdeInfo, &cieInfo);
510	}
511	if ( foundFDE ) {
512		typename CFI_Parser<A>::PrologInfo prolog;
513		if ( CFI_Parser<A>::parseFDEInstructions(fAddressSpace, fdeInfo, cieInfo, pc, &prolog) ) {
514			// save off parsed FDE info
515			fInfo.start_ip			= fdeInfo.pcStart;
516			fInfo.end_ip			= fdeInfo.pcEnd;
517			fInfo.lsda				= fdeInfo.lsda;
518			fInfo.handler			= cieInfo.personality;
519			fInfo.gp				= prolog.spExtraArgSize;  // some frameless functions need SP altered when resuming in function
520			fInfo.flags				= 0;
521			fInfo.format			= dwarfEncoding();
522			fInfo.unwind_info		= fdeInfo.fdeStart;
523			fInfo.unwind_info_size	= fdeInfo.fdeLength;
524			fInfo.extra				= (unw_word_t)mh;
525			if ( !foundInCache && (sectionOffsetOfFDE == 0) ) {
526				// don't add to cache entries the compact encoding table can find quickly
527				//fprintf(stderr, "getInfoFromDwarfSection(pc=0x%0llX), mh=0x%llX, start_ip=0x%0llX, fde=0x%0llX, personality=0x%0llX\n",
528				//	(uint64_t)pc, (uint64_t)mh, fInfo.start_ip, fInfo.unwind_info, fInfo.handler);
529#if !FOR_DYLD
530				DwarfFDECache<A>::add(mh, fdeInfo.pcStart, fdeInfo.pcEnd, fdeInfo.fdeStart);
531#endif
532			}
533			return true;
534		}
535	}
536	//DEBUG_MESSAGE("can't find/use FDE for pc=0x%llX\n", (uint64_t)pc);
537	return false;
538}
539
540
541template <typename A, typename R>
542bool UnwindCursor<A,R>::getInfoFromCompactEncodingSection(pint_t pc, pint_t mh, pint_t unwindSectionStart)
543{
544	const bool log = false;
545	if ( log ) fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX, mh=0x%llX)\n", (uint64_t)pc, (uint64_t)mh);
546
547	const UnwindSectionHeader<A> sectionHeader(fAddressSpace, unwindSectionStart);
548	if ( sectionHeader.version() != UNWIND_SECTION_VERSION )
549		return false;
550
551	// do a binary search of top level index to find page with unwind info
552	uint32_t targetFunctionOffset = pc - mh;
553	const UnwindSectionIndexArray<A> topIndex(fAddressSpace, unwindSectionStart + sectionHeader.indexSectionOffset());
554	uint32_t low = 0;
555	uint32_t high = sectionHeader.indexCount();
556	const uint32_t last = high - 1;
557	while ( low < high ) {
558		uint32_t mid = (low + high)/2;
559		//if ( log ) fprintf(stderr, "\tmid=%d, low=%d, high=%d, *mid=0x%08X\n", mid, low, high, topIndex.functionOffset(mid));
560		if ( topIndex.functionOffset(mid) <= targetFunctionOffset ) {
561			if ( (mid == last) || (topIndex.functionOffset(mid+1) > targetFunctionOffset) ) {
562				low = mid;
563				break;
564			}
565			else {
566				low = mid+1;
567			}
568		}
569		else {
570			high = mid;
571		}
572	}
573	const uint32_t firstLevelFunctionOffset = topIndex.functionOffset(low);
574	const uint32_t firstLevelNextPageFunctionOffset = topIndex.functionOffset(low+1);
575	const pint_t secondLevelAddr    = unwindSectionStart+topIndex.secondLevelPagesSectionOffset(low);
576	const pint_t lsdaArrayStartAddr = unwindSectionStart+topIndex.lsdaIndexArraySectionOffset(low);
577	const pint_t lsdaArrayEndAddr   = unwindSectionStart+topIndex.lsdaIndexArraySectionOffset(low+1);
578	if ( log ) fprintf(stderr, "\tfirst level search for result index=%d to secondLevelAddr=0x%llX\n",
579			low, (uint64_t)secondLevelAddr);
580	// do a binary search of second level page index
581	uint32_t encoding = 0;
582	pint_t funcStart = 0;
583	pint_t funcEnd = 0;
584	pint_t lsda = 0;
585	pint_t personality = 0;
586	uint32_t pageKind = fAddressSpace.get32(secondLevelAddr);
587	if ( pageKind == UNWIND_SECOND_LEVEL_REGULAR ) {
588		// regular page
589		UnwindSectionRegularPageHeader<A> pageHeader(fAddressSpace, secondLevelAddr);
590		UnwindSectionRegularArray<A> pageIndex(fAddressSpace, secondLevelAddr + pageHeader.entryPageOffset());
591		// binary search looks for entry with e where index[e].offset <= pc < index[e+1].offset
592		if ( log ) fprintf(stderr, "\tbinary search for targetFunctionOffset=0x%08llX in regular page starting at secondLevelAddr=0x%llX\n",
593			(uint64_t)targetFunctionOffset, (uint64_t)secondLevelAddr);
594		uint32_t low = 0;
595		uint32_t high = pageHeader.entryCount();
596		while ( low < high ) {
597			uint32_t mid = (low + high)/2;
598			if ( pageIndex.functionOffset(mid) <= targetFunctionOffset ) {
599				if ( mid == (uint32_t)(pageHeader.entryCount()-1) ) {
600					// at end of table
601					low = mid;
602					funcEnd = firstLevelNextPageFunctionOffset + mh;
603					break;
604				}
605				else if ( pageIndex.functionOffset(mid+1) > targetFunctionOffset ) {
606					// next is too big, so we found it
607					low = mid;
608					funcEnd = pageIndex.functionOffset(low+1) + mh;
609					break;
610				}
611				else {
612					low = mid+1;
613				}
614			}
615			else {
616				high = mid;
617			}
618		}
619		encoding  = pageIndex.encoding(low);
620		funcStart = pageIndex.functionOffset(low) + mh;
621		if ( pc < funcStart  ) {
622			if ( log ) fprintf(stderr, "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n", (uint64_t)pc, (uint64_t)funcStart, (uint64_t)funcEnd);
623			return false;
624		}
625		if ( pc > funcEnd ) {
626			if ( log ) fprintf(stderr, "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n", (uint64_t)pc, (uint64_t)funcStart, (uint64_t)funcEnd);
627			return false;
628		}
629	}
630	else if ( pageKind == UNWIND_SECOND_LEVEL_COMPRESSED ) {
631		// compressed page
632		UnwindSectionCompressedPageHeader<A> pageHeader(fAddressSpace, secondLevelAddr);
633		UnwindSectionCompressedArray<A> pageIndex(fAddressSpace, secondLevelAddr + pageHeader.entryPageOffset());
634		const uint32_t targetFunctionPageOffset = targetFunctionOffset - firstLevelFunctionOffset;
635		// binary search looks for entry with e where index[e].offset <= pc < index[e+1].offset
636		if ( log ) fprintf(stderr, "\tbinary search of compressed page starting at secondLevelAddr=0x%llX\n", (uint64_t)secondLevelAddr);
637		uint32_t low = 0;
638		const uint32_t last = pageHeader.entryCount() - 1;
639		uint32_t high = pageHeader.entryCount();
640		while ( low < high ) {
641			uint32_t mid = (low + high)/2;
642			if ( pageIndex.functionOffset(mid) <= targetFunctionPageOffset ) {
643				if ( (mid == last) || (pageIndex.functionOffset(mid+1) > targetFunctionPageOffset) ) {
644					low = mid;
645					break;
646				}
647				else {
648					low = mid+1;
649				}
650			}
651			else {
652				high = mid;
653			}
654		}
655		funcStart = pageIndex.functionOffset(low) + firstLevelFunctionOffset + mh;
656		if ( low < last )
657			funcEnd = pageIndex.functionOffset(low+1) + firstLevelFunctionOffset + mh;
658		else
659			funcEnd = firstLevelNextPageFunctionOffset + mh;
660		if ( pc < funcStart  ) {
661			DEBUG_MESSAGE("malformed __unwind_info, pc=0x%llX not in second level compressed unwind table. funcStart=0x%llX\n", (uint64_t)pc, (uint64_t)funcStart);
662			return false;
663		}
664		if ( pc > funcEnd ) {
665			DEBUG_MESSAGE("malformed __unwind_info, pc=0x%llX not in second level compressed unwind table. funcEnd=0x%llX\n", (uint64_t)pc, (uint64_t)funcEnd);
666			return false;
667		}
668		uint16_t encodingIndex = pageIndex.encodingIndex(low);
669		if ( encodingIndex < sectionHeader.commonEncodingsArrayCount() ) {
670			// encoding is in common table in section header
671			encoding = fAddressSpace.get32(unwindSectionStart+sectionHeader.commonEncodingsArraySectionOffset()+encodingIndex*sizeof(uint32_t));
672		}
673		else {
674			// encoding is in page specific table
675			uint16_t pageEncodingIndex = encodingIndex-sectionHeader.commonEncodingsArrayCount();
676			encoding = fAddressSpace.get32(secondLevelAddr+pageHeader.encodingsPageOffset()+pageEncodingIndex*sizeof(uint32_t));
677		}
678	}
679	else {
680		DEBUG_MESSAGE("malformed __unwind_info at 0x%0llX bad second level page\n", (uint64_t)unwindSectionStart);
681		return false;
682	}
683
684	// look up LSDA, if encoding says function has one
685	if ( encoding & UNWIND_HAS_LSDA ) {
686		UnwindSectionLsdaArray<A>  lsdaIndex(fAddressSpace, lsdaArrayStartAddr);
687		uint32_t funcStartOffset = funcStart - mh;
688		uint32_t low = 0;
689		uint32_t high = (lsdaArrayEndAddr-lsdaArrayStartAddr)/sizeof(unwind_info_section_header_lsda_index_entry);
690		// binary search looks for entry with exact match for functionOffset
691		if ( log ) fprintf(stderr, "\tbinary search of lsda table for targetFunctionOffset=0x%08X\n", funcStartOffset);
692		while ( low < high ) {
693			uint32_t mid = (low + high)/2;
694			if ( lsdaIndex.functionOffset(mid) == funcStartOffset ) {
695				lsda = lsdaIndex.lsdaOffset(mid) + mh;
696				break;
697			}
698			else if ( lsdaIndex.functionOffset(mid) < funcStartOffset ) {
699				low = mid+1;
700			}
701			else {
702				high = mid;
703			}
704		}
705		if ( lsda == 0 ) {
706			DEBUG_MESSAGE("found encoding 0x%08X with HAS_LSDA bit set for pc=0x%0llX, but lsda table has no entry\n", encoding, (uint64_t)pc);
707			return false;
708		}
709	}
710
711	// extact personality routine, if encoding says function has one
712	uint32_t personalityIndex = (encoding & UNWIND_PERSONALITY_MASK) >> (__builtin_ctz(UNWIND_PERSONALITY_MASK));
713	if ( personalityIndex != 0 ) {
714		--personalityIndex; // change 1-based to zero-based index
715		if ( personalityIndex > sectionHeader.personalityArrayCount() ) {
716			DEBUG_MESSAGE("found encoding 0x%08X with personality index %d, but personality table has only %d entires\n",
717							encoding, personalityIndex, sectionHeader.personalityArrayCount());
718			return false;
719		}
720		int32_t personalityDelta = fAddressSpace.get32(unwindSectionStart+sectionHeader.personalityArraySectionOffset()+personalityIndex*sizeof(uint32_t));
721		pint_t personalityPointer = personalityDelta + mh;
722		personality = fAddressSpace.getP(personalityPointer);
723		if (log ) fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), personalityDelta=0x%08X, personality=0x%08llX\n",
724			(uint64_t)pc, personalityDelta, (uint64_t)personality);
725	}
726
727	if (log ) fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), encoding=0x%08X, lsda=0x%08llX for funcStart=0x%llX\n",
728						(uint64_t)pc, encoding, (uint64_t)lsda, (uint64_t)funcStart);
729	fInfo.start_ip			= funcStart;
730	fInfo.end_ip			= funcEnd;
731	fInfo.lsda				= lsda;
732	fInfo.handler			= personality;
733	fInfo.gp				= 0;
734	fInfo.flags				= 0;
735	fInfo.format			= encoding;
736	fInfo.unwind_info		= 0;
737	fInfo.unwind_info_size	= 0;
738	fInfo.extra				= mh;
739	return true;
740}
741
742
743
744template <typename A, typename R>
745void UnwindCursor<A,R>::setInfoBasedOnIPRegister(bool isReturnAddress)
746{
747	pint_t pc = this->getReg(UNW_REG_IP);
748
749	// if the last line of a function is a "throw" the compile sometimes
750	// emits no instructions after the call to __cxa_throw.  This means
751	// the return address is actually the start of the next function.
752	// To disambiguate this, back up the pc when we know it is a return
753	// address.
754	if ( isReturnAddress )
755		--pc;
756
757	// ask address space object to find unwind sections for this pc
758	pint_t mh;
759	pint_t dwarfStart;
760	pint_t dwarfLength;
761	pint_t compactStart;
762	if ( fAddressSpace.findUnwindSections(pc, mh, dwarfStart, dwarfLength, compactStart) ) {
763		// if there is a compact unwind encoding table, look there first
764		if ( compactStart != 0 ) {
765			if ( this->getInfoFromCompactEncodingSection(pc, mh, compactStart) ) {
766#if !FOR_DYLD
767				// found info in table, done unless encoding says to use dwarf
768				uint32_t offsetInDwarfSection;
769				if ( (dwarfStart != 0) && dwarfWithOffset(offsetInDwarfSection) ) {
770					if ( this->getInfoFromDwarfSection(pc, mh, dwarfStart, dwarfLength, offsetInDwarfSection) ) {
771						// found info in dwarf, done
772						return;
773					}
774				}
775#endif
776				// if unwind table has entry, but entry says there is no unwind info, note that
777				if ( fInfo.format == 0 )
778					fUnwindInfoMissing = true;
779
780				// old compact encoding
781				if ( !mustUseDwarf() ) {
782					return;
783				}
784			}
785		}
786#if !FOR_DYLD || __ppc__
787		// if there is dwarf unwind info, look there next
788		if ( dwarfStart != 0 ) {
789			if ( this->getInfoFromDwarfSection(pc, mh, dwarfStart, dwarfLength, 0) ) {
790				// found info in dwarf, done
791				return;
792			}
793		}
794#endif
795	}
796
797#if !FOR_DYLD
798	// the PC is not in code loaded by dyld, look through __register_frame() registered FDEs
799	pint_t cachedFDE = DwarfFDECache<A>::findFDE(0, pc);
800	if ( cachedFDE != 0 ) {
801		CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
802		CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
803		const char* msg = CFI_Parser<A>::decodeFDE(fAddressSpace, cachedFDE, &fdeInfo, &cieInfo);
804		if ( msg == NULL ) {
805			typename CFI_Parser<A>::PrologInfo prolog;
806			if ( CFI_Parser<A>::parseFDEInstructions(fAddressSpace, fdeInfo, cieInfo, pc, &prolog) ) {
807				// save off parsed FDE info
808				fInfo.start_ip			= fdeInfo.pcStart;
809				fInfo.end_ip			= fdeInfo.pcEnd;
810				fInfo.lsda				= fdeInfo.lsda;
811				fInfo.handler			= cieInfo.personality;
812				fInfo.gp				= prolog.spExtraArgSize;  // some frameless functions need SP altered when resuming in function
813				fInfo.flags				= 0;
814				fInfo.format			= dwarfEncoding();
815				fInfo.unwind_info		= fdeInfo.fdeStart;
816				fInfo.unwind_info_size	= fdeInfo.fdeLength;
817				fInfo.extra				= 0;
818				return;
819			}
820		}
821	}
822
823#if KEYMGR_SUPPPORT
824	// lastly check for old style keymgr registration of dynamically generated FDEs
825	// acquire exclusive access to libgcc_object_info
826	libgcc_object_info* head = (libgcc_object_info*)_keymgr_get_and_lock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST);
827	if ( head != NULL ) {
828		// look at each FDE in keymgr
829		for (libgcc_object* ob = head->unseen_objects; ob != NULL; ob = ob->next) {
830			CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
831			CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
832			const char* msg = CFI_Parser<A>::decodeFDE(fAddressSpace, (pint_t)ob->fde, &fdeInfo, &cieInfo);
833			if ( msg == NULL ) {
834				// see if this FDE is for a function that includes the pc we are looking for
835				if ( (fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd) ) {
836					typename CFI_Parser<A>::PrologInfo prolog;
837					if ( CFI_Parser<A>::parseFDEInstructions(fAddressSpace, fdeInfo, cieInfo, pc, &prolog) ) {
838						// save off parsed FDE info
839						fInfo.start_ip			= fdeInfo.pcStart;
840						fInfo.end_ip			= fdeInfo.pcEnd;
841						fInfo.lsda				= fdeInfo.lsda;
842						fInfo.handler			= cieInfo.personality;
843						fInfo.gp				= prolog.spExtraArgSize;  // some frameless functions need SP altered when resuming in function
844						fInfo.flags				= 0;
845						fInfo.format			= dwarfEncoding();
846						fInfo.unwind_info		= fdeInfo.fdeStart;
847						fInfo.unwind_info_size	= fdeInfo.fdeLength;
848						fInfo.extra				= 0;
849						_keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, head);
850						return;
851					}
852				}
853			}
854		}
855	}
856	// release libgcc_object_info
857	_keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, head);
858#endif // KEYMGR_SUPPPORT
859
860#endif
861
862	// no unwind info, flag that we can't reliable unwind
863	fUnwindInfoMissing = true;
864}
865
866
867template <typename A, typename R>
868int UnwindCursor<A,R>::step()
869{
870	// bottom of stack is defined as when no more unwind info
871	if ( fUnwindInfoMissing )
872		return UNW_STEP_END;
873
874	// apply unwinding to register set
875	int result;
876	if ( this->mustUseDwarf() )
877		result = this->stepWithDwarfFDE();
878	else
879		result = this->stepWithCompactEncoding();
880
881	// update info based on new PC
882	if ( result == UNW_STEP_SUCCESS ) {
883		this->setInfoBasedOnIPRegister(true);
884		if ( fUnwindInfoMissing )
885			return UNW_STEP_END;
886	}
887
888	return result;
889}
890
891
892template <typename A, typename R>
893void UnwindCursor<A,R>::getInfo(unw_proc_info_t* info)
894{
895	*info = fInfo;
896}
897
898
899template <typename A, typename R>
900bool UnwindCursor<A,R>::getFunctionName(char* buf, size_t bufLen, unw_word_t* offset)
901{
902	return fAddressSpace.findFunctionName(this->getReg(UNW_REG_IP), buf, bufLen, offset);
903}
904
905}; // namespace libunwind
906
907
908#endif // __UNWINDCURSOR_HPP__
909
910
911
912
913