aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
diff options
context:
space:
mode:
authorRavitheja Addepally <ravitheja.addepally@intel.com>2017-06-28 07:58:31 +0000
committerRavitheja Addepally <ravitheja.addepally@intel.com>2017-06-28 07:58:31 +0000
commit99e376956d6fd12641f8515fb019e9220a2e477f (patch)
tree8a32df6c60408b749b136bab4e0ad149758e872f /lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
parenteecb353d0e25bae018bad815f9169c73666af5bd (diff)
downloadllvm-99e376956d6fd12641f8515fb019e9220a2e477f.tar.gz
llvm-99e376956d6fd12641f8515fb019e9220a2e477f.tar.bz2
llvm-99e376956d6fd12641f8515fb019e9220a2e477f.zip
Implementation of Intel(R) Processor Trace support for Linux
Summary: This patch implements support for Intel(R) Processor Trace in lldb server. The changes have support for starting/stopping and reading the trace data. The code is only available on Linux versions where the perf attributes for aux buffers are available. The patch also consists of Unit tests for testing the core buffer reading function. Reviewers: lldb-commits, labath, clayborg, zturner, tberghammer Reviewed By: labath, clayborg Subscribers: mgorny Differential Revision: https://reviews.llvm.org/D33674 llvm-svn: 306516
Diffstat (limited to 'lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp')
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp280
1 files changed, 279 insertions, 1 deletions
diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
index e39a1788fc00..8e378802de9c 100644
--- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ b/lldb/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;
+}