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 { 120 if (m_addr_context.line_entry.line == new_context.line_entry.line) 121 { 122 m_addr_context = new_context; 123 m_address_range = m_addr_context.line_entry.range; 124 ret_value = true; 125 if (log) 126 { 127 StreamString s; 128 m_address_range.Dump (&s, &m_thread.GetProcess().GetTarget(), Address::DumpStyleLoadAddress); 129 130 log->Printf ("Step range plan stepped to another range of same line: %s", s.GetData()); 131 } 132 } 133 else if (new_context.line_entry.range.GetBaseAddress().GetLoadAddress(&m_thread.GetProcess().GetTarget()) 134 != pc_load_addr) 135 { 136 // Another thing that sometimes happens here is that we step out of one line into the MIDDLE of another 137 // line. So far I mostly see this due to bugs in the debug information. 138 // But we probably don't want to be in the middle of a line range, so in that case reset the stepping 139 // range to the line we've stepped into the middle of and continue. 140 m_addr_context = new_context; 141 m_address_range = m_addr_context.line_entry.range; 142 ret_value = true; 143 if (log) 144 { 145 StreamString s; 146 m_address_range.Dump (&s, &m_thread.GetProcess().GetTarget(), Address::DumpStyleLoadAddress); 147 148 log->Printf ("Step range plan stepped to the middle of new line(%d): %s, continuing to clear this line.", 149 new_context.line_entry.line, 150 s.GetData()); 151 } 152 153 } 154 } 155 156 } 157 158 } 159 160 if (!ret_value && log) 161 log->Printf ("Step range plan out of range to 0x%llx", pc_load_addr); 162 163 return ret_value; 164 } 165 166 bool 167 ThreadPlanStepRange::InSymbol() 168 { 169 lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC(); 170 if (m_addr_context.function != NULL) 171 { 172 return m_addr_context.function->GetAddressRange().ContainsLoadAddress (cur_pc, &m_thread.GetProcess().GetTarget()); 173 } 174 else if (m_addr_context.symbol != NULL) 175 { 176 return m_addr_context.symbol->GetAddressRangeRef().ContainsLoadAddress (cur_pc, &m_thread.GetProcess().GetTarget()); 177 } 178 return false; 179 } 180 181 // FIXME: This should also handle inlining if we aren't going to do inlining in the 182 // main stack. 183 // 184 // Ideally we should remember the whole stack frame list, and then compare that 185 // to the current list. 186 187 bool 188 ThreadPlanStepRange::FrameIsYounger () 189 { 190 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 191 192 // FIXME: Might be better to do this by storing the FrameID we started in and seeing if that is still above 193 // us on the stack. Counting the whole stack could be expensive. 194 195 uint32_t current_depth = m_thread.GetStackFrameCount(); 196 if (current_depth == m_stack_depth) 197 { 198 if (log) 199 log->Printf ("Step range FrameIsYounger still in start function."); 200 return false; 201 } 202 else if (current_depth < m_stack_depth) 203 { 204 if (log) 205 log->Printf ("Step range FrameIsYounger stepped out: start depth: %d current depth %d.", m_stack_depth, current_depth); 206 return false; 207 } 208 else 209 { 210 if (log) 211 log->Printf ("Step range FrameIsYounger stepped in: start depth: %d current depth %d.", m_stack_depth, current_depth); 212 return true; 213 } 214 } 215 216 bool 217 ThreadPlanStepRange::FrameIsOlder () 218 { 219 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 220 uint32_t current_depth = m_thread.GetStackFrameCount(); 221 if (current_depth == m_stack_depth) 222 { 223 if (log) 224 log->Printf ("Step range FrameIsOlder still in start function."); 225 return false; 226 } 227 else if (current_depth < m_stack_depth) 228 { 229 if (log) 230 log->Printf ("Step range FrameIsOlder stepped out: start depth: %d current depth %d.", m_stack_depth, current_depth); 231 return true; 232 } 233 else 234 { 235 if (log) 236 log->Printf ("Step range FrameIsOlder stepped in: start depth: %d current depth %d.", m_stack_depth, current_depth); 237 return false; 238 } 239 } 240 241 bool 242 ThreadPlanStepRange::StopOthers () 243 { 244 if (m_stop_others == lldb::eOnlyThisThread 245 || m_stop_others == lldb::eOnlyDuringStepping) 246 return true; 247 else 248 return false; 249 } 250 251 bool 252 ThreadPlanStepRange::WillStop () 253 { 254 return true; 255 } 256 257 StateType 258 ThreadPlanStepRange::GetPlanRunState () 259 { 260 return eStateStepping; 261 } 262 263 bool 264 ThreadPlanStepRange::MischiefManaged () 265 { 266 bool done = true; 267 if (!IsPlanComplete()) 268 { 269 if (InRange()) 270 { 271 done = false; 272 } 273 else if (!FrameIsOlder()) 274 { 275 if (m_no_more_plans) 276 done = true; 277 else 278 done = false; 279 } 280 else 281 done = true; 282 } 283 284 if (done) 285 { 286 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 287 if (log) 288 log->Printf("Completed step through range plan."); 289 ThreadPlan::MischiefManaged (); 290 return true; 291 } 292 else 293 { 294 return false; 295 } 296 297 } 298