LLDB  mainline
IntelPTCollector.cpp
Go to the documentation of this file.
1 //===-- IntelPTCollector.cpp ------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "IntelPTCollector.h"
10 
11 #include "Perf.h"
12 #include "Procfs.h"
13 
17 
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/Support/Error.h"
20 #include "llvm/Support/MathExtras.h"
21 
22 #include <algorithm>
23 #include <cstddef>
24 #include <fstream>
25 #include <linux/perf_event.h>
26 #include <sstream>
27 #include <sys/ioctl.h>
28 #include <sys/syscall.h>
29 
30 using namespace lldb;
31 using namespace lldb_private;
32 using namespace process_linux;
33 using namespace llvm;
34 
35 IntelPTCollector::IntelPTCollector(NativeProcessProtocol &process)
36  : m_process(process) {}
37 
38 llvm::Expected<LinuxPerfZeroTscConversion &>
40  if (Expected<LinuxPerfZeroTscConversion> tsc_conversion =
42  return *tsc_conversion;
43  else
44  return createStringError(inconvertibleErrorCode(),
45  "Unable to load TSC to wall time conversion: %s",
46  toString(tsc_conversion.takeError()).c_str());
47 }
48 
50  if (m_process_trace_up && m_process_trace_up->TracesThread(tid))
51  return m_process_trace_up->TraceStop(tid);
52  return m_thread_traces.TraceStop(tid);
53 }
54 
56  if (request.IsProcessTracing()) {
57  Clear();
58  return Error::success();
59  } else {
60  Error error = Error::success();
61  for (int64_t tid : *request.tids)
62  error = joinErrors(std::move(error),
63  TraceStop(static_cast<lldb::tid_t>(tid)));
64  return error;
65  }
66 }
67 
69  if (request.IsProcessTracing()) {
70  if (m_process_trace_up) {
71  return createStringError(
72  inconvertibleErrorCode(),
73  "Process currently traced. Stop process tracing first");
74  }
75  if (request.IsPerCpuTracing()) {
77  return createStringError(
78  inconvertibleErrorCode(),
79  "Threads currently traced. Stop tracing them first.");
80  // CPU tracing is useless if we can't convert tsc to nanos.
81  Expected<LinuxPerfZeroTscConversion &> tsc_conversion =
83  if (!tsc_conversion)
84  return tsc_conversion.takeError();
85 
86  // We force the enabledment of TSCs, which is needed for correlating the
87  // cpu traces.
88  TraceIntelPTStartRequest effective_request = request;
89  effective_request.enable_tsc = true;
90 
91  if (Expected<IntelPTProcessTraceUP> trace =
93  m_process)) {
94  m_process_trace_up = std::move(*trace);
95  return Error::success();
96  } else {
97  return trace.takeError();
98  }
99  } else {
100  std::vector<lldb::tid_t> process_threads;
101  for (NativeThreadProtocol &thread : m_process.Threads())
102  process_threads.push_back(thread.GetID());
103 
104  // per-thread process tracing
105  if (Expected<IntelPTProcessTraceUP> trace =
106  IntelPTPerThreadProcessTrace::Start(request, process_threads)) {
107  m_process_trace_up = std::move(trace.get());
108  return Error::success();
109  } else {
110  return trace.takeError();
111  }
112  }
113  } else {
114  // individual thread tracing
115  Error error = Error::success();
116  for (int64_t tid : *request.tids) {
117  if (m_process_trace_up && m_process_trace_up->TracesThread(tid))
118  error = joinErrors(
119  std::move(error),
120  createStringError(inconvertibleErrorCode(),
121  formatv("Thread with tid {0} is currently "
122  "traced. Stop tracing it first.",
123  tid)
124  .str()
125  .c_str()));
126  else
127  error = joinErrors(std::move(error),
128  m_thread_traces.TraceStart(tid, request));
129  }
130  return error;
131  }
132 }
133 
135  if (m_process_trace_up)
136  m_process_trace_up->ProcessWillResume();
137 }
138 
140  if (m_process_trace_up)
141  m_process_trace_up->ProcessDidStop();
142 }
143 
145  if (m_process_trace_up)
146  return m_process_trace_up->TraceStart(tid);
147 
148  return Error::success();
149 }
150 
152  if (m_process_trace_up && m_process_trace_up->TracesThread(tid))
153  return m_process_trace_up->TraceStop(tid);
154  else if (m_thread_traces.TracesThread(tid))
155  return m_thread_traces.TraceStop(tid);
156  return Error::success();
157 }
158 
159 Expected<json::Value> IntelPTCollector::GetState() {
160  Expected<ArrayRef<uint8_t>> cpu_info = GetProcfsCpuInfo();
161  if (!cpu_info)
162  return cpu_info.takeError();
163 
165  if (m_process_trace_up)
166  state = m_process_trace_up->GetState();
167 
168  state.process_binary_data.push_back(
169  {IntelPTDataKinds::kProcFsCpuInfo, cpu_info->size()});
170 
172  [&](lldb::tid_t tid, const IntelPTSingleBufferTrace &thread_trace) {
173  state.traced_threads.push_back(
174  {tid,
175  {{IntelPTDataKinds::kIptTrace, thread_trace.GetIptTraceSize()}}});
176  });
177 
178  if (Expected<LinuxPerfZeroTscConversion &> tsc_conversion =
180  state.tsc_perf_zero_conversion = *tsc_conversion;
181  else
182  state.AddWarning(toString(tsc_conversion.takeError()));
183  return toJSON(state);
184 }
185 
186 Expected<std::vector<uint8_t>>
188  if (request.kind == IntelPTDataKinds::kProcFsCpuInfo)
189  return GetProcfsCpuInfo();
190 
191  if (m_process_trace_up) {
192  Expected<Optional<std::vector<uint8_t>>> data =
193  m_process_trace_up->TryGetBinaryData(request);
194  if (!data)
195  return data.takeError();
196  if (*data)
197  return **data;
198  }
199 
200  {
201  Expected<Optional<std::vector<uint8_t>>> data =
203  if (!data)
204  return data.takeError();
205  if (*data)
206  return **data;
207  }
208 
209  return createStringError(
210  inconvertibleErrorCode(),
211  formatv("Can't fetch data kind {0} for cpu_id {1}, tid {2} and "
212  "\"process tracing\" mode {3}",
213  request.kind, request.cpu_id, request.tid,
214  m_process_trace_up ? "enabled" : "not enabled"));
215 }
216 
218  if (Expected<uint32_t> intel_pt_type = GetIntelPTOSEventType()) {
219  return true;
220  } else {
221  llvm::consumeError(intel_pt_type.takeError());
222  return false;
223  }
224 }
225 
227  m_process_trace_up.reset();
229 }
lldb_private::toString
const char * toString(AppleArm64ExceptionClass EC)
Definition: AppleArm64ExceptionClass.h:38
lldb_private::toJSON
llvm::json::Value toJSON(const TraceSupportedResponse &packet)
Definition: TraceGDBRemotePackets.cpp:24
lldb_private::TraceStopRequest::IsProcessTracing
bool IsProcessTracing() const
Definition: TraceGDBRemotePackets.cpp:54
lldb_private::TraceGetStateResponse::traced_threads
std::vector< TraceThreadState > traced_threads
Definition: TraceGDBRemotePackets.h:133
lldb_private::TraceGetBinaryDataRequest::kind
std::string kind
Identifier for the data.
Definition: TraceGDBRemotePackets.h:153
llvm
Definition: Debugger.h:50
lldb_private::process_linux::IntelPTCollector::IsSupported
static bool IsSupported()
Definition: IntelPTCollector.cpp:217
lldb_private::TraceGetBinaryDataRequest
jLLDBTraceGetBinaryData gdb-remote packet
Definition: TraceGDBRemotePackets.h:149
lldb_private::process_linux::LoadPerfTscConversionParameters
llvm::Expected< LinuxPerfZeroTscConversion > LoadPerfTscConversionParameters()
Load PerfTscConversionParameters from perf_event_mmap_page, if available.
Definition: Perf.cpp:29
lldb_private::NativeThreadProtocol
Definition: NativeThreadProtocol.h:24
lldb_private::NativeProcessProtocol::Threads
ThreadIterable Threads() const
Definition: NativeProcessProtocol.h:224
lldb_private::TraceIntelPTStartRequest::IsPerCpuTracing
bool IsPerCpuTracing() const
Definition: TraceIntelPTGDBRemotePackets.cpp:21
lldb_private::TraceStopRequest::tids
llvm::Optional< std::vector< lldb::tid_t > > tids
If llvm::None, then this stops tracing the whole process.
Definition: TraceGDBRemotePackets.h:77
lldb_private::TraceIntelPTGetStateResponse
Definition: TraceIntelPTGDBRemotePackets.h:107
lldb_private::TraceGetStateResponse::process_binary_data
std::vector< TraceBinaryData > process_binary_data
Definition: TraceGDBRemotePackets.h:134
lldb_private::TraceStartRequest::tids
llvm::Optional< std::vector< lldb::tid_t > > tids
If llvm::None, then this starts tracing the whole process.
Definition: TraceGDBRemotePackets.h:49
lldb_private::process_linux::IntelPTCollector::TraceStop
llvm::Error TraceStop(const TraceStopRequest &request)
Implementation of the jLLDBTraceStop packet.
Definition: IntelPTCollector.cpp:55
Procfs.h
lldb_private::process_linux::IntelPTCollector::m_process
NativeProcessProtocol & m_process
The target process.
Definition: IntelPTCollector.h:82
error
static llvm::raw_ostream & error(Stream &strm)
Definition: CommandReturnObject.cpp:17
lldb_private::TraceStartRequest::IsProcessTracing
bool IsProcessTracing() const
jLLDBTraceStart
Definition: TraceGDBRemotePackets.cpp:32
lldb_private::process_linux::IntelPTCollector::GetBinaryData
llvm::Expected< std::vector< uint8_t > > GetBinaryData(const TraceGetBinaryDataRequest &request)
Implementation of the jLLDBTraceGetBinaryData packet.
Definition: IntelPTCollector.cpp:187
lldb_private::process_linux::IntelPTThreadTraceCollection::TracesThread
bool TracesThread(lldb::tid_t tid) const
Definition: IntelPTThreadTraceCollection.cpp:16
lldb_private::process_linux::IntelPTSingleBufferTrace::GetIptTraceSize
size_t GetIptTraceSize() const
Definition: IntelPTSingleBufferTrace.cpp:204
lldb_private::process_linux::IntelPTCollector::Clear
void Clear()
Dispose of all traces.
Definition: IntelPTCollector.cpp:226
lldb_private::process_linux::IntelPTSingleBufferTrace
This class wraps a single perf event collecting intel pt data in a single buffer.
Definition: IntelPTSingleBufferTrace.h:28
lldb_private::process_linux::IntelPTCollector::TraceStart
llvm::Error TraceStart(const TraceIntelPTStartRequest &request)
Implementation of the jLLDBTraceStart packet.
Definition: IntelPTCollector.cpp:68
StreamString.h
lldb_private::process_linux::IntelPTCollector::OnThreadCreated
llvm::Error OnThreadCreated(lldb::tid_t tid)
If "process tracing" is enabled, then trace the given thread.
Definition: IntelPTCollector.cpp:144
lldb_private::process_linux::IntelPTPerThreadProcessTrace::Start
static llvm::Expected< std::unique_ptr< IntelPTPerThreadProcessTrace > > Start(const TraceIntelPTStartRequest &request, llvm::ArrayRef< lldb::tid_t > current_tids)
Start tracing the current process by tracing each of its tids individually.
Definition: IntelPTPerThreadProcessTrace.cpp:55
lldb_private::TraceGetStateResponse::AddWarning
void AddWarning(llvm::StringRef warning)
Definition: TraceGDBRemotePackets.cpp:113
lldb_private::TraceIntelPTStartRequest
jLLDBTraceStart gdb-remote packet
Definition: TraceIntelPTGDBRemotePackets.h:33
ProcessPOSIXLog.h
lldb_private::process_linux::IntelPTCollector::ProcessWillResume
void ProcessWillResume()
To be invoked before the process will resume, so that we can capture the first instructions after the...
Definition: IntelPTCollector.cpp:134
lldb_private::process_linux::GetProcfsCpuInfo
llvm::Expected< llvm::ArrayRef< uint8_t > > GetProcfsCpuInfo()
Definition: Procfs.cpp:19
lldb_private::IntelPTDataKinds::kIptTrace
static const char * kIptTrace
Definition: TraceIntelPTGDBRemotePackets.h:27
lldb_private::process_linux::IntelPTThreadTraceCollection::ForEachThread
void ForEachThread(std::function< void(lldb::tid_t tid, IntelPTSingleBufferTrace &thread_trace)> callback)
Execute the provided callback on each thread that is being traced.
Definition: IntelPTThreadTraceCollection.cpp:50
IntelPTCollector.h
lldb_private::TraceStopRequest
jLLDBTraceStop gdb-remote packet
Definition: TraceGDBRemotePackets.h:64
lldb_private::process_linux::IntelPTCollector::OnThreadDestroyed
llvm::Error OnThreadDestroyed(lldb::tid_t tid)
Stops tracing a tracing upon a destroy event.
Definition: IntelPTCollector.cpp:151
lldb_private::process_linux::IntelPTThreadTraceCollection::TraceStart
llvm::Error TraceStart(lldb::tid_t tid, const TraceIntelPTStartRequest &request)
Start tracing the thread given by its tid.
Definition: IntelPTThreadTraceCollection.cpp:30
lldb_private::process_linux::IntelPTThreadTraceCollection::Clear
void Clear()
Dispose of all traces.
Definition: IntelPTThreadTraceCollection.cpp:66
Support.h
lldb_private::NativeProcessProtocol
Definition: NativeProcessProtocol.h:48
lldb_private::process_linux::IntelPTCollector::m_thread_traces
IntelPTThreadTraceCollection m_thread_traces
Threads traced due to "thread tracing".
Definition: IntelPTCollector.h:84
lldb_private::TraceGetBinaryDataRequest::tid
llvm::Optional< lldb::tid_t > tid
Optional tid if the data is related to a thread.
Definition: TraceGDBRemotePackets.h:155
lldb_private::TraceIntelPTStartRequest::enable_tsc
bool enable_tsc
Whether to enable TSC.
Definition: TraceIntelPTGDBRemotePackets.h:38
Perf.h
lldb_private::TraceGetBinaryDataRequest::cpu_id
llvm::Optional< lldb::cpu_id_t > cpu_id
Optional core id if the data is related to a cpu core.
Definition: TraceGDBRemotePackets.h:157
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
lldb_private::process_linux::IntelPTCollector::ProcessDidStop
void ProcessDidStop()
To be invoked as soon as we know the process stopped.
Definition: IntelPTCollector.cpp:139
lldb_private::process_linux::IntelPTThreadTraceCollection::TraceStop
llvm::Error TraceStop(lldb::tid_t tid)
Stop tracing the thread given by its tid.
Definition: IntelPTThreadTraceCollection.cpp:20
lldb_private::process_linux::IntelPTThreadTraceCollection::GetTracedThreadsCount
size_t GetTracedThreadsCount() const
Definition: IntelPTThreadTraceCollection.cpp:71
Error
llvm::Error Error
Definition: UdtRecordCompleter.cpp:30
lldb_private::process_linux::IntelPTMultiCoreTrace::StartOnAllCores
static llvm::Expected< std::unique_ptr< IntelPTMultiCoreTrace > > StartOnAllCores(const TraceIntelPTStartRequest &request, NativeProcessProtocol &process)
Start tracing all CPU cores.
Definition: IntelPTMultiCoreTrace.cpp:37
lldb_private::process_linux::IntelPTCollector::GetState
llvm::Expected< llvm::json::Value > GetState()
Implementation of the jLLDBTraceGetState packet.
Definition: IntelPTCollector.cpp:159
lldb_private::process_linux::GetIntelPTOSEventType
llvm::Expected< uint32_t > GetIntelPTOSEventType()
Return the Linux perf event type for Intel PT.
Definition: IntelPTSingleBufferTrace.cpp:111
lldb_private::process_linux::IntelPTCollector::m_process_trace_up
IntelPTProcessTraceUP m_process_trace_up
Only one instance of "process trace" can be active at a given time.
Definition: IntelPTCollector.h:88
lldb_private::TraceIntelPTGetStateResponse::tsc_perf_zero_conversion
llvm::Optional< LinuxPerfZeroTscConversion > tsc_perf_zero_conversion
The TSC to wall time conversion if it exists, otherwise nullptr.
Definition: TraceIntelPTGDBRemotePackets.h:109
lldb_private::process_linux::IntelPTCollector::FetchPerfTscConversionParameters
llvm::Expected< LinuxPerfZeroTscConversion & > FetchPerfTscConversionParameters()
Definition: IntelPTCollector.cpp:39
lldb
Definition: SBAddress.h:15
lldb_private::process_linux::IntelPTThreadTraceCollection::TryGetBinaryData
llvm::Expected< llvm::Optional< std::vector< uint8_t > > > TryGetBinaryData(const TraceGetBinaryDataRequest &request)
Definition: IntelPTThreadTraceCollection.cpp:76
lldb_private::IntelPTDataKinds::kProcFsCpuInfo
static const char * kProcFsCpuInfo
Definition: TraceIntelPTGDBRemotePackets.h:26
lldb::tid_t
uint64_t tid_t
Definition: lldb-types.h:86