1 //===-- ThreadPlanStepOverRange.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/ThreadPlanStepOverRange.h" 15 #include "lldb/Core/Log.h" 16 #include "lldb/Symbol/Block.h" 17 #include "lldb/Symbol/CompileUnit.h" 18 #include "lldb/Symbol/Function.h" 19 #include "lldb/Symbol/LineTable.h" 20 #include "lldb/Target/Process.h" 21 #include "lldb/Target/RegisterContext.h" 22 #include "lldb/Target/Target.h" 23 #include "lldb/Target/Thread.h" 24 #include "lldb/Target/ThreadPlanStepOut.h" 25 #include "lldb/Target/ThreadPlanStepThrough.h" 26 #include "lldb/Utility/Stream.h" 27 28 using namespace lldb_private; 29 using namespace lldb; 30 31 uint32_t ThreadPlanStepOverRange::s_default_flag_values = 0; 32 33 //---------------------------------------------------------------------- 34 // ThreadPlanStepOverRange: Step through a stack range, either stepping over or 35 // into 36 // based on the value of \a type. 37 //---------------------------------------------------------------------- 38 39 ThreadPlanStepOverRange::ThreadPlanStepOverRange( 40 Thread &thread, const AddressRange &range, 41 const SymbolContext &addr_context, lldb::RunMode stop_others, 42 LazyBool step_out_avoids_code_without_debug_info) 43 : ThreadPlanStepRange(ThreadPlan::eKindStepOverRange, 44 "Step range stepping over", thread, range, 45 addr_context, stop_others), 46 ThreadPlanShouldStopHere(this), m_first_resume(true) { 47 SetFlagsToDefault(); 48 SetupAvoidNoDebug(step_out_avoids_code_without_debug_info); 49 } 50 51 ThreadPlanStepOverRange::~ThreadPlanStepOverRange() = default; 52 53 void ThreadPlanStepOverRange::GetDescription(Stream *s, 54 lldb::DescriptionLevel level) { 55 if (level == lldb::eDescriptionLevelBrief) { 56 s->Printf("step over"); 57 return; 58 } 59 s->Printf("Stepping over"); 60 bool printed_line_info = false; 61 if (m_addr_context.line_entry.IsValid()) { 62 s->Printf(" line "); 63 m_addr_context.line_entry.DumpStopContext(s, false); 64 printed_line_info = true; 65 } 66 67 if (!printed_line_info || level == eDescriptionLevelVerbose) { 68 s->Printf(" using ranges: "); 69 DumpRanges(s); 70 } 71 72 s->PutChar('.'); 73 } 74 75 void ThreadPlanStepOverRange::SetupAvoidNoDebug( 76 LazyBool step_out_avoids_code_without_debug_info) { 77 bool avoid_nodebug = true; 78 switch (step_out_avoids_code_without_debug_info) { 79 case eLazyBoolYes: 80 avoid_nodebug = true; 81 break; 82 case eLazyBoolNo: 83 avoid_nodebug = false; 84 break; 85 case eLazyBoolCalculate: 86 avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug(); 87 break; 88 } 89 if (avoid_nodebug) 90 GetFlags().Set(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); 91 else 92 GetFlags().Clear(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); 93 // Step Over plans should always avoid no-debug on step in. Seems like you 94 // shouldn't 95 // have to say this, but a tail call looks more like a step in that a step 96 // out, so 97 // we want to catch this case. 98 GetFlags().Set(ThreadPlanShouldStopHere::eStepInAvoidNoDebug); 99 } 100 101 bool ThreadPlanStepOverRange::IsEquivalentContext( 102 const SymbolContext &context) { 103 // Match as much as is specified in the m_addr_context: 104 // This is a fairly loose sanity check. Note, sometimes the target doesn't 105 // get filled 106 // in so I left out the target check. And sometimes the module comes in as 107 // the .o file from the 108 // inlined range, so I left that out too... 109 if (m_addr_context.comp_unit) { 110 if (m_addr_context.comp_unit != context.comp_unit) 111 return false; 112 if (m_addr_context.function) { 113 if (m_addr_context.function != context.function) 114 return false; 115 // It is okay to return to a different block of a straight function, we 116 // only have to 117 // be more careful if returning from one inlined block to another. 118 if (m_addr_context.block->GetInlinedFunctionInfo() == nullptr && 119 context.block->GetInlinedFunctionInfo() == nullptr) 120 return true; 121 return m_addr_context.block == context.block; 122 } 123 } 124 // Fall back to symbol if we have no decision from comp_unit/function/block. 125 if (m_addr_context.symbol && m_addr_context.symbol == context.symbol) { 126 return true; 127 } 128 return false; 129 } 130 131 bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { 132 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 133 134 if (log) { 135 StreamString s; 136 s.Address( 137 m_thread.GetRegisterContext()->GetPC(), 138 m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize()); 139 log->Printf("ThreadPlanStepOverRange reached %s.", s.GetData()); 140 } 141 142 // If we're out of the range but in the same frame or in our caller's frame 143 // then we should stop. 144 // When stepping out we only stop others if we are forcing running one thread. 145 bool stop_others = (m_stop_others == lldb::eOnlyThisThread); 146 ThreadPlanSP new_plan_sp; 147 FrameComparison frame_order = CompareCurrentFrameToStartFrame(); 148 149 if (frame_order == eFrameCompareOlder) { 150 // If we're in an older frame then we should stop. 151 // 152 // A caveat to this is if we think the frame is older but we're actually in 153 // a trampoline. 154 // I'm going to make the assumption that you wouldn't RETURN to a 155 // trampoline. So if we are 156 // in a trampoline we think the frame is older because the trampoline 157 // confused the backtracer. 158 // As below, we step through first, and then try to figure out how to get 159 // back out again. 160 161 new_plan_sp = 162 m_thread.QueueThreadPlanForStepThrough(m_stack_id, false, stop_others); 163 164 if (new_plan_sp && log) 165 log->Printf( 166 "Thought I stepped out, but in fact arrived at a trampoline."); 167 } else if (frame_order == eFrameCompareYounger) { 168 // Make sure we really are in a new frame. Do that by unwinding and seeing 169 // if the 170 // start function really is our start function... 171 for (uint32_t i = 1;; ++i) { 172 StackFrameSP older_frame_sp = m_thread.GetStackFrameAtIndex(i); 173 if (!older_frame_sp) { 174 // We can't unwind the next frame we should just get out of here & 175 // stop... 176 break; 177 } 178 179 const SymbolContext &older_context = 180 older_frame_sp->GetSymbolContext(eSymbolContextEverything); 181 if (IsEquivalentContext(older_context)) { 182 new_plan_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop( 183 false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0, 184 true); 185 break; 186 } else { 187 new_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false, 188 stop_others); 189 // If we found a way through, then we should stop recursing. 190 if (new_plan_sp) 191 break; 192 } 193 } 194 } else { 195 // If we're still in the range, keep going. 196 if (InRange()) { 197 SetNextBranchBreakpoint(); 198 return false; 199 } 200 201 if (!InSymbol()) { 202 // This one is a little tricky. Sometimes we may be in a stub or 203 // something similar, 204 // in which case we need to get out of there. But if we are in a stub 205 // then it's 206 // likely going to be hard to get out from here. It is probably easiest 207 // to step into the 208 // stub, and then it will be straight-forward to step out. 209 new_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false, 210 stop_others); 211 } else { 212 // The current clang (at least through 424) doesn't always get the address 213 // range for the 214 // DW_TAG_inlined_subroutines right, so that when you leave the inlined 215 // range the line table says 216 // you are still in the source file of the inlining function. This is 217 // bad, because now you are missing 218 // the stack frame for the function containing the inlining, and if you 219 // sensibly do "finish" to get 220 // out of this function you will instead exit the containing function. 221 // To work around this, we check whether we are still in the source file 222 // we started in, and if not assume 223 // it is an error, and push a plan to get us out of this line and back to 224 // the containing file. 225 226 if (m_addr_context.line_entry.IsValid()) { 227 SymbolContext sc; 228 StackFrameSP frame_sp = m_thread.GetStackFrameAtIndex(0); 229 sc = frame_sp->GetSymbolContext(eSymbolContextEverything); 230 if (sc.line_entry.IsValid()) { 231 if (sc.line_entry.original_file != 232 m_addr_context.line_entry.original_file && 233 sc.comp_unit == m_addr_context.comp_unit && 234 sc.function == m_addr_context.function) { 235 // Okay, find the next occurrence of this file in the line table: 236 LineTable *line_table = m_addr_context.comp_unit->GetLineTable(); 237 if (line_table) { 238 Address cur_address = frame_sp->GetFrameCodeAddress(); 239 uint32_t entry_idx; 240 LineEntry line_entry; 241 if (line_table->FindLineEntryByAddress(cur_address, line_entry, 242 &entry_idx)) { 243 LineEntry next_line_entry; 244 bool step_past_remaining_inline = false; 245 if (entry_idx > 0) { 246 // We require the previous line entry and the current line 247 // entry come 248 // from the same file. 249 // The other requirement is that the previous line table entry 250 // be part of an 251 // inlined block, we don't want to step past cases where 252 // people have inlined 253 // some code fragment by using #include <source-fragment.c> 254 // directly. 255 LineEntry prev_line_entry; 256 if (line_table->GetLineEntryAtIndex(entry_idx - 1, 257 prev_line_entry) && 258 prev_line_entry.original_file == 259 line_entry.original_file) { 260 SymbolContext prev_sc; 261 Address prev_address = 262 prev_line_entry.range.GetBaseAddress(); 263 prev_address.CalculateSymbolContext(&prev_sc); 264 if (prev_sc.block) { 265 Block *inlined_block = 266 prev_sc.block->GetContainingInlinedBlock(); 267 if (inlined_block) { 268 AddressRange inline_range; 269 inlined_block->GetRangeContainingAddress(prev_address, 270 inline_range); 271 if (!inline_range.ContainsFileAddress(cur_address)) { 272 273 step_past_remaining_inline = true; 274 } 275 } 276 } 277 } 278 } 279 280 if (step_past_remaining_inline) { 281 uint32_t look_ahead_step = 1; 282 while (line_table->GetLineEntryAtIndex( 283 entry_idx + look_ahead_step, next_line_entry)) { 284 // Make sure we haven't wandered out of the function we 285 // started from... 286 Address next_line_address = 287 next_line_entry.range.GetBaseAddress(); 288 Function *next_line_function = 289 next_line_address.CalculateSymbolContextFunction(); 290 if (next_line_function != m_addr_context.function) 291 break; 292 293 if (next_line_entry.original_file == 294 m_addr_context.line_entry.original_file) { 295 const bool abort_other_plans = false; 296 const RunMode stop_other_threads = RunMode::eAllThreads; 297 lldb::addr_t cur_pc = m_thread.GetStackFrameAtIndex(0) 298 ->GetRegisterContext() 299 ->GetPC(); 300 AddressRange step_range( 301 cur_pc, 302 next_line_address.GetLoadAddress(&GetTarget()) - 303 cur_pc); 304 305 new_plan_sp = m_thread.QueueThreadPlanForStepOverRange( 306 abort_other_plans, step_range, sc, 307 stop_other_threads); 308 break; 309 } 310 look_ahead_step++; 311 } 312 } 313 } 314 } 315 } 316 } 317 } 318 } 319 } 320 321 // If we get to this point, we're not going to use a previously set "next 322 // branch" breakpoint, so delete it: 323 ClearNextBranchBreakpoint(); 324 325 // If we haven't figured out something to do yet, then ask the ShouldStopHere 326 // callback: 327 if (!new_plan_sp) { 328 new_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order); 329 } 330 331 if (!new_plan_sp) 332 m_no_more_plans = true; 333 else { 334 // Any new plan will be an implementation plan, so mark it private: 335 new_plan_sp->SetPrivate(true); 336 m_no_more_plans = false; 337 } 338 339 if (!new_plan_sp) { 340 // For efficiencies sake, we know we're done here so we don't have to do 341 // this 342 // calculation again in MischiefManaged. 343 SetPlanComplete(); 344 return true; 345 } else 346 return false; 347 } 348 349 bool ThreadPlanStepOverRange::DoPlanExplainsStop(Event *event_ptr) { 350 // For crashes, breakpoint hits, signals, etc, let the base plan (or some plan 351 // above us) 352 // handle the stop. That way the user can see the stop, step around, and then 353 // when they 354 // are done, continue and have their step complete. The exception is if we've 355 // hit our 356 // "run to next branch" breakpoint. 357 // Note, unlike the step in range plan, we don't mark ourselves complete if we 358 // hit an 359 // unexplained breakpoint/crash. 360 361 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 362 StopInfoSP stop_info_sp = GetPrivateStopInfo(); 363 bool return_value; 364 365 if (stop_info_sp) { 366 StopReason reason = stop_info_sp->GetStopReason(); 367 368 if (reason == eStopReasonTrace) { 369 return_value = true; 370 } else if (reason == eStopReasonBreakpoint) { 371 return_value = NextRangeBreakpointExplainsStop(stop_info_sp); 372 } else { 373 if (log) 374 log->PutCString("ThreadPlanStepInRange got asked if it explains the " 375 "stop for some reason other than step."); 376 return_value = false; 377 } 378 } else 379 return_value = true; 380 381 return return_value; 382 } 383 384 bool ThreadPlanStepOverRange::DoWillResume(lldb::StateType resume_state, 385 bool current_plan) { 386 if (resume_state != eStateSuspended && m_first_resume) { 387 m_first_resume = false; 388 if (resume_state == eStateStepping && current_plan) { 389 // See if we are about to step over an inlined call in the middle of the 390 // inlined stack, if so figure 391 // out its extents and reset our range to step over that. 392 bool in_inlined_stack = m_thread.DecrementCurrentInlinedDepth(); 393 if (in_inlined_stack) { 394 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); 395 if (log) 396 log->Printf("ThreadPlanStepInRange::DoWillResume: adjusting range to " 397 "the frame at inlined depth %d.", 398 m_thread.GetCurrentInlinedDepth()); 399 StackFrameSP stack_sp = m_thread.GetStackFrameAtIndex(0); 400 if (stack_sp) { 401 Block *frame_block = stack_sp->GetFrameBlock(); 402 lldb::addr_t curr_pc = m_thread.GetRegisterContext()->GetPC(); 403 AddressRange my_range; 404 if (frame_block->GetRangeContainingLoadAddress( 405 curr_pc, m_thread.GetProcess()->GetTarget(), my_range)) { 406 m_address_ranges.clear(); 407 m_address_ranges.push_back(my_range); 408 if (log) { 409 StreamString s; 410 const InlineFunctionInfo *inline_info = 411 frame_block->GetInlinedFunctionInfo(); 412 const char *name; 413 if (inline_info) 414 name = 415 inline_info 416 ->GetName(frame_block->CalculateSymbolContextFunction() 417 ->GetLanguage()) 418 .AsCString(); 419 else 420 name = "<unknown-notinlined>"; 421 422 s.Printf( 423 "Stepping over inlined function \"%s\" in inlined stack: ", 424 name); 425 DumpRanges(&s); 426 log->PutString(s.GetString()); 427 } 428 } 429 } 430 } 431 } 432 } 433 434 return true; 435 } 436