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