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