예제 #1
0
bool
Disassembler::Disassemble
(
    Debugger &debugger,
    const ArchSpec &arch,
    const char *plugin_name,
    const char *flavor,
    const ExecutionContext &exe_ctx,
    uint32_t num_instructions,
    uint32_t num_mixed_context_lines,
    uint32_t options,
    Stream &strm
)
{
    AddressRange range;
    StackFrame *frame = exe_ctx.GetFramePtr();
    if (frame)
    {
        SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
        if (sc.function)
        {
            range = sc.function->GetAddressRange();
        }
        else if (sc.symbol && sc.symbol->ValueIsAddress())
        {
            range.GetBaseAddress() = sc.symbol->GetAddress();
            range.SetByteSize (sc.symbol->GetByteSize());
        }
        else
        {
            range.GetBaseAddress() = frame->GetFrameCodeAddress();
        }

        if (range.GetBaseAddress().IsValid() && range.GetByteSize() == 0)
            range.SetByteSize (DEFAULT_DISASM_BYTE_SIZE);
    }

    return Disassemble (debugger, 
                        arch, 
                        plugin_name,
                        flavor,
                        exe_ctx, 
                        range, 
                        num_instructions, 
                        num_mixed_context_lines, 
                        options, 
                        strm);
}
예제 #2
0
bool
SymbolContext::GetAddressRange (uint32_t scope, AddressRange &range) const
{
    if ((scope & eSymbolContextLineEntry) && line_entry.IsValid())
    {
        range = line_entry.range;
        return true;
    }
    else if ((scope & eSymbolContextFunction) && function != NULL)
    {
        range = function->GetAddressRange();
        return true;
    }
    else if ((scope & eSymbolContextSymbol) && symbol != NULL && symbol->GetAddressRangePtr())
    {
        range = *symbol->GetAddressRangePtr();

        if (range.GetByteSize() == 0)
        {
            if (module_sp)
            {
                ObjectFile *objfile = module_sp->GetObjectFile();
                if (objfile)
                {
                    Symtab *symtab = objfile->GetSymtab();
                    if (symtab)
                        range.SetByteSize(symtab->CalculateSymbolSize (symbol));
                }
            }
        }
        return true;
    }
    range.Clear();
    return false;
}
예제 #3
0
bool
Disassembler::Disassemble
(
    Debugger &debugger,
    const ArchSpec &arch,
    const ExecutionContext &exe_ctx,
    uint32_t num_mixed_context_lines,
    bool show_bytes,
    Stream &strm
)
{
    AddressRange range;
    if (exe_ctx.frame)
    {
        SymbolContext sc(exe_ctx.frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
        if (sc.function)
        {
            range = sc.function->GetAddressRange();
        }
        else if (sc.symbol && sc.symbol->GetAddressRangePtr())
        {
            range = *sc.symbol->GetAddressRangePtr();
        }
        else
        {
            range.GetBaseAddress() = exe_ctx.frame->GetPC();
        }

        if (range.GetBaseAddress().IsValid() && range.GetByteSize() == 0)
            range.SetByteSize (DEFAULT_DISASM_BYTE_SIZE);
    }

    return Disassemble(debugger, arch, exe_ctx, range, num_mixed_context_lines, show_bytes, strm);
}
예제 #4
0
bool
Block::GetRangeContainingAddress (const Address& addr, AddressRange &range)
{
    Function *function = CalculateSymbolContextFunction();
    if (function)
    {
        const AddressRange &func_range = function->GetAddressRange();
        if (addr.GetSection() == func_range.GetBaseAddress().GetSection())
        {
            const addr_t addr_offset = addr.GetOffset();
            const addr_t func_offset = func_range.GetBaseAddress().GetOffset();
            if (addr_offset >= func_offset && addr_offset < func_offset + func_range.GetByteSize())
            {
                addr_t offset = addr_offset - func_offset;
                
                const Range *range_ptr = m_ranges.FindEntryThatContains (offset);

                if (range_ptr)
                {
                    range.GetBaseAddress() = func_range.GetBaseAddress();
                    range.GetBaseAddress().SetOffset(func_offset + range_ptr->GetRangeBase());
                    range.SetByteSize(range_ptr->GetByteSize());
                    return true;
                }
            }
        }
    }
    range.Clear();
    return false;
}
예제 #5
0
bool
SymbolContext::GetAddressRange (uint32_t scope, 
                                uint32_t range_idx, 
                                bool use_inline_block_range,
                                AddressRange &range) const
{
    if ((scope & eSymbolContextLineEntry) && line_entry.IsValid())
    {
        range = line_entry.range;
        return true;
    }
    
    if ((scope & eSymbolContextBlock) && (block != NULL))
    {
        if (use_inline_block_range)
        {
            Block *inline_block = block->GetContainingInlinedBlock();
            if (inline_block)
                return inline_block->GetRangeAtIndex (range_idx, range);
        }
        else
        {
            return block->GetRangeAtIndex (range_idx, range);
        }
    }

    if ((scope & eSymbolContextFunction) && (function != NULL))
    {
        if (range_idx == 0)
        {
            range = function->GetAddressRange();
            return true;
        }            
    } 
    
    if ((scope & eSymbolContextSymbol) && (symbol != NULL))
    {
        if (range_idx == 0)
        {
            if (symbol->ValueIsAddress())
            {
                range.GetBaseAddress() = symbol->GetAddress();
                range.SetByteSize (symbol->GetByteSize());
                return true;
            }
        }
    }
    range.Clear();
    return false;
}
예제 #6
0
bool
Disassembler::Disassemble
(
    Debugger &debugger,
    const ArchSpec &arch,
    const char *plugin_name,
    const char *flavor,
    const ExecutionContext &exe_ctx,
    const AddressRange &disasm_range,
    uint32_t num_instructions,
    uint32_t num_mixed_context_lines,
    uint32_t options,
    Stream &strm
)
{
    if (disasm_range.GetByteSize())
    {
        lldb::DisassemblerSP disasm_sp (Disassembler::FindPluginForTarget(exe_ctx.GetTargetSP(), arch, flavor, plugin_name));

        if (disasm_sp.get())
        {
            AddressRange range;
            ResolveAddress (exe_ctx, disasm_range.GetBaseAddress(), range.GetBaseAddress());
            range.SetByteSize (disasm_range.GetByteSize());
            const bool prefer_file_cache = false;
            size_t bytes_disassembled = disasm_sp->ParseInstructions (&exe_ctx, range, &strm, prefer_file_cache);
            if (bytes_disassembled == 0)
                return false;

            bool result = PrintInstructions (disasm_sp.get(),
                                             debugger,
                                             arch,
                                             exe_ctx,
                                             num_instructions,
                                             num_mixed_context_lines,
                                             options,
                                             strm);
            
            // FIXME: The DisassemblerLLVMC has a reference cycle and won't go away if it has any active instructions.
            // I'll fix that but for now, just clear the list and it will go away nicely.
            disasm_sp->GetInstructionList().Clear();
            return result;
        }
    }
    return false;
}
예제 #7
0
bool
Block::GetRangeAtIndex (uint32_t range_idx, AddressRange &range)
{
    if (range_idx < m_ranges.GetSize())
    {
        Function *function = CalculateSymbolContextFunction();
        if (function)
        {
            const Range &vm_range = m_ranges.GetEntryRef(range_idx);
            range.GetBaseAddress() = function->GetAddressRange().GetBaseAddress();
            range.GetBaseAddress().Slide(vm_range.GetRangeBase ());
            range.SetByteSize (vm_range.GetByteSize());
            return true;
        }
    }
    return false;
}
예제 #8
0
bool
Disassembler::Disassemble
(
    Debugger &debugger,
    const ArchSpec &arch,
    const char *plugin_name,
    const ExecutionContext &exe_ctx,
    const AddressRange &disasm_range,
    uint32_t num_instructions,
    uint32_t num_mixed_context_lines,
    uint32_t options,
    Stream &strm
)
{
    if (disasm_range.GetByteSize())
    {
        std::auto_ptr<Disassembler> disasm_ap (Disassembler::FindPlugin(arch, plugin_name));

        if (disasm_ap.get())
        {
            AddressRange range;
            ResolveAddress (exe_ctx, disasm_range.GetBaseAddress(), range.GetBaseAddress());
            range.SetByteSize (disasm_range.GetByteSize());
            
            size_t bytes_disassembled = disasm_ap->ParseInstructions (&exe_ctx, range, &strm);
            if (bytes_disassembled == 0)
                return false;

            return PrintInstructions (disasm_ap.get(),
                                      debugger,
                                      arch,
                                      exe_ctx,
                                      num_instructions,
                                      num_mixed_context_lines,
                                      options,
                                      strm);
        }
    }
    return false;
}
예제 #9
0
bool
DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t offset, Address startaddr, UnwindPlan& unwind_plan)
{
    dw_offset_t current_entry = offset;

    if (m_section_sp.get() == NULL || m_section_sp->IsEncrypted())
        return false;

    if (m_cfi_data_initialized == false)
        GetCFIData();

    uint32_t length = m_cfi_data.GetU32 (&offset);
    dw_offset_t cie_offset = m_cfi_data.GetU32 (&offset);

    assert (cie_offset != 0 && cie_offset != UINT32_MAX);

    // Translate the CIE_id from the eh_frame format, which
    // is relative to the FDE offset, into a __eh_frame section
    // offset
    if (m_is_eh_frame)
    {
        unwind_plan.SetSourceName ("eh_frame CFI");
        cie_offset = current_entry + 4 - cie_offset;
        unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
    }
    else
    {
        unwind_plan.SetSourceName ("DWARF CFI");
        // In theory the debug_frame info should be valid at all call sites
        // ("asynchronous unwind info" as it is sometimes called) but in practice
        // gcc et al all emit call frame info for the prologue and call sites, but
        // not for the epilogue or all the other locations during the function reliably.
        unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
    }
    unwind_plan.SetSourcedFromCompiler (eLazyBoolYes);

    const CIE *cie = GetCIE (cie_offset);
    assert (cie != NULL);

    const dw_offset_t end_offset = current_entry + length + 4;

    const lldb::addr_t pc_rel_addr = m_section_sp->GetFileAddress();
    const lldb::addr_t text_addr = LLDB_INVALID_ADDRESS;
    const lldb::addr_t data_addr = LLDB_INVALID_ADDRESS;
    lldb::addr_t range_base = m_cfi_data.GetGNUEHPointer(&offset, cie->ptr_encoding, pc_rel_addr, text_addr, data_addr);
    lldb::addr_t range_len = m_cfi_data.GetGNUEHPointer(&offset, cie->ptr_encoding & DW_EH_PE_MASK_ENCODING, pc_rel_addr, text_addr, data_addr);
    AddressRange range (range_base, m_objfile.GetAddressByteSize(), m_objfile.GetSectionList());
    range.SetByteSize (range_len);

    if (cie->augmentation[0] == 'z')
    {
        uint32_t aug_data_len = (uint32_t)m_cfi_data.GetULEB128(&offset);
        offset += aug_data_len;
    }

    uint32_t reg_num = 0;
    int32_t op_offset = 0;
    uint32_t code_align = cie->code_align;
    int32_t data_align = cie->data_align;

    unwind_plan.SetPlanValidAddressRange (range);
    UnwindPlan::Row *cie_initial_row = new UnwindPlan::Row;
    *cie_initial_row = cie->initial_row;
    UnwindPlan::RowSP row(cie_initial_row);

    unwind_plan.SetRegisterKind (m_reg_kind);
    unwind_plan.SetReturnAddressRegister (cie->return_addr_reg_num);

    UnwindPlan::Row::RegisterLocation reg_location;
    while (m_cfi_data.ValidOffset(offset) && offset < end_offset)
    {
        uint8_t inst = m_cfi_data.GetU8(&offset);
        uint8_t primary_opcode  = inst & 0xC0;
        uint8_t extended_opcode = inst & 0x3F;

        if (primary_opcode)
        {
            switch (primary_opcode)
            {
                case DW_CFA_advance_loc :   // (Row Creation Instruction)
                    {   // 0x40 - high 2 bits are 0x1, lower 6 bits are delta
                        // takes a single argument that represents a constant delta. The
                        // required action is to create a new table row with a location
                        // value that is computed by taking the current entry's location
                        // value and adding (delta * code_align). All other
                        // values in the new row are initially identical to the current row.
                        unwind_plan.AppendRow(row);
                        UnwindPlan::Row *newrow = new UnwindPlan::Row;
                        *newrow = *row.get();
                        row.reset (newrow);
                        row->SlideOffset(extended_opcode * code_align);
                    }
                    break;

                case DW_CFA_offset      :
                    {   // 0x80 - high 2 bits are 0x2, lower 6 bits are register
                        // takes two arguments: an unsigned LEB128 constant representing a
                        // factored offset and a register number. The required action is to
                        // change the rule for the register indicated by the register number
                        // to be an offset(N) rule with a value of
                        // (N = factored offset * data_align).
                        reg_num = extended_opcode;
                        op_offset = (int32_t)m_cfi_data.GetULEB128(&offset) * data_align;
                        reg_location.SetAtCFAPlusOffset(op_offset);
                        row->SetRegisterInfo (reg_num, reg_location);
                    }
                    break;

                case DW_CFA_restore     :
                    {   // 0xC0 - high 2 bits are 0x3, lower 6 bits are register
                        // takes a single argument that represents a register number. The
                        // required action is to change the rule for the indicated register
                        // to the rule assigned it by the initial_instructions in the CIE.
                        reg_num = extended_opcode;
                        // We only keep enough register locations around to
                        // unwind what is in our thread, and these are organized
                        // by the register index in that state, so we need to convert our
                        // GCC register number from the EH frame info, to a register index

                        if (unwind_plan.IsValidRowIndex(0) && unwind_plan.GetRowAtIndex(0)->GetRegisterInfo(reg_num, reg_location))
                            row->SetRegisterInfo (reg_num, reg_location);
                    }
                    break;
            }
        }
        else
        {
            switch (extended_opcode)
            {
                case DW_CFA_nop                 : // 0x0
                    break;

                case DW_CFA_set_loc             : // 0x1 (Row Creation Instruction)
                    {
                        // DW_CFA_set_loc takes a single argument that represents an address.
                        // The required action is to create a new table row using the
                        // specified address as the location. All other values in the new row
                        // are initially identical to the current row. The new location value
                        // should always be greater than the current one.
                        unwind_plan.AppendRow(row);
                        UnwindPlan::Row *newrow = new UnwindPlan::Row;
                        *newrow = *row.get();
                        row.reset (newrow);
                        row->SetOffset(m_cfi_data.GetPointer(&offset) - startaddr.GetFileAddress());
                    }
                    break;

                case DW_CFA_advance_loc1        : // 0x2 (Row Creation Instruction)
                    {
                        // takes a single uword argument that represents a constant delta.
                        // This instruction is identical to DW_CFA_advance_loc except for the
                        // encoding and size of the delta argument.
                        unwind_plan.AppendRow(row);
                        UnwindPlan::Row *newrow = new UnwindPlan::Row;
                        *newrow = *row.get();
                        row.reset (newrow);
                        row->SlideOffset (m_cfi_data.GetU8(&offset) * code_align);
                    }
                    break;

                case DW_CFA_advance_loc2        : // 0x3 (Row Creation Instruction)
                    {
                        // takes a single uword argument that represents a constant delta.
                        // This instruction is identical to DW_CFA_advance_loc except for the
                        // encoding and size of the delta argument.
                        unwind_plan.AppendRow(row);
                        UnwindPlan::Row *newrow = new UnwindPlan::Row;
                        *newrow = *row.get();
                        row.reset (newrow);
                        row->SlideOffset (m_cfi_data.GetU16(&offset) * code_align);
                    }
                    break;

                case DW_CFA_advance_loc4        : // 0x4 (Row Creation Instruction)
                    {
                        // takes a single uword argument that represents a constant delta.
                        // This instruction is identical to DW_CFA_advance_loc except for the
                        // encoding and size of the delta argument.
                        unwind_plan.AppendRow(row);
                        UnwindPlan::Row *newrow = new UnwindPlan::Row;
                        *newrow = *row.get();
                        row.reset (newrow);
                        row->SlideOffset (m_cfi_data.GetU32(&offset) * code_align);
                    }
                    break;

                case DW_CFA_offset_extended     : // 0x5
                    {
                        // takes two unsigned LEB128 arguments representing a register number
                        // and a factored offset. This instruction is identical to DW_CFA_offset
                        // except for the encoding and size of the register argument.
                        reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
                        op_offset = (int32_t)m_cfi_data.GetULEB128(&offset) * data_align;
                        reg_location.SetAtCFAPlusOffset(op_offset);
                        row->SetRegisterInfo (reg_num, reg_location);
                    }
                    break;

                case DW_CFA_restore_extended    : // 0x6
                    {
                        // takes a single unsigned LEB128 argument that represents a register
                        // number. This instruction is identical to DW_CFA_restore except for
                        // the encoding and size of the register argument.
                        reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
                        if (unwind_plan.IsValidRowIndex(0) && unwind_plan.GetRowAtIndex(0)->GetRegisterInfo(reg_num, reg_location))
                            row->SetRegisterInfo (reg_num, reg_location);
                    }
                    break;

                case DW_CFA_undefined           : // 0x7
                    {
                        // takes a single unsigned LEB128 argument that represents a register
                        // number. The required action is to set the rule for the specified
                        // register to undefined.
                        reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
                        reg_location.SetUndefined();
                        row->SetRegisterInfo (reg_num, reg_location);
                    }
                    break;

                case DW_CFA_same_value          : // 0x8
                    {
                        // takes a single unsigned LEB128 argument that represents a register
                        // number. The required action is to set the rule for the specified
                        // register to same value.
                        reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
                        reg_location.SetSame();
                        row->SetRegisterInfo (reg_num, reg_location);
                    }
                    break;

                case DW_CFA_register            : // 0x9
                    {
                        // takes two unsigned LEB128 arguments representing register numbers.
                        // The required action is to set the rule for the first register to be
                        // the second register.

                        reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
                        uint32_t other_reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
                        reg_location.SetInRegister(other_reg_num);
                        row->SetRegisterInfo (reg_num, reg_location);
                    }
                    break;

                case DW_CFA_remember_state      : // 0xA
                    {
                        // These instructions define a stack of information. Encountering the
                        // DW_CFA_remember_state instruction means to save the rules for every
                        // register on the current row on the stack. Encountering the
                        // DW_CFA_restore_state instruction means to pop the set of rules off
                        // the stack and place them in the current row. (This operation is
                        // useful for compilers that move epilogue code into the body of a
                        // function.)
                        unwind_plan.AppendRow (row);
                        UnwindPlan::Row *newrow = new UnwindPlan::Row;
                        *newrow = *row.get();
                        row.reset (newrow);
                    }
                    break;

                case DW_CFA_restore_state       : // 0xB
                    // These instructions define a stack of information. Encountering the
                    // DW_CFA_remember_state instruction means to save the rules for every
                    // register on the current row on the stack. Encountering the
                    // DW_CFA_restore_state instruction means to pop the set of rules off
                    // the stack and place them in the current row. (This operation is
                    // useful for compilers that move epilogue code into the body of a
                    // function.)
                    {
                        row = unwind_plan.GetRowAtIndex(unwind_plan.GetRowCount() - 1);
                    }
                    break;

                case DW_CFA_def_cfa             : // 0xC    (CFA Definition Instruction)
                    {
                        // Takes two unsigned LEB128 operands representing a register
                        // number and a (non-factored) offset. The required action
                        // is to define the current CFA rule to use the provided
                        // register and offset.
                        reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
                        op_offset = (int32_t)m_cfi_data.GetULEB128(&offset);
                        row->SetCFARegister (reg_num);
                        row->SetCFAOffset (op_offset);
                    }
                    break;

                case DW_CFA_def_cfa_register    : // 0xD    (CFA Definition Instruction)
                    {
                        // takes a single unsigned LEB128 argument representing a register
                        // number. The required action is to define the current CFA rule to
                        // use the provided register (but to keep the old offset).
                        reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
                        row->SetCFARegister (reg_num);
                    }
                    break;

                case DW_CFA_def_cfa_offset      : // 0xE    (CFA Definition Instruction)
                    {
                        // Takes a single unsigned LEB128 operand representing a
                        // (non-factored) offset. The required action is to define
                        // the current CFA rule to use the provided offset (but
                        // to keep the old register).
                        op_offset = (int32_t)m_cfi_data.GetULEB128(&offset);
                        row->SetCFAOffset (op_offset);
                    }
                    break;

                case DW_CFA_def_cfa_expression  : // 0xF    (CFA Definition Instruction)
                    {
                        size_t block_len = (size_t)m_cfi_data.GetULEB128(&offset);
                        offset += (uint32_t)block_len;
                    }
                    break;

                case DW_CFA_expression          : // 0x10
                    {
                        // Takes two operands: an unsigned LEB128 value representing
                        // a register number, and a DW_FORM_block value representing a DWARF
                        // expression. The required action is to change the rule for the
                        // register indicated by the register number to be an expression(E)
                        // rule where E is the DWARF expression. That is, the DWARF
                        // expression computes the address. The value of the CFA is
                        // pushed on the DWARF evaluation stack prior to execution of
                        // the DWARF expression.
                        reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
                        uint32_t block_len = (uint32_t)m_cfi_data.GetULEB128(&offset);
                        const uint8_t *block_data = (uint8_t *)m_cfi_data.GetData(&offset, block_len);

                        reg_location.SetAtDWARFExpression(block_data, block_len);
                        row->SetRegisterInfo (reg_num, reg_location);
                    }
                    break;

                case DW_CFA_offset_extended_sf  : // 0x11
                    {
                        // takes two operands: an unsigned LEB128 value representing a
                        // register number and a signed LEB128 factored offset. This
                        // instruction is identical to DW_CFA_offset_extended except
                        //that the second operand is signed and factored.
                        reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
                        op_offset = (int32_t)m_cfi_data.GetSLEB128(&offset) * data_align;
                        reg_location.SetAtCFAPlusOffset(op_offset);
                        row->SetRegisterInfo (reg_num, reg_location);
                    }
                    break;

                case DW_CFA_def_cfa_sf          : // 0x12   (CFA Definition Instruction)
                    {
                        // Takes two operands: an unsigned LEB128 value representing
                        // a register number and a signed LEB128 factored offset.
                        // This instruction is identical to DW_CFA_def_cfa except
                        // that the second operand is signed and factored.
                        reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
                        op_offset = (int32_t)m_cfi_data.GetSLEB128(&offset) * data_align;
                        row->SetCFARegister (reg_num);
                        row->SetCFAOffset (op_offset);
                    }
                    break;

                case DW_CFA_def_cfa_offset_sf   : // 0x13   (CFA Definition Instruction)
                    {
                        // takes a signed LEB128 operand representing a factored
                        // offset. This instruction is identical to  DW_CFA_def_cfa_offset
                        // except that the operand is signed and factored.
                        op_offset = (int32_t)m_cfi_data.GetSLEB128(&offset) * data_align;
                        row->SetCFAOffset (op_offset);
                    }
                    break;

                case DW_CFA_val_expression      :   // 0x16
                    {
                        // takes two operands: an unsigned LEB128 value representing a register
                        // number, and a DW_FORM_block value representing a DWARF expression.
                        // The required action is to change the rule for the register indicated
                        // by the register number to be a val_expression(E) rule where E is the
                        // DWARF expression. That is, the DWARF expression computes the value of
                        // the given register. The value of the CFA is pushed on the DWARF
                        // evaluation stack prior to execution of the DWARF expression.
                        reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
                        uint32_t block_len = (uint32_t)m_cfi_data.GetULEB128(&offset);
                        const uint8_t* block_data = (uint8_t*)m_cfi_data.GetData(&offset, block_len);
//#if defined(__i386__) || defined(__x86_64__)
//                      // The EH frame info for EIP and RIP contains code that looks for traps to
//                      // be a specific type and increments the PC.
//                      // For i386:
//                      // DW_CFA_val_expression where:
//                      // eip = DW_OP_breg6(+28), DW_OP_deref, DW_OP_dup, DW_OP_plus_uconst(0x34),
//                      //       DW_OP_deref, DW_OP_swap, DW_OP_plus_uconst(0), DW_OP_deref,
//                      //       DW_OP_dup, DW_OP_lit3, DW_OP_ne, DW_OP_swap, DW_OP_lit4, DW_OP_ne,
//                      //       DW_OP_and, DW_OP_plus
//                      // This basically does a:
//                      // eip = ucontenxt.mcontext32->gpr.eip;
//                      // if (ucontenxt.mcontext32->exc.trapno != 3 && ucontenxt.mcontext32->exc.trapno != 4)
//                      //   eip++;
//                      //
//                      // For x86_64:
//                      // DW_CFA_val_expression where:
//                      // rip =  DW_OP_breg3(+48), DW_OP_deref, DW_OP_dup, DW_OP_plus_uconst(0x90), DW_OP_deref,
//                      //          DW_OP_swap, DW_OP_plus_uconst(0), DW_OP_deref_size(4), DW_OP_dup, DW_OP_lit3,
//                      //          DW_OP_ne, DW_OP_swap, DW_OP_lit4, DW_OP_ne, DW_OP_and, DW_OP_plus
//                      // This basically does a:
//                      // rip = ucontenxt.mcontext64->gpr.rip;
//                      // if (ucontenxt.mcontext64->exc.trapno != 3 && ucontenxt.mcontext64->exc.trapno != 4)
//                      //   rip++;
//                      // The trap comparisons and increments are not needed as it hoses up the unwound PC which
//                      // is expected to point at least past the instruction that causes the fault/trap. So we
//                      // take it out by trimming the expression right at the first "DW_OP_swap" opcodes
//                      if (block_data != NULL && thread->GetPCRegNum(Thread::GCC) == reg_num)
//                      {
//                          if (thread->Is64Bit())
//                          {
//                              if (block_len > 9 && block_data[8] == DW_OP_swap && block_data[9] == DW_OP_plus_uconst)
//                                  block_len = 8;
//                          }
//                          else
//                          {
//                              if (block_len > 8 && block_data[7] == DW_OP_swap && block_data[8] == DW_OP_plus_uconst)
//                                  block_len = 7;
//                          }
//                      }
//#endif
                        reg_location.SetIsDWARFExpression(block_data, block_len);
                        row->SetRegisterInfo (reg_num, reg_location);
                    }
                    break;

                case DW_CFA_val_offset          :   // 0x14
                case DW_CFA_val_offset_sf       :   // 0x15
                default:
                    break;
            }
        }
    }
    unwind_plan.AppendRow(row);

    return true;
}
예제 #10
0
bool
CommandObjectDisassemble::Execute
(
    CommandInterpreter &interpreter,
    Args& command,
    CommandReturnObject &result
)
{
    Target *target = interpreter.GetDebugger().GetCurrentTarget().get();
    if (target == NULL)
    {
        result.AppendError ("invalid target, set executable file using 'file' command");
        result.SetStatus (eReturnStatusFailed);
        return false;
    }

    ArchSpec arch(target->GetArchitecture());
    if (!arch.IsValid())
    {
        result.AppendError ("target needs valid architecure in order to be able to disassemble");
        result.SetStatus (eReturnStatusFailed);
        return false;
    }

    Disassembler *disassembler = Disassembler::FindPlugin(arch);

    if (disassembler == NULL)
    {
        result.AppendErrorWithFormat ("Unable to find Disassembler plug-in for %s architecture.\n", arch.AsCString());
        result.SetStatus (eReturnStatusFailed);
        return false;
    }

    result.SetStatus (eReturnStatusSuccessFinishResult);

    if (command.GetArgumentCount() != 0)
    {
        result.AppendErrorWithFormat ("\"disassemble\" doesn't take any arguments.\n");
        result.SetStatus (eReturnStatusFailed);
        return false;
    }
    ExecutionContext exe_ctx(interpreter.GetDebugger().GetExecutionContext());

    if (m_options.show_mixed && m_options.num_lines_context == 0)
        m_options.num_lines_context = 3;

    if (!m_options.m_func_name.empty())
    {
        ConstString name(m_options.m_func_name.c_str());
        
        if (Disassembler::Disassemble (interpreter.GetDebugger(), 
                                       arch,
                                       exe_ctx,
                                       name,
                                       NULL,    // Module *
                                       m_options.show_mixed ? m_options.num_lines_context : 0,
                                       m_options.show_bytes,
                                       result.GetOutputStream()))
        {
            result.SetStatus (eReturnStatusSuccessFinishResult);
        }
        else
        {
            result.AppendErrorWithFormat ("Unable to find symbol with name '%s'.\n", name.GetCString());
            result.SetStatus (eReturnStatusFailed);
        }
    } 
    else
    {
        AddressRange range;
        if (m_options.m_start_addr != LLDB_INVALID_ADDRESS)
        {
            range.GetBaseAddress().SetOffset (m_options.m_start_addr);
            if (m_options.m_end_addr != LLDB_INVALID_ADDRESS)
            {
                if (m_options.m_end_addr < m_options.m_start_addr)
                {
                    result.AppendErrorWithFormat ("End address before start address.\n");
                    result.SetStatus (eReturnStatusFailed);
                    return false;            
                }
                range.SetByteSize (m_options.m_end_addr - m_options.m_start_addr);
            }
            else
                range.SetByteSize (DEFAULT_DISASM_BYTE_SIZE);
        } 
        else
        {
            if (exe_ctx.frame)
            {
                SymbolContext sc(exe_ctx.frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
                if (sc.function)
                    range = sc.function->GetAddressRange();
                else if (sc.symbol && sc.symbol->GetAddressRangePtr())
                    range = *sc.symbol->GetAddressRangePtr();
                else
                    range.GetBaseAddress() = exe_ctx.frame->GetPC();
            }
            else
            {
                result.AppendError ("invalid frame");
                result.SetStatus (eReturnStatusFailed);
                return false;
            }
        }
        if (range.GetByteSize() == 0)
            range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE);

        if (Disassembler::Disassemble (interpreter.GetDebugger(), 
                                       arch,
                                       exe_ctx,
                                       range,
                                       m_options.show_mixed ? m_options.num_lines_context : 0,
                                       m_options.show_bytes,
                                       result.GetOutputStream()))
        {
            result.SetStatus (eReturnStatusSuccessFinishResult);
        }
        else
        {
            result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8llx.\n", m_options.m_start_addr);
            result.SetStatus (eReturnStatusFailed);            
        }
    }

    return result.Succeeded();
}
bool
CommandObjectDisassemble::DoExecute (Args& command, CommandReturnObject &result)
{
    Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
    if (target == NULL)
    {
        result.AppendError ("invalid target, create a debug target using the 'target create' command");
        result.SetStatus (eReturnStatusFailed);
        return false;
    }
    if (!m_options.arch.IsValid())
        m_options.arch = target->GetArchitecture();

    if (!m_options.arch.IsValid())
    {
        result.AppendError ("use the --arch option or set the target architecure to disassemble");
        result.SetStatus (eReturnStatusFailed);
        return false;
    }

    const char *plugin_name = m_options.GetPluginName ();
    const char *flavor_string = m_options.GetFlavorString();

    DisassemblerSP disassembler = Disassembler::FindPlugin(m_options.arch, flavor_string, plugin_name);

    if (!disassembler)
    {
        if (plugin_name)
        {
            result.AppendErrorWithFormat ("Unable to find Disassembler plug-in named '%s' that supports the '%s' architecture.\n",
                                          plugin_name,
                                          m_options.arch.GetArchitectureName());
        }
        else
            result.AppendErrorWithFormat ("Unable to find Disassembler plug-in for the '%s' architecture.\n", 
                                          m_options.arch.GetArchitectureName());
        result.SetStatus (eReturnStatusFailed);
        return false;
    }
    else if (flavor_string != NULL && !disassembler->FlavorValidForArchSpec(m_options.arch, flavor_string))
        result.AppendWarningWithFormat("invalid disassembler flavor \"%s\", using default.\n", flavor_string);

    result.SetStatus (eReturnStatusSuccessFinishResult);

    if (command.GetArgumentCount() != 0)
    {
        result.AppendErrorWithFormat ("\"disassemble\" arguments are specified as options.\n");
        GetOptions()->GenerateOptionUsage (result.GetErrorStream(), this);
        result.SetStatus (eReturnStatusFailed);
        return false;
    }
    
    if (m_options.show_mixed && m_options.num_lines_context == 0)
        m_options.num_lines_context = 1;

    // Always show the PC in the disassembly
    uint32_t options = Disassembler::eOptionMarkPCAddress;

    // Mark the source line for the current PC only if we are doing mixed source and assembly
    if (m_options.show_mixed)
        options |= Disassembler::eOptionMarkPCSourceLine;

    if (m_options.show_bytes)
        options |= Disassembler::eOptionShowBytes;

    if (m_options.raw)
        options |= Disassembler::eOptionRawOuput;

    if (!m_options.func_name.empty())
    {
        ConstString name(m_options.func_name.c_str());
        
        if (Disassembler::Disassemble (m_interpreter.GetDebugger(), 
                                       m_options.arch,
                                       plugin_name,
                                       flavor_string,
                                       m_exe_ctx,
                                       name,
                                       NULL,    // Module *
                                       m_options.num_instructions,
                                       m_options.show_mixed ? m_options.num_lines_context : 0,
                                       options,
                                       result.GetOutputStream()))
        {
            result.SetStatus (eReturnStatusSuccessFinishResult);
        }
        else
        {
            result.AppendErrorWithFormat ("Unable to find symbol with name '%s'.\n", name.GetCString());
            result.SetStatus (eReturnStatusFailed);
        }
    } 
    else
    {
        std::vector<AddressRange> ranges;
        AddressRange range;
        StackFrame *frame = m_exe_ctx.GetFramePtr();
        if (m_options.frame_line)
        {
            if (frame == NULL)
            {
                result.AppendError ("Cannot disassemble around the current line without a selected frame.\n");
                result.SetStatus (eReturnStatusFailed);
                return false;
            }
            LineEntry pc_line_entry (frame->GetSymbolContext(eSymbolContextLineEntry).line_entry);
            if (pc_line_entry.IsValid())
            {
                range = pc_line_entry.range;
            }
            else
            {
                m_options.at_pc = true; // No line entry, so just disassemble around the current pc
                m_options.show_mixed = false;
            }
        }
        else if (m_options.current_function)
        {
            if (frame == NULL)
            {
                result.AppendError ("Cannot disassemble around the current function without a selected frame.\n");
                result.SetStatus (eReturnStatusFailed);
                return false;
            }
            Symbol *symbol = frame->GetSymbolContext(eSymbolContextSymbol).symbol;
            if (symbol)
            {
                range.GetBaseAddress() = symbol->GetAddress();
                range.SetByteSize(symbol->GetByteSize());
            }
        }

        // Did the "m_options.frame_line" find a valid range already? If so
        // skip the rest...
        if (range.GetByteSize() == 0)
        {
            if (m_options.at_pc)
            {
                if (frame == NULL)
                {
                    result.AppendError ("Cannot disassemble around the current PC without a selected frame.\n");
                    result.SetStatus (eReturnStatusFailed);
                    return false;
                }
                range.GetBaseAddress() = frame->GetFrameCodeAddress();
                if (m_options.num_instructions == 0)
                {
                    // Disassembling at the PC always disassembles some number of instructions (not the whole function).
                    m_options.num_instructions = DEFAULT_DISASM_NUM_INS;
                }
                ranges.push_back(range);
            }
            else
            {
                range.GetBaseAddress().SetOffset (m_options.start_addr);
                if (range.GetBaseAddress().IsValid())
                {
                    if (m_options.end_addr != LLDB_INVALID_ADDRESS)
                    {
                        if (m_options.end_addr <= m_options.start_addr)
                        {
                            result.AppendErrorWithFormat ("End address before start address.\n");
                            result.SetStatus (eReturnStatusFailed);
                            return false;            
                        }
                        range.SetByteSize (m_options.end_addr - m_options.start_addr);
                    }
                    ranges.push_back(range);
                }
                else
                {
                    if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS 
                        && target)
                    {
                        if (!target->GetSectionLoadList().IsEmpty())
                        {
                            bool failed = false;
                            Address symbol_containing_address;
                            if (target->GetSectionLoadList().ResolveLoadAddress (m_options.symbol_containing_addr, symbol_containing_address))
                            {
                                ModuleSP module_sp (symbol_containing_address.GetModule());
                                SymbolContext sc;
                                bool resolve_tail_call_address = true; // PC can be one past the address range of the function.
                                module_sp->ResolveSymbolContextForAddress (symbol_containing_address, eSymbolContextEverything, sc,
                                                                           resolve_tail_call_address);
                                if (sc.function || sc.symbol)
                                {
                                    sc.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, range);
                                }
                                else
                                {
                                    failed = true;
                                }
                            }
                            else
                            {
                                failed = true;
                            }
                            if (failed)
                            {
                                result.AppendErrorWithFormat ("Could not find function bounds for address 0x%" PRIx64 "\n", m_options.symbol_containing_addr);
                                result.SetStatus (eReturnStatusFailed);
                                return false;
                            }
                            ranges.push_back(range);
                        }
                        else
                        {
                            for (lldb::ModuleSP module_sp : target->GetImages().Modules())
                            {
                                lldb::addr_t file_addr = m_options.symbol_containing_addr;
                                Address file_address;
                                if (module_sp->ResolveFileAddress(file_addr, file_address))
                                {
                                    SymbolContext sc;
                                    bool resolve_tail_call_address = true; // PC can be one past the address range of the function.
                                    module_sp->ResolveSymbolContextForAddress (file_address, eSymbolContextEverything, sc, resolve_tail_call_address);
                                    if (sc.function || sc.symbol)
                                    {
                                        sc.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, range);
                                        ranges.push_back(range);
                                    }
                                }
                            }
                            
                        }
                    }
                }
            }
        }
        else
            ranges.push_back(range);

        if (m_options.num_instructions != 0)
        {
            if (ranges.size() == 0)
            {
                // The default action is to disassemble the current frame function.
                if (frame)
                {
                    SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
                    if (sc.function)
                        range.GetBaseAddress() = sc.function->GetAddressRange().GetBaseAddress();
                    else if (sc.symbol && sc.symbol->ValueIsAddress())
                        range.GetBaseAddress() = sc.symbol->GetAddress();
                    else
                        range.GetBaseAddress() = frame->GetFrameCodeAddress();
                }
                
                if (!range.GetBaseAddress().IsValid())
                {
                    result.AppendError ("invalid frame");
                    result.SetStatus (eReturnStatusFailed);
                    return false;
                }
            }
            
            bool print_sc_header = ranges.size() > 1;
            for (AddressRange cur_range : ranges)
            {
                if (Disassembler::Disassemble (m_interpreter.GetDebugger(),
                                               m_options.arch,
                                               plugin_name,
                                               flavor_string,
                                               m_exe_ctx,
                                               cur_range.GetBaseAddress(),
                                               m_options.num_instructions,
                                               m_options.show_mixed ? m_options.num_lines_context : 0,
                                               options,
                                               result.GetOutputStream()))
                {
                    result.SetStatus (eReturnStatusSuccessFinishResult);
                }
                else
                {
                    if (m_options.start_addr != LLDB_INVALID_ADDRESS)
                        result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", m_options.start_addr);
                    else if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS)
                        result.AppendErrorWithFormat ("Failed to disassemble memory in function at 0x%8.8" PRIx64 ".\n", m_options.symbol_containing_addr);
                    result.SetStatus (eReturnStatusFailed);
                }
            }
            if (print_sc_header)
                result.AppendMessage("\n");
        }
        else
        {
            if (ranges.size() == 0)
            {
                // The default action is to disassemble the current frame function.
                if (frame)
                {
                    SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
                    if (sc.function)
                        range = sc.function->GetAddressRange();
                    else if (sc.symbol && sc.symbol->ValueIsAddress())
                    {
                        range.GetBaseAddress() = sc.symbol->GetAddress();
                        range.SetByteSize (sc.symbol->GetByteSize());
                    }
                    else
                        range.GetBaseAddress() = frame->GetFrameCodeAddress();
                }
                else
                {
                    result.AppendError ("invalid frame");
                    result.SetStatus (eReturnStatusFailed);
                    return false;
                }
                ranges.push_back(range);
            }
            
            bool print_sc_header = ranges.size() > 1;
            for (AddressRange cur_range : ranges)
            {
                if (cur_range.GetByteSize() == 0)
                    cur_range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE);

                if (Disassembler::Disassemble (m_interpreter.GetDebugger(),
                                               m_options.arch,
                                               plugin_name,
                                               flavor_string,
                                               m_exe_ctx,
                                               cur_range,
                                               m_options.num_instructions,
                                               m_options.show_mixed ? m_options.num_lines_context : 0,
                                               options,
                                               result.GetOutputStream()))
                {
                    result.SetStatus (eReturnStatusSuccessFinishResult);
                }
                else
                {
                    result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", m_options.start_addr);
                    result.SetStatus (eReturnStatusFailed);            
                }
                if (print_sc_header)
                    result.AppendMessage("\n");
            }
        }
    }

    return result.Succeeded();
}
size_t
UnwindMacOSXFrameBackchain::GetStackFrameData_i386 (const ExecutionContext &exe_ctx)
{
    m_cursors.clear();
    
    Frame *first_frame = exe_ctx.GetFramePtr();

    Process *process = exe_ctx.GetProcessPtr();
    if (process == NULL)
        return 0;
    
    std::pair<lldb::addr_t, lldb::addr_t> fp_pc_pair;

    struct Frame_i386
    {
        uint32_t fp;
        uint32_t pc;
    };

    RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
    assert (reg_ctx);

    Cursor cursor;
    cursor.pc = reg_ctx->GetPC (LLDB_INVALID_ADDRESS);
    cursor.fp = reg_ctx->GetFP (0);
    
    Frame_i386 frame = { static_cast<uint32_t>(cursor.fp), static_cast<uint32_t>(cursor.pc) };

    m_cursors.push_back(cursor);

    const size_t k_frame_size = sizeof(frame);
    Error error;
    while (frame.fp != 0 && frame.pc != 0 && ((frame.fp & 7) == 0))
    {
        // Read both the FP and PC (8 bytes)
        if (process->ReadMemory (frame.fp, &frame.fp, k_frame_size, error) != k_frame_size)
            break;
        if (frame.pc >= 0x1000)
        {
            cursor.pc = frame.pc;
            cursor.fp = frame.fp;
            m_cursors.push_back (cursor);
        }
    }
    if (!m_cursors.empty())
    {
        lldb::addr_t first_frame_pc = m_cursors.front().pc;
        if (first_frame_pc != LLDB_INVALID_ADDRESS)
        {
            const uint32_t resolve_scope = eSymbolContextModule |
                                           eSymbolContextCompUnit |
                                           eSymbolContextFunction |
                                           eSymbolContextSymbol;

            SymbolContext first_frame_sc (first_frame->GetSymbolContext(resolve_scope));
            const AddressRange *addr_range_ptr = NULL;
            AddressRange range;
            if (first_frame_sc.function)
                addr_range_ptr = &first_frame_sc.function->GetAddressRange();
            else if (first_frame_sc.symbol)
            {
                range.GetBaseAddress() = first_frame_sc.symbol->GetAddress();
                range.SetByteSize (first_frame_sc.symbol->GetByteSize());
                addr_range_ptr = &range;
            }

            if (addr_range_ptr)
            {
                if (first_frame->GetFrameCodeAddress() == addr_range_ptr->GetBaseAddress())
                {
                    // We are at the first instruction, so we can recover the
                    // previous PC by dereferencing the SP
                    lldb::addr_t first_frame_sp = reg_ctx->GetSP (0);
                    // Read the real second frame return address into frame.pc
                    if (first_frame_sp && process->ReadMemory (first_frame_sp, &frame.pc, sizeof(frame.pc), error) == sizeof(frame.pc))
                    {
                        cursor.fp = m_cursors.front().fp;
                        cursor.pc = frame.pc;           // Set the new second frame PC

                        // Insert the second frame
                        m_cursors.insert(m_cursors.begin()+1, cursor);
                        
                        m_cursors.front().fp = first_frame_sp;
                    }
                }
            }
        }
    }
//    uint32_t i=0;
//    printf("      PC                 FP\n");
//    printf("      ------------------ ------------------ \n");
//    for (i=0; i<m_cursors.size(); ++i)
//    {
//        printf("[%3u] 0x%16.16" PRIx64 " 0x%16.16" PRIx64 "\n", i, m_cursors[i].pc, m_cursors[i].fp);
//    }
    return m_cursors.size();
}
bool
DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t dwarf_offset, Address startaddr, UnwindPlan& unwind_plan)
{
    lldb::offset_t offset = dwarf_offset;
    lldb::offset_t current_entry = offset;

    if (m_section_sp.get() == nullptr || m_section_sp->IsEncrypted())
        return false;

    if (m_cfi_data_initialized == false)
        GetCFIData();

    uint32_t length = m_cfi_data.GetU32 (&offset);
    dw_offset_t cie_offset;
    bool is_64bit = (length == UINT32_MAX);
    if (is_64bit) {
        length = m_cfi_data.GetU64 (&offset);
        cie_offset = m_cfi_data.GetU64 (&offset);
    } else {
        cie_offset = m_cfi_data.GetU32 (&offset);
    }

    assert (cie_offset != 0 && cie_offset != UINT32_MAX);

    // Translate the CIE_id from the eh_frame format, which
    // is relative to the FDE offset, into a __eh_frame section
    // offset
    if (m_is_eh_frame)
    {
        unwind_plan.SetSourceName ("eh_frame CFI");
        cie_offset = current_entry + (is_64bit ? 12 : 4) - cie_offset;
        unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
    }
    else
    {
        unwind_plan.SetSourceName ("DWARF CFI");
        // In theory the debug_frame info should be valid at all call sites
        // ("asynchronous unwind info" as it is sometimes called) but in practice
        // gcc et al all emit call frame info for the prologue and call sites, but
        // not for the epilogue or all the other locations during the function reliably.
        unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
    }
    unwind_plan.SetSourcedFromCompiler (eLazyBoolYes);

    const CIE *cie = GetCIE (cie_offset);
    assert (cie != nullptr);

    const dw_offset_t end_offset = current_entry + length + (is_64bit ? 12 : 4);

    const lldb::addr_t pc_rel_addr = m_section_sp->GetFileAddress();
    const lldb::addr_t text_addr = LLDB_INVALID_ADDRESS;
    const lldb::addr_t data_addr = LLDB_INVALID_ADDRESS;
    lldb::addr_t range_base = m_cfi_data.GetGNUEHPointer(&offset, cie->ptr_encoding, pc_rel_addr, text_addr, data_addr);
    lldb::addr_t range_len = m_cfi_data.GetGNUEHPointer(&offset, cie->ptr_encoding & DW_EH_PE_MASK_ENCODING, pc_rel_addr, text_addr, data_addr);
    AddressRange range (range_base, m_objfile.GetAddressByteSize(), m_objfile.GetSectionList());
    range.SetByteSize (range_len);

    addr_t lsda_data_file_address = LLDB_INVALID_ADDRESS;

    if (cie->augmentation[0] == 'z')
    {
        uint32_t aug_data_len = (uint32_t)m_cfi_data.GetULEB128(&offset);
        if (aug_data_len != 0 && cie->lsda_addr_encoding != DW_EH_PE_omit)
        {
            offset_t saved_offset = offset;
            lsda_data_file_address = m_cfi_data.GetGNUEHPointer(&offset, cie->lsda_addr_encoding, pc_rel_addr, text_addr, data_addr);
            if (offset - saved_offset != aug_data_len)
            {
                // There is more in the augmentation region than we know how to process;
                // don't read anything.
                lsda_data_file_address = LLDB_INVALID_ADDRESS;
            }
            offset = saved_offset;
        }
        offset += aug_data_len;
    }
    Address lsda_data;
    Address personality_function_ptr;

    if (lsda_data_file_address != LLDB_INVALID_ADDRESS && cie->personality_loc != LLDB_INVALID_ADDRESS)
    {
        m_objfile.GetModule()->ResolveFileAddress (lsda_data_file_address, lsda_data);
        m_objfile.GetModule()->ResolveFileAddress (cie->personality_loc, personality_function_ptr);
    }

    if (lsda_data.IsValid() && personality_function_ptr.IsValid())
    {
        unwind_plan.SetLSDAAddress (lsda_data);
        unwind_plan.SetPersonalityFunctionPtr (personality_function_ptr);
    }

    uint32_t code_align = cie->code_align;
    int32_t data_align = cie->data_align;

    unwind_plan.SetPlanValidAddressRange (range);
    UnwindPlan::Row *cie_initial_row = new UnwindPlan::Row;
    *cie_initial_row = cie->initial_row;
    UnwindPlan::RowSP row(cie_initial_row);

    unwind_plan.SetRegisterKind (m_reg_kind);
    unwind_plan.SetReturnAddressRegister (cie->return_addr_reg_num);

    std::vector<UnwindPlan::RowSP> stack;

    UnwindPlan::Row::RegisterLocation reg_location;
    while (m_cfi_data.ValidOffset(offset) && offset < end_offset)
    {
        uint8_t inst = m_cfi_data.GetU8(&offset);
        uint8_t primary_opcode  = inst & 0xC0;
        uint8_t extended_opcode = inst & 0x3F;

        if (!HandleCommonDwarfOpcode(primary_opcode, extended_opcode, data_align, offset, *row))
        {
            if (primary_opcode)
            {
                switch (primary_opcode)
                {
                    case DW_CFA_advance_loc :   // (Row Creation Instruction)
                    {   // 0x40 - high 2 bits are 0x1, lower 6 bits are delta
                        // takes a single argument that represents a constant delta. The
                        // required action is to create a new table row with a location
                        // value that is computed by taking the current entry's location
                        // value and adding (delta * code_align). All other
                        // values in the new row are initially identical to the current row.
                        unwind_plan.AppendRow(row);
                        UnwindPlan::Row *newrow = new UnwindPlan::Row;
                        *newrow = *row.get();
                        row.reset (newrow);
                        row->SlideOffset(extended_opcode * code_align);
                        break;
                    }

                    case DW_CFA_restore     :
                    {   // 0xC0 - high 2 bits are 0x3, lower 6 bits are register
                        // takes a single argument that represents a register number. The
                        // required action is to change the rule for the indicated register
                        // to the rule assigned it by the initial_instructions in the CIE.
                        uint32_t reg_num = extended_opcode;
                        // We only keep enough register locations around to
                        // unwind what is in our thread, and these are organized
                        // by the register index in that state, so we need to convert our
                        // GCC register number from the EH frame info, to a register index

                        if (unwind_plan.IsValidRowIndex(0) && unwind_plan.GetRowAtIndex(0)->GetRegisterInfo(reg_num, reg_location))
                            row->SetRegisterInfo (reg_num, reg_location);
                        break;
                    }
                }
            }
            else
            {
                switch (extended_opcode)
                {
                    case DW_CFA_set_loc             : // 0x1 (Row Creation Instruction)
                    {
                        // DW_CFA_set_loc takes a single argument that represents an address.
                        // The required action is to create a new table row using the
                        // specified address as the location. All other values in the new row
                        // are initially identical to the current row. The new location value
                        // should always be greater than the current one.
                        unwind_plan.AppendRow(row);
                        UnwindPlan::Row *newrow = new UnwindPlan::Row;
                        *newrow = *row.get();
                        row.reset (newrow);
                        row->SetOffset(m_cfi_data.GetPointer(&offset) - startaddr.GetFileAddress());
                        break;
                    }

                    case DW_CFA_advance_loc1        : // 0x2 (Row Creation Instruction)
                    {
                        // takes a single uword argument that represents a constant delta.
                        // This instruction is identical to DW_CFA_advance_loc except for the
                        // encoding and size of the delta argument.
                        unwind_plan.AppendRow(row);
                        UnwindPlan::Row *newrow = new UnwindPlan::Row;
                        *newrow = *row.get();
                        row.reset (newrow);
                        row->SlideOffset (m_cfi_data.GetU8(&offset) * code_align);
                        break;
                    }

                    case DW_CFA_advance_loc2        : // 0x3 (Row Creation Instruction)
                    {
                        // takes a single uword argument that represents a constant delta.
                        // This instruction is identical to DW_CFA_advance_loc except for the
                        // encoding and size of the delta argument.
                        unwind_plan.AppendRow(row);
                        UnwindPlan::Row *newrow = new UnwindPlan::Row;
                        *newrow = *row.get();
                        row.reset (newrow);
                        row->SlideOffset (m_cfi_data.GetU16(&offset) * code_align);
                        break;
                    }

                    case DW_CFA_advance_loc4        : // 0x4 (Row Creation Instruction)
                    {
                        // takes a single uword argument that represents a constant delta.
                        // This instruction is identical to DW_CFA_advance_loc except for the
                        // encoding and size of the delta argument.
                        unwind_plan.AppendRow(row);
                        UnwindPlan::Row *newrow = new UnwindPlan::Row;
                        *newrow = *row.get();
                        row.reset (newrow);
                        row->SlideOffset (m_cfi_data.GetU32(&offset) * code_align);
                        break;
                    }

                    case DW_CFA_restore_extended    : // 0x6
                    {
                        // takes a single unsigned LEB128 argument that represents a register
                        // number. This instruction is identical to DW_CFA_restore except for
                        // the encoding and size of the register argument.
                        uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
                        if (unwind_plan.IsValidRowIndex(0) && unwind_plan.GetRowAtIndex(0)->GetRegisterInfo(reg_num, reg_location))
                            row->SetRegisterInfo (reg_num, reg_location);
                        break;
                    }

                    case DW_CFA_remember_state      : // 0xA
                    {
                        // These instructions define a stack of information. Encountering the
                        // DW_CFA_remember_state instruction means to save the rules for every
                        // register on the current row on the stack. Encountering the
                        // DW_CFA_restore_state instruction means to pop the set of rules off
                        // the stack and place them in the current row. (This operation is
                        // useful for compilers that move epilogue code into the body of a
                        // function.)
                        stack.push_back (row);
                        UnwindPlan::Row *newrow = new UnwindPlan::Row;
                        *newrow = *row.get();
                        row.reset (newrow);
                        break;
                    }

                    case DW_CFA_restore_state       : // 0xB
                    {
                        // These instructions define a stack of information. Encountering the
                        // DW_CFA_remember_state instruction means to save the rules for every
                        // register on the current row on the stack. Encountering the
                        // DW_CFA_restore_state instruction means to pop the set of rules off
                        // the stack and place them in the current row. (This operation is
                        // useful for compilers that move epilogue code into the body of a
                        // function.)
                        lldb::addr_t offset = row->GetOffset ();
                        row = stack.back ();
                        stack.pop_back ();
                        row->SetOffset (offset);
                        break;
                    }

                    case DW_CFA_val_offset          :   // 0x14
                    case DW_CFA_val_offset_sf       :   // 0x15
                    default:
                        break;
                }
            }
        }
    }
    unwind_plan.AppendRow(row);

    return true;
}