You've already forked linux-packaging-mono
							
							
		
			
				
	
	
		
			1441 lines
		
	
	
		
			46 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1441 lines
		
	
	
		
			46 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //===-- SBThread.cpp --------------------------------------------*- C++ -*-===//
 | |
| //
 | |
| //                     The LLVM Compiler Infrastructure
 | |
| //
 | |
| // This file is distributed under the University of Illinois Open Source
 | |
| // License. See LICENSE.TXT for details.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "lldb/API/SBThread.h"
 | |
| 
 | |
| #include "lldb/API/SBFileSpec.h"
 | |
| #include "lldb/API/SBStream.h"
 | |
| #include "lldb/API/SBSymbolContext.h"
 | |
| #include "lldb/Breakpoint/BreakpointLocation.h"
 | |
| #include "lldb/Core/Debugger.h"
 | |
| #include "lldb/Core/State.h"
 | |
| #include "lldb/Core/StreamFile.h"
 | |
| #include "lldb/Core/ValueObject.h"
 | |
| #include "lldb/Interpreter/CommandInterpreter.h"
 | |
| #include "lldb/Symbol/CompileUnit.h"
 | |
| #include "lldb/Symbol/SymbolContext.h"
 | |
| #include "lldb/Target/Process.h"
 | |
| #include "lldb/Target/Queue.h"
 | |
| #include "lldb/Target/StopInfo.h"
 | |
| #include "lldb/Target/SystemRuntime.h"
 | |
| #include "lldb/Target/Target.h"
 | |
| #include "lldb/Target/Thread.h"
 | |
| #include "lldb/Target/ThreadPlan.h"
 | |
| #include "lldb/Target/ThreadPlanStepInRange.h"
 | |
| #include "lldb/Target/ThreadPlanStepInstruction.h"
 | |
| #include "lldb/Target/ThreadPlanStepOut.h"
 | |
| #include "lldb/Target/ThreadPlanStepRange.h"
 | |
| #include "lldb/Target/UnixSignals.h"
 | |
| #include "lldb/Utility/Stream.h"
 | |
| #include "lldb/Utility/StructuredData.h"
 | |
| 
 | |
| #include "lldb/API/SBAddress.h"
 | |
| #include "lldb/API/SBDebugger.h"
 | |
| #include "lldb/API/SBEvent.h"
 | |
| #include "lldb/API/SBFrame.h"
 | |
| #include "lldb/API/SBProcess.h"
 | |
| #include "lldb/API/SBThreadCollection.h"
 | |
| #include "lldb/API/SBThreadPlan.h"
 | |
| #include "lldb/API/SBValue.h"
 | |
| #include "lldb/lldb-enumerations.h"
 | |
| 
 | |
| using namespace lldb;
 | |
| using namespace lldb_private;
 | |
| 
 | |
| const char *SBThread::GetBroadcasterClassName() {
 | |
|   return Thread::GetStaticBroadcasterClass().AsCString();
 | |
| }
 | |
| 
 | |
| //----------------------------------------------------------------------
 | |
| // Constructors
 | |
| //----------------------------------------------------------------------
 | |
| SBThread::SBThread() : m_opaque_sp(new ExecutionContextRef()) {}
 | |
| 
 | |
| SBThread::SBThread(const ThreadSP &lldb_object_sp)
 | |
|     : m_opaque_sp(new ExecutionContextRef(lldb_object_sp)) {}
 | |
| 
 | |
| SBThread::SBThread(const SBThread &rhs)
 | |
|     : m_opaque_sp(new ExecutionContextRef(*rhs.m_opaque_sp)) {}
 | |
| 
 | |
| //----------------------------------------------------------------------
 | |
| // Assignment operator
 | |
| //----------------------------------------------------------------------
 | |
| 
 | |
| const lldb::SBThread &SBThread::operator=(const SBThread &rhs) {
 | |
|   if (this != &rhs)
 | |
|     *m_opaque_sp = *rhs.m_opaque_sp;
 | |
|   return *this;
 | |
| }
 | |
| 
 | |
| //----------------------------------------------------------------------
 | |
| // Destructor
 | |
| //----------------------------------------------------------------------
 | |
| SBThread::~SBThread() {}
 | |
| 
 | |
| lldb::SBQueue SBThread::GetQueue() const {
 | |
|   SBQueue sb_queue;
 | |
|   QueueSP queue_sp;
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     Process::StopLocker stop_locker;
 | |
|     if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
 | |
|       queue_sp = exe_ctx.GetThreadPtr()->GetQueue();
 | |
|       if (queue_sp) {
 | |
|         sb_queue.SetQueue(queue_sp);
 | |
|       }
 | |
|     } else {
 | |
|       if (log)
 | |
|         log->Printf("SBThread(%p)::GetQueue() => error: process is running",
 | |
|                     static_cast<void *>(exe_ctx.GetThreadPtr()));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (log)
 | |
|     log->Printf("SBThread(%p)::GetQueue () => SBQueue(%p)",
 | |
|                 static_cast<void *>(exe_ctx.GetThreadPtr()),
 | |
|                 static_cast<void *>(queue_sp.get()));
 | |
| 
 | |
|   return sb_queue;
 | |
| }
 | |
| 
 | |
| bool SBThread::IsValid() const {
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   Target *target = exe_ctx.GetTargetPtr();
 | |
|   Process *process = exe_ctx.GetProcessPtr();
 | |
|   if (target && process) {
 | |
|     Process::StopLocker stop_locker;
 | |
|     if (stop_locker.TryLock(&process->GetRunLock()))
 | |
|       return m_opaque_sp->GetThreadSP().get() != NULL;
 | |
|   }
 | |
|   // Without a valid target & process, this thread can't be valid.
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| void SBThread::Clear() { m_opaque_sp->Clear(); }
 | |
| 
 | |
| StopReason SBThread::GetStopReason() {
 | |
|   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
| 
 | |
|   StopReason reason = eStopReasonInvalid;
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     Process::StopLocker stop_locker;
 | |
|     if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
 | |
|       return exe_ctx.GetThreadPtr()->GetStopReason();
 | |
|     } else {
 | |
|       if (log)
 | |
|         log->Printf(
 | |
|             "SBThread(%p)::GetStopReason() => error: process is running",
 | |
|             static_cast<void *>(exe_ctx.GetThreadPtr()));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (log)
 | |
|     log->Printf("SBThread(%p)::GetStopReason () => %s",
 | |
|                 static_cast<void *>(exe_ctx.GetThreadPtr()),
 | |
|                 Thread::StopReasonAsCString(reason));
 | |
| 
 | |
|   return reason;
 | |
| }
 | |
| 
 | |
| size_t SBThread::GetStopReasonDataCount() {
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     Process::StopLocker stop_locker;
 | |
|     if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
 | |
|       StopInfoSP stop_info_sp = exe_ctx.GetThreadPtr()->GetStopInfo();
 | |
|       if (stop_info_sp) {
 | |
|         StopReason reason = stop_info_sp->GetStopReason();
 | |
|         switch (reason) {
 | |
|         case eStopReasonInvalid:
 | |
|         case eStopReasonNone:
 | |
|         case eStopReasonTrace:
 | |
|         case eStopReasonExec:
 | |
|         case eStopReasonPlanComplete:
 | |
|         case eStopReasonThreadExiting:
 | |
|         case eStopReasonInstrumentation:
 | |
|           // There is no data for these stop reasons.
 | |
|           return 0;
 | |
| 
 | |
|         case eStopReasonBreakpoint: {
 | |
|           break_id_t site_id = stop_info_sp->GetValue();
 | |
|           lldb::BreakpointSiteSP bp_site_sp(
 | |
|               exe_ctx.GetProcessPtr()->GetBreakpointSiteList().FindByID(
 | |
|                   site_id));
 | |
|           if (bp_site_sp)
 | |
|             return bp_site_sp->GetNumberOfOwners() * 2;
 | |
|           else
 | |
|             return 0; // Breakpoint must have cleared itself...
 | |
|         } break;
 | |
| 
 | |
|         case eStopReasonWatchpoint:
 | |
|           return 1;
 | |
| 
 | |
|         case eStopReasonSignal:
 | |
|           return 1;
 | |
| 
 | |
|         case eStopReasonException:
 | |
|           return 1;
 | |
|         }
 | |
|       }
 | |
|     } else {
 | |
|       Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
|       if (log)
 | |
|         log->Printf("SBThread(%p)::GetStopReasonDataCount() => error: process "
 | |
|                     "is running",
 | |
|                     static_cast<void *>(exe_ctx.GetThreadPtr()));
 | |
|     }
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| uint64_t SBThread::GetStopReasonDataAtIndex(uint32_t idx) {
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     Process::StopLocker stop_locker;
 | |
|     if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
 | |
|       Thread *thread = exe_ctx.GetThreadPtr();
 | |
|       StopInfoSP stop_info_sp = thread->GetStopInfo();
 | |
|       if (stop_info_sp) {
 | |
|         StopReason reason = stop_info_sp->GetStopReason();
 | |
|         switch (reason) {
 | |
|         case eStopReasonInvalid:
 | |
|         case eStopReasonNone:
 | |
|         case eStopReasonTrace:
 | |
|         case eStopReasonExec:
 | |
|         case eStopReasonPlanComplete:
 | |
|         case eStopReasonThreadExiting:
 | |
|         case eStopReasonInstrumentation:
 | |
|           // There is no data for these stop reasons.
 | |
|           return 0;
 | |
| 
 | |
|         case eStopReasonBreakpoint: {
 | |
|           break_id_t site_id = stop_info_sp->GetValue();
 | |
|           lldb::BreakpointSiteSP bp_site_sp(
 | |
|               exe_ctx.GetProcessPtr()->GetBreakpointSiteList().FindByID(
 | |
|                   site_id));
 | |
|           if (bp_site_sp) {
 | |
|             uint32_t bp_index = idx / 2;
 | |
|             BreakpointLocationSP bp_loc_sp(
 | |
|                 bp_site_sp->GetOwnerAtIndex(bp_index));
 | |
|             if (bp_loc_sp) {
 | |
|               if (idx & 1) {
 | |
|                 // Odd idx, return the breakpoint location ID
 | |
|                 return bp_loc_sp->GetID();
 | |
|               } else {
 | |
|                 // Even idx, return the breakpoint ID
 | |
|                 return bp_loc_sp->GetBreakpoint().GetID();
 | |
|               }
 | |
|             }
 | |
|           }
 | |
|           return LLDB_INVALID_BREAK_ID;
 | |
|         } break;
 | |
| 
 | |
|         case eStopReasonWatchpoint:
 | |
|           return stop_info_sp->GetValue();
 | |
| 
 | |
|         case eStopReasonSignal:
 | |
|           return stop_info_sp->GetValue();
 | |
| 
 | |
|         case eStopReasonException:
 | |
|           return stop_info_sp->GetValue();
 | |
|         }
 | |
|       }
 | |
|     } else {
 | |
|       Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
|       if (log)
 | |
|         log->Printf("SBThread(%p)::GetStopReasonDataAtIndex() => error: "
 | |
|                     "process is running",
 | |
|                     static_cast<void *>(exe_ctx.GetThreadPtr()));
 | |
|     }
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| bool SBThread::GetStopReasonExtendedInfoAsJSON(lldb::SBStream &stream) {
 | |
|   Stream &strm = stream.ref();
 | |
| 
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   if (!exe_ctx.HasThreadScope())
 | |
|     return false;
 | |
| 
 | |
|   StopInfoSP stop_info = exe_ctx.GetThreadPtr()->GetStopInfo();
 | |
|   StructuredData::ObjectSP info = stop_info->GetExtendedInfo();
 | |
|   if (!info)
 | |
|     return false;
 | |
| 
 | |
|   info->Dump(strm);
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| SBThreadCollection
 | |
| SBThread::GetStopReasonExtendedBacktraces(InstrumentationRuntimeType type) {
 | |
|   ThreadCollectionSP threads;
 | |
|   threads.reset(new ThreadCollection());
 | |
| 
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   if (!exe_ctx.HasThreadScope())
 | |
|     return threads;
 | |
| 
 | |
|   ProcessSP process_sp = exe_ctx.GetProcessSP();
 | |
| 
 | |
|   StopInfoSP stop_info = exe_ctx.GetThreadPtr()->GetStopInfo();
 | |
|   StructuredData::ObjectSP info = stop_info->GetExtendedInfo();
 | |
|   if (!info)
 | |
|     return threads;
 | |
| 
 | |
|   return process_sp->GetInstrumentationRuntime(type)
 | |
|       ->GetBacktracesFromExtendedStopInfo(info);
 | |
| }
 | |
| 
 | |
| size_t SBThread::GetStopDescription(char *dst, size_t dst_len) {
 | |
|   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
| 
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     Process::StopLocker stop_locker;
 | |
|     if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
 | |
| 
 | |
|       StopInfoSP stop_info_sp = exe_ctx.GetThreadPtr()->GetStopInfo();
 | |
|       if (stop_info_sp) {
 | |
|         const char *stop_desc = stop_info_sp->GetDescription();
 | |
|         if (stop_desc) {
 | |
|           if (log)
 | |
|             log->Printf(
 | |
|                 "SBThread(%p)::GetStopDescription (dst, dst_len) => \"%s\"",
 | |
|                 static_cast<void *>(exe_ctx.GetThreadPtr()), stop_desc);
 | |
|           if (dst)
 | |
|             return ::snprintf(dst, dst_len, "%s", stop_desc);
 | |
|           else {
 | |
|             // NULL dst passed in, return the length needed to contain the
 | |
|             // description
 | |
|             return ::strlen(stop_desc) + 1; // Include the NULL byte for size
 | |
|           }
 | |
|         } else {
 | |
|           size_t stop_desc_len = 0;
 | |
|           switch (stop_info_sp->GetStopReason()) {
 | |
|           case eStopReasonTrace:
 | |
|           case eStopReasonPlanComplete: {
 | |
|             static char trace_desc[] = "step";
 | |
|             stop_desc = trace_desc;
 | |
|             stop_desc_len =
 | |
|                 sizeof(trace_desc); // Include the NULL byte for size
 | |
|           } break;
 | |
| 
 | |
|           case eStopReasonBreakpoint: {
 | |
|             static char bp_desc[] = "breakpoint hit";
 | |
|             stop_desc = bp_desc;
 | |
|             stop_desc_len = sizeof(bp_desc); // Include the NULL byte for size
 | |
|           } break;
 | |
| 
 | |
|           case eStopReasonWatchpoint: {
 | |
|             static char wp_desc[] = "watchpoint hit";
 | |
|             stop_desc = wp_desc;
 | |
|             stop_desc_len = sizeof(wp_desc); // Include the NULL byte for size
 | |
|           } break;
 | |
| 
 | |
|           case eStopReasonSignal: {
 | |
|             stop_desc =
 | |
|                 exe_ctx.GetProcessPtr()->GetUnixSignals()->GetSignalAsCString(
 | |
|                     stop_info_sp->GetValue());
 | |
|             if (stop_desc == NULL || stop_desc[0] == '\0') {
 | |
|               static char signal_desc[] = "signal";
 | |
|               stop_desc = signal_desc;
 | |
|               stop_desc_len =
 | |
|                   sizeof(signal_desc); // Include the NULL byte for size
 | |
|             }
 | |
|           } break;
 | |
| 
 | |
|           case eStopReasonException: {
 | |
|             char exc_desc[] = "exception";
 | |
|             stop_desc = exc_desc;
 | |
|             stop_desc_len = sizeof(exc_desc); // Include the NULL byte for size
 | |
|           } break;
 | |
| 
 | |
|           case eStopReasonExec: {
 | |
|             char exc_desc[] = "exec";
 | |
|             stop_desc = exc_desc;
 | |
|             stop_desc_len = sizeof(exc_desc); // Include the NULL byte for size
 | |
|           } break;
 | |
| 
 | |
|           case eStopReasonThreadExiting: {
 | |
|             char limbo_desc[] = "thread exiting";
 | |
|             stop_desc = limbo_desc;
 | |
|             stop_desc_len = sizeof(limbo_desc);
 | |
|           } break;
 | |
|           default:
 | |
|             break;
 | |
|           }
 | |
| 
 | |
|           if (stop_desc && stop_desc[0]) {
 | |
|             if (log)
 | |
|               log->Printf(
 | |
|                   "SBThread(%p)::GetStopDescription (dst, dst_len) => '%s'",
 | |
|                   static_cast<void *>(exe_ctx.GetThreadPtr()), stop_desc);
 | |
| 
 | |
|             if (dst)
 | |
|               return ::snprintf(dst, dst_len, "%s", stop_desc) +
 | |
|                      1; // Include the NULL byte
 | |
| 
 | |
|             if (stop_desc_len == 0)
 | |
|               stop_desc_len = ::strlen(stop_desc) + 1; // Include the NULL byte
 | |
| 
 | |
|             return stop_desc_len;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     } else {
 | |
|       Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
|       if (log)
 | |
|         log->Printf(
 | |
|             "SBThread(%p)::GetStopDescription() => error: process is running",
 | |
|             static_cast<void *>(exe_ctx.GetThreadPtr()));
 | |
|     }
 | |
|   }
 | |
|   if (dst)
 | |
|     *dst = 0;
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| SBValue SBThread::GetStopReturnValue() {
 | |
|   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
|   ValueObjectSP return_valobj_sp;
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     Process::StopLocker stop_locker;
 | |
|     if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
 | |
|       StopInfoSP stop_info_sp = exe_ctx.GetThreadPtr()->GetStopInfo();
 | |
|       if (stop_info_sp) {
 | |
|         return_valobj_sp = StopInfo::GetReturnValueObject(stop_info_sp);
 | |
|       }
 | |
|     } else {
 | |
|       if (log)
 | |
|         log->Printf(
 | |
|             "SBThread(%p)::GetStopReturnValue() => error: process is running",
 | |
|             static_cast<void *>(exe_ctx.GetThreadPtr()));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (log)
 | |
|     log->Printf("SBThread(%p)::GetStopReturnValue () => %s",
 | |
|                 static_cast<void *>(exe_ctx.GetThreadPtr()),
 | |
|                 return_valobj_sp.get() ? return_valobj_sp->GetValueAsCString()
 | |
|                                        : "<no return value>");
 | |
| 
 | |
|   return SBValue(return_valobj_sp);
 | |
| }
 | |
| 
 | |
| void SBThread::SetThread(const ThreadSP &lldb_object_sp) {
 | |
|   m_opaque_sp->SetThreadSP(lldb_object_sp);
 | |
| }
 | |
| 
 | |
| lldb::tid_t SBThread::GetThreadID() const {
 | |
|   ThreadSP thread_sp(m_opaque_sp->GetThreadSP());
 | |
|   if (thread_sp)
 | |
|     return thread_sp->GetID();
 | |
|   return LLDB_INVALID_THREAD_ID;
 | |
| }
 | |
| 
 | |
| uint32_t SBThread::GetIndexID() const {
 | |
|   ThreadSP thread_sp(m_opaque_sp->GetThreadSP());
 | |
|   if (thread_sp)
 | |
|     return thread_sp->GetIndexID();
 | |
|   return LLDB_INVALID_INDEX32;
 | |
| }
 | |
| 
 | |
| const char *SBThread::GetName() const {
 | |
|   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
|   const char *name = NULL;
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     Process::StopLocker stop_locker;
 | |
|     if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
 | |
|       name = exe_ctx.GetThreadPtr()->GetName();
 | |
|     } else {
 | |
|       if (log)
 | |
|         log->Printf("SBThread(%p)::GetName() => error: process is running",
 | |
|                     static_cast<void *>(exe_ctx.GetThreadPtr()));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (log)
 | |
|     log->Printf("SBThread(%p)::GetName () => %s",
 | |
|                 static_cast<void *>(exe_ctx.GetThreadPtr()),
 | |
|                 name ? name : "NULL");
 | |
| 
 | |
|   return name;
 | |
| }
 | |
| 
 | |
| const char *SBThread::GetQueueName() const {
 | |
|   const char *name = NULL;
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     Process::StopLocker stop_locker;
 | |
|     if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
 | |
|       name = exe_ctx.GetThreadPtr()->GetQueueName();
 | |
|     } else {
 | |
|       if (log)
 | |
|         log->Printf("SBThread(%p)::GetQueueName() => error: process is running",
 | |
|                     static_cast<void *>(exe_ctx.GetThreadPtr()));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (log)
 | |
|     log->Printf("SBThread(%p)::GetQueueName () => %s",
 | |
|                 static_cast<void *>(exe_ctx.GetThreadPtr()),
 | |
|                 name ? name : "NULL");
 | |
| 
 | |
|   return name;
 | |
| }
 | |
| 
 | |
| lldb::queue_id_t SBThread::GetQueueID() const {
 | |
|   queue_id_t id = LLDB_INVALID_QUEUE_ID;
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     Process::StopLocker stop_locker;
 | |
|     if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
 | |
|       id = exe_ctx.GetThreadPtr()->GetQueueID();
 | |
|     } else {
 | |
|       if (log)
 | |
|         log->Printf("SBThread(%p)::GetQueueID() => error: process is running",
 | |
|                     static_cast<void *>(exe_ctx.GetThreadPtr()));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (log)
 | |
|     log->Printf("SBThread(%p)::GetQueueID () => 0x%" PRIx64,
 | |
|                 static_cast<void *>(exe_ctx.GetThreadPtr()), id);
 | |
| 
 | |
|   return id;
 | |
| }
 | |
| 
 | |
| bool SBThread::GetInfoItemByPathAsString(const char *path, SBStream &strm) {
 | |
|   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
|   bool success = false;
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     Process::StopLocker stop_locker;
 | |
|     if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
 | |
|       Thread *thread = exe_ctx.GetThreadPtr();
 | |
|       StructuredData::ObjectSP info_root_sp = thread->GetExtendedInfo();
 | |
|       if (info_root_sp) {
 | |
|         StructuredData::ObjectSP node =
 | |
|             info_root_sp->GetObjectForDotSeparatedPath(path);
 | |
|         if (node) {
 | |
|           if (node->GetType() == eStructuredDataTypeString) {
 | |
|             strm.Printf("%s", node->GetAsString()->GetValue().str().c_str());
 | |
|             success = true;
 | |
|           }
 | |
|           if (node->GetType() == eStructuredDataTypeInteger) {
 | |
|             strm.Printf("0x%" PRIx64, node->GetAsInteger()->GetValue());
 | |
|             success = true;
 | |
|           }
 | |
|           if (node->GetType() == eStructuredDataTypeFloat) {
 | |
|             strm.Printf("0x%f", node->GetAsFloat()->GetValue());
 | |
|             success = true;
 | |
|           }
 | |
|           if (node->GetType() == eStructuredDataTypeBoolean) {
 | |
|             if (node->GetAsBoolean()->GetValue() == true)
 | |
|               strm.Printf("true");
 | |
|             else
 | |
|               strm.Printf("false");
 | |
|             success = true;
 | |
|           }
 | |
|           if (node->GetType() == eStructuredDataTypeNull) {
 | |
|             strm.Printf("null");
 | |
|             success = true;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     } else {
 | |
|       if (log)
 | |
|         log->Printf("SBThread(%p)::GetInfoItemByPathAsString() => error: "
 | |
|                     "process is running",
 | |
|                     static_cast<void *>(exe_ctx.GetThreadPtr()));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (log)
 | |
|     log->Printf("SBThread(%p)::GetInfoItemByPathAsString (\"%s\") => \"%s\"",
 | |
|                 static_cast<void *>(exe_ctx.GetThreadPtr()), path, strm.GetData());
 | |
| 
 | |
|   return success;
 | |
| }
 | |
| 
 | |
| SBError SBThread::ResumeNewPlan(ExecutionContext &exe_ctx,
 | |
|                                 ThreadPlan *new_plan) {
 | |
|   SBError sb_error;
 | |
| 
 | |
|   Process *process = exe_ctx.GetProcessPtr();
 | |
|   if (!process) {
 | |
|     sb_error.SetErrorString("No process in SBThread::ResumeNewPlan");
 | |
|     return sb_error;
 | |
|   }
 | |
| 
 | |
|   Thread *thread = exe_ctx.GetThreadPtr();
 | |
|   if (!thread) {
 | |
|     sb_error.SetErrorString("No thread in SBThread::ResumeNewPlan");
 | |
|     return sb_error;
 | |
|   }
 | |
| 
 | |
|   // User level plans should be Master Plans so they can be interrupted, other
 | |
|   // plans executed, and
 | |
|   // then a "continue" will resume the plan.
 | |
|   if (new_plan != NULL) {
 | |
|     new_plan->SetIsMasterPlan(true);
 | |
|     new_plan->SetOkayToDiscard(false);
 | |
|   }
 | |
| 
 | |
|   // Why do we need to set the current thread by ID here???
 | |
|   process->GetThreadList().SetSelectedThreadByID(thread->GetID());
 | |
| 
 | |
|   if (process->GetTarget().GetDebugger().GetAsyncExecution())
 | |
|     sb_error.ref() = process->Resume();
 | |
|   else
 | |
|     sb_error.ref() = process->ResumeSynchronous(NULL);
 | |
| 
 | |
|   return sb_error;
 | |
| }
 | |
| 
 | |
| void SBThread::StepOver(lldb::RunMode stop_other_threads) {
 | |
|   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
| 
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   if (log)
 | |
|     log->Printf("SBThread(%p)::StepOver (stop_other_threads='%s')",
 | |
|                 static_cast<void *>(exe_ctx.GetThreadPtr()),
 | |
|                 Thread::RunModeAsCString(stop_other_threads));
 | |
| 
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     Thread *thread = exe_ctx.GetThreadPtr();
 | |
|     bool abort_other_plans = false;
 | |
|     StackFrameSP frame_sp(thread->GetStackFrameAtIndex(0));
 | |
| 
 | |
|     ThreadPlanSP new_plan_sp;
 | |
|     if (frame_sp) {
 | |
|       if (frame_sp->HasDebugInformation()) {
 | |
|         const LazyBool avoid_no_debug = eLazyBoolCalculate;
 | |
|         SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything));
 | |
|         new_plan_sp = thread->QueueThreadPlanForStepOverRange(
 | |
|             abort_other_plans, sc.line_entry, sc, stop_other_threads,
 | |
|             avoid_no_debug);
 | |
|       } else {
 | |
|         new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
 | |
|             true, abort_other_plans, stop_other_threads);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     // This returns an error, we should use it!
 | |
|     ResumeNewPlan(exe_ctx, new_plan_sp.get());
 | |
|   }
 | |
| }
 | |
| 
 | |
| void SBThread::StepInto(lldb::RunMode stop_other_threads) {
 | |
|   StepInto(NULL, stop_other_threads);
 | |
| }
 | |
| 
 | |
| void SBThread::StepInto(const char *target_name,
 | |
|                         lldb::RunMode stop_other_threads) {
 | |
|   SBError error;
 | |
|   StepInto(target_name, LLDB_INVALID_LINE_NUMBER, error, stop_other_threads);
 | |
| }
 | |
| 
 | |
| void SBThread::StepInto(const char *target_name, uint32_t end_line,
 | |
|                         SBError &error, lldb::RunMode stop_other_threads) {
 | |
|   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
| 
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   if (log)
 | |
|     log->Printf(
 | |
|         "SBThread(%p)::StepInto (target_name='%s', stop_other_threads='%s')",
 | |
|         static_cast<void *>(exe_ctx.GetThreadPtr()),
 | |
|         target_name ? target_name : "<NULL>",
 | |
|         Thread::RunModeAsCString(stop_other_threads));
 | |
| 
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     bool abort_other_plans = false;
 | |
| 
 | |
|     Thread *thread = exe_ctx.GetThreadPtr();
 | |
|     StackFrameSP frame_sp(thread->GetStackFrameAtIndex(0));
 | |
|     ThreadPlanSP new_plan_sp;
 | |
| 
 | |
|     if (frame_sp && frame_sp->HasDebugInformation()) {
 | |
|       SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything));
 | |
|       AddressRange range;
 | |
|       if (end_line == LLDB_INVALID_LINE_NUMBER)
 | |
|         range = sc.line_entry.range;
 | |
|       else {
 | |
|         if (!sc.GetAddressRangeFromHereToEndLine(end_line, range, error.ref()))
 | |
|           return;
 | |
|       }
 | |
| 
 | |
|       const LazyBool step_out_avoids_code_without_debug_info =
 | |
|           eLazyBoolCalculate;
 | |
|       const LazyBool step_in_avoids_code_without_debug_info =
 | |
|           eLazyBoolCalculate;
 | |
|       new_plan_sp = thread->QueueThreadPlanForStepInRange(
 | |
|           abort_other_plans, range, sc, target_name, stop_other_threads,
 | |
|           step_in_avoids_code_without_debug_info,
 | |
|           step_out_avoids_code_without_debug_info);
 | |
|     } else {
 | |
|       new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
 | |
|           false, abort_other_plans, stop_other_threads);
 | |
|     }
 | |
| 
 | |
|     error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
 | |
|   }
 | |
| }
 | |
| 
 | |
| void SBThread::StepOut() {
 | |
|   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
| 
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   if (log)
 | |
|     log->Printf("SBThread(%p)::StepOut ()",
 | |
|                 static_cast<void *>(exe_ctx.GetThreadPtr()));
 | |
| 
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     bool abort_other_plans = false;
 | |
|     bool stop_other_threads = false;
 | |
| 
 | |
|     Thread *thread = exe_ctx.GetThreadPtr();
 | |
| 
 | |
|     const LazyBool avoid_no_debug = eLazyBoolCalculate;
 | |
|     ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepOut(
 | |
|         abort_other_plans, NULL, false, stop_other_threads, eVoteYes,
 | |
|         eVoteNoOpinion, 0, avoid_no_debug));
 | |
| 
 | |
|     // This returns an error, we should use it!
 | |
|     ResumeNewPlan(exe_ctx, new_plan_sp.get());
 | |
|   }
 | |
| }
 | |
| 
 | |
| void SBThread::StepOutOfFrame(lldb::SBFrame &sb_frame) {
 | |
|   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
| 
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   if (!sb_frame.IsValid()) {
 | |
|     if (log)
 | |
|       log->Printf(
 | |
|           "SBThread(%p)::StepOutOfFrame passed an invalid frame, returning.",
 | |
|           static_cast<void *>(exe_ctx.GetThreadPtr()));
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   StackFrameSP frame_sp(sb_frame.GetFrameSP());
 | |
|   if (log) {
 | |
|     SBStream frame_desc_strm;
 | |
|     sb_frame.GetDescription(frame_desc_strm);
 | |
|     log->Printf("SBThread(%p)::StepOutOfFrame (frame = SBFrame(%p): %s)",
 | |
|                 static_cast<void *>(exe_ctx.GetThreadPtr()),
 | |
|                 static_cast<void *>(frame_sp.get()), frame_desc_strm.GetData());
 | |
|   }
 | |
| 
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     bool abort_other_plans = false;
 | |
|     bool stop_other_threads = false;
 | |
|     Thread *thread = exe_ctx.GetThreadPtr();
 | |
|     if (sb_frame.GetThread().GetThreadID() != thread->GetID()) {
 | |
|       log->Printf("SBThread(%p)::StepOutOfFrame passed a frame from another "
 | |
|                   "thread (0x%" PRIx64 " vrs. 0x%" PRIx64 ", returning.",
 | |
|                   static_cast<void *>(exe_ctx.GetThreadPtr()),
 | |
|                   sb_frame.GetThread().GetThreadID(), thread->GetID());
 | |
|     }
 | |
| 
 | |
|     ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepOut(
 | |
|         abort_other_plans, NULL, false, stop_other_threads, eVoteYes,
 | |
|         eVoteNoOpinion, frame_sp->GetFrameIndex()));
 | |
| 
 | |
|     // This returns an error, we should use it!
 | |
|     ResumeNewPlan(exe_ctx, new_plan_sp.get());
 | |
|   }
 | |
| }
 | |
| 
 | |
| void SBThread::StepInstruction(bool step_over) {
 | |
|   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
| 
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   if (log)
 | |
|     log->Printf("SBThread(%p)::StepInstruction (step_over=%i)",
 | |
|                 static_cast<void *>(exe_ctx.GetThreadPtr()), step_over);
 | |
| 
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     Thread *thread = exe_ctx.GetThreadPtr();
 | |
|     ThreadPlanSP new_plan_sp(
 | |
|         thread->QueueThreadPlanForStepSingleInstruction(step_over, true, true));
 | |
| 
 | |
|     // This returns an error, we should use it!
 | |
|     ResumeNewPlan(exe_ctx, new_plan_sp.get());
 | |
|   }
 | |
| }
 | |
| 
 | |
| void SBThread::RunToAddress(lldb::addr_t addr) {
 | |
|   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
| 
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   if (log)
 | |
|     log->Printf("SBThread(%p)::RunToAddress (addr=0x%" PRIx64 ")",
 | |
|                 static_cast<void *>(exe_ctx.GetThreadPtr()), addr);
 | |
| 
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     bool abort_other_plans = false;
 | |
|     bool stop_other_threads = true;
 | |
| 
 | |
|     Address target_addr(addr);
 | |
| 
 | |
|     Thread *thread = exe_ctx.GetThreadPtr();
 | |
| 
 | |
|     ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForRunToAddress(
 | |
|         abort_other_plans, target_addr, stop_other_threads));
 | |
| 
 | |
|     // This returns an error, we should use it!
 | |
|     ResumeNewPlan(exe_ctx, new_plan_sp.get());
 | |
|   }
 | |
| }
 | |
| 
 | |
| SBError SBThread::StepOverUntil(lldb::SBFrame &sb_frame,
 | |
|                                 lldb::SBFileSpec &sb_file_spec, uint32_t line) {
 | |
|   SBError sb_error;
 | |
|   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
|   char path[PATH_MAX];
 | |
| 
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   StackFrameSP frame_sp(sb_frame.GetFrameSP());
 | |
| 
 | |
|   if (log) {
 | |
|     SBStream frame_desc_strm;
 | |
|     sb_frame.GetDescription(frame_desc_strm);
 | |
|     sb_file_spec->GetPath(path, sizeof(path));
 | |
|     log->Printf("SBThread(%p)::StepOverUntil (frame = SBFrame(%p): %s, "
 | |
|                 "file+line = %s:%u)",
 | |
|                 static_cast<void *>(exe_ctx.GetThreadPtr()),
 | |
|                 static_cast<void *>(frame_sp.get()), frame_desc_strm.GetData(),
 | |
|                 path, line);
 | |
|   }
 | |
| 
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     Target *target = exe_ctx.GetTargetPtr();
 | |
|     Thread *thread = exe_ctx.GetThreadPtr();
 | |
| 
 | |
|     if (line == 0) {
 | |
|       sb_error.SetErrorString("invalid line argument");
 | |
|       return sb_error;
 | |
|     }
 | |
| 
 | |
|     if (!frame_sp) {
 | |
|       frame_sp = thread->GetSelectedFrame();
 | |
|       if (!frame_sp)
 | |
|         frame_sp = thread->GetStackFrameAtIndex(0);
 | |
|     }
 | |
| 
 | |
|     SymbolContext frame_sc;
 | |
|     if (!frame_sp) {
 | |
|       sb_error.SetErrorString("no valid frames in thread to step");
 | |
|       return sb_error;
 | |
|     }
 | |
| 
 | |
|     // If we have a frame, get its line
 | |
|     frame_sc = frame_sp->GetSymbolContext(
 | |
|         eSymbolContextCompUnit | eSymbolContextFunction |
 | |
|         eSymbolContextLineEntry | eSymbolContextSymbol);
 | |
| 
 | |
|     if (frame_sc.comp_unit == NULL) {
 | |
|       sb_error.SetErrorStringWithFormat(
 | |
|           "frame %u doesn't have debug information", frame_sp->GetFrameIndex());
 | |
|       return sb_error;
 | |
|     }
 | |
| 
 | |
|     FileSpec step_file_spec;
 | |
|     if (sb_file_spec.IsValid()) {
 | |
|       // The file spec passed in was valid, so use it
 | |
|       step_file_spec = sb_file_spec.ref();
 | |
|     } else {
 | |
|       if (frame_sc.line_entry.IsValid())
 | |
|         step_file_spec = frame_sc.line_entry.file;
 | |
|       else {
 | |
|         sb_error.SetErrorString("invalid file argument or no file for frame");
 | |
|         return sb_error;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     // Grab the current function, then we will make sure the "until" address is
 | |
|     // within the function.  We discard addresses that are out of the current
 | |
|     // function, and then if there are no addresses remaining, give an
 | |
|     // appropriate
 | |
|     // error message.
 | |
| 
 | |
|     bool all_in_function = true;
 | |
|     AddressRange fun_range = frame_sc.function->GetAddressRange();
 | |
| 
 | |
|     std::vector<addr_t> step_over_until_addrs;
 | |
|     const bool abort_other_plans = false;
 | |
|     const bool stop_other_threads = false;
 | |
|     const bool check_inlines = true;
 | |
|     const bool exact = false;
 | |
| 
 | |
|     SymbolContextList sc_list;
 | |
|     const uint32_t num_matches = frame_sc.comp_unit->ResolveSymbolContext(
 | |
|         step_file_spec, line, check_inlines, exact, eSymbolContextLineEntry,
 | |
|         sc_list);
 | |
|     if (num_matches > 0) {
 | |
|       SymbolContext sc;
 | |
|       for (uint32_t i = 0; i < num_matches; ++i) {
 | |
|         if (sc_list.GetContextAtIndex(i, sc)) {
 | |
|           addr_t step_addr =
 | |
|               sc.line_entry.range.GetBaseAddress().GetLoadAddress(target);
 | |
|           if (step_addr != LLDB_INVALID_ADDRESS) {
 | |
|             if (fun_range.ContainsLoadAddress(step_addr, target))
 | |
|               step_over_until_addrs.push_back(step_addr);
 | |
|             else
 | |
|               all_in_function = false;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (step_over_until_addrs.empty()) {
 | |
|       if (all_in_function) {
 | |
|         step_file_spec.GetPath(path, sizeof(path));
 | |
|         sb_error.SetErrorStringWithFormat("No line entries for %s:%u", path,
 | |
|                                           line);
 | |
|       } else
 | |
|         sb_error.SetErrorString("step until target not in current function");
 | |
|     } else {
 | |
|       ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepUntil(
 | |
|           abort_other_plans, &step_over_until_addrs[0],
 | |
|           step_over_until_addrs.size(), stop_other_threads,
 | |
|           frame_sp->GetFrameIndex()));
 | |
| 
 | |
|       sb_error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
 | |
|     }
 | |
|   } else {
 | |
|     sb_error.SetErrorString("this SBThread object is invalid");
 | |
|   }
 | |
|   return sb_error;
 | |
| }
 | |
| 
 | |
| SBError SBThread::StepUsingScriptedThreadPlan(const char *script_class_name) {
 | |
|   return StepUsingScriptedThreadPlan(script_class_name, true);
 | |
| }
 | |
| 
 | |
| SBError SBThread::StepUsingScriptedThreadPlan(const char *script_class_name,
 | |
|                                               bool resume_immediately) {
 | |
|   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
|   SBError sb_error;
 | |
| 
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   if (log) {
 | |
|     log->Printf("SBThread(%p)::StepUsingScriptedThreadPlan: class name: %s",
 | |
|                 static_cast<void *>(exe_ctx.GetThreadPtr()), script_class_name);
 | |
|   }
 | |
| 
 | |
|   if (!exe_ctx.HasThreadScope()) {
 | |
|     sb_error.SetErrorString("this SBThread object is invalid");
 | |
|     return sb_error;
 | |
|   }
 | |
| 
 | |
|   Thread *thread = exe_ctx.GetThreadPtr();
 | |
|   ThreadPlanSP thread_plan_sp =
 | |
|       thread->QueueThreadPlanForStepScripted(false, script_class_name, false);
 | |
| 
 | |
|   if (!thread_plan_sp) {
 | |
|     sb_error.SetErrorStringWithFormat(
 | |
|         "Error queueing thread plan for class: %s", script_class_name);
 | |
|     return sb_error;
 | |
|   }
 | |
| 
 | |
|   if (!resume_immediately) {
 | |
|     return sb_error;
 | |
|   }
 | |
| 
 | |
|   if (thread_plan_sp)
 | |
|     sb_error = ResumeNewPlan(exe_ctx, thread_plan_sp.get());
 | |
|   else {
 | |
|     sb_error.SetErrorStringWithFormat(
 | |
|         "Error resuming thread plan for class: %s.", script_class_name);
 | |
|     if (log)
 | |
|       log->Printf("SBThread(%p)::StepUsingScriptedThreadPlan: Error queuing "
 | |
|                   "thread plan for class: %s",
 | |
|                   static_cast<void *>(exe_ctx.GetThreadPtr()),
 | |
|                   script_class_name);
 | |
|   }
 | |
| 
 | |
|   return sb_error;
 | |
| }
 | |
| 
 | |
| SBError SBThread::JumpToLine(lldb::SBFileSpec &file_spec, uint32_t line) {
 | |
|   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
|   SBError sb_error;
 | |
| 
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   if (log)
 | |
|     log->Printf("SBThread(%p)::JumpToLine (file+line = %s:%u)",
 | |
|                 static_cast<void *>(exe_ctx.GetThreadPtr()),
 | |
|                 file_spec->GetPath().c_str(), line);
 | |
| 
 | |
|   if (!exe_ctx.HasThreadScope()) {
 | |
|     sb_error.SetErrorString("this SBThread object is invalid");
 | |
|     return sb_error;
 | |
|   }
 | |
| 
 | |
|   Thread *thread = exe_ctx.GetThreadPtr();
 | |
| 
 | |
|   Status err = thread->JumpToLine(file_spec.get(), line, true);
 | |
|   sb_error.SetError(err);
 | |
|   return sb_error;
 | |
| }
 | |
| 
 | |
| SBError SBThread::ReturnFromFrame(SBFrame &frame, SBValue &return_value) {
 | |
|   SBError sb_error;
 | |
| 
 | |
|   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
| 
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   if (log)
 | |
|     log->Printf("SBThread(%p)::ReturnFromFrame (frame=%d)",
 | |
|                 static_cast<void *>(exe_ctx.GetThreadPtr()),
 | |
|                 frame.GetFrameID());
 | |
| 
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     Thread *thread = exe_ctx.GetThreadPtr();
 | |
|     sb_error.SetError(
 | |
|         thread->ReturnFromFrame(frame.GetFrameSP(), return_value.GetSP()));
 | |
|   }
 | |
| 
 | |
|   return sb_error;
 | |
| }
 | |
| 
 | |
| SBError SBThread::UnwindInnermostExpression() {
 | |
|   SBError sb_error;
 | |
| 
 | |
|   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
| 
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   if (log)
 | |
|     log->Printf("SBThread(%p)::UnwindExpressionEvaluation",
 | |
|                 static_cast<void *>(exe_ctx.GetThreadPtr()));
 | |
| 
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     Thread *thread = exe_ctx.GetThreadPtr();
 | |
|     sb_error.SetError(thread->UnwindInnermostExpression());
 | |
|     if (sb_error.Success())
 | |
|       thread->SetSelectedFrameByIndex(0, false);
 | |
|   }
 | |
| 
 | |
|   return sb_error;
 | |
| }
 | |
| 
 | |
| bool SBThread::Suspend() {
 | |
|   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   bool result = false;
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     Process::StopLocker stop_locker;
 | |
|     if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
 | |
|       exe_ctx.GetThreadPtr()->SetResumeState(eStateSuspended);
 | |
|       result = true;
 | |
|     } else {
 | |
|       if (log)
 | |
|         log->Printf("SBThread(%p)::Suspend() => error: process is running",
 | |
|                     static_cast<void *>(exe_ctx.GetThreadPtr()));
 | |
|     }
 | |
|   }
 | |
|   if (log)
 | |
|     log->Printf("SBThread(%p)::Suspend() => %i",
 | |
|                 static_cast<void *>(exe_ctx.GetThreadPtr()), result);
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| bool SBThread::Resume() {
 | |
|   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   bool result = false;
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     Process::StopLocker stop_locker;
 | |
|     if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
 | |
|       const bool override_suspend = true;
 | |
|       exe_ctx.GetThreadPtr()->SetResumeState(eStateRunning, override_suspend);
 | |
|       result = true;
 | |
|     } else {
 | |
|       if (log)
 | |
|         log->Printf("SBThread(%p)::Resume() => error: process is running",
 | |
|                     static_cast<void *>(exe_ctx.GetThreadPtr()));
 | |
|     }
 | |
|   }
 | |
|   if (log)
 | |
|     log->Printf("SBThread(%p)::Resume() => %i",
 | |
|                 static_cast<void *>(exe_ctx.GetThreadPtr()), result);
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| bool SBThread::IsSuspended() {
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   if (exe_ctx.HasThreadScope())
 | |
|     return exe_ctx.GetThreadPtr()->GetResumeState() == eStateSuspended;
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| bool SBThread::IsStopped() {
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   if (exe_ctx.HasThreadScope())
 | |
|     return StateIsStoppedState(exe_ctx.GetThreadPtr()->GetState(), true);
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| SBProcess SBThread::GetProcess() {
 | |
|   SBProcess sb_process;
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     // Have to go up to the target so we can get a shared pointer to our
 | |
|     // process...
 | |
|     sb_process.SetSP(exe_ctx.GetProcessSP());
 | |
|   }
 | |
| 
 | |
|   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
|   if (log) {
 | |
|     SBStream frame_desc_strm;
 | |
|     sb_process.GetDescription(frame_desc_strm);
 | |
|     log->Printf("SBThread(%p)::GetProcess () => SBProcess(%p): %s",
 | |
|                 static_cast<void *>(exe_ctx.GetThreadPtr()),
 | |
|                 static_cast<void *>(sb_process.GetSP().get()),
 | |
|                 frame_desc_strm.GetData());
 | |
|   }
 | |
| 
 | |
|   return sb_process;
 | |
| }
 | |
| 
 | |
| uint32_t SBThread::GetNumFrames() {
 | |
|   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
| 
 | |
|   uint32_t num_frames = 0;
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     Process::StopLocker stop_locker;
 | |
|     if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
 | |
|       num_frames = exe_ctx.GetThreadPtr()->GetStackFrameCount();
 | |
|     } else {
 | |
|       if (log)
 | |
|         log->Printf("SBThread(%p)::GetNumFrames() => error: process is running",
 | |
|                     static_cast<void *>(exe_ctx.GetThreadPtr()));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (log)
 | |
|     log->Printf("SBThread(%p)::GetNumFrames () => %u",
 | |
|                 static_cast<void *>(exe_ctx.GetThreadPtr()), num_frames);
 | |
| 
 | |
|   return num_frames;
 | |
| }
 | |
| 
 | |
| SBFrame SBThread::GetFrameAtIndex(uint32_t idx) {
 | |
|   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
| 
 | |
|   SBFrame sb_frame;
 | |
|   StackFrameSP frame_sp;
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     Process::StopLocker stop_locker;
 | |
|     if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
 | |
|       frame_sp = exe_ctx.GetThreadPtr()->GetStackFrameAtIndex(idx);
 | |
|       sb_frame.SetFrameSP(frame_sp);
 | |
|     } else {
 | |
|       if (log)
 | |
|         log->Printf(
 | |
|             "SBThread(%p)::GetFrameAtIndex() => error: process is running",
 | |
|             static_cast<void *>(exe_ctx.GetThreadPtr()));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (log) {
 | |
|     SBStream frame_desc_strm;
 | |
|     sb_frame.GetDescription(frame_desc_strm);
 | |
|     log->Printf("SBThread(%p)::GetFrameAtIndex (idx=%d) => SBFrame(%p): %s",
 | |
|                 static_cast<void *>(exe_ctx.GetThreadPtr()), idx,
 | |
|                 static_cast<void *>(frame_sp.get()), frame_desc_strm.GetData());
 | |
|   }
 | |
| 
 | |
|   return sb_frame;
 | |
| }
 | |
| 
 | |
| lldb::SBFrame SBThread::GetSelectedFrame() {
 | |
|   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
| 
 | |
|   SBFrame sb_frame;
 | |
|   StackFrameSP frame_sp;
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     Process::StopLocker stop_locker;
 | |
|     if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
 | |
|       frame_sp = exe_ctx.GetThreadPtr()->GetSelectedFrame();
 | |
|       sb_frame.SetFrameSP(frame_sp);
 | |
|     } else {
 | |
|       if (log)
 | |
|         log->Printf(
 | |
|             "SBThread(%p)::GetSelectedFrame() => error: process is running",
 | |
|             static_cast<void *>(exe_ctx.GetThreadPtr()));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (log) {
 | |
|     SBStream frame_desc_strm;
 | |
|     sb_frame.GetDescription(frame_desc_strm);
 | |
|     log->Printf("SBThread(%p)::GetSelectedFrame () => SBFrame(%p): %s",
 | |
|                 static_cast<void *>(exe_ctx.GetThreadPtr()),
 | |
|                 static_cast<void *>(frame_sp.get()), frame_desc_strm.GetData());
 | |
|   }
 | |
| 
 | |
|   return sb_frame;
 | |
| }
 | |
| 
 | |
| lldb::SBFrame SBThread::SetSelectedFrame(uint32_t idx) {
 | |
|   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
| 
 | |
|   SBFrame sb_frame;
 | |
|   StackFrameSP frame_sp;
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     Process::StopLocker stop_locker;
 | |
|     if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
 | |
|       Thread *thread = exe_ctx.GetThreadPtr();
 | |
|       frame_sp = thread->GetStackFrameAtIndex(idx);
 | |
|       if (frame_sp) {
 | |
|         thread->SetSelectedFrame(frame_sp.get());
 | |
|         sb_frame.SetFrameSP(frame_sp);
 | |
|       }
 | |
|     } else {
 | |
|       if (log)
 | |
|         log->Printf(
 | |
|             "SBThread(%p)::SetSelectedFrame() => error: process is running",
 | |
|             static_cast<void *>(exe_ctx.GetThreadPtr()));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (log) {
 | |
|     SBStream frame_desc_strm;
 | |
|     sb_frame.GetDescription(frame_desc_strm);
 | |
|     log->Printf("SBThread(%p)::SetSelectedFrame (idx=%u) => SBFrame(%p): %s",
 | |
|                 static_cast<void *>(exe_ctx.GetThreadPtr()), idx,
 | |
|                 static_cast<void *>(frame_sp.get()), frame_desc_strm.GetData());
 | |
|   }
 | |
|   return sb_frame;
 | |
| }
 | |
| 
 | |
| bool SBThread::EventIsThreadEvent(const SBEvent &event) {
 | |
|   return Thread::ThreadEventData::GetEventDataFromEvent(event.get()) != NULL;
 | |
| }
 | |
| 
 | |
| SBFrame SBThread::GetStackFrameFromEvent(const SBEvent &event) {
 | |
|   return Thread::ThreadEventData::GetStackFrameFromEvent(event.get());
 | |
| }
 | |
| 
 | |
| SBThread SBThread::GetThreadFromEvent(const SBEvent &event) {
 | |
|   return Thread::ThreadEventData::GetThreadFromEvent(event.get());
 | |
| }
 | |
| 
 | |
| bool SBThread::operator==(const SBThread &rhs) const {
 | |
|   return m_opaque_sp->GetThreadSP().get() ==
 | |
|          rhs.m_opaque_sp->GetThreadSP().get();
 | |
| }
 | |
| 
 | |
| bool SBThread::operator!=(const SBThread &rhs) const {
 | |
|   return m_opaque_sp->GetThreadSP().get() !=
 | |
|          rhs.m_opaque_sp->GetThreadSP().get();
 | |
| }
 | |
| 
 | |
| bool SBThread::GetStatus(SBStream &status) const {
 | |
|   Stream &strm = status.ref();
 | |
| 
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     exe_ctx.GetThreadPtr()->GetStatus(strm, 0, 1, 1, true);
 | |
|   } else
 | |
|     strm.PutCString("No status");
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool SBThread::GetDescription(SBStream &description) const {
 | |
|     return GetDescription(description, false);
 | |
| }
 | |
| 
 | |
| bool SBThread::GetDescription(SBStream &description, bool stop_format) const {
 | |
|   Stream &strm = description.ref();
 | |
| 
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
| 
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     exe_ctx.GetThreadPtr()->DumpUsingSettingsFormat(strm,
 | |
|                                                     LLDB_INVALID_THREAD_ID,
 | |
|                                                     stop_format);
 | |
|     // strm.Printf("SBThread: tid = 0x%4.4" PRIx64,
 | |
|     // exe_ctx.GetThreadPtr()->GetID());
 | |
|   } else
 | |
|     strm.PutCString("No value");
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| SBThread SBThread::GetExtendedBacktraceThread(const char *type) {
 | |
|   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 | |
|   std::unique_lock<std::recursive_mutex> lock;
 | |
|   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
 | |
|   SBThread sb_origin_thread;
 | |
| 
 | |
|   if (exe_ctx.HasThreadScope()) {
 | |
|     Process::StopLocker stop_locker;
 | |
|     if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
 | |
|       ThreadSP real_thread(exe_ctx.GetThreadSP());
 | |
|       if (real_thread) {
 | |
|         ConstString type_const(type);
 | |
|         Process *process = exe_ctx.GetProcessPtr();
 | |
|         if (process) {
 | |
|           SystemRuntime *runtime = process->GetSystemRuntime();
 | |
|           if (runtime) {
 | |
|             ThreadSP new_thread_sp(
 | |
|                 runtime->GetExtendedBacktraceThread(real_thread, type_const));
 | |
|             if (new_thread_sp) {
 | |
|               // Save this in the Process' ExtendedThreadList so a strong
 | |
|               // pointer retains the
 | |
|               // object.
 | |
|               process->GetExtendedThreadList().AddThread(new_thread_sp);
 | |
|               sb_origin_thread.SetThread(new_thread_sp);
 | |
|               if (log) {
 | |
|                 const char *queue_name = new_thread_sp->GetQueueName();
 | |
|                 if (queue_name == NULL)
 | |
|                   queue_name = "";
 | |
|                 log->Printf("SBThread(%p)::GetExtendedBacktraceThread() => new "
 | |
|                             "extended Thread "
 | |
|                             "created (%p) with queue_id 0x%" PRIx64
 | |
|                             " queue name '%s'",
 | |
|                             static_cast<void *>(exe_ctx.GetThreadPtr()),
 | |
|                             static_cast<void *>(new_thread_sp.get()),
 | |
|                             new_thread_sp->GetQueueID(), queue_name);
 | |
|               }
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     } else {
 | |
|       if (log)
 | |
|         log->Printf("SBThread(%p)::GetExtendedBacktraceThread() => error: "
 | |
|                     "process is running",
 | |
|                     static_cast<void *>(exe_ctx.GetThreadPtr()));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (log && sb_origin_thread.IsValid() == false)
 | |
|     log->Printf("SBThread(%p)::GetExtendedBacktraceThread() is not returning a "
 | |
|                 "Valid thread",
 | |
|                 static_cast<void *>(exe_ctx.GetThreadPtr()));
 | |
|   return sb_origin_thread;
 | |
| }
 | |
| 
 | |
| uint32_t SBThread::GetExtendedBacktraceOriginatingIndexID() {
 | |
|   ThreadSP thread_sp(m_opaque_sp->GetThreadSP());
 | |
|   if (thread_sp)
 | |
|     return thread_sp->GetExtendedBacktraceOriginatingIndexID();
 | |
|   return LLDB_INVALID_INDEX32;
 | |
| }
 | |
| 
 | |
| bool SBThread::SafeToCallFunctions() {
 | |
|   ThreadSP thread_sp(m_opaque_sp->GetThreadSP());
 | |
|   if (thread_sp)
 | |
|     return thread_sp->SafeToCallFunctions();
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| lldb_private::Thread *SBThread::operator->() {
 | |
|   ThreadSP thread_sp(m_opaque_sp->GetThreadSP());
 | |
|   if (thread_sp)
 | |
|     return thread_sp.get();
 | |
|   else
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| lldb_private::Thread *SBThread::get() {
 | |
|   ThreadSP thread_sp(m_opaque_sp->GetThreadSP());
 | |
|   if (thread_sp)
 | |
|     return thread_sp.get();
 | |
|   else
 | |
|     return NULL;
 | |
| }
 |