ThreadPlanStepOut.cpp revision f4124deeb9532044a38c0774ced872f2709347da
1//===-- ThreadPlanStepOut.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/ThreadPlanStepOut.h" 11 12// C Includes 13// C++ Includes 14// Other libraries and framework includes 15// Project includes 16#include "lldb/Breakpoint/Breakpoint.h" 17#include "lldb/lldb-private-log.h" 18#include "lldb/Core/Log.h" 19#include "lldb/Core/Value.h" 20#include "lldb/Core/ValueObjectConstResult.h" 21#include "lldb/Target/Process.h" 22#include "lldb/Target/RegisterContext.h" 23#include "lldb/Target/StopInfo.h" 24#include "lldb/Target/Target.h" 25#include "lldb/Target/ThreadPlanStepOverRange.h" 26 27using namespace lldb; 28using namespace lldb_private; 29 30//---------------------------------------------------------------------- 31// ThreadPlanStepOut: Step out of the current frame 32//---------------------------------------------------------------------- 33 34ThreadPlanStepOut::ThreadPlanStepOut 35( 36 Thread &thread, 37 SymbolContext *context, 38 bool first_insn, 39 bool stop_others, 40 Vote stop_vote, 41 Vote run_vote, 42 uint32_t frame_idx 43) : 44 ThreadPlan (ThreadPlan::eKindStepOut, "Step out", thread, stop_vote, run_vote), 45 m_step_from_context (context), 46 m_step_from_insn (LLDB_INVALID_ADDRESS), 47 m_return_bp_id (LLDB_INVALID_BREAK_ID), 48 m_return_addr (LLDB_INVALID_ADDRESS), 49 m_first_insn (first_insn), 50 m_stop_others (stop_others), 51 m_step_through_inline_plan_sp(), 52 m_step_out_plan_sp (), 53 m_immediate_step_from_function(NULL) 54 55{ 56 m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0); 57 58 StackFrameSP return_frame_sp (m_thread.GetStackFrameAtIndex(frame_idx + 1)); 59 StackFrameSP immediate_return_from_sp (m_thread.GetStackFrameAtIndex (frame_idx)); 60 61 m_stack_depth = m_thread.GetStackFrameCount() - frame_idx; 62 63 // If the frame directly below the one we are returning to is inlined, we have to be 64 // a little more careful. It is non-trivial to determine the real "return code address" for 65 // an inlined frame, so we have to work our way to that frame and then step out. 66 if (immediate_return_from_sp && immediate_return_from_sp->IsInlined()) 67 { 68 if (frame_idx > 0) 69 { 70 // First queue a plan that gets us to this inlined frame, and when we get there we'll queue a second 71 // plan that walks us out of this frame. 72 m_step_out_plan_sp.reset (new ThreadPlanStepOut(m_thread, NULL, false, stop_others, eVoteNoOpinion, eVoteNoOpinion, frame_idx - 1)); 73 m_step_out_plan_sp->SetOkayToDiscard(true); 74 } 75 else 76 { 77 // If we're already at the inlined frame we're stepping through, then just do that now. 78 QueueInlinedStepPlan(false); 79 } 80 81 } 82 else if (return_frame_sp) 83 { 84 // Find the return address and set a breakpoint there: 85 // FIXME - can we do this more securely if we know first_insn? 86 87 m_return_addr = return_frame_sp->GetFrameCodeAddress().GetLoadAddress(&m_thread.GetProcess()->GetTarget()); 88 Breakpoint *return_bp = m_thread.CalculateTarget()->CreateBreakpoint (m_return_addr, true).get(); 89 if (return_bp != NULL) 90 { 91 return_bp->SetThreadID(m_thread.GetID()); 92 m_return_bp_id = return_bp->GetID(); 93 } 94 95 if (immediate_return_from_sp) 96 { 97 const SymbolContext &sc = immediate_return_from_sp->GetSymbolContext(eSymbolContextFunction); 98 if (sc.function) 99 { 100 m_immediate_step_from_function = sc.function; 101 } 102 } 103 } 104 105} 106 107void 108ThreadPlanStepOut::DidPush() 109{ 110 if (m_step_out_plan_sp) 111 m_thread.QueueThreadPlan(m_step_out_plan_sp, false); 112 else if (m_step_through_inline_plan_sp) 113 m_thread.QueueThreadPlan(m_step_through_inline_plan_sp, false); 114} 115 116ThreadPlanStepOut::~ThreadPlanStepOut () 117{ 118 if (m_return_bp_id != LLDB_INVALID_BREAK_ID) 119 m_thread.CalculateTarget()->RemoveBreakpointByID(m_return_bp_id); 120} 121 122void 123ThreadPlanStepOut::GetDescription (Stream *s, lldb::DescriptionLevel level) 124{ 125 if (level == lldb::eDescriptionLevelBrief) 126 s->Printf ("step out"); 127 else 128 { 129 if (m_step_out_plan_sp) 130 s->Printf ("Stepping out to inlined frame at depth: %d so we can walk through it.", m_stack_depth); 131 else if (m_step_through_inline_plan_sp) 132 s->Printf ("Stepping out by stepping through inlined function."); 133 else 134 s->Printf ("Stepping out from address 0x%llx to return address 0x%llx at depth: %d using breakpoint site %d", 135 (uint64_t)m_step_from_insn, 136 (uint64_t)m_return_addr, 137 m_stack_depth, 138 m_return_bp_id); 139 } 140} 141 142bool 143ThreadPlanStepOut::ValidatePlan (Stream *error) 144{ 145 if (m_step_out_plan_sp) 146 return m_step_out_plan_sp->ValidatePlan (error); 147 else if (m_step_through_inline_plan_sp) 148 return m_step_through_inline_plan_sp->ValidatePlan (error); 149 else if (m_return_bp_id == LLDB_INVALID_BREAK_ID) 150 { 151 error->PutCString("Could not create return address breakpoint."); 152 return false; 153 } 154 else 155 return true; 156} 157 158bool 159ThreadPlanStepOut::PlanExplainsStop () 160{ 161 // If one of our child plans just finished, then we do explain the stop. 162 if (m_step_out_plan_sp) 163 { 164 if (m_step_out_plan_sp->MischiefManaged()) 165 { 166 // If this one is done, then we are all done. 167 CalculateReturnValue(); 168 SetPlanComplete(); 169 return true; 170 } 171 else 172 return false; 173 } 174 else if (m_step_through_inline_plan_sp) 175 { 176 if (m_step_through_inline_plan_sp->MischiefManaged()) 177 return true; 178 else 179 return false; 180 } 181 182 // We don't explain signals or breakpoints (breakpoints that handle stepping in or 183 // out will be handled by a child plan. 184 185 StopInfoSP stop_info_sp = GetPrivateStopReason(); 186 if (stop_info_sp) 187 { 188 StopReason reason = stop_info_sp->GetStopReason(); 189 switch (reason) 190 { 191 case eStopReasonBreakpoint: 192 { 193 // If this is OUR breakpoint, we're fine, otherwise we don't know why this happened... 194 BreakpointSiteSP site_sp (m_thread.GetProcess()->GetBreakpointSiteList().FindByID (stop_info_sp->GetValue())); 195 if (site_sp && site_sp->IsBreakpointAtThisSite (m_return_bp_id)) 196 { 197 const uint32_t num_frames = m_thread.GetStackFrameCount(); 198 if (m_stack_depth > num_frames) 199 { 200 CalculateReturnValue(); 201 SetPlanComplete(); 202 } 203 204 // If there was only one owner, then we're done. But if we also hit some 205 // user breakpoint on our way out, we should mark ourselves as done, but 206 // also not claim to explain the stop, since it is more important to report 207 // the user breakpoint than the step out completion. 208 209 if (site_sp->GetNumberOfOwners() == 1) 210 return true; 211 212 } 213 return false; 214 } 215 case eStopReasonWatchpoint: 216 case eStopReasonSignal: 217 case eStopReasonException: 218 return false; 219 220 default: 221 return true; 222 } 223 } 224 return true; 225} 226 227bool 228ThreadPlanStepOut::ShouldStop (Event *event_ptr) 229{ 230 if (IsPlanComplete()) 231 { 232 return true; 233 } 234 else if (m_stack_depth > m_thread.GetStackFrameCount()) 235 { 236 CalculateReturnValue(); 237 SetPlanComplete(); 238 return true; 239 } 240 else 241 { 242 if (m_step_out_plan_sp) 243 { 244 if (m_step_out_plan_sp->MischiefManaged()) 245 { 246 // Now step through the inlined stack we are in: 247 if (QueueInlinedStepPlan(true)) 248 { 249 return false; 250 } 251 else 252 { 253 CalculateReturnValue(); 254 SetPlanComplete (); 255 return true; 256 } 257 } 258 else 259 return m_step_out_plan_sp->ShouldStop(event_ptr); 260 } 261 else if (m_step_through_inline_plan_sp) 262 { 263 if (m_step_through_inline_plan_sp->MischiefManaged()) 264 { 265 // We don't calculate the return value here because we don't know how to. 266 // But in case we had a return value sitting around from our process in 267 // getting here, let's clear it out. 268 m_return_valobj_sp.reset(); 269 SetPlanComplete(); 270 return true; 271 } 272 else 273 return m_step_through_inline_plan_sp->ShouldStop(event_ptr); 274 } 275 else 276 return false; 277 } 278} 279 280bool 281ThreadPlanStepOut::StopOthers () 282{ 283 return m_stop_others; 284} 285 286StateType 287ThreadPlanStepOut::GetPlanRunState () 288{ 289 return eStateRunning; 290} 291 292bool 293ThreadPlanStepOut::WillResume (StateType resume_state, bool current_plan) 294{ 295 ThreadPlan::WillResume (resume_state, current_plan); 296 if (m_step_out_plan_sp || m_step_through_inline_plan_sp) 297 return true; 298 299 if (m_return_bp_id == LLDB_INVALID_BREAK_ID) 300 return false; 301 302 if (current_plan) 303 { 304 Breakpoint *return_bp = m_thread.CalculateTarget()->GetBreakpointByID(m_return_bp_id).get(); 305 if (return_bp != NULL) 306 return_bp->SetEnabled (true); 307 } 308 return true; 309} 310 311bool 312ThreadPlanStepOut::WillStop () 313{ 314 if (m_return_bp_id != LLDB_INVALID_BREAK_ID) 315 { 316 Breakpoint *return_bp = m_thread.CalculateTarget()->GetBreakpointByID(m_return_bp_id).get(); 317 if (return_bp != NULL) 318 return_bp->SetEnabled (false); 319 } 320 321 return true; 322} 323 324bool 325ThreadPlanStepOut::MischiefManaged () 326{ 327 if (IsPlanComplete()) 328 { 329 // Did I reach my breakpoint? If so I'm done. 330 // 331 // I also check the stack depth, since if we've blown past the breakpoint for some 332 // reason and we're now stopping for some other reason altogether, then we're done 333 // with this step out operation. 334 335 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 336 if (log) 337 log->Printf("Completed step out plan."); 338 if (m_return_bp_id != LLDB_INVALID_BREAK_ID) 339 { 340 m_thread.CalculateTarget()->RemoveBreakpointByID (m_return_bp_id); 341 m_return_bp_id = LLDB_INVALID_BREAK_ID; 342 } 343 344 ThreadPlan::MischiefManaged (); 345 return true; 346 } 347 else 348 { 349 return false; 350 } 351} 352 353bool 354ThreadPlanStepOut::QueueInlinedStepPlan (bool queue_now) 355{ 356 // Now figure out the range of this inlined block, and set up a "step through range" 357 // plan for that. If we've been provided with a context, then use the block in that 358 // context. 359 StackFrameSP immediate_return_from_sp (m_thread.GetStackFrameAtIndex (0)); 360 if (!immediate_return_from_sp) 361 return false; 362 363 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 364 if (log) 365 { 366 StreamString s; 367 immediate_return_from_sp->Dump(&s, true, false); 368 log->Printf("Queuing inlined frame to step past: %s.", s.GetData()); 369 } 370 371 Block *from_block = immediate_return_from_sp->GetFrameBlock(); 372 if (from_block) 373 { 374 Block *inlined_block = from_block->GetContainingInlinedBlock(); 375 if (inlined_block) 376 { 377 size_t num_ranges = inlined_block->GetNumRanges(); 378 AddressRange inline_range; 379 if (inlined_block->GetRangeAtIndex(0, inline_range)) 380 { 381 SymbolContext inlined_sc; 382 inlined_block->CalculateSymbolContext(&inlined_sc); 383 RunMode run_mode = m_stop_others ? lldb::eOnlyThisThread : lldb::eAllThreads; 384 ThreadPlanStepOverRange *step_through_inline_plan_ptr = new ThreadPlanStepOverRange(m_thread, 385 inline_range, 386 inlined_sc, 387 run_mode); 388 step_through_inline_plan_ptr->SetOkayToDiscard(true); 389 StreamString errors; 390 if (!step_through_inline_plan_ptr->ValidatePlan(&errors)) 391 { 392 //FIXME: Log this failure. 393 delete step_through_inline_plan_ptr; 394 return false; 395 } 396 397 for (size_t i = 1; i < num_ranges; i++) 398 { 399 if (inlined_block->GetRangeAtIndex (i, inline_range)) 400 step_through_inline_plan_ptr->AddRange (inline_range); 401 } 402 m_step_through_inline_plan_sp.reset (step_through_inline_plan_ptr); 403 if (queue_now) 404 m_thread.QueueThreadPlan (m_step_through_inline_plan_sp, false); 405 return true; 406 } 407 } 408 } 409 410 return false; 411} 412 413void 414ThreadPlanStepOut::CalculateReturnValue () 415{ 416 if (m_return_valobj_sp) 417 return; 418 419 if (m_immediate_step_from_function != NULL) 420 { 421 Type *return_type = m_immediate_step_from_function->GetType(); 422 lldb::clang_type_t return_clang_type = m_immediate_step_from_function->GetReturnClangType(); 423 if (return_type && return_clang_type) 424 { 425 ClangASTType ast_type (return_type->GetClangAST(), return_clang_type); 426 427 lldb::ABISP abi_sp = m_thread.GetProcess()->GetABI(); 428 if (abi_sp) 429 { 430 m_return_valobj_sp = abi_sp->GetReturnValueObject(m_thread, ast_type); 431 } 432 } 433 } 434} 435