1 //===-- Decoder.h -----------------------------------------------*- C++ -*-===// 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 #ifndef Decoder_h_ 10 #define Decoder_h_ 11 12 // C/C++ Includes 13 #include <map> 14 #include <mutex> 15 #include <string> 16 #include <vector> 17 18 #include "lldb/API/SBDebugger.h" 19 #include "lldb/API/SBError.h" 20 #include "lldb/API/SBProcess.h" 21 #include "lldb/API/SBStream.h" 22 #include "lldb/API/SBStructuredData.h" 23 #include "lldb/API/SBTarget.h" 24 #include "lldb/API/SBTrace.h" 25 #include "lldb/API/SBTraceOptions.h" 26 #include "lldb/lldb-enumerations.h" 27 #include "lldb/lldb-types.h" 28 29 #include "intel-pt.h" 30 31 namespace ptdecoder_private { 32 /// \class Instruction 33 /// Represents an assembly instruction containing raw 34 /// instruction bytes, instruction address along with information 35 /// regarding execution flow context and Intel(R) Processor Trace 36 /// context. 37 class Instruction { 38 public: Instruction()39 Instruction() : ip(0), data(), error(), iclass(ptic_error), speculative(0) {} 40 41 Instruction(const Instruction &insn) = default; 42 Instruction(const struct pt_insn & insn)43 Instruction(const struct pt_insn &insn) 44 : ip(insn.ip), data(), error(insn.size == 0 ? "invalid instruction" : ""), 45 iclass(insn.iclass), speculative(insn.speculative) { 46 if (insn.size != 0) 47 data.assign(insn.raw, insn.raw + insn.size); 48 } 49 Instruction(const char * err)50 Instruction(const char *err) 51 : ip(0), data(), error(err ? err : "unknown error"), iclass(ptic_error), 52 speculative(0) {} 53 ~Instruction()54 ~Instruction() {} 55 GetInsnAddress()56 uint64_t GetInsnAddress() const { return ip; } 57 GetRawBytes(void * buf,size_t size)58 size_t GetRawBytes(void *buf, size_t size) const { 59 if ((buf == nullptr) || (size == 0)) 60 return data.size(); 61 62 size_t bytes_to_read = ((size <= data.size()) ? size : data.size()); 63 ::memcpy(buf, data.data(), bytes_to_read); 64 return bytes_to_read; 65 } 66 GetError()67 const std::string &GetError() const { return error; } 68 GetSpeculative()69 bool GetSpeculative() const { return speculative; } 70 71 private: 72 uint64_t ip; // instruction address in inferior's memory image 73 std::vector<uint8_t> data; // raw bytes 74 std::string error; // Error string if instruction is invalid 75 enum pt_insn_class iclass; // classification of the instruction 76 // A collection of flags giving additional information about instruction 77 uint32_t speculative : 1; // Instruction was executed speculatively or not 78 }; 79 80 /// \class InstructionList 81 /// Represents a list of assembly instructions. Each instruction is of 82 /// type Instruction. 83 class InstructionList { 84 public: InstructionList()85 InstructionList() : m_insn_vec() {} 86 InstructionList(const InstructionList & insn_list)87 InstructionList(const InstructionList &insn_list) 88 : m_insn_vec(insn_list.m_insn_vec) {} 89 ~InstructionList()90 ~InstructionList() {} 91 92 // Get number of instructions in the list GetSize()93 size_t GetSize() const { return m_insn_vec.size(); } 94 95 // Get instruction at index GetInstructionAtIndex(uint32_t idx)96 Instruction GetInstructionAtIndex(uint32_t idx) { 97 return (idx < m_insn_vec.size() ? m_insn_vec[idx] 98 : Instruction("invalid instruction")); 99 } 100 101 // Append intruction at the end of the list AppendInstruction(Instruction inst)102 void AppendInstruction(Instruction inst) { m_insn_vec.push_back(inst); } 103 104 private: 105 std::vector<Instruction> m_insn_vec; 106 }; 107 108 /// \class TraceOptions 109 /// Provides Intel(R) Processor Trace specific configuration options and 110 /// other information obtained by decoding and post-processing the trace 111 /// data. Currently, this information comprises of the total number of 112 /// assembly instructions executed for an inferior. 113 class TraceOptions : public lldb::SBTraceOptions { 114 public: TraceOptions()115 TraceOptions() : lldb::SBTraceOptions(), m_insn_log_size(0) {} 116 ~TraceOptions()117 ~TraceOptions() {} 118 119 /// Get total number of assembly instructions obtained after decoding the 120 /// complete Intel(R) Processor Trace data obtained from LLDB. 121 /// 122 /// \return 123 /// Total number of instructions. getInstructionLogSize()124 uint32_t getInstructionLogSize() const { return m_insn_log_size; } 125 126 /// Set total number of assembly instructions. 127 /// 128 /// \param[in] size 129 /// Value to be set. setInstructionLogSize(uint32_t size)130 void setInstructionLogSize(uint32_t size) { m_insn_log_size = size; } 131 132 private: 133 uint32_t m_insn_log_size; 134 }; 135 136 /// \class Decoder 137 /// This class makes use of Intel(R) Processor Trace hardware feature 138 /// (implememted inside LLDB) to gather trace data for an inferior (being 139 /// debugged with LLDB) to provide meaningful information out of it. 140 /// 141 /// Currently the meaningful information comprises of the execution flow 142 /// of the inferior (in terms of assembly instructions executed). The class 143 /// enables user to: 144 /// - start the trace with configuration options for a thread/process, 145 /// - stop the trace for a thread/process, 146 /// - get the execution flow (assembly instructions) for a thread and 147 /// - get trace specific information for a thread 148 class Decoder { 149 public: 150 typedef std::vector<Instruction> Instructions; 151 Decoder(lldb::SBDebugger & sbdebugger)152 Decoder(lldb::SBDebugger &sbdebugger) 153 : m_mapProcessUID_mapThreadID_TraceInfo_mutex(), 154 m_mapProcessUID_mapThreadID_TraceInfo(), 155 m_debugger_user_id(sbdebugger.GetID()) {} 156 ~Decoder()157 ~Decoder() {} 158 159 void StartProcessorTrace(lldb::SBProcess &sbprocess, 160 lldb::SBTraceOptions &sbtraceoptions, 161 lldb::SBError &sberror); 162 163 void StopProcessorTrace(lldb::SBProcess &sbprocess, lldb::SBError &sberror, 164 lldb::tid_t tid = LLDB_INVALID_THREAD_ID); 165 166 void GetInstructionLogAtOffset(lldb::SBProcess &sbprocess, lldb::tid_t tid, 167 uint32_t offset, uint32_t count, 168 InstructionList &result_list, 169 lldb::SBError &sberror); 170 171 void GetProcessorTraceInfo(lldb::SBProcess &sbprocess, lldb::tid_t tid, 172 TraceOptions &traceinfo, lldb::SBError &sberror); 173 174 private: 175 class ThreadTraceInfo; 176 typedef std::vector<uint8_t> Buffer; 177 178 // internal class to manage inferior's read-execute section information 179 class ReadExecuteSectionInfo { 180 public: 181 uint64_t load_address; 182 uint64_t file_offset; 183 uint64_t size; 184 std::string image_path; 185 ReadExecuteSectionInfo(const uint64_t addr,const uint64_t offset,const uint64_t sz,const std::string & path)186 ReadExecuteSectionInfo(const uint64_t addr, const uint64_t offset, 187 const uint64_t sz, const std::string &path) 188 : load_address(addr), file_offset(offset), size(sz), image_path(path) {} 189 190 ReadExecuteSectionInfo(const ReadExecuteSectionInfo &rxsection) = default; 191 }; 192 193 typedef struct pt_cpu CPUInfo; 194 typedef std::vector<ReadExecuteSectionInfo> ReadExecuteSectionInfos; 195 196 // Check whether the provided SBProcess belongs to the same SBDebugger with 197 // which Decoder class instance was constructed. 198 void CheckDebuggerID(lldb::SBProcess &sbprocess, lldb::SBError &sberror); 199 200 // Function to remove entries of finished processes/threads in the class 201 void RemoveDeadProcessesAndThreads(lldb::SBProcess &sbprocess); 202 203 // Parse cpu information from trace configuration received from LLDB 204 void ParseCPUInfo(CPUInfo &pt_cpu, lldb::SBStructuredData &s, 205 lldb::SBError &sberror); 206 207 /// Function performs following tasks for a given process and thread: 208 /// - Checks if the given thread is registered in the class or not. If not 209 /// then tries to register it if trace was ever started on the entire 210 /// process. Else returns error. 211 /// - fetches trace and other necessary information from LLDB (using 212 /// ReadTraceDataAndImageInfo()) and decodes the trace (using 213 /// DecodeProcessorTrace()) 214 void FetchAndDecode(lldb::SBProcess &sbprocess, lldb::tid_t tid, 215 lldb::SBError &sberror, 216 ThreadTraceInfo **threadTraceInfo); 217 218 // Helper function of FetchAndDecode() to get raw trace data and memory image 219 // info of inferior from LLDB 220 void ReadTraceDataAndImageInfo(lldb::SBProcess &sbprocess, lldb::tid_t tid, 221 lldb::SBError &sberror, 222 ThreadTraceInfo &threadTraceInfo); 223 224 // Helper function of FetchAndDecode() to initialize raw trace decoder and 225 // start trace decoding 226 void DecodeProcessorTrace(lldb::SBProcess &sbprocess, lldb::tid_t tid, 227 lldb::SBError &sberror, 228 ThreadTraceInfo &threadTraceInfo); 229 230 // Helper function of ReadTraceDataAndImageInfo() function for gathering 231 // inferior's memory image info along with all dynamic libraries linked with 232 // it 233 void GetTargetModulesInfo(lldb::SBTarget &sbtarget, 234 ReadExecuteSectionInfos &readExecuteSectionInfos, 235 lldb::SBError &sberror); 236 237 /// Helper functions of DecodeProcessorTrace() function for: 238 /// - initializing raw trace decoder (provided by Intel(R) Processor Trace 239 /// Decoding library) 240 /// - start trace decoding 241 void InitializePTInstDecoder( 242 struct pt_insn_decoder **decoder, struct pt_config *config, 243 const CPUInfo &pt_cpu, Buffer &pt_buffer, 244 const ReadExecuteSectionInfos &readExecuteSectionInfos, 245 lldb::SBError &sberror) const; 246 void DecodeTrace(struct pt_insn_decoder *decoder, 247 Instructions &instruction_list, lldb::SBError &sberror); 248 int HandlePTInstructionEvents(pt_insn_decoder *decoder, int errcode, 249 Instructions &instruction_list, 250 lldb::SBError &sberror); 251 252 int AppendErrorToInstructionList(int errcode, pt_insn_decoder *decoder, 253 Instructions &instruction_list, 254 lldb::SBError &sberror); 255 256 void AppendErrorWithOffsetToInstructionList(int errcode, 257 uint64_t decoder_offset, 258 Instructions &instruction_list, 259 lldb::SBError &sberror); 260 261 void AppendErrorWithoutOffsetToInstructionList(int errcode, 262 Instructions &instruction_list, 263 lldb::SBError &sberror); 264 265 // Function to diagnose and indicate errors during raw trace decoding 266 void Diagnose(struct pt_insn_decoder *decoder, int errcode, 267 lldb::SBError &sberror, const struct pt_insn *insn = nullptr); 268 269 class ThreadTraceInfo { 270 public: ThreadTraceInfo()271 ThreadTraceInfo() 272 : m_pt_buffer(), m_readExecuteSectionInfos(), m_thread_stop_id(0), 273 m_trace(), m_pt_cpu(), m_instruction_log() {} 274 275 ThreadTraceInfo(const ThreadTraceInfo &trace_info) = default; 276 ~ThreadTraceInfo()277 ~ThreadTraceInfo() {} 278 GetPTBuffer()279 Buffer &GetPTBuffer() { return m_pt_buffer; } 280 AllocatePTBuffer(uint64_t size)281 void AllocatePTBuffer(uint64_t size) { m_pt_buffer.assign(size, 0); } 282 GetReadExecuteSectionInfos()283 ReadExecuteSectionInfos &GetReadExecuteSectionInfos() { 284 return m_readExecuteSectionInfos; 285 } 286 GetCPUInfo()287 CPUInfo &GetCPUInfo() { return m_pt_cpu; } 288 GetInstructionLog()289 Instructions &GetInstructionLog() { return m_instruction_log; } 290 GetStopID()291 uint32_t GetStopID() const { return m_thread_stop_id; } 292 SetStopID(uint32_t stop_id)293 void SetStopID(uint32_t stop_id) { m_thread_stop_id = stop_id; } 294 GetUniqueTraceInstance()295 lldb::SBTrace &GetUniqueTraceInstance() { return m_trace; } 296 SetUniqueTraceInstance(lldb::SBTrace & trace)297 void SetUniqueTraceInstance(lldb::SBTrace &trace) { m_trace = trace; } 298 299 friend class Decoder; 300 301 private: 302 Buffer m_pt_buffer; // raw trace buffer 303 ReadExecuteSectionInfos 304 m_readExecuteSectionInfos; // inferior's memory image info 305 uint32_t m_thread_stop_id; // stop id for thread 306 lldb::SBTrace m_trace; // unique tracing instance of a thread/process 307 CPUInfo m_pt_cpu; // cpu info of the target on which inferior is running 308 Instructions m_instruction_log; // complete instruction log 309 }; 310 311 typedef std::map<lldb::user_id_t, ThreadTraceInfo> MapThreadID_TraceInfo; 312 typedef std::map<uint32_t, MapThreadID_TraceInfo> 313 MapProcessUID_MapThreadID_TraceInfo; 314 315 std::mutex m_mapProcessUID_mapThreadID_TraceInfo_mutex; 316 MapProcessUID_MapThreadID_TraceInfo 317 m_mapProcessUID_mapThreadID_TraceInfo; // to store trace information for 318 // each process and its associated 319 // threads 320 lldb::user_id_t m_debugger_user_id; // SBDebugger instance which is associated 321 // to this Decoder instance 322 }; 323 324 } // namespace ptdecoder_private 325 #endif // Decoder_h_ 326