Index: lldb/trunk/include/lldb/Symbol/UnwindPlan.h =================================================================== --- lldb/trunk/include/lldb/Symbol/UnwindPlan.h +++ lldb/trunk/include/lldb/Symbol/UnwindPlan.h @@ -237,17 +237,178 @@ } m_location; }; + class CFAValue + { + public: + + enum ValueType + { + unspecified, // not specified + isRegisterPlusOffset, // CFA = register + offset + isRegisterDereferenced, // CFA = [reg] + isDWARFExpression // CFA = eval(dwarf_expr) + }; + + CFAValue() : + m_type(unspecified), + m_value() + { + } + + bool + operator == (const CFAValue& rhs) const; + + bool + operator != (const CFAValue &rhs) const + { + return !(*this == rhs); + } + + void + SetUnspecified() + { + m_type = unspecified; + } + + bool + IsUnspecified () const + { + return m_type == unspecified; + } + + bool + IsRegisterPlusOffset () const + { + return m_type == isRegisterPlusOffset; + } + + void + SetIsRegisterPlusOffset (uint32_t reg_num, int32_t offset) + { + m_type = isRegisterPlusOffset; + m_value.reg.reg_num = reg_num; + m_value.reg.offset = offset; + } + + bool + IsRegisterDereferenced () const + { + return m_type == isRegisterDereferenced; + } + + void + SetIsRegisterDereferenced (uint32_t reg_num) + { + m_type = isRegisterDereferenced; + m_value.reg.reg_num = reg_num; + } + + bool + IsDWARFExpression () const + { + return m_type == isDWARFExpression; + } + + void + SetIsDWARFExpression (const uint8_t *opcodes, uint32_t len) + { + m_type = isDWARFExpression; + m_value.expr.opcodes = opcodes; + m_value.expr.length = len; + } + + uint32_t + GetRegisterNumber () const + { + if (m_type == isRegisterDereferenced || m_type == isRegisterPlusOffset) + return m_value.reg.reg_num; + return LLDB_INVALID_REGNUM; + } + + ValueType + GetValueType () const + { + return m_type; + } + + int32_t + GetOffset () const + { + if (m_type == isRegisterPlusOffset) + return m_value.reg.offset; + return 0; + } + + void IncOffset (int32_t delta) + { + if (m_type == isRegisterPlusOffset) + m_value.reg.offset += delta; + } + + void SetOffset (int32_t offset) + { + if (m_type == isRegisterPlusOffset) + m_value.reg.offset = offset; + } + + void + GetDWARFExpr (const uint8_t **opcodes, uint16_t& len) const + { + if (m_type == isDWARFExpression) + { + *opcodes = m_value.expr.opcodes; + len = m_value.expr.length; + } + else + { + *opcodes = NULL; + len = 0; + } + } + + const uint8_t * + GetDWARFExpressionBytes () + { + if (m_type == isDWARFExpression) + return m_value.expr.opcodes; + return NULL; + } + + int + GetDWARFExpressionLength () + { + if (m_type == isDWARFExpression) + return m_value.expr.length; + return 0; + } + + void + Dump (Stream &s, + const UnwindPlan* unwind_plan, + Thread* thread) const; + + private: + ValueType m_type; // How do we compute CFA value? + union + { + struct { + // For m_type == isRegisterPlusOffset or m_type == isRegisterDereferenced + uint32_t reg_num; // The register number + // For m_type == isRegisterPlusOffset + int32_t offset; + } reg; + // For m_type == isDWARFExpression + struct { + const uint8_t *opcodes; + uint16_t length; + } expr; + } m_value; + }; // class CFAValue + public: Row (); - - Row (const UnwindPlan::Row& rhs) : - m_offset (rhs.m_offset), - m_cfa_type (rhs.m_cfa_type), - m_cfa_reg_num (rhs.m_cfa_reg_num), - m_cfa_offset (rhs.m_cfa_offset), - m_register_locations (rhs.m_register_locations) - { - } + + Row (const UnwindPlan::Row& rhs) = default; bool operator == (const Row &rhs) const; @@ -279,47 +440,9 @@ m_offset += offset; } - // How we can reconstruct the CFA address for this stack frame, at this location - enum CFAType - { - CFAIsRegisterPlusOffset, // the CFA value in a register plus (or minus) an offset - CFAIsRegisterDereferenced // the address in a register is dereferenced to get CFA value - }; - - CFAType - GetCFAType () const - { - return m_cfa_type; - } - - void - SetCFAType (CFAType cfa_type) - { - m_cfa_type = cfa_type; - } - - // If GetCFAType() is CFAIsRegisterPlusOffset, add GetCFAOffset to the reg value to get CFA value - // If GetCFAType() is CFAIsRegisterDereferenced, dereference the addr in the reg to get CFA value - uint32_t - GetCFARegister () const - { - return m_cfa_reg_num; - } - - void - SetCFARegister (uint32_t reg_num); - - // This should not be used when GetCFAType() is CFAIsRegisterDereferenced; will return 0 in that case. - int32_t - GetCFAOffset () const - { - return m_cfa_offset; - } - - void - SetCFAOffset (int32_t offset) + CFAValue& GetCFAValue() { - m_cfa_offset = offset; + return m_cfa_value; } bool @@ -360,14 +483,7 @@ typedef std::map collection; lldb::addr_t m_offset; // Offset into the function for this row - CFAType m_cfa_type; - - // If m_cfa_type == CFAIsRegisterPlusOffset, the CFA address is computed as m_cfa_reg_num + m_cfa_offset - // If m_cfa_type == CFAIsRegisterDereferenced, the CFA address is computed as *(m_cfa_reg_num) - i.e. the - // address in m_cfa_reg_num is dereferenced and the pointer value read is the CFA addr. - uint32_t m_cfa_reg_num; // The Call Frame Address register number - int32_t m_cfa_offset; // The offset from the CFA for this row - + CFAValue m_cfa_value; collection m_register_locations; }; // class Row @@ -437,7 +553,7 @@ { if (m_row_list.empty()) return LLDB_INVALID_REGNUM; - return m_row_list.front()->GetCFARegister(); + return m_row_list.front()->GetCFAValue().GetRegisterNumber(); } // This UnwindPlan may not be valid at every address of the function span. Index: lldb/trunk/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp =================================================================== --- lldb/trunk/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp +++ lldb/trunk/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp @@ -587,7 +587,7 @@ UnwindPlan::RowSP row(new UnwindPlan::Row); // Our Call Frame Address is the stack pointer value - row->SetCFARegister (sp_reg_num); + row->GetCFAValue().SetIsRegisterPlusOffset (sp_reg_num, 0); // The previous PC is in the LR row->SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true); @@ -613,8 +613,7 @@ UnwindPlan::RowSP row(new UnwindPlan::Row); const int32_t ptr_size = 4; - row->SetCFARegister (fp_reg_num); - row->SetCFAOffset (2 * ptr_size); + row->GetCFAValue().SetIsRegisterPlusOffset (fp_reg_num, 2 * ptr_size); row->SetOffset (0); row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true); Index: lldb/trunk/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp =================================================================== --- lldb/trunk/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp +++ lldb/trunk/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp @@ -562,7 +562,7 @@ UnwindPlan::RowSP row(new UnwindPlan::Row); // Our previous Call Frame Address is the stack pointer - row->SetCFARegister (sp_reg_num); + row->GetCFAValue().SetIsRegisterPlusOffset (sp_reg_num, 0); // Our previous PC is in the LR row->SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true); @@ -589,8 +589,7 @@ UnwindPlan::RowSP row(new UnwindPlan::Row); const int32_t ptr_size = 8; - row->SetCFARegister (fp_reg_num); - row->SetCFAOffset (2 * ptr_size); + row->GetCFAValue().SetIsRegisterPlusOffset (fp_reg_num, 2 * ptr_size); row->SetOffset (0); row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true); Index: lldb/trunk/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp =================================================================== --- lldb/trunk/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp +++ lldb/trunk/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp @@ -746,8 +746,7 @@ uint32_t pc_reg_num = dwarf_eip; UnwindPlan::RowSP row(new UnwindPlan::Row); - row->SetCFARegister (sp_reg_num); - row->SetCFAOffset (4); + row->GetCFAValue().SetIsRegisterPlusOffset (sp_reg_num, 4); row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, -4, false); row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true); unwind_plan.AppendRow (row); @@ -774,8 +773,7 @@ UnwindPlan::RowSP row(new UnwindPlan::Row); const int32_t ptr_size = 4; - row->SetCFARegister (fp_reg_num); - row->SetCFAOffset (2 * ptr_size); + row->GetCFAValue().SetIsRegisterPlusOffset (fp_reg_num, 2 * ptr_size); row->SetOffset (0); row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true); Index: lldb/trunk/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp =================================================================== --- lldb/trunk/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp +++ lldb/trunk/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp @@ -385,8 +385,7 @@ UnwindPlan::RowSP row(new UnwindPlan::Row); // Our Call Frame Address is the stack pointer value - row->SetCFARegister(LLDB_REGNUM_GENERIC_SP); - row->SetCFAOffset(4); + row->GetCFAValue().SetIsRegisterPlusOffset (LLDB_REGNUM_GENERIC_SP, 4); row->SetOffset(0); // The previous PC is in the LR @@ -410,8 +409,7 @@ UnwindPlan::RowSP row(new UnwindPlan::Row); - row->SetCFARegister(LLDB_REGNUM_GENERIC_FP); - row->SetCFAOffset(8); + row->GetCFAValue().SetIsRegisterPlusOffset (LLDB_REGNUM_GENERIC_FP, 8); row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num,-8, true); row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num,-4, true); Index: lldb/trunk/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp =================================================================== --- lldb/trunk/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp +++ lldb/trunk/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp @@ -985,7 +985,7 @@ UnwindPlan::RowSP row(new UnwindPlan::Row); // Our Call Frame Address is the stack pointer value - row->SetCFARegister (sp_reg_num); + row->GetCFAValue().SetIsRegisterPlusOffset (sp_reg_num, 0); // The previous PC is in the LR row->SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true); @@ -1011,8 +1011,7 @@ UnwindPlan::RowSP row(new UnwindPlan::Row); const int32_t ptr_size = 4; - row->SetCFARegister (sp_reg_num); - row->SetCFAType(lldb_private::UnwindPlan::Row::CFAIsRegisterDereferenced); + row->GetCFAValue().SetIsRegisterDereferenced (sp_reg_num); row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * 1, true); row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true); Index: lldb/trunk/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp =================================================================== --- lldb/trunk/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp +++ lldb/trunk/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp @@ -985,7 +985,7 @@ UnwindPlan::RowSP row(new UnwindPlan::Row); // Our Call Frame Address is the stack pointer value - row->SetCFARegister (sp_reg_num); + row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 0); // The previous PC is in the LR row->SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true); @@ -1011,8 +1011,7 @@ UnwindPlan::RowSP row(new UnwindPlan::Row); const int32_t ptr_size = 8; - row->SetCFARegister (sp_reg_num); - row->SetCFAType(lldb_private::UnwindPlan::Row::CFAIsRegisterDereferenced); + row->GetCFAValue().SetIsRegisterDereferenced(sp_reg_num); row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * 2, true); row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true); Index: lldb/trunk/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp =================================================================== --- lldb/trunk/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp +++ lldb/trunk/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp @@ -1084,8 +1084,7 @@ uint32_t pc_reg_num = gcc_dwarf_rip; UnwindPlan::RowSP row(new UnwindPlan::Row); - row->SetCFARegister (sp_reg_num); - row->SetCFAOffset (8); + row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 8); row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, -8, false); row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true); unwind_plan.AppendRow (row); @@ -1112,8 +1111,7 @@ UnwindPlan::RowSP row(new UnwindPlan::Row); const int32_t ptr_size = 8; - row->SetCFARegister (gcc_dwarf_rbp); - row->SetCFAOffset (2 * ptr_size); + row->GetCFAValue().SetIsRegisterPlusOffset(gcc_dwarf_rbp, 2 * ptr_size); row->SetOffset (0); row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true); Index: lldb/trunk/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp =================================================================== --- lldb/trunk/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp +++ lldb/trunk/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp @@ -13643,7 +13643,7 @@ UnwindPlan::RowSP row(new UnwindPlan::Row); // Our previous Call Frame Address is the stack pointer - row->SetCFARegister (dwarf_sp); + row->GetCFAValue().SetIsRegisterPlusOffset (dwarf_sp, 0); // Our previous PC is in the LR row->SetRegisterLocationToRegister(dwarf_pc, dwarf_lr, true); Index: lldb/trunk/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp =================================================================== --- lldb/trunk/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp +++ lldb/trunk/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp @@ -349,7 +349,7 @@ const bool can_replace = false; // Our previous Call Frame Address is the stack pointer - row->SetCFARegister (arm64_dwarf::sp); + row->GetCFAValue().SetIsRegisterPlusOffset(arm64_dwarf::sp, 0); // Our previous PC is in the LR row->SetRegisterLocationToRegister(arm64_dwarf::pc, arm64_dwarf::lr, can_replace); Index: lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp +++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp @@ -599,7 +599,7 @@ if (!ReadCFAValueForRow (row_register_kind, active_row, m_cfa)) { - UnwindLogMsg ("failed to get cfa reg %d/%d", row_register_kind, active_row->GetCFARegister()); + UnwindLogMsg ("failed to get cfa"); m_frame_type = eNotAValidFrame; return; } @@ -1577,7 +1577,7 @@ UnwindPlan::RowSP active_row = m_fallback_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); - if (active_row && active_row->GetCFARegister() != LLDB_INVALID_REGNUM) + if (active_row && active_row->GetCFAValue().GetValueType() != UnwindPlan::Row::CFAValue::unspecified) { addr_t new_cfa; if (!ReadCFAValueForRow (m_fallback_unwind_plan_sp->GetRegisterKind(), active_row, new_cfa) @@ -1654,7 +1654,7 @@ UnwindPlan::RowSP active_row = m_fallback_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); - if (active_row && active_row->GetCFARegister() != LLDB_INVALID_REGNUM) + if (active_row && active_row->GetCFAValue().GetValueType() != UnwindPlan::Row::CFAValue::unspecified) { addr_t new_cfa; if (!ReadCFAValueForRow (m_fallback_unwind_plan_sp->GetRegisterKind(), active_row, new_cfa) @@ -1683,57 +1683,69 @@ const UnwindPlan::RowSP &row, addr_t &cfa_value) { - RegisterNumber cfa_reg (m_thread, row_register_kind, row->GetCFARegister()); RegisterValue reg_value; cfa_value = LLDB_INVALID_ADDRESS; addr_t cfa_reg_contents; - if (ReadGPRValue (cfa_reg, cfa_reg_contents)) + switch (row->GetCFAValue().GetValueType()) { - if (row->GetCFAType() == UnwindPlan::Row::CFAIsRegisterDereferenced) + case UnwindPlan::Row::CFAValue::isRegisterDereferenced: { - const RegisterInfo *reg_info = GetRegisterInfoAtIndex (cfa_reg.GetAsKind (eRegisterKindLLDB)); - RegisterValue reg_value; - if (reg_info) + RegisterNumber cfa_reg (m_thread, row_register_kind, row->GetCFAValue().GetRegisterNumber()); + if (ReadGPRValue (cfa_reg, cfa_reg_contents)) { - Error error = ReadRegisterValueFromMemory(reg_info, - cfa_reg_contents, - reg_info->byte_size, - reg_value); - if (error.Success ()) - { - cfa_value = reg_value.GetAsUInt64(); - UnwindLogMsg ("CFA value via dereferencing reg %s (%d): reg has val 0x%" PRIx64 ", CFA value is 0x%" PRIx64, - cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB), - cfa_reg_contents, cfa_value); - return true; - } - else + const RegisterInfo *reg_info = GetRegisterInfoAtIndex (cfa_reg.GetAsKind (eRegisterKindLLDB)); + RegisterValue reg_value; + if (reg_info) { - UnwindLogMsg ("Tried to deref reg %s (%d) [0x%" PRIx64 "] but memory read failed.", - cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB), - cfa_reg_contents); + Error error = ReadRegisterValueFromMemory(reg_info, + cfa_reg_contents, + reg_info->byte_size, + reg_value); + if (error.Success ()) + { + cfa_value = reg_value.GetAsUInt64(); + UnwindLogMsg ("CFA value via dereferencing reg %s (%d): reg has val 0x%" PRIx64 ", CFA value is 0x%" PRIx64, + cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB), + cfa_reg_contents, cfa_value); + return true; + } + else + { + UnwindLogMsg ("Tried to deref reg %s (%d) [0x%" PRIx64 "] but memory read failed.", + cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB), + cfa_reg_contents); + } } } + break; } - else + case UnwindPlan::Row::CFAValue::isRegisterPlusOffset: { - if (cfa_reg_contents == LLDB_INVALID_ADDRESS || cfa_reg_contents == 0 || cfa_reg_contents == 1) + RegisterNumber cfa_reg (m_thread, row_register_kind, row->GetCFAValue().GetRegisterNumber()); + if (ReadGPRValue (cfa_reg, cfa_reg_contents)) { - UnwindLogMsg ("Got an invalid CFA register value - reg %s (%d), value 0x%" PRIx64, + if (cfa_reg_contents == LLDB_INVALID_ADDRESS || cfa_reg_contents == 0 || cfa_reg_contents == 1) + { + UnwindLogMsg ("Got an invalid CFA register value - reg %s (%d), value 0x%" PRIx64, + cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB), + cfa_reg_contents); + cfa_reg_contents = LLDB_INVALID_ADDRESS; + return false; + } + cfa_value = cfa_reg_contents + row->GetCFAValue().GetOffset(); + UnwindLogMsg ("CFA is 0x%" PRIx64 ": Register %s (%d) contents are 0x%" PRIx64 ", offset is %d", + cfa_value, cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB), - cfa_reg_contents); - cfa_reg_contents = LLDB_INVALID_ADDRESS; - return false; + cfa_reg_contents, row->GetCFAValue().GetOffset()); + return true; } - cfa_value = cfa_reg_contents + row->GetCFAOffset (); - UnwindLogMsg ("CFA is 0x%" PRIx64 ": Register %s (%d) contents are 0x%" PRIx64 ", offset is %d", - cfa_value, - cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB), - cfa_reg_contents, row->GetCFAOffset ()); - return true; + break; } + // TODO: handle isDWARFExpression + default: + return false; } return false; } Index: lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp =================================================================== --- lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp +++ lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp @@ -662,8 +662,8 @@ m_cfa_reg_info = *reg_info; const uint32_t cfa_reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()]; assert (cfa_reg_num != LLDB_INVALID_REGNUM); - m_curr_row->SetCFARegister(cfa_reg_num); - m_curr_row->SetCFAOffset(m_initial_sp - reg_value.GetAsUInt64()); + m_curr_row->GetCFAValue().SetIsRegisterPlusOffset(cfa_reg_num, m_initial_sp - + reg_value.GetAsUInt64()); m_curr_row_modified = true; } break; @@ -673,7 +673,9 @@ // subsequent adjustments to the stack pointer. if (!m_fp_is_cfa) { - m_curr_row->SetCFAOffset (m_initial_sp - reg_value.GetAsUInt64()); + m_curr_row->GetCFAValue().SetIsRegisterPlusOffset( + m_curr_row->GetCFAValue().GetRegisterNumber(), + m_initial_sp - reg_value.GetAsUInt64()); m_curr_row_modified = true; } break; Index: lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp =================================================================== --- lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp +++ lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp @@ -630,8 +630,7 @@ // At the start of the function, find the CFA by adding wordsize to the SP register row->SetOffset (current_func_text_offset); - row->SetCFARegister (m_lldb_sp_regnum); - row->SetCFAOffset (m_wordsize); + row->GetCFAValue().SetIsRegisterPlusOffset(m_lldb_sp_regnum, m_wordsize); // caller's stack pointer value before the call insn is the CFA address initial_regloc.SetIsCFAPlusOffset (0); @@ -691,9 +690,9 @@ if (push_rbp_pattern_p ()) { current_sp_bytes_offset_from_cfa += m_wordsize; - row->SetCFAOffset (current_sp_bytes_offset_from_cfa); + row->GetCFAValue().SetOffset (current_sp_bytes_offset_from_cfa); UnwindPlan::Row::RegisterLocation regloc; - regloc.SetAtCFAPlusOffset (-row->GetCFAOffset()); + regloc.SetAtCFAPlusOffset (-row->GetCFAValue().GetOffset()); row->SetRegisterInfo (m_lldb_fp_regnum, regloc); saved_registers[m_machine_fp_regnum] = true; row_updated = true; @@ -701,7 +700,7 @@ else if (mov_rsp_rbp_pattern_p ()) { - row->SetCFARegister (m_lldb_fp_regnum); + row->GetCFAValue().SetIsRegisterPlusOffset(m_lldb_fp_regnum, row->GetCFAValue().GetOffset()); row_updated = true; } @@ -717,9 +716,9 @@ current_sp_bytes_offset_from_cfa += m_wordsize; // the PUSH instruction has moved the stack pointer - if the CFA is set in terms of the stack pointer, // we need to add a new row of instructions. - if (row->GetCFARegister() == m_lldb_sp_regnum) + if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum) { - row->SetCFAOffset (current_sp_bytes_offset_from_cfa); + row->GetCFAValue().SetOffset (current_sp_bytes_offset_from_cfa); row_updated = true; } // record where non-volatile (callee-saved, spilled) registers are saved on the stack @@ -748,7 +747,8 @@ if (machine_regno == (int)m_machine_fp_regnum) { - row->SetCFARegister (m_lldb_sp_regnum); + row->GetCFAValue().SetIsRegisterPlusOffset (m_lldb_sp_regnum, + row->GetCFAValue().GetOffset()); } in_epilogue = true; @@ -757,9 +757,10 @@ // the POP instruction has moved the stack pointer - if the CFA is set in terms of the stack pointer, // we need to add a new row of instructions. - if (row->GetCFARegister() == m_lldb_sp_regnum) + if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum) { - row->SetCFAOffset (current_sp_bytes_offset_from_cfa); + row->GetCFAValue().SetIsRegisterPlusOffset(m_lldb_sp_regnum, + current_sp_bytes_offset_from_cfa); row_updated = true; } } @@ -777,7 +778,7 @@ // In the Row, we want to express this as the offset from the CFA. If the frame base // is rbp (like the above instruction), the CFA offset for rbp is probably 16. So we // want to say that the value is stored at the CFA address - 96. - regloc.SetAtCFAPlusOffset (-(stack_offset + row->GetCFAOffset())); + regloc.SetAtCFAPlusOffset (-(stack_offset + row->GetCFAValue().GetOffset())); row->SetRegisterInfo (lldb_regno, regloc); @@ -787,9 +788,9 @@ else if (sub_rsp_pattern_p (stack_offset)) { current_sp_bytes_offset_from_cfa += stack_offset; - if (row->GetCFARegister() == m_lldb_sp_regnum) + if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum) { - row->SetCFAOffset (current_sp_bytes_offset_from_cfa); + row->GetCFAValue().SetOffset (current_sp_bytes_offset_from_cfa); row_updated = true; } } @@ -797,9 +798,9 @@ else if (add_rsp_pattern_p (stack_offset)) { current_sp_bytes_offset_from_cfa -= stack_offset; - if (row->GetCFARegister() == m_lldb_sp_regnum) + if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum) { - row->SetCFAOffset (current_sp_bytes_offset_from_cfa); + row->GetCFAValue().SetOffset (current_sp_bytes_offset_from_cfa); row_updated = true; } in_epilogue = true; @@ -833,9 +834,9 @@ else if (call_next_insn_pattern_p ()) { current_sp_bytes_offset_from_cfa += m_wordsize; - if (row->GetCFARegister() == m_lldb_sp_regnum) + if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum) { - row->SetCFAOffset (current_sp_bytes_offset_from_cfa); + row->GetCFAValue().SetOffset (current_sp_bytes_offset_from_cfa); row_updated = true; } } @@ -904,8 +905,8 @@ return false; uint32_t cfa_reg = m_exe_ctx.GetThreadPtr()->GetRegisterContext() ->ConvertRegisterKindToRegisterNumber (unwind_plan.GetRegisterKind(), - first_row->GetCFARegister()); - if (cfa_reg != m_lldb_sp_regnum || first_row->GetCFAOffset() != m_wordsize) + first_row->GetCFAValue().GetRegisterNumber()); + if (cfa_reg != m_lldb_sp_regnum || first_row->GetCFAValue().GetOffset() != m_wordsize) return false; UnwindPlan::RowSP original_last_row = unwind_plan.GetRowForFunctionOffset (-1); @@ -985,7 +986,7 @@ // Inspect the instruction to check if we need a new row for it. cfa_reg = m_exe_ctx.GetThreadPtr()->GetRegisterContext() ->ConvertRegisterKindToRegisterNumber (unwind_plan.GetRegisterKind(), - row->GetCFARegister()); + row->GetCFAValue().GetRegisterNumber()); if (cfa_reg == m_lldb_sp_regnum) { // CFA register is sp. @@ -996,7 +997,7 @@ if (call_next_insn_pattern_p ()) { row->SetOffset (offset); - row->SetCFAOffset (m_wordsize + row->GetCFAOffset()); + row->GetCFAValue().IncOffset (m_wordsize); UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); unwind_plan.InsertRow (new_row); @@ -1009,7 +1010,7 @@ if (push_reg_p (regno)) { row->SetOffset (offset); - row->SetCFAOffset (m_wordsize + row->GetCFAOffset()); + row->GetCFAValue().IncOffset (m_wordsize); UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); unwind_plan.InsertRow (new_row); @@ -1024,7 +1025,7 @@ // So we ignore this case. row->SetOffset (offset); - row->SetCFAOffset (-m_wordsize + row->GetCFAOffset()); + row->GetCFAValue().IncOffset (-m_wordsize); UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); unwind_plan.InsertRow (new_row); @@ -1036,7 +1037,7 @@ if (push_imm_pattern_p ()) { row->SetOffset (offset); - row->SetCFAOffset (m_wordsize + row->GetCFAOffset()); + row->GetCFAValue().IncOffset (m_wordsize); UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); unwind_plan.InsertRow (new_row); unwind_plan_updated = true; @@ -1048,7 +1049,7 @@ if (add_rsp_pattern_p (amount)) { row->SetOffset (offset); - row->SetCFAOffset (-amount + row->GetCFAOffset()); + row->GetCFAValue().IncOffset (-amount); UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); unwind_plan.InsertRow (new_row); @@ -1058,7 +1059,7 @@ if (sub_rsp_pattern_p (amount)) { row->SetOffset (offset); - row->SetCFAOffset (amount + row->GetCFAOffset()); + row->GetCFAValue().IncOffset (amount); UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); unwind_plan.InsertRow (new_row); @@ -1085,8 +1086,8 @@ && ret_pattern_p ()) { row->SetOffset (offset); - row->SetCFARegister (first_row->GetCFARegister()); - row->SetCFAOffset (m_wordsize); + row->GetCFAValue().SetIsRegisterPlusOffset ( + first_row->GetCFAValue().GetRegisterNumber(), m_wordsize); UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); unwind_plan.InsertRow (new_row); @@ -1169,8 +1170,7 @@ row->SetRegisterInfo (m_lldb_sp_regnum, sp_reginfo); // Zero instructions into the function - row->SetCFARegister (m_lldb_sp_regnum); - row->SetCFAOffset (m_wordsize); + row->GetCFAValue().SetIsRegisterPlusOffset (m_lldb_sp_regnum, m_wordsize); row->SetOffset (0); unwind_plan.AppendRow (row); UnwindPlan::Row *newrow = new UnwindPlan::Row; @@ -1178,7 +1178,7 @@ row.reset(newrow); // push %rbp has executed - stack moved, rbp now saved - row->SetCFAOffset (2 * m_wordsize); + row->GetCFAValue().IncOffset (m_wordsize); fp_reginfo.SetAtCFAPlusOffset (2 * -m_wordsize); row->SetRegisterInfo (m_lldb_fp_regnum, fp_reginfo); row->SetOffset (1); @@ -1189,8 +1189,7 @@ row.reset(newrow); // mov %rsp, %rbp has executed - row->SetCFARegister (m_lldb_fp_regnum); - row->SetCFAOffset (2 * m_wordsize); + row->GetCFAValue().SetIsRegisterPlusOffset (m_lldb_fp_regnum, 2 * m_wordsize); row->SetOffset (prologue_size); /// 3 or 4 bytes depending on arch unwind_plan.AppendRow (row); @@ -1300,9 +1299,10 @@ // If there is no description of the prologue, don't try to augment this eh_frame // unwinder code, fall back to assembly parsing instead. - if (first_row->GetCFAType() != UnwindPlan::Row::CFAType::CFAIsRegisterPlusOffset - || RegisterNumber (thread, unwind_plan.GetRegisterKind(), first_row->GetCFARegister()) != sp_regnum - || first_row->GetCFAOffset() != wordsize) + if (first_row->GetCFAValue().GetValueType() != UnwindPlan::Row::CFAValue::isRegisterPlusOffset + || RegisterNumber (thread, unwind_plan.GetRegisterKind(), + first_row->GetCFAValue().GetRegisterNumber()) != sp_regnum + || first_row->GetCFAValue().GetOffset() != wordsize) { return false; } @@ -1326,9 +1326,9 @@ // We're checking that both of them have an unwind rule like "CFA=esp+4" or CFA+rsp+8". - if (first_row->GetCFAType() == last_row->GetCFAType() - && first_row->GetCFARegister() == last_row->GetCFARegister() - && first_row->GetCFAOffset() == last_row->GetCFAOffset()) + if (first_row->GetCFAValue().GetValueType() == last_row->GetCFAValue().GetValueType() + && first_row->GetCFAValue().GetRegisterNumber() == last_row->GetCFAValue().GetRegisterNumber() + && first_row->GetCFAValue().GetOffset() == last_row->GetCFAValue().GetOffset()) { // Get the register locations for eip/rip from the first & last rows. // Are they both CFA plus an offset? Is it the same offset? Index: lldb/trunk/source/Symbol/CompactUnwindInfo.cpp =================================================================== --- lldb/trunk/source/Symbol/CompactUnwindInfo.cpp +++ lldb/trunk/source/Symbol/CompactUnwindInfo.cpp @@ -720,8 +720,9 @@ { case UNWIND_X86_64_MODE_RBP_FRAME: { - row->SetCFARegister (translate_to_eh_frame_regnum_x86_64 (UNWIND_X86_64_REG_RBP)); - row->SetCFAOffset (2 * wordsize); + row->GetCFAValue().SetIsRegisterPlusOffset ( + translate_to_eh_frame_regnum_x86_64 (UNWIND_X86_64_REG_RBP), + 2 * wordsize); row->SetOffset (0); row->SetRegisterLocationToAtCFAPlusOffset (x86_64_eh_regnum::rbp, wordsize * -2, true); row->SetRegisterLocationToAtCFAPlusOffset (x86_64_eh_regnum::rip, wordsize * -1, true); @@ -809,16 +810,9 @@ } } - if (mode == UNWIND_X86_64_MODE_STACK_IND) - { - row->SetCFAOffset (stack_size); - } - else - { - row->SetCFAOffset (stack_size * wordsize); - } + int32_t offset = mode == UNWIND_X86_64_MODE_STACK_IND ? stack_size : stack_size * wordsize; + row->GetCFAValue().SetIsRegisterPlusOffset (x86_64_eh_regnum::rsp, offset); - row->SetCFARegister (x86_64_eh_regnum::rsp); row->SetOffset (0); row->SetRegisterLocationToAtCFAPlusOffset (x86_64_eh_regnum::rip, wordsize * -1, true); row->SetRegisterLocationToIsCFAPlusOffset (x86_64_eh_regnum::rsp, 0, true); @@ -1009,8 +1003,8 @@ { case UNWIND_X86_MODE_EBP_FRAME: { - row->SetCFARegister (translate_to_eh_frame_regnum_i386 (UNWIND_X86_REG_EBP)); - row->SetCFAOffset (2 * wordsize); + row->GetCFAValue().SetIsRegisterPlusOffset ( + translate_to_eh_frame_regnum_i386 (UNWIND_X86_REG_EBP), 2 * wordsize); row->SetOffset (0); row->SetRegisterLocationToAtCFAPlusOffset (i386_eh_regnum::ebp, wordsize * -2, true); row->SetRegisterLocationToAtCFAPlusOffset (i386_eh_regnum::eip, wordsize * -1, true); @@ -1091,17 +1085,8 @@ } } - row->SetCFARegister (i386_eh_regnum::esp); - - if (mode == UNWIND_X86_MODE_STACK_IND) - { - row->SetCFAOffset (stack_size); - } - else - { - row->SetCFAOffset (stack_size * wordsize); - } - + int32_t offset = mode == UNWIND_X86_MODE_STACK_IND ? stack_size : stack_size * wordsize; + row->GetCFAValue().SetIsRegisterPlusOffset (i386_eh_regnum::esp, offset); row->SetOffset (0); row->SetRegisterLocationToAtCFAPlusOffset (i386_eh_regnum::eip, wordsize * -1, true); row->SetRegisterLocationToIsCFAPlusOffset (i386_eh_regnum::esp, 0, true); Index: lldb/trunk/source/Symbol/DWARFCallFrameInfo.cpp =================================================================== --- lldb/trunk/source/Symbol/DWARFCallFrameInfo.cpp +++ lldb/trunk/source/Symbol/DWARFCallFrameInfo.cpp @@ -284,8 +284,7 @@ // register and offset. uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); int op_offset = (int32_t)m_cfi_data.GetULEB128(&offset); - cie_sp->initial_row.SetCFARegister (reg_num); - cie_sp->initial_row.SetCFAOffset (op_offset); + cie_sp->initial_row.GetCFAValue().SetIsRegisterPlusOffset (reg_num, op_offset); continue; } if (primary_opcode == DW_CFA_offset) @@ -719,8 +718,7 @@ // 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); + row->GetCFAValue().SetIsRegisterPlusOffset (reg_num, op_offset); } break; @@ -730,7 +728,8 @@ // 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); + row->GetCFAValue().SetIsRegisterPlusOffset (reg_num, + row->GetCFAValue().GetOffset()); } break; @@ -741,7 +740,8 @@ // 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); + row->GetCFAValue().SetIsRegisterPlusOffset ( + row->GetCFAValue().GetRegisterNumber(), op_offset); } break; @@ -792,8 +792,7 @@ // 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); + row->GetCFAValue().SetIsRegisterPlusOffset (reg_num, op_offset); } break; @@ -803,7 +802,8 @@ // 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); + row->GetCFAValue().SetIsRegisterPlusOffset ( + row->GetCFAValue().GetRegisterNumber(), op_offset); } break; Index: lldb/trunk/source/Symbol/UnwindPlan.cpp =================================================================== --- lldb/trunk/source/Symbol/UnwindPlan.cpp +++ lldb/trunk/source/Symbol/UnwindPlan.cpp @@ -94,31 +94,7 @@ s.PutChar('='); if (m_type == atCFAPlusOffset) s.PutChar('['); - if (verbose) - s.Printf ("CFA%+d", m_location.offset); - - if (unwind_plan && row) - { - const uint32_t cfa_reg = row->GetCFARegister(); - const RegisterInfo *cfa_reg_info = unwind_plan->GetRegisterInfo (thread, cfa_reg); - const int32_t offset = row->GetCFAOffset() + m_location.offset; - if (verbose) - { - if (cfa_reg_info) - s.Printf (" (%s%+d)", cfa_reg_info->name, offset); - else - s.Printf (" (reg(%u)%+d)", cfa_reg, offset); - } - else - { - if (cfa_reg_info) - s.Printf ("%s", cfa_reg_info->name); - else - s.Printf ("reg(%u)", cfa_reg); - if (offset != 0) - s.Printf ("%+d", offset); - } - } + s.Printf ("CFA%+d", m_location.offset); if (m_type == atCFAPlusOffset) s.PutChar(']'); } @@ -150,38 +126,83 @@ } } +static void +DumpRegisterName (Stream &s, const UnwindPlan* unwind_plan, Thread *thread, uint32_t reg_num) { + const RegisterInfo *reg_info = unwind_plan->GetRegisterInfo (thread, reg_num); + if (reg_info) + s.PutCString (reg_info->name); + else + s.Printf ("reg(%u)", reg_num); +} + +bool +UnwindPlan::Row::CFAValue::operator == (const UnwindPlan::Row::CFAValue& rhs) const +{ + if (m_type == rhs.m_type) + { + switch (m_type) + { + case unspecified: + return true; + + case isRegisterPlusOffset: + return m_value.reg.offset == rhs.m_value.reg.offset; + + case isRegisterDereferenced: + return m_value.reg.reg_num == rhs.m_value.reg.reg_num; + + case isDWARFExpression: + if (m_value.expr.length == rhs.m_value.expr.length) + return !memcmp (m_value.expr.opcodes, rhs.m_value.expr.opcodes, m_value.expr.length); + break; + } + } + return false; +} + +void +UnwindPlan::Row::CFAValue::Dump(Stream &s, const UnwindPlan* unwind_plan, Thread* thread) const +{ + switch(m_type) { + case isRegisterPlusOffset: + DumpRegisterName(s, unwind_plan, thread, m_value.reg.reg_num); + s.Printf ("%+3d", m_value.reg.offset); + break; + case isRegisterDereferenced: + s.PutChar ('['); + DumpRegisterName(s, unwind_plan, thread, m_value.reg.reg_num); + s.PutChar (']'); + break; + case isDWARFExpression: + s.PutCString ("dwarf-expr"); + break; + default: + s.PutCString ("unspecified"); + break; + } +} + void UnwindPlan::Row::Clear () { - m_cfa_type = CFAIsRegisterPlusOffset; + m_cfa_value.SetUnspecified(); m_offset = 0; - m_cfa_reg_num = LLDB_INVALID_REGNUM; - m_cfa_offset = 0; m_register_locations.clear(); } void UnwindPlan::Row::Dump (Stream& s, const UnwindPlan* unwind_plan, Thread* thread, addr_t base_addr) const { - const RegisterInfo *reg_info = unwind_plan->GetRegisterInfo (thread, GetCFARegister()); - if (base_addr != LLDB_INVALID_ADDRESS) s.Printf ("0x%16.16" PRIx64 ": CFA=", base_addr + GetOffset()); else s.Printf ("%4" PRId64 ": CFA=", GetOffset()); - if (reg_info) - s.Printf ("%s", reg_info->name); - else - s.Printf ("reg(%u)", GetCFARegister()); - s.Printf ("%+3d => ", GetCFAOffset ()); + m_cfa_value.Dump(s, unwind_plan, thread); + s.Printf(" => "); for (collection::const_iterator idx = m_register_locations.begin (); idx != m_register_locations.end (); ++idx) { - reg_info = unwind_plan->GetRegisterInfo (thread, idx->first); - if (reg_info) - s.Printf ("%s", reg_info->name); - else - s.Printf ("reg(%u)", idx->first); + DumpRegisterName(s, unwind_plan, thread, idx->first); const bool verbose = false; idx->second.Dump(s, unwind_plan, this, thread, verbose); s.PutChar (' '); @@ -191,9 +212,7 @@ UnwindPlan::Row::Row() : m_offset (0), - m_cfa_type (CFAIsRegisterPlusOffset), - m_cfa_reg_num (LLDB_INVALID_REGNUM), - m_cfa_offset (0), + m_cfa_value (), m_register_locations () { } @@ -302,35 +321,11 @@ return true; } -void -UnwindPlan::Row::SetCFARegister (uint32_t reg_num) -{ - m_cfa_reg_num = reg_num; -} - bool UnwindPlan::Row::operator == (const UnwindPlan::Row& rhs) const { - if (m_offset != rhs.m_offset || m_cfa_reg_num != rhs.m_cfa_reg_num || m_cfa_offset != rhs.m_cfa_offset) - return false; - - if (m_cfa_type != rhs.m_cfa_type) - return false; - - if (m_cfa_type == CFAIsRegisterPlusOffset) - { - if (m_cfa_reg_num != rhs.m_cfa_reg_num) - return false; - if (m_cfa_offset != rhs.m_cfa_offset) - return false; - } - if (m_cfa_type == CFAIsRegisterDereferenced) - { - if (m_cfa_reg_num != rhs.m_cfa_reg_num) - return false; - } - - return m_register_locations == rhs.m_register_locations; + return m_offset == rhs.m_offset && m_cfa_value == rhs.m_cfa_value && + m_register_locations == rhs.m_register_locations; } void @@ -439,7 +434,10 @@ // If the 0th Row of unwind instructions is missing, or if it doesn't provide // a register to use to find the Canonical Frame Address, this is not a valid UnwindPlan. - if (GetRowAtIndex(0).get() == nullptr || GetRowAtIndex(0)->GetCFARegister() == LLDB_INVALID_REGNUM) + // CFA set by a DWARF expression is not currently supported, so ignore that as well. + if (GetRowAtIndex(0).get() == nullptr || + GetRowAtIndex(0)->GetCFAValue().GetValueType() == Row::CFAValue::unspecified || + GetRowAtIndex(0)->GetCFAValue().GetValueType() == Row::CFAValue::isDWARFExpression) { Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); if (log)