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_depth (0),
4730fdc8d8SChris Lattner     m_stack_id (),
48c982c768SGreg Clayton     m_no_more_plans (false),
4930fdc8d8SChris Lattner     m_first_run_event (true)
5030fdc8d8SChris Lattner {
51c4c9fedcSJim Ingham     AddRange(range);
5230fdc8d8SChris Lattner     m_stack_depth = m_thread.GetStackFrameCount();
5330fdc8d8SChris Lattner     m_stack_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
5430fdc8d8SChris Lattner }
5530fdc8d8SChris Lattner 
5630fdc8d8SChris Lattner ThreadPlanStepRange::~ThreadPlanStepRange ()
5730fdc8d8SChris Lattner {
5830fdc8d8SChris Lattner }
5930fdc8d8SChris Lattner 
6030fdc8d8SChris Lattner bool
6130fdc8d8SChris Lattner ThreadPlanStepRange::ValidatePlan (Stream *error)
6230fdc8d8SChris Lattner {
6330fdc8d8SChris Lattner     return true;
6430fdc8d8SChris Lattner }
6530fdc8d8SChris Lattner 
6630fdc8d8SChris Lattner Vote
6730fdc8d8SChris Lattner ThreadPlanStepRange::ShouldReportStop (Event *event_ptr)
6830fdc8d8SChris Lattner {
692d4edfbcSGreg Clayton     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
702cad65a5SGreg Clayton 
712cad65a5SGreg Clayton     const Vote vote = IsPlanComplete() ? eVoteYes : eVoteNo;
722cad65a5SGreg Clayton     if (log)
73411c0ce8SGreg Clayton         log->Printf ("ThreadPlanStepRange::ShouldReportStop() returning vote %i\n", vote);
742cad65a5SGreg Clayton     return vote;
7530fdc8d8SChris Lattner }
7630fdc8d8SChris Lattner 
77c4c9fedcSJim Ingham void
78c4c9fedcSJim Ingham ThreadPlanStepRange::AddRange(const AddressRange &new_range)
79c4c9fedcSJim Ingham {
80c4c9fedcSJim Ingham     // For now I'm just adding the ranges.  At some point we may want to
81c4c9fedcSJim Ingham     // condense the ranges if they overlap, though I don't think it is likely
82c4c9fedcSJim Ingham     // to be very important.
83c4c9fedcSJim Ingham     m_address_ranges.push_back (new_range);
84c4c9fedcSJim Ingham }
85c4c9fedcSJim Ingham 
86c4c9fedcSJim Ingham void
87c4c9fedcSJim Ingham ThreadPlanStepRange::DumpRanges(Stream *s)
88c4c9fedcSJim Ingham {
89c4c9fedcSJim Ingham     size_t num_ranges = m_address_ranges.size();
90c4c9fedcSJim Ingham     if (num_ranges == 1)
91c4c9fedcSJim Ingham     {
92*1ac04c30SGreg Clayton         m_address_ranges[0].Dump (s, m_thread.CalculateTarget().get(), Address::DumpStyleLoadAddress);
93c4c9fedcSJim Ingham     }
94c4c9fedcSJim Ingham     else
95c4c9fedcSJim Ingham     {
96c4c9fedcSJim Ingham         for (size_t i = 0; i < num_ranges; i++)
97c4c9fedcSJim Ingham         {
98c4c9fedcSJim Ingham             s->PutCString("%d: ");
99*1ac04c30SGreg Clayton             m_address_ranges[i].Dump (s, m_thread.CalculateTarget().get(), Address::DumpStyleLoadAddress);
100c4c9fedcSJim Ingham         }
101c4c9fedcSJim Ingham     }
102c4c9fedcSJim Ingham }
103c4c9fedcSJim Ingham 
10430fdc8d8SChris Lattner bool
10530fdc8d8SChris Lattner ThreadPlanStepRange::InRange ()
10630fdc8d8SChris Lattner {
1072d4edfbcSGreg Clayton     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
10830fdc8d8SChris Lattner     bool ret_value = false;
10930fdc8d8SChris Lattner 
11030fdc8d8SChris Lattner     lldb::addr_t pc_load_addr = m_thread.GetRegisterContext()->GetPC();
11130fdc8d8SChris Lattner 
112c4c9fedcSJim Ingham     size_t num_ranges = m_address_ranges.size();
113c4c9fedcSJim Ingham     for (size_t i = 0; i < num_ranges; i++)
114c4c9fedcSJim Ingham     {
115*1ac04c30SGreg Clayton         ret_value = m_address_ranges[i].ContainsLoadAddress(pc_load_addr, m_thread.CalculateTarget().get());
116c4c9fedcSJim Ingham         if (ret_value)
117c4c9fedcSJim Ingham             break;
118c4c9fedcSJim Ingham     }
11930fdc8d8SChris Lattner 
12030fdc8d8SChris Lattner     if (!ret_value)
12130fdc8d8SChris Lattner     {
12230fdc8d8SChris Lattner         // See if we've just stepped to another part of the same line number...
12330fdc8d8SChris Lattner         StackFrame *frame = m_thread.GetStackFrameAtIndex(0).get();
12430fdc8d8SChris Lattner 
12530fdc8d8SChris Lattner         SymbolContext new_context(frame->GetSymbolContext(eSymbolContextEverything));
12630fdc8d8SChris Lattner         if (m_addr_context.line_entry.IsValid() && new_context.line_entry.IsValid())
12730fdc8d8SChris Lattner         {
128843bfb2cSJim Ingham             if (m_addr_context.line_entry.file == new_context.line_entry.file)
129843bfb2cSJim Ingham             {
130843bfb2cSJim Ingham                 if (m_addr_context.line_entry.line == new_context.line_entry.line)
13130fdc8d8SChris Lattner                 {
13230fdc8d8SChris Lattner                     m_addr_context = new_context;
133c4c9fedcSJim Ingham                     AddRange(m_addr_context.line_entry.range);
13430fdc8d8SChris Lattner                     ret_value = true;
13530fdc8d8SChris Lattner                     if (log)
13630fdc8d8SChris Lattner                     {
13730fdc8d8SChris Lattner                         StreamString s;
138c4c9fedcSJim Ingham                         m_addr_context.line_entry.range.Dump (&s,
139*1ac04c30SGreg Clayton                                                               m_thread.CalculateTarget().get(),
140c4c9fedcSJim Ingham                                                               Address::DumpStyleLoadAddress);
14130fdc8d8SChris Lattner 
14230fdc8d8SChris Lattner                         log->Printf ("Step range plan stepped to another range of same line: %s", s.GetData());
14330fdc8d8SChris Lattner                     }
14430fdc8d8SChris Lattner                 }
145*1ac04c30SGreg Clayton                 else if (new_context.line_entry.range.GetBaseAddress().GetLoadAddress(m_thread.CalculateTarget().get())
146843bfb2cSJim Ingham                          != pc_load_addr)
147843bfb2cSJim Ingham                 {
148843bfb2cSJim Ingham                     // Another thing that sometimes happens here is that we step out of one line into the MIDDLE of another
149843bfb2cSJim Ingham                     // line.  So far I mostly see this due to bugs in the debug information.
150843bfb2cSJim Ingham                     // But we probably don't want to be in the middle of a line range, so in that case reset the stepping
151843bfb2cSJim Ingham                     // range to the line we've stepped into the middle of and continue.
152843bfb2cSJim Ingham                     m_addr_context = new_context;
153c4c9fedcSJim Ingham                     m_address_ranges.clear();
154c4c9fedcSJim Ingham                     AddRange(m_addr_context.line_entry.range);
155843bfb2cSJim Ingham                     ret_value = true;
156843bfb2cSJim Ingham                     if (log)
157843bfb2cSJim Ingham                     {
158843bfb2cSJim Ingham                         StreamString s;
159c4c9fedcSJim Ingham                         m_addr_context.line_entry.range.Dump (&s,
160*1ac04c30SGreg Clayton                                                               m_thread.CalculateTarget().get(),
161c4c9fedcSJim Ingham                                                               Address::DumpStyleLoadAddress);
162843bfb2cSJim Ingham 
163843bfb2cSJim Ingham                         log->Printf ("Step range plan stepped to the middle of new line(%d): %s, continuing to clear this line.",
164843bfb2cSJim Ingham                                      new_context.line_entry.line,
165843bfb2cSJim Ingham                                      s.GetData());
166843bfb2cSJim Ingham                     }
167843bfb2cSJim Ingham 
168843bfb2cSJim Ingham                 }
169843bfb2cSJim Ingham             }
170843bfb2cSJim Ingham 
17130fdc8d8SChris Lattner         }
17230fdc8d8SChris Lattner 
17330fdc8d8SChris Lattner     }
17430fdc8d8SChris Lattner 
17530fdc8d8SChris Lattner     if (!ret_value && log)
17630fdc8d8SChris Lattner         log->Printf ("Step range plan out of range to 0x%llx", pc_load_addr);
17730fdc8d8SChris Lattner 
17830fdc8d8SChris Lattner     return ret_value;
17930fdc8d8SChris Lattner }
18030fdc8d8SChris Lattner 
18130fdc8d8SChris Lattner bool
18230fdc8d8SChris Lattner ThreadPlanStepRange::InSymbol()
18330fdc8d8SChris Lattner {
18430fdc8d8SChris Lattner     lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC();
18530fdc8d8SChris Lattner     if (m_addr_context.function != NULL)
18630fdc8d8SChris Lattner     {
187*1ac04c30SGreg Clayton         return m_addr_context.function->GetAddressRange().ContainsLoadAddress (cur_pc, m_thread.CalculateTarget().get());
18830fdc8d8SChris Lattner     }
18930fdc8d8SChris Lattner     else if (m_addr_context.symbol != NULL)
19030fdc8d8SChris Lattner     {
191*1ac04c30SGreg Clayton         return m_addr_context.symbol->GetAddressRangeRef().ContainsLoadAddress (cur_pc, m_thread.CalculateTarget().get());
19230fdc8d8SChris Lattner     }
19330fdc8d8SChris Lattner     return false;
19430fdc8d8SChris Lattner }
19530fdc8d8SChris Lattner 
19630fdc8d8SChris Lattner // FIXME: This should also handle inlining if we aren't going to do inlining in the
19730fdc8d8SChris Lattner // main stack.
19830fdc8d8SChris Lattner //
19930fdc8d8SChris Lattner // Ideally we should remember the whole stack frame list, and then compare that
20030fdc8d8SChris Lattner // to the current list.
20130fdc8d8SChris Lattner 
20230fdc8d8SChris Lattner bool
20330fdc8d8SChris Lattner ThreadPlanStepRange::FrameIsYounger ()
20430fdc8d8SChris Lattner {
2052d4edfbcSGreg Clayton     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
2067ce490c6SJim Ingham 
2077ce490c6SJim Ingham     // FIXME: Might be better to do this by storing the FrameID we started in and seeing if that is still above
2087ce490c6SJim Ingham     // us on the stack.  Counting the whole stack could be expensive.
2097ce490c6SJim Ingham 
21030fdc8d8SChris Lattner     uint32_t current_depth = m_thread.GetStackFrameCount();
21130fdc8d8SChris Lattner     if (current_depth == m_stack_depth)
21230fdc8d8SChris Lattner     {
21330fdc8d8SChris Lattner         if (log)
21430fdc8d8SChris Lattner             log->Printf ("Step range FrameIsYounger still in start function.");
21530fdc8d8SChris Lattner         return false;
21630fdc8d8SChris Lattner     }
21730fdc8d8SChris Lattner     else if (current_depth < m_stack_depth)
21830fdc8d8SChris Lattner     {
21930fdc8d8SChris Lattner         if (log)
22030fdc8d8SChris Lattner             log->Printf ("Step range FrameIsYounger stepped out: start depth: %d current depth %d.", m_stack_depth, current_depth);
22130fdc8d8SChris Lattner         return false;
22230fdc8d8SChris Lattner     }
22330fdc8d8SChris Lattner     else
22430fdc8d8SChris Lattner     {
22530fdc8d8SChris Lattner         if (log)
22630fdc8d8SChris Lattner             log->Printf ("Step range FrameIsYounger stepped in: start depth: %d current depth %d.", m_stack_depth, current_depth);
22730fdc8d8SChris Lattner         return true;
22830fdc8d8SChris Lattner     }
22930fdc8d8SChris Lattner }
23030fdc8d8SChris Lattner 
23130fdc8d8SChris Lattner bool
23230fdc8d8SChris Lattner ThreadPlanStepRange::FrameIsOlder ()
23330fdc8d8SChris Lattner {
2342d4edfbcSGreg Clayton     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
23530fdc8d8SChris Lattner     uint32_t current_depth = m_thread.GetStackFrameCount();
23630fdc8d8SChris Lattner     if (current_depth == m_stack_depth)
23730fdc8d8SChris Lattner     {
23830fdc8d8SChris Lattner         if (log)
23930fdc8d8SChris Lattner             log->Printf ("Step range FrameIsOlder still in start function.");
24030fdc8d8SChris Lattner         return false;
24130fdc8d8SChris Lattner     }
24230fdc8d8SChris Lattner     else if (current_depth < m_stack_depth)
24330fdc8d8SChris Lattner     {
24430fdc8d8SChris Lattner         if (log)
24530fdc8d8SChris Lattner             log->Printf ("Step range FrameIsOlder stepped out: start depth: %d current depth %d.", m_stack_depth, current_depth);
24630fdc8d8SChris Lattner         return true;
24730fdc8d8SChris Lattner     }
24830fdc8d8SChris Lattner     else
24930fdc8d8SChris Lattner     {
25030fdc8d8SChris Lattner         if (log)
25130fdc8d8SChris Lattner             log->Printf ("Step range FrameIsOlder stepped in: start depth: %d current depth %d.", m_stack_depth, current_depth);
25230fdc8d8SChris Lattner         return false;
25330fdc8d8SChris Lattner     }
25430fdc8d8SChris Lattner }
25530fdc8d8SChris Lattner 
25630fdc8d8SChris Lattner bool
25730fdc8d8SChris Lattner ThreadPlanStepRange::StopOthers ()
25830fdc8d8SChris Lattner {
25930fdc8d8SChris Lattner     if (m_stop_others == lldb::eOnlyThisThread
26030fdc8d8SChris Lattner         || m_stop_others == lldb::eOnlyDuringStepping)
26130fdc8d8SChris Lattner         return true;
26230fdc8d8SChris Lattner     else
26330fdc8d8SChris Lattner         return false;
26430fdc8d8SChris Lattner }
26530fdc8d8SChris Lattner 
26630fdc8d8SChris Lattner bool
26730fdc8d8SChris Lattner ThreadPlanStepRange::WillStop ()
26830fdc8d8SChris Lattner {
26930fdc8d8SChris Lattner     return true;
27030fdc8d8SChris Lattner }
27130fdc8d8SChris Lattner 
27230fdc8d8SChris Lattner StateType
27306e827ccSJim Ingham ThreadPlanStepRange::GetPlanRunState ()
27430fdc8d8SChris Lattner {
27530fdc8d8SChris Lattner     return eStateStepping;
27630fdc8d8SChris Lattner }
27730fdc8d8SChris Lattner 
27830fdc8d8SChris Lattner bool
27930fdc8d8SChris Lattner ThreadPlanStepRange::MischiefManaged ()
28030fdc8d8SChris Lattner {
28130fdc8d8SChris Lattner     bool done = true;
28230fdc8d8SChris Lattner     if (!IsPlanComplete())
28330fdc8d8SChris Lattner     {
28430fdc8d8SChris Lattner         if (InRange())
28530fdc8d8SChris Lattner         {
28630fdc8d8SChris Lattner             done = false;
28730fdc8d8SChris Lattner         }
28830fdc8d8SChris Lattner         else if (!FrameIsOlder())
28930fdc8d8SChris Lattner         {
29030fdc8d8SChris Lattner             if (m_no_more_plans)
29130fdc8d8SChris Lattner                 done = true;
29230fdc8d8SChris Lattner             else
29330fdc8d8SChris Lattner                 done = false;
29430fdc8d8SChris Lattner         }
29530fdc8d8SChris Lattner         else
29630fdc8d8SChris Lattner             done = true;
29730fdc8d8SChris Lattner     }
29830fdc8d8SChris Lattner 
29930fdc8d8SChris Lattner     if (done)
30030fdc8d8SChris Lattner     {
3012d4edfbcSGreg Clayton         LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
30230fdc8d8SChris Lattner         if (log)
30330fdc8d8SChris Lattner             log->Printf("Completed step through range plan.");
30430fdc8d8SChris Lattner         ThreadPlan::MischiefManaged ();
30530fdc8d8SChris Lattner         return true;
30630fdc8d8SChris Lattner     }
30730fdc8d8SChris Lattner     else
30830fdc8d8SChris Lattner     {
30930fdc8d8SChris Lattner         return false;
31030fdc8d8SChris Lattner     }
31130fdc8d8SChris Lattner 
31230fdc8d8SChris Lattner }
313