summaryrefslogtreecommitdiff
path: root/source/Plugins/Process/Linux/NativeProcessLinux.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Plugins/Process/Linux/NativeProcessLinux.cpp')
-rw-r--r--source/Plugins/Process/Linux/NativeProcessLinux.cpp280
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;
+}