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_ranges (), 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 AddRange(range); 52 m_stack_depth = m_thread.GetStackFrameCount(); 53 m_stack_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); 54 } 55 56 ThreadPlanStepRange::~ThreadPlanStepRange () 57 { 58 } 59 60 bool 61 ThreadPlanStepRange::ValidatePlan (Stream *error) 62 { 63 return true; 64 } 65 66 bool 67 ThreadPlanStepRange::PlanExplainsStop () 68 { 69 // We don't explain signals or breakpoints (breakpoints that handle stepping in or 70 // out will be handled by a child plan. 71 StopInfoSP stop_info_sp = GetPrivateStopReason(); 72 if (stop_info_sp) 73 { 74 StopReason reason = stop_info_sp->GetStopReason(); 75 76 switch (reason) 77 { 78 case eStopReasonBreakpoint: 79 case eStopReasonWatchpoint: 80 case eStopReasonSignal: 81 case eStopReasonException: 82 return false; 83 default: 84 return true; 85 } 86 } 87 return true; 88 } 89 90 Vote 91 ThreadPlanStepRange::ShouldReportStop (Event *event_ptr) 92 { 93 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 94 95 const Vote vote = IsPlanComplete() ? eVoteYes : eVoteNo; 96 if (log) 97 log->Printf ("ThreadPlanStepRange::ShouldReportStop() returning vote %i\n", vote); 98 return vote; 99 } 100 101 void 102 ThreadPlanStepRange::AddRange(const AddressRange &new_range) 103 { 104 // For now I'm just adding the ranges. At some point we may want to 105 // condense the ranges if they overlap, though I don't think it is likely 106 // to be very important. 107 m_address_ranges.push_back (new_range); 108 } 109 110 void 111 ThreadPlanStepRange::DumpRanges(Stream *s) 112 { 113 size_t num_ranges = m_address_ranges.size(); 114 if (num_ranges == 1) 115 { 116 m_address_ranges[0].Dump (s, &m_thread.GetProcess().GetTarget(), Address::DumpStyleLoadAddress); 117 } 118 else 119 { 120 for (size_t i = 0; i < num_ranges; i++) 121 { 122 s->PutCString("%d: "); 123 m_address_ranges[i].Dump (s, &m_thread.GetProcess().GetTarget(), Address::DumpStyleLoadAddress); 124 } 125 } 126 } 127 128 bool 129 ThreadPlanStepRange::InRange () 130 { 131 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 132 bool ret_value = false; 133 134 lldb::addr_t pc_load_addr = m_thread.GetRegisterContext()->GetPC(); 135 136 size_t num_ranges = m_address_ranges.size(); 137 for (size_t i = 0; i < num_ranges; i++) 138 { 139 ret_value = m_address_ranges[i].ContainsLoadAddress(pc_load_addr, &m_thread.GetProcess().GetTarget()); 140 if (ret_value) 141 break; 142 } 143 144 if (!ret_value) 145 { 146 // See if we've just stepped to another part of the same line number... 147 StackFrame *frame = m_thread.GetStackFrameAtIndex(0).get(); 148 149 SymbolContext new_context(frame->GetSymbolContext(eSymbolContextEverything)); 150 if (m_addr_context.line_entry.IsValid() && new_context.line_entry.IsValid()) 151 { 152 if (m_addr_context.line_entry.file == new_context.line_entry.file) 153 { 154 if (m_addr_context.line_entry.line == new_context.line_entry.line) 155 { 156 m_addr_context = new_context; 157 AddRange(m_addr_context.line_entry.range); 158 ret_value = true; 159 if (log) 160 { 161 StreamString s; 162 m_addr_context.line_entry.range.Dump (&s, 163 &m_thread.GetProcess().GetTarget(), 164 Address::DumpStyleLoadAddress); 165 166 log->Printf ("Step range plan stepped to another range of same line: %s", s.GetData()); 167 } 168 } 169 else if (new_context.line_entry.range.GetBaseAddress().GetLoadAddress(&m_thread.GetProcess().GetTarget()) 170 != pc_load_addr) 171 { 172 // Another thing that sometimes happens here is that we step out of one line into the MIDDLE of another 173 // line. So far I mostly see this due to bugs in the debug information. 174 // But we probably don't want to be in the middle of a line range, so in that case reset the stepping 175 // range to the line we've stepped into the middle of and continue. 176 m_addr_context = new_context; 177 m_address_ranges.clear(); 178 AddRange(m_addr_context.line_entry.range); 179 ret_value = true; 180 if (log) 181 { 182 StreamString s; 183 m_addr_context.line_entry.range.Dump (&s, 184 &m_thread.GetProcess().GetTarget(), 185 Address::DumpStyleLoadAddress); 186 187 log->Printf ("Step range plan stepped to the middle of new line(%d): %s, continuing to clear this line.", 188 new_context.line_entry.line, 189 s.GetData()); 190 } 191 192 } 193 } 194 195 } 196 197 } 198 199 if (!ret_value && log) 200 log->Printf ("Step range plan out of range to 0x%llx", pc_load_addr); 201 202 return ret_value; 203 } 204 205 bool 206 ThreadPlanStepRange::InSymbol() 207 { 208 lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC(); 209 if (m_addr_context.function != NULL) 210 { 211 return m_addr_context.function->GetAddressRange().ContainsLoadAddress (cur_pc, &m_thread.GetProcess().GetTarget()); 212 } 213 else if (m_addr_context.symbol != NULL) 214 { 215 return m_addr_context.symbol->GetAddressRangeRef().ContainsLoadAddress (cur_pc, &m_thread.GetProcess().GetTarget()); 216 } 217 return false; 218 } 219 220 // FIXME: This should also handle inlining if we aren't going to do inlining in the 221 // main stack. 222 // 223 // Ideally we should remember the whole stack frame list, and then compare that 224 // to the current list. 225 226 bool 227 ThreadPlanStepRange::FrameIsYounger () 228 { 229 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 230 231 // FIXME: Might be better to do this by storing the FrameID we started in and seeing if that is still above 232 // us on the stack. Counting the whole stack could be expensive. 233 234 uint32_t current_depth = m_thread.GetStackFrameCount(); 235 if (current_depth == m_stack_depth) 236 { 237 if (log) 238 log->Printf ("Step range FrameIsYounger still in start function."); 239 return false; 240 } 241 else if (current_depth < m_stack_depth) 242 { 243 if (log) 244 log->Printf ("Step range FrameIsYounger stepped out: start depth: %d current depth %d.", m_stack_depth, current_depth); 245 return false; 246 } 247 else 248 { 249 if (log) 250 log->Printf ("Step range FrameIsYounger stepped in: start depth: %d current depth %d.", m_stack_depth, current_depth); 251 return true; 252 } 253 } 254 255 bool 256 ThreadPlanStepRange::FrameIsOlder () 257 { 258 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 259 uint32_t current_depth = m_thread.GetStackFrameCount(); 260 if (current_depth == m_stack_depth) 261 { 262 if (log) 263 log->Printf ("Step range FrameIsOlder still in start function."); 264 return false; 265 } 266 else if (current_depth < m_stack_depth) 267 { 268 if (log) 269 log->Printf ("Step range FrameIsOlder stepped out: start depth: %d current depth %d.", m_stack_depth, current_depth); 270 return true; 271 } 272 else 273 { 274 if (log) 275 log->Printf ("Step range FrameIsOlder stepped in: start depth: %d current depth %d.", m_stack_depth, current_depth); 276 return false; 277 } 278 } 279 280 bool 281 ThreadPlanStepRange::StopOthers () 282 { 283 if (m_stop_others == lldb::eOnlyThisThread 284 || m_stop_others == lldb::eOnlyDuringStepping) 285 return true; 286 else 287 return false; 288 } 289 290 bool 291 ThreadPlanStepRange::WillStop () 292 { 293 return true; 294 } 295 296 StateType 297 ThreadPlanStepRange::GetPlanRunState () 298 { 299 return eStateStepping; 300 } 301 302 bool 303 ThreadPlanStepRange::MischiefManaged () 304 { 305 bool done = true; 306 if (!IsPlanComplete()) 307 { 308 if (InRange()) 309 { 310 done = false; 311 } 312 else if (!FrameIsOlder()) 313 { 314 if (m_no_more_plans) 315 done = true; 316 else 317 done = false; 318 } 319 else 320 done = true; 321 } 322 323 if (done) 324 { 325 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 326 if (log) 327 log->Printf("Completed step through range plan."); 328 ThreadPlan::MischiefManaged (); 329 return true; 330 } 331 else 332 { 333 return false; 334 } 335 336 } 337