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 "CommandObjectTraceStartIntelPT.h"
12 #include "TraceIntelPTSessionFileParser.h"
13 #include "lldb/Core/PluginManager.h"
14 #include "lldb/Target/Process.h"
15 #include "lldb/Target/Target.h"
16 #include "lldb/Target/ThreadTrace.h"
17 
18 using namespace lldb;
19 using namespace lldb_private;
20 using namespace lldb_private::trace_intel_pt;
21 using namespace llvm;
22 
LLDB_PLUGIN_DEFINE(TraceIntelPT)23 LLDB_PLUGIN_DEFINE(TraceIntelPT)
24 
25 CommandObjectSP GetStartCommand(CommandInterpreter &interpreter) {
26   return CommandObjectSP(new CommandObjectTraceStartIntelPT(interpreter));
27 }
28 
Initialize()29 void TraceIntelPT::Initialize() {
30   PluginManager::RegisterPlugin(
31       GetPluginNameStatic(), "Intel Processor Trace", CreateInstance,
32       TraceIntelPTSessionFileParser::GetSchema(), GetStartCommand);
33 }
34 
Terminate()35 void TraceIntelPT::Terminate() {
36   PluginManager::UnregisterPlugin(CreateInstance);
37 }
38 
GetPluginNameStatic()39 ConstString TraceIntelPT::GetPluginNameStatic() {
40   static ConstString g_name("intel-pt");
41   return g_name;
42 }
43 
GetSchema()44 StringRef TraceIntelPT::GetSchema() {
45   return TraceIntelPTSessionFileParser::GetSchema();
46 }
47 
48 //------------------------------------------------------------------
49 // PluginInterface protocol
50 //------------------------------------------------------------------
51 
GetPluginName()52 ConstString TraceIntelPT::GetPluginName() { return GetPluginNameStatic(); }
53 
GetPluginVersion()54 uint32_t TraceIntelPT::GetPluginVersion() { return 1; }
55 
Dump(Stream * s) const56 void TraceIntelPT::Dump(Stream *s) const {}
57 
58 Expected<TraceSP>
CreateInstance(const json::Value & trace_session_file,StringRef session_file_dir,Debugger & debugger)59 TraceIntelPT::CreateInstance(const json::Value &trace_session_file,
60                              StringRef session_file_dir, Debugger &debugger) {
61   return TraceIntelPTSessionFileParser(debugger, trace_session_file,
62                                        session_file_dir)
63       .Parse();
64 }
65 
TraceIntelPT(const pt_cpu & pt_cpu,const std::vector<std::shared_ptr<ThreadTrace>> & traced_threads)66 TraceIntelPT::TraceIntelPT(
67     const pt_cpu &pt_cpu,
68     const std::vector<std::shared_ptr<ThreadTrace>> &traced_threads)
69     : m_pt_cpu(pt_cpu) {
70   for (const std::shared_ptr<ThreadTrace> &thread : traced_threads)
71     m_trace_threads.emplace(
72         std::piecewise_construct,
73         std::forward_as_tuple(thread->GetProcess()->GetID(), thread->GetID()),
74         std::forward_as_tuple(thread, pt_cpu));
75 }
76 
Decode(const Thread & thread)77 const DecodedThread *TraceIntelPT::Decode(const Thread &thread) {
78   auto it = m_trace_threads.find(
79       std::make_pair(thread.GetProcess()->GetID(), thread.GetID()));
80   if (it == m_trace_threads.end())
81     return nullptr;
82   return &it->second.Decode();
83 }
84 
GetCursorPosition(const Thread & thread)85 size_t TraceIntelPT::GetCursorPosition(const Thread &thread) {
86   const DecodedThread *decoded_thread = Decode(thread);
87   if (!decoded_thread)
88     return 0;
89   return decoded_thread->GetCursorPosition();
90 }
91 
TraverseInstructions(const Thread & thread,size_t position,TraceDirection direction,std::function<bool (size_t index,Expected<lldb::addr_t> load_addr)> callback)92 void TraceIntelPT::TraverseInstructions(
93     const Thread &thread, size_t position, TraceDirection direction,
94     std::function<bool(size_t index, Expected<lldb::addr_t> load_addr)>
95         callback) {
96   const DecodedThread *decoded_thread = Decode(thread);
97   if (!decoded_thread)
98     return;
99 
100   ArrayRef<IntelPTInstruction> instructions = decoded_thread->GetInstructions();
101 
102   ssize_t delta = direction == TraceDirection::Forwards ? 1 : -1;
103   for (ssize_t i = position; i < (ssize_t)instructions.size() && i >= 0;
104        i += delta)
105     if (!callback(i, instructions[i].GetLoadAddress()))
106       break;
107 }
108 
GetInstructionCount(const Thread & thread)109 size_t TraceIntelPT::GetInstructionCount(const Thread &thread) {
110   if (const DecodedThread *decoded_thread = Decode(thread))
111     return decoded_thread->GetInstructions().size();
112   else
113     return 0;
114 }
115