diff options
Diffstat (limited to 'source/Plugins/Process/Linux/NativeProcessLinux.cpp')
-rw-r--r-- | source/Plugins/Process/Linux/NativeProcessLinux.cpp | 280 |
1 files changed, 279 insertions, 1 deletions
diff --git a/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/source/Plugins/Process/Linux/NativeProcessLinux.cpp index e39a1788fc00..8e378802de9c 100644 --- a/source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ b/source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -289,7 +289,8 @@ Status NativeProcessProtocol::Attach( NativeProcessLinux::NativeProcessLinux() : NativeProcessProtocol(LLDB_INVALID_PROCESS_ID), m_arch(), m_supports_mem_region(eLazyBoolCalculate), m_mem_region_cache(), - m_pending_notification_tid(LLDB_INVALID_THREAD_ID) {} + m_pending_notification_tid(LLDB_INVALID_THREAD_ID), + m_pt_proces_trace_id(LLDB_INVALID_UID) {} void NativeProcessLinux::AttachToInferior(MainLoop &mainloop, lldb::pid_t pid, Status &error) { @@ -580,6 +581,7 @@ void NativeProcessLinux::MonitorCallback(lldb::pid_t pid, bool exited, info.si_pid); auto thread_sp = AddThread(pid); + // Resume the newly created thread. ResumeThread(*thread_sp, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER); ThreadWasCreated(*thread_sp); @@ -691,6 +693,7 @@ void NativeProcessLinux::WaitForNewThread(::pid_t tid) { LLDB_LOG(log, "pid = {0}: tracking new thread tid {1}", GetID(), tid); new_thread_sp = AddThread(tid); + ResumeThread(*new_thread_sp, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER); ThreadWasCreated(*new_thread_sp); } @@ -1301,6 +1304,9 @@ Status NativeProcessLinux::Detach() { e; // Save the error, but still attempt to detach from other threads. } + m_processor_trace_monitor.clear(); + m_pt_proces_trace_id = LLDB_INVALID_UID; + return error; } @@ -2089,6 +2095,8 @@ bool NativeProcessLinux::StopTrackingThread(lldb::tid_t thread_id) { } } + if (found) + StopTracingForThread(thread_id); SignalIfAllThreadsStopped(); return found; } @@ -2106,6 +2114,21 @@ NativeThreadLinuxSP NativeProcessLinux::AddThread(lldb::tid_t thread_id) { auto thread_sp = std::make_shared<NativeThreadLinux>(this, thread_id); m_threads.push_back(thread_sp); + + if (m_pt_proces_trace_id != LLDB_INVALID_UID) { + auto traceMonitor = ProcessorTraceMonitor::Create( + GetID(), thread_id, m_pt_process_trace_config, true); + if (traceMonitor) { + m_pt_traced_thread_group.insert(thread_id); + m_processor_trace_monitor.insert( + std::make_pair(thread_id, std::move(*traceMonitor))); + } else { + LLDB_LOG(log, "failed to start trace on thread {0}", thread_id); + Status error(traceMonitor.takeError()); + LLDB_LOG(log, "error {0}", error); + } + } + return thread_sp; } @@ -2405,3 +2428,258 @@ Status NativeProcessLinux::PtraceWrapper(int req, lldb::pid_t pid, void *addr, return error; } + +llvm::Expected<ProcessorTraceMonitor &> +NativeProcessLinux::LookupProcessorTraceInstance(lldb::user_id_t traceid, + lldb::tid_t thread) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); + if (thread == LLDB_INVALID_THREAD_ID && traceid == m_pt_proces_trace_id) { + LLDB_LOG(log, "thread not specified: {0}", traceid); + return Status("tracing not active thread not specified").ToError(); + } + + for (auto& iter : m_processor_trace_monitor) { + if (traceid == iter.second->GetTraceID() && + (thread == iter.first || thread == LLDB_INVALID_THREAD_ID)) + return *(iter.second); + } + + LLDB_LOG(log, "traceid not being traced: {0}", traceid); + return Status("tracing not active for this thread").ToError(); +} + +Status NativeProcessLinux::GetMetaData(lldb::user_id_t traceid, + lldb::tid_t thread, + llvm::MutableArrayRef<uint8_t> &buffer, + size_t offset) { + TraceOptions trace_options; + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); + Status error; + + LLDB_LOG(log, "traceid {0}", traceid); + + auto perf_monitor = LookupProcessorTraceInstance(traceid, thread); + if (!perf_monitor) { + LLDB_LOG(log, "traceid not being traced: {0}", traceid); + buffer = buffer.slice(buffer.size()); + error = perf_monitor.takeError(); + return error; + } + return (*perf_monitor).ReadPerfTraceData(buffer, offset); +} + +Status NativeProcessLinux::GetData(lldb::user_id_t traceid, lldb::tid_t thread, + llvm::MutableArrayRef<uint8_t> &buffer, + size_t offset) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); + Status error; + + LLDB_LOG(log, "traceid {0}", traceid); + + auto perf_monitor = LookupProcessorTraceInstance(traceid, thread); + if (!perf_monitor) { + LLDB_LOG(log, "traceid not being traced: {0}", traceid); + buffer = buffer.slice(buffer.size()); + error = perf_monitor.takeError(); + return error; + } + return (*perf_monitor).ReadPerfTraceAux(buffer, offset); +} + +Status NativeProcessLinux::GetTraceConfig(lldb::user_id_t traceid, + TraceOptions &config) { + Status error; + if (config.getThreadID() == LLDB_INVALID_THREAD_ID && + m_pt_proces_trace_id == traceid) { + if (m_pt_proces_trace_id == LLDB_INVALID_UID) { + error.SetErrorString("tracing not active for this process"); + return error; + } + config = m_pt_process_trace_config; + } else { + auto perf_monitor = + LookupProcessorTraceInstance(traceid, config.getThreadID()); + if (!perf_monitor) { + error = perf_monitor.takeError(); + return error; + } + error = (*perf_monitor).GetTraceConfig(config); + } + return error; +} + +lldb::user_id_t +NativeProcessLinux::StartTraceGroup(const TraceOptions &config, + Status &error) { + + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); + if (config.getType() != TraceType::eTraceTypeProcessorTrace) + return LLDB_INVALID_UID; + + if (m_pt_proces_trace_id != LLDB_INVALID_UID) { + error.SetErrorString("tracing already active on this process"); + return m_pt_proces_trace_id; + } + + for (const auto &thread_sp : m_threads) { + if (auto traceInstance = ProcessorTraceMonitor::Create( + GetID(), thread_sp->GetID(), config, true)) { + m_pt_traced_thread_group.insert(thread_sp->GetID()); + m_processor_trace_monitor.insert( + std::make_pair(thread_sp->GetID(), std::move(*traceInstance))); + } + } + + m_pt_process_trace_config = config; + error = ProcessorTraceMonitor::GetCPUType(m_pt_process_trace_config); + + // Trace on Complete process will have traceid of 0 + m_pt_proces_trace_id = 0; + + LLDB_LOG(log, "Process Trace ID {0}", m_pt_proces_trace_id); + return m_pt_proces_trace_id; +} + +lldb::user_id_t NativeProcessLinux::StartTrace(const TraceOptions &config, + Status &error) { + if (config.getType() != TraceType::eTraceTypeProcessorTrace) + return NativeProcessProtocol::StartTrace(config, error); + + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); + + lldb::tid_t threadid = config.getThreadID(); + + if (threadid == LLDB_INVALID_THREAD_ID) + return StartTraceGroup(config, error); + + auto thread_sp = GetThreadByID(threadid); + if (!thread_sp) { + // Thread not tracked by lldb so don't trace. + error.SetErrorString("invalid thread id"); + return LLDB_INVALID_UID; + } + + const auto &iter = m_processor_trace_monitor.find(threadid); + if (iter != m_processor_trace_monitor.end()) { + LLDB_LOG(log, "Thread already being traced"); + error.SetErrorString("tracing already active on this thread"); + return LLDB_INVALID_UID; + } + + auto traceMonitor = + ProcessorTraceMonitor::Create(GetID(), threadid, config, false); + if (!traceMonitor) { + error = traceMonitor.takeError(); + LLDB_LOG(log, "error {0}", error); + return LLDB_INVALID_UID; + } + lldb::user_id_t ret_trace_id = (*traceMonitor)->GetTraceID(); + m_processor_trace_monitor.insert( + std::make_pair(threadid, std::move(*traceMonitor))); + return ret_trace_id; +} + +Status NativeProcessLinux::StopTracingForThread(lldb::tid_t thread) { + Status error; + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); + LLDB_LOG(log, "Thread {0}", thread); + + const auto& iter = m_processor_trace_monitor.find(thread); + if (iter == m_processor_trace_monitor.end()) { + error.SetErrorString("tracing not active for this thread"); + return error; + } + + if (iter->second->GetTraceID() == m_pt_proces_trace_id) { + // traceid maps to the whole process so we have to erase it from the + // thread group. + LLDB_LOG(log, "traceid maps to process"); + m_pt_traced_thread_group.erase(thread); + } + m_processor_trace_monitor.erase(iter); + + return error; +} + +Status NativeProcessLinux::StopTrace(lldb::user_id_t traceid, + lldb::tid_t thread) { + Status error; + + TraceOptions trace_options; + trace_options.setThreadID(thread); + error = NativeProcessLinux::GetTraceConfig(traceid, trace_options); + + if (error.Fail()) + return error; + + switch (trace_options.getType()) { + case lldb::TraceType::eTraceTypeProcessorTrace: + if (traceid == m_pt_proces_trace_id && + thread == LLDB_INVALID_THREAD_ID) + StopProcessorTracingOnProcess(); + else + error = StopProcessorTracingOnThread(traceid, thread); + break; + default: + error.SetErrorString("trace not supported"); + break; + } + + return error; +} + +void NativeProcessLinux::StopProcessorTracingOnProcess() { + for (auto thread_id_iter : m_pt_traced_thread_group) + m_processor_trace_monitor.erase(thread_id_iter); + m_pt_traced_thread_group.clear(); + m_pt_proces_trace_id = LLDB_INVALID_UID; +} + +Status NativeProcessLinux::StopProcessorTracingOnThread(lldb::user_id_t traceid, + lldb::tid_t thread) { + Status error; + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); + + if (thread == LLDB_INVALID_THREAD_ID) { + for (auto& iter : m_processor_trace_monitor) { + if (iter.second->GetTraceID() == traceid) { + // Stopping a trace instance for an individual thread + // hence there will only be one traceid that can match. + m_processor_trace_monitor.erase(iter.first); + return error; + } + LLDB_LOG(log, "Trace ID {0}", iter.second->GetTraceID()); + } + + LLDB_LOG(log, "Invalid TraceID"); + error.SetErrorString("invalid trace id"); + return error; + } + + // thread is specified so we can use find function on the map. + const auto& iter = m_processor_trace_monitor.find(thread); + if (iter == m_processor_trace_monitor.end()) { + // thread not found in our map. + LLDB_LOG(log, "thread not being traced"); + error.SetErrorString("tracing not active for this thread"); + return error; + } + if (iter->second->GetTraceID() != traceid) { + // traceid did not match so it has to be invalid. + LLDB_LOG(log, "Invalid TraceID"); + error.SetErrorString("invalid trace id"); + return error; + } + + LLDB_LOG(log, "UID - {0} , Thread -{1}", traceid, thread); + + if (traceid == m_pt_proces_trace_id) { + // traceid maps to the whole process so we have to erase it from the + // thread group. + LLDB_LOG(log, "traceid maps to process"); + m_pt_traced_thread_group.erase(thread); + } + m_processor_trace_monitor.erase(iter); + + return error; +} |