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