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;
27 assert(status >= 0 &&
"We can't check for events if we got a failed status");
28 return status & pts_event_pending;
33 pt_insn_free_decoder(decoder);
37 pt_qry_free_decoder(decoder);
49 ArrayRef<uint8_t> buffer) {
50 Expected<pt_cpu> cpu_info = trace_intel_pt.
GetCPUInfo();
52 return cpu_info.takeError();
55 pt_config_init(&config);
56 config.cpu = *cpu_info;
58 int status = pt_cpu_errata(&config.errata, &config.cpu);
60 return make_error<IntelPTError>(status);
64 config.begin =
const_cast<uint8_t *
>(buffer.data());
65 config.end =
const_cast<uint8_t *
>(buffer.data() + buffer.size());
74 const pt_asid * , uint64_t
pc,
87 pt_image *image = pt_insn_get_image(decoder);
91 return make_error<IntelPTError>(status);
92 return Error::success();
96static Expected<PtInsnDecoderUP>
101 return config.takeError();
103 pt_insn_decoder *decoder_ptr = pt_insn_alloc_decoder(&*config);
105 return make_error<IntelPTError>(-pte_nomem);
110 return std::move(err);
119static Expected<PtQueryDecoderUP>
123 return config.takeError();
125 pt_query_decoder *decoder_ptr = pt_qry_alloc_decoder(&*config);
127 return make_error<IntelPTError>(-pte_nomem);
155 uint64_t insn_added_since_last_packet_offset =
190 if (insn_added_since_last_packet_offset >=
195 return createStringError(
196 inconvertibleErrorCode(),
197 "anomalous trace: possible infinite trace detected");
199 if (insn_added_since_last_packet_offset ==
202 return createStringError(
203 inconvertibleErrorCode(),
204 "anomalous trace: possible infinite loop detected of size %" PRIu64,
209 return Error::success();
224 auto most_recent_insn_index =
225 [&](uint64_t item_index) -> std::optional<uint64_t> {
238 auto prev_insn_index = [&](uint64_t item_index) -> std::optional<uint64_t> {
241 return most_recent_insn_index(item_index - 1);
245 std::optional<uint64_t> last_insn_index_opt =
247 if (!last_insn_index_opt)
249 uint64_t last_insn_index = *last_insn_index_opt;
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 &&
259 last_insn_copy_index = prev_insn_index(*last_insn_copy_index);
262 if (!last_insn_copy_index)
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;
275 if (std::optional<uint64_t> prev = prev_insn_index(insn_index_b))
276 insn_index_b = *prev;
282 loop_elements_visited++;
339 std::optional<lldb::addr_t> next_block_ip,
341 std::optional<DecodedThread::TSC> tsc_upper_bound)
370 static Expected<PSBBlockDecoder>
372 ArrayRef<uint8_t> buffer,
Process &process,
373 std::optional<lldb::addr_t> next_block_ip,
375 std::optional<DecodedThread::TSC> tsc_upper_bound) {
376 Expected<PtInsnDecoderUP> decoder_up =
379 return decoder_up.takeError();
381 return PSBBlockDecoder(std::move(*decoder_up), psb_block, next_block_ip,
382 decoded_thread, trace_intel_pt, tsc_upper_bound);
387 assert(status >= 0 &&
388 "Synchronization shouldn't fail because this PSB was previously "
389 "decoded correctly.");
431 std::memset(&insn, 0,
sizeof insn);
432 status = pt_insn_next(
m_decoder_up.get(), &insn,
sizeof(insn));
454 status = pt_insn_next(
m_decoder_up.get(), &insn,
sizeof(insn));
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",
485 int status = pt_insn_get_offset(
m_decoder_up.get(), &offset);
487 err_msg = formatv(
"{2} (skipping {0} of {1} bytes)", offset,
492 return createStringError(inconvertibleErrorCode(), err_msg);
495 return Error::success();
511 std::memset(&event, 0,
sizeof event);
512 status = pt_insn_event(
m_decoder_up.get(), &event,
sizeof(event));
521 consumeError(std::move(err));
522 return -pte_internal;
526 switch (event.type) {
531 case ptev_async_disabled:
563 ArrayRef<uint8_t> buffer) {
564 Expected<std::vector<PSBBlock>> blocks =
567 return blocks.takeError();
569 for (
size_t i = 0; i < blocks->size(); i++) {
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);
578 return decoder.takeError();
580 decoder->DecodePSBBlock();
583 return Error::success();
589 const std::vector<IntelPTThreadContinousExecution> &executions) {
590 bool has_seen_psbs =
false;
591 for (
size_t i = 0; i < executions.size(); i++) {
601 "per cpu decoding expects TSCs");
614 formatv(
"Unable to find intel pt data a thread "
615 "execution on cpu id = {0}",
623 if (variant == ThreadContinuousExecution::Variant::HintedStart ||
624 variant == ThreadContinuousExecution::Variant::OnlyEnd) {
626 formatv(
"Unable to find the context switch in for a thread "
627 "execution on cpu id = {0}",
633 for (
size_t j = 0; j < execution.
psb_blocks.size(); j++) {
637 trace_intel_pt, psb_block,
640 *decoded_thread.
GetThread()->GetProcess(),
646 return decoder.takeError();
648 has_seen_psbs =
true;
649 decoder->DecodePSBBlock();
658 if (i + 1 != executions.size() &&
659 (variant == ThreadContinuousExecution::Variant::OnlyStart ||
660 variant == ThreadContinuousExecution::Variant::HintedEnd)) {
662 formatv(
"Unable to find the context switch out for a thread "
663 "execution on cpu id = {0}",
669 return Error::success();
678 return exec.psb_blocks.empty() ? exec.thread_execution.GetLowestKnownTSC()
679 : exec.psb_blocks.front().tsc;
682 return get_tsc(*
this) < get_tsc(o);
685Expected<std::vector<PSBBlock>>
687 TraceIntelPT &trace_intel_pt, llvm::ArrayRef<uint8_t> buffer,
692 Expected<PtQueryDecoderUP> decoder_up =
695 return decoder_up.takeError();
697 pt_query_decoder *decoder = decoder_up.get().get();
699 std::vector<PSBBlock> executions;
703 int decoding_status = pt_qry_sync_forward(decoder, &maybe_ip);
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");
712 std::optional<uint64_t> ip;
713 if (!(pts_ip_suppressed & decoding_status))
716 std::optional<uint64_t> tsc;
720 decoding_status = pt_qry_event(decoder, &event,
sizeof(event));
738 if (expect_tscs && !tsc)
739 return createStringError(inconvertibleErrorCode(),
740 "Found a PSB without TSC.");
742 executions.push_back({
749 if (!executions.empty()) {
751 executions.back().size = buffer.size() - executions.back().psb_offset;
752 for (
int i = (
int)executions.size() - 2; i >= 0; i--) {
754 executions[i + 1].psb_offset - executions[i].psb_offset;
760Expected<std::optional<uint64_t>>
762 ArrayRef<uint8_t> buffer) {
763 Expected<PtQueryDecoderUP> decoder_up =
766 return decoder_up.takeError();
768 pt_query_decoder *decoder = decoder_up.get().get();
770 int status = pt_qry_sync_forward(decoder, &ip);
776 status = pt_qry_event(decoder, &event,
sizeof(event));
static llvm::raw_ostream & error(Stream &strm)
static Expected< pt_config > CreateBasicLibiptConfig(TraceIntelPT &trace_intel_pt, ArrayRef< uint8_t > buffer)
Create a basic configuration object limited to a given buffer that can be used for many different dec...
static Expected< PtQueryDecoderUP > CreateQueryDecoder(TraceIntelPT &trace_intel_pt, ArrayRef< uint8_t > buffer)
Create a query decoder for the given buffer.
bool IsEndOfStream(int status)
std::unique_ptr< pt_query_decoder, decltype(QueryDecoderDeleter)> PtQueryDecoderUP
static Expected< PtInsnDecoderUP > CreateInstructionDecoder(TraceIntelPT &trace_intel_pt, ArrayRef< uint8_t > buffer, Process &process)
Create an instruction decoder for the given buffer and the given process.
static Error SetupMemoryImage(pt_insn_decoder *decoder, Process &process)
Set up the memory image callback for the given decoder.
bool HasEvents(int status)
std::unique_ptr< pt_insn_decoder, decltype(InsnDecoderDeleter)> PtInsnDecoderUP
bool IsLibiptError(int status)
static int ReadProcessMemory(uint8_t *buffer, size_t size, const pt_asid *, uint64_t pc, void *context)
Callback used by libipt for reading the process memory.
Class used to identify anomalies in traces, which should often indicate a fatal error in the trace.
DecodedThread & m_decoded_thread
lldb::addr_t m_last_packet_offset
uint64_t m_extremely_large_decoding_threshold
uint64_t m_infinite_decoding_loop_threshold
uint64_t m_next_infinite_decoding_loop_threshold
PSBBlockAnomalyDetector(pt_insn_decoder &decoder, TraceIntelPT &trace_intel_pt, DecodedThread &decoded_thread)
pt_insn_decoder & m_decoder
void RefreshPacketOffset()
uint64_t m_insn_count_at_last_packet_offset
std::optional< uint64_t > TryIdentifyInfiniteLoop()
Class that decodes a raw buffer for a single PSB block using the low level libipt library.
PtInsnDecoderUP m_decoder_up
std::optional< DecodedThread::TSC > m_tsc_upper_bound
void DecodeInstructionsAndEvents(int status)
Decode all the instructions and events of the given PSB block.
bool AppendInstructionAndDetectAnomalies(const pt_insn &insn)
Append an instruction and return false if and only if a serious anomaly has been detected.
Error ProcessPTEventTSC(DecodedThread::TSC tsc)
Process the TSC of a decoded PT event.
DecodedThread & m_decoded_thread
PSBBlockAnomalyDetector m_anomaly_detector
PSBBlockDecoder(PtInsnDecoderUP &&decoder_up, const PSBBlock &psb_block, std::optional< lldb::addr_t > next_block_ip, DecodedThread &decoded_thread, TraceIntelPT &trace_intel_pt, std::optional< DecodedThread::TSC > tsc_upper_bound)
static Expected< PSBBlockDecoder > Create(TraceIntelPT &trace_intel_pt, const PSBBlock &psb_block, ArrayRef< uint8_t > buffer, Process &process, std::optional< lldb::addr_t > next_block_ip, DecodedThread &decoded_thread, std::optional< DecodedThread::TSC > tsc_upper_bound)
int ProcessPTEvents(int status)
Before querying instructions, we need to query the events associated with that instruction,...
std::optional< lldb::addr_t > m_next_block_ip
A plug-in interface definition class for debugging a process.
virtual size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, Status &error)
Read of memory from a process.
Class holding the instructions and function call hierarchy obtained from decoding a trace,...
lldb::TraceItemKind GetItemKindByIndex(uint64_t item_index) const
void AppendEvent(lldb::TraceEvent)
Append an event.
lldb::ThreadSP GetThread()
lldb::addr_t GetInstructionLoadAddress(uint64_t item_index) const
void AppendError(const IntelPTError &error)
Append a decoding error.
void NotifyCPU(lldb::cpu_id_t cpu_id)
Notify this object that a CPU has been seen.
uint64_t GetTotalInstructionCount() const
void NotifySyncPoint(lldb::addr_t psb_offset)
Notify this object that a new PSB has been seen.
void AppendCustomError(llvm::StringRef error, bool fatal=false)
Append a custom decoding.
void NotifyTsc(TSC tsc)
Notify this object that a new tsc has been seen.
uint64_t GetItemsCount() const
Get the total number of instruction, errors and events from the decoded trace.
void AppendInstruction(const pt_insn &insn)
Append an instruction.
Class for representing a libipt decoding error.
uint64_t GetExtremelyLargeDecodingThreshold()
uint64_t GetInfiniteDecodingLoopVerificationThreshold()
static PluginProperties & GetGlobalProperties()
Return the global properties for this trace plug-in.
llvm::Expected< pt_cpu > GetCPUInfo()
Get or fetch the cpu information from, for example, /proc/cpuinfo.
#define LLDB_INVALID_ADDRESS
llvm::Expected< std::vector< PSBBlock > > SplitTraceIntoPSBBlock(TraceIntelPT &trace_intel_pt, llvm::ArrayRef< uint8_t > buffer, bool expect_tscs)
Given an intel pt trace, split it in chunks delimited by PSB packets.
llvm::Error DecodeSingleTraceForThread(DecodedThread &decoded_thread, TraceIntelPT &trace_intel_pt, llvm::ArrayRef< uint8_t > buffer)
Decode a raw Intel PT trace for a single thread given in buffer and append the decoded instructions a...
llvm::Error DecodeSystemWideTraceForThread(DecodedThread &decoded_thread, TraceIntelPT &trace_intel_pt, const llvm::DenseMap< lldb::cpu_id_t, llvm::ArrayRef< uint8_t > > &buffers, const std::vector< IntelPTThreadContinousExecution > &executions)
Decode a raw Intel PT trace for a single thread that was collected in a per cpu core basis.
llvm::Expected< std::optional< uint64_t > > FindLowestTSCInTrace(TraceIntelPT &trace_intel_pt, llvm::ArrayRef< uint8_t > buffer)
Find the lowest TSC in the given trace.
A class that represents a running process on the host machine.
const char * toString(AppleArm64ExceptionClass EC)
@ eTraceEventDisabledHW
Tracing was disable for some time due to a hardware trigger.
@ eTraceEventDisabledSW
Tracing was disabled for some time due to a software trigger.
@ eTraceItemKindInstruction
This struct represents a continuous execution of a thread in a cpu, delimited by a context switch in ...
ThreadContinuousExecution thread_execution
std::vector< PSBBlock > psb_blocks
bool operator<(const IntelPTThreadContinousExecution &o) const
Comparator by time.
This struct represents a contiguous section of a trace that starts at a PSB and ends right before the...
std::optional< uint64_t > tsc
The timestamp associated with the PSB packet above.
uint64_t psb_offset
The memory offset of a PSB packet that is a synchronization point for the decoder.
uint64_t size
Size in bytes of this block.
uint64_t GetEndTSC() const
uint64_t GetLowestKnownTSC() const
enum lldb_private::trace_intel_pt::ThreadContinuousExecution::Variant variant