1*81ad6265SDimitry Andric //===-- LibiptDecoder.cpp --======-----------------------------------------===// 2*81ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 3*81ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 4*81ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 5*81ad6265SDimitry Andric // 6*81ad6265SDimitry Andric //===----------------------------------------------------------------------===// 7*81ad6265SDimitry Andric 8*81ad6265SDimitry Andric #include "LibiptDecoder.h" 9*81ad6265SDimitry Andric 10*81ad6265SDimitry Andric #include "TraceIntelPT.h" 11*81ad6265SDimitry Andric 12*81ad6265SDimitry Andric #include "lldb/Target/Process.h" 13*81ad6265SDimitry Andric 14*81ad6265SDimitry Andric using namespace lldb; 15*81ad6265SDimitry Andric using namespace lldb_private; 16*81ad6265SDimitry Andric using namespace lldb_private::trace_intel_pt; 17*81ad6265SDimitry Andric using namespace llvm; 18*81ad6265SDimitry Andric 19*81ad6265SDimitry Andric /// Class that decodes a raw buffer for a single thread using the low level 20*81ad6265SDimitry Andric /// libipt library. 21*81ad6265SDimitry Andric /// 22*81ad6265SDimitry Andric /// Throughout this code, the status of the decoder will be used to identify 23*81ad6265SDimitry Andric /// events needed to be processed or errors in the decoder. The values can be 24*81ad6265SDimitry Andric /// - negative: actual errors 25*81ad6265SDimitry Andric /// - positive or zero: not an error, but a list of bits signaling the status 26*81ad6265SDimitry Andric /// of the decoder, e.g. whether there are events that need to be decoded or 27*81ad6265SDimitry Andric /// not. 28*81ad6265SDimitry Andric class LibiptDecoder { 29*81ad6265SDimitry Andric public: 30*81ad6265SDimitry Andric /// \param[in] decoder 31*81ad6265SDimitry Andric /// A well configured decoder. Using the current state of that decoder, 32*81ad6265SDimitry Andric /// decoding will start at its next valid PSB. It's not assumed that the 33*81ad6265SDimitry Andric /// decoder is already pointing at a valid PSB. 34*81ad6265SDimitry Andric /// 35*81ad6265SDimitry Andric /// \param[in] decoded_thread 36*81ad6265SDimitry Andric /// A \a DecodedThread object where the decoded instructions will be 37*81ad6265SDimitry Andric /// appended to. It might have already some instructions. 38*81ad6265SDimitry Andric LibiptDecoder(pt_insn_decoder &decoder, DecodedThread &decoded_thread) 39*81ad6265SDimitry Andric : m_decoder(decoder), m_decoded_thread(decoded_thread) {} 40*81ad6265SDimitry Andric 41*81ad6265SDimitry Andric /// Decode all the instructions until the end of the trace. 42*81ad6265SDimitry Andric /// The decoding flow is based on 43*81ad6265SDimitry Andric /// https://github.com/intel/libipt/blob/master/doc/howto_libipt.md#the-instruction-flow-decode-loop. 44*81ad6265SDimitry Andric void DecodeUntilEndOfTrace() { 45*81ad6265SDimitry Andric // Multiple loops indicate gaps in the trace, which are found by the inner 46*81ad6265SDimitry Andric // call to DecodeInstructionsAndEvents. 47*81ad6265SDimitry Andric while (true) { 48*81ad6265SDimitry Andric int status = pt_insn_sync_forward(&m_decoder); 49*81ad6265SDimitry Andric 50*81ad6265SDimitry Andric if (IsLibiptError(status)) { 51*81ad6265SDimitry Andric m_decoded_thread.AppendError(IntelPTError(status)); 52*81ad6265SDimitry Andric break; 53*81ad6265SDimitry Andric } 54*81ad6265SDimitry Andric 55*81ad6265SDimitry Andric DecodeInstructionsAndEvents(status); 56*81ad6265SDimitry Andric } 57*81ad6265SDimitry Andric } 58*81ad6265SDimitry Andric 59*81ad6265SDimitry Andric /// Decode all the instructions that belong to the same PSB packet given its 60*81ad6265SDimitry Andric /// offset. 61*81ad6265SDimitry Andric void DecodePSB(uint64_t psb_offset) { 62*81ad6265SDimitry Andric int status = pt_insn_sync_set(&m_decoder, psb_offset); 63*81ad6265SDimitry Andric if (IsLibiptError(status)) { 64*81ad6265SDimitry Andric m_decoded_thread.AppendError(IntelPTError(status)); 65*81ad6265SDimitry Andric return; 66*81ad6265SDimitry Andric } 67*81ad6265SDimitry Andric DecodeInstructionsAndEvents(status, /*stop_on_psb_change=*/true); 68*81ad6265SDimitry Andric } 69*81ad6265SDimitry Andric 70*81ad6265SDimitry Andric private: 71*81ad6265SDimitry Andric /// Decode all the instructions and events until an error is found, the end 72*81ad6265SDimitry Andric /// of the trace is reached, or optionally a new PSB is reached. 73*81ad6265SDimitry Andric /// 74*81ad6265SDimitry Andric /// \param[in] status 75*81ad6265SDimitry Andric /// The status that was result of synchronizing to the most recent PSB. 76*81ad6265SDimitry Andric /// 77*81ad6265SDimitry Andric /// \param[in] stop_on_psb_change 78*81ad6265SDimitry Andric /// If \b true, decoding stops if a different PSB is reached. 79*81ad6265SDimitry Andric void DecodeInstructionsAndEvents(int status, 80*81ad6265SDimitry Andric bool stop_on_psb_change = false) { 81*81ad6265SDimitry Andric uint64_t psb_offset; 82*81ad6265SDimitry Andric pt_insn_get_sync_offset(&m_decoder, 83*81ad6265SDimitry Andric &psb_offset); // this can't fail because we got here 84*81ad6265SDimitry Andric 85*81ad6265SDimitry Andric while (ProcessPTEvents(status)) { 86*81ad6265SDimitry Andric if (stop_on_psb_change) { 87*81ad6265SDimitry Andric uint64_t cur_psb_offset; 88*81ad6265SDimitry Andric // this can't fail because we got here 89*81ad6265SDimitry Andric pt_insn_get_sync_offset(&m_decoder, &cur_psb_offset); 90*81ad6265SDimitry Andric if (cur_psb_offset != psb_offset) 91*81ad6265SDimitry Andric break; 92*81ad6265SDimitry Andric } 93*81ad6265SDimitry Andric 94*81ad6265SDimitry Andric // The status returned by pt_insn_next will need to be processed 95*81ad6265SDimitry Andric // by ProcessPTEvents in the next loop if it is not an error. 96*81ad6265SDimitry Andric pt_insn insn; 97*81ad6265SDimitry Andric std::memset(&insn, 0, sizeof insn); 98*81ad6265SDimitry Andric if (IsLibiptError(status = 99*81ad6265SDimitry Andric pt_insn_next(&m_decoder, &insn, sizeof(insn)))) { 100*81ad6265SDimitry Andric m_decoded_thread.AppendError(IntelPTError(status, insn.ip)); 101*81ad6265SDimitry Andric break; 102*81ad6265SDimitry Andric } 103*81ad6265SDimitry Andric m_decoded_thread.AppendInstruction(insn); 104*81ad6265SDimitry Andric } 105*81ad6265SDimitry Andric } 106*81ad6265SDimitry Andric 107*81ad6265SDimitry Andric /// Move the decoder forward to the next synchronization point (i.e. next PSB 108*81ad6265SDimitry Andric /// packet). 109*81ad6265SDimitry Andric /// 110*81ad6265SDimitry Andric /// Once the decoder is at that synchronization point, it can start decoding 111*81ad6265SDimitry Andric /// instructions. 112*81ad6265SDimitry Andric /// 113*81ad6265SDimitry Andric /// If errors are found, they will be appended to the trace. 114*81ad6265SDimitry Andric /// 115*81ad6265SDimitry Andric /// \return 116*81ad6265SDimitry Andric /// The libipt decoder status after moving to the next PSB. Negative if 117*81ad6265SDimitry Andric /// no PSB was found. 118*81ad6265SDimitry Andric int FindNextSynchronizationPoint() { 119*81ad6265SDimitry Andric // Try to sync the decoder. If it fails, then get the decoder_offset and 120*81ad6265SDimitry Andric // try to sync again from the next synchronization point. If the 121*81ad6265SDimitry Andric // new_decoder_offset is same as decoder_offset then we can't move to the 122*81ad6265SDimitry Andric // next synchronization point. Otherwise, keep resyncing until either end 123*81ad6265SDimitry Andric // of trace stream (eos) is reached or pt_insn_sync_forward() passes. 124*81ad6265SDimitry Andric int status = pt_insn_sync_forward(&m_decoder); 125*81ad6265SDimitry Andric 126*81ad6265SDimitry Andric // We make this call to record any synchronization errors. 127*81ad6265SDimitry Andric if (IsLibiptError(status)) 128*81ad6265SDimitry Andric m_decoded_thread.AppendError(IntelPTError(status)); 129*81ad6265SDimitry Andric 130*81ad6265SDimitry Andric return status; 131*81ad6265SDimitry Andric } 132*81ad6265SDimitry Andric 133*81ad6265SDimitry Andric /// Before querying instructions, we need to query the events associated that 134*81ad6265SDimitry Andric /// instruction e.g. timing events like ptev_tick, or paging events like 135*81ad6265SDimitry Andric /// ptev_paging. 136*81ad6265SDimitry Andric /// 137*81ad6265SDimitry Andric /// \param[in] status 138*81ad6265SDimitry Andric /// The status gotten from the previous instruction decoding or PSB 139*81ad6265SDimitry Andric /// synchronization. 140*81ad6265SDimitry Andric /// 141*81ad6265SDimitry Andric /// \return 142*81ad6265SDimitry Andric /// \b true if no errors were found processing the events. 143*81ad6265SDimitry Andric bool ProcessPTEvents(int status) { 144*81ad6265SDimitry Andric while (status & pts_event_pending) { 145*81ad6265SDimitry Andric pt_event event; 146*81ad6265SDimitry Andric status = pt_insn_event(&m_decoder, &event, sizeof(event)); 147*81ad6265SDimitry Andric if (IsLibiptError(status)) { 148*81ad6265SDimitry Andric m_decoded_thread.AppendError(IntelPTError(status)); 149*81ad6265SDimitry Andric return false; 150*81ad6265SDimitry Andric } 151*81ad6265SDimitry Andric 152*81ad6265SDimitry Andric if (event.has_tsc) 153*81ad6265SDimitry Andric m_decoded_thread.NotifyTsc(event.tsc); 154*81ad6265SDimitry Andric 155*81ad6265SDimitry Andric switch (event.type) { 156*81ad6265SDimitry Andric case ptev_enabled: 157*81ad6265SDimitry Andric // The kernel started or resumed tracing the program. 158*81ad6265SDimitry Andric break; 159*81ad6265SDimitry Andric case ptev_disabled: 160*81ad6265SDimitry Andric // The CPU paused tracing the program, e.g. due to ip filtering. 161*81ad6265SDimitry Andric m_decoded_thread.AppendEvent(lldb::eTraceEventDisabledHW); 162*81ad6265SDimitry Andric break; 163*81ad6265SDimitry Andric case ptev_async_disabled: 164*81ad6265SDimitry Andric // The kernel or user code paused tracing the program, e.g. 165*81ad6265SDimitry Andric // a breakpoint or a ioctl invocation pausing the trace, or a 166*81ad6265SDimitry Andric // context switch happened. 167*81ad6265SDimitry Andric m_decoded_thread.AppendEvent(lldb::eTraceEventDisabledSW); 168*81ad6265SDimitry Andric break; 169*81ad6265SDimitry Andric case ptev_overflow: 170*81ad6265SDimitry Andric // The CPU internal buffer had an overflow error and some instructions 171*81ad6265SDimitry Andric // were lost. 172*81ad6265SDimitry Andric m_decoded_thread.AppendError(IntelPTError(-pte_overflow)); 173*81ad6265SDimitry Andric break; 174*81ad6265SDimitry Andric default: 175*81ad6265SDimitry Andric break; 176*81ad6265SDimitry Andric } 177*81ad6265SDimitry Andric } 178*81ad6265SDimitry Andric 179*81ad6265SDimitry Andric return true; 180*81ad6265SDimitry Andric } 181*81ad6265SDimitry Andric 182*81ad6265SDimitry Andric private: 183*81ad6265SDimitry Andric pt_insn_decoder &m_decoder; 184*81ad6265SDimitry Andric DecodedThread &m_decoded_thread; 185*81ad6265SDimitry Andric }; 186*81ad6265SDimitry Andric 187*81ad6265SDimitry Andric /// Callback used by libipt for reading the process memory. 188*81ad6265SDimitry Andric /// 189*81ad6265SDimitry Andric /// More information can be found in 190*81ad6265SDimitry Andric /// https://github.com/intel/libipt/blob/master/doc/man/pt_image_set_callback.3.md 191*81ad6265SDimitry Andric static int ReadProcessMemory(uint8_t *buffer, size_t size, 192*81ad6265SDimitry Andric const pt_asid * /* unused */, uint64_t pc, 193*81ad6265SDimitry Andric void *context) { 194*81ad6265SDimitry Andric Process *process = static_cast<Process *>(context); 195*81ad6265SDimitry Andric 196*81ad6265SDimitry Andric Status error; 197*81ad6265SDimitry Andric int bytes_read = process->ReadMemory(pc, buffer, size, error); 198*81ad6265SDimitry Andric if (error.Fail()) 199*81ad6265SDimitry Andric return -pte_nomap; 200*81ad6265SDimitry Andric return bytes_read; 201*81ad6265SDimitry Andric } 202*81ad6265SDimitry Andric 203*81ad6265SDimitry Andric // RAII deleter for libipt's decoder 204*81ad6265SDimitry Andric auto DecoderDeleter = [](pt_insn_decoder *decoder) { 205*81ad6265SDimitry Andric pt_insn_free_decoder(decoder); 206*81ad6265SDimitry Andric }; 207*81ad6265SDimitry Andric 208*81ad6265SDimitry Andric using PtInsnDecoderUP = 209*81ad6265SDimitry Andric std::unique_ptr<pt_insn_decoder, decltype(DecoderDeleter)>; 210*81ad6265SDimitry Andric 211*81ad6265SDimitry Andric static Expected<PtInsnDecoderUP> 212*81ad6265SDimitry Andric CreateInstructionDecoder(TraceIntelPT &trace_intel_pt, 213*81ad6265SDimitry Andric ArrayRef<uint8_t> buffer) { 214*81ad6265SDimitry Andric Expected<pt_cpu> cpu_info = trace_intel_pt.GetCPUInfo(); 215*81ad6265SDimitry Andric if (!cpu_info) 216*81ad6265SDimitry Andric return cpu_info.takeError(); 217*81ad6265SDimitry Andric 218*81ad6265SDimitry Andric pt_config config; 219*81ad6265SDimitry Andric pt_config_init(&config); 220*81ad6265SDimitry Andric config.cpu = *cpu_info; 221*81ad6265SDimitry Andric int status = pte_ok; 222*81ad6265SDimitry Andric 223*81ad6265SDimitry Andric if (IsLibiptError(status = pt_cpu_errata(&config.errata, &config.cpu))) 224*81ad6265SDimitry Andric return make_error<IntelPTError>(status); 225*81ad6265SDimitry Andric 226*81ad6265SDimitry Andric // The libipt library does not modify the trace buffer, hence the 227*81ad6265SDimitry Andric // following casts are safe. 228*81ad6265SDimitry Andric config.begin = const_cast<uint8_t *>(buffer.data()); 229*81ad6265SDimitry Andric config.end = const_cast<uint8_t *>(buffer.data() + buffer.size()); 230*81ad6265SDimitry Andric 231*81ad6265SDimitry Andric pt_insn_decoder *decoder_ptr = pt_insn_alloc_decoder(&config); 232*81ad6265SDimitry Andric if (!decoder_ptr) 233*81ad6265SDimitry Andric return make_error<IntelPTError>(-pte_nomem); 234*81ad6265SDimitry Andric 235*81ad6265SDimitry Andric return PtInsnDecoderUP(decoder_ptr, DecoderDeleter); 236*81ad6265SDimitry Andric } 237*81ad6265SDimitry Andric 238*81ad6265SDimitry Andric static Error SetupMemoryImage(PtInsnDecoderUP &decoder_up, Process &process) { 239*81ad6265SDimitry Andric pt_image *image = pt_insn_get_image(decoder_up.get()); 240*81ad6265SDimitry Andric 241*81ad6265SDimitry Andric int status = pte_ok; 242*81ad6265SDimitry Andric if (IsLibiptError( 243*81ad6265SDimitry Andric status = pt_image_set_callback(image, ReadProcessMemory, &process))) 244*81ad6265SDimitry Andric return make_error<IntelPTError>(status); 245*81ad6265SDimitry Andric return Error::success(); 246*81ad6265SDimitry Andric } 247*81ad6265SDimitry Andric 248*81ad6265SDimitry Andric Error lldb_private::trace_intel_pt::DecodeSingleTraceForThread( 249*81ad6265SDimitry Andric DecodedThread &decoded_thread, TraceIntelPT &trace_intel_pt, 250*81ad6265SDimitry Andric ArrayRef<uint8_t> buffer) { 251*81ad6265SDimitry Andric Expected<PtInsnDecoderUP> decoder_up = 252*81ad6265SDimitry Andric CreateInstructionDecoder(trace_intel_pt, buffer); 253*81ad6265SDimitry Andric if (!decoder_up) 254*81ad6265SDimitry Andric return decoder_up.takeError(); 255*81ad6265SDimitry Andric 256*81ad6265SDimitry Andric if (Error err = SetupMemoryImage(*decoder_up, 257*81ad6265SDimitry Andric *decoded_thread.GetThread()->GetProcess())) 258*81ad6265SDimitry Andric return err; 259*81ad6265SDimitry Andric 260*81ad6265SDimitry Andric LibiptDecoder libipt_decoder(*decoder_up.get(), decoded_thread); 261*81ad6265SDimitry Andric libipt_decoder.DecodeUntilEndOfTrace(); 262*81ad6265SDimitry Andric return Error::success(); 263*81ad6265SDimitry Andric } 264*81ad6265SDimitry Andric 265*81ad6265SDimitry Andric Error lldb_private::trace_intel_pt::DecodeSystemWideTraceForThread( 266*81ad6265SDimitry Andric DecodedThread &decoded_thread, TraceIntelPT &trace_intel_pt, 267*81ad6265SDimitry Andric const DenseMap<lldb::cpu_id_t, llvm::ArrayRef<uint8_t>> &buffers, 268*81ad6265SDimitry Andric const std::vector<IntelPTThreadContinousExecution> &executions) { 269*81ad6265SDimitry Andric DenseMap<lldb::cpu_id_t, LibiptDecoder> decoders; 270*81ad6265SDimitry Andric for (auto &cpu_id_buffer : buffers) { 271*81ad6265SDimitry Andric Expected<PtInsnDecoderUP> decoder_up = 272*81ad6265SDimitry Andric CreateInstructionDecoder(trace_intel_pt, cpu_id_buffer.second); 273*81ad6265SDimitry Andric if (!decoder_up) 274*81ad6265SDimitry Andric return decoder_up.takeError(); 275*81ad6265SDimitry Andric 276*81ad6265SDimitry Andric if (Error err = SetupMemoryImage(*decoder_up, 277*81ad6265SDimitry Andric *decoded_thread.GetThread()->GetProcess())) 278*81ad6265SDimitry Andric return err; 279*81ad6265SDimitry Andric 280*81ad6265SDimitry Andric decoders.try_emplace(cpu_id_buffer.first, 281*81ad6265SDimitry Andric LibiptDecoder(*decoder_up->release(), decoded_thread)); 282*81ad6265SDimitry Andric } 283*81ad6265SDimitry Andric 284*81ad6265SDimitry Andric bool has_seen_psbs = false; 285*81ad6265SDimitry Andric for (size_t i = 0; i < executions.size(); i++) { 286*81ad6265SDimitry Andric const IntelPTThreadContinousExecution &execution = executions[i]; 287*81ad6265SDimitry Andric 288*81ad6265SDimitry Andric auto variant = execution.thread_execution.variant; 289*81ad6265SDimitry Andric // If we haven't seen a PSB yet, then it's fine not to show errors 290*81ad6265SDimitry Andric if (has_seen_psbs) { 291*81ad6265SDimitry Andric if (execution.intelpt_subtraces.empty()) { 292*81ad6265SDimitry Andric decoded_thread.AppendCustomError( 293*81ad6265SDimitry Andric formatv("Unable to find intel pt data for thread " 294*81ad6265SDimitry Andric "execution on cpu id = {0}", 295*81ad6265SDimitry Andric execution.thread_execution.cpu_id) 296*81ad6265SDimitry Andric .str()); 297*81ad6265SDimitry Andric } 298*81ad6265SDimitry Andric 299*81ad6265SDimitry Andric // If the first execution is incomplete because it doesn't have a previous 300*81ad6265SDimitry Andric // context switch in its cpu, all good. 301*81ad6265SDimitry Andric if (variant == ThreadContinuousExecution::Variant::OnlyEnd || 302*81ad6265SDimitry Andric variant == ThreadContinuousExecution::Variant::HintedStart) { 303*81ad6265SDimitry Andric decoded_thread.AppendCustomError( 304*81ad6265SDimitry Andric formatv("Thread execution starting on cpu id = {0} doesn't " 305*81ad6265SDimitry Andric "have a matching context switch in.", 306*81ad6265SDimitry Andric execution.thread_execution.cpu_id) 307*81ad6265SDimitry Andric .str()); 308*81ad6265SDimitry Andric } 309*81ad6265SDimitry Andric } 310*81ad6265SDimitry Andric 311*81ad6265SDimitry Andric LibiptDecoder &decoder = 312*81ad6265SDimitry Andric decoders.find(execution.thread_execution.cpu_id)->second; 313*81ad6265SDimitry Andric for (const IntelPTThreadSubtrace &intel_pt_execution : 314*81ad6265SDimitry Andric execution.intelpt_subtraces) { 315*81ad6265SDimitry Andric has_seen_psbs = true; 316*81ad6265SDimitry Andric decoder.DecodePSB(intel_pt_execution.psb_offset); 317*81ad6265SDimitry Andric } 318*81ad6265SDimitry Andric 319*81ad6265SDimitry Andric // If we haven't seen a PSB yet, then it's fine not to show errors 320*81ad6265SDimitry Andric if (has_seen_psbs) { 321*81ad6265SDimitry Andric // If the last execution is incomplete because it doesn't have a following 322*81ad6265SDimitry Andric // context switch in its cpu, all good. 323*81ad6265SDimitry Andric if ((variant == ThreadContinuousExecution::Variant::OnlyStart && 324*81ad6265SDimitry Andric i + 1 != executions.size()) || 325*81ad6265SDimitry Andric variant == ThreadContinuousExecution::Variant::HintedEnd) { 326*81ad6265SDimitry Andric decoded_thread.AppendCustomError( 327*81ad6265SDimitry Andric formatv("Thread execution on cpu id = {0} doesn't have a " 328*81ad6265SDimitry Andric "matching context switch out", 329*81ad6265SDimitry Andric execution.thread_execution.cpu_id) 330*81ad6265SDimitry Andric .str()); 331*81ad6265SDimitry Andric } 332*81ad6265SDimitry Andric } 333*81ad6265SDimitry Andric } 334*81ad6265SDimitry Andric return Error::success(); 335*81ad6265SDimitry Andric } 336*81ad6265SDimitry Andric 337*81ad6265SDimitry Andric bool IntelPTThreadContinousExecution::operator<( 338*81ad6265SDimitry Andric const IntelPTThreadContinousExecution &o) const { 339*81ad6265SDimitry Andric // As the context switch might be incomplete, we look first for the first real 340*81ad6265SDimitry Andric // PSB packet, which is a valid TSC. Otherwise, We query the thread execution 341*81ad6265SDimitry Andric // itself for some tsc. 342*81ad6265SDimitry Andric auto get_tsc = [](const IntelPTThreadContinousExecution &exec) { 343*81ad6265SDimitry Andric return exec.intelpt_subtraces.empty() 344*81ad6265SDimitry Andric ? exec.thread_execution.GetLowestKnownTSC() 345*81ad6265SDimitry Andric : exec.intelpt_subtraces.front().tsc; 346*81ad6265SDimitry Andric }; 347*81ad6265SDimitry Andric 348*81ad6265SDimitry Andric return get_tsc(*this) < get_tsc(o); 349*81ad6265SDimitry Andric } 350*81ad6265SDimitry Andric 351*81ad6265SDimitry Andric Expected<std::vector<IntelPTThreadSubtrace>> 352*81ad6265SDimitry Andric lldb_private::trace_intel_pt::SplitTraceInContinuousExecutions( 353*81ad6265SDimitry Andric TraceIntelPT &trace_intel_pt, llvm::ArrayRef<uint8_t> buffer) { 354*81ad6265SDimitry Andric Expected<PtInsnDecoderUP> decoder_up = 355*81ad6265SDimitry Andric CreateInstructionDecoder(trace_intel_pt, buffer); 356*81ad6265SDimitry Andric if (!decoder_up) 357*81ad6265SDimitry Andric return decoder_up.takeError(); 358*81ad6265SDimitry Andric 359*81ad6265SDimitry Andric pt_insn_decoder *decoder = decoder_up.get().get(); 360*81ad6265SDimitry Andric 361*81ad6265SDimitry Andric std::vector<IntelPTThreadSubtrace> executions; 362*81ad6265SDimitry Andric 363*81ad6265SDimitry Andric int status = pte_ok; 364*81ad6265SDimitry Andric while (!IsLibiptError(status = pt_insn_sync_forward(decoder))) { 365*81ad6265SDimitry Andric uint64_t tsc; 366*81ad6265SDimitry Andric if (IsLibiptError(pt_insn_time(decoder, &tsc, nullptr, nullptr))) 367*81ad6265SDimitry Andric return createStringError(inconvertibleErrorCode(), 368*81ad6265SDimitry Andric "intel pt trace doesn't have TSC timestamps"); 369*81ad6265SDimitry Andric 370*81ad6265SDimitry Andric uint64_t psb_offset; 371*81ad6265SDimitry Andric pt_insn_get_sync_offset(decoder, 372*81ad6265SDimitry Andric &psb_offset); // this can't fail because we got here 373*81ad6265SDimitry Andric 374*81ad6265SDimitry Andric executions.push_back({ 375*81ad6265SDimitry Andric psb_offset, 376*81ad6265SDimitry Andric tsc, 377*81ad6265SDimitry Andric }); 378*81ad6265SDimitry Andric } 379*81ad6265SDimitry Andric return executions; 380*81ad6265SDimitry Andric } 381