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