130fdc8d8SChris Lattner //===-- ThreadPlanStepInRange.cpp -------------------------------*- C++ -*-===// 230fdc8d8SChris Lattner // 330fdc8d8SChris Lattner // The LLVM Compiler Infrastructure 430fdc8d8SChris Lattner // 530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source 630fdc8d8SChris Lattner // License. See LICENSE.TXT for details. 730fdc8d8SChris Lattner // 830fdc8d8SChris Lattner //===----------------------------------------------------------------------===// 930fdc8d8SChris Lattner 1030fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepInRange.h" 1130fdc8d8SChris Lattner 1230fdc8d8SChris Lattner // C Includes 1330fdc8d8SChris Lattner // C++ Includes 1430fdc8d8SChris Lattner // Other libraries and framework includes 1530fdc8d8SChris Lattner // Project includes 1630fdc8d8SChris Lattner 1730fdc8d8SChris Lattner #include "lldb/lldb-private-log.h" 1830fdc8d8SChris Lattner #include "lldb/Core/Log.h" 1930fdc8d8SChris Lattner #include "lldb/Core/Stream.h" 20a56c8006SJim Ingham #include "lldb/Symbol/Symbol.h" 217ce490c6SJim Ingham #include "lldb/Symbol/Function.h" 2230fdc8d8SChris Lattner #include "lldb/Target/Process.h" 2330fdc8d8SChris Lattner #include "lldb/Target/RegisterContext.h" 2430fdc8d8SChris Lattner #include "lldb/Target/Thread.h" 2530fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepOut.h" 2630fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepThrough.h" 27a56c8006SJim Ingham #include "lldb/Core/RegularExpression.h" 2830fdc8d8SChris Lattner 2930fdc8d8SChris Lattner using namespace lldb; 3030fdc8d8SChris Lattner using namespace lldb_private; 3130fdc8d8SChris Lattner 3230fdc8d8SChris Lattner uint32_t ThreadPlanStepInRange::s_default_flag_values = ThreadPlanShouldStopHere::eAvoidNoDebug; 3330fdc8d8SChris Lattner 3430fdc8d8SChris Lattner //---------------------------------------------------------------------- 3530fdc8d8SChris Lattner // ThreadPlanStepInRange: Step through a stack range, either stepping over or into 3630fdc8d8SChris Lattner // based on the value of \a type. 3730fdc8d8SChris Lattner //---------------------------------------------------------------------- 3830fdc8d8SChris Lattner 3930fdc8d8SChris Lattner ThreadPlanStepInRange::ThreadPlanStepInRange 4030fdc8d8SChris Lattner ( 4130fdc8d8SChris Lattner Thread &thread, 4230fdc8d8SChris Lattner const AddressRange &range, 4330fdc8d8SChris Lattner const SymbolContext &addr_context, 4430fdc8d8SChris Lattner lldb::RunMode stop_others 4530fdc8d8SChris Lattner ) : 46b01e742aSJim Ingham ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others), 477ce490c6SJim Ingham ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL), 487ce490c6SJim Ingham m_step_past_prologue (true) 4930fdc8d8SChris Lattner { 5030fdc8d8SChris Lattner SetFlagsToDefault (); 5130fdc8d8SChris Lattner } 5230fdc8d8SChris Lattner 5330fdc8d8SChris Lattner ThreadPlanStepInRange::~ThreadPlanStepInRange () 5430fdc8d8SChris Lattner { 5530fdc8d8SChris Lattner } 5630fdc8d8SChris Lattner 5730fdc8d8SChris Lattner void 5830fdc8d8SChris Lattner ThreadPlanStepInRange::GetDescription (Stream *s, lldb::DescriptionLevel level) 5930fdc8d8SChris Lattner { 6030fdc8d8SChris Lattner if (level == lldb::eDescriptionLevelBrief) 6130fdc8d8SChris Lattner s->Printf("step in"); 6230fdc8d8SChris Lattner else 6330fdc8d8SChris Lattner { 6430fdc8d8SChris Lattner s->Printf ("Stepping through range (stepping into functions): "); 65f5e56de0SGreg Clayton m_address_range.Dump (s, &m_thread.GetProcess().GetTarget(), Address::DumpStyleLoadAddress); 6630fdc8d8SChris Lattner } 6730fdc8d8SChris Lattner } 6830fdc8d8SChris Lattner 6930fdc8d8SChris Lattner bool 7030fdc8d8SChris Lattner ThreadPlanStepInRange::ShouldStop (Event *event_ptr) 7130fdc8d8SChris Lattner { 7230fdc8d8SChris Lattner Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP); 7330fdc8d8SChris Lattner m_no_more_plans = false; 7430fdc8d8SChris Lattner 7530fdc8d8SChris Lattner if (log) 7630fdc8d8SChris Lattner { 7730fdc8d8SChris Lattner StreamString s; 7830fdc8d8SChris Lattner s.Address (m_thread.GetRegisterContext()->GetPC(), m_thread.GetProcess().GetAddressByteSize()); 7930fdc8d8SChris Lattner log->Printf("ThreadPlanStepInRange reached %s.", s.GetData()); 8030fdc8d8SChris Lattner } 8130fdc8d8SChris Lattner 8230fdc8d8SChris Lattner // If we're still in the range, keep going. 8330fdc8d8SChris Lattner if (InRange()) 8430fdc8d8SChris Lattner return false; 8530fdc8d8SChris Lattner 8630fdc8d8SChris Lattner // If we're in an older frame then we should stop. 8730fdc8d8SChris Lattner if (FrameIsOlder()) 8830fdc8d8SChris Lattner return true; 8930fdc8d8SChris Lattner 9030fdc8d8SChris Lattner // See if we are in a place we should step through (i.e. a trampoline of some sort): 9130fdc8d8SChris Lattner // One tricky bit here is that some stubs don't push a frame, so we have to check 9230fdc8d8SChris Lattner // both the case of a frame that is younger, or the same as this frame. 9330fdc8d8SChris Lattner // However, if the frame is the same, and we are still in the symbol we started 9430fdc8d8SChris Lattner // in, the we don't need to do this. This first check isn't strictly necessary, 9530fdc8d8SChris Lattner // but it is more efficient. 9630fdc8d8SChris Lattner 9730fdc8d8SChris Lattner if (!FrameIsYounger() && InSymbol()) 9830fdc8d8SChris Lattner { 9930fdc8d8SChris Lattner SetPlanComplete(); 10030fdc8d8SChris Lattner return true; 10130fdc8d8SChris Lattner } 10230fdc8d8SChris Lattner 10330fdc8d8SChris Lattner ThreadPlan* new_plan = NULL; 10430fdc8d8SChris Lattner 1059d790c5dSJim Ingham // Stepping through should be done stopping other threads in general, since we're setting a breakpoint and 1069d790c5dSJim Ingham // continuing... 1079d790c5dSJim Ingham 10830fdc8d8SChris Lattner bool stop_others; 1099d790c5dSJim Ingham if (m_stop_others != lldb::eAllThreads) 11030fdc8d8SChris Lattner stop_others = true; 11130fdc8d8SChris Lattner else 11230fdc8d8SChris Lattner stop_others = false; 11330fdc8d8SChris Lattner 11430fdc8d8SChris Lattner new_plan = m_thread.QueueThreadPlanForStepThrough (false, stop_others); 11508b87e0dSJim Ingham 11608b87e0dSJim Ingham if (log) 11708b87e0dSJim Ingham { 11808b87e0dSJim Ingham if (new_plan != NULL) 11908b87e0dSJim Ingham log->Printf ("Found a step through plan: %s", new_plan->GetName()); 12008b87e0dSJim Ingham else 12108b87e0dSJim Ingham log->Printf ("No step through plan found."); 12208b87e0dSJim Ingham } 12308b87e0dSJim Ingham 12430fdc8d8SChris Lattner // If not, give the "should_stop" callback a chance to push a plan to get us out of here. 12530fdc8d8SChris Lattner // But only do that if we actually have stepped in. 12630fdc8d8SChris Lattner if (!new_plan && FrameIsYounger()) 12730fdc8d8SChris Lattner new_plan = InvokeShouldStopHereCallback(); 12830fdc8d8SChris Lattner 1297ce490c6SJim Ingham // If we've stepped in and we are going to stop here, check to see if we were asked to 1307ce490c6SJim Ingham // run past the prologue, and if so do that. 1317ce490c6SJim Ingham 1327ce490c6SJim Ingham if (new_plan == NULL && FrameIsYounger() && m_step_past_prologue) 1337ce490c6SJim Ingham { 1347ce490c6SJim Ingham lldb::StackFrameSP curr_frame = m_thread.GetStackFrameAtIndex(0); 1357ce490c6SJim Ingham if (curr_frame) 1367ce490c6SJim Ingham { 1377ce490c6SJim Ingham size_t bytes_to_skip = 0; 1387ce490c6SJim Ingham lldb::addr_t curr_addr = m_thread.GetRegisterContext()->GetPC(); 1397ce490c6SJim Ingham Address func_start_address; 1407ce490c6SJim Ingham 1417ce490c6SJim Ingham SymbolContext sc = curr_frame->GetSymbolContext (eSymbolContextFunction | eSymbolContextSymbol); 1427ce490c6SJim Ingham 1437ce490c6SJim Ingham if (sc.function) 1447ce490c6SJim Ingham { 1457ce490c6SJim Ingham func_start_address = sc.function->GetAddressRange().GetBaseAddress(); 1467ce490c6SJim Ingham if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget())) 1477ce490c6SJim Ingham bytes_to_skip = sc.function->GetPrologueByteSize(); 1487ce490c6SJim Ingham } 1497ce490c6SJim Ingham else if (sc.symbol) 1507ce490c6SJim Ingham { 1517ce490c6SJim Ingham func_start_address = sc.symbol->GetValue(); 1527ce490c6SJim Ingham if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget())) 1537ce490c6SJim Ingham bytes_to_skip = sc.symbol->GetPrologueByteSize(); 1547ce490c6SJim Ingham } 1557ce490c6SJim Ingham 1567ce490c6SJim Ingham if (bytes_to_skip != 0) 1577ce490c6SJim Ingham { 1587ce490c6SJim Ingham func_start_address.Slide (bytes_to_skip); 1597ce490c6SJim Ingham if (log) 1607ce490c6SJim Ingham log->Printf ("Pushing past prologue "); 1617ce490c6SJim Ingham 1627ce490c6SJim Ingham new_plan = m_thread.QueueThreadPlanForRunToAddress(false, func_start_address,true); 1637ce490c6SJim Ingham } 1647ce490c6SJim Ingham } 1657ce490c6SJim Ingham } 1667ce490c6SJim Ingham 16730fdc8d8SChris Lattner if (new_plan == NULL) 16830fdc8d8SChris Lattner { 16930fdc8d8SChris Lattner m_no_more_plans = true; 17030fdc8d8SChris Lattner SetPlanComplete(); 17130fdc8d8SChris Lattner return true; 17230fdc8d8SChris Lattner } 17330fdc8d8SChris Lattner else 17430fdc8d8SChris Lattner { 17530fdc8d8SChris Lattner m_no_more_plans = false; 17630fdc8d8SChris Lattner return false; 17730fdc8d8SChris Lattner } 17830fdc8d8SChris Lattner } 17930fdc8d8SChris Lattner 18030fdc8d8SChris Lattner void 18130fdc8d8SChris Lattner ThreadPlanStepInRange::SetFlagsToDefault () 18230fdc8d8SChris Lattner { 18330fdc8d8SChris Lattner GetFlags().Set(ThreadPlanStepInRange::s_default_flag_values); 18430fdc8d8SChris Lattner } 18530fdc8d8SChris Lattner 18630fdc8d8SChris Lattner void 187a56c8006SJim Ingham ThreadPlanStepInRange::SetAvoidRegexp(const char *name) 188a56c8006SJim Ingham { 189a56c8006SJim Ingham if (m_avoid_regexp_ap.get() == NULL) 190a56c8006SJim Ingham m_avoid_regexp_ap.reset (new RegularExpression(name)); 191a56c8006SJim Ingham 192a56c8006SJim Ingham m_avoid_regexp_ap->Compile (name); 193a56c8006SJim Ingham } 194a56c8006SJim Ingham 195a56c8006SJim Ingham void 19630fdc8d8SChris Lattner ThreadPlanStepInRange::SetDefaultFlagValue (uint32_t new_value) 19730fdc8d8SChris Lattner { 19830fdc8d8SChris Lattner // TODO: Should we test this for sanity? 19930fdc8d8SChris Lattner ThreadPlanStepInRange::s_default_flag_values = new_value; 20030fdc8d8SChris Lattner } 20130fdc8d8SChris Lattner 202a56c8006SJim Ingham bool 203a56c8006SJim Ingham ThreadPlanStepInRange::FrameMatchesAvoidRegexp () 204a56c8006SJim Ingham { 205a56c8006SJim Ingham StackFrame *frame = GetThread().GetStackFrameAtIndex(0).get(); 206a56c8006SJim Ingham 207ee8aea10SJim Ingham RegularExpression *avoid_regexp_to_use; 208ee8aea10SJim Ingham 209ee8aea10SJim Ingham avoid_regexp_to_use = m_avoid_regexp_ap.get(); 210ee8aea10SJim Ingham if (avoid_regexp_to_use == NULL) 211ee8aea10SJim Ingham avoid_regexp_to_use = GetThread().GetSymbolsToAvoidRegexp(); 212ee8aea10SJim Ingham 213ee8aea10SJim Ingham if (avoid_regexp_to_use != NULL) 214a56c8006SJim Ingham { 215a56c8006SJim Ingham SymbolContext sc = frame->GetSymbolContext(eSymbolContextSymbol); 216a56c8006SJim Ingham if (sc.symbol != NULL) 217a56c8006SJim Ingham { 218a56c8006SJim Ingham const char *unnamed_symbol = "<UNKNOWN>"; 219a56c8006SJim Ingham const char *sym_name = sc.symbol->GetMangled().GetName().AsCString(unnamed_symbol); 220a56c8006SJim Ingham if (strcmp (sym_name, unnamed_symbol) != 0) 221ee8aea10SJim Ingham return avoid_regexp_to_use->Execute(sym_name); 222a56c8006SJim Ingham } 223a56c8006SJim Ingham } 224a56c8006SJim Ingham return false; 225a56c8006SJim Ingham } 226a56c8006SJim Ingham 22730fdc8d8SChris Lattner ThreadPlan * 22830fdc8d8SChris Lattner ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton) 22930fdc8d8SChris Lattner { 230a56c8006SJim Ingham bool should_step_out = false; 23130fdc8d8SChris Lattner StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get(); 232af0f1759SJim Ingham Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP); 23330fdc8d8SChris Lattner 234*73b472d4SGreg Clayton if (flags.Test(eAvoidNoDebug)) 235a56c8006SJim Ingham { 23630fdc8d8SChris Lattner if (!frame->HasDebugInformation()) 237af0f1759SJim Ingham { 238af0f1759SJim Ingham if (log) 239af0f1759SJim Ingham log->Printf ("Stepping out of frame with no debug info"); 240af0f1759SJim Ingham 241a56c8006SJim Ingham should_step_out = true; 242a56c8006SJim Ingham } 243af0f1759SJim Ingham } 244a56c8006SJim Ingham 245a56c8006SJim Ingham if (!should_step_out) 246a56c8006SJim Ingham { 247a56c8006SJim Ingham if (current_plan->GetKind() == eKindStepInRange) 248a56c8006SJim Ingham { 249a56c8006SJim Ingham ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan); 250a56c8006SJim Ingham should_step_out = step_in_range_plan->FrameMatchesAvoidRegexp (); 251a56c8006SJim Ingham } 252a56c8006SJim Ingham } 253a56c8006SJim Ingham 254a56c8006SJim Ingham if (should_step_out) 25530fdc8d8SChris Lattner { 25630fdc8d8SChris Lattner // FIXME: Make sure the ThreadPlanForStepOut does the right thing with inlined functions. 257a56c8006SJim Ingham return current_plan->GetThread().QueueThreadPlanForStepOut (false, NULL, true, 258a56c8006SJim Ingham current_plan->StopOthers(), 259a56c8006SJim Ingham eVoteNo, eVoteNoOpinion); 26030fdc8d8SChris Lattner } 26130fdc8d8SChris Lattner 26230fdc8d8SChris Lattner return NULL; 26330fdc8d8SChris Lattner } 264