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 
14 #include "lldb/Target/Process.h"
15 #include "lldb/Target/Target.h"
17 
18 using namespace lldb;
19 using namespace lldb_private;
20 using namespace lldb_private::trace_intel_pt;
21 using namespace llvm;
22 
24 
25 lldb::CommandObjectSP
26 TraceIntelPT::GetProcessTraceStartCommand(CommandInterpreter &interpreter) {
27  return CommandObjectSP(
28  new CommandObjectProcessTraceStartIntelPT(*this, interpreter));
29 }
30 
31 lldb::CommandObjectSP
32 TraceIntelPT::GetThreadTraceStartCommand(CommandInterpreter &interpreter) {
33  return CommandObjectSP(
34  new CommandObjectThreadTraceStartIntelPT(*this, interpreter));
35 }
36 
37 void TraceIntelPT::Initialize() {
38  PluginManager::RegisterPlugin(GetPluginNameStatic(), "Intel Processor Trace",
39  CreateInstanceForSessionFile,
40  CreateInstanceForLiveProcess,
41  TraceIntelPTSessionFileParser::GetSchema());
42 }
43 
44 void TraceIntelPT::Terminate() {
45  PluginManager::UnregisterPlugin(CreateInstanceForSessionFile);
46 }
47 
48 ConstString TraceIntelPT::GetPluginNameStatic() {
49  static ConstString g_name("intel-pt");
50  return g_name;
51 }
52 
53 StringRef TraceIntelPT::GetSchema() {
54  return TraceIntelPTSessionFileParser::GetSchema();
55 }
56 
57 //------------------------------------------------------------------
58 // PluginInterface protocol
59 //------------------------------------------------------------------
60 
61 ConstString TraceIntelPT::GetPluginName() { return GetPluginNameStatic(); }
62 
63 uint32_t TraceIntelPT::GetPluginVersion() { return 1; }
64 
65 void TraceIntelPT::Dump(Stream *s) const {}
66 
67 Expected<TraceSP> TraceIntelPT::CreateInstanceForSessionFile(
68  const json::Value &trace_session_file, StringRef session_file_dir,
69  Debugger &debugger) {
70  return TraceIntelPTSessionFileParser(debugger, trace_session_file,
71  session_file_dir)
72  .Parse();
73 }
74 
75 Expected<TraceSP> TraceIntelPT::CreateInstanceForLiveProcess(Process &process) {
76  TraceSP instance(new TraceIntelPT(process));
77  process.GetTarget().SetTrace(instance);
78  return instance;
79 }
80 
81 TraceIntelPT::TraceIntelPT(
82  const pt_cpu &cpu_info,
83  const std::vector<ThreadPostMortemTraceSP> &traced_threads)
84  : m_cpu_info(cpu_info) {
85  for (const ThreadPostMortemTraceSP &thread : traced_threads)
86  m_thread_decoders.emplace(
87  thread.get(), std::make_unique<PostMortemThreadDecoder>(thread, *this));
88 }
89 
92  if (m_failed_live_threads_decoder.hasValue())
94 
95  auto it = m_thread_decoders.find(&thread);
96  if (it == m_thread_decoders.end())
97  return nullptr;
98  return &it->second->Decode();
99 }
100 
102  const DecodedThread *decoded_thread = Decode(thread);
103  if (!decoded_thread)
104  return 0;
105  return decoded_thread->GetCursorPosition();
106 }
107 
109  Thread &thread, size_t position, TraceDirection direction,
110  std::function<bool(size_t index, Expected<lldb::addr_t> load_addr)>
111  callback) {
112  const DecodedThread *decoded_thread = Decode(thread);
113  if (!decoded_thread)
114  return;
115 
116  ArrayRef<IntelPTInstruction> instructions = decoded_thread->GetInstructions();
117 
118  ssize_t delta = direction == TraceDirection::Forwards ? 1 : -1;
119  for (ssize_t i = position; i < (ssize_t)instructions.size() && i >= 0;
120  i += delta)
121  if (!callback(i, instructions[i].GetLoadAddress()))
122  break;
123 }
124 
125 Optional<size_t> TraceIntelPT::GetInstructionCount(Thread &thread) {
126  if (const DecodedThread *decoded_thread = Decode(thread))
127  return decoded_thread->GetInstructions().size();
128  else
129  return None;
130 }
131 
133  Expected<std::vector<uint8_t>> cpu_info = GetLiveProcessBinaryData("cpuInfo");
134  if (!cpu_info)
135  return cpu_info.takeError();
136 
137  int64_t cpu_family = -1;
138  int64_t model = -1;
139  int64_t stepping = -1;
140  std::string vendor_id;
141 
142  StringRef rest(reinterpret_cast<const char *>(cpu_info->data()),
143  cpu_info->size());
144  while (!rest.empty()) {
145  StringRef line;
146  std::tie(line, rest) = rest.split('\n');
147 
148  SmallVector<StringRef, 2> columns;
149  line.split(columns, StringRef(":"), -1, false);
150 
151  if (columns.size() < 2)
152  continue; // continue searching
153 
154  columns[1] = columns[1].trim(" ");
155  if (columns[0].contains("cpu family") &&
156  columns[1].getAsInteger(10, cpu_family))
157  continue;
158 
159  else if (columns[0].contains("model") && columns[1].getAsInteger(10, model))
160  continue;
161 
162  else if (columns[0].contains("stepping") &&
163  columns[1].getAsInteger(10, stepping))
164  continue;
165 
166  else if (columns[0].contains("vendor_id")) {
167  vendor_id = columns[1].str();
168  if (!vendor_id.empty())
169  continue;
170  }
171 
172  if ((cpu_family != -1) && (model != -1) && (stepping != -1) &&
173  (!vendor_id.empty())) {
174  return pt_cpu{vendor_id == "GenuineIntel" ? pcv_intel : pcv_unknown,
175  static_cast<uint16_t>(cpu_family),
176  static_cast<uint8_t>(model),
177  static_cast<uint8_t>(stepping)};
178  }
179  }
180  return createStringError(inconvertibleErrorCode(),
181  "Failed parsing the target's /proc/cpuinfo file");
182 }
183 
184 Expected<pt_cpu> TraceIntelPT::GetCPUInfo() {
185  if (!m_cpu_info) {
186  if (llvm::Expected<pt_cpu> cpu_info = GetCPUInfoForLiveProcess())
187  m_cpu_info = *cpu_info;
188  else
189  return cpu_info.takeError();
190  }
191  return *m_cpu_info;
192 }
193 
195  Expected<TraceGetStateResponse> state) {
196  m_thread_decoders.clear();
197 
198  if (!state) {
199  m_failed_live_threads_decoder = DecodedThread(state.takeError());
200  return;
201  }
202 
203  for (const TraceThreadState &thread_state : state->tracedThreads) {
204  Thread &thread =
206  m_thread_decoders.emplace(
207  &thread, std::make_unique<LiveThreadDecoder>(thread, *this));
208  }
209 }
210 
211 bool TraceIntelPT::IsTraced(const Thread &thread) {
212  return m_thread_decoders.count(&thread);
213 }
214 
215 Error TraceIntelPT::Start(size_t thread_buffer_size,
216  size_t total_buffer_size_limit) {
217  TraceIntelPTStartRequest request;
218  request.threadBufferSize = thread_buffer_size;
219  request.processBufferSizeLimit = total_buffer_size_limit;
220  request.type = GetPluginName().AsCString();
221  return Trace::Start(toJSON(request));
222 }
223 
224 llvm::Error TraceIntelPT::Start(const std::vector<lldb::tid_t> &tids,
225  size_t thread_buffer_size) {
226  TraceIntelPTStartRequest request;
227  request.threadBufferSize = thread_buffer_size;
228  request.type = GetPluginName().AsCString();
229  request.tids.emplace();
230  for (lldb::tid_t tid : tids)
231  request.tids->push_back(tid);
232  return Trace::Start(toJSON(request));
233 }
234 
235 Expected<std::vector<uint8_t>>
237  return Trace::GetLiveThreadBinaryData(tid, "threadTraceBuffer");
238 }
lldb_private::toJSON
llvm::json::Value toJSON(const TraceSupportedResponse &packet)
Definition: TraceGDBRemotePackets.cpp:24
llvm
Definition: Debugger.h:49
CommandObjectTraceStartIntelPT.h
TraceIntelPTSessionFileParser.h
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:194
lldb_private::trace_intel_pt::DecodedThread::GetCursorPosition
size_t GetCursorPosition() const
Definition: DecodedThread.cpp:59
lldb_private::trace_intel_pt::TraceIntelPT::m_thread_decoders
std::map< const Thread *, std::unique_ptr< ThreadDecoder > > m_thread_decoders
Definition: TraceIntelPT.h:151
ThreadPostMortemTrace.h
lldb_private::TraceThreadState::tid
int64_t tid
Definition: TraceGDBRemotePackets.h:106
lldb_private::Process
Definition: Process.h:343
lldb_private::Process::GetThreadList
ThreadList & GetThreadList()
Definition: Process.h:2047
lldb_private::Process::GetTarget
Target & GetTarget()
Get the target object pointer for this module.
Definition: Process.h:1196
lldb_private::trace_intel_pt::TraceIntelPT
Definition: TraceIntelPT.h:18
lldb_private::ConstString::AsCString
const char * AsCString(const char *value_if_empty=nullptr) const
Get the string value as a C string.
Definition: ConstString.h:193
lldb_private::Trace::TraceDirection::Forwards
@ Forwards
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:441
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:236
Process.h
lldb_private::trace_intel_pt::TraceIntelPT::m_failed_live_threads_decoder
llvm::Optional< DecodedThread > m_failed_live_threads_decoder
Dummy DecodedThread used when decoding threads after there were errors when refreshing the live proce...
Definition: TraceIntelPT.h:154
Target.h
lldb_private::Trace::GetLiveProcessBinaryData
llvm::Expected< std::vector< uint8_t > > GetLiveProcessBinaryData(llvm::StringRef kind)
Get binary data of the current process given a data identifier.
Definition: Trace.cpp:426
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::Thread
Definition: Thread.h:62
lldb_private::ConstString
Definition: ConstString.h:40
lldb_private::TraceIntelPTStartRequest
jLLDBTraceStart gdb-remote packet
Definition: TraceIntelPTGDBRemotePackets.h:19
lldb_private::CommandInterpreter
Definition: CommandInterpreter.h:221
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:38
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:3101
lldb_private::Trace::Start
llvm::Error Start(const llvm::json::Value &request)
Start tracing a live process or its threads.
Definition: Trace.cpp:358
lldb_private::Trace::m_live_process
Process * m_live_process
Definition: Trace.h:322
lldb_private::trace_intel_pt::TraceIntelPT::GetCursorPosition
size_t GetCursorPosition(Thread &thread) override
Each decoded thread contains a cursor to the current position the user is stopped at.
Definition: TraceIntelPT.cpp:101
lldb_private::TraceIntelPTStartRequest::processBufferSizeLimit
llvm::Optional< int64_t > processBufferSizeLimit
Required when doing "process tracing".
Definition: TraceIntelPTGDBRemotePackets.h:27
lldb_private::trace_intel_pt::TraceIntelPT::Start
llvm::Error Start(size_t thread_buffer_size, size_t total_buffer_size_limit)
Start tracing a live process.
Definition: TraceIntelPT.cpp:215
uint32_t
lldb_private::trace_intel_pt::TraceIntelPTSessionFileParser
Definition: TraceIntelPTSessionFileParser.h:20
lldb_private::trace_intel_pt::TraceIntelPT::GetInstructionCount
llvm::Optional< size_t > GetInstructionCount(Thread &thread) override
Get the number of available instructions in the trace of the given thread.
Definition: TraceIntelPT.cpp:125
lldb_private::trace_intel_pt::TraceIntelPT::Decode
const DecodedThread * Decode(Thread &thread)
Decode the trace of the given thread that, i.e.
Definition: TraceIntelPT.cpp:90
uint16_t
PluginManager.h
lldb_private::trace_intel_pt::TraceIntelPT::GetCPUInfoForLiveProcess
llvm::Expected< pt_cpu > GetCPUInfoForLiveProcess()
Definition: TraceIntelPT.cpp:132
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:150
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:46
lldb_private::trace_intel_pt::TraceIntelPT::IsTraced
bool IsTraced(const Thread &thread) override
Check if a thread is currently traced by this object.
Definition: TraceIntelPT.cpp:211
lldb_private::Trace::TraceDirection
TraceDirection
Definition: Trace.h:47
lldb_private::trace_intel_pt::TraceIntelPT::GetCPUInfo
llvm::Expected< pt_cpu > GetCPUInfo()
Definition: TraceIntelPT.cpp:184
lldb_private::Trace::GetLiveThreadBinaryData
llvm::Expected< std::vector< uint8_t > > GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind)
Get binary data of a live thread given a data identifier.
Definition: Trace.cpp:408
lldb_private::trace_intel_pt::DecodedThread
Definition: DecodedThread.h:109
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:61
lldb
Definition: SBAddress.h:15
TraceIntelPT.h
lldb_private::trace_intel_pt::TraceIntelPT::TraverseInstructions
void TraverseInstructions(Thread &thread, size_t position, TraceDirection direction, std::function< bool(size_t index, llvm::Expected< lldb::addr_t > load_addr)> callback) override
Run the provided callback on the instructions of the trace of the given thread.
Definition: TraceIntelPT.cpp:108
lldb_private::trace_intel_pt::DecodedThread::GetInstructions
llvm::ArrayRef< IntelPTInstruction > GetInstructions() const
Get the instructions from the decoded trace.
Definition: DecodedThread.cpp:55
lldb_private::trace_intel_pt::CommandObjectProcessTraceStartIntelPT
Definition: CommandObjectTraceStartIntelPT.h:62
lldb::tid_t
uint64_t tid_t
Definition: lldb-types.h:86
lldb_private::trace_intel_pt::TraceIntelPT::GetPluginName
ConstString GetPluginName() override
PluginInterface protocol.
Definition: TraceIntelPT.cpp:61
lldb_private::TraceThreadState
Definition: TraceGDBRemotePackets.h:105