130fdc8d8SChris Lattner //===-- ThreadPlanStepRange.cpp ---------------------------------*- C++ -*-===// 230fdc8d8SChris Lattner // 330fdc8d8SChris Lattner // The LLVM Compiler Infrastructure 430fdc8d8SChris Lattner // 530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source 630fdc8d8SChris Lattner // License. See LICENSE.TXT for details. 730fdc8d8SChris Lattner // 830fdc8d8SChris Lattner //===----------------------------------------------------------------------===// 930fdc8d8SChris Lattner 1030fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepRange.h" 1130fdc8d8SChris Lattner 1230fdc8d8SChris Lattner // C Includes 1330fdc8d8SChris Lattner // C++ Includes 1430fdc8d8SChris Lattner // Other libraries and framework includes 1530fdc8d8SChris Lattner // Project includes 1630fdc8d8SChris Lattner 1730fdc8d8SChris Lattner #include "lldb/lldb-private-log.h" 1830fdc8d8SChris Lattner #include "lldb/Core/Log.h" 1930fdc8d8SChris Lattner #include "lldb/Core/Stream.h" 2030fdc8d8SChris Lattner #include "lldb/Symbol/Function.h" 2130fdc8d8SChris Lattner #include "lldb/Symbol/Symbol.h" 22f4b47e15SGreg Clayton #include "lldb/Target/Process.h" 23f4b47e15SGreg Clayton #include "lldb/Target/RegisterContext.h" 24f4b47e15SGreg Clayton #include "lldb/Target/StopInfo.h" 25f4b47e15SGreg Clayton #include "lldb/Target/Thread.h" 2630fdc8d8SChris Lattner 2730fdc8d8SChris Lattner using namespace lldb; 2830fdc8d8SChris Lattner using namespace lldb_private; 2930fdc8d8SChris Lattner 3030fdc8d8SChris Lattner 3130fdc8d8SChris Lattner //---------------------------------------------------------------------- 3230fdc8d8SChris Lattner // ThreadPlanStepRange: Step through a stack range, either stepping over or into 3330fdc8d8SChris Lattner // based on the value of \a type. 3430fdc8d8SChris Lattner //---------------------------------------------------------------------- 3530fdc8d8SChris Lattner 36242e0ad7SJim Ingham ThreadPlanStepRange::ThreadPlanStepRange (ThreadPlanKind kind, 37242e0ad7SJim Ingham const char *name, 38242e0ad7SJim Ingham Thread &thread, 39242e0ad7SJim Ingham const AddressRange &range, 40242e0ad7SJim Ingham const SymbolContext &addr_context, 41242e0ad7SJim Ingham lldb::RunMode stop_others) : 4235b21fefSJim Ingham ThreadPlan (kind, name, thread, eVoteNoOpinion, eVoteNoOpinion), 4330fdc8d8SChris Lattner m_addr_context (addr_context), 44c4c9fedcSJim Ingham m_address_ranges (), 4530fdc8d8SChris Lattner m_stop_others (stop_others), 4630fdc8d8SChris Lattner m_stack_id (), 47c982c768SGreg Clayton m_no_more_plans (false), 4830fdc8d8SChris Lattner m_first_run_event (true) 4930fdc8d8SChris Lattner { 50c4c9fedcSJim Ingham AddRange(range); 5130fdc8d8SChris Lattner m_stack_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); 5230fdc8d8SChris Lattner } 5330fdc8d8SChris Lattner 5430fdc8d8SChris Lattner ThreadPlanStepRange::~ThreadPlanStepRange () 5530fdc8d8SChris Lattner { 5630fdc8d8SChris Lattner } 5730fdc8d8SChris Lattner 5830fdc8d8SChris Lattner bool 5930fdc8d8SChris Lattner ThreadPlanStepRange::ValidatePlan (Stream *error) 6030fdc8d8SChris Lattner { 6130fdc8d8SChris Lattner return true; 6230fdc8d8SChris Lattner } 6330fdc8d8SChris Lattner 6430fdc8d8SChris Lattner Vote 6530fdc8d8SChris Lattner ThreadPlanStepRange::ShouldReportStop (Event *event_ptr) 6630fdc8d8SChris Lattner { 672d4edfbcSGreg Clayton LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 682cad65a5SGreg Clayton 692cad65a5SGreg Clayton const Vote vote = IsPlanComplete() ? eVoteYes : eVoteNo; 702cad65a5SGreg Clayton if (log) 71411c0ce8SGreg Clayton log->Printf ("ThreadPlanStepRange::ShouldReportStop() returning vote %i\n", vote); 722cad65a5SGreg Clayton return vote; 7330fdc8d8SChris Lattner } 7430fdc8d8SChris Lattner 75c4c9fedcSJim Ingham void 76c4c9fedcSJim Ingham ThreadPlanStepRange::AddRange(const AddressRange &new_range) 77c4c9fedcSJim Ingham { 78c4c9fedcSJim Ingham // For now I'm just adding the ranges. At some point we may want to 79c4c9fedcSJim Ingham // condense the ranges if they overlap, though I don't think it is likely 80c4c9fedcSJim Ingham // to be very important. 81c4c9fedcSJim Ingham m_address_ranges.push_back (new_range); 82c4c9fedcSJim Ingham } 83c4c9fedcSJim Ingham 84c4c9fedcSJim Ingham void 85c4c9fedcSJim Ingham ThreadPlanStepRange::DumpRanges(Stream *s) 86c4c9fedcSJim Ingham { 87c4c9fedcSJim Ingham size_t num_ranges = m_address_ranges.size(); 88c4c9fedcSJim Ingham if (num_ranges == 1) 89c4c9fedcSJim Ingham { 901ac04c30SGreg Clayton m_address_ranges[0].Dump (s, m_thread.CalculateTarget().get(), Address::DumpStyleLoadAddress); 91c4c9fedcSJim Ingham } 92c4c9fedcSJim Ingham else 93c4c9fedcSJim Ingham { 94c4c9fedcSJim Ingham for (size_t i = 0; i < num_ranges; i++) 95c4c9fedcSJim Ingham { 96c4c9fedcSJim Ingham s->PutCString("%d: "); 971ac04c30SGreg Clayton m_address_ranges[i].Dump (s, m_thread.CalculateTarget().get(), Address::DumpStyleLoadAddress); 98c4c9fedcSJim Ingham } 99c4c9fedcSJim Ingham } 100c4c9fedcSJim Ingham } 101c4c9fedcSJim Ingham 10230fdc8d8SChris Lattner bool 10330fdc8d8SChris Lattner ThreadPlanStepRange::InRange () 10430fdc8d8SChris Lattner { 1052d4edfbcSGreg Clayton LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 10630fdc8d8SChris Lattner bool ret_value = false; 10730fdc8d8SChris Lattner 10830fdc8d8SChris Lattner lldb::addr_t pc_load_addr = m_thread.GetRegisterContext()->GetPC(); 10930fdc8d8SChris Lattner 110c4c9fedcSJim Ingham size_t num_ranges = m_address_ranges.size(); 111c4c9fedcSJim Ingham for (size_t i = 0; i < num_ranges; i++) 112c4c9fedcSJim Ingham { 1131ac04c30SGreg Clayton ret_value = m_address_ranges[i].ContainsLoadAddress(pc_load_addr, m_thread.CalculateTarget().get()); 114c4c9fedcSJim Ingham if (ret_value) 115c4c9fedcSJim Ingham break; 116c4c9fedcSJim Ingham } 11730fdc8d8SChris Lattner 11830fdc8d8SChris Lattner if (!ret_value) 11930fdc8d8SChris Lattner { 12030fdc8d8SChris Lattner // See if we've just stepped to another part of the same line number... 12130fdc8d8SChris Lattner StackFrame *frame = m_thread.GetStackFrameAtIndex(0).get(); 12230fdc8d8SChris Lattner 12330fdc8d8SChris Lattner SymbolContext new_context(frame->GetSymbolContext(eSymbolContextEverything)); 12430fdc8d8SChris Lattner if (m_addr_context.line_entry.IsValid() && new_context.line_entry.IsValid()) 12530fdc8d8SChris Lattner { 126843bfb2cSJim Ingham if (m_addr_context.line_entry.file == new_context.line_entry.file) 127843bfb2cSJim Ingham { 128843bfb2cSJim Ingham if (m_addr_context.line_entry.line == new_context.line_entry.line) 12930fdc8d8SChris Lattner { 13030fdc8d8SChris Lattner m_addr_context = new_context; 131c4c9fedcSJim Ingham AddRange(m_addr_context.line_entry.range); 13230fdc8d8SChris Lattner ret_value = true; 13330fdc8d8SChris Lattner if (log) 13430fdc8d8SChris Lattner { 13530fdc8d8SChris Lattner StreamString s; 136c4c9fedcSJim Ingham m_addr_context.line_entry.range.Dump (&s, 1371ac04c30SGreg Clayton m_thread.CalculateTarget().get(), 138c4c9fedcSJim Ingham Address::DumpStyleLoadAddress); 13930fdc8d8SChris Lattner 14030fdc8d8SChris Lattner log->Printf ("Step range plan stepped to another range of same line: %s", s.GetData()); 14130fdc8d8SChris Lattner } 14230fdc8d8SChris Lattner } 1431ac04c30SGreg Clayton else if (new_context.line_entry.range.GetBaseAddress().GetLoadAddress(m_thread.CalculateTarget().get()) 144843bfb2cSJim Ingham != pc_load_addr) 145843bfb2cSJim Ingham { 146843bfb2cSJim Ingham // Another thing that sometimes happens here is that we step out of one line into the MIDDLE of another 147843bfb2cSJim Ingham // line. So far I mostly see this due to bugs in the debug information. 148843bfb2cSJim Ingham // But we probably don't want to be in the middle of a line range, so in that case reset the stepping 149843bfb2cSJim Ingham // range to the line we've stepped into the middle of and continue. 150843bfb2cSJim Ingham m_addr_context = new_context; 151c4c9fedcSJim Ingham m_address_ranges.clear(); 152c4c9fedcSJim Ingham AddRange(m_addr_context.line_entry.range); 153843bfb2cSJim Ingham ret_value = true; 154843bfb2cSJim Ingham if (log) 155843bfb2cSJim Ingham { 156843bfb2cSJim Ingham StreamString s; 157c4c9fedcSJim Ingham m_addr_context.line_entry.range.Dump (&s, 1581ac04c30SGreg Clayton m_thread.CalculateTarget().get(), 159c4c9fedcSJim Ingham Address::DumpStyleLoadAddress); 160843bfb2cSJim Ingham 161843bfb2cSJim Ingham log->Printf ("Step range plan stepped to the middle of new line(%d): %s, continuing to clear this line.", 162843bfb2cSJim Ingham new_context.line_entry.line, 163843bfb2cSJim Ingham s.GetData()); 164843bfb2cSJim Ingham } 165843bfb2cSJim Ingham 166843bfb2cSJim Ingham } 167843bfb2cSJim Ingham } 168843bfb2cSJim Ingham 16930fdc8d8SChris Lattner } 17030fdc8d8SChris Lattner 17130fdc8d8SChris Lattner } 17230fdc8d8SChris Lattner 17330fdc8d8SChris Lattner if (!ret_value && log) 17430fdc8d8SChris Lattner log->Printf ("Step range plan out of range to 0x%llx", pc_load_addr); 17530fdc8d8SChris Lattner 17630fdc8d8SChris Lattner return ret_value; 17730fdc8d8SChris Lattner } 17830fdc8d8SChris Lattner 17930fdc8d8SChris Lattner bool 18030fdc8d8SChris Lattner ThreadPlanStepRange::InSymbol() 18130fdc8d8SChris Lattner { 18230fdc8d8SChris Lattner lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC(); 18330fdc8d8SChris Lattner if (m_addr_context.function != NULL) 18430fdc8d8SChris Lattner { 1851ac04c30SGreg Clayton return m_addr_context.function->GetAddressRange().ContainsLoadAddress (cur_pc, m_thread.CalculateTarget().get()); 18630fdc8d8SChris Lattner } 187*e7612134SGreg Clayton else if (m_addr_context.symbol) 18830fdc8d8SChris Lattner { 189*e7612134SGreg Clayton AddressRange range(m_addr_context.symbol->GetAddress(), m_addr_context.symbol->GetByteSize()); 190*e7612134SGreg Clayton return range.ContainsLoadAddress (cur_pc, m_thread.CalculateTarget().get()); 19130fdc8d8SChris Lattner } 19230fdc8d8SChris Lattner return false; 19330fdc8d8SChris Lattner } 19430fdc8d8SChris Lattner 19530fdc8d8SChris Lattner // FIXME: This should also handle inlining if we aren't going to do inlining in the 19630fdc8d8SChris Lattner // main stack. 19730fdc8d8SChris Lattner // 19830fdc8d8SChris Lattner // Ideally we should remember the whole stack frame list, and then compare that 19930fdc8d8SChris Lattner // to the current list. 20030fdc8d8SChris Lattner 201b5c0d1ccSJim Ingham lldb::FrameComparison 202b5c0d1ccSJim Ingham ThreadPlanStepRange::CompareCurrentFrameToStartFrame() 20330fdc8d8SChris Lattner { 204b5c0d1ccSJim Ingham FrameComparison frame_order; 2057ce490c6SJim Ingham 206b5c0d1ccSJim Ingham StackID cur_frame_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); 2077ce490c6SJim Ingham 208b5c0d1ccSJim Ingham if (cur_frame_id == m_stack_id) 20930fdc8d8SChris Lattner { 210b5c0d1ccSJim Ingham frame_order = eFrameCompareEqual; 21130fdc8d8SChris Lattner } 212b5c0d1ccSJim Ingham else if (cur_frame_id < m_stack_id) 21330fdc8d8SChris Lattner { 214b5c0d1ccSJim Ingham frame_order = eFrameCompareYounger; 21530fdc8d8SChris Lattner } 21630fdc8d8SChris Lattner else 21730fdc8d8SChris Lattner { 218b5c0d1ccSJim Ingham frame_order = eFrameCompareOlder; 21930fdc8d8SChris Lattner } 220b5c0d1ccSJim Ingham return frame_order; 22130fdc8d8SChris Lattner } 22230fdc8d8SChris Lattner 22330fdc8d8SChris Lattner bool 22430fdc8d8SChris Lattner ThreadPlanStepRange::StopOthers () 22530fdc8d8SChris Lattner { 22630fdc8d8SChris Lattner if (m_stop_others == lldb::eOnlyThisThread 22730fdc8d8SChris Lattner || m_stop_others == lldb::eOnlyDuringStepping) 22830fdc8d8SChris Lattner return true; 22930fdc8d8SChris Lattner else 23030fdc8d8SChris Lattner return false; 23130fdc8d8SChris Lattner } 23230fdc8d8SChris Lattner 23330fdc8d8SChris Lattner bool 23430fdc8d8SChris Lattner ThreadPlanStepRange::WillStop () 23530fdc8d8SChris Lattner { 23630fdc8d8SChris Lattner return true; 23730fdc8d8SChris Lattner } 23830fdc8d8SChris Lattner 23930fdc8d8SChris Lattner StateType 24006e827ccSJim Ingham ThreadPlanStepRange::GetPlanRunState () 24130fdc8d8SChris Lattner { 24230fdc8d8SChris Lattner return eStateStepping; 24330fdc8d8SChris Lattner } 24430fdc8d8SChris Lattner 24530fdc8d8SChris Lattner bool 24630fdc8d8SChris Lattner ThreadPlanStepRange::MischiefManaged () 24730fdc8d8SChris Lattner { 24830fdc8d8SChris Lattner bool done = true; 24930fdc8d8SChris Lattner if (!IsPlanComplete()) 25030fdc8d8SChris Lattner { 25130fdc8d8SChris Lattner if (InRange()) 25230fdc8d8SChris Lattner { 25330fdc8d8SChris Lattner done = false; 25430fdc8d8SChris Lattner } 255b5c0d1ccSJim Ingham else 256b5c0d1ccSJim Ingham { 257b5c0d1ccSJim Ingham FrameComparison frame_order = CompareCurrentFrameToStartFrame(); 258b5c0d1ccSJim Ingham if (frame_order != eFrameCompareOlder) 25930fdc8d8SChris Lattner { 26030fdc8d8SChris Lattner if (m_no_more_plans) 26130fdc8d8SChris Lattner done = true; 26230fdc8d8SChris Lattner else 26330fdc8d8SChris Lattner done = false; 26430fdc8d8SChris Lattner } 26530fdc8d8SChris Lattner else 26630fdc8d8SChris Lattner done = true; 26730fdc8d8SChris Lattner } 268b5c0d1ccSJim Ingham } 26930fdc8d8SChris Lattner 27030fdc8d8SChris Lattner if (done) 27130fdc8d8SChris Lattner { 2722d4edfbcSGreg Clayton LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 27330fdc8d8SChris Lattner if (log) 27430fdc8d8SChris Lattner log->Printf("Completed step through range plan."); 27530fdc8d8SChris Lattner ThreadPlan::MischiefManaged (); 27630fdc8d8SChris Lattner return true; 27730fdc8d8SChris Lattner } 27830fdc8d8SChris Lattner else 27930fdc8d8SChris Lattner { 28030fdc8d8SChris Lattner return false; 28130fdc8d8SChris Lattner } 28230fdc8d8SChris Lattner 28330fdc8d8SChris Lattner } 284