[132916] distfiles
jeremyhu at macports.org
jeremyhu at macports.org
Fri Feb 13 00:53:30 PST 2015
Revision: 132916
https://trac.macports.org/changeset/132916
Author: jeremyhu at macports.org
Date: 2015-02-13 00:53:30 -0800 (Fri, 13 Feb 2015)
Log Message:
-----------
Move large ld64 patch to distfiles
Added Paths:
-----------
distfiles/ld64/
distfiles/ld64/ld64-97-standalone-libunwind-headers.patch
Added: distfiles/ld64/ld64-97-standalone-libunwind-headers.patch
===================================================================
--- distfiles/ld64/ld64-97-standalone-libunwind-headers.patch (rev 0)
+++ distfiles/ld64/ld64-97-standalone-libunwind-headers.patch 2015-02-13 08:53:30 UTC (rev 132916)
@@ -0,0 +1,4438 @@
+From ce433767d79be40375b69dd3139d04978401df3d Mon Sep 17 00:00:00 2001
+From: Nick Kledzik <kledzik at apple.com>
+Date: Fri, 18 Mar 2011 20:57:25 +0000
+Subject: [PATCH] ld64 should build stand-alone and not need libunwind headers
+
+(cherry picked from commit 231841085f71586b0b2d8f6b63b9317783e80c9e)
+---
+ src/ld/MachOReaderRelocatable.hpp | 6 +-
+ src/ld/dwarf2.h | 219 +++
+ src/ld/parsers/libunwind/AddressSpace.hpp | 439 ++++++
+ src/ld/parsers/libunwind/DwarfInstructions.hpp | 1726 ++++++++++++++++++++++++
+ src/ld/parsers/libunwind/DwarfParser.hpp | 819 +++++++++++
+ src/ld/parsers/libunwind/InternalMacros.h | 105 ++
+ src/ld/parsers/libunwind/Registers.hpp | 1050 ++++++++++++++
+ 7 files changed, 4361 insertions(+), 3 deletions(-)
+ create mode 100644 src/ld/parsers/libunwind/AddressSpace.hpp
+ create mode 100644 src/ld/parsers/libunwind/DwarfInstructions.hpp
+ create mode 100644 src/ld/parsers/libunwind/DwarfParser.hpp
+ create mode 100644 src/ld/parsers/libunwind/InternalMacros.h
+ create mode 100644 src/ld/parsers/libunwind/Registers.hpp
+
+diff --git a/src/ld/MachOReaderRelocatable.hpp b/src/ld/MachOReaderRelocatable.hpp
+index 2aa7926..b8e5960 100644
+--- src/ld/MachOReaderRelocatable.hpp
++++ src/ld/MachOReaderRelocatable.hpp
+@@ -40,9 +40,9 @@
+ #include "dwarf2.h"
+ #include "debugline.h"
+
+-#include <libunwind/DwarfInstructions.hpp>
+-#include <libunwind/AddressSpace.hpp>
+-#include <libunwind/Registers.hpp>
++#include "libunwind/DwarfInstructions.hpp"
++#include "libunwind/AddressSpace.hpp"
++#include "libunwind/Registers.hpp"
+
+ //
+ //
+diff --git a/src/ld/dwarf2.h b/src/ld/dwarf2.h
+index 7a7b4f2..411dbbc 100644
+--- src/ld/dwarf2.h
++++ src/ld/dwarf2.h
+@@ -87,4 +87,223 @@ enum {
+ DW_LNE_define_file
+ };
+
++
++// dwarf unwind instructions
++enum {
++ DW_CFA_nop = 0x0,
++ DW_CFA_set_loc = 0x1,
++ DW_CFA_advance_loc1 = 0x2,
++ DW_CFA_advance_loc2 = 0x3,
++ DW_CFA_advance_loc4 = 0x4,
++ DW_CFA_offset_extended = 0x5,
++ DW_CFA_restore_extended = 0x6,
++ DW_CFA_undefined = 0x7,
++ DW_CFA_same_value = 0x8,
++ DW_CFA_register = 0x9,
++ DW_CFA_remember_state = 0xA,
++ DW_CFA_restore_state = 0xB,
++ DW_CFA_def_cfa = 0xC,
++ DW_CFA_def_cfa_register = 0xD,
++ DW_CFA_def_cfa_offset = 0xE,
++ DW_CFA_def_cfa_expression = 0xF,
++ DW_CFA_expression = 0x10,
++ DW_CFA_offset_extended_sf = 0x11,
++ DW_CFA_def_cfa_sf = 0x12,
++ DW_CFA_def_cfa_offset_sf = 0x13,
++ DW_CFA_val_offset = 0x14,
++ DW_CFA_val_offset_sf = 0x15,
++ DW_CFA_val_expression = 0x16,
++ DW_CFA_advance_loc = 0x40, // high 2 bits are 0x1, lower 6 bits are delta
++ DW_CFA_offset = 0x80, // high 2 bits are 0x2, lower 6 bits are register
++ DW_CFA_restore = 0xC0, // high 2 bits are 0x3, lower 6 bits are register
++
++ // GNU extensions
++ DW_CFA_GNU_window_save = 0x2D,
++ DW_CFA_GNU_args_size = 0x2E,
++ DW_CFA_GNU_negative_offset_extended = 0x2F
++};
++
++
++// FSF exception handling Pointer-Encoding constants
++// Used in CFI augmentation by gcc compiler
++enum {
++ DW_EH_PE_ptr = 0x00,
++ DW_EH_PE_uleb128 = 0x01,
++ DW_EH_PE_udata2 = 0x02,
++ DW_EH_PE_udata4 = 0x03,
++ DW_EH_PE_udata8 = 0x04,
++ DW_EH_PE_signed = 0x08,
++ DW_EH_PE_sleb128 = 0x09,
++ DW_EH_PE_sdata2 = 0x0A,
++ DW_EH_PE_sdata4 = 0x0B,
++ DW_EH_PE_sdata8 = 0x0C,
++ DW_EH_PE_absptr = 0x00,
++ DW_EH_PE_pcrel = 0x10,
++ DW_EH_PE_textrel = 0x20,
++ DW_EH_PE_datarel = 0x30,
++ DW_EH_PE_funcrel = 0x40,
++ DW_EH_PE_aligned = 0x50,
++ DW_EH_PE_indirect = 0x80,
++ DW_EH_PE_omit = 0xFF
++};
++
++
++// DWARF expressions
++enum {
++ DW_OP_addr = 0x03, // constant address (size target specific)
++ DW_OP_deref = 0x06,
++ DW_OP_const1u = 0x08, // 1-byte constant
++ DW_OP_const1s = 0x09, // 1-byte constant
++ DW_OP_const2u = 0x0A, // 2-byte constant
++ DW_OP_const2s = 0x0B, // 2-byte constant
++ DW_OP_const4u = 0x0C, // 4-byte constant
++ DW_OP_const4s = 0x0D, // 4-byte constant
++ DW_OP_const8u = 0x0E, // 8-byte constant
++ DW_OP_const8s = 0x0F, // 8-byte constant
++ DW_OP_constu = 0x10, // ULEB128 constant
++ DW_OP_consts = 0x11, // SLEB128 constant
++ DW_OP_dup = 0x12,
++ DW_OP_drop = 0x13,
++ DW_OP_over = 0x14,
++ DW_OP_pick = 0x15, // 1-byte stack index
++ DW_OP_swap = 0x16,
++ DW_OP_rot = 0x17,
++ DW_OP_xderef = 0x18,
++ DW_OP_abs = 0x19,
++ DW_OP_and = 0x1A,
++ DW_OP_div = 0x1B,
++ DW_OP_minus = 0x1C,
++ DW_OP_mod = 0x1D,
++ DW_OP_mul = 0x1E,
++ DW_OP_neg = 0x1F,
++ DW_OP_not = 0x20,
++ DW_OP_or = 0x21,
++ DW_OP_plus = 0x22,
++ DW_OP_plus_uconst = 0x23, // ULEB128 addend
++ DW_OP_shl = 0x24,
++ DW_OP_shr = 0x25,
++ DW_OP_shra = 0x26,
++ DW_OP_xor = 0x27,
++ DW_OP_skip = 0x2F, // signed 2-byte constant
++ DW_OP_bra = 0x28, // signed 2-byte constant
++ DW_OP_eq = 0x29,
++ DW_OP_ge = 0x2A,
++ DW_OP_gt = 0x2B,
++ DW_OP_le = 0x2C,
++ DW_OP_lt = 0x2D,
++ DW_OP_ne = 0x2E,
++ DW_OP_lit0 = 0x30, // Literal 0
++ DW_OP_lit1 = 0x31, // Literal 1
++ DW_OP_lit2 = 0x32, // Literal 2
++ DW_OP_lit3 = 0x33, // Literal 3
++ DW_OP_lit4 = 0x34, // Literal 4
++ DW_OP_lit5 = 0x35, // Literal 5
++ DW_OP_lit6 = 0x36, // Literal 6
++ DW_OP_lit7 = 0x37, // Literal 7
++ DW_OP_lit8 = 0x38, // Literal 8
++ DW_OP_lit9 = 0x39, // Literal 9
++ DW_OP_lit10 = 0x3A, // Literal 10
++ DW_OP_lit11 = 0x3B, // Literal 11
++ DW_OP_lit12 = 0x3C, // Literal 12
++ DW_OP_lit13 = 0x3D, // Literal 13
++ DW_OP_lit14 = 0x3E, // Literal 14
++ DW_OP_lit15 = 0x3F, // Literal 15
++ DW_OP_lit16 = 0x40, // Literal 16
++ DW_OP_lit17 = 0x41, // Literal 17
++ DW_OP_lit18 = 0x42, // Literal 18
++ DW_OP_lit19 = 0x43, // Literal 19
++ DW_OP_lit20 = 0x44, // Literal 20
++ DW_OP_lit21 = 0x45, // Literal 21
++ DW_OP_lit22 = 0x46, // Literal 22
++ DW_OP_lit23 = 0x47, // Literal 23
++ DW_OP_lit24 = 0x48, // Literal 24
++ DW_OP_lit25 = 0x49, // Literal 25
++ DW_OP_lit26 = 0x4A, // Literal 26
++ DW_OP_lit27 = 0x4B, // Literal 27
++ DW_OP_lit28 = 0x4C, // Literal 28
++ DW_OP_lit29 = 0x4D, // Literal 29
++ DW_OP_lit30 = 0x4E, // Literal 30
++ DW_OP_lit31 = 0x4F, // Literal 31
++ DW_OP_reg0 = 0x50, // Contents of reg0
++ DW_OP_reg1 = 0x51, // Contents of reg1
++ DW_OP_reg2 = 0x52, // Contents of reg2
++ DW_OP_reg3 = 0x53, // Contents of reg3
++ DW_OP_reg4 = 0x54, // Contents of reg4
++ DW_OP_reg5 = 0x55, // Contents of reg5
++ DW_OP_reg6 = 0x56, // Contents of reg6
++ DW_OP_reg7 = 0x57, // Contents of reg7
++ DW_OP_reg8 = 0x58, // Contents of reg8
++ DW_OP_reg9 = 0x59, // Contents of reg9
++ DW_OP_reg10 = 0x5A, // Contents of reg10
++ DW_OP_reg11 = 0x5B, // Contents of reg11
++ DW_OP_reg12 = 0x5C, // Contents of reg12
++ DW_OP_reg13 = 0x5D, // Contents of reg13
++ DW_OP_reg14 = 0x5E, // Contents of reg14
++ DW_OP_reg15 = 0x5F, // Contents of reg15
++ DW_OP_reg16 = 0x60, // Contents of reg16
++ DW_OP_reg17 = 0x61, // Contents of reg17
++ DW_OP_reg18 = 0x62, // Contents of reg18
++ DW_OP_reg19 = 0x63, // Contents of reg19
++ DW_OP_reg20 = 0x64, // Contents of reg20
++ DW_OP_reg21 = 0x65, // Contents of reg21
++ DW_OP_reg22 = 0x66, // Contents of reg22
++ DW_OP_reg23 = 0x67, // Contents of reg23
++ DW_OP_reg24 = 0x68, // Contents of reg24
++ DW_OP_reg25 = 0x69, // Contents of reg25
++ DW_OP_reg26 = 0x6A, // Contents of reg26
++ DW_OP_reg27 = 0x6B, // Contents of reg27
++ DW_OP_reg28 = 0x6C, // Contents of reg28
++ DW_OP_reg29 = 0x6D, // Contents of reg29
++ DW_OP_reg30 = 0x6E, // Contents of reg30
++ DW_OP_reg31 = 0x6F, // Contents of reg31
++ DW_OP_breg0 = 0x70, // base register 0 + SLEB128 offset
++ DW_OP_breg1 = 0x71, // base register 1 + SLEB128 offset
++ DW_OP_breg2 = 0x72, // base register 2 + SLEB128 offset
++ DW_OP_breg3 = 0x73, // base register 3 + SLEB128 offset
++ DW_OP_breg4 = 0x74, // base register 4 + SLEB128 offset
++ DW_OP_breg5 = 0x75, // base register 5 + SLEB128 offset
++ DW_OP_breg6 = 0x76, // base register 6 + SLEB128 offset
++ DW_OP_breg7 = 0x77, // base register 7 + SLEB128 offset
++ DW_OP_breg8 = 0x78, // base register 8 + SLEB128 offset
++ DW_OP_breg9 = 0x79, // base register 9 + SLEB128 offset
++ DW_OP_breg10 = 0x7A, // base register 10 + SLEB128 offset
++ DW_OP_breg11 = 0x7B, // base register 11 + SLEB128 offset
++ DW_OP_breg12 = 0x7C, // base register 12 + SLEB128 offset
++ DW_OP_breg13 = 0x7D, // base register 13 + SLEB128 offset
++ DW_OP_breg14 = 0x7E, // base register 14 + SLEB128 offset
++ DW_OP_breg15 = 0x7F, // base register 15 + SLEB128 offset
++ DW_OP_breg16 = 0x80, // base register 16 + SLEB128 offset
++ DW_OP_breg17 = 0x81, // base register 17 + SLEB128 offset
++ DW_OP_breg18 = 0x82, // base register 18 + SLEB128 offset
++ DW_OP_breg19 = 0x83, // base register 19 + SLEB128 offset
++ DW_OP_breg20 = 0x84, // base register 20 + SLEB128 offset
++ DW_OP_breg21 = 0x85, // base register 21 + SLEB128 offset
++ DW_OP_breg22 = 0x86, // base register 22 + SLEB128 offset
++ DW_OP_breg23 = 0x87, // base register 23 + SLEB128 offset
++ DW_OP_breg24 = 0x88, // base register 24 + SLEB128 offset
++ DW_OP_breg25 = 0x89, // base register 25 + SLEB128 offset
++ DW_OP_breg26 = 0x8A, // base register 26 + SLEB128 offset
++ DW_OP_breg27 = 0x8B, // base register 27 + SLEB128 offset
++ DW_OP_breg28 = 0x8C, // base register 28 + SLEB128 offset
++ DW_OP_breg29 = 0x8D, // base register 29 + SLEB128 offset
++ DW_OP_breg30 = 0x8E, // base register 30 + SLEB128 offset
++ DW_OP_breg31 = 0x8F, // base register 31 + SLEB128 offset
++ DW_OP_regx = 0x90, // ULEB128 register
++ DW_OP_fbreg = 0x91, // SLEB128 offset
++ DW_OP_bregx = 0x92, // ULEB128 register followed by SLEB128 offset
++ DW_OP_piece = 0x93, // ULEB128 size of piece addressed
++ DW_OP_deref_size = 0x94, // 1-byte size of data retrieved
++ DW_OP_xderef_size = 0x95, // 1-byte size of data retrieved
++ DW_OP_nop = 0x96,
++ DW_OP_push_object_addres = 0x97,
++ DW_OP_call2 = 0x98, // 2-byte offset of DIE
++ DW_OP_call4 = 0x99, // 4-byte offset of DIE
++ DW_OP_call_ref = 0x9A, // 4- or 8-byte offset of DIE
++ DW_OP_lo_user = 0xE0,
++ DW_OP_APPLE_uninit = 0xF0,
++ DW_OP_hi_user = 0xFF
++};
++
++
++
+ #endif
+diff --git a/src/ld/parsers/libunwind/AddressSpace.hpp b/src/ld/parsers/libunwind/AddressSpace.hpp
+new file mode 100644
+index 0000000..bebd3e6
+--- /dev/null
++++ src/ld/parsers/libunwind/AddressSpace.hpp
+@@ -0,0 +1,439 @@
++/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
++ *
++ * Copyright (c) 2008 Apple Inc. All rights reserved.
++ *
++ * @APPLE_LICENSE_HEADER_START@
++ *
++ * This file contains Original Code and/or Modifications of Original Code
++ * as defined in and that are subject to the Apple Public Source License
++ * Version 2.0 (the 'License'). You may not use this file except in
++ * compliance with the License. Please obtain a copy of the License at
++ * http://www.opensource.apple.com/apsl/ and read it before using this
++ * file.
++ *
++ * The Original Code and all software distributed under the License are
++ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
++ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
++ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
++ * Please see the License for the specific language governing rights and
++ * limitations under the License.
++ *
++ * @APPLE_LICENSE_HEADER_END@
++ */
++
++//
++// C++ interface to lower levels of libuwind
++//
++
++#ifndef __ADDRESSSPACE_HPP__
++#define __ADDRESSSPACE_HPP__
++
++#include <stdint.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <dlfcn.h>
++#include <mach-o/loader.h>
++#include <mach-o/getsect.h>
++#include <mach-o/dyld_priv.h>
++#include <mach/i386/thread_status.h>
++#include <Availability.h>
++
++#include "FileAbstraction.hpp"
++#include "libunwind.h"
++#include "InternalMacros.h"
++#include "dwarf2.h"
++
++
++#if 0
++#if __i386__ || __x86_64__
++// In 10.6 and later i386 and x86_64 don't have a __dyld section
++// We need one to access private _dyld_func_lookup function.
++
++struct __DATA__dyld { long lazy; int (*lookup)(const char*, void**); };
++
++static volatile struct __DATA__dyld myDyldSection __attribute__ ((section ("__DATA,__dyld"))) = { 0, NULL };
++
++
++static int my_dyld_func_lookup(const char* dyld_func_name, void **address)
++{
++ return (*myDyldSection.lookup)(dyld_func_name, address);
++}
++#else
++ #define my_dyld_func_lookup _dyld_func_lookup
++#endif
++
++
++bool _dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info)
++{
++ static void* (*p)(void*, dyld_unwind_sections*) = NULL;
++
++ if(p == NULL)
++ my_dyld_func_lookup("__dyld_find_unwind_sections", (void**)&p);
++ return p(addr, info);
++}
++#endif // 0
++
++
++
++namespace libunwind {
++
++///
++/// LocalAddressSpace is used as a template parameter to UnwindCursor when unwinding a thread
++/// in the same process. It compiles away and making local unwinds very fast.
++///
++class LocalAddressSpace
++{
++public:
++
++ #if __LP64__
++ typedef uint64_t pint_t;
++ typedef int64_t sint_t;
++ #else
++ typedef uint32_t pint_t;
++ typedef int32_t sint_t;
++ #endif
++ uint8_t get8(pint_t addr) { return *((uint8_t*)addr); }
++ uint16_t get16(pint_t addr) { return *((uint16_t*)addr); }
++ uint32_t get32(pint_t addr) { return *((uint32_t*)addr); }
++ uint64_t get64(pint_t addr) { return *((uint64_t*)addr); }
++ double getDouble(pint_t addr) { return *((double*)addr); }
++ v128 getVector(pint_t addr) { return *((v128*)addr); }
++ uintptr_t getP(pint_t addr);
++ static uint64_t getULEB128(pint_t& addr, pint_t end);
++ static int64_t getSLEB128(pint_t& addr, pint_t end);
++
++ pint_t getEncodedP(pint_t& addr, pint_t end, uint8_t encoding);
++ bool findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset);
++ bool findUnwindSections(pint_t addr, pint_t& mh, pint_t& dwarfStart, pint_t& dwarfLen, pint_t& compactStart);
++
++};
++
++LocalAddressSpace sThisAddress;
++
++inline uintptr_t LocalAddressSpace::getP(pint_t addr)
++{
++#if __LP64__
++ return get64(addr);
++#else
++ return get32(addr);
++#endif
++}
++
++/* Read a ULEB128 into a 64-bit word. */
++inline uint64_t
++LocalAddressSpace::getULEB128(pint_t& addr, pint_t end)
++{
++ const uint8_t* p = (uint8_t*)addr;
++ const uint8_t* pend = (uint8_t*)end;
++ uint64_t result = 0;
++ int bit = 0;
++ do {
++ uint64_t b;
++
++ if ( p == pend )
++ ABORT("truncated uleb128 expression");
++
++ b = *p & 0x7f;
++
++ if (bit >= 64 || b << bit >> bit != b) {
++ ABORT("malformed uleb128 expression");
++ }
++ else {
++ result |= b << bit;
++ bit += 7;
++ }
++ } while ( *p++ >= 0x80 );
++ addr = (pint_t)p;
++ return result;
++}
++
++/* Read a SLEB128 into a 64-bit word. */
++inline int64_t
++LocalAddressSpace::getSLEB128(pint_t& addr, pint_t end)
++{
++ const uint8_t* p = (uint8_t*)addr;
++ int64_t result = 0;
++ int bit = 0;
++ uint8_t byte;
++ do {
++ byte = *p++;
++ result |= ((byte & 0x7f) << bit);
++ bit += 7;
++ } while (byte & 0x80);
++ // sign extend negative numbers
++ if ( (byte & 0x40) != 0 )
++ result |= (-1LL) << bit;
++ addr = (pint_t)p;
++ return result;
++}
++
++LocalAddressSpace::pint_t
++LocalAddressSpace::getEncodedP(pint_t& addr, pint_t end, uint8_t encoding)
++{
++ pint_t startAddr = addr;
++ const uint8_t* p = (uint8_t*)addr;
++ pint_t result;
++
++ // first get value
++ switch (encoding & 0x0F) {
++ case DW_EH_PE_ptr:
++ result = getP(addr);
++ p += sizeof(pint_t);
++ addr = (pint_t)p;
++ break;
++ case DW_EH_PE_uleb128:
++ result = getULEB128(addr, end);
++ break;
++ case DW_EH_PE_udata2:
++ result = get16(addr);
++ p += 2;
++ addr = (pint_t)p;
++ break;
++ case DW_EH_PE_udata4:
++ result = get32(addr);
++ p += 4;
++ addr = (pint_t)p;
++ break;
++ case DW_EH_PE_udata8:
++ result = get64(addr);
++ p += 8;
++ addr = (pint_t)p;
++ break;
++ case DW_EH_PE_sleb128:
++ result = getSLEB128(addr, end);
++ break;
++ case DW_EH_PE_sdata2:
++ result = (int16_t)get16(addr);
++ p += 2;
++ addr = (pint_t)p;
++ break;
++ case DW_EH_PE_sdata4:
++ result = (int32_t)get32(addr);
++ p += 4;
++ addr = (pint_t)p;
++ break;
++ case DW_EH_PE_sdata8:
++ result = get64(addr);
++ p += 8;
++ addr = (pint_t)p;
++ break;
++ default:
++ ABORT("unknown pointer encoding");
++ }
++
++ // then add relative offset
++ switch ( encoding & 0x70 ) {
++ case DW_EH_PE_absptr:
++ // do nothing
++ break;
++ case DW_EH_PE_pcrel:
++ result += startAddr;
++ break;
++ case DW_EH_PE_textrel:
++ ABORT("DW_EH_PE_textrel pointer encoding not supported");
++ break;
++ case DW_EH_PE_datarel:
++ ABORT("DW_EH_PE_datarel pointer encoding not supported");
++ break;
++ case DW_EH_PE_funcrel:
++ ABORT("DW_EH_PE_funcrel pointer encoding not supported");
++ break;
++ case DW_EH_PE_aligned:
++ ABORT("DW_EH_PE_aligned pointer encoding not supported");
++ break;
++ default:
++ ABORT("unknown pointer encoding");
++ break;
++ }
++
++ if ( encoding & DW_EH_PE_indirect )
++ result = getP(result);
++
++ return result;
++}
++
++
++inline bool LocalAddressSpace::findUnwindSections(pint_t addr, pint_t& mh, pint_t& dwarfStart, pint_t& dwarfLen, pint_t& compactStart)
++{
++ dyld_unwind_sections info;
++ if ( _dyld_find_unwind_sections((void*)addr, &info) ) {
++ mh = (pint_t)info.mh;
++ dwarfStart = (pint_t)info.dwarf_section;
++ dwarfLen = (pint_t)info.dwarf_section_length;
++ compactStart = (pint_t)info.compact_unwind_section;
++ return true;
++ }
++ return false;
++}
++
++
++inline bool LocalAddressSpace::findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset)
++{
++ dl_info dyldInfo;
++ if ( dladdr((void*)addr, &dyldInfo) ) {
++ if ( dyldInfo.dli_sname != NULL ) {
++ strlcpy(buf, dyldInfo.dli_sname, bufLen);
++ *offset = (addr - (pint_t)dyldInfo.dli_saddr);
++ return true;
++ }
++ }
++ return false;
++}
++
++
++
++#if UNW_REMOTE
++
++///
++/// OtherAddressSpace is used as a template parameter to UnwindCursor when unwinding a thread
++/// in the another process. The other process can be a different endianness and a different
++/// pointer size and is handled by the P template parameter.
++///
++template <typename P>
++class OtherAddressSpace
++{
++public:
++ OtherAddressSpace(task_t task) : fTask(task) {}
++
++ typedef typename P::uint_t pint_t;
++
++ uint8_t get8(pint_t addr);
++ uint16_t get16(pint_t addr);
++ uint32_t get32(pint_t addr);
++ uint64_t get64(pint_t addr);
++ pint_t getP(pint_t addr);
++ uint64_t getULEB128(pint_t& addr, pint_t end);
++ int64_t getSLEB128(pint_t& addr, pint_t end);
++ pint_t getEncodedP(pint_t& addr, pint_t end, uint8_t encoding);
++ bool findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset);
++ bool findUnwindSections(pint_t addr, unwind_sections& info);
++private:
++ void* localCopy(pint_t addr);
++
++
++ task_t fTask;
++};
++
++
++template <typename P>
++uint8_t OtherAddressSpace<P>::get8(pint_t addr)
++{
++ return *((uint8_t*)localCopy(addr));
++}
++
++template <typename P>
++uint16_t OtherAddressSpace<P>::get16(pint_t addr)
++{
++ return P::E::get16(*(uint16_t*)localCopy(addr));
++}
++
++template <typename P>
++uint32_t OtherAddressSpace<P>::get32(pint_t addr)
++{
++ return P::E::get32(*(uint32_t*)localCopy(addr));
++}
++
++template <typename P>
++uint64_t OtherAddressSpace<P>::get64(pint_t addr)
++{
++ return P::E::get64(*(uint64_t*)localCopy(addr));
++}
++
++template <typename P>
++typename P::uint_t OtherAddressSpace<P>::getP(pint_t addr)
++{
++ return P::getP(*(uint64_t*)localCopy(addr));
++}
++
++template <typename P>
++uint64_t OtherAddressSpace<P>::getULEB128(pint_t& addr, pint_t end)
++{
++ uintptr_t size = (end - addr);
++ LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t)localCopy(addr);
++ LocalAddressSpace::pint_t sladdr = laddr;
++ uint64_t result = LocalAddressSpace::getULEB128(laddr, laddr+size);
++ addr += (laddr-sladdr);
++ return result;
++}
++
++template <typename P>
++int64_t OtherAddressSpace<P>::getSLEB128(pint_t& addr, pint_t end)
++{
++ uintptr_t size = (end - addr);
++ LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t)localCopy(addr);
++ LocalAddressSpace::pint_t sladdr = laddr;
++ uint64_t result = LocalAddressSpace::getSLEB128(laddr, laddr+size);
++ addr += (laddr-sladdr);
++ return result;
++}
++
++template <typename P>
++void* OtherAddressSpace<P>::localCopy(pint_t addr)
++{
++ // FIX ME
++}
++
++template <typename P>
++bool OtherAddressSpace<P>::findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset)
++{
++ // FIX ME
++}
++
++
++
++///
++/// unw_addr_space is the base class that abstract unw_addr_space_t type in libunwind.h points to.
++///
++struct unw_addr_space
++{
++ cpu_type_t cpuType;
++ task_t taskPort;
++};
++
++
++///
++/// unw_addr_space_i386 is the concrete instance that a unw_addr_space_t points to when examining
++/// a 32-bit intel process.
++///
++struct unw_addr_space_i386 : public unw_addr_space
++{
++ unw_addr_space_i386(task_t task) : oas(task) {}
++ OtherAddressSpace<Pointer32<LittleEndian> > oas;
++};
++
++
++///
++/// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t points to when examining
++/// a 64-bit intel process.
++///
++struct unw_addr_space_x86_64 : public unw_addr_space
++{
++ unw_addr_space_x86_64(task_t task) : oas(task) {}
++ OtherAddressSpace<Pointer64<LittleEndian> > oas;
++};
++
++
++///
++/// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points to when examining
++/// a 32-bit PowerPC process.
++///
++struct unw_addr_space_ppc : public unw_addr_space
++{
++ unw_addr_space_ppc(task_t task) : oas(task) {}
++ OtherAddressSpace<Pointer32<BigEndian> > oas;
++};
++
++
++#endif // UNW_REMOTE
++
++
++} // namespace libunwind
++
++
++
++#endif // __ADDRESSSPACE_HPP__
++
++
++
++
+diff --git a/src/ld/parsers/libunwind/DwarfInstructions.hpp b/src/ld/parsers/libunwind/DwarfInstructions.hpp
+new file mode 100644
+index 0000000..b04582d
+--- /dev/null
++++ src/ld/parsers/libunwind/DwarfInstructions.hpp
+@@ -0,0 +1,1726 @@
++/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
++ *
++ * Copyright (c) 2008 Apple Inc. All rights reserved.
++ *
++ * @APPLE_LICENSE_HEADER_START@
++ *
++ * This file contains Original Code and/or Modifications of Original Code
++ * as defined in and that are subject to the Apple Public Source License
++ * Version 2.0 (the 'License'). You may not use this file except in
++ * compliance with the License. Please obtain a copy of the License at
++ * http://www.opensource.apple.com/apsl/ and read it before using this
++ * file.
++ *
++ * The Original Code and all software distributed under the License are
++ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
++ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
++ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
++ * Please see the License for the specific language governing rights and
++ * limitations under the License.
++ *
++ * @APPLE_LICENSE_HEADER_END@
++ */
++
++//
++// processor specific parsing of dwarf unwind instructions
++//
++
++#ifndef __DWARF_INSTRUCTIONS_HPP__
++#define __DWARF_INSTRUCTIONS_HPP__
++
++#include <stdint.h>
++#include <stdio.h>
++#include <stdlib.h>
++
++#include <algorithm>
++#include <vector>
++
++#include <libunwind.h>
++#include <mach-o/compact_unwind_encoding.h>
++
++#include "dwarf2.h"
++#include "AddressSpace.hpp"
++#include "Registers.hpp"
++#include "DwarfParser.hpp"
++#include "InternalMacros.h"
++//#include "CompactUnwinder.hpp"
++
++#define EXTRACT_BITS(value, mask) \
++ ( (value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask)))-1) )
++
++#define CFI_INVALID_ADDRESS ((pint_t)(-1))
++
++namespace libunwind {
++
++///
++/// Used by linker when parsing __eh_frame section
++///
++template <typename A>
++struct CFI_Reference {
++ typedef typename A::pint_t pint_t;
++ uint8_t encodingOfTargetAddress;
++ uint32_t offsetInCFI;
++ pint_t targetAddress;
++};
++template <typename A>
++struct CFI_Atom_Info {
++ typedef typename A::pint_t pint_t;
++ pint_t address;
++ uint32_t size;
++ bool isCIE;
++ union {
++ struct {
++ CFI_Reference<A> function;
++ CFI_Reference<A> cie;
++ CFI_Reference<A> lsda;
++ uint32_t compactUnwindInfo;
++ } fdeInfo;
++ struct {
++ CFI_Reference<A> personality;
++ } cieInfo;
++ } u;
++};
++
++typedef void (*WarnFunc)(void* ref, uint64_t funcAddr, const char* msg);
++
++///
++/// DwarfInstructions maps abtract dwarf unwind instructions to a particular architecture
++///
++template <typename A, typename R>
++class DwarfInstructions
++{
++public:
++ typedef typename A::pint_t pint_t;
++ typedef typename A::sint_t sint_t;
++
++ static const char* parseCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength,
++ CFI_Atom_Info<A>* infos, uint32_t infosCount, void* ref, WarnFunc warn);
++
++
++ static compact_unwind_encoding_t createCompactEncodingFromFDE(A& addressSpace, pint_t fdeStart,
++ pint_t* lsda, pint_t* personality,
++ char warningBuffer[1024]);
++
++ static int stepWithDwarf(A& addressSpace, pint_t pc, pint_t fdeStart, R& registers);
++
++private:
++
++ enum {
++ DW_X86_64_RET_ADDR = 16
++ };
++
++ enum {
++ DW_X86_RET_ADDR = 8
++ };
++
++ static pint_t evaluateExpression(pint_t expression, A& addressSpace, const R& registers, pint_t initialStackValue);
++ static pint_t getSavedRegister(A& addressSpace, const R& registers, pint_t cfa,
++ const typename CFI_Parser<A>::RegisterLocation& savedReg);
++ static double getSavedFloatRegister(A& addressSpace, const R& registers, pint_t cfa,
++ const typename CFI_Parser<A>::RegisterLocation& savedReg);
++ static v128 getSavedVectorRegister(A& addressSpace, const R& registers, pint_t cfa,
++ const typename CFI_Parser<A>::RegisterLocation& savedReg);
++
++ // x86 specific variants
++ static int lastRestoreReg(const Registers_x86&);
++ static bool isReturnAddressRegister(int regNum, const Registers_x86&);
++ static pint_t getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog, const Registers_x86&);
++
++ static uint32_t getEBPEncodedRegister(uint32_t reg, int32_t regOffsetFromBaseOffset, bool& failure);
++ static compact_unwind_encoding_t encodeToUseDwarf(const Registers_x86&);
++ static compact_unwind_encoding_t createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
++ const Registers_x86&, const typename CFI_Parser<A>::PrologInfo& prolog,
++ char warningBuffer[1024]);
++
++ // x86_64 specific variants
++ static int lastRestoreReg(const Registers_x86_64&);
++ static bool isReturnAddressRegister(int regNum, const Registers_x86_64&);
++ static pint_t getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog, const Registers_x86_64&);
++
++ static uint32_t getRBPEncodedRegister(uint32_t reg, int32_t regOffsetFromBaseOffset, bool& failure);
++ static compact_unwind_encoding_t encodeToUseDwarf(const Registers_x86_64&);
++ static compact_unwind_encoding_t createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
++ const Registers_x86_64&, const typename CFI_Parser<A>::PrologInfo& prolog,
++ char warningBuffer[1024]);
++
++ // ppc specific variants
++ static int lastRestoreReg(const Registers_ppc&);
++ static bool isReturnAddressRegister(int regNum, const Registers_ppc&);
++ static pint_t getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog, const Registers_ppc&);
++ static compact_unwind_encoding_t encodeToUseDwarf(const Registers_ppc&);
++ static compact_unwind_encoding_t createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
++ const Registers_ppc&, const typename CFI_Parser<A>::PrologInfo& prolog,
++ char warningBuffer[1024]);
++};
++
++
++
++
++template <typename A, typename R>
++const char* DwarfInstructions<A,R>::parseCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength,
++ CFI_Atom_Info<A>* infos, uint32_t infosCount, void* ref, WarnFunc warn)
++{
++ typename CFI_Parser<A>::CIE_Info cieInfo;
++ CFI_Atom_Info<A>* entry = infos;
++ CFI_Atom_Info<A>* end = &infos[infosCount];
++ const pint_t ehSectionEnd = ehSectionStart + sectionLength;
++ for (pint_t p=ehSectionStart; p < ehSectionEnd; ) {
++ pint_t currentCFI = p;
++ uint64_t cfiLength = addressSpace.get32(p);
++ p += 4;
++ if ( cfiLength == 0xffffffff ) {
++ // 0xffffffff means length is really next 8 bytes
++ cfiLength = addressSpace.get64(p);
++ p += 8;
++ }
++ if ( cfiLength == 0 )
++ return NULL; // end marker
++ if ( entry >= end )
++ return "too little space allocated for parseCFIs";
++ pint_t nextCFI = p + cfiLength;
++ uint32_t id = addressSpace.get32(p);
++ if ( id == 0 ) {
++ // is CIE
++ const char* err = CFI_Parser<A>::parseCIE(addressSpace, currentCFI, &cieInfo);
++ if ( err != NULL )
++ return err;
++ entry->address = currentCFI;
++ entry->size = nextCFI - currentCFI;
++ entry->isCIE = true;
++ entry->u.cieInfo.personality.targetAddress = cieInfo.personality;
++ entry->u.cieInfo.personality.offsetInCFI = cieInfo.personalityOffsetInCIE;
++ entry->u.cieInfo.personality.encodingOfTargetAddress = cieInfo.personalityEncoding;
++ ++entry;
++ }
++ else {
++ // is FDE
++ entry->address = currentCFI;
++ entry->size = nextCFI - currentCFI;
++ entry->isCIE = false;
++ entry->u.fdeInfo.function.targetAddress = CFI_INVALID_ADDRESS;
++ entry->u.fdeInfo.cie.targetAddress = CFI_INVALID_ADDRESS;
++ entry->u.fdeInfo.lsda.targetAddress = CFI_INVALID_ADDRESS;
++ uint32_t ciePointer = addressSpace.get32(p);
++ pint_t cieStart = p-ciePointer;
++ // validate pointer to CIE is within section
++ if ( (cieStart < ehSectionStart) || (cieStart > ehSectionEnd) )
++ return "FDE points to CIE outside __eh_frame section";
++ // optimize usual case where cie is same for all FDEs
++ if ( cieStart != cieInfo.cieStart ) {
++ const char* err = CFI_Parser<A>::parseCIE(addressSpace, cieStart, &cieInfo);
++ if ( err != NULL )
++ return err;
++ }
++ entry->u.fdeInfo.cie.targetAddress = cieStart;
++ entry->u.fdeInfo.cie.offsetInCFI = p-currentCFI;
++ entry->u.fdeInfo.cie.encodingOfTargetAddress = DW_EH_PE_sdata4 | DW_EH_PE_pcrel;
++ p += 4;
++ // parse pc begin and range
++ pint_t offsetOfFunctionAddress = p-currentCFI;
++ pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding);
++ pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding & 0x0F);
++ //fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
++ // test if pc is within the function this FDE covers
++ entry->u.fdeInfo.function.targetAddress = pcStart;
++ entry->u.fdeInfo.function.offsetInCFI = offsetOfFunctionAddress;
++ entry->u.fdeInfo.function.encodingOfTargetAddress = cieInfo.pointerEncoding;
++ // check for augmentation length
++ if ( cieInfo.fdesHaveAugmentationData ) {
++ uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
++ pint_t endOfAug = p + augLen;
++ if ( cieInfo.lsdaEncoding != 0 ) {
++ // peek at value (without indirection). Zero means no lsda
++ pint_t lsdaStart = p;
++ if ( addressSpace.getEncodedP(p, nextCFI, cieInfo.lsdaEncoding & 0x0F) != 0 ) {
++ // reset pointer and re-parse lsda address
++ p = lsdaStart;
++ pint_t offsetOfLSDAAddress = p-currentCFI;
++ entry->u.fdeInfo.lsda.targetAddress = addressSpace.getEncodedP(p, nextCFI, cieInfo.lsdaEncoding);
++ entry->u.fdeInfo.lsda.offsetInCFI = offsetOfLSDAAddress;
++ entry->u.fdeInfo.lsda.encodingOfTargetAddress = cieInfo.lsdaEncoding;
++ }
++ }
++ p = endOfAug;
++ }
++ // compute compact unwind encoding
++ typename CFI_Parser<A>::FDE_Info fdeInfo;
++ fdeInfo.fdeStart = currentCFI;
++ fdeInfo.fdeLength = nextCFI - currentCFI;
++ fdeInfo.fdeInstructions = p;
++ fdeInfo.pcStart = pcStart;
++ fdeInfo.pcEnd = pcStart + pcRange;
++ fdeInfo.lsda = entry->u.fdeInfo.lsda.targetAddress;
++ typename CFI_Parser<A>::PrologInfo prolog;
++ R dummy; // for proper selection of architecture specific functions
++ if ( CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, CFI_INVALID_ADDRESS, &prolog) ) {
++ char warningBuffer[1024];
++ entry->u.fdeInfo.compactUnwindInfo = createCompactEncodingFromProlog(addressSpace, fdeInfo.pcStart, dummy, prolog, warningBuffer);
++ if ( fdeInfo.lsda != CFI_INVALID_ADDRESS )
++ entry->u.fdeInfo.compactUnwindInfo |= UNWIND_HAS_LSDA;
++ if ( warningBuffer[0] != '\0' )
++ warn(ref, fdeInfo.pcStart, warningBuffer);
++ }
++ else {
++ warn(ref, CFI_INVALID_ADDRESS, "dwarf unwind instructions could not be parsed");
++ entry->u.fdeInfo.compactUnwindInfo = encodeToUseDwarf(dummy);
++ }
++ ++entry;
++ }
++ p = nextCFI;
++ }
++ if ( entry != end )
++ return "wrong entry count for parseCFIs";
++ return NULL; // success
++}
++
++
++
++
++template <typename A, typename R>
++compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromFDE(A& addressSpace, pint_t fdeStart,
++ pint_t* lsda, pint_t* personality,
++ char warningBuffer[1024])
++{
++ typename CFI_Parser<A>::FDE_Info fdeInfo;
++ typename CFI_Parser<A>::CIE_Info cieInfo;
++ R dummy; // for proper selection of architecture specific functions
++ if ( CFI_Parser<A>::decodeFDE(addressSpace, fdeStart, &fdeInfo, &cieInfo) == NULL ) {
++ typename CFI_Parser<A>::PrologInfo prolog;
++ if ( CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, CFI_INVALID_ADDRESS, &prolog) ) {
++ *lsda = fdeInfo.lsda;
++ *personality = cieInfo.personality;
++ compact_unwind_encoding_t encoding;
++ encoding = createCompactEncodingFromProlog(addressSpace, fdeInfo.pcStart, dummy, prolog, warningBuffer);
++ if ( fdeInfo.lsda != 0 )
++ encoding |= UNWIND_HAS_LSDA;
++ return encoding;
++ }
++ else {
++ strcpy(warningBuffer, "dwarf unwind instructions could not be parsed");
++ return encodeToUseDwarf(dummy);
++ }
++ }
++ else {
++ strcpy(warningBuffer, "dwarf FDE could not be parsed");
++ return encodeToUseDwarf(dummy);
++ }
++}
++
++
++template <typename A, typename R>
++typename A::pint_t DwarfInstructions<A,R>::getSavedRegister(A& addressSpace, const R& registers, pint_t cfa,
++ const typename CFI_Parser<A>::RegisterLocation& savedReg)
++{
++ switch ( savedReg.location ) {
++ case CFI_Parser<A>::kRegisterInCFA:
++ return addressSpace.getP(cfa + savedReg.value);
++
++ case CFI_Parser<A>::kRegisterAtExpression:
++ return addressSpace.getP(evaluateExpression(savedReg.value, addressSpace, registers, cfa));
++
++ case CFI_Parser<A>::kRegisterIsExpression:
++ return evaluateExpression(savedReg.value, addressSpace, registers, cfa);
++
++ case CFI_Parser<A>::kRegisterInRegister:
++ return registers.getRegister(savedReg.value);
++
++ case CFI_Parser<A>::kRegisterUnused:
++ case CFI_Parser<A>::kRegisterOffsetFromCFA:
++ // FIX ME
++ break;
++ }
++ ABORT("unsupported restore location for register");
++}
++
++template <typename A, typename R>
++double DwarfInstructions<A,R>::getSavedFloatRegister(A& addressSpace, const R& registers, pint_t cfa,
++ const typename CFI_Parser<A>::RegisterLocation& savedReg)
++{
++ switch ( savedReg.location ) {
++ case CFI_Parser<A>::kRegisterInCFA:
++ return addressSpace.getDouble(cfa + savedReg.value);
++
++ case CFI_Parser<A>::kRegisterAtExpression:
++ return addressSpace.getDouble(evaluateExpression(savedReg.value, addressSpace, registers, cfa));
++
++ case CFI_Parser<A>::kRegisterIsExpression:
++ case CFI_Parser<A>::kRegisterUnused:
++ case CFI_Parser<A>::kRegisterOffsetFromCFA:
++ case CFI_Parser<A>::kRegisterInRegister:
++ // FIX ME
++ break;
++ }
++ ABORT("unsupported restore location for float register");
++}
++
++template <typename A, typename R>
++v128 DwarfInstructions<A,R>::getSavedVectorRegister(A& addressSpace, const R& registers, pint_t cfa,
++ const typename CFI_Parser<A>::RegisterLocation& savedReg)
++{
++ switch ( savedReg.location ) {
++ case CFI_Parser<A>::kRegisterInCFA:
++ return addressSpace.getVector(cfa + savedReg.value);
++
++ case CFI_Parser<A>::kRegisterAtExpression:
++ return addressSpace.getVector(evaluateExpression(savedReg.value, addressSpace, registers, cfa));
++
++ case CFI_Parser<A>::kRegisterIsExpression:
++ case CFI_Parser<A>::kRegisterUnused:
++ case CFI_Parser<A>::kRegisterOffsetFromCFA:
++ case CFI_Parser<A>::kRegisterInRegister:
++ // FIX ME
++ break;
++ }
++ ABORT("unsupported restore location for vector register");
++}
++
++
++template <typename A, typename R>
++int DwarfInstructions<A,R>::stepWithDwarf(A& addressSpace, pint_t pc, pint_t fdeStart, R& registers)
++{
++ //fprintf(stderr, "stepWithDwarf(pc=0x%0llX, fdeStart=0x%0llX)\n", (uint64_t)pc, (uint64_t)fdeStart);
++ typename CFI_Parser<A>::FDE_Info fdeInfo;
++ typename CFI_Parser<A>::CIE_Info cieInfo;
++ if ( CFI_Parser<A>::decodeFDE(addressSpace, fdeStart, &fdeInfo, &cieInfo) == NULL ) {
++ typename CFI_Parser<A>::PrologInfo prolog;
++ if ( CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc, &prolog) ) {
++ R newRegisters = registers;
++
++ // get pointer to cfa (architecture specific)
++ pint_t cfa = getCFA(addressSpace, prolog, registers);
++
++ // restore registers that dwarf says were saved
++ pint_t returnAddress = 0;
++ for (int i=0; i <= lastRestoreReg(newRegisters); ++i) {
++ if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) {
++ if ( registers.validFloatRegister(i) )
++ newRegisters.setFloatRegister(i, getSavedFloatRegister(addressSpace, registers, cfa, prolog.savedRegisters[i]));
++ else if ( registers.validVectorRegister(i) )
++ newRegisters.setVectorRegister(i, getSavedVectorRegister(addressSpace, registers, cfa, prolog.savedRegisters[i]));
++ else if ( isReturnAddressRegister(i, registers) )
++ returnAddress = getSavedRegister(addressSpace, registers, cfa, prolog.savedRegisters[i]);
++ else if ( registers.validRegister(i) )
++ newRegisters.setRegister(i, getSavedRegister(addressSpace, registers, cfa, prolog.savedRegisters[i]));
++ else
++ return UNW_EBADREG;
++ }
++ }
++
++ // by definition the CFA is the stack pointer at the call site, so restoring SP means setting it to CFA
++ newRegisters.setSP(cfa);
++
++ // return address is address after call site instruction, so setting IP to that does a return
++ newRegisters.setIP(returnAddress);
++
++ // do the actual step by replacing the register set with the new ones
++ registers = newRegisters;
++
++ return UNW_STEP_SUCCESS;
++ }
++ }
++ return UNW_EBADFRAME;
++}
++
++
++
++template <typename A, typename R>
++typename A::pint_t DwarfInstructions<A,R>::evaluateExpression(pint_t expression, A& addressSpace,
++ const R& registers, pint_t initialStackValue)
++{
++ const bool log = false;
++ pint_t p = expression;
++ pint_t expressionEnd = expression+20; // just need something until length is read
++ uint64_t length = addressSpace.getULEB128(p, expressionEnd);
++ expressionEnd = p + length;
++ if (log) fprintf(stderr, "evaluateExpression(): length=%llu\n", length);
++ pint_t stack[100];
++ pint_t* sp = stack;
++ *(++sp) = initialStackValue;
++
++ while ( p < expressionEnd ) {
++ if (log) {
++ for(pint_t* t = sp; t > stack; --t) {
++ fprintf(stderr, "sp[] = 0x%llX\n", (uint64_t)(*t));
++ }
++ }
++ uint8_t opcode = addressSpace.get8(p++);
++ sint_t svalue;
++ pint_t value;
++ uint32_t reg;
++ switch (opcode) {
++ case DW_OP_addr:
++ // push immediate address sized value
++ value = addressSpace.getP(p);
++ p += sizeof(pint_t);
++ *(++sp) = value;
++ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
++ break;
++
++ case DW_OP_deref:
++ // pop stack, dereference, push result
++ value = *sp--;
++ *(++sp) = addressSpace.getP(value);
++ if (log) fprintf(stderr, "dereference 0x%llX\n", (uint64_t)value);
++ break;
++
++ case DW_OP_const1u:
++ // push immediate 1 byte value
++ value = addressSpace.get8(p);
++ p += 1;
++ *(++sp) = value;
++ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
++ break;
++
++ case DW_OP_const1s:
++ // push immediate 1 byte signed value
++ svalue = (int8_t)addressSpace.get8(p);
++ p += 1;
++ *(++sp) = svalue;
++ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)svalue);
++ break;
++
++ case DW_OP_const2u:
++ // push immediate 2 byte value
++ value = addressSpace.get16(p);
++ p += 2;
++ *(++sp) = value;
++ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
++ break;
++
++ case DW_OP_const2s:
++ // push immediate 2 byte signed value
++ svalue = (int16_t)addressSpace.get16(p);
++ p += 2;
++ *(++sp) = svalue;
++ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)svalue);
++ break;
++
++ case DW_OP_const4u:
++ // push immediate 4 byte value
++ value = addressSpace.get32(p);
++ p += 4;
++ *(++sp) = value;
++ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
++ break;
++
++ case DW_OP_const4s:
++ // push immediate 4 byte signed value
++ svalue = (int32_t)addressSpace.get32(p);
++ p += 4;
++ *(++sp) = svalue;
++ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)svalue);
++ break;
++
++ case DW_OP_const8u:
++ // push immediate 8 byte value
++ value = addressSpace.get64(p);
++ p += 8;
++ *(++sp) = value;
++ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
++ break;
++
++ case DW_OP_const8s:
++ // push immediate 8 byte signed value
++ value = (int32_t)addressSpace.get64(p);
++ p += 8;
++ *(++sp) = value;
++ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
++ break;
++
++ case DW_OP_constu:
++ // push immediate ULEB128 value
++ value = addressSpace.getULEB128(p, expressionEnd);
++ *(++sp) = value;
++ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value);
++ break;
++
++ case DW_OP_consts:
++ // push immediate SLEB128 value
++ svalue = addressSpace.getSLEB128(p, expressionEnd);
++ *(++sp) = svalue;
++ if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)svalue);
++ break;
++
++ case DW_OP_dup:
++ // push top of stack
++ value = *sp;
++ *(++sp) = value;
++ if (log) fprintf(stderr, "duplicate top of stack\n");
++ break;
++
++ case DW_OP_drop:
++ // pop
++ --sp;
++ if (log) fprintf(stderr, "pop top of stack\n");
++ break;
++
++ case DW_OP_over:
++ // dup second
++ value = sp[-1];
++ *(++sp) = value;
++ if (log) fprintf(stderr, "duplicate second in stack\n");
++ break;
++
++ case DW_OP_pick:
++ // pick from
++ reg = addressSpace.get8(p);
++ p += 1;
++ value = sp[-reg];
++ *(++sp) = value;
++ if (log) fprintf(stderr, "duplicate %d in stack\n", reg);
++ break;
++
++ case DW_OP_swap:
++ // swap top two
++ value = sp[0];
++ sp[0] = sp[-1];
++ sp[-1] = value;
++ if (log) fprintf(stderr, "swap top of stack\n");
++ break;
++
++ case DW_OP_rot:
++ // rotate top three
++ value = sp[0];
++ sp[0] = sp[-1];
++ sp[-1] = sp[-2];
++ sp[-2] = value;
++ if (log) fprintf(stderr, "rotate top three of stack\n");
++ break;
++
++ case DW_OP_xderef:
++ // pop stack, dereference, push result
++ value = *sp--;
++ *sp = *((uint64_t*)value);
++ if (log) fprintf(stderr, "x-dereference 0x%llX\n", (uint64_t)value);
++ break;
++
++ case DW_OP_abs:
++ svalue = *sp;
++ if ( svalue < 0 )
++ *sp = -svalue;
++ if (log) fprintf(stderr, "abs\n");
++ break;
++
++ case DW_OP_and:
++ value = *sp--;
++ *sp &= value;
++ if (log) fprintf(stderr, "and\n");
++ break;
++
++ case DW_OP_div:
++ svalue = *sp--;
++ *sp = *sp / svalue;
++ if (log) fprintf(stderr, "div\n");
++ break;
++
++ case DW_OP_minus:
++ svalue = *sp--;
++ *sp = *sp - svalue;
++ if (log) fprintf(stderr, "minus\n");
++ break;
++
++ case DW_OP_mod:
++ svalue = *sp--;
++ *sp = *sp % svalue;
++ if (log) fprintf(stderr, "module\n");
++ break;
++
++ case DW_OP_mul:
++ svalue = *sp--;
++ *sp = *sp * svalue;
++ if (log) fprintf(stderr, "mul\n");
++ break;
++
++ case DW_OP_neg:
++ *sp = 0 - *sp;
++ if (log) fprintf(stderr, "neg\n");
++ break;
++
++ case DW_OP_not:
++ svalue = *sp;
++ *sp = ~svalue;
++ if (log) fprintf(stderr, "not\n");
++ break;
++
++ case DW_OP_or:
++ value = *sp--;
++ *sp |= value;
++ if (log) fprintf(stderr, "or\n");
++ break;
++
++ case DW_OP_plus:
++ value = *sp--;
++ *sp += value;
++ if (log) fprintf(stderr, "plus\n");
++ break;
++
++ case DW_OP_plus_uconst:
++ // pop stack, add uelb128 constant, push result
++ *sp += addressSpace.getULEB128(p, expressionEnd);
++ if (log) fprintf(stderr, "add constant\n");
++ break;
++
++ case DW_OP_shl:
++ value = *sp--;
++ *sp = *sp << value;
++ if (log) fprintf(stderr, "shift left\n");
++ break;
++
++ case DW_OP_shr:
++ value = *sp--;
++ *sp = *sp >> value;
++ if (log) fprintf(stderr, "shift left\n");
++ break;
++
++ case DW_OP_shra:
++ value = *sp--;
++ svalue = *sp;
++ *sp = svalue >> value;
++ if (log) fprintf(stderr, "shift left arithmetric\n");
++ break;
++
++ case DW_OP_xor:
++ value = *sp--;
++ *sp ^= value;
++ if (log) fprintf(stderr, "xor\n");
++ break;
++
++ case DW_OP_skip:
++ svalue = (int16_t)addressSpace.get16(p);
++ p += 2;
++ p += svalue;
++ if (log) fprintf(stderr, "skip %lld\n", (uint64_t)svalue);
++ break;
++
++ case DW_OP_bra:
++ svalue = (int16_t)addressSpace.get16(p);
++ p += 2;
++ if ( *sp-- )
++ p += svalue;
++ if (log) fprintf(stderr, "bra %lld\n", (uint64_t)svalue);
++ break;
++
++ case DW_OP_eq:
++ value = *sp--;
++ *sp = (*sp == value);
++ if (log) fprintf(stderr, "eq\n");
++ break;
++
++ case DW_OP_ge:
++ value = *sp--;
++ *sp = (*sp >= value);
++ if (log) fprintf(stderr, "ge\n");
++ break;
++
++ case DW_OP_gt:
++ value = *sp--;
++ *sp = (*sp > value);
++ if (log) fprintf(stderr, "gt\n");
++ break;
++
++ case DW_OP_le:
++ value = *sp--;
++ *sp = (*sp <= value);
++ if (log) fprintf(stderr, "le\n");
++ break;
++
++ case DW_OP_lt:
++ value = *sp--;
++ *sp = (*sp < value);
++ if (log) fprintf(stderr, "lt\n");
++ break;
++
++ case DW_OP_ne:
++ value = *sp--;
++ *sp = (*sp != value);
++ if (log) fprintf(stderr, "ne\n");
++ break;
++
++ case DW_OP_lit0:
++ case DW_OP_lit1:
++ case DW_OP_lit2:
++ case DW_OP_lit3:
++ case DW_OP_lit4:
++ case DW_OP_lit5:
++ case DW_OP_lit6:
++ case DW_OP_lit7:
++ case DW_OP_lit8:
++ case DW_OP_lit9:
++ case DW_OP_lit10:
++ case DW_OP_lit11:
++ case DW_OP_lit12:
++ case DW_OP_lit13:
++ case DW_OP_lit14:
++ case DW_OP_lit15:
++ case DW_OP_lit16:
++ case DW_OP_lit17:
++ case DW_OP_lit18:
++ case DW_OP_lit19:
++ case DW_OP_lit20:
++ case DW_OP_lit21:
++ case DW_OP_lit22:
++ case DW_OP_lit23:
++ case DW_OP_lit24:
++ case DW_OP_lit25:
++ case DW_OP_lit26:
++ case DW_OP_lit27:
++ case DW_OP_lit28:
++ case DW_OP_lit29:
++ case DW_OP_lit30:
++ case DW_OP_lit31:
++ value = opcode - DW_OP_lit0;
++ *(++sp) = value;
++ if (log) fprintf(stderr, "push literal 0x%llX\n", (uint64_t)value);
++ break;
++
++ case DW_OP_reg0:
++ case DW_OP_reg1:
++ case DW_OP_reg2:
++ case DW_OP_reg3:
++ case DW_OP_reg4:
++ case DW_OP_reg5:
++ case DW_OP_reg6:
++ case DW_OP_reg7:
++ case DW_OP_reg8:
++ case DW_OP_reg9:
++ case DW_OP_reg10:
++ case DW_OP_reg11:
++ case DW_OP_reg12:
++ case DW_OP_reg13:
++ case DW_OP_reg14:
++ case DW_OP_reg15:
++ case DW_OP_reg16:
++ case DW_OP_reg17:
++ case DW_OP_reg18:
++ case DW_OP_reg19:
++ case DW_OP_reg20:
++ case DW_OP_reg21:
++ case DW_OP_reg22:
++ case DW_OP_reg23:
++ case DW_OP_reg24:
++ case DW_OP_reg25:
++ case DW_OP_reg26:
++ case DW_OP_reg27:
++ case DW_OP_reg28:
++ case DW_OP_reg29:
++ case DW_OP_reg30:
++ case DW_OP_reg31:
++ reg = opcode - DW_OP_reg0;
++ *(++sp) = registers.getRegister(reg);
++ if (log) fprintf(stderr, "push reg %d\n", reg);
++ break;
++
++ case DW_OP_regx:
++ reg = addressSpace.getULEB128(p, expressionEnd);
++ *(++sp) = registers.getRegister(reg);
++ if (log) fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t)svalue);
++ break;
++
++ case DW_OP_breg0:
++ case DW_OP_breg1:
++ case DW_OP_breg2:
++ case DW_OP_breg3:
++ case DW_OP_breg4:
++ case DW_OP_breg5:
++ case DW_OP_breg6:
++ case DW_OP_breg7:
++ case DW_OP_breg8:
++ case DW_OP_breg9:
++ case DW_OP_breg10:
++ case DW_OP_breg11:
++ case DW_OP_breg12:
++ case DW_OP_breg13:
++ case DW_OP_breg14:
++ case DW_OP_breg15:
++ case DW_OP_breg16:
++ case DW_OP_breg17:
++ case DW_OP_breg18:
++ case DW_OP_breg19:
++ case DW_OP_breg20:
++ case DW_OP_breg21:
++ case DW_OP_breg22:
++ case DW_OP_breg23:
++ case DW_OP_breg24:
++ case DW_OP_breg25:
++ case DW_OP_breg26:
++ case DW_OP_breg27:
++ case DW_OP_breg28:
++ case DW_OP_breg29:
++ case DW_OP_breg30:
++ case DW_OP_breg31:
++ reg = opcode - DW_OP_breg0;
++ svalue = addressSpace.getSLEB128(p, expressionEnd);
++ *(++sp) = registers.getRegister(reg) + svalue;
++ if (log) fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t)svalue);
++ break;
++
++ case DW_OP_bregx:
++ reg = addressSpace.getULEB128(p, expressionEnd);
++ svalue = addressSpace.getSLEB128(p, expressionEnd);
++ *(++sp) = registers.getRegister(reg) + svalue;
++ if (log) fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t)svalue);
++ break;
++
++ case DW_OP_fbreg:
++ ABORT("DW_OP_fbreg not implemented");
++ break;
++
++ case DW_OP_piece:
++ ABORT("DW_OP_piece not implemented");
++ break;
++
++ case DW_OP_deref_size:
++ // pop stack, dereference, push result
++ value = *sp--;
++ switch ( addressSpace.get8(p++) ) {
++ case 1:
++ value = addressSpace.get8(value);
++ break;
++ case 2:
++ value = addressSpace.get16(value);
++ break;
++ case 4:
++ value = addressSpace.get32(value);
++ break;
++ case 8:
++ value = addressSpace.get64(value);
++ break;
++ default:
++ ABORT("DW_OP_deref_size with bad size");
++ }
++ *(++sp) = value;
++ if (log) fprintf(stderr, "sized dereference 0x%llX\n", (uint64_t)value);
++ break;
++
++ case DW_OP_xderef_size:
++ case DW_OP_nop:
++ case DW_OP_push_object_addres:
++ case DW_OP_call2:
++ case DW_OP_call4:
++ case DW_OP_call_ref:
++ default:
++ ABORT("dwarf opcode not implemented");
++ }
++
++ }
++ if (log) fprintf(stderr, "expression evaluates to 0x%llX\n", (uint64_t)*sp);
++ return *sp;
++}
++
++
++
++//
++// x86_64 specific functions
++//
++
++template <typename A, typename R>
++int DwarfInstructions<A,R>::lastRestoreReg(const Registers_x86_64&)
++{
++ COMPILE_TIME_ASSERT( (int)CFI_Parser<A>::kMaxRegisterNumber > (int)DW_X86_64_RET_ADDR );
++ return DW_X86_64_RET_ADDR;
++}
++
++template <typename A, typename R>
++bool DwarfInstructions<A,R>::isReturnAddressRegister(int regNum, const Registers_x86_64&)
++{
++ return (regNum == DW_X86_64_RET_ADDR);
++}
++
++template <typename A, typename R>
++typename A::pint_t DwarfInstructions<A,R>::getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog,
++ const Registers_x86_64& registers)
++{
++ if ( prolog.cfaRegister != 0 )
++ return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset;
++ else if ( prolog.cfaExpression != 0 )
++ return evaluateExpression(prolog.cfaExpression, addressSpace, registers, 0);
++ else
++ ABORT("getCFA(): unknown location for x86_64 cfa");
++}
++
++
++
++template <typename A, typename R>
++compact_unwind_encoding_t DwarfInstructions<A,R>::encodeToUseDwarf(const Registers_x86_64&)
++{
++ return UNWIND_X86_64_MODE_DWARF;
++}
++
++template <typename A, typename R>
++compact_unwind_encoding_t DwarfInstructions<A,R>::encodeToUseDwarf(const Registers_x86&)
++{
++ return UNWIND_X86_MODE_DWARF;
++}
++
++
++
++template <typename A, typename R>
++uint32_t DwarfInstructions<A,R>::getRBPEncodedRegister(uint32_t reg, int32_t regOffsetFromBaseOffset, bool& failure)
++{
++ if ( (regOffsetFromBaseOffset < 0) || (regOffsetFromBaseOffset > 32) ) {
++ failure = true;
++ return 0;
++ }
++ unsigned int slotIndex = regOffsetFromBaseOffset/8;
++
++ switch ( reg ) {
++ case UNW_X86_64_RBX:
++ return UNWIND_X86_64_REG_RBX << (slotIndex*3);
++ case UNW_X86_64_R12:
++ return UNWIND_X86_64_REG_R12 << (slotIndex*3);
++ case UNW_X86_64_R13:
++ return UNWIND_X86_64_REG_R13 << (slotIndex*3);
++ case UNW_X86_64_R14:
++ return UNWIND_X86_64_REG_R14 << (slotIndex*3);
++ case UNW_X86_64_R15:
++ return UNWIND_X86_64_REG_R15 << (slotIndex*3);
++ }
++
++ // invalid register
++ failure = true;
++ return 0;
++}
++
++
++
++template <typename A, typename R>
++compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
++ const Registers_x86_64& r, const typename CFI_Parser<A>::PrologInfo& prolog,
++ char warningBuffer[1024])
++{
++ warningBuffer[0] = '\0';
++
++ if ( prolog.registerSavedTwiceInCIE == DW_X86_64_RET_ADDR ) {
++ warningBuffer[0] = '\0'; // silently disable conversion to compact unwind by linker
++ return UNWIND_X86_64_MODE_DWARF;
++ }
++ // don't create compact unwind info for unsupported dwarf kinds
++ if ( prolog.registerSavedMoreThanOnce ) {
++ strcpy(warningBuffer, "register saved more than once (might be shrink wrap)");
++ return UNWIND_X86_64_MODE_DWARF;
++ }
++ if ( prolog.cfaOffsetWasNegative ) {
++ strcpy(warningBuffer, "cfa had negative offset (dwarf might contain epilog)");
++ return UNWIND_X86_64_MODE_DWARF;
++ }
++ if ( prolog.spExtraArgSize != 0 ) {
++ strcpy(warningBuffer, "dwarf uses DW_CFA_GNU_args_size");
++ return UNWIND_X86_64_MODE_DWARF;
++ }
++ if ( prolog.sameValueUsed ) {
++ strcpy(warningBuffer, "dwarf uses DW_CFA_same_value");
++ return UNWIND_X86_64_MODE_DWARF;
++ }
++
++ // figure out which kind of frame this function uses
++ bool standardRBPframe = (
++ (prolog.cfaRegister == UNW_X86_64_RBP)
++ && (prolog.cfaRegisterOffset == 16)
++ && (prolog.savedRegisters[UNW_X86_64_RBP].location == CFI_Parser<A>::kRegisterInCFA)
++ && (prolog.savedRegisters[UNW_X86_64_RBP].value == -16) );
++ bool standardRSPframe = (prolog.cfaRegister == UNW_X86_64_RSP);
++ if ( !standardRBPframe && !standardRSPframe ) {
++ // no compact encoding for this
++ strcpy(warningBuffer, "does not use RBP or RSP based frame");
++ return UNWIND_X86_64_MODE_DWARF;
++ }
++
++ // scan which registers are saved
++ int saveRegisterCount = 0;
++ bool rbxSaved = false;
++ bool r12Saved = false;
++ bool r13Saved = false;
++ bool r14Saved = false;
++ bool r15Saved = false;
++ bool rbpSaved = false;
++ for (int i=0; i < 64; ++i) {
++ if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) {
++ if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterInCFA ) {
++ sprintf(warningBuffer, "register %d saved somewhere other that in frame", i);
++ return UNWIND_X86_64_MODE_DWARF;
++ }
++ switch (i) {
++ case UNW_X86_64_RBX:
++ rbxSaved = true;
++ ++saveRegisterCount;
++ break;
++ case UNW_X86_64_R12:
++ r12Saved = true;
++ ++saveRegisterCount;
++ break;
++ case UNW_X86_64_R13:
++ r13Saved = true;
++ ++saveRegisterCount;
++ break;
++ case UNW_X86_64_R14:
++ r14Saved = true;
++ ++saveRegisterCount;
++ break;
++ case UNW_X86_64_R15:
++ r15Saved = true;
++ ++saveRegisterCount;
++ break;
++ case UNW_X86_64_RBP:
++ rbpSaved = true;
++ ++saveRegisterCount;
++ break;
++ case DW_X86_64_RET_ADDR:
++ break;
++ default:
++ sprintf(warningBuffer, "non-standard register %d being saved in prolog", i);
++ return UNWIND_X86_64_MODE_DWARF;
++ }
++ }
++ }
++ const int64_t cfaOffsetRBX = prolog.savedRegisters[UNW_X86_64_RBX].value;
++ const int64_t cfaOffsetR12 = prolog.savedRegisters[UNW_X86_64_R12].value;
++ const int64_t cfaOffsetR13 = prolog.savedRegisters[UNW_X86_64_R13].value;
++ const int64_t cfaOffsetR14 = prolog.savedRegisters[UNW_X86_64_R14].value;
++ const int64_t cfaOffsetR15 = prolog.savedRegisters[UNW_X86_64_R15].value;
++ const int64_t cfaOffsetRBP = prolog.savedRegisters[UNW_X86_64_RBP].value;
++
++ // encode standard RBP frames
++ compact_unwind_encoding_t encoding = 0;
++ if ( standardRBPframe ) {
++ // | |
++ // +--------------+ <- CFA
++ // | ret addr |
++ // +--------------+
++ // | rbp |
++ // +--------------+ <- rbp
++ // ~ ~
++ // +--------------+
++ // | saved reg3 |
++ // +--------------+ <- CFA - offset+16
++ // | saved reg2 |
++ // +--------------+ <- CFA - offset+8
++ // | saved reg1 |
++ // +--------------+ <- CFA - offset
++ // | |
++ // +--------------+
++ // | |
++ // <- rsp
++ //
++ encoding = UNWIND_X86_64_MODE_RBP_FRAME;
++
++ // find save location of farthest register from rbp
++ int furthestCfaOffset = 0;
++ if ( rbxSaved & (cfaOffsetRBX < furthestCfaOffset) )
++ furthestCfaOffset = cfaOffsetRBX;
++ if ( r12Saved & (cfaOffsetR12 < furthestCfaOffset) )
++ furthestCfaOffset = cfaOffsetR12;
++ if ( r13Saved & (cfaOffsetR13 < furthestCfaOffset) )
++ furthestCfaOffset = cfaOffsetR13;
++ if ( r14Saved & (cfaOffsetR14 < furthestCfaOffset) )
++ furthestCfaOffset = cfaOffsetR14;
++ if ( r15Saved & (cfaOffsetR15 < furthestCfaOffset) )
++ furthestCfaOffset = cfaOffsetR15;
++
++ if ( furthestCfaOffset == 0 ) {
++ // no registers saved, nothing more to encode
++ return encoding;
++ }
++
++ // add stack offset to encoding
++ int rbpOffset = furthestCfaOffset + 16;
++ int encodedOffset = rbpOffset/(-8);
++ if ( encodedOffset > 255 ) {
++ strcpy(warningBuffer, "offset of saved registers too far to encode");
++ return UNWIND_X86_64_MODE_DWARF;
++ }
++ encoding |= (encodedOffset << __builtin_ctz(UNWIND_X86_64_RBP_FRAME_OFFSET));
++
++ // add register saved from each stack location
++ bool encodingFailure = false;
++ if ( rbxSaved )
++ encoding |= getRBPEncodedRegister(UNW_X86_64_RBX, cfaOffsetRBX - furthestCfaOffset, encodingFailure);
++ if ( r12Saved )
++ encoding |= getRBPEncodedRegister(UNW_X86_64_R12, cfaOffsetR12 - furthestCfaOffset, encodingFailure);
++ if ( r13Saved )
++ encoding |= getRBPEncodedRegister(UNW_X86_64_R13, cfaOffsetR13 - furthestCfaOffset, encodingFailure);
++ if ( r14Saved )
++ encoding |= getRBPEncodedRegister(UNW_X86_64_R14, cfaOffsetR14 - furthestCfaOffset, encodingFailure);
++ if ( r15Saved )
++ encoding |= getRBPEncodedRegister(UNW_X86_64_R15, cfaOffsetR15 - furthestCfaOffset, encodingFailure);
++
++ if ( encodingFailure ){
++ strcpy(warningBuffer, "saved registers not contiguous");
++ return UNWIND_X86_64_MODE_DWARF;
++ }
++
++ return encoding;
++ }
++ else {
++ // | |
++ // +--------------+ <- CFA
++ // | ret addr |
++ // +--------------+
++ // | saved reg1 |
++ // +--------------+ <- CFA - 16
++ // | saved reg2 |
++ // +--------------+ <- CFA - 24
++ // | saved reg3 |
++ // +--------------+ <- CFA - 32
++ // | saved reg4 |
++ // +--------------+ <- CFA - 40
++ // | saved reg5 |
++ // +--------------+ <- CFA - 48
++ // | saved reg6 |
++ // +--------------+ <- CFA - 56
++ // | |
++ // <- esp
++ //
++
++ // for RSP based frames we need to encode stack size in unwind info
++ encoding = UNWIND_X86_64_MODE_STACK_IMMD;
++ uint64_t stackValue = prolog.cfaRegisterOffset / 8;
++ uint32_t stackAdjust = 0;
++ bool immedStackSize = true;
++ const uint32_t stackMaxImmedValue = EXTRACT_BITS(0xFFFFFFFF,UNWIND_X86_64_FRAMELESS_STACK_SIZE);
++ if ( stackValue > stackMaxImmedValue ) {
++ // stack size is too big to fit as an immediate value, so encode offset of subq instruction in function
++ if ( prolog.codeOffsetAtStackDecrement == 0 ) {
++ strcpy(warningBuffer, "stack size is large but stack subq instruction not found");
++ return UNWIND_X86_64_MODE_DWARF;
++ }
++ pint_t functionContentAdjustStackIns = funcAddr + prolog.codeOffsetAtStackDecrement - 4;
++ try {
++ uint32_t stackDecrementInCode = addressSpace.get32(functionContentAdjustStackIns);
++ stackAdjust = (prolog.cfaRegisterOffset - stackDecrementInCode)/8;
++ }
++ catch (...) {
++ strcpy(warningBuffer, "stack size is large but stack subq instruction not found");
++ return UNWIND_X86_64_MODE_DWARF;
++ }
++ stackValue = functionContentAdjustStackIns - funcAddr;
++ immedStackSize = false;
++ if ( stackAdjust > 7 ) {
++ strcpy(warningBuffer, "stack subq instruction is too different from dwarf stack size");
++ return UNWIND_X86_64_MODE_DWARF;
++ }
++ encoding = UNWIND_X86_64_MODE_STACK_IND;
++ }
++
++
++ // validate that saved registers are all within 6 slots abutting return address
++ int registers[6];
++ for (int i=0; i < 6;++i)
++ registers[i] = 0;
++ if ( r15Saved ) {
++ if ( cfaOffsetR15 < -56 ) {
++ strcpy(warningBuffer, "r15 is saved too far from return address");
++ return UNWIND_X86_64_MODE_DWARF;
++ }
++ registers[(cfaOffsetR15+56)/8] = UNWIND_X86_64_REG_R15;
++ }
++ if ( r14Saved ) {
++ if ( cfaOffsetR14 < -56 ) {
++ strcpy(warningBuffer, "r14 is saved too far from return address");
++ return UNWIND_X86_64_MODE_DWARF;
++ }
++ registers[(cfaOffsetR14+56)/8] = UNWIND_X86_64_REG_R14;
++ }
++ if ( r13Saved ) {
++ if ( cfaOffsetR13 < -56 ) {
++ strcpy(warningBuffer, "r13 is saved too far from return address");
++ return UNWIND_X86_64_MODE_DWARF;
++ }
++ registers[(cfaOffsetR13+56)/8] = UNWIND_X86_64_REG_R13;
++ }
++ if ( r12Saved ) {
++ if ( cfaOffsetR12 < -56 ) {
++ strcpy(warningBuffer, "r12 is saved too far from return address");
++ return UNWIND_X86_64_MODE_DWARF;
++ }
++ registers[(cfaOffsetR12+56)/8] = UNWIND_X86_64_REG_R12;
++ }
++ if ( rbxSaved ) {
++ if ( cfaOffsetRBX < -56 ) {
++ strcpy(warningBuffer, "rbx is saved too far from return address");
++ return UNWIND_X86_64_MODE_DWARF;
++ }
++ registers[(cfaOffsetRBX+56)/8] = UNWIND_X86_64_REG_RBX;
++ }
++ if ( rbpSaved ) {
++ if ( cfaOffsetRBP < -56 ) {
++ strcpy(warningBuffer, "rbp is saved too far from return address");
++ return UNWIND_X86_64_MODE_DWARF;
++ }
++ registers[(cfaOffsetRBP+56)/8] = UNWIND_X86_64_REG_RBP;
++ }
++
++ // validate that saved registers are contiguous and abut return address on stack
++ for (int i=0; i < saveRegisterCount; ++i) {
++ if ( registers[5-i] == 0 ) {
++ strcpy(warningBuffer, "registers not save contiguously in stack");
++ return UNWIND_X86_64_MODE_DWARF;
++ }
++ }
++
++ // encode register permutation
++ // the 10-bits are encoded differently depending on the number of registers saved
++ int renumregs[6];
++ for (int i=6-saveRegisterCount; i < 6; ++i) {
++ int countless = 0;
++ for (int j=6-saveRegisterCount; j < i; ++j) {
++ if ( registers[j] < registers[i] )
++ ++countless;
++ }
++ renumregs[i] = registers[i] - countless -1;
++ }
++ uint32_t permutationEncoding = 0;
++ switch ( saveRegisterCount ) {
++ case 6:
++ permutationEncoding |= (120*renumregs[0] + 24*renumregs[1] + 6*renumregs[2] + 2*renumregs[3] + renumregs[4]);
++ break;
++ case 5:
++ permutationEncoding |= (120*renumregs[1] + 24*renumregs[2] + 6*renumregs[3] + 2*renumregs[4] + renumregs[5]);
++ break;
++ case 4:
++ permutationEncoding |= (60*renumregs[2] + 12*renumregs[3] + 3*renumregs[4] + renumregs[5]);
++ break;
++ case 3:
++ permutationEncoding |= (20*renumregs[3] + 4*renumregs[4] + renumregs[5]);
++ break;
++ case 2:
++ permutationEncoding |= (5*renumregs[4] + renumregs[5]);
++ break;
++ case 1:
++ permutationEncoding |= (renumregs[5]);
++ break;
++ }
++
++ encoding |= (stackValue << __builtin_ctz(UNWIND_X86_64_FRAMELESS_STACK_SIZE));
++ encoding |= (stackAdjust << __builtin_ctz(UNWIND_X86_64_FRAMELESS_STACK_ADJUST));
++ encoding |= (saveRegisterCount << __builtin_ctz(UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT));
++ encoding |= (permutationEncoding << __builtin_ctz(UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION));
++ return encoding;
++ }
++}
++
++
++
++
++//
++// x86 specific functions
++//
++template <typename A, typename R>
++int DwarfInstructions<A,R>::lastRestoreReg(const Registers_x86&)
++{
++ COMPILE_TIME_ASSERT( (int)CFI_Parser<A>::kMaxRegisterNumber > (int)DW_X86_RET_ADDR );
++ return DW_X86_RET_ADDR;
++}
++
++template <typename A, typename R>
++bool DwarfInstructions<A,R>::isReturnAddressRegister(int regNum, const Registers_x86&)
++{
++ return (regNum == DW_X86_RET_ADDR);
++}
++
++template <typename A, typename R>
++typename A::pint_t DwarfInstructions<A,R>::getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog,
++ const Registers_x86& registers)
++{
++ if ( prolog.cfaRegister != 0 )
++ return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset;
++ else if ( prolog.cfaExpression != 0 )
++ return evaluateExpression(prolog.cfaExpression, addressSpace, registers, 0);
++ else
++ ABORT("getCFA(): unknown location for x86 cfa");
++}
++
++
++
++
++
++template <typename A, typename R>
++uint32_t DwarfInstructions<A,R>::getEBPEncodedRegister(uint32_t reg, int32_t regOffsetFromBaseOffset, bool& failure)
++{
++ if ( (regOffsetFromBaseOffset < 0) || (regOffsetFromBaseOffset > 16) ) {
++ failure = true;
++ return 0;
++ }
++ unsigned int slotIndex = regOffsetFromBaseOffset/4;
++
++ switch ( reg ) {
++ case UNW_X86_EBX:
++ return UNWIND_X86_REG_EBX << (slotIndex*3);
++ case UNW_X86_ECX:
++ return UNWIND_X86_REG_ECX << (slotIndex*3);
++ case UNW_X86_EDX:
++ return UNWIND_X86_REG_EDX << (slotIndex*3);
++ case UNW_X86_EDI:
++ return UNWIND_X86_REG_EDI << (slotIndex*3);
++ case UNW_X86_ESI:
++ return UNWIND_X86_REG_ESI << (slotIndex*3);
++ }
++
++ // invalid register
++ failure = true;
++ return 0;
++}
++
++template <typename A, typename R>
++compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
++ const Registers_x86& r, const typename CFI_Parser<A>::PrologInfo& prolog,
++ char warningBuffer[1024])
++{
++ warningBuffer[0] = '\0';
++
++ if ( prolog.registerSavedTwiceInCIE == DW_X86_RET_ADDR ) {
++ warningBuffer[0] = '\0'; // silently disable conversion to compact unwind by linker
++ return UNWIND_X86_64_MODE_DWARF;
++ }
++ // don't create compact unwind info for unsupported dwarf kinds
++ if ( prolog.registerSavedMoreThanOnce ) {
++ strcpy(warningBuffer, "register saved more than once (might be shrink wrap)");
++ return UNWIND_X86_MODE_DWARF;
++ }
++ if ( prolog.spExtraArgSize != 0 ) {
++ strcpy(warningBuffer, "dwarf uses DW_CFA_GNU_args_size");
++ return UNWIND_X86_MODE_DWARF;
++ }
++ if ( prolog.sameValueUsed ) {
++ strcpy(warningBuffer, "dwarf uses DW_CFA_same_value");
++ return UNWIND_X86_MODE_DWARF;
++ }
++
++ // figure out which kind of frame this function uses
++ bool standardEBPframe = (
++ (prolog.cfaRegister == UNW_X86_EBP)
++ && (prolog.cfaRegisterOffset == 8)
++ && (prolog.savedRegisters[UNW_X86_EBP].location == CFI_Parser<A>::kRegisterInCFA)
++ && (prolog.savedRegisters[UNW_X86_EBP].value == -8) );
++ bool standardESPframe = (prolog.cfaRegister == UNW_X86_ESP);
++ if ( !standardEBPframe && !standardESPframe ) {
++ // no compact encoding for this
++ strcpy(warningBuffer, "does not use EBP or ESP based frame");
++ return UNWIND_X86_MODE_DWARF;
++ }
++
++ // scan which registers are saved
++ int saveRegisterCount = 0;
++ bool ebxSaved = false;
++ bool ecxSaved = false;
++ bool edxSaved = false;
++ bool esiSaved = false;
++ bool ediSaved = false;
++ bool ebpSaved = false;
++ for (int i=0; i < 64; ++i) {
++ if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) {
++ if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterInCFA ) {
++ sprintf(warningBuffer, "register %d saved somewhere other that in frame", i);
++ return UNWIND_X86_MODE_DWARF;
++ }
++ switch (i) {
++ case UNW_X86_EBX:
++ ebxSaved = true;
++ ++saveRegisterCount;
++ break;
++ case UNW_X86_ECX:
++ ecxSaved = true;
++ ++saveRegisterCount;
++ break;
++ case UNW_X86_EDX:
++ edxSaved = true;
++ ++saveRegisterCount;
++ break;
++ case UNW_X86_ESI:
++ esiSaved = true;
++ ++saveRegisterCount;
++ break;
++ case UNW_X86_EDI:
++ ediSaved = true;
++ ++saveRegisterCount;
++ break;
++ case UNW_X86_EBP:
++ ebpSaved = true;
++ ++saveRegisterCount;
++ break;
++ case DW_X86_RET_ADDR:
++ break;
++ default:
++ sprintf(warningBuffer, "non-standard register %d being saved in prolog", i);
++ return UNWIND_X86_MODE_DWARF;
++ }
++ }
++ }
++ const int32_t cfaOffsetEBX = prolog.savedRegisters[UNW_X86_EBX].value;
++ const int32_t cfaOffsetECX = prolog.savedRegisters[UNW_X86_ECX].value;
++ const int32_t cfaOffsetEDX = prolog.savedRegisters[UNW_X86_EDX].value;
++ const int32_t cfaOffsetEDI = prolog.savedRegisters[UNW_X86_EDI].value;
++ const int32_t cfaOffsetESI = prolog.savedRegisters[UNW_X86_ESI].value;
++ const int32_t cfaOffsetEBP = prolog.savedRegisters[UNW_X86_EBP].value;
++
++ // encode standard RBP frames
++ compact_unwind_encoding_t encoding = 0;
++ if ( standardEBPframe ) {
++ // | |
++ // +--------------+ <- CFA
++ // | ret addr |
++ // +--------------+
++ // | ebp |
++ // +--------------+ <- ebp
++ // ~ ~
++ // +--------------+
++ // | saved reg3 |
++ // +--------------+ <- CFA - offset+8
++ // | saved reg2 |
++ // +--------------+ <- CFA - offset+e
++ // | saved reg1 |
++ // +--------------+ <- CFA - offset
++ // | |
++ // +--------------+
++ // | |
++ // <- esp
++ //
++ encoding = UNWIND_X86_MODE_EBP_FRAME;
++
++ // find save location of farthest register from ebp
++ int furthestCfaOffset = 0;
++ if ( ebxSaved & (cfaOffsetEBX < furthestCfaOffset) )
++ furthestCfaOffset = cfaOffsetEBX;
++ if ( ecxSaved & (cfaOffsetECX < furthestCfaOffset) )
++ furthestCfaOffset = cfaOffsetECX;
++ if ( edxSaved & (cfaOffsetEDX < furthestCfaOffset) )
++ furthestCfaOffset = cfaOffsetEDX;
++ if ( ediSaved & (cfaOffsetEDI < furthestCfaOffset) )
++ furthestCfaOffset = cfaOffsetEDI;
++ if ( esiSaved & (cfaOffsetESI < furthestCfaOffset) )
++ furthestCfaOffset = cfaOffsetESI;
++
++ if ( furthestCfaOffset == 0 ) {
++ // no registers saved, nothing more to encode
++ return encoding;
++ }
++
++ // add stack offset to encoding
++ int ebpOffset = furthestCfaOffset + 8;
++ int encodedOffset = ebpOffset/(-4);
++ if ( encodedOffset > 255 ) {
++ strcpy(warningBuffer, "offset of saved registers too far to encode");
++ return UNWIND_X86_MODE_DWARF;
++ }
++ encoding |= (encodedOffset << __builtin_ctz(UNWIND_X86_EBP_FRAME_OFFSET));
++
++ // add register saved from each stack location
++ bool encodingFailure = false;
++ if ( ebxSaved )
++ encoding |= getEBPEncodedRegister(UNW_X86_EBX, cfaOffsetEBX - furthestCfaOffset, encodingFailure);
++ if ( ecxSaved )
++ encoding |= getEBPEncodedRegister(UNW_X86_ECX, cfaOffsetECX - furthestCfaOffset, encodingFailure);
++ if ( edxSaved )
++ encoding |= getEBPEncodedRegister(UNW_X86_EDX, cfaOffsetEDX - furthestCfaOffset, encodingFailure);
++ if ( ediSaved )
++ encoding |= getEBPEncodedRegister(UNW_X86_EDI, cfaOffsetEDI - furthestCfaOffset, encodingFailure);
++ if ( esiSaved )
++ encoding |= getEBPEncodedRegister(UNW_X86_ESI, cfaOffsetESI - furthestCfaOffset, encodingFailure);
++
++ if ( encodingFailure ){
++ strcpy(warningBuffer, "saved registers not contiguous");
++ return UNWIND_X86_MODE_DWARF;
++ }
++
++ return encoding;
++ }
++ else {
++ // | |
++ // +--------------+ <- CFA
++ // | ret addr |
++ // +--------------+
++ // | saved reg1 |
++ // +--------------+ <- CFA - 8
++ // | saved reg2 |
++ // +--------------+ <- CFA - 12
++ // | saved reg3 |
++ // +--------------+ <- CFA - 16
++ // | saved reg4 |
++ // +--------------+ <- CFA - 20
++ // | saved reg5 |
++ // +--------------+ <- CFA - 24
++ // | saved reg6 |
++ // +--------------+ <- CFA - 28
++ // | |
++ // <- esp
++ //
++
++ // for ESP based frames we need to encode stack size in unwind info
++ encoding = UNWIND_X86_MODE_STACK_IMMD;
++ uint64_t stackValue = prolog.cfaRegisterOffset / 4;
++ uint32_t stackAdjust = 0;
++ bool immedStackSize = true;
++ const uint32_t stackMaxImmedValue = EXTRACT_BITS(0xFFFFFFFF,UNWIND_X86_FRAMELESS_STACK_SIZE);
++ if ( stackValue > stackMaxImmedValue ) {
++ // stack size is too big to fit as an immediate value, so encode offset of subq instruction in function
++ pint_t functionContentAdjustStackIns = funcAddr + prolog.codeOffsetAtStackDecrement - 4;
++ uint32_t stackDecrementInCode = addressSpace.get32(functionContentAdjustStackIns);
++ stackAdjust = (prolog.cfaRegisterOffset - stackDecrementInCode)/4;
++ stackValue = functionContentAdjustStackIns - funcAddr;
++ immedStackSize = false;
++ if ( stackAdjust > 7 ) {
++ strcpy(warningBuffer, "stack subq instruction is too different from dwarf stack size");
++ return UNWIND_X86_MODE_DWARF;
++ }
++ encoding = UNWIND_X86_MODE_STACK_IND;
++ }
++
++
++ // validate that saved registers are all within 6 slots abutting return address
++ int registers[6];
++ for (int i=0; i < 6;++i)
++ registers[i] = 0;
++ if ( ebxSaved ) {
++ if ( cfaOffsetEBX < -28 ) {
++ strcpy(warningBuffer, "ebx is saved too far from return address");
++ return UNWIND_X86_MODE_DWARF;
++ }
++ registers[(cfaOffsetEBX+28)/4] = UNWIND_X86_REG_EBX;
++ }
++ if ( ecxSaved ) {
++ if ( cfaOffsetECX < -28 ) {
++ strcpy(warningBuffer, "ecx is saved too far from return address");
++ return UNWIND_X86_MODE_DWARF;
++ }
++ registers[(cfaOffsetECX+28)/4] = UNWIND_X86_REG_ECX;
++ }
++ if ( edxSaved ) {
++ if ( cfaOffsetEDX < -28 ) {
++ strcpy(warningBuffer, "edx is saved too far from return address");
++ return UNWIND_X86_MODE_DWARF;
++ }
++ registers[(cfaOffsetEDX+28)/4] = UNWIND_X86_REG_EDX;
++ }
++ if ( ediSaved ) {
++ if ( cfaOffsetEDI < -28 ) {
++ strcpy(warningBuffer, "edi is saved too far from return address");
++ return UNWIND_X86_MODE_DWARF;
++ }
++ registers[(cfaOffsetEDI+28)/4] = UNWIND_X86_REG_EDI;
++ }
++ if ( esiSaved ) {
++ if ( cfaOffsetESI < -28 ) {
++ strcpy(warningBuffer, "esi is saved too far from return address");
++ return UNWIND_X86_MODE_DWARF;
++ }
++ registers[(cfaOffsetESI+28)/4] = UNWIND_X86_REG_ESI;
++ }
++ if ( ebpSaved ) {
++ if ( cfaOffsetEBP < -28 ) {
++ strcpy(warningBuffer, "ebp is saved too far from return address");
++ return UNWIND_X86_MODE_DWARF;
++ }
++ registers[(cfaOffsetEBP+28)/4] = UNWIND_X86_REG_EBP;
++ }
++
++ // validate that saved registers are contiguous and abut return address on stack
++ for (int i=0; i < saveRegisterCount; ++i) {
++ if ( registers[5-i] == 0 ) {
++ strcpy(warningBuffer, "registers not save contiguously in stack");
++ return UNWIND_X86_MODE_DWARF;
++ }
++ }
++
++ // encode register permutation
++ // the 10-bits are encoded differently depending on the number of registers saved
++ int renumregs[6];
++ for (int i=6-saveRegisterCount; i < 6; ++i) {
++ int countless = 0;
++ for (int j=6-saveRegisterCount; j < i; ++j) {
++ if ( registers[j] < registers[i] )
++ ++countless;
++ }
++ renumregs[i] = registers[i] - countless -1;
++ }
++ uint32_t permutationEncoding = 0;
++ switch ( saveRegisterCount ) {
++ case 6:
++ permutationEncoding |= (120*renumregs[0] + 24*renumregs[1] + 6*renumregs[2] + 2*renumregs[3] + renumregs[4]);
++ break;
++ case 5:
++ permutationEncoding |= (120*renumregs[1] + 24*renumregs[2] + 6*renumregs[3] + 2*renumregs[4] + renumregs[5]);
++ break;
++ case 4:
++ permutationEncoding |= (60*renumregs[2] + 12*renumregs[3] + 3*renumregs[4] + renumregs[5]);
++ break;
++ case 3:
++ permutationEncoding |= (20*renumregs[3] + 4*renumregs[4] + renumregs[5]);
++ break;
++ case 2:
++ permutationEncoding |= (5*renumregs[4] + renumregs[5]);
++ break;
++ case 1:
++ permutationEncoding |= (renumregs[5]);
++ break;
++ }
++
++ encoding |= (stackValue << __builtin_ctz(UNWIND_X86_FRAMELESS_STACK_SIZE));
++ encoding |= (stackAdjust << __builtin_ctz(UNWIND_X86_FRAMELESS_STACK_ADJUST));
++ encoding |= (saveRegisterCount << __builtin_ctz(UNWIND_X86_FRAMELESS_STACK_REG_COUNT));
++ encoding |= (permutationEncoding << __builtin_ctz(UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION));
++ return encoding;
++ }
++}
++
++
++
++
++
++
++
++//
++// ppc specific functions
++//
++template <typename A, typename R>
++int DwarfInstructions<A,R>::lastRestoreReg(const Registers_ppc&)
++{
++ COMPILE_TIME_ASSERT( (int)CFI_Parser<A>::kMaxRegisterNumber > (int)UNW_PPC_SPEFSCR );
++ return UNW_PPC_SPEFSCR;
++}
++
++template <typename A, typename R>
++bool DwarfInstructions<A,R>::isReturnAddressRegister(int regNum, const Registers_ppc&)
++{
++ return (regNum == UNW_PPC_LR);
++}
++
++template <typename A, typename R>
++typename A::pint_t DwarfInstructions<A,R>::getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog,
++ const Registers_ppc& registers)
++{
++ if ( prolog.cfaRegister != 0 )
++ return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset;
++ else if ( prolog.cfaExpression != 0 )
++ return evaluateExpression(prolog.cfaExpression, addressSpace, registers, 0);
++ else
++ ABORT("getCFA(): unknown location for ppc cfa");
++}
++
++
++template <typename A, typename R>
++compact_unwind_encoding_t DwarfInstructions<A,R>::encodeToUseDwarf(const Registers_ppc&)
++{
++ return UNWIND_X86_MODE_DWARF;
++}
++
++
++template <typename A, typename R>
++compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
++ const Registers_ppc& r, const typename CFI_Parser<A>::PrologInfo& prolog,
++ char warningBuffer[1024])
++{
++ warningBuffer[0] = '\0';
++ return UNWIND_X86_MODE_DWARF;
++}
++
++
++
++
++} // namespace libunwind
++
++
++#endif // __DWARF_INSTRUCTIONS_HPP__
++
++
++
++
+diff --git a/src/ld/parsers/libunwind/DwarfParser.hpp b/src/ld/parsers/libunwind/DwarfParser.hpp
+new file mode 100644
+index 0000000..3824d2e
+--- /dev/null
++++ src/ld/parsers/libunwind/DwarfParser.hpp
+@@ -0,0 +1,819 @@
++/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
++ *
++ * Copyright (c) 2008 Apple Inc. All rights reserved.
++ *
++ * @APPLE_LICENSE_HEADER_START@
++ *
++ * This file contains Original Code and/or Modifications of Original Code
++ * as defined in and that are subject to the Apple Public Source License
++ * Version 2.0 (the 'License'). You may not use this file except in
++ * compliance with the License. Please obtain a copy of the License at
++ * http://www.opensource.apple.com/apsl/ and read it before using this
++ * file.
++ *
++ * The Original Code and all software distributed under the License are
++ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
++ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
++ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
++ * Please see the License for the specific language governing rights and
++ * limitations under the License.
++ *
++ * @APPLE_LICENSE_HEADER_END@
++ */
++
++//
++// processor specific parsing of dwarf unwind instructions
++//
++
++#ifndef __DWARF_PARSER_HPP__
++#define __DWARF_PARSER_HPP__
++
++#include <stdint.h>
++#include <stdio.h>
++#include <stdlib.h>
++
++#include <vector>
++
++#include "libunwind.h"
++#include "dwarf2.h"
++
++#include "AddressSpace.hpp"
++
++
++namespace libunwind {
++
++
++///
++/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
++/// See Dwarf Spec for details:
++/// http://www.linux-foundation.org/spec/booksets/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
++///
++template <typename A>
++class CFI_Parser
++{
++public:
++ typedef typename A::pint_t pint_t;
++
++ ///
++ /// Information encoded in a CIE (Common Information Entry)
++ ///
++ struct CIE_Info {
++ pint_t cieStart;
++ pint_t cieLength;
++ pint_t cieInstructions;
++ uint8_t pointerEncoding;
++ uint8_t lsdaEncoding;
++ uint8_t personalityEncoding;
++ uint8_t personalityOffsetInCIE;
++ pint_t personality;
++ int codeAlignFactor;
++ int dataAlignFactor;
++ bool isSignalFrame;
++ bool fdesHaveAugmentationData;
++ };
++
++ ///
++ /// Information about an FDE (Frame Description Entry)
++ ///
++ struct FDE_Info {
++ pint_t fdeStart;
++ pint_t fdeLength;
++ pint_t fdeInstructions;
++ pint_t pcStart;
++ pint_t pcEnd;
++ pint_t lsda;
++ };
++
++ ///
++ /// Used by linker when parsing __eh_frame section
++ ///
++ struct FDE_Reference {
++ pint_t address;
++ uint32_t offsetInFDE;
++ uint8_t encodingOfAddress;
++ };
++ struct FDE_Atom_Info {
++ pint_t fdeAddress;
++ FDE_Reference function;
++ FDE_Reference cie;
++ FDE_Reference lsda;
++ };
++ struct CIE_Atom_Info {
++ pint_t cieAddress;
++ FDE_Reference personality;
++ };
++
++
++ ///
++ /// Information about a frame layout and registers saved determined
++ /// by "running" the dwarf FDE "instructions"
++ ///
++ enum { kMaxRegisterNumber = 120 };
++ enum RegisterSavedWhere { kRegisterUnused, kRegisterInCFA, kRegisterOffsetFromCFA,
++ kRegisterInRegister, kRegisterAtExpression, kRegisterIsExpression } ;
++ struct RegisterLocation {
++ RegisterSavedWhere location;
++ int64_t value;
++ };
++ struct PrologInfo {
++ uint32_t cfaRegister;
++ int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
++ int64_t cfaExpression; // CFA = expression
++ uint32_t spExtraArgSize;
++ uint32_t codeOffsetAtStackDecrement;
++ uint8_t registerSavedTwiceInCIE;
++ bool registersInOtherRegisters;
++ bool registerSavedMoreThanOnce;
++ bool cfaOffsetWasNegative;
++ bool sameValueUsed;
++ RegisterLocation savedRegisters[kMaxRegisterNumber]; // from where to restore registers
++ };
++
++ struct PrologInfoStackEntry {
++ PrologInfoStackEntry(PrologInfoStackEntry* n, const PrologInfo& i)
++ : next(n), info(i) {}
++ PrologInfoStackEntry* next;
++ PrologInfo info;
++ };
++
++ static bool findFDE(A& addressSpace, pint_t pc, pint_t ehSectionStart, uint32_t sectionLength, pint_t fdeHint, FDE_Info* fdeInfo, CIE_Info* cieInfo);
++ static const char* decodeFDE(A& addressSpace, pint_t fdeStart, FDE_Info* fdeInfo, CIE_Info* cieInfo);
++ static bool parseFDEInstructions(A& addressSpace, const FDE_Info& fdeInfo, const CIE_Info& cieInfo, pint_t upToPC, PrologInfo* results);
++ static const char* getCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength,
++ std::vector<FDE_Atom_Info>& fdes, std::vector<CIE_Atom_Info>& cies);
++ static uint32_t getCFICount(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength);
++
++ static const char* parseCIE(A& addressSpace, pint_t cie, CIE_Info* cieInfo);
++
++private:
++ static bool parseInstructions(A& addressSpace, pint_t instructions, pint_t instructionsEnd, const CIE_Info& cieInfo,
++ pint_t pcoffset, PrologInfoStackEntry*& rememberStack, PrologInfo* results);
++};
++
++
++///
++/// Parse a FDE into a CIE_Info and an FDE_Info
++///
++template <typename A>
++const char* CFI_Parser<A>::decodeFDE(A& addressSpace, pint_t fdeStart, FDE_Info* fdeInfo, CIE_Info* cieInfo)
++{
++ pint_t p = fdeStart;
++ uint64_t cfiLength = addressSpace.get32(p);
++ p += 4;
++ if ( cfiLength == 0xffffffff ) {
++ // 0xffffffff means length is really next 8 bytes
++ cfiLength = addressSpace.get64(p);
++ p += 8;
++ }
++ if ( cfiLength == 0 )
++ return "FDE has zero length"; // end marker
++ uint32_t ciePointer = addressSpace.get32(p);
++ if ( ciePointer == 0 )
++ return "FDE is really a CIE"; // this is a CIE not an FDE
++ pint_t nextCFI = p + cfiLength;
++ pint_t cieStart = p-ciePointer;
++ const char* err = parseCIE(addressSpace, cieStart, cieInfo);
++ if (err != NULL)
++ return err;
++ p += 4;
++ // parse pc begin and range
++ pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
++ pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
++ // parse rest of info
++ fdeInfo->lsda = 0;
++ // check for augmentation length
++ if ( cieInfo->fdesHaveAugmentationData ) {
++ uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
++ pint_t endOfAug = p + augLen;
++ if ( cieInfo->lsdaEncoding != 0 ) {
++ // peek at value (without indirection). Zero means no lsda
++ pint_t lsdaStart = p;
++ if ( addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0 ) {
++ // reset pointer and re-parse lsda address
++ p = lsdaStart;
++ fdeInfo->lsda = addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
++ }
++ }
++ p = endOfAug;
++ }
++ fdeInfo->fdeStart = fdeStart;
++ fdeInfo->fdeLength = nextCFI - fdeStart;
++ fdeInfo->fdeInstructions = p;
++ fdeInfo->pcStart = pcStart;
++ fdeInfo->pcEnd = pcStart+pcRange;
++ return NULL; // success
++}
++
++
++///
++/// Scan an eh_frame section to find an FDE for a pc
++///
++template <typename A>
++bool CFI_Parser<A>::findFDE(A& addressSpace, pint_t pc, pint_t ehSectionStart, uint32_t sectionLength, pint_t fdeHint, FDE_Info* fdeInfo, CIE_Info* cieInfo)
++{
++ //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
++ pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
++ const pint_t ehSectionEnd = p + sectionLength;
++ while ( p < ehSectionEnd ) {
++ pint_t currentCFI = p;
++ //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
++ uint64_t cfiLength = addressSpace.get32(p);
++ p += 4;
++ if ( cfiLength == 0xffffffff ) {
++ // 0xffffffff means length is really next 8 bytes
++ cfiLength = addressSpace.get64(p);
++ p += 8;
++ }
++ if ( cfiLength == 0 )
++ return false; // end marker
++ uint32_t id = addressSpace.get32(p);
++ if ( id == 0 ) {
++ // skip over CIEs
++ p += cfiLength;
++ }
++ else {
++ // process FDE to see if it covers pc
++ pint_t nextCFI = p + cfiLength;
++ uint32_t ciePointer = addressSpace.get32(p);
++ pint_t cieStart = p-ciePointer;
++ // validate pointer to CIE is within section
++ if ( (ehSectionStart <= cieStart) && (cieStart < ehSectionEnd) ) {
++ if ( parseCIE(addressSpace, cieStart, cieInfo) == NULL ) {
++ p += 4;
++ // parse pc begin and range
++ pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
++ pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
++ //fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
++ // test if pc is within the function this FDE covers
++ if ( (pcStart < pc) && (pc <= pcStart+pcRange) ) {
++ // parse rest of info
++ fdeInfo->lsda = 0;
++ // check for augmentation length
++ if ( cieInfo->fdesHaveAugmentationData ) {
++ uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
++ pint_t endOfAug = p + augLen;
++ if ( cieInfo->lsdaEncoding != 0 ) {
++ // peek at value (without indirection). Zero means no lsda
++ pint_t lsdaStart = p;
++ if ( addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0 ) {
++ // reset pointer and re-parse lsda address
++ p = lsdaStart;
++ fdeInfo->lsda = addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
++ }
++ }
++ p = endOfAug;
++ }
++ fdeInfo->fdeStart = currentCFI;
++ fdeInfo->fdeLength = nextCFI - currentCFI;
++ fdeInfo->fdeInstructions = p;
++ fdeInfo->pcStart = pcStart;
++ fdeInfo->pcEnd = pcStart+pcRange;
++ //fprintf(stderr, "findFDE(pc=0x%llX) found with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pc, (uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
++ return true;
++ }
++ else {
++ //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));
++ // pc is not in begin/range, skip this FDE
++ }
++ }
++ else {
++ // malformed CIE, now augmentation describing pc range encoding
++ //fprintf(stderr, "malformed CIE\n");
++ }
++ }
++ else {
++ // malformed FDE. CIE is bad
++ //fprintf(stderr, "malformed FDE, cieStart=0x%llX, ehSectionStart=0x%llX, ehSectionEnd=0x%llX\n",
++ // (uint64_t)cieStart, (uint64_t)ehSectionStart, (uint64_t)ehSectionEnd);
++ }
++ p = nextCFI;
++ }
++ }
++ //fprintf(stderr, "findFDE(pc=0x%llX) not found\n",(uint64_t)pc);
++ return false;
++}
++
++
++
++///
++/// Extract info from a CIE
++///
++template <typename A>
++const char* CFI_Parser<A>::parseCIE(A& addressSpace, pint_t cie, CIE_Info* cieInfo)
++{
++ //fprintf(stderr, "parseCIE(0x%llX)\n", (long long)cie);
++ cieInfo->pointerEncoding = 0;
++ cieInfo->lsdaEncoding = 0;
++ cieInfo->personalityEncoding = 0;
++ cieInfo->personalityOffsetInCIE = 0;
++ cieInfo->personality = 0;
++ cieInfo->codeAlignFactor = 0;
++ cieInfo->dataAlignFactor = 0;
++ cieInfo->isSignalFrame = false;
++ cieInfo->fdesHaveAugmentationData = false;
++ cieInfo->cieStart = cie;
++ pint_t p = cie;
++ uint64_t cieLength = addressSpace.get32(p);
++ p += 4;
++ pint_t cieContentEnd = p + cieLength;
++ if ( cieLength == 0xffffffff ) {
++ // 0xffffffff means length is really next 8 bytes
++ cieLength = addressSpace.get64(p);
++ p += 8;
++ cieContentEnd = p + cieLength;
++ }
++ if ( cieLength == 0 )
++ return NULL;
++ // CIE ID is always 0
++ if ( addressSpace.get32(p) != 0 )
++ return "CIE ID is not zero";
++ p += 4;
++ // Version is always 1 or 3
++ uint8_t version = addressSpace.get8(p);
++ if ( (version != 1) && (version != 3) )
++ return "CIE version is not 1 or 3";
++ ++p;
++ // save start of augmentation string and find end
++ pint_t strStart = p;
++ while ( addressSpace.get8(p) != 0 )
++ ++p;
++ ++p;
++ // parse code aligment factor
++ cieInfo->codeAlignFactor = addressSpace.getULEB128(p, cieContentEnd);
++ // parse data alignment factor
++ cieInfo->dataAlignFactor = addressSpace.getSLEB128(p, cieContentEnd);
++ // parse return address register
++ addressSpace.getULEB128(p, cieContentEnd);
++ // parse augmentation data based on augmentation string
++ const char* result = NULL;
++ if ( addressSpace.get8(strStart) == 'z' ) {
++ // parse augmentation data length
++ addressSpace.getULEB128(p, cieContentEnd);
++ for (pint_t s=strStart; addressSpace.get8(s) != '\0'; ++s) {
++ switch ( addressSpace.get8(s) ) {
++ case 'z':
++ cieInfo->fdesHaveAugmentationData = true;
++ break;
++ case 'P':
++ cieInfo->personalityEncoding = addressSpace.get8(p);
++ ++p;
++ cieInfo->personalityOffsetInCIE = p-cie;
++ cieInfo->personality = addressSpace.getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
++ break;
++ case 'L':
++ cieInfo->lsdaEncoding = addressSpace.get8(p);
++ ++p;
++ break;
++ case 'R':
++ cieInfo->pointerEncoding = addressSpace.get8(p);
++ ++p;
++ break;
++ case 'S':
++ cieInfo->isSignalFrame = true;
++ break;
++ default:
++ // ignore unknown letters
++ break;
++ }
++ }
++ }
++ cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
++ cieInfo->cieInstructions = p;
++ return result;
++}
++
++
++template <typename A>
++uint32_t CFI_Parser<A>::getCFICount(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength)
++{
++ uint32_t count = 0;
++ const pint_t ehSectionEnd = ehSectionStart + sectionLength;
++ for (pint_t p=ehSectionStart; p < ehSectionEnd; ) {
++ uint64_t cfiLength = addressSpace.get32(p);
++ p += 4;
++ if ( cfiLength == 0xffffffff ) {
++ // 0xffffffff means length is really next 8 bytes
++ cfiLength = addressSpace.get64(p);
++ p += 8;
++ }
++ if ( cfiLength == 0 )
++ return count; // end marker
++ ++count;
++ p += cfiLength;
++ }
++ return count;
++}
++
++
++
++template <typename A>
++const char* CFI_Parser<A>::getCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength,
++ std::vector<FDE_Atom_Info>& fdes, std::vector<CIE_Atom_Info>& cies)
++{
++ const pint_t ehSectionEnd = ehSectionStart + sectionLength;
++ for (pint_t p=ehSectionStart; p < ehSectionEnd; ) {
++ pint_t currentCFI = p;
++ uint64_t cfiLength = addressSpace.get32(p);
++ p += 4;
++ if ( cfiLength == 0xffffffff ) {
++ // 0xffffffff means length is really next 8 bytes
++ cfiLength = addressSpace.get64(p);
++ p += 8;
++ }
++ if ( cfiLength == 0 )
++ return NULL; // end marker
++ uint32_t id = addressSpace.get32(p);
++ if ( id == 0 ) {
++ // is CIE
++ CIE_Info cieInfo;
++ const char* err = parseCIE(addressSpace, currentCFI, &cieInfo);
++ if ( err != NULL )
++ return err;
++ CIE_Atom_Info entry;
++ entry.cieAddress = currentCFI;
++ entry.personality.address = cieInfo.personality;
++ entry.personality.offsetInFDE = cieInfo.personalityOffsetInCIE;
++ entry.personality.encodingOfAddress = cieInfo.personalityEncoding;
++ cies.push_back(entry);
++ p += cfiLength;
++ }
++ else {
++ // is FDE
++ FDE_Atom_Info entry;
++ entry.fdeAddress = currentCFI;
++ entry.function.address = 0;
++ entry.cie.address = 0;
++ entry.lsda.address = 0;
++ pint_t nextCFI = p + cfiLength;
++ uint32_t ciePointer = addressSpace.get32(p);
++ pint_t cieStart = p-ciePointer;
++ // validate pointer to CIE is within section
++ if ( (cieStart < ehSectionStart) || (cieStart > ehSectionEnd) )
++ return "FDE points to CIE outside __eh_frame section";
++ CIE_Info cieInfo;
++ const char* err = parseCIE(addressSpace, cieStart, &cieInfo);
++ if ( err != NULL )
++ return err;
++ entry.cie.address = cieStart;
++ entry.cie.offsetInFDE = p-currentCFI;
++ entry.cie.encodingOfAddress = DW_EH_PE_sdata4 | DW_EH_PE_pcrel;
++ p += 4;
++ // parse pc begin and range
++ pint_t offsetOfFunctionAddress = p-currentCFI;
++ pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding);
++ pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding & 0x0F);
++ //fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
++ // test if pc is within the function this FDE covers
++ entry.function.address = pcStart;
++ entry.function.offsetInFDE = offsetOfFunctionAddress;
++ entry.function.encodingOfAddress = cieInfo.pointerEncoding;
++ // skip over augmentation length
++ if ( cieInfo.fdesHaveAugmentationData ) {
++ uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
++ pint_t endOfAug = p + augLen;
++ if ( (cieInfo.lsdaEncoding != 0) && (addressSpace.getP(p) != 0) ) {
++ pint_t offsetOfLSDAAddress = p-currentCFI;
++ entry.lsda.address = addressSpace.getEncodedP(p, nextCFI, cieInfo.lsdaEncoding);
++ entry.lsda.offsetInFDE = offsetOfLSDAAddress;
++ entry.lsda.encodingOfAddress = cieInfo.lsdaEncoding;
++ }
++ p = endOfAug;
++ }
++ fdes.push_back(entry);
++ p = nextCFI;
++ }
++ }
++ return NULL; // success
++}
++
++
++
++///
++/// "run" the dwarf instructions and create the abstact PrologInfo for an FDE
++///
++template <typename A>
++bool CFI_Parser<A>::parseFDEInstructions(A& addressSpace, const FDE_Info& fdeInfo, const CIE_Info& cieInfo, pint_t upToPC, PrologInfo* results)
++{
++ // clear results
++ bzero(results, sizeof(PrologInfo));
++ PrologInfoStackEntry* rememberStack = NULL;
++
++ // parse CIE then FDE instructions
++ return parseInstructions(addressSpace, cieInfo.cieInstructions, cieInfo.cieStart+cieInfo.cieLength,
++ cieInfo, (pint_t)(-1), rememberStack, results)
++ && parseInstructions(addressSpace, fdeInfo.fdeInstructions, fdeInfo.fdeStart+fdeInfo.fdeLength,
++ cieInfo, upToPC-fdeInfo.pcStart, rememberStack, results);
++}
++
++
++///
++/// "run" the dwarf instructions
++///
++template <typename A>
++bool CFI_Parser<A>::parseInstructions(A& addressSpace, pint_t instructions, pint_t instructionsEnd, const CIE_Info& cieInfo,
++ pint_t pcoffset, PrologInfoStackEntry*& rememberStack, PrologInfo* results)
++{
++ const bool logDwarf = false;
++ pint_t p = instructions;
++ uint32_t codeOffset = 0;
++ PrologInfo initialState = *results;
++ if ( logDwarf ) fprintf(stderr, "parseInstructions(instructions=0x%0llX)\n", (uint64_t)instructionsEnd);
++
++ // see Dwarf Spec, section 6.4.2 for details on unwind opcodes
++ while ( (p < instructionsEnd) && (codeOffset < pcoffset) ) {
++ uint64_t reg;
++ uint64_t reg2;
++ int64_t offset;
++ uint64_t length;
++ uint8_t opcode = addressSpace.get8(p);
++ uint8_t operand;
++ PrologInfoStackEntry* entry;
++ ++p;
++ switch (opcode) {
++ case DW_CFA_nop:
++ if ( logDwarf ) fprintf(stderr, "DW_CFA_nop\n");
++ break;
++ case DW_CFA_set_loc:
++ codeOffset = addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
++ if ( logDwarf ) fprintf(stderr, "DW_CFA_set_loc\n");
++ break;
++ case DW_CFA_advance_loc1:
++ codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
++ p += 1;
++ if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc1: new offset=%u\n", codeOffset);
++ break;
++ case DW_CFA_advance_loc2:
++ codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
++ p += 2;
++ if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc2: new offset=%u\n", codeOffset);
++ break;
++ case DW_CFA_advance_loc4:
++ codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
++ p += 4;
++ if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc4: new offset=%u\n", codeOffset);
++ break;
++ case DW_CFA_offset_extended:
++ reg = addressSpace.getULEB128(p, instructionsEnd);
++ offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
++ if ( reg > kMaxRegisterNumber ) {
++ fprintf(stderr, "malformed DW_CFA_offset_extended dwarf unwind, reg too big\n");
++ return false;
++ }
++ if ( results->savedRegisters[reg].location != kRegisterUnused )
++ results->registerSavedMoreThanOnce = true;
++ results->savedRegisters[reg].location = kRegisterInCFA;
++ results->savedRegisters[reg].value = offset;
++ if ( logDwarf ) fprintf(stderr, "DW_CFA_offset_extended(reg=%lld, offset=%lld)\n", reg, offset);
++ break;
++ case DW_CFA_restore_extended:
++ reg = addressSpace.getULEB128(p, instructionsEnd);;
++ if ( reg > kMaxRegisterNumber ) {
++ fprintf(stderr, "malformed DW_CFA_restore_extended dwarf unwind, reg too big\n");
++ return false;
++ }
++ results->savedRegisters[reg] = initialState.savedRegisters[reg];
++ if ( logDwarf ) fprintf(stderr, "DW_CFA_restore_extended(reg=%lld)\n", reg);
++ break;
++ case DW_CFA_undefined:
++ reg = addressSpace.getULEB128(p, instructionsEnd);
++ if ( reg > kMaxRegisterNumber ) {
++ fprintf(stderr, "malformed DW_CFA_undefined dwarf unwind, reg too big\n");
++ return false;
++ }
++ results->savedRegisters[reg].location = kRegisterUnused;
++ if ( logDwarf ) fprintf(stderr, "DW_CFA_undefined(reg=%lld)\n", reg);
++ break;
++ case DW_CFA_same_value:
++ reg = addressSpace.getULEB128(p, instructionsEnd);
++ if ( reg > kMaxRegisterNumber ) {
++ fprintf(stderr, "malformed DW_CFA_same_value dwarf unwind, reg too big\n");
++ return false;
++ }
++ // <rdar://problem/8456377> DW_CFA_same_value unsupported
++ // "same value" means register was stored in frame, but its current
++ // value has not changed, so no need to restore from frame.
++ // We model this as if the register was never saved.
++ results->savedRegisters[reg].location = kRegisterUnused;
++ // set flag to disable conversion to compact unwind
++ results->sameValueUsed = true;
++ if ( logDwarf ) fprintf(stderr, "DW_CFA_same_value(reg=%lld)\n", reg);
++ break;
++ case DW_CFA_register:
++ reg = addressSpace.getULEB128(p, instructionsEnd);
++ reg2 = addressSpace.getULEB128(p, instructionsEnd);
++ if ( reg > kMaxRegisterNumber ) {
++ fprintf(stderr, "malformed DW_CFA_register dwarf unwind, reg too big\n");
++ return false;
++ }
++ if ( reg2 > kMaxRegisterNumber ) {
++ fprintf(stderr, "malformed DW_CFA_register dwarf unwind, reg2 too big\n");
++ return false;
++ }
++ results->savedRegisters[reg].location = kRegisterInRegister;
++ results->savedRegisters[reg].value = reg2;
++ // set flag to disable conversion to compact unwind
++ results->registersInOtherRegisters = true;
++ if ( logDwarf ) fprintf(stderr, "DW_CFA_register(reg=%lld, reg2=%lld)\n", reg, reg2);
++ break;
++ case DW_CFA_remember_state:
++ // avoid operator new, because that would be an upward dependency
++ entry = (PrologInfoStackEntry*)malloc(sizeof(PrologInfoStackEntry));
++ if ( entry != NULL ) {
++ entry->next = rememberStack;
++ entry->info = *results;
++ rememberStack = entry;
++ }
++ else {
++ return false;
++ }
++ if ( logDwarf ) fprintf(stderr, "DW_CFA_remember_state\n");
++ break;
++ case DW_CFA_restore_state:
++ if ( rememberStack != NULL ) {
++ PrologInfoStackEntry* top = rememberStack;
++ *results = top->info;
++ rememberStack = top->next;
++ free((char*)top);
++ }
++ else {
++ return false;
++ }
++ if ( logDwarf ) fprintf(stderr, "DW_CFA_restore_state\n");
++ break;
++ case DW_CFA_def_cfa:
++ reg = addressSpace.getULEB128(p, instructionsEnd);
++ offset = addressSpace.getULEB128(p, instructionsEnd);
++ if ( reg > kMaxRegisterNumber ) {
++ fprintf(stderr, "malformed DW_CFA_def_cfa dwarf unwind, reg too big\n");
++ return false;
++ }
++ results->cfaRegister = reg;
++ results->cfaRegisterOffset = offset;
++ if ( offset > 0x80000000 )
++ results->cfaOffsetWasNegative = true;
++ if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa(reg=%lld, offset=%lld)\n", reg, offset);
++ break;
++ case DW_CFA_def_cfa_register:
++ reg = addressSpace.getULEB128(p, instructionsEnd);
++ if ( reg > kMaxRegisterNumber ) {
++ fprintf(stderr, "malformed DW_CFA_def_cfa_register dwarf unwind, reg too big\n");
++ return false;
++ }
++ results->cfaRegister = reg;
++ if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_register(%lld)\n", reg);
++ break;
++ case DW_CFA_def_cfa_offset:
++ results->cfaRegisterOffset = addressSpace.getULEB128(p, instructionsEnd);
++ results->codeOffsetAtStackDecrement = codeOffset;
++ if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_offset(%d)\n", results->cfaRegisterOffset);
++ break;
++ case DW_CFA_def_cfa_expression:
++ results->cfaRegister = 0;
++ results->cfaExpression = p;
++ length = addressSpace.getULEB128(p, instructionsEnd);
++ p += length;
++ if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_expression(expression=0x%llX, length=%llu)\n",
++ results->cfaExpression, length);
++ break;
++ case DW_CFA_expression:
++ reg = addressSpace.getULEB128(p, instructionsEnd);
++ if ( reg > kMaxRegisterNumber ) {
++ fprintf(stderr, "malformed DW_CFA_expression dwarf unwind, reg too big\n");
++ return false;
++ }
++ results->savedRegisters[reg].location = kRegisterAtExpression;
++ results->savedRegisters[reg].value = p;
++ length = addressSpace.getULEB128(p, instructionsEnd);
++ p += length;
++ if ( logDwarf ) fprintf(stderr, "DW_CFA_expression(reg=%lld, expression=0x%llX, length=%llu)\n",
++ reg, results->savedRegisters[reg].value, length);
++ break;
++ case DW_CFA_offset_extended_sf:
++ reg = addressSpace.getULEB128(p, instructionsEnd);
++ if ( reg > kMaxRegisterNumber ) {
++ fprintf(stderr, "malformed DW_CFA_offset_extended_sf dwarf unwind, reg too big\n");
++ return false;
++ }
++ offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
++ if ( results->savedRegisters[reg].location != kRegisterUnused )
++ results->registerSavedMoreThanOnce = true;
++ results->savedRegisters[reg].location = kRegisterInCFA;
++ results->savedRegisters[reg].value = offset;
++ if ( logDwarf ) fprintf(stderr, "DW_CFA_offset_extended_sf(reg=%lld, offset=%lld)\n", reg, offset);
++ break;
++ case DW_CFA_def_cfa_sf:
++ reg = addressSpace.getULEB128(p, instructionsEnd);
++ offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
++ if ( reg > kMaxRegisterNumber ) {
++ fprintf(stderr, "malformed DW_CFA_def_cfa_sf dwarf unwind, reg too big\n");
++ return false;
++ }
++ results->cfaRegister = reg;
++ results->cfaRegisterOffset = offset;
++ if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_sf(reg=%lld, offset=%lld)\n", reg, offset);
++ break;
++ case DW_CFA_def_cfa_offset_sf:
++ results->cfaRegisterOffset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
++ results->codeOffsetAtStackDecrement = codeOffset;
++ if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_offset_sf(%d)\n", results->cfaRegisterOffset);
++ break;
++ case DW_CFA_val_offset:
++ reg = addressSpace.getULEB128(p, instructionsEnd);
++ offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
++ results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
++ results->savedRegisters[reg].value = offset;
++ if ( logDwarf ) fprintf(stderr, "DW_CFA_val_offset(reg=%lld, offset=%lld\n", reg, offset);
++ break;
++ case DW_CFA_val_offset_sf:
++ reg = addressSpace.getULEB128(p, instructionsEnd);
++ if ( reg > kMaxRegisterNumber ) {
++ fprintf(stderr, "malformed DW_CFA_val_offset_sf dwarf unwind, reg too big\n");
++ return false;
++ }
++ offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
++ results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
++ results->savedRegisters[reg].value = offset;
++ if ( logDwarf ) fprintf(stderr, "DW_CFA_val_offset_sf(reg=%lld, offset=%lld\n", reg, offset);
++ break;
++ case DW_CFA_val_expression:
++ reg = addressSpace.getULEB128(p, instructionsEnd);
++ if ( reg > kMaxRegisterNumber ) {
++ fprintf(stderr, "malformed DW_CFA_val_expression dwarf unwind, reg too big\n");
++ return false;
++ }
++ results->savedRegisters[reg].location = kRegisterIsExpression;
++ results->savedRegisters[reg].value = p;
++ length = addressSpace.getULEB128(p, instructionsEnd);
++ p += length;
++ if ( logDwarf ) fprintf(stderr, "DW_CFA_val_expression(reg=%lld, expression=0x%llX, length=%lld)\n",
++ reg, results->savedRegisters[reg].value, length);
++ break;
++ case DW_CFA_GNU_args_size:
++ offset = addressSpace.getULEB128(p, instructionsEnd);
++ results->spExtraArgSize = offset;
++ if ( logDwarf ) fprintf(stderr, "DW_CFA_GNU_args_size(%lld)\n", offset);
++ break;
++ case DW_CFA_GNU_negative_offset_extended:
++ reg = addressSpace.getULEB128(p, instructionsEnd);
++ if ( reg > kMaxRegisterNumber ) {
++ fprintf(stderr, "malformed DW_CFA_GNU_negative_offset_extended dwarf unwind, reg too big\n");
++ return false;
++ }
++ offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
++ if ( results->savedRegisters[reg].location != kRegisterUnused )
++ results->registerSavedMoreThanOnce = true;
++ results->savedRegisters[reg].location = kRegisterInCFA;
++ results->savedRegisters[reg].value = -offset;
++ if ( logDwarf ) fprintf(stderr, "DW_CFA_GNU_negative_offset_extended(%lld)\n", offset);
++ break;
++ default:
++ operand = opcode & 0x3F;
++ switch ( opcode & 0xC0 ) {
++ case DW_CFA_offset:
++ reg = operand;
++ offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
++ if ( results->savedRegisters[reg].location != kRegisterUnused ) {
++ // look for idiom of PC saved twice in CIE to mean disable compact unwind encoding
++ if ( (pcoffset == (pint_t)(-1))
++ && (results->savedRegisters[reg].location == kRegisterInCFA)
++ && (results->savedRegisters[reg].value == offset) )
++ results->registerSavedTwiceInCIE = reg;
++ else
++ results->registerSavedMoreThanOnce = true;
++ }
++ results->savedRegisters[reg].location = kRegisterInCFA;
++ results->savedRegisters[reg].value = offset;
++ if ( logDwarf ) fprintf(stderr, "DW_CFA_offset(reg=%d, offset=%lld)\n", operand, offset);
++ break;
++ case DW_CFA_advance_loc:
++ codeOffset += operand * cieInfo.codeAlignFactor;
++ if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc: new offset=%u\n", codeOffset);
++ break;
++ case DW_CFA_restore:
++ // <rdar://problem/7503075> Python crashes when handling an exception thrown by an obj-c object
++ // libffi uses DW_CFA_restore in the middle of some custom dwarf, so it is not a good epilog flag
++ //return true; // gcc-4.5 starts the epilog with this
++ reg = operand;
++ results->savedRegisters[reg] = initialState.savedRegisters[reg];
++ if ( logDwarf ) fprintf(stderr, "DW_CFA_restore(reg=%lld)\n", reg);
++ break;
++ default:
++ if ( logDwarf ) fprintf(stderr, "unknown CFA opcode 0x%02X\n", opcode);
++ return false;
++ }
++ }
++ }
++
++ return true;
++}
++
++
++} // namespace libunwind
++
++
++#endif // __DWARF_PARSER_HPP__
++
++
++
++
+diff --git a/src/ld/parsers/libunwind/InternalMacros.h b/src/ld/parsers/libunwind/InternalMacros.h
+new file mode 100644
+index 0000000..25c1631
+--- /dev/null
++++ src/ld/parsers/libunwind/InternalMacros.h
+@@ -0,0 +1,105 @@
++/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
++ *
++ * Copyright (c) 2008 Apple Inc. All rights reserved.
++ *
++ * @APPLE_LICENSE_HEADER_START@
++ *
++ * This file contains Original Code and/or Modifications of Original Code
++ * as defined in and that are subject to the Apple Public Source License
++ * Version 2.0 (the 'License'). You may not use this file except in
++ * compliance with the License. Please obtain a copy of the License at
++ * http://www.opensource.apple.com/apsl/ and read it before using this
++ * file.
++ *
++ * The Original Code and all software distributed under the License are
++ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
++ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
++ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
++ * Please see the License for the specific language governing rights and
++ * limitations under the License.
++ *
++ * @APPLE_LICENSE_HEADER_END@
++ */
++
++
++
++#ifndef INTERNAL_MACROS_H
++#define INTERNAL_MACROS_H
++
++#include <assert.h>
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++ extern void __assert_rtn(const char *, const char *, int, const char *) __attribute__((noreturn));
++#ifdef __cplusplus
++}
++#endif
++
++#define UNW_STEP_SUCCESS 1
++#define UNW_STEP_END 0
++
++
++struct v128 { unsigned int vec[4]; };
++
++
++#define EXPORT __attribute__((visibility("default")))
++
++#define COMPILE_TIME_ASSERT( expr ) \
++ extern int compile_time_assert_failed[ ( expr ) ? 1 : -1 ] __attribute__( ( unused ) );
++
++#define ABORT(msg) __assert_rtn(__func__, __FILE__, __LINE__, msg)
++
++#if NDEBUG
++ #define DEBUG_MESSAGE(msg, ...)
++ #define DEBUG_PRINT_API(msg, ...)
++ #define DEBUG_PRINT_UNWINDING_TEST 0
++ #define DEBUG_PRINT_UNWINDING(msg, ...)
++ #define DEBUG_LOG_NON_ZERO(x) x;
++ #define INITIALIZE_DEBUG_PRINT_API
++ #define INITIALIZE_DEBUG_PRINT_UNWINDING
++#else
++ #define DEBUG_MESSAGE(msg, ...) fprintf(stderr, "libuwind: " msg, __VA_ARGS__)
++ #ifdef __cplusplus
++ extern "C" {
++ #endif
++ extern bool logAPIs();
++ extern bool logUnwinding();
++ #ifdef __cplusplus
++ }
++ #endif
++ #define DEBUG_LOG_NON_ZERO(x) { int _err = x; if ( _err != 0 ) fprintf(stderr, "libuwind: " #x "=%d in %s", _err, __FUNCTION__); }
++ #define DEBUG_PRINT_API(msg, ...) do { if ( logAPIs() ) fprintf(stderr, msg, __VA_ARGS__); } while(0)
++ #define DEBUG_PRINT_UNWINDING(msg, ...) do { if ( logUnwinding() ) fprintf(stderr, msg, __VA_ARGS__); } while(0)
++ #define DEBUG_PRINT_UNWINDING_TEST logUnwinding()
++ #define INITIALIZE_DEBUG_PRINT_API bool logAPIs() { static bool log = (getenv("LIBUNWIND_PRINT_APIS") != NULL); return log; }
++ #define INITIALIZE_DEBUG_PRINT_UNWINDING bool logUnwinding() { static bool log = (getenv("LIBUNWIND_PRINT_UNWINDING") != NULL); return log; }
++#endif
++
++
++// note hack for <rdar://problem/6175741>
++// Once libgcc_s.dylib vectors to libSystem, then we can remove the $ld$hide$os10.6$ lines
++#if __ppc__
++ #define NOT_HERE_BEFORE_10_6(sym) \
++ extern const char sym##_tmp3 __asm("$ld$hide$os10.3$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp3 = 0; \
++ extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
++ extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp5 = 0;
++ #define NEVER_HERE(sym) \
++ extern const char sym##_tmp3 __asm("$ld$hide$os10.3$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp3 = 0; \
++ extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
++ extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp5 = 0; \
++ extern const char sym##_tmp6 __asm("$ld$hide$os10.6$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp6 = 0;
++#else
++ #define NOT_HERE_BEFORE_10_6(sym) \
++ extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
++ extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp5 = 0;
++ #define NEVER_HERE(sym) \
++ extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
++ extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp5 = 0; \
++ extern const char sym##_tmp6 __asm("$ld$hide$os10.6$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp6 = 0;
++#endif
++
++
++
++#endif // INTERNAL_MACROS_H
+diff --git a/src/ld/parsers/libunwind/Registers.hpp b/src/ld/parsers/libunwind/Registers.hpp
+new file mode 100644
+index 0000000..7d39fd7
+--- /dev/null
++++ src/ld/parsers/libunwind/Registers.hpp
+@@ -0,0 +1,1050 @@
++/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
++ *
++ * Copyright (c) 2007-2009 Apple Inc. All rights reserved.
++ *
++ * @APPLE_LICENSE_HEADER_START@
++ *
++ * This file contains Original Code and/or Modifications of Original Code
++ * as defined in and that are subject to the Apple Public Source License
++ * Version 2.0 (the 'License'). You may not use this file except in
++ * compliance with the License. Please obtain a copy of the License at
++ * http://www.opensource.apple.com/apsl/ and read it before using this
++ * file.
++ *
++ * The Original Code and all software distributed under the License are
++ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
++ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
++ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
++ * Please see the License for the specific language governing rights and
++ * limitations under the License.
++ *
++ * @APPLE_LICENSE_HEADER_END@
++ */
++
++//
++// C++ interface to lower levels of libuwind
++//
++
++#ifndef __REGISTERS_HPP__
++#define __REGISTERS_HPP__
++
++#include <stdint.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <dlfcn.h>
++#include <mach-o/loader.h>
++#include <mach-o/getsect.h>
++#include <mach/i386/thread_status.h>
++
++#include "libunwind.h"
++#include "InternalMacros.h"
++
++namespace libunwind {
++
++
++///
++/// Registers_x86 holds the register state of a thread in a 32-bit intel process.
++///
++class Registers_x86
++{
++public:
++ Registers_x86();
++ Registers_x86(const void* registers);
++
++ bool validRegister(int num) const;
++ uint32_t getRegister(int num) const;
++ void setRegister(int num, uint32_t value);
++ bool validFloatRegister(int num) const { return false; }
++ double getFloatRegister(int num) const;
++ void setFloatRegister(int num, double value);
++ bool validVectorRegister(int num) const { return false; }
++ v128 getVectorRegister(int num) const;
++ void setVectorRegister(int num, v128 value);
++ const char* getRegisterName(int num);
++ void jumpto();
++
++ uint32_t getSP() const { return fRegisters.__esp; }
++ void setSP(uint32_t value) { fRegisters.__esp = value; }
++ uint32_t getIP() const { return fRegisters.__eip; }
++ void setIP(uint32_t value) { fRegisters.__eip = value; }
++ uint32_t getEBP() const { return fRegisters.__ebp; }
++ void setEBP(uint32_t value) { fRegisters.__ebp = value; }
++ uint32_t getEBX() const { return fRegisters.__ebx; }
++ void setEBX(uint32_t value) { fRegisters.__ebx = value; }
++ uint32_t getECX() const { return fRegisters.__ecx; }
++ void setECX(uint32_t value) { fRegisters.__ecx = value; }
++ uint32_t getEDX() const { return fRegisters.__edx; }
++ void setEDX(uint32_t value) { fRegisters.__edx = value; }
++ uint32_t getESI() const { return fRegisters.__esi; }
++ void setESI(uint32_t value) { fRegisters.__esi = value; }
++ uint32_t getEDI() const { return fRegisters.__edi; }
++ void setEDI(uint32_t value) { fRegisters.__edi = value; }
++
++private:
++ i386_thread_state_t fRegisters;
++};
++
++inline Registers_x86::Registers_x86(const void* registers)
++{
++ COMPILE_TIME_ASSERT( sizeof(Registers_x86) < sizeof(unw_context_t) );
++ fRegisters = *((i386_thread_state_t*)registers);
++}
++
++inline Registers_x86::Registers_x86()
++{
++ bzero(&fRegisters, sizeof(fRegisters));
++}
++
++
++inline bool Registers_x86::validRegister(int regNum) const
++{
++ if ( regNum == UNW_REG_IP )
++ return true;
++ if ( regNum == UNW_REG_SP )
++ return true;
++ if ( regNum < 0 )
++ return false;
++ if ( regNum > 7 )
++ return false;
++ return true;
++}
++
++inline uint32_t Registers_x86::getRegister(int regNum) const
++{
++ switch ( regNum ) {
++ case UNW_REG_IP:
++ return fRegisters.__eip;
++ case UNW_REG_SP:
++ return fRegisters.__esp;
++ case UNW_X86_EAX:
++ return fRegisters.__eax;
++ case UNW_X86_ECX:
++ return fRegisters.__ecx;
++ case UNW_X86_EDX:
++ return fRegisters.__edx;
++ case UNW_X86_EBX:
++ return fRegisters.__ebx;
++ case UNW_X86_EBP:
++ return fRegisters.__ebp;
++ case UNW_X86_ESP:
++ return fRegisters.__esp;
++ case UNW_X86_ESI:
++ return fRegisters.__esi;
++ case UNW_X86_EDI:
++ return fRegisters.__edi;
++ }
++ ABORT("unsupported x86 register");
++}
++
++inline void Registers_x86::setRegister(int regNum, uint32_t value)
++{
++ switch ( regNum ) {
++ case UNW_REG_IP:
++ fRegisters.__eip = value;
++ return;
++ case UNW_REG_SP:
++ fRegisters.__esp = value;
++ return;
++ case UNW_X86_EAX:
++ fRegisters.__eax = value;
++ return;
++ case UNW_X86_ECX:
++ fRegisters.__ecx = value;
++ return;
++ case UNW_X86_EDX:
++ fRegisters.__edx = value;
++ return;
++ case UNW_X86_EBX:
++ fRegisters.__ebx = value;
++ return;
++ case UNW_X86_EBP:
++ fRegisters.__ebp = value;
++ return;
++ case UNW_X86_ESP:
++ fRegisters.__esp = value;
++ return;
++ case UNW_X86_ESI:
++ fRegisters.__esi = value;
++ return;
++ case UNW_X86_EDI:
++ fRegisters.__edi = value;
++ return;
++ }
++ ABORT("unsupported x86 register");
++}
++
++inline const char* Registers_x86::getRegisterName(int regNum)
++{
++ switch ( regNum ) {
++ case UNW_REG_IP:
++ return "ip";
++ case UNW_REG_SP:
++ return "esp";
++ case UNW_X86_EAX:
++ return "eax";
++ case UNW_X86_ECX:
++ return "ecx";
++ case UNW_X86_EDX:
++ return "edx";
++ case UNW_X86_EBX:
++ return "ebx";
++ case UNW_X86_EBP:
++ return "ebp";
++ case UNW_X86_ESP:
++ return "esp";
++ case UNW_X86_ESI:
++ return "esi";
++ case UNW_X86_EDI:
++ return "edi";
++ default:
++ return "unknown register";
++ }
++}
++
++inline double Registers_x86::getFloatRegister(int num) const
++{
++ ABORT("no x86 float registers");
++}
++
++inline void Registers_x86::setFloatRegister(int num, double value)
++{
++ ABORT("no x86 float registers");
++}
++
++inline v128 Registers_x86::getVectorRegister(int num) const
++{
++ ABORT("no x86 vector registers");
++}
++
++inline void Registers_x86::setVectorRegister(int num, v128 value)
++{
++ ABORT("no x86 vector registers");
++}
++
++
++
++
++///
++/// Registers_x86_64 holds the register state of a thread in a 64-bit intel process.
++///
++class Registers_x86_64
++{
++public:
++ Registers_x86_64();
++ Registers_x86_64(const void* registers);
++
++ bool validRegister(int num) const;
++ uint64_t getRegister(int num) const;
++ void setRegister(int num, uint64_t value);
++ bool validFloatRegister(int num) const{ return false; }
++ double getFloatRegister(int num) const;
++ void setFloatRegister(int num, double value);
++ bool validVectorRegister(int num) const { return false; }
++ v128 getVectorRegister(int num) const;
++ void setVectorRegister(int num, v128 value);
++ const char* getRegisterName(int num);
++ void jumpto();
++ uint64_t getSP() const { return fRegisters.__rsp; }
++ void setSP(uint64_t value) { fRegisters.__rsp = value; }
++ uint64_t getIP() const { return fRegisters.__rip; }
++ void setIP(uint64_t value) { fRegisters.__rip = value; }
++ uint64_t getRBP() const { return fRegisters.__rbp; }
++ void setRBP(uint64_t value) { fRegisters.__rbp = value; }
++ uint64_t getRBX() const { return fRegisters.__rbx; }
++ void setRBX(uint64_t value) { fRegisters.__rbx = value; }
++ uint64_t getR12() const { return fRegisters.__r12; }
++ void setR12(uint64_t value) { fRegisters.__r12 = value; }
++ uint64_t getR13() const { return fRegisters.__r13; }
++ void setR13(uint64_t value) { fRegisters.__r13 = value; }
++ uint64_t getR14() const { return fRegisters.__r14; }
++ void setR14(uint64_t value) { fRegisters.__r14 = value; }
++ uint64_t getR15() const { return fRegisters.__r15; }
++ void setR15(uint64_t value) { fRegisters.__r15 = value; }
++private:
++ x86_thread_state64_t fRegisters;
++};
++
++inline Registers_x86_64::Registers_x86_64(const void* registers)
++{
++ COMPILE_TIME_ASSERT( sizeof(Registers_x86_64) < sizeof(unw_context_t) );
++ fRegisters = *((x86_thread_state64_t*)registers);
++}
++
++inline Registers_x86_64::Registers_x86_64()
++{
++ bzero(&fRegisters, sizeof(fRegisters));
++}
++
++
++inline bool Registers_x86_64::validRegister(int regNum) const
++{
++ if ( regNum == UNW_REG_IP )
++ return true;
++ if ( regNum == UNW_REG_SP )
++ return true;
++ if ( regNum < 0 )
++ return false;
++ if ( regNum > 15 )
++ return false;
++ return true;
++}
++
++inline uint64_t Registers_x86_64::getRegister(int regNum) const
++{
++ switch ( regNum ) {
++ case UNW_REG_IP:
++ return fRegisters.__rip;
++ case UNW_REG_SP:
++ return fRegisters.__rsp;
++ case UNW_X86_64_RAX:
++ return fRegisters.__rax;
++ case UNW_X86_64_RDX:
++ return fRegisters.__rdx;
++ case UNW_X86_64_RCX:
++ return fRegisters.__rcx;
++ case UNW_X86_64_RBX:
++ return fRegisters.__rbx;
++ case UNW_X86_64_RSI:
++ return fRegisters.__rsi;
++ case UNW_X86_64_RDI:
++ return fRegisters.__rdi;
++ case UNW_X86_64_RBP:
++ return fRegisters.__rbp;
++ case UNW_X86_64_RSP:
++ return fRegisters.__rsp;
++ case UNW_X86_64_R8:
++ return fRegisters.__r8;
++ case UNW_X86_64_R9:
++ return fRegisters.__r9;
++ case UNW_X86_64_R10:
++ return fRegisters.__r10;
++ case UNW_X86_64_R11:
++ return fRegisters.__r11;
++ case UNW_X86_64_R12:
++ return fRegisters.__r12;
++ case UNW_X86_64_R13:
++ return fRegisters.__r13;
++ case UNW_X86_64_R14:
++ return fRegisters.__r14;
++ case UNW_X86_64_R15:
++ return fRegisters.__r15;
++ }
++ ABORT("unsupported x86_64 register");
++}
++
++inline void Registers_x86_64::setRegister(int regNum, uint64_t value)
++{
++ switch ( regNum ) {
++ case UNW_REG_IP:
++ fRegisters.__rip = value;
++ return;
++ case UNW_REG_SP:
++ fRegisters.__rsp = value;
++ return;
++ case UNW_X86_64_RAX:
++ fRegisters.__rax = value;
++ return;
++ case UNW_X86_64_RDX:
++ fRegisters.__rdx = value;
++ return;
++ case UNW_X86_64_RCX:
++ fRegisters.__rcx = value;
++ return;
++ case UNW_X86_64_RBX:
++ fRegisters.__rbx = value;
++ return;
++ case UNW_X86_64_RSI:
++ fRegisters.__rsi = value;
++ return;
++ case UNW_X86_64_RDI:
++ fRegisters.__rdi = value;
++ return;
++ case UNW_X86_64_RBP:
++ fRegisters.__rbp = value;
++ return;
++ case UNW_X86_64_RSP:
++ fRegisters.__rsp = value;
++ return;
++ case UNW_X86_64_R8:
++ fRegisters.__r8 = value;
++ return;
++ case UNW_X86_64_R9:
++ fRegisters.__r9 = value;
++ return;
++ case UNW_X86_64_R10:
++ fRegisters.__r10 = value;
++ return;
++ case UNW_X86_64_R11:
++ fRegisters.__r11 = value;
++ return;
++ case UNW_X86_64_R12:
++ fRegisters.__r12 = value;
++ return;
++ case UNW_X86_64_R13:
++ fRegisters.__r13 = value;
++ return;
++ case UNW_X86_64_R14:
++ fRegisters.__r14 = value;
++ return;
++ case UNW_X86_64_R15:
++ fRegisters.__r15 = value;
++ return;
++ }
++ ABORT("unsupported x86_64 register");
++}
++
++inline const char* Registers_x86_64::getRegisterName(int regNum)
++{
++ switch ( regNum ) {
++ case UNW_REG_IP:
++ return "rip";
++ case UNW_REG_SP:
++ return "rsp";
++ case UNW_X86_64_RAX:
++ return "rax";
++ case UNW_X86_64_RDX:
++ return "rdx";
++ case UNW_X86_64_RCX:
++ return "rcx";
++ case UNW_X86_64_RBX:
++ return "rbx";
++ case UNW_X86_64_RSI:
++ return "rsi";
++ case UNW_X86_64_RDI:
++ return "rdi";
++ case UNW_X86_64_RBP:
++ return "rbp";
++ case UNW_X86_64_RSP:
++ return "rsp";
++ case UNW_X86_64_R8:
++ return "r8";
++ case UNW_X86_64_R9:
++ return "r9";
++ case UNW_X86_64_R10:
++ return "r10";
++ case UNW_X86_64_R11:
++ return "r11";
++ case UNW_X86_64_R12:
++ return "r12";
++ case UNW_X86_64_R13:
++ return "r13";
++ case UNW_X86_64_R14:
++ return "r14";
++ case UNW_X86_64_R15:
++ return "r15";
++ default:
++ return "unknown register";
++ }
++}
++
++double Registers_x86_64::getFloatRegister(int num) const
++{
++ ABORT("no x86_64 float registers");
++}
++
++void Registers_x86_64::setFloatRegister(int num, double value)
++{
++ ABORT("no x86_64 float registers");
++}
++
++inline v128 Registers_x86_64::getVectorRegister(int num) const
++{
++ ABORT("no x86_64 vector registers");
++}
++
++inline void Registers_x86_64::setVectorRegister(int num, v128 value)
++{
++ ABORT("no x86_64 vector registers");
++}
++
++
++///
++/// Registers_ppc holds the register state of a thread in a 32-bit PowerPC process.
++///
++class Registers_ppc
++{
++public:
++ Registers_ppc();
++ Registers_ppc(const void* registers);
++
++ bool validRegister(int num) const;
++ uint32_t getRegister(int num) const;
++ void setRegister(int num, uint32_t value);
++ bool validFloatRegister(int num) const;
++ double getFloatRegister(int num) const;
++ void setFloatRegister(int num, double value);
++ bool validVectorRegister(int num) const;
++ v128 getVectorRegister(int num) const;
++ void setVectorRegister(int num, v128 value);
++ void jumpto();
++ const char* getRegisterName(int num);
++ uint64_t getSP() const { return fRegisters.__r1; }
++ void setSP(uint64_t value) { fRegisters.__r1 = value; }
++ uint64_t getIP() const { return fRegisters.__srr0; }
++ void setIP(uint64_t value) { fRegisters.__srr0 = value; }
++private:
++ struct ppc_thread_state_t
++ {
++ unsigned int __srr0; /* Instruction address register (PC) */
++ unsigned int __srr1; /* Machine state register (supervisor) */
++ unsigned int __r0;
++ unsigned int __r1;
++ unsigned int __r2;
++ unsigned int __r3;
++ unsigned int __r4;
++ unsigned int __r5;
++ unsigned int __r6;
++ unsigned int __r7;
++ unsigned int __r8;
++ unsigned int __r9;
++ unsigned int __r10;
++ unsigned int __r11;
++ unsigned int __r12;
++ unsigned int __r13;
++ unsigned int __r14;
++ unsigned int __r15;
++ unsigned int __r16;
++ unsigned int __r17;
++ unsigned int __r18;
++ unsigned int __r19;
++ unsigned int __r20;
++ unsigned int __r21;
++ unsigned int __r22;
++ unsigned int __r23;
++ unsigned int __r24;
++ unsigned int __r25;
++ unsigned int __r26;
++ unsigned int __r27;
++ unsigned int __r28;
++ unsigned int __r29;
++ unsigned int __r30;
++ unsigned int __r31;
++ unsigned int __cr; /* Condition register */
++ unsigned int __xer; /* User's integer exception register */
++ unsigned int __lr; /* Link register */
++ unsigned int __ctr; /* Count register */
++ unsigned int __mq; /* MQ register (601 only) */
++ unsigned int __vrsave; /* Vector Save Register */
++ };
++
++ struct ppc_float_state_t
++ {
++ double __fpregs[32];
++
++ unsigned int __fpscr_pad; /* fpscr is 64 bits, 32 bits of rubbish */
++ unsigned int __fpscr; /* floating point status register */
++ };
++
++ ppc_thread_state_t fRegisters;
++ ppc_float_state_t fFloatRegisters;
++ v128 fVectorRegisters[32]; // offset 424
++};
++
++
++
++inline Registers_ppc::Registers_ppc(const void* registers)
++{
++ COMPILE_TIME_ASSERT( sizeof(Registers_ppc) < sizeof(unw_context_t) );
++ fRegisters = *((ppc_thread_state_t*)registers);
++ fFloatRegisters = *((ppc_float_state_t*)((char*)registers+160));
++ memcpy(fVectorRegisters, ((char*)registers+424), sizeof(fVectorRegisters));
++}
++
++inline Registers_ppc::Registers_ppc()
++{
++ bzero(&fRegisters, sizeof(fRegisters));
++ bzero(&fFloatRegisters, sizeof(fFloatRegisters));
++ bzero(&fVectorRegisters, sizeof(fVectorRegisters));
++}
++
++
++inline bool Registers_ppc::validRegister(int regNum) const
++{
++ if ( regNum == UNW_REG_IP )
++ return true;
++ if ( regNum == UNW_REG_SP )
++ return true;
++ if ( regNum == UNW_PPC_VRSAVE )
++ return true;
++ if ( regNum < 0 )
++ return false;
++ if ( regNum <= UNW_PPC_R31 )
++ return true;
++ if ( regNum == UNW_PPC_MQ )
++ return true;
++ if ( regNum == UNW_PPC_LR )
++ return true;
++ if ( regNum == UNW_PPC_CTR )
++ return true;
++ if ( (UNW_PPC_CR0 <= regNum) && (regNum <= UNW_PPC_CR7) )
++ return true;
++ return false;
++}
++
++
++inline uint32_t Registers_ppc::getRegister(int regNum) const
++{
++ switch ( regNum ) {
++ case UNW_REG_IP:
++ return fRegisters.__srr0;
++ case UNW_REG_SP:
++ return fRegisters.__r1;
++ case UNW_PPC_R0:
++ return fRegisters.__r0;
++ case UNW_PPC_R1:
++ return fRegisters.__r1;
++ case UNW_PPC_R2:
++ return fRegisters.__r2;
++ case UNW_PPC_R3:
++ return fRegisters.__r3;
++ case UNW_PPC_R4:
++ return fRegisters.__r4;
++ case UNW_PPC_R5:
++ return fRegisters.__r5;
++ case UNW_PPC_R6:
++ return fRegisters.__r6;
++ case UNW_PPC_R7:
++ return fRegisters.__r7;
++ case UNW_PPC_R8:
++ return fRegisters.__r8;
++ case UNW_PPC_R9:
++ return fRegisters.__r9;
++ case UNW_PPC_R10:
++ return fRegisters.__r10;
++ case UNW_PPC_R11:
++ return fRegisters.__r11;
++ case UNW_PPC_R12:
++ return fRegisters.__r12;
++ case UNW_PPC_R13:
++ return fRegisters.__r13;
++ case UNW_PPC_R14:
++ return fRegisters.__r14;
++ case UNW_PPC_R15:
++ return fRegisters.__r15;
++ case UNW_PPC_R16:
++ return fRegisters.__r16;
++ case UNW_PPC_R17:
++ return fRegisters.__r17;
++ case UNW_PPC_R18:
++ return fRegisters.__r18;
++ case UNW_PPC_R19:
++ return fRegisters.__r19;
++ case UNW_PPC_R20:
++ return fRegisters.__r20;
++ case UNW_PPC_R21:
++ return fRegisters.__r21;
++ case UNW_PPC_R22:
++ return fRegisters.__r22;
++ case UNW_PPC_R23:
++ return fRegisters.__r23;
++ case UNW_PPC_R24:
++ return fRegisters.__r24;
++ case UNW_PPC_R25:
++ return fRegisters.__r25;
++ case UNW_PPC_R26:
++ return fRegisters.__r26;
++ case UNW_PPC_R27:
++ return fRegisters.__r27;
++ case UNW_PPC_R28:
++ return fRegisters.__r28;
++ case UNW_PPC_R29:
++ return fRegisters.__r29;
++ case UNW_PPC_R30:
++ return fRegisters.__r30;
++ case UNW_PPC_R31:
++ return fRegisters.__r31;
++ case UNW_PPC_LR:
++ return fRegisters.__lr;
++ case UNW_PPC_CR0:
++ return (fRegisters.__cr & 0xF0000000);
++ case UNW_PPC_CR1:
++ return (fRegisters.__cr & 0x0F000000);
++ case UNW_PPC_CR2:
++ return (fRegisters.__cr & 0x00F00000);
++ case UNW_PPC_CR3:
++ return (fRegisters.__cr & 0x000F0000);
++ case UNW_PPC_CR4:
++ return (fRegisters.__cr & 0x0000F000);
++ case UNW_PPC_CR5:
++ return (fRegisters.__cr & 0x00000F00);
++ case UNW_PPC_CR6:
++ return (fRegisters.__cr & 0x000000F0);
++ case UNW_PPC_CR7:
++ return (fRegisters.__cr & 0x0000000F);
++ case UNW_PPC_VRSAVE:
++ return fRegisters.__vrsave;
++ }
++ ABORT("unsupported ppc register");
++}
++
++
++inline void Registers_ppc::setRegister(int regNum, uint32_t value)
++{
++ //fprintf(stderr, "Registers_ppc::setRegister(%d, 0x%08X)\n", regNum, value);
++ switch ( regNum ) {
++ case UNW_REG_IP:
++ fRegisters.__srr0 = value;
++ return;
++ case UNW_REG_SP:
++ fRegisters.__r1 = value;
++ return;
++ case UNW_PPC_R0:
++ fRegisters.__r0 = value;
++ return;
++ case UNW_PPC_R1:
++ fRegisters.__r1 = value;
++ return;
++ case UNW_PPC_R2:
++ fRegisters.__r2 = value;
++ return;
++ case UNW_PPC_R3:
++ fRegisters.__r3 = value;
++ return;
++ case UNW_PPC_R4:
++ fRegisters.__r4 = value;
++ return;
++ case UNW_PPC_R5:
++ fRegisters.__r5 = value;
++ return;
++ case UNW_PPC_R6:
++ fRegisters.__r6 = value;
++ return;
++ case UNW_PPC_R7:
++ fRegisters.__r7 = value;
++ return;
++ case UNW_PPC_R8:
++ fRegisters.__r8 = value;
++ return;
++ case UNW_PPC_R9:
++ fRegisters.__r9 = value;
++ return;
++ case UNW_PPC_R10:
++ fRegisters.__r10 = value;
++ return;
++ case UNW_PPC_R11:
++ fRegisters.__r11 = value;
++ return;
++ case UNW_PPC_R12:
++ fRegisters.__r12 = value;
++ return;
++ case UNW_PPC_R13:
++ fRegisters.__r13 = value;
++ return;
++ case UNW_PPC_R14:
++ fRegisters.__r14 = value;
++ return;
++ case UNW_PPC_R15:
++ fRegisters.__r15 = value;
++ return;
++ case UNW_PPC_R16:
++ fRegisters.__r16 = value;
++ return;
++ case UNW_PPC_R17:
++ fRegisters.__r17 = value;
++ return;
++ case UNW_PPC_R18:
++ fRegisters.__r18 = value;
++ return;
++ case UNW_PPC_R19:
++ fRegisters.__r19 = value;
++ return;
++ case UNW_PPC_R20:
++ fRegisters.__r20 = value;
++ return;
++ case UNW_PPC_R21:
++ fRegisters.__r21 = value;
++ return;
++ case UNW_PPC_R22:
++ fRegisters.__r22 = value;
++ return;
++ case UNW_PPC_R23:
++ fRegisters.__r23 = value;
++ return;
++ case UNW_PPC_R24:
++ fRegisters.__r24 = value;
++ return;
++ case UNW_PPC_R25:
++ fRegisters.__r25 = value;
++ return;
++ case UNW_PPC_R26:
++ fRegisters.__r26 = value;
++ return;
++ case UNW_PPC_R27:
++ fRegisters.__r27 = value;
++ return;
++ case UNW_PPC_R28:
++ fRegisters.__r28 = value;
++ return;
++ case UNW_PPC_R29:
++ fRegisters.__r29 = value;
++ return;
++ case UNW_PPC_R30:
++ fRegisters.__r30 = value;
++ return;
++ case UNW_PPC_R31:
++ fRegisters.__r31 = value;
++ return;
++ case UNW_PPC_MQ:
++ fRegisters.__mq = value;
++ return;
++ case UNW_PPC_LR:
++ fRegisters.__lr = value;
++ return;
++ case UNW_PPC_CTR:
++ fRegisters.__ctr = value;
++ return;
++ case UNW_PPC_CR0:
++ fRegisters.__cr &= 0x0FFFFFFF;
++ fRegisters.__cr |= (value & 0xF0000000);
++ return;
++ case UNW_PPC_CR1:
++ fRegisters.__cr &= 0xF0FFFFFF;
++ fRegisters.__cr |= (value & 0x0F000000);
++ return;
++ case UNW_PPC_CR2:
++ fRegisters.__cr &= 0xFF0FFFFF;
++ fRegisters.__cr |= (value & 0x00F00000);
++ return;
++ case UNW_PPC_CR3:
++ fRegisters.__cr &= 0xFFF0FFFF;
++ fRegisters.__cr |= (value & 0x000F0000);
++ return;
++ case UNW_PPC_CR4:
++ fRegisters.__cr &= 0xFFFF0FFF;
++ fRegisters.__cr |= (value & 0x0000F000);
++ return;
++ case UNW_PPC_CR5:
++ fRegisters.__cr &= 0xFFFFF0FF;
++ fRegisters.__cr |= (value & 0x00000F00);
++ return;
++ case UNW_PPC_CR6:
++ fRegisters.__cr &= 0xFFFFFF0F;
++ fRegisters.__cr |= (value & 0x000000F0);
++ return;
++ case UNW_PPC_CR7:
++ fRegisters.__cr &= 0xFFFFFFF0;
++ fRegisters.__cr |= (value & 0x0000000F);
++ return;
++ case UNW_PPC_VRSAVE:
++ fRegisters.__vrsave = value;
++ return;
++ // not saved
++ return;
++ case UNW_PPC_XER:
++ fRegisters.__xer = value;
++ return;
++ case UNW_PPC_AP:
++ case UNW_PPC_VSCR:
++ case UNW_PPC_SPEFSCR:
++ // not saved
++ return;
++ }
++ ABORT("unsupported ppc register");
++}
++
++inline bool Registers_ppc::validFloatRegister(int regNum) const
++{
++ if ( regNum < UNW_PPC_F0 )
++ return false;
++ if ( regNum > UNW_PPC_F31 )
++ return false;
++ return true;
++}
++
++inline double Registers_ppc::getFloatRegister(int regNum) const
++{
++ assert(validFloatRegister(regNum));
++ return fFloatRegisters.__fpregs[regNum-UNW_PPC_F0];
++}
++
++inline void Registers_ppc::setFloatRegister(int regNum, double value)
++{
++ //fprintf(stderr, "Registers_ppc::setFloatRegister(%d, %g))\n", regNum, value);
++ assert(validFloatRegister(regNum));
++ fFloatRegisters.__fpregs[regNum-UNW_PPC_F0] = value;
++}
++
++
++inline bool Registers_ppc::validVectorRegister(int regNum) const
++{
++ if ( regNum < UNW_PPC_V0 )
++ return false;
++ if ( regNum > UNW_PPC_V31 )
++ return false;
++ return true;
++}
++
++v128 Registers_ppc::getVectorRegister(int regNum) const
++{
++ assert(validVectorRegister(regNum));
++ v128 result = fVectorRegisters[regNum-UNW_PPC_V0];
++ //fprintf(stderr, "Registers_ppc::getVectorRegister(this=%p, %d) => <0x%08X, 0x%08X, 0x%08X, 0x%08X> \n",
++ // this, regNum, result.vec[0], result.vec[1], result.vec[2], result.vec[3]);
++ return result;
++}
++
++void Registers_ppc::setVectorRegister(int regNum, v128 value)
++{
++ assert(validVectorRegister(regNum));
++ //fprintf(stderr, "Registers_ppc::setVectorRegister(this=%p, %d) <0x%08X, 0x%08X, 0x%08X, 0x%08X> => <0x%08X, 0x%08X, 0x%08X, 0x%08X> \n",
++ // this, regNum, fVectorRegisters[regNum-UNW_PPC_V0].vec[0], fVectorRegisters[regNum-UNW_PPC_V0].vec[1], fVectorRegisters[regNum-UNW_PPC_V0].vec[2],
++ // fVectorRegisters[regNum-UNW_PPC_V0].vec[3], value.vec[0], value.vec[1], value.vec[2], value.vec[3]);
++ fVectorRegisters[regNum-UNW_PPC_V0] = value;
++}
++
++
++inline const char* Registers_ppc::getRegisterName(int regNum)
++{
++ switch ( regNum ) {
++ case UNW_REG_IP:
++ return "ip";
++ case UNW_REG_SP:
++ return "sp";
++ case UNW_PPC_R0:
++ return "r0";
++ case UNW_PPC_R1:
++ return "r1";
++ case UNW_PPC_R2:
++ return "r2";
++ case UNW_PPC_R3:
++ return "r3";
++ case UNW_PPC_R4:
++ return "r4";
++ case UNW_PPC_R5:
++ return "r5";
++ case UNW_PPC_R6:
++ return "r6";
++ case UNW_PPC_R7:
++ return "r7";
++ case UNW_PPC_R8:
++ return "r8";
++ case UNW_PPC_R9:
++ return "r9";
++ case UNW_PPC_R10:
++ return "r10";
++ case UNW_PPC_R11:
++ return "r11";
++ case UNW_PPC_R12:
++ return "r12";
++ case UNW_PPC_R13:
++ return "r13";
++ case UNW_PPC_R14:
++ return "r14";
++ case UNW_PPC_R15:
++ return "r15";
++ case UNW_PPC_R16:
++ return "r16";
++ case UNW_PPC_R17:
++ return "r17";
++ case UNW_PPC_R18:
++ return "r18";
++ case UNW_PPC_R19:
++ return "r19";
++ case UNW_PPC_R20:
++ return "r20";
++ case UNW_PPC_R21:
++ return "r21";
++ case UNW_PPC_R22:
++ return "r22";
++ case UNW_PPC_R23:
++ return "r23";
++ case UNW_PPC_R24:
++ return "r24";
++ case UNW_PPC_R25:
++ return "r25";
++ case UNW_PPC_R26:
++ return "r26";
++ case UNW_PPC_R27:
++ return "r27";
++ case UNW_PPC_R28:
++ return "r28";
++ case UNW_PPC_R29:
++ return "r29";
++ case UNW_PPC_R30:
++ return "r30";
++ case UNW_PPC_R31:
++ return "r31";
++ case UNW_PPC_F0:
++ return "fp0";
++ case UNW_PPC_F1:
++ return "fp1";
++ case UNW_PPC_F2:
++ return "fp2";
++ case UNW_PPC_F3:
++ return "fp3";
++ case UNW_PPC_F4:
++ return "fp4";
++ case UNW_PPC_F5:
++ return "fp5";
++ case UNW_PPC_F6:
++ return "fp6";
++ case UNW_PPC_F7:
++ return "fp7";
++ case UNW_PPC_F8:
++ return "fp8";
++ case UNW_PPC_F9:
++ return "fp9";
++ case UNW_PPC_F10:
++ return "fp10";
++ case UNW_PPC_F11:
++ return "fp11";
++ case UNW_PPC_F12:
++ return "fp12";
++ case UNW_PPC_F13:
++ return "fp13";
++ case UNW_PPC_F14:
++ return "fp14";
++ case UNW_PPC_F15:
++ return "fp15";
++ case UNW_PPC_F16:
++ return "fp16";
++ case UNW_PPC_F17:
++ return "fp17";
++ case UNW_PPC_F18:
++ return "fp18";
++ case UNW_PPC_F19:
++ return "fp19";
++ case UNW_PPC_F20:
++ return "fp20";
++ case UNW_PPC_F21:
++ return "fp21";
++ case UNW_PPC_F22:
++ return "fp22";
++ case UNW_PPC_F23:
++ return "fp23";
++ case UNW_PPC_F24:
++ return "fp24";
++ case UNW_PPC_F25:
++ return "fp25";
++ case UNW_PPC_F26:
++ return "fp26";
++ case UNW_PPC_F27:
++ return "fp27";
++ case UNW_PPC_F28:
++ return "fp28";
++ case UNW_PPC_F29:
++ return "fp29";
++ case UNW_PPC_F30:
++ return "fp30";
++ case UNW_PPC_F31:
++ return "fp31";
++ case UNW_PPC_LR:
++ return "lr";
++ default:
++ return "unknown register";
++ }
++
++
++}
++
++
++} // namespace libunwind
++
++
++
++#endif // __REGISTERS_HPP__
++
++
++
++
+--
+2.2.1
+
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/macports-changes/attachments/20150213/5c941286/attachment-0001.html>
More information about the macports-changes
mailing list