130fdc8d8SChris Lattner //===-- SBThread.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 104c5de699SEli Friedman #include "lldb/API/SBThread.h" 1130fdc8d8SChris Lattner 1230fdc8d8SChris Lattner #include "lldb/API/SBSymbolContext.h" 1330fdc8d8SChris Lattner #include "lldb/API/SBFileSpec.h" 14dde9cff3SCaroline Tice #include "lldb/API/SBStream.h" 154e78f606SGreg Clayton #include "lldb/Breakpoint/BreakpointLocation.h" 166611103cSGreg Clayton #include "lldb/Core/Debugger.h" 1730fdc8d8SChris Lattner #include "lldb/Core/Stream.h" 1830fdc8d8SChris Lattner #include "lldb/Core/StreamFile.h" 196611103cSGreg Clayton #include "lldb/Interpreter/CommandInterpreter.h" 2030fdc8d8SChris Lattner #include "lldb/Target/Thread.h" 2130fdc8d8SChris Lattner #include "lldb/Target/Process.h" 2230fdc8d8SChris Lattner #include "lldb/Symbol/SymbolContext.h" 2330fdc8d8SChris Lattner #include "lldb/Symbol/CompileUnit.h" 24f4b47e15SGreg Clayton #include "lldb/Target/StopInfo.h" 2530fdc8d8SChris Lattner #include "lldb/Target/Target.h" 2630fdc8d8SChris Lattner #include "lldb/Target/ThreadPlan.h" 2730fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepInstruction.h" 2830fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepOut.h" 2930fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepRange.h" 3030fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepInRange.h" 3130fdc8d8SChris Lattner 3230fdc8d8SChris Lattner 334c5de699SEli Friedman #include "lldb/API/SBAddress.h" 344c5de699SEli Friedman #include "lldb/API/SBDebugger.h" 3573ca05a2SJim Ingham #include "lldb/API/SBFrame.h" 364c5de699SEli Friedman #include "lldb/API/SBProcess.h" 3773ca05a2SJim Ingham #include "lldb/API/SBValue.h" 3830fdc8d8SChris Lattner 3930fdc8d8SChris Lattner using namespace lldb; 4030fdc8d8SChris Lattner using namespace lldb_private; 4130fdc8d8SChris Lattner 42cfd1acedSGreg Clayton //---------------------------------------------------------------------- 43cfd1acedSGreg Clayton // Constructors 44cfd1acedSGreg Clayton //---------------------------------------------------------------------- 4530fdc8d8SChris Lattner SBThread::SBThread () : 467fdf9ef1SGreg Clayton m_opaque_sp (new ExecutionContextRef()) 4730fdc8d8SChris Lattner { 4830fdc8d8SChris Lattner } 4930fdc8d8SChris Lattner 5030fdc8d8SChris Lattner SBThread::SBThread (const ThreadSP& lldb_object_sp) : 517fdf9ef1SGreg Clayton m_opaque_sp (new ExecutionContextRef(lldb_object_sp)) 5230fdc8d8SChris Lattner { 5330fdc8d8SChris Lattner } 5430fdc8d8SChris Lattner 5592ef5735SGreg Clayton SBThread::SBThread (const SBThread &rhs) : 567fdf9ef1SGreg Clayton m_opaque_sp (new ExecutionContextRef(*rhs.m_opaque_sp)) 5730fdc8d8SChris Lattner { 587fdf9ef1SGreg Clayton 5930fdc8d8SChris Lattner } 6030fdc8d8SChris Lattner 6130fdc8d8SChris Lattner //---------------------------------------------------------------------- 62cfd1acedSGreg Clayton // Assignment operator 63cfd1acedSGreg Clayton //---------------------------------------------------------------------- 64cfd1acedSGreg Clayton 65cfd1acedSGreg Clayton const lldb::SBThread & 66cfd1acedSGreg Clayton SBThread::operator = (const SBThread &rhs) 67cfd1acedSGreg Clayton { 68cfd1acedSGreg Clayton if (this != &rhs) 697fdf9ef1SGreg Clayton *m_opaque_sp = *rhs.m_opaque_sp; 70cfd1acedSGreg Clayton return *this; 71cfd1acedSGreg Clayton } 72cfd1acedSGreg Clayton 73cfd1acedSGreg Clayton //---------------------------------------------------------------------- 7430fdc8d8SChris Lattner // Destructor 7530fdc8d8SChris Lattner //---------------------------------------------------------------------- 7630fdc8d8SChris Lattner SBThread::~SBThread() 7730fdc8d8SChris Lattner { 7830fdc8d8SChris Lattner } 7930fdc8d8SChris Lattner 8030fdc8d8SChris Lattner bool 8130fdc8d8SChris Lattner SBThread::IsValid() const 8230fdc8d8SChris Lattner { 837fdf9ef1SGreg Clayton return m_opaque_sp->GetThreadSP().get() != NULL; 8430fdc8d8SChris Lattner } 8530fdc8d8SChris Lattner 8648e42549SGreg Clayton void 8748e42549SGreg Clayton SBThread::Clear () 8848e42549SGreg Clayton { 897fdf9ef1SGreg Clayton m_opaque_sp->Clear(); 9048e42549SGreg Clayton } 9148e42549SGreg Clayton 9248e42549SGreg Clayton 9330fdc8d8SChris Lattner StopReason 9430fdc8d8SChris Lattner SBThread::GetStopReason() 9530fdc8d8SChris Lattner { 962d4edfbcSGreg Clayton LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); 97ceb6b139SCaroline Tice 98ceb6b139SCaroline Tice StopReason reason = eStopReasonInvalid; 997fdf9ef1SGreg Clayton ExecutionContext exe_ctx (m_opaque_sp.get()); 1001ac04c30SGreg Clayton if (exe_ctx.HasThreadScope()) 10130fdc8d8SChris Lattner { 1027fdf9ef1SGreg Clayton Process::StopLocker stop_locker; 1037fdf9ef1SGreg Clayton if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) 1047fdf9ef1SGreg Clayton { 1051ac04c30SGreg Clayton Mutex::Locker api_locker (exe_ctx.GetTargetPtr()->GetAPIMutex()); 1061ac04c30SGreg Clayton StopInfoSP stop_info_sp = exe_ctx.GetThreadPtr()->GetStopInfo (); 107b15bfc75SJim Ingham if (stop_info_sp) 108ceb6b139SCaroline Tice reason = stop_info_sp->GetStopReason(); 10930fdc8d8SChris Lattner } 110c9858e4dSGreg Clayton else 111c9858e4dSGreg Clayton { 112c9858e4dSGreg Clayton if (log) 113c9858e4dSGreg Clayton log->Printf ("SBThread(%p)::GetStopReason() => error: process is running", exe_ctx.GetThreadPtr()); 114c9858e4dSGreg Clayton } 1157fdf9ef1SGreg Clayton } 116ceb6b139SCaroline Tice 117ceb6b139SCaroline Tice if (log) 1181ac04c30SGreg Clayton log->Printf ("SBThread(%p)::GetStopReason () => %s", exe_ctx.GetThreadPtr(), 119750cd175SCaroline Tice Thread::StopReasonAsCString (reason)); 120ceb6b139SCaroline Tice 121ceb6b139SCaroline Tice return reason; 12230fdc8d8SChris Lattner } 12330fdc8d8SChris Lattner 12430fdc8d8SChris Lattner size_t 1254e78f606SGreg Clayton SBThread::GetStopReasonDataCount () 1264e78f606SGreg Clayton { 1277fdf9ef1SGreg Clayton ExecutionContext exe_ctx (m_opaque_sp.get()); 1281ac04c30SGreg Clayton if (exe_ctx.HasThreadScope()) 1294e78f606SGreg Clayton { 1307fdf9ef1SGreg Clayton Process::StopLocker stop_locker; 1317fdf9ef1SGreg Clayton if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) 1327fdf9ef1SGreg Clayton { 1331ac04c30SGreg Clayton Mutex::Locker api_locker (exe_ctx.GetTargetPtr()->GetAPIMutex()); 1341ac04c30SGreg Clayton StopInfoSP stop_info_sp = exe_ctx.GetThreadPtr()->GetStopInfo (); 1354e78f606SGreg Clayton if (stop_info_sp) 1364e78f606SGreg Clayton { 1374e78f606SGreg Clayton StopReason reason = stop_info_sp->GetStopReason(); 1384e78f606SGreg Clayton switch (reason) 1394e78f606SGreg Clayton { 1404e78f606SGreg Clayton case eStopReasonInvalid: 1414e78f606SGreg Clayton case eStopReasonNone: 1424e78f606SGreg Clayton case eStopReasonTrace: 1434e78f606SGreg Clayton case eStopReasonPlanComplete: 1444e78f606SGreg Clayton // There is no data for these stop reasons. 1454e78f606SGreg Clayton return 0; 1464e78f606SGreg Clayton 1474e78f606SGreg Clayton case eStopReasonBreakpoint: 1484e78f606SGreg Clayton { 1494e78f606SGreg Clayton break_id_t site_id = stop_info_sp->GetValue(); 1501ac04c30SGreg Clayton lldb::BreakpointSiteSP bp_site_sp (exe_ctx.GetProcessPtr()->GetBreakpointSiteList().FindByID (site_id)); 1514e78f606SGreg Clayton if (bp_site_sp) 1524e78f606SGreg Clayton return bp_site_sp->GetNumberOfOwners () * 2; 1534e78f606SGreg Clayton else 1544e78f606SGreg Clayton return 0; // Breakpoint must have cleared itself... 1554e78f606SGreg Clayton } 1564e78f606SGreg Clayton break; 1574e78f606SGreg Clayton 1584e78f606SGreg Clayton case eStopReasonWatchpoint: 159290fa41bSJohnny Chen return 1; 1604e78f606SGreg Clayton 1614e78f606SGreg Clayton case eStopReasonSignal: 1624e78f606SGreg Clayton return 1; 1634e78f606SGreg Clayton 1644e78f606SGreg Clayton case eStopReasonException: 1654e78f606SGreg Clayton return 1; 1664e78f606SGreg Clayton } 1674e78f606SGreg Clayton } 1684e78f606SGreg Clayton } 169c9858e4dSGreg Clayton else 170c9858e4dSGreg Clayton { 171c9858e4dSGreg Clayton LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); 172c9858e4dSGreg Clayton if (log) 173c9858e4dSGreg Clayton log->Printf ("SBThread(%p)::GetStopReasonDataCount() => error: process is running", exe_ctx.GetThreadPtr()); 174c9858e4dSGreg Clayton } 1757fdf9ef1SGreg Clayton } 1764e78f606SGreg Clayton return 0; 1774e78f606SGreg Clayton } 1784e78f606SGreg Clayton 1794e78f606SGreg Clayton uint64_t 1804e78f606SGreg Clayton SBThread::GetStopReasonDataAtIndex (uint32_t idx) 1814e78f606SGreg Clayton { 1827fdf9ef1SGreg Clayton ExecutionContext exe_ctx (m_opaque_sp.get()); 1831ac04c30SGreg Clayton if (exe_ctx.HasThreadScope()) 1844e78f606SGreg Clayton { 1857fdf9ef1SGreg Clayton Process::StopLocker stop_locker; 1867fdf9ef1SGreg Clayton if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) 1877fdf9ef1SGreg Clayton { 1887fdf9ef1SGreg Clayton 1891ac04c30SGreg Clayton Mutex::Locker api_locker (exe_ctx.GetTargetPtr()->GetAPIMutex()); 1901ac04c30SGreg Clayton Thread *thread = exe_ctx.GetThreadPtr(); 1911ac04c30SGreg Clayton StopInfoSP stop_info_sp = thread->GetStopInfo (); 1924e78f606SGreg Clayton if (stop_info_sp) 1934e78f606SGreg Clayton { 1944e78f606SGreg Clayton StopReason reason = stop_info_sp->GetStopReason(); 1954e78f606SGreg Clayton switch (reason) 1964e78f606SGreg Clayton { 1974e78f606SGreg Clayton case eStopReasonInvalid: 1984e78f606SGreg Clayton case eStopReasonNone: 1994e78f606SGreg Clayton case eStopReasonTrace: 2004e78f606SGreg Clayton case eStopReasonPlanComplete: 2014e78f606SGreg Clayton // There is no data for these stop reasons. 2024e78f606SGreg Clayton return 0; 2034e78f606SGreg Clayton 2044e78f606SGreg Clayton case eStopReasonBreakpoint: 2054e78f606SGreg Clayton { 2064e78f606SGreg Clayton break_id_t site_id = stop_info_sp->GetValue(); 2071ac04c30SGreg Clayton lldb::BreakpointSiteSP bp_site_sp (exe_ctx.GetProcessPtr()->GetBreakpointSiteList().FindByID (site_id)); 2084e78f606SGreg Clayton if (bp_site_sp) 2094e78f606SGreg Clayton { 2104e78f606SGreg Clayton uint32_t bp_index = idx / 2; 2114e78f606SGreg Clayton BreakpointLocationSP bp_loc_sp (bp_site_sp->GetOwnerAtIndex (bp_index)); 2124e78f606SGreg Clayton if (bp_loc_sp) 2134e78f606SGreg Clayton { 2144e78f606SGreg Clayton if (bp_index & 1) 2154e78f606SGreg Clayton { 2164e78f606SGreg Clayton // Odd idx, return the breakpoint location ID 2174e78f606SGreg Clayton return bp_loc_sp->GetID(); 2184e78f606SGreg Clayton } 2194e78f606SGreg Clayton else 2204e78f606SGreg Clayton { 2214e78f606SGreg Clayton // Even idx, return the breakpoint ID 2224e78f606SGreg Clayton return bp_loc_sp->GetBreakpoint().GetID(); 2234e78f606SGreg Clayton } 2244e78f606SGreg Clayton } 2254e78f606SGreg Clayton } 2264e78f606SGreg Clayton return LLDB_INVALID_BREAK_ID; 2274e78f606SGreg Clayton } 2284e78f606SGreg Clayton break; 2294e78f606SGreg Clayton 2304e78f606SGreg Clayton case eStopReasonWatchpoint: 231290fa41bSJohnny Chen return stop_info_sp->GetValue(); 2324e78f606SGreg Clayton 2334e78f606SGreg Clayton case eStopReasonSignal: 2344e78f606SGreg Clayton return stop_info_sp->GetValue(); 2354e78f606SGreg Clayton 2364e78f606SGreg Clayton case eStopReasonException: 2374e78f606SGreg Clayton return stop_info_sp->GetValue(); 2384e78f606SGreg Clayton } 2394e78f606SGreg Clayton } 2404e78f606SGreg Clayton } 241c9858e4dSGreg Clayton else 242c9858e4dSGreg Clayton { 243c9858e4dSGreg Clayton LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); 244c9858e4dSGreg Clayton if (log) 245c9858e4dSGreg Clayton log->Printf ("SBThread(%p)::GetStopReasonDataAtIndex() => error: process is running", exe_ctx.GetThreadPtr()); 246c9858e4dSGreg Clayton } 2477fdf9ef1SGreg Clayton } 2484e78f606SGreg Clayton return 0; 2494e78f606SGreg Clayton } 2504e78f606SGreg Clayton 2514e78f606SGreg Clayton size_t 25230fdc8d8SChris Lattner SBThread::GetStopDescription (char *dst, size_t dst_len) 25330fdc8d8SChris Lattner { 2542d4edfbcSGreg Clayton LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); 255ceb6b139SCaroline Tice 2567fdf9ef1SGreg Clayton ExecutionContext exe_ctx (m_opaque_sp.get()); 2571ac04c30SGreg Clayton if (exe_ctx.HasThreadScope()) 25830fdc8d8SChris Lattner { 2597fdf9ef1SGreg Clayton Process::StopLocker stop_locker; 2607fdf9ef1SGreg Clayton if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) 2617fdf9ef1SGreg Clayton { 2627fdf9ef1SGreg Clayton 2631ac04c30SGreg Clayton Mutex::Locker api_locker (exe_ctx.GetTargetPtr()->GetAPIMutex()); 2641ac04c30SGreg Clayton StopInfoSP stop_info_sp = exe_ctx.GetThreadPtr()->GetStopInfo (); 265b15bfc75SJim Ingham if (stop_info_sp) 26630fdc8d8SChris Lattner { 267b15bfc75SJim Ingham const char *stop_desc = stop_info_sp->GetDescription(); 26830fdc8d8SChris Lattner if (stop_desc) 26930fdc8d8SChris Lattner { 270ceb6b139SCaroline Tice if (log) 2714838131bSGreg Clayton log->Printf ("SBThread(%p)::GetStopDescription (dst, dst_len) => \"%s\"", 2721ac04c30SGreg Clayton exe_ctx.GetThreadPtr(), stop_desc); 27330fdc8d8SChris Lattner if (dst) 27430fdc8d8SChris Lattner return ::snprintf (dst, dst_len, "%s", stop_desc); 27530fdc8d8SChris Lattner else 27630fdc8d8SChris Lattner { 27730fdc8d8SChris Lattner // NULL dst passed in, return the length needed to contain the description 27830fdc8d8SChris Lattner return ::strlen (stop_desc) + 1; // Include the NULL byte for size 27930fdc8d8SChris Lattner } 28030fdc8d8SChris Lattner } 28130fdc8d8SChris Lattner else 28230fdc8d8SChris Lattner { 28330fdc8d8SChris Lattner size_t stop_desc_len = 0; 284b15bfc75SJim Ingham switch (stop_info_sp->GetStopReason()) 28530fdc8d8SChris Lattner { 28630fdc8d8SChris Lattner case eStopReasonTrace: 28730fdc8d8SChris Lattner case eStopReasonPlanComplete: 28830fdc8d8SChris Lattner { 28930fdc8d8SChris Lattner static char trace_desc[] = "step"; 29030fdc8d8SChris Lattner stop_desc = trace_desc; 29130fdc8d8SChris Lattner stop_desc_len = sizeof(trace_desc); // Include the NULL byte for size 29230fdc8d8SChris Lattner } 29330fdc8d8SChris Lattner break; 29430fdc8d8SChris Lattner 29530fdc8d8SChris Lattner case eStopReasonBreakpoint: 29630fdc8d8SChris Lattner { 29730fdc8d8SChris Lattner static char bp_desc[] = "breakpoint hit"; 29830fdc8d8SChris Lattner stop_desc = bp_desc; 29930fdc8d8SChris Lattner stop_desc_len = sizeof(bp_desc); // Include the NULL byte for size 30030fdc8d8SChris Lattner } 30130fdc8d8SChris Lattner break; 30230fdc8d8SChris Lattner 30330fdc8d8SChris Lattner case eStopReasonWatchpoint: 30430fdc8d8SChris Lattner { 30530fdc8d8SChris Lattner static char wp_desc[] = "watchpoint hit"; 30630fdc8d8SChris Lattner stop_desc = wp_desc; 30730fdc8d8SChris Lattner stop_desc_len = sizeof(wp_desc); // Include the NULL byte for size 30830fdc8d8SChris Lattner } 30930fdc8d8SChris Lattner break; 31030fdc8d8SChris Lattner 31130fdc8d8SChris Lattner case eStopReasonSignal: 31230fdc8d8SChris Lattner { 3131ac04c30SGreg Clayton stop_desc = exe_ctx.GetProcessPtr()->GetUnixSignals ().GetSignalAsCString (stop_info_sp->GetValue()); 31430fdc8d8SChris Lattner if (stop_desc == NULL || stop_desc[0] == '\0') 31530fdc8d8SChris Lattner { 31630fdc8d8SChris Lattner static char signal_desc[] = "signal"; 31730fdc8d8SChris Lattner stop_desc = signal_desc; 31830fdc8d8SChris Lattner stop_desc_len = sizeof(signal_desc); // Include the NULL byte for size 31930fdc8d8SChris Lattner } 32030fdc8d8SChris Lattner } 32130fdc8d8SChris Lattner break; 32230fdc8d8SChris Lattner 32330fdc8d8SChris Lattner case eStopReasonException: 32430fdc8d8SChris Lattner { 32530fdc8d8SChris Lattner char exc_desc[] = "exception"; 32630fdc8d8SChris Lattner stop_desc = exc_desc; 32730fdc8d8SChris Lattner stop_desc_len = sizeof(exc_desc); // Include the NULL byte for size 32830fdc8d8SChris Lattner } 32930fdc8d8SChris Lattner break; 330c982c768SGreg Clayton 331c982c768SGreg Clayton default: 332c982c768SGreg Clayton break; 33330fdc8d8SChris Lattner } 33430fdc8d8SChris Lattner 33530fdc8d8SChris Lattner if (stop_desc && stop_desc[0]) 33630fdc8d8SChris Lattner { 337ceb6b139SCaroline Tice if (log) 33893aa84e8SGreg Clayton log->Printf ("SBThread(%p)::GetStopDescription (dst, dst_len) => '%s'", 3391ac04c30SGreg Clayton exe_ctx.GetThreadPtr(), stop_desc); 340ceb6b139SCaroline Tice 34130fdc8d8SChris Lattner if (dst) 34230fdc8d8SChris Lattner return ::snprintf (dst, dst_len, "%s", stop_desc) + 1; // Include the NULL byte 34330fdc8d8SChris Lattner 34430fdc8d8SChris Lattner if (stop_desc_len == 0) 34530fdc8d8SChris Lattner stop_desc_len = ::strlen (stop_desc) + 1; // Include the NULL byte 34630fdc8d8SChris Lattner 34730fdc8d8SChris Lattner return stop_desc_len; 34830fdc8d8SChris Lattner } 34930fdc8d8SChris Lattner } 35030fdc8d8SChris Lattner } 35130fdc8d8SChris Lattner } 352c9858e4dSGreg Clayton else 353c9858e4dSGreg Clayton { 354c9858e4dSGreg Clayton LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); 355c9858e4dSGreg Clayton if (log) 356c9858e4dSGreg Clayton log->Printf ("SBThread(%p)::GetStopDescription() => error: process is running", exe_ctx.GetThreadPtr()); 357c9858e4dSGreg Clayton } 3587fdf9ef1SGreg Clayton } 35930fdc8d8SChris Lattner if (dst) 36030fdc8d8SChris Lattner *dst = 0; 36130fdc8d8SChris Lattner return 0; 36230fdc8d8SChris Lattner } 36330fdc8d8SChris Lattner 36473ca05a2SJim Ingham SBValue 36573ca05a2SJim Ingham SBThread::GetStopReturnValue () 36673ca05a2SJim Ingham { 367c9858e4dSGreg Clayton LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); 36873ca05a2SJim Ingham ValueObjectSP return_valobj_sp; 3697fdf9ef1SGreg Clayton ExecutionContext exe_ctx (m_opaque_sp.get()); 3701ac04c30SGreg Clayton if (exe_ctx.HasThreadScope()) 37173ca05a2SJim Ingham { 3727fdf9ef1SGreg Clayton Process::StopLocker stop_locker; 3737fdf9ef1SGreg Clayton if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) 3747fdf9ef1SGreg Clayton { 3751ac04c30SGreg Clayton Mutex::Locker api_locker (exe_ctx.GetTargetPtr()->GetAPIMutex()); 3761ac04c30SGreg Clayton StopInfoSP stop_info_sp = exe_ctx.GetThreadPtr()->GetStopInfo (); 37773ca05a2SJim Ingham if (stop_info_sp) 37873ca05a2SJim Ingham { 37973ca05a2SJim Ingham return_valobj_sp = StopInfo::GetReturnValueObject (stop_info_sp); 38073ca05a2SJim Ingham } 38173ca05a2SJim Ingham } 382c9858e4dSGreg Clayton else 383c9858e4dSGreg Clayton { 384c9858e4dSGreg Clayton if (log) 385c9858e4dSGreg Clayton log->Printf ("SBThread(%p)::GetStopReturnValue() => error: process is running", exe_ctx.GetThreadPtr()); 386c9858e4dSGreg Clayton } 3877fdf9ef1SGreg Clayton } 38873ca05a2SJim Ingham 38973ca05a2SJim Ingham if (log) 3901ac04c30SGreg Clayton log->Printf ("SBThread(%p)::GetStopReturnValue () => %s", exe_ctx.GetThreadPtr(), 39173ca05a2SJim Ingham return_valobj_sp.get() 39273ca05a2SJim Ingham ? return_valobj_sp->GetValueAsCString() 39373ca05a2SJim Ingham : "<no return value>"); 39473ca05a2SJim Ingham 39573ca05a2SJim Ingham return SBValue (return_valobj_sp); 39673ca05a2SJim Ingham } 39773ca05a2SJim Ingham 39830fdc8d8SChris Lattner void 39930fdc8d8SChris Lattner SBThread::SetThread (const ThreadSP& lldb_object_sp) 40030fdc8d8SChris Lattner { 4017fdf9ef1SGreg Clayton m_opaque_sp->SetThreadSP (lldb_object_sp); 40230fdc8d8SChris Lattner } 40330fdc8d8SChris Lattner 40430fdc8d8SChris Lattner 40530fdc8d8SChris Lattner lldb::tid_t 40630fdc8d8SChris Lattner SBThread::GetThreadID () const 40730fdc8d8SChris Lattner { 4087fdf9ef1SGreg Clayton ThreadSP thread_sp(m_opaque_sp->GetThreadSP()); 40917a6ad05SGreg Clayton if (thread_sp) 4101ac04c30SGreg Clayton return thread_sp->GetID(); 4111ac04c30SGreg Clayton return LLDB_INVALID_THREAD_ID; 41230fdc8d8SChris Lattner } 41330fdc8d8SChris Lattner 41430fdc8d8SChris Lattner uint32_t 41530fdc8d8SChris Lattner SBThread::GetIndexID () const 41630fdc8d8SChris Lattner { 4177fdf9ef1SGreg Clayton ThreadSP thread_sp(m_opaque_sp->GetThreadSP()); 41817a6ad05SGreg Clayton if (thread_sp) 41917a6ad05SGreg Clayton return thread_sp->GetIndexID(); 42030fdc8d8SChris Lattner return LLDB_INVALID_INDEX32; 42130fdc8d8SChris Lattner } 4221ac04c30SGreg Clayton 42330fdc8d8SChris Lattner const char * 42430fdc8d8SChris Lattner SBThread::GetName () const 42530fdc8d8SChris Lattner { 426c9858e4dSGreg Clayton LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); 4274838131bSGreg Clayton const char *name = NULL; 4287fdf9ef1SGreg Clayton ExecutionContext exe_ctx (m_opaque_sp.get()); 4291ac04c30SGreg Clayton if (exe_ctx.HasThreadScope()) 430af67cecdSGreg Clayton { 4317fdf9ef1SGreg Clayton Process::StopLocker stop_locker; 4327fdf9ef1SGreg Clayton if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) 4337fdf9ef1SGreg Clayton { 4341ac04c30SGreg Clayton Mutex::Locker api_locker (exe_ctx.GetTargetPtr()->GetAPIMutex()); 4351ac04c30SGreg Clayton name = exe_ctx.GetThreadPtr()->GetName(); 436af67cecdSGreg Clayton } 437c9858e4dSGreg Clayton else 438c9858e4dSGreg Clayton { 439c9858e4dSGreg Clayton if (log) 440c9858e4dSGreg Clayton log->Printf ("SBThread(%p)::GetName() => error: process is running", exe_ctx.GetThreadPtr()); 441c9858e4dSGreg Clayton } 4427fdf9ef1SGreg Clayton } 443ceb6b139SCaroline Tice 444ceb6b139SCaroline Tice if (log) 4451ac04c30SGreg Clayton log->Printf ("SBThread(%p)::GetName () => %s", exe_ctx.GetThreadPtr(), name ? name : "NULL"); 446ceb6b139SCaroline Tice 4474838131bSGreg Clayton return name; 44830fdc8d8SChris Lattner } 44930fdc8d8SChris Lattner 45030fdc8d8SChris Lattner const char * 45130fdc8d8SChris Lattner SBThread::GetQueueName () const 45230fdc8d8SChris Lattner { 4534838131bSGreg Clayton const char *name = NULL; 4547fdf9ef1SGreg Clayton ExecutionContext exe_ctx (m_opaque_sp.get()); 455c9858e4dSGreg Clayton LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); 4561ac04c30SGreg Clayton if (exe_ctx.HasThreadScope()) 457af67cecdSGreg Clayton { 4587fdf9ef1SGreg Clayton Process::StopLocker stop_locker; 4597fdf9ef1SGreg Clayton if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) 4607fdf9ef1SGreg Clayton { 4611ac04c30SGreg Clayton Mutex::Locker api_locker (exe_ctx.GetTargetPtr()->GetAPIMutex()); 4621ac04c30SGreg Clayton name = exe_ctx.GetThreadPtr()->GetQueueName(); 463af67cecdSGreg Clayton } 464c9858e4dSGreg Clayton else 465c9858e4dSGreg Clayton { 466c9858e4dSGreg Clayton if (log) 467c9858e4dSGreg Clayton log->Printf ("SBThread(%p)::GetQueueName() => error: process is running", exe_ctx.GetThreadPtr()); 468c9858e4dSGreg Clayton } 4697fdf9ef1SGreg Clayton } 470ceb6b139SCaroline Tice 471ceb6b139SCaroline Tice if (log) 4721ac04c30SGreg Clayton log->Printf ("SBThread(%p)::GetQueueName () => %s", exe_ctx.GetThreadPtr(), name ? name : "NULL"); 473ceb6b139SCaroline Tice 4744838131bSGreg Clayton return name; 47530fdc8d8SChris Lattner } 47630fdc8d8SChris Lattner 477*64e7ead1SJim Ingham SBError 478*64e7ead1SJim Ingham SBThread::ResumeNewPlan (ExecutionContext &exe_ctx, ThreadPlan *new_plan) 479*64e7ead1SJim Ingham { 480*64e7ead1SJim Ingham SBError sb_error; 481*64e7ead1SJim Ingham 482*64e7ead1SJim Ingham Process *process = exe_ctx.GetProcessPtr(); 483*64e7ead1SJim Ingham if (!process) 484*64e7ead1SJim Ingham { 485*64e7ead1SJim Ingham sb_error.SetErrorString("No process in SBThread::ResumeNewPlan"); 486*64e7ead1SJim Ingham return sb_error; 487*64e7ead1SJim Ingham } 488*64e7ead1SJim Ingham 489*64e7ead1SJim Ingham Thread *thread = exe_ctx.GetThreadPtr(); 490*64e7ead1SJim Ingham if (!thread) 491*64e7ead1SJim Ingham { 492*64e7ead1SJim Ingham sb_error.SetErrorString("No thread in SBThread::ResumeNewPlan"); 493*64e7ead1SJim Ingham return sb_error; 494*64e7ead1SJim Ingham } 495*64e7ead1SJim Ingham 496*64e7ead1SJim Ingham // User level plans should be Master Plans so they can be interrupted, other plans executed, and 497*64e7ead1SJim Ingham // then a "continue" will resume the plan. 498*64e7ead1SJim Ingham if (new_plan != NULL) 499*64e7ead1SJim Ingham { 500*64e7ead1SJim Ingham new_plan->SetIsMasterPlan(true); 501*64e7ead1SJim Ingham new_plan->SetOkayToDiscard(false); 502*64e7ead1SJim Ingham } 503*64e7ead1SJim Ingham 504*64e7ead1SJim Ingham // Why do we need to set the current thread by ID here??? 505*64e7ead1SJim Ingham process->GetThreadList().SetSelectedThreadByID (thread->GetID()); 506*64e7ead1SJim Ingham sb_error.ref() = process->Resume(); 507*64e7ead1SJim Ingham 508*64e7ead1SJim Ingham if (sb_error.Success()) 509*64e7ead1SJim Ingham { 510*64e7ead1SJim Ingham // If we are doing synchronous mode, then wait for the 511*64e7ead1SJim Ingham // process to stop yet again! 512*64e7ead1SJim Ingham if (process->GetTarget().GetDebugger().GetAsyncExecution () == false) 513*64e7ead1SJim Ingham process->WaitForProcessToStop (NULL); 514*64e7ead1SJim Ingham } 515*64e7ead1SJim Ingham 516*64e7ead1SJim Ingham return sb_error; 517*64e7ead1SJim Ingham } 51830fdc8d8SChris Lattner 51930fdc8d8SChris Lattner void 52030fdc8d8SChris Lattner SBThread::StepOver (lldb::RunMode stop_other_threads) 52130fdc8d8SChris Lattner { 5222d4edfbcSGreg Clayton LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); 523ceb6b139SCaroline Tice 5247fdf9ef1SGreg Clayton ExecutionContext exe_ctx (m_opaque_sp.get()); 52517a6ad05SGreg Clayton 526ceb6b139SCaroline Tice if (log) 5271ac04c30SGreg Clayton log->Printf ("SBThread(%p)::StepOver (stop_other_threads='%s')", exe_ctx.GetThreadPtr(), 528ceb6b139SCaroline Tice Thread::RunModeAsCString (stop_other_threads)); 529ceb6b139SCaroline Tice 5301ac04c30SGreg Clayton if (exe_ctx.HasThreadScope()) 53130fdc8d8SChris Lattner { 5321ac04c30SGreg Clayton Mutex::Locker api_locker (exe_ctx.GetTargetPtr()->GetAPIMutex()); 5331ac04c30SGreg Clayton Thread *thread = exe_ctx.GetThreadPtr(); 53430fdc8d8SChris Lattner bool abort_other_plans = true; 5351ac04c30SGreg Clayton StackFrameSP frame_sp(thread->GetStackFrameAtIndex (0)); 536*64e7ead1SJim Ingham ThreadPlan *new_plan = NULL; 53730fdc8d8SChris Lattner 53830fdc8d8SChris Lattner if (frame_sp) 53930fdc8d8SChris Lattner { 54030fdc8d8SChris Lattner if (frame_sp->HasDebugInformation ()) 54130fdc8d8SChris Lattner { 54230fdc8d8SChris Lattner SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything)); 543*64e7ead1SJim Ingham new_plan = thread->QueueThreadPlanForStepRange (abort_other_plans, 54430fdc8d8SChris Lattner eStepTypeOver, 54530fdc8d8SChris Lattner sc.line_entry.range, 54630fdc8d8SChris Lattner sc, 547474966a4SGreg Clayton stop_other_threads, 548474966a4SGreg Clayton false); 54930fdc8d8SChris Lattner 55030fdc8d8SChris Lattner } 55130fdc8d8SChris Lattner else 55230fdc8d8SChris Lattner { 553*64e7ead1SJim Ingham new_plan = thread->QueueThreadPlanForStepSingleInstruction (true, 55430fdc8d8SChris Lattner abort_other_plans, 55530fdc8d8SChris Lattner stop_other_threads); 55630fdc8d8SChris Lattner } 55730fdc8d8SChris Lattner } 55830fdc8d8SChris Lattner 559*64e7ead1SJim Ingham // This returns an error, we should use it! 560*64e7ead1SJim Ingham ResumeNewPlan (exe_ctx, new_plan); 56130fdc8d8SChris Lattner } 56230fdc8d8SChris Lattner } 56330fdc8d8SChris Lattner 56430fdc8d8SChris Lattner void 56530fdc8d8SChris Lattner SBThread::StepInto (lldb::RunMode stop_other_threads) 56630fdc8d8SChris Lattner { 5672d4edfbcSGreg Clayton LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); 568ceb6b139SCaroline Tice 5697fdf9ef1SGreg Clayton ExecutionContext exe_ctx (m_opaque_sp.get()); 57017a6ad05SGreg Clayton 57117a6ad05SGreg Clayton if (log) 5721ac04c30SGreg Clayton log->Printf ("SBThread(%p)::StepInto (stop_other_threads='%s')", exe_ctx.GetThreadPtr(), 57317a6ad05SGreg Clayton Thread::RunModeAsCString (stop_other_threads)); 5741ac04c30SGreg Clayton if (exe_ctx.HasThreadScope()) 57530fdc8d8SChris Lattner { 5761ac04c30SGreg Clayton Mutex::Locker api_locker (exe_ctx.GetTargetPtr()->GetAPIMutex()); 57730fdc8d8SChris Lattner bool abort_other_plans = true; 57830fdc8d8SChris Lattner 5791ac04c30SGreg Clayton Thread *thread = exe_ctx.GetThreadPtr(); 5801ac04c30SGreg Clayton StackFrameSP frame_sp(thread->GetStackFrameAtIndex (0)); 581*64e7ead1SJim Ingham ThreadPlan *new_plan = NULL; 58230fdc8d8SChris Lattner 58330fdc8d8SChris Lattner if (frame_sp && frame_sp->HasDebugInformation ()) 58430fdc8d8SChris Lattner { 585474966a4SGreg Clayton bool avoid_code_without_debug_info = true; 58630fdc8d8SChris Lattner SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything)); 587*64e7ead1SJim Ingham new_plan = thread->QueueThreadPlanForStepRange (abort_other_plans, 58830fdc8d8SChris Lattner eStepTypeInto, 58930fdc8d8SChris Lattner sc.line_entry.range, 59030fdc8d8SChris Lattner sc, 591474966a4SGreg Clayton stop_other_threads, 592474966a4SGreg Clayton avoid_code_without_debug_info); 59330fdc8d8SChris Lattner } 59430fdc8d8SChris Lattner else 59530fdc8d8SChris Lattner { 596*64e7ead1SJim Ingham new_plan = thread->QueueThreadPlanForStepSingleInstruction (false, 59730fdc8d8SChris Lattner abort_other_plans, 59830fdc8d8SChris Lattner stop_other_threads); 59930fdc8d8SChris Lattner } 60030fdc8d8SChris Lattner 601*64e7ead1SJim Ingham // This returns an error, we should use it! 602*64e7ead1SJim Ingham ResumeNewPlan (exe_ctx, new_plan); 60330fdc8d8SChris Lattner } 60430fdc8d8SChris Lattner } 60530fdc8d8SChris Lattner 60630fdc8d8SChris Lattner void 60730fdc8d8SChris Lattner SBThread::StepOut () 60830fdc8d8SChris Lattner { 6092d4edfbcSGreg Clayton LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); 610ceb6b139SCaroline Tice 6117fdf9ef1SGreg Clayton ExecutionContext exe_ctx (m_opaque_sp.get()); 612ceb6b139SCaroline Tice 61317a6ad05SGreg Clayton if (log) 6141ac04c30SGreg Clayton log->Printf ("SBThread(%p)::StepOut ()", exe_ctx.GetThreadPtr()); 61517a6ad05SGreg Clayton 6161ac04c30SGreg Clayton if (exe_ctx.HasThreadScope()) 61730fdc8d8SChris Lattner { 6181ac04c30SGreg Clayton Mutex::Locker api_locker (exe_ctx.GetTargetPtr()->GetAPIMutex()); 61930fdc8d8SChris Lattner bool abort_other_plans = true; 62030fdc8d8SChris Lattner bool stop_other_threads = true; 62130fdc8d8SChris Lattner 6221ac04c30SGreg Clayton Thread *thread = exe_ctx.GetThreadPtr(); 6231ac04c30SGreg Clayton 624*64e7ead1SJim Ingham ThreadPlan *new_plan = thread->QueueThreadPlanForStepOut (abort_other_plans, 625481cef25SGreg Clayton NULL, 626481cef25SGreg Clayton false, 627481cef25SGreg Clayton stop_other_threads, 628481cef25SGreg Clayton eVoteYes, 629481cef25SGreg Clayton eVoteNoOpinion, 630481cef25SGreg Clayton 0); 631481cef25SGreg Clayton 632*64e7ead1SJim Ingham // This returns an error, we should use it! 633*64e7ead1SJim Ingham ResumeNewPlan (exe_ctx, new_plan); 634481cef25SGreg Clayton } 635481cef25SGreg Clayton } 636481cef25SGreg Clayton 637481cef25SGreg Clayton void 638481cef25SGreg Clayton SBThread::StepOutOfFrame (lldb::SBFrame &sb_frame) 639481cef25SGreg Clayton { 640481cef25SGreg Clayton LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); 641481cef25SGreg Clayton 6427fdf9ef1SGreg Clayton ExecutionContext exe_ctx (m_opaque_sp.get()); 643b9556accSGreg Clayton StackFrameSP frame_sp (sb_frame.GetFrameSP()); 644481cef25SGreg Clayton if (log) 645481cef25SGreg Clayton { 646481cef25SGreg Clayton SBStream frame_desc_strm; 647481cef25SGreg Clayton sb_frame.GetDescription (frame_desc_strm); 6481ac04c30SGreg Clayton log->Printf ("SBThread(%p)::StepOutOfFrame (frame = SBFrame(%p): %s)", exe_ctx.GetThreadPtr(), frame_sp.get(), frame_desc_strm.GetData()); 649481cef25SGreg Clayton } 650481cef25SGreg Clayton 6511ac04c30SGreg Clayton if (exe_ctx.HasThreadScope()) 652481cef25SGreg Clayton { 6531ac04c30SGreg Clayton Mutex::Locker api_locker (exe_ctx.GetTargetPtr()->GetAPIMutex()); 654481cef25SGreg Clayton bool abort_other_plans = true; 655481cef25SGreg Clayton bool stop_other_threads = true; 6561ac04c30SGreg Clayton Thread *thread = exe_ctx.GetThreadPtr(); 657481cef25SGreg Clayton 658*64e7ead1SJim Ingham ThreadPlan *new_plan = thread->QueueThreadPlanForStepOut (abort_other_plans, 659481cef25SGreg Clayton NULL, 660481cef25SGreg Clayton false, 661481cef25SGreg Clayton stop_other_threads, 662481cef25SGreg Clayton eVoteYes, 663481cef25SGreg Clayton eVoteNoOpinion, 664b9556accSGreg Clayton frame_sp->GetFrameIndex()); 66530fdc8d8SChris Lattner 666*64e7ead1SJim Ingham // This returns an error, we should use it! 667*64e7ead1SJim Ingham ResumeNewPlan (exe_ctx, new_plan); 66830fdc8d8SChris Lattner } 66930fdc8d8SChris Lattner } 67030fdc8d8SChris Lattner 67130fdc8d8SChris Lattner void 67230fdc8d8SChris Lattner SBThread::StepInstruction (bool step_over) 67330fdc8d8SChris Lattner { 6742d4edfbcSGreg Clayton LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); 675ceb6b139SCaroline Tice 6767fdf9ef1SGreg Clayton ExecutionContext exe_ctx (m_opaque_sp.get()); 6771ac04c30SGreg Clayton 678ceb6b139SCaroline Tice 67917a6ad05SGreg Clayton if (log) 6801ac04c30SGreg Clayton log->Printf ("SBThread(%p)::StepInstruction (step_over=%i)", exe_ctx.GetThreadPtr(), step_over); 68117a6ad05SGreg Clayton 6821ac04c30SGreg Clayton if (exe_ctx.HasThreadScope()) 68330fdc8d8SChris Lattner { 6841ac04c30SGreg Clayton Mutex::Locker api_locker (exe_ctx.GetTargetPtr()->GetAPIMutex()); 6851ac04c30SGreg Clayton Thread *thread = exe_ctx.GetThreadPtr(); 686*64e7ead1SJim Ingham ThreadPlan *new_plan = thread->QueueThreadPlanForStepSingleInstruction (step_over, true, true); 687*64e7ead1SJim Ingham 688*64e7ead1SJim Ingham // This returns an error, we should use it! 689*64e7ead1SJim Ingham ResumeNewPlan (exe_ctx, new_plan); 69030fdc8d8SChris Lattner } 69130fdc8d8SChris Lattner } 69230fdc8d8SChris Lattner 69330fdc8d8SChris Lattner void 69430fdc8d8SChris Lattner SBThread::RunToAddress (lldb::addr_t addr) 69530fdc8d8SChris Lattner { 6962d4edfbcSGreg Clayton LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); 697ceb6b139SCaroline Tice 6987fdf9ef1SGreg Clayton ExecutionContext exe_ctx (m_opaque_sp.get()); 699ceb6b139SCaroline Tice 70017a6ad05SGreg Clayton if (log) 7011ac04c30SGreg Clayton log->Printf ("SBThread(%p)::RunToAddress (addr=0x%llx)", exe_ctx.GetThreadPtr(), addr); 70217a6ad05SGreg Clayton 7031ac04c30SGreg Clayton if (exe_ctx.HasThreadScope()) 70430fdc8d8SChris Lattner { 7051ac04c30SGreg Clayton Mutex::Locker api_locker (exe_ctx.GetTargetPtr()->GetAPIMutex()); 70630fdc8d8SChris Lattner bool abort_other_plans = true; 70730fdc8d8SChris Lattner bool stop_other_threads = true; 70830fdc8d8SChris Lattner 709e72dfb32SGreg Clayton Address target_addr (addr); 71030fdc8d8SChris Lattner 7111ac04c30SGreg Clayton Thread *thread = exe_ctx.GetThreadPtr(); 7121ac04c30SGreg Clayton 713*64e7ead1SJim Ingham ThreadPlan *new_plan = thread->QueueThreadPlanForRunToAddress (abort_other_plans, target_addr, stop_other_threads); 714*64e7ead1SJim Ingham 715*64e7ead1SJim Ingham // This returns an error, we should use it! 716*64e7ead1SJim Ingham ResumeNewPlan (exe_ctx, new_plan); 71730fdc8d8SChris Lattner } 71830fdc8d8SChris Lattner } 71930fdc8d8SChris Lattner 720481cef25SGreg Clayton SBError 721481cef25SGreg Clayton SBThread::StepOverUntil (lldb::SBFrame &sb_frame, 722481cef25SGreg Clayton lldb::SBFileSpec &sb_file_spec, 723481cef25SGreg Clayton uint32_t line) 724481cef25SGreg Clayton { 725481cef25SGreg Clayton SBError sb_error; 726481cef25SGreg Clayton LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); 727481cef25SGreg Clayton char path[PATH_MAX]; 728481cef25SGreg Clayton 7297fdf9ef1SGreg Clayton ExecutionContext exe_ctx (m_opaque_sp.get()); 730b9556accSGreg Clayton StackFrameSP frame_sp (sb_frame.GetFrameSP()); 73117a6ad05SGreg Clayton 732481cef25SGreg Clayton if (log) 733481cef25SGreg Clayton { 734481cef25SGreg Clayton SBStream frame_desc_strm; 735481cef25SGreg Clayton sb_frame.GetDescription (frame_desc_strm); 736481cef25SGreg Clayton sb_file_spec->GetPath (path, sizeof(path)); 737481cef25SGreg Clayton log->Printf ("SBThread(%p)::StepOverUntil (frame = SBFrame(%p): %s, file+line = %s:%u)", 7381ac04c30SGreg Clayton exe_ctx.GetThreadPtr(), 739b9556accSGreg Clayton frame_sp.get(), 740481cef25SGreg Clayton frame_desc_strm.GetData(), 741481cef25SGreg Clayton path, line); 742481cef25SGreg Clayton } 743481cef25SGreg Clayton 7441ac04c30SGreg Clayton if (exe_ctx.HasThreadScope()) 745481cef25SGreg Clayton { 7461ac04c30SGreg Clayton Target *target = exe_ctx.GetTargetPtr(); 7471ac04c30SGreg Clayton Mutex::Locker api_locker (target->GetAPIMutex()); 7481ac04c30SGreg Clayton Thread *thread = exe_ctx.GetThreadPtr(); 749481cef25SGreg Clayton 750481cef25SGreg Clayton if (line == 0) 751481cef25SGreg Clayton { 752481cef25SGreg Clayton sb_error.SetErrorString("invalid line argument"); 753481cef25SGreg Clayton return sb_error; 754481cef25SGreg Clayton } 755481cef25SGreg Clayton 756481cef25SGreg Clayton StackFrameSP frame_sp; 757b9556accSGreg Clayton if (!frame_sp) 758481cef25SGreg Clayton { 7591ac04c30SGreg Clayton frame_sp = thread->GetSelectedFrame (); 760481cef25SGreg Clayton if (!frame_sp) 7611ac04c30SGreg Clayton frame_sp = thread->GetStackFrameAtIndex (0); 762481cef25SGreg Clayton } 763481cef25SGreg Clayton 764481cef25SGreg Clayton SymbolContext frame_sc; 765481cef25SGreg Clayton if (!frame_sp) 766481cef25SGreg Clayton { 767481cef25SGreg Clayton sb_error.SetErrorString("no valid frames in thread to step"); 768481cef25SGreg Clayton return sb_error; 769481cef25SGreg Clayton } 770481cef25SGreg Clayton 771481cef25SGreg Clayton // If we have a frame, get its line 772481cef25SGreg Clayton frame_sc = frame_sp->GetSymbolContext (eSymbolContextCompUnit | 773481cef25SGreg Clayton eSymbolContextFunction | 774481cef25SGreg Clayton eSymbolContextLineEntry | 775481cef25SGreg Clayton eSymbolContextSymbol ); 776481cef25SGreg Clayton 777481cef25SGreg Clayton if (frame_sc.comp_unit == NULL) 778481cef25SGreg Clayton { 779481cef25SGreg Clayton sb_error.SetErrorStringWithFormat("frame %u doesn't have debug information", frame_sp->GetFrameIndex()); 780481cef25SGreg Clayton return sb_error; 781481cef25SGreg Clayton } 782481cef25SGreg Clayton 783481cef25SGreg Clayton FileSpec step_file_spec; 784481cef25SGreg Clayton if (sb_file_spec.IsValid()) 785481cef25SGreg Clayton { 786481cef25SGreg Clayton // The file spec passed in was valid, so use it 787481cef25SGreg Clayton step_file_spec = sb_file_spec.ref(); 788481cef25SGreg Clayton } 789481cef25SGreg Clayton else 790481cef25SGreg Clayton { 791481cef25SGreg Clayton if (frame_sc.line_entry.IsValid()) 792481cef25SGreg Clayton step_file_spec = frame_sc.line_entry.file; 793481cef25SGreg Clayton else 794481cef25SGreg Clayton { 795481cef25SGreg Clayton sb_error.SetErrorString("invalid file argument or no file for frame"); 796481cef25SGreg Clayton return sb_error; 797481cef25SGreg Clayton } 798481cef25SGreg Clayton } 799481cef25SGreg Clayton 8009b70ddb3SJim Ingham // Grab the current function, then we will make sure the "until" address is 8019b70ddb3SJim Ingham // within the function. We discard addresses that are out of the current 8029b70ddb3SJim Ingham // function, and then if there are no addresses remaining, give an appropriate 8039b70ddb3SJim Ingham // error message. 8049b70ddb3SJim Ingham 8059b70ddb3SJim Ingham bool all_in_function = true; 8069b70ddb3SJim Ingham AddressRange fun_range = frame_sc.function->GetAddressRange(); 8079b70ddb3SJim Ingham 808481cef25SGreg Clayton std::vector<addr_t> step_over_until_addrs; 809481cef25SGreg Clayton const bool abort_other_plans = true; 810481cef25SGreg Clayton const bool stop_other_threads = true; 811481cef25SGreg Clayton const bool check_inlines = true; 812481cef25SGreg Clayton const bool exact = false; 813481cef25SGreg Clayton 814481cef25SGreg Clayton SymbolContextList sc_list; 8159b70ddb3SJim Ingham const uint32_t num_matches = frame_sc.comp_unit->ResolveSymbolContext (step_file_spec, 8169b70ddb3SJim Ingham line, 8179b70ddb3SJim Ingham check_inlines, 8189b70ddb3SJim Ingham exact, 8199b70ddb3SJim Ingham eSymbolContextLineEntry, 8209b70ddb3SJim Ingham sc_list); 821481cef25SGreg Clayton if (num_matches > 0) 822481cef25SGreg Clayton { 823481cef25SGreg Clayton SymbolContext sc; 824481cef25SGreg Clayton for (uint32_t i=0; i<num_matches; ++i) 825481cef25SGreg Clayton { 826481cef25SGreg Clayton if (sc_list.GetContextAtIndex(i, sc)) 827481cef25SGreg Clayton { 8289b70ddb3SJim Ingham addr_t step_addr = sc.line_entry.range.GetBaseAddress().GetLoadAddress(target); 829481cef25SGreg Clayton if (step_addr != LLDB_INVALID_ADDRESS) 830481cef25SGreg Clayton { 8319b70ddb3SJim Ingham if (fun_range.ContainsLoadAddress(step_addr, target)) 832481cef25SGreg Clayton step_over_until_addrs.push_back(step_addr); 8339b70ddb3SJim Ingham else 8349b70ddb3SJim Ingham all_in_function = false; 835481cef25SGreg Clayton } 836481cef25SGreg Clayton } 837481cef25SGreg Clayton } 838481cef25SGreg Clayton } 839481cef25SGreg Clayton 840481cef25SGreg Clayton if (step_over_until_addrs.empty()) 841481cef25SGreg Clayton { 8429b70ddb3SJim Ingham if (all_in_function) 8439b70ddb3SJim Ingham { 844481cef25SGreg Clayton step_file_spec.GetPath (path, sizeof(path)); 845fd54b368SJason Molenda sb_error.SetErrorStringWithFormat("No line entries for %s:%u", path, line); 846481cef25SGreg Clayton } 847481cef25SGreg Clayton else 84886edbf41SGreg Clayton sb_error.SetErrorString ("step until target not in current function"); 8499b70ddb3SJim Ingham } 8509b70ddb3SJim Ingham else 851481cef25SGreg Clayton { 852*64e7ead1SJim Ingham ThreadPlan *new_plan = thread->QueueThreadPlanForStepUntil (abort_other_plans, 853481cef25SGreg Clayton &step_over_until_addrs[0], 854481cef25SGreg Clayton step_over_until_addrs.size(), 855481cef25SGreg Clayton stop_other_threads, 856481cef25SGreg Clayton frame_sp->GetFrameIndex()); 857481cef25SGreg Clayton 858*64e7ead1SJim Ingham sb_error = ResumeNewPlan (exe_ctx, new_plan); 859481cef25SGreg Clayton } 860481cef25SGreg Clayton } 861481cef25SGreg Clayton else 862481cef25SGreg Clayton { 863481cef25SGreg Clayton sb_error.SetErrorString("this SBThread object is invalid"); 864481cef25SGreg Clayton } 865481cef25SGreg Clayton return sb_error; 866481cef25SGreg Clayton } 867481cef25SGreg Clayton 868481cef25SGreg Clayton 869722a0cdcSGreg Clayton bool 870722a0cdcSGreg Clayton SBThread::Suspend() 871722a0cdcSGreg Clayton { 872c9858e4dSGreg Clayton LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); 8737fdf9ef1SGreg Clayton ExecutionContext exe_ctx (m_opaque_sp.get()); 874c9858e4dSGreg Clayton bool result = false; 8751ac04c30SGreg Clayton if (exe_ctx.HasThreadScope()) 876722a0cdcSGreg Clayton { 877c9858e4dSGreg Clayton Process::StopLocker stop_locker; 878c9858e4dSGreg Clayton if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) 879c9858e4dSGreg Clayton { 8801ac04c30SGreg Clayton exe_ctx.GetThreadPtr()->SetResumeState (eStateSuspended); 881c9858e4dSGreg Clayton result = true; 882722a0cdcSGreg Clayton } 883c9858e4dSGreg Clayton else 884c9858e4dSGreg Clayton { 885c9858e4dSGreg Clayton if (log) 886c9858e4dSGreg Clayton log->Printf ("SBThread(%p)::Suspend() => error: process is running", exe_ctx.GetThreadPtr()); 887c9858e4dSGreg Clayton } 888c9858e4dSGreg Clayton } 889c9858e4dSGreg Clayton if (log) 890c9858e4dSGreg Clayton log->Printf ("SBThread(%p)::Suspend() => %i", exe_ctx.GetThreadPtr(), result); 891c9858e4dSGreg Clayton return result; 892722a0cdcSGreg Clayton } 893722a0cdcSGreg Clayton 894722a0cdcSGreg Clayton bool 895722a0cdcSGreg Clayton SBThread::Resume () 896722a0cdcSGreg Clayton { 897c9858e4dSGreg Clayton LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); 8987fdf9ef1SGreg Clayton ExecutionContext exe_ctx (m_opaque_sp.get()); 899c9858e4dSGreg Clayton bool result = false; 9001ac04c30SGreg Clayton if (exe_ctx.HasThreadScope()) 901722a0cdcSGreg Clayton { 902c9858e4dSGreg Clayton Process::StopLocker stop_locker; 903c9858e4dSGreg Clayton if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) 904c9858e4dSGreg Clayton { 9051ac04c30SGreg Clayton exe_ctx.GetThreadPtr()->SetResumeState (eStateRunning); 906c9858e4dSGreg Clayton result = true; 907722a0cdcSGreg Clayton } 908c9858e4dSGreg Clayton else 909c9858e4dSGreg Clayton { 910c9858e4dSGreg Clayton if (log) 911c9858e4dSGreg Clayton log->Printf ("SBThread(%p)::Resume() => error: process is running", exe_ctx.GetThreadPtr()); 912c9858e4dSGreg Clayton } 913c9858e4dSGreg Clayton } 914c9858e4dSGreg Clayton if (log) 915c9858e4dSGreg Clayton log->Printf ("SBThread(%p)::Resume() => %i", exe_ctx.GetThreadPtr(), result); 916c9858e4dSGreg Clayton return result; 917722a0cdcSGreg Clayton } 918722a0cdcSGreg Clayton 919722a0cdcSGreg Clayton bool 920722a0cdcSGreg Clayton SBThread::IsSuspended() 921722a0cdcSGreg Clayton { 9227fdf9ef1SGreg Clayton ExecutionContext exe_ctx (m_opaque_sp.get()); 9231ac04c30SGreg Clayton if (exe_ctx.HasThreadScope()) 9241ac04c30SGreg Clayton return exe_ctx.GetThreadPtr()->GetResumeState () == eStateSuspended; 925722a0cdcSGreg Clayton return false; 926722a0cdcSGreg Clayton } 927722a0cdcSGreg Clayton 92830fdc8d8SChris Lattner SBProcess 92930fdc8d8SChris Lattner SBThread::GetProcess () 93030fdc8d8SChris Lattner { 931ceb6b139SCaroline Tice 932b9556accSGreg Clayton SBProcess sb_process; 933b9556accSGreg Clayton ProcessSP process_sp; 9347fdf9ef1SGreg Clayton ExecutionContext exe_ctx (m_opaque_sp.get()); 9351ac04c30SGreg Clayton if (exe_ctx.HasThreadScope()) 93630fdc8d8SChris Lattner { 93730fdc8d8SChris Lattner // Have to go up to the target so we can get a shared pointer to our process... 9381ac04c30SGreg Clayton sb_process.SetSP (exe_ctx.GetProcessSP()); 93930fdc8d8SChris Lattner } 940ceb6b139SCaroline Tice 9412d4edfbcSGreg Clayton LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); 942ceb6b139SCaroline Tice if (log) 943ceb6b139SCaroline Tice { 944481cef25SGreg Clayton SBStream frame_desc_strm; 945b9556accSGreg Clayton sb_process.GetDescription (frame_desc_strm); 9461ac04c30SGreg Clayton log->Printf ("SBThread(%p)::GetProcess () => SBProcess(%p): %s", exe_ctx.GetThreadPtr(), 947b9556accSGreg Clayton process_sp.get(), frame_desc_strm.GetData()); 948ceb6b139SCaroline Tice } 949ceb6b139SCaroline Tice 950b9556accSGreg Clayton return sb_process; 95130fdc8d8SChris Lattner } 95230fdc8d8SChris Lattner 95330fdc8d8SChris Lattner uint32_t 95430fdc8d8SChris Lattner SBThread::GetNumFrames () 95530fdc8d8SChris Lattner { 9562d4edfbcSGreg Clayton LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); 957ceb6b139SCaroline Tice 958ceb6b139SCaroline Tice uint32_t num_frames = 0; 9597fdf9ef1SGreg Clayton ExecutionContext exe_ctx (m_opaque_sp.get()); 9601ac04c30SGreg Clayton if (exe_ctx.HasThreadScope()) 961af67cecdSGreg Clayton { 9627fdf9ef1SGreg Clayton Process::StopLocker stop_locker; 9637fdf9ef1SGreg Clayton if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) 9647fdf9ef1SGreg Clayton { 9651ac04c30SGreg Clayton Mutex::Locker api_locker (exe_ctx.GetTargetPtr()->GetAPIMutex()); 9661ac04c30SGreg Clayton num_frames = exe_ctx.GetThreadPtr()->GetStackFrameCount(); 967af67cecdSGreg Clayton } 968c9858e4dSGreg Clayton else 969c9858e4dSGreg Clayton { 970c9858e4dSGreg Clayton if (log) 971c9858e4dSGreg Clayton log->Printf ("SBThread(%p)::GetNumFrames() => error: process is running", exe_ctx.GetThreadPtr()); 972c9858e4dSGreg Clayton } 9737fdf9ef1SGreg Clayton } 974ceb6b139SCaroline Tice 975ceb6b139SCaroline Tice if (log) 9761ac04c30SGreg Clayton log->Printf ("SBThread(%p)::GetNumFrames () => %u", exe_ctx.GetThreadPtr(), num_frames); 977ceb6b139SCaroline Tice 978ceb6b139SCaroline Tice return num_frames; 97930fdc8d8SChris Lattner } 98030fdc8d8SChris Lattner 98130fdc8d8SChris Lattner SBFrame 98230fdc8d8SChris Lattner SBThread::GetFrameAtIndex (uint32_t idx) 98330fdc8d8SChris Lattner { 9842d4edfbcSGreg Clayton LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); 985ceb6b139SCaroline Tice 98630fdc8d8SChris Lattner SBFrame sb_frame; 987b9556accSGreg Clayton StackFrameSP frame_sp; 9887fdf9ef1SGreg Clayton ExecutionContext exe_ctx (m_opaque_sp.get()); 9891ac04c30SGreg Clayton if (exe_ctx.HasThreadScope()) 990af67cecdSGreg Clayton { 9917fdf9ef1SGreg Clayton Process::StopLocker stop_locker; 9927fdf9ef1SGreg Clayton if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) 9937fdf9ef1SGreg Clayton { 9941ac04c30SGreg Clayton Mutex::Locker api_locker (exe_ctx.GetTargetPtr()->GetAPIMutex()); 9951ac04c30SGreg Clayton frame_sp = exe_ctx.GetThreadPtr()->GetStackFrameAtIndex (idx); 996b9556accSGreg Clayton sb_frame.SetFrameSP (frame_sp); 997af67cecdSGreg Clayton } 998c9858e4dSGreg Clayton else 999c9858e4dSGreg Clayton { 1000c9858e4dSGreg Clayton if (log) 1001c9858e4dSGreg Clayton log->Printf ("SBThread(%p)::GetFrameAtIndex() => error: process is running", exe_ctx.GetThreadPtr()); 1002c9858e4dSGreg Clayton } 10037fdf9ef1SGreg Clayton } 1004ceb6b139SCaroline Tice 1005ceb6b139SCaroline Tice if (log) 1006ceb6b139SCaroline Tice { 1007481cef25SGreg Clayton SBStream frame_desc_strm; 1008481cef25SGreg Clayton sb_frame.GetDescription (frame_desc_strm); 10094838131bSGreg Clayton log->Printf ("SBThread(%p)::GetFrameAtIndex (idx=%d) => SBFrame(%p): %s", 10101ac04c30SGreg Clayton exe_ctx.GetThreadPtr(), idx, frame_sp.get(), frame_desc_strm.GetData()); 1011ceb6b139SCaroline Tice } 1012ceb6b139SCaroline Tice 101330fdc8d8SChris Lattner return sb_frame; 101430fdc8d8SChris Lattner } 101530fdc8d8SChris Lattner 1016f028a1fbSGreg Clayton lldb::SBFrame 1017f028a1fbSGreg Clayton SBThread::GetSelectedFrame () 1018f028a1fbSGreg Clayton { 1019f028a1fbSGreg Clayton LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); 1020f028a1fbSGreg Clayton 1021f028a1fbSGreg Clayton SBFrame sb_frame; 1022b9556accSGreg Clayton StackFrameSP frame_sp; 10237fdf9ef1SGreg Clayton ExecutionContext exe_ctx (m_opaque_sp.get()); 10241ac04c30SGreg Clayton if (exe_ctx.HasThreadScope()) 1025af67cecdSGreg Clayton { 10267fdf9ef1SGreg Clayton Process::StopLocker stop_locker; 10277fdf9ef1SGreg Clayton if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) 10287fdf9ef1SGreg Clayton { 10291ac04c30SGreg Clayton Mutex::Locker api_locker (exe_ctx.GetTargetPtr()->GetAPIMutex()); 10301ac04c30SGreg Clayton frame_sp = exe_ctx.GetThreadPtr()->GetSelectedFrame (); 1031b9556accSGreg Clayton sb_frame.SetFrameSP (frame_sp); 1032af67cecdSGreg Clayton } 1033c9858e4dSGreg Clayton else 1034c9858e4dSGreg Clayton { 1035c9858e4dSGreg Clayton if (log) 1036c9858e4dSGreg Clayton log->Printf ("SBThread(%p)::GetSelectedFrame() => error: process is running", exe_ctx.GetThreadPtr()); 1037c9858e4dSGreg Clayton } 10387fdf9ef1SGreg Clayton } 1039f028a1fbSGreg Clayton 1040f028a1fbSGreg Clayton if (log) 1041f028a1fbSGreg Clayton { 1042481cef25SGreg Clayton SBStream frame_desc_strm; 1043481cef25SGreg Clayton sb_frame.GetDescription (frame_desc_strm); 1044f028a1fbSGreg Clayton log->Printf ("SBThread(%p)::GetSelectedFrame () => SBFrame(%p): %s", 10451ac04c30SGreg Clayton exe_ctx.GetThreadPtr(), frame_sp.get(), frame_desc_strm.GetData()); 1046f028a1fbSGreg Clayton } 1047f028a1fbSGreg Clayton 1048f028a1fbSGreg Clayton return sb_frame; 1049f028a1fbSGreg Clayton } 1050f028a1fbSGreg Clayton 1051f028a1fbSGreg Clayton lldb::SBFrame 1052f028a1fbSGreg Clayton SBThread::SetSelectedFrame (uint32_t idx) 1053f028a1fbSGreg Clayton { 1054f028a1fbSGreg Clayton LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); 1055f028a1fbSGreg Clayton 1056f028a1fbSGreg Clayton SBFrame sb_frame; 1057b9556accSGreg Clayton StackFrameSP frame_sp; 10587fdf9ef1SGreg Clayton ExecutionContext exe_ctx (m_opaque_sp.get()); 10591ac04c30SGreg Clayton if (exe_ctx.HasThreadScope()) 1060f028a1fbSGreg Clayton { 10617fdf9ef1SGreg Clayton Process::StopLocker stop_locker; 10627fdf9ef1SGreg Clayton if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) 10637fdf9ef1SGreg Clayton { 10641ac04c30SGreg Clayton Mutex::Locker api_locker (exe_ctx.GetTargetPtr()->GetAPIMutex()); 10651ac04c30SGreg Clayton Thread *thread = exe_ctx.GetThreadPtr(); 10661ac04c30SGreg Clayton frame_sp = thread->GetStackFrameAtIndex (idx); 1067f028a1fbSGreg Clayton if (frame_sp) 1068f028a1fbSGreg Clayton { 10691ac04c30SGreg Clayton thread->SetSelectedFrame (frame_sp.get()); 1070b9556accSGreg Clayton sb_frame.SetFrameSP (frame_sp); 1071f028a1fbSGreg Clayton } 1072f028a1fbSGreg Clayton } 1073c9858e4dSGreg Clayton else 1074c9858e4dSGreg Clayton { 1075c9858e4dSGreg Clayton if (log) 1076c9858e4dSGreg Clayton log->Printf ("SBThread(%p)::SetSelectedFrame() => error: process is running", exe_ctx.GetThreadPtr()); 1077c9858e4dSGreg Clayton } 10787fdf9ef1SGreg Clayton } 1079f028a1fbSGreg Clayton 1080f028a1fbSGreg Clayton if (log) 1081f028a1fbSGreg Clayton { 1082481cef25SGreg Clayton SBStream frame_desc_strm; 1083481cef25SGreg Clayton sb_frame.GetDescription (frame_desc_strm); 1084f028a1fbSGreg Clayton log->Printf ("SBThread(%p)::SetSelectedFrame (idx=%u) => SBFrame(%p): %s", 10851ac04c30SGreg Clayton exe_ctx.GetThreadPtr(), idx, frame_sp.get(), frame_desc_strm.GetData()); 1086f028a1fbSGreg Clayton } 1087f028a1fbSGreg Clayton return sb_frame; 1088f028a1fbSGreg Clayton } 1089f028a1fbSGreg Clayton 1090f028a1fbSGreg Clayton 109130fdc8d8SChris Lattner bool 109230fdc8d8SChris Lattner SBThread::operator == (const SBThread &rhs) const 109330fdc8d8SChris Lattner { 10947fdf9ef1SGreg Clayton return m_opaque_sp->GetThreadSP().get() == rhs.m_opaque_sp->GetThreadSP().get(); 109530fdc8d8SChris Lattner } 109630fdc8d8SChris Lattner 109730fdc8d8SChris Lattner bool 109830fdc8d8SChris Lattner SBThread::operator != (const SBThread &rhs) const 109930fdc8d8SChris Lattner { 11007fdf9ef1SGreg Clayton return m_opaque_sp->GetThreadSP().get() != rhs.m_opaque_sp->GetThreadSP().get(); 110130fdc8d8SChris Lattner } 1102dde9cff3SCaroline Tice 1103dde9cff3SCaroline Tice bool 1104ceb6b139SCaroline Tice SBThread::GetDescription (SBStream &description) const 1105ceb6b139SCaroline Tice { 1106da7bc7d0SGreg Clayton Stream &strm = description.ref(); 1107da7bc7d0SGreg Clayton 11087fdf9ef1SGreg Clayton ExecutionContext exe_ctx (m_opaque_sp.get()); 11091ac04c30SGreg Clayton if (exe_ctx.HasThreadScope()) 1110ceb6b139SCaroline Tice { 11111ac04c30SGreg Clayton strm.Printf("SBThread: tid = 0x%4.4llx", exe_ctx.GetThreadPtr()->GetID()); 1112ceb6b139SCaroline Tice } 1113ceb6b139SCaroline Tice else 1114da7bc7d0SGreg Clayton strm.PutCString ("No value"); 1115ceb6b139SCaroline Tice 1116ceb6b139SCaroline Tice return true; 1117ceb6b139SCaroline Tice } 1118