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) 188 { 189 AddressRange range(m_addr_context.symbol->GetAddress(), m_addr_context.symbol->GetByteSize()); 190 return range.ContainsLoadAddress (cur_pc, m_thread.CalculateTarget().get()); 191 } 192 return false; 193 } 194 195 // FIXME: This should also handle inlining if we aren't going to do inlining in the 196 // main stack. 197 // 198 // Ideally we should remember the whole stack frame list, and then compare that 199 // to the current list. 200 201 lldb::FrameComparison 202 ThreadPlanStepRange::CompareCurrentFrameToStartFrame() 203 { 204 FrameComparison frame_order; 205 206 StackID cur_frame_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); 207 208 if (cur_frame_id == m_stack_id) 209 { 210 frame_order = eFrameCompareEqual; 211 } 212 else if (cur_frame_id < m_stack_id) 213 { 214 frame_order = eFrameCompareYounger; 215 } 216 else 217 { 218 frame_order = eFrameCompareOlder; 219 } 220 return frame_order; 221 } 222 223 bool 224 ThreadPlanStepRange::StopOthers () 225 { 226 if (m_stop_others == lldb::eOnlyThisThread 227 || m_stop_others == lldb::eOnlyDuringStepping) 228 return true; 229 else 230 return false; 231 } 232 233 bool 234 ThreadPlanStepRange::WillStop () 235 { 236 return true; 237 } 238 239 StateType 240 ThreadPlanStepRange::GetPlanRunState () 241 { 242 return eStateStepping; 243 } 244 245 bool 246 ThreadPlanStepRange::MischiefManaged () 247 { 248 bool done = true; 249 if (!IsPlanComplete()) 250 { 251 if (InRange()) 252 { 253 done = false; 254 } 255 else 256 { 257 FrameComparison frame_order = CompareCurrentFrameToStartFrame(); 258 if (frame_order != eFrameCompareOlder) 259 { 260 if (m_no_more_plans) 261 done = true; 262 else 263 done = false; 264 } 265 else 266 done = true; 267 } 268 } 269 270 if (done) 271 { 272 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 273 if (log) 274 log->Printf("Completed step through range plan."); 275 ThreadPlan::MischiefManaged (); 276 return true; 277 } 278 else 279 { 280 return false; 281 } 282 283 } 284