Index: include/lldb/Symbol/UnwindPlan.h =================================================================== --- include/lldb/Symbol/UnwindPlan.h +++ include/lldb/Symbol/UnwindPlan.h @@ -58,13 +58,13 @@ atDWARFExpression, // reg = deref(eval(dwarf_expr)) isDWARFExpression // reg = eval(dwarf_expr) }; - + RegisterLocation() : m_type(unspecified), m_location() { } - + bool operator == (const RegisterLocation& rhs) const; @@ -242,8 +242,10 @@ 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_cfa_deref_reg_num (rhs.m_cfa_deref_reg_num), m_register_locations (rhs.m_register_locations) { } @@ -275,12 +277,64 @@ 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; + } + + // This should be used when GetCFAType() returns CFAIsRegisterPlusOffset uint32_t GetCFARegister () const { return m_cfa_reg_num; } + // This should be used when GetCFAType() is set to CFAIsRegisterPlusOffset + void + SetCFARegister (uint32_t reg_num); + + // This should be used when GetCFAType() returns CFAIsRegisterPlusOffset + int32_t + GetCFAOffset () const + { + return m_cfa_offset; + } + + // This should be used when GetCFAType() is set to CFAIsRegisterPlusOffset + void + SetCFAOffset (int32_t offset) + { + m_cfa_offset = offset; + } + + // This should be used when GetCFAType() returns CFAIsRegisterDereferenced + uint32_t + GetCFARegisterNumberToDereference () const + { + return m_cfa_deref_reg_num; + } + + // This should be used when GetCFAType() is set to CFAIsRegisterDereferenced + void + SetCFARegisterNumberToDereference (uint32_t reg_num) + { + m_cfa_deref_reg_num = reg_num; + } + bool SetRegisterLocationToAtCFAPlusOffset (uint32_t reg_num, int32_t offset, @@ -309,23 +363,6 @@ SetRegisterLocationToSame (uint32_t reg_num, bool must_replace); - - - void - SetCFARegister (uint32_t reg_num); - - int32_t - GetCFAOffset () const - { - return m_cfa_offset; - } - - void - SetCFAOffset (int32_t offset) - { - m_cfa_offset = offset; - } - void Clear (); @@ -335,8 +372,16 @@ protected: 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 following ivars are used 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 + + // if m_cfa_type == CFAIsRegisterDereferenced, the following is used + uint32_t m_cfa_deref_reg_num; + collection m_register_locations; }; // class Row Index: source/Plugins/Process/Utility/RegisterContextLLDB.h =================================================================== --- source/Plugins/Process/Utility/RegisterContextLLDB.h +++ source/Plugins/Process/Utility/RegisterContextLLDB.h @@ -186,6 +186,10 @@ bool ReadGPRValue (lldb::RegisterKind register_kind, uint32_t regnum, lldb::addr_t &value); + // Get the CFA register for a given frame. + bool + ReadCFAValueForRow (lldb::RegisterKind register_kind, const UnwindPlan::RowSP &row, lldb::addr_t &value); + lldb::UnwindPlanSP GetFastUnwindPlanForFrame (); Index: source/Plugins/Process/Utility/RegisterContextLLDB.cpp =================================================================== --- source/Plugins/Process/Utility/RegisterContextLLDB.cpp +++ source/Plugins/Process/Utility/RegisterContextLLDB.cpp @@ -240,7 +240,7 @@ addr_t cfa_regval = LLDB_INVALID_ADDRESS; - if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval)) + if (!ReadCFAValueForRow (row_register_kind, active_row, cfa_regval)) { UnwindLogMsg ("could not read CFA register for this frame."); m_frame_type = eNotAValidFrame; @@ -370,7 +370,7 @@ { uint32_t cfa_regnum = row->GetCFARegister(); int cfa_offset = row->GetCFAOffset(); - if (!ReadGPRValue (row_register_kind, cfa_regnum, cfa_regval)) + if (!ReadCFAValueForRow (row_register_kind, row, cfa_regval)) { UnwindLogMsg ("failed to get cfa value"); if (m_frame_type != eSkipFrame) // don't override eSkipFrame @@ -565,7 +565,7 @@ } addr_t cfa_regval = LLDB_INVALID_ADDRESS; - if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval)) + if (!ReadCFAValueForRow (row_register_kind, active_row, cfa_regval)) { UnwindLogMsg ("failed to get cfa reg %d/%d", row_register_kind, active_row->GetCFARegister()); m_frame_type = eNotAValidFrame; @@ -1419,8 +1419,9 @@ { m_registers.clear(); m_full_unwind_plan_sp = m_fallback_unwind_plan_sp; + uint32_t cfa_regnum = active_row->GetCFARegister(); addr_t cfa_regval = LLDB_INVALID_ADDRESS; - if (ReadGPRValue (m_fallback_unwind_plan_sp->GetRegisterKind(), active_row->GetCFARegister(), cfa_regval)) + if (ReadCFAValueForRow(m_fallback_unwind_plan_sp->GetRegisterKind(), active_row, cfa_regval)) { m_cfa = cfa_regval + active_row->GetCFAOffset (); } @@ -1434,6 +1435,37 @@ return true; } +bool +RegisterContextLLDB::ReadCFAValueForRow (lldb::RegisterKind row_register_kind, + const UnwindPlan::RowSP &row, + addr_t &value) +{ + uint32_t cfa_regnum = row->GetCFARegister(); + RegisterValue reg_value; + addr_t tmp; + + value = LLDB_INVALID_ADDRESS; + + if (ReadGPRValue (row_register_kind, cfa_regnum, value)) + { + if (row->GetCFAType() == UnwindPlan::Row::CFAIsRegisterDereferenced) + { + tmp = value; + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(cfa_regnum); + RegisterValue reg_value; + Error error = ReadRegisterValueFromMemory(reg_info, + value, + reg_info->byte_size, + reg_value); + value = reg_value.GetAsUInt64(); + UnwindLogMsg("dereferenced address: %p yields: %lx\n", tmp, value); + return error.Success(); + } + return true; + } + return false; +} + // Retrieve a general purpose register value for THIS frame, as saved by the NEXT frame, i.e. the frame that // this frame called. e.g. // Index: source/Symbol/UnwindPlan.cpp =================================================================== --- source/Symbol/UnwindPlan.cpp +++ source/Symbol/UnwindPlan.cpp @@ -21,6 +21,11 @@ bool UnwindPlan::Row::RegisterLocation::operator == (const UnwindPlan::Row::RegisterLocation& rhs) const { + bool is_match = true; + + if (m_type != rhs.m_type) + is_match = false; + if (m_type == rhs.m_type) { switch (m_type) @@ -28,23 +33,28 @@ case unspecified: case undefined: case same: - return true; + break; case atCFAPlusOffset: case isCFAPlusOffset: - return m_location.offset == rhs.m_location.offset; + if (m_location.offset != rhs.m_location.offset) + is_match = false; + break; case inOtherRegister: - return m_location.reg_num == rhs.m_location.reg_num; + if (m_location.reg_num != rhs.m_location.reg_num) + is_match = false; + break; case atDWARFExpression: case isDWARFExpression: if (m_location.expr.length == rhs.m_location.expr.length) - return !memcmp (m_location.expr.opcodes, rhs.m_location.expr.opcodes, m_location.expr.length); + if (memcmp (m_location.expr.opcodes, rhs.m_location.expr.opcodes, m_location.expr.length) != 0) + is_match = false; break; } } - return false; + return is_match; } // This function doesn't copy the dwarf expression bytes; they must remain in allocated @@ -153,9 +163,11 @@ void UnwindPlan::Row::Clear () { + m_cfa_type = CFAIsRegisterPlusOffset; m_offset = 0; m_cfa_reg_num = LLDB_INVALID_REGNUM; m_cfa_offset = 0; + m_cfa_deref_reg_num = LLDB_INVALID_REGNUM; m_register_locations.clear(); } @@ -189,10 +201,12 @@ } UnwindPlan::Row::Row() : - m_offset(0), - m_cfa_reg_num(LLDB_INVALID_REGNUM), - m_cfa_offset(0), - m_register_locations() + m_offset (0), + m_cfa_type (CFAIsRegisterPlusOffset), + m_cfa_reg_num (LLDB_INVALID_REGNUM), + m_cfa_offset (0), + m_cfa_deref_reg_num (LLDB_INVALID_REGNUM), + m_register_locations () { } @@ -301,6 +315,23 @@ { 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_deref_reg_num != rhs.m_cfa_deref_reg_num) + return false; + } + return m_register_locations == rhs.m_register_locations; }