existing libunwind used '0' in lsda_encoding as 'not present,'
whereas that is a valid encoding and does occur and would be
ignored. a missing encoding is actually 0xff.
The commit that addresses this is:
commit 8d4b51028d1a12b58d616f4b605254a877caafcf
Author: joerg <joerg>
Date:   Tue Mar 11 23:52:17 2014 +0000
    0 is a valid LSDA encoding and can be seen in statically linked
    programs. Initialize lsdaEncoding to DW_EH_PE_omit and check for that
    value to decide whether a value should be decoded.
more bugfixes are necessary. this update is up to:
commit b1f513eedd332426d88acbb118b6e9070966dcb9
Author: joerg <joerg>
Date:   Wed May 14 22:13:36 2014 +0000
    Lazy VFP processing works a lot better if the functions contain a return
    instruction.
		
	
			
		
			
				
	
	
		
			547 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			547 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
//===--------------------------- DwarfParser.hpp --------------------------===//
 | 
						|
//
 | 
						|
//                     The LLVM Compiler Infrastructure
 | 
						|
//
 | 
						|
// This file is dual licensed under the MIT and the University of Illinois Open
 | 
						|
// Source Licenses. See LICENSE.TXT for details.
 | 
						|
//
 | 
						|
//
 | 
						|
//  Parses DWARF CFIs (FDEs and CIEs).
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#ifndef __DWARF_PARSER_HPP__
 | 
						|
#define __DWARF_PARSER_HPP__
 | 
						|
 | 
						|
#include <cstdint>
 | 
						|
#include <cstdlib>
 | 
						|
 | 
						|
#include "dwarf2.h"
 | 
						|
#include "AddressSpace.hpp"
 | 
						|
 | 
						|
namespace _Unwind {
 | 
						|
 | 
						|
/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
 | 
						|
/// See Dwarf Spec for details:
 | 
						|
///    http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
 | 
						|
///
 | 
						|
template <typename A, typename R> 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;
 | 
						|
    pint_t personality;
 | 
						|
    uint32_t codeAlignFactor;
 | 
						|
    int dataAlignFactor;
 | 
						|
    uint8_t pointerEncoding;
 | 
						|
    uint8_t lsdaEncoding;
 | 
						|
    uint8_t personalityEncoding;
 | 
						|
    uint8_t personalityOffsetInCIE;
 | 
						|
    bool isSignalFrame;
 | 
						|
    bool fdesHaveAugmentationData;
 | 
						|
    uint8_t returnAddressRegister;
 | 
						|
  };
 | 
						|
 | 
						|
  /// 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;
 | 
						|
  };
 | 
						|
 | 
						|
  /// Information about a frame layout and registers saved determined
 | 
						|
  /// by "running" the DWARF FDE "instructions"
 | 
						|
  enum {
 | 
						|
    kMaxRegisterNumber = R::LAST_REGISTER + 1
 | 
						|
  };
 | 
						|
  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;
 | 
						|
    RegisterLocation savedRegisters[kMaxRegisterNumber];
 | 
						|
  };
 | 
						|
 | 
						|
  struct PrologInfoStackEntry {
 | 
						|
    PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i)
 | 
						|
        : next(n), info(i) {}
 | 
						|
    PrologInfoStackEntry *next;
 | 
						|
    PrologInfo info;
 | 
						|
  };
 | 
						|
 | 
						|
  static void findPCRange(A &, pint_t, pint_t &, pint_t &);
 | 
						|
 | 
						|
  static bool decodeFDE(A &, pint_t, FDE_Info *, CIE_Info *,
 | 
						|
                        unw_proc_info_t *ctx);
 | 
						|
  static bool parseFDEInstructions(A &, const FDE_Info &, const CIE_Info &,
 | 
						|
                                   pint_t, PrologInfo *, unw_proc_info_t *ctx);
 | 
						|
 | 
						|
  static bool parseCIE(A &, pint_t, CIE_Info *);
 | 
						|
 | 
						|
private:
 | 
						|
  static bool parseInstructions(A &, pint_t, pint_t, const CIE_Info &, pint_t,
 | 
						|
                                PrologInfoStackEntry *&, PrologInfo *,
 | 
						|
                                unw_proc_info_t *ctx);
 | 
						|
};
 | 
						|
 | 
						|
///
 | 
						|
/// Parse a FDE and return the last PC it covers.
 | 
						|
///
 | 
						|
template <typename A, typename R>
 | 
						|
void CFI_Parser<A, R>::findPCRange(A &addressSpace, pint_t fde, pint_t &pcStart,
 | 
						|
                                   pint_t &pcEnd) {
 | 
						|
  pcStart = 0;
 | 
						|
  pcEnd = 0;
 | 
						|
  pint_t p = fde;
 | 
						|
  uint64_t cfiLength = addressSpace.get32(p);
 | 
						|
  p += 4;
 | 
						|
  if (cfiLength == 0xffffffff) {
 | 
						|
    // 0xffffffff means length is really the next 8 Bytes.
 | 
						|
    cfiLength = addressSpace.get64(p);
 | 
						|
    p += 8;
 | 
						|
  }
 | 
						|
  if (cfiLength == 0)
 | 
						|
    return;
 | 
						|
  uint32_t ciePointer = addressSpace.get32(p);
 | 
						|
  if (ciePointer == 0)
 | 
						|
    return;
 | 
						|
  pint_t nextCFI = p + cfiLength;
 | 
						|
  pint_t cieStart = p - ciePointer;
 | 
						|
  typename CFI_Parser<A, R>::CIE_Info cieInfo;
 | 
						|
  if (!parseCIE(addressSpace, cieStart, &cieInfo))
 | 
						|
    return;
 | 
						|
  p += 4;
 | 
						|
  // Parse pc begin and range.
 | 
						|
  pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding, NULL);
 | 
						|
  pcEnd = pcStart + addressSpace.getEncodedP(
 | 
						|
                        p, nextCFI, cieInfo.pointerEncoding & 0x0F, NULL);
 | 
						|
}
 | 
						|
 | 
						|
///
 | 
						|
/// Parse a FDE into a CIE_Info and an FDE_Info
 | 
						|
///
 | 
						|
template <typename A, typename R>
 | 
						|
bool CFI_Parser<A, R>::decodeFDE(A &addressSpace, pint_t fdeStart,
 | 
						|
                                 FDE_Info *fdeInfo, CIE_Info *cieInfo,
 | 
						|
                                 unw_proc_info_t *ctx) {
 | 
						|
  pint_t p = fdeStart;
 | 
						|
  uint64_t cfiLength = addressSpace.get32(p);
 | 
						|
  p += 4;
 | 
						|
  if (cfiLength == 0xffffffff) {
 | 
						|
    // 0xffffffff means length is really the next 8 Bytes.
 | 
						|
    cfiLength = addressSpace.get64(p);
 | 
						|
    p += 8;
 | 
						|
  }
 | 
						|
  if (cfiLength == 0)
 | 
						|
    return false;
 | 
						|
  uint32_t ciePointer = addressSpace.get32(p);
 | 
						|
  if (ciePointer == 0)
 | 
						|
    return false;
 | 
						|
  pint_t nextCFI = p + cfiLength;
 | 
						|
  pint_t cieStart = p - ciePointer;
 | 
						|
  if (!parseCIE(addressSpace, cieStart, cieInfo))
 | 
						|
    return false;
 | 
						|
  p += 4;
 | 
						|
  // Parse pc begin and range.
 | 
						|
  pint_t pcStart =
 | 
						|
      addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding, ctx);
 | 
						|
  pint_t pcRange = addressSpace.getEncodedP(
 | 
						|
      p, nextCFI, cieInfo->pointerEncoding & 0x0F, ctx);
 | 
						|
  // 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 != DW_EH_PE_omit) {
 | 
						|
      // Peek at value (without indirection).  Zero means no LSDA.
 | 
						|
      pint_t lsdaStart = p;
 | 
						|
      if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F,
 | 
						|
                                   ctx) != 0) {
 | 
						|
        // Reset pointer and re-parse LSDA address.
 | 
						|
        p = lsdaStart;
 | 
						|
        fdeInfo->lsda =
 | 
						|
            addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding, ctx);
 | 
						|
      }
 | 
						|
    }
 | 
						|
    p = endOfAug;
 | 
						|
  }
 | 
						|
  fdeInfo->fdeStart = fdeStart;
 | 
						|
  fdeInfo->fdeLength = nextCFI - fdeStart;
 | 
						|
  fdeInfo->fdeInstructions = p;
 | 
						|
  fdeInfo->pcStart = pcStart;
 | 
						|
  fdeInfo->pcEnd = pcStart + pcRange;
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
/// Extract info from a CIE
 | 
						|
template <typename A, typename R>
 | 
						|
bool CFI_Parser<A, R>::parseCIE(A &addressSpace, pint_t cie,
 | 
						|
                                CIE_Info *cieInfo) {
 | 
						|
  cieInfo->pointerEncoding = 0;
 | 
						|
  cieInfo->lsdaEncoding = DW_EH_PE_omit;
 | 
						|
  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 the next 8 Bytes.
 | 
						|
    cieLength = addressSpace.get64(p);
 | 
						|
    p += 8;
 | 
						|
    cieContentEnd = p + cieLength;
 | 
						|
  }
 | 
						|
  if (cieLength == 0)
 | 
						|
    return true;
 | 
						|
  // CIE ID is always 0
 | 
						|
  if (addressSpace.get32(p) != 0)
 | 
						|
    return false;
 | 
						|
  p += 4;
 | 
						|
  // Version is always 1 or 3
 | 
						|
  uint8_t version = addressSpace.get8(p);
 | 
						|
  if (version != 1 && version != 3)
 | 
						|
    return false;
 | 
						|
  ++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
 | 
						|
  cieInfo->returnAddressRegister = (uint8_t)addressSpace.getULEB128(p, cieContentEnd);
 | 
						|
  // Parse augmentation data based on augmentation string.
 | 
						|
  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, NULL);
 | 
						|
        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 true;
 | 
						|
}
 | 
						|
 | 
						|
/// "Run" the dwarf instructions and create the abstact PrologInfo for an FDE.
 | 
						|
template <typename A, typename R>
 | 
						|
bool CFI_Parser<A, R>::parseFDEInstructions(A &addressSpace,
 | 
						|
                                            const FDE_Info &fdeInfo,
 | 
						|
                                            const CIE_Info &cieInfo,
 | 
						|
                                            pint_t upToPC, PrologInfo *results,
 | 
						|
                                            unw_proc_info_t *ctx) {
 | 
						|
  // Clear results.
 | 
						|
  memset(results, 0, sizeof(*results));
 | 
						|
  PrologInfoStackEntry *rememberStack = NULL;
 | 
						|
 | 
						|
  // First parse the CIE then FDE instructions.
 | 
						|
  if (!parseInstructions(addressSpace, cieInfo.cieInstructions,
 | 
						|
                         cieInfo.cieStart + cieInfo.cieLength, cieInfo,
 | 
						|
                         (pint_t)(-1), rememberStack, results, ctx))
 | 
						|
    return false;
 | 
						|
  return parseInstructions(addressSpace, fdeInfo.fdeInstructions,
 | 
						|
                           fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo,
 | 
						|
                           upToPC - fdeInfo.pcStart, rememberStack, results,
 | 
						|
                           ctx);
 | 
						|
}
 | 
						|
 | 
						|
/// "Run" the DWARF instructions.
 | 
						|
template <typename A, typename R>
 | 
						|
bool
 | 
						|
CFI_Parser<A, R>::parseInstructions(A &addressSpace, pint_t instructions,
 | 
						|
                                    pint_t instructionsEnd,
 | 
						|
                                    const CIE_Info &cieInfo, pint_t pcoffset,
 | 
						|
                                    PrologInfoStackEntry *&rememberStack,
 | 
						|
                                    PrologInfo *results, unw_proc_info_t *ctx) {
 | 
						|
  pint_t p = instructions;
 | 
						|
  uint32_t codeOffset = 0;
 | 
						|
  PrologInfo initialState = *results;
 | 
						|
 | 
						|
  // 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:
 | 
						|
      break;
 | 
						|
    case DW_CFA_set_loc:
 | 
						|
      codeOffset = addressSpace.getEncodedP(p, instructionsEnd,
 | 
						|
                                            cieInfo.pointerEncoding, ctx);
 | 
						|
      break;
 | 
						|
    case DW_CFA_advance_loc1:
 | 
						|
      codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
 | 
						|
      p += 1;
 | 
						|
      break;
 | 
						|
    case DW_CFA_advance_loc2:
 | 
						|
      codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
 | 
						|
      p += 2;
 | 
						|
      break;
 | 
						|
    case DW_CFA_advance_loc4:
 | 
						|
      codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
 | 
						|
      p += 4;
 | 
						|
      break;
 | 
						|
    case DW_CFA_offset_extended:
 | 
						|
      reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
 | 
						|
      offset =
 | 
						|
          addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
 | 
						|
      if (reg > kMaxRegisterNumber)
 | 
						|
        return false;
 | 
						|
      results->savedRegisters[reg].location = kRegisterInCFA;
 | 
						|
      results->savedRegisters[reg].value = offset;
 | 
						|
      break;
 | 
						|
    case DW_CFA_restore_extended:
 | 
						|
      reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
 | 
						|
      if (reg > kMaxRegisterNumber)
 | 
						|
        return false;
 | 
						|
      results->savedRegisters[reg] = initialState.savedRegisters[reg];
 | 
						|
      break;
 | 
						|
    case DW_CFA_undefined:
 | 
						|
      reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
 | 
						|
      if (reg > kMaxRegisterNumber)
 | 
						|
        return false;
 | 
						|
      results->savedRegisters[reg].location = kRegisterUnused;
 | 
						|
      break;
 | 
						|
    case DW_CFA_same_value:
 | 
						|
      reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
 | 
						|
      if (reg > kMaxRegisterNumber)
 | 
						|
        return false;
 | 
						|
      // "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;
 | 
						|
      break;
 | 
						|
    case DW_CFA_register:
 | 
						|
      reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
 | 
						|
      reg2 = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
 | 
						|
      if (reg > kMaxRegisterNumber)
 | 
						|
        return false;
 | 
						|
      if (reg2 > kMaxRegisterNumber)
 | 
						|
        return false;
 | 
						|
      results->savedRegisters[reg].location = kRegisterInRegister;
 | 
						|
      results->savedRegisters[reg].value = 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)
 | 
						|
        return false;
 | 
						|
 | 
						|
      entry->next = rememberStack;
 | 
						|
      entry->info = *results;
 | 
						|
      rememberStack = entry;
 | 
						|
      break;
 | 
						|
    case DW_CFA_restore_state:
 | 
						|
      if (rememberStack == NULL)
 | 
						|
        return false;
 | 
						|
      {
 | 
						|
        PrologInfoStackEntry *top = rememberStack;
 | 
						|
        *results = top->info;
 | 
						|
        rememberStack = top->next;
 | 
						|
        free((char *)top);
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    case DW_CFA_def_cfa:
 | 
						|
      reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
 | 
						|
      offset = addressSpace.getULEB128(p, instructionsEnd);
 | 
						|
      if (reg > kMaxRegisterNumber)
 | 
						|
        return false;
 | 
						|
      results->cfaRegister = reg;
 | 
						|
      results->cfaRegisterOffset = offset;
 | 
						|
      break;
 | 
						|
    case DW_CFA_def_cfa_register:
 | 
						|
      reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
 | 
						|
      if (reg > kMaxRegisterNumber)
 | 
						|
        return false;
 | 
						|
      results->cfaRegister = reg;
 | 
						|
      break;
 | 
						|
    case DW_CFA_def_cfa_offset:
 | 
						|
      results->cfaRegisterOffset = addressSpace.getULEB128(p, instructionsEnd);
 | 
						|
      results->codeOffsetAtStackDecrement = codeOffset;
 | 
						|
      break;
 | 
						|
    case DW_CFA_def_cfa_expression:
 | 
						|
      results->cfaRegister = 0;
 | 
						|
      results->cfaExpression = p;
 | 
						|
      length = addressSpace.getULEB128(p, instructionsEnd);
 | 
						|
      p += length;
 | 
						|
      break;
 | 
						|
    case DW_CFA_expression:
 | 
						|
      reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
 | 
						|
      if (reg > kMaxRegisterNumber)
 | 
						|
        return false;
 | 
						|
      results->savedRegisters[reg].location = kRegisterAtExpression;
 | 
						|
      results->savedRegisters[reg].value = p;
 | 
						|
      length = addressSpace.getULEB128(p, instructionsEnd);
 | 
						|
      p += length;
 | 
						|
      break;
 | 
						|
    case DW_CFA_offset_extended_sf:
 | 
						|
      reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
 | 
						|
      if (reg > kMaxRegisterNumber)
 | 
						|
        return false;
 | 
						|
      offset =
 | 
						|
          addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
 | 
						|
      results->savedRegisters[reg].location = kRegisterInCFA;
 | 
						|
      results->savedRegisters[reg].value = offset;
 | 
						|
      break;
 | 
						|
    case DW_CFA_def_cfa_sf:
 | 
						|
      reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
 | 
						|
      offset =
 | 
						|
          addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
 | 
						|
      if (reg > kMaxRegisterNumber)
 | 
						|
        return false;
 | 
						|
      results->cfaRegister = reg;
 | 
						|
      results->cfaRegisterOffset = offset;
 | 
						|
      break;
 | 
						|
    case DW_CFA_def_cfa_offset_sf:
 | 
						|
      results->cfaRegisterOffset =
 | 
						|
          addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
 | 
						|
      results->codeOffsetAtStackDecrement = codeOffset;
 | 
						|
      break;
 | 
						|
    case DW_CFA_val_offset:
 | 
						|
      reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
 | 
						|
      offset =
 | 
						|
          addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
 | 
						|
      if (reg > kMaxRegisterNumber)
 | 
						|
        return false;
 | 
						|
      results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
 | 
						|
      results->savedRegisters[reg].value = offset;
 | 
						|
      break;
 | 
						|
    case DW_CFA_val_offset_sf:
 | 
						|
      reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
 | 
						|
      if (reg > kMaxRegisterNumber)
 | 
						|
        return false;
 | 
						|
      offset =
 | 
						|
          addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
 | 
						|
      results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
 | 
						|
      results->savedRegisters[reg].value = offset;
 | 
						|
      break;
 | 
						|
    case DW_CFA_val_expression:
 | 
						|
      reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
 | 
						|
      if (reg > kMaxRegisterNumber)
 | 
						|
        return false;
 | 
						|
      results->savedRegisters[reg].location = kRegisterIsExpression;
 | 
						|
      results->savedRegisters[reg].value = p;
 | 
						|
      length = addressSpace.getULEB128(p, instructionsEnd);
 | 
						|
      p += length;
 | 
						|
      break;
 | 
						|
    case DW_CFA_GNU_window_save:
 | 
						|
#if defined(__sparc__)
 | 
						|
      for (reg = 8; reg < 16; ++reg) {
 | 
						|
        results->savedRegisters[reg].location = kRegisterInRegister;
 | 
						|
        results->savedRegisters[reg].value = reg + 16;
 | 
						|
      }
 | 
						|
      for (reg = 16; reg < 32; ++reg) {
 | 
						|
        results->savedRegisters[reg].location = kRegisterInCFA;
 | 
						|
        results->savedRegisters[reg].value = (reg - 16) * sizeof(typename R::reg_t);
 | 
						|
      }
 | 
						|
      break;
 | 
						|
#else
 | 
						|
      return false;
 | 
						|
#endif
 | 
						|
    case DW_CFA_GNU_args_size:
 | 
						|
      offset = addressSpace.getULEB128(p, instructionsEnd);
 | 
						|
      results->spExtraArgSize = offset;
 | 
						|
      break;
 | 
						|
    case DW_CFA_GNU_negative_offset_extended:
 | 
						|
      reg = R::dwarf2regno(addressSpace.getULEB128(p, instructionsEnd));
 | 
						|
      if (reg > kMaxRegisterNumber)
 | 
						|
        return false;
 | 
						|
      offset =
 | 
						|
          addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
 | 
						|
      results->savedRegisters[reg].location = kRegisterInCFA;
 | 
						|
      results->savedRegisters[reg].value = -offset;
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      operand = opcode & 0x3F;
 | 
						|
      switch (opcode & 0xC0) {
 | 
						|
      case DW_CFA_offset:
 | 
						|
        reg = R::dwarf2regno(operand);
 | 
						|
        if (reg > kMaxRegisterNumber)
 | 
						|
          return false;
 | 
						|
        offset = addressSpace.getULEB128(p, instructionsEnd) *
 | 
						|
                 cieInfo.dataAlignFactor;
 | 
						|
        results->savedRegisters[reg].location = kRegisterInCFA;
 | 
						|
        results->savedRegisters[reg].value = offset;
 | 
						|
        break;
 | 
						|
      case DW_CFA_advance_loc:
 | 
						|
        codeOffset += operand * cieInfo.codeAlignFactor;
 | 
						|
        break;
 | 
						|
      case DW_CFA_restore:
 | 
						|
        reg = R::dwarf2regno(operand);
 | 
						|
        if (reg > kMaxRegisterNumber)
 | 
						|
          return false;
 | 
						|
        results->savedRegisters[reg] = initialState.savedRegisters[reg];
 | 
						|
        break;
 | 
						|
      default:
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
} // namespace _Unwind
 | 
						|
 | 
						|
#endif // __DWARF_PARSER_HPP__
 |