ThreadPlanStepUntil.cpp revision 296417
1//===-- ThreadPlanStepUntil.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// C Includes 11// C++ Includes 12// Other libraries and framework includes 13// Project includes 14#include "lldb/Target/ThreadPlanStepUntil.h" 15#include "lldb/Breakpoint/Breakpoint.h" 16#include "lldb/Core/Log.h" 17#include "lldb/Target/Process.h" 18#include "lldb/Target/RegisterContext.h" 19#include "lldb/Target/StopInfo.h" 20#include "lldb/Target/Target.h" 21 22using namespace lldb; 23using namespace lldb_private; 24 25//---------------------------------------------------------------------- 26// ThreadPlanStepUntil: Run until we reach a given line number or step out of the current frame 27//---------------------------------------------------------------------- 28 29ThreadPlanStepUntil::ThreadPlanStepUntil 30( 31 Thread &thread, 32 lldb::addr_t *address_list, 33 size_t num_addresses, 34 bool stop_others, 35 uint32_t frame_idx 36) : 37 ThreadPlan (ThreadPlan::eKindStepUntil, "Step until", thread, eVoteNoOpinion, eVoteNoOpinion), 38 m_step_from_insn (LLDB_INVALID_ADDRESS), 39 m_return_bp_id (LLDB_INVALID_BREAK_ID), 40 m_return_addr (LLDB_INVALID_ADDRESS), 41 m_stepped_out (false), 42 m_should_stop (false), 43 m_ran_analyze (false), 44 m_explains_stop (false), 45 m_until_points (), 46 m_stop_others (stop_others) 47{ 48 // Stash away our "until" addresses: 49 TargetSP target_sp (m_thread.CalculateTarget()); 50 51 StackFrameSP frame_sp (m_thread.GetStackFrameAtIndex (frame_idx)); 52 if (frame_sp) 53 { 54 m_step_from_insn = frame_sp->GetStackID().GetPC(); 55 lldb::user_id_t thread_id = m_thread.GetID(); 56 57 // Find the return address and set a breakpoint there: 58 // FIXME - can we do this more securely if we know first_insn? 59 60 StackFrameSP return_frame_sp (m_thread.GetStackFrameAtIndex(frame_idx + 1)); 61 if (return_frame_sp) 62 { 63 // TODO: add inline functionality 64 m_return_addr = return_frame_sp->GetStackID().GetPC(); 65 Breakpoint *return_bp = target_sp->CreateBreakpoint (m_return_addr, true, false).get(); 66 if (return_bp != nullptr) 67 { 68 return_bp->SetThreadID(thread_id); 69 m_return_bp_id = return_bp->GetID(); 70 return_bp->SetBreakpointKind ("until-return-backstop"); 71 } 72 } 73 74 m_stack_id = frame_sp->GetStackID(); 75 76 // Now set breakpoints on all our return addresses: 77 for (size_t i = 0; i < num_addresses; i++) 78 { 79 Breakpoint *until_bp = target_sp->CreateBreakpoint (address_list[i], true, false).get(); 80 if (until_bp != nullptr) 81 { 82 until_bp->SetThreadID(thread_id); 83 m_until_points[address_list[i]] = until_bp->GetID(); 84 until_bp->SetBreakpointKind("until-target"); 85 } 86 else 87 { 88 m_until_points[address_list[i]] = LLDB_INVALID_BREAK_ID; 89 } 90 } 91 } 92} 93 94ThreadPlanStepUntil::~ThreadPlanStepUntil () 95{ 96 Clear(); 97} 98 99void 100ThreadPlanStepUntil::Clear() 101{ 102 TargetSP target_sp (m_thread.CalculateTarget()); 103 if (target_sp) 104 { 105 if (m_return_bp_id != LLDB_INVALID_BREAK_ID) 106 { 107 target_sp->RemoveBreakpointByID(m_return_bp_id); 108 m_return_bp_id = LLDB_INVALID_BREAK_ID; 109 } 110 111 until_collection::iterator pos, end = m_until_points.end(); 112 for (pos = m_until_points.begin(); pos != end; pos++) 113 { 114 target_sp->RemoveBreakpointByID((*pos).second); 115 } 116 } 117 m_until_points.clear(); 118} 119 120void 121ThreadPlanStepUntil::GetDescription (Stream *s, lldb::DescriptionLevel level) 122{ 123 if (level == lldb::eDescriptionLevelBrief) 124 { 125 s->Printf ("step until"); 126 if (m_stepped_out) 127 s->Printf (" - stepped out"); 128 } 129 else 130 { 131 if (m_until_points.size() == 1) 132 s->Printf ("Stepping from address 0x%" PRIx64 " until we reach 0x%" PRIx64 " using breakpoint %d", 133 (uint64_t)m_step_from_insn, 134 (uint64_t) (*m_until_points.begin()).first, 135 (*m_until_points.begin()).second); 136 else 137 { 138 until_collection::iterator pos, end = m_until_points.end(); 139 s->Printf ("Stepping from address 0x%" PRIx64 " until we reach one of:", 140 (uint64_t)m_step_from_insn); 141 for (pos = m_until_points.begin(); pos != end; pos++) 142 { 143 s->Printf ("\n\t0x%" PRIx64 " (bp: %d)", (uint64_t) (*pos).first, (*pos).second); 144 } 145 } 146 s->Printf(" stepped out address is 0x%" PRIx64 ".", (uint64_t) m_return_addr); 147 } 148} 149 150bool 151ThreadPlanStepUntil::ValidatePlan (Stream *error) 152{ 153 if (m_return_bp_id == LLDB_INVALID_BREAK_ID) 154 return false; 155 else 156 { 157 until_collection::iterator pos, end = m_until_points.end(); 158 for (pos = m_until_points.begin(); pos != end; pos++) 159 { 160 if (!LLDB_BREAK_ID_IS_VALID ((*pos).second)) 161 return false; 162 } 163 return true; 164 } 165} 166 167void 168ThreadPlanStepUntil::AnalyzeStop() 169{ 170 if (m_ran_analyze) 171 return; 172 173 StopInfoSP stop_info_sp = GetPrivateStopInfo (); 174 m_should_stop = true; 175 m_explains_stop = false; 176 177 if (stop_info_sp) 178 { 179 StopReason reason = stop_info_sp->GetStopReason(); 180 181 if (reason == eStopReasonBreakpoint) 182 { 183 // If this is OUR breakpoint, we're fine, otherwise we don't know why this happened... 184 BreakpointSiteSP this_site = m_thread.GetProcess()->GetBreakpointSiteList().FindByID (stop_info_sp->GetValue()); 185 if (!this_site) 186 { 187 m_explains_stop = false; 188 return; 189 } 190 191 if (this_site->IsBreakpointAtThisSite (m_return_bp_id)) 192 { 193 // If we are at our "step out" breakpoint, and the stack depth has shrunk, then 194 // this is indeed our stop. 195 // If the stack depth has grown, then we've hit our step out breakpoint recursively. 196 // If we are the only breakpoint at that location, then we do explain the stop, and 197 // we'll just continue. 198 // If there was another breakpoint here, then we don't explain the stop, but we won't 199 // mark ourselves Completed, because maybe that breakpoint will continue, and then 200 // we'll finish the "until". 201 bool done; 202 StackID cur_frame_zero_id; 203 204 done = (m_stack_id < cur_frame_zero_id); 205 206 if (done) 207 { 208 m_stepped_out = true; 209 SetPlanComplete(); 210 } 211 else 212 m_should_stop = false; 213 214 if (this_site->GetNumberOfOwners() == 1) 215 m_explains_stop = true; 216 else 217 m_explains_stop = false; 218 return; 219 } 220 else 221 { 222 // Check if we've hit one of our "until" breakpoints. 223 until_collection::iterator pos, end = m_until_points.end(); 224 for (pos = m_until_points.begin(); pos != end; pos++) 225 { 226 if (this_site->IsBreakpointAtThisSite ((*pos).second)) 227 { 228 // If we're at the right stack depth, then we're done. 229 230 bool done; 231 StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); 232 233 if (frame_zero_id == m_stack_id) 234 done = true; 235 else if (frame_zero_id < m_stack_id) 236 done = false; 237 else 238 { 239 StackFrameSP older_frame_sp = m_thread.GetStackFrameAtIndex(1); 240 241 // But if we can't even unwind one frame we should just get out of here & stop... 242 if (older_frame_sp) 243 { 244 const SymbolContext &older_context 245 = older_frame_sp->GetSymbolContext(eSymbolContextEverything); 246 SymbolContext stack_context; 247 m_stack_id.GetSymbolContextScope()->CalculateSymbolContext(&stack_context); 248 249 done = (older_context == stack_context); 250 } 251 else 252 done = false; 253 } 254 255 if (done) 256 SetPlanComplete(); 257 else 258 m_should_stop = false; 259 260 // Otherwise we've hit this breakpoint recursively. If we're the 261 // only breakpoint here, then we do explain the stop, and we'll continue. 262 // If not then we should let higher plans handle this stop. 263 if (this_site->GetNumberOfOwners() == 1) 264 m_explains_stop = true; 265 else 266 { 267 m_should_stop = true; 268 m_explains_stop = false; 269 } 270 return; 271 } 272 } 273 } 274 // If we get here we haven't hit any of our breakpoints, so let the higher 275 // plans take care of the stop. 276 m_explains_stop = false; 277 return; 278 } 279 else if (IsUsuallyUnexplainedStopReason(reason)) 280 { 281 m_explains_stop = false; 282 } 283 else 284 { 285 m_explains_stop = true; 286 } 287 } 288} 289 290bool 291ThreadPlanStepUntil::DoPlanExplainsStop (Event *event_ptr) 292{ 293 // We don't explain signals or breakpoints (breakpoints that handle stepping in or 294 // out will be handled by a child plan. 295 AnalyzeStop(); 296 return m_explains_stop; 297} 298 299bool 300ThreadPlanStepUntil::ShouldStop (Event *event_ptr) 301{ 302 // If we've told our self in ExplainsStop that we plan to continue, then 303 // do so here. Otherwise, as long as this thread has stopped for a reason, 304 // we will stop. 305 306 StopInfoSP stop_info_sp = GetPrivateStopInfo (); 307 if (!stop_info_sp || stop_info_sp->GetStopReason() == eStopReasonNone) 308 return false; 309 310 AnalyzeStop(); 311 return m_should_stop; 312} 313 314bool 315ThreadPlanStepUntil::StopOthers () 316{ 317 return m_stop_others; 318} 319 320StateType 321ThreadPlanStepUntil::GetPlanRunState () 322{ 323 return eStateRunning; 324} 325 326bool 327ThreadPlanStepUntil::DoWillResume (StateType resume_state, bool current_plan) 328{ 329 if (current_plan) 330 { 331 TargetSP target_sp (m_thread.CalculateTarget()); 332 if (target_sp) 333 { 334 Breakpoint *return_bp = target_sp->GetBreakpointByID(m_return_bp_id).get(); 335 if (return_bp != nullptr) 336 return_bp->SetEnabled (true); 337 338 until_collection::iterator pos, end = m_until_points.end(); 339 for (pos = m_until_points.begin(); pos != end; pos++) 340 { 341 Breakpoint *until_bp = target_sp->GetBreakpointByID((*pos).second).get(); 342 if (until_bp != nullptr) 343 until_bp->SetEnabled (true); 344 } 345 } 346 } 347 348 m_should_stop = true; 349 m_ran_analyze = false; 350 m_explains_stop = false; 351 return true; 352} 353 354bool 355ThreadPlanStepUntil::WillStop () 356{ 357 TargetSP target_sp (m_thread.CalculateTarget()); 358 if (target_sp) 359 { 360 Breakpoint *return_bp = target_sp->GetBreakpointByID(m_return_bp_id).get(); 361 if (return_bp != nullptr) 362 return_bp->SetEnabled (false); 363 364 until_collection::iterator pos, end = m_until_points.end(); 365 for (pos = m_until_points.begin(); pos != end; pos++) 366 { 367 Breakpoint *until_bp = target_sp->GetBreakpointByID((*pos).second).get(); 368 if (until_bp != nullptr) 369 until_bp->SetEnabled (false); 370 } 371 } 372 return true; 373} 374 375bool 376ThreadPlanStepUntil::MischiefManaged () 377{ 378 // I'm letting "PlanExplainsStop" do all the work, and just reporting that here. 379 bool done = false; 380 if (IsPlanComplete()) 381 { 382 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 383 if (log) 384 log->Printf("Completed step until plan."); 385 386 Clear(); 387 done = true; 388 } 389 if (done) 390 ThreadPlan::MischiefManaged (); 391 392 return done; 393} 394