Index: lldb/trunk/include/lldb/Symbol/UnwindPlan.h =================================================================== --- lldb/trunk/include/lldb/Symbol/UnwindPlan.h +++ lldb/trunk/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,6 +242,7 @@ 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) @@ -275,12 +276,50 @@ 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; + } + bool SetRegisterLocationToAtCFAPlusOffset (uint32_t reg_num, int32_t offset, @@ -309,23 +348,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 +357,13 @@ 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 + collection m_register_locations; }; // class Row Index: lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h =================================================================== --- lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h +++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h @@ -333,6 +333,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: lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp +++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp @@ -232,7 +232,6 @@ m_full_unwind_plan_sp = GetFullUnwindPlanForFrame (); UnwindPlan::RowSP active_row; - int cfa_offset = 0; lldb::RegisterKind row_register_kind = eRegisterKindGeneric; if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->PlanValidAtAddress (m_current_pc)) { @@ -254,18 +253,13 @@ } - addr_t cfa_regval = LLDB_INVALID_ADDRESS; - if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval)) + if (!ReadCFAValueForRow (row_register_kind, active_row, m_cfa)) { UnwindLogMsg ("could not read CFA register for this frame."); m_frame_type = eNotAValidFrame; return; } - cfa_offset = active_row->GetCFAOffset (); - m_cfa = cfa_regval + cfa_offset; - - UnwindLogMsg ("cfa_regval = 0x%16.16" PRIx64 " (cfa_regval = 0x%16.16" PRIx64 ", cfa_offset = %i)", m_cfa, cfa_regval, cfa_offset); UnwindLogMsg ("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64 " using %s UnwindPlan", (uint64_t) m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()), (uint64_t) m_cfa, @@ -378,14 +372,11 @@ m_all_registers_available = false; m_current_offset = -1; m_current_offset_backed_up_one = -1; - addr_t cfa_regval = LLDB_INVALID_ADDRESS; RegisterKind row_register_kind = m_full_unwind_plan_sp->GetRegisterKind (); UnwindPlan::RowSP row = m_full_unwind_plan_sp->GetRowForFunctionOffset(0); if (row.get()) { - 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, m_cfa)) { UnwindLogMsg ("failed to get cfa value"); if (m_frame_type != eSkipFrame) // don't override eSkipFrame @@ -394,19 +385,18 @@ } return; } - m_cfa = cfa_regval + cfa_offset; // A couple of sanity checks.. - if (cfa_regval == LLDB_INVALID_ADDRESS || cfa_regval == 0 || cfa_regval == 1) + if (m_cfa == LLDB_INVALID_ADDRESS || m_cfa == 0 || m_cfa == 1) { UnwindLogMsg ("could not find a valid cfa address"); m_frame_type = eNotAValidFrame; return; } - // cfa_regval should point into the stack memory; if we can query memory region permissions, + // m_cfa should point into the stack memory; if we can query memory region permissions, // see if the memory is allocated & readable. - if (process->GetLoadAddressPermissions(cfa_regval, permissions) + if (process->GetLoadAddressPermissions(m_cfa, permissions) && (permissions & ePermissionsReadable) == 0) { m_frame_type = eNotAValidFrame; @@ -600,8 +590,7 @@ return; } - addr_t cfa_regval = LLDB_INVALID_ADDRESS; - if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval)) + if (!ReadCFAValueForRow (row_register_kind, active_row, m_cfa)) { UnwindLogMsg ("failed to get cfa reg %d/%d", row_register_kind, active_row->GetCFARegister()); m_frame_type = eNotAValidFrame; @@ -609,12 +598,11 @@ } cfa_offset = active_row->GetCFAOffset (); - m_cfa = cfa_regval + cfa_offset; - UnwindLogMsg ("cfa_regval = 0x%16.16" PRIx64 " (cfa_regval = 0x%16.16" PRIx64 ", cfa_offset = %i)", m_cfa, cfa_regval, cfa_offset); + UnwindLogMsg ("m_cfa = 0x%16.16" PRIx64 " (cfa_offset = %i)", m_cfa, cfa_offset); // A couple of sanity checks.. - if (cfa_regval == LLDB_INVALID_ADDRESS || cfa_regval == 0 || cfa_regval == 1) + if (m_cfa == LLDB_INVALID_ADDRESS || m_cfa == (addr_t)cfa_offset || m_cfa == (addr_t)cfa_offset + 1) { UnwindLogMsg ("could not find a valid cfa address"); m_frame_type = eNotAValidFrame; @@ -1478,11 +1466,8 @@ { m_registers.clear(); m_full_unwind_plan_sp = m_fallback_unwind_plan_sp; - addr_t cfa_regval = LLDB_INVALID_ADDRESS; - if (ReadGPRValue (m_fallback_unwind_plan_sp->GetRegisterKind(), active_row->GetCFARegister(), cfa_regval)) - { - m_cfa = cfa_regval + active_row->GetCFAOffset (); - } + m_cfa = LLDB_INVALID_ADDRESS; + ReadCFAValueForRow(m_fallback_unwind_plan_sp->GetRegisterKind(), active_row, m_cfa); UnwindLogMsg ("trying to unwind from this function with the UnwindPlan '%s' because UnwindPlan '%s' failed.", m_fallback_unwind_plan_sp->GetSourceName().GetCString(), @@ -1493,6 +1478,38 @@ 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) + { + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(cfa_regnum); + RegisterValue reg_value; + tmp = value; + Error error = ReadRegisterValueFromMemory(reg_info, + value, + reg_info->byte_size, + reg_value); + value = reg_value.GetAsUInt64(); + UnwindLogMsg("dereferenced address: 0x%16.16" PRIx64 " yields: %lx", tmp, value); + return error.Success(); + } + value = value + row->GetCFAOffset (); + 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: lldb/trunk/source/Symbol/UnwindPlan.cpp =================================================================== --- lldb/trunk/source/Symbol/UnwindPlan.cpp +++ lldb/trunk/source/Symbol/UnwindPlan.cpp @@ -153,6 +153,7 @@ void UnwindPlan::Row::Clear () { + m_cfa_type = CFAIsRegisterPlusOffset; m_offset = 0; m_cfa_reg_num = LLDB_INVALID_REGNUM; m_cfa_offset = 0; @@ -189,10 +190,11 @@ } 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_register_locations () { } @@ -301,6 +303,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_reg_num != rhs.m_cfa_reg_num) + return false; + } + return m_register_locations == rhs.m_register_locations; }