LLDB  mainline
TraceIntelPT.cpp
Go to the documentation of this file.
1 //===-- TraceIntelPT.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 "TraceIntelPT.h"
10 
11 #include "../common/ThreadPostMortemTrace.h"
13 #include "DecodedThread.h"
14 #include "TraceIntelPTConstants.h"
18 #include "lldb/Target/Process.h"
19 #include "lldb/Target/Target.h"
20 #include "llvm/ADT/None.h"
21 
22 using namespace lldb;
23 using namespace lldb_private;
24 using namespace lldb_private::trace_intel_pt;
25 using namespace llvm;
26 
28 
29 lldb::CommandObjectSP
30 TraceIntelPT::GetProcessTraceStartCommand(CommandInterpreter &interpreter) {
31  return CommandObjectSP(
32  new CommandObjectProcessTraceStartIntelPT(*this, interpreter));
33 }
34 
35 lldb::CommandObjectSP
36 TraceIntelPT::GetThreadTraceStartCommand(CommandInterpreter &interpreter) {
37  return CommandObjectSP(
38  new CommandObjectThreadTraceStartIntelPT(*this, interpreter));
39 }
40 
41 void TraceIntelPT::Initialize() {
42  PluginManager::RegisterPlugin(GetPluginNameStatic(), "Intel Processor Trace",
43  CreateInstanceForSessionFile,
44  CreateInstanceForLiveProcess,
45  TraceIntelPTSessionFileParser::GetSchema());
46 }
47 
48 void TraceIntelPT::Terminate() {
49  PluginManager::UnregisterPlugin(CreateInstanceForSessionFile);
50 }
51 
52 StringRef TraceIntelPT::GetSchema() {
53  return TraceIntelPTSessionFileParser::GetSchema();
54 }
55 
56 void TraceIntelPT::Dump(Stream *s) const {}
57 
58 llvm::Error TraceIntelPT::SaveLiveTraceToDisk(FileSpec directory) {
59  RefreshLiveProcessState();
60  return TraceIntelPTSessionSaver().SaveToDisk(*this, directory);
61 }
62 
63 Expected<TraceSP> TraceIntelPT::CreateInstanceForSessionFile(
64  const json::Value &trace_session_file, StringRef session_file_dir,
65  Debugger &debugger) {
66  return TraceIntelPTSessionFileParser(debugger, trace_session_file,
67  session_file_dir)
68  .Parse();
69 }
70 
71 Expected<TraceSP> TraceIntelPT::CreateInstanceForLiveProcess(Process &process) {
72  TraceSP instance(new TraceIntelPT(process));
73  process.GetTarget().SetTrace(instance);
74  return instance;
75 }
76 
77 TraceIntelPT::TraceIntelPT(
78  const pt_cpu &cpu_info,
79  const std::vector<ThreadPostMortemTraceSP> &traced_threads)
80  : m_cpu_info(cpu_info) {
81  for (const ThreadPostMortemTraceSP &thread : traced_threads)
82  m_thread_decoders.emplace(
83  thread->GetID(),
84  std::make_unique<PostMortemThreadDecoder>(thread, *this));
85 }
86 
89  if (m_live_refresh_error.hasValue())
90  return std::make_shared<DecodedThread>(
91  thread.shared_from_this(),
92  createStringError(inconvertibleErrorCode(), *m_live_refresh_error));
93 
94  auto it = m_thread_decoders.find(thread.GetID());
95  if (it == m_thread_decoders.end())
96  return std::make_shared<DecodedThread>(
97  thread.shared_from_this(),
98  createStringError(inconvertibleErrorCode(), "thread not traced"));
99  return it->second->Decode();
100 }
101 
102 lldb::TraceCursorUP TraceIntelPT::GetCursor(Thread &thread) {
103  return Decode(thread)->GetCursor();
104 }
105 
106 void TraceIntelPT::DumpTraceInfo(Thread &thread, Stream &s, bool verbose) {
107  Optional<size_t> raw_size = GetRawTraceSize(thread);
108  s.Printf("\nthread #%u: tid = %" PRIu64, thread.GetIndexID(), thread.GetID());
109  if (!raw_size) {
110  s.Printf(", not traced\n");
111  return;
112  }
113  s.Printf("\n Raw trace size: %zu bytes\n", *raw_size);
114  return;
115 }
116 
117 Optional<size_t> TraceIntelPT::GetRawTraceSize(Thread &thread) {
118  if (IsTraced(thread.GetID()))
119  return Decode(thread)->GetRawTraceSize();
120  else
121  return None;
122 }
123 
125  Expected<std::vector<uint8_t>> cpu_info = GetLiveProcessBinaryData("cpuInfo");
126  if (!cpu_info)
127  return cpu_info.takeError();
128 
129  int64_t cpu_family = -1;
130  int64_t model = -1;
131  int64_t stepping = -1;
132  std::string vendor_id;
133 
134  StringRef rest(reinterpret_cast<const char *>(cpu_info->data()),
135  cpu_info->size());
136  while (!rest.empty()) {
137  StringRef line;
138  std::tie(line, rest) = rest.split('\n');
139 
140  SmallVector<StringRef, 2> columns;
141  line.split(columns, StringRef(":"), -1, false);
142 
143  if (columns.size() < 2)
144  continue; // continue searching
145 
146  columns[1] = columns[1].trim(" ");
147  if (columns[0].contains("cpu family") &&
148  columns[1].getAsInteger(10, cpu_family))
149  continue;
150 
151  else if (columns[0].contains("model") && columns[1].getAsInteger(10, model))
152  continue;
153 
154  else if (columns[0].contains("stepping") &&
155  columns[1].getAsInteger(10, stepping))
156  continue;
157 
158  else if (columns[0].contains("vendor_id")) {
159  vendor_id = columns[1].str();
160  if (!vendor_id.empty())
161  continue;
162  }
163 
164  if ((cpu_family != -1) && (model != -1) && (stepping != -1) &&
165  (!vendor_id.empty())) {
166  return pt_cpu{vendor_id == "GenuineIntel" ? pcv_intel : pcv_unknown,
167  static_cast<uint16_t>(cpu_family),
168  static_cast<uint8_t>(model),
169  static_cast<uint8_t>(stepping)};
170  }
171  }
172  return createStringError(inconvertibleErrorCode(),
173  "Failed parsing the target's /proc/cpuinfo file");
174 }
175 
176 Expected<pt_cpu> TraceIntelPT::GetCPUInfo() {
177  if (!m_cpu_info) {
178  if (llvm::Expected<pt_cpu> cpu_info = GetCPUInfoForLiveProcess())
179  m_cpu_info = *cpu_info;
180  else
181  return cpu_info.takeError();
182  }
183  return *m_cpu_info;
184 }
185 
187 
189  Expected<TraceGetStateResponse> state) {
190  m_thread_decoders.clear();
191 
192  if (!state) {
193  m_live_refresh_error = toString(state.takeError());
194  return;
195  }
196 
197  for (const TraceThreadState &thread_state : state->tracedThreads) {
198  Thread &thread =
200  m_thread_decoders.emplace(
201  thread_state.tid, std::make_unique<LiveThreadDecoder>(thread, *this));
202  }
203 }
204 
207  return m_thread_decoders.count(tid);
208 }
209 
210 // The information here should match the description of the intel-pt section
211 // of the jLLDBTraceStart packet in the lldb/docs/lldb-gdb-remote.txt
212 // documentation file. Similarly, it should match the CLI help messages of the
213 // TraceIntelPTOptions.td file.
215  return R"(Parameters:
216 
217  Note: If a parameter is not specified, a default value will be used.
218 
219  - int threadBufferSize (defaults to 4096 bytes):
220  [process and thread tracing]
221  Trace size in bytes per thread. It must be a power of 2 greater
222  than or equal to 4096 (2^12). The trace is circular keeping the
223  the most recent data.
224 
225  - boolean enableTsc (default to false):
226  [process and thread tracing]
227  Whether to use enable TSC timestamps or not. This is supported on
228  all devices that support intel-pt.
229 
230  - psbPeriod (defaults to null):
231  [process and thread tracing]
232  This value defines the period in which PSB packets will be generated.
233  A PSB packet is a synchronization packet that contains a TSC
234  timestamp and the current absolute instruction pointer.
235 
236  This parameter can only be used if
237 
238  /sys/bus/event_source/devices/intel_pt/caps/psb_cyc
239 
240  is 1. Otherwise, the PSB period will be defined by the processor.
241 
242  If supported, valid values for this period can be found in
243 
244  /sys/bus/event_source/devices/intel_pt/caps/psb_periods
245 
246  which contains a hexadecimal number, whose bits represent
247  valid values e.g. if bit 2 is set, then value 2 is valid.
248 
249  The psb_period value is converted to the approximate number of
250  raw trace bytes between PSB packets as:
251 
252  2 ^ (value + 11)
253 
254  e.g. value 3 means 16KiB between PSB packets. Defaults to 0 if
255  supported.
256 
257  - int processBufferSizeLimit (defaults to 500 MB):
258  [process tracing only]
259  Maximum total trace size per process in bytes. This limit applies
260  to the sum of the sizes of all thread traces of this process,
261  excluding the ones created explicitly with "thread tracing".
262  Whenever a thread is attempted to be traced due to this command
263  and the limit would be reached, the process is stopped with a
264  "processor trace" reason, so that the user can retrace the process
265  if needed.)";
266 }
267 
268 Error TraceIntelPT::Start(size_t thread_buffer_size,
269  size_t total_buffer_size_limit, bool enable_tsc,
270  Optional<size_t> psb_period) {
271  TraceIntelPTStartRequest request;
272  request.threadBufferSize = thread_buffer_size;
273  request.processBufferSizeLimit = total_buffer_size_limit;
274  request.enableTsc = enable_tsc;
275  request.psbPeriod = psb_period.map([](size_t val) { return (int64_t)val; });
276  request.type = GetPluginName().str();
277  return Trace::Start(toJSON(request));
278 }
279 
281  size_t thread_buffer_size = kDefaultThreadBufferSize;
282  size_t process_buffer_size_limit = kDefaultProcessBufferSizeLimit;
283  bool enable_tsc = kDefaultEnableTscValue;
284  Optional<size_t> psb_period = kDefaultPsbPeriod;
285 
286  if (configuration) {
287  if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) {
288  dict->GetValueForKeyAsInteger("threadBufferSize", thread_buffer_size);
289  dict->GetValueForKeyAsInteger("processBufferSizeLimit",
290  process_buffer_size_limit);
291  dict->GetValueForKeyAsBoolean("enableTsc", enable_tsc);
292  dict->GetValueForKeyAsInteger("psbPeriod", psb_period);
293  } else {
294  return createStringError(inconvertibleErrorCode(),
295  "configuration object is not a dictionary");
296  }
297  }
298 
299  return Start(thread_buffer_size, process_buffer_size_limit, enable_tsc,
300  psb_period);
301 }
302 
303 llvm::Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,
304  size_t thread_buffer_size, bool enable_tsc,
305  Optional<size_t> psb_period) {
306  TraceIntelPTStartRequest request;
307  request.threadBufferSize = thread_buffer_size;
308  request.enableTsc = enable_tsc;
309  request.psbPeriod = psb_period.map([](size_t val) { return (int64_t)val; });
310  request.type = GetPluginName().str();
311  request.tids.emplace();
312  for (lldb::tid_t tid : tids)
313  request.tids->push_back(tid);
314  return Trace::Start(toJSON(request));
315 }
316 
317 Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,
318  StructuredData::ObjectSP configuration) {
319  size_t thread_buffer_size = kDefaultThreadBufferSize;
320  bool enable_tsc = kDefaultEnableTscValue;
321  Optional<size_t> psb_period = kDefaultPsbPeriod;
322 
323  if (configuration) {
324  if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) {
325  dict->GetValueForKeyAsInteger("threadBufferSize", thread_buffer_size);
326  dict->GetValueForKeyAsBoolean("enableTsc", enable_tsc);
327  dict->GetValueForKeyAsInteger("psbPeriod", psb_period);
328  } else {
329  return createStringError(inconvertibleErrorCode(),
330  "configuration object is not a dictionary");
331  }
332  }
333 
334  return Start(tids, thread_buffer_size, enable_tsc, psb_period);
335 }
336 
337 Expected<std::vector<uint8_t>>
339  return Trace::GetLiveThreadBinaryData(tid, "threadTraceBuffer");
340 }
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
llvm
Definition: Debugger.h:49
TraceIntelPTSessionSaver.h
CommandObjectTraceStartIntelPT.h
lldb_private::StructuredData::Dictionary
Definition: StructuredData.h:352
lldb_private::trace_intel_pt::TraceIntelPT::GetPluginName
llvm::StringRef GetPluginName() override
PluginInterface protocol.
Definition: TraceIntelPT.h:31
lldb_private::Trace::GetLiveProcessBinaryData
llvm::Expected< llvm::ArrayRef< uint8_t > > GetLiveProcessBinaryData(llvm::StringRef kind)
Get binary data of the current process given a data identifier.
Definition: Trace.cpp:164
TraceIntelPTSessionFileParser.h
lldb_private::Thread::GetIndexID
uint32_t GetIndexID() const
Definition: Thread.cpp:1379
lldb_private::TraceStartRequest::type
std::string type
Tracing technology name, e.g. intel-pt, arm-coresight.
Definition: TraceGDBRemotePackets.h:43
lldb_private::trace_intel_pt::TraceIntelPT::DoRefreshLiveProcessState
void DoRefreshLiveProcessState(llvm::Expected< TraceGetStateResponse > state) override
Method to be overriden by the plug-in to refresh its own state.
Definition: TraceIntelPT.cpp:188
lldb_private::TraceThreadState::tid
int64_t tid
Definition: TraceGDBRemotePackets.h:109
lldb_private::trace_intel_pt::TraceIntelPT::Start
llvm::Error Start(size_t thread_buffer_size, size_t total_buffer_size_limit, bool enable_tsc, llvm::Optional< size_t > psb_period)
Start tracing a live process.
lldb_private::Process
Definition: Process.h:338
lldb_private::Process::GetThreadList
ThreadList & GetThreadList()
Definition: Process.h:2075
lldb_private::TraceIntelPTStartRequest::enableTsc
bool enableTsc
Whether to enable TSC.
Definition: TraceIntelPTGDBRemotePackets.h:24
lldb_private::Process::GetTarget
Target & GetTarget()
Get the target object pointer for this module.
Definition: Process.h:1206
lldb_private::trace_intel_pt::TraceIntelPT
Definition: TraceIntelPT.h:21
lldb_private::Stream
Definition: Stream.h:28
lldb_private::Trace::RefreshLiveProcessState
void RefreshLiveProcessState()
Method to be invoked by the plug-in to refresh the live process state.
Definition: Trace.cpp:179
lldb_private::trace_intel_pt::TraceIntelPT::m_live_refresh_error
llvm::Optional< std::string > m_live_refresh_error
Error gotten after a failed live process update, if any.
Definition: TraceIntelPT.h:185
lldb_private::trace_intel_pt::TraceIntelPTSessionSaver
Definition: TraceIntelPTSessionSaver.h:21
lldb_private::trace_intel_pt::TraceIntelPT::GetLiveThreadBuffer
llvm::Expected< std::vector< uint8_t > > GetLiveThreadBuffer(lldb::tid_t tid)
Get the thread buffer content for a live thread.
Definition: TraceIntelPT.cpp:338
Process.h
lldb_private::trace_intel_pt::TraceIntelPT::GetStartConfigurationHelp
const char * GetStartConfigurationHelp() override
Definition: TraceIntelPT.cpp:214
Target.h
lldb_private::FileSpec
Definition: FileSpec.h:56
lldb_private::ThreadList::FindThreadByID
lldb::ThreadSP FindThreadByID(lldb::tid_t tid, bool can_update=true)
Definition: ThreadList.cpp:102
lldb_private::trace_intel_pt::CommandObjectThreadTraceStartIntelPT
Definition: CommandObjectTraceStartIntelPT.h:20
lldb_private::trace_intel_pt::TraceIntelPT::GetCursor
lldb::TraceCursorUP GetCursor(Thread &thread) override
Get a TraceCursor for the given thread's trace.
Definition: TraceIntelPT.cpp:102
lldb_private::trace_intel_pt::kDefaultThreadBufferSize
const size_t kDefaultThreadBufferSize
Definition: TraceIntelPTConstants.h:19
lldb_private::Thread
Definition: Thread.h:60
DecodedThread.h
lldb_private::TraceIntelPTStartRequest::psbPeriod
llvm::Optional< int64_t > psbPeriod
PSB packet period.
Definition: TraceIntelPTGDBRemotePackets.h:27
lldb_private::StructuredData::ObjectSP
std::shared_ptr< Object > ObjectSP
Definition: StructuredData.h:59
lldb_private::trace_intel_pt::kDefaultProcessBufferSizeLimit
const size_t kDefaultProcessBufferSizeLimit
Definition: TraceIntelPTConstants.h:20
lldb_private::TraceIntelPTStartRequest
jLLDBTraceStart gdb-remote packet
Definition: TraceIntelPTGDBRemotePackets.h:19
lldb_private::trace_intel_pt::TraceIntelPT::m_thread_decoders
std::map< lldb::tid_t, std::unique_ptr< ThreadDecoder > > m_thread_decoders
Definition: TraceIntelPT.h:183
lldb_private::CommandInterpreter
Definition: CommandInterpreter.h:214
lldb_private::trace_intel_pt::TraceIntelPT::GetRawTraceSize
llvm::Optional< size_t > GetRawTraceSize(Thread &thread)
Definition: TraceIntelPT.cpp:117
lldb_private::Trace::GetLiveThreadBinaryData
llvm::Expected< llvm::ArrayRef< uint8_t > > GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind)
Get binary data of a live thread given a data identifier.
Definition: Trace.cpp:146
lldb_private::Debugger
Definition: Debugger.h:70
lldb_private::TraceIntelPTStartRequest::threadBufferSize
int64_t threadBufferSize
Size in bytes to use for each thread's trace buffer.
Definition: TraceIntelPTGDBRemotePackets.h:21
string
string(SUBSTRING ${p} 10 -1 pStripped) if($
Definition: Plugins/CMakeLists.txt:40
lldb_private::Trace::Start
virtual llvm::Error Start(StructuredData::ObjectSP configuration=StructuredData::ObjectSP())=0
Start tracing a live process.
lldb_private::trace_intel_pt::TraceIntelPT::IsTraced
bool IsTraced(lldb::tid_t tid) override
Check if a thread is currently traced by this object.
Definition: TraceIntelPT.cpp:205
lldb_private::Target::SetTrace
void SetTrace(const lldb::TraceSP &trace_sp)
Set the Trace object containing processor trace information of this target.
Definition: Target.cpp:3134
lldb_private::UserID::GetID
lldb::user_id_t GetID() const
Get accessor for the user ID.
Definition: UserID.h:47
lldb_private::trace_intel_pt::kDefaultEnableTscValue
const bool kDefaultEnableTscValue
Definition: TraceIntelPTConstants.h:21
lldb_private::Trace::m_live_process
Process * m_live_process
Process traced by this object if doing live tracing. Otherwise it's null.
Definition: Trace.h:317
lldb_private::trace_intel_pt::TraceIntelPT::DumpTraceInfo
void DumpTraceInfo(Thread &thread, Stream &s, bool verbose) override
Dump general info about a given thread's trace.
Definition: TraceIntelPT.cpp:106
lldb_private::TraceIntelPTStartRequest::processBufferSizeLimit
llvm::Optional< int64_t > processBufferSizeLimit
Required when doing "process tracing".
Definition: TraceIntelPTGDBRemotePackets.h:34
lldb_private::trace_intel_pt::TraceIntelPTSessionFileParser
Definition: TraceIntelPTSessionFileParser.h:21
TraceIntelPTConstants.h
lldb_private::trace_intel_pt::TraceIntelPT::GetLiveProcess
Process * GetLiveProcess()
Get the current traced live process.
Definition: TraceIntelPT.cpp:186
lldb_private::StructuredData::Object::GetAsDictionary
Dictionary * GetAsDictionary()
Definition: StructuredData.h:91
uint16_t
PluginManager.h
lldb_private::Stream::Printf
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:107
lldb_private::trace_intel_pt::TraceIntelPT::GetCPUInfoForLiveProcess
llvm::Expected< pt_cpu > GetCPUInfoForLiveProcess()
Definition: TraceIntelPT.cpp:124
lldb_private::trace_intel_pt::DecodedThreadSP
std::shared_ptr< DecodedThread > DecodedThreadSP
Definition: DecodedThread.h:159
lldb_private::trace_intel_pt::TraceIntelPTSessionSaver::SaveToDisk
llvm::Error SaveToDisk(TraceIntelPT &trace_ipt, FileSpec directory)
Save the Intel PT trace of a live process to the specified directory, which will be created if needed...
Definition: TraceIntelPTSessionSaver.cpp:34
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
lldb_private::trace_intel_pt::TraceIntelPT::m_cpu_info
llvm::Optional< pt_cpu > m_cpu_info
It is provided by either a session file or a live process' "cpuInfo" binary data.
Definition: TraceIntelPT.h:182
Error
llvm::Error Error
Definition: UdtRecordCompleter.cpp:29
lldb_private::TraceStartRequest::tids
llvm::Optional< std::vector< int64_t > > tids
If llvm::None, then this starts tracing the whole process.
Definition: TraceGDBRemotePackets.h:47
lldb_private::trace_intel_pt::kDefaultPsbPeriod
const llvm::Optional< size_t > kDefaultPsbPeriod
Definition: TraceIntelPTConstants.h:22
lldb_private::trace_intel_pt::TraceIntelPT::GetCPUInfo
llvm::Expected< pt_cpu > GetCPUInfo()
Definition: TraceIntelPT.cpp:176
lldb_private::trace_intel_pt
Definition: CommandObjectTraceStartIntelPT.h:18
LLDB_PLUGIN_DEFINE
#define LLDB_PLUGIN_DEFINE(PluginName)
Definition: PluginManager.h:31
lldb_private::trace_intel_pt::TraceIntelPTSessionFileParser::Parse
llvm::Expected< lldb::TraceSP > Parse()
Parse the structured data trace session and create the corresponding Target objects.
Definition: TraceIntelPTSessionFileParser.cpp:57
lldb
Definition: SBAddress.h:15
lldb_private::trace_intel_pt::TraceIntelPT::Decode
DecodedThreadSP Decode(Thread &thread)
Decode the trace of the given thread that, i.e.
Definition: TraceIntelPT.cpp:87
TraceIntelPT.h
lldb_private::trace_intel_pt::CommandObjectProcessTraceStartIntelPT
Definition: CommandObjectTraceStartIntelPT.h:64
lldb::tid_t
uint64_t tid_t
Definition: lldb-types.h:86
lldb_private::TraceThreadState
Definition: TraceGDBRemotePackets.h:108