1 //===-- ThreadPlanStepRange.cpp ---------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "lldb/Target/ThreadPlanStepRange.h" 11 12 // C Includes 13 // C++ Includes 14 // Other libraries and framework includes 15 // Project includes 16 17 #include "lldb/lldb-private-log.h" 18 #include "lldb/Core/Log.h" 19 #include "lldb/Core/Stream.h" 20 #include "lldb/Symbol/Function.h" 21 #include "lldb/Symbol/Symbol.h" 22 #include "lldb/Target/Process.h" 23 #include "lldb/Target/RegisterContext.h" 24 #include "lldb/Target/StopInfo.h" 25 #include "lldb/Target/Thread.h" 26 27 using namespace lldb; 28 using namespace lldb_private; 29 30 31 //---------------------------------------------------------------------- 32 // ThreadPlanStepRange: Step through a stack range, either stepping over or into 33 // based on the value of \a type. 34 //---------------------------------------------------------------------- 35 36 ThreadPlanStepRange::ThreadPlanStepRange (ThreadPlanKind kind, const char *name, Thread &thread, const AddressRange &range, const SymbolContext &addr_context, lldb::RunMode stop_others) : 37 ThreadPlan (kind, name, thread, eVoteNoOpinion, eVoteNoOpinion), 38 m_addr_context (addr_context), 39 m_address_range (range), 40 m_stop_others (stop_others), 41 m_stack_depth (0), 42 m_stack_id (), 43 m_no_more_plans (false), 44 m_first_run_event (true) 45 { 46 m_stack_depth = m_thread.GetStackFrameCount(); 47 m_stack_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); 48 } 49 50 ThreadPlanStepRange::~ThreadPlanStepRange () 51 { 52 } 53 54 bool 55 ThreadPlanStepRange::ValidatePlan (Stream *error) 56 { 57 return true; 58 } 59 60 bool 61 ThreadPlanStepRange::PlanExplainsStop () 62 { 63 // We don't explain signals or breakpoints (breakpoints that handle stepping in or 64 // out will be handled by a child plan. 65 StopInfoSP stop_info_sp = GetPrivateStopReason(); 66 if (stop_info_sp) 67 { 68 StopReason reason = stop_info_sp->GetStopReason(); 69 70 switch (reason) 71 { 72 case eStopReasonBreakpoint: 73 case eStopReasonWatchpoint: 74 case eStopReasonSignal: 75 case eStopReasonException: 76 return false; 77 default: 78 return true; 79 } 80 } 81 return true; 82 } 83 84 Vote 85 ThreadPlanStepRange::ShouldReportStop (Event *event_ptr) 86 { 87 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 88 89 const Vote vote = IsPlanComplete() ? eVoteYes : eVoteNo; 90 if (log) 91 log->Printf ("ThreadPlanStepRange::ShouldReportStop() returning vote %i\n", vote); 92 return vote; 93 } 94 95 bool 96 ThreadPlanStepRange::InRange () 97 { 98 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 99 bool ret_value = false; 100 101 lldb::addr_t pc_load_addr = m_thread.GetRegisterContext()->GetPC(); 102 103 ret_value = m_address_range.ContainsLoadAddress(pc_load_addr, &m_thread.GetProcess().GetTarget()); 104 105 if (!ret_value) 106 { 107 // See if we've just stepped to another part of the same line number... 108 StackFrame *frame = m_thread.GetStackFrameAtIndex(0).get(); 109 110 SymbolContext new_context(frame->GetSymbolContext(eSymbolContextEverything)); 111 if (m_addr_context.line_entry.IsValid() && new_context.line_entry.IsValid()) 112 { 113 if ((m_addr_context.line_entry.file == new_context.line_entry.file) 114 && (m_addr_context.line_entry.line == new_context.line_entry.line)) 115 { 116 m_addr_context = new_context; 117 m_address_range = m_addr_context.line_entry.range; 118 ret_value = true; 119 if (log) 120 { 121 StreamString s; 122 m_address_range.Dump (&s, &m_thread.GetProcess().GetTarget(), Address::DumpStyleLoadAddress); 123 124 log->Printf ("Step range plan stepped to another range of same line: %s", s.GetData()); 125 } 126 } 127 } 128 129 } 130 131 if (!ret_value && log) 132 log->Printf ("Step range plan out of range to 0x%llx", pc_load_addr); 133 134 return ret_value; 135 } 136 137 bool 138 ThreadPlanStepRange::InSymbol() 139 { 140 lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC(); 141 if (m_addr_context.function != NULL) 142 { 143 return m_addr_context.function->GetAddressRange().ContainsLoadAddress (cur_pc, &m_thread.GetProcess().GetTarget()); 144 } 145 else if (m_addr_context.symbol != NULL) 146 { 147 return m_addr_context.symbol->GetAddressRangeRef().ContainsLoadAddress (cur_pc, &m_thread.GetProcess().GetTarget()); 148 } 149 return false; 150 } 151 152 // FIXME: This should also handle inlining if we aren't going to do inlining in the 153 // main stack. 154 // 155 // Ideally we should remember the whole stack frame list, and then compare that 156 // to the current list. 157 158 bool 159 ThreadPlanStepRange::FrameIsYounger () 160 { 161 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 162 163 // FIXME: Might be better to do this by storing the FrameID we started in and seeing if that is still above 164 // us on the stack. Counting the whole stack could be expensive. 165 166 uint32_t current_depth = m_thread.GetStackFrameCount(); 167 if (current_depth == m_stack_depth) 168 { 169 if (log) 170 log->Printf ("Step range FrameIsYounger still in start function."); 171 return false; 172 } 173 else if (current_depth < m_stack_depth) 174 { 175 if (log) 176 log->Printf ("Step range FrameIsYounger stepped out: start depth: %d current depth %d.", m_stack_depth, current_depth); 177 return false; 178 } 179 else 180 { 181 if (log) 182 log->Printf ("Step range FrameIsYounger stepped in: start depth: %d current depth %d.", m_stack_depth, current_depth); 183 return true; 184 } 185 } 186 187 bool 188 ThreadPlanStepRange::FrameIsOlder () 189 { 190 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 191 uint32_t current_depth = m_thread.GetStackFrameCount(); 192 if (current_depth == m_stack_depth) 193 { 194 if (log) 195 log->Printf ("Step range FrameIsOlder still in start function."); 196 return false; 197 } 198 else if (current_depth < m_stack_depth) 199 { 200 if (log) 201 log->Printf ("Step range FrameIsOlder stepped out: start depth: %d current depth %d.", m_stack_depth, current_depth); 202 return true; 203 } 204 else 205 { 206 if (log) 207 log->Printf ("Step range FrameIsOlder stepped in: start depth: %d current depth %d.", m_stack_depth, current_depth); 208 return false; 209 } 210 } 211 212 bool 213 ThreadPlanStepRange::StopOthers () 214 { 215 if (m_stop_others == lldb::eOnlyThisThread 216 || m_stop_others == lldb::eOnlyDuringStepping) 217 return true; 218 else 219 return false; 220 } 221 222 bool 223 ThreadPlanStepRange::WillStop () 224 { 225 return true; 226 } 227 228 StateType 229 ThreadPlanStepRange::GetPlanRunState () 230 { 231 return eStateStepping; 232 } 233 234 bool 235 ThreadPlanStepRange::MischiefManaged () 236 { 237 bool done = true; 238 if (!IsPlanComplete()) 239 { 240 if (InRange()) 241 { 242 done = false; 243 } 244 else if (!FrameIsOlder()) 245 { 246 if (m_no_more_plans) 247 done = true; 248 else 249 done = false; 250 } 251 else 252 done = true; 253 } 254 255 if (done) 256 { 257 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 258 if (log) 259 log->Printf("Completed step through range plan."); 260 ThreadPlan::MischiefManaged (); 261 return true; 262 } 263 else 264 { 265 return false; 266 } 267 268 } 269