130fdc8d8SChris Lattner //===-- ThreadPlanStepOverRange.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/ThreadPlanStepOverRange.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"
20513c6bb8SJim Ingham #include "lldb/Symbol/Block.h"
21513c6bb8SJim Ingham #include "lldb/Symbol/Function.h"
2230fdc8d8SChris Lattner #include "lldb/Target/Process.h"
2330fdc8d8SChris Lattner #include "lldb/Target/RegisterContext.h"
24514487e8SGreg Clayton #include "lldb/Target/Target.h"
2530fdc8d8SChris Lattner #include "lldb/Target/Thread.h"
2630fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepOut.h"
2730fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepThrough.h"
2830fdc8d8SChris Lattner 
2930fdc8d8SChris Lattner using namespace lldb_private;
302d4edfbcSGreg Clayton using namespace lldb;
3130fdc8d8SChris Lattner 
3230fdc8d8SChris Lattner 
3330fdc8d8SChris Lattner //----------------------------------------------------------------------
3430fdc8d8SChris Lattner // ThreadPlanStepOverRange: Step through a stack range, either stepping over or into
3530fdc8d8SChris Lattner // based on the value of \a type.
3630fdc8d8SChris Lattner //----------------------------------------------------------------------
3730fdc8d8SChris Lattner 
3830fdc8d8SChris Lattner ThreadPlanStepOverRange::ThreadPlanStepOverRange
3930fdc8d8SChris Lattner (
4030fdc8d8SChris Lattner     Thread &thread,
4130fdc8d8SChris Lattner     const AddressRange &range,
4230fdc8d8SChris Lattner     const SymbolContext &addr_context,
4364e7ead1SJim Ingham     lldb::RunMode stop_others
4430fdc8d8SChris Lattner ) :
45513c6bb8SJim Ingham     ThreadPlanStepRange (ThreadPlan::eKindStepOverRange, "Step range stepping over", thread, range, addr_context, stop_others),
46513c6bb8SJim Ingham     m_first_resume(true)
4730fdc8d8SChris Lattner {
4830fdc8d8SChris Lattner }
4930fdc8d8SChris Lattner 
5030fdc8d8SChris Lattner ThreadPlanStepOverRange::~ThreadPlanStepOverRange ()
5130fdc8d8SChris Lattner {
5230fdc8d8SChris Lattner }
5330fdc8d8SChris Lattner 
5430fdc8d8SChris Lattner void
5530fdc8d8SChris Lattner ThreadPlanStepOverRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
5630fdc8d8SChris Lattner {
5730fdc8d8SChris Lattner     if (level == lldb::eDescriptionLevelBrief)
5830fdc8d8SChris Lattner         s->Printf("step over");
5930fdc8d8SChris Lattner     else
6030fdc8d8SChris Lattner     {
6130fdc8d8SChris Lattner         s->Printf ("stepping through range (stepping over functions): ");
62c4c9fedcSJim Ingham         DumpRanges(s);
6330fdc8d8SChris Lattner     }
6430fdc8d8SChris Lattner }
6530fdc8d8SChris Lattner 
6630fdc8d8SChris Lattner bool
6730fdc8d8SChris Lattner ThreadPlanStepOverRange::ShouldStop (Event *event_ptr)
6830fdc8d8SChris Lattner {
692d4edfbcSGreg Clayton     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
7030fdc8d8SChris Lattner 
7130fdc8d8SChris Lattner     if (log)
7230fdc8d8SChris Lattner     {
7330fdc8d8SChris Lattner         StreamString s;
74514487e8SGreg Clayton         s.Address (m_thread.GetRegisterContext()->GetPC(),
751ac04c30SGreg Clayton                    m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
7630fdc8d8SChris Lattner         log->Printf("ThreadPlanStepOverRange reached %s.", s.GetData());
7730fdc8d8SChris Lattner     }
7830fdc8d8SChris Lattner 
7930fdc8d8SChris Lattner     // If we're out of the range but in the same frame or in our caller's frame
8030fdc8d8SChris Lattner     // then we should stop.
81*4a58e968SJim Ingham     // When stepping out we only stop others if we are forcing running one thread.
8230fdc8d8SChris Lattner     bool stop_others;
8330fdc8d8SChris Lattner     if (m_stop_others == lldb::eOnlyThisThread)
8430fdc8d8SChris Lattner         stop_others = true;
8530fdc8d8SChris Lattner     else
8630fdc8d8SChris Lattner         stop_others = false;
8730fdc8d8SChris Lattner 
8830fdc8d8SChris Lattner     ThreadPlan* new_plan = NULL;
8930fdc8d8SChris Lattner 
90b5c0d1ccSJim Ingham     FrameComparison frame_order = CompareCurrentFrameToStartFrame();
91b5c0d1ccSJim Ingham 
92b5c0d1ccSJim Ingham     if (frame_order == eFrameCompareOlder)
935822173bSJim Ingham     {
945822173bSJim Ingham         // If we're in an older frame then we should stop.
955822173bSJim Ingham         //
965822173bSJim Ingham         // A caveat to this is if we think the frame is older but we're actually in a trampoline.
975822173bSJim Ingham         // I'm going to make the assumption that you wouldn't RETURN to a trampoline.  So if we are
985822173bSJim Ingham         // in a trampoline we think the frame is older because the trampoline confused the backtracer.
995822173bSJim Ingham         // As below, we step through first, and then try to figure out how to get back out again.
1005822173bSJim Ingham 
10118de2fdcSJim Ingham         new_plan = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);
1025822173bSJim Ingham 
1035822173bSJim Ingham         if (new_plan != NULL && log)
1045822173bSJim Ingham             log->Printf("Thought I stepped out, but in fact arrived at a trampoline.");
1055822173bSJim Ingham     }
106b5c0d1ccSJim Ingham     else if (frame_order == eFrameCompareYounger)
107b5c0d1ccSJim Ingham     {
108b5c0d1ccSJim Ingham         // Make sure we really are in a new frame.  Do that by unwinding and seeing if the
109b5c0d1ccSJim Ingham         // start function really is our start function...
110b5c0d1ccSJim Ingham         StackFrameSP older_frame_sp = m_thread.GetStackFrameAtIndex(1);
111b5c0d1ccSJim Ingham 
112b5c0d1ccSJim Ingham         // But if we can't even unwind one frame we should just get out of here & stop...
113b5c0d1ccSJim Ingham         if (older_frame_sp)
114b5c0d1ccSJim Ingham         {
115b5c0d1ccSJim Ingham             const SymbolContext &older_context = older_frame_sp->GetSymbolContext(eSymbolContextEverything);
1165f1a4e1fSJim Ingham 
1175f1a4e1fSJim Ingham             // Match as much as is specified in the m_addr_context:
1185f1a4e1fSJim Ingham             // This is a fairly loose sanity check.  Note, sometimes the target doesn't get filled
1195f1a4e1fSJim Ingham             // in so I left out the target check.  And sometimes the module comes in as the .o file from the
1205f1a4e1fSJim Ingham             // inlined range, so I left that out too...
1215f1a4e1fSJim Ingham 
122513c6bb8SJim Ingham             bool older_ctx_is_equivalent = true;
1235f1a4e1fSJim Ingham             if (m_addr_context.comp_unit)
1245f1a4e1fSJim Ingham             {
1255f1a4e1fSJim Ingham                 if (m_addr_context.comp_unit == older_context.comp_unit)
1265f1a4e1fSJim Ingham                 {
1275f1a4e1fSJim Ingham                     if (m_addr_context.function && m_addr_context.function == older_context.function)
1285f1a4e1fSJim Ingham                     {
1295f1a4e1fSJim Ingham                         if (m_addr_context.block && m_addr_context.block == older_context.block)
1305f1a4e1fSJim Ingham                         {
1315f1a4e1fSJim Ingham                             older_ctx_is_equivalent = true;
1325f1a4e1fSJim Ingham                         }
1335f1a4e1fSJim Ingham                     }
1345f1a4e1fSJim Ingham                 }
1355f1a4e1fSJim Ingham             }
1365f1a4e1fSJim Ingham             else if (m_addr_context.symbol && m_addr_context.symbol == older_context.symbol)
1375f1a4e1fSJim Ingham             {
1385f1a4e1fSJim Ingham                 older_ctx_is_equivalent = true;
1395f1a4e1fSJim Ingham             }
1405f1a4e1fSJim Ingham 
1415f1a4e1fSJim Ingham             if (older_ctx_is_equivalent)
14230fdc8d8SChris Lattner             {
143481cef25SGreg Clayton                 new_plan = m_thread.QueueThreadPlanForStepOut (false,
144481cef25SGreg Clayton                                                            NULL,
145481cef25SGreg Clayton                                                            true,
146481cef25SGreg Clayton                                                            stop_others,
147e0d378b3SGreg Clayton                                                            eVoteNo,
148e0d378b3SGreg Clayton                                                            eVoteNoOpinion,
149481cef25SGreg Clayton                                                            0);
15030fdc8d8SChris Lattner             }
151b5c0d1ccSJim Ingham             else
152b5c0d1ccSJim Ingham             {
15318de2fdcSJim Ingham                 new_plan = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);
154b5c0d1ccSJim Ingham 
155b5c0d1ccSJim Ingham             }
156b5c0d1ccSJim Ingham         }
157b5c0d1ccSJim Ingham     }
158564d8bc2SJim Ingham     else
159564d8bc2SJim Ingham     {
160564d8bc2SJim Ingham         // If we're still in the range, keep going.
161564d8bc2SJim Ingham         if (InRange())
162564d8bc2SJim Ingham         {
163564d8bc2SJim Ingham             SetNextBranchBreakpoint();
164564d8bc2SJim Ingham             return false;
165564d8bc2SJim Ingham         }
166564d8bc2SJim Ingham 
167564d8bc2SJim Ingham 
168564d8bc2SJim Ingham         if (!InSymbol())
16930fdc8d8SChris Lattner         {
17030fdc8d8SChris Lattner             // This one is a little tricky.  Sometimes we may be in a stub or something similar,
17130fdc8d8SChris Lattner             // in which case we need to get out of there.  But if we are in a stub then it's
17230fdc8d8SChris Lattner             // likely going to be hard to get out from here.  It is probably easiest to step into the
17330fdc8d8SChris Lattner             // stub, and then it will be straight-forward to step out.
17418de2fdcSJim Ingham             new_plan = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);
17530fdc8d8SChris Lattner         }
176564d8bc2SJim Ingham     }
177564d8bc2SJim Ingham 
178564d8bc2SJim Ingham     // If we get to this point, we're not going to use a previously set "next branch" breakpoint, so delete it:
179564d8bc2SJim Ingham     ClearNextBranchBreakpoint();
18030fdc8d8SChris Lattner 
18130fdc8d8SChris Lattner     if (new_plan == NULL)
18230fdc8d8SChris Lattner         m_no_more_plans = true;
18330fdc8d8SChris Lattner     else
18430fdc8d8SChris Lattner         m_no_more_plans = false;
18530fdc8d8SChris Lattner 
18630fdc8d8SChris Lattner     if (new_plan == NULL)
18730fdc8d8SChris Lattner     {
18830fdc8d8SChris Lattner         // For efficiencies sake, we know we're done here so we don't have to do this
18930fdc8d8SChris Lattner         // calculation again in MischiefManaged.
19030fdc8d8SChris Lattner         SetPlanComplete();
19130fdc8d8SChris Lattner         return true;
19230fdc8d8SChris Lattner     }
19330fdc8d8SChris Lattner     else
19430fdc8d8SChris Lattner         return false;
19530fdc8d8SChris Lattner }
196fbbfe6ecSJim Ingham 
197fbbfe6ecSJim Ingham bool
198fbbfe6ecSJim Ingham ThreadPlanStepOverRange::PlanExplainsStop ()
199fbbfe6ecSJim Ingham {
200fbbfe6ecSJim Ingham     // For crashes, breakpoint hits, signals, etc, let the base plan (or some plan above us)
201fbbfe6ecSJim Ingham     // handle the stop.  That way the user can see the stop, step around, and then when they
202fbbfe6ecSJim Ingham     // are done, continue and have their step complete.  The exception is if we've hit our
203fbbfe6ecSJim Ingham     // "run to next branch" breakpoint.
204fbbfe6ecSJim Ingham     // Note, unlike the step in range plan, we don't mark ourselves complete if we hit an
205fbbfe6ecSJim Ingham     // unexplained breakpoint/crash.
206fbbfe6ecSJim Ingham 
207fbbfe6ecSJim Ingham     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
208fbbfe6ecSJim Ingham     StopInfoSP stop_info_sp = GetPrivateStopReason();
209fbbfe6ecSJim Ingham     if (stop_info_sp)
210fbbfe6ecSJim Ingham     {
211fbbfe6ecSJim Ingham         StopReason reason = stop_info_sp->GetStopReason();
212fbbfe6ecSJim Ingham 
213fbbfe6ecSJim Ingham         switch (reason)
214fbbfe6ecSJim Ingham         {
215513c6bb8SJim Ingham         case eStopReasonTrace:
216513c6bb8SJim Ingham             return true;
217513c6bb8SJim Ingham             break;
218fbbfe6ecSJim Ingham         case eStopReasonBreakpoint:
219fbbfe6ecSJim Ingham             if (NextRangeBreakpointExplainsStop(stop_info_sp))
220fbbfe6ecSJim Ingham                 return true;
221fbbfe6ecSJim Ingham             else
222fbbfe6ecSJim Ingham                 return false;
223fbbfe6ecSJim Ingham             break;
224fbbfe6ecSJim Ingham         case eStopReasonWatchpoint:
225fbbfe6ecSJim Ingham         case eStopReasonSignal:
226fbbfe6ecSJim Ingham         case eStopReasonException:
227513c6bb8SJim Ingham         default:
228fbbfe6ecSJim Ingham             if (log)
229fbbfe6ecSJim Ingham                 log->PutCString ("ThreadPlanStepInRange got asked if it explains the stop for some reason other than step.");
230fbbfe6ecSJim Ingham             return false;
231fbbfe6ecSJim Ingham             break;
232fbbfe6ecSJim Ingham         }
233fbbfe6ecSJim Ingham     }
234fbbfe6ecSJim Ingham     return true;
235fbbfe6ecSJim Ingham }
236513c6bb8SJim Ingham 
237513c6bb8SJim Ingham bool
238513c6bb8SJim Ingham ThreadPlanStepOverRange::WillResume (lldb::StateType resume_state, bool current_plan)
239513c6bb8SJim Ingham {
240513c6bb8SJim Ingham     if (resume_state != eStateSuspended && m_first_resume)
241513c6bb8SJim Ingham     {
242513c6bb8SJim Ingham         m_first_resume = false;
243513c6bb8SJim Ingham         if (resume_state == eStateStepping && current_plan)
244513c6bb8SJim Ingham         {
245513c6bb8SJim Ingham             // See if we are about to step over an inlined call in the middle of the inlined stack, if so figure
246513c6bb8SJim Ingham             // out its extents and reset our range to step over that.
247513c6bb8SJim Ingham             bool in_inlined_stack = m_thread.DecrementCurrentInlinedDepth();
248513c6bb8SJim Ingham             if (in_inlined_stack)
249513c6bb8SJim Ingham             {
250513c6bb8SJim Ingham                 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
251513c6bb8SJim Ingham                 if (log)
252513c6bb8SJim Ingham                     log->Printf ("ThreadPlanStepInRange::WillResume: adjusting range to the frame at inlined depth %d.",
253513c6bb8SJim Ingham                                  m_thread.GetCurrentInlinedDepth());
254513c6bb8SJim Ingham                 StackFrameSP stack_sp = m_thread.GetStackFrameAtIndex(0);
255513c6bb8SJim Ingham                 if (stack_sp)
256513c6bb8SJim Ingham                 {
257513c6bb8SJim Ingham                     Block *frame_block = stack_sp->GetFrameBlock();
258513c6bb8SJim Ingham                     lldb::addr_t curr_pc = m_thread.GetRegisterContext()->GetPC();
259513c6bb8SJim Ingham                     AddressRange my_range;
260513c6bb8SJim Ingham                     if (frame_block->GetRangeContainingLoadAddress(curr_pc, m_thread.GetProcess()->GetTarget(), my_range))
261513c6bb8SJim Ingham                     {
262513c6bb8SJim Ingham                         m_address_ranges.clear();
263513c6bb8SJim Ingham                         m_address_ranges.push_back(my_range);
264513c6bb8SJim Ingham                         if (log)
265513c6bb8SJim Ingham                         {
266513c6bb8SJim Ingham                             StreamString s;
267513c6bb8SJim Ingham                             const InlineFunctionInfo *inline_info = frame_block->GetInlinedFunctionInfo();
268513c6bb8SJim Ingham                             const char *name;
269513c6bb8SJim Ingham                             if (inline_info)
270513c6bb8SJim Ingham                                 name = inline_info->GetName().AsCString();
271513c6bb8SJim Ingham                             else
272513c6bb8SJim Ingham                                 name = "<unknown-notinlined>";
273513c6bb8SJim Ingham 
274513c6bb8SJim Ingham                             s.Printf ("Stepping over inlined function \"%s\" in inlined stack: ", name);
275513c6bb8SJim Ingham                             DumpRanges(&s);
276513c6bb8SJim Ingham                             log->PutCString(s.GetData());
277513c6bb8SJim Ingham                         }
278513c6bb8SJim Ingham                     }
279513c6bb8SJim Ingham 
280513c6bb8SJim Ingham                 }
281513c6bb8SJim Ingham             }
282513c6bb8SJim Ingham         }
283513c6bb8SJim Ingham     }
284513c6bb8SJim Ingham 
285513c6bb8SJim Ingham     return ThreadPlan::WillResume(resume_state, current_plan);
286513c6bb8SJim Ingham }
287