brintos

brintos / llvm-project-archived public Read only

0
0
Text · 29.3 KiB · f8241ef Raw
784 lines · cpp
1//===-- LibiptDecoder.cpp --======-----------------------------------------===//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7 8#include "LibiptDecoder.h"9#include "TraceIntelPT.h"10#include "lldb/Target/Process.h"11#include <optional>12 13using namespace lldb;14using namespace lldb_private;15using namespace lldb_private::trace_intel_pt;16using namespace llvm;17 18bool IsLibiptError(int status) { return status < 0; }19 20bool IsEndOfStream(int status) {21  assert(status >= 0 && "We can't check if we reached the end of the stream if "22                        "we got a failed status");23  return status & pts_eos;24}25 26bool HasEvents(int status) {27  assert(status >= 0 && "We can't check for events if we got a failed status");28  return status & pts_event_pending;29}30 31// RAII deleter for libipt's decoders32auto InsnDecoderDeleter = [](pt_insn_decoder *decoder) {33  pt_insn_free_decoder(decoder);34};35 36auto QueryDecoderDeleter = [](pt_query_decoder *decoder) {37  pt_qry_free_decoder(decoder);38};39 40using PtInsnDecoderUP =41    std::unique_ptr<pt_insn_decoder, decltype(InsnDecoderDeleter)>;42 43using PtQueryDecoderUP =44    std::unique_ptr<pt_query_decoder, decltype(QueryDecoderDeleter)>;45 46/// Create a basic configuration object limited to a given buffer that can be47/// used for many different decoders.48static Expected<pt_config> CreateBasicLibiptConfig(TraceIntelPT &trace_intel_pt,49                                                   ArrayRef<uint8_t> buffer) {50  Expected<pt_cpu> cpu_info = trace_intel_pt.GetCPUInfo();51  if (!cpu_info)52    return cpu_info.takeError();53 54  pt_config config;55  pt_config_init(&config);56  config.cpu = *cpu_info;57 58  int status = pt_cpu_errata(&config.errata, &config.cpu);59  if (IsLibiptError(status))60    return make_error<IntelPTError>(status);61 62  // The libipt library does not modify the trace buffer, hence the63  // following casts are safe.64  config.begin = const_cast<uint8_t *>(buffer.data());65  config.end = const_cast<uint8_t *>(buffer.data() + buffer.size());66  return config;67}68 69/// Callback used by libipt for reading the process memory.70///71/// More information can be found in72/// https://github.com/intel/libipt/blob/master/doc/man/pt_image_set_callback.3.md73static int ReadProcessMemory(uint8_t *buffer, size_t size,74                             const pt_asid * /* unused */, uint64_t pc,75                             void *context) {76  Process *process = static_cast<Process *>(context);77 78  Status error;79  int bytes_read = process->ReadMemory(pc, buffer, size, error);80  if (error.Fail())81    return -pte_nomap;82  return bytes_read;83}84 85/// Set up the memory image callback for the given decoder.86static Error SetupMemoryImage(pt_insn_decoder *decoder, Process &process) {87  pt_image *image = pt_insn_get_image(decoder);88 89  int status = pt_image_set_callback(image, ReadProcessMemory, &process);90  if (IsLibiptError(status))91    return make_error<IntelPTError>(status);92  return Error::success();93}94 95/// Create an instruction decoder for the given buffer and the given process.96static Expected<PtInsnDecoderUP>97CreateInstructionDecoder(TraceIntelPT &trace_intel_pt, ArrayRef<uint8_t> buffer,98                         Process &process) {99  Expected<pt_config> config = CreateBasicLibiptConfig(trace_intel_pt, buffer);100  if (!config)101    return config.takeError();102 103  pt_insn_decoder *decoder_ptr = pt_insn_alloc_decoder(&*config);104  if (!decoder_ptr)105    return make_error<IntelPTError>(-pte_nomem);106 107  PtInsnDecoderUP decoder_up(decoder_ptr, InsnDecoderDeleter);108 109  if (Error err = SetupMemoryImage(decoder_ptr, process))110    return std::move(err);111 112  return decoder_up;113}114 115/// Create a query decoder for the given buffer. The query decoder is the116/// highest level decoder that operates directly on packets and doesn't perform117/// actual instruction decoding. That's why it can be useful for inspecting a118/// raw trace without pinning it to a particular process.119static Expected<PtQueryDecoderUP>120CreateQueryDecoder(TraceIntelPT &trace_intel_pt, ArrayRef<uint8_t> buffer) {121  Expected<pt_config> config = CreateBasicLibiptConfig(trace_intel_pt, buffer);122  if (!config)123    return config.takeError();124 125  pt_query_decoder *decoder_ptr = pt_qry_alloc_decoder(&*config);126  if (!decoder_ptr)127    return make_error<IntelPTError>(-pte_nomem);128 129  return PtQueryDecoderUP(decoder_ptr, QueryDecoderDeleter);130}131 132/// Class used to identify anomalies in traces, which should often indicate a133/// fatal error in the trace.134class PSBBlockAnomalyDetector {135public:136  PSBBlockAnomalyDetector(pt_insn_decoder &decoder,137                          TraceIntelPT &trace_intel_pt,138                          DecodedThread &decoded_thread)139      : m_decoder(decoder), m_decoded_thread(decoded_thread) {140    m_infinite_decoding_loop_threshold =141        trace_intel_pt.GetGlobalProperties()142            .GetInfiniteDecodingLoopVerificationThreshold();143    m_extremely_large_decoding_threshold =144        trace_intel_pt.GetGlobalProperties()145            .GetExtremelyLargeDecodingThreshold();146    m_next_infinite_decoding_loop_threshold =147        m_infinite_decoding_loop_threshold;148  }149 150  /// \return151  ///   An \a llvm::Error if an anomaly that includes the last instruction item152  ///   in the trace, or \a llvm::Error::success otherwise.153  Error DetectAnomaly() {154    RefreshPacketOffset();155    uint64_t insn_added_since_last_packet_offset =156        m_decoded_thread.GetTotalInstructionCount() -157        m_insn_count_at_last_packet_offset;158 159    // We want to check if we might have fallen in an infinite loop. As this160    // check is not a no-op, we want to do it when we have a strong suggestion161    // that things went wrong. First, we check how many instructions we have162    // decoded since we processed an Intel PT packet for the last time. This163    // number should be low, because at some point we should see branches, jumps164    // or interrupts that require a new packet to be processed. Once we reach165    // certain threshold we start analyzing the trace.166    //167    // We use the number of decoded instructions since the last Intel PT packet168    // as a proxy because, in fact, we don't expect a single packet to give,169    // say, 100k instructions. That would mean that there are 100k sequential170    // instructions without any single branch, which is highly unlikely, or that171    // we found an infinite loop using direct jumps, e.g.172    //173    //   0x0A: nop or pause174    //   0x0C: jump to 0x0A175    //176    // which is indeed code that is found in the kernel. I presume we reach177    // this kind of code in the decoder because we don't handle self-modified178    // code in post-mortem kernel traces.179    //180    // We are right now only signaling the anomaly as a trace error, but it181    // would be more conservative to also discard all the trace items found in182    // this PSB. I prefer not to do that for the time being to give more183    // exposure to this kind of anomalies and help debugging. Discarding the184    // trace items would just make investigation harded.185    //186    // Finally, if the user wants to see if a specific thread has an anomaly,187    // it's enough to run the `thread trace dump info` command and look for the188    // count of this kind of errors.189 190    if (insn_added_since_last_packet_offset >=191        m_extremely_large_decoding_threshold) {192      // In this case, we have decoded a massive amount of sequential193      // instructions that don't loop. Honestly I wonder if this will ever194      // happen, but better safe than sorry.195      return createStringError(196          inconvertibleErrorCode(),197          "anomalous trace: possible infinite trace detected");198    }199    if (insn_added_since_last_packet_offset ==200        m_next_infinite_decoding_loop_threshold) {201      if (std::optional<uint64_t> loop_size = TryIdentifyInfiniteLoop()) {202        return createStringError(203            inconvertibleErrorCode(),204            "anomalous trace: possible infinite loop detected of size %" PRIu64,205            *loop_size);206      }207      m_next_infinite_decoding_loop_threshold *= 2;208    }209    return Error::success();210  }211 212private:213  std::optional<uint64_t> TryIdentifyInfiniteLoop() {214    // The infinite decoding loops we'll encounter are due to sequential215    // instructions that repeat themselves due to direct jumps, therefore in a216    // cycle each individual address will only appear once. We use this217    // information to detect cycles by finding the last 2 ocurrences of the last218    // instruction added to the trace. Then we traverse the trace making sure219    // that these two instructions where the ends of a repeating loop.220 221    // This is a utility that returns the most recent instruction index given a222    // position in the trace. If the given position is an instruction, that223    // position is returned. It skips non-instruction items.224    auto most_recent_insn_index =225        [&](uint64_t item_index) -> std::optional<uint64_t> {226      while (true) {227        if (m_decoded_thread.GetItemKindByIndex(item_index) ==228            lldb::eTraceItemKindInstruction) {229          return item_index;230        }231        if (item_index == 0)232          return std::nullopt;233        item_index--;234      }235      return std::nullopt;236    };237    // Similar to most_recent_insn_index but skips the starting position.238    auto prev_insn_index = [&](uint64_t item_index) -> std::optional<uint64_t> {239      if (item_index == 0)240        return std::nullopt;241      return most_recent_insn_index(item_index - 1);242    };243 244    // We first find the most recent instruction.245    std::optional<uint64_t> last_insn_index_opt =246        *prev_insn_index(m_decoded_thread.GetItemsCount());247    if (!last_insn_index_opt)248      return std::nullopt;249    uint64_t last_insn_index = *last_insn_index_opt;250 251    // We then find the most recent previous occurrence of that last252    // instruction.253    std::optional<uint64_t> last_insn_copy_index =254        prev_insn_index(last_insn_index);255    uint64_t loop_size = 1;256    while (last_insn_copy_index &&257           m_decoded_thread.GetInstructionLoadAddress(*last_insn_copy_index) !=258               m_decoded_thread.GetInstructionLoadAddress(last_insn_index)) {259      last_insn_copy_index = prev_insn_index(*last_insn_copy_index);260      loop_size++;261    }262    if (!last_insn_copy_index)263      return std::nullopt;264 265    // Now we check if the segment between these last positions of the last266    // instruction address is in fact a repeating loop.267    uint64_t loop_elements_visited = 1;268    uint64_t insn_index_a = last_insn_index,269             insn_index_b = *last_insn_copy_index;270    while (loop_elements_visited < loop_size) {271      if (std::optional<uint64_t> prev = prev_insn_index(insn_index_a))272        insn_index_a = *prev;273      else274        return std::nullopt;275      if (std::optional<uint64_t> prev = prev_insn_index(insn_index_b))276        insn_index_b = *prev;277      else278        return std::nullopt;279      if (m_decoded_thread.GetInstructionLoadAddress(insn_index_a) !=280          m_decoded_thread.GetInstructionLoadAddress(insn_index_b))281        return std::nullopt;282      loop_elements_visited++;283    }284    return loop_size;285  }286 287  // Refresh the internal counters if a new packet offset has been visited288  void RefreshPacketOffset() {289    lldb::addr_t new_packet_offset;290    if (!IsLibiptError(pt_insn_get_offset(&m_decoder, &new_packet_offset)) &&291        new_packet_offset != m_last_packet_offset) {292      m_last_packet_offset = new_packet_offset;293      m_next_infinite_decoding_loop_threshold =294          m_infinite_decoding_loop_threshold;295      m_insn_count_at_last_packet_offset =296          m_decoded_thread.GetTotalInstructionCount();297    }298  }299 300  pt_insn_decoder &m_decoder;301  DecodedThread &m_decoded_thread;302  lldb::addr_t m_last_packet_offset = LLDB_INVALID_ADDRESS;303  uint64_t m_insn_count_at_last_packet_offset = 0;304  uint64_t m_infinite_decoding_loop_threshold;305  uint64_t m_next_infinite_decoding_loop_threshold;306  uint64_t m_extremely_large_decoding_threshold;307};308 309/// Class that decodes a raw buffer for a single PSB block using the low level310/// libipt library. It assumes that kernel and user mode instructions are not311/// mixed in the same PSB block.312///313/// Throughout this code, the status of the decoder will be used to identify314/// events needed to be processed or errors in the decoder. The values can be315/// - negative: actual errors316/// - positive or zero: not an error, but a list of bits signaling the status317/// of the decoder, e.g. whether there are events that need to be decoded or318/// not.319class PSBBlockDecoder {320public:321  /// \param[in] decoder322  ///     A decoder configured to start and end within the boundaries of the323  ///     given \p psb_block.324  ///325  /// \param[in] psb_block326  ///     The PSB block to decode.327  ///328  /// \param[in] next_block_ip329  ///     The starting ip at the next PSB block of the same thread if available.330  ///331  /// \param[in] decoded_thread332  ///     A \a DecodedThread object where the decoded instructions will be333  ///     appended to. It might have already some instructions.334  ///335  /// \param[in] tsc_upper_bound336  ///   Maximum allowed value of TSCs decoded from this PSB block.337  ///   Any of this PSB's data occurring after this TSC will be excluded.338  PSBBlockDecoder(PtInsnDecoderUP &&decoder_up, const PSBBlock &psb_block,339                  std::optional<lldb::addr_t> next_block_ip,340                  DecodedThread &decoded_thread, TraceIntelPT &trace_intel_pt,341                  std::optional<DecodedThread::TSC> tsc_upper_bound)342      : m_decoder_up(std::move(decoder_up)), m_psb_block(psb_block),343        m_next_block_ip(next_block_ip), m_decoded_thread(decoded_thread),344        m_anomaly_detector(*m_decoder_up, trace_intel_pt, decoded_thread),345        m_tsc_upper_bound(tsc_upper_bound) {}346 347  /// \param[in] trace_intel_pt348  ///     The main Trace object that own the PSB block.349  ///350  /// \param[in] decoder351  ///     A decoder configured to start and end within the boundaries of the352  ///     given \p psb_block.353  ///354  /// \param[in] psb_block355  ///     The PSB block to decode.356  ///357  /// \param[in] buffer358  ///     The raw intel pt trace for this block.359  ///360  /// \param[in] process361  ///     The process to decode. It provides the memory image to use for362  ///     decoding.363  ///364  /// \param[in] next_block_ip365  ///     The starting ip at the next PSB block of the same thread if available.366  ///367  /// \param[in] decoded_thread368  ///     A \a DecodedThread object where the decoded instructions will be369  ///     appended to. It might have already some instructions.370  static Expected<PSBBlockDecoder>371  Create(TraceIntelPT &trace_intel_pt, const PSBBlock &psb_block,372         ArrayRef<uint8_t> buffer, Process &process,373         std::optional<lldb::addr_t> next_block_ip,374         DecodedThread &decoded_thread,375         std::optional<DecodedThread::TSC> tsc_upper_bound) {376    Expected<PtInsnDecoderUP> decoder_up =377        CreateInstructionDecoder(trace_intel_pt, buffer, process);378    if (!decoder_up)379      return decoder_up.takeError();380 381    return PSBBlockDecoder(std::move(*decoder_up), psb_block, next_block_ip,382                           decoded_thread, trace_intel_pt, tsc_upper_bound);383  }384 385  void DecodePSBBlock() {386    int status = pt_insn_sync_forward(m_decoder_up.get());387    assert(status >= 0 &&388           "Synchronization shouldn't fail because this PSB was previously "389           "decoded correctly.");390 391    // We emit a TSC before a sync event to more easily associate a timestamp to392    // the sync event. If present, the current block's TSC would be the first393    // TSC we'll see when processing events.394    if (m_psb_block.tsc)395      m_decoded_thread.NotifyTsc(*m_psb_block.tsc);396 397    m_decoded_thread.NotifySyncPoint(m_psb_block.psb_offset);398 399    DecodeInstructionsAndEvents(status);400  }401 402private:403  /// Append an instruction and return \b false if and only if a serious anomaly404  /// has been detected.405  bool AppendInstructionAndDetectAnomalies(const pt_insn &insn) {406    m_decoded_thread.AppendInstruction(insn);407 408    if (Error err = m_anomaly_detector.DetectAnomaly()) {409      m_decoded_thread.AppendCustomError(toString(std::move(err)),410                                         /*fatal=*/true);411      return false;412    }413    return true;414  }415  /// Decode all the instructions and events of the given PSB block. The416  /// decoding loop might stop abruptly if an infinite decoding loop is417  /// detected.418  void DecodeInstructionsAndEvents(int status) {419    pt_insn insn;420 421    while (true) {422      status = ProcessPTEvents(status);423 424      if (IsLibiptError(status))425        return;426      else if (IsEndOfStream(status))427        break;428 429      // The status returned by pt_insn_next will need to be processed430      // by ProcessPTEvents in the next loop if it is not an error.431      std::memset(&insn, 0, sizeof insn);432      status = pt_insn_next(m_decoder_up.get(), &insn, sizeof(insn));433 434      if (IsLibiptError(status)) {435        m_decoded_thread.AppendError(IntelPTError(status, insn.ip));436        return;437      } else if (IsEndOfStream(status)) {438        break;439      }440 441      if (!AppendInstructionAndDetectAnomalies(insn))442        return;443    }444 445    // We need to keep querying non-branching instructions until we hit the446    // starting point of the next PSB. We won't see events at this point. This447    // is based on448    // https://github.com/intel/libipt/blob/master/doc/howto_libipt.md#parallel-decode449    if (m_next_block_ip && insn.ip != 0) {450      while (insn.ip != *m_next_block_ip) {451        if (!AppendInstructionAndDetectAnomalies(insn))452          return;453 454        status = pt_insn_next(m_decoder_up.get(), &insn, sizeof(insn));455 456        if (IsLibiptError(status)) {457          m_decoded_thread.AppendError(IntelPTError(status, insn.ip));458          return;459        }460      }461    }462  }463 464  /// Process the TSC of a decoded PT event. Specifically, check if this TSC465  /// is below the TSC upper bound for this PSB. If the TSC exceeds the upper466  /// bound, return an error to abort decoding. Otherwise add the it to the467  /// underlying DecodedThread and decoding should continue as expected.468  ///469  /// \param[in] tsc470  ///   The TSC of the a decoded event.471  Error ProcessPTEventTSC(DecodedThread::TSC tsc) {472    if (m_tsc_upper_bound && tsc >= *m_tsc_upper_bound) {473      // This event and all the remaining events of this PSB have a TSC474      // outside the range of the "owning" ThreadContinuousExecution. For475      // now we drop all of these events/instructions, future work can476      // improve upon this by determining the "owning"477      // ThreadContinuousExecution of the remaining PSB data.478      std::string err_msg = formatv("decoding truncated: TSC {0} exceeds "479                                    "maximum TSC value {1}, will skip decoding"480                                    " the remaining data of the PSB",481                                    tsc, *m_tsc_upper_bound)482                                .str();483 484      uint64_t offset;485      int status = pt_insn_get_offset(m_decoder_up.get(), &offset);486      if (!IsLibiptError(status)) {487        err_msg = formatv("{2} (skipping {0} of {1} bytes)", offset,488                          m_psb_block.size, err_msg)489                      .str();490      }491      m_decoded_thread.AppendCustomError(err_msg);492      return createStringError(inconvertibleErrorCode(), err_msg);493    } else {494      m_decoded_thread.NotifyTsc(tsc);495      return Error::success();496    }497  }498 499  /// Before querying instructions, we need to query the events associated with500  /// that instruction, e.g. timing and trace disablement events.501  ///502  /// \param[in] status503  ///   The status gotten from the previous instruction decoding or PSB504  ///   synchronization.505  ///506  /// \return507  ///     The pte_status after decoding events.508  int ProcessPTEvents(int status) {509    while (HasEvents(status)) {510      pt_event event;511      std::memset(&event, 0, sizeof event);512      status = pt_insn_event(m_decoder_up.get(), &event, sizeof(event));513 514      if (IsLibiptError(status)) {515        m_decoded_thread.AppendError(IntelPTError(status));516        return status;517      }518 519      if (event.has_tsc) {520        if (Error err = ProcessPTEventTSC(event.tsc)) {521          consumeError(std::move(err));522          return -pte_internal;523        }524      }525 526      switch (event.type) {527      case ptev_disabled:528        // The CPU paused tracing the program, e.g. due to ip filtering.529        m_decoded_thread.AppendEvent(lldb::eTraceEventDisabledHW);530        break;531      case ptev_async_disabled:532        // The kernel or user code paused tracing the program, e.g.533        // a breakpoint or a ioctl invocation pausing the trace, or a534        // context switch happened.535        m_decoded_thread.AppendEvent(lldb::eTraceEventDisabledSW);536        break;537      case ptev_overflow:538        // The CPU internal buffer had an overflow error and some instructions539        // were lost. A OVF packet comes with an FUP packet (harcoded address)540        // according to the documentation, so we'll continue seeing instructions541        // after this event.542        m_decoded_thread.AppendError(IntelPTError(-pte_overflow));543        break;544      default:545        break;546      }547    }548 549    return status;550  }551 552private:553  PtInsnDecoderUP m_decoder_up;554  PSBBlock m_psb_block;555  std::optional<lldb::addr_t> m_next_block_ip;556  DecodedThread &m_decoded_thread;557  PSBBlockAnomalyDetector m_anomaly_detector;558  std::optional<DecodedThread::TSC> m_tsc_upper_bound;559};560 561Error lldb_private::trace_intel_pt::DecodeSingleTraceForThread(562    DecodedThread &decoded_thread, TraceIntelPT &trace_intel_pt,563    ArrayRef<uint8_t> buffer) {564  Expected<std::vector<PSBBlock>> blocks =565      SplitTraceIntoPSBBlock(trace_intel_pt, buffer, /*expect_tscs=*/false);566  if (!blocks)567    return blocks.takeError();568 569  for (size_t i = 0; i < blocks->size(); i++) {570    PSBBlock &block = blocks->at(i);571 572    Expected<PSBBlockDecoder> decoder = PSBBlockDecoder::Create(573        trace_intel_pt, block, buffer.slice(block.psb_offset, block.size),574        *decoded_thread.GetThread()->GetProcess(),575        i + 1 < blocks->size() ? blocks->at(i + 1).starting_ip : std::nullopt,576        decoded_thread, std::nullopt);577    if (!decoder)578      return decoder.takeError();579 580    decoder->DecodePSBBlock();581  }582 583  return Error::success();584}585 586Error lldb_private::trace_intel_pt::DecodeSystemWideTraceForThread(587    DecodedThread &decoded_thread, TraceIntelPT &trace_intel_pt,588    const DenseMap<lldb::cpu_id_t, llvm::ArrayRef<uint8_t>> &buffers,589    const std::vector<IntelPTThreadContinousExecution> &executions) {590  bool has_seen_psbs = false;591  for (size_t i = 0; i < executions.size(); i++) {592    const IntelPTThreadContinousExecution &execution = executions[i];593 594    auto variant = execution.thread_execution.variant;595 596    // We emit the first valid tsc597    if (execution.psb_blocks.empty()) {598      decoded_thread.NotifyTsc(execution.thread_execution.GetLowestKnownTSC());599    } else {600      assert(execution.psb_blocks.front().tsc &&601             "per cpu decoding expects TSCs");602      decoded_thread.NotifyTsc(603          std::min(execution.thread_execution.GetLowestKnownTSC(),604                   *execution.psb_blocks.front().tsc));605    }606 607    // We then emit the CPU, which will be correctly associated with a tsc.608    decoded_thread.NotifyCPU(execution.thread_execution.cpu_id);609 610    // If we haven't seen a PSB yet, then it's fine not to show errors611    if (has_seen_psbs) {612      if (execution.psb_blocks.empty()) {613        decoded_thread.AppendCustomError(614            formatv("Unable to find intel pt data a thread "615                    "execution on cpu id = {0}",616                    execution.thread_execution.cpu_id)617                .str());618      }619 620      // A hinted start is a non-initial execution that doesn't have a switch621      // in. An only end is an initial execution that doesn't have a switch in.622      // Any of those cases represent a gap because we have seen a PSB before.623      if (variant == ThreadContinuousExecution::Variant::HintedStart ||624          variant == ThreadContinuousExecution::Variant::OnlyEnd) {625        decoded_thread.AppendCustomError(626            formatv("Unable to find the context switch in for a thread "627                    "execution on cpu id = {0}",628                    execution.thread_execution.cpu_id)629                .str());630      }631    }632 633    for (size_t j = 0; j < execution.psb_blocks.size(); j++) {634      const PSBBlock &psb_block = execution.psb_blocks[j];635 636      Expected<PSBBlockDecoder> decoder = PSBBlockDecoder::Create(637          trace_intel_pt, psb_block,638          buffers.lookup(execution.thread_execution.cpu_id)639              .slice(psb_block.psb_offset, psb_block.size),640          *decoded_thread.GetThread()->GetProcess(),641          j + 1 < execution.psb_blocks.size()642              ? execution.psb_blocks[j + 1].starting_ip643              : std::nullopt,644          decoded_thread, execution.thread_execution.GetEndTSC());645      if (!decoder)646        return decoder.takeError();647 648      has_seen_psbs = true;649      decoder->DecodePSBBlock();650    }651 652    // If we haven't seen a PSB yet, then it's fine not to show errors653    if (has_seen_psbs) {654      // A hinted end is a non-ending execution that doesn't have a switch out.655      // An only start is an ending execution that doesn't have a switch out.656      // Any of those cases represent a gap if we still have executions to657      // process and we have seen a PSB before.658      if (i + 1 != executions.size() &&659          (variant == ThreadContinuousExecution::Variant::OnlyStart ||660           variant == ThreadContinuousExecution::Variant::HintedEnd)) {661        decoded_thread.AppendCustomError(662            formatv("Unable to find the context switch out for a thread "663                    "execution on cpu id = {0}",664                    execution.thread_execution.cpu_id)665                .str());666      }667    }668  }669  return Error::success();670}671 672bool IntelPTThreadContinousExecution::operator<(673    const IntelPTThreadContinousExecution &o) const {674  // As the context switch might be incomplete, we look first for the first real675  // PSB packet, which is a valid TSC. Otherwise, We query the thread execution676  // itself for some tsc.677  auto get_tsc = [](const IntelPTThreadContinousExecution &exec) {678    return exec.psb_blocks.empty() ? exec.thread_execution.GetLowestKnownTSC()679                                   : exec.psb_blocks.front().tsc;680  };681 682  return get_tsc(*this) < get_tsc(o);683}684 685Expected<std::vector<PSBBlock>>686lldb_private::trace_intel_pt::SplitTraceIntoPSBBlock(687    TraceIntelPT &trace_intel_pt, llvm::ArrayRef<uint8_t> buffer,688    bool expect_tscs) {689  // This follows690  // https://github.com/intel/libipt/blob/master/doc/howto_libipt.md#parallel-decode691 692  Expected<PtQueryDecoderUP> decoder_up =693      CreateQueryDecoder(trace_intel_pt, buffer);694  if (!decoder_up)695    return decoder_up.takeError();696 697  pt_query_decoder *decoder = decoder_up.get().get();698 699  std::vector<PSBBlock> executions;700 701  while (true) {702    uint64_t maybe_ip = LLDB_INVALID_ADDRESS;703    int decoding_status = pt_qry_sync_forward(decoder, &maybe_ip);704    if (IsLibiptError(decoding_status))705      break;706 707    uint64_t psb_offset;708    int offset_status = pt_qry_get_sync_offset(decoder, &psb_offset);709    assert(offset_status >= 0 &&710           "This can't fail because we were able to synchronize");711 712    std::optional<uint64_t> ip;713    if (!(pts_ip_suppressed & decoding_status))714      ip = maybe_ip;715 716    std::optional<uint64_t> tsc;717    // Now we fetch the first TSC that comes after the PSB.718    while (HasEvents(decoding_status)) {719      pt_event event;720      decoding_status = pt_qry_event(decoder, &event, sizeof(event));721      if (IsLibiptError(decoding_status))722        break;723      if (event.has_tsc) {724        tsc = event.tsc;725        break;726      }727    }728    if (IsLibiptError(decoding_status)) {729      // We continue to the next PSB. This effectively merges this PSB with the730      // previous one, and that should be fine because this PSB might be the731      // direct continuation of the previous thread and it's better to show an732      // error in the decoded thread than to hide it. If this is the first PSB,733      // we are okay losing it. Besides that, an error at processing events734      // means that we wouldn't be able to get any instruction out of it.735      continue;736    }737 738    if (expect_tscs && !tsc)739      return createStringError(inconvertibleErrorCode(),740                               "Found a PSB without TSC.");741 742    executions.push_back({743        psb_offset,744        tsc,745        0,746        ip,747    });748  }749  if (!executions.empty()) {750    // We now adjust the sizes of each block751    executions.back().size = buffer.size() - executions.back().psb_offset;752    for (int i = (int)executions.size() - 2; i >= 0; i--) {753      executions[i].size =754          executions[i + 1].psb_offset - executions[i].psb_offset;755    }756  }757  return executions;758}759 760Expected<std::optional<uint64_t>>761lldb_private::trace_intel_pt::FindLowestTSCInTrace(TraceIntelPT &trace_intel_pt,762                                                   ArrayRef<uint8_t> buffer) {763  Expected<PtQueryDecoderUP> decoder_up =764      CreateQueryDecoder(trace_intel_pt, buffer);765  if (!decoder_up)766    return decoder_up.takeError();767 768  pt_query_decoder *decoder = decoder_up.get().get();769  uint64_t ip = LLDB_INVALID_ADDRESS;770  int status = pt_qry_sync_forward(decoder, &ip);771  if (IsLibiptError(status))772    return std::nullopt;773 774  while (HasEvents(status)) {775    pt_event event;776    status = pt_qry_event(decoder, &event, sizeof(event));777    if (IsLibiptError(status))778      return std::nullopt;779    if (event.has_tsc)780      return event.tsc;781  }782  return std::nullopt;783}784