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 ConstString TraceIntelPT::GetPluginNameStatic() {
53  static ConstString g_name("intel-pt");
54  return g_name;
55 }
56 
57 StringRef TraceIntelPT::GetSchema() {
58  return TraceIntelPTSessionFileParser::GetSchema();
59 }
60 
61 void TraceIntelPT::Dump(Stream *s) const {}
62 
63 llvm::Error TraceIntelPT::SaveLiveTraceToDisk(FileSpec directory) {
64  RefreshLiveProcessState();
65  return TraceIntelPTSessionSaver().SaveToDisk(*this, directory);
66 }
67 
68 Expected<TraceSP> TraceIntelPT::CreateInstanceForSessionFile(
69  const json::Value &trace_session_file, StringRef session_file_dir,
70  Debugger &debugger) {
71  return TraceIntelPTSessionFileParser(debugger, trace_session_file,
72  session_file_dir)
73  .Parse();
74 }
75 
76 Expected<TraceSP> TraceIntelPT::CreateInstanceForLiveProcess(Process &process) {
77  TraceSP instance(new TraceIntelPT(process));
78  process.GetTarget().SetTrace(instance);
79  return instance;
80 }
81 
82 TraceIntelPT::TraceIntelPT(
83  const pt_cpu &cpu_info,
84  const std::vector<ThreadPostMortemTraceSP> &traced_threads)
85  : m_cpu_info(cpu_info) {
86  for (const ThreadPostMortemTraceSP &thread : traced_threads)
87  m_thread_decoders.emplace(
88  thread->GetID(),
89  std::make_unique<PostMortemThreadDecoder>(thread, *this));
90 }
91 
94  if (m_live_refresh_error.hasValue())
95  return std::make_shared<DecodedThread>(
96  thread.shared_from_this(),
97  createStringError(inconvertibleErrorCode(), *m_live_refresh_error));
98 
99  auto it = m_thread_decoders.find(thread.GetID());
100  if (it == m_thread_decoders.end())
101  return std::make_shared<DecodedThread>(
102  thread.shared_from_this(),
103  createStringError(inconvertibleErrorCode(), "thread not traced"));
104  return it->second->Decode();
105 }
106 
107 lldb::TraceCursorUP TraceIntelPT::GetCursor(Thread &thread) {
108  return Decode(thread)->GetCursor();
109 }
110 
111 void TraceIntelPT::DumpTraceInfo(Thread &thread, Stream &s, bool verbose) {
112  Optional<size_t> raw_size = GetRawTraceSize(thread);
113  s.Printf("\nthread #%u: tid = %" PRIu64, thread.GetIndexID(), thread.GetID());
114  if (!raw_size) {
115  s.Printf(", not traced\n");
116  return;
117  }
118  s.Printf("\n Raw trace size: %zu bytes\n", *raw_size);
119  return;
120 }
121 
122 Optional<size_t> TraceIntelPT::GetRawTraceSize(Thread &thread) {
123  if (IsTraced(thread.GetID()))
124  return Decode(thread)->GetRawTraceSize();
125  else
126  return None;
127 }
128 
130  Expected<std::vector<uint8_t>> cpu_info = GetLiveProcessBinaryData("cpuInfo");
131  if (!cpu_info)
132  return cpu_info.takeError();
133 
134  int64_t cpu_family = -1;
135  int64_t model = -1;
136  int64_t stepping = -1;
137  std::string vendor_id;
138 
139  StringRef rest(reinterpret_cast<const char *>(cpu_info->data()),
140  cpu_info->size());
141  while (!rest.empty()) {
142  StringRef line;
143  std::tie(line, rest) = rest.split('\n');
144 
145  SmallVector<StringRef, 2> columns;
146  line.split(columns, StringRef(":"), -1, false);
147 
148  if (columns.size() < 2)
149  continue; // continue searching
150 
151  columns[1] = columns[1].trim(" ");
152  if (columns[0].contains("cpu family") &&
153  columns[1].getAsInteger(10, cpu_family))
154  continue;
155 
156  else if (columns[0].contains("model") && columns[1].getAsInteger(10, model))
157  continue;
158 
159  else if (columns[0].contains("stepping") &&
160  columns[1].getAsInteger(10, stepping))
161  continue;
162 
163  else if (columns[0].contains("vendor_id")) {
164  vendor_id = columns[1].str();
165  if (!vendor_id.empty())
166  continue;
167  }
168 
169  if ((cpu_family != -1) && (model != -1) && (stepping != -1) &&
170  (!vendor_id.empty())) {
171  return pt_cpu{vendor_id == "GenuineIntel" ? pcv_intel : pcv_unknown,
172  static_cast<uint16_t>(cpu_family),
173  static_cast<uint8_t>(model),
174  static_cast<uint8_t>(stepping)};
175  }
176  }
177  return createStringError(inconvertibleErrorCode(),
178  "Failed parsing the target's /proc/cpuinfo file");
179 }
180 
181 Expected<pt_cpu> TraceIntelPT::GetCPUInfo() {
182  if (!m_cpu_info) {
183  if (llvm::Expected<pt_cpu> cpu_info = GetCPUInfoForLiveProcess())
184  m_cpu_info = *cpu_info;
185  else
186  return cpu_info.takeError();
187  }
188  return *m_cpu_info;
189 }
190 
192 
194  Expected<TraceGetStateResponse> state) {
195  m_thread_decoders.clear();
196 
197  if (!state) {
198  m_live_refresh_error = toString(state.takeError());
199  return;
200  }
201 
202  for (const TraceThreadState &thread_state : state->tracedThreads) {
203  Thread &thread =
205  m_thread_decoders.emplace(
206  thread_state.tid, std::make_unique<LiveThreadDecoder>(thread, *this));
207  }
208 }
209 
212  return m_thread_decoders.count(tid);
213 }
214 
215 // The information here should match the description of the intel-pt section
216 // of the jLLDBTraceStart packet in the lldb/docs/lldb-gdb-remote.txt
217 // documentation file. Similarly, it should match the CLI help messages of the
218 // TraceIntelPTOptions.td file.
220  return R"(Parameters:
221 
222  Note: If a parameter is not specified, a default value will be used.
223 
224  - int threadBufferSize (defaults to 4096 bytes):
225  [process and thread tracing]
226  Trace size in bytes per thread. It must be a power of 2 greater
227  than or equal to 4096 (2^12). The trace is circular keeping the
228  the most recent data.
229 
230  - boolean enableTsc (default to false):
231  [process and thread tracing]
232  Whether to use enable TSC timestamps or not. This is supported on
233  all devices that support intel-pt.
234 
235  - psbPeriod (defaults to null):
236  [process and thread tracing]
237  This value defines the period in which PSB packets will be generated.
238  A PSB packet is a synchronization packet that contains a TSC
239  timestamp and the current absolute instruction pointer.
240 
241  This parameter can only be used if
242 
243  /sys/bus/event_source/devices/intel_pt/caps/psb_cyc
244 
245  is 1. Otherwise, the PSB period will be defined by the processor.
246 
247  If supported, valid values for this period can be found in
248 
249  /sys/bus/event_source/devices/intel_pt/caps/psb_periods
250 
251  which contains a hexadecimal number, whose bits represent
252  valid values e.g. if bit 2 is set, then value 2 is valid.
253 
254  The psb_period value is converted to the approximate number of
255  raw trace bytes between PSB packets as:
256 
257  2 ^ (value + 11)
258 
259  e.g. value 3 means 16KiB between PSB packets. Defaults to 0 if
260  supported.
261 
262  - int processBufferSizeLimit (defaults to 500 MB):
263  [process tracing only]
264  Maximum total trace size per process in bytes. This limit applies
265  to the sum of the sizes of all thread traces of this process,
266  excluding the ones created explicitly with "thread tracing".
267  Whenever a thread is attempted to be traced due to this command
268  and the limit would be reached, the process is stopped with a
269  "processor trace" reason, so that the user can retrace the process
270  if needed.)";
271 }
272 
273 Error TraceIntelPT::Start(size_t thread_buffer_size,
274  size_t total_buffer_size_limit, bool enable_tsc,
275  Optional<size_t> psb_period) {
276  TraceIntelPTStartRequest request;
277  request.threadBufferSize = thread_buffer_size;
278  request.processBufferSizeLimit = total_buffer_size_limit;
279  request.enableTsc = enable_tsc;
280  request.psbPeriod = psb_period.map([](size_t val) { return (int64_t)val; });
281  request.type = GetPluginName().str();
282  return Trace::Start(toJSON(request));
283 }
284 
286  size_t thread_buffer_size = kDefaultThreadBufferSize;
287  size_t process_buffer_size_limit = kDefaultProcessBufferSizeLimit;
288  bool enable_tsc = kDefaultEnableTscValue;
289  Optional<size_t> psb_period = kDefaultPsbPeriod;
290 
291  if (configuration) {
292  if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) {
293  dict->GetValueForKeyAsInteger("threadBufferSize", thread_buffer_size);
294  dict->GetValueForKeyAsInteger("processBufferSizeLimit",
295  process_buffer_size_limit);
296  dict->GetValueForKeyAsBoolean("enableTsc", enable_tsc);
297  dict->GetValueForKeyAsInteger("psbPeriod", psb_period);
298  } else {
299  return createStringError(inconvertibleErrorCode(),
300  "configuration object is not a dictionary");
301  }
302  }
303 
304  return Start(thread_buffer_size, process_buffer_size_limit, enable_tsc,
305  psb_period);
306 }
307 
308 llvm::Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,
309  size_t thread_buffer_size, bool enable_tsc,
310  Optional<size_t> psb_period) {
311  TraceIntelPTStartRequest request;
312  request.threadBufferSize = thread_buffer_size;
313  request.enableTsc = enable_tsc;
314  request.psbPeriod = psb_period.map([](size_t val) { return (int64_t)val; });
315  request.type = GetPluginName().str();
316  request.tids.emplace();
317  for (lldb::tid_t tid : tids)
318  request.tids->push_back(tid);
319  return Trace::Start(toJSON(request));
320 }
321 
322 Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,
323  StructuredData::ObjectSP configuration) {
324  size_t thread_buffer_size = kDefaultThreadBufferSize;
325  bool enable_tsc = kDefaultEnableTscValue;
326  Optional<size_t> psb_period = kDefaultPsbPeriod;
327 
328  if (configuration) {
329  if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) {
330  dict->GetValueForKeyAsInteger("threadBufferSize", thread_buffer_size);
331  dict->GetValueForKeyAsBoolean("enableTsc", enable_tsc);
332  dict->GetValueForKeyAsInteger("psbPeriod", psb_period);
333  } else {
334  return createStringError(inconvertibleErrorCode(),
335  "configuration object is not a dictionary");
336  }
337  }
338 
339  return Start(tids, thread_buffer_size, enable_tsc, psb_period);
340 }
341 
342 Expected<std::vector<uint8_t>>
344  return Trace::GetLiveThreadBinaryData(tid, "threadTraceBuffer");
345 }
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:166
TraceIntelPTSessionFileParser.h
lldb_private::Thread::GetIndexID
uint32_t GetIndexID() const
Definition: Thread.cpp:1387
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:193
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:340
lldb_private::Process::GetThreadList
ThreadList & GetThreadList()
Definition: Process.h:2107
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:1208
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:181
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:187
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:343
Process.h
lldb_private::trace_intel_pt::TraceIntelPT::GetStartConfigurationHelp
const char * GetStartConfigurationHelp() override
Definition: TraceIntelPT.cpp:219
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:107
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::ConstString
Definition: ConstString.h:40
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:185
lldb_private::CommandInterpreter
Definition: CommandInterpreter.h:214
lldb_private::trace_intel_pt::TraceIntelPT::GetRawTraceSize
llvm::Optional< size_t > GetRawTraceSize(Thread &thread)
Definition: TraceIntelPT.cpp:122
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:148
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:210
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:3069
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:111
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:191
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:129
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:184
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:181
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:92
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